Open sub-windows as embedded if the OS does not support them

This commit is contained in:
Juan Linietsky 2020-03-14 13:06:39 -03:00
parent 441f1a5fe9
commit c7b4dcae2f
32 changed files with 1027 additions and 636 deletions

View file

@ -2853,7 +2853,10 @@ void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
Vector2 theme_ofs = path->get_theme_stylebox("normal", "LineEdit")->get_offset(); Vector2 theme_ofs = path->get_theme_stylebox("normal", "LineEdit")->get_offset();
path->set_position(get_global_position() + path_rect.position - theme_ofs); path->set_position(get_global_position() + path_rect.position - theme_ofs);
path->set_size(path_rect.size); 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->grab_focus();
path->set_cursor_position(path->get_text().length()); path->set_cursor_position(path->get_text().length());
clicking_on_name = false; clicking_on_name = false;

View file

@ -264,11 +264,8 @@ void EditorNode::_update_title() {
void EditorNode::_unhandled_input(const Ref<InputEvent> &p_event) { 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; 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; EditorPlugin *old_editor = editor_plugin_screen;

View file

@ -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_border_width(MARGIN_TOP, 24 * EDSCALE);
style_window->set_expand_margin_size(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", style_default);
theme->set_stylebox("panel_window", "AcceptDialog", style_window); theme->set_stylebox("panel_window", "Window", style_window);
theme->set_color("title_color", "AcceptDialog", font_color); theme->set_color("title_color", "Window", font_color);
theme->set_icon("close", "AcceptDialog", theme->get_icon("GuiClose", "EditorIcons")); theme->set_icon("close", "Window", theme->get_icon("GuiClose", "EditorIcons"));
theme->set_icon("close_highlight", "AcceptDialog", theme->get_icon("GuiClose", "EditorIcons")); theme->set_icon("close_highlight", "Window", theme->get_icon("GuiClose", "EditorIcons"));
theme->set_constant("close_h_ofs", "AcceptDialog", 22 * EDSCALE); theme->set_constant("close_h_ofs", "Window", 22 * EDSCALE);
theme->set_constant("close_v_ofs", "AcceptDialog", 20 * EDSCALE); theme->set_constant("close_v_ofs", "Window", 20 * EDSCALE);
theme->set_constant("title_height", "AcceptDialog", 24 * EDSCALE); theme->set_constant("title_height", "Window", 24 * EDSCALE);
theme->set_font("title_font", "AcceptDialog", theme->get_font("title", "EditorFonts")); 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 // complex window, for now only Editor settings and Project settings
Ref<StyleBoxFlat> style_complex_window = style_window->duplicate(); Ref<StyleBoxFlat> style_complex_window = style_window->duplicate();

View file

@ -2350,8 +2350,6 @@ void FileSystemDock::_file_multi_selected(int p_index, bool p_selected) {
} }
void FileSystemDock::_tree_gui_input(Ref<InputEvent> p_event) { 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; Ref<InputEventKey> key = p_event;
if (key.is_valid() && key->is_pressed() && !key->is_echo()) { 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) { 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; Ref<InputEventKey> key = p_event;
if (key.is_valid() && key->is_pressed() && !key->is_echo()) { if (key.is_valid() && key->is_pressed() && !key->is_echo()) {

View file

@ -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_global_position(state_machine_draw->get_global_transform().xform(edit_rect.position));
name_edit->set_size(edit_rect.size); name_edit->set_size(edit_rect.size);
name_edit->set_text(node_rects[i].node_name); 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->grab_focus();
name_edit->select_all(); name_edit->select_all();

View file

@ -477,7 +477,7 @@ void CanvasItemEditor::_unhandled_key_input(const Ref<InputEvent> &p_ev) {
Ref<InputEventKey> k = p_ev; Ref<InputEventKey> k = p_ev;
if (!is_visible_in_tree() || get_viewport()->gui_has_modal_stack()) if (!is_visible_in_tree())
return; return;
if (k->get_keycode() == KEY_CONTROL || k->get_keycode() == KEY_ALT || k->get_keycode() == KEY_SHIFT) { if (k->get_keycode() == KEY_CONTROL || k->get_keycode() == KEY_ALT || k->get_keycode() == KEY_SHIFT) {

View file

@ -5718,7 +5718,7 @@ void SpatialEditor::snap_selected_nodes_to_floor() {
void SpatialEditor::_unhandled_key_input(Ref<InputEvent> p_event) { 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; return;
snap_key_enabled = InputFilter::get_singleton()->is_key_pressed(KEY_CONTROL); snap_key_enabled = InputFilter::get_singleton()->is_key_pressed(KEY_CONTROL);

View file

@ -75,9 +75,6 @@ void SceneTreeDock::_input(Ref<InputEvent> p_event) {
void SceneTreeDock::_unhandled_key_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()) if (get_focus_owner() && get_focus_owner()->is_text_field())
return; return;

View file

@ -120,6 +120,7 @@ static int audio_driver_idx = -1;
// Engine config/tools // Engine config/tools
static bool single_window = false;
static bool editor = false; static bool editor = false;
static bool project_manager = false; static bool project_manager = false;
static String locale; 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(" --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(" --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(" --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"); OS::get_singleton()->print("\n");
#endif #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 } else if (I->get() == "--gpu-abort") { // force windowed window
Engine::singleton->abort_on_gpu_errors = true; 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 } else if (I->get() == "-t" || I->get() == "--always-on-top") { // force always-on-top window
init_always_on_top = true; init_always_on_top = true;
@ -1710,6 +1715,9 @@ bool Main::start() {
} }
#endif #endif
if (single_window) {
sml->get_root()->set_embed_subwindows_hint(true);
}
ResourceLoader::add_custom_loaders(); ResourceLoader::add_custom_loaders();
ResourceSaver::add_custom_savers(); ResourceSaver::add_custom_savers();

View file

@ -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()); 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_ _THREAD_SAFE_METHOD_
ERR_FAIL_COND(!windows.has(p_window)); ERR_FAIL_COND(!windows.has(p_window));
WindowData &wd = windows[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) { 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 #endif
if (!wd.resize_callback.is_null()) { if (!wd.rect_changed_callback.is_null()) {
Variant size = wd.size; Variant rect = Rect2i(wd.im_position, wd.size);
Variant *sizep = &size; Variant *rectp = &rect;
Variant ret; Variant ret;
Callable::CallError ce; Callable::CallError ce;
wd.resize_callback.call((const Variant **)&sizep, 1, ret, ce); wd.rect_changed_callback.call((const Variant **)&rectp, 1, ret, ce);
} }
} }

View file

@ -121,7 +121,7 @@ class DisplayServerX11 : public DisplayServer {
Size2i size; Size2i size;
Size2i im_position; Size2i im_position;
bool im_active = false; bool im_active = false;
Callable resize_callback; Callable rect_changed_callback;
Callable event_callback; Callable event_callback;
Callable input_event_callback; Callable input_event_callback;
Callable input_text_callback; Callable input_text_callback;
@ -268,7 +268,7 @@ public:
virtual void delete_sub_window(WindowID p_id); 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_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_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_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); virtual void window_set_input_text_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);

View file

@ -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; return window_id;
} }
void DisplayServerWindows::delete_sub_window(WindowID p_window) { void DisplayServerWindows::delete_sub_window(WindowID p_window) {
@ -449,12 +453,12 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) {
windows.erase(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_ _THREAD_SAFE_METHOD_
ERR_FAIL_COND(!windows.has(p_window)); 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) { 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)); ERR_FAIL_COND(!windows.has(p_window));
WindowData &wd = windows[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) { 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 { } else {
if (wd.resizable) { if (wd.resizable) {
if (p_maximized) { if (p_maximized) {
SetWindowLongPtr(wd.hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_MAXIMIZE); style = WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_MAXIMIZE;
} else { } else {
SetWindowLongPtr(wd.hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE); style = GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE;
} }
} else { } 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); SetWindowPos(wd.hWnd, wd.always_on_top ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE);
if (p_repaint) { if (p_repaint) {
@ -2208,6 +2224,15 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
int x = LOWORD(lParam); int x = LOWORD(lParam);
int y = HIWORD(lParam); int y = HIWORD(lParam);
windows[window_id].last_pos = Point2(x, y); 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; } 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 *sizep = &size;
Variant ret; Variant ret;
Callable::CallError ce; 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) { if (wParam == SIZE_MAXIMIZED) {
@ -2541,9 +2566,13 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
DWORD dwExStyle; DWORD dwExStyle;
DWORD dwStyle; DWORD dwStyle;
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; dwExStyle = WS_EX_WINDOWEDGE;
dwStyle = WS_OVERLAPPEDWINDOW; dwStyle = WS_OVERLAPPEDWINDOW;
if (window_id_counter == MAIN_WINDOW_ID) {
dwExStyle |= WS_EX_APPWINDOW;
}
RECT WindowRect; RECT WindowRect;
WindowRect.left = p_rect.position.x; WindowRect.left = p_rect.position.x;
@ -2594,10 +2623,6 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
DragAcceptFiles(wd.hWnd, true); 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 // IME
wd.im_himc = ImmGetContext(wd.hWnd); wd.im_himc = ImmGetContext(wd.hWnd);
ImmReleaseContext(wd.hWnd, wd.im_himc); 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 defined(VULKAN_ENABLED)
if (rendering_driver == "vulkan") { if (rendering_driver == "vulkan") {

View file

@ -200,7 +200,7 @@ class DisplayServerWindows : public DisplayServer {
bool layered_window = false; bool layered_window = false;
Callable resize_callback; Callable rect_changed_callback;
Callable event_callback; Callable event_callback;
Callable input_event_callback; Callable input_event_callback;
Callable input_text_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 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 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_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_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);

View file

@ -460,7 +460,7 @@ Transform2D CanvasItem::get_screen_transform() const {
Transform2D xform = get_global_transform_with_canvas(); Transform2D xform = get_global_transform_with_canvas();
Window *w = Object::cast_to<Window>(get_viewport()); Window *w = Object::cast_to<Window>(get_viewport());
if (w) { if (w && !w->is_embedding_subwindows()) {
Transform2D s; Transform2D s;
s.set_origin(w->get_position()); s.set_origin(w->get_position());

View file

@ -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 (!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); on_action_event(p_event);
} }
} }

View file

@ -620,7 +620,10 @@ void ColorPicker::_screen_pick_pressed() {
screen->call_deferred("connect", "hide", Callable(btn_pick, "set_pressed"), varray(false)); screen->call_deferred("connect", "hide", Callable(btn_pick, "set_pressed"), varray(false));
} }
screen->raise(); 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() { void ColorPicker::_focus_enter() {

View file

@ -494,76 +494,54 @@ void Control::_notification(int p_notification) {
data.parent = Object::cast_to<Control>(get_parent()); data.parent = Object::cast_to<Control>(get_parent());
if (is_set_as_toplevel()) { Node *parent = this; //meh
data.SI = get_viewport()->_gui_add_subwindow_control(this); Control *parent_control = NULL;
bool subwindow = false;
if (data.theme.is_null() && data.parent && data.parent->data.theme_owner) { while (parent) {
data.theme_owner = data.parent->data.theme_owner;
notification(NOTIFICATION_THEME_CHANGED); parent = parent->get_parent();
if (!parent)
break;
CanvasItem *ci = Object::cast_to<CanvasItem>(parent);
if (ci && ci->is_set_as_toplevel()) {
subwindow = true;
break;
} }
} else { parent_control = Object::cast_to<Control>(parent);
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;
}
parent_control = Object::cast_to<Control>(parent);
if (parent_control) {
break;
} else if (ci) {
} else {
break;
}
}
if (parent_control) { if (parent_control) {
//do nothing, has a parent control break;
if (data.theme.is_null() && parent_control->data.theme_owner) { } else if (ci) {
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 { } else {
//is a regular root control break;
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));
} }
} }
/* if (parent_control && !subwindow) {
if (data.theme.is_null() && data.parent && data.parent->data.theme_owner) { //do nothing, has a parent control and not toplevel
data.theme_owner=data.parent->data.theme_owner; if (data.theme.is_null() && parent_control->data.theme_owner) {
notification(NOTIFICATION_THEME_CHANGED); 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; } break;
case NOTIFICATION_EXIT_CANVAS: { 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)); 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) { if (data.RI) {
get_viewport()->_gui_remove_root_control(data.RI); get_viewport()->_gui_remove_root_control(data.RI);
data.RI = NULL; data.RI = NULL;
@ -608,9 +576,6 @@ void Control::_notification(int p_notification) {
data.parent->update(); data.parent->update();
update(); update();
if (data.SI) {
get_viewport()->_gui_set_subwindow_order_dirty();
}
if (data.RI) { if (data.RI) {
get_viewport()->_gui_set_root_order_dirty(); get_viewport()->_gui_set_root_order_dirty();
} }
@ -652,10 +617,6 @@ void Control::_notification(int p_notification) {
minimum_size_changed(); minimum_size_changed();
update(); update();
} break; } break;
case NOTIFICATION_MODAL_CLOSE: {
emit_signal("modal_closed");
} break;
case NOTIFICATION_VISIBILITY_CHANGED: { case NOTIFICATION_VISIBILITY_CHANGED: {
if (!is_visible_in_tree()) { if (!is_visible_in_tree()) {
@ -663,10 +624,6 @@ void Control::_notification(int p_notification) {
if (get_viewport() != NULL) if (get_viewport() != NULL)
get_viewport()->_gui_hid_control(this); get_viewport()->_gui_hid_control(this);
if (is_inside_tree()) {
_modal_stack_remove();
}
//remove key focus //remove key focus
//remove modalness //remove modalness
} else { } else {
@ -790,19 +747,6 @@ void Control::set_drag_preview(Control *p_control) {
get_viewport()->_gui_set_drag_preview(this, 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 { Size2 Control::get_minimum_size() const {
ScriptInstance *si = const_cast<Control *>(this)->get_script_instance(); 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()); ERR_FAIL_COND_V(!is_inside_tree(), Point2());
Point2 global_pos = get_global_position(); Point2 global_pos = get_global_position();
Window *w = Object::cast_to<Window>(get_viewport()); Window *w = Object::cast_to<Window>(get_viewport());
if (w) { if (w && !w->is_embedding_subwindows()) {
global_pos += w->get_position(); global_pos += w->get_position();
} }
@ -1828,7 +1772,7 @@ Rect2 Control::get_screen_rect() const {
Rect2 r(get_global_position(), get_size()); Rect2 r(get_global_position(), get_size());
Window *w = Object::cast_to<Window>(get_viewport()); Window *w = Object::cast_to<Window>(get_viewport());
if (w) { if (w && !w->is_embedding_subwindows()) {
r.position += w->get_position(); r.position += w->get_position();
} }
@ -2021,7 +1965,7 @@ Control *Control::find_next_valid_focus() const {
next_child = const_cast<Control *>(this); next_child = const_cast<Control *>(this);
while (next_child) { while (next_child) {
if (next_child->data.SI || next_child->data.RI) if (next_child->data.RI)
break; break;
next_child = next_child->get_parent_control(); 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()); 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) { 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); 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); Control *c = Object::cast_to<Control>(base);
if (c) { if (c) {
if (c->data.SI)
break;
if (c->data.RI) if (c->data.RI)
break; 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); Node *child = p_at->get_child(i);
Control *childc = Object::cast_to<Control>(child); Control *childc = Object::cast_to<Control>(child);
if (childc && childc->data.SI) if (childc && childc->data.RI)
continue; //subwindow, ignore continue; //subwindow, ignore
_window_find_focus_neighbour(p_dir, p_at->get_child(i), p_points, p_min, r_closest_dist, r_closest); _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; 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 { Control *Control::get_focus_owner() const {
ERR_FAIL_COND_V(!is_inside_tree(), NULL); ERR_FAIL_COND_V(!is_inside_tree(), NULL);
@ -2712,7 +2609,7 @@ Control *Control::get_root_parent_control() const {
if (c) { if (c) {
root = c; root = c;
if (c->data.RI || c->data.MI || c->is_toplevel_control()) if (c->data.RI || c->is_toplevel_control())
break; 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_global_position"), &Control::get_global_position);
ClassDB::bind_method(D_METHOD("get_rect"), &Control::get_rect); 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("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("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("get_focus_mode"), &Control::get_focus_mode);
ClassDB::bind_method(D_METHOD("has_focus"), &Control::has_focus); 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_ENTER);
BIND_CONSTANT(NOTIFICATION_FOCUS_EXIT); BIND_CONSTANT(NOTIFICATION_FOCUS_EXIT);
BIND_CONSTANT(NOTIFICATION_THEME_CHANGED); BIND_CONSTANT(NOTIFICATION_THEME_CHANGED);
BIND_CONSTANT(NOTIFICATION_MODAL_CLOSE);
BIND_CONSTANT(NOTIFICATION_SCROLL_BEGIN); BIND_CONSTANT(NOTIFICATION_SCROLL_BEGIN);
BIND_CONSTANT(NOTIFICATION_SCROLL_END); BIND_CONSTANT(NOTIFICATION_SCROLL_END);
@ -3093,7 +2988,6 @@ void Control::_bind_methods() {
ADD_SIGNAL(MethodInfo("focus_exited")); ADD_SIGNAL(MethodInfo("focus_exited"));
ADD_SIGNAL(MethodInfo("size_flags_changed")); ADD_SIGNAL(MethodInfo("size_flags_changed"));
ADD_SIGNAL(MethodInfo("minimum_size_changed")); ADD_SIGNAL(MethodInfo("minimum_size_changed"));
ADD_SIGNAL(MethodInfo("modal_closed"));
ADD_SIGNAL(MethodInfo("theme_changed")); ADD_SIGNAL(MethodInfo("theme_changed"));
BIND_VMETHOD(MethodInfo(Variant::BOOL, "has_point", PropertyInfo(Variant::VECTOR2, "point"))); BIND_VMETHOD(MethodInfo(Variant::BOOL, "has_point", PropertyInfo(Variant::VECTOR2, "point")));
@ -3103,14 +2997,10 @@ Control::Control() {
data.parent = NULL; data.parent = NULL;
data.mouse_filter = MOUSE_FILTER_STOP; data.mouse_filter = MOUSE_FILTER_STOP;
data.pass_on_modal_close_click = true;
data.SI = NULL;
data.MI = NULL;
data.RI = NULL; data.RI = NULL;
data.theme_owner = NULL; data.theme_owner = NULL;
data.theme_owner_window = NULL; data.theme_owner_window = NULL;
data.modal_exclusive = false;
data.default_cursor = CURSOR_ARROW; data.default_cursor = CURSOR_ARROW;
data.h_size_flags = SIZE_FILL; data.h_size_flags = SIZE_FILL;
data.v_size_flags = SIZE_FILL; data.v_size_flags = SIZE_FILL;
@ -3119,7 +3009,6 @@ Control::Control() {
data.parent_canvas_item = NULL; data.parent_canvas_item = NULL;
data.scale = Vector2(1, 1); data.scale = Vector2(1, 1);
data.modal_frame = 0;
data.block_minimum_size_adjust = false; data.block_minimum_size_adjust = false;
data.disable_visibility_clip = false; data.disable_visibility_clip = false;
data.h_grow = GROW_DIRECTION_END; data.h_grow = GROW_DIRECTION_END;

View file

@ -168,8 +168,6 @@ private:
float expand; float expand;
Point2 custom_minimum_size; Point2 custom_minimum_size;
bool pass_on_modal_close_click;
MouseFilter mouse_filter; MouseFilter mouse_filter;
bool clip_contents; bool clip_contents;
@ -179,22 +177,16 @@ private:
Control *parent; Control *parent;
ObjectID drag_owner; ObjectID drag_owner;
bool modal_exclusive;
uint64_t modal_frame; //frame used to put something as modal
Ref<Theme> theme; Ref<Theme> theme;
Control *theme_owner; Control *theme_owner;
Window *theme_owner_window; Window *theme_owner_window;
String tooltip; String tooltip;
CursorShape default_cursor; CursorShape default_cursor;
List<Control *>::Element *MI; //modal item
List<Control *>::Element *SI;
List<Control *>::Element *RI; List<Control *>::Element *RI;
CanvasItem *parent_canvas_item; CanvasItem *parent_canvas_item;
ObjectID modal_prev_focus_owner;
NodePath focus_neighbour[4]; NodePath focus_neighbour[4];
NodePath focus_next; NodePath focus_next;
NodePath focus_prev; NodePath focus_prev;
@ -240,8 +232,6 @@ private:
Transform2D _get_internal_transform() const; Transform2D _get_internal_transform() const;
friend class Viewport; friend class Viewport;
void _modal_stack_remove();
void _modal_set_prev_focus_owner(ObjectID p_prev);
void _update_minimum_size_cache(); void _update_minimum_size_cache();
friend class Window; friend class Window;
@ -293,7 +283,6 @@ public:
NOTIFICATION_FOCUS_ENTER = 43, NOTIFICATION_FOCUS_ENTER = 43,
NOTIFICATION_FOCUS_EXIT = 44, NOTIFICATION_FOCUS_EXIT = 44,
NOTIFICATION_THEME_CHANGED = 45, NOTIFICATION_THEME_CHANGED = 45,
NOTIFICATION_MODAL_CLOSE = 46,
NOTIFICATION_SCROLL_BEGIN = 47, NOTIFICATION_SCROLL_BEGIN = 47,
NOTIFICATION_SCROLL_END = 48, NOTIFICATION_SCROLL_END = 48,
@ -341,9 +330,6 @@ public:
void set_custom_minimum_size(const Size2 &p_custom); void set_custom_minimum_size(const Size2 &p_custom);
Size2 get_custom_minimum_size() const; 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; Control *get_parent_control() const;
/* POSITIONING */ /* POSITIONING */
@ -398,8 +384,6 @@ public:
void set_scale(const Vector2 &p_scale); void set_scale(const Vector2 &p_scale);
Vector2 get_scale() const; Vector2 get_scale() const;
void show_modal(bool p_exclusive = false);
void set_theme(const Ref<Theme> &p_theme); void set_theme(const Ref<Theme> &p_theme);
Ref<Theme> get_theme() const; Ref<Theme> get_theme() const;
@ -438,9 +422,6 @@ public:
void set_mouse_filter(MouseFilter p_filter); void set_mouse_filter(MouseFilter p_filter);
MouseFilter get_mouse_filter() const; MouseFilter get_mouse_filter() const;
void set_pass_on_modal_close_click(bool p_pass_on);
bool pass_on_modal_close_click() const;
/* SKINNING */ /* SKINNING */
void add_theme_icon_override(const StringName &p_name, const Ref<Texture2D> &p_icon); void add_theme_icon_override(const StringName &p_name, const Ref<Texture2D> &p_icon);

View file

@ -43,20 +43,24 @@ void MenuButton::_unhandled_key_input(Ref<InputEvent> p_event) {
if (!get_parent() || !is_visible_in_tree() || is_disabled()) if (!get_parent() || !is_visible_in_tree() || is_disabled())
return; return;
bool global_only = (get_viewport()->get_modal_stack_top() && !get_viewport()->get_modal_stack_top()->is_a_parent_of(this)); //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))
if (popup->activate_item_by_event(p_event, global_only)) // accept_event();
if (popup->activate_item_by_event(p_event, false))
accept_event(); accept_event();
} }
} }
void MenuButton::pressed() { void MenuButton::pressed() {
emit_signal("about_to_popup");
Size2 size = get_size(); Size2 size = get_size();
Point2 gp = get_screen_position(); 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_size(Size2(size.width, 0));
popup->set_parent_rect(Rect2(Point2(gp - popup->get_position()), get_size())); popup->set_parent_rect(Rect2(Point2(gp - popup->get_position()), get_size()));
popup->popup(); popup->popup();

View file

@ -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); Point2 pos = p + Point2(get_size().width, items[over]._ofs_cache - style->get_offset().y);
Size2 size = pm->get_size(); Size2 size = pm->get_size();
// fix pos // 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; pos.x = p.x - size.width;
pm->set_position(pos); pm->set_position(pos);
@ -203,7 +203,7 @@ void PopupMenu::_scroll(float p_factor, const Point2 &p_over) {
dy = MIN(dy, limit); dy = MIN(dy, limit);
} else if (dy < 0) { } else if (dy < 0) {
const float global_bottom = get_position().y + get_size().y; 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; const float limit = global_bottom > viewport_height ? global_bottom - viewport_height : 0;
dy = -MIN(-dy, limit); dy = -MIN(-dy, limit);
} }
@ -295,7 +295,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
case BUTTON_WHEEL_DOWN: { 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()); _scroll(-b->get_factor(), b->get_position());
} }
} break; } break;
@ -382,7 +382,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventPanGesture> pan_gesture = p_event; Ref<InputEventPanGesture> pan_gesture = p_event;
if (pan_gesture.is_valid()) { 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()); _scroll(-pan_gesture->get_delta().y, pan_gesture->get_position());
} }
} }
@ -591,6 +591,9 @@ void PopupMenu::_notification(int p_what) {
initial_button_mask = InputFilter::get_singleton()->get_mouse_button_mask(); initial_button_mask = InputFilter::get_singleton()->get_mouse_button_mask();
during_grabbed_click = (bool)initial_button_mask; during_grabbed_click = (bool)initial_button_mask;
} break;
case NOTIFICATION_WM_SIZE_CHANGED: {
} break; } break;
case NOTIFICATION_VISIBILITY_CHANGED: { case NOTIFICATION_VISIBILITY_CHANGED: {

View file

@ -2819,7 +2819,10 @@ bool Tree::edit_selected() {
value_editor->set_position(textedpos + Point2i(0, text_editor->get_size().height)); value_editor->set_position(textedpos + Point2i(0, text_editor->get_size().height));
value_editor->set_size(Size2(rect.size.width, 1)); 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; updating_value_editor = true;
value_editor->set_min(c.min); value_editor->set_min(c.min);
value_editor->set_max(c.max); value_editor->set_max(c.max);
@ -2828,8 +2831,10 @@ bool Tree::edit_selected() {
value_editor->set_exp_ratio(c.expr); value_editor->set_exp_ratio(c.expr);
updating_value_editor = false; updating_value_editor = false;
} }
#ifndef _MSC_VER
text_editor->show_modal(); #warning show modal no longer works, need to replace by a popup
#endif
text_editor->show();
text_editor->grab_focus(); text_editor->grab_focus();
return true; return true;
} }

View file

@ -187,6 +187,7 @@ public:
Viewport::GUI::GUI() { Viewport::GUI::GUI() {
embed_subwindows_hint = false; embed_subwindows_hint = false;
embedding_subwindows = false;
dragging = false; dragging = false;
mouse_focus = NULL; mouse_focus = NULL;
@ -198,8 +199,6 @@ Viewport::GUI::GUI() {
tooltip = NULL; tooltip = NULL;
tooltip_popup = NULL; tooltip_popup = NULL;
tooltip_label = 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; 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() { void Viewport::_own_world_changed() {
ERR_FAIL_COND(world.is_null()); ERR_FAIL_COND(world.is_null());
ERR_FAIL_COND(own_world.is_null()); ERR_FAIL_COND(own_world.is_null());
@ -263,6 +436,8 @@ void Viewport::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: { case NOTIFICATION_ENTER_TREE: {
gui.embedding_subwindows = gui.embed_subwindows_hint;
if (get_parent()) { if (get_parent()) {
parent = get_parent()->get_viewport(); parent = get_parent()->get_viewport();
VisualServer::get_singleton()->viewport_set_parent_viewport(viewport, parent->get_viewport_rid()); 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); //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; } break;
case NOTIFICATION_READY: { case NOTIFICATION_READY: {
#ifndef _3D_DISABLED #ifndef _3D_DISABLED
@ -358,6 +532,7 @@ void Viewport::_notification(int p_what) {
remove_from_group("_viewports"); remove_from_group("_viewports");
VS::get_singleton()->viewport_set_active(viewport, false); VS::get_singleton()->viewport_set_active(viewport, false);
VisualServer::get_singleton()->viewport_set_parent_viewport(viewport, RID());
} break; } break;
case NOTIFICATION_INTERNAL_PROCESS: { case NOTIFICATION_INTERNAL_PROCESS: {
@ -1318,25 +1493,16 @@ Transform2D Viewport::_get_input_pre_xform() const {
return pre_xf; 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) { 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(); 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 { 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) { 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); 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() { void Viewport::_gui_sort_roots() {
if (!gui.roots_order_dirty) 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) { Control *Viewport::_gui_find_control(const Point2 &p_global) {
_gui_prepare_subwindows(); //aca va 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;
}
_gui_sort_roots(); _gui_sort_roots();
for (List<Control *>::Element *E = gui.roots.back(); E; E = E->prev()) { 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)) if (Object::cast_to<Viewport>(p_node))
return NULL; return NULL;
//subwindows first!!
if (!p_node->is_visible()) { if (!p_node->is_visible()) {
//return _find_next_visible_control_at_pos(p_node,p_global,r_inv_xform); //return _find_next_visible_control_at_pos(p_node,p_global,r_inv_xform);
return NULL; //canvas item hidden, discard return NULL; //canvas item hidden, discard
@ -1735,39 +1846,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
bool is_handled = false; 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) { if (is_handled) {
set_input_as_handled(); set_input_as_handled();
return; return;
@ -1990,15 +2068,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
over = _gui_find_control(mpos); 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 (over != gui.mouse_over) {
if (gui.mouse_over) { if (gui.mouse_over) {
@ -2039,11 +2108,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
bool can_tooltip = true; 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; bool is_tooltip_shown = false;
if (gui.tooltip_popup) { if (gui.tooltip_popup) {
@ -2122,14 +2186,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Control *over = _gui_find_control(pos); Control *over = _gui_find_control(pos);
if (over) { 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()) { if (over->can_process()) {
touch_event = touch_event->xformed_by(Transform2D()); //make a copy 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 (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()) { if (over->can_process()) {
Transform2D localizer = over->get_global_transform_with_canvas().affine_inverse(); 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 Control *from = gui.key_focus ? gui.key_focus : NULL; //hmm
//keyboard focus //keyboard focus
@ -2319,61 +2352,10 @@ List<Control *>::Element *Viewport::_gui_add_root_control(Control *p_control) {
return gui.roots.push_back(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() { void Viewport::_gui_set_root_order_dirty() {
gui.roots_order_dirty = true; 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) { 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."); 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); 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) { void Viewport::_gui_unfocus_control(Control *p_control) {
if (gui.key_focus == 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) { bool Viewport::_gui_control_has_focus(const Control *p_control) {
return gui.key_focus == p_control; return gui.key_focus == p_control;
@ -2561,22 +2523,6 @@ void Viewport::_drop_physics_mouseover() {
#endif #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() { Control *Viewport::_gui_get_focus_owner() {
return gui.key_focus; return gui.key_focus;
@ -2647,10 +2593,317 @@ void Viewport::_post_gui_grab_click_focus() {
void Viewport::input_text(const String &p_text) { void Viewport::input_text(const String &p_text) {
if (gui.subwindow_focused) {
gui.subwindow_focused->input_text(p_text);
return;
}
if (gui.key_focus) { if (gui.key_focus) {
gui.key_focus->call("set_text", p_text); 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) { void Viewport::input(const Ref<InputEvent> &p_event, bool p_local_coords) {
ERR_FAIL_COND(!is_inside_tree()); 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; ev = p_event;
} }
if (is_embedding_subwindows() && _sub_windows_forward_input(p_event)) {
set_input_as_handled();
return;
}
if (!is_input_handled()) { 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 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; return size;
} }
bool Viewport::gui_has_modal_stack() const {
return gui.modal_stack.size();
}
void Viewport::set_disable_input(bool p_disable) { void Viewport::set_disable_input(bool p_disable) {
disable_input = p_disable; disable_input = p_disable;
} }
@ -2800,10 +3053,6 @@ Variant Viewport::gui_get_drag_data() const {
return gui.drag_data; 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 { String Viewport::get_configuration_warning() const {
/*if (get_parent() && !Object::cast_to<Control>(get_parent()) && !render_target) { /*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("get_mouse_position"), &Viewport::get_mouse_position);
ClassDB::bind_method(D_METHOD("warp_mouse", "to_position"), &Viewport::warp_mouse); 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_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("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("set_disable_input", "disable"), &Viewport::set_disable_input);
ClassDB::bind_method(D_METHOD("is_input_disabled"), &Viewport::is_input_disabled); 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); 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() { Viewport::Viewport() {
world_2d = Ref<World2D>(memnew(World2D)); world_2d = Ref<World2D>(memnew(World2D));
@ -3227,6 +3466,8 @@ Viewport::Viewport() {
gui.roots_order_dirty = false; gui.roots_order_dirty = false;
gui.mouse_focus = NULL; gui.mouse_focus = NULL;
gui.last_mouse_focus = NULL; gui.last_mouse_focus = NULL;
gui.subwindow_focused = nullptr;
gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED;
msaa = MSAA_DISABLED; msaa = MSAA_DISABLED;
@ -3302,6 +3543,16 @@ DisplayServer::WindowID SubViewport::get_window_id() const {
return DisplayServer::INVALID_WINDOW_ID; 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() { void SubViewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_arvr", "use"), &SubViewport::set_use_arvr); 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); 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_DISABLED);
BIND_ENUM_CONSTANT(UPDATE_ONCE); BIND_ENUM_CONSTANT(UPDATE_ONCE);
BIND_ENUM_CONSTANT(UPDATE_WHEN_VISIBLE); BIND_ENUM_CONSTANT(UPDATE_WHEN_VISIBLE);
BIND_ENUM_CONSTANT(UPDATE_WHEN_PARENT_VISIBLE);
BIND_ENUM_CONSTANT(UPDATE_ALWAYS); BIND_ENUM_CONSTANT(UPDATE_ALWAYS);
BIND_ENUM_CONSTANT(CLEAR_MODE_ALWAYS); BIND_ENUM_CONSTANT(CLEAR_MODE_ALWAYS);

View file

@ -151,6 +151,10 @@ public:
DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MAX, DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MAX,
}; };
enum {
SUBWINDOW_CANVAS_LAYER = 1024
};
private: private:
friend class ViewportTexture; friend class ViewportTexture;
@ -183,6 +187,7 @@ private:
RID viewport; RID viewport;
RID current_canvas; RID current_canvas;
RID subwindow_canvas;
bool audio_listener; bool audio_listener;
RID internal_listener; RID internal_listener;
@ -269,6 +274,31 @@ private:
Ref<ViewportTexture> default_texture; Ref<ViewportTexture> default_texture;
Set<ViewportTexture *> viewport_textures; 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 { struct GUI {
// info used when this is a window // info used when this is a window
@ -290,17 +320,24 @@ private:
Control *drag_preview; Control *drag_preview;
float tooltip_timer; float tooltip_timer;
float tooltip_delay; float tooltip_delay;
List<Control *> modal_stack;
Transform2D focus_inv_xform; 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; bool roots_order_dirty;
List<Control *> roots; List<Control *> roots;
int canvas_sort_index; //for sorting items with canvas as root int canvas_sort_index; //for sorting items with canvas as root
bool dragging; bool dragging;
bool embed_subwindows_hint; 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();
} gui; } gui;
@ -316,10 +353,7 @@ private:
void _gui_call_input(Control *p_control, const Ref<InputEvent> &p_input); void _gui_call_input(Control *p_control, const Ref<InputEvent> &p_input);
void _gui_call_notification(Control *p_control, int p_what); 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_roots();
void _gui_sort_modal_stack();
Control *_gui_find_control(const Point2 &p_global); 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); 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; friend class Control;
List<Control *>::Element *_gui_add_root_control(Control *p_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_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); String _gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_which = NULL);
void _gui_cancel_tooltip(); 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_force_drag(Control *p_base, const Variant &p_data, Control *p_control);
void _gui_set_drag_preview(Control *p_base, 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_remove_focus();
void _gui_unfocus_control(Control *p_control); void _gui_unfocus_control(Control *p_control);
bool _gui_control_has_focus(const Control *p_control); bool _gui_control_has_focus(const Control *p_control);
@ -367,8 +391,6 @@ private:
Control *_gui_get_focus_owner(); 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); bool _gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_check);
friend class Listener; friend class Listener;
@ -394,8 +416,20 @@ private:
void _update_canvas_items(Node *p_node); void _update_canvas_items(Node *p_node);
void _gui_set_root_order_dirty();
void _own_world_changed(); 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: 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); 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); void set_physics_object_picking(bool p_enable);
bool get_physics_object_picking(); bool get_physics_object_picking();
bool gui_has_modal_stack() const;
Variant gui_get_drag_data() const; Variant gui_get_drag_data() const;
Control *get_modal_stack_top() const;
void gui_reset_canvas_sort_index(); void gui_reset_canvas_sort_index();
int gui_get_canvas_sort_index(); int gui_get_canvas_sort_index();
@ -503,8 +534,6 @@ public:
void set_snap_controls_to_pixels(bool p_enable); void set_snap_controls_to_pixels(bool p_enable);
bool is_snap_controls_to_pixels_enabled() const; bool is_snap_controls_to_pixels_enabled() const;
void _subwindow_visibility_changed();
void set_input_as_handled(); void set_input_as_handled();
bool is_input_handled() const; bool is_input_handled() const;
@ -546,6 +575,7 @@ public:
UPDATE_DISABLED, UPDATE_DISABLED,
UPDATE_ONCE, //then goes to disabled UPDATE_ONCE, //then goes to disabled
UPDATE_WHEN_VISIBLE, // default UPDATE_WHEN_VISIBLE, // default
UPDATE_WHEN_PARENT_VISIBLE,
UPDATE_ALWAYS UPDATE_ALWAYS
}; };
@ -557,6 +587,7 @@ private:
protected: protected:
static void _bind_methods(); static void _bind_methods();
virtual DisplayServer::WindowID get_window_id() const; virtual DisplayServer::WindowID get_window_id() const;
void _notification(int p_what);
public: public:
void set_size(const Size2i &p_size); void set_size(const Size2i &p_size);

View file

@ -37,9 +37,14 @@
#include "scene/scene_string_names.h" #include "scene/scene_string_names.h"
void Window::set_title(const String &p_title) { void Window::set_title(const String &p_title) {
title = p_title; title = p_title;
if (window_id == DisplayServer::INVALID_WINDOW_ID)
return; if (embedder) {
DisplayServer::get_singleton()->window_set_title(p_title, window_id); 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 { String Window::get_title() const {
return title; return title;
@ -61,28 +66,25 @@ int Window::get_current_screen() const {
void Window::set_position(const Point2i &p_position) { void Window::set_position(const Point2i &p_position) {
position = p_position; position = p_position;
if (window_id == DisplayServer::INVALID_WINDOW_ID)
return; if (embedder) {
DisplayServer::get_singleton()->window_set_position(p_position, window_id); 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 { Point2i Window::get_position() const {
if (window_id != DisplayServer::INVALID_WINDOW_ID) {
position = DisplayServer::get_singleton()->window_get_position(window_id);
}
return position; return position;
} }
void Window::set_size(const Size2i &p_size) { void Window::set_size(const Size2i &p_size) {
size = p_size; size = p_size;
if (window_id != DisplayServer::INVALID_WINDOW_ID) { _update_window_size();
DisplayServer::get_singleton()->window_set_size(p_size, window_id);
}
_update_size();
} }
Size2i Window::get_size() const { Size2i Window::get_size() const {
if (window_id != DisplayServer::INVALID_WINDOW_ID) {
size = DisplayServer::get_singleton()->window_get_size(window_id);
}
return size; return size;
} }
@ -96,22 +98,19 @@ Size2i Window::get_real_size() const {
void Window::set_max_size(const Size2i &p_max_size) { void Window::set_max_size(const Size2i &p_max_size) {
max_size = p_max_size; max_size = p_max_size;
if (window_id == DisplayServer::INVALID_WINDOW_ID) DisplayServer::get_singleton()->window_set_min_size(max_size, window_id);
return; _update_window_size();
DisplayServer::get_singleton()->window_set_max_size(p_max_size, window_id);
} }
Size2i Window::get_max_size() const { 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 min_size;
}
return max_size;
} }
void Window::set_min_size(const Size2i &p_min_size) { void Window::set_min_size(const Size2i &p_min_size) {
min_size = p_min_size; min_size = p_min_size;
if (window_id == DisplayServer::INVALID_WINDOW_ID) DisplayServer::get_singleton()->window_set_max_size(max_size, window_id);
return; _update_window_size();
DisplayServer::get_singleton()->window_set_min_size(p_min_size, window_id);
} }
Size2i Window::get_min_size() const { Size2i Window::get_min_size() const {
if (window_id != DisplayServer::INVALID_WINDOW_ID) { if (window_id != DisplayServer::INVALID_WINDOW_ID) {
@ -123,9 +122,14 @@ Size2i Window::get_min_size() const {
void Window::set_mode(Mode p_mode) { void Window::set_mode(Mode p_mode) {
mode = p_mode; mode = p_mode;
if (window_id == DisplayServer::INVALID_WINDOW_ID)
return; if (embedder) {
DisplayServer::get_singleton()->window_set_mode(DisplayServer::WindowMode(p_mode), window_id); 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 { 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) { void Window::set_flag(Flags p_flag, bool p_enabled) {
ERR_FAIL_INDEX(p_flag, FLAG_MAX); ERR_FAIL_INDEX(p_flag, FLAG_MAX);
flags[p_flag] = p_enabled; flags[p_flag] = p_enabled;
if (window_id == DisplayServer::INVALID_WINDOW_ID)
return; if (embedder) {
DisplayServer::get_singleton()->window_set_flag(DisplayServer::WindowFlags(p_flag), p_enabled, window_id); 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 { bool Window::get_flag(Flags p_flag) const {
@ -165,7 +174,11 @@ void Window::request_attention() {
} }
} }
void Window::move_to_foreground() { 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); 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 DisplayServer::get_singleton()->window_can_draw(window_id);
} }
return true; return visible;
} }
void Window::set_ime_active(bool p_active) { 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 { bool Window::is_embedded() const {
ERR_FAIL_COND_V(!is_inside_tree(), false); ERR_FAIL_COND_V(!is_inside_tree(), false);
if (get_parent_viewport()) { Viewport *parent_vp = get_parent_viewport();
return get_parent_viewport()->is_embedding_subwindows(); return parent_vp && parent_vp->is_embedding_subwindows();
} else {
return false;
}
} }
void Window::_make_window() { void Window::_make_window() {
@ -210,6 +220,7 @@ void Window::_make_window() {
f |= (1 << i); f |= (1 << i);
} }
} }
window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), f, Rect2i(position, size)); window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), f, Rect2i(position, size));
ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID); ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID);
DisplayServer::get_singleton()->window_set_current_screen(current_screen, 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_min_size(min_size, window_id);
DisplayServer::get_singleton()->window_set_title(title, 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) { if (transient_parent && transient_parent->window_id != DisplayServer::INVALID_WINDOW_ID) {
DisplayServer::get_singleton()->window_set_transient(window_id, transient_parent->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); 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() { void Window::_update_from_window() {
@ -236,10 +249,6 @@ void Window::_update_from_window() {
for (int i = 0; i < FLAG_MAX; i++) { for (int i = 0; i < FLAG_MAX; i++) {
flags[i] = DisplayServer::get_singleton()->window_get_flag(DisplayServer::WindowFlags(i), window_id); 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() { void Window::_clear_window() {
@ -256,16 +265,26 @@ void Window::_clear_window() {
} }
_update_from_window(); _update_from_window();
print_line("deleting window bye");
DisplayServer::get_singleton()->delete_sub_window(window_id); DisplayServer::get_singleton()->delete_sub_window(window_id);
window_id = DisplayServer::INVALID_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; //we must always accept this as the truth
_update_size(); 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) { void Window::_propagate_window_notification(Node *p_node, int p_notification) {
@ -335,11 +354,15 @@ void Window::set_visible(bool p_visible) {
return; return;
} }
if (updating_child_controls) {
_update_child_controls();
}
ERR_FAIL_COND_MSG(get_parent() == nullptr, "Can't change visibility of main window."); 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) { if (!p_visible && window_id != DisplayServer::INVALID_WINDOW_ID) {
_clear_window(); _clear_window();
} }
@ -348,7 +371,16 @@ void Window::set_visible(bool p_visible) {
_update_window_callbacks(); _update_window_callbacks();
} }
} else { } 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) { if (!visible) {
@ -356,6 +388,8 @@ void Window::set_visible(bool p_visible) {
} }
notification(NOTIFICATION_VISIBILITY_CHANGED); notification(NOTIFICATION_VISIBILITY_CHANGED);
emit_signal(SceneStringNames::get_singleton()->visibility_changed); emit_signal(SceneStringNames::get_singleton()->visibility_changed);
VS::get_singleton()->viewport_set_active(get_viewport_rid(), visible);
} }
void Window::_clear_transient() { void Window::_clear_transient() {
@ -458,7 +492,38 @@ bool Window::is_visible() const {
return visible; 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;
Size2i final_size_override; Size2i final_size_override;
@ -563,7 +628,7 @@ void Window::_update_size() {
stretch_transform.elements[2] = margin * scale; 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); _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); notification(NOTIFICATION_WM_SIZE_CHANGED);
if (embedder) {
embedder->_sub_window_update(this);
}
} }
void Window::_update_window_callbacks() { 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_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_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_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); 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) { void Window::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) { 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 //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 { } else {
if (get_parent() == nullptr) { if (get_parent() == nullptr) {
//it's the root window! //it's the root window!
visible = true; //always visible visible = true; //always visible
window_id = DisplayServer::MAIN_WINDOW_ID; window_id = DisplayServer::MAIN_WINDOW_ID;
_update_from_window(); _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(); _update_window_callbacks();
VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_WHEN_VISIBLE);
} else { } else {
//create //create
if (visible) { if (visible) {
@ -623,6 +738,7 @@ void Window::_notification(int p_what) {
if (visible) { if (visible) {
notification(NOTIFICATION_VISIBILITY_CHANGED); notification(NOTIFICATION_VISIBILITY_CHANGED);
emit_signal(SceneStringNames::get_singleton()->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) { if (window_id == DisplayServer::MAIN_WINDOW_ID) {
VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_DISABLED);
_update_window_callbacks(); _update_window_callbacks();
} else { } else {
_clear_window(); _clear_window();
} }
} else { } 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.x < 0);
ERR_FAIL_COND(p_size.y < 0); ERR_FAIL_COND(p_size.y < 0);
content_scale_size = p_size; content_scale_size = p_size;
_update_size(); _update_viewport_size();
} }
Size2i Window::get_content_scale_size() const { 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) { void Window::set_content_scale_mode(ContentScaleMode p_mode) {
content_scale_mode = p_mode; content_scale_mode = p_mode;
_update_size(); _update_viewport_size();
} }
Window::ContentScaleMode Window::get_content_scale_mode() const { Window::ContentScaleMode Window::get_content_scale_mode() const {
return content_scale_mode; 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) { void Window::set_content_scale_aspect(ContentScaleAspect p_aspect) {
content_scale_aspect = p_aspect; content_scale_aspect = p_aspect;
_update_size(); _update_viewport_size();
} }
Window::ContentScaleAspect Window::get_content_scale_aspect() const { Window::ContentScaleAspect Window::get_content_scale_aspect() const {
return content_scale_aspect; 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."); ERR_FAIL_MSG("Only the root window can set and use font oversampling.");
} }
use_font_oversampling = p_oversampling; use_font_oversampling = p_oversampling;
_update_size(); _update_viewport_size();
} }
bool Window::is_using_font_oversampling() const { bool Window::is_using_font_oversampling() const {
return use_font_oversampling; return use_font_oversampling;
@ -724,22 +849,17 @@ Size2 Window::_get_contents_minimum_size() const {
} }
void Window::_update_child_controls() { void Window::_update_child_controls() {
Size2 max = _get_contents_minimum_size(); if (!updating_child_controls) {
Size2 new_size(MAX(max.x, size.x), MAX(max.y, size.y));
if (new_size != size) {
set_size(new_size);
}
set_min_size(max);
updating_child_controls = false;
}
void Window::child_controls_changed() {
if (!is_inside_tree()) {
return; return;
} }
if (updating_child_controls) { _update_window_size();
updating_child_controls = false;
}
void Window::child_controls_changed() {
if (!is_inside_tree() || !visible || updating_child_controls) {
return; return;
} }
@ -762,7 +882,7 @@ void Window::_window_input(const Ref<InputEvent> &p_ev) {
if (exclusive_child != nullptr) { if (exclusive_child != nullptr) {
exclusive_child->grab_focus(); exclusive_child->grab_focus();
print_line("drop because of exclusive");
return; //has an exclusive child, can't get events until child is closed 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) { void Window::popup(const Rect2 &p_screen_rect) {
emit_signal("about_to_popup"); emit_signal("about_to_popup");
if (p_screen_rect != Rect2()) { if (p_screen_rect != Rect2()) {
set_position(p_screen_rect.position); set_position(p_screen_rect.position);
set_size(p_screen_rect.size); set_size(p_screen_rect.size);
@ -917,7 +1038,9 @@ Size2 Window::get_contents_minimum_size() const {
} }
void Window::grab_focus() { 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); 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)) { 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 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) { 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()) { 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); 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) { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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()) { if (is_embedded()) {
//viewport //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 { } else {
int x = get_position().x; int x = get_position().x;
int closest_dist = 0x7FFFFFFF; int closest_dist = 0x7FFFFFFF;
@ -1188,6 +1337,7 @@ Window::Window() {
} }
content_scale_mode = CONTENT_SCALE_MODE_DISABLED; content_scale_mode = CONTENT_SCALE_MODE_DISABLED;
content_scale_aspect = CONTENT_SCALE_ASPECT_IGNORE; content_scale_aspect = CONTENT_SCALE_ASPECT_IGNORE;
VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_DISABLED);
} }
Window::~Window() { Window::~Window() {
} }

View file

@ -103,20 +103,13 @@ private:
void _clear_window(); void _clear_window();
void _update_from_window(); void _update_from_window();
void _resize_callback(const Size2i &p_callback); void _update_viewport_size();
void _event_callback(DisplayServer::WindowEvent p_event); void _update_window_size();
void _update_size();
void _propagate_window_notification(Node *p_node, int p_notification); void _propagate_window_notification(Node *p_node, int p_notification);
virtual DisplayServer::WindowID get_window_id() const; 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 _update_window_callbacks();
void _clear_transient(); void _clear_transient();
@ -130,6 +123,18 @@ private:
Control *theme_owner = nullptr; Control *theme_owner = nullptr;
Window *theme_owner_window = 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: protected:
virtual void _post_popup() {} virtual void _post_popup() {}
virtual Size2 _get_contents_minimum_size() const; 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_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; 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();
~Window(); ~Window();

View file

@ -524,18 +524,19 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// WindowDialog // WindowDialog
theme->set_stylebox("panel", "AcceptDialog", default_style); theme->set_stylebox("panel", "Window", 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_stylebox("window_panel", "Window", 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_constant("scaleborder_size", "Window", 4 * scale);
theme->set_font("title_font", "AcceptDialog", large_font); theme->set_font("title_font", "Window", large_font);
theme->set_color("title_color", "AcceptDialog", Color(0, 0, 0)); theme->set_color("title_color", "Window", Color(0, 0, 0));
theme->set_constant("title_height", "AcceptDialog", 20 * scale); theme->set_constant("title_height", "Window", 20 * scale);
theme->set_constant("resize_margin", "Window", 4 * scale);
theme->set_icon("close", "AcceptDialog", make_icon(close_png)); theme->set_icon("close", "Window", make_icon(close_png));
theme->set_icon("close_highlight", "AcceptDialog", make_icon(close_hl_png)); theme->set_icon("close_highlight", "Window", make_icon(close_hl_png));
theme->set_constant("close_h_ofs", "AcceptDialog", 18 * scale); theme->set_constant("close_h_ofs", "Window", 18 * scale);
theme->set_constant("close_v_ofs", "AcceptDialog", 18 * scale); theme->set_constant("close_v_ofs", "Window", 18 * scale);
// File Dialog // File Dialog

View file

@ -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_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_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_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_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)); ClassDB::bind_method(D_METHOD("window_set_input_text_callback", "callback", "window_id"), &DisplayServer::window_set_input_text_callback, DEFVAL(MAIN_WINDOW_ID));

View file

@ -182,7 +182,7 @@ public:
virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i & = Rect2i()); 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 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 { enum WindowEvent {
WINDOW_EVENT_MOUSE_ENTER, WINDOW_EVENT_MOUSE_ENTER,

View file

@ -316,7 +316,10 @@ void VisualServerViewport::draw_viewports() {
//draw viewports //draw viewports
RENDER_TIMESTAMP(">Render 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]; Viewport *vp = active_viewports[i];
@ -328,11 +331,37 @@ void VisualServerViewport::draw_viewports() {
} }
//ERR_CONTINUE(!vp->render_target.is_valid()); //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; visible = visible && vp->size.x > 1 && vp->size.y > 1;
if (!visible) if (visible) {
continue; 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)); RENDER_TIMESTAMP(">Rendering Viewport " + itos(i));

View file

@ -73,6 +73,8 @@ public:
RID shadow_atlas; RID shadow_atlas;
int shadow_atlas_size; int shadow_atlas_size;
uint64_t last_pass = 0;
int render_info[VS::VIEWPORT_RENDER_INFO_MAX]; int render_info[VS::VIEWPORT_RENDER_INFO_MAX];
VS::ViewportDebugDraw debug_draw; VS::ViewportDebugDraw debug_draw;
@ -129,6 +131,8 @@ public:
} }
}; };
uint64_t draw_viewports_pass = 0;
mutable RID_PtrOwner<Viewport> viewport_owner; mutable RID_PtrOwner<Viewport> viewport_owner;
struct ViewportSort { struct ViewportSort {
@ -139,9 +143,9 @@ public:
if (left_to_screen == right_to_screen) { 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);
} }
}; };

View file

@ -2060,6 +2060,7 @@ void VisualServer::_bind_methods() {
BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_DISABLED); BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_DISABLED);
BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_ONCE); BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_ONCE);
BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_WHEN_VISIBLE); 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_UPDATE_ALWAYS);
BIND_ENUM_CONSTANT(VIEWPORT_CLEAR_ALWAYS); BIND_ENUM_CONSTANT(VIEWPORT_CLEAR_ALWAYS);

View file

@ -592,6 +592,7 @@ public:
VIEWPORT_UPDATE_DISABLED, VIEWPORT_UPDATE_DISABLED,
VIEWPORT_UPDATE_ONCE, //then goes to disabled, must be manually updated VIEWPORT_UPDATE_ONCE, //then goes to disabled, must be manually updated
VIEWPORT_UPDATE_WHEN_VISIBLE, // default VIEWPORT_UPDATE_WHEN_VISIBLE, // default
VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE,
VIEWPORT_UPDATE_ALWAYS VIEWPORT_UPDATE_ALWAYS
}; };