summaryrefslogtreecommitdiffstats
path: root/scene/gui/menu_bar.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/gui/menu_bar.cpp')
-rw-r--r--scene/gui/menu_bar.cpp228
1 files changed, 126 insertions, 102 deletions
diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp
index 13a42d0407..371d6c69af 100644
--- a/scene/gui/menu_bar.cpp
+++ b/scene/gui/menu_bar.cpp
@@ -202,52 +202,6 @@ void MenuBar::_popup_visibility_changed(bool p_visible) {
}
}
-void MenuBar::_update_submenu(const String &p_menu_name, PopupMenu *p_child) {
- int count = p_child->get_item_count();
- global_menus.insert(p_menu_name);
- for (int i = 0; i < count; i++) {
- if (p_child->is_item_separator(i)) {
- DisplayServer::get_singleton()->global_menu_add_separator(p_menu_name);
- } else if (!p_child->get_item_submenu(i).is_empty()) {
- Node *n = p_child->get_node_or_null(p_child->get_item_submenu(i));
- ERR_FAIL_NULL_MSG(n, "Item subnode does not exist: '" + p_child->get_item_submenu(i) + "'.");
- PopupMenu *pm = Object::cast_to<PopupMenu>(n);
- ERR_FAIL_NULL_MSG(pm, "Item subnode is not a PopupMenu: '" + p_child->get_item_submenu(i) + "'.");
-
- DisplayServer::get_singleton()->global_menu_add_submenu_item(p_menu_name, atr(p_child->get_item_text(i)), p_menu_name + "/" + itos(i));
- _update_submenu(p_menu_name + "/" + itos(i), pm);
- } else {
- int index = DisplayServer::get_singleton()->global_menu_add_item(p_menu_name, atr(p_child->get_item_text(i)), callable_mp(p_child, &PopupMenu::activate_item), Callable(), i);
-
- if (p_child->is_item_checkable(i)) {
- DisplayServer::get_singleton()->global_menu_set_item_checkable(p_menu_name, index, true);
- }
- if (p_child->is_item_radio_checkable(i)) {
- DisplayServer::get_singleton()->global_menu_set_item_radio_checkable(p_menu_name, index, true);
- }
- DisplayServer::get_singleton()->global_menu_set_item_checked(p_menu_name, index, p_child->is_item_checked(i));
- DisplayServer::get_singleton()->global_menu_set_item_disabled(p_menu_name, index, p_child->is_item_disabled(i));
- DisplayServer::get_singleton()->global_menu_set_item_max_states(p_menu_name, index, p_child->get_item_max_states(i));
- DisplayServer::get_singleton()->global_menu_set_item_icon(p_menu_name, index, p_child->get_item_icon(i));
- DisplayServer::get_singleton()->global_menu_set_item_state(p_menu_name, index, p_child->get_item_state(i));
- DisplayServer::get_singleton()->global_menu_set_item_indentation_level(p_menu_name, index, p_child->get_item_indent(i));
- DisplayServer::get_singleton()->global_menu_set_item_tooltip(p_menu_name, index, p_child->get_item_tooltip(i));
- if (!p_child->is_item_shortcut_disabled(i) && p_child->get_item_shortcut(i).is_valid() && p_child->get_item_shortcut(i)->has_valid_event()) {
- Array events = p_child->get_item_shortcut(i)->get_events();
- for (int j = 0; j < events.size(); j++) {
- Ref<InputEventKey> ie = events[j];
- if (ie.is_valid()) {
- DisplayServer::get_singleton()->global_menu_set_item_accelerator(p_menu_name, index, ie->get_keycode_with_modifiers());
- break;
- }
- }
- } else if (p_child->get_item_accelerator(i) != Key::NONE) {
- DisplayServer::get_singleton()->global_menu_set_item_accelerator(p_menu_name, i, p_child->get_item_accelerator(i));
- }
- }
- }
-}
-
bool MenuBar::is_native_menu() const {
#ifdef TOOLS_ENABLED
if (is_part_of_edited_scene()) {
@@ -258,52 +212,67 @@ bool MenuBar::is_native_menu() const {
return (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU) && is_native);
}
-void MenuBar::_clear_menu() {
+String MenuBar::bind_global_menu() {
+#ifdef TOOLS_ENABLED
+ if (is_part_of_edited_scene()) {
+ return String();
+ }
+#endif
if (!DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU)) {
- return;
+ return String();
}
- // Remove root menu items.
- int count = DisplayServer::get_singleton()->global_menu_get_item_count("_main");
- for (int i = count - 1; i >= 0; i--) {
- if (global_menus.has(DisplayServer::get_singleton()->global_menu_get_item_submenu("_main", i))) {
- DisplayServer::get_singleton()->global_menu_remove_item("_main", i);
+ if (!global_menu_name.is_empty()) {
+ return global_menu_name; // Already bound.
+ }
+
+ DisplayServer *ds = DisplayServer::get_singleton();
+ global_menu_name = "__MenuBar#" + itos(get_instance_id());
+
+ int global_start_idx = -1;
+ int count = ds->global_menu_get_item_count("_main");
+ String prev_tag;
+ for (int i = 0; i < count; i++) {
+ String tag = ds->global_menu_get_item_tag("_main", i).operator String().get_slice("#", 1);
+ if (!tag.is_empty() && tag != prev_tag) {
+ if (i >= start_index) {
+ global_start_idx = i;
+ break;
+ }
}
+ prev_tag = tag;
}
- // Erase submenu contents.
- for (const String &E : global_menus) {
- DisplayServer::get_singleton()->global_menu_clear(E);
+ if (global_start_idx == -1) {
+ global_start_idx = count;
}
- global_menus.clear();
-}
-void MenuBar::_update_menu() {
- _clear_menu();
+ Vector<PopupMenu *> popups = _get_popups();
+ for (int i = 0; i < menu_cache.size(); i++) {
+ String submenu_name = popups[i]->bind_global_menu();
+ int index = ds->global_menu_add_submenu_item("_main", menu_cache[i].name, submenu_name, global_start_idx + i);
+ ds->global_menu_set_item_tag("_main", index, global_menu_name + "#" + itos(i));
+ ds->global_menu_set_item_hidden("_main", index, menu_cache[i].hidden);
+ ds->global_menu_set_item_disabled("_main", index, menu_cache[i].disabled);
+ ds->global_menu_set_item_tooltip("_main", index, menu_cache[i].tooltip);
+ }
+
+ return global_menu_name;
+}
- if (!is_visible_in_tree()) {
+void MenuBar::unbind_global_menu() {
+ if (global_menu_name.is_empty()) {
return;
}
- int index = start_index;
- if (is_native_menu()) {
- Vector<PopupMenu *> popups = _get_popups();
- String root_name = "MenuBar<" + String::num_int64((uint64_t)this, 16) + ">";
- for (int i = 0; i < popups.size(); i++) {
- if (menu_cache[i].hidden) {
- continue;
- }
- String menu_name = atr(String(popups[i]->get_meta("_menu_name", popups[i]->get_name())));
-
- index = DisplayServer::get_singleton()->global_menu_add_submenu_item("_main", menu_name, root_name + "/" + itos(i), index);
- if (menu_cache[i].disabled) {
- DisplayServer::get_singleton()->global_menu_set_item_disabled("_main", index, true);
- }
- _update_submenu(root_name + "/" + itos(i), popups[i]);
- index++;
- }
+ DisplayServer *ds = DisplayServer::get_singleton();
+ int global_start = _find_global_start_index();
+ Vector<PopupMenu *> popups = _get_popups();
+ for (int i = menu_cache.size() - 1; i >= 0; i--) {
+ popups[i]->unbind_global_menu();
+ ds->global_menu_remove_item("_main", global_start + i);
}
- update_minimum_size();
- queue_redraw();
+
+ global_menu_name = String();
}
void MenuBar::_notification(int p_what) {
@@ -312,25 +281,43 @@ void MenuBar::_notification(int p_what) {
if (get_menu_count() > 0) {
_refresh_menu_names();
}
+ if (is_native_menu()) {
+ bind_global_menu();
+ }
} break;
case NOTIFICATION_EXIT_TREE: {
- _clear_menu();
+ unbind_global_menu();
} break;
case NOTIFICATION_MOUSE_EXIT: {
focused_menu = -1;
selected_menu = -1;
queue_redraw();
} break;
- case NOTIFICATION_TRANSLATION_CHANGED:
+ case NOTIFICATION_TRANSLATION_CHANGED: {
+ DisplayServer *ds = DisplayServer::get_singleton();
+ bool is_global = !global_menu_name.is_empty();
+ int global_start = _find_global_start_index();
+ for (int i = 0; i < menu_cache.size(); i++) {
+ shape(menu_cache.write[i]);
+ if (is_global) {
+ ds->global_menu_set_item_text("_main", global_start + i, atr(menu_cache[i].name));
+ }
+ }
+ } break;
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case NOTIFICATION_THEME_CHANGED: {
for (int i = 0; i < menu_cache.size(); i++) {
shape(menu_cache.write[i]);
}
- _update_menu();
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
- _update_menu();
+ if (is_native_menu()) {
+ if (is_visible_in_tree()) {
+ bind_global_menu();
+ } else {
+ unbind_global_menu();
+ }
+ }
} break;
case NOTIFICATION_DRAW: {
if (is_native_menu()) {
@@ -512,14 +499,20 @@ void MenuBar::shape(Menu &p_menu) {
}
void MenuBar::_refresh_menu_names() {
+ DisplayServer *ds = DisplayServer::get_singleton();
+ bool is_global = !global_menu_name.is_empty();
+ int global_start = _find_global_start_index();
+
Vector<PopupMenu *> popups = _get_popups();
for (int i = 0; i < popups.size(); i++) {
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) {
+ ds->global_menu_set_item_text("_main", global_start + i, atr(menu_cache[i].name));
+ }
}
}
- _update_menu();
}
Vector<PopupMenu *> MenuBar::_get_popups() const {
@@ -560,11 +553,14 @@ void MenuBar::add_child_notify(Node *p_child) {
menu_cache.push_back(menu);
p_child->connect("renamed", callable_mp(this, &MenuBar::_refresh_menu_names));
- p_child->connect("menu_changed", callable_mp(this, &MenuBar::_update_menu));
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));
- _update_menu();
+ if (!global_menu_name.is_empty()) {
+ String submenu_name = pm->bind_global_menu();
+ int index = DisplayServer::get_singleton()->global_menu_add_submenu_item("_main", atr(menu.name), submenu_name, _find_global_start_index() + menu_cache.size() - 1);
+ DisplayServer::get_singleton()->global_menu_set_item_tag("_main", index, global_menu_name + "#" + itos(menu_cache.size() - 1));
+ }
}
void MenuBar::move_child_notify(Node *p_child) {
@@ -586,9 +582,20 @@ void MenuBar::move_child_notify(Node *p_child) {
}
Menu menu = menu_cache[old_idx];
menu_cache.remove_at(old_idx);
- menu_cache.insert(get_menu_idx_from_control(pm), menu);
+ int new_idx = get_menu_idx_from_control(pm);
+ menu_cache.insert(new_idx, menu);
- _update_menu();
+ if (!global_menu_name.is_empty()) {
+ int global_start = _find_global_start_index();
+ if (old_idx != -1) {
+ DisplayServer::get_singleton()->global_menu_remove_item("_main", global_start + old_idx);
+ }
+ if (new_idx != -1) {
+ String submenu_name = pm->bind_global_menu();
+ int index = DisplayServer::get_singleton()->global_menu_add_submenu_item("_main", atr(menu.name), submenu_name, global_start + new_idx);
+ DisplayServer::get_singleton()->global_menu_set_item_tag("_main", index, global_menu_name + "#" + itos(new_idx));
+ }
+ }
}
void MenuBar::remove_child_notify(Node *p_child) {
@@ -603,15 +610,17 @@ void MenuBar::remove_child_notify(Node *p_child) {
menu_cache.remove_at(idx);
+ if (!global_menu_name.is_empty()) {
+ pm->unbind_global_menu();
+ DisplayServer::get_singleton()->global_menu_remove_item("_main", _find_global_start_index() + idx);
+ }
+
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("menu_changed", callable_mp(this, &MenuBar::_update_menu));
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));
-
- _update_menu();
}
void MenuBar::_bind_methods() {
@@ -699,7 +708,8 @@ 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;
- _update_menu();
+ update_minimum_size();
+ queue_redraw();
}
}
@@ -710,7 +720,8 @@ Control::TextDirection MenuBar::get_text_direction() const {
void MenuBar::set_language(const String &p_language) {
if (language != p_language) {
language = p_language;
- _update_menu();
+ update_minimum_size();
+ queue_redraw();
}
}
@@ -732,7 +743,10 @@ bool MenuBar::is_flat() const {
void MenuBar::set_start_index(int p_index) {
if (start_index != p_index) {
start_index = p_index;
- _update_menu();
+ if (!global_menu_name.is_empty()) {
+ unbind_global_menu();
+ bind_global_menu();
+ }
}
}
@@ -742,11 +756,12 @@ int MenuBar::get_start_index() const {
void MenuBar::set_prefer_global_menu(bool p_enabled) {
if (is_native != p_enabled) {
+ is_native = p_enabled;
if (is_native) {
- _clear_menu();
+ bind_global_menu();
+ } else {
+ unbind_global_menu();
}
- is_native = p_enabled;
- _update_menu();
}
}
@@ -790,7 +805,9 @@ 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]);
- _update_menu();
+ if (!global_menu_name.is_empty()) {
+ DisplayServer::get_singleton()->global_menu_set_item_text("_main", _find_global_start_index() + p_menu, atr(menu_cache[p_menu].name));
+ }
}
String MenuBar::get_menu_title(int p_menu) const {
@@ -802,7 +819,10 @@ 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);
- menu_cache.write[p_menu].name = p_tooltip;
+ menu_cache.write[p_menu].tooltip = p_tooltip;
+ if (!global_menu_name.is_empty()) {
+ DisplayServer::get_singleton()->global_menu_set_item_tooltip("_main", _find_global_start_index() + p_menu, p_tooltip);
+ }
}
String MenuBar::get_menu_tooltip(int p_menu) const {
@@ -813,7 +833,9 @@ 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;
- _update_menu();
+ if (!global_menu_name.is_empty()) {
+ DisplayServer::get_singleton()->global_menu_set_item_disabled("_main", _find_global_start_index() + p_menu, p_disabled);
+ }
}
bool MenuBar::is_menu_disabled(int p_menu) const {
@@ -824,7 +846,9 @@ 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;
- _update_menu();
+ if (!global_menu_name.is_empty()) {
+ DisplayServer::get_singleton()->global_menu_set_item_hidden("_main", _find_global_start_index() + p_menu, p_hidden);
+ }
}
bool MenuBar::is_menu_hidden(int p_menu) const {