2014-02-10 01:10:30 +00:00
/*************************************************************************/
/* control.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 12:16:55 +00:00
/* https://godotengine.org */
2014-02-10 01:10:30 +00:00
/*************************************************************************/
2020-01-01 10:16:22 +00:00
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
2014-02-10 01:10:30 +00:00
/* */
/* 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"
2018-09-11 16:13:45 +00:00
# include "core/message_queue.h"
# include "core/os/keyboard.h"
# include "core/os/os.h"
# include "core/print_string.h"
2019-06-12 20:35:35 +00:00
# include "core/project_settings.h"
2014-02-10 01:10:30 +00:00
# include "scene/gui/label.h"
2017-03-05 15:44:50 +00:00
# include "scene/gui/panel.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"
2017-03-05 15:44:50 +00:00
# include "scene/scene_string_names.h"
2020-03-27 18:21:27 +00:00
# include "servers/rendering_server.h"
2019-06-12 20:35:35 +00:00
2016-03-09 16:59:35 +00:00
# ifdef TOOLS_ENABLED
2017-03-05 13:21:25 +00:00
# include "editor/editor_settings.h"
2019-03-31 16:53:24 +00:00
# include "editor/plugins/canvas_item_editor_plugin.h"
2016-03-09 16:59:35 +00:00
# endif
2014-02-10 01:10:30 +00:00
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 {
2014-02-10 01:10:30 +00:00
2016-06-27 13:47:51 +00:00
Dictionary s ;
2017-09-10 13:37:49 +00:00
s [ " rotation " ] = get_rotation ( ) ;
2017-03-05 15:44:50 +00:00
s [ " scale " ] = get_scale ( ) ;
2017-11-07 07:58:35 +00:00
s [ " pivot " ] = get_pivot_offset ( ) ;
2017-08-04 23:55:03 +00:00
Array anchors ;
anchors . push_back ( get_anchor ( MARGIN_LEFT ) ) ;
anchors . push_back ( get_anchor ( MARGIN_TOP ) ) ;
anchors . push_back ( get_anchor ( MARGIN_RIGHT ) ) ;
anchors . push_back ( get_anchor ( MARGIN_BOTTOM ) ) ;
s [ " anchors " ] = anchors ;
2017-11-07 07:58:35 +00:00
Array margins ;
margins . push_back ( get_margin ( MARGIN_LEFT ) ) ;
margins . push_back ( get_margin ( MARGIN_TOP ) ) ;
margins . push_back ( get_margin ( MARGIN_RIGHT ) ) ;
margins . push_back ( get_margin ( MARGIN_BOTTOM ) ) ;
s [ " margins " ] = margins ;
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 ) {
2014-02-10 01:10:30 +00:00
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 " ] ) ;
2017-11-15 22:03:25 +00:00
Array anchors = state [ " anchors " ] ;
2017-11-07 07:58:35 +00:00
data . anchor [ MARGIN_LEFT ] = anchors [ 0 ] ;
data . anchor [ MARGIN_TOP ] = anchors [ 1 ] ;
data . anchor [ MARGIN_RIGHT ] = anchors [ 2 ] ;
data . anchor [ MARGIN_BOTTOM ] = anchors [ 3 ] ;
Array margins = state [ " margins " ] ;
data . margin [ MARGIN_LEFT ] = margins [ 0 ] ;
data . margin [ MARGIN_TOP ] = margins [ 1 ] ;
data . margin [ MARGIN_RIGHT ] = margins [ 2 ] ;
data . margin [ MARGIN_BOTTOM ] = margins [ 3 ] ;
_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 ) {
2019-03-31 16:53:24 +00:00
# ifdef TOOLS_ENABLED
set_position ( p_position , CanvasItemEditor : : get_singleton ( ) - > is_anchors_mode_enabled ( ) ) ;
# else
// Unlikely to happen. TODO: enclose all _edit_ functions into TOOLS_ENABLED
2017-11-15 22:03:25 +00:00
set_position ( p_position ) ;
2019-03-31 16:53:24 +00:00
# endif
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 ) {
2019-03-31 16:53:24 +00:00
# ifdef TOOLS_ENABLED
set_position ( ( get_position ( ) + get_transform ( ) . basis_xform ( p_edit_rect . position ) ) . snapped ( Vector2 ( 1 , 1 ) ) , CanvasItemEditor : : get_singleton ( ) - > is_anchors_mode_enabled ( ) ) ;
set_size ( p_edit_rect . size . snapped ( Vector2 ( 1 , 1 ) ) , CanvasItemEditor : : get_singleton ( ) - > is_anchors_mode_enabled ( ) ) ;
# else
// Unlikely to happen. TODO: enclose all _edit_ functions into TOOLS_ENABLED
2017-11-07 07:58:35 +00:00
set_position ( ( get_position ( ) + get_transform ( ) . basis_xform ( p_edit_rect . position ) ) . snapped ( Vector2 ( 1 , 1 ) ) ) ;
set_size ( p_edit_rect . size . snapped ( Vector2 ( 1 , 1 ) ) ) ;
2019-03-31 16:53:24 +00:00
# endif
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 ;
}
void Control : : _edit_set_rotation ( float p_rotation ) {
set_rotation ( p_rotation ) ;
}
float Control : : _edit_get_rotation ( ) const {
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
2017-03-05 15:44:50 +00:00
void Control : : set_custom_minimum_size ( const Size2 & p_custom ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( p_custom = = data . custom_minimum_size )
2014-02-10 01:10:30 +00:00
return ;
2017-03-05 15:44:50 +00:00
data . custom_minimum_size = p_custom ;
2014-02-10 01:10:30 +00:00
minimum_size_changed ( ) ;
}
2017-03-05 15:44:50 +00:00
Size2 Control : : get_custom_minimum_size ( ) const {
2014-02-10 01:10:30 +00:00
return data . custom_minimum_size ;
}
2018-05-15 20:12:35 +00:00
void Control : : _update_minimum_size_cache ( ) {
2014-02-10 01:10:30 +00:00
Size2 minsize = get_minimum_size ( ) ;
2017-03-05 15:44:50 +00:00
minsize . x = MAX ( minsize . x , data . custom_minimum_size . x ) ;
minsize . y = MAX ( minsize . y , data . custom_minimum_size . y ) ;
2018-07-01 00:36:54 +00:00
bool size_changed = false ;
if ( data . minimum_size_cache ! = minsize )
size_changed = true ;
2018-05-15 20:12:35 +00:00
data . minimum_size_cache = minsize ;
data . minimum_size_valid = true ;
2018-07-01 00:36:54 +00:00
if ( size_changed )
minimum_size_changed ( ) ;
2018-05-15 20:12:35 +00:00
}
Size2 Control : : get_combined_minimum_size ( ) const {
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
}
2017-07-06 20:42:44 +00:00
Transform2D Control : : _get_internal_transform ( ) const {
Transform2D rot_scale ;
rot_scale . set_rotation_and_scale ( data . rotation , data . scale ) ;
Transform2D offset ;
offset . set_origin ( - data . pivot_offset ) ;
return offset . affine_inverse ( ) * ( rot_scale * offset ) ;
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
bool Control : : _set ( const StringName & p_name , const Variant & p_value ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
String name = p_name ;
2016-03-20 05:25:05 +00:00
if ( ! name . begins_with ( " custom " ) ) {
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
2017-03-05 15:44:50 +00:00
if ( p_value . get_type ( ) = = Variant : : NIL ) {
2014-02-10 01:10:30 +00:00
if ( name . begins_with ( " custom_icons/ " ) ) {
2017-03-05 15:44:50 +00:00
String dname = name . get_slicec ( ' / ' , 1 ) ;
2019-02-25 15:13:25 +00:00
if ( data . icon_override . has ( dname ) ) {
2020-02-21 17:28:45 +00:00
data . icon_override [ dname ] - > disconnect ( " changed " , callable_mp ( this , & Control : : _override_changed ) ) ;
2019-02-25 15:13:25 +00:00
}
2014-02-10 01:10:30 +00:00
data . icon_override . erase ( dname ) ;
2015-04-21 19:01:58 +00:00
notification ( NOTIFICATION_THEME_CHANGED ) ;
2015-12-20 21:21:53 +00:00
} else if ( name . begins_with ( " custom_shaders/ " ) ) {
2017-03-05 15:44:50 +00:00
String dname = name . get_slicec ( ' / ' , 1 ) ;
2019-02-25 15:13:25 +00:00
if ( data . shader_override . has ( dname ) ) {
2020-02-21 17:28:45 +00:00
data . shader_override [ dname ] - > disconnect ( " changed " , callable_mp ( this , & Control : : _override_changed ) ) ;
2019-02-25 15:13:25 +00:00
}
2015-12-20 21:21:53 +00:00
data . shader_override . erase ( dname ) ;
notification ( NOTIFICATION_THEME_CHANGED ) ;
2014-02-10 01:10:30 +00:00
} else if ( name . begins_with ( " custom_styles/ " ) ) {
2017-03-05 15:44:50 +00:00
String dname = name . get_slicec ( ' / ' , 1 ) ;
2019-02-25 15:13:25 +00:00
if ( data . style_override . has ( dname ) ) {
2020-02-21 17:28:45 +00:00
data . style_override [ dname ] - > disconnect ( " changed " , callable_mp ( this , & Control : : _override_changed ) ) ;
2019-02-25 15:13:25 +00:00
}
2014-02-10 01:10:30 +00:00
data . style_override . erase ( dname ) ;
2015-04-21 19:01:58 +00:00
notification ( NOTIFICATION_THEME_CHANGED ) ;
2014-02-10 01:10:30 +00:00
} else if ( name . begins_with ( " custom_fonts/ " ) ) {
2017-03-05 15:44:50 +00:00
String dname = name . get_slicec ( ' / ' , 1 ) ;
2016-06-17 19:00:27 +00:00
if ( data . font_override . has ( dname ) ) {
2020-02-21 17:28:45 +00:00
data . font_override [ dname ] - > disconnect ( " changed " , callable_mp ( this , & Control : : _override_changed ) ) ;
2016-06-17 19:00:27 +00:00
}
2014-02-10 01:10:30 +00:00
data . font_override . erase ( dname ) ;
2015-04-21 19:01:58 +00:00
notification ( NOTIFICATION_THEME_CHANGED ) ;
2014-02-10 01:10:30 +00:00
} else if ( name . begins_with ( " custom_colors/ " ) ) {
2017-03-05 15:44:50 +00:00
String dname = name . get_slicec ( ' / ' , 1 ) ;
2014-02-10 01:10:30 +00:00
data . color_override . erase ( dname ) ;
2015-04-21 19:01:58 +00:00
notification ( NOTIFICATION_THEME_CHANGED ) ;
2014-02-10 01:10:30 +00:00
} else if ( name . begins_with ( " custom_constants/ " ) ) {
2017-03-05 15:44:50 +00:00
String dname = name . get_slicec ( ' / ' , 1 ) ;
2014-02-10 01:10:30 +00:00
data . constant_override . erase ( dname ) ;
2015-04-21 19:01:58 +00:00
notification ( NOTIFICATION_THEME_CHANGED ) ;
2014-02-10 01:10:30 +00:00
} else
return false ;
} else {
if ( name . begins_with ( " custom_icons/ " ) ) {
2017-03-05 15:44:50 +00:00
String dname = name . get_slicec ( ' / ' , 1 ) ;
2020-03-12 12:37:40 +00:00
add_theme_icon_override ( dname , p_value ) ;
2015-12-20 21:21:53 +00:00
} else if ( name . begins_with ( " custom_shaders/ " ) ) {
2017-03-05 15:44:50 +00:00
String dname = name . get_slicec ( ' / ' , 1 ) ;
2020-03-12 12:37:40 +00:00
add_theme_shader_override ( dname , p_value ) ;
2014-02-10 01:10:30 +00:00
} else if ( name . begins_with ( " custom_styles/ " ) ) {
2017-03-05 15:44:50 +00:00
String dname = name . get_slicec ( ' / ' , 1 ) ;
2020-03-12 12:37:40 +00:00
add_theme_style_override ( dname , p_value ) ;
2014-02-10 01:10:30 +00:00
} else if ( name . begins_with ( " custom_fonts/ " ) ) {
2017-03-05 15:44:50 +00:00
String dname = name . get_slicec ( ' / ' , 1 ) ;
2020-03-12 12:37:40 +00:00
add_theme_font_override ( dname , p_value ) ;
2014-02-10 01:10:30 +00:00
} else if ( name . begins_with ( " custom_colors/ " ) ) {
2017-03-05 15:44:50 +00:00
String dname = name . get_slicec ( ' / ' , 1 ) ;
2020-03-12 12:37:40 +00:00
add_theme_color_override ( dname , p_value ) ;
2014-02-10 01:10:30 +00:00
} else if ( name . begins_with ( " custom_constants/ " ) ) {
2017-03-05 15:44:50 +00:00
String dname = name . get_slicec ( ' / ' , 1 ) ;
2020-03-12 12:37:40 +00:00
add_theme_constant_override ( dname , p_value ) ;
2014-02-10 01:10:30 +00:00
} else
return false ;
}
return true ;
}
void Control : : _update_minimum_size ( ) {
2014-11-06 00:20:42 +00:00
if ( ! is_inside_tree ( ) )
2014-02-10 01:10:30 +00:00
return ;
Size2 minsize = get_combined_minimum_size ( ) ;
if ( minsize . x > data . size_cache . x | |
2017-03-05 15:44:50 +00:00
minsize . y > data . size_cache . y ) {
2019-07-27 10:55:03 +00:00
_size_changed ( ) ;
2014-02-10 01:10:30 +00:00
}
2018-05-15 20:12:35 +00:00
data . updating_last_minimum_size = false ;
if ( minsize ! = data . last_minimum_size ) {
2018-05-17 21:02:16 +00:00
data . last_minimum_size = minsize ;
2018-05-15 20:12:35 +00:00
emit_signal ( SceneStringNames : : get_singleton ( ) - > minimum_size_changed ) ;
}
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
bool Control : : _get ( const StringName & p_name , Variant & r_ret ) const {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
String sname = p_name ;
2014-02-10 01:10:30 +00:00
2016-06-12 18:31:38 +00:00
if ( ! sname . begins_with ( " custom " ) ) {
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
if ( sname . begins_with ( " custom_icons/ " ) ) {
2017-03-05 15:44:50 +00:00
String name = sname . get_slicec ( ' / ' , 1 ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
r_ret = data . icon_override . has ( name ) ? Variant ( data . icon_override [ name ] ) : Variant ( ) ;
2015-12-20 21:21:53 +00:00
} else if ( sname . begins_with ( " custom_shaders/ " ) ) {
2017-03-05 15:44:50 +00:00
String name = sname . get_slicec ( ' / ' , 1 ) ;
2015-12-20 21:21:53 +00:00
2017-03-05 15:44:50 +00:00
r_ret = data . shader_override . has ( name ) ? Variant ( data . shader_override [ name ] ) : Variant ( ) ;
2014-02-10 01:10:30 +00:00
} else if ( sname . begins_with ( " custom_styles/ " ) ) {
2017-03-05 15:44:50 +00:00
String name = sname . get_slicec ( ' / ' , 1 ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
r_ret = data . style_override . has ( name ) ? Variant ( data . style_override [ name ] ) : Variant ( ) ;
2014-02-10 01:10:30 +00:00
} else if ( sname . begins_with ( " custom_fonts/ " ) ) {
2017-03-05 15:44:50 +00:00
String name = sname . get_slicec ( ' / ' , 1 ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
r_ret = data . font_override . has ( name ) ? Variant ( data . font_override [ name ] ) : Variant ( ) ;
2014-02-10 01:10:30 +00:00
} else if ( sname . begins_with ( " custom_colors/ " ) ) {
2017-03-05 15:44:50 +00:00
String name = sname . get_slicec ( ' / ' , 1 ) ;
r_ret = data . color_override . has ( name ) ? Variant ( data . color_override [ name ] ) : Variant ( ) ;
2014-02-10 01:10:30 +00:00
} else if ( sname . begins_with ( " custom_constants/ " ) ) {
2017-03-05 15:44:50 +00:00
String name = sname . get_slicec ( ' / ' , 1 ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
r_ret = data . constant_override . has ( name ) ? Variant ( data . constant_override [ name ] ) : Variant ( ) ;
2014-02-10 01:10:30 +00:00
} else
return false ;
return true ;
}
2017-03-05 15:44:50 +00:00
void Control : : _get_property_list ( List < PropertyInfo > * p_list ) const {
2014-02-10 01:10:30 +00:00
2018-11-14 17:02:21 +00:00
Ref < Theme > theme = Theme : : get_default ( ) ;
/* Using the default theme since the properties below are meant for editor only
2014-02-10 01:10:30 +00:00
if ( data . theme . is_valid ( ) ) {
2017-03-05 15:44:50 +00:00
theme = data . theme ;
2014-02-10 01:10:30 +00:00
} else {
2017-03-05 15:44:50 +00:00
theme = Theme : : get_default ( ) ;
2018-11-14 15:23:47 +00:00
2018-11-14 17:02:21 +00:00
} */
2014-02-10 01:10:30 +00:00
{
List < StringName > names ;
2017-03-05 15:44:50 +00:00
theme - > get_icon_list ( get_class_name ( ) , & names ) ;
for ( List < StringName > : : Element * E = names . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
uint32_t hint = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE ;
2014-02-10 01:10:30 +00:00
if ( data . icon_override . has ( E - > get ( ) ) )
2017-03-05 15:44:50 +00:00
hint | = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED ;
2014-02-10 01:10:30 +00:00
2019-06-11 18:43:37 +00:00
p_list - > push_back ( PropertyInfo ( Variant : : OBJECT , " custom_icons/ " + E - > get ( ) , PROPERTY_HINT_RESOURCE_TYPE , " Texture2D " , hint ) ) ;
2014-02-10 01:10:30 +00:00
}
}
2015-12-20 21:21:53 +00:00
{
List < StringName > names ;
2017-03-05 15:44:50 +00:00
theme - > get_shader_list ( get_class_name ( ) , & names ) ;
for ( List < StringName > : : Element * E = names . front ( ) ; E ; E = E - > next ( ) ) {
2015-12-20 21:21:53 +00:00
2017-03-05 15:44:50 +00:00
uint32_t hint = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE ;
2015-12-20 21:21:53 +00:00
if ( data . shader_override . has ( E - > get ( ) ) )
2017-03-05 15:44:50 +00:00
hint | = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED ;
2015-12-20 21:21:53 +00:00
2018-08-24 09:20:39 +00:00
p_list - > push_back ( PropertyInfo ( Variant : : OBJECT , " custom_shaders/ " + E - > get ( ) , PROPERTY_HINT_RESOURCE_TYPE , " Shader,VisualShader " , hint ) ) ;
2015-12-20 21:21:53 +00:00
}
}
2014-02-10 01:10:30 +00:00
{
List < StringName > names ;
2017-03-05 15:44:50 +00:00
theme - > get_stylebox_list ( get_class_name ( ) , & names ) ;
for ( List < StringName > : : Element * E = names . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
uint32_t hint = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE ;
2014-02-10 01:10:30 +00:00
if ( data . style_override . has ( E - > get ( ) ) )
2017-03-05 15:44:50 +00:00
hint | = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
p_list - > push_back ( PropertyInfo ( Variant : : OBJECT , " custom_styles/ " + E - > get ( ) , PROPERTY_HINT_RESOURCE_TYPE , " StyleBox " , hint ) ) ;
2014-02-10 01:10:30 +00:00
}
}
{
List < StringName > names ;
2017-03-05 15:44:50 +00:00
theme - > get_font_list ( get_class_name ( ) , & names ) ;
for ( List < StringName > : : Element * E = names . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
uint32_t hint = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE ;
2014-02-10 01:10:30 +00:00
if ( data . font_override . has ( E - > get ( ) ) )
2017-03-05 15:44:50 +00:00
hint | = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
p_list - > push_back ( PropertyInfo ( Variant : : OBJECT , " custom_fonts/ " + E - > get ( ) , PROPERTY_HINT_RESOURCE_TYPE , " Font " , hint ) ) ;
2014-02-10 01:10:30 +00:00
}
}
{
List < StringName > names ;
2017-03-05 15:44:50 +00:00
theme - > get_color_list ( get_class_name ( ) , & names ) ;
for ( List < StringName > : : Element * E = names . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
uint32_t hint = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE ;
2014-02-10 01:10:30 +00:00
if ( data . color_override . has ( E - > get ( ) ) )
2017-03-05 15:44:50 +00:00
hint | = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
p_list - > push_back ( PropertyInfo ( Variant : : COLOR , " custom_colors/ " + E - > get ( ) , PROPERTY_HINT_NONE , " " , hint ) ) ;
2014-02-10 01:10:30 +00:00
}
}
{
List < StringName > names ;
2017-03-05 15:44:50 +00:00
theme - > get_constant_list ( get_class_name ( ) , & names ) ;
for ( List < StringName > : : Element * E = names . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
uint32_t hint = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE ;
2014-02-10 01:10:30 +00:00
if ( data . constant_override . has ( E - > get ( ) ) )
2017-03-05 15:44:50 +00:00
hint | = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
p_list - > push_back ( PropertyInfo ( Variant : : INT , " custom_constants/ " + E - > get ( ) , PROPERTY_HINT_RANGE , " -16384,16384 " , hint ) ) ;
2014-02-10 01:10:30 +00:00
}
}
}
Control * Control : : get_parent_control ( ) const {
return data . parent ;
}
2017-03-05 15:44:50 +00:00
void Control : : _resize ( const Size2 & p_size ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
_size_changed ( ) ;
}
2016-08-06 01:46:45 +00:00
//moved theme configuration here, so controls can set up even if still not inside active scene
void Control : : add_child_notify ( Node * p_child ) {
2017-08-24 20:58:51 +00:00
Control * child_c = Object : : cast_to < Control > ( p_child ) ;
2016-08-06 01:46:45 +00:00
2020-03-06 17:00:16 +00:00
if ( child_c & & child_c - > data . theme . is_null ( ) & & ( data . theme_owner | | data . theme_owner_window ) ) {
_propagate_theme_changed ( child_c , data . theme_owner , data . theme_owner_window ) ; //need to propagate here, since many controls may require setting up stuff
}
Window * child_w = Object : : cast_to < Window > ( p_child ) ;
if ( child_w & & child_w - > theme . is_null ( ) & & ( data . theme_owner | | data . theme_owner_window ) ) {
_propagate_theme_changed ( child_w , data . theme_owner , data . theme_owner_window ) ; //need to propagate here, since many controls may require setting up stuff
2016-08-06 01:46:45 +00:00
}
}
void Control : : remove_child_notify ( Node * p_child ) {
2017-08-24 20:58:51 +00:00
Control * child_c = Object : : cast_to < Control > ( p_child ) ;
2016-08-06 01:46:45 +00:00
2020-03-06 17:00:16 +00:00
if ( child_c & & ( child_c - > data . theme_owner | | child_c - > data . theme_owner_window ) & & child_c - > data . theme . is_null ( ) ) {
_propagate_theme_changed ( child_c , NULL , NULL ) ;
}
Window * child_w = Object : : cast_to < Window > ( p_child ) ;
if ( child_w & & ( child_w - > theme_owner | | child_w - > theme_owner_window ) & & child_w - > theme . is_null ( ) ) {
_propagate_theme_changed ( child_w , NULL , NULL ) ;
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 ( ) ;
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
void Control : : _notification ( int p_notification ) {
2017-03-05 15:44:50 +00:00
switch ( p_notification ) {
2014-02-10 01:10:30 +00:00
2014-11-06 00:20:42 +00:00
case NOTIFICATION_ENTER_TREE : {
2014-02-10 01:10:30 +00:00
2018-05-15 20:12:35 +00:00
} break ;
case NOTIFICATION_POST_ENTER_TREE : {
2018-06-02 00:28:49 +00:00
data . minimum_size_valid = false ;
_size_changed ( ) ;
2014-02-10 01:10:30 +00:00
} break ;
2014-11-06 00:20:42 +00:00
case NOTIFICATION_EXIT_TREE : {
2014-02-10 01:10:30 +00:00
2016-01-17 01:41:10 +00:00
get_viewport ( ) - > _gui_remove_control ( this ) ;
2014-02-10 01:10:30 +00:00
} break ;
case NOTIFICATION_ENTER_CANVAS : {
2017-08-24 20:58:51 +00:00
data . parent = Object : : cast_to < Control > ( get_parent ( ) ) ;
2014-02-10 01:10:30 +00:00
2020-03-14 16:06:39 +00:00
Node * parent = this ; //meh
Control * parent_control = NULL ;
bool subwindow = false ;
2016-06-14 00:10:45 +00:00
2020-03-14 16:06:39 +00:00
while ( parent ) {
2014-02-10 01:10:30 +00:00
2020-03-14 16:06:39 +00:00
parent = parent - > get_parent ( ) ;
2016-06-14 00:37:04 +00:00
2020-03-14 16:06:39 +00:00
if ( ! parent )
break ;
2014-02-10 01:10:30 +00:00
2020-03-14 16:06:39 +00:00
CanvasItem * ci = Object : : cast_to < CanvasItem > ( parent ) ;
if ( ci & & ci - > is_set_as_toplevel ( ) ) {
subwindow = true ;
break ;
2014-02-10 01:10:30 +00:00
}
2020-03-14 16:06:39 +00:00
parent_control = Object : : cast_to < Control > ( parent ) ;
2014-02-10 01:10:30 +00:00
2020-03-14 16:06:39 +00:00
if ( parent_control ) {
break ;
} else if ( ci ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
} else {
2020-03-14 16:06:39 +00:00
break ;
2016-01-17 01:41:10 +00:00
}
2014-02-10 01:10:30 +00:00
}
2020-03-14 16:06:39 +00:00
if ( parent_control & & ! subwindow ) {
//do nothing, has a parent control and not toplevel
if ( data . theme . is_null ( ) & & parent_control - > data . theme_owner ) {
data . theme_owner = parent_control - > data . theme_owner ;
notification ( NOTIFICATION_THEME_CHANGED ) ;
}
} else {
//is a regular root control or toplevel
data . RI = get_viewport ( ) - > _gui_add_root_control ( this ) ;
2017-01-14 11:26:56 +00:00
}
2014-02-10 01:10:30 +00:00
2020-03-14 16:06:39 +00:00
data . parent_canvas_item = get_parent_item ( ) ;
if ( data . parent_canvas_item ) {
data . parent_canvas_item - > connect ( " item_rect_changed " , callable_mp ( this , & Control : : _size_changed ) ) ;
} else {
//connect viewport
get_viewport ( ) - > connect ( " size_changed " , callable_mp ( this , & Control : : _size_changed ) ) ;
}
2014-02-10 01:10:30 +00:00
} break ;
case NOTIFICATION_EXIT_CANVAS : {
if ( data . parent_canvas_item ) {
2020-02-21 17:28:45 +00:00
data . parent_canvas_item - > disconnect ( " item_rect_changed " , callable_mp ( this , & Control : : _size_changed ) ) ;
2017-03-05 15:44:50 +00:00
data . parent_canvas_item = NULL ;
2016-01-17 23:03:57 +00:00
} else if ( ! is_set_as_toplevel ( ) ) {
2016-01-17 01:41:10 +00:00
//disconnect viewport
2020-02-21 17:28:45 +00:00
get_viewport ( ) - > disconnect ( " size_changed " , callable_mp ( this , & Control : : _size_changed ) ) ;
2014-02-10 01:10:30 +00:00
}
2016-01-17 01:41:10 +00:00
if ( data . RI ) {
get_viewport ( ) - > _gui_remove_root_control ( data . RI ) ;
2017-03-05 15:44:50 +00:00
data . RI = NULL ;
2016-01-17 01:41:10 +00:00
}
2017-03-05 15:44:50 +00:00
data . parent = NULL ;
data . parent_canvas_item = NULL ;
2017-01-14 11:26:56 +00:00
/*
if ( data . theme_owner & & data . theme . is_null ( ) ) {
data . theme_owner = NULL ;
notification ( NOTIFICATION_THEME_CHANGED ) ;
}
*/
2014-02-10 01:10:30 +00:00
} break ;
2017-03-05 15:44:50 +00:00
case NOTIFICATION_MOVED_IN_PARENT : {
// some parents need to know the order of the childrens to draw (like TabContainer)
2017-03-24 20:45:31 +00:00
// update if necessary
2017-03-05 15:44:50 +00:00
if ( data . parent )
data . parent - > update ( ) ;
update ( ) ;
if ( data . RI ) {
get_viewport ( ) - > _gui_set_root_order_dirty ( ) ;
}
} break ;
2014-02-10 01:10:30 +00:00
case NOTIFICATION_RESIZED : {
emit_signal ( SceneStringNames : : get_singleton ( ) - > resized ) ;
} break ;
case NOTIFICATION_DRAW : {
2016-08-31 02:44:14 +00:00
_update_canvas_item_transform ( ) ;
2020-03-27 18:21:27 +00:00
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 ) ;
2014-02-10 01:10:30 +00:00
//emit_signal(SceneStringNames::get_singleton()->draw);
} break ;
case NOTIFICATION_MOUSE_ENTER : {
2017-01-12 03:51:08 +00:00
emit_signal ( SceneStringNames : : get_singleton ( ) - > mouse_entered ) ;
2014-02-10 01:10:30 +00:00
} break ;
case NOTIFICATION_MOUSE_EXIT : {
2017-01-12 03:51:08 +00:00
emit_signal ( SceneStringNames : : get_singleton ( ) - > mouse_exited ) ;
2014-02-10 01:10:30 +00:00
} break ;
case NOTIFICATION_FOCUS_ENTER : {
2017-01-12 03:51:08 +00:00
emit_signal ( SceneStringNames : : get_singleton ( ) - > focus_entered ) ;
2014-02-10 01:10:30 +00:00
update ( ) ;
} break ;
case NOTIFICATION_FOCUS_EXIT : {
2017-01-12 03:51:08 +00:00
emit_signal ( SceneStringNames : : get_singleton ( ) - > focus_exited ) ;
2014-02-10 01:10:30 +00:00
update ( ) ;
} break ;
case NOTIFICATION_THEME_CHANGED : {
2019-09-03 18:48:47 +00:00
minimum_size_changed ( ) ;
2014-02-10 01:10:30 +00:00
update ( ) ;
} break ;
case NOTIFICATION_VISIBILITY_CHANGED : {
2017-01-13 13:45:50 +00:00
if ( ! is_visible_in_tree ( ) ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( get_viewport ( ) ! = NULL )
2016-03-22 04:46:33 +00:00
get_viewport ( ) - > _gui_hid_control ( this ) ;
2016-04-07 07:46:38 +00:00
2014-02-10 01:10:30 +00:00
//remove key focus
2020-03-20 02:32:09 +00:00
2014-02-10 01:10:30 +00:00
} else {
2018-05-15 20:12:35 +00:00
data . minimum_size_valid = false ;
2014-02-10 01:10:30 +00:00
_size_changed ( ) ;
}
} break ;
}
}
bool Control : : clips_input ( ) const {
2018-07-29 15:46:53 +00:00
if ( get_script_instance ( ) ) {
return get_script_instance ( ) - > call ( SceneStringNames : : get_singleton ( ) - > _clips_input ) ;
}
2014-02-10 01:10:30 +00:00
return false ;
}
2017-03-05 15:44:50 +00:00
bool Control : : has_point ( const Point2 & p_point ) const {
2014-02-10 01:10:30 +00:00
if ( get_script_instance ( ) ) {
2017-03-05 15:44:50 +00:00
Variant v = p_point ;
const Variant * p = & v ;
2020-02-19 19:27:19 +00:00
Callable : : CallError ce ;
2017-03-05 15:44:50 +00:00
Variant ret = get_script_instance ( ) - > call ( SceneStringNames : : get_singleton ( ) - > has_point , & p , 1 , ce ) ;
2020-02-19 19:27:19 +00:00
if ( ce . error = = Callable : : CallError : : CALL_OK ) {
2014-02-10 01:10:30 +00:00
return ret ;
}
}
/*if (has_stylebox("mask")) {
Ref < StyleBox > mask = get_stylebox ( " mask " ) ;
return mask - > test_mask ( p_point , Rect2 ( Point2 ( ) , get_size ( ) ) ) ;
} */
2017-03-05 15:44:50 +00:00
return Rect2 ( Point2 ( ) , get_size ( ) ) . has_point ( p_point ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void Control : : set_drag_forwarding ( Control * p_target ) {
2016-05-03 14:10:28 +00:00
if ( p_target )
2017-08-07 10:17:31 +00:00
data . drag_owner = p_target - > get_instance_id ( ) ;
2016-05-03 14:10:28 +00:00
else
2020-02-12 17:24:06 +00:00
data . drag_owner = ObjectID ( ) ;
2016-05-03 14:10:28 +00:00
}
2017-03-05 15:44:50 +00:00
Variant Control : : get_drag_data ( const Point2 & p_point ) {
2014-02-10 01:10:30 +00:00
2020-02-12 17:24:06 +00:00
if ( data . drag_owner . is_valid ( ) ) {
2016-05-03 14:10:28 +00:00
Object * obj = ObjectDB : : get_instance ( data . drag_owner ) ;
if ( obj ) {
2017-08-24 20:58:51 +00:00
Control * c = Object : : cast_to < Control > ( obj ) ;
2017-03-05 15:44:50 +00:00
return c - > call ( " get_drag_data_fw " , p_point , this ) ;
2016-05-03 14:10:28 +00:00
}
}
2014-02-10 01:10:30 +00:00
if ( get_script_instance ( ) ) {
2017-03-05 15:44:50 +00:00
Variant v = p_point ;
const Variant * p = & v ;
2020-02-19 19:27:19 +00:00
Callable : : CallError ce ;
2017-03-05 15:44:50 +00:00
Variant ret = get_script_instance ( ) - > call ( SceneStringNames : : get_singleton ( ) - > get_drag_data , & p , 1 , ce ) ;
2020-02-19 19:27:19 +00:00
if ( ce . error = = Callable : : CallError : : CALL_OK )
2014-02-10 01:10:30 +00:00
return ret ;
}
return Variant ( ) ;
}
2017-03-05 15:44:50 +00:00
bool Control : : can_drop_data ( const Point2 & p_point , const Variant & p_data ) const {
2014-02-10 01:10:30 +00:00
2020-02-12 17:24:06 +00:00
if ( data . drag_owner . is_valid ( ) ) {
2016-05-03 14:10:28 +00:00
Object * obj = ObjectDB : : get_instance ( data . drag_owner ) ;
if ( obj ) {
2017-08-24 20:58:51 +00:00
Control * c = Object : : cast_to < Control > ( obj ) ;
2017-03-05 15:44:50 +00:00
return c - > call ( " can_drop_data_fw " , p_point , p_data , this ) ;
2016-05-03 14:10:28 +00:00
}
}
2014-02-10 01:10:30 +00:00
if ( get_script_instance ( ) ) {
2017-03-05 15:44:50 +00:00
Variant v = p_point ;
const Variant * p [ 2 ] = { & v , & p_data } ;
2020-02-19 19:27:19 +00:00
Callable : : CallError ce ;
2017-03-05 15:44:50 +00:00
Variant ret = get_script_instance ( ) - > call ( SceneStringNames : : get_singleton ( ) - > can_drop_data , p , 2 , ce ) ;
2020-02-19 19:27:19 +00:00
if ( ce . error = = Callable : : CallError : : CALL_OK )
2014-02-10 01:10:30 +00:00
return ret ;
}
return Variant ( ) ;
}
2017-03-05 15:44:50 +00:00
void Control : : drop_data ( const Point2 & p_point , const Variant & p_data ) {
2014-02-10 01:10:30 +00:00
2020-02-12 17:24:06 +00:00
if ( data . drag_owner . is_valid ( ) ) {
2016-05-03 14:10:28 +00:00
Object * obj = ObjectDB : : get_instance ( data . drag_owner ) ;
if ( obj ) {
2017-08-24 20:58:51 +00:00
Control * c = Object : : cast_to < Control > ( obj ) ;
2017-03-05 15:44:50 +00:00
c - > call ( " drop_data_fw " , p_point , p_data , this ) ;
2016-05-03 14:10:28 +00:00
return ;
}
}
2014-02-10 01:10:30 +00:00
if ( get_script_instance ( ) ) {
2017-03-05 15:44:50 +00:00
Variant v = p_point ;
const Variant * p [ 2 ] = { & v , & p_data } ;
2020-02-19 19:27:19 +00:00
Callable : : CallError ce ;
2017-03-05 15:44:50 +00:00
Variant ret = get_script_instance ( ) - > call ( SceneStringNames : : get_singleton ( ) - > drop_data , p , 2 , ce ) ;
2020-02-19 19:27:19 +00:00
if ( ce . error = = Callable : : CallError : : CALL_OK )
2014-02-10 01:10:30 +00:00
return ;
}
}
2017-03-05 15:44:50 +00:00
void Control : : force_drag ( const Variant & p_data , Control * p_control ) {
2014-02-10 01:10:30 +00:00
2014-11-06 00:20:42 +00:00
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND ( p_data . get_type ( ) = = Variant : : NIL ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
get_viewport ( ) - > _gui_force_drag ( this , p_data , p_control ) ;
2014-02-10 01:10:30 +00:00
}
void Control : : set_drag_preview ( Control * p_control ) {
2016-01-17 01:41:10 +00:00
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
2018-10-07 21:50:42 +00:00
ERR_FAIL_COND ( ! get_viewport ( ) - > gui_is_dragging ( ) ) ;
2017-03-05 15:44:50 +00:00
get_viewport ( ) - > _gui_set_drag_preview ( this , p_control ) ;
2014-02-10 01:10:30 +00:00
}
Size2 Control : : get_minimum_size ( ) const {
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
ScriptInstance * si = const_cast < Control * > ( this ) - > get_script_instance ( ) ;
2014-02-10 01:10:30 +00:00
if ( si ) {
2020-02-19 19:27:19 +00:00
Callable : : CallError ce ;
2017-03-13 15:45:27 +00:00
Variant s = si - > call ( SceneStringNames : : get_singleton ( ) - > _get_minimum_size , NULL , 0 , ce ) ;
2020-02-19 19:27:19 +00:00
if ( ce . error = = Callable : : CallError : : CALL_OK )
2014-02-10 01:10:30 +00:00
return s ;
}
return Size2 ( ) ;
}
2020-03-06 17:00:16 +00:00
template < class T >
2020-03-12 12:37:40 +00:00
bool Control : : _find_theme_item ( Control * p_theme_owner , Window * p_theme_owner_window , T & r_ret , T ( Theme : : * get_func ) ( const StringName & , const StringName & ) const , bool ( Theme : : * has_func ) ( const StringName & , const StringName & ) const , const StringName & p_name , const StringName & p_type ) {
2014-02-10 01:10:30 +00:00
2020-03-06 17:00:16 +00:00
// try with custom themes
2020-03-12 12:37:40 +00:00
Control * theme_owner = p_theme_owner ;
Window * theme_owner_window = p_theme_owner_window ;
2014-12-17 01:31:57 +00:00
2020-03-06 17:00:16 +00:00
while ( theme_owner | | theme_owner_window ) {
StringName class_name = p_type ;
while ( class_name ! = StringName ( ) ) {
if ( theme_owner & & ( theme_owner - > data . theme . operator - > ( ) - > * has_func ) ( p_name , class_name ) ) {
r_ret = ( theme_owner - > data . theme . operator - > ( ) - > * get_func ) ( p_name , class_name ) ;
return true ;
}
if ( theme_owner_window & & ( theme_owner_window - > theme . operator - > ( ) - > * has_func ) ( p_name , class_name ) ) {
r_ret = ( theme_owner_window - > theme . operator - > ( ) - > * get_func ) ( p_name , class_name ) ;
return true ;
}
class_name = ClassDB : : get_parent_class_nocheck ( class_name ) ;
}
Node * parent = theme_owner ? theme_owner - > get_parent ( ) : theme_owner_window - > get_parent ( ) ;
Control * parent_c = Object : : cast_to < Control > ( parent ) ;
if ( parent_c ) {
theme_owner = parent_c - > data . theme_owner ;
theme_owner_window = parent_c - > data . theme_owner_window ;
} else {
Window * parent_w = Object : : cast_to < Window > ( parent ) ;
if ( parent_w ) {
theme_owner = parent_w - > theme_owner ;
theme_owner_window = parent_w - > theme_owner_window ;
} else {
theme_owner = NULL ;
theme_owner_window = NULL ;
}
}
2014-12-17 01:31:57 +00:00
}
2020-03-06 17:00:16 +00:00
return false ;
}
2014-02-10 01:10:30 +00:00
2020-03-12 12:37:40 +00:00
bool Control : : _has_theme_item ( Control * p_theme_owner , Window * p_theme_owner_window , bool ( Theme : : * has_func ) ( const StringName & , const StringName & ) const , const StringName & p_name , const StringName & p_type ) {
2014-02-10 01:10:30 +00:00
// try with custom themes
2020-03-12 12:37:40 +00:00
Control * theme_owner = p_theme_owner ;
Window * theme_owner_window = p_theme_owner_window ;
2014-02-10 01:10:30 +00:00
2020-03-06 17:00:16 +00:00
while ( theme_owner | | theme_owner_window ) {
2014-02-10 01:10:30 +00:00
2020-03-06 17:00:16 +00:00
StringName class_name = p_type ;
2017-01-11 21:29:59 +00:00
2017-03-05 15:44:50 +00:00
while ( class_name ! = StringName ( ) ) {
2020-03-06 17:00:16 +00:00
if ( theme_owner & & ( theme_owner - > data . theme . operator - > ( ) - > * has_func ) ( p_name , class_name ) ) {
return true ;
}
if ( theme_owner_window & & ( theme_owner_window - > theme . operator - > ( ) - > * has_func ) ( p_name , class_name ) ) {
return true ;
2017-01-11 21:29:59 +00:00
}
class_name = ClassDB : : get_parent_class_nocheck ( class_name ) ;
}
2020-03-06 17:00:16 +00:00
Node * parent = theme_owner ? theme_owner - > get_parent ( ) : theme_owner_window - > get_parent ( ) ;
Control * parent_c = Object : : cast_to < Control > ( parent ) ;
if ( parent_c ) {
theme_owner = parent_c - > data . theme_owner ;
theme_owner_window = parent_c - > data . theme_owner_window ;
} else {
Window * parent_w = Object : : cast_to < Window > ( parent ) ;
if ( parent_w ) {
theme_owner = parent_w - > theme_owner ;
theme_owner_window = parent_w - > theme_owner_window ;
} else {
theme_owner = NULL ;
theme_owner_window = NULL ;
}
}
}
return false ;
}
2020-03-12 12:37:40 +00:00
Ref < Texture2D > Control : : get_theme_icon ( const StringName & p_name , const StringName & p_type ) const {
2020-03-06 17:00:16 +00:00
if ( p_type = = StringName ( ) | | p_type = = get_class_name ( ) ) {
const Ref < Texture2D > * tex = data . icon_override . getptr ( p_name ) ;
if ( tex )
return * tex ;
}
StringName type = p_type ? p_type : get_class_name ( ) ;
2020-03-12 12:37:40 +00:00
return get_icons ( data . theme_owner , data . theme_owner_window , p_name , type ) ;
}
Ref < Texture2D > Control : : get_icons ( Control * p_theme_owner , Window * p_theme_owner_window , const StringName & p_name , const StringName & p_type ) {
2020-03-06 17:00:16 +00:00
Ref < Texture2D > icon ;
2014-02-10 01:10:30 +00:00
2020-03-12 12:37:40 +00:00
if ( _find_theme_item ( p_theme_owner , p_theme_owner_window , icon , & Theme : : get_icon , & Theme : : has_icon , p_name , p_type ) ) {
2020-03-06 17:00:16 +00:00
return icon ;
2014-02-10 01:10:30 +00:00
}
2019-07-05 20:32:52 +00:00
if ( Theme : : get_project_default ( ) . is_valid ( ) ) {
2020-03-12 12:37:40 +00:00
if ( Theme : : get_project_default ( ) - > has_icon ( p_name , p_type ) ) {
return Theme : : get_project_default ( ) - > get_icon ( p_name , p_type ) ;
2019-07-05 20:32:52 +00:00
}
}
2020-03-12 12:37:40 +00:00
return Theme : : get_default ( ) - > get_icon ( p_name , p_type ) ;
2014-02-10 01:10:30 +00:00
}
2020-03-12 12:37:40 +00:00
Ref < Shader > Control : : get_theme_shader ( const StringName & p_name , const StringName & p_type ) const {
2019-09-20 11:48:24 +00:00
if ( p_type = = StringName ( ) | | p_type = = get_class_name ( ) ) {
2015-12-20 21:21:53 +00:00
2017-03-05 15:44:50 +00:00
const Ref < Shader > * sdr = data . shader_override . getptr ( p_name ) ;
2015-12-20 21:21:53 +00:00
if ( sdr )
return * sdr ;
}
2017-03-05 15:44:50 +00:00
StringName type = p_type ? p_type : get_class_name ( ) ;
2015-12-20 21:21:53 +00:00
2020-03-12 12:37:40 +00:00
return get_shaders ( data . theme_owner , data . theme_owner_window , p_name , type ) ;
}
Ref < Shader > Control : : get_shaders ( Control * p_theme_owner , Window * p_theme_owner_window , const StringName & p_name , const StringName & p_type ) {
2020-03-06 17:00:16 +00:00
Ref < Shader > shader ;
2015-12-20 21:21:53 +00:00
2020-03-12 12:37:40 +00:00
if ( _find_theme_item ( p_theme_owner , p_theme_owner_window , shader , & Theme : : get_shader , & Theme : : has_shader , p_name , p_type ) ) {
2020-03-06 17:00:16 +00:00
return shader ;
2015-12-20 21:21:53 +00:00
}
2019-07-05 20:32:52 +00:00
if ( Theme : : get_project_default ( ) . is_valid ( ) ) {
2020-03-12 12:37:40 +00:00
if ( Theme : : get_project_default ( ) - > has_shader ( p_name , p_type ) ) {
return Theme : : get_project_default ( ) - > get_shader ( p_name , p_type ) ;
2019-07-05 20:32:52 +00:00
}
}
2020-03-12 12:37:40 +00:00
return Theme : : get_default ( ) - > get_shader ( p_name , p_type ) ;
2015-12-20 21:21:53 +00:00
}
2020-03-12 12:37:40 +00:00
Ref < StyleBox > Control : : get_theme_stylebox ( const StringName & p_name , const StringName & p_type ) const {
2016-03-08 23:00:52 +00:00
2019-09-20 11:48:24 +00:00
if ( p_type = = StringName ( ) | | p_type = = get_class_name ( ) ) {
2017-03-05 15:44:50 +00:00
const Ref < StyleBox > * style = data . style_override . getptr ( p_name ) ;
2014-12-17 01:31:57 +00:00
if ( style )
return * style ;
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
StringName type = p_type ? p_type : get_class_name ( ) ;
2014-02-10 01:10:30 +00:00
2020-03-12 12:37:40 +00:00
return get_styleboxs ( data . theme_owner , data . theme_owner_window , p_name , type ) ;
}
Ref < StyleBox > Control : : get_styleboxs ( Control * p_theme_owner , Window * p_theme_owner_window , const StringName & p_name , const StringName & p_type ) {
2020-03-06 17:00:16 +00:00
Ref < StyleBox > stylebox ;
2018-01-05 03:22:06 +00:00
2020-03-12 12:37:40 +00:00
if ( _find_theme_item ( p_theme_owner , p_theme_owner_window , stylebox , & Theme : : get_stylebox , & Theme : : has_stylebox , p_name , p_type ) ) {
2020-03-06 17:00:16 +00:00
return stylebox ;
2014-02-10 01:10:30 +00:00
}
2020-03-06 17:00:16 +00:00
if ( Theme : : get_project_default ( ) . is_valid ( ) ) {
2020-03-12 12:37:40 +00:00
if ( Theme : : get_project_default ( ) - > has_stylebox ( p_name , p_type ) ) {
return Theme : : get_project_default ( ) - > get_stylebox ( p_name , p_type ) ;
2020-03-06 17:00:16 +00:00
}
2017-09-14 16:15:04 +00:00
}
2020-03-06 17:00:16 +00:00
2020-03-12 12:37:40 +00:00
return Theme : : get_default ( ) - > get_stylebox ( p_name , p_type ) ;
2014-02-10 01:10:30 +00:00
}
2020-03-12 12:37:40 +00:00
Ref < Font > Control : : get_theme_font ( const StringName & p_name , const StringName & p_type ) const {
2014-12-17 01:31:57 +00:00
2019-09-20 11:48:24 +00:00
if ( p_type = = StringName ( ) | | p_type = = get_class_name ( ) ) {
2017-03-05 15:44:50 +00:00
const Ref < Font > * font = data . font_override . getptr ( p_name ) ;
2014-12-17 01:31:57 +00:00
if ( font )
return * font ;
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
StringName type = p_type ? p_type : get_class_name ( ) ;
2014-02-10 01:10:30 +00:00
2020-03-12 12:37:40 +00:00
return get_fonts ( data . theme_owner , data . theme_owner_window , p_name , type ) ;
}
Ref < Font > Control : : get_fonts ( Control * p_theme_owner , Window * p_theme_owner_window , const StringName & p_name , const StringName & p_type ) {
2020-03-06 17:00:16 +00:00
Ref < Font > font ;
2014-02-10 01:10:30 +00:00
2020-03-12 12:37:40 +00:00
if ( _find_theme_item ( p_theme_owner , p_theme_owner_window , font , & Theme : : get_font , & Theme : : has_font , p_name , p_type ) ) {
2020-03-06 17:00:16 +00:00
return font ;
}
2017-01-11 21:29:59 +00:00
2020-03-06 17:00:16 +00:00
if ( Theme : : get_project_default ( ) . is_valid ( ) ) {
2020-03-12 12:37:40 +00:00
if ( Theme : : get_project_default ( ) - > has_font ( p_name , p_type ) ) {
return Theme : : get_project_default ( ) - > get_font ( p_name , p_type ) ;
2017-01-11 21:29:59 +00:00
}
2014-02-10 01:10:30 +00:00
}
2020-03-12 12:37:40 +00:00
return Theme : : get_default ( ) - > get_font ( p_name , p_type ) ;
2014-02-10 01:10:30 +00:00
}
2020-03-12 12:37:40 +00:00
Color Control : : get_theme_color ( const StringName & p_name , const StringName & p_type ) const {
2014-12-17 01:31:57 +00:00
2019-09-20 11:48:24 +00:00
if ( p_type = = StringName ( ) | | p_type = = get_class_name ( ) ) {
2017-03-05 15:44:50 +00:00
const Color * color = data . color_override . getptr ( p_name ) ;
2014-12-17 01:31:57 +00:00
if ( color )
return * color ;
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
StringName type = p_type ? p_type : get_class_name ( ) ;
2017-01-11 21:29:59 +00:00
2020-03-12 12:37:40 +00:00
return get_colors ( data . theme_owner , data . theme_owner_window , p_name , type ) ;
}
Color Control : : get_colors ( Control * p_theme_owner , Window * p_theme_owner_window , const StringName & p_name , const StringName & p_type ) {
2020-03-06 17:00:16 +00:00
Color color ;
2017-01-11 21:29:59 +00:00
2020-03-12 12:37:40 +00:00
if ( _find_theme_item ( p_theme_owner , p_theme_owner_window , color , & Theme : : get_color , & Theme : : has_color , p_name , p_type ) ) {
2020-03-06 17:00:16 +00:00
return color ;
2014-02-10 01:10:30 +00:00
}
2019-07-05 20:32:52 +00:00
if ( Theme : : get_project_default ( ) . is_valid ( ) ) {
2020-03-12 12:37:40 +00:00
if ( Theme : : get_project_default ( ) - > has_color ( p_name , p_type ) ) {
return Theme : : get_project_default ( ) - > get_color ( p_name , p_type ) ;
2019-07-05 20:32:52 +00:00
}
}
2020-03-12 12:37:40 +00:00
return Theme : : get_default ( ) - > get_color ( p_name , p_type ) ;
2014-02-10 01:10:30 +00:00
}
2020-03-12 12:37:40 +00:00
int Control : : get_theme_constant ( const StringName & p_name , const StringName & p_type ) const {
2014-12-17 01:31:57 +00:00
2019-09-20 11:48:24 +00:00
if ( p_type = = StringName ( ) | | p_type = = get_class_name ( ) ) {
2017-03-05 15:44:50 +00:00
const int * constant = data . constant_override . getptr ( p_name ) ;
2014-12-17 01:31:57 +00:00
if ( constant )
return * constant ;
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
StringName type = p_type ? p_type : get_class_name ( ) ;
2014-02-10 01:10:30 +00:00
2020-03-12 12:37:40 +00:00
return get_constants ( data . theme_owner , data . theme_owner_window , p_name , type ) ;
}
int Control : : get_constants ( Control * p_theme_owner , Window * p_theme_owner_window , const StringName & p_name , const StringName & p_type ) {
2020-03-06 17:00:16 +00:00
int constant ;
2017-01-11 21:29:59 +00:00
2020-03-12 12:37:40 +00:00
if ( _find_theme_item ( p_theme_owner , p_theme_owner_window , constant , & Theme : : get_constant , & Theme : : has_constant , p_name , p_type ) ) {
2020-03-06 17:00:16 +00:00
return constant ;
2014-02-10 01:10:30 +00:00
}
2019-07-05 20:32:52 +00:00
if ( Theme : : get_project_default ( ) . is_valid ( ) ) {
2020-03-12 12:37:40 +00:00
if ( Theme : : get_project_default ( ) - > has_constant ( p_name , p_type ) ) {
return Theme : : get_project_default ( ) - > get_constant ( p_name , p_type ) ;
2019-07-05 20:32:52 +00:00
}
}
2020-03-12 12:37:40 +00:00
return Theme : : get_default ( ) - > get_constant ( p_name , p_type ) ;
2014-02-10 01:10:30 +00:00
}
2020-03-12 12:37:40 +00:00
bool Control : : has_theme_icon_override ( const StringName & p_name ) const {
2016-06-01 14:41:25 +00:00
2019-06-11 18:43:37 +00:00
const Ref < Texture2D > * tex = data . icon_override . getptr ( p_name ) ;
2019-06-26 13:08:25 +00:00
return tex ! = NULL ;
2016-06-01 14:41:25 +00:00
}
2020-03-12 12:37:40 +00:00
bool Control : : has_theme_shader_override ( const StringName & p_name ) const {
2016-06-01 14:41:25 +00:00
2017-03-05 15:44:50 +00:00
const Ref < Shader > * sdr = data . shader_override . getptr ( p_name ) ;
2019-06-26 13:08:25 +00:00
return sdr ! = NULL ;
2016-06-01 14:41:25 +00:00
}
2020-03-12 12:37:40 +00:00
bool Control : : has_theme_stylebox_override ( const StringName & p_name ) const {
2016-06-01 14:41:25 +00:00
2017-03-05 15:44:50 +00:00
const Ref < StyleBox > * style = data . style_override . getptr ( p_name ) ;
2019-06-26 13:08:25 +00:00
return style ! = NULL ;
2016-06-01 14:41:25 +00:00
}
2020-03-12 12:37:40 +00:00
bool Control : : has_theme_font_override ( const StringName & p_name ) const {
2016-06-01 14:41:25 +00:00
2017-03-05 15:44:50 +00:00
const Ref < Font > * font = data . font_override . getptr ( p_name ) ;
2019-06-26 13:08:25 +00:00
return font ! = NULL ;
2016-06-01 14:41:25 +00:00
}
2020-03-12 12:37:40 +00:00
bool Control : : has_theme_color_override ( const StringName & p_name ) const {
2016-06-01 14:41:25 +00:00
2017-03-05 15:44:50 +00:00
const Color * color = data . color_override . getptr ( p_name ) ;
2019-06-26 13:08:25 +00:00
return color ! = NULL ;
2016-06-01 14:41:25 +00:00
}
2020-03-12 12:37:40 +00:00
bool Control : : has_theme_constant_override ( const StringName & p_name ) const {
2016-06-01 14:41:25 +00:00
2017-03-05 15:44:50 +00:00
const int * constant = data . constant_override . getptr ( p_name ) ;
2019-06-26 13:08:25 +00:00
return constant ! = NULL ;
2016-06-01 14:41:25 +00:00
}
2014-02-10 01:10:30 +00:00
2020-03-12 12:37:40 +00:00
bool Control : : has_theme_icon ( const StringName & p_name , const StringName & p_type ) const {
2016-03-08 23:00:52 +00:00
2019-09-20 11:48:24 +00:00
if ( p_type = = StringName ( ) | | p_type = = get_class_name ( ) ) {
2020-03-12 12:37:40 +00:00
if ( has_theme_icon_override ( p_name ) )
2014-12-17 01:31:57 +00:00
return true ;
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
StringName type = p_type ? p_type : get_class_name ( ) ;
2014-02-10 01:10:30 +00:00
2020-03-12 12:37:40 +00:00
return has_icons ( data . theme_owner , data . theme_owner_window , p_name , type ) ;
}
bool Control : : has_icons ( Control * p_theme_owner , Window * p_theme_owner_window , const StringName & p_name , const StringName & p_type ) {
if ( _has_theme_item ( p_theme_owner , p_theme_owner_window , & Theme : : has_icon , p_name , p_type ) ) {
2020-03-06 17:00:16 +00:00
return true ;
2014-02-10 01:10:30 +00:00
}
2019-07-05 20:32:52 +00:00
if ( Theme : : get_project_default ( ) . is_valid ( ) ) {
2020-03-12 12:37:40 +00:00
if ( Theme : : get_project_default ( ) - > has_color ( p_name , p_type ) ) {
2019-07-05 20:32:52 +00:00
return true ;
}
}
2020-03-12 12:37:40 +00:00
return Theme : : get_default ( ) - > has_icon ( p_name , p_type ) ;
2015-12-20 21:21:53 +00:00
}
2020-03-12 12:37:40 +00:00
bool Control : : has_theme_shader ( const StringName & p_name , const StringName & p_type ) const {
2016-06-01 14:41:25 +00:00
2019-09-20 11:48:24 +00:00
if ( p_type = = StringName ( ) | | p_type = = get_class_name ( ) ) {
2020-03-12 12:37:40 +00:00
if ( has_theme_shader_override ( p_name ) )
2015-12-20 21:21:53 +00:00
return true ;
}
2017-03-05 15:44:50 +00:00
StringName type = p_type ? p_type : get_class_name ( ) ;
2015-12-20 21:21:53 +00:00
2020-03-12 12:37:40 +00:00
return has_shaders ( data . theme_owner , data . theme_owner_window , p_name , type ) ;
}
bool Control : : has_shaders ( Control * p_theme_owner , Window * p_theme_owner_window , const StringName & p_name , const StringName & p_type ) {
if ( _has_theme_item ( p_theme_owner , p_theme_owner_window , & Theme : : has_shader , p_name , p_type ) ) {
2020-03-06 17:00:16 +00:00
return true ;
2015-12-20 21:21:53 +00:00
}
2019-07-05 20:32:52 +00:00
if ( Theme : : get_project_default ( ) . is_valid ( ) ) {
2020-03-12 12:37:40 +00:00
if ( Theme : : get_project_default ( ) - > has_shader ( p_name , p_type ) ) {
2019-07-05 20:32:52 +00:00
return true ;
}
}
2020-03-12 12:37:40 +00:00
return Theme : : get_default ( ) - > has_shader ( p_name , p_type ) ;
2014-02-10 01:10:30 +00:00
}
2020-03-12 12:37:40 +00:00
bool Control : : has_theme_stylebox ( const StringName & p_name , const StringName & p_type ) const {
2016-03-08 23:00:52 +00:00
2019-09-20 11:48:24 +00:00
if ( p_type = = StringName ( ) | | p_type = = get_class_name ( ) ) {
2020-03-12 12:37:40 +00:00
if ( has_theme_stylebox_override ( p_name ) )
2014-12-17 01:31:57 +00:00
return true ;
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
StringName type = p_type ? p_type : get_class_name ( ) ;
2014-02-10 01:10:30 +00:00
2020-03-12 12:37:40 +00:00
return has_styleboxs ( data . theme_owner , data . theme_owner_window , p_name , type ) ;
}
bool Control : : has_styleboxs ( Control * p_theme_owner , Window * p_theme_owner_window , const StringName & p_name , const StringName & p_type ) {
if ( _has_theme_item ( p_theme_owner , p_theme_owner_window , & Theme : : has_stylebox , p_name , p_type ) ) {
2020-03-06 17:00:16 +00:00
return true ;
2014-02-10 01:10:30 +00:00
}
2019-07-05 20:32:52 +00:00
if ( Theme : : get_project_default ( ) . is_valid ( ) ) {
2020-03-12 12:37:40 +00:00
if ( Theme : : get_project_default ( ) - > has_stylebox ( p_name , p_type ) ) {
2019-07-05 20:32:52 +00:00
return true ;
}
}
2020-03-12 12:37:40 +00:00
return Theme : : get_default ( ) - > has_stylebox ( p_name , p_type ) ;
2014-02-10 01:10:30 +00:00
}
2020-03-12 12:37:40 +00:00
bool Control : : has_theme_font ( const StringName & p_name , const StringName & p_type ) const {
2016-03-08 23:00:52 +00:00
2019-09-20 11:48:24 +00:00
if ( p_type = = StringName ( ) | | p_type = = get_class_name ( ) ) {
2020-03-12 12:37:40 +00:00
if ( has_theme_font_override ( p_name ) )
2014-12-17 01:31:57 +00:00
return true ;
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
StringName type = p_type ? p_type : get_class_name ( ) ;
2014-02-10 01:10:30 +00:00
2020-03-12 12:37:40 +00:00
return has_fonts ( data . theme_owner , data . theme_owner_window , p_name , type ) ;
}
bool Control : : has_fonts ( Control * p_theme_owner , Window * p_theme_owner_window , const StringName & p_name , const StringName & p_type ) {
if ( _has_theme_item ( p_theme_owner , p_theme_owner_window , & Theme : : has_font , p_name , p_type ) ) {
2020-03-06 17:00:16 +00:00
return true ;
2014-02-10 01:10:30 +00:00
}
2019-07-05 20:32:52 +00:00
if ( Theme : : get_project_default ( ) . is_valid ( ) ) {
2020-03-12 12:37:40 +00:00
if ( Theme : : get_project_default ( ) - > has_font ( p_name , p_type ) ) {
2019-07-05 20:32:52 +00:00
return true ;
}
}
2020-03-12 12:37:40 +00:00
return Theme : : get_default ( ) - > has_font ( p_name , p_type ) ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2020-03-12 12:37:40 +00:00
bool Control : : has_theme_color ( const StringName & p_name , const StringName & p_type ) const {
2016-06-01 14:41:25 +00:00
2019-09-20 11:48:24 +00:00
if ( p_type = = StringName ( ) | | p_type = = get_class_name ( ) ) {
2020-03-12 12:37:40 +00:00
if ( has_theme_color_override ( p_name ) )
2014-12-17 01:31:57 +00:00
return true ;
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
StringName type = p_type ? p_type : get_class_name ( ) ;
2014-02-10 01:10:30 +00:00
2020-03-12 12:37:40 +00:00
return has_colors ( data . theme_owner , data . theme_owner_window , p_name , type ) ;
}
bool Control : : has_colors ( Control * p_theme_owner , Window * p_theme_owner_window , const StringName & p_name , const StringName & p_type ) {
if ( _has_theme_item ( p_theme_owner , p_theme_owner_window , & Theme : : has_color , p_name , p_type ) ) {
2020-03-06 17:00:16 +00:00
return true ;
2014-02-10 01:10:30 +00:00
}
2019-07-05 20:32:52 +00:00
if ( Theme : : get_project_default ( ) . is_valid ( ) ) {
2020-03-12 12:37:40 +00:00
if ( Theme : : get_project_default ( ) - > has_color ( p_name , p_type ) ) {
2019-07-05 20:32:52 +00:00
return true ;
}
}
2020-03-12 12:37:40 +00:00
return Theme : : get_default ( ) - > has_color ( p_name , p_type ) ;
2014-02-10 01:10:30 +00:00
}
2020-03-12 12:37:40 +00:00
bool Control : : has_theme_constant ( const StringName & p_name , const StringName & p_type ) const {
2014-12-17 01:31:57 +00:00
2019-09-20 11:48:24 +00:00
if ( p_type = = StringName ( ) | | p_type = = get_class_name ( ) ) {
2020-03-12 12:37:40 +00:00
if ( has_theme_constant_override ( p_name ) )
2014-12-17 01:31:57 +00:00
return true ;
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
StringName type = p_type ? p_type : get_class_name ( ) ;
2014-02-10 01:10:30 +00:00
2020-03-12 12:37:40 +00:00
return has_constants ( data . theme_owner , data . theme_owner_window , p_name , p_type ) ;
}
bool Control : : has_constants ( Control * p_theme_owner , Window * p_theme_owner_window , const StringName & p_name , const StringName & p_type ) {
if ( _has_theme_item ( p_theme_owner , p_theme_owner_window , & Theme : : has_constant , p_name , p_type ) ) {
2020-03-06 17:00:16 +00:00
return true ;
2014-02-10 01:10:30 +00:00
}
2019-07-05 20:32:52 +00:00
if ( Theme : : get_project_default ( ) . is_valid ( ) ) {
2020-03-12 12:37:40 +00:00
if ( Theme : : get_project_default ( ) - > has_constant ( p_name , p_type ) ) {
2019-07-05 20:32:52 +00:00
return true ;
}
}
2020-03-12 12:37:40 +00:00
return Theme : : get_default ( ) - > has_constant ( p_name , p_type ) ;
2014-02-10 01:10:30 +00:00
}
2018-05-05 14:59:00 +00:00
Rect2 Control : : get_parent_anchorable_rect ( ) const {
if ( ! is_inside_tree ( ) )
return Rect2 ( ) ;
2014-02-10 01:10:30 +00:00
2018-05-05 14:59:00 +00:00
Rect2 parent_rect ;
2014-02-10 01:10:30 +00:00
if ( data . parent_canvas_item ) {
2018-05-05 14:59:00 +00:00
parent_rect = data . parent_canvas_item - > get_anchorable_rect ( ) ;
2016-01-17 01:41:10 +00:00
} else {
2018-05-05 14:59:00 +00:00
parent_rect = get_viewport ( ) - > get_visible_rect ( ) ;
2016-03-08 23:00:52 +00:00
}
2017-06-12 19:18:17 +00:00
2018-05-05 14:59:00 +00:00
return parent_rect ;
}
Size2 Control : : get_parent_area_size ( ) const {
return get_parent_anchorable_rect ( ) . size ;
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
float margin_pos [ 4 ] ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < 4 ; i + + ) {
2014-02-10 01:10:30 +00:00
2018-05-05 14:59:00 +00:00
float area = parent_rect . size [ i & 1 ] ;
2017-07-06 07:16:27 +00:00
margin_pos [ i ] = data . margin [ i ] + ( data . anchor [ i ] * area ) ;
2014-02-10 01:10:30 +00:00
}
2017-07-05 21:01:26 +00:00
Point2 new_pos_cache = Point2 ( margin_pos [ 0 ] , margin_pos [ 1 ] ) ;
Size2 new_size_cache = Point2 ( margin_pos [ 2 ] , margin_pos [ 3 ] ) - new_pos_cache ;
2017-07-06 16:26:39 +00:00
2017-03-05 15:44:50 +00:00
Size2 minimum_size = get_combined_minimum_size ( ) ;
2014-02-10 01:10:30 +00:00
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
}
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
2016-08-31 02:44:14 +00:00
bool pos_changed = new_pos_cache ! = data . pos_cache ;
bool size_changed = new_size_cache ! = data . size_cache ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
data . pos_cache = new_pos_cache ;
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 ( size_changed ) {
notification ( NOTIFICATION_RESIZED ) ;
}
if ( pos_changed | | size_changed ) {
item_rect_changed ( size_changed ) ;
_change_notify_margins ( ) ;
_notify_transform ( ) ;
}
2016-08-31 02:44:14 +00:00
2018-07-04 12:29:29 +00:00
if ( pos_changed & & ! size_changed ) {
_update_canvas_item_transform ( ) ; //move because it won't be updated
}
2016-08-31 02:44:14 +00:00
}
2014-02-10 01:10:30 +00:00
}
2017-08-11 17:25:26 +00:00
void Control : : set_anchor ( Margin p_margin , float p_anchor , bool p_keep_margin , bool p_push_opposite_anchor ) {
2019-10-05 17:17:07 +00:00
ERR_FAIL_INDEX ( ( int ) p_margin , 4 ) ;
2018-05-05 14:59:00 +00:00
Rect2 parent_rect = get_parent_anchorable_rect ( ) ;
float parent_range = ( p_margin = = MARGIN_LEFT | | p_margin = = MARGIN_RIGHT ) ? parent_rect . size . x : parent_rect . size . y ;
2018-01-11 22:21:04 +00:00
float previous_margin_pos = data . margin [ p_margin ] + data . anchor [ p_margin ] * parent_range ;
float previous_opposite_margin_pos = data . margin [ ( p_margin + 2 ) % 4 ] + data . anchor [ ( p_margin + 2 ) % 4 ] * parent_range ;
2019-03-31 16:53:24 +00:00
data . anchor [ p_margin ] = p_anchor ;
2017-08-11 17:25:26 +00:00
if ( ( ( p_margin = = MARGIN_LEFT | | p_margin = = MARGIN_TOP ) & & data . anchor [ p_margin ] > data . anchor [ ( p_margin + 2 ) % 4 ] ) | |
( ( p_margin = = MARGIN_RIGHT | | p_margin = = MARGIN_BOTTOM ) & & data . anchor [ p_margin ] < data . anchor [ ( p_margin + 2 ) % 4 ] ) ) {
if ( p_push_opposite_anchor ) {
data . anchor [ ( p_margin + 2 ) % 4 ] = data . anchor [ p_margin ] ;
2017-07-06 07:16:27 +00:00
} else {
2017-08-11 17:25:26 +00:00
data . anchor [ p_margin ] = data . anchor [ ( p_margin + 2 ) % 4 ] ;
}
}
2018-01-11 22:21:04 +00:00
if ( ! p_keep_margin ) {
2018-05-05 14:59:00 +00:00
data . margin [ p_margin ] = previous_margin_pos - data . anchor [ p_margin ] * parent_range ;
2018-01-11 22:21:04 +00:00
if ( p_push_opposite_anchor ) {
2018-05-05 14:59:00 +00:00
data . margin [ ( p_margin + 2 ) % 4 ] = previous_opposite_margin_pos - data . anchor [ ( p_margin + 2 ) % 4 ] * parent_range ;
2017-07-06 07:16:27 +00:00
}
2014-02-10 01:10:30 +00:00
}
2018-01-11 22:21:04 +00:00
if ( is_inside_tree ( ) ) {
_size_changed ( ) ;
}
2017-07-10 22:14:22 +00:00
update ( ) ;
2019-03-19 17:37:28 +00:00
_change_notify ( " anchor_left " ) ;
_change_notify ( " anchor_right " ) ;
_change_notify ( " anchor_top " ) ;
_change_notify ( " anchor_bottom " ) ;
2014-02-10 01:10:30 +00:00
}
2017-07-06 07:16:27 +00:00
void Control : : _set_anchor ( Margin p_margin , float p_anchor ) {
2019-03-31 16:53:24 +00:00
set_anchor ( p_margin , p_anchor ) ;
2016-03-09 16:59:35 +00:00
}
2017-08-11 17:25:26 +00:00
void Control : : set_anchor_and_margin ( Margin p_margin , float p_anchor , float p_pos , bool p_push_opposite_anchor ) {
2014-02-10 01:10:30 +00:00
2017-08-11 17:25:26 +00:00
set_anchor ( p_margin , p_anchor , false , p_push_opposite_anchor ) ;
2017-03-05 15:44:50 +00:00
set_margin ( p_margin , p_pos ) ;
2014-02-10 01:10:30 +00:00
}
2019-03-31 16:53:24 +00:00
void Control : : set_anchors_preset ( LayoutPreset p_preset , bool p_keep_margins ) {
2019-10-05 17:17:07 +00:00
ERR_FAIL_INDEX ( ( int ) p_preset , 16 ) ;
2017-08-11 16:16:28 +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_WIDE :
2019-03-31 16:53:24 +00:00
set_anchor ( MARGIN_LEFT , ANCHOR_BEGIN , p_keep_margins ) ;
2017-08-11 16:16:28 +00:00
break ;
case PRESET_CENTER_TOP :
case PRESET_CENTER_BOTTOM :
case PRESET_CENTER :
case PRESET_VCENTER_WIDE :
2019-03-31 16:53:24 +00:00
set_anchor ( MARGIN_LEFT , 0.5 , p_keep_margins ) ;
2017-08-11 16:16:28 +00:00
break ;
case PRESET_TOP_RIGHT :
case PRESET_BOTTOM_RIGHT :
case PRESET_CENTER_RIGHT :
case PRESET_RIGHT_WIDE :
2019-03-31 16:53:24 +00:00
set_anchor ( MARGIN_LEFT , ANCHOR_END , p_keep_margins ) ;
2017-08-11 16:16:28 +00:00
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_WIDE :
2019-03-31 16:53:24 +00:00
set_anchor ( MARGIN_TOP , ANCHOR_BEGIN , p_keep_margins ) ;
2017-08-11 16:16:28 +00:00
break ;
case PRESET_CENTER_LEFT :
case PRESET_CENTER_RIGHT :
case PRESET_CENTER :
case PRESET_HCENTER_WIDE :
2019-03-31 16:53:24 +00:00
set_anchor ( MARGIN_TOP , 0.5 , p_keep_margins ) ;
2017-08-11 16:16:28 +00:00
break ;
case PRESET_BOTTOM_LEFT :
case PRESET_BOTTOM_RIGHT :
case PRESET_CENTER_BOTTOM :
case PRESET_BOTTOM_WIDE :
2019-03-31 16:53:24 +00:00
set_anchor ( MARGIN_TOP , ANCHOR_END , p_keep_margins ) ;
2017-08-11 16:16:28 +00:00
break ;
}
// Right
switch ( p_preset ) {
case PRESET_TOP_LEFT :
case PRESET_BOTTOM_LEFT :
case PRESET_CENTER_LEFT :
case PRESET_LEFT_WIDE :
2019-03-31 16:53:24 +00:00
set_anchor ( MARGIN_RIGHT , ANCHOR_BEGIN , p_keep_margins ) ;
2017-08-11 16:16:28 +00:00
break ;
case PRESET_CENTER_TOP :
case PRESET_CENTER_BOTTOM :
case PRESET_CENTER :
case PRESET_VCENTER_WIDE :
2019-03-31 16:53:24 +00:00
set_anchor ( MARGIN_RIGHT , 0.5 , p_keep_margins ) ;
2017-08-11 16:16:28 +00:00
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_WIDE :
2019-03-31 16:53:24 +00:00
set_anchor ( MARGIN_RIGHT , ANCHOR_END , p_keep_margins ) ;
2017-08-11 16:16:28 +00:00
break ;
}
// Bottom
switch ( p_preset ) {
case PRESET_TOP_LEFT :
case PRESET_TOP_RIGHT :
case PRESET_CENTER_TOP :
case PRESET_TOP_WIDE :
2019-03-31 16:53:24 +00:00
set_anchor ( MARGIN_BOTTOM , ANCHOR_BEGIN , p_keep_margins ) ;
2017-08-11 16:16:28 +00:00
break ;
case PRESET_CENTER_LEFT :
case PRESET_CENTER_RIGHT :
case PRESET_CENTER :
case PRESET_HCENTER_WIDE :
2019-03-31 16:53:24 +00:00
set_anchor ( MARGIN_BOTTOM , 0.5 , p_keep_margins ) ;
2017-08-11 16:16:28 +00:00
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_WIDE :
2019-03-31 16:53:24 +00:00
set_anchor ( MARGIN_BOTTOM , ANCHOR_END , p_keep_margins ) ;
2017-08-11 16:16:28 +00:00
break ;
}
}
2017-09-19 20:39:19 +00:00
void Control : : set_margins_preset ( LayoutPreset p_preset , LayoutPresetMode p_resize_mode , int p_margin ) {
2019-10-05 17:17:07 +00:00
ERR_FAIL_INDEX ( ( int ) p_preset , 16 ) ;
ERR_FAIL_INDEX ( ( int ) p_resize_mode , 4 ) ;
2017-09-26 22:31:05 +00:00
// Calculate the size if the node is not resized
2017-09-19 20:39:19 +00:00
Size2 min_size = get_minimum_size ( ) ;
Size2 new_size = get_size ( ) ;
2017-09-26 22:31:05 +00:00
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 ;
}
2017-09-19 20:39:19 +00:00
2018-05-05 14:59:00 +00:00
Rect2 parent_rect = get_parent_anchorable_rect ( ) ;
2017-09-26 22:31:05 +00:00
//Left
2017-09-19 20:39:19 +00:00
switch ( p_preset ) {
2017-09-26 22:31:05 +00:00
case PRESET_TOP_LEFT :
case PRESET_BOTTOM_LEFT :
case PRESET_CENTER_LEFT :
2017-09-19 20:39:19 +00:00
case PRESET_TOP_WIDE :
case PRESET_BOTTOM_WIDE :
2017-09-26 22:31:05 +00:00
case PRESET_LEFT_WIDE :
2017-09-19 20:39:19 +00:00
case PRESET_HCENTER_WIDE :
case PRESET_WIDE :
2018-05-05 14:59:00 +00:00
data . margin [ 0 ] = parent_rect . size . x * ( 0.0 - data . anchor [ 0 ] ) + p_margin + parent_rect . position . x ;
2017-09-19 20:39:19 +00:00
break ;
2017-09-26 22:31:05 +00:00
case PRESET_CENTER_TOP :
case PRESET_CENTER_BOTTOM :
case PRESET_CENTER :
case PRESET_VCENTER_WIDE :
2018-05-05 14:59:00 +00:00
data . margin [ 0 ] = parent_rect . size . x * ( 0.5 - data . anchor [ 0 ] ) - new_size . x / 2 + parent_rect . position . x ;
2017-09-26 22:31:05 +00:00
break ;
case PRESET_TOP_RIGHT :
case PRESET_BOTTOM_RIGHT :
case PRESET_CENTER_RIGHT :
case PRESET_RIGHT_WIDE :
2018-05-05 14:59:00 +00:00
data . margin [ 0 ] = parent_rect . size . x * ( 1.0 - data . anchor [ 0 ] ) - new_size . x - p_margin + parent_rect . position . x ;
2017-09-19 20:39:19 +00:00
break ;
}
2017-09-26 22:31:05 +00:00
// Top
2017-09-19 20:39:19 +00:00
switch ( p_preset ) {
2017-09-26 22:31:05 +00:00
case PRESET_TOP_LEFT :
case PRESET_TOP_RIGHT :
case PRESET_CENTER_TOP :
2017-09-19 20:39:19 +00:00
case PRESET_LEFT_WIDE :
case PRESET_RIGHT_WIDE :
2017-09-26 22:31:05 +00:00
case PRESET_TOP_WIDE :
2017-09-19 20:39:19 +00:00
case PRESET_VCENTER_WIDE :
case PRESET_WIDE :
2018-05-05 14:59:00 +00:00
data . margin [ 1 ] = parent_rect . size . y * ( 0.0 - data . anchor [ 1 ] ) + p_margin + parent_rect . position . y ;
2017-09-19 20:39:19 +00:00
break ;
2017-09-26 22:31:05 +00:00
case PRESET_CENTER_LEFT :
case PRESET_CENTER_RIGHT :
case PRESET_CENTER :
case PRESET_HCENTER_WIDE :
2018-05-05 14:59:00 +00:00
data . margin [ 1 ] = parent_rect . size . y * ( 0.5 - data . anchor [ 1 ] ) - new_size . y / 2 + parent_rect . position . y ;
2017-09-26 22:31:05 +00:00
break ;
case PRESET_BOTTOM_LEFT :
case PRESET_BOTTOM_RIGHT :
case PRESET_CENTER_BOTTOM :
case PRESET_BOTTOM_WIDE :
2018-05-05 14:59:00 +00:00
data . margin [ 1 ] = parent_rect . size . y * ( 1.0 - data . anchor [ 1 ] ) - new_size . y - p_margin + parent_rect . position . y ;
2017-09-19 20:39:19 +00:00
break ;
}
2017-09-26 22:31:05 +00:00
// Right
2017-09-19 20:39:19 +00:00
switch ( p_preset ) {
case PRESET_TOP_LEFT :
case PRESET_BOTTOM_LEFT :
case PRESET_CENTER_LEFT :
case PRESET_LEFT_WIDE :
2018-05-05 14:59:00 +00:00
data . margin [ 2 ] = parent_rect . size . x * ( 0.0 - data . anchor [ 2 ] ) + new_size . x + p_margin + parent_rect . position . x ;
2017-09-19 20:39:19 +00:00
break ;
case PRESET_CENTER_TOP :
case PRESET_CENTER_BOTTOM :
case PRESET_CENTER :
case PRESET_VCENTER_WIDE :
2018-05-05 14:59:00 +00:00
data . margin [ 2 ] = parent_rect . size . x * ( 0.5 - data . anchor [ 2 ] ) + new_size . x / 2 + parent_rect . position . x ;
2017-09-19 20:39:19 +00:00
break ;
case PRESET_TOP_RIGHT :
case PRESET_BOTTOM_RIGHT :
case PRESET_CENTER_RIGHT :
2017-09-26 22:31:05 +00:00
case PRESET_TOP_WIDE :
2017-09-19 20:39:19 +00:00
case PRESET_RIGHT_WIDE :
2017-09-26 22:31:05 +00:00
case PRESET_BOTTOM_WIDE :
case PRESET_HCENTER_WIDE :
case PRESET_WIDE :
2018-05-05 14:59:00 +00:00
data . margin [ 2 ] = parent_rect . size . x * ( 1.0 - data . anchor [ 2 ] ) - p_margin + parent_rect . position . x ;
2017-09-19 20:39:19 +00:00
break ;
}
2017-09-26 22:31:05 +00:00
// Bottom
2017-09-19 20:39:19 +00:00
switch ( p_preset ) {
case PRESET_TOP_LEFT :
case PRESET_TOP_RIGHT :
case PRESET_CENTER_TOP :
case PRESET_TOP_WIDE :
2018-05-05 14:59:00 +00:00
data . margin [ 3 ] = parent_rect . size . y * ( 0.0 - data . anchor [ 3 ] ) + new_size . y + p_margin + parent_rect . position . y ;
2017-09-19 20:39:19 +00:00
break ;
case PRESET_CENTER_LEFT :
case PRESET_CENTER_RIGHT :
case PRESET_CENTER :
case PRESET_HCENTER_WIDE :
2018-05-05 14:59:00 +00:00
data . margin [ 3 ] = parent_rect . size . y * ( 0.5 - data . anchor [ 3 ] ) + new_size . y / 2 + parent_rect . position . y ;
2017-09-19 20:39:19 +00:00
break ;
case PRESET_BOTTOM_LEFT :
case PRESET_BOTTOM_RIGHT :
case PRESET_CENTER_BOTTOM :
2017-09-26 22:31:05 +00:00
case PRESET_LEFT_WIDE :
case PRESET_RIGHT_WIDE :
2017-09-19 20:39:19 +00:00
case PRESET_BOTTOM_WIDE :
2017-09-26 22:31:05 +00:00
case PRESET_VCENTER_WIDE :
case PRESET_WIDE :
2018-05-05 14:59:00 +00:00
data . margin [ 3 ] = parent_rect . size . y * ( 1.0 - data . anchor [ 3 ] ) - p_margin + parent_rect . position . y ;
2017-09-19 20:39:19 +00:00
break ;
}
2017-09-26 22:31:05 +00:00
_size_changed ( ) ;
2017-09-19 20:39:19 +00:00
}
void Control : : set_anchors_and_margins_preset ( LayoutPreset p_preset , LayoutPresetMode p_resize_mode , int p_margin ) {
set_anchors_preset ( p_preset ) ;
set_margins_preset ( p_preset , p_resize_mode , p_margin ) ;
}
2017-07-06 07:16:27 +00:00
float Control : : get_anchor ( Margin p_margin ) const {
2016-03-08 23:00:52 +00:00
2019-10-05 17:17:07 +00:00
ERR_FAIL_INDEX_V ( int ( p_margin ) , 4 , 0.0 ) ;
2016-03-08 23:00:52 +00:00
return data . anchor [ p_margin ] ;
2014-02-10 01:10:30 +00:00
}
void Control : : _change_notify_margins ( ) {
// this avoids sending the whole object data again on a change
2017-04-01 04:07:35 +00:00
_change_notify ( " margin_left " ) ;
_change_notify ( " margin_top " ) ;
_change_notify ( " margin_right " ) ;
_change_notify ( " margin_bottom " ) ;
2017-05-28 13:38:22 +00:00
_change_notify ( " rect_position " ) ;
2017-04-01 04:07:35 +00:00
_change_notify ( " rect_size " ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void Control : : set_margin ( Margin p_margin , float p_value ) {
2014-02-10 01:10:30 +00:00
2019-10-05 17:17:07 +00:00
ERR_FAIL_INDEX ( ( int ) p_margin , 4 ) ;
2017-03-05 15:44:50 +00:00
data . margin [ p_margin ] = p_value ;
2014-02-10 01:10:30 +00:00
_size_changed ( ) ;
}
2017-03-05 15:44:50 +00:00
void Control : : set_begin ( const Size2 & p_point ) {
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
data . margin [ 0 ] = p_point . x ;
data . margin [ 1 ] = p_point . y ;
2014-02-10 01:10:30 +00:00
_size_changed ( ) ;
}
2017-03-05 15:44:50 +00:00
void Control : : set_end ( const Size2 & p_point ) {
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
data . margin [ 2 ] = p_point . x ;
data . margin [ 3 ] = p_point . y ;
2014-02-10 01:10:30 +00:00
_size_changed ( ) ;
}
float Control : : get_margin ( Margin p_margin ) const {
2016-03-08 23:00:52 +00:00
2019-10-05 17:17:07 +00:00
ERR_FAIL_INDEX_V ( ( int ) p_margin , 4 , 0 ) ;
2014-02-10 01:10:30 +00:00
return data . margin [ p_margin ] ;
}
Size2 Control : : get_begin ( ) const {
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
return Size2 ( data . margin [ 0 ] , data . margin [ 1 ] ) ;
2014-02-10 01:10:30 +00:00
}
Size2 Control : : get_end ( ) const {
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
return Size2 ( data . margin [ 2 ] , data . margin [ 3 ] ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-29 15:29:38 +00:00
Point2 Control : : get_global_position ( ) const {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
return get_global_transform ( ) . get_origin ( ) ;
}
2020-03-12 12:37:40 +00:00
Point2 Control : : get_screen_position ( ) const {
ERR_FAIL_COND_V ( ! is_inside_tree ( ) , Point2 ( ) ) ;
Point2 global_pos = get_global_position ( ) ;
Window * w = Object : : cast_to < Window > ( get_viewport ( ) ) ;
2020-03-14 16:06:39 +00:00
if ( w & & ! w - > is_embedding_subwindows ( ) ) {
2020-03-12 12:37:40 +00:00
global_pos + = w - > get_position ( ) ;
}
return global_pos ;
}
2019-03-31 16:53:24 +00:00
void Control : : _set_global_position ( const Point2 & p_point ) {
set_global_position ( p_point ) ;
}
void Control : : set_global_position ( const Point2 & p_point , bool p_keep_margins ) {
2016-03-08 23:00:52 +00:00
2017-01-11 03:52:51 +00:00
Transform2D inv ;
2014-02-10 01:10:30 +00:00
if ( data . parent_canvas_item ) {
inv = data . parent_canvas_item - > get_global_transform ( ) . affine_inverse ( ) ;
}
2019-03-31 16:53:24 +00:00
set_position ( inv . xform ( p_point ) , p_keep_margins ) ;
2014-02-10 01:10:30 +00:00
}
2019-03-31 16:53:24 +00:00
void Control : : _compute_anchors ( Rect2 p_rect , const float p_margins [ 4 ] , float ( & r_anchors ) [ 4 ] ) {
Size2 parent_rect_size = get_parent_anchorable_rect ( ) . size ;
2019-06-04 19:58:21 +00:00
ERR_FAIL_COND ( parent_rect_size . x = = 0.0 ) ;
ERR_FAIL_COND ( parent_rect_size . y = = 0.0 ) ;
2019-03-31 16:53:24 +00:00
r_anchors [ 0 ] = ( p_rect . position . x - p_margins [ 0 ] ) / parent_rect_size . x ;
r_anchors [ 1 ] = ( p_rect . position . y - p_margins [ 1 ] ) / parent_rect_size . y ;
r_anchors [ 2 ] = ( p_rect . position . x + p_rect . size . x - p_margins [ 2 ] ) / parent_rect_size . x ;
r_anchors [ 3 ] = ( p_rect . position . y + p_rect . size . y - p_margins [ 3 ] ) / parent_rect_size . y ;
}
2018-05-05 14:59:00 +00:00
void Control : : _compute_margins ( Rect2 p_rect , const float p_anchors [ 4 ] , float ( & r_margins ) [ 4 ] ) {
2016-03-08 23:00:52 +00:00
2018-05-05 14:59:00 +00:00
Size2 parent_rect_size = get_parent_anchorable_rect ( ) . size ;
2018-09-25 18:14:40 +00:00
r_margins [ 0 ] = p_rect . position . x - ( p_anchors [ 0 ] * parent_rect_size . x ) ;
r_margins [ 1 ] = p_rect . position . y - ( p_anchors [ 1 ] * parent_rect_size . y ) ;
r_margins [ 2 ] = p_rect . position . x + p_rect . size . x - ( p_anchors [ 2 ] * parent_rect_size . x ) ;
r_margins [ 3 ] = p_rect . position . y + p_rect . size . y - ( p_anchors [ 3 ] * parent_rect_size . y ) ;
2018-05-05 14:59:00 +00:00
}
2016-03-08 23:00:52 +00:00
2019-03-31 16:53:24 +00:00
void Control : : _set_position ( const Size2 & p_point ) {
set_position ( p_point ) ;
}
2014-02-10 01:10:30 +00:00
2019-03-31 16:53:24 +00:00
void Control : : set_position ( const Size2 & p_point , bool p_keep_margins ) {
if ( p_keep_margins ) {
_compute_anchors ( Rect2 ( p_point , data . size_cache ) , data . margin , data . anchor ) ;
_change_notify ( " anchor_left " ) ;
_change_notify ( " anchor_right " ) ;
_change_notify ( " anchor_top " ) ;
_change_notify ( " anchor_bottom " ) ;
} else {
_compute_margins ( Rect2 ( p_point , data . size_cache ) , data . anchor , data . margin ) ;
}
2014-02-10 01:10:30 +00:00
_size_changed ( ) ;
}
2019-03-31 16:53:24 +00:00
void Control : : _set_size ( const Size2 & p_size ) {
set_size ( p_size ) ;
}
void Control : : set_size ( const Size2 & p_size , bool p_keep_margins ) {
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +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 ;
2016-03-08 23:00:52 +00:00
2019-03-31 16:53:24 +00:00
if ( p_keep_margins ) {
_compute_anchors ( Rect2 ( data . pos_cache , new_size ) , data . margin , data . anchor ) ;
_change_notify ( " anchor_left " ) ;
_change_notify ( " anchor_right " ) ;
_change_notify ( " anchor_top " ) ;
_change_notify ( " anchor_bottom " ) ;
} else {
_compute_margins ( Rect2 ( data . pos_cache , new_size ) , data . anchor , data . margin ) ;
}
2014-02-10 01:10:30 +00:00
_size_changed ( ) ;
}
2017-03-29 15:29:38 +00:00
Size2 Control : : get_position ( ) const {
2014-02-10 01:10:30 +00:00
return data . pos_cache ;
}
Size2 Control : : get_size ( ) const {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
return data . size_cache ;
}
Rect2 Control : : get_global_rect ( ) const {
2016-03-08 23:00:52 +00:00
2017-03-29 15:29:38 +00:00
return Rect2 ( get_global_position ( ) , get_size ( ) ) ;
2014-02-10 01:10:30 +00:00
}
2020-03-12 12:37:40 +00:00
Rect2 Control : : get_screen_rect ( ) const {
ERR_FAIL_COND_V ( ! is_inside_tree ( ) , Rect2 ( ) ) ;
Rect2 r ( get_global_position ( ) , get_size ( ) ) ;
Window * w = Object : : cast_to < Window > ( get_viewport ( ) ) ;
2020-03-14 16:06:39 +00:00
if ( w & & ! w - > is_embedding_subwindows ( ) ) {
2020-03-12 12:37:40 +00:00
r . position + = w - > get_position ( ) ;
}
return r ;
}
2014-02-10 01:10:30 +00:00
Rect2 Control : : get_window_rect ( ) const {
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( ! is_inside_tree ( ) , Rect2 ( ) ) ;
2014-02-10 01:10:30 +00:00
Rect2 gr = get_global_rect ( ) ;
2017-06-03 22:25:13 +00:00
gr . position + = get_viewport ( ) - > get_visible_rect ( ) . position ;
2014-02-10 01:10:30 +00:00
return gr ;
}
Rect2 Control : : get_rect ( ) const {
2016-03-08 23:00:52 +00:00
2017-03-29 15:29:38 +00:00
return Rect2 ( get_position ( ) , get_size ( ) ) ;
2014-02-10 01:10:30 +00:00
}
2018-05-05 14:59:00 +00:00
Rect2 Control : : get_anchorable_rect ( ) const {
return Rect2 ( Point2 ( ) , get_size ( ) ) ;
}
2020-03-12 12:37:40 +00:00
void Control : : add_theme_icon_override ( const StringName & p_name , const Ref < Texture2D > & p_icon ) {
2014-02-10 01:10:30 +00:00
2019-02-25 15:13:25 +00:00
if ( data . icon_override . has ( p_name ) ) {
2020-02-21 17:28:45 +00:00
data . icon_override [ p_name ] - > disconnect ( " changed " , callable_mp ( this , & Control : : _override_changed ) ) ;
2019-02-25 15:13:25 +00:00
}
2019-05-20 17:32:31 +00:00
// clear if "null" is passed instead of a icon
if ( p_icon . is_null ( ) ) {
data . icon_override . erase ( p_name ) ;
} else {
data . icon_override [ p_name ] = p_icon ;
if ( data . icon_override [ p_name ] . is_valid ( ) ) {
2020-02-21 17:28:45 +00:00
data . icon_override [ p_name ] - > connect ( " changed " , callable_mp ( this , & Control : : _override_changed ) , Vector < Variant > ( ) , CONNECT_REFERENCE_COUNTED ) ;
2019-05-20 17:32:31 +00:00
}
2019-02-25 15:13:25 +00:00
}
2014-02-10 01:10:30 +00:00
notification ( NOTIFICATION_THEME_CHANGED ) ;
2015-12-20 21:21:53 +00:00
}
2014-02-10 01:10:30 +00:00
2020-03-12 12:37:40 +00:00
void Control : : add_theme_shader_override ( const StringName & p_name , const Ref < Shader > & p_shader ) {
2019-05-20 17:32:31 +00:00
2019-02-25 15:13:25 +00:00
if ( data . shader_override . has ( p_name ) ) {
2020-02-21 17:28:45 +00:00
data . shader_override [ p_name ] - > disconnect ( " changed " , callable_mp ( this , & Control : : _override_changed ) ) ;
2019-02-25 15:13:25 +00:00
}
2019-05-20 17:32:31 +00:00
// clear if "null" is passed instead of a shader
if ( p_shader . is_null ( ) ) {
data . shader_override . erase ( p_name ) ;
} else {
data . shader_override [ p_name ] = p_shader ;
if ( data . shader_override [ p_name ] . is_valid ( ) ) {
2020-02-21 17:28:45 +00:00
data . shader_override [ p_name ] - > connect ( " changed " , callable_mp ( this , & Control : : _override_changed ) , Vector < Variant > ( ) , CONNECT_REFERENCE_COUNTED ) ;
2019-05-20 17:32:31 +00:00
}
2019-02-25 15:13:25 +00:00
}
2015-12-20 21:21:53 +00:00
notification ( NOTIFICATION_THEME_CHANGED ) ;
2014-02-10 01:10:30 +00:00
}
2020-03-12 12:37:40 +00:00
void Control : : add_theme_style_override ( const StringName & p_name , const Ref < StyleBox > & p_style ) {
2014-02-10 01:10:30 +00:00
2019-02-25 15:13:25 +00:00
if ( data . style_override . has ( p_name ) ) {
2020-02-21 17:28:45 +00:00
data . style_override [ p_name ] - > disconnect ( " changed " , callable_mp ( this , & Control : : _override_changed ) ) ;
2019-02-25 15:13:25 +00:00
}
2019-05-20 17:32:31 +00:00
// clear if "null" is passed instead of a style
if ( p_style . is_null ( ) ) {
data . style_override . erase ( p_name ) ;
} else {
data . style_override [ p_name ] = p_style ;
if ( data . style_override [ p_name ] . is_valid ( ) ) {
2020-02-21 17:28:45 +00:00
data . style_override [ p_name ] - > connect ( " changed " , callable_mp ( this , & Control : : _override_changed ) , Vector < Variant > ( ) , CONNECT_REFERENCE_COUNTED ) ;
2019-05-20 17:32:31 +00:00
}
}
2014-02-10 01:10:30 +00:00
notification ( NOTIFICATION_THEME_CHANGED ) ;
}
2020-03-12 12:37:40 +00:00
void Control : : add_theme_font_override ( const StringName & p_name , const Ref < Font > & p_font ) {
2014-02-10 01:10:30 +00:00
2016-06-17 19:00:27 +00:00
if ( data . font_override . has ( p_name ) ) {
2020-02-21 17:28:45 +00:00
data . font_override [ p_name ] - > disconnect ( " changed " , callable_mp ( this , & Control : : _override_changed ) ) ;
2016-06-17 19:00:27 +00:00
}
2019-05-20 17:32:31 +00:00
// clear if "null" is passed instead of a font
if ( p_font . is_null ( ) ) {
data . font_override . erase ( p_name ) ;
} else {
data . font_override [ p_name ] = p_font ;
if ( data . font_override [ p_name ] . is_valid ( ) ) {
2020-02-21 17:28:45 +00:00
data . font_override [ p_name ] - > connect ( " changed " , callable_mp ( this , & Control : : _override_changed ) , Vector < Variant > ( ) , CONNECT_REFERENCE_COUNTED ) ;
2019-05-20 17:32:31 +00:00
}
}
2014-02-10 01:10:30 +00:00
notification ( NOTIFICATION_THEME_CHANGED ) ;
}
2020-03-12 12:37:40 +00:00
void Control : : add_theme_color_override ( const StringName & p_name , const Color & p_color ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
data . color_override [ p_name ] = p_color ;
2014-02-10 01:10:30 +00:00
notification ( NOTIFICATION_THEME_CHANGED ) ;
}
2020-03-12 12:37:40 +00:00
void Control : : add_theme_constant_override ( const StringName & p_name , int p_constant ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
data . constant_override [ p_name ] = p_constant ;
2014-02-10 01:10:30 +00:00
notification ( NOTIFICATION_THEME_CHANGED ) ;
}
void Control : : set_focus_mode ( FocusMode p_focus_mode ) {
2019-10-05 17:17:07 +00:00
ERR_FAIL_INDEX ( ( int ) p_focus_mode , 3 ) ;
2017-03-05 15:44:50 +00:00
if ( is_inside_tree ( ) & & p_focus_mode = = FOCUS_NONE & & data . focus_mode ! = FOCUS_NONE & & has_focus ( ) )
2014-02-10 01:10:30 +00:00
release_focus ( ) ;
2017-03-05 15:44:50 +00:00
data . focus_mode = p_focus_mode ;
2014-02-10 01:10:30 +00:00
}
static Control * _next_control ( Control * p_from ) {
if ( p_from - > is_set_as_toplevel ( ) )
return NULL ; // can't go above
2017-08-24 20:58:51 +00:00
Control * parent = Object : : cast_to < Control > ( p_from - > get_parent ( ) ) ;
2014-02-10 01:10:30 +00:00
if ( ! parent ) {
return NULL ;
}
int next = p_from - > get_position_in_parent ( ) ;
2017-03-05 15:44:50 +00:00
ERR_FAIL_INDEX_V ( next , parent - > get_child_count ( ) , NULL ) ;
for ( int i = ( next + 1 ) ; i < parent - > get_child_count ( ) ; i + + ) {
2014-02-10 01:10:30 +00:00
2017-08-24 20:58:51 +00:00
Control * c = Object : : cast_to < Control > ( parent - > get_child ( i ) ) ;
2017-01-13 13:45:50 +00:00
if ( ! c | | ! c - > is_visible_in_tree ( ) | | c - > is_set_as_toplevel ( ) )
2014-02-10 01:10:30 +00:00
continue ;
return c ;
}
//no next in parent, try the same in parent
return _next_control ( parent ) ;
}
Control * Control : : find_next_valid_focus ( ) const {
2017-03-05 15:44:50 +00:00
Control * from = const_cast < Control * > ( this ) ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
while ( true ) {
2016-03-08 23:00:52 +00:00
2017-11-16 09:45:52 +00:00
// If the focus property is manually overwritten, attempt to use it.
if ( ! data . focus_next . is_empty ( ) ) {
Node * n = get_node ( data . focus_next ) ;
2019-12-16 00:33:25 +00:00
Control * c ;
2017-11-16 09:45:52 +00:00
if ( n ) {
2019-12-16 00:33:25 +00:00
c = Object : : cast_to < Control > ( n ) ;
ERR_FAIL_COND_V_MSG ( ! c , NULL , " Next focus node is not a control: " + n - > get_name ( ) + " . " ) ;
2017-11-16 09:45:52 +00:00
} else {
return NULL ;
}
2019-12-16 00:33:25 +00:00
if ( c - > is_visible ( ) & & c - > get_focus_mode ( ) ! = FOCUS_NONE )
return c ;
2017-11-16 09:45:52 +00:00
}
2014-02-10 01:10:30 +00:00
// find next child
2017-03-05 15:44:50 +00:00
Control * next_child = NULL ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < from - > get_child_count ( ) ; i + + ) {
2014-02-10 01:10:30 +00:00
2017-08-24 20:58:51 +00:00
Control * c = Object : : cast_to < Control > ( from - > get_child ( i ) ) ;
2017-01-13 13:45:50 +00:00
if ( ! c | | ! c - > is_visible_in_tree ( ) | | c - > is_set_as_toplevel ( ) ) {
2014-02-10 01:10:30 +00:00
continue ;
}
2017-03-05 15:44:50 +00:00
next_child = c ;
2014-02-10 01:10:30 +00:00
break ;
}
2019-06-26 13:08:25 +00:00
if ( ! next_child ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
next_child = _next_control ( from ) ;
2014-02-10 01:10:30 +00:00
if ( ! next_child ) { //nothing else.. go up and find either window or subwindow
2017-03-05 15:44:50 +00:00
next_child = const_cast < Control * > ( this ) ;
while ( next_child & & ! next_child - > is_set_as_toplevel ( ) ) {
2017-08-24 20:58:51 +00:00
next_child = cast_to < Control > ( next_child - > get_parent ( ) ) ;
2014-02-10 01:10:30 +00:00
}
if ( ! next_child ) {
2016-01-17 01:41:10 +00:00
2017-03-05 15:44:50 +00:00
next_child = const_cast < Control * > ( this ) ;
while ( next_child ) {
2016-01-17 01:41:10 +00:00
2020-03-14 16:06:39 +00:00
if ( next_child - > data . RI )
2016-01-17 01:41:10 +00:00
break ;
2017-03-05 15:44:50 +00:00
next_child = next_child - > get_parent_control ( ) ;
2016-01-17 01:41:10 +00:00
}
2014-02-10 01:10:30 +00:00
}
}
}
2017-03-05 15:44:50 +00:00
if ( next_child = = this ) // no next control->
return ( get_focus_mode ( ) = = FOCUS_ALL ) ? next_child : NULL ;
2016-10-05 06:56:58 +00:00
if ( next_child ) {
2017-03-05 15:44:50 +00:00
if ( next_child - > get_focus_mode ( ) = = FOCUS_ALL )
2016-10-05 06:56:58 +00:00
return next_child ;
from = next_child ;
2017-03-05 15:44:50 +00:00
} else
break ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
return NULL ;
}
static Control * _prev_control ( Control * p_from ) {
2017-03-05 15:44:50 +00:00
Control * child = NULL ;
for ( int i = p_from - > get_child_count ( ) - 1 ; i > = 0 ; i - - ) {
2014-02-10 01:10:30 +00:00
2017-08-24 20:58:51 +00:00
Control * c = Object : : cast_to < Control > ( p_from - > get_child ( i ) ) ;
2017-01-13 13:45:50 +00:00
if ( ! c | | ! c - > is_visible_in_tree ( ) | | c - > is_set_as_toplevel ( ) )
2014-02-10 01:10:30 +00:00
continue ;
2017-03-05 15:44:50 +00:00
child = c ;
2014-02-10 01:10:30 +00:00
break ;
}
if ( ! child )
return p_from ;
//no prev in parent, try the same in parent
return _prev_control ( child ) ;
}
Control * Control : : find_prev_valid_focus ( ) const {
2017-03-05 15:44:50 +00:00
Control * from = const_cast < Control * > ( this ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
while ( true ) {
2014-02-10 01:10:30 +00:00
2017-11-16 09:45:52 +00:00
// If the focus property is manually overwritten, attempt to use it.
if ( ! data . focus_prev . is_empty ( ) ) {
Node * n = get_node ( data . focus_prev ) ;
2019-12-16 00:33:25 +00:00
Control * c ;
2017-11-16 09:45:52 +00:00
if ( n ) {
2019-12-16 00:33:25 +00:00
c = Object : : cast_to < Control > ( n ) ;
ERR_FAIL_COND_V_MSG ( ! c , NULL , " Previous focus node is not a control: " + n - > get_name ( ) + " . " ) ;
2017-11-16 09:45:52 +00:00
} else {
return NULL ;
}
2019-12-16 00:33:25 +00:00
if ( c - > is_visible ( ) & & c - > get_focus_mode ( ) ! = FOCUS_NONE )
return c ;
2017-11-16 09:45:52 +00:00
}
2014-02-10 01:10:30 +00:00
// find prev child
2017-03-05 15:44:50 +00:00
Control * prev_child = NULL ;
2014-02-10 01:10:30 +00:00
2017-08-24 20:58:51 +00:00
if ( from - > is_set_as_toplevel ( ) | | ! Object : : cast_to < Control > ( from - > get_parent ( ) ) ) {
2014-02-10 01:10:30 +00:00
2018-01-18 20:37:17 +00:00
//find last of the children
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
prev_child = _prev_control ( from ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
} else {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = ( from - > get_position_in_parent ( ) - 1 ) ; i > = 0 ; i - - ) {
2014-02-10 01:10:30 +00:00
2017-08-24 20:58:51 +00:00
Control * c = Object : : cast_to < Control > ( from - > get_parent ( ) - > get_child ( i ) ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( ! c | | ! c - > is_visible_in_tree ( ) | | c - > is_set_as_toplevel ( ) ) {
continue ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
prev_child = c ;
break ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
if ( ! prev_child ) {
2014-02-10 01:10:30 +00:00
2017-08-24 20:58:51 +00:00
prev_child = Object : : cast_to < Control > ( from - > get_parent ( ) ) ;
2017-03-05 15:44:50 +00:00
} else {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
prev_child = _prev_control ( prev_child ) ;
}
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( prev_child = = this ) // no prev control->
return ( get_focus_mode ( ) = = FOCUS_ALL ) ? prev_child : NULL ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( prev_child - > get_focus_mode ( ) = = FOCUS_ALL )
return prev_child ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
from = prev_child ;
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
return NULL ;
2014-02-10 01:10:30 +00:00
}
Control : : FocusMode Control : : get_focus_mode ( ) const {
return data . focus_mode ;
}
bool Control : : has_focus ( ) const {
2016-01-17 01:41:10 +00:00
return is_inside_tree ( ) & & get_viewport ( ) - > _gui_control_has_focus ( this ) ;
2014-02-10 01:10:30 +00:00
}
void Control : : grab_focus ( ) {
2019-08-31 23:25:22 +00:00
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
2018-09-06 16:32:34 +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. " ) ;
2014-02-10 01:10:30 +00:00
return ;
2018-09-06 16:32:34 +00:00
}
2016-01-17 01:41:10 +00:00
get_viewport ( ) - > _gui_control_grab_focus ( this ) ;
2016-03-08 23:00:52 +00:00
}
2014-02-10 01:10:30 +00:00
void Control : : release_focus ( ) {
2014-11-06 00:20:42 +00:00
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
2014-02-10 01:10:30 +00:00
if ( ! has_focus ( ) )
return ;
2016-01-17 01:41:10 +00:00
get_viewport ( ) - > _gui_remove_focus ( ) ;
2014-02-10 01:10:30 +00:00
update ( ) ;
}
bool Control : : is_toplevel_control ( ) const {
2016-01-17 01:41:10 +00:00
return is_inside_tree ( ) & & ( ! data . parent_canvas_item & & ! data . RI & & is_set_as_toplevel ( ) ) ;
2014-02-10 01:10:30 +00:00
}
2020-03-06 17:00:16 +00:00
void Control : : _propagate_theme_changed ( Node * p_at , Control * p_owner , Window * p_owner_window , bool p_assign ) {
2016-06-14 00:10:45 +00:00
2017-08-24 20:58:51 +00:00
Control * c = Object : : cast_to < Control > ( p_at ) ;
2016-06-14 00:10:45 +00:00
2017-03-05 15:44:50 +00:00
if ( c & & c ! = p_owner & & c - > data . theme . is_valid ( ) ) // has a theme, this can't be propagated
2016-06-14 00:10:45 +00:00
return ;
2014-02-10 01:10:30 +00:00
2020-03-06 17:00:16 +00:00
Window * w = c = = nullptr ? Object : : cast_to < Window > ( p_at ) : nullptr ;
if ( w & & w ! = p_owner_window & & w - > theme . is_valid ( ) ) // has a theme, this can't be propagated
return ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < p_at - > get_child_count ( ) ; i + + ) {
2016-06-14 00:10:45 +00:00
2017-08-24 20:58:51 +00:00
CanvasItem * child = Object : : cast_to < CanvasItem > ( p_at - > get_child ( i ) ) ;
2016-06-14 00:10:45 +00:00
if ( child ) {
2020-03-06 17:00:16 +00:00
_propagate_theme_changed ( child , p_owner , p_owner_window , p_assign ) ;
} else {
Window * window = Object : : cast_to < Window > ( p_at - > get_child ( i ) ) ;
if ( window ) {
_propagate_theme_changed ( window , p_owner , p_owner_window , p_assign ) ;
}
2016-06-14 00:10:45 +00:00
}
2014-02-10 01:10:30 +00:00
}
2016-06-14 00:10:45 +00:00
if ( c ) {
2016-07-18 19:41:28 +00:00
if ( p_assign ) {
2017-03-05 15:44:50 +00:00
c - > data . theme_owner = p_owner ;
2020-03-06 17:00:16 +00:00
c - > data . theme_owner_window = p_owner_window ;
}
c - > notification ( Control : : NOTIFICATION_THEME_CHANGED ) ;
c - > emit_signal ( SceneStringNames : : get_singleton ( ) - > theme_changed ) ;
}
if ( w ) {
if ( p_assign ) {
w - > theme_owner = p_owner ;
w - > theme_owner_window = p_owner_window ;
2016-07-18 19:41:28 +00:00
}
2020-03-06 17:00:16 +00:00
w - > notification ( Window : : NOTIFICATION_THEME_CHANGED ) ;
w - > emit_signal ( SceneStringNames : : get_singleton ( ) - > theme_changed ) ;
2016-06-14 00:10:45 +00:00
}
2014-02-10 01:10:30 +00:00
}
2016-07-18 19:41:28 +00:00
void Control : : _theme_changed ( ) {
2020-03-06 17:00:16 +00:00
_propagate_theme_changed ( this , this , nullptr , false ) ;
2016-07-18 19:41:28 +00:00
}
2017-03-05 15:44:50 +00:00
void Control : : set_theme ( const Ref < Theme > & p_theme ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( data . theme = = p_theme )
2016-07-18 19:41:28 +00:00
return ;
if ( data . theme . is_valid ( ) ) {
2020-02-21 17:28:45 +00:00
data . theme - > disconnect ( " changed " , callable_mp ( this , & Control : : _theme_changed ) ) ;
2016-07-18 19:41:28 +00:00
}
2017-03-05 15:44:50 +00:00
data . theme = p_theme ;
2014-02-10 01:10:30 +00:00
if ( ! p_theme . is_null ( ) ) {
2018-01-05 03:22:06 +00:00
data . theme_owner = this ;
2020-03-06 17:00:16 +00:00
data . theme_owner_window = nullptr ;
_propagate_theme_changed ( this , this , nullptr ) ;
2014-02-10 01:10:30 +00:00
} else {
2020-03-06 17:00:16 +00:00
Control * parent_c = Object : : cast_to < Control > ( get_parent ( ) ) ;
2014-02-10 01:10:30 +00:00
2020-03-06 17:00:16 +00:00
if ( parent_c & & ( parent_c - > data . theme_owner | | parent_c - > data . theme_owner_window ) ) {
Control : : _propagate_theme_changed ( this , parent_c - > data . theme_owner , parent_c - > data . theme_owner_window ) ;
} else {
Window * parent_w = cast_to < Window > ( get_parent ( ) ) ;
if ( parent_w & & ( parent_w - > theme_owner | | parent_w - > theme_owner_window ) ) {
Control : : _propagate_theme_changed ( this , parent_w - > theme_owner , parent_w - > theme_owner_window ) ;
} else {
Control : : _propagate_theme_changed ( this , nullptr , nullptr ) ;
}
2014-02-10 01:10:30 +00:00
}
}
2016-07-18 19:41:28 +00:00
if ( data . theme . is_valid ( ) ) {
2020-02-21 17:28:45 +00:00
data . theme - > connect ( " changed " , callable_mp ( this , & Control : : _theme_changed ) , varray ( ) , CONNECT_DEFERRED ) ;
2016-07-18 19:41:28 +00:00
}
2014-02-10 01:10:30 +00:00
}
2016-01-17 01:41:10 +00:00
void Control : : accept_event ( ) {
2014-02-10 01:10:30 +00:00
2014-11-06 00:20:42 +00:00
if ( is_inside_tree ( ) )
2016-01-17 01:41:10 +00:00
get_viewport ( ) - > _gui_accept_event ( ) ;
2014-02-10 01:10:30 +00:00
}
Ref < Theme > Control : : get_theme ( ) const {
return data . theme ;
}
2017-03-05 15:44:50 +00:00
void Control : : set_tooltip ( const String & p_tooltip ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
data . tooltip = p_tooltip ;
2019-06-28 16:38:57 +00:00
update_configuration_warning ( ) ;
2014-02-10 01:10:30 +00:00
}
2018-07-20 21:14:33 +00:00
2017-03-05 15:44:50 +00:00
String Control : : get_tooltip ( const Point2 & p_pos ) const {
2014-02-10 01:10:30 +00:00
return data . tooltip ;
}
2018-07-20 21:14:33 +00:00
Control * Control : : make_custom_tooltip ( const String & p_text ) const {
if ( get_script_instance ( ) ) {
return const_cast < Control * > ( this ) - > call ( " _make_custom_tooltip " , p_text ) ;
}
return NULL ;
}
2014-02-10 01:10:30 +00:00
void Control : : set_default_cursor_shape ( CursorShape p_shape ) {
2019-10-05 17:17:07 +00:00
ERR_FAIL_INDEX ( int ( p_shape ) , CURSOR_MAX ) ;
2017-03-05 15:44:50 +00:00
data . default_cursor = p_shape ;
2014-02-10 01:10:30 +00:00
}
Control : : CursorShape Control : : get_default_cursor_shape ( ) const {
return data . default_cursor ;
}
2017-03-05 15:44:50 +00:00
Control : : CursorShape Control : : get_cursor_shape ( const Point2 & p_pos ) const {
2014-02-10 01:10:30 +00:00
return data . default_cursor ;
}
2017-01-11 03:52:51 +00:00
Transform2D Control : : get_transform ( ) const {
2014-02-10 01:10:30 +00:00
2017-07-06 20:42:44 +00:00
Transform2D xform = _get_internal_transform ( ) ;
xform [ 2 ] + = get_position ( ) ;
2015-12-12 16:54:26 +00:00
return xform ;
2014-02-10 01:10:30 +00:00
}
String Control : : _get_tooltip ( ) const {
return data . tooltip ;
}
void Control : : set_focus_neighbour ( Margin p_margin , const NodePath & p_neighbour ) {
2018-10-04 07:17:59 +00:00
ERR_FAIL_INDEX ( ( int ) p_margin , 4 ) ;
2017-03-05 15:44:50 +00:00
data . focus_neighbour [ p_margin ] = p_neighbour ;
2014-02-10 01:10:30 +00:00
}
NodePath Control : : get_focus_neighbour ( Margin p_margin ) const {
2018-10-04 07:17:59 +00:00
ERR_FAIL_INDEX_V ( ( int ) p_margin , 4 , NodePath ( ) ) ;
2014-02-10 01:10:30 +00:00
return data . focus_neighbour [ p_margin ] ;
}
2017-11-16 09:45:52 +00:00
void Control : : set_focus_next ( const NodePath & p_next ) {
data . focus_next = p_next ;
}
NodePath Control : : get_focus_next ( ) const {
return data . focus_next ;
}
void Control : : set_focus_previous ( const NodePath & p_prev ) {
data . focus_prev = p_prev ;
}
NodePath Control : : get_focus_previous ( ) const {
return data . focus_prev ;
}
2014-02-10 01:10:30 +00:00
# define MAX_NEIGHBOUR_SEARCH_COUNT 512
2017-03-05 15:44:50 +00:00
Control * Control : : _get_focus_neighbour ( Margin p_margin , int p_count ) {
2014-02-10 01:10:30 +00:00
2019-10-05 17:17:07 +00:00
ERR_FAIL_INDEX_V ( ( int ) p_margin , 4 , NULL ) ;
2014-02-10 01:10:30 +00:00
if ( p_count > = MAX_NEIGHBOUR_SEARCH_COUNT )
return NULL ;
if ( ! data . focus_neighbour [ p_margin ] . is_empty ( ) ) {
2017-03-05 15:44:50 +00:00
Control * c = NULL ;
Node * n = get_node ( data . focus_neighbour [ p_margin ] ) ;
2014-02-10 01:10:30 +00:00
if ( n ) {
2017-08-24 20:58:51 +00:00
c = Object : : cast_to < Control > ( n ) ;
2019-08-08 20:11:48 +00:00
ERR_FAIL_COND_V_MSG ( ! c , NULL , " Neighbor focus node is not a control: " + n - > get_name ( ) + " . " ) ;
2014-02-10 01:10:30 +00:00
} else {
return NULL ;
}
2017-03-05 15:44:50 +00:00
bool valid = true ;
2017-01-13 13:45:50 +00:00
if ( ! c - > is_visible ( ) )
2017-03-05 15:44:50 +00:00
valid = false ;
if ( c - > get_focus_mode ( ) = = FOCUS_NONE )
valid = false ;
2014-02-10 01:10:30 +00:00
if ( valid )
return c ;
2017-03-05 15:44:50 +00:00
c = c - > _get_focus_neighbour ( p_margin , p_count + 1 ) ;
2014-02-10 01:10:30 +00:00
return c ;
}
2017-03-05 15:44:50 +00:00
float dist = 1e7 ;
Control * result = NULL ;
2014-02-10 01:10:30 +00:00
Point2 points [ 4 ] ;
2017-01-11 03:52:51 +00:00
Transform2D xform = get_global_transform ( ) ;
2014-02-10 01:10:30 +00:00
2018-05-05 14:59:00 +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
2017-03-05 15:44:50 +00:00
const Vector2 dir [ 4 ] = {
Vector2 ( - 1 , 0 ) ,
Vector2 ( 0 , - 1 ) ,
Vector2 ( 1 , 0 ) ,
Vector2 ( 0 , 1 )
2014-02-10 01:10:30 +00:00
} ;
2017-03-05 15:44:50 +00:00
Vector2 vdir = dir [ p_margin ] ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
float maxd = - 1e7 ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < 4 ; i + + ) {
2014-02-10 01:10:30 +00:00
float d = vdir . dot ( points [ i ] ) ;
2017-03-05 15:44:50 +00:00
if ( d > maxd )
maxd = d ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
Node * base = this ;
2014-02-10 01:10:30 +00:00
while ( base ) {
2017-08-24 20:58:51 +00:00
Control * c = Object : : cast_to < Control > ( base ) ;
2014-02-10 01:10:30 +00:00
if ( c ) {
2016-01-17 01:41:10 +00:00
if ( c - > data . RI )
2014-02-10 01:10:30 +00:00
break ;
}
2017-03-05 15:44:50 +00:00
base = base - > get_parent ( ) ;
2014-02-10 01:10:30 +00:00
}
if ( ! base )
return NULL ;
2017-03-05 15:44:50 +00:00
_window_find_focus_neighbour ( vdir , base , points , maxd , dist , & result ) ;
2014-02-10 01:10:30 +00:00
return result ;
}
2017-03-05 15:44:50 +00:00
void Control : : _window_find_focus_neighbour ( const Vector2 & p_dir , Node * p_at , const Point2 * p_points , float p_min , float & r_closest_dist , Control * * r_closest ) {
2014-02-10 01:10:30 +00:00
2017-08-24 20:58:51 +00:00
if ( Object : : cast_to < Viewport > ( p_at ) )
2014-02-10 01:10:30 +00:00
return ; //bye
2017-08-24 20:58:51 +00:00
Control * c = Object : : cast_to < Control > ( p_at ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( c & & c ! = this & & c - > get_focus_mode ( ) = = FOCUS_ALL & & c - > is_visible_in_tree ( ) ) {
2014-02-10 01:10:30 +00:00
Point2 points [ 4 ] ;
2017-01-11 03:52:51 +00:00
Transform2D xform = c - > get_global_transform ( ) ;
2014-02-10 01:10:30 +00:00
2018-05-05 14:59:00 +00:00
points [ 0 ] = xform . xform ( Point2 ( ) ) ;
2020-01-19 22:38:50 +00:00
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 ) ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
float min = 1e7 ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < 4 ; i + + ) {
2014-02-10 01:10:30 +00:00
float d = p_dir . dot ( points [ i ] ) ;
if ( d < min )
2017-03-05 15:44:50 +00:00
min = d ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
if ( min > ( p_min - CMP_EPSILON ) ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < 4 ; i + + ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
Vector2 la = p_points [ i ] ;
Vector2 lb = p_points [ ( i + 1 ) % 4 ] ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
for ( int j = 0 ; j < 4 ; j + + ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
Vector2 fa = points [ j ] ;
Vector2 fb = points [ ( j + 1 ) % 4 ] ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
Vector2 pa , pb ;
float d = Geometry : : get_closest_points_between_segments ( la , lb , fa , fb , pa , pb ) ;
2014-02-10 01:10:30 +00:00
//float d = Geometry::get_closest_distance_between_segments(Vector3(la.x,la.y,0),Vector3(lb.x,lb.y,0),Vector3(fa.x,fa.y,0),Vector3(fb.x,fb.y,0));
2017-03-05 15:44:50 +00:00
if ( d < r_closest_dist ) {
r_closest_dist = d ;
* r_closest = c ;
2014-02-10 01:10:30 +00:00
}
}
}
}
}
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < p_at - > get_child_count ( ) ; i + + ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
Node * child = p_at - > get_child ( i ) ;
2017-08-24 20:58:51 +00:00
Control * childc = Object : : cast_to < Control > ( child ) ;
2020-03-14 16:06:39 +00:00
if ( childc & & childc - > data . RI )
2014-02-10 01:10:30 +00:00
continue ; //subwindow, ignore
2017-03-05 15:44:50 +00:00
_window_find_focus_neighbour ( p_dir , p_at - > get_child ( i ) , p_points , p_min , r_closest_dist , r_closest ) ;
2014-02-10 01:10:30 +00:00
}
}
void Control : : set_h_size_flags ( int p_flags ) {
2017-03-05 15:44:50 +00:00
if ( data . h_size_flags = = p_flags )
2014-02-10 01:10:30 +00:00
return ;
2017-03-05 15:44:50 +00:00
data . h_size_flags = p_flags ;
2014-02-10 01:10:30 +00:00
emit_signal ( SceneStringNames : : get_singleton ( ) - > size_flags_changed ) ;
}
2017-03-05 15:44:50 +00:00
int Control : : get_h_size_flags ( ) const {
2014-02-10 01:10:30 +00:00
return data . h_size_flags ;
}
void Control : : set_v_size_flags ( int p_flags ) {
2017-03-05 15:44:50 +00:00
if ( data . v_size_flags = = p_flags )
2014-02-10 01:10:30 +00:00
return ;
2017-03-05 15:44:50 +00:00
data . v_size_flags = p_flags ;
2014-02-10 01:10:30 +00:00
emit_signal ( SceneStringNames : : get_singleton ( ) - > size_flags_changed ) ;
}
void Control : : set_stretch_ratio ( float p_ratio ) {
2017-03-05 15:44:50 +00:00
if ( data . expand = = p_ratio )
2014-02-10 01:10:30 +00:00
return ;
2017-03-05 15:44:50 +00:00
data . expand = p_ratio ;
2014-02-10 01:10:30 +00:00
emit_signal ( SceneStringNames : : get_singleton ( ) - > size_flags_changed ) ;
}
float Control : : get_stretch_ratio ( ) const {
return data . expand ;
}
void Control : : grab_click_focus ( ) {
2014-11-06 00:20:42 +00:00
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
2014-02-10 01:10:30 +00:00
2016-01-17 01:41:10 +00:00
get_viewport ( ) - > _gui_grab_click_focus ( this ) ;
2014-02-10 01:10:30 +00:00
}
void Control : : minimum_size_changed ( ) {
2016-08-25 20:45:20 +00:00
if ( ! is_inside_tree ( ) | | data . block_minimum_size_adjust )
2014-02-10 01:10:30 +00:00
return ;
2018-05-15 20:12:35 +00:00
Control * invalidate = this ;
//invalidate cache upwards
while ( invalidate & & invalidate - > data . minimum_size_valid ) {
invalidate - > data . minimum_size_valid = false ;
if ( invalidate - > is_set_as_toplevel ( ) )
break ; // do not go further up
2020-03-06 17:00:16 +00:00
if ( ! invalidate - > data . parent & & get_parent ( ) ) {
Window * parent_window = Object : : cast_to < Window > ( get_parent ( ) ) ;
if ( parent_window & & parent_window - > is_wrapping_controls ( ) ) {
parent_window - > child_controls_changed ( ) ;
}
}
2018-05-15 20:12:35 +00:00
invalidate = invalidate - > data . parent ;
}
if ( ! is_visible_in_tree ( ) )
return ;
if ( data . updating_last_minimum_size )
2014-02-10 01:10:30 +00:00
return ;
2018-05-15 20:12:35 +00:00
data . updating_last_minimum_size = true ;
2014-02-10 01:10:30 +00:00
2018-05-15 20:12:35 +00:00
MessageQueue : : get_singleton ( ) - > push_call ( this , " _update_minimum_size " ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
int Control : : get_v_size_flags ( ) const {
2014-02-10 01:10:30 +00:00
return data . v_size_flags ;
}
2017-01-08 22:54:19 +00:00
void Control : : set_mouse_filter ( MouseFilter p_filter ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
ERR_FAIL_INDEX ( p_filter , 3 ) ;
data . mouse_filter = p_filter ;
2019-06-28 16:38:57 +00:00
update_configuration_warning ( ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
Control : : MouseFilter Control : : get_mouse_filter ( ) const {
2014-02-10 01:10:30 +00:00
2017-01-08 22:54:19 +00:00
return data . mouse_filter ;
2014-02-10 01:10:30 +00:00
}
Control * Control : : get_focus_owner ( ) const {
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( ! is_inside_tree ( ) , NULL ) ;
2016-01-17 01:41:10 +00:00
return get_viewport ( ) - > _gui_get_focus_owner ( ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void Control : : warp_mouse ( const Point2 & p_to_pos ) {
2015-02-14 22:22:06 +00:00
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
get_viewport ( ) - > warp_mouse ( get_global_transform ( ) . xform ( p_to_pos ) ) ;
}
2015-10-17 13:29:54 +00:00
bool Control : : is_text_field ( ) const {
2017-03-05 15:44:50 +00:00
/*
2015-10-17 13:29:54 +00:00
if ( get_script_instance ( ) ) {
Variant v = p_point ;
const Variant * p [ 2 ] = { & v , & p_data } ;
2020-02-19 19:27:19 +00:00
Callable : : CallError ce ;
2015-10-17 13:29:54 +00:00
Variant ret = get_script_instance ( ) - > call ( " is_text_field " , p , 2 , ce ) ;
2020-02-19 19:27:19 +00:00
if ( ce . error = = Callable : : CallError : : CALL_OK )
2015-10-17 13:29:54 +00:00
return ret ;
}
*/
2017-03-05 15:44:50 +00:00
return false ;
2015-10-17 13:29:54 +00:00
}
2016-05-06 21:38:08 +00:00
void Control : : set_rotation ( float p_radians ) {
2015-12-12 16:54:26 +00:00
2017-03-05 15:44:50 +00:00
data . rotation = p_radians ;
2015-12-12 16:54:26 +00:00
update ( ) ;
_notify_transform ( ) ;
2017-04-03 16:34:44 +00:00
_change_notify ( " rect_rotation " ) ;
2015-12-12 16:54:26 +00:00
}
2017-03-05 15:44:50 +00:00
float Control : : get_rotation ( ) const {
2015-12-12 16:54:26 +00:00
return data . rotation ;
}
2017-11-10 10:07:52 +00:00
void Control : : set_rotation_degrees ( float p_degrees ) {
2016-05-06 21:38:08 +00:00
set_rotation ( Math : : deg2rad ( p_degrees ) ) ;
}
2017-11-10 10:07:52 +00:00
float Control : : get_rotation_degrees ( ) const {
2016-05-06 21:38:08 +00:00
return Math : : rad2deg ( get_rotation ( ) ) ;
}
2019-02-25 15:13:25 +00:00
void Control : : _override_changed ( ) {
2016-06-17 19:00:27 +00:00
notification ( NOTIFICATION_THEME_CHANGED ) ;
2020-03-06 17:00:16 +00:00
emit_signal ( SceneStringNames : : get_singleton ( ) - > theme_changed ) ;
2019-02-25 15:13:25 +00:00
minimum_size_changed ( ) ; // overrides are likely to affect minimum size
2016-06-17 19:00:27 +00:00
}
2016-05-06 21:38:08 +00:00
2017-07-06 20:42:44 +00:00
void Control : : set_pivot_offset ( const Vector2 & p_pivot ) {
data . pivot_offset = p_pivot ;
update ( ) ;
_notify_transform ( ) ;
_change_notify ( " rect_pivot_offset " ) ;
}
Vector2 Control : : get_pivot_offset ( ) const {
return data . pivot_offset ;
}
2017-03-05 15:44:50 +00:00
void Control : : set_scale ( const Vector2 & p_scale ) {
2015-12-12 16:54:26 +00:00
2017-03-05 15:44:50 +00:00
data . scale = p_scale ;
2020-01-13 11:13:45 +00:00
// 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 ;
2015-12-12 16:54:26 +00:00
update ( ) ;
_notify_transform ( ) ;
}
2017-03-05 15:44:50 +00:00
Vector2 Control : : get_scale ( ) const {
2015-12-12 16:54:26 +00:00
return data . scale ;
}
2016-01-19 23:27:27 +00:00
Control * Control : : get_root_parent_control ( ) const {
2017-03-05 15:44:50 +00:00
const CanvasItem * ci = this ;
const Control * root = this ;
2016-01-19 23:27:27 +00:00
2017-03-05 15:44:50 +00:00
while ( ci ) {
2016-01-19 23:27:27 +00:00
2017-08-24 20:58:51 +00:00
const Control * c = Object : : cast_to < Control > ( ci ) ;
2016-01-19 23:27:27 +00:00
if ( c ) {
2017-03-05 15:44:50 +00:00
root = c ;
2016-01-19 23:27:27 +00:00
2020-03-14 16:06:39 +00:00
if ( c - > data . RI | | c - > is_toplevel_control ( ) )
2016-01-19 23:27:27 +00:00
break ;
}
2017-03-05 15:44:50 +00:00
ci = ci - > get_parent_item ( ) ;
2016-01-19 23:27:27 +00:00
}
2017-03-05 15:44:50 +00:00
return const_cast < Control * > ( root ) ;
2016-01-19 23:27:27 +00:00
}
2015-12-12 16:54:26 +00:00
2016-08-25 20:45:20 +00:00
void Control : : set_block_minimum_size_adjust ( bool p_block ) {
2017-03-05 15:44:50 +00:00
data . block_minimum_size_adjust = p_block ;
2016-08-25 20:45:20 +00:00
}
2016-01-24 13:57:42 +00:00
2016-08-25 20:45:20 +00:00
bool Control : : is_minimum_size_adjust_blocked ( ) const {
2016-01-24 13:57:42 +00:00
2016-08-25 20:45:20 +00:00
return data . block_minimum_size_adjust ;
}
2016-08-31 02:44:14 +00:00
void Control : : set_disable_visibility_clip ( bool p_ignore ) {
2017-03-05 15:44:50 +00:00
data . disable_visibility_clip = p_ignore ;
2016-08-31 02:44:14 +00:00
update ( ) ;
}
bool Control : : is_visibility_clip_disabled ( ) const {
return data . disable_visibility_clip ;
}
2017-03-05 15:44:50 +00:00
void Control : : get_argument_options ( const StringName & p_function , int p_idx , List < String > * r_options ) const {
2016-09-11 14:48:31 +00:00
2018-12-18 01:53:54 +00:00
# ifdef TOOLS_ENABLED
const String quote_style = EDITOR_DEF ( " text_editor/completion/use_single_quotes " , 0 ) ? " ' " : " \" " ;
# else
const String quote_style = " \" " ;
# endif
2017-03-05 15:44:50 +00:00
Node : : get_argument_options ( p_function , p_idx , r_options ) ;
2016-09-11 14:48:31 +00:00
2017-03-05 15:44:50 +00:00
if ( p_idx = = 0 ) {
2016-09-11 14:48:31 +00:00
List < StringName > sn ;
String pf = p_function ;
2017-03-05 15:44:50 +00:00
if ( pf = = " add_color_override " | | pf = = " has_color " | | pf = = " has_color_override " | | pf = = " get_color " ) {
Theme : : get_default ( ) - > get_color_list ( get_class ( ) , & sn ) ;
} else if ( pf = = " add_style_override " | | pf = = " has_style " | | pf = = " has_style_override " | | pf = = " get_style " ) {
Theme : : get_default ( ) - > get_stylebox_list ( get_class ( ) , & sn ) ;
} else if ( pf = = " add_font_override " | | pf = = " has_font " | | pf = = " has_font_override " | | pf = = " get_font " ) {
Theme : : get_default ( ) - > get_font_list ( get_class ( ) , & sn ) ;
} else if ( pf = = " add_constant_override " | | pf = = " has_constant " | | pf = = " has_constant_override " | | pf = = " get_constant " ) {
Theme : : get_default ( ) - > get_constant_list ( get_class ( ) , & sn ) ;
2016-09-11 14:48:31 +00:00
}
sn . sort_custom < StringName : : AlphCompare > ( ) ;
2017-03-05 15:44:50 +00:00
for ( List < StringName > : : Element * E = sn . front ( ) ; E ; E = E - > next ( ) ) {
2018-12-18 01:53:54 +00:00
r_options - > push_back ( quote_style + E - > get ( ) + quote_style ) ;
2016-09-11 14:48:31 +00:00
}
}
}
2019-06-28 16:38:57 +00:00
String Control : : get_configuration_warning ( ) const {
String warning = CanvasItem : : get_configuration_warning ( ) ;
if ( data . mouse_filter = = MOUSE_FILTER_IGNORE & & data . tooltip ! = " " ) {
if ( warning ! = String ( ) ) {
2019-07-08 22:17:04 +00:00
warning + = " \n \n " ;
2019-06-28 16:38:57 +00:00
}
warning + = TTR ( " 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 warning ;
}
2017-01-09 18:50:08 +00:00
void Control : : set_clip_contents ( bool p_clip ) {
2017-03-05 15:44:50 +00:00
data . clip_contents = p_clip ;
2017-01-09 18:50:08 +00:00
update ( ) ;
}
bool Control : : is_clipping_contents ( ) {
return data . clip_contents ;
}
2016-09-11 14:48:31 +00:00
2017-07-06 16:26:39 +00:00
void Control : : set_h_grow_direction ( GrowDirection p_direction ) {
2019-10-05 17:17:07 +00:00
ERR_FAIL_INDEX ( ( int ) p_direction , 3 ) ;
2017-07-06 16:26:39 +00:00
data . h_grow = p_direction ;
_size_changed ( ) ;
}
Control : : GrowDirection Control : : get_h_grow_direction ( ) const {
return data . h_grow ;
}
void Control : : set_v_grow_direction ( GrowDirection p_direction ) {
2019-10-05 17:17:07 +00:00
ERR_FAIL_INDEX ( ( int ) p_direction , 3 ) ;
2017-07-06 16:26:39 +00:00
data . v_grow = p_direction ;
_size_changed ( ) ;
}
Control : : GrowDirection Control : : get_v_grow_direction ( ) const {
return data . v_grow ;
}
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("_window_resize_event"),&Control::_window_resize_event);
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " _update_minimum_size " ) , & Control : : _update_minimum_size ) ;
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 ) ;
2019-03-31 16:53:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_anchors_preset " , " preset " , " keep_margins " ) , & Control : : set_anchors_preset , DEFVAL ( false ) ) ;
2017-09-19 20:39:19 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_margins_preset " , " preset " , " resize_mode " , " margin " ) , & Control : : set_margins_preset , DEFVAL ( PRESET_MODE_MINSIZE ) , DEFVAL ( 0 ) ) ;
ClassDB : : bind_method ( D_METHOD ( " set_anchors_and_margins_preset " , " preset " , " resize_mode " , " margin " ) , & Control : : set_anchors_and_margins_preset , DEFVAL ( PRESET_MODE_MINSIZE ) , DEFVAL ( 0 ) ) ;
2017-07-06 07:16:27 +00:00
ClassDB : : bind_method ( D_METHOD ( " _set_anchor " , " margin " , " anchor " ) , & Control : : _set_anchor ) ;
2019-03-31 16:53:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_anchor " , " margin " , " anchor " , " keep_margin " , " push_opposite_anchor " ) , & Control : : set_anchor , DEFVAL ( false ) , DEFVAL ( true ) ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_anchor " , " margin " ) , & Control : : get_anchor ) ;
ClassDB : : bind_method ( D_METHOD ( " set_margin " , " margin " , " offset " ) , & Control : : set_margin ) ;
2017-08-11 17:25:26 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_anchor_and_margin " , " margin " , " anchor " , " offset " , " push_opposite_anchor " ) , & Control : : set_anchor_and_margin , DEFVAL ( false ) ) ;
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 ) ;
2019-03-31 16:53:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_position " , " position " , " keep_margins " ) , & Control : : set_position , DEFVAL ( false ) ) ;
ClassDB : : bind_method ( D_METHOD ( " _set_position " , " margin " ) , & Control : : _set_position ) ;
ClassDB : : bind_method ( D_METHOD ( " set_size " , " size " , " keep_margins " ) , & Control : : set_size , DEFVAL ( false ) ) ;
ClassDB : : bind_method ( D_METHOD ( " _set_size " , " size " ) , & Control : : _set_size ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_custom_minimum_size " , " size " ) , & Control : : set_custom_minimum_size ) ;
2019-03-31 16:53:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_global_position " , " position " , " keep_margins " ) , & Control : : set_global_position , DEFVAL ( false ) ) ;
ClassDB : : bind_method ( D_METHOD ( " _set_global_position " , " position " ) , & Control : : _set_global_position ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_rotation " , " radians " ) , & Control : : set_rotation ) ;
2017-11-10 10:07:52 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_rotation_degrees " , " degrees " ) , & Control : : set_rotation_degrees ) ;
2017-03-05 15:44:50 +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-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_margin " , " margin " ) , & Control : : get_margin ) ;
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-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_size " ) , & Control : : get_size ) ;
ClassDB : : bind_method ( D_METHOD ( " get_rotation " ) , & Control : : get_rotation ) ;
2017-11-10 10:07:52 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_rotation_degrees " ) , & Control : : get_rotation_degrees ) ;
2017-03-05 15:44:50 +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-03-05 15:44:50 +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 ) ;
2017-03-05 15:44:50 +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 ) ;
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_focus_owner " ) , & Control : : get_focus_owner ) ;
2017-03-05 15:44:50 +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 ) ;
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 ) ;
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-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
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_shader_override " , " name " , " shader " ) , & Control : : add_theme_shader_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 ) ;
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 ) ;
ClassDB : : bind_method ( D_METHOD ( " get_theme_icon " , " name " , " type " ) , & Control : : get_theme_icon , DEFVAL ( " " ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_theme_stylebox " , " name " , " type " ) , & Control : : get_theme_stylebox , DEFVAL ( " " ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_theme_font " , " name " , " type " ) , & Control : : get_theme_font , DEFVAL ( " " ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_theme_color " , " name " , " type " ) , & Control : : get_theme_color , DEFVAL ( " " ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_theme_constant " , " name " , " type " ) , & Control : : get_theme_constant , DEFVAL ( " " ) ) ;
ClassDB : : bind_method ( D_METHOD ( " has_theme_icon_override " , " name " ) , & Control : : has_theme_icon_override ) ;
ClassDB : : bind_method ( D_METHOD ( " has_theme_shader_override " , " name " ) , & Control : : has_theme_shader_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 ) ;
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 ) ;
ClassDB : : bind_method ( D_METHOD ( " has_theme_icon " , " name " , " type " ) , & Control : : has_theme_icon , DEFVAL ( " " ) ) ;
ClassDB : : bind_method ( D_METHOD ( " has_theme_stylebox " , " name " , " type " ) , & Control : : has_theme_stylebox , DEFVAL ( " " ) ) ;
ClassDB : : bind_method ( D_METHOD ( " has_theme_font " , " name " , " type " ) , & Control : : has_theme_font , DEFVAL ( " " ) ) ;
ClassDB : : bind_method ( D_METHOD ( " has_theme_color " , " name " , " type " ) , & Control : : has_theme_color , DEFVAL ( " " ) ) ;
ClassDB : : bind_method ( D_METHOD ( " has_theme_constant " , " name " , " type " ) , & Control : : has_theme_constant , DEFVAL ( " " ) ) ;
2014-02-10 01:10:30 +00:00
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 ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_tooltip " , " tooltip " ) , & Control : : set_tooltip ) ;
2017-09-10 13:37:49 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_tooltip " , " at_position " ) , & Control : : get_tooltip , DEFVAL ( Point2 ( ) ) ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " _get_tooltip " ) , & Control : : _get_tooltip ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +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
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_focus_neighbour " , " margin " , " neighbour " ) , & Control : : set_focus_neighbour ) ;
ClassDB : : bind_method ( D_METHOD ( " get_focus_neighbour " , " margin " ) , & Control : : get_focus_neighbour ) ;
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-03-05 15:44:50 +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
2017-03-05 15:44:50 +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-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " grab_click_focus " ) , & Control : : grab_click_focus ) ;
2014-02-10 01:10:30 +00:00
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_drag_forwarding " , " target " ) , & Control : : set_drag_forwarding ) ;
ClassDB : : bind_method ( D_METHOD ( " set_drag_preview " , " control " ) , & Control : : set_drag_preview ) ;
2014-02-10 01:10:30 +00:00
2017-09-10 13:37:49 +00:00
ClassDB : : bind_method ( D_METHOD ( " warp_mouse " , " to_position " ) , & Control : : warp_mouse ) ;
2015-02-14 22:22:06 +00:00
2017-02-13 11:47:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " minimum_size_changed " ) , & Control : : minimum_size_changed ) ;
2015-02-14 22:22:06 +00:00
2017-05-20 15:38:03 +00:00
BIND_VMETHOD ( MethodInfo ( " _gui_input " , PropertyInfo ( Variant : : OBJECT , " event " , PROPERTY_HINT_RESOURCE_TYPE , " InputEvent " ) ) ) ;
2017-03-13 15:45:27 +00:00
BIND_VMETHOD ( MethodInfo ( Variant : : VECTOR2 , " _get_minimum_size " ) ) ;
2019-08-26 16:38:16 +00:00
MethodInfo get_drag_data = MethodInfo ( " get_drag_data " , PropertyInfo ( Variant : : VECTOR2 , " position " ) ) ;
get_drag_data . return_val . usage | = PROPERTY_USAGE_NIL_IS_VARIANT ;
BIND_VMETHOD ( get_drag_data ) ;
2017-09-10 13:37:49 +00:00
BIND_VMETHOD ( MethodInfo ( Variant : : BOOL , " can_drop_data " , PropertyInfo ( Variant : : VECTOR2 , " position " ) , PropertyInfo ( Variant : : NIL , " data " ) ) ) ;
BIND_VMETHOD ( MethodInfo ( " drop_data " , PropertyInfo ( Variant : : VECTOR2 , " position " ) , PropertyInfo ( Variant : : NIL , " data " ) ) ) ;
2018-07-20 21:14:33 +00:00
BIND_VMETHOD ( MethodInfo ( Variant : : OBJECT , " _make_custom_tooltip " , PropertyInfo ( Variant : : STRING , " for_text " ) ) ) ;
2018-07-29 15:46:53 +00:00
BIND_VMETHOD ( MethodInfo ( Variant : : BOOL , " _clips_input " ) ) ;
2017-03-05 15:44:50 +00:00
ADD_GROUP ( " Anchor " , " anchor_ " ) ;
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 18:20:53 +00:00
ADD_PROPERTYI ( PropertyInfo ( Variant : : FLOAT , " anchor_left " , PROPERTY_HINT_RANGE , " 0,1,0.001,or_lesser,or_greater " ) , " _set_anchor " , " get_anchor " , MARGIN_LEFT ) ;
ADD_PROPERTYI ( PropertyInfo ( Variant : : FLOAT , " anchor_top " , PROPERTY_HINT_RANGE , " 0,1,0.001,or_lesser,or_greater " ) , " _set_anchor " , " get_anchor " , MARGIN_TOP ) ;
ADD_PROPERTYI ( PropertyInfo ( Variant : : FLOAT , " anchor_right " , PROPERTY_HINT_RANGE , " 0,1,0.001,or_lesser,or_greater " ) , " _set_anchor " , " get_anchor " , MARGIN_RIGHT ) ;
ADD_PROPERTYI ( PropertyInfo ( Variant : : FLOAT , " anchor_bottom " , PROPERTY_HINT_RANGE , " 0,1,0.001,or_lesser,or_greater " ) , " _set_anchor " , " get_anchor " , MARGIN_BOTTOM ) ;
2017-03-05 15:44:50 +00:00
ADD_GROUP ( " Margin " , " margin_ " ) ;
2018-11-08 14:30:02 +00:00
ADD_PROPERTYI ( PropertyInfo ( Variant : : INT , " margin_left " , PROPERTY_HINT_RANGE , " -4096,4096 " ) , " set_margin " , " get_margin " , MARGIN_LEFT ) ;
ADD_PROPERTYI ( PropertyInfo ( Variant : : INT , " margin_top " , PROPERTY_HINT_RANGE , " -4096,4096 " ) , " set_margin " , " get_margin " , MARGIN_TOP ) ;
ADD_PROPERTYI ( PropertyInfo ( Variant : : INT , " margin_right " , PROPERTY_HINT_RANGE , " -4096,4096 " ) , " set_margin " , " get_margin " , MARGIN_RIGHT ) ;
ADD_PROPERTYI ( PropertyInfo ( Variant : : INT , " margin_bottom " , PROPERTY_HINT_RANGE , " -4096,4096 " ) , " set_margin " , " get_margin " , MARGIN_BOTTOM ) ;
2017-03-05 15:44:50 +00:00
2017-07-06 16:26:39 +00:00
ADD_GROUP ( " Grow Direction " , " grow_ " ) ;
2018-11-08 14:30:02 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " grow_horizontal " , PROPERTY_HINT_ENUM , " Begin,End,Both " ) , " set_h_grow_direction " , " get_h_grow_direction " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " grow_vertical " , PROPERTY_HINT_ENUM , " Begin,End,Both " ) , " set_v_grow_direction " , " get_v_grow_direction " ) ;
2017-07-06 16:26:39 +00:00
2017-03-05 15:44:50 +00:00
ADD_GROUP ( " Rect " , " rect_ " ) ;
2019-03-31 16:53:24 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR2 , " rect_position " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_EDITOR ) , " _set_position " , " get_position " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR2 , " rect_global_position " , PROPERTY_HINT_NONE , " " , 0 ) , " _set_global_position " , " get_global_position " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR2 , " rect_size " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_EDITOR ) , " _set_size " , " get_size " ) ;
2018-11-08 14:30:02 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR2 , " rect_min_size " ) , " set_custom_minimum_size " , " get_custom_minimum_size " ) ;
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 18:20:53 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " rect_rotation " , PROPERTY_HINT_RANGE , " -360,360,0.1,or_lesser,or_greater " ) , " set_rotation_degrees " , " get_rotation_degrees " ) ;
2018-11-08 14:30:02 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR2 , " rect_scale " ) , " set_scale " , " get_scale " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR2 , " rect_pivot_offset " ) , " set_pivot_offset " , " get_pivot_offset " ) ;
2018-02-19 03:24:05 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " rect_clip_content " ) , " set_clip_contents " , " is_clipping_contents " ) ;
2017-03-05 15:44:50 +00:00
ADD_GROUP ( " Hint " , " hint_ " ) ;
2018-11-08 14:30:02 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " hint_tooltip " , PROPERTY_HINT_MULTILINE_TEXT ) , " set_tooltip " , " _get_tooltip " ) ;
2017-03-05 15:44:50 +00:00
ADD_GROUP ( " Focus " , " focus_ " ) ;
2018-11-08 14:30:02 +00:00
ADD_PROPERTYI ( PropertyInfo ( Variant : : NODE_PATH , " focus_neighbour_left " , PROPERTY_HINT_NODE_PATH_VALID_TYPES , " Control " ) , " set_focus_neighbour " , " get_focus_neighbour " , MARGIN_LEFT ) ;
ADD_PROPERTYI ( PropertyInfo ( Variant : : NODE_PATH , " focus_neighbour_top " , PROPERTY_HINT_NODE_PATH_VALID_TYPES , " Control " ) , " set_focus_neighbour " , " get_focus_neighbour " , MARGIN_TOP ) ;
ADD_PROPERTYI ( PropertyInfo ( Variant : : NODE_PATH , " focus_neighbour_right " , PROPERTY_HINT_NODE_PATH_VALID_TYPES , " Control " ) , " set_focus_neighbour " , " get_focus_neighbour " , MARGIN_RIGHT ) ;
ADD_PROPERTYI ( PropertyInfo ( Variant : : NODE_PATH , " focus_neighbour_bottom " , PROPERTY_HINT_NODE_PATH_VALID_TYPES , " Control " ) , " set_focus_neighbour " , " get_focus_neighbour " , MARGIN_BOTTOM ) ;
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
ADD_GROUP ( " Mouse " , " mouse_ " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " mouse_filter " , PROPERTY_HINT_ENUM , " Stop,Pass,Ignore " ) , " set_mouse_filter " , " get_mouse_filter " ) ;
2018-09-13 01:38:39 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " mouse_default_cursor_shape " , PROPERTY_HINT_ENUM , " Arrow,Ibeam,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
ADD_GROUP ( " Size Flags " , " size_flags_ " ) ;
2017-07-13 06:50:15 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " size_flags_horizontal " , PROPERTY_HINT_FLAGS , " Fill,Expand,Shrink Center,Shrink End " ) , " set_h_size_flags " , " get_h_size_flags " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " size_flags_vertical " , PROPERTY_HINT_FLAGS , " Fill,Expand,Shrink Center,Shrink End " ) , " set_v_size_flags " , " get_v_size_flags " ) ;
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 18:20:53 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " size_flags_stretch_ratio " , PROPERTY_HINT_RANGE , " 0,128,0.01 " ) , " set_stretch_ratio " , " get_stretch_ratio " ) ;
2017-03-05 15:44:50 +00:00
ADD_GROUP ( " Theme " , " " ) ;
2018-11-08 14:30:02 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : OBJECT , " theme " , PROPERTY_HINT_RESOURCE_TYPE , " Theme " ) , " set_theme " , " get_theme " ) ;
2017-03-05 15:44:50 +00:00
ADD_GROUP ( " " , " " ) ;
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
BIND_CONSTANT ( NOTIFICATION_RESIZED ) ;
BIND_CONSTANT ( NOTIFICATION_MOUSE_ENTER ) ;
BIND_CONSTANT ( NOTIFICATION_MOUSE_EXIT ) ;
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 ) ;
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 ) ;
BIND_ENUM_CONSTANT ( PRESET_WIDE ) ;
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 ) ;
2017-08-20 15:45:01 +00:00
BIND_ENUM_CONSTANT ( SIZE_FILL ) ;
2017-10-21 18:58:02 +00:00
BIND_ENUM_CONSTANT ( SIZE_EXPAND ) ;
2017-08-20 15:45:01 +00:00
BIND_ENUM_CONSTANT ( SIZE_EXPAND_FILL ) ;
BIND_ENUM_CONSTANT ( SIZE_SHRINK_CENTER ) ;
BIND_ENUM_CONSTANT ( SIZE_SHRINK_END ) ;
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
2017-03-05 15:44:50 +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-03-05 15:44:50 +00:00
ADD_SIGNAL ( MethodInfo ( " mouse_entered " ) ) ;
ADD_SIGNAL ( MethodInfo ( " mouse_exited " ) ) ;
ADD_SIGNAL ( MethodInfo ( " focus_entered " ) ) ;
ADD_SIGNAL ( MethodInfo ( " focus_exited " ) ) ;
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
2017-08-29 05:15:46 +00:00
BIND_VMETHOD ( MethodInfo ( Variant : : BOOL , " has_point " , PropertyInfo ( Variant : : VECTOR2 , " point " ) ) ) ;
2014-02-10 01:10:30 +00:00
}
Control : : Control ( ) {
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
data . parent = NULL ;
2016-01-17 01:41:10 +00:00
2017-03-05 15:44:50 +00:00
data . mouse_filter = MOUSE_FILTER_STOP ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
data . RI = NULL ;
data . theme_owner = NULL ;
2020-03-06 17:00:16 +00:00
data . theme_owner_window = NULL ;
2014-02-10 01:10:30 +00:00
data . default_cursor = CURSOR_ARROW ;
2017-03-05 15:44:50 +00:00
data . h_size_flags = SIZE_FILL ;
data . v_size_flags = SIZE_FILL ;
data . expand = 1 ;
data . rotation = 0 ;
data . parent_canvas_item = NULL ;
data . scale = Vector2 ( 1 , 1 ) ;
2020-02-12 17:24:06 +00:00
2017-03-05 15:44:50 +00:00
data . block_minimum_size_adjust = false ;
data . disable_visibility_clip = false ;
2017-07-06 16:26:39 +00:00
data . h_grow = GROW_DIRECTION_END ;
data . v_grow = GROW_DIRECTION_END ;
2018-05-15 20:12:35 +00:00
data . minimum_size_valid = false ;
data . updating_last_minimum_size = false ;
2017-03-05 15:44:50 +00:00
data . clip_contents = false ;
for ( int i = 0 ; i < 4 ; i + + ) {
data . anchor [ i ] = ANCHOR_BEGIN ;
data . margin [ i ] = 0 ;
}
data . focus_mode = FOCUS_NONE ;
}
Control : : ~ Control ( ) {
2014-02-10 01:10:30 +00:00
}