Browse Source

Merge pull request #89875 from bruvzg/menu_use_rids

[MenuBar] Use NativeMenu RIDs instead of indices to track items.
Rémi Verschelde 1 year ago
parent
commit
0acfb38376

+ 2 - 2
doc/classes/DisplayServer.xml

@@ -553,7 +553,7 @@
 			<param index="0" name="menu_root" type="String" />
 			<param index="1" name="tag" type="Variant" />
 			<description>
-				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.
 			</description>
 		</method>
@@ -562,7 +562,7 @@
 			<param index="0" name="menu_root" type="String" />
 			<param index="1" name="text" type="String" />
 			<description>
-				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.
 			</description>
 		</method>

+ 11 - 2
doc/classes/NativeMenu.xml

@@ -211,12 +211,21 @@
 				[b]Note:[/b] This method is implemented on macOS and Windows.
 			</description>
 		</method>
+		<method name="find_item_index_with_submenu" qualifiers="const">
+			<return type="int" />
+			<param index="0" name="rid" type="RID" />
+			<param index="1" name="submenu_rid" type="RID" />
+			<description>
+				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.
+			</description>
+		</method>
 		<method name="find_item_index_with_tag" qualifiers="const">
 			<return type="int" />
 			<param index="0" name="rid" type="RID" />
 			<param index="1" name="tag" type="Variant" />
 			<description>
-				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.
 			</description>
 		</method>
@@ -225,7 +234,7 @@
 			<param index="0" name="rid" type="RID" />
 			<param index="1" name="text" type="String" />
 			<description>
-				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.
 			</description>
 		</method>

+ 55 - 31
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<PopupMenu *> 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();
 }

+ 1 - 1
scene/gui/menu_bar.h

@@ -55,7 +55,7 @@ class MenuBar : public Control {
 		Ref<TextLine> text_buf;
 		bool hidden = false;
 		bool disabled = false;
-		int global_index = -1;
+		RID submenu_rid;
 
 		Menu(const String &p_name) {
 			name = p_name;

+ 14 - 0
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;

+ 1 - 0
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;