Allow TreeItem nodes to toggle visibility

This commit is contained in:
monkeyman192 2022-04-03 18:37:08 +10:00
parent dc8c906b64
commit 31381f8c9e
3 changed files with 90 additions and 8 deletions

View File

@ -687,6 +687,10 @@
<member name="disable_folding" type="bool" setter="set_disable_folding" getter="is_folding_disabled">
If [code]true[/code], folding is disabled for this TreeItem.
</member>
<member name="visible" type="bool" setter="set_visible" getter="is_visible">
If [code]true[/code], the [TreeItem] is visible (default).
Note that if a [TreeItem] is set to not be visible, none of its children will be visible either.
</member>
</members>
<constants>
<constant name="CELL_MODE_STRING" value="0" enum="TreeCellMode">

View File

@ -544,6 +544,21 @@ bool TreeItem::is_collapsed() {
return collapsed;
}
void TreeItem::set_visible(bool p_visible) {
if (visible == p_visible) {
return;
}
visible = p_visible;
if (tree) {
tree->update();
_changed_notify();
}
}
bool TreeItem::is_visible() {
return visible;
}
void TreeItem::uncollapse_tree() {
TreeItem *t = this;
while (t) {
@ -646,7 +661,7 @@ TreeItem *TreeItem::get_first_child() const {
return first_child;
}
TreeItem *TreeItem::get_prev_visible(bool p_wrap) {
TreeItem *TreeItem::_get_prev_visible(bool p_wrap) {
TreeItem *current = this;
TreeItem *prev = current->get_prev();
@ -682,7 +697,21 @@ TreeItem *TreeItem::get_prev_visible(bool p_wrap) {
return current;
}
TreeItem *TreeItem::get_next_visible(bool p_wrap) {
TreeItem *TreeItem::get_prev_visible(bool p_wrap) {
TreeItem *loop = this;
TreeItem *prev = this->_get_prev_visible(p_wrap);
while (prev && !prev->is_visible()) {
prev = prev->_get_prev_visible(p_wrap);
if (prev == loop) {
// Check that we haven't looped all the way around to the start.
prev = nullptr;
break;
}
}
return prev;
}
TreeItem *TreeItem::_get_next_visible(bool p_wrap) {
TreeItem *current = this;
if (!current->collapsed && current->first_child) {
@ -709,12 +738,37 @@ TreeItem *TreeItem::get_next_visible(bool p_wrap) {
return current;
}
TreeItem *TreeItem::get_next_visible(bool p_wrap) {
TreeItem *loop = this;
TreeItem *next = this->_get_next_visible(p_wrap);
while (next && !next->is_visible()) {
next = next->_get_next_visible(p_wrap);
if (next == loop) {
// Check that we haven't looped all the way around to the start.
next = nullptr;
break;
}
}
return next;
}
TreeItem *TreeItem::get_child(int p_idx) {
_create_children_cache();
ERR_FAIL_INDEX_V(p_idx, children_cache.size(), nullptr);
return children_cache.get(p_idx);
}
int TreeItem::get_visible_child_count() {
_create_children_cache();
int visible_count = 0;
for (int i = 0; i < children_cache.size(); i++) {
if (children_cache[i]->is_visible()) {
visible_count += 1;
}
}
return visible_count;
}
int TreeItem::get_child_count() {
_create_children_cache();
return children_cache.size();
@ -1256,6 +1310,9 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collapsed", "enable"), &TreeItem::set_collapsed);
ClassDB::bind_method(D_METHOD("is_collapsed"), &TreeItem::is_collapsed);
ClassDB::bind_method(D_METHOD("set_visible", "enable"), &TreeItem::set_visible);
ClassDB::bind_method(D_METHOD("is_visible"), &TreeItem::is_visible);
ClassDB::bind_method(D_METHOD("uncollapse_tree"), &TreeItem::uncollapse_tree);
ClassDB::bind_method(D_METHOD("set_custom_minimum_height", "height"), &TreeItem::set_custom_minimum_height);
@ -1340,6 +1397,7 @@ void TreeItem::_bind_methods() {
}
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collapsed"), "set_collapsed", "is_collapsed");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_folding"), "set_disable_folding", "is_folding_disabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "custom_minimum_height", PROPERTY_HINT_RANGE, "0,1000,1"), "set_custom_minimum_height", "get_custom_minimum_height");
@ -1445,7 +1503,7 @@ void Tree::update_cache() {
}
int Tree::compute_item_height(TreeItem *p_item) const {
if (p_item == root && hide_root) {
if ((p_item == root && hide_root) || !p_item->is_visible()) {
return 0;
}
@ -1506,6 +1564,9 @@ int Tree::compute_item_height(TreeItem *p_item) const {
}
int Tree::get_item_height(TreeItem *p_item) const {
if (!p_item->is_visible()) {
return 0;
}
int height = compute_item_height(p_item);
height += cache.vseparation;
@ -1686,6 +1747,10 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
return -1; //draw no more!
}
if (!p_item->is_visible()) {
return 0;
}
RID ci = get_canvas_item();
int htotal = 0;
@ -2056,7 +2121,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
}
}
if (!p_item->disable_folding && !hide_folding && p_item->first_child) { //has children, draw the guide box
if (!p_item->disable_folding && !hide_folding && p_item->first_child && p_item->get_visible_child_count() != 0) { //has visible children, draw the guide box
Ref<Texture2D> arrow;
@ -2382,6 +2447,11 @@ void Tree::_range_click_timeout() {
}
int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int x_limit, bool p_double_click, TreeItem *p_item, MouseButton p_button, const Ref<InputEventWithModifiers> &p_mod) {
if (p_item && !p_item->is_visible()) {
// Skip any processing of invisible items.
return 0;
}
int item_h = compute_item_height(p_item) + cache.vseparation;
bool skip = (p_item == root && hide_root);
@ -4147,7 +4217,7 @@ int Tree::get_column_minimum_width(int p_column) const {
depth += 1;
} else {
TreeItem *common_parent = item->get_parent();
while (common_parent != next->get_parent()) {
while (common_parent != next->get_parent() && common_parent) {
common_parent = common_parent->get_parent();
depth -= 1;
}
@ -4464,7 +4534,7 @@ Point2 Tree::get_scroll() const {
}
void Tree::scroll_to_item(TreeItem *p_item, bool p_center_on_item) {
if (!is_visible_in_tree()) {
if (!is_visible_in_tree() || !p_item->is_visible()) {
return; // Hack to work around crash in get_item_rect() if Tree is not in tree.
}
@ -4588,7 +4658,7 @@ void Tree::_do_incr_search(const String &p_add) {
TreeItem *Tree::_find_item_at_pos(TreeItem *p_item, const Point2 &p_pos, int &r_column, int &h, int &section) const {
Point2 pos = p_pos;
if (root != p_item || !hide_root) {
if ((root != p_item || !hide_root) && p_item->is_visible()) {
h = compute_item_height(p_item) + cache.vseparation;
if (pos.y < h) {
if (drop_mode_flags == DROP_MODE_ON_ITEM) {
@ -4621,7 +4691,7 @@ TreeItem *Tree::_find_item_at_pos(TreeItem *p_item, const Point2 &p_pos, int &r_
h = 0;
}
if (p_item->is_collapsed()) {
if (p_item->is_collapsed() || !p_item->is_visible()) {
return nullptr; // do not try children, it's collapsed
}

View File

@ -124,6 +124,7 @@ private:
Vector<Cell> cells;
bool collapsed = false; // won't show children
bool visible = true;
bool disable_folding = false;
int custom_min_height = 0;
@ -209,6 +210,9 @@ private:
void _propagate_check_through_children(int p_column, bool p_checked, bool p_emit_signal);
void _propagate_check_through_parents(int p_column, bool p_emit_signal);
TreeItem *_get_prev_visible(bool p_wrap = false);
TreeItem *_get_next_visible(bool p_wrap = false);
public:
void set_text(int p_column, String p_text);
String get_text(int p_column) const;
@ -273,6 +277,9 @@ public:
void set_collapsed(bool p_collapsed);
bool is_collapsed();
void set_visible(bool p_visible);
bool is_visible();
void uncollapse_tree();
void set_custom_minimum_height(int p_height);
@ -335,6 +342,7 @@ public:
TreeItem *get_next_visible(bool p_wrap = false);
TreeItem *get_child(int p_idx);
int get_visible_child_count();
int get_child_count();
Array get_children();
int get_index();