diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 310dc95443..3d55237dff 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -362,42 +362,52 @@ void OptionsGroup::activate_line(Line& line) } // create all controls for the option group from the m_lines -bool OptionsGroup::activate() +bool OptionsGroup::activate(std::function throw_if_canceled) { if (sizer)//(!sizer->IsEmpty()) return false; - if (staticbox) { - stb = new wxStaticBox(m_parent, wxID_ANY, _(title)); - if (!wxOSX) stb->SetBackgroundStyle(wxBG_STYLE_PAINT); - stb->SetFont(wxOSX ? wxGetApp().normal_font() : wxGetApp().bold_font()); + try { + if (staticbox) { + stb = new wxStaticBox(m_parent, wxID_ANY, _(title)); + if (!wxOSX) stb->SetBackgroundStyle(wxBG_STYLE_PAINT); + stb->SetFont(wxOSX ? wxGetApp().normal_font() : wxGetApp().bold_font()); + } + else + stb = nullptr; + sizer = (staticbox ? new wxStaticBoxSizer(stb, wxVERTICAL) : new wxBoxSizer(wxVERTICAL)); + + auto num_columns = 1U; + size_t grow_col = 1; + + if (label_width == 0) + grow_col = 0; + else + num_columns++; + + if (extra_column) { + num_columns++; + grow_col++; + } + + m_grid_sizer = new wxFlexGridSizer(0, num_columns, 1, 0); + static_cast(m_grid_sizer)->SetFlexibleDirection(wxBOTH); + static_cast(m_grid_sizer)->AddGrowableCol(grow_col); + + sizer->Add(m_grid_sizer, 0, wxEXPAND | wxALL, wxOSX || !staticbox ? 0 : 5); + + // activate lines + for (Line& line: m_lines) { + throw_if_canceled(); + activate_line(line); + } + } catch (UIBuildCanceled&) { + auto p = sizer; + this->clear(); + p->Clear(true); + delete p; + throw; } - else - stb = nullptr; - sizer = (staticbox ? new wxStaticBoxSizer(stb, wxVERTICAL) : new wxBoxSizer(wxVERTICAL)); - - auto num_columns = 1U; - size_t grow_col = 1; - - if (label_width == 0) - grow_col = 0; - else - num_columns++; - - if (extra_column) { - num_columns++; - grow_col++; - } - - m_grid_sizer = new wxFlexGridSizer(0, num_columns, 1, 0); - static_cast(m_grid_sizer)->SetFlexibleDirection(wxBOTH); - static_cast(m_grid_sizer)->AddGrowableCol(grow_col); - - sizer->Add(m_grid_sizer, 0, wxEXPAND | wxALL, wxOSX || !staticbox ? 0 : 5); - - // activate lines - for (Line& line: m_lines) - activate_line(line); return true; } diff --git a/src/slic3r/GUI/OptionsGroup.hpp b/src/slic3r/GUI/OptionsGroup.hpp index 4d70347aa4..8dcba2213c 100644 --- a/src/slic3r/GUI/OptionsGroup.hpp +++ b/src/slic3r/GUI/OptionsGroup.hpp @@ -24,6 +24,9 @@ namespace Slic3r { namespace GUI { +// Thrown if the building of a parameter page is canceled. +class UIBuildCanceled : public std::exception {}; + /// Widget type describes a function object that returns a wxWindow (our widget) and accepts a wxWidget (parent window). using widget_t = std::function;//!std::function; @@ -124,7 +127,7 @@ public: void activate_line(Line& line); // create all controls for the option group from the m_lines - bool activate(); + bool activate(std::function throw_if_canceled = [](){}); // delete all controls from the option group void clear(); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 7352c70376..e688034712 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -297,15 +297,28 @@ void Tab::create_preset_tab() // This helps to process all the cursor key events on Windows in the tree control, // so that the cursor jumps to the last item. m_treectrl->Bind(wxEVT_TREE_SEL_CHANGED, [this](wxTreeEvent&) { - if (!m_disable_tree_sel_changed_event && !m_pages.empty()) - m_page_switch_planned = true; + if (!m_disable_tree_sel_changed_event && !m_pages.empty()) { + if (m_page_switch_running) + m_page_switch_planned = true; + else { + m_page_switch_running = true; + do { + m_page_switch_planned = false; + } while (this->tree_sel_change_delayed()); + m_page_switch_running = false; + } + } + m_treectrl->Update(); }); +#if 0 m_treectrl->Bind(wxEVT_IDLE, [this](wxIdleEvent&) { if (m_page_switch_planned) { - this->tree_sel_change_delayed(); - m_page_switch_planned = false; + do { + m_page_switch_planned = false; + } while (this->tree_sel_change_delayed()); } }); +#endif m_treectrl->Bind(wxEVT_KEY_DOWN, &Tab::OnKeyDown, this); @@ -424,7 +437,7 @@ void Tab::OnActivate() #endif // __WXOSX__ // create controls on active page - active_selected_page(); + activate_selected_page(); // m_active_page->Show(); m_hsizer->Layout(); Refresh(); @@ -2820,9 +2833,9 @@ void TabPrinter::update_pages() rebuild_page_tree(); } -void TabPrinter::active_selected_page() +void TabPrinter::activate_selected_page(std::function throw_if_canceled) { - Tab::active_selected_page(); + Tab::activate_selected_page(throw_if_canceled); // "extruders_count" doesn't update from the update_config(), // so update it implicitly @@ -3372,19 +3385,20 @@ void Tab::update_description_lines() update_preset_description_line(); } -void Tab::active_selected_page() +void Tab::activate_selected_page(std::function throw_if_canceled) { if (!m_active_page) return; - m_active_page->activate(m_mode); + m_active_page->activate(m_mode, throw_if_canceled); update_changed_ui(); update_description_lines(); toggle_options(); } -void Tab::tree_sel_change_delayed() +bool Tab::tree_sel_change_delayed() { +#if 1 // There is a bug related to Ubuntu overlay scrollbars, see https://github.com/prusa3d/PrusaSlicer/issues/898 and https://github.com/prusa3d/PrusaSlicer/issues/952. // The issue apparently manifests when Show()ing a window with overlay scrollbars while the UI is frozen. For this reason, // we will Thaw the UI prematurely on Linux. This means destroing the no_updates object prematurely. @@ -3398,6 +3412,7 @@ void Tab::tree_sel_change_delayed() //#ifdef __WXOSX__ // Use Freeze/Thaw to avoid flickering during clear/activate new page wxWindowUpdateLocker noUpdates(this); //#endif +#endif #endif Page* page = nullptr; @@ -3411,29 +3426,50 @@ void Tab::tree_sel_change_delayed() m_is_modified_values = page->m_is_modified_values; break; } - if (page == nullptr || m_active_page == page) return; + if (page == nullptr || m_active_page == page) + return false; // clear pages from the controls m_active_page = page; - clear_pages(); + + auto throw_if_canceled = std::function([this](){ +#ifdef WIN32 + wxCheckForInterrupt(m_treectrl); + if (m_page_switch_planned) + throw UIBuildCanceled(); +#endif // WIN32 + }); - //for (auto& el : m_pages) - // el.get()->Hide(); + try { + clear_pages(); + throw_if_canceled(); - if (wxGetApp().mainframe->is_active_and_shown_tab(this)) { - active_selected_page(); -// m_active_page->Show(); + //for (auto& el : m_pages) + // el.get()->Hide(); + + if (wxGetApp().mainframe->is_active_and_shown_tab(this)) { + activate_selected_page(throw_if_canceled); + // m_active_page->Show(); + } + + #ifdef __linux__ + no_updates.reset(nullptr); + #endif + + update_undo_buttons(); + throw_if_canceled(); + + // m_active_page->Show(); + m_hsizer->Layout(); + throw_if_canceled(); + Refresh(); + } catch (const UIBuildCanceled&) { + if (m_active_page) + m_active_page->clear(); + return true; } - #ifdef __linux__ - no_updates.reset(nullptr); - #endif - - update_undo_buttons(); - -// m_active_page->Show(); - m_hsizer->Layout(); - Refresh(); + return false; } void Tab::OnKeyDown(wxKeyEvent& event) @@ -3892,16 +3928,17 @@ void Page::update_visibility(ConfigOptionMode mode, bool update_contolls_visibil m_show = ret_val; } -void Page::activate(ConfigOptionMode mode) +void Page::activate(ConfigOptionMode mode, std::function throw_if_canceled) { //if (m_parent) //m_parent->SetSizer(m_vsizer); for (auto group : m_optgroups) { - if (!group->activate()) + if (!group->activate(throw_if_canceled)) continue; m_vsizer->Add(group->sizer, 0, wxEXPAND | wxALL, 10); group->update_visibility(mode); group->reload_config(); + throw_if_canceled(); } } diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 9d65d767a1..a3711f453e 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -73,7 +73,7 @@ public: void set_config(DynamicPrintConfig* config_in) { m_config = config_in; } void reload_config(); void update_visibility(ConfigOptionMode mode, bool update_contolls_visibility); - void activate(ConfigOptionMode mode); + void activate(ConfigOptionMode mode, std::function throw_if_canceled); void clear(); void msw_rescale(); void sys_color_changed(); @@ -239,6 +239,7 @@ protected: DynamicPrintConfig m_cache_config; + bool m_page_switch_running = false; bool m_page_switch_planned = false; public: @@ -294,7 +295,7 @@ public: virtual void clear_pages(); virtual void update_description_lines(); - virtual void active_selected_page(); + virtual void activate_selected_page(std::function throw_if_canceled); void OnTreeSelChange(wxTreeEvent& event); void OnKeyDown(wxKeyEvent& event); @@ -354,7 +355,8 @@ protected: void compatible_widget_reload(PresetDependencies &deps); void load_key_value(const std::string& opt_key, const boost::any& value, bool saved_value = false); - void tree_sel_change_delayed(); + // return true if cancelled + bool tree_sel_change_delayed(); void on_presets_changed(); void build_preset_description_line(ConfigOptionsGroup* optgroup); void update_preset_description_line(); @@ -447,7 +449,7 @@ public: void build() override; void build_fff(); void build_sla(); - void active_selected_page() override; + void activate_selected_page(std::function throw_if_canceled) override; void clear_pages() override; void toggle_options() override; void update() override;