diff options
Diffstat (limited to 'src/slic3r/GUI/OptionsGroup.cpp')
-rw-r--r-- | src/slic3r/GUI/OptionsGroup.cpp | 640 |
1 files changed, 436 insertions, 204 deletions
diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 207d42b5b..10774abe3 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -1,40 +1,46 @@ #include "OptionsGroup.hpp" #include "ConfigExceptions.hpp" +#include "Plater.hpp" +#include "GUI_App.hpp" +#include "OG_CustomCtrl.hpp" #include <utility> #include <wx/numformatter.h> #include <boost/algorithm/string/split.hpp> #include <boost/algorithm/string/classification.hpp> +#include "libslic3r/Exception.hpp" #include "libslic3r/Utils.hpp" #include "I18N.hpp" namespace Slic3r { namespace GUI { -const t_field& OptionsGroup::build_field(const Option& opt, wxStaticText* label/* = nullptr*/) { - return build_field(opt.opt_id, opt.opt, label); +const t_field& OptionsGroup::build_field(const Option& opt) { + return build_field(opt.opt_id, opt.opt); } -const t_field& OptionsGroup::build_field(const t_config_option_key& id, wxStaticText* label/* = nullptr*/) { +const t_field& OptionsGroup::build_field(const t_config_option_key& id) { const ConfigOptionDef& opt = m_options.at(id).opt; - return build_field(id, opt, label); + return build_field(id, opt); } -const t_field& OptionsGroup::build_field(const t_config_option_key& id, const ConfigOptionDef& opt, wxStaticText* label/* = nullptr*/) { +const t_field& OptionsGroup::build_field(const t_config_option_key& id, const ConfigOptionDef& opt) { // Check the gui_type field first, fall through // is the normal type. - if (opt.gui_type.compare("select") == 0) { - } else if (opt.gui_type.compare("select_open") == 0) { + if (opt.gui_type == "select") { + } else if (opt.gui_type == "select_open") { m_fields.emplace(id, std::move(Choice::Create<Choice>(this->ctrl_parent(), opt, id))); - } else if (opt.gui_type.compare("color") == 0) { + } else if (opt.gui_type == "color") { m_fields.emplace(id, std::move(ColourPicker::Create<ColourPicker>(this->ctrl_parent(), opt, id))); - } else if (opt.gui_type.compare("f_enum_open") == 0 || - opt.gui_type.compare("i_enum_open") == 0 || - opt.gui_type.compare("i_enum_closed") == 0) { + } else if (opt.gui_type == "f_enum_open" || + opt.gui_type == "i_enum_open" || + opt.gui_type == "i_enum_closed") { m_fields.emplace(id, std::move(Choice::Create<Choice>(this->ctrl_parent(), opt, id))); - } else if (opt.gui_type.compare("slider") == 0) { + } else if (opt.gui_type == "slider") { m_fields.emplace(id, std::move(SliderCtrl::Create<SliderCtrl>(this->ctrl_parent(), opt, id))); - } else if (opt.gui_type.compare("i_spin") == 0) { // Spinctrl - } else if (opt.gui_type.compare("legend") == 0) { // StaticText + } else if (opt.gui_type == "i_spin") { // Spinctrl + } else if (opt.gui_type == "legend") { // StaticText m_fields.emplace(id, std::move(StaticText::Create<StaticText>(this->ctrl_parent(), opt, id))); + } else if (opt.gui_type == "one_string") { + m_fields.emplace(id, std::move(TextCtrl::Create<TextCtrl>(this->ctrl_parent(), opt, id))); } else { switch (opt.type) { case coFloatOrPercent: @@ -62,7 +68,7 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co break; case coNone: break; default: - throw /*//!ConfigGUITypeError("")*/std::logic_error("This control doesn't exist till now"); break; + throw Slic3r::LogicError("This control doesn't exist till now"); break; } } // Grab a reference to fields for convenience @@ -84,9 +90,7 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co this->on_set_focus(opt_id); }; field->m_parent = parent(); - - //! Label to change background color, when option is modified - field->m_Label = label; + field->m_back_to_initial_value = [this](std::string opt_id) { if (!m_disabled) this->back_to_initial_value(opt_id); @@ -100,29 +104,98 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co return field; } -void OptionsGroup::add_undo_buttuns_to_sizer(wxSizer* sizer, const t_field& field) +OptionsGroup::OptionsGroup( wxWindow* _parent, const wxString& title, + bool is_tab_opt /* = false */, + column_t extra_clmn /* = nullptr */) : + m_parent(_parent), title(title), + m_use_custom_ctrl(is_tab_opt), + staticbox(title!=""), extra_column(extra_clmn) { - if (!m_show_modified_btns) { - field->m_Undo_btn->set_as_hidden(); - field->m_Undo_to_sys_btn->set_as_hidden(); - return; +} + +wxWindow* OptionsGroup::ctrl_parent() const +{ + return this->custom_ctrl && m_use_custom_ctrl_as_parent ? static_cast<wxWindow*>(this->custom_ctrl) : (this->stb ? static_cast<wxWindow*>(this->stb) : this->parent()); +} + +bool OptionsGroup::is_legend_line() +{ + if (m_lines.size() == 1) { + const std::vector<Option>& option_set = m_lines.front().get_options(); + return !option_set.empty() && option_set.front().opt.gui_type == "legend"; } + return false; +} - sizer->Add(field->m_Undo_to_sys_btn, 0, wxALIGN_CENTER_VERTICAL); - sizer->Add(field->m_Undo_btn, 0, wxALIGN_CENTER_VERTICAL); +void OptionsGroup::show_field(const t_config_option_key& opt_key, bool show/* = true*/) +{ + Field* field = get_field(opt_key); + if (!field) return; + wxWindow* win = field->getWindow(); + if (!win) return; + wxSizerItem* win_item = m_grid_sizer->GetItem(win, true); + if (!win_item) return; + + const size_t cols = (size_t)m_grid_sizer->GetCols(); + const size_t rows = (size_t)m_grid_sizer->GetEffectiveRowsCount(); + + auto show_row = [this, show, cols, win_item](wxSizerItem* item, size_t row_shift) { + // check if item contanes required win + if (!item->IsWindow() || item != win_item) + return false; + // show/hide hole line contanes this window + for (size_t i = 0; i < cols; ++i) + m_grid_sizer->Show(row_shift + i, show); + return true; + }; + + size_t row_shift = 0; + for (size_t j = 0; j < rows; ++j) { + for (size_t i = 0; i < cols; ++i) { + wxSizerItem* item = m_grid_sizer->GetItem(row_shift + i); + if (!item) + continue; + if (item->IsSizer()) { + for (wxSizerItem* child_item : item->GetSizer()->GetChildren()) + if (show_row(child_item, row_shift)) + return; + } + else if (show_row(item, row_shift)) + return; + } + row_shift += cols; + } } -void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = nullptr*/) { - if ( line.full_width && ( - line.sizer != nullptr || - line.widget != nullptr || - !line.get_extra_widgets().empty() ) +void OptionsGroup::append_line(const Line& line) +{ + m_lines.emplace_back(line); + + if (line.full_width && ( + line.widget != nullptr || + !line.get_extra_widgets().empty()) + ) + return; + + auto option_set = line.get_options(); + for (auto opt : option_set) + m_options.emplace(opt.opt_id, opt); + + // add mode value for current line to m_options_mode + if (!option_set.empty()) + m_options_mode.push_back(option_set[0].opt.mode); +} + +void OptionsGroup::activate_line(Line& line) +{ + m_use_custom_ctrl_as_parent = false; + + if (line.full_width && ( + line.widget != nullptr || + !line.get_extra_widgets().empty()) ) { - if (line.sizer != nullptr) { - sizer->Add(line.sizer, 0, wxEXPAND | wxALL, wxOSX ? 0 : 15); - return; - } if (line.widget != nullptr) { + // description lines sizer->Add(line.widget(this->ctrl_parent()), 0, wxEXPAND | wxALL, wxOSX ? 0 : 15); return; } @@ -140,140 +213,128 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n } auto option_set = line.get_options(); - for (auto opt : option_set) - m_options.emplace(opt.opt_id, opt); + bool is_legend_line = option_set.front().opt.gui_type == "legend"; + + if (!custom_ctrl && m_use_custom_ctrl) { + custom_ctrl = new OG_CustomCtrl(is_legend_line || !staticbox ? this->parent() : static_cast<wxWindow*>(this->stb), this); + if (is_legend_line) + sizer->Add(custom_ctrl, 0, wxEXPAND | wxLEFT, wxOSX ? 0 : 10); + else + sizer->Add(custom_ctrl, 0, wxEXPAND | wxALL, wxOSX || !staticbox ? 0 : 5); + } // Set sidetext width for a better alignment of options in line // "m_show_modified_btns==true" means that options groups are in tabs - if (option_set.size() > 1 && m_show_modified_btns) { + if (option_set.size() > 1 && m_use_custom_ctrl) { sidetext_width = Field::def_width_thinner(); - /* Temporary commented till UI-review will be completed - if (m_show_modified_btns) // means that options groups are in tabs - sublabel_width = Field::def_width(); - */ } - // add mode value for current line to m_options_mode - if (!option_set.empty()) - m_options_mode.push_back(option_set[0].opt.mode); - // if we have a single option with no label, no sidetext just add it directly to sizer if (option_set.size() == 1 && label_width == 0 && option_set.front().opt.full_width && option_set.front().opt.label.empty() && option_set.front().opt.sidetext.size() == 0 && option_set.front().side_widget == nullptr && line.get_extra_widgets().size() == 0) { - wxSizer* tmp_sizer; -#if 0//#ifdef __WXGTK__ - tmp_sizer = new wxBoxSizer(wxVERTICAL); - m_panel->SetSizer(tmp_sizer); - m_panel->Layout(); -#else - tmp_sizer = sizer; -#endif /* __WXGTK__ */ const auto& option = option_set.front(); const auto& field = build_field(option); - auto btn_sizer = new wxBoxSizer(wxHORIZONTAL); - add_undo_buttuns_to_sizer(btn_sizer, field); - tmp_sizer->Add(btn_sizer, 0, wxEXPAND | wxALL, 0); if (is_window_field(field)) - tmp_sizer->Add(field->getWindow(), 0, wxEXPAND | wxALL, wxOSX ? 0 : 5); + sizer->Add(field->getWindow(), 0, wxEXPAND | wxALL, wxOSX ? 0 : 5); if (is_sizer_field(field)) - tmp_sizer->Add(field->getSizer(), 0, wxEXPAND | wxALL, wxOSX ? 0 : 5); + sizer->Add(field->getSizer(), 0, wxEXPAND | wxALL, wxOSX ? 0 : 5); return; } auto grid_sizer = m_grid_sizer; -#if 0//#ifdef __WXGTK__ - m_panel->SetSizer(m_grid_sizer); - m_panel->Layout(); -#endif /* __WXGTK__ */ + + if (custom_ctrl) + m_use_custom_ctrl_as_parent = true; // if we have an extra column, build it - if (extra_column) - { - m_extra_column_item_ptrs.push_back(extra_column(this->ctrl_parent(), line)); - grid_sizer->Add(m_extra_column_item_ptrs.back(), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 3); - } + if (extra_column) + { + m_extra_column_item_ptrs.push_back(extra_column(this->ctrl_parent(), line)); + grid_sizer->Add(m_extra_column_item_ptrs.back(), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 3); + } - // Build a label if we have it + // Build a label if we have it wxStaticText* label=nullptr; if (label_width != 0) { - if (! line.near_label_widget || ! line.label.IsEmpty()) { - // Only create the label if it is going to be displayed. - long label_style = staticbox ? 0 : wxALIGN_RIGHT; + if (custom_ctrl) { + if (line.near_label_widget) + line.near_label_widget_win = line.near_label_widget(this->ctrl_parent()); + } + else { + if (!line.near_label_widget || !line.label.IsEmpty()) { + // Only create the label if it is going to be displayed. + long label_style = staticbox ? 0 : wxALIGN_RIGHT; #ifdef __WXGTK__ - // workaround for correct text align of the StaticBox on Linux - // flags wxALIGN_RIGHT and wxALIGN_CENTRE don't work when Ellipsize flags are _not_ given. - // Text is properly aligned only when Ellipsize is checked. - label_style |= staticbox ? 0 : wxST_ELLIPSIZE_END; + // workaround for correct text align of the StaticBox on Linux + // flags wxALIGN_RIGHT and wxALIGN_CENTRE don't work when Ellipsize flags are _not_ given. + // Text is properly aligned only when Ellipsize is checked. + label_style |= staticbox ? 0 : wxST_ELLIPSIZE_END; #endif /* __WXGTK__ */ - label = new wxStaticText(this->ctrl_parent(), wxID_ANY, line.label + (line.label.IsEmpty() ? "" : ": "), - wxDefaultPosition, wxSize(label_width*wxGetApp().em_unit(), -1), label_style); - label->SetBackgroundStyle(wxBG_STYLE_PAINT); - label->SetFont(wxGetApp().normal_font()); - label->Wrap(label_width*wxGetApp().em_unit()); // avoid a Linux/GTK bug - } - if (!line.near_label_widget) - grid_sizer->Add(label, 0, (staticbox ? 0 : wxALIGN_RIGHT | wxRIGHT) | wxALIGN_CENTER_VERTICAL, line.label.IsEmpty() ? 0 : 5); - else { - m_near_label_widget_ptrs.push_back(line.near_label_widget(this->ctrl_parent())); - - if (line.label.IsEmpty()) - grid_sizer->Add(m_near_label_widget_ptrs.back(), 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 7); - else { + label = new wxStaticText(this->ctrl_parent(), wxID_ANY, line.label + (line.label.IsEmpty() ? "" : ": "), + wxDefaultPosition, wxSize(label_width * wxGetApp().em_unit(), -1), label_style); + label->SetBackgroundStyle(wxBG_STYLE_PAINT); + label->SetFont(wxGetApp().normal_font()); + label->Wrap(label_width * wxGetApp().em_unit()); // avoid a Linux/GTK bug + } + if (!line.near_label_widget) + grid_sizer->Add(label, 0, (staticbox ? 0 : wxALIGN_RIGHT | wxRIGHT) | wxALIGN_CENTER_VERTICAL, line.label.IsEmpty() ? 0 : 5); + else if (!line.label.IsEmpty()) { // If we're here, we have some widget near the label // so we need a horizontal sizer to arrange these things auto sizer = new wxBoxSizer(wxHORIZONTAL); grid_sizer->Add(sizer, 0, wxEXPAND | (staticbox ? wxALL : wxBOTTOM | wxTOP | wxLEFT), staticbox ? 0 : 1); - sizer->Add(m_near_label_widget_ptrs.back(), 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 7); sizer->Add(label, 0, (staticbox ? 0 : wxALIGN_RIGHT | wxRIGHT) | wxALIGN_CENTER_VERTICAL, 5); } + if (label != nullptr && line.label_tooltip != "") + label->SetToolTip(line.label_tooltip); } - if (label != nullptr && line.label_tooltip != "") - label->SetToolTip(line.label_tooltip); } - if (full_Label != nullptr) - *full_Label = label; // Initiate the pointer to the control of the full label, if we need this one. - // If there's a widget, build it and add the result to the sizer. + // If there's a widget, build it and add the result to the sizer. if (line.widget != nullptr) { auto wgt = line.widget(this->ctrl_parent()); - // If widget doesn't have label, don't use border - grid_sizer->Add(wgt, 0, wxEXPAND | wxBOTTOM | wxTOP, (wxOSX || line.label.IsEmpty()) ? 0 : 5); + if (custom_ctrl) + line.widget_sizer = wgt; + else + grid_sizer->Add(wgt, 0, wxEXPAND | wxBOTTOM | wxTOP, (wxOSX || line.label.IsEmpty()) ? 0 : 5); return; } - + // If we're here, we have more than one option or a single option with sidetext // so we need a horizontal sizer to arrange these things auto sizer = new wxBoxSizer(wxHORIZONTAL); - grid_sizer->Add(sizer, 0, wxEXPAND | (staticbox ? wxALL : wxBOTTOM | wxTOP | wxLEFT), staticbox ? 0 : 1); + if (!custom_ctrl) + grid_sizer->Add(sizer, 0, wxEXPAND | (staticbox ? wxALL : wxBOTTOM | wxTOP | wxLEFT), staticbox ? 0 : 1); // If we have a single option with no sidetext just add it directly to the grid sizer if (option_set.size() == 1 && option_set.front().opt.sidetext.size() == 0 && option_set.front().opt.label.empty() && option_set.front().side_widget == nullptr && line.get_extra_widgets().size() == 0) { const auto& option = option_set.front(); - const auto& field = build_field(option, label); - - add_undo_buttuns_to_sizer(sizer, field); - if (is_window_field(field)) - sizer->Add(field->getWindow(), option.opt.full_width ? 1 : 0, //(option.opt.full_width ? wxEXPAND : 0) | - wxBOTTOM | wxTOP | (option.opt.full_width ? wxEXPAND : wxALIGN_CENTER_VERTICAL), (wxOSX || !staticbox) ? 0 : 2); - if (is_sizer_field(field)) - sizer->Add(field->getSizer(), 1, /*(*/option.opt.full_width ? wxEXPAND : /*0) |*/ wxALIGN_CENTER_VERTICAL, 0); - return; + const auto& field = build_field(option); + + if (!custom_ctrl) { + if (is_window_field(field)) + sizer->Add(field->getWindow(), option.opt.full_width ? 1 : 0, + wxBOTTOM | wxTOP | (option.opt.full_width ? wxEXPAND : wxALIGN_CENTER_VERTICAL), (wxOSX || !staticbox) ? 0 : 2); + if (is_sizer_field(field)) + sizer->Add(field->getSizer(), 1, option.opt.full_width ? wxEXPAND : wxALIGN_CENTER_VERTICAL, 0); + } + return; } for (auto opt : option_set) { ConfigOptionDef option = opt.opt; wxSizer* sizer_tmp = sizer; // add label if any - if (!option.label.empty()) { + if (!option.label.empty() && !custom_ctrl) { //! To correct translation by context have to use wxGETTEXT_IN_CONTEXT macro from wxWidget 3.1.1 wxString str_label = (option.label == L_CONTEXT("Top", "Layers") || option.label == L_CONTEXT("Bottom", "Layers")) ? - _CTX(option.label, "Layers") : - _(option.label); + _CTX(option.label, "Layers") : + _(option.label); label = new wxStaticText(this->ctrl_parent(), wxID_ANY, str_label + ": ", wxDefaultPosition, //wxDefaultSize); wxSize(sublabel_width != -1 ? sublabel_width * wxGetApp().em_unit() : -1, -1), wxALIGN_RIGHT); label->SetBackgroundStyle(wxBG_STYLE_PAINT); @@ -283,42 +344,41 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n // add field const Option& opt_ref = opt; - auto& field = build_field(opt_ref, label); - add_undo_buttuns_to_sizer(sizer_tmp, field); - if (option_set.size() == 1 && option_set.front().opt.full_width) - { - const auto v_sizer = new wxBoxSizer(wxVERTICAL); - sizer_tmp->Add(v_sizer, 1, wxEXPAND); - is_sizer_field(field) ? - v_sizer->Add(field->getSizer(), 0, wxEXPAND) : - v_sizer->Add(field->getWindow(), 0, wxEXPAND); - break;//return; - } + auto& field = build_field(opt_ref); + if (!custom_ctrl) { + if (option_set.size() == 1 && option_set.front().opt.full_width) + { + const auto v_sizer = new wxBoxSizer(wxVERTICAL); + sizer_tmp->Add(v_sizer, 1, wxEXPAND); + is_sizer_field(field) ? + v_sizer->Add(field->getSizer(), 0, wxEXPAND) : + v_sizer->Add(field->getWindow(), 0, wxEXPAND); + break; + } - is_sizer_field(field) ? - sizer_tmp->Add(field->getSizer(), 0, wxALIGN_CENTER_VERTICAL, 0) : - sizer_tmp->Add(field->getWindow(), 0, wxALIGN_CENTER_VERTICAL, 0); - - // add sidetext if any - if (!option.sidetext.empty() || sidetext_width > 0) { - auto sidetext = new wxStaticText( this->ctrl_parent(), wxID_ANY, _(option.sidetext), wxDefaultPosition, - wxSize(sidetext_width != -1 ? sidetext_width*wxGetApp().em_unit() : -1, -1), wxALIGN_LEFT); - sidetext->SetBackgroundStyle(wxBG_STYLE_PAINT); - sidetext->SetFont(wxGetApp().normal_font()); - sizer_tmp->Add(sidetext, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 4); - field->set_side_text_ptr(sidetext); - } + is_sizer_field(field) ? + sizer_tmp->Add(field->getSizer(), 0, wxALIGN_CENTER_VERTICAL, 0) : + sizer_tmp->Add(field->getWindow(), 0, wxALIGN_CENTER_VERTICAL, 0); + + // add sidetext if any + if (!option.sidetext.empty() || sidetext_width > 0) { + auto sidetext = new wxStaticText(this->ctrl_parent(), wxID_ANY, _(option.sidetext), wxDefaultPosition, + wxSize(sidetext_width != -1 ? sidetext_width * wxGetApp().em_unit() : -1, -1), wxALIGN_LEFT); + sidetext->SetBackgroundStyle(wxBG_STYLE_PAINT); + sidetext->SetFont(wxGetApp().normal_font()); + sizer_tmp->Add(sidetext, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 4); + } - // add side widget if any - if (opt.side_widget != nullptr) { - sizer_tmp->Add(opt.side_widget(this->ctrl_parent())/*!.target<wxWindow>()*/, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 1); //! requires verification - } + // add side widget if any + if (opt.side_widget != nullptr) { + sizer_tmp->Add(opt.side_widget(this->ctrl_parent())/*!.target<wxWindow>()*/, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 1); //! requires verification + } - if (opt.opt_id != option_set.back().opt_id) //! istead of (opt != option_set.back()) - { - sizer_tmp->AddSpacer(6); - } + if (opt.opt_id != option_set.back().opt_id) //! istead of (opt != option_set.back()) + sizer_tmp->AddSpacer(6); + } } + // add extra sizers if any for (auto extra_widget : line.get_extra_widgets()) { @@ -331,15 +391,108 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n return; } - sizer->Add(extra_widget(this->ctrl_parent())/*!.target<wxWindow>()*/, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 4); //! requires verification + line.extra_widget_sizer = extra_widget(this->ctrl_parent()); + if (!custom_ctrl) + sizer->Add(line.extra_widget_sizer, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 4); //! requires verification + } +} + +// create all controls for the option group from the m_lines +bool OptionsGroup::activate(std::function<void()> throw_if_canceled) +{ + if (sizer)//(!sizer->IsEmpty()) + return false; + + 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<wxFlexGridSizer*>(m_grid_sizer)->SetFlexibleDirection(wxBOTH); + static_cast<wxFlexGridSizer*>(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; + } + + return true; +} +// delete all controls from the option group +void OptionsGroup::clear(bool destroy_custom_ctrl) +{ + if (!sizer) + return; + + m_grid_sizer = nullptr; + sizer = nullptr; + + for (Line& line : m_lines) { + if (line.near_label_widget_win) + line.near_label_widget_win = nullptr; + + if (line.widget_sizer) { + line.widget_sizer->Clear(true); + line.widget_sizer = nullptr; + } + + if (line.extra_widget_sizer) { + line.extra_widget_sizer->Clear(true); + line.extra_widget_sizer = nullptr; + } } + + if (custom_ctrl) { + for (auto const &item : m_fields) { + wxWindow* win = item.second.get()->getWindow(); + if (win) + win = nullptr; + } + if (destroy_custom_ctrl) + custom_ctrl->Destroy(); + else + custom_ctrl = nullptr; + } + + m_extra_column_item_ptrs.clear(); + m_fields.clear(); } -Line OptionsGroup::create_single_option_line(const Option& option) const { +Line OptionsGroup::create_single_option_line(const Option& option, const wxString& path/* = wxEmptyString*/) const { // Line retval{ _(option.opt.label), _(option.opt.tooltip) }; wxString tooltip = _(option.opt.tooltip); edit_tooltip(tooltip); Line retval{ _(option.opt.label), tooltip }; + retval.label_path = path; Option tmp(option); tmp.opt.label = std::string(""); retval.append_option(tmp); @@ -378,6 +531,9 @@ Option ConfigOptionsGroup::get_option(const std::string& opt_key, int opt_index std::pair<std::string, int> pair(opt_key, opt_index); m_opt_map.emplace(opt_id, pair); + if (m_use_custom_ctrl) // fill group and category values just for options from Settings Tab + wxGetApp().sidebar().get_searcher().add_key(opt_id, title, this->config_category()); + return Option(*m_config->def()->get(opt_key), opt_id); } @@ -392,13 +548,11 @@ void ConfigOptionsGroup::on_change_OG(const t_config_option_key& opt_id, const b return; } - auto itOption = it->second; - std::string opt_key = itOption.first; - int opt_index = itOption.second; + auto itOption = it->second; + const std::string &opt_key = itOption.first; + int opt_index = itOption.second; - auto option = m_options.at(opt_id).opt; - - change_opt_value(*m_config, opt_key, value, opt_index == -1 ? 0 : opt_index); + this->change_opt_value(opt_key, value, opt_index == -1 ? 0 : opt_index); } OptionsGroup::on_change_OG(opt_id, value); @@ -429,9 +583,10 @@ void ConfigOptionsGroup::back_to_config_value(const DynamicPrintConfig& config, } else if (m_opt_map.find(opt_key) == m_opt_map.end() || // This option don't have corresponded field - opt_key == "bed_shape" || opt_key == "compatible_printers" || opt_key == "compatible_prints" ) { + opt_key == "bed_shape" || opt_key == "filament_ramming_parameters" || + opt_key == "compatible_printers" || opt_key == "compatible_prints" ) { value = get_config_value(config, opt_key); - change_opt_value(*m_config, opt_key, value); + this->change_opt_value(opt_key, value); return; } else @@ -482,15 +637,38 @@ void ConfigOptionsGroup::Show(const bool show) #endif /* __WXGTK__ */ } -bool ConfigOptionsGroup::update_visibility(ConfigOptionMode mode) { +bool ConfigOptionsGroup::is_visible(ConfigOptionMode mode) +{ if (m_options_mode.empty()) return true; - int opt_mode_size = m_options_mode.size(); - if (m_grid_sizer->GetEffectiveRowsCount() != opt_mode_size && - opt_mode_size == 1) + if (m_options_mode.size() == 1) return m_options_mode[0] <= mode; - Show(true); + size_t hidden_row_cnt = 0; + for (auto opt_mode : m_options_mode) + if (opt_mode > mode) + hidden_row_cnt++; + + return hidden_row_cnt != m_options_mode.size(); +} + +bool ConfigOptionsGroup::update_visibility(ConfigOptionMode mode) +{ + if (m_options_mode.empty() || !m_grid_sizer) + return true; + + if (custom_ctrl) { + bool show = custom_ctrl->update_visibility(mode); + this->Show(show); + return show; + } + + int opt_mode_size = m_options_mode.size(); + if (m_grid_sizer->GetEffectiveRowsCount() != opt_mode_size && + opt_mode_size == 1) + return m_options_mode[0] <= mode; + + Show(true); int coef = 0; int hidden_row_cnt = 0; @@ -519,48 +697,53 @@ void ConfigOptionsGroup::msw_rescale() for (auto extra_col : m_extra_column_item_ptrs) rescale_extra_column_item(extra_col); - // update bitmaps for near label widgets (like "Set uniform scale" button on settings panel) - if (rescale_near_label_widget) - for (auto near_label_widget : m_near_label_widget_ptrs) - rescale_near_label_widget(near_label_widget); - // update undo buttons : rescale bitmaps for (const auto& field : m_fields) - field.second->msw_rescale(sidetext_width>0); - - const int em = em_unit(parent()); - - // rescale width of label column - if (!m_options_mode.empty() && label_width > 1) - { - const int cols = m_grid_sizer->GetCols(); - const int rows = m_grid_sizer->GetEffectiveRowsCount(); - const int label_col = extra_column == nullptr ? 0 : 1; - - for (int i = 0; i < rows; i++) - { - const wxSizerItem* label_item = m_grid_sizer->GetItem(i*cols+label_col); - if (label_item->IsWindow()) - { - auto label = dynamic_cast<wxStaticText*>(label_item->GetWindow()); - if (label != nullptr) { - label->SetMinSize(wxSize(label_width*em, -1)); + field.second->msw_rescale(); + + auto rescale = [](wxSizer* sizer) { + for (wxSizerItem* item : sizer->GetChildren()) + if (item->IsWindow()) { + wxWindow* win = item->GetWindow(); + // check if window is ScalableButton + ScalableButton* sc_btn = dynamic_cast<ScalableButton*>(win); + if (sc_btn) { + sc_btn->msw_rescale(); + sc_btn->SetSize(sc_btn->GetBestSize()); + return; } - } - else if (label_item->IsSizer()) // case when we have near_label_widget - { - const wxSizerItem* l_item = label_item->GetSizer()->GetItem(1); - if (l_item->IsWindow()) - { - auto label = dynamic_cast<wxStaticText*>(l_item->GetWindow()); - if (label != nullptr) { - label->SetMinSize(wxSize(label_width*em, -1)); - } + // check if window is wxButton + wxButton* btn = dynamic_cast<wxButton*>(win); + if (btn) { + btn->SetSize(btn->GetBestSize()); + return; } } - } - m_grid_sizer->Layout(); + }; + + // scale widgets and extra widgets if any exists + for (const Line& line : m_lines) { + if (line.widget_sizer) + rescale(line.widget_sizer); + if (line.extra_widget_sizer) + rescale(line.extra_widget_sizer); } + + if (custom_ctrl) + custom_ctrl->msw_rescale(); +} + +void ConfigOptionsGroup::sys_color_changed() +{ + // update undo buttons : rescale bitmaps + for (const auto& field : m_fields) + field.second->sys_color_changed(); +} + +void ConfigOptionsGroup::refresh() +{ + if (custom_ctrl) + custom_ctrl->Refresh(); } boost::any ConfigOptionsGroup::config_value(const std::string& opt_key, int opt_index, bool deserialize) { @@ -570,7 +753,7 @@ boost::any ConfigOptionsGroup::config_value(const std::string& opt_key, int opt_ // Aggregate the strings the old way. // Currently used for the post_process config value only. if (opt_index != -1) - throw std::out_of_range("Can't deserialize option indexed value"); + throw Slic3r::OutOfRange("Can't deserialize option indexed value"); // return join(';', m_config->get(opt_key)}); return get_config_value(*m_config, opt_key); } @@ -650,11 +833,15 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config ret = config.option<ConfigOptionStrings>(opt_key)->values; break; } + if (opt_key == "filament_ramming_parameters") { + ret = config.opt_string(opt_key, static_cast<unsigned int>(idx)); + break; + } if (config.option<ConfigOptionStrings>(opt_key)->values.empty()) ret = text_value; - else if (opt->gui_flags.compare("serialized") == 0) { + else if (opt->gui_flags == "serialized") { std::vector<std::string> values = config.option<ConfigOptionStrings>(opt_key)->values; - if (!values.empty() && values[0].compare("") != 0) + if (!values.empty() && !values[0].empty()) for (auto el : values) text_value += el + ";"; ret = text_value; @@ -680,29 +867,40 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config opt_key == "fill_pattern" ) { ret = static_cast<int>(config.option<ConfigOptionEnum<InfillPattern>>(opt_key)->value); } - else if (opt_key.compare("gcode_flavor") == 0 ) { + else if (opt_key == "ironing_type") { + ret = static_cast<int>(config.option<ConfigOptionEnum<IroningType>>(opt_key)->value); + } + else if (opt_key == "gcode_flavor") { ret = static_cast<int>(config.option<ConfigOptionEnum<GCodeFlavor>>(opt_key)->value); } - else if (opt_key.compare("support_material_pattern") == 0) { + else if (opt_key == "machine_limits_usage") { + ret = static_cast<int>(config.option<ConfigOptionEnum<MachineLimitsUsage>>(opt_key)->value); + } + else if (opt_key == "support_material_pattern") { ret = static_cast<int>(config.option<ConfigOptionEnum<SupportMaterialPattern>>(opt_key)->value); } - else if (opt_key.compare("seam_position") == 0) { + else if (opt_key == "seam_position") { ret = static_cast<int>(config.option<ConfigOptionEnum<SeamPosition>>(opt_key)->value); } - else if (opt_key.compare("host_type") == 0) { + else if (opt_key == "host_type") { ret = static_cast<int>(config.option<ConfigOptionEnum<PrintHostType>>(opt_key)->value); } - else if (opt_key.compare("display_orientation") == 0) { + else if (opt_key == "display_orientation") { ret = static_cast<int>(config.option<ConfigOptionEnum<SLADisplayOrientation>>(opt_key)->value); } - else if (opt_key.compare("support_pillar_connection_mode") == 0) { + else if (opt_key == "support_pillar_connection_mode") { ret = static_cast<int>(config.option<ConfigOptionEnum<SLAPillarConnectionMode>>(opt_key)->value); } + else if (opt_key == "printhost_authorization_type") { + ret = static_cast<int>(config.option<ConfigOptionEnum<AuthorizationType>>(opt_key)->value); + } } break; case coPoints: - if (opt_key.compare("bed_shape") == 0) + if (opt_key == "bed_shape") ret = config.option<ConfigOptionPoints>(opt_key)->values; + if (opt_key == "thumbnails") + ret = get_thumbnails_string(config.option<ConfigOptionPoints>(opt_key)->values); else ret = config.option<ConfigOptionPoints>(opt_key)->get_at(idx); break; @@ -728,6 +926,40 @@ Field* ConfigOptionsGroup::get_fieldc(const t_config_option_key& opt_key, int op return opt_id.empty() ? nullptr : get_field(opt_id); } +std::pair<OG_CustomCtrl*, bool*> ConfigOptionsGroup::get_custom_ctrl_with_blinking_ptr(const t_config_option_key& opt_key, int opt_index/* = -1*/) +{ + Field* field = get_fieldc(opt_key, opt_index); + + if (field) + return {custom_ctrl, field->get_blink_ptr()}; + + for (Line& line : m_lines) + for (const Option& opt : line.get_options()) + if (opt.opt_id == opt_key && line.widget) + return { custom_ctrl, line.get_blink_ptr() }; + + return { nullptr, nullptr }; +} + +// Change an option on m_config, possibly call ModelConfig::touch(). +void ConfigOptionsGroup::change_opt_value(const t_config_option_key& opt_key, const boost::any& value, int opt_index /*= 0*/) + +{ + Slic3r::GUI::change_opt_value(const_cast<DynamicPrintConfig&>(*m_config), opt_key, value, opt_index); + if (m_modelconfig) + m_modelconfig->touch(); +} + +ogStaticText::ogStaticText(wxWindow* parent, const wxString& text) : + wxStaticText(parent, wxID_ANY, text, wxDefaultPosition, wxDefaultSize) +{ + if (!text.IsEmpty()) { + Wrap(60 * wxGetApp().em_unit()); + GetParent()->Layout(); + } +} + + void ogStaticText::SetText(const wxString& value, bool wrap/* = true*/) { SetLabel(value); |