Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.x] Make popup menus focus items automatically when not using the mouse #57643

Merged
merged 1 commit into from
Feb 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions doc/classes/PopupMenu.xml
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,13 @@
[b]Note:[/b] The indices of items after the removed item will be shifted by one.
</description>
</method>
<method name="set_current_index">
<return type="void" />
<argument index="0" name="index" type="int" />
<description>
Sets the currently focused item as the given [code]index[/code].
</description>
</method>
<method name="set_hide_on_window_lose_focus">
<return type="void" />
<argument index="0" name="enable" type="bool" />
Expand Down
9 changes: 9 additions & 0 deletions scene/gui/menu_button.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
/*************************************************************************/

#include "menu_button.h"
#include "core/os/input.h"
#include "core/os/keyboard.h"
#include "scene/main/viewport.h"

Expand Down Expand Up @@ -61,6 +62,14 @@ void MenuButton::pressed() {
popup->set_size(Size2(size.width, 0));
popup->set_scale(get_global_transform().get_scale());
popup->set_parent_rect(Rect2(Point2(gp - popup->get_global_position()), get_size()));

// If not triggered by the mouse, start the popup with its first item selected.
if (popup->get_item_count() > 0 &&
((get_action_mode() == ActionMode::ACTION_MODE_BUTTON_PRESS && Input::get_singleton()->is_action_just_pressed("ui_accept")) ||
(get_action_mode() == ActionMode::ACTION_MODE_BUTTON_RELEASE && Input::get_singleton()->is_action_just_released("ui_accept")))) {
popup->set_current_index(0);
}

popup->popup();
}

Expand Down
9 changes: 9 additions & 0 deletions scene/gui/option_button.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
/*************************************************************************/

#include "option_button.h"
#include "core/os/input.h"
#include "core/print_string.h"

Size2 OptionButton::get_minimum_size() const {
Expand Down Expand Up @@ -109,6 +110,14 @@ void OptionButton::pressed() {
popup->set_global_position(get_global_position() + Size2(0, size.height * get_global_transform().get_scale().y));
popup->set_size(Size2(size.width, 0));
popup->set_scale(get_global_transform().get_scale());

// If not triggered by the mouse, start the popup with its first item selected.
if (popup->get_item_count() > 0 &&
((get_action_mode() == ActionMode::ACTION_MODE_BUTTON_PRESS && Input::get_singleton()->is_action_just_pressed("ui_accept")) ||
(get_action_mode() == ActionMode::ACTION_MODE_BUTTON_RELEASE && Input::get_singleton()->is_action_just_released("ui_accept")))) {
popup->set_current_index(0);
}

popup->popup();
}

Expand Down
19 changes: 16 additions & 3 deletions scene/gui/popup_menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ void PopupMenu::_activate_submenu(int over) {
Popup *pm = Object::cast_to<Popup>(n);
ERR_FAIL_COND_MSG(!pm, "Item subnode is not a Popup: " + items[over].submenu + ".");
if (pm->is_visible_in_tree()) {
return; //already visible!
return; // Already visible.
}

Point2 p = get_global_position();
Expand All @@ -155,17 +155,21 @@ void PopupMenu::_activate_submenu(int over) {

Point2 pos = p + Point2(get_size().width, items[over]._ofs_cache - style->get_offset().y) * get_global_transform().get_scale();
Size2 size = pm->get_size();
// fix pos
// Fix pos.
if (pos.x + size.width > get_viewport_rect().size.width) {
pos.x = p.x - size.width;
}

pm->set_position(pos);
pm->set_scale(get_global_transform().get_scale());
pm->popup();

PopupMenu *pum = Object::cast_to<PopupMenu>(pm);
if (pum) {
// If not triggered by the mouse, start the popup with its first item selected.
if (pum->get_item_count() > 0 && Input::get_singleton()->is_action_just_pressed("ui_accept")) {
pum->set_current_index(0);
}

pr.position -= pum->get_global_position();
pum->clear_autohide_areas();
pum->add_autohide_area(Rect2(pr.position.x, pr.position.y, pr.size.x, items[over]._ofs_cache));
Expand All @@ -174,6 +178,8 @@ void PopupMenu::_activate_submenu(int over) {
pum->add_autohide_area(Rect2(pr.position.x, pr.position.y + from, pr.size.x, pr.size.y - from));
}
}

pm->popup();
}

void PopupMenu::_submenu_timeout() {
Expand Down Expand Up @@ -1033,6 +1039,12 @@ bool PopupMenu::is_item_shortcut_disabled(int p_idx) const {
return items[p_idx].shortcut_is_disabled;
}

void PopupMenu::set_current_index(int p_idx) {
ERR_FAIL_INDEX(p_idx, items.size());
mouse_over = p_idx;
update();
}

int PopupMenu::get_current_index() const {
return mouse_over;
}
Expand Down Expand Up @@ -1403,6 +1415,7 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_item_tooltip", "idx"), &PopupMenu::get_item_tooltip);
ClassDB::bind_method(D_METHOD("get_item_shortcut", "idx"), &PopupMenu::get_item_shortcut);

ClassDB::bind_method(D_METHOD("set_current_index", "index"), &PopupMenu::set_current_index);
ClassDB::bind_method(D_METHOD("get_current_index"), &PopupMenu::get_current_index);
ClassDB::bind_method(D_METHOD("get_item_count"), &PopupMenu::get_item_count);

Expand Down
2 changes: 2 additions & 0 deletions scene/gui/popup_menu.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,9 @@ class PopupMenu : public Popup {
Ref<ShortCut> get_item_shortcut(int p_idx) const;
int get_item_state(int p_idx) const;

void set_current_index(int p_idx);
int get_current_index() const;

int get_item_count() const;

bool activate_item_by_event(const Ref<InputEvent> &p_event, bool p_for_global_only = false);
Expand Down