1 | /**************************************************************************/ |
2 | /* window.cpp */ |
3 | /**************************************************************************/ |
4 | /* This file is part of: */ |
5 | /* GODOT ENGINE */ |
6 | /* https://godotengine.org */ |
7 | /**************************************************************************/ |
8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
10 | /* */ |
11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
12 | /* a copy of this software and associated documentation files (the */ |
13 | /* "Software"), to deal in the Software without restriction, including */ |
14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
17 | /* the following conditions: */ |
18 | /* */ |
19 | /* The above copyright notice and this permission notice shall be */ |
20 | /* included in all copies or substantial portions of the Software. */ |
21 | /* */ |
22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
29 | /**************************************************************************/ |
30 | |
31 | #include "window.h" |
32 | |
33 | #include "core/config/project_settings.h" |
34 | #include "core/debugger/engine_debugger.h" |
35 | #include "core/input/shortcut.h" |
36 | #include "core/string/translation.h" |
37 | #include "core/variant/variant_parser.h" |
38 | #include "scene/gui/control.h" |
39 | #include "scene/scene_string_names.h" |
40 | #include "scene/theme/theme_db.h" |
41 | #include "scene/theme/theme_owner.h" |
42 | |
43 | // Dynamic properties. |
44 | |
45 | bool Window::_set(const StringName &p_name, const Variant &p_value) { |
46 | ERR_MAIN_THREAD_GUARD_V(false); |
47 | |
48 | String name = p_name; |
49 | if (!name.begins_with("theme_override" )) { |
50 | return false; |
51 | } |
52 | |
53 | if (p_value.get_type() == Variant::NIL || (p_value.get_type() == Variant::OBJECT && (Object *)p_value == nullptr)) { |
54 | if (name.begins_with("theme_override_icons/" )) { |
55 | String dname = name.get_slicec('/', 1); |
56 | if (theme_icon_override.has(dname)) { |
57 | theme_icon_override[dname]->disconnect_changed(callable_mp(this, &Window::_notify_theme_override_changed)); |
58 | } |
59 | theme_icon_override.erase(dname); |
60 | _notify_theme_override_changed(); |
61 | } else if (name.begins_with("theme_override_styles/" )) { |
62 | String dname = name.get_slicec('/', 1); |
63 | if (theme_style_override.has(dname)) { |
64 | theme_style_override[dname]->disconnect_changed(callable_mp(this, &Window::_notify_theme_override_changed)); |
65 | } |
66 | theme_style_override.erase(dname); |
67 | _notify_theme_override_changed(); |
68 | } else if (name.begins_with("theme_override_fonts/" )) { |
69 | String dname = name.get_slicec('/', 1); |
70 | if (theme_font_override.has(dname)) { |
71 | theme_font_override[dname]->disconnect_changed(callable_mp(this, &Window::_notify_theme_override_changed)); |
72 | } |
73 | theme_font_override.erase(dname); |
74 | _notify_theme_override_changed(); |
75 | } else if (name.begins_with("theme_override_font_sizes/" )) { |
76 | String dname = name.get_slicec('/', 1); |
77 | theme_font_size_override.erase(dname); |
78 | _notify_theme_override_changed(); |
79 | } else if (name.begins_with("theme_override_colors/" )) { |
80 | String dname = name.get_slicec('/', 1); |
81 | theme_color_override.erase(dname); |
82 | _notify_theme_override_changed(); |
83 | } else if (name.begins_with("theme_override_constants/" )) { |
84 | String dname = name.get_slicec('/', 1); |
85 | theme_constant_override.erase(dname); |
86 | _notify_theme_override_changed(); |
87 | } else { |
88 | return false; |
89 | } |
90 | |
91 | } else { |
92 | if (name.begins_with("theme_override_icons/" )) { |
93 | String dname = name.get_slicec('/', 1); |
94 | add_theme_icon_override(dname, p_value); |
95 | } else if (name.begins_with("theme_override_styles/" )) { |
96 | String dname = name.get_slicec('/', 1); |
97 | add_theme_style_override(dname, p_value); |
98 | } else if (name.begins_with("theme_override_fonts/" )) { |
99 | String dname = name.get_slicec('/', 1); |
100 | add_theme_font_override(dname, p_value); |
101 | } else if (name.begins_with("theme_override_font_sizes/" )) { |
102 | String dname = name.get_slicec('/', 1); |
103 | add_theme_font_size_override(dname, p_value); |
104 | } else if (name.begins_with("theme_override_colors/" )) { |
105 | String dname = name.get_slicec('/', 1); |
106 | add_theme_color_override(dname, p_value); |
107 | } else if (name.begins_with("theme_override_constants/" )) { |
108 | String dname = name.get_slicec('/', 1); |
109 | add_theme_constant_override(dname, p_value); |
110 | } else { |
111 | return false; |
112 | } |
113 | } |
114 | return true; |
115 | } |
116 | |
117 | bool Window::_get(const StringName &p_name, Variant &r_ret) const { |
118 | ERR_READ_THREAD_GUARD_V(false); |
119 | |
120 | String sname = p_name; |
121 | if (!sname.begins_with("theme_override" )) { |
122 | return false; |
123 | } |
124 | |
125 | if (sname.begins_with("theme_override_icons/" )) { |
126 | String name = sname.get_slicec('/', 1); |
127 | r_ret = theme_icon_override.has(name) ? Variant(theme_icon_override[name]) : Variant(); |
128 | } else if (sname.begins_with("theme_override_styles/" )) { |
129 | String name = sname.get_slicec('/', 1); |
130 | r_ret = theme_style_override.has(name) ? Variant(theme_style_override[name]) : Variant(); |
131 | } else if (sname.begins_with("theme_override_fonts/" )) { |
132 | String name = sname.get_slicec('/', 1); |
133 | r_ret = theme_font_override.has(name) ? Variant(theme_font_override[name]) : Variant(); |
134 | } else if (sname.begins_with("theme_override_font_sizes/" )) { |
135 | String name = sname.get_slicec('/', 1); |
136 | r_ret = theme_font_size_override.has(name) ? Variant(theme_font_size_override[name]) : Variant(); |
137 | } else if (sname.begins_with("theme_override_colors/" )) { |
138 | String name = sname.get_slicec('/', 1); |
139 | r_ret = theme_color_override.has(name) ? Variant(theme_color_override[name]) : Variant(); |
140 | } else if (sname.begins_with("theme_override_constants/" )) { |
141 | String name = sname.get_slicec('/', 1); |
142 | r_ret = theme_constant_override.has(name) ? Variant(theme_constant_override[name]) : Variant(); |
143 | } else { |
144 | return false; |
145 | } |
146 | |
147 | return true; |
148 | } |
149 | |
150 | void Window::_get_property_list(List<PropertyInfo> *p_list) const { |
151 | ERR_READ_THREAD_GUARD; |
152 | |
153 | Ref<Theme> default_theme = ThemeDB::get_singleton()->get_default_theme(); |
154 | |
155 | p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Theme Overrides" , "theme_override_" ), PROPERTY_HINT_NONE, "theme_override_" , PROPERTY_USAGE_GROUP)); |
156 | |
157 | { |
158 | List<StringName> names; |
159 | default_theme->get_color_list(get_class_name(), &names); |
160 | for (const StringName &E : names) { |
161 | uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE; |
162 | if (theme_color_override.has(E)) { |
163 | usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED; |
164 | } |
165 | |
166 | p_list->push_back(PropertyInfo(Variant::COLOR, PNAME("theme_override_colors" ) + String("/" ) + E, PROPERTY_HINT_NONE, "" , usage)); |
167 | } |
168 | } |
169 | { |
170 | List<StringName> names; |
171 | default_theme->get_constant_list(get_class_name(), &names); |
172 | for (const StringName &E : names) { |
173 | uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE; |
174 | if (theme_constant_override.has(E)) { |
175 | usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED; |
176 | } |
177 | |
178 | p_list->push_back(PropertyInfo(Variant::INT, PNAME("theme_override_constants" ) + String("/" ) + E, PROPERTY_HINT_RANGE, "-16384,16384" , usage)); |
179 | } |
180 | } |
181 | { |
182 | List<StringName> names; |
183 | default_theme->get_font_list(get_class_name(), &names); |
184 | for (const StringName &E : names) { |
185 | uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE; |
186 | if (theme_font_override.has(E)) { |
187 | usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED; |
188 | } |
189 | |
190 | p_list->push_back(PropertyInfo(Variant::OBJECT, PNAME("theme_override_fonts" ) + String("/" ) + E, PROPERTY_HINT_RESOURCE_TYPE, "Font" , usage)); |
191 | } |
192 | } |
193 | { |
194 | List<StringName> names; |
195 | default_theme->get_font_size_list(get_class_name(), &names); |
196 | for (const StringName &E : names) { |
197 | uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE; |
198 | if (theme_font_size_override.has(E)) { |
199 | usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED; |
200 | } |
201 | |
202 | 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)); |
203 | } |
204 | } |
205 | { |
206 | List<StringName> names; |
207 | default_theme->get_icon_list(get_class_name(), &names); |
208 | for (const StringName &E : names) { |
209 | uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE; |
210 | if (theme_icon_override.has(E)) { |
211 | usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED; |
212 | } |
213 | |
214 | p_list->push_back(PropertyInfo(Variant::OBJECT, PNAME("theme_override_icons" ) + String("/" ) + E, PROPERTY_HINT_RESOURCE_TYPE, "Texture2D" , usage)); |
215 | } |
216 | } |
217 | { |
218 | List<StringName> names; |
219 | default_theme->get_stylebox_list(get_class_name(), &names); |
220 | for (const StringName &E : names) { |
221 | uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE; |
222 | if (theme_style_override.has(E)) { |
223 | usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED; |
224 | } |
225 | |
226 | p_list->push_back(PropertyInfo(Variant::OBJECT, PNAME("theme_override_styles" ) + String("/" ) + E, PROPERTY_HINT_RESOURCE_TYPE, "StyleBox" , usage)); |
227 | } |
228 | } |
229 | } |
230 | |
231 | void Window::_validate_property(PropertyInfo &p_property) const { |
232 | if (p_property.name == "position" && initial_position != WINDOW_INITIAL_POSITION_ABSOLUTE) { |
233 | p_property.usage = PROPERTY_USAGE_NONE; |
234 | } |
235 | |
236 | if (p_property.name == "current_screen" && initial_position != WINDOW_INITIAL_POSITION_CENTER_OTHER_SCREEN) { |
237 | p_property.usage = PROPERTY_USAGE_NONE; |
238 | } |
239 | |
240 | if (p_property.name == "theme_type_variation" ) { |
241 | List<StringName> names; |
242 | |
243 | // Only the default theme and the project theme are used for the list of options. |
244 | // This is an imposed limitation to simplify the logic needed to leverage those options. |
245 | ThemeDB::get_singleton()->get_default_theme()->get_type_variation_list(get_class_name(), &names); |
246 | if (ThemeDB::get_singleton()->get_project_theme().is_valid()) { |
247 | ThemeDB::get_singleton()->get_project_theme()->get_type_variation_list(get_class_name(), &names); |
248 | } |
249 | names.sort_custom<StringName::AlphCompare>(); |
250 | |
251 | Vector<StringName> unique_names; |
252 | String hint_string; |
253 | for (const StringName &E : names) { |
254 | // Skip duplicate values. |
255 | if (unique_names.has(E)) { |
256 | continue; |
257 | } |
258 | |
259 | hint_string += String(E) + "," ; |
260 | unique_names.append(E); |
261 | } |
262 | |
263 | p_property.hint_string = hint_string; |
264 | } |
265 | } |
266 | |
267 | // |
268 | |
269 | void Window::set_title(const String &p_title) { |
270 | ERR_MAIN_THREAD_GUARD; |
271 | |
272 | title = p_title; |
273 | |
274 | if (embedder) { |
275 | embedder->_sub_window_update(this); |
276 | } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { |
277 | String tr_title = atr(p_title); |
278 | #ifdef DEBUG_ENABLED |
279 | if (window_id == DisplayServer::MAIN_WINDOW_ID) { |
280 | // Append a suffix to the window title to denote that the project is running |
281 | // from a debug build (including the editor). Since this results in lower performance, |
282 | // this should be clearly presented to the user. |
283 | tr_title = vformat("%s (DEBUG)" , tr_title); |
284 | } |
285 | #endif |
286 | DisplayServer::get_singleton()->window_set_title(tr_title, window_id); |
287 | } |
288 | } |
289 | |
290 | String Window::get_title() const { |
291 | ERR_READ_THREAD_GUARD_V(String()); |
292 | return title; |
293 | } |
294 | |
295 | void Window::set_initial_position(Window::WindowInitialPosition p_initial_position) { |
296 | ERR_MAIN_THREAD_GUARD; |
297 | |
298 | initial_position = p_initial_position; |
299 | notify_property_list_changed(); |
300 | } |
301 | |
302 | Window::WindowInitialPosition Window::get_initial_position() const { |
303 | ERR_READ_THREAD_GUARD_V(WINDOW_INITIAL_POSITION_ABSOLUTE); |
304 | return initial_position; |
305 | } |
306 | |
307 | void Window::set_current_screen(int p_screen) { |
308 | ERR_MAIN_THREAD_GUARD; |
309 | |
310 | current_screen = p_screen; |
311 | if (window_id == DisplayServer::INVALID_WINDOW_ID) { |
312 | return; |
313 | } |
314 | DisplayServer::get_singleton()->window_set_current_screen(p_screen, window_id); |
315 | } |
316 | |
317 | int Window::get_current_screen() const { |
318 | ERR_READ_THREAD_GUARD_V(0); |
319 | |
320 | if (window_id != DisplayServer::INVALID_WINDOW_ID) { |
321 | current_screen = DisplayServer::get_singleton()->window_get_current_screen(window_id); |
322 | } |
323 | return current_screen; |
324 | } |
325 | |
326 | void Window::set_position(const Point2i &p_position) { |
327 | ERR_MAIN_THREAD_GUARD; |
328 | |
329 | position = p_position; |
330 | |
331 | if (embedder) { |
332 | embedder->_sub_window_update(this); |
333 | |
334 | } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { |
335 | DisplayServer::get_singleton()->window_set_position(p_position, window_id); |
336 | } |
337 | } |
338 | |
339 | Point2i Window::get_position() const { |
340 | ERR_READ_THREAD_GUARD_V(Point2i()); |
341 | |
342 | return position; |
343 | } |
344 | |
345 | void Window::move_to_center() { |
346 | ERR_MAIN_THREAD_GUARD; |
347 | ERR_FAIL_COND(!is_inside_tree()); |
348 | |
349 | Rect2 parent_rect; |
350 | |
351 | if (is_embedded()) { |
352 | parent_rect = get_embedder()->get_visible_rect(); |
353 | } else { |
354 | int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(get_window_id()); |
355 | parent_rect.position = DisplayServer::get_singleton()->screen_get_position(parent_screen); |
356 | parent_rect.size = DisplayServer::get_singleton()->screen_get_size(parent_screen); |
357 | } |
358 | |
359 | if (parent_rect != Rect2()) { |
360 | set_position(parent_rect.position + (parent_rect.size - get_size()) / 2); |
361 | } |
362 | } |
363 | |
364 | void Window::set_size(const Size2i &p_size) { |
365 | ERR_MAIN_THREAD_GUARD; |
366 | |
367 | size = p_size; |
368 | _update_window_size(); |
369 | } |
370 | |
371 | Size2i Window::get_size() const { |
372 | ERR_READ_THREAD_GUARD_V(Size2i()); |
373 | return size; |
374 | } |
375 | |
376 | void Window::reset_size() { |
377 | ERR_MAIN_THREAD_GUARD; |
378 | set_size(Size2i()); |
379 | } |
380 | |
381 | Point2i Window::get_position_with_decorations() const { |
382 | ERR_READ_THREAD_GUARD_V(Point2i()); |
383 | if (window_id != DisplayServer::INVALID_WINDOW_ID) { |
384 | return DisplayServer::get_singleton()->window_get_position_with_decorations(window_id); |
385 | } |
386 | return position; |
387 | } |
388 | |
389 | Size2i Window::get_size_with_decorations() const { |
390 | ERR_READ_THREAD_GUARD_V(Size2i()); |
391 | if (window_id != DisplayServer::INVALID_WINDOW_ID) { |
392 | return DisplayServer::get_singleton()->window_get_size_with_decorations(window_id); |
393 | } |
394 | return size; |
395 | } |
396 | |
397 | Size2i Window::_clamp_limit_size(const Size2i &p_limit_size) { |
398 | // Force window limits to respect size limitations of rendering server. |
399 | Size2i max_window_size = RS::get_singleton()->get_maximum_viewport_size(); |
400 | if (max_window_size != Size2i()) { |
401 | return p_limit_size.clamp(Vector2i(), max_window_size); |
402 | } else { |
403 | return p_limit_size.max(Vector2i()); |
404 | } |
405 | } |
406 | |
407 | void Window::_validate_limit_size() { |
408 | // When max_size is invalid, max_size_used falls back to respect size limitations of rendering server. |
409 | bool max_size_valid = (max_size.x > 0 || max_size.y > 0) && max_size.x >= min_size.x && max_size.y >= min_size.y; |
410 | max_size_used = max_size_valid ? max_size : RS::get_singleton()->get_maximum_viewport_size(); |
411 | } |
412 | |
413 | void Window::set_max_size(const Size2i &p_max_size) { |
414 | ERR_MAIN_THREAD_GUARD; |
415 | Size2i max_size_clamped = _clamp_limit_size(p_max_size); |
416 | if (max_size == max_size_clamped) { |
417 | return; |
418 | } |
419 | max_size = max_size_clamped; |
420 | |
421 | _validate_limit_size(); |
422 | _update_window_size(); |
423 | } |
424 | |
425 | Size2i Window::get_max_size() const { |
426 | ERR_READ_THREAD_GUARD_V(Size2i()); |
427 | return max_size; |
428 | } |
429 | |
430 | void Window::set_min_size(const Size2i &p_min_size) { |
431 | ERR_MAIN_THREAD_GUARD; |
432 | Size2i min_size_clamped = _clamp_limit_size(p_min_size); |
433 | if (min_size == min_size_clamped) { |
434 | return; |
435 | } |
436 | min_size = min_size_clamped; |
437 | |
438 | _validate_limit_size(); |
439 | _update_window_size(); |
440 | } |
441 | |
442 | Size2i Window::get_min_size() const { |
443 | ERR_READ_THREAD_GUARD_V(Size2i()); |
444 | return min_size; |
445 | } |
446 | |
447 | void Window::set_mode(Mode p_mode) { |
448 | ERR_MAIN_THREAD_GUARD; |
449 | mode = p_mode; |
450 | |
451 | if (embedder) { |
452 | embedder->_sub_window_update(this); |
453 | |
454 | } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { |
455 | DisplayServer::get_singleton()->window_set_mode(DisplayServer::WindowMode(p_mode), window_id); |
456 | } |
457 | } |
458 | |
459 | Window::Mode Window::get_mode() const { |
460 | ERR_READ_THREAD_GUARD_V(MODE_WINDOWED); |
461 | if (window_id != DisplayServer::INVALID_WINDOW_ID) { |
462 | mode = (Mode)DisplayServer::get_singleton()->window_get_mode(window_id); |
463 | } |
464 | return mode; |
465 | } |
466 | |
467 | void Window::set_flag(Flags p_flag, bool p_enabled) { |
468 | ERR_MAIN_THREAD_GUARD; |
469 | ERR_FAIL_INDEX(p_flag, FLAG_MAX); |
470 | flags[p_flag] = p_enabled; |
471 | |
472 | if (embedder) { |
473 | embedder->_sub_window_update(this); |
474 | |
475 | } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { |
476 | if (!is_in_edited_scene_root()) { |
477 | DisplayServer::get_singleton()->window_set_flag(DisplayServer::WindowFlags(p_flag), p_enabled, window_id); |
478 | } |
479 | } |
480 | } |
481 | |
482 | bool Window::get_flag(Flags p_flag) const { |
483 | ERR_READ_THREAD_GUARD_V(false); |
484 | ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false); |
485 | if (window_id != DisplayServer::INVALID_WINDOW_ID) { |
486 | if (!is_in_edited_scene_root()) { |
487 | flags[p_flag] = DisplayServer::get_singleton()->window_get_flag(DisplayServer::WindowFlags(p_flag), window_id); |
488 | } |
489 | } |
490 | return flags[p_flag]; |
491 | } |
492 | |
493 | bool Window::is_maximize_allowed() const { |
494 | ERR_READ_THREAD_GUARD_V(false); |
495 | if (window_id != DisplayServer::INVALID_WINDOW_ID) { |
496 | return DisplayServer::get_singleton()->window_is_maximize_allowed(window_id); |
497 | } |
498 | return true; |
499 | } |
500 | |
501 | void Window::request_attention() { |
502 | ERR_MAIN_THREAD_GUARD; |
503 | if (window_id != DisplayServer::INVALID_WINDOW_ID) { |
504 | DisplayServer::get_singleton()->window_request_attention(window_id); |
505 | } |
506 | } |
507 | |
508 | void Window::move_to_foreground() { |
509 | ERR_MAIN_THREAD_GUARD; |
510 | if (embedder) { |
511 | embedder->_sub_window_grab_focus(this); |
512 | |
513 | } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { |
514 | DisplayServer::get_singleton()->window_move_to_foreground(window_id); |
515 | } |
516 | } |
517 | |
518 | bool Window::can_draw() const { |
519 | ERR_READ_THREAD_GUARD_V(false); |
520 | if (!is_inside_tree()) { |
521 | return false; |
522 | } |
523 | if (window_id != DisplayServer::INVALID_WINDOW_ID) { |
524 | return DisplayServer::get_singleton()->window_can_draw(window_id); |
525 | } |
526 | |
527 | return visible; |
528 | } |
529 | |
530 | void Window::set_ime_active(bool p_active) { |
531 | ERR_MAIN_THREAD_GUARD; |
532 | if (window_id != DisplayServer::INVALID_WINDOW_ID) { |
533 | DisplayServer::get_singleton()->window_set_ime_active(p_active, window_id); |
534 | } |
535 | } |
536 | |
537 | void Window::set_ime_position(const Point2i &p_pos) { |
538 | ERR_MAIN_THREAD_GUARD; |
539 | if (window_id != DisplayServer::INVALID_WINDOW_ID) { |
540 | DisplayServer::get_singleton()->window_set_ime_position(p_pos, window_id); |
541 | } |
542 | } |
543 | |
544 | bool Window::is_embedded() const { |
545 | ERR_READ_THREAD_GUARD_V(false); |
546 | return get_embedder() != nullptr; |
547 | } |
548 | |
549 | bool Window::is_in_edited_scene_root() const { |
550 | ERR_READ_THREAD_GUARD_V(false); |
551 | #ifdef TOOLS_ENABLED |
552 | return is_part_of_edited_scene(); |
553 | #else |
554 | return false; |
555 | #endif |
556 | } |
557 | |
558 | void Window::_make_window() { |
559 | ERR_FAIL_COND(window_id != DisplayServer::INVALID_WINDOW_ID); |
560 | |
561 | uint32_t f = 0; |
562 | for (int i = 0; i < FLAG_MAX; i++) { |
563 | if (flags[i]) { |
564 | f |= (1 << i); |
565 | } |
566 | } |
567 | |
568 | DisplayServer::VSyncMode vsync_mode = DisplayServer::get_singleton()->window_get_vsync_mode(DisplayServer::MAIN_WINDOW_ID); |
569 | Rect2i window_rect; |
570 | if (initial_position == WINDOW_INITIAL_POSITION_ABSOLUTE) { |
571 | window_rect = Rect2i(position, size); |
572 | } else if (initial_position == WINDOW_INITIAL_POSITION_CENTER_PRIMARY_SCREEN) { |
573 | window_rect = Rect2i(DisplayServer::get_singleton()->screen_get_position(DisplayServer::SCREEN_PRIMARY) + (DisplayServer::get_singleton()->screen_get_size(DisplayServer::SCREEN_PRIMARY) - size) / 2, size); |
574 | } else if (initial_position == WINDOW_INITIAL_POSITION_CENTER_MAIN_WINDOW_SCREEN) { |
575 | 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); |
576 | } else if (initial_position == WINDOW_INITIAL_POSITION_CENTER_OTHER_SCREEN) { |
577 | window_rect = Rect2i(DisplayServer::get_singleton()->screen_get_position(current_screen) + (DisplayServer::get_singleton()->screen_get_size(current_screen) - size) / 2, size); |
578 | } else if (initial_position == WINDOW_INITIAL_POSITION_CENTER_SCREEN_WITH_MOUSE_FOCUS) { |
579 | 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); |
580 | } else if (initial_position == WINDOW_INITIAL_POSITION_CENTER_SCREEN_WITH_KEYBOARD_FOCUS) { |
581 | 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); |
582 | } |
583 | |
584 | window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), vsync_mode, f, window_rect); |
585 | ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID); |
586 | DisplayServer::get_singleton()->window_set_max_size(Size2i(), window_id); |
587 | DisplayServer::get_singleton()->window_set_min_size(Size2i(), window_id); |
588 | DisplayServer::get_singleton()->window_set_mouse_passthrough(mpath, window_id); |
589 | String tr_title = atr(title); |
590 | #ifdef DEBUG_ENABLED |
591 | if (window_id == DisplayServer::MAIN_WINDOW_ID) { |
592 | // Append a suffix to the window title to denote that the project is running |
593 | // from a debug build (including the editor). Since this results in lower performance, |
594 | // this should be clearly presented to the user. |
595 | tr_title = vformat("%s (DEBUG)" , tr_title); |
596 | } |
597 | #endif |
598 | DisplayServer::get_singleton()->window_set_title(tr_title, window_id); |
599 | DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id); |
600 | |
601 | if (is_in_edited_scene_root()) { |
602 | DisplayServer::get_singleton()->window_set_exclusive(window_id, false); |
603 | } else { |
604 | DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive); |
605 | } |
606 | |
607 | _update_window_size(); |
608 | |
609 | if (transient_parent && transient_parent->window_id != DisplayServer::INVALID_WINDOW_ID) { |
610 | DisplayServer::get_singleton()->window_set_transient(window_id, transient_parent->window_id); |
611 | } |
612 | |
613 | if (transient_parent) { |
614 | for (const Window *E : transient_children) { |
615 | if (E->window_id != DisplayServer::INVALID_WINDOW_ID) { |
616 | DisplayServer::get_singleton()->window_set_transient(E->window_id, transient_parent->window_id); |
617 | } |
618 | } |
619 | } |
620 | |
621 | _update_window_callbacks(); |
622 | |
623 | RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_VISIBLE); |
624 | DisplayServer::get_singleton()->show_window(window_id); |
625 | } |
626 | |
627 | void Window::_update_from_window() { |
628 | ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID); |
629 | mode = (Mode)DisplayServer::get_singleton()->window_get_mode(window_id); |
630 | for (int i = 0; i < FLAG_MAX; i++) { |
631 | flags[i] = DisplayServer::get_singleton()->window_get_flag(DisplayServer::WindowFlags(i), window_id); |
632 | } |
633 | } |
634 | |
635 | void Window::_clear_window() { |
636 | ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID); |
637 | |
638 | bool had_focus = has_focus(); |
639 | |
640 | if (transient_parent && transient_parent->window_id != DisplayServer::INVALID_WINDOW_ID) { |
641 | DisplayServer::get_singleton()->window_set_transient(window_id, DisplayServer::INVALID_WINDOW_ID); |
642 | } |
643 | |
644 | for (const Window *E : transient_children) { |
645 | if (E->window_id != DisplayServer::INVALID_WINDOW_ID) { |
646 | DisplayServer::get_singleton()->window_set_transient(E->window_id, DisplayServer::INVALID_WINDOW_ID); |
647 | } |
648 | } |
649 | |
650 | _update_from_window(); |
651 | |
652 | DisplayServer::get_singleton()->delete_sub_window(window_id); |
653 | window_id = DisplayServer::INVALID_WINDOW_ID; |
654 | |
655 | // If closing window was focused and has a parent, return focus. |
656 | if (had_focus && transient_parent) { |
657 | transient_parent->grab_focus(); |
658 | } |
659 | |
660 | _update_viewport_size(); |
661 | RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED); |
662 | } |
663 | |
664 | void Window::_rect_changed_callback(const Rect2i &p_callback) { |
665 | //we must always accept this as the truth |
666 | if (size == p_callback.size && position == p_callback.position) { |
667 | return; |
668 | } |
669 | position = p_callback.position; |
670 | |
671 | if (size != p_callback.size) { |
672 | size = p_callback.size; |
673 | _update_viewport_size(); |
674 | } |
675 | } |
676 | |
677 | void Window::_propagate_window_notification(Node *p_node, int p_notification) { |
678 | p_node->notification(p_notification); |
679 | for (int i = 0; i < p_node->get_child_count(); i++) { |
680 | Node *child = p_node->get_child(i); |
681 | Window *window = Object::cast_to<Window>(child); |
682 | if (window) { |
683 | continue; |
684 | } |
685 | _propagate_window_notification(child, p_notification); |
686 | } |
687 | } |
688 | |
689 | void Window::_event_callback(DisplayServer::WindowEvent p_event) { |
690 | switch (p_event) { |
691 | case DisplayServer::WINDOW_EVENT_MOUSE_ENTER: { |
692 | Window *root = get_tree()->get_root(); |
693 | if (root->gui.windowmanager_window_over) { |
694 | #ifdef DEV_ENABLED |
695 | WARN_PRINT_ONCE("Entering a window while a window is hovered should never happen in DisplayServer." ); |
696 | #endif // DEV_ENABLED |
697 | root->gui.windowmanager_window_over->_event_callback(DisplayServer::WINDOW_EVENT_MOUSE_EXIT); |
698 | } |
699 | _propagate_window_notification(this, NOTIFICATION_WM_MOUSE_ENTER); |
700 | root->gui.windowmanager_window_over = this; |
701 | mouse_in_window = true; |
702 | if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CURSOR_SHAPE)) { |
703 | DisplayServer::get_singleton()->cursor_set_shape(DisplayServer::CURSOR_ARROW); //restore cursor shape |
704 | } |
705 | } break; |
706 | case DisplayServer::WINDOW_EVENT_MOUSE_EXIT: { |
707 | Window *root = get_tree()->get_root(); |
708 | if (!root->gui.windowmanager_window_over) { |
709 | #ifdef DEV_ENABLED |
710 | WARN_PRINT_ONCE("Exiting a window while no window is hovered should never happen in DisplayServer." ); |
711 | #endif // DEV_ENABLED |
712 | return; |
713 | } |
714 | mouse_in_window = false; |
715 | root->gui.windowmanager_window_over->_mouse_leave_viewport(); |
716 | root->gui.windowmanager_window_over = nullptr; |
717 | _propagate_window_notification(this, NOTIFICATION_WM_MOUSE_EXIT); |
718 | } break; |
719 | case DisplayServer::WINDOW_EVENT_FOCUS_IN: { |
720 | focused = true; |
721 | _propagate_window_notification(this, NOTIFICATION_WM_WINDOW_FOCUS_IN); |
722 | emit_signal(SNAME("focus_entered" )); |
723 | |
724 | } break; |
725 | case DisplayServer::WINDOW_EVENT_FOCUS_OUT: { |
726 | focused = false; |
727 | _propagate_window_notification(this, NOTIFICATION_WM_WINDOW_FOCUS_OUT); |
728 | emit_signal(SNAME("focus_exited" )); |
729 | } break; |
730 | case DisplayServer::WINDOW_EVENT_CLOSE_REQUEST: { |
731 | if (exclusive_child != nullptr) { |
732 | break; //has an exclusive child, can't get events until child is closed |
733 | } |
734 | _propagate_window_notification(this, NOTIFICATION_WM_CLOSE_REQUEST); |
735 | emit_signal(SNAME("close_requested" )); |
736 | } break; |
737 | case DisplayServer::WINDOW_EVENT_GO_BACK_REQUEST: { |
738 | _propagate_window_notification(this, NOTIFICATION_WM_GO_BACK_REQUEST); |
739 | emit_signal(SNAME("go_back_requested" )); |
740 | } break; |
741 | case DisplayServer::WINDOW_EVENT_DPI_CHANGE: { |
742 | _update_viewport_size(); |
743 | _propagate_window_notification(this, NOTIFICATION_WM_DPI_CHANGE); |
744 | emit_signal(SNAME("dpi_changed" )); |
745 | } break; |
746 | case DisplayServer::WINDOW_EVENT_TITLEBAR_CHANGE: { |
747 | emit_signal(SNAME("titlebar_changed" )); |
748 | } break; |
749 | } |
750 | } |
751 | |
752 | void Window::update_mouse_cursor_state() { |
753 | ERR_MAIN_THREAD_GUARD; |
754 | // Update states based on mouse cursor position. |
755 | // This includes updated mouse_enter or mouse_exit signals or the current mouse cursor shape. |
756 | // These details are set in Viewport::_gui_input_event. To instantly |
757 | // see the changes in the viewport, we need to trigger a mouse motion event. |
758 | // This function should be called whenever scene tree changes affect the mouse cursor. |
759 | Ref<InputEventMouseMotion> mm; |
760 | Vector2 pos = get_mouse_position(); |
761 | Transform2D xform = get_global_canvas_transform().affine_inverse(); |
762 | mm.instantiate(); |
763 | mm->set_position(pos); |
764 | mm->set_global_position(xform.xform(pos)); |
765 | mm->set_device(InputEvent::DEVICE_ID_INTERNAL); |
766 | push_input(mm); |
767 | } |
768 | |
769 | void Window::show() { |
770 | ERR_MAIN_THREAD_GUARD; |
771 | set_visible(true); |
772 | } |
773 | |
774 | void Window::hide() { |
775 | ERR_MAIN_THREAD_GUARD; |
776 | set_visible(false); |
777 | } |
778 | |
779 | void Window::set_visible(bool p_visible) { |
780 | ERR_MAIN_THREAD_GUARD; |
781 | if (visible == p_visible) { |
782 | return; |
783 | } |
784 | |
785 | if (!is_inside_tree()) { |
786 | visible = p_visible; |
787 | return; |
788 | } |
789 | |
790 | ERR_FAIL_COND_MSG(get_parent() == nullptr, "Can't change visibility of main window." ); |
791 | |
792 | visible = p_visible; |
793 | |
794 | // Stop any queued resizing, as the window will be resized right now. |
795 | updating_child_controls = false; |
796 | |
797 | Viewport *embedder_vp = get_embedder(); |
798 | |
799 | if (!embedder_vp) { |
800 | if (!p_visible && window_id != DisplayServer::INVALID_WINDOW_ID) { |
801 | _clear_window(); |
802 | } |
803 | if (p_visible && window_id == DisplayServer::INVALID_WINDOW_ID) { |
804 | _make_window(); |
805 | } |
806 | } else { |
807 | if (visible) { |
808 | embedder = embedder_vp; |
809 | if (initial_position != WINDOW_INITIAL_POSITION_ABSOLUTE) { |
810 | position = (embedder->get_visible_rect().size - size) / 2; |
811 | } |
812 | embedder->_sub_window_register(this); |
813 | RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE); |
814 | } else { |
815 | embedder->_sub_window_remove(this); |
816 | embedder = nullptr; |
817 | RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED); |
818 | } |
819 | _update_window_size(); |
820 | } |
821 | |
822 | if (!visible) { |
823 | focused = false; |
824 | } |
825 | notification(NOTIFICATION_VISIBILITY_CHANGED); |
826 | emit_signal(SceneStringNames::get_singleton()->visibility_changed); |
827 | |
828 | RS::get_singleton()->viewport_set_active(get_viewport_rid(), visible); |
829 | |
830 | //update transient exclusive |
831 | if (transient_parent) { |
832 | if (exclusive && visible) { |
833 | if (!is_in_edited_scene_root()) { |
834 | ERR_FAIL_COND_MSG(transient_parent->exclusive_child && transient_parent->exclusive_child != this, "Transient parent has another exclusive child." ); |
835 | transient_parent->exclusive_child = this; |
836 | } |
837 | } else { |
838 | if (transient_parent->exclusive_child == this) { |
839 | transient_parent->exclusive_child = nullptr; |
840 | } |
841 | } |
842 | } |
843 | } |
844 | |
845 | void Window::_clear_transient() { |
846 | if (transient_parent) { |
847 | if (transient_parent->window_id != DisplayServer::INVALID_WINDOW_ID && window_id != DisplayServer::INVALID_WINDOW_ID) { |
848 | DisplayServer::get_singleton()->window_set_transient(window_id, DisplayServer::INVALID_WINDOW_ID); |
849 | } |
850 | transient_parent->transient_children.erase(this); |
851 | if (transient_parent->exclusive_child == this) { |
852 | transient_parent->exclusive_child = nullptr; |
853 | } |
854 | transient_parent = nullptr; |
855 | } |
856 | } |
857 | |
858 | void Window::_make_transient() { |
859 | if (!get_parent()) { |
860 | //main window, can't be transient |
861 | return; |
862 | } |
863 | //find transient parent |
864 | Viewport *vp = get_parent()->get_viewport(); |
865 | Window *window = nullptr; |
866 | while (vp) { |
867 | window = Object::cast_to<Window>(vp); |
868 | if (window) { |
869 | break; |
870 | } |
871 | if (!vp->get_parent()) { |
872 | break; |
873 | } |
874 | |
875 | vp = vp->get_parent()->get_viewport(); |
876 | } |
877 | |
878 | if (window) { |
879 | transient_parent = window; |
880 | window->transient_children.insert(this); |
881 | if (is_inside_tree() && is_visible() && exclusive) { |
882 | if (transient_parent->exclusive_child == nullptr) { |
883 | if (!is_in_edited_scene_root()) { |
884 | transient_parent->exclusive_child = this; |
885 | } |
886 | } else if (transient_parent->exclusive_child != this) { |
887 | ERR_PRINT("Making child transient exclusive, but parent has another exclusive child" ); |
888 | } |
889 | } |
890 | } |
891 | |
892 | //see if we can make transient |
893 | if (transient_parent->window_id != DisplayServer::INVALID_WINDOW_ID && window_id != DisplayServer::INVALID_WINDOW_ID) { |
894 | DisplayServer::get_singleton()->window_set_transient(window_id, transient_parent->window_id); |
895 | } |
896 | } |
897 | |
898 | void Window::set_transient(bool p_transient) { |
899 | ERR_MAIN_THREAD_GUARD; |
900 | if (transient == p_transient) { |
901 | return; |
902 | } |
903 | |
904 | transient = p_transient; |
905 | |
906 | if (!is_inside_tree()) { |
907 | return; |
908 | } |
909 | |
910 | if (transient) { |
911 | _make_transient(); |
912 | } else { |
913 | _clear_transient(); |
914 | } |
915 | } |
916 | |
917 | bool Window::is_transient() const { |
918 | ERR_READ_THREAD_GUARD_V(false); |
919 | return transient; |
920 | } |
921 | |
922 | void Window::set_exclusive(bool p_exclusive) { |
923 | ERR_MAIN_THREAD_GUARD; |
924 | if (exclusive == p_exclusive) { |
925 | return; |
926 | } |
927 | |
928 | exclusive = p_exclusive; |
929 | |
930 | if (!embedder && window_id != DisplayServer::INVALID_WINDOW_ID) { |
931 | if (is_in_edited_scene_root()) { |
932 | DisplayServer::get_singleton()->window_set_exclusive(window_id, false); |
933 | } else { |
934 | DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive); |
935 | } |
936 | } |
937 | |
938 | if (transient_parent) { |
939 | if (p_exclusive && is_inside_tree() && is_visible()) { |
940 | ERR_FAIL_COND_MSG(transient_parent->exclusive_child && transient_parent->exclusive_child != this, "Transient parent has another exclusive child." ); |
941 | if (!is_in_edited_scene_root()) { |
942 | transient_parent->exclusive_child = this; |
943 | } |
944 | } else { |
945 | if (transient_parent->exclusive_child == this) { |
946 | transient_parent->exclusive_child = nullptr; |
947 | } |
948 | } |
949 | } |
950 | } |
951 | |
952 | bool Window::is_exclusive() const { |
953 | ERR_READ_THREAD_GUARD_V(false); |
954 | return exclusive; |
955 | } |
956 | |
957 | bool Window::is_visible() const { |
958 | ERR_READ_THREAD_GUARD_V(false); |
959 | return visible; |
960 | } |
961 | |
962 | Size2i Window::_clamp_window_size(const Size2i &p_size) { |
963 | Size2i window_size_clamped = p_size; |
964 | Size2 minsize = get_clamped_minimum_size(); |
965 | window_size_clamped = window_size_clamped.max(minsize); |
966 | |
967 | if (max_size_used != Size2i()) { |
968 | window_size_clamped = window_size_clamped.min(max_size_used); |
969 | } |
970 | |
971 | return window_size_clamped; |
972 | } |
973 | |
974 | void Window::_update_window_size() { |
975 | Size2i size_limit = get_clamped_minimum_size(); |
976 | |
977 | size = size.max(size_limit); |
978 | |
979 | bool reset_min_first = false; |
980 | |
981 | if (max_size_used != Size2i()) { |
982 | // Force window size to respect size limitations of max_size_used. |
983 | size = size.min(max_size_used); |
984 | |
985 | if (size_limit.x > max_size_used.x) { |
986 | size_limit.x = max_size_used.x; |
987 | reset_min_first = true; |
988 | } |
989 | if (size_limit.y > max_size_used.y) { |
990 | size_limit.y = max_size_used.y; |
991 | reset_min_first = true; |
992 | } |
993 | } |
994 | |
995 | if (embedder) { |
996 | size.x = MAX(size.x, 1); |
997 | size.y = MAX(size.y, 1); |
998 | |
999 | embedder->_sub_window_update(this); |
1000 | } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { |
1001 | if (reset_min_first && wrap_controls) { |
1002 | // Avoid an error if setting max_size to a value between min_size and the previous size_limit. |
1003 | DisplayServer::get_singleton()->window_set_min_size(Size2i(), window_id); |
1004 | } |
1005 | |
1006 | DisplayServer::get_singleton()->window_set_max_size(max_size_used, window_id); |
1007 | DisplayServer::get_singleton()->window_set_min_size(size_limit, window_id); |
1008 | DisplayServer::get_singleton()->window_set_size(size, window_id); |
1009 | } |
1010 | |
1011 | //update the viewport |
1012 | _update_viewport_size(); |
1013 | } |
1014 | |
1015 | void Window::_update_viewport_size() { |
1016 | //update the viewport part |
1017 | |
1018 | Size2i final_size; |
1019 | Size2i final_size_override; |
1020 | Rect2i attach_to_screen_rect(Point2i(), size); |
1021 | float font_oversampling = 1.0; |
1022 | window_transform = Transform2D(); |
1023 | |
1024 | if (content_scale_stretch == Window::CONTENT_SCALE_STRETCH_INTEGER) { |
1025 | // We always want to make sure that the content scale factor is a whole |
1026 | // number, else there will be pixel wobble no matter what. |
1027 | content_scale_factor = Math::floor(content_scale_factor); |
1028 | |
1029 | // A content scale factor of zero is pretty useless. |
1030 | if (content_scale_factor < 1) { |
1031 | content_scale_factor = 1; |
1032 | } |
1033 | } |
1034 | |
1035 | if (content_scale_mode == CONTENT_SCALE_MODE_DISABLED || content_scale_size.x == 0 || content_scale_size.y == 0) { |
1036 | font_oversampling = content_scale_factor; |
1037 | final_size = size; |
1038 | final_size_override = Size2(size) / content_scale_factor; |
1039 | } else { |
1040 | //actual screen video mode |
1041 | Size2 video_mode = size; |
1042 | Size2 desired_res = content_scale_size; |
1043 | |
1044 | Size2 viewport_size; |
1045 | Size2 screen_size; |
1046 | |
1047 | float viewport_aspect = desired_res.aspect(); |
1048 | float video_mode_aspect = video_mode.aspect(); |
1049 | |
1050 | if (content_scale_aspect == CONTENT_SCALE_ASPECT_IGNORE || Math::is_equal_approx(viewport_aspect, video_mode_aspect)) { |
1051 | //same aspect or ignore aspect |
1052 | viewport_size = desired_res; |
1053 | screen_size = video_mode; |
1054 | } else if (viewport_aspect < video_mode_aspect) { |
1055 | // screen ratio is smaller vertically |
1056 | |
1057 | if (content_scale_aspect == CONTENT_SCALE_ASPECT_KEEP_HEIGHT || content_scale_aspect == CONTENT_SCALE_ASPECT_EXPAND) { |
1058 | //will stretch horizontally |
1059 | viewport_size.x = desired_res.y * video_mode_aspect; |
1060 | viewport_size.y = desired_res.y; |
1061 | screen_size = video_mode; |
1062 | |
1063 | } else { |
1064 | //will need black bars |
1065 | viewport_size = desired_res; |
1066 | screen_size.x = video_mode.y * viewport_aspect; |
1067 | screen_size.y = video_mode.y; |
1068 | } |
1069 | } else { |
1070 | //screen ratio is smaller horizontally |
1071 | if (content_scale_aspect == CONTENT_SCALE_ASPECT_KEEP_WIDTH || content_scale_aspect == CONTENT_SCALE_ASPECT_EXPAND) { |
1072 | //will stretch horizontally |
1073 | viewport_size.x = desired_res.x; |
1074 | viewport_size.y = desired_res.x / video_mode_aspect; |
1075 | screen_size = video_mode; |
1076 | |
1077 | } else { |
1078 | //will need black bars |
1079 | viewport_size = desired_res; |
1080 | screen_size.x = video_mode.x; |
1081 | screen_size.y = video_mode.x / viewport_aspect; |
1082 | } |
1083 | } |
1084 | |
1085 | screen_size = screen_size.floor(); |
1086 | viewport_size = viewport_size.floor(); |
1087 | |
1088 | if (content_scale_stretch == Window::CONTENT_SCALE_STRETCH_INTEGER) { |
1089 | Size2i screen_scale = (screen_size / viewport_size).floor(); |
1090 | int scale_factor = MIN(screen_scale.x, screen_scale.y); |
1091 | |
1092 | if (scale_factor < 1) { |
1093 | scale_factor = 1; |
1094 | } |
1095 | |
1096 | screen_size = viewport_size * scale_factor; |
1097 | } |
1098 | |
1099 | Size2 margin; |
1100 | Size2 offset; |
1101 | |
1102 | if (screen_size.x < video_mode.x) { |
1103 | margin.x = Math::round((video_mode.x - screen_size.x) / 2.0); |
1104 | offset.x = Math::round(margin.x * viewport_size.y / screen_size.y); |
1105 | } |
1106 | |
1107 | if (screen_size.y < video_mode.y) { |
1108 | margin.y = Math::round((video_mode.y - screen_size.y) / 2.0); |
1109 | offset.y = Math::round(margin.y * viewport_size.x / screen_size.x); |
1110 | } |
1111 | |
1112 | switch (content_scale_mode) { |
1113 | case CONTENT_SCALE_MODE_DISABLED: { |
1114 | // Already handled above |
1115 | //_update_font_oversampling(1.0); |
1116 | } break; |
1117 | case CONTENT_SCALE_MODE_CANVAS_ITEMS: { |
1118 | final_size = screen_size; |
1119 | final_size_override = viewport_size / content_scale_factor; |
1120 | attach_to_screen_rect = Rect2(margin, screen_size); |
1121 | font_oversampling = (screen_size.x / viewport_size.x) * content_scale_factor; |
1122 | |
1123 | window_transform.translate_local(margin); |
1124 | } break; |
1125 | case CONTENT_SCALE_MODE_VIEWPORT: { |
1126 | final_size = (viewport_size / content_scale_factor).floor(); |
1127 | attach_to_screen_rect = Rect2(margin, screen_size); |
1128 | |
1129 | window_transform.translate_local(margin); |
1130 | if (final_size.x != 0 && final_size.y != 0) { |
1131 | Transform2D scale_transform; |
1132 | scale_transform.scale(Vector2(attach_to_screen_rect.size) / Vector2(final_size)); |
1133 | window_transform *= scale_transform; |
1134 | } |
1135 | } break; |
1136 | } |
1137 | } |
1138 | |
1139 | bool allocate = is_inside_tree() && visible && (window_id != DisplayServer::INVALID_WINDOW_ID || embedder != nullptr); |
1140 | _set_size(final_size, final_size_override, allocate); |
1141 | |
1142 | if (window_id != DisplayServer::INVALID_WINDOW_ID) { |
1143 | RenderingServer::get_singleton()->viewport_attach_to_screen(get_viewport_rid(), attach_to_screen_rect, window_id); |
1144 | } else { |
1145 | RenderingServer::get_singleton()->viewport_attach_to_screen(get_viewport_rid(), Rect2i(), DisplayServer::INVALID_WINDOW_ID); |
1146 | } |
1147 | |
1148 | if (window_id == DisplayServer::MAIN_WINDOW_ID) { |
1149 | if (!use_font_oversampling) { |
1150 | font_oversampling = 1.0; |
1151 | } |
1152 | if (TS->font_get_global_oversampling() != font_oversampling) { |
1153 | TS->font_set_global_oversampling(font_oversampling); |
1154 | } |
1155 | } |
1156 | |
1157 | notification(NOTIFICATION_WM_SIZE_CHANGED); |
1158 | |
1159 | if (embedder) { |
1160 | embedder->_sub_window_update(this); |
1161 | } |
1162 | } |
1163 | |
1164 | void Window::_update_window_callbacks() { |
1165 | DisplayServer::get_singleton()->window_set_rect_changed_callback(callable_mp(this, &Window::_rect_changed_callback), window_id); |
1166 | DisplayServer::get_singleton()->window_set_window_event_callback(callable_mp(this, &Window::_event_callback), window_id); |
1167 | DisplayServer::get_singleton()->window_set_input_event_callback(callable_mp(this, &Window::_window_input), window_id); |
1168 | DisplayServer::get_singleton()->window_set_input_text_callback(callable_mp(this, &Window::_window_input_text), window_id); |
1169 | DisplayServer::get_singleton()->window_set_drop_files_callback(callable_mp(this, &Window::_window_drop_files), window_id); |
1170 | } |
1171 | |
1172 | Viewport *Window::get_embedder() const { |
1173 | ERR_READ_THREAD_GUARD_V(nullptr); |
1174 | Viewport *vp = get_parent_viewport(); |
1175 | |
1176 | while (vp) { |
1177 | if (vp->is_embedding_subwindows()) { |
1178 | return vp; |
1179 | } |
1180 | |
1181 | if (vp->get_parent()) { |
1182 | vp = vp->get_parent()->get_viewport(); |
1183 | } else { |
1184 | vp = nullptr; |
1185 | } |
1186 | } |
1187 | return nullptr; |
1188 | } |
1189 | |
1190 | void Window::_notification(int p_what) { |
1191 | ERR_MAIN_THREAD_GUARD; |
1192 | switch (p_what) { |
1193 | case NOTIFICATION_POSTINITIALIZE: { |
1194 | initialized = true; |
1195 | |
1196 | _invalidate_theme_cache(); |
1197 | _update_theme_item_cache(); |
1198 | } break; |
1199 | |
1200 | case NOTIFICATION_PARENTED: { |
1201 | theme_owner->assign_theme_on_parented(this); |
1202 | } break; |
1203 | |
1204 | case NOTIFICATION_UNPARENTED: { |
1205 | theme_owner->clear_theme_on_unparented(this); |
1206 | } break; |
1207 | |
1208 | case NOTIFICATION_ENTER_TREE: { |
1209 | bool embedded = false; |
1210 | { |
1211 | embedder = get_embedder(); |
1212 | if (embedder) { |
1213 | embedded = true; |
1214 | if (!visible) { |
1215 | embedder = nullptr; // Not yet since not visible. |
1216 | } |
1217 | } |
1218 | } |
1219 | |
1220 | if (embedded) { |
1221 | // Create as embedded. |
1222 | if (embedder) { |
1223 | if (initial_position != WINDOW_INITIAL_POSITION_ABSOLUTE) { |
1224 | position = (embedder->get_visible_rect().size - size) / 2; |
1225 | } |
1226 | embedder->_sub_window_register(this); |
1227 | RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE); |
1228 | _update_window_size(); |
1229 | } |
1230 | |
1231 | } else { |
1232 | if (!get_parent()) { |
1233 | // It's the root window! |
1234 | visible = true; // Always visible. |
1235 | window_id = DisplayServer::MAIN_WINDOW_ID; |
1236 | DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id); |
1237 | _update_from_window(); |
1238 | // Since this window already exists (created on start), we must update pos and size from it. |
1239 | { |
1240 | position = DisplayServer::get_singleton()->window_get_position(window_id); |
1241 | size = DisplayServer::get_singleton()->window_get_size(window_id); |
1242 | focused = DisplayServer::get_singleton()->window_is_focused(window_id); |
1243 | } |
1244 | _update_window_size(); // Inform DisplayServer of minimum and maximum size. |
1245 | _update_viewport_size(); // Then feed back to the viewport. |
1246 | _update_window_callbacks(); |
1247 | RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_VISIBLE); |
1248 | } else { |
1249 | // Create. |
1250 | if (visible) { |
1251 | _make_window(); |
1252 | } |
1253 | } |
1254 | } |
1255 | |
1256 | if (transient) { |
1257 | _make_transient(); |
1258 | } |
1259 | if (visible) { |
1260 | notification(NOTIFICATION_VISIBILITY_CHANGED); |
1261 | emit_signal(SceneStringNames::get_singleton()->visibility_changed); |
1262 | RS::get_singleton()->viewport_set_active(get_viewport_rid(), true); |
1263 | } |
1264 | |
1265 | #ifdef TOOLS_ENABLED |
1266 | if (is_part_of_edited_scene()) { |
1267 | // Don't translate Windows on scene when inside editor. |
1268 | set_message_translation(false); |
1269 | notification(NOTIFICATION_TRANSLATION_CHANGED); |
1270 | } |
1271 | #endif |
1272 | |
1273 | // Emits NOTIFICATION_THEME_CHANGED internally. |
1274 | set_theme_context(ThemeDB::get_singleton()->get_nearest_theme_context(this)); |
1275 | } break; |
1276 | |
1277 | case NOTIFICATION_READY: { |
1278 | if (wrap_controls) { |
1279 | // Finish any resizing immediately so it doesn't interfere on stuff overriding _ready(). |
1280 | _update_child_controls(); |
1281 | } |
1282 | } break; |
1283 | |
1284 | case NOTIFICATION_THEME_CHANGED: { |
1285 | emit_signal(SceneStringNames::get_singleton()->theme_changed); |
1286 | _invalidate_theme_cache(); |
1287 | _update_theme_item_cache(); |
1288 | } break; |
1289 | |
1290 | case NOTIFICATION_TRANSLATION_CHANGED: { |
1291 | _invalidate_theme_cache(); |
1292 | _update_theme_item_cache(); |
1293 | |
1294 | if (!embedder && window_id != DisplayServer::INVALID_WINDOW_ID) { |
1295 | String tr_title = atr(title); |
1296 | #ifdef DEBUG_ENABLED |
1297 | if (window_id == DisplayServer::MAIN_WINDOW_ID) { |
1298 | // Append a suffix to the window title to denote that the project is running |
1299 | // from a debug build (including the editor). Since this results in lower performance, |
1300 | // this should be clearly presented to the user. |
1301 | tr_title = vformat("%s (DEBUG)" , tr_title); |
1302 | } |
1303 | #endif |
1304 | DisplayServer::get_singleton()->window_set_title(tr_title, window_id); |
1305 | } |
1306 | } break; |
1307 | |
1308 | case NOTIFICATION_VISIBILITY_CHANGED: { |
1309 | if (unparent_when_invisible && !is_visible()) { |
1310 | Node *p = get_parent(); |
1311 | if (p) { |
1312 | p->remove_child(this); |
1313 | } |
1314 | } |
1315 | } break; |
1316 | |
1317 | case NOTIFICATION_EXIT_TREE: { |
1318 | set_theme_context(nullptr, false); |
1319 | |
1320 | if (transient) { |
1321 | _clear_transient(); |
1322 | } |
1323 | |
1324 | if (!is_embedded() && window_id != DisplayServer::INVALID_WINDOW_ID) { |
1325 | if (window_id == DisplayServer::MAIN_WINDOW_ID) { |
1326 | RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED); |
1327 | _update_window_callbacks(); |
1328 | } else { |
1329 | _clear_window(); |
1330 | } |
1331 | } else { |
1332 | if (embedder) { |
1333 | embedder->_sub_window_remove(this); |
1334 | embedder = nullptr; |
1335 | RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED); |
1336 | } |
1337 | _update_viewport_size(); //called by clear and make, which does not happen here |
1338 | } |
1339 | |
1340 | RS::get_singleton()->viewport_set_active(get_viewport_rid(), false); |
1341 | } break; |
1342 | |
1343 | case NOTIFICATION_VP_MOUSE_ENTER: { |
1344 | emit_signal(SceneStringNames::get_singleton()->mouse_entered); |
1345 | } break; |
1346 | |
1347 | case NOTIFICATION_VP_MOUSE_EXIT: { |
1348 | emit_signal(SceneStringNames::get_singleton()->mouse_exited); |
1349 | } break; |
1350 | } |
1351 | } |
1352 | |
1353 | void Window::set_content_scale_size(const Size2i &p_size) { |
1354 | ERR_MAIN_THREAD_GUARD; |
1355 | ERR_FAIL_COND(p_size.x < 0); |
1356 | ERR_FAIL_COND(p_size.y < 0); |
1357 | content_scale_size = p_size; |
1358 | _update_viewport_size(); |
1359 | } |
1360 | |
1361 | Size2i Window::get_content_scale_size() const { |
1362 | ERR_READ_THREAD_GUARD_V(Size2i()); |
1363 | return content_scale_size; |
1364 | } |
1365 | |
1366 | void Window::set_content_scale_mode(ContentScaleMode p_mode) { |
1367 | ERR_MAIN_THREAD_GUARD; |
1368 | content_scale_mode = p_mode; |
1369 | _update_viewport_size(); |
1370 | } |
1371 | |
1372 | Window::ContentScaleMode Window::get_content_scale_mode() const { |
1373 | ERR_READ_THREAD_GUARD_V(CONTENT_SCALE_MODE_DISABLED); |
1374 | return content_scale_mode; |
1375 | } |
1376 | |
1377 | void Window::set_content_scale_aspect(ContentScaleAspect p_aspect) { |
1378 | ERR_MAIN_THREAD_GUARD; |
1379 | content_scale_aspect = p_aspect; |
1380 | _update_viewport_size(); |
1381 | } |
1382 | |
1383 | Window::ContentScaleAspect Window::get_content_scale_aspect() const { |
1384 | ERR_READ_THREAD_GUARD_V(CONTENT_SCALE_ASPECT_IGNORE); |
1385 | return content_scale_aspect; |
1386 | } |
1387 | |
1388 | void Window::set_content_scale_stretch(ContentScaleStretch p_stretch) { |
1389 | content_scale_stretch = p_stretch; |
1390 | _update_viewport_size(); |
1391 | } |
1392 | |
1393 | Window::ContentScaleStretch Window::get_content_scale_stretch() const { |
1394 | return content_scale_stretch; |
1395 | } |
1396 | |
1397 | void Window::set_content_scale_factor(real_t p_factor) { |
1398 | ERR_MAIN_THREAD_GUARD; |
1399 | ERR_FAIL_COND(p_factor <= 0); |
1400 | content_scale_factor = p_factor; |
1401 | _update_viewport_size(); |
1402 | } |
1403 | |
1404 | real_t Window::get_content_scale_factor() const { |
1405 | ERR_READ_THREAD_GUARD_V(0); |
1406 | return content_scale_factor; |
1407 | } |
1408 | |
1409 | void Window::set_use_font_oversampling(bool p_oversampling) { |
1410 | ERR_MAIN_THREAD_GUARD; |
1411 | if (is_inside_tree() && window_id != DisplayServer::MAIN_WINDOW_ID) { |
1412 | ERR_FAIL_MSG("Only the root window can set and use font oversampling." ); |
1413 | } |
1414 | use_font_oversampling = p_oversampling; |
1415 | _update_viewport_size(); |
1416 | } |
1417 | |
1418 | bool Window::is_using_font_oversampling() const { |
1419 | ERR_READ_THREAD_GUARD_V(false); |
1420 | return use_font_oversampling; |
1421 | } |
1422 | |
1423 | DisplayServer::WindowID Window::get_window_id() const { |
1424 | ERR_READ_THREAD_GUARD_V(DisplayServer::INVALID_WINDOW_ID); |
1425 | if (embedder) { |
1426 | return parent->get_window_id(); |
1427 | } |
1428 | return window_id; |
1429 | } |
1430 | |
1431 | void Window::set_mouse_passthrough_polygon(const Vector<Vector2> &p_region) { |
1432 | ERR_MAIN_THREAD_GUARD; |
1433 | mpath = p_region; |
1434 | if (window_id == DisplayServer::INVALID_WINDOW_ID) { |
1435 | return; |
1436 | } |
1437 | DisplayServer::get_singleton()->window_set_mouse_passthrough(mpath, window_id); |
1438 | } |
1439 | |
1440 | Vector<Vector2> Window::get_mouse_passthrough_polygon() const { |
1441 | return mpath; |
1442 | } |
1443 | |
1444 | void Window::set_wrap_controls(bool p_enable) { |
1445 | ERR_MAIN_THREAD_GUARD; |
1446 | wrap_controls = p_enable; |
1447 | |
1448 | if (!is_inside_tree()) { |
1449 | return; |
1450 | } |
1451 | |
1452 | if (updating_child_controls) { |
1453 | _update_child_controls(); |
1454 | } else { |
1455 | _update_window_size(); |
1456 | } |
1457 | } |
1458 | |
1459 | bool Window::is_wrapping_controls() const { |
1460 | ERR_READ_THREAD_GUARD_V(false); |
1461 | return wrap_controls; |
1462 | } |
1463 | |
1464 | Size2 Window::_get_contents_minimum_size() const { |
1465 | Size2 max; |
1466 | |
1467 | for (int i = 0; i < get_child_count(); i++) { |
1468 | Control *c = Object::cast_to<Control>(get_child(i)); |
1469 | if (c) { |
1470 | Point2i pos = c->get_position(); |
1471 | Size2i min = c->get_combined_minimum_size(); |
1472 | |
1473 | max.x = MAX(pos.x + min.x, max.x); |
1474 | max.y = MAX(pos.y + min.y, max.y); |
1475 | } |
1476 | } |
1477 | |
1478 | return max; |
1479 | } |
1480 | |
1481 | void Window::child_controls_changed() { |
1482 | ERR_MAIN_THREAD_GUARD; |
1483 | if (!is_inside_tree() || !visible || updating_child_controls) { |
1484 | return; |
1485 | } |
1486 | |
1487 | updating_child_controls = true; |
1488 | call_deferred(SNAME("_update_child_controls" )); |
1489 | } |
1490 | |
1491 | void Window::_update_child_controls() { |
1492 | if (!updating_child_controls) { |
1493 | return; |
1494 | } |
1495 | |
1496 | _update_window_size(); |
1497 | |
1498 | updating_child_controls = false; |
1499 | } |
1500 | |
1501 | bool Window::_can_consume_input_events() const { |
1502 | return exclusive_child == nullptr; |
1503 | } |
1504 | |
1505 | void Window::_window_input(const Ref<InputEvent> &p_ev) { |
1506 | if (EngineDebugger::is_active()) { |
1507 | // Quit from game window using the stop shortcut (F8 by default). |
1508 | // The custom shortcut is provided via environment variable when running from the editor. |
1509 | if (debugger_stop_shortcut.is_null()) { |
1510 | String shortcut_str = OS::get_singleton()->get_environment("__GODOT_EDITOR_STOP_SHORTCUT__" ); |
1511 | if (!shortcut_str.is_empty()) { |
1512 | Variant shortcut_var; |
1513 | |
1514 | VariantParser::StreamString ss; |
1515 | ss.s = shortcut_str; |
1516 | |
1517 | String errs; |
1518 | int line; |
1519 | VariantParser::parse(&ss, shortcut_var, errs, line); |
1520 | debugger_stop_shortcut = shortcut_var; |
1521 | } |
1522 | |
1523 | if (debugger_stop_shortcut.is_null()) { |
1524 | // Define a default shortcut if it wasn't provided or is invalid. |
1525 | debugger_stop_shortcut.instantiate(); |
1526 | debugger_stop_shortcut->set_events({ (Variant)InputEventKey::create_reference(Key::F8) }); |
1527 | } |
1528 | } |
1529 | |
1530 | Ref<InputEventKey> k = p_ev; |
1531 | if (k.is_valid() && k->is_pressed() && !k->is_echo() && debugger_stop_shortcut->matches_event(k)) { |
1532 | EngineDebugger::get_singleton()->send_message("request_quit" , Array()); |
1533 | } |
1534 | } |
1535 | |
1536 | if (exclusive_child != nullptr) { |
1537 | if (!is_embedding_subwindows()) { // Not embedding, no need for event. |
1538 | return; |
1539 | } |
1540 | } |
1541 | |
1542 | if (p_ev->get_device() != InputEvent::DEVICE_ID_INTERNAL) { |
1543 | emit_signal(SceneStringNames::get_singleton()->window_input, p_ev); |
1544 | } |
1545 | |
1546 | if (is_inside_tree()) { |
1547 | push_input(p_ev); |
1548 | } |
1549 | } |
1550 | |
1551 | void Window::_window_input_text(const String &p_text) { |
1552 | push_text_input(p_text); |
1553 | } |
1554 | |
1555 | void Window::_window_drop_files(const Vector<String> &p_files) { |
1556 | emit_signal(SNAME("files_dropped" ), p_files); |
1557 | } |
1558 | |
1559 | Viewport *Window::get_parent_viewport() const { |
1560 | ERR_READ_THREAD_GUARD_V(nullptr); |
1561 | if (get_parent()) { |
1562 | return get_parent()->get_viewport(); |
1563 | } else { |
1564 | return nullptr; |
1565 | } |
1566 | } |
1567 | |
1568 | Window *Window::get_parent_visible_window() const { |
1569 | ERR_READ_THREAD_GUARD_V(nullptr); |
1570 | Viewport *vp = get_parent_viewport(); |
1571 | Window *window = nullptr; |
1572 | while (vp) { |
1573 | window = Object::cast_to<Window>(vp); |
1574 | if (window && window->visible) { |
1575 | break; |
1576 | } |
1577 | if (!vp->get_parent()) { |
1578 | break; |
1579 | } |
1580 | |
1581 | vp = vp->get_parent()->get_viewport(); |
1582 | } |
1583 | return window; |
1584 | } |
1585 | |
1586 | void Window::(const Rect2i &p_parent_rect) { |
1587 | ERR_MAIN_THREAD_GUARD; |
1588 | ERR_FAIL_COND(!is_inside_tree()); |
1589 | ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window." ); |
1590 | |
1591 | if (!is_embedded()) { |
1592 | Window *window = get_parent_visible_window(); |
1593 | |
1594 | if (!window) { |
1595 | popup(p_parent_rect); |
1596 | } else { |
1597 | popup(Rect2i(window->get_position() + p_parent_rect.position, p_parent_rect.size)); |
1598 | } |
1599 | } else { |
1600 | popup(p_parent_rect); |
1601 | } |
1602 | } |
1603 | |
1604 | void Window::(const Size2i &p_size, float p_fallback_ratio) { |
1605 | ERR_MAIN_THREAD_GUARD; |
1606 | ERR_FAIL_COND(!is_inside_tree()); |
1607 | ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window." ); |
1608 | |
1609 | // Consider the current size when calling with the default value. |
1610 | Size2i expected_size = p_size == Size2i() ? size : p_size; |
1611 | |
1612 | Rect2 parent_rect; |
1613 | |
1614 | if (is_embedded()) { |
1615 | parent_rect = get_embedder()->get_visible_rect(); |
1616 | } else { |
1617 | DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id(); |
1618 | int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id); |
1619 | parent_rect.position = DisplayServer::get_singleton()->screen_get_position(parent_screen); |
1620 | parent_rect.size = DisplayServer::get_singleton()->screen_get_size(parent_screen); |
1621 | } |
1622 | |
1623 | Vector2i size_ratio = parent_rect.size * p_fallback_ratio; |
1624 | |
1625 | Rect2i ; |
1626 | popup_rect.size = Vector2i(MIN(size_ratio.x, expected_size.x), MIN(size_ratio.y, expected_size.y)); |
1627 | popup_rect.size = _clamp_window_size(popup_rect.size); |
1628 | |
1629 | if (parent_rect != Rect2()) { |
1630 | popup_rect.position = parent_rect.position + (parent_rect.size - popup_rect.size) / 2; |
1631 | } |
1632 | |
1633 | popup(popup_rect); |
1634 | } |
1635 | |
1636 | void Window::(const Size2i &p_minsize) { |
1637 | ERR_MAIN_THREAD_GUARD; |
1638 | ERR_FAIL_COND(!is_inside_tree()); |
1639 | ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window." ); |
1640 | |
1641 | // Consider the current size when calling with the default value. |
1642 | Size2i expected_size = p_minsize == Size2i() ? size : p_minsize; |
1643 | |
1644 | Rect2 parent_rect; |
1645 | |
1646 | if (is_embedded()) { |
1647 | parent_rect = get_embedder()->get_visible_rect(); |
1648 | } else { |
1649 | DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id(); |
1650 | int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id); |
1651 | parent_rect.position = DisplayServer::get_singleton()->screen_get_position(parent_screen); |
1652 | parent_rect.size = DisplayServer::get_singleton()->screen_get_size(parent_screen); |
1653 | } |
1654 | |
1655 | Rect2i ; |
1656 | popup_rect.size = _clamp_window_size(expected_size); |
1657 | |
1658 | if (parent_rect != Rect2()) { |
1659 | popup_rect.position = parent_rect.position + (parent_rect.size - popup_rect.size) / 2; |
1660 | } |
1661 | |
1662 | popup(popup_rect); |
1663 | } |
1664 | |
1665 | void Window::(float p_ratio) { |
1666 | ERR_MAIN_THREAD_GUARD; |
1667 | ERR_FAIL_COND(!is_inside_tree()); |
1668 | ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window." ); |
1669 | ERR_FAIL_COND_MSG(p_ratio <= 0.0 || p_ratio > 1.0, "Ratio must be between 0.0 and 1.0!" ); |
1670 | |
1671 | Rect2 parent_rect; |
1672 | |
1673 | if (is_embedded()) { |
1674 | parent_rect = get_embedder()->get_visible_rect(); |
1675 | } else { |
1676 | DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id(); |
1677 | int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id); |
1678 | parent_rect.position = DisplayServer::get_singleton()->screen_get_position(parent_screen); |
1679 | parent_rect.size = DisplayServer::get_singleton()->screen_get_size(parent_screen); |
1680 | } |
1681 | |
1682 | Rect2i ; |
1683 | if (parent_rect != Rect2()) { |
1684 | popup_rect.size = parent_rect.size * p_ratio; |
1685 | popup_rect.size = _clamp_window_size(popup_rect.size); |
1686 | popup_rect.position = parent_rect.position + (parent_rect.size - popup_rect.size) / 2; |
1687 | } |
1688 | |
1689 | popup(popup_rect); |
1690 | } |
1691 | |
1692 | void Window::(const Rect2i &p_screen_rect) { |
1693 | ERR_MAIN_THREAD_GUARD; |
1694 | emit_signal(SNAME("about_to_popup" )); |
1695 | |
1696 | if (!get_embedder() && get_flag(FLAG_POPUP)) { |
1697 | // Send a focus-out notification when opening a Window Manager Popup. |
1698 | SceneTree *scene_tree = get_tree(); |
1699 | if (scene_tree) { |
1700 | scene_tree->notify_group_flags(SceneTree::GROUP_CALL_DEFERRED, "_viewports" , NOTIFICATION_WM_WINDOW_FOCUS_OUT); |
1701 | } |
1702 | } |
1703 | |
1704 | // Update window size to calculate the actual window size based on contents minimum size and minimum size. |
1705 | _update_window_size(); |
1706 | |
1707 | if (p_screen_rect != Rect2i()) { |
1708 | set_position(p_screen_rect.position); |
1709 | set_size(p_screen_rect.size); |
1710 | } |
1711 | |
1712 | Rect2i adjust = _popup_adjust_rect(); |
1713 | if (adjust != Rect2i()) { |
1714 | set_position(adjust.position); |
1715 | set_size(adjust.size); |
1716 | } |
1717 | |
1718 | int scr = DisplayServer::get_singleton()->get_screen_count(); |
1719 | for (int i = 0; i < scr; i++) { |
1720 | Rect2i r = DisplayServer::get_singleton()->screen_get_usable_rect(i); |
1721 | if (r.has_point(position)) { |
1722 | current_screen = i; |
1723 | break; |
1724 | } |
1725 | } |
1726 | |
1727 | set_transient(true); |
1728 | set_visible(true); |
1729 | |
1730 | Rect2i parent_rect; |
1731 | if (is_embedded()) { |
1732 | parent_rect = get_embedder()->get_visible_rect(); |
1733 | } else { |
1734 | int screen_id = DisplayServer::get_singleton()->window_get_current_screen(get_window_id()); |
1735 | parent_rect = DisplayServer::get_singleton()->screen_get_usable_rect(screen_id); |
1736 | } |
1737 | if (parent_rect != Rect2i() && !parent_rect.intersects(Rect2i(position, size))) { |
1738 | ERR_PRINT(vformat("Window %d spawned at invalid position: %s." , get_window_id(), position)); |
1739 | set_position((parent_rect.size - size) / 2); |
1740 | } |
1741 | if (parent_rect != Rect2i() && is_clamped_to_embedder() && is_embedded()) { |
1742 | Rect2i new_rect = fit_rect_in_parent(Rect2i(position, size), parent_rect); |
1743 | set_position(new_rect.position); |
1744 | set_size(new_rect.size); |
1745 | } |
1746 | |
1747 | _post_popup(); |
1748 | notification(NOTIFICATION_POST_POPUP); |
1749 | } |
1750 | |
1751 | bool Window::_try_parent_dialog(Node *p_from_node) { |
1752 | ERR_FAIL_NULL_V(p_from_node, false); |
1753 | ERR_FAIL_COND_V_MSG(is_inside_tree(), false, "Attempting to parent and popup a dialog that already has a parent." ); |
1754 | |
1755 | Window *w = p_from_node->get_last_exclusive_window(); |
1756 | if (w && w != this) { |
1757 | w->add_child(this); |
1758 | return true; |
1759 | } |
1760 | return false; |
1761 | } |
1762 | |
1763 | void Window::(Node *p_from_node, const Rect2i &p_screen_rect) { |
1764 | if (_try_parent_dialog(p_from_node)) { |
1765 | popup(p_screen_rect); |
1766 | } |
1767 | } |
1768 | |
1769 | void Window::(Node *p_from_node, const Rect2i &p_parent_rect) { |
1770 | if (_try_parent_dialog(p_from_node)) { |
1771 | popup_on_parent(p_parent_rect); |
1772 | } |
1773 | } |
1774 | |
1775 | void Window::(Node *p_from_node, const Size2i &p_minsize) { |
1776 | if (_try_parent_dialog(p_from_node)) { |
1777 | popup_centered(p_minsize); |
1778 | } |
1779 | } |
1780 | |
1781 | void Window::(Node *p_from_node, float p_ratio) { |
1782 | if (_try_parent_dialog(p_from_node)) { |
1783 | popup_centered_ratio(p_ratio); |
1784 | } |
1785 | } |
1786 | |
1787 | void Window::(Node *p_from_node, const Size2i &p_size, float p_fallback_ratio) { |
1788 | if (_try_parent_dialog(p_from_node)) { |
1789 | popup_centered_clamped(p_size, p_fallback_ratio); |
1790 | } |
1791 | } |
1792 | |
1793 | Rect2i Window::fit_rect_in_parent(Rect2i p_rect, const Rect2i &p_parent_rect) const { |
1794 | ERR_READ_THREAD_GUARD_V(Rect2i()); |
1795 | Size2i limit = p_parent_rect.size; |
1796 | if (p_rect.position.x + p_rect.size.x > limit.x) { |
1797 | p_rect.position.x = limit.x - p_rect.size.x; |
1798 | } |
1799 | if (p_rect.position.y + p_rect.size.y > limit.y) { |
1800 | p_rect.position.y = limit.y - p_rect.size.y; |
1801 | } |
1802 | |
1803 | if (p_rect.position.x < 0) { |
1804 | p_rect.position.x = 0; |
1805 | } |
1806 | |
1807 | int title_height = get_flag(Window::FLAG_BORDERLESS) ? 0 : theme_cache.title_height; |
1808 | |
1809 | if (p_rect.position.y < title_height) { |
1810 | p_rect.position.y = title_height; |
1811 | } |
1812 | |
1813 | return p_rect; |
1814 | } |
1815 | |
1816 | Size2 Window::get_contents_minimum_size() const { |
1817 | ERR_READ_THREAD_GUARD_V(Size2()); |
1818 | Vector2 ms; |
1819 | if (GDVIRTUAL_CALL(_get_contents_minimum_size, ms)) { |
1820 | return ms; |
1821 | } |
1822 | return _get_contents_minimum_size(); |
1823 | } |
1824 | |
1825 | Size2 Window::get_clamped_minimum_size() const { |
1826 | ERR_READ_THREAD_GUARD_V(Size2()); |
1827 | if (!wrap_controls) { |
1828 | return min_size; |
1829 | } |
1830 | |
1831 | return min_size.max(get_contents_minimum_size()); |
1832 | } |
1833 | |
1834 | void Window::grab_focus() { |
1835 | ERR_MAIN_THREAD_GUARD; |
1836 | if (embedder) { |
1837 | embedder->_sub_window_grab_focus(this); |
1838 | } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { |
1839 | DisplayServer::get_singleton()->window_move_to_foreground(window_id); |
1840 | } |
1841 | } |
1842 | |
1843 | bool Window::has_focus() const { |
1844 | ERR_READ_THREAD_GUARD_V(false); |
1845 | if (window_id != DisplayServer::INVALID_WINDOW_ID) { |
1846 | return DisplayServer::get_singleton()->window_is_focused(window_id); |
1847 | } |
1848 | return focused; |
1849 | } |
1850 | |
1851 | Rect2i Window::get_usable_parent_rect() const { |
1852 | ERR_READ_THREAD_GUARD_V(Rect2i()); |
1853 | ERR_FAIL_COND_V(!is_inside_tree(), Rect2()); |
1854 | Rect2i parent_rect; |
1855 | if (is_embedded()) { |
1856 | parent_rect = get_embedder()->get_visible_rect(); |
1857 | } else { |
1858 | const Window *w = is_visible() ? this : get_parent_visible_window(); |
1859 | //find a parent that can contain us |
1860 | ERR_FAIL_NULL_V(w, Rect2()); |
1861 | |
1862 | parent_rect = DisplayServer::get_singleton()->screen_get_usable_rect(DisplayServer::get_singleton()->window_get_current_screen(w->get_window_id())); |
1863 | } |
1864 | return parent_rect; |
1865 | } |
1866 | |
1867 | void Window::add_child_notify(Node *p_child) { |
1868 | if (is_inside_tree() && wrap_controls) { |
1869 | child_controls_changed(); |
1870 | } |
1871 | } |
1872 | |
1873 | void Window::remove_child_notify(Node *p_child) { |
1874 | if (is_inside_tree() && wrap_controls) { |
1875 | child_controls_changed(); |
1876 | } |
1877 | } |
1878 | |
1879 | // Theming. |
1880 | |
1881 | void Window::set_theme_owner_node(Node *p_node) { |
1882 | ERR_MAIN_THREAD_GUARD; |
1883 | theme_owner->set_owner_node(p_node); |
1884 | } |
1885 | |
1886 | Node *Window::get_theme_owner_node() const { |
1887 | ERR_READ_THREAD_GUARD_V(nullptr); |
1888 | return theme_owner->get_owner_node(); |
1889 | } |
1890 | |
1891 | bool Window::has_theme_owner_node() const { |
1892 | ERR_READ_THREAD_GUARD_V(false); |
1893 | return theme_owner->has_owner_node(); |
1894 | } |
1895 | |
1896 | void Window::set_theme_context(ThemeContext *p_context, bool p_propagate) { |
1897 | ERR_MAIN_THREAD_GUARD; |
1898 | theme_owner->set_owner_context(p_context, p_propagate); |
1899 | } |
1900 | |
1901 | void Window::set_theme(const Ref<Theme> &p_theme) { |
1902 | ERR_MAIN_THREAD_GUARD; |
1903 | if (theme == p_theme) { |
1904 | return; |
1905 | } |
1906 | |
1907 | if (theme.is_valid()) { |
1908 | theme->disconnect_changed(callable_mp(this, &Window::_theme_changed)); |
1909 | } |
1910 | |
1911 | theme = p_theme; |
1912 | if (theme.is_valid()) { |
1913 | theme_owner->propagate_theme_changed(this, this, is_inside_tree(), true); |
1914 | theme->connect_changed(callable_mp(this, &Window::_theme_changed), CONNECT_DEFERRED); |
1915 | return; |
1916 | } |
1917 | |
1918 | Control *parent_c = Object::cast_to<Control>(get_parent()); |
1919 | if (parent_c && parent_c->has_theme_owner_node()) { |
1920 | theme_owner->propagate_theme_changed(this, parent_c->get_theme_owner_node(), is_inside_tree(), true); |
1921 | return; |
1922 | } |
1923 | |
1924 | Window *parent_w = cast_to<Window>(get_parent()); |
1925 | if (parent_w && parent_w->has_theme_owner_node()) { |
1926 | theme_owner->propagate_theme_changed(this, parent_w->get_theme_owner_node(), is_inside_tree(), true); |
1927 | return; |
1928 | } |
1929 | |
1930 | theme_owner->propagate_theme_changed(this, nullptr, is_inside_tree(), true); |
1931 | } |
1932 | |
1933 | Ref<Theme> Window::get_theme() const { |
1934 | ERR_READ_THREAD_GUARD_V(Ref<Theme>()); |
1935 | return theme; |
1936 | } |
1937 | |
1938 | void Window::_theme_changed() { |
1939 | if (is_inside_tree()) { |
1940 | theme_owner->propagate_theme_changed(this, this, true, false); |
1941 | } |
1942 | } |
1943 | |
1944 | void Window::_notify_theme_override_changed() { |
1945 | if (!bulk_theme_override && is_inside_tree()) { |
1946 | notification(NOTIFICATION_THEME_CHANGED); |
1947 | } |
1948 | } |
1949 | |
1950 | void Window::_invalidate_theme_cache() { |
1951 | theme_icon_cache.clear(); |
1952 | theme_style_cache.clear(); |
1953 | theme_font_cache.clear(); |
1954 | theme_font_size_cache.clear(); |
1955 | theme_color_cache.clear(); |
1956 | theme_constant_cache.clear(); |
1957 | } |
1958 | |
1959 | void Window::_update_theme_item_cache() { |
1960 | // Request an update on the next frame to reflect theme changes. |
1961 | // Updating without a delay can cause a lot of lag. |
1962 | if (!wrap_controls) { |
1963 | updating_embedded_window = true; |
1964 | call_deferred(SNAME("_update_embedded_window" )); |
1965 | } else { |
1966 | child_controls_changed(); |
1967 | } |
1968 | |
1969 | ThemeDB::get_singleton()->update_class_instance_items(this); |
1970 | } |
1971 | |
1972 | void Window::_update_embedded_window() { |
1973 | if (!updating_embedded_window) { |
1974 | return; |
1975 | } |
1976 | |
1977 | if (embedder) { |
1978 | embedder->_sub_window_update(this); |
1979 | }; |
1980 | |
1981 | updating_embedded_window = false; |
1982 | } |
1983 | |
1984 | void Window::set_theme_type_variation(const StringName &p_theme_type) { |
1985 | ERR_MAIN_THREAD_GUARD; |
1986 | theme_type_variation = p_theme_type; |
1987 | if (is_inside_tree()) { |
1988 | notification(NOTIFICATION_THEME_CHANGED); |
1989 | } |
1990 | } |
1991 | |
1992 | StringName Window::get_theme_type_variation() const { |
1993 | ERR_READ_THREAD_GUARD_V(StringName()); |
1994 | return theme_type_variation; |
1995 | } |
1996 | |
1997 | /// Theme property lookup. |
1998 | |
1999 | Ref<Texture2D> Window::get_theme_icon(const StringName &p_name, const StringName &p_theme_type) const { |
2000 | ERR_READ_THREAD_GUARD_V(Ref<Texture2D>()); |
2001 | if (!initialized) { |
2002 | WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED" ); |
2003 | } |
2004 | |
2005 | if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) { |
2006 | const Ref<Texture2D> *tex = theme_icon_override.getptr(p_name); |
2007 | if (tex) { |
2008 | return *tex; |
2009 | } |
2010 | } |
2011 | |
2012 | if (theme_icon_cache.has(p_theme_type) && theme_icon_cache[p_theme_type].has(p_name)) { |
2013 | return theme_icon_cache[p_theme_type][p_name]; |
2014 | } |
2015 | |
2016 | List<StringName> theme_types; |
2017 | theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); |
2018 | Ref<Texture2D> icon = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_ICON, p_name, theme_types); |
2019 | theme_icon_cache[p_theme_type][p_name] = icon; |
2020 | return icon; |
2021 | } |
2022 | |
2023 | Ref<StyleBox> Window::get_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const { |
2024 | ERR_READ_THREAD_GUARD_V(Ref<StyleBox>()); |
2025 | if (!initialized) { |
2026 | WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED" ); |
2027 | } |
2028 | |
2029 | if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) { |
2030 | const Ref<StyleBox> *style = theme_style_override.getptr(p_name); |
2031 | if (style) { |
2032 | return *style; |
2033 | } |
2034 | } |
2035 | |
2036 | if (theme_style_cache.has(p_theme_type) && theme_style_cache[p_theme_type].has(p_name)) { |
2037 | return theme_style_cache[p_theme_type][p_name]; |
2038 | } |
2039 | |
2040 | List<StringName> theme_types; |
2041 | theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); |
2042 | Ref<StyleBox> style = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_STYLEBOX, p_name, theme_types); |
2043 | theme_style_cache[p_theme_type][p_name] = style; |
2044 | return style; |
2045 | } |
2046 | |
2047 | Ref<Font> Window::get_theme_font(const StringName &p_name, const StringName &p_theme_type) const { |
2048 | ERR_READ_THREAD_GUARD_V(Ref<Font>()); |
2049 | if (!initialized) { |
2050 | WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED" ); |
2051 | } |
2052 | |
2053 | if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) { |
2054 | const Ref<Font> *font = theme_font_override.getptr(p_name); |
2055 | if (font) { |
2056 | return *font; |
2057 | } |
2058 | } |
2059 | |
2060 | if (theme_font_cache.has(p_theme_type) && theme_font_cache[p_theme_type].has(p_name)) { |
2061 | return theme_font_cache[p_theme_type][p_name]; |
2062 | } |
2063 | |
2064 | List<StringName> theme_types; |
2065 | theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); |
2066 | Ref<Font> font = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_FONT, p_name, theme_types); |
2067 | theme_font_cache[p_theme_type][p_name] = font; |
2068 | return font; |
2069 | } |
2070 | |
2071 | int Window::get_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const { |
2072 | ERR_READ_THREAD_GUARD_V(0); |
2073 | if (!initialized) { |
2074 | WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED" ); |
2075 | } |
2076 | |
2077 | if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) { |
2078 | const int *font_size = theme_font_size_override.getptr(p_name); |
2079 | if (font_size && (*font_size) > 0) { |
2080 | return *font_size; |
2081 | } |
2082 | } |
2083 | |
2084 | if (theme_font_size_cache.has(p_theme_type) && theme_font_size_cache[p_theme_type].has(p_name)) { |
2085 | return theme_font_size_cache[p_theme_type][p_name]; |
2086 | } |
2087 | |
2088 | List<StringName> theme_types; |
2089 | theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); |
2090 | int font_size = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types); |
2091 | theme_font_size_cache[p_theme_type][p_name] = font_size; |
2092 | return font_size; |
2093 | } |
2094 | |
2095 | Color Window::get_theme_color(const StringName &p_name, const StringName &p_theme_type) const { |
2096 | ERR_READ_THREAD_GUARD_V(Color()); |
2097 | if (!initialized) { |
2098 | WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED" ); |
2099 | } |
2100 | |
2101 | if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) { |
2102 | const Color *color = theme_color_override.getptr(p_name); |
2103 | if (color) { |
2104 | return *color; |
2105 | } |
2106 | } |
2107 | |
2108 | if (theme_color_cache.has(p_theme_type) && theme_color_cache[p_theme_type].has(p_name)) { |
2109 | return theme_color_cache[p_theme_type][p_name]; |
2110 | } |
2111 | |
2112 | List<StringName> theme_types; |
2113 | theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); |
2114 | Color color = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_COLOR, p_name, theme_types); |
2115 | theme_color_cache[p_theme_type][p_name] = color; |
2116 | return color; |
2117 | } |
2118 | |
2119 | int Window::get_theme_constant(const StringName &p_name, const StringName &p_theme_type) const { |
2120 | ERR_READ_THREAD_GUARD_V(0); |
2121 | if (!initialized) { |
2122 | WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED" ); |
2123 | } |
2124 | |
2125 | if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) { |
2126 | const int *constant = theme_constant_override.getptr(p_name); |
2127 | if (constant) { |
2128 | return *constant; |
2129 | } |
2130 | } |
2131 | |
2132 | if (theme_constant_cache.has(p_theme_type) && theme_constant_cache[p_theme_type].has(p_name)) { |
2133 | return theme_constant_cache[p_theme_type][p_name]; |
2134 | } |
2135 | |
2136 | List<StringName> theme_types; |
2137 | theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); |
2138 | int constant = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_CONSTANT, p_name, theme_types); |
2139 | theme_constant_cache[p_theme_type][p_name] = constant; |
2140 | return constant; |
2141 | } |
2142 | |
2143 | Variant Window::get_theme_item(Theme::DataType p_data_type, const StringName &p_name, const StringName &p_theme_type) const { |
2144 | switch (p_data_type) { |
2145 | case Theme::DATA_TYPE_COLOR: |
2146 | return get_theme_color(p_name, p_theme_type); |
2147 | case Theme::DATA_TYPE_CONSTANT: |
2148 | return get_theme_constant(p_name, p_theme_type); |
2149 | case Theme::DATA_TYPE_FONT: |
2150 | return get_theme_font(p_name, p_theme_type); |
2151 | case Theme::DATA_TYPE_FONT_SIZE: |
2152 | return get_theme_font_size(p_name, p_theme_type); |
2153 | case Theme::DATA_TYPE_ICON: |
2154 | return get_theme_icon(p_name, p_theme_type); |
2155 | case Theme::DATA_TYPE_STYLEBOX: |
2156 | return get_theme_stylebox(p_name, p_theme_type); |
2157 | case Theme::DATA_TYPE_MAX: |
2158 | break; // Can't happen, but silences warning. |
2159 | } |
2160 | |
2161 | return Variant(); |
2162 | } |
2163 | |
2164 | #ifdef TOOLS_ENABLED |
2165 | Ref<Texture2D> Window::get_editor_theme_icon(const StringName &p_name) const { |
2166 | return get_theme_icon(p_name, SNAME("EditorIcons" )); |
2167 | } |
2168 | #endif |
2169 | |
2170 | bool Window::has_theme_icon(const StringName &p_name, const StringName &p_theme_type) const { |
2171 | ERR_READ_THREAD_GUARD_V(false); |
2172 | if (!initialized) { |
2173 | WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED" ); |
2174 | } |
2175 | |
2176 | if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) { |
2177 | if (has_theme_icon_override(p_name)) { |
2178 | return true; |
2179 | } |
2180 | } |
2181 | |
2182 | List<StringName> theme_types; |
2183 | theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); |
2184 | return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_ICON, p_name, theme_types); |
2185 | } |
2186 | |
2187 | bool Window::has_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const { |
2188 | ERR_READ_THREAD_GUARD_V(false); |
2189 | if (!initialized) { |
2190 | WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED" ); |
2191 | } |
2192 | |
2193 | if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) { |
2194 | if (has_theme_stylebox_override(p_name)) { |
2195 | return true; |
2196 | } |
2197 | } |
2198 | |
2199 | List<StringName> theme_types; |
2200 | theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); |
2201 | return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_STYLEBOX, p_name, theme_types); |
2202 | } |
2203 | |
2204 | bool Window::has_theme_font(const StringName &p_name, const StringName &p_theme_type) const { |
2205 | ERR_READ_THREAD_GUARD_V(false); |
2206 | if (!initialized) { |
2207 | WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED" ); |
2208 | } |
2209 | |
2210 | if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) { |
2211 | if (has_theme_font_override(p_name)) { |
2212 | return true; |
2213 | } |
2214 | } |
2215 | |
2216 | List<StringName> theme_types; |
2217 | theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); |
2218 | return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_FONT, p_name, theme_types); |
2219 | } |
2220 | |
2221 | bool Window::has_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const { |
2222 | ERR_READ_THREAD_GUARD_V(false); |
2223 | if (!initialized) { |
2224 | WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED" ); |
2225 | } |
2226 | |
2227 | if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) { |
2228 | if (has_theme_font_size_override(p_name)) { |
2229 | return true; |
2230 | } |
2231 | } |
2232 | |
2233 | List<StringName> theme_types; |
2234 | theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); |
2235 | return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types); |
2236 | } |
2237 | |
2238 | bool Window::has_theme_color(const StringName &p_name, const StringName &p_theme_type) const { |
2239 | ERR_READ_THREAD_GUARD_V(false); |
2240 | if (!initialized) { |
2241 | WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED" ); |
2242 | } |
2243 | |
2244 | if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) { |
2245 | if (has_theme_color_override(p_name)) { |
2246 | return true; |
2247 | } |
2248 | } |
2249 | |
2250 | List<StringName> theme_types; |
2251 | theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); |
2252 | return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_COLOR, p_name, theme_types); |
2253 | } |
2254 | |
2255 | bool Window::has_theme_constant(const StringName &p_name, const StringName &p_theme_type) const { |
2256 | ERR_READ_THREAD_GUARD_V(false); |
2257 | if (!initialized) { |
2258 | WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED" ); |
2259 | } |
2260 | |
2261 | if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) { |
2262 | if (has_theme_constant_override(p_name)) { |
2263 | return true; |
2264 | } |
2265 | } |
2266 | |
2267 | List<StringName> theme_types; |
2268 | theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); |
2269 | return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_CONSTANT, p_name, theme_types); |
2270 | } |
2271 | |
2272 | /// Local property overrides. |
2273 | |
2274 | void Window::add_theme_icon_override(const StringName &p_name, const Ref<Texture2D> &p_icon) { |
2275 | ERR_MAIN_THREAD_GUARD; |
2276 | ERR_FAIL_COND(!p_icon.is_valid()); |
2277 | |
2278 | if (theme_icon_override.has(p_name)) { |
2279 | theme_icon_override[p_name]->disconnect_changed(callable_mp(this, &Window::_notify_theme_override_changed)); |
2280 | } |
2281 | |
2282 | theme_icon_override[p_name] = p_icon; |
2283 | theme_icon_override[p_name]->connect_changed(callable_mp(this, &Window::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED); |
2284 | _notify_theme_override_changed(); |
2285 | } |
2286 | |
2287 | void Window::add_theme_style_override(const StringName &p_name, const Ref<StyleBox> &p_style) { |
2288 | ERR_MAIN_THREAD_GUARD; |
2289 | ERR_FAIL_COND(!p_style.is_valid()); |
2290 | |
2291 | if (theme_style_override.has(p_name)) { |
2292 | theme_style_override[p_name]->disconnect_changed(callable_mp(this, &Window::_notify_theme_override_changed)); |
2293 | } |
2294 | |
2295 | theme_style_override[p_name] = p_style; |
2296 | theme_style_override[p_name]->connect_changed(callable_mp(this, &Window::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED); |
2297 | _notify_theme_override_changed(); |
2298 | } |
2299 | |
2300 | void Window::add_theme_font_override(const StringName &p_name, const Ref<Font> &p_font) { |
2301 | ERR_MAIN_THREAD_GUARD; |
2302 | ERR_FAIL_COND(!p_font.is_valid()); |
2303 | |
2304 | if (theme_font_override.has(p_name)) { |
2305 | theme_font_override[p_name]->disconnect_changed(callable_mp(this, &Window::_notify_theme_override_changed)); |
2306 | } |
2307 | |
2308 | theme_font_override[p_name] = p_font; |
2309 | theme_font_override[p_name]->connect_changed(callable_mp(this, &Window::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED); |
2310 | _notify_theme_override_changed(); |
2311 | } |
2312 | |
2313 | void Window::add_theme_font_size_override(const StringName &p_name, int p_font_size) { |
2314 | ERR_MAIN_THREAD_GUARD; |
2315 | theme_font_size_override[p_name] = p_font_size; |
2316 | _notify_theme_override_changed(); |
2317 | } |
2318 | |
2319 | void Window::add_theme_color_override(const StringName &p_name, const Color &p_color) { |
2320 | ERR_MAIN_THREAD_GUARD; |
2321 | theme_color_override[p_name] = p_color; |
2322 | _notify_theme_override_changed(); |
2323 | } |
2324 | |
2325 | void Window::add_theme_constant_override(const StringName &p_name, int p_constant) { |
2326 | ERR_MAIN_THREAD_GUARD; |
2327 | theme_constant_override[p_name] = p_constant; |
2328 | _notify_theme_override_changed(); |
2329 | } |
2330 | |
2331 | void Window::remove_theme_icon_override(const StringName &p_name) { |
2332 | ERR_MAIN_THREAD_GUARD; |
2333 | if (theme_icon_override.has(p_name)) { |
2334 | theme_icon_override[p_name]->disconnect_changed(callable_mp(this, &Window::_notify_theme_override_changed)); |
2335 | } |
2336 | |
2337 | theme_icon_override.erase(p_name); |
2338 | _notify_theme_override_changed(); |
2339 | } |
2340 | |
2341 | void Window::remove_theme_style_override(const StringName &p_name) { |
2342 | ERR_MAIN_THREAD_GUARD; |
2343 | if (theme_style_override.has(p_name)) { |
2344 | theme_style_override[p_name]->disconnect_changed(callable_mp(this, &Window::_notify_theme_override_changed)); |
2345 | } |
2346 | |
2347 | theme_style_override.erase(p_name); |
2348 | _notify_theme_override_changed(); |
2349 | } |
2350 | |
2351 | void Window::remove_theme_font_override(const StringName &p_name) { |
2352 | ERR_MAIN_THREAD_GUARD; |
2353 | if (theme_font_override.has(p_name)) { |
2354 | theme_font_override[p_name]->disconnect_changed(callable_mp(this, &Window::_notify_theme_override_changed)); |
2355 | } |
2356 | |
2357 | theme_font_override.erase(p_name); |
2358 | _notify_theme_override_changed(); |
2359 | } |
2360 | |
2361 | void Window::remove_theme_font_size_override(const StringName &p_name) { |
2362 | ERR_MAIN_THREAD_GUARD; |
2363 | theme_font_size_override.erase(p_name); |
2364 | _notify_theme_override_changed(); |
2365 | } |
2366 | |
2367 | void Window::remove_theme_color_override(const StringName &p_name) { |
2368 | ERR_MAIN_THREAD_GUARD; |
2369 | theme_color_override.erase(p_name); |
2370 | _notify_theme_override_changed(); |
2371 | } |
2372 | |
2373 | void Window::remove_theme_constant_override(const StringName &p_name) { |
2374 | ERR_MAIN_THREAD_GUARD; |
2375 | theme_constant_override.erase(p_name); |
2376 | _notify_theme_override_changed(); |
2377 | } |
2378 | |
2379 | bool Window::has_theme_icon_override(const StringName &p_name) const { |
2380 | ERR_READ_THREAD_GUARD_V(false); |
2381 | const Ref<Texture2D> *tex = theme_icon_override.getptr(p_name); |
2382 | return tex != nullptr; |
2383 | } |
2384 | |
2385 | bool Window::has_theme_stylebox_override(const StringName &p_name) const { |
2386 | ERR_READ_THREAD_GUARD_V(false); |
2387 | const Ref<StyleBox> *style = theme_style_override.getptr(p_name); |
2388 | return style != nullptr; |
2389 | } |
2390 | |
2391 | bool Window::has_theme_font_override(const StringName &p_name) const { |
2392 | ERR_READ_THREAD_GUARD_V(false); |
2393 | const Ref<Font> *font = theme_font_override.getptr(p_name); |
2394 | return font != nullptr; |
2395 | } |
2396 | |
2397 | bool Window::has_theme_font_size_override(const StringName &p_name) const { |
2398 | ERR_READ_THREAD_GUARD_V(false); |
2399 | const int *font_size = theme_font_size_override.getptr(p_name); |
2400 | return font_size != nullptr; |
2401 | } |
2402 | |
2403 | bool Window::has_theme_color_override(const StringName &p_name) const { |
2404 | ERR_READ_THREAD_GUARD_V(false); |
2405 | const Color *color = theme_color_override.getptr(p_name); |
2406 | return color != nullptr; |
2407 | } |
2408 | |
2409 | bool Window::has_theme_constant_override(const StringName &p_name) const { |
2410 | ERR_READ_THREAD_GUARD_V(false); |
2411 | const int *constant = theme_constant_override.getptr(p_name); |
2412 | return constant != nullptr; |
2413 | } |
2414 | |
2415 | /// Default theme properties. |
2416 | |
2417 | float Window::get_theme_default_base_scale() const { |
2418 | ERR_READ_THREAD_GUARD_V(0); |
2419 | return theme_owner->get_theme_default_base_scale(); |
2420 | } |
2421 | |
2422 | Ref<Font> Window::get_theme_default_font() const { |
2423 | ERR_READ_THREAD_GUARD_V(Ref<Font>()); |
2424 | return theme_owner->get_theme_default_font(); |
2425 | } |
2426 | |
2427 | int Window::get_theme_default_font_size() const { |
2428 | ERR_READ_THREAD_GUARD_V(0); |
2429 | return theme_owner->get_theme_default_font_size(); |
2430 | } |
2431 | |
2432 | /// Bulk actions. |
2433 | |
2434 | void Window::begin_bulk_theme_override() { |
2435 | ERR_MAIN_THREAD_GUARD; |
2436 | bulk_theme_override = true; |
2437 | } |
2438 | |
2439 | void Window::end_bulk_theme_override() { |
2440 | ERR_MAIN_THREAD_GUARD; |
2441 | ERR_FAIL_COND(!bulk_theme_override); |
2442 | |
2443 | bulk_theme_override = false; |
2444 | _notify_theme_override_changed(); |
2445 | } |
2446 | |
2447 | // |
2448 | |
2449 | Rect2i Window::get_parent_rect() const { |
2450 | ERR_READ_THREAD_GUARD_V(Rect2i()); |
2451 | ERR_FAIL_COND_V(!is_inside_tree(), Rect2i()); |
2452 | if (is_embedded()) { |
2453 | //viewport |
2454 | Node *n = get_parent(); |
2455 | ERR_FAIL_NULL_V(n, Rect2i()); |
2456 | Viewport *p = n->get_viewport(); |
2457 | ERR_FAIL_NULL_V(p, Rect2i()); |
2458 | |
2459 | return p->get_visible_rect(); |
2460 | } else { |
2461 | int x = get_position().x; |
2462 | int closest_dist = 0x7FFFFFFF; |
2463 | Rect2i closest_rect; |
2464 | for (int i = 0; i < DisplayServer::get_singleton()->get_screen_count(); i++) { |
2465 | Rect2i s(DisplayServer::get_singleton()->screen_get_position(i), DisplayServer::get_singleton()->screen_get_size(i)); |
2466 | int d; |
2467 | if (x >= s.position.x && x < s.size.x) { |
2468 | //contained |
2469 | closest_rect = s; |
2470 | break; |
2471 | } else if (x < s.position.x) { |
2472 | d = s.position.x - x; |
2473 | } else { |
2474 | d = x - (s.position.x + s.size.x); |
2475 | } |
2476 | |
2477 | if (d < closest_dist) { |
2478 | closest_dist = d; |
2479 | closest_rect = s; |
2480 | } |
2481 | } |
2482 | return closest_rect; |
2483 | } |
2484 | } |
2485 | |
2486 | void Window::set_clamp_to_embedder(bool p_enable) { |
2487 | ERR_MAIN_THREAD_GUARD; |
2488 | clamp_to_embedder = p_enable; |
2489 | } |
2490 | |
2491 | bool Window::is_clamped_to_embedder() const { |
2492 | ERR_READ_THREAD_GUARD_V(false); |
2493 | return clamp_to_embedder; |
2494 | } |
2495 | |
2496 | void Window::set_unparent_when_invisible(bool p_unparent) { |
2497 | unparent_when_invisible = p_unparent; |
2498 | } |
2499 | |
2500 | void Window::set_layout_direction(Window::LayoutDirection p_direction) { |
2501 | ERR_MAIN_THREAD_GUARD; |
2502 | ERR_FAIL_INDEX((int)p_direction, 4); |
2503 | |
2504 | layout_dir = p_direction; |
2505 | propagate_notification(Control::NOTIFICATION_LAYOUT_DIRECTION_CHANGED); |
2506 | } |
2507 | |
2508 | Window::LayoutDirection Window::get_layout_direction() const { |
2509 | ERR_READ_THREAD_GUARD_V(LAYOUT_DIRECTION_INHERITED); |
2510 | return layout_dir; |
2511 | } |
2512 | |
2513 | bool Window::is_layout_rtl() const { |
2514 | ERR_READ_THREAD_GUARD_V(false); |
2515 | if (layout_dir == LAYOUT_DIRECTION_INHERITED) { |
2516 | if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction" ))) { |
2517 | return true; |
2518 | } |
2519 | Node *parent_node = get_parent(); |
2520 | while (parent_node) { |
2521 | Control *parent_control = Object::cast_to<Control>(parent_node); |
2522 | if (parent_control) { |
2523 | return parent_control->is_layout_rtl(); |
2524 | } |
2525 | |
2526 | Window *parent_window = Object::cast_to<Window>(parent_node); |
2527 | if (parent_window) { |
2528 | return parent_window->is_layout_rtl(); |
2529 | } |
2530 | parent_node = parent_node->get_parent(); |
2531 | } |
2532 | |
2533 | int root_dir = GLOBAL_GET(SNAME("internationalization/rendering/root_node_layout_direction" )); |
2534 | if (root_dir == 1) { |
2535 | return false; |
2536 | } else if (root_dir == 2) { |
2537 | return true; |
2538 | } else { |
2539 | String locale = TranslationServer::get_singleton()->get_tool_locale(); |
2540 | return TS->is_locale_right_to_left(locale); |
2541 | } |
2542 | } else if (layout_dir == LAYOUT_DIRECTION_LOCALE) { |
2543 | if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction" ))) { |
2544 | return true; |
2545 | } else { |
2546 | String locale = TranslationServer::get_singleton()->get_tool_locale(); |
2547 | return TS->is_locale_right_to_left(locale); |
2548 | } |
2549 | } else { |
2550 | return (layout_dir == LAYOUT_DIRECTION_RTL); |
2551 | } |
2552 | } |
2553 | |
2554 | void Window::set_auto_translate(bool p_enable) { |
2555 | ERR_MAIN_THREAD_GUARD; |
2556 | if (p_enable == auto_translate) { |
2557 | return; |
2558 | } |
2559 | |
2560 | auto_translate = p_enable; |
2561 | |
2562 | notification(MainLoop::NOTIFICATION_TRANSLATION_CHANGED); |
2563 | } |
2564 | |
2565 | bool Window::is_auto_translating() const { |
2566 | ERR_READ_THREAD_GUARD_V(false); |
2567 | return auto_translate; |
2568 | } |
2569 | |
2570 | Transform2D Window::get_final_transform() const { |
2571 | ERR_READ_THREAD_GUARD_V(Transform2D()); |
2572 | return window_transform * stretch_transform * global_canvas_transform; |
2573 | } |
2574 | |
2575 | Transform2D Window::get_screen_transform_internal(bool p_absolute_position) const { |
2576 | ERR_READ_THREAD_GUARD_V(Transform2D()); |
2577 | Transform2D embedder_transform; |
2578 | if (get_embedder()) { |
2579 | embedder_transform.translate_local(get_position()); |
2580 | embedder_transform = get_embedder()->get_screen_transform_internal(p_absolute_position) * embedder_transform; |
2581 | } else if (p_absolute_position) { |
2582 | embedder_transform.translate_local(get_position()); |
2583 | } |
2584 | return embedder_transform * get_final_transform(); |
2585 | } |
2586 | |
2587 | Transform2D Window::() const { |
2588 | ERR_READ_THREAD_GUARD_V(Transform2D()); |
2589 | if (is_embedding_subwindows()) { |
2590 | return Transform2D(); |
2591 | } |
2592 | Transform2D ; |
2593 | popup_base_transform.set_origin(get_position()); |
2594 | popup_base_transform *= get_final_transform(); |
2595 | if (get_embedder()) { |
2596 | return get_embedder()->get_popup_base_transform() * popup_base_transform; |
2597 | } |
2598 | return popup_base_transform; |
2599 | } |
2600 | |
2601 | bool Window::is_directly_attached_to_screen() const { |
2602 | if (get_embedder()) { |
2603 | return get_embedder()->is_directly_attached_to_screen(); |
2604 | } |
2605 | // Distinguish between the case that this is a native Window and not inside the tree. |
2606 | return is_inside_tree(); |
2607 | } |
2608 | |
2609 | bool Window::is_attached_in_viewport() const { |
2610 | return get_embedder(); |
2611 | } |
2612 | |
2613 | void Window::_update_mouse_over(Vector2 p_pos) { |
2614 | if (!mouse_in_window) { |
2615 | if (is_embedded()) { |
2616 | mouse_in_window = true; |
2617 | _propagate_window_notification(this, NOTIFICATION_WM_MOUSE_ENTER); |
2618 | } else { |
2619 | // Prevent update based on delayed InputEvents from DisplayServer. |
2620 | return; |
2621 | } |
2622 | } |
2623 | |
2624 | bool new_in = get_visible_rect().has_point(p_pos); |
2625 | if (new_in == gui.mouse_in_viewport) { |
2626 | if (new_in) { |
2627 | Viewport::_update_mouse_over(p_pos); |
2628 | } |
2629 | return; |
2630 | } |
2631 | |
2632 | if (new_in) { |
2633 | notification(NOTIFICATION_VP_MOUSE_ENTER); |
2634 | Viewport::_update_mouse_over(p_pos); |
2635 | } else { |
2636 | Viewport::_mouse_leave_viewport(); |
2637 | } |
2638 | } |
2639 | |
2640 | void Window::_mouse_leave_viewport() { |
2641 | Viewport::_mouse_leave_viewport(); |
2642 | if (is_embedded()) { |
2643 | mouse_in_window = false; |
2644 | _propagate_window_notification(this, NOTIFICATION_WM_MOUSE_EXIT); |
2645 | } |
2646 | } |
2647 | |
2648 | void Window::_bind_methods() { |
2649 | ClassDB::bind_method(D_METHOD("set_title" , "title" ), &Window::set_title); |
2650 | ClassDB::bind_method(D_METHOD("get_title" ), &Window::get_title); |
2651 | |
2652 | ClassDB::bind_method(D_METHOD("get_window_id" ), &Window::get_window_id); |
2653 | |
2654 | ClassDB::bind_method(D_METHOD("set_initial_position" , "initial_position" ), &Window::set_initial_position); |
2655 | ClassDB::bind_method(D_METHOD("get_initial_position" ), &Window::get_initial_position); |
2656 | |
2657 | ClassDB::bind_method(D_METHOD("set_current_screen" , "index" ), &Window::set_current_screen); |
2658 | ClassDB::bind_method(D_METHOD("get_current_screen" ), &Window::get_current_screen); |
2659 | |
2660 | ClassDB::bind_method(D_METHOD("set_position" , "position" ), &Window::set_position); |
2661 | ClassDB::bind_method(D_METHOD("get_position" ), &Window::get_position); |
2662 | ClassDB::bind_method(D_METHOD("move_to_center" ), &Window::move_to_center); |
2663 | |
2664 | ClassDB::bind_method(D_METHOD("set_size" , "size" ), &Window::set_size); |
2665 | ClassDB::bind_method(D_METHOD("get_size" ), &Window::get_size); |
2666 | ClassDB::bind_method(D_METHOD("reset_size" ), &Window::reset_size); |
2667 | |
2668 | ClassDB::bind_method(D_METHOD("get_position_with_decorations" ), &Window::get_position_with_decorations); |
2669 | ClassDB::bind_method(D_METHOD("get_size_with_decorations" ), &Window::get_size_with_decorations); |
2670 | |
2671 | ClassDB::bind_method(D_METHOD("set_max_size" , "max_size" ), &Window::set_max_size); |
2672 | ClassDB::bind_method(D_METHOD("get_max_size" ), &Window::get_max_size); |
2673 | |
2674 | ClassDB::bind_method(D_METHOD("set_min_size" , "min_size" ), &Window::set_min_size); |
2675 | ClassDB::bind_method(D_METHOD("get_min_size" ), &Window::get_min_size); |
2676 | |
2677 | ClassDB::bind_method(D_METHOD("set_mode" , "mode" ), &Window::set_mode); |
2678 | ClassDB::bind_method(D_METHOD("get_mode" ), &Window::get_mode); |
2679 | |
2680 | ClassDB::bind_method(D_METHOD("set_flag" , "flag" , "enabled" ), &Window::set_flag); |
2681 | ClassDB::bind_method(D_METHOD("get_flag" , "flag" ), &Window::get_flag); |
2682 | |
2683 | ClassDB::bind_method(D_METHOD("is_maximize_allowed" ), &Window::is_maximize_allowed); |
2684 | |
2685 | ClassDB::bind_method(D_METHOD("request_attention" ), &Window::request_attention); |
2686 | |
2687 | ClassDB::bind_method(D_METHOD("move_to_foreground" ), &Window::move_to_foreground); |
2688 | |
2689 | ClassDB::bind_method(D_METHOD("set_visible" , "visible" ), &Window::set_visible); |
2690 | ClassDB::bind_method(D_METHOD("is_visible" ), &Window::is_visible); |
2691 | |
2692 | ClassDB::bind_method(D_METHOD("hide" ), &Window::hide); |
2693 | ClassDB::bind_method(D_METHOD("show" ), &Window::show); |
2694 | |
2695 | ClassDB::bind_method(D_METHOD("set_transient" , "transient" ), &Window::set_transient); |
2696 | ClassDB::bind_method(D_METHOD("is_transient" ), &Window::is_transient); |
2697 | |
2698 | ClassDB::bind_method(D_METHOD("set_exclusive" , "exclusive" ), &Window::set_exclusive); |
2699 | ClassDB::bind_method(D_METHOD("is_exclusive" ), &Window::is_exclusive); |
2700 | |
2701 | ClassDB::bind_method(D_METHOD("set_unparent_when_invisible" , "unparent" ), &Window::set_unparent_when_invisible); |
2702 | |
2703 | ClassDB::bind_method(D_METHOD("can_draw" ), &Window::can_draw); |
2704 | ClassDB::bind_method(D_METHOD("has_focus" ), &Window::has_focus); |
2705 | ClassDB::bind_method(D_METHOD("grab_focus" ), &Window::grab_focus); |
2706 | |
2707 | ClassDB::bind_method(D_METHOD("set_ime_active" , "active" ), &Window::set_ime_active); |
2708 | ClassDB::bind_method(D_METHOD("set_ime_position" , "position" ), &Window::set_ime_position); |
2709 | |
2710 | ClassDB::bind_method(D_METHOD("is_embedded" ), &Window::is_embedded); |
2711 | |
2712 | ClassDB::bind_method(D_METHOD("get_contents_minimum_size" ), &Window::get_contents_minimum_size); |
2713 | |
2714 | ClassDB::bind_method(D_METHOD("set_content_scale_size" , "size" ), &Window::set_content_scale_size); |
2715 | ClassDB::bind_method(D_METHOD("get_content_scale_size" ), &Window::get_content_scale_size); |
2716 | |
2717 | ClassDB::bind_method(D_METHOD("set_content_scale_mode" , "mode" ), &Window::set_content_scale_mode); |
2718 | ClassDB::bind_method(D_METHOD("get_content_scale_mode" ), &Window::get_content_scale_mode); |
2719 | |
2720 | ClassDB::bind_method(D_METHOD("set_content_scale_aspect" , "aspect" ), &Window::set_content_scale_aspect); |
2721 | ClassDB::bind_method(D_METHOD("get_content_scale_aspect" ), &Window::get_content_scale_aspect); |
2722 | |
2723 | ClassDB::bind_method(D_METHOD("set_content_scale_stretch" , "stretch" ), &Window::set_content_scale_stretch); |
2724 | ClassDB::bind_method(D_METHOD("get_content_scale_stretch" ), &Window::get_content_scale_stretch); |
2725 | |
2726 | ClassDB::bind_method(D_METHOD("set_content_scale_factor" , "factor" ), &Window::set_content_scale_factor); |
2727 | ClassDB::bind_method(D_METHOD("get_content_scale_factor" ), &Window::get_content_scale_factor); |
2728 | |
2729 | ClassDB::bind_method(D_METHOD("set_use_font_oversampling" , "enable" ), &Window::set_use_font_oversampling); |
2730 | ClassDB::bind_method(D_METHOD("is_using_font_oversampling" ), &Window::is_using_font_oversampling); |
2731 | |
2732 | ClassDB::bind_method(D_METHOD("set_mouse_passthrough_polygon" , "polygon" ), &Window::set_mouse_passthrough_polygon); |
2733 | ClassDB::bind_method(D_METHOD("get_mouse_passthrough_polygon" ), &Window::get_mouse_passthrough_polygon); |
2734 | |
2735 | ClassDB::bind_method(D_METHOD("set_wrap_controls" , "enable" ), &Window::set_wrap_controls); |
2736 | ClassDB::bind_method(D_METHOD("is_wrapping_controls" ), &Window::is_wrapping_controls); |
2737 | ClassDB::bind_method(D_METHOD("child_controls_changed" ), &Window::child_controls_changed); |
2738 | |
2739 | ClassDB::bind_method(D_METHOD("_update_child_controls" ), &Window::_update_child_controls); |
2740 | ClassDB::bind_method(D_METHOD("_update_embedded_window" ), &Window::_update_embedded_window); |
2741 | |
2742 | ClassDB::bind_method(D_METHOD("set_theme" , "theme" ), &Window::set_theme); |
2743 | ClassDB::bind_method(D_METHOD("get_theme" ), &Window::get_theme); |
2744 | |
2745 | ClassDB::bind_method(D_METHOD("set_theme_type_variation" , "theme_type" ), &Window::set_theme_type_variation); |
2746 | ClassDB::bind_method(D_METHOD("get_theme_type_variation" ), &Window::get_theme_type_variation); |
2747 | |
2748 | ClassDB::bind_method(D_METHOD("begin_bulk_theme_override" ), &Window::begin_bulk_theme_override); |
2749 | ClassDB::bind_method(D_METHOD("end_bulk_theme_override" ), &Window::end_bulk_theme_override); |
2750 | |
2751 | ClassDB::bind_method(D_METHOD("add_theme_icon_override" , "name" , "texture" ), &Window::add_theme_icon_override); |
2752 | ClassDB::bind_method(D_METHOD("add_theme_stylebox_override" , "name" , "stylebox" ), &Window::add_theme_style_override); |
2753 | ClassDB::bind_method(D_METHOD("add_theme_font_override" , "name" , "font" ), &Window::add_theme_font_override); |
2754 | ClassDB::bind_method(D_METHOD("add_theme_font_size_override" , "name" , "font_size" ), &Window::add_theme_font_size_override); |
2755 | ClassDB::bind_method(D_METHOD("add_theme_color_override" , "name" , "color" ), &Window::add_theme_color_override); |
2756 | ClassDB::bind_method(D_METHOD("add_theme_constant_override" , "name" , "constant" ), &Window::add_theme_constant_override); |
2757 | |
2758 | ClassDB::bind_method(D_METHOD("remove_theme_icon_override" , "name" ), &Window::remove_theme_icon_override); |
2759 | ClassDB::bind_method(D_METHOD("remove_theme_stylebox_override" , "name" ), &Window::remove_theme_style_override); |
2760 | ClassDB::bind_method(D_METHOD("remove_theme_font_override" , "name" ), &Window::remove_theme_font_override); |
2761 | ClassDB::bind_method(D_METHOD("remove_theme_font_size_override" , "name" ), &Window::remove_theme_font_size_override); |
2762 | ClassDB::bind_method(D_METHOD("remove_theme_color_override" , "name" ), &Window::remove_theme_color_override); |
2763 | ClassDB::bind_method(D_METHOD("remove_theme_constant_override" , "name" ), &Window::remove_theme_constant_override); |
2764 | |
2765 | ClassDB::bind_method(D_METHOD("get_theme_icon" , "name" , "theme_type" ), &Window::get_theme_icon, DEFVAL("" )); |
2766 | ClassDB::bind_method(D_METHOD("get_theme_stylebox" , "name" , "theme_type" ), &Window::get_theme_stylebox, DEFVAL("" )); |
2767 | ClassDB::bind_method(D_METHOD("get_theme_font" , "name" , "theme_type" ), &Window::get_theme_font, DEFVAL("" )); |
2768 | ClassDB::bind_method(D_METHOD("get_theme_font_size" , "name" , "theme_type" ), &Window::get_theme_font_size, DEFVAL("" )); |
2769 | ClassDB::bind_method(D_METHOD("get_theme_color" , "name" , "theme_type" ), &Window::get_theme_color, DEFVAL("" )); |
2770 | ClassDB::bind_method(D_METHOD("get_theme_constant" , "name" , "theme_type" ), &Window::get_theme_constant, DEFVAL("" )); |
2771 | |
2772 | ClassDB::bind_method(D_METHOD("has_theme_icon_override" , "name" ), &Window::has_theme_icon_override); |
2773 | ClassDB::bind_method(D_METHOD("has_theme_stylebox_override" , "name" ), &Window::has_theme_stylebox_override); |
2774 | ClassDB::bind_method(D_METHOD("has_theme_font_override" , "name" ), &Window::has_theme_font_override); |
2775 | ClassDB::bind_method(D_METHOD("has_theme_font_size_override" , "name" ), &Window::has_theme_font_size_override); |
2776 | ClassDB::bind_method(D_METHOD("has_theme_color_override" , "name" ), &Window::has_theme_color_override); |
2777 | ClassDB::bind_method(D_METHOD("has_theme_constant_override" , "name" ), &Window::has_theme_constant_override); |
2778 | |
2779 | ClassDB::bind_method(D_METHOD("has_theme_icon" , "name" , "theme_type" ), &Window::has_theme_icon, DEFVAL("" )); |
2780 | ClassDB::bind_method(D_METHOD("has_theme_stylebox" , "name" , "theme_type" ), &Window::has_theme_stylebox, DEFVAL("" )); |
2781 | ClassDB::bind_method(D_METHOD("has_theme_font" , "name" , "theme_type" ), &Window::has_theme_font, DEFVAL("" )); |
2782 | ClassDB::bind_method(D_METHOD("has_theme_font_size" , "name" , "theme_type" ), &Window::has_theme_font_size, DEFVAL("" )); |
2783 | ClassDB::bind_method(D_METHOD("has_theme_color" , "name" , "theme_type" ), &Window::has_theme_color, DEFVAL("" )); |
2784 | ClassDB::bind_method(D_METHOD("has_theme_constant" , "name" , "theme_type" ), &Window::has_theme_constant, DEFVAL("" )); |
2785 | |
2786 | ClassDB::bind_method(D_METHOD("get_theme_default_base_scale" ), &Window::get_theme_default_base_scale); |
2787 | ClassDB::bind_method(D_METHOD("get_theme_default_font" ), &Window::get_theme_default_font); |
2788 | ClassDB::bind_method(D_METHOD("get_theme_default_font_size" ), &Window::get_theme_default_font_size); |
2789 | |
2790 | ClassDB::bind_method(D_METHOD("set_layout_direction" , "direction" ), &Window::set_layout_direction); |
2791 | ClassDB::bind_method(D_METHOD("get_layout_direction" ), &Window::get_layout_direction); |
2792 | ClassDB::bind_method(D_METHOD("is_layout_rtl" ), &Window::is_layout_rtl); |
2793 | |
2794 | ClassDB::bind_method(D_METHOD("set_auto_translate" , "enable" ), &Window::set_auto_translate); |
2795 | ClassDB::bind_method(D_METHOD("is_auto_translating" ), &Window::is_auto_translating); |
2796 | |
2797 | ClassDB::bind_method(D_METHOD("popup" , "rect" ), &Window::popup, DEFVAL(Rect2i())); |
2798 | ClassDB::bind_method(D_METHOD("popup_on_parent" , "parent_rect" ), &Window::popup_on_parent); |
2799 | ClassDB::bind_method(D_METHOD("popup_centered" , "minsize" ), &Window::popup_centered, DEFVAL(Size2i())); |
2800 | ClassDB::bind_method(D_METHOD("popup_centered_ratio" , "ratio" ), &Window::popup_centered_ratio, DEFVAL(0.8)); |
2801 | ClassDB::bind_method(D_METHOD("popup_centered_clamped" , "minsize" , "fallback_ratio" ), &Window::popup_centered_clamped, DEFVAL(Size2i()), DEFVAL(0.75)); |
2802 | |
2803 | ClassDB::bind_method(D_METHOD("popup_exclusive" , "from_node" , "rect" ), &Window::popup_exclusive, DEFVAL(Rect2i())); |
2804 | ClassDB::bind_method(D_METHOD("popup_exclusive_on_parent" , "from_node" , "parent_rect" ), &Window::popup_exclusive_on_parent); |
2805 | ClassDB::bind_method(D_METHOD("popup_exclusive_centered" , "from_node" , "minsize" ), &Window::popup_exclusive_centered, DEFVAL(Size2i())); |
2806 | ClassDB::bind_method(D_METHOD("popup_exclusive_centered_ratio" , "from_node" , "ratio" ), &Window::popup_exclusive_centered_ratio, DEFVAL(0.8)); |
2807 | ClassDB::bind_method(D_METHOD("popup_exclusive_centered_clamped" , "from_node" , "minsize" , "fallback_ratio" ), &Window::popup_exclusive_centered_clamped, DEFVAL(Size2i()), DEFVAL(0.75)); |
2808 | |
2809 | // Keep the enum values in sync with the `Mode` enum. |
2810 | ADD_PROPERTY(PropertyInfo(Variant::INT, "mode" , PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,Fullscreen,Exclusive Fullscreen" ), "set_mode" , "get_mode" ); |
2811 | |
2812 | ADD_PROPERTY(PropertyInfo(Variant::STRING, "title" ), "set_title" , "get_title" ); |
2813 | |
2814 | // Keep the enum values in sync with the `WindowInitialPosition` enum. |
2815 | 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" ); |
2816 | ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "position" , PROPERTY_HINT_NONE, "suffix:px" ), "set_position" , "get_position" ); |
2817 | ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size" , PROPERTY_HINT_NONE, "suffix:px" ), "set_size" , "get_size" ); |
2818 | ADD_PROPERTY(PropertyInfo(Variant::INT, "current_screen" , PROPERTY_HINT_RANGE, "0,64,1,or_greater" ), "set_current_screen" , "get_current_screen" ); |
2819 | |
2820 | ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "mouse_passthrough_polygon" ), "set_mouse_passthrough_polygon" , "get_mouse_passthrough_polygon" ); |
2821 | |
2822 | ADD_GROUP("Flags" , "" ); |
2823 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible" ), "set_visible" , "is_visible" ); |
2824 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "wrap_controls" ), "set_wrap_controls" , "is_wrapping_controls" ); |
2825 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transient" ), "set_transient" , "is_transient" ); |
2826 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclusive" ), "set_exclusive" , "is_exclusive" ); |
2827 | ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "unresizable" ), "set_flag" , "get_flag" , FLAG_RESIZE_DISABLED); |
2828 | ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "borderless" ), "set_flag" , "get_flag" , FLAG_BORDERLESS); |
2829 | ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "always_on_top" ), "set_flag" , "get_flag" , FLAG_ALWAYS_ON_TOP); |
2830 | ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "transparent" ), "set_flag" , "get_flag" , FLAG_TRANSPARENT); |
2831 | ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "unfocusable" ), "set_flag" , "get_flag" , FLAG_NO_FOCUS); |
2832 | ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "popup_window" ), "set_flag" , "get_flag" , FLAG_POPUP); |
2833 | ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "extend_to_title" ), "set_flag" , "get_flag" , FLAG_EXTEND_TO_TITLE); |
2834 | ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "mouse_passthrough" ), "set_flag" , "get_flag" , FLAG_MOUSE_PASSTHROUGH); |
2835 | |
2836 | ADD_GROUP("Limits" , "" ); |
2837 | ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "min_size" , PROPERTY_HINT_NONE, "suffix:px" ), "set_min_size" , "get_min_size" ); |
2838 | ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "max_size" , PROPERTY_HINT_NONE, "suffix:px" ), "set_max_size" , "get_max_size" ); |
2839 | |
2840 | ADD_GROUP("Content Scale" , "content_scale_" ); |
2841 | ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "content_scale_size" ), "set_content_scale_size" , "get_content_scale_size" ); |
2842 | ADD_PROPERTY(PropertyInfo(Variant::INT, "content_scale_mode" , PROPERTY_HINT_ENUM, "Disabled,Canvas Items,Viewport" ), "set_content_scale_mode" , "get_content_scale_mode" ); |
2843 | 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" ); |
2844 | ADD_PROPERTY(PropertyInfo(Variant::INT, "content_scale_stretch" , PROPERTY_HINT_ENUM, "Fractional,Integer" ), "set_content_scale_stretch" , "get_content_scale_stretch" ); |
2845 | 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" ); |
2846 | |
2847 | ADD_GROUP("Localization" , "" ); |
2848 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_translate" ), "set_auto_translate" , "is_auto_translating" ); |
2849 | |
2850 | ADD_GROUP("Theme" , "theme_" ); |
2851 | ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "theme" , PROPERTY_HINT_RESOURCE_TYPE, "Theme" ), "set_theme" , "get_theme" ); |
2852 | ADD_PROPERTY(PropertyInfo(Variant::STRING, "theme_type_variation" , PROPERTY_HINT_ENUM_SUGGESTION), "set_theme_type_variation" , "get_theme_type_variation" ); |
2853 | |
2854 | ADD_SIGNAL(MethodInfo("window_input" , PropertyInfo(Variant::OBJECT, "event" , PROPERTY_HINT_RESOURCE_TYPE, "InputEvent" ))); |
2855 | ADD_SIGNAL(MethodInfo("files_dropped" , PropertyInfo(Variant::PACKED_STRING_ARRAY, "files" ))); |
2856 | ADD_SIGNAL(MethodInfo("mouse_entered" )); |
2857 | ADD_SIGNAL(MethodInfo("mouse_exited" )); |
2858 | ADD_SIGNAL(MethodInfo("focus_entered" )); |
2859 | ADD_SIGNAL(MethodInfo("focus_exited" )); |
2860 | ADD_SIGNAL(MethodInfo("close_requested" )); |
2861 | ADD_SIGNAL(MethodInfo("go_back_requested" )); |
2862 | ADD_SIGNAL(MethodInfo("visibility_changed" )); |
2863 | ADD_SIGNAL(MethodInfo("about_to_popup" )); |
2864 | ADD_SIGNAL(MethodInfo("theme_changed" )); |
2865 | ADD_SIGNAL(MethodInfo("dpi_changed" )); |
2866 | ADD_SIGNAL(MethodInfo("titlebar_changed" )); |
2867 | |
2868 | BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED); |
2869 | BIND_CONSTANT(NOTIFICATION_THEME_CHANGED); |
2870 | |
2871 | BIND_ENUM_CONSTANT(MODE_WINDOWED); |
2872 | BIND_ENUM_CONSTANT(MODE_MINIMIZED); |
2873 | BIND_ENUM_CONSTANT(MODE_MAXIMIZED); |
2874 | BIND_ENUM_CONSTANT(MODE_FULLSCREEN); |
2875 | BIND_ENUM_CONSTANT(MODE_EXCLUSIVE_FULLSCREEN); |
2876 | |
2877 | BIND_ENUM_CONSTANT(FLAG_RESIZE_DISABLED); |
2878 | BIND_ENUM_CONSTANT(FLAG_BORDERLESS); |
2879 | BIND_ENUM_CONSTANT(FLAG_ALWAYS_ON_TOP); |
2880 | BIND_ENUM_CONSTANT(FLAG_TRANSPARENT); |
2881 | BIND_ENUM_CONSTANT(FLAG_NO_FOCUS); |
2882 | BIND_ENUM_CONSTANT(FLAG_POPUP); |
2883 | BIND_ENUM_CONSTANT(FLAG_EXTEND_TO_TITLE); |
2884 | BIND_ENUM_CONSTANT(FLAG_MOUSE_PASSTHROUGH); |
2885 | BIND_ENUM_CONSTANT(FLAG_MAX); |
2886 | |
2887 | BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_DISABLED); |
2888 | BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_CANVAS_ITEMS); |
2889 | BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_VIEWPORT); |
2890 | |
2891 | BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_IGNORE); |
2892 | BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_KEEP); |
2893 | BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_KEEP_WIDTH); |
2894 | BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_KEEP_HEIGHT); |
2895 | BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_EXPAND); |
2896 | |
2897 | BIND_ENUM_CONSTANT(CONTENT_SCALE_STRETCH_FRACTIONAL); |
2898 | BIND_ENUM_CONSTANT(CONTENT_SCALE_STRETCH_INTEGER); |
2899 | |
2900 | BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_INHERITED); |
2901 | BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_LOCALE); |
2902 | BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_LTR); |
2903 | BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_RTL); |
2904 | |
2905 | BIND_ENUM_CONSTANT(WINDOW_INITIAL_POSITION_ABSOLUTE); |
2906 | BIND_ENUM_CONSTANT(WINDOW_INITIAL_POSITION_CENTER_PRIMARY_SCREEN); |
2907 | BIND_ENUM_CONSTANT(WINDOW_INITIAL_POSITION_CENTER_MAIN_WINDOW_SCREEN); |
2908 | BIND_ENUM_CONSTANT(WINDOW_INITIAL_POSITION_CENTER_OTHER_SCREEN); |
2909 | BIND_ENUM_CONSTANT(WINDOW_INITIAL_POSITION_CENTER_SCREEN_WITH_MOUSE_FOCUS); |
2910 | BIND_ENUM_CONSTANT(WINDOW_INITIAL_POSITION_CENTER_SCREEN_WITH_KEYBOARD_FOCUS); |
2911 | |
2912 | GDVIRTUAL_BIND(_get_contents_minimum_size); |
2913 | |
2914 | BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Window, embedded_border); |
2915 | BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Window, embedded_unfocused_border); |
2916 | |
2917 | BIND_THEME_ITEM(Theme::DATA_TYPE_FONT, Window, title_font); |
2918 | BIND_THEME_ITEM(Theme::DATA_TYPE_FONT_SIZE, Window, title_font_size); |
2919 | BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Window, title_color); |
2920 | BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Window, title_height); |
2921 | BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Window, title_outline_modulate); |
2922 | BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Window, title_outline_size); |
2923 | |
2924 | BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, Window, close); |
2925 | BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, Window, close_pressed); |
2926 | BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Window, close_h_offset); |
2927 | BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Window, close_v_offset); |
2928 | |
2929 | BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Window, resize_margin); |
2930 | } |
2931 | |
2932 | Window::Window() { |
2933 | RenderingServer *rendering_server = RenderingServer::get_singleton(); |
2934 | if (rendering_server) { |
2935 | max_size = rendering_server->get_maximum_viewport_size(); |
2936 | max_size_used = max_size; // Update max_size_used. |
2937 | } |
2938 | |
2939 | theme_owner = memnew(ThemeOwner(this)); |
2940 | RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED); |
2941 | } |
2942 | |
2943 | Window::~Window() { |
2944 | memdelete(theme_owner); |
2945 | |
2946 | // Resources need to be disconnected. |
2947 | for (KeyValue<StringName, Ref<Texture2D>> &E : theme_icon_override) { |
2948 | E.value->disconnect_changed(callable_mp(this, &Window::_notify_theme_override_changed)); |
2949 | } |
2950 | for (KeyValue<StringName, Ref<StyleBox>> &E : theme_style_override) { |
2951 | E.value->disconnect_changed(callable_mp(this, &Window::_notify_theme_override_changed)); |
2952 | } |
2953 | for (KeyValue<StringName, Ref<Font>> &E : theme_font_override) { |
2954 | E.value->disconnect_changed(callable_mp(this, &Window::_notify_theme_override_changed)); |
2955 | } |
2956 | |
2957 | // Then override maps can be simply cleared. |
2958 | theme_icon_override.clear(); |
2959 | theme_style_override.clear(); |
2960 | theme_font_override.clear(); |
2961 | theme_font_size_override.clear(); |
2962 | theme_color_override.clear(); |
2963 | theme_constant_override.clear(); |
2964 | } |
2965 | |