Browse Source

Merge pull request #88300 from FaycalElOuariachi/add-TreeItem-is_visible_in_tree

Add `is_visible_in_tree` in `TreeItem`
Rémi Verschelde 1 year ago
parent
commit
c84d3385f7
3 changed files with 44 additions and 11 deletions
  1. 6 0
      doc/classes/TreeItem.xml
  2. 34 11
      scene/gui/tree.cpp
  3. 4 0
      scene/gui/tree.h

+ 6 - 0
doc/classes/TreeItem.xml

@@ -438,6 +438,12 @@
 				Returns [code]true[/code] if the given [param column] is selected.
 			</description>
 		</method>
+		<method name="is_visible_in_tree" qualifiers="const">
+			<return type="bool" />
+			<description>
+				Returns [code]true[/code] if [member visible] is [code]true[/code] and all its ancestors are also visible.
+			</description>
+		</method>
 		<method name="move_after">
 			<return type="void" />
 			<param index="0" name="item" type="TreeItem" />

+ 34 - 11
scene/gui/tree.cpp

@@ -691,7 +691,7 @@ bool TreeItem::_is_any_collapsed(bool p_only_visible) {
 }
 
 bool TreeItem::is_any_collapsed(bool p_only_visible) {
-	if (p_only_visible && !is_visible()) {
+	if (p_only_visible && !is_visible_in_tree()) {
 		return false;
 	}
 
@@ -712,12 +712,31 @@ void TreeItem::set_visible(bool p_visible) {
 		tree->queue_redraw();
 		_changed_notify();
 	}
+
+	_handle_visibility_changed(p_visible);
 }
 
 bool TreeItem::is_visible() {
 	return visible;
 }
 
+bool TreeItem::is_visible_in_tree() const {
+	return visible && parent_visible_in_tree;
+}
+
+void TreeItem::_handle_visibility_changed(bool p_visible) {
+	TreeItem *child = get_first_child();
+	while (child) {
+		child->_propagate_visibility_changed(p_visible);
+		child = child->get_next();
+	}
+}
+
+void TreeItem::_propagate_visibility_changed(bool p_parent_visible_in_tree) {
+	parent_visible_in_tree = p_parent_visible_in_tree;
+	_handle_visibility_changed(p_parent_visible_in_tree);
+}
+
 void TreeItem::uncollapse_tree() {
 	TreeItem *t = this;
 	while (t) {
@@ -788,6 +807,7 @@ TreeItem *TreeItem::create_child(int p_index) {
 	}
 
 	ti->parent = this;
+	ti->parent_visible_in_tree = is_visible_in_tree();
 
 	return ti;
 }
@@ -799,6 +819,8 @@ void TreeItem::add_child(TreeItem *p_item) {
 
 	p_item->_change_tree(tree);
 	p_item->parent = this;
+	p_item->parent_visible_in_tree = is_visible_in_tree();
+	p_item->_handle_visibility_changed(p_item->parent_visible_in_tree);
 
 	TreeItem *item_prev = first_child;
 	while (item_prev && item_prev->next) {
@@ -906,7 +928,7 @@ TreeItem *TreeItem::_get_prev_in_tree(bool p_wrap, bool p_include_invisible) {
 TreeItem *TreeItem::get_prev_visible(bool p_wrap) {
 	TreeItem *loop = this;
 	TreeItem *prev_item = _get_prev_in_tree(p_wrap);
-	while (prev_item && !prev_item->is_visible()) {
+	while (prev_item && !prev_item->is_visible_in_tree()) {
 		prev_item = prev_item->_get_prev_in_tree(p_wrap);
 		if (prev_item == loop) {
 			// Check that we haven't looped all the way around to the start.
@@ -947,7 +969,7 @@ TreeItem *TreeItem::_get_next_in_tree(bool p_wrap, bool p_include_invisible) {
 TreeItem *TreeItem::get_next_visible(bool p_wrap) {
 	TreeItem *loop = this;
 	TreeItem *next_item = _get_next_in_tree(p_wrap);
-	while (next_item && !next_item->is_visible()) {
+	while (next_item && !next_item->is_visible_in_tree()) {
 		next_item = next_item->_get_next_in_tree(p_wrap);
 		if (next_item == loop) {
 			// Check that we haven't looped all the way around to the start.
@@ -1641,6 +1663,7 @@ void TreeItem::_bind_methods() {
 
 	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("is_visible_in_tree"), &TreeItem::is_visible_in_tree);
 
 	ClassDB::bind_method(D_METHOD("uncollapse_tree"), &TreeItem::uncollapse_tree);
 
@@ -1790,7 +1813,7 @@ Size2 Tree::_get_cell_icon_size(const TreeItem::Cell &p_cell) const {
 }
 
 int Tree::compute_item_height(TreeItem *p_item) const {
-	if ((p_item == root && hide_root) || !p_item->is_visible()) {
+	if ((p_item == root && hide_root) || !p_item->is_visible_in_tree()) {
 		return 0;
 	}
 
@@ -1848,7 +1871,7 @@ int Tree::compute_item_height(TreeItem *p_item) const {
 }
 
 int Tree::get_item_height(TreeItem *p_item) const {
-	if (!p_item->is_visible()) {
+	if (!p_item->is_visible_in_tree()) {
 		return 0;
 	}
 	int height = compute_item_height(p_item);
@@ -2050,7 +2073,7 @@ 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()) {
+	if (!p_item->is_visible_in_tree()) {
 		return 0;
 	}
 
@@ -2507,7 +2530,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
 			}
 
 			// Draw relationship lines.
-			if (theme_cache.draw_relationship_lines > 0 && (!hide_root || c->parent != root) && c->is_visible()) {
+			if (theme_cache.draw_relationship_lines > 0 && (!hide_root || c->parent != root) && c->is_visible_in_tree()) {
 				int root_ofs = children_pos.x + ((p_item->disable_folding || hide_folding) ? theme_cache.h_separation : theme_cache.item_margin);
 				int parent_ofs = p_pos.x + theme_cache.item_margin;
 				Point2i root_pos = Point2i(root_ofs, children_pos.y + child_self_height / 2) - theme_cache.offset + p_draw_ofs;
@@ -2788,7 +2811,7 @@ 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()) {
+	if (p_item && !p_item->is_visible_in_tree()) {
 		// Skip any processing of invisible items.
 		return 0;
 	}
@@ -4797,7 +4820,7 @@ int Tree::get_item_offset(TreeItem *p_item) const {
 			return ofs;
 		}
 
-		if ((it != root || !hide_root) && it->is_visible()) {
+		if ((it != root || !hide_root) && it->is_visible_in_tree()) {
 			ofs += compute_item_height(it);
 			ofs += theme_cache.v_separation;
 		}
@@ -5171,7 +5194,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) && p_item->is_visible()) {
+	if ((root != p_item || !hide_root) && p_item->is_visible_in_tree()) {
 		h = compute_item_height(p_item) + theme_cache.v_separation;
 		if (pos.y < h) {
 			if (drop_mode_flags == DROP_MODE_ON_ITEM) {
@@ -5204,7 +5227,7 @@ TreeItem *Tree::_find_item_at_pos(TreeItem *p_item, const Point2 &p_pos, int &r_
 		h = 0;
 	}
 
-	if (p_item->is_collapsed() || !p_item->is_visible()) {
+	if (p_item->is_collapsed() || !p_item->is_visible_in_tree()) {
 		return nullptr; // do not try children, it's collapsed
 	}
 

+ 4 - 0
scene/gui/tree.h

@@ -129,6 +129,7 @@ private:
 
 	bool collapsed = false; // won't show children
 	bool visible = true;
+	bool parent_visible_in_tree = true;
 	bool disable_folding = false;
 	int custom_min_height = 0;
 
@@ -147,6 +148,8 @@ private:
 	void _changed_notify();
 	void _cell_selected(int p_cell);
 	void _cell_deselected(int p_cell);
+	void _handle_visibility_changed(bool p_visible);
+	void _propagate_visibility_changed(bool p_parent_visible_in_tree);
 
 	void _change_tree(Tree *p_tree);
 
@@ -300,6 +303,7 @@ public:
 
 	void set_visible(bool p_visible);
 	bool is_visible();
+	bool is_visible_in_tree() const;
 
 	void uncollapse_tree();