Forráskód Böngészése

Make all get_configuration_warning() overrides retrieve warnings from parent

ArrowInAKnee 5 éve
szülő
commit
e48430b1d4

+ 6 - 2
scene/2d/animated_sprite.cpp

@@ -667,11 +667,15 @@ StringName AnimatedSprite::get_animation() const {
 
 String AnimatedSprite::get_configuration_warning() const {
 
+	String warning = Node2D::get_configuration_warning();
 	if (frames.is_null()) {
-		return TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite to display frames.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite to display frames.");
 	}
 
-	return String();
+	return warning;
 }
 
 void AnimatedSprite::_bind_methods() {

+ 7 - 3
scene/2d/canvas_modulate.cpp

@@ -81,17 +81,21 @@ Color CanvasModulate::get_color() const {
 
 String CanvasModulate::get_configuration_warning() const {
 
+	String warning = Node2D::get_configuration_warning();
 	if (!is_visible_in_tree() || !is_inside_tree())
-		return String();
+		return warning;
 
 	List<Node *> nodes;
 	get_tree()->get_nodes_in_group("_canvas_modulate_" + itos(get_canvas().get_id()), &nodes);
 
 	if (nodes.size() > 1) {
-		return TTR("Only one visible CanvasModulate is allowed per scene (or set of instanced scenes). The first created one will work, while the rest will be ignored.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("Only one visible CanvasModulate is allowed per scene (or set of instanced scenes). The first created one will work, while the rest will be ignored.");
 	}
 
-	return String();
+	return warning;
 }
 
 CanvasModulate::CanvasModulate() {

+ 10 - 3
scene/2d/collision_polygon_2d.cpp

@@ -247,15 +247,22 @@ bool CollisionPolygon2D::_edit_is_selected_on_click(const Point2 &p_point, doubl
 
 String CollisionPolygon2D::get_configuration_warning() const {
 
+	String warning = Node2D::get_configuration_warning();
 	if (!Object::cast_to<CollisionObject2D>(get_parent())) {
-		return TTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape.");
 	}
 
 	if (polygon.empty()) {
-		return TTR("An empty CollisionPolygon2D has no effect on collision.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("An empty CollisionPolygon2D has no effect on collision.");
 	}
 
-	return String();
+	return warning;
 }
 
 void CollisionPolygon2D::set_disabled(bool p_disabled) {

+ 15 - 4
scene/2d/collision_shape_2d.cpp

@@ -180,18 +180,29 @@ bool CollisionShape2D::_edit_is_selected_on_click(const Point2 &p_point, double
 
 String CollisionShape2D::get_configuration_warning() const {
 
+	String warning = Node2D::get_configuration_warning();
 	if (!Object::cast_to<CollisionObject2D>(get_parent())) {
-		return TTR("CollisionShape2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("CollisionShape2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape.");
 	}
 	if (!shape.is_valid()) {
-		return TTR("A shape must be provided for CollisionShape2D to function. Please create a shape resource for it!");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("A shape must be provided for CollisionShape2D to function. Please create a shape resource for it!");
 	}
+
 	Ref<ConvexPolygonShape2D> convex = shape;
 	Ref<ConcavePolygonShape2D> concave = shape;
 	if (convex.is_valid() || concave.is_valid()) {
-		return TTR("Polygon-based shapes are not meant be used nor edited directly through the CollisionShape2D node. Please use the CollisionPolygon2D node instead.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("Polygon-based shapes are not meant be used nor edited directly through the CollisionShape2D node. Please use the CollisionPolygon2D node instead.");
 	}
-	return String();
+	return warning;
 }
 
 void CollisionShape2D::set_disabled(bool p_disabled) {

+ 2 - 2
scene/2d/cpu_particles_2d.cpp

@@ -267,7 +267,7 @@ bool CPUParticles2D::get_fractional_delta() const {
 
 String CPUParticles2D::get_configuration_warning() const {
 
-	String warnings;
+	String warnings = Node2D::get_configuration_warning();
 
 	CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr());
 
@@ -275,7 +275,7 @@ String CPUParticles2D::get_configuration_warning() const {
 		if (get_param(PARAM_ANIM_SPEED) != 0.0 || get_param(PARAM_ANIM_OFFSET) != 0.0 ||
 				get_param_curve(PARAM_ANIM_SPEED).is_valid() || get_param_curve(PARAM_ANIM_OFFSET).is_valid()) {
 			if (warnings != String())
-				warnings += "\n";
+				warnings += "\n\n";
 			warnings += "- " + TTR("CPUParticles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled.");
 		}
 	}

+ 6 - 2
scene/2d/light_2d.cpp

@@ -352,11 +352,15 @@ void Light2D::_notification(int p_what) {
 
 String Light2D::get_configuration_warning() const {
 
+	String warning = Node2D::get_configuration_warning();
 	if (!texture.is_valid()) {
-		return TTR("A texture with the shape of the light must be supplied to the \"Texture\" property.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("A texture with the shape of the light must be supplied to the \"Texture\" property.");
 	}
 
-	return String();
+	return warning;
 }
 
 void Light2D::set_shadow_smooth(float p_amount) {

+ 10 - 3
scene/2d/light_occluder_2d.cpp

@@ -268,15 +268,22 @@ int LightOccluder2D::get_occluder_light_mask() const {
 
 String LightOccluder2D::get_configuration_warning() const {
 
+	String warning = Node2D::get_configuration_warning();
 	if (!occluder_polygon.is_valid()) {
-		return TTR("An occluder polygon must be set (or drawn) for this occluder to take effect.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("An occluder polygon must be set (or drawn) for this occluder to take effect.");
 	}
 
 	if (occluder_polygon.is_valid() && occluder_polygon->get_polygon().size() == 0) {
-		return TTR("The occluder polygon for this occluder is empty. Please draw a polygon.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("The occluder polygon for this occluder is empty. Please draw a polygon.");
 	}
 
-	return String();
+	return warning;
 }
 
 void LightOccluder2D::_bind_methods() {

+ 12 - 3
scene/2d/navigation_polygon.cpp

@@ -504,20 +504,29 @@ String NavigationPolygonInstance::get_configuration_warning() const {
 	if (!is_visible_in_tree() || !is_inside_tree())
 		return String();
 
+	String warning = Node2D::get_configuration_warning();
 	if (!navpoly.is_valid()) {
-		return TTR("A NavigationPolygon resource must be set or created for this node to work. Please set a property or draw a polygon.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("A NavigationPolygon resource must be set or created for this node to work. Please set a property or draw a polygon.");
 	}
 	const Node2D *c = this;
 	while (c) {
 
 		if (Object::cast_to<Navigation2D>(c)) {
-			return String();
+			return warning;
 		}
 
 		c = Object::cast_to<Node2D>(c->get_parent());
 	}
 
-	return TTR("NavigationPolygonInstance must be a child or grandchild to a Navigation2D node. It only provides navigation data.");
+	if (warning != String()) {
+		warning += "\n\n";
+	}
+	warning += TTR("NavigationPolygonInstance must be a child or grandchild to a Navigation2D node. It only provides navigation data.");
+
+	return warning;
 }
 
 void NavigationPolygonInstance::_bind_methods() {

+ 6 - 3
scene/2d/parallax_layer.cpp

@@ -143,12 +143,15 @@ void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, float p_sc
 }
 
 String ParallaxLayer::get_configuration_warning() const {
-
+	String warning = Node2D::get_configuration_warning();
 	if (!Object::cast_to<ParallaxBackground>(get_parent())) {
-		return TTR("ParallaxLayer node only works when set as child of a ParallaxBackground node.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("ParallaxLayer node only works when set as child of a ParallaxBackground node.");
 	}
 
-	return String();
+	return warning;
 }
 
 void ParallaxLayer::_bind_methods() {

+ 13 - 11
scene/2d/particles_2d.cpp

@@ -227,17 +227,19 @@ bool Particles2D::get_fractional_delta() const {
 }
 
 String Particles2D::get_configuration_warning() const {
-
+	String warning = Node2D::get_configuration_warning();
 	if (OS::get_singleton()->get_current_video_driver() == OS::VIDEO_DRIVER_GLES2) {
-		return TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles2D node instead. You can use the \"Convert to CPUParticles\" option for this purpose.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles2D node instead. You can use the \"Convert to CPUParticles\" option for this purpose.");
+		return warning;
 	}
 
-	String warnings;
-
 	if (process_material.is_null()) {
-		if (warnings != String())
-			warnings += "\n";
-		warnings += "- " + TTR("A material to process the particles is not assigned, so no behavior is imprinted.");
+		if (warning != String())
+			warning += "\n\n";
+		warning += "- " + TTR("A material to process the particles is not assigned, so no behavior is imprinted.");
 	} else {
 
 		CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr());
@@ -247,14 +249,14 @@ String Particles2D::get_configuration_warning() const {
 			if (process &&
 					(process->get_param(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 ||
 							process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) {
-				if (warnings != String())
-					warnings += "\n";
-				warnings += "- " + TTR("Particles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled.");
+				if (warning != String())
+					warning += "\n\n";
+				warning += "- " + TTR("Particles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled.");
 			}
 		}
 	}
 
-	return warnings;
+	return warning;
 }
 
 Rect2 Particles2D::capture_rect() const {

+ 6 - 2
scene/2d/path_2d.cpp

@@ -275,11 +275,15 @@ String PathFollow2D::get_configuration_warning() const {
 	if (!is_visible_in_tree() || !is_inside_tree())
 		return String();
 
+	String warning = Node2D::get_configuration_warning();
 	if (!Object::cast_to<Path2D>(get_parent())) {
-		return TTR("PathFollow2D only works when set as a child of a Path2D node.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("PathFollow2D only works when set as a child of a Path2D node.");
 	}
 
-	return String();
+	return warning;
 }
 
 void PathFollow2D::_bind_methods() {

+ 6 - 2
scene/2d/remote_transform_2d.cpp

@@ -186,11 +186,15 @@ void RemoteTransform2D::force_update_cache() {
 
 String RemoteTransform2D::get_configuration_warning() const {
 
+	String warning = Node2D::get_configuration_warning();
 	if (!has_node(remote_node) || !Object::cast_to<Node2D>(get_node(remote_node))) {
-		return TTR("Path property must point to a valid Node2D node to work.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("Path property must point to a valid Node2D node to work.");
 	}
 
-	return String();
+	return warning;
 }
 
 void RemoteTransform2D::_bind_methods() {

+ 6 - 2
scene/2d/visibility_notifier_2d.cpp

@@ -330,12 +330,16 @@ void VisibilityEnabler2D::_node_removed(Node *p_node) {
 }
 
 String VisibilityEnabler2D::get_configuration_warning() const {
+	String warning = VisibilityNotifier2D::get_configuration_warning();
 #ifdef TOOLS_ENABLED
 	if (is_inside_tree() && get_parent() && (get_parent()->get_filename() == String() && get_parent() != get_tree()->get_edited_scene_root())) {
-		return TTR("VisibilityEnabler2D works best when used with the edited scene root directly as parent.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("VisibilityEnabler2D works best when used with the edited scene root directly as parent.");
 	}
 #endif
-	return String();
+	return warning;
 }
 
 void VisibilityEnabler2D::_bind_methods() {

+ 34 - 11
scene/3d/arvr_nodes.cpp

@@ -58,13 +58,17 @@ String ARVRCamera::get_configuration_warning() const {
 	if (!is_visible() || !is_inside_tree())
 		return String();
 
+	String warning = Camera::get_configuration_warning();
 	// must be child node of ARVROrigin!
 	ARVROrigin *origin = Object::cast_to<ARVROrigin>(get_parent());
 	if (origin == NULL) {
-		return TTR("ARVRCamera must have an ARVROrigin node as its parent.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("ARVRCamera must have an ARVROrigin node as its parent.");
 	};
 
-	return String();
+	return warning;
 };
 
 Vector3 ARVRCamera::project_local_ray_normal(const Point2 &p_pos) const {
@@ -367,17 +371,24 @@ String ARVRController::get_configuration_warning() const {
 	if (!is_visible() || !is_inside_tree())
 		return String();
 
+	String warning = Spatial::get_configuration_warning();
 	// must be child node of ARVROrigin!
 	ARVROrigin *origin = Object::cast_to<ARVROrigin>(get_parent());
 	if (origin == NULL) {
-		return TTR("ARVRController must have an ARVROrigin node as its parent.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("ARVRController must have an ARVROrigin node as its parent.");
 	};
 
 	if (controller_id == 0) {
-		return TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller.");
 	};
 
-	return String();
+	return warning;
 };
 
 ARVRController::ARVRController() {
@@ -494,17 +505,24 @@ String ARVRAnchor::get_configuration_warning() const {
 	if (!is_visible() || !is_inside_tree())
 		return String();
 
+	String warning = Spatial::get_configuration_warning();
 	// must be child node of ARVROrigin!
 	ARVROrigin *origin = Object::cast_to<ARVROrigin>(get_parent());
 	if (origin == NULL) {
-		return TTR("ARVRAnchor must have an ARVROrigin node as its parent.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("ARVRAnchor must have an ARVROrigin node as its parent.");
 	};
 
 	if (anchor_id == 0) {
-		return TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor.");
 	};
 
-	return String();
+	return warning;
 };
 
 Plane ARVRAnchor::get_plane() const {
@@ -535,10 +553,15 @@ String ARVROrigin::get_configuration_warning() const {
 	if (!is_visible() || !is_inside_tree())
 		return String();
 
-	if (tracked_camera == NULL)
-		return TTR("ARVROrigin requires an ARVRCamera child node.");
+	String warning = Spatial::get_configuration_warning();
+	if (tracked_camera == NULL) {
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("ARVROrigin requires an ARVRCamera child node.");
+	}
 
-	return String();
+	return warning;
 };
 
 void ARVROrigin::_bind_methods() {

+ 10 - 3
scene/3d/collision_polygon.cpp

@@ -164,15 +164,22 @@ bool CollisionPolygon::is_disabled() const {
 
 String CollisionPolygon::get_configuration_warning() const {
 
+	String warning = Spatial::get_configuration_warning();
 	if (!Object::cast_to<CollisionObject>(get_parent())) {
-		return TTR("CollisionPolygon only serves to provide a collision shape to a CollisionObject derived node. Please only use it as a child of Area, StaticBody, RigidBody, KinematicBody, etc. to give them a shape.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("CollisionPolygon only serves to provide a collision shape to a CollisionObject derived node. Please only use it as a child of Area, StaticBody, RigidBody, KinematicBody, etc. to give them a shape.");
 	}
 
 	if (polygon.empty()) {
-		return TTR("An empty CollisionPolygon has no effect on collision.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("An empty CollisionPolygon has no effect on collision.");
 	}
 
-	return String();
+	return warning;
 }
 
 bool CollisionPolygon::_is_editable_3d_polygon() const {

+ 18 - 5
scene/3d/collision_shape.cpp

@@ -115,27 +115,40 @@ void CollisionShape::resource_changed(RES res) {
 
 String CollisionShape::get_configuration_warning() const {
 
+	String warning = Spatial::get_configuration_warning();
 	if (!Object::cast_to<CollisionObject>(get_parent())) {
-		return TTR("CollisionShape only serves to provide a collision shape to a CollisionObject derived node. Please only use it as a child of Area, StaticBody, RigidBody, KinematicBody, etc. to give them a shape.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("CollisionShape only serves to provide a collision shape to a CollisionObject derived node. Please only use it as a child of Area, StaticBody, RigidBody, KinematicBody, etc. to give them a shape.");
 	}
 
 	if (!shape.is_valid()) {
-		return TTR("A shape must be provided for CollisionShape to function. Please create a shape resource for it.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("A shape must be provided for CollisionShape to function. Please create a shape resource for it.");
 	}
 
 	if (shape->is_class("PlaneShape")) {
-		return TTR("Plane shapes don't work well and will be removed in future versions. Please don't use them.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("Plane shapes don't work well and will be removed in future versions. Please don't use them.");
 	}
 
 	if (Object::cast_to<RigidBody>(get_parent())) {
 		if (Object::cast_to<ConcavePolygonShape>(*shape)) {
 			if (Object::cast_to<RigidBody>(get_parent())->get_mode() != RigidBody::MODE_STATIC) {
-				return TTR("ConcavePolygonShape doesn't support RigidBody in another mode than static.");
+				if (warning != String()) {
+					warning += "\n\n";
+				}
+				warning += TTR("ConcavePolygonShape doesn't support RigidBody in another mode than static.");
 			}
 		}
 	}
 
-	return String();
+	return warning;
 }
 
 void CollisionShape::_bind_methods() {

+ 1 - 1
scene/3d/cpu_particles.cpp

@@ -201,7 +201,7 @@ bool CPUParticles::get_fractional_delta() const {
 
 String CPUParticles::get_configuration_warning() const {
 
-	String warnings;
+	String warnings = GeometryInstance::get_configuration_warning();
 
 	bool mesh_found = false;
 	bool anim_material_found = false;

+ 6 - 3
scene/3d/gi_probe.cpp

@@ -490,11 +490,14 @@ PoolVector<Face3> GIProbe::get_faces(uint32_t p_usage_flags) const {
 }
 
 String GIProbe::get_configuration_warning() const {
-
+	String warning = VisualInstance::get_configuration_warning();
 	if (OS::get_singleton()->get_current_video_driver() == OS::VIDEO_DRIVER_GLES2) {
-		return TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead.");
 	}
-	return String();
+	return warning;
 }
 
 void GIProbe::_bind_methods() {

+ 12 - 3
scene/3d/navigation_mesh.cpp

@@ -697,19 +697,28 @@ String NavigationMeshInstance::get_configuration_warning() const {
 	if (!is_visible_in_tree() || !is_inside_tree())
 		return String();
 
+	String warning = Spatial::get_configuration_warning();
 	if (!navmesh.is_valid()) {
-		return TTR("A NavigationMesh resource must be set or created for this node to work.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("A NavigationMesh resource must be set or created for this node to work.");
+		return warning;
 	}
 	const Spatial *c = this;
 	while (c) {
 
 		if (Object::cast_to<Navigation>(c))
-			return String();
+			return warning;
 
 		c = Object::cast_to<Spatial>(c->get_parent());
 	}
 
-	return TTR("NavigationMeshInstance must be a child or grandchild to a Navigation node. It only provides navigation data.");
+	if (warning != String()) {
+		warning += "\n\n";
+	}
+	warning += TTR("NavigationMeshInstance must be a child or grandchild to a Navigation node. It only provides navigation data.");
+	return warning;
 }
 
 void NavigationMeshInstance::_bind_methods() {

+ 2 - 2
scene/3d/particles.cpp

@@ -244,7 +244,7 @@ String Particles::get_configuration_warning() const {
 		return TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles node instead. You can use the \"Convert to CPUParticles\" option for this purpose.");
 	}
 
-	String warnings;
+	String warnings = GeometryInstance::get_configuration_warning();
 
 	bool meshes_found = false;
 	bool anim_material_found = false;
@@ -267,7 +267,7 @@ String Particles::get_configuration_warning() const {
 
 	if (!meshes_found) {
 		if (warnings != String())
-			warnings += "\n";
+			warnings += "\n\n";
 		warnings += "- " + TTR("Nothing is visible because meshes have not been assigned to draw passes.");
 	}
 

+ 10 - 3
scene/3d/path.cpp

@@ -264,16 +264,23 @@ String PathFollow::get_configuration_warning() const {
 	if (!is_visible_in_tree() || !is_inside_tree())
 		return String();
 
+	String warning = Spatial::get_configuration_warning();
 	if (!Object::cast_to<Path>(get_parent())) {
-		return TTR("PathFollow only works when set as a child of a Path node.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("PathFollow only works when set as a child of a Path node.");
 	} else {
 		Path *path = Object::cast_to<Path>(get_parent());
 		if (path->get_curve().is_valid() && !path->get_curve()->is_up_vector_enabled() && rotation_mode == ROTATION_ORIENTED) {
-			return TTR("PathFollow's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its parent Path's Curve resource.");
+			if (warning != String()) {
+				warning += "\n\n";
+			}
+			warning += TTR("PathFollow's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its parent Path's Curve resource.");
 		}
 	}
 
-	return String();
+	return warning;
 }
 
 void PathFollow::_bind_methods() {

+ 6 - 2
scene/3d/remote_transform.cpp

@@ -180,11 +180,15 @@ void RemoteTransform::force_update_cache() {
 
 String RemoteTransform::get_configuration_warning() const {
 
+	String warning = Spatial::get_configuration_warning();
 	if (!has_node(remote_node) || !Object::cast_to<Spatial>(get_node(remote_node))) {
-		return TTR("The \"Remote Path\" property must point to a valid Spatial or Spatial-derived node to work.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("The \"Remote Path\" property must point to a valid Spatial or Spatial-derived node to work.");
 	}
 
-	return String();
+	return warning;
 }
 
 void RemoteTransform::_bind_methods() {

+ 6 - 2
scene/3d/sprite_3d.cpp

@@ -1205,11 +1205,15 @@ StringName AnimatedSprite3D::get_animation() const {
 
 String AnimatedSprite3D::get_configuration_warning() const {
 
+	String warning = SpriteBase3D::get_configuration_warning();
 	if (frames.is_null()) {
-		return TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite3D to display frames.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite3D to display frames.");
 	}
 
-	return String();
+	return warning;
 }
 
 void AnimatedSprite3D::_bind_methods() {

+ 6 - 2
scene/3d/vehicle_body.cpp

@@ -104,11 +104,15 @@ void VehicleWheel::_notification(int p_what) {
 }
 
 String VehicleWheel::get_configuration_warning() const {
+	String warning = Spatial::get_configuration_warning();
 	if (!Object::cast_to<VehicleBody>(get_parent())) {
-		return TTR("VehicleWheel serves to provide a wheel system to a VehicleBody. Please use it as a child of a VehicleBody.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("VehicleWheel serves to provide a wheel system to a VehicleBody. Please use it as a child of a VehicleBody.");
 	}
 
-	return String();
+	return warning;
 }
 
 void VehicleWheel::_update(PhysicsDirectBodyState *s) {

+ 11 - 3
scene/3d/world_environment.cpp

@@ -79,8 +79,13 @@ Ref<Environment> WorldEnvironment::get_environment() const {
 
 String WorldEnvironment::get_configuration_warning() const {
 
+	String warning = Node::get_configuration_warning();
 	if (!environment.is_valid()) {
-		return TTR("WorldEnvironment requires its \"Environment\" property to contain an Environment to have a visible effect.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("WorldEnvironment requires its \"Environment\" property to contain an Environment to have a visible effect.");
+		return warning;
 	}
 
 	if (/*!is_visible_in_tree() ||*/ !is_inside_tree())
@@ -90,7 +95,10 @@ String WorldEnvironment::get_configuration_warning() const {
 	get_tree()->get_nodes_in_group("_world_environment_" + itos(get_viewport()->find_world()->get_scenario().get_id()), &nodes);
 
 	if (nodes.size() > 1) {
-		return TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes).");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes).");
 	}
 
 	// Commenting this warning for now, I think it makes no sense. If anyone can figure out what its supposed to do, feedback welcome. Else it should be deprecated.
@@ -98,7 +106,7 @@ String WorldEnvironment::get_configuration_warning() const {
 	//	return TTR("This WorldEnvironment is ignored. Either add a Camera (for 3D scenes) or set this environment's Background Mode to Canvas (for 2D scenes).");
 	//}
 
-	return String();
+	return warning;
 }
 
 void WorldEnvironment::_bind_methods() {

+ 6 - 2
scene/gui/popup.cpp

@@ -234,11 +234,15 @@ Popup::Popup() {
 
 String Popup::get_configuration_warning() const {
 
+	String warning = Control::get_configuration_warning();
 	if (is_visible_in_tree()) {
-		return TTR("Popups will hide by default unless you call popup() or any of the popup*() functions. Making them visible for editing is fine, but they will hide upon running.");
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("Popups will hide by default unless you call popup() or any of the popup*() functions. Making them visible for editing is fine, but they will hide upon running.");
 	}
 
-	return String();
+	return warning;
 }
 
 Popup::~Popup() {

+ 10 - 4
scene/gui/scroll_container.cpp

@@ -537,6 +537,8 @@ void ScrollContainer::set_follow_focus(bool p_follow) {
 
 String ScrollContainer::get_configuration_warning() const {
 
+	String warning = Control::get_configuration_warning();
+
 	int found = 0;
 
 	for (int i = 0; i < get_child_count(); i++) {
@@ -552,10 +554,14 @@ String ScrollContainer::get_configuration_warning() const {
 		found++;
 	}
 
-	if (found != 1)
-		return TTR("ScrollContainer is intended to work with a single child control.\nUse a container as child (VBox, HBox, etc.), or a Control and set the custom minimum size manually.");
-	else
-		return "";
+	if (found != 1) {
+		if (warning != String()) {
+			warning += "\n\n";
+		}
+		warning += TTR("ScrollContainer is intended to work with a single child control.\nUse a container as child (VBox, HBox, etc.), or a Control and set the custom minimum size manually.");
+	}
+
+	return warning;
 }
 
 HScrollBar *ScrollContainer::get_h_scrollbar() {

+ 6 - 2
scene/main/viewport.cpp

@@ -2986,10 +2986,14 @@ String Viewport::get_configuration_warning() const {
 		return TTR("This viewport is not set as render target. If you intend for it to display its contents directly to the screen, make it a child of a Control so it can obtain a size. Otherwise, make it a RenderTarget and assign its internal texture to some node for display.");
 	}*/
 
+	String warning = Node::get_configuration_warning();
+
 	if (size.x == 0 || size.y == 0) {
-		return TTR("Viewport size must be greater than 0 to render anything.");
+		if (warning != String())
+			warning += "\n\n";
+		warning += TTR("Viewport size must be greater than 0 to render anything.");
 	}
-	return String();
+	return warning;
 }
 
 void Viewport::gui_reset_canvas_sort_index() {