From 5851f1e2dd8855666d3aeb750242277cd4158ae5 Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Mon, 25 Mar 2024 10:41:03 +0200 Subject: [PATCH] [MenuBar] Use NativeMenu RIDs instead of indices to track items. --- doc/classes/DisplayServer.xml | 4 +- doc/classes/NativeMenu.xml | 13 +++++- scene/gui/menu_bar.cpp | 86 ++++++++++++++++++++++------------- scene/gui/menu_bar.h | 2 +- servers/native_menu.cpp | 14 ++++++ servers/native_menu.h | 1 + 6 files changed, 84 insertions(+), 36 deletions(-) diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index ecb8438edbb..ae0dc53f5d9 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -553,7 +553,7 @@ - Returns the index of the item with the specified [param tag]. Index is automatically assigned to each item by the engine. Index can not be set manually. + Returns the index of the item with the specified [param tag]. Indices are automatically assigned to each item by the engine, and cannot be set manually. [b]Note:[/b] This method is implemented only on macOS. @@ -562,7 +562,7 @@ - Returns the index of the item with the specified [param text]. Index is automatically assigned to each item by the engine. Index can not be set manually. + Returns the index of the item with the specified [param text]. Indices are automatically assigned to each item by the engine, and cannot be set manually. [b]Note:[/b] This method is implemented only on macOS. diff --git a/doc/classes/NativeMenu.xml b/doc/classes/NativeMenu.xml index cfe3f3f5c57..475874dee75 100644 --- a/doc/classes/NativeMenu.xml +++ b/doc/classes/NativeMenu.xml @@ -211,12 +211,21 @@ [b]Note:[/b] This method is implemented on macOS and Windows. + + + + + + Returns the index of the item with the submenu specified by [param submenu_rid]. Indices are automatically assigned to each item by the engine, and cannot be set manually. + [b]Note:[/b] This method is implemented on macOS and Windows. + + - Returns the index of the item with the specified [param tag]. Index is automatically assigned to each item by the engine. Index can not be set manually. + Returns the index of the item with the specified [param tag]. Indices are automatically assigned to each item by the engine, and cannot be set manually. [b]Note:[/b] This method is implemented on macOS and Windows. @@ -225,7 +234,7 @@ - Returns the index of the item with the specified [param text]. Index is automatically assigned to each item by the engine. Index can not be set manually. + Returns the index of the item with the specified [param text]. Indices are automatically assigned to each item by the engine, and cannot be set manually. [b]Note:[/b] This method is implemented on macOS and Windows. diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp index 8eb455d0acb..2ce12794a78 100644 --- a/scene/gui/menu_bar.cpp +++ b/scene/gui/menu_bar.cpp @@ -236,12 +236,12 @@ void MenuBar::bind_global_menu() { RID submenu_rid = popups[i]->bind_global_menu(); if (!popups[i]->is_system_menu()) { int index = nmenu->add_submenu_item(main_menu, menu_cache[i].name, submenu_rid, global_menu_tag + "#" + itos(i), global_start_idx + i); - menu_cache.write[i].global_index = index; + menu_cache.write[i].submenu_rid = submenu_rid; nmenu->set_item_hidden(main_menu, index, menu_cache[i].hidden); nmenu->set_item_disabled(main_menu, index, menu_cache[i].disabled); nmenu->set_item_tooltip(main_menu, index, menu_cache[i].tooltip); } else { - menu_cache.write[i].global_index = -1; + menu_cache.write[i].submenu_rid = RID(); } } } @@ -257,11 +257,14 @@ void MenuBar::unbind_global_menu() { Vector popups = _get_popups(); for (int i = menu_cache.size() - 1; i >= 0; i--) { if (!popups[i]->is_system_menu()) { - popups[i]->unbind_global_menu(); - if (menu_cache[i].global_index >= 0) { - nmenu->remove_item(main_menu, menu_cache[i].global_index); + if (menu_cache[i].submenu_rid.is_valid()) { + int item_idx = nmenu->find_item_index_with_submenu(main_menu, menu_cache[i].submenu_rid); + if (item_idx >= 0) { + nmenu->remove_item(main_menu, item_idx); + } } - menu_cache.write[i].global_index = -1; + popups[i]->unbind_global_menu(); + menu_cache.write[i].submenu_rid = RID(); } } @@ -292,8 +295,11 @@ void MenuBar::_notification(int p_what) { RID main_menu = is_global ? nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID) : RID(); for (int i = 0; i < menu_cache.size(); i++) { shape(menu_cache.write[i]); - if (is_global && menu_cache[i].global_index >= 0) { - nmenu->set_item_text(main_menu, menu_cache[i].global_index, atr(menu_cache[i].name)); + if (is_global && menu_cache[i].submenu_rid.is_valid()) { + int item_idx = nmenu->find_item_index_with_submenu(main_menu, menu_cache[i].submenu_rid); + if (item_idx >= 0) { + nmenu->set_item_text(main_menu, item_idx, atr(menu_cache[i].name)); + } } } } break; @@ -500,8 +506,11 @@ void MenuBar::_refresh_menu_names() { if (!popups[i]->has_meta("_menu_name") && String(popups[i]->get_name()) != get_menu_title(i)) { menu_cache.write[i].name = popups[i]->get_name(); shape(menu_cache.write[i]); - if (is_global && menu_cache[i].global_index >= 0) { - nmenu->set_item_text(main_menu, menu_cache[i].global_index, atr(menu_cache[i].name)); + if (is_global && menu_cache[i].submenu_rid.is_valid()) { + int item_idx = nmenu->find_item_index_with_submenu(main_menu, menu_cache[i].submenu_rid); + if (item_idx >= 0) { + nmenu->set_item_text(main_menu, item_idx, atr(menu_cache[i].name)); + } } } } @@ -554,8 +563,8 @@ void MenuBar::add_child_notify(Node *p_child) { RID submenu_rid = pm->bind_global_menu(); if (!pm->is_system_menu()) { - int index = nmenu->add_submenu_item(main_menu, atr(menu.name), submenu_rid, global_menu_tag + "#" + itos(menu_cache.size() - 1), _find_global_start_index() + menu_cache.size() - 1); - menu_cache.write[menu_cache.size() - 1].global_index = index; + nmenu->add_submenu_item(main_menu, atr(menu.name), submenu_rid, global_menu_tag + "#" + itos(menu_cache.size() - 1), _find_global_start_index() + menu_cache.size() - 1); + menu_cache.write[menu_cache.size() - 1].submenu_rid = submenu_rid; } } update_minimum_size(); @@ -589,13 +598,14 @@ void MenuBar::move_child_notify(Node *p_child) { RID main_menu = nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID); int global_start = _find_global_start_index(); - if (menu.global_index >= 0) { - nmenu->remove_item(main_menu, menu.global_index); + if (menu.submenu_rid.is_valid()) { + int item_idx = nmenu->find_item_index_with_submenu(main_menu, menu.submenu_rid); + if (item_idx >= 0) { + nmenu->remove_item(main_menu, item_idx); + } } if (new_idx != -1) { - RID submenu_rid = pm->bind_global_menu(); - int index = nmenu->add_submenu_item(main_menu, atr(menu.name), submenu_rid, global_menu_tag + "#" + itos(new_idx), global_start + new_idx); - menu_cache.write[new_idx].global_index = index; + nmenu->add_submenu_item(main_menu, atr(menu.name), menu.submenu_rid, global_menu_tag + "#" + itos(new_idx), global_start + new_idx); } } } @@ -611,20 +621,22 @@ void MenuBar::remove_child_notify(Node *p_child) { int idx = get_menu_idx_from_control(pm); - menu_cache.remove_at(idx); - if (!global_menu_tag.is_empty()) { if (!pm->is_system_menu()) { - pm->unbind_global_menu(); - if (menu_cache[idx].global_index >= 0) { + if (menu_cache[idx].submenu_rid.is_valid()) { NativeMenu *nmenu = NativeMenu::get_singleton(); RID main_menu = nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID); - nmenu->remove_item(main_menu, menu_cache[idx].global_index); - menu_cache.write[idx].global_index = -1; + int item_idx = nmenu->find_item_index_with_submenu(main_menu, menu_cache[idx].submenu_rid); + if (item_idx >= 0) { + nmenu->remove_item(main_menu, item_idx); + } } + pm->unbind_global_menu(); } } + menu_cache.remove_at(idx); + p_child->remove_meta("_menu_name"); p_child->remove_meta("_menu_tooltip"); @@ -817,10 +829,13 @@ void MenuBar::set_menu_title(int p_menu, const String &p_title) { } menu_cache.write[p_menu].name = p_title; shape(menu_cache.write[p_menu]); - if (!global_menu_tag.is_empty() && menu_cache[p_menu].global_index >= 0) { + if (!global_menu_tag.is_empty() && menu_cache[p_menu].submenu_rid.is_valid()) { NativeMenu *nmenu = NativeMenu::get_singleton(); RID main_menu = nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID); - nmenu->set_item_text(main_menu, menu_cache[p_menu].global_index, atr(menu_cache[p_menu].name)); + int item_idx = nmenu->find_item_index_with_submenu(main_menu, menu_cache[p_menu].submenu_rid); + if (item_idx >= 0) { + nmenu->set_item_text(main_menu, item_idx, atr(menu_cache[p_menu].name)); + } } update_minimum_size(); } @@ -835,10 +850,13 @@ void MenuBar::set_menu_tooltip(int p_menu, const String &p_tooltip) { PopupMenu *pm = get_menu_popup(p_menu); pm->set_meta("_menu_tooltip", p_tooltip); menu_cache.write[p_menu].tooltip = p_tooltip; - if (!global_menu_tag.is_empty() && menu_cache[p_menu].global_index >= 0) { + if (!global_menu_tag.is_empty() && menu_cache[p_menu].submenu_rid.is_valid()) { NativeMenu *nmenu = NativeMenu::get_singleton(); RID main_menu = nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID); - nmenu->set_item_tooltip(main_menu, menu_cache[p_menu].global_index, p_tooltip); + int item_idx = nmenu->find_item_index_with_submenu(main_menu, menu_cache[p_menu].submenu_rid); + if (item_idx >= 0) { + nmenu->set_item_tooltip(main_menu, item_idx, p_tooltip); + } } } @@ -850,10 +868,13 @@ String MenuBar::get_menu_tooltip(int p_menu) const { void MenuBar::set_menu_disabled(int p_menu, bool p_disabled) { ERR_FAIL_INDEX(p_menu, menu_cache.size()); menu_cache.write[p_menu].disabled = p_disabled; - if (!global_menu_tag.is_empty() && menu_cache[p_menu].global_index >= 0) { + if (!global_menu_tag.is_empty() && menu_cache[p_menu].submenu_rid.is_valid()) { NativeMenu *nmenu = NativeMenu::get_singleton(); RID main_menu = nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID); - nmenu->set_item_disabled(main_menu, menu_cache[p_menu].global_index, p_disabled); + int item_idx = nmenu->find_item_index_with_submenu(main_menu, menu_cache[p_menu].submenu_rid); + if (item_idx >= 0) { + nmenu->set_item_disabled(main_menu, item_idx, p_disabled); + } } } @@ -865,10 +886,13 @@ bool MenuBar::is_menu_disabled(int p_menu) const { void MenuBar::set_menu_hidden(int p_menu, bool p_hidden) { ERR_FAIL_INDEX(p_menu, menu_cache.size()); menu_cache.write[p_menu].hidden = p_hidden; - if (!global_menu_tag.is_empty() && menu_cache[p_menu].global_index >= 0) { + if (!global_menu_tag.is_empty() && menu_cache[p_menu].submenu_rid.is_valid()) { NativeMenu *nmenu = NativeMenu::get_singleton(); RID main_menu = nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID); - nmenu->set_item_hidden(main_menu, menu_cache[p_menu].global_index, p_hidden); + int item_idx = nmenu->find_item_index_with_submenu(main_menu, menu_cache[p_menu].submenu_rid); + if (item_idx >= 0) { + nmenu->set_item_hidden(main_menu, item_idx, p_hidden); + } } update_minimum_size(); } diff --git a/scene/gui/menu_bar.h b/scene/gui/menu_bar.h index 631b791e1b5..04f6afc2fa7 100644 --- a/scene/gui/menu_bar.h +++ b/scene/gui/menu_bar.h @@ -55,7 +55,7 @@ class MenuBar : public Control { Ref text_buf; bool hidden = false; bool disabled = false; - int global_index = -1; + RID submenu_rid; Menu(const String &p_name) { name = p_name; diff --git a/servers/native_menu.cpp b/servers/native_menu.cpp index d1894ba6c31..ca46560c7c0 100644 --- a/servers/native_menu.cpp +++ b/servers/native_menu.cpp @@ -68,6 +68,7 @@ void NativeMenu::_bind_methods() { ClassDB::bind_method(D_METHOD("find_item_index_with_text", "rid", "text"), &NativeMenu::find_item_index_with_text); ClassDB::bind_method(D_METHOD("find_item_index_with_tag", "rid", "tag"), &NativeMenu::find_item_index_with_tag); + ClassDB::bind_method(D_METHOD("find_item_index_with_submenu", "rid", "submenu_rid"), &NativeMenu::find_item_index_with_submenu); ClassDB::bind_method(D_METHOD("is_item_checked", "rid", "idx"), &NativeMenu::is_item_checked); ClassDB::bind_method(D_METHOD("is_item_checkable", "rid", "idx"), &NativeMenu::is_item_checkable); @@ -263,6 +264,19 @@ int NativeMenu::find_item_index_with_tag(const RID &p_rid, const Variant &p_tag) return -1; } +int NativeMenu::find_item_index_with_submenu(const RID &p_rid, const RID &p_submenu_rid) const { + if (!has_menu(p_rid) || !has_menu(p_submenu_rid)) { + return -1; + } + int count = get_item_count(p_rid); + for (int i = 0; i < count; i++) { + if (p_submenu_rid == get_item_submenu(p_rid, i)) { + return i; + } + } + return -1; +} + bool NativeMenu::is_item_checked(const RID &p_rid, int p_idx) const { WARN_PRINT("Global menus are not supported on this platform."); return false; diff --git a/servers/native_menu.h b/servers/native_menu.h index f65e193972a..2bc061a2162 100644 --- a/servers/native_menu.h +++ b/servers/native_menu.h @@ -102,6 +102,7 @@ public: virtual int find_item_index_with_text(const RID &p_rid, const String &p_text) const; virtual int find_item_index_with_tag(const RID &p_rid, const Variant &p_tag) const; + virtual int find_item_index_with_submenu(const RID &p_rid, const RID &p_submenu_rid) const; virtual bool is_item_checked(const RID &p_rid, int p_idx) const; virtual bool is_item_checkable(const RID &p_rid, int p_idx) const;