From ec247582df69755509ebf910e03a9a091930b10e Mon Sep 17 00:00:00 2001 From: "chunmao.guo" Date: Tue, 27 Feb 2024 12:15:27 +0800 Subject: [PATCH] ENH: reuse controls in param Field Change-Id: I42bb4da01e1e9b64c343b7fda4357a9553cf8684 Jira: STUDIO-5983 --- src/slic3r/GUI/Field.cpp | 149 +++++++++++++++++++++++---- src/slic3r/GUI/GUI_App.cpp | 13 ++- src/slic3r/GUI/OptionsGroup.cpp | 7 +- src/slic3r/GUI/Tab.cpp | 6 +- src/slic3r/GUI/Widgets/ComboBox.cpp | 1 + src/slic3r/GUI/Widgets/TextInput.cpp | 8 ++ src/slic3r/GUI/Widgets/TextInput.hpp | 2 + 7 files changed, 158 insertions(+), 28 deletions(-) diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 47dc78c35..fac266f00 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -83,7 +83,6 @@ wxString get_thumbnails_string(const std::vector& values) return ret_str; } - Field::~Field() { if (m_on_kill_focus) @@ -94,11 +93,6 @@ Field::~Field() m_back_to_initial_value = nullptr; if (m_back_to_sys_value) m_back_to_sys_value = nullptr; - if (getWindow()) { - wxWindow* win = getWindow(); - win->Destroy(); - win = nullptr; - } } void Field::PostInitialize() @@ -162,7 +156,7 @@ void Field::PostInitialize() } evt.Skip(); - }); + }, getWindow()->GetId()); } } @@ -486,6 +480,101 @@ void Field::sys_color_changed() #endif } +std::vector**> spools; +std::vector*> spools2; + +void switch_window_pools() +{ + for (auto p : spools) { + spools2.push_back(*p); + *p = new std::deque; + } +} + +void release_window_pools() +{ + for (auto p : spools2) { + delete p; + } + spools2.clear(); +} + +template +struct Builder +{ + Builder() + { + pool_ = new std::deque; + spools.push_back(&pool_); + } + + template + T *build(wxWindow * p, Args ...args) + { + if (pool_->empty()) { + auto t = new T(p, args...); + t->SetClientData(pool_); + return t; + } + auto t = dynamic_cast(pool_->front()); + pool_->pop_front(); + t->Reparent(p); + t->Enable(); + t->Show(); + return t; + } + std::deque* pool_; +}; + +struct wxEventFunctorRef +{ + wxEventFunctor * func; +}; + +wxEventFunctor & wxMakeEventFunctor(const int, wxEventFunctorRef func) +{ + return *func.func; +} + +struct myEvtHandler : wxEvtHandler +{ + void UnbindAll() + { + size_t cookie; + for (wxDynamicEventTableEntry *entry = GetFirstDynamicEntry(cookie); + entry; + entry = GetNextDynamicEntry(cookie)) { + // In Field, All Bind has id, but for TextInput, ComboBox, SpinInput, all not + if (entry->m_id != wxID_ANY && entry->m_lastId == wxID_ANY) + Unbind(entry->m_eventType, + wxEventFunctorRef{entry->m_fn}, + entry->m_id, + entry->m_lastId, + entry->m_callbackUserData); + //DoUnbind(entry->m_id, entry->m_lastId, entry->m_eventType, *entry->m_fn, entry->m_callbackUserData); + } + } +}; + +static void unbind_events(wxEvtHandler *h) +{ + static_cast(h)->UnbindAll(); +} + +void free_window(wxWindow *win) +{ + unbind_events(win); + for (auto c : win->GetChildren()) + if (dynamic_cast(c)) + unbind_events(c); + win->Hide(); + if (auto sizer = win->GetContainingSizer()) + sizer->Clear(); + win->Reparent(wxGetApp().mainframe); + if (win->GetClientData()) + reinterpret_cast*>(win->GetClientData())->push_back(win); +} + template bool is_defined_input_value(wxWindow* win, const ConfigOptionType& type) { @@ -550,10 +639,15 @@ void TextCtrl::BUILD() { // BBS: new param ui style // const long style = m_opt.multiline ? wxTE_MULTILINE : wxTE_PROCESS_ENTER/*0*/; + static Builder builder1; + static Builder<::TextInput> builder2; auto temp = m_opt.multiline - ? (wxWindow *) new wxTextCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, wxTE_MULTILINE) - : new ::TextInput(m_parent, text_value, _L(m_opt.sidetext), "", wxDefaultPosition, size, wxTE_PROCESS_ENTER); + ? (wxWindow*)builder1.build(m_parent, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE) + : builder2.build(m_parent, "", "", "", wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER); + temp->SetLabel(_L(m_opt.sidetext)); auto text_ctrl = m_opt.multiline ? (wxTextCtrl *)temp : ((TextInput *) temp)->GetTextCtrl(); + text_ctrl->SetLabel(text_value); + temp->SetSize(size); m_combine_side_text = !m_opt.multiline; if (parent_is_custom_ctrl && m_opt.height < 0) opt_height = (double) text_ctrl->GetSize().GetHeight() / m_em_unit; @@ -608,7 +702,7 @@ void TextCtrl::BUILD() { if (!bEnterPressed) propagate_value(); }), temp->GetId()); -/* + /* // select all text using Ctrl+A temp->Bind(wxEVT_CHAR, ([temp](wxKeyEvent& event) { @@ -777,7 +871,8 @@ void CheckBox::BUILD() { m_last_meaningful_value = static_cast(check_value); // BBS: use ::CheckBox - auto temp = new ::CheckBox(m_parent); + static Builder<::CheckBox> builder; + auto temp = builder.build(m_parent); if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT); //temp->SetBackgroundColour(*wxWHITE); temp->SetValue(check_value); @@ -896,8 +991,14 @@ void SpinCtrl::BUILD() { ? 0 : m_opt.min; const int max_val = m_opt.max < 2147483647 ? m_opt.max : 2147483647; - auto temp = new SpinInput(m_parent, text_value, _L(m_opt.sidetext), wxDefaultPosition, size, - wxSP_ARROW_KEYS, min_val, max_val, default_value); + static Builder builder; + auto temp = builder.build(m_parent, "", "", wxDefaultPosition, wxDefaultSize, + wxSP_ARROW_KEYS); + temp->SetSize(size); + temp->SetLabel(_L(m_opt.sidetext)); + temp->GetTextCtrl()->SetLabel(text_value); + temp->SetRange(min_val, max_val); + temp->SetValue(default_value); m_combine_side_text = true; #ifdef __WXGTK3__ wxSize best_sz = temp->GetBestSize(); @@ -920,7 +1021,7 @@ void SpinCtrl::BUILD() { } propagate_value(); - })); + }), temp->GetId()); temp->Bind(wxEVT_SPINCTRL, ([this](wxCommandEvent e) { propagate_value(); }), temp->GetId()); @@ -1072,14 +1173,15 @@ void Choice::BUILD() if (m_opt.nullable) m_last_meaningful_value = dynamic_cast(m_opt.default_value.get())->get_at(0); - choice_ctrl* temp; + choice_ctrl * temp; auto dynamic_list = dynamic_lists.find(m_opt.opt_key); if (dynamic_list != dynamic_lists.end()) m_list = dynamic_list->second; if (m_opt.gui_type != ConfigOptionDef::GUIType::undefined && m_opt.gui_type != ConfigOptionDef::GUIType::select_open && m_list == nullptr) { m_is_editable = true; - temp = new choice_ctrl(m_parent, wxID_ANY, wxString(""), wxDefaultPosition, size, 0, nullptr, wxTE_PROCESS_ENTER); + static Builder builder1; + temp = builder1.build(m_parent, wxID_ANY, wxString(""), wxDefaultPosition, wxDefaultSize, 0, nullptr, wxTE_PROCESS_ENTER); } else { #ifdef UNDEIFNED__WXOSX__ // __WXOSX__ // BBS @@ -1091,9 +1193,12 @@ void Choice::BUILD() temp->SetTextCtrlStyle(wxTE_READONLY); temp->Create(m_parent, wxID_ANY, wxString(""), wxDefaultPosition, size, 0, nullptr); #else - temp = new choice_ctrl(m_parent, wxID_ANY, wxString(""), wxDefaultPosition, size, 0, nullptr, wxCB_READONLY); + static Builder builder2; + temp = builder2.build(m_parent, wxID_ANY, wxString(""), wxDefaultPosition, wxDefaultSize, 0, nullptr, wxCB_READONLY); #endif //__WXOSX__ } + temp->SetSize(size); + temp->Clear(); temp->GetDropDown().SetUseContentWidth(true); if (parent_is_custom_ctrl && m_opt.height < 0) opt_height = (double) temp->GetTextCtrl()->GetSize().GetHeight() / m_em_unit; @@ -1146,9 +1251,9 @@ void Choice::BUILD() e.StopPropagation(); else e.Skip(); - }); - temp->Bind(wxEVT_COMBOBOX_DROPDOWN, [this](wxCommandEvent&) { m_is_dropped = true; }); - temp->Bind(wxEVT_COMBOBOX_CLOSEUP, [this](wxCommandEvent&) { m_is_dropped = false; }); + }, temp->GetId()); + temp->Bind(wxEVT_COMBOBOX_DROPDOWN, [this](wxCommandEvent&) { m_is_dropped = true; }, temp->GetId()); + temp->Bind(wxEVT_COMBOBOX_CLOSEUP, [this](wxCommandEvent&) { m_is_dropped = false; }, temp->GetId()); temp->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent&) { on_change_field(); }, temp->GetId()); @@ -1157,12 +1262,12 @@ void Choice::BUILD() e.Skip(); if (!bEnterPressed) propagate_value(); - } ); + }, temp->GetId() ); temp->Bind(wxEVT_TEXT_ENTER, [this](wxEvent& e) { EnterPressed enter(this); propagate_value(); - } ); + }, temp->GetId() ); } temp->SetToolTip(get_tooltip_text(temp->GetValue())); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index ce9377683..117f68fb0 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -3471,7 +3471,10 @@ void GUI_App::check_printer_presets() #endif } -void GUI_App::recreate_GUI(const wxString& msg_name) +void switch_window_pools(); +void release_window_pools(); + +void GUI_App::recreate_GUI(const wxString &msg_name) { BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "recreate_GUI enter"; m_is_recreating_gui = true; @@ -3479,12 +3482,18 @@ void GUI_App::recreate_GUI(const wxString& msg_name) update_http_extra_header(); mainframe->shutdown(); - ProgressDialog dlg(msg_name, msg_name, 100, nullptr, wxPD_AUTO_HIDE); dlg.Pulse(); dlg.Update(10, _L("Rebuild") + dots); MainFrame *old_main_frame = mainframe; + struct ClientData : wxClientData + { + ~ClientData() { release_window_pools(); } + }; + old_main_frame->SetClientObject(new ClientData); + + switch_window_pools(); mainframe = new MainFrame(); if (is_editor()) // hide settings tabs after first Layout diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 1aacd2553..53b003815 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -514,6 +514,9 @@ bool OptionsGroup::activate(std::function throw_if_canceled/* = [](){}*/ return true; } + +void free_window(wxWindow *win); + // delete all controls from the option group void OptionsGroup::clear(bool destroy_custom_ctrl) { @@ -542,8 +545,10 @@ void OptionsGroup::clear(bool destroy_custom_ctrl) if (custom_ctrl) { for (auto const &item : m_fields) { wxWindow* win = item.second.get()->getWindow(); - if (win) + if (win) { + free_window(win); win = nullptr; + } } //BBS: custom_ctrl already destroyed from sizer->clear(), no need to destroy here anymore if (destroy_custom_ctrl) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 9ce0a9725..8b8481537 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -4661,12 +4661,12 @@ void Tab::clear_pages() { // invalidated highlighter, if any exists m_highlighter.invalidate(); - //BBS: clear page in Parent - //m_page_sizer->Clear(true); - m_parent->clear_page(); // clear pages from the controlls for (auto p : m_pages) p->clear(); + //BBS: clear page in Parent + //m_page_sizer->Clear(true); + m_parent->clear_page(); // nulling pointers m_parent_preset_description_line = nullptr; diff --git a/src/slic3r/GUI/Widgets/ComboBox.cpp b/src/slic3r/GUI/Widgets/ComboBox.cpp index 5f32294aa..c930b26ec 100644 --- a/src/slic3r/GUI/Widgets/ComboBox.cpp +++ b/src/slic3r/GUI/Widgets/ComboBox.cpp @@ -165,6 +165,7 @@ int ComboBox::Append(const wxString &item, void ComboBox::DoClear() { + SetIcon("drop_down"); texts.clear(); tips.clear(); icons.clear(); diff --git a/src/slic3r/GUI/Widgets/TextInput.cpp b/src/slic3r/GUI/Widgets/TextInput.cpp index 2ac9be3f1..e8536735f 100644 --- a/src/slic3r/GUI/Widgets/TextInput.cpp +++ b/src/slic3r/GUI/Widgets/TextInput.cpp @@ -101,6 +101,14 @@ void TextInput::SetIcon(const wxBitmap &icon) Rescale(); } +void TextInput::SetIcon(const wxString &icon) +{ + if (this->icon.name() == icon.ToStdString()) + return; + this->icon = ScalableBitmap(this, icon.ToStdString(), 16); + Rescale(); +} + void TextInput::SetLabelColor(StateColor const &color) { label_color = color; diff --git a/src/slic3r/GUI/Widgets/TextInput.hpp b/src/slic3r/GUI/Widgets/TextInput.hpp index 152fb88f3..61f729506 100644 --- a/src/slic3r/GUI/Widgets/TextInput.hpp +++ b/src/slic3r/GUI/Widgets/TextInput.hpp @@ -42,6 +42,8 @@ public: void SetIcon(const wxBitmap & icon); + void SetIcon(const wxString & icon); + void SetLabelColor(StateColor const &color); void SetTextColor(StateColor const &color);