diff options
Diffstat (limited to 'scene/gui/popup_menu.cpp')
-rw-r--r-- | scene/gui/popup_menu.cpp | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 03860c7449..78bc64d9bd 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -295,7 +295,18 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); if (!items.is_empty()) { + Input *input = Input::get_singleton(); + Ref<InputEventJoypadMotion> joypadmotion_event = p_event; + Ref<InputEventJoypadButton> joypadbutton_event = p_event; + bool is_joypad_event = (joypadmotion_event.is_valid() || joypadbutton_event.is_valid()); + if (p_event->is_action("ui_down", true) && p_event->is_pressed()) { + if (is_joypad_event) { + if (!input->is_action_just_pressed("ui_down", true)) { + return; + } + set_process_internal(true); + } int search_from = mouse_over + 1; if (search_from >= items.size()) { search_from = 0; @@ -328,6 +339,12 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) { } } } else if (p_event->is_action("ui_up", true) && p_event->is_pressed()) { + if (is_joypad_event) { + if (!input->is_action_just_pressed("ui_up", true)) { + return; + } + set_process_internal(true); + } int search_from = mouse_over - 1; if (search_from < 0) { search_from = items.size() - 1; @@ -905,6 +922,82 @@ void PopupMenu::_notification(int p_what) { } break; case NOTIFICATION_INTERNAL_PROCESS: { + Input *input = Input::get_singleton(); + + if (input->is_action_just_released("ui_up") || input->is_action_just_released("ui_down")) { + gamepad_event_delay_ms = DEFAULT_GAMEPAD_EVENT_DELAY_MS; + set_process_internal(false); + return; + } + gamepad_event_delay_ms -= get_process_delta_time(); + if (gamepad_event_delay_ms <= 0) { + if (input->is_action_pressed("ui_down")) { + gamepad_event_delay_ms = GAMEPAD_EVENT_REPEAT_RATE_MS + gamepad_event_delay_ms; + int search_from = mouse_over + 1; + if (search_from >= items.size()) { + search_from = 0; + } + + bool match_found = false; + for (int i = search_from; i < items.size(); i++) { + if (!items[i].separator && !items[i].disabled) { + mouse_over = i; + emit_signal(SNAME("id_focused"), i); + scroll_to_item(i); + control->queue_redraw(); + match_found = true; + break; + } + } + + if (!match_found) { + // If the last item is not selectable, try re-searching from the start. + for (int i = 0; i < search_from; i++) { + if (!items[i].separator && !items[i].disabled) { + mouse_over = i; + emit_signal(SNAME("id_focused"), i); + scroll_to_item(i); + control->queue_redraw(); + break; + } + } + } + } + + if (input->is_action_pressed("ui_up")) { + gamepad_event_delay_ms = GAMEPAD_EVENT_REPEAT_RATE_MS + gamepad_event_delay_ms; + int search_from = mouse_over - 1; + if (search_from < 0) { + search_from = items.size() - 1; + } + + bool match_found = false; + for (int i = search_from; i >= 0; i--) { + if (!items[i].separator && !items[i].disabled) { + mouse_over = i; + emit_signal(SNAME("id_focused"), i); + scroll_to_item(i); + control->queue_redraw(); + match_found = true; + break; + } + } + + if (!match_found) { + // If the first item is not selectable, try re-searching from the end. + for (int i = items.size() - 1; i >= search_from; i--) { + if (!items[i].separator && !items[i].disabled) { + mouse_over = i; + emit_signal(SNAME("id_focused"), i); + scroll_to_item(i); + control->queue_redraw(); + break; + } + } + } + } + } + // Only used when using operating system windows. if (!activated_by_keyboard && !is_embedded() && autohide_areas.size()) { Point2 mouse_pos = DisplayServer::get_singleton()->mouse_get_position(); |