| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /*  menu_bar.cpp                                                          */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /*                         This file is part of:                          */ | 
					
						
							|  |  |  | /*                             GODOT ENGINE                               */ | 
					
						
							|  |  |  | /*                        https://godotengine.org                         */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ | 
					
						
							|  |  |  | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */ | 
					
						
							|  |  |  | /*                                                                        */ | 
					
						
							|  |  |  | /* Permission is hereby granted, free of charge, to any person obtaining  */ | 
					
						
							|  |  |  | /* a copy of this software and associated documentation files (the        */ | 
					
						
							|  |  |  | /* "Software"), to deal in the Software without restriction, including    */ | 
					
						
							|  |  |  | /* without limitation the rights to use, copy, modify, merge, publish,    */ | 
					
						
							|  |  |  | /* distribute, sublicense, and/or sell copies of the Software, and to     */ | 
					
						
							|  |  |  | /* permit persons to whom the Software is furnished to do so, subject to  */ | 
					
						
							|  |  |  | /* the following conditions:                                              */ | 
					
						
							|  |  |  | /*                                                                        */ | 
					
						
							|  |  |  | /* The above copyright notice and this permission notice shall be         */ | 
					
						
							|  |  |  | /* included in all copies or substantial portions of the Software.        */ | 
					
						
							|  |  |  | /*                                                                        */ | 
					
						
							|  |  |  | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */ | 
					
						
							|  |  |  | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */ | 
					
						
							|  |  |  | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ | 
					
						
							|  |  |  | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */ | 
					
						
							|  |  |  | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */ | 
					
						
							|  |  |  | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */ | 
					
						
							|  |  |  | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "menu_bar.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "scene/main/window.h"
 | 
					
						
							| 
									
										
										
										
											2023-09-08 21:00:10 +02:00
										 |  |  | #include "scene/theme/theme_db.h"
 | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | void MenuBar::gui_input(const Ref<InputEvent> &p_event) { | 
					
						
							|  |  |  | 	ERR_FAIL_COND(p_event.is_null()); | 
					
						
							|  |  |  | 	if (is_native_menu()) { | 
					
						
							|  |  |  | 		// Handled by OS.
 | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	MutexLock lock(mutex); | 
					
						
							| 
									
										
										
										
											2022-09-24 18:01:02 +10:00
										 |  |  | 	if (p_event->is_action("ui_left", true) && p_event->is_pressed()) { | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		int new_sel = selected_menu; | 
					
						
							|  |  |  | 		int old_sel = (selected_menu < 0) ? 0 : selected_menu; | 
					
						
							|  |  |  | 		do { | 
					
						
							|  |  |  | 			new_sel--; | 
					
						
							|  |  |  | 			if (new_sel < 0) { | 
					
						
							|  |  |  | 				new_sel = menu_cache.size() - 1; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (old_sel == new_sel) { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} while (menu_cache[new_sel].hidden || menu_cache[new_sel].disabled); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (selected_menu != new_sel) { | 
					
						
							|  |  |  | 			selected_menu = new_sel; | 
					
						
							|  |  |  | 			focused_menu = selected_menu; | 
					
						
							|  |  |  | 			if (active_menu >= 0) { | 
					
						
							|  |  |  | 				get_menu_popup(active_menu)->hide(); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-08-27 20:56:34 -03:00
										 |  |  | 			_open_popup(selected_menu, true); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2022-09-24 18:01:02 +10:00
										 |  |  | 	} else if (p_event->is_action("ui_right", true) && p_event->is_pressed()) { | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		int new_sel = selected_menu; | 
					
						
							|  |  |  | 		int old_sel = (selected_menu < 0) ? menu_cache.size() - 1 : selected_menu; | 
					
						
							|  |  |  | 		do { | 
					
						
							|  |  |  | 			new_sel++; | 
					
						
							|  |  |  | 			if (new_sel >= menu_cache.size()) { | 
					
						
							|  |  |  | 				new_sel = 0; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (old_sel == new_sel) { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} while (menu_cache[new_sel].hidden || menu_cache[new_sel].disabled); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (selected_menu != new_sel) { | 
					
						
							|  |  |  | 			selected_menu = new_sel; | 
					
						
							|  |  |  | 			focused_menu = selected_menu; | 
					
						
							|  |  |  | 			if (active_menu >= 0) { | 
					
						
							|  |  |  | 				get_menu_popup(active_menu)->hide(); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-08-27 20:56:34 -03:00
										 |  |  | 			_open_popup(selected_menu, true); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2025-03-21 16:42:23 +02:00
										 |  |  | 	} else if (p_event->is_action("ui_accept", true) && p_event->is_pressed()) { | 
					
						
							|  |  |  | 		if (focused_menu == -1) { | 
					
						
							|  |  |  | 			focused_menu = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		selected_menu = focused_menu; | 
					
						
							|  |  |  | 		if (active_menu >= 0) { | 
					
						
							|  |  |  | 			get_menu_popup(active_menu)->hide(); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		_open_popup(selected_menu, true); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Ref<InputEventMouseMotion> mm = p_event; | 
					
						
							|  |  |  | 	if (mm.is_valid()) { | 
					
						
							|  |  |  | 		int old_sel = selected_menu; | 
					
						
							|  |  |  | 		focused_menu = _get_index_at_point(mm->get_position()); | 
					
						
							|  |  |  | 		if (focused_menu >= 0) { | 
					
						
							|  |  |  | 			selected_menu = focused_menu; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (selected_menu != old_sel) { | 
					
						
							| 
									
										
										
										
											2022-08-13 23:21:24 +02:00
										 |  |  | 			queue_redraw(); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Ref<InputEventMouseButton> mb = p_event; | 
					
						
							|  |  |  | 	if (mb.is_valid()) { | 
					
						
							|  |  |  | 		if (mb->is_pressed() && (mb->get_button_index() == MouseButton::LEFT || mb->get_button_index() == MouseButton::RIGHT)) { | 
					
						
							|  |  |  | 			int index = _get_index_at_point(mb->get_position()); | 
					
						
							|  |  |  | 			if (index >= 0) { | 
					
						
							|  |  |  | 				_open_popup(index); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-27 20:56:34 -03:00
										 |  |  | void MenuBar::_open_popup(int p_index, bool p_focus_item) { | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 	ERR_FAIL_INDEX(p_index, menu_cache.size()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	PopupMenu *pm = get_menu_popup(p_index); | 
					
						
							|  |  |  | 	if (pm->is_visible()) { | 
					
						
							|  |  |  | 		pm->hide(); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Rect2 item_rect = _get_menu_item_rect(p_index); | 
					
						
							| 
									
										
										
										
											2024-06-06 16:46:13 +02:00
										 |  |  | 	Size2 canvas_scale = get_canvas_transform().get_scale(); | 
					
						
							|  |  |  | 	Point2 screen_pos = get_screen_position() + item_rect.position * canvas_scale; | 
					
						
							|  |  |  | 	Size2 screen_size = item_rect.size * canvas_scale; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	active_menu = p_index; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pm->set_size(Size2(screen_size.x, 0)); | 
					
						
							|  |  |  | 	screen_pos.y += screen_size.y; | 
					
						
							|  |  |  | 	if (is_layout_rtl()) { | 
					
						
							|  |  |  | 		screen_pos.x += screen_size.x - pm->get_size().width; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	pm->set_position(screen_pos); | 
					
						
							|  |  |  | 	pm->popup(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-27 20:56:34 -03:00
										 |  |  | 	if (p_focus_item) { | 
					
						
							|  |  |  | 		for (int i = 0; i < pm->get_item_count(); i++) { | 
					
						
							|  |  |  | 			if (!pm->is_item_disabled(i)) { | 
					
						
							| 
									
										
										
										
											2022-09-06 10:51:14 -03:00
										 |  |  | 				pm->set_focused_item(i); | 
					
						
							| 
									
										
										
										
											2022-08-27 20:56:34 -03:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-13 23:21:24 +02:00
										 |  |  | 	queue_redraw(); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MenuBar::shortcut_input(const Ref<InputEvent> &p_event) { | 
					
						
							|  |  |  | 	ERR_FAIL_COND(p_event.is_null()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (disable_shortcuts) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-23 22:23:34 +01:00
										 |  |  | 	if (p_event->is_pressed() && (Object::cast_to<InputEventKey>(p_event.ptr()) || Object::cast_to<InputEventJoypadButton>(p_event.ptr()) || Object::cast_to<InputEventAction>(*p_event) || Object::cast_to<InputEventShortcut>(*p_event))) { | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		if (!get_parent() || !is_visible_in_tree()) { | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		Vector<PopupMenu *> popups = _get_popups(); | 
					
						
							|  |  |  | 		for (int i = 0; i < popups.size(); i++) { | 
					
						
							|  |  |  | 			if (menu_cache[i].hidden || menu_cache[i].disabled) { | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (popups[i]->activate_item_by_event(p_event, false)) { | 
					
						
							|  |  |  | 				accept_event(); | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MenuBar::_popup_visibility_changed(bool p_visible) { | 
					
						
							|  |  |  | 	if (!p_visible) { | 
					
						
							|  |  |  | 		active_menu = -1; | 
					
						
							|  |  |  | 		focused_menu = -1; | 
					
						
							|  |  |  | 		set_process_internal(false); | 
					
						
							| 
									
										
										
										
											2022-08-13 23:21:24 +02:00
										 |  |  | 		queue_redraw(); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (switch_on_hover) { | 
					
						
							| 
									
										
										
										
											2023-12-18 18:07:34 +02:00
										 |  |  | 		set_process_internal(true); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool MenuBar::is_native_menu() const { | 
					
						
							| 
									
										
										
										
											2023-03-17 01:58:30 +01:00
										 |  |  | #ifdef TOOLS_ENABLED
 | 
					
						
							|  |  |  | 	if (is_part_of_edited_scene()) { | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-03-17 01:58:30 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-07 20:42:24 +02:00
										 |  |  | 	return (NativeMenu::get_singleton()->has_feature(NativeMenu::FEATURE_GLOBAL_MENU) && prefer_native); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 19:41:01 +02:00
										 |  |  | void MenuBar::bind_global_menu() { | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | #ifdef TOOLS_ENABLED
 | 
					
						
							|  |  |  | 	if (is_part_of_edited_scene()) { | 
					
						
							| 
									
										
										
										
											2024-01-19 19:41:01 +02:00
										 |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2024-01-19 19:41:01 +02:00
										 |  |  | 	if (!NativeMenu::get_singleton()->has_feature(NativeMenu::FEATURE_GLOBAL_MENU)) { | 
					
						
							|  |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 19:41:01 +02:00
										 |  |  | 	if (!global_menu_tag.is_empty()) { | 
					
						
							|  |  |  | 		return; // Already bound.
 | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 19:41:01 +02:00
										 |  |  | 	NativeMenu *nmenu = NativeMenu::get_singleton(); | 
					
						
							|  |  |  | 	RID main_menu = nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	global_menu_tag = "__MenuBar#" + itos(get_instance_id()); | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	int global_start_idx = -1; | 
					
						
							| 
									
										
										
										
											2024-01-19 19:41:01 +02:00
										 |  |  | 	int count = nmenu->get_item_count(main_menu); | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 	String prev_tag; | 
					
						
							| 
									
										
										
										
											2024-09-02 22:48:58 +03:00
										 |  |  | 	if (start_index >= 0) { | 
					
						
							|  |  |  | 		for (int i = 0; i < count; i++) { | 
					
						
							| 
									
										
										
										
											2024-11-16 17:16:07 +01:00
										 |  |  | 			String tag = nmenu->get_item_tag(main_menu, i).operator String().get_slicec('#', 1); | 
					
						
							| 
									
										
										
										
											2024-09-02 22:48:58 +03:00
										 |  |  | 			if (!tag.is_empty() && tag != prev_tag) { | 
					
						
							| 
									
										
										
										
											2025-03-27 14:42:42 +01:00
										 |  |  | 				MenuBar *mb = ObjectDB::get_instance<MenuBar>(ObjectID(static_cast<uint64_t>(tag.to_int()))); | 
					
						
							| 
									
										
										
										
											2024-09-02 22:48:58 +03:00
										 |  |  | 				if (mb && mb->get_start_index() >= start_index) { | 
					
						
							|  |  |  | 					global_start_idx = i; | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2024-09-02 22:48:58 +03:00
										 |  |  | 			prev_tag = tag; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 	if (global_start_idx == -1) { | 
					
						
							|  |  |  | 		global_start_idx = count; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 	Vector<PopupMenu *> popups = _get_popups(); | 
					
						
							|  |  |  | 	for (int i = 0; i < menu_cache.size(); i++) { | 
					
						
							| 
									
										
										
										
											2024-01-19 19:41:01 +02:00
										 |  |  | 		RID submenu_rid = popups[i]->bind_global_menu(); | 
					
						
							| 
									
										
										
										
											2023-10-15 20:52:56 +03:00
										 |  |  | 		if (!popups[i]->is_system_menu()) { | 
					
						
							| 
									
										
										
										
											2024-01-19 19:41:01 +02:00
										 |  |  | 			int index = nmenu->add_submenu_item(main_menu, menu_cache[i].name, submenu_rid, global_menu_tag + "#" + itos(i), global_start_idx + i); | 
					
						
							| 
									
										
										
										
											2024-03-25 10:41:03 +02:00
										 |  |  | 			menu_cache.write[i].submenu_rid = submenu_rid; | 
					
						
							| 
									
										
										
										
											2024-01-19 19:41:01 +02:00
										 |  |  | 			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); | 
					
						
							| 
									
										
										
										
											2023-12-19 09:57:48 +02:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2024-03-25 10:41:03 +02:00
										 |  |  | 			menu_cache.write[i].submenu_rid = RID(); | 
					
						
							| 
									
										
										
										
											2023-10-15 20:52:56 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | void MenuBar::unbind_global_menu() { | 
					
						
							| 
									
										
										
										
											2024-01-19 19:41:01 +02:00
										 |  |  | 	if (global_menu_tag.is_empty()) { | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 19:41:01 +02:00
										 |  |  | 	NativeMenu *nmenu = NativeMenu::get_singleton(); | 
					
						
							|  |  |  | 	RID main_menu = nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 	Vector<PopupMenu *> popups = _get_popups(); | 
					
						
							|  |  |  | 	for (int i = menu_cache.size() - 1; i >= 0; i--) { | 
					
						
							| 
									
										
										
										
											2023-10-15 20:52:56 +03:00
										 |  |  | 		if (!popups[i]->is_system_menu()) { | 
					
						
							| 
									
										
										
										
											2024-03-25 10:41:03 +02:00
										 |  |  | 			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); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2023-12-19 09:57:48 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2024-03-25 10:41:03 +02:00
										 |  |  | 			popups[i]->unbind_global_menu(); | 
					
						
							|  |  |  | 			menu_cache.write[i].submenu_rid = RID(); | 
					
						
							| 
									
										
										
										
											2023-10-15 20:52:56 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 19:41:01 +02:00
										 |  |  | 	global_menu_tag = String(); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MenuBar::_notification(int p_what) { | 
					
						
							|  |  |  | 	switch (p_what) { | 
					
						
							| 
									
										
										
										
											2025-03-21 16:42:23 +02:00
										 |  |  | 		case NOTIFICATION_ACCESSIBILITY_UPDATE: { | 
					
						
							|  |  |  | 			RID ae = get_accessibility_element(); | 
					
						
							|  |  |  | 			ERR_FAIL_COND(ae.is_null()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_MENU_BAR); | 
					
						
							|  |  |  | 		} break; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		case NOTIFICATION_ENTER_TREE: { | 
					
						
							|  |  |  | 			if (get_menu_count() > 0) { | 
					
						
							|  |  |  | 				_refresh_menu_names(); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 			if (is_native_menu()) { | 
					
						
							|  |  |  | 				bind_global_menu(); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} break; | 
					
						
							|  |  |  | 		case NOTIFICATION_EXIT_TREE: { | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 			unbind_global_menu(); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} break; | 
					
						
							|  |  |  | 		case NOTIFICATION_MOUSE_EXIT: { | 
					
						
							|  |  |  | 			focused_menu = -1; | 
					
						
							| 
									
										
										
										
											2022-12-29 01:59:05 +01:00
										 |  |  | 			selected_menu = -1; | 
					
						
							| 
									
										
										
										
											2022-08-13 23:21:24 +02:00
										 |  |  | 			queue_redraw(); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} break; | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 		case NOTIFICATION_TRANSLATION_CHANGED: { | 
					
						
							| 
									
										
										
										
											2024-01-19 19:41:01 +02:00
										 |  |  | 			NativeMenu *nmenu = NativeMenu::get_singleton(); | 
					
						
							|  |  |  | 			bool is_global = !global_menu_tag.is_empty(); | 
					
						
							| 
									
										
										
										
											2024-03-06 20:29:31 +02:00
										 |  |  | 			RID main_menu = is_global ? nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID) : RID(); | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 			for (int i = 0; i < menu_cache.size(); i++) { | 
					
						
							|  |  |  | 				shape(menu_cache.write[i]); | 
					
						
							| 
									
										
										
										
											2024-03-25 10:41:03 +02:00
										 |  |  | 				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)); | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2025-06-15 13:21:31 +08:00
										 |  |  | 			if (!is_global) { | 
					
						
							|  |  |  | 				update_minimum_size(); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 		} break; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: | 
					
						
							|  |  |  | 		case NOTIFICATION_THEME_CHANGED: { | 
					
						
							|  |  |  | 			for (int i = 0; i < menu_cache.size(); i++) { | 
					
						
							|  |  |  | 				shape(menu_cache.write[i]); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2025-06-15 13:21:31 +08:00
										 |  |  | 			if (global_menu_tag.is_empty()) { | 
					
						
							|  |  |  | 				update_minimum_size(); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} break; | 
					
						
							|  |  |  | 		case NOTIFICATION_VISIBILITY_CHANGED: { | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 			if (is_native_menu()) { | 
					
						
							|  |  |  | 				if (is_visible_in_tree()) { | 
					
						
							|  |  |  | 					bind_global_menu(); | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					unbind_global_menu(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} break; | 
					
						
							|  |  |  | 		case NOTIFICATION_DRAW: { | 
					
						
							|  |  |  | 			if (is_native_menu()) { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			for (int i = 0; i < menu_cache.size(); i++) { | 
					
						
							|  |  |  | 				_draw_menu_item(i); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} break; | 
					
						
							|  |  |  | 		case NOTIFICATION_INTERNAL_PROCESS: { | 
					
						
							|  |  |  | 			MutexLock lock(mutex); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-31 11:11:52 +03:00
										 |  |  | 			if (is_native_menu()) { | 
					
						
							|  |  |  | 				// Handled by OS.
 | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-12-18 18:07:34 +02:00
										 |  |  | 			Vector2 pos = get_local_mouse_position(); | 
					
						
							| 
									
										
										
										
											2022-08-30 20:18:06 -03:00
										 |  |  | 			if (pos == old_mouse_pos) { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			old_mouse_pos = pos; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 			int index = _get_index_at_point(pos); | 
					
						
							|  |  |  | 			if (index >= 0 && index != active_menu) { | 
					
						
							|  |  |  | 				selected_menu = index; | 
					
						
							|  |  |  | 				focused_menu = selected_menu; | 
					
						
							| 
									
										
										
										
											2022-08-31 11:11:52 +03:00
										 |  |  | 				if (active_menu >= 0) { | 
					
						
							|  |  |  | 					get_menu_popup(active_menu)->hide(); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 				_open_popup(index); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int MenuBar::_get_index_at_point(const Point2 &p_point) const { | 
					
						
							| 
									
										
										
										
											2022-08-31 15:02:40 +03:00
										 |  |  | 	Ref<StyleBox> style = theme_cache.normal; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 	int offset = 0; | 
					
						
							| 
									
										
										
										
											2023-05-26 17:02:00 +03:00
										 |  |  | 	Point2 point = p_point; | 
					
						
							|  |  |  | 	if (is_layout_rtl()) { | 
					
						
							|  |  |  | 		point.x = get_size().x - point.x; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 	for (int i = 0; i < menu_cache.size(); i++) { | 
					
						
							|  |  |  | 		if (menu_cache[i].hidden) { | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		Size2 size = menu_cache[i].text_buf->get_size() + style->get_minimum_size(); | 
					
						
							| 
									
										
										
										
											2023-05-26 17:02:00 +03:00
										 |  |  | 		if (point.x > offset && point.x < offset + size.x) { | 
					
						
							|  |  |  | 			if (point.y > 0 && point.y < size.y) { | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 				return i; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-08-31 15:02:40 +03:00
										 |  |  | 		offset += size.x + theme_cache.h_separation; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Rect2 MenuBar::_get_menu_item_rect(int p_index) const { | 
					
						
							|  |  |  | 	ERR_FAIL_INDEX_V(p_index, menu_cache.size(), Rect2()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-31 15:02:40 +03:00
										 |  |  | 	Ref<StyleBox> style = theme_cache.normal; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	int offset = 0; | 
					
						
							|  |  |  | 	for (int i = 0; i < p_index; i++) { | 
					
						
							|  |  |  | 		if (menu_cache[i].hidden) { | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		Size2 size = menu_cache[i].text_buf->get_size() + style->get_minimum_size(); | 
					
						
							| 
									
										
										
										
											2022-08-31 15:02:40 +03:00
										 |  |  | 		offset += size.x + theme_cache.h_separation; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-26 17:02:00 +03:00
										 |  |  | 	Size2 size = menu_cache[p_index].text_buf->get_size() + style->get_minimum_size(); | 
					
						
							|  |  |  | 	if (is_layout_rtl()) { | 
					
						
							|  |  |  | 		return Rect2(Point2(get_size().x - offset - size.x, 0), size); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		return Rect2(Point2(offset, 0), size); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MenuBar::_draw_menu_item(int p_index) { | 
					
						
							|  |  |  | 	ERR_FAIL_INDEX(p_index, menu_cache.size()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	RID ci = get_canvas_item(); | 
					
						
							|  |  |  | 	bool hovered = (focused_menu == p_index); | 
					
						
							|  |  |  | 	bool pressed = (active_menu == p_index); | 
					
						
							|  |  |  | 	bool rtl = is_layout_rtl(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (menu_cache[p_index].hidden) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Color color; | 
					
						
							| 
									
										
										
										
											2023-06-09 17:00:50 +02:00
										 |  |  | 	Ref<StyleBox> style; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 	Rect2 item_rect = _get_menu_item_rect(p_index); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (menu_cache[p_index].disabled) { | 
					
						
							|  |  |  | 		if (rtl && has_theme_stylebox(SNAME("disabled_mirrored"))) { | 
					
						
							| 
									
										
										
										
											2022-08-31 15:02:40 +03:00
										 |  |  | 			style = theme_cache.disabled_mirrored; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2022-08-31 15:02:40 +03:00
										 |  |  | 			style = theme_cache.disabled; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if (!flat) { | 
					
						
							|  |  |  | 			style->draw(ci, item_rect); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-08-31 15:02:40 +03:00
										 |  |  | 		color = theme_cache.font_disabled_color; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 	} else if (hovered && pressed && has_theme_stylebox("hover_pressed")) { | 
					
						
							|  |  |  | 		if (rtl && has_theme_stylebox(SNAME("hover_pressed_mirrored"))) { | 
					
						
							| 
									
										
										
										
											2022-08-31 15:02:40 +03:00
										 |  |  | 			style = theme_cache.hover_pressed_mirrored; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2022-08-31 15:02:40 +03:00
										 |  |  | 			style = theme_cache.hover_pressed; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if (!flat) { | 
					
						
							|  |  |  | 			style->draw(ci, item_rect); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (has_theme_color(SNAME("font_hover_pressed_color"))) { | 
					
						
							| 
									
										
										
										
											2022-08-31 15:02:40 +03:00
										 |  |  | 			color = theme_cache.font_hover_pressed_color; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} else if (pressed) { | 
					
						
							|  |  |  | 		if (rtl && has_theme_stylebox(SNAME("pressed_mirrored"))) { | 
					
						
							| 
									
										
										
										
											2022-08-31 15:02:40 +03:00
										 |  |  | 			style = theme_cache.pressed_mirrored; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2022-08-31 15:02:40 +03:00
										 |  |  | 			style = theme_cache.pressed; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if (!flat) { | 
					
						
							|  |  |  | 			style->draw(ci, item_rect); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (has_theme_color(SNAME("font_pressed_color"))) { | 
					
						
							| 
									
										
										
										
											2022-08-31 15:02:40 +03:00
										 |  |  | 			color = theme_cache.font_pressed_color; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2022-08-31 15:02:40 +03:00
										 |  |  | 			color = theme_cache.font_color; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} else if (hovered) { | 
					
						
							|  |  |  | 		if (rtl && has_theme_stylebox(SNAME("hover_mirrored"))) { | 
					
						
							| 
									
										
										
										
											2022-08-31 15:02:40 +03:00
										 |  |  | 			style = theme_cache.hover_mirrored; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2022-08-31 15:02:40 +03:00
										 |  |  | 			style = theme_cache.hover; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if (!flat) { | 
					
						
							|  |  |  | 			style->draw(ci, item_rect); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-08-31 15:02:40 +03:00
										 |  |  | 		color = theme_cache.font_hover_color; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		if (rtl && has_theme_stylebox(SNAME("normal_mirrored"))) { | 
					
						
							| 
									
										
										
										
											2022-08-31 15:02:40 +03:00
										 |  |  | 			style = theme_cache.normal_mirrored; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2022-08-31 15:02:40 +03:00
										 |  |  | 			style = theme_cache.normal; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if (!flat) { | 
					
						
							|  |  |  | 			style->draw(ci, item_rect); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Focus colors only take precedence over normal state.
 | 
					
						
							| 
									
										
										
										
											2025-09-03 20:39:18 -03:00
										 |  |  | 		if (has_focus(true)) { | 
					
						
							| 
									
										
										
										
											2022-08-31 15:02:40 +03:00
										 |  |  | 			color = theme_cache.font_focus_color; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2022-08-31 15:02:40 +03:00
										 |  |  | 			color = theme_cache.font_color; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Point2 text_ofs = item_rect.position + Point2(style->get_margin(SIDE_LEFT), style->get_margin(SIDE_TOP)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-31 15:02:40 +03:00
										 |  |  | 	Color font_outline_color = theme_cache.font_outline_color; | 
					
						
							|  |  |  | 	int outline_size = theme_cache.outline_size; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 	if (outline_size > 0 && font_outline_color.a > 0) { | 
					
						
							|  |  |  | 		menu_cache[p_index].text_buf->draw_outline(ci, text_ofs, outline_size, font_outline_color); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	menu_cache[p_index].text_buf->draw(ci, text_ofs, color); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MenuBar::shape(Menu &p_menu) { | 
					
						
							|  |  |  | 	p_menu.text_buf->clear(); | 
					
						
							|  |  |  | 	if (text_direction == Control::TEXT_DIRECTION_INHERITED) { | 
					
						
							|  |  |  | 		p_menu.text_buf->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		p_menu.text_buf->set_direction((TextServer::Direction)text_direction); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-10 15:14:18 +08:00
										 |  |  | 	const String &lang = language.is_empty() ? _get_locale() : language; | 
					
						
							|  |  |  | 	p_menu.text_buf->add_string(atr(p_menu.name), theme_cache.font, theme_cache.font_size, lang); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MenuBar::_refresh_menu_names() { | 
					
						
							| 
									
										
										
										
											2024-01-19 19:41:01 +02:00
										 |  |  | 	NativeMenu *nmenu = NativeMenu::get_singleton(); | 
					
						
							|  |  |  | 	bool is_global = !global_menu_tag.is_empty(); | 
					
						
							| 
									
										
										
										
											2024-03-06 20:29:31 +02:00
										 |  |  | 	RID main_menu = is_global ? nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID) : RID(); | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-26 14:12:38 +08:00
										 |  |  | 	bool dirty = false; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 	Vector<PopupMenu *> popups = _get_popups(); | 
					
						
							|  |  |  | 	for (int i = 0; i < popups.size(); i++) { | 
					
						
							| 
									
										
										
										
											2024-12-20 23:35:07 +02:00
										 |  |  | 		String menu_name = popups[i]->get_title().is_empty() ? String(popups[i]->get_name()) : popups[i]->get_title(); | 
					
						
							|  |  |  | 		if (!popups[i]->has_meta("_menu_name") && menu_name != get_menu_title(i)) { | 
					
						
							|  |  |  | 			menu_cache.write[i].name = menu_name; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 			shape(menu_cache.write[i]); | 
					
						
							| 
									
										
										
										
											2025-05-26 14:12:38 +08:00
										 |  |  | 			dirty = true; | 
					
						
							| 
									
										
										
										
											2024-03-25 10:41:03 +02:00
										 |  |  | 			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)); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-05-26 14:12:38 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (dirty && !is_global) { | 
					
						
							|  |  |  | 		queue_redraw(); | 
					
						
							|  |  |  | 		update_minimum_size(); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Vector<PopupMenu *> MenuBar::_get_popups() const { | 
					
						
							|  |  |  | 	Vector<PopupMenu *> popups; | 
					
						
							|  |  |  | 	for (int i = 0; i < get_child_count(); i++) { | 
					
						
							|  |  |  | 		PopupMenu *pm = Object::cast_to<PopupMenu>(get_child(i)); | 
					
						
							|  |  |  | 		if (!pm) { | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		popups.push_back(pm); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return popups; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int MenuBar::get_menu_idx_from_control(PopupMenu *p_child) const { | 
					
						
							|  |  |  | 	ERR_FAIL_NULL_V(p_child, -1); | 
					
						
							|  |  |  | 	ERR_FAIL_COND_V(p_child->get_parent() != this, -1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Vector<PopupMenu *> popups = _get_popups(); | 
					
						
							|  |  |  | 	for (int i = 0; i < popups.size(); i++) { | 
					
						
							|  |  |  | 		if (popups[i] == p_child) { | 
					
						
							|  |  |  | 			return i; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-20 23:35:07 +02:00
										 |  |  | void MenuBar::_popup_changed(ObjectID p_menu) { | 
					
						
							| 
									
										
										
										
											2025-03-27 14:42:42 +01:00
										 |  |  | 	PopupMenu *pm = ObjectDB::get_instance<PopupMenu>(p_menu); | 
					
						
							| 
									
										
										
										
											2024-12-20 23:35:07 +02:00
										 |  |  | 	if (!pm) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int idx = get_menu_idx_from_control(pm); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	String menu_name = pm->get_title().is_empty() ? String(pm->get_name()) : pm->get_title(); | 
					
						
							|  |  |  | 	menu_name = String(pm->get_meta("_menu_name", menu_name)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	menu_cache.write[idx].name = menu_name; | 
					
						
							|  |  |  | 	shape(menu_cache.write[idx]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	update_minimum_size(); | 
					
						
							|  |  |  | 	queue_redraw(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | void MenuBar::add_child_notify(Node *p_child) { | 
					
						
							|  |  |  | 	Control::add_child_notify(p_child); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	PopupMenu *pm = Object::cast_to<PopupMenu>(p_child); | 
					
						
							|  |  |  | 	if (!pm) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-12-20 23:35:07 +02:00
										 |  |  | 	String menu_name = pm->get_title().is_empty() ? String(pm->get_name()) : pm->get_title(); | 
					
						
							|  |  |  | 	Menu menu = Menu(menu_name); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 	shape(menu); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-20 23:35:07 +02:00
										 |  |  | 	pm->connect("title_changed", callable_mp(this, &MenuBar::_popup_changed).bind(pm->get_instance_id()), CONNECT_REFERENCE_COUNTED); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 	menu_cache.push_back(menu); | 
					
						
							|  |  |  | 	p_child->connect("renamed", callable_mp(this, &MenuBar::_refresh_menu_names)); | 
					
						
							|  |  |  | 	p_child->connect("about_to_popup", callable_mp(this, &MenuBar::_popup_visibility_changed).bind(true)); | 
					
						
							|  |  |  | 	p_child->connect("popup_hide", callable_mp(this, &MenuBar::_popup_visibility_changed).bind(false)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 19:41:01 +02:00
										 |  |  | 	if (!global_menu_tag.is_empty()) { | 
					
						
							|  |  |  | 		NativeMenu *nmenu = NativeMenu::get_singleton(); | 
					
						
							|  |  |  | 		RID main_menu = nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		RID submenu_rid = pm->bind_global_menu(); | 
					
						
							| 
									
										
										
										
											2023-10-15 20:52:56 +03:00
										 |  |  | 		if (!pm->is_system_menu()) { | 
					
						
							| 
									
										
										
										
											2024-03-25 10:41:03 +02:00
										 |  |  | 			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; | 
					
						
							| 
									
										
										
										
											2023-10-15 20:52:56 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-10-25 22:14:29 +03:00
										 |  |  | 	update_minimum_size(); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MenuBar::move_child_notify(Node *p_child) { | 
					
						
							|  |  |  | 	Control::move_child_notify(p_child); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	PopupMenu *pm = Object::cast_to<PopupMenu>(p_child); | 
					
						
							|  |  |  | 	if (!pm) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int old_idx = -1; | 
					
						
							| 
									
										
										
										
											2024-12-20 23:35:07 +02:00
										 |  |  | 	String menu_name = pm->get_title().is_empty() ? String(pm->get_name()) : pm->get_title(); | 
					
						
							|  |  |  | 	menu_name = String(pm->get_meta("_menu_name", menu_name)); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 	// Find the previous menu index of the control.
 | 
					
						
							|  |  |  | 	for (int i = 0; i < get_menu_count(); i++) { | 
					
						
							|  |  |  | 		if (get_menu_title(i) == menu_name) { | 
					
						
							|  |  |  | 			old_idx = i; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	Menu menu = menu_cache[old_idx]; | 
					
						
							|  |  |  | 	menu_cache.remove_at(old_idx); | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 	int new_idx = get_menu_idx_from_control(pm); | 
					
						
							|  |  |  | 	menu_cache.insert(new_idx, menu); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 19:41:01 +02:00
										 |  |  | 	if (!global_menu_tag.is_empty()) { | 
					
						
							| 
									
										
										
										
											2023-10-15 20:52:56 +03:00
										 |  |  | 		if (!pm->is_system_menu()) { | 
					
						
							| 
									
										
										
										
											2024-01-19 19:41:01 +02:00
										 |  |  | 			NativeMenu *nmenu = NativeMenu::get_singleton(); | 
					
						
							|  |  |  | 			RID main_menu = nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-15 20:52:56 +03:00
										 |  |  | 			int global_start = _find_global_start_index(); | 
					
						
							| 
									
										
										
										
											2024-03-25 10:41:03 +02:00
										 |  |  | 			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); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2023-10-15 20:52:56 +03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			if (new_idx != -1) { | 
					
						
							| 
									
										
										
										
											2024-03-25 10:41:03 +02:00
										 |  |  | 				nmenu->add_submenu_item(main_menu, atr(menu.name), menu.submenu_rid, global_menu_tag + "#" + itos(new_idx), global_start + new_idx); | 
					
						
							| 
									
										
										
										
											2023-10-15 20:52:56 +03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MenuBar::remove_child_notify(Node *p_child) { | 
					
						
							|  |  |  | 	Control::remove_child_notify(p_child); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	PopupMenu *pm = Object::cast_to<PopupMenu>(p_child); | 
					
						
							|  |  |  | 	if (!pm) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int idx = get_menu_idx_from_control(pm); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 19:41:01 +02:00
										 |  |  | 	if (!global_menu_tag.is_empty()) { | 
					
						
							| 
									
										
										
										
											2023-10-15 20:52:56 +03:00
										 |  |  | 		if (!pm->is_system_menu()) { | 
					
						
							| 
									
										
										
										
											2024-03-25 10:41:03 +02:00
										 |  |  | 			if (menu_cache[idx].submenu_rid.is_valid()) { | 
					
						
							| 
									
										
										
										
											2024-01-19 19:41:01 +02:00
										 |  |  | 				NativeMenu *nmenu = NativeMenu::get_singleton(); | 
					
						
							|  |  |  | 				RID main_menu = nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID); | 
					
						
							| 
									
										
										
										
											2024-03-25 10:41:03 +02:00
										 |  |  | 				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); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2023-12-19 09:57:48 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2024-03-25 10:41:03 +02:00
										 |  |  | 			pm->unbind_global_menu(); | 
					
						
							| 
									
										
										
										
											2023-10-15 20:52:56 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-20 23:35:07 +02:00
										 |  |  | 	pm->disconnect("title_changed", callable_mp(this, &MenuBar::_popup_changed)); | 
					
						
							| 
									
										
										
										
											2024-03-25 10:41:03 +02:00
										 |  |  | 	menu_cache.remove_at(idx); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 	p_child->remove_meta("_menu_name"); | 
					
						
							|  |  |  | 	p_child->remove_meta("_menu_tooltip"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	p_child->disconnect("renamed", callable_mp(this, &MenuBar::_refresh_menu_names)); | 
					
						
							|  |  |  | 	p_child->disconnect("about_to_popup", callable_mp(this, &MenuBar::_popup_visibility_changed)); | 
					
						
							|  |  |  | 	p_child->disconnect("popup_hide", callable_mp(this, &MenuBar::_popup_visibility_changed)); | 
					
						
							| 
									
										
										
										
											2023-10-25 22:14:29 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	update_minimum_size(); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MenuBar::_bind_methods() { | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_switch_on_hover", "enable"), &MenuBar::set_switch_on_hover); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("is_switch_on_hover"), &MenuBar::is_switch_on_hover); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_disable_shortcuts", "disabled"), &MenuBar::set_disable_shortcuts); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_prefer_global_menu", "enabled"), &MenuBar::set_prefer_global_menu); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("is_prefer_global_menu"), &MenuBar::is_prefer_global_menu); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("is_native_menu"), &MenuBar::is_native_menu); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_menu_count"), &MenuBar::get_menu_count); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_text_direction", "direction"), &MenuBar::set_text_direction); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_text_direction"), &MenuBar::get_text_direction); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_language", "language"), &MenuBar::set_language); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_language"), &MenuBar::get_language); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_flat", "enabled"), &MenuBar::set_flat); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("is_flat"), &MenuBar::is_flat); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_start_index", "enabled"), &MenuBar::set_start_index); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_start_index"), &MenuBar::get_start_index); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_menu_title", "menu", "title"), &MenuBar::set_menu_title); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_menu_title", "menu"), &MenuBar::get_menu_title); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_menu_tooltip", "menu", "tooltip"), &MenuBar::set_menu_tooltip); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_menu_tooltip", "menu"), &MenuBar::get_menu_tooltip); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_menu_disabled", "menu", "disabled"), &MenuBar::set_menu_disabled); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("is_menu_disabled", "menu"), &MenuBar::is_menu_disabled); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_menu_hidden", "menu", "hidden"), &MenuBar::set_menu_hidden); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("is_menu_hidden", "menu"), &MenuBar::is_menu_hidden); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_menu_popup", "menu"), &MenuBar::get_menu_popup); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat"); | 
					
						
							| 
									
										
										
										
											2023-03-10 11:42:09 -05:00
										 |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::INT, "start_index"), "set_start_index", "get_start_index"); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "switch_on_hover"), "set_switch_on_hover", "is_switch_on_hover"); | 
					
						
							|  |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "prefer_global_menu"), "set_prefer_global_menu", "is_prefer_global_menu"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ADD_GROUP("BiDi", ""); | 
					
						
							|  |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction"); | 
					
						
							|  |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "set_language", "get_language"); | 
					
						
							| 
									
										
										
										
											2023-09-08 21:00:10 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, MenuBar, normal); | 
					
						
							|  |  |  | 	BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, MenuBar, normal_mirrored); | 
					
						
							|  |  |  | 	BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, MenuBar, disabled); | 
					
						
							|  |  |  | 	BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, MenuBar, disabled_mirrored); | 
					
						
							|  |  |  | 	BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, MenuBar, pressed); | 
					
						
							|  |  |  | 	BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, MenuBar, pressed_mirrored); | 
					
						
							|  |  |  | 	BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, MenuBar, hover); | 
					
						
							|  |  |  | 	BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, MenuBar, hover_mirrored); | 
					
						
							|  |  |  | 	BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, MenuBar, hover_pressed); | 
					
						
							|  |  |  | 	BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, MenuBar, hover_pressed_mirrored); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	BIND_THEME_ITEM(Theme::DATA_TYPE_FONT, MenuBar, font); | 
					
						
							|  |  |  | 	BIND_THEME_ITEM(Theme::DATA_TYPE_FONT_SIZE, MenuBar, font_size); | 
					
						
							|  |  |  | 	BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, MenuBar, outline_size); | 
					
						
							|  |  |  | 	BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, MenuBar, font_outline_color); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, MenuBar, font_color); | 
					
						
							|  |  |  | 	BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, MenuBar, font_disabled_color); | 
					
						
							|  |  |  | 	BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, MenuBar, font_pressed_color); | 
					
						
							|  |  |  | 	BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, MenuBar, font_hover_color); | 
					
						
							|  |  |  | 	BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, MenuBar, font_hover_pressed_color); | 
					
						
							|  |  |  | 	BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, MenuBar, font_focus_color); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, MenuBar, h_separation); | 
					
						
							| 
									
										
										
										
											2025-03-06 15:42:10 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ADD_CLASS_DEPENDENCY("PopupMenu"); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MenuBar::set_switch_on_hover(bool p_enabled) { | 
					
						
							|  |  |  | 	switch_on_hover = p_enabled; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool MenuBar::is_switch_on_hover() { | 
					
						
							|  |  |  | 	return switch_on_hover; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MenuBar::set_disable_shortcuts(bool p_disabled) { | 
					
						
							|  |  |  | 	disable_shortcuts = p_disabled; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MenuBar::set_text_direction(Control::TextDirection p_text_direction) { | 
					
						
							|  |  |  | 	ERR_FAIL_COND((int)p_text_direction < -1 || (int)p_text_direction > 3); | 
					
						
							|  |  |  | 	if (text_direction != p_text_direction) { | 
					
						
							|  |  |  | 		text_direction = p_text_direction; | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 		update_minimum_size(); | 
					
						
							|  |  |  | 		queue_redraw(); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Control::TextDirection MenuBar::get_text_direction() const { | 
					
						
							|  |  |  | 	return text_direction; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MenuBar::set_language(const String &p_language) { | 
					
						
							|  |  |  | 	if (language != p_language) { | 
					
						
							|  |  |  | 		language = p_language; | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 		update_minimum_size(); | 
					
						
							|  |  |  | 		queue_redraw(); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | String MenuBar::get_language() const { | 
					
						
							|  |  |  | 	return language; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MenuBar::set_flat(bool p_enabled) { | 
					
						
							|  |  |  | 	if (flat != p_enabled) { | 
					
						
							|  |  |  | 		flat = p_enabled; | 
					
						
							| 
									
										
										
										
											2022-08-13 23:21:24 +02:00
										 |  |  | 		queue_redraw(); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool MenuBar::is_flat() const { | 
					
						
							|  |  |  | 	return flat; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MenuBar::set_start_index(int p_index) { | 
					
						
							|  |  |  | 	if (start_index != p_index) { | 
					
						
							|  |  |  | 		start_index = p_index; | 
					
						
							| 
									
										
										
										
											2024-01-19 19:41:01 +02:00
										 |  |  | 		if (!global_menu_tag.is_empty()) { | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 			unbind_global_menu(); | 
					
						
							|  |  |  | 			bind_global_menu(); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int MenuBar::get_start_index() const { | 
					
						
							|  |  |  | 	return start_index; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MenuBar::set_prefer_global_menu(bool p_enabled) { | 
					
						
							| 
									
										
										
										
											2024-03-07 20:42:24 +02:00
										 |  |  | 	if (prefer_native != p_enabled) { | 
					
						
							|  |  |  | 		prefer_native = p_enabled; | 
					
						
							|  |  |  | 		if (prefer_native) { | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 			bind_global_menu(); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			unbind_global_menu(); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool MenuBar::is_prefer_global_menu() const { | 
					
						
							| 
									
										
										
										
											2024-03-07 20:42:24 +02:00
										 |  |  | 	return prefer_native; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Size2 MenuBar::get_minimum_size() const { | 
					
						
							|  |  |  | 	if (is_native_menu()) { | 
					
						
							|  |  |  | 		return Size2(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-31 15:02:40 +03:00
										 |  |  | 	Ref<StyleBox> style = theme_cache.normal; | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	Vector2 size; | 
					
						
							|  |  |  | 	for (int i = 0; i < menu_cache.size(); i++) { | 
					
						
							|  |  |  | 		if (menu_cache[i].hidden) { | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		Size2 sz = menu_cache[i].text_buf->get_size() + style->get_minimum_size(); | 
					
						
							|  |  |  | 		size.y = MAX(size.y, sz.y); | 
					
						
							| 
									
										
										
										
											2022-08-19 17:10:53 +03:00
										 |  |  | 		size.x += sz.x; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (menu_cache.size() > 1) { | 
					
						
							| 
									
										
										
										
											2022-08-31 15:02:40 +03:00
										 |  |  | 		size.x += theme_cache.h_separation * (menu_cache.size() - 1); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return size; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int MenuBar::get_menu_count() const { | 
					
						
							|  |  |  | 	return menu_cache.size(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MenuBar::set_menu_title(int p_menu, const String &p_title) { | 
					
						
							|  |  |  | 	ERR_FAIL_INDEX(p_menu, menu_cache.size()); | 
					
						
							|  |  |  | 	PopupMenu *pm = get_menu_popup(p_menu); | 
					
						
							| 
									
										
										
										
											2024-12-20 23:35:07 +02:00
										 |  |  | 	String menu_name = pm->get_title().is_empty() ? String(pm->get_name()) : pm->get_title(); | 
					
						
							|  |  |  | 	if (p_title == menu_name) { | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | 		pm->remove_meta("_menu_name"); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		pm->set_meta("_menu_name", p_title); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	menu_cache.write[p_menu].name = p_title; | 
					
						
							|  |  |  | 	shape(menu_cache.write[p_menu]); | 
					
						
							| 
									
										
										
										
											2024-03-25 10:41:03 +02:00
										 |  |  | 	if (!global_menu_tag.is_empty() && menu_cache[p_menu].submenu_rid.is_valid()) { | 
					
						
							| 
									
										
										
										
											2024-01-19 19:41:01 +02:00
										 |  |  | 		NativeMenu *nmenu = NativeMenu::get_singleton(); | 
					
						
							|  |  |  | 		RID main_menu = nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID); | 
					
						
							| 
									
										
										
										
											2024-03-25 10:41:03 +02:00
										 |  |  | 		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)); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-10-25 22:14:29 +03:00
										 |  |  | 	update_minimum_size(); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | String MenuBar::get_menu_title(int p_menu) const { | 
					
						
							|  |  |  | 	ERR_FAIL_INDEX_V(p_menu, menu_cache.size(), String()); | 
					
						
							|  |  |  | 	return menu_cache[p_menu].name; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MenuBar::set_menu_tooltip(int p_menu, const String &p_tooltip) { | 
					
						
							|  |  |  | 	ERR_FAIL_INDEX(p_menu, menu_cache.size()); | 
					
						
							|  |  |  | 	PopupMenu *pm = get_menu_popup(p_menu); | 
					
						
							|  |  |  | 	pm->set_meta("_menu_tooltip", p_tooltip); | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 	menu_cache.write[p_menu].tooltip = p_tooltip; | 
					
						
							| 
									
										
										
										
											2024-03-25 10:41:03 +02:00
										 |  |  | 	if (!global_menu_tag.is_empty() && menu_cache[p_menu].submenu_rid.is_valid()) { | 
					
						
							| 
									
										
										
										
											2024-01-19 19:41:01 +02:00
										 |  |  | 		NativeMenu *nmenu = NativeMenu::get_singleton(); | 
					
						
							|  |  |  | 		RID main_menu = nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID); | 
					
						
							| 
									
										
										
										
											2024-03-25 10:41:03 +02:00
										 |  |  | 		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); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | String MenuBar::get_menu_tooltip(int p_menu) const { | 
					
						
							|  |  |  | 	ERR_FAIL_INDEX_V(p_menu, menu_cache.size(), String()); | 
					
						
							|  |  |  | 	return menu_cache[p_menu].tooltip; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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; | 
					
						
							| 
									
										
										
										
											2024-03-25 10:41:03 +02:00
										 |  |  | 	if (!global_menu_tag.is_empty() && menu_cache[p_menu].submenu_rid.is_valid()) { | 
					
						
							| 
									
										
										
										
											2024-01-19 19:41:01 +02:00
										 |  |  | 		NativeMenu *nmenu = NativeMenu::get_singleton(); | 
					
						
							|  |  |  | 		RID main_menu = nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID); | 
					
						
							| 
									
										
										
										
											2024-03-25 10:41:03 +02:00
										 |  |  | 		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); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool MenuBar::is_menu_disabled(int p_menu) const { | 
					
						
							|  |  |  | 	ERR_FAIL_INDEX_V(p_menu, menu_cache.size(), false); | 
					
						
							|  |  |  | 	return menu_cache[p_menu].disabled; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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; | 
					
						
							| 
									
										
										
										
											2024-03-25 10:41:03 +02:00
										 |  |  | 	if (!global_menu_tag.is_empty() && menu_cache[p_menu].submenu_rid.is_valid()) { | 
					
						
							| 
									
										
										
										
											2024-01-19 19:41:01 +02:00
										 |  |  | 		NativeMenu *nmenu = NativeMenu::get_singleton(); | 
					
						
							|  |  |  | 		RID main_menu = nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID); | 
					
						
							| 
									
										
										
										
											2024-03-25 10:41:03 +02:00
										 |  |  | 		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); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-07-11 11:17:35 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-10-25 22:14:29 +03:00
										 |  |  | 	update_minimum_size(); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool MenuBar::is_menu_hidden(int p_menu) const { | 
					
						
							|  |  |  | 	ERR_FAIL_INDEX_V(p_menu, menu_cache.size(), false); | 
					
						
							|  |  |  | 	return menu_cache[p_menu].hidden; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PopupMenu *MenuBar::get_menu_popup(int p_idx) const { | 
					
						
							|  |  |  | 	Vector<PopupMenu *> controls = _get_popups(); | 
					
						
							|  |  |  | 	if (p_idx >= 0 && p_idx < controls.size()) { | 
					
						
							|  |  |  | 		return controls[p_idx]; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		return nullptr; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | String MenuBar::get_tooltip(const Point2 &p_pos) const { | 
					
						
							|  |  |  | 	int index = _get_index_at_point(p_pos); | 
					
						
							|  |  |  | 	if (index >= 0 && index < menu_cache.size()) { | 
					
						
							|  |  |  | 		return menu_cache[index].tooltip; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		return String(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MenuBar::MenuBar() { | 
					
						
							| 
									
										
										
										
											2025-04-12 20:51:17 +03:00
										 |  |  | 	set_focus_mode(FOCUS_ACCESSIBILITY); | 
					
						
							| 
									
										
										
										
											2022-08-19 16:49:50 +03:00
										 |  |  | 	set_process_shortcut_input(true); | 
					
						
							| 
									
										
										
										
											2022-08-01 12:28:16 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MenuBar::~MenuBar() { | 
					
						
							|  |  |  | } |