comparison foosdk/sdk/foobar2000/SDK/menu_helpers.cpp @ 1:20d02a178406 default tip

*: check in everything else yay
author Paper <paper@tflc.us>
date Mon, 05 Jan 2026 02:15:46 -0500
parents
children
comparison
equal deleted inserted replaced
0:e9bb126753e7 1:20d02a178406
1 #include "foobar2000-sdk-pch.h"
2 #include "menu_helpers.h"
3 #include "metadb.h"
4 #include "playlist.h"
5
6
7 bool menu_helpers::context_get_description(const GUID& p_guid,pfc::string_base & out) {
8 service_ptr_t<contextmenu_item> ptr; t_uint32 index;
9 if (!menu_item_resolver::g_resolve_context_command(p_guid, ptr, index)) return false;
10 bool rv = ptr->get_item_description(index, out);
11 if (!rv) out.reset();
12 return rv;
13 }
14
15 static bool run_context_command_internal(const GUID & p_command,const GUID & p_subcommand,const pfc::list_base_const_t<metadb_handle_ptr> & data,const GUID & caller) {
16 if (data.get_count() == 0) return false;
17 service_ptr_t<contextmenu_item> ptr; t_uint32 index;
18 if (!menu_item_resolver::g_resolve_context_command(p_command, ptr, index)) return false;
19
20 {
21 TRACK_CALL_TEXT("menu_helpers::run_command(), by GUID");
22 ptr->item_execute_simple(index, p_subcommand, data, caller);
23 }
24
25 return true;
26 }
27
28 bool menu_helpers::run_command_context(const GUID & p_command,const GUID & p_subcommand,const pfc::list_base_const_t<metadb_handle_ptr> & data)
29 {
30 return run_context_command_internal(p_command,p_subcommand,data,contextmenu_item::caller_undefined);
31 }
32
33 bool menu_helpers::run_command_context_ex(const GUID & p_command,const GUID & p_subcommand,const pfc::list_base_const_t<metadb_handle_ptr> & data,const GUID & caller)
34 {
35 return run_context_command_internal(p_command,p_subcommand,data,caller);
36 }
37
38 bool menu_helpers::test_command_context(const GUID & p_guid)
39 {
40 service_ptr_t<contextmenu_item> ptr; t_uint32 index;
41 return menu_item_resolver::g_resolve_context_command(p_guid, ptr, index);
42 }
43
44 static bool g_is_checked(const GUID & p_command,const GUID & p_subcommand,const pfc::list_base_const_t<metadb_handle_ptr> & data,const GUID & caller)
45 {
46 service_ptr_t<contextmenu_item> ptr; t_uint32 index;
47 if (!menu_item_resolver::g_resolve_context_command(p_command, ptr, index)) return false;
48
49 unsigned displayflags = 0;
50 pfc::string_formatter dummystring;
51 if (!ptr->item_get_display_data(dummystring,displayflags,index,p_subcommand,data,caller)) return false;
52 return (displayflags & contextmenu_item_node::FLAG_CHECKED) != 0;
53
54 }
55
56 bool menu_helpers::is_command_checked_context(const GUID & p_command,const GUID & p_subcommand,const pfc::list_base_const_t<metadb_handle_ptr> & data)
57 {
58 return g_is_checked(p_command,p_subcommand,data,contextmenu_item::caller_undefined);
59 }
60
61 bool menu_helpers::is_command_checked_context_playlist(const GUID & p_command,const GUID & p_subcommand)
62 {
63 metadb_handle_list temp;
64 playlist_manager::get()->activeplaylist_get_selected_items(temp);
65 return g_is_checked(p_command,p_subcommand,temp,contextmenu_item::caller_playlist);
66 }
67
68
69
70
71
72
73
74 bool menu_helpers::run_command_context_playlist(const GUID & p_command,const GUID & p_subcommand)
75 {
76 metadb_handle_list temp;
77 playlist_manager::get()->activeplaylist_get_selected_items(temp);
78 return run_command_context_ex(p_command,p_subcommand,temp,contextmenu_item::caller_playlist);
79 }
80
81 bool menu_helpers::run_command_context_now_playing(const GUID & p_command,const GUID & p_subcommand)
82 {
83 metadb_handle_ptr item;
84 if (!playback_control::get()->get_now_playing(item)) return false;//not playing
85 return run_command_context_ex(p_command,p_subcommand,pfc::list_single_ref_t<metadb_handle_ptr>(item),contextmenu_item::caller_now_playing);
86 }
87
88
89 bool menu_helpers::guid_from_name(const char * p_name,unsigned p_name_len,GUID & p_out)
90 {
91 pfc::string8_fastalloc nametemp;
92 for( auto ptr : contextmenu_item::enumerate() ) {
93 unsigned n, m = ptr->get_num_items();
94 for(n=0;n<m;n++)
95 {
96 ptr->get_item_name(n,nametemp);
97 if (!strcmp_ex(nametemp,SIZE_MAX,p_name,p_name_len))
98 {
99 p_out = ptr->get_item_guid(n);
100 return true;
101 }
102 }
103 }
104 return false;
105 }
106
107 bool menu_helpers::name_from_guid(const GUID & p_guid,pfc::string_base & p_out) {
108 service_ptr_t<contextmenu_item> ptr; t_uint32 index;
109 if (!menu_item_resolver::g_resolve_context_command(p_guid, ptr, index)) return false;
110 ptr->get_item_name(index, p_out);
111 return true;
112 }
113
114
115 static unsigned calc_total_action_count()
116 {
117 unsigned ret = 0;
118 for( auto ptr : contextmenu_item::enumerate()) ret += ptr->get_num_items();
119 return ret;
120 }
121
122
123 const char * menu_helpers::guid_to_name_table::search(const GUID & p_guid)
124 {
125 if (!m_inited)
126 {
127 m_data.set_size(calc_total_action_count());
128 t_size dataptr = 0;
129 pfc::string8_fastalloc nametemp;
130
131 for( auto ptr : contextmenu_item::enumerate())
132 {
133 unsigned n, m = ptr->get_num_items();
134 for(n=0;n<m;n++)
135 {
136 assert(dataptr < m_data.get_size());
137
138 ptr->get_item_name(n,nametemp);
139 m_data[dataptr].m_name = pfc::strDup(nametemp);
140 m_data[dataptr].m_guid = ptr->get_item_guid(n);
141 dataptr++;
142 }
143 }
144 assert(dataptr == m_data.get_size());
145
146 pfc::sort_t(m_data,entry_compare,m_data.get_size());
147 m_inited = true;
148 }
149 t_size index;
150 if (pfc::bsearch_t(m_data.get_size(),m_data,entry_compare_search,p_guid,index))
151 return m_data[index].m_name;
152 else
153 return 0;
154 }
155
156 int menu_helpers::guid_to_name_table::entry_compare_search(const entry & entry1,const GUID & entry2)
157 {
158 return pfc::guid_compare(entry1.m_guid,entry2);
159 }
160
161 int menu_helpers::guid_to_name_table::entry_compare(const entry & entry1,const entry & entry2)
162 {
163 return pfc::guid_compare(entry1.m_guid,entry2.m_guid);
164 }
165
166 menu_helpers::guid_to_name_table::guid_to_name_table()
167 {
168 m_inited = false;
169 }
170
171 menu_helpers::guid_to_name_table::~guid_to_name_table()
172 {
173 t_size n, m = m_data.get_size();
174 for(n=0;n<m;n++) free(m_data[n].m_name);
175
176 }
177
178
179 int menu_helpers::name_to_guid_table::entry_compare_search(const entry & entry1,const search_entry & entry2)
180 {
181 return stricmp_utf8_ex(entry1.m_name,SIZE_MAX,entry2.m_name,entry2.m_name_len);
182 }
183
184 int menu_helpers::name_to_guid_table::entry_compare(const entry & entry1,const entry & entry2)
185 {
186 return stricmp_utf8(entry1.m_name,entry2.m_name);
187 }
188
189 bool menu_helpers::name_to_guid_table::search(const char * p_name,unsigned p_name_len,GUID & p_out)
190 {
191 if (!m_inited)
192 {
193 m_data.set_size(calc_total_action_count());
194 t_size dataptr = 0;
195 pfc::string8_fastalloc nametemp;
196
197 for( auto ptr : contextmenu_item::enumerate() )
198 {
199 unsigned n, m = ptr->get_num_items();
200 for(n=0;n<m;n++)
201 {
202 assert(dataptr < m_data.get_size());
203
204 ptr->get_item_name(n,nametemp);
205 m_data[dataptr].m_name = pfc::strDup(nametemp);
206 m_data[dataptr].m_guid = ptr->get_item_guid(n);
207 dataptr++;
208 }
209 }
210 assert(dataptr == m_data.get_size());
211
212 pfc::sort_t(m_data,entry_compare,m_data.get_size());
213 m_inited = true;
214 }
215 t_size index;
216 search_entry temp = {p_name,p_name_len};
217 if (pfc::bsearch_t(m_data.get_size(),m_data,entry_compare_search,temp,index))
218 {
219 p_out = m_data[index].m_guid;
220 return true;
221 }
222 else
223 return false;
224 }
225
226 menu_helpers::name_to_guid_table::name_to_guid_table()
227 {
228 m_inited = false;
229 }
230
231 menu_helpers::name_to_guid_table::~name_to_guid_table()
232 {
233 t_size n, m = m_data.get_size();
234 for(n=0;n<m;n++) free(m_data[n].m_name);
235
236 }
237
238 bool menu_helpers::find_command_by_name(const char * p_name,service_ptr_t<contextmenu_item> & p_item,unsigned & p_index)
239 {
240 pfc::string8_fastalloc path,name;
241
242 for (auto ptr : contextmenu_item::enumerate()) {
243 // if (ptr->get_type()==type)
244 {
245 unsigned action, num_actions = ptr->get_num_items();
246 for (action = 0; action < num_actions; action++)
247 {
248 ptr->get_item_default_path(action, path); ptr->get_item_name(action, name);
249 if (!path.is_empty()) path += "/";
250 path += name;
251 if (!stricmp_utf8(p_name, path))
252 {
253 p_item = ptr;
254 p_index = action;
255 return true;
256 }
257 }
258 }
259 }
260 return false;
261
262 }
263
264 bool menu_helpers::find_command_by_name(const char * p_name,GUID & p_command)
265 {
266 service_ptr_t<contextmenu_item> item;
267 unsigned index;
268 bool ret = find_command_by_name(p_name,item,index);
269 if (ret) p_command = item->get_item_guid(index);
270 return ret;
271 }
272
273
274 bool standard_commands::run_main(const GUID & p_guid) {
275 t_uint32 index;
276 mainmenu_commands::ptr ptr;
277 if (!menu_item_resolver::g_resolve_main_command(p_guid, ptr, index)) return false;
278 ptr->execute(index,service_ptr_t<service_base>());
279 return true;
280 }
281
282 bool menu_item_resolver::g_resolve_context_command(const GUID & id, contextmenu_item::ptr & out, t_uint32 & out_index) {
283 return menu_item_resolver::get()->resolve_context_command(id, out, out_index);
284 }
285 bool menu_item_resolver::g_resolve_main_command(const GUID & id, mainmenu_commands::ptr & out, t_uint32 & out_index) {
286 return menu_item_resolver::get()->resolve_main_command(id, out, out_index);
287 }
288
289 static bool char_is_separator(char x)
290 {
291 for( auto s : {' ', ',', '/', '-'}) {
292 if (x==s) return true;
293 }
294 return false;
295 }
296
297 static bool capitalize_exception( const char * ptr, size_t len ) {
298 for( auto e : {"for", "to", "from", "with", "by", "in", "at", "and", "or", "on", "a", "of", "as" }) {
299 if ( len == strlen(e) && memcmp(ptr, e, len) == 0 ) return true;
300 }
301 return false;
302 }
303 #if FB2K_MENU_CAPS == FB2K_MENU_CAPS_TITLE
304 static pfc::string8 capitalizeThis( const char * arg ) {
305 pfc::string8 work; work.prealloc( 256 );
306 auto base = arg;
307 while(*base) {
308 auto ptr = base;
309 while(*ptr && ! char_is_separator(*ptr) ) ++ptr;
310 if ( ptr > base ) {
311 if ( !capitalize_exception( base, ptr-base ) ) {
312 unsigned c = 0;
313 auto d = pfc::utf8_decode_char(base, c, ptr-base);
314 if ( d > 0 ) {
315 c = uCharUpper( c );
316 work.add_char( c );
317 base += d;
318 }
319 }
320 work.add_string_nc(base, ptr - base);
321 }
322 while(*ptr && char_is_separator(*ptr)) {
323 work.add_byte(*ptr++);
324 }
325 base = ptr;
326 }
327 return work;
328 }
329 #endif // #if FB2K_MENU_CAPS == FB2K_MENU_CAPS_TITLE
330
331 void fb2k::capitalizeMenuLabel( pfc::string_base & inOut ) {
332 #if FB2K_MENU_CAPS == FB2K_MENU_CAPS_TITLE
333 inOut = capitalizeThis( inOut );
334 #else
335 (void) inOut;
336 #endif
337 }