summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYuri Sizov <11782833+YuriSizov@users.noreply.github.com>2023-05-31 13:02:19 +0200
committerGitHub <noreply@github.com>2023-05-31 13:02:19 +0200
commit5598fec7c0a820b79a8518c49e12f93eca804958 (patch)
treec93b81425923beda4d25513f1e6a2fef74526be7
parent943e5b9019011645045923f4e14401afb4323c91 (diff)
parent3ed7bdc26f30747961a0b189c20747d117f33f63 (diff)
downloadredot-engine-5598fec7c0a820b79a8518c49e12f93eca804958.tar.gz
Merge pull request #77446 from YuriSizov/gui-treeitem-add-child
Implement `TreeItem.add_child`
-rw-r--r--doc/classes/TreeItem.xml10
-rw-r--r--scene/gui/tree.cpp117
-rw-r--r--scene/gui/tree.h7
3 files changed, 86 insertions, 48 deletions
diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml
index 2bd8f57bd2..33b69929bd 100644
--- a/doc/classes/TreeItem.xml
+++ b/doc/classes/TreeItem.xml
@@ -22,6 +22,13 @@
Adds a button with [Texture2D] [param button] at column [param column]. The [param id] is used to identify the button in the according [signal Tree.button_clicked] signal and can be different from the buttons index. If not specified, the next available index is used, which may be retrieved by calling [method get_button_count] immediately before this method. Optionally, the button can be [param disabled] and have a [param tooltip_text].
</description>
</method>
+ <method name="add_child">
+ <return type="void" />
+ <param index="0" name="child" type="TreeItem" />
+ <description>
+ Adds a previously unparented [TreeItem] as a direct child of this one. The [param child] item must not be a part of any [Tree] or parented to any [TreeItem]. See also [method remove_child].
+ </description>
+ </method>
<method name="call_recursive" qualifiers="vararg">
<return type="void" />
<param index="0" name="method" type="StringName" />
@@ -430,7 +437,8 @@
<return type="void" />
<param index="0" name="child" type="TreeItem" />
<description>
- Removes the given child [TreeItem] and all its children from the [Tree]. Note that it doesn't free the item from memory, so it can be reused later. To completely remove a [TreeItem] use [method Object.free].
+ Removes the given child [TreeItem] and all its children from the [Tree]. Note that it doesn't free the item from memory, so it can be reused later (see [method add_child]). To completely remove a [TreeItem] use [method Object.free].
+ [b]Note:[/b] If you want to move a child from one [Tree] to another, then instead of removing and adding it manually you can use [method move_before] or [method move_after].
</description>
</method>
<method name="select">
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 9ec461cad4..8afd4af19d 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -677,23 +677,26 @@ TreeItem *TreeItem::create_child(int p_index) {
tree->queue_redraw();
}
- TreeItem *l_prev = nullptr;
- TreeItem *c = first_child;
- int idx = 0;
+ TreeItem *item_prev = nullptr;
+ TreeItem *item_next = first_child;
- while (c) {
- if (idx++ == p_index) {
- c->prev = ti;
- ti->next = c;
+ int idx = 0;
+ while (item_next) {
+ if (idx == p_index) {
+ item_next->prev = ti;
+ ti->next = item_next;
break;
}
- l_prev = c;
- c = c->next;
+
+ item_prev = item_next;
+ item_next = item_next->next;
+ idx++;
}
- if (l_prev) {
- l_prev->next = ti;
- ti->prev = l_prev;
+ if (item_prev) {
+ item_prev->next = ti;
+ ti->prev = item_prev;
+
if (!children_cache.is_empty()) {
if (ti->next) {
children_cache.insert(p_index, ti);
@@ -713,6 +716,46 @@ TreeItem *TreeItem::create_child(int p_index) {
return ti;
}
+void TreeItem::add_child(TreeItem *p_item) {
+ ERR_FAIL_NULL(p_item);
+ ERR_FAIL_COND(p_item->tree);
+ ERR_FAIL_COND(p_item->parent);
+
+ p_item->_change_tree(tree);
+ p_item->parent = this;
+
+ TreeItem *item_prev = first_child;
+ while (item_prev && item_prev->next) {
+ item_prev = item_prev->next;
+ }
+
+ if (item_prev) {
+ item_prev->next = p_item;
+ p_item->prev = item_prev;
+ } else {
+ first_child = p_item;
+ }
+
+ if (!children_cache.is_empty()) {
+ children_cache.append(p_item);
+ }
+
+ validate_cache();
+}
+
+void TreeItem::remove_child(TreeItem *p_item) {
+ ERR_FAIL_NULL(p_item);
+ ERR_FAIL_COND(p_item->parent != this);
+
+ p_item->_unlink_from_tree();
+ p_item->_change_tree(nullptr);
+ p_item->prev = nullptr;
+ p_item->next = nullptr;
+ p_item->parent = nullptr;
+
+ validate_cache();
+}
+
Tree *TreeItem::get_tree() const {
return tree;
}
@@ -888,6 +931,18 @@ TypedArray<TreeItem> TreeItem::get_children() {
return arr;
}
+void TreeItem::clear_children() {
+ TreeItem *c = first_child;
+ while (c) {
+ TreeItem *aux = c;
+ c = c->get_next();
+ aux->parent = nullptr; // So it won't try to recursively auto-remove from me in here.
+ memdelete(aux);
+ }
+
+ first_child = nullptr;
+};
+
int TreeItem::get_index() {
int idx = 0;
TreeItem *c = this;
@@ -943,7 +998,7 @@ void TreeItem::move_before(TreeItem *p_item) {
} else {
parent->first_child = this;
// If the cache is empty, it has not been built but there
- // are items in the tree (note p_item != nullptr,) so we cannot update it.
+ // are items in the tree (note p_item != nullptr) so we cannot update it.
if (!parent->children_cache.is_empty()) {
parent->children_cache.insert(0, this);
}
@@ -1003,21 +1058,6 @@ void TreeItem::move_after(TreeItem *p_item) {
validate_cache();
}
-void TreeItem::remove_child(TreeItem *p_item) {
- ERR_FAIL_NULL(p_item);
- ERR_FAIL_COND(p_item->parent != this);
-
- p_item->_unlink_from_tree();
- p_item->prev = nullptr;
- p_item->next = nullptr;
- p_item->parent = nullptr;
-
- if (tree) {
- tree->queue_redraw();
- }
- validate_cache();
-}
-
void TreeItem::set_selectable(int p_column, bool p_selectable) {
ERR_FAIL_INDEX(p_column, cells.size());
cells.write[p_column].selectable = p_selectable;
@@ -1542,6 +1582,9 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_folding_disabled"), &TreeItem::is_folding_disabled);
ClassDB::bind_method(D_METHOD("create_child", "index"), &TreeItem::create_child, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("add_child", "child"), &TreeItem::add_child);
+ ClassDB::bind_method(D_METHOD("remove_child", "child"), &TreeItem::remove_child);
+
ClassDB::bind_method(D_METHOD("get_tree"), &TreeItem::get_tree);
ClassDB::bind_method(D_METHOD("get_next"), &TreeItem::get_next);
@@ -1563,8 +1606,6 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("move_before", "item"), &TreeItem::move_before);
ClassDB::bind_method(D_METHOD("move_after", "item"), &TreeItem::move_after);
- ClassDB::bind_method(D_METHOD("remove_child", "child"), &TreeItem::remove_child);
-
{
MethodInfo mi;
mi.name = "call_recursive";
@@ -1585,28 +1626,17 @@ void TreeItem::_bind_methods() {
BIND_ENUM_CONSTANT(CELL_MODE_CUSTOM);
}
-void TreeItem::clear_children() {
- TreeItem *c = first_child;
- while (c) {
- TreeItem *aux = c;
- c = c->get_next();
- aux->parent = nullptr; // so it won't try to recursively autoremove from me in here
- memdelete(aux);
- }
-
- first_child = nullptr;
-};
-
TreeItem::TreeItem(Tree *p_tree) {
tree = p_tree;
}
TreeItem::~TreeItem() {
_unlink_from_tree();
+ _change_tree(nullptr);
+
validate_cache();
prev = nullptr;
clear_children();
- _change_tree(nullptr);
}
/**********************************************/
@@ -4484,6 +4514,7 @@ bool Tree::is_column_expanding(int p_column) const {
return columns[p_column].expand;
}
+
int Tree::get_column_expand_ratio(int p_column) const {
ERR_FAIL_INDEX_V(p_column, columns.size(), 1);
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index 24b649b040..a5122bb1a7 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -336,6 +336,8 @@ public:
/* Item manipulation */
TreeItem *create_child(int p_index = -1);
+ void add_child(TreeItem *p_item);
+ void remove_child(TreeItem *p_item);
Tree *get_tree() const;
@@ -354,6 +356,7 @@ public:
int get_visible_child_count();
int get_child_count();
TypedArray<TreeItem> get_children();
+ void clear_children();
int get_index();
#ifdef DEV_ENABLED
@@ -366,12 +369,8 @@ public:
void move_before(TreeItem *p_item);
void move_after(TreeItem *p_item);
- void remove_child(TreeItem *p_item);
-
void call_recursive(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- void clear_children();
-
~TreeItem();
};