diff options
author | Rémi Verschelde <rverschelde@gmail.com> | 2023-09-25 17:17:51 +0200 |
---|---|---|
committer | Rémi Verschelde <rverschelde@gmail.com> | 2023-09-25 17:17:51 +0200 |
commit | c57d9f348343f7c8f670a25db4acf7f6be338bf7 (patch) | |
tree | 2e446646dedf2fd822a235851a9844a8971f51d5 /scene/gui/tab_bar.cpp | |
parent | 1a0e653d7f1987bc3593bd50d7ae37c954883d3f (diff) | |
parent | 18811ac8141f2b8dfb45413400643af11d09f2b0 (diff) | |
download | redot-engine-c57d9f348343f7c8f670a25db4acf7f6be338bf7.tar.gz |
Merge pull request #79104 from DrRevert/focusable_tabs_refactor
Allow to focus individual tabs in `TabBar`/`TabContainer`
Diffstat (limited to 'scene/gui/tab_bar.cpp')
-rw-r--r-- | scene/gui/tab_bar.cpp | 91 |
1 files changed, 88 insertions, 3 deletions
diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp index a9c16a9942..14eed4c7a2 100644 --- a/scene/gui/tab_bar.cpp +++ b/scene/gui/tab_bar.cpp @@ -290,6 +290,34 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) { } } } + + if (p_event->is_pressed()) { + 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_right", true)) { + if (is_joypad_event) { + if (!input->is_action_just_pressed("ui_right", true)) { + return; + } + set_process_internal(true); + } + if (is_layout_rtl() ? select_previous_available() : select_next_available()) { + accept_event(); + } + } else if (p_event->is_action("ui_left", true)) { + if (is_joypad_event) { + if (!input->is_action_just_pressed("ui_left", true)) { + return; + } + set_process_internal(true); + } + if (is_layout_rtl() ? select_next_available() : select_previous_available()) { + accept_event(); + } + } + } } void TabBar::_shape(int p_tab) { @@ -307,6 +335,28 @@ void TabBar::_shape(int p_tab) { void TabBar::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_INTERNAL_PROCESS: { + Input *input = Input::get_singleton(); + + if (input->is_action_just_released("ui_left") || input->is_action_just_released("ui_right")) { + 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) { + gamepad_event_delay_ms = GAMEPAD_EVENT_REPEAT_RATE_MS + gamepad_event_delay_ms; + if (input->is_action_pressed("ui_right")) { + is_layout_rtl() ? select_previous_available() : select_next_available(); + } + + if (input->is_action_pressed("ui_left")) { + is_layout_rtl() ? select_next_available() : select_previous_available(); + } + } + } break; + case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { queue_redraw(); } break; @@ -379,7 +429,7 @@ void TabBar::_notification(int p_what) { col = theme_cache.font_unselected_color; } - _draw_tab(sb, col, i, rtl ? size.width - ofs - tabs[i].size_cache : ofs); + _draw_tab(sb, col, i, rtl ? size.width - ofs - tabs[i].size_cache : ofs, false); } ofs += tabs[i].size_cache; @@ -390,7 +440,7 @@ void TabBar::_notification(int p_what) { Ref<StyleBox> sb = tabs[current].disabled ? theme_cache.tab_disabled_style : theme_cache.tab_selected_style; float x = rtl ? size.width - tabs[current].ofs_cache - tabs[current].size_cache : tabs[current].ofs_cache; - _draw_tab(sb, theme_cache.font_selected_color, current, x); + _draw_tab(sb, theme_cache.font_selected_color, current, x, has_focus()); } if (buttons_visible) { @@ -456,12 +506,16 @@ void TabBar::_notification(int p_what) { } } -void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_index, float p_x) { +void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_index, float p_x, bool p_focus) { RID ci = get_canvas_item(); bool rtl = is_layout_rtl(); Rect2 sb_rect = Rect2(p_x, 0, tabs[p_index].size_cache, get_size().height); p_tab_style->draw(ci, sb_rect); + if (p_focus) { + Ref<StyleBox> focus_style = theme_cache.tab_focus_style; + focus_style->draw(ci, sb_rect); + } p_x += rtl ? tabs[p_index].size_cache - p_tab_style->get_margin(SIDE_LEFT) : p_tab_style->get_margin(SIDE_LEFT); @@ -607,6 +661,33 @@ int TabBar::get_hovered_tab() const { return hover; } +bool TabBar::select_previous_available() { + const int offset_end = (get_current_tab() + 1); + for (int i = 1; i < offset_end; i++) { + int target_tab = get_current_tab() - i; + if (target_tab < 0) { + target_tab += get_tab_count(); + } + if (!is_tab_disabled(target_tab)) { + set_current_tab(target_tab); + return true; + } + } + return false; +} + +bool TabBar::select_next_available() { + const int offset_end = (get_tab_count() - get_current_tab()); + for (int i = 1; i < offset_end; i++) { + int target_tab = (get_current_tab() + i) % get_tab_count(); + if (!is_tab_disabled(target_tab)) { + set_current_tab(target_tab); + return true; + } + } + return false; +} + int TabBar::get_tab_offset() const { return offset; } @@ -1589,6 +1670,8 @@ void TabBar::_bind_methods() { ClassDB::bind_method(D_METHOD("set_current_tab", "tab_idx"), &TabBar::set_current_tab); ClassDB::bind_method(D_METHOD("get_current_tab"), &TabBar::get_current_tab); ClassDB::bind_method(D_METHOD("get_previous_tab"), &TabBar::get_previous_tab); + ClassDB::bind_method(D_METHOD("select_previous_available"), &TabBar::select_previous_available); + ClassDB::bind_method(D_METHOD("select_next_available"), &TabBar::select_next_available); ClassDB::bind_method(D_METHOD("set_tab_title", "tab_idx", "title"), &TabBar::set_tab_title); ClassDB::bind_method(D_METHOD("get_tab_title", "tab_idx"), &TabBar::get_tab_title); ClassDB::bind_method(D_METHOD("set_tab_text_direction", "tab_idx", "direction"), &TabBar::set_tab_text_direction); @@ -1674,6 +1757,7 @@ void TabBar::_bind_methods() { BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, TabBar, tab_hovered_style, "tab_hovered"); BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, TabBar, tab_selected_style, "tab_selected"); BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, TabBar, tab_disabled_style, "tab_disabled"); + BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, TabBar, tab_focus_style, "tab_focus"); BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, TabBar, increment_icon, "increment"); BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, TabBar, increment_hl_icon, "increment_highlight"); @@ -1699,5 +1783,6 @@ void TabBar::_bind_methods() { TabBar::TabBar() { set_size(Size2(get_size().width, get_minimum_size().height)); + set_focus_mode(FOCUS_ALL); connect("mouse_exited", callable_mp(this, &TabBar::_on_mouse_exited)); } |