Merge pull request #82248 from lawnjelly/child_order_changed
[3.x] Deprecate `NOTIFICATION_MOVED_IN_PARENT`
This commit is contained in:
commit
fae70792a0
14 changed files with 224 additions and 47 deletions
|
@ -797,6 +797,11 @@
|
|||
When this signal is received, the child [code]node[/code] is still in the tree and valid. This signal is emitted [i]after[/i] the child node's own [signal tree_exiting] and [constant NOTIFICATION_EXIT_TREE].
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="child_order_changed">
|
||||
<description>
|
||||
Emitted when the list of children is changed. This happens when child nodes are added, moved, or removed.
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="ready">
|
||||
<description>
|
||||
Emitted when the node is ready.
|
||||
|
@ -835,7 +840,7 @@
|
|||
This notification is emitted [i]after[/i] the related [signal tree_exiting].
|
||||
</constant>
|
||||
<constant name="NOTIFICATION_MOVED_IN_PARENT" value="12">
|
||||
Notification received when the node is moved in the parent.
|
||||
[i]Deprecated.[/i] This notification is no longer emitted. Use [constant NOTIFICATION_CHILD_ORDER_CHANGED] instead.
|
||||
</constant>
|
||||
<constant name="NOTIFICATION_READY" value="13">
|
||||
Notification received when the node is ready. See [method _ready].
|
||||
|
@ -874,6 +879,9 @@
|
|||
<constant name="NOTIFICATION_PATH_CHANGED" value="23">
|
||||
Notification received when the node's [NodePath] changed.
|
||||
</constant>
|
||||
<constant name="NOTIFICATION_CHILD_ORDER_CHANGED" value="24">
|
||||
Notification received when the list of children is changed. This happens when child nodes are added, moved, or removed.
|
||||
</constant>
|
||||
<constant name="NOTIFICATION_INTERNAL_PROCESS" value="25">
|
||||
Notification received every frame when the internal process flag is set (see [method set_process_internal]).
|
||||
</constant>
|
||||
|
|
|
@ -2399,6 +2399,12 @@ bool Main::iteration() {
|
|||
exit = true;
|
||||
}
|
||||
visual_server_callbacks->flush();
|
||||
|
||||
// Ensure that VisualServer is kept up to date at least once with any ordering changes
|
||||
// of canvas items before a render.
|
||||
// This ensures this will be done at least once in apps that create their own MainLoop.
|
||||
Viewport::flush_canvas_parents_dirty_order();
|
||||
|
||||
message_queue->flush();
|
||||
|
||||
VisualServer::get_singleton()->sync(); //sync if still drawing from previous frames.
|
||||
|
|
|
@ -611,20 +611,6 @@ void CanvasItem::_notification(int p_what) {
|
|||
notification(NOTIFICATION_RESET_PHYSICS_INTERPOLATION);
|
||||
}
|
||||
} break;
|
||||
case NOTIFICATION_MOVED_IN_PARENT: {
|
||||
if (!is_inside_tree()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (canvas_group != "") {
|
||||
get_tree()->call_group_flags(SceneTree::GROUP_CALL_UNIQUE, canvas_group, "_toplevel_raise_self");
|
||||
} else {
|
||||
CanvasItem *p = get_parent_item();
|
||||
ERR_FAIL_COND(!p);
|
||||
VisualServer::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);
|
||||
|
@ -662,6 +648,20 @@ void CanvasItem::_name_changed_notify() {
|
|||
}
|
||||
#endif
|
||||
|
||||
void CanvasItem::update_draw_order() {
|
||||
if (!is_inside_tree()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (canvas_group != "") {
|
||||
get_tree()->call_group_flags(SceneTree::GROUP_CALL_UNIQUE, canvas_group, "_toplevel_raise_self");
|
||||
} else {
|
||||
CanvasItem *p = get_parent_item();
|
||||
ERR_FAIL_NULL(p);
|
||||
VisualServer::get_singleton()->canvas_item_set_draw_index(canvas_item, get_index());
|
||||
}
|
||||
}
|
||||
|
||||
void CanvasItem::update() {
|
||||
if (!is_inside_tree()) {
|
||||
return;
|
||||
|
|
|
@ -296,6 +296,8 @@ public:
|
|||
virtual Transform2D _edit_get_transform() const;
|
||||
#endif
|
||||
|
||||
void update_draw_order();
|
||||
|
||||
/* VISIBILITY */
|
||||
|
||||
void set_visible(bool p_visible);
|
||||
|
|
|
@ -30,9 +30,20 @@
|
|||
|
||||
#include "skeleton_2d.h"
|
||||
|
||||
void Bone2D::_order_changed_in_parent() {
|
||||
if (skeleton) {
|
||||
skeleton->_make_bone_setup_dirty();
|
||||
}
|
||||
}
|
||||
|
||||
void Bone2D::_notification(int p_what) {
|
||||
if (p_what == NOTIFICATION_ENTER_TREE) {
|
||||
Node *parent = get_parent();
|
||||
|
||||
if (parent) {
|
||||
parent->connect("child_order_changed", this, "_order_changed_in_parent");
|
||||
}
|
||||
|
||||
parent_bone = Object::cast_to<Bone2D>(parent);
|
||||
skeleton = nullptr;
|
||||
while (parent) {
|
||||
|
@ -59,13 +70,13 @@ void Bone2D::_notification(int p_what) {
|
|||
skeleton->_make_transform_dirty();
|
||||
}
|
||||
}
|
||||
if (p_what == NOTIFICATION_MOVED_IN_PARENT) {
|
||||
if (skeleton) {
|
||||
skeleton->_make_bone_setup_dirty();
|
||||
}
|
||||
}
|
||||
|
||||
if (p_what == NOTIFICATION_EXIT_TREE) {
|
||||
Node *parent = get_parent();
|
||||
if (parent) {
|
||||
parent->disconnect("child_order_changed", this, "_order_changed_in_parent");
|
||||
}
|
||||
|
||||
if (skeleton) {
|
||||
for (int i = 0; i < skeleton->bones.size(); i++) {
|
||||
if (skeleton->bones[i].bone == this) {
|
||||
|
@ -89,6 +100,8 @@ void Bone2D::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_default_length", "default_length"), &Bone2D::set_default_length);
|
||||
ClassDB::bind_method(D_METHOD("get_default_length"), &Bone2D::get_default_length);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_order_changed_in_parent"), &Bone2D::_order_changed_in_parent);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "rest"), "set_rest", "get_rest");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::REAL, "default_length", PROPERTY_HINT_RANGE, "1,1024,1"), "set_default_length", "get_default_length");
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ class Bone2D : public Node2D {
|
|||
protected:
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
void _order_changed_in_parent();
|
||||
|
||||
public:
|
||||
void set_rest(const Transform2D &p_rest);
|
||||
|
|
|
@ -592,22 +592,6 @@ void Control::_notification(int p_notification) {
|
|||
}
|
||||
*/
|
||||
|
||||
} break;
|
||||
case NOTIFICATION_MOVED_IN_PARENT: {
|
||||
// some parents need to know the order of the children to draw (like TabContainer)
|
||||
// update if necessary
|
||||
if (data.parent) {
|
||||
data.parent->update();
|
||||
}
|
||||
update();
|
||||
|
||||
if (data.SI) {
|
||||
get_viewport()->_gui_set_subwindow_order_dirty();
|
||||
}
|
||||
if (data.RI) {
|
||||
get_viewport()->_gui_set_root_order_dirty();
|
||||
}
|
||||
|
||||
} break;
|
||||
case NOTIFICATION_RESIZED: {
|
||||
emit_signal(SceneStringNames::get_singleton()->resized);
|
||||
|
@ -2665,6 +2649,15 @@ Control::GrowDirection Control::get_v_grow_direction() const {
|
|||
return data.v_grow;
|
||||
}
|
||||
|
||||
void Control::_query_order_update(bool &r_subwindow_order_dirty, bool &r_root_order_dirty) const {
|
||||
if (data.SI) {
|
||||
r_subwindow_order_dirty = true;
|
||||
}
|
||||
if (data.RI) {
|
||||
r_root_order_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Control::_bind_methods() {
|
||||
//ClassDB::bind_method(D_METHOD("_window_resize_event"),&Control::_window_resize_event);
|
||||
ClassDB::bind_method(D_METHOD("_size_changed"), &Control::_size_changed);
|
||||
|
|
|
@ -508,6 +508,8 @@ public:
|
|||
virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const;
|
||||
virtual String get_configuration_warning() const;
|
||||
|
||||
void _query_order_update(bool &r_subwindow_order_dirty, bool &r_root_order_dirty) const;
|
||||
|
||||
Control();
|
||||
~Control();
|
||||
};
|
||||
|
|
|
@ -228,15 +228,16 @@ void CanvasLayer::_notification(int p_what) {
|
|||
viewport = RID();
|
||||
_update_follow_viewport(false);
|
||||
} break;
|
||||
case NOTIFICATION_MOVED_IN_PARENT: {
|
||||
// Note: As this step requires traversing the entire scene tree, it is thus expensive
|
||||
// to move the canvas layer multiple times. Take special care when deleting / moving
|
||||
// multiple nodes to prevent multiple NOTIFICATION_MOVED_IN_PARENT occurring.
|
||||
_update_layer_orders();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void CanvasLayer::update_draw_order() {
|
||||
// Note: As this step requires traversing the entire scene tree, it is thus expensive
|
||||
// to move the canvas layer multiple times. Take special care when deleting / moving
|
||||
// multiple nodes to prevent this happening multiple times.
|
||||
_update_layer_orders();
|
||||
}
|
||||
|
||||
Size2 CanvasLayer::get_viewport_size() const {
|
||||
if (!is_inside_tree()) {
|
||||
return Size2(1, 1);
|
||||
|
|
|
@ -70,6 +70,8 @@ protected:
|
|||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void update_draw_order();
|
||||
|
||||
void set_layer(int p_xform);
|
||||
int get_layer() const;
|
||||
|
||||
|
|
|
@ -426,9 +426,8 @@ void Node::move_child(Node *p_child, int p_pos) {
|
|||
}
|
||||
// notification second
|
||||
move_child_notify(p_child);
|
||||
for (int i = motion_from; i <= motion_to; i++) {
|
||||
data.children[i]->notification(NOTIFICATION_MOVED_IN_PARENT);
|
||||
}
|
||||
Viewport::notify_canvas_parent_children_moved(*this, motion_from, motion_to + 1);
|
||||
|
||||
p_child->_propagate_groups_dirty();
|
||||
|
||||
data.blocked--;
|
||||
|
@ -1364,9 +1363,11 @@ void Node::remove_child(Node *p_child) {
|
|||
|
||||
for (int i = idx; i < child_count; i++) {
|
||||
children[i]->data.pos = i;
|
||||
children[i]->notification(NOTIFICATION_MOVED_IN_PARENT);
|
||||
}
|
||||
|
||||
Viewport::notify_canvas_parent_children_moved(*this, idx, child_count);
|
||||
Viewport::notify_canvas_parent_child_count_reduced(*this);
|
||||
|
||||
p_child->data.parent = nullptr;
|
||||
p_child->data.pos = -1;
|
||||
|
||||
|
@ -3193,6 +3194,7 @@ void Node::_bind_methods() {
|
|||
BIND_CONSTANT(NOTIFICATION_DRAG_BEGIN);
|
||||
BIND_CONSTANT(NOTIFICATION_DRAG_END);
|
||||
BIND_CONSTANT(NOTIFICATION_PATH_CHANGED);
|
||||
BIND_CONSTANT(NOTIFICATION_CHILD_ORDER_CHANGED);
|
||||
BIND_CONSTANT(NOTIFICATION_INTERNAL_PROCESS);
|
||||
BIND_CONSTANT(NOTIFICATION_INTERNAL_PHYSICS_PROCESS);
|
||||
BIND_CONSTANT(NOTIFICATION_POST_ENTER_TREE);
|
||||
|
@ -3233,6 +3235,7 @@ void Node::_bind_methods() {
|
|||
ADD_SIGNAL(MethodInfo("tree_exited"));
|
||||
ADD_SIGNAL(MethodInfo("child_entered_tree", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT, "Node")));
|
||||
ADD_SIGNAL(MethodInfo("child_exiting_tree", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT, "Node")));
|
||||
ADD_SIGNAL(MethodInfo("child_order_changed"));
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "pause_mode", PROPERTY_HINT_ENUM, "Inherit,Stop,Process"), "set_pause_mode", "get_pause_mode");
|
||||
|
||||
|
|
|
@ -134,6 +134,11 @@ private:
|
|||
|
||||
int process_priority;
|
||||
|
||||
// If canvas item children of a node change child order,
|
||||
// we store this information in the scenetree in a temporary structure
|
||||
// allocated on demand per node.
|
||||
uint32_t canvas_parent_id = UINT32_MAX;
|
||||
|
||||
// Keep bitpacked values together to get better packing
|
||||
PauseMode pause_mode : 2;
|
||||
PhysicsInterpolationMode physics_interpolation_mode : 2;
|
||||
|
@ -279,7 +284,7 @@ public:
|
|||
NOTIFICATION_DRAG_BEGIN = 21,
|
||||
NOTIFICATION_DRAG_END = 22,
|
||||
NOTIFICATION_PATH_CHANGED = 23,
|
||||
//NOTIFICATION_TRANSLATION_CHANGED = 24, moved below
|
||||
NOTIFICATION_CHILD_ORDER_CHANGED = 24,
|
||||
NOTIFICATION_INTERNAL_PROCESS = 25,
|
||||
NOTIFICATION_INTERNAL_PHYSICS_PROCESS = 26,
|
||||
NOTIFICATION_POST_ENTER_TREE = 27,
|
||||
|
@ -455,6 +460,9 @@ public:
|
|||
_FORCE_INLINE_ bool is_physics_interpolated_and_enabled() const { return is_inside_tree() && get_tree()->is_physics_interpolation_enabled() && is_physics_interpolated(); }
|
||||
void reset_physics_interpolation();
|
||||
|
||||
uint32_t get_canvas_parent_id() const { return data.canvas_parent_id; }
|
||||
void set_canvas_parent_id(uint32_t p_id) { data.canvas_parent_id = p_id; }
|
||||
|
||||
bool is_node_ready() const;
|
||||
void request_ready();
|
||||
|
||||
|
|
|
@ -54,6 +54,8 @@
|
|||
#include "scene/scene_string_names.h"
|
||||
#include "servers/physics_2d_server.h"
|
||||
|
||||
LocalVector<Viewport::GUI::CanvasParent> Viewport::GUI::canvas_parents_dirty_order;
|
||||
|
||||
void ViewportTexture::setup_local_to_scene() {
|
||||
Node *local_scene = get_local_scene();
|
||||
if (!local_scene) {
|
||||
|
@ -3214,6 +3216,130 @@ bool Viewport::is_handling_input_locally() const {
|
|||
return handle_input_locally;
|
||||
}
|
||||
|
||||
void Viewport::notify_canvas_parent_child_count_reduced(const Node &p_parent) {
|
||||
uint32_t id = p_parent.get_canvas_parent_id();
|
||||
|
||||
ERR_FAIL_COND(id == UINT32_MAX);
|
||||
ERR_FAIL_UNSIGNED_INDEX(id, GUI::canvas_parents_dirty_order.size());
|
||||
|
||||
GUI::CanvasParent &d = GUI::canvas_parents_dirty_order[id];
|
||||
|
||||
// No pending children moved.
|
||||
if (!d.last_child_moved_plus_one) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t num_children = p_parent.get_child_count();
|
||||
d.last_child_moved_plus_one = MIN(d.last_child_moved_plus_one, num_children);
|
||||
}
|
||||
|
||||
void Viewport::notify_canvas_parent_children_moved(Node &r_parent, uint32_t p_first_child, uint32_t p_last_child_plus_one) {
|
||||
// First ensure the parent has a CanvasParent allocated.
|
||||
uint32_t id = r_parent.get_canvas_parent_id();
|
||||
|
||||
if (id == UINT32_MAX) {
|
||||
id = GUI::canvas_parents_dirty_order.size();
|
||||
r_parent.set_canvas_parent_id(id);
|
||||
GUI::canvas_parents_dirty_order.resize(id + 1);
|
||||
|
||||
GUI::CanvasParent &d = GUI::canvas_parents_dirty_order[id];
|
||||
d.id = r_parent.get_instance_id();
|
||||
d.first_child_moved = p_first_child;
|
||||
d.last_child_moved_plus_one = p_last_child_plus_one;
|
||||
return;
|
||||
}
|
||||
|
||||
GUI::CanvasParent &d = GUI::canvas_parents_dirty_order[id];
|
||||
DEV_CHECK_ONCE(d.id == r_parent.get_instance_id());
|
||||
d.first_child_moved = MIN(d.first_child_moved, p_first_child);
|
||||
d.last_child_moved_plus_one = MAX(d.last_child_moved_plus_one, p_last_child_plus_one);
|
||||
}
|
||||
|
||||
void Viewport::flush_canvas_parents_dirty_order() {
|
||||
bool canvas_layers_moved = false;
|
||||
|
||||
for (uint32_t n = 0; n < GUI::canvas_parents_dirty_order.size(); n++) {
|
||||
GUI::CanvasParent &d = GUI::canvas_parents_dirty_order[n];
|
||||
|
||||
Object *obj = ObjectDB::get_instance(d.id);
|
||||
if (!obj) {
|
||||
// May have been deleted.
|
||||
continue;
|
||||
}
|
||||
|
||||
Node *node = static_cast<Node *>(obj);
|
||||
Control *parent_control = Object::cast_to<Control>(node);
|
||||
|
||||
// Allow anything subscribing to this signal (skeletons etc)
|
||||
// to make any changes necessary.
|
||||
node->emit_signal("child_order_changed");
|
||||
|
||||
// Reset the id stored in the node, as this data is cleared after every flush.
|
||||
node->set_canvas_parent_id(UINT32_MAX);
|
||||
|
||||
// This should be very rare, as the last_child_moved_plus_one is usually kept up
|
||||
// to date when within the scene tree. But it may become out of date outside the scene tree.
|
||||
// This will cause no problems, just a very small possibility of more notifications being sent than
|
||||
// necessary in that very rare situation.
|
||||
if (d.last_child_moved_plus_one > (uint32_t)node->get_child_count()) {
|
||||
d.last_child_moved_plus_one = node->get_child_count();
|
||||
}
|
||||
|
||||
bool subwindow_order_dirty = false;
|
||||
bool root_order_dirty = false;
|
||||
bool control_found = false;
|
||||
|
||||
for (uint32_t c = d.first_child_moved; c < d.last_child_moved_plus_one; c++) {
|
||||
Node *child = node->get_child(c);
|
||||
|
||||
CanvasItem *ci = Object::cast_to<CanvasItem>(child);
|
||||
if (ci) {
|
||||
ci->update_draw_order();
|
||||
|
||||
Control *control = Object::cast_to<Control>(ci);
|
||||
if (control) {
|
||||
control->_query_order_update(subwindow_order_dirty, root_order_dirty);
|
||||
|
||||
if (parent_control && !control_found) {
|
||||
control_found = true;
|
||||
|
||||
// In case of regressions, this could be moved to AFTER
|
||||
// the children have been updated.
|
||||
parent_control->update();
|
||||
}
|
||||
control->update();
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
CanvasLayer *cl = Object::cast_to<CanvasLayer>(child);
|
||||
if (cl) {
|
||||
// If any canvas layers moved, we need to do an expensive update,
|
||||
// so we ensure doing this only once.
|
||||
if (!canvas_layers_moved) {
|
||||
canvas_layers_moved = true;
|
||||
cl->update_draw_order();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Viewport *viewport = node->get_viewport();
|
||||
if (viewport) {
|
||||
if (subwindow_order_dirty) {
|
||||
viewport->_gui_set_subwindow_order_dirty();
|
||||
}
|
||||
if (root_order_dirty) {
|
||||
viewport->_gui_set_root_order_dirty();
|
||||
}
|
||||
}
|
||||
|
||||
node->notification(Node::NOTIFICATION_CHILD_ORDER_CHANGED);
|
||||
}
|
||||
|
||||
GUI::canvas_parents_dirty_order.clear();
|
||||
}
|
||||
|
||||
void Viewport::_validate_property(PropertyInfo &property) const {
|
||||
if (VisualServer::get_singleton()->is_low_end() && (property.name == "hdr" || property.name == "use_32_bpc_depth" || property.name == "debanding" || property.name == "sharpen_intensity" || property.name == "debug_draw")) {
|
||||
// Only available in GLES3.
|
||||
|
|
|
@ -326,6 +326,14 @@ private:
|
|||
bool dragging;
|
||||
bool drag_successful;
|
||||
|
||||
struct CanvasParent {
|
||||
ObjectID id;
|
||||
uint32_t first_child_moved = UINT32_MAX;
|
||||
uint32_t last_child_moved_plus_one = 0;
|
||||
};
|
||||
|
||||
static LocalVector<CanvasParent> canvas_parents_dirty_order;
|
||||
|
||||
GUI();
|
||||
} gui;
|
||||
|
||||
|
@ -588,6 +596,10 @@ public:
|
|||
bool gui_is_dragging() const;
|
||||
bool gui_is_drag_successful() const;
|
||||
|
||||
static void notify_canvas_parent_children_moved(Node &r_parent, uint32_t p_first_child, uint32_t p_last_child_plus_one);
|
||||
static void notify_canvas_parent_child_count_reduced(const Node &p_parent);
|
||||
static void flush_canvas_parents_dirty_order();
|
||||
|
||||
Viewport();
|
||||
~Viewport();
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue