Skip to content

Commit

Permalink
Introduce Window option to contain multiple Viewports with a focu…
Browse files Browse the repository at this point in the history
…sed `Control`

This PR introduces an option `Window.multi_viewport_focus` to allow all
contained `Viewports` to keep their focused `Control` independently from
other Viewports in the same `Window`.
  • Loading branch information
Sauermann committed Mar 23, 2024
1 parent fe01776 commit 65e88eb
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 4 deletions.
4 changes: 4 additions & 0 deletions doc/classes/Window.xml
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,10 @@
[b]Note:[/b] On Windows, the portion of a window that lies outside the region is not drawn, while on Linux (X11) and macOS it is.
[b]Note:[/b] This property is implemented on Linux (X11), macOS and Windows.
</member>
<member name="multi_viewport_focus" type="bool" setter="set_multi_viewport_focus" getter="is_multi_viewport_focus_enabled" default="false">
If [code]false[/code], only a single focused [Control] is allowed in [Viewport] nodes within this window. If [code]true[/code], every [Viewport] in this window keeps an independent state of their own focused [Control] node.
This setting affects only the window itself and child [SubViewport] nodes. Child [Window] nodes and their child nodes aren't affected by this setting. This is useful for splitscreen input handling.
</member>
<member name="popup_window" type="bool" setter="set_flag" getter="get_flag" default="false">
If [code]true[/code], the [Window] will be considered a popup. Popups are sub-windows that don't show as separate windows in system's window manager's window list and will send close request when anything is clicked outside of them (unless [member exclusive] is enabled).
</member>
Expand Down
31 changes: 27 additions & 4 deletions scene/main/viewport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2509,11 +2509,34 @@ bool Viewport::_gui_control_has_focus(const Control *p_control) {
}

void Viewport::_gui_control_grab_focus(Control *p_control) {
if (gui.key_focus && gui.key_focus == p_control) {
// No need for change.
return;
Window *base_window = get_base_window();
if (base_window->is_multi_viewport_focus_enabled()) {
// Release previous focus.
if (gui.key_focus && gui.key_focus != p_control) {
gui_release_focus();
}

// Ensure chain of SubViewportContainer focus in parent Viewport. Needs to happen, even if control has focus in this Viewport.
Viewport *vp = this;
if (Object::cast_to<SubViewport>(vp)) {
SubViewportContainer *svc = Object::cast_to<SubViewportContainer>(get_parent());
if (svc) {
svc->grab_focus();
}
}
if (gui.key_focus == p_control) {
// No need for change.
return;
}
} else {
if (gui.key_focus && gui.key_focus == p_control) {
// No need for change.
return;
}
get_tree()->call_group("_viewports", "_gui_remove_focus_for_window", (Node *)base_window);
}
get_tree()->call_group("_viewports", "_gui_remove_focus_for_window", (Node *)get_base_window());

// Perform necessary adjustments for focuschange.
if (p_control->is_inside_tree() && p_control->get_viewport() == this) {
gui.key_focus = p_control;
emit_signal(SNAME("gui_focus_changed"), p_control);
Expand Down
15 changes: 15 additions & 0 deletions scene/main/window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2749,6 +2749,16 @@ void Window::_mouse_leave_viewport() {
}
}

void Window::set_multi_viewport_focus(bool p_enable) {
ERR_MAIN_THREAD_GUARD;
multi_viewport_focus = p_enable;
}

bool Window::is_multi_viewport_focus_enabled() const {
ERR_READ_THREAD_GUARD_V(false);
return multi_viewport_focus;
}

void Window::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_title", "title"), &Window::set_title);
ClassDB::bind_method(D_METHOD("get_title"), &Window::get_title);
Expand Down Expand Up @@ -2903,6 +2913,9 @@ void Window::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_layout_direction"), &Window::get_layout_direction);
ClassDB::bind_method(D_METHOD("is_layout_rtl"), &Window::is_layout_rtl);

ClassDB::bind_method(D_METHOD("set_multi_viewport_focus", "enable"), &Window::set_multi_viewport_focus);
ClassDB::bind_method(D_METHOD("is_multi_viewport_focus_enabled"), &Window::is_multi_viewport_focus_enabled);

#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("set_auto_translate", "enable"), &Window::set_auto_translate);
ClassDB::bind_method(D_METHOD("is_auto_translating"), &Window::is_auto_translating);
Expand Down Expand Up @@ -2961,6 +2974,8 @@ void Window::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "content_scale_stretch", PROPERTY_HINT_ENUM, "Fractional,Integer"), "set_content_scale_stretch", "get_content_scale_stretch");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "content_scale_factor", PROPERTY_HINT_RANGE, "0.5,8.0,0.01"), "set_content_scale_factor", "get_content_scale_factor");

ADD_PROPERTY(PropertyInfo(Variant::BOOL, "multi_viewport_focus"), "set_multi_viewport_focus", "is_multi_viewport_focus_enabled");

#ifndef DISABLE_DEPRECATED
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_translate", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_auto_translate", "is_auto_translating");
#endif
Expand Down
5 changes: 5 additions & 0 deletions scene/main/window.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ class Window : public Viewport {
bool unparent_when_invisible = false;
bool keep_title_visible = false;

bool multi_viewport_focus = false;

LayoutDirection layout_dir = LAYOUT_DIRECTION_INHERITED;

void _update_child_controls();
Expand Down Expand Up @@ -474,6 +476,9 @@ class Window : public Viewport {
virtual bool is_directly_attached_to_screen() const override;
virtual bool is_attached_in_viewport() const override;

void set_multi_viewport_focus(bool p_enable);
bool is_multi_viewport_focus_enabled() const;

Rect2i get_parent_rect() const;
virtual DisplayServer::WindowID get_window_id() const override;

Expand Down

0 comments on commit 65e88eb

Please sign in to comment.