Browse Source

Backport CanvasLayer visibility

Haoyu Qiu 3 years ago
parent
commit
f49ffe4bb0

+ 11 - 0
doc/classes/CanvasLayer.xml

@@ -47,7 +47,18 @@
 		<member name="transform" type="Transform2D" setter="set_transform" getter="get_transform" default="Transform2D( 1, 0, 0, 1, 0, 0 )">
 			The layer's transform.
 		</member>
+		<member name="visible" type="bool" setter="set_visible" getter="is_visible" default="true">
+			If [code]false[/code], any [CanvasItem] under this [CanvasLayer] will be hidden.
+			Unlike [member CanvasItem.visible], visibility of a [CanvasLayer] isn't propagated to underlying layers.
+		</member>
 	</members>
+	<signals>
+		<signal name="visibility_changed">
+			<description>
+				Emitted when visibility of the layer is changed. See [member visible].
+			</description>
+		</signal>
+	</signals>
 	<constants>
 	</constants>
 </class>

+ 15 - 1
editor/scene_tree_editor.cpp

@@ -361,6 +361,17 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent, bool p_scroll
 			}
 
 			_update_visibility_color(p_node, item);
+		} else if (p_node->is_class("CanvasLayer")) {
+			bool v = p_node->call("is_visible");
+			if (v) {
+				item->add_button(0, get_icon("GuiVisibilityVisible", "EditorIcons"), BUTTON_VISIBILITY, false, TTR("Toggle Visibility"));
+			} else {
+				item->add_button(0, get_icon("GuiVisibilityHidden", "EditorIcons"), BUTTON_VISIBILITY, false, TTR("Toggle Visibility"));
+			}
+
+			if (!p_node->is_connected("visibility_changed", this, "_node_visibility_changed")) {
+				p_node->connect("visibility_changed", this, "_node_visibility_changed", varray(p_node));
+			}
 		} else if (p_node->is_class("Spatial")) {
 			bool is_locked = p_node->has_meta("_edit_lock_");
 			if (is_locked) {
@@ -470,6 +481,9 @@ void SceneTreeEditor::_node_visibility_changed(Node *p_node) {
 	if (p_node->is_class("CanvasItem")) {
 		visible = p_node->call("is_visible");
 		CanvasItemEditor::get_singleton()->get_viewport_control()->update();
+	} else if (p_node->is_class("CanvasLayer")) {
+		visible = p_node->call("is_visible");
+		CanvasItemEditor::get_singleton()->get_viewport_control()->update();
 	} else if (p_node->is_class("Spatial")) {
 		visible = p_node->call("is_visible");
 	}
@@ -528,7 +542,7 @@ void SceneTreeEditor::_node_removed(Node *p_node) {
 		p_node->disconnect("script_changed", this, "_node_script_changed");
 	}
 
-	if (p_node->is_class("Spatial") || p_node->is_class("CanvasItem")) {
+	if (p_node->is_class("Spatial") || p_node->is_class("CanvasItem") || p_node->is_class("CanvasLayer")) {
 		if (p_node->is_connected("visibility_changed", this, "_node_visibility_changed")) {
 			p_node->disconnect("visibility_changed", this, "_node_visibility_changed");
 		}

+ 35 - 50
scene/2d/canvas_item.cpp

@@ -350,31 +350,19 @@ Transform2D CanvasItem::_edit_get_transform() const {
 #endif
 
 bool CanvasItem::is_visible_in_tree() const {
-	if (!is_inside_tree()) {
-		return false;
-	}
-
-	const CanvasItem *p = this;
-
-	while (p) {
-		if (!p->visible) {
-			return false;
-		}
-		p = p->get_parent_item();
-	}
-
-	return true;
+	return visible && parent_visible_in_tree;
 }
 
-void CanvasItem::_propagate_visibility_changed(bool p_visible) {
+void CanvasItem::_propagate_visibility_changed(bool p_visible, bool p_was_visible) {
 	if (p_visible && first_draw) { //avoid propagating it twice
 		first_draw = false;
 	}
+	parent_visible_in_tree = p_visible;
 	notification(NOTIFICATION_VISIBILITY_CHANGED);
 
-	if (p_visible) {
-		update(); //todo optimize
-	} else {
+	if (visible && p_visible) {
+		update();
+	} else if (!p_visible && (visible || p_was_visible)) {
 		emit_signal(SceneStringNames::get_singleton()->hide);
 	}
 	_block();
@@ -383,43 +371,39 @@ void CanvasItem::_propagate_visibility_changed(bool p_visible) {
 		CanvasItem *c = Object::cast_to<CanvasItem>(get_child(i));
 
 		if (c && c->visible) { //should the toplevels stop propagation? i think so but..
-			c->_propagate_visibility_changed(p_visible);
+			c->_propagate_visibility_changed(p_visible, !p_visible);
 		}
 	}
 
 	_unblock();
 }
 
-void CanvasItem::show() {
-	if (visible) {
+void CanvasItem::set_visible(bool p_visible) {
+	if (visible == p_visible) {
 		return;
 	}
 
-	visible = true;
-	VisualServer::get_singleton()->canvas_item_set_visible(canvas_item, true);
+	visible = p_visible;
+	VisualServer::get_singleton()->canvas_item_set_visible(canvas_item, p_visible);
 
 	if (!is_inside_tree()) {
 		return;
 	}
 
-	_propagate_visibility_changed(true);
+	_propagate_visibility_changed(p_visible, !p_visible);
 	_change_notify("visible");
 }
 
-void CanvasItem::hide() {
-	if (!visible) {
-		return;
-	}
-
-	visible = false;
-	VisualServer::get_singleton()->canvas_item_set_visible(canvas_item, false);
+void CanvasItem::show() {
+	set_visible(true);
+}
 
-	if (!is_inside_tree()) {
-		return;
-	}
+void CanvasItem::hide() {
+	set_visible(false);
+}
 
-	_propagate_visibility_changed(false);
-	_change_notify("visible");
+bool CanvasItem::is_visible() const {
+	return visible;
 }
 
 CanvasItem *CanvasItem::current_item_drawn = nullptr;
@@ -435,7 +419,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()) { //todo optimize this!!
+	if (is_visible_in_tree()) {
 		if (first_draw) {
 			notification(NOTIFICATION_VISIBILITY_CHANGED);
 			first_draw = false;
@@ -556,10 +540,20 @@ void CanvasItem::_notification(int p_what) {
 		case NOTIFICATION_ENTER_TREE: {
 			ERR_FAIL_COND(!is_inside_tree());
 			first_draw = true;
-			if (get_parent()) {
-				CanvasItem *ci = Object::cast_to<CanvasItem>(get_parent());
+
+			Node *parent = get_parent();
+			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();
@@ -591,6 +585,7 @@ void CanvasItem::_notification(int p_what) {
 				C = nullptr;
 			}
 			global_invalid = true;
+			parent_visible_in_tree = false;
 		} break;
 		case NOTIFICATION_DRAW:
 		case NOTIFICATION_TRANSFORM_CHANGED: {
@@ -601,17 +596,6 @@ void CanvasItem::_notification(int p_what) {
 	}
 }
 
-void CanvasItem::set_visible(bool p_visible) {
-	if (p_visible) {
-		show();
-	} else {
-		hide();
-	}
-}
-bool CanvasItem::is_visible() const {
-	return visible;
-}
-
 void CanvasItem::update() {
 	if (!is_inside_tree()) {
 		return;
@@ -1267,6 +1251,7 @@ 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);

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

@@ -162,6 +162,8 @@ VARIANT_ENUM_CAST(CanvasItemMaterial::LightMode)
 class CanvasItem : public Node {
 	GDCLASS(CanvasItem, Node);
 
+	friend class CanvasLayer;
+
 public:
 	enum BlendMode {
 
@@ -191,6 +193,7 @@ private:
 
 	bool first_draw;
 	bool visible;
+	bool parent_visible_in_tree;
 	bool pending_update;
 	bool toplevel;
 	bool drawing;
@@ -207,7 +210,7 @@ private:
 
 	void _toplevel_raise_self();
 
-	void _propagate_visibility_changed(bool p_visible);
+	void _propagate_visibility_changed(bool p_visible, bool p_was_visible = false);
 
 	void _update_callback();
 

+ 34 - 0
scene/main/canvas_layer.cpp

@@ -29,6 +29,7 @@
 /*************************************************************************/
 
 #include "canvas_layer.h"
+#include "scene/2d/canvas_item.h"
 #include "viewport.h"
 
 void CanvasLayer::set_layer(int p_xform) {
@@ -42,6 +43,32 @@ int CanvasLayer::get_layer() const {
 	return layer;
 }
 
+void CanvasLayer::set_visible(bool p_visible) {
+	if (p_visible == visible) {
+		return;
+	}
+
+	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->notification(CanvasItem::NOTIFICATION_VISIBILITY_CHANGED);
+			}
+		}
+	}
+}
+
+bool CanvasLayer::is_visible() const {
+	return visible;
+}
+
 void CanvasLayer::set_transform(const Transform2D &p_xform) {
 	transform = p_xform;
 	locrotscale_dirty = true;
@@ -265,6 +292,9 @@ void CanvasLayer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_layer", "layer"), &CanvasLayer::set_layer);
 	ClassDB::bind_method(D_METHOD("get_layer"), &CanvasLayer::get_layer);
 
+	ClassDB::bind_method(D_METHOD("set_visible", "visible"), &CanvasLayer::set_visible);
+	ClassDB::bind_method(D_METHOD("is_visible"), &CanvasLayer::is_visible);
+
 	ClassDB::bind_method(D_METHOD("set_transform", "transform"), &CanvasLayer::set_transform);
 	ClassDB::bind_method(D_METHOD("get_transform"), &CanvasLayer::get_transform);
 
@@ -293,6 +323,7 @@ void CanvasLayer::_bind_methods() {
 
 	ADD_GROUP("Layer", "");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "layer", PROPERTY_HINT_RANGE, "-128,128,1"), "set_layer", "get_layer");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
 	ADD_GROUP("Transform", "");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation_degrees", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees");
@@ -304,6 +335,8 @@ void CanvasLayer::_bind_methods() {
 	ADD_GROUP("Follow Viewport", "follow_viewport");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_viewport_enable"), "set_follow_viewport", "is_following_viewport");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "follow_viewport_scale", PROPERTY_HINT_RANGE, "0.001,1000,0.001,or_greater,or_lesser"), "set_follow_viewport_scale", "get_follow_viewport_scale");
+
+	ADD_SIGNAL(MethodInfo("visibility_changed"));
 }
 
 #ifdef TOOLS_ENABLED
@@ -326,6 +359,7 @@ CanvasLayer::CanvasLayer() {
 	custom_viewport = nullptr;
 	custom_viewport_id = 0;
 	sort_index = 0;
+	visible = true;
 	follow_viewport = false;
 	follow_viewport_scale = 1.0;
 }

+ 4 - 0
scene/main/canvas_layer.h

@@ -53,6 +53,7 @@ class CanvasLayer : public Node {
 	Viewport *vp;
 
 	int sort_index;
+	bool visible;
 
 	bool follow_viewport;
 	float follow_viewport_scale;
@@ -69,6 +70,9 @@ public:
 	void set_layer(int p_xform);
 	int get_layer() const;
 
+	void set_visible(bool p_visible);
+	bool is_visible() const;
+
 	void set_transform(const Transform2D &p_xform);
 	Transform2D get_transform() const;