2
0
Эх сурвалжийг харах

Add methods for node reparenting

Tomasz Chabora 5 жил өмнө
parent
commit
2bdd7e9ea0

+ 9 - 0
doc/classes/Node.xml

@@ -604,6 +604,15 @@
 				Removes a node from a group. See notes in the description, and the group methods in [SceneTree].
 				Removes a node from a group. See notes in the description, and the group methods in [SceneTree].
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="reparent">
+			<return type="void" />
+			<param index="0" name="new_parent" type="Node" />
+			<param index="1" name="keep_global_transform" type="bool" default="true" />
+			<description>
+				Changes the parent of this [Node] to the [param new_parent]. The node needs to already have a parent.
+				If [param keep_global_transform] is [code]true[/code], the node's global transform will be preserved if supported. [Node2D], [Node3D] and [Control] support this argument (but [Control] keeps only position).
+			</description>
+		</method>
 		<method name="replace_by">
 		<method name="replace_by">
 			<return type="void" />
 			<return type="void" />
 			<param index="0" name="node" type="Node" />
 			<param index="0" name="node" type="Node" />

+ 8 - 0
scene/2d/node_2d.cpp

@@ -131,6 +131,14 @@ void Node2D::_update_transform() {
 	_notify_transform();
 	_notify_transform();
 }
 }
 
 
+void Node2D::reparent(Node *p_parent, bool p_keep_global_transform) {
+	Transform2D temp = get_global_transform();
+	Node::reparent(p_parent);
+	if (p_keep_global_transform) {
+		set_global_transform(temp);
+	}
+}
+
 void Node2D::set_position(const Point2 &p_pos) {
 void Node2D::set_position(const Point2 &p_pos) {
 	if (_xform_dirty) {
 	if (_xform_dirty) {
 		const_cast<Node2D *>(this)->_update_xform_values();
 		const_cast<Node2D *>(this)->_update_xform_values();

+ 1 - 0
scene/2d/node_2d.h

@@ -72,6 +72,7 @@ public:
 
 
 	virtual void _edit_set_rect(const Rect2 &p_edit_rect) override;
 	virtual void _edit_set_rect(const Rect2 &p_edit_rect) override;
 #endif
 #endif
+	virtual void reparent(Node *p_parent, bool p_keep_global_transform = true) override;
 
 
 	void set_position(const Point2 &p_pos);
 	void set_position(const Point2 &p_pos);
 	void set_rotation(real_t p_radians);
 	void set_rotation(real_t p_radians);

+ 8 - 0
scene/3d/node_3d.cpp

@@ -607,6 +607,14 @@ void Node3D::set_disable_gizmos(bool p_enabled) {
 #endif
 #endif
 }
 }
 
 
+void Node3D::reparent(Node *p_parent, bool p_keep_global_transform) {
+	Transform3D temp = get_global_transform();
+	Node::reparent(p_parent);
+	if (p_keep_global_transform) {
+		set_global_transform(temp);
+	}
+}
+
 void Node3D::set_disable_scale(bool p_enabled) {
 void Node3D::set_disable_scale(bool p_enabled) {
 	data.disable_scale = p_enabled;
 	data.disable_scale = p_enabled;
 }
 }

+ 1 - 0
scene/3d/node_3d.h

@@ -210,6 +210,7 @@ public:
 	virtual void set_transform_gizmo_visible(bool p_enabled) { data.transform_gizmo_visible = p_enabled; };
 	virtual void set_transform_gizmo_visible(bool p_enabled) { data.transform_gizmo_visible = p_enabled; };
 	virtual bool is_transform_gizmo_visible() const { return data.transform_gizmo_visible; };
 	virtual bool is_transform_gizmo_visible() const { return data.transform_gizmo_visible; };
 #endif
 #endif
+	virtual void reparent(Node *p_parent, bool p_keep_global_transform = true) override;
 
 
 	void set_disable_gizmos(bool p_enabled);
 	void set_disable_gizmos(bool p_enabled);
 	void update_gizmos();
 	void update_gizmos();

+ 8 - 0
scene/gui/control.cpp

@@ -184,6 +184,14 @@ Size2 Control::_edit_get_minimum_size() const {
 }
 }
 #endif
 #endif
 
 
+void Control::reparent(Node *p_parent, bool p_keep_global_transform) {
+	Transform2D temp = get_global_transform();
+	Node::reparent(p_parent);
+	if (p_keep_global_transform) {
+		set_global_position(temp.get_origin());
+	}
+}
+
 // Editor integration.
 // Editor integration.
 
 
 void Control::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
 void Control::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {

+ 1 - 0
scene/gui/control.h

@@ -384,6 +384,7 @@ public:
 
 
 	virtual Size2 _edit_get_minimum_size() const override;
 	virtual Size2 _edit_get_minimum_size() const override;
 #endif
 #endif
+	virtual void reparent(Node *p_parent, bool p_keep_global_transform = true) override;
 
 
 	// Editor integration.
 	// Editor integration.
 
 

+ 13 - 0
scene/main/node.cpp

@@ -1435,6 +1435,18 @@ TypedArray<Node> Node::find_children(const String &p_pattern, const String &p_ty
 	return ret;
 	return ret;
 }
 }
 
 
+void Node::reparent(Node *p_parent, bool p_keep_global_transform) {
+	ERR_FAIL_NULL(p_parent);
+	ERR_FAIL_NULL_MSG(data.parent, "Node needs a parent to be reparented.");
+
+	if (p_parent == data.parent) {
+		return;
+	}
+
+	data.parent->remove_child(this);
+	p_parent->add_child(this);
+}
+
 Node *Node::get_parent() const {
 Node *Node::get_parent() const {
 	return data.parent;
 	return data.parent;
 }
 }
@@ -2792,6 +2804,7 @@ void Node::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_name"), &Node::get_name);
 	ClassDB::bind_method(D_METHOD("get_name"), &Node::get_name);
 	ClassDB::bind_method(D_METHOD("add_child", "node", "legible_unique_name", "internal"), &Node::add_child, DEFVAL(false), DEFVAL(0));
 	ClassDB::bind_method(D_METHOD("add_child", "node", "legible_unique_name", "internal"), &Node::add_child, DEFVAL(false), DEFVAL(0));
 	ClassDB::bind_method(D_METHOD("remove_child", "node"), &Node::remove_child);
 	ClassDB::bind_method(D_METHOD("remove_child", "node"), &Node::remove_child);
+	ClassDB::bind_method(D_METHOD("reparent", "new_parent", "keep_global_transform"), &Node::reparent, DEFVAL(true));
 	ClassDB::bind_method(D_METHOD("get_child_count", "include_internal"), &Node::get_child_count, DEFVAL(false)); // Note that the default value bound for include_internal is false, while the method is declared with true. This is because internal nodes are irrelevant for GDSCript.
 	ClassDB::bind_method(D_METHOD("get_child_count", "include_internal"), &Node::get_child_count, DEFVAL(false)); // Note that the default value bound for include_internal is false, while the method is declared with true. This is because internal nodes are irrelevant for GDSCript.
 	ClassDB::bind_method(D_METHOD("get_children", "include_internal"), &Node::_get_children, DEFVAL(false));
 	ClassDB::bind_method(D_METHOD("get_children", "include_internal"), &Node::_get_children, DEFVAL(false));
 	ClassDB::bind_method(D_METHOD("get_child", "idx", "include_internal"), &Node::get_child, DEFVAL(false));
 	ClassDB::bind_method(D_METHOD("get_child", "idx", "include_internal"), &Node::get_child, DEFVAL(false));

+ 1 - 0
scene/main/node.h

@@ -317,6 +317,7 @@ public:
 	bool has_node_and_resource(const NodePath &p_path) const;
 	bool has_node_and_resource(const NodePath &p_path) const;
 	Node *get_node_and_resource(const NodePath &p_path, Ref<Resource> &r_res, Vector<StringName> &r_leftover_subpath, bool p_last_is_property = true) const;
 	Node *get_node_and_resource(const NodePath &p_path, Ref<Resource> &r_res, Vector<StringName> &r_leftover_subpath, bool p_last_is_property = true) const;
 
 
+	virtual void reparent(Node *p_parent, bool p_keep_global_transform = true);
 	Node *get_parent() const;
 	Node *get_parent() const;
 	Node *find_parent(const String &p_pattern) const;
 	Node *find_parent(const String &p_pattern) const;