From 272c29793166d7f8662c03d782abecc10d4b6d30 Mon Sep 17 00:00:00 2001 From: EricEzaM Date: Sun, 2 Oct 2022 16:46:37 +1000 Subject: [PATCH] Improve MenuButton and OptionButton * MenuButton + OptionButton: Add method `show_popup()` which performs required popup setup before showing (prefer use of this over `get_popup()->popup()`, otherwise GH #66308 occurs) * MenuButton: Ensure that the menu can be opened with a shortcut, if one is set for the button. (GH #66403). Ensure that popupmenu item shortcuts are checked first before the MenuButton shortcut. --- doc/classes/MenuButton.xml | 6 ++++ doc/classes/OptionButton.xml | 6 ++++ scene/gui/menu_button.cpp | 34 ++++++++++---------- scene/gui/menu_button.h | 4 +-- scene/gui/option_button.cpp | 61 +++++++++++++++++++++--------------- scene/gui/option_button.h | 1 + 6 files changed, 68 insertions(+), 44 deletions(-) diff --git a/doc/classes/MenuButton.xml b/doc/classes/MenuButton.xml index 1f38510e83e..4d5d5a011bd 100644 --- a/doc/classes/MenuButton.xml +++ b/doc/classes/MenuButton.xml @@ -25,6 +25,12 @@ If [code]true[/code], shortcuts are disabled and cannot be used to trigger the button. + + + + Adjusts popup position and sizing for the [MenuButton], then shows the [PopupMenu]. Prefer this over using [code]get_popup().popup()[/code]. + + diff --git a/doc/classes/OptionButton.xml b/doc/classes/OptionButton.xml index f10c096c1bb..199535298c9 100644 --- a/doc/classes/OptionButton.xml +++ b/doc/classes/OptionButton.xml @@ -190,6 +190,12 @@ Sets the tooltip of the item at index [param idx]. + + + + Adjusts popup position and sizing for the [OptionButton], then shows the [PopupMenu]. Prefer this over using [code]get_popup().popup()[/code]. + + diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index 67a36240a2d..fa8df48412c 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -44,15 +44,12 @@ void MenuButton::shortcut_input(const Ref &p_event) { return; } - if (p_event->is_pressed() && !p_event->is_echo() && (Object::cast_to(p_event.ptr()) || Object::cast_to(p_event.ptr()) || Object::cast_to(*p_event) || Object::cast_to(*p_event))) { - if (!get_parent() || !is_visible_in_tree() || is_disabled()) { - return; - } - - if (popup->activate_item_by_event(p_event, false)) { - accept_event(); - } + if (p_event->is_pressed() && !p_event->is_echo() && !is_disabled() && is_visible_in_tree() && popup->activate_item_by_event(p_event, false)) { + accept_event(); + return; } + + Button::shortcut_input(p_event); } void MenuButton::_popup_visibility_changed(bool p_visible) { @@ -91,6 +88,18 @@ void MenuButton::pressed() { return; } + show_popup(); +} + +PopupMenu *MenuButton::get_popup() const { + return popup; +} + +void MenuButton::show_popup() { + if (!get_viewport()) { + return; + } + emit_signal(SNAME("about_to_popup")); Size2 size = get_size() * get_viewport()->get_canvas_transform().get_scale(); @@ -116,14 +125,6 @@ void MenuButton::pressed() { popup->popup(); } -void MenuButton::gui_input(const Ref &p_event) { - BaseButton::gui_input(p_event); -} - -PopupMenu *MenuButton::get_popup() const { - return popup; -} - void MenuButton::set_switch_on_hover(bool p_enabled) { switch_on_hover = p_enabled; } @@ -226,6 +227,7 @@ void MenuButton::_get_property_list(List *p_list) const { void MenuButton::_bind_methods() { ClassDB::bind_method(D_METHOD("get_popup"), &MenuButton::get_popup); + ClassDB::bind_method(D_METHOD("show_popup"), &MenuButton::show_popup); ClassDB::bind_method(D_METHOD("set_switch_on_hover", "enable"), &MenuButton::set_switch_on_hover); ClassDB::bind_method(D_METHOD("is_switch_on_hover"), &MenuButton::is_switch_on_hover); ClassDB::bind_method(D_METHOD("set_disable_shortcuts", "disabled"), &MenuButton::set_disable_shortcuts); diff --git a/scene/gui/menu_button.h b/scene/gui/menu_button.h index 97c0d21f1e3..3aacbca3a81 100644 --- a/scene/gui/menu_button.h +++ b/scene/gui/menu_button.h @@ -44,8 +44,6 @@ class MenuButton : public Button { Vector2i mouse_pos_adjusted; - virtual void gui_input(const Ref &p_event) override; - void _popup_visibility_changed(bool p_visible); protected: @@ -60,6 +58,8 @@ public: virtual void pressed() override; PopupMenu *get_popup() const; + void show_popup(); + void set_switch_on_hover(bool p_enabled); bool is_switch_on_hover(); void set_disable_shortcuts(bool p_disabled); diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index 08f5e0bbfb6..2cbece69f26 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -231,32 +231,7 @@ void OptionButton::pressed() { return; } - Size2 size = get_size() * get_viewport()->get_canvas_transform().get_scale(); - popup->set_position(get_screen_position() + Size2(0, size.height * get_global_transform().get_scale().y)); - popup->set_size(Size2(size.width, 0)); - - // If not triggered by the mouse, start the popup with the checked item (or the first enabled one) focused. - if (current != NONE_SELECTED && !popup->is_item_disabled(current)) { - if (!_was_pressed_by_mouse()) { - popup->set_focused_item(current); - } else { - popup->scroll_to_item(current); - } - } else { - for (int i = 0; i < popup->get_item_count(); i++) { - if (!popup->is_item_disabled(i)) { - if (!_was_pressed_by_mouse()) { - popup->set_focused_item(i); - } else { - popup->scroll_to_item(i); - } - - break; - } - } - } - - popup->popup(); + show_popup(); } void OptionButton::add_icon_item(const Ref &p_icon, const String &p_label, int p_id) { @@ -511,6 +486,39 @@ PopupMenu *OptionButton::get_popup() const { return popup; } +void OptionButton::show_popup() { + if (!get_viewport()) { + return; + } + + Size2 size = get_size() * get_viewport()->get_canvas_transform().get_scale(); + popup->set_position(get_screen_position() + Size2(0, size.height * get_global_transform().get_scale().y)); + popup->set_size(Size2(size.width, 0)); + + // If not triggered by the mouse, start the popup with the checked item (or the first enabled one) focused. + if (current != NONE_SELECTED && !popup->is_item_disabled(current)) { + if (!_was_pressed_by_mouse()) { + popup->set_focused_item(current); + } else { + popup->scroll_to_item(current); + } + } else { + for (int i = 0; i < popup->get_item_count(); i++) { + if (!popup->is_item_disabled(i)) { + if (!_was_pressed_by_mouse()) { + popup->set_focused_item(i); + } else { + popup->scroll_to_item(i); + } + + break; + } + } + } + + popup->popup(); +} + void OptionButton::get_translatable_strings(List *p_strings) const { popup->get_translatable_strings(p_strings); } @@ -548,6 +556,7 @@ void OptionButton::_bind_methods() { ClassDB::bind_method(D_METHOD("_select_int", "idx"), &OptionButton::_select_int); ClassDB::bind_method(D_METHOD("get_popup"), &OptionButton::get_popup); + ClassDB::bind_method(D_METHOD("show_popup"), &OptionButton::show_popup); ClassDB::bind_method(D_METHOD("set_item_count", "count"), &OptionButton::set_item_count); ClassDB::bind_method(D_METHOD("get_item_count"), &OptionButton::get_item_count); diff --git a/scene/gui/option_button.h b/scene/gui/option_button.h index 2c7e0510f5d..b76a31d37ec 100644 --- a/scene/gui/option_button.h +++ b/scene/gui/option_button.h @@ -123,6 +123,7 @@ public: void remove_item(int p_idx); PopupMenu *get_popup() const; + void show_popup(); virtual void get_translatable_strings(List *p_strings) const override;