From c7b4dcae2f3b75ad7146e36f196893731f403144 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Sat, 14 Mar 2020 13:06:39 -0300 Subject: [PATCH] Open sub-windows as embedded if the OS does not support them --- editor/animation_track_editor.cpp | 5 +- editor/editor_node.cpp | 5 +- editor/editor_themes.cpp | 19 +- editor/filesystem_dock.cpp | 4 - .../animation_state_machine_editor.cpp | 6 +- editor/plugins/canvas_item_editor_plugin.cpp | 2 +- editor/plugins/spatial_editor_plugin.cpp | 2 +- editor/scene_tree_dock.cpp | 3 - main/main.cpp | 8 + platform/linuxbsd/display_server_x11.cpp | 12 +- platform/linuxbsd/display_server_x11.h | 4 +- platform/windows/display_server_windows.cpp | 57 +- platform/windows/display_server_windows.h | 4 +- scene/2d/canvas_item.cpp | 2 +- scene/gui/base_button.cpp | 3 - scene/gui/color_picker.cpp | 5 +- scene/gui/control.cpp | 195 +---- scene/gui/control.h | 19 - scene/gui/menu_button.cpp | 14 +- scene/gui/popup_menu.cpp | 11 +- scene/gui/tree.cpp | 11 +- scene/main/viewport.cpp | 760 ++++++++++++------ scene/main/viewport.h | 81 +- scene/main/window.cpp | 334 +++++--- scene/main/window.h | 25 +- .../resources/default_theme/default_theme.cpp | 21 +- servers/display_server.cpp | 2 +- servers/display_server.h | 2 +- servers/visual/visual_server_viewport.cpp | 37 +- servers/visual/visual_server_viewport.h | 8 +- servers/visual_server.cpp | 1 + servers/visual_server.h | 1 + 32 files changed, 1027 insertions(+), 636 deletions(-) diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 3da8f29697e..766df27e62d 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -2853,7 +2853,10 @@ void AnimationTrackEdit::_gui_input(const Ref &p_event) { Vector2 theme_ofs = path->get_theme_stylebox("normal", "LineEdit")->get_offset(); path->set_position(get_global_position() + path_rect.position - theme_ofs); path->set_size(path_rect.size); - path->show_modal(); +#ifndef _MSC_VER +#warning show modal not supported any longer, need to move this to a popup +#endif + path->show(); path->grab_focus(); path->set_cursor_position(path->get_text().length()); clicking_on_name = false; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 291f3dc319c..2cc6bad2a9b 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -264,11 +264,8 @@ void EditorNode::_update_title() { void EditorNode::_unhandled_input(const Ref &p_event) { - if (Node::get_viewport()->get_modal_stack_top()) - return; //ignore because of modal window - Ref k = p_event; - if (k.is_valid() && k->is_pressed() && !k->is_echo() && !gui_base->get_viewport()->gui_has_modal_stack()) { + if (k.is_valid() && k->is_pressed() && !k->is_echo()) { EditorPlugin *old_editor = editor_plugin_screen; diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index c7f353f6fb1..4eedf61a5fd 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -911,15 +911,16 @@ Ref create_editor_theme(const Ref p_theme) { style_window->set_border_width(MARGIN_TOP, 24 * EDSCALE); style_window->set_expand_margin_size(MARGIN_TOP, 24 * EDSCALE); - theme->set_stylebox("panel", "AcceptDialog", style_default); - theme->set_stylebox("panel_window", "AcceptDialog", style_window); - theme->set_color("title_color", "AcceptDialog", font_color); - theme->set_icon("close", "AcceptDialog", theme->get_icon("GuiClose", "EditorIcons")); - theme->set_icon("close_highlight", "AcceptDialog", theme->get_icon("GuiClose", "EditorIcons")); - theme->set_constant("close_h_ofs", "AcceptDialog", 22 * EDSCALE); - theme->set_constant("close_v_ofs", "AcceptDialog", 20 * EDSCALE); - theme->set_constant("title_height", "AcceptDialog", 24 * EDSCALE); - theme->set_font("title_font", "AcceptDialog", theme->get_font("title", "EditorFonts")); + theme->set_stylebox("panel", "Window", style_default); + theme->set_stylebox("panel_window", "Window", style_window); + theme->set_color("title_color", "Window", font_color); + theme->set_icon("close", "Window", theme->get_icon("GuiClose", "EditorIcons")); + theme->set_icon("close_highlight", "Window", theme->get_icon("GuiClose", "EditorIcons")); + theme->set_constant("close_h_ofs", "Window", 22 * EDSCALE); + theme->set_constant("close_v_ofs", "Window", 20 * EDSCALE); + theme->set_constant("title_height", "Window", 24 * EDSCALE); + theme->set_constant("resize_margin", "Window", 4 * EDSCALE); + theme->set_font("title_font", "Window", theme->get_font("title", "EditorFonts")); // complex window, for now only Editor settings and Project settings Ref style_complex_window = style_window->duplicate(); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index e951259cc75..e1fcddda3ac 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -2350,8 +2350,6 @@ void FileSystemDock::_file_multi_selected(int p_index, bool p_selected) { } void FileSystemDock::_tree_gui_input(Ref p_event) { - if (get_viewport()->get_modal_stack_top()) - return; // Ignore because of modal window. Ref key = p_event; if (key.is_valid() && key->is_pressed() && !key->is_echo()) { @@ -2368,8 +2366,6 @@ void FileSystemDock::_tree_gui_input(Ref p_event) { } void FileSystemDock::_file_list_gui_input(Ref p_event) { - if (get_viewport()->get_modal_stack_top()) - return; // Ignore because of modal window. Ref key = p_event; if (key.is_valid() && key->is_pressed() && !key->is_echo()) { diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index ea7a97982cf..c5979bf9528 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -158,7 +158,11 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Refset_global_position(state_machine_draw->get_global_transform().xform(edit_rect.position)); name_edit->set_size(edit_rect.size); name_edit->set_text(node_rects[i].node_name); - name_edit->show_modal(); +#ifndef _MSC_VER +#warning no more show modal, so it must replaced by a popup +#endif + //name_edit->show_modal(); + name_edit->show(); name_edit->grab_focus(); name_edit->select_all(); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 1ad0df52245..4cc0bd47802 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -477,7 +477,7 @@ void CanvasItemEditor::_unhandled_key_input(const Ref &p_ev) { Ref k = p_ev; - if (!is_visible_in_tree() || get_viewport()->gui_has_modal_stack()) + if (!is_visible_in_tree()) return; if (k->get_keycode() == KEY_CONTROL || k->get_keycode() == KEY_ALT || k->get_keycode() == KEY_SHIFT) { diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 286125d31b8..f0730f0144d 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -5718,7 +5718,7 @@ void SpatialEditor::snap_selected_nodes_to_floor() { void SpatialEditor::_unhandled_key_input(Ref p_event) { - if (!is_visible_in_tree() || get_viewport()->gui_has_modal_stack()) + if (!is_visible_in_tree()) return; snap_key_enabled = InputFilter::get_singleton()->is_key_pressed(KEY_CONTROL); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index f0b9b32c34f..613ba53fed3 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -75,9 +75,6 @@ void SceneTreeDock::_input(Ref p_event) { void SceneTreeDock::_unhandled_key_input(Ref p_event) { - if (get_viewport()->get_modal_stack_top()) - return; //ignore because of modal window - if (get_focus_owner() && get_focus_owner()->is_text_field()) return; diff --git a/main/main.cpp b/main/main.cpp index df603744b68..2ce30018290 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -120,6 +120,7 @@ static int audio_driver_idx = -1; // Engine config/tools +static bool single_window = false; static bool editor = false; static bool project_manager = false; static String locale; @@ -303,6 +304,7 @@ void Main::print_help(const char *p_binary) { OS::get_singleton()->print(" --no-window Disable window creation (Windows only). Useful together with --script.\n"); OS::get_singleton()->print(" --enable-vsync-via-compositor When vsync is enabled, vsync via the OS' window compositor (Windows only).\n"); OS::get_singleton()->print(" --disable-vsync-via-compositor Disable vsync via the OS' window compositor (Windows only).\n"); + OS::get_singleton()->print(" --single-window Use a single window (no separate subwindows).\n"); OS::get_singleton()->print("\n"); #endif @@ -576,6 +578,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } else if (I->get() == "--gpu-abort") { // force windowed window Engine::singleton->abort_on_gpu_errors = true; + } else if (I->get() == "--single-window") { // force single window + + single_window = true; } else if (I->get() == "-t" || I->get() == "--always-on-top") { // force always-on-top window init_always_on_top = true; @@ -1710,6 +1715,9 @@ bool Main::start() { } #endif + if (single_window) { + sml->get_root()->set_embed_subwindows_hint(true); + } ResourceLoader::add_custom_loaders(); ResourceSaver::add_custom_savers(); diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index b96e6b4e7af..f93dbc5371f 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -708,13 +708,13 @@ void DisplayServerX11::window_set_title(const String &p_title, WindowID p_window XChangeProperty(x11_display, wd.x11_window, _net_wm_name, utf8_string, 8, PropModeReplace, (unsigned char *)p_title.utf8().get_data(), p_title.utf8().length()); } -void DisplayServerX11::window_set_resize_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerX11::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; - wd.resize_callback = p_callable; + wd.rect_changed_callback = p_callable; } void DisplayServerX11::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) { @@ -2224,12 +2224,12 @@ void DisplayServerX11::_window_changed(XEvent *event) { } #endif - if (!wd.resize_callback.is_null()) { - Variant size = wd.size; - Variant *sizep = &size; + if (!wd.rect_changed_callback.is_null()) { + Variant rect = Rect2i(wd.im_position, wd.size); + Variant *rectp = ▭ Variant ret; Callable::CallError ce; - wd.resize_callback.call((const Variant **)&sizep, 1, ret, ce); + wd.rect_changed_callback.call((const Variant **)&rectp, 1, ret, ce); } } diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h index 9df5d876d3b..f06d8382395 100644 --- a/platform/linuxbsd/display_server_x11.h +++ b/platform/linuxbsd/display_server_x11.h @@ -121,7 +121,7 @@ class DisplayServerX11 : public DisplayServer { Size2i size; Size2i im_position; bool im_active = false; - Callable resize_callback; + Callable rect_changed_callback; Callable event_callback; Callable input_event_callback; Callable input_text_callback; @@ -268,7 +268,7 @@ public: virtual void delete_sub_window(WindowID p_id); virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID); - virtual void window_set_resize_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID); + virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID); virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID); virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID); virtual void window_set_input_text_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID); diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index e2c78da5a98..b8956328481 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -420,6 +420,10 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod } } + ShowWindow(windows[window_id].hWnd, SW_SHOW); // Show The Window + SetForegroundWindow(windows[window_id].hWnd); // Slightly Higher Priority + SetFocus(windows[window_id].hWnd); // Sets Keyboard Focus To + return window_id; } void DisplayServerWindows::delete_sub_window(WindowID p_window) { @@ -449,12 +453,12 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) { windows.erase(p_window); } -void DisplayServerWindows::window_set_resize_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerWindows::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); - windows[p_window].resize_callback = p_callable; + windows[p_window].rect_changed_callback = p_callable; } void DisplayServerWindows::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) { @@ -757,20 +761,32 @@ void DisplayServerWindows::_update_window_style(WindowID p_window, bool p_repain ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; + DWORD style = 0; + DWORD style_ex = WS_EX_WINDOWEDGE; + if (p_window == MAIN_WINDOW_ID) { + style_ex |= WS_EX_APPWINDOW; + } + if (wd.fullscreen || wd.borderless) { - SetWindowLongPtr(wd.hWnd, GWL_STYLE, WS_SYSMENU | WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE); + style = WS_SYSMENU | WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE; + if (wd.borderless) { + style_ex |= WS_EX_TOOLWINDOW; + } } else { if (wd.resizable) { if (p_maximized) { - SetWindowLongPtr(wd.hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_MAXIMIZE); + style = WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_MAXIMIZE; } else { - SetWindowLongPtr(wd.hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE); + style = GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE; } } else { - SetWindowLongPtr(wd.hWnd, GWL_STYLE, WS_CAPTION | WS_MINIMIZEBOX | WS_POPUPWINDOW | WS_VISIBLE); + style = WS_CAPTION | WS_MINIMIZEBOX | WS_POPUPWINDOW | WS_VISIBLE; } } + SetWindowLongPtr(wd.hWnd, GWL_STYLE, style); + SetWindowLongPtr(wd.hWnd, GWL_EXSTYLE, style_ex); + SetWindowPos(wd.hWnd, wd.always_on_top ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE); if (p_repaint) { @@ -2208,6 +2224,15 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA int x = LOWORD(lParam); int y = HIWORD(lParam); windows[window_id].last_pos = Point2(x, y); + + if (!windows[window_id].rect_changed_callback.is_null()) { + + Variant size = Rect2i(windows[window_id].last_pos.x, windows[window_id].last_pos.y, windows[window_id].width, windows[window_id].height); + Variant *sizep = &size; + Variant ret; + Callable::CallError ce; + windows[window_id].rect_changed_callback.call((const Variant **)&sizep, 1, ret, ce); + } } } break; @@ -2232,13 +2257,13 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } } - if (!windows[window_id].resize_callback.is_null()) { + if (!windows[window_id].rect_changed_callback.is_null()) { - Variant size = Size2(windows[window_id].width, windows[window_id].height); + Variant size = Rect2i(windows[window_id].last_pos.x, windows[window_id].last_pos.y, windows[window_id].width, windows[window_id].height); Variant *sizep = &size; Variant ret; Callable::CallError ce; - windows[window_id].resize_callback.call((const Variant **)&sizep, 1, ret, ce); + windows[window_id].rect_changed_callback.call((const Variant **)&sizep, 1, ret, ce); } if (wParam == SIZE_MAXIMIZED) { @@ -2541,9 +2566,13 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, DWORD dwExStyle; DWORD dwStyle; - dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; + dwExStyle = WS_EX_WINDOWEDGE; dwStyle = WS_OVERLAPPEDWINDOW; + if (window_id_counter == MAIN_WINDOW_ID) { + dwExStyle |= WS_EX_APPWINDOW; + } + RECT WindowRect; WindowRect.left = p_rect.position.x; @@ -2594,10 +2623,6 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, DragAcceptFiles(wd.hWnd, true); - ShowWindow(wd.hWnd, SW_SHOW); // Show The Window - SetForegroundWindow(wd.hWnd); // Slightly Higher Priority - SetFocus(wd.hWnd); // Sets Keyboard Focus To - // IME wd.im_himc = ImmGetContext(wd.hWnd); ImmReleaseContext(wd.hWnd, wd.im_himc); @@ -2743,6 +2768,10 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win } } + ShowWindow(windows[MAIN_WINDOW_ID].hWnd, SW_SHOW); // Show The Window + SetForegroundWindow(windows[MAIN_WINDOW_ID].hWnd); // Slightly Higher Priority + SetFocus(windows[MAIN_WINDOW_ID].hWnd); // Sets Keyboard Focus To + #if defined(VULKAN_ENABLED) if (rendering_driver == "vulkan") { diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 0c07e6283c8..ba9eef886bd 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -200,7 +200,7 @@ class DisplayServerWindows : public DisplayServer { bool layered_window = false; - Callable resize_callback; + Callable rect_changed_callback; Callable event_callback; Callable input_event_callback; Callable input_text_callback; @@ -293,7 +293,7 @@ public: virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()); virtual void delete_sub_window(WindowID p_window); - virtual void window_set_resize_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID); + virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID); virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID); virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID); diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 321f3f2e6fa..7a0fc3352b5 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -460,7 +460,7 @@ Transform2D CanvasItem::get_screen_transform() const { Transform2D xform = get_global_transform_with_canvas(); Window *w = Object::cast_to(get_viewport()); - if (w) { + if (w && !w->is_embedding_subwindows()) { Transform2D s; s.set_origin(w->get_position()); diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index 07bc91e7e7f..a05ac08e9da 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -357,9 +357,6 @@ void BaseButton::_unhandled_input(Ref p_event) { if (!is_disabled() && is_visible_in_tree() && !p_event->is_echo() && shortcut.is_valid() && shortcut->is_shortcut(p_event)) { - if (get_viewport()->get_modal_stack_top() && !get_viewport()->get_modal_stack_top()->is_a_parent_of(this)) - return; //ignore because of modal window - on_action_event(p_event); } } diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 2a3f7467dc4..948e46b649f 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -620,7 +620,10 @@ void ColorPicker::_screen_pick_pressed() { screen->call_deferred("connect", "hide", Callable(btn_pick, "set_pressed"), varray(false)); } screen->raise(); - screen->show_modal(); +#ifndef _MSC_VER +#warning show modal no longer works, needs to be converted to a popup +#endif + //screen->show_modal(); } void ColorPicker::_focus_enter() { diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 062d15c05b3..bfaace69d74 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -494,76 +494,54 @@ void Control::_notification(int p_notification) { data.parent = Object::cast_to(get_parent()); - if (is_set_as_toplevel()) { - data.SI = get_viewport()->_gui_add_subwindow_control(this); + Node *parent = this; //meh + Control *parent_control = NULL; + bool subwindow = false; - if (data.theme.is_null() && data.parent && data.parent->data.theme_owner) { - data.theme_owner = data.parent->data.theme_owner; - notification(NOTIFICATION_THEME_CHANGED); + while (parent) { + + parent = parent->get_parent(); + + if (!parent) + break; + + CanvasItem *ci = Object::cast_to(parent); + if (ci && ci->is_set_as_toplevel()) { + subwindow = true; + break; } - } else { - - Node *parent = this; //meh - Control *parent_control = NULL; - bool subwindow = false; - - while (parent) { - - parent = parent->get_parent(); - - if (!parent) - break; - - CanvasItem *ci = Object::cast_to(parent); - if (ci && ci->is_set_as_toplevel()) { - subwindow = true; - break; - } - - parent_control = Object::cast_to(parent); - - if (parent_control) { - break; - } else if (ci) { - - } else { - break; - } - } + parent_control = Object::cast_to(parent); if (parent_control) { - //do nothing, has a parent control - if (data.theme.is_null() && parent_control->data.theme_owner) { - data.theme_owner = parent_control->data.theme_owner; - notification(NOTIFICATION_THEME_CHANGED); - } - } else if (subwindow) { - //is a subwindow (process input before other controls for that canvas) - data.SI = get_viewport()->_gui_add_subwindow_control(this); + break; + } else if (ci) { + } else { - //is a regular root control - data.RI = get_viewport()->_gui_add_root_control(this); - } - - data.parent_canvas_item = get_parent_item(); - - if (data.parent_canvas_item) { - - data.parent_canvas_item->connect("item_rect_changed", callable_mp(this, &Control::_size_changed)); - } else { - //connect viewport - get_viewport()->connect("size_changed", callable_mp(this, &Control::_size_changed)); + break; } } - /* - if (data.theme.is_null() && data.parent && data.parent->data.theme_owner) { - data.theme_owner=data.parent->data.theme_owner; - notification(NOTIFICATION_THEME_CHANGED); + if (parent_control && !subwindow) { + //do nothing, has a parent control and not toplevel + if (data.theme.is_null() && parent_control->data.theme_owner) { + data.theme_owner = parent_control->data.theme_owner; + notification(NOTIFICATION_THEME_CHANGED); + } + } else { + //is a regular root control or toplevel + data.RI = get_viewport()->_gui_add_root_control(this); } - */ + data.parent_canvas_item = get_parent_item(); + + if (data.parent_canvas_item) { + + data.parent_canvas_item->connect("item_rect_changed", callable_mp(this, &Control::_size_changed)); + } else { + //connect viewport + get_viewport()->connect("size_changed", callable_mp(this, &Control::_size_changed)); + } } break; case NOTIFICATION_EXIT_CANVAS: { @@ -576,16 +554,6 @@ void Control::_notification(int p_notification) { get_viewport()->disconnect("size_changed", callable_mp(this, &Control::_size_changed)); } - if (data.MI) { - get_viewport()->_gui_remove_modal_control(data.MI); - data.MI = NULL; - } - - if (data.SI) { - get_viewport()->_gui_remove_subwindow_control(data.SI); - data.SI = NULL; - } - if (data.RI) { get_viewport()->_gui_remove_root_control(data.RI); data.RI = NULL; @@ -608,9 +576,6 @@ void Control::_notification(int p_notification) { data.parent->update(); update(); - if (data.SI) { - get_viewport()->_gui_set_subwindow_order_dirty(); - } if (data.RI) { get_viewport()->_gui_set_root_order_dirty(); } @@ -652,10 +617,6 @@ void Control::_notification(int p_notification) { minimum_size_changed(); update(); } break; - case NOTIFICATION_MODAL_CLOSE: { - - emit_signal("modal_closed"); - } break; case NOTIFICATION_VISIBILITY_CHANGED: { if (!is_visible_in_tree()) { @@ -663,10 +624,6 @@ void Control::_notification(int p_notification) { if (get_viewport() != NULL) get_viewport()->_gui_hid_control(this); - if (is_inside_tree()) { - _modal_stack_remove(); - } - //remove key focus //remove modalness } else { @@ -790,19 +747,6 @@ void Control::set_drag_preview(Control *p_control) { get_viewport()->_gui_set_drag_preview(this, p_control); } -bool Control::is_window_modal_on_top() const { - - if (!is_inside_tree()) - return false; - - return get_viewport()->_gui_is_modal_on_top(this); -} - -uint64_t Control::get_modal_frame() const { - - return data.modal_frame; -} - Size2 Control::get_minimum_size() const { ScriptInstance *si = const_cast(this)->get_script_instance(); @@ -1720,7 +1664,7 @@ Point2 Control::get_screen_position() const { ERR_FAIL_COND_V(!is_inside_tree(), Point2()); Point2 global_pos = get_global_position(); Window *w = Object::cast_to(get_viewport()); - if (w) { + if (w && !w->is_embedding_subwindows()) { global_pos += w->get_position(); } @@ -1828,7 +1772,7 @@ Rect2 Control::get_screen_rect() const { Rect2 r(get_global_position(), get_size()); Window *w = Object::cast_to(get_viewport()); - if (w) { + if (w && !w->is_embedding_subwindows()) { r.position += w->get_position(); } @@ -2021,7 +1965,7 @@ Control *Control::find_next_valid_focus() const { next_child = const_cast(this); while (next_child) { - if (next_child->data.SI || next_child->data.RI) + if (next_child->data.RI) break; next_child = next_child->get_parent_control(); } @@ -2164,41 +2108,6 @@ bool Control::is_toplevel_control() const { return is_inside_tree() && (!data.parent_canvas_item && !data.RI && is_set_as_toplevel()); } -void Control::show_modal(bool p_exclusive) { - - ERR_FAIL_COND(!is_inside_tree()); - ERR_FAIL_COND(!data.SI); - - if (is_visible_in_tree()) - hide(); - - ERR_FAIL_COND(data.MI != NULL); - show(); - raise(); - data.modal_exclusive = p_exclusive; - data.MI = get_viewport()->_gui_show_modal(this); - data.modal_frame = Engine::get_singleton()->get_frames_drawn(); -} - -void Control::_modal_set_prev_focus_owner(ObjectID p_prev) { - data.modal_prev_focus_owner = p_prev; -} - -void Control::_modal_stack_remove() { - - ERR_FAIL_COND(!is_inside_tree()); - - if (!data.MI) - return; - - List::Element *element = data.MI; - data.MI = NULL; - - get_viewport()->_gui_remove_from_modal_stack(element, data.modal_prev_focus_owner); - - data.modal_prev_focus_owner = ObjectID(); -} - void Control::_propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_assign) { Control *c = Object::cast_to(p_at); @@ -2444,8 +2353,6 @@ Control *Control::_get_focus_neighbour(Margin p_margin, int p_count) { Control *c = Object::cast_to(base); if (c) { - if (c->data.SI) - break; if (c->data.RI) break; } @@ -2515,7 +2422,7 @@ void Control::_window_find_focus_neighbour(const Vector2 &p_dir, Node *p_at, con Node *child = p_at->get_child(i); Control *childc = Object::cast_to(child); - if (childc && childc->data.SI) + if (childc && childc->data.RI) continue; //subwindow, ignore _window_find_focus_neighbour(p_dir, p_at->get_child(i), p_points, p_min, r_closest_dist, r_closest); } @@ -2609,16 +2516,6 @@ Control::MouseFilter Control::get_mouse_filter() const { return data.mouse_filter; } -void Control::set_pass_on_modal_close_click(bool p_pass_on) { - - data.pass_on_modal_close_click = p_pass_on; -} - -bool Control::pass_on_modal_close_click() const { - - return data.pass_on_modal_close_click; -} - Control *Control::get_focus_owner() const { ERR_FAIL_COND_V(!is_inside_tree(), NULL); @@ -2712,7 +2609,7 @@ Control *Control::get_root_parent_control() const { if (c) { root = c; - if (c->data.RI || c->data.MI || c->is_toplevel_control()) + if (c->data.RI || c->is_toplevel_control()) break; } @@ -2864,7 +2761,6 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("get_global_position"), &Control::get_global_position); ClassDB::bind_method(D_METHOD("get_rect"), &Control::get_rect); ClassDB::bind_method(D_METHOD("get_global_rect"), &Control::get_global_rect); - ClassDB::bind_method(D_METHOD("show_modal", "exclusive"), &Control::show_modal, DEFVAL(false)); ClassDB::bind_method(D_METHOD("set_focus_mode", "mode"), &Control::set_focus_mode); ClassDB::bind_method(D_METHOD("get_focus_mode"), &Control::get_focus_mode); ClassDB::bind_method(D_METHOD("has_focus"), &Control::has_focus); @@ -3024,7 +2920,6 @@ void Control::_bind_methods() { BIND_CONSTANT(NOTIFICATION_FOCUS_ENTER); BIND_CONSTANT(NOTIFICATION_FOCUS_EXIT); BIND_CONSTANT(NOTIFICATION_THEME_CHANGED); - BIND_CONSTANT(NOTIFICATION_MODAL_CLOSE); BIND_CONSTANT(NOTIFICATION_SCROLL_BEGIN); BIND_CONSTANT(NOTIFICATION_SCROLL_END); @@ -3093,7 +2988,6 @@ void Control::_bind_methods() { ADD_SIGNAL(MethodInfo("focus_exited")); ADD_SIGNAL(MethodInfo("size_flags_changed")); ADD_SIGNAL(MethodInfo("minimum_size_changed")); - ADD_SIGNAL(MethodInfo("modal_closed")); ADD_SIGNAL(MethodInfo("theme_changed")); BIND_VMETHOD(MethodInfo(Variant::BOOL, "has_point", PropertyInfo(Variant::VECTOR2, "point"))); @@ -3103,14 +2997,10 @@ Control::Control() { data.parent = NULL; data.mouse_filter = MOUSE_FILTER_STOP; - data.pass_on_modal_close_click = true; - data.SI = NULL; - data.MI = NULL; data.RI = NULL; data.theme_owner = NULL; data.theme_owner_window = NULL; - data.modal_exclusive = false; data.default_cursor = CURSOR_ARROW; data.h_size_flags = SIZE_FILL; data.v_size_flags = SIZE_FILL; @@ -3119,7 +3009,6 @@ Control::Control() { data.parent_canvas_item = NULL; data.scale = Vector2(1, 1); - data.modal_frame = 0; data.block_minimum_size_adjust = false; data.disable_visibility_clip = false; data.h_grow = GROW_DIRECTION_END; diff --git a/scene/gui/control.h b/scene/gui/control.h index 22839df7121..c52e80fa705 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -168,8 +168,6 @@ private: float expand; Point2 custom_minimum_size; - bool pass_on_modal_close_click; - MouseFilter mouse_filter; bool clip_contents; @@ -179,22 +177,16 @@ private: Control *parent; ObjectID drag_owner; - bool modal_exclusive; - uint64_t modal_frame; //frame used to put something as modal Ref theme; Control *theme_owner; Window *theme_owner_window; String tooltip; CursorShape default_cursor; - List::Element *MI; //modal item - List::Element *SI; List::Element *RI; CanvasItem *parent_canvas_item; - ObjectID modal_prev_focus_owner; - NodePath focus_neighbour[4]; NodePath focus_next; NodePath focus_prev; @@ -240,8 +232,6 @@ private: Transform2D _get_internal_transform() const; friend class Viewport; - void _modal_stack_remove(); - void _modal_set_prev_focus_owner(ObjectID p_prev); void _update_minimum_size_cache(); friend class Window; @@ -293,7 +283,6 @@ public: NOTIFICATION_FOCUS_ENTER = 43, NOTIFICATION_FOCUS_EXIT = 44, NOTIFICATION_THEME_CHANGED = 45, - NOTIFICATION_MODAL_CLOSE = 46, NOTIFICATION_SCROLL_BEGIN = 47, NOTIFICATION_SCROLL_END = 48, @@ -341,9 +330,6 @@ public: void set_custom_minimum_size(const Size2 &p_custom); Size2 get_custom_minimum_size() const; - bool is_window_modal_on_top() const; - uint64_t get_modal_frame() const; //frame in which this was made modal - Control *get_parent_control() const; /* POSITIONING */ @@ -398,8 +384,6 @@ public: void set_scale(const Vector2 &p_scale); Vector2 get_scale() const; - void show_modal(bool p_exclusive = false); - void set_theme(const Ref &p_theme); Ref get_theme() const; @@ -438,9 +422,6 @@ public: void set_mouse_filter(MouseFilter p_filter); MouseFilter get_mouse_filter() const; - void set_pass_on_modal_close_click(bool p_pass_on); - bool pass_on_modal_close_click() const; - /* SKINNING */ void add_theme_icon_override(const StringName &p_name, const Ref &p_icon); diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index 4cae7b8f40f..61441ff9586 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -43,20 +43,24 @@ void MenuButton::_unhandled_key_input(Ref p_event) { if (!get_parent() || !is_visible_in_tree() || is_disabled()) return; - bool global_only = (get_viewport()->get_modal_stack_top() && !get_viewport()->get_modal_stack_top()->is_a_parent_of(this)); - - if (popup->activate_item_by_event(p_event, global_only)) + //bool global_only = (get_viewport()->get_modal_stack_top() && !get_viewport()->get_modal_stack_top()->is_a_parent_of(this)); + //if (popup->activate_item_by_event(p_event, global_only)) + // accept_event(); + if (popup->activate_item_by_event(p_event, false)) accept_event(); } } void MenuButton::pressed() { - emit_signal("about_to_popup"); Size2 size = get_size(); Point2 gp = get_screen_position(); - popup->set_position(gp + Size2(0, size.height * get_global_transform().get_scale().y)); + + gp.y += get_size().y; + + popup->set_position(gp); + popup->set_size(Size2(size.width, 0)); popup->set_parent_rect(Rect2(Point2(gp - popup->get_position()), get_size())); popup->popup(); diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 6951026dec4..e325f2661a6 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -163,7 +163,7 @@ void PopupMenu::_activate_submenu(int over) { Point2 pos = p + Point2(get_size().width, items[over]._ofs_cache - style->get_offset().y); Size2 size = pm->get_size(); // fix pos - if (pos.x + size.width > get_screen_rect().size.width) + if (pos.x + size.width > get_parent_rect().size.width) pos.x = p.x - size.width; pm->set_position(pos); @@ -203,7 +203,7 @@ void PopupMenu::_scroll(float p_factor, const Point2 &p_over) { dy = MIN(dy, limit); } else if (dy < 0) { const float global_bottom = get_position().y + get_size().y; - const float viewport_height = get_screen_rect().size.y; + const float viewport_height = get_parent_rect().size.y; const float limit = global_bottom > viewport_height ? global_bottom - viewport_height : 0; dy = -MIN(-dy, limit); } @@ -295,7 +295,7 @@ void PopupMenu::_gui_input(const Ref &p_event) { case BUTTON_WHEEL_DOWN: { - if (get_position().y + get_size().y > get_screen_rect().size.y) { + if (get_position().y + get_size().y > get_parent_rect().size.y) { _scroll(-b->get_factor(), b->get_position()); } } break; @@ -382,7 +382,7 @@ void PopupMenu::_gui_input(const Ref &p_event) { Ref pan_gesture = p_event; if (pan_gesture.is_valid()) { - if (get_position().y + get_size().y > get_screen_rect().size.y || get_position().y < 0) { + if (get_position().y + get_size().y > get_parent_rect().size.y || get_position().y < 0) { _scroll(-pan_gesture->get_delta().y, pan_gesture->get_position()); } } @@ -591,6 +591,9 @@ void PopupMenu::_notification(int p_what) { initial_button_mask = InputFilter::get_singleton()->get_mouse_button_mask(); during_grabbed_click = (bool)initial_button_mask; + } break; + case NOTIFICATION_WM_SIZE_CHANGED: { + } break; case NOTIFICATION_VISIBILITY_CHANGED: { diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 7bac82bf63d..38ae1f36bc5 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -2819,7 +2819,10 @@ bool Tree::edit_selected() { value_editor->set_position(textedpos + Point2i(0, text_editor->get_size().height)); value_editor->set_size(Size2(rect.size.width, 1)); - value_editor->show_modal(); +#ifndef _MSC_VER +#warning show modal no longer works, need to replace by a popup +#endif + value_editor->show(); updating_value_editor = true; value_editor->set_min(c.min); value_editor->set_max(c.max); @@ -2828,8 +2831,10 @@ bool Tree::edit_selected() { value_editor->set_exp_ratio(c.expr); updating_value_editor = false; } - - text_editor->show_modal(); +#ifndef _MSC_VER +#warning show modal no longer works, need to replace by a popup +#endif + text_editor->show(); text_editor->grab_focus(); return true; } diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 50d0520d4b8..0dcb013c376 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -187,6 +187,7 @@ public: Viewport::GUI::GUI() { embed_subwindows_hint = false; + embedding_subwindows = false; dragging = false; mouse_focus = NULL; @@ -198,8 +199,6 @@ Viewport::GUI::GUI() { tooltip = NULL; tooltip_popup = NULL; tooltip_label = NULL; - subwindow_visibility_dirty = false; - subwindow_order_dirty = false; } ///////////////////////////////////// @@ -236,6 +235,180 @@ void Viewport::_collision_object_input_event(CollisionObject *p_object, Camera * physics_last_id = id; } +void Viewport::_sub_window_update_order() { + + for (int i = 0; i < gui.sub_windows.size(); i++) { + VS::get_singleton()->canvas_item_set_draw_index(gui.sub_windows[i].canvas_item, i); + } +} + +void Viewport::_sub_window_register(Window *p_window) { + + ERR_FAIL_COND(!is_inside_tree()); + for (int i = 0; i < gui.sub_windows.size(); i++) { + ERR_FAIL_COND(gui.sub_windows[i].window == p_window); + } + + if (gui.sub_windows.size() == 0) { + subwindow_canvas = VS::get_singleton()->canvas_create(); + VS::get_singleton()->viewport_attach_canvas(viewport, subwindow_canvas); + VS::get_singleton()->viewport_set_canvas_stacking(viewport, subwindow_canvas, SUBWINDOW_CANVAS_LAYER, 0); + } + SubWindow sw; + sw.canvas_item = VS::get_singleton()->canvas_item_create(); + VS::get_singleton()->canvas_item_set_parent(sw.canvas_item, subwindow_canvas); + sw.window = p_window; + gui.sub_windows.push_back(sw); + + _sub_window_grab_focus(p_window); + + VisualServer::get_singleton()->viewport_set_parent_viewport(p_window->viewport, viewport); +} + +void Viewport::_sub_window_update(Window *p_window) { + + int index = -1; + for (int i = 0; i < gui.sub_windows.size(); i++) { + if (gui.sub_windows[i].window == p_window) { + index = i; + break; + } + } + + ERR_FAIL_COND(index == -1); + + const SubWindow &sw = gui.sub_windows[index]; + + Transform2D pos; + pos.set_origin(p_window->get_position()); + VS::get_singleton()->canvas_item_clear(sw.canvas_item); + Rect2i r = Rect2i(p_window->get_position(), sw.window->get_size()); + + if (!p_window->get_flag(Window::FLAG_BORDERLESS)) { + Ref panel = p_window->get_theme_stylebox("panel_window"); + panel->draw(sw.canvas_item, r); + + // Draw the title bar text. + Ref title_font = p_window->get_theme_font("title_font"); + Color title_color = p_window->get_theme_color("title_color"); + int title_height = p_window->get_theme_constant("title_height"); + int font_height = title_font->get_height() - title_font->get_descent() * 2; + int x = (r.size.width - title_font->get_string_size(p_window->get_title()).x) / 2; + int y = (-title_height + font_height) / 2; + + int close_h_ofs = p_window->get_theme_constant("close_h_ofs"); + int close_v_ofs = p_window->get_theme_constant("close_v_ofs"); + + title_font->draw(sw.canvas_item, r.position + Point2(x, y), p_window->get_title(), title_color, r.size.width - panel->get_minimum_size().x - close_h_ofs); + + bool hl = gui.subwindow_focused == sw.window && gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE && gui.subwindow_drag_close_inside; + + Ref close_icon = p_window->get_theme_icon(hl ? "close_highlight" : "close"); + close_icon->draw(sw.canvas_item, r.position + Vector2(r.size.width - close_h_ofs, -close_v_ofs)); + } + + VS::get_singleton()->canvas_item_add_texture_rect(sw.canvas_item, r, sw.window->get_texture()->get_rid()); +} + +void Viewport::_sub_window_grab_focus(Window *p_window) { + + if (p_window == nullptr) { + //release current focus + if (gui.subwindow_focused) { + gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT); + gui.subwindow_focused = nullptr; + gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED; + } + + Window *this_window = Object::cast_to(this); + if (this_window) { + this_window->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN); + } + + return; + } + int index = -1; + for (int i = 0; i < gui.sub_windows.size(); i++) { + if (gui.sub_windows[i].window == p_window) { + index = i; + break; + } + } + + ERR_FAIL_COND(index == -1); + + if (gui.subwindow_focused) { + if (gui.subwindow_focused == p_window) { + return; //nothing to do + } + gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT); + gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED; + } else { + Window *this_window = Object::cast_to(this); + if (this_window) { + this_window->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT); + } + } + + Window *old_focus = gui.subwindow_focused; + + gui.subwindow_focused = p_window; + + gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN); + + { //move to foreground + SubWindow sw = gui.sub_windows[index]; + gui.sub_windows.remove(index); + gui.sub_windows.push_back(sw); + index = gui.sub_windows.size() - 1; + _sub_window_update_order(); + } + + if (old_focus) { + _sub_window_update(old_focus); + } + + _sub_window_update(p_window); +} + +void Viewport::_sub_window_remove(Window *p_window) { + + for (int i = 0; i < gui.sub_windows.size(); i++) { + if (gui.sub_windows[i].window == p_window) { + VS::get_singleton()->free(gui.sub_windows[i].canvas_item); + gui.sub_windows.remove(i); + break; + } + } + + if (gui.sub_windows.size() == 0) { + VS::get_singleton()->free(subwindow_canvas); + subwindow_canvas = RID(); + } + + if (gui.subwindow_focused == p_window) { + Window *parent_visible = p_window->get_parent_visible_window(); + + gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED; + + gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT); + + if (parent_visible && parent_visible != this) { + + gui.subwindow_focused = parent_visible; + gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN); + } else { + gui.subwindow_focused = nullptr; + Window *this_window = Object::cast_to(this); + if (this_window) { + this_window->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN); + } + } + } + + VisualServer::get_singleton()->viewport_set_parent_viewport(p_window->viewport, p_window->parent ? p_window->parent->viewport : RID()); +} + void Viewport::_own_world_changed() { ERR_FAIL_COND(world.is_null()); ERR_FAIL_COND(own_world.is_null()); @@ -263,6 +436,8 @@ void Viewport::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { + gui.embedding_subwindows = gui.embed_subwindows_hint; + if (get_parent()) { parent = get_parent()->get_viewport(); VisualServer::get_singleton()->viewport_set_parent_viewport(viewport, parent->get_viewport_rid()); @@ -297,7 +472,6 @@ void Viewport::_notification(int p_what) { //VisualServer::get_singleton()->instance_geometry_set_flag(contact_3d_debug_instance, VS::INSTANCE_FLAG_VISIBLE_IN_ALL_ROOMS, true); } - VS::get_singleton()->viewport_set_active(viewport, true); } break; case NOTIFICATION_READY: { #ifndef _3D_DISABLED @@ -358,6 +532,7 @@ void Viewport::_notification(int p_what) { remove_from_group("_viewports"); VS::get_singleton()->viewport_set_active(viewport, false); + VisualServer::get_singleton()->viewport_set_parent_viewport(viewport, RID()); } break; case NOTIFICATION_INTERNAL_PROCESS: { @@ -1318,25 +1493,16 @@ Transform2D Viewport::_get_input_pre_xform() const { return pre_xf; } -Vector2 Viewport::_get_window_offset() const { - - if (get_parent() && get_parent()->has_method("get_global_position")) { - return get_parent()->call("get_global_position"); - } - return Vector2(); -} - Ref Viewport::_make_input_local(const Ref &ev) { - Vector2 vp_ofs = _get_window_offset(); Transform2D ai = get_final_transform().affine_inverse() * _get_input_pre_xform(); - return ev->xformed_by(ai, -vp_ofs); + return ev->xformed_by(ai); } Vector2 Viewport::get_mouse_position() const { - return (get_final_transform().affine_inverse() * _get_input_pre_xform()).xform(InputFilter::get_singleton()->get_mouse_position() - _get_window_offset()); + return gui.last_mouse_pos; } void Viewport::warp_mouse(const Vector2 &p_pos) { @@ -1345,40 +1511,6 @@ void Viewport::warp_mouse(const Vector2 &p_pos) { InputFilter::get_singleton()->warp_mouse_position(gpos); } -void Viewport::_gui_prepare_subwindows() { - - if (gui.subwindow_visibility_dirty) { - - gui.subwindows.clear(); - for (List::Element *E = gui.all_known_subwindows.front(); E; E = E->next()) { - if (E->get()->is_visible_in_tree()) { - gui.subwindows.push_back(E->get()); - } - } - - gui.subwindow_visibility_dirty = false; - gui.subwindow_order_dirty = true; - } - - _gui_sort_subwindows(); -} - -void Viewport::_gui_sort_subwindows() { - - if (!gui.subwindow_order_dirty) - return; - - gui.modal_stack.sort_custom(); - gui.subwindows.sort_custom(); - - gui.subwindow_order_dirty = false; -} - -void Viewport::_gui_sort_modal_stack() { - - gui.modal_stack.sort_custom(); -} - void Viewport::_gui_sort_roots() { if (!gui.roots_order_dirty) @@ -1581,26 +1713,7 @@ void Viewport::_gui_call_notification(Control *p_control, int p_what) { } Control *Viewport::_gui_find_control(const Point2 &p_global) { - _gui_prepare_subwindows(); - - for (List::Element *E = gui.subwindows.back(); E; E = E->prev()) { - - Control *sw = E->get(); - if (!sw->is_visible_in_tree()) - continue; - - Transform2D xform; - CanvasItem *pci = sw->get_parent_item(); - if (pci) - xform = pci->get_global_transform_with_canvas(); - else - xform = sw->get_canvas_transform(); - - Control *ret = _gui_find_control_at_pos(sw, p_global, xform, gui.focus_inv_xform); - if (ret) - return ret; - } - + //aca va subwindows _gui_sort_roots(); for (List::Element *E = gui.roots.back(); E; E = E->prev()) { @@ -1629,8 +1742,6 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_ if (Object::cast_to(p_node)) return NULL; - //subwindows first!! - if (!p_node->is_visible()) { //return _find_next_visible_control_at_pos(p_node,p_global,r_inv_xform); return NULL; //canvas item hidden, discard @@ -1735,39 +1846,6 @@ void Viewport::_gui_input_event(Ref p_event) { bool is_handled = false; - _gui_sort_modal_stack(); - while (!gui.modal_stack.empty()) { - - Control *top = gui.modal_stack.back()->get(); - Vector2 pos2 = top->get_global_transform_with_canvas().affine_inverse().xform(mpos); - if (!top->has_point(pos2)) { - - if (top->data.modal_exclusive || top->data.modal_frame == Engine::get_singleton()->get_frames_drawn()) { - //cancel event, sorry, modal exclusive EATS UP ALL - //alternative, you can't pop out a window the same frame it was made modal (fixes many issues) - set_input_as_handled(); - - return; // no one gets the event if exclusive NO ONE - } - - if (mb->get_button_index() == BUTTON_WHEEL_UP || mb->get_button_index() == BUTTON_WHEEL_DOWN || mb->get_button_index() == BUTTON_WHEEL_LEFT || mb->get_button_index() == BUTTON_WHEEL_RIGHT) { - //cancel scroll wheel events, only clicks should trigger focus changes. - set_input_as_handled(); - return; - } - - top->notification(Control::NOTIFICATION_MODAL_CLOSE); - top->_modal_stack_remove(); - top->hide(); - - if (!top->pass_on_modal_close_click()) { - is_handled = true; - } - } else { - break; - } - } - if (is_handled) { set_input_as_handled(); return; @@ -1990,15 +2068,6 @@ void Viewport::_gui_input_event(Ref p_event) { over = _gui_find_control(mpos); } - if (gui.drag_data.get_type() == Variant::NIL && over && !gui.modal_stack.empty()) { - - Control *top = gui.modal_stack.back()->get(); - - if (over != top && !top->is_a_parent_of(over)) { - over = NULL; //nothing can be found outside the modal stack - } - } - if (over != gui.mouse_over) { if (gui.mouse_over) { @@ -2039,11 +2108,6 @@ void Viewport::_gui_input_event(Ref p_event) { bool can_tooltip = true; - if (!gui.modal_stack.empty()) { - if (gui.modal_stack.back()->get() != over && !gui.modal_stack.back()->get()->is_a_parent_of(over)) - can_tooltip = false; - } - bool is_tooltip_shown = false; if (gui.tooltip_popup) { @@ -2122,14 +2186,6 @@ void Viewport::_gui_input_event(Ref p_event) { Control *over = _gui_find_control(pos); if (over) { - if (!gui.modal_stack.empty()) { - - Control *top = gui.modal_stack.back()->get(); - if (over != top && !top->is_a_parent_of(over)) { - - return; - } - } if (over->can_process()) { touch_event = touch_event->xformed_by(Transform2D()); //make a copy @@ -2195,14 +2251,6 @@ void Viewport::_gui_input_event(Ref p_event) { } if (over) { - if (!gui.modal_stack.empty()) { - - Control *top = gui.modal_stack.back()->get(); - if (over != top && !top->is_a_parent_of(over)) { - - return; - } - } if (over->can_process()) { Transform2D localizer = over->get_global_transform_with_canvas().affine_inverse(); @@ -2246,21 +2294,6 @@ void Viewport::_gui_input_event(Ref p_event) { } } - if (p_event->is_pressed() && p_event->is_action("ui_cancel") && !gui.modal_stack.empty()) { - - _gui_sort_modal_stack(); - Control *top = gui.modal_stack.back()->get(); - if (!top->data.modal_exclusive) { - - top->notification(Control::NOTIFICATION_MODAL_CLOSE); - top->_modal_stack_remove(); - top->hide(); - // Close modal, set input as handled - set_input_as_handled(); - return; - } - } - Control *from = gui.key_focus ? gui.key_focus : NULL; //hmm //keyboard focus @@ -2319,61 +2352,10 @@ List::Element *Viewport::_gui_add_root_control(Control *p_control) { return gui.roots.push_back(p_control); } -List::Element *Viewport::_gui_add_subwindow_control(Control *p_control) { - - p_control->connect("visibility_changed", callable_mp(this, &Viewport::_subwindow_visibility_changed)); - - if (p_control->is_visible_in_tree()) { - gui.subwindow_order_dirty = true; - gui.subwindows.push_back(p_control); - } - - return gui.all_known_subwindows.push_back(p_control); -} - -void Viewport::_gui_set_subwindow_order_dirty() { - gui.subwindow_order_dirty = true; -} - void Viewport::_gui_set_root_order_dirty() { gui.roots_order_dirty = true; } -void Viewport::_gui_remove_modal_control(List::Element *MI) { - - gui.modal_stack.erase(MI); -} - -void Viewport::_gui_remove_from_modal_stack(List::Element *MI, ObjectID p_prev_focus_owner) { - - //transfer the focus stack to the next - - List::Element *next = MI->next(); - - gui.modal_stack.erase(MI); - - if (p_prev_focus_owner.is_valid()) { - - // for previous window in stack, pass the focus so it feels more - // natural - - if (!next) { //top of stack - - Object *pfo = ObjectDB::get_instance(p_prev_focus_owner); - Control *pfoc = Object::cast_to(pfo); - if (!pfoc) - return; - - if (!pfoc->is_inside_tree() || !pfoc->is_visible_in_tree()) - return; - pfoc->grab_focus(); - } else { - - next->get()->_modal_set_prev_focus_owner(p_prev_focus_owner); - } - } -} - void Viewport::_gui_force_drag(Control *p_base, const Variant &p_data, Control *p_control) { ERR_FAIL_COND_MSG(p_data.get_type() == Variant::NIL, "Drag data must be a value."); @@ -2410,21 +2392,6 @@ void Viewport::_gui_remove_root_control(List::Element *RI) { gui.roots.erase(RI); } -void Viewport::_gui_remove_subwindow_control(List::Element *SI) { - - ERR_FAIL_COND(!SI); - - Control *control = SI->get(); - - control->disconnect("visibility_changed", callable_mp(this, &Viewport::_subwindow_visibility_changed)); - - List::Element *E = gui.subwindows.find(control); - if (E) - gui.subwindows.erase(E); - - gui.all_known_subwindows.erase(SI); -} - void Viewport::_gui_unfocus_control(Control *p_control) { if (gui.key_focus == p_control) { @@ -2485,11 +2452,6 @@ void Viewport::_gui_remove_focus() { } } -bool Viewport::_gui_is_modal_on_top(const Control *p_control) { - - return (gui.modal_stack.size() && gui.modal_stack.back()->get() == p_control); -} - bool Viewport::_gui_control_has_focus(const Control *p_control) { return gui.key_focus == p_control; @@ -2561,22 +2523,6 @@ void Viewport::_drop_physics_mouseover() { #endif } -List::Element *Viewport::_gui_show_modal(Control *p_control) { - - List::Element *node = gui.modal_stack.push_back(p_control); - if (gui.key_focus) - p_control->_modal_set_prev_focus_owner(gui.key_focus->get_instance_id()); - else - p_control->_modal_set_prev_focus_owner(ObjectID()); - - if (gui.mouse_focus && !p_control->is_a_parent_of(gui.mouse_focus) && !gui.mouse_click_grabber) { - - _drop_mouse_focus(); - } - - return node; -} - Control *Viewport::_gui_get_focus_owner() { return gui.key_focus; @@ -2647,10 +2593,317 @@ void Viewport::_post_gui_grab_click_focus() { void Viewport::input_text(const String &p_text) { + if (gui.subwindow_focused) { + gui.subwindow_focused->input_text(p_text); + return; + } + if (gui.key_focus) { gui.key_focus->call("set_text", p_text); } } +Viewport::SubWindowResize Viewport::_sub_window_get_resize_margin(Window *p_subwindow, const Point2 &p_point) { + + if (p_subwindow->get_flag(Window::FLAG_BORDERLESS)) { + return SUB_WINDOW_RESIZE_DISABLED; + } + + Rect2i r = Rect2i(p_subwindow->get_position(), p_subwindow->get_size()); + + int title_height = p_subwindow->get_theme_constant("title_height"); + + r.position.y -= title_height; + r.size.y += title_height; + + if (r.has_point(p_point)) { + return SUB_WINDOW_RESIZE_DISABLED; //it's inside, so no resize + } + + int dist_x = p_point.x < r.position.x ? (p_point.x - r.position.x) : (p_point.x > (r.position.x + r.size.x) ? (p_point.x - (r.position.x + r.size.x)) : 0); + int dist_y = p_point.y < r.position.y ? (p_point.y - r.position.y) : (p_point.y > (r.position.y + r.size.y) ? (p_point.y - (r.position.y + r.size.y)) : 0); + + int limit = p_subwindow->get_theme_constant("resize_margin"); + + if (ABS(dist_x) > limit) { + return SUB_WINDOW_RESIZE_DISABLED; + } + + if (ABS(dist_y) > limit) { + return SUB_WINDOW_RESIZE_DISABLED; + } + + if (dist_x < 0 && dist_y < 0) { + return SUB_WINDOW_RESIZE_TOP_LEFT; + } + + if (dist_x == 0 && dist_y < 0) { + return SUB_WINDOW_RESIZE_TOP; + } + + if (dist_x > 0 && dist_y < 0) { + return SUB_WINDOW_RESIZE_TOP_RIGHT; + } + + if (dist_x < 0 && dist_y == 0) { + return SUB_WINDOW_RESIZE_LEFT; + } + + if (dist_x > 0 && dist_y == 0) { + return SUB_WINDOW_RESIZE_RIGHT; + } + + if (dist_x < 0 && dist_y > 0) { + return SUB_WINDOW_RESIZE_BOTTOM_LEFT; + } + + if (dist_x == 0 && dist_y > 0) { + return SUB_WINDOW_RESIZE_BOTTOM; + } + + if (dist_x > 0 && dist_y > 0) { + return SUB_WINDOW_RESIZE_BOTTOM_RIGHT; + } + + return SUB_WINDOW_RESIZE_DISABLED; +} +bool Viewport::_sub_windows_forward_input(const Ref &p_event) { + + if (gui.subwindow_drag != SUB_WINDOW_DRAG_DISABLED) { + + ERR_FAIL_COND_V(gui.subwindow_focused == nullptr, false); + + Ref mb = p_event; + if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + + if (gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE) { + if (gui.subwindow_drag_close_rect.has_point(mb->get_position())) { + //close window + gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_CLOSE_REQUEST); + } + } + gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED; + if (gui.subwindow_focused != nullptr) { //may have been erased + _sub_window_update(gui.subwindow_focused); + } + } + + Ref mm = p_event; + if (mm.is_valid()) { + + if (gui.subwindow_drag == SUB_WINDOW_DRAG_MOVE) { + Vector2 diff = mm->get_position() - gui.subwindow_drag_from; + Rect2i new_rect(gui.subwindow_drag_pos + diff, gui.subwindow_focused->get_size()); + gui.subwindow_focused->_rect_changed_callback(new_rect); + } + if (gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE) { + gui.subwindow_drag_close_inside = gui.subwindow_drag_close_rect.has_point(mm->get_position()); + } + if (gui.subwindow_drag == SUB_WINDOW_DRAG_RESIZE) { + Vector2i diff = mm->get_position() - gui.subwindow_drag_from; + Size2i min_size = gui.subwindow_focused->get_min_size(); + if (gui.subwindow_focused->is_wrapping_controls()) { + Size2i cms = gui.subwindow_focused->get_contents_minimum_size(); + min_size.x = MAX(cms.x, min_size.x); + min_size.y = MAX(cms.y, min_size.y); + } + min_size.x = MAX(min_size.x, 1); + min_size.y = MAX(min_size.y, 1); + + Rect2i r = gui.subwindow_resize_from_rect; + + Size2i limit = r.size - min_size; + + switch (gui.subwindow_resize_mode) { + case SUB_WINDOW_RESIZE_TOP_LEFT: { + + diff.x = MIN(diff.x, limit.x); + diff.y = MIN(diff.y, limit.y); + r.position += diff; + r.size -= diff; + } break; + case SUB_WINDOW_RESIZE_TOP: { + diff.x = 0; + diff.y = MIN(diff.y, limit.y); + r.position += diff; + r.size -= diff; + } break; + case SUB_WINDOW_RESIZE_TOP_RIGHT: { + diff.x = MAX(diff.x, -limit.x); + diff.y = MIN(diff.y, limit.y); + r.position.y += diff.y; + r.size.y -= diff.y; + r.size.x += diff.x; + } break; + case SUB_WINDOW_RESIZE_LEFT: { + diff.x = MIN(diff.x, limit.x); + diff.y = 0; + r.position += diff; + r.size -= diff; + + } break; + case SUB_WINDOW_RESIZE_RIGHT: { + diff.x = MAX(diff.x, -limit.x); + r.size.x += diff.x; + } break; + case SUB_WINDOW_RESIZE_BOTTOM_LEFT: { + diff.x = MIN(diff.x, limit.x); + diff.y = MAX(diff.y, -limit.y); + r.position.x += diff.x; + r.size.x -= diff.x; + r.size.y += diff.y; + + } break; + case SUB_WINDOW_RESIZE_BOTTOM: { + diff.y = MAX(diff.y, -limit.y); + r.size.y += diff.y; + } break; + case SUB_WINDOW_RESIZE_BOTTOM_RIGHT: { + diff.x = MAX(diff.x, -limit.x); + diff.y = MAX(diff.y, -limit.y); + r.size += diff; + + } break; + default: { + } + } + + gui.subwindow_focused->_rect_changed_callback(r); + } + + if (gui.subwindow_focused) { //may have been erased + _sub_window_update(gui.subwindow_focused); + } + } + + return true; //handled + } + Ref mb = p_event; + //if the event is a mouse button, we need to check whether another window was clicked + + if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + + bool click_on_window = false; + for (int i = gui.sub_windows.size() - 1; i >= 0; i--) { + SubWindow &sw = gui.sub_windows.write[i]; + + //clicked inside window? + + Rect2i r = Rect2i(sw.window->get_position(), sw.window->get_size()); + + if (!sw.window->get_flag(Window::FLAG_BORDERLESS)) { + //check top bar + int title_height = sw.window->get_theme_constant("title_height"); + Rect2i title_bar = r; + title_bar.position.y -= title_height; + title_bar.size.y = title_height; + + if (title_bar.has_point(mb->get_position())) { + + click_on_window = true; + + int close_h_ofs = sw.window->get_theme_constant("close_h_ofs"); + int close_v_ofs = sw.window->get_theme_constant("close_v_ofs"); + Ref close_icon = sw.window->get_theme_icon("close"); + + Rect2 close_rect; + close_rect.position = Vector2(r.position.x + r.size.x - close_v_ofs, r.position.y - close_h_ofs); + close_rect.size = close_icon->get_size(); + + if (gui.subwindow_focused != sw.window) { + //refocus + _sub_window_grab_focus(sw.window); + } + + if (close_rect.has_point(mb->get_position())) { + + gui.subwindow_drag = SUB_WINDOW_DRAG_CLOSE; + gui.subwindow_drag_close_inside = true; //starts inside + gui.subwindow_drag_close_rect = close_rect; + } else { + + gui.subwindow_drag = SUB_WINDOW_DRAG_MOVE; + } + + gui.subwindow_drag_from = mb->get_position(); + gui.subwindow_drag_pos = sw.window->get_position(); + + _sub_window_update(sw.window); + } else { + gui.subwindow_resize_mode = _sub_window_get_resize_margin(gui.subwindow_focused, mb->get_position()); + if (gui.subwindow_resize_mode != SUB_WINDOW_RESIZE_DISABLED) { + gui.subwindow_resize_from_rect = r; + gui.subwindow_drag_from = mb->get_position(); + gui.subwindow_drag = SUB_WINDOW_DRAG_RESIZE; + click_on_window = true; + } + } + } + if (!click_on_window && r.has_point(mb->get_position())) { + //clicked, see if it needs to fetch focus + if (gui.subwindow_focused != sw.window) { + //refocus + _sub_window_grab_focus(sw.window); + } + + click_on_window = true; + } + + if (click_on_window) { + break; + } + } + + if (!click_on_window && gui.subwindow_focused) { + //no window found and clicked, remove focus + _sub_window_grab_focus(nullptr); + } + } + + if (gui.subwindow_focused) { + + Ref mm = p_event; + if (mm.is_valid()) { + + SubWindowResize resize = _sub_window_get_resize_margin(gui.subwindow_focused, mm->get_position()); + if (resize != SUB_WINDOW_RESIZE_DISABLED) { + + DisplayServer::CursorShape shapes[SUB_WINDOW_RESIZE_MAX] = { + DisplayServer::CURSOR_ARROW, + DisplayServer::CURSOR_FDIAGSIZE, + DisplayServer::CURSOR_VSIZE, + DisplayServer::CURSOR_BDIAGSIZE, + DisplayServer::CURSOR_HSIZE, + DisplayServer::CURSOR_HSIZE, + DisplayServer::CURSOR_BDIAGSIZE, + DisplayServer::CURSOR_VSIZE, + DisplayServer::CURSOR_FDIAGSIZE + }; + + DisplayServer::get_singleton()->cursor_set_shape(shapes[resize]); + + return true; //reserved for showing the resize cursor + } + } + } + + if (gui.subwindow_drag != SUB_WINDOW_DRAG_DISABLED) { + return true; // dragging, don't pass the event + } + + if (!gui.subwindow_focused) { + return false; + } + + Transform2D window_ofs; + window_ofs.set_origin(-gui.subwindow_focused->get_position()); + + Ref ev = p_event->xformed_by(window_ofs); + + gui.subwindow_focused->_window_input(ev); + + return true; +} + void Viewport::input(const Ref &p_event, bool p_local_coords) { ERR_FAIL_COND(!is_inside_tree()); @@ -2671,6 +2924,11 @@ void Viewport::input(const Ref &p_event, bool p_local_coords) { ev = p_event; } + if (is_embedding_subwindows() && _sub_windows_forward_input(p_event)) { + set_input_as_handled(); + return; + } + if (!is_input_handled()) { get_tree()->_call_input_pause(input_group, "_input", ev, this); //not a bug, must happen before GUI, order is _input -> gui input -> _unhandled input } @@ -2782,11 +3040,6 @@ Vector2 Viewport::get_camera_rect_size() const { return size; } -bool Viewport::gui_has_modal_stack() const { - - return gui.modal_stack.size(); -} - void Viewport::set_disable_input(bool p_disable) { disable_input = p_disable; } @@ -2800,10 +3053,6 @@ Variant Viewport::gui_get_drag_data() const { return gui.drag_data; } -Control *Viewport::get_modal_stack_top() const { - return gui.modal_stack.size() ? gui.modal_stack.back()->get() : NULL; -} - String Viewport::get_configuration_warning() const { /*if (get_parent() && !Object::cast_to(get_parent()) && !render_target) { @@ -3039,12 +3288,9 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("get_mouse_position"), &Viewport::get_mouse_position); ClassDB::bind_method(D_METHOD("warp_mouse", "to_position"), &Viewport::warp_mouse); - ClassDB::bind_method(D_METHOD("gui_has_modal_stack"), &Viewport::gui_has_modal_stack); ClassDB::bind_method(D_METHOD("gui_get_drag_data"), &Viewport::gui_get_drag_data); ClassDB::bind_method(D_METHOD("gui_is_dragging"), &Viewport::gui_is_dragging); - ClassDB::bind_method(D_METHOD("get_modal_stack_top"), &Viewport::get_modal_stack_top); - ClassDB::bind_method(D_METHOD("set_disable_input", "disable"), &Viewport::set_disable_input); ClassDB::bind_method(D_METHOD("is_input_disabled"), &Viewport::is_input_disabled); @@ -3157,13 +3403,6 @@ void Viewport::_bind_methods() { BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MAX); } -void Viewport::_subwindow_visibility_changed() { - - // unfortunately, we don't know the sender, i.e. which subwindow changed; - // so we have to check them all. - gui.subwindow_visibility_dirty = true; -} - Viewport::Viewport() { world_2d = Ref(memnew(World2D)); @@ -3227,6 +3466,8 @@ Viewport::Viewport() { gui.roots_order_dirty = false; gui.mouse_focus = NULL; gui.last_mouse_focus = NULL; + gui.subwindow_focused = nullptr; + gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED; msaa = MSAA_DISABLED; @@ -3302,6 +3543,16 @@ DisplayServer::WindowID SubViewport::get_window_id() const { return DisplayServer::INVALID_WINDOW_ID; } +void SubViewport::_notification(int p_what) { + + if (p_what == NOTIFICATION_ENTER_TREE) { + VS::get_singleton()->viewport_set_active(get_viewport_rid(), true); + } + if (p_what == NOTIFICATION_EXIT_TREE) { + VS::get_singleton()->viewport_set_active(get_viewport_rid(), false); + } +} + void SubViewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_use_arvr", "use"), &SubViewport::set_use_arvr); ClassDB::bind_method(D_METHOD("is_using_arvr"), &SubViewport::is_using_arvr); @@ -3323,6 +3574,7 @@ void SubViewport::_bind_methods() { BIND_ENUM_CONSTANT(UPDATE_DISABLED); BIND_ENUM_CONSTANT(UPDATE_ONCE); BIND_ENUM_CONSTANT(UPDATE_WHEN_VISIBLE); + BIND_ENUM_CONSTANT(UPDATE_WHEN_PARENT_VISIBLE); BIND_ENUM_CONSTANT(UPDATE_ALWAYS); BIND_ENUM_CONSTANT(CLEAR_MODE_ALWAYS); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 3d90eaf3b37..08dd5051614 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -151,6 +151,10 @@ public: DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MAX, }; + enum { + SUBWINDOW_CANVAS_LAYER = 1024 + }; + private: friend class ViewportTexture; @@ -183,6 +187,7 @@ private: RID viewport; RID current_canvas; + RID subwindow_canvas; bool audio_listener; RID internal_listener; @@ -269,6 +274,31 @@ private: Ref default_texture; Set viewport_textures; + enum SubWindowDrag { + SUB_WINDOW_DRAG_DISABLED, + SUB_WINDOW_DRAG_MOVE, + SUB_WINDOW_DRAG_CLOSE, + SUB_WINDOW_DRAG_RESIZE, + }; + + enum SubWindowResize { + SUB_WINDOW_RESIZE_DISABLED, + SUB_WINDOW_RESIZE_TOP_LEFT, + SUB_WINDOW_RESIZE_TOP, + SUB_WINDOW_RESIZE_TOP_RIGHT, + SUB_WINDOW_RESIZE_LEFT, + SUB_WINDOW_RESIZE_RIGHT, + SUB_WINDOW_RESIZE_BOTTOM_LEFT, + SUB_WINDOW_RESIZE_BOTTOM, + SUB_WINDOW_RESIZE_BOTTOM_RIGHT, + SUB_WINDOW_RESIZE_MAX + }; + + struct SubWindow { + Window *window; + RID canvas_item; + }; + struct GUI { // info used when this is a window @@ -290,17 +320,24 @@ private: Control *drag_preview; float tooltip_timer; float tooltip_delay; - List modal_stack; Transform2D focus_inv_xform; - bool subwindow_order_dirty; - bool subwindow_visibility_dirty; - List subwindows; // visible subwindows - List all_known_subwindows; bool roots_order_dirty; List roots; int canvas_sort_index; //for sorting items with canvas as root bool dragging; bool embed_subwindows_hint; + bool embedding_subwindows; + + Window *subwindow_focused; + SubWindowDrag subwindow_drag; + Vector2 subwindow_drag_from; + Vector2 subwindow_drag_pos; + Rect2i subwindow_drag_close_rect; + bool subwindow_drag_close_inside; + SubWindowResize subwindow_resize_mode; + Rect2i subwindow_resize_from_rect; + + Vector sub_windows; GUI(); } gui; @@ -316,10 +353,7 @@ private: void _gui_call_input(Control *p_control, const Ref &p_input); void _gui_call_notification(Control *p_control, int p_what); - void _gui_prepare_subwindows(); - void _gui_sort_subwindows(); void _gui_sort_roots(); - void _gui_sort_modal_stack(); Control *_gui_find_control(const Point2 &p_global); Control *_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform, Transform2D &r_inv_xform); @@ -334,15 +368,8 @@ private: friend class Control; List::Element *_gui_add_root_control(Control *p_control); - List::Element *_gui_add_subwindow_control(Control *p_control); - void _gui_set_subwindow_order_dirty(); - void _gui_set_root_order_dirty(); - - void _gui_remove_modal_control(List::Element *MI); - void _gui_remove_from_modal_stack(List::Element *MI, ObjectID p_prev_focus_owner); void _gui_remove_root_control(List::Element *RI); - void _gui_remove_subwindow_control(List::Element *SI); String _gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_which = NULL); void _gui_cancel_tooltip(); @@ -354,9 +381,6 @@ private: void _gui_force_drag(Control *p_base, const Variant &p_data, Control *p_control); void _gui_set_drag_preview(Control *p_base, Control *p_control); - bool _gui_is_modal_on_top(const Control *p_control); - List::Element *_gui_show_modal(Control *p_control); - void _gui_remove_focus(); void _gui_unfocus_control(Control *p_control); bool _gui_control_has_focus(const Control *p_control); @@ -367,8 +391,6 @@ private: Control *_gui_get_focus_owner(); - Vector2 _get_window_offset() const; - bool _gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_check); friend class Listener; @@ -394,8 +416,20 @@ private: void _update_canvas_items(Node *p_node); + void _gui_set_root_order_dirty(); + void _own_world_changed(); + friend class Window; + + void _sub_window_update_order(); + void _sub_window_register(Window *p_window); + void _sub_window_update(Window *p_window); + void _sub_window_grab_focus(Window *p_window); + void _sub_window_remove(Window *p_window); + bool _sub_windows_forward_input(const Ref &p_event); + SubWindowResize _sub_window_get_resize_margin(Window *p_subwindow, const Point2 &p_point); + protected: void _set_size(const Size2i &p_size, const Size2i &p_size_override, const Rect2i &p_to_screen_rect, const Transform2D &p_stretch_transform, bool p_allocated); @@ -485,10 +519,7 @@ public: void set_physics_object_picking(bool p_enable); bool get_physics_object_picking(); - bool gui_has_modal_stack() const; - Variant gui_get_drag_data() const; - Control *get_modal_stack_top() const; void gui_reset_canvas_sort_index(); int gui_get_canvas_sort_index(); @@ -503,8 +534,6 @@ public: void set_snap_controls_to_pixels(bool p_enable); bool is_snap_controls_to_pixels_enabled() const; - void _subwindow_visibility_changed(); - void set_input_as_handled(); bool is_input_handled() const; @@ -546,6 +575,7 @@ public: UPDATE_DISABLED, UPDATE_ONCE, //then goes to disabled UPDATE_WHEN_VISIBLE, // default + UPDATE_WHEN_PARENT_VISIBLE, UPDATE_ALWAYS }; @@ -557,6 +587,7 @@ private: protected: static void _bind_methods(); virtual DisplayServer::WindowID get_window_id() const; + void _notification(int p_what); public: void set_size(const Size2i &p_size); diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 6d61f3f0a82..4ea00a41879 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -37,9 +37,14 @@ #include "scene/scene_string_names.h" void Window::set_title(const String &p_title) { title = p_title; - if (window_id == DisplayServer::INVALID_WINDOW_ID) - return; - DisplayServer::get_singleton()->window_set_title(p_title, window_id); + + if (embedder) { + embedder->_sub_window_update(this); + + } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { + + DisplayServer::get_singleton()->window_set_title(p_title, window_id); + } } String Window::get_title() const { return title; @@ -61,28 +66,25 @@ int Window::get_current_screen() const { void Window::set_position(const Point2i &p_position) { position = p_position; - if (window_id == DisplayServer::INVALID_WINDOW_ID) - return; - DisplayServer::get_singleton()->window_set_position(p_position, window_id); + + if (embedder) { + embedder->_sub_window_update(this); + + } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { + + DisplayServer::get_singleton()->window_set_position(p_position, window_id); + } } Point2i Window::get_position() const { - if (window_id != DisplayServer::INVALID_WINDOW_ID) { - position = DisplayServer::get_singleton()->window_get_position(window_id); - } return position; } void Window::set_size(const Size2i &p_size) { size = p_size; - if (window_id != DisplayServer::INVALID_WINDOW_ID) { - DisplayServer::get_singleton()->window_set_size(p_size, window_id); - } - _update_size(); + _update_window_size(); } Size2i Window::get_size() const { - if (window_id != DisplayServer::INVALID_WINDOW_ID) { - size = DisplayServer::get_singleton()->window_get_size(window_id); - } + return size; } @@ -96,22 +98,19 @@ Size2i Window::get_real_size() const { void Window::set_max_size(const Size2i &p_max_size) { max_size = p_max_size; - if (window_id == DisplayServer::INVALID_WINDOW_ID) - return; - DisplayServer::get_singleton()->window_set_max_size(p_max_size, window_id); + DisplayServer::get_singleton()->window_set_min_size(max_size, window_id); + _update_window_size(); } Size2i Window::get_max_size() const { - if (window_id != DisplayServer::INVALID_WINDOW_ID) { - max_size = DisplayServer::get_singleton()->window_get_max_size(window_id); - } - return max_size; + + return min_size; } void Window::set_min_size(const Size2i &p_min_size) { + min_size = p_min_size; - if (window_id == DisplayServer::INVALID_WINDOW_ID) - return; - DisplayServer::get_singleton()->window_set_min_size(p_min_size, window_id); + DisplayServer::get_singleton()->window_set_max_size(max_size, window_id); + _update_window_size(); } Size2i Window::get_min_size() const { if (window_id != DisplayServer::INVALID_WINDOW_ID) { @@ -123,9 +122,14 @@ Size2i Window::get_min_size() const { void Window::set_mode(Mode p_mode) { mode = p_mode; - if (window_id == DisplayServer::INVALID_WINDOW_ID) - return; - DisplayServer::get_singleton()->window_set_mode(DisplayServer::WindowMode(p_mode), window_id); + + if (embedder) { + embedder->_sub_window_update(this); + + } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { + + DisplayServer::get_singleton()->window_set_mode(DisplayServer::WindowMode(p_mode), window_id); + } } Window::Mode Window::get_mode() const { @@ -139,9 +143,14 @@ Window::Mode Window::get_mode() const { void Window::set_flag(Flags p_flag, bool p_enabled) { ERR_FAIL_INDEX(p_flag, FLAG_MAX); flags[p_flag] = p_enabled; - if (window_id == DisplayServer::INVALID_WINDOW_ID) - return; - DisplayServer::get_singleton()->window_set_flag(DisplayServer::WindowFlags(p_flag), p_enabled, window_id); + + if (embedder) { + embedder->_sub_window_update(this); + + } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { + + DisplayServer::get_singleton()->window_set_flag(DisplayServer::WindowFlags(p_flag), p_enabled, window_id); + } } bool Window::get_flag(Flags p_flag) const { @@ -165,7 +174,11 @@ void Window::request_attention() { } } void Window::move_to_foreground() { - if (window_id != DisplayServer::INVALID_WINDOW_ID) { + + if (embedder) { + embedder->_sub_window_grab_focus(this); + + } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { DisplayServer::get_singleton()->window_move_to_foreground(window_id); } } @@ -178,7 +191,7 @@ bool Window::can_draw() const { return DisplayServer::get_singleton()->window_can_draw(window_id); } - return true; + return visible; } void Window::set_ime_active(bool p_active) { @@ -194,11 +207,8 @@ void Window::set_ime_position(const Point2i &p_pos) { bool Window::is_embedded() const { ERR_FAIL_COND_V(!is_inside_tree(), false); - if (get_parent_viewport()) { - return get_parent_viewport()->is_embedding_subwindows(); - } else { - return false; - } + Viewport *parent_vp = get_parent_viewport(); + return parent_vp && parent_vp->is_embedding_subwindows(); } void Window::_make_window() { @@ -210,6 +220,7 @@ void Window::_make_window() { f |= (1 << i); } } + window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), f, Rect2i(position, size)); ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID); DisplayServer::get_singleton()->window_set_current_screen(current_screen, window_id); @@ -217,7 +228,7 @@ void Window::_make_window() { DisplayServer::get_singleton()->window_set_min_size(min_size, window_id); DisplayServer::get_singleton()->window_set_title(title, window_id); - _update_size(); + _update_window_size(); if (transient_parent && transient_parent->window_id != DisplayServer::INVALID_WINDOW_ID) { DisplayServer::get_singleton()->window_set_transient(window_id, transient_parent->window_id); @@ -228,6 +239,8 @@ void Window::_make_window() { DisplayServer::get_singleton()->window_set_transient(E->get()->window_id, transient_parent->window_id); } } + + VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_WHEN_VISIBLE); } void Window::_update_from_window() { @@ -236,10 +249,6 @@ void Window::_update_from_window() { for (int i = 0; i < FLAG_MAX; i++) { flags[i] = DisplayServer::get_singleton()->window_get_flag(DisplayServer::WindowFlags(i), window_id); } - position = DisplayServer::get_singleton()->window_get_position(window_id); - size = DisplayServer::get_singleton()->window_get_size(window_id); - max_size = DisplayServer::get_singleton()->window_get_max_size(window_id); - min_size = DisplayServer::get_singleton()->window_get_min_size(window_id); } void Window::_clear_window() { @@ -256,16 +265,26 @@ void Window::_clear_window() { } _update_from_window(); - print_line("deleting window bye"); + DisplayServer::get_singleton()->delete_sub_window(window_id); window_id = DisplayServer::INVALID_WINDOW_ID; - _update_size(); + _update_viewport_size(); + + VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_DISABLED); } -void Window::_resize_callback(const Size2i &p_callback) { +void Window::_rect_changed_callback(const Rect2i &p_callback) { - size = p_callback; - _update_size(); + //we must always accept this as the truth + if (size == p_callback.size && position == p_callback.position) { + return; + } + position = p_callback.position; + + if (size != p_callback.size) { + size = p_callback.size; + _update_viewport_size(); + } } void Window::_propagate_window_notification(Node *p_node, int p_notification) { @@ -335,11 +354,15 @@ void Window::set_visible(bool p_visible) { return; } + if (updating_child_controls) { + _update_child_controls(); + } + ERR_FAIL_COND_MSG(get_parent() == nullptr, "Can't change visibility of main window."); - bool subwindow = get_parent() && get_parent()->get_viewport()->is_embedding_subwindows(); + Viewport *embedder_vp = _get_embedder(); - if (!subwindow) { + if (!embedder_vp) { if (!p_visible && window_id != DisplayServer::INVALID_WINDOW_ID) { _clear_window(); } @@ -348,7 +371,16 @@ void Window::set_visible(bool p_visible) { _update_window_callbacks(); } } else { - _update_size(); + if (visible) { + embedder = embedder_vp; + embedder->_sub_window_register(this); + VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE); + } else { + embedder->_sub_window_remove(this); + embedder = nullptr; + VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_DISABLED); + } + _update_window_size(); } if (!visible) { @@ -356,6 +388,8 @@ void Window::set_visible(bool p_visible) { } notification(NOTIFICATION_VISIBILITY_CHANGED); emit_signal(SceneStringNames::get_singleton()->visibility_changed); + + VS::get_singleton()->viewport_set_active(get_viewport_rid(), visible); } void Window::_clear_transient() { @@ -458,7 +492,38 @@ bool Window::is_visible() const { return visible; } -void Window::_update_size() { +void Window::_update_window_size() { + + Size2i size_limit; + if (wrap_controls) { + size_limit = get_contents_minimum_size(); + } + + size_limit.x = MAX(size_limit.x, min_size.x); + size_limit.y = MAX(size_limit.y, min_size.y); + + size.x = MAX(size_limit.x, size.x); + size.y = MAX(size_limit.y, size.y); + + if (max_size.x > 0 && max_size.x > min_size.x && max_size.x > size.x) { + size.x = max_size.x; + } + + if (max_size.y > 0 && max_size.y > min_size.y && max_size.y > size.y) { + size.y = max_size.y; + } + + if (embedder) { + embedder->_sub_window_update(this); + } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { + DisplayServer::get_singleton()->window_set_size(size, window_id); + } + + //update the viewport + _update_viewport_size(); +} +void Window::_update_viewport_size() { + //update the viewport part Size2i final_size; Size2i final_size_override; @@ -563,7 +628,7 @@ void Window::_update_size() { stretch_transform.elements[2] = margin * scale; } - bool allocate = is_inside_tree() && visible && (window_id != DisplayServer::INVALID_WINDOW_ID || (get_parent() && get_parent()->get_viewport()->is_embedding_subwindows())); + bool allocate = is_inside_tree() && visible && (window_id != DisplayServer::INVALID_WINDOW_ID || embedder != nullptr); _set_size(final_size, final_size_override, attach_to_screen_rect, stretch_transform, allocate); @@ -586,28 +651,78 @@ void Window::_update_size() { } notification(NOTIFICATION_WM_SIZE_CHANGED); + + if (embedder) { + embedder->_sub_window_update(this); + } } void Window::_update_window_callbacks() { - DisplayServer::get_singleton()->window_set_resize_callback(callable_mp(this, &Window::_resize_callback), window_id); + DisplayServer::get_singleton()->window_set_rect_changed_callback(callable_mp(this, &Window::_rect_changed_callback), window_id); DisplayServer::get_singleton()->window_set_window_event_callback(callable_mp(this, &Window::_event_callback), window_id); DisplayServer::get_singleton()->window_set_input_event_callback(callable_mp(this, &Window::_window_input), window_id); DisplayServer::get_singleton()->window_set_input_text_callback(callable_mp(this, &Window::_window_input_text), window_id); DisplayServer::get_singleton()->window_set_drop_files_callback(callable_mp(this, &Window::_window_drop_files), window_id); } + +Viewport *Window::_get_embedder() const { + + Viewport *vp = get_parent_viewport(); + + while (vp) { + + if (vp->is_embedding_subwindows()) { + return vp; + } + + if (vp->get_parent()) { + vp = vp->get_parent()->get_viewport(); + } else { + vp = nullptr; + } + } + return nullptr; +} + void Window::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { - if (is_embedded()) { + + bool embedded = false; + { + + embedder = _get_embedder(); + + if (embedder) { + embedded = true; + + if (!visible) { + embedder = nullptr; //not yet since not visible + } + } + } + + if (embedded) { //create as embedded - _update_size(); + if (embedder) { + embedder->_sub_window_register(this); + VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE); + _update_window_size(); + } + } else { if (get_parent() == nullptr) { //it's the root window! visible = true; //always visible window_id = DisplayServer::MAIN_WINDOW_ID; _update_from_window(); - _update_size(); + //since this window already exists (created on start), we must update pos and size from it + { + position = DisplayServer::get_singleton()->window_get_position(window_id); + size = DisplayServer::get_singleton()->window_get_size(window_id); + } + _update_viewport_size(); //then feed back to the viewport _update_window_callbacks(); + VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_WHEN_VISIBLE); } else { //create if (visible) { @@ -623,6 +738,7 @@ void Window::_notification(int p_what) { if (visible) { notification(NOTIFICATION_VISIBILITY_CHANGED); emit_signal(SceneStringNames::get_singleton()->visibility_changed); + VS::get_singleton()->viewport_set_active(get_viewport_rid(), true); } } @@ -643,13 +759,22 @@ void Window::_notification(int p_what) { if (window_id == DisplayServer::MAIN_WINDOW_ID) { + VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_DISABLED); _update_window_callbacks(); } else { _clear_window(); } } else { - _update_size(); //called by clear and make, which does not happen here + + if (embedder) { + embedder->_sub_window_remove(this); + embedder = nullptr; + VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_DISABLED); + } + _update_viewport_size(); //called by clear and make, which does not happen here } + + VS::get_singleton()->viewport_set_active(get_viewport_rid(), false); } } @@ -657,7 +782,7 @@ void Window::set_content_scale_size(const Size2i &p_size) { ERR_FAIL_COND(p_size.x < 0); ERR_FAIL_COND(p_size.y < 0); content_scale_size = p_size; - _update_size(); + _update_viewport_size(); } Size2i Window::get_content_scale_size() const { @@ -666,7 +791,7 @@ Size2i Window::get_content_scale_size() const { void Window::set_content_scale_mode(ContentScaleMode p_mode) { content_scale_mode = p_mode; - _update_size(); + _update_viewport_size(); } Window::ContentScaleMode Window::get_content_scale_mode() const { return content_scale_mode; @@ -674,7 +799,7 @@ Window::ContentScaleMode Window::get_content_scale_mode() const { void Window::set_content_scale_aspect(ContentScaleAspect p_aspect) { content_scale_aspect = p_aspect; - _update_size(); + _update_viewport_size(); } Window::ContentScaleAspect Window::get_content_scale_aspect() const { return content_scale_aspect; @@ -685,7 +810,7 @@ void Window::set_use_font_oversampling(bool p_oversampling) { ERR_FAIL_MSG("Only the root window can set and use font oversampling."); } use_font_oversampling = p_oversampling; - _update_size(); + _update_viewport_size(); } bool Window::is_using_font_oversampling() const { return use_font_oversampling; @@ -724,22 +849,17 @@ Size2 Window::_get_contents_minimum_size() const { } void Window::_update_child_controls() { - Size2 max = _get_contents_minimum_size(); - - Size2 new_size(MAX(max.x, size.x), MAX(max.y, size.y)); - - if (new_size != size) { - set_size(new_size); - } - set_min_size(max); - updating_child_controls = false; -} -void Window::child_controls_changed() { - if (!is_inside_tree()) { + if (!updating_child_controls) { return; } - if (updating_child_controls) { + _update_window_size(); + + updating_child_controls = false; +} +void Window::child_controls_changed() { + + if (!is_inside_tree() || !visible || updating_child_controls) { return; } @@ -762,7 +882,7 @@ void Window::_window_input(const Ref &p_ev) { if (exclusive_child != nullptr) { exclusive_child->grab_focus(); - print_line("drop because of exclusive"); + return; //has an exclusive child, can't get events until child is closed } @@ -901,6 +1021,7 @@ void Window::popup_centered_ratio(float p_ratio) { void Window::popup(const Rect2 &p_screen_rect) { emit_signal("about_to_popup"); + if (p_screen_rect != Rect2()) { set_position(p_screen_rect.position); set_size(p_screen_rect.size); @@ -917,7 +1038,9 @@ Size2 Window::get_contents_minimum_size() const { } void Window::grab_focus() { - if (window_id != DisplayServer::INVALID_WINDOW_ID) { + if (embedder) { + embedder->_sub_window_grab_focus(this); + } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { DisplayServer::get_singleton()->window_move_to_foreground(window_id); } } @@ -939,6 +1062,10 @@ void Window::add_child_notify(Node *p_child) { if (child_w && child_w->theme.is_null() && (theme_owner || theme_owner_window)) { Control::_propagate_theme_changed(child_w, theme_owner, theme_owner_window); //need to propagate here, since many controls may require setting up stuff } + + if (is_inside_tree() && wrap_controls) { + child_controls_changed(); + } } void Window::remove_child_notify(Node *p_child) { @@ -954,6 +1081,10 @@ void Window::remove_child_notify(Node *p_child) { if (child_w && (child_w->theme_owner || child_w->theme_owner_window) && child_w->theme.is_null()) { Control::_propagate_theme_changed(child_w, NULL, NULL); } + + if (is_inside_tree() && wrap_controls) { + child_controls_changed(); + } } void Window::set_theme(const Ref &p_theme) { @@ -988,47 +1119,65 @@ Ref Window::get_theme() const { } Ref Window::get_theme_icon(const StringName &p_name, const StringName &p_type) const { - return Control::get_icons(theme_owner, theme_owner_window, p_name, p_type); + StringName type = p_type ? p_type : get_class_name(); + return Control::get_icons(theme_owner, theme_owner_window, p_name, type); } Ref Window::get_theme_shader(const StringName &p_name, const StringName &p_type) const { - return Control::get_shaders(theme_owner, theme_owner_window, p_name, p_type); + StringName type = p_type ? p_type : get_class_name(); + return Control::get_shaders(theme_owner, theme_owner_window, p_name, type); } Ref Window::get_theme_stylebox(const StringName &p_name, const StringName &p_type) const { - return Control::get_styleboxs(theme_owner, theme_owner_window, p_name, p_type); + StringName type = p_type ? p_type : get_class_name(); + return Control::get_styleboxs(theme_owner, theme_owner_window, p_name, type); } Ref Window::get_theme_font(const StringName &p_name, const StringName &p_type) const { - return Control::get_fonts(theme_owner, theme_owner_window, p_name, p_type); + StringName type = p_type ? p_type : get_class_name(); + return Control::get_fonts(theme_owner, theme_owner_window, p_name, type); } Color Window::get_theme_color(const StringName &p_name, const StringName &p_type) const { - return Control::get_colors(theme_owner, theme_owner_window, p_name, p_type); + StringName type = p_type ? p_type : get_class_name(); + return Control::get_colors(theme_owner, theme_owner_window, p_name, type); } int Window::get_theme_constant(const StringName &p_name, const StringName &p_type) const { - return Control::get_constants(theme_owner, theme_owner_window, p_name, p_type); + StringName type = p_type ? p_type : get_class_name(); + return Control::get_constants(theme_owner, theme_owner_window, p_name, type); } bool Window::has_theme_icon(const StringName &p_name, const StringName &p_type) const { - return Control::has_icons(theme_owner, theme_owner_window, p_name, p_type); + StringName type = p_type ? p_type : get_class_name(); + return Control::has_icons(theme_owner, theme_owner_window, p_name, type); } bool Window::has_theme_shader(const StringName &p_name, const StringName &p_type) const { - return Control::has_shaders(theme_owner, theme_owner_window, p_name, p_type); + StringName type = p_type ? p_type : get_class_name(); + return Control::has_shaders(theme_owner, theme_owner_window, p_name, type); } bool Window::has_theme_stylebox(const StringName &p_name, const StringName &p_type) const { - return Control::has_styleboxs(theme_owner, theme_owner_window, p_name, p_type); + StringName type = p_type ? p_type : get_class_name(); + return Control::has_styleboxs(theme_owner, theme_owner_window, p_name, type); } bool Window::has_theme_font(const StringName &p_name, const StringName &p_type) const { - return Control::has_fonts(theme_owner, theme_owner_window, p_name, p_type); + StringName type = p_type ? p_type : get_class_name(); + return Control::has_fonts(theme_owner, theme_owner_window, p_name, type); } bool Window::has_theme_color(const StringName &p_name, const StringName &p_type) const { - return Control::has_colors(theme_owner, theme_owner_window, p_name, p_type); + StringName type = p_type ? p_type : get_class_name(); + return Control::has_colors(theme_owner, theme_owner_window, p_name, type); } bool Window::has_theme_constant(const StringName &p_name, const StringName &p_type) const { - return Control::has_constants(theme_owner, theme_owner_window, p_name, p_type); + StringName type = p_type ? p_type : get_class_name(); + return Control::has_constants(theme_owner, theme_owner_window, p_name, type); } -Rect2i Window::get_screen_rect() const { +Rect2i Window::get_parent_rect() const { + ERR_FAIL_COND_V(!is_inside_tree(), Rect2i()); if (is_embedded()) { //viewport - return Rect2i(); + Node *n = get_parent(); + ERR_FAIL_COND_V(!n, Rect2i()); + Viewport *p = n->get_viewport(); + ERR_FAIL_COND_V(!p, Rect2i()); + + return p->get_visible_rect(); } else { int x = get_position().x; int closest_dist = 0x7FFFFFFF; @@ -1188,6 +1337,7 @@ Window::Window() { } content_scale_mode = CONTENT_SCALE_MODE_DISABLED; content_scale_aspect = CONTENT_SCALE_ASPECT_IGNORE; + VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_DISABLED); } Window::~Window() { } diff --git a/scene/main/window.h b/scene/main/window.h index 298a6115752..04c077a550d 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -103,20 +103,13 @@ private: void _clear_window(); void _update_from_window(); - void _resize_callback(const Size2i &p_callback); - void _event_callback(DisplayServer::WindowEvent p_event); - - void _update_size(); + void _update_viewport_size(); + void _update_window_size(); void _propagate_window_notification(Node *p_node, int p_notification); virtual DisplayServer::WindowID get_window_id() const; - void _window_input(const Ref &p_ev); - void _window_input_text(const String &p_text); - void _window_drop_files(const Vector &p_files); - - void _window_unhandled_input(const Ref &p_ev); void _update_window_callbacks(); void _clear_transient(); @@ -130,6 +123,18 @@ private: Control *theme_owner = nullptr; Window *theme_owner_window = nullptr; + Viewport *_get_embedder() const; + + Viewport *embedder = nullptr; + + friend class Viewport; //friend back, can call the methods below + + void _window_input(const Ref &p_ev); + void _window_input_text(const String &p_text); + void _window_drop_files(const Vector &p_files); + void _rect_changed_callback(const Rect2i &p_callback); + void _event_callback(DisplayServer::WindowEvent p_event); + protected: virtual void _post_popup() {} virtual Size2 _get_contents_minimum_size() const; @@ -243,7 +248,7 @@ public: bool has_theme_color(const StringName &p_name, const StringName &p_type = StringName()) const; bool has_theme_constant(const StringName &p_name, const StringName &p_type = StringName()) const; - Rect2i get_screen_rect() const; + Rect2i get_parent_rect() const; Window(); ~Window(); diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 2449f1adf01..0c457793079 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -524,18 +524,19 @@ void fill_default_theme(Ref &theme, const Ref &default_font, const // WindowDialog - theme->set_stylebox("panel", "AcceptDialog", default_style); - theme->set_stylebox("window_panel", "AcceptDialog", sb_expand(make_stylebox(popup_window_png, 10, 26, 10, 8), 8, 24, 8, 6)); - theme->set_constant("scaleborder_size", "AcceptDialog", 4 * scale); + theme->set_stylebox("panel", "Window", default_style); + theme->set_stylebox("window_panel", "Window", sb_expand(make_stylebox(popup_window_png, 10, 26, 10, 8), 8, 24, 8, 6)); + theme->set_constant("scaleborder_size", "Window", 4 * scale); - theme->set_font("title_font", "AcceptDialog", large_font); - theme->set_color("title_color", "AcceptDialog", Color(0, 0, 0)); - theme->set_constant("title_height", "AcceptDialog", 20 * scale); + theme->set_font("title_font", "Window", large_font); + theme->set_color("title_color", "Window", Color(0, 0, 0)); + theme->set_constant("title_height", "Window", 20 * scale); + theme->set_constant("resize_margin", "Window", 4 * scale); - theme->set_icon("close", "AcceptDialog", make_icon(close_png)); - theme->set_icon("close_highlight", "AcceptDialog", make_icon(close_hl_png)); - theme->set_constant("close_h_ofs", "AcceptDialog", 18 * scale); - theme->set_constant("close_v_ofs", "AcceptDialog", 18 * scale); + theme->set_icon("close", "Window", make_icon(close_png)); + theme->set_icon("close_highlight", "Window", make_icon(close_hl_png)); + theme->set_constant("close_h_ofs", "Window", 18 * scale); + theme->set_constant("close_v_ofs", "Window", 18 * scale); // File Dialog diff --git a/servers/display_server.cpp b/servers/display_server.cpp index 5b030be5a65..efa3c8af7bf 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -276,7 +276,7 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("window_get_size", "window_id"), &DisplayServer::window_get_size, DEFVAL(MAIN_WINDOW_ID)); ClassDB::bind_method(D_METHOD("window_set_size", "size", "window_id"), &DisplayServer::window_set_size, DEFVAL(MAIN_WINDOW_ID)); - ClassDB::bind_method(D_METHOD("window_set_resize_callback", "callback", "window_id"), &DisplayServer::window_set_resize_callback, DEFVAL(MAIN_WINDOW_ID)); + ClassDB::bind_method(D_METHOD("window_set_rect_changed_callback", "callback", "window_id"), &DisplayServer::window_set_rect_changed_callback, DEFVAL(MAIN_WINDOW_ID)); ClassDB::bind_method(D_METHOD("window_set_window_event_callback", "callback", "window_id"), &DisplayServer::window_set_window_event_callback, DEFVAL(MAIN_WINDOW_ID)); ClassDB::bind_method(D_METHOD("window_set_input_event_callback", "callback", "window_id"), &DisplayServer::window_set_input_event_callback, DEFVAL(MAIN_WINDOW_ID)); ClassDB::bind_method(D_METHOD("window_set_input_text_callback", "callback", "window_id"), &DisplayServer::window_set_input_text_callback, DEFVAL(MAIN_WINDOW_ID)); diff --git a/servers/display_server.h b/servers/display_server.h index 69e110d2b14..dfa98e350fb 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -182,7 +182,7 @@ public: virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i & = Rect2i()); virtual void delete_sub_window(WindowID p_id); - virtual void window_set_resize_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) = 0; + virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) = 0; enum WindowEvent { WINDOW_EVENT_MOUSE_ENTER, diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index aca96d65529..555d5f99c7a 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -316,7 +316,10 @@ void VisualServerViewport::draw_viewports() { //draw viewports RENDER_TIMESTAMP(">Render Viewports"); - for (int i = 0; i < active_viewports.size(); i++) { + //determine what is visible + draw_viewports_pass++; + + for (int i = active_viewports.size() - 1; i >= 0; i--) { //to compute parent dependency, must go in reverse draw order Viewport *vp = active_viewports[i]; @@ -328,11 +331,37 @@ void VisualServerViewport::draw_viewports() { } //ERR_CONTINUE(!vp->render_target.is_valid()); - bool visible = vp->viewport_to_screen_rect != Rect2() || vp->update_mode == VS::VIEWPORT_UPDATE_ALWAYS || vp->update_mode == VS::VIEWPORT_UPDATE_ONCE || (vp->update_mode == VS::VIEWPORT_UPDATE_WHEN_VISIBLE && VSG::storage->render_target_was_used(vp->render_target)); + bool visible = vp->viewport_to_screen_rect != Rect2(); + + if (vp->update_mode == VS::VIEWPORT_UPDATE_ALWAYS || vp->update_mode == VS::VIEWPORT_UPDATE_ONCE) { + visible = true; + } + + if (vp->update_mode == VS::VIEWPORT_UPDATE_WHEN_VISIBLE && VSG::storage->render_target_was_used(vp->render_target)) { + visible = true; + } + + if (vp->update_mode == VS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE) { + Viewport *parent = viewport_owner.getornull(vp->parent); + if (parent && parent->last_pass == draw_viewports_pass) { + visible = true; + } + } + visible = visible && vp->size.x > 1 && vp->size.y > 1; - if (!visible) - continue; + if (visible) { + vp->last_pass = draw_viewports_pass; + } + } + + for (int i = 0; i < active_viewports.size(); i++) { + + Viewport *vp = active_viewports[i]; + + if (vp->last_pass != draw_viewports_pass) { + continue; //should not draw + } RENDER_TIMESTAMP(">Rendering Viewport " + itos(i)); diff --git a/servers/visual/visual_server_viewport.h b/servers/visual/visual_server_viewport.h index 38983d5e8a5..06372376f8b 100644 --- a/servers/visual/visual_server_viewport.h +++ b/servers/visual/visual_server_viewport.h @@ -73,6 +73,8 @@ public: RID shadow_atlas; int shadow_atlas_size; + uint64_t last_pass = 0; + int render_info[VS::VIEWPORT_RENDER_INFO_MAX]; VS::ViewportDebugDraw debug_draw; @@ -129,6 +131,8 @@ public: } }; + uint64_t draw_viewports_pass = 0; + mutable RID_PtrOwner viewport_owner; struct ViewportSort { @@ -139,9 +143,9 @@ public: if (left_to_screen == right_to_screen) { - return p_left->parent == p_right->self; + return p_right->parent == p_left->self; } - return right_to_screen; + return (right_to_screen ? 0 : 1) < (left_to_screen ? 0 : 1); } }; diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index 62c3704f5b8..1e4ee5cb504 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -2060,6 +2060,7 @@ void VisualServer::_bind_methods() { BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_DISABLED); BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_ONCE); BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_WHEN_VISIBLE); + BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE); BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_ALWAYS); BIND_ENUM_CONSTANT(VIEWPORT_CLEAR_ALWAYS); diff --git a/servers/visual_server.h b/servers/visual_server.h index d41c80dfa18..506800cc7d4 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -592,6 +592,7 @@ public: VIEWPORT_UPDATE_DISABLED, VIEWPORT_UPDATE_ONCE, //then goes to disabled, must be manually updated VIEWPORT_UPDATE_WHEN_VISIBLE, // default + VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE, VIEWPORT_UPDATE_ALWAYS };