2020-03-04 01:51:12 +00:00
/**************************************************************************/
/* window.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
# include "window.h"
2024-01-30 20:03:28 +00:00
# include "window.compat.inc"
2020-03-04 01:51:12 +00:00
2022-02-12 01:46:22 +00:00
# include "core/config/project_settings.h"
2020-03-04 16:36:09 +00:00
# include "core/debugger/engine_debugger.h"
2022-08-30 11:32:34 +00:00
# include "core/input/shortcut.h"
2020-09-03 11:22:16 +00:00
# include "core/string/translation.h"
2022-08-30 11:32:34 +00:00
# include "core/variant/variant_parser.h"
2020-03-06 17:00:16 +00:00
# include "scene/gui/control.h"
# include "scene/scene_string_names.h"
2022-08-08 16:29:36 +00:00
# include "scene/theme/theme_db.h"
2022-09-02 14:03:23 +00:00
# include "scene/theme/theme_owner.h"
2020-03-20 02:32:09 +00:00
2023-11-17 06:54:07 +00:00
// Editor integration.
int Window : : root_layout_direction = 0 ;
void Window : : set_root_layout_direction ( int p_root_dir ) {
root_layout_direction = p_root_dir ;
}
2022-11-29 20:01:45 +00:00
// Dynamic properties.
bool Window : : _set ( const StringName & p_name , const Variant & p_value ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD_V ( false ) ;
2022-11-29 20:01:45 +00:00
String name = p_name ;
2024-01-23 21:29:45 +00:00
2022-11-29 20:01:45 +00:00
if ( ! name . begins_with ( " theme_override " ) ) {
return false ;
}
if ( p_value . get_type ( ) = = Variant : : NIL | | ( p_value . get_type ( ) = = Variant : : OBJECT & & ( Object * ) p_value = = nullptr ) ) {
if ( name . begins_with ( " theme_override_icons/ " ) ) {
String dname = name . get_slicec ( ' / ' , 1 ) ;
if ( theme_icon_override . has ( dname ) ) {
2023-07-03 19:29:37 +00:00
theme_icon_override [ dname ] - > disconnect_changed ( callable_mp ( this , & Window : : _notify_theme_override_changed ) ) ;
2022-11-29 20:01:45 +00:00
}
theme_icon_override . erase ( dname ) ;
_notify_theme_override_changed ( ) ;
} else if ( name . begins_with ( " theme_override_styles/ " ) ) {
String dname = name . get_slicec ( ' / ' , 1 ) ;
if ( theme_style_override . has ( dname ) ) {
2023-07-03 19:29:37 +00:00
theme_style_override [ dname ] - > disconnect_changed ( callable_mp ( this , & Window : : _notify_theme_override_changed ) ) ;
2022-11-29 20:01:45 +00:00
}
theme_style_override . erase ( dname ) ;
_notify_theme_override_changed ( ) ;
} else if ( name . begins_with ( " theme_override_fonts/ " ) ) {
String dname = name . get_slicec ( ' / ' , 1 ) ;
if ( theme_font_override . has ( dname ) ) {
2023-07-03 19:29:37 +00:00
theme_font_override [ dname ] - > disconnect_changed ( callable_mp ( this , & Window : : _notify_theme_override_changed ) ) ;
2022-11-29 20:01:45 +00:00
}
theme_font_override . erase ( dname ) ;
_notify_theme_override_changed ( ) ;
} else if ( name . begins_with ( " theme_override_font_sizes/ " ) ) {
String dname = name . get_slicec ( ' / ' , 1 ) ;
theme_font_size_override . erase ( dname ) ;
_notify_theme_override_changed ( ) ;
} else if ( name . begins_with ( " theme_override_colors/ " ) ) {
String dname = name . get_slicec ( ' / ' , 1 ) ;
theme_color_override . erase ( dname ) ;
_notify_theme_override_changed ( ) ;
} else if ( name . begins_with ( " theme_override_constants/ " ) ) {
String dname = name . get_slicec ( ' / ' , 1 ) ;
theme_constant_override . erase ( dname ) ;
_notify_theme_override_changed ( ) ;
} else {
return false ;
}
} else {
if ( name . begins_with ( " theme_override_icons/ " ) ) {
String dname = name . get_slicec ( ' / ' , 1 ) ;
add_theme_icon_override ( dname , p_value ) ;
} else if ( name . begins_with ( " theme_override_styles/ " ) ) {
String dname = name . get_slicec ( ' / ' , 1 ) ;
add_theme_style_override ( dname , p_value ) ;
} else if ( name . begins_with ( " theme_override_fonts/ " ) ) {
String dname = name . get_slicec ( ' / ' , 1 ) ;
add_theme_font_override ( dname , p_value ) ;
} else if ( name . begins_with ( " theme_override_font_sizes/ " ) ) {
String dname = name . get_slicec ( ' / ' , 1 ) ;
add_theme_font_size_override ( dname , p_value ) ;
} else if ( name . begins_with ( " theme_override_colors/ " ) ) {
String dname = name . get_slicec ( ' / ' , 1 ) ;
add_theme_color_override ( dname , p_value ) ;
} else if ( name . begins_with ( " theme_override_constants/ " ) ) {
String dname = name . get_slicec ( ' / ' , 1 ) ;
add_theme_constant_override ( dname , p_value ) ;
} else {
return false ;
}
}
return true ;
}
bool Window : : _get ( const StringName & p_name , Variant & r_ret ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-11-29 20:01:45 +00:00
String sname = p_name ;
2024-01-23 21:29:45 +00:00
2022-11-29 20:01:45 +00:00
if ( ! sname . begins_with ( " theme_override " ) ) {
return false ;
}
if ( sname . begins_with ( " theme_override_icons/ " ) ) {
String name = sname . get_slicec ( ' / ' , 1 ) ;
r_ret = theme_icon_override . has ( name ) ? Variant ( theme_icon_override [ name ] ) : Variant ( ) ;
} else if ( sname . begins_with ( " theme_override_styles/ " ) ) {
String name = sname . get_slicec ( ' / ' , 1 ) ;
r_ret = theme_style_override . has ( name ) ? Variant ( theme_style_override [ name ] ) : Variant ( ) ;
} else if ( sname . begins_with ( " theme_override_fonts/ " ) ) {
String name = sname . get_slicec ( ' / ' , 1 ) ;
r_ret = theme_font_override . has ( name ) ? Variant ( theme_font_override [ name ] ) : Variant ( ) ;
} else if ( sname . begins_with ( " theme_override_font_sizes/ " ) ) {
String name = sname . get_slicec ( ' / ' , 1 ) ;
r_ret = theme_font_size_override . has ( name ) ? Variant ( theme_font_size_override [ name ] ) : Variant ( ) ;
} else if ( sname . begins_with ( " theme_override_colors/ " ) ) {
String name = sname . get_slicec ( ' / ' , 1 ) ;
r_ret = theme_color_override . has ( name ) ? Variant ( theme_color_override [ name ] ) : Variant ( ) ;
} else if ( sname . begins_with ( " theme_override_constants/ " ) ) {
String name = sname . get_slicec ( ' / ' , 1 ) ;
r_ret = theme_constant_override . has ( name ) ? Variant ( theme_constant_override [ name ] ) : Variant ( ) ;
} else {
return false ;
}
return true ;
}
void Window : : _get_property_list ( List < PropertyInfo > * p_list ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD ;
2022-11-29 20:01:45 +00:00
Ref < Theme > default_theme = ThemeDB : : get_singleton ( ) - > get_default_theme ( ) ;
2023-03-27 10:06:07 +00:00
p_list - > push_back ( PropertyInfo ( Variant : : NIL , GNAME ( " Theme Overrides " , " theme_override_ " ) , PROPERTY_HINT_NONE , " theme_override_ " , PROPERTY_USAGE_GROUP ) ) ;
2022-11-29 20:01:45 +00:00
{
List < StringName > names ;
default_theme - > get_color_list ( get_class_name ( ) , & names ) ;
for ( const StringName & E : names ) {
uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE ;
if ( theme_color_override . has ( E ) ) {
usage | = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED ;
}
2023-03-27 10:06:07 +00:00
p_list - > push_back ( PropertyInfo ( Variant : : COLOR , PNAME ( " theme_override_colors " ) + String ( " / " ) + E , PROPERTY_HINT_NONE , " " , usage ) ) ;
2022-11-29 20:01:45 +00:00
}
}
{
List < StringName > names ;
default_theme - > get_constant_list ( get_class_name ( ) , & names ) ;
for ( const StringName & E : names ) {
uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE ;
if ( theme_constant_override . has ( E ) ) {
usage | = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED ;
}
2023-03-27 10:06:07 +00:00
p_list - > push_back ( PropertyInfo ( Variant : : INT , PNAME ( " theme_override_constants " ) + String ( " / " ) + E , PROPERTY_HINT_RANGE , " -16384,16384 " , usage ) ) ;
2022-11-29 20:01:45 +00:00
}
}
{
List < StringName > names ;
default_theme - > get_font_list ( get_class_name ( ) , & names ) ;
for ( const StringName & E : names ) {
uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE ;
if ( theme_font_override . has ( E ) ) {
usage | = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED ;
}
2023-03-27 10:06:07 +00:00
p_list - > push_back ( PropertyInfo ( Variant : : OBJECT , PNAME ( " theme_override_fonts " ) + String ( " / " ) + E , PROPERTY_HINT_RESOURCE_TYPE , " Font " , usage ) ) ;
2022-11-29 20:01:45 +00:00
}
}
{
List < StringName > names ;
default_theme - > get_font_size_list ( get_class_name ( ) , & names ) ;
for ( const StringName & E : names ) {
uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE ;
if ( theme_font_size_override . has ( E ) ) {
usage | = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED ;
}
2023-03-27 10:06:07 +00:00
p_list - > push_back ( PropertyInfo ( Variant : : INT , PNAME ( " theme_override_font_sizes " ) + String ( " / " ) + E , PROPERTY_HINT_RANGE , " 1,256,1,or_greater,suffix:px " , usage ) ) ;
2022-11-29 20:01:45 +00:00
}
}
{
List < StringName > names ;
default_theme - > get_icon_list ( get_class_name ( ) , & names ) ;
for ( const StringName & E : names ) {
uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE ;
if ( theme_icon_override . has ( E ) ) {
usage | = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED ;
}
2023-03-27 10:06:07 +00:00
p_list - > push_back ( PropertyInfo ( Variant : : OBJECT , PNAME ( " theme_override_icons " ) + String ( " / " ) + E , PROPERTY_HINT_RESOURCE_TYPE , " Texture2D " , usage ) ) ;
2022-11-29 20:01:45 +00:00
}
}
{
List < StringName > names ;
default_theme - > get_stylebox_list ( get_class_name ( ) , & names ) ;
for ( const StringName & E : names ) {
uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE ;
if ( theme_style_override . has ( E ) ) {
usage | = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED ;
}
2023-03-27 10:06:07 +00:00
p_list - > push_back ( PropertyInfo ( Variant : : OBJECT , PNAME ( " theme_override_styles " ) + String ( " / " ) + E , PROPERTY_HINT_RESOURCE_TYPE , " StyleBox " , usage ) ) ;
2022-11-29 20:01:45 +00:00
}
}
}
void Window : : _validate_property ( PropertyInfo & p_property ) const {
2023-01-04 22:00:02 +00:00
if ( p_property . name = = " position " & & initial_position ! = WINDOW_INITIAL_POSITION_ABSOLUTE ) {
p_property . usage = PROPERTY_USAGE_NONE ;
}
2023-01-19 08:28:53 +00:00
if ( p_property . name = = " current_screen " & & initial_position ! = WINDOW_INITIAL_POSITION_CENTER_OTHER_SCREEN ) {
2023-01-04 22:00:02 +00:00
p_property . usage = PROPERTY_USAGE_NONE ;
}
2022-11-29 20:01:45 +00:00
if ( p_property . name = = " theme_type_variation " ) {
List < StringName > names ;
// Only the default theme and the project theme are used for the list of options.
// This is an imposed limitation to simplify the logic needed to leverage those options.
ThemeDB : : get_singleton ( ) - > get_default_theme ( ) - > get_type_variation_list ( get_class_name ( ) , & names ) ;
if ( ThemeDB : : get_singleton ( ) - > get_project_theme ( ) . is_valid ( ) ) {
ThemeDB : : get_singleton ( ) - > get_project_theme ( ) - > get_type_variation_list ( get_class_name ( ) , & names ) ;
}
names . sort_custom < StringName : : AlphCompare > ( ) ;
Vector < StringName > unique_names ;
String hint_string ;
for ( const StringName & E : names ) {
// Skip duplicate values.
if ( unique_names . has ( E ) ) {
continue ;
}
hint_string + = String ( E ) + " , " ;
unique_names . append ( E ) ;
}
p_property . hint_string = hint_string ;
}
}
//
2020-03-04 01:51:12 +00:00
void Window : : set_title ( const String & p_title ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-03-04 01:51:12 +00:00
title = p_title ;
2023-08-08 08:31:56 +00:00
tr_title = atr ( p_title ) ;
# ifdef DEBUG_ENABLED
if ( window_id = = DisplayServer : : MAIN_WINDOW_ID ) {
// Append a suffix to the window title to denote that the project is running
// from a debug build (including the editor). Since this results in lower performance,
// this should be clearly presented to the user.
tr_title = vformat ( " %s (DEBUG) " , tr_title ) ;
}
# endif
2020-03-14 16:06:39 +00:00
if ( embedder ) {
embedder - > _sub_window_update ( this ) ;
} else if ( window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
2022-01-21 09:08:07 +00:00
DisplayServer : : get_singleton ( ) - > window_set_title ( tr_title , window_id ) ;
2023-11-30 14:04:00 +00:00
if ( keep_title_visible ) {
Size2i title_size = DisplayServer : : get_singleton ( ) - > window_get_title_size ( tr_title , window_id ) ;
Size2i size_limit = get_clamped_minimum_size ( ) ;
if ( title_size . x > size_limit . x | | title_size . y > size_limit . y ) {
_update_window_size ( ) ;
}
}
2020-03-14 16:06:39 +00:00
}
2020-03-04 01:51:12 +00:00
}
2020-05-14 12:29:06 +00:00
2020-03-04 01:51:12 +00:00
String Window : : get_title ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( String ( ) ) ;
2020-03-04 01:51:12 +00:00
return title ;
}
2023-01-04 22:00:02 +00:00
void Window : : set_initial_position ( Window : : WindowInitialPosition p_initial_position ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2023-01-04 22:00:02 +00:00
initial_position = p_initial_position ;
notify_property_list_changed ( ) ;
}
Window : : WindowInitialPosition Window : : get_initial_position ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( WINDOW_INITIAL_POSITION_ABSOLUTE ) ;
2023-01-04 22:00:02 +00:00
return initial_position ;
}
2020-03-04 01:51:12 +00:00
void Window : : set_current_screen ( int p_screen ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-03-04 01:51:12 +00:00
current_screen = p_screen ;
2020-05-14 14:41:43 +00:00
if ( window_id = = DisplayServer : : INVALID_WINDOW_ID ) {
2020-03-04 01:51:12 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2020-03-04 01:51:12 +00:00
DisplayServer : : get_singleton ( ) - > window_set_current_screen ( p_screen , window_id ) ;
}
2020-05-14 12:29:06 +00:00
2020-03-04 01:51:12 +00:00
int Window : : get_current_screen ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( 0 ) ;
2020-03-04 01:51:12 +00:00
if ( window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
current_screen = DisplayServer : : get_singleton ( ) - > window_get_current_screen ( window_id ) ;
}
return current_screen ;
}
void Window : : set_position ( const Point2i & p_position ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-03-04 01:51:12 +00:00
position = p_position ;
2020-03-14 16:06:39 +00:00
if ( embedder ) {
embedder - > _sub_window_update ( this ) ;
} else if ( window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
DisplayServer : : get_singleton ( ) - > window_set_position ( p_position , window_id ) ;
}
2020-03-04 01:51:12 +00:00
}
2020-05-14 12:29:06 +00:00
2020-03-04 01:51:12 +00:00
Point2i Window : : get_position ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Point2i ( ) ) ;
2020-03-04 01:51:12 +00:00
return position ;
}
2023-08-26 07:30:31 +00:00
void Window : : move_to_center ( ) {
ERR_MAIN_THREAD_GUARD ;
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
Rect2 parent_rect ;
if ( is_embedded ( ) ) {
parent_rect = get_embedder ( ) - > get_visible_rect ( ) ;
} else {
int parent_screen = DisplayServer : : get_singleton ( ) - > window_get_current_screen ( get_window_id ( ) ) ;
parent_rect . position = DisplayServer : : get_singleton ( ) - > screen_get_position ( parent_screen ) ;
parent_rect . size = DisplayServer : : get_singleton ( ) - > screen_get_size ( parent_screen ) ;
}
if ( parent_rect ! = Rect2 ( ) ) {
set_position ( parent_rect . position + ( parent_rect . size - get_size ( ) ) / 2 ) ;
}
}
2020-03-04 01:51:12 +00:00
void Window : : set_size ( const Size2i & p_size ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-03-04 01:51:12 +00:00
size = p_size ;
2020-03-14 16:06:39 +00:00
_update_window_size ( ) ;
2020-03-04 01:51:12 +00:00
}
2020-05-14 12:29:06 +00:00
2020-03-04 01:51:12 +00:00
Size2i Window : : get_size ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Size2i ( ) ) ;
2020-03-04 01:51:12 +00:00
return size ;
}
2021-11-20 08:04:57 +00:00
void Window : : reset_size ( ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2021-11-20 08:04:57 +00:00
set_size ( Size2i ( ) ) ;
}
2022-11-30 08:28:16 +00:00
Point2i Window : : get_position_with_decorations ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Point2i ( ) ) ;
2020-03-04 01:51:12 +00:00
if ( window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
2022-11-30 08:28:16 +00:00
return DisplayServer : : get_singleton ( ) - > window_get_position_with_decorations ( window_id ) ;
}
return position ;
}
Size2i Window : : get_size_with_decorations ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Size2i ( ) ) ;
2022-11-30 08:28:16 +00:00
if ( window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
return DisplayServer : : get_singleton ( ) - > window_get_size_with_decorations ( window_id ) ;
2020-03-04 01:51:12 +00:00
}
return size ;
}
2022-06-18 10:52:30 +00:00
Size2i Window : : _clamp_limit_size ( const Size2i & p_limit_size ) {
// Force window limits to respect size limitations of rendering server.
Size2i max_window_size = RS : : get_singleton ( ) - > get_maximum_viewport_size ( ) ;
if ( max_window_size ! = Size2i ( ) ) {
return p_limit_size . clamp ( Vector2i ( ) , max_window_size ) ;
} else {
return p_limit_size . max ( Vector2i ( ) ) ;
}
}
void Window : : _validate_limit_size ( ) {
// When max_size is invalid, max_size_used falls back to respect size limitations of rendering server.
bool max_size_valid = ( max_size . x > 0 | | max_size . y > 0 ) & & max_size . x > = min_size . x & & max_size . y > = min_size . y ;
max_size_used = max_size_valid ? max_size : RS : : get_singleton ( ) - > get_maximum_viewport_size ( ) ;
}
2020-03-04 01:51:12 +00:00
void Window : : set_max_size ( const Size2i & p_max_size ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-06-18 10:52:30 +00:00
Size2i max_size_clamped = _clamp_limit_size ( p_max_size ) ;
if ( max_size = = max_size_clamped ) {
return ;
}
max_size = max_size_clamped ;
_validate_limit_size ( ) ;
2020-03-14 16:06:39 +00:00
_update_window_size ( ) ;
2020-03-04 01:51:12 +00:00
}
2020-03-14 16:06:39 +00:00
2020-03-07 16:02:54 +00:00
Size2i Window : : get_max_size ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Size2i ( ) ) ;
2020-03-07 16:02:54 +00:00
return max_size ;
2020-03-04 01:51:12 +00:00
}
void Window : : set_min_size ( const Size2i & p_min_size ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-06-18 10:52:30 +00:00
Size2i min_size_clamped = _clamp_limit_size ( p_min_size ) ;
if ( min_size = = min_size_clamped ) {
return ;
}
min_size = min_size_clamped ;
_validate_limit_size ( ) ;
2020-03-14 16:06:39 +00:00
_update_window_size ( ) ;
2020-03-04 01:51:12 +00:00
}
2020-03-07 16:02:54 +00:00
2020-03-04 01:51:12 +00:00
Size2i Window : : get_min_size ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Size2i ( ) ) ;
2020-03-04 01:51:12 +00:00
return min_size ;
}
void Window : : set_mode ( Mode p_mode ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-03-04 01:51:12 +00:00
mode = p_mode ;
2020-03-14 16:06:39 +00:00
if ( embedder ) {
embedder - > _sub_window_update ( this ) ;
} else if ( window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
DisplayServer : : get_singleton ( ) - > window_set_mode ( DisplayServer : : WindowMode ( p_mode ) , window_id ) ;
}
2020-03-04 01:51:12 +00:00
}
Window : : Mode Window : : get_mode ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( MODE_WINDOWED ) ;
2020-03-04 01:51:12 +00:00
if ( window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
mode = ( Mode ) DisplayServer : : get_singleton ( ) - > window_get_mode ( window_id ) ;
}
return mode ;
}
void Window : : set_flag ( Flags p_flag , bool p_enabled ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-03-04 01:51:12 +00:00
ERR_FAIL_INDEX ( p_flag , FLAG_MAX ) ;
flags [ p_flag ] = p_enabled ;
2020-03-14 16:06:39 +00:00
2024-02-02 07:46:01 +00:00
if ( p_flag = = FLAG_TRANSPARENT ) {
set_transparent_background ( p_enabled ) ;
}
2020-03-14 16:06:39 +00:00
if ( embedder ) {
embedder - > _sub_window_update ( this ) ;
} else if ( window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
2022-10-11 05:39:36 +00:00
if ( ! is_in_edited_scene_root ( ) ) {
2022-06-09 08:59:01 +00:00
DisplayServer : : get_singleton ( ) - > window_set_flag ( DisplayServer : : WindowFlags ( p_flag ) , p_enabled , window_id ) ;
}
2020-03-14 16:06:39 +00:00
}
2020-03-04 01:51:12 +00:00
}
bool Window : : get_flag ( Flags p_flag ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2020-03-04 01:51:12 +00:00
ERR_FAIL_INDEX_V ( p_flag , FLAG_MAX , false ) ;
if ( window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
2022-10-11 05:39:36 +00:00
if ( ! is_in_edited_scene_root ( ) ) {
2022-06-09 08:59:01 +00:00
flags [ p_flag ] = DisplayServer : : get_singleton ( ) - > window_get_flag ( DisplayServer : : WindowFlags ( p_flag ) , window_id ) ;
}
2020-03-04 01:51:12 +00:00
}
return flags [ p_flag ] ;
}
bool Window : : is_maximize_allowed ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2020-03-04 01:51:12 +00:00
if ( window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
return DisplayServer : : get_singleton ( ) - > window_is_maximize_allowed ( window_id ) ;
}
return true ;
}
void Window : : request_attention ( ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-03-04 01:51:12 +00:00
if ( window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
DisplayServer : : get_singleton ( ) - > window_request_attention ( window_id ) ;
}
}
2020-05-14 12:29:06 +00:00
2023-10-08 18:41:22 +00:00
# ifndef DISABLE_DEPRECATED
2020-03-04 01:51:12 +00:00
void Window : : move_to_foreground ( ) {
2023-10-08 18:41:22 +00:00
WARN_DEPRECATED_MSG ( R " *(The " move_to_foreground ( ) " method is deprecated, use " grab_focus ( ) " instead.)* " ) ;
grab_focus ( ) ;
2020-03-04 01:51:12 +00:00
}
2023-10-08 18:41:22 +00:00
# endif // DISABLE_DEPRECATED
2020-03-04 01:51:12 +00:00
bool Window : : can_draw ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2020-03-04 01:51:12 +00:00
if ( ! is_inside_tree ( ) ) {
return false ;
}
if ( window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
return DisplayServer : : get_singleton ( ) - > window_can_draw ( window_id ) ;
}
2020-03-14 16:06:39 +00:00
return visible ;
2020-03-04 01:51:12 +00:00
}
void Window : : set_ime_active ( bool p_active ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-03-04 01:51:12 +00:00
if ( window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
DisplayServer : : get_singleton ( ) - > window_set_ime_active ( p_active , window_id ) ;
}
}
2020-05-14 12:29:06 +00:00
2020-03-04 01:51:12 +00:00
void Window : : set_ime_position ( const Point2i & p_pos ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-03-04 01:51:12 +00:00
if ( window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
DisplayServer : : get_singleton ( ) - > window_set_ime_position ( p_pos , window_id ) ;
}
}
bool Window : : is_embedded ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2023-02-05 16:35:39 +00:00
return get_embedder ( ) ! = nullptr ;
2020-03-04 01:51:12 +00:00
}
2022-10-11 05:39:36 +00:00
bool Window : : is_in_edited_scene_root ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-10-11 05:39:36 +00:00
# ifdef TOOLS_ENABLED
2023-03-17 00:58:30 +00:00
return is_part_of_edited_scene ( ) ;
2022-10-11 05:39:36 +00:00
# else
return false ;
# endif
}
2020-03-04 01:51:12 +00:00
void Window : : _make_window ( ) {
ERR_FAIL_COND ( window_id ! = DisplayServer : : INVALID_WINDOW_ID ) ;
2023-12-22 16:50:21 +00:00
if ( transient & & transient_to_focused ) {
_make_transient ( ) ;
}
2020-03-04 01:51:12 +00:00
uint32_t f = 0 ;
for ( int i = 0 ; i < FLAG_MAX ; i + + ) {
if ( flags [ i ] ) {
f | = ( 1 < < i ) ;
}
}
2020-03-14 16:06:39 +00:00
2021-06-19 15:44:59 +00:00
DisplayServer : : VSyncMode vsync_mode = DisplayServer : : get_singleton ( ) - > window_get_vsync_mode ( DisplayServer : : MAIN_WINDOW_ID ) ;
2023-01-04 22:00:02 +00:00
Rect2i window_rect ;
if ( initial_position = = WINDOW_INITIAL_POSITION_ABSOLUTE ) {
window_rect = Rect2i ( position , size ) ;
2023-01-19 08:28:53 +00:00
} else if ( initial_position = = WINDOW_INITIAL_POSITION_CENTER_PRIMARY_SCREEN ) {
window_rect = Rect2i ( DisplayServer : : get_singleton ( ) - > screen_get_position ( DisplayServer : : SCREEN_PRIMARY ) + ( DisplayServer : : get_singleton ( ) - > screen_get_size ( DisplayServer : : SCREEN_PRIMARY ) - size ) / 2 , size ) ;
} else if ( initial_position = = WINDOW_INITIAL_POSITION_CENTER_MAIN_WINDOW_SCREEN ) {
window_rect = Rect2i ( DisplayServer : : get_singleton ( ) - > screen_get_position ( DisplayServer : : SCREEN_OF_MAIN_WINDOW ) + ( DisplayServer : : get_singleton ( ) - > screen_get_size ( DisplayServer : : SCREEN_OF_MAIN_WINDOW ) - size ) / 2 , size ) ;
} else if ( initial_position = = WINDOW_INITIAL_POSITION_CENTER_OTHER_SCREEN ) {
2023-01-04 22:00:02 +00:00
window_rect = Rect2i ( DisplayServer : : get_singleton ( ) - > screen_get_position ( current_screen ) + ( DisplayServer : : get_singleton ( ) - > screen_get_size ( current_screen ) - size ) / 2 , size ) ;
2023-03-21 11:08:46 +00:00
} else if ( initial_position = = WINDOW_INITIAL_POSITION_CENTER_SCREEN_WITH_MOUSE_FOCUS ) {
window_rect = Rect2i ( DisplayServer : : get_singleton ( ) - > screen_get_position ( DisplayServer : : SCREEN_WITH_MOUSE_FOCUS ) + ( DisplayServer : : get_singleton ( ) - > screen_get_size ( DisplayServer : : SCREEN_WITH_MOUSE_FOCUS ) - size ) / 2 , size ) ;
} else if ( initial_position = = WINDOW_INITIAL_POSITION_CENTER_SCREEN_WITH_KEYBOARD_FOCUS ) {
window_rect = Rect2i ( DisplayServer : : get_singleton ( ) - > screen_get_position ( DisplayServer : : SCREEN_WITH_KEYBOARD_FOCUS ) + ( DisplayServer : : get_singleton ( ) - > screen_get_size ( DisplayServer : : SCREEN_WITH_KEYBOARD_FOCUS ) - size ) / 2 , size ) ;
2023-01-04 22:00:02 +00:00
}
2023-03-21 11:08:46 +00:00
2023-01-04 22:00:02 +00:00
window_id = DisplayServer : : get_singleton ( ) - > create_sub_window ( DisplayServer : : WindowMode ( mode ) , vsync_mode , f , window_rect ) ;
2020-03-04 01:51:12 +00:00
ERR_FAIL_COND ( window_id = = DisplayServer : : INVALID_WINDOW_ID ) ;
2022-08-04 20:11:32 +00:00
DisplayServer : : get_singleton ( ) - > window_set_max_size ( Size2i ( ) , window_id ) ;
DisplayServer : : get_singleton ( ) - > window_set_min_size ( Size2i ( ) , window_id ) ;
2023-01-15 10:05:25 +00:00
DisplayServer : : get_singleton ( ) - > window_set_mouse_passthrough ( mpath , window_id ) ;
2022-01-21 09:08:07 +00:00
DisplayServer : : get_singleton ( ) - > window_set_title ( tr_title , window_id ) ;
2020-03-24 23:15:35 +00:00
DisplayServer : : get_singleton ( ) - > window_attach_instance_id ( get_instance_id ( ) , window_id ) ;
2022-10-11 05:39:36 +00:00
if ( is_in_edited_scene_root ( ) ) {
2022-06-09 08:59:01 +00:00
DisplayServer : : get_singleton ( ) - > window_set_exclusive ( window_id , false ) ;
2022-10-11 05:39:36 +00:00
} else {
DisplayServer : : get_singleton ( ) - > window_set_exclusive ( window_id , exclusive ) ;
2022-06-09 08:59:01 +00:00
}
2020-03-04 01:51:12 +00:00
2020-03-14 16:06:39 +00:00
_update_window_size ( ) ;
2020-03-04 19:03:30 +00:00
if ( transient_parent & & transient_parent - > window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
DisplayServer : : get_singleton ( ) - > window_set_transient ( window_id , transient_parent - > window_id ) ;
}
2022-11-02 14:23:25 +00:00
if ( transient_parent ) {
for ( const Window * E : transient_children ) {
if ( E - > window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
DisplayServer : : get_singleton ( ) - > window_set_transient ( E - > window_id , transient_parent - > window_id ) ;
}
2020-03-04 19:03:30 +00:00
}
}
2020-03-14 16:06:39 +00:00
2020-08-22 15:50:06 +00:00
_update_window_callbacks ( ) ;
2020-03-27 18:21:27 +00:00
RS : : get_singleton ( ) - > viewport_set_update_mode ( get_viewport_rid ( ) , RS : : VIEWPORT_UPDATE_WHEN_VISIBLE ) ;
2020-08-21 07:39:30 +00:00
DisplayServer : : get_singleton ( ) - > show_window ( window_id ) ;
2020-03-04 01:51:12 +00:00
}
2020-05-14 12:29:06 +00:00
2020-03-04 01:51:12 +00:00
void Window : : _update_from_window ( ) {
ERR_FAIL_COND ( window_id = = DisplayServer : : INVALID_WINDOW_ID ) ;
mode = ( Mode ) DisplayServer : : get_singleton ( ) - > window_get_mode ( window_id ) ;
for ( int i = 0 ; i < FLAG_MAX ; i + + ) {
flags [ i ] = DisplayServer : : get_singleton ( ) - > window_get_flag ( DisplayServer : : WindowFlags ( i ) , window_id ) ;
}
}
void Window : : _clear_window ( ) {
ERR_FAIL_COND ( window_id = = DisplayServer : : INVALID_WINDOW_ID ) ;
2020-03-04 19:03:30 +00:00
2023-06-15 07:53:31 +00:00
bool had_focus = has_focus ( ) ;
2020-03-04 19:03:30 +00:00
if ( transient_parent & & transient_parent - > window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
DisplayServer : : get_singleton ( ) - > window_set_transient ( window_id , DisplayServer : : INVALID_WINDOW_ID ) ;
}
2022-05-18 23:43:40 +00:00
for ( const Window * E : transient_children ) {
if ( E - > window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
DisplayServer : : get_singleton ( ) - > window_set_transient ( E - > window_id , DisplayServer : : INVALID_WINDOW_ID ) ;
2020-03-04 19:03:30 +00:00
}
}
2020-03-04 01:51:12 +00:00
_update_from_window ( ) ;
2020-03-14 16:06:39 +00:00
2020-03-04 01:51:12 +00:00
DisplayServer : : get_singleton ( ) - > delete_sub_window ( window_id ) ;
window_id = DisplayServer : : INVALID_WINDOW_ID ;
2020-03-14 16:06:39 +00:00
2022-01-15 18:47:34 +00:00
// If closing window was focused and has a parent, return focus.
2023-06-15 07:53:31 +00:00
if ( had_focus & & transient_parent ) {
2022-01-15 18:47:34 +00:00
transient_parent - > grab_focus ( ) ;
}
2020-03-12 23:12:34 +00:00
_update_viewport_size ( ) ;
2020-03-27 18:21:27 +00:00
RS : : get_singleton ( ) - > viewport_set_update_mode ( get_viewport_rid ( ) , RS : : VIEWPORT_UPDATE_DISABLED ) ;
2023-12-22 16:50:21 +00:00
if ( transient & & transient_to_focused ) {
_clear_transient ( ) ;
}
2020-03-04 01:51:12 +00:00
}
2020-03-14 16:06:39 +00:00
void Window : : _rect_changed_callback ( const Rect2i & p_callback ) {
//we must always accept this as the truth
if ( size = = p_callback . size & & position = = p_callback . position ) {
return ;
}
position = p_callback . position ;
if ( size ! = p_callback . size ) {
size = p_callback . size ;
_update_viewport_size ( ) ;
}
2020-03-04 01:51:12 +00:00
}
2020-03-04 16:36:09 +00:00
void Window : : _propagate_window_notification ( Node * p_node , int p_notification ) {
p_node - > notification ( p_notification ) ;
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
Node * child = p_node - > get_child ( i ) ;
Window * window = Object : : cast_to < Window > ( child ) ;
if ( window ) {
2021-08-17 05:07:53 +00:00
continue ;
2020-03-04 16:36:09 +00:00
}
_propagate_window_notification ( child , p_notification ) ;
}
}
void Window : : _event_callback ( DisplayServer : : WindowEvent p_event ) {
switch ( p_event ) {
case DisplayServer : : WINDOW_EVENT_MOUSE_ENTER : {
2023-11-27 06:47:43 +00:00
if ( ! is_inside_tree ( ) ) {
return ;
}
2023-01-06 20:48:20 +00:00
Window * root = get_tree ( ) - > get_root ( ) ;
2023-08-02 19:17:42 +00:00
if ( root - > gui . windowmanager_window_over ) {
# ifdef DEV_ENABLED
WARN_PRINT_ONCE ( " Entering a window while a window is hovered should never happen in DisplayServer. " ) ;
# endif // DEV_ENABLED
root - > gui . windowmanager_window_over - > _event_callback ( DisplayServer : : WINDOW_EVENT_MOUSE_EXIT ) ;
}
_propagate_window_notification ( this , NOTIFICATION_WM_MOUSE_ENTER ) ;
2023-01-06 20:48:20 +00:00
root - > gui . windowmanager_window_over = this ;
2023-08-06 11:07:28 +00:00
mouse_in_window = true ;
2022-08-23 09:14:07 +00:00
if ( DisplayServer : : get_singleton ( ) - > has_feature ( DisplayServer : : FEATURE_CURSOR_SHAPE ) ) {
DisplayServer : : get_singleton ( ) - > cursor_set_shape ( DisplayServer : : CURSOR_ARROW ) ; //restore cursor shape
}
2020-03-04 16:36:09 +00:00
} break ;
case DisplayServer : : WINDOW_EVENT_MOUSE_EXIT : {
2023-11-27 06:47:43 +00:00
if ( ! is_inside_tree ( ) ) {
return ;
}
2024-03-26 19:28:34 +00:00
// Ensure keeping the order of input events and window events when input events are buffered or accumulated.
Input : : get_singleton ( ) - > flush_buffered_events ( ) ;
2023-01-06 20:48:20 +00:00
Window * root = get_tree ( ) - > get_root ( ) ;
2023-08-02 19:17:42 +00:00
if ( ! root - > gui . windowmanager_window_over ) {
# ifdef DEV_ENABLED
WARN_PRINT_ONCE ( " Exiting a window while no window is hovered should never happen in DisplayServer. " ) ;
# endif // DEV_ENABLED
return ;
}
2023-08-06 11:07:28 +00:00
mouse_in_window = false ;
2023-01-06 20:48:20 +00:00
root - > gui . windowmanager_window_over - > _mouse_leave_viewport ( ) ;
root - > gui . windowmanager_window_over = nullptr ;
2020-03-04 16:36:09 +00:00
_propagate_window_notification ( this , NOTIFICATION_WM_MOUSE_EXIT ) ;
} break ;
case DisplayServer : : WINDOW_EVENT_FOCUS_IN : {
2020-03-06 17:00:16 +00:00
focused = true ;
2020-06-29 23:47:18 +00:00
_propagate_window_notification ( this , NOTIFICATION_WM_WINDOW_FOCUS_IN ) ;
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " focus_entered " ) ) ;
2020-03-06 17:00:16 +00:00
2020-03-04 16:36:09 +00:00
} break ;
case DisplayServer : : WINDOW_EVENT_FOCUS_OUT : {
2020-03-06 17:00:16 +00:00
focused = false ;
2020-06-29 23:47:18 +00:00
_propagate_window_notification ( this , NOTIFICATION_WM_WINDOW_FOCUS_OUT ) ;
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " focus_exited " ) ) ;
2020-03-04 16:36:09 +00:00
} break ;
case DisplayServer : : WINDOW_EVENT_CLOSE_REQUEST : {
2020-03-06 17:00:16 +00:00
if ( exclusive_child ! = nullptr ) {
break ; //has an exclusive child, can't get events until child is closed
}
2020-03-04 16:36:09 +00:00
_propagate_window_notification ( this , NOTIFICATION_WM_CLOSE_REQUEST ) ;
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " close_requested " ) ) ;
2020-03-04 16:36:09 +00:00
} break ;
case DisplayServer : : WINDOW_EVENT_GO_BACK_REQUEST : {
_propagate_window_notification ( this , NOTIFICATION_WM_GO_BACK_REQUEST ) ;
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " go_back_requested " ) ) ;
2020-03-04 16:36:09 +00:00
} break ;
2020-03-07 16:02:54 +00:00
case DisplayServer : : WINDOW_EVENT_DPI_CHANGE : {
2020-07-03 10:06:03 +00:00
_update_viewport_size ( ) ;
2020-03-07 16:02:54 +00:00
_propagate_window_notification ( this , NOTIFICATION_WM_DPI_CHANGE ) ;
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " dpi_changed " ) ) ;
2020-03-07 16:02:54 +00:00
} break ;
2022-09-22 09:06:11 +00:00
case DisplayServer : : WINDOW_EVENT_TITLEBAR_CHANGE : {
emit_signal ( SNAME ( " titlebar_changed " ) ) ;
} break ;
2020-03-04 16:36:09 +00:00
}
}
2022-09-29 21:45:51 +00:00
void Window : : update_mouse_cursor_state ( ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-09-29 21:45:51 +00:00
// Update states based on mouse cursor position.
// This includes updated mouse_enter or mouse_exit signals or the current mouse cursor shape.
// These details are set in Viewport::_gui_input_event. To instantly
// see the changes in the viewport, we need to trigger a mouse motion event.
// This function should be called whenever scene tree changes affect the mouse cursor.
2022-03-10 17:44:28 +00:00
Ref < InputEventMouseMotion > mm ;
Vector2 pos = get_mouse_position ( ) ;
Transform2D xform = get_global_canvas_transform ( ) . affine_inverse ( ) ;
mm . instantiate ( ) ;
mm - > set_position ( pos ) ;
mm - > set_global_position ( xform . xform ( pos ) ) ;
2023-02-04 22:16:54 +00:00
mm - > set_device ( InputEvent : : DEVICE_ID_INTERNAL ) ;
2022-03-10 17:44:28 +00:00
push_input ( mm ) ;
}
2020-03-06 17:00:16 +00:00
void Window : : show ( ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-03-06 17:00:16 +00:00
set_visible ( true ) ;
}
2020-05-14 12:29:06 +00:00
2020-03-06 17:00:16 +00:00
void Window : : hide ( ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-03-06 17:00:16 +00:00
set_visible ( false ) ;
}
2020-03-04 01:51:12 +00:00
void Window : : set_visible ( bool p_visible ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-03-04 01:51:12 +00:00
if ( visible = = p_visible ) {
return ;
}
if ( ! is_inside_tree ( ) ) {
2023-01-15 15:04:05 +00:00
visible = p_visible ;
2020-03-04 01:51:12 +00:00
return ;
}
2023-09-28 09:40:18 +00:00
ERR_FAIL_NULL_MSG ( get_parent ( ) , " Can't change visibility of main window. " ) ;
2020-03-04 01:51:12 +00:00
2023-01-15 15:04:05 +00:00
visible = p_visible ;
// Stop any queued resizing, as the window will be resized right now.
updating_child_controls = false ;
2023-02-05 16:35:39 +00:00
Viewport * embedder_vp = get_embedder ( ) ;
2020-03-04 01:51:12 +00:00
2020-03-14 16:06:39 +00:00
if ( ! embedder_vp ) {
2020-03-06 17:00:16 +00:00
if ( ! p_visible & & window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
2020-03-04 01:51:12 +00:00
_clear_window ( ) ;
}
2020-03-06 17:00:16 +00:00
if ( p_visible & & window_id = = DisplayServer : : INVALID_WINDOW_ID ) {
2020-03-04 01:51:12 +00:00
_make_window ( ) ;
}
} else {
2020-03-14 16:06:39 +00:00
if ( visible ) {
embedder = embedder_vp ;
2023-06-05 06:34:32 +00:00
if ( initial_position ! = WINDOW_INITIAL_POSITION_ABSOLUTE ) {
position = ( embedder - > get_visible_rect ( ) . size - size ) / 2 ;
}
2020-03-14 16:06:39 +00:00
embedder - > _sub_window_register ( this ) ;
2020-03-27 18:21:27 +00:00
RS : : get_singleton ( ) - > viewport_set_update_mode ( get_viewport_rid ( ) , RS : : VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE ) ;
2020-03-14 16:06:39 +00:00
} else {
embedder - > _sub_window_remove ( this ) ;
embedder = nullptr ;
2020-03-27 18:21:27 +00:00
RS : : get_singleton ( ) - > viewport_set_update_mode ( get_viewport_rid ( ) , RS : : VIEWPORT_UPDATE_DISABLED ) ;
2020-03-14 16:06:39 +00:00
}
_update_window_size ( ) ;
2020-03-04 01:51:12 +00:00
}
2020-03-06 17:00:16 +00:00
if ( ! visible ) {
focused = false ;
}
notification ( NOTIFICATION_VISIBILITY_CHANGED ) ;
emit_signal ( SceneStringNames : : get_singleton ( ) - > visibility_changed ) ;
2020-03-14 16:06:39 +00:00
2020-03-27 18:21:27 +00:00
RS : : get_singleton ( ) - > viewport_set_active ( get_viewport_rid ( ) , visible ) ;
2020-06-30 17:01:10 +00:00
//update transient exclusive
if ( transient_parent ) {
2023-09-30 18:33:03 +00:00
_set_transient_exclusive_child ( true ) ;
2020-06-30 17:01:10 +00:00
}
2020-03-04 01:51:12 +00:00
}
2020-03-04 19:03:30 +00:00
void Window : : _clear_transient ( ) {
if ( transient_parent ) {
if ( transient_parent - > window_id ! = DisplayServer : : INVALID_WINDOW_ID & & window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
DisplayServer : : get_singleton ( ) - > window_set_transient ( window_id , DisplayServer : : INVALID_WINDOW_ID ) ;
}
transient_parent - > transient_children . erase ( this ) ;
2020-03-06 17:00:16 +00:00
if ( transient_parent - > exclusive_child = = this ) {
transient_parent - > exclusive_child = nullptr ;
}
2020-03-04 19:03:30 +00:00
transient_parent = nullptr ;
}
}
void Window : : _make_transient ( ) {
if ( ! get_parent ( ) ) {
//main window, can't be transient
return ;
}
//find transient parent
2023-12-22 16:50:21 +00:00
2020-03-04 19:03:30 +00:00
Window * window = nullptr ;
2023-12-22 16:50:21 +00:00
if ( ! is_embedded ( ) & & transient_to_focused ) {
DisplayServer : : WindowID focused_window_id = DisplayServer : : get_singleton ( ) - > get_focused_window ( ) ;
if ( focused_window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
window = Object : : cast_to < Window > ( ObjectDB : : get_instance ( DisplayServer : : get_singleton ( ) - > window_get_attached_instance_id ( focused_window_id ) ) ) ;
2020-03-04 19:03:30 +00:00
}
2023-12-22 16:50:21 +00:00
}
2020-03-04 19:03:30 +00:00
2023-12-22 16:50:21 +00:00
if ( ! window ) {
Viewport * vp = get_parent ( ) - > get_viewport ( ) ;
while ( vp ) {
window = Object : : cast_to < Window > ( vp ) ;
if ( window ) {
break ;
}
if ( ! vp - > get_parent ( ) ) {
break ;
}
vp = vp - > get_parent ( ) - > get_viewport ( ) ;
}
2020-03-04 19:03:30 +00:00
}
if ( window ) {
transient_parent = window ;
window - > transient_children . insert ( this ) ;
2023-09-30 18:33:03 +00:00
_set_transient_exclusive_child ( ) ;
2020-03-04 19:03:30 +00:00
}
//see if we can make transient
if ( transient_parent - > window_id ! = DisplayServer : : INVALID_WINDOW_ID & & window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
DisplayServer : : get_singleton ( ) - > window_set_transient ( window_id , transient_parent - > window_id ) ;
}
}
2023-09-30 18:33:03 +00:00
void Window : : _set_transient_exclusive_child ( bool p_clear_invalid ) {
if ( exclusive & & visible & & is_inside_tree ( ) ) {
if ( ! is_in_edited_scene_root ( ) ) {
// Transient parent has another exclusive child.
if ( transient_parent - > exclusive_child & & transient_parent - > exclusive_child ! = this ) {
2024-01-28 20:51:39 +00:00
ERR_PRINT ( vformat ( " Attempting to make child window exclusive, but the parent window already has another exclusive child. This window: %s, parent window: %s, current exclusive child window: %s " , get_description ( ) , transient_parent - > get_description ( ) , transient_parent - > exclusive_child - > get_description ( ) ) ) ;
2023-09-30 18:33:03 +00:00
}
transient_parent - > exclusive_child = this ;
}
} else if ( p_clear_invalid ) {
if ( transient_parent - > exclusive_child = = this ) {
transient_parent - > exclusive_child = nullptr ;
}
}
}
2020-03-04 19:03:30 +00:00
void Window : : set_transient ( bool p_transient ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-03-04 19:03:30 +00:00
if ( transient = = p_transient ) {
return ;
}
transient = p_transient ;
if ( ! is_inside_tree ( ) ) {
return ;
}
if ( transient ) {
2023-12-22 16:50:21 +00:00
if ( ! transient_to_focused ) {
_make_transient ( ) ;
}
2020-03-04 19:03:30 +00:00
} else {
_clear_transient ( ) ;
}
}
2020-05-14 12:29:06 +00:00
2020-03-04 19:03:30 +00:00
bool Window : : is_transient ( ) const {
return transient ;
}
2023-12-22 16:50:21 +00:00
void Window : : set_transient_to_focused ( bool p_transient_to_focused ) {
ERR_MAIN_THREAD_GUARD ;
if ( transient_to_focused = = p_transient_to_focused ) {
return ;
}
transient_to_focused = p_transient_to_focused ;
}
bool Window : : is_transient_to_focused ( ) const {
ERR_READ_THREAD_GUARD_V ( false ) ;
return transient_to_focused ;
}
2020-03-06 17:00:16 +00:00
void Window : : set_exclusive ( bool p_exclusive ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-03-06 17:00:16 +00:00
if ( exclusive = = p_exclusive ) {
return ;
}
exclusive = p_exclusive ;
2022-01-19 12:04:05 +00:00
if ( ! embedder & & window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
2022-10-11 05:39:36 +00:00
if ( is_in_edited_scene_root ( ) ) {
2022-06-09 08:59:01 +00:00
DisplayServer : : get_singleton ( ) - > window_set_exclusive ( window_id , false ) ;
2022-10-11 05:39:36 +00:00
} else {
DisplayServer : : get_singleton ( ) - > window_set_exclusive ( window_id , exclusive ) ;
2022-06-09 08:59:01 +00:00
}
2022-01-19 12:04:05 +00:00
}
2020-03-06 17:00:16 +00:00
if ( transient_parent ) {
2023-09-30 18:33:03 +00:00
_set_transient_exclusive_child ( true ) ;
2020-03-06 17:00:16 +00:00
}
}
bool Window : : is_exclusive ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2020-03-06 17:00:16 +00:00
return exclusive ;
}
2020-03-04 01:51:12 +00:00
bool Window : : is_visible ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2020-03-04 01:51:12 +00:00
return visible ;
}
2022-06-18 10:52:30 +00:00
Size2i Window : : _clamp_window_size ( const Size2i & p_size ) {
Size2i window_size_clamped = p_size ;
Size2 minsize = get_clamped_minimum_size ( ) ;
window_size_clamped = window_size_clamped . max ( minsize ) ;
2022-08-21 22:16:56 +00:00
2022-06-18 10:52:30 +00:00
if ( max_size_used ! = Size2i ( ) ) {
window_size_clamped = window_size_clamped . min ( max_size_used ) ;
2022-08-21 22:16:56 +00:00
}
2022-06-18 10:52:30 +00:00
return window_size_clamped ;
}
2020-03-14 16:06:39 +00:00
2022-06-18 10:52:30 +00:00
void Window : : _update_window_size ( ) {
Size2i size_limit = get_clamped_minimum_size ( ) ;
2023-11-24 15:31:24 +00:00
if ( ! embedder & & window_id ! = DisplayServer : : INVALID_WINDOW_ID & & keep_title_visible ) {
Size2i title_size = DisplayServer : : get_singleton ( ) - > window_get_title_size ( tr_title , window_id ) ;
size_limit = size_limit . max ( title_size ) ;
}
2020-03-14 16:06:39 +00:00
2022-06-18 10:52:30 +00:00
size = size . max ( size_limit ) ;
2020-03-14 16:06:39 +00:00
2022-08-04 20:11:32 +00:00
bool reset_min_first = false ;
2022-06-18 10:52:30 +00:00
if ( max_size_used ! = Size2i ( ) ) {
// Force window size to respect size limitations of max_size_used.
size = size . min ( max_size_used ) ;
2022-08-04 20:11:32 +00:00
2022-06-18 10:52:30 +00:00
if ( size_limit . x > max_size_used . x ) {
size_limit . x = max_size_used . x ;
2022-08-04 20:11:32 +00:00
reset_min_first = true ;
}
2022-06-18 10:52:30 +00:00
if ( size_limit . y > max_size_used . y ) {
size_limit . y = max_size_used . y ;
2022-08-04 20:11:32 +00:00
reset_min_first = true ;
}
2020-03-14 16:06:39 +00:00
}
if ( embedder ) {
2024-03-03 11:49:08 +00:00
size = size . max ( Size2i ( 1 , 1 ) ) ;
2022-08-04 20:11:32 +00:00
2020-03-14 16:06:39 +00:00
embedder - > _sub_window_update ( this ) ;
} else if ( window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
2022-08-04 20:11:32 +00:00
if ( reset_min_first & & wrap_controls ) {
// Avoid an error if setting max_size to a value between min_size and the previous size_limit.
DisplayServer : : get_singleton ( ) - > window_set_min_size ( Size2i ( ) , window_id ) ;
}
2022-06-18 10:52:30 +00:00
DisplayServer : : get_singleton ( ) - > window_set_max_size ( max_size_used , window_id ) ;
2021-07-08 23:06:16 +00:00
DisplayServer : : get_singleton ( ) - > window_set_min_size ( size_limit , window_id ) ;
2022-10-10 19:24:28 +00:00
DisplayServer : : get_singleton ( ) - > window_set_size ( size , window_id ) ;
2020-03-14 16:06:39 +00:00
}
//update the viewport
_update_viewport_size ( ) ;
}
2020-05-14 12:29:06 +00:00
2020-03-14 16:06:39 +00:00
void Window : : _update_viewport_size ( ) {
//update the viewport part
2020-03-04 01:51:12 +00:00
Size2i final_size ;
Size2i final_size_override ;
Rect2i attach_to_screen_rect ( Point2i ( ) , size ) ;
float font_oversampling = 1.0 ;
2022-03-31 20:40:26 +00:00
window_transform = Transform2D ( ) ;
2020-03-04 01:51:12 +00:00
2023-04-06 21:41:27 +00:00
if ( content_scale_stretch = = Window : : CONTENT_SCALE_STRETCH_INTEGER ) {
// We always want to make sure that the content scale factor is a whole
// number, else there will be pixel wobble no matter what.
content_scale_factor = Math : : floor ( content_scale_factor ) ;
// A content scale factor of zero is pretty useless.
if ( content_scale_factor < 1 ) {
content_scale_factor = 1 ;
}
}
2020-03-04 01:51:12 +00:00
if ( content_scale_mode = = CONTENT_SCALE_MODE_DISABLED | | content_scale_size . x = = 0 | | content_scale_size . y = = 0 ) {
2021-12-17 12:11:19 +00:00
font_oversampling = content_scale_factor ;
2020-03-04 01:51:12 +00:00
final_size = size ;
2021-12-17 12:11:19 +00:00
final_size_override = Size2 ( size ) / content_scale_factor ;
2020-03-04 01:51:12 +00:00
} else {
//actual screen video mode
Size2 video_mode = size ;
Size2 desired_res = content_scale_size ;
Size2 viewport_size ;
Size2 screen_size ;
float viewport_aspect = desired_res . aspect ( ) ;
float video_mode_aspect = video_mode . aspect ( ) ;
if ( content_scale_aspect = = CONTENT_SCALE_ASPECT_IGNORE | | Math : : is_equal_approx ( viewport_aspect , video_mode_aspect ) ) {
//same aspect or ignore aspect
viewport_size = desired_res ;
screen_size = video_mode ;
} else if ( viewport_aspect < video_mode_aspect ) {
// screen ratio is smaller vertically
if ( content_scale_aspect = = CONTENT_SCALE_ASPECT_KEEP_HEIGHT | | content_scale_aspect = = CONTENT_SCALE_ASPECT_EXPAND ) {
//will stretch horizontally
viewport_size . x = desired_res . y * video_mode_aspect ;
viewport_size . y = desired_res . y ;
screen_size = video_mode ;
} else {
//will need black bars
viewport_size = desired_res ;
screen_size . x = video_mode . y * viewport_aspect ;
screen_size . y = video_mode . y ;
}
} else {
//screen ratio is smaller horizontally
if ( content_scale_aspect = = CONTENT_SCALE_ASPECT_KEEP_WIDTH | | content_scale_aspect = = CONTENT_SCALE_ASPECT_EXPAND ) {
//will stretch horizontally
viewport_size . x = desired_res . x ;
viewport_size . y = desired_res . x / video_mode_aspect ;
screen_size = video_mode ;
} else {
//will need black bars
viewport_size = desired_res ;
screen_size . x = video_mode . x ;
screen_size . y = video_mode . x / viewport_aspect ;
}
}
screen_size = screen_size . floor ( ) ;
viewport_size = viewport_size . floor ( ) ;
2023-04-06 21:41:27 +00:00
if ( content_scale_stretch = = Window : : CONTENT_SCALE_STRETCH_INTEGER ) {
Size2i screen_scale = ( screen_size / viewport_size ) . floor ( ) ;
int scale_factor = MIN ( screen_scale . x , screen_scale . y ) ;
if ( scale_factor < 1 ) {
scale_factor = 1 ;
}
screen_size = viewport_size * scale_factor ;
}
2020-03-04 01:51:12 +00:00
Size2 margin ;
Size2 offset ;
2023-02-14 18:30:02 +00:00
2023-04-06 21:41:27 +00:00
if ( screen_size . x < video_mode . x ) {
2020-03-04 01:51:12 +00:00
margin . x = Math : : round ( ( video_mode . x - screen_size . x ) / 2.0 ) ;
offset . x = Math : : round ( margin . x * viewport_size . y / screen_size . y ) ;
2023-04-06 21:41:27 +00:00
}
if ( screen_size . y < video_mode . y ) {
2020-03-04 01:51:12 +00:00
margin . y = Math : : round ( ( video_mode . y - screen_size . y ) / 2.0 ) ;
offset . y = Math : : round ( margin . y * viewport_size . x / screen_size . x ) ;
}
switch ( content_scale_mode ) {
case CONTENT_SCALE_MODE_DISABLED : {
// Already handled above
//_update_font_oversampling(1.0);
} break ;
2020-07-02 20:15:11 +00:00
case CONTENT_SCALE_MODE_CANVAS_ITEMS : {
2020-03-04 01:51:12 +00:00
final_size = screen_size ;
2021-12-17 12:11:19 +00:00
final_size_override = viewport_size / content_scale_factor ;
2020-03-04 01:51:12 +00:00
attach_to_screen_rect = Rect2 ( margin , screen_size ) ;
2021-12-17 12:11:19 +00:00
font_oversampling = ( screen_size . x / viewport_size . x ) * content_scale_factor ;
2020-07-02 20:15:11 +00:00
2022-03-31 20:40:26 +00:00
window_transform . translate_local ( margin ) ;
2020-03-04 01:51:12 +00:00
} break ;
2020-07-02 20:15:11 +00:00
case CONTENT_SCALE_MODE_VIEWPORT : {
2022-05-06 17:50:53 +00:00
final_size = ( viewport_size / content_scale_factor ) . floor ( ) ;
2020-03-04 01:51:12 +00:00
attach_to_screen_rect = Rect2 ( margin , screen_size ) ;
2022-03-31 20:40:26 +00:00
window_transform . translate_local ( margin ) ;
if ( final_size . x ! = 0 & & final_size . y ! = 0 ) {
Transform2D scale_transform ;
scale_transform . scale ( Vector2 ( attach_to_screen_rect . size ) / Vector2 ( final_size ) ) ;
window_transform * = scale_transform ;
}
2020-03-04 01:51:12 +00:00
} break ;
}
}
2020-03-14 16:06:39 +00:00
bool allocate = is_inside_tree ( ) & & visible & & ( window_id ! = DisplayServer : : INVALID_WINDOW_ID | | embedder ! = nullptr ) ;
2023-02-02 18:00:07 +00:00
_set_size ( final_size , final_size_override , allocate ) ;
2020-03-04 01:51:12 +00:00
if ( window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
2020-03-27 18:21:27 +00:00
RenderingServer : : get_singleton ( ) - > viewport_attach_to_screen ( get_viewport_rid ( ) , attach_to_screen_rect , window_id ) ;
2020-03-04 01:51:12 +00:00
} else {
2020-03-27 18:21:27 +00:00
RenderingServer : : get_singleton ( ) - > viewport_attach_to_screen ( get_viewport_rid ( ) , Rect2i ( ) , DisplayServer : : INVALID_WINDOW_ID ) ;
2020-03-04 01:51:12 +00:00
}
if ( window_id = = DisplayServer : : MAIN_WINDOW_ID ) {
if ( ! use_font_oversampling ) {
font_oversampling = 1.0 ;
}
2020-12-27 13:30:33 +00:00
if ( TS - > font_get_global_oversampling ( ) ! = font_oversampling ) {
TS - > font_set_global_oversampling ( font_oversampling ) ;
2020-03-04 01:51:12 +00:00
}
}
2020-03-06 17:00:16 +00:00
2024-02-21 18:28:34 +00:00
notification ( NOTIFICATION_WM_SIZE_CHANGED ) ;
2020-03-14 16:06:39 +00:00
if ( embedder ) {
embedder - > _sub_window_update ( this ) ;
}
2020-03-04 01:51:12 +00:00
}
2020-03-04 16:36:09 +00:00
void Window : : _update_window_callbacks ( ) {
2020-03-14 16:06:39 +00:00
DisplayServer : : get_singleton ( ) - > window_set_rect_changed_callback ( callable_mp ( this , & Window : : _rect_changed_callback ) , window_id ) ;
2020-03-04 16:36:09 +00:00
DisplayServer : : get_singleton ( ) - > window_set_window_event_callback ( callable_mp ( this , & Window : : _event_callback ) , window_id ) ;
DisplayServer : : get_singleton ( ) - > window_set_input_event_callback ( callable_mp ( this , & Window : : _window_input ) , window_id ) ;
DisplayServer : : get_singleton ( ) - > window_set_input_text_callback ( callable_mp ( this , & Window : : _window_input_text ) , window_id ) ;
DisplayServer : : get_singleton ( ) - > window_set_drop_files_callback ( callable_mp ( this , & Window : : _window_drop_files ) , window_id ) ;
}
2020-03-14 16:06:39 +00:00
2024-03-04 18:21:10 +00:00
void Window : : set_force_native ( bool p_force_native ) {
if ( force_native = = p_force_native ) {
return ;
}
2024-03-19 10:39:50 +00:00
if ( is_visible ( ) & & ! is_in_edited_scene_root ( ) ) {
2024-04-13 18:03:29 +00:00
ERR_FAIL_MSG ( " Can't change \" force_native \" while a window is displayed. Consider hiding window before changing this value. " ) ;
2024-03-04 18:21:10 +00:00
}
2024-04-13 18:03:29 +00:00
force_native = p_force_native ;
2024-03-04 18:21:10 +00:00
}
bool Window : : get_force_native ( ) const {
return force_native ;
}
2023-02-05 16:35:39 +00:00
Viewport * Window : : get_embedder ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( nullptr ) ;
2024-03-19 10:39:50 +00:00
if ( force_native & & DisplayServer : : get_singleton ( ) - > has_feature ( DisplayServer : : FEATURE_SUBWINDOWS ) & & ! is_in_edited_scene_root ( ) ) {
2024-03-04 18:21:10 +00:00
return nullptr ;
}
2020-03-14 16:06:39 +00:00
Viewport * vp = get_parent_viewport ( ) ;
while ( vp ) {
if ( vp - > is_embedding_subwindows ( ) ) {
return vp ;
}
if ( vp - > get_parent ( ) ) {
vp = vp - > get_parent ( ) - > get_viewport ( ) ;
} else {
vp = nullptr ;
}
}
return nullptr ;
}
2020-03-04 01:51:12 +00:00
void Window : : _notification ( int p_what ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2021-07-28 02:32:03 +00:00
switch ( p_what ) {
2022-09-01 10:38:08 +00:00
case NOTIFICATION_POSTINITIALIZE : {
2023-04-03 16:01:10 +00:00
initialized = true ;
2022-09-01 10:38:08 +00:00
_invalidate_theme_cache ( ) ;
_update_theme_item_cache ( ) ;
} break ;
2022-09-02 14:45:09 +00:00
case NOTIFICATION_PARENTED : {
theme_owner - > assign_theme_on_parented ( this ) ;
} break ;
case NOTIFICATION_UNPARENTED : {
theme_owner - > clear_theme_on_unparented ( this ) ;
} break ;
2021-07-28 02:32:03 +00:00
case NOTIFICATION_ENTER_TREE : {
bool embedded = false ;
{
2023-02-05 16:35:39 +00:00
embedder = get_embedder ( ) ;
2021-07-28 02:32:03 +00:00
if ( embedder ) {
embedded = true ;
if ( ! visible ) {
2022-02-15 17:06:48 +00:00
embedder = nullptr ; // Not yet since not visible.
2021-07-28 02:32:03 +00:00
}
2020-03-14 16:06:39 +00:00
}
}
2021-07-28 02:32:03 +00:00
if ( embedded ) {
2022-02-15 17:06:48 +00:00
// Create as embedded.
2021-07-28 02:32:03 +00:00
if ( embedder ) {
2023-06-05 06:34:32 +00:00
if ( initial_position ! = WINDOW_INITIAL_POSITION_ABSOLUTE ) {
position = ( embedder - > get_visible_rect ( ) . size - size ) / 2 ;
}
2021-07-28 02:32:03 +00:00
embedder - > _sub_window_register ( this ) ;
RS : : get_singleton ( ) - > viewport_set_update_mode ( get_viewport_rid ( ) , RS : : VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE ) ;
_update_window_size ( ) ;
2020-03-14 16:06:39 +00:00
}
2021-07-28 02:32:03 +00:00
2020-03-04 01:51:12 +00:00
} else {
2022-02-15 17:06:48 +00:00
if ( ! get_parent ( ) ) {
// It's the root window!
visible = true ; // Always visible.
2021-07-28 02:32:03 +00:00
window_id = DisplayServer : : MAIN_WINDOW_ID ;
DisplayServer : : get_singleton ( ) - > window_attach_instance_id ( get_instance_id ( ) , window_id ) ;
_update_from_window ( ) ;
2022-02-15 17:06:48 +00:00
// Since this window already exists (created on start), we must update pos and size from it.
2021-07-28 02:32:03 +00:00
{
position = DisplayServer : : get_singleton ( ) - > window_get_position ( window_id ) ;
size = DisplayServer : : get_singleton ( ) - > window_get_size ( window_id ) ;
2023-06-15 07:53:31 +00:00
focused = DisplayServer : : get_singleton ( ) - > window_is_focused ( window_id ) ;
2021-07-28 02:32:03 +00:00
}
2023-02-14 11:15:14 +00:00
_update_window_size ( ) ; // Inform DisplayServer of minimum and maximum size.
2022-02-15 17:06:48 +00:00
_update_viewport_size ( ) ; // Then feed back to the viewport.
2021-07-28 02:32:03 +00:00
_update_window_callbacks ( ) ;
RS : : get_singleton ( ) - > viewport_set_update_mode ( get_viewport_rid ( ) , RS : : VIEWPORT_UPDATE_WHEN_VISIBLE ) ;
2024-02-02 07:46:01 +00:00
if ( DisplayServer : : get_singleton ( ) - > window_get_flag ( DisplayServer : : WindowFlags ( FLAG_TRANSPARENT ) , window_id ) ) {
set_transparent_background ( true ) ;
}
2021-07-28 02:32:03 +00:00
} else {
2022-02-15 17:06:48 +00:00
// Create.
2021-07-28 02:32:03 +00:00
if ( visible ) {
_make_window ( ) ;
}
2020-03-06 17:00:16 +00:00
}
2020-03-04 01:51:12 +00:00
}
2023-12-22 16:50:21 +00:00
if ( transient & & ! transient_to_focused ) {
2021-07-28 02:32:03 +00:00
_make_transient ( ) ;
}
if ( visible ) {
notification ( NOTIFICATION_VISIBILITY_CHANGED ) ;
emit_signal ( SceneStringNames : : get_singleton ( ) - > visibility_changed ) ;
RS : : get_singleton ( ) - > viewport_set_active ( get_viewport_rid ( ) , true ) ;
}
2022-06-01 01:20:00 +00:00
2023-09-06 14:11:05 +00:00
// Emits NOTIFICATION_THEME_CHANGED internally.
set_theme_context ( ThemeDB : : get_singleton ( ) - > get_nearest_theme_context ( this ) ) ;
2022-07-08 19:29:36 +00:00
} break ;
2021-07-28 02:32:03 +00:00
case NOTIFICATION_READY : {
if ( wrap_controls ) {
2023-01-15 15:04:05 +00:00
// Finish any resizing immediately so it doesn't interfere on stuff overriding _ready().
2021-07-28 02:32:03 +00:00
_update_child_controls ( ) ;
}
} break ;
2022-02-15 17:06:48 +00:00
2023-04-20 13:13:21 +00:00
case NOTIFICATION_THEME_CHANGED : {
emit_signal ( SceneStringNames : : get_singleton ( ) - > theme_changed ) ;
_invalidate_theme_cache ( ) ;
_update_theme_item_cache ( ) ;
} break ;
2021-07-28 02:32:03 +00:00
case NOTIFICATION_TRANSLATION_CHANGED : {
2022-09-01 10:38:08 +00:00
_invalidate_theme_cache ( ) ;
_update_theme_item_cache ( ) ;
2023-08-08 08:31:56 +00:00
tr_title = atr ( title ) ;
2022-01-21 09:08:07 +00:00
# ifdef DEBUG_ENABLED
2023-08-08 08:31:56 +00:00
if ( window_id = = DisplayServer : : MAIN_WINDOW_ID ) {
// Append a suffix to the window title to denote that the project is running
// from a debug build (including the editor). Since this results in lower performance,
// this should be clearly presented to the user.
tr_title = vformat ( " %s (DEBUG) " , tr_title ) ;
}
2022-01-21 09:08:07 +00:00
# endif
2023-08-08 08:31:56 +00:00
if ( ! embedder & & window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
2022-01-21 09:08:07 +00:00
DisplayServer : : get_singleton ( ) - > window_set_title ( tr_title , window_id ) ;
2023-12-06 08:51:27 +00:00
if ( keep_title_visible ) {
Size2i title_size = DisplayServer : : get_singleton ( ) - > window_get_title_size ( tr_title , window_id ) ;
Size2i size_limit = get_clamped_minimum_size ( ) ;
if ( title_size . x > size_limit . x | | title_size . y > size_limit . y ) {
_update_window_size ( ) ;
}
}
2021-05-27 17:31:33 +00:00
}
2021-07-28 02:32:03 +00:00
} break ;
2022-02-15 17:06:48 +00:00
2023-04-20 13:13:21 +00:00
case NOTIFICATION_VISIBILITY_CHANGED : {
if ( unparent_when_invisible & & ! is_visible ( ) ) {
Node * p = get_parent ( ) ;
if ( p ) {
p - > remove_child ( this ) ;
}
}
} break ;
2021-07-28 02:32:03 +00:00
case NOTIFICATION_EXIT_TREE : {
2023-09-06 14:11:05 +00:00
set_theme_context ( nullptr , false ) ;
2021-07-28 02:32:03 +00:00
if ( transient ) {
_clear_transient ( ) ;
}
2020-03-04 19:03:30 +00:00
2021-07-28 02:32:03 +00:00
if ( ! is_embedded ( ) & & window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
if ( window_id = = DisplayServer : : MAIN_WINDOW_ID ) {
RS : : get_singleton ( ) - > viewport_set_update_mode ( get_viewport_rid ( ) , RS : : VIEWPORT_UPDATE_DISABLED ) ;
_update_window_callbacks ( ) ;
} else {
_clear_window ( ) ;
}
2020-03-04 01:51:12 +00:00
} else {
2021-07-28 02:32:03 +00:00
if ( embedder ) {
embedder - > _sub_window_remove ( this ) ;
embedder = nullptr ;
RS : : get_singleton ( ) - > viewport_set_update_mode ( get_viewport_rid ( ) , RS : : VIEWPORT_UPDATE_DISABLED ) ;
}
_update_viewport_size ( ) ; //called by clear and make, which does not happen here
2020-03-14 16:06:39 +00:00
}
2021-07-28 02:32:03 +00:00
RS : : get_singleton ( ) - > viewport_set_active ( get_viewport_rid ( ) , false ) ;
} break ;
2023-01-06 20:48:20 +00:00
case NOTIFICATION_VP_MOUSE_ENTER : {
emit_signal ( SceneStringNames : : get_singleton ( ) - > mouse_entered ) ;
} break ;
case NOTIFICATION_VP_MOUSE_EXIT : {
emit_signal ( SceneStringNames : : get_singleton ( ) - > mouse_exited ) ;
} break ;
2020-03-04 01:51:12 +00:00
}
}
void Window : : set_content_scale_size ( const Size2i & p_size ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-03-04 01:51:12 +00:00
ERR_FAIL_COND ( p_size . x < 0 ) ;
ERR_FAIL_COND ( p_size . y < 0 ) ;
content_scale_size = p_size ;
2020-03-14 16:06:39 +00:00
_update_viewport_size ( ) ;
2020-03-04 01:51:12 +00:00
}
Size2i Window : : get_content_scale_size ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Size2i ( ) ) ;
2020-03-04 01:51:12 +00:00
return content_scale_size ;
}
2020-03-04 19:03:30 +00:00
void Window : : set_content_scale_mode ( ContentScaleMode p_mode ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-03-04 01:51:12 +00:00
content_scale_mode = p_mode ;
2020-03-14 16:06:39 +00:00
_update_viewport_size ( ) ;
2020-03-04 01:51:12 +00:00
}
2020-05-14 12:29:06 +00:00
2020-03-04 01:51:12 +00:00
Window : : ContentScaleMode Window : : get_content_scale_mode ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( CONTENT_SCALE_MODE_DISABLED ) ;
2020-03-04 01:51:12 +00:00
return content_scale_mode ;
}
2020-03-04 19:03:30 +00:00
void Window : : set_content_scale_aspect ( ContentScaleAspect p_aspect ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-03-04 01:51:12 +00:00
content_scale_aspect = p_aspect ;
2020-03-14 16:06:39 +00:00
_update_viewport_size ( ) ;
2020-03-04 01:51:12 +00:00
}
2020-05-14 12:29:06 +00:00
2020-03-04 01:51:12 +00:00
Window : : ContentScaleAspect Window : : get_content_scale_aspect ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( CONTENT_SCALE_ASPECT_IGNORE ) ;
2020-03-04 01:51:12 +00:00
return content_scale_aspect ;
}
2023-04-06 21:41:27 +00:00
void Window : : set_content_scale_stretch ( ContentScaleStretch p_stretch ) {
content_scale_stretch = p_stretch ;
_update_viewport_size ( ) ;
}
Window : : ContentScaleStretch Window : : get_content_scale_stretch ( ) const {
return content_scale_stretch ;
}
2023-08-08 08:31:56 +00:00
void Window : : set_keep_title_visible ( bool p_title_visible ) {
if ( keep_title_visible = = p_title_visible ) {
return ;
}
keep_title_visible = p_title_visible ;
if ( window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
_update_window_size ( ) ;
}
}
bool Window : : get_keep_title_visible ( ) const {
return keep_title_visible ;
}
2021-12-17 12:11:19 +00:00
void Window : : set_content_scale_factor ( real_t p_factor ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2021-12-17 12:11:19 +00:00
ERR_FAIL_COND ( p_factor < = 0 ) ;
content_scale_factor = p_factor ;
_update_viewport_size ( ) ;
}
real_t Window : : get_content_scale_factor ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( 0 ) ;
2021-12-17 12:11:19 +00:00
return content_scale_factor ;
}
2020-03-04 01:51:12 +00:00
void Window : : set_use_font_oversampling ( bool p_oversampling ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-03-04 01:51:12 +00:00
if ( is_inside_tree ( ) & & window_id ! = DisplayServer : : MAIN_WINDOW_ID ) {
ERR_FAIL_MSG ( " Only the root window can set and use font oversampling. " ) ;
}
use_font_oversampling = p_oversampling ;
2020-03-14 16:06:39 +00:00
_update_viewport_size ( ) ;
2020-03-04 01:51:12 +00:00
}
2020-05-14 12:29:06 +00:00
2020-03-04 01:51:12 +00:00
bool Window : : is_using_font_oversampling ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2020-03-04 01:51:12 +00:00
return use_font_oversampling ;
}
DisplayServer : : WindowID Window : : get_window_id ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( DisplayServer : : INVALID_WINDOW_ID ) ;
2021-02-28 23:12:20 +00:00
if ( embedder ) {
return parent - > get_window_id ( ) ;
}
2020-03-04 01:51:12 +00:00
return window_id ;
}
2023-01-15 10:05:25 +00:00
void Window : : set_mouse_passthrough_polygon ( const Vector < Vector2 > & p_region ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2023-01-15 10:05:25 +00:00
mpath = p_region ;
if ( window_id = = DisplayServer : : INVALID_WINDOW_ID ) {
return ;
}
DisplayServer : : get_singleton ( ) - > window_set_mouse_passthrough ( mpath , window_id ) ;
}
Vector < Vector2 > Window : : get_mouse_passthrough_polygon ( ) const {
return mpath ;
}
2020-03-06 17:00:16 +00:00
void Window : : set_wrap_controls ( bool p_enable ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-03-06 17:00:16 +00:00
wrap_controls = p_enable ;
2023-01-15 15:04:05 +00:00
if ( ! is_inside_tree ( ) ) {
return ;
}
if ( updating_child_controls ) {
_update_child_controls ( ) ;
2022-08-04 20:11:32 +00:00
} else {
_update_window_size ( ) ;
2020-03-06 17:00:16 +00:00
}
}
bool Window : : is_wrapping_controls ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2020-03-06 17:00:16 +00:00
return wrap_controls ;
}
Size2 Window : : _get_contents_minimum_size ( ) const {
Size2 max ;
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
Control * c = Object : : cast_to < Control > ( get_child ( i ) ) ;
if ( c ) {
Point2i pos = c - > get_position ( ) ;
Size2i min = c - > get_combined_minimum_size ( ) ;
2024-03-03 11:49:08 +00:00
max = max . max ( pos + min ) ;
2020-03-06 17:00:16 +00:00
}
}
return max ;
}
2020-05-14 12:29:06 +00:00
2023-01-15 15:04:05 +00:00
void Window : : child_controls_changed ( ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2023-01-15 15:04:05 +00:00
if ( ! is_inside_tree ( ) | | ! visible | | updating_child_controls ) {
2020-03-14 16:06:39 +00:00
return ;
}
2020-03-06 17:00:16 +00:00
2023-01-15 15:04:05 +00:00
updating_child_controls = true ;
2023-12-18 14:46:56 +00:00
callable_mp ( this , & Window : : _update_child_controls ) . call_deferred ( ) ;
2020-03-06 17:00:16 +00:00
}
2020-05-14 12:29:06 +00:00
2023-01-15 15:04:05 +00:00
void Window : : _update_child_controls ( ) {
if ( ! updating_child_controls ) {
2020-03-06 17:00:16 +00:00
return ;
}
2023-01-15 15:04:05 +00:00
_update_window_size ( ) ;
updating_child_controls = false ;
2020-03-06 17:00:16 +00:00
}
2020-07-01 12:27:43 +00:00
bool Window : : _can_consume_input_events ( ) const {
return exclusive_child = = nullptr ;
}
2020-03-04 16:36:09 +00:00
void Window : : _window_input ( const Ref < InputEvent > & p_ev ) {
2024-04-09 09:47:06 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-03-04 16:36:09 +00:00
if ( EngineDebugger : : is_active ( ) ) {
2022-08-30 11:32:34 +00:00
// Quit from game window using the stop shortcut (F8 by default).
// The custom shortcut is provided via environment variable when running from the editor.
if ( debugger_stop_shortcut . is_null ( ) ) {
String shortcut_str = OS : : get_singleton ( ) - > get_environment ( " __GODOT_EDITOR_STOP_SHORTCUT__ " ) ;
if ( ! shortcut_str . is_empty ( ) ) {
Variant shortcut_var ;
VariantParser : : StreamString ss ;
ss . s = shortcut_str ;
String errs ;
int line ;
VariantParser : : parse ( & ss , shortcut_var , errs , line ) ;
debugger_stop_shortcut = shortcut_var ;
}
if ( debugger_stop_shortcut . is_null ( ) ) {
// Define a default shortcut if it wasn't provided or is invalid.
debugger_stop_shortcut . instantiate ( ) ;
debugger_stop_shortcut - > set_events ( { ( Variant ) InputEventKey : : create_reference ( Key : : F8 ) } ) ;
}
}
2020-03-04 16:36:09 +00:00
Ref < InputEventKey > k = p_ev ;
2022-08-30 11:32:34 +00:00
if ( k . is_valid ( ) & & k - > is_pressed ( ) & & ! k - > is_echo ( ) & & debugger_stop_shortcut - > matches_event ( k ) ) {
2020-03-04 16:36:09 +00:00
EngineDebugger : : get_singleton ( ) - > send_message ( " request_quit " , Array ( ) ) ;
}
}
2020-03-06 17:00:16 +00:00
if ( exclusive_child ! = nullptr ) {
2022-02-24 09:21:23 +00:00
if ( ! is_embedding_subwindows ( ) ) { // Not embedding, no need for event.
2020-07-01 12:27:43 +00:00
return ;
}
2020-03-06 17:00:16 +00:00
}
2020-03-12 12:37:40 +00:00
2023-09-01 06:40:35 +00:00
// If the event needs to be handled in a Window-derived class, then it should overwrite
// `_input_from_window` instead of subscribing to the `window_input` signal, because the signal
// filters out internal events.
_input_from_window ( p_ev ) ;
if ( p_ev - > get_device ( ) ! = InputEvent : : DEVICE_ID_INTERNAL & & is_inside_tree ( ) ) {
2022-11-28 21:54:47 +00:00
emit_signal ( SceneStringNames : : get_singleton ( ) - > window_input , p_ev ) ;
}
2020-07-01 12:27:43 +00:00
2023-02-15 14:35:16 +00:00
if ( is_inside_tree ( ) ) {
push_input ( p_ev ) ;
}
2020-03-04 16:36:09 +00:00
}
2020-05-14 12:29:06 +00:00
2020-03-04 16:36:09 +00:00
void Window : : _window_input_text ( const String & p_text ) {
2021-08-22 15:37:22 +00:00
push_text_input ( p_text ) ;
2020-03-04 16:36:09 +00:00
}
2020-05-14 12:29:06 +00:00
2020-03-04 16:36:09 +00:00
void Window : : _window_drop_files ( const Vector < String > & p_files ) {
2022-04-10 19:25:24 +00:00
emit_signal ( SNAME ( " files_dropped " ) , p_files ) ;
2020-03-04 16:36:09 +00:00
}
2020-03-06 17:00:16 +00:00
Viewport * Window : : get_parent_viewport ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( nullptr ) ;
2020-03-06 17:00:16 +00:00
if ( get_parent ( ) ) {
return get_parent ( ) - > get_viewport ( ) ;
} else {
return nullptr ;
}
}
Window * Window : : get_parent_visible_window ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( nullptr ) ;
2020-03-06 17:00:16 +00:00
Viewport * vp = get_parent_viewport ( ) ;
Window * window = nullptr ;
while ( vp ) {
window = Object : : cast_to < Window > ( vp ) ;
if ( window & & window - > visible ) {
break ;
}
if ( ! vp - > get_parent ( ) ) {
break ;
}
vp = vp - > get_parent ( ) - > get_viewport ( ) ;
}
return window ;
}
2020-03-25 14:16:19 +00:00
void Window : : popup_on_parent ( const Rect2i & p_parent_rect ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-03-06 17:00:16 +00:00
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
ERR_FAIL_COND_MSG ( window_id = = DisplayServer : : MAIN_WINDOW_ID , " Can't popup the main window. " ) ;
if ( ! is_embedded ( ) ) {
Window * window = get_parent_visible_window ( ) ;
if ( ! window ) {
popup ( p_parent_rect ) ;
} else {
2020-03-25 14:16:19 +00:00
popup ( Rect2i ( window - > get_position ( ) + p_parent_rect . position , p_parent_rect . size ) ) ;
2020-03-06 17:00:16 +00:00
}
} else {
popup ( p_parent_rect ) ;
}
}
2020-03-25 14:16:19 +00:00
void Window : : popup_centered_clamped ( const Size2i & p_size , float p_fallback_ratio ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-03-06 17:00:16 +00:00
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
ERR_FAIL_COND_MSG ( window_id = = DisplayServer : : MAIN_WINDOW_ID , " Can't popup the main window. " ) ;
2023-02-10 13:45:49 +00:00
// Consider the current size when calling with the default value.
Size2i expected_size = p_size = = Size2i ( ) ? size : p_size ;
2020-03-06 17:00:16 +00:00
Rect2 parent_rect ;
if ( is_embedded ( ) ) {
2023-02-05 16:35:39 +00:00
parent_rect = get_embedder ( ) - > get_visible_rect ( ) ;
2020-03-06 17:00:16 +00:00
} else {
DisplayServer : : WindowID parent_id = get_parent_visible_window ( ) - > get_window_id ( ) ;
int parent_screen = DisplayServer : : get_singleton ( ) - > window_get_current_screen ( parent_id ) ;
parent_rect . position = DisplayServer : : get_singleton ( ) - > screen_get_position ( parent_screen ) ;
parent_rect . size = DisplayServer : : get_singleton ( ) - > screen_get_size ( parent_screen ) ;
}
2020-03-25 14:16:19 +00:00
Vector2i size_ratio = parent_rect . size * p_fallback_ratio ;
2020-03-06 17:00:16 +00:00
2020-03-25 14:16:19 +00:00
Rect2i popup_rect ;
2024-03-03 11:49:08 +00:00
popup_rect . size = size_ratio . min ( expected_size ) ;
2022-06-18 10:52:30 +00:00
popup_rect . size = _clamp_window_size ( popup_rect . size ) ;
2022-02-21 08:17:28 +00:00
if ( parent_rect ! = Rect2 ( ) ) {
popup_rect . position = parent_rect . position + ( parent_rect . size - popup_rect . size ) / 2 ;
}
2020-03-06 17:00:16 +00:00
popup ( popup_rect ) ;
}
2020-03-25 14:16:19 +00:00
void Window : : popup_centered ( const Size2i & p_minsize ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-03-06 17:00:16 +00:00
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
ERR_FAIL_COND_MSG ( window_id = = DisplayServer : : MAIN_WINDOW_ID , " Can't popup the main window. " ) ;
2023-02-10 13:45:49 +00:00
// Consider the current size when calling with the default value.
Size2i expected_size = p_minsize = = Size2i ( ) ? size : p_minsize ;
2020-03-06 17:00:16 +00:00
Rect2 parent_rect ;
if ( is_embedded ( ) ) {
2023-02-05 16:35:39 +00:00
parent_rect = get_embedder ( ) - > get_visible_rect ( ) ;
2020-03-06 17:00:16 +00:00
} else {
DisplayServer : : WindowID parent_id = get_parent_visible_window ( ) - > get_window_id ( ) ;
int parent_screen = DisplayServer : : get_singleton ( ) - > window_get_current_screen ( parent_id ) ;
parent_rect . position = DisplayServer : : get_singleton ( ) - > screen_get_position ( parent_screen ) ;
parent_rect . size = DisplayServer : : get_singleton ( ) - > screen_get_size ( parent_screen ) ;
}
2020-03-25 14:16:19 +00:00
Rect2i popup_rect ;
2023-02-10 13:45:49 +00:00
popup_rect . size = _clamp_window_size ( expected_size ) ;
2022-02-21 08:17:28 +00:00
if ( parent_rect ! = Rect2 ( ) ) {
popup_rect . position = parent_rect . position + ( parent_rect . size - popup_rect . size ) / 2 ;
}
2020-03-06 17:00:16 +00:00
popup ( popup_rect ) ;
}
void Window : : popup_centered_ratio ( float p_ratio ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-03-06 17:00:16 +00:00
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
ERR_FAIL_COND_MSG ( window_id = = DisplayServer : : MAIN_WINDOW_ID , " Can't popup the main window. " ) ;
2021-10-24 15:27:08 +00:00
ERR_FAIL_COND_MSG ( p_ratio < = 0.0 | | p_ratio > 1.0 , " Ratio must be between 0.0 and 1.0! " ) ;
2020-03-06 17:00:16 +00:00
2020-05-16 21:36:42 +00:00
Rect2 parent_rect ;
2020-03-06 17:00:16 +00:00
if ( is_embedded ( ) ) {
2023-02-05 16:35:39 +00:00
parent_rect = get_embedder ( ) - > get_visible_rect ( ) ;
2020-03-06 17:00:16 +00:00
} else {
DisplayServer : : WindowID parent_id = get_parent_visible_window ( ) - > get_window_id ( ) ;
int parent_screen = DisplayServer : : get_singleton ( ) - > window_get_current_screen ( parent_id ) ;
parent_rect . position = DisplayServer : : get_singleton ( ) - > screen_get_position ( parent_screen ) ;
parent_rect . size = DisplayServer : : get_singleton ( ) - > screen_get_size ( parent_screen ) ;
}
2020-03-25 14:16:19 +00:00
Rect2i popup_rect ;
2022-02-21 08:17:28 +00:00
if ( parent_rect ! = Rect2 ( ) ) {
popup_rect . size = parent_rect . size * p_ratio ;
2022-06-18 10:52:30 +00:00
popup_rect . size = _clamp_window_size ( popup_rect . size ) ;
2022-02-21 08:17:28 +00:00
popup_rect . position = parent_rect . position + ( parent_rect . size - popup_rect . size ) / 2 ;
}
2020-03-06 17:00:16 +00:00
popup ( popup_rect ) ;
}
2020-03-25 14:16:19 +00:00
void Window : : popup ( const Rect2i & p_screen_rect ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " about_to_popup " ) ) ;
2020-03-14 16:06:39 +00:00
2023-02-05 16:35:39 +00:00
if ( ! get_embedder ( ) & & get_flag ( FLAG_POPUP ) ) {
2022-03-27 00:26:49 +00:00
// Send a focus-out notification when opening a Window Manager Popup.
SceneTree * scene_tree = get_tree ( ) ;
if ( scene_tree ) {
2023-06-23 16:03:48 +00:00
scene_tree - > notify_group_flags ( SceneTree : : GROUP_CALL_DEFERRED , " _viewports " , NOTIFICATION_WM_WINDOW_FOCUS_OUT ) ;
2022-03-27 00:26:49 +00:00
}
}
2021-01-15 00:37:45 +00:00
// Update window size to calculate the actual window size based on contents minimum size and minimum size.
_update_window_size ( ) ;
2020-03-25 14:16:19 +00:00
if ( p_screen_rect ! = Rect2i ( ) ) {
2020-03-06 17:00:16 +00:00
set_position ( p_screen_rect . position ) ;
2023-07-18 15:14:32 +00:00
int screen_id = DisplayServer : : get_singleton ( ) - > get_screen_from_rect ( p_screen_rect ) ;
Size2i screen_size = DisplayServer : : get_singleton ( ) - > screen_get_usable_rect ( screen_id ) . size ;
Size2i new_size = p_screen_rect . size . min ( screen_size ) ;
set_size ( new_size ) ;
2020-03-06 17:00:16 +00:00
}
2020-03-20 02:32:09 +00:00
Rect2i adjust = _popup_adjust_rect ( ) ;
if ( adjust ! = Rect2i ( ) ) {
set_position ( adjust . position ) ;
set_size ( adjust . size ) ;
}
2020-03-30 13:18:29 +00:00
int scr = DisplayServer : : get_singleton ( ) - > get_screen_count ( ) ;
for ( int i = 0 ; i < scr ; i + + ) {
Rect2i r = DisplayServer : : get_singleton ( ) - > screen_get_usable_rect ( i ) ;
if ( r . has_point ( position ) ) {
current_screen = i ;
break ;
}
}
2020-03-06 17:00:16 +00:00
set_transient ( true ) ;
set_visible ( true ) ;
2022-05-23 21:00:29 +00:00
2022-10-01 15:44:33 +00:00
Rect2i parent_rect ;
if ( is_embedded ( ) ) {
2023-02-05 16:35:39 +00:00
parent_rect = get_embedder ( ) - > get_visible_rect ( ) ;
2022-10-01 15:44:33 +00:00
} else {
int screen_id = DisplayServer : : get_singleton ( ) - > window_get_current_screen ( get_window_id ( ) ) ;
parent_rect = DisplayServer : : get_singleton ( ) - > screen_get_usable_rect ( screen_id ) ;
}
if ( parent_rect ! = Rect2i ( ) & & ! parent_rect . intersects ( Rect2i ( position , size ) ) ) {
2022-05-23 21:00:29 +00:00
ERR_PRINT ( vformat ( " Window %d spawned at invalid position: %s. " , get_window_id ( ) , position ) ) ;
2022-10-01 15:44:33 +00:00
set_position ( ( parent_rect . size - size ) / 2 ) ;
2022-05-23 21:00:29 +00:00
}
2023-03-29 20:35:07 +00:00
if ( parent_rect ! = Rect2i ( ) & & is_clamped_to_embedder ( ) & & is_embedded ( ) ) {
2023-03-19 16:26:22 +00:00
Rect2i new_rect = fit_rect_in_parent ( Rect2i ( position , size ) , parent_rect ) ;
set_position ( new_rect . position ) ;
set_size ( new_rect . size ) ;
}
2022-05-23 21:00:29 +00:00
2020-03-06 17:00:16 +00:00
_post_popup ( ) ;
notification ( NOTIFICATION_POST_POPUP ) ;
}
2023-04-20 13:13:21 +00:00
bool Window : : _try_parent_dialog ( Node * p_from_node ) {
ERR_FAIL_NULL_V ( p_from_node , false ) ;
ERR_FAIL_COND_V_MSG ( is_inside_tree ( ) , false , " Attempting to parent and popup a dialog that already has a parent. " ) ;
Window * w = p_from_node - > get_last_exclusive_window ( ) ;
if ( w & & w ! = this ) {
w - > add_child ( this ) ;
return true ;
}
return false ;
}
void Window : : popup_exclusive ( Node * p_from_node , const Rect2i & p_screen_rect ) {
if ( _try_parent_dialog ( p_from_node ) ) {
popup ( p_screen_rect ) ;
}
}
void Window : : popup_exclusive_on_parent ( Node * p_from_node , const Rect2i & p_parent_rect ) {
if ( _try_parent_dialog ( p_from_node ) ) {
popup_on_parent ( p_parent_rect ) ;
}
}
void Window : : popup_exclusive_centered ( Node * p_from_node , const Size2i & p_minsize ) {
if ( _try_parent_dialog ( p_from_node ) ) {
popup_centered ( p_minsize ) ;
}
}
void Window : : popup_exclusive_centered_ratio ( Node * p_from_node , float p_ratio ) {
if ( _try_parent_dialog ( p_from_node ) ) {
popup_centered_ratio ( p_ratio ) ;
}
}
void Window : : popup_exclusive_centered_clamped ( Node * p_from_node , const Size2i & p_size , float p_fallback_ratio ) {
if ( _try_parent_dialog ( p_from_node ) ) {
popup_centered_clamped ( p_size , p_fallback_ratio ) ;
}
}
2023-03-19 16:26:22 +00:00
Rect2i Window : : fit_rect_in_parent ( Rect2i p_rect , const Rect2i & p_parent_rect ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Rect2i ( ) ) ;
2023-03-19 16:26:22 +00:00
Size2i limit = p_parent_rect . size ;
if ( p_rect . position . x + p_rect . size . x > limit . x ) {
p_rect . position . x = limit . x - p_rect . size . x ;
}
if ( p_rect . position . y + p_rect . size . y > limit . y ) {
p_rect . position . y = limit . y - p_rect . size . y ;
}
if ( p_rect . position . x < 0 ) {
p_rect . position . x = 0 ;
}
2023-09-12 13:01:42 +00:00
int title_height = get_flag ( Window : : FLAG_BORDERLESS ) ? 0 : theme_cache . title_height ;
2023-03-19 16:26:22 +00:00
if ( p_rect . position . y < title_height ) {
p_rect . position . y = title_height ;
}
return p_rect ;
}
2020-03-12 12:37:40 +00:00
Size2 Window : : get_contents_minimum_size ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Size2 ( ) ) ;
2023-08-03 13:25:05 +00:00
Vector2 ms ;
if ( GDVIRTUAL_CALL ( _get_contents_minimum_size , ms ) ) {
return ms ;
}
return _get_contents_minimum_size ( ) ;
2020-03-12 12:37:40 +00:00
}
2022-06-18 10:52:30 +00:00
Size2 Window : : get_clamped_minimum_size ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Size2 ( ) ) ;
2022-06-18 10:52:30 +00:00
if ( ! wrap_controls ) {
return min_size ;
}
return min_size . max ( get_contents_minimum_size ( ) ) ;
}
2020-03-06 17:00:16 +00:00
void Window : : grab_focus ( ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-03-14 16:06:39 +00:00
if ( embedder ) {
embedder - > _sub_window_grab_focus ( this ) ;
} else if ( window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
2020-03-06 17:00:16 +00:00
DisplayServer : : get_singleton ( ) - > window_move_to_foreground ( window_id ) ;
}
}
bool Window : : has_focus ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2023-06-15 07:53:31 +00:00
if ( window_id ! = DisplayServer : : INVALID_WINDOW_ID ) {
return DisplayServer : : get_singleton ( ) - > window_is_focused ( window_id ) ;
}
2020-03-06 17:00:16 +00:00
return focused ;
}
2020-03-20 02:32:09 +00:00
Rect2i Window : : get_usable_parent_rect ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Rect2i ( ) ) ;
2020-03-20 02:32:09 +00:00
ERR_FAIL_COND_V ( ! is_inside_tree ( ) , Rect2 ( ) ) ;
2022-09-29 09:53:28 +00:00
Rect2i parent_rect ;
2020-03-20 02:32:09 +00:00
if ( is_embedded ( ) ) {
2023-02-05 16:35:39 +00:00
parent_rect = get_embedder ( ) - > get_visible_rect ( ) ;
2020-03-20 02:32:09 +00:00
} else {
const Window * w = is_visible ( ) ? this : get_parent_visible_window ( ) ;
//find a parent that can contain us
2023-06-06 12:59:54 +00:00
ERR_FAIL_NULL_V ( w , Rect2 ( ) ) ;
2020-03-20 02:32:09 +00:00
2022-09-29 09:53:28 +00:00
parent_rect = DisplayServer : : get_singleton ( ) - > screen_get_usable_rect ( DisplayServer : : get_singleton ( ) - > window_get_current_screen ( w - > get_window_id ( ) ) ) ;
2020-03-20 02:32:09 +00:00
}
2022-09-29 09:53:28 +00:00
return parent_rect ;
2020-03-20 02:32:09 +00:00
}
2020-03-06 17:00:16 +00:00
void Window : : add_child_notify ( Node * p_child ) {
2020-03-14 16:06:39 +00:00
if ( is_inside_tree ( ) & & wrap_controls ) {
child_controls_changed ( ) ;
}
2020-03-06 17:00:16 +00:00
}
void Window : : remove_child_notify ( Node * p_child ) {
2020-03-14 16:06:39 +00:00
if ( is_inside_tree ( ) & & wrap_controls ) {
child_controls_changed ( ) ;
}
2020-03-06 17:00:16 +00:00
}
2022-11-29 20:01:45 +00:00
// Theming.
2022-09-02 14:03:23 +00:00
void Window : : set_theme_owner_node ( Node * p_node ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-09-02 14:03:23 +00:00
theme_owner - > set_owner_node ( p_node ) ;
}
Node * Window : : get_theme_owner_node ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( nullptr ) ;
2022-09-02 14:03:23 +00:00
return theme_owner - > get_owner_node ( ) ;
}
bool Window : : has_theme_owner_node ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-09-02 14:03:23 +00:00
return theme_owner - > has_owner_node ( ) ;
}
2023-09-06 14:11:05 +00:00
void Window : : set_theme_context ( ThemeContext * p_context , bool p_propagate ) {
ERR_MAIN_THREAD_GUARD ;
theme_owner - > set_owner_context ( p_context , p_propagate ) ;
}
2020-03-06 17:00:16 +00:00
void Window : : set_theme ( const Ref < Theme > & p_theme ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-05-14 14:41:43 +00:00
if ( theme = = p_theme ) {
2020-03-06 17:00:16 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2020-03-06 17:00:16 +00:00
2022-07-08 19:29:36 +00:00
if ( theme . is_valid ( ) ) {
2023-07-03 19:29:37 +00:00
theme - > disconnect_changed ( callable_mp ( this , & Window : : _theme_changed ) ) ;
2022-07-08 19:29:36 +00:00
}
2020-03-06 17:00:16 +00:00
theme = p_theme ;
2022-07-08 19:29:36 +00:00
if ( theme . is_valid ( ) ) {
2022-09-02 14:03:23 +00:00
theme_owner - > propagate_theme_changed ( this , this , is_inside_tree ( ) , true ) ;
2023-07-03 19:29:37 +00:00
theme - > connect_changed ( callable_mp ( this , & Window : : _theme_changed ) , CONNECT_DEFERRED ) ;
2022-07-08 19:29:36 +00:00
return ;
}
2020-03-06 17:00:16 +00:00
2022-07-08 19:29:36 +00:00
Control * parent_c = Object : : cast_to < Control > ( get_parent ( ) ) ;
2022-09-02 14:03:23 +00:00
if ( parent_c & & parent_c - > has_theme_owner_node ( ) ) {
theme_owner - > propagate_theme_changed ( this , parent_c - > get_theme_owner_node ( ) , is_inside_tree ( ) , true ) ;
2022-07-08 19:29:36 +00:00
return ;
2020-03-06 17:00:16 +00:00
}
2022-07-08 19:29:36 +00:00
Window * parent_w = cast_to < Window > ( get_parent ( ) ) ;
2022-09-02 14:03:23 +00:00
if ( parent_w & & parent_w - > has_theme_owner_node ( ) ) {
theme_owner - > propagate_theme_changed ( this , parent_w - > get_theme_owner_node ( ) , is_inside_tree ( ) , true ) ;
2022-07-08 19:29:36 +00:00
return ;
}
2022-09-02 14:03:23 +00:00
theme_owner - > propagate_theme_changed ( this , nullptr , is_inside_tree ( ) , true ) ;
2020-03-06 17:00:16 +00:00
}
2020-05-14 12:29:06 +00:00
2020-03-06 17:00:16 +00:00
Ref < Theme > Window : : get_theme ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Ref < Theme > ( ) ) ;
2020-03-06 17:00:16 +00:00
return theme ;
}
2022-07-08 19:29:36 +00:00
void Window : : _theme_changed ( ) {
if ( is_inside_tree ( ) ) {
2022-09-02 14:03:23 +00:00
theme_owner - > propagate_theme_changed ( this , this , true , false ) ;
2022-07-08 19:29:36 +00:00
}
}
2022-11-29 20:01:45 +00:00
void Window : : _notify_theme_override_changed ( ) {
if ( ! bulk_theme_override & & is_inside_tree ( ) ) {
notification ( NOTIFICATION_THEME_CHANGED ) ;
}
}
2022-09-01 10:38:08 +00:00
void Window : : _invalidate_theme_cache ( ) {
theme_icon_cache . clear ( ) ;
theme_style_cache . clear ( ) ;
theme_font_cache . clear ( ) ;
theme_font_size_cache . clear ( ) ;
theme_color_cache . clear ( ) ;
theme_constant_cache . clear ( ) ;
}
void Window : : _update_theme_item_cache ( ) {
2022-11-29 20:01:45 +00:00
// Request an update on the next frame to reflect theme changes.
// Updating without a delay can cause a lot of lag.
2023-01-15 15:04:05 +00:00
if ( ! wrap_controls ) {
updating_embedded_window = true ;
2023-12-18 14:46:56 +00:00
callable_mp ( this , & Window : : _update_embedded_window ) . call_deferred ( ) ;
2023-01-15 15:04:05 +00:00
} else {
child_controls_changed ( ) ;
}
2023-09-08 19:00:10 +00:00
ThemeDB : : get_singleton ( ) - > update_class_instance_items ( this ) ;
2023-01-15 15:04:05 +00:00
}
void Window : : _update_embedded_window ( ) {
if ( ! updating_embedded_window ) {
return ;
}
if ( embedder ) {
embedder - > _sub_window_update ( this ) ;
} ;
updating_embedded_window = false ;
2022-09-01 10:38:08 +00:00
}
2021-07-04 20:42:23 +00:00
void Window : : set_theme_type_variation ( const StringName & p_theme_type ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2021-07-04 20:42:23 +00:00
theme_type_variation = p_theme_type ;
2022-07-08 19:29:36 +00:00
if ( is_inside_tree ( ) ) {
notification ( NOTIFICATION_THEME_CHANGED ) ;
}
2020-03-12 12:37:40 +00:00
}
2020-05-14 12:29:06 +00:00
2021-07-04 20:42:23 +00:00
StringName Window : : get_theme_type_variation ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( StringName ( ) ) ;
2021-07-04 20:42:23 +00:00
return theme_type_variation ;
2020-03-12 12:37:40 +00:00
}
2020-05-14 12:29:06 +00:00
2022-11-29 20:01:45 +00:00
/// Theme property lookup.
2021-03-30 17:16:33 +00:00
Ref < Texture2D > Window : : get_theme_icon ( const StringName & p_name , const StringName & p_theme_type ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Ref < Texture2D > ( ) ) ;
2023-04-03 16:01:10 +00:00
if ( ! initialized ) {
2024-01-28 20:51:39 +00:00
WARN_PRINT_ONCE ( vformat ( " Attempting to access theme items too early in %s; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED " , get_description ( ) ) ) ;
2023-04-03 16:01:10 +00:00
}
2022-11-29 20:01:45 +00:00
if ( p_theme_type = = StringName ( ) | | p_theme_type = = get_class_name ( ) | | p_theme_type = = theme_type_variation ) {
const Ref < Texture2D > * tex = theme_icon_override . getptr ( p_name ) ;
if ( tex ) {
return * tex ;
}
}
2022-09-01 10:38:08 +00:00
if ( theme_icon_cache . has ( p_theme_type ) & & theme_icon_cache [ p_theme_type ] . has ( p_name ) ) {
return theme_icon_cache [ p_theme_type ] [ p_name ] ;
}
2021-03-30 17:16:33 +00:00
List < StringName > theme_types ;
2022-09-02 14:03:23 +00:00
theme_owner - > get_theme_type_dependencies ( this , p_theme_type , & theme_types ) ;
Ref < Texture2D > icon = theme_owner - > get_theme_item_in_types ( Theme : : DATA_TYPE_ICON , p_name , theme_types ) ;
2022-09-01 10:38:08 +00:00
theme_icon_cache [ p_theme_type ] [ p_name ] = icon ;
return icon ;
2020-03-12 12:37:40 +00:00
}
2020-05-14 12:29:06 +00:00
2021-03-30 17:16:33 +00:00
Ref < StyleBox > Window : : get_theme_stylebox ( const StringName & p_name , const StringName & p_theme_type ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Ref < StyleBox > ( ) ) ;
2023-04-03 16:01:10 +00:00
if ( ! initialized ) {
2024-01-28 20:51:39 +00:00
WARN_PRINT_ONCE ( vformat ( " Attempting to access theme items too early in %s; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED " , get_description ( ) ) ) ;
2023-04-03 16:01:10 +00:00
}
2022-11-29 20:01:45 +00:00
if ( p_theme_type = = StringName ( ) | | p_theme_type = = get_class_name ( ) | | p_theme_type = = theme_type_variation ) {
const Ref < StyleBox > * style = theme_style_override . getptr ( p_name ) ;
if ( style ) {
return * style ;
}
}
2022-09-01 10:38:08 +00:00
if ( theme_style_cache . has ( p_theme_type ) & & theme_style_cache [ p_theme_type ] . has ( p_name ) ) {
return theme_style_cache [ p_theme_type ] [ p_name ] ;
}
2021-03-30 17:16:33 +00:00
List < StringName > theme_types ;
2022-09-02 14:03:23 +00:00
theme_owner - > get_theme_type_dependencies ( this , p_theme_type , & theme_types ) ;
Ref < StyleBox > style = theme_owner - > get_theme_item_in_types ( Theme : : DATA_TYPE_STYLEBOX , p_name , theme_types ) ;
2022-09-01 10:38:08 +00:00
theme_style_cache [ p_theme_type ] [ p_name ] = style ;
return style ;
2020-09-03 11:22:16 +00:00
}
2021-03-30 17:16:33 +00:00
Ref < Font > Window : : get_theme_font ( const StringName & p_name , const StringName & p_theme_type ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Ref < Font > ( ) ) ;
2023-04-03 16:01:10 +00:00
if ( ! initialized ) {
2024-01-28 20:51:39 +00:00
WARN_PRINT_ONCE ( vformat ( " Attempting to access theme items too early in %s; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED " , get_description ( ) ) ) ;
2023-04-03 16:01:10 +00:00
}
2022-11-29 20:01:45 +00:00
if ( p_theme_type = = StringName ( ) | | p_theme_type = = get_class_name ( ) | | p_theme_type = = theme_type_variation ) {
const Ref < Font > * font = theme_font_override . getptr ( p_name ) ;
if ( font ) {
return * font ;
}
}
2022-09-01 10:38:08 +00:00
if ( theme_font_cache . has ( p_theme_type ) & & theme_font_cache [ p_theme_type ] . has ( p_name ) ) {
return theme_font_cache [ p_theme_type ] [ p_name ] ;
}
2021-03-30 17:16:33 +00:00
List < StringName > theme_types ;
2022-09-02 14:03:23 +00:00
theme_owner - > get_theme_type_dependencies ( this , p_theme_type , & theme_types ) ;
Ref < Font > font = theme_owner - > get_theme_item_in_types ( Theme : : DATA_TYPE_FONT , p_name , theme_types ) ;
2022-09-01 10:38:08 +00:00
theme_font_cache [ p_theme_type ] [ p_name ] = font ;
return font ;
2020-03-12 12:37:40 +00:00
}
2020-05-14 12:29:06 +00:00
2021-03-30 17:16:33 +00:00
int Window : : get_theme_font_size ( const StringName & p_name , const StringName & p_theme_type ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( 0 ) ;
2023-04-03 16:01:10 +00:00
if ( ! initialized ) {
2024-01-28 20:51:39 +00:00
WARN_PRINT_ONCE ( vformat ( " Attempting to access theme items too early in %s; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED " , get_description ( ) ) ) ;
2023-04-03 16:01:10 +00:00
}
2022-11-29 20:01:45 +00:00
if ( p_theme_type = = StringName ( ) | | p_theme_type = = get_class_name ( ) | | p_theme_type = = theme_type_variation ) {
const int * font_size = theme_font_size_override . getptr ( p_name ) ;
if ( font_size & & ( * font_size ) > 0 ) {
return * font_size ;
}
}
2022-09-01 10:38:08 +00:00
if ( theme_font_size_cache . has ( p_theme_type ) & & theme_font_size_cache [ p_theme_type ] . has ( p_name ) ) {
return theme_font_size_cache [ p_theme_type ] [ p_name ] ;
}
2021-03-30 17:16:33 +00:00
List < StringName > theme_types ;
2022-09-02 14:03:23 +00:00
theme_owner - > get_theme_type_dependencies ( this , p_theme_type , & theme_types ) ;
int font_size = theme_owner - > get_theme_item_in_types ( Theme : : DATA_TYPE_FONT_SIZE , p_name , theme_types ) ;
2022-09-01 10:38:08 +00:00
theme_font_size_cache [ p_theme_type ] [ p_name ] = font_size ;
return font_size ;
2020-03-12 12:37:40 +00:00
}
2021-03-30 17:16:33 +00:00
Color Window : : get_theme_color ( const StringName & p_name , const StringName & p_theme_type ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Color ( ) ) ;
2023-04-03 16:01:10 +00:00
if ( ! initialized ) {
2024-01-28 20:51:39 +00:00
WARN_PRINT_ONCE ( vformat ( " Attempting to access theme items too early in %s; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED " , get_description ( ) ) ) ;
2023-04-03 16:01:10 +00:00
}
2022-11-29 20:01:45 +00:00
if ( p_theme_type = = StringName ( ) | | p_theme_type = = get_class_name ( ) | | p_theme_type = = theme_type_variation ) {
const Color * color = theme_color_override . getptr ( p_name ) ;
if ( color ) {
return * color ;
}
}
2022-09-01 10:38:08 +00:00
if ( theme_color_cache . has ( p_theme_type ) & & theme_color_cache [ p_theme_type ] . has ( p_name ) ) {
return theme_color_cache [ p_theme_type ] [ p_name ] ;
}
2021-03-30 17:16:33 +00:00
List < StringName > theme_types ;
2022-09-02 14:03:23 +00:00
theme_owner - > get_theme_type_dependencies ( this , p_theme_type , & theme_types ) ;
Color color = theme_owner - > get_theme_item_in_types ( Theme : : DATA_TYPE_COLOR , p_name , theme_types ) ;
2022-09-01 10:38:08 +00:00
theme_color_cache [ p_theme_type ] [ p_name ] = color ;
return color ;
2020-03-12 12:37:40 +00:00
}
2020-05-14 12:29:06 +00:00
2021-03-30 17:16:33 +00:00
int Window : : get_theme_constant ( const StringName & p_name , const StringName & p_theme_type ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( 0 ) ;
2023-04-03 16:01:10 +00:00
if ( ! initialized ) {
2024-01-28 20:51:39 +00:00
WARN_PRINT_ONCE ( vformat ( " Attempting to access theme items too early in %s; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED " , get_description ( ) ) ) ;
2023-04-03 16:01:10 +00:00
}
2022-11-29 20:01:45 +00:00
if ( p_theme_type = = StringName ( ) | | p_theme_type = = get_class_name ( ) | | p_theme_type = = theme_type_variation ) {
const int * constant = theme_constant_override . getptr ( p_name ) ;
if ( constant ) {
return * constant ;
}
}
2022-09-01 10:38:08 +00:00
if ( theme_constant_cache . has ( p_theme_type ) & & theme_constant_cache [ p_theme_type ] . has ( p_name ) ) {
return theme_constant_cache [ p_theme_type ] [ p_name ] ;
}
2021-03-30 17:16:33 +00:00
List < StringName > theme_types ;
2022-09-02 14:03:23 +00:00
theme_owner - > get_theme_type_dependencies ( this , p_theme_type , & theme_types ) ;
int constant = theme_owner - > get_theme_item_in_types ( Theme : : DATA_TYPE_CONSTANT , p_name , theme_types ) ;
2022-09-01 10:38:08 +00:00
theme_constant_cache [ p_theme_type ] [ p_name ] = constant ;
return constant ;
2020-03-12 12:37:40 +00:00
}
2020-05-14 12:29:06 +00:00
2023-09-08 19:00:10 +00:00
Variant Window : : get_theme_item ( Theme : : DataType p_data_type , const StringName & p_name , const StringName & p_theme_type ) const {
switch ( p_data_type ) {
case Theme : : DATA_TYPE_COLOR :
return get_theme_color ( p_name , p_theme_type ) ;
case Theme : : DATA_TYPE_CONSTANT :
return get_theme_constant ( p_name , p_theme_type ) ;
case Theme : : DATA_TYPE_FONT :
return get_theme_font ( p_name , p_theme_type ) ;
case Theme : : DATA_TYPE_FONT_SIZE :
return get_theme_font_size ( p_name , p_theme_type ) ;
case Theme : : DATA_TYPE_ICON :
return get_theme_icon ( p_name , p_theme_type ) ;
case Theme : : DATA_TYPE_STYLEBOX :
return get_theme_stylebox ( p_name , p_theme_type ) ;
case Theme : : DATA_TYPE_MAX :
break ; // Can't happen, but silences warning.
}
return Variant ( ) ;
}
2023-08-13 00:33:39 +00:00
# ifdef TOOLS_ENABLED
Ref < Texture2D > Window : : get_editor_theme_icon ( const StringName & p_name ) const {
return get_theme_icon ( p_name , SNAME ( " EditorIcons " ) ) ;
}
# endif
2021-03-30 17:16:33 +00:00
bool Window : : has_theme_icon ( const StringName & p_name , const StringName & p_theme_type ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2023-04-03 16:01:10 +00:00
if ( ! initialized ) {
2024-01-28 20:51:39 +00:00
WARN_PRINT_ONCE ( vformat ( " Attempting to access theme items too early in %s; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED " , get_description ( ) ) ) ;
2023-04-03 16:01:10 +00:00
}
2022-11-29 20:01:45 +00:00
if ( p_theme_type = = StringName ( ) | | p_theme_type = = get_class_name ( ) | | p_theme_type = = theme_type_variation ) {
if ( has_theme_icon_override ( p_name ) ) {
return true ;
}
}
2021-03-30 17:16:33 +00:00
List < StringName > theme_types ;
2022-09-02 14:03:23 +00:00
theme_owner - > get_theme_type_dependencies ( this , p_theme_type , & theme_types ) ;
return theme_owner - > has_theme_item_in_types ( Theme : : DATA_TYPE_ICON , p_name , theme_types ) ;
2020-03-12 12:37:40 +00:00
}
2020-05-14 12:29:06 +00:00
2021-03-30 17:16:33 +00:00
bool Window : : has_theme_stylebox ( const StringName & p_name , const StringName & p_theme_type ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2023-04-03 16:01:10 +00:00
if ( ! initialized ) {
2024-01-28 20:51:39 +00:00
WARN_PRINT_ONCE ( vformat ( " Attempting to access theme items too early in %s; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED " , get_description ( ) ) ) ;
2023-04-03 16:01:10 +00:00
}
2022-11-29 20:01:45 +00:00
if ( p_theme_type = = StringName ( ) | | p_theme_type = = get_class_name ( ) | | p_theme_type = = theme_type_variation ) {
if ( has_theme_stylebox_override ( p_name ) ) {
return true ;
}
}
2021-03-30 17:16:33 +00:00
List < StringName > theme_types ;
2022-09-02 14:03:23 +00:00
theme_owner - > get_theme_type_dependencies ( this , p_theme_type , & theme_types ) ;
return theme_owner - > has_theme_item_in_types ( Theme : : DATA_TYPE_STYLEBOX , p_name , theme_types ) ;
2020-09-03 11:22:16 +00:00
}
2021-03-30 17:16:33 +00:00
bool Window : : has_theme_font ( const StringName & p_name , const StringName & p_theme_type ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2023-04-03 16:01:10 +00:00
if ( ! initialized ) {
2024-01-28 20:51:39 +00:00
WARN_PRINT_ONCE ( vformat ( " Attempting to access theme items too early in %s; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED " , get_description ( ) ) ) ;
2023-04-03 16:01:10 +00:00
}
2022-11-29 20:01:45 +00:00
if ( p_theme_type = = StringName ( ) | | p_theme_type = = get_class_name ( ) | | p_theme_type = = theme_type_variation ) {
if ( has_theme_font_override ( p_name ) ) {
return true ;
}
}
2021-03-30 17:16:33 +00:00
List < StringName > theme_types ;
2022-09-02 14:03:23 +00:00
theme_owner - > get_theme_type_dependencies ( this , p_theme_type , & theme_types ) ;
return theme_owner - > has_theme_item_in_types ( Theme : : DATA_TYPE_FONT , p_name , theme_types ) ;
2020-03-12 12:37:40 +00:00
}
2020-05-14 12:29:06 +00:00
2021-03-30 17:16:33 +00:00
bool Window : : has_theme_font_size ( const StringName & p_name , const StringName & p_theme_type ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2023-04-03 16:01:10 +00:00
if ( ! initialized ) {
2024-01-28 20:51:39 +00:00
WARN_PRINT_ONCE ( vformat ( " Attempting to access theme items too early in %s; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED " , get_description ( ) ) ) ;
2023-04-03 16:01:10 +00:00
}
2022-11-29 20:01:45 +00:00
if ( p_theme_type = = StringName ( ) | | p_theme_type = = get_class_name ( ) | | p_theme_type = = theme_type_variation ) {
if ( has_theme_font_size_override ( p_name ) ) {
return true ;
}
}
2021-03-30 17:16:33 +00:00
List < StringName > theme_types ;
2022-09-02 14:03:23 +00:00
theme_owner - > get_theme_type_dependencies ( this , p_theme_type , & theme_types ) ;
return theme_owner - > has_theme_item_in_types ( Theme : : DATA_TYPE_FONT_SIZE , p_name , theme_types ) ;
2021-03-30 17:16:33 +00:00
}
bool Window : : has_theme_color ( const StringName & p_name , const StringName & p_theme_type ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2023-04-03 16:01:10 +00:00
if ( ! initialized ) {
2024-01-28 20:51:39 +00:00
WARN_PRINT_ONCE ( vformat ( " Attempting to access theme items too early in %s; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED " , get_description ( ) ) ) ;
2023-04-03 16:01:10 +00:00
}
2022-11-29 20:01:45 +00:00
if ( p_theme_type = = StringName ( ) | | p_theme_type = = get_class_name ( ) | | p_theme_type = = theme_type_variation ) {
if ( has_theme_color_override ( p_name ) ) {
return true ;
}
}
2021-03-30 17:16:33 +00:00
List < StringName > theme_types ;
2022-09-02 14:03:23 +00:00
theme_owner - > get_theme_type_dependencies ( this , p_theme_type , & theme_types ) ;
return theme_owner - > has_theme_item_in_types ( Theme : : DATA_TYPE_COLOR , p_name , theme_types ) ;
2021-03-30 17:16:33 +00:00
}
bool Window : : has_theme_constant ( const StringName & p_name , const StringName & p_theme_type ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2023-04-03 16:01:10 +00:00
if ( ! initialized ) {
2024-01-28 20:51:39 +00:00
WARN_PRINT_ONCE ( vformat ( " Attempting to access theme items too early in %s; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED " , get_description ( ) ) ) ;
2023-04-03 16:01:10 +00:00
}
2022-11-29 20:01:45 +00:00
if ( p_theme_type = = StringName ( ) | | p_theme_type = = get_class_name ( ) | | p_theme_type = = theme_type_variation ) {
if ( has_theme_constant_override ( p_name ) ) {
return true ;
}
}
2021-03-30 17:16:33 +00:00
List < StringName > theme_types ;
2022-09-02 14:03:23 +00:00
theme_owner - > get_theme_type_dependencies ( this , p_theme_type , & theme_types ) ;
return theme_owner - > has_theme_item_in_types ( Theme : : DATA_TYPE_CONSTANT , p_name , theme_types ) ;
2020-03-12 12:37:40 +00:00
}
2022-11-29 20:01:45 +00:00
/// Local property overrides.
void Window : : add_theme_icon_override ( const StringName & p_name , const Ref < Texture2D > & p_icon ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-11-29 20:01:45 +00:00
ERR_FAIL_COND ( ! p_icon . is_valid ( ) ) ;
if ( theme_icon_override . has ( p_name ) ) {
2023-07-03 19:29:37 +00:00
theme_icon_override [ p_name ] - > disconnect_changed ( callable_mp ( this , & Window : : _notify_theme_override_changed ) ) ;
2022-11-29 20:01:45 +00:00
}
theme_icon_override [ p_name ] = p_icon ;
2023-07-03 19:29:37 +00:00
theme_icon_override [ p_name ] - > connect_changed ( callable_mp ( this , & Window : : _notify_theme_override_changed ) , CONNECT_REFERENCE_COUNTED ) ;
2022-11-29 20:01:45 +00:00
_notify_theme_override_changed ( ) ;
}
void Window : : add_theme_style_override ( const StringName & p_name , const Ref < StyleBox > & p_style ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-11-29 20:01:45 +00:00
ERR_FAIL_COND ( ! p_style . is_valid ( ) ) ;
if ( theme_style_override . has ( p_name ) ) {
2023-07-03 19:29:37 +00:00
theme_style_override [ p_name ] - > disconnect_changed ( callable_mp ( this , & Window : : _notify_theme_override_changed ) ) ;
2022-11-29 20:01:45 +00:00
}
theme_style_override [ p_name ] = p_style ;
2023-07-03 19:29:37 +00:00
theme_style_override [ p_name ] - > connect_changed ( callable_mp ( this , & Window : : _notify_theme_override_changed ) , CONNECT_REFERENCE_COUNTED ) ;
2022-11-29 20:01:45 +00:00
_notify_theme_override_changed ( ) ;
}
void Window : : add_theme_font_override ( const StringName & p_name , const Ref < Font > & p_font ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-11-29 20:01:45 +00:00
ERR_FAIL_COND ( ! p_font . is_valid ( ) ) ;
if ( theme_font_override . has ( p_name ) ) {
2023-07-03 19:29:37 +00:00
theme_font_override [ p_name ] - > disconnect_changed ( callable_mp ( this , & Window : : _notify_theme_override_changed ) ) ;
2022-11-29 20:01:45 +00:00
}
theme_font_override [ p_name ] = p_font ;
2023-07-03 19:29:37 +00:00
theme_font_override [ p_name ] - > connect_changed ( callable_mp ( this , & Window : : _notify_theme_override_changed ) , CONNECT_REFERENCE_COUNTED ) ;
2022-11-29 20:01:45 +00:00
_notify_theme_override_changed ( ) ;
}
void Window : : add_theme_font_size_override ( const StringName & p_name , int p_font_size ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-11-29 20:01:45 +00:00
theme_font_size_override [ p_name ] = p_font_size ;
_notify_theme_override_changed ( ) ;
}
void Window : : add_theme_color_override ( const StringName & p_name , const Color & p_color ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-11-29 20:01:45 +00:00
theme_color_override [ p_name ] = p_color ;
_notify_theme_override_changed ( ) ;
}
void Window : : add_theme_constant_override ( const StringName & p_name , int p_constant ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-11-29 20:01:45 +00:00
theme_constant_override [ p_name ] = p_constant ;
_notify_theme_override_changed ( ) ;
}
void Window : : remove_theme_icon_override ( const StringName & p_name ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-11-29 20:01:45 +00:00
if ( theme_icon_override . has ( p_name ) ) {
2023-07-03 19:29:37 +00:00
theme_icon_override [ p_name ] - > disconnect_changed ( callable_mp ( this , & Window : : _notify_theme_override_changed ) ) ;
2022-11-29 20:01:45 +00:00
}
theme_icon_override . erase ( p_name ) ;
_notify_theme_override_changed ( ) ;
}
void Window : : remove_theme_style_override ( const StringName & p_name ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-11-29 20:01:45 +00:00
if ( theme_style_override . has ( p_name ) ) {
2023-07-03 19:29:37 +00:00
theme_style_override [ p_name ] - > disconnect_changed ( callable_mp ( this , & Window : : _notify_theme_override_changed ) ) ;
2022-11-29 20:01:45 +00:00
}
theme_style_override . erase ( p_name ) ;
_notify_theme_override_changed ( ) ;
}
void Window : : remove_theme_font_override ( const StringName & p_name ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-11-29 20:01:45 +00:00
if ( theme_font_override . has ( p_name ) ) {
2023-07-03 19:29:37 +00:00
theme_font_override [ p_name ] - > disconnect_changed ( callable_mp ( this , & Window : : _notify_theme_override_changed ) ) ;
2022-11-29 20:01:45 +00:00
}
theme_font_override . erase ( p_name ) ;
_notify_theme_override_changed ( ) ;
}
void Window : : remove_theme_font_size_override ( const StringName & p_name ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-11-29 20:01:45 +00:00
theme_font_size_override . erase ( p_name ) ;
_notify_theme_override_changed ( ) ;
}
void Window : : remove_theme_color_override ( const StringName & p_name ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-11-29 20:01:45 +00:00
theme_color_override . erase ( p_name ) ;
_notify_theme_override_changed ( ) ;
}
void Window : : remove_theme_constant_override ( const StringName & p_name ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-11-29 20:01:45 +00:00
theme_constant_override . erase ( p_name ) ;
_notify_theme_override_changed ( ) ;
}
bool Window : : has_theme_icon_override ( const StringName & p_name ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-11-29 20:01:45 +00:00
const Ref < Texture2D > * tex = theme_icon_override . getptr ( p_name ) ;
return tex ! = nullptr ;
}
bool Window : : has_theme_stylebox_override ( const StringName & p_name ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-11-29 20:01:45 +00:00
const Ref < StyleBox > * style = theme_style_override . getptr ( p_name ) ;
return style ! = nullptr ;
}
bool Window : : has_theme_font_override ( const StringName & p_name ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-11-29 20:01:45 +00:00
const Ref < Font > * font = theme_font_override . getptr ( p_name ) ;
return font ! = nullptr ;
}
bool Window : : has_theme_font_size_override ( const StringName & p_name ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-11-29 20:01:45 +00:00
const int * font_size = theme_font_size_override . getptr ( p_name ) ;
return font_size ! = nullptr ;
}
bool Window : : has_theme_color_override ( const StringName & p_name ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-11-29 20:01:45 +00:00
const Color * color = theme_color_override . getptr ( p_name ) ;
return color ! = nullptr ;
}
bool Window : : has_theme_constant_override ( const StringName & p_name ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2022-11-29 20:01:45 +00:00
const int * constant = theme_constant_override . getptr ( p_name ) ;
return constant ! = nullptr ;
}
/// Default theme properties.
2021-10-02 20:06:14 +00:00
float Window : : get_theme_default_base_scale ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( 0 ) ;
2022-09-02 14:03:23 +00:00
return theme_owner - > get_theme_default_base_scale ( ) ;
2021-10-02 20:06:14 +00:00
}
Ref < Font > Window : : get_theme_default_font ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Ref < Font > ( ) ) ;
2022-09-02 14:03:23 +00:00
return theme_owner - > get_theme_default_font ( ) ;
2021-10-02 20:06:14 +00:00
}
int Window : : get_theme_default_font_size ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( 0 ) ;
2022-09-02 14:03:23 +00:00
return theme_owner - > get_theme_default_font_size ( ) ;
2021-10-02 20:06:14 +00:00
}
2022-11-29 20:01:45 +00:00
/// Bulk actions.
void Window : : begin_bulk_theme_override ( ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-11-29 20:01:45 +00:00
bulk_theme_override = true ;
}
void Window : : end_bulk_theme_override ( ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2022-11-29 20:01:45 +00:00
ERR_FAIL_COND ( ! bulk_theme_override ) ;
bulk_theme_override = false ;
_notify_theme_override_changed ( ) ;
}
//
2020-03-14 16:06:39 +00:00
Rect2i Window : : get_parent_rect ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Rect2i ( ) ) ;
2020-03-14 16:06:39 +00:00
ERR_FAIL_COND_V ( ! is_inside_tree ( ) , Rect2i ( ) ) ;
2020-03-12 12:37:40 +00:00
if ( is_embedded ( ) ) {
//viewport
2020-03-14 16:06:39 +00:00
Node * n = get_parent ( ) ;
2023-06-06 12:59:54 +00:00
ERR_FAIL_NULL_V ( n , Rect2i ( ) ) ;
2020-03-14 16:06:39 +00:00
Viewport * p = n - > get_viewport ( ) ;
2023-06-06 12:59:54 +00:00
ERR_FAIL_NULL_V ( p , Rect2i ( ) ) ;
2020-03-14 16:06:39 +00:00
return p - > get_visible_rect ( ) ;
2020-03-12 12:37:40 +00:00
} else {
int x = get_position ( ) . x ;
int closest_dist = 0x7FFFFFFF ;
Rect2i closest_rect ;
for ( int i = 0 ; i < DisplayServer : : get_singleton ( ) - > get_screen_count ( ) ; i + + ) {
Rect2i s ( DisplayServer : : get_singleton ( ) - > screen_get_position ( i ) , DisplayServer : : get_singleton ( ) - > screen_get_size ( i ) ) ;
int d ;
if ( x > = s . position . x & & x < s . size . x ) {
//contained
closest_rect = s ;
break ;
} else if ( x < s . position . x ) {
d = s . position . x - x ;
} else {
d = x - ( s . position . x + s . size . x ) ;
}
if ( d < closest_dist ) {
closest_dist = d ;
closest_rect = s ;
}
}
return closest_rect ;
}
}
2020-07-01 15:39:42 +00:00
void Window : : set_clamp_to_embedder ( bool p_enable ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-07-01 15:39:42 +00:00
clamp_to_embedder = p_enable ;
}
bool Window : : is_clamped_to_embedder ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2020-07-01 15:39:42 +00:00
return clamp_to_embedder ;
}
2023-04-20 13:13:21 +00:00
void Window : : set_unparent_when_invisible ( bool p_unparent ) {
unparent_when_invisible = p_unparent ;
}
2020-09-03 11:22:16 +00:00
void Window : : set_layout_direction ( Window : : LayoutDirection p_direction ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2020-09-03 11:22:16 +00:00
ERR_FAIL_INDEX ( ( int ) p_direction , 4 ) ;
layout_dir = p_direction ;
propagate_notification ( Control : : NOTIFICATION_LAYOUT_DIRECTION_CHANGED ) ;
}
Window : : LayoutDirection Window : : get_layout_direction ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( LAYOUT_DIRECTION_INHERITED ) ;
2020-09-03 11:22:16 +00:00
return layout_dir ;
}
bool Window : : is_layout_rtl ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2020-09-03 11:22:16 +00:00
if ( layout_dir = = LAYOUT_DIRECTION_INHERITED ) {
2023-11-17 06:54:07 +00:00
# ifdef TOOLS_ENABLED
if ( is_part_of_edited_scene ( ) & & GLOBAL_GET ( SNAME ( " internationalization/rendering/force_right_to_left_layout_direction " ) ) ) {
return true ;
}
if ( is_inside_tree ( ) ) {
Node * edited_scene_root = get_tree ( ) - > get_edited_scene_root ( ) ;
if ( edited_scene_root = = this ) {
int proj_root_layout_direction = GLOBAL_GET ( SNAME ( " internationalization/rendering/root_node_layout_direction " ) ) ;
if ( proj_root_layout_direction = = 1 ) {
return false ;
} else if ( proj_root_layout_direction = = 2 ) {
return true ;
} else if ( proj_root_layout_direction = = 3 ) {
String locale = OS : : get_singleton ( ) - > get_locale ( ) ;
return TS - > is_locale_right_to_left ( locale ) ;
} else {
String locale = TranslationServer : : get_singleton ( ) - > get_tool_locale ( ) ;
return TS - > is_locale_right_to_left ( locale ) ;
}
}
}
# else
2023-02-21 22:08:05 +00:00
if ( GLOBAL_GET ( SNAME ( " internationalization/rendering/force_right_to_left_layout_direction " ) ) ) {
return true ;
}
2023-11-17 06:54:07 +00:00
# endif
2023-02-21 22:08:05 +00:00
Node * parent_node = get_parent ( ) ;
while ( parent_node ) {
Control * parent_control = Object : : cast_to < Control > ( parent_node ) ;
if ( parent_control ) {
return parent_control - > is_layout_rtl ( ) ;
2020-09-03 11:22:16 +00:00
}
2023-02-21 22:08:05 +00:00
Window * parent_window = Object : : cast_to < Window > ( parent_node ) ;
if ( parent_window ) {
return parent_window - > is_layout_rtl ( ) ;
}
parent_node = parent_node - > get_parent ( ) ;
}
2023-11-17 06:54:07 +00:00
if ( root_layout_direction = = 1 ) {
2023-02-21 22:08:05 +00:00
return false ;
2023-11-17 06:54:07 +00:00
} else if ( root_layout_direction = = 2 ) {
2023-02-21 22:08:05 +00:00
return true ;
2023-11-17 06:54:07 +00:00
} else if ( root_layout_direction = = 3 ) {
String locale = OS : : get_singleton ( ) - > get_locale ( ) ;
return TS - > is_locale_right_to_left ( locale ) ;
2023-02-21 22:08:05 +00:00
} else {
2020-09-03 11:22:16 +00:00
String locale = TranslationServer : : get_singleton ( ) - > get_tool_locale ( ) ;
return TS - > is_locale_right_to_left ( locale ) ;
}
} else if ( layout_dir = = LAYOUT_DIRECTION_LOCALE ) {
2021-07-19 17:25:15 +00:00
if ( GLOBAL_GET ( SNAME ( " internationalization/rendering/force_right_to_left_layout_direction " ) ) ) {
2020-09-03 11:22:16 +00:00
return true ;
2023-02-21 22:08:05 +00:00
} else {
String locale = TranslationServer : : get_singleton ( ) - > get_tool_locale ( ) ;
return TS - > is_locale_right_to_left ( locale ) ;
2020-09-03 11:22:16 +00:00
}
} else {
return ( layout_dir = = LAYOUT_DIRECTION_RTL ) ;
}
}
2024-01-23 21:29:45 +00:00
# ifndef DISABLE_DEPRECATED
2021-05-27 17:31:33 +00:00
void Window : : set_auto_translate ( bool p_enable ) {
2023-05-12 11:53:15 +00:00
ERR_MAIN_THREAD_GUARD ;
2024-01-23 21:29:45 +00:00
set_auto_translate_mode ( p_enable ? AUTO_TRANSLATE_MODE_ALWAYS : AUTO_TRANSLATE_MODE_DISABLED ) ;
2021-05-27 17:31:33 +00:00
}
bool Window : : is_auto_translating ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( false ) ;
2024-01-23 21:29:45 +00:00
return can_auto_translate ( ) ;
2021-05-27 17:31:33 +00:00
}
2024-01-23 21:29:45 +00:00
# endif
2021-05-27 17:31:33 +00:00
2023-02-02 18:28:14 +00:00
Transform2D Window : : get_final_transform ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Transform2D ( ) ) ;
2023-02-02 18:28:14 +00:00
return window_transform * stretch_transform * global_canvas_transform ;
}
2023-01-20 21:33:05 +00:00
Transform2D Window : : get_screen_transform_internal ( bool p_absolute_position ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Transform2D ( ) ) ;
2022-11-14 17:21:06 +00:00
Transform2D embedder_transform ;
2023-02-05 16:35:39 +00:00
if ( get_embedder ( ) ) {
2022-07-16 09:47:54 +00:00
embedder_transform . translate_local ( get_position ( ) ) ;
2023-02-05 16:35:39 +00:00
embedder_transform = get_embedder ( ) - > get_screen_transform_internal ( p_absolute_position ) * embedder_transform ;
2023-01-20 21:33:05 +00:00
} else if ( p_absolute_position ) {
embedder_transform . translate_local ( get_position ( ) ) ;
2022-03-28 09:01:29 +00:00
}
2023-02-02 18:28:14 +00:00
return embedder_transform * get_final_transform ( ) ;
2022-03-28 09:01:29 +00:00
}
2022-11-13 20:38:29 +00:00
Transform2D Window : : get_popup_base_transform ( ) const {
2023-05-12 11:53:15 +00:00
ERR_READ_THREAD_GUARD_V ( Transform2D ( ) ) ;
2022-11-13 20:38:29 +00:00
if ( is_embedding_subwindows ( ) ) {
return Transform2D ( ) ;
}
2023-01-31 17:06:21 +00:00
Transform2D popup_base_transform ;
popup_base_transform . set_origin ( get_position ( ) ) ;
2023-02-02 18:28:14 +00:00
popup_base_transform * = get_final_transform ( ) ;
2023-02-05 16:35:39 +00:00
if ( get_embedder ( ) ) {
return get_embedder ( ) - > get_popup_base_transform ( ) * popup_base_transform ;
2022-11-13 20:38:29 +00:00
}
2023-01-31 17:06:21 +00:00
return popup_base_transform ;
2022-11-13 20:38:29 +00:00
}
2023-06-06 18:42:41 +00:00
bool Window : : is_directly_attached_to_screen ( ) const {
if ( get_embedder ( ) ) {
return get_embedder ( ) - > is_directly_attached_to_screen ( ) ;
}
// Distinguish between the case that this is a native Window and not inside the tree.
return is_inside_tree ( ) ;
}
2023-01-06 20:48:20 +00:00
bool Window : : is_attached_in_viewport ( ) const {
return get_embedder ( ) ;
}
2023-08-06 11:07:28 +00:00
void Window : : _update_mouse_over ( Vector2 p_pos ) {
if ( ! mouse_in_window ) {
if ( is_embedded ( ) ) {
mouse_in_window = true ;
_propagate_window_notification ( this , NOTIFICATION_WM_MOUSE_ENTER ) ;
}
}
bool new_in = get_visible_rect ( ) . has_point ( p_pos ) ;
if ( new_in = = gui . mouse_in_viewport ) {
if ( new_in ) {
Viewport : : _update_mouse_over ( p_pos ) ;
}
return ;
}
if ( new_in ) {
notification ( NOTIFICATION_VP_MOUSE_ENTER ) ;
Viewport : : _update_mouse_over ( p_pos ) ;
} else {
Viewport : : _mouse_leave_viewport ( ) ;
}
}
void Window : : _mouse_leave_viewport ( ) {
Viewport : : _mouse_leave_viewport ( ) ;
if ( is_embedded ( ) ) {
mouse_in_window = false ;
_propagate_window_notification ( this , NOTIFICATION_WM_MOUSE_EXIT ) ;
}
}
2020-03-04 01:51:12 +00:00
void Window : : _bind_methods ( ) {
2020-03-04 19:03:30 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_title " , " title " ) , & Window : : set_title ) ;
ClassDB : : bind_method ( D_METHOD ( " get_title " ) , & Window : : get_title ) ;
2023-05-20 21:48:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_window_id " ) , & Window : : get_window_id ) ;
2023-01-04 22:00:02 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_initial_position " , " initial_position " ) , & Window : : set_initial_position ) ;
ClassDB : : bind_method ( D_METHOD ( " get_initial_position " ) , & Window : : get_initial_position ) ;
2020-03-04 19:03:30 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_current_screen " , " index " ) , & Window : : set_current_screen ) ;
ClassDB : : bind_method ( D_METHOD ( " get_current_screen " ) , & Window : : get_current_screen ) ;
ClassDB : : bind_method ( D_METHOD ( " set_position " , " position " ) , & Window : : set_position ) ;
ClassDB : : bind_method ( D_METHOD ( " get_position " ) , & Window : : get_position ) ;
2023-08-26 07:30:31 +00:00
ClassDB : : bind_method ( D_METHOD ( " move_to_center " ) , & Window : : move_to_center ) ;
2020-03-04 19:03:30 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_size " , " size " ) , & Window : : set_size ) ;
ClassDB : : bind_method ( D_METHOD ( " get_size " ) , & Window : : get_size ) ;
2021-11-20 08:04:57 +00:00
ClassDB : : bind_method ( D_METHOD ( " reset_size " ) , & Window : : reset_size ) ;
2020-03-04 19:03:30 +00:00
2022-11-30 08:28:16 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_position_with_decorations " ) , & Window : : get_position_with_decorations ) ;
ClassDB : : bind_method ( D_METHOD ( " get_size_with_decorations " ) , & Window : : get_size_with_decorations ) ;
2020-03-04 19:03:30 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_max_size " , " max_size " ) , & Window : : set_max_size ) ;
ClassDB : : bind_method ( D_METHOD ( " get_max_size " ) , & Window : : get_max_size ) ;
ClassDB : : bind_method ( D_METHOD ( " set_min_size " , " min_size " ) , & Window : : set_min_size ) ;
ClassDB : : bind_method ( D_METHOD ( " get_min_size " ) , & Window : : get_min_size ) ;
ClassDB : : bind_method ( D_METHOD ( " set_mode " , " mode " ) , & Window : : set_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " get_mode " ) , & Window : : get_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " set_flag " , " flag " , " enabled " ) , & Window : : set_flag ) ;
ClassDB : : bind_method ( D_METHOD ( " get_flag " , " flag " ) , & Window : : get_flag ) ;
ClassDB : : bind_method ( D_METHOD ( " is_maximize_allowed " ) , & Window : : is_maximize_allowed ) ;
ClassDB : : bind_method ( D_METHOD ( " request_attention " ) , & Window : : request_attention ) ;
2023-10-08 18:41:22 +00:00
# ifndef DISABLE_DEPRECATED
2020-03-04 19:03:30 +00:00
ClassDB : : bind_method ( D_METHOD ( " move_to_foreground " ) , & Window : : move_to_foreground ) ;
2023-10-08 18:41:22 +00:00
# endif // DISABLE_DEPRECATED
2020-03-04 19:03:30 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_visible " , " visible " ) , & Window : : set_visible ) ;
ClassDB : : bind_method ( D_METHOD ( " is_visible " ) , & Window : : is_visible ) ;
2020-03-06 17:00:16 +00:00
ClassDB : : bind_method ( D_METHOD ( " hide " ) , & Window : : hide ) ;
ClassDB : : bind_method ( D_METHOD ( " show " ) , & Window : : show ) ;
2020-03-04 19:03:30 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_transient " , " transient " ) , & Window : : set_transient ) ;
ClassDB : : bind_method ( D_METHOD ( " is_transient " ) , & Window : : is_transient ) ;
2023-12-22 16:50:21 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_transient_to_focused " , " enable " ) , & Window : : set_transient_to_focused ) ;
ClassDB : : bind_method ( D_METHOD ( " is_transient_to_focused " ) , & Window : : is_transient_to_focused ) ;
2020-03-06 17:00:16 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_exclusive " , " exclusive " ) , & Window : : set_exclusive ) ;
ClassDB : : bind_method ( D_METHOD ( " is_exclusive " ) , & Window : : is_exclusive ) ;
2023-04-20 13:13:21 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_unparent_when_invisible " , " unparent " ) , & Window : : set_unparent_when_invisible ) ;
2020-04-01 01:49:23 +00:00
ClassDB : : bind_method ( D_METHOD ( " can_draw " ) , & Window : : can_draw ) ;
2020-03-06 17:00:16 +00:00
ClassDB : : bind_method ( D_METHOD ( " has_focus " ) , & Window : : has_focus ) ;
ClassDB : : bind_method ( D_METHOD ( " grab_focus " ) , & Window : : grab_focus ) ;
2020-03-04 19:03:30 +00:00
2021-02-19 12:35:31 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_ime_active " , " active " ) , & Window : : set_ime_active ) ;
ClassDB : : bind_method ( D_METHOD ( " set_ime_position " , " position " ) , & Window : : set_ime_position ) ;
2020-03-04 19:03:30 +00:00
ClassDB : : bind_method ( D_METHOD ( " is_embedded " ) , & Window : : is_embedded ) ;
2021-07-02 18:35:56 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_contents_minimum_size " ) , & Window : : get_contents_minimum_size ) ;
2024-03-04 18:21:10 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_force_native " , " force_native " ) , & Window : : set_force_native ) ;
ClassDB : : bind_method ( D_METHOD ( " get_force_native " ) , & Window : : get_force_native ) ;
2020-03-04 19:03:30 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_content_scale_size " , " size " ) , & Window : : set_content_scale_size ) ;
ClassDB : : bind_method ( D_METHOD ( " get_content_scale_size " ) , & Window : : get_content_scale_size ) ;
ClassDB : : bind_method ( D_METHOD ( " set_content_scale_mode " , " mode " ) , & Window : : set_content_scale_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " get_content_scale_mode " ) , & Window : : get_content_scale_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " set_content_scale_aspect " , " aspect " ) , & Window : : set_content_scale_aspect ) ;
ClassDB : : bind_method ( D_METHOD ( " get_content_scale_aspect " ) , & Window : : get_content_scale_aspect ) ;
2023-04-06 21:41:27 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_content_scale_stretch " , " stretch " ) , & Window : : set_content_scale_stretch ) ;
ClassDB : : bind_method ( D_METHOD ( " get_content_scale_stretch " ) , & Window : : get_content_scale_stretch ) ;
2023-08-08 08:31:56 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_keep_title_visible " , " title_visible " ) , & Window : : set_keep_title_visible ) ;
ClassDB : : bind_method ( D_METHOD ( " get_keep_title_visible " ) , & Window : : get_keep_title_visible ) ;
2021-12-17 12:11:19 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_content_scale_factor " , " factor " ) , & Window : : set_content_scale_factor ) ;
ClassDB : : bind_method ( D_METHOD ( " get_content_scale_factor " ) , & Window : : get_content_scale_factor ) ;
2020-03-04 19:03:30 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_use_font_oversampling " , " enable " ) , & Window : : set_use_font_oversampling ) ;
ClassDB : : bind_method ( D_METHOD ( " is_using_font_oversampling " ) , & Window : : is_using_font_oversampling ) ;
2023-01-15 10:05:25 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_mouse_passthrough_polygon " , " polygon " ) , & Window : : set_mouse_passthrough_polygon ) ;
ClassDB : : bind_method ( D_METHOD ( " get_mouse_passthrough_polygon " ) , & Window : : get_mouse_passthrough_polygon ) ;
2020-03-06 17:00:16 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_wrap_controls " , " enable " ) , & Window : : set_wrap_controls ) ;
ClassDB : : bind_method ( D_METHOD ( " is_wrapping_controls " ) , & Window : : is_wrapping_controls ) ;
ClassDB : : bind_method ( D_METHOD ( " child_controls_changed " ) , & Window : : child_controls_changed ) ;
ClassDB : : bind_method ( D_METHOD ( " set_theme " , " theme " ) , & Window : : set_theme ) ;
ClassDB : : bind_method ( D_METHOD ( " get_theme " ) , & Window : : get_theme ) ;
2021-07-04 20:42:23 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_theme_type_variation " , " theme_type " ) , & Window : : set_theme_type_variation ) ;
ClassDB : : bind_method ( D_METHOD ( " get_theme_type_variation " ) , & Window : : get_theme_type_variation ) ;
2021-03-30 17:16:33 +00:00
2022-11-29 20:01:45 +00:00
ClassDB : : bind_method ( D_METHOD ( " begin_bulk_theme_override " ) , & Window : : begin_bulk_theme_override ) ;
ClassDB : : bind_method ( D_METHOD ( " end_bulk_theme_override " ) , & Window : : end_bulk_theme_override ) ;
ClassDB : : bind_method ( D_METHOD ( " add_theme_icon_override " , " name " , " texture " ) , & Window : : add_theme_icon_override ) ;
ClassDB : : bind_method ( D_METHOD ( " add_theme_stylebox_override " , " name " , " stylebox " ) , & Window : : add_theme_style_override ) ;
ClassDB : : bind_method ( D_METHOD ( " add_theme_font_override " , " name " , " font " ) , & Window : : add_theme_font_override ) ;
ClassDB : : bind_method ( D_METHOD ( " add_theme_font_size_override " , " name " , " font_size " ) , & Window : : add_theme_font_size_override ) ;
ClassDB : : bind_method ( D_METHOD ( " add_theme_color_override " , " name " , " color " ) , & Window : : add_theme_color_override ) ;
ClassDB : : bind_method ( D_METHOD ( " add_theme_constant_override " , " name " , " constant " ) , & Window : : add_theme_constant_override ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_theme_icon_override " , " name " ) , & Window : : remove_theme_icon_override ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_theme_stylebox_override " , " name " ) , & Window : : remove_theme_style_override ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_theme_font_override " , " name " ) , & Window : : remove_theme_font_override ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_theme_font_size_override " , " name " ) , & Window : : remove_theme_font_size_override ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_theme_color_override " , " name " ) , & Window : : remove_theme_color_override ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_theme_constant_override " , " name " ) , & Window : : remove_theme_constant_override ) ;
2024-01-30 20:03:28 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_theme_icon " , " name " , " theme_type " ) , & Window : : get_theme_icon , DEFVAL ( StringName ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_theme_stylebox " , " name " , " theme_type " ) , & Window : : get_theme_stylebox , DEFVAL ( StringName ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_theme_font " , " name " , " theme_type " ) , & Window : : get_theme_font , DEFVAL ( StringName ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_theme_font_size " , " name " , " theme_type " ) , & Window : : get_theme_font_size , DEFVAL ( StringName ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_theme_color " , " name " , " theme_type " ) , & Window : : get_theme_color , DEFVAL ( StringName ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_theme_constant " , " name " , " theme_type " ) , & Window : : get_theme_constant , DEFVAL ( StringName ( ) ) ) ;
2020-03-12 12:37:40 +00:00
2022-11-29 20:01:45 +00:00
ClassDB : : bind_method ( D_METHOD ( " has_theme_icon_override " , " name " ) , & Window : : has_theme_icon_override ) ;
ClassDB : : bind_method ( D_METHOD ( " has_theme_stylebox_override " , " name " ) , & Window : : has_theme_stylebox_override ) ;
ClassDB : : bind_method ( D_METHOD ( " has_theme_font_override " , " name " ) , & Window : : has_theme_font_override ) ;
ClassDB : : bind_method ( D_METHOD ( " has_theme_font_size_override " , " name " ) , & Window : : has_theme_font_size_override ) ;
ClassDB : : bind_method ( D_METHOD ( " has_theme_color_override " , " name " ) , & Window : : has_theme_color_override ) ;
ClassDB : : bind_method ( D_METHOD ( " has_theme_constant_override " , " name " ) , & Window : : has_theme_constant_override ) ;
2024-01-30 20:03:28 +00:00
ClassDB : : bind_method ( D_METHOD ( " has_theme_icon " , " name " , " theme_type " ) , & Window : : has_theme_icon , DEFVAL ( StringName ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " has_theme_stylebox " , " name " , " theme_type " ) , & Window : : has_theme_stylebox , DEFVAL ( StringName ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " has_theme_font " , " name " , " theme_type " ) , & Window : : has_theme_font , DEFVAL ( StringName ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " has_theme_font_size " , " name " , " theme_type " ) , & Window : : has_theme_font_size , DEFVAL ( StringName ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " has_theme_color " , " name " , " theme_type " ) , & Window : : has_theme_color , DEFVAL ( StringName ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " has_theme_constant " , " name " , " theme_type " ) , & Window : : has_theme_constant , DEFVAL ( StringName ( ) ) ) ;
2020-03-12 12:37:40 +00:00
2021-10-02 20:06:14 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_theme_default_base_scale " ) , & Window : : get_theme_default_base_scale ) ;
ClassDB : : bind_method ( D_METHOD ( " get_theme_default_font " ) , & Window : : get_theme_default_font ) ;
ClassDB : : bind_method ( D_METHOD ( " get_theme_default_font_size " ) , & Window : : get_theme_default_font_size ) ;
2020-09-03 11:22:16 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_layout_direction " , " direction " ) , & Window : : set_layout_direction ) ;
ClassDB : : bind_method ( D_METHOD ( " get_layout_direction " ) , & Window : : get_layout_direction ) ;
ClassDB : : bind_method ( D_METHOD ( " is_layout_rtl " ) , & Window : : is_layout_rtl ) ;
2024-01-23 21:29:45 +00:00
# ifndef DISABLE_DEPRECATED
2021-05-27 17:31:33 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_auto_translate " , " enable " ) , & Window : : set_auto_translate ) ;
ClassDB : : bind_method ( D_METHOD ( " is_auto_translating " ) , & Window : : is_auto_translating ) ;
2024-01-23 21:29:45 +00:00
# endif
2021-05-27 17:31:33 +00:00
2020-03-20 02:32:09 +00:00
ClassDB : : bind_method ( D_METHOD ( " popup " , " rect " ) , & Window : : popup , DEFVAL ( Rect2i ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " popup_on_parent " , " parent_rect " ) , & Window : : popup_on_parent ) ;
ClassDB : : bind_method ( D_METHOD ( " popup_centered " , " minsize " ) , & Window : : popup_centered , DEFVAL ( Size2i ( ) ) ) ;
2023-04-20 13:13:21 +00:00
ClassDB : : bind_method ( D_METHOD ( " popup_centered_ratio " , " ratio " ) , & Window : : popup_centered_ratio , DEFVAL ( 0.8 ) ) ;
2020-03-27 12:13:01 +00:00
ClassDB : : bind_method ( D_METHOD ( " popup_centered_clamped " , " minsize " , " fallback_ratio " ) , & Window : : popup_centered_clamped , DEFVAL ( Size2i ( ) ) , DEFVAL ( 0.75 ) ) ;
2020-03-20 02:32:09 +00:00
2023-04-20 13:13:21 +00:00
ClassDB : : bind_method ( D_METHOD ( " popup_exclusive " , " from_node " , " rect " ) , & Window : : popup_exclusive , DEFVAL ( Rect2i ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " popup_exclusive_on_parent " , " from_node " , " parent_rect " ) , & Window : : popup_exclusive_on_parent ) ;
ClassDB : : bind_method ( D_METHOD ( " popup_exclusive_centered " , " from_node " , " minsize " ) , & Window : : popup_exclusive_centered , DEFVAL ( Size2i ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " popup_exclusive_centered_ratio " , " from_node " , " ratio " ) , & Window : : popup_exclusive_centered_ratio , DEFVAL ( 0.8 ) ) ;
ClassDB : : bind_method ( D_METHOD ( " popup_exclusive_centered_clamped " , " from_node " , " minsize " , " fallback_ratio " ) , & Window : : popup_exclusive_centered_clamped , DEFVAL ( Size2i ( ) ) , DEFVAL ( 0.75 ) ) ;
2023-06-21 15:56:23 +00:00
// Keep the enum values in sync with the `Mode` enum.
2023-07-04 10:09:26 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " mode " , PROPERTY_HINT_ENUM , " Windowed,Minimized,Maximized,Fullscreen,Exclusive Fullscreen " ) , " set_mode " , " get_mode " ) ;
2023-06-21 15:56:23 +00:00
2020-03-04 19:03:30 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " title " ) , " set_title " , " get_title " ) ;
2023-06-21 15:56:23 +00:00
// Keep the enum values in sync with the `WindowInitialPosition` enum.
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " initial_position " , PROPERTY_HINT_ENUM , " Absolute,Center of Primary Screen,Center of Main Window Screen,Center of Other Screen,Center of Screen With Mouse Pointer,Center of Screen With Keyboard Focus " ) , " set_initial_position " , " get_initial_position " ) ;
2022-05-20 05:24:41 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR2I , " position " , PROPERTY_HINT_NONE , " suffix:px " ) , " set_position " , " get_position " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR2I , " size " , PROPERTY_HINT_NONE , " suffix:px " ) , " set_size " , " get_size " ) ;
2023-01-19 08:28:53 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " current_screen " , PROPERTY_HINT_RANGE , " 0,64,1,or_greater " ) , " set_current_screen " , " get_current_screen " ) ;
2021-05-27 17:31:33 +00:00
2023-01-15 10:05:25 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : PACKED_VECTOR2_ARRAY , " mouse_passthrough_polygon " ) , " set_mouse_passthrough_polygon " , " get_mouse_passthrough_polygon " ) ;
2020-03-04 19:03:30 +00:00
ADD_GROUP ( " Flags " , " " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " visible " ) , " set_visible " , " is_visible " ) ;
2020-03-06 17:00:16 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " wrap_controls " ) , " set_wrap_controls " , " is_wrapping_controls " ) ;
2020-03-04 19:03:30 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " transient " ) , " set_transient " , " is_transient " ) ;
2023-12-22 16:50:21 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " transient_to_focused " ) , " set_transient_to_focused " , " is_transient_to_focused " ) ;
2020-03-06 17:00:16 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " exclusive " ) , " set_exclusive " , " is_exclusive " ) ;
2020-03-04 19:03:30 +00:00
ADD_PROPERTYI ( PropertyInfo ( Variant : : BOOL , " unresizable " ) , " set_flag " , " get_flag " , FLAG_RESIZE_DISABLED ) ;
ADD_PROPERTYI ( PropertyInfo ( Variant : : BOOL , " borderless " ) , " set_flag " , " get_flag " , FLAG_BORDERLESS ) ;
ADD_PROPERTYI ( PropertyInfo ( Variant : : BOOL , " always_on_top " ) , " set_flag " , " get_flag " , FLAG_ALWAYS_ON_TOP ) ;
ADD_PROPERTYI ( PropertyInfo ( Variant : : BOOL , " transparent " ) , " set_flag " , " get_flag " , FLAG_TRANSPARENT ) ;
2020-03-20 20:51:53 +00:00
ADD_PROPERTYI ( PropertyInfo ( Variant : : BOOL , " unfocusable " ) , " set_flag " , " get_flag " , FLAG_NO_FOCUS ) ;
2022-02-24 09:21:23 +00:00
ADD_PROPERTYI ( PropertyInfo ( Variant : : BOOL , " popup_window " ) , " set_flag " , " get_flag " , FLAG_POPUP ) ;
2022-08-23 10:40:48 +00:00
ADD_PROPERTYI ( PropertyInfo ( Variant : : BOOL , " extend_to_title " ) , " set_flag " , " get_flag " , FLAG_EXTEND_TO_TITLE ) ;
2023-01-15 10:05:25 +00:00
ADD_PROPERTYI ( PropertyInfo ( Variant : : BOOL , " mouse_passthrough " ) , " set_flag " , " get_flag " , FLAG_MOUSE_PASSTHROUGH ) ;
2024-03-04 18:21:10 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " force_native " ) , " set_force_native " , " get_force_native " ) ;
2021-05-27 17:31:33 +00:00
2020-03-04 19:03:30 +00:00
ADD_GROUP ( " Limits " , " " ) ;
2022-05-20 05:24:41 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR2I , " min_size " , PROPERTY_HINT_NONE , " suffix:px " ) , " set_min_size " , " get_min_size " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR2I , " max_size " , PROPERTY_HINT_NONE , " suffix:px " ) , " set_max_size " , " get_max_size " ) ;
2023-08-08 08:31:56 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " keep_title_visible " ) , " set_keep_title_visible " , " get_keep_title_visible " ) ;
2021-05-27 17:31:33 +00:00
2020-03-04 19:03:30 +00:00
ADD_GROUP ( " Content Scale " , " content_scale_ " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR2I , " content_scale_size " ) , " set_content_scale_size " , " get_content_scale_size " ) ;
2021-05-22 02:30:58 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " content_scale_mode " , PROPERTY_HINT_ENUM , " Disabled,Canvas Items,Viewport " ) , " set_content_scale_mode " , " get_content_scale_mode " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " content_scale_aspect " , PROPERTY_HINT_ENUM , " Ignore,Keep,Keep Width,Keep Height,Expand " ) , " set_content_scale_aspect " , " get_content_scale_aspect " ) ;
2023-04-06 21:41:27 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " content_scale_stretch " , PROPERTY_HINT_ENUM , " Fractional,Integer " ) , " set_content_scale_stretch " , " get_content_scale_stretch " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " content_scale_factor " , PROPERTY_HINT_RANGE , " 0.5,8.0,0.01 " ) , " set_content_scale_factor " , " get_content_scale_factor " ) ;
2021-05-27 17:31:33 +00:00
2024-01-23 21:29:45 +00:00
# ifndef DISABLE_DEPRECATED
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " auto_translate " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NO_EDITOR ) , " set_auto_translate " , " is_auto_translating " ) ;
# endif
2022-11-29 20:01:45 +00:00
2021-03-30 17:16:33 +00:00
ADD_GROUP ( " Theme " , " theme_ " ) ;
2020-03-06 17:00:16 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : OBJECT , " theme " , PROPERTY_HINT_RESOURCE_TYPE , " Theme " ) , " set_theme " , " get_theme " ) ;
2021-07-04 20:42:23 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " theme_type_variation " , PROPERTY_HINT_ENUM_SUGGESTION ) , " set_theme_type_variation " , " get_theme_type_variation " ) ;
2020-03-04 19:03:30 +00:00
2020-03-06 17:00:16 +00:00
ADD_SIGNAL ( MethodInfo ( " window_input " , PropertyInfo ( Variant : : OBJECT , " event " , PROPERTY_HINT_RESOURCE_TYPE , " InputEvent " ) ) ) ;
2020-03-12 12:37:40 +00:00
ADD_SIGNAL ( MethodInfo ( " files_dropped " , PropertyInfo ( Variant : : PACKED_STRING_ARRAY , " files " ) ) ) ;
2020-03-04 16:36:09 +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 ( " close_requested " ) ) ;
ADD_SIGNAL ( MethodInfo ( " go_back_requested " ) ) ;
2020-03-06 17:00:16 +00:00
ADD_SIGNAL ( MethodInfo ( " visibility_changed " ) ) ;
2020-03-12 12:37:40 +00:00
ADD_SIGNAL ( MethodInfo ( " about_to_popup " ) ) ;
2022-01-19 07:59:42 +00:00
ADD_SIGNAL ( MethodInfo ( " theme_changed " ) ) ;
2023-01-23 19:39:29 +00:00
ADD_SIGNAL ( MethodInfo ( " dpi_changed " ) ) ;
2022-09-22 09:06:11 +00:00
ADD_SIGNAL ( MethodInfo ( " titlebar_changed " ) ) ;
2020-03-06 17:00:16 +00:00
BIND_CONSTANT ( NOTIFICATION_VISIBILITY_CHANGED ) ;
2022-07-08 19:29:36 +00:00
BIND_CONSTANT ( NOTIFICATION_THEME_CHANGED ) ;
2020-03-20 20:51:53 +00:00
BIND_ENUM_CONSTANT ( MODE_WINDOWED ) ;
BIND_ENUM_CONSTANT ( MODE_MINIMIZED ) ;
BIND_ENUM_CONSTANT ( MODE_MAXIMIZED ) ;
BIND_ENUM_CONSTANT ( MODE_FULLSCREEN ) ;
2022-01-28 09:19:53 +00:00
BIND_ENUM_CONSTANT ( MODE_EXCLUSIVE_FULLSCREEN ) ;
2020-03-20 20:51:53 +00:00
BIND_ENUM_CONSTANT ( FLAG_RESIZE_DISABLED ) ;
BIND_ENUM_CONSTANT ( FLAG_BORDERLESS ) ;
BIND_ENUM_CONSTANT ( FLAG_ALWAYS_ON_TOP ) ;
BIND_ENUM_CONSTANT ( FLAG_TRANSPARENT ) ;
BIND_ENUM_CONSTANT ( FLAG_NO_FOCUS ) ;
2022-02-24 09:21:23 +00:00
BIND_ENUM_CONSTANT ( FLAG_POPUP ) ;
2022-08-23 10:40:48 +00:00
BIND_ENUM_CONSTANT ( FLAG_EXTEND_TO_TITLE ) ;
2023-01-15 10:05:25 +00:00
BIND_ENUM_CONSTANT ( FLAG_MOUSE_PASSTHROUGH ) ;
2020-03-20 20:51:53 +00:00
BIND_ENUM_CONSTANT ( FLAG_MAX ) ;
BIND_ENUM_CONSTANT ( CONTENT_SCALE_MODE_DISABLED ) ;
2020-07-02 20:15:11 +00:00
BIND_ENUM_CONSTANT ( CONTENT_SCALE_MODE_CANVAS_ITEMS ) ;
BIND_ENUM_CONSTANT ( CONTENT_SCALE_MODE_VIEWPORT ) ;
2020-03-20 20:51:53 +00:00
BIND_ENUM_CONSTANT ( CONTENT_SCALE_ASPECT_IGNORE ) ;
BIND_ENUM_CONSTANT ( CONTENT_SCALE_ASPECT_KEEP ) ;
BIND_ENUM_CONSTANT ( CONTENT_SCALE_ASPECT_KEEP_WIDTH ) ;
BIND_ENUM_CONSTANT ( CONTENT_SCALE_ASPECT_KEEP_HEIGHT ) ;
BIND_ENUM_CONSTANT ( CONTENT_SCALE_ASPECT_EXPAND ) ;
2020-09-03 11:22:16 +00:00
2023-04-06 21:41:27 +00:00
BIND_ENUM_CONSTANT ( CONTENT_SCALE_STRETCH_FRACTIONAL ) ;
BIND_ENUM_CONSTANT ( CONTENT_SCALE_STRETCH_INTEGER ) ;
2020-09-03 11:22:16 +00:00
BIND_ENUM_CONSTANT ( LAYOUT_DIRECTION_INHERITED ) ;
BIND_ENUM_CONSTANT ( LAYOUT_DIRECTION_LOCALE ) ;
BIND_ENUM_CONSTANT ( LAYOUT_DIRECTION_LTR ) ;
BIND_ENUM_CONSTANT ( LAYOUT_DIRECTION_RTL ) ;
2023-01-04 22:00:02 +00:00
BIND_ENUM_CONSTANT ( WINDOW_INITIAL_POSITION_ABSOLUTE ) ;
2023-01-19 08:28:53 +00:00
BIND_ENUM_CONSTANT ( WINDOW_INITIAL_POSITION_CENTER_PRIMARY_SCREEN ) ;
BIND_ENUM_CONSTANT ( WINDOW_INITIAL_POSITION_CENTER_MAIN_WINDOW_SCREEN ) ;
BIND_ENUM_CONSTANT ( WINDOW_INITIAL_POSITION_CENTER_OTHER_SCREEN ) ;
2023-03-21 11:08:46 +00:00
BIND_ENUM_CONSTANT ( WINDOW_INITIAL_POSITION_CENTER_SCREEN_WITH_MOUSE_FOCUS ) ;
BIND_ENUM_CONSTANT ( WINDOW_INITIAL_POSITION_CENTER_SCREEN_WITH_KEYBOARD_FOCUS ) ;
2023-08-02 16:53:37 +00:00
GDVIRTUAL_BIND ( _get_contents_minimum_size ) ;
2023-09-12 13:01:42 +00:00
BIND_THEME_ITEM ( Theme : : DATA_TYPE_STYLEBOX , Window , embedded_border ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_STYLEBOX , Window , embedded_unfocused_border ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_FONT , Window , title_font ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_FONT_SIZE , Window , title_font_size ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Window , title_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Window , title_height ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Window , title_outline_modulate ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Window , title_outline_size ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , Window , close ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , Window , close_pressed ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Window , close_h_offset ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Window , close_v_offset ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Window , resize_margin ) ;
2020-03-04 01:51:12 +00:00
}
Window : : Window ( ) {
2022-08-21 22:16:56 +00:00
RenderingServer * rendering_server = RenderingServer : : get_singleton ( ) ;
if ( rendering_server ) {
max_size = rendering_server - > get_maximum_viewport_size ( ) ;
2022-06-18 10:52:30 +00:00
max_size_used = max_size ; // Update max_size_used.
2022-08-21 22:16:56 +00:00
}
2023-09-06 14:11:05 +00:00
theme_owner = memnew ( ThemeOwner ( this ) ) ;
2020-03-27 18:21:27 +00:00
RS : : get_singleton ( ) - > viewport_set_update_mode ( get_viewport_rid ( ) , RS : : VIEWPORT_UPDATE_DISABLED ) ;
2020-03-04 01:51:12 +00:00
}
2020-05-14 12:29:06 +00:00
2020-03-04 01:51:12 +00:00
Window : : ~ Window ( ) {
2022-09-02 14:03:23 +00:00
memdelete ( theme_owner ) ;
2022-11-29 20:01:45 +00:00
// Resources need to be disconnected.
for ( KeyValue < StringName , Ref < Texture2D > > & E : theme_icon_override ) {
2023-07-03 19:29:37 +00:00
E . value - > disconnect_changed ( callable_mp ( this , & Window : : _notify_theme_override_changed ) ) ;
2022-11-29 20:01:45 +00:00
}
for ( KeyValue < StringName , Ref < StyleBox > > & E : theme_style_override ) {
2023-07-03 19:29:37 +00:00
E . value - > disconnect_changed ( callable_mp ( this , & Window : : _notify_theme_override_changed ) ) ;
2022-11-29 20:01:45 +00:00
}
for ( KeyValue < StringName , Ref < Font > > & E : theme_font_override ) {
2023-07-03 19:29:37 +00:00
E . value - > disconnect_changed ( callable_mp ( this , & Window : : _notify_theme_override_changed ) ) ;
2022-11-29 20:01:45 +00:00
}
// Then override maps can be simply cleared.
theme_icon_override . clear ( ) ;
theme_style_override . clear ( ) ;
theme_font_override . clear ( ) ;
theme_font_size_override . clear ( ) ;
theme_color_override . clear ( ) ;
theme_constant_override . clear ( ) ;
2020-03-04 01:51:12 +00:00
}