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;