Browse Source

Merge pull request #58870 from timothyqiu/canvas-item-visibility-3.x

Rémi Verschelde 3 years ago
parent
commit
927dd95b27
3 changed files with 44 additions and 43 deletions
  1. 38 30
      scene/2d/canvas_item.cpp
  2. 2 2
      scene/2d/canvas_item.h
  3. 4 11
      scene/main/canvas_layer.cpp

+ 38 - 30
scene/2d/canvas_item.cpp

@@ -350,21 +350,45 @@ Transform2D CanvasItem::_edit_get_transform() const {
 #endif
 
 bool CanvasItem::is_visible_in_tree() const {
-	return visible && parent_visible_in_tree;
+	if (!is_inside_tree()) {
+		return false;
+	}
+
+	const CanvasItem *p = this;
+
+	while (p) {
+		if (!p->visible) {
+			return false;
+		}
+		p = p->get_parent_item();
+	}
+
+	if (canvas_layer) {
+		return canvas_layer->is_visible();
+	}
+
+	return true;
 }
 
-void CanvasItem::_propagate_visibility_changed(bool p_visible, bool p_is_source) {
+void CanvasItem::_toplevel_visibility_changed(bool p_visible) {
+	VisualServer::get_singleton()->canvas_item_set_visible(canvas_item, visible && p_visible);
+
+	if (visible) {
+		_propagate_visibility_changed(p_visible);
+	} else {
+		notification(NOTIFICATION_VISIBILITY_CHANGED);
+	}
+}
+
+void CanvasItem::_propagate_visibility_changed(bool p_visible) {
 	if (p_visible && first_draw) { //avoid propagating it twice
 		first_draw = false;
 	}
-	if (!p_is_source) {
-		parent_visible_in_tree = p_visible;
-	}
 	notification(NOTIFICATION_VISIBILITY_CHANGED);
 
-	if (visible && p_visible) {
-		update();
-	} else if (!p_visible && (visible || p_is_source)) {
+	if (p_visible) {
+		update(); // Todo optimize.
+	} else {
 		emit_signal(SceneStringNames::get_singleton()->hide);
 	}
 	_block();
@@ -372,12 +396,8 @@ void CanvasItem::_propagate_visibility_changed(bool p_visible, bool p_is_source)
 	for (int i = 0; i < get_child_count(); i++) {
 		CanvasItem *c = Object::cast_to<CanvasItem>(get_child(i));
 
-		if (c) { // Should the top_levels stop propagation? I think so, but...
-			if (c->visible) {
-				c->_propagate_visibility_changed(p_visible);
-			} else {
-				c->parent_visible_in_tree = p_visible;
-			}
+		if (c && c->visible && !c->toplevel) {
+			c->_propagate_visibility_changed(p_visible);
 		}
 	}
 
@@ -392,14 +412,11 @@ void CanvasItem::set_visible(bool p_visible) {
 	visible = p_visible;
 	VisualServer::get_singleton()->canvas_item_set_visible(canvas_item, p_visible);
 
-	if (!parent_visible_in_tree) {
-		if (is_inside_tree()) {
-			notification(NOTIFICATION_VISIBILITY_CHANGED);
-		}
+	if (!is_inside_tree()) {
 		return;
 	}
 
-	_propagate_visibility_changed(p_visible, true);
+	_propagate_visibility_changed(p_visible);
 	_change_notify("visible");
 }
 
@@ -428,7 +445,7 @@ void CanvasItem::_update_callback() {
 
 	VisualServer::get_singleton()->canvas_item_clear(get_canvas_item());
 	//todo updating = true - only allow drawing here
-	if (is_visible_in_tree()) {
+	if (is_visible_in_tree()) { // Todo optimize this!!
 		if (first_draw) {
 			notification(NOTIFICATION_VISIBILITY_CHANGED);
 			first_draw = false;
@@ -554,15 +571,7 @@ void CanvasItem::_notification(int p_what) {
 			if (parent) {
 				CanvasItem *ci = Object::cast_to<CanvasItem>(parent);
 				if (ci) {
-					parent_visible_in_tree = ci->is_visible_in_tree();
 					C = ci->children_items.push_back(this);
-				} else {
-					CanvasLayer *cl = Object::cast_to<CanvasLayer>(parent);
-					if (cl) {
-						parent_visible_in_tree = cl->is_visible();
-					} else {
-						parent_visible_in_tree = true;
-					}
 				}
 			}
 			_enter_canvas();
@@ -594,7 +603,6 @@ void CanvasItem::_notification(int p_what) {
 				C = nullptr;
 			}
 			global_invalid = true;
-			parent_visible_in_tree = false;
 		} break;
 		case NOTIFICATION_DRAW:
 		case NOTIFICATION_TRANSFORM_CHANGED: {
@@ -1059,6 +1067,7 @@ void CanvasItem::force_update_transform() {
 }
 
 void CanvasItem::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("_toplevel_visibility_changed", "visible"), &CanvasItem::_toplevel_visibility_changed);
 	ClassDB::bind_method(D_METHOD("_toplevel_raise_self"), &CanvasItem::_toplevel_raise_self);
 	ClassDB::bind_method(D_METHOD("_update_callback"), &CanvasItem::_update_callback);
 
@@ -1260,7 +1269,6 @@ CanvasItem::CanvasItem() :
 		xform_change(this) {
 	canvas_item = RID_PRIME(VisualServer::get_singleton()->canvas_item_create());
 	visible = true;
-	parent_visible_in_tree = false;
 	pending_update = false;
 	modulate = Color(1, 1, 1, 1);
 	self_modulate = Color(1, 1, 1, 1);

+ 2 - 2
scene/2d/canvas_item.h

@@ -193,7 +193,6 @@ private:
 
 	bool first_draw;
 	bool visible;
-	bool parent_visible_in_tree;
 	bool pending_update;
 	bool toplevel;
 	bool drawing;
@@ -209,8 +208,9 @@ private:
 	mutable bool global_invalid;
 
 	void _toplevel_raise_self();
+	void _toplevel_visibility_changed(bool p_visible);
 
-	void _propagate_visibility_changed(bool p_visible, bool p_is_source = false);
+	void _propagate_visibility_changed(bool p_visible);
 
 	void _update_callback();
 

+ 4 - 11
scene/main/canvas_layer.cpp

@@ -51,17 +51,10 @@ void CanvasLayer::set_visible(bool p_visible) {
 	visible = p_visible;
 	emit_signal("visibility_changed");
 
-	for (int i = 0; i < get_child_count(); i++) {
-		CanvasItem *c = Object::cast_to<CanvasItem>(get_child(i));
-		if (c) {
-			VisualServer::get_singleton()->canvas_item_set_visible(c->get_canvas_item(), p_visible && c->is_visible());
-
-			if (c->is_visible()) {
-				c->_propagate_visibility_changed(p_visible);
-			} else {
-				c->parent_visible_in_tree = p_visible;
-			}
-		}
+	// For CanvasItems that is explicitly top level or has non-CanvasItem parents.
+	if (is_inside_tree()) {
+		const String group = "root_canvas" + itos(canvas.get_id());
+		get_tree()->call_group_flags(SceneTree::GROUP_CALL_UNIQUE, group, "_toplevel_visibility_changed", p_visible);
 	}
 }