diff options
Diffstat (limited to 'scene/gui/menu_bar.cpp')
-rw-r--r-- | scene/gui/menu_bar.cpp | 228 |
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 { |