diff --git a/doc/classes/SubViewportContainer.xml b/doc/classes/SubViewportContainer.xml
index b01a81a61f06..d1c5de661521 100644
--- a/doc/classes/SubViewportContainer.xml
+++ b/doc/classes/SubViewportContainer.xml
@@ -4,7 +4,7 @@
A container used for displaying the contents of a [SubViewport].
- A container that displays the contents of underlying [SubViewport] child nodes. It uses the combined size of the [SubViewport]s as minimum size, unless [member stretch] is enabled.
+ An interface that displays the contents of underlying [SubViewport] child nodes and handles input event propagation. It uses the combined size of the [SubViewport]s as minimum size, unless [member stretch] is enabled.
[b]Note:[/b] Changing a [SubViewportContainer]'s [member Control.scale] will cause its contents to appear distorted. To change its visual size without causing distortion, adjust the node's margins instead (if it's not already in a container).
[b]Note:[/b] The [SubViewportContainer] forwards mouse-enter and mouse-exit notifications to its sub-viewports.
@@ -26,6 +26,9 @@
If [code]false[/code], the [Control] nodes inside its [SubViewport] children are considered as targets.
If [code]true[/code], the [SubViewportContainer] itself will be considered as a target.
+
+ If [code]true[/code], input events will be sent to all child [SubViewport] nodes. If [code]false[/code], when a child [SubViewport] sets an input event to handled, it will not be sent to additional child [SubViewport] nodes.
+
If [code]true[/code], the sub-viewport will be automatically resized to the control's size.
[b]Note:[/b] If [code]true[/code], this will prohibit changing [member SubViewport.size] of its children manually.
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index 3e772c4e884b..9c267f94acc7 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -185,7 +185,6 @@
Returns whether the current [InputEvent] has been handled. Input events are not handled until [method set_input_as_handled] has been called during the lifetime of an [InputEvent].
This is usually done as part of input handling methods like [method Node._input], [method Control._gui_input] or others, as well as in corresponding signal handlers.
- If [member handle_input_locally] is set to [code]false[/code], this method will try finding the first parent viewport that is set to handle input locally, and return its value for [method is_input_handled] instead.
@@ -308,10 +307,8 @@
If [code]true[/code], the GUI controls on the viewport will lay pixel perfectly.
-
- If [code]true[/code], this viewport will mark incoming input events as handled by itself. If [code]false[/code], this is instead done by the first parent viewport that is set to handle input locally.
- A [SubViewportContainer] will automatically set this property to [code]false[/code] for the [Viewport] contained inside of it.
- See also [method set_input_as_handled] and [method is_input_handled].
+
+ This member is not used by the engine and always returns [code]true[/code].
The automatic LOD bias to use for meshes rendered within the [Viewport] (this is analogous to [member ReflectionProbe.mesh_lod_threshold]). Higher values will use less detailed versions of meshes that have LOD variations generated. If set to [code]0.0[/code], automatic LOD is disabled. Increase [member mesh_lod_threshold] to improve performance at the cost of geometry detail.
diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp
index 9e885e9d6292..ca127ba351be 100644
--- a/scene/gui/subviewport_container.cpp
+++ b/scene/gui/subviewport_container.cpp
@@ -79,6 +79,14 @@ void SubViewportContainer::set_stretch_shrink(int p_shrink) {
queue_redraw();
}
+void SubViewportContainer::set_send_input_to_all_viewports(bool p_enable) {
+ send_input_event_to_all_viewports = p_enable;
+}
+
+bool SubViewportContainer::is_send_input_to_all_viewports_enabled() {
+ return send_input_event_to_all_viewports;
+}
+
void SubViewportContainer::recalc_force_viewport_sizes() {
if (!stretch) {
return;
@@ -126,8 +134,6 @@ void SubViewportContainer::_notification(int p_what) {
} else {
c->set_update_mode(SubViewport::UPDATE_DISABLED);
}
-
- c->set_handle_input_locally(false); //do not handle input locally here
}
} break;
@@ -227,13 +233,24 @@ void SubViewportContainer::gui_input(const Ref &p_event) {
}
void SubViewportContainer::_send_event_to_viewports(const Ref &p_event) {
- for (int i = 0; i < get_child_count(); i++) {
+ bool is_handled = false;
+ // The input order is consistent with the display order, so that the topmost SubViewport receives the input events first.
+ for (int i = get_child_count() - 1; i >= 0; i--) {
SubViewport *c = Object::cast_to(get_child(i));
if (!c || c->is_input_disabled()) {
continue;
}
c->push_input(p_event);
+ if (c->is_input_handled()) {
+ is_handled = true;
+ if (!send_input_event_to_all_viewports) {
+ break;
+ }
+ }
+ }
+ if (is_handled) {
+ get_viewport()->set_input_as_handled();
}
}
@@ -297,9 +314,13 @@ void SubViewportContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_mouse_target", "amount"), &SubViewportContainer::set_mouse_target);
ClassDB::bind_method(D_METHOD("is_mouse_target_enabled"), &SubViewportContainer::is_mouse_target_enabled);
+ ClassDB::bind_method(D_METHOD("set_send_input_to_all_viewports", "enable"), &SubViewportContainer::set_send_input_to_all_viewports);
+ ClassDB::bind_method(D_METHOD("is_send_input_to_all_viewports_enabled"), &SubViewportContainer::is_send_input_to_all_viewports_enabled);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stretch"), "set_stretch", "is_stretch_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_shrink", PROPERTY_HINT_RANGE, "1,32,1,or_greater"), "set_stretch_shrink", "get_stretch_shrink");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "mouse_target"), "set_mouse_target", "is_mouse_target_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "send_input_to_all_viewports"), "set_send_input_to_all_viewports", "is_send_input_to_all_viewports_enabled");
GDVIRTUAL_BIND(_propagate_input_event, "event");
}
diff --git a/scene/gui/subviewport_container.h b/scene/gui/subviewport_container.h
index 660f9edf7494..ad68eabe6db8 100644
--- a/scene/gui/subviewport_container.h
+++ b/scene/gui/subviewport_container.h
@@ -39,6 +39,7 @@ class SubViewportContainer : public Container {
bool stretch = false;
int shrink = 1;
bool mouse_target = false;
+ bool send_input_event_to_all_viewports = false;
void _notify_viewports(int p_notification);
bool _is_propagated_in_gui_input(const Ref &p_event);
@@ -58,6 +59,9 @@ class SubViewportContainer : public Container {
void set_stretch(bool p_enable);
bool is_stretch_enabled() const;
+ void set_send_input_to_all_viewports(bool p_enable);
+ bool is_send_input_to_all_viewports_enabled();
+
virtual void input(const Ref &p_event) override;
virtual void unhandled_input(const Ref &p_event) override;
virtual void gui_input(const Ref &p_event) override;
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 6c83c7843fb8..e6538cedf3b1 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -750,14 +750,6 @@ void Viewport::_process_picking() {
while (physics_picking_events.size()) {
local_input_handled = false;
- if (!handle_input_locally) {
- Viewport *vp = this;
- while (!Object::cast_to(vp) && vp->get_parent()) {
- vp = vp->get_parent()->get_viewport();
- }
- vp->local_input_handled = false;
- }
-
Ref ev = physics_picking_events.front()->get();
physics_picking_events.pop_front();
@@ -3143,16 +3135,6 @@ void Viewport::push_input(const Ref &p_event, bool p_local_coords) {
}
local_input_handled = false;
- if (!handle_input_locally) {
- Viewport *vp = this;
- while (true) {
- if (Object::cast_to(vp) || !vp->get_parent()) {
- break;
- }
- vp = vp->get_parent()->get_viewport();
- }
- vp->local_input_handled = false;
- }
Ref ev;
if (!p_local_coords) {
@@ -3548,57 +3530,22 @@ void Viewport::gui_cancel_drag() {
void Viewport::set_input_as_handled() {
ERR_MAIN_THREAD_GUARD;
- if (!handle_input_locally) {
- ERR_FAIL_COND(!is_inside_tree());
- Viewport *vp = this;
- while (true) {
- if (Object::cast_to(vp)) {
- break;
- }
- if (!vp->get_parent()) {
- break;
- }
- vp = vp->get_parent()->get_viewport();
- }
- if (vp != this) {
- vp->set_input_as_handled();
- return;
- }
- }
-
local_input_handled = true;
}
bool Viewport::is_input_handled() const {
ERR_READ_THREAD_GUARD_V(false);
- if (!handle_input_locally) {
- ERR_FAIL_COND_V(!is_inside_tree(), false);
- const Viewport *vp = this;
- while (true) {
- if (Object::cast_to(vp)) {
- break;
- }
- if (!vp->get_parent()) {
- break;
- }
- vp = vp->get_parent()->get_viewport();
- }
- if (vp != this) {
- return vp->is_input_handled();
- }
- }
return local_input_handled;
}
+#ifndef DISABLE_DEPRECATED
void Viewport::set_handle_input_locally(bool p_enable) {
- ERR_MAIN_THREAD_GUARD;
- handle_input_locally = p_enable;
}
bool Viewport::is_handling_input_locally() const {
- ERR_READ_THREAD_GUARD_V(false);
- return handle_input_locally;
+ return true; // Now viewports always handle input locally.
}
+#endif // DISABLE_DEPRECATED
void Viewport::set_default_canvas_item_texture_filter(DefaultCanvasItemTextureFilter p_filter) {
ERR_MAIN_THREAD_GUARD;
@@ -4719,8 +4666,10 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_input_as_handled"), &Viewport::set_input_as_handled);
ClassDB::bind_method(D_METHOD("is_input_handled"), &Viewport::is_input_handled);
+#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("set_handle_input_locally", "enable"), &Viewport::set_handle_input_locally);
ClassDB::bind_method(D_METHOD("is_handling_input_locally"), &Viewport::is_handling_input_locally);
+#endif // DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("set_default_canvas_item_texture_filter", "mode"), &Viewport::set_default_canvas_item_texture_filter);
ClassDB::bind_method(D_METHOD("get_default_canvas_item_texture_filter"), &Viewport::get_default_canvas_item_texture_filter);
@@ -4801,7 +4750,9 @@ void Viewport::_bind_methods() {
#endif // _3D_DISABLED
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_2d", PROPERTY_HINT_RESOURCE_TYPE, "World2D", PROPERTY_USAGE_NONE), "set_world_2d", "get_world_2d");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transparent_bg"), "set_transparent_background", "has_transparent_background");
+#ifndef DISABLE_DEPRECATED
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "handle_input_locally"), "set_handle_input_locally", "is_handling_input_locally");
+#endif // DISABLE_DEPRECATED
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_2d_transforms_to_pixel"), "set_snap_2d_transforms_to_pixel", "is_snap_2d_transforms_to_pixel_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_2d_vertices_to_pixel"), "set_snap_2d_vertices_to_pixel", "is_snap_2d_vertices_to_pixel_enabled");
ADD_GROUP("Rendering", "");
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 3a5ad2d83cb4..8ee4300a6731 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -268,7 +268,6 @@ class Viewport : public Node {
Transform3D physics_last_camera_transform;
ObjectID physics_last_id;
- bool handle_input_locally = true;
bool local_input_handled = false;
Ref world_2d;
@@ -623,8 +622,10 @@ class Viewport : public Node {
void set_input_as_handled();
bool is_input_handled() const;
+#ifndef DISABLE_DEPRECATED
void set_handle_input_locally(bool p_enable);
bool is_handling_input_locally() const;
+#endif // DISABLE_DEPRECATED
bool gui_is_dragging() const;
bool gui_is_drag_successful() const;