Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement TreeItem.add_child #77446

Merged
merged 1 commit into from
May 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 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,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].
YuriSizov marked this conversation as resolved.
Show resolved Hide resolved
[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">
Expand Down
117 changes: 74 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,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);
YuriSizov marked this conversation as resolved.
Show resolved Hide resolved
p_item->prev = nullptr;
p_item->next = nullptr;
p_item->parent = nullptr;

validate_cache();
}

Tree *TreeItem::get_tree() const {
return tree;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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";
Expand All @@ -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);
YuriSizov marked this conversation as resolved.
Show resolved Hide resolved

validate_cache();
prev = nullptr;
clear_children();
_change_tree(nullptr);
}

/**********************************************/
Expand Down Expand Up @@ -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);

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