Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make SubViewportContainer event propagation aware of focused Control #79248

Merged
merged 1 commit into from
Jul 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/classes/SubViewportContainer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<tutorials>
</tutorials>
<members>
<member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" overrides="Control" enum="Control.FocusMode" default="1" />
<member name="stretch" type="bool" setter="set_stretch" getter="is_stretch_enabled" default="false">
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.
Expand Down
4 changes: 2 additions & 2 deletions doc/classes/Viewport.xml
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,8 @@
- [method Node._input]
- [method Control._gui_input] for [Control] nodes
- [method Node._shortcut_input]
- [method Node._unhandled_input]
- [method Node._unhandled_key_input]
- [method Node._unhandled_input]
If an earlier method marks the input as handled via [method set_input_as_handled], any later method in this list will not be called.
If none of the methods handle the event and [member physics_object_picking] is [code]true[/code], the event is used for physics object picking.
</description>
Expand All @@ -183,8 +183,8 @@
While this method serves a similar purpose as [method Input.parse_input_event], it does not remap the specified [param event] based on project settings like [member ProjectSettings.input_devices/pointing/emulate_touch_from_mouse].
Calling this method will propagate calls to child nodes for following methods in the given order:
- [method Node._shortcut_input]
- [method Node._unhandled_input]
- [method Node._unhandled_key_input]
- [method Node._unhandled_input]
If an earlier method marks the input as handled via [method set_input_as_handled], any later method in this list will not be called.
If none of the methods handle the event and [member physics_object_picking] is [code]true[/code], the event is used for physics object picking.
[b]Note:[/b] This method doesn't propagate input events to embedded [Window]s or [SubViewport]s.
Expand Down
23 changes: 22 additions & 1 deletion scene/gui/subviewport_container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,18 @@ void SubViewportContainer::_notification(int p_what) {
case NOTIFICATION_MOUSE_EXIT: {
_notify_viewports(NOTIFICATION_VP_MOUSE_EXIT);
} break;

case NOTIFICATION_FOCUS_ENTER: {
// If focused, send InputEvent to the SubViewport before the Gui-Input stage.
set_process_input(true);
set_process_unhandled_input(false);
} break;

case NOTIFICATION_FOCUS_EXIT: {
// A different Control has focus and should receive Gui-Input before the InputEvent is sent to the SubViewport.
set_process_input(false);
set_process_unhandled_input(true);
} break;
}
}

Expand All @@ -168,6 +180,14 @@ void SubViewportContainer::_notify_viewports(int p_notification) {
}

void SubViewportContainer::input(const Ref<InputEvent> &p_event) {
_propagate_nonpositional_event(p_event);
}

void SubViewportContainer::unhandled_input(const Ref<InputEvent> &p_event) {
_propagate_nonpositional_event(p_event);
}

void SubViewportContainer::_propagate_nonpositional_event(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());

if (Engine::get_singleton()->is_editor_hint()) {
Expand Down Expand Up @@ -262,5 +282,6 @@ void SubViewportContainer::_bind_methods() {
}

SubViewportContainer::SubViewportContainer() {
set_process_input(true);
set_process_unhandled_input(true);
set_focus_mode(FOCUS_CLICK);
}
2 changes: 2 additions & 0 deletions scene/gui/subviewport_container.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class SubViewportContainer : public Container {
void _notify_viewports(int p_notification);
bool _is_propagated_in_gui_input(const Ref<InputEvent> &p_event);
void _send_event_to_viewports(const Ref<InputEvent> &p_event);
void _propagate_nonpositional_event(const Ref<InputEvent> &p_event);

protected:
void _notification(int p_what);
Expand All @@ -54,6 +55,7 @@ class SubViewportContainer : public Container {
bool is_stretch_enabled() const;

virtual void input(const Ref<InputEvent> &p_event) override;
virtual void unhandled_input(const Ref<InputEvent> &p_event) override;
virtual void gui_input(const Ref<InputEvent> &p_event) override;
void set_stretch_shrink(int p_shrink);
int get_stretch_shrink() const;
Expand Down
12 changes: 6 additions & 6 deletions scene/main/viewport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3025,18 +3025,18 @@ void Viewport::_push_unhandled_input_internal(const Ref<InputEvent> &p_event) {
get_tree()->_call_input_pause(shortcut_input_group, SceneTree::CALL_INPUT_TYPE_SHORTCUT_INPUT, p_event, this);
}

// Unhandled Input.
if (!is_input_handled()) {
ERR_FAIL_COND(!is_inside_tree());
get_tree()->_call_input_pause(unhandled_input_group, SceneTree::CALL_INPUT_TYPE_UNHANDLED_INPUT, p_event, this);
}

// Unhandled key Input - Used for performance reasons - This is called a lot less than _unhandled_input since it ignores MouseMotion, and to handle Unicode input with Alt / Ctrl modifiers after handling shortcuts.
if (!is_input_handled() && (Object::cast_to<InputEventKey>(*p_event) != nullptr)) {
ERR_FAIL_COND(!is_inside_tree());
get_tree()->_call_input_pause(unhandled_key_input_group, SceneTree::CALL_INPUT_TYPE_UNHANDLED_KEY_INPUT, p_event, this);
}

// Unhandled Input.
if (!is_input_handled()) {
ERR_FAIL_COND(!is_inside_tree());
get_tree()->_call_input_pause(unhandled_input_group, SceneTree::CALL_INPUT_TYPE_UNHANDLED_INPUT, p_event, this);
}

if (physics_object_picking && !is_input_handled()) {
if (Input::get_singleton()->get_mouse_mode() != Input::MOUSE_MODE_CAPTURED &&
(Object::cast_to<InputEventMouse>(*p_event) ||
Expand Down
Loading