2014-02-10 01:10:30 +00:00
/**************************************************************************/
/* control.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-04 23:50:27 +00:00
2014-02-10 01:10:30 +00:00
# include "control.h"
2021-09-05 20:01:36 +00:00
# include "container.h"
2020-11-07 22:33:38 +00:00
# include "core/config/project_settings.h"
2020-05-25 17:20:45 +00:00
# include "core/math/geometry_2d.h"
2018-09-11 16:13:45 +00:00
# include "core/os/os.h"
2024-08-15 07:00:47 +00:00
# include "core/string/translation_server.h"
2019-06-12 20:35:35 +00:00
# include "scene/main/canvas_layer.h"
2020-03-04 01:51:12 +00:00
# include "scene/main/window.h"
2022-08-08 16:29:36 +00:00
# include "scene/theme/theme_db.h"
2022-09-02 14:03:23 +00:00
# include "scene/theme/theme_owner.h"
2020-03-27 18:21:27 +00:00
# include "servers/rendering_server.h"
2020-09-03 11:22:16 +00:00
# include "servers/text_server.h"
2019-06-12 20:35:35 +00:00
2016-03-09 16:59:35 +00:00
# ifdef TOOLS_ENABLED
2021-11-08 20:53:41 +00:00
# include "editor/plugins/control_editor_plugin.h"
2016-03-09 16:59:35 +00:00
# endif
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
// Editor plugin interoperability.
// TODO: Decouple controls from their editor plugin and get rid of this.
2019-10-21 21:37:07 +00:00
# ifdef TOOLS_ENABLED
2017-11-15 22:03:25 +00:00
Dictionary Control : : _edit_get_state ( ) const {
2016-06-27 13:47:51 +00:00
Dictionary s ;
2017-09-10 13:37:49 +00:00
s [ " rotation " ] = get_rotation ( ) ;
2016-06-27 13:47:51 +00:00
s [ " scale " ] = get_scale ( ) ;
2017-11-07 07:58:35 +00:00
s [ " pivot " ] = get_pivot_offset ( ) ;
2021-11-08 20:53:41 +00:00
2017-08-04 23:55:03 +00:00
Array anchors ;
2020-12-22 16:24:29 +00:00
anchors . push_back ( get_anchor ( SIDE_LEFT ) ) ;
anchors . push_back ( get_anchor ( SIDE_TOP ) ) ;
anchors . push_back ( get_anchor ( SIDE_RIGHT ) ) ;
anchors . push_back ( get_anchor ( SIDE_BOTTOM ) ) ;
2017-08-04 23:55:03 +00:00
s [ " anchors " ] = anchors ;
2021-11-08 20:53:41 +00:00
2020-12-22 16:24:29 +00:00
Array offsets ;
offsets . push_back ( get_offset ( SIDE_LEFT ) ) ;
offsets . push_back ( get_offset ( SIDE_TOP ) ) ;
offsets . push_back ( get_offset ( SIDE_RIGHT ) ) ;
offsets . push_back ( get_offset ( SIDE_BOTTOM ) ) ;
s [ " offsets " ] = offsets ;
2021-11-08 20:53:41 +00:00
s [ " layout_mode " ] = _get_layout_mode ( ) ;
s [ " anchors_layout_preset " ] = _get_anchors_layout_preset ( ) ;
2016-06-27 13:47:51 +00:00
return s ;
2014-02-10 01:10:30 +00:00
}
2019-03-31 16:53:24 +00:00
2017-11-15 22:03:25 +00:00
void Control : : _edit_set_state ( const Dictionary & p_state ) {
2024-01-19 12:21:39 +00:00
ERR_FAIL_COND ( p_state . is_empty ( ) | |
2021-10-28 13:19:35 +00:00
! p_state . has ( " rotation " ) | | ! p_state . has ( " scale " ) | |
2021-11-08 20:53:41 +00:00
! p_state . has ( " pivot " ) | | ! p_state . has ( " anchors " ) | | ! p_state . has ( " offsets " ) | |
! p_state . has ( " layout_mode " ) | | ! p_state . has ( " anchors_layout_preset " ) ) ;
2017-11-15 22:03:25 +00:00
Dictionary state = p_state ;
2016-06-27 13:47:51 +00:00
2017-11-15 22:03:25 +00:00
set_rotation ( state [ " rotation " ] ) ;
set_scale ( state [ " scale " ] ) ;
2017-11-07 07:58:35 +00:00
set_pivot_offset ( state [ " pivot " ] ) ;
2021-11-08 20:53:41 +00:00
2017-11-15 22:03:25 +00:00
Array anchors = state [ " anchors " ] ;
2021-11-08 20:53:41 +00:00
// If anchors are not in their default position, force the anchor layout mode in place of position.
LayoutMode _layout = ( LayoutMode ) ( int ) state [ " layout_mode " ] ;
if ( _layout = = LayoutMode : : LAYOUT_MODE_POSITION ) {
bool anchors_mode = ( ( real_t ) anchors [ 0 ] ! = 0.0 | | ( real_t ) anchors [ 1 ] ! = 0.0 | | ( real_t ) anchors [ 2 ] ! = 0.0 | | ( real_t ) anchors [ 3 ] ! = 0.0 ) ;
if ( anchors_mode ) {
_layout = LayoutMode : : LAYOUT_MODE_ANCHORS ;
}
}
_set_layout_mode ( _layout ) ;
2023-01-03 16:21:26 +00:00
if ( _layout = = LayoutMode : : LAYOUT_MODE_ANCHORS | | _layout = = LayoutMode : : LAYOUT_MODE_UNCONTROLLED ) {
2021-11-08 20:53:41 +00:00
_set_anchors_layout_preset ( ( int ) state [ " anchors_layout_preset " ] ) ;
}
2020-12-22 16:24:29 +00:00
data . anchor [ SIDE_LEFT ] = anchors [ 0 ] ;
data . anchor [ SIDE_TOP ] = anchors [ 1 ] ;
data . anchor [ SIDE_RIGHT ] = anchors [ 2 ] ;
data . anchor [ SIDE_BOTTOM ] = anchors [ 3 ] ;
2021-11-08 20:53:41 +00:00
2020-12-22 16:24:29 +00:00
Array offsets = state [ " offsets " ] ;
data . offset [ SIDE_LEFT ] = offsets [ 0 ] ;
data . offset [ SIDE_TOP ] = offsets [ 1 ] ;
data . offset [ SIDE_RIGHT ] = offsets [ 2 ] ;
data . offset [ SIDE_BOTTOM ] = offsets [ 3 ] ;
2021-11-08 20:53:41 +00:00
2017-11-07 07:58:35 +00:00
_size_changed ( ) ;
2014-02-10 01:10:30 +00:00
}
2017-11-15 22:03:25 +00:00
void Control : : _edit_set_position ( const Point2 & p_position ) {
2021-03-14 11:35:29 +00:00
ERR_FAIL_COND_MSG ( ! Engine : : get_singleton ( ) - > is_editor_hint ( ) , " This function can only be used from editor plugins. " ) ;
2023-01-03 16:21:26 +00:00
set_position ( p_position , ControlEditorToolbar : : get_singleton ( ) - > is_anchors_mode_enabled ( ) & & get_parent_control ( ) ) ;
2017-11-15 22:03:25 +00:00
} ;
Point2 Control : : _edit_get_position ( ) const {
return get_position ( ) ;
} ;
2018-03-08 20:35:41 +00:00
void Control : : _edit_set_scale ( const Size2 & p_scale ) {
set_scale ( p_scale ) ;
}
Size2 Control : : _edit_get_scale ( ) const {
return data . scale ;
}
2017-11-15 22:03:25 +00:00
void Control : : _edit_set_rect ( const Rect2 & p_edit_rect ) {
2021-03-14 11:35:29 +00:00
ERR_FAIL_COND_MSG ( ! Engine : : get_singleton ( ) - > is_editor_hint ( ) , " This function can only be used from editor plugins. " ) ;
2024-03-03 13:37:52 +00:00
set_position ( ( get_position ( ) + get_transform ( ) . basis_xform ( p_edit_rect . position ) ) . snappedf ( 1 ) , ControlEditorToolbar : : get_singleton ( ) - > is_anchors_mode_enabled ( ) ) ;
set_size ( p_edit_rect . size . snappedf ( 1 ) , ControlEditorToolbar : : get_singleton ( ) - > is_anchors_mode_enabled ( ) ) ;
2017-11-15 22:03:25 +00:00
}
Rect2 Control : : _edit_get_rect ( ) const {
return Rect2 ( Point2 ( ) , get_size ( ) ) ;
}
bool Control : : _edit_use_rect ( ) const {
return true ;
}
2021-01-30 04:10:32 +00:00
void Control : : _edit_set_rotation ( real_t p_rotation ) {
2017-11-15 22:03:25 +00:00
set_rotation ( p_rotation ) ;
}
2021-01-30 04:10:32 +00:00
real_t Control : : _edit_get_rotation ( ) const {
2017-11-15 22:03:25 +00:00
return get_rotation ( ) ;
}
bool Control : : _edit_use_rotation ( ) const {
return true ;
}
void Control : : _edit_set_pivot ( const Point2 & p_pivot ) {
2017-11-07 07:58:35 +00:00
Vector2 delta_pivot = p_pivot - get_pivot_offset ( ) ;
Vector2 move = Vector2 ( ( cos ( data . rotation ) - 1.0 ) * delta_pivot . x - sin ( data . rotation ) * delta_pivot . y , sin ( data . rotation ) * delta_pivot . x + ( cos ( data . rotation ) - 1.0 ) * delta_pivot . y ) ;
set_position ( get_position ( ) + move ) ;
2017-11-15 22:03:25 +00:00
set_pivot_offset ( p_pivot ) ;
}
Point2 Control : : _edit_get_pivot ( ) const {
return get_pivot_offset ( ) ;
}
bool Control : : _edit_use_pivot ( ) const {
return true ;
}
2019-10-21 21:37:07 +00:00
Size2 Control : : _edit_get_minimum_size ( ) const {
return get_combined_minimum_size ( ) ;
}
# endif
2020-02-17 17:29:14 +00:00
void Control : : reparent ( Node * p_parent , bool p_keep_global_transform ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-02-17 17:29:14 +00:00
if ( p_keep_global_transform ) {
2024-02-29 11:46:07 +00:00
Transform2D temp = get_global_transform ( ) ;
Node : : reparent ( p_parent ) ;
2020-02-17 17:29:14 +00:00
set_global_position ( temp . get_origin ( ) ) ;
2024-02-29 11:46:07 +00:00
} else {
Node : : reparent ( p_parent ) ;
2020-02-17 17:29:14 +00:00
}
}
2019-10-21 21:37:07 +00:00
2022-07-22 15:06:03 +00:00
// Editor integration.
2023-11-17 06:54:07 +00:00
int Control : : root_layout_direction = 0 ;
void Control : : set_root_layout_direction ( int p_root_dir ) {
root_layout_direction = p_root_dir ;
}
2024-01-03 11:10:11 +00:00
# ifdef TOOLS_ENABLED
2022-07-22 15:06:03 +00:00
void Control : : get_argument_options ( const StringName & p_function , int p_idx , List < String > * r_options ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
if ( p_idx = = 0 ) {
2024-01-03 11:10:11 +00:00
const String pf = p_function ;
2023-11-17 13:47:13 +00:00
Theme : : DataType type = Theme : : DATA_TYPE_MAX ;
2024-05-24 00:07:28 +00:00
if ( pf = = " add_theme_color_override " | | pf = = " has_theme_color " | | pf = = " has_theme_color_override " | | pf = = " get_theme_color " | | pf = = " remove_theme_color_override " ) {
2023-11-17 13:47:13 +00:00
type = Theme : : DATA_TYPE_COLOR ;
2024-05-24 00:07:28 +00:00
} else if ( pf = = " add_theme_constant_override " | | pf = = " has_theme_constant " | | pf = = " has_theme_constant_override " | | pf = = " get_theme_constant " | | pf = = " remove_theme_constant_override " ) {
2023-11-17 13:47:13 +00:00
type = Theme : : DATA_TYPE_CONSTANT ;
2024-05-24 00:07:28 +00:00
} else if ( pf = = " add_theme_font_override " | | pf = = " has_theme_font " | | pf = = " has_theme_font_override " | | pf = = " get_theme_font " | | pf = = " remove_theme_font_override " ) {
2023-11-17 13:47:13 +00:00
type = Theme : : DATA_TYPE_FONT ;
2024-05-24 00:07:28 +00:00
} else if ( pf = = " add_theme_font_size_override " | | pf = = " has_theme_font_size " | | pf = = " has_theme_font_size_override " | | pf = = " get_theme_font_size " | | pf = = " remove_theme_font_size_override " ) {
2023-11-17 13:47:13 +00:00
type = Theme : : DATA_TYPE_FONT_SIZE ;
2024-05-24 00:07:28 +00:00
} else if ( pf = = " add_theme_icon_override " | | pf = = " has_theme_icon " | | pf = = " has_theme_icon_override " | | pf = = " get_theme_icon " | | pf = = " remove_theme_icon_override " ) {
2023-11-17 13:47:13 +00:00
type = Theme : : DATA_TYPE_ICON ;
2024-05-24 00:07:28 +00:00
} else if ( pf = = " add_theme_stylebox_override " | | pf = = " has_theme_stylebox " | | pf = = " has_theme_stylebox_override " | | pf = = " get_theme_stylebox " | | pf = = " remove_theme_stylebox_override " ) {
2023-11-17 13:47:13 +00:00
type = Theme : : DATA_TYPE_STYLEBOX ;
2022-07-22 15:06:03 +00:00
}
2023-11-17 13:47:13 +00:00
if ( type ! = Theme : : DATA_TYPE_MAX ) {
List < ThemeDB : : ThemeItemBind > theme_items ;
ThemeDB : : get_singleton ( ) - > get_class_items ( get_class_name ( ) , & theme_items , true , type ) ;
List < StringName > sn ;
for ( const ThemeDB : : ThemeItemBind & E : theme_items ) {
if ( E . data_type = = type ) {
sn . push_back ( E . item_name ) ;
}
}
sn . sort_custom < StringName : : AlphCompare > ( ) ;
for ( const StringName & name : sn ) {
r_options - > push_back ( String ( name ) . quote ( ) ) ;
}
2022-07-22 15:06:03 +00:00
}
}
2023-11-17 13:47:13 +00:00
CanvasItem : : get_argument_options ( p_function , p_idx , r_options ) ;
2022-07-22 15:06:03 +00:00
}
2024-01-03 11:10:11 +00:00
# endif
2022-07-22 15:06:03 +00:00
2024-02-17 18:03:21 +00:00
PackedStringArray Control : : get_configuration_warnings ( ) const {
ERR_READ_THREAD_GUARD_V ( PackedStringArray ( ) ) ;
2024-06-19 14:40:50 +00:00
PackedStringArray warnings = CanvasItem : : get_configuration_warnings ( ) ;
2022-07-22 15:06:03 +00:00
if ( data . mouse_filter = = MOUSE_FILTER_IGNORE & & ! data . tooltip . is_empty ( ) ) {
warnings . push_back ( RTR ( " The Hint Tooltip won't be displayed as the control's Mouse Filter is set to \" Ignore \" . To solve this, set the Mouse Filter to \" Stop \" or \" Pass \" . " ) ) ;
}
return warnings ;
}
bool Control : : is_text_field ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-07-22 15:06:03 +00:00
return false ;
}
// Dynamic properties.
2021-09-05 20:01:36 +00:00
String Control : : properties_managed_by_container [ ] = {
" offset_left " ,
" offset_top " ,
" offset_right " ,
" offset_bottom " ,
" anchor_left " ,
" anchor_top " ,
" anchor_right " ,
" anchor_bottom " ,
2022-01-23 17:14:31 +00:00
" position " ,
" rotation " ,
" scale " ,
" size "
2021-09-05 20:01:36 +00:00
} ;
2014-02-10 01:10:30 +00:00
bool Control : : _set ( const StringName & p_name , const Variant & p_value ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD_V ( false ) ;
2014-02-10 01:10:30 +00:00
String name = p_name ;
2024-01-23 21:29:45 +00:00
2022-03-05 20:35:10 +00:00
if ( ! name . begins_with ( " theme_override " ) ) {
2017-01-08 22:11:35 +00:00
return false ;
2016-03-20 05:25:05 +00:00
}
2014-02-10 01:10:30 +00:00
2021-12-21 09:37:08 +00:00
if ( p_value . get_type ( ) = = Variant : : NIL | | ( p_value . get_type ( ) = = Variant : : OBJECT & & ( Object * ) p_value = = nullptr ) ) {
2022-03-05 20:35:10 +00:00
if ( name . begins_with ( " theme_override_icons/ " ) ) {
2015-06-29 03:29:49 +00:00
String dname = name . get_slicec ( ' / ' , 1 ) ;
2022-11-29 20:01:45 +00:00
if ( data . theme_icon_override . has ( dname ) ) {
2023-07-03 19:29:37 +00:00
data . theme_icon_override [ dname ] - > disconnect_changed ( callable_mp ( this , & Control : : _notify_theme_override_changed ) ) ;
2019-02-25 15:13:25 +00:00
}
2022-11-29 20:01:45 +00:00
data . theme_icon_override . erase ( dname ) ;
2022-07-08 19:29:36 +00:00
_notify_theme_override_changed ( ) ;
2022-03-05 20:35:10 +00:00
} else if ( name . begins_with ( " theme_override_styles/ " ) ) {
2015-06-29 03:29:49 +00:00
String dname = name . get_slicec ( ' / ' , 1 ) ;
2022-11-29 20:01:45 +00:00
if ( data . theme_style_override . has ( dname ) ) {
2023-07-03 19:29:37 +00:00
data . theme_style_override [ dname ] - > disconnect_changed ( callable_mp ( this , & Control : : _notify_theme_override_changed ) ) ;
2019-02-25 15:13:25 +00:00
}
2022-11-29 20:01:45 +00:00
data . theme_style_override . erase ( dname ) ;
2022-07-08 19:29:36 +00:00
_notify_theme_override_changed ( ) ;
2022-03-05 20:35:10 +00:00
} else if ( name . begins_with ( " theme_override_fonts/ " ) ) {
2015-06-29 03:29:49 +00:00
String dname = name . get_slicec ( ' / ' , 1 ) ;
2022-11-29 20:01:45 +00:00
if ( data . theme_font_override . has ( dname ) ) {
2023-07-03 19:29:37 +00:00
data . theme_font_override [ dname ] - > disconnect_changed ( callable_mp ( this , & Control : : _notify_theme_override_changed ) ) ;
2016-06-17 19:00:27 +00:00
}
2022-11-29 20:01:45 +00:00
data . theme_font_override . erase ( dname ) ;
2022-07-08 19:29:36 +00:00
_notify_theme_override_changed ( ) ;
2022-03-05 20:35:10 +00:00
} else if ( name . begins_with ( " theme_override_font_sizes/ " ) ) {
2020-09-03 11:22:16 +00:00
String dname = name . get_slicec ( ' / ' , 1 ) ;
2022-11-29 20:01:45 +00:00
data . theme_font_size_override . erase ( dname ) ;
2022-07-08 19:29:36 +00:00
_notify_theme_override_changed ( ) ;
2022-03-05 20:35:10 +00:00
} else if ( name . begins_with ( " theme_override_colors/ " ) ) {
2015-06-29 03:29:49 +00:00
String dname = name . get_slicec ( ' / ' , 1 ) ;
2022-11-29 20:01:45 +00:00
data . theme_color_override . erase ( dname ) ;
2022-07-08 19:29:36 +00:00
_notify_theme_override_changed ( ) ;
2022-03-05 20:35:10 +00:00
} else if ( name . begins_with ( " theme_override_constants/ " ) ) {
2015-06-29 03:29:49 +00:00
String dname = name . get_slicec ( ' / ' , 1 ) ;
2022-11-29 20:01:45 +00:00
data . theme_constant_override . erase ( dname ) ;
2022-07-08 19:29:36 +00:00
_notify_theme_override_changed ( ) ;
2020-05-14 14:41:43 +00:00
} else {
2014-02-10 01:10:30 +00:00
return false ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
} else {
2022-03-05 20:35:10 +00:00
if ( name . begins_with ( " theme_override_icons/ " ) ) {
2015-06-29 03:29:49 +00:00
String dname = name . get_slicec ( ' / ' , 1 ) ;
2020-03-12 12:37:40 +00:00
add_theme_icon_override ( dname , p_value ) ;
2022-03-05 20:35:10 +00:00
} else if ( name . begins_with ( " theme_override_styles/ " ) ) {
2015-06-29 03:29:49 +00:00
String dname = name . get_slicec ( ' / ' , 1 ) ;
2020-03-12 12:37:40 +00:00
add_theme_style_override ( dname , p_value ) ;
2022-03-05 20:35:10 +00:00
} else if ( name . begins_with ( " theme_override_fonts/ " ) ) {
2015-06-29 03:29:49 +00:00
String dname = name . get_slicec ( ' / ' , 1 ) ;
2020-03-12 12:37:40 +00:00
add_theme_font_override ( dname , p_value ) ;
2022-03-05 20:35:10 +00:00
} else if ( name . begins_with ( " theme_override_font_sizes/ " ) ) {
2020-09-03 11:22:16 +00:00
String dname = name . get_slicec ( ' / ' , 1 ) ;
add_theme_font_size_override ( dname , p_value ) ;
2022-03-05 20:35:10 +00:00
} else if ( name . begins_with ( " theme_override_colors/ " ) ) {
2015-06-29 03:29:49 +00:00
String dname = name . get_slicec ( ' / ' , 1 ) ;
2020-03-12 12:37:40 +00:00
add_theme_color_override ( dname , p_value ) ;
2022-03-05 20:35:10 +00:00
} else if ( name . begins_with ( " theme_override_constants/ " ) ) {
2015-06-29 03:29:49 +00:00
String dname = name . get_slicec ( ' / ' , 1 ) ;
2020-03-12 12:37:40 +00:00
add_theme_constant_override ( dname , p_value ) ;
2020-05-14 14:41:43 +00:00
} else {
2014-02-10 01:10:30 +00:00
return false ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
2024-01-23 21:29:45 +00:00
2014-02-10 01:10:30 +00:00
return true ;
}
bool Control : : _get ( const StringName & p_name , Variant & r_ret ) const {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD_V ( false ) ;
2014-02-10 01:10:30 +00:00
String sname = p_name ;
2024-01-23 21:29:45 +00:00
2021-07-31 20:44:37 +00:00
if ( ! sname . begins_with ( " theme_override " ) ) {
2017-01-08 22:11:35 +00:00
return false ;
2016-06-12 18:31:38 +00:00
}
2014-02-10 01:10:30 +00:00
2021-07-31 20:44:37 +00:00
if ( sname . begins_with ( " theme_override_icons/ " ) ) {
2015-06-29 03:29:49 +00:00
String name = sname . get_slicec ( ' / ' , 1 ) ;
2022-11-29 20:01:45 +00:00
r_ret = data . theme_icon_override . has ( name ) ? Variant ( data . theme_icon_override [ name ] ) : Variant ( ) ;
2021-07-31 20:44:37 +00:00
} else if ( sname . begins_with ( " theme_override_styles/ " ) ) {
2015-06-29 03:29:49 +00:00
String name = sname . get_slicec ( ' / ' , 1 ) ;
2022-11-29 20:01:45 +00:00
r_ret = data . theme_style_override . has ( name ) ? Variant ( data . theme_style_override [ name ] ) : Variant ( ) ;
2021-07-31 20:44:37 +00:00
} else if ( sname . begins_with ( " theme_override_fonts/ " ) ) {
2015-06-29 03:29:49 +00:00
String name = sname . get_slicec ( ' / ' , 1 ) ;
2022-11-29 20:01:45 +00:00
r_ret = data . theme_font_override . has ( name ) ? Variant ( data . theme_font_override [ name ] ) : Variant ( ) ;
2021-07-31 20:44:37 +00:00
} else if ( sname . begins_with ( " theme_override_font_sizes/ " ) ) {
2020-09-03 11:22:16 +00:00
String name = sname . get_slicec ( ' / ' , 1 ) ;
2022-11-29 20:01:45 +00:00
r_ret = data . theme_font_size_override . has ( name ) ? Variant ( data . theme_font_size_override [ name ] ) : Variant ( ) ;
2021-07-31 20:44:37 +00:00
} else if ( sname . begins_with ( " theme_override_colors/ " ) ) {
2015-06-29 03:29:49 +00:00
String name = sname . get_slicec ( ' / ' , 1 ) ;
2022-11-29 20:01:45 +00:00
r_ret = data . theme_color_override . has ( name ) ? Variant ( data . theme_color_override [ name ] ) : Variant ( ) ;
2021-07-31 20:44:37 +00:00
} else if ( sname . begins_with ( " theme_override_constants/ " ) ) {
2015-06-29 03:29:49 +00:00
String name = sname . get_slicec ( ' / ' , 1 ) ;
2022-11-29 20:01:45 +00:00
r_ret = data . theme_constant_override . has ( name ) ? Variant ( data . theme_constant_override [ name ] ) : Variant ( ) ;
2020-05-14 14:41:43 +00:00
} else {
2014-02-10 01:10:30 +00:00
return false ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
return true ;
}
2020-05-14 12:29:06 +00:00
2014-02-10 01:10:30 +00:00
void Control : : _get_property_list ( List < PropertyInfo > * p_list ) const {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2023-11-11 17:29:42 +00:00
List < ThemeDB : : ThemeItemBind > theme_items ;
ThemeDB : : get_singleton ( ) - > get_class_items ( get_class_name ( ) , & theme_items , true ) ;
2014-02-10 01:10:30 +00:00
2023-03-27 10:06:07 +00:00
p_list - > push_back ( PropertyInfo ( Variant : : NIL , GNAME ( " Theme Overrides " , " theme_override_ " ) , PROPERTY_HINT_NONE , " theme_override_ " , PROPERTY_USAGE_GROUP ) ) ;
2021-07-31 20:44:37 +00:00
2023-11-11 17:29:42 +00:00
for ( const ThemeDB : : ThemeItemBind & E : theme_items ) {
uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE ;
switch ( E . data_type ) {
case Theme : : DATA_TYPE_COLOR : {
if ( data . theme_color_override . has ( E . item_name ) ) {
usage | = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED ;
}
p_list - > push_back ( PropertyInfo ( Variant : : COLOR , PNAME ( " theme_override_colors " ) + String ( " / " ) + E . item_name , PROPERTY_HINT_NONE , " " , usage ) ) ;
} break ;
case Theme : : DATA_TYPE_CONSTANT : {
if ( data . theme_constant_override . has ( E . item_name ) ) {
usage | = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED ;
}
p_list - > push_back ( PropertyInfo ( Variant : : INT , PNAME ( " theme_override_constants " ) + String ( " / " ) + E . item_name , PROPERTY_HINT_RANGE , " -16384,16384 " , usage ) ) ;
} break ;
case Theme : : DATA_TYPE_FONT : {
if ( data . theme_font_override . has ( E . item_name ) ) {
usage | = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED ;
}
p_list - > push_back ( PropertyInfo ( Variant : : OBJECT , PNAME ( " theme_override_fonts " ) + String ( " / " ) + E . item_name , PROPERTY_HINT_RESOURCE_TYPE , " Font " , usage ) ) ;
} break ;
case Theme : : DATA_TYPE_FONT_SIZE : {
if ( data . theme_font_size_override . has ( E . item_name ) ) {
usage | = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED ;
}
p_list - > push_back ( PropertyInfo ( Variant : : INT , PNAME ( " theme_override_font_sizes " ) + String ( " / " ) + E . item_name , PROPERTY_HINT_RANGE , " 1,256,1,or_greater,suffix:px " , usage ) ) ;
} break ;
case Theme : : DATA_TYPE_ICON : {
if ( data . theme_icon_override . has ( E . item_name ) ) {
usage | = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED ;
}
p_list - > push_back ( PropertyInfo ( Variant : : OBJECT , PNAME ( " theme_override_icons " ) + String ( " / " ) + E . item_name , PROPERTY_HINT_RESOURCE_TYPE , " Texture2D " , usage ) ) ;
} break ;
case Theme : : DATA_TYPE_STYLEBOX : {
if ( data . theme_style_override . has ( E . item_name ) ) {
usage | = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED ;
}
p_list - > push_back ( PropertyInfo ( Variant : : OBJECT , PNAME ( " theme_override_styles " ) + String ( " / " ) + E . item_name , PROPERTY_HINT_RESOURCE_TYPE , " StyleBox " , usage ) ) ;
} break ;
default : {
// Silences warning.
} break ;
2014-02-10 01:10:30 +00:00
}
}
}
2022-08-12 20:57:11 +00:00
void Control : : _validate_property ( PropertyInfo & p_property ) const {
2021-11-08 20:53:41 +00:00
// Update theme type variation options.
2022-08-12 20:57:11 +00:00
if ( p_property . name = = " theme_type_variation " ) {
2021-07-04 20:42:23 +00:00
List < StringName > names ;
// Only the default theme and the project theme are used for the list of options.
// This is an imposed limitation to simplify the logic needed to leverage those options.
2022-08-08 16:29:36 +00:00
ThemeDB : : get_singleton ( ) - > get_default_theme ( ) - > get_type_variation_list ( get_class_name ( ) , & names ) ;
if ( ThemeDB : : get_singleton ( ) - > get_project_theme ( ) . is_valid ( ) ) {
ThemeDB : : get_singleton ( ) - > get_project_theme ( ) - > get_type_variation_list ( get_class_name ( ) , & names ) ;
2021-07-04 20:42:23 +00:00
}
names . sort_custom < StringName : : AlphCompare > ( ) ;
Vector < StringName > unique_names ;
String hint_string ;
2021-07-24 13:46:25 +00:00
for ( const StringName & E : names ) {
2021-07-04 20:42:23 +00:00
// Skip duplicate values.
2021-07-16 03:45:57 +00:00
if ( unique_names . has ( E ) ) {
2021-07-04 20:42:23 +00:00
continue ;
}
2021-07-16 03:45:57 +00:00
hint_string + = String ( E ) + " , " ;
unique_names . append ( E ) ;
2021-07-04 20:42:23 +00:00
}
2022-08-12 20:57:11 +00:00
p_property . hint_string = hint_string ;
2021-07-04 20:42:23 +00:00
}
2021-11-08 20:53:41 +00:00
2022-08-12 20:57:11 +00:00
if ( p_property . name = = " mouse_force_pass_scroll_events " ) {
2022-05-16 13:10:30 +00:00
// Disable force pass if the control is not stopping the event.
if ( data . mouse_filter ! = MOUSE_FILTER_STOP ) {
2022-08-12 20:57:11 +00:00
p_property . usage | = PROPERTY_USAGE_READ_ONLY ;
2022-05-16 13:10:30 +00:00
}
}
2022-08-12 20:57:11 +00:00
if ( p_property . name = = " scale " ) {
p_property . hint = PROPERTY_HINT_LINK ;
2022-04-05 00:58:21 +00:00
}
2021-11-08 20:53:41 +00:00
// Validate which positioning properties should be displayed depending on the parent and the layout mode.
Node * parent_node = get_parent_control ( ) ;
if ( ! parent_node ) {
// If there is no parent, display both anchor and container options.
// Set the layout mode to be disabled with the proper value.
2022-08-12 20:57:11 +00:00
if ( p_property . name = = " layout_mode " ) {
p_property . hint_string = " Position,Anchors,Container,Uncontrolled " ;
p_property . usage | = PROPERTY_USAGE_READ_ONLY ;
2021-11-08 20:53:41 +00:00
}
// Use the layout mode to display or hide advanced anchoring properties.
bool use_custom_anchors = _get_anchors_layout_preset ( ) = = - 1 ; // Custom "preset".
2022-08-12 20:57:11 +00:00
if ( ! use_custom_anchors & & ( p_property . name . begins_with ( " anchor_ " ) | | p_property . name . begins_with ( " offset_ " ) | | p_property . name . begins_with ( " grow_ " ) ) ) {
p_property . usage ^ = PROPERTY_USAGE_EDITOR ;
2021-11-08 20:53:41 +00:00
}
} else if ( Object : : cast_to < Container > ( parent_node ) ) {
// If the parent is a container, display only container-related properties.
2022-11-30 14:08:39 +00:00
if ( p_property . name . begins_with ( " anchor_ " ) | | p_property . name . begins_with ( " offset_ " ) | | p_property . name . begins_with ( " grow_ " ) | | p_property . name = = " anchors_preset " ) {
p_property . usage ^ = PROPERTY_USAGE_DEFAULT ;
} else if ( p_property . name = = " position " | | p_property . name = = " rotation " | | p_property . name = = " scale " | | p_property . name = = " size " | | p_property . name = = " pivot_offset " ) {
p_property . usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_READ_ONLY ;
2022-08-12 20:57:11 +00:00
} else if ( p_property . name = = " layout_mode " ) {
2021-11-08 20:53:41 +00:00
// Set the layout mode to be disabled with the proper value.
2022-08-12 20:57:11 +00:00
p_property . hint_string = " Position,Anchors,Container,Uncontrolled " ;
p_property . usage | = PROPERTY_USAGE_READ_ONLY ;
} else if ( p_property . name = = " size_flags_horizontal " | | p_property . name = = " size_flags_vertical " ) {
2021-11-08 20:53:41 +00:00
// Filter allowed size flags based on the parent container configuration.
Container * parent_container = Object : : cast_to < Container > ( parent_node ) ;
Vector < int > size_flags ;
2022-08-12 20:57:11 +00:00
if ( p_property . name = = " size_flags_horizontal " ) {
2021-11-08 20:53:41 +00:00
size_flags = parent_container - > get_allowed_size_flags_horizontal ( ) ;
2022-08-12 20:57:11 +00:00
} else if ( p_property . name = = " size_flags_vertical " ) {
2021-11-08 20:53:41 +00:00
size_flags = parent_container - > get_allowed_size_flags_vertical ( ) ;
}
// Enforce the order of the options, regardless of what the container provided.
String hint_string ;
if ( size_flags . has ( SIZE_FILL ) ) {
hint_string + = " Fill:1 " ;
}
if ( size_flags . has ( SIZE_EXPAND ) ) {
if ( ! hint_string . is_empty ( ) ) {
hint_string + = " , " ;
}
hint_string + = " Expand:2 " ;
}
if ( size_flags . has ( SIZE_SHRINK_CENTER ) ) {
if ( ! hint_string . is_empty ( ) ) {
hint_string + = " , " ;
}
hint_string + = " Shrink Center:4 " ;
}
if ( size_flags . has ( SIZE_SHRINK_END ) ) {
if ( ! hint_string . is_empty ( ) ) {
hint_string + = " , " ;
}
hint_string + = " Shrink End:8 " ;
}
if ( hint_string . is_empty ( ) ) {
2022-08-12 20:57:11 +00:00
p_property . hint_string = " " ;
p_property . usage | = PROPERTY_USAGE_READ_ONLY ;
2021-11-08 20:53:41 +00:00
} else {
2022-08-12 20:57:11 +00:00
p_property . hint_string = hint_string ;
2021-11-08 20:53:41 +00:00
}
}
} else {
// If the parent is NOT a container or not a control at all, display only anchoring-related properties.
2022-08-12 20:57:11 +00:00
if ( p_property . name . begins_with ( " size_flags_ " ) ) {
p_property . usage ^ = PROPERTY_USAGE_EDITOR ;
2021-11-08 20:53:41 +00:00
2022-08-12 20:57:11 +00:00
} else if ( p_property . name = = " layout_mode " ) {
2021-11-08 20:53:41 +00:00
// Set the layout mode to be enabled with proper options.
2022-08-12 20:57:11 +00:00
p_property . hint_string = " Position,Anchors " ;
2021-11-08 20:53:41 +00:00
}
// Use the layout mode to display or hide advanced anchoring properties.
2023-01-03 16:21:26 +00:00
LayoutMode _layout = _get_layout_mode ( ) ;
bool use_anchors = ( _layout = = LayoutMode : : LAYOUT_MODE_ANCHORS | | _layout = = LayoutMode : : LAYOUT_MODE_UNCONTROLLED ) ;
2022-08-12 20:57:11 +00:00
if ( ! use_anchors & & p_property . name = = " anchors_preset " ) {
p_property . usage ^ = PROPERTY_USAGE_EDITOR ;
2021-11-08 20:53:41 +00:00
}
bool use_custom_anchors = use_anchors & & _get_anchors_layout_preset ( ) = = - 1 ; // Custom "preset".
2022-08-12 20:57:11 +00:00
if ( ! use_custom_anchors & & ( p_property . name . begins_with ( " anchor_ " ) | | p_property . name . begins_with ( " offset_ " ) | | p_property . name . begins_with ( " grow_ " ) ) ) {
p_property . usage ^ = PROPERTY_USAGE_EDITOR ;
2021-11-08 20:53:41 +00:00
}
2021-09-05 20:01:36 +00:00
}
2021-11-08 20:53:41 +00:00
2021-09-05 20:01:36 +00:00
// Disable the property if it's managed by the parent container.
2021-11-08 20:53:41 +00:00
if ( ! Object : : cast_to < Container > ( parent_node ) ) {
return ;
}
2021-09-05 20:01:36 +00:00
bool property_is_managed_by_container = false ;
for ( unsigned i = 0 ; i < properties_managed_by_container_count ; i + + ) {
2022-08-12 20:57:11 +00:00
property_is_managed_by_container = properties_managed_by_container [ i ] = = p_property . name ;
2021-09-05 20:01:36 +00:00
if ( property_is_managed_by_container ) {
break ;
}
}
if ( property_is_managed_by_container ) {
2022-08-12 20:57:11 +00:00
p_property . usage | = PROPERTY_USAGE_READ_ONLY ;
2021-09-05 20:01:36 +00:00
}
2021-07-04 20:42:23 +00:00
}
2022-08-19 15:36:15 +00:00
bool Control : : _property_can_revert ( const StringName & p_name ) const {
if ( p_name = = " layout_mode " | | p_name = = " anchors_preset " ) {
return true ;
}
return false ;
}
bool Control : : _property_get_revert ( const StringName & p_name , Variant & r_property ) const {
if ( p_name = = " layout_mode " ) {
r_property = _get_default_layout_mode ( ) ;
return true ;
} else if ( p_name = = " anchors_preset " ) {
r_property = LayoutPreset : : PRESET_TOP_LEFT ;
return true ;
}
return false ;
}
2022-07-22 15:06:03 +00:00
// Global relations.
bool Control : : is_top_level_control ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-07-22 15:06:03 +00:00
return is_inside_tree ( ) & & ( ! data . parent_canvas_item & & ! data . RI & & is_set_as_top_level ( ) ) ;
}
2014-02-10 01:10:30 +00:00
Control * Control : : get_parent_control ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( nullptr ) ;
2023-01-03 16:21:26 +00:00
return data . parent_control ;
2014-02-10 01:10:30 +00:00
}
2021-07-19 17:25:15 +00:00
Window * Control : : get_parent_window ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( nullptr ) ;
2021-07-19 17:25:15 +00:00
return data . parent_window ;
}
2022-07-22 15:06:03 +00:00
Control * Control : : get_root_parent_control ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( nullptr ) ;
2022-07-22 15:06:03 +00:00
const CanvasItem * ci = this ;
const Control * root = this ;
2020-09-03 11:22:16 +00:00
2022-07-22 15:06:03 +00:00
while ( ci ) {
const Control * c = Object : : cast_to < Control > ( ci ) ;
if ( c ) {
root = c ;
2020-09-03 11:22:16 +00:00
2022-07-22 15:06:03 +00:00
if ( c - > data . RI | | c - > is_top_level_control ( ) ) {
break ;
2020-09-03 11:22:16 +00:00
}
}
2022-07-22 15:06:03 +00:00
ci = ci - > get_parent_item ( ) ;
2021-05-27 17:31:33 +00:00
}
2022-07-22 15:06:03 +00:00
return const_cast < Control * > ( root ) ;
2020-09-30 10:00:21 +00:00
}
2022-07-22 15:06:03 +00:00
Rect2 Control : : get_parent_anchorable_rect ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Rect2 ( ) ) ;
2022-07-22 15:06:03 +00:00
if ( ! is_inside_tree ( ) ) {
return Rect2 ( ) ;
2020-03-06 17:00:16 +00:00
}
2022-07-22 15:06:03 +00:00
Rect2 parent_rect ;
if ( data . parent_canvas_item ) {
parent_rect = data . parent_canvas_item - > get_anchorable_rect ( ) ;
} else {
# ifdef TOOLS_ENABLED
2023-01-27 20:03:45 +00:00
Node * edited_scene_root = get_tree ( ) - > get_edited_scene_root ( ) ;
Node * scene_root_parent = edited_scene_root ? edited_scene_root - > get_parent ( ) : nullptr ;
if ( scene_root_parent & & get_viewport ( ) = = scene_root_parent - > get_viewport ( ) ) {
2022-10-18 14:43:37 +00:00
parent_rect . size = Size2 ( GLOBAL_GET ( " display/window/size/viewport_width " ) , GLOBAL_GET ( " display/window/size/viewport_height " ) ) ;
2022-07-22 15:06:03 +00:00
} else {
parent_rect = get_viewport ( ) - > get_visible_rect ( ) ;
}
2020-03-06 17:00:16 +00:00
2022-07-22 15:06:03 +00:00
# else
parent_rect = get_viewport ( ) - > get_visible_rect ( ) ;
# endif
2016-08-06 01:46:45 +00:00
}
2022-07-22 15:06:03 +00:00
return parent_rect ;
2016-08-06 01:46:45 +00:00
}
2022-07-22 15:06:03 +00:00
Size2 Control : : get_parent_area_size ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Size2 ( ) ) ;
2022-07-22 15:06:03 +00:00
return get_parent_anchorable_rect ( ) . size ;
}
2016-08-06 01:46:45 +00:00
2022-07-22 15:06:03 +00:00
// Positioning and sizing.
2020-03-06 17:00:16 +00:00
2022-07-22 15:06:03 +00:00
Transform2D Control : : _get_internal_transform ( ) const {
2024-03-16 14:02:28 +00:00
// T(pivot_offset) * R(rotation) * S(scale) * T(-pivot_offset)
Transform2D xform ( data . rotation , data . scale , 0.0f , data . pivot_offset ) ;
xform . translate_local ( - data . pivot_offset ) ;
return xform ;
2016-08-06 01:46:45 +00:00
}
2014-02-10 01:10:30 +00:00
2016-08-31 02:44:14 +00:00
void Control : : _update_canvas_item_transform ( ) {
2017-07-06 20:42:44 +00:00
Transform2D xform = _get_internal_transform ( ) ;
xform [ 2 ] + = get_position ( ) ;
2022-01-31 11:30:35 +00:00
// We use a little workaround to avoid flickering when moving the pivot with _edit_set_pivot()
if ( is_inside_tree ( ) & & Math : : abs ( Math : : sin ( data . rotation * 4.0f ) ) < 0.00001f & & get_viewport ( ) - > is_snap_controls_to_pixels_enabled ( ) ) {
2024-06-29 16:30:42 +00:00
xform [ 2 ] = ( xform [ 2 ] + Vector2 ( 0.5 , 0.5 ) ) . floor ( ) ;
2022-01-31 11:30:35 +00:00
}
2020-03-27 18:21:27 +00:00
RenderingServer : : get_singleton ( ) - > canvas_item_set_transform ( get_canvas_item ( ) , xform ) ;
2016-08-31 02:44:14 +00:00
}
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
Transform2D Control : : get_transform ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Transform2D ( ) ) ;
2022-07-22 15:06:03 +00:00
Transform2D xform = _get_internal_transform ( ) ;
xform [ 2 ] + = get_position ( ) ;
return xform ;
}
2022-02-15 17:06:48 +00:00
2023-02-02 16:20:31 +00:00
void Control : : _top_level_changed_on_parent ( ) {
2022-10-16 17:41:42 +00:00
// Update root control status.
_notification ( NOTIFICATION_EXIT_CANVAS ) ;
_notification ( NOTIFICATION_ENTER_CANVAS ) ;
}
2022-07-22 15:06:03 +00:00
/// Anchors and offsets.
2022-02-15 17:06:48 +00:00
2022-07-22 15:06:03 +00:00
void Control : : _set_anchor ( Side p_side , real_t p_anchor ) {
set_anchor ( p_side , p_anchor ) ;
}
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
void Control : : set_anchor ( Side p_side , real_t p_anchor , bool p_keep_offset , bool p_push_opposite_anchor ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
ERR_FAIL_INDEX ( ( int ) p_side , 4 ) ;
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
Rect2 parent_rect = get_parent_anchorable_rect ( ) ;
real_t parent_range = ( p_side = = SIDE_LEFT | | p_side = = SIDE_RIGHT ) ? parent_rect . size . x : parent_rect . size . y ;
real_t previous_pos = data . offset [ p_side ] + data . anchor [ p_side ] * parent_range ;
real_t previous_opposite_pos = data . offset [ ( p_side + 2 ) % 4 ] + data . anchor [ ( p_side + 2 ) % 4 ] * parent_range ;
2022-06-01 01:20:00 +00:00
2022-07-22 15:06:03 +00:00
data . anchor [ p_side ] = p_anchor ;
2016-06-14 00:37:04 +00:00
2022-07-22 15:06:03 +00:00
if ( ( ( p_side = = SIDE_LEFT | | p_side = = SIDE_TOP ) & & data . anchor [ p_side ] > data . anchor [ ( p_side + 2 ) % 4 ] ) | |
( ( p_side = = SIDE_RIGHT | | p_side = = SIDE_BOTTOM ) & & data . anchor [ p_side ] < data . anchor [ ( p_side + 2 ) % 4 ] ) ) {
if ( p_push_opposite_anchor ) {
data . anchor [ ( p_side + 2 ) % 4 ] = data . anchor [ p_side ] ;
} else {
data . anchor [ p_side ] = data . anchor [ ( p_side + 2 ) % 4 ] ;
}
}
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
if ( ! p_keep_offset ) {
data . offset [ p_side ] = previous_pos - data . anchor [ p_side ] * parent_range ;
if ( p_push_opposite_anchor ) {
data . offset [ ( p_side + 2 ) % 4 ] = previous_opposite_pos - data . anchor [ ( p_side + 2 ) % 4 ] * parent_range ;
}
}
if ( is_inside_tree ( ) ) {
_size_changed ( ) ;
}
2022-03-17 08:11:46 +00:00
2022-08-13 21:21:24 +00:00
queue_redraw ( ) ;
2022-07-22 15:06:03 +00:00
}
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
real_t Control : : get_anchor ( Side p_side ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( 0 ) ;
2022-07-22 15:06:03 +00:00
ERR_FAIL_INDEX_V ( int ( p_side ) , 4 , 0.0 ) ;
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
return data . anchor [ p_side ] ;
}
2020-03-14 16:06:39 +00:00
2022-07-22 15:06:03 +00:00
void Control : : set_offset ( Side p_side , real_t p_value ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
ERR_FAIL_INDEX ( ( int ) p_side , 4 ) ;
2022-03-16 07:50:48 +00:00
if ( data . offset [ p_side ] = = p_value ) {
return ;
}
2022-02-15 17:06:48 +00:00
2022-07-22 15:06:03 +00:00
data . offset [ p_side ] = p_value ;
_size_changed ( ) ;
}
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
real_t Control : : get_offset ( Side p_side ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( 0 ) ;
2022-07-22 15:06:03 +00:00
ERR_FAIL_INDEX_V ( ( int ) p_side , 4 , 0 ) ;
2016-01-17 01:41:10 +00:00
2022-07-22 15:06:03 +00:00
return data . offset [ p_side ] ;
}
2022-02-15 17:06:48 +00:00
2022-07-22 15:06:03 +00:00
void Control : : set_anchor_and_offset ( Side p_side , real_t p_anchor , real_t p_pos , bool p_push_opposite_anchor ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
set_anchor ( p_side , p_anchor , false , p_push_opposite_anchor ) ;
set_offset ( p_side , p_pos ) ;
}
2017-03-05 15:44:50 +00:00
2023-04-13 13:26:50 +00:00
void Control : : set_begin ( const Point2 & p_point ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2023-01-13 05:59:29 +00:00
ERR_FAIL_COND ( ! isfinite ( p_point . x ) | | ! isfinite ( p_point . y ) ) ;
2022-03-16 07:50:48 +00:00
if ( data . offset [ 0 ] = = p_point . x & & data . offset [ 1 ] = = p_point . y ) {
return ;
}
2022-07-22 15:06:03 +00:00
data . offset [ 0 ] = p_point . x ;
data . offset [ 1 ] = p_point . y ;
_size_changed ( ) ;
}
2022-02-15 17:06:48 +00:00
2023-04-13 13:26:50 +00:00
Point2 Control : : get_begin ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Vector2 ( ) ) ;
2023-04-13 13:26:50 +00:00
return Point2 ( data . offset [ 0 ] , data . offset [ 1 ] ) ;
2022-07-22 15:06:03 +00:00
}
2022-02-15 17:06:48 +00:00
2023-04-13 13:26:50 +00:00
void Control : : set_end ( const Point2 & p_point ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-03-16 07:50:48 +00:00
if ( data . offset [ 2 ] = = p_point . x & & data . offset [ 3 ] = = p_point . y ) {
return ;
}
2022-07-22 15:06:03 +00:00
data . offset [ 2 ] = p_point . x ;
data . offset [ 3 ] = p_point . y ;
_size_changed ( ) ;
}
2022-02-15 17:06:48 +00:00
2023-04-13 13:26:50 +00:00
Point2 Control : : get_end ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Point2 ( ) ) ;
2023-04-13 13:26:50 +00:00
return Point2 ( data . offset [ 2 ] , data . offset [ 3 ] ) ;
2022-07-22 15:06:03 +00:00
}
2022-02-15 17:06:48 +00:00
2022-07-22 15:06:03 +00:00
void Control : : set_h_grow_direction ( GrowDirection p_direction ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-03-16 07:50:48 +00:00
if ( data . h_grow = = p_direction ) {
return ;
}
2022-07-22 15:06:03 +00:00
ERR_FAIL_INDEX ( ( int ) p_direction , 3 ) ;
2022-02-15 17:06:48 +00:00
2022-07-22 15:06:03 +00:00
data . h_grow = p_direction ;
_size_changed ( ) ;
}
2022-02-15 17:06:48 +00:00
2022-07-22 15:06:03 +00:00
Control : : GrowDirection Control : : get_h_grow_direction ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( GROW_DIRECTION_BEGIN ) ;
2022-07-22 15:06:03 +00:00
return data . h_grow ;
}
2022-02-15 17:06:48 +00:00
2022-07-22 15:06:03 +00:00
void Control : : set_v_grow_direction ( GrowDirection p_direction ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-03-16 07:50:48 +00:00
if ( data . v_grow = = p_direction ) {
return ;
}
2022-07-22 15:06:03 +00:00
ERR_FAIL_INDEX ( ( int ) p_direction , 3 ) ;
2022-02-15 17:06:48 +00:00
2022-07-22 15:06:03 +00:00
data . v_grow = p_direction ;
_size_changed ( ) ;
}
2022-02-15 17:06:48 +00:00
2022-07-22 15:06:03 +00:00
Control : : GrowDirection Control : : get_v_grow_direction ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( GROW_DIRECTION_BEGIN ) ;
2022-07-22 15:06:03 +00:00
return data . v_grow ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : _compute_anchors ( Rect2 p_rect , const real_t p_offsets [ 4 ] , real_t ( & r_anchors ) [ 4 ] ) {
Size2 parent_rect_size = get_parent_anchorable_rect ( ) . size ;
ERR_FAIL_COND ( parent_rect_size . x = = 0.0 ) ;
ERR_FAIL_COND ( parent_rect_size . y = = 0.0 ) ;
real_t x = p_rect . position . x ;
if ( is_layout_rtl ( ) ) {
x = parent_rect_size . x - x - p_rect . size . x ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
r_anchors [ 0 ] = ( x - p_offsets [ 0 ] ) / parent_rect_size . x ;
r_anchors [ 1 ] = ( p_rect . position . y - p_offsets [ 1 ] ) / parent_rect_size . y ;
r_anchors [ 2 ] = ( x + p_rect . size . x - p_offsets [ 2 ] ) / parent_rect_size . x ;
r_anchors [ 3 ] = ( p_rect . position . y + p_rect . size . y - p_offsets [ 3 ] ) / parent_rect_size . y ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : _compute_offsets ( Rect2 p_rect , const real_t p_anchors [ 4 ] , real_t ( & r_offsets ) [ 4 ] ) {
Size2 parent_rect_size = get_parent_anchorable_rect ( ) . size ;
real_t x = p_rect . position . x ;
if ( is_layout_rtl ( ) ) {
x = parent_rect_size . x - x - p_rect . size . x ;
2020-05-14 14:41:43 +00:00
}
2022-07-22 15:06:03 +00:00
r_offsets [ 0 ] = x - ( p_anchors [ 0 ] * parent_rect_size . x ) ;
r_offsets [ 1 ] = p_rect . position . y - ( p_anchors [ 1 ] * parent_rect_size . y ) ;
r_offsets [ 2 ] = x + p_rect . size . x - ( p_anchors [ 2 ] * parent_rect_size . x ) ;
r_offsets [ 3 ] = p_rect . position . y + p_rect . size . y - ( p_anchors [ 3 ] * parent_rect_size . y ) ;
2016-05-03 14:10:28 +00:00
}
2022-07-22 15:06:03 +00:00
/// Presets and layout modes.
void Control : : _set_layout_mode ( LayoutMode p_mode ) {
bool list_changed = false ;
2022-08-19 15:36:15 +00:00
if ( data . stored_layout_mode ! = p_mode ) {
list_changed = true ;
data . stored_layout_mode = p_mode ;
}
2022-07-22 15:06:03 +00:00
2022-08-19 15:36:15 +00:00
if ( data . stored_layout_mode = = LayoutMode : : LAYOUT_MODE_POSITION ) {
data . stored_use_custom_anchors = false ;
set_anchors_and_offsets_preset ( LayoutPreset : : PRESET_TOP_LEFT , LayoutPresetMode : : PRESET_MODE_KEEP_SIZE ) ;
set_grow_direction_preset ( LayoutPreset : : PRESET_TOP_LEFT ) ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
if ( list_changed ) {
notify_property_list_changed ( ) ;
}
2014-02-10 01:10:30 +00:00
}
2023-01-10 20:07:57 +00:00
void Control : : _update_layout_mode ( ) {
LayoutMode computed_layout = _get_layout_mode ( ) ;
if ( data . stored_layout_mode ! = computed_layout ) {
data . stored_layout_mode = computed_layout ;
notify_property_list_changed ( ) ;
}
}
2022-07-22 15:06:03 +00:00
Control : : LayoutMode Control : : _get_layout_mode ( ) const {
Node * parent_node = get_parent_control ( ) ;
// In these modes the property is read-only.
if ( ! parent_node ) {
return LayoutMode : : LAYOUT_MODE_UNCONTROLLED ;
} else if ( Object : : cast_to < Container > ( parent_node ) ) {
return LayoutMode : : LAYOUT_MODE_CONTAINER ;
2016-05-03 14:10:28 +00:00
}
2022-07-22 15:06:03 +00:00
// If anchors are not in the top-left position, this is definitely in anchors mode.
if ( _get_anchors_layout_preset ( ) ! = ( int ) LayoutPreset : : PRESET_TOP_LEFT ) {
return LayoutMode : : LAYOUT_MODE_ANCHORS ;
2014-02-10 01:10:30 +00:00
}
2022-08-19 15:36:15 +00:00
// Otherwise fallback on what's stored.
return data . stored_layout_mode ;
}
Control : : LayoutMode Control : : _get_default_layout_mode ( ) const {
Node * parent_node = get_parent_control ( ) ;
// In these modes the property is read-only.
if ( ! parent_node ) {
return LayoutMode : : LAYOUT_MODE_UNCONTROLLED ;
} else if ( Object : : cast_to < Container > ( parent_node ) ) {
return LayoutMode : : LAYOUT_MODE_CONTAINER ;
2022-07-22 15:06:03 +00:00
}
2022-08-19 15:36:15 +00:00
// Otherwise fallback on the position mode.
2022-07-22 15:06:03 +00:00
return LayoutMode : : LAYOUT_MODE_POSITION ;
2014-02-10 01:10:30 +00:00
}
2020-05-14 12:29:06 +00:00
2022-07-22 15:06:03 +00:00
void Control : : _set_anchors_layout_preset ( int p_preset ) {
2023-01-03 16:21:26 +00:00
if ( data . stored_layout_mode ! = LayoutMode : : LAYOUT_MODE_UNCONTROLLED & & data . stored_layout_mode ! = LayoutMode : : LAYOUT_MODE_ANCHORS ) {
// In other modes the anchor preset is non-operational and shouldn't be set to anything.
return ;
2016-05-03 14:10:28 +00:00
}
2022-07-22 15:06:03 +00:00
if ( p_preset = = - 1 ) {
2022-08-19 15:36:15 +00:00
if ( ! data . stored_use_custom_anchors ) {
data . stored_use_custom_anchors = true ;
2022-07-22 15:06:03 +00:00
notify_property_list_changed ( ) ;
}
return ; // Keep settings as is.
}
2014-02-10 01:10:30 +00:00
2023-01-03 16:21:26 +00:00
bool list_changed = false ;
2022-08-19 15:36:15 +00:00
if ( data . stored_use_custom_anchors ) {
2022-07-22 15:06:03 +00:00
list_changed = true ;
2022-08-19 15:36:15 +00:00
data . stored_use_custom_anchors = false ;
2022-07-22 15:06:03 +00:00
}
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
LayoutPreset preset = ( LayoutPreset ) p_preset ;
// Set correct anchors.
set_anchors_preset ( preset ) ;
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
// Select correct preset mode.
switch ( preset ) {
case PRESET_TOP_LEFT :
case PRESET_TOP_RIGHT :
case PRESET_BOTTOM_LEFT :
case PRESET_BOTTOM_RIGHT :
case PRESET_CENTER_LEFT :
case PRESET_CENTER_TOP :
case PRESET_CENTER_RIGHT :
case PRESET_CENTER_BOTTOM :
case PRESET_CENTER :
set_offsets_preset ( preset , LayoutPresetMode : : PRESET_MODE_KEEP_SIZE ) ;
break ;
case PRESET_LEFT_WIDE :
case PRESET_TOP_WIDE :
case PRESET_RIGHT_WIDE :
case PRESET_BOTTOM_WIDE :
case PRESET_VCENTER_WIDE :
case PRESET_HCENTER_WIDE :
case PRESET_FULL_RECT :
set_offsets_preset ( preset , LayoutPresetMode : : PRESET_MODE_MINSIZE ) ;
break ;
}
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
// Select correct grow directions.
set_grow_direction_preset ( preset ) ;
2021-10-28 07:07:18 +00:00
2022-07-22 15:06:03 +00:00
if ( list_changed ) {
notify_property_list_changed ( ) ;
2021-08-22 15:37:22 +00:00
}
}
2022-07-22 15:06:03 +00:00
int Control : : _get_anchors_layout_preset ( ) const {
2023-01-03 16:21:26 +00:00
// If this is a layout mode that doesn't rely on anchors, avoid excessive checks.
if ( data . stored_layout_mode ! = LayoutMode : : LAYOUT_MODE_UNCONTROLLED & & data . stored_layout_mode ! = LayoutMode : : LAYOUT_MODE_ANCHORS ) {
return LayoutPreset : : PRESET_TOP_LEFT ;
}
2022-07-22 15:06:03 +00:00
// If the custom preset was selected by user, use it.
2022-08-19 15:36:15 +00:00
if ( data . stored_use_custom_anchors ) {
2022-07-22 15:06:03 +00:00
return - 1 ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
// Check anchors to determine if the current state matches a preset, or not.
2021-03-30 17:16:33 +00:00
2022-07-22 15:06:03 +00:00
float left = get_anchor ( SIDE_LEFT ) ;
float right = get_anchor ( SIDE_RIGHT ) ;
float top = get_anchor ( SIDE_TOP ) ;
float bottom = get_anchor ( SIDE_BOTTOM ) ;
2014-12-17 01:31:57 +00:00
2022-07-22 15:06:03 +00:00
if ( left = = ANCHOR_BEGIN & & right = = ANCHOR_BEGIN & & top = = ANCHOR_BEGIN & & bottom = = ANCHOR_BEGIN ) {
return ( int ) LayoutPreset : : PRESET_TOP_LEFT ;
}
if ( left = = ANCHOR_END & & right = = ANCHOR_END & & top = = ANCHOR_BEGIN & & bottom = = ANCHOR_BEGIN ) {
return ( int ) LayoutPreset : : PRESET_TOP_RIGHT ;
}
if ( left = = ANCHOR_BEGIN & & right = = ANCHOR_BEGIN & & top = = ANCHOR_END & & bottom = = ANCHOR_END ) {
return ( int ) LayoutPreset : : PRESET_BOTTOM_LEFT ;
}
if ( left = = ANCHOR_END & & right = = ANCHOR_END & & top = = ANCHOR_END & & bottom = = ANCHOR_END ) {
return ( int ) LayoutPreset : : PRESET_BOTTOM_RIGHT ;
}
2020-03-06 17:00:16 +00:00
2022-07-22 15:06:03 +00:00
if ( left = = ANCHOR_BEGIN & & right = = ANCHOR_BEGIN & & top = = 0.5 & & bottom = = 0.5 ) {
return ( int ) LayoutPreset : : PRESET_CENTER_LEFT ;
}
if ( left = = ANCHOR_END & & right = = ANCHOR_END & & top = = 0.5 & & bottom = = 0.5 ) {
return ( int ) LayoutPreset : : PRESET_CENTER_RIGHT ;
}
if ( left = = 0.5 & & right = = 0.5 & & top = = ANCHOR_BEGIN & & bottom = = ANCHOR_BEGIN ) {
return ( int ) LayoutPreset : : PRESET_CENTER_TOP ;
}
if ( left = = 0.5 & & right = = 0.5 & & top = = ANCHOR_END & & bottom = = ANCHOR_END ) {
return ( int ) LayoutPreset : : PRESET_CENTER_BOTTOM ;
}
if ( left = = 0.5 & & right = = 0.5 & & top = = 0.5 & & bottom = = 0.5 ) {
return ( int ) LayoutPreset : : PRESET_CENTER ;
}
2020-03-06 17:00:16 +00:00
2022-07-22 15:06:03 +00:00
if ( left = = ANCHOR_BEGIN & & right = = ANCHOR_BEGIN & & top = = ANCHOR_BEGIN & & bottom = = ANCHOR_END ) {
return ( int ) LayoutPreset : : PRESET_LEFT_WIDE ;
}
if ( left = = ANCHOR_END & & right = = ANCHOR_END & & top = = ANCHOR_BEGIN & & bottom = = ANCHOR_END ) {
return ( int ) LayoutPreset : : PRESET_RIGHT_WIDE ;
}
if ( left = = ANCHOR_BEGIN & & right = = ANCHOR_END & & top = = ANCHOR_BEGIN & & bottom = = ANCHOR_BEGIN ) {
return ( int ) LayoutPreset : : PRESET_TOP_WIDE ;
}
if ( left = = ANCHOR_BEGIN & & right = = ANCHOR_END & & top = = ANCHOR_END & & bottom = = ANCHOR_END ) {
return ( int ) LayoutPreset : : PRESET_BOTTOM_WIDE ;
2014-12-17 01:31:57 +00:00
}
2021-03-30 17:16:33 +00:00
2022-07-22 15:06:03 +00:00
if ( left = = 0.5 & & right = = 0.5 & & top = = ANCHOR_BEGIN & & bottom = = ANCHOR_END ) {
return ( int ) LayoutPreset : : PRESET_VCENTER_WIDE ;
}
if ( left = = ANCHOR_BEGIN & & right = = ANCHOR_END & & top = = 0.5 & & bottom = = 0.5 ) {
return ( int ) LayoutPreset : : PRESET_HCENTER_WIDE ;
2021-03-30 17:16:33 +00:00
}
2022-07-22 15:06:03 +00:00
if ( left = = ANCHOR_BEGIN & & right = = ANCHOR_END & & top = = ANCHOR_BEGIN & & bottom = = ANCHOR_END ) {
return ( int ) LayoutPreset : : PRESET_FULL_RECT ;
2021-03-30 17:16:33 +00:00
}
2022-07-22 15:06:03 +00:00
// Does not match any preset, return "Custom".
return - 1 ;
2020-03-06 17:00:16 +00:00
}
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
void Control : : set_anchors_preset ( LayoutPreset p_preset , bool p_keep_offsets ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
ERR_FAIL_INDEX ( ( int ) p_preset , 16 ) ;
2021-03-30 17:16:33 +00:00
2022-07-22 15:06:03 +00:00
//Left
switch ( p_preset ) {
case PRESET_TOP_LEFT :
case PRESET_BOTTOM_LEFT :
case PRESET_CENTER_LEFT :
case PRESET_TOP_WIDE :
case PRESET_BOTTOM_WIDE :
case PRESET_LEFT_WIDE :
case PRESET_HCENTER_WIDE :
case PRESET_FULL_RECT :
set_anchor ( SIDE_LEFT , ANCHOR_BEGIN , p_keep_offsets ) ;
break ;
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
case PRESET_CENTER_TOP :
case PRESET_CENTER_BOTTOM :
case PRESET_CENTER :
case PRESET_VCENTER_WIDE :
set_anchor ( SIDE_LEFT , 0.5 , p_keep_offsets ) ;
break ;
2020-03-06 17:00:16 +00:00
2022-07-22 15:06:03 +00:00
case PRESET_TOP_RIGHT :
case PRESET_BOTTOM_RIGHT :
case PRESET_CENTER_RIGHT :
case PRESET_RIGHT_WIDE :
set_anchor ( SIDE_LEFT , ANCHOR_END , p_keep_offsets ) ;
break ;
}
2017-01-11 21:29:59 +00:00
2022-07-22 15:06:03 +00:00
// Top
switch ( p_preset ) {
case PRESET_TOP_LEFT :
case PRESET_TOP_RIGHT :
case PRESET_CENTER_TOP :
case PRESET_LEFT_WIDE :
case PRESET_RIGHT_WIDE :
case PRESET_TOP_WIDE :
case PRESET_VCENTER_WIDE :
case PRESET_FULL_RECT :
set_anchor ( SIDE_TOP , ANCHOR_BEGIN , p_keep_offsets ) ;
break ;
case PRESET_CENTER_LEFT :
case PRESET_CENTER_RIGHT :
case PRESET_CENTER :
case PRESET_HCENTER_WIDE :
set_anchor ( SIDE_TOP , 0.5 , p_keep_offsets ) ;
break ;
case PRESET_BOTTOM_LEFT :
case PRESET_BOTTOM_RIGHT :
case PRESET_CENTER_BOTTOM :
case PRESET_BOTTOM_WIDE :
set_anchor ( SIDE_TOP , ANCHOR_END , p_keep_offsets ) ;
break ;
}
// Right
switch ( p_preset ) {
case PRESET_TOP_LEFT :
case PRESET_BOTTOM_LEFT :
case PRESET_CENTER_LEFT :
case PRESET_LEFT_WIDE :
set_anchor ( SIDE_RIGHT , ANCHOR_BEGIN , p_keep_offsets ) ;
break ;
case PRESET_CENTER_TOP :
case PRESET_CENTER_BOTTOM :
case PRESET_CENTER :
case PRESET_VCENTER_WIDE :
set_anchor ( SIDE_RIGHT , 0.5 , p_keep_offsets ) ;
break ;
case PRESET_TOP_RIGHT :
case PRESET_BOTTOM_RIGHT :
case PRESET_CENTER_RIGHT :
case PRESET_TOP_WIDE :
case PRESET_RIGHT_WIDE :
case PRESET_BOTTOM_WIDE :
case PRESET_HCENTER_WIDE :
case PRESET_FULL_RECT :
set_anchor ( SIDE_RIGHT , ANCHOR_END , p_keep_offsets ) ;
break ;
}
// Bottom
switch ( p_preset ) {
case PRESET_TOP_LEFT :
case PRESET_TOP_RIGHT :
case PRESET_CENTER_TOP :
case PRESET_TOP_WIDE :
set_anchor ( SIDE_BOTTOM , ANCHOR_BEGIN , p_keep_offsets ) ;
break ;
case PRESET_CENTER_LEFT :
case PRESET_CENTER_RIGHT :
case PRESET_CENTER :
case PRESET_HCENTER_WIDE :
set_anchor ( SIDE_BOTTOM , 0.5 , p_keep_offsets ) ;
break ;
case PRESET_BOTTOM_LEFT :
case PRESET_BOTTOM_RIGHT :
case PRESET_CENTER_BOTTOM :
case PRESET_LEFT_WIDE :
case PRESET_RIGHT_WIDE :
case PRESET_BOTTOM_WIDE :
case PRESET_VCENTER_WIDE :
case PRESET_FULL_RECT :
set_anchor ( SIDE_BOTTOM , ANCHOR_END , p_keep_offsets ) ;
break ;
}
}
void Control : : set_offsets_preset ( LayoutPreset p_preset , LayoutPresetMode p_resize_mode , int p_margin ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
ERR_FAIL_INDEX ( ( int ) p_preset , 16 ) ;
ERR_FAIL_INDEX ( ( int ) p_resize_mode , 4 ) ;
// Calculate the size if the node is not resized
Size2 min_size = get_minimum_size ( ) ;
Size2 new_size = get_size ( ) ;
if ( p_resize_mode = = PRESET_MODE_MINSIZE | | p_resize_mode = = PRESET_MODE_KEEP_HEIGHT ) {
new_size . x = min_size . x ;
}
if ( p_resize_mode = = PRESET_MODE_MINSIZE | | p_resize_mode = = PRESET_MODE_KEEP_WIDTH ) {
new_size . y = min_size . y ;
}
Rect2 parent_rect = get_parent_anchorable_rect ( ) ;
real_t x = parent_rect . size . x ;
if ( is_layout_rtl ( ) ) {
x = parent_rect . size . x - x - new_size . x ;
}
//Left
switch ( p_preset ) {
case PRESET_TOP_LEFT :
case PRESET_BOTTOM_LEFT :
case PRESET_CENTER_LEFT :
case PRESET_TOP_WIDE :
case PRESET_BOTTOM_WIDE :
case PRESET_LEFT_WIDE :
case PRESET_HCENTER_WIDE :
case PRESET_FULL_RECT :
data . offset [ 0 ] = x * ( 0.0 - data . anchor [ 0 ] ) + p_margin + parent_rect . position . x ;
break ;
case PRESET_CENTER_TOP :
case PRESET_CENTER_BOTTOM :
case PRESET_CENTER :
case PRESET_VCENTER_WIDE :
data . offset [ 0 ] = x * ( 0.5 - data . anchor [ 0 ] ) - new_size . x / 2 + parent_rect . position . x ;
break ;
case PRESET_TOP_RIGHT :
case PRESET_BOTTOM_RIGHT :
case PRESET_CENTER_RIGHT :
case PRESET_RIGHT_WIDE :
data . offset [ 0 ] = x * ( 1.0 - data . anchor [ 0 ] ) - new_size . x - p_margin + parent_rect . position . x ;
break ;
}
// Top
switch ( p_preset ) {
case PRESET_TOP_LEFT :
case PRESET_TOP_RIGHT :
case PRESET_CENTER_TOP :
case PRESET_LEFT_WIDE :
case PRESET_RIGHT_WIDE :
case PRESET_TOP_WIDE :
case PRESET_VCENTER_WIDE :
case PRESET_FULL_RECT :
data . offset [ 1 ] = parent_rect . size . y * ( 0.0 - data . anchor [ 1 ] ) + p_margin + parent_rect . position . y ;
break ;
case PRESET_CENTER_LEFT :
case PRESET_CENTER_RIGHT :
case PRESET_CENTER :
case PRESET_HCENTER_WIDE :
data . offset [ 1 ] = parent_rect . size . y * ( 0.5 - data . anchor [ 1 ] ) - new_size . y / 2 + parent_rect . position . y ;
break ;
case PRESET_BOTTOM_LEFT :
case PRESET_BOTTOM_RIGHT :
case PRESET_CENTER_BOTTOM :
case PRESET_BOTTOM_WIDE :
data . offset [ 1 ] = parent_rect . size . y * ( 1.0 - data . anchor [ 1 ] ) - new_size . y - p_margin + parent_rect . position . y ;
break ;
}
// Right
switch ( p_preset ) {
case PRESET_TOP_LEFT :
case PRESET_BOTTOM_LEFT :
case PRESET_CENTER_LEFT :
case PRESET_LEFT_WIDE :
data . offset [ 2 ] = x * ( 0.0 - data . anchor [ 2 ] ) + new_size . x + p_margin + parent_rect . position . x ;
break ;
case PRESET_CENTER_TOP :
case PRESET_CENTER_BOTTOM :
case PRESET_CENTER :
case PRESET_VCENTER_WIDE :
data . offset [ 2 ] = x * ( 0.5 - data . anchor [ 2 ] ) + new_size . x / 2 + parent_rect . position . x ;
break ;
case PRESET_TOP_RIGHT :
case PRESET_BOTTOM_RIGHT :
case PRESET_CENTER_RIGHT :
case PRESET_TOP_WIDE :
case PRESET_RIGHT_WIDE :
case PRESET_BOTTOM_WIDE :
case PRESET_HCENTER_WIDE :
case PRESET_FULL_RECT :
data . offset [ 2 ] = x * ( 1.0 - data . anchor [ 2 ] ) - p_margin + parent_rect . position . x ;
break ;
}
// Bottom
switch ( p_preset ) {
case PRESET_TOP_LEFT :
case PRESET_TOP_RIGHT :
case PRESET_CENTER_TOP :
case PRESET_TOP_WIDE :
data . offset [ 3 ] = parent_rect . size . y * ( 0.0 - data . anchor [ 3 ] ) + new_size . y + p_margin + parent_rect . position . y ;
break ;
case PRESET_CENTER_LEFT :
case PRESET_CENTER_RIGHT :
case PRESET_CENTER :
case PRESET_HCENTER_WIDE :
data . offset [ 3 ] = parent_rect . size . y * ( 0.5 - data . anchor [ 3 ] ) + new_size . y / 2 + parent_rect . position . y ;
break ;
case PRESET_BOTTOM_LEFT :
case PRESET_BOTTOM_RIGHT :
case PRESET_CENTER_BOTTOM :
case PRESET_LEFT_WIDE :
case PRESET_RIGHT_WIDE :
case PRESET_BOTTOM_WIDE :
case PRESET_VCENTER_WIDE :
case PRESET_FULL_RECT :
data . offset [ 3 ] = parent_rect . size . y * ( 1.0 - data . anchor [ 3 ] ) - p_margin + parent_rect . position . y ;
break ;
}
_size_changed ( ) ;
}
void Control : : set_anchors_and_offsets_preset ( LayoutPreset p_preset , LayoutPresetMode p_resize_mode , int p_margin ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
set_anchors_preset ( p_preset ) ;
set_offsets_preset ( p_preset , p_resize_mode , p_margin ) ;
}
void Control : : set_grow_direction_preset ( LayoutPreset p_preset ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
// Select correct horizontal grow direction.
switch ( p_preset ) {
case PRESET_TOP_LEFT :
case PRESET_BOTTOM_LEFT :
case PRESET_CENTER_LEFT :
case PRESET_LEFT_WIDE :
set_h_grow_direction ( GrowDirection : : GROW_DIRECTION_END ) ;
break ;
case PRESET_TOP_RIGHT :
case PRESET_BOTTOM_RIGHT :
case PRESET_CENTER_RIGHT :
case PRESET_RIGHT_WIDE :
set_h_grow_direction ( GrowDirection : : GROW_DIRECTION_BEGIN ) ;
break ;
case PRESET_CENTER_TOP :
case PRESET_CENTER_BOTTOM :
case PRESET_CENTER :
case PRESET_TOP_WIDE :
case PRESET_BOTTOM_WIDE :
case PRESET_VCENTER_WIDE :
case PRESET_HCENTER_WIDE :
case PRESET_FULL_RECT :
set_h_grow_direction ( GrowDirection : : GROW_DIRECTION_BOTH ) ;
break ;
2020-03-06 17:00:16 +00:00
}
2022-07-22 15:06:03 +00:00
// Select correct vertical grow direction.
switch ( p_preset ) {
case PRESET_TOP_LEFT :
case PRESET_TOP_RIGHT :
case PRESET_CENTER_TOP :
case PRESET_TOP_WIDE :
set_v_grow_direction ( GrowDirection : : GROW_DIRECTION_END ) ;
break ;
case PRESET_BOTTOM_LEFT :
case PRESET_BOTTOM_RIGHT :
case PRESET_CENTER_BOTTOM :
case PRESET_BOTTOM_WIDE :
set_v_grow_direction ( GrowDirection : : GROW_DIRECTION_BEGIN ) ;
break ;
case PRESET_CENTER_LEFT :
case PRESET_CENTER_RIGHT :
case PRESET_CENTER :
case PRESET_LEFT_WIDE :
case PRESET_RIGHT_WIDE :
case PRESET_VCENTER_WIDE :
case PRESET_HCENTER_WIDE :
case PRESET_FULL_RECT :
set_v_grow_direction ( GrowDirection : : GROW_DIRECTION_BOTH ) ;
break ;
2020-03-06 17:00:16 +00:00
}
2022-07-22 15:06:03 +00:00
}
2020-03-06 17:00:16 +00:00
2022-07-22 15:06:03 +00:00
/// Manual positioning.
2023-04-13 13:26:50 +00:00
void Control : : _set_position ( const Point2 & p_point ) {
2022-07-22 15:06:03 +00:00
set_position ( p_point ) ;
2020-03-12 12:37:40 +00:00
}
2023-04-13 13:26:50 +00:00
void Control : : set_position ( const Point2 & p_point , bool p_keep_offsets ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2024-05-03 02:41:17 +00:00
# ifdef TOOLS_ENABLED
// Can't compute anchors, set position directly and return immediately.
if ( saving & & ! is_inside_tree ( ) ) {
data . pos_cache = p_point ;
return ;
}
# endif
2022-07-22 15:06:03 +00:00
if ( p_keep_offsets ) {
_compute_anchors ( Rect2 ( p_point , data . size_cache ) , data . offset , data . anchor ) ;
2021-03-30 17:16:33 +00:00
} else {
2022-07-22 15:06:03 +00:00
_compute_offsets ( Rect2 ( p_point , data . size_cache ) , data . anchor , data . offset ) ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
_size_changed ( ) ;
2021-03-30 17:16:33 +00:00
}
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
Size2 Control : : get_position ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Size2 ( ) ) ;
2022-07-22 15:06:03 +00:00
return data . pos_cache ;
}
2019-07-05 20:32:52 +00:00
2022-07-22 15:06:03 +00:00
void Control : : _set_global_position ( const Point2 & p_point ) {
set_global_position ( p_point ) ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : set_global_position ( const Point2 & p_point , bool p_keep_offsets ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2024-03-15 03:19:44 +00:00
// (parent_global_transform * T(new_position) * internal_transform).origin == new_global_position
// (T(new_position) * internal_transform).origin == new_position_in_parent_space
// new_position == new_position_in_parent_space - internal_transform.origin
Point2 position_in_parent_space = data . parent_canvas_item ? data . parent_canvas_item - > get_global_transform ( ) . affine_inverse ( ) . xform ( p_point ) : p_point ;
set_position ( position_in_parent_space - _get_internal_transform ( ) . get_origin ( ) , p_keep_offsets ) ;
2014-02-10 01:10:30 +00:00
}
2020-03-12 12:37:40 +00:00
2022-07-22 15:06:03 +00:00
Point2 Control : : get_global_position ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Point2 ( ) ) ;
2022-07-22 15:06:03 +00:00
return get_global_transform ( ) . get_origin ( ) ;
2020-03-12 12:37:40 +00:00
}
2022-07-22 15:06:03 +00:00
Point2 Control : : get_screen_position ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Point2 ( ) ) ;
2022-07-22 15:06:03 +00:00
ERR_FAIL_COND_V ( ! is_inside_tree ( ) , Point2 ( ) ) ;
2022-10-01 02:31:52 +00:00
return get_screen_transform ( ) . get_origin ( ) ;
2020-09-03 11:22:16 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : _set_size ( const Size2 & p_size ) {
# ifdef DEBUG_ENABLED
if ( data . size_warning & & ( data . anchor [ SIDE_LEFT ] ! = data . anchor [ SIDE_RIGHT ] | | data . anchor [ SIDE_TOP ] ! = data . anchor [ SIDE_BOTTOM ] ) ) {
WARN_PRINT ( " Nodes with non-equal opposite anchors will have their size overridden after _ready(). \n If you want to set size, change the anchors or consider using set_deferred(). " ) ;
2014-12-17 01:31:57 +00:00
}
2022-07-22 15:06:03 +00:00
# endif
set_size ( p_size ) ;
2020-03-12 12:37:40 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : set_size ( const Size2 & p_size , bool p_keep_offsets ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2023-01-13 05:59:29 +00:00
ERR_FAIL_COND ( ! isfinite ( p_size . x ) | | ! isfinite ( p_size . y ) ) ;
2022-07-22 15:06:03 +00:00
Size2 new_size = p_size ;
Size2 min = get_combined_minimum_size ( ) ;
if ( new_size . x < min . x ) {
new_size . x = min . x ;
}
if ( new_size . y < min . y ) {
new_size . y = min . y ;
2014-12-17 01:31:57 +00:00
}
2014-02-10 01:10:30 +00:00
2024-05-03 02:41:17 +00:00
# ifdef TOOLS_ENABLED
// Can't compute anchors, set size directly and return immediately.
if ( saving & & ! is_inside_tree ( ) ) {
data . size_cache = new_size ;
return ;
}
# endif
2022-07-22 15:06:03 +00:00
if ( p_keep_offsets ) {
_compute_anchors ( Rect2 ( data . pos_cache , new_size ) , data . offset , data . anchor ) ;
} else {
_compute_offsets ( Rect2 ( data . pos_cache , new_size ) , data . anchor , data . offset ) ;
}
_size_changed ( ) ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
Size2 Control : : get_size ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Size2 ( ) ) ;
2022-07-22 15:06:03 +00:00
return data . size_cache ;
2016-06-01 14:41:25 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : reset_size ( ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
set_size ( Size2 ( ) ) ;
2016-06-01 14:41:25 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : set_rect ( const Rect2 & p_rect ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
for ( int i = 0 ; i < 4 ; i + + ) {
data . anchor [ i ] = ANCHOR_BEGIN ;
}
2016-06-01 14:41:25 +00:00
2022-07-22 15:06:03 +00:00
_compute_offsets ( p_rect , data . anchor , data . offset ) ;
if ( is_inside_tree ( ) ) {
_size_changed ( ) ;
}
2020-09-03 11:22:16 +00:00
}
2022-07-22 15:06:03 +00:00
Rect2 Control : : get_rect ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Rect2 ( ) ) ;
2022-10-01 02:31:52 +00:00
Transform2D xform = get_transform ( ) ;
return Rect2 ( xform . get_origin ( ) , xform . get_scale ( ) * get_size ( ) ) ;
2016-06-01 14:41:25 +00:00
}
2022-07-22 15:06:03 +00:00
Rect2 Control : : get_global_rect ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Rect2 ( ) ) ;
2022-10-01 02:31:52 +00:00
Transform2D xform = get_global_transform ( ) ;
return Rect2 ( xform . get_origin ( ) , xform . get_scale ( ) * get_size ( ) ) ;
2016-06-01 14:41:25 +00:00
}
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
Rect2 Control : : get_screen_rect ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Rect2 ( ) ) ;
2022-07-22 15:06:03 +00:00
ERR_FAIL_COND_V ( ! is_inside_tree ( ) , Rect2 ( ) ) ;
2014-02-10 01:10:30 +00:00
2022-10-01 02:31:52 +00:00
Transform2D xform = get_screen_transform ( ) ;
return Rect2 ( xform . get_origin ( ) , xform . get_scale ( ) * get_size ( ) ) ;
2014-02-10 01:10:30 +00:00
}
2020-03-12 12:37:40 +00:00
2022-07-22 15:06:03 +00:00
Rect2 Control : : get_anchorable_rect ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Rect2 ( ) ) ;
2022-07-22 15:06:03 +00:00
return Rect2 ( Point2 ( ) , get_size ( ) ) ;
2020-09-03 11:22:16 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : set_scale ( const Vector2 & p_scale ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-03-16 07:50:48 +00:00
if ( data . scale = = p_scale ) {
return ;
}
2022-07-22 15:06:03 +00:00
data . scale = p_scale ;
// Avoid having 0 scale values, can lead to errors in physics and rendering.
if ( data . scale . x = = 0 ) {
data . scale . x = CMP_EPSILON ;
}
if ( data . scale . y = = 0 ) {
data . scale . y = CMP_EPSILON ;
2014-12-17 01:31:57 +00:00
}
2022-08-13 21:21:24 +00:00
queue_redraw ( ) ;
2022-07-22 15:06:03 +00:00
_notify_transform ( ) ;
}
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
Vector2 Control : : get_scale ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Vector2 ( ) ) ;
2022-07-22 15:06:03 +00:00
return data . scale ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : set_rotation ( real_t p_radians ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-03-16 07:50:48 +00:00
if ( data . rotation = = p_radians ) {
return ;
}
2022-07-22 15:06:03 +00:00
data . rotation = p_radians ;
2022-08-13 21:21:24 +00:00
queue_redraw ( ) ;
2022-07-22 15:06:03 +00:00
_notify_transform ( ) ;
}
2014-02-10 01:10:30 +00:00
2022-12-18 15:58:19 +00:00
void Control : : set_rotation_degrees ( real_t p_degrees ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-12-18 15:58:19 +00:00
set_rotation ( Math : : deg_to_rad ( p_degrees ) ) ;
}
2022-07-22 15:06:03 +00:00
real_t Control : : get_rotation ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( 0 ) ;
2022-07-22 15:06:03 +00:00
return data . rotation ;
2014-02-10 01:10:30 +00:00
}
2022-12-18 15:58:19 +00:00
real_t Control : : get_rotation_degrees ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( 0 ) ;
2022-12-18 15:58:19 +00:00
return Math : : rad_to_deg ( get_rotation ( ) ) ;
}
2022-07-22 15:06:03 +00:00
void Control : : set_pivot_offset ( const Vector2 & p_pivot ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-03-16 07:50:48 +00:00
if ( data . pivot_offset = = p_pivot ) {
return ;
}
2022-07-22 15:06:03 +00:00
data . pivot_offset = p_pivot ;
2022-08-13 21:21:24 +00:00
queue_redraw ( ) ;
2022-07-22 15:06:03 +00:00
_notify_transform ( ) ;
}
2021-10-02 20:06:14 +00:00
2022-07-22 15:06:03 +00:00
Vector2 Control : : get_pivot_offset ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Vector2 ( ) ) ;
2022-07-22 15:06:03 +00:00
return data . pivot_offset ;
}
2021-10-02 20:06:14 +00:00
2022-07-22 15:06:03 +00:00
/// Sizes.
2021-10-02 20:06:14 +00:00
2022-07-22 15:06:03 +00:00
void Control : : _update_minimum_size ( ) {
if ( ! is_inside_tree ( ) ) {
2023-06-06 20:05:53 +00:00
data . updating_last_minimum_size = false ;
2022-07-22 15:06:03 +00:00
return ;
2021-10-02 20:06:14 +00:00
}
2023-06-06 18:55:03 +00:00
Size2 minsize = get_combined_minimum_size ( ) ;
data . updating_last_minimum_size = false ;
if ( minsize ! = data . last_minimum_size ) {
data . last_minimum_size = minsize ;
_size_changed ( ) ;
2023-09-04 15:01:33 +00:00
emit_signal ( SceneStringName ( minimum_size_changed ) ) ;
2023-06-06 18:55:03 +00:00
}
}
void Control : : update_minimum_size ( ) {
ERR_MAIN_THREAD_GUARD ;
if ( ! is_inside_tree ( ) | | data . block_minimum_size_adjust ) {
return ;
}
2021-10-02 20:06:14 +00:00
2023-01-03 16:21:26 +00:00
// Invalidate cache upwards.
2023-06-06 20:05:53 +00:00
Control * invalidate = this ;
2022-07-22 15:06:03 +00:00
while ( invalidate & & invalidate - > data . minimum_size_valid ) {
invalidate - > data . minimum_size_valid = false ;
if ( invalidate - > is_set_as_top_level ( ) ) {
2023-01-03 16:21:26 +00:00
break ; // Do not go further up.
2021-10-02 20:06:14 +00:00
}
2023-01-03 16:21:26 +00:00
Window * parent_window = invalidate - > get_parent_window ( ) ;
if ( parent_window & & parent_window - > is_wrapping_controls ( ) ) {
parent_window - > child_controls_changed ( ) ;
break ; // Stop on a window as well.
2021-10-02 20:06:14 +00:00
}
2023-01-03 16:21:26 +00:00
invalidate = invalidate - > get_parent_control ( ) ;
2021-10-02 20:06:14 +00:00
}
2022-07-22 15:06:03 +00:00
if ( ! is_visible_in_tree ( ) ) {
return ;
2021-10-02 20:06:14 +00:00
}
2022-07-22 15:06:03 +00:00
if ( data . updating_last_minimum_size ) {
return ;
2021-12-31 15:53:43 +00:00
}
2022-07-22 15:06:03 +00:00
data . updating_last_minimum_size = true ;
2021-10-02 20:06:14 +00:00
2023-12-18 14:46:56 +00:00
callable_mp ( this , & Control : : _update_minimum_size ) . call_deferred ( ) ;
2022-07-22 15:06:03 +00:00
}
2021-10-02 20:06:14 +00:00
2022-07-22 15:06:03 +00:00
void Control : : set_block_minimum_size_adjust ( bool p_block ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
data . block_minimum_size_adjust = p_block ;
}
2021-10-02 20:06:14 +00:00
2022-07-22 15:06:03 +00:00
Size2 Control : : get_minimum_size ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Size2 ( ) ) ;
2022-07-22 15:06:03 +00:00
Vector2 ms ;
2022-10-18 16:47:44 +00:00
GDVIRTUAL_CALL ( _get_minimum_size , ms ) ;
return ms ;
2022-07-22 15:06:03 +00:00
}
2021-10-02 20:06:14 +00:00
2022-09-22 23:53:24 +00:00
void Control : : set_custom_minimum_size ( const Size2 & p_custom ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
if ( p_custom = = data . custom_minimum_size ) {
return ;
2021-12-31 15:53:43 +00:00
}
2020-03-12 12:37:40 +00:00
2023-01-13 05:59:29 +00:00
if ( ! isfinite ( p_custom . x ) | | ! isfinite ( p_custom . y ) ) {
2022-12-12 12:51:37 +00:00
// Prevent infinite loop.
return ;
}
2022-07-22 15:06:03 +00:00
data . custom_minimum_size = p_custom ;
update_minimum_size ( ) ;
2023-11-09 13:09:15 +00:00
update_configuration_warnings ( ) ;
2021-10-02 20:06:14 +00:00
}
2022-09-22 23:53:24 +00:00
Size2 Control : : get_custom_minimum_size ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Size2 ( ) ) ;
2022-07-22 15:06:03 +00:00
return data . custom_minimum_size ;
2021-10-02 20:06:14 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : _update_minimum_size_cache ( ) {
Size2 minsize = get_minimum_size ( ) ;
2024-03-03 11:49:08 +00:00
minsize = minsize . max ( data . custom_minimum_size ) ;
2022-07-22 15:06:03 +00:00
data . minimum_size_cache = minsize ;
data . minimum_size_valid = true ;
2018-05-05 14:59:00 +00:00
}
2022-07-22 15:06:03 +00:00
Size2 Control : : get_combined_minimum_size ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Size2 ( ) ) ;
2022-07-22 15:06:03 +00:00
if ( ! data . minimum_size_valid ) {
const_cast < Control * > ( this ) - > _update_minimum_size_cache ( ) ;
}
return data . minimum_size_cache ;
2014-02-10 01:10:30 +00:00
}
void Control : : _size_changed ( ) {
2018-05-05 14:59:00 +00:00
Rect2 parent_rect = get_parent_anchorable_rect ( ) ;
2014-02-10 01:10:30 +00:00
2021-01-30 04:10:32 +00:00
real_t edge_pos [ 4 ] ;
2014-02-10 01:10:30 +00:00
for ( int i = 0 ; i < 4 ; i + + ) {
2021-01-30 04:10:32 +00:00
real_t area = parent_rect . size [ i & 1 ] ;
2020-12-22 16:24:29 +00:00
edge_pos [ i ] = data . offset [ i ] + ( data . anchor [ i ] * area ) ;
2014-02-10 01:10:30 +00:00
}
2020-12-22 16:24:29 +00:00
Point2 new_pos_cache = Point2 ( edge_pos [ 0 ] , edge_pos [ 1 ] ) ;
Size2 new_size_cache = Point2 ( edge_pos [ 2 ] , edge_pos [ 3 ] ) - new_pos_cache ;
2017-07-06 16:26:39 +00:00
2014-02-10 01:10:30 +00:00
Size2 minimum_size = get_combined_minimum_size ( ) ;
2018-02-12 03:58:39 +00:00
if ( minimum_size . width > new_size_cache . width ) {
if ( data . h_grow = = GROW_DIRECTION_BEGIN ) {
new_pos_cache . x + = new_size_cache . width - minimum_size . width ;
} else if ( data . h_grow = = GROW_DIRECTION_BOTH ) {
new_pos_cache . x + = 0.5 * ( new_size_cache . width - minimum_size . width ) ;
2017-07-06 16:26:39 +00:00
}
2018-02-12 03:58:39 +00:00
new_size_cache . width = minimum_size . width ;
2017-07-06 16:26:39 +00:00
}
2020-09-03 11:22:16 +00:00
if ( is_layout_rtl ( ) ) {
2023-06-06 08:49:05 +00:00
new_pos_cache . x = parent_rect . size . x + 2 * parent_rect . position . x - new_pos_cache . x - new_size_cache . x ;
2020-09-03 11:22:16 +00:00
}
2018-02-12 03:58:39 +00:00
if ( minimum_size . height > new_size_cache . height ) {
if ( data . v_grow = = GROW_DIRECTION_BEGIN ) {
new_pos_cache . y + = new_size_cache . height - minimum_size . height ;
} else if ( data . v_grow = = GROW_DIRECTION_BOTH ) {
new_pos_cache . y + = 0.5 * ( new_size_cache . height - minimum_size . height ) ;
2017-07-06 16:26:39 +00:00
}
2018-02-12 03:58:39 +00:00
new_size_cache . height = minimum_size . height ;
2017-07-06 16:26:39 +00:00
}
2014-02-10 01:10:30 +00:00
2024-07-04 23:41:21 +00:00
bool pos_changed = ! new_pos_cache . is_equal_approx ( data . pos_cache ) ;
bool size_changed = ! new_size_cache . is_equal_approx ( data . size_cache ) ;
2014-02-10 01:10:30 +00:00
2024-07-04 23:41:21 +00:00
if ( pos_changed ) {
data . pos_cache = new_pos_cache ;
}
if ( size_changed ) {
data . size_cache = new_size_cache ;
}
2014-02-10 01:10:30 +00:00
2018-07-04 12:29:29 +00:00
if ( is_inside_tree ( ) ) {
if ( pos_changed | | size_changed ) {
2024-05-28 19:48:43 +00:00
// Ensure global transform is marked as dirty before `NOTIFICATION_RESIZED` / `item_rect_changed` signal
// so an up to date global transform could be obtained when handling these.
2018-07-04 12:29:29 +00:00
_notify_transform ( ) ;
2024-05-28 19:48:43 +00:00
2024-07-01 03:17:43 +00:00
item_rect_changed ( size_changed ) ;
2024-05-28 19:48:43 +00:00
if ( size_changed ) {
notification ( NOTIFICATION_RESIZED ) ;
}
2018-07-04 12:29:29 +00:00
}
2016-08-31 02:44:14 +00:00
2018-07-04 12:29:29 +00:00
if ( pos_changed & & ! size_changed ) {
2024-07-04 23:41:21 +00:00
_update_canvas_item_transform ( ) ;
2023-07-31 23:55:31 +00:00
}
2024-07-04 23:41:21 +00:00
} else if ( pos_changed ) {
_notify_transform ( ) ;
2016-08-31 02:44:14 +00:00
}
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : _clear_size_warning ( ) {
data . size_warning = false ;
}
2021-11-08 20:53:41 +00:00
2022-07-22 15:06:03 +00:00
// Container sizing.
2021-11-08 20:53:41 +00:00
2023-01-07 19:37:21 +00:00
void Control : : set_h_size_flags ( BitField < SizeFlags > p_flags ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2023-01-07 19:37:21 +00:00
if ( ( int ) data . h_size_flags = = ( int ) p_flags ) {
2022-07-22 15:06:03 +00:00
return ;
2021-11-08 20:53:41 +00:00
}
2022-07-22 15:06:03 +00:00
data . h_size_flags = p_flags ;
2023-09-04 15:01:33 +00:00
emit_signal ( SceneStringName ( size_flags_changed ) ) ;
2022-07-22 15:06:03 +00:00
}
2023-01-07 19:37:21 +00:00
BitField < Control : : SizeFlags > Control : : get_h_size_flags ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( SIZE_EXPAND_FILL ) ;
2022-07-22 15:06:03 +00:00
return data . h_size_flags ;
}
2021-11-08 20:53:41 +00:00
2023-01-07 19:37:21 +00:00
void Control : : set_v_size_flags ( BitField < SizeFlags > p_flags ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2023-01-07 19:37:21 +00:00
if ( ( int ) data . v_size_flags = = ( int ) p_flags ) {
2022-07-22 15:06:03 +00:00
return ;
2021-11-08 20:53:41 +00:00
}
2022-07-22 15:06:03 +00:00
data . v_size_flags = p_flags ;
2023-09-04 15:01:33 +00:00
emit_signal ( SceneStringName ( size_flags_changed ) ) ;
2021-11-08 20:53:41 +00:00
}
2023-01-07 19:37:21 +00:00
BitField < Control : : SizeFlags > Control : : get_v_size_flags ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( SIZE_EXPAND_FILL ) ;
2022-07-22 15:06:03 +00:00
return data . v_size_flags ;
}
2021-11-08 20:53:41 +00:00
2022-07-22 15:06:03 +00:00
void Control : : set_stretch_ratio ( real_t p_ratio ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
if ( data . expand = = p_ratio ) {
return ;
2021-11-08 20:53:41 +00:00
}
2022-07-22 15:06:03 +00:00
data . expand = p_ratio ;
2023-09-04 15:01:33 +00:00
emit_signal ( SceneStringName ( size_flags_changed ) ) ;
2022-07-22 15:06:03 +00:00
}
2019-10-05 17:17:07 +00:00
2022-07-22 15:06:03 +00:00
real_t Control : : get_stretch_ratio ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( 0 ) ;
2022-07-22 15:06:03 +00:00
return data . expand ;
}
2018-01-11 22:21:04 +00:00
2022-07-22 15:06:03 +00:00
// Input events.
2017-08-11 17:25:26 +00:00
2022-07-22 15:06:03 +00:00
void Control : : _call_gui_input ( const Ref < InputEvent > & p_event ) {
2022-11-28 21:54:47 +00:00
if ( p_event - > get_device ( ) ! = InputEvent : : DEVICE_ID_INTERNAL ) {
2023-09-04 15:01:33 +00:00
emit_signal ( SceneStringName ( gui_input ) , p_event ) ; // Signal should be first, so it's possible to override an event (and then accept it).
2022-11-28 21:54:47 +00:00
}
2022-07-22 15:06:03 +00:00
if ( ! is_inside_tree ( ) | | get_viewport ( ) - > is_input_handled ( ) ) {
2022-11-28 21:54:47 +00:00
return ; // Input was handled, abort.
}
if ( p_event - > get_device ( ) ! = InputEvent : : DEVICE_ID_INTERNAL ) {
GDVIRTUAL_CALL ( _gui_input , p_event ) ;
2017-08-11 17:25:26 +00:00
}
2022-07-22 15:06:03 +00:00
if ( ! is_inside_tree ( ) | | get_viewport ( ) - > is_input_handled ( ) ) {
2022-11-28 21:54:47 +00:00
return ; // Input was handled, abort.
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
gui_input ( p_event ) ;
}
void Control : : gui_input ( const Ref < InputEvent > & p_event ) {
}
void Control : : accept_event ( ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2018-01-11 22:21:04 +00:00
if ( is_inside_tree ( ) ) {
2022-07-22 15:06:03 +00:00
get_viewport ( ) - > _gui_accept_event ( ) ;
2018-01-11 22:21:04 +00:00
}
2022-07-22 15:06:03 +00:00
}
2018-01-11 22:21:04 +00:00
2022-07-22 15:06:03 +00:00
bool Control : : has_point ( const Point2 & p_point ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-07-22 15:06:03 +00:00
bool ret ;
if ( GDVIRTUAL_CALL ( _has_point , p_point , ret ) ) {
return ret ;
}
return Rect2 ( Point2 ( ) , get_size ( ) ) . has_point ( p_point ) ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : set_mouse_filter ( MouseFilter p_filter ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
ERR_FAIL_INDEX ( p_filter , 3 ) ;
2023-10-31 17:55:34 +00:00
if ( data . mouse_filter = = p_filter ) {
return ;
}
2022-07-22 15:06:03 +00:00
data . mouse_filter = p_filter ;
notify_property_list_changed ( ) ;
update_configuration_warnings ( ) ;
2023-10-31 17:55:34 +00:00
if ( get_viewport ( ) ) {
get_viewport ( ) - > _gui_update_mouse_over ( ) ;
}
2016-03-09 16:59:35 +00:00
}
2022-07-22 15:06:03 +00:00
Control : : MouseFilter Control : : get_mouse_filter ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( MOUSE_FILTER_IGNORE ) ;
2022-07-22 15:06:03 +00:00
return data . mouse_filter ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : set_force_pass_scroll_events ( bool p_force_pass_scroll_events ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
data . force_pass_scroll_events = p_force_pass_scroll_events ;
}
2022-02-12 21:19:06 +00:00
2022-07-22 15:06:03 +00:00
bool Control : : is_force_pass_scroll_events ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-07-22 15:06:03 +00:00
return data . force_pass_scroll_events ;
}
void Control : : warp_mouse ( const Point2 & p_position ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
get_viewport ( ) - > warp_mouse ( get_global_transform_with_canvas ( ) . xform ( p_position ) ) ;
}
2022-09-24 14:32:53 +00:00
void Control : : set_shortcut_context ( const Node * p_node ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-09-24 14:32:53 +00:00
if ( p_node ! = nullptr ) {
data . shortcut_context = p_node - > get_instance_id ( ) ;
} else {
data . shortcut_context = ObjectID ( ) ;
}
}
Node * Control : : get_shortcut_context ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( nullptr ) ;
2022-09-24 14:32:53 +00:00
Object * ctx_obj = ObjectDB : : get_instance ( data . shortcut_context ) ;
Node * ctx_node = Object : : cast_to < Node > ( ctx_obj ) ;
return ctx_node ;
}
bool Control : : is_focus_owner_in_shortcut_context ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-09-24 14:32:53 +00:00
if ( data . shortcut_context = = ObjectID ( ) ) {
// No context, therefore global - always "in" context.
return true ;
}
const Node * ctx_node = get_shortcut_context ( ) ;
const Control * vp_focus = get_viewport ( ) ? get_viewport ( ) - > gui_get_focus_owner ( ) : nullptr ;
// If the context is valid and the viewport focus is valid, check if the context is the focus or is a parent of it.
return ctx_node & & vp_focus & & ( ctx_node = = vp_focus | | ctx_node - > is_ancestor_of ( vp_focus ) ) ;
}
2022-07-22 15:06:03 +00:00
// Drag and drop handling.
2023-01-09 18:24:36 +00:00
void Control : : set_drag_forwarding ( const Callable & p_drag , const Callable & p_can_drop , const Callable & p_drop ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2023-01-09 18:24:36 +00:00
data . forward_drag = p_drag ;
data . forward_can_drop = p_can_drop ;
data . forward_drop = p_drop ;
}
2022-07-22 15:06:03 +00:00
Variant Control : : get_drag_data ( const Point2 & p_point ) {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Variant ( ) ) ;
2023-01-09 18:24:36 +00:00
Variant ret ;
if ( data . forward_drag . is_valid ( ) ) {
Variant p = p_point ;
const Variant * vp [ 1 ] = { & p } ;
Callable : : CallError ce ;
data . forward_drag . callp ( ( const Variant * * ) vp , 1 , ret , ce ) ;
if ( ce . error ! = Callable : : CallError : : CALL_OK ) {
ERR_FAIL_V_MSG ( Variant ( ) , " Error calling forwarded method from 'get_drag_data': " + Variant : : get_callable_error_text ( data . forward_drag , ( const Variant * * ) vp , 1 , ce ) + " . " ) ;
2022-02-12 21:19:06 +00:00
}
2023-01-09 18:24:36 +00:00
return ret ;
2021-11-08 20:53:41 +00:00
}
2022-02-12 21:19:06 +00:00
2023-01-09 18:24:36 +00:00
GDVIRTUAL_CALL ( _get_drag_data , p_point , ret ) ;
return ret ;
2022-07-22 15:06:03 +00:00
}
2021-11-08 20:53:41 +00:00
2022-07-22 15:06:03 +00:00
bool Control : : can_drop_data ( const Point2 & p_point , const Variant & p_data ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2023-01-09 18:24:36 +00:00
if ( data . forward_can_drop . is_valid ( ) ) {
Variant ret ;
Variant p = p_point ;
const Variant * vp [ 2 ] = { & p , & p_data } ;
Callable : : CallError ce ;
data . forward_can_drop . callp ( ( const Variant * * ) vp , 2 , ret , ce ) ;
if ( ce . error ! = Callable : : CallError : : CALL_OK ) {
ERR_FAIL_V_MSG ( Variant ( ) , " Error calling forwarded method from 'can_drop_data': " + Variant : : get_callable_error_text ( data . forward_can_drop , ( const Variant * * ) vp , 2 , ce ) + " . " ) ;
2022-07-22 15:06:03 +00:00
}
2023-01-09 18:24:36 +00:00
return ret ;
2021-11-08 20:53:41 +00:00
}
2022-09-29 09:53:28 +00:00
bool ret = false ;
2022-10-18 16:47:44 +00:00
GDVIRTUAL_CALL ( _can_drop_data , p_point , p_data , ret ) ;
return ret ;
2021-11-08 20:53:41 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : drop_data ( const Point2 & p_point , const Variant & p_data ) {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD ;
2023-01-09 18:24:36 +00:00
if ( data . forward_drop . is_valid ( ) ) {
Variant ret ;
Variant p = p_point ;
const Variant * vp [ 2 ] = { & p , & p_data } ;
Callable : : CallError ce ;
data . forward_drop . callp ( ( const Variant * * ) vp , 2 , ret , ce ) ;
if ( ce . error ! = Callable : : CallError : : CALL_OK ) {
ERR_FAIL_MSG ( " Error calling forwarded method from 'drop_data': " + Variant : : get_callable_error_text ( data . forward_drop , ( const Variant * * ) vp , 2 , ce ) + " . " ) ;
2022-07-22 15:06:03 +00:00
}
2023-01-09 18:24:36 +00:00
return ;
2021-11-08 20:53:41 +00:00
}
2022-07-22 15:06:03 +00:00
GDVIRTUAL_CALL ( _drop_data , p_point , p_data ) ;
}
2021-11-08 20:53:41 +00:00
2022-07-22 15:06:03 +00:00
void Control : : force_drag ( const Variant & p_data , Control * p_control ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
ERR_FAIL_COND ( p_data . get_type ( ) = = Variant : : NIL ) ;
2021-11-08 20:53:41 +00:00
2022-07-22 15:06:03 +00:00
get_viewport ( ) - > _gui_force_drag ( this , p_data , p_control ) ;
}
2021-11-08 20:53:41 +00:00
2022-07-22 15:06:03 +00:00
void Control : : set_drag_preview ( Control * p_control ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
ERR_FAIL_COND ( ! get_viewport ( ) - > gui_is_dragging ( ) ) ;
get_viewport ( ) - > _gui_set_drag_preview ( this , p_control ) ;
}
2021-11-08 20:53:41 +00:00
2022-07-22 15:06:03 +00:00
bool Control : : is_drag_successful ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-07-22 15:06:03 +00:00
return is_inside_tree ( ) & & get_viewport ( ) - > gui_is_drag_successful ( ) ;
}
2021-11-08 20:53:41 +00:00
2022-07-22 15:06:03 +00:00
// Focus.
void Control : : set_focus_mode ( FocusMode p_focus_mode ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
ERR_FAIL_INDEX ( ( int ) p_focus_mode , 3 ) ;
2021-11-08 20:53:41 +00:00
2022-07-22 15:06:03 +00:00
if ( is_inside_tree ( ) & & p_focus_mode = = FOCUS_NONE & & data . focus_mode ! = FOCUS_NONE & & has_focus ( ) ) {
release_focus ( ) ;
2021-11-08 20:53:41 +00:00
}
2022-07-22 15:06:03 +00:00
data . focus_mode = p_focus_mode ;
2021-11-08 20:53:41 +00:00
}
2022-07-22 15:06:03 +00:00
Control : : FocusMode Control : : get_focus_mode ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( FOCUS_NONE ) ;
2022-07-22 15:06:03 +00:00
return data . focus_mode ;
}
2019-10-05 17:17:07 +00:00
2022-07-22 15:06:03 +00:00
bool Control : : has_focus ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-07-22 15:06:03 +00:00
return is_inside_tree ( ) & & get_viewport ( ) - > _gui_control_has_focus ( this ) ;
}
2017-08-11 16:16:28 +00:00
2022-07-22 15:06:03 +00:00
void Control : : grab_focus ( ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
2017-08-11 16:16:28 +00:00
2022-07-22 15:06:03 +00:00
if ( data . focus_mode = = FOCUS_NONE ) {
WARN_PRINT ( " This control can't grab focus. Use set_focus_mode() to allow a control to get focus. " ) ;
return ;
2017-08-11 16:16:28 +00:00
}
2022-07-22 15:06:03 +00:00
get_viewport ( ) - > _gui_control_grab_focus ( this ) ;
}
2017-08-11 16:16:28 +00:00
2022-07-22 15:06:03 +00:00
void Control : : grab_click_focus ( ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
2017-08-11 16:16:28 +00:00
2022-07-22 15:06:03 +00:00
get_viewport ( ) - > _gui_grab_click_focus ( this ) ;
}
2017-08-11 16:16:28 +00:00
2022-07-22 15:06:03 +00:00
void Control : : release_focus ( ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
2017-08-11 16:16:28 +00:00
2022-07-22 15:06:03 +00:00
if ( ! has_focus ( ) ) {
return ;
}
2017-08-11 16:16:28 +00:00
2022-07-22 15:06:03 +00:00
get_viewport ( ) - > gui_release_focus ( ) ;
}
static Control * _next_control ( Control * p_from ) {
if ( p_from - > is_set_as_top_level ( ) ) {
return nullptr ; // Can't go above.
2017-08-11 16:16:28 +00:00
}
2022-07-22 15:06:03 +00:00
Control * parent = Object : : cast_to < Control > ( p_from - > get_parent ( ) ) ;
2017-08-11 16:16:28 +00:00
2022-07-22 15:06:03 +00:00
if ( ! parent ) {
return nullptr ;
}
2017-08-11 16:16:28 +00:00
2022-07-22 15:06:03 +00:00
int next = p_from - > get_index ( ) ;
ERR_FAIL_INDEX_V ( next , parent - > get_child_count ( ) , nullptr ) ;
for ( int i = ( next + 1 ) ; i < parent - > get_child_count ( ) ; i + + ) {
Control * c = Object : : cast_to < Control > ( parent - > get_child ( i ) ) ;
if ( ! c | | ! c - > is_visible_in_tree ( ) | | c - > is_set_as_top_level ( ) ) {
continue ;
}
return c ;
2017-08-11 16:16:28 +00:00
}
2022-07-22 15:06:03 +00:00
// No next in parent, try the same in parent.
return _next_control ( parent ) ;
2017-08-11 16:16:28 +00:00
}
2022-07-22 15:06:03 +00:00
Control * Control : : find_next_valid_focus ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( nullptr ) ;
2022-07-22 15:06:03 +00:00
Control * from = const_cast < Control * > ( this ) ;
2019-10-05 17:17:07 +00:00
2022-07-22 15:06:03 +00:00
while ( true ) {
// If the focus property is manually overwritten, attempt to use it.
2017-09-19 20:39:19 +00:00
2022-07-22 15:06:03 +00:00
if ( ! data . focus_next . is_empty ( ) ) {
2023-06-05 12:56:54 +00:00
Node * n = get_node_or_null ( data . focus_next ) ;
ERR_FAIL_NULL_V_MSG ( n , nullptr , " Next focus node path is invalid: ' " + data . focus_next + " '. " ) ;
Control * c = Object : : cast_to < Control > ( n ) ;
ERR_FAIL_NULL_V_MSG ( c , nullptr , " Next focus node is not a control: ' " + n - > get_name ( ) + " '. " ) ;
2022-07-22 15:06:03 +00:00
if ( c - > is_visible ( ) & & c - > get_focus_mode ( ) ! = FOCUS_NONE ) {
return c ;
}
}
2017-09-26 22:31:05 +00:00
2022-07-22 15:06:03 +00:00
// Find next child.
Control * next_child = nullptr ;
for ( int i = 0 ; i < from - > get_child_count ( ) ; i + + ) {
Control * c = Object : : cast_to < Control > ( from - > get_child ( i ) ) ;
if ( ! c | | ! c - > is_visible_in_tree ( ) | | c - > is_set_as_top_level ( ) ) {
continue ;
}
next_child = c ;
2017-09-19 20:39:19 +00:00
break ;
2022-07-22 15:06:03 +00:00
}
2017-09-26 22:31:05 +00:00
2022-07-22 15:06:03 +00:00
if ( ! next_child ) {
next_child = _next_control ( from ) ;
if ( ! next_child ) { // Nothing else. Go up and find either window or subwindow.
next_child = const_cast < Control * > ( this ) ;
while ( next_child & & ! next_child - > is_set_as_top_level ( ) ) {
next_child = cast_to < Control > ( next_child - > get_parent ( ) ) ;
}
if ( ! next_child ) {
next_child = const_cast < Control * > ( this ) ;
while ( next_child ) {
if ( next_child - > data . RI ) {
break ;
}
next_child = next_child - > get_parent_control ( ) ;
}
}
}
}
if ( next_child = = from | | next_child = = this ) { // No next control.
return ( get_focus_mode ( ) = = FOCUS_ALL ) ? next_child : nullptr ;
}
if ( next_child ) {
if ( next_child - > get_focus_mode ( ) = = FOCUS_ALL ) {
return next_child ;
}
from = next_child ;
} else {
2017-09-26 22:31:05 +00:00
break ;
2022-07-22 15:06:03 +00:00
}
}
return nullptr ;
}
static Control * _prev_control ( Control * p_from ) {
Control * child = nullptr ;
for ( int i = p_from - > get_child_count ( ) - 1 ; i > = 0 ; i - - ) {
Control * c = Object : : cast_to < Control > ( p_from - > get_child ( i ) ) ;
if ( ! c | | ! c - > is_visible_in_tree ( ) | | c - > is_set_as_top_level ( ) ) {
continue ;
}
child = c ;
break ;
}
2017-09-26 22:31:05 +00:00
2022-07-22 15:06:03 +00:00
if ( ! child ) {
return p_from ;
2017-09-19 20:39:19 +00:00
}
2022-07-22 15:06:03 +00:00
// No prev in parent, try the same in parent.
return _prev_control ( child ) ;
}
2017-09-26 22:31:05 +00:00
2022-07-22 15:06:03 +00:00
Control * Control : : find_prev_valid_focus ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( nullptr ) ;
2022-07-22 15:06:03 +00:00
Control * from = const_cast < Control * > ( this ) ;
2017-09-26 22:31:05 +00:00
2022-07-22 15:06:03 +00:00
while ( true ) {
// If the focus property is manually overwritten, attempt to use it.
2017-09-19 20:39:19 +00:00
2022-07-22 15:06:03 +00:00
if ( ! data . focus_prev . is_empty ( ) ) {
2023-06-05 12:56:54 +00:00
Node * n = get_node_or_null ( data . focus_prev ) ;
ERR_FAIL_NULL_V_MSG ( n , nullptr , " Previous focus node path is invalid: ' " + data . focus_prev + " '. " ) ;
Control * c = Object : : cast_to < Control > ( n ) ;
ERR_FAIL_NULL_V_MSG ( c , nullptr , " Previous focus node is not a control: ' " + n - > get_name ( ) + " '. " ) ;
2022-07-22 15:06:03 +00:00
if ( c - > is_visible ( ) & & c - > get_focus_mode ( ) ! = FOCUS_NONE ) {
return c ;
}
}
2017-09-19 20:39:19 +00:00
2022-07-22 15:06:03 +00:00
// Find prev child.
2017-09-19 20:39:19 +00:00
2022-07-22 15:06:03 +00:00
Control * prev_child = nullptr ;
2017-09-19 20:39:19 +00:00
2022-07-22 15:06:03 +00:00
if ( from - > is_set_as_top_level ( ) | | ! Object : : cast_to < Control > ( from - > get_parent ( ) ) ) {
// Find last of the children.
2017-09-19 20:39:19 +00:00
2022-07-22 15:06:03 +00:00
prev_child = _prev_control ( from ) ;
2017-09-19 20:39:19 +00:00
2022-07-22 15:06:03 +00:00
} else {
for ( int i = ( from - > get_index ( ) - 1 ) ; i > = 0 ; i - - ) {
Control * c = Object : : cast_to < Control > ( from - > get_parent ( ) - > get_child ( i ) ) ;
2017-09-19 20:39:19 +00:00
2022-07-22 15:06:03 +00:00
if ( ! c | | ! c - > is_visible_in_tree ( ) | | c - > is_set_as_top_level ( ) ) {
continue ;
}
2017-09-19 20:39:19 +00:00
2022-07-22 15:06:03 +00:00
prev_child = c ;
break ;
}
2017-09-19 20:39:19 +00:00
2022-07-22 15:06:03 +00:00
if ( ! prev_child ) {
prev_child = Object : : cast_to < Control > ( from - > get_parent ( ) ) ;
} else {
prev_child = _prev_control ( prev_child ) ;
}
}
2021-11-08 20:53:41 +00:00
2022-07-22 15:06:03 +00:00
if ( prev_child = = from | | prev_child = = this ) { // No prev control.
return ( get_focus_mode ( ) = = FOCUS_ALL ) ? prev_child : nullptr ;
}
2021-11-08 20:53:41 +00:00
2022-07-22 15:06:03 +00:00
if ( prev_child - > get_focus_mode ( ) = = FOCUS_ALL ) {
return prev_child ;
}
2021-11-08 20:53:41 +00:00
2022-07-22 15:06:03 +00:00
from = prev_child ;
2021-11-08 20:53:41 +00:00
}
2019-10-05 17:17:07 +00:00
2022-07-22 15:06:03 +00:00
return nullptr ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : set_focus_neighbor ( Side p_side , const NodePath & p_neighbor ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-12-22 16:24:29 +00:00
ERR_FAIL_INDEX ( ( int ) p_side , 4 ) ;
2022-07-22 15:06:03 +00:00
data . focus_neighbor [ p_side ] = p_neighbor ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
NodePath Control : : get_focus_neighbor ( Side p_side ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( NodePath ( ) ) ;
2022-07-22 15:06:03 +00:00
ERR_FAIL_INDEX_V ( ( int ) p_side , 4 , NodePath ( ) ) ;
return data . focus_neighbor [ p_side ] ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : set_focus_next ( const NodePath & p_next ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
data . focus_next = p_next ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
NodePath Control : : get_focus_next ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( NodePath ( ) ) ;
2022-07-22 15:06:03 +00:00
return data . focus_next ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : set_focus_previous ( const NodePath & p_prev ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
data . focus_prev = p_prev ;
2014-02-10 01:10:30 +00:00
}
2020-05-14 12:29:06 +00:00
2022-07-22 15:06:03 +00:00
NodePath Control : : get_focus_previous ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( NodePath ( ) ) ;
2022-07-22 15:06:03 +00:00
return data . focus_prev ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
# define MAX_NEIGHBOR_SEARCH_COUNT 512
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
Control * Control : : _get_focus_neighbor ( Side p_side , int p_count ) {
ERR_FAIL_INDEX_V ( ( int ) p_side , 4 , nullptr ) ;
if ( p_count > = MAX_NEIGHBOR_SEARCH_COUNT ) {
return nullptr ;
2020-03-12 12:37:40 +00:00
}
2022-07-22 15:06:03 +00:00
if ( ! data . focus_neighbor [ p_side ] . is_empty ( ) ) {
2023-06-05 12:56:54 +00:00
Node * n = get_node_or_null ( data . focus_neighbor [ p_side ] ) ;
ERR_FAIL_NULL_V_MSG ( n , nullptr , " Neighbor focus node path is invalid: ' " + data . focus_neighbor [ p_side ] + " '. " ) ;
Control * c = Object : : cast_to < Control > ( n ) ;
ERR_FAIL_NULL_V_MSG ( c , nullptr , " Neighbor focus node is not a control: ' " + n - > get_name ( ) + " '. " ) ;
2022-07-22 15:06:03 +00:00
bool valid = true ;
if ( ! c - > is_visible ( ) ) {
valid = false ;
}
if ( c - > get_focus_mode ( ) = = FOCUS_NONE ) {
valid = false ;
}
if ( valid ) {
return c ;
}
2020-03-12 12:37:40 +00:00
2022-07-22 15:06:03 +00:00
c = c - > _get_focus_neighbor ( p_side , p_count + 1 ) ;
return c ;
}
2020-03-12 12:37:40 +00:00
2022-07-22 15:06:03 +00:00
real_t dist = 1e7 ;
Control * result = nullptr ;
2019-03-31 16:53:24 +00:00
2022-07-22 15:06:03 +00:00
Point2 points [ 4 ] ;
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
Transform2D xform = get_global_transform ( ) ;
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
points [ 0 ] = xform . xform ( Point2 ( ) ) ;
points [ 1 ] = xform . xform ( Point2 ( get_size ( ) . x , 0 ) ) ;
points [ 2 ] = xform . xform ( get_size ( ) ) ;
points [ 3 ] = xform . xform ( Point2 ( 0 , get_size ( ) . y ) ) ;
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
const Vector2 dir [ 4 ] = {
Vector2 ( - 1 , 0 ) ,
Vector2 ( 0 , - 1 ) ,
Vector2 ( 1 , 0 ) ,
Vector2 ( 0 , 1 )
} ;
2019-06-04 19:58:21 +00:00
2022-07-22 15:06:03 +00:00
Vector2 vdir = dir [ p_side ] ;
2019-03-31 16:53:24 +00:00
2022-07-22 15:06:03 +00:00
real_t maxd = - 1e7 ;
2020-09-03 11:22:16 +00:00
2022-07-22 15:06:03 +00:00
for ( int i = 0 ; i < 4 ; i + + ) {
real_t d = vdir . dot ( points [ i ] ) ;
if ( d > maxd ) {
maxd = d ;
}
2020-09-03 11:22:16 +00:00
}
2016-03-08 23:00:52 +00:00
2022-07-22 15:06:03 +00:00
Node * base = this ;
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
while ( base ) {
Control * c = Object : : cast_to < Control > ( base ) ;
if ( c ) {
if ( c - > data . RI ) {
break ;
}
}
base = base - > get_parent ( ) ;
2019-03-31 16:53:24 +00:00
}
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
if ( ! base ) {
return nullptr ;
2020-09-03 11:22:16 +00:00
}
2022-07-22 15:06:03 +00:00
_window_find_focus_neighbor ( vdir , base , points , maxd , dist , & result ) ;
2020-09-03 11:22:16 +00:00
2022-07-22 15:06:03 +00:00
return result ;
2019-03-31 16:53:24 +00:00
}
2023-08-16 12:02:22 +00:00
Control * Control : : find_valid_focus_neighbor ( Side p_side ) const {
return const_cast < Control * > ( this ) - > _get_focus_neighbor ( p_side ) ;
}
2022-07-22 15:06:03 +00:00
void Control : : _window_find_focus_neighbor ( const Vector2 & p_dir , Node * p_at , const Point2 * p_points , real_t p_min , real_t & r_closest_dist , Control * * r_closest ) {
if ( Object : : cast_to < Viewport > ( p_at ) ) {
return ; //bye
2020-05-14 14:41:43 +00:00
}
2016-03-08 23:00:52 +00:00
2022-07-22 15:06:03 +00:00
Control * c = Object : : cast_to < Control > ( p_at ) ;
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
if ( c & & c ! = this & & c - > get_focus_mode ( ) = = FOCUS_ALL & & c - > is_visible_in_tree ( ) ) {
Point2 points [ 4 ] ;
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
Transform2D xform = c - > get_global_transform ( ) ;
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
points [ 0 ] = xform . xform ( Point2 ( ) ) ;
points [ 1 ] = xform . xform ( Point2 ( c - > get_size ( ) . x , 0 ) ) ;
points [ 2 ] = xform . xform ( c - > get_size ( ) ) ;
points [ 3 ] = xform . xform ( Point2 ( 0 , c - > get_size ( ) . y ) ) ;
2021-11-20 08:04:57 +00:00
2024-08-13 20:20:51 +00:00
// Tie-breaking aims to address situations where a potential focus neighbor's bounding rect
// is right next to the currently focused control (e.g. in BoxContainer with
// separation overridden to 0). This needs specific handling so that the correct
// focus neighbor is selected.
// Calculate centers of the potential neighbor, currently focused, and closest controls.
Point2 center = xform . xform ( 0.5 * c - > get_size ( ) ) ;
// We only have the points, not an actual reference.
Point2 p_center = 0.25 * ( p_points [ 0 ] + p_points [ 1 ] + p_points [ 2 ] + p_points [ 3 ] ) ;
Point2 closest_center ;
bool should_tiebreak = false ;
if ( * r_closest ! = nullptr ) {
should_tiebreak = true ;
Control * closest = * r_closest ;
Transform2D closest_xform = closest - > get_global_transform ( ) ;
closest_center = closest_xform . xform ( 0.5 * closest - > get_size ( ) ) ;
}
2022-07-22 15:06:03 +00:00
real_t min = 1e7 ;
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
for ( int i = 0 ; i < 4 ; i + + ) {
real_t d = p_dir . dot ( points [ i ] ) ;
if ( d < min ) {
min = d ;
}
}
2020-03-12 12:37:40 +00:00
2022-07-22 15:06:03 +00:00
if ( min > ( p_min - CMP_EPSILON ) ) {
for ( int i = 0 ; i < 4 ; i + + ) {
Vector2 la = p_points [ i ] ;
Vector2 lb = p_points [ ( i + 1 ) % 4 ] ;
2020-03-12 12:37:40 +00:00
2022-07-22 15:06:03 +00:00
for ( int j = 0 ; j < 4 ; j + + ) {
Vector2 fa = points [ j ] ;
Vector2 fb = points [ ( j + 1 ) % 4 ] ;
Vector2 pa , pb ;
real_t d = Geometry2D : : get_closest_points_between_segments ( la , lb , fa , fb , pa , pb ) ;
if ( d < r_closest_dist ) {
r_closest_dist = d ;
* r_closest = c ;
2024-08-13 20:20:51 +00:00
} else if ( should_tiebreak & & d = = r_closest_dist ) {
// Tie-break in favor of the control most aligned with p_dir.
if ( p_dir . dot ( ( center - p_center ) . normalized ( ) ) > p_dir . dot ( ( closest_center - p_center ) . normalized ( ) ) ) {
r_closest_dist = d ;
* r_closest = c ;
}
2022-07-22 15:06:03 +00:00
}
}
}
}
2020-03-12 12:37:40 +00:00
}
2022-07-22 15:06:03 +00:00
for ( int i = 0 ; i < p_at - > get_child_count ( ) ; i + + ) {
Node * child = p_at - > get_child ( i ) ;
Control * childc = Object : : cast_to < Control > ( child ) ;
if ( childc & & childc - > data . RI ) {
continue ; //subwindow, ignore
}
_window_find_focus_neighbor ( p_dir , p_at - > get_child ( i ) , p_points , p_min , r_closest_dist , r_closest ) ;
}
2020-03-12 12:37:40 +00:00
}
2022-07-22 15:06:03 +00:00
// Rendering.
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
void Control : : set_default_cursor_shape ( CursorShape p_shape ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
ERR_FAIL_INDEX ( int ( p_shape ) , CURSOR_MAX ) ;
2014-02-10 01:10:30 +00:00
2022-03-10 17:44:28 +00:00
if ( data . default_cursor = = p_shape ) {
return ;
}
2022-07-22 15:06:03 +00:00
data . default_cursor = p_shape ;
2022-03-10 17:44:28 +00:00
if ( ! is_inside_tree ( ) ) {
return ;
}
if ( ! get_global_rect ( ) . has_point ( get_global_mouse_position ( ) ) ) {
return ;
}
2022-09-29 21:45:51 +00:00
// Display the new cursor shape instantly.
get_viewport ( ) - > update_mouse_cursor_state ( ) ;
2018-05-05 14:59:00 +00:00
}
2022-07-22 15:06:03 +00:00
Control : : CursorShape Control : : get_default_cursor_shape ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( CURSOR_ARROW ) ;
2022-07-22 15:06:03 +00:00
return data . default_cursor ;
2021-08-12 17:35:42 +00:00
}
2022-07-22 15:06:03 +00:00
Control : : CursorShape Control : : get_cursor_shape ( const Point2 & p_pos ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( CURSOR_ARROW ) ;
2022-07-22 15:06:03 +00:00
return data . default_cursor ;
2021-08-12 17:35:42 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : set_disable_visibility_clip ( bool p_ignore ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-03-16 07:50:48 +00:00
if ( data . disable_visibility_clip = = p_ignore ) {
return ;
}
2022-07-22 15:06:03 +00:00
data . disable_visibility_clip = p_ignore ;
2022-08-13 21:21:24 +00:00
queue_redraw ( ) ;
2015-12-20 21:21:53 +00:00
}
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
bool Control : : is_visibility_clip_disabled ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-07-22 15:06:03 +00:00
return data . disable_visibility_clip ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : set_clip_contents ( bool p_clip ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-03-16 07:50:48 +00:00
if ( data . clip_contents = = p_clip ) {
return ;
}
2022-07-22 15:06:03 +00:00
data . clip_contents = p_clip ;
2022-08-13 21:21:24 +00:00
queue_redraw ( ) ;
2014-02-10 01:10:30 +00:00
}
2020-05-14 12:29:06 +00:00
2022-07-22 15:06:03 +00:00
bool Control : : is_clipping_contents ( ) {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-07-22 15:06:03 +00:00
return data . clip_contents ;
2020-09-03 11:22:16 +00:00
}
2022-07-22 15:06:03 +00:00
// Theming.
2020-05-14 12:29:06 +00:00
2022-07-08 19:29:36 +00:00
void Control : : _theme_changed ( ) {
if ( is_inside_tree ( ) ) {
2022-09-02 14:03:23 +00:00
data . theme_owner - > propagate_theme_changed ( this , this , true , false ) ;
2022-07-08 19:29:36 +00:00
}
2021-03-22 01:43:01 +00:00
}
2022-07-08 19:29:36 +00:00
void Control : : _notify_theme_override_changed ( ) {
if ( ! data . bulk_theme_override & & is_inside_tree ( ) ) {
2022-07-22 15:06:03 +00:00
notification ( NOTIFICATION_THEME_CHANGED ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
2022-08-12 11:36:06 +00:00
void Control : : _invalidate_theme_cache ( ) {
data . theme_icon_cache . clear ( ) ;
data . theme_style_cache . clear ( ) ;
data . theme_font_cache . clear ( ) ;
data . theme_font_size_cache . clear ( ) ;
data . theme_color_cache . clear ( ) ;
data . theme_constant_cache . clear ( ) ;
}
2022-08-31 12:02:40 +00:00
void Control : : _update_theme_item_cache ( ) {
2023-09-08 19:00:10 +00:00
ThemeDB : : get_singleton ( ) - > update_class_instance_items ( this ) ;
2022-08-31 12:02:40 +00:00
}
2022-09-02 14:03:23 +00:00
void Control : : set_theme_owner_node ( Node * p_node ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-09-02 14:03:23 +00:00
data . theme_owner - > set_owner_node ( p_node ) ;
}
Node * Control : : get_theme_owner_node ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( nullptr ) ;
2022-09-02 14:03:23 +00:00
return data . theme_owner - > get_owner_node ( ) ;
}
bool Control : : has_theme_owner_node ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-09-02 14:03:23 +00:00
return data . theme_owner - > has_owner_node ( ) ;
}
2023-09-06 14:11:05 +00:00
void Control : : set_theme_context ( ThemeContext * p_context , bool p_propagate ) {
ERR_MAIN_THREAD_GUARD ;
data . theme_owner - > set_owner_context ( p_context , p_propagate ) ;
}
2022-07-22 15:06:03 +00:00
void Control : : set_theme ( const Ref < Theme > & p_theme ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
if ( data . theme = = p_theme ) {
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
if ( data . theme . is_valid ( ) ) {
2023-07-03 19:29:37 +00:00
data . theme - > disconnect_changed ( callable_mp ( this , & Control : : _theme_changed ) ) ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
data . theme = p_theme ;
2022-07-08 19:29:36 +00:00
if ( data . theme . is_valid ( ) ) {
2022-09-02 14:03:23 +00:00
data . theme_owner - > propagate_theme_changed ( this , this , is_inside_tree ( ) , true ) ;
2023-07-03 19:29:37 +00:00
data . theme - > connect_changed ( callable_mp ( this , & Control : : _theme_changed ) , CONNECT_DEFERRED ) ;
2022-07-08 19:29:36 +00:00
return ;
}
2022-07-22 15:06:03 +00:00
2022-07-08 19:29:36 +00:00
Control * parent_c = Object : : cast_to < Control > ( get_parent ( ) ) ;
2022-09-02 14:03:23 +00:00
if ( parent_c & & parent_c - > has_theme_owner_node ( ) ) {
data . theme_owner - > propagate_theme_changed ( this , parent_c - > get_theme_owner_node ( ) , is_inside_tree ( ) , true ) ;
2022-07-08 19:29:36 +00:00
return ;
2022-07-22 15:06:03 +00:00
}
2014-02-10 01:10:30 +00:00
2022-07-08 19:29:36 +00:00
Window * parent_w = cast_to < Window > ( get_parent ( ) ) ;
2022-09-02 14:03:23 +00:00
if ( parent_w & & parent_w - > has_theme_owner_node ( ) ) {
data . theme_owner - > propagate_theme_changed ( this , parent_w - > get_theme_owner_node ( ) , is_inside_tree ( ) , true ) ;
2022-07-08 19:29:36 +00:00
return ;
2014-02-10 01:10:30 +00:00
}
2022-07-08 19:29:36 +00:00
2022-09-02 14:03:23 +00:00
data . theme_owner - > propagate_theme_changed ( this , nullptr , is_inside_tree ( ) , true ) ;
2022-07-22 15:06:03 +00:00
}
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
Ref < Theme > Control : : get_theme ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Ref < Theme > ( ) ) ;
2022-07-22 15:06:03 +00:00
return data . theme ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : set_theme_type_variation ( const StringName & p_theme_type ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-03-16 07:50:48 +00:00
if ( data . theme_type_variation = = p_theme_type ) {
return ;
}
2022-07-22 15:06:03 +00:00
data . theme_type_variation = p_theme_type ;
2022-07-08 19:29:36 +00:00
if ( is_inside_tree ( ) ) {
notification ( NOTIFICATION_THEME_CHANGED ) ;
}
2022-07-22 15:06:03 +00:00
}
2016-03-08 23:00:52 +00:00
2022-07-22 15:06:03 +00:00
StringName Control : : get_theme_type_variation ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( StringName ( ) ) ;
2022-07-22 15:06:03 +00:00
return data . theme_type_variation ;
}
2017-11-16 09:45:52 +00:00
2022-07-22 15:06:03 +00:00
/// Theme property lookup.
2017-11-16 09:45:52 +00:00
2022-07-22 15:06:03 +00:00
Ref < Texture2D > Control : : get_theme_icon ( const StringName & p_name , const StringName & p_theme_type ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Ref < Texture2D > ( ) ) ;
2023-04-03 16:01:10 +00:00
if ( ! data . initialized ) {
2024-01-28 20:51:39 +00:00
WARN_PRINT_ONCE ( vformat ( " Attempting to access theme items too early in %s; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED " , get_description ( ) ) ) ;
2023-04-03 16:01:10 +00:00
}
2022-07-22 15:06:03 +00:00
if ( p_theme_type = = StringName ( ) | | p_theme_type = = get_class_name ( ) | | p_theme_type = = data . theme_type_variation ) {
2022-11-29 20:01:45 +00:00
const Ref < Texture2D > * tex = data . theme_icon_override . getptr ( p_name ) ;
2022-07-22 15:06:03 +00:00
if ( tex ) {
return * tex ;
}
2014-02-10 01:10:30 +00:00
}
2022-08-12 11:36:06 +00:00
if ( data . theme_icon_cache . has ( p_theme_type ) & & data . theme_icon_cache [ p_theme_type ] . has ( p_name ) ) {
return data . theme_icon_cache [ p_theme_type ] [ p_name ] ;
}
2024-06-24 14:09:20 +00:00
Vector < StringName > theme_types ;
data . theme_owner - > get_theme_type_dependencies ( this , p_theme_type , theme_types ) ;
2022-09-02 14:03:23 +00:00
Ref < Texture2D > icon = data . theme_owner - > get_theme_item_in_types ( Theme : : DATA_TYPE_ICON , p_name , theme_types ) ;
2022-08-12 11:36:06 +00:00
data . theme_icon_cache [ p_theme_type ] [ p_name ] = icon ;
return icon ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
Ref < StyleBox > Control : : get_theme_stylebox ( const StringName & p_name , const StringName & p_theme_type ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Ref < StyleBox > ( ) ) ;
2023-04-03 16:01:10 +00:00
if ( ! data . initialized ) {
2024-01-28 20:51:39 +00:00
WARN_PRINT_ONCE ( vformat ( " Attempting to access theme items too early in %s; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED " , get_description ( ) ) ) ;
2023-04-03 16:01:10 +00:00
}
2022-07-22 15:06:03 +00:00
if ( p_theme_type = = StringName ( ) | | p_theme_type = = get_class_name ( ) | | p_theme_type = = data . theme_type_variation ) {
2022-11-29 20:01:45 +00:00
const Ref < StyleBox > * style = data . theme_style_override . getptr ( p_name ) ;
2022-07-22 15:06:03 +00:00
if ( style ) {
return * style ;
}
}
2020-05-14 12:29:06 +00:00
2022-08-12 11:36:06 +00:00
if ( data . theme_style_cache . has ( p_theme_type ) & & data . theme_style_cache [ p_theme_type ] . has ( p_name ) ) {
return data . theme_style_cache [ p_theme_type ] [ p_name ] ;
}
2024-06-24 14:09:20 +00:00
Vector < StringName > theme_types ;
data . theme_owner - > get_theme_type_dependencies ( this , p_theme_type , theme_types ) ;
2022-09-02 14:03:23 +00:00
Ref < StyleBox > style = data . theme_owner - > get_theme_item_in_types ( Theme : : DATA_TYPE_STYLEBOX , p_name , theme_types ) ;
2022-08-12 11:36:06 +00:00
data . theme_style_cache [ p_theme_type ] [ p_name ] = style ;
return style ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
Ref < Font > Control : : get_theme_font ( const StringName & p_name , const StringName & p_theme_type ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Ref < Font > ( ) ) ;
2023-04-03 16:01:10 +00:00
if ( ! data . initialized ) {
2024-01-28 20:51:39 +00:00
WARN_PRINT_ONCE ( vformat ( " Attempting to access theme items too early in %s; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED " , get_description ( ) ) ) ;
2023-04-03 16:01:10 +00:00
}
2022-07-22 15:06:03 +00:00
if ( p_theme_type = = StringName ( ) | | p_theme_type = = get_class_name ( ) | | p_theme_type = = data . theme_type_variation ) {
2022-11-29 20:01:45 +00:00
const Ref < Font > * font = data . theme_font_override . getptr ( p_name ) ;
2022-07-22 15:06:03 +00:00
if ( font ) {
return * font ;
}
2018-09-06 16:32:34 +00:00
}
2016-01-17 01:41:10 +00:00
2022-08-12 11:36:06 +00:00
if ( data . theme_font_cache . has ( p_theme_type ) & & data . theme_font_cache [ p_theme_type ] . has ( p_name ) ) {
return data . theme_font_cache [ p_theme_type ] [ p_name ] ;
}
2024-06-24 14:09:20 +00:00
Vector < StringName > theme_types ;
data . theme_owner - > get_theme_type_dependencies ( this , p_theme_type , theme_types ) ;
2022-09-02 14:03:23 +00:00
Ref < Font > font = data . theme_owner - > get_theme_item_in_types ( Theme : : DATA_TYPE_FONT , p_name , theme_types ) ;
2022-08-12 11:36:06 +00:00
data . theme_font_cache [ p_theme_type ] [ p_name ] = font ;
return font ;
2016-03-08 23:00:52 +00:00
}
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
int Control : : get_theme_font_size ( const StringName & p_name , const StringName & p_theme_type ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( 0 ) ;
2023-04-03 16:01:10 +00:00
if ( ! data . initialized ) {
2024-01-28 20:51:39 +00:00
WARN_PRINT_ONCE ( vformat ( " Attempting to access theme items too early in %s; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED " , get_description ( ) ) ) ;
2023-04-03 16:01:10 +00:00
}
2022-07-22 15:06:03 +00:00
if ( p_theme_type = = StringName ( ) | | p_theme_type = = get_class_name ( ) | | p_theme_type = = data . theme_type_variation ) {
2022-11-29 20:01:45 +00:00
const int * font_size = data . theme_font_size_override . getptr ( p_name ) ;
2022-07-22 15:06:03 +00:00
if ( font_size & & ( * font_size ) > 0 ) {
return * font_size ;
}
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2022-08-12 11:36:06 +00:00
if ( data . theme_font_size_cache . has ( p_theme_type ) & & data . theme_font_size_cache [ p_theme_type ] . has ( p_name ) ) {
return data . theme_font_size_cache [ p_theme_type ] [ p_name ] ;
}
2024-06-24 14:09:20 +00:00
Vector < StringName > theme_types ;
data . theme_owner - > get_theme_type_dependencies ( this , p_theme_type , theme_types ) ;
2022-09-02 14:03:23 +00:00
int font_size = data . theme_owner - > get_theme_item_in_types ( Theme : : DATA_TYPE_FONT_SIZE , p_name , theme_types ) ;
2022-08-12 11:36:06 +00:00
data . theme_font_size_cache [ p_theme_type ] [ p_name ] = font_size ;
return font_size ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
Color Control : : get_theme_color ( const StringName & p_name , const StringName & p_theme_type ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Color ( ) ) ;
2023-04-03 16:01:10 +00:00
if ( ! data . initialized ) {
2024-01-28 20:51:39 +00:00
WARN_PRINT_ONCE ( vformat ( " Attempting to access theme items too early in %s; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED " , get_description ( ) ) ) ;
2023-04-03 16:01:10 +00:00
}
2022-07-22 15:06:03 +00:00
if ( p_theme_type = = StringName ( ) | | p_theme_type = = get_class_name ( ) | | p_theme_type = = data . theme_type_variation ) {
2022-11-29 20:01:45 +00:00
const Color * color = data . theme_color_override . getptr ( p_name ) ;
2022-07-22 15:06:03 +00:00
if ( color ) {
return * color ;
}
}
2014-02-10 01:10:30 +00:00
2022-08-12 11:36:06 +00:00
if ( data . theme_color_cache . has ( p_theme_type ) & & data . theme_color_cache [ p_theme_type ] . has ( p_name ) ) {
return data . theme_color_cache [ p_theme_type ] [ p_name ] ;
}
2024-06-24 14:09:20 +00:00
Vector < StringName > theme_types ;
data . theme_owner - > get_theme_type_dependencies ( this , p_theme_type , theme_types ) ;
2022-09-02 14:03:23 +00:00
Color color = data . theme_owner - > get_theme_item_in_types ( Theme : : DATA_TYPE_COLOR , p_name , theme_types ) ;
2022-08-12 11:36:06 +00:00
data . theme_color_cache [ p_theme_type ] [ p_name ] = color ;
return color ;
2022-07-22 15:06:03 +00:00
}
2016-06-14 00:10:45 +00:00
2022-07-22 15:06:03 +00:00
int Control : : get_theme_constant ( const StringName & p_name , const StringName & p_theme_type ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( 0 ) ;
2023-04-03 16:01:10 +00:00
if ( ! data . initialized ) {
2024-01-28 20:51:39 +00:00
WARN_PRINT_ONCE ( vformat ( " Attempting to access theme items too early in %s; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED " , get_description ( ) ) ) ;
2023-04-03 16:01:10 +00:00
}
2022-07-22 15:06:03 +00:00
if ( p_theme_type = = StringName ( ) | | p_theme_type = = get_class_name ( ) | | p_theme_type = = data . theme_type_variation ) {
2022-11-29 20:01:45 +00:00
const int * constant = data . theme_constant_override . getptr ( p_name ) ;
2022-07-22 15:06:03 +00:00
if ( constant ) {
return * constant ;
}
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2022-08-12 11:36:06 +00:00
if ( data . theme_constant_cache . has ( p_theme_type ) & & data . theme_constant_cache [ p_theme_type ] . has ( p_name ) ) {
return data . theme_constant_cache [ p_theme_type ] [ p_name ] ;
}
2024-06-24 14:09:20 +00:00
Vector < StringName > theme_types ;
data . theme_owner - > get_theme_type_dependencies ( this , p_theme_type , theme_types ) ;
2022-09-02 14:03:23 +00:00
int constant = data . theme_owner - > get_theme_item_in_types ( Theme : : DATA_TYPE_CONSTANT , p_name , theme_types ) ;
2022-08-12 11:36:06 +00:00
data . theme_constant_cache [ p_theme_type ] [ p_name ] = constant ;
return constant ;
2022-07-22 15:06:03 +00:00
}
2020-03-06 17:00:16 +00:00
2023-09-08 19:00:10 +00:00
Variant Control : : get_theme_item ( Theme : : DataType p_data_type , const StringName & p_name , const StringName & p_theme_type ) const {
switch ( p_data_type ) {
case Theme : : DATA_TYPE_COLOR :
return get_theme_color ( p_name , p_theme_type ) ;
case Theme : : DATA_TYPE_CONSTANT :
return get_theme_constant ( p_name , p_theme_type ) ;
case Theme : : DATA_TYPE_FONT :
return get_theme_font ( p_name , p_theme_type ) ;
case Theme : : DATA_TYPE_FONT_SIZE :
return get_theme_font_size ( p_name , p_theme_type ) ;
case Theme : : DATA_TYPE_ICON :
return get_theme_icon ( p_name , p_theme_type ) ;
case Theme : : DATA_TYPE_STYLEBOX :
return get_theme_stylebox ( p_name , p_theme_type ) ;
case Theme : : DATA_TYPE_MAX :
break ; // Can't happen, but silences warning.
}
return Variant ( ) ;
}
2023-08-13 00:33:39 +00:00
# ifdef TOOLS_ENABLED
Ref < Texture2D > Control : : get_editor_theme_icon ( const StringName & p_name ) const {
return get_theme_icon ( p_name , SNAME ( " EditorIcons " ) ) ;
}
# endif
2022-07-22 15:06:03 +00:00
bool Control : : has_theme_icon ( const StringName & p_name , const StringName & p_theme_type ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2023-04-03 16:01:10 +00:00
if ( ! data . initialized ) {
2024-01-28 20:51:39 +00:00
WARN_PRINT_ONCE ( vformat ( " Attempting to access theme items too early in %s; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED " , get_description ( ) ) ) ;
2023-04-03 16:01:10 +00:00
}
2022-07-22 15:06:03 +00:00
if ( p_theme_type = = StringName ( ) | | p_theme_type = = get_class_name ( ) | | p_theme_type = = data . theme_type_variation ) {
if ( has_theme_icon_override ( p_name ) ) {
return true ;
}
2020-05-14 14:41:43 +00:00
}
2020-03-06 17:00:16 +00:00
2024-06-24 14:09:20 +00:00
Vector < StringName > theme_types ;
data . theme_owner - > get_theme_type_dependencies ( this , p_theme_type , theme_types ) ;
2022-09-02 14:03:23 +00:00
return data . theme_owner - > has_theme_item_in_types ( Theme : : DATA_TYPE_ICON , p_name , theme_types ) ;
2022-07-22 15:06:03 +00:00
}
bool Control : : has_theme_stylebox ( const StringName & p_name , const StringName & p_theme_type ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2023-04-03 16:01:10 +00:00
if ( ! data . initialized ) {
2024-01-28 20:51:39 +00:00
WARN_PRINT_ONCE ( vformat ( " Attempting to access theme items too early in %s; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED " , get_description ( ) ) ) ;
2023-04-03 16:01:10 +00:00
}
2022-07-22 15:06:03 +00:00
if ( p_theme_type = = StringName ( ) | | p_theme_type = = get_class_name ( ) | | p_theme_type = = data . theme_type_variation ) {
if ( has_theme_stylebox_override ( p_name ) ) {
return true ;
2016-06-14 00:10:45 +00:00
}
2014-02-10 01:10:30 +00:00
}
2024-06-24 14:09:20 +00:00
Vector < StringName > theme_types ;
data . theme_owner - > get_theme_type_dependencies ( this , p_theme_type , theme_types ) ;
2022-09-02 14:03:23 +00:00
return data . theme_owner - > has_theme_item_in_types ( Theme : : DATA_TYPE_STYLEBOX , p_name , theme_types ) ;
2022-07-22 15:06:03 +00:00
}
bool Control : : has_theme_font ( const StringName & p_name , const StringName & p_theme_type ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2023-04-03 16:01:10 +00:00
if ( ! data . initialized ) {
2024-01-28 20:51:39 +00:00
WARN_PRINT_ONCE ( vformat ( " Attempting to access theme items too early in %s; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED " , get_description ( ) ) ) ;
2023-04-03 16:01:10 +00:00
}
2022-07-22 15:06:03 +00:00
if ( p_theme_type = = StringName ( ) | | p_theme_type = = get_class_name ( ) | | p_theme_type = = data . theme_type_variation ) {
if ( has_theme_font_override ( p_name ) ) {
return true ;
2020-03-06 17:00:16 +00:00
}
}
2024-06-24 14:09:20 +00:00
Vector < StringName > theme_types ;
data . theme_owner - > get_theme_type_dependencies ( this , p_theme_type , theme_types ) ;
2022-09-02 14:03:23 +00:00
return data . theme_owner - > has_theme_item_in_types ( Theme : : DATA_TYPE_FONT , p_name , theme_types ) ;
2022-07-22 15:06:03 +00:00
}
bool Control : : has_theme_font_size ( const StringName & p_name , const StringName & p_theme_type ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2023-04-03 16:01:10 +00:00
if ( ! data . initialized ) {
2024-01-28 20:51:39 +00:00
WARN_PRINT_ONCE ( vformat ( " Attempting to access theme items too early in %s; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED " , get_description ( ) ) ) ;
2023-04-03 16:01:10 +00:00
}
2022-07-22 15:06:03 +00:00
if ( p_theme_type = = StringName ( ) | | p_theme_type = = get_class_name ( ) | | p_theme_type = = data . theme_type_variation ) {
if ( has_theme_font_size_override ( p_name ) ) {
return true ;
2016-07-18 19:41:28 +00:00
}
2016-06-14 00:10:45 +00:00
}
2014-02-10 01:10:30 +00:00
2024-06-24 14:09:20 +00:00
Vector < StringName > theme_types ;
data . theme_owner - > get_theme_type_dependencies ( this , p_theme_type , theme_types ) ;
2022-09-02 14:03:23 +00:00
return data . theme_owner - > has_theme_item_in_types ( Theme : : DATA_TYPE_FONT_SIZE , p_name , theme_types ) ;
2016-07-18 19:41:28 +00:00
}
2022-07-22 15:06:03 +00:00
bool Control : : has_theme_color ( const StringName & p_name , const StringName & p_theme_type ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2023-04-03 16:01:10 +00:00
if ( ! data . initialized ) {
2024-01-28 20:51:39 +00:00
WARN_PRINT_ONCE ( vformat ( " Attempting to access theme items too early in %s; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED " , get_description ( ) ) ) ;
2023-04-03 16:01:10 +00:00
}
2022-07-22 15:06:03 +00:00
if ( p_theme_type = = StringName ( ) | | p_theme_type = = get_class_name ( ) | | p_theme_type = = data . theme_type_variation ) {
if ( has_theme_color_override ( p_name ) ) {
return true ;
}
2021-08-12 17:35:42 +00:00
}
2022-07-22 15:06:03 +00:00
2024-06-24 14:09:20 +00:00
Vector < StringName > theme_types ;
data . theme_owner - > get_theme_type_dependencies ( this , p_theme_type , theme_types ) ;
2022-09-02 14:03:23 +00:00
return data . theme_owner - > has_theme_item_in_types ( Theme : : DATA_TYPE_COLOR , p_name , theme_types ) ;
2021-08-12 17:35:42 +00:00
}
2022-07-22 15:06:03 +00:00
bool Control : : has_theme_constant ( const StringName & p_name , const StringName & p_theme_type ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2023-04-03 16:01:10 +00:00
if ( ! data . initialized ) {
2024-01-28 20:51:39 +00:00
WARN_PRINT_ONCE ( vformat ( " Attempting to access theme items too early in %s; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED " , get_description ( ) ) ) ;
2023-04-03 16:01:10 +00:00
}
2022-07-22 15:06:03 +00:00
if ( p_theme_type = = StringName ( ) | | p_theme_type = = get_class_name ( ) | | p_theme_type = = data . theme_type_variation ) {
if ( has_theme_constant_override ( p_name ) ) {
return true ;
}
2020-05-14 14:41:43 +00:00
}
2016-07-18 19:41:28 +00:00
2024-06-24 14:09:20 +00:00
Vector < StringName > theme_types ;
data . theme_owner - > get_theme_type_dependencies ( this , p_theme_type , theme_types ) ;
2022-09-02 14:03:23 +00:00
return data . theme_owner - > has_theme_item_in_types ( Theme : : DATA_TYPE_CONSTANT , p_name , theme_types ) ;
2022-07-22 15:06:03 +00:00
}
2016-07-18 19:41:28 +00:00
2022-07-22 15:06:03 +00:00
/// Local property overrides.
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
void Control : : add_theme_icon_override ( const StringName & p_name , const Ref < Texture2D > & p_icon ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
ERR_FAIL_COND ( ! p_icon . is_valid ( ) ) ;
2014-02-10 01:10:30 +00:00
2022-11-29 20:01:45 +00:00
if ( data . theme_icon_override . has ( p_name ) ) {
2023-07-03 19:29:37 +00:00
data . theme_icon_override [ p_name ] - > disconnect_changed ( callable_mp ( this , & Control : : _notify_theme_override_changed ) ) ;
2016-07-18 19:41:28 +00:00
}
2022-07-22 15:06:03 +00:00
2022-11-29 20:01:45 +00:00
data . theme_icon_override [ p_name ] = p_icon ;
2023-07-03 19:29:37 +00:00
data . theme_icon_override [ p_name ] - > connect_changed ( callable_mp ( this , & Control : : _notify_theme_override_changed ) , CONNECT_REFERENCE_COUNTED ) ;
2022-07-08 19:29:36 +00:00
_notify_theme_override_changed ( ) ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : add_theme_style_override ( const StringName & p_name , const Ref < StyleBox > & p_style ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
ERR_FAIL_COND ( ! p_style . is_valid ( ) ) ;
2022-11-29 20:01:45 +00:00
if ( data . theme_style_override . has ( p_name ) ) {
2023-07-03 19:29:37 +00:00
data . theme_style_override [ p_name ] - > disconnect_changed ( callable_mp ( this , & Control : : _notify_theme_override_changed ) ) ;
2022-07-22 15:06:03 +00:00
}
2022-11-29 20:01:45 +00:00
data . theme_style_override [ p_name ] = p_style ;
2023-07-03 19:29:37 +00:00
data . theme_style_override [ p_name ] - > connect_changed ( callable_mp ( this , & Control : : _notify_theme_override_changed ) , CONNECT_REFERENCE_COUNTED ) ;
2022-07-08 19:29:36 +00:00
_notify_theme_override_changed ( ) ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : add_theme_font_override ( const StringName & p_name , const Ref < Font > & p_font ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
ERR_FAIL_COND ( ! p_font . is_valid ( ) ) ;
2022-11-29 20:01:45 +00:00
if ( data . theme_font_override . has ( p_name ) ) {
2023-07-03 19:29:37 +00:00
data . theme_font_override [ p_name ] - > disconnect_changed ( callable_mp ( this , & Control : : _notify_theme_override_changed ) ) ;
2022-07-22 15:06:03 +00:00
}
2022-11-29 20:01:45 +00:00
data . theme_font_override [ p_name ] = p_font ;
2023-07-03 19:29:37 +00:00
data . theme_font_override [ p_name ] - > connect_changed ( callable_mp ( this , & Control : : _notify_theme_override_changed ) , CONNECT_REFERENCE_COUNTED ) ;
2022-07-08 19:29:36 +00:00
_notify_theme_override_changed ( ) ;
2021-03-30 17:16:33 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : add_theme_font_size_override ( const StringName & p_name , int p_font_size ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-11-29 20:01:45 +00:00
data . theme_font_size_override [ p_name ] = p_font_size ;
2022-07-08 19:29:36 +00:00
_notify_theme_override_changed ( ) ;
2021-03-30 17:16:33 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : add_theme_color_override ( const StringName & p_name , const Color & p_color ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-11-29 20:01:45 +00:00
data . theme_color_override [ p_name ] = p_color ;
2022-07-08 19:29:36 +00:00
_notify_theme_override_changed ( ) ;
2014-02-10 01:10:30 +00:00
}
2018-07-20 21:14:33 +00:00
2022-07-22 15:06:03 +00:00
void Control : : add_theme_constant_override ( const StringName & p_name , int p_constant ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-11-29 20:01:45 +00:00
data . theme_constant_override [ p_name ] = p_constant ;
2022-07-08 19:29:36 +00:00
_notify_theme_override_changed ( ) ;
2014-02-10 01:10:30 +00:00
}
2020-05-14 12:29:06 +00:00
2022-07-22 15:06:03 +00:00
void Control : : remove_theme_icon_override ( const StringName & p_name ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-11-29 20:01:45 +00:00
if ( data . theme_icon_override . has ( p_name ) ) {
2023-07-03 19:29:37 +00:00
data . theme_icon_override [ p_name ] - > disconnect_changed ( callable_mp ( this , & Control : : _notify_theme_override_changed ) ) ;
2018-07-20 21:14:33 +00:00
}
2022-07-22 15:06:03 +00:00
2022-11-29 20:01:45 +00:00
data . theme_icon_override . erase ( p_name ) ;
2022-07-08 19:29:36 +00:00
_notify_theme_override_changed ( ) ;
2018-07-20 21:14:33 +00:00
}
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
void Control : : remove_theme_style_override ( const StringName & p_name ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-11-29 20:01:45 +00:00
if ( data . theme_style_override . has ( p_name ) ) {
2023-07-03 19:29:37 +00:00
data . theme_style_override [ p_name ] - > disconnect_changed ( callable_mp ( this , & Control : : _notify_theme_override_changed ) ) ;
2022-07-22 15:06:03 +00:00
}
2019-10-05 17:17:07 +00:00
2022-11-29 20:01:45 +00:00
data . theme_style_override . erase ( p_name ) ;
2022-07-08 19:29:36 +00:00
_notify_theme_override_changed ( ) ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : remove_theme_font_override ( const StringName & p_name ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-11-29 20:01:45 +00:00
if ( data . theme_font_override . has ( p_name ) ) {
2023-07-03 19:29:37 +00:00
data . theme_font_override [ p_name ] - > disconnect_changed ( callable_mp ( this , & Control : : _notify_theme_override_changed ) ) ;
2022-07-22 15:06:03 +00:00
}
2022-11-29 20:01:45 +00:00
data . theme_font_override . erase ( p_name ) ;
2022-07-08 19:29:36 +00:00
_notify_theme_override_changed ( ) ;
2014-02-10 01:10:30 +00:00
}
2020-05-14 12:29:06 +00:00
2022-07-22 15:06:03 +00:00
void Control : : remove_theme_font_size_override ( const StringName & p_name ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-11-29 20:01:45 +00:00
data . theme_font_size_override . erase ( p_name ) ;
2022-07-08 19:29:36 +00:00
_notify_theme_override_changed ( ) ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : remove_theme_color_override ( const StringName & p_name ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-11-29 20:01:45 +00:00
data . theme_color_override . erase ( p_name ) ;
2022-07-08 19:29:36 +00:00
_notify_theme_override_changed ( ) ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : remove_theme_constant_override ( const StringName & p_name ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-11-29 20:01:45 +00:00
data . theme_constant_override . erase ( p_name ) ;
2022-07-08 19:29:36 +00:00
_notify_theme_override_changed ( ) ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
bool Control : : has_theme_icon_override ( const StringName & p_name ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-11-29 20:01:45 +00:00
const Ref < Texture2D > * tex = data . theme_icon_override . getptr ( p_name ) ;
2022-07-22 15:06:03 +00:00
return tex ! = nullptr ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
bool Control : : has_theme_stylebox_override ( const StringName & p_name ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-11-29 20:01:45 +00:00
const Ref < StyleBox > * style = data . theme_style_override . getptr ( p_name ) ;
2022-07-22 15:06:03 +00:00
return style ! = nullptr ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
bool Control : : has_theme_font_override ( const StringName & p_name ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-11-29 20:01:45 +00:00
const Ref < Font > * font = data . theme_font_override . getptr ( p_name ) ;
2022-07-22 15:06:03 +00:00
return font ! = nullptr ;
2017-11-16 09:45:52 +00:00
}
2022-07-22 15:06:03 +00:00
bool Control : : has_theme_font_size_override ( const StringName & p_name ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-11-29 20:01:45 +00:00
const int * font_size = data . theme_font_size_override . getptr ( p_name ) ;
2022-07-22 15:06:03 +00:00
return font_size ! = nullptr ;
2017-11-16 09:45:52 +00:00
}
2022-07-22 15:06:03 +00:00
bool Control : : has_theme_color_override ( const StringName & p_name ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-11-29 20:01:45 +00:00
const Color * color = data . theme_color_override . getptr ( p_name ) ;
2022-07-22 15:06:03 +00:00
return color ! = nullptr ;
2017-11-16 09:45:52 +00:00
}
2022-07-22 15:06:03 +00:00
bool Control : : has_theme_constant_override ( const StringName & p_name ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-11-29 20:01:45 +00:00
const int * constant = data . theme_constant_override . getptr ( p_name ) ;
2022-07-22 15:06:03 +00:00
return constant ! = nullptr ;
2017-11-16 09:45:52 +00:00
}
2022-07-22 15:06:03 +00:00
/// Default theme properties.
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
float Control : : get_theme_default_base_scale ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( 0 ) ;
2022-09-02 14:03:23 +00:00
return data . theme_owner - > get_theme_default_base_scale ( ) ;
2022-07-22 15:06:03 +00:00
}
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
Ref < Font > Control : : get_theme_default_font ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Ref < Font > ( ) ) ;
2022-09-02 14:03:23 +00:00
return data . theme_owner - > get_theme_default_font ( ) ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
int Control : : get_theme_default_font_size ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( 0 ) ;
2022-09-02 14:03:23 +00:00
return data . theme_owner - > get_theme_default_font_size ( ) ;
2014-02-10 01:10:30 +00:00
}
2020-05-14 12:29:06 +00:00
2022-07-22 15:06:03 +00:00
/// Bulk actions.
void Control : : begin_bulk_theme_override ( ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
data . bulk_theme_override = true ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : end_bulk_theme_override ( ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
ERR_FAIL_COND ( ! data . bulk_theme_override ) ;
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
data . bulk_theme_override = false ;
2022-07-08 19:29:36 +00:00
_notify_theme_override_changed ( ) ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
// Internationalization.
2023-01-18 07:33:35 +00:00
TypedArray < Vector3i > Control : : structured_text_parser ( TextServer : : StructuredTextParser p_parser_type , const Array & p_args , const String & p_text ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( TypedArray < Vector3i > ( ) ) ;
2022-07-22 15:06:03 +00:00
if ( p_parser_type = = TextServer : : STRUCTURED_TEXT_CUSTOM ) {
2023-01-18 07:33:35 +00:00
TypedArray < Vector3i > ret ;
2022-10-18 16:47:44 +00:00
GDVIRTUAL_CALL ( _structured_text_parser , p_args , p_text , ret ) ;
return ret ;
2022-07-22 15:06:03 +00:00
} else {
return TS - > parse_structured_text ( p_parser_type , p_args , p_text ) ;
}
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
void Control : : set_layout_direction ( Control : : LayoutDirection p_direction ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-03-16 07:50:48 +00:00
if ( data . layout_dir = = p_direction ) {
return ;
}
2022-07-22 15:06:03 +00:00
ERR_FAIL_INDEX ( ( int ) p_direction , 4 ) ;
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
data . layout_dir = p_direction ;
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
propagate_notification ( NOTIFICATION_LAYOUT_DIRECTION_CHANGED ) ;
}
2014-02-10 01:10:30 +00:00
2022-07-22 15:06:03 +00:00
Control : : LayoutDirection Control : : get_layout_direction ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( LAYOUT_DIRECTION_INHERITED ) ;
2022-07-22 15:06:03 +00:00
return data . layout_dir ;
}
2018-05-15 20:12:35 +00:00
2022-07-22 15:06:03 +00:00
bool Control : : is_layout_rtl ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-07-22 15:06:03 +00:00
if ( data . is_rtl_dirty ) {
const_cast < Control * > ( this ) - > data . is_rtl_dirty = false ;
if ( data . layout_dir = = LAYOUT_DIRECTION_INHERITED ) {
2023-11-17 06:54:07 +00:00
# ifdef TOOLS_ENABLED
if ( is_part_of_edited_scene ( ) & & GLOBAL_GET ( SNAME ( " internationalization/rendering/force_right_to_left_layout_direction " ) ) ) {
const_cast < Control * > ( this ) - > data . is_rtl = true ;
return data . is_rtl ;
}
if ( is_inside_tree ( ) ) {
Node * edited_scene_root = get_tree ( ) - > get_edited_scene_root ( ) ;
if ( edited_scene_root = = this ) {
int proj_root_layout_direction = GLOBAL_GET ( SNAME ( " internationalization/rendering/root_node_layout_direction " ) ) ;
if ( proj_root_layout_direction = = 1 ) {
const_cast < Control * > ( this ) - > data . is_rtl = false ;
} else if ( proj_root_layout_direction = = 2 ) {
const_cast < Control * > ( this ) - > data . is_rtl = true ;
} else if ( proj_root_layout_direction = = 3 ) {
String locale = OS : : get_singleton ( ) - > get_locale ( ) ;
const_cast < Control * > ( this ) - > data . is_rtl = TS - > is_locale_right_to_left ( locale ) ;
} else {
String locale = TranslationServer : : get_singleton ( ) - > get_tool_locale ( ) ;
const_cast < Control * > ( this ) - > data . is_rtl = TS - > is_locale_right_to_left ( locale ) ;
}
return data . is_rtl ;
}
}
# else
2023-02-21 22:08:05 +00:00
if ( GLOBAL_GET ( SNAME ( " internationalization/rendering/force_right_to_left_layout_direction " ) ) ) {
const_cast < Control * > ( this ) - > data . is_rtl = true ;
return data . is_rtl ;
}
2023-11-17 06:54:07 +00:00
# endif
2023-02-21 22:08:05 +00:00
Node * parent_node = get_parent ( ) ;
while ( parent_node ) {
Control * parent_control = Object : : cast_to < Control > ( parent_node ) ;
if ( parent_control ) {
const_cast < Control * > ( this ) - > data . is_rtl = parent_control - > is_layout_rtl ( ) ;
return data . is_rtl ;
2022-07-22 15:06:03 +00:00
}
2023-02-21 22:08:05 +00:00
Window * parent_window = Object : : cast_to < Window > ( parent_node ) ;
if ( parent_window ) {
const_cast < Control * > ( this ) - > data . is_rtl = parent_window - > is_layout_rtl ( ) ;
return data . is_rtl ;
}
parent_node = parent_node - > get_parent ( ) ;
}
2023-11-17 06:54:07 +00:00
if ( root_layout_direction = = 1 ) {
2023-02-21 22:08:05 +00:00
const_cast < Control * > ( this ) - > data . is_rtl = false ;
2023-11-17 06:54:07 +00:00
} else if ( root_layout_direction = = 2 ) {
2023-02-21 22:08:05 +00:00
const_cast < Control * > ( this ) - > data . is_rtl = true ;
2023-11-17 06:54:07 +00:00
} else if ( root_layout_direction = = 3 ) {
String locale = OS : : get_singleton ( ) - > get_locale ( ) ;
const_cast < Control * > ( this ) - > data . is_rtl = TS - > is_locale_right_to_left ( locale ) ;
2023-02-21 22:08:05 +00:00
} else {
String locale = TranslationServer : : get_singleton ( ) - > get_tool_locale ( ) ;
const_cast < Control * > ( this ) - > data . is_rtl = TS - > is_locale_right_to_left ( locale ) ;
2022-07-22 15:06:03 +00:00
}
} else if ( data . layout_dir = = LAYOUT_DIRECTION_LOCALE ) {
if ( GLOBAL_GET ( SNAME ( " internationalization/rendering/force_right_to_left_layout_direction " ) ) ) {
const_cast < Control * > ( this ) - > data . is_rtl = true ;
} else {
String locale = TranslationServer : : get_singleton ( ) - > get_tool_locale ( ) ;
const_cast < Control * > ( this ) - > data . is_rtl = TS - > is_locale_right_to_left ( locale ) ;
2020-03-06 17:00:16 +00:00
}
2022-07-22 15:06:03 +00:00
} else {
const_cast < Control * > ( this ) - > data . is_rtl = ( data . layout_dir = = LAYOUT_DIRECTION_RTL ) ;
2020-03-06 17:00:16 +00:00
}
2020-05-14 14:41:43 +00:00
}
2022-07-22 15:06:03 +00:00
return data . is_rtl ;
}
2018-05-15 20:12:35 +00:00
2022-11-17 12:54:45 +00:00
void Control : : set_localize_numeral_system ( bool p_enable ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-11-17 12:54:45 +00:00
if ( p_enable = = data . localize_numeral_system ) {
return ;
}
data . localize_numeral_system = p_enable ;
notification ( MainLoop : : NOTIFICATION_TRANSLATION_CHANGED ) ;
}
bool Control : : is_localizing_numeral_system ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-11-17 12:54:45 +00:00
return data . localize_numeral_system ;
}
2024-01-23 21:29:45 +00:00
# ifndef DISABLE_DEPRECATED
2022-07-22 15:06:03 +00:00
void Control : : set_auto_translate ( bool p_enable ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2024-01-23 21:29:45 +00:00
set_auto_translate_mode ( p_enable ? AUTO_TRANSLATE_MODE_ALWAYS : AUTO_TRANSLATE_MODE_DISABLED ) ;
2014-02-10 01:10:30 +00:00
}
2022-07-22 15:06:03 +00:00
bool Control : : is_auto_translating ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2024-01-23 21:29:45 +00:00
return can_auto_translate ( ) ;
2014-02-10 01:10:30 +00:00
}
2024-01-23 21:29:45 +00:00
# endif
2014-02-10 01:10:30 +00:00
2024-09-24 11:11:49 +00:00
void Control : : set_tooltip_auto_translate_mode ( AutoTranslateMode p_mode ) {
ERR_MAIN_THREAD_GUARD ;
data . tooltip_auto_translate_mode = p_mode ;
}
Node : : AutoTranslateMode Control : : get_tooltip_auto_translate_mode ( ) const {
ERR_READ_THREAD_GUARD_V ( AUTO_TRANSLATE_MODE_INHERIT ) ;
return data . tooltip_auto_translate_mode ;
}
2022-07-22 15:06:03 +00:00
// Extra properties.
2022-05-16 13:10:30 +00:00
2022-08-25 10:42:17 +00:00
void Control : : set_tooltip_text ( const String & p_hint ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-08-25 10:42:17 +00:00
data . tooltip = p_hint ;
2022-07-22 15:06:03 +00:00
update_configuration_warnings ( ) ;
2022-05-16 13:10:30 +00:00
}
2022-08-25 10:42:17 +00:00
String Control : : get_tooltip_text ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( String ( ) ) ;
2022-07-22 15:06:03 +00:00
return data . tooltip ;
2015-02-14 22:22:06 +00:00
}
2022-07-22 15:06:03 +00:00
String Control : : get_tooltip ( const Point2 & p_pos ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( String ( ) ) ;
2023-02-23 13:36:10 +00:00
String ret ;
if ( GDVIRTUAL_CALL ( _get_tooltip , p_pos , ret ) ) {
return ret ;
}
2022-07-22 15:06:03 +00:00
return data . tooltip ;
2015-10-17 13:29:54 +00:00
}
2022-07-22 15:06:03 +00:00
Control * Control : : make_custom_tooltip ( const String & p_text ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( nullptr ) ;
2022-07-22 15:06:03 +00:00
Object * ret = nullptr ;
2022-10-18 16:47:44 +00:00
GDVIRTUAL_CALL ( _make_custom_tooltip , p_text , ret ) ;
return Object : : cast_to < Control > ( ret ) ;
2020-09-03 11:22:16 +00:00
}
2022-07-22 15:06:03 +00:00
// Base object overrides.
2015-12-12 16:54:26 +00:00
2022-07-22 15:06:03 +00:00
void Control : : _notification ( int p_notification ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-07-22 15:06:03 +00:00
switch ( p_notification ) {
2024-05-03 02:41:17 +00:00
# ifdef TOOLS_ENABLED
case NOTIFICATION_EDITOR_PRE_SAVE : {
saving = true ;
} break ;
case NOTIFICATION_EDITOR_POST_SAVE : {
saving = false ;
} break ;
# endif
2022-08-31 12:02:40 +00:00
case NOTIFICATION_POSTINITIALIZE : {
2023-04-03 16:01:10 +00:00
data . initialized = true ;
2022-08-31 12:02:40 +00:00
_invalidate_theme_cache ( ) ;
_update_theme_item_cache ( ) ;
} break ;
2022-09-02 14:45:09 +00:00
case NOTIFICATION_PARENTED : {
2023-01-03 16:21:26 +00:00
Node * parent_node = get_parent ( ) ;
data . parent_control = Object : : cast_to < Control > ( parent_node ) ;
data . parent_window = Object : : cast_to < Window > ( parent_node ) ;
2022-09-02 14:45:09 +00:00
data . theme_owner - > assign_theme_on_parented ( this ) ;
2023-01-10 20:07:57 +00:00
_update_layout_mode ( ) ;
2022-09-02 14:45:09 +00:00
} break ;
case NOTIFICATION_UNPARENTED : {
2023-01-03 16:21:26 +00:00
data . parent_control = nullptr ;
data . parent_window = nullptr ;
2022-09-02 14:45:09 +00:00
data . theme_owner - > clear_theme_on_unparented ( this ) ;
} break ;
2022-08-12 11:36:06 +00:00
case NOTIFICATION_ENTER_TREE : {
2023-09-06 14:11:05 +00:00
// Emits NOTIFICATION_THEME_CHANGED internally.
set_theme_context ( ThemeDB : : get_singleton ( ) - > get_nearest_theme_context ( this ) ) ;
2022-08-12 11:36:06 +00:00
} break ;
2022-07-22 15:06:03 +00:00
case NOTIFICATION_POST_ENTER_TREE : {
data . is_rtl_dirty = true ;
2023-06-06 20:05:53 +00:00
update_minimum_size ( ) ;
2022-07-22 15:06:03 +00:00
_size_changed ( ) ;
} break ;
2015-12-12 16:54:26 +00:00
2022-07-22 15:06:03 +00:00
case NOTIFICATION_EXIT_TREE : {
2023-09-06 14:11:05 +00:00
set_theme_context ( nullptr , false ) ;
2024-01-23 21:29:45 +00:00
2022-07-22 15:06:03 +00:00
release_focus ( ) ;
get_viewport ( ) - > _gui_remove_control ( this ) ;
} break ;
2016-01-19 23:27:27 +00:00
2022-07-22 15:06:03 +00:00
case NOTIFICATION_READY : {
# ifdef DEBUG_ENABLED
2024-05-13 14:56:03 +00:00
connect ( SceneStringName ( ready ) , callable_mp ( this , & Control : : _clear_size_warning ) , CONNECT_DEFERRED | CONNECT_ONE_SHOT ) ;
2022-07-22 15:06:03 +00:00
# endif
} break ;
2016-01-19 23:27:27 +00:00
2022-07-22 15:06:03 +00:00
case NOTIFICATION_ENTER_CANVAS : {
data . is_rtl_dirty = true ;
CanvasItem * node = this ;
bool has_parent_control = false ;
2016-01-19 23:27:27 +00:00
2022-07-22 15:06:03 +00:00
while ( ! node - > is_set_as_top_level ( ) ) {
CanvasItem * parent = Object : : cast_to < CanvasItem > ( node - > get_parent ( ) ) ;
if ( ! parent ) {
break ;
}
2015-12-12 16:54:26 +00:00
2022-07-22 15:06:03 +00:00
Control * parent_control = Object : : cast_to < Control > ( parent ) ;
if ( parent_control ) {
has_parent_control = true ;
break ;
}
2016-01-24 13:57:42 +00:00
2022-07-22 15:06:03 +00:00
node = parent ;
}
2016-08-31 02:44:14 +00:00
2022-07-22 15:06:03 +00:00
if ( has_parent_control ) {
// Do nothing, has a parent control.
} else {
// Is a regular root control or top_level.
Viewport * viewport = get_viewport ( ) ;
2023-06-06 12:59:54 +00:00
ERR_FAIL_NULL ( viewport ) ;
2022-07-22 15:06:03 +00:00
data . RI = viewport - > _gui_add_root_control ( this ) ;
2023-04-05 16:53:32 +00:00
get_parent ( ) - > connect ( SNAME ( " child_order_changed " ) , callable_mp ( get_viewport ( ) , & Viewport : : gui_set_root_order_dirty ) , CONNECT_REFERENCE_COUNTED ) ;
2022-07-22 15:06:03 +00:00
}
2016-08-31 02:44:14 +00:00
2022-07-22 15:06:03 +00:00
data . parent_canvas_item = get_parent_item ( ) ;
2016-08-31 02:44:14 +00:00
2022-07-22 15:06:03 +00:00
if ( data . parent_canvas_item ) {
2024-05-13 14:56:03 +00:00
data . parent_canvas_item - > connect ( SceneStringName ( item_rect_changed ) , callable_mp ( this , & Control : : _size_changed ) ) ;
2022-07-22 15:06:03 +00:00
} else {
// Connect viewport.
Viewport * viewport = get_viewport ( ) ;
2023-06-06 12:59:54 +00:00
ERR_FAIL_NULL ( viewport ) ;
2022-07-22 15:06:03 +00:00
viewport - > connect ( " size_changed " , callable_mp ( this , & Control : : _size_changed ) ) ;
}
} break ;
2016-09-11 14:48:31 +00:00
2022-07-22 15:06:03 +00:00
case NOTIFICATION_EXIT_CANVAS : {
if ( data . parent_canvas_item ) {
2024-05-13 14:56:03 +00:00
data . parent_canvas_item - > disconnect ( SceneStringName ( item_rect_changed ) , callable_mp ( this , & Control : : _size_changed ) ) ;
2022-07-22 15:06:03 +00:00
data . parent_canvas_item = nullptr ;
2022-10-05 21:26:41 +00:00
} else {
// Disconnect viewport.
2022-07-22 15:06:03 +00:00
Viewport * viewport = get_viewport ( ) ;
2023-06-06 12:59:54 +00:00
ERR_FAIL_NULL ( viewport ) ;
2022-07-22 15:06:03 +00:00
viewport - > disconnect ( " size_changed " , callable_mp ( this , & Control : : _size_changed ) ) ;
}
2016-09-11 14:48:31 +00:00
2022-07-22 15:06:03 +00:00
if ( data . RI ) {
get_viewport ( ) - > _gui_remove_root_control ( data . RI ) ;
data . RI = nullptr ;
2023-04-05 16:53:32 +00:00
get_parent ( ) - > disconnect ( SNAME ( " child_order_changed " ) , callable_mp ( get_viewport ( ) , & Viewport : : gui_set_root_order_dirty ) ) ;
2022-07-22 15:06:03 +00:00
}
2019-06-28 16:38:57 +00:00
2022-07-22 15:06:03 +00:00
data . parent_canvas_item = nullptr ;
data . is_rtl_dirty = true ;
} break ;
2019-06-28 16:38:57 +00:00
2023-04-05 16:53:32 +00:00
case NOTIFICATION_CHILD_ORDER_CHANGED : {
2023-01-03 16:21:26 +00:00
// Some parents need to know the order of the children to draw (like TabContainer),
// so we update them just in case.
2022-08-13 21:21:24 +00:00
queue_redraw ( ) ;
2022-07-22 15:06:03 +00:00
} break ;
2019-06-28 16:38:57 +00:00
2022-07-22 15:06:03 +00:00
case NOTIFICATION_RESIZED : {
2023-09-04 15:01:33 +00:00
emit_signal ( SceneStringName ( resized ) ) ;
2022-07-22 15:06:03 +00:00
} break ;
2017-01-09 18:50:08 +00:00
2022-07-22 15:06:03 +00:00
case NOTIFICATION_DRAW : {
_update_canvas_item_transform ( ) ;
RenderingServer : : get_singleton ( ) - > canvas_item_set_custom_rect ( get_canvas_item ( ) , ! data . disable_visibility_clip , Rect2 ( Point2 ( ) , get_size ( ) ) ) ;
RenderingServer : : get_singleton ( ) - > canvas_item_set_clip ( get_canvas_item ( ) , data . clip_contents ) ;
} break ;
2016-09-11 14:48:31 +00:00
2022-07-22 15:06:03 +00:00
case NOTIFICATION_MOUSE_ENTER : {
2023-09-04 15:01:33 +00:00
emit_signal ( SceneStringName ( mouse_entered ) ) ;
2022-07-22 15:06:03 +00:00
} break ;
2019-10-05 17:17:07 +00:00
2022-07-22 15:06:03 +00:00
case NOTIFICATION_MOUSE_EXIT : {
2023-09-04 15:01:33 +00:00
emit_signal ( SceneStringName ( mouse_exited ) ) ;
2022-07-22 15:06:03 +00:00
} break ;
2017-07-06 16:26:39 +00:00
2022-07-22 15:06:03 +00:00
case NOTIFICATION_FOCUS_ENTER : {
2023-09-04 15:01:33 +00:00
emit_signal ( SceneStringName ( focus_entered ) ) ;
2022-08-13 21:21:24 +00:00
queue_redraw ( ) ;
2022-07-22 15:06:03 +00:00
} break ;
2017-07-06 16:26:39 +00:00
2022-07-22 15:06:03 +00:00
case NOTIFICATION_FOCUS_EXIT : {
2023-09-04 15:01:33 +00:00
emit_signal ( SceneStringName ( focus_exited ) ) ;
2022-08-13 21:21:24 +00:00
queue_redraw ( ) ;
2022-07-22 15:06:03 +00:00
} break ;
2019-10-05 17:17:07 +00:00
2022-07-22 15:06:03 +00:00
case NOTIFICATION_THEME_CHANGED : {
2023-09-04 15:01:33 +00:00
emit_signal ( SceneStringName ( theme_changed ) ) ;
2023-06-06 20:05:53 +00:00
2022-08-12 11:36:06 +00:00
_invalidate_theme_cache ( ) ;
2022-08-31 12:02:40 +00:00
_update_theme_item_cache ( ) ;
2022-08-13 21:21:24 +00:00
queue_redraw ( ) ;
2023-06-06 20:05:53 +00:00
update_minimum_size ( ) ;
_size_changed ( ) ;
2022-07-22 15:06:03 +00:00
} break ;
2020-05-14 12:29:06 +00:00
2022-07-22 15:06:03 +00:00
case NOTIFICATION_VISIBILITY_CHANGED : {
if ( ! is_visible_in_tree ( ) ) {
if ( get_viewport ( ) ! = nullptr ) {
get_viewport ( ) - > _gui_hide_control ( this ) ;
}
} else {
2023-06-06 20:05:53 +00:00
update_minimum_size ( ) ;
2023-06-06 18:55:03 +00:00
_size_changed ( ) ;
2022-07-22 15:06:03 +00:00
}
} break ;
case NOTIFICATION_TRANSLATION_CHANGED :
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED : {
if ( is_inside_tree ( ) ) {
data . is_rtl_dirty = true ;
2023-06-06 20:05:53 +00:00
2022-08-12 11:36:06 +00:00
_invalidate_theme_cache ( ) ;
2022-08-31 12:02:40 +00:00
_update_theme_item_cache ( ) ;
2023-06-06 20:05:53 +00:00
queue_redraw ( ) ;
update_minimum_size ( ) ;
2022-07-22 15:06:03 +00:00
_size_changed ( ) ;
}
} break ;
}
2017-07-06 16:26:39 +00:00
}
2014-02-10 01:10:30 +00:00
void Control : : _bind_methods ( ) {
2017-02-13 11:47:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " accept_event " ) , & Control : : accept_event ) ;
ClassDB : : bind_method ( D_METHOD ( " get_minimum_size " ) , & Control : : get_minimum_size ) ;
ClassDB : : bind_method ( D_METHOD ( " get_combined_minimum_size " ) , & Control : : get_combined_minimum_size ) ;
2021-11-08 20:53:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " _set_layout_mode " , " mode " ) , & Control : : _set_layout_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " _get_layout_mode " ) , & Control : : _get_layout_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " _set_anchors_layout_preset " , " preset " ) , & Control : : _set_anchors_layout_preset ) ;
ClassDB : : bind_method ( D_METHOD ( " _get_anchors_layout_preset " ) , & Control : : _get_anchors_layout_preset ) ;
2020-12-22 16:24:29 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_anchors_preset " , " preset " , " keep_offsets " ) , & Control : : set_anchors_preset , DEFVAL ( false ) ) ;
ClassDB : : bind_method ( D_METHOD ( " set_offsets_preset " , " preset " , " resize_mode " , " margin " ) , & Control : : set_offsets_preset , DEFVAL ( PRESET_MODE_MINSIZE ) , DEFVAL ( 0 ) ) ;
ClassDB : : bind_method ( D_METHOD ( " set_anchors_and_offsets_preset " , " preset " , " resize_mode " , " margin " ) , & Control : : set_anchors_and_offsets_preset , DEFVAL ( PRESET_MODE_MINSIZE ) , DEFVAL ( 0 ) ) ;
2021-11-08 20:53:41 +00:00
2020-12-22 16:24:29 +00:00
ClassDB : : bind_method ( D_METHOD ( " _set_anchor " , " side " , " anchor " ) , & Control : : _set_anchor ) ;
ClassDB : : bind_method ( D_METHOD ( " set_anchor " , " side " , " anchor " , " keep_offset " , " push_opposite_anchor " ) , & Control : : set_anchor , DEFVAL ( false ) , DEFVAL ( true ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_anchor " , " side " ) , & Control : : get_anchor ) ;
ClassDB : : bind_method ( D_METHOD ( " set_offset " , " side " , " offset " ) , & Control : : set_offset ) ;
2021-11-08 20:53:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_offset " , " offset " ) , & Control : : get_offset ) ;
2020-12-22 16:24:29 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_anchor_and_offset " , " side " , " anchor " , " offset " , " push_opposite_anchor " ) , & Control : : set_anchor_and_offset , DEFVAL ( false ) ) ;
2021-11-08 20:53:41 +00:00
2017-09-10 13:37:49 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_begin " , " position " ) , & Control : : set_begin ) ;
ClassDB : : bind_method ( D_METHOD ( " set_end " , " position " ) , & Control : : set_end ) ;
2020-12-22 16:24:29 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_position " , " position " , " keep_offsets " ) , & Control : : set_position , DEFVAL ( false ) ) ;
ClassDB : : bind_method ( D_METHOD ( " _set_position " , " position " ) , & Control : : _set_position ) ;
ClassDB : : bind_method ( D_METHOD ( " set_size " , " size " , " keep_offsets " ) , & Control : : set_size , DEFVAL ( false ) ) ;
2021-11-20 08:04:57 +00:00
ClassDB : : bind_method ( D_METHOD ( " reset_size " ) , & Control : : reset_size ) ;
2019-03-31 16:53:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " _set_size " , " size " ) , & Control : : _set_size ) ;
2017-02-13 11:47:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_custom_minimum_size " , " size " ) , & Control : : set_custom_minimum_size ) ;
2020-12-22 16:24:29 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_global_position " , " position " , " keep_offsets " ) , & Control : : set_global_position , DEFVAL ( false ) ) ;
2019-03-31 16:53:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " _set_global_position " , " position " ) , & Control : : _set_global_position ) ;
2017-02-13 11:47:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_rotation " , " radians " ) , & Control : : set_rotation ) ;
2022-12-18 15:58:19 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_rotation_degrees " , " degrees " ) , & Control : : set_rotation_degrees ) ;
2017-02-13 11:47:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_scale " , " scale " ) , & Control : : set_scale ) ;
2017-07-06 20:42:44 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_pivot_offset " , " pivot_offset " ) , & Control : : set_pivot_offset ) ;
2017-02-13 11:47:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_begin " ) , & Control : : get_begin ) ;
ClassDB : : bind_method ( D_METHOD ( " get_end " ) , & Control : : get_end ) ;
2017-03-29 15:29:38 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_position " ) , & Control : : get_position ) ;
2017-02-13 11:47:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_size " ) , & Control : : get_size ) ;
ClassDB : : bind_method ( D_METHOD ( " get_rotation " ) , & Control : : get_rotation ) ;
2022-12-18 15:58:19 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_rotation_degrees " ) , & Control : : get_rotation_degrees ) ;
2017-02-13 11:47:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_scale " ) , & Control : : get_scale ) ;
2017-07-06 20:42:44 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_pivot_offset " ) , & Control : : get_pivot_offset ) ;
2017-02-13 11:47:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_custom_minimum_size " ) , & Control : : get_custom_minimum_size ) ;
2019-03-01 13:16:19 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_parent_area_size " ) , & Control : : get_parent_area_size ) ;
2017-03-29 15:29:38 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_global_position " ) , & Control : : get_global_position ) ;
2022-03-13 15:02:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_screen_position " ) , & Control : : get_screen_position ) ;
2017-02-13 11:47:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_rect " ) , & Control : : get_rect ) ;
ClassDB : : bind_method ( D_METHOD ( " get_global_rect " ) , & Control : : get_global_rect ) ;
ClassDB : : bind_method ( D_METHOD ( " set_focus_mode " , " mode " ) , & Control : : set_focus_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " get_focus_mode " ) , & Control : : get_focus_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " has_focus " ) , & Control : : has_focus ) ;
ClassDB : : bind_method ( D_METHOD ( " grab_focus " ) , & Control : : grab_focus ) ;
ClassDB : : bind_method ( D_METHOD ( " release_focus " ) , & Control : : release_focus ) ;
2021-01-23 22:34:44 +00:00
ClassDB : : bind_method ( D_METHOD ( " find_prev_valid_focus " ) , & Control : : find_prev_valid_focus ) ;
ClassDB : : bind_method ( D_METHOD ( " find_next_valid_focus " ) , & Control : : find_next_valid_focus ) ;
2023-08-16 12:02:22 +00:00
ClassDB : : bind_method ( D_METHOD ( " find_valid_focus_neighbor " , " side " ) , & Control : : find_valid_focus_neighbor ) ;
2017-03-05 15:44:50 +00:00
2017-02-13 11:47:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_h_size_flags " , " flags " ) , & Control : : set_h_size_flags ) ;
ClassDB : : bind_method ( D_METHOD ( " get_h_size_flags " ) , & Control : : get_h_size_flags ) ;
2017-03-05 15:44:50 +00:00
2017-02-13 11:47:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_stretch_ratio " , " ratio " ) , & Control : : set_stretch_ratio ) ;
ClassDB : : bind_method ( D_METHOD ( " get_stretch_ratio " ) , & Control : : get_stretch_ratio ) ;
2017-03-05 15:44:50 +00:00
2017-02-13 11:47:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_v_size_flags " , " flags " ) , & Control : : set_v_size_flags ) ;
ClassDB : : bind_method ( D_METHOD ( " get_v_size_flags " ) , & Control : : get_v_size_flags ) ;
2017-03-05 15:44:50 +00:00
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_theme " , " theme " ) , & Control : : set_theme ) ;
ClassDB : : bind_method ( D_METHOD ( " get_theme " ) , & Control : : get_theme ) ;
2017-03-05 15:44:50 +00:00
2021-07-04 20:42:23 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_theme_type_variation " , " theme_type " ) , & Control : : set_theme_type_variation ) ;
ClassDB : : bind_method ( D_METHOD ( " get_theme_type_variation " ) , & Control : : get_theme_type_variation ) ;
2021-03-30 17:16:33 +00:00
2021-08-12 17:35:42 +00:00
ClassDB : : bind_method ( D_METHOD ( " begin_bulk_theme_override " ) , & Control : : begin_bulk_theme_override ) ;
ClassDB : : bind_method ( D_METHOD ( " end_bulk_theme_override " ) , & Control : : end_bulk_theme_override ) ;
2020-03-12 12:37:40 +00:00
ClassDB : : bind_method ( D_METHOD ( " add_theme_icon_override " , " name " , " texture " ) , & Control : : add_theme_icon_override ) ;
ClassDB : : bind_method ( D_METHOD ( " add_theme_stylebox_override " , " name " , " stylebox " ) , & Control : : add_theme_style_override ) ;
ClassDB : : bind_method ( D_METHOD ( " add_theme_font_override " , " name " , " font " ) , & Control : : add_theme_font_override ) ;
2020-09-03 11:22:16 +00:00
ClassDB : : bind_method ( D_METHOD ( " add_theme_font_size_override " , " name " , " font_size " ) , & Control : : add_theme_font_size_override ) ;
2020-03-12 12:37:40 +00:00
ClassDB : : bind_method ( D_METHOD ( " add_theme_color_override " , " name " , " color " ) , & Control : : add_theme_color_override ) ;
ClassDB : : bind_method ( D_METHOD ( " add_theme_constant_override " , " name " , " constant " ) , & Control : : add_theme_constant_override ) ;
2021-03-22 01:43:01 +00:00
ClassDB : : bind_method ( D_METHOD ( " remove_theme_icon_override " , " name " ) , & Control : : remove_theme_icon_override ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_theme_stylebox_override " , " name " ) , & Control : : remove_theme_style_override ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_theme_font_override " , " name " ) , & Control : : remove_theme_font_override ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_theme_font_size_override " , " name " ) , & Control : : remove_theme_font_size_override ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_theme_color_override " , " name " ) , & Control : : remove_theme_color_override ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_theme_constant_override " , " name " ) , & Control : : remove_theme_constant_override ) ;
2024-01-30 20:03:28 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_theme_icon " , " name " , " theme_type " ) , & Control : : get_theme_icon , DEFVAL ( StringName ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_theme_stylebox " , " name " , " theme_type " ) , & Control : : get_theme_stylebox , DEFVAL ( StringName ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_theme_font " , " name " , " theme_type " ) , & Control : : get_theme_font , DEFVAL ( StringName ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_theme_font_size " , " name " , " theme_type " ) , & Control : : get_theme_font_size , DEFVAL ( StringName ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_theme_color " , " name " , " theme_type " ) , & Control : : get_theme_color , DEFVAL ( StringName ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_theme_constant " , " name " , " theme_type " ) , & Control : : get_theme_constant , DEFVAL ( StringName ( ) ) ) ;
2020-03-12 12:37:40 +00:00
ClassDB : : bind_method ( D_METHOD ( " has_theme_icon_override " , " name " ) , & Control : : has_theme_icon_override ) ;
ClassDB : : bind_method ( D_METHOD ( " has_theme_stylebox_override " , " name " ) , & Control : : has_theme_stylebox_override ) ;
ClassDB : : bind_method ( D_METHOD ( " has_theme_font_override " , " name " ) , & Control : : has_theme_font_override ) ;
2020-09-03 11:22:16 +00:00
ClassDB : : bind_method ( D_METHOD ( " has_theme_font_size_override " , " name " ) , & Control : : has_theme_font_size_override ) ;
2020-03-12 12:37:40 +00:00
ClassDB : : bind_method ( D_METHOD ( " has_theme_color_override " , " name " ) , & Control : : has_theme_color_override ) ;
ClassDB : : bind_method ( D_METHOD ( " has_theme_constant_override " , " name " ) , & Control : : has_theme_constant_override ) ;
2024-01-30 20:03:28 +00:00
ClassDB : : bind_method ( D_METHOD ( " has_theme_icon " , " name " , " theme_type " ) , & Control : : has_theme_icon , DEFVAL ( StringName ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " has_theme_stylebox " , " name " , " theme_type " ) , & Control : : has_theme_stylebox , DEFVAL ( StringName ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " has_theme_font " , " name " , " theme_type " ) , & Control : : has_theme_font , DEFVAL ( StringName ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " has_theme_font_size " , " name " , " theme_type " ) , & Control : : has_theme_font_size , DEFVAL ( StringName ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " has_theme_color " , " name " , " theme_type " ) , & Control : : has_theme_color , DEFVAL ( StringName ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " has_theme_constant " , " name " , " theme_type " ) , & Control : : has_theme_constant , DEFVAL ( StringName ( ) ) ) ;
2014-02-10 01:10:30 +00:00
2021-10-02 20:06:14 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_theme_default_base_scale " ) , & Control : : get_theme_default_base_scale ) ;
ClassDB : : bind_method ( D_METHOD ( " get_theme_default_font " ) , & Control : : get_theme_default_font ) ;
ClassDB : : bind_method ( D_METHOD ( " get_theme_default_font_size " ) , & Control : : get_theme_default_font_size ) ;
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_parent_control " ) , & Control : : get_parent_control ) ;
2014-02-10 01:10:30 +00:00
2017-07-06 16:26:39 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_h_grow_direction " , " direction " ) , & Control : : set_h_grow_direction ) ;
ClassDB : : bind_method ( D_METHOD ( " get_h_grow_direction " ) , & Control : : get_h_grow_direction ) ;
ClassDB : : bind_method ( D_METHOD ( " set_v_grow_direction " , " direction " ) , & Control : : set_v_grow_direction ) ;
ClassDB : : bind_method ( D_METHOD ( " get_v_grow_direction " ) , & Control : : get_v_grow_direction ) ;
2024-09-24 11:11:49 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_tooltip_auto_translate_mode " , " mode " ) , & Control : : set_tooltip_auto_translate_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " get_tooltip_auto_translate_mode " ) , & Control : : get_tooltip_auto_translate_mode ) ;
2022-08-25 10:42:17 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_tooltip_text " , " hint " ) , & Control : : set_tooltip_text ) ;
ClassDB : : bind_method ( D_METHOD ( " get_tooltip_text " ) , & Control : : get_tooltip_text ) ;
2017-09-10 13:37:49 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_tooltip " , " at_position " ) , & Control : : get_tooltip , DEFVAL ( Point2 ( ) ) ) ;
2014-02-10 01:10:30 +00:00
2017-02-13 11:47:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_default_cursor_shape " , " shape " ) , & Control : : set_default_cursor_shape ) ;
ClassDB : : bind_method ( D_METHOD ( " get_default_cursor_shape " ) , & Control : : get_default_cursor_shape ) ;
2017-09-10 13:37:49 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_cursor_shape " , " position " ) , & Control : : get_cursor_shape , DEFVAL ( Point2 ( ) ) ) ;
2014-02-10 01:10:30 +00:00
2020-12-22 16:24:29 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_focus_neighbor " , " side " , " neighbor " ) , & Control : : set_focus_neighbor ) ;
ClassDB : : bind_method ( D_METHOD ( " get_focus_neighbor " , " side " ) , & Control : : get_focus_neighbor ) ;
2014-02-10 01:10:30 +00:00
2017-11-16 09:45:52 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_focus_next " , " next " ) , & Control : : set_focus_next ) ;
ClassDB : : bind_method ( D_METHOD ( " get_focus_next " ) , & Control : : get_focus_next ) ;
ClassDB : : bind_method ( D_METHOD ( " set_focus_previous " , " previous " ) , & Control : : set_focus_previous ) ;
ClassDB : : bind_method ( D_METHOD ( " get_focus_previous " ) , & Control : : get_focus_previous ) ;
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " force_drag " , " data " , " preview " ) , & Control : : force_drag ) ;
2014-02-10 01:10:30 +00:00
2017-02-13 11:47:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_mouse_filter " , " filter " ) , & Control : : set_mouse_filter ) ;
ClassDB : : bind_method ( D_METHOD ( " get_mouse_filter " ) , & Control : : get_mouse_filter ) ;
2014-02-10 01:10:30 +00:00
2022-05-16 13:10:30 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_force_pass_scroll_events " , " force_pass_scroll_events " ) , & Control : : set_force_pass_scroll_events ) ;
ClassDB : : bind_method ( D_METHOD ( " is_force_pass_scroll_events " ) , & Control : : is_force_pass_scroll_events ) ;
2017-02-13 11:47:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_clip_contents " , " enable " ) , & Control : : set_clip_contents ) ;
ClassDB : : bind_method ( D_METHOD ( " is_clipping_contents " ) , & Control : : is_clipping_contents ) ;
2017-01-09 18:50:08 +00:00
2017-02-13 11:47:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " grab_click_focus " ) , & Control : : grab_click_focus ) ;
2014-02-10 01:10:30 +00:00
2023-01-09 18:24:36 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_drag_forwarding " , " drag_func " , " can_drop_func " , " drop_func " ) , & Control : : set_drag_forwarding ) ;
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_drag_preview " , " control " ) , & Control : : set_drag_preview ) ;
2021-10-28 07:07:18 +00:00
ClassDB : : bind_method ( D_METHOD ( " is_drag_successful " ) , & Control : : is_drag_successful ) ;
2014-02-10 01:10:30 +00:00
2022-03-27 09:17:36 +00:00
ClassDB : : bind_method ( D_METHOD ( " warp_mouse " , " position " ) , & Control : : warp_mouse ) ;
2015-02-14 22:22:06 +00:00
2022-09-24 14:32:53 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_shortcut_context " , " node " ) , & Control : : set_shortcut_context ) ;
ClassDB : : bind_method ( D_METHOD ( " get_shortcut_context " ) , & Control : : get_shortcut_context ) ;
2021-12-06 13:02:34 +00:00
ClassDB : : bind_method ( D_METHOD ( " update_minimum_size " ) , & Control : : update_minimum_size ) ;
2015-02-14 22:22:06 +00:00
2020-09-03 11:22:16 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_layout_direction " , " direction " ) , & Control : : set_layout_direction ) ;
ClassDB : : bind_method ( D_METHOD ( " get_layout_direction " ) , & Control : : get_layout_direction ) ;
ClassDB : : bind_method ( D_METHOD ( " is_layout_rtl " ) , & Control : : is_layout_rtl ) ;
2024-01-23 21:29:45 +00:00
# ifndef DISABLE_DEPRECATED
2021-05-27 17:31:33 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_auto_translate " , " enable " ) , & Control : : set_auto_translate ) ;
ClassDB : : bind_method ( D_METHOD ( " is_auto_translating " ) , & Control : : is_auto_translating ) ;
2024-01-23 21:29:45 +00:00
# endif
2021-05-27 17:31:33 +00:00
2022-11-17 12:54:45 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_localize_numeral_system " , " enable " ) , & Control : : set_localize_numeral_system ) ;
ClassDB : : bind_method ( D_METHOD ( " is_localizing_numeral_system " ) , & Control : : is_localizing_numeral_system ) ;
2021-11-08 20:53:41 +00:00
ADD_GROUP ( " Layout " , " " ) ;
2022-01-23 17:14:31 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " clip_contents " ) , " set_clip_contents " , " is_clipping_contents " ) ;
2022-09-22 23:53:24 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR2 , " custom_minimum_size " , PROPERTY_HINT_NONE , " suffix:px " ) , " set_custom_minimum_size " , " get_custom_minimum_size " ) ;
2023-02-21 22:08:05 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " layout_direction " , PROPERTY_HINT_ENUM , " Inherited,Based on Locale,Left-to-Right,Right-to-Left " ) , " set_layout_direction " , " get_layout_direction " ) ;
2022-08-19 15:36:15 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " layout_mode " , PROPERTY_HINT_ENUM , " Position,Anchors,Container,Uncontrolled " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL ) , " _set_layout_mode " , " _get_layout_mode " ) ;
2021-11-08 20:53:41 +00:00
ADD_PROPERTY_DEFAULT ( " layout_mode " , LayoutMode : : LAYOUT_MODE_POSITION ) ;
2022-07-20 10:15:23 +00:00
const String anchors_presets_options = " Custom:-1,PresetFullRect:15, "
2021-11-08 20:53:41 +00:00
" PresetTopLeft:0,PresetTopRight:1,PresetBottomRight:3,PresetBottomLeft:2, "
" PresetCenterLeft:4,PresetCenterTop:5,PresetCenterRight:6,PresetCenterBottom:7,PresetCenter:8, "
" PresetLeftWide:9,PresetTopWide:10,PresetRightWide:11,PresetBottomWide:12,PresetVCenterWide:13,PresetHCenterWide:14 " ;
2022-08-19 15:36:15 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " anchors_preset " , PROPERTY_HINT_ENUM , anchors_presets_options , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL ) , " _set_anchors_layout_preset " , " _get_anchors_layout_preset " ) ;
2021-11-08 20:53:41 +00:00
ADD_PROPERTY_DEFAULT ( " anchors_preset " , - 1 ) ;
ADD_SUBGROUP_INDENT ( " Anchor Points " , " anchor_ " , 1 ) ;
2022-03-27 17:16:03 +00:00
ADD_PROPERTYI ( PropertyInfo ( Variant : : FLOAT , " anchor_left " , PROPERTY_HINT_RANGE , " 0,1,0.001,or_less,or_greater " ) , " _set_anchor " , " get_anchor " , SIDE_LEFT ) ;
ADD_PROPERTYI ( PropertyInfo ( Variant : : FLOAT , " anchor_top " , PROPERTY_HINT_RANGE , " 0,1,0.001,or_less,or_greater " ) , " _set_anchor " , " get_anchor " , SIDE_TOP ) ;
ADD_PROPERTYI ( PropertyInfo ( Variant : : FLOAT , " anchor_right " , PROPERTY_HINT_RANGE , " 0,1,0.001,or_less,or_greater " ) , " _set_anchor " , " get_anchor " , SIDE_RIGHT ) ;
ADD_PROPERTYI ( PropertyInfo ( Variant : : FLOAT , " anchor_bottom " , PROPERTY_HINT_RANGE , " 0,1,0.001,or_less,or_greater " ) , " _set_anchor " , " get_anchor " , SIDE_BOTTOM ) ;
2017-03-05 15:44:50 +00:00
2021-11-08 20:53:41 +00:00
ADD_SUBGROUP_INDENT ( " Anchor Offsets " , " offset_ " , 1 ) ;
2021-12-03 00:09:19 +00:00
ADD_PROPERTYI ( PropertyInfo ( Variant : : INT , " offset_left " , PROPERTY_HINT_RANGE , " -4096,4096,suffix:px " ) , " set_offset " , " get_offset " , SIDE_LEFT ) ;
ADD_PROPERTYI ( PropertyInfo ( Variant : : INT , " offset_top " , PROPERTY_HINT_RANGE , " -4096,4096,suffix:px " ) , " set_offset " , " get_offset " , SIDE_TOP ) ;
ADD_PROPERTYI ( PropertyInfo ( Variant : : INT , " offset_right " , PROPERTY_HINT_RANGE , " -4096,4096,suffix:px " ) , " set_offset " , " get_offset " , SIDE_RIGHT ) ;
ADD_PROPERTYI ( PropertyInfo ( Variant : : INT , " offset_bottom " , PROPERTY_HINT_RANGE , " -4096,4096,suffix:px " ) , " set_offset " , " get_offset " , SIDE_BOTTOM ) ;
2017-03-05 15:44:50 +00:00
2021-11-08 20:53:41 +00:00
ADD_SUBGROUP_INDENT ( " Grow Direction " , " grow_ " , 1 ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " grow_horizontal " , PROPERTY_HINT_ENUM , " Left,Right,Both " ) , " set_h_grow_direction " , " get_h_grow_direction " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " grow_vertical " , PROPERTY_HINT_ENUM , " Top,Bottom,Both " ) , " set_v_grow_direction " , " get_v_grow_direction " ) ;
2020-09-03 11:22:16 +00:00
2022-01-23 17:14:31 +00:00
ADD_SUBGROUP ( " Transform " , " " ) ;
2021-12-03 00:09:19 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR2 , " size " , PROPERTY_HINT_NONE , " suffix:px " , PROPERTY_USAGE_EDITOR ) , " _set_size " , " get_size " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR2 , " position " , PROPERTY_HINT_NONE , " suffix:px " , PROPERTY_USAGE_EDITOR ) , " _set_position " , " get_position " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR2 , " global_position " , PROPERTY_HINT_NONE , " suffix:px " , PROPERTY_USAGE_NONE ) , " _set_global_position " , " get_global_position " ) ;
2023-09-23 14:27:01 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " rotation " , PROPERTY_HINT_RANGE , " -360,360,0.1,or_less,or_greater,radians_as_degrees " ) , " set_rotation " , " get_rotation " ) ;
2022-12-18 15:58:19 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " rotation_degrees " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NONE ) , " set_rotation_degrees " , " get_rotation_degrees " ) ;
2022-01-23 17:14:31 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR2 , " scale " ) , " set_scale " , " get_scale " ) ;
2022-06-20 02:55:52 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR2 , " pivot_offset " , PROPERTY_HINT_NONE , " suffix:px " ) , " set_pivot_offset " , " get_pivot_offset " ) ;
2021-11-08 20:53:41 +00:00
ADD_SUBGROUP ( " Container Sizing " , " size_flags_ " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " size_flags_horizontal " , PROPERTY_HINT_FLAGS , " Fill:1,Expand:2,Shrink Center:4,Shrink End:8 " ) , " set_h_size_flags " , " get_h_size_flags " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " size_flags_vertical " , PROPERTY_HINT_FLAGS , " Fill:1,Expand:2,Shrink Center:4,Shrink End:8 " ) , " set_v_size_flags " , " get_v_size_flags " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " size_flags_stretch_ratio " , PROPERTY_HINT_RANGE , " 0,20,0.01,or_greater " ) , " set_stretch_ratio " , " get_stretch_ratio " ) ;
2022-11-17 12:54:45 +00:00
ADD_GROUP ( " Localization " , " " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " localize_numeral_system " ) , " set_localize_numeral_system " , " is_localizing_numeral_system " ) ;
2017-03-05 15:44:50 +00:00
2024-01-23 21:29:45 +00:00
# ifndef DISABLE_DEPRECATED
2024-04-15 05:51:40 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " auto_translate " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NONE ) , " set_auto_translate " , " is_auto_translating " ) ;
2024-01-23 21:29:45 +00:00
# endif
2022-08-25 10:42:17 +00:00
ADD_GROUP ( " Tooltip " , " tooltip_ " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " tooltip_text " , PROPERTY_HINT_MULTILINE_TEXT ) , " set_tooltip_text " , " get_tooltip_text " ) ;
2024-09-24 11:11:49 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " tooltip_auto_translate_mode " , PROPERTY_HINT_ENUM , " Inherit,Always,Disabled " ) , " set_tooltip_auto_translate_mode " , " get_tooltip_auto_translate_mode " ) ;
2017-03-05 15:44:50 +00:00
2017-01-03 03:38:16 +00:00
ADD_GROUP ( " Focus " , " focus_ " ) ;
2020-12-22 16:24:29 +00:00
ADD_PROPERTYI ( PropertyInfo ( Variant : : NODE_PATH , " focus_neighbor_left " , PROPERTY_HINT_NODE_PATH_VALID_TYPES , " Control " ) , " set_focus_neighbor " , " get_focus_neighbor " , SIDE_LEFT ) ;
ADD_PROPERTYI ( PropertyInfo ( Variant : : NODE_PATH , " focus_neighbor_top " , PROPERTY_HINT_NODE_PATH_VALID_TYPES , " Control " ) , " set_focus_neighbor " , " get_focus_neighbor " , SIDE_TOP ) ;
ADD_PROPERTYI ( PropertyInfo ( Variant : : NODE_PATH , " focus_neighbor_right " , PROPERTY_HINT_NODE_PATH_VALID_TYPES , " Control " ) , " set_focus_neighbor " , " get_focus_neighbor " , SIDE_RIGHT ) ;
ADD_PROPERTYI ( PropertyInfo ( Variant : : NODE_PATH , " focus_neighbor_bottom " , PROPERTY_HINT_NODE_PATH_VALID_TYPES , " Control " ) , " set_focus_neighbor " , " get_focus_neighbor " , SIDE_BOTTOM ) ;
2018-11-08 14:30:02 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : NODE_PATH , " focus_next " , PROPERTY_HINT_NODE_PATH_VALID_TYPES , " Control " ) , " set_focus_next " , " get_focus_next " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : NODE_PATH , " focus_previous " , PROPERTY_HINT_NODE_PATH_VALID_TYPES , " Control " ) , " set_focus_previous " , " get_focus_previous " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " focus_mode " , PROPERTY_HINT_ENUM , " None,Click,All " ) , " set_focus_mode " , " get_focus_mode " ) ;
2017-03-05 15:44:50 +00:00
2017-01-08 22:54:19 +00:00
ADD_GROUP ( " Mouse " , " mouse_ " ) ;
2024-06-19 18:00:48 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " mouse_filter " , PROPERTY_HINT_ENUM , " Stop,Pass (Propagate Up),Ignore " ) , " set_mouse_filter " , " get_mouse_filter " ) ;
2022-05-16 13:10:30 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " mouse_force_pass_scroll_events " ) , " set_force_pass_scroll_events " , " is_force_pass_scroll_events " ) ;
2021-05-22 02:30:58 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " mouse_default_cursor_shape " , PROPERTY_HINT_ENUM , " Arrow,I-Beam,Pointing Hand,Cross,Wait,Busy,Drag,Can Drop,Forbidden,Vertical Resize,Horizontal Resize,Secondary Diagonal Resize,Main Diagonal Resize,Move,Vertical Split,Horizontal Split,Help " ) , " set_default_cursor_shape " , " get_default_cursor_shape " ) ;
2017-03-05 15:44:50 +00:00
2022-09-24 14:32:53 +00:00
ADD_GROUP ( " Input " , " " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : OBJECT , " shortcut_context " , PROPERTY_HINT_NODE_TYPE , " Node " ) , " set_shortcut_context " , " get_shortcut_context " ) ;
2021-03-30 17:16:33 +00:00
ADD_GROUP ( " Theme " , " theme_ " ) ;
2018-11-08 14:30:02 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : OBJECT , " theme " , PROPERTY_HINT_RESOURCE_TYPE , " Theme " ) , " set_theme " , " get_theme " ) ;
2021-07-04 20:42:23 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " theme_type_variation " , PROPERTY_HINT_ENUM_SUGGESTION ) , " set_theme_type_variation " , " get_theme_type_variation " ) ;
2021-05-27 17:31:33 +00:00
2017-08-20 15:45:01 +00:00
BIND_ENUM_CONSTANT ( FOCUS_NONE ) ;
BIND_ENUM_CONSTANT ( FOCUS_CLICK ) ;
BIND_ENUM_CONSTANT ( FOCUS_ALL ) ;
2017-03-05 15:44:50 +00:00
2014-02-10 01:10:30 +00:00
BIND_CONSTANT ( NOTIFICATION_RESIZED ) ;
BIND_CONSTANT ( NOTIFICATION_MOUSE_ENTER ) ;
BIND_CONSTANT ( NOTIFICATION_MOUSE_EXIT ) ;
2023-10-31 17:55:34 +00:00
BIND_CONSTANT ( NOTIFICATION_MOUSE_ENTER_SELF ) ;
BIND_CONSTANT ( NOTIFICATION_MOUSE_EXIT_SELF ) ;
2014-02-10 01:10:30 +00:00
BIND_CONSTANT ( NOTIFICATION_FOCUS_ENTER ) ;
BIND_CONSTANT ( NOTIFICATION_FOCUS_EXIT ) ;
BIND_CONSTANT ( NOTIFICATION_THEME_CHANGED ) ;
2018-02-27 15:37:20 +00:00
BIND_CONSTANT ( NOTIFICATION_SCROLL_BEGIN ) ;
BIND_CONSTANT ( NOTIFICATION_SCROLL_END ) ;
2020-09-03 11:22:16 +00:00
BIND_CONSTANT ( NOTIFICATION_LAYOUT_DIRECTION_CHANGED ) ;
2017-03-05 15:44:50 +00:00
2017-08-20 15:45:01 +00:00
BIND_ENUM_CONSTANT ( CURSOR_ARROW ) ;
BIND_ENUM_CONSTANT ( CURSOR_IBEAM ) ;
BIND_ENUM_CONSTANT ( CURSOR_POINTING_HAND ) ;
BIND_ENUM_CONSTANT ( CURSOR_CROSS ) ;
BIND_ENUM_CONSTANT ( CURSOR_WAIT ) ;
BIND_ENUM_CONSTANT ( CURSOR_BUSY ) ;
BIND_ENUM_CONSTANT ( CURSOR_DRAG ) ;
BIND_ENUM_CONSTANT ( CURSOR_CAN_DROP ) ;
BIND_ENUM_CONSTANT ( CURSOR_FORBIDDEN ) ;
BIND_ENUM_CONSTANT ( CURSOR_VSIZE ) ;
BIND_ENUM_CONSTANT ( CURSOR_HSIZE ) ;
BIND_ENUM_CONSTANT ( CURSOR_BDIAGSIZE ) ;
BIND_ENUM_CONSTANT ( CURSOR_FDIAGSIZE ) ;
BIND_ENUM_CONSTANT ( CURSOR_MOVE ) ;
BIND_ENUM_CONSTANT ( CURSOR_VSPLIT ) ;
BIND_ENUM_CONSTANT ( CURSOR_HSPLIT ) ;
BIND_ENUM_CONSTANT ( CURSOR_HELP ) ;
BIND_ENUM_CONSTANT ( PRESET_TOP_LEFT ) ;
BIND_ENUM_CONSTANT ( PRESET_TOP_RIGHT ) ;
BIND_ENUM_CONSTANT ( PRESET_BOTTOM_LEFT ) ;
BIND_ENUM_CONSTANT ( PRESET_BOTTOM_RIGHT ) ;
BIND_ENUM_CONSTANT ( PRESET_CENTER_LEFT ) ;
BIND_ENUM_CONSTANT ( PRESET_CENTER_TOP ) ;
BIND_ENUM_CONSTANT ( PRESET_CENTER_RIGHT ) ;
BIND_ENUM_CONSTANT ( PRESET_CENTER_BOTTOM ) ;
BIND_ENUM_CONSTANT ( PRESET_CENTER ) ;
BIND_ENUM_CONSTANT ( PRESET_LEFT_WIDE ) ;
BIND_ENUM_CONSTANT ( PRESET_TOP_WIDE ) ;
BIND_ENUM_CONSTANT ( PRESET_RIGHT_WIDE ) ;
BIND_ENUM_CONSTANT ( PRESET_BOTTOM_WIDE ) ;
BIND_ENUM_CONSTANT ( PRESET_VCENTER_WIDE ) ;
BIND_ENUM_CONSTANT ( PRESET_HCENTER_WIDE ) ;
2022-03-19 00:02:57 +00:00
BIND_ENUM_CONSTANT ( PRESET_FULL_RECT ) ;
2017-08-20 15:45:01 +00:00
2017-09-19 20:39:19 +00:00
BIND_ENUM_CONSTANT ( PRESET_MODE_MINSIZE ) ;
BIND_ENUM_CONSTANT ( PRESET_MODE_KEEP_WIDTH ) ;
2017-10-21 18:58:02 +00:00
BIND_ENUM_CONSTANT ( PRESET_MODE_KEEP_HEIGHT ) ;
2017-09-19 20:39:19 +00:00
BIND_ENUM_CONSTANT ( PRESET_MODE_KEEP_SIZE ) ;
2023-01-07 19:37:21 +00:00
BIND_BITFIELD_FLAG ( SIZE_SHRINK_BEGIN ) ;
BIND_BITFIELD_FLAG ( SIZE_FILL ) ;
BIND_BITFIELD_FLAG ( SIZE_EXPAND ) ;
BIND_BITFIELD_FLAG ( SIZE_EXPAND_FILL ) ;
BIND_BITFIELD_FLAG ( SIZE_SHRINK_CENTER ) ;
BIND_BITFIELD_FLAG ( SIZE_SHRINK_END ) ;
2017-08-20 15:45:01 +00:00
BIND_ENUM_CONSTANT ( MOUSE_FILTER_STOP ) ;
BIND_ENUM_CONSTANT ( MOUSE_FILTER_PASS ) ;
BIND_ENUM_CONSTANT ( MOUSE_FILTER_IGNORE ) ;
BIND_ENUM_CONSTANT ( GROW_DIRECTION_BEGIN ) ;
BIND_ENUM_CONSTANT ( GROW_DIRECTION_END ) ;
2018-02-12 03:58:39 +00:00
BIND_ENUM_CONSTANT ( GROW_DIRECTION_BOTH ) ;
2017-08-20 15:45:01 +00:00
BIND_ENUM_CONSTANT ( ANCHOR_BEGIN ) ;
BIND_ENUM_CONSTANT ( ANCHOR_END ) ;
2017-08-15 22:48:38 +00:00
2020-09-03 11:22:16 +00:00
BIND_ENUM_CONSTANT ( LAYOUT_DIRECTION_INHERITED ) ;
BIND_ENUM_CONSTANT ( LAYOUT_DIRECTION_LOCALE ) ;
BIND_ENUM_CONSTANT ( LAYOUT_DIRECTION_LTR ) ;
BIND_ENUM_CONSTANT ( LAYOUT_DIRECTION_RTL ) ;
BIND_ENUM_CONSTANT ( TEXT_DIRECTION_INHERITED ) ;
BIND_ENUM_CONSTANT ( TEXT_DIRECTION_AUTO ) ;
BIND_ENUM_CONSTANT ( TEXT_DIRECTION_LTR ) ;
BIND_ENUM_CONSTANT ( TEXT_DIRECTION_RTL ) ;
2014-02-10 01:10:30 +00:00
ADD_SIGNAL ( MethodInfo ( " resized " ) ) ;
2018-09-01 20:03:28 +00:00
ADD_SIGNAL ( MethodInfo ( " gui_input " , PropertyInfo ( Variant : : OBJECT , " event " , PROPERTY_HINT_RESOURCE_TYPE , " InputEvent " ) ) ) ;
2017-01-12 03:51:08 +00:00
ADD_SIGNAL ( MethodInfo ( " mouse_entered " ) ) ;
ADD_SIGNAL ( MethodInfo ( " mouse_exited " ) ) ;
ADD_SIGNAL ( MethodInfo ( " focus_entered " ) ) ;
ADD_SIGNAL ( MethodInfo ( " focus_exited " ) ) ;
2014-02-10 01:10:30 +00:00
ADD_SIGNAL ( MethodInfo ( " size_flags_changed " ) ) ;
ADD_SIGNAL ( MethodInfo ( " minimum_size_changed " ) ) ;
2020-03-06 17:00:16 +00:00
ADD_SIGNAL ( MethodInfo ( " theme_changed " ) ) ;
2017-03-13 23:30:40 +00:00
2023-02-05 19:02:50 +00:00
GDVIRTUAL_BIND ( _has_point , " point " ) ;
2021-08-22 01:52:44 +00:00
GDVIRTUAL_BIND ( _structured_text_parser , " args " , " text " ) ;
GDVIRTUAL_BIND ( _get_minimum_size ) ;
2023-02-23 13:36:10 +00:00
GDVIRTUAL_BIND ( _get_tooltip , " at_position " ) ;
2021-08-22 01:52:44 +00:00
2021-08-22 15:37:22 +00:00
GDVIRTUAL_BIND ( _get_drag_data , " at_position " ) ;
GDVIRTUAL_BIND ( _can_drop_data , " at_position " , " data " ) ;
GDVIRTUAL_BIND ( _drop_data , " at_position " , " data " ) ;
GDVIRTUAL_BIND ( _make_custom_tooltip , " for_text " ) ;
GDVIRTUAL_BIND ( _gui_input , " event " ) ;
2014-02-10 01:10:30 +00:00
}
2022-08-24 15:45:14 +00:00
2022-09-02 14:03:23 +00:00
Control : : Control ( ) {
2023-09-06 14:11:05 +00:00
data . theme_owner = memnew ( ThemeOwner ( this ) ) ;
2024-02-16 23:57:32 +00:00
set_physics_interpolation_mode ( Node : : PHYSICS_INTERPOLATION_MODE_OFF ) ;
2022-09-02 14:03:23 +00:00
}
2022-08-24 15:45:14 +00:00
Control : : ~ Control ( ) {
2022-09-02 14:03:23 +00:00
memdelete ( data . theme_owner ) ;
2022-08-24 15:45:14 +00:00
// Resources need to be disconnected.
2022-11-29 20:01:45 +00:00
for ( KeyValue < StringName , Ref < Texture2D > > & E : data . theme_icon_override ) {
2023-07-03 19:29:37 +00:00
E . value - > disconnect_changed ( callable_mp ( this , & Control : : _notify_theme_override_changed ) ) ;
2022-08-24 15:45:14 +00:00
}
2022-11-29 20:01:45 +00:00
for ( KeyValue < StringName , Ref < StyleBox > > & E : data . theme_style_override ) {
2023-07-03 19:29:37 +00:00
E . value - > disconnect_changed ( callable_mp ( this , & Control : : _notify_theme_override_changed ) ) ;
2022-08-24 15:45:14 +00:00
}
2022-11-29 20:01:45 +00:00
for ( KeyValue < StringName , Ref < Font > > & E : data . theme_font_override ) {
2023-07-03 19:29:37 +00:00
E . value - > disconnect_changed ( callable_mp ( this , & Control : : _notify_theme_override_changed ) ) ;
2022-08-24 15:45:14 +00:00
}
// Then override maps can be simply cleared.
2022-11-29 20:01:45 +00:00
data . theme_icon_override . clear ( ) ;
data . theme_style_override . clear ( ) ;
data . theme_font_override . clear ( ) ;
data . theme_font_size_override . clear ( ) ;
data . theme_color_override . clear ( ) ;
data . theme_constant_override . clear ( ) ;
2022-08-24 15:45:14 +00:00
}