diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/foosdk/sdk/foobar2000/SDK/menu_helpers.cpp	Mon Jan 05 02:15:46 2026 -0500
@@ -0,0 +1,337 @@
+#include "foobar2000-sdk-pch.h"
+#include "menu_helpers.h"
+#include "metadb.h"
+#include "playlist.h"
+
+
+bool menu_helpers::context_get_description(const GUID& p_guid,pfc::string_base & out) {
+	service_ptr_t<contextmenu_item> ptr; t_uint32 index;
+	if (!menu_item_resolver::g_resolve_context_command(p_guid, ptr, index)) return false;
+	bool rv = ptr->get_item_description(index, out);
+	if (!rv) out.reset();
+	return rv;
+}
+
+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) {
+	if (data.get_count() == 0) return false;
+	service_ptr_t<contextmenu_item> ptr; t_uint32 index;
+	if (!menu_item_resolver::g_resolve_context_command(p_command, ptr, index)) return false;
+	
+	{
+		TRACK_CALL_TEXT("menu_helpers::run_command(), by GUID");
+		ptr->item_execute_simple(index, p_subcommand, data, caller);
+	}
+	
+	return true;
+}
+
+bool menu_helpers::run_command_context(const GUID & p_command,const GUID & p_subcommand,const pfc::list_base_const_t<metadb_handle_ptr> & data)
+{
+	return run_context_command_internal(p_command,p_subcommand,data,contextmenu_item::caller_undefined);
+}
+
+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)
+{
+	return run_context_command_internal(p_command,p_subcommand,data,caller);
+}
+
+bool menu_helpers::test_command_context(const GUID & p_guid)
+{
+	service_ptr_t<contextmenu_item> ptr; t_uint32 index;
+	return menu_item_resolver::g_resolve_context_command(p_guid, ptr, index);
+}
+
+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)
+{
+	service_ptr_t<contextmenu_item> ptr; t_uint32 index;
+	if (!menu_item_resolver::g_resolve_context_command(p_command, ptr, index)) return false;
+
+	unsigned displayflags = 0;
+	pfc::string_formatter dummystring;
+	if (!ptr->item_get_display_data(dummystring,displayflags,index,p_subcommand,data,caller)) return false;
+	return (displayflags & contextmenu_item_node::FLAG_CHECKED) != 0;
+
+}
+
+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)
+{
+	return g_is_checked(p_command,p_subcommand,data,contextmenu_item::caller_undefined);
+}
+
+bool menu_helpers::is_command_checked_context_playlist(const GUID & p_command,const GUID & p_subcommand)
+{
+	metadb_handle_list temp;
+	playlist_manager::get()->activeplaylist_get_selected_items(temp);
+	return g_is_checked(p_command,p_subcommand,temp,contextmenu_item::caller_playlist);
+}
+
+
+
+
+
+
+
+bool menu_helpers::run_command_context_playlist(const GUID & p_command,const GUID & p_subcommand)
+{
+	metadb_handle_list temp;
+	playlist_manager::get()->activeplaylist_get_selected_items(temp);
+	return run_command_context_ex(p_command,p_subcommand,temp,contextmenu_item::caller_playlist);
+}
+
+bool menu_helpers::run_command_context_now_playing(const GUID & p_command,const GUID & p_subcommand)
+{
+	metadb_handle_ptr item;
+	if (!playback_control::get()->get_now_playing(item)) return false;//not playing
+	return run_command_context_ex(p_command,p_subcommand,pfc::list_single_ref_t<metadb_handle_ptr>(item),contextmenu_item::caller_now_playing);
+}
+
+
+bool menu_helpers::guid_from_name(const char * p_name,unsigned p_name_len,GUID & p_out)
+{
+	pfc::string8_fastalloc nametemp;
+	for( auto ptr : contextmenu_item::enumerate() ) {
+		unsigned n, m = ptr->get_num_items();
+		for(n=0;n<m;n++)
+		{
+			ptr->get_item_name(n,nametemp);
+			if (!strcmp_ex(nametemp,SIZE_MAX,p_name,p_name_len))
+			{
+				p_out = ptr->get_item_guid(n);
+				return true;
+			}
+		}
+	}
+	return false;
+}
+
+bool menu_helpers::name_from_guid(const GUID & p_guid,pfc::string_base & p_out) {
+	service_ptr_t<contextmenu_item> ptr; t_uint32 index;
+	if (!menu_item_resolver::g_resolve_context_command(p_guid, ptr, index)) return false;
+	ptr->get_item_name(index, p_out);
+	return true;
+}
+
+
+static unsigned calc_total_action_count()
+{
+	unsigned ret = 0;
+	for( auto ptr : contextmenu_item::enumerate()) ret += ptr->get_num_items();
+	return ret;
+}
+
+
+const char * menu_helpers::guid_to_name_table::search(const GUID & p_guid)
+{
+	if (!m_inited)
+	{
+		m_data.set_size(calc_total_action_count());
+		t_size dataptr = 0;
+		pfc::string8_fastalloc nametemp;
+
+		for( auto ptr : contextmenu_item::enumerate()) 
+		{
+			unsigned n, m = ptr->get_num_items();
+			for(n=0;n<m;n++)
+			{
+				assert(dataptr < m_data.get_size());
+
+				ptr->get_item_name(n,nametemp);
+				m_data[dataptr].m_name = pfc::strDup(nametemp);
+				m_data[dataptr].m_guid = ptr->get_item_guid(n);
+				dataptr++;
+			}
+		}
+		assert(dataptr == m_data.get_size());
+
+		pfc::sort_t(m_data,entry_compare,m_data.get_size());
+		m_inited = true;
+	}
+	t_size index;
+	if (pfc::bsearch_t(m_data.get_size(),m_data,entry_compare_search,p_guid,index))
+		return m_data[index].m_name;
+	else
+		return 0;
+}
+
+int menu_helpers::guid_to_name_table::entry_compare_search(const entry & entry1,const GUID & entry2)
+{
+	return pfc::guid_compare(entry1.m_guid,entry2);
+}
+
+int menu_helpers::guid_to_name_table::entry_compare(const entry & entry1,const entry & entry2)
+{
+	return pfc::guid_compare(entry1.m_guid,entry2.m_guid);
+}
+
+menu_helpers::guid_to_name_table::guid_to_name_table()
+{
+	m_inited = false;
+}
+
+menu_helpers::guid_to_name_table::~guid_to_name_table()
+{
+	t_size n, m = m_data.get_size();
+	for(n=0;n<m;n++) free(m_data[n].m_name);
+
+}
+
+
+int menu_helpers::name_to_guid_table::entry_compare_search(const entry & entry1,const search_entry & entry2)
+{
+	return stricmp_utf8_ex(entry1.m_name,SIZE_MAX,entry2.m_name,entry2.m_name_len);
+}
+
+int menu_helpers::name_to_guid_table::entry_compare(const entry & entry1,const entry & entry2)
+{
+	return stricmp_utf8(entry1.m_name,entry2.m_name);
+}
+
+bool menu_helpers::name_to_guid_table::search(const char * p_name,unsigned p_name_len,GUID & p_out)
+{
+	if (!m_inited)
+	{
+		m_data.set_size(calc_total_action_count());
+		t_size dataptr = 0;
+		pfc::string8_fastalloc nametemp;
+
+		for( auto ptr : contextmenu_item::enumerate() ) 
+		{
+			unsigned n, m = ptr->get_num_items();
+			for(n=0;n<m;n++)
+			{
+				assert(dataptr < m_data.get_size());
+
+				ptr->get_item_name(n,nametemp);
+				m_data[dataptr].m_name = pfc::strDup(nametemp);
+				m_data[dataptr].m_guid = ptr->get_item_guid(n);
+				dataptr++;
+			}
+		}
+		assert(dataptr == m_data.get_size());
+
+		pfc::sort_t(m_data,entry_compare,m_data.get_size());
+		m_inited = true;
+	}
+	t_size index;
+	search_entry temp = {p_name,p_name_len};
+	if (pfc::bsearch_t(m_data.get_size(),m_data,entry_compare_search,temp,index))
+	{
+		p_out = m_data[index].m_guid;
+		return true;
+	}
+	else
+		return false;
+}
+
+menu_helpers::name_to_guid_table::name_to_guid_table()
+{
+	m_inited = false;
+}
+
+menu_helpers::name_to_guid_table::~name_to_guid_table()
+{
+	t_size n, m = m_data.get_size();
+	for(n=0;n<m;n++) free(m_data[n].m_name);
+
+}
+
+bool menu_helpers::find_command_by_name(const char * p_name,service_ptr_t<contextmenu_item> & p_item,unsigned & p_index)
+{
+	pfc::string8_fastalloc path,name;
+
+	for (auto ptr : contextmenu_item::enumerate()) {
+		//		if (ptr->get_type()==type)
+		{
+			unsigned action, num_actions = ptr->get_num_items();
+			for (action = 0; action < num_actions; action++)
+			{
+				ptr->get_item_default_path(action, path); ptr->get_item_name(action, name);
+				if (!path.is_empty()) path += "/";
+				path += name;
+				if (!stricmp_utf8(p_name, path))
+				{
+					p_item = ptr;
+					p_index = action;
+					return true;
+				}
+			}
+		}
+	}
+	return false;
+
+}
+
+bool menu_helpers::find_command_by_name(const char * p_name,GUID & p_command)
+{
+	service_ptr_t<contextmenu_item> item;
+	unsigned index;
+	bool ret = find_command_by_name(p_name,item,index);
+	if (ret) p_command = item->get_item_guid(index);
+	return ret;
+}
+
+
+bool standard_commands::run_main(const GUID & p_guid) {
+	t_uint32 index;
+	mainmenu_commands::ptr ptr;
+	if (!menu_item_resolver::g_resolve_main_command(p_guid, ptr, index)) return false;
+	ptr->execute(index,service_ptr_t<service_base>());
+	return true;
+}
+
+bool menu_item_resolver::g_resolve_context_command(const GUID & id, contextmenu_item::ptr & out, t_uint32 & out_index) {
+	return menu_item_resolver::get()->resolve_context_command(id, out, out_index);
+}
+bool menu_item_resolver::g_resolve_main_command(const GUID & id, mainmenu_commands::ptr & out, t_uint32 & out_index) {
+	return menu_item_resolver::get()->resolve_main_command(id, out, out_index);
+}
+
+static bool char_is_separator(char x)
+{
+    for( auto s : {' ', ',', '/', '-'}) {
+        if (x==s) return true;
+    }
+    return false;
+}
+
+static bool capitalize_exception( const char * ptr, size_t len ) {
+    for( auto e : {"for", "to", "from", "with", "by", "in", "at", "and", "or", "on", "a", "of", "as" }) {
+        if ( len == strlen(e) && memcmp(ptr, e, len) == 0 ) return true;
+    }
+    return false;
+}
+#if FB2K_MENU_CAPS == FB2K_MENU_CAPS_TITLE
+static pfc::string8 capitalizeThis( const char * arg ) {
+    pfc::string8 work; work.prealloc( 256 );
+    auto base = arg;
+    while(*base) {
+        auto ptr = base;
+        while(*ptr && ! char_is_separator(*ptr) ) ++ptr;
+        if ( ptr > base ) {
+            if ( !capitalize_exception( base, ptr-base ) ) {
+                unsigned c = 0;
+                auto d = pfc::utf8_decode_char(base, c, ptr-base);
+                if ( d > 0 ) {
+                    c = uCharUpper( c );
+                    work.add_char( c );
+                    base += d;
+                }
+            }
+            work.add_string_nc(base, ptr - base);
+        }
+        while(*ptr && char_is_separator(*ptr)) {
+            work.add_byte(*ptr++);
+        }
+        base = ptr;
+    }
+    return work;
+}
+#endif // #if FB2K_MENU_CAPS == FB2K_MENU_CAPS_TITLE
+
+void fb2k::capitalizeMenuLabel( pfc::string_base & inOut ) {
+#if FB2K_MENU_CAPS == FB2K_MENU_CAPS_TITLE
+    inOut = capitalizeThis( inOut );
+#else
+    (void) inOut;
+#endif
+}