summaryrefslogtreecommitdiff
path: root/scene/gui
diff options
context:
space:
mode:
authorderammo <817160+derammo@users.noreply.github.com>2022-08-03 18:08:16 -0400
committerderammo <817160+derammo@users.noreply.github.com>2022-08-04 08:24:51 -0400
commit4e6c8e00fcd5d7812047a807bea6bf38b9e0b159 (patch)
treea0adcbc570d5ce46e996cdd438f2357fc69344c3 /scene/gui
parentea4b8de2b4c06e6f18bf0470d716f787bddfecc3 (diff)
fixed Tree UI control bug corrupting child cache
Diffstat (limited to 'scene/gui')
-rw-r--r--scene/gui/tree.cpp34
-rw-r--r--scene/gui/tree.h7
2 files changed, 39 insertions, 2 deletions
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 1eb6c5a554..ede7bfb0bf 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -749,6 +749,7 @@ int TreeItem::get_child_count() {
}
Array TreeItem::get_children() {
+ // Don't need to explicitly create children cache, because get_child_count creates it.
int size = get_child_count();
Array arr;
arr.resize(size);
@@ -770,6 +771,22 @@ int TreeItem::get_index() {
return idx - 1;
}
+#ifdef DEV_ENABLED
+void TreeItem::validate_cache() const {
+ if (!parent || parent->children_cache.is_empty()) {
+ return;
+ }
+ TreeItem *scan = parent->first_child;
+ int index = 0;
+ while (scan) {
+ DEV_ASSERT(parent->children_cache[index] == scan);
+ ++index;
+ scan = scan->get_next();
+ }
+ DEV_ASSERT(index == parent->children_cache.size());
+}
+#endif
+
void TreeItem::move_before(TreeItem *p_item) {
ERR_FAIL_NULL(p_item);
ERR_FAIL_COND(is_root);
@@ -797,7 +814,11 @@ void TreeItem::move_before(TreeItem *p_item) {
parent->children_cache.clear();
} else {
parent->first_child = this;
- parent->children_cache.insert(0, 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.
+ if (!parent->children_cache.is_empty()) {
+ parent->children_cache.insert(0, this);
+ }
}
prev = item_prev;
@@ -807,6 +828,8 @@ void TreeItem::move_before(TreeItem *p_item) {
if (tree && old_tree == tree) {
tree->update();
}
+
+ validate_cache();
}
void TreeItem::move_after(TreeItem *p_item) {
@@ -839,12 +862,17 @@ void TreeItem::move_after(TreeItem *p_item) {
if (next) {
parent->children_cache.clear();
} else {
- parent->children_cache.append(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.
+ if (!parent->children_cache.is_empty()) {
+ parent->children_cache.append(this);
+ }
}
if (tree && old_tree == tree) {
tree->update();
}
+ validate_cache();
}
void TreeItem::remove_child(TreeItem *p_item) {
@@ -859,6 +887,7 @@ void TreeItem::remove_child(TreeItem *p_item) {
if (tree) {
tree->update();
}
+ validate_cache();
}
void TreeItem::set_selectable(int p_column, bool p_selectable) {
@@ -1396,6 +1425,7 @@ TreeItem::TreeItem(Tree *p_tree) {
TreeItem::~TreeItem() {
_unlink_from_tree();
+ validate_cache();
prev = nullptr;
clear_children();
_change_tree(nullptr);
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index f0819e2980..bcc2419b80 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -342,6 +342,13 @@ public:
Array get_children();
int get_index();
+#ifdef DEV_ENABLED
+ // This debugging code can be removed once the current refactoring of this class is complete.
+ void validate_cache() const;
+#else
+ void validate_cache() const {}
+#endif
+
void move_before(TreeItem *p_item);
void move_after(TreeItem *p_item);