2023-01-05 13:25:55 +01:00
/**************************************************************************/
/* tab_bar.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
2018-01-05 00:50:27 +01:00
2021-10-17 18:55:44 +02:00
# include "tab_bar.h"
2014-02-10 02:10:30 +01:00
2020-09-03 13:22:16 +02:00
# include "core/string/translation.h"
2018-02-07 14:01:45 +01:00
# include "scene/gui/box_container.h"
# include "scene/gui/label.h"
# include "scene/gui/texture_rect.h"
2022-03-20 02:24:36 +01:00
# include "scene/main/viewport.h"
2023-09-08 21:00:10 +02:00
# include "scene/theme/theme_db.h"
2014-02-10 02:10:30 +01:00
2021-10-17 18:55:44 +02:00
Size2 TabBar : : get_minimum_size ( ) const {
2022-01-19 17:11:44 +01:00
Size2 ms ;
if ( tabs . is_empty ( ) ) {
return ms ;
}
2023-03-09 03:52:57 +01:00
int y_margin = MAX ( MAX ( MAX ( theme_cache . tab_unselected_style - > get_minimum_size ( ) . height , theme_cache . tab_hovered_style - > get_minimum_size ( ) . height ) , theme_cache . tab_selected_style - > get_minimum_size ( ) . height ) , theme_cache . tab_disabled_style - > get_minimum_size ( ) . height ) ;
2020-09-03 13:22:16 +02:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < tabs . size ( ) ; i + + ) {
2022-01-19 17:11:44 +01:00
if ( tabs [ i ] . hidden ) {
continue ;
2014-02-10 02:10:30 +01:00
}
2016-05-01 16:27:33 +02:00
2022-01-19 17:11:44 +01:00
int ofs = ms . width ;
2016-05-01 16:27:33 +02:00
2022-01-19 17:11:44 +01:00
Ref < StyleBox > style ;
2020-05-14 16:41:43 +02:00
if ( tabs [ i ] . disabled ) {
2022-08-31 14:02:40 +02:00
style = theme_cache . tab_disabled_style ;
2020-05-14 16:41:43 +02:00
} else if ( current = = i ) {
2022-08-31 14:02:40 +02:00
style = theme_cache . tab_selected_style ;
2023-03-09 03:52:57 +01:00
} else if ( hover = = i ) {
style = theme_cache . tab_hovered_style ;
2020-05-14 16:41:43 +02:00
} else {
2022-08-31 14:02:40 +02:00
style = theme_cache . tab_unselected_style ;
2022-01-19 17:11:44 +01:00
}
ms . width + = style - > get_minimum_size ( ) . width ;
2023-03-31 21:17:59 +02:00
if ( tabs [ i ] . icon . is_valid ( ) ) {
const Size2 icon_size = _get_tab_icon_size ( i ) ;
ms . height = MAX ( ms . height , icon_size . height + y_margin ) ;
ms . width + = icon_size . width + theme_cache . h_separation ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2022-01-19 17:11:44 +01:00
if ( ! tabs [ i ] . text . is_empty ( ) ) {
2022-08-31 14:02:40 +02:00
ms . width + = tabs [ i ] . size_text + theme_cache . h_separation ;
2022-01-19 17:11:44 +01:00
}
ms . height = MAX ( ms . height , tabs [ i ] . text_buf - > get_size ( ) . y + y_margin ) ;
bool close_visible = cb_displaypolicy = = CLOSE_BUTTON_SHOW_ALWAYS | | ( cb_displaypolicy = = CLOSE_BUTTON_SHOW_ACTIVE_ONLY & & i = = current ) ;
2015-07-26 15:44:10 +02:00
if ( tabs [ i ] . right_button . is_valid ( ) ) {
2019-06-11 20:43:37 +02:00
Ref < Texture2D > rb = tabs [ i ] . right_button ;
2022-01-19 17:11:44 +01:00
if ( close_visible ) {
2022-08-31 14:02:40 +02:00
ms . width + = theme_cache . button_hl_style - > get_minimum_size ( ) . width + rb - > get_width ( ) ;
2022-01-19 17:11:44 +01:00
} else {
2022-08-31 14:02:40 +02:00
ms . width + = theme_cache . button_hl_style - > get_margin ( SIDE_LEFT ) + rb - > get_width ( ) + theme_cache . h_separation ;
2022-01-19 17:11:44 +01:00
}
2022-03-07 02:17:35 +01:00
ms . height = MAX ( ms . height , rb - > get_height ( ) + y_margin ) ;
2022-01-19 17:11:44 +01:00
}
if ( close_visible ) {
2022-08-31 14:02:40 +02:00
ms . width + = theme_cache . button_hl_style - > get_margin ( SIDE_LEFT ) + theme_cache . close_icon - > get_width ( ) + theme_cache . h_separation ;
2022-01-19 17:11:44 +01:00
2022-08-31 14:02:40 +02:00
ms . height = MAX ( ms . height , theme_cache . close_icon - > get_height ( ) + y_margin ) ;
2015-07-26 15:44:10 +02:00
}
2015-08-18 20:27:01 +02:00
2022-01-19 17:11:44 +01:00
if ( ms . width - ofs > style - > get_minimum_size ( ) . width ) {
2022-08-31 14:02:40 +02:00
ms . width - = theme_cache . h_separation ;
2015-08-18 20:27:01 +02:00
}
2014-02-10 02:10:30 +01:00
}
2021-03-30 12:20:00 +02:00
if ( clip_tabs ) {
ms . width = 0 ;
}
2014-02-10 02:10:30 +01:00
return ms ;
}
2021-10-17 18:55:44 +02:00
void TabBar : : gui_input ( const Ref < InputEvent > & p_event ) {
2021-04-05 08:52:21 +02:00
ERR_FAIL_COND ( p_event . is_null ( ) ) ;
2017-05-20 17:38:03 +02:00
Ref < InputEventMouseMotion > mm = p_event ;
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
if ( mm . is_valid ( ) ) {
2017-06-03 10:54:24 +02:00
Point2 pos = mm - > get_position ( ) ;
2015-07-26 15:44:10 +02:00
2015-12-14 14:24:28 +01:00
if ( buttons_visible ) {
2020-09-03 13:22:16 +02:00
if ( is_layout_rtl ( ) ) {
2022-08-31 14:02:40 +02:00
if ( pos . x < theme_cache . decrement_icon - > get_width ( ) ) {
2021-09-18 16:24:36 +02:00
if ( highlight_arrow ! = 1 ) {
highlight_arrow = 1 ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2021-09-18 16:24:36 +02:00
}
2022-08-31 14:02:40 +02:00
} else if ( pos . x < theme_cache . increment_icon - > get_width ( ) + theme_cache . decrement_icon - > get_width ( ) ) {
2021-09-18 16:24:36 +02:00
if ( highlight_arrow ! = 0 ) {
highlight_arrow = 0 ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2021-09-18 16:24:36 +02:00
}
} else if ( highlight_arrow ! = - 1 ) {
highlight_arrow = - 1 ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2020-09-03 13:22:16 +02:00
}
} else {
2022-08-31 14:02:40 +02:00
int limit_minus_buttons = get_size ( ) . width - theme_cache . increment_icon - > get_width ( ) - theme_cache . decrement_icon - > get_width ( ) ;
if ( pos . x > limit_minus_buttons + theme_cache . decrement_icon - > get_width ( ) ) {
2021-09-18 16:24:36 +02:00
if ( highlight_arrow ! = 1 ) {
highlight_arrow = 1 ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2021-09-18 16:24:36 +02:00
}
2021-03-30 12:20:00 +02:00
} else if ( pos . x > limit_minus_buttons ) {
2021-09-18 16:24:36 +02:00
if ( highlight_arrow ! = 0 ) {
highlight_arrow = 0 ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2021-09-18 16:24:36 +02:00
}
} else if ( highlight_arrow ! = - 1 ) {
highlight_arrow = - 1 ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2020-09-03 13:22:16 +02:00
}
2015-12-14 14:24:28 +01:00
}
}
2022-03-20 02:24:36 +01:00
if ( get_viewport ( ) - > gui_is_dragging ( ) & & can_drop_data ( pos , get_viewport ( ) - > gui_get_drag_data ( ) ) ) {
dragging_valid_tab = true ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2022-03-20 02:24:36 +01:00
}
2022-12-27 03:17:05 +01:00
if ( ! tabs . is_empty ( ) ) {
_update_hover ( ) ;
}
2022-03-20 02:24:36 +01:00
2015-07-26 15:44:10 +02:00
return ;
}
2017-05-20 17:38:03 +02:00
Ref < InputEventMouseButton > mb = p_event ;
2017-11-16 23:57:57 +01:00
if ( mb . is_valid ( ) ) {
2022-09-02 11:37:48 +02:00
if ( mb - > is_pressed ( ) & & mb - > get_button_index ( ) = = MouseButton : : WHEEL_UP & & ! mb - > is_command_or_control_pressed ( ) ) {
2017-11-16 23:57:57 +01:00
if ( scrolling_enabled & & buttons_visible ) {
if ( offset > 0 ) {
offset - - ;
2022-01-12 01:33:43 +01:00
_update_cache ( ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2017-11-16 23:57:57 +01:00
}
}
2015-07-26 15:44:10 +02:00
}
2022-09-02 11:37:48 +02:00
if ( mb - > is_pressed ( ) & & mb - > get_button_index ( ) = = MouseButton : : WHEEL_DOWN & & ! mb - > is_command_or_control_pressed ( ) ) {
2017-11-16 23:57:57 +01:00
if ( scrolling_enabled & & buttons_visible ) {
2022-01-12 01:33:43 +01:00
if ( missing_right & & offset < tabs . size ( ) ) {
2017-11-16 23:57:57 +01:00
offset + + ;
2022-01-12 01:33:43 +01:00
_update_cache ( ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2017-11-16 23:57:57 +01:00
}
}
}
2021-08-13 23:31:57 +02:00
if ( rb_pressing & & ! mb - > is_pressed ( ) & & mb - > get_button_index ( ) = = MouseButton : : LEFT ) {
2017-11-16 23:57:57 +01:00
if ( rb_hover ! = - 1 ) {
2022-01-19 17:11:44 +01:00
emit_signal ( SNAME ( " tab_button_pressed " ) , rb_hover ) ;
2017-11-16 23:57:57 +01:00
}
2016-05-01 16:27:33 +02:00
2017-11-16 23:57:57 +01:00
rb_pressing = false ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2015-08-18 20:27:01 +02:00
}
2021-08-13 23:31:57 +02:00
if ( cb_pressing & & ! mb - > is_pressed ( ) & & mb - > get_button_index ( ) = = MouseButton : : LEFT ) {
2017-11-16 23:57:57 +01:00
if ( cb_hover ! = - 1 ) {
2021-10-28 00:39:13 +02:00
emit_signal ( SNAME ( " tab_close_pressed " ) , cb_hover ) ;
2017-11-16 23:57:57 +01:00
}
2014-02-10 02:10:30 +01:00
2017-11-16 23:57:57 +01:00
cb_pressing = false ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2017-11-16 23:57:57 +01:00
}
2014-02-10 02:10:30 +01:00
2021-08-13 23:31:57 +02:00
if ( mb - > is_pressed ( ) & & ( mb - > get_button_index ( ) = = MouseButton : : LEFT | | ( select_with_rmb & & mb - > get_button_index ( ) = = MouseButton : : RIGHT ) ) ) {
2021-09-25 11:01:45 +02:00
Point2 pos = mb - > get_position ( ) ;
2015-12-14 14:24:28 +01:00
2017-11-16 23:57:57 +01:00
if ( buttons_visible ) {
2020-09-03 13:22:16 +02:00
if ( is_layout_rtl ( ) ) {
2022-08-31 14:02:40 +02:00
if ( pos . x < theme_cache . decrement_icon - > get_width ( ) ) {
2020-09-03 13:22:16 +02:00
if ( missing_right ) {
offset + + ;
2022-01-12 01:33:43 +01:00
_update_cache ( ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2020-09-03 13:22:16 +02:00
}
return ;
2022-08-31 14:02:40 +02:00
} else if ( pos . x < theme_cache . increment_icon - > get_width ( ) + theme_cache . decrement_icon - > get_width ( ) ) {
2020-09-03 13:22:16 +02:00
if ( offset > 0 ) {
offset - - ;
2022-01-12 01:33:43 +01:00
_update_cache ( ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2020-09-03 13:22:16 +02:00
}
return ;
2017-11-16 23:57:57 +01:00
}
2020-09-03 13:22:16 +02:00
} else {
2022-08-31 14:02:40 +02:00
int limit = get_size ( ) . width - theme_cache . increment_icon - > get_width ( ) - theme_cache . decrement_icon - > get_width ( ) ;
if ( pos . x > limit + theme_cache . decrement_icon - > get_width ( ) ) {
2020-09-03 13:22:16 +02:00
if ( missing_right ) {
offset + + ;
2022-01-12 01:33:43 +01:00
_update_cache ( ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2020-09-03 13:22:16 +02:00
}
return ;
} else if ( pos . x > limit ) {
if ( offset > 0 ) {
offset - - ;
2022-01-12 01:33:43 +01:00
_update_cache ( ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2020-09-03 13:22:16 +02:00
}
return ;
2017-11-16 23:57:57 +01:00
}
2015-12-14 14:24:28 +01:00
}
}
2021-10-27 21:13:04 +02:00
if ( tabs . is_empty ( ) ) {
2021-10-20 14:37:43 +02:00
// Return early if there are no actual tabs to handle input for.
return ;
}
2017-11-16 23:57:57 +01:00
int found = - 1 ;
2021-10-08 03:38:04 +02:00
for ( int i = offset ; i < = max_drawn_tab ; i + + ) {
2022-01-19 17:11:44 +01:00
if ( tabs [ i ] . hidden ) {
continue ;
}
2017-11-16 23:57:57 +01:00
if ( tabs [ i ] . rb_rect . has_point ( pos ) ) {
rb_pressing = true ;
2023-04-05 19:00:23 +02:00
_update_hover ( ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2017-11-16 23:57:57 +01:00
return ;
}
2015-07-26 15:44:10 +02:00
2021-11-29 21:12:05 +01:00
if ( tabs [ i ] . cb_rect . has_point ( pos ) & & ( cb_displaypolicy = = CLOSE_BUTTON_SHOW_ALWAYS | | ( cb_displaypolicy = = CLOSE_BUTTON_SHOW_ACTIVE_ONLY & & i = = current ) ) ) {
2017-11-16 23:57:57 +01:00
cb_pressing = true ;
2023-04-05 19:00:23 +02:00
_update_hover ( ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2017-11-16 23:57:57 +01:00
return ;
}
2015-08-18 20:27:01 +02:00
2020-09-03 13:22:16 +02:00
if ( pos . x > = get_tab_rect ( i ) . position . x & & pos . x < get_tab_rect ( i ) . position . x + tabs [ i ] . size_cache ) {
2017-11-16 23:57:57 +01:00
if ( ! tabs [ i ] . disabled ) {
found = i ;
}
break ;
2017-02-27 19:07:50 +01:00
}
2014-02-10 02:10:30 +01:00
}
2017-11-16 23:57:57 +01:00
if ( found ! = - 1 ) {
2024-01-15 00:39:47 +01:00
if ( deselect_enabled & & get_current_tab ( ) = = found ) {
set_current_tab ( - 1 ) ;
} else {
set_current_tab ( found ) ;
}
2022-01-19 17:11:44 +01:00
if ( mb - > get_button_index ( ) = = MouseButton : : RIGHT ) {
// Right mouse button clicked.
emit_signal ( SNAME ( " tab_rmb_clicked " ) , found ) ;
}
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " tab_clicked " ) , found ) ;
2017-11-16 23:57:57 +01:00
}
2014-02-10 02:10:30 +01:00
}
}
2023-06-25 17:56:52 +02:00
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 ( ) ;
}
}
}
2014-02-10 02:10:30 +01:00
}
2021-10-17 18:55:44 +02:00
void TabBar : : _shape ( int p_tab ) {
2020-09-03 13:22:16 +02:00
tabs . write [ p_tab ] . text_buf - > clear ( ) ;
2021-09-24 02:20:15 +02:00
tabs . write [ p_tab ] . text_buf - > set_width ( - 1 ) ;
2020-09-03 13:22:16 +02:00
if ( tabs [ p_tab ] . text_direction = = Control : : TEXT_DIRECTION_INHERITED ) {
tabs . write [ p_tab ] . text_buf - > set_direction ( is_layout_rtl ( ) ? TextServer : : DIRECTION_RTL : TextServer : : DIRECTION_LTR ) ;
} else {
tabs . write [ p_tab ] . text_buf - > set_direction ( ( TextServer : : Direction ) tabs [ p_tab ] . text_direction ) ;
}
2023-10-19 04:12:50 +02:00
tabs . write [ p_tab ] . text_buf - > add_string ( atr ( tabs [ p_tab ] . text ) , theme_cache . font , theme_cache . font_size , tabs [ p_tab ] . language ) ;
2022-08-31 14:02:40 +02:00
}
2021-10-17 18:55:44 +02:00
void TabBar : : _notification ( int p_what ) {
2017-03-05 16:44:50 +01:00
switch ( p_what ) {
2023-10-24 18:00:54 +02:00
case NOTIFICATION_ENTER_TREE : {
if ( scroll_to_selected ) {
ensure_tab_visible ( current ) ;
}
} break ;
2023-06-25 17:56:52 +02:00
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 ;
2020-09-03 13:22:16 +02:00
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED : {
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2020-09-03 13:22:16 +02:00
} break ;
2022-02-15 18:06:48 +01:00
2021-06-04 15:21:52 +02:00
case NOTIFICATION_THEME_CHANGED :
2019-05-05 18:50:37 +02:00
case NOTIFICATION_TRANSLATION_CHANGED : {
2019-09-30 11:56:20 +02:00
for ( int i = 0 ; i < tabs . size ( ) ; + + i ) {
2020-09-03 13:22:16 +02:00
_shape ( i ) ;
2019-09-30 11:56:20 +02:00
}
2022-01-19 17:11:44 +01:00
2023-02-15 12:12:56 +01:00
queue_redraw ( ) ;
2022-01-19 17:11:44 +01:00
[[fallthrough]] ;
}
2016-01-23 00:19:57 +01:00
case NOTIFICATION_RESIZED : {
2022-01-19 17:11:44 +01:00
int ofs_old = offset ;
int max_old = max_drawn_tab ;
2017-06-15 17:30:03 +02:00
_update_cache ( ) ;
2016-01-23 00:19:57 +01:00
_ensure_no_over_offset ( ) ;
2022-01-19 17:11:44 +01:00
if ( scroll_to_selected & & ( offset ! = ofs_old | | max_drawn_tab ! = max_old ) ) {
ensure_tab_visible ( current ) ;
}
2016-01-23 00:19:57 +01:00
} break ;
2022-02-15 18:06:48 +01:00
2022-03-20 02:24:36 +01:00
case NOTIFICATION_DRAG_END : {
if ( dragging_valid_tab ) {
dragging_valid_tab = false ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2022-03-20 02:24:36 +01:00
}
} break ;
2014-02-10 02:10:30 +01:00
case NOTIFICATION_DRAW : {
2022-12-27 03:17:05 +01:00
bool rtl = is_layout_rtl ( ) ;
Vector2 size = get_size ( ) ;
2022-01-12 01:33:43 +01:00
if ( tabs . is_empty ( ) ) {
2022-12-27 03:17:05 +01:00
// Draw the drop indicator where the first tab would be if there are no tabs.
if ( dragging_valid_tab ) {
int x = rtl ? size . x : 0 ;
theme_cache . drop_mark_icon - > draw ( get_canvas_item ( ) , Point2 ( x - ( theme_cache . drop_mark_icon - > get_width ( ) / 2 ) , ( size . height - theme_cache . drop_mark_icon - > get_height ( ) ) / 2 ) , theme_cache . drop_mark_color ) ;
}
2022-01-12 01:33:43 +01:00
return ;
}
2022-08-31 14:02:40 +02:00
int limit_minus_buttons = size . width - theme_cache . increment_icon - > get_width ( ) - theme_cache . decrement_icon - > get_width ( ) ;
2014-02-10 02:10:30 +01:00
2022-01-13 00:43:31 +01:00
int ofs = tabs [ offset ] . ofs_cache ;
2015-12-14 14:24:28 +01:00
2022-01-13 00:43:31 +01:00
// Draw unselected tabs in the back.
2022-01-12 01:33:43 +01:00
for ( int i = offset ; i < = max_drawn_tab ; i + + ) {
2022-01-19 17:11:44 +01:00
if ( tabs [ i ] . hidden ) {
continue ;
}
2022-01-13 00:43:31 +01:00
if ( i ! = current ) {
Ref < StyleBox > sb ;
Color col ;
if ( tabs [ i ] . disabled ) {
2022-08-31 14:02:40 +02:00
sb = theme_cache . tab_disabled_style ;
col = theme_cache . font_disabled_color ;
2023-03-09 03:52:57 +01:00
} else if ( i = = hover ) {
sb = theme_cache . tab_hovered_style ;
col = theme_cache . font_hovered_color ;
2020-09-03 13:22:16 +02:00
} else {
2022-08-31 14:02:40 +02:00
sb = theme_cache . tab_unselected_style ;
col = theme_cache . font_unselected_color ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-06-25 17:56:52 +02:00
_draw_tab ( sb , col , i , rtl ? size . width - ofs - tabs [ i ] . size_cache : ofs , false ) ;
2020-09-03 13:22:16 +02:00
}
2014-02-10 02:10:30 +01:00
2022-01-13 00:43:31 +01:00
ofs + = tabs [ i ] . size_cache ;
}
2015-08-18 20:27:01 +02:00
2022-01-13 00:43:31 +01:00
// Draw selected tab in the front, but only if it's visible.
2022-01-19 17:11:44 +01:00
if ( current > = offset & & current < = max_drawn_tab & & ! tabs [ current ] . hidden ) {
2022-08-31 14:02:40 +02:00
Ref < StyleBox > sb = tabs [ current ] . disabled ? theme_cache . tab_disabled_style : theme_cache . tab_selected_style ;
2022-01-13 00:43:31 +01:00
float x = rtl ? size . width - tabs [ current ] . ofs_cache - tabs [ current ] . size_cache : tabs [ current ] . ofs_cache ;
2015-08-18 20:27:01 +02:00
2023-06-25 17:56:52 +02:00
_draw_tab ( sb , theme_cache . font_selected_color , current , x , has_focus ( ) ) ;
2014-02-10 02:10:30 +01:00
}
2022-01-19 17:11:44 +01:00
if ( buttons_visible ) {
2022-08-31 14:02:40 +02:00
int vofs = ( size . height - theme_cache . increment_icon - > get_size ( ) . height ) / 2 ;
2015-12-14 14:24:28 +01:00
2020-09-03 13:22:16 +02:00
if ( rtl ) {
if ( missing_right ) {
2022-08-31 14:02:40 +02:00
draw_texture ( highlight_arrow = = 1 ? theme_cache . decrement_hl_icon : theme_cache . decrement_icon , Point2 ( 0 , vofs ) ) ;
2020-09-03 13:22:16 +02:00
} else {
2022-08-31 14:02:40 +02:00
draw_texture ( theme_cache . decrement_icon , Point2 ( 0 , vofs ) , Color ( 1 , 1 , 1 , 0.5 ) ) ;
2020-09-03 13:22:16 +02:00
}
2015-12-14 14:24:28 +01:00
2020-09-03 13:22:16 +02:00
if ( offset > 0 ) {
2022-08-31 14:02:40 +02:00
draw_texture ( highlight_arrow = = 0 ? theme_cache . increment_hl_icon : theme_cache . increment_icon , Point2 ( theme_cache . increment_icon - > get_size ( ) . width , vofs ) ) ;
2020-09-03 13:22:16 +02:00
} else {
2022-08-31 14:02:40 +02:00
draw_texture ( theme_cache . increment_icon , Point2 ( theme_cache . increment_icon - > get_size ( ) . width , vofs ) , Color ( 1 , 1 , 1 , 0.5 ) ) ;
2020-09-03 13:22:16 +02:00
}
2020-05-14 16:41:43 +02:00
} else {
2020-09-03 13:22:16 +02:00
if ( offset > 0 ) {
2022-08-31 14:02:40 +02:00
draw_texture ( highlight_arrow = = 0 ? theme_cache . decrement_hl_icon : theme_cache . decrement_icon , Point2 ( limit_minus_buttons , vofs ) ) ;
2020-09-03 13:22:16 +02:00
} else {
2022-08-31 14:02:40 +02:00
draw_texture ( theme_cache . decrement_icon , Point2 ( limit_minus_buttons , vofs ) , Color ( 1 , 1 , 1 , 0.5 ) ) ;
2020-09-03 13:22:16 +02:00
}
if ( missing_right ) {
2022-08-31 14:02:40 +02:00
draw_texture ( highlight_arrow = = 1 ? theme_cache . increment_hl_icon : theme_cache . increment_icon , Point2 ( limit_minus_buttons + theme_cache . decrement_icon - > get_size ( ) . width , vofs ) ) ;
2020-09-03 13:22:16 +02:00
} else {
2022-08-31 14:02:40 +02:00
draw_texture ( theme_cache . increment_icon , Point2 ( limit_minus_buttons + theme_cache . decrement_icon - > get_size ( ) . width , vofs ) , Color ( 1 , 1 , 1 , 0.5 ) ) ;
2020-09-03 13:22:16 +02:00
}
2020-05-14 16:41:43 +02:00
}
2015-12-14 14:24:28 +01:00
}
2022-03-20 02:24:36 +01:00
if ( dragging_valid_tab ) {
int x ;
int tab_hover = get_hovered_tab ( ) ;
if ( tab_hover ! = - 1 ) {
Rect2 tab_rect = get_tab_rect ( tab_hover ) ;
x = tab_rect . position . x ;
if ( get_local_mouse_position ( ) . x > x + tab_rect . size . width / 2 ) {
x + = tab_rect . size . width ;
}
} else {
if ( rtl ^ ( get_local_mouse_position ( ) . x < get_tab_rect ( 0 ) . position . x ) ) {
x = get_tab_rect ( 0 ) . position . x ;
if ( rtl ) {
x + = get_tab_rect ( 0 ) . size . width ;
}
} else {
Rect2 tab_rect = get_tab_rect ( get_tab_count ( ) - 1 ) ;
x = tab_rect . position . x ;
if ( ! rtl ) {
x + = tab_rect . size . width ;
}
}
}
2022-08-31 14:02:40 +02:00
theme_cache . drop_mark_icon - > draw ( get_canvas_item ( ) , Point2 ( x - theme_cache . drop_mark_icon - > get_width ( ) / 2 , ( size . height - theme_cache . drop_mark_icon - > get_height ( ) ) / 2 ) , theme_cache . drop_mark_color ) ;
2022-03-20 02:24:36 +01:00
}
2014-02-10 02:10:30 +01:00
} break ;
}
}
2023-06-25 17:56:52 +02:00
void TabBar : : _draw_tab ( Ref < StyleBox > & p_tab_style , Color & p_font_color , int p_index , float p_x , bool p_focus ) {
2022-01-13 00:43:31 +01:00
RID ci = get_canvas_item ( ) ;
2022-01-19 17:11:44 +01:00
bool rtl = is_layout_rtl ( ) ;
2022-01-13 00:43:31 +01:00
2022-01-19 17:11:44 +01:00
Rect2 sb_rect = Rect2 ( p_x , 0 , tabs [ p_index ] . size_cache , get_size ( ) . height ) ;
2023-09-27 23:23:22 +02:00
if ( tab_style_v_flip ) {
draw_set_transform ( Point2 ( 0.0 , p_tab_style - > get_draw_rect ( sb_rect ) . size . y ) , 0.0 , Size2 ( 1.0 , - 1.0 ) ) ;
}
2022-01-13 00:43:31 +01:00
p_tab_style - > draw ( ci , sb_rect ) ;
2023-09-27 23:23:22 +02:00
if ( tab_style_v_flip ) {
draw_set_transform ( Point2 ( ) , 0.0 , Size2 ( 1.0 , 1.0 ) ) ;
}
2023-06-25 17:56:52 +02:00
if ( p_focus ) {
Ref < StyleBox > focus_style = theme_cache . tab_focus_style ;
focus_style - > draw ( ci , sb_rect ) ;
}
2022-01-13 00:43:31 +01:00
2022-01-19 17:11:44 +01:00
p_x + = rtl ? tabs [ p_index ] . size_cache - p_tab_style - > get_margin ( SIDE_LEFT ) : p_tab_style - > get_margin ( SIDE_LEFT ) ;
2022-01-13 00:43:31 +01:00
Size2i sb_ms = p_tab_style - > get_minimum_size ( ) ;
2022-01-19 17:11:44 +01:00
// Draw the icon.
Ref < Texture2D > icon = tabs [ p_index ] . icon ;
2022-01-13 00:43:31 +01:00
if ( icon . is_valid ( ) ) {
2023-03-31 21:17:59 +02:00
const Size2 icon_size = _get_tab_icon_size ( p_index ) ;
const Point2 icon_pos = Point2i ( rtl ? p_x - icon_size . width : p_x , p_tab_style - > get_margin ( SIDE_TOP ) + ( ( sb_rect . size . y - sb_ms . y ) - icon_size . height ) / 2 ) ;
icon - > draw_rect ( ci , Rect2 ( icon_pos , icon_size ) ) ;
2022-01-13 00:43:31 +01:00
2023-03-31 21:17:59 +02:00
p_x = rtl ? p_x - icon_size . width - theme_cache . h_separation : p_x + icon_size . width + theme_cache . h_separation ;
2022-01-13 00:43:31 +01:00
}
2022-01-19 17:11:44 +01:00
// Draw the text.
if ( ! tabs [ p_index ] . text . is_empty ( ) ) {
Point2i text_pos = Point2i ( rtl ? p_x - tabs [ p_index ] . size_text : p_x ,
p_tab_style - > get_margin ( SIDE_TOP ) + ( ( sb_rect . size . y - sb_ms . y ) - tabs [ p_index ] . text_buf - > get_size ( ) . y ) / 2 ) ;
2022-01-13 00:43:31 +01:00
2022-08-31 14:02:40 +02:00
if ( theme_cache . outline_size > 0 & & theme_cache . font_outline_color . a > 0 ) {
tabs [ p_index ] . text_buf - > draw_outline ( ci , text_pos , theme_cache . outline_size , theme_cache . font_outline_color ) ;
2022-01-19 17:11:44 +01:00
}
tabs [ p_index ] . text_buf - > draw ( ci , text_pos , p_font_color ) ;
2022-01-13 00:43:31 +01:00
2022-08-31 14:02:40 +02:00
p_x = rtl ? p_x - tabs [ p_index ] . size_text - theme_cache . h_separation : p_x + tabs [ p_index ] . size_text + theme_cache . h_separation ;
2022-01-19 17:11:44 +01:00
}
2022-01-13 00:43:31 +01:00
2022-01-19 17:11:44 +01:00
// Draw and calculate rect of the right button.
if ( tabs [ p_index ] . right_button . is_valid ( ) ) {
2022-08-31 14:02:40 +02:00
Ref < StyleBox > style = theme_cache . button_hl_style ;
2022-01-19 17:11:44 +01:00
Ref < Texture2D > rb = tabs [ p_index ] . right_button ;
2022-01-13 00:43:31 +01:00
Rect2 rb_rect ;
rb_rect . size = style - > get_minimum_size ( ) + rb - > get_size ( ) ;
2022-01-19 17:11:44 +01:00
rb_rect . position . x = rtl ? p_x - rb_rect . size . width : p_x ;
2022-01-13 00:43:31 +01:00
rb_rect . position . y = p_tab_style - > get_margin ( SIDE_TOP ) + ( ( sb_rect . size . y - sb_ms . y ) - ( rb_rect . size . y ) ) / 2 ;
2022-01-19 17:11:44 +01:00
tabs . write [ p_index ] . rb_rect = rb_rect ;
2022-01-13 00:43:31 +01:00
if ( rb_hover = = p_index ) {
if ( rb_pressing ) {
2022-08-31 14:02:40 +02:00
theme_cache . button_pressed_style - > draw ( ci , rb_rect ) ;
2022-01-13 00:43:31 +01:00
} else {
style - > draw ( ci , rb_rect ) ;
}
}
2022-01-19 17:11:44 +01:00
rb - > draw ( ci , Point2i ( rb_rect . position . x + style - > get_margin ( SIDE_LEFT ) , rb_rect . position . y + style - > get_margin ( SIDE_TOP ) ) ) ;
p_x = rtl ? rb_rect . position . x : rb_rect . position . x + rb_rect . size . width ;
2023-10-14 00:17:51 +02:00
} else {
tabs . write [ p_index ] . rb_rect = Rect2 ( ) ;
2022-01-13 00:43:31 +01:00
}
2022-01-19 17:11:44 +01:00
// Draw and calculate rect of the close button.
2022-01-13 00:43:31 +01:00
if ( cb_displaypolicy = = CLOSE_BUTTON_SHOW_ALWAYS | | ( cb_displaypolicy = = CLOSE_BUTTON_SHOW_ACTIVE_ONLY & & p_index = = current ) ) {
2022-08-31 14:02:40 +02:00
Ref < StyleBox > style = theme_cache . button_hl_style ;
Ref < Texture2D > cb = theme_cache . close_icon ;
2022-01-13 00:43:31 +01:00
Rect2 cb_rect ;
cb_rect . size = style - > get_minimum_size ( ) + cb - > get_size ( ) ;
2022-01-19 17:11:44 +01:00
cb_rect . position . x = rtl ? p_x - cb_rect . size . width : p_x ;
2022-01-13 00:43:31 +01:00
cb_rect . position . y = p_tab_style - > get_margin ( SIDE_TOP ) + ( ( sb_rect . size . y - sb_ms . y ) - ( cb_rect . size . y ) ) / 2 ;
2022-01-19 17:11:44 +01:00
tabs . write [ p_index ] . cb_rect = cb_rect ;
if ( ! tabs [ p_index ] . disabled & & cb_hover = = p_index ) {
2022-01-13 00:43:31 +01:00
if ( cb_pressing ) {
2022-08-31 14:02:40 +02:00
theme_cache . button_pressed_style - > draw ( ci , cb_rect ) ;
2022-01-13 00:43:31 +01:00
} else {
style - > draw ( ci , cb_rect ) ;
}
}
2022-01-19 17:11:44 +01:00
cb - > draw ( ci , Point2i ( cb_rect . position . x + style - > get_margin ( SIDE_LEFT ) , cb_rect . position . y + style - > get_margin ( SIDE_TOP ) ) ) ;
2022-01-13 00:43:31 +01:00
}
}
2021-11-03 19:05:28 +01:00
void TabBar : : set_tab_count ( int p_count ) {
2022-01-19 17:11:44 +01:00
if ( p_count = = tabs . size ( ) ) {
return ;
}
2021-11-03 19:05:28 +01:00
ERR_FAIL_COND ( p_count < 0 ) ;
tabs . resize ( p_count ) ;
2022-01-19 17:11:44 +01:00
if ( p_count = = 0 ) {
offset = 0 ;
max_drawn_tab = 0 ;
2024-01-15 00:39:47 +01:00
current = - 1 ;
previous = - 1 ;
2022-01-19 17:11:44 +01:00
} else {
offset = MIN ( offset , p_count - 1 ) ;
max_drawn_tab = MIN ( max_drawn_tab , p_count - 1 ) ;
current = MIN ( current , p_count - 1 ) ;
2022-02-14 05:58:17 +01:00
_update_cache ( ) ;
_ensure_no_over_offset ( ) ;
if ( scroll_to_selected ) {
ensure_tab_visible ( current ) ;
}
2022-01-19 17:11:44 +01:00
}
2022-02-14 05:58:17 +01:00
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2022-01-19 17:11:44 +01:00
update_minimum_size ( ) ;
2021-11-03 19:05:28 +01:00
notify_property_list_changed ( ) ;
}
2021-10-17 18:55:44 +02:00
int TabBar : : get_tab_count ( ) const {
2014-02-10 02:10:30 +01:00
return tabs . size ( ) ;
}
2021-10-17 18:55:44 +02:00
void TabBar : : set_current_tab ( int p_current ) {
2024-01-15 00:39:47 +01:00
if ( p_current = = - 1 ) {
// An index of -1 is only valid if deselecting is enabled or there are no valid tabs.
ERR_FAIL_COND_MSG ( ! _can_deselect ( ) , " Cannot deselect tabs, deselection is not enabled. " ) ;
} else {
ERR_FAIL_INDEX ( p_current , get_tab_count ( ) ) ;
}
2014-02-10 02:10:30 +01:00
2020-09-08 22:30:47 +02:00
previous = current ;
2017-03-05 16:44:50 +01:00
current = p_current ;
2014-02-10 02:10:30 +01:00
2022-01-19 17:11:44 +01:00
if ( current = = previous ) {
emit_signal ( SNAME ( " tab_selected " ) , current ) ;
return ;
}
emit_signal ( SNAME ( " tab_selected " ) , current ) ;
2017-06-15 17:30:03 +02:00
_update_cache ( ) ;
2022-01-19 17:11:44 +01:00
if ( scroll_to_selected ) {
ensure_tab_visible ( current ) ;
}
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2017-08-05 17:56:00 +02:00
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " tab_changed " ) , p_current ) ;
2014-02-10 02:10:30 +01:00
}
2021-10-17 18:55:44 +02:00
int TabBar : : get_current_tab ( ) const {
2014-02-10 02:10:30 +01:00
return current ;
}
2021-10-17 18:55:44 +02:00
int TabBar : : get_previous_tab ( ) const {
2020-09-08 22:30:47 +02:00
return previous ;
}
2021-10-17 18:55:44 +02:00
int TabBar : : get_hovered_tab ( ) const {
2017-06-15 17:30:03 +02:00
return hover ;
}
2023-06-25 17:56:52 +02:00
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 ( ) ;
}
2023-10-25 21:26:03 +02:00
if ( ! is_tab_disabled ( target_tab ) & & ! is_tab_hidden ( target_tab ) ) {
2023-06-25 17:56:52 +02:00
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 ( ) ;
2023-10-25 21:26:03 +02:00
if ( ! is_tab_disabled ( target_tab ) & & ! is_tab_hidden ( target_tab ) ) {
2023-06-25 17:56:52 +02:00
set_current_tab ( target_tab ) ;
return true ;
}
}
return false ;
}
2021-10-17 18:55:44 +02:00
int TabBar : : get_tab_offset ( ) const {
2017-11-16 23:57:57 +01:00
return offset ;
}
2021-10-17 18:55:44 +02:00
bool TabBar : : get_offset_buttons_visible ( ) const {
2017-11-16 23:57:57 +01:00
return buttons_visible ;
}
2021-10-17 18:55:44 +02:00
void TabBar : : set_tab_title ( int p_tab , const String & p_title ) {
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX ( p_tab , tabs . size ( ) ) ;
2022-03-16 08:50:48 +01:00
if ( tabs [ p_tab ] . text = = p_title ) {
return ;
}
2018-07-25 03:11:03 +02:00
tabs . write [ p_tab ] . text = p_title ;
2022-01-19 17:11:44 +01:00
2020-09-03 13:22:16 +02:00
_shape ( p_tab ) ;
2022-01-12 01:33:43 +01:00
_update_cache ( ) ;
2022-01-19 17:11:44 +01:00
_ensure_no_over_offset ( ) ;
if ( scroll_to_selected ) {
ensure_tab_visible ( current ) ;
}
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2021-12-06 14:02:34 +01:00
update_minimum_size ( ) ;
2014-02-10 02:10:30 +01:00
}
2021-10-17 18:55:44 +02:00
String TabBar : : get_tab_title ( int p_tab ) const {
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX_V ( p_tab , tabs . size ( ) , " " ) ;
2014-02-10 02:10:30 +01:00
return tabs [ p_tab ] . text ;
}
2021-10-17 18:55:44 +02:00
void TabBar : : set_tab_text_direction ( int p_tab , Control : : TextDirection p_text_direction ) {
2020-09-03 13:22:16 +02:00
ERR_FAIL_INDEX ( p_tab , tabs . size ( ) ) ;
ERR_FAIL_COND ( ( int ) p_text_direction < - 1 | | ( int ) p_text_direction > 3 ) ;
2022-01-19 17:11:44 +01:00
2020-09-03 13:22:16 +02:00
if ( tabs [ p_tab ] . text_direction ! = p_text_direction ) {
tabs . write [ p_tab ] . text_direction = p_text_direction ;
_shape ( p_tab ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2020-09-03 13:22:16 +02:00
}
}
2021-10-17 18:55:44 +02:00
Control : : TextDirection TabBar : : get_tab_text_direction ( int p_tab ) const {
2020-09-03 13:22:16 +02:00
ERR_FAIL_INDEX_V ( p_tab , tabs . size ( ) , Control : : TEXT_DIRECTION_INHERITED ) ;
return tabs [ p_tab ] . text_direction ;
}
2021-10-17 18:55:44 +02:00
void TabBar : : set_tab_language ( int p_tab , const String & p_language ) {
2020-09-03 13:22:16 +02:00
ERR_FAIL_INDEX ( p_tab , tabs . size ( ) ) ;
2022-01-19 17:11:44 +01:00
2020-09-03 13:22:16 +02:00
if ( tabs [ p_tab ] . language ! = p_language ) {
tabs . write [ p_tab ] . language = p_language ;
_shape ( p_tab ) ;
2022-01-19 17:11:44 +01:00
_update_cache ( ) ;
_ensure_no_over_offset ( ) ;
if ( scroll_to_selected ) {
ensure_tab_visible ( current ) ;
}
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2022-01-19 17:11:44 +01:00
update_minimum_size ( ) ;
2020-09-03 13:22:16 +02:00
}
}
2021-10-17 18:55:44 +02:00
String TabBar : : get_tab_language ( int p_tab ) const {
2020-09-03 13:22:16 +02:00
ERR_FAIL_INDEX_V ( p_tab , tabs . size ( ) , " " ) ;
return tabs [ p_tab ] . language ;
}
2021-10-17 18:55:44 +02:00
void TabBar : : set_tab_icon ( int p_tab , const Ref < Texture2D > & p_icon ) {
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX ( p_tab , tabs . size ( ) ) ;
2022-03-16 08:50:48 +01:00
if ( tabs [ p_tab ] . icon = = p_icon ) {
return ;
}
2018-07-25 03:11:03 +02:00
tabs . write [ p_tab ] . icon = p_icon ;
2022-01-19 17:11:44 +01:00
2022-01-12 01:33:43 +01:00
_update_cache ( ) ;
2022-01-19 17:11:44 +01:00
_ensure_no_over_offset ( ) ;
if ( scroll_to_selected ) {
ensure_tab_visible ( current ) ;
}
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2021-12-06 14:02:34 +01:00
update_minimum_size ( ) ;
2014-02-10 02:10:30 +01:00
}
2016-05-01 16:27:33 +02:00
2021-10-17 18:55:44 +02:00
Ref < Texture2D > TabBar : : get_tab_icon ( int p_tab ) const {
2019-06-11 20:43:37 +02:00
ERR_FAIL_INDEX_V ( p_tab , tabs . size ( ) , Ref < Texture2D > ( ) ) ;
2014-02-10 02:10:30 +01:00
return tabs [ p_tab ] . icon ;
}
2023-03-31 21:17:59 +02:00
void TabBar : : set_tab_icon_max_width ( int p_tab , int p_width ) {
ERR_FAIL_INDEX ( p_tab , tabs . size ( ) ) ;
if ( tabs [ p_tab ] . icon_max_width = = p_width ) {
return ;
}
tabs . write [ p_tab ] . icon_max_width = p_width ;
_update_cache ( ) ;
_ensure_no_over_offset ( ) ;
if ( scroll_to_selected ) {
ensure_tab_visible ( current ) ;
}
queue_redraw ( ) ;
update_minimum_size ( ) ;
}
int TabBar : : get_tab_icon_max_width ( int p_tab ) const {
ERR_FAIL_INDEX_V ( p_tab , tabs . size ( ) , 0 ) ;
return tabs [ p_tab ] . icon_max_width ;
}
2021-10-17 18:55:44 +02:00
void TabBar : : set_tab_disabled ( int p_tab , bool p_disabled ) {
2017-02-27 19:07:50 +01:00
ERR_FAIL_INDEX ( p_tab , tabs . size ( ) ) ;
2022-03-16 08:50:48 +01:00
if ( tabs [ p_tab ] . disabled = = p_disabled ) {
return ;
}
2018-07-25 03:11:03 +02:00
tabs . write [ p_tab ] . disabled = p_disabled ;
2022-01-19 17:11:44 +01:00
_update_cache ( ) ;
_ensure_no_over_offset ( ) ;
if ( scroll_to_selected ) {
ensure_tab_visible ( current ) ;
}
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2022-01-19 17:11:44 +01:00
update_minimum_size ( ) ;
2017-02-27 19:07:50 +01:00
}
2020-05-14 14:29:06 +02:00
2021-11-03 19:05:28 +01:00
bool TabBar : : is_tab_disabled ( int p_tab ) const {
2017-02-27 19:07:50 +01:00
ERR_FAIL_INDEX_V ( p_tab , tabs . size ( ) , false ) ;
return tabs [ p_tab ] . disabled ;
}
2022-01-19 17:11:44 +01:00
void TabBar : : set_tab_hidden ( int p_tab , bool p_hidden ) {
ERR_FAIL_INDEX ( p_tab , tabs . size ( ) ) ;
2022-03-16 08:50:48 +01:00
if ( tabs [ p_tab ] . hidden = = p_hidden ) {
return ;
}
2022-01-19 17:11:44 +01:00
tabs . write [ p_tab ] . hidden = p_hidden ;
_update_cache ( ) ;
_ensure_no_over_offset ( ) ;
if ( scroll_to_selected ) {
ensure_tab_visible ( current ) ;
}
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2022-01-19 17:11:44 +01:00
update_minimum_size ( ) ;
}
bool TabBar : : is_tab_hidden ( int p_tab ) const {
ERR_FAIL_INDEX_V ( p_tab , tabs . size ( ) , false ) ;
return tabs [ p_tab ] . hidden ;
}
2023-04-11 18:48:47 +02:00
void TabBar : : set_tab_metadata ( int p_tab , const Variant & p_metadata ) {
ERR_FAIL_INDEX ( p_tab , tabs . size ( ) ) ;
tabs . write [ p_tab ] . metadata = p_metadata ;
}
Variant TabBar : : get_tab_metadata ( int p_tab ) const {
ERR_FAIL_INDEX_V ( p_tab , tabs . size ( ) , Variant ( ) ) ;
return tabs [ p_tab ] . metadata ;
}
2022-01-19 17:11:44 +01:00
void TabBar : : set_tab_button_icon ( int p_tab , const Ref < Texture2D > & p_icon ) {
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX ( p_tab , tabs . size ( ) ) ;
2022-03-16 08:50:48 +01:00
if ( tabs [ p_tab ] . right_button = = p_icon ) {
return ;
}
2022-01-19 17:11:44 +01:00
tabs . write [ p_tab ] . right_button = p_icon ;
2017-11-16 23:57:57 +01:00
_update_cache ( ) ;
2022-01-19 17:11:44 +01:00
_ensure_no_over_offset ( ) ;
if ( scroll_to_selected ) {
ensure_tab_visible ( current ) ;
}
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2021-12-06 14:02:34 +01:00
update_minimum_size ( ) ;
2015-07-26 15:44:10 +02:00
}
2020-05-14 14:29:06 +02:00
2022-01-19 17:11:44 +01:00
Ref < Texture2D > TabBar : : get_tab_button_icon ( int p_tab ) const {
2019-06-11 20:43:37 +02:00
ERR_FAIL_INDEX_V ( p_tab , tabs . size ( ) , Ref < Texture2D > ( ) ) ;
2015-07-26 15:44:10 +02:00
return tabs [ p_tab ] . right_button ;
}
2021-10-17 18:55:44 +02:00
void TabBar : : _update_hover ( ) {
2018-10-21 15:57:55 +02:00
if ( ! is_inside_tree ( ) ) {
return ;
}
2022-02-07 21:40:16 +01:00
ERR_FAIL_COND ( tabs . is_empty ( ) ) ;
2018-10-21 15:57:55 +02:00
const Point2 & pos = get_local_mouse_position ( ) ;
2022-01-19 17:11:44 +01:00
// Test hovering to display right or close button.
2018-10-21 15:57:55 +02:00
int hover_now = - 1 ;
int hover_buttons = - 1 ;
2022-01-19 17:11:44 +01:00
for ( int i = offset ; i < = max_drawn_tab ; i + + ) {
if ( tabs [ i ] . hidden ) {
continue ;
}
2018-10-21 15:57:55 +02:00
Rect2 rect = get_tab_rect ( i ) ;
if ( rect . has_point ( pos ) ) {
hover_now = i ;
}
2022-01-19 17:11:44 +01:00
2018-10-21 15:57:55 +02:00
if ( tabs [ i ] . rb_rect . has_point ( pos ) ) {
rb_hover = i ;
cb_hover = - 1 ;
hover_buttons = i ;
} else if ( ! tabs [ i ] . disabled & & tabs [ i ] . cb_rect . has_point ( pos ) ) {
cb_hover = i ;
rb_hover = - 1 ;
hover_buttons = i ;
2022-01-19 17:11:44 +01:00
}
if ( hover_buttons ! = - 1 ) {
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2018-10-21 15:57:55 +02:00
break ;
}
}
2022-01-19 17:11:44 +01:00
2018-10-21 15:57:55 +02:00
if ( hover ! = hover_now ) {
hover = hover_now ;
2022-01-19 17:11:44 +01:00
if ( hover ! = - 1 ) {
emit_signal ( SNAME ( " tab_hovered " ) , hover ) ;
}
2023-06-28 01:33:13 +02:00
_update_cache ( ) ;
2023-03-09 03:52:57 +01:00
queue_redraw ( ) ;
2018-10-21 15:57:55 +02:00
}
2021-11-29 21:12:05 +01:00
if ( hover_buttons = = - 1 ) { // No hover.
2022-01-19 17:11:44 +01:00
int rb_hover_old = rb_hover ;
int cb_hover_old = cb_hover ;
2018-10-21 15:57:55 +02:00
rb_hover = hover_buttons ;
cb_hover = hover_buttons ;
2022-01-19 17:11:44 +01:00
if ( rb_hover ! = rb_hover_old | | cb_hover ! = cb_hover_old ) {
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2022-01-19 17:11:44 +01:00
}
2018-10-21 15:57:55 +02:00
}
}
2023-09-26 19:12:08 +02:00
void TabBar : : _update_cache ( bool p_update_hover ) {
2022-01-12 01:33:43 +01:00
if ( tabs . is_empty ( ) ) {
2022-05-28 06:54:45 +02:00
buttons_visible = false ;
2022-01-12 01:33:43 +01:00
return ;
}
int limit = get_size ( ) . width ;
2022-08-31 14:02:40 +02:00
int limit_minus_buttons = limit - theme_cache . increment_icon - > get_width ( ) - theme_cache . decrement_icon - > get_width ( ) ;
2017-06-15 17:30:03 +02:00
int w = 0 ;
2022-02-03 06:45:31 +01:00
max_drawn_tab = tabs . size ( ) - 1 ;
2022-01-12 01:33:43 +01:00
2017-06-15 17:30:03 +02:00
for ( int i = 0 ; i < tabs . size ( ) ; i + + ) {
2020-09-03 13:22:16 +02:00
tabs . write [ i ] . text_buf - > set_width ( - 1 ) ;
2022-02-03 06:45:31 +01:00
tabs . write [ i ] . size_text = Math : : ceil ( tabs [ i ] . text_buf - > get_size ( ) . x ) ;
2022-01-19 17:11:44 +01:00
tabs . write [ i ] . size_cache = get_tab_width ( i ) ;
2022-02-03 06:45:31 +01:00
if ( max_width > 0 & & tabs [ i ] . size_cache > max_width ) {
int size_textless = tabs [ i ] . size_cache - tabs [ i ] . size_text ;
int mw = MAX ( size_textless , max_width ) ;
2022-01-19 17:11:44 +01:00
2022-02-03 06:45:31 +01:00
tabs . write [ i ] . size_text = MAX ( mw - size_textless , 1 ) ;
tabs . write [ i ] . text_buf - > set_width ( tabs [ i ] . size_text ) ;
tabs . write [ i ] . size_cache = size_textless + tabs [ i ] . size_text ;
2017-06-15 17:30:03 +02:00
}
2022-01-19 17:11:44 +01:00
2022-02-03 06:45:31 +01:00
if ( i < offset | | i > max_drawn_tab ) {
tabs . write [ i ] . ofs_cache = 0 ;
2022-01-19 17:11:44 +01:00
continue ;
2017-06-15 17:30:03 +02:00
}
2022-01-12 01:33:43 +01:00
2022-02-03 06:45:31 +01:00
tabs . write [ i ] . ofs_cache = w ;
2022-01-12 01:33:43 +01:00
2022-02-03 06:45:31 +01:00
if ( tabs [ i ] . hidden ) {
continue ;
2017-06-15 17:30:03 +02:00
}
2022-01-12 01:33:43 +01:00
2022-02-03 06:45:31 +01:00
w + = tabs [ i ] . size_cache ;
2022-01-12 01:33:43 +01:00
// Check if all tabs would fit inside the area.
2022-01-19 17:11:44 +01:00
if ( clip_tabs & & i > offset & & ( w > limit | | ( offset > 0 & & w > limit_minus_buttons ) ) ) {
tabs . write [ i ] . ofs_cache = 0 ;
w - = tabs [ i ] . size_cache ;
2022-02-03 06:45:31 +01:00
max_drawn_tab = i - 1 ;
2022-01-12 01:33:43 +01:00
while ( w > limit_minus_buttons & & max_drawn_tab > offset ) {
2022-01-19 17:11:44 +01:00
tabs . write [ max_drawn_tab ] . ofs_cache = 0 ;
if ( ! tabs [ max_drawn_tab ] . hidden ) {
w - = tabs [ max_drawn_tab ] . size_cache ;
}
max_drawn_tab - - ;
2022-01-12 01:33:43 +01:00
}
}
}
missing_right = max_drawn_tab < tabs . size ( ) - 1 ;
buttons_visible = offset > 0 | | missing_right ;
if ( tab_alignment = = ALIGNMENT_LEFT ) {
2023-09-26 19:12:08 +02:00
if ( p_update_hover ) {
_update_hover ( ) ;
}
2022-01-12 01:33:43 +01:00
return ;
2022-01-19 17:11:44 +01:00
}
if ( tab_alignment = = ALIGNMENT_CENTER ) {
2022-01-12 01:33:43 +01:00
w = ( ( buttons_visible ? limit_minus_buttons : limit ) - w ) / 2 ;
} else if ( tab_alignment = = ALIGNMENT_RIGHT ) {
w = ( buttons_visible ? limit_minus_buttons : limit ) - w ;
}
for ( int i = offset ; i < = max_drawn_tab ; i + + ) {
tabs . write [ i ] . ofs_cache = w ;
2022-01-19 17:11:44 +01:00
if ( ! tabs [ i ] . hidden ) {
w + = tabs [ i ] . size_cache ;
}
2017-06-15 17:30:03 +02:00
}
2022-01-19 17:11:44 +01:00
2023-09-26 19:12:08 +02:00
if ( p_update_hover ) {
_update_hover ( ) ;
}
2017-06-15 17:30:03 +02:00
}
2021-10-17 18:55:44 +02:00
void TabBar : : _on_mouse_exited ( ) {
2019-09-23 04:07:00 +02:00
rb_hover = - 1 ;
cb_hover = - 1 ;
hover = - 1 ;
highlight_arrow = - 1 ;
2022-03-20 02:24:36 +01:00
dragging_valid_tab = false ;
2023-09-26 19:12:08 +02:00
_update_cache ( false ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2019-09-23 04:07:00 +02:00
}
2021-10-17 18:55:44 +02:00
void TabBar : : add_tab ( const String & p_str , const Ref < Texture2D > & p_icon ) {
2014-02-10 02:10:30 +01:00
Tab t ;
2017-03-05 16:44:50 +01:00
t . text = p_str ;
2020-09-03 13:22:16 +02:00
t . text_buf - > set_direction ( is_layout_rtl ( ) ? TextServer : : DIRECTION_RTL : TextServer : : DIRECTION_LTR ) ;
2017-03-05 16:44:50 +01:00
t . icon = p_icon ;
2014-02-10 02:10:30 +01:00
tabs . push_back ( t ) ;
2022-01-19 17:11:44 +01:00
2022-02-03 06:45:31 +01:00
_shape ( tabs . size ( ) - 1 ) ;
2017-06-15 17:30:03 +02:00
_update_cache ( ) ;
2022-01-19 17:11:44 +01:00
if ( scroll_to_selected ) {
ensure_tab_visible ( current ) ;
}
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2021-12-06 14:02:34 +01:00
update_minimum_size ( ) ;
2022-03-02 15:37:10 +01:00
2024-01-15 00:39:47 +01:00
if ( tabs . size ( ) = = 1 ) {
if ( is_inside_tree ( ) ) {
set_current_tab ( 0 ) ;
} else {
current = 0 ;
previous = - 1 ;
}
2022-03-02 15:37:10 +01:00
}
2014-02-10 02:10:30 +01:00
}
2021-10-17 18:55:44 +02:00
void TabBar : : clear_tabs ( ) {
2022-03-02 15:37:10 +01:00
if ( tabs . is_empty ( ) ) {
return ;
}
2015-06-22 05:03:19 +02:00
tabs . clear ( ) ;
2022-01-19 17:11:44 +01:00
offset = 0 ;
max_drawn_tab = 0 ;
2024-01-15 00:39:47 +01:00
current = - 1 ;
previous = - 1 ;
2022-01-19 17:11:44 +01:00
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2022-01-19 17:11:44 +01:00
update_minimum_size ( ) ;
2021-11-03 19:05:28 +01:00
notify_property_list_changed ( ) ;
2015-06-22 05:03:19 +02:00
}
2021-10-17 18:55:44 +02:00
void TabBar : : remove_tab ( int p_idx ) {
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX ( p_idx , tabs . size ( ) ) ;
2021-07-04 00:17:03 +02:00
tabs . remove_at ( p_idx ) ;
2022-03-02 15:37:10 +01:00
2024-01-15 00:39:47 +01:00
bool is_tab_changing = current = = p_idx ;
2022-03-02 15:37:10 +01:00
if ( current > = p_idx & & current > 0 ) {
2014-02-10 02:10:30 +01:00
current - - ;
2020-05-14 16:41:43 +02:00
}
2024-01-15 00:39:47 +01:00
if ( previous > = p_idx & & previous > 0 ) {
previous - - ;
}
2014-02-10 02:10:30 +01:00
2022-03-02 15:37:10 +01:00
if ( tabs . is_empty ( ) ) {
2022-02-14 05:58:17 +01:00
offset = 0 ;
max_drawn_tab = 0 ;
2024-01-15 00:39:47 +01:00
current = - 1 ;
previous = - 1 ;
2022-02-14 05:58:17 +01:00
} else {
2024-01-15 00:39:47 +01:00
if ( current ! = - 1 ) {
// Try to change to a valid tab if possible (without firing the `tab_selected` signal).
for ( int i = current ; i < tabs . size ( ) ; i + + ) {
2023-10-25 21:26:03 +02:00
if ( ! is_tab_disabled ( i ) & & ! is_tab_hidden ( i ) ) {
current = i ;
break ;
}
}
2024-01-15 00:39:47 +01:00
// If nothing, try backwards.
if ( is_tab_disabled ( current ) | | is_tab_hidden ( current ) ) {
for ( int i = current - 1 ; i > = 0 ; i - - ) {
if ( ! is_tab_disabled ( i ) & & ! is_tab_hidden ( i ) ) {
current = i ;
break ;
}
}
}
// If still no valid tab, deselect.
if ( is_tab_disabled ( current ) | | is_tab_hidden ( current ) ) {
current = - 1 ;
}
2023-10-25 21:26:03 +02:00
}
2022-02-14 05:58:17 +01:00
offset = MIN ( offset , tabs . size ( ) - 1 ) ;
max_drawn_tab = MIN ( max_drawn_tab , tabs . size ( ) - 1 ) ;
2014-02-10 02:10:30 +01:00
2022-02-14 05:58:17 +01:00
_update_cache ( ) ;
_ensure_no_over_offset ( ) ;
2022-03-02 15:37:10 +01:00
if ( scroll_to_selected ) {
2022-02-14 05:58:17 +01:00
ensure_tab_visible ( current ) ;
}
2022-01-19 17:11:44 +01:00
}
2022-02-14 05:58:17 +01:00
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2022-01-19 17:11:44 +01:00
update_minimum_size ( ) ;
2021-11-03 19:05:28 +01:00
notify_property_list_changed ( ) ;
2022-03-02 15:37:10 +01:00
if ( is_tab_changing & & is_inside_tree ( ) ) {
emit_signal ( SNAME ( " tab_changed " ) , current ) ;
}
2015-06-22 05:03:19 +02:00
}
2021-10-17 18:55:44 +02:00
Variant TabBar : : get_drag_data ( const Point2 & p_point ) {
2020-05-14 16:41:43 +02:00
if ( ! drag_to_rearrange_enabled ) {
2022-03-02 15:37:10 +01:00
return Control : : get_drag_data ( p_point ) ; // Allow stuff like TabContainer to override it.
2020-05-14 16:41:43 +02:00
}
2023-10-19 04:12:50 +02:00
return _handle_get_drag_data ( " tab_bar_tab " , p_point ) ;
}
bool TabBar : : can_drop_data ( const Point2 & p_point , const Variant & p_data ) const {
if ( ! drag_to_rearrange_enabled ) {
return Control : : can_drop_data ( p_point , p_data ) ; // Allow stuff like TabContainer to override it.
}
return _handle_can_drop_data ( " tab_bar_tab " , p_point , p_data ) ;
}
void TabBar : : drop_data ( const Point2 & p_point , const Variant & p_data ) {
if ( ! drag_to_rearrange_enabled ) {
Control : : drop_data ( p_point , p_data ) ; // Allow stuff like TabContainer to override it.
return ;
}
2018-02-07 14:01:45 +01:00
2023-10-19 04:12:50 +02:00
_handle_drop_data ( " tab_bar_tab " , p_point , p_data , callable_mp ( this , & TabBar : : move_tab ) , callable_mp ( this , & TabBar : : _move_tab_from ) ) ;
}
Variant TabBar : : _handle_get_drag_data ( const String & p_type , const Point2 & p_point ) {
2018-02-07 14:01:45 +01:00
int tab_over = get_tab_idx_at_point ( p_point ) ;
2020-05-14 16:41:43 +02:00
if ( tab_over < 0 ) {
2018-02-07 14:01:45 +01:00
return Variant ( ) ;
2020-05-14 16:41:43 +02:00
}
2018-02-07 14:01:45 +01:00
HBoxContainer * drag_preview = memnew ( HBoxContainer ) ;
if ( ! tabs [ tab_over ] . icon . is_null ( ) ) {
2023-03-31 21:17:59 +02:00
const Size2 icon_size = _get_tab_icon_size ( tab_over ) ;
2018-02-07 14:01:45 +01:00
TextureRect * tf = memnew ( TextureRect ) ;
tf - > set_texture ( tabs [ tab_over ] . icon ) ;
2023-03-31 21:17:59 +02:00
tf - > set_stretch_mode ( TextureRect : : STRETCH_KEEP_ASPECT_CENTERED ) ;
tf - > set_expand_mode ( TextureRect : : EXPAND_IGNORE_SIZE ) ;
tf - > set_custom_minimum_size ( icon_size ) ;
2018-02-07 14:01:45 +01:00
drag_preview - > add_child ( tf ) ;
}
2022-01-19 17:11:44 +01:00
2023-10-19 04:12:50 +02:00
Label * label = memnew ( Label ( get_tab_title ( tab_over ) ) ) ;
2018-02-07 14:01:45 +01:00
drag_preview - > add_child ( label ) ;
2022-01-19 17:11:44 +01:00
2018-02-07 14:01:45 +01:00
set_drag_preview ( drag_preview ) ;
Dictionary drag_data ;
2023-10-19 04:12:50 +02:00
drag_data [ " type " ] = p_type ;
drag_data [ " tab_index " ] = tab_over ;
2018-02-07 14:01:45 +01:00
drag_data [ " from_path " ] = get_path ( ) ;
2022-03-02 15:37:10 +01:00
2018-02-07 14:01:45 +01:00
return drag_data ;
2017-07-05 15:44:53 +02:00
}
2023-10-19 04:12:50 +02:00
bool TabBar : : _handle_can_drop_data ( const String & p_type , const Point2 & p_point , const Variant & p_data ) const {
2018-02-07 14:01:45 +01:00
Dictionary d = p_data ;
2020-05-14 16:41:43 +02:00
if ( ! d . has ( " type " ) ) {
2018-02-07 14:01:45 +01:00
return false ;
2020-05-14 16:41:43 +02:00
}
2018-02-07 14:01:45 +01:00
2023-10-19 04:12:50 +02:00
if ( String ( d [ " type " ] ) = = p_type ) {
2018-02-07 14:01:45 +01:00
NodePath from_path = d [ " from_path " ] ;
NodePath to_path = get_path ( ) ;
if ( from_path = = to_path ) {
return true ;
} else if ( get_tabs_rearrange_group ( ) ! = - 1 ) {
2021-11-29 21:12:05 +01:00
// Drag and drop between other TabBars.
2018-02-07 14:01:45 +01:00
Node * from_node = get_node ( from_path ) ;
2021-10-17 18:55:44 +02:00
TabBar * from_tabs = Object : : cast_to < TabBar > ( from_node ) ;
2018-02-07 14:01:45 +01:00
if ( from_tabs & & from_tabs - > get_tabs_rearrange_group ( ) = = get_tabs_rearrange_group ( ) ) {
return true ;
}
}
}
2022-03-02 15:37:10 +01:00
2018-02-07 14:01:45 +01:00
return false ;
2017-07-05 15:44:53 +02:00
}
2023-10-19 04:12:50 +02:00
void TabBar : : _handle_drop_data ( const String & p_type , const Point2 & p_point , const Variant & p_data , const Callable & p_move_tab_callback , const Callable & p_move_tab_from_other_callback ) {
2018-02-07 14:01:45 +01:00
Dictionary d = p_data ;
2020-05-14 16:41:43 +02:00
if ( ! d . has ( " type " ) ) {
2018-02-07 14:01:45 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2018-02-07 14:01:45 +01:00
2023-10-19 04:12:50 +02:00
if ( String ( d [ " type " ] ) = = p_type ) {
int tab_from_id = d [ " tab_index " ] ;
2022-03-02 15:37:10 +01:00
int hover_now = get_tab_idx_at_point ( p_point ) ;
2018-02-07 14:01:45 +01:00
NodePath from_path = d [ " from_path " ] ;
NodePath to_path = get_path ( ) ;
2022-01-19 17:11:44 +01:00
2018-02-07 14:01:45 +01:00
if ( from_path = = to_path ) {
2022-03-20 02:24:36 +01:00
if ( tab_from_id = = hover_now ) {
return ;
}
// Drop the new tab to the left or right depending on where the target tab is being hovered.
if ( hover_now ! = - 1 ) {
Rect2 tab_rect = get_tab_rect ( hover_now ) ;
if ( is_layout_rtl ( ) ^ ( p_point . x < = tab_rect . position . x + tab_rect . size . width / 2 ) ) {
if ( hover_now > tab_from_id ) {
hover_now - = 1 ;
}
} else if ( tab_from_id > hover_now ) {
hover_now + = 1 ;
}
} else {
2022-12-27 03:17:05 +01:00
int x = tabs . is_empty ( ) ? 0 : get_tab_rect ( 0 ) . position . x ;
hover_now = is_layout_rtl ( ) ^ ( p_point . x < x ) ? 0 : get_tab_count ( ) - 1 ;
2020-05-14 16:41:43 +02:00
}
2022-01-19 17:11:44 +01:00
2023-10-19 04:12:50 +02:00
p_move_tab_callback . call ( tab_from_id , hover_now ) ;
2022-03-20 02:24:36 +01:00
if ( ! is_tab_disabled ( hover_now ) ) {
emit_signal ( SNAME ( " active_tab_rearranged " ) , hover_now ) ;
set_current_tab ( hover_now ) ;
}
2018-02-07 14:01:45 +01:00
} else if ( get_tabs_rearrange_group ( ) ! = - 1 ) {
2021-11-29 21:12:05 +01:00
// Drag and drop between Tabs.
2022-01-19 17:11:44 +01:00
2018-02-07 14:01:45 +01:00
Node * from_node = get_node ( from_path ) ;
2021-10-17 18:55:44 +02:00
TabBar * from_tabs = Object : : cast_to < TabBar > ( from_node ) ;
2022-01-19 17:11:44 +01:00
2018-02-07 14:01:45 +01:00
if ( from_tabs & & from_tabs - > get_tabs_rearrange_group ( ) = = get_tabs_rearrange_group ( ) ) {
2020-05-14 16:41:43 +02:00
if ( tab_from_id > = from_tabs - > get_tab_count ( ) ) {
2018-02-07 14:01:45 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2022-01-19 17:11:44 +01:00
2022-03-20 02:24:36 +01:00
// Drop the new tab to the left or right depending on where the target tab is being hovered.
if ( hover_now ! = - 1 ) {
Rect2 tab_rect = get_tab_rect ( hover_now ) ;
if ( is_layout_rtl ( ) ^ ( p_point . x > tab_rect . position . x + tab_rect . size . width / 2 ) ) {
hover_now + = 1 ;
}
} else {
2022-12-27 03:17:05 +01:00
hover_now = tabs . is_empty ( ) | | ( is_layout_rtl ( ) ^ ( p_point . x < get_tab_rect ( 0 ) . position . x ) ) ? 0 : get_tab_count ( ) ;
2020-05-14 16:41:43 +02:00
}
2022-01-19 17:11:44 +01:00
2023-10-19 04:12:50 +02:00
p_move_tab_from_other_callback . call ( from_tabs , tab_from_id , hover_now ) ;
}
}
}
}
2022-01-19 17:11:44 +01:00
2023-10-19 04:12:50 +02:00
void TabBar : : _move_tab_from ( TabBar * p_from_tabbar , int p_from_index , int p_to_index ) {
Tab moving_tab = p_from_tabbar - > tabs [ p_from_index ] ;
p_from_tabbar - > remove_tab ( p_from_index ) ;
tabs . insert ( p_to_index , moving_tab ) ;
2022-03-20 02:24:36 +01:00
2023-10-19 04:12:50 +02:00
if ( tabs . size ( ) > 1 ) {
if ( current > = p_to_index ) {
current + + ;
}
if ( previous > = p_to_index ) {
previous + + ;
}
}
2022-03-02 15:37:10 +01:00
2023-10-19 04:12:50 +02:00
if ( ! is_tab_disabled ( p_to_index ) ) {
set_current_tab ( p_to_index ) ;
} else {
_update_cache ( ) ;
queue_redraw ( ) ;
2018-02-07 14:01:45 +01:00
}
2023-10-19 04:12:50 +02:00
update_minimum_size ( ) ;
2017-07-05 15:44:53 +02:00
}
2021-10-17 18:55:44 +02:00
int TabBar : : get_tab_idx_at_point ( const Point2 & p_point ) const {
2017-07-05 15:44:53 +02:00
int hover_now = - 1 ;
2022-12-27 03:17:05 +01:00
if ( ! tabs . is_empty ( ) ) {
for ( int i = offset ; i < = max_drawn_tab ; i + + ) {
Rect2 rect = get_tab_rect ( i ) ;
if ( rect . has_point ( p_point ) ) {
hover_now = i ;
}
2017-07-05 15:44:53 +02:00
}
}
return hover_now ;
}
2021-11-25 03:58:47 +01:00
void TabBar : : set_tab_alignment ( AlignmentMode p_alignment ) {
ERR_FAIL_INDEX ( p_alignment , ALIGNMENT_MAX ) ;
2022-03-16 08:50:48 +01:00
if ( tab_alignment = = p_alignment ) {
return ;
}
2021-11-25 03:58:47 +01:00
tab_alignment = p_alignment ;
2022-01-19 17:11:44 +01:00
2022-01-12 01:33:43 +01:00
_update_cache ( ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2015-06-22 05:03:19 +02:00
}
2021-11-25 03:58:47 +01:00
TabBar : : AlignmentMode TabBar : : get_tab_alignment ( ) const {
return tab_alignment ;
2014-02-10 02:10:30 +01:00
}
2021-10-17 18:55:44 +02:00
void TabBar : : set_clip_tabs ( bool p_clip_tabs ) {
2021-03-30 12:20:00 +02:00
if ( clip_tabs = = p_clip_tabs ) {
return ;
}
clip_tabs = p_clip_tabs ;
2022-01-19 17:11:44 +01:00
if ( ! clip_tabs ) {
offset = 0 ;
max_drawn_tab = 0 ;
}
2022-01-12 01:33:43 +01:00
_update_cache ( ) ;
2022-01-19 17:11:44 +01:00
if ( scroll_to_selected ) {
ensure_tab_visible ( current ) ;
}
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2021-12-06 14:02:34 +01:00
update_minimum_size ( ) ;
2021-03-30 12:20:00 +02:00
}
2021-10-17 18:55:44 +02:00
bool TabBar : : get_clip_tabs ( ) const {
2021-03-30 12:20:00 +02:00
return clip_tabs ;
}
2023-09-27 23:23:22 +02:00
void TabBar : : set_tab_style_v_flip ( bool p_tab_style_v_flip ) {
tab_style_v_flip = p_tab_style_v_flip ;
}
2022-03-02 15:37:10 +01:00
void TabBar : : move_tab ( int p_from , int p_to ) {
if ( p_from = = p_to ) {
2017-07-12 16:48:43 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2017-07-12 16:48:43 +02:00
2022-03-02 15:37:10 +01:00
ERR_FAIL_INDEX ( p_from , tabs . size ( ) ) ;
ERR_FAIL_INDEX ( p_to , tabs . size ( ) ) ;
Tab tab_from = tabs [ p_from ] ;
tabs . remove_at ( p_from ) ;
tabs . insert ( p_to , tab_from ) ;
2017-07-12 16:48:43 +02:00
2022-03-02 15:37:10 +01:00
if ( current = = p_from ) {
current = p_to ;
} else if ( current > p_from & & current < = p_to ) {
current - - ;
} else if ( current < p_from & & current > = p_to ) {
current + + ;
}
if ( previous = = p_from ) {
previous = p_to ;
2024-01-15 00:39:47 +01:00
} else if ( previous > p_from & & previous < = p_to ) {
2022-03-02 15:37:10 +01:00
previous - - ;
2024-01-15 00:39:47 +01:00
} else if ( previous < p_from & & previous > = p_to ) {
2022-03-02 15:37:10 +01:00
previous + + ;
}
2017-07-12 16:48:43 +02:00
_update_cache ( ) ;
2022-01-19 17:11:44 +01:00
_ensure_no_over_offset ( ) ;
if ( scroll_to_selected ) {
ensure_tab_visible ( current ) ;
}
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2021-11-03 19:05:28 +01:00
notify_property_list_changed ( ) ;
2017-07-12 16:48:43 +02:00
}
2021-10-17 18:55:44 +02:00
int TabBar : : get_tab_width ( int p_idx ) const {
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX_V ( p_idx , tabs . size ( ) , 0 ) ;
2016-01-13 11:39:31 +01:00
2022-01-19 17:11:44 +01:00
Ref < StyleBox > style ;
if ( tabs [ p_idx ] . disabled ) {
2022-08-31 14:02:40 +02:00
style = theme_cache . tab_disabled_style ;
2022-01-19 17:11:44 +01:00
} else if ( current = = p_idx ) {
2022-08-31 14:02:40 +02:00
style = theme_cache . tab_selected_style ;
2023-09-26 19:12:08 +02:00
// Use the unselected style's width if the hovered one is shorter, to avoid an infinite loop when switching tabs with the mouse.
} else if ( hover = = p_idx & & theme_cache . tab_hovered_style - > get_minimum_size ( ) . width > = theme_cache . tab_unselected_style - > get_minimum_size ( ) . width ) {
2023-03-09 03:52:57 +01:00
style = theme_cache . tab_hovered_style ;
2022-01-19 17:11:44 +01:00
} else {
2022-08-31 14:02:40 +02:00
style = theme_cache . tab_unselected_style ;
2022-01-19 17:11:44 +01:00
}
int x = style - > get_minimum_size ( ) . width ;
2016-01-13 11:39:31 +01:00
2023-03-31 21:17:59 +02:00
if ( tabs [ p_idx ] . icon . is_valid ( ) ) {
const Size2 icon_size = _get_tab_icon_size ( p_idx ) ;
x + = icon_size . width + theme_cache . h_separation ;
2016-01-13 11:39:31 +01:00
}
2022-01-19 17:11:44 +01:00
if ( ! tabs [ p_idx ] . text . is_empty ( ) ) {
2022-08-31 14:02:40 +02:00
x + = tabs [ p_idx ] . size_text + theme_cache . h_separation ;
2020-05-14 16:41:43 +02:00
}
2016-01-13 11:39:31 +01:00
2022-01-19 17:11:44 +01:00
bool close_visible = cb_displaypolicy = = CLOSE_BUTTON_SHOW_ALWAYS | | ( cb_displaypolicy = = CLOSE_BUTTON_SHOW_ACTIVE_ONLY & & p_idx = = current ) ;
2016-01-13 11:39:31 +01:00
if ( tabs [ p_idx ] . right_button . is_valid ( ) ) {
2022-08-31 14:02:40 +02:00
Ref < StyleBox > btn_style = theme_cache . button_hl_style ;
2019-06-11 20:43:37 +02:00
Ref < Texture2D > rb = tabs [ p_idx ] . right_button ;
2022-01-19 17:11:44 +01:00
if ( close_visible ) {
x + = btn_style - > get_minimum_size ( ) . width + rb - > get_width ( ) ;
} else {
2022-08-31 14:02:40 +02:00
x + = btn_style - > get_margin ( SIDE_LEFT ) + rb - > get_width ( ) + theme_cache . h_separation ;
2022-01-19 17:11:44 +01:00
}
2016-01-13 11:39:31 +01:00
}
2022-01-19 17:11:44 +01:00
if ( close_visible ) {
2022-08-31 14:02:40 +02:00
Ref < StyleBox > btn_style = theme_cache . button_hl_style ;
Ref < Texture2D > cb = theme_cache . close_icon ;
x + = btn_style - > get_margin ( SIDE_LEFT ) + cb - > get_width ( ) + theme_cache . h_separation ;
2022-01-19 17:11:44 +01:00
}
if ( x > style - > get_minimum_size ( ) . width ) {
2022-08-31 14:02:40 +02:00
x - = theme_cache . h_separation ;
2016-01-13 11:39:31 +01:00
}
return x ;
}
2014-02-10 02:10:30 +01:00
2023-03-31 21:17:59 +02:00
Size2 TabBar : : _get_tab_icon_size ( int p_index ) const {
ERR_FAIL_INDEX_V ( p_index , tabs . size ( ) , Size2 ( ) ) ;
const TabBar : : Tab & tab = tabs [ p_index ] ;
Size2 icon_size = tab . icon - > get_size ( ) ;
int icon_max_width = 0 ;
if ( theme_cache . icon_max_width > 0 ) {
icon_max_width = theme_cache . icon_max_width ;
}
if ( tab . icon_max_width > 0 & & ( icon_max_width = = 0 | | tab . icon_max_width < icon_max_width ) ) {
icon_max_width = tab . icon_max_width ;
}
if ( icon_max_width > 0 & & icon_size . width > icon_max_width ) {
icon_size . height = icon_size . height * icon_max_width / icon_size . width ;
icon_size . width = icon_max_width ;
}
return icon_size ;
}
2021-10-17 18:55:44 +02:00
void TabBar : : _ensure_no_over_offset ( ) {
2022-01-12 01:33:43 +01:00
if ( ! is_inside_tree ( ) | | ! buttons_visible ) {
2016-01-23 00:19:57 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-01-23 00:19:57 +01:00
2022-08-31 14:02:40 +02:00
int limit_minus_buttons = get_size ( ) . width - theme_cache . increment_icon - > get_width ( ) - theme_cache . decrement_icon - > get_width ( ) ;
2016-01-23 00:19:57 +01:00
2022-01-12 01:33:43 +01:00
int prev_offset = offset ;
int total_w = tabs [ max_drawn_tab ] . ofs_cache + tabs [ max_drawn_tab ] . size_cache - tabs [ offset ] . ofs_cache ;
2022-01-19 17:11:44 +01:00
for ( int i = offset ; i > 0 ; i - - ) {
if ( tabs [ i - 1 ] . hidden ) {
continue ;
}
total_w + = tabs [ i - 1 ] . size_cache ;
2016-01-23 00:19:57 +01:00
2022-01-12 01:33:43 +01:00
if ( total_w < limit_minus_buttons ) {
2016-01-23 00:19:57 +01:00
offset - - ;
} else {
break ;
}
}
2022-01-12 01:33:43 +01:00
if ( prev_offset ! = offset ) {
_update_cache ( ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2020-05-14 16:41:43 +02:00
}
2022-01-12 01:33:43 +01:00
}
2016-01-11 01:45:11 +01:00
2024-01-15 00:39:47 +01:00
bool TabBar : : _can_deselect ( ) const {
if ( deselect_enabled ) {
return true ;
}
// All tabs must be disabled or hidden.
for ( const Tab & tab : tabs ) {
if ( ! tab . disabled & & ! tab . hidden ) {
return false ;
}
}
return true ;
}
2022-01-12 01:33:43 +01:00
void TabBar : : ensure_tab_visible ( int p_idx ) {
if ( ! is_inside_tree ( ) | | ! buttons_visible ) {
2020-05-10 12:56:01 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2024-01-15 00:39:47 +01:00
if ( p_idx = = - 1 & & _can_deselect ( ) ) {
return ;
}
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX ( p_idx , tabs . size ( ) ) ;
2016-01-11 01:45:11 +01:00
2022-01-19 17:11:44 +01:00
if ( tabs [ p_idx ] . hidden | | ( p_idx > = offset & & p_idx < = max_drawn_tab ) ) {
2017-06-15 17:30:03 +02:00
return ;
}
2022-01-12 01:33:43 +01:00
2017-06-15 17:30:03 +02:00
if ( p_idx < offset ) {
2017-03-05 16:44:50 +01:00
offset = p_idx ;
2022-01-12 01:33:43 +01:00
_update_cache ( ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2022-01-12 01:33:43 +01:00
2016-01-11 01:45:11 +01:00
return ;
}
2022-08-31 14:02:40 +02:00
int limit_minus_buttons = get_size ( ) . width - theme_cache . increment_icon - > get_width ( ) - theme_cache . decrement_icon - > get_width ( ) ;
2021-03-30 12:20:00 +02:00
2022-01-12 01:33:43 +01:00
int total_w = tabs [ max_drawn_tab ] . ofs_cache - tabs [ offset ] . ofs_cache ;
for ( int i = max_drawn_tab ; i < = p_idx ; i + + ) {
2022-01-19 17:11:44 +01:00
if ( tabs [ i ] . hidden ) {
continue ;
}
2022-01-12 01:33:43 +01:00
total_w + = tabs [ i ] . size_cache ;
}
int prev_offset = offset ;
for ( int i = offset ; i < p_idx ; i + + ) {
2022-01-19 17:11:44 +01:00
if ( tabs [ i ] . hidden ) {
continue ;
}
2022-01-12 01:33:43 +01:00
if ( total_w > limit_minus_buttons ) {
total_w - = tabs [ i ] . size_cache ;
2017-06-15 17:30:03 +02:00
offset + + ;
2022-01-12 01:33:43 +01:00
} else {
break ;
2017-06-15 17:30:03 +02:00
}
2016-01-11 01:45:11 +01:00
}
2017-06-15 17:30:03 +02:00
if ( prev_offset ! = offset ) {
2022-01-12 01:33:43 +01:00
_update_cache ( ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2016-01-11 01:45:11 +01:00
}
2017-06-15 17:30:03 +02:00
}
2016-01-11 01:45:11 +01:00
2021-10-17 18:55:44 +02:00
Rect2 TabBar : : get_tab_rect ( int p_tab ) const {
2019-06-21 11:34:32 +02:00
ERR_FAIL_INDEX_V ( p_tab , tabs . size ( ) , Rect2 ( ) ) ;
2020-09-03 13:22:16 +02:00
if ( is_layout_rtl ( ) ) {
return Rect2 ( get_size ( ) . width - tabs [ p_tab ] . ofs_cache - tabs [ p_tab ] . size_cache , 0 , tabs [ p_tab ] . size_cache , get_size ( ) . height ) ;
} else {
return Rect2 ( tabs [ p_tab ] . ofs_cache , 0 , tabs [ p_tab ] . size_cache , get_size ( ) . height ) ;
}
2016-01-11 01:45:11 +01:00
}
2021-10-17 18:55:44 +02:00
void TabBar : : set_tab_close_display_policy ( CloseButtonDisplayPolicy p_policy ) {
2017-07-22 18:15:31 +02:00
ERR_FAIL_INDEX ( p_policy , CLOSE_BUTTON_MAX ) ;
2022-03-16 08:50:48 +01:00
if ( cb_displaypolicy = = p_policy ) {
return ;
}
2017-03-05 16:44:50 +01:00
cb_displaypolicy = p_policy ;
2022-01-19 17:11:44 +01:00
2022-01-12 01:33:43 +01:00
_update_cache ( ) ;
2022-01-19 17:11:44 +01:00
_ensure_no_over_offset ( ) ;
if ( scroll_to_selected ) {
ensure_tab_visible ( current ) ;
}
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2022-01-19 17:11:44 +01:00
update_minimum_size ( ) ;
2016-01-13 11:39:31 +01:00
}
2021-10-17 18:55:44 +02:00
TabBar : : CloseButtonDisplayPolicy TabBar : : get_tab_close_display_policy ( ) const {
2017-07-22 18:15:31 +02:00
return cb_displaypolicy ;
}
2022-02-03 06:45:31 +01:00
void TabBar : : set_max_tab_width ( int p_width ) {
ERR_FAIL_COND ( p_width < 0 ) ;
2022-03-16 08:50:48 +01:00
if ( max_width = = p_width ) {
return ;
}
2022-02-03 06:45:31 +01:00
max_width = p_width ;
_update_cache ( ) ;
_ensure_no_over_offset ( ) ;
if ( scroll_to_selected ) {
ensure_tab_visible ( current ) ;
}
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2022-02-03 06:45:31 +01:00
update_minimum_size ( ) ;
}
int TabBar : : get_max_tab_width ( ) const {
return max_width ;
2017-06-15 17:30:03 +02:00
}
2021-10-17 18:55:44 +02:00
void TabBar : : set_scrolling_enabled ( bool p_enabled ) {
2017-11-16 23:57:57 +01:00
scrolling_enabled = p_enabled ;
}
2021-10-17 18:55:44 +02:00
bool TabBar : : get_scrolling_enabled ( ) const {
2017-11-16 23:57:57 +01:00
return scrolling_enabled ;
}
2021-10-17 18:55:44 +02:00
void TabBar : : set_drag_to_rearrange_enabled ( bool p_enabled ) {
2018-02-07 14:01:45 +01:00
drag_to_rearrange_enabled = p_enabled ;
}
2021-10-17 18:55:44 +02:00
bool TabBar : : get_drag_to_rearrange_enabled ( ) const {
2018-02-07 14:01:45 +01:00
return drag_to_rearrange_enabled ;
}
2020-05-14 14:29:06 +02:00
2021-10-17 18:55:44 +02:00
void TabBar : : set_tabs_rearrange_group ( int p_group_id ) {
2018-02-07 14:01:45 +01:00
tabs_rearrange_group = p_group_id ;
}
2021-10-17 18:55:44 +02:00
int TabBar : : get_tabs_rearrange_group ( ) const {
2018-02-07 14:01:45 +01:00
return tabs_rearrange_group ;
}
2022-01-19 17:11:44 +01:00
void TabBar : : set_scroll_to_selected ( bool p_enabled ) {
scroll_to_selected = p_enabled ;
if ( p_enabled ) {
ensure_tab_visible ( current ) ;
}
}
bool TabBar : : get_scroll_to_selected ( ) const {
return scroll_to_selected ;
}
2021-10-17 18:55:44 +02:00
void TabBar : : set_select_with_rmb ( bool p_enabled ) {
2018-01-02 08:10:49 +01:00
select_with_rmb = p_enabled ;
}
2021-10-17 18:55:44 +02:00
bool TabBar : : get_select_with_rmb ( ) const {
2018-01-02 08:10:49 +01:00
return select_with_rmb ;
}
2024-01-15 00:39:47 +01:00
void TabBar : : set_deselect_enabled ( bool p_enabled ) {
if ( deselect_enabled = = p_enabled ) {
return ;
}
deselect_enabled = p_enabled ;
if ( ! deselect_enabled & & current = = - 1 & & ! tabs . is_empty ( ) ) {
select_next_available ( ) ;
}
}
bool TabBar : : get_deselect_enabled ( ) const {
return deselect_enabled ;
}
2021-11-03 19:05:28 +01:00
bool TabBar : : _set ( const StringName & p_name , const Variant & p_value ) {
Vector < String > components = String ( p_name ) . split ( " / " , true , 2 ) ;
if ( components . size ( ) > = 2 & & components [ 0 ] . begins_with ( " tab_ " ) & & components [ 0 ] . trim_prefix ( " tab_ " ) . is_valid_int ( ) ) {
int tab_index = components [ 0 ] . trim_prefix ( " tab_ " ) . to_int ( ) ;
2023-11-18 23:40:56 +01:00
const String & property = components [ 1 ] ;
2021-11-03 19:05:28 +01:00
if ( property = = " title " ) {
set_tab_title ( tab_index , p_value ) ;
return true ;
} else if ( property = = " icon " ) {
set_tab_icon ( tab_index , p_value ) ;
return true ;
2023-12-13 17:06:14 +01:00
} else if ( property = = " disabled " ) {
2021-11-03 19:05:28 +01:00
set_tab_disabled ( tab_index , p_value ) ;
return true ;
}
}
return false ;
}
bool TabBar : : _get ( const StringName & p_name , Variant & r_ret ) const {
Vector < String > components = String ( p_name ) . split ( " / " , true , 2 ) ;
if ( components . size ( ) > = 2 & & components [ 0 ] . begins_with ( " tab_ " ) & & components [ 0 ] . trim_prefix ( " tab_ " ) . is_valid_int ( ) ) {
int tab_index = components [ 0 ] . trim_prefix ( " tab_ " ) . to_int ( ) ;
2023-11-18 23:40:56 +01:00
const String & property = components [ 1 ] ;
2021-11-03 19:05:28 +01:00
if ( property = = " title " ) {
r_ret = get_tab_title ( tab_index ) ;
return true ;
} else if ( property = = " icon " ) {
r_ret = get_tab_icon ( tab_index ) ;
return true ;
2023-12-13 17:06:14 +01:00
} else if ( property = = " disabled " ) {
2021-11-03 19:05:28 +01:00
r_ret = is_tab_disabled ( tab_index ) ;
return true ;
}
}
return false ;
}
void TabBar : : _get_property_list ( List < PropertyInfo > * p_list ) const {
for ( int i = 0 ; i < tabs . size ( ) ; i + + ) {
p_list - > push_back ( PropertyInfo ( Variant : : STRING , vformat ( " tab_%d/title " , i ) ) ) ;
PropertyInfo pi = PropertyInfo ( Variant : : OBJECT , vformat ( " tab_%d/icon " , i ) , PROPERTY_HINT_RESOURCE_TYPE , " Texture2D " ) ;
pi . usage & = ~ ( get_tab_icon ( i ) . is_null ( ) ? PROPERTY_USAGE_STORAGE : 0 ) ;
p_list - > push_back ( pi ) ;
pi = PropertyInfo ( Variant : : BOOL , vformat ( " tab_%d/disabled " , i ) ) ;
pi . usage & = ~ ( ! is_tab_disabled ( i ) ? PROPERTY_USAGE_STORAGE : 0 ) ;
p_list - > push_back ( pi ) ;
}
}
2021-10-17 18:55:44 +02:00
void TabBar : : _bind_methods ( ) {
2022-01-07 13:58:28 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_tab_count " , " count " ) , & TabBar : : set_tab_count ) ;
2021-10-17 18:55:44 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_tab_count " ) , & TabBar : : get_tab_count ) ;
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 ) ;
2023-06-25 17:56:52 +02:00
ClassDB : : bind_method ( D_METHOD ( " select_previous_available " ) , & TabBar : : select_previous_available ) ;
ClassDB : : bind_method ( D_METHOD ( " select_next_available " ) , & TabBar : : select_next_available ) ;
2021-10-17 18:55:44 +02:00
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 ) ;
ClassDB : : bind_method ( D_METHOD ( " get_tab_text_direction " , " tab_idx " ) , & TabBar : : get_tab_text_direction ) ;
ClassDB : : bind_method ( D_METHOD ( " set_tab_language " , " tab_idx " , " language " ) , & TabBar : : set_tab_language ) ;
ClassDB : : bind_method ( D_METHOD ( " get_tab_language " , " tab_idx " ) , & TabBar : : get_tab_language ) ;
ClassDB : : bind_method ( D_METHOD ( " set_tab_icon " , " tab_idx " , " icon " ) , & TabBar : : set_tab_icon ) ;
ClassDB : : bind_method ( D_METHOD ( " get_tab_icon " , " tab_idx " ) , & TabBar : : get_tab_icon ) ;
2023-03-31 21:17:59 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_tab_icon_max_width " , " tab_idx " , " width " ) , & TabBar : : set_tab_icon_max_width ) ;
ClassDB : : bind_method ( D_METHOD ( " get_tab_icon_max_width " , " tab_idx " ) , & TabBar : : get_tab_icon_max_width ) ;
2022-01-19 17:11:44 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_tab_button_icon " , " tab_idx " , " icon " ) , & TabBar : : set_tab_button_icon ) ;
ClassDB : : bind_method ( D_METHOD ( " get_tab_button_icon " , " tab_idx " ) , & TabBar : : get_tab_button_icon ) ;
2021-10-17 18:55:44 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_tab_disabled " , " tab_idx " , " disabled " ) , & TabBar : : set_tab_disabled ) ;
2021-11-03 19:05:28 +01:00
ClassDB : : bind_method ( D_METHOD ( " is_tab_disabled " , " tab_idx " ) , & TabBar : : is_tab_disabled ) ;
2022-01-19 17:11:44 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_tab_hidden " , " tab_idx " , " hidden " ) , & TabBar : : set_tab_hidden ) ;
ClassDB : : bind_method ( D_METHOD ( " is_tab_hidden " , " tab_idx " ) , & TabBar : : is_tab_hidden ) ;
2023-04-11 18:48:47 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_tab_metadata " , " tab_idx " , " metadata " ) , & TabBar : : set_tab_metadata ) ;
ClassDB : : bind_method ( D_METHOD ( " get_tab_metadata " , " tab_idx " ) , & TabBar : : get_tab_metadata ) ;
2021-10-17 18:55:44 +02:00
ClassDB : : bind_method ( D_METHOD ( " remove_tab " , " tab_idx " ) , & TabBar : : remove_tab ) ;
ClassDB : : bind_method ( D_METHOD ( " add_tab " , " title " , " icon " ) , & TabBar : : add_tab , DEFVAL ( " " ) , DEFVAL ( Ref < Texture2D > ( ) ) ) ;
2022-03-02 15:37:10 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_tab_idx_at_point " , " point " ) , & TabBar : : get_tab_idx_at_point ) ;
2021-11-25 03:58:47 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_tab_alignment " , " alignment " ) , & TabBar : : set_tab_alignment ) ;
ClassDB : : bind_method ( D_METHOD ( " get_tab_alignment " ) , & TabBar : : get_tab_alignment ) ;
2021-10-17 18:55:44 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_clip_tabs " , " clip_tabs " ) , & TabBar : : set_clip_tabs ) ;
ClassDB : : bind_method ( D_METHOD ( " get_clip_tabs " ) , & TabBar : : get_clip_tabs ) ;
ClassDB : : bind_method ( D_METHOD ( " get_tab_offset " ) , & TabBar : : get_tab_offset ) ;
ClassDB : : bind_method ( D_METHOD ( " get_offset_buttons_visible " ) , & TabBar : : get_offset_buttons_visible ) ;
ClassDB : : bind_method ( D_METHOD ( " ensure_tab_visible " , " idx " ) , & TabBar : : ensure_tab_visible ) ;
ClassDB : : bind_method ( D_METHOD ( " get_tab_rect " , " tab_idx " ) , & TabBar : : get_tab_rect ) ;
ClassDB : : bind_method ( D_METHOD ( " move_tab " , " from " , " to " ) , & TabBar : : move_tab ) ;
ClassDB : : bind_method ( D_METHOD ( " set_tab_close_display_policy " , " policy " ) , & TabBar : : set_tab_close_display_policy ) ;
ClassDB : : bind_method ( D_METHOD ( " get_tab_close_display_policy " ) , & TabBar : : get_tab_close_display_policy ) ;
2022-02-03 06:45:31 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_max_tab_width " , " width " ) , & TabBar : : set_max_tab_width ) ;
ClassDB : : bind_method ( D_METHOD ( " get_max_tab_width " ) , & TabBar : : get_max_tab_width ) ;
2021-10-17 18:55:44 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_scrolling_enabled " , " enabled " ) , & TabBar : : set_scrolling_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " get_scrolling_enabled " ) , & TabBar : : get_scrolling_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " set_drag_to_rearrange_enabled " , " enabled " ) , & TabBar : : set_drag_to_rearrange_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " get_drag_to_rearrange_enabled " ) , & TabBar : : get_drag_to_rearrange_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " set_tabs_rearrange_group " , " group_id " ) , & TabBar : : set_tabs_rearrange_group ) ;
ClassDB : : bind_method ( D_METHOD ( " get_tabs_rearrange_group " ) , & TabBar : : get_tabs_rearrange_group ) ;
2022-01-19 17:11:44 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_scroll_to_selected " , " enabled " ) , & TabBar : : set_scroll_to_selected ) ;
ClassDB : : bind_method ( D_METHOD ( " get_scroll_to_selected " ) , & TabBar : : get_scroll_to_selected ) ;
2021-10-17 18:55:44 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_select_with_rmb " , " enabled " ) , & TabBar : : set_select_with_rmb ) ;
ClassDB : : bind_method ( D_METHOD ( " get_select_with_rmb " ) , & TabBar : : get_select_with_rmb ) ;
2024-01-15 00:39:47 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_deselect_enabled " , " enabled " ) , & TabBar : : set_deselect_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " get_deselect_enabled " ) , & TabBar : : get_deselect_enabled ) ;
2023-01-08 13:52:57 +01:00
ClassDB : : bind_method ( D_METHOD ( " clear_tabs " ) , & TabBar : : clear_tabs ) ;
2018-01-02 08:10:49 +01:00
2022-01-19 17:11:44 +01:00
ADD_SIGNAL ( MethodInfo ( " tab_selected " , PropertyInfo ( Variant : : INT , " tab " ) ) ) ;
2017-03-05 16:44:50 +01:00
ADD_SIGNAL ( MethodInfo ( " tab_changed " , PropertyInfo ( Variant : : INT , " tab " ) ) ) ;
2022-01-19 17:11:44 +01:00
ADD_SIGNAL ( MethodInfo ( " tab_clicked " , PropertyInfo ( Variant : : INT , " tab " ) ) ) ;
2021-10-01 01:18:23 +02:00
ADD_SIGNAL ( MethodInfo ( " tab_rmb_clicked " , PropertyInfo ( Variant : : INT , " tab " ) ) ) ;
2021-10-28 00:39:13 +02:00
ADD_SIGNAL ( MethodInfo ( " tab_close_pressed " , PropertyInfo ( Variant : : INT , " tab " ) ) ) ;
2022-01-19 17:11:44 +01:00
ADD_SIGNAL ( MethodInfo ( " tab_button_pressed " , PropertyInfo ( Variant : : INT , " tab " ) ) ) ;
2020-12-08 10:51:06 +01:00
ADD_SIGNAL ( MethodInfo ( " tab_hovered " , PropertyInfo ( Variant : : INT , " tab " ) ) ) ;
2021-10-01 01:18:23 +02:00
ADD_SIGNAL ( MethodInfo ( " active_tab_rearranged " , PropertyInfo ( Variant : : INT , " idx_to " ) ) ) ;
2014-02-10 02:10:30 +01:00
2023-10-24 18:00:54 +02:00
// "current_tab" property must come after "tab_count", otherwise the property isn't loaded correctly.
ADD_ARRAY_COUNT ( " Tabs " , " tab_count " , " set_tab_count " , " get_tab_count " , " tab_ " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " current_tab " , PROPERTY_HINT_RANGE , " -1,4096,1 " ) , " set_current_tab " , " get_current_tab " ) ;
2021-11-25 03:58:47 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " tab_alignment " , PROPERTY_HINT_ENUM , " Left,Center,Right " ) , " set_tab_alignment " , " get_tab_alignment " ) ;
2021-03-30 12:20:00 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " clip_tabs " ) , " set_clip_tabs " , " get_clip_tabs " ) ;
2018-11-08 15:30:02 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " tab_close_display_policy " , PROPERTY_HINT_ENUM , " Show Never,Show Active Only,Show Always " ) , " set_tab_close_display_policy " , " get_tab_close_display_policy " ) ;
2022-05-20 07:24:41 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " max_tab_width " , PROPERTY_HINT_RANGE , " 0,99999,1,suffix:px " ) , " set_max_tab_width " , " get_max_tab_width " ) ;
2017-11-16 23:57:57 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " scrolling_enabled " ) , " set_scrolling_enabled " , " get_scrolling_enabled " ) ;
2018-02-07 14:01:45 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " drag_to_rearrange_enabled " ) , " set_drag_to_rearrange_enabled " , " get_drag_to_rearrange_enabled " ) ;
2022-03-19 17:15:51 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " tabs_rearrange_group " ) , " set_tabs_rearrange_group " , " get_tabs_rearrange_group " ) ;
2022-01-19 17:11:44 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " scroll_to_selected " ) , " set_scroll_to_selected " , " get_scroll_to_selected " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " select_with_rmb " ) , " set_select_with_rmb " , " get_select_with_rmb " ) ;
2024-01-15 00:39:47 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " deselect_enabled " ) , " set_deselect_enabled " , " get_deselect_enabled " ) ;
2015-08-18 20:27:01 +02:00
2021-11-25 03:58:47 +01:00
BIND_ENUM_CONSTANT ( ALIGNMENT_LEFT ) ;
BIND_ENUM_CONSTANT ( ALIGNMENT_CENTER ) ;
BIND_ENUM_CONSTANT ( ALIGNMENT_RIGHT ) ;
BIND_ENUM_CONSTANT ( ALIGNMENT_MAX ) ;
2017-08-20 17:45:01 +02:00
2017-10-21 20:58:02 +02:00
BIND_ENUM_CONSTANT ( CLOSE_BUTTON_SHOW_NEVER ) ;
2017-08-20 17:45:01 +02:00
BIND_ENUM_CONSTANT ( CLOSE_BUTTON_SHOW_ACTIVE_ONLY ) ;
BIND_ENUM_CONSTANT ( CLOSE_BUTTON_SHOW_ALWAYS ) ;
BIND_ENUM_CONSTANT ( CLOSE_BUTTON_MAX ) ;
2023-09-08 21:00:10 +02:00
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , TabBar , h_separation ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , TabBar , icon_max_width ) ;
BIND_THEME_ITEM_CUSTOM ( Theme : : DATA_TYPE_STYLEBOX , TabBar , tab_unselected_style , " tab_unselected " ) ;
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 " ) ;
2023-06-25 17:56:52 +02:00
BIND_THEME_ITEM_CUSTOM ( Theme : : DATA_TYPE_STYLEBOX , TabBar , tab_focus_style , " tab_focus " ) ;
2023-09-08 21:00:10 +02:00
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 " ) ;
BIND_THEME_ITEM_CUSTOM ( Theme : : DATA_TYPE_ICON , TabBar , decrement_icon , " decrement " ) ;
BIND_THEME_ITEM_CUSTOM ( Theme : : DATA_TYPE_ICON , TabBar , decrement_hl_icon , " decrement_highlight " ) ;
BIND_THEME_ITEM_CUSTOM ( Theme : : DATA_TYPE_ICON , TabBar , drop_mark_icon , " drop_mark " ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , TabBar , drop_mark_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , TabBar , font_selected_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , TabBar , font_hovered_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , TabBar , font_unselected_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , TabBar , font_disabled_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , TabBar , font_outline_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_FONT , TabBar , font ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_FONT_SIZE , TabBar , font_size ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , TabBar , outline_size ) ;
BIND_THEME_ITEM_CUSTOM ( Theme : : DATA_TYPE_ICON , TabBar , close_icon , " close " ) ;
BIND_THEME_ITEM_CUSTOM ( Theme : : DATA_TYPE_STYLEBOX , TabBar , button_pressed_style , " button_pressed " ) ;
BIND_THEME_ITEM_CUSTOM ( Theme : : DATA_TYPE_STYLEBOX , TabBar , button_hl_style , " button_highlight " ) ;
2014-02-10 02:10:30 +01:00
}
2021-10-17 18:55:44 +02:00
TabBar : : TabBar ( ) {
2022-01-19 17:11:44 +01:00
set_size ( Size2 ( get_size ( ) . width , get_minimum_size ( ) . height ) ) ;
2023-06-25 17:56:52 +02:00
set_focus_mode ( FOCUS_ALL ) ;
2021-10-17 18:55:44 +02:00
connect ( " mouse_exited " , callable_mp ( this , & TabBar : : _on_mouse_exited ) ) ;
2014-02-10 02:10:30 +01:00
}