|
1
|
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 }
|