summaryrefslogtreecommitdiff
path: root/scene/main
diff options
context:
space:
mode:
Diffstat (limited to 'scene/main')
-rw-r--r--scene/main/SCsub2
-rw-r--r--scene/main/canvas_item.cpp1489
-rw-r--r--scene/main/canvas_item.h426
-rw-r--r--scene/main/canvas_layer.cpp36
-rw-r--r--scene/main/http_request.cpp8
-rw-r--r--scene/main/instance_placeholder.cpp10
-rw-r--r--scene/main/node.cpp145
-rw-r--r--scene/main/node.h26
-rw-r--r--scene/main/scene_tree.cpp433
-rw-r--r--scene/main/scene_tree.h60
-rw-r--r--scene/main/shader_globals_override.cpp257
-rw-r--r--scene/main/shader_globals_override.h37
-rw-r--r--[-rwxr-xr-x]scene/main/timer.cpp0
-rw-r--r--[-rwxr-xr-x]scene/main/timer.h0
-rw-r--r--scene/main/viewport.cpp2098
-rw-r--r--scene/main/viewport.h293
-rw-r--r--scene/main/window.cpp1406
-rw-r--r--scene/main/window.h265
18 files changed, 5503 insertions, 1488 deletions
diff --git a/scene/main/SCsub b/scene/main/SCsub
index b01e2fd54d..fc61250247 100644
--- a/scene/main/SCsub
+++ b/scene/main/SCsub
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.scene_sources, "*.cpp")
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
new file mode 100644
index 0000000000..2eacad68c3
--- /dev/null
+++ b/scene/main/canvas_item.cpp
@@ -0,0 +1,1489 @@
+/*************************************************************************/
+/* canvas_item.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "canvas_item.h"
+
+#include "core/input/input_filter.h"
+#include "core/message_queue.h"
+#include "core/method_bind_ext.gen.inc"
+#include "scene/main/canvas_layer.h"
+#include "scene/main/viewport.h"
+#include "scene/main/window.h"
+#include "scene/resources/font.h"
+#include "scene/resources/style_box.h"
+#include "scene/resources/texture.h"
+#include "scene/scene_string_names.h"
+#include "servers/rendering_server.h"
+
+Mutex CanvasItemMaterial::material_mutex;
+SelfList<CanvasItemMaterial>::List *CanvasItemMaterial::dirty_materials = nullptr;
+Map<CanvasItemMaterial::MaterialKey, CanvasItemMaterial::ShaderData> CanvasItemMaterial::shader_map;
+CanvasItemMaterial::ShaderNames *CanvasItemMaterial::shader_names = nullptr;
+
+void CanvasItemMaterial::init_shaders() {
+
+ dirty_materials = memnew(SelfList<CanvasItemMaterial>::List);
+
+ shader_names = memnew(ShaderNames);
+
+ shader_names->particles_anim_h_frames = "particles_anim_h_frames";
+ shader_names->particles_anim_v_frames = "particles_anim_v_frames";
+ shader_names->particles_anim_loop = "particles_anim_loop";
+}
+
+void CanvasItemMaterial::finish_shaders() {
+
+ memdelete(dirty_materials);
+ memdelete(shader_names);
+ dirty_materials = nullptr;
+}
+
+void CanvasItemMaterial::_update_shader() {
+
+ dirty_materials->remove(&element);
+
+ MaterialKey mk = _compute_key();
+ if (mk.key == current_key.key)
+ return; //no update required in the end
+
+ if (shader_map.has(current_key)) {
+ shader_map[current_key].users--;
+ if (shader_map[current_key].users == 0) {
+ //deallocate shader, as it's no longer in use
+ RS::get_singleton()->free(shader_map[current_key].shader);
+ shader_map.erase(current_key);
+ }
+ }
+
+ current_key = mk;
+
+ if (shader_map.has(mk)) {
+
+ RS::get_singleton()->material_set_shader(_get_material(), shader_map[mk].shader);
+ shader_map[mk].users++;
+ return;
+ }
+
+ //must create a shader!
+
+ String code = "shader_type canvas_item;\nrender_mode ";
+ switch (blend_mode) {
+ case BLEND_MODE_MIX: code += "blend_mix"; break;
+ case BLEND_MODE_ADD: code += "blend_add"; break;
+ case BLEND_MODE_SUB: code += "blend_sub"; break;
+ case BLEND_MODE_MUL: code += "blend_mul"; break;
+ case BLEND_MODE_PREMULT_ALPHA: code += "blend_premul_alpha"; break;
+ case BLEND_MODE_DISABLED: code += "blend_disabled"; break;
+ }
+
+ switch (light_mode) {
+ case LIGHT_MODE_NORMAL: break;
+ case LIGHT_MODE_UNSHADED: code += ",unshaded"; break;
+ case LIGHT_MODE_LIGHT_ONLY: code += ",light_only"; break;
+ }
+
+ code += ";\n";
+
+ if (particles_animation) {
+
+ code += "uniform int particles_anim_h_frames;\n";
+ code += "uniform int particles_anim_v_frames;\n";
+ code += "uniform bool particles_anim_loop;\n";
+
+ code += "void vertex() {\n";
+
+ code += "\tfloat h_frames = float(particles_anim_h_frames);\n";
+ code += "\tfloat v_frames = float(particles_anim_v_frames);\n";
+
+ code += "\tVERTEX.xy /= vec2(h_frames, v_frames);\n";
+
+ code += "\tfloat particle_total_frames = float(particles_anim_h_frames * particles_anim_v_frames);\n";
+ code += "\tfloat particle_frame = floor(INSTANCE_CUSTOM.z * float(particle_total_frames));\n";
+ code += "\tif (!particles_anim_loop) {\n";
+ code += "\t\tparticle_frame = clamp(particle_frame, 0.0, particle_total_frames - 1.0);\n";
+ code += "\t} else {\n";
+ code += "\t\tparticle_frame = mod(particle_frame, particle_total_frames);\n";
+ code += "\t}";
+ code += "\tUV /= vec2(h_frames, v_frames);\n";
+ code += "\tUV += vec2(mod(particle_frame, h_frames) / h_frames, floor(particle_frame / h_frames) / v_frames);\n";
+ code += "}\n";
+ }
+
+ ShaderData shader_data;
+ shader_data.shader = RS::get_singleton()->shader_create();
+ shader_data.users = 1;
+
+ RS::get_singleton()->shader_set_code(shader_data.shader, code);
+
+ shader_map[mk] = shader_data;
+
+ RS::get_singleton()->material_set_shader(_get_material(), shader_data.shader);
+}
+
+void CanvasItemMaterial::flush_changes() {
+
+ MutexLock lock(material_mutex);
+
+ while (dirty_materials->first()) {
+
+ dirty_materials->first()->self()->_update_shader();
+ }
+}
+
+void CanvasItemMaterial::_queue_shader_change() {
+
+ MutexLock lock(material_mutex);
+
+ if (!element.in_list()) {
+ dirty_materials->add(&element);
+ }
+}
+
+bool CanvasItemMaterial::_is_shader_dirty() const {
+
+ MutexLock lock(material_mutex);
+
+ return element.in_list();
+}
+void CanvasItemMaterial::set_blend_mode(BlendMode p_blend_mode) {
+
+ blend_mode = p_blend_mode;
+ _queue_shader_change();
+}
+
+CanvasItemMaterial::BlendMode CanvasItemMaterial::get_blend_mode() const {
+ return blend_mode;
+}
+
+void CanvasItemMaterial::set_light_mode(LightMode p_light_mode) {
+
+ light_mode = p_light_mode;
+ _queue_shader_change();
+}
+
+CanvasItemMaterial::LightMode CanvasItemMaterial::get_light_mode() const {
+
+ return light_mode;
+}
+
+void CanvasItemMaterial::set_particles_animation(bool p_particles_anim) {
+ particles_animation = p_particles_anim;
+ _queue_shader_change();
+ _change_notify();
+}
+
+bool CanvasItemMaterial::get_particles_animation() const {
+ return particles_animation;
+}
+
+void CanvasItemMaterial::set_particles_anim_h_frames(int p_frames) {
+
+ particles_anim_h_frames = p_frames;
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_h_frames, p_frames);
+}
+
+int CanvasItemMaterial::get_particles_anim_h_frames() const {
+
+ return particles_anim_h_frames;
+}
+void CanvasItemMaterial::set_particles_anim_v_frames(int p_frames) {
+
+ particles_anim_v_frames = p_frames;
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_v_frames, p_frames);
+}
+
+int CanvasItemMaterial::get_particles_anim_v_frames() const {
+
+ return particles_anim_v_frames;
+}
+
+void CanvasItemMaterial::set_particles_anim_loop(bool p_loop) {
+
+ particles_anim_loop = p_loop;
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_loop, particles_anim_loop);
+}
+
+bool CanvasItemMaterial::get_particles_anim_loop() const {
+
+ return particles_anim_loop;
+}
+
+void CanvasItemMaterial::_validate_property(PropertyInfo &property) const {
+ if (property.name.begins_with("particles_anim_") && !particles_animation) {
+ property.usage = 0;
+ }
+}
+
+RID CanvasItemMaterial::get_shader_rid() const {
+
+ ERR_FAIL_COND_V(!shader_map.has(current_key), RID());
+ return shader_map[current_key].shader;
+}
+
+Shader::Mode CanvasItemMaterial::get_shader_mode() const {
+
+ return Shader::MODE_CANVAS_ITEM;
+}
+
+void CanvasItemMaterial::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_blend_mode", "blend_mode"), &CanvasItemMaterial::set_blend_mode);
+ ClassDB::bind_method(D_METHOD("get_blend_mode"), &CanvasItemMaterial::get_blend_mode);
+
+ ClassDB::bind_method(D_METHOD("set_light_mode", "light_mode"), &CanvasItemMaterial::set_light_mode);
+ ClassDB::bind_method(D_METHOD("get_light_mode"), &CanvasItemMaterial::get_light_mode);
+
+ ClassDB::bind_method(D_METHOD("set_particles_animation", "particles_anim"), &CanvasItemMaterial::set_particles_animation);
+ ClassDB::bind_method(D_METHOD("get_particles_animation"), &CanvasItemMaterial::get_particles_animation);
+
+ ClassDB::bind_method(D_METHOD("set_particles_anim_h_frames", "frames"), &CanvasItemMaterial::set_particles_anim_h_frames);
+ ClassDB::bind_method(D_METHOD("get_particles_anim_h_frames"), &CanvasItemMaterial::get_particles_anim_h_frames);
+
+ ClassDB::bind_method(D_METHOD("set_particles_anim_v_frames", "frames"), &CanvasItemMaterial::set_particles_anim_v_frames);
+ ClassDB::bind_method(D_METHOD("get_particles_anim_v_frames"), &CanvasItemMaterial::get_particles_anim_v_frames);
+
+ ClassDB::bind_method(D_METHOD("set_particles_anim_loop", "loop"), &CanvasItemMaterial::set_particles_anim_loop);
+ ClassDB::bind_method(D_METHOD("get_particles_anim_loop"), &CanvasItemMaterial::get_particles_anim_loop);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul,Premult Alpha"), "set_blend_mode", "get_blend_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mode", PROPERTY_HINT_ENUM, "Normal,Unshaded,Light Only"), "set_light_mode", "get_light_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "particles_animation"), "set_particles_animation", "get_particles_animation");
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "particles_anim_h_frames", PROPERTY_HINT_RANGE, "1,128,1"), "set_particles_anim_h_frames", "get_particles_anim_h_frames");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "particles_anim_v_frames", PROPERTY_HINT_RANGE, "1,128,1"), "set_particles_anim_v_frames", "get_particles_anim_v_frames");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "particles_anim_loop"), "set_particles_anim_loop", "get_particles_anim_loop");
+
+ BIND_ENUM_CONSTANT(BLEND_MODE_MIX);
+ BIND_ENUM_CONSTANT(BLEND_MODE_ADD);
+ BIND_ENUM_CONSTANT(BLEND_MODE_SUB);
+ BIND_ENUM_CONSTANT(BLEND_MODE_MUL);
+ BIND_ENUM_CONSTANT(BLEND_MODE_PREMULT_ALPHA);
+
+ BIND_ENUM_CONSTANT(LIGHT_MODE_NORMAL);
+ BIND_ENUM_CONSTANT(LIGHT_MODE_UNSHADED);
+ BIND_ENUM_CONSTANT(LIGHT_MODE_LIGHT_ONLY);
+}
+
+CanvasItemMaterial::CanvasItemMaterial() :
+ element(this) {
+
+ blend_mode = BLEND_MODE_MIX;
+ light_mode = LIGHT_MODE_NORMAL;
+ particles_animation = false;
+
+ set_particles_anim_h_frames(1);
+ set_particles_anim_v_frames(1);
+ set_particles_anim_loop(false);
+
+ current_key.key = 0;
+ current_key.invalid_key = 1;
+ _queue_shader_change();
+}
+
+CanvasItemMaterial::~CanvasItemMaterial() {
+
+ MutexLock lock(material_mutex);
+
+ if (shader_map.has(current_key)) {
+ shader_map[current_key].users--;
+ if (shader_map[current_key].users == 0) {
+ //deallocate shader, as it's no longer in use
+ RS::get_singleton()->free(shader_map[current_key].shader);
+ shader_map.erase(current_key);
+ }
+
+ RS::get_singleton()->material_set_shader(_get_material(), RID());
+ }
+}
+
+///////////////////////////////////////////////////////////////////
+#ifdef TOOLS_ENABLED
+bool CanvasItem::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+ if (_edit_use_rect()) {
+ return _edit_get_rect().has_point(p_point);
+ } else {
+ return p_point.length() < p_tolerance;
+ }
+}
+
+Transform2D CanvasItem::_edit_get_transform() const {
+ return Transform2D(_edit_get_rotation(), _edit_get_position() + _edit_get_pivot());
+}
+#endif
+
+bool CanvasItem::is_visible_in_tree() const {
+
+ if (!is_inside_tree())
+ return false;
+
+ const CanvasItem *p = this;
+
+ while (p) {
+ if (!p->visible)
+ return false;
+ if (p->window && !p->window->is_visible()) {
+ return false;
+ }
+ p = p->get_parent_item();
+ }
+
+ return true;
+}
+
+void CanvasItem::_propagate_visibility_changed(bool p_visible) {
+
+ if (p_visible && first_draw) { //avoid propagating it twice
+ first_draw = false;
+ }
+ notification(NOTIFICATION_VISIBILITY_CHANGED);
+
+ if (p_visible)
+ update(); //todo optimize
+ else
+ emit_signal(SceneStringNames::get_singleton()->hide);
+ _block();
+
+ for (int i = 0; i < get_child_count(); i++) {
+
+ CanvasItem *c = Object::cast_to<CanvasItem>(get_child(i));
+
+ if (c && c->visible) //should the toplevels stop propagation? i think so but..
+ c->_propagate_visibility_changed(p_visible);
+ }
+
+ _unblock();
+}
+
+void CanvasItem::show() {
+
+ if (visible)
+ return;
+
+ visible = true;
+ RenderingServer::get_singleton()->canvas_item_set_visible(canvas_item, true);
+
+ if (!is_inside_tree())
+ return;
+
+ _propagate_visibility_changed(true);
+ _change_notify("visible");
+}
+
+void CanvasItem::hide() {
+
+ if (!visible)
+ return;
+
+ visible = false;
+ RenderingServer::get_singleton()->canvas_item_set_visible(canvas_item, false);
+
+ if (!is_inside_tree())
+ return;
+
+ _propagate_visibility_changed(false);
+ _change_notify("visible");
+}
+
+CanvasItem *CanvasItem::current_item_drawn = nullptr;
+CanvasItem *CanvasItem::get_current_item_drawn() {
+ return current_item_drawn;
+}
+
+void CanvasItem::_update_callback() {
+
+ if (!is_inside_tree()) {
+ pending_update = false;
+ return;
+ }
+
+ RenderingServer::get_singleton()->canvas_item_clear(get_canvas_item());
+ //todo updating = true - only allow drawing here
+ if (is_visible_in_tree()) { //todo optimize this!!
+ if (first_draw) {
+ notification(NOTIFICATION_VISIBILITY_CHANGED);
+ first_draw = false;
+ }
+ drawing = true;
+ current_item_drawn = this;
+ notification(NOTIFICATION_DRAW);
+ emit_signal(SceneStringNames::get_singleton()->draw);
+ if (get_script_instance()) {
+ get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_draw, nullptr, 0);
+ }
+ current_item_drawn = nullptr;
+ drawing = false;
+ }
+ //todo updating = false
+ pending_update = false; // don't change to false until finished drawing (avoid recursive update)
+}
+
+Transform2D CanvasItem::get_global_transform_with_canvas() const {
+
+ if (canvas_layer)
+ return canvas_layer->get_transform() * get_global_transform();
+ else if (is_inside_tree())
+ return get_viewport()->get_canvas_transform() * get_global_transform();
+ else
+ return get_global_transform();
+}
+
+Transform2D CanvasItem::get_screen_transform() const {
+ ERR_FAIL_COND_V(!is_inside_tree(), Transform2D());
+ Transform2D xform = get_global_transform_with_canvas();
+
+ Window *w = Object::cast_to<Window>(get_viewport());
+ if (w && !w->is_embedding_subwindows()) {
+ Transform2D s;
+ s.set_origin(w->get_position());
+
+ xform = s * xform;
+ }
+
+ return xform;
+}
+
+Transform2D CanvasItem::get_global_transform() const {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND_V(!is_inside_tree(), get_transform());
+#endif
+ if (global_invalid) {
+
+ const CanvasItem *pi = get_parent_item();
+ if (pi)
+ global_transform = pi->get_global_transform() * get_transform();
+ else
+ global_transform = get_transform();
+
+ global_invalid = false;
+ }
+
+ return global_transform;
+}
+
+void CanvasItem::_toplevel_raise_self() {
+
+ if (!is_inside_tree())
+ return;
+
+ if (canvas_layer)
+ RenderingServer::get_singleton()->canvas_item_set_draw_index(canvas_item, canvas_layer->get_sort_index());
+ else
+ RenderingServer::get_singleton()->canvas_item_set_draw_index(canvas_item, get_viewport()->gui_get_canvas_sort_index());
+}
+
+void CanvasItem::_enter_canvas() {
+
+ if ((!Object::cast_to<CanvasItem>(get_parent())) || toplevel) {
+
+ Node *n = this;
+
+ canvas_layer = nullptr;
+
+ while (n) {
+
+ canvas_layer = Object::cast_to<CanvasLayer>(n);
+ if (canvas_layer) {
+ break;
+ }
+ if (Object::cast_to<Viewport>(n)) {
+ break;
+ }
+ n = n->get_parent();
+ }
+
+ RID canvas;
+ if (canvas_layer)
+ canvas = canvas_layer->get_canvas();
+ else
+ canvas = get_viewport()->find_world_2d()->get_canvas();
+
+ RenderingServer::get_singleton()->canvas_item_set_parent(canvas_item, canvas);
+
+ group = "root_canvas" + itos(canvas.get_id());
+
+ add_to_group(group);
+ if (canvas_layer)
+ canvas_layer->reset_sort_index();
+ else
+ get_viewport()->gui_reset_canvas_sort_index();
+
+ get_tree()->call_group_flags(SceneTree::GROUP_CALL_UNIQUE, group, "_toplevel_raise_self");
+
+ } else {
+
+ CanvasItem *parent = get_parent_item();
+ canvas_layer = parent->canvas_layer;
+ RenderingServer::get_singleton()->canvas_item_set_parent(canvas_item, parent->get_canvas_item());
+ RenderingServer::get_singleton()->canvas_item_set_draw_index(canvas_item, get_index());
+ }
+
+ pending_update = false;
+ update();
+
+ notification(NOTIFICATION_ENTER_CANVAS);
+}
+
+void CanvasItem::_exit_canvas() {
+
+ notification(NOTIFICATION_EXIT_CANVAS, true); //reverse the notification
+ RenderingServer::get_singleton()->canvas_item_set_parent(canvas_item, RID());
+ canvas_layer = nullptr;
+ group = "";
+}
+
+void CanvasItem::_notification(int p_what) {
+
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+
+ _update_texture_filter_changed(false);
+ _update_texture_repeat_changed(false);
+
+ first_draw = true;
+ Node *parent = get_parent();
+ if (parent) {
+ CanvasItem *ci = Object::cast_to<CanvasItem>(parent);
+ if (ci)
+ C = ci->children_items.push_back(this);
+ if (!ci) {
+ //look for a window
+ Viewport *viewport = nullptr;
+
+ while (parent) {
+ viewport = Object::cast_to<Viewport>(parent);
+ if (viewport) {
+ break;
+ }
+ parent = parent->get_parent();
+ }
+
+ ERR_FAIL_COND(!viewport);
+
+ window = Object::cast_to<Window>(viewport);
+ if (window) {
+ window->connect(SceneStringNames::get_singleton()->visibility_changed, callable_mp(this, &CanvasItem::_window_visibility_changed));
+ }
+ }
+ }
+ _enter_canvas();
+ if (!block_transform_notify && !xform_change.in_list()) {
+ get_tree()->xform_change_list.add(&xform_change);
+ }
+ } break;
+ case NOTIFICATION_MOVED_IN_PARENT: {
+
+ if (!is_inside_tree())
+ break;
+
+ if (group != "") {
+ get_tree()->call_group_flags(SceneTree::GROUP_CALL_UNIQUE, group, "_toplevel_raise_self");
+ } else {
+ CanvasItem *p = get_parent_item();
+ ERR_FAIL_COND(!p);
+ RenderingServer::get_singleton()->canvas_item_set_draw_index(canvas_item, get_index());
+ }
+
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ if (xform_change.in_list())
+ get_tree()->xform_change_list.remove(&xform_change);
+ _exit_canvas();
+ if (C) {
+ Object::cast_to<CanvasItem>(get_parent())->children_items.erase(C);
+ C = nullptr;
+ }
+ if (window) {
+ window->disconnect(SceneStringNames::get_singleton()->visibility_changed, callable_mp(this, &CanvasItem::_window_visibility_changed));
+ }
+ global_invalid = true;
+ } break;
+ case NOTIFICATION_DRAW:
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+
+ } break;
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+
+ emit_signal(SceneStringNames::get_singleton()->visibility_changed);
+ } break;
+ }
+}
+
+void CanvasItem::set_visible(bool p_visible) {
+
+ if (p_visible)
+ show();
+ else
+ hide();
+}
+
+void CanvasItem::_window_visibility_changed() {
+
+ if (visible) {
+ _propagate_visibility_changed(window->is_visible());
+ }
+}
+
+bool CanvasItem::is_visible() const {
+
+ return visible;
+}
+
+void CanvasItem::update() {
+
+ if (!is_inside_tree())
+ return;
+ if (pending_update)
+ return;
+
+ pending_update = true;
+
+ MessageQueue::get_singleton()->push_call(this, "_update_callback");
+}
+
+void CanvasItem::set_modulate(const Color &p_modulate) {
+
+ if (modulate == p_modulate)
+ return;
+
+ modulate = p_modulate;
+ RenderingServer::get_singleton()->canvas_item_set_modulate(canvas_item, modulate);
+}
+Color CanvasItem::get_modulate() const {
+
+ return modulate;
+}
+
+void CanvasItem::set_as_toplevel(bool p_toplevel) {
+
+ if (toplevel == p_toplevel)
+ return;
+
+ if (!is_inside_tree()) {
+ toplevel = p_toplevel;
+ return;
+ }
+
+ _exit_canvas();
+ toplevel = p_toplevel;
+ _enter_canvas();
+}
+
+bool CanvasItem::is_set_as_toplevel() const {
+
+ return toplevel;
+}
+
+CanvasItem *CanvasItem::get_parent_item() const {
+
+ if (toplevel)
+ return nullptr;
+
+ return Object::cast_to<CanvasItem>(get_parent());
+}
+
+void CanvasItem::set_self_modulate(const Color &p_self_modulate) {
+
+ if (self_modulate == p_self_modulate)
+ return;
+
+ self_modulate = p_self_modulate;
+ RenderingServer::get_singleton()->canvas_item_set_self_modulate(canvas_item, self_modulate);
+}
+Color CanvasItem::get_self_modulate() const {
+
+ return self_modulate;
+}
+
+void CanvasItem::set_light_mask(int p_light_mask) {
+
+ if (light_mask == p_light_mask)
+ return;
+
+ light_mask = p_light_mask;
+ RS::get_singleton()->canvas_item_set_light_mask(canvas_item, p_light_mask);
+}
+
+int CanvasItem::get_light_mask() const {
+
+ return light_mask;
+}
+
+void CanvasItem::item_rect_changed(bool p_size_changed) {
+
+ if (p_size_changed)
+ update();
+ emit_signal(SceneStringNames::get_singleton()->item_rect_changed);
+}
+
+void CanvasItem::draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width) {
+
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ RenderingServer::get_singleton()->canvas_item_add_line(canvas_item, p_from, p_to, p_color, p_width);
+}
+
+void CanvasItem::draw_polyline(const Vector<Point2> &p_points, const Color &p_color, float p_width) {
+
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ Vector<Color> colors;
+ colors.push_back(p_color);
+ RenderingServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, colors, p_width);
+}
+
+void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) {
+
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ RenderingServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, p_colors, p_width);
+}
+
+void CanvasItem::draw_arc(const Vector2 &p_center, float p_radius, float p_start_angle, float p_end_angle, int p_point_count, const Color &p_color, float p_width) {
+
+ Vector<Point2> points;
+ points.resize(p_point_count);
+ const float delta_angle = p_end_angle - p_start_angle;
+ for (int i = 0; i < p_point_count; i++) {
+ float theta = (i / (p_point_count - 1.0f)) * delta_angle + p_start_angle;
+ points.set(i, p_center + Vector2(Math::cos(theta), Math::sin(theta)) * p_radius);
+ }
+
+ draw_polyline(points, p_color, p_width);
+}
+
+void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width) {
+
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ Vector<Color> colors;
+ colors.push_back(p_color);
+ RenderingServer::get_singleton()->canvas_item_add_multiline(canvas_item, p_points, colors, p_width);
+}
+
+void CanvasItem::draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) {
+
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ RenderingServer::get_singleton()->canvas_item_add_multiline(canvas_item, p_points, p_colors, p_width);
+}
+
+void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled, float p_width) {
+
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ if (p_filled) {
+ if (p_width != 1.0) {
+ WARN_PRINT("The draw_rect() \"width\" argument has no effect when \"filled\" is \"true\".");
+ }
+
+ RenderingServer::get_singleton()->canvas_item_add_rect(canvas_item, p_rect, p_color);
+ } else {
+ // Thick lines are offset depending on their width to avoid partial overlapping.
+ // Thin lines don't require an offset, so don't apply one in this case
+ float offset;
+ if (p_width >= 2) {
+ offset = p_width / 2.0;
+ } else {
+ offset = 0.0;
+ }
+
+ RenderingServer::get_singleton()->canvas_item_add_line(
+ canvas_item,
+ p_rect.position + Size2(-offset, 0),
+ p_rect.position + Size2(p_rect.size.width + offset, 0),
+ p_color,
+ p_width);
+ RenderingServer::get_singleton()->canvas_item_add_line(
+ canvas_item,
+ p_rect.position + Size2(p_rect.size.width, offset),
+ p_rect.position + Size2(p_rect.size.width, p_rect.size.height - offset),
+ p_color,
+ p_width);
+ RenderingServer::get_singleton()->canvas_item_add_line(
+ canvas_item,
+ p_rect.position + Size2(p_rect.size.width + offset, p_rect.size.height),
+ p_rect.position + Size2(-offset, p_rect.size.height),
+ p_color,
+ p_width);
+ RenderingServer::get_singleton()->canvas_item_add_line(
+ canvas_item,
+ p_rect.position + Size2(0, p_rect.size.height - offset),
+ p_rect.position + Size2(0, offset),
+ p_color,
+ p_width);
+ }
+}
+
+void CanvasItem::draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color) {
+
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ RenderingServer::get_singleton()->canvas_item_add_circle(canvas_item, p_pos, p_radius, p_color);
+}
+
+void CanvasItem::draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
+
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ ERR_FAIL_COND(p_texture.is_null());
+
+ p_texture->draw(canvas_item, p_pos, p_modulate, false, p_normal_map, p_specular_map, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat));
+}
+
+void CanvasItem::draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
+
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ ERR_FAIL_COND(p_texture.is_null());
+ p_texture->draw_rect(canvas_item, p_rect, p_tile, p_modulate, p_transpose, p_normal_map, p_specular_map, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat));
+}
+void CanvasItem::draw_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, bool p_clip_uv, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
+
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_FAIL_COND(p_texture.is_null());
+ p_texture->draw_rect_region(canvas_item, p_rect, p_src_rect, p_modulate, p_transpose, p_normal_map, p_specular_map, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat), p_clip_uv);
+}
+
+void CanvasItem::draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect) {
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ ERR_FAIL_COND(p_style_box.is_null());
+
+ p_style_box->draw(canvas_item, p_rect);
+}
+void CanvasItem::draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture, float p_width, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
+
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
+ RID rid_normal = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
+ RID rid_specular = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
+
+ RenderingServer::get_singleton()->canvas_item_add_primitive(canvas_item, p_points, p_colors, p_uvs, rid, p_width, rid_normal, rid_specular, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat));
+}
+void CanvasItem::draw_set_transform(const Point2 &p_offset, float p_rot, const Size2 &p_scale) {
+
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ Transform2D xform(p_rot, p_offset);
+ xform.scale_basis(p_scale);
+ RenderingServer::get_singleton()->canvas_item_add_set_transform(canvas_item, xform);
+}
+
+void CanvasItem::draw_set_transform_matrix(const Transform2D &p_matrix) {
+
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ RenderingServer::get_singleton()->canvas_item_add_set_transform(canvas_item, p_matrix);
+}
+
+void CanvasItem::draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
+
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
+ RID rid_normal = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
+ RID rid_specular = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
+
+ RenderingServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, p_colors, p_uvs, rid, rid_normal, rid_specular, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat));
+}
+
+void CanvasItem::draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
+
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ Vector<Color> colors;
+ colors.push_back(p_color);
+ RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
+ RID rid_normal = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
+ RID rid_specular = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
+
+ RenderingServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, colors, p_uvs, rid, rid_normal, rid_specular, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat));
+}
+
+void CanvasItem::draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, const Transform2D &p_transform, const Color &p_modulate, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
+
+ ERR_FAIL_COND(p_mesh.is_null());
+ RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
+ RID normal_map_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
+ RID specular_map_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
+
+ RenderingServer::get_singleton()->canvas_item_add_mesh(canvas_item, p_mesh->get_rid(), p_transform, p_modulate, texture_rid, normal_map_rid, specular_map_rid, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat));
+}
+void CanvasItem::draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
+
+ ERR_FAIL_COND(p_multimesh.is_null());
+ RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
+ RID normal_map_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
+ RID specular_map_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
+
+ RenderingServer::get_singleton()->canvas_item_add_multimesh(canvas_item, p_multimesh->get_rid(), texture_rid, normal_map_rid, specular_map_rid, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat));
+}
+
+void CanvasItem::draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, const Color &p_modulate, int p_clip_w) {
+
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ ERR_FAIL_COND(p_font.is_null());
+ p_font->draw(canvas_item, p_pos, p_text, p_modulate, p_clip_w);
+}
+
+float CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next, const Color &p_modulate) {
+
+ ERR_FAIL_COND_V_MSG(!drawing, 0, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ ERR_FAIL_COND_V(p_char.length() != 1, 0);
+ ERR_FAIL_COND_V(p_font.is_null(), 0);
+
+ if (p_font->has_outline()) {
+ p_font->draw_char(canvas_item, p_pos, p_char[0], p_next.c_str()[0], Color(1, 1, 1), true);
+ }
+ return p_font->draw_char(canvas_item, p_pos, p_char[0], p_next.c_str()[0], p_modulate);
+}
+
+void CanvasItem::_notify_transform(CanvasItem *p_node) {
+
+ /* This check exists to avoid re-propagating the transform
+ * notification down the tree on dirty nodes. It provides
+ * optimization by avoiding redundancy (nodes are dirty, will get the
+ * notification anyway).
+ */
+
+ if (/*p_node->xform_change.in_list() &&*/ p_node->global_invalid) {
+ return; //nothing to do
+ }
+
+ p_node->global_invalid = true;
+
+ if (p_node->notify_transform && !p_node->xform_change.in_list()) {
+ if (!p_node->block_transform_notify) {
+ if (p_node->is_inside_tree())
+ get_tree()->xform_change_list.add(&p_node->xform_change);
+ }
+ }
+
+ for (List<CanvasItem *>::Element *E = p_node->children_items.front(); E; E = E->next()) {
+
+ CanvasItem *ci = E->get();
+ if (ci->toplevel)
+ continue;
+ _notify_transform(ci);
+ }
+}
+
+Rect2 CanvasItem::get_viewport_rect() const {
+
+ ERR_FAIL_COND_V(!is_inside_tree(), Rect2());
+ return get_viewport()->get_visible_rect();
+}
+
+RID CanvasItem::get_canvas() const {
+
+ ERR_FAIL_COND_V(!is_inside_tree(), RID());
+
+ if (canvas_layer)
+ return canvas_layer->get_canvas();
+ else
+ return get_viewport()->find_world_2d()->get_canvas();
+}
+
+ObjectID CanvasItem::get_canvas_layer_instance_id() const {
+
+ if (canvas_layer) {
+ return canvas_layer->get_instance_id();
+ } else {
+ return ObjectID();
+ }
+}
+
+CanvasItem *CanvasItem::get_toplevel() const {
+
+ CanvasItem *ci = const_cast<CanvasItem *>(this);
+ while (!ci->toplevel && Object::cast_to<CanvasItem>(ci->get_parent())) {
+ ci = Object::cast_to<CanvasItem>(ci->get_parent());
+ }
+
+ return ci;
+}
+
+Ref<World2D> CanvasItem::get_world_2d() const {
+
+ ERR_FAIL_COND_V(!is_inside_tree(), Ref<World2D>());
+
+ CanvasItem *tl = get_toplevel();
+
+ if (tl->get_viewport()) {
+ return tl->get_viewport()->find_world_2d();
+ } else {
+ return Ref<World2D>();
+ }
+}
+
+RID CanvasItem::get_viewport_rid() const {
+
+ ERR_FAIL_COND_V(!is_inside_tree(), RID());
+ return get_viewport()->get_viewport_rid();
+}
+
+void CanvasItem::set_block_transform_notify(bool p_enable) {
+ block_transform_notify = p_enable;
+}
+
+bool CanvasItem::is_block_transform_notify_enabled() const {
+
+ return block_transform_notify;
+}
+
+void CanvasItem::set_draw_behind_parent(bool p_enable) {
+
+ if (behind == p_enable)
+ return;
+ behind = p_enable;
+ RenderingServer::get_singleton()->canvas_item_set_draw_behind_parent(canvas_item, behind);
+}
+
+bool CanvasItem::is_draw_behind_parent_enabled() const {
+
+ return behind;
+}
+
+void CanvasItem::set_material(const Ref<Material> &p_material) {
+
+ material = p_material;
+ RID rid;
+ if (material.is_valid())
+ rid = material->get_rid();
+ RS::get_singleton()->canvas_item_set_material(canvas_item, rid);
+ _change_notify(); //properties for material exposed
+}
+
+void CanvasItem::set_use_parent_material(bool p_use_parent_material) {
+
+ use_parent_material = p_use_parent_material;
+ RS::get_singleton()->canvas_item_set_use_parent_material(canvas_item, p_use_parent_material);
+}
+
+bool CanvasItem::get_use_parent_material() const {
+
+ return use_parent_material;
+}
+
+Ref<Material> CanvasItem::get_material() const {
+
+ return material;
+}
+
+Vector2 CanvasItem::make_canvas_position_local(const Vector2 &screen_point) const {
+
+ ERR_FAIL_COND_V(!is_inside_tree(), screen_point);
+
+ Transform2D local_matrix = (get_canvas_transform() * get_global_transform()).affine_inverse();
+
+ return local_matrix.xform(screen_point);
+}
+
+Ref<InputEvent> CanvasItem::make_input_local(const Ref<InputEvent> &p_event) const {
+
+ ERR_FAIL_COND_V(p_event.is_null(), p_event);
+ ERR_FAIL_COND_V(!is_inside_tree(), p_event);
+
+ return p_event->xformed_by((get_canvas_transform() * get_global_transform()).affine_inverse());
+}
+
+Vector2 CanvasItem::get_global_mouse_position() const {
+
+ ERR_FAIL_COND_V(!get_viewport(), Vector2());
+ return get_canvas_transform().affine_inverse().xform(get_viewport()->get_mouse_position());
+}
+
+Vector2 CanvasItem::get_local_mouse_position() const {
+
+ ERR_FAIL_COND_V(!get_viewport(), Vector2());
+
+ return get_global_transform().affine_inverse().xform(get_global_mouse_position());
+}
+
+void CanvasItem::force_update_transform() {
+ ERR_FAIL_COND(!is_inside_tree());
+ if (!xform_change.in_list()) {
+ return;
+ }
+
+ get_tree()->xform_change_list.remove(&xform_change);
+
+ notification(NOTIFICATION_TRANSFORM_CHANGED);
+}
+
+void CanvasItem::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("_toplevel_raise_self"), &CanvasItem::_toplevel_raise_self);
+ ClassDB::bind_method(D_METHOD("_update_callback"), &CanvasItem::_update_callback);
+
+#ifdef TOOLS_ENABLED
+ ClassDB::bind_method(D_METHOD("_edit_set_state", "state"), &CanvasItem::_edit_set_state);
+ ClassDB::bind_method(D_METHOD("_edit_get_state"), &CanvasItem::_edit_get_state);
+ ClassDB::bind_method(D_METHOD("_edit_set_position", "position"), &CanvasItem::_edit_set_position);
+ ClassDB::bind_method(D_METHOD("_edit_get_position"), &CanvasItem::_edit_get_position);
+ ClassDB::bind_method(D_METHOD("_edit_set_scale", "scale"), &CanvasItem::_edit_set_scale);
+ ClassDB::bind_method(D_METHOD("_edit_get_scale"), &CanvasItem::_edit_get_scale);
+ ClassDB::bind_method(D_METHOD("_edit_set_rect", "rect"), &CanvasItem::_edit_set_rect);
+ ClassDB::bind_method(D_METHOD("_edit_get_rect"), &CanvasItem::_edit_get_rect);
+ ClassDB::bind_method(D_METHOD("_edit_use_rect"), &CanvasItem::_edit_use_rect);
+ ClassDB::bind_method(D_METHOD("_edit_set_rotation", "degrees"), &CanvasItem::_edit_set_rotation);
+ ClassDB::bind_method(D_METHOD("_edit_get_rotation"), &CanvasItem::_edit_get_rotation);
+ ClassDB::bind_method(D_METHOD("_edit_use_rotation"), &CanvasItem::_edit_use_rotation);
+ ClassDB::bind_method(D_METHOD("_edit_set_pivot", "pivot"), &CanvasItem::_edit_set_pivot);
+ ClassDB::bind_method(D_METHOD("_edit_get_pivot"), &CanvasItem::_edit_get_pivot);
+ ClassDB::bind_method(D_METHOD("_edit_use_pivot"), &CanvasItem::_edit_use_pivot);
+ ClassDB::bind_method(D_METHOD("_edit_get_transform"), &CanvasItem::_edit_get_transform);
+#endif
+
+ ClassDB::bind_method(D_METHOD("get_canvas_item"), &CanvasItem::get_canvas_item);
+
+ ClassDB::bind_method(D_METHOD("set_visible", "visible"), &CanvasItem::set_visible);
+ ClassDB::bind_method(D_METHOD("is_visible"), &CanvasItem::is_visible);
+ ClassDB::bind_method(D_METHOD("is_visible_in_tree"), &CanvasItem::is_visible_in_tree);
+ ClassDB::bind_method(D_METHOD("show"), &CanvasItem::show);
+ ClassDB::bind_method(D_METHOD("hide"), &CanvasItem::hide);
+
+ ClassDB::bind_method(D_METHOD("update"), &CanvasItem::update);
+
+ ClassDB::bind_method(D_METHOD("set_as_toplevel", "enable"), &CanvasItem::set_as_toplevel);
+ ClassDB::bind_method(D_METHOD("is_set_as_toplevel"), &CanvasItem::is_set_as_toplevel);
+
+ ClassDB::bind_method(D_METHOD("set_light_mask", "light_mask"), &CanvasItem::set_light_mask);
+ ClassDB::bind_method(D_METHOD("get_light_mask"), &CanvasItem::get_light_mask);
+
+ ClassDB::bind_method(D_METHOD("set_modulate", "modulate"), &CanvasItem::set_modulate);
+ ClassDB::bind_method(D_METHOD("get_modulate"), &CanvasItem::get_modulate);
+ ClassDB::bind_method(D_METHOD("set_self_modulate", "self_modulate"), &CanvasItem::set_self_modulate);
+ ClassDB::bind_method(D_METHOD("get_self_modulate"), &CanvasItem::get_self_modulate);
+
+ ClassDB::bind_method(D_METHOD("set_draw_behind_parent", "enable"), &CanvasItem::set_draw_behind_parent);
+ ClassDB::bind_method(D_METHOD("is_draw_behind_parent_enabled"), &CanvasItem::is_draw_behind_parent_enabled);
+
+ ClassDB::bind_method(D_METHOD("_set_on_top", "on_top"), &CanvasItem::_set_on_top);
+ ClassDB::bind_method(D_METHOD("_is_on_top"), &CanvasItem::_is_on_top);
+ //ClassDB::bind_method(D_METHOD("get_transform"),&CanvasItem::get_transform);
+
+ ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width"), &CanvasItem::draw_line, DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("draw_polyline", "points", "color", "width"), &CanvasItem::draw_polyline, DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("draw_polyline_colors", "points", "colors", "width"), &CanvasItem::draw_polyline_colors, DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("draw_arc", "center", "radius", "start_angle", "end_angle", "point_count", "color", "width"), &CanvasItem::draw_arc, DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("draw_multiline", "points", "color", "width"), &CanvasItem::draw_multiline, DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("draw_multiline_colors", "points", "colors", "width"), &CanvasItem::draw_multiline_colors, DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled", "width"), &CanvasItem::draw_rect, DEFVAL(true), DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("draw_circle", "position", "radius", "color"), &CanvasItem::draw_circle);
+ ClassDB::bind_method(D_METHOD("draw_texture", "texture", "position", "modulate", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
+ ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture", "rect", "tile", "modulate", "transpose", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
+ ClassDB::bind_method(D_METHOD("draw_texture_rect_region", "texture", "rect", "src_rect", "modulate", "transpose", "normal_map", "specular_map", "specular_shininess", "clip_uv", "texture_filter", "texture_repeat"), &CanvasItem::draw_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(true), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
+ ClassDB::bind_method(D_METHOD("draw_style_box", "style_box", "rect"), &CanvasItem::draw_style_box);
+ ClassDB::bind_method(D_METHOD("draw_primitive", "points", "colors", "uvs", "texture", "width", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_primitive, DEFVAL(Ref<Texture2D>()), DEFVAL(1.0), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
+ ClassDB::bind_method(D_METHOD("draw_polygon", "points", "colors", "uvs", "texture", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
+ ClassDB::bind_method(D_METHOD("draw_colored_polygon", "points", "color", "uvs", "texture", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_colored_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
+ ClassDB::bind_method(D_METHOD("draw_string", "font", "position", "text", "modulate", "clip_w"), &CanvasItem::draw_string, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("draw_char", "font", "position", "char", "next", "modulate"), &CanvasItem::draw_char, DEFVAL(Color(1, 1, 1, 1)));
+ ClassDB::bind_method(D_METHOD("draw_mesh", "mesh", "texture", "normal_map", "specular_map", "specular_shininess", "transform", "modulate", "texture_filter", "texture_repeat"), &CanvasItem::draw_mesh, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
+ ClassDB::bind_method(D_METHOD("draw_multimesh", "multimesh", "texture", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_multimesh, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
+
+ ClassDB::bind_method(D_METHOD("draw_set_transform", "position", "rotation", "scale"), &CanvasItem::draw_set_transform);
+ ClassDB::bind_method(D_METHOD("draw_set_transform_matrix", "xform"), &CanvasItem::draw_set_transform_matrix);
+ ClassDB::bind_method(D_METHOD("get_transform"), &CanvasItem::get_transform);
+ ClassDB::bind_method(D_METHOD("get_global_transform"), &CanvasItem::get_global_transform);
+ ClassDB::bind_method(D_METHOD("get_global_transform_with_canvas"), &CanvasItem::get_global_transform_with_canvas);
+ ClassDB::bind_method(D_METHOD("get_viewport_transform"), &CanvasItem::get_viewport_transform);
+ ClassDB::bind_method(D_METHOD("get_viewport_rect"), &CanvasItem::get_viewport_rect);
+ ClassDB::bind_method(D_METHOD("get_canvas_transform"), &CanvasItem::get_canvas_transform);
+ ClassDB::bind_method(D_METHOD("get_local_mouse_position"), &CanvasItem::get_local_mouse_position);
+ ClassDB::bind_method(D_METHOD("get_global_mouse_position"), &CanvasItem::get_global_mouse_position);
+ ClassDB::bind_method(D_METHOD("get_canvas"), &CanvasItem::get_canvas);
+ ClassDB::bind_method(D_METHOD("get_world_2d"), &CanvasItem::get_world_2d);
+ //ClassDB::bind_method(D_METHOD("get_viewport"),&CanvasItem::get_viewport);
+
+ ClassDB::bind_method(D_METHOD("set_material", "material"), &CanvasItem::set_material);
+ ClassDB::bind_method(D_METHOD("get_material"), &CanvasItem::get_material);
+
+ ClassDB::bind_method(D_METHOD("set_use_parent_material", "enable"), &CanvasItem::set_use_parent_material);
+ ClassDB::bind_method(D_METHOD("get_use_parent_material"), &CanvasItem::get_use_parent_material);
+
+ ClassDB::bind_method(D_METHOD("set_notify_local_transform", "enable"), &CanvasItem::set_notify_local_transform);
+ ClassDB::bind_method(D_METHOD("is_local_transform_notification_enabled"), &CanvasItem::is_local_transform_notification_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_notify_transform", "enable"), &CanvasItem::set_notify_transform);
+ ClassDB::bind_method(D_METHOD("is_transform_notification_enabled"), &CanvasItem::is_transform_notification_enabled);
+
+ ClassDB::bind_method(D_METHOD("force_update_transform"), &CanvasItem::force_update_transform);
+
+ ClassDB::bind_method(D_METHOD("make_canvas_position_local", "screen_point"), &CanvasItem::make_canvas_position_local);
+ ClassDB::bind_method(D_METHOD("make_input_local", "event"), &CanvasItem::make_input_local);
+
+ ClassDB::bind_method(D_METHOD("set_texture_filter", "mode"), &CanvasItem::set_texture_filter);
+ ClassDB::bind_method(D_METHOD("get_texture_filter"), &CanvasItem::get_texture_filter);
+
+ ClassDB::bind_method(D_METHOD("set_texture_repeat", "mode"), &CanvasItem::set_texture_repeat);
+ ClassDB::bind_method(D_METHOD("get_texture_repeat"), &CanvasItem::get_texture_repeat);
+
+ BIND_VMETHOD(MethodInfo("_draw"));
+
+ ADD_GROUP("Visibility", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "self_modulate"), "set_self_modulate", "get_self_modulate");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_behind_parent"), "set_draw_behind_parent", "is_draw_behind_parent_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_on_top", PROPERTY_HINT_NONE, "", 0), "_set_on_top", "_is_on_top"); //compatibility
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask");
+
+ ADD_GROUP("Texture", "texture_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "ParentNode,Nearest,Linear,MipmapNearest,MipmapLinear,MipmapNearestAniso,MipmapLinearAniso"), "set_texture_filter", "get_texture_filter");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "ParentNode,Disabled,Enabled,Mirror"), "set_texture_repeat", "get_texture_repeat");
+
+ ADD_GROUP("Material", "");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,CanvasItemMaterial"), "set_material", "get_material");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_parent_material"), "set_use_parent_material", "get_use_parent_material");
+ //exporting these things doesn't really make much sense i think
+ // ADD_PROPERTY(PropertyInfo(Variant::BOOL, "toplevel", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_as_toplevel", "is_set_as_toplevel");
+ // ADD_PROPERTY(PropertyInfo(Variant::BOOL,"transform/notify"),"set_transform_notify","is_transform_notify_enabled");
+
+ ADD_SIGNAL(MethodInfo("draw"));
+ ADD_SIGNAL(MethodInfo("visibility_changed"));
+ ADD_SIGNAL(MethodInfo("hide"));
+ ADD_SIGNAL(MethodInfo("item_rect_changed"));
+
+ BIND_CONSTANT(NOTIFICATION_TRANSFORM_CHANGED);
+ BIND_CONSTANT(NOTIFICATION_DRAW);
+ BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED);
+ BIND_CONSTANT(NOTIFICATION_ENTER_CANVAS);
+ BIND_CONSTANT(NOTIFICATION_EXIT_CANVAS);
+
+ BIND_ENUM_CONSTANT(TEXTURE_FILTER_PARENT_NODE);
+ BIND_ENUM_CONSTANT(TEXTURE_FILTER_NEAREST);
+ BIND_ENUM_CONSTANT(TEXTURE_FILTER_LINEAR);
+ BIND_ENUM_CONSTANT(TEXTURE_FILTER_NEAREST_WITH_MIPMAPS);
+ BIND_ENUM_CONSTANT(TEXTURE_FILTER_LINEAR_WITH_MIPMAPS);
+ BIND_ENUM_CONSTANT(TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC);
+ BIND_ENUM_CONSTANT(TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC);
+ BIND_ENUM_CONSTANT(TEXTURE_FILTER_MAX);
+
+ BIND_ENUM_CONSTANT(TEXTURE_REPEAT_PARENT_NODE);
+ BIND_ENUM_CONSTANT(TEXTURE_REPEAT_DISABLED);
+ BIND_ENUM_CONSTANT(TEXTURE_REPEAT_ENABLED);
+ BIND_ENUM_CONSTANT(TEXTURE_REPEAT_MIRROR);
+ BIND_ENUM_CONSTANT(TEXTURE_REPEAT_MAX);
+}
+
+Transform2D CanvasItem::get_canvas_transform() const {
+
+ ERR_FAIL_COND_V(!is_inside_tree(), Transform2D());
+
+ if (canvas_layer)
+ return canvas_layer->get_transform();
+ else if (Object::cast_to<CanvasItem>(get_parent()))
+ return Object::cast_to<CanvasItem>(get_parent())->get_canvas_transform();
+ else
+ return get_viewport()->get_canvas_transform();
+}
+
+Transform2D CanvasItem::get_viewport_transform() const {
+
+ ERR_FAIL_COND_V(!is_inside_tree(), Transform2D());
+
+ if (canvas_layer) {
+
+ if (get_viewport()) {
+ return get_viewport()->get_final_transform() * canvas_layer->get_transform();
+ } else {
+ return canvas_layer->get_transform();
+ }
+
+ } else {
+ return get_viewport()->get_final_transform() * get_viewport()->get_canvas_transform();
+ }
+}
+
+void CanvasItem::set_notify_local_transform(bool p_enable) {
+ notify_local_transform = p_enable;
+}
+
+bool CanvasItem::is_local_transform_notification_enabled() const {
+ return notify_local_transform;
+}
+
+void CanvasItem::set_notify_transform(bool p_enable) {
+ if (notify_transform == p_enable)
+ return;
+
+ notify_transform = p_enable;
+
+ if (notify_transform && is_inside_tree()) {
+ //this ensures that invalid globals get resolved, so notifications can be received
+ get_global_transform();
+ }
+}
+
+bool CanvasItem::is_transform_notification_enabled() const {
+ return notify_transform;
+}
+
+int CanvasItem::get_canvas_layer() const {
+
+ if (canvas_layer)
+ return canvas_layer->get_layer();
+ else
+ return 0;
+}
+
+void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
+
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ if (texture_filter == TEXTURE_FILTER_PARENT_NODE) {
+ CanvasItem *parent_item = get_parent_item();
+ if (parent_item) {
+ texture_filter_cache = parent_item->texture_filter_cache;
+ } else {
+ //from viewport
+ switch (get_viewport()->get_default_canvas_item_texture_filter()) {
+ case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST: texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST; break;
+ case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR: texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR; break;
+ case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS; break;
+ case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS; break;
+ default: {
+ }
+ }
+ }
+ } else {
+ texture_filter_cache = RS::CanvasItemTextureFilter(texture_filter);
+ }
+ RS::get_singleton()->canvas_item_set_default_texture_filter(get_canvas_item(), texture_filter_cache);
+ update();
+
+ if (p_propagate) {
+ for (List<CanvasItem *>::Element *E = children_items.front(); E; E = E->next()) {
+ if (!E->get()->toplevel && E->get()->texture_filter == TEXTURE_FILTER_PARENT_NODE) {
+ E->get()->_update_texture_filter_changed(true);
+ }
+ }
+ }
+}
+
+void CanvasItem::set_texture_filter(TextureFilter p_texture_filter) {
+ ERR_FAIL_INDEX(p_texture_filter, TEXTURE_FILTER_MAX);
+ if (texture_filter == p_texture_filter) {
+ return;
+ }
+ texture_filter = p_texture_filter;
+ _update_texture_filter_changed(true);
+}
+
+CanvasItem::TextureFilter CanvasItem::get_texture_filter() const {
+ return texture_filter;
+}
+
+void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
+
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ if (texture_repeat == TEXTURE_REPEAT_PARENT_NODE) {
+ CanvasItem *parent_item = get_parent_item();
+ if (parent_item) {
+ texture_repeat_cache = parent_item->texture_repeat_cache;
+ } else {
+ //from viewport
+ switch (get_viewport()->get_default_canvas_item_texture_repeat()) {
+ case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: texture_repeat_cache = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED; break;
+ case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: texture_repeat_cache = RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED; break;
+ case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: texture_repeat_cache = RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR; break;
+ default: {
+ }
+ }
+ }
+ } else {
+ texture_repeat_cache = RS::CanvasItemTextureRepeat(texture_repeat);
+ }
+ RS::get_singleton()->canvas_item_set_default_texture_repeat(get_canvas_item(), texture_repeat_cache);
+ update();
+ if (p_propagate) {
+ for (List<CanvasItem *>::Element *E = children_items.front(); E; E = E->next()) {
+ if (!E->get()->toplevel && E->get()->texture_repeat == TEXTURE_REPEAT_PARENT_NODE) {
+ E->get()->_update_texture_repeat_changed(true);
+ }
+ }
+ }
+}
+
+void CanvasItem::set_texture_repeat(TextureRepeat p_texture_repeat) {
+ ERR_FAIL_INDEX(p_texture_repeat, TEXTURE_REPEAT_MAX);
+ if (texture_repeat == p_texture_repeat) {
+ return;
+ }
+ texture_repeat = p_texture_repeat;
+ _update_texture_repeat_changed(true);
+}
+
+CanvasItem::TextureRepeat CanvasItem::get_texture_repeat() const {
+ return texture_repeat;
+}
+
+CanvasItem::CanvasItem() :
+ xform_change(this) {
+
+ window = nullptr;
+ canvas_item = RenderingServer::get_singleton()->canvas_item_create();
+ visible = true;
+ pending_update = false;
+ modulate = Color(1, 1, 1, 1);
+ self_modulate = Color(1, 1, 1, 1);
+ toplevel = false;
+ first_draw = false;
+ drawing = false;
+ behind = false;
+ block_transform_notify = false;
+ canvas_layer = nullptr;
+ use_parent_material = false;
+ global_invalid = true;
+ notify_local_transform = false;
+ notify_transform = false;
+ light_mask = 1;
+ texture_repeat = TEXTURE_REPEAT_PARENT_NODE;
+ texture_filter = TEXTURE_FILTER_PARENT_NODE;
+ texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
+ texture_repeat_cache = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
+
+ C = nullptr;
+}
+
+CanvasItem::~CanvasItem() {
+
+ RenderingServer::get_singleton()->free(canvas_item);
+}
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
new file mode 100644
index 0000000000..dc17c5283b
--- /dev/null
+++ b/scene/main/canvas_item.h
@@ -0,0 +1,426 @@
+/*************************************************************************/
+/* canvas_item.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef CANVAS_ITEM_H
+#define CANVAS_ITEM_H
+
+#include "scene/main/node.h"
+#include "scene/main/scene_tree.h"
+#include "scene/resources/material.h"
+#include "scene/resources/multimesh.h"
+#include "scene/resources/shader.h"
+#include "scene/resources/texture.h"
+
+class CanvasLayer;
+class Viewport;
+class Font;
+
+class StyleBox;
+
+class CanvasItemMaterial : public Material {
+
+ GDCLASS(CanvasItemMaterial, Material);
+
+public:
+ enum BlendMode {
+ BLEND_MODE_MIX,
+ BLEND_MODE_ADD,
+ BLEND_MODE_SUB,
+ BLEND_MODE_MUL,
+ BLEND_MODE_PREMULT_ALPHA,
+ BLEND_MODE_DISABLED
+ };
+
+ enum LightMode {
+ LIGHT_MODE_NORMAL,
+ LIGHT_MODE_UNSHADED,
+ LIGHT_MODE_LIGHT_ONLY
+ };
+
+private:
+ union MaterialKey {
+
+ struct {
+ uint32_t blend_mode : 4;
+ uint32_t light_mode : 4;
+ uint32_t particles_animation : 1;
+ uint32_t invalid_key : 1;
+ };
+
+ uint32_t key;
+
+ bool operator<(const MaterialKey &p_key) const {
+ return key < p_key.key;
+ }
+ };
+
+ struct ShaderNames {
+ StringName particles_anim_h_frames;
+ StringName particles_anim_v_frames;
+ StringName particles_anim_loop;
+ };
+
+ static ShaderNames *shader_names;
+
+ struct ShaderData {
+ RID shader;
+ int users;
+ };
+
+ static Map<MaterialKey, ShaderData> shader_map;
+
+ MaterialKey current_key;
+
+ _FORCE_INLINE_ MaterialKey _compute_key() const {
+
+ MaterialKey mk;
+ mk.key = 0;
+ mk.blend_mode = blend_mode;
+ mk.light_mode = light_mode;
+ mk.particles_animation = particles_animation;
+ return mk;
+ }
+
+ static Mutex material_mutex;
+ static SelfList<CanvasItemMaterial>::List *dirty_materials;
+ SelfList<CanvasItemMaterial> element;
+
+ void _update_shader();
+ _FORCE_INLINE_ void _queue_shader_change();
+ _FORCE_INLINE_ bool _is_shader_dirty() const;
+
+ BlendMode blend_mode;
+ LightMode light_mode;
+ bool particles_animation;
+
+ int particles_anim_h_frames;
+ int particles_anim_v_frames;
+ bool particles_anim_loop;
+
+protected:
+ static void _bind_methods();
+ void _validate_property(PropertyInfo &property) const;
+
+public:
+ void set_blend_mode(BlendMode p_blend_mode);
+ BlendMode get_blend_mode() const;
+
+ void set_light_mode(LightMode p_light_mode);
+ LightMode get_light_mode() const;
+
+ void set_particles_animation(bool p_particles_anim);
+ bool get_particles_animation() const;
+
+ void set_particles_anim_h_frames(int p_frames);
+ int get_particles_anim_h_frames() const;
+ void set_particles_anim_v_frames(int p_frames);
+ int get_particles_anim_v_frames() const;
+
+ void set_particles_anim_loop(bool p_loop);
+ bool get_particles_anim_loop() const;
+
+ static void init_shaders();
+ static void finish_shaders();
+ static void flush_changes();
+
+ RID get_shader_rid() const;
+
+ virtual Shader::Mode get_shader_mode() const;
+
+ CanvasItemMaterial();
+ virtual ~CanvasItemMaterial();
+};
+
+VARIANT_ENUM_CAST(CanvasItemMaterial::BlendMode)
+VARIANT_ENUM_CAST(CanvasItemMaterial::LightMode)
+
+class CanvasItem : public Node {
+
+ GDCLASS(CanvasItem, Node);
+
+public:
+ enum TextureFilter {
+ TEXTURE_FILTER_PARENT_NODE,
+ TEXTURE_FILTER_NEAREST,
+ TEXTURE_FILTER_LINEAR,
+ TEXTURE_FILTER_NEAREST_WITH_MIPMAPS,
+ TEXTURE_FILTER_LINEAR_WITH_MIPMAPS,
+ TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC,
+ TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC,
+ TEXTURE_FILTER_MAX
+ };
+
+ enum TextureRepeat {
+ TEXTURE_REPEAT_PARENT_NODE,
+ TEXTURE_REPEAT_DISABLED,
+ TEXTURE_REPEAT_ENABLED,
+ TEXTURE_REPEAT_MIRROR,
+ TEXTURE_REPEAT_MAX,
+ };
+
+private:
+ mutable SelfList<Node> xform_change;
+
+ RID canvas_item;
+ String group;
+
+ CanvasLayer *canvas_layer;
+
+ Color modulate;
+ Color self_modulate;
+
+ List<CanvasItem *> children_items;
+ List<CanvasItem *>::Element *C;
+
+ int light_mask;
+
+ Window *window;
+ bool first_draw;
+ bool visible;
+ bool pending_update;
+ bool toplevel;
+ bool drawing;
+ bool block_transform_notify;
+ bool behind;
+ bool use_parent_material;
+ bool notify_local_transform;
+ bool notify_transform;
+
+ RS::CanvasItemTextureFilter texture_filter_cache;
+ RS::CanvasItemTextureRepeat texture_repeat_cache;
+
+ TextureFilter texture_filter;
+ TextureRepeat texture_repeat;
+
+ Ref<Material> material;
+
+ mutable Transform2D global_transform;
+ mutable bool global_invalid;
+
+ void _toplevel_raise_self();
+
+ void _propagate_visibility_changed(bool p_visible);
+
+ void _update_callback();
+
+ void _enter_canvas();
+ void _exit_canvas();
+
+ void _window_visibility_changed();
+
+ void _notify_transform(CanvasItem *p_node);
+
+ void _set_on_top(bool p_on_top) { set_draw_behind_parent(!p_on_top); }
+ bool _is_on_top() const { return !is_draw_behind_parent_enabled(); }
+
+ static CanvasItem *current_item_drawn;
+ friend class Viewport;
+ void _update_texture_repeat_changed(bool p_propagate);
+ void _update_texture_filter_changed(bool p_propagate);
+
+protected:
+ _FORCE_INLINE_ void _notify_transform() {
+ if (!is_inside_tree()) return;
+ _notify_transform(this);
+ if (!block_transform_notify && notify_local_transform) notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
+ }
+
+ void item_rect_changed(bool p_size_changed = true);
+
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ enum {
+ NOTIFICATION_TRANSFORM_CHANGED = SceneTree::NOTIFICATION_TRANSFORM_CHANGED, //unique
+ NOTIFICATION_DRAW = 30,
+ NOTIFICATION_VISIBILITY_CHANGED = 31,
+ NOTIFICATION_ENTER_CANVAS = 32,
+ NOTIFICATION_EXIT_CANVAS = 33,
+ NOTIFICATION_LOCAL_TRANSFORM_CHANGED = 35,
+ NOTIFICATION_WORLD_2D_CHANGED = 36,
+
+ };
+
+ /* EDITOR */
+#ifdef TOOLS_ENABLED
+ // Select the node
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
+ // Save and restore a CanvasItem state
+ virtual void _edit_set_state(const Dictionary &p_state){};
+ virtual Dictionary _edit_get_state() const { return Dictionary(); };
+
+ // Used to move the node
+ virtual void _edit_set_position(const Point2 &p_position) = 0;
+ virtual Point2 _edit_get_position() const = 0;
+
+ // Used to scale the node
+ virtual void _edit_set_scale(const Size2 &p_scale) = 0;
+ virtual Size2 _edit_get_scale() const = 0;
+
+ // Used to rotate the node
+ virtual bool _edit_use_rotation() const { return false; };
+ virtual void _edit_set_rotation(float p_rotation){};
+ virtual float _edit_get_rotation() const { return 0.0; };
+
+ // Used to resize/move the node
+ virtual bool _edit_use_rect() const { return false; }; // MAYBE REPLACE BY A _edit_get_editmode()
+ virtual void _edit_set_rect(const Rect2 &p_rect){};
+ virtual Rect2 _edit_get_rect() const { return Rect2(0, 0, 0, 0); };
+ virtual Size2 _edit_get_minimum_size() const { return Size2(-1, -1); }; // LOOKS WEIRD
+
+ // Used to set a pivot
+ virtual bool _edit_use_pivot() const { return false; };
+ virtual void _edit_set_pivot(const Point2 &p_pivot){};
+ virtual Point2 _edit_get_pivot() const { return Point2(); };
+
+ virtual Transform2D _edit_get_transform() const;
+#endif
+
+ /* VISIBILITY */
+
+ void set_visible(bool p_visible);
+ bool is_visible() const;
+ bool is_visible_in_tree() const;
+ void show();
+ void hide();
+
+ void update();
+
+ virtual void set_light_mask(int p_light_mask);
+ int get_light_mask() const;
+
+ void set_modulate(const Color &p_modulate);
+ Color get_modulate() const;
+
+ void set_self_modulate(const Color &p_self_modulate);
+ Color get_self_modulate() const;
+
+ /* DRAWING API */
+
+ void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0);
+ void draw_polyline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0);
+ void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0);
+ void draw_arc(const Vector2 &p_center, float p_radius, float p_start_angle, float p_end_angle, int p_point_count, const Color &p_color, float p_width = 1.0);
+ void draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0);
+ void draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0);
+ void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true, float p_width = 1.0);
+ void draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color);
+ void draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1), const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
+ void draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
+ void draw_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), bool p_clip_uv = false, TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
+ void draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect);
+ void draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture = Ref<Texture2D>(), float p_width = 1, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
+ void draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture2D> p_texture = Ref<Texture2D>(), const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
+ void draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture2D> p_texture = Ref<Texture2D>(), const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
+
+ void draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
+ void draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
+
+ void draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, const Color &p_modulate = Color(1, 1, 1), int p_clip_w = -1);
+ float draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next = "", const Color &p_modulate = Color(1, 1, 1));
+
+ void draw_set_transform(const Point2 &p_offset, float p_rot, const Size2 &p_scale);
+ void draw_set_transform_matrix(const Transform2D &p_matrix);
+
+ static CanvasItem *get_current_item_drawn();
+
+ /* RECT / TRANSFORM */
+
+ void set_as_toplevel(bool p_toplevel);
+ bool is_set_as_toplevel() const;
+
+ void set_draw_behind_parent(bool p_enable);
+ bool is_draw_behind_parent_enabled() const;
+
+ CanvasItem *get_parent_item() const;
+
+ virtual Transform2D get_transform() const = 0;
+
+ virtual Transform2D get_global_transform() const;
+ virtual Transform2D get_global_transform_with_canvas() const;
+ virtual Transform2D get_screen_transform() const;
+
+ CanvasItem *get_toplevel() const;
+ _FORCE_INLINE_ RID get_canvas_item() const {
+ return canvas_item;
+ }
+
+ void set_block_transform_notify(bool p_enable);
+ bool is_block_transform_notify_enabled() const;
+
+ Transform2D get_canvas_transform() const;
+ Transform2D get_viewport_transform() const;
+ Rect2 get_viewport_rect() const;
+ RID get_viewport_rid() const;
+ RID get_canvas() const;
+ ObjectID get_canvas_layer_instance_id() const;
+ Ref<World2D> get_world_2d() const;
+
+ virtual void set_material(const Ref<Material> &p_material);
+ Ref<Material> get_material() const;
+
+ virtual void set_use_parent_material(bool p_use_parent_material);
+ bool get_use_parent_material() const;
+
+ Ref<InputEvent> make_input_local(const Ref<InputEvent> &p_event) const;
+ Vector2 make_canvas_position_local(const Vector2 &screen_point) const;
+
+ Vector2 get_global_mouse_position() const;
+ Vector2 get_local_mouse_position() const;
+
+ void set_notify_local_transform(bool p_enable);
+ bool is_local_transform_notification_enabled() const;
+
+ void set_notify_transform(bool p_enable);
+ bool is_transform_notification_enabled() const;
+
+ void force_update_transform();
+
+ void set_texture_filter(TextureFilter p_texture_filter);
+ TextureFilter get_texture_filter() const;
+
+ void set_texture_repeat(TextureRepeat p_texture_repeat);
+ TextureRepeat get_texture_repeat() const;
+
+ // Used by control nodes to retrieve the parent's anchorable area
+ virtual Rect2 get_anchorable_rect() const { return Rect2(0, 0, 0, 0); };
+
+ int get_canvas_layer() const;
+
+ CanvasItem();
+ ~CanvasItem();
+};
+
+VARIANT_ENUM_CAST(CanvasItem::TextureFilter)
+VARIANT_ENUM_CAST(CanvasItem::TextureRepeat)
+
+#endif // CANVAS_ITEM_H
diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp
index 2085fa3a60..c1caa943e3 100644
--- a/scene/main/canvas_layer.cpp
+++ b/scene/main/canvas_layer.cpp
@@ -35,7 +35,7 @@ void CanvasLayer::set_layer(int p_xform) {
layer = p_xform;
if (viewport.is_valid())
- VisualServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_position_in_parent());
+ RenderingServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_index());
}
int CanvasLayer::get_layer() const {
@@ -48,7 +48,7 @@ void CanvasLayer::set_transform(const Transform2D &p_xform) {
transform = p_xform;
locrotscale_dirty = true;
if (viewport.is_valid())
- VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
+ RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
}
Transform2D CanvasLayer::get_transform() const {
@@ -61,7 +61,7 @@ void CanvasLayer::_update_xform() {
transform.set_rotation_and_scale(rot, scale);
transform.set_origin(ofs);
if (viewport.is_valid())
- VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
+ RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
}
void CanvasLayer::_update_locrotscale() {
@@ -150,16 +150,16 @@ void CanvasLayer::_notification(int p_what) {
vp->_canvas_layer_add(this);
viewport = vp->get_viewport_rid();
- VisualServer::get_singleton()->viewport_attach_canvas(viewport, canvas);
- VisualServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_position_in_parent());
- VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
+ RenderingServer::get_singleton()->viewport_attach_canvas(viewport, canvas);
+ RenderingServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_index());
+ RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
_update_follow_viewport();
} break;
case NOTIFICATION_EXIT_TREE: {
vp->_canvas_layer_remove(this);
- VisualServer::get_singleton()->viewport_remove_canvas(viewport, canvas);
+ RenderingServer::get_singleton()->viewport_remove_canvas(viewport, canvas);
viewport = RID();
_update_follow_viewport(false);
@@ -167,7 +167,7 @@ void CanvasLayer::_notification(int p_what) {
case NOTIFICATION_MOVED_IN_PARENT: {
if (is_inside_tree())
- VisualServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_position_in_parent());
+ RenderingServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_index());
} break;
}
@@ -191,7 +191,7 @@ void CanvasLayer::set_custom_viewport(Node *p_viewport) {
ERR_FAIL_NULL(p_viewport);
if (is_inside_tree()) {
vp->_canvas_layer_remove(this);
- VisualServer::get_singleton()->viewport_remove_canvas(viewport, canvas);
+ RenderingServer::get_singleton()->viewport_remove_canvas(viewport, canvas);
viewport = RID();
}
@@ -213,9 +213,9 @@ void CanvasLayer::set_custom_viewport(Node *p_viewport) {
vp->_canvas_layer_add(this);
viewport = vp->get_viewport_rid();
- VisualServer::get_singleton()->viewport_attach_canvas(viewport, canvas);
- VisualServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_position_in_parent());
- VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
+ RenderingServer::get_singleton()->viewport_attach_canvas(viewport, canvas);
+ RenderingServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_index());
+ RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
}
}
@@ -266,9 +266,9 @@ void CanvasLayer::_update_follow_viewport(bool p_force_exit) {
return;
}
if (p_force_exit || !follow_viewport) {
- VS::get_singleton()->canvas_set_parent(canvas, RID(), 1.0);
+ RS::get_singleton()->canvas_set_parent(canvas, RID(), 1.0);
} else {
- VS::get_singleton()->canvas_set_parent(canvas, vp->get_world_2d()->get_canvas(), follow_viewport_scale);
+ RS::get_singleton()->canvas_set_parent(canvas, vp->get_world_2d()->get_canvas(), follow_viewport_scale);
}
}
@@ -320,13 +320,13 @@ void CanvasLayer::_bind_methods() {
CanvasLayer::CanvasLayer() {
- vp = NULL;
+ vp = nullptr;
scale = Vector2(1, 1);
rot = 0;
locrotscale_dirty = false;
layer = 1;
- canvas = VS::get_singleton()->canvas_create();
- custom_viewport = NULL;
+ canvas = RS::get_singleton()->canvas_create();
+ custom_viewport = nullptr;
sort_index = 0;
follow_viewport = false;
@@ -335,5 +335,5 @@ CanvasLayer::CanvasLayer() {
CanvasLayer::~CanvasLayer() {
- VS::get_singleton()->free(canvas);
+ RS::get_singleton()->free(canvas);
}
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index fee2ada76d..dc0da015ac 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -162,12 +162,12 @@ void HTTPRequest::cancel_request() {
thread_request_quit = true;
Thread::wait_to_finish(thread);
memdelete(thread);
- thread = NULL;
+ thread = nullptr;
}
if (file) {
memdelete(file);
- file = NULL;
+ file = nullptr;
}
client->close();
body.resize(0);
@@ -566,7 +566,7 @@ void HTTPRequest::_bind_methods() {
HTTPRequest::HTTPRequest() {
- thread = NULL;
+ thread = nullptr;
port = 80;
redirections = 0;
@@ -583,7 +583,7 @@ HTTPRequest::HTTPRequest() {
thread_done = false;
downloaded = 0;
body_size_limit = -1;
- file = NULL;
+ file = nullptr;
timer = memnew(Timer);
timer->set_one_shot(true);
diff --git a/scene/main/instance_placeholder.cpp b/scene/main/instance_placeholder.cpp
index fe238af1c4..062b221c84 100644
--- a/scene/main/instance_placeholder.cpp
+++ b/scene/main/instance_placeholder.cpp
@@ -77,11 +77,11 @@ String InstancePlaceholder::get_instance_path() const {
Node *InstancePlaceholder::create_instance(bool p_replace, const Ref<PackedScene> &p_custom_scene) {
- ERR_FAIL_COND_V(!is_inside_tree(), NULL);
+ ERR_FAIL_COND_V(!is_inside_tree(), nullptr);
Node *base = get_parent();
if (!base)
- return NULL;
+ return nullptr;
Ref<PackedScene> ps;
if (p_custom_scene.is_valid())
@@ -90,12 +90,12 @@ Node *InstancePlaceholder::create_instance(bool p_replace, const Ref<PackedScene
ps = ResourceLoader::load(path, "PackedScene");
if (!ps.is_valid())
- return NULL;
+ return nullptr;
Node *scene = ps->instance();
if (!scene)
- return NULL;
+ return nullptr;
scene->set_name(get_name());
- int pos = get_position_in_parent();
+ int pos = get_index();
for (List<PropSet>::Element *E = stored_values.front(); E; E = E->next()) {
scene->set(E->get().name, E->get().value);
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 973dff07d2..4c02a15531 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -82,7 +82,7 @@ void Node::_notification(int p_notification) {
if (data.parent)
data.pause_owner = data.parent->data.pause_owner;
else
- data.pause_owner = NULL;
+ data.pause_owner = nullptr;
} else {
data.pause_owner = this;
}
@@ -112,17 +112,17 @@ void Node::_notification(int p_notification) {
if (data.unhandled_key_input)
remove_from_group("_vp_unhandled_key_input" + itos(get_viewport()->get_instance_id()));
- data.pause_owner = NULL;
+ data.pause_owner = nullptr;
if (data.path_cache) {
memdelete(data.path_cache);
- data.path_cache = NULL;
+ data.path_cache = nullptr;
}
} break;
case NOTIFICATION_PATH_CHANGED: {
if (data.path_cache) {
memdelete(data.path_cache);
- data.path_cache = NULL;
+ data.path_cache = nullptr;
}
} break;
case NOTIFICATION_READY: {
@@ -149,7 +149,7 @@ void Node::_notification(int p_notification) {
set_physics_process(true);
}
- get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_ready, NULL, 0);
+ get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_ready, nullptr, 0);
}
} break;
@@ -158,11 +158,11 @@ void Node::_notification(int p_notification) {
} break;
case NOTIFICATION_PREDELETE: {
- set_owner(NULL);
+ set_owner(nullptr);
while (data.owned.size()) {
- data.owned.front()->get()->set_owner(NULL);
+ data.owned.front()->get()->set_owner(nullptr);
}
if (data.parent) {
@@ -226,7 +226,7 @@ void Node::_propagate_enter_tree() {
if (get_script_instance()) {
- get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_enter_tree, NULL, 0);
+ get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_enter_tree, nullptr, 0);
}
emit_signal(SceneStringNames::get_singleton()->tree_entered);
@@ -278,7 +278,7 @@ void Node::_propagate_exit_tree() {
if (get_script_instance()) {
- get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_exit_tree, NULL, 0);
+ get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_exit_tree, nullptr, 0);
}
emit_signal(SceneStringNames::get_singleton()->tree_exiting);
@@ -290,17 +290,17 @@ void Node::_propagate_exit_tree() {
for (Map<StringName, GroupData>::Element *E = data.grouped.front(); E; E = E->next()) {
data.tree->remove_from_group(E->key(), this);
- E->get().group = NULL;
+ E->get().group = nullptr;
}
- data.viewport = NULL;
+ data.viewport = nullptr;
if (data.tree)
data.tree->tree_changed();
data.inside_tree = false;
data.ready_notified = false;
- data.tree = NULL;
+ data.tree = nullptr;
data.depth = -1;
}
@@ -423,7 +423,7 @@ void Node::set_pause_mode(PauseMode p_mode) {
if ((data.pause_mode == PAUSE_MODE_INHERIT) == prev_inherits)
return; ///nothing changed
- Node *owner = NULL;
+ Node *owner = nullptr;
if (data.pause_mode == PAUSE_MODE_INHERIT) {
@@ -914,7 +914,7 @@ void Node::set_process_priority(int p_priority) {
data.process_priority = p_priority;
// Make sure we are in SceneTree.
- if (data.tree == NULL) {
+ if (data.tree == nullptr) {
return;
}
@@ -1268,7 +1268,7 @@ void Node::add_child_below_node(Node *p_node, Node *p_child, bool p_legible_uniq
add_child(p_child, p_legible_unique_name);
if (is_a_parent_of(p_node)) {
- move_child(p_child, p_node->get_position_in_parent() + 1);
+ move_child(p_child, p_node->get_index() + 1);
} else {
WARN_PRINT("Cannot move under node " + p_node->get_name() + " as " + p_child->get_name() + " does not share a parent.");
}
@@ -1295,7 +1295,7 @@ void Node::_propagate_validate_owner() {
if (!found) {
data.owner->data.owned.erase(data.OW);
- data.owner = NULL;
+ data.owner = nullptr;
}
}
@@ -1336,7 +1336,7 @@ void Node::remove_child(Node *p_child) {
//if (data.scene) { does not matter
- p_child->_set_tree(NULL);
+ p_child->_set_tree(nullptr);
//}
remove_child_notify(p_child);
@@ -1354,7 +1354,7 @@ void Node::remove_child(Node *p_child) {
children[i]->notification(NOTIFICATION_MOVED_IN_PARENT);
}
- p_child->data.parent = NULL;
+ p_child->data.parent = nullptr;
p_child->data.pos = -1;
// validate owner
@@ -1371,7 +1371,7 @@ int Node::get_child_count() const {
}
Node *Node::get_child(int p_index) const {
- ERR_FAIL_INDEX_V(p_index, data.children.size(), NULL);
+ ERR_FAIL_INDEX_V(p_index, data.children.size(), nullptr);
return data.children[p_index];
}
@@ -1386,19 +1386,19 @@ Node *Node::_get_child_by_name(const StringName &p_name) const {
return cd[i];
}
- return NULL;
+ return nullptr;
}
Node *Node::get_node_or_null(const NodePath &p_path) const {
if (p_path.is_empty()) {
- return NULL;
+ return nullptr;
}
- ERR_FAIL_COND_V_MSG(!data.inside_tree && p_path.is_absolute(), NULL, "Can't use get_node() with absolute paths from outside the active scene tree.");
+ ERR_FAIL_COND_V_MSG(!data.inside_tree && p_path.is_absolute(), nullptr, "Can't use get_node() with absolute paths from outside the active scene tree.");
- Node *current = NULL;
- Node *root = NULL;
+ Node *current = nullptr;
+ Node *root = nullptr;
if (!p_path.is_absolute()) {
current = const_cast<Node *>(this); //start from this
@@ -1412,7 +1412,7 @@ Node *Node::get_node_or_null(const NodePath &p_path) const {
for (int i = 0; i < p_path.get_name_count(); i++) {
StringName name = p_path.get_name(i);
- Node *next = NULL;
+ Node *next = nullptr;
if (name == SceneStringNames::get_singleton()->dot) { // .
@@ -1420,18 +1420,18 @@ Node *Node::get_node_or_null(const NodePath &p_path) const {
} else if (name == SceneStringNames::get_singleton()->doubledot) { // ..
- if (current == NULL || !current->data.parent)
- return NULL;
+ if (current == nullptr || !current->data.parent)
+ return nullptr;
next = current->data.parent;
- } else if (current == NULL) {
+ } else if (current == nullptr) {
if (name == root->get_name())
next = root;
} else {
- next = NULL;
+ next = nullptr;
for (int j = 0; j < current->data.children.size(); j++) {
@@ -1443,8 +1443,8 @@ Node *Node::get_node_or_null(const NodePath &p_path) const {
break;
}
}
- if (next == NULL) {
- return NULL;
+ if (next == nullptr) {
+ return nullptr;
};
}
current = next;
@@ -1456,13 +1456,13 @@ Node *Node::get_node_or_null(const NodePath &p_path) const {
Node *Node::get_node(const NodePath &p_path) const {
Node *node = get_node_or_null(p_path);
- ERR_FAIL_COND_V_MSG(!node, NULL, "Node not found: " + p_path + ".");
+ ERR_FAIL_COND_V_MSG(!node, nullptr, "Node not found: " + p_path + ".");
return node;
}
bool Node::has_node(const NodePath &p_path) const {
- return get_node_or_null(p_path) != NULL;
+ return get_node_or_null(p_path) != nullptr;
}
Node *Node::find_node(const String &p_mask, bool p_recursive, bool p_owned) const {
@@ -1482,7 +1482,7 @@ Node *Node::find_node(const String &p_mask, bool p_recursive, bool p_owned) cons
if (ret)
return ret;
}
- return NULL;
+ return nullptr;
}
Node *Node::get_parent() const {
@@ -1500,7 +1500,7 @@ Node *Node::find_parent(const String &p_mask) const {
p = p->data.parent;
}
- return NULL;
+ return nullptr;
}
bool Node::is_a_parent_of(const Node *p_node) const {
@@ -1607,8 +1607,8 @@ void Node::set_owner(Node *p_owner) {
if (data.owner) {
data.owner->data.owned.erase(data.OW);
- data.OW = NULL;
- data.owner = NULL;
+ data.OW = nullptr;
+ data.owner = nullptr;
}
ERR_FAIL_COND(p_owner == this);
@@ -1663,7 +1663,7 @@ Node *Node::find_common_parent_with(const Node *p_node) const {
}
if (!common_parent)
- return NULL;
+ return nullptr;
return const_cast<Node *>(common_parent);
}
@@ -1762,7 +1762,7 @@ void Node::add_to_group(const StringName &p_identifier, bool p_persistent) {
if (data.tree) {
gd.group = data.tree->add_to_group(p_identifier, this);
} else {
- gd.group = NULL;
+ gd.group = nullptr;
}
gd.persistent = p_persistent;
@@ -1918,6 +1918,7 @@ int Node::get_index() const {
return data.pos;
}
+
void Node::remove_and_skip() {
ERR_FAIL_COND(!data.parent);
@@ -1935,7 +1936,7 @@ void Node::remove_and_skip() {
continue;
remove_child(c_node);
- c_node->_propagate_replace_owner(this, NULL);
+ c_node->_propagate_replace_owner(this, nullptr);
children.push_back(c_node);
clear = false;
break;
@@ -1949,7 +1950,7 @@ void Node::remove_and_skip() {
Node *c_node = children.front()->get();
data.parent->add_child(c_node);
- c_node->_propagate_replace_owner(NULL, new_owner);
+ c_node->_propagate_replace_owner(nullptr, new_owner);
children.pop_front();
}
@@ -2042,14 +2043,9 @@ bool Node::get_scene_instance_load_placeholder() const {
return data.use_placeholder;
}
-int Node::get_position_in_parent() const {
-
- return data.pos;
-}
-
Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const {
- Node *node = NULL;
+ Node *node = nullptr;
bool instanced = false;
@@ -2063,25 +2059,25 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
} else if ((p_flags & DUPLICATE_USE_INSTANCING) && get_filename() != String()) {
Ref<PackedScene> res = ResourceLoader::load(get_filename());
- ERR_FAIL_COND_V(res.is_null(), NULL);
+ ERR_FAIL_COND_V(res.is_null(), nullptr);
PackedScene::GenEditState ges = PackedScene::GEN_EDIT_STATE_DISABLED;
#ifdef TOOLS_ENABLED
if (p_flags & DUPLICATE_FROM_EDITOR)
ges = PackedScene::GEN_EDIT_STATE_INSTANCE;
#endif
node = res->instance(ges);
- ERR_FAIL_COND_V(!node, NULL);
+ ERR_FAIL_COND_V(!node, nullptr);
instanced = true;
} else {
Object *obj = ClassDB::instance(get_class());
- ERR_FAIL_COND_V(!obj, NULL);
+ ERR_FAIL_COND_V(!obj, nullptr);
node = Object::cast_to<Node>(obj);
if (!node)
memdelete(obj);
- ERR_FAIL_COND_V(!node, NULL);
+ ERR_FAIL_COND_V(!node, nullptr);
}
if (get_filename() != "") { //an instance
@@ -2189,7 +2185,7 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
if (!dup) {
memdelete(node);
- return NULL;
+ return nullptr;
}
node->add_child(dup);
@@ -2204,18 +2200,18 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
if (!parent) {
memdelete(node);
- return NULL;
+ return nullptr;
}
Node *dup = E->get()->_duplicate(p_flags, r_duplimap);
if (!dup) {
memdelete(node);
- return NULL;
+ return nullptr;
}
parent->add_child(dup);
- int pos = E->get()->get_position_in_parent();
+ int pos = E->get()->get_index();
if (pos < parent->get_child_count() - 1) {
@@ -2256,7 +2252,7 @@ void Node::_duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p
if (get_owner() != get_parent()->get_owner())
return;
- Node *node = NULL;
+ Node *node = nullptr;
if (get_filename() != "") {
@@ -2369,15 +2365,15 @@ void Node::_duplicate_signals(const Node *p_original, Node *p_copy) const {
Node *Node::duplicate_and_reown(const Map<Node *, Node *> &p_reown_map) const {
- ERR_FAIL_COND_V(get_filename() != "", NULL);
+ ERR_FAIL_COND_V(get_filename() != "", nullptr);
Object *obj = ClassDB::instance(get_class());
- ERR_FAIL_COND_V_MSG(!obj, NULL, "Node: Could not duplicate: " + String(get_class()) + ".");
+ ERR_FAIL_COND_V_MSG(!obj, nullptr, "Node: Could not duplicate: " + String(get_class()) + ".");
Node *node = Object::cast_to<Node>(obj);
if (!node) {
memdelete(obj);
- ERR_FAIL_V_MSG(NULL, "Node: Could not duplicate: " + String(get_class()) + ".");
+ ERR_FAIL_V_MSG(nullptr, "Node: Could not duplicate: " + String(get_class()) + ".");
}
node->set_name(get_name());
@@ -2591,7 +2587,7 @@ Node *Node::get_node_and_resource(const NodePath &p_path, RES &r_res, Vector<Str
r_res = RES();
r_leftover_subpath = Vector<StringName>();
if (!node)
- return NULL;
+ return nullptr;
if (p_path.get_subname_count()) {
@@ -2601,7 +2597,7 @@ Node *Node::get_node_and_resource(const NodePath &p_path, RES &r_res, Vector<Str
Variant new_res_v = j == 0 ? node->get(p_path.get_subname(j)) : r_res->get(p_path.get_subname(j));
if (new_res_v.get_type() == Variant::NIL) { // Found nothing on that path
- return NULL;
+ return nullptr;
}
RES new_res = new_res_v;
@@ -2623,8 +2619,8 @@ Node *Node::get_node_and_resource(const NodePath &p_path, RES &r_res, Vector<Str
void Node::_set_tree(SceneTree *p_tree) {
- SceneTree *tree_changed_a = NULL;
- SceneTree *tree_changed_b = NULL;
+ SceneTree *tree_changed_a = nullptr;
+ SceneTree *tree_changed_b = nullptr;
//ERR_FAIL_COND(p_scene && data.parent && !data.parent->data.scene); //nobug if both are null
@@ -2697,9 +2693,9 @@ void Node::queue_delete() {
}
}
-Array Node::_get_children() const {
+TypedArray<Node> Node::_get_children() const {
- Array arr;
+ TypedArray<Node> arr;
int cc = get_child_count();
arr.resize(cc);
for (int i = 0; i < cc; i++)
@@ -2860,7 +2856,6 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_pause_mode"), &Node::get_pause_mode);
ClassDB::bind_method(D_METHOD("can_process"), &Node::can_process);
ClassDB::bind_method(D_METHOD("print_stray_nodes"), &Node::_print_stray_nodes);
- ClassDB::bind_method(D_METHOD("get_position_in_parent"), &Node::get_position_in_parent);
ClassDB::bind_method(D_METHOD("set_display_folded", "fold"), &Node::set_display_folded);
ClassDB::bind_method(D_METHOD("is_displayed_folded"), &Node::is_displayed_folded);
@@ -2950,9 +2945,9 @@ void Node::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_WM_MOUSE_EXIT);
BIND_CONSTANT(NOTIFICATION_WM_FOCUS_IN);
BIND_CONSTANT(NOTIFICATION_WM_FOCUS_OUT);
- BIND_CONSTANT(NOTIFICATION_WM_QUIT_REQUEST);
+ BIND_CONSTANT(NOTIFICATION_WM_CLOSE_REQUEST);
BIND_CONSTANT(NOTIFICATION_WM_GO_BACK_REQUEST);
- BIND_CONSTANT(NOTIFICATION_WM_UNFOCUS_REQUEST);
+ BIND_CONSTANT(NOTIFICATION_WM_SIZE_CHANGED);
BIND_CONSTANT(NOTIFICATION_OS_MEMORY_WARNING);
BIND_CONSTANT(NOTIFICATION_TRANSLATION_CHANGED);
BIND_CONSTANT(NOTIFICATION_WM_ABOUT);
@@ -3012,8 +3007,8 @@ Node::Node() {
data.pos = -1;
data.depth = -1;
data.blocked = 0;
- data.parent = NULL;
- data.tree = NULL;
+ data.parent = nullptr;
+ data.tree = nullptr;
data.physics_process = false;
data.idle_process = false;
data.process_priority = 0;
@@ -3022,18 +3017,18 @@ Node::Node() {
data.inside_tree = false;
data.ready_notified = false;
- data.owner = NULL;
- data.OW = NULL;
+ data.owner = nullptr;
+ data.OW = nullptr;
data.input = false;
data.unhandled_input = false;
data.unhandled_key_input = false;
data.pause_mode = PAUSE_MODE_INHERIT;
- data.pause_owner = NULL;
+ data.pause_owner = nullptr;
data.network_master = 1; //server by default
- data.path_cache = NULL;
+ data.path_cache = nullptr;
data.parent_owned = false;
data.in_constructor = true;
- data.viewport = NULL;
+ data.viewport = nullptr;
data.use_placeholder = false;
data.display_folded = false;
data.ready_first = true;
diff --git a/scene/main/node.h b/scene/main/node.h
index d1f75b71ec..1c1b7bbd7a 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -37,6 +37,7 @@
#include "core/object.h"
#include "core/project_settings.h"
#include "core/script_language.h"
+#include "core/typed_array.h"
#include "scene/main/scene_tree.h"
class Viewport;
@@ -180,9 +181,9 @@ private:
void _duplicate_signals(const Node *p_original, Node *p_copy) const;
void _duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p_reown_map) const;
- Node *_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap = NULL) const;
+ Node *_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap = nullptr) const;
- Array _get_children() const;
+ TypedArray<Node> _get_children() const;
Array _get_groups() const;
Variant _rpc_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
@@ -244,13 +245,16 @@ public:
NOTIFICATION_INTERNAL_PHYSICS_PROCESS = 26,
NOTIFICATION_POST_ENTER_TREE = 27,
//keep these linked to node
- NOTIFICATION_WM_MOUSE_ENTER = MainLoop::NOTIFICATION_WM_MOUSE_ENTER,
- NOTIFICATION_WM_MOUSE_EXIT = MainLoop::NOTIFICATION_WM_MOUSE_EXIT,
- NOTIFICATION_WM_FOCUS_IN = MainLoop::NOTIFICATION_WM_FOCUS_IN,
- NOTIFICATION_WM_FOCUS_OUT = MainLoop::NOTIFICATION_WM_FOCUS_OUT,
- NOTIFICATION_WM_QUIT_REQUEST = MainLoop::NOTIFICATION_WM_QUIT_REQUEST,
- NOTIFICATION_WM_GO_BACK_REQUEST = MainLoop::NOTIFICATION_WM_GO_BACK_REQUEST,
- NOTIFICATION_WM_UNFOCUS_REQUEST = MainLoop::NOTIFICATION_WM_UNFOCUS_REQUEST,
+
+ NOTIFICATION_WM_MOUSE_ENTER = 1002,
+ NOTIFICATION_WM_MOUSE_EXIT = 1003,
+ NOTIFICATION_WM_FOCUS_IN = 1004,
+ NOTIFICATION_WM_FOCUS_OUT = 1005,
+ NOTIFICATION_WM_CLOSE_REQUEST = 1006,
+ NOTIFICATION_WM_GO_BACK_REQUEST = 1007,
+ NOTIFICATION_WM_SIZE_CHANGED = 1008,
+ NOTIFICATION_WM_DPI_CHANGE = 1009,
+
NOTIFICATION_OS_MEMORY_WARNING = MainLoop::NOTIFICATION_OS_MEMORY_WARNING,
NOTIFICATION_TRANSLATION_CHANGED = MainLoop::NOTIFICATION_TRANSLATION_CHANGED,
NOTIFICATION_WM_ABOUT = MainLoop::NOTIFICATION_WM_ABOUT,
@@ -283,7 +287,7 @@ public:
Node *find_parent(const String &p_mask) const;
_FORCE_INLINE_ SceneTree *get_tree() const {
- ERR_FAIL_COND_V(!data.tree, NULL);
+ ERR_FAIL_COND_V(!data.tree, nullptr);
return data.tree;
}
@@ -366,8 +370,6 @@ public:
void set_process_unhandled_key_input(bool p_enable);
bool is_processing_unhandled_key_input() const;
- int get_position_in_parent() const;
-
Node *duplicate(int p_flags = DUPLICATE_GROUPS | DUPLICATE_SIGNALS | DUPLICATE_SCRIPTS) const;
Node *duplicate_and_reown(const Map<Node *, Node *> &p_reown_map) const;
#ifdef TOOLS_ENABLED
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index f472de220b..f30a899d69 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -31,6 +31,7 @@
#include "scene_tree.h"
#include "core/debugger/engine_debugger.h"
+#include "core/input/input_filter.h"
#include "core/io/marshalls.h"
#include "core/io/resource_loader.h"
#include "core/message_queue.h"
@@ -39,7 +40,6 @@
#include "core/os/os.h"
#include "core/print_string.h"
#include "core/project_settings.h"
-#include "main/input_default.h"
#include "node.h"
#include "scene/debugger/scene_debugger.h"
#include "scene/resources/dynamic_font.h"
@@ -47,10 +47,11 @@
#include "scene/resources/mesh.h"
#include "scene/resources/packed_scene.h"
#include "scene/scene_string_names.h"
-#include "servers/navigation_server.h"
-#include "servers/physics_2d_server.h"
-#include "servers/physics_server.h"
-#include "viewport.h"
+#include "servers/display_server.h"
+#include "servers/navigation_server_3d.h"
+#include "servers/physics_server_2d.h"
+#include "servers/physics_server_3d.h"
+#include "window.h"
#include <stdio.h>
@@ -111,7 +112,7 @@ void SceneTree::node_added(Node *p_node) {
void SceneTree::node_removed(Node *p_node) {
if (current_scene == p_node) {
- current_scene = NULL;
+ current_scene = nullptr;
}
emit_signal(node_removed_name, p_node);
if (call_lock > 0)
@@ -397,69 +398,6 @@ void SceneTree::set_group(const StringName &p_group, const String &p_name, const
set_group_flags(0, p_group, p_name, p_value);
}
-void SceneTree::set_input_as_handled() {
-
- input_handled = true;
-}
-
-void SceneTree::input_text(const String &p_text) {
-
- root_lock++;
-
- call_group_flags(GROUP_CALL_REALTIME, "_viewports", "_vp_input_text", p_text); //special one for GUI, as controls use their own process check
-
- root_lock--;
-}
-
-bool SceneTree::is_input_handled() {
- return input_handled;
-}
-
-void SceneTree::input_event(const Ref<InputEvent> &p_event) {
-
- if (Engine::get_singleton()->is_editor_hint() && (Object::cast_to<InputEventJoypadButton>(p_event.ptr()) || Object::cast_to<InputEventJoypadMotion>(*p_event)))
- return; //avoid joy input on editor
-
- current_event++;
- root_lock++;
-
- input_handled = false;
-
- // Don't make const ref unless you can find and fix what caused GH-34691.
- Ref<InputEvent> ev = p_event;
-
- MainLoop::input_event(ev);
-
- call_group_flags(GROUP_CALL_REALTIME, "_viewports", "_vp_input", ev); //special one for GUI, as controls use their own process check
-
- if (EngineDebugger::is_active()) {
- //quit from game window using F8
- Ref<InputEventKey> k = ev;
- if (k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_keycode() == KEY_F8) {
- EngineDebugger::get_singleton()->send_message("request_quit", Array());
- }
- }
-
- _flush_ugc();
- root_lock--;
- //MessageQueue::get_singleton()->flush(); //flushing here causes UI and other places slowness
-
- root_lock++;
-
- if (!input_handled) {
- call_group_flags(GROUP_CALL_REALTIME, "_viewports", "_vp_unhandled_input", ev); //special one for GUI, as controls use their own process check
- _flush_ugc();
- // input_handled = true; - no reason to set this as handled
- root_lock--;
- //MessageQueue::get_singleton()->flush(); //flushing here causes UI and other places slowness
- } else {
- // input_handled = true; - no reason to set this as handled
- root_lock--;
- }
-
- _call_idle_callbacks();
-}
-
void SceneTree::init() {
initialized = true;
root->_set_tree(this);
@@ -493,19 +431,11 @@ bool SceneTree::iteration(float p_time) {
return _quit;
}
-void SceneTree::_update_font_oversampling(float p_ratio) {
-
- if (use_font_oversampling) {
- DynamicFontAtSize::font_oversampling = p_ratio;
- DynamicFont::update_oversampling();
- }
-}
-
bool SceneTree::idle(float p_time) {
//print_line("ram: "+itos(OS::get_singleton()->get_static_memory_usage())+" sram: "+itos(OS::get_singleton()->get_dynamic_memory_usage()));
//print_line("node count: "+itos(get_node_count()));
- //print_line("TEXTURE RAM: "+itos(VS::get_singleton()->get_render_info(VS::INFO_TEXTURE_MEM_USED)));
+ //print_line("TEXTURE RAM: "+itos(RS::get_singleton()->get_render_info(RS::INFO_TEXTURE_MEM_USED)));
root_lock++;
@@ -526,15 +456,6 @@ bool SceneTree::idle(float p_time) {
_notify_group_pause("idle_process_internal", Node::NOTIFICATION_INTERNAL_PROCESS);
_notify_group_pause("idle_process", Node::NOTIFICATION_PROCESS);
- Size2 win_size = Size2(OS::get_singleton()->get_window_size().width, OS::get_singleton()->get_window_size().height);
-
- if (win_size != last_screen_size) {
-
- last_screen_size = win_size;
- _update_root_rect();
- emit_signal("screen_resized");
- }
-
_flush_ugc();
MessageQueue::get_singleton()->flush(); //small little hack
flush_transform_notifications(); //transforms after world update, to avoid unnecessary enter/exit notifications
@@ -618,10 +539,10 @@ void SceneTree::finish() {
MainLoop::finish();
if (root) {
- root->_set_tree(NULL);
+ root->_set_tree(nullptr);
root->_propagate_after_exit_tree();
memdelete(root); //delete root
- root = NULL;
+ root = nullptr;
}
// cleanup timers
@@ -642,59 +563,36 @@ void SceneTree::quit(int p_exit_code) {
_quit = true;
}
-void SceneTree::_notification(int p_notification) {
-
- switch (p_notification) {
-
- case NOTIFICATION_WM_QUIT_REQUEST: {
-
- get_root()->propagate_notification(p_notification);
-
- if (accept_quit) {
- _quit = true;
- break;
- }
- } break;
-
- case NOTIFICATION_WM_GO_BACK_REQUEST: {
-
- get_root()->propagate_notification(p_notification);
+void SceneTree::_main_window_close() {
- if (quit_on_go_back) {
- _quit = true;
- break;
- }
- } break;
+ if (accept_quit) {
+ _quit = true;
+ }
+}
+void SceneTree::_main_window_go_back() {
+ if (quit_on_go_back) {
+ _quit = true;
+ }
+}
- case NOTIFICATION_WM_FOCUS_IN: {
+void SceneTree::_main_window_focus_in() {
+ InputFilter *id = InputFilter::get_singleton();
+ if (id) {
+ id->ensure_touch_mouse_raised();
+ }
+}
- InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
- if (id) {
- id->ensure_touch_mouse_raised();
- }
+void SceneTree::_notification(int p_notification) {
- get_root()->propagate_notification(p_notification);
- } break;
+ switch (p_notification) {
case NOTIFICATION_TRANSLATION_CHANGED: {
if (!Engine::get_singleton()->is_editor_hint()) {
get_root()->propagate_notification(p_notification);
}
} break;
-
- case NOTIFICATION_WM_UNFOCUS_REQUEST: {
-
- notify_group_flags(GROUP_CALL_REALTIME | GROUP_CALL_MULTILEVEL, "input", NOTIFICATION_WM_UNFOCUS_REQUEST);
-
- get_root()->propagate_notification(p_notification);
-
- } break;
-
case NOTIFICATION_OS_MEMORY_WARNING:
case NOTIFICATION_OS_IME_UPDATE:
- case NOTIFICATION_WM_MOUSE_ENTER:
- case NOTIFICATION_WM_MOUSE_EXIT:
- case NOTIFICATION_WM_FOCUS_OUT:
case NOTIFICATION_WM_ABOUT:
case NOTIFICATION_CRASH:
case NOTIFICATION_APP_RESUMED:
@@ -898,9 +796,9 @@ void SceneTree::set_pause(bool p_enabled) {
if (p_enabled == pause)
return;
pause = p_enabled;
- NavigationServer::get_singleton()->set_active(!p_enabled);
- PhysicsServer::get_singleton()->set_active(!p_enabled);
- Physics2DServer::get_singleton()->set_active(!p_enabled);
+ NavigationServer3D::get_singleton()->set_active(!p_enabled);
+ PhysicsServer3D::get_singleton()->set_active(!p_enabled);
+ PhysicsServer2D::get_singleton()->set_active(!p_enabled);
if (get_root())
get_root()->propagate_notification(p_enabled ? Node::NOTIFICATION_PAUSED : Node::NOTIFICATION_UNPAUSED);
}
@@ -910,7 +808,7 @@ bool SceneTree::is_paused() const {
return pause;
}
-void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p_method, const Ref<InputEvent> &p_input) {
+void SceneTree::_notify_group_pause(const StringName &p_group, int p_notification) {
Map<StringName, Group>::Element *E = group_map.find(p_group);
if (!E)
@@ -919,7 +817,7 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p
if (g.nodes.empty())
return;
- _update_group_order(g);
+ _update_group_order(g, p_notification == Node::NOTIFICATION_PROCESS || p_notification == Node::NOTIFICATION_INTERNAL_PROCESS || p_notification == Node::NOTIFICATION_PHYSICS_PROCESS || p_notification == Node::NOTIFICATION_INTERNAL_PHYSICS_PROCESS);
//copy, so copy on write happens in case something is removed from process while being called
//performance is not lost because only if something is added/removed the vector is copied.
@@ -928,15 +826,9 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p
int node_count = nodes_copy.size();
Node **nodes = nodes_copy.ptrw();
- Variant arg = p_input;
- const Variant *v[1] = { &arg };
-
call_lock++;
- for (int i = node_count - 1; i >= 0; i--) {
-
- if (input_handled)
- break;
+ for (int i = 0; i < node_count; i++) {
Node *n = nodes[i];
if (call_lock && call_skip.has(n))
@@ -944,8 +836,10 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p
if (!n->can_process())
continue;
+ if (!n->can_process_notification(p_notification))
+ continue;
- n->call_multilevel(p_method, (const Variant **)v, 1);
+ n->notification(p_notification);
//ERR_FAIL_COND(node_count != g.nodes.size());
}
@@ -954,7 +848,18 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p
call_skip.clear();
}
-void SceneTree::_notify_group_pause(const StringName &p_group, int p_notification) {
+/*
+void SceneMainLoop::_update_listener_2d() {
+
+ if (listener_2d.is_valid()) {
+
+ SpatialSound2DServer::get_singleton()->listener_set_space( listener_2d, world_2d->get_sound_space() );
+ }
+
+}
+*/
+
+void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p_method, const Ref<InputEvent> &p_input, Viewport *p_viewport) {
Map<StringName, Group>::Element *E = group_map.find(p_group);
if (!E)
@@ -963,7 +868,7 @@ void SceneTree::_notify_group_pause(const StringName &p_group, int p_notificatio
if (g.nodes.empty())
return;
- _update_group_order(g, p_notification == Node::NOTIFICATION_PROCESS || p_notification == Node::NOTIFICATION_INTERNAL_PROCESS || p_notification == Node::NOTIFICATION_PHYSICS_PROCESS || p_notification == Node::NOTIFICATION_INTERNAL_PHYSICS_PROCESS);
+ _update_group_order(g);
//copy, so copy on write happens in case something is removed from process while being called
//performance is not lost because only if something is added/removed the vector is copied.
@@ -972,9 +877,15 @@ void SceneTree::_notify_group_pause(const StringName &p_group, int p_notificatio
int node_count = nodes_copy.size();
Node **nodes = nodes_copy.ptrw();
+ Variant arg = p_input;
+ const Variant *v[1] = { &arg };
+
call_lock++;
- for (int i = 0; i < node_count; i++) {
+ for (int i = node_count - 1; i >= 0; i--) {
+
+ if (p_viewport->is_input_handled())
+ break;
Node *n = nodes[i];
if (call_lock && call_skip.has(n))
@@ -982,10 +893,8 @@ void SceneTree::_notify_group_pause(const StringName &p_group, int p_notificatio
if (!n->can_process())
continue;
- if (!n->can_process_notification(p_notification))
- continue;
- n->notification(p_notification);
+ n->call_multilevel(p_method, (const Variant **)v, 1);
//ERR_FAIL_COND(node_count != g.nodes.size());
}
@@ -993,18 +902,6 @@ void SceneTree::_notify_group_pause(const StringName &p_group, int p_notificatio
if (call_lock == 0)
call_skip.clear();
}
-
-/*
-void SceneMainLoop::_update_listener_2d() {
-
- if (listener_2d.is_valid()) {
-
- SpatialSound2DServer::get_singleton()->listener_set_space( listener_2d, world_2d->get_sound_space() );
- }
-
-}
-*/
-
Variant SceneTree::_call_group_flags(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
r_error.error = Callable::CallError::CALL_OK;
@@ -1129,129 +1026,6 @@ int SceneTree::get_node_count() const {
return node_count;
}
-void SceneTree::_update_root_rect() {
-
- if (stretch_mode == STRETCH_MODE_DISABLED) {
-
- _update_font_oversampling(1.0);
- root->set_size((last_screen_size / stretch_shrink).floor());
- root->set_attach_to_screen_rect(Rect2(Point2(), last_screen_size));
- root->set_size_override_stretch(false);
- root->set_size_override(false, Size2());
- root->update_canvas_items();
- return; //user will take care
- }
-
- //actual screen video mode
- Size2 video_mode = Size2(OS::get_singleton()->get_window_size().width, OS::get_singleton()->get_window_size().height);
- Size2 desired_res = stretch_min;
-
- Size2 viewport_size;
- Size2 screen_size;
-
- float viewport_aspect = desired_res.aspect();
- float video_mode_aspect = video_mode.aspect();
-
- if (use_font_oversampling && stretch_aspect == STRETCH_ASPECT_IGNORE) {
- WARN_PRINT("Font oversampling only works with the resize modes 'Keep Width', 'Keep Height', and 'Expand'.");
- }
-
- if (stretch_aspect == STRETCH_ASPECT_IGNORE || Math::is_equal_approx(viewport_aspect, video_mode_aspect)) {
- //same aspect or ignore aspect
- viewport_size = desired_res;
- screen_size = video_mode;
- } else if (viewport_aspect < video_mode_aspect) {
- // screen ratio is smaller vertically
-
- if (stretch_aspect == STRETCH_ASPECT_KEEP_HEIGHT || stretch_aspect == STRETCH_ASPECT_EXPAND) {
-
- //will stretch horizontally
- viewport_size.x = desired_res.y * video_mode_aspect;
- viewport_size.y = desired_res.y;
- screen_size = video_mode;
-
- } else {
- //will need black bars
- viewport_size = desired_res;
- screen_size.x = video_mode.y * viewport_aspect;
- screen_size.y = video_mode.y;
- }
- } else {
- //screen ratio is smaller horizontally
- if (stretch_aspect == STRETCH_ASPECT_KEEP_WIDTH || stretch_aspect == STRETCH_ASPECT_EXPAND) {
-
- //will stretch horizontally
- viewport_size.x = desired_res.x;
- viewport_size.y = desired_res.x / video_mode_aspect;
- screen_size = video_mode;
-
- } else {
- //will need black bars
- viewport_size = desired_res;
- screen_size.x = video_mode.x;
- screen_size.y = video_mode.x / viewport_aspect;
- }
- }
-
- screen_size = screen_size.floor();
- viewport_size = viewport_size.floor();
-
- Size2 margin;
- Size2 offset;
- //black bars and margin
- if (stretch_aspect != STRETCH_ASPECT_EXPAND && screen_size.x < video_mode.x) {
- margin.x = Math::round((video_mode.x - screen_size.x) / 2.0);
- VisualServer::get_singleton()->black_bars_set_margins(margin.x, 0, margin.x, 0);
- offset.x = Math::round(margin.x * viewport_size.y / screen_size.y);
- } else if (stretch_aspect != STRETCH_ASPECT_EXPAND && screen_size.y < video_mode.y) {
- margin.y = Math::round((video_mode.y - screen_size.y) / 2.0);
- VisualServer::get_singleton()->black_bars_set_margins(0, margin.y, 0, margin.y);
- offset.y = Math::round(margin.y * viewport_size.x / screen_size.x);
- } else {
- VisualServer::get_singleton()->black_bars_set_margins(0, 0, 0, 0);
- }
-
- switch (stretch_mode) {
- case STRETCH_MODE_DISABLED: {
- // Already handled above
- _update_font_oversampling(1.0);
- } break;
- case STRETCH_MODE_2D: {
-
- _update_font_oversampling(screen_size.x / viewport_size.x); //screen / viewport radio drives oversampling
- root->set_size((screen_size / stretch_shrink).floor());
- root->set_attach_to_screen_rect(Rect2(margin, screen_size));
- root->set_size_override_stretch(true);
- root->set_size_override(true, (viewport_size / stretch_shrink).floor());
- root->update_canvas_items(); //force them to update just in case
-
- } break;
- case STRETCH_MODE_VIEWPORT: {
-
- _update_font_oversampling(1.0);
- root->set_size((viewport_size / stretch_shrink).floor());
- root->set_attach_to_screen_rect(Rect2(margin, screen_size));
- root->set_size_override_stretch(false);
- root->set_size_override(false, Size2());
- root->update_canvas_items(); //force them to update just in case
-
- if (use_font_oversampling) {
- WARN_PRINT("Font oversampling does not work in 'Viewport' stretch mode, only '2D'.");
- }
-
- } break;
- }
-}
-
-void SceneTree::set_screen_stretch(StretchMode p_mode, StretchAspect p_aspect, const Size2 &p_minsize, real_t p_shrink) {
-
- stretch_mode = p_mode;
- stretch_aspect = p_aspect;
- stretch_min = p_minsize;
- stretch_shrink = p_shrink;
- _update_root_rect();
-}
-
void SceneTree::set_edited_scene_root(Node *p_node) {
#ifdef TOOLS_ENABLED
edited_scene_root = p_node;
@@ -1263,7 +1037,7 @@ Node *SceneTree::get_edited_scene_root() const {
#ifdef TOOLS_ENABLED
return edited_scene_root;
#else
- return NULL;
+ return nullptr;
#endif
}
@@ -1282,7 +1056,7 @@ void SceneTree::_change_scene(Node *p_to) {
if (current_scene) {
memdelete(current_scene);
- current_scene = NULL;
+ current_scene = nullptr;
}
// If we're quitting, abort.
@@ -1308,7 +1082,7 @@ Error SceneTree::change_scene(const String &p_path) {
}
Error SceneTree::change_scene_to(const Ref<PackedScene> &p_scene) {
- Node *new_scene = NULL;
+ Node *new_scene = nullptr;
if (p_scene.is_valid()) {
new_scene = p_scene->instance();
ERR_FAIL_COND_V(!new_scene, ERR_CANT_CREATE);
@@ -1330,18 +1104,6 @@ void SceneTree::add_current_scene(Node *p_current) {
root->add_child(p_current);
}
-void SceneTree::drop_files(const Vector<String> &p_files, int p_from_screen) {
-
- emit_signal("files_dropped", p_files, p_from_screen);
- MainLoop::drop_files(p_files, p_from_screen);
-}
-
-void SceneTree::global_menu_action(const Variant &p_id, const Variant &p_meta) {
-
- emit_signal("global_menu_action", p_id, p_meta);
- MainLoop::global_menu_action(p_id, p_meta);
-}
-
Ref<SceneTreeTimer> SceneTree::create_timer(float p_delay_sec, bool p_process_pause) {
Ref<SceneTreeTimer> stt;
@@ -1469,8 +1231,6 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pause", "enable"), &SceneTree::set_pause);
ClassDB::bind_method(D_METHOD("is_paused"), &SceneTree::is_paused);
- ClassDB::bind_method(D_METHOD("set_input_as_handled"), &SceneTree::set_input_as_handled);
- ClassDB::bind_method(D_METHOD("is_input_handled"), &SceneTree::is_input_handled);
ClassDB::bind_method(D_METHOD("create_timer", "time_sec", "pause_mode_process"), &SceneTree::create_timer, DEFVAL(true));
@@ -1478,8 +1238,6 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_frame"), &SceneTree::get_frame);
ClassDB::bind_method(D_METHOD("quit", "exit_code"), &SceneTree::quit, DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("set_screen_stretch", "mode", "aspect", "minsize", "shrink"), &SceneTree::set_screen_stretch, DEFVAL(1));
-
ClassDB::bind_method(D_METHOD("queue_delete", "obj"), &SceneTree::queue_delete);
MethodInfo mi;
@@ -1529,15 +1287,11 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_refuse_new_network_connections", "refuse"), &SceneTree::set_refuse_new_network_connections);
ClassDB::bind_method(D_METHOD("is_refusing_new_network_connections"), &SceneTree::is_refusing_new_network_connections);
- ClassDB::bind_method(D_METHOD("set_use_font_oversampling", "enable"), &SceneTree::set_use_font_oversampling);
- ClassDB::bind_method(D_METHOD("is_using_font_oversampling"), &SceneTree::is_using_font_oversampling);
-
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_collisions_hint"), "set_debug_collisions_hint", "is_debugging_collisions_hint");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_navigation_hint"), "set_debug_navigation_hint", "is_debugging_navigation_hint");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "paused"), "set_pause", "is_paused");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_network_connections"), "set_refuse_new_network_connections", "is_refusing_new_network_connections");
ADD_PROPERTY_DEFAULT("refuse_new_network_connections", false);
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_font_oversampling"), "set_use_font_oversampling", "is_using_font_oversampling");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "edited_scene_root", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_edited_scene_root", "get_edited_scene_root");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "current_scene", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_current_scene", "get_current_scene");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "network_peer", PROPERTY_HINT_RESOURCE_TYPE, "NetworkedMultiplayerPeer", 0), "set_network_peer", "get_network_peer");
@@ -1549,14 +1303,12 @@ void SceneTree::_bind_methods() {
ADD_SIGNAL(MethodInfo("node_added", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("node_removed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("node_renamed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
- ADD_SIGNAL(MethodInfo("screen_resized"));
ADD_SIGNAL(MethodInfo("node_configuration_warning_changed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("idle_frame"));
ADD_SIGNAL(MethodInfo("physics_frame"));
ADD_SIGNAL(MethodInfo("files_dropped", PropertyInfo(Variant::PACKED_STRING_ARRAY, "files"), PropertyInfo(Variant::INT, "screen")));
- ADD_SIGNAL(MethodInfo("global_menu_action", PropertyInfo(Variant::NIL, "id"), PropertyInfo(Variant::NIL, "meta")));
ADD_SIGNAL(MethodInfo("network_peer_connected", PropertyInfo(Variant::INT, "id")));
ADD_SIGNAL(MethodInfo("network_peer_disconnected", PropertyInfo(Variant::INT, "id")));
ADD_SIGNAL(MethodInfo("connected_to_server"));
@@ -1567,19 +1319,9 @@ void SceneTree::_bind_methods() {
BIND_ENUM_CONSTANT(GROUP_CALL_REVERSE);
BIND_ENUM_CONSTANT(GROUP_CALL_REALTIME);
BIND_ENUM_CONSTANT(GROUP_CALL_UNIQUE);
-
- BIND_ENUM_CONSTANT(STRETCH_MODE_DISABLED);
- BIND_ENUM_CONSTANT(STRETCH_MODE_2D);
- BIND_ENUM_CONSTANT(STRETCH_MODE_VIEWPORT);
-
- BIND_ENUM_CONSTANT(STRETCH_ASPECT_IGNORE);
- BIND_ENUM_CONSTANT(STRETCH_ASPECT_KEEP);
- BIND_ENUM_CONSTANT(STRETCH_ASPECT_KEEP_WIDTH);
- BIND_ENUM_CONSTANT(STRETCH_ASPECT_KEEP_HEIGHT);
- BIND_ENUM_CONSTANT(STRETCH_ASPECT_EXPAND);
}
-SceneTree *SceneTree::singleton = NULL;
+SceneTree *SceneTree::singleton = nullptr;
SceneTree::IdleCallback SceneTree::idle_callbacks[SceneTree::MAX_IDLE_CALLBACKS];
int SceneTree::idle_callback_count = 0;
@@ -1596,19 +1338,6 @@ void SceneTree::add_idle_callback(IdleCallback p_callback) {
idle_callbacks[idle_callback_count++] = p_callback;
}
-void SceneTree::set_use_font_oversampling(bool p_oversampling) {
-
- if (use_font_oversampling == p_oversampling)
- return;
-
- use_font_oversampling = p_oversampling;
- _update_root_rect();
-}
-
-bool SceneTree::is_using_font_oversampling() const {
- return use_font_oversampling;
-}
-
void SceneTree::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
if (p_function == "change_scene") {
@@ -1643,12 +1372,11 @@ void SceneTree::get_argument_options(const StringName &p_function, int p_idx, Li
SceneTree::SceneTree() {
- if (singleton == NULL) singleton = this;
+ if (singleton == nullptr) singleton = this;
_quit = false;
accept_quit = true;
quit_on_go_back = true;
initialized = false;
- use_font_oversampling = false;
#ifdef DEBUG_ENABLED
debug_collisions_hint = false;
debug_navigation_hint = false;
@@ -1664,8 +1392,7 @@ SceneTree::SceneTree() {
physics_process_time = 1;
idle_process_time = 1;
- root = NULL;
- input_handled = false;
+ root = nullptr;
pause = false;
current_frame = 0;
current_event = 0;
@@ -1680,11 +1407,10 @@ SceneTree::SceneTree() {
//create with mainloop
- root = memnew(Viewport);
+ root = memnew(Window);
root->set_name("root");
- root->set_handle_input_locally(false);
if (!root->get_world().is_valid())
- root->set_world(Ref<World>(memnew(World)));
+ root->set_world(Ref<World3D>(memnew(World3D)));
// Initialize network state
multiplayer_poll = true;
@@ -1693,12 +1419,16 @@ SceneTree::SceneTree() {
//root->set_world_2d( Ref<World2D>( memnew( World2D )));
root->set_as_audio_listener(true);
root->set_as_audio_listener_2d(true);
- current_scene = NULL;
+ current_scene = nullptr;
- int msaa_mode = GLOBAL_DEF("rendering/quality/filters/msaa", 0);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/msaa", PropertyInfo(Variant::INT, "rendering/quality/filters/msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x,AndroidVR 2x,AndroidVR 4x"));
+ int msaa_mode = GLOBAL_DEF("rendering/quality/screen_filters/msaa", 0);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_filters/msaa", PropertyInfo(Variant::INT, "rendering/quality/screen_filters/msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x"));
root->set_msaa(Viewport::MSAA(msaa_mode));
+ int ssaa_mode = GLOBAL_DEF("rendering/quality/screen_filters/screen_space_aa", 0);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_filters/screen_space_aa", PropertyInfo(Variant::INT, "rendering/quality/screen_filters/screen_space_aa", PROPERTY_HINT_ENUM, "Disabled,FXAA"));
+ root->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode));
+
{ //load default fallback environment
//get possible extensions
List<String> exts;
@@ -1730,26 +1460,23 @@ SceneTree::SceneTree() {
}
}
- stretch_mode = STRETCH_MODE_DISABLED;
- stretch_aspect = STRETCH_ASPECT_IGNORE;
- stretch_shrink = 1;
-
- last_screen_size = Size2(OS::get_singleton()->get_window_size().width, OS::get_singleton()->get_window_size().height);
- _update_root_rect();
-
root->set_physics_object_picking(GLOBAL_DEF("physics/common/enable_object_picking", true));
+ root->connect("close_requested", callable_mp(this, &SceneTree::_main_window_close));
+ root->connect("go_back_requested", callable_mp(this, &SceneTree::_main_window_go_back));
+ root->connect("focus_entered", callable_mp(this, &SceneTree::_main_window_focus_in));
+
#ifdef TOOLS_ENABLED
- edited_scene_root = NULL;
+ edited_scene_root = nullptr;
#endif
}
SceneTree::~SceneTree() {
if (root) {
- root->_set_tree(NULL);
+ root->_set_tree(nullptr);
root->_propagate_after_exit_tree();
memdelete(root);
}
- if (singleton == this) singleton = NULL;
+ if (singleton == this) singleton = nullptr;
}
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index 2f805d074f..319b5a7e74 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -36,12 +36,14 @@
#include "core/os/thread_safe.h"
#include "core/self_list.h"
#include "scene/resources/mesh.h"
-#include "scene/resources/world.h"
#include "scene/resources/world_2d.h"
+#include "scene/resources/world_3d.h"
+
+#undef Window
class PackedScene;
class Node;
-class Viewport;
+class Window;
class Material;
class Mesh;
class SceneDebugger;
@@ -76,22 +78,6 @@ class SceneTree : public MainLoop {
public:
typedef void (*IdleCallback)();
- enum StretchMode {
-
- STRETCH_MODE_DISABLED,
- STRETCH_MODE_2D,
- STRETCH_MODE_VIEWPORT,
- };
-
- enum StretchAspect {
-
- STRETCH_ASPECT_IGNORE,
- STRETCH_ASPECT_KEEP,
- STRETCH_ASPECT_KEEP_WIDTH,
- STRETCH_ASPECT_KEEP_HEIGHT,
- STRETCH_ASPECT_EXPAND,
- };
-
private:
struct Group {
@@ -101,7 +87,7 @@ private:
Group() { changed = false; };
};
- Viewport *root;
+ Window *root;
uint64_t tree_version;
float physics_process_time;
@@ -119,15 +105,12 @@ private:
Map<StringName, Group> group_map;
bool _quit;
bool initialized;
- bool input_handled;
- Size2 last_screen_size;
StringName tree_changed_name;
StringName node_added_name;
StringName node_removed_name;
StringName node_renamed_name;
- bool use_font_oversampling;
int64_t current_frame;
int64_t current_event;
int node_count;
@@ -147,14 +130,6 @@ private:
int call_lock;
Set<Node *> call_skip; //skip erased nodes
- StretchMode stretch_mode;
- StretchAspect stretch_aspect;
- Size2i stretch_min;
- real_t stretch_shrink;
-
- void _update_font_oversampling(float p_ratio);
- void _update_root_rect();
-
List<ObjectID> delete_queue;
Map<UGCall, Vector<Variant>> unique_group_calls;
@@ -208,14 +183,13 @@ private:
void make_group_changed(const StringName &p_group);
void _notify_group_pause(const StringName &p_group, int p_notification);
- void _call_input_pause(const StringName &p_group, const StringName &p_method, const Ref<InputEvent> &p_input);
Variant _call_group_flags(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
Variant _call_group(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
void _flush_delete_queue();
//optimization
friend class CanvasItem;
- friend class Spatial;
+ friend class Node3D;
friend class Viewport;
SelfList<Node>::List xform_change_list;
@@ -232,6 +206,13 @@ private:
static int idle_callback_count;
void _call_idle_callbacks();
+ void _main_window_focus_in();
+ void _main_window_close();
+ void _main_window_go_back();
+
+ //used by viewport
+ void _call_input_pause(const StringName &p_group, const StringName &p_method, const Ref<InputEvent> &p_input, Viewport *p_viewport);
+
protected:
void _notification(int p_notification);
static void _bind_methods();
@@ -249,7 +230,7 @@ public:
GROUP_CALL_MULTILEVEL = 8,
};
- _FORCE_INLINE_ Viewport *get_root() const { return root; }
+ _FORCE_INLINE_ Window *get_root() const { return root; }
void call_group_flags(uint32_t p_call_flags, const StringName &p_group, const StringName &p_function, VARIANT_ARG_LIST);
void notify_group_flags(uint32_t p_call_flags, const StringName &p_group, int p_notification);
@@ -261,8 +242,6 @@ public:
void flush_transform_notifications();
- virtual void input_text(const String &p_text);
- virtual void input_event(const Ref<InputEvent> &p_event);
virtual void init();
virtual bool iteration(float p_time);
@@ -275,8 +254,6 @@ public:
void quit(int p_exit_code = -1);
- void set_input_as_handled();
- bool is_input_handled();
_FORCE_INLINE_ float get_physics_process_time() const { return physics_process_time; }
_FORCE_INLINE_ float get_idle_process_time() const { return idle_process_time; }
@@ -335,11 +312,6 @@ public:
void get_nodes_in_group(const StringName &p_group, List<Node *> *p_list);
bool has_group(const StringName &p_identifier) const;
- void set_screen_stretch(StretchMode p_mode, StretchAspect p_aspect, const Size2 &p_minsize, real_t p_shrink = 1);
-
- void set_use_font_oversampling(bool p_oversampling);
- bool is_using_font_oversampling() const;
-
//void change_scene(const String& p_path);
//Node *get_loaded_scene();
@@ -359,8 +331,6 @@ public:
static SceneTree *get_singleton() { return singleton; }
- void drop_files(const Vector<String> &p_files, int p_from_screen = 0);
- void global_menu_action(const Variant &p_id, const Variant &p_meta);
void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const;
//network API
@@ -388,8 +358,6 @@ public:
~SceneTree();
};
-VARIANT_ENUM_CAST(SceneTree::StretchMode);
-VARIANT_ENUM_CAST(SceneTree::StretchAspect);
VARIANT_ENUM_CAST(SceneTree::GroupCallFlags);
#endif
diff --git a/scene/main/shader_globals_override.cpp b/scene/main/shader_globals_override.cpp
new file mode 100644
index 0000000000..13582cf655
--- /dev/null
+++ b/scene/main/shader_globals_override.cpp
@@ -0,0 +1,257 @@
+#include "shader_globals_override.h"
+
+#include "core/core_string_names.h"
+#include "scene/main/window.h"
+#include "scene/scene_string_names.h"
+
+StringName *ShaderGlobalsOverride::_remap(const StringName &p_name) const {
+
+ StringName *r = param_remaps.getptr(p_name);
+ if (!r) {
+ //not cached, do caching
+ String p = p_name;
+ if (p.begins_with("params/")) {
+ String q = p.replace_first("params/", "");
+ param_remaps[p] = q;
+ r = param_remaps.getptr(q);
+ }
+ }
+
+ return r;
+}
+bool ShaderGlobalsOverride::_set(const StringName &p_name, const Variant &p_value) {
+
+ StringName *r = _remap(p_name);
+
+ if (r) {
+ Override *o = overrides.getptr(*r);
+ if (!o) {
+ Override ov;
+ ov.in_use = false;
+ overrides[*r] = ov;
+ o = overrides.getptr(*r);
+ }
+ if (o) {
+ o->override = p_value;
+ if (active) {
+ RS::get_singleton()->global_variable_set_override(*r, p_value);
+ }
+ o->in_use = p_value.get_type() != Variant::NIL;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ShaderGlobalsOverride::_get(const StringName &p_name, Variant &r_ret) const {
+
+ StringName *r = _remap(p_name);
+
+ if (r) {
+ const Override *o = overrides.getptr(*r);
+ if (o) {
+ r_ret = o->override;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void ShaderGlobalsOverride::_get_property_list(List<PropertyInfo> *p_list) const {
+
+ Vector<StringName> variables;
+ variables = RS::get_singleton()->global_variable_get_list();
+ for (int i = 0; i < variables.size(); i++) {
+ PropertyInfo pinfo;
+ pinfo.name = "params/" + variables[i];
+ pinfo.usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE;
+
+ switch (RS::get_singleton()->global_variable_get_type(variables[i])) {
+ case RS::GLOBAL_VAR_TYPE_BOOL: {
+ pinfo.type = Variant::BOOL;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_BVEC2: {
+ pinfo.type = Variant::INT;
+ pinfo.hint = PROPERTY_HINT_FLAGS;
+ pinfo.hint_string = "x,y";
+ } break;
+ case RS::GLOBAL_VAR_TYPE_BVEC3: {
+ pinfo.type = Variant::INT;
+ pinfo.hint = PROPERTY_HINT_FLAGS;
+ pinfo.hint_string = "x,y,z";
+ } break;
+ case RS::GLOBAL_VAR_TYPE_BVEC4: {
+ pinfo.type = Variant::INT;
+ pinfo.hint = PROPERTY_HINT_FLAGS;
+ pinfo.hint_string = "x,y,z,w";
+ } break;
+ case RS::GLOBAL_VAR_TYPE_INT: {
+ pinfo.type = Variant::INT;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_IVEC2: {
+ pinfo.type = Variant::VECTOR2I;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_IVEC3: {
+ pinfo.type = Variant::VECTOR3I;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_IVEC4: {
+ pinfo.type = Variant::PACKED_INT32_ARRAY;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_RECT2I: {
+ pinfo.type = Variant::RECT2I;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_UINT: {
+ pinfo.type = Variant::INT;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_UVEC2: {
+ pinfo.type = Variant::VECTOR2I;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_UVEC3: {
+ pinfo.type = Variant::VECTOR3I;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_UVEC4: {
+ pinfo.type = Variant::PACKED_INT32_ARRAY;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_FLOAT: {
+ pinfo.type = Variant::FLOAT;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_VEC2: {
+ pinfo.type = Variant::VECTOR2;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_VEC3: {
+ pinfo.type = Variant::VECTOR3;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_VEC4: {
+ pinfo.type = Variant::PLANE;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_RECT2: {
+ pinfo.type = Variant::RECT2;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_COLOR: {
+ pinfo.type = Variant::COLOR;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_MAT2: {
+ pinfo.type = Variant::PACKED_INT32_ARRAY;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_MAT3: {
+ pinfo.type = Variant::BASIS;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_TRANSFORM_2D: {
+ pinfo.type = Variant::TRANSFORM2D;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_TRANSFORM: {
+ pinfo.type = Variant::TRANSFORM;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_MAT4: {
+ pinfo.type = Variant::PACKED_INT32_ARRAY;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_SAMPLER2D: {
+ pinfo.type = Variant::OBJECT;
+ pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;
+ pinfo.hint_string = "Texture2D";
+ } break;
+ case RS::GLOBAL_VAR_TYPE_SAMPLER2DARRAY: {
+ pinfo.type = Variant::OBJECT;
+ pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;
+ pinfo.hint_string = "Texture2DArray";
+ } break;
+ case RS::GLOBAL_VAR_TYPE_SAMPLER3D: {
+ pinfo.type = Variant::OBJECT;
+ pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;
+ pinfo.hint_string = "Texture3D";
+ } break;
+ case RS::GLOBAL_VAR_TYPE_SAMPLERCUBE: {
+ pinfo.type = Variant::OBJECT;
+ pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;
+ pinfo.hint_string = "Cubemap";
+ } break;
+ default: {
+
+ } break;
+ }
+
+ if (!overrides.has(variables[i])) {
+ Override o;
+ o.in_use = false;
+ Callable::CallError ce;
+ o.override = Variant::construct(pinfo.type, NULL, 0, ce);
+ overrides[variables[i]] = o;
+ }
+
+ Override *o = overrides.getptr(variables[i]);
+ if (o->in_use && o->override.get_type() != Variant::NIL) {
+ pinfo.usage |= PROPERTY_USAGE_CHECKED;
+ pinfo.usage |= PROPERTY_USAGE_STORAGE;
+ }
+
+ p_list->push_back(pinfo);
+ }
+}
+
+void ShaderGlobalsOverride::_activate() {
+
+ List<Node *> nodes;
+ get_tree()->get_nodes_in_group(SceneStringNames::get_singleton()->shader_overrides_group_active, &nodes);
+ if (nodes.size() == 0) {
+ //good we are the only override, enable all
+ active = true;
+ add_to_group(SceneStringNames::get_singleton()->shader_overrides_group_active);
+
+ const StringName *K = nullptr;
+ while ((K = overrides.next(K))) {
+ Override *o = overrides.getptr(*K);
+ if (o->in_use && o->override.get_type() != Variant::NIL) {
+ RS::get_singleton()->global_variable_set_override(*K, o->override);
+ }
+ }
+
+ update_configuration_warning(); //may have activated
+ }
+}
+
+void ShaderGlobalsOverride::_notification(int p_what) {
+
+ if (p_what == Node3D::NOTIFICATION_ENTER_TREE) {
+
+ add_to_group(SceneStringNames::get_singleton()->shader_overrides_group);
+ _activate();
+
+ } else if (p_what == Node3D::NOTIFICATION_EXIT_TREE) {
+
+ if (active) {
+ //remove overrides
+ const StringName *K = nullptr;
+ while ((K = overrides.next(K))) {
+ Override *o = overrides.getptr(*K);
+ if (o->in_use) {
+ RS::get_singleton()->global_variable_set_override(*K, Variant());
+ }
+ }
+ }
+
+ remove_from_group(SceneStringNames::get_singleton()->shader_overrides_group_active);
+ remove_from_group(SceneStringNames::get_singleton()->shader_overrides_group);
+ get_tree()->call_group(SceneStringNames::get_singleton()->shader_overrides_group, "_activate"); //another may want to activate when this is removed
+ active = false;
+ }
+}
+
+String ShaderGlobalsOverride::get_configuration_warning() const {
+
+ if (!active) {
+ return TTR("ShaderGlobalsOverride is not active because another node of the same type is in the scene.");
+ }
+
+ return String();
+}
+
+void ShaderGlobalsOverride::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("_activate"), &ShaderGlobalsOverride::_activate);
+}
+
+ShaderGlobalsOverride::ShaderGlobalsOverride() {
+ active = false;
+}
diff --git a/scene/main/shader_globals_override.h b/scene/main/shader_globals_override.h
new file mode 100644
index 0000000000..33d0dc948f
--- /dev/null
+++ b/scene/main/shader_globals_override.h
@@ -0,0 +1,37 @@
+#ifndef SHADER_GLOBALS_OVERRIDE_H
+#define SHADER_GLOBALS_OVERRIDE_H
+
+#include "scene/3d/node_3d.h"
+
+class ShaderGlobalsOverride : public Node {
+
+ GDCLASS(ShaderGlobalsOverride, Node);
+
+ struct Override {
+ bool in_use = false;
+ Variant override;
+ };
+
+ StringName *_remap(const StringName &p_name) const;
+
+ bool active;
+ mutable HashMap<StringName, Override> overrides;
+ mutable HashMap<StringName, StringName> param_remaps;
+
+ void _activate();
+
+protected:
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_ret) const;
+ void _get_property_list(List<PropertyInfo> *p_list) const;
+
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ String get_configuration_warning() const;
+
+ ShaderGlobalsOverride();
+};
+
+#endif // SHADER_GLOBALS_OVERRIDE_H
diff --git a/scene/main/timer.cpp b/scene/main/timer.cpp
index 7c847095e1..7c847095e1 100755..100644
--- a/scene/main/timer.cpp
+++ b/scene/main/timer.cpp
diff --git a/scene/main/timer.h b/scene/main/timer.h
index 044566738e..044566738e 100755..100644
--- a/scene/main/timer.h
+++ b/scene/main/timer.h
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 8ef3bdd04e..51dd22db81 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -32,14 +32,14 @@
#include "core/core_string_names.h"
#include "core/debugger/engine_debugger.h"
-#include "core/os/input.h"
+#include "core/input/input_filter.h"
#include "core/os/os.h"
#include "core/project_settings.h"
#include "scene/2d/collision_object_2d.h"
-#include "scene/3d/camera.h"
-#include "scene/3d/collision_object.h"
-#include "scene/3d/listener.h"
-#include "scene/3d/spatial.h"
+#include "scene/3d/camera_3d.h"
+#include "scene/3d/collision_object_3d.h"
+#include "scene/3d/listener_3d.h"
+#include "scene/3d/node_3d.h"
#include "scene/3d/world_environment.h"
#include "scene/gui/control.h"
#include "scene/gui/label.h"
@@ -49,9 +49,11 @@
#include "scene/gui/popup_menu.h"
#include "scene/main/canvas_layer.h"
#include "scene/main/timer.h"
+#include "scene/main/window.h"
#include "scene/resources/mesh.h"
#include "scene/scene_string_names.h"
-#include "servers/physics_2d_server.h"
+#include "servers/display_server.h"
+#include "servers/physics_server_2d.h"
void ViewportTexture::setup_local_to_scene() {
@@ -59,7 +61,7 @@ void ViewportTexture::setup_local_to_scene() {
vp->viewport_textures.erase(this);
}
- vp = NULL;
+ vp = nullptr;
Node *local_scene = get_local_scene();
if (!local_scene) {
@@ -76,11 +78,11 @@ void ViewportTexture::setup_local_to_scene() {
vp->viewport_textures.insert(this);
if (proxy_ph.is_valid()) {
- VS::get_singleton()->texture_proxy_update(proxy, vp->texture_rid);
- VS::get_singleton()->free(proxy_ph);
+ RS::get_singleton()->texture_proxy_update(proxy, vp->texture_rid);
+ RS::get_singleton()->free(proxy_ph);
} else {
ERR_FAIL_COND(proxy.is_valid()); //should be invalid
- proxy = VS::get_singleton()->texture_proxy_create(vp->texture_rid);
+ proxy = RS::get_singleton()->texture_proxy_create(vp->texture_rid);
}
}
@@ -120,8 +122,8 @@ RID ViewportTexture::get_rid() const {
//ERR_FAIL_COND_V_MSG(!vp, RID(), "Viewport Texture must be set to use it.");
if (proxy.is_null()) {
- proxy_ph = VS::get_singleton()->texture_2d_placeholder_create();
- proxy = VS::get_singleton()->texture_proxy_create(proxy_ph);
+ proxy_ph = RS::get_singleton()->texture_2d_placeholder_create();
+ proxy = RS::get_singleton()->texture_proxy_create(proxy_ph);
}
return proxy;
}
@@ -133,7 +135,7 @@ bool ViewportTexture::has_alpha() const {
Ref<Image> ViewportTexture::get_data() const {
ERR_FAIL_COND_V_MSG(!vp, Ref<Image>(), "Viewport Texture must be set to use it.");
- return VS::get_singleton()->texture_2d_get(vp->texture_rid);
+ return RS::get_singleton()->texture_2d_get(vp->texture_rid);
}
void ViewportTexture::_bind_methods() {
@@ -141,12 +143,12 @@ void ViewportTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_viewport_path_in_scene", "path"), &ViewportTexture::set_viewport_path_in_scene);
ClassDB::bind_method(D_METHOD("get_viewport_path_in_scene"), &ViewportTexture::get_viewport_path_in_scene);
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "viewport_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Viewport", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT), "set_viewport_path_in_scene", "get_viewport_path_in_scene");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "viewport_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "SubViewport", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT), "set_viewport_path_in_scene", "get_viewport_path_in_scene");
}
ViewportTexture::ViewportTexture() {
- vp = NULL;
+ vp = nullptr;
set_local_to_scene(true);
}
@@ -157,18 +159,18 @@ ViewportTexture::~ViewportTexture() {
}
if (proxy_ph.is_valid()) {
- VS::get_singleton()->free(proxy_ph);
+ RS::get_singleton()->free(proxy_ph);
}
if (proxy.is_valid()) {
- VS::get_singleton()->free(proxy);
+ RS::get_singleton()->free(proxy);
}
}
/////////////////////////////////////
-class TooltipPanel : public PanelContainer {
+class TooltipPanel : public PopupPanel {
- GDCLASS(TooltipPanel, PanelContainer);
+ GDCLASS(TooltipPanel, PopupPanel);
public:
TooltipPanel(){};
@@ -184,39 +186,25 @@ public:
Viewport::GUI::GUI() {
+ embed_subwindows_hint = false;
+ embedding_subwindows = false;
+
dragging = false;
- mouse_focus = NULL;
- mouse_click_grabber = NULL;
+ mouse_focus = nullptr;
+ forced_mouse_focus = false;
+ mouse_click_grabber = nullptr;
mouse_focus_mask = 0;
- key_focus = NULL;
- mouse_over = NULL;
+ key_focus = nullptr;
+ mouse_over = nullptr;
+ drag_mouse_over = nullptr;
- tooltip = NULL;
- tooltip_popup = NULL;
- tooltip_label = NULL;
- subwindow_visibility_dirty = false;
- subwindow_order_dirty = false;
+ tooltip = nullptr;
+ tooltip_popup = nullptr;
+ tooltip_label = nullptr;
}
/////////////////////////////////////
-void Viewport::_update_stretch_transform() {
-
- if (size_override_stretch && size_override) {
-
- stretch_transform = Transform2D();
- Size2 scale = size / (size_override_size + size_override_margin * 2);
- stretch_transform.scale(scale);
- stretch_transform.elements[2] = size_override_margin * scale;
-
- } else {
-
- stretch_transform = Transform2D();
- }
-
- _update_global_transform();
-}
-
void Viewport::update_worlds() {
if (!is_inside_tree())
@@ -230,7 +218,7 @@ void Viewport::update_worlds() {
find_world()->_update(get_tree()->get_frame());
}
-void Viewport::_collision_object_input_event(CollisionObject *p_object, Camera *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape) {
+void Viewport::_collision_object_input_event(CollisionObject3D *p_object, Camera3D *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape) {
Transform object_transform = p_object->get_global_transform();
Transform camera_transform = p_camera->get_global_transform();
@@ -249,6 +237,191 @@ void Viewport::_collision_object_input_event(CollisionObject *p_object, Camera *
physics_last_id = id;
}
+void Viewport::_sub_window_update_order() {
+
+ for (int i = 0; i < gui.sub_windows.size(); i++) {
+ RS::get_singleton()->canvas_item_set_draw_index(gui.sub_windows[i].canvas_item, i);
+ }
+}
+
+void Viewport::_sub_window_register(Window *p_window) {
+
+ ERR_FAIL_COND(!is_inside_tree());
+ for (int i = 0; i < gui.sub_windows.size(); i++) {
+ ERR_FAIL_COND(gui.sub_windows[i].window == p_window);
+ }
+
+ if (gui.sub_windows.size() == 0) {
+ subwindow_canvas = RS::get_singleton()->canvas_create();
+ RS::get_singleton()->viewport_attach_canvas(viewport, subwindow_canvas);
+ RS::get_singleton()->viewport_set_canvas_stacking(viewport, subwindow_canvas, SUBWINDOW_CANVAS_LAYER, 0);
+ }
+ SubWindow sw;
+ sw.canvas_item = RS::get_singleton()->canvas_item_create();
+ RS::get_singleton()->canvas_item_set_parent(sw.canvas_item, subwindow_canvas);
+ sw.window = p_window;
+ gui.sub_windows.push_back(sw);
+
+ _sub_window_grab_focus(p_window);
+
+ RenderingServer::get_singleton()->viewport_set_parent_viewport(p_window->viewport, viewport);
+}
+
+void Viewport::_sub_window_update(Window *p_window) {
+
+ int index = -1;
+ for (int i = 0; i < gui.sub_windows.size(); i++) {
+ if (gui.sub_windows[i].window == p_window) {
+ index = i;
+ break;
+ }
+ }
+
+ ERR_FAIL_COND(index == -1);
+
+ const SubWindow &sw = gui.sub_windows[index];
+
+ Transform2D pos;
+ pos.set_origin(p_window->get_position());
+ RS::get_singleton()->canvas_item_clear(sw.canvas_item);
+ Rect2i r = Rect2i(p_window->get_position(), sw.window->get_size());
+
+ if (!p_window->get_flag(Window::FLAG_BORDERLESS)) {
+ Ref<StyleBox> panel = p_window->get_theme_stylebox("panel_window");
+ panel->draw(sw.canvas_item, r);
+
+ // Draw the title bar text.
+ Ref<Font> title_font = p_window->get_theme_font("title_font");
+ Color title_color = p_window->get_theme_color("title_color");
+ int title_height = p_window->get_theme_constant("title_height");
+ int font_height = title_font->get_height() - title_font->get_descent() * 2;
+ int x = (r.size.width - title_font->get_string_size(p_window->get_title()).x) / 2;
+ int y = (-title_height + font_height) / 2;
+
+ int close_h_ofs = p_window->get_theme_constant("close_h_ofs");
+ int close_v_ofs = p_window->get_theme_constant("close_v_ofs");
+
+ title_font->draw(sw.canvas_item, r.position + Point2(x, y), p_window->get_title(), title_color, r.size.width - panel->get_minimum_size().x - close_h_ofs);
+
+ bool hl = gui.subwindow_focused == sw.window && gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE && gui.subwindow_drag_close_inside;
+
+ Ref<Texture2D> close_icon = p_window->get_theme_icon(hl ? "close_highlight" : "close");
+ close_icon->draw(sw.canvas_item, r.position + Vector2(r.size.width - close_h_ofs, -close_v_ofs));
+ }
+
+ RS::get_singleton()->canvas_item_add_texture_rect(sw.canvas_item, r, sw.window->get_texture()->get_rid());
+}
+
+void Viewport::_sub_window_grab_focus(Window *p_window) {
+
+ if (p_window == nullptr) {
+ //release current focus
+ if (gui.subwindow_focused) {
+ gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT);
+ gui.subwindow_focused = nullptr;
+ gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED;
+ }
+
+ Window *this_window = Object::cast_to<Window>(this);
+ if (this_window) {
+ this_window->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN);
+ }
+
+ return;
+ }
+
+ int index = -1;
+ for (int i = 0; i < gui.sub_windows.size(); i++) {
+ if (gui.sub_windows[i].window == p_window) {
+ index = i;
+ break;
+ }
+ }
+
+ ERR_FAIL_COND(index == -1);
+
+ if (p_window->get_flag(Window::FLAG_NO_FOCUS)) {
+ //can only move to foreground, but no focus granted
+ SubWindow sw = gui.sub_windows[index];
+ gui.sub_windows.remove(index);
+ gui.sub_windows.push_back(sw);
+ index = gui.sub_windows.size() - 1;
+ _sub_window_update_order();
+ return; //i guess not...
+ }
+
+ if (gui.subwindow_focused) {
+ if (gui.subwindow_focused == p_window) {
+ return; //nothing to do
+ }
+ gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT);
+ gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED;
+ } else {
+ Window *this_window = Object::cast_to<Window>(this);
+ if (this_window) {
+ this_window->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT);
+ }
+ }
+
+ Window *old_focus = gui.subwindow_focused;
+
+ gui.subwindow_focused = p_window;
+
+ gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN);
+
+ { //move to foreground
+ SubWindow sw = gui.sub_windows[index];
+ gui.sub_windows.remove(index);
+ gui.sub_windows.push_back(sw);
+ index = gui.sub_windows.size() - 1;
+ _sub_window_update_order();
+ }
+
+ if (old_focus) {
+ _sub_window_update(old_focus);
+ }
+
+ _sub_window_update(p_window);
+}
+
+void Viewport::_sub_window_remove(Window *p_window) {
+
+ for (int i = 0; i < gui.sub_windows.size(); i++) {
+ if (gui.sub_windows[i].window == p_window) {
+ RS::get_singleton()->free(gui.sub_windows[i].canvas_item);
+ gui.sub_windows.remove(i);
+ break;
+ }
+ }
+
+ if (gui.sub_windows.size() == 0) {
+ RS::get_singleton()->free(subwindow_canvas);
+ subwindow_canvas = RID();
+ }
+
+ if (gui.subwindow_focused == p_window) {
+ Window *parent_visible = p_window->get_parent_visible_window();
+
+ gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED;
+
+ gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT);
+
+ if (parent_visible && parent_visible != this) {
+
+ gui.subwindow_focused = parent_visible;
+ gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN);
+ } else {
+ gui.subwindow_focused = nullptr;
+ Window *this_window = Object::cast_to<Window>(this);
+ if (this_window) {
+ this_window->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN);
+ }
+ }
+ }
+
+ RenderingServer::get_singleton()->viewport_set_parent_viewport(p_window->viewport, p_window->parent ? p_window->parent->viewport : RID());
+}
+
void Viewport::_own_world_changed() {
ERR_FAIL_COND(world.is_null());
ERR_FAIL_COND(own_world.is_null());
@@ -264,7 +437,7 @@ void Viewport::_own_world_changed() {
}
if (is_inside_tree()) {
- VisualServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
+ RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
}
_update_listener();
@@ -276,16 +449,18 @@ void Viewport::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
+ gui.embedding_subwindows = gui.embed_subwindows_hint;
+
if (get_parent()) {
parent = get_parent()->get_viewport();
- VisualServer::get_singleton()->viewport_set_parent_viewport(viewport, parent->get_viewport_rid());
+ RenderingServer::get_singleton()->viewport_set_parent_viewport(viewport, parent->get_viewport_rid());
} else {
- parent = NULL;
+ parent = nullptr;
}
current_canvas = find_world_2d()->get_canvas();
- VisualServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
- VisualServer::get_singleton()->viewport_attach_canvas(viewport, current_canvas);
+ RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
+ RenderingServer::get_singleton()->viewport_attach_canvas(viewport, current_canvas);
_update_listener();
_update_listener_2d();
@@ -295,30 +470,29 @@ void Viewport::_notification(int p_what) {
add_to_group("_viewports");
if (get_tree()->is_debugging_collisions_hint()) {
//2D
- Physics2DServer::get_singleton()->space_set_debug_contacts(find_world_2d()->get_space(), get_tree()->get_collision_debug_contact_count());
- contact_2d_debug = VisualServer::get_singleton()->canvas_item_create();
- VisualServer::get_singleton()->canvas_item_set_parent(contact_2d_debug, find_world_2d()->get_canvas());
+ PhysicsServer2D::get_singleton()->space_set_debug_contacts(find_world_2d()->get_space(), get_tree()->get_collision_debug_contact_count());
+ contact_2d_debug = RenderingServer::get_singleton()->canvas_item_create();
+ RenderingServer::get_singleton()->canvas_item_set_parent(contact_2d_debug, find_world_2d()->get_canvas());
//3D
- PhysicsServer::get_singleton()->space_set_debug_contacts(find_world()->get_space(), get_tree()->get_collision_debug_contact_count());
- contact_3d_debug_multimesh = VisualServer::get_singleton()->multimesh_create();
- VisualServer::get_singleton()->multimesh_allocate(contact_3d_debug_multimesh, get_tree()->get_collision_debug_contact_count(), VS::MULTIMESH_TRANSFORM_3D, true);
- VisualServer::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh, 0);
- VisualServer::get_singleton()->multimesh_set_mesh(contact_3d_debug_multimesh, get_tree()->get_debug_contact_mesh()->get_rid());
- contact_3d_debug_instance = VisualServer::get_singleton()->instance_create();
- VisualServer::get_singleton()->instance_set_base(contact_3d_debug_instance, contact_3d_debug_multimesh);
- VisualServer::get_singleton()->instance_set_scenario(contact_3d_debug_instance, find_world()->get_scenario());
- //VisualServer::get_singleton()->instance_geometry_set_flag(contact_3d_debug_instance, VS::INSTANCE_FLAG_VISIBLE_IN_ALL_ROOMS, true);
- }
-
- VS::get_singleton()->viewport_set_active(viewport, true);
+ PhysicsServer3D::get_singleton()->space_set_debug_contacts(find_world()->get_space(), get_tree()->get_collision_debug_contact_count());
+ contact_3d_debug_multimesh = RenderingServer::get_singleton()->multimesh_create();
+ RenderingServer::get_singleton()->multimesh_allocate(contact_3d_debug_multimesh, get_tree()->get_collision_debug_contact_count(), RS::MULTIMESH_TRANSFORM_3D, true);
+ RenderingServer::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh, 0);
+ RenderingServer::get_singleton()->multimesh_set_mesh(contact_3d_debug_multimesh, get_tree()->get_debug_contact_mesh()->get_rid());
+ contact_3d_debug_instance = RenderingServer::get_singleton()->instance_create();
+ RenderingServer::get_singleton()->instance_set_base(contact_3d_debug_instance, contact_3d_debug_multimesh);
+ RenderingServer::get_singleton()->instance_set_scenario(contact_3d_debug_instance, find_world()->get_scenario());
+ //RenderingServer::get_singleton()->instance_geometry_set_flag(contact_3d_debug_instance, RS::INSTANCE_FLAG_VISIBLE_IN_ALL_ROOMS, true);
+ }
+
} break;
case NOTIFICATION_READY: {
#ifndef _3D_DISABLED
if (listeners.size() && !listener) {
- Listener *first = NULL;
- for (Set<Listener *>::Element *E = listeners.front(); E; E = E->next()) {
+ Listener3D *first = nullptr;
+ for (Set<Listener3D *>::Element *E = listeners.front(); E; E = E->next()) {
- if (first == NULL || first->is_greater_than(E->get())) {
+ if (first == nullptr || first->is_greater_than(E->get())) {
first = E->get();
}
}
@@ -329,10 +503,10 @@ void Viewport::_notification(int p_what) {
if (cameras.size() && !camera) {
//there are cameras but no current camera, pick first in tree and make it current
- Camera *first = NULL;
- for (Set<Camera *>::Element *E = cameras.front(); E; E = E->next()) {
+ Camera3D *first = nullptr;
+ for (Set<Camera3D *>::Element *E = cameras.front(); E; E = E->next()) {
- if (first == NULL || first->is_greater_than(E->get())) {
+ if (first == nullptr || first->is_greater_than(E->get())) {
first = E->get();
}
}
@@ -353,24 +527,24 @@ void Viewport::_notification(int p_what) {
if (world_2d.is_valid())
world_2d->_remove_viewport(this);
- VisualServer::get_singleton()->viewport_set_scenario(viewport, RID());
- // SpatialSoundServer::get_singleton()->listener_set_space(internal_listener, RID());
- VisualServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas);
+ RenderingServer::get_singleton()->viewport_set_scenario(viewport, RID());
+ RenderingServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas);
if (contact_2d_debug.is_valid()) {
- VisualServer::get_singleton()->free(contact_2d_debug);
+ RenderingServer::get_singleton()->free(contact_2d_debug);
contact_2d_debug = RID();
}
if (contact_3d_debug_multimesh.is_valid()) {
- VisualServer::get_singleton()->free(contact_3d_debug_multimesh);
- VisualServer::get_singleton()->free(contact_3d_debug_instance);
+ RenderingServer::get_singleton()->free(contact_3d_debug_multimesh);
+ RenderingServer::get_singleton()->free(contact_3d_debug_instance);
contact_3d_debug_instance = RID();
contact_3d_debug_multimesh = RID();
}
remove_from_group("_viewports");
- VS::get_singleton()->viewport_set_active(viewport, false);
+ RS::get_singleton()->viewport_set_active(viewport, false);
+ RenderingServer::get_singleton()->viewport_set_parent_viewport(viewport, RID());
} break;
case NOTIFICATION_INTERNAL_PROCESS: {
@@ -387,36 +561,36 @@ void Viewport::_notification(int p_what) {
if (get_tree()->is_debugging_collisions_hint() && contact_2d_debug.is_valid()) {
- VisualServer::get_singleton()->canvas_item_clear(contact_2d_debug);
- VisualServer::get_singleton()->canvas_item_set_draw_index(contact_2d_debug, 0xFFFFF); //very high index
+ RenderingServer::get_singleton()->canvas_item_clear(contact_2d_debug);
+ RenderingServer::get_singleton()->canvas_item_set_draw_index(contact_2d_debug, 0xFFFFF); //very high index
- Vector<Vector2> points = Physics2DServer::get_singleton()->space_get_contacts(find_world_2d()->get_space());
- int point_count = Physics2DServer::get_singleton()->space_get_contact_count(find_world_2d()->get_space());
+ Vector<Vector2> points = PhysicsServer2D::get_singleton()->space_get_contacts(find_world_2d()->get_space());
+ int point_count = PhysicsServer2D::get_singleton()->space_get_contact_count(find_world_2d()->get_space());
Color ccol = get_tree()->get_debug_collision_contact_color();
for (int i = 0; i < point_count; i++) {
- VisualServer::get_singleton()->canvas_item_add_rect(contact_2d_debug, Rect2(points[i] - Vector2(2, 2), Vector2(5, 5)), ccol);
+ RenderingServer::get_singleton()->canvas_item_add_rect(contact_2d_debug, Rect2(points[i] - Vector2(2, 2), Vector2(5, 5)), ccol);
}
}
if (get_tree()->is_debugging_collisions_hint() && contact_3d_debug_multimesh.is_valid()) {
- Vector<Vector3> points = PhysicsServer::get_singleton()->space_get_contacts(find_world()->get_space());
- int point_count = PhysicsServer::get_singleton()->space_get_contact_count(find_world()->get_space());
+ Vector<Vector3> points = PhysicsServer3D::get_singleton()->space_get_contacts(find_world()->get_space());
+ int point_count = PhysicsServer3D::get_singleton()->space_get_contact_count(find_world()->get_space());
- VS::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh, point_count);
+ RS::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh, point_count);
}
- if (physics_object_picking && (to_screen_rect == Rect2() || Input::get_singleton()->get_mouse_mode() != Input::MOUSE_MODE_CAPTURED)) {
+ if (physics_object_picking && (to_screen_rect == Rect2i() || InputFilter::get_singleton()->get_mouse_mode() != InputFilter::MOUSE_MODE_CAPTURED)) {
#ifndef _3D_DISABLED
Vector2 last_pos(1e20, 1e20);
- CollisionObject *last_object = NULL;
+ CollisionObject3D *last_object = nullptr;
ObjectID last_id;
#endif
- PhysicsDirectSpaceState::RayResult result;
- Physics2DDirectSpaceState *ss2d = Physics2DServer::get_singleton()->space_get_direct_state(find_world_2d()->get_space());
+ PhysicsDirectSpaceState3D::RayResult result;
+ PhysicsDirectSpaceState2D *ss2d = PhysicsServer2D::get_singleton()->space_get_direct_state(find_world_2d()->get_space());
if (physics_has_last_mousepos) {
// if no mouse event exists, create a motion one. This is necessary because objects or camera may have moved.
@@ -433,6 +607,7 @@ void Viewport::_notification(int p_what) {
if (!has_mouse_event) {
Ref<InputEventMouseMotion> mm;
mm.instance();
+
mm->set_device(InputEvent::DEVICE_ID_INTERNAL);
mm->set_global_position(physics_last_mousepos);
mm->set_position(physics_last_mousepos);
@@ -522,7 +697,7 @@ void Viewport::_notification(int p_what) {
uint64_t frame = get_tree()->get_frame();
- Physics2DDirectSpaceState::ShapeResult res[64];
+ PhysicsDirectSpaceState2D::ShapeResult res[64];
for (Set<CanvasLayer *>::Element *E = canvas_layers.front(); E; E = E->next()) {
Transform2D canvas_transform;
ObjectID canvas_layer_id;
@@ -597,7 +772,7 @@ void Viewport::_notification(int p_what) {
if (physics_object_capture.is_valid()) {
- CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_capture));
+ CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_capture));
if (co && camera) {
_collision_object_input_event(co, camera, ev, Vector3(), Vector3(), 0);
captured = true;
@@ -630,14 +805,14 @@ void Viewport::_notification(int p_what) {
Vector3 from = camera->project_ray_origin(pos);
Vector3 dir = camera->project_ray_normal(pos);
- PhysicsDirectSpaceState *space = PhysicsServer::get_singleton()->space_get_direct_state(find_world()->get_space());
+ PhysicsDirectSpaceState3D *space = PhysicsServer3D::get_singleton()->space_get_direct_state(find_world()->get_space());
if (space) {
bool col = space->intersect_ray(from, from + dir * 10000, result, Set<RID>(), 0xFFFFFFFF, true, true, true);
ObjectID new_collider;
if (col) {
- CollisionObject *co = Object::cast_to<CollisionObject>(result.collider);
+ CollisionObject3D *co = Object::cast_to<CollisionObject3D>(result.collider);
if (co) {
_collision_object_input_event(co, camera, ev, result.position, result.normal, result.shape);
@@ -654,7 +829,7 @@ void Viewport::_notification(int p_what) {
if (physics_object_over.is_valid()) {
- CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_over));
+ CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_over));
if (co) {
co->_mouse_exit();
}
@@ -662,7 +837,7 @@ void Viewport::_notification(int p_what) {
if (new_collider.is_valid()) {
- CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(new_collider));
+ CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(new_collider));
if (co) {
co->_mouse_enter();
}
@@ -680,13 +855,12 @@ void Viewport::_notification(int p_what) {
}
} break;
- case SceneTree::NOTIFICATION_WM_MOUSE_EXIT:
- case SceneTree::NOTIFICATION_WM_FOCUS_OUT: {
+ case NOTIFICATION_WM_MOUSE_EXIT:
+ case NOTIFICATION_WM_FOCUS_OUT: {
_drop_physics_mouseover();
- if (gui.mouse_focus) {
- //if mouse is being pressed, send a release event
+ if (gui.mouse_focus && !gui.forced_mouse_focus) {
_drop_mouse_focus();
}
} break;
@@ -698,16 +872,6 @@ RID Viewport::get_viewport_rid() const {
return viewport;
}
-void Viewport::set_use_arvr(bool p_use_arvr) {
- arvr = p_use_arvr;
-
- VS::get_singleton()->viewport_set_use_arvr(viewport, arvr);
-}
-
-bool Viewport::use_arvr() {
- return arvr;
-}
-
void Viewport::update_canvas_items() {
if (!is_inside_tree())
return;
@@ -715,48 +879,57 @@ void Viewport::update_canvas_items() {
_update_canvas_items(this);
}
-void Viewport::set_size(const Size2 &p_size) {
+void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_2d_override, const Rect2i &p_to_screen_rect, const Transform2D &p_stretch_transform, bool p_allocated) {
- if (size == p_size.floor())
+ if (size == p_size && size_allocated == p_allocated && stretch_transform == p_stretch_transform && p_size_2d_override == size_2d_override && to_screen_rect != p_to_screen_rect)
return;
- size = p_size.floor();
- VS::get_singleton()->viewport_set_size(viewport, size.width, size.height);
- _update_stretch_transform();
+ size = p_size;
+ size_allocated = p_allocated;
+ size_2d_override = p_size_2d_override;
+ stretch_transform = p_stretch_transform;
+ to_screen_rect = p_to_screen_rect;
+
+ if (p_allocated) {
+ RS::get_singleton()->viewport_set_size(viewport, size.width, size.height);
+ } else {
+ RS::get_singleton()->viewport_set_size(viewport, 0, 0);
+ }
+ _update_global_transform();
+
+ update_canvas_items();
emit_signal("size_changed");
}
+Size2i Viewport::_get_size() const {
+ return size;
+}
+Size2i Viewport::_get_size_2d_override() const {
+ return size_2d_override;
+}
+bool Viewport::_is_size_allocated() const {
+ return size_allocated;
+}
+
Rect2 Viewport::get_visible_rect() const {
Rect2 r;
if (size == Size2()) {
- r = Rect2(Point2(), OS::get_singleton()->get_window_size());
+ r = Rect2(Point2(), DisplayServer::get_singleton()->window_get_size());
} else {
r = Rect2(Point2(), size);
}
- if (size_override) {
- r.size = size_override_size;
+ if (size_2d_override != Size2i()) {
+ r.size = size_2d_override;
}
return r;
}
-Size2 Viewport::get_size() const {
-
- return size;
-}
-
void Viewport::_update_listener() {
- /*
- if (is_inside_tree() && audio_listener && (camera || listener) && (!get_parent() || (Object::cast_to<Control>(get_parent()) && Object::cast_to<Control>(get_parent())->is_visible_in_tree()))) {
- SpatialSoundServer::get_singleton()->listener_set_space(internal_listener, find_world()->get_sound_space());
- } else {
- SpatialSoundServer::get_singleton()->listener_set_space(internal_listener, RID());
- }
-*/
}
void Viewport::_update_listener_2d() {
@@ -805,9 +978,9 @@ void Viewport::enable_canvas_transform_override(bool p_enable) {
override_canvas_transform = p_enable;
if (p_enable) {
- VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform_override);
+ RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform_override);
} else {
- VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform);
+ RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform);
}
}
@@ -822,7 +995,7 @@ void Viewport::set_canvas_transform_override(const Transform2D &p_transform) {
canvas_transform_override = p_transform;
if (override_canvas_transform) {
- VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform_override);
+ RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform_override);
}
}
@@ -835,7 +1008,7 @@ void Viewport::set_canvas_transform(const Transform2D &p_transform) {
canvas_transform = p_transform;
if (!override_canvas_transform) {
- VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform);
+ RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform);
}
}
@@ -848,7 +1021,7 @@ void Viewport::_update_global_transform() {
Transform2D sxform = stretch_transform * global_canvas_transform;
- VisualServer::get_singleton()->viewport_set_global_canvas_transform(viewport, sxform);
+ RenderingServer::get_singleton()->viewport_set_global_canvas_transform(viewport, sxform);
}
void Viewport::set_global_canvas_transform(const Transform2D &p_transform) {
@@ -864,14 +1037,9 @@ Transform2D Viewport::get_global_canvas_transform() const {
}
void Viewport::_listener_transform_changed_notify() {
-
-#ifndef _3D_DISABLED
-//if (listener)
-// SpatialSoundServer::get_singleton()->listener_set_transform(internal_listener, listener->get_listener_transform());
-#endif
}
-void Viewport::_listener_set(Listener *p_listener) {
+void Viewport::_listener_set(Listener3D *p_listener) {
#ifndef _3D_DISABLED
@@ -885,38 +1053,38 @@ void Viewport::_listener_set(Listener *p_listener) {
#endif
}
-bool Viewport::_listener_add(Listener *p_listener) {
+bool Viewport::_listener_add(Listener3D *p_listener) {
listeners.insert(p_listener);
return listeners.size() == 1;
}
-void Viewport::_listener_remove(Listener *p_listener) {
+void Viewport::_listener_remove(Listener3D *p_listener) {
listeners.erase(p_listener);
if (listener == p_listener) {
- listener = NULL;
+ listener = nullptr;
}
}
#ifndef _3D_DISABLED
-void Viewport::_listener_make_next_current(Listener *p_exclude) {
+void Viewport::_listener_make_next_current(Listener3D *p_exclude) {
if (listeners.size() > 0) {
- for (Set<Listener *>::Element *E = listeners.front(); E; E = E->next()) {
+ for (Set<Listener3D *>::Element *E = listeners.front(); E; E = E->next()) {
if (p_exclude == E->get())
continue;
if (!E->get()->is_inside_tree())
continue;
- if (listener != NULL)
+ if (listener != nullptr)
return;
E->get()->make_current();
}
} else {
// Attempt to reset listener to the camera position
- if (camera != NULL) {
+ if (camera != nullptr) {
_update_listener();
_camera_transform_changed_notify();
}
@@ -927,13 +1095,10 @@ void Viewport::_listener_make_next_current(Listener *p_exclude) {
void Viewport::_camera_transform_changed_notify() {
#ifndef _3D_DISABLED
-// If there is an active listener in the scene, it takes priority over the camera
-// if (camera && !listener)
-// SpatialSoundServer::get_singleton()->listener_set_transform(internal_listener, camera->get_camera_transform());
#endif
}
-void Viewport::_camera_set(Camera *p_camera) {
+void Viewport::_camera_set(Camera3D *p_camera) {
#ifndef _3D_DISABLED
@@ -941,18 +1106,20 @@ void Viewport::_camera_set(Camera *p_camera) {
return;
if (camera) {
- camera->notification(Camera::NOTIFICATION_LOST_CURRENT);
+ camera->notification(Camera3D::NOTIFICATION_LOST_CURRENT);
}
+
camera = p_camera;
+
if (!camera_override) {
if (camera)
- VisualServer::get_singleton()->viewport_attach_camera(viewport, camera->get_camera());
+ RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera->get_camera());
else
- VisualServer::get_singleton()->viewport_attach_camera(viewport, RID());
+ RenderingServer::get_singleton()->viewport_attach_camera(viewport, RID());
}
if (camera) {
- camera->notification(Camera::NOTIFICATION_BECAME_CURRENT);
+ camera->notification(Camera3D::NOTIFICATION_BECAME_CURRENT);
}
_update_listener();
@@ -960,31 +1127,31 @@ void Viewport::_camera_set(Camera *p_camera) {
#endif
}
-bool Viewport::_camera_add(Camera *p_camera) {
+bool Viewport::_camera_add(Camera3D *p_camera) {
cameras.insert(p_camera);
return cameras.size() == 1;
}
-void Viewport::_camera_remove(Camera *p_camera) {
+void Viewport::_camera_remove(Camera3D *p_camera) {
cameras.erase(p_camera);
if (camera == p_camera) {
- camera->notification(Camera::NOTIFICATION_LOST_CURRENT);
- camera = NULL;
+ camera->notification(Camera3D::NOTIFICATION_LOST_CURRENT);
+ camera = nullptr;
}
}
#ifndef _3D_DISABLED
-void Viewport::_camera_make_next_current(Camera *p_exclude) {
+void Viewport::_camera_make_next_current(Camera3D *p_exclude) {
- for (Set<Camera *>::Element *E = cameras.front(); E; E = E->next()) {
+ for (Set<Camera3D *>::Element *E = cameras.front(); E; E = E->next()) {
if (p_exclude == E->get())
continue;
if (!E->get()->is_inside_tree())
continue;
- if (camera != NULL)
+ if (camera != nullptr)
return;
E->get()->make_current();
@@ -1005,7 +1172,7 @@ void Viewport::_canvas_layer_remove(CanvasLayer *p_canvas_layer) {
void Viewport::set_transparent_background(bool p_enable) {
transparent_bg = p_enable;
- VS::get_singleton()->viewport_set_transparent_background(viewport, p_enable);
+ RS::get_singleton()->viewport_set_transparent_background(viewport, p_enable);
}
bool Viewport::has_transparent_background() const {
@@ -1024,7 +1191,7 @@ void Viewport::set_world_2d(const Ref<World2D> &p_world_2d) {
if (is_inside_tree()) {
find_world_2d()->_remove_viewport(this);
- VisualServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas);
+ RenderingServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas);
}
if (p_world_2d.is_valid())
@@ -1038,7 +1205,7 @@ void Viewport::set_world_2d(const Ref<World2D> &p_world_2d) {
if (is_inside_tree()) {
current_canvas = find_world_2d()->get_canvas();
- VisualServer::get_singleton()->viewport_attach_canvas(viewport, current_canvas);
+ RenderingServer::get_singleton()->viewport_attach_canvas(viewport, current_canvas);
find_world_2d()->_register_viewport(this, Rect2());
}
}
@@ -1060,17 +1227,20 @@ void Viewport::_propagate_enter_world(Node *p_node) {
if (!p_node->is_inside_tree()) //may not have entered scene yet
return;
- if (Object::cast_to<Spatial>(p_node) || Object::cast_to<WorldEnvironment>(p_node)) {
-
- p_node->notification(Spatial::NOTIFICATION_ENTER_WORLD);
+#ifndef _3D_DISABLED
+ if (Object::cast_to<Node3D>(p_node) || Object::cast_to<WorldEnvironment>(p_node)) {
+ p_node->notification(Node3D::NOTIFICATION_ENTER_WORLD);
} else {
+#endif
Viewport *v = Object::cast_to<Viewport>(p_node);
if (v) {
if (v->world.is_valid() || v->own_world.is_valid())
return;
}
+#ifndef _3D_DISABLED
}
+#endif
}
for (int i = 0; i < p_node->get_child_count(); i++) {
@@ -1097,17 +1267,20 @@ void Viewport::_propagate_exit_world(Node *p_node) {
if (!p_node->is_inside_tree()) //may have exited scene already
return;
- if (Object::cast_to<Spatial>(p_node) || Object::cast_to<WorldEnvironment>(p_node)) {
-
- p_node->notification(Spatial::NOTIFICATION_EXIT_WORLD);
+#ifndef _3D_DISABLED
+ if (Object::cast_to<Node3D>(p_node) || Object::cast_to<WorldEnvironment>(p_node)) {
+ p_node->notification(Node3D::NOTIFICATION_EXIT_WORLD);
} else {
+#endif
Viewport *v = Object::cast_to<Viewport>(p_node);
if (v) {
if (v->world.is_valid() || v->own_world.is_valid())
return;
}
+#ifndef _3D_DISABLED
}
+#endif
}
for (int i = 0; i < p_node->get_child_count(); i++) {
@@ -1116,7 +1289,7 @@ void Viewport::_propagate_exit_world(Node *p_node) {
}
}
-void Viewport::set_world(const Ref<World> &p_world) {
+void Viewport::set_world(const Ref<World3D> &p_world) {
if (world == p_world)
return;
@@ -1135,7 +1308,7 @@ void Viewport::set_world(const Ref<World> &p_world) {
own_world = world->duplicate();
world->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_changed));
} else {
- own_world = Ref<World>(memnew(World));
+ own_world = Ref<World3D>(memnew(World3D));
}
}
@@ -1143,13 +1316,13 @@ void Viewport::set_world(const Ref<World> &p_world) {
_propagate_enter_world(this);
if (is_inside_tree()) {
- VisualServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
+ RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
}
_update_listener();
}
-Ref<World> Viewport::get_world() const {
+Ref<World3D> Viewport::get_world() const {
return world;
}
@@ -1159,7 +1332,7 @@ Ref<World2D> Viewport::get_world_2d() const {
return world_2d;
}
-Ref<World> Viewport::find_world() const {
+Ref<World3D> Viewport::find_world() const {
if (own_world.is_valid())
return own_world;
@@ -1168,15 +1341,15 @@ Ref<World> Viewport::find_world() const {
else if (parent)
return parent->find_world();
else
- return Ref<World>();
+ return Ref<World3D>();
}
-Listener *Viewport::get_listener() const {
+Listener3D *Viewport::get_listener() const {
return listener;
}
-Camera *Viewport::get_camera() const {
+Camera3D *Viewport::get_camera() const {
return camera;
}
@@ -1188,18 +1361,18 @@ void Viewport::enable_camera_override(bool p_enable) {
}
if (p_enable) {
- camera_override.rid = VisualServer::get_singleton()->camera_create();
+ camera_override.rid = RenderingServer::get_singleton()->camera_create();
} else {
- VisualServer::get_singleton()->free(camera_override.rid);
+ RenderingServer::get_singleton()->free(camera_override.rid);
camera_override.rid = RID();
}
if (p_enable) {
- VisualServer::get_singleton()->viewport_attach_camera(viewport, camera_override.rid);
+ RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera_override.rid);
} else if (camera) {
- VisualServer::get_singleton()->viewport_attach_camera(viewport, camera->get_camera());
+ RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera->get_camera());
} else {
- VisualServer::get_singleton()->viewport_attach_camera(viewport, RID());
+ RenderingServer::get_singleton()->viewport_attach_camera(viewport, RID());
}
#endif
}
@@ -1211,7 +1384,7 @@ bool Viewport::is_camera_override_enabled() const {
void Viewport::set_camera_override_transform(const Transform &p_transform) {
if (camera_override) {
camera_override.transform = p_transform;
- VisualServer::get_singleton()->camera_set_transform(camera_override.rid, p_transform);
+ RenderingServer::get_singleton()->camera_set_transform(camera_override.rid, p_transform);
}
}
@@ -1234,7 +1407,7 @@ void Viewport::set_camera_override_perspective(float p_fovy_degrees, float p_z_n
camera_override.z_far = p_z_far;
camera_override.projection = CameraOverrideData::PROJECTION_PERSPECTIVE;
- VisualServer::get_singleton()->camera_set_perspective(camera_override.rid, camera_override.fov, camera_override.z_near, camera_override.z_far);
+ RenderingServer::get_singleton()->camera_set_perspective(camera_override.rid, camera_override.fov, camera_override.z_near, camera_override.z_far);
}
}
@@ -1249,7 +1422,7 @@ void Viewport::set_camera_override_orthogonal(float p_size, float p_z_near, floa
camera_override.z_far = p_z_far;
camera_override.projection = CameraOverrideData::PROJECTION_ORTHOGONAL;
- VisualServer::get_singleton()->camera_set_orthogonal(camera_override.rid, camera_override.size, camera_override.z_near, camera_override.z_far);
+ RenderingServer::get_singleton()->camera_set_orthogonal(camera_override.rid, camera_override.size, camera_override.z_near, camera_override.z_far);
}
}
@@ -1278,77 +1451,18 @@ void Viewport::_update_canvas_items(Node *p_node) {
}
}
-void Viewport::set_size_override(bool p_enable, const Size2 &p_size, const Vector2 &p_margin) {
-
- if (size_override == p_enable && p_size == size_override_size)
- return;
-
- size_override = p_enable;
- if (p_size.x >= 0 || p_size.y >= 0) {
- size_override_size = p_size;
- }
- size_override_margin = p_margin;
-
- _update_stretch_transform();
- emit_signal("size_changed");
-}
-
-Size2 Viewport::get_size_override() const {
-
- return size_override_size;
-}
-bool Viewport::is_size_override_enabled() const {
-
- return size_override;
-}
-void Viewport::set_size_override_stretch(bool p_enable) {
-
- if (p_enable == size_override_stretch)
- return;
-
- size_override_stretch = p_enable;
-
- _update_stretch_transform();
-}
-
-bool Viewport::is_size_override_stretch_enabled() const {
-
- return size_override_stretch;
-}
-
-void Viewport::set_update_mode(UpdateMode p_mode) {
-
- update_mode = p_mode;
- VS::get_singleton()->viewport_set_update_mode(viewport, VS::ViewportUpdateMode(p_mode));
-}
-Viewport::UpdateMode Viewport::get_update_mode() const {
-
- return update_mode;
-}
-
Ref<ViewportTexture> Viewport::get_texture() const {
return default_texture;
}
-void Viewport::set_clear_mode(ClearMode p_mode) {
-
- clear_mode = p_mode;
- VS::get_singleton()->viewport_set_clear_mode(viewport, VS::ViewportClearMode(p_mode));
-}
-
-Viewport::ClearMode Viewport::get_clear_mode() const {
-
- return clear_mode;
-}
-
void Viewport::set_shadow_atlas_size(int p_size) {
if (shadow_atlas_size == p_size)
return;
shadow_atlas_size = p_size;
- VS::get_singleton()->viewport_set_shadow_atlas_size(viewport, p_size);
+ RS::get_singleton()->viewport_set_shadow_atlas_size(viewport, p_size);
}
int Viewport::get_shadow_atlas_size() const {
@@ -1367,7 +1481,7 @@ void Viewport::set_shadow_atlas_quadrant_subdiv(int p_quadrant, ShadowAtlasQuadr
shadow_atlas_quadrant_subdiv[p_quadrant] = p_subdiv;
static const int subdiv[SHADOW_ATLAS_QUADRANT_SUBDIV_MAX] = { 0, 1, 4, 16, 64, 256, 1024 };
- VS::get_singleton()->viewport_set_shadow_atlas_quadrant_subdivision(viewport, p_quadrant, subdiv[p_subdiv]);
+ RS::get_singleton()->viewport_set_shadow_atlas_quadrant_subdivision(viewport, p_quadrant, subdiv[p_subdiv]);
}
Viewport::ShadowAtlasQuadrantSubdiv Viewport::get_shadow_atlas_quadrant_subdiv(int p_quadrant) const {
@@ -1379,7 +1493,7 @@ Transform2D Viewport::_get_input_pre_xform() const {
Transform2D pre_xf;
- if (to_screen_rect != Rect2()) {
+ if (to_screen_rect.size.x != 0 && to_screen_rect.size.y != 0) {
pre_xf.elements[2] = -to_screen_rect.position;
pre_xf.scale(size / to_screen_rect.size);
@@ -1388,118 +1502,22 @@ Transform2D Viewport::_get_input_pre_xform() const {
return pre_xf;
}
-Vector2 Viewport::_get_window_offset() const {
-
- if (get_parent() && get_parent()->has_method("get_global_position")) {
- return get_parent()->call("get_global_position");
- }
- return Vector2();
-}
-
Ref<InputEvent> Viewport::_make_input_local(const Ref<InputEvent> &ev) {
- Vector2 vp_ofs = _get_window_offset();
Transform2D ai = get_final_transform().affine_inverse() * _get_input_pre_xform();
- return ev->xformed_by(ai, -vp_ofs);
-}
-
-void Viewport::_vp_input_text(const String &p_text) {
-
- if (gui.key_focus) {
- gui.key_focus->call("set_text", p_text);
- }
-}
-
-void Viewport::_vp_input(const Ref<InputEvent> &p_ev) {
-
- if (disable_input)
- return;
-
-#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_a_parent_of(this)) {
- return;
- }
-#endif
-
- if (to_screen_rect == Rect2())
- return; //if render target, can't get input events
-
- //this one handles system input, p_ev are in system coordinates
- //they are converted to viewport coordinates
-
- Ref<InputEvent> ev = _make_input_local(p_ev);
- input(ev);
-}
-
-void Viewport::_vp_unhandled_input(const Ref<InputEvent> &p_ev) {
-
- if (disable_input)
- return;
-#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_a_parent_of(this)) {
- return;
- }
-#endif
-
- /*
- if (parent_control && !parent_control->is_visible_in_tree())
- return;
- */
-
- if (to_screen_rect == Rect2())
- return; //if render target, can't get input events
-
- //this one handles system input, p_ev are in system coordinates
- //they are converted to viewport coordinates
-
- Ref<InputEvent> ev = _make_input_local(p_ev);
- unhandled_input(ev);
+ return ev->xformed_by(ai);
}
Vector2 Viewport::get_mouse_position() const {
- return (get_final_transform().affine_inverse() * _get_input_pre_xform()).xform(Input::get_singleton()->get_mouse_position() - _get_window_offset());
+ return gui.last_mouse_pos;
}
void Viewport::warp_mouse(const Vector2 &p_pos) {
Vector2 gpos = (get_final_transform().affine_inverse() * _get_input_pre_xform()).affine_inverse().xform(p_pos);
- Input::get_singleton()->warp_mouse_position(gpos);
-}
-
-void Viewport::_gui_prepare_subwindows() {
-
- if (gui.subwindow_visibility_dirty) {
-
- gui.subwindows.clear();
- for (List<Control *>::Element *E = gui.all_known_subwindows.front(); E; E = E->next()) {
- if (E->get()->is_visible_in_tree()) {
- gui.subwindows.push_back(E->get());
- }
- }
-
- gui.subwindow_visibility_dirty = false;
- gui.subwindow_order_dirty = true;
- }
-
- _gui_sort_subwindows();
-}
-
-void Viewport::_gui_sort_subwindows() {
-
- if (!gui.subwindow_order_dirty)
- return;
-
- gui.modal_stack.sort_custom<Control::CComparator>();
- gui.subwindows.sort_custom<Control::CComparator>();
-
- gui.subwindow_order_dirty = false;
-}
-
-void Viewport::_gui_sort_modal_stack() {
-
- gui.modal_stack.sort_custom<Control::CComparator>();
+ InputFilter::get_singleton()->warp_mouse_position(gpos);
}
void Viewport::_gui_sort_roots() {
@@ -1514,12 +1532,12 @@ void Viewport::_gui_sort_roots() {
void Viewport::_gui_cancel_tooltip() {
- gui.tooltip = NULL;
+ gui.tooltip = nullptr;
gui.tooltip_timer = -1;
if (gui.tooltip_popup) {
gui.tooltip_popup->queue_delete();
- gui.tooltip_popup = NULL;
- gui.tooltip_label = NULL;
+ gui.tooltip_popup = nullptr;
+ gui.tooltip_label = nullptr;
}
}
@@ -1557,7 +1575,7 @@ void Viewport::_gui_show_tooltip() {
return;
}
- Control *which = NULL;
+ Control *which = nullptr;
String tooltip = _gui_get_tooltip(gui.tooltip, gui.tooltip->get_global_transform().xform_inv(gui.tooltip_pos), &which);
tooltip = tooltip.strip_edges();
if (tooltip.length() == 0)
@@ -1565,8 +1583,8 @@ void Viewport::_gui_show_tooltip() {
if (gui.tooltip_popup) {
memdelete(gui.tooltip_popup);
- gui.tooltip_popup = NULL;
- gui.tooltip_label = NULL;
+ gui.tooltip_popup = nullptr;
+ gui.tooltip_label = nullptr;
}
if (!which) {
@@ -1575,47 +1593,49 @@ void Viewport::_gui_show_tooltip() {
Control *rp = which;
- gui.tooltip_popup = which->make_custom_tooltip(tooltip);
-
- if (!gui.tooltip_popup) {
- gui.tooltip_popup = memnew(TooltipPanel);
+ Control *base_tooltip = which->make_custom_tooltip(tooltip);
+ if (!base_tooltip) {
gui.tooltip_label = memnew(TooltipLabel);
- gui.tooltip_popup->add_child(gui.tooltip_label);
-
- Ref<StyleBox> ttp = gui.tooltip_label->get_stylebox("panel", "TooltipPanel");
-
- gui.tooltip_label->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, ttp->get_margin(MARGIN_LEFT));
- gui.tooltip_label->set_anchor_and_margin(MARGIN_TOP, Control::ANCHOR_BEGIN, ttp->get_margin(MARGIN_TOP));
- gui.tooltip_label->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -ttp->get_margin(MARGIN_RIGHT));
- gui.tooltip_label->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, -ttp->get_margin(MARGIN_BOTTOM));
gui.tooltip_label->set_text(tooltip);
+ base_tooltip = gui.tooltip_label;
}
+ base_tooltip->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+
+ TooltipPanel *panel = memnew(TooltipPanel);
+ panel->set_transient(false);
+ panel->set_flag(Window::FLAG_NO_FOCUS, true);
+ panel->set_wrap_controls(true);
+ panel->add_child(base_tooltip);
+
+ gui.tooltip_popup = panel;
+
rp->add_child(gui.tooltip_popup);
- gui.tooltip_popup->force_parent_owned();
- gui.tooltip_popup->set_as_toplevel(true);
- if (gui.tooltip) // Avoids crash when rapidly switching controls.
- gui.tooltip_popup->set_scale(gui.tooltip->get_global_transform().get_scale());
+
+ //if (gui.tooltip) // Avoids crash when rapidly switching controls.
+ // gui.tooltip_popup->set_scale(gui.tooltip->get_global_transform().get_scale());
Point2 tooltip_offset = ProjectSettings::get_singleton()->get("display/mouse_cursor/tooltip_position_offset");
- Rect2 r(gui.tooltip_pos + tooltip_offset, gui.tooltip_popup->get_minimum_size());
- Rect2 vr = gui.tooltip_popup->get_viewport_rect();
- if (r.size.x * gui.tooltip_popup->get_scale().x + r.position.x > vr.size.x)
- r.position.x = vr.size.x - r.size.x * gui.tooltip_popup->get_scale().x;
- else if (r.position.x < 0)
- r.position.x = 0;
-
- if (r.size.y * gui.tooltip_popup->get_scale().y + r.position.y > vr.size.y)
- r.position.y = vr.size.y - r.size.y * gui.tooltip_popup->get_scale().y;
- else if (r.position.y < 0)
- r.position.y = 0;
-
- gui.tooltip_popup->set_global_position(r.position);
+ Rect2 r(gui.tooltip_pos + tooltip_offset, gui.tooltip_popup->get_contents_minimum_size());
+
+ Rect2i vr = gui.tooltip_popup->get_parent_visible_window()->get_usable_parent_rect();
+
+ if (r.size.x + r.position.x > vr.size.x + vr.position.x)
+ r.position.x = vr.position.x + vr.size.x - r.size.x;
+ else if (r.position.x < vr.position.x)
+ r.position.x = vr.position.x;
+
+ if (r.size.y + r.position.y > vr.size.y + vr.position.y)
+ r.position.y = vr.position.y + vr.size.y - r.size.y;
+ else if (r.position.y < vr.position.y)
+ r.position.y = vr.position.y;
+
+ gui.tooltip_popup->set_position(r.position);
gui.tooltip_popup->set_size(r.size);
- gui.tooltip_popup->raise();
gui.tooltip_popup->show();
+ gui.tooltip_popup->child_controls_changed();
}
void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_input) {
@@ -1635,7 +1655,7 @@ void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_inpu
Ref<InputEventPanGesture> pn = p_input;
cant_stop_me_now = pn.is_valid() || cant_stop_me_now;
- bool ismouse = ev.is_valid() || Object::cast_to<InputEventMouseMotion>(*p_input) != NULL;
+ bool ismouse = ev.is_valid() || Object::cast_to<InputEventMouseMotion>(*p_input) != nullptr;
CanvasItem *ci = p_control;
while (ci) {
@@ -1704,26 +1724,7 @@ void Viewport::_gui_call_notification(Control *p_control, int p_what) {
}
Control *Viewport::_gui_find_control(const Point2 &p_global) {
- _gui_prepare_subwindows();
-
- for (List<Control *>::Element *E = gui.subwindows.back(); E; E = E->prev()) {
-
- Control *sw = E->get();
- if (!sw->is_visible_in_tree())
- continue;
-
- Transform2D xform;
- CanvasItem *pci = sw->get_parent_item();
- if (pci)
- xform = pci->get_global_transform_with_canvas();
- else
- xform = sw->get_canvas_transform();
-
- Control *ret = _gui_find_control_at_pos(sw, p_global, xform, gui.focus_inv_xform);
- if (ret)
- return ret;
- }
-
+ //aca va subwindows
_gui_sort_roots();
for (List<Control *>::Element *E = gui.roots.back(); E; E = E->prev()) {
@@ -1744,25 +1745,23 @@ Control *Viewport::_gui_find_control(const Point2 &p_global) {
return ret;
}
- return NULL;
+ return nullptr;
}
Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform, Transform2D &r_inv_xform) {
if (Object::cast_to<Viewport>(p_node))
- return NULL;
-
- //subwindows first!!
+ return nullptr;
if (!p_node->is_visible()) {
//return _find_next_visible_control_at_pos(p_node,p_global,r_inv_xform);
- return NULL; //canvas item hidden, discard
+ return nullptr; //canvas item hidden, discard
}
Transform2D matrix = p_xform * p_node->get_transform();
// matrix.basis_determinant() == 0.0f implies that node does not exist on scene
if (matrix.basis_determinant() == 0.0f)
- return NULL;
+ return nullptr;
Control *c = Object::cast_to<Control>(p_node);
@@ -1770,9 +1769,6 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_
for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
- if (p_node == gui.tooltip_popup)
- continue;
-
CanvasItem *ci = Object::cast_to<CanvasItem>(p_node->get_child(i));
if (!ci || ci->is_set_as_toplevel())
continue;
@@ -1784,7 +1780,7 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_
}
if (!c)
- return NULL;
+ return nullptr;
matrix.affine_invert();
@@ -1793,7 +1789,7 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_
r_inv_xform = matrix;
return c;
} else
- return NULL;
+ return nullptr;
}
bool Viewport::_gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_check) {
@@ -1858,39 +1854,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
bool is_handled = false;
- _gui_sort_modal_stack();
- while (!gui.modal_stack.empty()) {
-
- Control *top = gui.modal_stack.back()->get();
- Vector2 pos2 = top->get_global_transform_with_canvas().affine_inverse().xform(mpos);
- if (!top->has_point(pos2)) {
-
- if (top->data.modal_exclusive || top->data.modal_frame == Engine::get_singleton()->get_frames_drawn()) {
- //cancel event, sorry, modal exclusive EATS UP ALL
- //alternative, you can't pop out a window the same frame it was made modal (fixes many issues)
- set_input_as_handled();
-
- return; // no one gets the event if exclusive NO ONE
- }
-
- if (mb->get_button_index() == BUTTON_WHEEL_UP || mb->get_button_index() == BUTTON_WHEEL_DOWN || mb->get_button_index() == BUTTON_WHEEL_LEFT || mb->get_button_index() == BUTTON_WHEEL_RIGHT) {
- //cancel scroll wheel events, only clicks should trigger focus changes.
- set_input_as_handled();
- return;
- }
-
- top->notification(Control::NOTIFICATION_MODAL_CLOSE);
- top->_modal_stack_remove();
- top->hide();
-
- if (!top->pass_on_modal_close_click()) {
- is_handled = true;
- }
- } else {
- break;
- }
- }
-
if (is_handled) {
set_input_as_handled();
return;
@@ -1979,7 +1942,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (gui.drag_preview) {
memdelete(gui.drag_preview);
- gui.drag_preview = NULL;
+ gui.drag_preview = nullptr;
}
_propagate_viewport_notification(this, NOTIFICATION_DRAG_END);
//change mouse accordingly
@@ -1992,20 +1955,18 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == BUTTON_LEFT) {
- if (gui.mouse_over) {
- Size2 pos = mpos;
- pos = gui.focus_inv_xform.xform(pos);
-
- _gui_drop(gui.mouse_over, pos, false);
+ if (gui.drag_mouse_over) {
+ _gui_drop(gui.drag_mouse_over, gui.drag_mouse_over_pos, false);
}
if (gui.drag_preview && mb->get_button_index() == BUTTON_LEFT) {
memdelete(gui.drag_preview);
- gui.drag_preview = NULL;
+ gui.drag_preview = nullptr;
}
gui.drag_data = Variant();
gui.dragging = false;
+ gui.drag_mouse_over = nullptr;
_propagate_viewport_notification(this, NOTIFICATION_DRAG_END);
//change mouse accordingly
}
@@ -2028,7 +1989,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
//disable mouse focus if needed before calling input, this makes popups on mouse press event work better, as the release will never be received otherwise
if (gui.mouse_focus_mask == 0) {
- gui.mouse_focus = NULL;
+ gui.mouse_focus = nullptr;
+ gui.forced_mouse_focus = false;
}
if (mouse_focus && mouse_focus->can_process()) {
@@ -2053,7 +2015,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.last_mouse_pos = mpos;
- Control *over = NULL;
+ Control *over = nullptr;
// D&D
if (!gui.drag_attempted && gui.mouse_focus && mm->get_button_mask() & BUTTON_MASK_LEFT) {
@@ -2073,14 +2035,15 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.drag_data = control->get_drag_data(control->get_global_transform_with_canvas().affine_inverse().xform(mpos) - gui.drag_accum);
if (gui.drag_data.get_type() != Variant::NIL) {
- gui.mouse_focus = NULL;
+ gui.mouse_focus = nullptr;
+ gui.forced_mouse_focus = false;
gui.mouse_focus_mask = 0;
break;
} else {
- if (gui.drag_preview != NULL) {
+ if (gui.drag_preview != nullptr) {
ERR_PRINT("Don't set a drag preview and return null data. Preview was deleted and drag request ignored.");
memdelete(gui.drag_preview);
- gui.drag_preview = NULL;
+ gui.drag_preview = nullptr;
}
gui.dragging = false;
}
@@ -2113,45 +2076,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
over = _gui_find_control(mpos);
}
- if (gui.drag_data.get_type() == Variant::NIL && over && !gui.modal_stack.empty()) {
-
- Control *top = gui.modal_stack.back()->get();
-
- if (over != top && !top->is_a_parent_of(over)) {
-
- PopupMenu *popup_menu = Object::cast_to<PopupMenu>(top);
- MenuButton *popup_menu_parent = NULL;
- MenuButton *menu_button = Object::cast_to<MenuButton>(over);
-
- if (popup_menu) {
- popup_menu_parent = Object::cast_to<MenuButton>(popup_menu->get_parent());
- if (!popup_menu_parent) {
- // Go through the parents to see if there's a MenuButton at the end.
- while (Object::cast_to<PopupMenu>(popup_menu->get_parent())) {
- popup_menu = Object::cast_to<PopupMenu>(popup_menu->get_parent());
- }
- popup_menu_parent = Object::cast_to<MenuButton>(popup_menu->get_parent());
- }
- }
-
- // If the mouse is over a menu button, this menu will open automatically
- // if there is already a pop-up menu open at the same hierarchical level.
- if (popup_menu_parent && menu_button && popup_menu_parent->is_switch_on_hover() &&
- !menu_button->is_disabled() && menu_button->is_switch_on_hover() &&
- (popup_menu_parent->get_parent()->is_a_parent_of(menu_button) ||
- menu_button->get_parent()->is_a_parent_of(popup_menu))) {
-
- popup_menu->notification(Control::NOTIFICATION_MODAL_CLOSE);
- popup_menu->_modal_stack_remove();
- popup_menu->hide();
-
- menu_button->pressed();
- } else {
- over = NULL; //nothing can be found outside the modal stack
- }
- }
- }
-
if (over != gui.mouse_over) {
if (gui.mouse_over) {
@@ -2167,103 +2091,195 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.mouse_over = over;
- if (gui.drag_preview) {
- gui.drag_preview->set_position(mpos);
- }
+ DisplayServer::CursorShape ds_cursor_shape = (DisplayServer::CursorShape)InputFilter::get_singleton()->get_default_cursor_shape();
- if (!over) {
- OS::get_singleton()->set_cursor_shape((OS::CursorShape)Input::get_singleton()->get_default_cursor_shape());
- return;
- }
+ if (over) {
- Transform2D localizer = over->get_global_transform_with_canvas().affine_inverse();
- Size2 pos = localizer.xform(mpos);
- Vector2 speed = localizer.basis_xform(mm->get_speed());
- Vector2 rel = localizer.basis_xform(mm->get_relative());
+ Transform2D localizer = over->get_global_transform_with_canvas().affine_inverse();
+ Size2 pos = localizer.xform(mpos);
+ Vector2 speed = localizer.basis_xform(mm->get_speed());
+ Vector2 rel = localizer.basis_xform(mm->get_relative());
- mm = mm->xformed_by(Transform2D()); //make a copy
+ mm = mm->xformed_by(Transform2D()); //make a copy
- mm->set_global_position(mpos);
- mm->set_speed(speed);
- mm->set_relative(rel);
+ mm->set_global_position(mpos);
+ mm->set_speed(speed);
+ mm->set_relative(rel);
- if (mm->get_button_mask() == 0) {
- //nothing pressed
+ if (mm->get_button_mask() == 0) {
+ //nothing pressed
- bool can_tooltip = true;
+ bool can_tooltip = true;
- if (!gui.modal_stack.empty()) {
- if (gui.modal_stack.back()->get() != over && !gui.modal_stack.back()->get()->is_a_parent_of(over))
- can_tooltip = false;
- }
+ bool is_tooltip_shown = false;
- bool is_tooltip_shown = false;
+ if (gui.tooltip_popup) {
+ if (can_tooltip && gui.tooltip) {
+ String tooltip = _gui_get_tooltip(over, gui.tooltip->get_global_transform().xform_inv(mpos));
- if (gui.tooltip_popup) {
- if (can_tooltip && gui.tooltip) {
- String tooltip = _gui_get_tooltip(over, gui.tooltip->get_global_transform().xform_inv(mpos));
+ if (tooltip.length() == 0)
+ _gui_cancel_tooltip();
+ else if (gui.tooltip_label) {
+ if (tooltip == gui.tooltip_label->get_text()) {
+ is_tooltip_shown = true;
+ }
+ } else {
- if (tooltip.length() == 0)
- _gui_cancel_tooltip();
- else if (gui.tooltip_label) {
- if (tooltip == gui.tooltip_label->get_text()) {
- is_tooltip_shown = true;
+ Variant t = gui.tooltip_popup->call("get_tooltip_text");
+
+ if (t.get_type() == Variant::STRING) {
+ if (tooltip == String(t)) {
+ is_tooltip_shown = true;
+ }
+ } else {
+ is_tooltip_shown = true; //well, nothing to compare against, likely using custom control, so if it changes there is nothing we can do
+ }
}
- } else if (tooltip == String(gui.tooltip_popup->call("get_tooltip_text"))) {
- is_tooltip_shown = true;
- }
- } else
- _gui_cancel_tooltip();
+ } else
+ _gui_cancel_tooltip();
+ }
+
+ if (can_tooltip && !is_tooltip_shown) {
+
+ gui.tooltip = over;
+ gui.tooltip_pos = over->get_screen_transform().xform(pos); //(parent_xform * get_transform()).affine_inverse().xform(pos);
+ gui.tooltip_timer = gui.tooltip_delay;
+ }
}
- if (can_tooltip && !is_tooltip_shown) {
+ //pos = gui.focus_inv_xform.xform(pos);
+
+ mm->set_position(pos);
- gui.tooltip = over;
- gui.tooltip_pos = mpos; //(parent_xform * get_transform()).affine_inverse().xform(pos);
- gui.tooltip_timer = gui.tooltip_delay;
+ Control::CursorShape cursor_shape = Control::CURSOR_ARROW;
+ {
+ Control *c = over;
+ Vector2 cpos = pos;
+ while (c) {
+ cursor_shape = c->get_cursor_shape(cpos);
+ cpos = c->get_transform().xform(cpos);
+ if (cursor_shape != Control::CURSOR_ARROW)
+ break;
+ if (c->data.mouse_filter == Control::MOUSE_FILTER_STOP)
+ break;
+ if (c->is_set_as_toplevel())
+ break;
+ c = c->get_parent_control();
+ }
+ }
+
+ ds_cursor_shape = (DisplayServer::CursorShape)cursor_shape;
+
+ if (over && over->can_process()) {
+ _gui_call_input(over, mm);
}
+
+ set_input_as_handled();
}
- //pos = gui.focus_inv_xform.xform(pos);
+ if (gui.drag_data.get_type() != Variant::NIL) {
+ //handle dragandrop
- mm->set_position(pos);
+ if (gui.drag_preview) {
+ gui.drag_preview->set_position(mpos);
+ }
- Control::CursorShape cursor_shape = Control::CURSOR_ARROW;
- {
- Control *c = over;
- Vector2 cpos = pos;
- while (c) {
- cursor_shape = c->get_cursor_shape(cpos);
- cpos = c->get_transform().xform(cpos);
- if (cursor_shape != Control::CURSOR_ARROW)
- break;
- if (c->data.mouse_filter == Control::MOUSE_FILTER_STOP)
- break;
- if (c->is_set_as_toplevel())
- break;
- c = c->get_parent_control();
+ gui.drag_mouse_over = over;
+ gui.drag_mouse_over_pos = Vector2();
+
+ //find the window this is above of
+
+ //see if there is an embedder
+ Viewport *embedder = nullptr;
+ Vector2 viewport_pos;
+
+ if (is_embedding_subwindows()) {
+ embedder = this;
+ viewport_pos = mpos;
+ } else {
+ //not an embeder, but may be a subwindow of an embedder
+ Window *w = Object::cast_to<Window>(this);
+ if (w) {
+ if (w->is_embedded()) {
+ embedder = w->_get_embedder();
+
+ Transform2D ai = (get_final_transform().affine_inverse() * _get_input_pre_xform()).affine_inverse();
+
+ viewport_pos = ai.xform(mpos) + w->get_position(); //to parent coords
+ }
+ }
}
- }
- OS::get_singleton()->set_cursor_shape((OS::CursorShape)cursor_shape);
+ Viewport *viewport_under = nullptr;
- if (over && over->can_process()) {
- _gui_call_input(over, mm);
- }
+ if (embedder) {
+ //use embedder logic
- set_input_as_handled();
+ for (int i = embedder->gui.sub_windows.size() - 1; i >= 0; i--) {
+ Window *sw = embedder->gui.sub_windows[i].window;
+ Rect2 swrect = Rect2i(sw->get_position(), sw->get_size());
+ if (!sw->get_flag(Window::FLAG_BORDERLESS)) {
+ int title_height = sw->get_theme_constant("title_height");
+ swrect.position.y -= title_height;
+ swrect.size.y += title_height;
+ }
- if (gui.drag_data.get_type() != Variant::NIL && mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (swrect.has_point(viewport_pos)) {
+ viewport_under = sw;
+ viewport_pos -= sw->get_position();
+ }
+ }
+
+ if (!viewport_under) {
+ //not in a subwindow, likely in embedder
+ viewport_under = embedder;
+ }
+ } else {
+ //use displayserver logic
+ Vector2i screen_mouse_pos = DisplayServer::get_singleton()->mouse_get_position();
+
+ DisplayServer::WindowID window_id = DisplayServer::get_singleton()->get_window_at_screen_position(screen_mouse_pos);
+
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ ObjectID object_under = DisplayServer::get_singleton()->window_get_attached_instance_id(window_id);
+
+ if (object_under != ObjectID()) { //fetch window
+ Window *w = Object::cast_to<Window>(ObjectDB::get_instance(object_under));
+ if (w) {
+ viewport_under = w;
+ viewport_pos = screen_mouse_pos - w->get_position();
+ }
+ }
+ }
+ }
- bool can_drop = _gui_drop(over, pos, true);
+ if (viewport_under) {
+ Transform2D ai = (viewport_under->get_final_transform().affine_inverse() * viewport_under->_get_input_pre_xform());
+ viewport_pos = ai.xform(viewport_pos);
+ //find control under at pos
+ gui.drag_mouse_over = viewport_under->_gui_find_control(viewport_pos);
+ if (gui.drag_mouse_over) {
+ Transform2D localizer = gui.drag_mouse_over->get_global_transform_with_canvas().affine_inverse();
+ gui.drag_mouse_over_pos = localizer.xform(viewport_pos);
+
+ if (mm->get_button_mask() & BUTTON_MASK_LEFT) {
+
+ bool can_drop = _gui_drop(gui.drag_mouse_over, gui.drag_mouse_over_pos, true);
+
+ if (!can_drop) {
+ ds_cursor_shape = DisplayServer::CURSOR_FORBIDDEN;
+ } else {
+ ds_cursor_shape = DisplayServer::CURSOR_CAN_DROP;
+ }
+ }
+ }
- if (!can_drop) {
- OS::get_singleton()->set_cursor_shape(OS::CURSOR_FORBIDDEN);
} else {
- OS::get_singleton()->set_cursor_shape(OS::CURSOR_CAN_DROP);
+ gui.drag_mouse_over = nullptr;
}
- //change mouse accordingly i guess
}
+
+ DisplayServer::get_singleton()->cursor_set_shape(ds_cursor_shape);
}
Ref<InputEventScreenTouch> touch_event = p_event;
@@ -2275,14 +2291,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Control *over = _gui_find_control(pos);
if (over) {
- if (!gui.modal_stack.empty()) {
-
- Control *top = gui.modal_stack.back()->get();
- if (over != top && !top->is_a_parent_of(over)) {
-
- return;
- }
- }
if (over->can_process()) {
touch_event = touch_event->xformed_by(Transform2D()); //make a copy
@@ -2348,14 +2356,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
if (over) {
- if (!gui.modal_stack.empty()) {
-
- Control *top = gui.modal_stack.back()->get();
- if (over != top && !top->is_a_parent_of(over)) {
-
- return;
- }
- }
if (over->can_process()) {
Transform2D localizer = over->get_global_transform_with_canvas().affine_inverse();
@@ -2399,22 +2399,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
}
- if (p_event->is_pressed() && p_event->is_action("ui_cancel") && !gui.modal_stack.empty()) {
-
- _gui_sort_modal_stack();
- Control *top = gui.modal_stack.back()->get();
- if (!top->data.modal_exclusive) {
-
- top->notification(Control::NOTIFICATION_MODAL_CLOSE);
- top->_modal_stack_remove();
- top->hide();
- // Close modal, set input as handled
- set_input_as_handled();
- return;
- }
- }
-
- Control *from = gui.key_focus ? gui.key_focus : NULL; //hmm
+ Control *from = gui.key_focus ? gui.key_focus : nullptr; //hmm
//keyboard focus
//if (from && p_event->is_pressed() && !p_event->get_alt() && !p_event->get_metakey() && !p_event->key->get_command()) {
@@ -2424,9 +2409,9 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
bool mods = k.is_valid() && (k->get_control() || k->get_alt() || k->get_shift() || k->get_metakey());
if (from && p_event->is_pressed()) {
- Control *next = NULL;
+ Control *next = nullptr;
- Input *input = Input::get_singleton();
+ InputFilter *input = InputFilter::get_singleton();
if (p_event->is_action_pressed("ui_focus_next") && input->is_action_just_pressed("ui_focus_next")) {
@@ -2472,68 +2457,17 @@ List<Control *>::Element *Viewport::_gui_add_root_control(Control *p_control) {
return gui.roots.push_back(p_control);
}
-List<Control *>::Element *Viewport::_gui_add_subwindow_control(Control *p_control) {
-
- p_control->connect("visibility_changed", callable_mp(this, &Viewport::_subwindow_visibility_changed));
-
- if (p_control->is_visible_in_tree()) {
- gui.subwindow_order_dirty = true;
- gui.subwindows.push_back(p_control);
- }
-
- return gui.all_known_subwindows.push_back(p_control);
-}
-
-void Viewport::_gui_set_subwindow_order_dirty() {
- gui.subwindow_order_dirty = true;
-}
-
void Viewport::_gui_set_root_order_dirty() {
gui.roots_order_dirty = true;
}
-void Viewport::_gui_remove_modal_control(List<Control *>::Element *MI) {
-
- gui.modal_stack.erase(MI);
-}
-
-void Viewport::_gui_remove_from_modal_stack(List<Control *>::Element *MI, ObjectID p_prev_focus_owner) {
-
- //transfer the focus stack to the next
-
- List<Control *>::Element *next = MI->next();
-
- gui.modal_stack.erase(MI);
-
- if (p_prev_focus_owner.is_valid()) {
-
- // for previous window in stack, pass the focus so it feels more
- // natural
-
- if (!next) { //top of stack
-
- Object *pfo = ObjectDB::get_instance(p_prev_focus_owner);
- Control *pfoc = Object::cast_to<Control>(pfo);
- if (!pfoc)
- return;
-
- if (!pfoc->is_inside_tree() || !pfoc->is_visible_in_tree())
- return;
- pfoc->grab_focus();
- } else {
-
- next->get()->_modal_set_prev_focus_owner(p_prev_focus_owner);
- }
- }
-}
-
void Viewport::_gui_force_drag(Control *p_base, const Variant &p_data, Control *p_control) {
ERR_FAIL_COND_MSG(p_data.get_type() == Variant::NIL, "Drag data must be a value.");
gui.dragging = true;
gui.drag_data = p_data;
- gui.mouse_focus = NULL;
+ gui.mouse_focus = nullptr;
if (p_control) {
_gui_set_drag_preview(p_base, p_control);
@@ -2545,7 +2479,7 @@ void Viewport::_gui_set_drag_preview(Control *p_base, Control *p_control) {
ERR_FAIL_NULL(p_control);
ERR_FAIL_COND(!Object::cast_to<Control>((Object *)p_control));
ERR_FAIL_COND(p_control->is_inside_tree());
- ERR_FAIL_COND(p_control->get_parent() != NULL);
+ ERR_FAIL_COND(p_control->get_parent() != nullptr);
if (gui.drag_preview) {
memdelete(gui.drag_preview);
@@ -2563,21 +2497,6 @@ void Viewport::_gui_remove_root_control(List<Control *>::Element *RI) {
gui.roots.erase(RI);
}
-void Viewport::_gui_remove_subwindow_control(List<Control *>::Element *SI) {
-
- ERR_FAIL_COND(!SI);
-
- Control *control = SI->get();
-
- control->disconnect("visibility_changed", callable_mp(this, &Viewport::_subwindow_visibility_changed));
-
- List<Control *>::Element *E = gui.subwindows.find(control);
- if (E)
- gui.subwindows.erase(E);
-
- gui.all_known_subwindows.erase(SI);
-}
-
void Viewport::_gui_unfocus_control(Control *p_control) {
if (gui.key_focus == p_control) {
@@ -2591,20 +2510,12 @@ void Viewport::_gui_hid_control(Control *p_control) {
_drop_mouse_focus();
}
- /* ???
- if (data.window==p_control) {
- window->drag_data=Variant();
- if (window->drag_preview) {
- memdelete( window->drag_preview);
- window->drag_preview=NULL;
- }
- }
- */
-
if (gui.key_focus == p_control)
_gui_remove_focus();
if (gui.mouse_over == p_control)
- gui.mouse_over = NULL;
+ gui.mouse_over = nullptr;
+ if (gui.drag_mouse_over == p_control)
+ gui.drag_mouse_over = nullptr;
if (gui.tooltip == p_control)
_gui_cancel_tooltip();
}
@@ -2612,37 +2523,32 @@ void Viewport::_gui_hid_control(Control *p_control) {
void Viewport::_gui_remove_control(Control *p_control) {
if (gui.mouse_focus == p_control) {
- gui.mouse_focus = NULL;
+ gui.mouse_focus = nullptr;
+ gui.forced_mouse_focus = false;
gui.mouse_focus_mask = 0;
}
if (gui.last_mouse_focus == p_control) {
- gui.last_mouse_focus = NULL;
+ gui.last_mouse_focus = nullptr;
}
if (gui.key_focus == p_control)
- gui.key_focus = NULL;
+ gui.key_focus = nullptr;
if (gui.mouse_over == p_control)
- gui.mouse_over = NULL;
+ gui.mouse_over = nullptr;
+ if (gui.drag_mouse_over == p_control)
+ gui.drag_mouse_over = nullptr;
if (gui.tooltip == p_control)
- gui.tooltip = NULL;
- if (gui.tooltip_popup == p_control) {
- _gui_cancel_tooltip();
- }
+ gui.tooltip = nullptr;
}
void Viewport::_gui_remove_focus() {
if (gui.key_focus) {
Node *f = gui.key_focus;
- gui.key_focus = NULL;
+ gui.key_focus = nullptr;
f->notification(Control::NOTIFICATION_FOCUS_EXIT, true);
}
}
-bool Viewport::_gui_is_modal_on_top(const Control *p_control) {
-
- return (gui.modal_stack.size() && gui.modal_stack.back()->get() == p_control);
-}
-
bool Viewport::_gui_control_has_focus(const Control *p_control) {
return gui.key_focus == p_control;
@@ -2671,7 +2577,8 @@ void Viewport::_drop_mouse_focus() {
Control *c = gui.mouse_focus;
int mask = gui.mouse_focus_mask;
- gui.mouse_focus = NULL;
+ gui.mouse_focus = nullptr;
+ gui.forced_mouse_focus = false;
gui.mouse_focus_mask = 0;
for (int i = 0; i < 3; i++) {
@@ -2703,7 +2610,7 @@ void Viewport::_drop_physics_mouseover() {
#ifndef _3D_DISABLED
if (physics_object_over.is_valid()) {
- CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_over));
+ CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_over));
if (co) {
co->_mouse_exit();
}
@@ -2714,22 +2621,6 @@ void Viewport::_drop_physics_mouseover() {
#endif
}
-List<Control *>::Element *Viewport::_gui_show_modal(Control *p_control) {
-
- List<Control *>::Element *node = gui.modal_stack.push_back(p_control);
- if (gui.key_focus)
- p_control->_modal_set_prev_focus_owner(gui.key_focus->get_instance_id());
- else
- p_control->_modal_set_prev_focus_owner(ObjectID());
-
- if (gui.mouse_focus && !p_control->is_a_parent_of(gui.mouse_focus) && !gui.mouse_click_grabber) {
-
- _drop_mouse_focus();
- }
-
- return node;
-}
-
Control *Viewport::_gui_get_focus_owner() {
return gui.key_focus;
@@ -2748,7 +2639,7 @@ void Viewport::_post_gui_grab_click_focus() {
// Redundant grab requests were made
return;
}
- gui.mouse_click_grabber = NULL;
+ gui.mouse_click_grabber = nullptr;
if (gui.mouse_focus) {
@@ -2798,44 +2689,390 @@ void Viewport::_post_gui_grab_click_focus() {
///////////////////////////////
-void Viewport::input(const Ref<InputEvent> &p_event) {
+void Viewport::input_text(const String &p_text) {
+
+ if (gui.subwindow_focused) {
+ gui.subwindow_focused->input_text(p_text);
+ return;
+ }
+
+ if (gui.key_focus) {
+ gui.key_focus->call("set_text", p_text);
+ }
+}
+Viewport::SubWindowResize Viewport::_sub_window_get_resize_margin(Window *p_subwindow, const Point2 &p_point) {
+
+ if (p_subwindow->get_flag(Window::FLAG_BORDERLESS)) {
+ return SUB_WINDOW_RESIZE_DISABLED;
+ }
+
+ Rect2i r = Rect2i(p_subwindow->get_position(), p_subwindow->get_size());
+
+ int title_height = p_subwindow->get_theme_constant("title_height");
+
+ r.position.y -= title_height;
+ r.size.y += title_height;
+
+ if (r.has_point(p_point)) {
+ return SUB_WINDOW_RESIZE_DISABLED; //it's inside, so no resize
+ }
+
+ int dist_x = p_point.x < r.position.x ? (p_point.x - r.position.x) : (p_point.x > (r.position.x + r.size.x) ? (p_point.x - (r.position.x + r.size.x)) : 0);
+ int dist_y = p_point.y < r.position.y ? (p_point.y - r.position.y) : (p_point.y > (r.position.y + r.size.y) ? (p_point.y - (r.position.y + r.size.y)) : 0);
+
+ int limit = p_subwindow->get_theme_constant("resize_margin");
+
+ if (ABS(dist_x) > limit) {
+ return SUB_WINDOW_RESIZE_DISABLED;
+ }
+
+ if (ABS(dist_y) > limit) {
+ return SUB_WINDOW_RESIZE_DISABLED;
+ }
+
+ if (dist_x < 0 && dist_y < 0) {
+ return SUB_WINDOW_RESIZE_TOP_LEFT;
+ }
+
+ if (dist_x == 0 && dist_y < 0) {
+ return SUB_WINDOW_RESIZE_TOP;
+ }
+
+ if (dist_x > 0 && dist_y < 0) {
+ return SUB_WINDOW_RESIZE_TOP_RIGHT;
+ }
+
+ if (dist_x < 0 && dist_y == 0) {
+ return SUB_WINDOW_RESIZE_LEFT;
+ }
+
+ if (dist_x > 0 && dist_y == 0) {
+ return SUB_WINDOW_RESIZE_RIGHT;
+ }
+
+ if (dist_x < 0 && dist_y > 0) {
+ return SUB_WINDOW_RESIZE_BOTTOM_LEFT;
+ }
+
+ if (dist_x == 0 && dist_y > 0) {
+ return SUB_WINDOW_RESIZE_BOTTOM;
+ }
+
+ if (dist_x > 0 && dist_y > 0) {
+ return SUB_WINDOW_RESIZE_BOTTOM_RIGHT;
+ }
+
+ return SUB_WINDOW_RESIZE_DISABLED;
+}
+bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
+
+ if (gui.subwindow_drag != SUB_WINDOW_DRAG_DISABLED) {
+
+ ERR_FAIL_COND_V(gui.subwindow_focused == nullptr, false);
+
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+
+ if (gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE) {
+ if (gui.subwindow_drag_close_rect.has_point(mb->get_position())) {
+ //close window
+ gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_CLOSE_REQUEST);
+ }
+ }
+ gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED;
+ if (gui.subwindow_focused != nullptr) { //may have been erased
+ _sub_window_update(gui.subwindow_focused);
+ }
+ }
+
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+
+ if (gui.subwindow_drag == SUB_WINDOW_DRAG_MOVE) {
+ Vector2 diff = mm->get_position() - gui.subwindow_drag_from;
+ Rect2i new_rect(gui.subwindow_drag_pos + diff, gui.subwindow_focused->get_size());
+ gui.subwindow_focused->_rect_changed_callback(new_rect);
+ }
+ if (gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE) {
+ gui.subwindow_drag_close_inside = gui.subwindow_drag_close_rect.has_point(mm->get_position());
+ }
+ if (gui.subwindow_drag == SUB_WINDOW_DRAG_RESIZE) {
+ Vector2i diff = mm->get_position() - gui.subwindow_drag_from;
+ Size2i min_size = gui.subwindow_focused->get_min_size();
+ if (gui.subwindow_focused->is_wrapping_controls()) {
+ Size2i cms = gui.subwindow_focused->get_contents_minimum_size();
+ min_size.x = MAX(cms.x, min_size.x);
+ min_size.y = MAX(cms.y, min_size.y);
+ }
+ min_size.x = MAX(min_size.x, 1);
+ min_size.y = MAX(min_size.y, 1);
+
+ Rect2i r = gui.subwindow_resize_from_rect;
+
+ Size2i limit = r.size - min_size;
+
+ switch (gui.subwindow_resize_mode) {
+ case SUB_WINDOW_RESIZE_TOP_LEFT: {
+
+ diff.x = MIN(diff.x, limit.x);
+ diff.y = MIN(diff.y, limit.y);
+ r.position += diff;
+ r.size -= diff;
+ } break;
+ case SUB_WINDOW_RESIZE_TOP: {
+ diff.x = 0;
+ diff.y = MIN(diff.y, limit.y);
+ r.position += diff;
+ r.size -= diff;
+ } break;
+ case SUB_WINDOW_RESIZE_TOP_RIGHT: {
+ diff.x = MAX(diff.x, -limit.x);
+ diff.y = MIN(diff.y, limit.y);
+ r.position.y += diff.y;
+ r.size.y -= diff.y;
+ r.size.x += diff.x;
+ } break;
+ case SUB_WINDOW_RESIZE_LEFT: {
+ diff.x = MIN(diff.x, limit.x);
+ diff.y = 0;
+ r.position += diff;
+ r.size -= diff;
+
+ } break;
+ case SUB_WINDOW_RESIZE_RIGHT: {
+ diff.x = MAX(diff.x, -limit.x);
+ r.size.x += diff.x;
+ } break;
+ case SUB_WINDOW_RESIZE_BOTTOM_LEFT: {
+ diff.x = MIN(diff.x, limit.x);
+ diff.y = MAX(diff.y, -limit.y);
+ r.position.x += diff.x;
+ r.size.x -= diff.x;
+ r.size.y += diff.y;
+
+ } break;
+ case SUB_WINDOW_RESIZE_BOTTOM: {
+ diff.y = MAX(diff.y, -limit.y);
+ r.size.y += diff.y;
+ } break;
+ case SUB_WINDOW_RESIZE_BOTTOM_RIGHT: {
+ diff.x = MAX(diff.x, -limit.x);
+ diff.y = MAX(diff.y, -limit.y);
+ r.size += diff;
+
+ } break;
+ default: {
+ }
+ }
+
+ gui.subwindow_focused->_rect_changed_callback(r);
+ }
+
+ if (gui.subwindow_focused) { //may have been erased
+ _sub_window_update(gui.subwindow_focused);
+ }
+ }
+
+ return true; //handled
+ }
+ Ref<InputEventMouseButton> mb = p_event;
+ //if the event is a mouse button, we need to check whether another window was clicked
+
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+
+ bool click_on_window = false;
+ for (int i = gui.sub_windows.size() - 1; i >= 0; i--) {
+ SubWindow &sw = gui.sub_windows.write[i];
+
+ //clicked inside window?
+
+ Rect2i r = Rect2i(sw.window->get_position(), sw.window->get_size());
+
+ if (!sw.window->get_flag(Window::FLAG_BORDERLESS)) {
+ //check top bar
+ int title_height = sw.window->get_theme_constant("title_height");
+ Rect2i title_bar = r;
+ title_bar.position.y -= title_height;
+ title_bar.size.y = title_height;
+
+ if (title_bar.has_point(mb->get_position())) {
+
+ click_on_window = true;
+
+ int close_h_ofs = sw.window->get_theme_constant("close_h_ofs");
+ int close_v_ofs = sw.window->get_theme_constant("close_v_ofs");
+ Ref<Texture2D> close_icon = sw.window->get_theme_icon("close");
+
+ Rect2 close_rect;
+ close_rect.position = Vector2(r.position.x + r.size.x - close_v_ofs, r.position.y - close_h_ofs);
+ close_rect.size = close_icon->get_size();
+
+ if (gui.subwindow_focused != sw.window) {
+ //refocus
+ _sub_window_grab_focus(sw.window);
+ }
+
+ if (close_rect.has_point(mb->get_position())) {
+
+ gui.subwindow_drag = SUB_WINDOW_DRAG_CLOSE;
+ gui.subwindow_drag_close_inside = true; //starts inside
+ gui.subwindow_drag_close_rect = close_rect;
+ } else {
+
+ gui.subwindow_drag = SUB_WINDOW_DRAG_MOVE;
+ }
+
+ gui.subwindow_drag_from = mb->get_position();
+ gui.subwindow_drag_pos = sw.window->get_position();
+
+ _sub_window_update(sw.window);
+ } else {
+ gui.subwindow_resize_mode = _sub_window_get_resize_margin(sw.window, mb->get_position());
+ if (gui.subwindow_resize_mode != SUB_WINDOW_RESIZE_DISABLED) {
+ gui.subwindow_resize_from_rect = r;
+ gui.subwindow_drag_from = mb->get_position();
+ gui.subwindow_drag = SUB_WINDOW_DRAG_RESIZE;
+ click_on_window = true;
+ }
+ }
+ }
+ if (!click_on_window && r.has_point(mb->get_position())) {
+ //clicked, see if it needs to fetch focus
+ if (gui.subwindow_focused != sw.window) {
+ //refocus
+ _sub_window_grab_focus(sw.window);
+ }
+
+ click_on_window = true;
+ }
+
+ if (click_on_window) {
+ break;
+ }
+ }
+
+ if (!click_on_window && gui.subwindow_focused) {
+ //no window found and clicked, remove focus
+ _sub_window_grab_focus(nullptr);
+ }
+ }
+
+ if (gui.subwindow_focused) {
+
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+
+ SubWindowResize resize = _sub_window_get_resize_margin(gui.subwindow_focused, mm->get_position());
+ if (resize != SUB_WINDOW_RESIZE_DISABLED) {
+
+ DisplayServer::CursorShape shapes[SUB_WINDOW_RESIZE_MAX] = {
+ DisplayServer::CURSOR_ARROW,
+ DisplayServer::CURSOR_FDIAGSIZE,
+ DisplayServer::CURSOR_VSIZE,
+ DisplayServer::CURSOR_BDIAGSIZE,
+ DisplayServer::CURSOR_HSIZE,
+ DisplayServer::CURSOR_HSIZE,
+ DisplayServer::CURSOR_BDIAGSIZE,
+ DisplayServer::CURSOR_VSIZE,
+ DisplayServer::CURSOR_FDIAGSIZE
+ };
+
+ DisplayServer::get_singleton()->cursor_set_shape(shapes[resize]);
+
+ return true; //reserved for showing the resize cursor
+ }
+ }
+ }
+
+ if (gui.subwindow_drag != SUB_WINDOW_DRAG_DISABLED) {
+ return true; // dragging, don't pass the event
+ }
+
+ if (!gui.subwindow_focused) {
+ return false;
+ }
+
+ Transform2D window_ofs;
+ window_ofs.set_origin(-gui.subwindow_focused->get_position());
+
+ Ref<InputEvent> ev = p_event->xformed_by(window_ofs);
+
+ gui.subwindow_focused->_window_input(ev);
+
+ return true;
+}
+
+void Viewport::input(const Ref<InputEvent> &p_event, bool p_local_coords) {
ERR_FAIL_COND(!is_inside_tree());
+ if (disable_input)
+ return;
+
+ if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_a_parent_of(this)) {
+ return;
+ }
+
local_input_handled = false;
+ Ref<InputEvent> ev;
+ if (!p_local_coords) {
+ ev = _make_input_local(p_event);
+ } else {
+ ev = p_event;
+ }
+
+ if (is_embedding_subwindows() && _sub_windows_forward_input(p_event)) {
+ set_input_as_handled();
+ return;
+ }
+
if (!is_input_handled()) {
- get_tree()->_call_input_pause(input_group, "_input", p_event); //not a bug, must happen before GUI, order is _input -> gui input -> _unhandled input
+ get_tree()->_call_input_pause(input_group, "_input", ev, this); //not a bug, must happen before GUI, order is _input -> gui input -> _unhandled input
}
if (!is_input_handled()) {
- _gui_input_event(p_event);
+ _gui_input_event(ev);
}
- //get_tree()->call_group(SceneTree::GROUP_CALL_REVERSE|SceneTree::GROUP_CALL_REALTIME|SceneTree::GROUP_CALL_MULIILEVEL,gui_input_group,"_gui_input",p_event); //special one for GUI, as controls use their own process check
+ //get_tree()->call_group(SceneTree::GROUP_CALL_REVERSE|SceneTree::GROUP_CALL_REALTIME|SceneTree::GROUP_CALL_MULIILEVEL,gui_input_group,"_gui_input",ev); //special one for GUI, as controls use their own process check
}
-void Viewport::unhandled_input(const Ref<InputEvent> &p_event) {
+void Viewport::unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
ERR_FAIL_COND(!is_inside_tree());
- get_tree()->_call_input_pause(unhandled_input_group, "_unhandled_input", p_event);
+ if (disable_input)
+ return;
+
+ if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_a_parent_of(this)) {
+ return;
+ }
+
+ Ref<InputEvent> ev;
+ if (!p_local_coords) {
+ ev = _make_input_local(p_event);
+ } else {
+ ev = p_event;
+ }
+
+ get_tree()->_call_input_pause(unhandled_input_group, "_unhandled_input", ev, this);
//call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"unhandled_input","_unhandled_input",ev);
- if (!get_tree()->input_handled && Object::cast_to<InputEventKey>(*p_event) != NULL) {
- get_tree()->_call_input_pause(unhandled_key_input_group, "_unhandled_key_input", p_event);
+ if (!is_input_handled() && Object::cast_to<InputEventKey>(*ev) != nullptr) {
+ get_tree()->_call_input_pause(unhandled_key_input_group, "_unhandled_key_input", ev, this);
//call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"unhandled_key_input","_unhandled_key_input",ev);
}
- if (physics_object_picking && !get_tree()->input_handled) {
+ if (physics_object_picking && !is_input_handled()) {
- if (Input::get_singleton()->get_mouse_mode() != Input::MOUSE_MODE_CAPTURED &&
- (Object::cast_to<InputEventMouseButton>(*p_event) ||
- Object::cast_to<InputEventMouseMotion>(*p_event) ||
- Object::cast_to<InputEventScreenDrag>(*p_event) ||
- Object::cast_to<InputEventScreenTouch>(*p_event) ||
- Object::cast_to<InputEventKey>(*p_event) //to remember state
+ if (InputFilter::get_singleton()->get_mouse_mode() != InputFilter::MOUSE_MODE_CAPTURED &&
+ (Object::cast_to<InputEventMouseButton>(*ev) ||
+ Object::cast_to<InputEventMouseMotion>(*ev) ||
+ Object::cast_to<InputEventScreenDrag>(*ev) ||
+ Object::cast_to<InputEventScreenTouch>(*ev) ||
+ Object::cast_to<InputEventKey>(*ev) //to remember state
)) {
- physics_picking_events.push_back(p_event);
+ physics_picking_events.push_back(ev);
}
}
}
@@ -2849,7 +3086,7 @@ void Viewport::set_use_own_world(bool p_world) {
_propagate_exit_world(this);
if (!p_world) {
- own_world = Ref<World>();
+ own_world = Ref<World3D>();
if (world.is_valid()) {
world->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_changed));
}
@@ -2858,7 +3095,7 @@ void Viewport::set_use_own_world(bool p_world) {
own_world = world->duplicate();
world->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_changed));
} else {
- own_world = Ref<World>(memnew(World));
+ own_world = Ref<World3D>(memnew(World3D));
}
}
@@ -2866,7 +3103,7 @@ void Viewport::set_use_own_world(bool p_world) {
_propagate_enter_world(this);
if (is_inside_tree()) {
- VisualServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
+ RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
}
_update_listener();
@@ -2877,30 +3114,6 @@ bool Viewport::is_using_own_world() const {
return own_world.is_valid();
}
-void Viewport::set_attach_to_screen_rect(const Rect2 &p_rect) {
-
- VS::get_singleton()->viewport_attach_to_screen(viewport, p_rect);
- to_screen_rect = p_rect;
-}
-
-Rect2 Viewport::get_attach_to_screen_rect() const {
-
- return to_screen_rect;
-}
-
-void Viewport::set_use_render_direct_to_screen(bool p_render_direct_to_screen) {
-
- if (p_render_direct_to_screen == render_direct_to_screen)
- return;
-
- render_direct_to_screen = p_render_direct_to_screen;
- VS::get_singleton()->viewport_set_render_direct_to_screen(viewport, p_render_direct_to_screen);
-}
-
-bool Viewport::is_using_render_direct_to_screen() const {
- return render_direct_to_screen;
-}
-
void Viewport::set_physics_object_picking(bool p_enable) {
physics_object_picking = p_enable;
@@ -2925,11 +3138,6 @@ Vector2 Viewport::get_camera_rect_size() const {
return size;
}
-bool Viewport::gui_has_modal_stack() const {
-
- return gui.modal_stack.size();
-}
-
void Viewport::set_disable_input(bool p_disable) {
disable_input = p_disable;
}
@@ -2943,10 +3151,6 @@ Variant Viewport::gui_get_drag_data() const {
return gui.drag_data;
}
-Control *Viewport::get_modal_stack_top() const {
- return gui.modal_stack.size() ? gui.modal_stack.back()->get() : NULL;
-}
-
String Viewport::get_configuration_warning() const {
/*if (get_parent() && !Object::cast_to<Control>(get_parent()) && !render_target) {
@@ -2969,11 +3173,11 @@ int Viewport::gui_get_canvas_sort_index() {
void Viewport::set_msaa(MSAA p_msaa) {
- ERR_FAIL_INDEX(p_msaa, 7);
+ ERR_FAIL_INDEX(p_msaa, MSAA_MAX);
if (msaa == p_msaa)
return;
msaa = p_msaa;
- VS::get_singleton()->viewport_set_msaa(viewport, VS::ViewportMSAA(p_msaa));
+ RS::get_singleton()->viewport_set_msaa(viewport, RS::ViewportMSAA(p_msaa));
}
Viewport::MSAA Viewport::get_msaa() const {
@@ -2981,10 +3185,23 @@ Viewport::MSAA Viewport::get_msaa() const {
return msaa;
}
+void Viewport::set_screen_space_aa(ScreenSpaceAA p_screen_space_aa) {
+
+ ERR_FAIL_INDEX(p_screen_space_aa, SCREEN_SPACE_AA_MAX);
+ if (screen_space_aa == p_screen_space_aa)
+ return;
+ screen_space_aa = p_screen_space_aa;
+ RS::get_singleton()->viewport_set_screen_space_aa(viewport, RS::ViewportScreenSpaceAA(p_screen_space_aa));
+}
+
+Viewport::ScreenSpaceAA Viewport::get_screen_space_aa() const {
+
+ return screen_space_aa;
+}
void Viewport::set_debug_draw(DebugDraw p_debug_draw) {
debug_draw = p_debug_draw;
- VS::get_singleton()->viewport_set_debug_draw(viewport, VS::ViewportDebugDraw(p_debug_draw));
+ RS::get_singleton()->viewport_set_debug_draw(viewport, RS::ViewportDebugDraw(p_debug_draw));
}
Viewport::DebugDraw Viewport::get_debug_draw() const {
@@ -2994,7 +3211,7 @@ Viewport::DebugDraw Viewport::get_debug_draw() const {
int Viewport::get_render_info(RenderInfo p_info) {
- return VS::get_singleton()->viewport_get_render_info(viewport, VS::ViewportRenderInfo(p_info));
+ return RS::get_singleton()->viewport_get_render_info(viewport, RS::ViewportRenderInfo(p_info));
}
void Viewport::set_snap_controls_to_pixels(bool p_enable) {
@@ -3017,7 +3234,17 @@ void Viewport::set_input_as_handled() {
local_input_handled = true;
} else {
ERR_FAIL_COND(!is_inside_tree());
- get_tree()->set_input_as_handled();
+ Viewport *vp = this;
+ while (true) {
+ if (Object::cast_to<Window>(vp)) {
+ break;
+ }
+ if (!vp->get_parent()) {
+ break;
+ }
+ vp = vp->get_parent()->get_viewport();
+ }
+ vp->set_input_as_handled();
}
}
@@ -3025,8 +3252,17 @@ bool Viewport::is_input_handled() const {
if (handle_input_locally) {
return local_input_handled;
} else {
- ERR_FAIL_COND_V(!is_inside_tree(), false);
- return get_tree()->is_input_handled();
+ const Viewport *vp = this;
+ while (true) {
+ if (Object::cast_to<Window>(vp)) {
+ break;
+ }
+ if (!vp->get_parent()) {
+ break;
+ }
+ vp = vp->get_parent()->get_viewport();
+ }
+ return vp->is_input_handled();
}
}
@@ -3086,13 +3322,47 @@ void Viewport::_propagate_update_default_repeat(Node *p_node) {
}
}
-void Viewport::_bind_methods() {
+DisplayServer::WindowID Viewport::get_window_id() const {
+ return DisplayServer::MAIN_WINDOW_ID;
+}
- ClassDB::bind_method(D_METHOD("set_use_arvr", "use"), &Viewport::set_use_arvr);
- ClassDB::bind_method(D_METHOD("use_arvr"), &Viewport::use_arvr);
+Viewport *Viewport::get_parent_viewport() const {
+ ERR_FAIL_COND_V(!is_inside_tree(), nullptr);
+ if (!get_parent()) {
+ return nullptr; //root viewport
+ }
+
+ return get_parent()->get_viewport();
+}
+
+void Viewport::set_embed_subwindows_hint(bool p_embed) {
+ gui.embed_subwindows_hint = p_embed;
+}
+bool Viewport::get_embed_subwindows_hint() const {
+ return gui.embed_subwindows_hint;
+}
+bool Viewport::is_embedding_subwindows() const {
+ return gui.embed_subwindows_hint;
+}
+
+void Viewport::pass_mouse_focus_to(Viewport *p_viewport, Control *p_control) {
+ ERR_FAIL_NULL(p_viewport);
+ ERR_FAIL_NULL(p_control);
+
+ if (gui.mouse_focus) {
+ p_viewport->gui.mouse_focus = p_control;
+ p_viewport->gui.mouse_focus_mask = gui.mouse_focus_mask;
+ p_viewport->gui.key_focus = p_control;
+ p_viewport->gui.forced_mouse_focus = true;
+
+ gui.mouse_focus = nullptr;
+ gui.forced_mouse_focus = false;
+ gui.mouse_focus_mask = 0;
+ }
+}
+
+void Viewport::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_size", "size"), &Viewport::set_size);
- ClassDB::bind_method(D_METHOD("get_size"), &Viewport::get_size);
ClassDB::bind_method(D_METHOD("set_world_2d", "world_2d"), &Viewport::set_world_2d);
ClassDB::bind_method(D_METHOD("get_world_2d"), &Viewport::get_world_2d);
ClassDB::bind_method(D_METHOD("find_world_2d"), &Viewport::find_world_2d);
@@ -3111,25 +3381,12 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_transparent_background", "enable"), &Viewport::set_transparent_background);
ClassDB::bind_method(D_METHOD("has_transparent_background"), &Viewport::has_transparent_background);
- ClassDB::bind_method(D_METHOD("_vp_input"), &Viewport::_vp_input);
- ClassDB::bind_method(D_METHOD("_vp_input_text", "text"), &Viewport::_vp_input_text);
- ClassDB::bind_method(D_METHOD("_vp_unhandled_input"), &Viewport::_vp_unhandled_input);
-
- ClassDB::bind_method(D_METHOD("set_size_override", "enable", "size", "margin"), &Viewport::set_size_override, DEFVAL(Size2(-1, -1)), DEFVAL(Size2(0, 0)));
- ClassDB::bind_method(D_METHOD("get_size_override"), &Viewport::get_size_override);
- ClassDB::bind_method(D_METHOD("is_size_override_enabled"), &Viewport::is_size_override_enabled);
- ClassDB::bind_method(D_METHOD("set_size_override_stretch", "enabled"), &Viewport::set_size_override_stretch);
- ClassDB::bind_method(D_METHOD("is_size_override_stretch_enabled"), &Viewport::is_size_override_stretch_enabled);
-
- ClassDB::bind_method(D_METHOD("set_clear_mode", "mode"), &Viewport::set_clear_mode);
- ClassDB::bind_method(D_METHOD("get_clear_mode"), &Viewport::get_clear_mode);
-
- ClassDB::bind_method(D_METHOD("set_update_mode", "mode"), &Viewport::set_update_mode);
- ClassDB::bind_method(D_METHOD("get_update_mode"), &Viewport::get_update_mode);
-
ClassDB::bind_method(D_METHOD("set_msaa", "msaa"), &Viewport::set_msaa);
ClassDB::bind_method(D_METHOD("get_msaa"), &Viewport::get_msaa);
+ ClassDB::bind_method(D_METHOD("set_screen_space_aa", "screen_space_aa"), &Viewport::set_screen_space_aa);
+ ClassDB::bind_method(D_METHOD("get_screen_space_aa"), &Viewport::get_screen_space_aa);
+
ClassDB::bind_method(D_METHOD("set_debug_draw", "debug_draw"), &Viewport::set_debug_draw);
ClassDB::bind_method(D_METHOD("get_debug_draw"), &Viewport::get_debug_draw);
@@ -3141,8 +3398,9 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_physics_object_picking"), &Viewport::get_physics_object_picking);
ClassDB::bind_method(D_METHOD("get_viewport_rid"), &Viewport::get_viewport_rid);
- ClassDB::bind_method(D_METHOD("input", "local_event"), &Viewport::input);
- ClassDB::bind_method(D_METHOD("unhandled_input", "local_event"), &Viewport::unhandled_input);
+ ClassDB::bind_method(D_METHOD("input_text", "text"), &Viewport::input_text);
+ ClassDB::bind_method(D_METHOD("input", "event", "in_local_coords"), &Viewport::input, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("unhandled_input", "event", "in_local_coords"), &Viewport::unhandled_input, DEFVAL(false));
ClassDB::bind_method(D_METHOD("update_worlds"), &Viewport::update_worlds);
@@ -3156,19 +3414,13 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_as_audio_listener_2d", "enable"), &Viewport::set_as_audio_listener_2d);
ClassDB::bind_method(D_METHOD("is_audio_listener_2d"), &Viewport::is_audio_listener_2d);
- ClassDB::bind_method(D_METHOD("set_attach_to_screen_rect", "rect"), &Viewport::set_attach_to_screen_rect);
- ClassDB::bind_method(D_METHOD("set_use_render_direct_to_screen", "enable"), &Viewport::set_use_render_direct_to_screen);
- ClassDB::bind_method(D_METHOD("is_using_render_direct_to_screen"), &Viewport::is_using_render_direct_to_screen);
ClassDB::bind_method(D_METHOD("get_mouse_position"), &Viewport::get_mouse_position);
ClassDB::bind_method(D_METHOD("warp_mouse", "to_position"), &Viewport::warp_mouse);
- ClassDB::bind_method(D_METHOD("gui_has_modal_stack"), &Viewport::gui_has_modal_stack);
ClassDB::bind_method(D_METHOD("gui_get_drag_data"), &Viewport::gui_get_drag_data);
ClassDB::bind_method(D_METHOD("gui_is_dragging"), &Viewport::gui_is_dragging);
- ClassDB::bind_method(D_METHOD("get_modal_stack_top"), &Viewport::get_modal_stack_top);
-
ClassDB::bind_method(D_METHOD("set_disable_input", "disable"), &Viewport::set_disable_input);
ClassDB::bind_method(D_METHOD("is_input_disabled"), &Viewport::is_input_disabled);
@@ -3194,13 +3446,13 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_default_canvas_item_texture_filter", "mode"), &Viewport::set_default_canvas_item_texture_filter);
ClassDB::bind_method(D_METHOD("get_default_canvas_item_texture_filter"), &Viewport::get_default_canvas_item_texture_filter);
+ ClassDB::bind_method(D_METHOD("set_embed_subwindows_hint", "enable"), &Viewport::set_embed_subwindows_hint);
+ ClassDB::bind_method(D_METHOD("get_embed_subwindows_hint"), &Viewport::get_embed_subwindows_hint);
+ ClassDB::bind_method(D_METHOD("is_embedding_subwindows"), &Viewport::is_embedding_subwindows);
+
ClassDB::bind_method(D_METHOD("set_default_canvas_item_texture_repeat", "mode"), &Viewport::set_default_canvas_item_texture_repeat);
ClassDB::bind_method(D_METHOD("get_default_canvas_item_texture_repeat"), &Viewport::get_default_canvas_item_texture_repeat);
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "arvr"), "set_use_arvr", "use_arvr");
-
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "size_override_stretch"), "set_size_override_stretch", "is_size_override_stretch_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "own_world"), "set_use_own_world", "is_using_own_world");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world", PROPERTY_HINT_RESOURCE_TYPE, "World"), "set_world", "get_world");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_2d", PROPERTY_HINT_RESOURCE_TYPE, "World2D", 0), "set_world_2d", "get_world_2d");
@@ -3208,11 +3460,8 @@ void Viewport::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "handle_input_locally"), "set_handle_input_locally", "is_handling_input_locally");
ADD_GROUP("Rendering", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x,AndroidVR 2x,AndroidVR 4x"), "set_msaa", "get_msaa");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "render_direct_to_screen"), "set_use_render_direct_to_screen", "is_using_render_direct_to_screen");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_space_aa", PROPERTY_HINT_ENUM, "Disabled,FXAA"), "set_screen_space_aa", "get_screen_space_aa");
ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw");
- ADD_GROUP("Render Target", "render_target_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "render_target_clear_mode", PROPERTY_HINT_ENUM, "Always,Never,Next Frame"), "set_clear_mode", "get_clear_mode");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "render_target_update_mode", PROPERTY_HINT_ENUM, "Disabled,Once,When Visible,Always"), "set_update_mode", "get_update_mode");
ADD_GROUP("Canvas Items", "canvas_item_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,MipmapLinear,MipmapNearest"), "set_default_canvas_item_texture_filter", "get_default_canvas_item_texture_filter");
ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_repeat", PROPERTY_HINT_ENUM, "Disabled,Enabled,Mirror"), "set_default_canvas_item_texture_repeat", "get_default_canvas_item_texture_repeat");
@@ -3224,6 +3473,7 @@ void Viewport::_bind_methods() {
ADD_GROUP("GUI", "gui_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gui_disable_input"), "set_disable_input", "is_input_disabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gui_snap_controls_to_pixels"), "set_snap_controls_to_pixels", "is_snap_controls_to_pixels_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gui_embed_subwindows"), "set_embed_subwindows_hint", "get_embed_subwindows_hint");
ADD_GROUP("Shadow Atlas", "shadow_atlas_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_atlas_size"), "set_shadow_atlas_size", "get_shadow_atlas_size");
ADD_PROPERTYI(PropertyInfo(Variant::INT, "shadow_atlas_quad_0", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), "set_shadow_atlas_quadrant_subdiv", "get_shadow_atlas_quadrant_subdiv", 0);
@@ -3236,11 +3486,6 @@ void Viewport::_bind_methods() {
ADD_SIGNAL(MethodInfo("size_changed"));
ADD_SIGNAL(MethodInfo("gui_focus_changed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
- BIND_ENUM_CONSTANT(UPDATE_DISABLED);
- BIND_ENUM_CONSTANT(UPDATE_ONCE);
- BIND_ENUM_CONSTANT(UPDATE_WHEN_VISIBLE);
- BIND_ENUM_CONSTANT(UPDATE_ALWAYS);
-
BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED);
BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_1);
BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_4);
@@ -3250,6 +3495,17 @@ void Viewport::_bind_methods() {
BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_1024);
BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_MAX);
+ BIND_ENUM_CONSTANT(MSAA_DISABLED);
+ BIND_ENUM_CONSTANT(MSAA_2X);
+ BIND_ENUM_CONSTANT(MSAA_4X);
+ BIND_ENUM_CONSTANT(MSAA_8X);
+ BIND_ENUM_CONSTANT(MSAA_16X);
+ BIND_ENUM_CONSTANT(MSAA_MAX);
+
+ BIND_ENUM_CONSTANT(SCREEN_SPACE_AA_DISABLED);
+ BIND_ENUM_CONSTANT(SCREEN_SPACE_AA_FXAA);
+ BIND_ENUM_CONSTANT(SCREEN_SPACE_AA_MAX);
+
BIND_ENUM_CONSTANT(RENDER_INFO_OBJECTS_IN_FRAME);
BIND_ENUM_CONSTANT(RENDER_INFO_VERTICES_IN_FRAME);
BIND_ENUM_CONSTANT(RENDER_INFO_MATERIAL_CHANGES_IN_FRAME);
@@ -3260,9 +3516,10 @@ void Viewport::_bind_methods() {
BIND_ENUM_CONSTANT(DEBUG_DRAW_DISABLED);
BIND_ENUM_CONSTANT(DEBUG_DRAW_UNSHADED);
+ BIND_ENUM_CONSTANT(DEBUG_DRAW_LIGHTING);
BIND_ENUM_CONSTANT(DEBUG_DRAW_OVERDRAW);
BIND_ENUM_CONSTANT(DEBUG_DRAW_WIREFRAME);
-
+ BIND_ENUM_CONSTANT(DEBUG_DRAW_NORMAL_BUFFER);
BIND_ENUM_CONSTANT(DEBUG_DRAW_GI_PROBE_ALBEDO);
BIND_ENUM_CONSTANT(DEBUG_DRAW_GI_PROBE_LIGHTING);
BIND_ENUM_CONSTANT(DEBUG_DRAW_GI_PROBE_EMISSION);
@@ -3270,68 +3527,47 @@ void Viewport::_bind_methods() {
BIND_ENUM_CONSTANT(DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS);
BIND_ENUM_CONSTANT(DEBUG_DRAW_SCENE_LUMINANCE);
BIND_ENUM_CONSTANT(DEBUG_DRAW_SSAO);
-
- BIND_ENUM_CONSTANT(MSAA_DISABLED);
- BIND_ENUM_CONSTANT(MSAA_2X);
- BIND_ENUM_CONSTANT(MSAA_4X);
- BIND_ENUM_CONSTANT(MSAA_8X);
- BIND_ENUM_CONSTANT(MSAA_16X);
-
- BIND_ENUM_CONSTANT(CLEAR_MODE_ALWAYS);
- BIND_ENUM_CONSTANT(CLEAR_MODE_NEVER);
- BIND_ENUM_CONSTANT(CLEAR_MODE_ONLY_NEXT_FRAME);
+ BIND_ENUM_CONSTANT(DEBUG_DRAW_ROUGHNESS_LIMITER);
+ BIND_ENUM_CONSTANT(DEBUG_DRAW_PSSM_SPLITS);
+ BIND_ENUM_CONSTANT(DEBUG_DRAW_DECAL_ATLAS);
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR);
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS);
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS);
-
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_MAX);
+
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MIRROR);
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MAX);
}
-void Viewport::_subwindow_visibility_changed() {
-
- // unfortunately, we don't know the sender, i.e. which subwindow changed;
- // so we have to check them all.
- gui.subwindow_visibility_dirty = true;
-}
-
Viewport::Viewport() {
world_2d = Ref<World2D>(memnew(World2D));
- viewport = VisualServer::get_singleton()->viewport_create();
- texture_rid = VisualServer::get_singleton()->viewport_get_texture(viewport);
-
- render_direct_to_screen = false;
+ viewport = RenderingServer::get_singleton()->viewport_create();
+ texture_rid = RenderingServer::get_singleton()->viewport_get_texture(viewport);
default_texture.instance();
default_texture->vp = const_cast<Viewport *>(this);
viewport_textures.insert(default_texture.ptr());
- default_texture->proxy = VS::get_singleton()->texture_proxy_create(texture_rid);
+ default_texture->proxy = RS::get_singleton()->texture_proxy_create(texture_rid);
- //internal_listener = SpatialSoundServer::get_singleton()->listener_create();
audio_listener = false;
//internal_listener_2d = SpatialSound2DServer::get_singleton()->listener_create();
audio_listener_2d = false;
transparent_bg = false;
- parent = NULL;
- listener = NULL;
- camera = NULL;
+ parent = nullptr;
+ listener = nullptr;
+ camera = nullptr;
override_canvas_transform = false;
- canvas_layers.insert(NULL); // This eases picking code (interpreted as the canvas of the Viewport)
- arvr = false;
- size_override = false;
- size_override_stretch = false;
- size_override_size = Size2(1, 1);
+ canvas_layers.insert(nullptr); // This eases picking code (interpreted as the canvas of the Viewport)
+
gen_mipmaps = false;
//clear=true;
- update_mode = UPDATE_WHEN_VISIBLE;
physics_object_picking = false;
physics_has_last_mousepos = false;
@@ -3361,19 +3597,21 @@ Viewport::Viewport() {
gui.tooltip_delay = GLOBAL_DEF("gui/timers/tooltip_delay_sec", 0.5);
ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/tooltip_delay_sec", PropertyInfo(Variant::FLOAT, "gui/timers/tooltip_delay_sec", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater")); // No negative numbers
- gui.tooltip = NULL;
- gui.tooltip_label = NULL;
- gui.drag_preview = NULL;
+ gui.tooltip = nullptr;
+ gui.tooltip_label = nullptr;
+ gui.drag_preview = nullptr;
gui.drag_attempted = false;
gui.canvas_sort_index = 0;
gui.roots_order_dirty = false;
- gui.mouse_focus = NULL;
- gui.last_mouse_focus = NULL;
+ gui.mouse_focus = nullptr;
+ gui.forced_mouse_focus = false;
+ gui.last_mouse_focus = nullptr;
+ gui.subwindow_focused = nullptr;
+ gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED;
msaa = MSAA_DISABLED;
-
+ screen_space_aa = SCREEN_SPACE_AA_DISABLED;
debug_draw = DEBUG_DRAW_DISABLED;
- clear_mode = CLEAR_MODE_ALWAYS;
snap_controls_to_pixels = true;
physics_last_mouse_state.alt = false;
@@ -3384,6 +3622,8 @@ Viewport::Viewport() {
local_input_handled = false;
handle_input_locally = true;
+ size_allocated = false;
+
default_canvas_item_texture_filter = DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
default_canvas_item_texture_repeat = DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
}
@@ -3392,9 +3632,143 @@ Viewport::~Viewport() {
//erase itself from viewport textures
for (Set<ViewportTexture *>::Element *E = viewport_textures.front(); E; E = E->next()) {
- E->get()->vp = NULL;
+ E->get()->vp = nullptr;
+ }
+ RenderingServer::get_singleton()->free(viewport);
+}
+
+/////////////////////////////////
+
+void SubViewport::set_use_xr(bool p_use_xr) {
+ xr = p_use_xr;
+
+ RS::get_singleton()->viewport_set_use_xr(get_viewport_rid(), xr);
+}
+
+bool SubViewport::is_using_xr() {
+ return xr;
+}
+
+void SubViewport::set_size(const Size2i &p_size) {
+ _set_size(p_size, _get_size_2d_override(), Rect2i(), _stretch_transform(), true);
+}
+Size2i SubViewport::get_size() const {
+ return _get_size();
+}
+
+void SubViewport::set_size_2d_override(const Size2i &p_size) {
+
+ _set_size(_get_size(), p_size, Rect2i(), _stretch_transform(), true);
+}
+Size2i SubViewport::get_size_2d_override() const {
+
+ return _get_size_2d_override();
+}
+
+void SubViewport::set_size_2d_override_stretch(bool p_enable) {
+
+ if (p_enable == size_2d_override_stretch) {
+ return;
}
- VisualServer::get_singleton()->free(viewport);
- //SpatialSoundServer::get_singleton()->free(internal_listener);
- //SpatialSound2DServer::get_singleton()->free(internal_listener_2d);
+
+ size_2d_override_stretch = p_enable;
+ _set_size(_get_size(), _get_size_2d_override(), Rect2i(), _stretch_transform(), true);
+}
+bool SubViewport::is_size_2d_override_stretch_enabled() const {
+
+ return size_2d_override_stretch;
+}
+
+void SubViewport::set_update_mode(UpdateMode p_mode) {
+
+ update_mode = p_mode;
+ RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::ViewportUpdateMode(p_mode));
+}
+SubViewport::UpdateMode SubViewport::get_update_mode() const {
+
+ return update_mode;
+}
+
+void SubViewport::set_clear_mode(ClearMode p_mode) {
+
+ clear_mode = p_mode;
+ RS::get_singleton()->viewport_set_clear_mode(get_viewport_rid(), RS::ViewportClearMode(p_mode));
+}
+SubViewport::ClearMode SubViewport::get_clear_mode() const {
+
+ return clear_mode;
+}
+
+DisplayServer::WindowID SubViewport::get_window_id() const {
+ return DisplayServer::INVALID_WINDOW_ID;
+}
+
+Transform2D SubViewport::_stretch_transform() {
+
+ Transform2D transform = Transform2D();
+ Size2i view_size_2d_override = _get_size_2d_override();
+ if (size_2d_override_stretch && view_size_2d_override.width > 0 && view_size_2d_override.height > 0) {
+ Size2 scale = _get_size() / view_size_2d_override;
+ transform.scale(scale);
+ }
+
+ return transform;
+}
+
+void SubViewport::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+ RS::get_singleton()->viewport_set_active(get_viewport_rid(), true);
+ }
+ if (p_what == NOTIFICATION_EXIT_TREE) {
+ RS::get_singleton()->viewport_set_active(get_viewport_rid(), false);
+ }
+}
+
+void SubViewport::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_use_xr", "use"), &SubViewport::set_use_xr);
+ ClassDB::bind_method(D_METHOD("is_using_xr"), &SubViewport::is_using_xr);
+
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &SubViewport::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &SubViewport::get_size);
+
+ ClassDB::bind_method(D_METHOD("set_size_2d_override", "size"), &SubViewport::set_size_2d_override);
+ ClassDB::bind_method(D_METHOD("get_size_2d_override"), &SubViewport::get_size_2d_override);
+
+ ClassDB::bind_method(D_METHOD("set_size_2d_override_stretch", "enable"), &SubViewport::set_size_2d_override_stretch);
+ ClassDB::bind_method(D_METHOD("is_size_2d_override_stretch_enabled"), &SubViewport::is_size_2d_override_stretch_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_update_mode", "mode"), &SubViewport::set_update_mode);
+ ClassDB::bind_method(D_METHOD("get_update_mode"), &SubViewport::get_update_mode);
+
+ ClassDB::bind_method(D_METHOD("set_clear_mode", "mode"), &SubViewport::set_clear_mode);
+ ClassDB::bind_method(D_METHOD("get_clear_mode"), &SubViewport::get_clear_mode);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "xr"), "set_use_xr", "is_using_xr");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size_2d_override"), "set_size_2d_override", "get_size_2d_override");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "size_2d_override_stretch"), "set_size_2d_override_stretch", "is_size_2d_override_stretch_enabled");
+ ADD_GROUP("Render Target", "render_target_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "render_target_clear_mode", PROPERTY_HINT_ENUM, "Always,Never,Next Frame"), "set_clear_mode", "get_clear_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "render_target_update_mode", PROPERTY_HINT_ENUM, "Disabled,Once,When Visible,Always"), "set_update_mode", "get_update_mode");
+
+ BIND_ENUM_CONSTANT(CLEAR_MODE_ALWAYS);
+ BIND_ENUM_CONSTANT(CLEAR_MODE_NEVER);
+ BIND_ENUM_CONSTANT(CLEAR_MODE_ONLY_NEXT_FRAME);
+
+ BIND_ENUM_CONSTANT(UPDATE_DISABLED);
+ BIND_ENUM_CONSTANT(UPDATE_ONCE);
+ BIND_ENUM_CONSTANT(UPDATE_WHEN_VISIBLE);
+ BIND_ENUM_CONSTANT(UPDATE_WHEN_PARENT_VISIBLE);
+ BIND_ENUM_CONSTANT(UPDATE_ALWAYS);
+}
+
+SubViewport::SubViewport() {
+ xr = false;
+ size_2d_override_stretch = false;
+ update_mode = UPDATE_WHEN_VISIBLE;
+ clear_mode = CLEAR_MODE_ALWAYS;
+}
+
+SubViewport::~SubViewport() {
}
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index e511ce1b17..7e2df9fe42 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -35,11 +35,12 @@
#include "scene/main/node.h"
#include "scene/resources/texture.h"
#include "scene/resources/world_2d.h"
-#include "servers/visual_server.h"
+#include "servers/display_server.h"
+#include "servers/rendering_server.h"
-class Camera;
+class Camera3D;
class Camera2D;
-class Listener;
+class Listener3D;
class Control;
class CanvasItem;
class CanvasLayer;
@@ -47,7 +48,7 @@ class Panel;
class Label;
class Timer;
class Viewport;
-class CollisionObject;
+class CollisionObject3D;
class ViewportTexture : public Texture2D {
@@ -88,13 +89,6 @@ class Viewport : public Node {
GDCLASS(Viewport, Node);
public:
- enum UpdateMode {
- UPDATE_DISABLED,
- UPDATE_ONCE, //then goes to disabled
- UPDATE_WHEN_VISIBLE, // default
- UPDATE_ALWAYS
- };
-
enum ShadowAtlasQuadrantSubdiv {
SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED,
SHADOW_ATLAS_QUADRANT_SUBDIV_1,
@@ -112,10 +106,16 @@ public:
MSAA_4X,
MSAA_8X,
MSAA_16X,
+ MSAA_MAX
};
- enum RenderInfo {
+ enum ScreenSpaceAA {
+ SCREEN_SPACE_AA_DISABLED,
+ SCREEN_SPACE_AA_FXAA,
+ SCREEN_SPACE_AA_MAX
+ };
+ enum RenderInfo {
RENDER_INFO_OBJECTS_IN_FRAME,
RENDER_INFO_VERTICES_IN_FRAME,
RENDER_INFO_MATERIAL_CHANGES_IN_FRAME,
@@ -139,14 +139,9 @@ public:
DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS,
DEBUG_DRAW_SCENE_LUMINANCE,
DEBUG_DRAW_SSAO,
- DEBUG_DRAW_ROUGHNESS_LIMITER
- };
-
- enum ClearMode {
-
- CLEAR_MODE_ALWAYS,
- CLEAR_MODE_NEVER,
- CLEAR_MODE_ONLY_NEXT_FRAME
+ DEBUG_DRAW_ROUGHNESS_LIMITER,
+ DEBUG_DRAW_PSSM_SPLITS,
+ DEBUG_DRAW_DECAL_ATLAS
};
enum DefaultCanvasItemTextureFilter {
@@ -164,15 +159,17 @@ public:
DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MAX,
};
+ enum {
+ SUBWINDOW_CANVAS_LAYER = 1024
+ };
+
private:
friend class ViewportTexture;
Viewport *parent;
- Listener *listener;
- Set<Listener *> listeners;
-
- bool arvr;
+ Listener3D *listener;
+ Set<Listener3D *> listeners;
struct CameraOverrideData {
Transform transform;
@@ -192,12 +189,13 @@ private:
}
} camera_override;
- Camera *camera;
- Set<Camera *> cameras;
+ Camera3D *camera;
+ Set<Camera3D *> cameras;
Set<CanvasLayer *> canvas_layers;
RID viewport;
RID current_canvas;
+ RID subwindow_canvas;
bool audio_listener;
RID internal_listener;
@@ -212,23 +210,17 @@ private:
Transform2D global_canvas_transform;
Transform2D stretch_transform;
- Size2 size;
- Rect2 to_screen_rect;
- bool render_direct_to_screen;
+ Size2i size;
+ Size2i size_2d_override;
+ bool size_allocated;
RID contact_2d_debug;
RID contact_3d_debug_multimesh;
RID contact_3d_debug_instance;
- bool size_override;
- bool size_override_stretch;
- Size2 size_override_size;
- Size2 size_override_margin;
-
Rect2 last_vp_rect;
bool transparent_bg;
- ClearMode clear_mode;
bool filter;
bool gen_mipmaps;
@@ -253,7 +245,7 @@ private:
} physics_last_mouse_state;
- void _collision_object_input_event(CollisionObject *p_object, Camera *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape);
+ void _collision_object_input_event(CollisionObject3D *p_object, Camera3D *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape);
bool handle_input_locally;
bool local_input_handled;
@@ -261,9 +253,10 @@ private:
Map<ObjectID, uint64_t> physics_2d_mouseover;
Ref<World2D> world_2d;
- Ref<World> world;
- Ref<World> own_world;
+ Ref<World3D> world;
+ Ref<World3D> own_world;
+ Rect2i to_screen_rect;
StringName input_group;
StringName gui_input_group;
StringName unhandled_input_group;
@@ -276,10 +269,8 @@ private:
void _propagate_exit_world(Node *p_node);
void _propagate_viewport_notification(Node *p_node, int p_what);
- void _update_stretch_transform();
void _update_global_transform();
- UpdateMode update_mode;
RID texture_rid;
DebugDraw debug_draw;
@@ -288,12 +279,39 @@ private:
ShadowAtlasQuadrantSubdiv shadow_atlas_quadrant_subdiv[4];
MSAA msaa;
+ ScreenSpaceAA screen_space_aa;
Ref<ViewportTexture> default_texture;
Set<ViewportTexture *> viewport_textures;
+ enum SubWindowDrag {
+ SUB_WINDOW_DRAG_DISABLED,
+ SUB_WINDOW_DRAG_MOVE,
+ SUB_WINDOW_DRAG_CLOSE,
+ SUB_WINDOW_DRAG_RESIZE,
+ };
+
+ enum SubWindowResize {
+ SUB_WINDOW_RESIZE_DISABLED,
+ SUB_WINDOW_RESIZE_TOP_LEFT,
+ SUB_WINDOW_RESIZE_TOP,
+ SUB_WINDOW_RESIZE_TOP_RIGHT,
+ SUB_WINDOW_RESIZE_LEFT,
+ SUB_WINDOW_RESIZE_RIGHT,
+ SUB_WINDOW_RESIZE_BOTTOM_LEFT,
+ SUB_WINDOW_RESIZE_BOTTOM,
+ SUB_WINDOW_RESIZE_BOTTOM_RIGHT,
+ SUB_WINDOW_RESIZE_MAX
+ };
+
+ struct SubWindow {
+ Window *window;
+ RID canvas_item;
+ };
+
struct GUI {
// info used when this is a window
+ bool forced_mouse_focus; //used for menu buttons
bool key_event_accepted;
Control *mouse_focus;
Control *last_mouse_focus;
@@ -301,8 +319,10 @@ private:
int mouse_focus_mask;
Control *key_focus;
Control *mouse_over;
+ Control *drag_mouse_over;
+ Vector2 drag_mouse_over_pos;
Control *tooltip;
- Control *tooltip_popup;
+ Window *tooltip_popup;
Label *tooltip_label;
Point2 tooltip_pos;
Point2 last_mouse_pos;
@@ -312,16 +332,24 @@ private:
Control *drag_preview;
float tooltip_timer;
float tooltip_delay;
- List<Control *> modal_stack;
Transform2D focus_inv_xform;
- bool subwindow_order_dirty;
- bool subwindow_visibility_dirty;
- List<Control *> subwindows; // visible subwindows
- List<Control *> all_known_subwindows;
bool roots_order_dirty;
List<Control *> roots;
int canvas_sort_index; //for sorting items with canvas as root
bool dragging;
+ bool embed_subwindows_hint;
+ bool embedding_subwindows;
+
+ Window *subwindow_focused;
+ SubWindowDrag subwindow_drag;
+ Vector2 subwindow_drag_from;
+ Vector2 subwindow_drag_pos;
+ Rect2i subwindow_drag_close_rect;
+ bool subwindow_drag_close_inside;
+ SubWindowResize subwindow_resize_mode;
+ Rect2i subwindow_resize_from_rect;
+
+ Vector<SubWindow> sub_windows;
GUI();
} gui;
@@ -337,10 +365,7 @@ private:
void _gui_call_input(Control *p_control, const Ref<InputEvent> &p_input);
void _gui_call_notification(Control *p_control, int p_what);
- void _gui_prepare_subwindows();
- void _gui_sort_subwindows();
void _gui_sort_roots();
- void _gui_sort_modal_stack();
Control *_gui_find_control(const Point2 &p_global);
Control *_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform, Transform2D &r_inv_xform);
@@ -350,25 +375,15 @@ private:
_FORCE_INLINE_ Transform2D _get_input_pre_xform() const;
- void _vp_input(const Ref<InputEvent> &p_ev);
- void _vp_input_text(const String &p_text);
- void _vp_unhandled_input(const Ref<InputEvent> &p_ev);
Ref<InputEvent> _make_input_local(const Ref<InputEvent> &ev);
friend class Control;
List<Control *>::Element *_gui_add_root_control(Control *p_control);
- List<Control *>::Element *_gui_add_subwindow_control(Control *p_control);
-
- void _gui_set_subwindow_order_dirty();
- void _gui_set_root_order_dirty();
- void _gui_remove_modal_control(List<Control *>::Element *MI);
- void _gui_remove_from_modal_stack(List<Control *>::Element *MI, ObjectID p_prev_focus_owner);
void _gui_remove_root_control(List<Control *>::Element *RI);
- void _gui_remove_subwindow_control(List<Control *>::Element *SI);
- String _gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_which = NULL);
+ String _gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_which = nullptr);
void _gui_cancel_tooltip();
void _gui_show_tooltip();
@@ -378,9 +393,6 @@ private:
void _gui_force_drag(Control *p_base, const Variant &p_data, Control *p_control);
void _gui_set_drag_preview(Control *p_base, Control *p_control);
- bool _gui_is_modal_on_top(const Control *p_control);
- List<Control *>::Element *_gui_show_modal(Control *p_control);
-
void _gui_remove_focus();
void _gui_unfocus_control(Control *p_control);
bool _gui_control_has_focus(const Control *p_control);
@@ -391,23 +403,21 @@ private:
Control *_gui_get_focus_owner();
- Vector2 _get_window_offset() const;
-
bool _gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_check);
- friend class Listener;
+ friend class Listener3D;
void _listener_transform_changed_notify();
- void _listener_set(Listener *p_listener);
- bool _listener_add(Listener *p_listener); //true if first
- void _listener_remove(Listener *p_listener);
- void _listener_make_next_current(Listener *p_exclude);
+ void _listener_set(Listener3D *p_listener);
+ bool _listener_add(Listener3D *p_listener); //true if first
+ void _listener_remove(Listener3D *p_listener);
+ void _listener_make_next_current(Listener3D *p_exclude);
- friend class Camera;
+ friend class Camera3D;
void _camera_transform_changed_notify();
- void _camera_set(Camera *p_camera);
- bool _camera_add(Camera *p_camera); //true if first
- void _camera_remove(Camera *p_camera);
- void _camera_make_next_current(Camera *p_exclude);
+ void _camera_set(Camera3D *p_camera);
+ bool _camera_add(Camera3D *p_camera); //true if first
+ void _camera_remove(Camera3D *p_camera);
+ void _camera_make_next_current(Camera3D *p_exclude);
friend class CanvasLayer;
void _canvas_layer_add(CanvasLayer *p_canvas_layer);
@@ -418,16 +428,34 @@ private:
void _update_canvas_items(Node *p_node);
+ void _gui_set_root_order_dirty();
+
void _own_world_changed();
+ friend class Window;
+
+ void _sub_window_update_order();
+ void _sub_window_register(Window *p_window);
+ void _sub_window_update(Window *p_window);
+ void _sub_window_grab_focus(Window *p_window);
+ void _sub_window_remove(Window *p_window);
+ bool _sub_windows_forward_input(const Ref<InputEvent> &p_event);
+ SubWindowResize _sub_window_get_resize_margin(Window *p_subwindow, const Point2 &p_point);
+
protected:
+ void _set_size(const Size2i &p_size, const Size2i &p_size_2d_override, const Rect2i &p_to_screen_rect, const Transform2D &p_stretch_transform, bool p_allocated);
+
+ Size2i _get_size() const;
+ Size2i _get_size_2d_override() const;
+ bool _is_size_allocated() const;
+
void _notification(int p_what);
static void _bind_methods();
virtual void _validate_property(PropertyInfo &property) const;
public:
- Listener *get_listener() const;
- Camera *get_camera() const;
+ Listener3D *get_listener() const;
+ Camera3D *get_camera() const;
void enable_camera_override(bool p_enable);
bool is_camera_override_enabled() const;
@@ -438,26 +466,21 @@ public:
void set_camera_override_perspective(float p_fovy_degrees, float p_z_near, float p_z_far);
void set_camera_override_orthogonal(float p_size, float p_z_near, float p_z_far);
- void set_use_arvr(bool p_use_arvr);
- bool use_arvr();
-
void set_as_audio_listener(bool p_enable);
bool is_audio_listener() const;
void set_as_audio_listener_2d(bool p_enable);
bool is_audio_listener_2d() const;
- void set_size(const Size2 &p_size);
void update_canvas_items();
- Size2 get_size() const;
Rect2 get_visible_rect() const;
RID get_viewport_rid() const;
- void set_world(const Ref<World> &p_world);
+ void set_world(const Ref<World3D> &p_world);
void set_world_2d(const Ref<World2D> &p_world_2d);
- Ref<World> get_world() const;
- Ref<World> find_world() const;
+ Ref<World3D> get_world() const;
+ Ref<World3D> find_world() const;
Ref<World2D> get_world_2d() const;
Ref<World2D> find_world_2d() const;
@@ -479,18 +502,6 @@ public:
void set_transparent_background(bool p_enable);
bool has_transparent_background() const;
- void set_size_override(bool p_enable, const Size2 &p_size = Size2(-1, -1), const Vector2 &p_margin = Vector2());
- Size2 get_size_override() const;
-
- bool is_size_override_enabled() const;
- void set_size_override_stretch(bool p_enable);
- bool is_size_override_stretch_enabled() const;
-
- void set_clear_mode(ClearMode p_mode);
- ClearMode get_clear_mode() const;
-
- void set_update_mode(UpdateMode p_mode);
- UpdateMode get_update_mode() const;
Ref<ViewportTexture> get_texture() const;
void set_shadow_atlas_size(int p_size);
@@ -502,34 +513,29 @@ public:
void set_msaa(MSAA p_msaa);
MSAA get_msaa() const;
+ void set_screen_space_aa(ScreenSpaceAA p_screen_space_aa);
+ ScreenSpaceAA get_screen_space_aa() const;
+
Vector2 get_camera_coords(const Vector2 &p_viewport_coords) const;
Vector2 get_camera_rect_size() const;
void set_use_own_world(bool p_world);
bool is_using_own_world() const;
- void input(const Ref<InputEvent> &p_event);
- void unhandled_input(const Ref<InputEvent> &p_event);
+ void input_text(const String &p_text);
+ void input(const Ref<InputEvent> &p_event, bool p_local_coords = false);
+ void unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coords = false);
void set_disable_input(bool p_disable);
bool is_input_disabled() const;
- void set_attach_to_screen_rect(const Rect2 &p_rect);
- Rect2 get_attach_to_screen_rect() const;
-
- void set_use_render_direct_to_screen(bool p_render_direct_to_screen);
- bool is_using_render_direct_to_screen() const;
-
Vector2 get_mouse_position() const;
void warp_mouse(const Vector2 &p_pos);
void set_physics_object_picking(bool p_enable);
bool get_physics_object_picking();
- bool gui_has_modal_stack() const;
-
Variant gui_get_drag_data() const;
- Control *get_modal_stack_top() const;
void gui_reset_canvas_sort_index();
int gui_get_canvas_sort_index();
@@ -544,8 +550,6 @@ public:
void set_snap_controls_to_pixels(bool p_enable);
bool is_snap_controls_to_pixels_enabled() const;
- void _subwindow_visibility_changed();
-
void set_input_as_handled();
bool is_input_handled() const;
@@ -560,15 +564,80 @@ public:
void set_default_canvas_item_texture_repeat(DefaultCanvasItemTextureRepeat p_repeat);
DefaultCanvasItemTextureRepeat get_default_canvas_item_texture_repeat() const;
+ virtual DisplayServer::WindowID get_window_id() const = 0;
+
+ void set_embed_subwindows_hint(bool p_embed);
+ bool get_embed_subwindows_hint() const;
+ bool is_embedding_subwindows() const;
+
+ Viewport *get_parent_viewport() const;
+
+ void pass_mouse_focus_to(Viewport *p_viewport, Control *p_control);
+
Viewport();
~Viewport();
};
-VARIANT_ENUM_CAST(Viewport::UpdateMode);
+class SubViewport : public Viewport {
+
+ GDCLASS(SubViewport, Viewport);
+
+public:
+ enum ClearMode {
+
+ CLEAR_MODE_ALWAYS,
+ CLEAR_MODE_NEVER,
+ CLEAR_MODE_ONLY_NEXT_FRAME
+ };
+
+ enum UpdateMode {
+ UPDATE_DISABLED,
+ UPDATE_ONCE, //then goes to disabled
+ UPDATE_WHEN_VISIBLE, // default
+ UPDATE_WHEN_PARENT_VISIBLE,
+ UPDATE_ALWAYS
+ };
+
+private:
+ UpdateMode update_mode;
+ ClearMode clear_mode;
+ bool xr;
+ bool size_2d_override_stretch;
+
+protected:
+ static void _bind_methods();
+ virtual DisplayServer::WindowID get_window_id() const;
+ Transform2D _stretch_transform();
+ void _notification(int p_what);
+
+public:
+ void set_size(const Size2i &p_size);
+ Size2i get_size() const;
+
+ void set_size_2d_override(const Size2i &p_size);
+ Size2i get_size_2d_override() const;
+
+ void set_use_xr(bool p_use_xr);
+ bool is_using_xr();
+
+ void set_size_2d_override_stretch(bool p_enable);
+ bool is_size_2d_override_stretch_enabled() const;
+
+ void set_update_mode(UpdateMode p_mode);
+ UpdateMode get_update_mode() const;
+
+ void set_clear_mode(ClearMode p_mode);
+ ClearMode get_clear_mode() const;
+
+ SubViewport();
+ ~SubViewport();
+};
+VARIANT_ENUM_CAST(SubViewport::UpdateMode);
VARIANT_ENUM_CAST(Viewport::ShadowAtlasQuadrantSubdiv);
VARIANT_ENUM_CAST(Viewport::MSAA);
+VARIANT_ENUM_CAST(Viewport::ScreenSpaceAA);
VARIANT_ENUM_CAST(Viewport::DebugDraw);
-VARIANT_ENUM_CAST(Viewport::ClearMode);
+VARIANT_ENUM_CAST(SubViewport::ClearMode);
VARIANT_ENUM_CAST(Viewport::RenderInfo);
VARIANT_ENUM_CAST(Viewport::DefaultCanvasItemTextureFilter);
VARIANT_ENUM_CAST(Viewport::DefaultCanvasItemTextureRepeat);
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
new file mode 100644
index 0000000000..19954299de
--- /dev/null
+++ b/scene/main/window.cpp
@@ -0,0 +1,1406 @@
+/*************************************************************************/
+/* window.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "window.h"
+
+#include "core/debugger/engine_debugger.h"
+#include "core/os/keyboard.h"
+#include "scene/gui/control.h"
+#include "scene/resources/dynamic_font.h"
+#include "scene/scene_string_names.h"
+
+void Window::set_title(const String &p_title) {
+ title = p_title;
+
+ if (embedder) {
+ embedder->_sub_window_update(this);
+
+ } else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+
+ DisplayServer::get_singleton()->window_set_title(p_title, window_id);
+ }
+}
+String Window::get_title() const {
+ return title;
+}
+
+void Window::set_current_screen(int p_screen) {
+ current_screen = p_screen;
+ if (window_id == DisplayServer::INVALID_WINDOW_ID)
+ return;
+ DisplayServer::get_singleton()->window_set_current_screen(p_screen, window_id);
+}
+int Window::get_current_screen() const {
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ current_screen = DisplayServer::get_singleton()->window_get_current_screen(window_id);
+ }
+ return current_screen;
+}
+
+void Window::set_position(const Point2i &p_position) {
+
+ position = p_position;
+
+ if (embedder) {
+ embedder->_sub_window_update(this);
+
+ } else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+
+ DisplayServer::get_singleton()->window_set_position(p_position, window_id);
+ }
+}
+Point2i Window::get_position() const {
+ return position;
+}
+
+void Window::set_size(const Size2i &p_size) {
+ size = p_size;
+ _update_window_size();
+}
+Size2i Window::get_size() const {
+
+ return size;
+}
+
+Size2i Window::get_real_size() const {
+
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ return DisplayServer::get_singleton()->window_get_real_size(window_id);
+ }
+ return size;
+}
+
+void Window::set_max_size(const Size2i &p_max_size) {
+ max_size = p_max_size;
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_set_max_size(max_size, window_id);
+ }
+ _update_window_size();
+}
+
+Size2i Window::get_max_size() const {
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ max_size = DisplayServer::get_singleton()->window_get_max_size(window_id);
+ }
+ return max_size;
+}
+
+void Window::set_min_size(const Size2i &p_min_size) {
+ min_size = p_min_size;
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_set_min_size(min_size, window_id);
+ }
+ _update_window_size();
+}
+
+Size2i Window::get_min_size() const {
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ min_size = DisplayServer::get_singleton()->window_get_min_size(window_id);
+ }
+ return min_size;
+}
+
+void Window::set_mode(Mode p_mode) {
+
+ mode = p_mode;
+
+ if (embedder) {
+ embedder->_sub_window_update(this);
+
+ } else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+
+ DisplayServer::get_singleton()->window_set_mode(DisplayServer::WindowMode(p_mode), window_id);
+ }
+}
+
+Window::Mode Window::get_mode() const {
+
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ mode = (Mode)DisplayServer::get_singleton()->window_get_mode(window_id);
+ }
+ return mode;
+}
+
+void Window::set_flag(Flags p_flag, bool p_enabled) {
+ ERR_FAIL_INDEX(p_flag, FLAG_MAX);
+ flags[p_flag] = p_enabled;
+
+ if (embedder) {
+ embedder->_sub_window_update(this);
+
+ } else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+
+ DisplayServer::get_singleton()->window_set_flag(DisplayServer::WindowFlags(p_flag), p_enabled, window_id);
+ }
+}
+
+bool Window::get_flag(Flags p_flag) const {
+ ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ flags[p_flag] = DisplayServer::get_singleton()->window_get_flag(DisplayServer::WindowFlags(p_flag), window_id);
+ }
+ return flags[p_flag];
+}
+
+bool Window::is_maximize_allowed() const {
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ return DisplayServer::get_singleton()->window_is_maximize_allowed(window_id);
+ }
+ return true;
+}
+
+void Window::request_attention() {
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_request_attention(window_id);
+ }
+}
+void Window::move_to_foreground() {
+
+ if (embedder) {
+ embedder->_sub_window_grab_focus(this);
+
+ } else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_move_to_foreground(window_id);
+ }
+}
+
+bool Window::can_draw() const {
+ if (!is_inside_tree()) {
+ return false;
+ }
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ return DisplayServer::get_singleton()->window_can_draw(window_id);
+ }
+
+ return visible;
+}
+
+void Window::set_ime_active(bool p_active) {
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_set_ime_active(p_active, window_id);
+ }
+}
+void Window::set_ime_position(const Point2i &p_pos) {
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_set_ime_position(p_pos, window_id);
+ }
+}
+
+bool Window::is_embedded() const {
+ ERR_FAIL_COND_V(!is_inside_tree(), false);
+
+ return _get_embedder() != nullptr;
+}
+
+void Window::_make_window() {
+ ERR_FAIL_COND(window_id != DisplayServer::INVALID_WINDOW_ID);
+
+ uint32_t f = 0;
+ for (int i = 0; i < FLAG_MAX; i++) {
+ if (flags[i]) {
+ f |= (1 << i);
+ }
+ }
+
+ window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), f, Rect2i(position, size));
+ ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID);
+ DisplayServer::get_singleton()->window_set_current_screen(current_screen, window_id);
+ DisplayServer::get_singleton()->window_set_max_size(max_size, window_id);
+ DisplayServer::get_singleton()->window_set_min_size(min_size, window_id);
+ DisplayServer::get_singleton()->window_set_title(title, window_id);
+ DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id);
+
+ _update_window_size();
+
+ if (transient_parent && transient_parent->window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_set_transient(window_id, transient_parent->window_id);
+ }
+
+ for (Set<Window *>::Element *E = transient_children.front(); E; E = E->next()) {
+ if (E->get()->window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_set_transient(E->get()->window_id, transient_parent->window_id);
+ }
+ }
+
+ RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_VISIBLE);
+}
+void Window::_update_from_window() {
+
+ ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID);
+ mode = (Mode)DisplayServer::get_singleton()->window_get_mode(window_id);
+ for (int i = 0; i < FLAG_MAX; i++) {
+ flags[i] = DisplayServer::get_singleton()->window_get_flag(DisplayServer::WindowFlags(i), window_id);
+ }
+}
+
+void Window::_clear_window() {
+ ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID);
+
+ if (transient_parent && transient_parent->window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_set_transient(window_id, DisplayServer::INVALID_WINDOW_ID);
+ }
+
+ for (Set<Window *>::Element *E = transient_children.front(); E; E = E->next()) {
+ if (E->get()->window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_set_transient(E->get()->window_id, DisplayServer::INVALID_WINDOW_ID);
+ }
+ }
+
+ _update_from_window();
+
+ DisplayServer::get_singleton()->delete_sub_window(window_id);
+ window_id = DisplayServer::INVALID_WINDOW_ID;
+
+ _update_viewport_size();
+ RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
+}
+
+void Window::_rect_changed_callback(const Rect2i &p_callback) {
+
+ //we must always accept this as the truth
+ if (size == p_callback.size && position == p_callback.position) {
+ return;
+ }
+ position = p_callback.position;
+
+ if (size != p_callback.size) {
+ size = p_callback.size;
+ _update_viewport_size();
+ }
+}
+
+void Window::_propagate_window_notification(Node *p_node, int p_notification) {
+ p_node->notification(p_notification);
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ Node *child = p_node->get_child(i);
+ Window *window = Object::cast_to<Window>(child);
+ if (window) {
+ break;
+ }
+ _propagate_window_notification(child, p_notification);
+ }
+}
+
+void Window::_event_callback(DisplayServer::WindowEvent p_event) {
+
+ switch (p_event) {
+ case DisplayServer::WINDOW_EVENT_MOUSE_ENTER: {
+ _propagate_window_notification(this, NOTIFICATION_WM_MOUSE_ENTER);
+ emit_signal("mouse_entered");
+ } break;
+ case DisplayServer::WINDOW_EVENT_MOUSE_EXIT: {
+ _propagate_window_notification(this, NOTIFICATION_WM_MOUSE_EXIT);
+ emit_signal("mouse_exited");
+ } break;
+ case DisplayServer::WINDOW_EVENT_FOCUS_IN: {
+ focused = true;
+ _propagate_window_notification(this, NOTIFICATION_WM_FOCUS_IN);
+ emit_signal("focus_entered");
+
+ } break;
+ case DisplayServer::WINDOW_EVENT_FOCUS_OUT: {
+ focused = false;
+ _propagate_window_notification(this, NOTIFICATION_WM_FOCUS_OUT);
+ emit_signal("focus_exited");
+ } break;
+ case DisplayServer::WINDOW_EVENT_CLOSE_REQUEST: {
+ if (exclusive_child != nullptr) {
+ break; //has an exclusive child, can't get events until child is closed
+ }
+ _propagate_window_notification(this, NOTIFICATION_WM_CLOSE_REQUEST);
+ emit_signal("close_requested");
+ } break;
+ case DisplayServer::WINDOW_EVENT_GO_BACK_REQUEST: {
+ _propagate_window_notification(this, NOTIFICATION_WM_GO_BACK_REQUEST);
+ emit_signal("go_back_requested");
+ } break;
+ case DisplayServer::WINDOW_EVENT_DPI_CHANGE: {
+ _propagate_window_notification(this, NOTIFICATION_WM_DPI_CHANGE);
+ emit_signal("dpi_changed");
+ } break;
+ }
+}
+
+void Window::show() {
+ set_visible(true);
+}
+void Window::hide() {
+ set_visible(false);
+}
+
+void Window::set_visible(bool p_visible) {
+
+ if (visible == p_visible) {
+ return;
+ }
+
+ visible = p_visible;
+
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ if (updating_child_controls) {
+ _update_child_controls();
+ }
+
+ ERR_FAIL_COND_MSG(get_parent() == nullptr, "Can't change visibility of main window.");
+
+ Viewport *embedder_vp = _get_embedder();
+
+ if (!embedder_vp) {
+ if (!p_visible && window_id != DisplayServer::INVALID_WINDOW_ID) {
+ _clear_window();
+ }
+ if (p_visible && window_id == DisplayServer::INVALID_WINDOW_ID) {
+ _make_window();
+ _update_window_callbacks();
+ }
+ } else {
+ if (visible) {
+ embedder = embedder_vp;
+ embedder->_sub_window_register(this);
+ RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE);
+ } else {
+ embedder->_sub_window_remove(this);
+ embedder = nullptr;
+ RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
+ }
+ _update_window_size();
+ }
+
+ if (!visible) {
+ focused = false;
+ }
+ notification(NOTIFICATION_VISIBILITY_CHANGED);
+ emit_signal(SceneStringNames::get_singleton()->visibility_changed);
+
+ RS::get_singleton()->viewport_set_active(get_viewport_rid(), visible);
+}
+
+void Window::_clear_transient() {
+ if (transient_parent) {
+ if (transient_parent->window_id != DisplayServer::INVALID_WINDOW_ID && window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_set_transient(window_id, DisplayServer::INVALID_WINDOW_ID);
+ }
+ transient_parent->transient_children.erase(this);
+ if (transient_parent->exclusive_child == this) {
+ transient_parent->exclusive_child = nullptr;
+ }
+ transient_parent = nullptr;
+ }
+}
+
+void Window::_make_transient() {
+ if (!get_parent()) {
+ //main window, can't be transient
+ return;
+ }
+ //find transient parent
+ Viewport *vp = get_parent()->get_viewport();
+ Window *window = nullptr;
+ while (vp) {
+ window = Object::cast_to<Window>(vp);
+ if (window) {
+ break;
+ }
+ if (!vp->get_parent()) {
+ break;
+ }
+
+ vp = vp->get_parent()->get_viewport();
+ }
+
+ if (window) {
+ transient_parent = window;
+ window->transient_children.insert(this);
+ if (is_inside_tree() && is_visible() && exclusive) {
+ if (transient_parent->exclusive_child == nullptr) {
+ transient_parent->exclusive_child = this;
+ } else if (transient_parent->exclusive_child != this) {
+ ERR_PRINT("Making child transient exclusive, but parent has another exclusive child");
+ }
+ }
+ }
+
+ //see if we can make transient
+ if (transient_parent->window_id != DisplayServer::INVALID_WINDOW_ID && window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_set_transient(window_id, transient_parent->window_id);
+ }
+}
+
+void Window::set_transient(bool p_transient) {
+ if (transient == p_transient) {
+ return;
+ }
+
+ transient = p_transient;
+
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ if (transient) {
+ _make_transient();
+ } else {
+ _clear_transient();
+ }
+}
+bool Window::is_transient() const {
+ return transient;
+}
+
+void Window::set_exclusive(bool p_exclusive) {
+
+ if (exclusive == p_exclusive) {
+ return;
+ }
+
+ exclusive = p_exclusive;
+
+ if (transient_parent) {
+ if (p_exclusive && is_inside_tree() && is_visible()) {
+ ERR_FAIL_COND_MSG(transient_parent->exclusive_child && transient_parent->exclusive_child != this, "Transient parent has another exclusive child.");
+ transient_parent->exclusive_child = this;
+ } else {
+ if (transient_parent->exclusive_child == this) {
+ transient_parent->exclusive_child = nullptr;
+ }
+ }
+ }
+}
+
+bool Window::is_exclusive() const {
+ return exclusive;
+}
+
+bool Window::is_visible() const {
+ return visible;
+}
+
+void Window::_update_window_size() {
+
+ Size2i size_limit;
+ if (wrap_controls) {
+ size_limit = get_contents_minimum_size();
+ }
+
+ size_limit.x = MAX(size_limit.x, min_size.x);
+ size_limit.y = MAX(size_limit.y, min_size.y);
+
+ size.x = MAX(size_limit.x, size.x);
+ size.y = MAX(size_limit.y, size.y);
+
+ if (max_size.x > 0 && max_size.x > min_size.x && max_size.x > size.x) {
+ size.x = max_size.x;
+ }
+
+ if (max_size.y > 0 && max_size.y > min_size.y && max_size.y > size.y) {
+ size.y = max_size.y;
+ }
+
+ if (embedder) {
+ embedder->_sub_window_update(this);
+ } else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_set_size(size, window_id);
+ }
+
+ //update the viewport
+ _update_viewport_size();
+}
+void Window::_update_viewport_size() {
+ //update the viewport part
+
+ Size2i final_size;
+ Size2i final_size_override;
+ Rect2i attach_to_screen_rect(Point2i(), size);
+ Transform2D stretch_transform;
+ float font_oversampling = 1.0;
+
+ if (content_scale_mode == CONTENT_SCALE_MODE_DISABLED || content_scale_size.x == 0 || content_scale_size.y == 0) {
+
+ stretch_transform = Transform2D();
+ final_size = size;
+
+ } else {
+
+ //actual screen video mode
+ Size2 video_mode = size;
+ Size2 desired_res = content_scale_size;
+
+ Size2 viewport_size;
+ Size2 screen_size;
+
+ float viewport_aspect = desired_res.aspect();
+ float video_mode_aspect = video_mode.aspect();
+
+ if (content_scale_aspect == CONTENT_SCALE_ASPECT_IGNORE || Math::is_equal_approx(viewport_aspect, video_mode_aspect)) {
+ //same aspect or ignore aspect
+ viewport_size = desired_res;
+ screen_size = video_mode;
+ } else if (viewport_aspect < video_mode_aspect) {
+ // screen ratio is smaller vertically
+
+ if (content_scale_aspect == CONTENT_SCALE_ASPECT_KEEP_HEIGHT || content_scale_aspect == CONTENT_SCALE_ASPECT_EXPAND) {
+
+ //will stretch horizontally
+ viewport_size.x = desired_res.y * video_mode_aspect;
+ viewport_size.y = desired_res.y;
+ screen_size = video_mode;
+
+ } else {
+ //will need black bars
+ viewport_size = desired_res;
+ screen_size.x = video_mode.y * viewport_aspect;
+ screen_size.y = video_mode.y;
+ }
+ } else {
+ //screen ratio is smaller horizontally
+ if (content_scale_aspect == CONTENT_SCALE_ASPECT_KEEP_WIDTH || content_scale_aspect == CONTENT_SCALE_ASPECT_EXPAND) {
+
+ //will stretch horizontally
+ viewport_size.x = desired_res.x;
+ viewport_size.y = desired_res.x / video_mode_aspect;
+ screen_size = video_mode;
+
+ } else {
+ //will need black bars
+ viewport_size = desired_res;
+ screen_size.x = video_mode.x;
+ screen_size.y = video_mode.x / viewport_aspect;
+ }
+ }
+
+ screen_size = screen_size.floor();
+ viewport_size = viewport_size.floor();
+
+ Size2 margin;
+ Size2 offset;
+ //black bars and margin
+ if (content_scale_aspect != CONTENT_SCALE_ASPECT_EXPAND && screen_size.x < video_mode.x) {
+ margin.x = Math::round((video_mode.x - screen_size.x) / 2.0);
+ //RenderingServer::get_singleton()->black_bars_set_margins(margin.x, 0, margin.x, 0);
+ offset.x = Math::round(margin.x * viewport_size.y / screen_size.y);
+ } else if (content_scale_aspect != CONTENT_SCALE_ASPECT_EXPAND && screen_size.y < video_mode.y) {
+ margin.y = Math::round((video_mode.y - screen_size.y) / 2.0);
+ //RenderingServer::get_singleton()->black_bars_set_margins(0, margin.y, 0, margin.y);
+ offset.y = Math::round(margin.y * viewport_size.x / screen_size.x);
+ } else {
+ //RenderingServer::get_singleton()->black_bars_set_margins(0, 0, 0, 0);
+ }
+
+ switch (content_scale_mode) {
+ case CONTENT_SCALE_MODE_DISABLED: {
+ // Already handled above
+ //_update_font_oversampling(1.0);
+ } break;
+ case CONTENT_SCALE_MODE_OBJECTS: {
+
+ final_size = screen_size;
+ final_size_override = viewport_size;
+ attach_to_screen_rect = Rect2(margin, screen_size);
+ font_oversampling = screen_size.x / viewport_size.x;
+ } break;
+ case CONTENT_SCALE_MODE_PIXELS: {
+
+ final_size = viewport_size;
+ attach_to_screen_rect = Rect2(margin, screen_size);
+
+ } break;
+ }
+
+ Size2 scale = size / (Vector2(final_size) + margin * 2);
+ stretch_transform.scale(scale);
+ stretch_transform.elements[2] = margin * scale;
+ }
+
+ bool allocate = is_inside_tree() && visible && (window_id != DisplayServer::INVALID_WINDOW_ID || embedder != nullptr);
+
+ _set_size(final_size, final_size_override, attach_to_screen_rect, stretch_transform, allocate);
+
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ RenderingServer::get_singleton()->viewport_attach_to_screen(get_viewport_rid(), attach_to_screen_rect, window_id);
+ } else {
+ RenderingServer::get_singleton()->viewport_attach_to_screen(get_viewport_rid(), Rect2i(), DisplayServer::INVALID_WINDOW_ID);
+ }
+
+ if (window_id == DisplayServer::MAIN_WINDOW_ID) {
+
+ if (!use_font_oversampling) {
+ font_oversampling = 1.0;
+ }
+ if (DynamicFontAtSize::font_oversampling != font_oversampling) {
+
+ DynamicFontAtSize::font_oversampling = font_oversampling;
+ DynamicFont::update_oversampling();
+ }
+ }
+
+ notification(NOTIFICATION_WM_SIZE_CHANGED);
+
+ if (embedder) {
+ embedder->_sub_window_update(this);
+ }
+}
+
+void Window::_update_window_callbacks() {
+ DisplayServer::get_singleton()->window_set_rect_changed_callback(callable_mp(this, &Window::_rect_changed_callback), window_id);
+ DisplayServer::get_singleton()->window_set_window_event_callback(callable_mp(this, &Window::_event_callback), window_id);
+ DisplayServer::get_singleton()->window_set_input_event_callback(callable_mp(this, &Window::_window_input), window_id);
+ DisplayServer::get_singleton()->window_set_input_text_callback(callable_mp(this, &Window::_window_input_text), window_id);
+ DisplayServer::get_singleton()->window_set_drop_files_callback(callable_mp(this, &Window::_window_drop_files), window_id);
+}
+
+Viewport *Window::_get_embedder() const {
+
+ Viewport *vp = get_parent_viewport();
+
+ while (vp) {
+
+ if (vp->is_embedding_subwindows()) {
+ return vp;
+ }
+
+ if (vp->get_parent()) {
+ vp = vp->get_parent()->get_viewport();
+ } else {
+ vp = nullptr;
+ }
+ }
+ return nullptr;
+}
+
+void Window::_notification(int p_what) {
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+
+ bool embedded = false;
+ {
+
+ embedder = _get_embedder();
+
+ if (embedder) {
+ embedded = true;
+
+ if (!visible) {
+ embedder = nullptr; //not yet since not visible
+ }
+ }
+ }
+
+ if (embedded) {
+ //create as embedded
+ if (embedder) {
+ embedder->_sub_window_register(this);
+ RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE);
+ _update_window_size();
+ }
+
+ } else {
+ if (get_parent() == nullptr) {
+ //it's the root window!
+ visible = true; //always visible
+ window_id = DisplayServer::MAIN_WINDOW_ID;
+ DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id);
+ _update_from_window();
+ //since this window already exists (created on start), we must update pos and size from it
+ {
+ position = DisplayServer::get_singleton()->window_get_position(window_id);
+ size = DisplayServer::get_singleton()->window_get_size(window_id);
+ }
+ _update_viewport_size(); //then feed back to the viewport
+ _update_window_callbacks();
+ RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_VISIBLE);
+ } else {
+ //create
+ if (visible) {
+ _make_window();
+ _update_window_callbacks();
+ }
+ }
+ }
+
+ if (transient) {
+ _make_transient();
+ }
+ if (visible) {
+ notification(NOTIFICATION_VISIBILITY_CHANGED);
+ emit_signal(SceneStringNames::get_singleton()->visibility_changed);
+ RS::get_singleton()->viewport_set_active(get_viewport_rid(), true);
+ }
+ }
+
+ if (p_what == NOTIFICATION_READY) {
+
+ if (wrap_controls) {
+ _update_child_controls();
+ }
+ }
+
+ if (p_what == NOTIFICATION_EXIT_TREE) {
+
+ if (transient) {
+ _clear_transient();
+ }
+
+ if (!is_embedded() && window_id != DisplayServer::INVALID_WINDOW_ID) {
+
+ if (window_id == DisplayServer::MAIN_WINDOW_ID) {
+
+ RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
+ _update_window_callbacks();
+ } else {
+ _clear_window();
+ }
+ } else {
+
+ if (embedder) {
+ embedder->_sub_window_remove(this);
+ embedder = nullptr;
+ RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
+ }
+ _update_viewport_size(); //called by clear and make, which does not happen here
+ }
+
+ RS::get_singleton()->viewport_set_active(get_viewport_rid(), false);
+ }
+}
+
+void Window::set_content_scale_size(const Size2i &p_size) {
+ ERR_FAIL_COND(p_size.x < 0);
+ ERR_FAIL_COND(p_size.y < 0);
+ content_scale_size = p_size;
+ _update_viewport_size();
+}
+
+Size2i Window::get_content_scale_size() const {
+ return content_scale_size;
+}
+
+void Window::set_content_scale_mode(ContentScaleMode p_mode) {
+ content_scale_mode = p_mode;
+ _update_viewport_size();
+}
+Window::ContentScaleMode Window::get_content_scale_mode() const {
+ return content_scale_mode;
+}
+
+void Window::set_content_scale_aspect(ContentScaleAspect p_aspect) {
+ content_scale_aspect = p_aspect;
+ _update_viewport_size();
+}
+Window::ContentScaleAspect Window::get_content_scale_aspect() const {
+ return content_scale_aspect;
+}
+
+void Window::set_use_font_oversampling(bool p_oversampling) {
+ if (is_inside_tree() && window_id != DisplayServer::MAIN_WINDOW_ID) {
+ ERR_FAIL_MSG("Only the root window can set and use font oversampling.");
+ }
+ use_font_oversampling = p_oversampling;
+ _update_viewport_size();
+}
+bool Window::is_using_font_oversampling() const {
+ return use_font_oversampling;
+}
+
+DisplayServer::WindowID Window::get_window_id() const {
+ return window_id;
+}
+
+void Window::set_wrap_controls(bool p_enable) {
+ wrap_controls = p_enable;
+ if (wrap_controls) {
+ child_controls_changed();
+ }
+}
+
+bool Window::is_wrapping_controls() const {
+ return wrap_controls;
+}
+
+Size2 Window::_get_contents_minimum_size() const {
+ Size2 max;
+
+ for (int i = 0; i < get_child_count(); i++) {
+ Control *c = Object::cast_to<Control>(get_child(i));
+ if (c) {
+ Point2i pos = c->get_position();
+ Size2i min = c->get_combined_minimum_size();
+
+ max.x = MAX(pos.x + min.x, max.x);
+ max.y = MAX(pos.y + min.y, max.y);
+ }
+ }
+
+ return max;
+}
+void Window::_update_child_controls() {
+
+ if (!updating_child_controls) {
+ return;
+ }
+
+ _update_window_size();
+
+ updating_child_controls = false;
+}
+void Window::child_controls_changed() {
+
+ if (!is_inside_tree() || !visible || updating_child_controls) {
+ return;
+ }
+
+ updating_child_controls = true;
+ call_deferred("_update_child_controls");
+}
+
+void Window::_window_input(const Ref<InputEvent> &p_ev) {
+ if (Engine::get_singleton()->is_editor_hint() && (Object::cast_to<InputEventJoypadButton>(p_ev.ptr()) || Object::cast_to<InputEventJoypadMotion>(*p_ev)))
+ return; //avoid joy input on editor
+
+ if (EngineDebugger::is_active()) {
+ //quit from game window using F8
+ Ref<InputEventKey> k = p_ev;
+ if (k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_keycode() == KEY_F8) {
+ EngineDebugger::get_singleton()->send_message("request_quit", Array());
+ }
+ }
+
+ if (exclusive_child != nullptr) {
+ exclusive_child->grab_focus();
+
+ return; //has an exclusive child, can't get events until child is closed
+ }
+
+ emit_signal(SceneStringNames::get_singleton()->window_input, p_ev);
+ input(p_ev);
+ if (!is_input_handled()) {
+ unhandled_input(p_ev);
+ }
+}
+void Window::_window_input_text(const String &p_text) {
+ input_text(p_text);
+}
+void Window::_window_drop_files(const Vector<String> &p_files) {
+ emit_signal("files_dropped", p_files, current_screen);
+}
+
+Viewport *Window::get_parent_viewport() const {
+
+ if (get_parent()) {
+ return get_parent()->get_viewport();
+ } else {
+ return nullptr;
+ }
+}
+
+Window *Window::get_parent_visible_window() const {
+
+ Viewport *vp = get_parent_viewport();
+ Window *window = nullptr;
+ while (vp) {
+ window = Object::cast_to<Window>(vp);
+ if (window && window->visible) {
+ break;
+ }
+ if (!vp->get_parent()) {
+ break;
+ }
+
+ vp = vp->get_parent()->get_viewport();
+ }
+ return window;
+}
+
+void Window::popup_on_parent(const Rect2i &p_parent_rect) {
+
+ ERR_FAIL_COND(!is_inside_tree());
+ ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window.");
+
+ if (!is_embedded()) {
+ Window *window = get_parent_visible_window();
+
+ if (!window) {
+ popup(p_parent_rect);
+ } else {
+ popup(Rect2i(window->get_position() + p_parent_rect.position, p_parent_rect.size));
+ }
+ } else {
+ popup(p_parent_rect);
+ }
+}
+
+void Window::popup_centered_clamped(const Size2i &p_size, float p_fallback_ratio) {
+
+ ERR_FAIL_COND(!is_inside_tree());
+ ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window.");
+
+ Rect2 parent_rect;
+
+ if (is_embedded()) {
+ parent_rect = get_parent_viewport()->get_visible_rect();
+ } else {
+ DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id();
+ int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id);
+ parent_rect.position = DisplayServer::get_singleton()->screen_get_position(parent_screen);
+ parent_rect.size = DisplayServer::get_singleton()->screen_get_size(parent_screen);
+ }
+
+ Vector2i size_ratio = parent_rect.size * p_fallback_ratio;
+
+ Rect2i popup_rect;
+ popup_rect.size = Vector2i(MIN(size_ratio.x, p_size.x), MIN(size_ratio.y, p_size.y));
+ popup_rect.position = (parent_rect.size - popup_rect.size) / 2;
+
+ popup(popup_rect);
+}
+
+void Window::popup_centered(const Size2i &p_minsize) {
+ ERR_FAIL_COND(!is_inside_tree());
+ ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window.");
+
+ Rect2 parent_rect;
+
+ if (is_embedded()) {
+ parent_rect = get_parent_viewport()->get_visible_rect();
+ } else {
+ DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id();
+ int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id);
+ parent_rect.position = DisplayServer::get_singleton()->screen_get_position(parent_screen);
+ parent_rect.size = DisplayServer::get_singleton()->screen_get_size(parent_screen);
+ }
+
+ Rect2i popup_rect;
+ if (p_minsize == Size2i()) {
+ popup_rect.size = _get_contents_minimum_size();
+ } else {
+ popup_rect.size = p_minsize;
+ }
+ popup_rect.position = (parent_rect.size - popup_rect.size) / 2;
+
+ popup(popup_rect);
+}
+
+void Window::popup_centered_ratio(float p_ratio) {
+
+ ERR_FAIL_COND(!is_inside_tree());
+ ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window.");
+
+ Rect2i parent_rect;
+
+ if (is_embedded()) {
+ parent_rect = get_parent_viewport()->get_visible_rect();
+ } else {
+ DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id();
+ int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id);
+ parent_rect.position = DisplayServer::get_singleton()->screen_get_position(parent_screen);
+ parent_rect.size = DisplayServer::get_singleton()->screen_get_size(parent_screen);
+ }
+
+ Rect2i popup_rect;
+ popup_rect.size = parent_rect.size * p_ratio;
+ popup_rect.position = (parent_rect.size - popup_rect.size) / 2;
+
+ popup(popup_rect);
+}
+
+void Window::popup(const Rect2i &p_screen_rect) {
+
+ emit_signal("about_to_popup");
+
+ if (p_screen_rect != Rect2i()) {
+ set_position(p_screen_rect.position);
+ set_size(p_screen_rect.size);
+ }
+
+ Rect2i adjust = _popup_adjust_rect();
+ if (adjust != Rect2i()) {
+ set_position(adjust.position);
+ set_size(adjust.size);
+ }
+
+ set_transient(true);
+ set_visible(true);
+ _post_popup();
+ notification(NOTIFICATION_POST_POPUP);
+}
+
+Size2 Window::get_contents_minimum_size() const {
+ return _get_contents_minimum_size();
+}
+
+void Window::grab_focus() {
+ if (embedder) {
+ embedder->_sub_window_grab_focus(this);
+ } else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_move_to_foreground(window_id);
+ }
+}
+
+bool Window::has_focus() const {
+ return focused;
+}
+
+Rect2i Window::get_usable_parent_rect() const {
+ ERR_FAIL_COND_V(!is_inside_tree(), Rect2());
+ Rect2i parent;
+ if (is_embedded()) {
+ parent = _get_embedder()->get_visible_rect();
+ } else {
+
+ const Window *w = is_visible() ? this : get_parent_visible_window();
+ //find a parent that can contain us
+ ERR_FAIL_COND_V(!w, Rect2());
+
+ parent = DisplayServer::get_singleton()->screen_get_usable_rect(DisplayServer::get_singleton()->window_get_current_screen(w->get_window_id()));
+ }
+ return parent;
+}
+
+void Window::add_child_notify(Node *p_child) {
+
+ Control *child_c = Object::cast_to<Control>(p_child);
+
+ if (child_c && child_c->data.theme.is_null() && (theme_owner || theme_owner_window)) {
+ Control::_propagate_theme_changed(child_c, theme_owner, theme_owner_window); //need to propagate here, since many controls may require setting up stuff
+ }
+
+ Window *child_w = Object::cast_to<Window>(p_child);
+
+ if (child_w && child_w->theme.is_null() && (theme_owner || theme_owner_window)) {
+ Control::_propagate_theme_changed(child_w, theme_owner, theme_owner_window); //need to propagate here, since many controls may require setting up stuff
+ }
+
+ if (is_inside_tree() && wrap_controls) {
+ child_controls_changed();
+ }
+}
+
+void Window::remove_child_notify(Node *p_child) {
+
+ Control *child_c = Object::cast_to<Control>(p_child);
+
+ if (child_c && (child_c->data.theme_owner || child_c->data.theme_owner_window) && child_c->data.theme.is_null()) {
+ Control::_propagate_theme_changed(child_c, nullptr, nullptr);
+ }
+
+ Window *child_w = Object::cast_to<Window>(p_child);
+
+ if (child_w && (child_w->theme_owner || child_w->theme_owner_window) && child_w->theme.is_null()) {
+ Control::_propagate_theme_changed(child_w, nullptr, nullptr);
+ }
+
+ if (is_inside_tree() && wrap_controls) {
+ child_controls_changed();
+ }
+}
+
+void Window::set_theme(const Ref<Theme> &p_theme) {
+
+ if (theme == p_theme)
+ return;
+
+ theme = p_theme;
+
+ if (!p_theme.is_null()) {
+
+ theme_owner = nullptr;
+ theme_owner_window = this;
+ Control::_propagate_theme_changed(this, nullptr, this);
+ } else {
+
+ Control *parent_c = cast_to<Control>(get_parent());
+ if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) {
+ Control::_propagate_theme_changed(this, parent_c->data.theme_owner, parent_c->data.theme_owner_window);
+ } else {
+ Window *parent_w = cast_to<Window>(get_parent());
+ if (parent_w && (parent_w->theme_owner || parent_w->theme_owner_window)) {
+ Control::_propagate_theme_changed(this, parent_w->theme_owner, parent_w->theme_owner_window);
+ } else {
+ Control::_propagate_theme_changed(this, nullptr, nullptr);
+ }
+ }
+ }
+}
+Ref<Theme> Window::get_theme() const {
+ return theme;
+}
+
+Ref<Texture2D> Window::get_theme_icon(const StringName &p_name, const StringName &p_type) const {
+ StringName type = p_type ? p_type : get_class_name();
+ return Control::get_icons(theme_owner, theme_owner_window, p_name, type);
+}
+Ref<Shader> Window::get_theme_shader(const StringName &p_name, const StringName &p_type) const {
+ StringName type = p_type ? p_type : get_class_name();
+ return Control::get_shaders(theme_owner, theme_owner_window, p_name, type);
+}
+Ref<StyleBox> Window::get_theme_stylebox(const StringName &p_name, const StringName &p_type) const {
+ StringName type = p_type ? p_type : get_class_name();
+ return Control::get_styleboxs(theme_owner, theme_owner_window, p_name, type);
+}
+Ref<Font> Window::get_theme_font(const StringName &p_name, const StringName &p_type) const {
+ StringName type = p_type ? p_type : get_class_name();
+ return Control::get_fonts(theme_owner, theme_owner_window, p_name, type);
+}
+Color Window::get_theme_color(const StringName &p_name, const StringName &p_type) const {
+ StringName type = p_type ? p_type : get_class_name();
+ return Control::get_colors(theme_owner, theme_owner_window, p_name, type);
+}
+int Window::get_theme_constant(const StringName &p_name, const StringName &p_type) const {
+ StringName type = p_type ? p_type : get_class_name();
+ return Control::get_constants(theme_owner, theme_owner_window, p_name, type);
+}
+
+bool Window::has_theme_icon(const StringName &p_name, const StringName &p_type) const {
+ StringName type = p_type ? p_type : get_class_name();
+ return Control::has_icons(theme_owner, theme_owner_window, p_name, type);
+}
+bool Window::has_theme_shader(const StringName &p_name, const StringName &p_type) const {
+ StringName type = p_type ? p_type : get_class_name();
+ return Control::has_shaders(theme_owner, theme_owner_window, p_name, type);
+}
+bool Window::has_theme_stylebox(const StringName &p_name, const StringName &p_type) const {
+ StringName type = p_type ? p_type : get_class_name();
+ return Control::has_styleboxs(theme_owner, theme_owner_window, p_name, type);
+}
+bool Window::has_theme_font(const StringName &p_name, const StringName &p_type) const {
+ StringName type = p_type ? p_type : get_class_name();
+ return Control::has_fonts(theme_owner, theme_owner_window, p_name, type);
+}
+bool Window::has_theme_color(const StringName &p_name, const StringName &p_type) const {
+ StringName type = p_type ? p_type : get_class_name();
+ return Control::has_colors(theme_owner, theme_owner_window, p_name, type);
+}
+bool Window::has_theme_constant(const StringName &p_name, const StringName &p_type) const {
+ StringName type = p_type ? p_type : get_class_name();
+ return Control::has_constants(theme_owner, theme_owner_window, p_name, type);
+}
+
+Rect2i Window::get_parent_rect() const {
+ ERR_FAIL_COND_V(!is_inside_tree(), Rect2i());
+ if (is_embedded()) {
+ //viewport
+ Node *n = get_parent();
+ ERR_FAIL_COND_V(!n, Rect2i());
+ Viewport *p = n->get_viewport();
+ ERR_FAIL_COND_V(!p, Rect2i());
+
+ return p->get_visible_rect();
+ } else {
+ int x = get_position().x;
+ int closest_dist = 0x7FFFFFFF;
+ Rect2i closest_rect;
+ for (int i = 0; i < DisplayServer::get_singleton()->get_screen_count(); i++) {
+ Rect2i s(DisplayServer::get_singleton()->screen_get_position(i), DisplayServer::get_singleton()->screen_get_size(i));
+ int d;
+ if (x >= s.position.x && x < s.size.x) {
+ //contained
+ closest_rect = s;
+ break;
+ } else if (x < s.position.x) {
+ d = s.position.x - x;
+ } else {
+ d = x - (s.position.x + s.size.x);
+ }
+
+ if (d < closest_dist) {
+ closest_dist = d;
+ closest_rect = s;
+ }
+ }
+ return closest_rect;
+ }
+}
+
+void Window::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_title", "title"), &Window::set_title);
+ ClassDB::bind_method(D_METHOD("get_title"), &Window::get_title);
+
+ ClassDB::bind_method(D_METHOD("set_current_screen", "index"), &Window::set_current_screen);
+ ClassDB::bind_method(D_METHOD("get_current_screen"), &Window::get_current_screen);
+
+ ClassDB::bind_method(D_METHOD("set_position", "position"), &Window::set_position);
+ ClassDB::bind_method(D_METHOD("get_position"), &Window::get_position);
+
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &Window::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &Window::get_size);
+
+ ClassDB::bind_method(D_METHOD("get_real_size"), &Window::get_real_size);
+
+ ClassDB::bind_method(D_METHOD("set_max_size", "max_size"), &Window::set_max_size);
+ ClassDB::bind_method(D_METHOD("get_max_size"), &Window::get_max_size);
+
+ ClassDB::bind_method(D_METHOD("set_min_size", "min_size"), &Window::set_min_size);
+ ClassDB::bind_method(D_METHOD("get_min_size"), &Window::get_min_size);
+
+ ClassDB::bind_method(D_METHOD("set_mode", "mode"), &Window::set_mode);
+ ClassDB::bind_method(D_METHOD("get_mode"), &Window::get_mode);
+
+ ClassDB::bind_method(D_METHOD("set_flag", "flag", "enabled"), &Window::set_flag);
+ ClassDB::bind_method(D_METHOD("get_flag", "flag"), &Window::get_flag);
+
+ ClassDB::bind_method(D_METHOD("is_maximize_allowed"), &Window::is_maximize_allowed);
+
+ ClassDB::bind_method(D_METHOD("request_attention"), &Window::request_attention);
+
+ ClassDB::bind_method(D_METHOD("move_to_foreground"), &Window::move_to_foreground);
+
+ ClassDB::bind_method(D_METHOD("set_visible", "visible"), &Window::set_visible);
+ ClassDB::bind_method(D_METHOD("is_visible"), &Window::is_visible);
+
+ ClassDB::bind_method(D_METHOD("hide"), &Window::hide);
+ ClassDB::bind_method(D_METHOD("show"), &Window::show);
+
+ ClassDB::bind_method(D_METHOD("set_transient", "transient"), &Window::set_transient);
+ ClassDB::bind_method(D_METHOD("is_transient"), &Window::is_transient);
+
+ ClassDB::bind_method(D_METHOD("set_exclusive", "exclusive"), &Window::set_exclusive);
+ ClassDB::bind_method(D_METHOD("is_exclusive"), &Window::is_exclusive);
+
+ ClassDB::bind_method(D_METHOD("can_draw"), &Window::can_draw);
+ ClassDB::bind_method(D_METHOD("has_focus"), &Window::has_focus);
+ ClassDB::bind_method(D_METHOD("grab_focus"), &Window::grab_focus);
+
+ ClassDB::bind_method(D_METHOD("set_ime_active"), &Window::set_ime_active);
+ ClassDB::bind_method(D_METHOD("set_ime_position"), &Window::set_ime_position);
+
+ ClassDB::bind_method(D_METHOD("is_embedded"), &Window::is_embedded);
+
+ ClassDB::bind_method(D_METHOD("set_content_scale_size", "size"), &Window::set_content_scale_size);
+ ClassDB::bind_method(D_METHOD("get_content_scale_size"), &Window::get_content_scale_size);
+
+ ClassDB::bind_method(D_METHOD("set_content_scale_mode", "mode"), &Window::set_content_scale_mode);
+ ClassDB::bind_method(D_METHOD("get_content_scale_mode"), &Window::get_content_scale_mode);
+
+ ClassDB::bind_method(D_METHOD("set_content_scale_aspect", "aspect"), &Window::set_content_scale_aspect);
+ ClassDB::bind_method(D_METHOD("get_content_scale_aspect"), &Window::get_content_scale_aspect);
+
+ ClassDB::bind_method(D_METHOD("set_use_font_oversampling", "enable"), &Window::set_use_font_oversampling);
+ ClassDB::bind_method(D_METHOD("is_using_font_oversampling"), &Window::is_using_font_oversampling);
+
+ ClassDB::bind_method(D_METHOD("set_wrap_controls", "enable"), &Window::set_wrap_controls);
+ ClassDB::bind_method(D_METHOD("is_wrapping_controls"), &Window::is_wrapping_controls);
+ ClassDB::bind_method(D_METHOD("child_controls_changed"), &Window::child_controls_changed);
+
+ ClassDB::bind_method(D_METHOD("_update_child_controls"), &Window::_update_child_controls);
+
+ ClassDB::bind_method(D_METHOD("set_theme", "theme"), &Window::set_theme);
+ ClassDB::bind_method(D_METHOD("get_theme"), &Window::get_theme);
+
+ ClassDB::bind_method(D_METHOD("get_theme_icon", "name", "type"), &Window::get_theme_icon, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_stylebox", "name", "type"), &Window::get_theme_stylebox, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_font", "name", "type"), &Window::get_theme_font, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_color", "name", "type"), &Window::get_theme_color, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_constant", "name", "type"), &Window::get_theme_constant, DEFVAL(""));
+
+ ClassDB::bind_method(D_METHOD("has_theme_icon", "name", "type"), &Window::has_theme_icon, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_stylebox", "name", "type"), &Window::has_theme_stylebox, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_font", "name", "type"), &Window::has_theme_font, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_color", "name", "type"), &Window::has_theme_color, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_constant", "name", "type"), &Window::has_theme_constant, DEFVAL(""));
+
+ ClassDB::bind_method(D_METHOD("popup", "rect"), &Window::popup, DEFVAL(Rect2i()));
+ ClassDB::bind_method(D_METHOD("popup_on_parent", "parent_rect"), &Window::popup_on_parent);
+ ClassDB::bind_method(D_METHOD("popup_centered_ratio", "ratio"), &Window::popup_centered_ratio, DEFVAL(0.8));
+ ClassDB::bind_method(D_METHOD("popup_centered", "minsize"), &Window::popup_centered, DEFVAL(Size2i()));
+ ClassDB::bind_method(D_METHOD("popup_centered_clamped", "minsize", "fallback_ratio"), &Window::popup_centered_clamped, DEFVAL(Size2i()), DEFVAL(0.75));
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "title"), "set_title", "get_title");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "position"), "set_position", "get_position");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,FullScreen"), "set_mode", "get_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_screen"), "set_current_screen", "get_current_screen");
+ ADD_GROUP("Flags", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "wrap_controls"), "set_wrap_controls", "is_wrapping_controls");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transient"), "set_transient", "is_transient");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclusive"), "set_exclusive", "is_exclusive");
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "unresizable"), "set_flag", "get_flag", FLAG_RESIZE_DISABLED);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "borderless"), "set_flag", "get_flag", FLAG_BORDERLESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "always_on_top"), "set_flag", "get_flag", FLAG_ALWAYS_ON_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "transparent"), "set_flag", "get_flag", FLAG_TRANSPARENT);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "unfocusable"), "set_flag", "get_flag", FLAG_NO_FOCUS);
+ ADD_GROUP("Limits", "");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "min_size"), "set_min_size", "get_min_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "max_size"), "set_max_size", "get_max_size");
+ ADD_GROUP("Content Scale", "content_scale_");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "content_scale_size"), "set_content_scale_size", "get_content_scale_size");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "content_scale_mode", PROPERTY_HINT_ENUM, "Disabled,Object,Pixels"), "set_content_scale_mode", "get_content_scale_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "content_scale_aspect", PROPERTY_HINT_ENUM, "Ignore,Keep,KeepWidth,KeepHeight,Expand"), "set_content_scale_aspect", "get_content_scale_aspect");
+ ADD_GROUP("Theme", "");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "theme", PROPERTY_HINT_RESOURCE_TYPE, "Theme"), "set_theme", "get_theme");
+
+ ADD_SIGNAL(MethodInfo("window_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
+ ADD_SIGNAL(MethodInfo("files_dropped", PropertyInfo(Variant::PACKED_STRING_ARRAY, "files")));
+ ADD_SIGNAL(MethodInfo("mouse_entered"));
+ ADD_SIGNAL(MethodInfo("mouse_exited"));
+ ADD_SIGNAL(MethodInfo("focus_entered"));
+ ADD_SIGNAL(MethodInfo("focus_exited"));
+ ADD_SIGNAL(MethodInfo("close_requested"));
+ ADD_SIGNAL(MethodInfo("go_back_requested"));
+ ADD_SIGNAL(MethodInfo("visibility_changed"));
+ ADD_SIGNAL(MethodInfo("about_to_popup"));
+
+ BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED);
+
+ BIND_ENUM_CONSTANT(MODE_WINDOWED);
+ BIND_ENUM_CONSTANT(MODE_MINIMIZED);
+ BIND_ENUM_CONSTANT(MODE_MAXIMIZED);
+ BIND_ENUM_CONSTANT(MODE_FULLSCREEN);
+
+ BIND_ENUM_CONSTANT(FLAG_RESIZE_DISABLED);
+ BIND_ENUM_CONSTANT(FLAG_BORDERLESS);
+ BIND_ENUM_CONSTANT(FLAG_ALWAYS_ON_TOP);
+ BIND_ENUM_CONSTANT(FLAG_TRANSPARENT);
+ BIND_ENUM_CONSTANT(FLAG_NO_FOCUS);
+ BIND_ENUM_CONSTANT(FLAG_MAX);
+
+ BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_DISABLED);
+ BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_OBJECTS);
+ BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_PIXELS);
+
+ BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_IGNORE);
+ BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_KEEP);
+ BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_KEEP_WIDTH);
+ BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_KEEP_HEIGHT);
+ BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_EXPAND);
+}
+
+Window::Window() {
+ for (int i = 0; i < FLAG_MAX; i++) {
+ flags[i] = false;
+ }
+ content_scale_mode = CONTENT_SCALE_MODE_DISABLED;
+ content_scale_aspect = CONTENT_SCALE_ASPECT_IGNORE;
+ RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
+}
+Window::~Window() {
+}
diff --git a/scene/main/window.h b/scene/main/window.h
new file mode 100644
index 0000000000..adaa5ca3be
--- /dev/null
+++ b/scene/main/window.h
@@ -0,0 +1,265 @@
+/*************************************************************************/
+/* window.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef WINDOW_H
+#define WINDOW_H
+
+#include "scene/main/viewport.h"
+#include "scene/resources/theme.h"
+#include "servers/display_server.h"
+
+class Control;
+class Window : public Viewport {
+ GDCLASS(Window, Viewport)
+public:
+ enum Mode {
+ MODE_WINDOWED = DisplayServer::WINDOW_MODE_WINDOWED,
+ MODE_MINIMIZED = DisplayServer::WINDOW_MODE_MINIMIZED,
+ MODE_MAXIMIZED = DisplayServer::WINDOW_MODE_MAXIMIZED,
+ MODE_FULLSCREEN = DisplayServer::WINDOW_MODE_FULLSCREEN,
+ };
+
+ enum Flags {
+ FLAG_RESIZE_DISABLED = DisplayServer::WINDOW_FLAG_RESIZE_DISABLED,
+ FLAG_BORDERLESS = DisplayServer::WINDOW_FLAG_BORDERLESS,
+ FLAG_ALWAYS_ON_TOP = DisplayServer::WINDOW_FLAG_ALWAYS_ON_TOP,
+ FLAG_TRANSPARENT = DisplayServer::WINDOW_FLAG_TRANSPARENT,
+ FLAG_NO_FOCUS = DisplayServer::WINDOW_FLAG_NO_FOCUS,
+ FLAG_MAX = DisplayServer::WINDOW_FLAG_MAX,
+ };
+
+ enum ContentScaleMode {
+ CONTENT_SCALE_MODE_DISABLED,
+ CONTENT_SCALE_MODE_OBJECTS,
+ CONTENT_SCALE_MODE_PIXELS,
+ };
+
+ enum ContentScaleAspect {
+ CONTENT_SCALE_ASPECT_IGNORE,
+ CONTENT_SCALE_ASPECT_KEEP,
+ CONTENT_SCALE_ASPECT_KEEP_WIDTH,
+ CONTENT_SCALE_ASPECT_KEEP_HEIGHT,
+ CONTENT_SCALE_ASPECT_EXPAND,
+ };
+
+ enum {
+ DEFAULT_WINDOW_SIZE = 100,
+ };
+
+private:
+ DisplayServer::WindowID window_id = DisplayServer::INVALID_WINDOW_ID;
+
+ String title;
+ mutable int current_screen = 0;
+ mutable Vector2i position;
+ mutable Size2i size = Size2i(DEFAULT_WINDOW_SIZE, DEFAULT_WINDOW_SIZE);
+ mutable Size2i min_size;
+ mutable Size2i max_size;
+ mutable Mode mode = MODE_WINDOWED;
+ mutable bool flags[FLAG_MAX];
+ bool visible = true;
+ bool focused = false;
+
+ bool use_font_oversampling = false;
+ bool transient = false;
+ bool exclusive = false;
+ bool wrap_controls = false;
+ bool updating_child_controls = false;
+
+ void _update_child_controls();
+
+ Size2i content_scale_size;
+ ContentScaleMode content_scale_mode;
+ ContentScaleAspect content_scale_aspect;
+
+ void _make_window();
+ void _clear_window();
+ void _update_from_window();
+
+ void _update_viewport_size();
+ void _update_window_size();
+
+ void _propagate_window_notification(Node *p_node, int p_notification);
+
+ void _update_window_callbacks();
+
+ void _clear_transient();
+ void _make_transient();
+ Window *transient_parent = nullptr;
+ Window *exclusive_child = nullptr;
+ Set<Window *> transient_children;
+
+ friend class Control;
+ Ref<Theme> theme;
+ Control *theme_owner = nullptr;
+ Window *theme_owner_window = nullptr;
+
+ Viewport *embedder = nullptr;
+
+ friend class Viewport; //friend back, can call the methods below
+
+ void _window_input(const Ref<InputEvent> &p_ev);
+ void _window_input_text(const String &p_text);
+ void _window_drop_files(const Vector<String> &p_files);
+ void _rect_changed_callback(const Rect2i &p_callback);
+ void _event_callback(DisplayServer::WindowEvent p_event);
+
+protected:
+ Viewport *_get_embedder() const;
+
+ virtual Rect2i _popup_adjust_rect() const { return Rect2i(); }
+
+ virtual void _post_popup() {}
+ virtual Size2 _get_contents_minimum_size() const;
+ static void _bind_methods();
+ void _notification(int p_what);
+
+ virtual void add_child_notify(Node *p_child);
+ virtual void remove_child_notify(Node *p_child);
+
+public:
+ enum {
+
+ NOTIFICATION_VISIBILITY_CHANGED = 30,
+ NOTIFICATION_POST_POPUP = 31,
+ NOTIFICATION_THEME_CHANGED = 32,
+ };
+
+ void set_title(const String &p_title);
+ String get_title() const;
+
+ void set_current_screen(int p_screen);
+ int get_current_screen() const;
+
+ void set_position(const Point2i &p_position);
+ Point2i get_position() const;
+
+ void set_size(const Size2i &p_size);
+ Size2i get_size() const;
+
+ Size2i get_real_size() const;
+
+ void set_max_size(const Size2i &p_max_size);
+ Size2i get_max_size() const;
+
+ void set_min_size(const Size2i &p_min_size);
+ Size2i get_min_size() const;
+
+ void set_mode(Mode p_mode);
+ Mode get_mode() const;
+
+ void set_flag(Flags p_flag, bool p_enabled);
+ bool get_flag(Flags p_flag) const;
+
+ bool is_maximize_allowed() const;
+
+ void request_attention();
+ void move_to_foreground();
+
+ void set_visible(bool p_visible);
+ bool is_visible() const;
+
+ void show();
+ void hide();
+
+ void set_transient(bool p_transient);
+ bool is_transient() const;
+
+ void set_exclusive(bool p_exclusive);
+ bool is_exclusive() const;
+
+ bool can_draw() const;
+
+ void set_ime_active(bool p_active);
+ void set_ime_position(const Point2i &p_pos);
+
+ bool is_embedded() const;
+
+ void set_content_scale_size(const Size2i &p_size);
+ Size2i get_content_scale_size() const;
+
+ void set_content_scale_mode(ContentScaleMode p_mode);
+ ContentScaleMode get_content_scale_mode() const;
+
+ void set_content_scale_aspect(ContentScaleAspect p_aspect);
+ ContentScaleAspect get_content_scale_aspect() const;
+
+ void set_use_font_oversampling(bool p_oversampling);
+ bool is_using_font_oversampling() const;
+
+ void set_wrap_controls(bool p_enable);
+ bool is_wrapping_controls() const;
+ void child_controls_changed();
+
+ Window *get_parent_visible_window() const;
+ Viewport *get_parent_viewport() const;
+ void popup(const Rect2i &p_rect = Rect2i());
+ void popup_on_parent(const Rect2i &p_parent_rect);
+ void popup_centered_ratio(float p_ratio = 0.8);
+ void popup_centered(const Size2i &p_minsize = Size2i());
+ void popup_centered_clamped(const Size2i &p_size = Size2i(), float p_fallback_ratio = 0.75);
+
+ void set_theme(const Ref<Theme> &p_theme);
+ Ref<Theme> get_theme() const;
+
+ Size2 get_contents_minimum_size() const;
+
+ void grab_focus();
+ bool has_focus() const;
+
+ Rect2i get_usable_parent_rect() const;
+
+ Ref<Texture2D> get_theme_icon(const StringName &p_name, const StringName &p_type = StringName()) const;
+ Ref<Shader> get_theme_shader(const StringName &p_name, const StringName &p_type = StringName()) const;
+ Ref<StyleBox> get_theme_stylebox(const StringName &p_name, const StringName &p_type = StringName()) const;
+ Ref<Font> get_theme_font(const StringName &p_name, const StringName &p_type = StringName()) const;
+ Color get_theme_color(const StringName &p_name, const StringName &p_type = StringName()) const;
+ int get_theme_constant(const StringName &p_name, const StringName &p_type = StringName()) const;
+
+ bool has_theme_icon(const StringName &p_name, const StringName &p_type = StringName()) const;
+ bool has_theme_shader(const StringName &p_name, const StringName &p_type = StringName()) const;
+ bool has_theme_stylebox(const StringName &p_name, const StringName &p_type = StringName()) const;
+ bool has_theme_font(const StringName &p_name, const StringName &p_type = StringName()) const;
+ bool has_theme_color(const StringName &p_name, const StringName &p_type = StringName()) const;
+ bool has_theme_constant(const StringName &p_name, const StringName &p_type = StringName()) const;
+
+ Rect2i get_parent_rect() const;
+ virtual DisplayServer::WindowID get_window_id() const;
+
+ Window();
+ ~Window();
+};
+
+VARIANT_ENUM_CAST(Window::Mode);
+VARIANT_ENUM_CAST(Window::Flags);
+VARIANT_ENUM_CAST(Window::ContentScaleMode);
+VARIANT_ENUM_CAST(Window::ContentScaleAspect);
+
+#endif // WINDOW_H