summaryrefslogtreecommitdiff
path: root/scene/main
diff options
context:
space:
mode:
Diffstat (limited to 'scene/main')
-rw-r--r--scene/main/canvas_item.cpp56
-rw-r--r--scene/main/canvas_item.h23
-rw-r--r--scene/main/instance_placeholder.cpp2
-rw-r--r--scene/main/multiplayer_peer.cpp16
-rw-r--r--scene/main/multiplayer_peer.h8
-rw-r--r--scene/main/node.cpp103
-rw-r--r--scene/main/node.h13
-rw-r--r--scene/main/scene_tree.cpp28
-rw-r--r--scene/main/viewport.cpp16
-rw-r--r--scene/main/window.cpp78
-rw-r--r--scene/main/window.h2
11 files changed, 227 insertions, 118 deletions
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 05d86f77f2..840913d466 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -986,8 +986,8 @@ void CanvasItem::_bind_methods() {
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);
- ClassDB::bind_method(D_METHOD("set_clip_children", "enable"), &CanvasItem::set_clip_children);
- ClassDB::bind_method(D_METHOD("is_clipping_children"), &CanvasItem::is_clipping_children);
+ ClassDB::bind_method(D_METHOD("set_clip_children_mode", "mode"), &CanvasItem::set_clip_children_mode);
+ ClassDB::bind_method(D_METHOD("get_clip_children_mode"), &CanvasItem::get_clip_children_mode);
GDVIRTUAL_BIND(_draw);
@@ -997,7 +997,7 @@ void CanvasItem::_bind_methods() {
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, "top_level"), "set_as_top_level", "is_set_as_top_level");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_children"), "set_clip_children", "is_clipping_children");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "clip_children", PROPERTY_HINT_ENUM, "Disabled,Clip Only,Clip + Draw"), "set_clip_children_mode", "get_clip_children_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask");
ADD_GROUP("Texture", "texture_");
@@ -1035,6 +1035,11 @@ void CanvasItem::_bind_methods() {
BIND_ENUM_CONSTANT(TEXTURE_REPEAT_ENABLED);
BIND_ENUM_CONSTANT(TEXTURE_REPEAT_MIRROR);
BIND_ENUM_CONSTANT(TEXTURE_REPEAT_MAX);
+
+ BIND_ENUM_CONSTANT(CLIP_CHILDREN_DISABLED);
+ BIND_ENUM_CONSTANT(CLIP_CHILDREN_ONLY);
+ BIND_ENUM_CONSTANT(CLIP_CHILDREN_AND_DRAW);
+ BIND_ENUM_CONSTANT(CLIP_CHILDREN_MAX);
}
Transform2D CanvasItem::get_canvas_transform() const {
@@ -1092,7 +1097,7 @@ int CanvasItem::get_canvas_layer() const {
}
}
-void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
+void CanvasItem::_refresh_texture_filter_cache() {
if (!is_inside_tree()) {
return;
}
@@ -1107,6 +1112,14 @@ void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
} else {
texture_filter_cache = RS::CanvasItemTextureFilter(texture_filter);
}
+}
+
+void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
+ if (!is_inside_tree()) {
+ return;
+ }
+ _refresh_texture_filter_cache();
+
RS::get_singleton()->canvas_item_set_default_texture_filter(get_canvas_item(), texture_filter_cache);
queue_redraw();
@@ -1133,7 +1146,7 @@ CanvasItem::TextureFilter CanvasItem::get_texture_filter() const {
return texture_filter;
}
-void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
+void CanvasItem::_refresh_texture_repeat_cache() {
if (!is_inside_tree()) {
return;
}
@@ -1148,6 +1161,14 @@ void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
} else {
texture_repeat_cache = RS::CanvasItemTextureRepeat(texture_repeat);
}
+}
+
+void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
+ if (!is_inside_tree()) {
+ return;
+ }
+ _refresh_texture_repeat_cache();
+
RS::get_singleton()->canvas_item_set_default_texture_repeat(get_canvas_item(), texture_repeat_cache);
queue_redraw();
if (p_propagate) {
@@ -1169,26 +1190,39 @@ void CanvasItem::set_texture_repeat(TextureRepeat p_texture_repeat) {
notify_property_list_changed();
}
-void CanvasItem::set_clip_children(bool p_enabled) {
- if (clip_children == p_enabled) {
+void CanvasItem::set_clip_children_mode(ClipChildrenMode p_clip_mode) {
+ ERR_FAIL_COND(p_clip_mode >= CLIP_CHILDREN_MAX);
+
+ if (clip_children_mode == p_clip_mode) {
return;
}
- clip_children = p_enabled;
+ clip_children_mode = p_clip_mode;
if (Object::cast_to<CanvasGroup>(this) != nullptr) {
//avoid accidental bugs, make this not work on CanvasGroup
return;
}
- RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), clip_children ? RS::CANVAS_GROUP_MODE_OPAQUE : RS::CANVAS_GROUP_MODE_DISABLED);
+
+ RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), RS::CanvasGroupMode(clip_children_mode));
}
-bool CanvasItem::is_clipping_children() const {
- return clip_children;
+CanvasItem::ClipChildrenMode CanvasItem::get_clip_children_mode() const {
+ return clip_children_mode;
}
CanvasItem::TextureRepeat CanvasItem::get_texture_repeat() const {
return texture_repeat;
}
+CanvasItem::TextureFilter CanvasItem::get_texture_filter_in_tree() {
+ _refresh_texture_filter_cache();
+ return (TextureFilter)texture_filter_cache;
+}
+
+CanvasItem::TextureRepeat CanvasItem::get_texture_repeat_in_tree() {
+ _refresh_texture_repeat_cache();
+ return (TextureRepeat)texture_repeat_cache;
+}
+
CanvasItem::CanvasItem() :
xform_change(this) {
canvas_item = RenderingServer::get_singleton()->canvas_item_create();
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
index b80289fdb4..565ea930ce 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -66,8 +66,16 @@ public:
TEXTURE_REPEAT_MAX,
};
+ enum ClipChildrenMode {
+ CLIP_CHILDREN_DISABLED,
+ CLIP_CHILDREN_ONLY,
+ CLIP_CHILDREN_AND_DRAW,
+ CLIP_CHILDREN_MAX,
+ };
+
private:
- mutable SelfList<Node> xform_change;
+ mutable SelfList<Node>
+ xform_change;
RID canvas_item;
StringName canvas_group;
@@ -85,7 +93,6 @@ private:
Window *window = nullptr;
bool visible = true;
bool parent_visible_in_tree = false;
- bool clip_children = false;
bool pending_update = false;
bool top_level = false;
bool drawing = false;
@@ -95,6 +102,8 @@ private:
bool notify_local_transform = false;
bool notify_transform = false;
+ ClipChildrenMode clip_children_mode = CLIP_CHILDREN_DISABLED;
+
RS::CanvasItemTextureFilter texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
RS::CanvasItemTextureRepeat texture_repeat_cache = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
TextureFilter texture_filter = TEXTURE_FILTER_PARENT_NODE;
@@ -121,7 +130,9 @@ private:
static CanvasItem *current_item_drawn;
friend class Viewport;
+ void _refresh_texture_repeat_cache();
void _update_texture_repeat_changed(bool p_propagate);
+ void _refresh_texture_filter_cache();
void _update_texture_filter_changed(bool p_propagate);
protected:
@@ -200,8 +211,8 @@ public:
void queue_redraw();
void move_to_front();
- void set_clip_children(bool p_enabled);
- bool is_clipping_children() const;
+ void set_clip_children_mode(ClipChildrenMode p_clip_mode);
+ ClipChildrenMode get_clip_children_mode() const;
virtual void set_light_mask(int p_light_mask);
int get_light_mask() const;
@@ -310,6 +321,9 @@ public:
virtual void set_texture_repeat(TextureRepeat p_texture_repeat);
TextureRepeat get_texture_repeat() const;
+ TextureFilter get_texture_filter_in_tree();
+ TextureRepeat get_texture_repeat_in_tree();
+
// Used by control nodes to retrieve the parent's anchorable area
virtual Rect2 get_anchorable_rect() const { return Rect2(0, 0, 0, 0); };
@@ -321,6 +335,7 @@ public:
VARIANT_ENUM_CAST(CanvasItem::TextureFilter)
VARIANT_ENUM_CAST(CanvasItem::TextureRepeat)
+VARIANT_ENUM_CAST(CanvasItem::ClipChildrenMode)
class CanvasTexture : public Texture2D {
GDCLASS(CanvasTexture, Texture2D);
diff --git a/scene/main/instance_placeholder.cpp b/scene/main/instance_placeholder.cpp
index 6dd83e4636..56e719968b 100644
--- a/scene/main/instance_placeholder.cpp
+++ b/scene/main/instance_placeholder.cpp
@@ -100,7 +100,7 @@ Node *InstancePlaceholder::create_instance(bool p_replace, const Ref<PackedScene
}
if (p_replace) {
- queue_delete();
+ queue_free();
base->remove_child(this);
}
diff --git a/scene/main/multiplayer_peer.cpp b/scene/main/multiplayer_peer.cpp
index 9b63118f7c..462dc1babb 100644
--- a/scene/main/multiplayer_peer.cpp
+++ b/scene/main/multiplayer_peer.cpp
@@ -78,6 +78,10 @@ bool MultiplayerPeer::is_refusing_new_connections() const {
return refuse_connections;
}
+bool MultiplayerPeer::is_server_relay_supported() const {
+ return false;
+}
+
void MultiplayerPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_transfer_channel", "channel"), &MultiplayerPeer::set_transfer_channel);
ClassDB::bind_method(D_METHOD("get_transfer_channel"), &MultiplayerPeer::get_transfer_channel);
@@ -86,6 +90,8 @@ void MultiplayerPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_target_peer", "id"), &MultiplayerPeer::set_target_peer);
ClassDB::bind_method(D_METHOD("get_packet_peer"), &MultiplayerPeer::get_packet_peer);
+ ClassDB::bind_method(D_METHOD("get_packet_channel"), &MultiplayerPeer::get_packet_channel);
+ ClassDB::bind_method(D_METHOD("get_packet_mode"), &MultiplayerPeer::get_packet_mode);
ClassDB::bind_method(D_METHOD("poll"), &MultiplayerPeer::poll);
@@ -96,6 +102,8 @@ void MultiplayerPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_refuse_new_connections", "enable"), &MultiplayerPeer::set_refuse_new_connections);
ClassDB::bind_method(D_METHOD("is_refusing_new_connections"), &MultiplayerPeer::is_refusing_new_connections);
+ ClassDB::bind_method(D_METHOD("is_server_relay_supported"), &MultiplayerPeer::is_server_relay_supported);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_connections"), "set_refuse_new_connections", "is_refusing_new_connections");
ADD_PROPERTY(PropertyInfo(Variant::INT, "transfer_mode", PROPERTY_HINT_ENUM, "Unreliable,Unreliable Ordered,Reliable"), "set_transfer_mode", "get_transfer_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "transfer_channel", PROPERTY_HINT_RANGE, "0,255,1"), "set_transfer_channel", "get_transfer_channel");
@@ -177,6 +185,14 @@ bool MultiplayerPeerExtension::is_refusing_new_connections() const {
return MultiplayerPeer::is_refusing_new_connections();
}
+bool MultiplayerPeerExtension::is_server_relay_supported() const {
+ bool can_relay;
+ if (GDVIRTUAL_CALL(_is_server_relay_supported, can_relay)) {
+ return can_relay;
+ }
+ return MultiplayerPeer::is_server_relay_supported();
+}
+
void MultiplayerPeerExtension::_bind_methods() {
GDVIRTUAL_BIND(_get_packet, "r_buffer", "r_buffer_size");
GDVIRTUAL_BIND(_put_packet, "p_buffer", "p_buffer_size");
diff --git a/scene/main/multiplayer_peer.h b/scene/main/multiplayer_peer.h
index ab7483ece5..63ce66871e 100644
--- a/scene/main/multiplayer_peer.h
+++ b/scene/main/multiplayer_peer.h
@@ -74,10 +74,13 @@ public:
virtual TransferMode get_transfer_mode() const;
virtual void set_refuse_new_connections(bool p_enable);
virtual bool is_refusing_new_connections() const;
+ virtual bool is_server_relay_supported() const;
virtual void set_target_peer(int p_peer_id) = 0;
virtual int get_packet_peer() const = 0;
+ virtual TransferMode get_packet_mode() const = 0;
+ virtual int get_packet_channel() const = 0;
virtual bool is_server() const = 0;
@@ -123,12 +126,17 @@ public:
virtual bool is_refusing_new_connections() const override;
GDVIRTUAL0RC(bool, _is_refusing_new_connections); // Optional.
+ virtual bool is_server_relay_supported() const override;
+ GDVIRTUAL0RC(bool, _is_server_relay_supported); // Optional.
+
EXBIND1(set_transfer_channel, int);
EXBIND0RC(int, get_transfer_channel);
EXBIND1(set_transfer_mode, TransferMode);
EXBIND0RC(TransferMode, get_transfer_mode);
EXBIND1(set_target_peer, int);
EXBIND0RC(int, get_packet_peer);
+ EXBIND0RC(TransferMode, get_packet_mode);
+ EXBIND0RC(int, get_packet_channel);
EXBIND0RC(bool, is_server);
EXBIND0(poll);
EXBIND0RC(int, get_unique_id);
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 101a63db1b..038f182e8b 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -322,62 +322,62 @@ void Node::_propagate_exit_tree() {
data.depth = -1;
}
-void Node::move_child(Node *p_child, int p_pos) {
+void Node::move_child(Node *p_child, int p_index) {
ERR_FAIL_NULL(p_child);
ERR_FAIL_COND_MSG(p_child->data.parent != this, "Child is not a child of this node.");
// We need to check whether node is internal and move it only in the relevant node range.
if (p_child->_is_internal_front()) {
- if (p_pos < 0) {
- p_pos += data.internal_children_front;
+ if (p_index < 0) {
+ p_index += data.internal_children_front;
}
- ERR_FAIL_INDEX_MSG(p_pos, data.internal_children_front, vformat("Invalid new child position: %d. Child is internal.", p_pos));
- _move_child(p_child, p_pos);
+ ERR_FAIL_INDEX_MSG(p_index, data.internal_children_front, vformat("Invalid new child index: %d. Child is internal.", p_index));
+ _move_child(p_child, p_index);
} else if (p_child->_is_internal_back()) {
- if (p_pos < 0) {
- p_pos += data.internal_children_back;
+ if (p_index < 0) {
+ p_index += data.internal_children_back;
}
- ERR_FAIL_INDEX_MSG(p_pos, data.internal_children_back, vformat("Invalid new child position: %d. Child is internal.", p_pos));
- _move_child(p_child, data.children.size() - data.internal_children_back + p_pos);
+ ERR_FAIL_INDEX_MSG(p_index, data.internal_children_back, vformat("Invalid new child index: %d. Child is internal.", p_index));
+ _move_child(p_child, data.children.size() - data.internal_children_back + p_index);
} else {
- if (p_pos < 0) {
- p_pos += get_child_count(false);
+ if (p_index < 0) {
+ p_index += get_child_count(false);
}
- ERR_FAIL_INDEX_MSG(p_pos, data.children.size() + 1 - data.internal_children_front - data.internal_children_back, vformat("Invalid new child position: %d.", p_pos));
- _move_child(p_child, p_pos + data.internal_children_front);
+ ERR_FAIL_INDEX_MSG(p_index, data.children.size() + 1 - data.internal_children_front - data.internal_children_back, vformat("Invalid new child index: %d.", p_index));
+ _move_child(p_child, p_index + data.internal_children_front);
}
}
-void Node::_move_child(Node *p_child, int p_pos, bool p_ignore_end) {
+void Node::_move_child(Node *p_child, int p_index, bool p_ignore_end) {
ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, move_child() failed. Consider using call_deferred(\"move_child\") instead (or \"popup\" if this is from a popup).");
// Specifying one place beyond the end
- // means the same as moving to the last position
+ // means the same as moving to the last index
if (!p_ignore_end) { // p_ignore_end is a little hack to make back internal children work properly.
if (p_child->_is_internal_front()) {
- if (p_pos == data.internal_children_front) {
- p_pos--;
+ if (p_index == data.internal_children_front) {
+ p_index--;
}
} else if (p_child->_is_internal_back()) {
- if (p_pos == data.children.size()) {
- p_pos--;
+ if (p_index == data.children.size()) {
+ p_index--;
}
} else {
- if (p_pos == data.children.size() - data.internal_children_back) {
- p_pos--;
+ if (p_index == data.children.size() - data.internal_children_back) {
+ p_index--;
}
}
}
- if (p_child->data.pos == p_pos) {
+ if (p_child->data.index == p_index) {
return; //do nothing
}
- int motion_from = MIN(p_pos, p_child->data.pos);
- int motion_to = MAX(p_pos, p_child->data.pos);
+ int motion_from = MIN(p_index, p_child->data.index);
+ int motion_to = MAX(p_index, p_child->data.index);
- data.children.remove_at(p_child->data.pos);
- data.children.insert(p_pos, p_child);
+ data.children.remove_at(p_child->data.index);
+ data.children.insert(p_index, p_child);
if (data.tree) {
data.tree->tree_changed();
@@ -386,7 +386,7 @@ void Node::_move_child(Node *p_child, int p_pos, bool p_ignore_end) {
data.blocked++;
//new pos first
for (int i = motion_from; i <= motion_to; i++) {
- data.children[i]->data.pos = i;
+ data.children[i]->data.index = i;
}
// notification second
move_child_notify(p_child);
@@ -1024,11 +1024,9 @@ String increase_numeric_string(const String &s) {
void Node::_generate_serial_child_name(const Node *p_child, StringName &name) const {
if (name == StringName()) {
- //no name and a new name is needed, create one.
+ // No name and a new name is needed, create one.
name = p_child->get_class();
- // Adjust casing according to project setting.
- name = adjust_name_casing(name);
}
//quickly test if proposed name exists
@@ -1106,7 +1104,7 @@ void Node::_add_child_nocheck(Node *p_child, const StringName &p_name) {
//add a child node quickly, without name validation
p_child->data.name = p_name;
- p_child->data.pos = data.children.size();
+ p_child->data.index = data.children.size();
data.children.push_back(p_child);
p_child->data.parent = this;
@@ -1173,9 +1171,9 @@ void Node::remove_child(Node *p_child) {
Node **children = data.children.ptrw();
int idx = -1;
- if (p_child->data.pos >= 0 && p_child->data.pos < child_count) {
- if (children[p_child->data.pos] == p_child) {
- idx = p_child->data.pos;
+ if (p_child->data.index >= 0 && p_child->data.index < child_count) {
+ if (children[p_child->data.index] == p_child) {
+ idx = p_child->data.index;
}
}
@@ -1211,12 +1209,12 @@ void Node::remove_child(Node *p_child) {
children = data.children.ptrw();
for (int i = idx; i < child_count; i++) {
- children[i]->data.pos = i;
+ children[i]->data.index = i;
children[i]->notification(NOTIFICATION_MOVED_IN_PARENT);
}
p_child->data.parent = nullptr;
- p_child->data.pos = -1;
+ p_child->data.index = -1;
if (data.inside_tree) {
p_child->_propagate_after_exit_tree();
@@ -1343,12 +1341,23 @@ Node *Node::get_node(const NodePath &p_path) const {
Node *node = get_node_or_null(p_path);
if (unlikely(!node)) {
+ // Try to get a clear description of this node in the error message.
+ String desc;
+ if (is_inside_tree()) {
+ desc = get_path();
+ } else {
+ desc = get_name();
+ if (desc.is_empty()) {
+ desc = get_class();
+ }
+ }
+
if (p_path.is_absolute()) {
ERR_FAIL_V_MSG(nullptr,
- vformat(R"(Node not found: "%s" (absolute path attempted from "%s").)", p_path, get_path()));
+ vformat(R"(Node not found: "%s" (absolute path attempted from "%s").)", p_path, desc));
} else {
ERR_FAIL_V_MSG(nullptr,
- vformat(R"(Node not found: "%s" (relative to "%s").)", p_path, get_path()));
+ vformat(R"(Node not found: "%s" (relative to "%s").)", p_path, desc));
}
}
@@ -1475,7 +1484,7 @@ bool Node::is_greater_than(const Node *p_node) const {
int idx = data.depth - 1;
while (n) {
ERR_FAIL_INDEX_V(idx, data.depth, false);
- this_stack[idx--] = n->data.pos;
+ this_stack[idx--] = n->data.index;
n = n->data.parent;
}
ERR_FAIL_COND_V(idx != -1, false);
@@ -1483,7 +1492,7 @@ bool Node::is_greater_than(const Node *p_node) const {
idx = p_node->data.depth - 1;
while (n) {
ERR_FAIL_INDEX_V(idx, p_node->data.depth, false);
- that_stack[idx--] = n->data.pos;
+ that_stack[idx--] = n->data.index;
n = n->data.parent;
}
@@ -1894,9 +1903,9 @@ int Node::get_index(bool p_include_internal) const {
ERR_FAIL_COND_V_MSG(!p_include_internal && (_is_internal_front() || _is_internal_back()), -1, "Node is internal. Can't get index with 'include_internal' being false.");
if (data.parent && !p_include_internal) {
- return data.pos - data.parent->data.internal_children_front;
+ return data.index - data.parent->data.internal_children_front;
}
- return data.pos;
+ return data.index;
}
Ref<Tween> Node::create_tween() {
@@ -2391,12 +2400,12 @@ void Node::replace_by(Node *p_node, bool p_keep_groups) {
}
Node *parent = data.parent;
- int pos_in_parent = data.pos;
+ int index_in_parent = data.index;
if (data.parent) {
parent->remove_child(this);
parent->add_child(p_node);
- parent->move_child(p_node, pos_in_parent);
+ parent->move_child(p_node, index_in_parent);
}
while (get_child_count()) {
@@ -2571,7 +2580,7 @@ void Node::print_orphan_nodes() {
#endif
}
-void Node::queue_delete() {
+void Node::queue_free() {
if (is_inside_tree()) {
get_tree()->queue_delete(this);
} else {
@@ -2759,7 +2768,7 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_to_group", "group", "persistent"), &Node::add_to_group, DEFVAL(false));
ClassDB::bind_method(D_METHOD("remove_from_group", "group"), &Node::remove_from_group);
ClassDB::bind_method(D_METHOD("is_in_group", "group"), &Node::is_in_group);
- ClassDB::bind_method(D_METHOD("move_child", "child_node", "to_position"), &Node::move_child);
+ ClassDB::bind_method(D_METHOD("move_child", "child_node", "to_index"), &Node::move_child);
ClassDB::bind_method(D_METHOD("get_groups"), &Node::_get_groups);
ClassDB::bind_method(D_METHOD("set_owner", "owner"), &Node::set_owner);
ClassDB::bind_method(D_METHOD("get_owner"), &Node::get_owner);
@@ -2813,7 +2822,7 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_viewport"), &Node::get_viewport);
- ClassDB::bind_method(D_METHOD("queue_free"), &Node::queue_delete);
+ ClassDB::bind_method(D_METHOD("queue_free"), &Node::queue_free);
ClassDB::bind_method(D_METHOD("request_ready"), &Node::request_ready);
diff --git a/scene/main/node.h b/scene/main/node.h
index 4e6530cccd..4a3ec253b1 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -91,6 +91,7 @@ private:
SceneTree::Group *group = nullptr;
};
+ // This Data struct is to avoid namespace pollution in derived classes.
struct Data {
String scene_file_path;
Ref<SceneState> instance_state;
@@ -104,7 +105,7 @@ private:
int internal_children_front = 0;
int internal_children_back = 0;
- int pos = -1;
+ int index = -1;
int depth = -1;
int blocked = 0; // Safeguard that throws an error when attempting to modify the tree in a harmful way while being traversed.
StringName name;
@@ -186,8 +187,8 @@ private:
Error _rpc_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
Error _rpc_id_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- _FORCE_INLINE_ bool _is_internal_front() const { return data.parent && data.pos < data.parent->data.internal_children_front; }
- _FORCE_INLINE_ bool _is_internal_back() const { return data.parent && data.pos >= data.parent->data.children.size() - data.parent->data.internal_children_back; }
+ _FORCE_INLINE_ bool _is_internal_front() const { return data.parent && data.index < data.parent->data.internal_children_front; }
+ _FORCE_INLINE_ bool _is_internal_back() const { return data.parent && data.index >= data.parent->data.children.size() - data.parent->data.internal_children_back; }
friend class SceneTree;
@@ -346,8 +347,8 @@ public:
void get_groups(List<GroupInfo> *p_groups) const;
int get_persistent_group_count() const;
- void move_child(Node *p_child, int p_pos);
- void _move_child(Node *p_child, int p_pos, bool p_ignore_end = false);
+ void move_child(Node *p_child, int p_index);
+ void _move_child(Node *p_child, int p_index, bool p_ignore_end = false);
void set_owner(Node *p_owner);
Node *get_owner() const;
@@ -459,7 +460,7 @@ public:
#endif
static String adjust_name_casing(const String &p_name);
- void queue_delete();
+ void queue_free();
//hacks for speed
static void init_node_hrcr();
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index af481749d5..5ff9a29792 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -44,6 +44,7 @@
#include "node.h"
#include "scene/animation/tween.h"
#include "scene/debugger/scene_debugger.h"
+#include "scene/gui/control.h"
#include "scene/main/multiplayer_api.h"
#include "scene/main/viewport.h"
#include "scene/resources/environment.h"
@@ -895,6 +896,8 @@ void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_cal
call_lock++;
+ Vector<ObjectID> no_context_node_ids; // Nodes may be deleted due to this shortcut input.
+
for (int i = gr_node_count - 1; i >= 0; i--) {
if (p_viewport->is_input_handled()) {
break;
@@ -913,9 +916,22 @@ void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_cal
case CALL_INPUT_TYPE_INPUT:
n->_call_input(p_input);
break;
- case CALL_INPUT_TYPE_SHORTCUT_INPUT:
+ case CALL_INPUT_TYPE_SHORTCUT_INPUT: {
+ const Control *c = Object::cast_to<Control>(n);
+ if (c) {
+ // If calling shortcut input on a control, ensure it respects the shortcut context.
+ // Shortcut context (based on focus) only makes sense for controls (UI), so don't need to worry about it for nodes
+ if (c->get_shortcut_context() == nullptr) {
+ no_context_node_ids.append(n->get_instance_id());
+ continue;
+ }
+ if (!c->is_focus_owner_in_shortcut_context()) {
+ continue;
+ }
+ }
n->_call_shortcut_input(p_input);
break;
+ }
case CALL_INPUT_TYPE_UNHANDLED_INPUT:
n->_call_unhandled_input(p_input);
break;
@@ -925,6 +941,13 @@ void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_cal
}
}
+ for (const ObjectID &id : no_context_node_ids) {
+ Node *n = Object::cast_to<Node>(ObjectDB::get_instance(id));
+ if (n) {
+ n->_call_shortcut_input(p_input);
+ }
+ }
+
call_lock--;
if (call_lock == 0) {
call_skip.clear();
@@ -1390,6 +1413,9 @@ SceneTree::SceneTree() {
ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/msaa_3d", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/msaa_3d", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)")));
root->set_msaa_3d(Viewport::MSAA(msaa_mode_3d));
+ const bool transparent_background = GLOBAL_DEF("rendering/transparent_background", false);
+ root->set_transparent_background(transparent_background);
+
const int ssaa_mode = GLOBAL_DEF_BASIC("rendering/anti_aliasing/quality/screen_space_aa", 0);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/screen_space_aa", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast)"));
root->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode));
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 1f90f4a848..f395ede409 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -1161,7 +1161,7 @@ void Viewport::_gui_cancel_tooltip() {
gui.tooltip_timer = Ref<SceneTreeTimer>();
}
if (gui.tooltip_popup) {
- gui.tooltip_popup->queue_delete();
+ gui.tooltip_popup->queue_free();
}
}
@@ -1263,6 +1263,7 @@ void Viewport::_gui_show_tooltip() {
Point2 tooltip_offset = ProjectSettings::get_singleton()->get("display/mouse_cursor/tooltip_position_offset");
Rect2 r(gui.tooltip_pos + tooltip_offset, gui.tooltip_popup->get_contents_minimum_size());
+ r.size = r.size.min(panel->get_max_size());
Window *window = gui.tooltip_popup->get_parent_visible_window();
Rect2i vr;
@@ -1408,10 +1409,6 @@ Control *Viewport::gui_find_control(const Point2 &p_global) {
}
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 nullptr;
- }
-
if (!p_node->is_visible()) {
return nullptr; // Canvas item hidden, discard.
}
@@ -1495,7 +1492,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.key_event_accepted = false;
Point2 mpos = mb->get_position();
- gui.last_mouse_pos = mpos;
if (mb->is_pressed()) {
Size2 pos = mpos;
if (gui.mouse_focus_mask != MouseButton::NONE) {
@@ -1649,8 +1645,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.key_event_accepted = false;
Point2 mpos = mm->get_position();
- gui.last_mouse_pos = mpos;
-
// Drag & drop.
if (!gui.drag_attempted && gui.mouse_focus && (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE) {
gui.drag_accum += mm->get_relative();
@@ -2764,6 +2758,11 @@ void Viewport::push_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
ev = p_event;
}
+ Ref<InputEventMouse> me = ev;
+ if (me.is_valid()) {
+ gui.last_mouse_pos = me->get_position();
+ }
+
if (is_embedding_subwindows() && _sub_windows_forward_input(ev)) {
set_input_as_handled();
return;
@@ -3732,6 +3731,7 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_global_canvas_transform", "xform"), &Viewport::set_global_canvas_transform);
ClassDB::bind_method(D_METHOD("get_global_canvas_transform"), &Viewport::get_global_canvas_transform);
ClassDB::bind_method(D_METHOD("get_final_transform"), &Viewport::get_final_transform);
+ ClassDB::bind_method(D_METHOD("get_screen_transform"), &Viewport::get_screen_transform);
ClassDB::bind_method(D_METHOD("get_visible_rect"), &Viewport::get_visible_rect);
ClassDB::bind_method(D_METHOD("set_transparent_background", "enable"), &Viewport::set_transparent_background);
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 7fb3f32d36..ebb11ecee8 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -157,26 +157,18 @@ void Window::set_flag(Flags p_flag, bool p_enabled) {
embedder->_sub_window_update(this);
} else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
-#ifdef TOOLS_ENABLED
- if ((p_flag != FLAG_POPUP) || !(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
+ if (!is_in_edited_scene_root()) {
DisplayServer::get_singleton()->window_set_flag(DisplayServer::WindowFlags(p_flag), p_enabled, window_id);
}
-#else
- DisplayServer::get_singleton()->window_set_flag(DisplayServer::WindowFlags(p_flag), p_enabled, window_id);
-#endif
}
}
bool Window::get_flag(Flags p_flag) const {
ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
if (window_id != DisplayServer::INVALID_WINDOW_ID) {
-#ifdef TOOLS_ENABLED
- if ((p_flag != FLAG_POPUP) || !(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
+ if (!is_in_edited_scene_root()) {
flags[p_flag] = DisplayServer::get_singleton()->window_get_flag(DisplayServer::WindowFlags(p_flag), window_id);
}
-#else
- flags[p_flag] = DisplayServer::get_singleton()->window_get_flag(DisplayServer::WindowFlags(p_flag), window_id);
-#endif
}
return flags[p_flag];
}
@@ -232,6 +224,14 @@ bool Window::is_embedded() const {
return _get_embedder() != nullptr;
}
+bool Window::is_in_edited_scene_root() const {
+#ifdef TOOLS_ENABLED
+ return (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this));
+#else
+ return false;
+#endif
+}
+
void Window::_make_window() {
ERR_FAIL_COND(window_id != DisplayServer::INVALID_WINDOW_ID);
@@ -259,15 +259,12 @@ void Window::_make_window() {
#endif
DisplayServer::get_singleton()->window_set_title(tr_title, window_id);
DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id);
-#ifdef TOOLS_ENABLED
- if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
- DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive);
- } else {
+
+ if (is_in_edited_scene_root()) {
DisplayServer::get_singleton()->window_set_exclusive(window_id, false);
+ } else {
+ DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive);
}
-#else
- DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive);
-#endif
_update_window_size();
@@ -465,14 +462,10 @@ void Window::set_visible(bool p_visible) {
//update transient exclusive
if (transient_parent) {
if (exclusive && visible) {
-#ifdef TOOLS_ENABLED
- if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
+ if (!is_in_edited_scene_root()) {
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
- transient_parent->exclusive_child = this;
-#endif
} else {
if (transient_parent->exclusive_child == this) {
transient_parent->exclusive_child = nullptr;
@@ -519,13 +512,9 @@ void Window::_make_transient() {
window->transient_children.insert(this);
if (is_inside_tree() && is_visible() && exclusive) {
if (transient_parent->exclusive_child == nullptr) {
-#ifdef TOOLS_ENABLED
- if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
+ if (!is_in_edited_scene_root()) {
transient_parent->exclusive_child = this;
}
-#else
- transient_parent->exclusive_child = this;
-#endif
} else if (transient_parent->exclusive_child != this) {
ERR_PRINT("Making child transient exclusive, but parent has another exclusive child");
}
@@ -568,27 +557,19 @@ void Window::set_exclusive(bool p_exclusive) {
exclusive = p_exclusive;
if (!embedder && window_id != DisplayServer::INVALID_WINDOW_ID) {
-#ifdef TOOLS_ENABLED
- if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
- DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive);
- } else {
+ if (is_in_edited_scene_root()) {
DisplayServer::get_singleton()->window_set_exclusive(window_id, false);
+ } else {
+ DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive);
}
-#else
- DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive);
-#endif
}
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.");
-#ifdef TOOLS_ENABLED
- if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
+ if (!is_in_edited_scene_root()) {
transient_parent->exclusive_child = this;
}
-#else
- transient_parent->exclusive_child = this;
-#endif
} else {
if (transient_parent->exclusive_child == this) {
transient_parent->exclusive_child = nullptr;
@@ -606,6 +587,18 @@ bool Window::is_visible() const {
}
void Window::_update_window_size() {
+ // 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();
+
+ if (max_window_size != Size2i()) {
+ size = size.min(max_window_size);
+ min_size = min_size.min(max_window_size);
+ max_size = max_size.min(max_window_size);
+ }
+ }
+
Size2i size_limit;
if (wrap_controls) {
size_limit = get_contents_minimum_size();
@@ -651,9 +644,9 @@ void Window::_update_window_size() {
DisplayServer::get_singleton()->window_set_min_size(Size2i(), window_id);
}
- DisplayServer::get_singleton()->window_set_size(size, window_id);
DisplayServer::get_singleton()->window_set_max_size(max_size_valid ? max_size : Size2i(), window_id);
DisplayServer::get_singleton()->window_set_min_size(size_limit, window_id);
+ DisplayServer::get_singleton()->window_set_size(size, window_id);
}
//update the viewport
@@ -1847,6 +1840,11 @@ void Window::_bind_methods() {
}
Window::Window() {
+ RenderingServer *rendering_server = RenderingServer::get_singleton();
+ if (rendering_server) {
+ max_size = rendering_server->get_maximum_viewport_size();
+ }
+
theme_owner = memnew(ThemeOwner);
RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
}
diff --git a/scene/main/window.h b/scene/main/window.h
index 786f0ada38..03597b309a 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -234,6 +234,8 @@ public:
void set_clamp_to_embedder(bool p_enable);
bool is_clamped_to_embedder() const;
+ bool is_in_edited_scene_root() const;
+
bool can_draw() const;
void set_ime_active(bool p_active);