summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--editor/animation_track_editor.cpp5
-rw-r--r--editor/editor_node.cpp5
-rw-r--r--editor/editor_themes.cpp19
-rw-r--r--editor/filesystem_dock.cpp4
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp6
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp2
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp2
-rw-r--r--editor/scene_tree_dock.cpp3
-rw-r--r--main/main.cpp8
-rw-r--r--platform/linuxbsd/display_server_x11.cpp12
-rw-r--r--platform/linuxbsd/display_server_x11.h4
-rw-r--r--platform/windows/display_server_windows.cpp57
-rw-r--r--platform/windows/display_server_windows.h4
-rw-r--r--scene/2d/canvas_item.cpp2
-rw-r--r--scene/gui/base_button.cpp3
-rw-r--r--scene/gui/color_picker.cpp5
-rw-r--r--scene/gui/control.cpp189
-rw-r--r--scene/gui/control.h19
-rw-r--r--scene/gui/menu_button.cpp14
-rw-r--r--scene/gui/popup_menu.cpp11
-rw-r--r--scene/gui/tree.cpp11
-rw-r--r--scene/main/viewport.cpp760
-rw-r--r--scene/main/viewport.h81
-rw-r--r--scene/main/window.cpp328
-rw-r--r--scene/main/window.h25
-rw-r--r--scene/resources/default_theme/default_theme.cpp25
-rw-r--r--servers/display_server.cpp2
-rw-r--r--servers/display_server.h2
-rw-r--r--servers/visual/visual_server_viewport.cpp37
-rw-r--r--servers/visual/visual_server_viewport.h8
-rw-r--r--servers/visual_server.cpp1
-rw-r--r--servers/visual_server.h1
32 files changed, 1023 insertions, 632 deletions
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 3da8f29697..766df27e62 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -2853,7 +2853,10 @@ void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &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 291f3dc319..2cc6bad2a9 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<InputEvent> &p_event) {
- if (Node::get_viewport()->get_modal_stack_top())
- return; //ignore because of modal window
-
Ref<InputEventKey> 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 c7f353f6fb..4eedf61a5f 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -911,15 +911,16 @@ Ref<Theme> create_editor_theme(const Ref<Theme> 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<StyleBoxFlat> style_complex_window = style_window->duplicate();
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index e951259cc7..e1fcddda3a 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<InputEvent> p_event) {
- if (get_viewport()->get_modal_stack_top())
- return; // Ignore because of modal window.
Ref<InputEventKey> key = p_event;
if (key.is_valid() && key->is_pressed() && !key->is_echo()) {
@@ -2368,8 +2366,6 @@ void FileSystemDock::_tree_gui_input(Ref<InputEvent> p_event) {
}
void FileSystemDock::_file_list_gui_input(Ref<InputEvent> p_event) {
- if (get_viewport()->get_modal_stack_top())
- return; // Ignore because of modal window.
Ref<InputEventKey> 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 ea7a97982c..c5979bf952 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 Ref<InputEv
name_edit->set_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 1ad0df5224..4cc0bd4780 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<InputEvent> &p_ev) {
Ref<InputEventKey> 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 286125d31b..f0730f0144 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<InputEvent> 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 f0b9b32c34..613ba53fed 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -75,9 +75,6 @@ void SceneTreeDock::_input(Ref<InputEvent> p_event) {
void SceneTreeDock::_unhandled_key_input(Ref<InputEvent> 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 df603744b6..2ce3001829 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 b96e6b4e7a..f93dbc5371 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 = &rect;
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 9df5d876d3..f06d838239 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 e2c78da5a9..b895632848 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 0c07e6283c..ba9eef886b 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 321f3f2e6f..7a0fc3352b 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<Window>(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 07bc91e7e7..a05ac08e9d 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -357,9 +357,6 @@ void BaseButton::_unhandled_input(Ref<InputEvent> 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 2a3f7467dc..948e46b649 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 062d15c05b..bfaace69d7 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<Control>(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);
- }
-
- } 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<CanvasItem>(parent);
- if (ci && ci->is_set_as_toplevel()) {
- subwindow = true;
- break;
- }
+ while (parent) {
- parent_control = Object::cast_to<Control>(parent);
+ parent = parent->get_parent();
- if (parent_control) {
- break;
- } else if (ci) {
+ if (!parent)
+ break;
- } else {
- break;
- }
+ CanvasItem *ci = Object::cast_to<CanvasItem>(parent);
+ if (ci && ci->is_set_as_toplevel()) {
+ subwindow = true;
+ break;
}
- 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);
- } else {
- //is a regular root control
- data.RI = get_viewport()->_gui_add_root_control(this);
- }
-
- data.parent_canvas_item = get_parent_item();
+ parent_control = Object::cast_to<Control>(parent);
- if (data.parent_canvas_item) {
+ if (parent_control) {
+ break;
+ } else if (ci) {
- 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<Control *>(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<Window>(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<Window>(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<Control *>(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<Control *>::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<Control>(p_at);
@@ -2444,8 +2353,6 @@ Control *Control::_get_focus_neighbour(Margin p_margin, int p_count) {
Control *c = Object::cast_to<Control>(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<Control>(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 22839df712..c52e80fa70 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> theme;
Control *theme_owner;
Window *theme_owner_window;
String tooltip;
CursorShape default_cursor;
- List<Control *>::Element *MI; //modal item
- List<Control *>::Element *SI;
List<Control *>::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<Theme> &p_theme);
Ref<Theme> 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<Texture2D> &p_icon);
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index 4cae7b8f40..61441ff958 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -43,20 +43,24 @@ void MenuButton::_unhandled_key_input(Ref<InputEvent> 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 6951026dec..e325f2661a 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<InputEvent> &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<InputEvent> &p_event) {
Ref<InputEventPanGesture> 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());
}
}
@@ -592,6 +592,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: {
if (!is_visible()) {
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 7bac82bf63..38ae1f36bc 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 50d0520d4b..0dcb013c37 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<StyleBox> panel = p_window->get_theme_stylebox("panel_window");
+ panel->draw(sw.canvas_item, r);
+
+ // Draw the title bar text.
+ Ref<Font> 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<Texture2D> 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<Window>(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<Window>(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<Window>(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<InputEvent> Viewport::_make_input_local(const Ref<InputEvent> &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<Control *>::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<Control::CComparator>();
- gui.subwindows.sort_custom<Control::CComparator>();
-
- gui.subwindow_order_dirty = false;
-}
-
-void Viewport::_gui_sort_modal_stack() {
-
- gui.modal_stack.sort_custom<Control::CComparator>();
-}
-
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<Control *>::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<Control *>::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<Viewport>(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<InputEvent> 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<InputEvent> 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<InputEvent> 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<InputEvent> 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<InputEvent> 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<InputEvent> 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<Control *>::Element *Viewport::_gui_add_root_control(Control *p_control) {
return gui.roots.push_back(p_control);
}
-List<Control *>::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<Control *>::Element *MI) {
-
- gui.modal_stack.erase(MI);
-}
-
-void Viewport::_gui_remove_from_modal_stack(List<Control *>::Element *MI, ObjectID p_prev_focus_owner) {
-
- //transfer the focus stack to the next
-
- List<Control *>::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<Control>(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<Control *>::Element *RI) {
gui.roots.erase(RI);
}
-void Viewport::_gui_remove_subwindow_control(List<Control *>::Element *SI) {
-
- ERR_FAIL_COND(!SI);
-
- Control *control = SI->get();
-
- control->disconnect("visibility_changed", callable_mp(this, &Viewport::_subwindow_visibility_changed));
-
- List<Control *>::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<Control *>::Element *Viewport::_gui_show_modal(Control *p_control) {
-
- List<Control *>::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<InputEvent> &p_event) {
+
+ if (gui.subwindow_drag != SUB_WINDOW_DRAG_DISABLED) {
+
+ ERR_FAIL_COND_V(gui.subwindow_focused == nullptr, false);
+
+ Ref<InputEventMouseButton> 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<InputEventMouseMotion> 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<InputEventMouseButton> 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<Texture2D> 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<InputEventMouseMotion> 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<InputEvent> ev = p_event->xformed_by(window_ofs);
+
+ gui.subwindow_focused->_window_input(ev);
+
+ return true;
+}
+
void Viewport::input(const Ref<InputEvent> &p_event, bool p_local_coords) {
ERR_FAIL_COND(!is_inside_tree());
@@ -2671,6 +2924,11 @@ void Viewport::input(const Ref<InputEvent> &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<Control>(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<World2D>(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 3d90eaf3b3..08dd505161 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<ViewportTexture> default_texture;
Set<ViewportTexture *> 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<Control *> modal_stack;
Transform2D focus_inv_xform;
- bool subwindow_order_dirty;
- bool subwindow_visibility_dirty;
- List<Control *> subwindows; // visible subwindows
- List<Control *> all_known_subwindows;
bool roots_order_dirty;
List<Control *> 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<SubWindow> sub_windows;
GUI();
} gui;
@@ -316,10 +353,7 @@ private:
void _gui_call_input(Control *p_control, const Ref<InputEvent> &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<Control *>::Element *_gui_add_root_control(Control *p_control);
- List<Control *>::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<Control *>::Element *MI);
- void _gui_remove_from_modal_stack(List<Control *>::Element *MI, ObjectID p_prev_focus_owner);
void _gui_remove_root_control(List<Control *>::Element *RI);
- void _gui_remove_subwindow_control(List<Control *>::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<Control *>::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<InputEvent> &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 6d61f3f0a8..4ea00a4187 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();
+ if (!updating_child_controls) {
+ return;
+ }
- Size2 new_size(MAX(max.x, size.x), MAX(max.y, size.y));
+ _update_window_size();
- 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()) {
- return;
- }
- if (updating_child_controls) {
+ if (!is_inside_tree() || !visible || updating_child_controls) {
return;
}
@@ -762,7 +882,7 @@ void Window::_window_input(const Ref<InputEvent> &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<Theme> &p_theme) {
@@ -988,47 +1119,65 @@ Ref<Theme> Window::get_theme() const {
}
Ref<Texture2D> 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<Shader> 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<StyleBox> 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<Font> 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 298a611575..04c077a550 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<InputEvent> &p_ev);
- void _window_input_text(const String &p_text);
- void _window_drop_files(const Vector<String> &p_files);
-
- void _window_unhandled_input(const Ref<InputEvent> &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<InputEvent> &p_ev);
+ void _window_input_text(const String &p_text);
+ void _window_drop_files(const Vector<String> &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 2449f1adf0..0c45779307 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> &theme, const Ref<Font> &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_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_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_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", "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", "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 5b030be5a6..efa3c8af7b 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 69e110d2b1..dfa98e350f 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 aca96d6552..555d5f99c7 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 38983d5e8a..06372376f8 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> 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 62c3704f5b..1e4ee5cb50 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 d41c80dfa1..506800cc7d 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
};