2014-02-10 02:10:30 +01:00
/**************************************************************************/
/* tree.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
2014-02-10 02:10:30 +01:00
# include "tree.h"
2017-08-27 21:07:15 +02:00
2020-11-07 23:33:38 +01:00
# include "core/config/project_settings.h"
2020-04-28 15:19:37 +02:00
# include "core/input/input.h"
2018-09-11 18:13:45 +02:00
# include "core/math/math_funcs.h"
# include "core/os/keyboard.h"
# include "core/os/os.h"
2022-02-15 18:06:48 +01:00
# include "scene/gui/box_container.h"
2023-04-25 17:43:26 +02:00
# include "scene/gui/text_edit.h"
2020-03-04 02:51:12 +01:00
# include "scene/main/window.h"
2023-09-08 21:00:10 +02:00
# include "scene/theme/theme_db.h"
2014-02-10 02:10:30 +01:00
2019-04-05 14:06:16 +02:00
# include <limits.h>
2014-02-10 02:10:30 +01:00
Size2 TreeItem : : Cell : : get_icon_size ( ) const {
2020-05-14 16:41:43 +02:00
if ( icon . is_null ( ) ) {
2014-02-10 02:10:30 +01:00
return Size2 ( ) ;
2020-05-14 16:41:43 +02:00
}
if ( icon_region = = Rect2i ( ) ) {
2014-02-10 02:10:30 +01:00
return icon - > get_size ( ) ;
2020-05-14 16:41:43 +02:00
} else {
2014-02-10 02:10:30 +01:00
return icon_region . size ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2015-08-29 06:43:21 +02:00
2017-07-19 22:00:46 +02:00
void TreeItem : : Cell : : draw_icon ( const RID & p_where , const Point2 & p_pos , const Size2 & p_size , const Color & p_color ) const {
2020-05-14 16:41:43 +02:00
if ( icon . is_null ( ) ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
Size2i dsize = ( p_size = = Size2 ( ) ) ? icon - > get_size ( ) : p_size ;
if ( icon_region = = Rect2i ( ) ) {
2017-07-19 22:00:46 +02:00
icon - > draw_rect_region ( p_where , Rect2 ( p_pos , dsize ) , Rect2 ( Point2 ( ) , icon - > get_size ( ) ) , p_color ) ;
2014-02-10 02:10:30 +01:00
} else {
2017-07-19 22:00:46 +02:00
icon - > draw_rect_region ( p_where , Rect2 ( p_pos , dsize ) , icon_region , p_color ) ;
2014-02-10 02:10:30 +01:00
}
}
void TreeItem : : _changed_notify ( int p_cell ) {
2023-12-11 12:31:49 +01:00
if ( tree ) {
tree - > item_changed ( p_cell , this ) ;
}
2014-02-10 02:10:30 +01:00
}
void TreeItem : : _changed_notify ( ) {
2023-12-11 12:31:49 +01:00
if ( tree ) {
tree - > item_changed ( - 1 , this ) ;
}
2014-02-10 02:10:30 +01:00
}
void TreeItem : : _cell_selected ( int p_cell ) {
2023-12-11 12:31:49 +01:00
if ( tree ) {
tree - > item_selected ( p_cell , this ) ;
}
2014-02-10 02:10:30 +01:00
}
void TreeItem : : _cell_deselected ( int p_cell ) {
2023-12-11 12:31:49 +01:00
if ( tree ) {
tree - > item_deselected ( p_cell , this ) ;
}
2014-02-10 02:10:30 +01:00
}
2021-03-07 21:07:30 +01:00
void TreeItem : : _change_tree ( Tree * p_tree ) {
if ( p_tree = = tree ) {
return ;
}
TreeItem * c = first_child ;
while ( c ) {
c - > _change_tree ( p_tree ) ;
c = c - > next ;
}
2021-07-03 22:36:22 +02:00
if ( tree ) {
if ( tree - > root = = this ) {
tree - > root = nullptr ;
}
2021-03-07 21:07:30 +01:00
2021-07-03 22:36:22 +02:00
if ( tree - > popup_edited_item = = this ) {
tree - > popup_edited_item = nullptr ;
2022-04-07 13:49:28 +02:00
tree - > popup_pressing_edited_item = nullptr ;
2021-07-03 22:36:22 +02:00
tree - > pressing_for_editor = false ;
}
2021-03-07 21:07:30 +01:00
2021-07-03 22:36:22 +02:00
if ( tree - > cache . hover_item = = this ) {
tree - > cache . hover_item = nullptr ;
}
2021-03-07 21:07:30 +01:00
2021-07-03 22:36:22 +02:00
if ( tree - > selected_item = = this ) {
2024-02-27 16:34:15 +01:00
for ( int i = 0 ; i < tree - > selected_item - > cells . size ( ) ; i + + ) {
tree - > selected_item - > cells . write [ i ] . selected = false ;
}
2021-07-03 22:36:22 +02:00
tree - > selected_item = nullptr ;
}
2021-03-07 21:07:30 +01:00
2021-07-03 22:36:22 +02:00
if ( tree - > drop_mode_over = = this ) {
tree - > drop_mode_over = nullptr ;
}
2021-03-07 21:07:30 +01:00
2021-07-03 22:36:22 +02:00
if ( tree - > single_select_defer = = this ) {
tree - > single_select_defer = nullptr ;
}
if ( tree - > edited_item = = this ) {
tree - > edited_item = nullptr ;
tree - > pressing_for_editor = false ;
}
2021-03-07 21:07:30 +01:00
2022-08-13 23:21:24 +02:00
tree - > queue_redraw ( ) ;
2021-03-07 21:07:30 +01:00
}
tree = p_tree ;
if ( tree ) {
2022-08-13 23:21:24 +02:00
tree - > queue_redraw ( ) ;
2021-03-07 21:07:30 +01:00
cells . resize ( tree - > columns . size ( ) ) ;
}
}
2014-02-10 02:10:30 +01:00
/* cell mode */
void TreeItem : : set_cell_mode ( int p_column , TreeCellMode p_mode ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2021-09-24 10:11:44 +02:00
2022-03-16 08:50:48 +01:00
if ( cells [ p_column ] . mode = = p_mode ) {
return ;
}
2018-07-25 03:11:03 +02:00
Cell & c = cells . write [ p_column ] ;
2014-02-10 02:10:30 +01:00
c . mode = p_mode ;
c . min = 0 ;
c . max = 100 ;
c . step = 1 ;
c . val = 0 ;
c . checked = false ;
2019-06-11 20:43:37 +02:00
c . icon = Ref < Texture2D > ( ) ;
2015-08-31 00:37:23 +02:00
c . text = " " ;
2020-09-03 13:22:16 +02:00
c . dirty = true ;
2014-02-10 02:10:30 +01:00
c . icon_max_w = 0 ;
2021-09-24 10:11:44 +02:00
c . cached_minimum_size_dirty = true ;
2014-02-10 02:10:30 +01:00
_changed_notify ( p_column ) ;
}
TreeItem : : TreeCellMode TreeItem : : get_cell_mode ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , TreeItem : : CELL_MODE_STRING ) ;
return cells [ p_column ] . mode ;
}
2023-04-25 17:43:26 +02:00
/* multiline editable */
void TreeItem : : set_edit_multiline ( int p_column , bool p_multiline ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
cells . write [ p_column ] . edit_multiline = p_multiline ;
_changed_notify ( p_column ) ;
}
bool TreeItem : : is_edit_multiline ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , false ) ;
return cells [ p_column ] . edit_multiline ;
}
2014-02-10 02:10:30 +01:00
/* check mode */
void TreeItem : : set_checked ( int p_column , bool p_checked ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2021-09-24 10:11:44 +02:00
2022-03-16 08:50:48 +01:00
if ( cells [ p_column ] . checked = = p_checked ) {
return ;
}
2018-07-25 03:11:03 +02:00
cells . write [ p_column ] . checked = p_checked ;
2021-07-22 22:34:54 +02:00
cells . write [ p_column ] . indeterminate = false ;
2021-09-24 10:11:44 +02:00
cells . write [ p_column ] . cached_minimum_size_dirty = true ;
2021-07-22 22:34:54 +02:00
_changed_notify ( p_column ) ;
}
void TreeItem : : set_indeterminate ( int p_column , bool p_indeterminate ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2021-09-24 10:11:44 +02:00
2021-07-22 22:34:54 +02:00
// Prevent uncheck if indeterminate set to false twice
if ( p_indeterminate = = cells [ p_column ] . indeterminate ) {
return ;
}
2021-09-24 10:11:44 +02:00
2021-07-22 22:34:54 +02:00
cells . write [ p_column ] . indeterminate = p_indeterminate ;
cells . write [ p_column ] . checked = false ;
2021-09-24 10:11:44 +02:00
cells . write [ p_column ] . cached_minimum_size_dirty = true ;
2014-02-10 02:10:30 +01:00
_changed_notify ( p_column ) ;
}
bool TreeItem : : is_checked ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , false ) ;
return cells [ p_column ] . checked ;
}
2021-07-22 22:34:54 +02:00
bool TreeItem : : is_indeterminate ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , false ) ;
return cells [ p_column ] . indeterminate ;
}
2021-09-17 17:50:24 +02:00
void TreeItem : : propagate_check ( int p_column , bool p_emit_signal ) {
bool ch = cells [ p_column ] . checked ;
if ( p_emit_signal ) {
2022-02-06 15:53:53 +01:00
tree - > emit_signal ( SNAME ( " check_propagated_to_item " ) , this , p_column ) ;
2021-09-17 17:50:24 +02:00
}
_propagate_check_through_children ( p_column , ch , p_emit_signal ) ;
_propagate_check_through_parents ( p_column , p_emit_signal ) ;
}
void TreeItem : : _propagate_check_through_children ( int p_column , bool p_checked , bool p_emit_signal ) {
TreeItem * current = get_first_child ( ) ;
while ( current ) {
current - > set_checked ( p_column , p_checked ) ;
if ( p_emit_signal ) {
2022-02-06 15:53:53 +01:00
current - > tree - > emit_signal ( SNAME ( " check_propagated_to_item " ) , current , p_column ) ;
2021-09-17 17:50:24 +02:00
}
current - > _propagate_check_through_children ( p_column , p_checked , p_emit_signal ) ;
current = current - > get_next ( ) ;
}
}
void TreeItem : : _propagate_check_through_parents ( int p_column , bool p_emit_signal ) {
TreeItem * current = get_parent ( ) ;
if ( ! current ) {
return ;
}
2023-07-27 09:24:40 +02:00
bool any_checked = false ;
bool any_unchecked = false ;
bool any_indeterminate = false ;
2021-09-17 17:50:24 +02:00
TreeItem * child_item = current - > get_first_child ( ) ;
while ( child_item ) {
if ( ! child_item - > is_checked ( p_column ) ) {
2023-07-27 09:24:40 +02:00
any_unchecked = true ;
2021-09-17 17:50:24 +02:00
if ( child_item - > is_indeterminate ( p_column ) ) {
2023-07-27 09:24:40 +02:00
any_indeterminate = true ;
2021-09-17 17:50:24 +02:00
break ;
}
} else {
2023-07-27 09:24:40 +02:00
any_checked = true ;
2021-09-17 17:50:24 +02:00
}
child_item = child_item - > get_next ( ) ;
}
2023-07-27 09:24:40 +02:00
if ( any_indeterminate | | ( any_checked & & any_unchecked ) ) {
2021-09-17 17:50:24 +02:00
current - > set_indeterminate ( p_column , true ) ;
2023-07-27 09:24:40 +02:00
} else if ( current - > is_indeterminate ( p_column ) & & ! any_checked ) {
current - > set_indeterminate ( p_column , false ) ;
2021-09-17 17:50:24 +02:00
} else {
2023-07-27 09:24:40 +02:00
current - > set_checked ( p_column , any_checked ) ;
2021-09-17 17:50:24 +02:00
}
if ( p_emit_signal ) {
2022-02-06 15:53:53 +01:00
current - > tree - > emit_signal ( SNAME ( " check_propagated_to_item " ) , current , p_column ) ;
2021-09-17 17:50:24 +02:00
}
current - > _propagate_check_through_parents ( p_column , p_emit_signal ) ;
}
2014-02-10 02:10:30 +01:00
void TreeItem : : set_text ( int p_column , String p_text ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2022-03-16 08:50:48 +01:00
if ( cells [ p_column ] . text = = p_text ) {
return ;
}
2018-07-25 03:11:03 +02:00
cells . write [ p_column ] . text = p_text ;
2020-09-03 13:22:16 +02:00
cells . write [ p_column ] . dirty = true ;
2014-02-10 02:10:30 +01:00
2018-09-22 22:31:56 +02:00
if ( cells [ p_column ] . mode = = TreeItem : : CELL_MODE_RANGE ) {
2017-11-15 19:50:37 +01:00
Vector < String > strings = p_text . split ( " , " ) ;
2018-07-25 03:11:03 +02:00
cells . write [ p_column ] . min = INT_MAX ;
cells . write [ p_column ] . max = INT_MIN ;
2017-11-15 19:50:37 +01:00
for ( int i = 0 ; i < strings . size ( ) ; i + + ) {
int value = i ;
2020-12-15 13:04:21 +01:00
if ( ! strings [ i ] . get_slicec ( ' : ' , 1 ) . is_empty ( ) ) {
2017-11-15 19:50:37 +01:00
value = strings [ i ] . get_slicec ( ' : ' , 1 ) . to_int ( ) ;
}
2018-07-25 03:11:03 +02:00
cells . write [ p_column ] . min = MIN ( cells [ p_column ] . min , value ) ;
cells . write [ p_column ] . max = MAX ( cells [ p_column ] . max , value ) ;
2017-11-15 19:50:37 +01:00
}
2018-07-25 03:11:03 +02:00
cells . write [ p_column ] . step = 0 ;
2024-03-01 05:27:36 +01:00
} else {
// Don't auto translate if it's in string mode and editable, as the text can be changed to anything by the user.
if ( tree & & ( ! cells [ p_column ] . editable | | cells [ p_column ] . mode ! = TreeItem : : CELL_MODE_STRING ) ) {
cells . write [ p_column ] . xl_text = tree - > atr ( p_text ) ;
} else {
cells . write [ p_column ] . xl_text = p_text ;
}
2014-02-10 02:10:30 +01:00
}
2021-09-24 10:11:44 +02:00
cells . write [ p_column ] . cached_minimum_size_dirty = true ;
2014-02-10 02:10:30 +01:00
_changed_notify ( p_column ) ;
}
String TreeItem : : get_text ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , " " ) ;
return cells [ p_column ] . text ;
}
2020-09-03 13:22:16 +02:00
void TreeItem : : set_text_direction ( int p_column , Control : : TextDirection p_text_direction ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
ERR_FAIL_COND ( ( int ) p_text_direction < - 1 | | ( int ) p_text_direction > 3 ) ;
2022-03-16 08:50:48 +01:00
if ( cells [ p_column ] . text_direction = = p_text_direction ) {
return ;
2020-09-03 13:22:16 +02:00
}
2022-03-16 08:50:48 +01:00
cells . write [ p_column ] . text_direction = p_text_direction ;
cells . write [ p_column ] . dirty = true ;
_changed_notify ( p_column ) ;
2021-09-24 10:11:44 +02:00
cells . write [ p_column ] . cached_minimum_size_dirty = true ;
2020-09-03 13:22:16 +02:00
}
Control : : TextDirection TreeItem : : get_text_direction ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , Control : : TEXT_DIRECTION_INHERITED ) ;
return cells [ p_column ] . text_direction ;
}
2023-06-03 14:17:35 +02:00
void TreeItem : : set_autowrap_mode ( int p_column , TextServer : : AutowrapMode p_mode ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
ERR_FAIL_COND ( p_mode < TextServer : : AUTOWRAP_OFF | | p_mode > TextServer : : AUTOWRAP_WORD_SMART ) ;
if ( cells [ p_column ] . autowrap_mode = = p_mode ) {
return ;
}
cells . write [ p_column ] . autowrap_mode = p_mode ;
cells . write [ p_column ] . dirty = true ;
_changed_notify ( p_column ) ;
cells . write [ p_column ] . cached_minimum_size_dirty = true ;
}
TextServer : : AutowrapMode TreeItem : : get_autowrap_mode ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , TextServer : : AUTOWRAP_OFF ) ;
return cells [ p_column ] . autowrap_mode ;
}
2023-06-27 17:22:10 +02:00
void TreeItem : : set_text_overrun_behavior ( int p_column , TextServer : : OverrunBehavior p_behavior ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
if ( cells [ p_column ] . text_buf - > get_text_overrun_behavior ( ) = = p_behavior ) {
return ;
}
cells . write [ p_column ] . text_buf - > set_text_overrun_behavior ( p_behavior ) ;
cells . write [ p_column ] . dirty = true ;
cells . write [ p_column ] . cached_minimum_size_dirty = true ;
2024-04-24 03:58:12 +02:00
_changed_notify ( p_column ) ;
2023-06-27 17:22:10 +02:00
}
TextServer : : OverrunBehavior TreeItem : : get_text_overrun_behavior ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , TextServer : : OVERRUN_TRIM_ELLIPSIS ) ;
return cells [ p_column ] . text_buf - > get_text_overrun_behavior ( ) ;
}
2022-04-19 12:27:18 +02:00
void TreeItem : : set_structured_text_bidi_override ( int p_column , TextServer : : StructuredTextParser p_parser ) {
2020-09-03 13:22:16 +02:00
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2021-09-24 10:11:44 +02:00
2020-09-03 13:22:16 +02:00
if ( cells [ p_column ] . st_parser ! = p_parser ) {
cells . write [ p_column ] . st_parser = p_parser ;
cells . write [ p_column ] . dirty = true ;
2021-09-24 10:11:44 +02:00
cells . write [ p_column ] . cached_minimum_size_dirty = true ;
2020-09-03 13:22:16 +02:00
_changed_notify ( p_column ) ;
}
}
2022-04-19 12:27:18 +02:00
TextServer : : StructuredTextParser TreeItem : : get_structured_text_bidi_override ( int p_column ) const {
2023-01-18 08:33:35 +01:00
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , TextServer : : STRUCTURED_TEXT_DEFAULT ) ;
2020-09-03 13:22:16 +02:00
return cells [ p_column ] . st_parser ;
}
void TreeItem : : set_structured_text_bidi_override_options ( int p_column , Array p_args ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2021-09-24 10:11:44 +02:00
2022-03-16 08:50:48 +01:00
if ( cells [ p_column ] . st_args = = p_args ) {
return ;
}
2020-09-03 13:22:16 +02:00
cells . write [ p_column ] . st_args = p_args ;
cells . write [ p_column ] . dirty = true ;
2021-09-24 10:11:44 +02:00
cells . write [ p_column ] . cached_minimum_size_dirty = true ;
2020-09-03 13:22:16 +02:00
_changed_notify ( p_column ) ;
}
Array TreeItem : : get_structured_text_bidi_override_options ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , Array ( ) ) ;
return cells [ p_column ] . st_args ;
}
void TreeItem : : set_language ( int p_column , const String & p_language ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2021-09-24 10:11:44 +02:00
2020-09-03 13:22:16 +02:00
if ( cells [ p_column ] . language ! = p_language ) {
cells . write [ p_column ] . language = p_language ;
cells . write [ p_column ] . dirty = true ;
2021-09-24 10:11:44 +02:00
cells . write [ p_column ] . cached_minimum_size_dirty = true ;
2020-09-03 13:22:16 +02:00
_changed_notify ( p_column ) ;
}
}
String TreeItem : : get_language ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , " " ) ;
return cells [ p_column ] . language ;
}
2016-08-31 04:44:14 +02:00
void TreeItem : : set_suffix ( int p_column , String p_suffix ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2021-09-24 10:11:44 +02:00
2022-03-16 08:50:48 +01:00
if ( cells [ p_column ] . suffix = = p_suffix ) {
return ;
}
2018-07-25 03:11:03 +02:00
cells . write [ p_column ] . suffix = p_suffix ;
2021-09-24 10:11:44 +02:00
cells . write [ p_column ] . cached_minimum_size_dirty = true ;
2016-08-31 04:44:14 +02:00
_changed_notify ( p_column ) ;
}
String TreeItem : : get_suffix ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , " " ) ;
return cells [ p_column ] . suffix ;
}
2014-02-10 02:10:30 +01:00
2019-06-11 20:43:37 +02:00
void TreeItem : : set_icon ( int p_column , const Ref < Texture2D > & p_icon ) {
2014-02-10 02:10:30 +01:00
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2021-09-24 10:11:44 +02:00
2022-03-16 08:50:48 +01:00
if ( cells [ p_column ] . icon = = p_icon ) {
return ;
}
2018-07-25 03:11:03 +02:00
cells . write [ p_column ] . icon = p_icon ;
2021-09-24 10:11:44 +02:00
cells . write [ p_column ] . cached_minimum_size_dirty = true ;
2014-02-10 02:10:30 +01:00
_changed_notify ( p_column ) ;
}
2019-06-11 20:43:37 +02:00
Ref < Texture2D > TreeItem : : get_icon ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , Ref < Texture2D > ( ) ) ;
2014-02-10 02:10:30 +01:00
return cells [ p_column ] . icon ;
}
void TreeItem : : set_icon_region ( int p_column , const Rect2 & p_icon_region ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2021-09-24 10:11:44 +02:00
2022-03-16 08:50:48 +01:00
if ( cells [ p_column ] . icon_region = = p_icon_region ) {
return ;
}
2018-07-25 03:11:03 +02:00
cells . write [ p_column ] . icon_region = p_icon_region ;
2021-09-24 10:11:44 +02:00
cells . write [ p_column ] . cached_minimum_size_dirty = true ;
2014-02-10 02:10:30 +01:00
_changed_notify ( p_column ) ;
}
Rect2 TreeItem : : get_icon_region ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , Rect2 ( ) ) ;
return cells [ p_column ] . icon_region ;
}
2019-08-24 17:13:48 +02:00
void TreeItem : : set_icon_modulate ( int p_column , const Color & p_modulate ) {
2017-07-19 22:00:46 +02:00
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2022-03-16 08:50:48 +01:00
if ( cells [ p_column ] . icon_color = = p_modulate ) {
return ;
}
2019-08-24 17:13:48 +02:00
cells . write [ p_column ] . icon_color = p_modulate ;
2017-07-19 22:00:46 +02:00
_changed_notify ( p_column ) ;
}
2019-08-24 17:13:48 +02:00
Color TreeItem : : get_icon_modulate ( int p_column ) const {
2017-07-19 22:00:46 +02:00
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , Color ( ) ) ;
return cells [ p_column ] . icon_color ;
}
2014-02-10 02:10:30 +01:00
void TreeItem : : set_icon_max_width ( int p_column , int p_max ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2021-09-24 10:11:44 +02:00
2022-03-16 08:50:48 +01:00
if ( cells [ p_column ] . icon_max_w = = p_max ) {
return ;
}
2018-07-25 03:11:03 +02:00
cells . write [ p_column ] . icon_max_w = p_max ;
2021-09-24 10:11:44 +02:00
cells . write [ p_column ] . cached_minimum_size_dirty = true ;
2014-02-10 02:10:30 +01:00
_changed_notify ( p_column ) ;
}
int TreeItem : : get_icon_max_width ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , 0 ) ;
return cells [ p_column ] . icon_max_w ;
}
/* range works for mode number or mode combo */
void TreeItem : : set_range ( int p_column , double p_value ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2020-05-14 16:41:43 +02:00
if ( cells [ p_column ] . step > 0 ) {
2020-12-21 19:02:57 +01:00
p_value = Math : : snapped ( p_value , cells [ p_column ] . step ) ;
2020-05-14 16:41:43 +02:00
}
if ( p_value < cells [ p_column ] . min ) {
2014-02-10 02:10:30 +01:00
p_value = cells [ p_column ] . min ;
2020-05-14 16:41:43 +02:00
}
if ( p_value > cells [ p_column ] . max ) {
2014-02-10 02:10:30 +01:00
p_value = cells [ p_column ] . max ;
2020-05-14 16:41:43 +02:00
}
2015-08-31 00:37:23 +02:00
2022-03-16 08:50:48 +01:00
if ( cells [ p_column ] . val = = p_value ) {
return ;
}
2018-07-25 03:11:03 +02:00
cells . write [ p_column ] . val = p_value ;
2020-09-03 13:22:16 +02:00
cells . write [ p_column ] . dirty = true ;
2014-02-10 02:10:30 +01:00
_changed_notify ( p_column ) ;
}
double TreeItem : : get_range ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , 0 ) ;
return cells [ p_column ] . val ;
}
bool TreeItem : : is_range_exponential ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , false ) ;
return cells [ p_column ] . expr ;
}
2020-05-14 14:29:06 +02:00
2014-02-10 02:10:30 +01:00
void TreeItem : : set_range_config ( int p_column , double p_min , double p_max , double p_step , bool p_exp ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2022-03-16 08:50:48 +01:00
if ( cells [ p_column ] . min = = p_min & & cells [ p_column ] . max = = p_max & & cells [ p_column ] . step = = p_step & & cells [ p_column ] . expr = = p_exp ) {
return ;
}
2018-07-25 03:11:03 +02:00
cells . write [ p_column ] . min = p_min ;
cells . write [ p_column ] . max = p_max ;
cells . write [ p_column ] . step = p_step ;
cells . write [ p_column ] . expr = p_exp ;
2014-02-10 02:10:30 +01:00
_changed_notify ( p_column ) ;
}
void TreeItem : : get_range_config ( int p_column , double & r_min , double & r_max , double & r_step ) const {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
r_min = cells [ p_column ] . min ;
r_max = cells [ p_column ] . max ;
r_step = cells [ p_column ] . step ;
}
void TreeItem : : set_metadata ( int p_column , const Variant & p_meta ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2018-07-25 03:11:03 +02:00
cells . write [ p_column ] . meta = p_meta ;
2014-02-10 02:10:30 +01:00
}
Variant TreeItem : : get_metadata ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , Variant ( ) ) ;
return cells [ p_column ] . meta ;
}
2024-01-20 17:55:34 +01:00
# ifndef DISABLE_DEPRECATED
2014-02-10 02:10:30 +01:00
void TreeItem : : set_custom_draw ( int p_column , Object * p_object , const StringName & p_callback ) {
2024-01-20 17:55:34 +01:00
WARN_DEPRECATED_MSG ( R " *(The " set_custom_draw ( ) " method is deprecated, use " set_custom_draw_callback ( ) " instead.)* " ) ;
2014-02-10 02:10:30 +01:00
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
ERR_FAIL_NULL ( p_object ) ;
2024-01-20 17:55:34 +01:00
cells . write [ p_column ] . custom_draw_callback = Callable ( p_object , p_callback ) ;
_changed_notify ( p_column ) ;
}
# endif // DISABLE_DEPRECATED
void TreeItem : : set_custom_draw_callback ( int p_column , const Callable & p_callback ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2018-07-25 03:11:03 +02:00
cells . write [ p_column ] . custom_draw_callback = p_callback ;
2024-01-20 16:42:28 +01:00
_changed_notify ( p_column ) ;
2014-02-10 02:10:30 +01:00
}
2024-01-20 17:55:34 +01:00
Callable TreeItem : : get_custom_draw_callback ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , Callable ( ) ) ;
return cells [ p_column ] . custom_draw_callback ;
}
2014-02-10 02:10:30 +01:00
void TreeItem : : set_collapsed ( bool p_collapsed ) {
2020-05-14 16:41:43 +02:00
if ( collapsed = = p_collapsed | | ! tree ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
collapsed = p_collapsed ;
TreeItem * ci = tree - > selected_item ;
if ( ci ) {
while ( ci & & ci ! = this ) {
ci = ci - > parent ;
}
Fix misc. source comment typos
Found using `codespell -q 3 -S ./thirdparty,*.po -L ang,ba,cas,dof,doubleclick,fave,hist,leapyear,lod,nd,numer,ois,paket,seeked,sinc,switchs,te,uint -D ~/Projects/codespell/codespell_lib/data/dictionary.txt `
2019-09-19 20:36:39 +02:00
if ( ci ) { // collapsing cursor/selected, move it!
2014-02-10 02:10:30 +01:00
if ( tree - > select_mode = = Tree : : SELECT_MULTI ) {
2015-08-31 00:37:23 +02:00
tree - > selected_item = this ;
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " cell_selected " ) ) ;
2014-02-10 02:10:30 +01:00
} else {
select ( tree - > selected_col ) ;
}
2022-08-13 23:21:24 +02:00
tree - > queue_redraw ( ) ;
2014-02-10 02:10:30 +01:00
}
}
_changed_notify ( ) ;
2021-07-17 23:22:52 +02:00
tree - > emit_signal ( SNAME ( " item_collapsed " ) , this ) ;
2014-02-10 02:10:30 +01:00
}
bool TreeItem : : is_collapsed ( ) {
return collapsed ;
}
2022-07-01 15:43:39 +02:00
void TreeItem : : set_collapsed_recursive ( bool p_collapsed ) {
if ( ! tree ) {
return ;
}
set_collapsed ( p_collapsed ) ;
TreeItem * child = get_first_child ( ) ;
while ( child ) {
child - > set_collapsed_recursive ( p_collapsed ) ;
child = child - > get_next ( ) ;
}
}
bool TreeItem : : _is_any_collapsed ( bool p_only_visible ) {
TreeItem * child = get_first_child ( ) ;
// Check on children directly first (avoid recursing if possible).
while ( child ) {
if ( child - > get_first_child ( ) & & child - > is_collapsed ( ) & & ( ! p_only_visible | | ( child - > is_visible ( ) & & child - > get_visible_child_count ( ) ) ) ) {
return true ;
}
child = child - > get_next ( ) ;
}
child = get_first_child ( ) ;
// Otherwise recurse on children.
while ( child ) {
if ( child - > get_first_child ( ) & & ( ! p_only_visible | | ( child - > is_visible ( ) & & child - > get_visible_child_count ( ) ) ) & & child - > _is_any_collapsed ( p_only_visible ) ) {
return true ;
}
child = child - > get_next ( ) ;
}
return false ;
}
bool TreeItem : : is_any_collapsed ( bool p_only_visible ) {
2024-02-13 22:27:15 +01:00
if ( p_only_visible & & ! is_visible_in_tree ( ) ) {
2022-07-01 15:43:39 +02:00
return false ;
}
// Collapsed if this is collapsed and it has children (only considers visible if only visible is set).
if ( is_collapsed ( ) & & get_first_child ( ) & & ( ! p_only_visible | | get_visible_child_count ( ) ) ) {
return true ;
}
return _is_any_collapsed ( p_only_visible ) ;
}
2022-04-03 10:37:08 +02:00
void TreeItem : : set_visible ( bool p_visible ) {
if ( visible = = p_visible ) {
return ;
}
visible = p_visible ;
if ( tree ) {
2022-08-13 23:21:24 +02:00
tree - > queue_redraw ( ) ;
2022-04-03 10:37:08 +02:00
_changed_notify ( ) ;
}
2024-02-13 22:27:15 +01:00
_handle_visibility_changed ( p_visible ) ;
2022-04-03 10:37:08 +02:00
}
bool TreeItem : : is_visible ( ) {
return visible ;
}
2024-02-13 22:27:15 +01:00
bool TreeItem : : is_visible_in_tree ( ) const {
return visible & & parent_visible_in_tree ;
}
void TreeItem : : _handle_visibility_changed ( bool p_visible ) {
TreeItem * child = get_first_child ( ) ;
while ( child ) {
child - > _propagate_visibility_changed ( p_visible ) ;
child = child - > get_next ( ) ;
}
}
void TreeItem : : _propagate_visibility_changed ( bool p_parent_visible_in_tree ) {
parent_visible_in_tree = p_parent_visible_in_tree ;
_handle_visibility_changed ( p_parent_visible_in_tree ) ;
}
2021-03-19 13:57:52 +01:00
void TreeItem : : uncollapse_tree ( ) {
TreeItem * t = this ;
while ( t ) {
t - > set_collapsed ( false ) ;
t = t - > parent ;
}
}
2017-09-05 14:31:07 +02:00
void TreeItem : : set_custom_minimum_height ( int p_height ) {
2022-03-16 08:50:48 +01:00
if ( custom_min_height = = p_height ) {
return ;
}
2017-09-05 14:31:07 +02:00
custom_min_height = p_height ;
2021-09-24 10:11:44 +02:00
2022-01-27 17:34:33 +01:00
for ( Cell & c : cells ) {
2021-09-24 10:11:44 +02:00
c . cached_minimum_size_dirty = true ;
2022-01-27 17:34:33 +01:00
}
2021-09-24 10:11:44 +02:00
2017-09-05 14:31:07 +02:00
_changed_notify ( ) ;
}
int TreeItem : : get_custom_minimum_height ( ) const {
return custom_min_height ;
}
2021-03-07 21:07:30 +01:00
/* Item manipulation */
2022-12-22 08:05:04 +01:00
TreeItem * TreeItem : : create_child ( int p_index ) {
2021-03-07 21:07:30 +01:00
TreeItem * ti = memnew ( TreeItem ( tree ) ) ;
if ( tree ) {
ti - > cells . resize ( tree - > columns . size ( ) ) ;
2022-08-13 23:21:24 +02:00
tree - > queue_redraw ( ) ;
2021-03-07 21:07:30 +01:00
}
2023-05-31 11:31:43 +02:00
TreeItem * item_prev = nullptr ;
TreeItem * item_next = first_child ;
2021-03-07 21:07:30 +01:00
2024-07-25 19:57:32 +02:00
if ( p_index < 0 & & last_child ) {
item_prev = last_child ;
} else {
int idx = 0 ;
while ( item_next ) {
if ( idx = = p_index ) {
item_next - > prev = ti ;
ti - > next = item_next ;
break ;
}
2023-05-31 11:31:43 +02:00
2024-07-25 19:57:32 +02:00
item_prev = item_next ;
item_next = item_next - > next ;
idx + + ;
}
2021-03-07 21:07:30 +01:00
}
2023-05-31 11:31:43 +02:00
if ( item_prev ) {
item_prev - > next = ti ;
ti - > prev = item_prev ;
2021-03-07 21:07:30 +01:00
if ( ! children_cache . is_empty ( ) ) {
if ( ti - > next ) {
2022-12-22 08:05:04 +01:00
children_cache . insert ( p_index , ti ) ;
2021-03-07 21:07:30 +01:00
} else {
children_cache . append ( ti ) ;
}
}
} else {
first_child = ti ;
if ( ! children_cache . is_empty ( ) ) {
children_cache . insert ( 0 , ti ) ;
}
}
2024-07-25 19:57:32 +02:00
if ( item_prev = = last_child ) {
last_child = ti ;
}
2021-03-07 21:07:30 +01:00
ti - > parent = this ;
2024-02-13 22:27:15 +01:00
ti - > parent_visible_in_tree = is_visible_in_tree ( ) ;
2021-03-07 21:07:30 +01:00
return ti ;
}
2023-05-31 11:31:43 +02:00
void TreeItem : : add_child ( TreeItem * p_item ) {
ERR_FAIL_NULL ( p_item ) ;
ERR_FAIL_COND ( p_item - > tree ) ;
ERR_FAIL_COND ( p_item - > parent ) ;
p_item - > _change_tree ( tree ) ;
p_item - > parent = this ;
2024-02-13 22:27:15 +01:00
p_item - > parent_visible_in_tree = is_visible_in_tree ( ) ;
p_item - > _handle_visibility_changed ( p_item - > parent_visible_in_tree ) ;
2023-05-31 11:31:43 +02:00
2024-07-25 19:57:32 +02:00
if ( last_child ) {
last_child - > next = p_item ;
p_item - > prev = last_child ;
2023-05-31 11:31:43 +02:00
} else {
first_child = p_item ;
}
2024-07-25 19:57:32 +02:00
last_child = p_item ;
2023-05-31 11:31:43 +02:00
if ( ! children_cache . is_empty ( ) ) {
children_cache . append ( p_item ) ;
}
validate_cache ( ) ;
}
void TreeItem : : remove_child ( TreeItem * p_item ) {
ERR_FAIL_NULL ( p_item ) ;
ERR_FAIL_COND ( p_item - > parent ! = this ) ;
p_item - > _unlink_from_tree ( ) ;
p_item - > _change_tree ( nullptr ) ;
p_item - > prev = nullptr ;
p_item - > next = nullptr ;
p_item - > parent = nullptr ;
validate_cache ( ) ;
}
2021-06-28 15:40:56 +02:00
Tree * TreeItem : : get_tree ( ) const {
2021-03-07 21:07:30 +01:00
return tree ;
}
2021-06-28 15:40:56 +02:00
TreeItem * TreeItem : : get_next ( ) const {
2014-02-10 02:10:30 +01:00
return next ;
}
TreeItem * TreeItem : : get_prev ( ) {
2021-03-07 21:07:30 +01:00
if ( prev ) {
return prev ;
2020-05-14 16:41:43 +02:00
}
2015-08-31 00:37:23 +02:00
2021-03-07 21:07:30 +01:00
if ( ! parent | | parent - > first_child = = this ) {
return nullptr ;
}
// This is an edge case
TreeItem * l_prev = parent - > first_child ;
while ( l_prev & & l_prev - > next ! = this ) {
l_prev = l_prev - > next ;
2020-05-14 16:41:43 +02:00
}
2015-08-31 00:37:23 +02:00
2021-03-07 21:07:30 +01:00
prev = l_prev ;
2014-02-10 02:10:30 +01:00
return prev ;
}
2021-06-28 15:40:56 +02:00
TreeItem * TreeItem : : get_parent ( ) const {
2014-02-10 02:10:30 +01:00
return parent ;
}
2021-06-28 15:40:56 +02:00
TreeItem * TreeItem : : get_first_child ( ) const {
2021-03-07 21:07:30 +01:00
return first_child ;
2014-02-10 02:10:30 +01:00
}
2023-05-11 04:17:03 +02:00
TreeItem * TreeItem : : _get_prev_in_tree ( bool p_wrap , bool p_include_invisible ) {
2014-02-10 02:10:30 +01:00
TreeItem * current = this ;
2022-09-29 11:53:28 +02:00
TreeItem * prev_item = current - > get_prev ( ) ;
2014-02-10 02:10:30 +01:00
2022-09-29 11:53:28 +02:00
if ( ! prev_item ) {
2014-02-10 02:10:30 +01:00
current = current - > parent ;
2019-05-11 18:32:53 +02:00
if ( current = = tree - > root & & tree - > hide_root ) {
2020-04-02 01:20:12 +02:00
return nullptr ;
2019-05-11 18:32:53 +02:00
} else if ( ! current ) {
if ( p_wrap ) {
current = this ;
2024-01-28 21:51:39 +01:00
TreeItem * temp = get_next_visible ( ) ;
2019-05-11 18:32:53 +02:00
while ( temp ) {
current = temp ;
temp = temp - > get_next_visible ( ) ;
}
} else {
2020-04-02 01:20:12 +02:00
return nullptr ;
2019-05-11 18:32:53 +02:00
}
}
2014-02-10 02:10:30 +01:00
} else {
2022-09-29 11:53:28 +02:00
current = prev_item ;
2024-07-25 19:57:32 +02:00
while ( ( ! current - > collapsed | | p_include_invisible ) & & current - > last_child ) {
current = current - > last_child ;
2014-02-10 02:10:30 +01:00
}
}
return current ;
}
2022-04-03 10:37:08 +02:00
TreeItem * TreeItem : : get_prev_visible ( bool p_wrap ) {
TreeItem * loop = this ;
2024-01-28 21:51:39 +01:00
TreeItem * prev_item = _get_prev_in_tree ( p_wrap ) ;
2024-02-13 22:27:15 +01:00
while ( prev_item & & ! prev_item - > is_visible_in_tree ( ) ) {
2023-05-11 04:17:03 +02:00
prev_item = prev_item - > _get_prev_in_tree ( p_wrap ) ;
2022-09-29 11:53:28 +02:00
if ( prev_item = = loop ) {
2022-04-03 10:37:08 +02:00
// Check that we haven't looped all the way around to the start.
2022-09-29 11:53:28 +02:00
prev_item = nullptr ;
2022-04-03 10:37:08 +02:00
break ;
}
}
2022-09-29 11:53:28 +02:00
return prev_item ;
2022-04-03 10:37:08 +02:00
}
2023-05-11 04:17:03 +02:00
TreeItem * TreeItem : : _get_next_in_tree ( bool p_wrap , bool p_include_invisible ) {
2014-02-10 02:10:30 +01:00
TreeItem * current = this ;
2023-05-11 04:17:03 +02:00
if ( ( ! current - > collapsed | | p_include_invisible ) & & current - > first_child ) {
2021-03-07 21:07:30 +01:00
current = current - > first_child ;
2014-02-10 02:10:30 +01:00
} else if ( current - > next ) {
current = current - > next ;
} else {
while ( current & & ! current - > next ) {
current = current - > parent ;
}
2019-05-11 18:32:53 +02:00
if ( ! current ) {
2020-05-14 16:41:43 +02:00
if ( p_wrap ) {
2019-05-11 18:32:53 +02:00
return tree - > root ;
2020-05-14 16:41:43 +02:00
} else {
2020-04-02 01:20:12 +02:00
return nullptr ;
2020-05-14 16:41:43 +02:00
}
2019-05-11 18:32:53 +02:00
} else {
2014-02-10 02:10:30 +01:00
current = current - > next ;
2019-05-11 18:32:53 +02:00
}
2014-02-10 02:10:30 +01:00
}
return current ;
}
2022-04-03 10:37:08 +02:00
TreeItem * TreeItem : : get_next_visible ( bool p_wrap ) {
TreeItem * loop = this ;
2024-01-28 21:51:39 +01:00
TreeItem * next_item = _get_next_in_tree ( p_wrap ) ;
2024-02-13 22:27:15 +01:00
while ( next_item & & ! next_item - > is_visible_in_tree ( ) ) {
2023-05-11 04:17:03 +02:00
next_item = next_item - > _get_next_in_tree ( p_wrap ) ;
2022-09-29 11:53:28 +02:00
if ( next_item = = loop ) {
2022-04-03 10:37:08 +02:00
// Check that we haven't looped all the way around to the start.
2022-09-29 11:53:28 +02:00
next_item = nullptr ;
2022-04-03 10:37:08 +02:00
break ;
}
}
2022-09-29 11:53:28 +02:00
return next_item ;
2022-04-03 10:37:08 +02:00
}
2023-05-11 04:17:03 +02:00
TreeItem * TreeItem : : get_prev_in_tree ( bool p_wrap ) {
2024-01-28 21:51:39 +01:00
TreeItem * prev_item = _get_prev_in_tree ( p_wrap , true ) ;
2023-05-11 04:17:03 +02:00
return prev_item ;
}
TreeItem * TreeItem : : get_next_in_tree ( bool p_wrap ) {
2024-01-28 21:51:39 +01:00
TreeItem * next_item = _get_next_in_tree ( p_wrap , true ) ;
2023-05-11 04:17:03 +02:00
return next_item ;
}
2022-12-22 08:05:04 +01:00
TreeItem * TreeItem : : get_child ( int p_index ) {
2021-03-07 21:07:30 +01:00
_create_children_cache ( ) ;
2022-07-25 09:51:18 +02:00
2022-12-22 08:05:04 +01:00
if ( p_index < 0 ) {
p_index + = children_cache . size ( ) ;
2022-07-25 09:51:18 +02:00
}
2022-12-22 08:05:04 +01:00
ERR_FAIL_INDEX_V ( p_index , children_cache . size ( ) , nullptr ) ;
2022-07-25 09:51:18 +02:00
2022-12-22 08:05:04 +01:00
return children_cache . get ( p_index ) ;
2021-03-07 21:07:30 +01:00
}
2022-04-03 10:37:08 +02:00
int TreeItem : : get_visible_child_count ( ) {
_create_children_cache ( ) ;
int visible_count = 0 ;
for ( int i = 0 ; i < children_cache . size ( ) ; i + + ) {
if ( children_cache [ i ] - > is_visible ( ) ) {
visible_count + = 1 ;
}
}
return visible_count ;
}
2021-03-07 21:07:30 +01:00
int TreeItem : : get_child_count ( ) {
_create_children_cache ( ) ;
return children_cache . size ( ) ;
}
2022-08-08 00:52:20 +02:00
TypedArray < TreeItem > TreeItem : : get_children ( ) {
2022-08-04 00:08:16 +02:00
// Don't need to explicitly create children cache, because get_child_count creates it.
2021-03-07 21:07:30 +01:00
int size = get_child_count ( ) ;
2022-08-08 00:52:20 +02:00
TypedArray < TreeItem > arr ;
2021-03-07 21:07:30 +01:00
arr . resize ( size ) ;
for ( int i = 0 ; i < size ; i + + ) {
arr [ i ] = children_cache [ i ] ;
}
return arr ;
}
2023-05-31 11:31:43 +02:00
void TreeItem : : clear_children ( ) {
TreeItem * c = first_child ;
while ( c ) {
TreeItem * aux = c ;
c = c - > get_next ( ) ;
aux - > parent = nullptr ; // So it won't try to recursively auto-remove from me in here.
memdelete ( aux ) ;
}
first_child = nullptr ;
2024-07-25 19:57:32 +02:00
last_child = nullptr ;
children_cache . clear ( ) ;
2023-05-31 11:31:43 +02:00
} ;
2021-03-07 21:07:30 +01:00
int TreeItem : : get_index ( ) {
int idx = 0 ;
TreeItem * c = this ;
while ( c ) {
c = c - > get_prev ( ) ;
idx + + ;
}
return idx - 1 ;
}
2022-08-04 00:08:16 +02:00
# ifdef DEV_ENABLED
void TreeItem : : validate_cache ( ) const {
if ( ! parent | | parent - > children_cache . is_empty ( ) ) {
return ;
}
TreeItem * scan = parent - > first_child ;
int index = 0 ;
while ( scan ) {
DEV_ASSERT ( parent - > children_cache [ index ] = = scan ) ;
+ + index ;
scan = scan - > get_next ( ) ;
}
DEV_ASSERT ( index = = parent - > children_cache . size ( ) ) ;
}
# endif
2021-03-07 21:07:30 +01:00
void TreeItem : : move_before ( TreeItem * p_item ) {
2014-02-10 02:10:30 +01:00
ERR_FAIL_NULL ( p_item ) ;
2021-03-07 21:07:30 +01:00
ERR_FAIL_COND ( is_root ) ;
2023-06-06 14:59:54 +02:00
ERR_FAIL_NULL ( p_item - > parent ) ;
2014-02-10 02:10:30 +01:00
2021-03-07 21:07:30 +01:00
if ( p_item = = this ) {
return ;
}
2014-02-10 02:10:30 +01:00
2021-03-07 21:07:30 +01:00
TreeItem * p = p_item - > parent ;
while ( p ) {
ERR_FAIL_COND_MSG ( p = = this , " Can't move to a descendant " ) ;
p = p - > parent ;
}
2014-02-10 02:10:30 +01:00
2021-03-07 21:07:30 +01:00
Tree * old_tree = tree ;
_unlink_from_tree ( ) ;
_change_tree ( p_item - > tree ) ;
parent = p_item - > parent ;
TreeItem * item_prev = p_item - > get_prev ( ) ;
if ( item_prev ) {
item_prev - > next = this ;
parent - > children_cache . clear ( ) ;
} else {
parent - > first_child = this ;
2022-08-04 00:08:16 +02:00
// If the cache is empty, it has not been built but there
2023-05-31 11:31:43 +02:00
// are items in the tree (note p_item != nullptr) so we cannot update it.
2022-08-04 00:08:16 +02:00
if ( ! parent - > children_cache . is_empty ( ) ) {
parent - > children_cache . insert ( 0 , this ) ;
}
2021-03-07 21:07:30 +01:00
}
prev = item_prev ;
next = p_item ;
p_item - > prev = this ;
2021-07-03 22:36:22 +02:00
if ( tree & & old_tree = = tree ) {
2022-08-13 23:21:24 +02:00
tree - > queue_redraw ( ) ;
2021-03-07 21:07:30 +01:00
}
2022-08-04 00:08:16 +02:00
validate_cache ( ) ;
2021-03-07 21:07:30 +01:00
}
void TreeItem : : move_after ( TreeItem * p_item ) {
ERR_FAIL_NULL ( p_item ) ;
ERR_FAIL_COND ( is_root ) ;
2023-06-06 14:59:54 +02:00
ERR_FAIL_NULL ( p_item - > parent ) ;
2021-03-07 21:07:30 +01:00
if ( p_item = = this ) {
return ;
}
2014-02-10 02:10:30 +01:00
2021-03-07 21:07:30 +01:00
TreeItem * p = p_item - > parent ;
while ( p ) {
ERR_FAIL_COND_MSG ( p = = this , " Can't move to a descendant " ) ;
p = p - > parent ;
2014-02-10 02:10:30 +01:00
}
2021-03-07 21:07:30 +01:00
Tree * old_tree = tree ;
_unlink_from_tree ( ) ;
_change_tree ( p_item - > tree ) ;
if ( p_item - > next ) {
p_item - > next - > prev = this ;
}
parent = p_item - > parent ;
prev = p_item ;
next = p_item - > next ;
p_item - > next = this ;
if ( next ) {
parent - > children_cache . clear ( ) ;
} else {
2024-07-25 19:57:32 +02:00
parent - > last_child = this ;
2022-08-04 00:08:16 +02:00
// If the cache is empty, it has not been built but there
// are items in the tree (note p_item != nullptr,) so we cannot update it.
if ( ! parent - > children_cache . is_empty ( ) ) {
parent - > children_cache . append ( this ) ;
}
2021-03-07 21:07:30 +01:00
}
2021-07-03 22:36:22 +02:00
if ( tree & & old_tree = = tree ) {
2022-08-13 23:21:24 +02:00
tree - > queue_redraw ( ) ;
2021-03-07 21:07:30 +01:00
}
2022-08-04 00:08:16 +02:00
validate_cache ( ) ;
2021-03-07 21:07:30 +01:00
}
2014-02-10 02:10:30 +01:00
void TreeItem : : set_selectable ( int p_column , bool p_selectable ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2018-07-25 03:11:03 +02:00
cells . write [ p_column ] . selectable = p_selectable ;
2014-02-10 02:10:30 +01:00
}
bool TreeItem : : is_selectable ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , false ) ;
return cells [ p_column ] . selectable ;
}
bool TreeItem : : is_selected ( int p_column ) {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , false ) ;
return cells [ p_column ] . selectable & & cells [ p_column ] . selected ;
}
void TreeItem : : set_as_cursor ( int p_column ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! tree ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
if ( tree - > select_mode ! = Tree : : SELECT_MULTI ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2022-12-03 16:27:48 +01:00
if ( tree - > selected_item = = this & & tree - > selected_col = = p_column ) {
2022-03-16 08:50:48 +01:00
return ;
}
2014-02-10 02:10:30 +01:00
tree - > selected_item = this ;
tree - > selected_col = p_column ;
2022-08-13 23:21:24 +02:00
tree - > queue_redraw ( ) ;
2014-02-10 02:10:30 +01:00
}
void TreeItem : : select ( int p_column ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
_cell_selected ( p_column ) ;
}
void TreeItem : : deselect ( int p_column ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
_cell_deselected ( p_column ) ;
}
2019-06-11 20:43:37 +02:00
void TreeItem : : add_button ( int p_column , const Ref < Texture2D > & p_button , int p_id , bool p_disabled , const String & p_tooltip ) {
2014-02-10 02:10:30 +01:00
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
ERR_FAIL_COND ( ! p_button . is_valid ( ) ) ;
TreeItem : : Cell : : Button button ;
button . texture = p_button ;
2020-05-14 16:41:43 +02:00
if ( p_id < 0 ) {
2014-02-10 02:10:30 +01:00
p_id = cells [ p_column ] . buttons . size ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
button . id = p_id ;
2016-02-03 00:44:42 +01:00
button . disabled = p_disabled ;
2017-04-24 21:41:17 +02:00
button . tooltip = p_tooltip ;
2018-07-25 03:11:03 +02:00
cells . write [ p_column ] . buttons . push_back ( button ) ;
2021-09-24 10:11:44 +02:00
cells . write [ p_column ] . cached_minimum_size_dirty = true ;
2014-02-10 02:10:30 +01:00
_changed_notify ( p_column ) ;
}
int TreeItem : : get_button_count ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , - 1 ) ;
return cells [ p_column ] . buttons . size ( ) ;
}
2020-05-14 14:29:06 +02:00
2022-12-22 08:05:04 +01:00
Ref < Texture2D > TreeItem : : get_button ( int p_column , int p_index ) const {
2019-06-11 20:43:37 +02:00
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , Ref < Texture2D > ( ) ) ;
2022-12-22 08:05:04 +01:00
ERR_FAIL_INDEX_V ( p_index , cells [ p_column ] . buttons . size ( ) , Ref < Texture2D > ( ) ) ;
return cells [ p_column ] . buttons [ p_index ] . texture ;
2014-02-10 02:10:30 +01:00
}
2020-05-14 14:29:06 +02:00
2022-12-22 08:05:04 +01:00
String TreeItem : : get_button_tooltip_text ( int p_column , int p_index ) const {
2019-09-04 16:47:47 +02:00
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , String ( ) ) ;
2022-12-22 08:05:04 +01:00
ERR_FAIL_INDEX_V ( p_index , cells [ p_column ] . buttons . size ( ) , String ( ) ) ;
return cells [ p_column ] . buttons [ p_index ] . tooltip ;
2019-09-04 16:47:47 +02:00
}
2020-05-14 14:29:06 +02:00
2022-12-22 08:05:04 +01:00
int TreeItem : : get_button_id ( int p_column , int p_index ) const {
2022-02-08 16:56:13 +01:00
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , - 1 ) ;
2022-12-22 08:05:04 +01:00
ERR_FAIL_INDEX_V ( p_index , cells [ p_column ] . buttons . size ( ) , - 1 ) ;
return cells [ p_column ] . buttons [ p_index ] . id ;
2022-02-08 16:56:13 +01:00
}
2022-12-22 08:05:04 +01:00
void TreeItem : : erase_button ( int p_column , int p_index ) {
2014-02-10 02:10:30 +01:00
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2022-12-22 08:05:04 +01:00
ERR_FAIL_INDEX ( p_index , cells [ p_column ] . buttons . size ( ) ) ;
cells . write [ p_column ] . buttons . remove_at ( p_index ) ;
2014-02-10 02:10:30 +01:00
_changed_notify ( p_column ) ;
}
int TreeItem : : get_button_by_id ( int p_column , int p_id ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , - 1 ) ;
for ( int i = 0 ; i < cells [ p_column ] . buttons . size ( ) ; i + + ) {
2020-05-14 16:41:43 +02:00
if ( cells [ p_column ] . buttons [ i ] . id = = p_id ) {
2014-02-10 02:10:30 +01:00
return i ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
return - 1 ;
}
2016-02-03 00:44:42 +01:00
2024-01-28 20:55:48 +01:00
Color TreeItem : : get_button_color ( int p_column , int p_index ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , Color ( ) ) ;
ERR_FAIL_INDEX_V ( p_index , cells [ p_column ] . buttons . size ( ) , Color ( ) ) ;
return cells [ p_column ] . buttons [ p_index ] . color ;
}
2023-06-18 10:51:58 +02:00
void TreeItem : : set_button_tooltip_text ( int p_column , int p_index , const String & p_tooltip ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
ERR_FAIL_INDEX ( p_index , cells [ p_column ] . buttons . size ( ) ) ;
cells . write [ p_column ] . buttons . write [ p_index ] . tooltip = p_tooltip ;
}
2022-12-22 08:05:04 +01:00
void TreeItem : : set_button ( int p_column , int p_index , const Ref < Texture2D > & p_button ) {
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND ( p_button . is_null ( ) ) ;
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2022-12-22 08:05:04 +01:00
ERR_FAIL_INDEX ( p_index , cells [ p_column ] . buttons . size ( ) ) ;
2022-03-16 08:50:48 +01:00
2022-12-22 08:05:04 +01:00
if ( cells [ p_column ] . buttons [ p_index ] . texture = = p_button ) {
2022-03-16 08:50:48 +01:00
return ;
}
2022-12-22 08:05:04 +01:00
cells . write [ p_column ] . buttons . write [ p_index ] . texture = p_button ;
2021-09-24 10:11:44 +02:00
cells . write [ p_column ] . cached_minimum_size_dirty = true ;
2014-02-10 02:10:30 +01:00
_changed_notify ( p_column ) ;
}
2022-12-22 08:05:04 +01:00
void TreeItem : : set_button_color ( int p_column , int p_index , const Color & p_color ) {
2016-12-28 14:12:08 +01:00
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2022-12-22 08:05:04 +01:00
ERR_FAIL_INDEX ( p_index , cells [ p_column ] . buttons . size ( ) ) ;
2022-03-16 08:50:48 +01:00
2022-12-22 08:05:04 +01:00
if ( cells [ p_column ] . buttons [ p_index ] . color = = p_color ) {
2022-03-16 08:50:48 +01:00
return ;
}
2022-12-22 08:05:04 +01:00
cells . write [ p_column ] . buttons . write [ p_index ] . color = p_color ;
2016-12-28 14:12:08 +01:00
_changed_notify ( p_column ) ;
}
2022-12-22 08:05:04 +01:00
void TreeItem : : set_button_disabled ( int p_column , int p_index , bool p_disabled ) {
2019-07-09 09:13:00 +02:00
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2022-12-22 08:05:04 +01:00
ERR_FAIL_INDEX ( p_index , cells [ p_column ] . buttons . size ( ) ) ;
2019-07-09 09:13:00 +02:00
2022-12-22 08:05:04 +01:00
if ( cells [ p_column ] . buttons [ p_index ] . disabled = = p_disabled ) {
2022-03-16 08:50:48 +01:00
return ;
}
2022-12-22 08:05:04 +01:00
cells . write [ p_column ] . buttons . write [ p_index ] . disabled = p_disabled ;
2021-09-24 10:11:44 +02:00
cells . write [ p_column ] . cached_minimum_size_dirty = true ;
2019-07-09 09:13:00 +02:00
_changed_notify ( p_column ) ;
}
2022-12-22 08:05:04 +01:00
bool TreeItem : : is_button_disabled ( int p_column , int p_index ) const {
2019-07-09 09:13:00 +02:00
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , false ) ;
2022-12-22 08:05:04 +01:00
ERR_FAIL_INDEX_V ( p_index , cells [ p_column ] . buttons . size ( ) , false ) ;
2019-07-09 09:13:00 +02:00
2022-12-22 08:05:04 +01:00
return cells [ p_column ] . buttons [ p_index ] . disabled ;
2019-07-09 09:13:00 +02:00
}
2014-02-10 02:10:30 +01:00
void TreeItem : : set_editable ( int p_column , bool p_editable ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2021-09-24 10:11:44 +02:00
2022-03-16 08:50:48 +01:00
if ( cells [ p_column ] . editable = = p_editable ) {
return ;
}
2018-07-25 03:11:03 +02:00
cells . write [ p_column ] . editable = p_editable ;
2021-09-24 10:11:44 +02:00
cells . write [ p_column ] . cached_minimum_size_dirty = true ;
2014-02-10 02:10:30 +01:00
_changed_notify ( p_column ) ;
}
bool TreeItem : : is_editable ( int p_column ) {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , false ) ;
return cells [ p_column ] . editable ;
}
void TreeItem : : set_custom_color ( int p_column , const Color & p_color ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2022-03-16 08:50:48 +01:00
2022-10-06 06:08:52 +02:00
if ( cells [ p_column ] . custom_color & & cells [ p_column ] . color = = p_color ) {
2022-03-16 08:50:48 +01:00
return ;
}
2018-07-25 03:11:03 +02:00
cells . write [ p_column ] . custom_color = true ;
cells . write [ p_column ] . color = p_color ;
2014-02-10 02:10:30 +01:00
_changed_notify ( p_column ) ;
}
2020-05-14 14:29:06 +02:00
2016-03-12 14:44:12 +01:00
Color TreeItem : : get_custom_color ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , Color ( ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! cells [ p_column ] . custom_color ) {
2016-03-12 14:44:12 +01:00
return Color ( ) ;
2020-05-14 16:41:43 +02:00
}
2016-03-12 14:44:12 +01:00
return cells [ p_column ] . color ;
}
2020-05-14 14:29:06 +02:00
2014-02-10 02:10:30 +01:00
void TreeItem : : clear_custom_color ( int p_column ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2018-07-25 03:11:03 +02:00
cells . write [ p_column ] . custom_color = false ;
cells . write [ p_column ] . color = Color ( ) ;
2014-02-10 02:10:30 +01:00
_changed_notify ( p_column ) ;
}
2021-05-27 17:32:30 +02:00
void TreeItem : : set_custom_font ( int p_column , const Ref < Font > & p_font ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2021-09-24 10:11:44 +02:00
2024-01-20 16:42:28 +01:00
if ( cells [ p_column ] . custom_font = = p_font ) {
return ;
}
2021-05-27 17:32:30 +02:00
cells . write [ p_column ] . custom_font = p_font ;
2021-09-24 10:11:44 +02:00
cells . write [ p_column ] . cached_minimum_size_dirty = true ;
2024-01-20 16:42:28 +01:00
_changed_notify ( p_column ) ;
2021-05-27 17:32:30 +02:00
}
2020-12-27 14:30:33 +01:00
2021-05-27 17:32:30 +02:00
Ref < Font > TreeItem : : get_custom_font ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , Ref < Font > ( ) ) ;
return cells [ p_column ] . custom_font ;
}
2020-12-27 14:30:33 +01:00
void TreeItem : : set_custom_font_size ( int p_column , int p_font_size ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2021-09-24 10:11:44 +02:00
2024-01-20 16:42:28 +01:00
if ( cells [ p_column ] . custom_font_size = = p_font_size ) {
return ;
}
2020-12-27 14:30:33 +01:00
cells . write [ p_column ] . custom_font_size = p_font_size ;
2021-09-24 10:11:44 +02:00
cells . write [ p_column ] . cached_minimum_size_dirty = true ;
2024-01-20 16:42:28 +01:00
_changed_notify ( p_column ) ;
2020-12-27 14:30:33 +01:00
}
int TreeItem : : get_custom_font_size ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , - 1 ) ;
return cells [ p_column ] . custom_font_size ;
}
2022-08-29 15:55:49 +02:00
void TreeItem : : set_tooltip_text ( int p_column , const String & p_tooltip ) {
2014-02-10 02:10:30 +01:00
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2018-07-25 03:11:03 +02:00
cells . write [ p_column ] . tooltip = p_tooltip ;
2014-02-10 02:10:30 +01:00
}
2022-08-29 15:55:49 +02:00
String TreeItem : : get_tooltip_text ( int p_column ) const {
2014-02-10 02:10:30 +01:00
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , " " ) ;
return cells [ p_column ] . tooltip ;
}
2016-05-11 16:46:08 +02:00
void TreeItem : : set_custom_bg_color ( int p_column , const Color & p_color , bool p_bg_outline ) {
2014-02-10 02:10:30 +01:00
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2022-03-16 08:50:48 +01:00
if ( cells [ p_column ] . custom_bg_color & & cells [ p_column ] . custom_bg_outline = = p_bg_outline & & cells [ p_column ] . bg_color = = p_color ) {
return ;
}
2018-07-25 03:11:03 +02:00
cells . write [ p_column ] . custom_bg_color = true ;
cells . write [ p_column ] . custom_bg_outline = p_bg_outline ;
cells . write [ p_column ] . bg_color = p_color ;
2014-02-10 02:10:30 +01:00
_changed_notify ( p_column ) ;
}
void TreeItem : : clear_custom_bg_color ( int p_column ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2018-07-25 03:11:03 +02:00
cells . write [ p_column ] . custom_bg_color = false ;
cells . write [ p_column ] . bg_color = Color ( ) ;
2014-02-10 02:10:30 +01:00
_changed_notify ( p_column ) ;
}
Color TreeItem : : get_custom_bg_color ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , Color ( ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! cells [ p_column ] . custom_bg_color ) {
2014-02-10 02:10:30 +01:00
return Color ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
return cells [ p_column ] . bg_color ;
}
2017-06-05 01:35:08 +02:00
void TreeItem : : set_custom_as_button ( int p_column , bool p_button ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2021-09-24 10:11:44 +02:00
2024-01-20 16:42:28 +01:00
if ( cells [ p_column ] . custom_button = = p_button ) {
return ;
}
2018-07-25 03:11:03 +02:00
cells . write [ p_column ] . custom_button = p_button ;
2021-09-24 10:11:44 +02:00
cells . write [ p_column ] . cached_minimum_size_dirty = true ;
2024-01-20 16:42:28 +01:00
_changed_notify ( p_column ) ;
2017-06-05 01:35:08 +02:00
}
bool TreeItem : : is_custom_set_as_button ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , false ) ;
return cells [ p_column ] . custom_button ;
}
2021-11-25 03:58:47 +01:00
void TreeItem : : set_text_alignment ( int p_column , HorizontalAlignment p_alignment ) {
2017-06-25 22:30:28 +02:00
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2021-09-24 10:11:44 +02:00
2022-03-16 08:50:48 +01:00
if ( cells [ p_column ] . text_alignment = = p_alignment ) {
return ;
}
2021-11-25 03:58:47 +01:00
cells . write [ p_column ] . text_alignment = p_alignment ;
2021-09-24 10:11:44 +02:00
cells . write [ p_column ] . cached_minimum_size_dirty = true ;
2017-06-25 22:30:28 +02:00
_changed_notify ( p_column ) ;
}
2021-11-25 03:58:47 +01:00
HorizontalAlignment TreeItem : : get_text_alignment ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , HORIZONTAL_ALIGNMENT_LEFT ) ;
return cells [ p_column ] . text_alignment ;
2017-06-25 22:30:28 +02:00
}
void TreeItem : : set_expand_right ( int p_column , bool p_enable ) {
ERR_FAIL_INDEX ( p_column , cells . size ( ) ) ;
2021-09-24 10:11:44 +02:00
2022-03-16 08:50:48 +01:00
if ( cells [ p_column ] . expand_right = = p_enable ) {
return ;
}
2018-07-25 03:11:03 +02:00
cells . write [ p_column ] . expand_right = p_enable ;
2021-09-24 10:11:44 +02:00
cells . write [ p_column ] . cached_minimum_size_dirty = true ;
2017-06-25 22:30:28 +02:00
_changed_notify ( p_column ) ;
}
bool TreeItem : : get_expand_right ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , false ) ;
return cells [ p_column ] . expand_right ;
}
void TreeItem : : set_disable_folding ( bool p_disable ) {
2022-03-16 08:50:48 +01:00
if ( disable_folding = = p_disable ) {
return ;
}
2017-06-25 22:30:28 +02:00
disable_folding = p_disable ;
2021-09-24 10:11:44 +02:00
2022-01-27 17:34:33 +01:00
for ( Cell & c : cells ) {
2021-09-24 10:11:44 +02:00
c . cached_minimum_size_dirty = true ;
2022-01-27 17:34:33 +01:00
}
2021-09-24 10:11:44 +02:00
2017-06-25 22:30:28 +02:00
_changed_notify ( 0 ) ;
}
bool TreeItem : : is_folding_disabled ( ) const {
return disable_folding ;
}
2021-06-28 15:40:56 +02:00
Size2 TreeItem : : get_minimum_size ( int p_column ) {
ERR_FAIL_INDEX_V ( p_column , cells . size ( ) , Size2 ( ) ) ;
2022-09-29 11:53:28 +02:00
Tree * parent_tree = get_tree ( ) ;
2023-06-06 14:59:54 +02:00
ERR_FAIL_NULL_V ( parent_tree , Size2 ( ) ) ;
2021-06-28 15:40:56 +02:00
2021-09-24 10:11:44 +02:00
const TreeItem : : Cell & cell = cells [ p_column ] ;
2021-06-28 15:40:56 +02:00
2021-09-24 10:11:44 +02:00
if ( cell . cached_minimum_size_dirty ) {
2024-04-24 03:58:12 +02:00
Size2 size = Size2 (
parent_tree - > theme_cache . inner_item_margin_left + parent_tree - > theme_cache . inner_item_margin_right ,
parent_tree - > theme_cache . inner_item_margin_top + parent_tree - > theme_cache . inner_item_margin_bottom ) ;
2021-06-28 15:40:56 +02:00
2021-09-01 16:26:41 +02:00
// Text.
if ( ! cell . text . is_empty ( ) ) {
if ( cell . dirty ) {
2022-09-29 11:53:28 +02:00
parent_tree - > update_item_cell ( this , p_column ) ;
2021-09-01 16:26:41 +02:00
}
Size2 text_size = cell . text_buf - > get_size ( ) ;
2024-04-24 03:58:12 +02:00
if ( get_text_overrun_behavior ( p_column ) = = TextServer : : OVERRUN_NO_TRIMMING ) {
size . width + = text_size . width ;
}
2021-09-01 16:26:41 +02:00
size . height = MAX ( size . height , text_size . height ) ;
2021-06-28 15:40:56 +02:00
}
2021-09-01 16:26:41 +02:00
// Icon.
if ( cell . mode = = CELL_MODE_CHECK ) {
2022-11-30 16:06:14 +01:00
size . width + = parent_tree - > theme_cache . checked - > get_width ( ) + parent_tree - > theme_cache . h_separation ;
2021-09-01 16:26:41 +02:00
}
if ( cell . icon . is_valid ( ) ) {
2023-03-31 21:17:59 +02:00
Size2i icon_size = parent_tree - > _get_cell_icon_size ( cell ) ;
2022-11-30 16:06:14 +01:00
size . width + = icon_size . width + parent_tree - > theme_cache . h_separation ;
2021-09-01 16:26:41 +02:00
size . height = MAX ( size . height , icon_size . height ) ;
2021-06-28 15:40:56 +02:00
}
2021-09-01 16:26:41 +02:00
// Buttons.
for ( int i = 0 ; i < cell . buttons . size ( ) ; i + + ) {
Ref < Texture2D > texture = cell . buttons [ i ] . texture ;
if ( texture . is_valid ( ) ) {
2022-09-29 11:53:28 +02:00
Size2 button_size = texture - > get_size ( ) + parent_tree - > theme_cache . button_pressed - > get_minimum_size ( ) ;
2024-04-24 03:58:12 +02:00
size . width + = button_size . width + parent_tree - > theme_cache . button_margin ;
2021-09-01 16:26:41 +02:00
size . height = MAX ( size . height , button_size . height ) ;
}
2021-06-28 15:40:56 +02:00
}
2021-09-01 16:26:41 +02:00
2021-09-24 10:11:44 +02:00
cells . write [ p_column ] . cached_minimum_size = size ;
cells . write [ p_column ] . cached_minimum_size_dirty = false ;
2021-06-28 15:40:56 +02:00
}
2021-09-24 10:11:44 +02:00
return cell . cached_minimum_size ;
2021-06-28 15:40:56 +02:00
}
2022-02-22 12:15:43 +01:00
void TreeItem : : _call_recursive_bind ( const Variant * * p_args , int p_argcount , Callable : : CallError & r_error ) {
2018-10-07 18:25:57 +02:00
if ( p_argcount < 1 ) {
2020-02-19 20:27:19 +01:00
r_error . error = Callable : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
2023-09-29 18:19:46 +02:00
r_error . expected = 1 ;
2022-02-22 12:15:43 +01:00
return ;
2018-10-07 18:25:57 +02:00
}
2023-12-28 23:44:23 +01:00
if ( ! p_args [ 0 ] - > is_string ( ) ) {
2020-02-19 20:27:19 +01:00
r_error . error = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
2018-10-07 18:25:57 +02:00
r_error . argument = 0 ;
2020-02-20 22:58:05 +01:00
r_error . expected = Variant : : STRING_NAME ;
2022-02-22 12:15:43 +01:00
return ;
2018-10-07 18:25:57 +02:00
}
StringName method = * p_args [ 0 ] ;
call_recursive ( method , & p_args [ 1 ] , p_argcount - 1 , r_error ) ;
}
2020-02-19 20:27:19 +01:00
void recursive_call_aux ( TreeItem * p_item , const StringName & p_method , const Variant * * p_args , int p_argcount , Callable : : CallError & r_error ) {
2018-10-07 18:25:57 +02:00
if ( ! p_item ) {
return ;
}
2022-03-09 14:58:40 +01:00
p_item - > callp ( p_method , p_args , p_argcount , r_error ) ;
2021-03-07 21:07:30 +01:00
TreeItem * c = p_item - > get_first_child ( ) ;
2018-10-07 18:25:57 +02:00
while ( c ) {
recursive_call_aux ( c , p_method , p_args , p_argcount , r_error ) ;
c = c - > get_next ( ) ;
}
}
2020-02-19 20:27:19 +01:00
void TreeItem : : call_recursive ( const StringName & p_method , const Variant * * p_args , int p_argcount , Callable : : CallError & r_error ) {
2018-10-07 18:25:57 +02:00
recursive_call_aux ( this , p_method , p_args , p_argcount , r_error ) ;
}
2014-02-10 02:10:30 +01:00
void TreeItem : : _bind_methods ( ) {
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_cell_mode " , " column " , " mode " ) , & TreeItem : : set_cell_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " get_cell_mode " , " column " ) , & TreeItem : : get_cell_mode ) ;
2014-02-10 02:10:30 +01:00
2023-04-25 17:43:26 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_edit_multiline " , " column " , " multiline " ) , & TreeItem : : set_edit_multiline ) ;
ClassDB : : bind_method ( D_METHOD ( " is_edit_multiline " , " column " ) , & TreeItem : : is_edit_multiline ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_checked " , " column " , " checked " ) , & TreeItem : : set_checked ) ;
2021-07-22 22:34:54 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_indeterminate " , " column " , " indeterminate " ) , & TreeItem : : set_indeterminate ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " is_checked " , " column " ) , & TreeItem : : is_checked ) ;
2021-07-22 22:34:54 +02:00
ClassDB : : bind_method ( D_METHOD ( " is_indeterminate " , " column " ) , & TreeItem : : is_indeterminate ) ;
2014-02-10 02:10:30 +01:00
2021-09-17 17:50:24 +02:00
ClassDB : : bind_method ( D_METHOD ( " propagate_check " , " column " , " emit_signal " ) , & TreeItem : : propagate_check , DEFVAL ( true ) ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_text " , " column " , " text " ) , & TreeItem : : set_text ) ;
ClassDB : : bind_method ( D_METHOD ( " get_text " , " column " ) , & TreeItem : : get_text ) ;
2014-02-10 02:10:30 +01:00
2020-09-03 13:22:16 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_text_direction " , " column " , " direction " ) , & TreeItem : : set_text_direction ) ;
ClassDB : : bind_method ( D_METHOD ( " get_text_direction " , " column " ) , & TreeItem : : get_text_direction ) ;
2023-06-03 14:17:35 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_autowrap_mode " , " column " , " autowrap_mode " ) , & TreeItem : : set_autowrap_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " get_autowrap_mode " , " column " ) , & TreeItem : : get_autowrap_mode ) ;
2023-06-27 17:22:10 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_text_overrun_behavior " , " column " , " overrun_behavior " ) , & TreeItem : : set_text_overrun_behavior ) ;
ClassDB : : bind_method ( D_METHOD ( " get_text_overrun_behavior " , " column " ) , & TreeItem : : get_text_overrun_behavior ) ;
2020-09-03 13:22:16 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_structured_text_bidi_override " , " column " , " parser " ) , & TreeItem : : set_structured_text_bidi_override ) ;
ClassDB : : bind_method ( D_METHOD ( " get_structured_text_bidi_override " , " column " ) , & TreeItem : : get_structured_text_bidi_override ) ;
ClassDB : : bind_method ( D_METHOD ( " set_structured_text_bidi_override_options " , " column " , " args " ) , & TreeItem : : set_structured_text_bidi_override_options ) ;
ClassDB : : bind_method ( D_METHOD ( " get_structured_text_bidi_override_options " , " column " ) , & TreeItem : : get_structured_text_bidi_override_options ) ;
ClassDB : : bind_method ( D_METHOD ( " set_language " , " column " , " language " ) , & TreeItem : : set_language ) ;
ClassDB : : bind_method ( D_METHOD ( " get_language " , " column " ) , & TreeItem : : get_language ) ;
2020-05-05 20:51:13 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_suffix " , " column " , " text " ) , & TreeItem : : set_suffix ) ;
ClassDB : : bind_method ( D_METHOD ( " get_suffix " , " column " ) , & TreeItem : : get_suffix ) ;
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_icon " , " column " , " texture " ) , & TreeItem : : set_icon ) ;
ClassDB : : bind_method ( D_METHOD ( " get_icon " , " column " ) , & TreeItem : : get_icon ) ;
2014-02-10 02:10:30 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_icon_region " , " column " , " region " ) , & TreeItem : : set_icon_region ) ;
ClassDB : : bind_method ( D_METHOD ( " get_icon_region " , " column " ) , & TreeItem : : get_icon_region ) ;
2015-08-31 00:37:23 +02:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_icon_max_width " , " column " , " width " ) , & TreeItem : : set_icon_max_width ) ;
ClassDB : : bind_method ( D_METHOD ( " get_icon_max_width " , " column " ) , & TreeItem : : get_icon_max_width ) ;
2014-02-10 02:10:30 +01:00
2019-08-24 17:13:48 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_icon_modulate " , " column " , " modulate " ) , & TreeItem : : set_icon_modulate ) ;
ClassDB : : bind_method ( D_METHOD ( " get_icon_modulate " , " column " ) , & TreeItem : : get_icon_modulate ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_range " , " column " , " value " ) , & TreeItem : : set_range ) ;
ClassDB : : bind_method ( D_METHOD ( " get_range " , " column " ) , & TreeItem : : get_range ) ;
ClassDB : : bind_method ( D_METHOD ( " set_range_config " , " column " , " min " , " max " , " step " , " expr " ) , & TreeItem : : set_range_config , DEFVAL ( false ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_range_config " , " column " ) , & TreeItem : : _get_range_config ) ;
2014-02-10 02:10:30 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_metadata " , " column " , " meta " ) , & TreeItem : : set_metadata ) ;
ClassDB : : bind_method ( D_METHOD ( " get_metadata " , " column " ) , & TreeItem : : get_metadata ) ;
2014-02-10 02:10:30 +01:00
2024-01-20 17:55:34 +01:00
# ifndef DISABLE_DEPRECATED
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_custom_draw " , " column " , " object " , " callback " ) , & TreeItem : : set_custom_draw ) ;
2024-01-20 17:55:34 +01:00
# endif // DISABLE_DEPRECATED
ClassDB : : bind_method ( D_METHOD ( " set_custom_draw_callback " , " column " , " callback " ) , & TreeItem : : set_custom_draw_callback ) ;
ClassDB : : bind_method ( D_METHOD ( " get_custom_draw_callback " , " column " ) , & TreeItem : : get_custom_draw_callback ) ;
2014-02-10 02:10:30 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_collapsed " , " enable " ) , & TreeItem : : set_collapsed ) ;
ClassDB : : bind_method ( D_METHOD ( " is_collapsed " ) , & TreeItem : : is_collapsed ) ;
2014-02-10 02:10:30 +01:00
2022-07-01 15:43:39 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_collapsed_recursive " , " enable " ) , & TreeItem : : set_collapsed_recursive ) ;
ClassDB : : bind_method ( D_METHOD ( " is_any_collapsed " , " only_visible " ) , & TreeItem : : is_any_collapsed , DEFVAL ( false ) ) ;
2022-04-03 10:37:08 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_visible " , " enable " ) , & TreeItem : : set_visible ) ;
ClassDB : : bind_method ( D_METHOD ( " is_visible " ) , & TreeItem : : is_visible ) ;
2024-02-13 22:27:15 +01:00
ClassDB : : bind_method ( D_METHOD ( " is_visible_in_tree " ) , & TreeItem : : is_visible_in_tree ) ;
2022-04-03 10:37:08 +02:00
2021-03-19 13:57:52 +01:00
ClassDB : : bind_method ( D_METHOD ( " uncollapse_tree " ) , & TreeItem : : uncollapse_tree ) ;
2017-09-05 14:31:07 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_custom_minimum_height " , " height " ) , & TreeItem : : set_custom_minimum_height ) ;
ClassDB : : bind_method ( D_METHOD ( " get_custom_minimum_height " ) , & TreeItem : : get_custom_minimum_height ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_selectable " , " column " , " selectable " ) , & TreeItem : : set_selectable ) ;
ClassDB : : bind_method ( D_METHOD ( " is_selectable " , " column " ) , & TreeItem : : is_selectable ) ;
2015-08-31 00:37:23 +02:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " is_selected " , " column " ) , & TreeItem : : is_selected ) ;
ClassDB : : bind_method ( D_METHOD ( " select " , " column " ) , & TreeItem : : select ) ;
ClassDB : : bind_method ( D_METHOD ( " deselect " , " column " ) , & TreeItem : : deselect ) ;
2014-02-10 02:10:30 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_editable " , " column " , " enabled " ) , & TreeItem : : set_editable ) ;
ClassDB : : bind_method ( D_METHOD ( " is_editable " , " column " ) , & TreeItem : : is_editable ) ;
2014-02-10 02:10:30 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_custom_color " , " column " , " color " ) , & TreeItem : : set_custom_color ) ;
2019-10-06 22:07:50 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_custom_color " , " column " ) , & TreeItem : : get_custom_color ) ;
2021-05-27 17:32:30 +02:00
ClassDB : : bind_method ( D_METHOD ( " clear_custom_color " , " column " ) , & TreeItem : : clear_custom_color ) ;
ClassDB : : bind_method ( D_METHOD ( " set_custom_font " , " column " , " font " ) , & TreeItem : : set_custom_font ) ;
ClassDB : : bind_method ( D_METHOD ( " get_custom_font " , " column " ) , & TreeItem : : get_custom_font ) ;
2014-02-10 02:10:30 +01:00
2020-12-27 14:30:33 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_custom_font_size " , " column " , " font_size " ) , & TreeItem : : set_custom_font_size ) ;
ClassDB : : bind_method ( D_METHOD ( " get_custom_font_size " , " column " ) , & TreeItem : : get_custom_font_size ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_custom_bg_color " , " column " , " color " , " just_outline " ) , & TreeItem : : set_custom_bg_color , DEFVAL ( false ) ) ;
ClassDB : : bind_method ( D_METHOD ( " clear_custom_bg_color " , " column " ) , & TreeItem : : clear_custom_bg_color ) ;
ClassDB : : bind_method ( D_METHOD ( " get_custom_bg_color " , " column " ) , & TreeItem : : get_custom_bg_color ) ;
2014-02-10 02:10:30 +01:00
2017-06-05 01:35:08 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_custom_as_button " , " column " , " enable " ) , & TreeItem : : set_custom_as_button ) ;
ClassDB : : bind_method ( D_METHOD ( " is_custom_set_as_button " , " column " ) , & TreeItem : : is_custom_set_as_button ) ;
2022-08-29 15:55:49 +02:00
ClassDB : : bind_method ( D_METHOD ( " add_button " , " column " , " button " , " id " , " disabled " , " tooltip_text " ) , & TreeItem : : add_button , DEFVAL ( - 1 ) , DEFVAL ( false ) , DEFVAL ( " " ) ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_button_count " , " column " ) , & TreeItem : : get_button_count ) ;
2022-12-22 08:05:04 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_button_tooltip_text " , " column " , " button_index " ) , & TreeItem : : get_button_tooltip_text ) ;
ClassDB : : bind_method ( D_METHOD ( " get_button_id " , " column " , " button_index " ) , & TreeItem : : get_button_id ) ;
2022-02-08 16:56:13 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_button_by_id " , " column " , " id " ) , & TreeItem : : get_button_by_id ) ;
2024-01-28 20:55:48 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_button_color " , " column " , " id " ) , & TreeItem : : get_button_color ) ;
2022-12-22 08:05:04 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_button " , " column " , " button_index " ) , & TreeItem : : get_button ) ;
2023-06-18 10:51:58 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_button_tooltip_text " , " column " , " button_index " , " tooltip " ) , & TreeItem : : set_button_tooltip_text ) ;
2022-12-22 08:05:04 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_button " , " column " , " button_index " , " button " ) , & TreeItem : : set_button ) ;
ClassDB : : bind_method ( D_METHOD ( " erase_button " , " column " , " button_index " ) , & TreeItem : : erase_button ) ;
ClassDB : : bind_method ( D_METHOD ( " set_button_disabled " , " column " , " button_index " , " disabled " ) , & TreeItem : : set_button_disabled ) ;
ClassDB : : bind_method ( D_METHOD ( " set_button_color " , " column " , " button_index " , " color " ) , & TreeItem : : set_button_color ) ;
ClassDB : : bind_method ( D_METHOD ( " is_button_disabled " , " column " , " button_index " ) , & TreeItem : : is_button_disabled ) ;
2014-02-10 02:10:30 +01:00
2022-08-29 15:55:49 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_tooltip_text " , " column " , " tooltip " ) , & TreeItem : : set_tooltip_text ) ;
ClassDB : : bind_method ( D_METHOD ( " get_tooltip_text " , " column " ) , & TreeItem : : get_tooltip_text ) ;
2021-11-25 03:58:47 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_text_alignment " , " column " , " text_alignment " ) , & TreeItem : : set_text_alignment ) ;
ClassDB : : bind_method ( D_METHOD ( " get_text_alignment " , " column " ) , & TreeItem : : get_text_alignment ) ;
2021-03-07 21:07:30 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_expand_right " , " column " , " enable " ) , & TreeItem : : set_expand_right ) ;
ClassDB : : bind_method ( D_METHOD ( " get_expand_right " , " column " ) , & TreeItem : : get_expand_right ) ;
2014-02-10 02:10:30 +01:00
2017-06-25 22:30:28 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_disable_folding " , " disable " ) , & TreeItem : : set_disable_folding ) ;
ClassDB : : bind_method ( D_METHOD ( " is_folding_disabled " ) , & TreeItem : : is_folding_disabled ) ;
2022-12-22 08:05:04 +01:00
ClassDB : : bind_method ( D_METHOD ( " create_child " , " index " ) , & TreeItem : : create_child , DEFVAL ( - 1 ) ) ;
2023-05-31 11:31:43 +02:00
ClassDB : : bind_method ( D_METHOD ( " add_child " , " child " ) , & TreeItem : : add_child ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_child " , " child " ) , & TreeItem : : remove_child ) ;
2021-03-07 21:07:30 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_tree " ) , & TreeItem : : get_tree ) ;
ClassDB : : bind_method ( D_METHOD ( " get_next " ) , & TreeItem : : get_next ) ;
ClassDB : : bind_method ( D_METHOD ( " get_prev " ) , & TreeItem : : get_prev ) ;
ClassDB : : bind_method ( D_METHOD ( " get_parent " ) , & TreeItem : : get_parent ) ;
ClassDB : : bind_method ( D_METHOD ( " get_first_child " ) , & TreeItem : : get_first_child ) ;
2023-05-11 04:17:03 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_next_in_tree " , " wrap " ) , & TreeItem : : get_next_in_tree , DEFVAL ( false ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_prev_in_tree " , " wrap " ) , & TreeItem : : get_prev_in_tree , DEFVAL ( false ) ) ;
2021-03-07 21:07:30 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_next_visible " , " wrap " ) , & TreeItem : : get_next_visible , DEFVAL ( false ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_prev_visible " , " wrap " ) , & TreeItem : : get_prev_visible , DEFVAL ( false ) ) ;
2022-12-22 08:05:04 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_child " , " index " ) , & TreeItem : : get_child ) ;
2021-03-07 21:07:30 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_child_count " ) , & TreeItem : : get_child_count ) ;
ClassDB : : bind_method ( D_METHOD ( " get_children " ) , & TreeItem : : get_children ) ;
ClassDB : : bind_method ( D_METHOD ( " get_index " ) , & TreeItem : : get_index ) ;
2022-01-28 15:06:54 +01:00
ClassDB : : bind_method ( D_METHOD ( " move_before " , " item " ) , & TreeItem : : move_before ) ;
ClassDB : : bind_method ( D_METHOD ( " move_after " , " item " ) , & TreeItem : : move_after ) ;
2021-03-07 21:07:30 +01:00
2018-10-07 18:25:57 +02:00
{
MethodInfo mi ;
mi . name = " call_recursive " ;
2020-02-20 22:58:05 +01:00
mi . arguments . push_back ( PropertyInfo ( Variant : : STRING_NAME , " method " ) ) ;
2018-10-07 18:25:57 +02:00
ClassDB : : bind_vararg_method ( METHOD_FLAGS_DEFAULT , " call_recursive " , & TreeItem : : _call_recursive_bind , mi ) ;
}
2018-01-11 23:35:12 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " collapsed " ) , " set_collapsed " , " is_collapsed " ) ;
2022-04-03 10:37:08 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " visible " ) , " set_visible " , " is_visible " ) ;
2018-01-11 23:35:12 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " disable_folding " ) , " set_disable_folding " , " is_folding_disabled " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " custom_minimum_height " , PROPERTY_HINT_RANGE , " 0,1000,1 " ) , " set_custom_minimum_height " , " get_custom_minimum_height " ) ;
2017-08-20 17:45:01 +02:00
BIND_ENUM_CONSTANT ( CELL_MODE_STRING ) ;
BIND_ENUM_CONSTANT ( CELL_MODE_CHECK ) ;
BIND_ENUM_CONSTANT ( CELL_MODE_RANGE ) ;
BIND_ENUM_CONSTANT ( CELL_MODE_ICON ) ;
BIND_ENUM_CONSTANT ( CELL_MODE_CUSTOM ) ;
2014-02-10 02:10:30 +01:00
}
TreeItem : : TreeItem ( Tree * p_tree ) {
tree = p_tree ;
}
TreeItem : : ~ TreeItem ( ) {
2021-03-07 21:07:30 +01:00
_unlink_from_tree ( ) ;
2023-05-31 11:31:43 +02:00
_change_tree ( nullptr ) ;
2022-08-04 00:08:16 +02:00
validate_cache ( ) ;
2021-03-07 21:07:30 +01:00
prev = nullptr ;
2014-02-10 02:10:30 +01:00
clear_children ( ) ;
}
/**********************************************/
/**********************************************/
/**********************************************/
/**********************************************/
/**********************************************/
/**********************************************/
2022-08-31 14:02:40 +02:00
void Tree : : _update_theme_item_cache ( ) {
Control : : _update_theme_item_cache ( ) ;
theme_cache . base_scale = get_theme_default_base_scale ( ) ;
2014-02-10 02:10:30 +01:00
}
2023-03-31 21:17:59 +02:00
Size2 Tree : : _get_cell_icon_size ( const TreeItem : : Cell & p_cell ) const {
Size2i icon_size = p_cell . get_icon_size ( ) ;
int max_width = 0 ;
if ( theme_cache . icon_max_width > 0 ) {
max_width = theme_cache . icon_max_width ;
}
if ( p_cell . icon_max_w > 0 & & ( max_width = = 0 | | p_cell . icon_max_w < max_width ) ) {
max_width = p_cell . icon_max_w ;
}
if ( max_width > 0 & & icon_size . width > max_width ) {
icon_size . height = icon_size . height * max_width / icon_size . width ;
icon_size . width = max_width ;
}
return icon_size ;
}
2014-02-10 02:10:30 +01:00
int Tree : : compute_item_height ( TreeItem * p_item ) const {
2024-02-13 22:27:15 +01:00
if ( ( p_item = = root & & hide_root ) | | ! p_item - > is_visible_in_tree ( ) ) {
2014-02-10 02:10:30 +01:00
return 0 ;
2020-05-14 16:41:43 +02:00
}
2015-08-31 00:37:23 +02:00
2022-08-31 14:02:40 +02:00
ERR_FAIL_COND_V ( theme_cache . font . is_null ( ) , 0 ) ;
2020-09-03 13:22:16 +02:00
int height = 0 ;
2014-02-10 02:10:30 +01:00
for ( int i = 0 ; i < columns . size ( ) ; i + + ) {
2020-09-03 13:22:16 +02:00
if ( p_item - > cells [ i ] . dirty ) {
const_cast < Tree * > ( this ) - > update_item_cell ( p_item , i ) ;
}
height = MAX ( height , p_item - > cells [ i ] . text_buf - > get_size ( ) . y ) ;
2014-02-10 02:10:30 +01:00
for ( int j = 0 ; j < p_item - > cells [ i ] . buttons . size ( ) ; j + + ) {
Size2i s ; // = cache.button_pressed->get_minimum_size();
s + = p_item - > cells [ i ] . buttons [ j ] . texture - > get_size ( ) ;
2020-05-14 16:41:43 +02:00
if ( s . height > height ) {
2014-02-10 02:10:30 +01:00
height = s . height ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
switch ( p_item - > cells [ i ] . mode ) {
case TreeItem : : CELL_MODE_CHECK : {
2022-08-31 14:02:40 +02:00
int check_icon_h = theme_cache . checked - > get_height ( ) ;
2020-05-14 16:41:43 +02:00
if ( height < check_icon_h ) {
2014-02-10 02:10:30 +01:00
height = check_icon_h ;
2020-05-14 16:41:43 +02:00
}
2020-02-22 20:47:50 +01:00
[[fallthrough]] ;
2014-02-10 02:10:30 +01:00
}
case TreeItem : : CELL_MODE_STRING :
case TreeItem : : CELL_MODE_CUSTOM :
case TreeItem : : CELL_MODE_ICON : {
2019-06-11 20:43:37 +02:00
Ref < Texture2D > icon = p_item - > cells [ i ] . icon ;
2014-02-10 02:10:30 +01:00
if ( ! icon . is_null ( ) ) {
2023-03-31 21:17:59 +02:00
Size2i s = _get_cell_icon_size ( p_item - > cells [ i ] ) ;
2020-05-14 16:41:43 +02:00
if ( s . height > height ) {
2014-02-10 02:10:30 +01:00
height = s . height ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2017-06-05 01:35:08 +02:00
if ( p_item - > cells [ i ] . mode = = TreeItem : : CELL_MODE_CUSTOM & & p_item - > cells [ i ] . custom_button ) {
2022-08-31 14:02:40 +02:00
height + = theme_cache . custom_button - > get_minimum_size ( ) . height ;
2017-06-05 01:35:08 +02:00
}
2015-08-31 00:37:23 +02:00
2014-02-10 02:10:30 +01:00
} break ;
2019-04-09 17:08:36 +02:00
default : {
}
2014-02-10 02:10:30 +01:00
}
}
2023-04-25 17:43:26 +02:00
int item_min_height = MAX ( theme_cache . font - > get_height ( theme_cache . font_size ) , p_item - > get_custom_minimum_height ( ) ) ;
2020-05-14 16:41:43 +02:00
if ( height < item_min_height ) {
2017-09-05 14:31:07 +02:00
height = item_min_height ;
2020-05-14 16:41:43 +02:00
}
2015-08-31 00:37:23 +02:00
2022-11-30 16:06:14 +01:00
height + = theme_cache . v_separation ;
2015-08-31 00:37:23 +02:00
2014-02-10 02:10:30 +01:00
return height ;
}
int Tree : : get_item_height ( TreeItem * p_item ) const {
2024-02-13 22:27:15 +01:00
if ( ! p_item - > is_visible_in_tree ( ) ) {
2022-04-03 10:37:08 +02:00
return 0 ;
}
2014-02-10 02:10:30 +01:00
int height = compute_item_height ( p_item ) ;
2022-11-30 16:06:14 +01:00
height + = theme_cache . v_separation ;
2014-02-10 02:10:30 +01:00
2018-01-18 21:37:17 +01:00
if ( ! p_item - > collapsed ) { /* if not collapsed, check the children */
2014-02-10 02:10:30 +01:00
2021-03-07 21:07:30 +01:00
TreeItem * c = p_item - > first_child ;
2014-02-10 02:10:30 +01:00
while ( c ) {
height + = get_item_height ( c ) ;
c = c - > next ;
}
}
return height ;
}
2023-04-28 09:45:29 +02:00
void Tree : : draw_item_rect ( TreeItem : : Cell & p_cell , const Rect2i & p_rect , const Color & p_color , const Color & p_icon_color , int p_ol_size , const Color & p_ol_color ) {
2022-08-31 14:02:40 +02:00
ERR_FAIL_COND ( theme_cache . font . is_null ( ) ) ;
2018-01-06 19:48:54 +01:00
2023-04-27 20:16:28 +02:00
Rect2i rect = p_rect . grow_individual ( - theme_cache . inner_item_margin_left , - theme_cache . inner_item_margin_top , - theme_cache . inner_item_margin_right , - theme_cache . inner_item_margin_bottom ) ;
2020-09-03 13:22:16 +02:00
Size2 ts = p_cell . text_buf - > get_size ( ) ;
bool rtl = is_layout_rtl ( ) ;
2017-06-25 22:30:28 +02:00
int w = 0 ;
2023-04-27 20:16:28 +02:00
Size2i bmsize ;
2017-06-25 22:30:28 +02:00
if ( ! p_cell . icon . is_null ( ) ) {
2023-04-27 20:16:28 +02:00
bmsize = _get_cell_icon_size ( p_cell ) ;
2022-11-30 16:06:14 +01:00
w + = bmsize . width + theme_cache . h_separation ;
2020-09-03 13:22:16 +02:00
if ( rect . size . width > 0 & & ( w + ts . width ) > rect . size . width ) {
ts . width = rect . size . width - w ;
}
2017-06-25 22:30:28 +02:00
}
2020-09-03 13:22:16 +02:00
w + = ts . width ;
2017-06-25 22:30:28 +02:00
2021-11-25 03:58:47 +01:00
switch ( p_cell . text_alignment ) {
case HORIZONTAL_ALIGNMENT_FILL :
case HORIZONTAL_ALIGNMENT_LEFT : {
2020-09-03 13:22:16 +02:00
if ( rtl ) {
rect . position . x + = MAX ( 0 , ( rect . size . width - w ) ) ;
}
2021-11-25 03:58:47 +01:00
} break ;
case HORIZONTAL_ALIGNMENT_CENTER :
2017-12-28 11:27:57 +01:00
rect . position . x + = MAX ( 0 , ( rect . size . width - w ) / 2 ) ;
2020-09-03 13:22:16 +02:00
break ;
2021-11-25 03:58:47 +01:00
case HORIZONTAL_ALIGNMENT_RIGHT :
2020-09-03 13:22:16 +02:00
if ( ! rtl ) {
rect . position . x + = MAX ( 0 , ( rect . size . width - w ) ) ;
}
break ;
2017-06-25 22:30:28 +02:00
}
2014-02-10 02:10:30 +01:00
RID ci = get_canvas_item ( ) ;
2020-09-03 13:22:16 +02:00
2023-02-04 16:17:42 +01:00
if ( rtl & & rect . size . width > 0 ) {
2020-09-03 13:22:16 +02:00
Point2 draw_pos = rect . position ;
2023-04-28 09:45:29 +02:00
draw_pos . y + = Math : : floor ( ( rect . size . y - p_cell . text_buf - > get_size ( ) . y ) * 0.5 ) ;
2020-12-25 22:45:28 +01:00
if ( p_ol_size > 0 & & p_ol_color . a > 0 ) {
p_cell . text_buf - > draw_outline ( ci , draw_pos , p_ol_size , p_ol_color ) ;
}
2020-09-03 13:22:16 +02:00
p_cell . text_buf - > draw ( ci , draw_pos , p_color ) ;
2022-11-30 16:06:14 +01:00
rect . position . x + = ts . width + theme_cache . h_separation ;
rect . size . x - = ts . width + theme_cache . h_separation ;
2020-09-03 13:22:16 +02:00
}
2014-02-10 02:10:30 +01:00
if ( ! p_cell . icon . is_null ( ) ) {
2017-07-19 22:00:46 +02:00
p_cell . draw_icon ( ci , rect . position + Size2i ( 0 , Math : : floor ( ( real_t ) ( rect . size . y - bmsize . y ) / 2 ) ) , bmsize , p_icon_color ) ;
2022-11-30 16:06:14 +01:00
rect . position . x + = bmsize . x + theme_cache . h_separation ;
rect . size . x - = bmsize . x + theme_cache . h_separation ;
2014-02-10 02:10:30 +01:00
}
2023-02-04 16:17:42 +01:00
if ( ! rtl & & rect . size . width > 0 ) {
2020-09-03 13:22:16 +02:00
Point2 draw_pos = rect . position ;
2023-04-28 09:45:29 +02:00
draw_pos . y + = Math : : floor ( ( rect . size . y - p_cell . text_buf - > get_size ( ) . y ) * 0.5 ) ;
2020-12-25 22:45:28 +01:00
if ( p_ol_size > 0 & & p_ol_color . a > 0 ) {
p_cell . text_buf - > draw_outline ( ci , draw_pos , p_ol_size , p_ol_color ) ;
}
2020-09-03 13:22:16 +02:00
p_cell . text_buf - > draw ( ci , draw_pos , p_color ) ;
}
}
void Tree : : update_column ( int p_col ) {
columns . write [ p_col ] . text_buf - > clear ( ) ;
if ( columns [ p_col ] . text_direction = = Control : : TEXT_DIRECTION_INHERITED ) {
columns . write [ p_col ] . text_buf - > set_direction ( is_layout_rtl ( ) ? TextServer : : DIRECTION_RTL : TextServer : : DIRECTION_LTR ) ;
} else {
columns . write [ p_col ] . text_buf - > set_direction ( ( TextServer : : Direction ) columns [ p_col ] . text_direction ) ;
}
2021-05-27 17:32:30 +02:00
2024-03-01 05:27:36 +01:00
columns . write [ p_col ] . xl_title = atr ( columns [ p_col ] . title ) ;
columns . write [ p_col ] . text_buf - > add_string ( columns [ p_col ] . xl_title , theme_cache . tb_font , theme_cache . tb_font_size , columns [ p_col ] . language ) ;
2023-07-11 10:58:19 +02:00
columns . write [ p_col ] . cached_minimum_width_dirty = true ;
2020-09-03 13:22:16 +02:00
}
void Tree : : update_item_cell ( TreeItem * p_item , int p_col ) {
String valtext ;
p_item - > cells . write [ p_col ] . text_buf - > clear ( ) ;
if ( p_item - > cells [ p_col ] . mode = = TreeItem : : CELL_MODE_RANGE ) {
2021-12-09 10:42:46 +01:00
if ( ! p_item - > cells [ p_col ] . text . is_empty ( ) ) {
2020-09-03 13:22:16 +02:00
if ( ! p_item - > cells [ p_col ] . editable ) {
return ;
}
int option = ( int ) p_item - > cells [ p_col ] . val ;
2023-12-16 00:56:06 +01:00
valtext = atr ( ETR ( " (Other) " ) ) ;
2020-09-03 13:22:16 +02:00
Vector < String > strings = p_item - > cells [ p_col ] . text . split ( " , " ) ;
for ( int j = 0 ; j < strings . size ( ) ; j + + ) {
int value = j ;
2020-12-15 13:04:21 +01:00
if ( ! strings [ j ] . get_slicec ( ' : ' , 1 ) . is_empty ( ) ) {
2020-09-03 13:22:16 +02:00
value = strings [ j ] . get_slicec ( ' : ' , 1 ) . to_int ( ) ;
}
if ( option = = value ) {
2024-03-01 05:27:36 +01:00
valtext = atr ( strings [ j ] . get_slicec ( ' : ' , 0 ) ) ;
2020-09-03 13:22:16 +02:00
break ;
}
}
} else {
valtext = String : : num ( p_item - > cells [ p_col ] . val , Math : : range_step_decimals ( p_item - > cells [ p_col ] . step ) ) ;
}
} else {
2024-03-01 05:27:36 +01:00
// Don't auto translate if it's in string mode and editable, as the text can be changed to anything by the user.
if ( ! p_item - > cells [ p_col ] . editable | | p_item - > cells [ p_col ] . mode ! = TreeItem : : CELL_MODE_STRING ) {
p_item - > cells . write [ p_col ] . xl_text = atr ( p_item - > cells [ p_col ] . text ) ;
} else {
p_item - > cells . write [ p_col ] . xl_text = p_item - > cells [ p_col ] . text ;
}
valtext = p_item - > cells [ p_col ] . xl_text ;
2020-09-03 13:22:16 +02:00
}
2021-12-09 10:42:46 +01:00
if ( ! p_item - > cells [ p_col ] . suffix . is_empty ( ) ) {
2024-03-01 05:27:36 +01:00
if ( ! valtext . is_empty ( ) ) {
valtext + = " " ;
}
valtext + = p_item - > cells [ p_col ] . suffix ;
2020-09-03 13:22:16 +02:00
}
if ( p_item - > cells [ p_col ] . text_direction = = Control : : TEXT_DIRECTION_INHERITED ) {
p_item - > cells . write [ p_col ] . text_buf - > set_direction ( is_layout_rtl ( ) ? TextServer : : DIRECTION_RTL : TextServer : : DIRECTION_LTR ) ;
} else {
p_item - > cells . write [ p_col ] . text_buf - > set_direction ( ( TextServer : : Direction ) p_item - > cells [ p_col ] . text_direction ) ;
}
2021-05-27 17:32:30 +02:00
Ref < Font > font ;
if ( p_item - > cells [ p_col ] . custom_font . is_valid ( ) ) {
font = p_item - > cells [ p_col ] . custom_font ;
} else {
2022-08-31 14:02:40 +02:00
font = theme_cache . font ;
2021-05-27 17:32:30 +02:00
}
2020-12-27 14:30:33 +01:00
int font_size ;
if ( p_item - > cells [ p_col ] . custom_font_size > 0 ) {
font_size = p_item - > cells [ p_col ] . custom_font_size ;
} else {
2022-08-31 14:02:40 +02:00
font_size = theme_cache . font_size ;
2020-12-27 14:30:33 +01:00
}
2022-05-09 11:47:10 +02:00
p_item - > cells . write [ p_col ] . text_buf - > add_string ( valtext , font , font_size , p_item - > cells [ p_col ] . language ) ;
2023-06-03 14:17:35 +02:00
BitField < TextServer : : LineBreakFlag > break_flags = TextServer : : BREAK_MANDATORY | TextServer : : BREAK_TRIM_EDGE_SPACES ;
switch ( p_item - > cells . write [ p_col ] . autowrap_mode ) {
case TextServer : : AUTOWRAP_OFF :
break ;
case TextServer : : AUTOWRAP_ARBITRARY :
break_flags . set_flag ( TextServer : : BREAK_GRAPHEME_BOUND ) ;
break ;
case TextServer : : AUTOWRAP_WORD :
break_flags . set_flag ( TextServer : : BREAK_WORD_BOUND ) ;
break ;
case TextServer : : AUTOWRAP_WORD_SMART :
break_flags . set_flag ( TextServer : : BREAK_WORD_BOUND ) ;
break_flags . set_flag ( TextServer : : BREAK_ADAPTIVE ) ;
break ;
}
p_item - > cells . write [ p_col ] . text_buf - > set_break_flags ( break_flags ) ;
2020-09-03 13:22:16 +02:00
TS - > shaped_text_set_bidi_override ( p_item - > cells [ p_col ] . text_buf - > get_rid ( ) , structured_text_parser ( p_item - > cells [ p_col ] . st_parser , p_item - > cells [ p_col ] . st_args , valtext ) ) ;
p_item - > cells . write [ p_col ] . dirty = false ;
}
void Tree : : update_item_cache ( TreeItem * p_item ) {
for ( int i = 0 ; i < p_item - > cells . size ( ) ; i + + ) {
update_item_cell ( p_item , i ) ;
}
2021-03-07 21:07:30 +01:00
TreeItem * c = p_item - > first_child ;
2020-09-03 13:22:16 +02:00
while ( c ) {
update_item_cache ( c ) ;
c = c - > next ;
}
2014-02-10 02:10:30 +01:00
}
2023-07-11 10:58:19 +02:00
int Tree : : draw_item ( const Point2i & p_pos , const Point2 & p_draw_ofs , const Size2 & p_draw_size , TreeItem * p_item , int & r_self_height ) {
2022-08-31 14:02:40 +02:00
if ( p_pos . y - theme_cache . offset . y > ( p_draw_size . height ) ) {
2014-02-10 02:10:30 +01:00
return - 1 ; //draw no more!
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2024-02-13 22:27:15 +01:00
if ( ! p_item - > is_visible_in_tree ( ) ) {
2022-04-03 10:37:08 +02:00
return 0 ;
}
2014-02-10 02:10:30 +01:00
RID ci = get_canvas_item ( ) ;
int htotal = 0 ;
2023-04-28 09:45:29 +02:00
int label_h = 0 ;
2021-07-04 05:13:28 +02:00
bool rtl = cache . rtl ;
2014-02-10 02:10:30 +01:00
/* Draw label, if height fits */
2017-01-21 23:00:25 +01:00
bool skip = ( p_item = = root & & hide_root ) ;
2014-02-10 02:10:30 +01:00
2023-04-28 09:45:29 +02:00
if ( ! skip ) {
2022-02-16 13:56:32 +01:00
// Draw separation.
2014-02-10 02:10:30 +01:00
2022-08-31 14:02:40 +02:00
ERR_FAIL_COND_V ( theme_cache . font . is_null ( ) , - 1 ) ;
2014-02-10 02:10:30 +01:00
2022-11-30 16:06:14 +01:00
int ofs = p_pos . x + ( ( p_item - > disable_folding | | hide_folding ) ? theme_cache . h_separation : theme_cache . item_margin ) ;
2019-02-12 21:10:08 +01:00
int skip2 = 0 ;
2014-02-10 02:10:30 +01:00
for ( int i = 0 ; i < columns . size ( ) ; i + + ) {
2019-02-12 21:10:08 +01:00
if ( skip2 ) {
skip2 - - ;
2017-06-25 22:30:28 +02:00
continue ;
}
2023-01-14 21:32:48 +01:00
int item_width = get_column_width ( i ) ;
2014-02-10 02:10:30 +01:00
if ( i = = 0 ) {
2023-01-14 21:32:48 +01:00
item_width - = ofs ;
2014-02-10 02:10:30 +01:00
2023-01-14 21:32:48 +01:00
if ( item_width < = 0 ) {
2014-02-10 02:10:30 +01:00
ofs = get_column_width ( 0 ) ;
continue ;
}
} else {
2022-11-30 16:06:14 +01:00
ofs + = theme_cache . h_separation ;
2023-01-14 21:32:48 +01:00
item_width - = theme_cache . h_separation ;
2014-02-10 02:10:30 +01:00
}
2017-06-25 22:30:28 +02:00
if ( p_item - > cells [ i ] . expand_right ) {
int plus = 1 ;
2024-03-01 05:27:36 +01:00
while ( i + plus < columns . size ( ) & & ! p_item - > cells [ i + plus ] . editable & & p_item - > cells [ i + plus ] . mode = = TreeItem : : CELL_MODE_STRING & & p_item - > cells [ i + plus ] . xl_text . is_empty ( ) & & p_item - > cells [ i + plus ] . icon . is_null ( ) ) {
2023-01-14 21:32:48 +01:00
item_width + = get_column_width ( i + plus ) ;
2017-06-25 22:30:28 +02:00
plus + + ;
2019-02-12 21:10:08 +01:00
skip2 + + ;
2017-06-25 22:30:28 +02:00
}
}
2021-07-04 05:13:28 +02:00
if ( ! rtl & & p_item - > cells [ i ] . buttons . size ( ) ) {
2023-01-14 21:32:48 +01:00
int buttons_width = 0 ;
2021-07-04 05:13:28 +02:00
for ( int j = p_item - > cells [ i ] . buttons . size ( ) - 1 ; j > = 0 ; j - - ) {
2023-01-14 21:32:48 +01:00
Ref < Texture2D > button_texture = p_item - > cells [ i ] . buttons [ j ] . texture ;
buttons_width + = button_texture - > get_size ( ) . width + theme_cache . button_pressed - > get_minimum_size ( ) . width + theme_cache . button_margin ;
2021-07-04 05:13:28 +02:00
}
2022-08-31 14:02:40 +02:00
int total_ofs = ofs - theme_cache . offset . x ;
2021-07-04 05:13:28 +02:00
2023-01-14 21:32:48 +01:00
if ( total_ofs + item_width > p_draw_size . width ) {
item_width = MAX ( buttons_width , p_draw_size . width - total_ofs ) ;
2021-07-04 05:13:28 +02:00
}
}
2023-01-14 21:32:48 +01:00
int item_width_with_buttons = item_width ; // used later for drawing buttons
int buttons_width = 0 ;
2014-02-10 02:10:30 +01:00
for ( int j = p_item - > cells [ i ] . buttons . size ( ) - 1 ; j > = 0 ; j - - ) {
2023-01-14 21:32:48 +01:00
Ref < Texture2D > button_texture = p_item - > cells [ i ] . buttons [ j ] . texture ;
Size2 button_size = button_texture - > get_size ( ) + theme_cache . button_pressed - > get_minimum_size ( ) ;
2014-02-10 02:10:30 +01:00
2023-01-14 21:32:48 +01:00
item_width - = button_size . width + theme_cache . button_margin ;
buttons_width + = button_size . width + theme_cache . button_margin ;
2014-02-10 02:10:30 +01:00
}
2023-06-27 17:22:10 +02:00
int text_width = item_width - theme_cache . inner_item_margin_left - theme_cache . inner_item_margin_right ;
if ( p_item - > cells [ i ] . icon . is_valid ( ) ) {
2023-10-26 14:47:45 +02:00
text_width - = _get_cell_icon_size ( p_item - > cells [ i ] ) . x + theme_cache . h_separation ;
2023-06-27 17:22:10 +02:00
}
p_item - > cells . write [ i ] . text_buf - > set_width ( text_width ) ;
2023-04-28 09:45:29 +02:00
2023-07-11 10:58:19 +02:00
r_self_height = compute_item_height ( p_item ) ;
label_h = r_self_height + theme_cache . v_separation ;
if ( p_pos . y + label_h - theme_cache . offset . y < 0 ) {
continue ; // No need to draw.
2023-04-28 09:45:29 +02:00
}
2023-01-14 21:32:48 +01:00
Rect2i item_rect = Rect2i ( Point2i ( ofs , p_pos . y ) - theme_cache . offset + p_draw_ofs , Size2i ( item_width , label_h ) ) ;
2014-02-10 02:10:30 +01:00
Rect2i cell_rect = item_rect ;
if ( i ! = 0 ) {
2022-11-30 16:06:14 +01:00
cell_rect . position . x - = theme_cache . h_separation ;
cell_rect . size . x + = theme_cache . h_separation ;
2014-02-10 02:10:30 +01:00
}
2022-08-31 14:02:40 +02:00
if ( theme_cache . draw_guides ) {
2020-09-03 13:22:16 +02:00
Rect2 r = cell_rect ;
if ( rtl ) {
r . position . x = get_size ( ) . width - r . position . x - r . size . x ;
}
2022-08-31 14:02:40 +02:00
RenderingServer : : get_singleton ( ) - > canvas_item_add_line ( ci , Point2i ( r . position . x , r . position . y + r . size . height ) , r . position + r . size , theme_cache . guide_color , 1 ) ;
2018-11-19 02:00:31 +01:00
}
2014-02-10 02:10:30 +01:00
2015-12-08 19:04:56 +01:00
if ( i = = 0 ) {
2014-02-10 02:10:30 +01:00
if ( p_item - > cells [ 0 ] . selected & & select_mode = = SELECT_ROW ) {
2023-01-04 03:59:34 +01:00
const Rect2 content_rect = _get_content_rect ( ) ;
Rect2i row_rect = Rect2i ( Point2i ( content_rect . position . x , item_rect . position . y ) , Size2i ( content_rect . size . x , item_rect . size . y ) ) ;
2020-09-03 13:22:16 +02:00
if ( rtl ) {
row_rect . position . x = get_size ( ) . width - row_rect . position . x - row_rect . size . x ;
}
2020-05-14 16:41:43 +02:00
if ( has_focus ( ) ) {
2022-08-31 14:02:40 +02:00
theme_cache . selected_focus - > draw ( ci , row_rect ) ;
2020-05-14 16:41:43 +02:00
} else {
2022-08-31 14:02:40 +02:00
theme_cache . selected - > draw ( ci , row_rect ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
}
2020-02-03 23:10:24 +01:00
if ( ( select_mode = = SELECT_ROW & & selected_item = = p_item ) | | p_item - > cells [ i ] . selected | | ! p_item - > has_meta ( " __focus_rect " ) ) {
2021-09-25 11:01:45 +02:00
Rect2i r = cell_rect ;
2019-08-11 15:54:55 +02:00
2022-07-26 03:58:49 +02:00
if ( select_mode ! = SELECT_ROW ) {
2024-03-28 16:15:38 +01:00
p_item - > set_meta ( " __focus_rect " , Rect2 ( r . position , r . size ) ) ;
2022-07-26 03:58:49 +02:00
if ( rtl ) {
r . position . x = get_size ( ) . width - r . position . x - r . size . x ;
}
if ( p_item - > cells [ i ] . selected ) {
if ( has_focus ( ) ) {
2022-08-31 14:02:40 +02:00
theme_cache . selected_focus - > draw ( ci , r ) ;
2022-07-26 03:58:49 +02:00
} else {
2022-08-31 14:02:40 +02:00
theme_cache . selected - > draw ( ci , r ) ;
2022-07-26 03:58:49 +02:00
}
2019-08-11 15:54:55 +02:00
}
2024-03-28 16:15:38 +01:00
} else {
p_item - > set_meta ( " __focus_col_ " + itos ( i ) , Rect2 ( r . position , r . size ) ) ;
2016-08-20 18:00:25 +02:00
}
2014-02-10 02:10:30 +01:00
}
if ( p_item - > cells [ i ] . custom_bg_color ) {
2015-11-14 00:56:44 +01:00
Rect2 r = cell_rect ;
2017-06-26 02:12:36 +02:00
if ( i = = 0 ) {
r . position . x = p_draw_ofs . x ;
2023-01-14 21:32:48 +01:00
r . size . x = item_width + ofs ;
2017-06-26 02:12:36 +02:00
} else {
2022-11-30 16:06:14 +01:00
r . position . x - = theme_cache . h_separation ;
r . size . x + = theme_cache . h_separation ;
2017-06-26 02:12:36 +02:00
}
2020-09-03 13:22:16 +02:00
if ( rtl ) {
r . position . x = get_size ( ) . width - r . position . x - r . size . x ;
}
2016-05-11 16:46:08 +02:00
if ( p_item - > cells [ i ] . custom_bg_outline ) {
2020-03-27 19:21:27 +01:00
RenderingServer : : get_singleton ( ) - > canvas_item_add_rect ( ci , Rect2 ( r . position . x , r . position . y , r . size . x , 1 ) , p_item - > cells [ i ] . bg_color ) ;
RenderingServer : : get_singleton ( ) - > canvas_item_add_rect ( ci , Rect2 ( r . position . x , r . position . y + r . size . y - 1 , r . size . x , 1 ) , p_item - > cells [ i ] . bg_color ) ;
RenderingServer : : get_singleton ( ) - > canvas_item_add_rect ( ci , Rect2 ( r . position . x , r . position . y , 1 , r . size . y ) , p_item - > cells [ i ] . bg_color ) ;
RenderingServer : : get_singleton ( ) - > canvas_item_add_rect ( ci , Rect2 ( r . position . x + r . size . x - 1 , r . position . y , 1 , r . size . y ) , p_item - > cells [ i ] . bg_color ) ;
2016-05-11 16:46:08 +02:00
} else {
2020-03-27 19:21:27 +01:00
RenderingServer : : get_singleton ( ) - > canvas_item_add_rect ( ci , r , p_item - > cells [ i ] . bg_color ) ;
2016-05-11 16:46:08 +02:00
}
}
2021-08-25 12:03:16 +02:00
if ( drop_mode_flags & & drop_mode_over ) {
2016-05-11 16:46:08 +02:00
Rect2 r = cell_rect ;
2020-09-03 13:22:16 +02:00
if ( rtl ) {
r . position . x = get_size ( ) . width - r . position . x - r . size . x ;
}
2021-08-25 12:03:16 +02:00
if ( drop_mode_over = = p_item ) {
if ( drop_mode_section = = 0 | | drop_mode_section = = - 1 ) {
// Line above.
2022-08-31 14:02:40 +02:00
RenderingServer : : get_singleton ( ) - > canvas_item_add_rect ( ci , Rect2 ( r . position . x , r . position . y , r . size . x , 1 ) , theme_cache . drop_position_color ) ;
2021-08-25 12:03:16 +02:00
}
if ( drop_mode_section = = 0 ) {
// Side lines.
2022-08-31 14:02:40 +02:00
RenderingServer : : get_singleton ( ) - > canvas_item_add_rect ( ci , Rect2 ( r . position . x , r . position . y , 1 , r . size . y ) , theme_cache . drop_position_color ) ;
RenderingServer : : get_singleton ( ) - > canvas_item_add_rect ( ci , Rect2 ( r . position . x + r . size . x - 1 , r . position . y , 1 , r . size . y ) , theme_cache . drop_position_color ) ;
2021-08-25 12:03:16 +02:00
}
if ( drop_mode_section = = 0 | | ( drop_mode_section = = 1 & & ( ! p_item - > get_first_child ( ) | | p_item - > is_collapsed ( ) ) ) ) {
// Line below.
2022-08-31 14:02:40 +02:00
RenderingServer : : get_singleton ( ) - > canvas_item_add_rect ( ci , Rect2 ( r . position . x , r . position . y + r . size . y , r . size . x , 1 ) , theme_cache . drop_position_color ) ;
2021-08-25 12:03:16 +02:00
}
} else if ( drop_mode_over = = p_item - > get_parent ( ) ) {
if ( drop_mode_section = = 1 & & ! p_item - > get_prev ( ) /* && !drop_mode_over->is_collapsed() */ ) { // The drop_mode_over shouldn't ever be collapsed in here, otherwise we would be drawing a child of a collapsed item.
// Line above.
2022-08-31 14:02:40 +02:00
RenderingServer : : get_singleton ( ) - > canvas_item_add_rect ( ci , Rect2 ( r . position . x , r . position . y , r . size . x , 1 ) , theme_cache . drop_position_color ) ;
2021-08-25 12:03:16 +02:00
}
2016-05-11 16:46:08 +02:00
}
2014-02-10 02:10:30 +01:00
}
2023-01-14 21:32:48 +01:00
Color cell_color ;
2022-08-31 14:02:40 +02:00
if ( p_item - > cells [ i ] . custom_color ) {
2023-01-14 21:32:48 +01:00
cell_color = p_item - > cells [ i ] . color ;
2022-08-31 14:02:40 +02:00
} else {
2023-01-14 21:32:48 +01:00
cell_color = p_item - > cells [ i ] . selected ? theme_cache . font_selected_color : theme_cache . font_color ;
2022-08-31 14:02:40 +02:00
}
Color font_outline_color = theme_cache . font_outline_color ;
int outline_size = theme_cache . font_outline_size ;
2017-07-19 22:00:46 +02:00
Color icon_col = p_item - > cells [ i ] . icon_color ;
2015-08-31 00:37:23 +02:00
2020-09-03 13:22:16 +02:00
if ( p_item - > cells [ i ] . dirty ) {
const_cast < Tree * > ( this ) - > update_item_cell ( p_item , i ) ;
}
if ( rtl ) {
item_rect . position . x = get_size ( ) . width - item_rect . position . x - item_rect . size . x ;
}
2017-06-04 00:25:13 +02:00
Point2i text_pos = item_rect . position ;
2023-04-25 17:43:26 +02:00
text_pos . y + = Math : : floor ( p_draw_ofs . y ) - _get_title_button_height ( ) ;
2014-02-10 02:10:30 +01:00
switch ( p_item - > cells [ i ] . mode ) {
case TreeItem : : CELL_MODE_STRING : {
2023-04-28 09:45:29 +02:00
draw_item_rect ( p_item - > cells . write [ i ] , item_rect , cell_color , icon_col , outline_size , font_outline_color ) ;
2014-02-10 02:10:30 +01:00
} break ;
case TreeItem : : CELL_MODE_CHECK : {
2017-06-04 00:25:13 +02:00
Point2i check_ofs = item_rect . position ;
2023-11-13 14:38:56 +01:00
check_ofs . y + = Math : : floor ( ( real_t ) ( item_rect . size . y - theme_cache . checked - > get_height ( ) ) / 2 ) ;
2014-02-10 02:10:30 +01:00
2023-11-13 14:38:56 +01:00
if ( p_item - > cells [ i ] . editable ) {
if ( p_item - > cells [ i ] . indeterminate ) {
theme_cache . indeterminate - > draw ( ci , check_ofs ) ;
} else if ( p_item - > cells [ i ] . checked ) {
theme_cache . checked - > draw ( ci , check_ofs ) ;
} else {
theme_cache . unchecked - > draw ( ci , check_ofs ) ;
}
2014-02-10 02:10:30 +01:00
} else {
2023-11-13 14:38:56 +01:00
if ( p_item - > cells [ i ] . indeterminate ) {
theme_cache . indeterminate_disabled - > draw ( ci , check_ofs ) ;
} else if ( p_item - > cells [ i ] . checked ) {
theme_cache . checked_disabled - > draw ( ci , check_ofs ) ;
} else {
theme_cache . unchecked_disabled - > draw ( ci , check_ofs ) ;
}
2014-02-10 02:10:30 +01:00
}
2023-11-13 14:38:56 +01:00
int check_w = theme_cache . checked - > get_width ( ) + theme_cache . h_separation ;
2014-02-10 02:10:30 +01:00
text_pos . x + = check_w ;
item_rect . size . x - = check_w ;
2017-06-04 00:25:13 +02:00
item_rect . position . x + = check_w ;
2014-02-10 02:10:30 +01:00
2023-11-13 14:38:56 +01:00
if ( ! p_item - > cells [ i ] . editable ) {
cell_color = theme_cache . font_disabled_color ;
}
2023-04-28 09:45:29 +02:00
draw_item_rect ( p_item - > cells . write [ i ] , item_rect , cell_color , icon_col , outline_size , font_outline_color ) ;
2014-02-10 02:10:30 +01:00
} break ;
2018-09-22 22:31:56 +02:00
case TreeItem : : CELL_MODE_RANGE : {
2021-12-09 10:42:46 +01:00
if ( ! p_item - > cells [ i ] . text . is_empty ( ) ) {
2020-05-14 16:41:43 +02:00
if ( ! p_item - > cells [ i ] . editable ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2022-08-31 14:02:40 +02:00
Ref < Texture2D > downarrow = theme_cache . select_arrow ;
2020-09-03 13:22:16 +02:00
int cell_width = item_rect . size . x - downarrow - > get_width ( ) ;
2014-02-10 02:10:30 +01:00
2020-09-03 13:22:16 +02:00
if ( rtl ) {
2020-12-25 22:45:28 +01:00
if ( outline_size > 0 & & font_outline_color . a > 0 ) {
p_item - > cells [ i ] . text_buf - > draw_outline ( ci , text_pos + Vector2 ( cell_width - text_width , 0 ) , outline_size , font_outline_color ) ;
}
2023-01-14 21:32:48 +01:00
p_item - > cells [ i ] . text_buf - > draw ( ci , text_pos + Vector2 ( cell_width - text_width , 0 ) , cell_color ) ;
2020-09-03 13:22:16 +02:00
} else {
2020-12-25 22:45:28 +01:00
if ( outline_size > 0 & & font_outline_color . a > 0 ) {
p_item - > cells [ i ] . text_buf - > draw_outline ( ci , text_pos , outline_size , font_outline_color ) ;
}
2023-01-14 21:32:48 +01:00
p_item - > cells [ i ] . text_buf - > draw ( ci , text_pos , cell_color ) ;
2020-09-03 13:22:16 +02:00
}
2014-02-10 02:10:30 +01:00
2017-06-04 00:25:13 +02:00
Point2i arrow_pos = item_rect . position ;
2014-02-10 02:10:30 +01:00
arrow_pos . x + = item_rect . size . x - downarrow - > get_width ( ) ;
arrow_pos . y + = Math : : floor ( ( ( item_rect . size . y - downarrow - > get_height ( ) ) ) / 2.0 ) ;
2019-08-24 17:13:48 +02:00
downarrow - > draw ( ci , arrow_pos ) ;
2014-02-10 02:10:30 +01:00
} else {
2022-08-31 14:02:40 +02:00
Ref < Texture2D > updown = theme_cache . updown ;
2015-08-31 00:37:23 +02:00
2020-09-03 13:22:16 +02:00
int cell_width = item_rect . size . x - updown - > get_width ( ) ;
2016-08-31 04:44:14 +02:00
2020-09-03 13:22:16 +02:00
if ( rtl ) {
2020-12-25 22:45:28 +01:00
if ( outline_size > 0 & & font_outline_color . a > 0 ) {
p_item - > cells [ i ] . text_buf - > draw_outline ( ci , text_pos + Vector2 ( cell_width - text_width , 0 ) , outline_size , font_outline_color ) ;
}
2023-01-14 21:32:48 +01:00
p_item - > cells [ i ] . text_buf - > draw ( ci , text_pos + Vector2 ( cell_width - text_width , 0 ) , cell_color ) ;
2020-09-03 13:22:16 +02:00
} else {
2020-12-25 22:45:28 +01:00
if ( outline_size > 0 & & font_outline_color . a > 0 ) {
p_item - > cells [ i ] . text_buf - > draw_outline ( ci , text_pos , outline_size , font_outline_color ) ;
}
2023-01-14 21:32:48 +01:00
p_item - > cells [ i ] . text_buf - > draw ( ci , text_pos , cell_color ) ;
2020-05-14 16:41:43 +02:00
}
2016-08-31 04:44:14 +02:00
2020-05-14 16:41:43 +02:00
if ( ! p_item - > cells [ i ] . editable ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2017-06-04 00:25:13 +02:00
Point2i updown_pos = item_rect . position ;
2014-02-10 02:10:30 +01:00
updown_pos . x + = item_rect . size . x - updown - > get_width ( ) ;
updown_pos . y + = Math : : floor ( ( ( item_rect . size . y - updown - > get_height ( ) ) ) / 2.0 ) ;
2019-08-24 17:13:48 +02:00
updown - > draw ( ci , updown_pos ) ;
2014-02-10 02:10:30 +01:00
}
} break ;
case TreeItem : : CELL_MODE_ICON : {
2020-05-14 16:41:43 +02:00
if ( p_item - > cells [ i ] . icon . is_null ( ) ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2023-03-31 21:17:59 +02:00
Size2i icon_size = _get_cell_icon_size ( p_item - > cells [ i ] ) ;
2014-02-10 02:10:30 +01:00
Point2i icon_ofs = ( item_rect . size - icon_size ) / 2 ;
2017-06-04 00:25:13 +02:00
icon_ofs + = item_rect . position ;
2014-02-10 02:10:30 +01:00
2017-07-19 22:00:46 +02:00
draw_texture_rect ( p_item - > cells [ i ] . icon , Rect2 ( icon_ofs , icon_size ) , false , icon_col ) ;
2014-02-10 02:10:30 +01:00
} break ;
case TreeItem : : CELL_MODE_CUSTOM : {
2024-01-20 17:55:34 +01:00
if ( p_item - > cells [ i ] . custom_draw_callback . is_valid ( ) ) {
Variant args [ ] = { p_item , Rect2 ( item_rect ) } ;
const Variant * argptrs [ ] = { & args [ 0 ] , & args [ 1 ] } ;
Callable : : CallError ce ;
Variant ret ;
p_item - > cells [ i ] . custom_draw_callback . callp ( argptrs , 2 , ret , ce ) ;
if ( ce . error ! = Callable : : CallError : : CALL_OK ) {
ERR_PRINT ( " Error calling custom draw method: " + Variant : : get_callable_error_text ( p_item - > cells [ i ] . custom_draw_callback , argptrs , 2 , ce ) + " . " ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
if ( ! p_item - > cells [ i ] . editable ) {
2023-04-28 09:45:29 +02:00
draw_item_rect ( p_item - > cells . write [ i ] , item_rect , cell_color , icon_col , outline_size , font_outline_color ) ;
2014-02-10 02:10:30 +01:00
break ;
}
2022-08-31 14:02:40 +02:00
Ref < Texture2D > downarrow = theme_cache . select_arrow ;
2014-02-10 02:10:30 +01:00
Rect2i ir = item_rect ;
2015-08-31 00:37:23 +02:00
2017-06-04 00:25:13 +02:00
Point2i arrow_pos = item_rect . position ;
2014-02-10 02:10:30 +01:00
arrow_pos . x + = item_rect . size . x - downarrow - > get_width ( ) ;
arrow_pos . y + = Math : : floor ( ( ( item_rect . size . y - downarrow - > get_height ( ) ) ) / 2.0 ) ;
2017-06-05 01:35:08 +02:00
ir . size . width - = downarrow - > get_width ( ) ;
if ( p_item - > cells [ i ] . custom_button ) {
if ( cache . hover_item = = p_item & & cache . hover_cell = = i ) {
2021-08-13 23:31:57 +02:00
if ( Input : : get_singleton ( ) - > is_mouse_button_pressed ( MouseButton : : LEFT ) ) {
2022-08-31 14:02:40 +02:00
draw_style_box ( theme_cache . custom_button_pressed , ir ) ;
2017-06-05 01:35:08 +02:00
} else {
2022-08-31 14:02:40 +02:00
draw_style_box ( theme_cache . custom_button_hover , ir ) ;
2023-01-14 21:32:48 +01:00
cell_color = theme_cache . custom_button_font_highlight ;
2017-06-05 01:35:08 +02:00
}
} else {
2022-08-31 14:02:40 +02:00
draw_style_box ( theme_cache . custom_button , ir ) ;
2017-06-05 01:35:08 +02:00
}
2022-08-31 14:02:40 +02:00
ir . size - = theme_cache . custom_button - > get_minimum_size ( ) ;
ir . position + = theme_cache . custom_button - > get_offset ( ) ;
2017-06-05 01:35:08 +02:00
}
2023-04-28 09:45:29 +02:00
draw_item_rect ( p_item - > cells . write [ i ] , ir , cell_color , icon_col , outline_size , font_outline_color ) ;
2014-02-10 02:10:30 +01:00
downarrow - > draw ( ci , arrow_pos ) ;
} break ;
}
2023-01-14 21:32:48 +01:00
for ( int j = p_item - > cells [ i ] . buttons . size ( ) - 1 ; j > = 0 ; j - - ) {
Ref < Texture2D > button_texture = p_item - > cells [ i ] . buttons [ j ] . texture ;
Size2 button_size = button_texture - > get_size ( ) + theme_cache . button_pressed - > get_minimum_size ( ) ;
Point2i button_ofs = Point2i ( ofs + item_width_with_buttons - button_size . width , p_pos . y ) - theme_cache . offset + p_draw_ofs ;
if ( cache . click_type = = Cache : : CLICK_BUTTON & & cache . click_item = = p_item & & cache . click_column = = i & & cache . click_index = = j & & ! p_item - > cells [ i ] . buttons [ j ] . disabled ) {
// Being pressed.
Point2 od = button_ofs ;
if ( rtl ) {
od . x = get_size ( ) . width - od . x - button_size . x ;
}
theme_cache . button_pressed - > draw ( get_canvas_item ( ) , Rect2 ( od . x , od . y , button_size . width , MAX ( button_size . height , label_h ) ) ) ;
}
button_ofs . y + = ( label_h - button_size . height ) / 2 ;
button_ofs + = theme_cache . button_pressed - > get_offset ( ) ;
if ( rtl ) {
button_ofs . x = get_size ( ) . width - button_ofs . x - button_texture - > get_width ( ) ;
}
button_texture - > draw ( ci , button_ofs , p_item - > cells [ i ] . buttons [ j ] . disabled ? Color ( 1 , 1 , 1 , 0.5 ) : p_item - > cells [ i ] . buttons [ j ] . color ) ;
item_width_with_buttons - = button_size . width + theme_cache . button_margin ;
}
2014-02-10 02:10:30 +01:00
if ( i = = 0 ) {
ofs = get_column_width ( 0 ) ;
} else {
2023-01-14 21:32:48 +01:00
ofs + = item_width + buttons_width ;
2014-02-10 02:10:30 +01:00
}
if ( select_mode = = SELECT_MULTI & & selected_item = = p_item & & selected_col = = i ) {
2020-09-03 13:22:16 +02:00
if ( is_layout_rtl ( ) ) {
cell_rect . position . x = get_size ( ) . width - cell_rect . position . x - cell_rect . size . x ;
}
2020-05-14 16:41:43 +02:00
if ( has_focus ( ) ) {
2022-08-31 14:02:40 +02:00
theme_cache . cursor - > draw ( ci , cell_rect ) ;
2020-05-14 16:41:43 +02:00
} else {
2022-08-31 14:02:40 +02:00
theme_cache . cursor_unfocus - > draw ( ci , cell_rect ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
}
2022-04-03 10:37:08 +02:00
if ( ! p_item - > disable_folding & & ! hide_folding & & p_item - > first_child & & p_item - > get_visible_child_count ( ) ! = 0 ) { //has visible children, draw the guide box
2017-06-26 02:12:36 +02:00
2019-06-11 20:43:37 +02:00
Ref < Texture2D > arrow ;
2017-06-26 02:12:36 +02:00
if ( p_item - > collapsed ) {
2022-08-31 14:02:40 +02:00
if ( is_layout_rtl ( ) ) {
arrow = theme_cache . arrow_collapsed_mirrored ;
} else {
arrow = theme_cache . arrow_collapsed ;
}
2017-06-26 02:12:36 +02:00
} else {
2022-08-31 14:02:40 +02:00
arrow = theme_cache . arrow ;
2017-06-26 02:12:36 +02:00
}
2022-08-31 14:02:40 +02:00
Point2 apos = p_pos + Point2i ( 0 , ( label_h - arrow - > get_height ( ) ) / 2 ) - theme_cache . offset + p_draw_ofs ;
apos . x + = theme_cache . item_margin - arrow - > get_width ( ) ;
2020-09-03 13:22:16 +02:00
if ( rtl ) {
apos . x = get_size ( ) . width - apos . x - arrow - > get_width ( ) ;
}
arrow - > draw ( ci , apos ) ;
2017-06-26 02:12:36 +02:00
}
2014-02-10 02:10:30 +01:00
}
Point2 children_pos = p_pos ;
if ( ! skip ) {
2022-08-31 14:02:40 +02:00
children_pos . x + = theme_cache . item_margin ;
2014-02-10 02:10:30 +01:00
htotal + = label_h ;
children_pos . y + = htotal ;
}
2018-01-18 21:37:17 +01:00
if ( ! p_item - > collapsed ) { /* if not collapsed, check the children */
2021-03-07 21:07:30 +01:00
TreeItem * c = p_item - > first_child ;
2014-02-10 02:10:30 +01:00
2022-08-31 14:02:40 +02:00
int base_ofs = children_pos . y - theme_cache . offset . y + p_draw_ofs . y ;
2021-05-02 17:34:29 +02:00
int prev_ofs = base_ofs ;
int prev_hl_ofs = base_ofs ;
2019-03-06 16:10:36 +01:00
2014-02-10 02:10:30 +01:00
while ( c ) {
2022-04-10 00:14:24 +02:00
int child_h = - 1 ;
2023-04-28 09:45:29 +02:00
int child_self_height = 0 ;
2021-06-21 15:46:43 +02:00
if ( htotal > = 0 ) {
2023-07-11 10:58:19 +02:00
child_h = draw_item ( children_pos , p_draw_ofs , p_draw_size , c , child_self_height ) ;
2023-04-28 09:45:29 +02:00
child_self_height + = theme_cache . v_separation ;
2022-04-10 00:14:24 +02:00
}
2019-03-06 16:10:36 +01:00
2022-04-10 00:14:24 +02:00
// Draw relationship lines.
2024-02-13 22:27:15 +01:00
if ( theme_cache . draw_relationship_lines > 0 & & ( ! hide_root | | c - > parent ! = root ) & & c - > is_visible_in_tree ( ) ) {
2022-11-30 16:06:14 +01:00
int root_ofs = children_pos . x + ( ( p_item - > disable_folding | | hide_folding ) ? theme_cache . h_separation : theme_cache . item_margin ) ;
2022-08-31 14:02:40 +02:00
int parent_ofs = p_pos . x + theme_cache . item_margin ;
2023-04-28 09:45:29 +02:00
Point2i root_pos = Point2i ( root_ofs , children_pos . y + child_self_height / 2 ) - theme_cache . offset + p_draw_ofs ;
2016-06-15 19:10:19 +02:00
2022-05-31 16:23:33 +02:00
if ( c - > get_visible_child_count ( ) > 0 ) {
2022-08-31 14:02:40 +02:00
root_pos - = Point2i ( theme_cache . arrow - > get_width ( ) , 0 ) ;
2022-04-10 00:14:24 +02:00
}
2021-06-21 15:46:43 +02:00
2022-08-31 14:02:40 +02:00
float line_width = theme_cache . relationship_line_width * Math : : round ( theme_cache . base_scale ) ;
float parent_line_width = theme_cache . parent_hl_line_width * Math : : round ( theme_cache . base_scale ) ;
float children_line_width = theme_cache . children_hl_line_width * Math : : round ( theme_cache . base_scale ) ;
2017-12-15 18:40:45 +01:00
2022-08-31 14:02:40 +02:00
Point2i parent_pos = Point2i ( parent_ofs - theme_cache . arrow - > get_width ( ) / 2 , p_pos . y + label_h / 2 + theme_cache . arrow - > get_height ( ) / 2 ) - theme_cache . offset + p_draw_ofs ;
2018-01-04 10:03:46 +01:00
2022-04-10 00:14:24 +02:00
int more_prev_ofs = 0 ;
2021-05-02 17:34:29 +02:00
2022-04-10 00:14:24 +02:00
if ( root_pos . y + line_width > = 0 ) {
if ( rtl ) {
root_pos . x = get_size ( ) . width - root_pos . x ;
parent_pos . x = get_size ( ) . width - parent_pos . x ;
}
2021-05-02 17:34:29 +02:00
2022-04-10 00:14:24 +02:00
// Order of parts on this bend: the horizontal line first, then the vertical line.
if ( _is_branch_selected ( c ) ) {
// If this item or one of its children is selected, we draw the line using parent highlight style.
if ( htotal > = 0 ) {
2022-08-31 14:02:40 +02:00
RenderingServer : : get_singleton ( ) - > canvas_item_add_line ( ci , root_pos , Point2i ( parent_pos . x + Math : : floor ( parent_line_width / 2 ) , root_pos . y ) , theme_cache . parent_hl_line_color , parent_line_width ) ;
2022-04-10 00:14:24 +02:00
}
2022-08-31 14:02:40 +02:00
RenderingServer : : get_singleton ( ) - > canvas_item_add_line ( ci , Point2i ( parent_pos . x , root_pos . y + Math : : floor ( parent_line_width / 2 ) ) , Point2i ( parent_pos . x , prev_hl_ofs ) , theme_cache . parent_hl_line_color , parent_line_width ) ;
2022-04-10 00:14:24 +02:00
2022-08-31 14:02:40 +02:00
more_prev_ofs = theme_cache . parent_hl_line_margin ;
2022-04-10 00:14:24 +02:00
prev_hl_ofs = root_pos . y + Math : : floor ( parent_line_width / 2 ) ;
} else if ( p_item - > is_selected ( 0 ) ) {
// If parent item is selected (but this item is not), we draw the line using children highlight style.
// Siblings of the selected branch can be drawn with a slight offset and their vertical line must appear as highlighted.
if ( _is_sibling_branch_selected ( c ) ) {
if ( htotal > = 0 ) {
2022-08-31 14:02:40 +02:00
RenderingServer : : get_singleton ( ) - > canvas_item_add_line ( ci , root_pos , Point2i ( parent_pos . x + Math : : floor ( parent_line_width / 2 ) , root_pos . y ) , theme_cache . children_hl_line_color , children_line_width ) ;
2022-04-10 00:14:24 +02:00
}
2022-08-31 14:02:40 +02:00
RenderingServer : : get_singleton ( ) - > canvas_item_add_line ( ci , Point2i ( parent_pos . x , root_pos . y + Math : : floor ( parent_line_width / 2 ) ) , Point2i ( parent_pos . x , prev_hl_ofs ) , theme_cache . parent_hl_line_color , parent_line_width ) ;
2021-05-25 23:44:04 +02:00
prev_hl_ofs = root_pos . y + Math : : floor ( parent_line_width / 2 ) ;
2022-04-10 00:14:24 +02:00
} else {
if ( htotal > = 0 ) {
2022-08-31 14:02:40 +02:00
RenderingServer : : get_singleton ( ) - > canvas_item_add_line ( ci , root_pos , Point2i ( parent_pos . x + Math : : floor ( children_line_width / 2 ) , root_pos . y ) , theme_cache . children_hl_line_color , children_line_width ) ;
2021-06-21 15:46:43 +02:00
}
2022-08-31 14:02:40 +02:00
RenderingServer : : get_singleton ( ) - > canvas_item_add_line ( ci , Point2i ( parent_pos . x , root_pos . y + Math : : floor ( children_line_width / 2 ) ) , Point2i ( parent_pos . x , prev_ofs + Math : : floor ( children_line_width / 2 ) ) , theme_cache . children_hl_line_color , children_line_width ) ;
2022-04-10 00:14:24 +02:00
}
} else {
// If nothing of the above is true, we draw the line using normal style.
// Siblings of the selected branch can be drawn with a slight offset and their vertical line must appear as highlighted.
if ( _is_sibling_branch_selected ( c ) ) {
if ( htotal > = 0 ) {
2022-08-31 14:02:40 +02:00
RenderingServer : : get_singleton ( ) - > canvas_item_add_line ( ci , root_pos , Point2i ( parent_pos . x + theme_cache . parent_hl_line_margin , root_pos . y ) , theme_cache . relationship_line_color , line_width ) ;
2022-04-10 00:14:24 +02:00
}
2022-08-31 14:02:40 +02:00
RenderingServer : : get_singleton ( ) - > canvas_item_add_line ( ci , Point2i ( parent_pos . x , root_pos . y + Math : : floor ( parent_line_width / 2 ) ) , Point2i ( parent_pos . x , prev_hl_ofs ) , theme_cache . parent_hl_line_color , parent_line_width ) ;
2021-05-25 23:44:04 +02:00
2022-04-10 00:14:24 +02:00
prev_hl_ofs = root_pos . y + Math : : floor ( parent_line_width / 2 ) ;
} else {
if ( htotal > = 0 ) {
2022-08-31 14:02:40 +02:00
RenderingServer : : get_singleton ( ) - > canvas_item_add_line ( ci , root_pos , Point2i ( parent_pos . x + Math : : floor ( line_width / 2 ) , root_pos . y ) , theme_cache . relationship_line_color , line_width ) ;
2021-06-21 15:46:43 +02:00
}
2022-08-31 14:02:40 +02:00
RenderingServer : : get_singleton ( ) - > canvas_item_add_line ( ci , Point2i ( parent_pos . x , root_pos . y + Math : : floor ( line_width / 2 ) ) , Point2i ( parent_pos . x , prev_ofs + Math : : floor ( line_width / 2 ) ) , theme_cache . relationship_line_color , line_width ) ;
2021-05-02 17:34:29 +02:00
}
}
2018-01-04 10:03:46 +01:00
}
2014-02-10 02:10:30 +01:00
2022-04-10 00:14:24 +02:00
prev_ofs = root_pos . y + more_prev_ofs ;
}
2021-05-02 17:34:29 +02:00
2022-04-10 00:14:24 +02:00
if ( child_h < 0 ) {
if ( htotal = = - 1 ) {
break ; // Last loop done, stop.
2018-01-04 10:03:46 +01:00
}
2022-04-10 00:14:24 +02:00
2022-08-31 14:02:40 +02:00
if ( theme_cache . draw_relationship_lines = = 0 ) {
2022-04-10 00:14:24 +02:00
return - 1 ; // No need to draw anymore, full stop.
}
htotal = - 1 ;
2022-08-31 14:02:40 +02:00
children_pos . y = theme_cache . offset . y + p_draw_size . height ;
2022-04-10 00:14:24 +02:00
} else {
htotal + = child_h ;
children_pos . y + = child_h ;
2018-01-04 10:03:46 +01:00
}
2014-02-10 02:10:30 +01:00
c = c - > next ;
}
}
return htotal ;
}
2016-05-11 16:46:08 +02:00
int Tree : : _count_selected_items ( TreeItem * p_from ) const {
int count = 0 ;
for ( int i = 0 ; i < columns . size ( ) ; i + + ) {
2020-05-14 16:41:43 +02:00
if ( p_from - > is_selected ( i ) ) {
2016-05-11 16:46:08 +02:00
count + + ;
2020-05-14 16:41:43 +02:00
}
2016-05-11 16:46:08 +02:00
}
2024-02-04 14:21:03 +01:00
for ( TreeItem * c = p_from - > get_first_child ( ) ; c ; c = c - > get_next ( ) ) {
count + = _count_selected_items ( c ) ;
2016-05-11 16:46:08 +02:00
}
return count ;
}
2020-05-14 14:29:06 +02:00
2021-05-02 17:34:29 +02:00
bool Tree : : _is_branch_selected ( TreeItem * p_from ) const {
for ( int i = 0 ; i < columns . size ( ) ; i + + ) {
if ( p_from - > is_selected ( i ) ) {
return true ;
}
}
TreeItem * child_item = p_from - > get_first_child ( ) ;
while ( child_item ) {
if ( _is_branch_selected ( child_item ) ) {
return true ;
}
child_item = child_item - > get_next ( ) ;
}
return false ;
}
bool Tree : : _is_sibling_branch_selected ( TreeItem * p_from ) const {
TreeItem * sibling_item = p_from - > get_next ( ) ;
while ( sibling_item ) {
if ( _is_branch_selected ( sibling_item ) ) {
return true ;
}
sibling_item = sibling_item - > get_next ( ) ;
}
return false ;
}
2016-07-09 18:14:46 +02:00
void Tree : : select_single_item ( TreeItem * p_selected , TreeItem * p_current , int p_col , TreeItem * p_prev , bool * r_in_range , bool p_force_deselect ) {
2022-11-16 09:25:36 +01:00
popup_editor - > hide ( ) ;
2018-07-25 03:11:03 +02:00
TreeItem : : Cell & selected_cell = p_selected - > cells . write [ p_col ] ;
2014-02-10 02:10:30 +01:00
bool switched = false ;
if ( r_in_range & & ! * r_in_range & & ( p_current = = p_selected | | p_current = = p_prev ) ) {
* r_in_range = true ;
switched = true ;
}
2016-06-30 22:51:45 +02:00
bool emitted_row = false ;
2014-02-10 02:10:30 +01:00
for ( int i = 0 ; i < columns . size ( ) ; i + + ) {
2018-07-25 03:11:03 +02:00
TreeItem : : Cell & c = p_current - > cells . write [ i ] ;
2014-02-10 02:10:30 +01:00
2020-05-14 16:41:43 +02:00
if ( ! c . selectable ) {
2014-02-10 02:10:30 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
if ( select_mode = = SELECT_ROW ) {
2017-08-18 23:19:12 +02:00
if ( p_selected = = p_current & & ( ! c . selected | | allow_reselect ) ) {
2014-02-10 02:10:30 +01:00
c . selected = true ;
selected_item = p_selected ;
2016-06-30 22:51:45 +02:00
if ( ! emitted_row ) {
2024-05-14 14:21:31 +02:00
emit_signal ( SceneStringName ( item_selected ) ) ;
2016-06-30 22:51:45 +02:00
emitted_row = true ;
}
2016-12-20 22:47:24 +01:00
} else if ( c . selected ) {
2022-01-01 21:36:18 +01:00
if ( p_selected ! = p_current ) {
// Deselect other rows.
c . selected = false ;
}
2014-02-10 02:10:30 +01:00
}
2024-03-28 16:15:38 +01:00
if ( & selected_cell = = & c ) {
selected_col = i ;
}
2014-02-10 02:10:30 +01:00
} else if ( select_mode = = SELECT_SINGLE | | select_mode = = SELECT_MULTI ) {
2015-08-30 04:46:32 +02:00
if ( ! r_in_range & & & selected_cell = = & c ) {
2017-08-18 23:19:12 +02:00
if ( ! selected_cell . selected | | allow_reselect ) {
2014-02-10 02:10:30 +01:00
selected_cell . selected = true ;
2015-08-31 00:37:23 +02:00
2014-02-10 02:10:30 +01:00
selected_item = p_selected ;
selected_col = i ;
2015-08-30 04:46:32 +02:00
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " cell_selected " ) ) ;
2020-05-14 16:41:43 +02:00
if ( select_mode = = SELECT_MULTI ) {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " multi_selected " ) , p_current , i , true ) ;
2020-05-14 16:41:43 +02:00
} else if ( select_mode = = SELECT_SINGLE ) {
2024-05-14 14:21:31 +02:00
emit_signal ( SceneStringName ( item_selected ) ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
} else if ( select_mode = = SELECT_MULTI & & ( selected_item ! = p_selected | | selected_col ! = i ) ) {
selected_item = p_selected ;
selected_col = i ;
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " cell_selected " ) ) ;
2014-02-10 02:10:30 +01:00
}
} else {
2016-07-09 18:14:46 +02:00
if ( r_in_range & & * r_in_range & & ! p_force_deselect ) {
2014-02-10 02:10:30 +01:00
if ( ! c . selected & & c . selectable ) {
c . selected = true ;
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " multi_selected " ) , p_current , i , true ) ;
2014-02-10 02:10:30 +01:00
}
2016-07-09 18:14:46 +02:00
} else if ( ! r_in_range | | p_force_deselect ) {
2020-05-14 16:41:43 +02:00
if ( select_mode = = SELECT_MULTI & & c . selected ) {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " multi_selected " ) , p_current , i , false ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
c . selected = false ;
}
//p_current->deselected_signal.call(p_col);
}
}
}
if ( ! switched & & r_in_range & & * r_in_range & & ( p_current = = p_selected | | p_current = = p_prev ) ) {
* r_in_range = false ;
}
2021-03-07 21:07:30 +01:00
TreeItem * c = p_current - > first_child ;
2014-02-10 02:10:30 +01:00
while ( c ) {
2016-07-09 18:14:46 +02:00
select_single_item ( p_selected , c , p_col , p_prev , r_in_range , p_current - > is_collapsed ( ) | | p_force_deselect ) ;
2014-02-10 02:10:30 +01:00
c = c - > next ;
}
}
Rect2 Tree : : search_item_rect ( TreeItem * p_from , TreeItem * p_item ) {
return Rect2 ( ) ;
}
2015-12-08 19:04:56 +01:00
void Tree : : _range_click_timeout ( ) {
2021-08-13 23:31:57 +02:00
if ( range_item_last & & ! range_drag_enabled & & Input : : get_singleton ( ) - > is_mouse_button_pressed ( MouseButton : : LEFT ) ) {
2022-09-06 19:09:32 +02:00
Point2 pos = get_local_mouse_position ( ) - theme_cache . panel_style - > get_offset ( ) ;
2015-12-08 19:04:56 +01:00
if ( show_column_titles ) {
pos . y - = _get_title_button_height ( ) ;
if ( pos . y < 0 ) {
range_click_timer - > stop ( ) ;
return ;
}
}
2021-06-24 07:54:00 +02:00
if ( ! root ) {
return ;
}
2015-12-08 19:04:56 +01:00
click_handled = false ;
2017-05-20 17:38:03 +02:00
Ref < InputEventMouseButton > mb ;
2021-06-18 00:03:09 +02:00
mb . instantiate ( ) ;
2015-12-08 19:04:56 +01:00
2022-09-06 19:09:32 +02:00
int x_limit = get_size ( ) . width - theme_cache . panel_style - > get_minimum_size ( ) . width ;
2022-12-31 06:50:20 +01:00
if ( v_scroll - > is_visible ( ) ) {
x_limit - = v_scroll - > get_minimum_size ( ) . width ;
2021-07-04 05:13:28 +02:00
}
cache . rtl = is_layout_rtl ( ) ;
2019-02-13 09:23:29 +01:00
propagate_mouse_activated = false ; // done from outside, so signal handler can't clear the tree in the middle of emit (which is a common case)
2015-12-08 19:04:56 +01:00
blocked + + ;
2022-08-31 14:02:40 +02:00
propagate_mouse_event ( pos + theme_cache . offset , 0 , 0 , x_limit + theme_cache . offset . width , false , root , MouseButton : : LEFT , mb ) ;
2015-12-08 19:04:56 +01:00
blocked - - ;
if ( range_click_timer - > is_one_shot ( ) ) {
range_click_timer - > set_wait_time ( 0.05 ) ;
range_click_timer - > set_one_shot ( false ) ;
range_click_timer - > start ( ) ;
}
2020-05-14 16:41:43 +02:00
if ( ! click_handled ) {
2015-12-08 19:04:56 +01:00
range_click_timer - > stop ( ) ;
2020-05-14 16:41:43 +02:00
}
2015-12-08 19:04:56 +01:00
2019-01-14 21:20:33 +01:00
if ( propagate_mouse_activated ) {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " item_activated " ) ) ;
2019-01-14 21:20:33 +01:00
propagate_mouse_activated = false ;
}
2015-12-08 19:04:56 +01:00
} else {
range_click_timer - > stop ( ) ;
}
}
2014-02-10 02:10:30 +01:00
2021-08-13 23:31:57 +02:00
int Tree : : propagate_mouse_event ( const Point2i & p_pos , int x_ofs , int y_ofs , int x_limit , bool p_double_click , TreeItem * p_item , MouseButton p_button , const Ref < InputEventWithModifiers > & p_mod ) {
2024-02-13 22:27:15 +01:00
if ( p_item & & ! p_item - > is_visible_in_tree ( ) ) {
2022-04-03 10:37:08 +02:00
// Skip any processing of invisible items.
return 0 ;
}
2022-11-30 16:06:14 +01:00
int item_h = compute_item_height ( p_item ) + theme_cache . v_separation ;
2014-02-10 02:10:30 +01:00
bool skip = ( p_item = = root & & hide_root ) ;
if ( ! skip & & p_pos . y < item_h ) {
// check event!
2016-01-21 14:08:40 +01:00
if ( range_click_timer - > get_time_left ( ) > 0 & & p_item ! = range_item_last ) {
return - 1 ;
}
2024-05-08 11:30:26 +02:00
if ( ! p_item - > disable_folding & & ! hide_folding & & p_item - > first_child & & ( p_pos . x < ( x_ofs + theme_cache . item_margin ) ) ) {
2022-07-01 15:43:39 +02:00
if ( enable_recursive_folding & & p_mod - > is_shift_pressed ( ) ) {
p_item - > set_collapsed_recursive ( ! p_item - > is_collapsed ( ) ) ;
} else {
p_item - > set_collapsed ( ! p_item - > is_collapsed ( ) ) ;
}
2021-12-10 16:54:47 +01:00
return - 1 ;
2014-02-10 02:10:30 +01:00
}
2015-08-31 00:37:23 +02:00
2014-02-10 02:10:30 +01:00
int x = p_pos . x ;
/* find clicked column */
int col = - 1 ;
int col_ofs = 0 ;
int col_width = 0 ;
2021-07-04 05:13:28 +02:00
int limit_w = x_limit ;
2014-02-10 02:10:30 +01:00
for ( int i = 0 ; i < columns . size ( ) ; i + + ) {
col_width = get_column_width ( i ) ;
2017-06-25 22:30:28 +02:00
if ( p_item - > cells [ i ] . expand_right ) {
int plus = 1 ;
2021-12-09 10:42:46 +01:00
while ( i + plus < columns . size ( ) & & ! p_item - > cells [ i + plus ] . editable & & p_item - > cells [ i + plus ] . mode = = TreeItem : : CELL_MODE_STRING & & p_item - > cells [ i + plus ] . text . is_empty ( ) & & p_item - > cells [ i + plus ] . icon . is_null ( ) ) {
2022-11-30 16:06:14 +01:00
col_width + = theme_cache . h_separation ;
2017-06-25 22:30:28 +02:00
col_width + = get_column_width ( i + plus ) ;
plus + + ;
}
}
2014-02-10 02:10:30 +01:00
if ( x > col_width ) {
col_ofs + = col_width ;
x - = col_width ;
2021-07-04 05:13:28 +02:00
limit_w - = col_width ;
2014-02-10 02:10:30 +01:00
continue ;
}
col = i ;
break ;
}
2020-05-14 16:41:43 +02:00
if ( col = = - 1 ) {
2014-02-10 02:10:30 +01:00
return - 1 ;
2020-05-14 16:41:43 +02:00
} else if ( col = = 0 ) {
2022-11-30 16:06:14 +01:00
int margin = x_ofs + theme_cache . item_margin ; //-theme_cache.h_separation;
2022-09-06 19:09:32 +02:00
//int lm = theme_cache.panel_style->get_margin(SIDE_LEFT);
2014-02-10 02:10:30 +01:00
col_width - = margin ;
2021-07-04 05:13:28 +02:00
limit_w - = margin ;
2014-02-10 02:10:30 +01:00
col_ofs + = margin ;
x - = margin ;
} else {
2022-11-30 16:06:14 +01:00
col_width - = theme_cache . h_separation ;
limit_w - = theme_cache . h_separation ;
x - = theme_cache . h_separation ;
2014-02-10 02:10:30 +01:00
}
2018-07-25 03:11:03 +02:00
const TreeItem : : Cell & c = p_item - > cells [ col ] ;
2014-02-10 02:10:30 +01:00
2023-10-09 22:41:36 +02:00
if ( ! cache . rtl & & ! p_item - > cells [ col ] . buttons . is_empty ( ) ) {
2021-07-04 05:13:28 +02:00
int button_w = 0 ;
for ( int j = p_item - > cells [ col ] . buttons . size ( ) - 1 ; j > = 0 ; j - - ) {
Ref < Texture2D > b = p_item - > cells [ col ] . buttons [ j ] . texture ;
2022-08-31 14:02:40 +02:00
button_w + = b - > get_size ( ) . width + theme_cache . button_pressed - > get_minimum_size ( ) . width + theme_cache . button_margin ;
2021-07-04 05:13:28 +02:00
}
col_width = MAX ( button_w , MIN ( limit_w , col_width ) ) ;
}
2014-02-10 02:10:30 +01:00
for ( int j = c . buttons . size ( ) - 1 ; j > = 0 ; j - - ) {
2019-06-11 20:43:37 +02:00
Ref < Texture2D > b = c . buttons [ j ] . texture ;
2022-08-31 14:02:40 +02:00
int w = b - > get_size ( ) . width + theme_cache . button_pressed - > get_minimum_size ( ) . width ;
2016-02-03 00:44:42 +01:00
2014-02-10 02:10:30 +01:00
if ( x > col_width - w ) {
2016-02-03 00:44:42 +01:00
if ( c . buttons [ j ] . disabled ) {
pressed_button = - 1 ;
cache . click_type = Cache : : CLICK_NONE ;
return - 1 ;
}
2020-01-15 21:54:52 +01:00
// Make sure the click is correct.
Point2 click_pos = get_global_mouse_position ( ) - get_global_position ( ) ;
if ( ! get_item_at_position ( click_pos ) ) {
pressed_button = - 1 ;
cache . click_type = Cache : : CLICK_NONE ;
return - 1 ;
}
2014-02-10 02:10:30 +01:00
pressed_button = j ;
cache . click_type = Cache : : CLICK_BUTTON ;
cache . click_index = j ;
cache . click_id = c . buttons [ j ] . id ;
cache . click_item = p_item ;
cache . click_column = col ;
2020-01-15 21:54:52 +01:00
cache . click_pos = click_pos ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2014-02-10 02:10:30 +01:00
return - 1 ;
}
2021-07-04 05:13:28 +02:00
2022-08-31 14:02:40 +02:00
col_width - = w + theme_cache . button_margin ;
2014-02-10 02:10:30 +01:00
}
2023-10-09 22:41:36 +02:00
if ( ! p_item - > disable_folding & & ! hide_folding & & ! p_item - > cells [ col ] . editable & & ! p_item - > cells [ col ] . selectable & & p_item - > get_first_child ( ) ) {
if ( enable_recursive_folding & & p_mod - > is_shift_pressed ( ) ) {
p_item - > set_collapsed_recursive ( ! p_item - > is_collapsed ( ) ) ;
} else {
p_item - > set_collapsed ( ! p_item - > is_collapsed ( ) ) ;
}
return - 1 ; // Collapse/uncollapse, because nothing can be done with the item.
}
bool already_selected = c . selected ;
bool already_cursor = ( p_item = = selected_item ) & & col = = selected_col ;
2021-08-13 23:31:57 +02:00
if ( p_button = = MouseButton : : LEFT | | ( p_button = = MouseButton : : RIGHT & & allow_rmb_select ) ) {
2014-02-10 02:10:30 +01:00
/* process selection */
2021-04-13 10:25:44 +02:00
if ( p_double_click & & ( ! c . editable | | c . mode = = TreeItem : : CELL_MODE_CUSTOM | | c . mode = = TreeItem : : CELL_MODE_ICON /*|| c.mode==TreeItem::CELL_MODE_CHECK*/ ) ) { //it's confusing for check
2022-01-05 05:03:52 +01:00
// Emits the "item_activated" signal.
2019-01-14 21:20:33 +01:00
propagate_mouse_activated = true ;
2017-05-04 22:01:26 +02:00
incr_search . clear ( ) ;
2014-02-10 02:10:30 +01:00
return - 1 ;
}
2023-01-06 20:19:34 +01:00
if ( c . selectable ) {
if ( select_mode = = SELECT_MULTI & & p_mod - > is_command_or_control_pressed ( ) ) {
if ( c . selected & & p_button = = MouseButton : : LEFT ) {
p_item - > deselect ( col ) ;
emit_signal ( SNAME ( " multi_selected " ) , p_item , col , false ) ;
} else {
p_item - > select ( col ) ;
emit_signal ( SNAME ( " multi_selected " ) , p_item , col , true ) ;
emit_signal ( SNAME ( " item_mouse_selected " ) , get_local_mouse_position ( ) , p_button ) ;
}
2014-02-10 02:10:30 +01:00
} else {
2021-04-24 22:33:50 +02:00
if ( select_mode = = SELECT_MULTI & & p_mod - > is_shift_pressed ( ) & & selected_item & & selected_item ! = p_item ) {
2014-02-10 02:10:30 +01:00
bool inrange = false ;
2015-08-30 04:46:32 +02:00
2014-02-10 02:10:30 +01:00
select_single_item ( p_item , root , col , selected_item , & inrange ) ;
2021-09-18 09:33:18 +02:00
emit_signal ( SNAME ( " item_mouse_selected " ) , get_local_mouse_position ( ) , p_button ) ;
2014-02-10 02:10:30 +01:00
} else {
2016-05-11 16:46:08 +02:00
int icount = _count_selected_items ( root ) ;
2021-08-13 23:31:57 +02:00
if ( select_mode = = SELECT_MULTI & & icount > 1 & & p_button ! = MouseButton : : RIGHT ) {
2016-05-11 16:46:08 +02:00
single_select_defer = p_item ;
single_select_defer_column = col ;
} else {
2021-08-13 23:31:57 +02:00
if ( p_button ! = MouseButton : : RIGHT | | ! c . selected ) {
2016-05-16 04:41:48 +02:00
select_single_item ( p_item , root , col ) ;
}
2021-09-18 09:33:18 +02:00
emit_signal ( SNAME ( " item_mouse_selected " ) , get_local_mouse_position ( ) , p_button ) ;
2016-05-11 16:46:08 +02:00
}
2014-02-10 02:10:30 +01:00
}
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2014-02-10 02:10:30 +01:00
}
}
}
2020-05-14 16:41:43 +02:00
if ( ! c . editable ) {
2014-02-10 02:10:30 +01:00
return - 1 ; // if cell is not editable, don't bother
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
/* editing */
2017-08-18 23:19:12 +02:00
bool bring_up_editor = allow_reselect ? ( c . selected & & already_selected ) : c . selected ;
2014-02-10 02:10:30 +01:00
String editor_text = c . text ;
switch ( c . mode ) {
case TreeItem : : CELL_MODE_STRING : {
//nothing in particular
2020-07-01 15:59:42 +02:00
if ( select_mode = = SELECT_MULTI & & ( get_viewport ( ) - > get_processed_events_count ( ) = = focus_in_id | | ! already_cursor ) ) {
2014-02-10 02:10:30 +01:00
bring_up_editor = false ;
}
} break ;
case TreeItem : : CELL_MODE_CHECK : {
bring_up_editor = false ; //checkboxes are not edited with editor
2017-01-21 23:00:25 +01:00
if ( force_edit_checkbox_only_on_checkbox ) {
2022-08-31 14:02:40 +02:00
if ( x < theme_cache . checked - > get_width ( ) ) {
2017-01-21 23:00:25 +01:00
p_item - > set_checked ( col , ! c . checked ) ;
2021-09-18 09:33:18 +02:00
item_edited ( col , p_item , p_button ) ;
2017-01-21 23:00:25 +01:00
}
} else {
p_item - > set_checked ( col , ! c . checked ) ;
2021-09-18 09:33:18 +02:00
item_edited ( col , p_item , p_button ) ;
2017-01-21 23:00:25 +01:00
}
2016-09-19 23:07:24 +02:00
click_handled = true ;
//p_item->edited_signal.call(col);
2014-02-10 02:10:30 +01:00
} break ;
2018-09-22 22:31:56 +02:00
case TreeItem : : CELL_MODE_RANGE : {
2021-12-09 10:42:46 +01:00
if ( ! c . text . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
//if (x >= (get_column_width(col)-item_h/2)) {
popup_menu - > clear ( ) ;
for ( int i = 0 ; i < c . text . get_slice_count ( " , " ) ; i + + ) {
2015-06-29 05:29:49 +02:00
String s = c . text . get_slicec ( ' , ' , i ) ;
2020-12-15 13:04:21 +01:00
popup_menu - > add_item ( s . get_slicec ( ' : ' , 0 ) , s . get_slicec ( ' : ' , 1 ) . is_empty ( ) ? i : s . get_slicec ( ' : ' , 1 ) . to_int ( ) ) ;
2014-02-10 02:10:30 +01:00
}
popup_menu - > set_size ( Size2 ( col_width , 0 ) ) ;
2022-08-31 14:02:40 +02:00
popup_menu - > set_position ( get_screen_position ( ) + Point2i ( col_ofs , _get_title_button_height ( ) + y_ofs + item_h ) - theme_cache . offset ) ;
2014-02-10 02:10:30 +01:00
popup_menu - > popup ( ) ;
popup_edited_item = p_item ;
popup_edited_item_col = col ;
//}
bring_up_editor = false ;
} else {
if ( x > = ( col_width - item_h / 2 ) ) {
/* touching the combo */
bool up = p_pos . y < ( item_h / 2 ) ;
2015-08-31 00:37:23 +02:00
2021-08-13 23:31:57 +02:00
if ( p_button = = MouseButton : : LEFT ) {
2015-12-08 19:04:56 +01:00
if ( range_click_timer - > get_time_left ( ) = = 0 ) {
range_item_last = p_item ;
range_up_last = up ;
range_click_timer - > set_wait_time ( 0.6 ) ;
range_click_timer - > set_one_shot ( true ) ;
range_click_timer - > start ( ) ;
} else if ( up ! = range_up_last ) {
return - 1 ; // break. avoid changing direction on mouse held
}
2014-02-10 02:10:30 +01:00
p_item - > set_range ( col , c . val + ( up ? 1.0 : - 1.0 ) * c . step ) ;
2015-08-31 00:37:23 +02:00
2021-09-18 09:33:18 +02:00
item_edited ( col , p_item , p_button ) ;
2015-12-08 19:04:56 +01:00
2021-08-13 23:31:57 +02:00
} else if ( p_button = = MouseButton : : RIGHT ) {
2014-02-10 02:10:30 +01:00
p_item - > set_range ( col , ( up ? c . max : c . min ) ) ;
2021-09-18 09:33:18 +02:00
item_edited ( col , p_item , p_button ) ;
2021-08-13 23:31:57 +02:00
} else if ( p_button = = MouseButton : : WHEEL_UP ) {
2014-02-10 02:10:30 +01:00
p_item - > set_range ( col , c . val + c . step ) ;
2021-09-18 09:33:18 +02:00
item_edited ( col , p_item , p_button ) ;
2021-08-13 23:31:57 +02:00
} else if ( p_button = = MouseButton : : WHEEL_DOWN ) {
2014-02-10 02:10:30 +01:00
p_item - > set_range ( col , c . val - c . step ) ;
2021-09-18 09:33:18 +02:00
item_edited ( col , p_item , p_button ) ;
2014-02-10 02:10:30 +01:00
}
2015-08-31 00:37:23 +02:00
//p_item->edited_signal.call(col);
2014-02-10 02:10:30 +01:00
bring_up_editor = false ;
2016-07-26 22:24:34 +02:00
} else {
2019-07-23 17:27:55 +02:00
editor_text = String : : num ( p_item - > cells [ col ] . val , Math : : range_step_decimals ( p_item - > cells [ col ] . step ) ) ;
2020-07-01 15:59:42 +02:00
if ( select_mode = = SELECT_MULTI & & get_viewport ( ) - > get_processed_events_count ( ) = = focus_in_id ) {
2014-02-10 02:10:30 +01:00
bring_up_editor = false ;
2020-05-14 16:41:43 +02:00
}
2015-08-31 00:37:23 +02:00
}
2014-02-10 02:10:30 +01:00
}
click_handled = true ;
} break ;
case TreeItem : : CELL_MODE_ICON : {
bring_up_editor = false ;
} break ;
case TreeItem : : CELL_MODE_CUSTOM : {
edited_item = p_item ;
2015-08-31 00:37:23 +02:00
edited_col = col ;
2022-08-31 14:02:40 +02:00
bool on_arrow = x > col_width - theme_cache . select_arrow - > get_width ( ) ;
2017-03-05 16:44:50 +01:00
2022-08-31 14:02:40 +02:00
custom_popup_rect = Rect2i ( get_global_position ( ) + Point2i ( col_ofs , _get_title_button_height ( ) + y_ofs + item_h - theme_cache . offset . y ) , Size2 ( get_column_width ( col ) , item_h ) ) ;
2017-08-10 21:02:19 +02:00
2017-06-05 01:35:08 +02:00
if ( on_arrow | | ! p_item - > cells [ col ] . custom_button ) {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " custom_popup_edited " ) , ( ( bool ) ( x > = ( col_width - item_h / 2 ) ) ) ) ;
2017-06-05 01:35:08 +02:00
}
if ( ! p_item - > cells [ col ] . custom_button | | ! on_arrow ) {
2021-09-18 09:33:18 +02:00
item_edited ( col , p_item , p_button ) ;
2017-06-05 01:35:08 +02:00
}
2014-02-10 02:10:30 +01:00
click_handled = true ;
return - 1 ;
} break ;
} ;
2021-08-13 23:31:57 +02:00
if ( ! bring_up_editor | | p_button ! = MouseButton : : LEFT ) {
2014-02-10 02:10:30 +01:00
return - 1 ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2016-09-19 23:07:24 +02:00
click_handled = true ;
2022-04-07 13:49:28 +02:00
popup_pressing_edited_item = p_item ;
popup_pressing_edited_item_column = col ;
2014-02-10 02:10:30 +01:00
2022-08-31 14:02:40 +02:00
pressing_item_rect = Rect2 ( get_global_position ( ) + Point2i ( col_ofs , _get_title_button_height ( ) + y_ofs ) - theme_cache . offset , Size2 ( col_width , item_h ) ) ;
2015-08-29 06:43:21 +02:00
pressing_for_editor_text = editor_text ;
pressing_for_editor = true ;
2014-02-10 02:10:30 +01:00
return - 1 ; //select
} else {
Point2i new_pos = p_pos ;
2015-08-31 00:37:23 +02:00
2014-02-10 02:10:30 +01:00
if ( ! skip ) {
2022-08-31 14:02:40 +02:00
x_ofs + = theme_cache . item_margin ;
//new_pos.x-=theme_cache.item_margin;
2014-02-10 02:10:30 +01:00
y_ofs + = item_h ;
new_pos . y - = item_h ;
}
2015-08-31 00:37:23 +02:00
2018-01-18 21:37:17 +01:00
if ( ! p_item - > collapsed ) { /* if not collapsed, check the children */
2014-02-10 02:10:30 +01:00
2021-03-07 21:07:30 +01:00
TreeItem * c = p_item - > first_child ;
2014-02-10 02:10:30 +01:00
while ( c ) {
2021-07-04 05:13:28 +02:00
int child_h = propagate_mouse_event ( new_pos , x_ofs , y_ofs , x_limit , p_double_click , c , p_button , p_mod ) ;
2014-02-10 02:10:30 +01:00
2020-05-14 16:41:43 +02:00
if ( child_h < 0 ) {
2014-02-10 02:10:30 +01:00
return - 1 ; // break, stop propagating, no need to anymore
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
new_pos . y - = child_h ;
y_ofs + = child_h ;
c = c - > next ;
item_h + = child_h ;
}
}
2021-09-18 09:33:18 +02:00
if ( p_item = = root ) {
emit_signal ( SNAME ( " empty_clicked " ) , get_local_mouse_position ( ) , p_button ) ;
2019-04-09 19:22:14 +02:00
}
2014-02-10 02:10:30 +01:00
}
return item_h ; // nothing found
}
2023-04-25 17:43:26 +02:00
void Tree : : _text_editor_popup_modal_close ( ) {
2024-05-17 09:03:52 +02:00
if ( popup_edit_commited ) {
return ; // Already processed by LineEdit/TextEdit commit.
}
2024-05-01 13:39:54 +02:00
if ( popup_editor - > get_hide_reason ( ) = = Popup : : HIDE_REASON_CANCELED ) {
2024-05-17 09:03:52 +02:00
return ; // ESC pressed, app focus lost, or forced close from code.
2016-01-23 15:45:36 +01:00
}
2020-05-14 16:41:43 +02:00
if ( value_editor - > has_point ( value_editor - > get_local_mouse_position ( ) ) ) {
2016-01-27 16:24:49 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-01-23 15:45:36 +01:00
2023-04-25 17:43:26 +02:00
if ( ! popup_edited_item ) {
return ;
}
if ( popup_edited_item - > is_edit_multiline ( popup_edited_item_col ) & & popup_edited_item - > get_cell_mode ( popup_edited_item_col ) = = TreeItem : : CELL_MODE_STRING ) {
_apply_multiline_edit ( ) ;
} else {
_line_editor_submit ( line_editor - > get_text ( ) ) ;
}
2016-01-23 15:45:36 +01:00
}
2023-04-25 17:43:26 +02:00
void Tree : : _text_editor_gui_input ( const Ref < InputEvent > & p_event ) {
2024-05-17 09:03:52 +02:00
if ( popup_edit_commited ) {
return ; // Already processed by _text_editor_popup_modal_close
}
if ( popup_editor - > get_hide_reason ( ) = = Popup : : HIDE_REASON_CANCELED ) {
return ; // ESC pressed, app focus lost, or forced close from code.
}
2023-04-25 17:43:26 +02:00
if ( p_event - > is_action_pressed ( " ui_text_newline_blank " , true ) ) {
accept_event ( ) ;
} else if ( p_event - > is_action_pressed ( " ui_text_newline " ) ) {
2024-05-17 09:03:52 +02:00
popup_edit_commited = true ; // End edit popup processing.
2023-04-25 17:43:26 +02:00
popup_editor - > hide ( ) ;
_apply_multiline_edit ( ) ;
accept_event ( ) ;
}
}
void Tree : : _apply_multiline_edit ( ) {
if ( ! popup_edited_item ) {
return ;
}
if ( popup_edited_item_col < 0 | | popup_edited_item_col > columns . size ( ) ) {
return ;
}
TreeItem : : Cell & c = popup_edited_item - > cells . write [ popup_edited_item_col ] ;
switch ( c . mode ) {
case TreeItem : : CELL_MODE_STRING : {
c . text = text_editor - > get_text ( ) ;
} break ;
default : {
ERR_FAIL ( ) ;
}
}
item_edited ( popup_edited_item_col , popup_edited_item ) ;
queue_redraw ( ) ;
}
void Tree : : _line_editor_submit ( String p_text ) {
2024-05-17 09:03:52 +02:00
if ( popup_edit_commited ) {
return ; // Already processed by _text_editor_popup_modal_close
}
if ( popup_editor - > get_hide_reason ( ) = = Popup : : HIDE_REASON_CANCELED ) {
return ; // ESC pressed, app focus lost, or forced close from code.
}
popup_edit_commited = true ; // End edit popup processing.
2020-03-20 03:32:09 +01:00
popup_editor - > hide ( ) ;
2014-02-10 02:10:30 +01:00
2020-05-14 16:41:43 +02:00
if ( ! popup_edited_item ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2020-05-14 16:41:43 +02:00
if ( popup_edited_item_col < 0 | | popup_edited_item_col > columns . size ( ) ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2018-07-25 03:11:03 +02:00
TreeItem : : Cell & c = popup_edited_item - > cells . write [ popup_edited_item_col ] ;
2014-02-10 02:10:30 +01:00
switch ( c . mode ) {
case TreeItem : : CELL_MODE_STRING : {
c . text = p_text ;
//popup_edited_item->edited_signal.call( popup_edited_item_col );
} break ;
case TreeItem : : CELL_MODE_RANGE : {
2020-07-24 20:07:57 +02:00
c . val = p_text . to_float ( ) ;
2020-05-14 16:41:43 +02:00
if ( c . step > 0 ) {
2020-12-21 19:02:57 +01:00
c . val = Math : : snapped ( c . val , c . step ) ;
2020-05-14 16:41:43 +02:00
}
if ( c . val < c . min ) {
2014-12-07 06:04:20 +01:00
c . val = c . min ;
2020-05-14 16:41:43 +02:00
} else if ( c . val > c . max ) {
2014-12-07 06:04:20 +01:00
c . val = c . max ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
//popup_edited_item->edited_signal.call( popup_edited_item_col );
} break ;
2019-04-09 17:08:36 +02:00
default : {
ERR_FAIL ( ) ;
}
2014-02-10 02:10:30 +01:00
}
2015-08-31 00:37:23 +02:00
item_edited ( popup_edited_item_col , popup_edited_item ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2014-02-10 02:10:30 +01:00
}
void Tree : : value_editor_changed ( double p_value ) {
if ( updating_value_editor ) {
return ;
}
if ( ! popup_edited_item ) {
return ;
}
2024-08-23 19:25:13 +02:00
const TreeItem : : Cell & c = popup_edited_item - > cells [ popup_edited_item_col ] ;
2022-07-06 17:36:30 +02:00
2024-08-23 19:25:13 +02:00
line_editor - > set_text ( String : : num ( p_value , Math : : range_step_decimals ( c . step ) ) ) ;
2022-07-06 17:36:30 +02:00
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2014-02-10 02:10:30 +01:00
}
void Tree : : popup_select ( int p_option ) {
2020-05-14 16:41:43 +02:00
if ( ! popup_edited_item ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2020-05-14 16:41:43 +02:00
if ( popup_edited_item_col < 0 | | popup_edited_item_col > columns . size ( ) ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2018-07-25 03:11:03 +02:00
popup_edited_item - > cells . write [ popup_edited_item_col ] . val = p_option ;
2014-02-10 02:10:30 +01:00
//popup_edited_item->edited_signal.call( popup_edited_item_col );
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2015-08-31 00:37:23 +02:00
item_edited ( popup_edited_item_col , popup_edited_item ) ;
2014-02-10 02:10:30 +01:00
}
2017-12-31 05:56:17 +01:00
void Tree : : _go_left ( ) {
if ( selected_col = = 0 ) {
2021-03-07 21:07:30 +01:00
if ( selected_item - > get_first_child ( ) ! = nullptr & & ! selected_item - > is_collapsed ( ) ) {
2017-12-31 05:56:17 +01:00
selected_item - > set_collapsed ( true ) ;
} else {
if ( columns . size ( ) = = 1 ) { // goto parent with one column
TreeItem * parent = selected_item - > get_parent ( ) ;
if ( selected_item ! = get_root ( ) & & parent & & parent - > is_selectable ( selected_col ) & & ! ( hide_root & & parent = = get_root ( ) ) ) {
select_single_item ( parent , get_root ( ) , selected_col ) ;
}
} else if ( selected_item - > get_prev_visible ( ) ) {
selected_col = columns . size ( ) - 1 ;
_go_up ( ) ; // go to upper column if possible
}
}
} else {
if ( select_mode = = SELECT_MULTI ) {
selected_col - - ;
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " cell_selected " ) ) ;
2017-12-31 05:56:17 +01:00
} else {
selected_item - > select ( selected_col - 1 ) ;
}
}
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2017-12-31 05:56:17 +01:00
accept_event ( ) ;
ensure_cursor_is_visible ( ) ;
}
2014-02-10 02:10:30 +01:00
2017-12-31 05:56:17 +01:00
void Tree : : _go_right ( ) {
if ( selected_col = = ( columns . size ( ) - 1 ) ) {
2021-03-07 21:07:30 +01:00
if ( selected_item - > get_first_child ( ) ! = nullptr & & selected_item - > is_collapsed ( ) ) {
2017-12-31 05:56:17 +01:00
selected_item - > set_collapsed ( false ) ;
} else if ( selected_item - > get_next_visible ( ) ) {
2020-01-01 10:57:40 +01:00
selected_col = 0 ;
2017-12-31 05:56:17 +01:00
_go_down ( ) ;
}
} else {
if ( select_mode = = SELECT_MULTI ) {
selected_col + + ;
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " cell_selected " ) ) ;
2017-12-31 05:56:17 +01:00
} else {
selected_item - > select ( selected_col + 1 ) ;
}
}
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2017-12-31 05:56:17 +01:00
ensure_cursor_is_visible ( ) ;
accept_event ( ) ;
}
void Tree : : _go_up ( ) {
2020-04-02 01:20:12 +02:00
TreeItem * prev = nullptr ;
2017-12-31 05:56:17 +01:00
if ( ! selected_item ) {
prev = get_last_item ( ) ;
selected_col = 0 ;
} else {
prev = selected_item - > get_prev_visible ( ) ;
}
2024-06-14 22:55:01 +02:00
int col = MAX ( selected_col , 0 ) ;
2017-12-31 05:56:17 +01:00
if ( select_mode = = SELECT_MULTI ) {
2020-05-14 16:41:43 +02:00
if ( ! prev ) {
2017-05-20 17:38:03 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2023-12-16 00:12:45 +01:00
2024-06-14 22:55:01 +02:00
select_single_item ( prev , get_root ( ) , col ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2017-12-31 05:56:17 +01:00
} else {
2020-05-14 16:41:43 +02:00
while ( prev & & ! prev - > cells [ col ] . selectable ) {
2017-12-31 05:56:17 +01:00
prev = prev - > get_prev_visible ( ) ;
2020-05-14 16:41:43 +02:00
}
if ( ! prev ) {
2017-12-31 05:56:17 +01:00
return ; // do nothing..
2020-05-14 16:41:43 +02:00
}
2017-12-31 05:56:17 +01:00
prev - > select ( col ) ;
2014-02-10 02:10:30 +01:00
}
2017-12-31 05:56:17 +01:00
ensure_cursor_is_visible ( ) ;
accept_event ( ) ;
}
void Tree : : _go_down ( ) {
2020-04-02 01:20:12 +02:00
TreeItem * next = nullptr ;
2017-12-31 05:56:17 +01:00
if ( ! selected_item ) {
2019-11-12 08:15:29 +01:00
if ( root ) {
next = hide_root ? root - > get_next_visible ( ) : root ;
}
2017-12-31 05:56:17 +01:00
} else {
next = selected_item - > get_next_visible ( ) ;
}
2014-02-10 02:10:30 +01:00
2024-06-14 22:55:01 +02:00
int col = MAX ( selected_col , 0 ) ;
2017-12-31 05:56:17 +01:00
if ( select_mode = = SELECT_MULTI ) {
if ( ! next ) {
return ;
}
2014-02-10 02:10:30 +01:00
2024-06-14 22:55:01 +02:00
select_single_item ( next , get_root ( ) , col ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2017-12-31 05:56:17 +01:00
} else {
2020-05-14 16:41:43 +02:00
while ( next & & ! next - > cells [ col ] . selectable ) {
2017-12-31 05:56:17 +01:00
next = next - > get_next_visible ( ) ;
2020-05-14 16:41:43 +02:00
}
2017-12-31 05:56:17 +01:00
if ( ! next ) {
return ; // do nothing..
}
next - > select ( col ) ;
}
2014-02-10 02:10:30 +01:00
2017-12-31 05:56:17 +01:00
ensure_cursor_is_visible ( ) ;
accept_event ( ) ;
}
2014-02-10 02:10:30 +01:00
2022-07-05 19:30:45 +02:00
bool Tree : : _scroll ( bool p_horizontal , float p_pages ) {
ScrollBar * scroll = p_horizontal ? ( ScrollBar * ) h_scroll : ( ScrollBar * ) v_scroll ;
double prev_value = scroll - > get_value ( ) ;
scroll - > set_value ( scroll - > get_value ( ) + scroll - > get_page ( ) * p_pages ) ;
return scroll - > get_value ( ) ! = prev_value ;
}
2023-01-04 03:59:34 +01:00
Rect2 Tree : : _get_scrollbar_layout_rect ( ) const {
const Size2 control_size = get_size ( ) ;
const Ref < StyleBox > background = theme_cache . panel_style ;
// This is the background stylebox's content rect.
const real_t width = control_size . x - background - > get_margin ( SIDE_LEFT ) - background - > get_margin ( SIDE_RIGHT ) ;
const real_t height = control_size . y - background - > get_margin ( SIDE_TOP ) - background - > get_margin ( SIDE_BOTTOM ) ;
const Rect2 content_rect = Rect2 ( background - > get_offset ( ) , Size2 ( width , height ) ) ;
// Use the stylebox's margins by default. Can be overridden by `scrollbar_margin_*`.
const real_t top = theme_cache . scrollbar_margin_top < 0 ? content_rect . get_position ( ) . y : theme_cache . scrollbar_margin_top ;
const real_t right = theme_cache . scrollbar_margin_right < 0 ? content_rect . get_end ( ) . x : ( control_size . x - theme_cache . scrollbar_margin_right ) ;
const real_t bottom = theme_cache . scrollbar_margin_bottom < 0 ? content_rect . get_end ( ) . y : ( control_size . y - theme_cache . scrollbar_margin_bottom ) ;
const real_t left = theme_cache . scrollbar_margin_left < 0 ? content_rect . get_position ( ) . x : theme_cache . scrollbar_margin_left ;
return Rect2 ( left , top , right - left , bottom - top ) ;
}
Rect2 Tree : : _get_content_rect ( ) const {
const Size2 control_size = get_size ( ) ;
const Ref < StyleBox > background = theme_cache . panel_style ;
// This is the background stylebox's content rect.
const real_t width = control_size . x - background - > get_margin ( SIDE_LEFT ) - background - > get_margin ( SIDE_RIGHT ) ;
const real_t height = control_size . y - background - > get_margin ( SIDE_TOP ) - background - > get_margin ( SIDE_BOTTOM ) ;
const Rect2 content_rect = Rect2 ( background - > get_offset ( ) , Size2 ( width , height ) ) ;
// Scrollbars won't affect Tree's content rect if they're not visible or placed inside the stylebox margin area.
const real_t v_size = v_scroll - > is_visible ( ) ? ( v_scroll - > get_combined_minimum_size ( ) . x + theme_cache . scrollbar_h_separation ) : 0 ;
const real_t h_size = h_scroll - > is_visible ( ) ? ( h_scroll - > get_combined_minimum_size ( ) . y + theme_cache . scrollbar_v_separation ) : 0 ;
const Point2 scroll_begin = _get_scrollbar_layout_rect ( ) . get_end ( ) - Vector2 ( v_size , h_size ) ;
2024-03-03 14:37:52 +01:00
const Size2 offset = ( content_rect . get_end ( ) - scroll_begin ) . maxf ( 0 ) ;
2023-01-04 03:59:34 +01:00
return content_rect . grow_individual ( 0 , 0 , - offset . x , - offset . y ) ;
}
2021-08-22 17:37:22 +02:00
void Tree : : gui_input ( const Ref < InputEvent > & p_event ) {
2021-04-05 08:52:21 +02:00
ERR_FAIL_COND ( p_event . is_null ( ) ) ;
2017-12-31 05:56:17 +01:00
Ref < InputEventKey > k = p_event ;
2014-02-10 02:10:30 +01:00
2022-09-02 11:37:48 +02:00
bool is_command = k . is_valid ( ) & & k - > is_command_or_control_pressed ( ) ;
2024-02-13 02:25:37 +01:00
if ( p_event - > is_action ( " ui_right " ) & & p_event - > is_pressed ( ) ) {
2020-05-14 16:41:43 +02:00
if ( ! cursor_can_exit_tree ) {
2017-12-31 05:56:17 +01:00
accept_event ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2024-08-28 18:32:45 +02:00
if ( ! selected_item | | selected_col > ( columns . size ( ) - 1 ) ) {
2017-12-31 05:56:17 +01:00
return ;
}
2024-08-28 18:32:45 +02:00
2024-02-13 02:25:37 +01:00
if ( k . is_valid ( ) & & k - > is_shift_pressed ( ) ) {
selected_item - > set_collapsed_recursive ( false ) ;
2024-08-28 18:32:45 +02:00
} else if ( select_mode ! = SELECT_ROW ) {
2017-12-31 05:56:17 +01:00
_go_right ( ) ;
2024-08-28 18:32:45 +02:00
} else if ( selected_item - > get_first_child ( ) ! = nullptr & & selected_item - > is_collapsed ( ) ) {
selected_item - > set_collapsed ( false ) ;
} else {
_go_down ( ) ;
2017-12-31 05:56:17 +01:00
}
2024-02-13 02:25:37 +01:00
} else if ( p_event - > is_action ( " ui_left " ) & & p_event - > is_pressed ( ) ) {
2020-05-14 16:41:43 +02:00
if ( ! cursor_can_exit_tree ) {
2017-12-31 05:56:17 +01:00
accept_event ( ) ;
2020-05-14 16:41:43 +02:00
}
2017-09-16 18:26:05 +02:00
2024-08-28 18:32:45 +02:00
if ( ! selected_item | | selected_col < 0 ) {
2017-12-31 05:56:17 +01:00
return ;
}
2024-02-13 02:25:37 +01:00
if ( k . is_valid ( ) & & k - > is_shift_pressed ( ) ) {
selected_item - > set_collapsed_recursive ( true ) ;
2024-08-28 18:32:45 +02:00
} else if ( select_mode ! = SELECT_ROW ) {
2017-12-31 05:56:17 +01:00
_go_left ( ) ;
2024-08-28 18:32:45 +02:00
} else if ( selected_item - > get_first_child ( ) ! = nullptr & & ! selected_item - > is_collapsed ( ) ) {
selected_item - > set_collapsed ( true ) ;
} else {
_go_up ( ) ;
2017-12-31 05:56:17 +01:00
}
2024-02-13 02:25:37 +01:00
} else if ( p_event - > is_action ( " ui_up " ) & & p_event - > is_pressed ( ) & & ! is_command ) {
2020-05-14 16:41:43 +02:00
if ( ! cursor_can_exit_tree ) {
2017-12-31 05:56:17 +01:00
accept_event ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2017-12-31 05:56:17 +01:00
_go_up ( ) ;
2014-02-10 02:10:30 +01:00
2024-02-13 02:25:37 +01:00
} else if ( p_event - > is_action ( " ui_down " ) & & p_event - > is_pressed ( ) & & ! is_command ) {
2020-05-14 16:41:43 +02:00
if ( ! cursor_can_exit_tree ) {
2017-12-31 05:56:17 +01:00
accept_event ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2017-12-31 05:56:17 +01:00
_go_down ( ) ;
2014-02-10 02:10:30 +01:00
2024-02-13 02:25:37 +01:00
} else if ( p_event - > is_action ( " ui_page_down " ) & & p_event - > is_pressed ( ) ) {
2020-05-14 16:41:43 +02:00
if ( ! cursor_can_exit_tree ) {
2017-12-31 05:56:17 +01:00
accept_event ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2020-04-02 01:20:12 +02:00
TreeItem * next = nullptr ;
2020-05-14 16:41:43 +02:00
if ( ! selected_item ) {
2017-12-31 05:56:17 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2017-12-31 05:56:17 +01:00
next = selected_item ;
2014-02-10 02:10:30 +01:00
2017-12-31 05:56:17 +01:00
for ( int i = 0 ; i < 10 ; i + + ) {
TreeItem * _n = next - > get_next_visible ( ) ;
if ( _n ) {
next = _n ;
} else {
2019-05-20 20:34:55 +02:00
break ;
2017-12-31 05:56:17 +01:00
}
}
2020-05-14 16:41:43 +02:00
if ( next = = selected_item ) {
2017-12-31 05:56:17 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2017-12-31 05:56:17 +01:00
if ( select_mode = = SELECT_MULTI ) {
selected_item = next ;
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " cell_selected " ) ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2017-12-31 05:56:17 +01:00
} else {
2020-05-14 16:41:43 +02:00
while ( next & & ! next - > cells [ selected_col ] . selectable ) {
2017-12-31 05:56:17 +01:00
next = next - > get_next_visible ( ) ;
2020-05-14 16:41:43 +02:00
}
2017-12-31 05:56:17 +01:00
if ( ! next ) {
return ; // do nothing..
}
next - > select ( selected_col ) ;
}
2014-02-10 02:10:30 +01:00
2017-12-31 05:56:17 +01:00
ensure_cursor_is_visible ( ) ;
2024-02-13 02:25:37 +01:00
} else if ( p_event - > is_action ( " ui_page_up " ) & & p_event - > is_pressed ( ) ) {
2020-05-14 16:41:43 +02:00
if ( ! cursor_can_exit_tree ) {
2017-12-31 05:56:17 +01:00
accept_event ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2020-04-02 01:20:12 +02:00
TreeItem * prev = nullptr ;
2020-05-14 16:41:43 +02:00
if ( ! selected_item ) {
2017-12-31 05:56:17 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2017-12-31 05:56:17 +01:00
prev = selected_item ;
2014-02-10 02:10:30 +01:00
2017-12-31 05:56:17 +01:00
for ( int i = 0 ; i < 10 ; i + + ) {
TreeItem * _n = prev - > get_prev_visible ( ) ;
if ( _n ) {
prev = _n ;
} else {
2019-05-20 20:34:55 +02:00
break ;
2017-12-31 05:56:17 +01:00
}
}
2020-05-14 16:41:43 +02:00
if ( prev = = selected_item ) {
2017-12-31 05:56:17 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2017-12-31 05:56:17 +01:00
if ( select_mode = = SELECT_MULTI ) {
selected_item = prev ;
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " cell_selected " ) ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2017-12-31 05:56:17 +01:00
} else {
2020-05-14 16:41:43 +02:00
while ( prev & & ! prev - > cells [ selected_col ] . selectable ) {
2017-12-31 05:56:17 +01:00
prev = prev - > get_prev_visible ( ) ;
2020-05-14 16:41:43 +02:00
}
2017-12-31 05:56:17 +01:00
if ( ! prev ) {
return ; // do nothing..
}
prev - > select ( selected_col ) ;
}
ensure_cursor_is_visible ( ) ;
2024-02-13 02:25:37 +01:00
} else if ( p_event - > is_action ( " ui_accept " ) & & p_event - > is_pressed ( ) ) {
2017-12-31 05:56:17 +01:00
if ( selected_item ) {
//bring up editor if possible
if ( ! edit_selected ( ) ) {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " item_activated " ) ) ;
2017-12-31 05:56:17 +01:00
incr_search . clear ( ) ;
}
}
accept_event ( ) ;
2024-02-13 02:25:37 +01:00
} else if ( p_event - > is_action ( " ui_select " ) & & p_event - > is_pressed ( ) ) {
2017-12-31 05:56:17 +01:00
if ( select_mode = = SELECT_MULTI ) {
2020-05-14 16:41:43 +02:00
if ( ! selected_item ) {
2017-12-31 05:56:17 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2017-12-31 05:56:17 +01:00
if ( selected_item - > is_selected ( selected_col ) ) {
selected_item - > deselect ( selected_col ) ;
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " multi_selected " ) , selected_item , selected_col , false ) ;
2017-12-31 05:56:17 +01:00
} else if ( selected_item - > is_selectable ( selected_col ) ) {
selected_item - > select ( selected_col ) ;
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " multi_selected " ) , selected_item , selected_col , true ) ;
2017-12-31 05:56:17 +01:00
}
}
accept_event ( ) ;
}
2014-02-10 02:10:30 +01:00
2023-04-18 08:50:24 +02:00
if ( allow_search & & k . is_valid ( ) ) { // Incremental search
2017-12-31 05:56:17 +01:00
2020-05-14 16:41:43 +02:00
if ( ! k - > is_pressed ( ) ) {
2017-12-31 05:56:17 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2022-09-02 11:37:48 +02:00
if ( k - > is_command_or_control_pressed ( ) | | ( k - > is_shift_pressed ( ) & & k - > get_unicode ( ) = = 0 ) | | k - > is_meta_pressed ( ) ) {
2017-12-31 05:56:17 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
if ( ! root ) {
2017-12-31 05:56:17 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2020-05-14 16:41:43 +02:00
if ( hide_root & & ! root - > get_next_visible ( ) ) {
2017-12-31 05:56:17 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2017-12-31 05:56:17 +01:00
if ( k - > get_unicode ( ) > 0 ) {
_do_incr_search ( String : : chr ( k - > get_unicode ( ) ) ) ;
accept_event ( ) ;
return ;
} else {
2021-08-13 23:31:57 +02:00
if ( k - > get_keycode ( ) ! = Key : : SHIFT ) {
2017-12-31 05:56:17 +01:00
last_keypress = 0 ;
2020-05-14 16:41:43 +02:00
}
2017-05-20 17:38:03 +02:00
}
}
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
Ref < InputEventMouseMotion > mm = p_event ;
if ( mm . is_valid ( ) ) {
2022-09-06 19:09:32 +02:00
Ref < StyleBox > bg = theme_cache . panel_style ;
2020-09-03 13:22:16 +02:00
bool rtl = is_layout_rtl ( ) ;
2014-02-10 02:10:30 +01:00
2020-09-03 13:22:16 +02:00
Point2 pos = mm - > get_position ( ) ;
if ( rtl ) {
pos . x = get_size ( ) . width - pos . x ;
}
2022-09-06 19:09:32 +02:00
pos - = theme_cache . panel_style - > get_offset ( ) ;
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
Cache : : ClickType old_hover = cache . hover_type ;
int old_index = cache . hover_index ;
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
cache . hover_type = Cache : : CLICK_NONE ;
cache . hover_index = 0 ;
if ( show_column_titles ) {
pos . y - = _get_title_button_height ( ) ;
if ( pos . y < 0 ) {
2022-08-31 14:02:40 +02:00
pos . x + = theme_cache . offset . x ;
2017-05-20 17:38:03 +02:00
int len = 0 ;
for ( int i = 0 ; i < columns . size ( ) ; i + + ) {
len + = get_column_width ( i ) ;
if ( pos . x < len ) {
cache . hover_type = Cache : : CLICK_TITLE ;
cache . hover_index = i ;
break ;
2014-02-10 02:10:30 +01:00
}
}
}
2017-05-20 17:38:03 +02:00
}
2014-02-10 02:10:30 +01:00
2017-06-05 01:35:08 +02:00
if ( root ) {
2017-06-03 10:54:24 +02:00
Point2 mpos = mm - > get_position ( ) ;
2020-09-03 13:22:16 +02:00
if ( rtl ) {
mpos . x = get_size ( ) . width - mpos . x ;
}
2022-09-06 19:09:32 +02:00
mpos - = theme_cache . panel_style - > get_offset ( ) ;
2017-05-20 17:38:03 +02:00
mpos . y - = _get_title_button_height ( ) ;
if ( mpos . y > = 0 ) {
2020-05-14 16:41:43 +02:00
if ( h_scroll - > is_visible_in_tree ( ) ) {
2017-05-20 17:38:03 +02:00
mpos . x + = h_scroll - > get_value ( ) ;
2020-05-14 16:41:43 +02:00
}
if ( v_scroll - > is_visible_in_tree ( ) ) {
2017-05-20 17:38:03 +02:00
mpos . y + = v_scroll - > get_value ( ) ;
2020-05-14 16:41:43 +02:00
}
2016-05-11 16:46:08 +02:00
2020-06-06 23:02:22 +02:00
TreeItem * old_it = cache . hover_item ;
int old_col = cache . hover_cell ;
2017-05-20 17:38:03 +02:00
int col , h , section ;
TreeItem * it = _find_item_at_pos ( root , mpos , col , h , section ) ;
2016-05-11 16:46:08 +02:00
2018-07-13 15:00:10 +02:00
if ( drop_mode_flags ) {
if ( it ! = drop_mode_over ) {
drop_mode_over = it ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2018-07-13 15:00:10 +02:00
}
if ( it & & section ! = drop_mode_section ) {
drop_mode_section = section ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2018-07-13 15:00:10 +02:00
}
2016-05-11 16:46:08 +02:00
}
2017-06-05 01:35:08 +02:00
2020-06-06 23:02:22 +02:00
cache . hover_item = it ;
cache . hover_cell = col ;
2018-07-13 15:00:10 +02:00
2020-06-06 23:02:22 +02:00
if ( it ! = old_it | | col ! = old_col ) {
2020-09-08 11:20:07 +02:00
if ( old_it & & old_col > = old_it - > cells . size ( ) ) {
2022-08-13 23:21:24 +02:00
// Columns may have changed since last redraw().
queue_redraw ( ) ;
2020-09-08 11:20:07 +02:00
} else {
// Only need to update if mouse enters/exits a button
bool was_over_button = old_it & & old_it - > cells [ old_col ] . custom_button ;
bool is_over_button = it & & it - > cells [ col ] . custom_button ;
if ( was_over_button | | is_over_button ) {
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2020-09-08 11:20:07 +02:00
}
2020-06-06 23:02:22 +02:00
}
2017-06-05 01:35:08 +02:00
}
2016-05-11 16:46:08 +02:00
}
2017-05-20 17:38:03 +02:00
}
2016-05-11 16:46:08 +02:00
2020-06-06 23:02:22 +02:00
// Update if mouse enters/exits columns
2017-05-20 17:38:03 +02:00
if ( cache . hover_type ! = old_hover | | cache . hover_index ! = old_index ) {
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2017-05-20 17:38:03 +02:00
}
2015-08-29 06:43:21 +02:00
2022-04-07 13:49:28 +02:00
if ( pressing_for_editor & & popup_pressing_edited_item & & ( popup_pressing_edited_item - > get_cell_mode ( popup_pressing_edited_item_column ) = = TreeItem : : CELL_MODE_RANGE ) ) {
/* This needs to happen now, because the popup can be closed when pressing another item, and must remain the popup edited item until it actually closes */
popup_edited_item = popup_pressing_edited_item ;
popup_edited_item_col = popup_pressing_edited_item_column ;
popup_pressing_edited_item = nullptr ;
popup_pressing_edited_item_column = - 1 ;
2015-08-29 06:43:21 +02:00
2017-05-20 17:38:03 +02:00
if ( ! range_drag_enabled ) {
2022-04-07 13:49:28 +02:00
//range drag
2017-06-03 10:54:24 +02:00
Vector2 cpos = mm - > get_position ( ) ;
2020-09-03 13:22:16 +02:00
if ( rtl ) {
cpos . x = get_size ( ) . width - cpos . x ;
}
2017-05-20 17:38:03 +02:00
if ( cpos . distance_to ( pressing_pos ) > 2 ) {
range_drag_enabled = true ;
range_drag_capture_pos = cpos ;
range_drag_base = popup_edited_item - > get_range ( popup_edited_item_col ) ;
2020-04-28 15:19:37 +02:00
Input : : get_singleton ( ) - > set_mouse_mode ( Input : : MOUSE_MODE_CAPTURED ) ;
2015-08-29 06:43:21 +02:00
}
2017-05-20 17:38:03 +02:00
} else {
2018-07-25 03:11:03 +02:00
const TreeItem : : Cell & c = popup_edited_item - > cells [ popup_edited_item_col ] ;
2017-05-20 17:38:03 +02:00
float diff_y = - mm - > get_relative ( ) . y ;
2021-10-16 01:22:57 +02:00
diff_y = Math : : pow ( ABS ( diff_y ) , 1.8f ) * SIGN ( diff_y ) ;
2017-05-20 17:38:03 +02:00
diff_y * = 0.1 ;
range_drag_base = CLAMP ( range_drag_base + c . step * diff_y , c . min , c . max ) ;
popup_edited_item - > set_range ( popup_edited_item_col , range_drag_base ) ;
item_edited ( popup_edited_item_col , popup_edited_item ) ;
2015-08-29 06:43:21 +02:00
}
2017-05-20 17:38:03 +02:00
}
2015-08-29 06:43:21 +02:00
2017-05-20 17:38:03 +02:00
if ( drag_touching & & ! drag_touching_deaccel ) {
drag_accum - = mm - > get_relative ( ) . y ;
v_scroll - > set_value ( drag_from + drag_accum ) ;
2021-12-29 14:22:22 +01:00
drag_speed = - mm - > get_velocity ( ) . y ;
2017-05-20 17:38:03 +02:00
}
}
2015-08-31 00:37:23 +02:00
2021-09-18 09:33:18 +02:00
Ref < InputEventMouseButton > mb = p_event ;
if ( mb . is_valid ( ) ) {
2020-09-03 13:22:16 +02:00
bool rtl = is_layout_rtl ( ) ;
2021-09-18 09:33:18 +02:00
if ( ! mb - > is_pressed ( ) ) {
2022-08-13 18:30:41 +02:00
if ( mb - > get_button_index ( ) = = MouseButton : : LEFT | |
mb - > get_button_index ( ) = = MouseButton : : RIGHT ) {
2021-09-18 09:33:18 +02:00
Point2 pos = mb - > get_position ( ) ;
2020-09-03 13:22:16 +02:00
if ( rtl ) {
pos . x = get_size ( ) . width - pos . x ;
}
2022-09-06 19:09:32 +02:00
pos - = theme_cache . panel_style - > get_offset ( ) ;
2017-05-20 17:38:03 +02:00
if ( show_column_titles ) {
pos . y - = _get_title_button_height ( ) ;
2017-05-17 12:55:55 +02:00
2017-05-20 17:38:03 +02:00
if ( pos . y < 0 ) {
2022-08-31 14:02:40 +02:00
pos . x + = theme_cache . offset . x ;
2017-05-20 17:38:03 +02:00
int len = 0 ;
for ( int i = 0 ; i < columns . size ( ) ; i + + ) {
len + = get_column_width ( i ) ;
2022-08-13 18:30:41 +02:00
if ( pos . x < static_cast < real_t > ( len ) ) {
emit_signal ( SNAME ( " column_title_clicked " ) , i , mb - > get_button_index ( ) ) ;
2017-05-20 17:38:03 +02:00
break ;
2017-05-17 12:55:55 +02:00
}
}
}
2017-05-20 17:38:03 +02:00
}
2022-08-13 18:30:41 +02:00
}
2017-05-17 12:55:55 +02:00
2022-08-13 18:30:41 +02:00
if ( mb - > get_button_index ( ) = = MouseButton : : LEFT ) {
2017-05-20 17:38:03 +02:00
if ( single_select_defer ) {
select_single_item ( single_select_defer , root , single_select_defer_column ) ;
2020-04-02 01:20:12 +02:00
single_select_defer = nullptr ;
2017-05-20 17:38:03 +02:00
}
2016-05-11 16:46:08 +02:00
2017-05-20 17:38:03 +02:00
range_click_timer - > stop ( ) ;
2015-12-08 19:04:56 +01:00
2017-05-20 17:38:03 +02:00
if ( pressing_for_editor ) {
if ( range_drag_enabled ) {
range_drag_enabled = false ;
2020-04-28 15:19:37 +02:00
Input : : get_singleton ( ) - > set_mouse_mode ( Input : : MOUSE_MODE_VISIBLE ) ;
2017-05-20 17:38:03 +02:00
warp_mouse ( range_drag_capture_pos ) ;
} else {
2024-03-28 16:15:38 +01:00
Rect2 rect ;
if ( select_mode = = SELECT_ROW ) {
rect = get_selected ( ) - > get_meta ( " __focus_col_ " + itos ( selected_col ) ) ;
} else {
rect = get_selected ( ) - > get_meta ( " __focus_rect " ) ;
}
2021-09-18 09:33:18 +02:00
Point2 mpos = mb - > get_position ( ) ;
2022-02-26 13:38:46 +01:00
int icon_size_x = 0 ;
Ref < Texture2D > icon = get_selected ( ) - > get_icon ( selected_col ) ;
if ( icon . is_valid ( ) ) {
Rect2i icon_region = get_selected ( ) - > get_icon_region ( selected_col ) ;
if ( icon_region = = Rect2i ( ) ) {
icon_size_x = icon - > get_width ( ) ;
} else {
icon_size_x = icon_region . size . width ;
}
}
2022-12-21 16:58:59 +01:00
// Icon is treated as if it is outside of the rect so that double clicking on it will emit the item_icon_double_clicked signal.
2020-09-03 13:22:16 +02:00
if ( rtl ) {
2022-02-26 13:38:46 +01:00
mpos . x = get_size ( ) . width - ( mpos . x + icon_size_x ) ;
} else {
mpos . x - = icon_size_x ;
2020-09-03 13:22:16 +02:00
}
if ( rect . has_point ( mpos ) ) {
2019-09-13 21:14:12 +02:00
if ( ! edit_selected ( ) ) {
2022-12-21 16:58:59 +01:00
emit_signal ( SNAME ( " item_icon_double_clicked " ) ) ;
2019-09-13 21:14:12 +02:00
}
2016-07-28 21:37:52 +02:00
} else {
2022-12-21 16:58:59 +01:00
emit_signal ( SNAME ( " item_icon_double_clicked " ) ) ;
2016-07-28 21:37:52 +02:00
}
2015-08-29 06:43:21 +02:00
}
2017-05-20 17:38:03 +02:00
pressing_for_editor = false ;
}
2015-08-29 06:43:21 +02:00
2017-05-20 17:38:03 +02:00
if ( drag_touching ) {
if ( drag_speed = = 0 ) {
drag_touching_deaccel = false ;
drag_touching = false ;
2018-04-11 09:28:14 +02:00
set_physics_process_internal ( false ) ;
2017-05-20 17:38:03 +02:00
} else {
drag_touching_deaccel = true ;
2014-02-10 02:10:30 +01:00
}
}
}
2021-09-18 09:33:18 +02:00
if ( cache . click_type = = Cache : : CLICK_BUTTON & & cache . click_item ! = nullptr ) {
// make sure in case of wrong reference after reconstructing whole TreeItems
cache . click_item = get_item_at_position ( cache . click_pos ) ;
emit_signal ( " button_clicked " , cache . click_item , cache . click_column , cache . click_id , mb - > get_button_index ( ) ) ;
}
cache . click_type = Cache : : CLICK_NONE ;
cache . click_index = - 1 ;
cache . click_id = - 1 ;
cache . click_item = nullptr ;
cache . click_column = 0 ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2017-05-20 17:38:03 +02:00
return ;
}
2014-02-10 02:10:30 +01:00
2020-05-14 16:41:43 +02:00
if ( range_drag_enabled ) {
2017-05-20 17:38:03 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2015-08-31 00:37:23 +02:00
2021-09-18 09:33:18 +02:00
switch ( mb - > get_button_index ( ) ) {
2021-08-13 23:31:57 +02:00
case MouseButton : : RIGHT :
case MouseButton : : LEFT : {
2022-09-06 19:09:32 +02:00
Ref < StyleBox > bg = theme_cache . panel_style ;
2017-05-20 17:38:03 +02:00
2021-09-18 09:33:18 +02:00
Point2 pos = mb - > get_position ( ) ;
2020-09-03 13:22:16 +02:00
if ( rtl ) {
pos . x = get_size ( ) . width - pos . x ;
}
pos - = bg - > get_offset ( ) ;
2017-05-20 17:38:03 +02:00
cache . click_type = Cache : : CLICK_NONE ;
2017-08-26 18:55:43 +02:00
if ( show_column_titles ) {
2017-05-20 17:38:03 +02:00
pos . y - = _get_title_button_height ( ) ;
if ( pos . y < 0 ) {
2022-08-31 14:02:40 +02:00
pos . x + = theme_cache . offset . x ;
2022-08-13 18:30:41 +02:00
int len = 0 ;
for ( int i = 0 ; i < columns . size ( ) ; i + + ) {
len + = get_column_width ( i ) ;
if ( pos . x < static_cast < real_t > ( len ) ) {
cache . click_type = Cache : : CLICK_TITLE ;
cache . click_index = i ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2022-08-13 18:30:41 +02:00
break ;
2014-02-10 02:10:30 +01:00
}
2016-05-16 17:23:40 +02:00
}
2014-02-10 02:10:30 +01:00
break ;
2016-05-16 17:23:40 +02:00
}
2017-05-20 17:38:03 +02:00
}
2021-09-18 09:33:18 +02:00
2021-03-07 21:07:30 +01:00
if ( ! root | | ( ! root - > get_first_child ( ) & & hide_root ) ) {
2024-03-19 04:31:32 +01:00
emit_signal ( SNAME ( " empty_clicked " ) , get_local_mouse_position ( ) , mb - > get_button_index ( ) ) ;
2017-05-20 17:38:03 +02:00
break ;
}
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
click_handled = false ;
pressing_for_editor = false ;
2019-01-14 21:20:33 +01:00
propagate_mouse_activated = false ;
2014-02-10 02:10:30 +01:00
2022-09-06 19:09:32 +02:00
int x_limit = get_size ( ) . width - theme_cache . panel_style - > get_minimum_size ( ) . width ;
2022-12-31 06:50:20 +01:00
if ( v_scroll - > is_visible ( ) ) {
x_limit - = v_scroll - > get_minimum_size ( ) . width ;
2021-07-04 05:13:28 +02:00
}
cache . rtl = is_layout_rtl ( ) ;
2017-05-20 17:38:03 +02:00
blocked + + ;
2022-08-31 14:02:40 +02:00
propagate_mouse_event ( pos + theme_cache . offset , 0 , 0 , x_limit + theme_cache . offset . width , mb - > is_double_click ( ) , root , mb - > get_button_index ( ) , mb ) ;
2017-05-20 17:38:03 +02:00
blocked - - ;
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
if ( pressing_for_editor ) {
2021-09-18 09:33:18 +02:00
pressing_pos = mb - > get_position ( ) ;
2020-09-03 13:22:16 +02:00
if ( rtl ) {
pressing_pos . x = get_size ( ) . width - pressing_pos . x ;
}
2017-05-20 17:38:03 +02:00
}
2014-02-10 02:10:30 +01:00
2021-09-18 09:33:18 +02:00
if ( mb - > get_button_index ( ) = = MouseButton : : RIGHT ) {
2017-05-20 17:38:03 +02:00
break ;
2020-05-14 16:41:43 +02:00
}
2016-05-16 04:41:48 +02:00
2017-05-20 17:38:03 +02:00
if ( drag_touching ) {
2018-04-11 09:28:14 +02:00
set_physics_process_internal ( false ) ;
2017-05-20 17:38:03 +02:00
drag_touching_deaccel = false ;
drag_touching = false ;
drag_speed = 0 ;
drag_from = 0 ;
}
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
if ( ! click_handled ) {
drag_speed = 0 ;
drag_accum = 0 ;
//last_drag_accum=0;
drag_from = v_scroll - > get_value ( ) ;
2022-10-17 00:59:51 +02:00
drag_touching = DisplayServer : : get_singleton ( ) - > is_touchscreen_available ( ) ;
2017-05-20 17:38:03 +02:00
drag_touching_deaccel = false ;
if ( drag_touching ) {
2018-04-11 09:28:14 +02:00
set_physics_process_internal ( true ) ;
2014-02-10 02:10:30 +01:00
}
2017-11-27 16:58:28 +01:00
2021-09-18 09:33:18 +02:00
if ( mb - > get_button_index ( ) = = MouseButton : : LEFT ) {
2023-06-08 23:24:00 +02:00
if ( get_item_at_position ( mb - > get_position ( ) ) = = nullptr & & ! mb - > is_shift_pressed ( ) & & ! mb - > is_command_or_control_pressed ( ) ) {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " nothing_selected " ) ) ;
2020-05-14 16:41:43 +02:00
}
2017-11-27 16:58:28 +01:00
}
2017-05-20 17:38:03 +02:00
}
2014-02-10 02:10:30 +01:00
2019-01-14 21:20:33 +01:00
if ( propagate_mouse_activated ) {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " item_activated " ) ) ;
2019-01-14 21:20:33 +01:00
propagate_mouse_activated = false ;
}
2017-05-20 17:38:03 +02:00
} break ;
2021-08-13 23:31:57 +02:00
case MouseButton : : WHEEL_UP : {
2022-07-05 19:30:45 +02:00
if ( _scroll ( false , - mb - > get_factor ( ) / 8 ) ) {
2019-10-02 12:34:04 +02:00
accept_event ( ) ;
}
2017-05-20 17:38:03 +02:00
} break ;
2021-08-13 23:31:57 +02:00
case MouseButton : : WHEEL_DOWN : {
2022-07-05 19:30:45 +02:00
if ( _scroll ( false , mb - > get_factor ( ) / 8 ) ) {
accept_event ( ) ;
}
} break ;
case MouseButton : : WHEEL_LEFT : {
if ( _scroll ( true , - mb - > get_factor ( ) / 8 ) ) {
accept_event ( ) ;
}
} break ;
case MouseButton : : WHEEL_RIGHT : {
if ( _scroll ( true , mb - > get_factor ( ) / 8 ) ) {
2019-10-02 12:34:04 +02:00
accept_event ( ) ;
}
2017-05-20 17:38:03 +02:00
} break ;
2021-03-25 21:56:12 +01:00
default :
break ;
2017-05-20 17:38:03 +02:00
}
2014-02-10 02:10:30 +01:00
}
2017-11-01 21:49:39 +01:00
Ref < InputEventPanGesture > pan_gesture = p_event ;
if ( pan_gesture . is_valid ( ) ) {
2020-01-03 11:29:22 +01:00
double prev_v = v_scroll - > get_value ( ) ;
2017-11-01 21:49:39 +01:00
v_scroll - > set_value ( v_scroll - > get_value ( ) + v_scroll - > get_page ( ) * pan_gesture - > get_delta ( ) . y / 8 ) ;
2020-01-03 11:29:22 +01:00
double prev_h = h_scroll - > get_value ( ) ;
2020-09-03 13:22:16 +02:00
if ( is_layout_rtl ( ) ) {
h_scroll - > set_value ( h_scroll - > get_value ( ) + h_scroll - > get_page ( ) * - pan_gesture - > get_delta ( ) . x / 8 ) ;
} else {
h_scroll - > set_value ( h_scroll - > get_value ( ) + h_scroll - > get_page ( ) * pan_gesture - > get_delta ( ) . x / 8 ) ;
}
2020-01-03 11:29:22 +01:00
if ( v_scroll - > get_value ( ) ! = prev_v | | h_scroll - > get_value ( ) ! = prev_h ) {
2019-10-02 12:34:04 +02:00
accept_event ( ) ;
}
2017-11-01 21:49:39 +01:00
}
2014-02-10 02:10:30 +01:00
}
2022-11-26 15:58:25 +01:00
bool Tree : : edit_selected ( bool p_force_edit ) {
2014-02-10 02:10:30 +01:00
TreeItem * s = get_selected ( ) ;
2023-06-06 14:59:54 +02:00
ERR_FAIL_NULL_V_MSG ( s , false , " No item selected. " ) ;
2014-02-10 02:10:30 +01:00
ensure_cursor_is_visible ( ) ;
int col = get_selected_column ( ) ;
2019-08-08 22:11:48 +02:00
ERR_FAIL_INDEX_V_MSG ( col , columns . size ( ) , false , " No item column selected. " ) ;
2014-02-10 02:10:30 +01:00
2022-11-26 15:58:25 +01:00
if ( ! s - > cells [ col ] . editable & & ! p_force_edit ) {
2014-02-10 02:10:30 +01:00
return false ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-12-27 17:19:52 +01:00
float popup_scale = popup_editor - > is_embedded ( ) ? 1.0 : popup_editor - > get_parent_visible_window ( ) - > get_content_scale_factor ( ) ;
2024-03-28 16:15:38 +01:00
Rect2 rect ;
if ( select_mode = = SELECT_ROW ) {
rect = s - > get_meta ( " __focus_col_ " + itos ( selected_col ) ) ;
} else {
rect = s - > get_meta ( " __focus_rect " ) ;
}
2023-12-27 17:19:52 +01:00
rect . position * = popup_scale ;
2014-02-10 02:10:30 +01:00
popup_edited_item = s ;
popup_edited_item_col = col ;
2018-07-25 03:11:03 +02:00
const TreeItem : : Cell & c = s - > cells [ col ] ;
2014-02-10 02:10:30 +01:00
2015-11-05 16:20:45 +01:00
if ( c . mode = = TreeItem : : CELL_MODE_CHECK ) {
s - > set_checked ( col , ! c . checked ) ;
item_edited ( col , s ) ;
return true ;
} else if ( c . mode = = TreeItem : : CELL_MODE_CUSTOM ) {
2014-02-10 02:10:30 +01:00
edited_item = s ;
edited_col = col ;
2017-06-04 00:25:13 +02:00
custom_popup_rect = Rect2i ( get_global_position ( ) + rect . position , rect . size ) ;
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " custom_popup_edited " ) , false ) ;
2014-02-10 02:10:30 +01:00
item_edited ( col , s ) ;
return true ;
2021-12-09 10:42:46 +01:00
} else if ( c . mode = = TreeItem : : CELL_MODE_RANGE & & ! c . text . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
popup_menu - > clear ( ) ;
for ( int i = 0 ; i < c . text . get_slice_count ( " , " ) ; i + + ) {
2019-02-12 21:10:08 +01:00
String s2 = c . text . get_slicec ( ' , ' , i ) ;
2020-12-15 13:04:21 +01:00
popup_menu - > add_item ( s2 . get_slicec ( ' : ' , 0 ) , s2 . get_slicec ( ' : ' , 1 ) . is_empty ( ) ? i : s2 . get_slicec ( ' : ' , 1 ) . to_int ( ) ) ;
2014-02-10 02:10:30 +01:00
}
popup_menu - > set_size ( Size2 ( rect . size . width , 0 ) ) ;
2021-08-31 17:43:35 +02:00
popup_menu - > set_position ( get_screen_position ( ) + rect . position + Point2i ( 0 , rect . size . height ) ) ;
2014-02-10 02:10:30 +01:00
popup_menu - > popup ( ) ;
popup_edited_item = s ;
popup_edited_item_col = col ;
2023-04-25 17:43:26 +02:00
return true ;
} else if ( ( c . mode = = TreeItem : : CELL_MODE_STRING & & ! c . edit_multiline ) | | c . mode = = TreeItem : : CELL_MODE_RANGE ) {
2020-03-20 03:32:09 +01:00
Rect2 popup_rect ;
2022-12-20 04:19:18 +01:00
int value_editor_height = c . mode = = TreeItem : : CELL_MODE_RANGE ? value_editor - > get_minimum_size ( ) . height : 0 ;
// "floor()" centers vertically.
2023-04-25 17:43:26 +02:00
Vector2 ofs ( 0 , Math : : floor ( ( MAX ( line_editor - > get_minimum_size ( ) . height , rect . size . height - value_editor_height ) - rect . size . height ) / 2 ) ) ;
2020-03-20 03:32:09 +01:00
2023-04-25 17:43:26 +02:00
popup_rect . position = get_screen_position ( ) + rect . position - ofs ;
2020-03-20 03:32:09 +01:00
popup_rect . size = rect . size ;
2022-08-17 16:02:17 +02:00
// Account for icon.
2023-12-27 17:19:52 +01:00
Size2 icon_size = _get_cell_icon_size ( c ) * popup_scale ;
2023-03-31 21:17:59 +02:00
popup_rect . position . x + = icon_size . x ;
popup_rect . size . x - = icon_size . x ;
2022-08-17 16:02:17 +02:00
2023-04-25 17:43:26 +02:00
line_editor - > clear ( ) ;
line_editor - > set_text ( c . mode = = TreeItem : : CELL_MODE_STRING ? c . text : String : : num ( c . val , Math : : range_step_decimals ( c . step ) ) ) ;
line_editor - > select_all ( ) ;
line_editor - > show ( ) ;
text_editor - > hide ( ) ;
2014-02-10 02:10:30 +01:00
2018-09-22 22:31:56 +02:00
if ( c . mode = = TreeItem : : CELL_MODE_RANGE ) {
2022-12-20 04:19:18 +01:00
popup_rect . size . y + = value_editor_height ;
2020-03-20 03:32:09 +01:00
2020-03-14 17:06:39 +01:00
value_editor - > show ( ) ;
2014-02-10 02:10:30 +01:00
updating_value_editor = true ;
value_editor - > set_min ( c . min ) ;
value_editor - > set_max ( c . max ) ;
value_editor - > set_step ( c . step ) ;
2017-01-04 05:16:14 +01:00
value_editor - > set_value ( c . val ) ;
2017-01-13 18:08:30 +01:00
value_editor - > set_exp_ratio ( c . expr ) ;
2014-02-10 02:10:30 +01:00
updating_value_editor = false ;
2020-03-20 03:32:09 +01:00
} else {
value_editor - > hide ( ) ;
2014-02-10 02:10:30 +01:00
}
2020-03-20 03:32:09 +01:00
popup_editor - > set_position ( popup_rect . position ) ;
2023-12-27 17:19:52 +01:00
popup_editor - > set_size ( popup_rect . size * popup_scale ) ;
if ( ! popup_editor - > is_embedded ( ) ) {
popup_editor - > set_content_scale_factor ( popup_scale ) ;
}
2024-05-17 09:03:52 +02:00
popup_edit_commited = false ; // Start edit popup processing.
2020-03-20 03:32:09 +01:00
popup_editor - > popup ( ) ;
popup_editor - > child_controls_changed ( ) ;
2023-04-25 17:43:26 +02:00
line_editor - > grab_focus ( ) ;
return true ;
} else if ( c . mode = = TreeItem : : CELL_MODE_STRING & & c . edit_multiline ) {
line_editor - > hide ( ) ;
text_editor - > clear ( ) ;
text_editor - > set_text ( c . text ) ;
text_editor - > select_all ( ) ;
text_editor - > show ( ) ;
popup_editor - > set_position ( get_screen_position ( ) + rect . position ) ;
2023-12-27 17:19:52 +01:00
popup_editor - > set_size ( rect . size * popup_scale ) ;
if ( ! popup_editor - > is_embedded ( ) ) {
popup_editor - > set_content_scale_factor ( popup_scale ) ;
}
2024-05-17 09:03:52 +02:00
popup_edit_commited = false ; // Start edit popup processing.
2023-04-25 17:43:26 +02:00
popup_editor - > popup ( ) ;
popup_editor - > child_controls_changed ( ) ;
2014-02-10 02:10:30 +01:00
text_editor - > grab_focus ( ) ;
2020-03-20 03:32:09 +01:00
2014-02-10 02:10:30 +01:00
return true ;
}
return false ;
}
2020-12-31 08:43:03 +01:00
bool Tree : : is_editing ( ) {
return popup_editor - > is_visible ( ) ;
}
2022-11-26 15:58:25 +01:00
void Tree : : set_editor_selection ( int p_from_line , int p_to_line , int p_from_column , int p_to_column , int p_caret ) {
if ( p_from_column = = - 1 | | p_to_column = = - 1 ) {
line_editor - > select ( p_from_line , p_to_line ) ;
} else {
text_editor - > select ( p_from_line , p_from_column , p_to_line , p_to_column , p_caret ) ;
}
}
2014-02-10 02:10:30 +01:00
Size2 Tree : : get_internal_min_size ( ) const {
2023-01-04 03:59:34 +01:00
Size2i size ;
2020-05-14 16:41:43 +02:00
if ( root ) {
2014-02-10 02:10:30 +01:00
size . height + = get_item_height ( root ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
for ( int i = 0 ; i < columns . size ( ) ; i + + ) {
2021-06-28 15:40:56 +02:00
size . width + = get_column_minimum_width ( i ) ;
2014-02-10 02:10:30 +01:00
}
2015-08-31 00:37:23 +02:00
2014-02-10 02:10:30 +01:00
return size ;
}
void Tree : : update_scrollbars ( ) {
2023-01-04 03:59:34 +01:00
const Size2 control_size = get_size ( ) ;
const Ref < StyleBox > background = theme_cache . panel_style ;
// This is the background stylebox's content rect.
const real_t width = control_size . x - background - > get_margin ( SIDE_LEFT ) - background - > get_margin ( SIDE_RIGHT ) ;
const real_t height = control_size . y - background - > get_margin ( SIDE_TOP ) - background - > get_margin ( SIDE_BOTTOM ) ;
const Rect2 content_rect = Rect2 ( background - > get_offset ( ) , Size2 ( width , height ) ) ;
2023-01-03 15:50:35 +01:00
const Size2 hmin = h_scroll - > get_combined_minimum_size ( ) ;
const Size2 vmin = v_scroll - > get_combined_minimum_size ( ) ;
const Size2 internal_min_size = get_internal_min_size ( ) ;
const int title_button_height = _get_title_button_height ( ) ;
Size2 tree_content_size = content_rect . get_size ( ) - Vector2 ( 0 , title_button_height ) ;
bool display_vscroll = internal_min_size . height > tree_content_size . height ;
bool display_hscroll = internal_min_size . width > tree_content_size . width ;
2021-06-25 21:19:46 +02:00
for ( int i = 0 ; i < 2 ; i + + ) {
// Check twice, as both values are dependent on each other.
if ( display_hscroll ) {
2023-01-03 15:50:35 +01:00
tree_content_size . height = content_rect . get_size ( ) . height - title_button_height - hmin . height ;
display_vscroll = internal_min_size . height > tree_content_size . height ;
2021-06-25 21:19:46 +02:00
}
if ( display_vscroll ) {
2023-01-03 15:50:35 +01:00
tree_content_size . width = content_rect . get_size ( ) . width - vmin . width ;
display_hscroll = internal_min_size . width > tree_content_size . width ;
2021-06-25 21:19:46 +02:00
}
}
if ( display_vscroll ) {
2014-02-10 02:10:30 +01:00
v_scroll - > show ( ) ;
2021-06-25 21:19:46 +02:00
v_scroll - > set_max ( internal_min_size . height ) ;
2023-01-03 15:50:35 +01:00
v_scroll - > set_page ( tree_content_size . height ) ;
2022-08-31 14:02:40 +02:00
theme_cache . offset . y = v_scroll - > get_value ( ) ;
2021-06-25 21:19:46 +02:00
} else {
v_scroll - > hide ( ) ;
2022-08-31 14:02:40 +02:00
theme_cache . offset . y = 0 ;
2014-02-10 02:10:30 +01:00
}
2015-08-31 00:37:23 +02:00
2021-06-25 21:19:46 +02:00
if ( display_hscroll ) {
2014-02-10 02:10:30 +01:00
h_scroll - > show ( ) ;
2021-06-25 21:19:46 +02:00
h_scroll - > set_max ( internal_min_size . width ) ;
2023-01-03 15:50:35 +01:00
h_scroll - > set_page ( tree_content_size . width ) ;
2022-08-31 14:02:40 +02:00
theme_cache . offset . x = h_scroll - > get_value ( ) ;
2021-06-25 21:19:46 +02:00
} else {
h_scroll - > hide ( ) ;
2022-08-31 14:02:40 +02:00
theme_cache . offset . x = 0 ;
2015-08-31 00:37:23 +02:00
}
2023-01-04 03:59:34 +01:00
const Rect2 scroll_rect = _get_scrollbar_layout_rect ( ) ;
v_scroll - > set_begin ( scroll_rect . get_position ( ) + Vector2 ( scroll_rect . get_size ( ) . x - vmin . width , 0 ) ) ;
v_scroll - > set_end ( scroll_rect . get_end ( ) - Vector2 ( 0 , display_hscroll ? hmin . height : 0 ) ) ;
h_scroll - > set_begin ( scroll_rect . get_position ( ) + Vector2 ( 0 , scroll_rect . get_size ( ) . y - hmin . height ) ) ;
h_scroll - > set_end ( scroll_rect . get_end ( ) - Vector2 ( display_vscroll ? vmin . width : 0 , 0 ) ) ;
2014-02-10 02:10:30 +01:00
}
int Tree : : _get_title_button_height ( ) const {
2023-07-07 18:48:13 +02:00
ERR_FAIL_COND_V ( theme_cache . tb_font . is_null ( ) | | theme_cache . title_button . is_null ( ) , 0 ) ;
2020-09-03 13:22:16 +02:00
int h = 0 ;
if ( show_column_titles ) {
for ( int i = 0 ; i < columns . size ( ) ; i + + ) {
2022-08-31 14:02:40 +02:00
h = MAX ( h , columns [ i ] . text_buf - > get_size ( ) . y + theme_cache . title_button - > get_minimum_size ( ) . height ) ;
2020-09-03 13:22:16 +02:00
}
}
return h ;
2014-02-10 02:10:30 +01:00
}
void Tree : : _notification ( int p_what ) {
2022-02-15 18:06:48 +01:00
switch ( p_what ) {
case NOTIFICATION_FOCUS_ENTER : {
if ( get_viewport ( ) ) {
focus_in_id = get_viewport ( ) - > get_processed_events_count ( ) ;
}
} break ;
case NOTIFICATION_MOUSE_EXIT : {
if ( cache . hover_type ! = Cache : : CLICK_NONE ) {
cache . hover_type = Cache : : CLICK_NONE ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2022-02-15 18:06:48 +01:00
}
} break ;
case NOTIFICATION_VISIBILITY_CHANGED : {
drag_touching = false ;
} break ;
case NOTIFICATION_DRAG_END : {
drop_mode_flags = 0 ;
scrolling = false ;
set_physics_process_internal ( false ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2022-02-15 18:06:48 +01:00
} break ;
2014-02-10 02:10:30 +01:00
2022-02-15 18:06:48 +01:00
case NOTIFICATION_DRAG_BEGIN : {
single_select_defer = nullptr ;
2022-08-31 14:02:40 +02:00
if ( theme_cache . scroll_speed > 0 ) {
2022-02-15 18:06:48 +01:00
scrolling = true ;
set_physics_process_internal ( true ) ;
}
} break ;
2015-08-24 01:15:56 +02:00
2022-02-15 18:06:48 +01:00
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS : {
if ( drag_touching ) {
if ( drag_touching_deaccel ) {
float pos = v_scroll - > get_value ( ) ;
pos + = drag_speed * get_physics_process_delta_time ( ) ;
2014-02-10 02:10:30 +01:00
2022-02-15 18:06:48 +01:00
bool turnoff = false ;
if ( pos < 0 ) {
pos = 0 ;
turnoff = true ;
set_physics_process_internal ( false ) ;
drag_touching = false ;
drag_touching_deaccel = false ;
}
if ( pos > ( v_scroll - > get_max ( ) - v_scroll - > get_page ( ) ) ) {
pos = v_scroll - > get_max ( ) - v_scroll - > get_page ( ) ;
turnoff = true ;
}
2014-02-10 02:10:30 +01:00
2022-02-15 18:06:48 +01:00
v_scroll - > set_value ( pos ) ;
float sgn = drag_speed < 0 ? - 1 : 1 ;
float val = Math : : abs ( drag_speed ) ;
val - = 1000 * get_physics_process_delta_time ( ) ;
2014-02-10 02:10:30 +01:00
2022-02-15 18:06:48 +01:00
if ( val < 0 ) {
turnoff = true ;
}
drag_speed = sgn * val ;
2014-02-10 02:10:30 +01:00
2022-02-15 18:06:48 +01:00
if ( turnoff ) {
set_physics_process_internal ( false ) ;
drag_touching = false ;
drag_touching_deaccel = false ;
}
2014-02-10 02:10:30 +01:00
}
}
2017-03-05 16:44:50 +01:00
2022-02-15 18:06:48 +01:00
Point2 mouse_position = get_viewport ( ) - > get_mouse_position ( ) - get_global_position ( ) ;
2022-08-31 14:02:40 +02:00
if ( scrolling & & get_rect ( ) . grow ( theme_cache . scroll_border ) . has_point ( mouse_position ) ) {
2022-02-15 18:06:48 +01:00
Point2 point ;
2018-12-29 15:41:31 +01:00
2022-08-31 14:02:40 +02:00
if ( ( ABS ( mouse_position . x ) < ABS ( mouse_position . x - get_size ( ) . width ) ) & & ( ABS ( mouse_position . x ) < theme_cache . scroll_border ) ) {
point . x = mouse_position . x - theme_cache . scroll_border ;
} else if ( ABS ( mouse_position . x - get_size ( ) . width ) < theme_cache . scroll_border ) {
point . x = mouse_position . x - ( get_size ( ) . width - theme_cache . scroll_border ) ;
2022-02-15 18:06:48 +01:00
}
2018-12-29 15:41:31 +01:00
2022-08-31 14:02:40 +02:00
if ( ( ABS ( mouse_position . y ) < ABS ( mouse_position . y - get_size ( ) . height ) ) & & ( ABS ( mouse_position . y ) < theme_cache . scroll_border ) ) {
point . y = mouse_position . y - theme_cache . scroll_border ;
} else if ( ABS ( mouse_position . y - get_size ( ) . height ) < theme_cache . scroll_border ) {
point . y = mouse_position . y - ( get_size ( ) . height - theme_cache . scroll_border ) ;
2022-02-15 18:06:48 +01:00
}
2018-12-29 15:41:31 +01:00
2022-08-31 14:02:40 +02:00
point * = theme_cache . scroll_speed * get_physics_process_delta_time ( ) ;
2022-02-15 18:06:48 +01:00
point + = get_scroll ( ) ;
h_scroll - > set_value ( point . x ) ;
v_scroll - > set_value ( point . y ) ;
}
} break ;
2014-02-10 02:10:30 +01:00
2022-02-15 18:06:48 +01:00
case NOTIFICATION_DRAW : {
2022-08-31 14:02:40 +02:00
v_scroll - > set_custom_step ( theme_cache . font - > get_height ( theme_cache . font_size ) ) ;
2022-02-15 18:06:48 +01:00
update_scrollbars ( ) ;
RID ci = get_canvas_item ( ) ;
2015-08-31 00:37:23 +02:00
2022-09-06 19:09:32 +02:00
Ref < StyleBox > bg = theme_cache . panel_style ;
2023-01-04 03:59:34 +01:00
const Rect2 content_rect = _get_content_rect ( ) ;
2015-08-31 00:37:23 +02:00
2023-01-04 03:59:34 +01:00
Point2 draw_ofs = content_rect . position ;
Size2 draw_size = content_rect . size ;
2014-02-10 02:10:30 +01:00
2022-02-15 18:06:48 +01:00
bg - > draw ( ci , Rect2 ( Point2 ( ) , get_size ( ) ) ) ;
2014-02-10 02:10:30 +01:00
2022-02-15 18:06:48 +01:00
int tbh = _get_title_button_height ( ) ;
2014-02-10 02:10:30 +01:00
2022-02-15 18:06:48 +01:00
draw_ofs . y + = tbh ;
draw_size . y - = tbh ;
2014-02-10 02:10:30 +01:00
2022-02-15 18:06:48 +01:00
cache . rtl = is_layout_rtl ( ) ;
2021-07-04 05:13:28 +02:00
2022-02-15 18:06:48 +01:00
if ( root & & get_size ( ) . x > 0 & & get_size ( ) . y > 0 ) {
2023-07-11 10:58:19 +02:00
int self_height = 0 ; // Just to pass a reference, we don't need the root's `self_height`.
draw_item ( Point2 ( ) , draw_ofs , draw_size , root , self_height ) ;
2022-02-15 18:06:48 +01:00
}
2020-12-25 22:45:28 +01:00
2022-02-15 18:06:48 +01:00
if ( show_column_titles ) {
//title buttons
2022-09-06 19:09:32 +02:00
int ofs2 = theme_cache . panel_style - > get_margin ( SIDE_LEFT ) ;
2022-02-15 18:06:48 +01:00
for ( int i = 0 ; i < columns . size ( ) ; i + + ) {
2022-08-31 14:02:40 +02:00
Ref < StyleBox > sb = ( cache . click_type = = Cache : : CLICK_TITLE & & cache . click_index = = i ) ? theme_cache . title_button_pressed : ( ( cache . hover_type = = Cache : : CLICK_TITLE & & cache . hover_index = = i ) ? theme_cache . title_button_hover : theme_cache . title_button ) ;
Rect2 tbrect = Rect2 ( ofs2 - theme_cache . offset . x , bg - > get_margin ( SIDE_TOP ) , get_column_width ( i ) , tbh ) ;
2022-02-15 18:06:48 +01:00
if ( cache . rtl ) {
tbrect . position . x = get_size ( ) . width - tbrect . size . x - tbrect . position . x ;
}
sb - > draw ( ci , tbrect ) ;
ofs2 + = tbrect . size . width ;
//text
int clip_w = tbrect . size . width - sb - > get_minimum_size ( ) . width ;
columns . write [ i ] . text_buf - > set_width ( clip_w ) ;
2023-07-11 10:58:19 +02:00
columns . write [ i ] . cached_minimum_width_dirty = true ;
2022-02-15 18:06:48 +01:00
2023-03-26 03:13:31 +02:00
Vector2 text_pos = Point2i ( tbrect . position . x , tbrect . position . y + ( tbrect . size . height - columns [ i ] . text_buf - > get_size ( ) . y ) / 2 ) ;
switch ( columns [ i ] . title_alignment ) {
case HorizontalAlignment : : HORIZONTAL_ALIGNMENT_LEFT : {
text_pos . x + = cache . rtl ? tbrect . size . width - ( sb - > get_offset ( ) . x + columns [ i ] . text_buf - > get_size ( ) . x ) : sb - > get_offset ( ) . x ;
break ;
}
case HorizontalAlignment : : HORIZONTAL_ALIGNMENT_RIGHT : {
text_pos . x + = cache . rtl ? sb - > get_offset ( ) . x : tbrect . size . width - ( sb - > get_offset ( ) . x + columns [ i ] . text_buf - > get_size ( ) . x ) ;
break ;
}
default : {
2024-04-23 09:46:19 +02:00
text_pos . x + = ( tbrect . size . width - columns [ i ] . text_buf - > get_size ( ) . x ) / 2 ;
2023-03-26 03:13:31 +02:00
break ;
}
}
2022-08-31 14:02:40 +02:00
if ( theme_cache . font_outline_size > 0 & & theme_cache . font_outline_color . a > 0 ) {
columns [ i ] . text_buf - > draw_outline ( ci , text_pos , theme_cache . font_outline_size , theme_cache . font_outline_color ) ;
2022-02-15 18:06:48 +01:00
}
2022-08-31 14:02:40 +02:00
columns [ i ] . text_buf - > draw ( ci , text_pos , theme_cache . title_button_color ) ;
2020-12-25 22:45:28 +01:00
}
2014-02-10 02:10:30 +01:00
}
2021-05-09 12:41:47 +02:00
2022-09-06 19:09:32 +02:00
// Draw the focus outline last, so that it is drawn in front of the section headings.
2022-02-15 18:06:48 +01:00
// Otherwise, section heading backgrounds can appear to be in front of the focus outline when scrolling.
if ( has_focus ( ) ) {
RenderingServer : : get_singleton ( ) - > canvas_item_add_clip_ignore ( ci , true ) ;
2022-09-06 19:09:32 +02:00
theme_cache . focus_style - > draw ( ci , Rect2 ( Point2 ( ) , get_size ( ) ) ) ;
2022-02-15 18:06:48 +01:00
RenderingServer : : get_singleton ( ) - > canvas_item_add_clip_ignore ( ci , false ) ;
}
} break ;
2014-02-10 02:10:30 +01:00
2022-02-15 18:06:48 +01:00
case NOTIFICATION_THEME_CHANGED :
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED :
case NOTIFICATION_TRANSLATION_CHANGED : {
_update_all ( ) ;
} break ;
2018-10-04 19:33:34 +02:00
2022-02-15 18:06:48 +01:00
case NOTIFICATION_RESIZED :
case NOTIFICATION_TRANSFORM_CHANGED : {
if ( popup_edited_item ! = nullptr ) {
Rect2 rect = popup_edited_item - > get_meta ( " __focus_rect " ) ;
2018-10-04 19:33:34 +02:00
2023-04-25 17:43:26 +02:00
popup_editor - > set_position ( get_global_position ( ) + rect . position ) ;
popup_editor - > set_size ( rect . size ) ;
popup_editor - > child_controls_changed ( ) ;
2018-10-04 19:33:34 +02:00
}
2022-02-15 18:06:48 +01:00
} break ;
2018-10-04 19:33:34 +02:00
}
2014-02-10 02:10:30 +01:00
}
2020-09-03 13:22:16 +02:00
void Tree : : _update_all ( ) {
for ( int i = 0 ; i < columns . size ( ) ; i + + ) {
update_column ( i ) ;
}
if ( root ) {
update_item_cache ( root ) ;
}
}
2014-02-10 02:10:30 +01:00
Size2 Tree : : get_minimum_size ( ) const {
2024-04-24 03:58:12 +02:00
Vector2 min_size = Vector2 ( 0 , _get_title_button_height ( ) ) ;
if ( theme_cache . panel_style . is_valid ( ) ) {
min_size + = theme_cache . panel_style - > get_minimum_size ( ) ;
}
Vector2 content_min_size = get_internal_min_size ( ) ;
if ( h_scroll_enabled ) {
content_min_size . x = 0 ;
min_size . y + = h_scroll - > get_combined_minimum_size ( ) . height ;
2021-06-25 21:19:46 +02:00
}
2024-04-24 03:58:12 +02:00
if ( v_scroll_enabled ) {
min_size . x + = v_scroll - > get_combined_minimum_size ( ) . width ;
content_min_size . y = 0 ;
}
return min_size + content_min_size ;
2014-02-10 02:10:30 +01:00
}
2022-12-22 08:05:04 +01:00
TreeItem * Tree : : create_item ( TreeItem * p_parent , int p_index ) {
2020-04-02 01:20:12 +02:00
ERR_FAIL_COND_V ( blocked > 0 , nullptr ) ;
2014-02-10 02:10:30 +01:00
2020-04-02 01:20:12 +02:00
TreeItem * ti = nullptr ;
2014-02-10 02:10:30 +01:00
if ( p_parent ) {
2021-03-07 21:07:30 +01:00
ERR_FAIL_COND_V_MSG ( p_parent - > tree ! = this , nullptr , " A different tree owns the given parent " ) ;
2022-12-22 08:05:04 +01:00
ti = p_parent - > create_child ( p_index ) ;
2014-02-10 02:10:30 +01:00
} else {
2017-12-14 22:13:48 +01:00
if ( ! root ) {
// No root exists, make the given item the new root.
ti = memnew ( TreeItem ( this ) ) ;
2023-06-06 14:59:54 +02:00
ERR_FAIL_NULL_V ( ti , nullptr ) ;
2017-12-14 22:13:48 +01:00
ti - > cells . resize ( columns . size ( ) ) ;
2021-03-07 21:07:30 +01:00
ti - > is_root = true ;
2017-12-14 22:13:48 +01:00
root = ti ;
} else {
// Root exists, append or insert to root.
2022-12-22 08:05:04 +01:00
ti = create_item ( root , p_index ) ;
2017-12-14 22:13:48 +01:00
}
2014-02-10 02:10:30 +01:00
}
return ti ;
}
2021-06-28 15:40:56 +02:00
TreeItem * Tree : : get_root ( ) const {
2014-02-10 02:10:30 +01:00
return root ;
}
2020-05-14 14:29:06 +02:00
2021-06-28 15:40:56 +02:00
TreeItem * Tree : : get_last_item ( ) const {
2014-02-10 02:10:30 +01:00
TreeItem * last = root ;
2024-07-25 19:57:32 +02:00
while ( last & & last - > last_child & & ! last - > collapsed ) {
last = last - > last_child ;
2014-02-10 02:10:30 +01:00
}
return last ;
}
2022-05-26 12:12:57 +02:00
void Tree : : item_edited ( int p_column , TreeItem * p_item , MouseButton p_custom_mouse_index ) {
2014-02-10 02:10:30 +01:00
edited_item = p_item ;
edited_col = p_column ;
2020-09-03 13:22:16 +02:00
if ( p_item ! = nullptr & & p_column > = 0 & & p_column < p_item - > cells . size ( ) ) {
edited_item - > cells . write [ p_column ] . dirty = true ;
}
2022-05-26 12:12:57 +02:00
emit_signal ( SNAME ( " item_edited " ) ) ;
if ( p_custom_mouse_index ! = MouseButton : : NONE ) {
emit_signal ( SNAME ( " custom_item_clicked " ) , p_custom_mouse_index ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
void Tree : : item_changed ( int p_column , TreeItem * p_item ) {
2024-08-27 05:49:27 +02:00
if ( p_item ! = nullptr ) {
if ( p_column > = 0 & & p_column < p_item - > cells . size ( ) ) {
p_item - > cells . write [ p_column ] . dirty = true ;
columns . write [ p_column ] . cached_minimum_width_dirty = true ;
} else if ( p_column = = - 1 ) {
for ( int i = 0 ; i < p_item - > cells . size ( ) ; i + + ) {
p_item - > cells . write [ i ] . dirty = true ;
columns . write [ i ] . cached_minimum_width_dirty = true ;
}
}
2020-09-03 13:22:16 +02:00
}
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2014-02-10 02:10:30 +01:00
}
void Tree : : item_selected ( int p_column , TreeItem * p_item ) {
if ( select_mode = = SELECT_MULTI ) {
2020-05-14 16:41:43 +02:00
if ( ! p_item - > cells [ p_column ] . selectable ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2018-07-25 03:11:03 +02:00
p_item - > cells . write [ p_column ] . selected = true ;
2021-07-17 23:22:52 +02:00
//emit_signal(SNAME("multi_selected"),p_item,p_column,true); - NO this is for TreeItem::select
2014-02-10 02:10:30 +01:00
2018-01-13 17:27:32 +01:00
selected_col = p_column ;
2023-01-06 20:19:34 +01:00
selected_item = p_item ;
2014-02-10 02:10:30 +01:00
} else {
select_single_item ( p_item , root , p_column ) ;
}
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2014-02-10 02:10:30 +01:00
}
void Tree : : item_deselected ( int p_column , TreeItem * p_item ) {
2023-01-06 20:19:34 +01:00
if ( select_mode = = SELECT_SINGLE & & selected_item = = p_item & & selected_col = = p_column ) {
2021-02-07 22:11:27 +01:00
selected_item = nullptr ;
2023-01-06 20:19:34 +01:00
selected_col = - 1 ;
} else {
if ( select_mode = = SELECT_ROW & & selected_item = = p_item ) {
selected_item = nullptr ;
2021-03-03 19:39:29 +01:00
selected_col = - 1 ;
2023-01-06 20:19:34 +01:00
} else {
if ( select_mode = = SELECT_MULTI ) {
selected_item = p_item ;
selected_col = p_column ;
}
2021-03-03 19:39:29 +01:00
}
2021-02-07 22:11:27 +01:00
}
2016-12-20 22:47:24 +01:00
if ( select_mode = = SELECT_MULTI | | select_mode = = SELECT_SINGLE ) {
2018-07-25 03:11:03 +02:00
p_item - > cells . write [ p_column ] . selected = false ;
2023-01-14 19:04:46 +01:00
} else if ( select_mode = = SELECT_ROW ) {
for ( int i = 0 ; i < p_item - > cells . size ( ) ; i + + ) {
p_item - > cells . write [ i ] . selected = false ;
}
2015-08-31 00:37:23 +02:00
}
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2014-02-10 02:10:30 +01:00
}
void Tree : : set_select_mode ( SelectMode p_mode ) {
2015-08-31 00:37:23 +02:00
select_mode = p_mode ;
2014-02-10 02:10:30 +01:00
}
2018-01-11 23:35:12 +01:00
Tree : : SelectMode Tree : : get_select_mode ( ) const {
return select_mode ;
}
2017-11-27 16:58:28 +01:00
void Tree : : deselect_all ( ) {
2023-01-14 17:05:07 +01:00
if ( root ) {
TreeItem * item = root ;
while ( item ) {
if ( select_mode = = SELECT_ROW ) {
item - > deselect ( 0 ) ;
} else {
for ( int i = 0 ; i < columns . size ( ) ; i + + ) {
item - > deselect ( i ) ;
}
}
TreeItem * prev_item = item ;
item = get_next_selected ( root ) ;
ERR_FAIL_COND ( item = = prev_item ) ;
2022-11-12 01:02:36 +01:00
}
2017-11-27 16:58:28 +01:00
}
2020-04-02 01:20:12 +02:00
selected_item = nullptr ;
2017-11-27 16:58:28 +01:00
selected_col = - 1 ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2017-11-27 16:58:28 +01:00
}
bool Tree : : is_anything_selected ( ) {
2020-04-02 01:20:12 +02:00
return ( selected_item ! = nullptr ) ;
2017-11-27 16:58:28 +01:00
}
2014-02-10 02:10:30 +01:00
void Tree : : clear ( ) {
2019-06-20 16:59:48 +02:00
ERR_FAIL_COND ( blocked > 0 ) ;
2014-02-10 02:10:30 +01:00
2016-03-18 00:10:09 +01:00
if ( pressing_for_editor ) {
if ( range_drag_enabled ) {
range_drag_enabled = false ;
2020-04-28 15:19:37 +02:00
Input : : get_singleton ( ) - > set_mouse_mode ( Input : : MOUSE_MODE_VISIBLE ) ;
2016-03-18 00:10:09 +01:00
warp_mouse ( range_drag_capture_pos ) ;
}
pressing_for_editor = false ;
}
2014-02-10 02:10:30 +01:00
if ( root ) {
memdelete ( root ) ;
2020-04-02 01:20:12 +02:00
root = nullptr ;
2014-02-10 02:10:30 +01:00
} ;
2020-04-02 01:20:12 +02:00
selected_item = nullptr ;
edited_item = nullptr ;
popup_edited_item = nullptr ;
2022-04-07 13:49:28 +02:00
popup_pressing_edited_item = nullptr ;
2014-02-10 02:10:30 +01:00
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2014-02-10 02:10:30 +01:00
} ;
void Tree : : set_hide_root ( bool p_enabled ) {
2022-03-16 08:50:48 +01:00
if ( hide_root = = p_enabled ) {
return ;
}
2015-08-31 00:37:23 +02:00
hide_root = p_enabled ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2024-04-24 03:58:12 +02:00
update_minimum_size ( ) ;
2014-02-10 02:10:30 +01:00
}
2018-01-11 23:35:12 +01:00
bool Tree : : is_root_hidden ( ) const {
return hide_root ;
}
2021-06-28 15:40:56 +02:00
void Tree : : set_column_custom_minimum_width ( int p_column , int p_min_width ) {
2014-02-10 02:10:30 +01:00
ERR_FAIL_INDEX ( p_column , columns . size ( ) ) ;
2022-03-16 08:50:48 +01:00
if ( columns [ p_column ] . custom_min_width = = p_min_width ) {
return ;
}
2021-06-28 15:40:56 +02:00
if ( p_min_width < 0 ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2021-06-28 15:40:56 +02:00
columns . write [ p_column ] . custom_min_width = p_min_width ;
2023-07-11 10:58:19 +02:00
columns . write [ p_column ] . cached_minimum_width_dirty = true ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2014-02-10 02:10:30 +01:00
}
2020-05-14 14:29:06 +02:00
2014-02-10 02:10:30 +01:00
void Tree : : set_column_expand ( int p_column , bool p_expand ) {
ERR_FAIL_INDEX ( p_column , columns . size ( ) ) ;
2015-08-31 00:37:23 +02:00
2022-03-16 08:50:48 +01:00
if ( columns [ p_column ] . expand = = p_expand ) {
return ;
}
2018-07-25 03:11:03 +02:00
columns . write [ p_column ] . expand = p_expand ;
2023-07-11 10:58:19 +02:00
columns . write [ p_column ] . cached_minimum_width_dirty = true ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2014-02-10 02:10:30 +01:00
}
2021-07-04 05:13:28 +02:00
void Tree : : set_column_expand_ratio ( int p_column , int p_ratio ) {
ERR_FAIL_INDEX ( p_column , columns . size ( ) ) ;
2022-03-16 08:50:48 +01:00
if ( columns [ p_column ] . expand_ratio = = p_ratio ) {
return ;
}
2021-07-04 05:13:28 +02:00
columns . write [ p_column ] . expand_ratio = p_ratio ;
2023-07-11 10:58:19 +02:00
columns . write [ p_column ] . cached_minimum_width_dirty = true ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2021-07-04 05:13:28 +02:00
}
void Tree : : set_column_clip_content ( int p_column , bool p_fit ) {
ERR_FAIL_INDEX ( p_column , columns . size ( ) ) ;
2022-03-16 08:50:48 +01:00
if ( columns [ p_column ] . clip_content = = p_fit ) {
return ;
}
2021-07-04 05:13:28 +02:00
columns . write [ p_column ] . clip_content = p_fit ;
2023-07-11 10:58:19 +02:00
columns . write [ p_column ] . cached_minimum_width_dirty = true ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2021-07-04 05:13:28 +02:00
}
bool Tree : : is_column_expanding ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , columns . size ( ) , false ) ;
return columns [ p_column ] . expand ;
}
2023-05-31 11:31:43 +02:00
2021-07-04 05:13:28 +02:00
int Tree : : get_column_expand_ratio ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , columns . size ( ) , 1 ) ;
return columns [ p_column ] . expand_ratio ;
}
bool Tree : : is_column_clipping_content ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , columns . size ( ) , false ) ;
return columns [ p_column ] . clip_content ;
}
2014-02-10 02:10:30 +01:00
TreeItem * Tree : : get_selected ( ) const {
return selected_item ;
}
2022-11-09 13:45:21 +01:00
void Tree : : set_selected ( TreeItem * p_item , int p_column ) {
ERR_FAIL_INDEX ( p_column , columns . size ( ) ) ;
2023-06-06 14:59:54 +02:00
ERR_FAIL_NULL ( p_item ) ;
2023-11-14 04:27:07 +01:00
ERR_FAIL_COND_MSG ( p_item - > get_tree ( ) ! = this , " The provided TreeItem does not belong to this Tree. Ensure that the TreeItem is a part of the Tree before setting it as selected. " ) ;
2022-11-09 13:45:21 +01:00
select_single_item ( p_item , get_root ( ) , p_column ) ;
}
2014-02-10 02:10:30 +01:00
int Tree : : get_selected_column ( ) const {
return selected_col ;
}
TreeItem * Tree : : get_edited ( ) const {
return edited_item ;
}
int Tree : : get_edited_column ( ) const {
return edited_col ;
}
TreeItem * Tree : : get_next_selected ( TreeItem * p_item ) {
2020-05-14 16:41:43 +02:00
if ( ! root ) {
2020-04-02 01:20:12 +02:00
return nullptr ;
2020-05-14 16:41:43 +02:00
}
2015-08-31 00:37:23 +02:00
2014-02-10 02:10:30 +01:00
while ( true ) {
if ( ! p_item ) {
p_item = root ;
} else {
2021-03-07 21:07:30 +01:00
if ( p_item - > first_child ) {
p_item = p_item - > first_child ;
2015-08-31 00:37:23 +02:00
2014-02-10 02:10:30 +01:00
} else if ( p_item - > next ) {
2015-08-31 00:37:23 +02:00
p_item = p_item - > next ;
2014-02-10 02:10:30 +01:00
} else {
while ( ! p_item - > next ) {
p_item = p_item - > parent ;
2020-05-14 16:41:43 +02:00
if ( p_item = = nullptr ) {
2020-04-02 01:20:12 +02:00
return nullptr ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2015-08-31 00:37:23 +02:00
2014-02-10 02:10:30 +01:00
p_item = p_item - > next ;
}
}
2015-08-31 00:37:23 +02:00
2020-05-14 16:41:43 +02:00
for ( int i = 0 ; i < columns . size ( ) ; i + + ) {
if ( p_item - > cells [ i ] . selected ) {
2014-02-10 02:10:30 +01:00
return p_item ;
2020-05-14 16:41:43 +02:00
}
}
2014-02-10 02:10:30 +01:00
}
2015-08-31 00:37:23 +02:00
2020-04-02 01:20:12 +02:00
return nullptr ;
2014-02-10 02:10:30 +01:00
}
2021-06-28 15:40:56 +02:00
int Tree : : get_column_minimum_width ( int p_column ) const {
2014-02-10 02:10:30 +01:00
ERR_FAIL_INDEX_V ( p_column , columns . size ( ) , - 1 ) ;
2015-08-31 00:37:23 +02:00
2023-07-11 10:58:19 +02:00
if ( columns [ p_column ] . cached_minimum_width_dirty ) {
// Use the custom minimum width.
int min_width = columns [ p_column ] . custom_min_width ;
2021-07-04 05:13:28 +02:00
2023-07-11 10:58:19 +02:00
// Check if the visible title of the column is wider.
if ( show_column_titles ) {
2024-04-23 09:46:19 +02:00
const float padding = theme_cache . title_button - > get_margin ( SIDE_LEFT ) + theme_cache . title_button - > get_margin ( SIDE_RIGHT ) ;
min_width = MAX ( theme_cache . font - > get_string_size ( columns [ p_column ] . xl_title , HORIZONTAL_ALIGNMENT_LEFT , - 1 , theme_cache . font_size ) . width + padding , min_width ) ;
2023-07-11 10:58:19 +02:00
}
2024-04-24 03:58:12 +02:00
if ( root & & ! columns [ p_column ] . clip_content ) {
int depth = 1 ;
TreeItem * last = nullptr ;
TreeItem * first = hide_root ? root - > get_next_visible ( ) : root ;
for ( TreeItem * item = first ; item ; last = item , item = item - > get_next_visible ( ) ) {
// Get column indentation.
int indent ;
if ( p_column = = 0 ) {
if ( last ) {
if ( item - > parent = = last ) {
depth + = 1 ;
} else if ( item - > parent ! = last - > parent ) {
depth = hide_root ? 0 : 1 ;
for ( TreeItem * iter = item - > parent ; iter ; iter = iter - > parent ) {
depth + = 1 ;
}
2023-07-11 10:58:19 +02:00
}
2021-06-28 15:40:56 +02:00
}
2024-04-24 03:58:12 +02:00
indent = theme_cache . item_margin * depth ;
} else {
indent = theme_cache . h_separation ;
2021-06-28 15:40:56 +02:00
}
2023-07-11 10:58:19 +02:00
// Get the item minimum size.
Size2 item_size = item - > get_minimum_size ( p_column ) ;
2024-04-24 03:58:12 +02:00
item_size . width + = indent ;
2021-09-24 10:11:44 +02:00
2023-07-11 10:58:19 +02:00
// Check if the item is wider.
min_width = MAX ( min_width , item_size . width ) ;
}
2021-06-28 15:40:56 +02:00
}
2023-07-11 10:58:19 +02:00
columns . get ( p_column ) . cached_minimum_width = min_width ;
columns . get ( p_column ) . cached_minimum_width_dirty = false ;
2020-05-14 16:41:43 +02:00
}
2021-07-04 05:13:28 +02:00
2023-07-11 10:58:19 +02:00
return columns [ p_column ] . cached_minimum_width ;
2021-06-28 15:40:56 +02:00
}
2015-08-31 00:37:23 +02:00
2021-06-28 15:40:56 +02:00
int Tree : : get_column_width ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , columns . size ( ) , - 1 ) ;
2021-03-17 20:10:36 +01:00
2021-07-04 05:13:28 +02:00
int column_width = get_column_minimum_width ( p_column ) ;
2021-06-28 15:40:56 +02:00
if ( columns [ p_column ] . expand ) {
2023-01-04 03:59:34 +01:00
int expand_area = _get_content_rect ( ) . size . width ;
2021-06-28 15:40:56 +02:00
int expanding_total = 0 ;
2015-08-31 00:37:23 +02:00
2021-06-28 15:40:56 +02:00
for ( int i = 0 ; i < columns . size ( ) ; i + + ) {
2021-07-04 05:13:28 +02:00
expand_area - = get_column_minimum_width ( i ) ;
if ( columns [ i ] . expand ) {
expanding_total + = columns [ i ] . expand_ratio ;
2021-06-28 15:40:56 +02:00
}
2014-02-10 02:10:30 +01:00
}
2021-07-04 05:13:28 +02:00
if ( expand_area > = expanding_total & & expanding_total > 0 ) {
column_width + = expand_area * columns [ p_column ] . expand_ratio / expanding_total ;
2021-06-28 15:40:56 +02:00
}
2021-07-04 05:13:28 +02:00
}
2015-08-31 00:37:23 +02:00
2021-07-04 05:13:28 +02:00
return column_width ;
2014-02-10 02:10:30 +01:00
}
void Tree : : propagate_set_columns ( TreeItem * p_item ) {
p_item - > cells . resize ( columns . size ( ) ) ;
2015-08-31 00:37:23 +02:00
2021-03-07 21:07:30 +01:00
TreeItem * c = p_item - > get_first_child ( ) ;
2014-02-10 02:10:30 +01:00
while ( c ) {
propagate_set_columns ( c ) ;
2020-09-03 13:22:16 +02:00
c = c - > next ;
2014-02-10 02:10:30 +01:00
}
}
void Tree : : set_columns ( int p_columns ) {
ERR_FAIL_COND ( p_columns < 1 ) ;
ERR_FAIL_COND ( blocked > 0 ) ;
columns . resize ( p_columns ) ;
2015-08-31 00:37:23 +02:00
2020-05-14 16:41:43 +02:00
if ( root ) {
2014-02-10 02:10:30 +01:00
propagate_set_columns ( root ) ;
2020-05-14 16:41:43 +02:00
}
if ( selected_col > = p_columns ) {
2014-02-10 02:10:30 +01:00
selected_col = p_columns - 1 ;
2020-05-14 16:41:43 +02:00
}
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2014-02-10 02:10:30 +01:00
}
int Tree : : get_columns ( ) const {
return columns . size ( ) ;
}
void Tree : : _scroll_moved ( float ) {
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2014-02-10 02:10:30 +01:00
}
Rect2 Tree : : get_custom_popup_rect ( ) const {
return custom_popup_rect ;
}
int Tree : : get_item_offset ( TreeItem * p_item ) const {
TreeItem * it = root ;
int ofs = _get_title_button_height ( ) ;
2020-05-14 16:41:43 +02:00
if ( ! it ) {
2014-02-10 02:10:30 +01:00
return 0 ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
while ( true ) {
2020-05-14 16:41:43 +02:00
if ( it = = p_item ) {
2014-02-10 02:10:30 +01:00
return ofs ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2024-02-13 22:27:15 +01:00
if ( ( it ! = root | | ! hide_root ) & & it - > is_visible_in_tree ( ) ) {
2023-04-12 11:49:52 +02:00
ofs + = compute_item_height ( it ) ;
2022-11-30 16:06:14 +01:00
ofs + = theme_cache . v_separation ;
2020-01-02 02:20:43 +01:00
}
2014-02-10 02:10:30 +01:00
2021-03-07 21:07:30 +01:00
if ( it - > first_child & & ! it - > collapsed ) {
it = it - > first_child ;
2014-02-10 02:10:30 +01:00
} else if ( it - > next ) {
it = it - > next ;
} else {
while ( ! it - > next ) {
it = it - > parent ;
2020-05-14 16:41:43 +02:00
if ( it = = nullptr ) {
2014-02-10 02:10:30 +01:00
return 0 ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
it = it - > next ;
}
}
return - 1 ; //not found
}
void Tree : : ensure_cursor_is_visible ( ) {
2020-01-03 11:29:22 +01:00
if ( ! is_inside_tree ( ) ) {
2014-02-10 02:10:30 +01:00
return ;
2020-01-03 11:29:22 +01:00
}
if ( ! selected_item | | ( selected_col = = - 1 ) ) {
return ; // Nothing under cursor.
}
2014-02-10 02:10:30 +01:00
2022-11-11 16:27:28 +01:00
// Note: Code below similar to Tree::scroll_to_item(), in case of bug fix both.
2023-01-04 03:59:34 +01:00
const Size2 area_size = _get_content_rect ( ) . size ;
2020-01-01 15:20:12 +01:00
2020-01-03 11:29:22 +01:00
int y_offset = get_item_offset ( selected_item ) ;
if ( y_offset ! = - 1 ) {
const int tbh = _get_title_button_height ( ) ;
y_offset - = tbh ;
2020-01-01 15:20:12 +01:00
2022-11-30 16:06:14 +01:00
const int cell_h = compute_item_height ( selected_item ) + theme_cache . v_separation ;
2022-11-11 16:27:28 +01:00
int screen_h = area_size . height - tbh ;
2014-02-10 02:10:30 +01:00
2020-01-03 11:29:22 +01:00
if ( cell_h > screen_h ) { // Screen size is too small, maybe it was not resized yet.
v_scroll - > set_value ( y_offset ) ;
} else if ( y_offset + cell_h > v_scroll - > get_value ( ) + screen_h ) {
2023-12-18 15:46:56 +01:00
callable_mp ( ( Range * ) v_scroll , & Range : : set_value ) . call_deferred ( y_offset - screen_h + cell_h ) ;
2020-01-03 11:29:22 +01:00
} else if ( y_offset < v_scroll - > get_value ( ) ) {
v_scroll - > set_value ( y_offset ) ;
}
}
if ( select_mode ! = SELECT_ROW ) { // Cursor always at col 0 in this mode.
int x_offset = 0 ;
for ( int i = 0 ; i < selected_col ; i + + ) {
x_offset + = get_column_width ( i ) ;
}
const int cell_w = get_column_width ( selected_col ) ;
2023-01-04 03:59:34 +01:00
const int screen_w = area_size . width ;
2020-01-03 11:29:22 +01:00
if ( cell_w > screen_w ) {
h_scroll - > set_value ( x_offset ) ;
} else if ( x_offset + cell_w > h_scroll - > get_value ( ) + screen_w ) {
2023-12-18 15:46:56 +01:00
callable_mp ( ( Range * ) h_scroll , & Range : : set_value ) . call_deferred ( x_offset - screen_w + cell_w ) ;
2020-01-03 11:29:22 +01:00
} else if ( x_offset < h_scroll - > get_value ( ) ) {
h_scroll - > set_value ( x_offset ) ;
}
2019-04-12 04:21:48 +02:00
}
2014-02-10 02:10:30 +01:00
}
int Tree : : get_pressed_button ( ) const {
return pressed_button ;
}
2022-04-07 13:49:28 +02:00
Rect2 Tree : : get_item_rect ( TreeItem * p_item , int p_column , int p_button ) const {
2014-02-10 02:10:30 +01:00
ERR_FAIL_NULL_V ( p_item , Rect2 ( ) ) ;
ERR_FAIL_COND_V ( p_item - > tree ! = this , Rect2 ( ) ) ;
if ( p_column ! = - 1 ) {
ERR_FAIL_INDEX_V ( p_column , columns . size ( ) , Rect2 ( ) ) ;
}
2022-04-07 13:49:28 +02:00
if ( p_button ! = - 1 ) {
ERR_FAIL_COND_V ( p_column = = - 1 , Rect2 ( ) ) ; // pass a column if you want to pass a button
ERR_FAIL_INDEX_V ( p_button , p_item - > cells [ p_column ] . buttons . size ( ) , Rect2 ( ) ) ;
}
2014-02-10 02:10:30 +01:00
int ofs = get_item_offset ( p_item ) ;
int height = compute_item_height ( p_item ) ;
Rect2 r ;
2017-06-04 00:25:13 +02:00
r . position . y = ofs ;
2014-02-10 02:10:30 +01:00
r . size . height = height ;
if ( p_column = = - 1 ) {
2017-06-04 00:25:13 +02:00
r . position . x = 0 ;
2014-02-10 02:10:30 +01:00
r . size . x = get_size ( ) . width ;
} else {
int accum = 0 ;
for ( int i = 0 ; i < p_column ; i + + ) {
accum + = get_column_width ( i ) ;
}
2017-06-04 00:25:13 +02:00
r . position . x = accum ;
2014-02-10 02:10:30 +01:00
r . size . x = get_column_width ( p_column ) ;
2022-04-07 13:49:28 +02:00
if ( p_button ! = - 1 ) {
const TreeItem : : Cell & c = p_item - > cells [ p_column ] ;
Vector2 ofst = Vector2 ( r . position . x + r . size . x , r . position . y ) ;
for ( int j = c . buttons . size ( ) - 1 ; j > = 0 ; j - - ) {
Ref < Texture2D > b = c . buttons [ j ] . texture ;
2022-08-31 14:02:40 +02:00
Size2 size = b - > get_size ( ) + theme_cache . button_pressed - > get_minimum_size ( ) ;
2022-04-07 13:49:28 +02:00
ofst . x - = size . x ;
if ( j = = p_button ) {
return Rect2 ( ofst , size ) ;
}
}
}
2014-02-10 02:10:30 +01:00
}
return r ;
}
void Tree : : set_column_titles_visible ( bool p_show ) {
2022-03-16 08:50:48 +01:00
if ( show_column_titles = = p_show ) {
return ;
}
2014-02-10 02:10:30 +01:00
show_column_titles = p_show ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2024-04-24 03:58:12 +02:00
update_minimum_size ( ) ;
2014-02-10 02:10:30 +01:00
}
bool Tree : : are_column_titles_visible ( ) const {
return show_column_titles ;
}
void Tree : : set_column_title ( int p_column , const String & p_title ) {
ERR_FAIL_INDEX ( p_column , columns . size ( ) ) ;
2022-03-16 08:50:48 +01:00
if ( columns [ p_column ] . title = = p_title ) {
return ;
}
2018-07-25 03:11:03 +02:00
columns . write [ p_column ] . title = p_title ;
2024-03-01 05:27:36 +01:00
columns . write [ p_column ] . xl_title = atr ( p_title ) ;
2020-09-03 13:22:16 +02:00
update_column ( p_column ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2014-02-10 02:10:30 +01:00
}
String Tree : : get_column_title ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , columns . size ( ) , " " ) ;
return columns [ p_column ] . title ;
}
2023-03-26 03:13:31 +02:00
void Tree : : set_column_title_alignment ( int p_column , HorizontalAlignment p_alignment ) {
ERR_FAIL_INDEX ( p_column , columns . size ( ) ) ;
if ( p_alignment = = HORIZONTAL_ALIGNMENT_FILL ) {
WARN_PRINT ( " HORIZONTAL_ALIGNMENT_FILL is not supported for column titles. " ) ;
}
if ( columns [ p_column ] . title_alignment = = p_alignment ) {
return ;
}
columns . write [ p_column ] . title_alignment = p_alignment ;
update_column ( p_column ) ;
queue_redraw ( ) ;
}
HorizontalAlignment Tree : : get_column_title_alignment ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , columns . size ( ) , HorizontalAlignment : : HORIZONTAL_ALIGNMENT_CENTER ) ;
return columns [ p_column ] . title_alignment ;
}
2020-09-03 13:22:16 +02:00
void Tree : : set_column_title_direction ( int p_column , Control : : TextDirection p_text_direction ) {
ERR_FAIL_INDEX ( p_column , columns . size ( ) ) ;
ERR_FAIL_COND ( ( int ) p_text_direction < - 1 | | ( int ) p_text_direction > 3 ) ;
if ( columns [ p_column ] . text_direction ! = p_text_direction ) {
columns . write [ p_column ] . text_direction = p_text_direction ;
update_column ( p_column ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2020-09-03 13:22:16 +02:00
}
}
Control : : TextDirection Tree : : get_column_title_direction ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , columns . size ( ) , TEXT_DIRECTION_INHERITED ) ;
return columns [ p_column ] . text_direction ;
}
void Tree : : set_column_title_language ( int p_column , const String & p_language ) {
ERR_FAIL_INDEX ( p_column , columns . size ( ) ) ;
if ( columns [ p_column ] . language ! = p_language ) {
columns . write [ p_column ] . language = p_language ;
update_column ( p_column ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2020-09-03 13:22:16 +02:00
}
}
String Tree : : get_column_title_language ( int p_column ) const {
ERR_FAIL_INDEX_V ( p_column , columns . size ( ) , " " ) ;
return columns [ p_column ] . language ;
}
2014-02-10 02:10:30 +01:00
Point2 Tree : : get_scroll ( ) const {
Point2 ofs ;
2020-05-14 16:41:43 +02:00
if ( h_scroll - > is_visible_in_tree ( ) ) {
2017-01-04 05:16:14 +01:00
ofs . x = h_scroll - > get_value ( ) ;
2020-05-14 16:41:43 +02:00
}
if ( v_scroll - > is_visible_in_tree ( ) ) {
2017-01-04 05:16:14 +01:00
ofs . y = v_scroll - > get_value ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
return ofs ;
}
2020-07-05 20:06:51 +02:00
void Tree : : scroll_to_item ( TreeItem * p_item , bool p_center_on_item ) {
2022-05-27 04:56:52 +02:00
ERR_FAIL_NULL ( p_item ) ;
2017-11-04 20:21:41 +01:00
update_scrollbars ( ) ;
2022-11-11 16:27:28 +01:00
// Note: Code below similar to Tree::ensure_cursor_is_visible(), in case of bug fix both.
2023-01-04 03:59:34 +01:00
const Size2 area_size = _get_content_rect ( ) . size ;
2017-11-04 20:21:41 +01:00
2022-11-11 16:27:28 +01:00
int y_offset = get_item_offset ( p_item ) ;
if ( y_offset ! = - 1 ) {
const int tbh = _get_title_button_height ( ) ;
y_offset - = tbh ;
2022-11-30 16:06:14 +01:00
const int cell_h = compute_item_height ( p_item ) + theme_cache . v_separation ;
2022-11-11 16:27:28 +01:00
int screen_h = area_size . height - tbh ;
if ( p_center_on_item ) {
v_scroll - > set_value ( y_offset - ( screen_h - cell_h ) / 2.0f ) ;
2020-07-05 20:06:51 +02:00
} else {
2022-11-11 16:27:28 +01:00
if ( cell_h > screen_h ) { // Screen size is too small, maybe it was not resized yet.
v_scroll - > set_value ( y_offset ) ;
} else if ( y_offset + cell_h > v_scroll - > get_value ( ) + screen_h ) {
v_scroll - > set_value ( y_offset - screen_h + cell_h ) ;
} else if ( y_offset < v_scroll - > get_value ( ) ) {
v_scroll - > set_value ( y_offset ) ;
2020-07-05 20:06:51 +02:00
}
}
2017-11-04 20:21:41 +01:00
}
}
2021-06-25 21:19:46 +02:00
void Tree : : set_h_scroll_enabled ( bool p_enable ) {
2022-03-16 08:50:48 +01:00
if ( h_scroll_enabled = = p_enable ) {
return ;
}
2021-06-25 21:19:46 +02:00
h_scroll_enabled = p_enable ;
2021-12-06 14:02:34 +01:00
update_minimum_size ( ) ;
2021-06-25 21:19:46 +02:00
}
bool Tree : : is_h_scroll_enabled ( ) const {
return h_scroll_enabled ;
}
void Tree : : set_v_scroll_enabled ( bool p_enable ) {
2022-03-16 08:50:48 +01:00
if ( v_scroll_enabled = = p_enable ) {
return ;
}
2021-06-25 21:19:46 +02:00
v_scroll_enabled = p_enable ;
2021-12-06 14:02:34 +01:00
update_minimum_size ( ) ;
2021-06-25 21:19:46 +02:00
}
bool Tree : : is_v_scroll_enabled ( ) const {
return v_scroll_enabled ;
}
2014-02-10 02:10:30 +01:00
TreeItem * Tree : : _search_item_text ( TreeItem * p_at , const String & p_find , int * r_col , bool p_selectable , bool p_backwards ) {
2019-05-11 18:32:53 +02:00
TreeItem * from = p_at ;
2020-07-20 00:53:46 +02:00
TreeItem * loop = nullptr ; // Safe-guard against infinite loop.
2014-02-10 02:10:30 +01:00
while ( p_at ) {
for ( int i = 0 ; i < columns . size ( ) ; i + + ) {
if ( p_at - > get_text ( i ) . findn ( p_find ) = = 0 & & ( ! p_selectable | | p_at - > is_selectable ( i ) ) ) {
2020-05-14 16:41:43 +02:00
if ( r_col ) {
2014-02-10 02:10:30 +01:00
* r_col = i ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
return p_at ;
}
}
2020-05-14 16:41:43 +02:00
if ( p_backwards ) {
2019-05-11 18:32:53 +02:00
p_at = p_at - > get_prev_visible ( true ) ;
2020-05-14 16:41:43 +02:00
} else {
2019-05-11 18:32:53 +02:00
p_at = p_at - > get_next_visible ( true ) ;
2020-05-14 16:41:43 +02:00
}
2019-05-11 18:32:53 +02:00
2020-05-14 16:41:43 +02:00
if ( ( p_at ) = = from ) {
2019-05-11 18:32:53 +02:00
break ;
2020-05-14 16:41:43 +02:00
}
2020-07-20 00:53:46 +02:00
if ( ! loop ) {
loop = p_at ;
} else if ( loop = = p_at ) {
break ;
}
2014-02-10 02:10:30 +01:00
}
2020-04-02 01:20:12 +02:00
return nullptr ;
2014-02-10 02:10:30 +01:00
}
TreeItem * Tree : : search_item_text ( const String & p_find , int * r_col , bool p_selectable ) {
2019-06-04 01:50:50 +02:00
TreeItem * from = get_selected ( ) ;
2019-05-11 18:32:53 +02:00
2020-05-14 16:41:43 +02:00
if ( ! from ) {
2019-05-11 18:32:53 +02:00
from = root ;
2020-05-14 16:41:43 +02:00
}
if ( ! from ) {
2020-04-02 01:20:12 +02:00
return nullptr ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2019-06-04 01:50:50 +02:00
return _search_item_text ( from - > get_next_visible ( true ) , p_find , r_col , p_selectable ) ;
2014-02-10 02:10:30 +01:00
}
2020-02-02 04:07:01 +01:00
TreeItem * Tree : : get_item_with_text ( const String & p_find ) const {
for ( TreeItem * current = root ; current ; current = current - > get_next_visible ( ) ) {
for ( int i = 0 ; i < columns . size ( ) ; i + + ) {
if ( current - > get_text ( i ) = = p_find ) {
return current ;
}
}
}
2020-04-02 01:20:12 +02:00
return nullptr ;
2020-02-02 04:07:01 +01:00
}
2023-05-11 04:17:03 +02:00
TreeItem * Tree : : get_item_with_metadata ( const Variant & p_find , int p_column ) const {
if ( p_column < 0 ) {
for ( TreeItem * current = root ; current ; current = current - > get_next_in_tree ( ) ) {
for ( int i = 0 ; i < columns . size ( ) ; i + + ) {
if ( current - > get_metadata ( i ) = = p_find ) {
return current ;
}
}
}
return nullptr ;
}
for ( TreeItem * current = root ; current ; current = current - > get_next_in_tree ( ) ) {
if ( current - > get_metadata ( p_column ) = = p_find ) {
return current ;
}
}
return nullptr ;
}
2014-02-10 02:10:30 +01:00
void Tree : : _do_incr_search ( const String & p_add ) {
uint64_t time = OS : : get_singleton ( ) - > get_ticks_usec ( ) / 1000 ; // convert to msec
uint64_t diff = time - last_keypress ;
2022-10-20 15:43:17 +02:00
if ( diff > uint64_t ( GLOBAL_GET ( " gui/timers/incremental_search_max_interval_msec " ) ) ) {
2014-02-10 02:10:30 +01:00
incr_search = p_add ;
2020-05-14 16:41:43 +02:00
} else if ( incr_search ! = p_add ) {
2014-02-10 02:10:30 +01:00
incr_search + = p_add ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
last_keypress = time ;
int col ;
TreeItem * item = search_item_text ( incr_search , & col , true ) ;
2020-05-14 16:41:43 +02:00
if ( ! item ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-01-07 21:04:23 +01:00
if ( select_mode = = SELECT_MULTI ) {
item - > set_as_cursor ( col ) ;
} else {
item - > select ( col ) ;
}
2014-02-10 02:10:30 +01:00
ensure_cursor_is_visible ( ) ;
}
2016-05-11 16:46:08 +02:00
TreeItem * Tree : : _find_item_at_pos ( TreeItem * p_item , const Point2 & p_pos , int & r_column , int & h , int & section ) const {
2014-02-10 02:10:30 +01:00
Point2 pos = p_pos ;
2024-02-13 22:27:15 +01:00
if ( ( root ! = p_item | | ! hide_root ) & & p_item - > is_visible_in_tree ( ) ) {
2022-11-30 16:06:14 +01:00
h = compute_item_height ( p_item ) + theme_cache . v_separation ;
2014-02-10 02:10:30 +01:00
if ( pos . y < h ) {
2016-05-11 16:46:08 +02:00
if ( drop_mode_flags = = DROP_MODE_ON_ITEM ) {
section = 0 ;
} else if ( drop_mode_flags = = DROP_MODE_INBETWEEN ) {
section = pos . y < h / 2 ? - 1 : 1 ;
} else if ( pos . y < h / 4 ) {
section = - 1 ;
} else if ( pos . y > = ( h * 3 / 4 ) ) {
section = 1 ;
} else {
section = 0 ;
}
2014-02-10 02:10:30 +01:00
for ( int i = 0 ; i < columns . size ( ) ; i + + ) {
int w = get_column_width ( i ) ;
if ( pos . x < w ) {
r_column = i ;
2016-05-11 16:46:08 +02:00
2014-02-10 02:10:30 +01:00
return p_item ;
}
pos . x - = w ;
}
2016-05-11 16:46:08 +02:00
2020-04-02 01:20:12 +02:00
return nullptr ;
2014-02-10 02:10:30 +01:00
} else {
pos . y - = h ;
}
} else {
h = 0 ;
}
2024-02-13 22:27:15 +01:00
if ( p_item - > is_collapsed ( ) | | ! p_item - > is_visible_in_tree ( ) ) {
2020-04-02 01:20:12 +02:00
return nullptr ; // do not try children, it's collapsed
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2021-03-07 21:07:30 +01:00
TreeItem * n = p_item - > get_first_child ( ) ;
2014-02-10 02:10:30 +01:00
while ( n ) {
int ch ;
2016-05-11 16:46:08 +02:00
TreeItem * r = _find_item_at_pos ( n , pos , r_column , ch , section ) ;
2014-02-10 02:10:30 +01:00
pos . y - = ch ;
h + = ch ;
2020-05-14 16:41:43 +02:00
if ( r ) {
2014-02-10 02:10:30 +01:00
return r ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
n = n - > get_next ( ) ;
}
2020-04-02 01:20:12 +02:00
return nullptr ;
2014-02-10 02:10:30 +01:00
}
2024-04-18 09:23:31 +02:00
// When on a button, r_index is valid.
// When on an item, both r_item and r_column are valid.
// Otherwise, all output arguments are invalid.
void Tree : : _find_button_at_pos ( const Point2 & p_pos , TreeItem * & r_item , int & r_column , int & r_index ) const {
r_item = nullptr ;
r_column = - 1 ;
r_index = - 1 ;
if ( ! root ) {
return ;
}
Point2 pos = p_pos - theme_cache . panel_style - > get_offset ( ) ;
pos . y - = _get_title_button_height ( ) ;
if ( pos . y < 0 ) {
return ;
}
if ( cache . rtl ) {
pos . x = get_size ( ) . width - pos . x ;
}
pos + = theme_cache . offset ; // Scrolling.
int col , h , section ;
TreeItem * it = _find_item_at_pos ( root , pos , col , h , section ) ;
if ( ! it ) {
return ;
}
r_item = it ;
r_column = col ;
const TreeItem : : Cell & c = it - > cells [ col ] ;
if ( c . buttons . is_empty ( ) ) {
return ;
}
int x_limit = get_size ( ) . width - theme_cache . panel_style - > get_minimum_size ( ) . width + theme_cache . offset . x ;
if ( v_scroll - > is_visible_in_tree ( ) ) {
x_limit - = v_scroll - > get_minimum_size ( ) . width ;
}
for ( int i = 0 ; i < col ; i + + ) {
const int col_w = get_column_width ( i ) + theme_cache . h_separation ;
pos . x - = col_w ;
x_limit - = col_w ;
}
int x_check ;
if ( cache . rtl ) {
x_check = get_column_width ( col ) ;
} else {
// Right edge of the buttons area, relative to the start of the column.
int buttons_area_min = 0 ;
if ( col = = 0 ) {
// Content of column 0 should take indentation into account.
for ( TreeItem * current = it ; current & & ( current ! = root | | ! hide_root ) ; current = current - > parent ) {
buttons_area_min + = theme_cache . item_margin ;
}
}
for ( int i = c . buttons . size ( ) - 1 ; i > = 0 ; i - - ) {
Ref < Texture2D > b = c . buttons [ i ] . texture ;
buttons_area_min + = b - > get_size ( ) . width + theme_cache . button_pressed - > get_minimum_size ( ) . width + theme_cache . button_margin ;
}
x_check = MAX ( buttons_area_min , MIN ( get_column_width ( col ) , x_limit ) ) ;
}
for ( int i = c . buttons . size ( ) - 1 ; i > = 0 ; i - - ) {
Ref < Texture2D > b = c . buttons [ i ] . texture ;
Size2 size = b - > get_size ( ) + theme_cache . button_pressed - > get_minimum_size ( ) ;
if ( pos . x > x_check - size . width ) {
x_limit - = theme_cache . item_margin ;
r_index = i ;
return ;
}
x_check - = size . width + theme_cache . button_margin ;
}
}
2017-09-10 15:37:49 +02:00
int Tree : : get_column_at_position ( const Point2 & p_pos ) const {
2016-05-11 16:46:08 +02:00
if ( root ) {
Point2 pos = p_pos ;
2020-09-03 13:22:16 +02:00
if ( is_layout_rtl ( ) ) {
pos . x = get_size ( ) . width - pos . x ;
}
2022-09-06 19:09:32 +02:00
pos - = theme_cache . panel_style - > get_offset ( ) ;
2016-05-11 16:46:08 +02:00
pos . y - = _get_title_button_height ( ) ;
2020-05-14 16:41:43 +02:00
if ( pos . y < 0 ) {
2016-05-11 16:46:08 +02:00
return - 1 ;
2020-05-14 16:41:43 +02:00
}
2016-05-11 16:46:08 +02:00
2020-05-14 16:41:43 +02:00
if ( h_scroll - > is_visible_in_tree ( ) ) {
2017-01-04 05:16:14 +01:00
pos . x + = h_scroll - > get_value ( ) ;
2020-05-14 16:41:43 +02:00
}
if ( v_scroll - > is_visible_in_tree ( ) ) {
2017-01-04 05:16:14 +01:00
pos . y + = v_scroll - > get_value ( ) ;
2020-05-14 16:41:43 +02:00
}
2016-05-11 16:46:08 +02:00
int col , h , section ;
TreeItem * it = _find_item_at_pos ( root , pos , col , h , section ) ;
if ( it ) {
return col ;
}
}
return - 1 ;
}
2017-09-10 15:37:49 +02:00
int Tree : : get_drop_section_at_position ( const Point2 & p_pos ) const {
2016-05-11 16:46:08 +02:00
if ( root ) {
Point2 pos = p_pos ;
2020-09-03 13:22:16 +02:00
if ( is_layout_rtl ( ) ) {
pos . x = get_size ( ) . width - pos . x ;
}
2022-09-06 19:09:32 +02:00
pos - = theme_cache . panel_style - > get_offset ( ) ;
2016-05-11 16:46:08 +02:00
pos . y - = _get_title_button_height ( ) ;
2020-05-14 16:41:43 +02:00
if ( pos . y < 0 ) {
2016-05-11 16:46:08 +02:00
return - 100 ;
2020-05-14 16:41:43 +02:00
}
2016-05-11 16:46:08 +02:00
2020-05-14 16:41:43 +02:00
if ( h_scroll - > is_visible_in_tree ( ) ) {
2017-01-04 05:16:14 +01:00
pos . x + = h_scroll - > get_value ( ) ;
2020-05-14 16:41:43 +02:00
}
if ( v_scroll - > is_visible_in_tree ( ) ) {
2017-01-04 05:16:14 +01:00
pos . y + = v_scroll - > get_value ( ) ;
2020-05-14 16:41:43 +02:00
}
2016-05-11 16:46:08 +02:00
int col , h , section ;
TreeItem * it = _find_item_at_pos ( root , pos , col , h , section ) ;
if ( it ) {
return section ;
}
}
return - 100 ;
}
2020-05-14 14:29:06 +02:00
2024-07-16 08:23:44 +02:00
bool Tree : : can_drop_data ( const Point2 & p_point , const Variant & p_data ) const {
if ( drag_touching ) {
// Disable data drag & drop when touch dragging.
return false ;
}
return Control : : can_drop_data ( p_point , p_data ) ;
}
Variant Tree : : get_drag_data ( const Point2 & p_point ) {
if ( drag_touching ) {
// Disable data drag & drop when touch dragging.
return Variant ( ) ;
}
return Control : : get_drag_data ( p_point ) ;
}
2017-09-10 15:37:49 +02:00
TreeItem * Tree : : get_item_at_position ( const Point2 & p_pos ) const {
2016-05-11 16:46:08 +02:00
if ( root ) {
Point2 pos = p_pos ;
2020-09-03 13:22:16 +02:00
if ( is_layout_rtl ( ) ) {
pos . x = get_size ( ) . width - pos . x ;
}
2022-09-06 19:09:32 +02:00
pos - = theme_cache . panel_style - > get_offset ( ) ;
2016-05-11 16:46:08 +02:00
pos . y - = _get_title_button_height ( ) ;
2020-05-14 16:41:43 +02:00
if ( pos . y < 0 ) {
2020-04-02 01:20:12 +02:00
return nullptr ;
2020-05-14 16:41:43 +02:00
}
2016-05-11 16:46:08 +02:00
2020-05-14 16:41:43 +02:00
if ( h_scroll - > is_visible_in_tree ( ) ) {
2017-01-04 05:16:14 +01:00
pos . x + = h_scroll - > get_value ( ) ;
2020-05-14 16:41:43 +02:00
}
if ( v_scroll - > is_visible_in_tree ( ) ) {
2017-01-04 05:16:14 +01:00
pos . y + = v_scroll - > get_value ( ) ;
2020-05-14 16:41:43 +02:00
}
2016-05-11 16:46:08 +02:00
int col , h , section ;
TreeItem * it = _find_item_at_pos ( root , pos , col , h , section ) ;
if ( it ) {
return it ;
}
}
2020-04-02 01:20:12 +02:00
return nullptr ;
2016-05-11 16:46:08 +02:00
}
2019-12-13 06:13:47 +01:00
int Tree : : get_button_id_at_position ( const Point2 & p_pos ) const {
2024-04-18 09:23:31 +02:00
TreeItem * it ;
int col , index ;
_find_button_at_pos ( p_pos , it , col , index ) ;
2019-12-13 06:13:47 +01:00
2024-04-18 09:23:31 +02:00
if ( index = = - 1 ) {
return - 1 ;
2019-12-13 06:13:47 +01:00
}
2024-04-18 09:23:31 +02:00
return it - > cells [ col ] . buttons [ index ] . id ;
2019-12-13 06:13:47 +01:00
}
2014-02-10 02:10:30 +01:00
String Tree : : get_tooltip ( const Point2 & p_pos ) const {
2024-04-18 09:23:31 +02:00
Point2 pos = p_pos - theme_cache . panel_style - > get_offset ( ) ;
pos . y - = _get_title_button_height ( ) ;
if ( pos . y < 0 ) {
return Control : : get_tooltip ( p_pos ) ;
}
2014-02-10 02:10:30 +01:00
2024-04-18 09:23:31 +02:00
TreeItem * it ;
int col , index ;
_find_button_at_pos ( p_pos , it , col , index ) ;
2014-02-10 02:10:30 +01:00
2024-04-18 09:23:31 +02:00
if ( index ! = - 1 ) {
return it - > cells [ col ] . buttons [ index ] . tooltip ;
}
2024-04-18 11:35:26 +02:00
2024-04-18 09:23:31 +02:00
if ( it ) {
const String item_tooltip = it - > get_tooltip_text ( col ) ;
if ( item_tooltip . is_empty ( ) ) {
return it - > get_text ( col ) ;
2014-02-10 02:10:30 +01:00
}
2024-04-18 09:23:31 +02:00
return item_tooltip ;
2014-02-10 02:10:30 +01:00
}
return Control : : get_tooltip ( p_pos ) ;
}
void Tree : : set_cursor_can_exit_tree ( bool p_enable ) {
cursor_can_exit_tree = p_enable ;
}
2015-11-14 00:56:44 +01:00
void Tree : : set_hide_folding ( bool p_hide ) {
2022-03-16 08:50:48 +01:00
if ( hide_folding = = p_hide ) {
return ;
}
2015-11-14 00:56:44 +01:00
hide_folding = p_hide ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2015-11-14 00:56:44 +01:00
}
bool Tree : : is_folding_hidden ( ) const {
return hide_folding ;
}
2022-07-01 15:43:39 +02:00
void Tree : : set_enable_recursive_folding ( bool p_enable ) {
enable_recursive_folding = p_enable ;
}
bool Tree : : is_recursive_folding_enabled ( ) const {
return enable_recursive_folding ;
}
2016-05-11 16:46:08 +02:00
void Tree : : set_drop_mode_flags ( int p_flags ) {
2020-05-14 16:41:43 +02:00
if ( drop_mode_flags = = p_flags ) {
2016-05-12 01:57:52 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-05-11 16:46:08 +02:00
drop_mode_flags = p_flags ;
if ( drop_mode_flags = = 0 ) {
2020-04-02 01:20:12 +02:00
drop_mode_over = nullptr ;
2016-05-11 16:46:08 +02:00
}
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2016-05-11 16:46:08 +02:00
}
int Tree : : get_drop_mode_flags ( ) const {
return drop_mode_flags ;
}
2017-01-21 23:00:25 +01:00
void Tree : : set_edit_checkbox_cell_only_when_checkbox_is_pressed ( bool p_enable ) {
force_edit_checkbox_only_on_checkbox = p_enable ;
}
bool Tree : : get_edit_checkbox_cell_only_when_checkbox_is_pressed ( ) const {
return force_edit_checkbox_only_on_checkbox ;
}
2016-05-16 04:41:48 +02:00
void Tree : : set_allow_rmb_select ( bool p_allow ) {
allow_rmb_select = p_allow ;
}
bool Tree : : get_allow_rmb_select ( ) const {
return allow_rmb_select ;
}
2017-08-18 23:19:12 +02:00
void Tree : : set_allow_reselect ( bool p_allow ) {
allow_reselect = p_allow ;
}
bool Tree : : get_allow_reselect ( ) const {
return allow_reselect ;
}
2023-04-18 08:50:24 +02:00
void Tree : : set_allow_search ( bool p_allow ) {
allow_search = p_allow ;
}
bool Tree : : get_allow_search ( ) const {
return allow_search ;
}
2014-02-10 02:10:30 +01:00
void Tree : : _bind_methods ( ) {
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " clear " ) , & Tree : : clear ) ;
2022-12-22 08:05:04 +01:00
ClassDB : : bind_method ( D_METHOD ( " create_item " , " parent " , " index " ) , & Tree : : create_item , DEFVAL ( Variant ( ) ) , DEFVAL ( - 1 ) ) ;
2017-03-05 16:44:50 +01:00
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_root " ) , & Tree : : get_root ) ;
2021-06-28 15:40:56 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_column_custom_minimum_width " , " column " , " min_width " ) , & Tree : : set_column_custom_minimum_width ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_column_expand " , " column " , " expand " ) , & Tree : : set_column_expand ) ;
2021-07-04 05:13:28 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_column_expand_ratio " , " column " , " ratio " ) , & Tree : : set_column_expand_ratio ) ;
ClassDB : : bind_method ( D_METHOD ( " set_column_clip_content " , " column " , " enable " ) , & Tree : : set_column_clip_content ) ;
ClassDB : : bind_method ( D_METHOD ( " is_column_expanding " , " column " ) , & Tree : : is_column_expanding ) ;
ClassDB : : bind_method ( D_METHOD ( " is_column_clipping_content " , " column " ) , & Tree : : is_column_clipping_content ) ;
ClassDB : : bind_method ( D_METHOD ( " get_column_expand_ratio " , " column " ) , & Tree : : get_column_expand_ratio ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_column_width " , " column " ) , & Tree : : get_column_width ) ;
2017-03-05 16:44:50 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_hide_root " , " enable " ) , & Tree : : set_hide_root ) ;
2018-01-11 23:35:12 +01:00
ClassDB : : bind_method ( D_METHOD ( " is_root_hidden " ) , & Tree : : is_root_hidden ) ;
2022-01-25 16:37:41 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_next_selected " , " from " ) , & Tree : : get_next_selected ) ;
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_selected " ) , & Tree : : get_selected ) ;
2022-11-09 13:45:21 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_selected " , " item " , " column " ) , & Tree : : set_selected ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_selected_column " ) , & Tree : : get_selected_column ) ;
ClassDB : : bind_method ( D_METHOD ( " get_pressed_button " ) , & Tree : : get_pressed_button ) ;
ClassDB : : bind_method ( D_METHOD ( " set_select_mode " , " mode " ) , & Tree : : set_select_mode ) ;
2018-01-11 23:35:12 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_select_mode " ) , & Tree : : get_select_mode ) ;
2023-01-08 11:38:04 +01:00
ClassDB : : bind_method ( D_METHOD ( " deselect_all " ) , & Tree : : deselect_all ) ;
2017-03-05 16:44:50 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_columns " , " amount " ) , & Tree : : set_columns ) ;
ClassDB : : bind_method ( D_METHOD ( " get_columns " ) , & Tree : : get_columns ) ;
2017-03-05 16:44:50 +01:00
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_edited " ) , & Tree : : get_edited ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_edited_column " ) , & Tree : : get_edited_column ) ;
2022-11-26 15:58:25 +01:00
ClassDB : : bind_method ( D_METHOD ( " edit_selected " , " force_edit " ) , & Tree : : edit_selected , DEFVAL ( false ) ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_custom_popup_rect " ) , & Tree : : get_custom_popup_rect ) ;
2022-04-07 13:49:28 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_item_area_rect " , " item " , " column " , " button_index " ) , & Tree : : get_item_rect , DEFVAL ( - 1 ) , DEFVAL ( - 1 ) ) ;
2017-09-10 15:37:49 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_item_at_position " , " position " ) , & Tree : : get_item_at_position ) ;
ClassDB : : bind_method ( D_METHOD ( " get_column_at_position " , " position " ) , & Tree : : get_column_at_position ) ;
ClassDB : : bind_method ( D_METHOD ( " get_drop_section_at_position " , " position " ) , & Tree : : get_drop_section_at_position ) ;
2022-02-08 16:56:13 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_button_id_at_position " , " position " ) , & Tree : : get_button_id_at_position ) ;
2017-03-05 16:44:50 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " ensure_cursor_is_visible " ) , & Tree : : ensure_cursor_is_visible ) ;
2017-03-05 16:44:50 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_column_titles_visible " , " visible " ) , & Tree : : set_column_titles_visible ) ;
ClassDB : : bind_method ( D_METHOD ( " are_column_titles_visible " ) , & Tree : : are_column_titles_visible ) ;
2017-03-05 16:44:50 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_column_title " , " column " , " title " ) , & Tree : : set_column_title ) ;
ClassDB : : bind_method ( D_METHOD ( " get_column_title " , " column " ) , & Tree : : get_column_title ) ;
2020-09-03 13:22:16 +02:00
2023-03-26 03:13:31 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_column_title_alignment " , " column " , " title_alignment " ) , & Tree : : set_column_title_alignment ) ;
ClassDB : : bind_method ( D_METHOD ( " get_column_title_alignment " , " column " ) , & Tree : : get_column_title_alignment ) ;
2020-09-03 13:22:16 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_column_title_direction " , " column " , " direction " ) , & Tree : : set_column_title_direction ) ;
ClassDB : : bind_method ( D_METHOD ( " get_column_title_direction " , " column " ) , & Tree : : get_column_title_direction ) ;
ClassDB : : bind_method ( D_METHOD ( " set_column_title_language " , " column " , " language " ) , & Tree : : set_column_title_language ) ;
ClassDB : : bind_method ( D_METHOD ( " get_column_title_language " , " column " ) , & Tree : : get_column_title_language ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_scroll " ) , & Tree : : get_scroll ) ;
2020-07-05 20:06:51 +02:00
ClassDB : : bind_method ( D_METHOD ( " scroll_to_item " , " item " , " center_on_item " ) , & Tree : : scroll_to_item , DEFVAL ( false ) ) ;
2017-03-05 16:44:50 +01:00
2021-06-25 21:19:46 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_h_scroll_enabled " , " h_scroll " ) , & Tree : : set_h_scroll_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " is_h_scroll_enabled " ) , & Tree : : is_h_scroll_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " set_v_scroll_enabled " , " h_scroll " ) , & Tree : : set_v_scroll_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " is_v_scroll_enabled " ) , & Tree : : is_v_scroll_enabled ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_hide_folding " , " hide " ) , & Tree : : set_hide_folding ) ;
ClassDB : : bind_method ( D_METHOD ( " is_folding_hidden " ) , & Tree : : is_folding_hidden ) ;
2017-03-05 16:44:50 +01:00
2022-07-01 15:43:39 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_enable_recursive_folding " , " enable " ) , & Tree : : set_enable_recursive_folding ) ;
ClassDB : : bind_method ( D_METHOD ( " is_recursive_folding_enabled " ) , & Tree : : is_recursive_folding_enabled ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_drop_mode_flags " , " flags " ) , & Tree : : set_drop_mode_flags ) ;
ClassDB : : bind_method ( D_METHOD ( " get_drop_mode_flags " ) , & Tree : : get_drop_mode_flags ) ;
2017-03-05 16:44:50 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_allow_rmb_select " , " allow " ) , & Tree : : set_allow_rmb_select ) ;
ClassDB : : bind_method ( D_METHOD ( " get_allow_rmb_select " ) , & Tree : : get_allow_rmb_select ) ;
2017-03-05 16:44:50 +01:00
2017-08-18 23:19:12 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_allow_reselect " , " allow " ) , & Tree : : set_allow_reselect ) ;
ClassDB : : bind_method ( D_METHOD ( " get_allow_reselect " ) , & Tree : : get_allow_reselect ) ;
2017-03-05 16:44:50 +01:00
2023-04-18 08:50:24 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_allow_search " , " allow " ) , & Tree : : set_allow_search ) ;
ClassDB : : bind_method ( D_METHOD ( " get_allow_search " ) , & Tree : : get_allow_search ) ;
2018-01-11 23:35:12 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " columns " ) , " set_columns " , " get_columns " ) ;
2021-12-30 18:04:14 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " column_titles_visible " ) , " set_column_titles_visible " , " are_column_titles_visible " ) ;
2018-01-11 23:35:12 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " allow_reselect " ) , " set_allow_reselect " , " get_allow_reselect " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " allow_rmb_select " ) , " set_allow_rmb_select " , " get_allow_rmb_select " ) ;
2023-04-18 08:50:24 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " allow_search " ) , " set_allow_search " , " get_allow_search " ) ;
2018-01-11 23:35:12 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " hide_folding " ) , " set_hide_folding " , " is_folding_hidden " ) ;
2022-07-01 15:43:39 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " enable_recursive_folding " ) , " set_enable_recursive_folding " , " is_recursive_folding_enabled " ) ;
2018-01-11 23:35:12 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " hide_root " ) , " set_hide_root " , " is_root_hidden " ) ;
2021-05-22 04:30:58 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " drop_mode_flags " , PROPERTY_HINT_FLAGS , " On Item,In Between " ) , " set_drop_mode_flags " , " get_drop_mode_flags " ) ;
2018-01-11 23:35:12 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " select_mode " , PROPERTY_HINT_ENUM , " Single,Row,Multi " ) , " set_select_mode " , " get_select_mode " ) ;
2021-06-25 21:19:46 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " scroll_horizontal_enabled " ) , " set_h_scroll_enabled " , " is_h_scroll_enabled " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " scroll_vertical_enabled " ) , " set_v_scroll_enabled " , " is_v_scroll_enabled " ) ;
2018-01-11 23:35:12 +01:00
2014-02-10 02:10:30 +01:00
ADD_SIGNAL ( MethodInfo ( " item_selected " ) ) ;
ADD_SIGNAL ( MethodInfo ( " cell_selected " ) ) ;
2018-09-01 12:05:51 +02:00
ADD_SIGNAL ( MethodInfo ( " multi_selected " , PropertyInfo ( Variant : : OBJECT , " item " , PROPERTY_HINT_RESOURCE_TYPE , " TreeItem " ) , PropertyInfo ( Variant : : INT , " column " ) , PropertyInfo ( Variant : : BOOL , " selected " ) ) ) ;
2024-03-20 23:38:27 +01:00
ADD_SIGNAL ( MethodInfo ( " item_mouse_selected " , PropertyInfo ( Variant : : VECTOR2 , " mouse_position " ) , PropertyInfo ( Variant : : INT , " mouse_button_index " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( " empty_clicked " , PropertyInfo ( Variant : : VECTOR2 , " click_position " ) , PropertyInfo ( Variant : : INT , " mouse_button_index " ) ) ) ;
2014-02-10 02:10:30 +01:00
ADD_SIGNAL ( MethodInfo ( " item_edited " ) ) ;
2021-09-18 09:33:18 +02:00
ADD_SIGNAL ( MethodInfo ( " custom_item_clicked " , PropertyInfo ( Variant : : INT , " mouse_button_index " ) ) ) ;
2022-12-21 16:58:59 +01:00
ADD_SIGNAL ( MethodInfo ( " item_icon_double_clicked " ) ) ;
2018-09-01 12:05:51 +02:00
ADD_SIGNAL ( MethodInfo ( " item_collapsed " , PropertyInfo ( Variant : : OBJECT , " item " , PROPERTY_HINT_RESOURCE_TYPE , " TreeItem " ) ) ) ;
2021-09-17 17:50:24 +02:00
ADD_SIGNAL ( MethodInfo ( " check_propagated_to_item " , PropertyInfo ( Variant : : OBJECT , " item " , PROPERTY_HINT_RESOURCE_TYPE , " TreeItem " ) , PropertyInfo ( Variant : : INT , " column " ) ) ) ;
2021-09-18 09:33:18 +02:00
ADD_SIGNAL ( MethodInfo ( " button_clicked " , PropertyInfo ( Variant : : OBJECT , " item " , PROPERTY_HINT_RESOURCE_TYPE , " TreeItem " ) , PropertyInfo ( Variant : : INT , " column " ) , PropertyInfo ( Variant : : INT , " id " ) , PropertyInfo ( Variant : : INT , " mouse_button_index " ) ) ) ;
2014-02-10 02:10:30 +01:00
ADD_SIGNAL ( MethodInfo ( " custom_popup_edited " , PropertyInfo ( Variant : : BOOL , " arrow_clicked " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( " item_activated " ) ) ;
2022-08-13 18:30:41 +02:00
ADD_SIGNAL ( MethodInfo ( " column_title_clicked " , PropertyInfo ( Variant : : INT , " column " ) , PropertyInfo ( Variant : : INT , " mouse_button_index " ) ) ) ;
2017-11-26 12:49:21 +01:00
ADD_SIGNAL ( MethodInfo ( " nothing_selected " ) ) ;
2014-02-10 02:10:30 +01:00
2017-08-20 17:45:01 +02:00
BIND_ENUM_CONSTANT ( SELECT_SINGLE ) ;
BIND_ENUM_CONSTANT ( SELECT_ROW ) ;
BIND_ENUM_CONSTANT ( SELECT_MULTI ) ;
2016-05-11 16:46:08 +02:00
2017-08-20 17:45:01 +02:00
BIND_ENUM_CONSTANT ( DROP_MODE_DISABLED ) ;
BIND_ENUM_CONSTANT ( DROP_MODE_ON_ITEM ) ;
BIND_ENUM_CONSTANT ( DROP_MODE_INBETWEEN ) ;
2023-09-08 21:00:10 +02:00
BIND_THEME_ITEM_CUSTOM ( Theme : : DATA_TYPE_STYLEBOX , Tree , panel_style , " panel " ) ;
BIND_THEME_ITEM_CUSTOM ( Theme : : DATA_TYPE_STYLEBOX , Tree , focus_style , " focus " ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_FONT , Tree , font ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_FONT_SIZE , Tree , font_size ) ;
BIND_THEME_ITEM_CUSTOM ( Theme : : DATA_TYPE_FONT , Tree , tb_font , " title_button_font " ) ;
BIND_THEME_ITEM_CUSTOM ( Theme : : DATA_TYPE_FONT_SIZE , Tree , tb_font_size , " title_button_font_size " ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_STYLEBOX , Tree , selected ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_STYLEBOX , Tree , selected_focus ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_STYLEBOX , Tree , cursor ) ;
BIND_THEME_ITEM_CUSTOM ( Theme : : DATA_TYPE_STYLEBOX , Tree , cursor_unfocus , " cursor_unfocused " ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_STYLEBOX , Tree , button_pressed ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , Tree , checked ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , Tree , unchecked ) ;
2023-11-13 14:38:56 +01:00
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , Tree , checked_disabled ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , Tree , unchecked_disabled ) ;
2023-09-08 21:00:10 +02:00
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , Tree , indeterminate ) ;
2023-11-13 14:38:56 +01:00
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , Tree , indeterminate_disabled ) ;
2023-09-08 21:00:10 +02:00
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , Tree , arrow ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , Tree , arrow_collapsed ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , Tree , arrow_collapsed_mirrored ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , Tree , select_arrow ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , Tree , updown ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_STYLEBOX , Tree , custom_button ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_STYLEBOX , Tree , custom_button_hover ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_STYLEBOX , Tree , custom_button_pressed ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Tree , custom_button_font_highlight ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Tree , font_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Tree , font_selected_color ) ;
2023-11-13 14:38:56 +01:00
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Tree , font_disabled_color ) ;
2023-09-08 21:00:10 +02:00
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Tree , drop_position_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Tree , h_separation ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Tree , v_separation ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Tree , inner_item_margin_bottom ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Tree , inner_item_margin_left ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Tree , inner_item_margin_right ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Tree , inner_item_margin_top ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Tree , item_margin ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Tree , button_margin ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Tree , icon_max_width ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Tree , font_outline_color ) ;
BIND_THEME_ITEM_CUSTOM ( Theme : : DATA_TYPE_CONSTANT , Tree , font_outline_size , " outline_size " ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Tree , draw_guides ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Tree , guide_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Tree , draw_relationship_lines ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Tree , relationship_line_width ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Tree , parent_hl_line_width ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Tree , children_hl_line_width ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Tree , parent_hl_line_margin ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Tree , relationship_line_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Tree , parent_hl_line_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Tree , children_hl_line_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Tree , scroll_border ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Tree , scroll_speed ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Tree , scrollbar_margin_top ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Tree , scrollbar_margin_right ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Tree , scrollbar_margin_bottom ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Tree , scrollbar_margin_left ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Tree , scrollbar_h_separation ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Tree , scrollbar_v_separation ) ;
BIND_THEME_ITEM_CUSTOM ( Theme : : DATA_TYPE_STYLEBOX , Tree , title_button , " title_button_normal " ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_STYLEBOX , Tree , title_button_pressed ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_STYLEBOX , Tree , title_button_hover ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Tree , title_button_color ) ;
2014-02-10 02:10:30 +01:00
}
Tree : : Tree ( ) {
columns . resize ( 1 ) ;
2017-03-05 16:44:50 +01:00
2014-02-10 02:10:30 +01:00
set_focus_mode ( FOCUS_ALL ) ;
2015-08-31 00:37:23 +02:00
2014-02-10 02:10:30 +01:00
popup_menu = memnew ( PopupMenu ) ;
popup_menu - > hide ( ) ;
2021-08-25 15:49:30 +02:00
add_child ( popup_menu , false , INTERNAL_MODE_FRONT ) ;
2020-03-20 03:32:09 +01:00
2020-07-01 15:59:42 +02:00
popup_editor = memnew ( Popup ) ;
2021-08-25 15:49:30 +02:00
add_child ( popup_editor , false , INTERNAL_MODE_FRONT ) ;
2023-04-25 17:43:26 +02:00
2020-03-20 03:32:09 +01:00
popup_editor_vb = memnew ( VBoxContainer ) ;
2022-02-08 10:14:58 +01:00
popup_editor_vb - > add_theme_constant_override ( " separation " , 0 ) ;
2022-03-19 01:02:57 +01:00
popup_editor_vb - > set_anchors_and_offsets_preset ( PRESET_FULL_RECT ) ;
2023-04-25 17:43:26 +02:00
popup_editor - > add_child ( popup_editor_vb ) ;
line_editor = memnew ( LineEdit ) ;
line_editor - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
line_editor - > hide ( ) ;
popup_editor_vb - > add_child ( line_editor ) ;
text_editor = memnew ( TextEdit ) ;
2020-03-20 03:32:09 +01:00
text_editor - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2023-04-25 17:43:26 +02:00
text_editor - > hide ( ) ;
popup_editor_vb - > add_child ( text_editor ) ;
2014-02-10 02:10:30 +01:00
value_editor = memnew ( HSlider ) ;
2022-12-20 04:19:18 +01:00
value_editor - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2014-02-10 02:10:30 +01:00
value_editor - > hide ( ) ;
2023-04-25 17:43:26 +02:00
popup_editor_vb - > add_child ( value_editor ) ;
2014-02-10 02:10:30 +01:00
h_scroll = memnew ( HScrollBar ) ;
v_scroll = memnew ( VScrollBar ) ;
2015-08-31 00:37:23 +02:00
2021-08-25 15:49:30 +02:00
add_child ( h_scroll , false , INTERNAL_MODE_FRONT ) ;
add_child ( v_scroll , false , INTERNAL_MODE_FRONT ) ;
2014-02-10 02:10:30 +01:00
2015-12-08 19:04:56 +01:00
range_click_timer = memnew ( Timer ) ;
2020-02-21 18:28:45 +01:00
range_click_timer - > connect ( " timeout " , callable_mp ( this , & Tree : : _range_click_timeout ) ) ;
2021-08-25 15:49:30 +02:00
add_child ( range_click_timer , false , INTERNAL_MODE_FRONT ) ;
2015-12-08 19:04:56 +01:00
2024-05-14 11:42:00 +02:00
h_scroll - > connect ( SceneStringName ( value_changed ) , callable_mp ( this , & Tree : : _scroll_moved ) ) ;
v_scroll - > connect ( SceneStringName ( value_changed ) , callable_mp ( this , & Tree : : _scroll_moved ) ) ;
2023-04-25 17:43:26 +02:00
line_editor - > connect ( " text_submitted " , callable_mp ( this , & Tree : : _line_editor_submit ) ) ;
2024-05-13 16:56:03 +02:00
text_editor - > connect ( SceneStringName ( gui_input ) , callable_mp ( this , & Tree : : _text_editor_gui_input ) ) ;
2023-04-25 17:43:26 +02:00
popup_editor - > connect ( " popup_hide " , callable_mp ( this , & Tree : : _text_editor_popup_modal_close ) ) ;
2024-05-14 14:13:31 +02:00
popup_menu - > connect ( SceneStringName ( id_pressed ) , callable_mp ( this , & Tree : : popup_select ) ) ;
2024-05-14 11:42:00 +02:00
value_editor - > connect ( SceneStringName ( value_changed ) , callable_mp ( this , & Tree : : value_editor_changed ) ) ;
2014-02-10 02:10:30 +01:00
2018-10-04 19:33:34 +02:00
set_notify_transform ( true ) ;
2014-02-10 02:10:30 +01:00
2017-01-08 23:54:19 +01:00
set_mouse_filter ( MOUSE_FILTER_STOP ) ;
2014-02-10 02:10:30 +01:00
2017-01-09 19:50:08 +01:00
set_clip_contents ( true ) ;
2014-02-10 02:10:30 +01:00
}
Tree : : ~ Tree ( ) {
if ( root ) {
memdelete ( root ) ;
}
}