Mercurial > foo_out_sdl
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 } |
