From 14ae9ac8655e39e73ccdd4d8665e585ee4e8ac24 Mon Sep 17 00:00:00 2001 From: Hilderin <81109165+Hilderin@users.noreply.github.com> Date: Sat, 14 Sep 2024 13:30:42 -0400 Subject: [PATCH] Fix progress dialog steals focus --- editor/editor_node.cpp | 15 +++++++- editor/editor_node.h | 1 + editor/progress_dialog.cpp | 72 +++++++++++++++++++++----------------- editor/progress_dialog.h | 15 ++++---- editor/window_wrapper.cpp | 2 -- 5 files changed, 64 insertions(+), 41 deletions(-) diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 66fd2cf904ec..8e73d83448c0 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -341,6 +341,19 @@ void EditorNode::_update_title() { } } +void EditorNode::input(const Ref &p_event) { + Ref k = p_event; + if (k.is_null()) { + return; + } + + // Prevent all shortcuts while the progress dialog is displayed + // to simulate a exclusive popup. + if (progress_dialog->is_visible()) { + get_tree()->get_root()->set_input_as_handled(); + } +} + void EditorNode::shortcut_input(const Ref &p_event) { ERR_FAIL_COND(p_event.is_null()); @@ -6840,7 +6853,7 @@ EditorNode::EditorNode() { resource_preview = memnew(EditorResourcePreview); add_child(resource_preview); progress_dialog = memnew(ProgressDialog); - progress_dialog->set_unparent_when_invisible(true); + add_child(progress_dialog); progress_dialog->connect(SceneStringName(visibility_changed), callable_mp(this, &EditorNode::_progress_dialog_visibility_changed)); gui_base = memnew(Panel); diff --git a/editor/editor_node.h b/editor/editor_node.h index 4127dd1539db..95a299d06e7b 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -592,6 +592,7 @@ class EditorNode : public Node { void _exit_editor(int p_exit_code); + virtual void input(const Ref &p_event) override; virtual void shortcut_input(const Ref &p_event) override; bool has_main_screen() const { return true; } diff --git a/editor/progress_dialog.cpp b/editor/progress_dialog.cpp index 2f345e516161..e054a52259b7 100644 --- a/editor/progress_dialog.cpp +++ b/editor/progress_dialog.cpp @@ -35,6 +35,7 @@ #include "editor/editor_node.h" #include "editor/themes/editor_scale.h" #include "main/main.h" +#include "scene/main/window.h" #include "servers/display_server.h" void BackgroundProgress::_add_task(const String &p_task, const String &p_label, int p_steps) { @@ -126,6 +127,21 @@ void BackgroundProgress::end_task(const String &p_task) { ProgressDialog *ProgressDialog::singleton = nullptr; +void ProgressDialog::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_THEME_CHANGED: { + Ref style = main->get_theme_stylebox(SceneStringName(panel), SNAME("PopupMenu")); + main_border_size = style->get_minimum_size(); + main->set_offset(SIDE_LEFT, style->get_margin(SIDE_LEFT)); + main->set_offset(SIDE_RIGHT, -style->get_margin(SIDE_RIGHT)); + main->set_offset(SIDE_TOP, style->get_margin(SIDE_TOP)); + main->set_offset(SIDE_BOTTOM, -style->get_margin(SIDE_BOTTOM)); + + center_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), "PopupPanel")); + } break; + } +} + void ProgressDialog::_update_ui() { // Run main loop for two frames. if (is_inside_tree()) { @@ -135,33 +151,20 @@ void ProgressDialog::_update_ui() { } void ProgressDialog::_popup() { + // Activate processing of all inputs in EditorNode, and the EditorNode::input method + // will discard every key input. + EditorNode::get_singleton()->set_process_input(true); + Size2 ms = main->get_combined_minimum_size(); ms.width = MAX(500 * EDSCALE, ms.width); + ms += main_border_size; - Ref style = main->get_theme_stylebox(SceneStringName(panel), SNAME("PopupMenu")); - ms += style->get_minimum_size(); + center_panel->set_custom_minimum_size(ms); - main->set_offset(SIDE_LEFT, style->get_margin(SIDE_LEFT)); - main->set_offset(SIDE_RIGHT, -style->get_margin(SIDE_RIGHT)); - main->set_offset(SIDE_TOP, style->get_margin(SIDE_TOP)); - main->set_offset(SIDE_BOTTOM, -style->get_margin(SIDE_BOTTOM)); + // Be sure it's always the very last node to prevent user interaction while the dialog is visible. + get_parent()->move_child(this, get_parent()->get_child_count() - 1); - if (is_inside_tree()) { - Rect2i adjust = _popup_adjust_rect(); - if (adjust != Rect2i()) { - set_position(adjust.position); - set_size(adjust.size); - } - } else { - for (Window *window : host_windows) { - if (window->has_focus()) { - popup_exclusive_centered(window, ms); - return; - } - } - // No host window found, use main window. - EditorInterface::get_singleton()->popup_dialog_centered(this, ms); - } + show(); } void ProgressDialog::add_task(const String &p_task, const String &p_label, int p_steps, bool p_can_cancel) { @@ -231,27 +234,32 @@ void ProgressDialog::end_task(const String &p_task) { if (tasks.is_empty()) { hide(); + EditorNode::get_singleton()->set_process_input(false); } else { _popup(); } } -void ProgressDialog::add_host_window(Window *p_window) { - ERR_FAIL_NULL(p_window); - host_windows.push_back(p_window); -} - void ProgressDialog::_cancel_pressed() { canceled = true; } ProgressDialog::ProgressDialog() { - main = memnew(VBoxContainer); - add_child(main); - main->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); - set_exclusive(true); - set_flag(Window::FLAG_POPUP, false); + // We want to cover the entire screen to prevent the user from interacting with the Editor. + set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); + // Be sure it's the top most component. + set_z_index(RS::CANVAS_ITEM_Z_MAX); singleton = this; + hide(); + + center_panel = memnew(PanelContainer); + add_child(center_panel); + center_panel->set_h_size_flags(SIZE_SHRINK_BEGIN); + center_panel->set_v_size_flags(SIZE_SHRINK_BEGIN); + + main = memnew(VBoxContainer); + center_panel->add_child(main); + cancel_hb = memnew(HBoxContainer); main->add_child(cancel_hb); cancel_hb->hide(); diff --git a/editor/progress_dialog.h b/editor/progress_dialog.h index 355812b0b7a6..660262f92206 100644 --- a/editor/progress_dialog.h +++ b/editor/progress_dialog.h @@ -33,8 +33,9 @@ #include "scene/gui/box_container.h" #include "scene/gui/button.h" +#include "scene/gui/center_container.h" #include "scene/gui/label.h" -#include "scene/gui/popup.h" +#include "scene/gui/panel_container.h" #include "scene/gui/progress_bar.h" class BackgroundProgress : public HBoxContainer { @@ -64,8 +65,8 @@ class BackgroundProgress : public HBoxContainer { BackgroundProgress() {} }; -class ProgressDialog : public PopupPanel { - GDCLASS(ProgressDialog, PopupPanel); +class ProgressDialog : public CenterContainer { + GDCLASS(ProgressDialog, CenterContainer); struct Task { String task; VBoxContainer *vb = nullptr; @@ -77,9 +78,10 @@ class ProgressDialog : public PopupPanel { Button *cancel = nullptr; HashMap tasks; + PanelContainer *center_panel = nullptr; VBoxContainer *main = nullptr; - LocalVector host_windows; + Size2 main_border_size; static ProgressDialog *singleton; void _popup(); @@ -89,14 +91,15 @@ class ProgressDialog : public PopupPanel { void _update_ui(); bool canceled = false; +protected: + void _notification(int p_what); + public: static ProgressDialog *get_singleton() { return singleton; } void add_task(const String &p_task, const String &p_label, int p_steps, bool p_can_cancel = false); bool task_step(const String &p_task, const String &p_state, int p_step = -1, bool p_force_redraw = true); void end_task(const String &p_task); - void add_host_window(Window *p_window); - ProgressDialog(); }; diff --git a/editor/window_wrapper.cpp b/editor/window_wrapper.cpp index 9496ba016cd0..90539b3d4415 100644 --- a/editor/window_wrapper.cpp +++ b/editor/window_wrapper.cpp @@ -333,8 +333,6 @@ WindowWrapper::WindowWrapper() { window_background = memnew(Panel); window_background->set_anchors_and_offsets_preset(PRESET_FULL_RECT); window->add_child(window_background); - - ProgressDialog::get_singleton()->add_host_window(window); } // ScreenSelect