From d6568f9ce72db6aa94f0c1be5c0450007c173602 Mon Sep 17 00:00:00 2001 From: YuSanka <yusanka@gmail.com> Date: Tue, 16 Jan 2018 16:28:01 +0100 Subject: [PATCH] To Tab added functions to save/delete/upload presets... Changed m_options OptionsGroup from const t_optiondef_map& to std::map<t_config_option_key, Option>. --- xs/src/slic3r/GUI/Field.cpp | 8 +- xs/src/slic3r/GUI/Field.hpp | 2 +- xs/src/slic3r/GUI/GUI.cpp | 13 +- xs/src/slic3r/GUI/OptionsGroup.cpp | 23 ++- xs/src/slic3r/GUI/OptionsGroup.hpp | 12 +- xs/src/slic3r/GUI/Tab.cpp | 302 ++++++++++++++++++++++++++--- xs/src/slic3r/GUI/Tab.h | 28 ++- 7 files changed, 332 insertions(+), 56 deletions(-) diff --git a/xs/src/slic3r/GUI/Field.cpp b/xs/src/slic3r/GUI/Field.cpp index 0118b22e7..54cd080b4 100644 --- a/xs/src/slic3r/GUI/Field.cpp +++ b/xs/src/slic3r/GUI/Field.cpp @@ -348,7 +348,11 @@ void Choice::set_value(boost::any value) case coFloat: case coPercent: case coStrings:{ - wxString text_value = boost::any_cast<wxString>(value); + wxString text_value; + if (m_opt.type == coInt) + text_value = wxString::Format(_T("%i"), int(boost::any_cast<int>(value))); + else + text_value = boost::any_cast<wxString>(value); auto idx = 0; for (auto el : m_opt.enum_values) { @@ -454,7 +458,7 @@ void Point::BUILD() temp->Add(new wxStaticText(m_parent, wxID_ANY, "x:")/*, 0, wxALIGN_CENTER_VERTICAL, 0*/); temp->Add(x_textctrl); - temp->Add(new wxStaticText(m_parent, wxID_ANY, "y:")/*, 0, wxALIGN_CENTER_VERTICAL, 0*/); + temp->Add(new wxStaticText(m_parent, wxID_ANY, " y:")/*, 0, wxALIGN_CENTER_VERTICAL, 0*/); temp->Add(y_textctrl); x_textctrl->Bind(wxEVT_TEXT, ([=](wxCommandEvent e) { on_change_field(e/*$self->option->opt_id*/); }), x_textctrl->GetId()); diff --git a/xs/src/slic3r/GUI/Field.hpp b/xs/src/slic3r/GUI/Field.hpp index 71e31a015..645b6683b 100644 --- a/xs/src/slic3r/GUI/Field.hpp +++ b/xs/src/slic3r/GUI/Field.hpp @@ -213,7 +213,7 @@ public: dynamic_cast<wxColourPickerCtrl*>(window)->SetColour(value); } void set_value(boost::any value) { - dynamic_cast<wxColourPickerCtrl*>(window)->SetColour(boost::any_cast<std::string>(value)); + dynamic_cast<wxColourPickerCtrl*>(window)->SetColour(boost::any_cast</*std::s*/wxString>(value)); } boost::any get_value() override { diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp index 31558534f..2953f6492 100644 --- a/xs/src/slic3r/GUI/GUI.cpp +++ b/xs/src/slic3r/GUI/GUI.cpp @@ -279,6 +279,7 @@ void change_opt_value(DynamicPrintConfig& config, t_config_option_key opt_key, b void add_created_tab(Tab* panel, PresetBundle *preset_bundle, AppConfig *app_config) { panel->m_no_controller = app_config->get("no_controller").empty(); + panel->m_show_btn_incompatible_presets = app_config->get("show_incompatible_presets").empty(); panel->create_preset_tab(preset_bundle); // Callback to be executed after any of the configuration fields(Perl class Slic3r::GUI::OptionsGroup::Field) change their value. panel->m_on_value_change = [/*this*/](std::string opt_key, boost::any value){ @@ -291,9 +292,9 @@ void add_created_tab(Tab* panel, PresetBundle *preset_bundle, AppConfig *app_con // if (loaded && Slic3r::GUI::autosave) m_config->save(Slic3r::GUI::autosave) ; }; -// # Install a callback for the tab to update the platter and print controller presets, when -// # a preset changes at Slic3r::GUI::Tab. -// $tab->on_presets_changed(sub{ + // Install a callback for the tab to update the platter and print controller presets, when + // a preset changes at Slic3r::GUI::Tab. + panel->m_on_presets_changed = [](){ // if ($self->{plater}) { // # Update preset combo boxes(Print settings, Filament, Printer) from their respective tabs. // $self->{plater}->update_presets($tab_name, @_); @@ -312,10 +313,10 @@ void add_created_tab(Tab* panel, PresetBundle *preset_bundle, AppConfig *app_con // } // $self->{plater}->on_config_change($tab->{presets}->get_current_preset->config); // } -// }); + }; - //# Load the currently selected preset into the GUI, update the preset selection box. -// panel->load_current_preset; + // Load the currently selected preset into the GUI, update the preset selection box. + panel->load_current_preset(); g_wxTabPanel->AddPage(panel, panel->title()); } diff --git a/xs/src/slic3r/GUI/OptionsGroup.cpp b/xs/src/slic3r/GUI/OptionsGroup.cpp index 65be1f04b..bf1cd8eb4 100644 --- a/xs/src/slic3r/GUI/OptionsGroup.cpp +++ b/xs/src/slic3r/GUI/OptionsGroup.cpp @@ -11,7 +11,7 @@ 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) { - const ConfigOptionDef& opt = m_options.at(id); + const ConfigOptionDef& opt = m_options.at(id).opt; return build_field(id, opt); } @@ -86,6 +86,8 @@ void OptionsGroup::append_line(const Line& line) { } auto option_set = line.get_options(); + for (auto opt : option_set) + m_options.emplace(opt.opt_id, opt); // 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 && @@ -122,7 +124,6 @@ void OptionsGroup::append_line(const Line& line) { // if we have a single option with no sidetext just add it directly to the grid sizer -//! auto option_set = line.get_options(); if (option_set.size() == 1 && option_set.front().opt.sidetext.size() == 0 && option_set.front().side_widget == nullptr && line.get_extra_widgets().size() == 0) { const auto& option = option_set.front(); @@ -225,7 +226,7 @@ void ConfigOptionsGroup::on_change_OG(t_config_option_key opt_id, boost::any val std::string opt_key = itOption.first; int opt_index = itOption.second; - auto option = m_options.at(opt_id); + auto option = m_options.at(opt_id).opt; // get value //! auto field_value = get_value(opt_id); @@ -260,7 +261,7 @@ void ConfigOptionsGroup::reload_config(){ auto opt_id = it->first; std::string opt_key = m_opt_map.at(opt_id).first; int opt_index = m_opt_map.at(opt_id).second; - auto option = m_options.at(opt_id); + auto option = m_options.at(opt_id).opt; set_value(opt_id, config_value(opt_key, opt_index, option.gui_flags.compare("serialized") == 0 )); } } @@ -284,6 +285,8 @@ boost::any ConfigOptionsGroup::config_value(std::string opt_key, int opt_index, boost::any ConfigOptionsGroup::get_config_value(DynamicPrintConfig& config, std::string opt_key, int opt_index/* = -1*/) { + size_t idx = opt_index == -1 ? 0 : opt_index; + boost::any ret; wxString text_value = wxString(""); const ConfigOptionDef* opt = config.def()->get(opt_key); @@ -308,7 +311,9 @@ boost::any ConfigOptionsGroup::get_config_value(DynamicPrintConfig& config, std: break; case coPercents: case coFloats:{ - double val = config.opt_float(opt_key, 0/*opt_index*/); + double val = opt->type == coFloats ? + config.opt_float(opt_key, idx/*0opt_index*/) : + config.option<ConfigOptionPercents>(opt_key)->values.at(idx/*0*/); ret = val - int(val) == 0 ? wxString::Format(_T("%i"), int(val)) : wxNumberFormatter::ToString(val, 2); @@ -324,19 +329,19 @@ boost::any ConfigOptionsGroup::get_config_value(DynamicPrintConfig& config, std: if (config.option<ConfigOptionStrings>(opt_key)->values.empty()) ret = text_value; else - ret = static_cast<wxString>(config.opt_string(opt_key, static_cast<unsigned int>(0)/*opt_index*/)); + ret = static_cast<wxString>(config.opt_string(opt_key, static_cast<unsigned int>(idx/*0*/)/*opt_index*/)); break; case coBool: ret = config.opt_bool(opt_key); break; case coBools: - ret = config.opt_bool(opt_key, 0/*opt_index*/); + ret = config.opt_bool(opt_key, idx/*0opt_index*/); break; case coInt: ret = config.opt_int(opt_key); break; case coInts: - ret = config.opt_int(opt_key, 0/*opt_index*/); + ret = config.opt_int(opt_key, idx/*0/*opt_index*/); break; case coEnum:{ if (opt_key.compare("external_fill_pattern") == 0 || @@ -355,7 +360,7 @@ boost::any ConfigOptionsGroup::get_config_value(DynamicPrintConfig& config, std: break; case coPoints:{ const auto &value = *config.option<ConfigOptionPoints>(opt_key); - ret = value.values.at(0); + ret = value.values.at(idx/*0*/); } break; case coNone: diff --git a/xs/src/slic3r/GUI/OptionsGroup.hpp b/xs/src/slic3r/GUI/OptionsGroup.hpp index 2e006b391..398946177 100644 --- a/xs/src/slic3r/GUI/OptionsGroup.hpp +++ b/xs/src/slic3r/GUI/OptionsGroup.hpp @@ -91,17 +91,15 @@ public: void append_single_option_line(const Option& option) { append_line(create_single_option_line(option)); } // return a non-owning pointer reference - inline /*const*/ Field* get_field(t_config_option_key id) const { try { return m_fields.at(id).get(); } catch (std::out_of_range e) { return nullptr; } } -//! inline const Option& get_option(t_config_option_key id) const { try { return options.at(id).get(); } catch (std::out_of_range e) { return nullptr; } } - // } - inline void set_value(t_config_option_key id, boost::any value) { try { m_fields.at(id)->set_value(value); } catch (std::out_of_range e) {;} } + inline /*const*/ Field* get_field(t_config_option_key id) const { try { return m_fields.at(id).get(); } catch (std::out_of_range e) { return nullptr; } } + bool set_value(t_config_option_key id, boost::any value) { try { m_fields.at(id)->set_value(value); return true; } catch (std::out_of_range e) { return false; } } boost::any get_value(t_config_option_key id) { try { return m_fields.at(id)->get_value(); } catch (std::out_of_range e) { ; } } inline void enable() { for (auto& field : m_fields) field.second->enable(); } inline void disable() { for (auto& field : m_fields) field.second->disable(); } OptionsGroup(wxWindow* _parent, std::string title, const ConfigDef& configs) : - m_options(configs.options), m_parent(_parent), title(wxString(title)) { + m_optiondefs(configs.options), m_parent(_parent), title(wxString(title)) { sizer = (staticbox ? new wxStaticBoxSizer(new wxStaticBox(_parent, wxID_ANY, title), wxVERTICAL) : new wxBoxSizer(wxVERTICAL)); auto num_columns = 1U; if (label_width != 0) num_columns++; @@ -114,7 +112,8 @@ public: } protected: - const t_optiondef_map& m_options; + const t_optiondef_map& m_optiondefs; //#WHY + std::map<t_config_option_key, Option> m_options; wxWindow* m_parent {nullptr}; /// Field list, contains unique_ptrs of the derived type. @@ -168,7 +167,6 @@ public: }; // Static text shown among the options. -// Currently used for the filament cooling legend only. class ogStaticText :public wxStaticText{ public: ogStaticText() {} diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp index d5855c17b..0bb42f45f 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -31,20 +31,8 @@ void Tab::create_preset_tab(PresetBundle *preset_bundle) panel->SetSizer(sizer); // preset chooser - //! Add Preset from PrintPreset - // choice menu for Experiments - wxString choices[] = - { - _T("First"), - _T("Second"), - _T("Third") - }; - - m_presets_choice = new wxBitmapComboBox(panel, wxID_ANY, "", wxDefaultPosition, wxSize(270, -1)/*, nCntEl, choices, wxCB_READONLY*/); + m_presets_choice = new wxBitmapComboBox(panel, wxID_ANY, "", wxDefaultPosition, wxSize(270, -1), 0, 0,wxCB_READONLY); const wxBitmap* bmp = new wxBitmap(wxString::FromUTF8(Slic3r::var("flag-green-icon.png").c_str()), wxBITMAP_TYPE_PNG); - for (auto el:choices) - m_presets_choice->Append(wxString::FromUTF8(el).c_str(), *bmp); - m_presets_choice->SetSelection(m_presets_choice->GetCount() - 1); //buttons wxBitmap bmpMenu; @@ -53,8 +41,7 @@ void Tab::create_preset_tab(PresetBundle *preset_bundle) bmpMenu = wxBitmap(wxString::FromUTF8(Slic3r::var("delete.png").c_str()), wxBITMAP_TYPE_PNG); m_btn_delete_preset = new wxBitmapButton(panel, wxID_ANY, bmpMenu, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE); - // $self->{show_incompatible_presets} = 0; // !!! - + m_show_incompatible_presets = false; m_bmp_show_incompatible_presets = new wxBitmap(wxString::FromUTF8(Slic3r::var("flag-red-icon.png").c_str()), wxBITMAP_TYPE_PNG); m_bmp_hide_incompatible_presets = new wxBitmap(wxString::FromUTF8(Slic3r::var("flag-green-icon.png").c_str()), wxBITMAP_TYPE_PNG); m_btn_hide_incompatible_presets = new wxBitmapButton(panel, wxID_ANY, *m_bmp_hide_incompatible_presets, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE); @@ -96,7 +83,13 @@ void Tab::create_preset_tab(PresetBundle *preset_bundle) m_treectrl->Bind(wxEVT_KEY_DOWN, &Tab::OnKeyDown, this); m_treectrl->Bind(wxEVT_COMBOBOX, &Tab::OnComboBox, this); - m_btn_save_preset->Bind(wxEVT_BUTTON, &Tab::save_preset, this); + m_presets_choice->Bind(wxEVT_COMBOBOX, ([this](wxCommandEvent e){ + select_preset(m_presets_choice->GetStringSelection()); + })); + + m_btn_save_preset->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e){ + save_preset(m_presets_choice->GetStringSelection().ToStdString()); + })); m_btn_delete_preset->Bind(wxEVT_BUTTON, &Tab::delete_preset, this); m_btn_hide_incompatible_presets->Bind(wxEVT_BUTTON, &Tab::toggle_show_hide_incompatible, this); @@ -141,6 +134,11 @@ void Tab::update_dirty(){ // _on_presets_changed; } +void Tab::update_tab_ui() +{ + m_presets->update_tab_ui(m_presets_choice, m_show_incompatible_presets); +} + // Load a provied DynamicConfig into the tab, modifying the active preset. // This could be used for example by setting a Wipe Tower position by interactive manipulation in the 3D view. void Tab::load_config(DynamicPrintConfig config) @@ -223,6 +221,18 @@ Field* Tab::get_field(t_config_option_key opt_key, int opt_index/* = -1*/) const return field; } +// Set a key/value pair on this page. Return true if the value has been modified. +// Currently used for distributing extruders_count over preset pages of Slic3r::GUI::Tab::Printer +// after a preset is loaded. +bool Tab::set_value(t_config_option_key opt_key, boost::any value){ + bool changed = false; + for(auto page: m_pages) { + if (page->set_value(opt_key, value)) + changed = true; + } + return changed; +} + // To be called by custom widgets, load a value into a config, // update the preset selection boxes (the dirty flags) void Tab::load_key_value(std::string opt_key, boost::any value) @@ -237,6 +247,16 @@ void Tab::load_key_value(std::string opt_key, boost::any value) update(); } +// Call a callback to update the selection of presets on the platter: +// To update the content of the selection boxes, +// to update the filament colors of the selection boxes, +// to update the "dirty" flags of the selection boxes, +// to uddate number of "filament" selection boxes when the number of extruders change. +void Tab::on_presets_changed(/*std::vector<std::string> reload_dependent_tabs*/){ + if (m_on_presets_changed != nullptr) + m_on_presets_changed(/*m_presets, reload_dependent_tabs*/); +} + void Tab::reload_compatible_printers_widget() { bool has_any = !m_config->option<ConfigOptionStrings>("compatible_printers")->values.empty(); @@ -1161,6 +1181,17 @@ void TabPrinter::build_extruder_pages(){ rebuild_page_tree(); } +// this gets executed after preset is loaded and before GUI fields are updated +void TabPrinter::on_preset_loaded() +{ + // update the extruders count field + auto *nozzle_diameter = dynamic_cast<const ConfigOptionFloats*>(m_config->option("nozzle_diameter")); + int extruders_count = nozzle_diameter->values.size(); + set_value("extruders_count", extruders_count); + // update the GUI field according to the number of nozzle diameters supplied + extruders_count_changed(extruders_count); +} + void TabPrinter::update(){ Freeze(); @@ -1246,9 +1277,27 @@ void TabPrinter::update(){ Thaw(); } +// Initialize the UI from the current preset void Tab::load_current_preset() { - ; + auto preset = m_presets->get_edited_preset(); +// try{ +// local $SIG{ __WARN__ } = Slic3r::GUI::warning_catcher($self); + preset.is_default ? m_btn_delete_preset->Disable() : m_btn_delete_preset->Enable(true); + update(); + // For the printer profile, generate the extruder pages. + on_preset_loaded(); + // Reload preset pages with the new configuration values. + reload_config(); +// }; + // use CallAfter because some field triggers schedule on_change calls using CallAfter, + // and we don't want them to be called after this update_dirty() as they would mark the + // preset dirty again + // (not sure this is true anymore now that update_dirty is idempotent) + wxTheApp->CallAfter([this]{ + update_tab_ui(); + on_presets_changed(); + }); } //Regerenerate content of the page tree. @@ -1278,6 +1327,111 @@ void Tab::rebuild_page_tree() Thaw(); } +// Called by the UI combo box when the user switches profiles. +// Select a preset by a name.If !defined(name), then the default preset is selected. +// If the current profile is modified, user is asked to save the changes. +void Tab::select_preset(wxString preset_name) +{ + std::string name = preset_name.ToStdString(); + auto force = false; + auto presets = m_presets; + // If no name is provided, select the "-- default --" preset. + if (name.empty()) + name= presets->default_preset().name; + auto current_dirty = presets->current_is_dirty(); + auto canceled = false; + auto printer_tab = presets->name().compare("printer")==0; + m_reload_dependent_tabs = {}; + if (!force && current_dirty && !may_discard_current_dirty_preset()) { + canceled = true; + } else if(printer_tab) { + // Before switching the printer to a new one, verify, whether the currently active print and filament + // are compatible with the new printer. + // If they are not compatible and the current print or filament are dirty, let user decide + // whether to discard the changes or keep the current printer selection. + auto new_printer_preset = presets->find_preset(name, true); + auto print_presets = &m_preset_bundle->prints; + bool print_preset_dirty = print_presets->current_is_dirty(); + bool print_preset_compatible = print_presets->get_edited_preset().is_compatible_with_printer(*new_printer_preset); + canceled = !force && print_preset_dirty && !print_preset_compatible && + !may_discard_current_dirty_preset(print_presets, name); + auto filament_presets = &m_preset_bundle->filaments; + bool filament_preset_dirty = filament_presets->current_is_dirty(); + bool filament_preset_compatible = filament_presets->get_edited_preset().is_compatible_with_printer(*new_printer_preset); + if (!canceled && !force) { + canceled = filament_preset_dirty && !filament_preset_compatible && + !may_discard_current_dirty_preset(filament_presets, name); + } + if (!canceled) { + if (!print_preset_compatible) { + // The preset will be switched to a different, compatible preset, or the '-- default --'. + m_reload_dependent_tabs.push_back("Print"); + if (print_preset_dirty) print_presets->discard_current_changes(); + } + if (!filament_preset_compatible) { + // The preset will be switched to a different, compatible preset, or the '-- default --'. + m_reload_dependent_tabs.push_back("Filament"); + if (filament_preset_dirty) filament_presets->discard_current_changes(); + } + } + } + if (canceled) { + update_tab_ui(); + // Trigger the on_presets_changed event so that we also restore the previous value in the plater selector, + // if this action was initiated from the platter. + on_presets_changed(); + } + else { + if (current_dirty) presets->discard_current_changes() ; + presets->select_preset_by_name(name, force); + // Mark the print & filament enabled if they are compatible with the currently selected preset. + // The following method should not discard changes of current print or filament presets on change of a printer profile, + // if they are compatible with the current printer. + if (current_dirty || printer_tab) + m_preset_bundle->update_compatible_with_printer(true); + // Initialize the UI from the current preset. + load_current_preset(/*\@reload_dependent_tabs*/); + } + +} + +// If the current preset is dirty, the user is asked whether the changes may be discarded. +// if the current preset was not dirty, or the user agreed to discard the changes, 1 is returned. +bool Tab::may_discard_current_dirty_preset(PresetCollection* presets /*= nullptr*/, std::string new_printer_name /*= ""*/) +{ + if (presets == nullptr) presets = m_presets; + // Display a dialog showing the dirty options in a human readable form. + auto old_preset = presets->get_edited_preset(); + auto type_name = presets->name(); + auto tab = " "; + auto name = old_preset.is_default ? + ("Default " + type_name + " preset") : + (type_name + " preset\n" + tab + old_preset.name); + // Collect descriptions of the dirty options. + std::vector<std::string> option_names; + for(auto opt_key: presets->current_dirty_options()) { + auto opt = m_config->def()->options.at(opt_key); + std::string name = ""; + if (!opt.category.empty()) + name += opt.category + " > "; + name += !opt.full_label.empty() ? + opt.full_label : + opt.label; + option_names.push_back(name); + } + // Show a confirmation dialog with the list of dirty options. + std::string changes = ""; + for (auto changed_name : option_names) + changes += tab + changed_name + "\n"; + auto message = (!new_printer_name.empty()) ? + name + "\n\nis not compatible with printer\n" +tab + new_printer_name+ "\n\nand it has the following unsaved changes:" : + name + "\n\nhas the following unsaved changes:"; + auto confirm = new wxMessageDialog(parent(), + message + "\n" +changes +"\n\nDiscard changes and continue anyway?", + "Unsaved Changes", wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION); + return confirm->ShowModal() == wxID_YES; +} + void Tab::OnTreeSelChange(wxTreeEvent& event) { if (m_disable_tree_sel_changed_event) return; @@ -1303,13 +1457,108 @@ void Tab::OnKeyDown(wxKeyEvent& event) event.GetKeyCode() == WXK_TAB ? m_treectrl->Navigate(event.ShiftDown() ? wxNavigationKeyEvent::IsBackward : wxNavigationKeyEvent::IsForward) : event.Skip(); -}; +} -void Tab::save_preset(wxCommandEvent &event){}; -void Tab::delete_preset(wxCommandEvent &event){}; -void Tab::toggle_show_hide_incompatible(wxCommandEvent &event){}; +// Save the current preset into file. +// This removes the "dirty" flag of the preset, possibly creates a new preset under a new name, +// and activates the new preset. +// Wizard calls save_preset with a name "My Settings", otherwise no name is provided and this method +// opens a Slic3r::GUI::SavePresetWindow dialog. +void Tab::save_preset(std::string name /*= ""*/) +{ + // since buttons(and choices too) don't get focus on Mac, we set focus manually + // to the treectrl so that the EVT_* events are fired for the input field having + // focus currently.is there anything better than this ? +//! m_treectrl->OnSetFocus(); -// # Return a callback to create a Tab widget to mark the preferences as compatible / incompatible to the current printer. + if (name.empty()) { + auto preset = m_presets->get_selected_preset(); + auto default_name = preset.is_default ? "Untitled" : preset.name; +// $default_name = ~s / \.[iI][nN][iI]$//; +// my $dlg = Slic3r::GUI::SavePresetWindow->new($self, +// title = > lc($self->title), +// default = > $default_name, +// values = > [map $_->name, grep !$_->default && !$_->external, @{$self->{presets}}], +// ); +// return unless $dlg->ShowModal == wxID_OK; +// name = $dlg->get_name; + } + // Save the preset into Slic3r::data_dir / presets / section_name / preset_name.ini + try + { + m_presets->save_current_preset(name); + } + catch (const std::exception &e) + { + return; + } + + // Mark the print & filament enabled if they are compatible with the currently selected preset. + m_preset_bundle->update_compatible_with_printer(false); + // Add the new item into the UI component, remove dirty flags and activate the saved item. + update_tab_ui(); + // Update the selection boxes at the platter. + on_presets_changed(); +} + +// Called for a currently selected preset. +void Tab::delete_preset(wxCommandEvent &event) +{ + auto current_preset = m_presets->get_selected_preset(); + // Don't let the user delete the ' - default - ' configuration. + std::string action = current_preset.is_external ? "remove" : "delete"; + std::string msg = "Are you sure you want to " + action + " the selected preset?"; + action = current_preset.is_external ? "Remove" : "Delete"; + std::string title = action + " Preset"; + if (current_preset.is_default || + wxID_YES != /*new*/ (wxMessageDialog(parent(), msg, title, wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION)).ShowModal()) + return; + // Delete the file and select some other reasonable preset. + // The 'external' presets will only be removed from the preset list, their files will not be deleted. + try{ m_presets->delete_current_preset(); } + catch (const std::exception &e) + { + return; + } + // Load the newly selected preset into the UI, update selection combo boxes with their dirty flags. + load_current_preset(); +} + +void Tab::toggle_show_hide_incompatible(wxCommandEvent &event) +{ + m_show_incompatible_presets = !m_show_incompatible_presets; + update_show_hide_incompatible_button(); + update_tab_ui(); +} + +void Tab::update_show_hide_incompatible_button() +{ + m_btn_hide_incompatible_presets->SetBitmap(m_show_incompatible_presets ? + *m_bmp_show_incompatible_presets : *m_bmp_hide_incompatible_presets); + m_btn_hide_incompatible_presets->SetToolTip(m_show_incompatible_presets ? + "Both compatible an incompatible presets are shown. Click to hide presets not compatible with the current printer." : + "Only compatible presets are shown. Click to show both the presets compatible and not compatible with the current printer."); +} + +void Tab::update_ui_from_settings() +{ + // Show the 'show / hide presets' button only for the print and filament tabs, and only if enabled + // in application preferences. + bool show = m_show_btn_incompatible_presets && m_presets->name().compare("printer") != 0; + show ? m_btn_hide_incompatible_presets->Show() : m_btn_hide_incompatible_presets->Hide(); + // If the 'show / hide presets' button is hidden, hide the incompatible presets. + if (show) { + update_show_hide_incompatible_button(); + } + else { + if (m_show_incompatible_presets) { + m_show_incompatible_presets = false; + update_tab_ui(); + } + } +} + +// Return a callback to create a Tab widget to mark the preferences as compatible / incompatible to the current printer. wxSizer* Tab::compatible_printers_widget(wxWindow* parent, wxCheckBox** checkbox, wxButton** btn) { *checkbox = new wxCheckBox(parent, wxID_ANY, "All"); @@ -1392,6 +1641,15 @@ Field* Page::get_field(t_config_option_key opt_key, int opt_index/* = -1*/) cons return field; } +bool Page::set_value(t_config_option_key opt_key, boost::any value){ + bool changed = false; + for(auto optgroup: m_optgroups) { + if (optgroup->set_value(opt_key, value)) + changed = 1 ; + } + return changed; +} + // package Slic3r::GUI::Tab::Page; ConfigOptionsGroupShp Page::new_optgroup(std::string title, int noncommon_label_width /*= -1*/) { diff --git a/xs/src/slic3r/GUI/Tab.h b/xs/src/slic3r/GUI/Tab.h index d657fdd09..4736c8325 100644 --- a/xs/src/slic3r/GUI/Tab.h +++ b/xs/src/slic3r/GUI/Tab.h @@ -65,7 +65,7 @@ public: void set_config(DynamicPrintConfig* config_in) { m_config = config_in; } void reload_config(); Field* get_field(t_config_option_key opt_key, int opt_index = -1) const; - + bool set_value(t_config_option_key opt_key, boost::any value); ConfigOptionsGroupShp new_optgroup(std::string title, int noncommon_label_width = -1); }; @@ -94,13 +94,18 @@ protected: std::map<std::string, size_t> m_icon_index; // Map from an icon file name to its index in $self->{icons}. std::vector<PageShp> m_pages; // $self->{pages} = []; bool m_disable_tree_sel_changed_event; + bool m_show_incompatible_presets; + + std::vector<std::string> m_reload_dependent_tabs = {}; public: PresetBundle* m_preset_bundle; bool m_no_controller; + bool m_show_btn_incompatible_presets; PresetCollection* m_presets; DynamicPrintConfig* m_config; t_change m_on_value_change{ nullptr }; + std::function<void(/*PresetCollection*, std::vector<std::string>*/)> m_on_presets_changed{ nullptr }; public: Tab() {} @@ -118,32 +123,37 @@ public: m_on_value_change(opt_key, value); update(); }; - void on_presets_changed(){}; void load_current_preset(); void rebuild_page_tree(); - void select_preset(wxString preset_name){}; - + void select_preset(wxString preset_name = ""); + bool may_discard_current_dirty_preset(PresetCollection* presets = nullptr, std::string new_printer_name = ""); wxSizer* compatible_printers_widget(wxWindow* parent, wxCheckBox** checkbox, wxButton** btn); void load_key_value(std::string opt_key, boost::any value); + void on_presets_changed(); void reload_compatible_printers_widget(); void OnTreeSelChange(wxTreeEvent& event); void OnKeyDown(wxKeyEvent& event); void OnComboBox(wxCommandEvent& event) { select_preset(m_presets_choice->GetStringSelection()); } - void save_preset(wxCommandEvent &event); + void save_preset(std::string name = ""); void delete_preset(wxCommandEvent &event); void toggle_show_hide_incompatible(wxCommandEvent &event); - + void update_show_hide_incompatible_button(); + void update_ui_from_settings(); + PageShp add_options_page(wxString title, std::string icon, bool is_extruder_pages = false); - virtual void OnActivate(){}; + virtual void OnActivate(){} + virtual void on_preset_loaded(){} virtual void build() = 0; virtual void update() = 0; void update_dirty(); + void update_tab_ui(); void load_config(DynamicPrintConfig config); virtual void reload_config(); Field* get_field(t_config_option_key opt_key, int opt_index = -1) const; + bool set_value(t_config_option_key opt_key, boost::any value); wxSizer* description_line_widget(wxWindow* parent, ogStaticText** StaticText); }; @@ -161,7 +171,7 @@ public: void build() override; void reload_config() override; void update() override; - void OnActivate(); + void OnActivate() override; }; //Slic3r::GUI::Tab::Filament; @@ -177,7 +187,6 @@ public: void build() override; void reload_config() override; void update() override; - void OnActivate() override; }; @@ -201,6 +210,7 @@ public: void update_serial_ports(); void extruders_count_changed(size_t extruders_count); void build_extruder_pages(); + void on_preset_loaded() override; }; } // GUI