Skip to content

Commit

Permalink
Implement TreeItem.add_child
Browse files Browse the repository at this point in the history
  • Loading branch information
YuriSizov committed May 24, 2023
1 parent 4c677c8 commit 5a44395
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 48 deletions.
9 changes: 8 additions & 1 deletion doc/classes/TreeItem.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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" />
Expand Down Expand Up @@ -430,7 +437,7 @@
<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].
</description>
</method>
<method name="select">
Expand Down
123 changes: 80 additions & 43 deletions scene/gui/tree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -713,6 +716,52 @@ 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);
}

if (tree) {
tree->queue_redraw();
}
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;

if (tree) {
tree->queue_redraw();
}
validate_cache();
}

Tree *TreeItem::get_tree() const {
return tree;
}
Expand Down Expand Up @@ -888,6 +937,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 autoremove from me in here
memdelete(aux);
}

first_child = nullptr;
};

int TreeItem::get_index() {
int idx = 0;
TreeItem *c = this;
Expand Down Expand Up @@ -943,7 +1004,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);
}
Expand Down Expand Up @@ -1003,21 +1064,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;
Expand Down Expand Up @@ -1542,6 +1588,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);
Expand All @@ -1563,8 +1612,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";
Expand All @@ -1585,28 +1632,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);
}

/**********************************************/
Expand Down Expand Up @@ -4484,6 +4520,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);

Expand Down
7 changes: 3 additions & 4 deletions scene/gui/tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,8 @@ class TreeItem : public Object {
/* 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;

Expand All @@ -354,6 +356,7 @@ class TreeItem : public Object {
int get_visible_child_count();
int get_child_count();
TypedArray<TreeItem> get_children();
void clear_children();
int get_index();

#ifdef DEV_ENABLED
Expand All @@ -366,12 +369,8 @@ class TreeItem : public Object {
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();
};

Expand Down

0 comments on commit 5a44395

Please sign in to comment.