summaryrefslogtreecommitdiff
path: root/scene/main
diff options
context:
space:
mode:
Diffstat (limited to 'scene/main')
-rw-r--r--scene/main/canvas_item.cpp37
-rw-r--r--scene/main/canvas_item.h7
-rw-r--r--scene/main/http_request.cpp21
-rw-r--r--scene/main/http_request.h8
-rw-r--r--scene/main/multiplayer_api.cpp18
-rw-r--r--scene/main/multiplayer_api.h8
-rw-r--r--scene/main/multiplayer_peer.cpp2
-rw-r--r--scene/main/node.cpp26
-rw-r--r--scene/main/node.h1
-rw-r--r--scene/main/viewport.cpp161
-rw-r--r--scene/main/viewport.h18
-rw-r--r--scene/main/window.cpp105
-rw-r--r--scene/main/window.h6
13 files changed, 269 insertions, 149 deletions
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 7b0554442c..0ea8f6c5f1 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -154,17 +154,7 @@ Transform2D CanvasItem::get_global_transform_with_canvas() const {
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;
+ return get_viewport()->get_popup_base_transform() * get_global_transform_with_canvas();
}
Transform2D CanvasItem::get_global_transform() const {
@@ -195,7 +185,7 @@ void CanvasItem::_top_level_raise_self() {
}
void CanvasItem::_enter_canvas() {
- // Resolves to nullptr if the node is toplevel.
+ // Resolves to nullptr if the node is top_level.
CanvasItem *parent_item = get_parent_item();
if (parent_item) {
@@ -410,11 +400,28 @@ void CanvasItem::set_as_top_level(bool p_top_level) {
_exit_canvas();
top_level = p_top_level;
+ _top_level_changed();
_enter_canvas();
_notify_transform();
}
+void CanvasItem::_top_level_changed() {
+ // Inform children that top_level status has changed on a parent.
+ int children = get_child_count();
+ for (int i = 0; i < children; i++) {
+ CanvasItem *child = Object::cast_to<CanvasItem>(get_child(i));
+ if (child) {
+ child->_top_level_changed_on_parent();
+ }
+ }
+}
+
+void CanvasItem::_top_level_changed_on_parent() {
+ // Inform children that top_level status has changed on a parent.
+ _top_level_changed();
+}
+
bool CanvasItem::is_set_as_top_level() const {
return top_level;
}
@@ -927,6 +934,12 @@ void CanvasItem::force_update_transform() {
notification(NOTIFICATION_TRANSFORM_CHANGED);
}
+void CanvasItem::_validate_property(PropertyInfo &p_property) const {
+ if (hide_clip_children && p_property.name == "clip_children") {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+}
+
void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("_top_level_raise_self"), &CanvasItem::_top_level_raise_self);
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
index 644fe856ec..2fa1d56667 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -106,6 +106,7 @@ private:
bool use_parent_material = false;
bool notify_local_transform = false;
bool notify_transform = false;
+ bool hide_clip_children = false;
ClipChildrenMode clip_children_mode = CLIP_CHILDREN_DISABLED;
@@ -124,6 +125,9 @@ private:
void _propagate_visibility_changed(bool p_parent_visible_in_tree);
void _handle_visibility_change(bool p_visible);
+ virtual void _top_level_changed();
+ virtual void _top_level_changed_on_parent();
+
void _redraw_callback();
void _enter_canvas();
@@ -155,6 +159,9 @@ protected:
void _notification(int p_what);
static void _bind_methods();
+ void _validate_property(PropertyInfo &p_property) const;
+
+ _FORCE_INLINE_ void set_hide_clip_children(bool p_value) { hide_clip_children = p_value; }
GDVIRTUAL0(_draw)
public:
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index 46ba7e67eb..0d53f740db 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -33,7 +33,7 @@
#include "scene/main/timer.h"
Error HTTPRequest::_request() {
- return client->connect_to_host(url, port, use_tls, validate_tls);
+ return client->connect_to_host(url, port, use_tls ? tls_options : nullptr);
}
Error HTTPRequest::_parse_url(const String &p_url) {
@@ -96,7 +96,7 @@ String HTTPRequest::get_header_value(const PackedStringArray &p_headers, const S
return value;
}
-Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_headers, bool p_tls_validate_domain, HTTPClient::Method p_method, const String &p_request_data) {
+Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_headers, HTTPClient::Method p_method, const String &p_request_data) {
// Copy the string into a raw buffer.
Vector<uint8_t> raw_data;
@@ -108,10 +108,10 @@ Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_h
memcpy(w, charstr.ptr(), len);
}
- return request_raw(p_url, p_custom_headers, p_tls_validate_domain, p_method, raw_data);
+ return request_raw(p_url, p_custom_headers, p_method, raw_data);
}
-Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_custom_headers, bool p_tls_validate_domain, HTTPClient::Method p_method, const Vector<uint8_t> &p_request_data_raw) {
+Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_custom_headers, HTTPClient::Method p_method, const Vector<uint8_t> &p_request_data_raw) {
ERR_FAIL_COND_V(!is_inside_tree(), ERR_UNCONFIGURED);
ERR_FAIL_COND_V_MSG(requesting, ERR_BUSY, "HTTPRequest is processing a request. Wait for completion or cancel it before attempting a new one.");
@@ -127,8 +127,6 @@ Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_cust
return err;
}
- validate_tls = p_tls_validate_domain;
-
headers = p_custom_headers;
if (accept_gzip) {
@@ -590,10 +588,16 @@ void HTTPRequest::_timeout() {
_defer_done(RESULT_TIMEOUT, 0, PackedStringArray(), PackedByteArray());
}
+void HTTPRequest::set_tls_options(const Ref<TLSOptions> &p_options) {
+ ERR_FAIL_COND(p_options.is_null() || p_options->is_server());
+ tls_options = p_options;
+}
+
void HTTPRequest::_bind_methods() {
- ClassDB::bind_method(D_METHOD("request", "url", "custom_headers", "tls_validate_domain", "method", "request_data"), &HTTPRequest::request, DEFVAL(PackedStringArray()), DEFVAL(true), DEFVAL(HTTPClient::METHOD_GET), DEFVAL(String()));
- ClassDB::bind_method(D_METHOD("request_raw", "url", "custom_headers", "tls_validate_domain", "method", "request_data_raw"), &HTTPRequest::request_raw, DEFVAL(PackedStringArray()), DEFVAL(true), DEFVAL(HTTPClient::METHOD_GET), DEFVAL(PackedByteArray()));
+ ClassDB::bind_method(D_METHOD("request", "url", "custom_headers", "method", "request_data"), &HTTPRequest::request, DEFVAL(PackedStringArray()), DEFVAL(HTTPClient::METHOD_GET), DEFVAL(String()));
+ ClassDB::bind_method(D_METHOD("request_raw", "url", "custom_headers", "method", "request_data_raw"), &HTTPRequest::request_raw, DEFVAL(PackedStringArray()), DEFVAL(HTTPClient::METHOD_GET), DEFVAL(PackedByteArray()));
ClassDB::bind_method(D_METHOD("cancel_request"), &HTTPRequest::cancel_request);
+ ClassDB::bind_method(D_METHOD("set_tls_options", "client_options"), &HTTPRequest::set_tls_options);
ClassDB::bind_method(D_METHOD("get_http_client_status"), &HTTPRequest::get_http_client_status);
@@ -654,6 +658,7 @@ void HTTPRequest::_bind_methods() {
HTTPRequest::HTTPRequest() {
client = Ref<HTTPClient>(HTTPClient::create());
+ tls_options = TLSOptions::client();
timer = memnew(Timer);
timer->set_one_shot(true);
timer->connect("timeout", callable_mp(this, &HTTPRequest::_timeout));
diff --git a/scene/main/http_request.h b/scene/main/http_request.h
index add4e9538d..9a91171eaf 100644
--- a/scene/main/http_request.h
+++ b/scene/main/http_request.h
@@ -68,8 +68,8 @@ private:
String url;
int port = 80;
Vector<String> headers;
- bool validate_tls = false;
bool use_tls = false;
+ Ref<TLSOptions> tls_options;
HTTPClient::Method method;
Vector<uint8_t> request_data;
@@ -125,8 +125,8 @@ protected:
static void _bind_methods();
public:
- Error request(const String &p_url, const Vector<String> &p_custom_headers = Vector<String>(), bool p_tls_validate_domain = true, HTTPClient::Method p_method = HTTPClient::METHOD_GET, const String &p_request_data = ""); //connects to a full url and perform request
- Error request_raw(const String &p_url, const Vector<String> &p_custom_headers = Vector<String>(), bool p_tls_validate_domain = true, HTTPClient::Method p_method = HTTPClient::METHOD_GET, const Vector<uint8_t> &p_request_data_raw = Vector<uint8_t>()); //connects to a full url and perform request
+ Error request(const String &p_url, const Vector<String> &p_custom_headers = Vector<String>(), HTTPClient::Method p_method = HTTPClient::METHOD_GET, const String &p_request_data = ""); //connects to a full url and perform request
+ Error request_raw(const String &p_url, const Vector<String> &p_custom_headers = Vector<String>(), HTTPClient::Method p_method = HTTPClient::METHOD_GET, const Vector<uint8_t> &p_request_data_raw = Vector<uint8_t>()); //connects to a full url and perform request
void cancel_request();
HTTPClient::Status get_http_client_status() const;
@@ -161,6 +161,8 @@ public:
void set_http_proxy(const String &p_host, int p_port);
void set_https_proxy(const String &p_host, int p_port);
+ void set_tls_options(const Ref<TLSOptions> &p_options);
+
HTTPRequest();
};
diff --git a/scene/main/multiplayer_api.cpp b/scene/main/multiplayer_api.cpp
index e36cbc4414..950eb2809c 100644
--- a/scene/main/multiplayer_api.cpp
+++ b/scene/main/multiplayer_api.cpp
@@ -135,7 +135,7 @@ Error MultiplayerAPI::encode_and_compress_variant(const Variant &p_variant, uint
return err;
}
if (r_buffer) {
- // The first byte is not used by the marshalling, so store the type
+ // The first byte is not used by the marshaling, so store the type
// so we know how to decompress and decode this variant.
r_buffer[0] = p_variant.get_type();
}
@@ -329,9 +329,9 @@ void MultiplayerAPI::_bind_methods() {
/// MultiplayerAPIExtension
Error MultiplayerAPIExtension::poll() {
- int err = OK;
+ Error err = OK;
GDVIRTUAL_CALL(_poll, err);
- return (Error)err;
+ return err;
}
void MultiplayerAPIExtension::set_multiplayer_peer(const Ref<MultiplayerPeer> &p_peer) {
@@ -364,9 +364,9 @@ Error MultiplayerAPIExtension::rpcp(Object *p_obj, int p_peer_id, const StringNa
for (int i = 0; i < p_argcount; i++) {
args.push_back(*p_arg[i]);
}
- int ret = FAILED;
+ Error ret = FAILED;
GDVIRTUAL_CALL(_rpc, p_peer_id, p_obj, p_method, args, ret);
- return (Error)ret;
+ return ret;
}
int MultiplayerAPIExtension::get_remote_sender_id() {
@@ -376,15 +376,15 @@ int MultiplayerAPIExtension::get_remote_sender_id() {
}
Error MultiplayerAPIExtension::object_configuration_add(Object *p_object, Variant p_config) {
- int err = ERR_UNAVAILABLE;
+ Error err = ERR_UNAVAILABLE;
GDVIRTUAL_CALL(_object_configuration_add, p_object, p_config, err);
- return (Error)err;
+ return err;
}
Error MultiplayerAPIExtension::object_configuration_remove(Object *p_object, Variant p_config) {
- int err = ERR_UNAVAILABLE;
+ Error err = ERR_UNAVAILABLE;
GDVIRTUAL_CALL(_object_configuration_remove, p_object, p_config, err);
- return (Error)err;
+ return err;
}
void MultiplayerAPIExtension::_bind_methods() {
diff --git a/scene/main/multiplayer_api.h b/scene/main/multiplayer_api.h
index 0b107ee50b..a578e6f2f1 100644
--- a/scene/main/multiplayer_api.h
+++ b/scene/main/multiplayer_api.h
@@ -101,15 +101,15 @@ public:
virtual Error object_configuration_remove(Object *p_object, Variant p_config) override;
// Extensions
- GDVIRTUAL0R(int, _poll);
+ GDVIRTUAL0R(Error, _poll);
GDVIRTUAL1(_set_multiplayer_peer, Ref<MultiplayerPeer>);
GDVIRTUAL0R(Ref<MultiplayerPeer>, _get_multiplayer_peer);
GDVIRTUAL0RC(int, _get_unique_id);
GDVIRTUAL0RC(PackedInt32Array, _get_peer_ids);
- GDVIRTUAL4R(int, _rpc, int, Object *, StringName, Array);
+ GDVIRTUAL4R(Error, _rpc, int, Object *, StringName, Array);
GDVIRTUAL0RC(int, _get_remote_sender_id);
- GDVIRTUAL2R(int, _object_configuration_add, Object *, Variant);
- GDVIRTUAL2R(int, _object_configuration_remove, Object *, Variant);
+ GDVIRTUAL2R(Error, _object_configuration_add, Object *, Variant);
+ GDVIRTUAL2R(Error, _object_configuration_remove, Object *, Variant);
};
#endif // MULTIPLAYER_API_H
diff --git a/scene/main/multiplayer_peer.cpp b/scene/main/multiplayer_peer.cpp
index 83555966d7..f3e56a1455 100644
--- a/scene/main/multiplayer_peer.cpp
+++ b/scene/main/multiplayer_peer.cpp
@@ -163,7 +163,7 @@ Error MultiplayerPeerExtension::put_packet(const uint8_t *p_buffer, int p_buffer
if (!GDVIRTUAL_CALL(_put_packet_script, a, err)) {
return FAILED;
}
- return (Error)err;
+ return err;
}
WARN_PRINT_ONCE("MultiplayerPeerExtension::_put_packet_native is unimplemented!");
return FAILED;
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index def91c424c..52c1df8110 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -946,7 +946,7 @@ String Node::validate_child_name(Node *p_child) {
#endif
String Node::adjust_name_casing(const String &p_name) {
- switch (GLOBAL_GET("editor/node_naming/name_casing").operator int()) {
+ switch (GLOBAL_GET("editor/naming/node_name_casing").operator int()) {
case NAME_CASING_PASCAL_CASE:
return p_name.to_pascal_case();
case NAME_CASING_CAMEL_CASE:
@@ -1987,7 +1987,16 @@ String Node::get_scene_file_path() const {
}
void Node::set_editor_description(const String &p_editor_description) {
+ if (data.editor_description == p_editor_description) {
+ return;
+ }
+
data.editor_description = p_editor_description;
+
+ if (Engine::get_singleton()->is_editor_hint() && is_inside_tree()) {
+ // Update tree so the tooltip in the Scene tree dock is also updated in the editor.
+ get_tree()->tree_changed();
+ }
}
String Node::get_editor_description() const {
@@ -2126,13 +2135,13 @@ Node *Node::_duplicate(int p_flags, HashMap<const Node *, Node *> *r_duplimap) c
} else if ((p_flags & DUPLICATE_USE_INSTANTIATION) && !get_scene_file_path().is_empty()) {
Ref<PackedScene> res = ResourceLoader::load(get_scene_file_path());
ERR_FAIL_COND_V(res.is_null(), nullptr);
- PackedScene::GenEditState ges = PackedScene::GEN_EDIT_STATE_DISABLED;
+ PackedScene::GenEditState edit_state = PackedScene::GEN_EDIT_STATE_DISABLED;
#ifdef TOOLS_ENABLED
if (p_flags & DUPLICATE_FROM_EDITOR) {
- ges = PackedScene::GEN_EDIT_STATE_INSTANCE;
+ edit_state = PackedScene::GEN_EDIT_STATE_INSTANCE;
}
#endif
- node = res->instantiate(ges);
+ node = res->instantiate(edit_state);
ERR_FAIL_COND_V(!node, nullptr);
node->set_scene_instance_load_placeholder(get_scene_instance_load_placeholder());
@@ -2213,7 +2222,7 @@ Node *Node::_duplicate(int p_flags, HashMap<const Node *, Node *> *r_duplimap) c
Variant value = N->get()->get(name).duplicate(true);
- if (E.usage & PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE) {
+ if (E.usage & PROPERTY_USAGE_ALWAYS_DUPLICATE) {
Resource *res = Object::cast_to<Resource>(value);
if (res) { // Duplicate only if it's a resource
current_node->set(name, res->duplicate());
@@ -2799,8 +2808,8 @@ void Node::unhandled_key_input(const Ref<InputEvent> &p_key_event) {
}
void Node::_bind_methods() {
- GLOBAL_DEF(PropertyInfo(Variant::INT, "editor/node_naming/name_num_separator", PROPERTY_HINT_ENUM, "None,Space,Underscore,Dash"), 0);
- GLOBAL_DEF(PropertyInfo(Variant::INT, "editor/node_naming/name_casing", PROPERTY_HINT_ENUM, "PascalCase,camelCase,snake_case"), NAME_CASING_PASCAL_CASE);
+ GLOBAL_DEF(PropertyInfo(Variant::INT, "editor/naming/node_name_num_separator", PROPERTY_HINT_ENUM, "None,Space,Underscore,Dash"), 0);
+ GLOBAL_DEF(PropertyInfo(Variant::INT, "editor/naming/node_name_casing", PROPERTY_HINT_ENUM, "PascalCase,camelCase,snake_case"), NAME_CASING_PASCAL_CASE);
ClassDB::bind_static_method("Node", D_METHOD("print_orphan_nodes"), &Node::print_orphan_nodes);
ClassDB::bind_method(D_METHOD("add_sibling", "sibling", "force_readable_name"), &Node::add_sibling, DEFVAL(false));
@@ -2947,6 +2956,7 @@ void Node::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_POST_ENTER_TREE);
BIND_CONSTANT(NOTIFICATION_DISABLED);
BIND_CONSTANT(NOTIFICATION_ENABLED);
+ BIND_CONSTANT(NOTIFICATION_NODE_RECACHE_REQUESTED);
BIND_CONSTANT(NOTIFICATION_EDITOR_PRE_SAVE);
BIND_CONSTANT(NOTIFICATION_EDITOR_POST_SAVE);
@@ -3021,7 +3031,7 @@ void Node::_bind_methods() {
}
String Node::_get_name_num_separator() {
- switch (GLOBAL_GET("editor/node_naming/name_num_separator").operator int()) {
+ switch (GLOBAL_GET("editor/naming/node_name_num_separator").operator int()) {
case 0:
return "";
case 1:
diff --git a/scene/main/node.h b/scene/main/node.h
index dbdcca6170..493578bc5b 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -270,6 +270,7 @@ public:
NOTIFICATION_POST_ENTER_TREE = 27,
NOTIFICATION_DISABLED = 28,
NOTIFICATION_ENABLED = 29,
+ NOTIFICATION_NODE_RECACHE_REQUESTED = 30,
//keep these linked to node
NOTIFICATION_WM_MOUSE_ENTER = 1002,
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 07bcf45899..28521c5bbe 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -524,7 +524,12 @@ void Viewport::_process_picking() {
if (!physics_object_picking) {
return;
}
- if (to_screen_rect != Rect2i() && Input::get_singleton()->get_mouse_mode() == Input::MOUSE_MODE_CAPTURED) {
+ if (Object::cast_to<Window>(this) && Input::get_singleton()->get_mouse_mode() == Input::MOUSE_MODE_CAPTURED) {
+ return;
+ }
+ if (!gui.mouse_in_viewport) {
+ // Clear picking events if mouse has left viewport.
+ physics_picking_events.clear();
return;
}
@@ -704,25 +709,15 @@ void Viewport::_process_picking() {
}
#ifndef _3D_DISABLED
- bool captured = false;
-
+ CollisionObject3D *capture_object = nullptr;
if (physics_object_capture.is_valid()) {
- CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_capture));
- if (co && camera_3d) {
- _collision_object_3d_input_event(co, camera_3d, ev, Vector3(), Vector3(), 0);
- captured = true;
- if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && !mb->is_pressed()) {
- physics_object_capture = ObjectID();
- }
-
- } else {
+ capture_object = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_capture));
+ if (!capture_object || !camera_3d || (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && !mb->is_pressed())) {
physics_object_capture = ObjectID();
}
}
- if (captured) {
- // None.
- } else if (pos == last_pos) {
+ if (pos == last_pos) {
if (last_id.is_valid()) {
if (ObjectDB::get_instance(last_id) && last_object) {
// Good, exists.
@@ -748,13 +743,12 @@ void Viewport::_process_picking() {
bool col = space->intersect_ray(ray_params, result);
ObjectID new_collider;
- if (col) {
- CollisionObject3D *co = Object::cast_to<CollisionObject3D>(result.collider);
- if (co && co->can_process()) {
- _collision_object_3d_input_event(co, camera_3d, ev, result.position, result.normal, result.shape);
+ CollisionObject3D *co = col ? Object::cast_to<CollisionObject3D>(result.collider) : nullptr;
+ if (co && co->can_process()) {
+ new_collider = result.collider_id;
+ if (!capture_object) {
last_object = co;
last_id = result.collider_id;
- new_collider = last_id;
if (co->get_capture_input_on_drag() && mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) {
physics_object_capture = last_id;
}
@@ -763,21 +757,24 @@ void Viewport::_process_picking() {
if (is_mouse && new_collider != physics_object_over) {
if (physics_object_over.is_valid()) {
- CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_over));
- if (co) {
- co->_mouse_exit();
+ CollisionObject3D *previous_co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_over));
+ if (previous_co) {
+ previous_co->_mouse_exit();
}
}
if (new_collider.is_valid()) {
- CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(new_collider));
- if (co) {
- co->_mouse_enter();
- }
+ DEV_ASSERT(co);
+ co->_mouse_enter();
}
physics_object_over = new_collider;
}
+ if (capture_object) {
+ _collision_object_3d_input_event(capture_object, camera_3d, ev, result.position, result.normal, result.shape);
+ } else if (new_collider.is_valid()) {
+ _collision_object_3d_input_event(co, camera_3d, ev, result.position, result.normal, result.shape);
+ }
}
last_pos = pos;
@@ -799,16 +796,21 @@ void Viewport::update_canvas_items() {
_update_canvas_items(this);
}
-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 && size_allocated == p_allocated && stretch_transform == p_stretch_transform && p_size_2d_override == size_2d_override && to_screen_rect == p_to_screen_rect) {
+void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_2d_override, bool p_allocated) {
+ Transform2D stretch_transform_new = Transform2D();
+ if (is_size_2d_override_stretch_enabled() && p_size_2d_override.width > 0 && p_size_2d_override.height > 0) {
+ Size2 scale = Size2(p_size) / Size2(p_size_2d_override);
+ stretch_transform_new.scale(scale);
+ }
+
+ if (size == p_size && size_allocated == p_allocated && stretch_transform == stretch_transform_new && p_size_2d_override == size_2d_override) {
return;
}
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;
+ stretch_transform = stretch_transform_new;
#ifndef _3D_DISABLED
if (!use_xr) {
@@ -1053,6 +1055,29 @@ Transform2D Viewport::get_final_transform() const {
return stretch_transform * global_canvas_transform;
}
+void Viewport::assign_next_enabled_camera_2d(const StringName &p_camera_group) {
+ List<Node *> camera_list;
+ get_tree()->get_nodes_in_group(p_camera_group, &camera_list);
+
+ Camera2D *new_camera = nullptr;
+ for (Node *E : camera_list) {
+ Camera2D *cam = Object::cast_to<Camera2D>(E);
+ if (!cam) {
+ continue; // Non-camera node (e.g. ParallaxBackground).
+ }
+
+ if (cam->is_enabled()) {
+ new_camera = cam;
+ break;
+ }
+ }
+
+ _camera_2d_set(new_camera);
+ if (!camera_2d) {
+ set_canvas_transform(Transform2D());
+ }
+}
+
void Viewport::_update_canvas_items(Node *p_node) {
if (p_node != this) {
Window *w = Object::cast_to<Window>(p_node);
@@ -1117,23 +1142,12 @@ Viewport::PositionalShadowAtlasQuadrantSubdiv Viewport::get_positional_shadow_at
return positional_shadow_atlas_quadrant_subdiv[p_quadrant];
}
-Transform2D Viewport::_get_input_pre_xform() const {
- Transform2D pre_xf;
-
- if (to_screen_rect.size.x != 0 && to_screen_rect.size.y != 0) {
- pre_xf.columns[2] = -to_screen_rect.position;
- pre_xf.scale(Vector2(size) / to_screen_rect.size);
- }
-
- return pre_xf;
-}
-
Ref<InputEvent> Viewport::_make_input_local(const Ref<InputEvent> &ev) {
if (ev.is_null()) {
return ev; // No transformation defined for null event
}
- Transform2D ai = get_final_transform().affine_inverse() * _get_input_pre_xform();
+ Transform2D ai = get_final_transform().affine_inverse();
return ev->xformed_by(ai);
}
@@ -1795,9 +1809,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
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.
+ viewport_pos = get_final_transform().xform(mpos) + w->get_position(); // To parent coords.
}
}
}
@@ -1847,7 +1859,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (viewport_under) {
if (viewport_under != this) {
- Transform2D ai = (viewport_under->get_final_transform().affine_inverse() * viewport_under->_get_input_pre_xform());
+ Transform2D ai = viewport_under->get_final_transform().affine_inverse();
viewport_pos = ai.xform(viewport_pos);
}
// Find control under at position.
@@ -2853,7 +2865,7 @@ bool Viewport::get_physics_object_picking() {
}
Vector2 Viewport::get_camera_coords(const Vector2 &p_viewport_coords) const {
- Transform2D xf = get_final_transform();
+ Transform2D xf = stretch_transform * global_canvas_transform;
return xf.xform(p_viewport_coords);
}
@@ -3245,7 +3257,7 @@ Viewport::SDFScale Viewport::get_sdf_scale() const {
}
Transform2D Viewport::get_screen_transform() const {
- return _get_input_pre_xform().affine_inverse() * get_final_transform();
+ return get_final_transform();
}
void Viewport::set_canvas_cull_mask(uint32_t p_canvas_cull_mask) {
@@ -4108,9 +4120,26 @@ Viewport::~Viewport() {
/////////////////////////////////
void SubViewport::set_size(const Size2i &p_size) {
- _set_size(p_size, _get_size_2d_override(), Rect2i(), _stretch_transform(), true);
+ _internal_set_size(p_size);
+}
+
+void SubViewport::set_size_force(const Size2i &p_size) {
+ // Use only for setting the size from the parent SubViewportContainer with enabled stretch mode.
+ // Don't expose function to scripting.
+ _internal_set_size(p_size, true);
+}
+void SubViewport::_internal_set_size(const Size2i &p_size, bool p_force) {
SubViewportContainer *c = Object::cast_to<SubViewportContainer>(get_parent());
+ if (!p_force && c && c->is_stretch_enabled()) {
+#ifdef DEBUG_ENABLED
+ WARN_PRINT("Can't change the size of a `SubViewport` with a `SubViewportContainer` parent that has `stretch` enabled. Set `SubViewportContainer.stretch` to `false` to allow changing the size manually.");
+#endif // DEBUG_ENABLED
+ return;
+ }
+
+ _set_size(p_size, _get_size_2d_override(), true);
+
if (c) {
c->update_minimum_size();
}
@@ -4121,7 +4150,7 @@ Size2i SubViewport::get_size() const {
}
void SubViewport::set_size_2d_override(const Size2i &p_size) {
- _set_size(_get_size(), p_size, Rect2i(), _stretch_transform(), true);
+ _set_size(_get_size(), p_size, true);
}
Size2i SubViewport::get_size_2d_override() const {
@@ -4134,7 +4163,7 @@ void SubViewport::set_size_2d_override_stretch(bool p_enable) {
}
size_2d_override_stretch = p_enable;
- _set_size(_get_size(), _get_size_2d_override(), Rect2i(), _stretch_transform(), true);
+ _set_size(_get_size(), _get_size_2d_override(), true);
}
bool SubViewport::is_size_2d_override_stretch_enabled() const {
@@ -4163,17 +4192,6 @@ DisplayServer::WindowID SubViewport::get_window_id() const {
return DisplayServer::INVALID_WINDOW_ID;
}
-Transform2D SubViewport::_stretch_transform() {
- Transform2D transform;
- 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 = Size2(_get_size()) / Size2(view_size_2d_override);
- transform.scale(scale);
- }
-
- return transform;
-}
-
Transform2D SubViewport::get_screen_transform() const {
Transform2D container_transform;
SubViewportContainer *c = Object::cast_to<SubViewportContainer>(get_parent());
@@ -4185,7 +4203,22 @@ Transform2D SubViewport::get_screen_transform() const {
} else {
WARN_PRINT_ONCE("SubViewport is not a child of a SubViewportContainer. get_screen_transform doesn't return the actual screen position.");
}
- return container_transform * Viewport::get_screen_transform();
+ return container_transform * get_final_transform();
+}
+
+Transform2D SubViewport::get_popup_base_transform() const {
+ if (is_embedding_subwindows()) {
+ return Transform2D();
+ }
+ SubViewportContainer *c = Object::cast_to<SubViewportContainer>(get_parent());
+ if (!c) {
+ return get_final_transform();
+ }
+ Transform2D container_transform;
+ if (c->is_stretch_enabled()) {
+ container_transform.scale(Vector2(c->get_stretch_shrink(), c->get_stretch_shrink()));
+ }
+ return c->get_screen_transform() * container_transform * get_final_transform();
}
void SubViewport::_notification(int p_what) {
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 603e92b071..2142aaaaef 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -275,7 +275,6 @@ private:
Ref<World2D> world_2d;
- Rect2i to_screen_rect;
StringName input_group;
StringName gui_input_group;
StringName shortcut_input_group;
@@ -408,8 +407,6 @@ private:
void _perform_drop(Control *p_control = nullptr, Point2 p_pos = Point2());
void _gui_cleanup_internal_state(Ref<InputEvent> p_event);
- _FORCE_INLINE_ Transform2D _get_input_pre_xform() const;
-
Ref<InputEvent> _make_input_local(const Ref<InputEvent> &ev);
friend class Control;
@@ -471,7 +468,7 @@ private:
uint64_t event_count = 0;
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);
+ void _set_size(const Size2i &p_size, const Size2i &p_size_2d_override, bool p_allocated);
Size2i _get_size() const;
Size2i _get_size_2d_override() const;
@@ -510,7 +507,8 @@ public:
void set_global_canvas_transform(const Transform2D &p_transform);
Transform2D get_global_canvas_transform() const;
- Transform2D get_final_transform() const;
+ virtual Transform2D get_final_transform() const;
+ void assign_next_enabled_camera_2d(const StringName &p_camera_group);
void gui_set_root_order_dirty();
@@ -648,7 +646,10 @@ public:
void set_canvas_cull_mask_bit(uint32_t p_layer, bool p_enable);
bool get_canvas_cull_mask_bit(uint32_t p_layer) const;
+ virtual bool is_size_2d_override_stretch_enabled() const { return true; }
+
virtual Transform2D get_screen_transform() const;
+ virtual Transform2D get_popup_base_transform() const { return Transform2D(); }
#ifndef _3D_DISABLED
bool use_xr = false;
@@ -752,21 +753,23 @@ private:
ClearMode clear_mode = CLEAR_MODE_ALWAYS;
bool size_2d_override_stretch = false;
+ void _internal_set_size(const Size2i &p_size, bool p_force = false);
+
protected:
static void _bind_methods();
virtual DisplayServer::WindowID get_window_id() const override;
- Transform2D _stretch_transform();
void _notification(int p_what);
public:
void set_size(const Size2i &p_size);
Size2i get_size() const;
+ void set_size_force(const Size2i &p_size);
void set_size_2d_override(const Size2i &p_size);
Size2i get_size_2d_override() const;
void set_size_2d_override_stretch(bool p_enable);
- bool is_size_2d_override_stretch_enabled() const;
+ bool is_size_2d_override_stretch_enabled() const override;
void set_update_mode(UpdateMode p_mode);
UpdateMode get_update_mode() const;
@@ -775,6 +778,7 @@ public:
ClearMode get_clear_mode() const;
virtual Transform2D get_screen_transform() const override;
+ virtual Transform2D get_popup_base_transform() const override;
SubViewport();
~SubViewport();
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 2c6599d849..33946246b0 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -663,18 +663,18 @@ void Window::set_visible(bool p_visible) {
return;
}
- visible = p_visible;
-
if (!is_inside_tree()) {
+ visible = p_visible;
return;
}
- if (updating_child_controls) {
- _update_child_controls();
- }
-
ERR_FAIL_COND_MSG(get_parent() == nullptr, "Can't change visibility of main window.");
+ visible = p_visible;
+
+ // Stop any queued resizing, as the window will be resized right now.
+ updating_child_controls = false;
+
Viewport *embedder_vp = _get_embedder();
if (!embedder_vp) {
@@ -833,7 +833,7 @@ bool Window::is_visible() const {
}
void Window::_update_window_size() {
- // Force window to respect size limitations of rendering server
+ // Force window to respect size limitations of rendering server.
RenderingServer *rendering_server = RenderingServer::get_singleton();
if (rendering_server) {
Size2i max_window_size = rendering_server->get_maximum_viewport_size();
@@ -905,16 +905,13 @@ void Window::_update_viewport_size() {
Size2i final_size;
Size2i final_size_override;
Rect2i attach_to_screen_rect(Point2i(), size);
- Transform2D stretch_transform_new;
float font_oversampling = 1.0;
+ window_transform = Transform2D();
if (content_scale_mode == CONTENT_SCALE_MODE_DISABLED || content_scale_size.x == 0 || content_scale_size.y == 0) {
font_oversampling = content_scale_factor;
final_size = size;
final_size_override = Size2(size) / content_scale_factor;
-
- stretch_transform_new = Transform2D();
- stretch_transform_new.scale(Size2(content_scale_factor, content_scale_factor));
} else {
//actual screen video mode
Size2 video_mode = size;
@@ -990,20 +987,24 @@ void Window::_update_viewport_size() {
attach_to_screen_rect = Rect2(margin, screen_size);
font_oversampling = (screen_size.x / viewport_size.x) * content_scale_factor;
- Size2 scale = Vector2(screen_size) / Vector2(final_size_override);
- stretch_transform_new.scale(scale);
-
+ window_transform.translate_local(margin);
} break;
case CONTENT_SCALE_MODE_VIEWPORT: {
final_size = (viewport_size / content_scale_factor).floor();
attach_to_screen_rect = Rect2(margin, screen_size);
+ window_transform.translate_local(margin);
+ if (final_size.x != 0 && final_size.y != 0) {
+ Transform2D scale_transform;
+ scale_transform.scale(Vector2(attach_to_screen_rect.size) / Vector2(final_size));
+ window_transform *= scale_transform;
+ }
} break;
}
}
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_new, allocate);
+ _set_size(final_size, final_size_override, allocate);
if (window_id != DisplayServer::INVALID_WINDOW_ID) {
RenderingServer::get_singleton()->viewport_attach_to_screen(get_viewport_rid(), attach_to_screen_rect, window_id);
@@ -1130,6 +1131,7 @@ void Window::_notification(int p_what) {
case NOTIFICATION_READY: {
if (wrap_controls) {
+ // Finish any resizing immediately so it doesn't interfere on stuff overriding _ready().
_update_child_controls();
}
} break;
@@ -1138,9 +1140,7 @@ void Window::_notification(int p_what) {
_invalidate_theme_cache();
_update_theme_item_cache();
- if (embedder) {
- embedder->_sub_window_update(this);
- } else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ if (!embedder && window_id != DisplayServer::INVALID_WINDOW_ID) {
String tr_title = atr(title);
#ifdef DEBUG_ENABLED
if (window_id == DisplayServer::MAIN_WINDOW_ID) {
@@ -1152,8 +1152,6 @@ void Window::_notification(int p_what) {
#endif
DisplayServer::get_singleton()->window_set_title(tr_title, window_id);
}
-
- child_controls_changed();
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -1254,8 +1252,13 @@ Vector<Vector2> Window::get_mouse_passthrough_polygon() const {
void Window::set_wrap_controls(bool p_enable) {
wrap_controls = p_enable;
- if (wrap_controls) {
- child_controls_changed();
+
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ if (updating_child_controls) {
+ _update_child_controls();
} else {
_update_window_size();
}
@@ -1282,23 +1285,23 @@ Size2 Window::_get_contents_minimum_size() const {
return max;
}
-void Window::_update_child_controls() {
- if (!updating_child_controls) {
+void Window::child_controls_changed() {
+ if (!is_inside_tree() || !visible || updating_child_controls) {
return;
}
- _update_window_size();
-
- updating_child_controls = false;
+ updating_child_controls = true;
+ call_deferred(SNAME("_update_child_controls"));
}
-void Window::child_controls_changed() {
- if (!is_inside_tree() || !visible || updating_child_controls) {
+void Window::_update_child_controls() {
+ if (!updating_child_controls) {
return;
}
- updating_child_controls = true;
- call_deferred(SNAME("_update_child_controls"));
+ _update_window_size();
+
+ updating_child_controls = false;
}
bool Window::_can_consume_input_events() const {
@@ -1647,7 +1650,24 @@ void Window::_invalidate_theme_cache() {
void Window::_update_theme_item_cache() {
// Request an update on the next frame to reflect theme changes.
// Updating without a delay can cause a lot of lag.
- child_controls_changed();
+ if (!wrap_controls) {
+ updating_embedded_window = true;
+ call_deferred(SNAME("_update_embedded_window"));
+ } else {
+ child_controls_changed();
+ }
+}
+
+void Window::_update_embedded_window() {
+ if (!updating_embedded_window) {
+ return;
+ }
+
+ if (embedder) {
+ embedder->_sub_window_update(this);
+ };
+
+ updating_embedded_window = false;
}
void Window::set_theme_type_variation(const StringName &p_theme_type) {
@@ -2095,13 +2115,30 @@ bool Window::is_auto_translating() const {
return auto_translate;
}
+Transform2D Window::get_final_transform() const {
+ return window_transform * stretch_transform * global_canvas_transform;
+}
+
Transform2D Window::get_screen_transform() const {
Transform2D embedder_transform;
if (_get_embedder()) {
embedder_transform.translate_local(get_position());
embedder_transform = _get_embedder()->get_screen_transform() * embedder_transform;
}
- return embedder_transform * Viewport::get_screen_transform();
+ return embedder_transform * get_final_transform();
+}
+
+Transform2D Window::get_popup_base_transform() const {
+ if (is_embedding_subwindows()) {
+ return Transform2D();
+ }
+ Transform2D popup_base_transform;
+ popup_base_transform.set_origin(get_position());
+ popup_base_transform *= get_final_transform();
+ if (_get_embedder()) {
+ return _get_embedder()->get_popup_base_transform() * popup_base_transform;
+ }
+ return popup_base_transform;
}
void Window::_bind_methods() {
@@ -2188,6 +2225,7 @@ void Window::_bind_methods() {
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("_update_embedded_window"), &Window::_update_embedded_window);
ClassDB::bind_method(D_METHOD("set_theme", "theme"), &Window::set_theme);
ClassDB::bind_method(D_METHOD("get_theme"), &Window::get_theme);
@@ -2303,6 +2341,7 @@ void Window::_bind_methods() {
ADD_SIGNAL(MethodInfo("visibility_changed"));
ADD_SIGNAL(MethodInfo("about_to_popup"));
ADD_SIGNAL(MethodInfo("theme_changed"));
+ ADD_SIGNAL(MethodInfo("dpi_changed"));
ADD_SIGNAL(MethodInfo("titlebar_changed"));
BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED);
diff --git a/scene/main/window.h b/scene/main/window.h
index e9c217f973..9861fefc68 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -116,6 +116,7 @@ private:
bool exclusive = false;
bool wrap_controls = false;
bool updating_child_controls = false;
+ bool updating_embedded_window = false;
bool clamp_to_embedder = false;
LayoutDirection layout_dir = LAYOUT_DIRECTION_INHERITED;
@@ -123,6 +124,7 @@ private:
bool auto_translate = true;
void _update_child_controls();
+ void _update_embedded_window();
Size2i content_scale_size;
ContentScaleMode content_scale_mode = CONTENT_SCALE_MODE_DISABLED;
@@ -171,6 +173,8 @@ private:
Viewport *embedder = nullptr;
+ Transform2D window_transform;
+
friend class Viewport; //friend back, can call the methods below
void _window_input(const Ref<InputEvent> &p_ev);
@@ -372,7 +376,9 @@ public:
//
+ virtual Transform2D get_final_transform() const override;
virtual Transform2D get_screen_transform() const override;
+ virtual Transform2D get_popup_base_transform() const override;
Rect2i get_parent_rect() const;
virtual DisplayServer::WindowID get_window_id() const override;