diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm index 6baefa545..7bd019070 100644 --- a/lib/Slic3r/GUI/MainFrame.pm +++ b/lib/Slic3r/GUI/MainFrame.pm @@ -154,6 +154,10 @@ sub _init_tabpanel { my $value = $event->GetInt(); $self->{plater}->on_extruders_change($value); } + if ($opt_key eq 'printer_technology'){ + my $value = $event->GetInt();# 0 ~ "ptFFF"; 1 ~ "ptSLA" + $self->{plater}->show_preset_comboboxes($value); + } } # don't save while loading for the first time $self->config->save($Slic3r::GUI::autosave) if $Slic3r::GUI::autosave && $self->{loaded}; @@ -166,7 +170,7 @@ sub _init_tabpanel { my $tab = Slic3r::GUI::get_preset_tab($tab_name); if ($self->{plater}) { - # Update preset combo boxes (Print settings, Filament, Printer) from their respective tabs. + # Update preset combo boxes (Print settings, Filament, Material, Printer) from their respective tabs. my $presets = $tab->get_presets; if (defined $presets){ my $reload_dependent_tabs = $tab->get_dependent_tabs; @@ -174,7 +178,7 @@ sub _init_tabpanel { $self->{plater}->{"selected_item_$tab_name"} = $tab->get_selected_preset_item; if ($tab_name eq 'printer') { # Printer selected at the Printer tab, update "compatible" marks at the print and filament selectors. - for my $tab_name_other (qw(print filament)) { + for my $tab_name_other (qw(print filament sla_material)) { # If the printer tells us that the print or filament preset has been switched or invalidated, # refresh the print or filament tab page. Otherwise just refresh the combo box. my $update_action = ($reload_dependent_tabs && (first { $_ eq $tab_name_other } (@{$reload_dependent_tabs}))) @@ -190,7 +194,7 @@ sub _init_tabpanel { }); Slic3r::GUI::create_preset_tabs($self->{no_controller}, $VALUE_CHANGE_EVENT, $PRESETS_CHANGED_EVENT); $self->{options_tabs} = {}; - for my $tab_name (qw(print filament printer)) { + for my $tab_name (qw(print filament sla_material printer)) { $self->{options_tabs}{$tab_name} = Slic3r::GUI::get_preset_tab("$tab_name"); } @@ -202,8 +206,14 @@ sub _init_tabpanel { # load initial config my $full_config = wxTheApp->{preset_bundle}->full_config; $self->{plater}->on_config_change($full_config); + # Show a correct number of filament fields. - $self->{plater}->on_extruders_change(int(@{$full_config->nozzle_diameter})); + if (defined $full_config->nozzle_diameter){ # nozzle_diameter is undefined when SLA printer is selected + $self->{plater}->on_extruders_change(int(@{$full_config->nozzle_diameter})); + } + + # Show correct preset comboboxes according to the printer_technology + $self->{plater}->show_preset_comboboxes(($full_config->printer_technology eq "FFF") ? 0 : 1); } } diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 8c3b10b90..f4a2f99ff 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -520,20 +520,21 @@ sub new { { my $presets; { - $presets = $self->{presets_sizer} = Wx::FlexGridSizer->new(3, 2, 1, 2); + $presets = $self->{presets_sizer} = Wx::FlexGridSizer->new(4, 2, 1, 2); $presets->AddGrowableCol(1, 1); $presets->SetFlexibleDirection(wxHORIZONTAL); my %group_labels = ( print => L('Print settings'), filament => L('Filament'), + sla_material=> L('SLA material'), printer => L('Printer'), ); - # UI Combo boxes for a print, multiple filaments, and a printer. + # UI Combo boxes for a print, multiple filaments, SLA material and a printer. # Initially a single filament combo box is created, but the number of combo boxes for the filament selection may increase, # once a printer preset with multiple extruders is activated. # $self->{preset_choosers}{$group}[$idx] $self->{preset_choosers} = {}; - for my $group (qw(print filament printer)) { + for my $group (qw(print filament sla_material printer)) { my $text = Wx::StaticText->new($self->{right_panel}, -1, "$group_labels{$group}:", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); $text->SetFont($Slic3r::GUI::small_font); my $choice = Wx::BitmapComboBox->new($self->{right_panel}, -1, "", wxDefaultPosition, wxDefaultSize, [], wxCB_READONLY); @@ -554,7 +555,7 @@ sub new { $presets->Layout; } - my $frequently_changed_parameters_sizer = Wx::BoxSizer->new(wxHORIZONTAL); + my $frequently_changed_parameters_sizer = $self->{frequently_changed_parameters_sizer} = Wx::BoxSizer->new(wxHORIZONTAL); Slic3r::GUI::add_frequently_changed_parameters($self->{right_panel}, $frequently_changed_parameters_sizer, $presets); my $object_info_sizer; @@ -726,16 +727,17 @@ sub update_ui_from_settings } } -# Update preset combo boxes (Print settings, Filament, Printer) from their respective tabs. +# Update preset combo boxes (Print settings, Filament, Material, Printer) from their respective tabs. # Called by # Slic3r::GUI::Tab::Print::_on_presets_changed # Slic3r::GUI::Tab::Filament::_on_presets_changed +# Slic3r::GUI::Tab::Material::_on_presets_changed # Slic3r::GUI::Tab::Printer::_on_presets_changed # when the presets are loaded or the user selects another preset. # For Print settings and Printer, synchronize the selection index with their tabs. # For Filament, synchronize the selection index for a single extruder printer only, otherwise keep the selection. sub update_presets { - # $group: one of qw(print filament printer) + # $group: one of qw(print filament sla_material printer) # $presets: PresetCollection my ($self, $group, $presets) = @_; my @choosers = @{$self->{preset_choosers}{$group}}; @@ -751,6 +753,8 @@ sub update_presets { } } elsif ($group eq 'print') { wxTheApp->{preset_bundle}->print->update_platter_ui($choosers[0]); + } elsif ($group eq 'sla_material') { + wxTheApp->{preset_bundle}->sla_material->update_platter_ui($choosers[0]); } elsif ($group eq 'printer') { # Update the print choosers to only contain the compatible presets, update the dirty flags. wxTheApp->{preset_bundle}->print->update_platter_ui($self->{preset_choosers}{print}->[0]); @@ -1931,6 +1935,24 @@ sub update { $self->{preview3D}->reload_print if $self->{preview3D}; } +# When a printer technology is changed, the UI needs to be updated to show/hide needed preset combo boxes. +sub show_preset_comboboxes{ + my ($self, $showSLA) = @_; #if showSLA is oposite value to "ptFFF" + + my $choices = $self->{preset_choosers}{filament}; + my $print_filament_ctrls_cnt = 2 + 2 * ($#$choices+1); + + foreach (0..$print_filament_ctrls_cnt-1){ + $self->{presets_sizer}->Show($_, !$showSLA); + } + $self->{presets_sizer}->Show($print_filament_ctrls_cnt , $showSLA); + $self->{presets_sizer}->Show($print_filament_ctrls_cnt+1, $showSLA); + + $self->{frequently_changed_parameters_sizer}->Show(0,!$showSLA); + + $self->Layout; +} + # When a number of extruders changes, the UI needs to be updated to show a single filament selection combo box per extruder. # Also the wxTheApp->{preset_bundle}->filament_presets needs to be resized accordingly # and some reasonable default has to be selected for the additional extruders. diff --git a/xs/src/libslic3r/Config.hpp b/xs/src/libslic3r/Config.hpp index 7f75f815d..bd98e060a 100644 --- a/xs/src/libslic3r/Config.hpp +++ b/xs/src/libslic3r/Config.hpp @@ -49,9 +49,9 @@ enum ConfigOptionType { coPercents = coPercent + coVectorType, // a fraction or an absolute value coFloatOrPercent = 5, - // single 2d point. Currently not used. + // single 2d point (Point2f). Currently not used. coPoint = 6, - // vector of 2d points. Currently used for the definition of the print bed and for the extruder offsets. + // vector of 2d points (Point2f). Currently used for the definition of the print bed and for the extruder offsets. coPoints = coPoint + coVectorType, // single boolean value coBool = 7, @@ -821,12 +821,7 @@ public: bool deserialize(const std::string &str, bool append = false) override { UNUSED(append); - const t_config_enum_values &enum_keys_map = ConfigOptionEnum::get_enum_values(); - auto it = enum_keys_map.find(str); - if (it == enum_keys_map.end()) - return false; - this->value = static_cast(it->second); - return true; + return from_string(str, this->value); } static bool has(T value) @@ -838,7 +833,7 @@ public: } // Map from an enum name to an enum integer value. - static t_config_enum_names& get_enum_names() + static const t_config_enum_names& get_enum_names() { static t_config_enum_names names; if (names.empty()) { @@ -855,7 +850,17 @@ public: return names; } // Map from an enum name to an enum integer value. - static t_config_enum_values& get_enum_values(); + static const t_config_enum_values& get_enum_values(); + + static bool from_string(const std::string &str, T &value) + { + const t_config_enum_values &enum_keys_map = ConfigOptionEnum::get_enum_values(); + auto it = enum_keys_map.find(str); + if (it == enum_keys_map.end()) + return false; + value = static_cast(it->second); + return true; + } }; // Generic enum configuration value. @@ -900,7 +905,7 @@ public: // What type? bool, int, string etc. ConfigOptionType type = coNone; // Default value of this option. The default value object is owned by ConfigDef, it is released in its destructor. - ConfigOption *default_value = nullptr; + const ConfigOption *default_value = nullptr; // Usually empty. // Special values - "i_enum_open", "f_enum_open" to provide combo box for int or float selection, @@ -958,7 +963,7 @@ public: std::vector enum_labels; // For enums (when type == coEnum). Maps enum_values to enums. // Initialized by ConfigOptionEnum::get_enum_values() - t_config_enum_values *enum_keys_map = nullptr; + const t_config_enum_values *enum_keys_map = nullptr; bool has_enum_value(const std::string &value) const { for (const std::string &v : enum_values) diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 400530151..a00e99ce5 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -17,9 +17,51 @@ namespace Slic3r { #define L(s) Slic3r::I18N::translate(s) PrintConfigDef::PrintConfigDef() +{ + this->init_common_params(); + this->init_fff_params(); + this->init_sla_params(); +} + +void PrintConfigDef::init_common_params() { t_optiondef_map &Options = this->options; + ConfigOptionDef* def; + + def = this->add("printer_technology", coEnum); + def->label = L("Printer technology"); + def->tooltip = L("Printer technology"); + def->cli = "printer-technology=s"; + def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); + def->enum_values.push_back("FFF"); + def->enum_values.push_back("SLA"); + def->default_value = new ConfigOptionEnum(ptFFF); + + def = this->add("bed_shape", coPoints); + def->label = L("Bed shape"); + def->default_value = new ConfigOptionPoints { Pointf(0,0), Pointf(200,0), Pointf(200,200), Pointf(0,200) }; + def = this->add("layer_height", coFloat); + def->label = L("Layer height"); + def->category = L("Layers and Perimeters"); + def->tooltip = L("This setting controls the height (and thus the total number) of the slices/layers. " + "Thinner layers give better accuracy but take more time to print."); + def->sidetext = L("mm"); + def->cli = "layer-height=f"; + def->min = 0; + def->default_value = new ConfigOptionFloat(0.3); + + def = this->add("max_print_height", coFloat); + def->label = L("Max print height"); + def->tooltip = L("Set this to the maximum height that can be reached by your extruder while printing."); + def->sidetext = L("mm"); + def->cli = "max-print-height=f"; + def->default_value = new ConfigOptionFloat(200.0); +} + +void PrintConfigDef::init_fff_params() +{ + t_optiondef_map &Options = this->options; ConfigOptionDef* def; // Maximum extruder temperature, bumped to 1500 to support printing of glass. @@ -33,10 +75,6 @@ PrintConfigDef::PrintConfigDef() def->cli = "avoid-crossing-perimeters!"; def->default_value = new ConfigOptionBool(false); - def = this->add("bed_shape", coPoints); - def->label = L("Bed shape"); - def->default_value = new ConfigOptionPoints { Vec2d(0,0), Vec2d(200,0), Vec2d(200,200), Vec2d(0,200) }; - def = this->add("bed_temperature", coInts); def->label = L("Other layers"); def->tooltip = L("Bed temperature for layers after the first one. " @@ -906,16 +944,6 @@ PrintConfigDef::PrintConfigDef() def->height = 50; def->default_value = new ConfigOptionString(""); - def = this->add("layer_height", coFloat); - def->label = L("Layer height"); - def->category = L("Layers and Perimeters"); - def->tooltip = L("This setting controls the height (and thus the total number) of the slices/layers. " - "Thinner layers give better accuracy but take more time to print."); - def->sidetext = L("mm"); - def->cli = "layer-height=f"; - def->min = 0; - def->default_value = new ConfigOptionFloat(0.3); - def = this->add("remaining_times", coBool); def->label = L("Supports remaining times"); def->tooltip = L("Emit M73 P[percent printed] R[remaining time in minutes] at 1 minute" @@ -1036,13 +1064,6 @@ PrintConfigDef::PrintConfigDef() def->min = 0; def->default_value = new ConfigOptionFloats { 0. }; - def = this->add("max_print_height", coFloat); - def->label = L("Max print height"); - def->tooltip = L("Set this to the maximum height that can be reached by your extruder while printing."); - def->sidetext = L("mm"); - def->cli = "max-print-height=f"; - def->default_value = new ConfigOptionFloat(200.0); - def = this->add("max_print_speed", coFloat); def->label = L("Max print speed"); def->tooltip = L("When setting other speed settings to 0 Slic3r will autocalculate the optimal speed " @@ -2087,6 +2108,103 @@ PrintConfigDef::PrintConfigDef() def->default_value = new ConfigOptionFloat(0); } +void PrintConfigDef::init_sla_params() +{ + t_optiondef_map &Options = this->options; + ConfigOptionDef* def; + + // SLA Printer settings + def = this->add("display_width", coFloat); + def->label = L("Display width"); + def->tooltip = L("Width of the display"); + def->cli = "display-width=f"; + def->min = 1; + def->default_value = new ConfigOptionFloat(150.); + + def = this->add("display_height", coFloat); + def->label = L("Display height"); + def->tooltip = L("Height of the display"); + def->cli = "display-height=f"; + def->min = 1; + def->default_value = new ConfigOptionFloat(100.); + + def = this->add("display_pixels_x", coInt); + def->full_label = L("Number of pixels in"); + def->label = ("X"); + def->tooltip = L("Number of pixels in X"); + def->cli = "display-pixels-x=i"; + def->min = 100; + def->default_value = new ConfigOptionInt(2000); + + def = this->add("display_pixels_y", coInt); + def->label = ("Y"); + def->tooltip = L("Number of pixels in Y"); + def->cli = "display-pixels-y=i"; + def->min = 100; + def->default_value = new ConfigOptionInt(1000); + + def = this->add("printer_correction", coFloats); + def->full_label = L("Printer scaling correction"); + def->tooltip = L("Printer scaling correction"); + def->min = 0; + def->default_value = new ConfigOptionFloats( { 1., 1., 1. } ); + + // SLA Material settings. + def = this->add("initial_layer_height", coFloat); + def->label = L("Initial layer height"); + def->tooltip = L("Initial layer height"); + def->sidetext = L("mm"); + def->cli = "initial-layer-height=f"; + def->min = 0; + def->default_value = new ConfigOptionFloat(0.3); + + def = this->add("exposure_time", coFloat); + def->label = L("Exposure time"); + def->tooltip = L("Exposure time"); + def->sidetext = L("s"); + def->cli = "exposure-time=f"; + def->min = 0; + def->default_value = new ConfigOptionFloat(10); + + def = this->add("initial_exposure_time", coFloat); + def->label = L("Initial exposure time"); + def->tooltip = L("Initial exposure time"); + def->sidetext = L("s"); + def->cli = "initial-exposure-time=f"; + def->min = 0; + def->default_value = new ConfigOptionFloat(15); + + def = this->add("material_correction_printing", coFloats); + def->full_label = L("Correction for expansion when printing"); + def->tooltip = L("Correction for expansion when printing"); + def->min = 0; + def->default_value = new ConfigOptionFloats( { 1. , 1., 1. } ); + + def = this->add("material_correction_curing", coFloats); + def->full_label = L("Correction for expansion after curing"); + def->tooltip = L("Correction for expansion after curing"); + def->min = 0; + def->default_value = new ConfigOptionFloats( { 1. , 1., 1. } ); + + def = this->add("material_notes", coString); + def->label = L("SLA print material notes"); + def->tooltip = L("You can put your notes regarding the SLA print material here."); + def->cli = "material-notes=s"; + def->multiline = true; + def->full_width = true; + def->height = 130; + def->default_value = new ConfigOptionString(""); + + def = this->add("default_sla_material_profile", coString); + def->label = L("Default SLA material profile"); + def->tooltip = L("Default print profile associated with the current printer profile. " + "On selection of the current printer profile, this print profile will be activated."); + def->default_value = new ConfigOptionString(); + + def = this->add("sla_material_settings_id", coString); + def->default_value = new ConfigOptionString(""); +} + void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value) { // handle legacy options @@ -2410,4 +2528,8 @@ StaticPrintConfig::StaticCache PrintConfig::s_c StaticPrintConfig::StaticCache HostConfig::s_cache_HostConfig; StaticPrintConfig::StaticCache FullPrintConfig::s_cache_FullPrintConfig; +StaticPrintConfig::StaticCache SLAMaterialConfig::s_cache_SLAMaterialConfig; +StaticPrintConfig::StaticCache SLAPrinterConfig::s_cache_SLAPrinterConfig; +StaticPrintConfig::StaticCache SLAFullPrintConfig::s_cache_SLAFullPrintConfig; + } diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index 438e90681..5144ad424 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -22,6 +22,14 @@ namespace Slic3r { +enum PrinterTechnology +{ + // Fused Filament Fabrication + ptFFF, + // Stereolitography + ptSLA, +}; + enum GCodeFlavor { gcfRepRap, gcfRepetier, gcfTeacup, gcfMakerWare, gcfMarlin, gcfSailfish, gcfMach3, gcfMachinekit, gcfSmoothie, gcfNoExtrusion, @@ -48,7 +56,16 @@ enum FilamentType { ftPLA, ftABS, ftPET, ftHIPS, ftFLEX, ftSCAFF, ftEDGE, ftNGEN, ftPVA }; -template<> inline t_config_enum_values& ConfigOptionEnum::get_enum_values() { +template<> inline const t_config_enum_values& ConfigOptionEnum::get_enum_values() { + static t_config_enum_values keys_map; + if (keys_map.empty()) { + keys_map["FFF"] = ptFFF; + keys_map["SLA"] = ptSLA; + } + return keys_map; +} + +template<> inline const t_config_enum_values& ConfigOptionEnum::get_enum_values() { static t_config_enum_values keys_map; if (keys_map.empty()) { keys_map["reprap"] = gcfRepRap; @@ -94,7 +111,7 @@ template<> inline t_config_enum_values& ConfigOptionEnum::get_enu return keys_map; } -template<> inline t_config_enum_values& ConfigOptionEnum::get_enum_values() { +template<> inline const t_config_enum_values& ConfigOptionEnum::get_enum_values() { static t_config_enum_values keys_map; if (keys_map.empty()) { keys_map["rectilinear"] = smpRectilinear; @@ -104,7 +121,7 @@ template<> inline t_config_enum_values& ConfigOptionEnum return keys_map; } -template<> inline t_config_enum_values& ConfigOptionEnum::get_enum_values() { +template<> inline const t_config_enum_values& ConfigOptionEnum::get_enum_values() { static t_config_enum_values keys_map; if (keys_map.empty()) { keys_map["random"] = spRandom; @@ -115,7 +132,7 @@ template<> inline t_config_enum_values& ConfigOptionEnum::get_enum return keys_map; } -template<> inline t_config_enum_values& ConfigOptionEnum::get_enum_values() { +template<> inline const t_config_enum_values& ConfigOptionEnum::get_enum_values() { static t_config_enum_values keys_map; if (keys_map.empty()) { keys_map["PLA"] = ftPLA; @@ -139,6 +156,11 @@ public: PrintConfigDef(); static void handle_legacy(t_config_option_key &opt_key, std::string &value); + +private: + void init_common_params(); + void init_fff_params(); + void init_sla_params(); }; // The one and only global definition of SLic3r configuration options. @@ -847,6 +869,73 @@ protected: } }; +class SLAMaterialConfig : public StaticPrintConfig +{ + STATIC_PRINT_CONFIG_CACHE(SLAMaterialConfig) +public: + ConfigOptionFloat layer_height; + ConfigOptionFloat initial_layer_height; + ConfigOptionFloat exposure_time; + ConfigOptionFloat initial_exposure_time; + ConfigOptionFloats material_correction_printing; + ConfigOptionFloats material_correction_curing; +protected: + void initialize(StaticCacheBase &cache, const char *base_ptr) + { + OPT_PTR(layer_height); + OPT_PTR(initial_layer_height); + OPT_PTR(exposure_time); + OPT_PTR(initial_exposure_time); + OPT_PTR(material_correction_printing); + OPT_PTR(material_correction_curing); + } +}; + +class SLAPrinterConfig : public StaticPrintConfig +{ + STATIC_PRINT_CONFIG_CACHE(SLAPrinterConfig) +public: + ConfigOptionEnum printer_technology; + ConfigOptionPoints bed_shape; + ConfigOptionFloat max_print_height; + ConfigOptionFloat display_width; + ConfigOptionFloat display_height; + ConfigOptionInt display_pixels_x; + ConfigOptionInt display_pixels_y; + ConfigOptionFloats printer_correction; +protected: + void initialize(StaticCacheBase &cache, const char *base_ptr) + { + OPT_PTR(printer_technology); + OPT_PTR(bed_shape); + OPT_PTR(max_print_height); + OPT_PTR(display_width); + OPT_PTR(display_height); + OPT_PTR(display_pixels_x); + OPT_PTR(display_pixels_y); + OPT_PTR(printer_correction); + } +}; + +class SLAFullPrintConfig : public SLAPrinterConfig, public SLAMaterialConfig +{ + STATIC_PRINT_CONFIG_CACHE_DERIVED(SLAFullPrintConfig) + SLAFullPrintConfig() : SLAPrinterConfig(0), SLAMaterialConfig(0) { initialize_cache(); *this = s_cache_SLAFullPrintConfig.defaults(); } + +public: + // Validate the SLAFullPrintConfig. Returns an empty string on success, otherwise an error message is returned. +// std::string validate(); + +protected: + // Protected constructor to be called to initialize ConfigCache::m_default. + SLAFullPrintConfig(int) : SLAPrinterConfig(0), SLAMaterialConfig(0) {} + void initialize(StaticCacheBase &cache, const char *base_ptr) + { + this->SLAPrinterConfig ::initialize(cache, base_ptr); + this->SLAMaterialConfig::initialize(cache, base_ptr); + } +}; + #undef STATIC_PRINT_CONFIG_CACHE #undef STATIC_PRINT_CONFIG_CACHE_BASE #undef STATIC_PRINT_CONFIG_CACHE_DERIVED diff --git a/xs/src/slic3r/GUI/AppConfig.cpp b/xs/src/slic3r/GUI/AppConfig.cpp index 2a33cd733..0f77b1953 100644 --- a/xs/src/slic3r/GUI/AppConfig.cpp +++ b/xs/src/slic3r/GUI/AppConfig.cpp @@ -233,6 +233,7 @@ void AppConfig::reset_selections() if (it != m_storage.end()) { it->second.erase("print"); it->second.erase("filament"); + it->second.erase("sla_material"); it->second.erase("printer"); m_dirty = true; } diff --git a/xs/src/slic3r/GUI/Field.cpp b/xs/src/slic3r/GUI/Field.cpp index 3c7c817a6..87f6693a8 100644 --- a/xs/src/slic3r/GUI/Field.cpp +++ b/xs/src/slic3r/GUI/Field.cpp @@ -274,7 +274,7 @@ void CheckBox::BUILD() { bool check_value = m_opt.type == coBool ? m_opt.default_value->getBool() : m_opt.type == coBools ? - static_cast(m_opt.default_value)->get_at(m_opt_idx) : + static_cast(m_opt.default_value)->get_at(m_opt_idx) : false; auto temp = new wxCheckBox(m_parent, wxID_ANY, wxString(""), wxDefaultPosition, size); @@ -599,7 +599,7 @@ void ColourPicker::BUILD() if (m_opt.height >= 0) size.SetHeight(m_opt.height); if (m_opt.width >= 0) size.SetWidth(m_opt.width); - wxString clr(static_cast(m_opt.default_value)->get_at(m_opt_idx)); + wxString clr(static_cast(m_opt.default_value)->get_at(m_opt_idx)); auto temp = new wxColourPickerCtrl(m_parent, wxID_ANY, clr, wxDefaultPosition, size); // // recast as a wxWindow to fit the calling convention @@ -631,7 +631,7 @@ void PointCtrl::BUILD() // wxSize field_size(40, -1); - auto default_pt = static_cast(m_opt.default_value)->values.at(0); + auto default_pt = static_cast(m_opt.default_value)->values.at(0); double val = default_pt(0); wxString X = val - int(val) == 0 ? wxString::Format(_T("%i"), int(val)) : wxNumberFormatter::ToString(val, 2, wxNumberFormatter::Style_None); val = default_pt(1); @@ -695,7 +695,7 @@ void StaticText::BUILD() if (m_opt.height >= 0) size.SetHeight(m_opt.height); if (m_opt.width >= 0) size.SetWidth(m_opt.width); - wxString legend(static_cast(m_opt.default_value)->value); + wxString legend(static_cast(m_opt.default_value)->value); auto temp = new wxStaticText(m_parent, wxID_ANY, legend, wxDefaultPosition, size); temp->SetFont(bold_font()); diff --git a/xs/src/slic3r/GUI/Field.hpp b/xs/src/slic3r/GUI/Field.hpp index e19c47d68..41eef0303 100644 --- a/xs/src/slic3r/GUI/Field.hpp +++ b/xs/src/slic3r/GUI/Field.hpp @@ -38,6 +38,7 @@ wxString double_to_string(double const value); class MyButton : public wxButton { + bool hidden = false; // never show button if it's hidden ones public: MyButton() {} MyButton(wxWindow* parent, wxWindowID id, const wxString& label = wxEmptyString, @@ -52,6 +53,12 @@ public: // overridden from wxWindow base class virtual bool AcceptsFocusFromKeyboard() const { return false; } + + virtual bool Show(bool show = true) override { + if (!show) + hidden = true; + return wxButton::Show(!hidden); + } }; class Field { diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp index 18f63f65e..8348db9c2 100644 --- a/xs/src/slic3r/GUI/GUI.cpp +++ b/xs/src/slic3r/GUI/GUI.cpp @@ -496,20 +496,33 @@ void open_preferences_dialog(int event_preferences) void create_preset_tabs(bool no_controller, int event_value_change, int event_presets_changed) { update_label_colours_from_appconfig(); - add_created_tab(new TabPrint (g_wxTabPanel, no_controller)); - add_created_tab(new TabFilament (g_wxTabPanel, no_controller)); - add_created_tab(new TabPrinter (g_wxTabPanel, no_controller)); - for (size_t i = 0; i < g_wxTabPanel->GetPageCount(); ++ i) { - Tab *tab = dynamic_cast(g_wxTabPanel->GetPage(i)); - if (! tab) - continue; - tab->set_event_value_change(wxEventType(event_value_change)); - tab->set_event_presets_changed(wxEventType(event_presets_changed)); - } + add_created_tab(new TabPrint (g_wxTabPanel, no_controller), event_value_change, event_presets_changed); + add_created_tab(new TabFilament (g_wxTabPanel, no_controller), event_value_change, event_presets_changed); + add_created_tab(new TabSLAMaterial (g_wxTabPanel, no_controller), event_value_change, event_presets_changed); + add_created_tab(new TabPrinter (g_wxTabPanel, no_controller), event_value_change, event_presets_changed); +} + +std::vector preset_tabs = { + { "print", nullptr, ptFFF }, + { "filament", nullptr, ptFFF }, + { "sla_material", nullptr, ptSLA } +}; +const std::vector& get_preset_tabs() { + return preset_tabs; +} + +Tab* get_tab(const std::string& name) +{ + std::vector::iterator it = std::find_if(preset_tabs.begin(), preset_tabs.end(), + [name](PresetTab& tab){ return name == tab.name; }); + return it != preset_tabs.end() ? it->panel : nullptr; } TabIface* get_preset_tab_iface(char *name) { + Tab* tab = get_tab(name); + if (tab) return new TabIface(tab); + for (size_t i = 0; i < g_wxTabPanel->GetPageCount(); ++ i) { Tab *tab = dynamic_cast(g_wxTabPanel->GetPage(i)); if (! tab) @@ -629,13 +642,28 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt } } -void add_created_tab(Tab* panel) +void add_created_tab(Tab* panel, int event_value_change, int event_presets_changed) { panel->create_preset_tab(g_PresetBundle); // Load the currently selected preset into the GUI, update the preset selection box. panel->load_current_preset(); - g_wxTabPanel->AddPage(panel, panel->title()); + + panel->set_event_value_change(wxEventType(event_value_change)); + panel->set_event_presets_changed(wxEventType(event_presets_changed)); + + const wxString& tab_name = panel->GetName(); + bool add_panel = true; + + auto it = std::find_if( preset_tabs.begin(), preset_tabs.end(), + [tab_name](PresetTab& tab){return tab.name == tab_name; }); + if (it != preset_tabs.end()) { + it->panel = panel; + add_panel = it->technology == g_PresetBundle->printers.get_edited_preset().printer_technology(); + } + + if (add_panel) + g_wxTabPanel->AddPage(panel, panel->title()); } void load_current_presets() @@ -676,6 +704,10 @@ PresetBundle* get_preset_bundle() return g_PresetBundle; } +wxNotebook* get_tab_panel() { + return g_wxTabPanel; +} + const wxColour& get_label_clr_modified() { return g_color_label_modified; } diff --git a/xs/src/slic3r/GUI/GUI.hpp b/xs/src/slic3r/GUI/GUI.hpp index 165288819..990711323 100644 --- a/xs/src/slic3r/GUI/GUI.hpp +++ b/xs/src/slic3r/GUI/GUI.hpp @@ -3,7 +3,7 @@ #include #include -#include "Config.hpp" +#include "PrintConfig.hpp" #include "../../libslic3r/Utils.hpp" #include @@ -80,6 +80,13 @@ inline t_file_wild_card& get_file_wild_card() { return FILE_WILDCARDS; } +struct PresetTab { + std::string name; + Tab* panel; + PrinterTechnology technology; +}; + + void disable_screensaver(); void enable_screensaver(); bool debugged(); @@ -97,6 +104,7 @@ void set_3DScene(_3DScene *scene); AppConfig* get_app_config(); wxApp* get_app(); PresetBundle* get_preset_bundle(); +wxNotebook* get_tab_panel(); const wxColour& get_label_clr_modified(); const wxColour& get_label_clr_sys(); @@ -108,6 +116,9 @@ void set_label_clr_sys(const wxColour& clr); const wxFont& small_font(); const wxFont& bold_font(); +Tab* get_tab(const std::string& name); +const std::vector& get_preset_tabs(); + extern void add_menus(wxMenuBar *menu, int event_preferences_changed, int event_language_change); // This is called when closing the application, when loading a config file or when starting the config wizard @@ -130,7 +141,7 @@ void create_preset_tabs(bool no_controller, int event_value_change, int event_pr TabIface* get_preset_tab_iface(char *name); // add it at the end of the tab panel. -void add_created_tab(Tab* panel); +void add_created_tab(Tab* panel, int event_value_change, int event_presets_changed); // Change option value in config void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index = 0); diff --git a/xs/src/slic3r/GUI/Preset.cpp b/xs/src/slic3r/GUI/Preset.cpp index 8335e48b5..90b9db597 100644 --- a/xs/src/slic3r/GUI/Preset.cpp +++ b/xs/src/slic3r/GUI/Preset.cpp @@ -120,6 +120,11 @@ VendorProfile VendorProfile::from_ini(const ptree &tree, const boost::filesystem VendorProfile::PrinterModel model; model.id = section.first.substr(printer_model_key.size()); model.name = section.second.get("name", model.id); + auto technology_field = section.second.get("technology", "FFF"); + if (! ConfigOptionEnum::from_string(technology_field, model.technology)) { + BOOST_LOG_TRIVIAL(error) << boost::format("Vendor bundle: `%1%`: Invalid printer technology field: `%2%`") % id % technology_field; + model.technology = ptFFF; + } section.second.get("variants", ""); const auto variants_field = section.second.get("variants", ""); std::vector variants; @@ -177,7 +182,7 @@ void Preset::normalize(DynamicPrintConfig &config) { auto *nozzle_diameter = dynamic_cast(config.option("nozzle_diameter")); if (nozzle_diameter != nullptr) - // Loaded the Printer settings. Verify, that all extruder dependent values have enough values. + // Loaded the FFF Printer settings. Verify, that all extruder dependent values have enough values. set_num_extruders(config, (unsigned int)nozzle_diameter->values.size()); if (config.option("filament_diameter") != nullptr) { // This config contains single or multiple filament presets. @@ -204,12 +209,9 @@ void Preset::normalize(DynamicPrintConfig &config) } } -// Load a config file, return a C++ class Slic3r::DynamicPrintConfig with $keys initialized from the config file. -// In case of a "default" config item, return the default values. -DynamicPrintConfig& Preset::load(const std::vector &keys) +DynamicPrintConfig& Preset::load(const std::vector &keys, const StaticPrintConfig &defaults) { // Set the configuration from the defaults. - Slic3r::FullPrintConfig defaults; this->config.apply_only(defaults, keys.empty() ? defaults.keys() : keys); if (! this->is_default) { // Load the preset file, apply preset values on top of defaults. @@ -260,8 +262,9 @@ bool Preset::is_compatible_with_printer(const Preset &active_printer) const { DynamicPrintConfig config; config.set_key_value("printer_preset", new ConfigOptionString(active_printer.name)); - config.set_key_value("num_extruders", new ConfigOptionInt( - (int)static_cast(active_printer.config.option("nozzle_diameter"))->values.size())); + const ConfigOption *opt = active_printer.config.option("nozzle_diameter"); + if (opt) + config.set_key_value("num_extruders", new ConfigOptionInt((int)static_cast(opt)->values.size())); return this->is_compatible_with_printer(active_printer, &config); } @@ -329,8 +332,10 @@ const std::vector& Preset::printer_options() static std::vector s_opts; if (s_opts.empty()) { s_opts = { - "bed_shape", "z_offset", "gcode_flavor", "use_relative_e_distances", "serial_port", "serial_speed", "host_type", - "print_host", "printhost_apikey", "printhost_cafile", "use_firmware_retraction", "use_volumetric_e", "variable_layer_height", + "printer_technology", + "bed_shape", "z_offset", "gcode_flavor", "use_relative_e_distances", "serial_port", "serial_speed", + "use_firmware_retraction", "use_volumetric_e", "variable_layer_height", + "host_type", "print_host", "printhost_apikey", "printhost_cafile", "single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode", "between_objects_gcode", "printer_vendor", "printer_model", "printer_variant", "printer_notes", "cooling_tube_retraction", "cooling_tube_length", "parking_pos_retraction", "extra_loading_move", "max_print_height", "default_print_profile", "inherits", @@ -360,7 +365,39 @@ const std::vector& Preset::nozzle_options() return s_opts; } -PresetCollection::PresetCollection(Preset::Type type, const std::vector &keys) : +const std::vector& Preset::sla_printer_options() +{ + static std::vector s_opts; + if (s_opts.empty()) { + s_opts = { + "printer_technology", + "bed_shape", "max_print_height", + "display_width", "display_height", "display_pixels_x", "display_pixels_y", + "printer_correction", + "printer_notes", + "inherits" + }; + } + return s_opts; +} + +const std::vector& Preset::sla_material_options() +{ + static std::vector s_opts; + if (s_opts.empty()) { + s_opts = { + "layer_height", "initial_layer_height", + "exposure_time", "initial_exposure_time", + "material_correction_printing", "material_correction_curing", + "material_notes", + "compatible_printers", + "compatible_printers_condition", "inherits" + }; + } + return s_opts; +} + +PresetCollection::PresetCollection(Preset::Type type, const std::vector &keys, const Slic3r::StaticPrintConfig &defaults, const std::string &default_name) : m_type(type), m_edited_preset(type, "", false), m_idx_selected(0), @@ -368,8 +405,7 @@ PresetCollection::PresetCollection(Preset::Type type, const std::vectoradd_default_preset(keys, defaults, default_name); m_edited_preset.config.apply(m_presets.front().config); } @@ -383,7 +419,7 @@ PresetCollection::~PresetCollection() void PresetCollection::reset(bool delete_files) { - if (m_presets.size() > 1) { + if (m_presets.size() > m_num_default_presets) { if (delete_files) { // Erase the preset files. for (Preset &preset : m_presets) @@ -391,11 +427,19 @@ void PresetCollection::reset(bool delete_files) boost::nowide::remove(preset.file.c_str()); } // Don't use m_presets.resize() here as it requires a default constructor for Preset. - m_presets.erase(m_presets.begin() + 1, m_presets.end()); + m_presets.erase(m_presets.begin() + m_num_default_presets, m_presets.end()); this->select_preset(0); } } +void PresetCollection::add_default_preset(const std::vector &keys, const Slic3r::StaticPrintConfig &defaults, const std::string &preset_name) +{ + // Insert just the default preset. + m_presets.emplace_back(Preset(this->type(), preset_name, true)); + m_presets.back().load(keys, defaults); + ++ m_num_default_presets; +} + // Load all presets found in dir_path. // Throws an exception on error. void PresetCollection::load_presets(const std::string &dir_path, const std::string &subdir) @@ -418,14 +462,15 @@ void PresetCollection::load_presets(const std::string &dir_path, const std::stri try { Preset preset(m_type, name, false); preset.file = dir_entry.path().string(); - preset.load(keys); + //FIXME One should initialize with SLAFullPrintConfig for the SLA profiles! + preset.load(keys, static_cast(FullPrintConfig::defaults())); m_presets.emplace_back(preset); } catch (const std::runtime_error &err) { errors_cummulative += err.what(); errors_cummulative += "\n"; } } - std::sort(m_presets.begin() + 1, m_presets.end()); + std::sort(m_presets.begin() + m_num_default_presets, m_presets.end()); this->select_preset(first_visible_idx()); if (! errors_cummulative.empty()) throw std::runtime_error(errors_cummulative); @@ -643,7 +688,7 @@ Preset* PresetCollection::find_preset(const std::string &name, bool first_visibl // Return index of the first visible preset. Certainly at least the '- default -' preset shall be visible. size_t PresetCollection::first_visible_idx() const { - size_t idx = m_default_suppressed ? 1 : 0; + size_t idx = m_default_suppressed ? m_num_default_presets : 0; for (; idx < this->m_presets.size(); ++ idx) if (m_presets[idx].is_visible) break; @@ -656,7 +701,7 @@ void PresetCollection::set_default_suppressed(bool default_suppressed) { if (m_default_suppressed != default_suppressed) { m_default_suppressed = default_suppressed; - m_presets.front().is_visible = ! default_suppressed || (m_presets.size() > 1 && m_idx_selected > 0); + m_presets.front().is_visible = ! default_suppressed || (m_presets.size() > m_num_default_presets && m_idx_selected > 0); } } @@ -664,9 +709,10 @@ size_t PresetCollection::update_compatible_with_printer_internal(const Preset &a { DynamicPrintConfig config; config.set_key_value("printer_preset", new ConfigOptionString(active_printer.name)); - config.set_key_value("num_extruders", new ConfigOptionInt( - (int)static_cast(active_printer.config.option("nozzle_diameter"))->values.size())); - for (size_t idx_preset = 1; idx_preset < m_presets.size(); ++ idx_preset) { + const ConfigOption *opt = active_printer.config.option("nozzle_diameter"); + if (opt) + config.set_key_value("num_extruders", new ConfigOptionInt((int)static_cast(opt)->values.size())); + for (size_t idx_preset = m_num_default_presets; idx_preset < m_presets.size(); ++ idx_preset) { bool selected = idx_preset == m_idx_selected; Preset &preset_selected = m_presets[idx_preset]; Preset &preset_edited = selected ? m_edited_preset : preset_selected; @@ -707,7 +753,7 @@ void PresetCollection::update_platter_ui(wxBitmapComboBox *ui) wxString selected = ""; if (!this->m_presets.front().is_visible) ui->Append("------- " +_(L("System presets")) + " -------", wxNullBitmap); - for (size_t i = this->m_presets.front().is_visible ? 0 : 1; i < this->m_presets.size(); ++i) { + for (size_t i = this->m_presets.front().is_visible ? 0 : m_num_default_presets; i < this->m_presets.size(); ++i) { const Preset &preset = this->m_presets[i]; if (! preset.is_visible || (! preset.is_compatible && i != m_idx_selected)) continue; @@ -745,7 +791,7 @@ void PresetCollection::update_platter_ui(wxBitmapComboBox *ui) if (i == m_idx_selected) selected = wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()); } - if (preset.is_default) + if (i + 1 == m_num_default_presets) ui->Append("------- " + _(L("System presets")) + " -------", wxNullBitmap); } if (!nonsys_presets.empty()) @@ -775,7 +821,7 @@ size_t PresetCollection::update_tab_ui(wxBitmapComboBox *ui, bool show_incompati wxString selected = ""; if (!this->m_presets.front().is_visible) ui->Append("------- " + _(L("System presets")) + " -------", wxNullBitmap); - for (size_t i = this->m_presets.front().is_visible ? 0 : 1; i < this->m_presets.size(); ++i) { + for (size_t i = this->m_presets.front().is_visible ? 0 : m_num_default_presets; i < this->m_presets.size(); ++i) { const Preset &preset = this->m_presets[i]; if (! preset.is_visible || (! show_incompatible && ! preset.is_compatible && i != m_idx_selected)) continue; @@ -805,7 +851,7 @@ size_t PresetCollection::update_tab_ui(wxBitmapComboBox *ui, bool show_incompati if (i == m_idx_selected) selected = wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()); } - if (preset.is_default) + if (i + 1 == m_num_default_presets) ui->Append("------- " + _(L("System presets")) + " -------", wxNullBitmap); } if (!nonsys_presets.empty()) @@ -853,11 +899,11 @@ bool PresetCollection::update_dirty_ui(wxBitmapComboBox *ui) return was_dirty != is_dirty; } -std::vector PresetCollection::dirty_options(const Preset *edited, const Preset *reference, const bool is_printer_type /*= false*/) +std::vector PresetCollection::dirty_options(const Preset *edited, const Preset *reference, const bool deep_compare /*= false*/) { std::vector changed; if (edited != nullptr && reference != nullptr) { - changed = is_printer_type ? + changed = deep_compare ? reference->config.deep_diff(edited->config) : reference->config.diff(edited->config); // The "compatible_printers" option key is handled differently from the others: @@ -897,7 +943,7 @@ bool PresetCollection::select_preset_by_name(const std::string &name_w_suffix, b idx = it - m_presets.begin(); else { // Find the first visible preset. - for (size_t i = m_default_suppressed ? 1 : 0; i < m_presets.size(); ++ i) + for (size_t i = m_default_suppressed ? m_num_default_presets : 0; i < m_presets.size(); ++ i) if (m_presets[i].is_visible) { idx = i; break; @@ -939,7 +985,7 @@ std::vector PresetCollection::merge_presets(PresetCollection &&othe if (preset.is_default || preset.is_external) continue; Preset key(m_type, preset.name); - auto it = std::lower_bound(m_presets.begin() + 1, m_presets.end(), key); + auto it = std::lower_bound(m_presets.begin() + m_num_default_presets, m_presets.end(), key); if (it == m_presets.end() || it->name != preset.name) { if (preset.vendor != nullptr) { // Re-assign a pointer to the vendor structure in the new PresetBundle. diff --git a/xs/src/slic3r/GUI/Preset.hpp b/xs/src/slic3r/GUI/Preset.hpp index 0d00cae48..821d7dc54 100644 --- a/xs/src/slic3r/GUI/Preset.hpp +++ b/xs/src/slic3r/GUI/Preset.hpp @@ -52,6 +52,7 @@ public: PrinterModel() {} std::string id; std::string name; + PrinterTechnology technology; std::vector variants; PrinterVariant* variant(const std::string &name) { for (auto &v : this->variants) @@ -83,6 +84,7 @@ public: TYPE_INVALID, TYPE_PRINT, TYPE_FILAMENT, + TYPE_SLA_MATERIAL, TYPE_PRINTER, }; @@ -123,8 +125,7 @@ public: DynamicPrintConfig config; // Load this profile for the following keys only. - // Throws std::runtime_error in case the file cannot be read. - DynamicPrintConfig& load(const std::vector &keys); + DynamicPrintConfig& load(const std::vector &keys, const StaticPrintConfig &defaults); void save(); @@ -149,6 +150,10 @@ public: std::string& compatible_printers_condition() { return Preset::compatible_printers_condition(this->config); } const std::string& compatible_printers_condition() const { return Preset::compatible_printers_condition(const_cast(this)->config); } + static PrinterTechnology& printer_technology(DynamicPrintConfig &cfg) { return cfg.option>("printer_technology", true)->value; } + PrinterTechnology& printer_technology() { return Preset::printer_technology(this->config); } + const PrinterTechnology& printer_technology() const { return Preset::printer_technology(const_cast(this)->config); } + // Mark this preset as compatible if it is compatible with active_printer. bool update_compatible_with_printer(const Preset &active_printer, const DynamicPrintConfig *extra_config); @@ -167,6 +172,10 @@ public: static const std::vector& printer_options(); // Nozzle options of the printer options. static const std::vector& nozzle_options(); + + static const std::vector& sla_printer_options(); + static const std::vector& sla_material_options(); + static void update_suffix_modified(); protected: @@ -184,15 +193,15 @@ class PresetCollection { public: // Initialize the PresetCollection with the "- default -" preset. - PresetCollection(Preset::Type type, const std::vector &keys); + PresetCollection(Preset::Type type, const std::vector &keys, const Slic3r::StaticPrintConfig &defaults, const std::string &default_name = "- default -"); ~PresetCollection(); typedef std::deque::iterator Iterator; typedef std::deque::const_iterator ConstIterator; - Iterator begin() { return m_presets.begin() + 1; } - ConstIterator begin() const { return m_presets.begin() + 1; } - Iterator end() { return m_presets.end(); } - ConstIterator end() const { return m_presets.end(); } + Iterator begin() { return m_presets.begin() + m_num_default_presets; } + ConstIterator begin() const { return m_presets.begin() + m_num_default_presets; } + Iterator end() { return m_presets.end(); } + ConstIterator end() const { return m_presets.end(); } void reset(bool delete_files); @@ -200,6 +209,9 @@ public: std::string name() const; const std::deque& operator()() const { return m_presets; } + // Add default preset at the start of the collection, increment the m_default_preset counter. + void add_default_preset(const std::vector &keys, const Slic3r::StaticPrintConfig &defaults, const std::string &preset_name); + // Load ini files of the particular type from the provided directory path. void load_presets(const std::string &dir_path, const std::string &subdir); @@ -247,6 +259,8 @@ public: Preset& get_selected_preset() { return m_presets[m_idx_selected]; } const Preset& get_selected_preset() const { return m_presets[m_idx_selected]; } int get_selected_idx() const { return m_idx_selected; } + // Returns the name of the selected preset, or an empty string if no preset is selected. + std::string get_selected_preset_name() const { return (m_idx_selected == -1) ? std::string() : this->get_selected_preset().name; } // For the current edited preset, return the parent preset if there is one. // If there is no parent preset, nullptr is returned. // The parent preset may be a system preset or a user preset, which will be @@ -283,7 +297,7 @@ public: template size_t first_compatible_idx(PreferedCondition prefered_condition) const { - size_t i = m_default_suppressed ? 1 : 0; + size_t i = m_default_suppressed ? m_num_default_presets : 0; size_t n = this->m_presets.size(); size_t i_compatible = n; for (; i < n; ++ i) @@ -309,7 +323,8 @@ public: const Preset& first_compatible() const { return this->preset(this->first_compatible_idx()); } // Return number of presets including the "- default -" preset. - size_t size() const { return this->m_presets.size(); } + size_t size() const { return m_presets.size(); } + bool has_defaults_only() const { return m_presets.size() <= m_num_default_presets; } // For Print / Filament presets, disable those, which are not compatible with the printer. template @@ -327,11 +342,11 @@ public: // Compare the content of get_selected_preset() with get_edited_preset() configs, return true if they differ. bool current_is_dirty() const { return ! this->current_dirty_options().empty(); } // Compare the content of get_selected_preset() with get_edited_preset() configs, return the list of keys where they differ. - std::vector current_dirty_options(const bool is_printer_type = false) const - { return dirty_options(&this->get_edited_preset(), &this->get_selected_preset(), is_printer_type); } + std::vector current_dirty_options(const bool deep_compare = false) const + { return dirty_options(&this->get_edited_preset(), &this->get_selected_preset(), deep_compare); } // Compare the content of get_selected_preset() with get_edited_preset() configs, return the list of keys where they differ. - std::vector current_different_from_parent_options(const bool is_printer_type = false) const - { return dirty_options(&this->get_edited_preset(), this->get_selected_preset_parent(), is_printer_type); } + std::vector current_different_from_parent_options(const bool deep_compare = false) const + { return dirty_options(&this->get_edited_preset(), this->get_selected_preset_parent(), deep_compare); } // Update the choice UI from the list of presets. // If show_incompatible, all presets are shown, otherwise only the compatible presets are shown. @@ -374,8 +389,16 @@ private: std::deque::iterator find_preset_internal(const std::string &name) { Preset key(m_type, name); - auto it = std::lower_bound(m_presets.begin() + 1, m_presets.end(), key); - return ((it == m_presets.end() || it->name != name) && m_presets.front().name == name) ? m_presets.begin() : it; + auto it = std::lower_bound(m_presets.begin() + m_num_default_presets, m_presets.end(), key); + if (it == m_presets.end() || it->name != name) { + // Preset has not been not found in the sorted list of non-default presets. Try the defaults. + for (size_t i = 0; i < m_num_default_presets; ++ i) + if (m_presets[i].name == name) { + it = m_presets.begin() + i; + break; + } + } + return it; } std::deque::const_iterator find_preset_internal(const std::string &name) const { return const_cast(this)->find_preset_internal(name); } @@ -395,7 +418,8 @@ private: // Selected preset. int m_idx_selected; // Is the "- default -" preset suppressed? - bool m_default_suppressed = true; + bool m_default_suppressed = true; + size_t m_num_default_presets = 0; // Compatible & incompatible marks, to be placed at the wxBitmapComboBox items of a Platter. // These bitmaps are not owned by PresetCollection, but by a PresetBundle. const wxBitmap *m_bitmap_compatible = nullptr; diff --git a/xs/src/slic3r/GUI/PresetBundle.cpp b/xs/src/slic3r/GUI/PresetBundle.cpp index 94baa0e0e..cd3924dd0 100644 --- a/xs/src/slic3r/GUI/PresetBundle.cpp +++ b/xs/src/slic3r/GUI/PresetBundle.cpp @@ -40,9 +40,10 @@ static std::vector s_project_options { }; PresetBundle::PresetBundle() : - prints(Preset::TYPE_PRINT, Preset::print_options()), - filaments(Preset::TYPE_FILAMENT, Preset::filament_options()), - printers(Preset::TYPE_PRINTER, Preset::printer_options()), + prints(Preset::TYPE_PRINT, Preset::print_options(), static_cast(FullPrintConfig::defaults())), + filaments(Preset::TYPE_FILAMENT, Preset::filament_options(), static_cast(FullPrintConfig::defaults())), + sla_materials(Preset::TYPE_SLA_MATERIAL, Preset::sla_material_options(), static_cast(SLAFullPrintConfig::defaults())), + printers(Preset::TYPE_PRINTER, Preset::printer_options(), static_cast(FullPrintConfig::defaults()), "- default FFF -"), m_bitmapCompatible(new wxBitmap), m_bitmapIncompatible(new wxBitmap), m_bitmapLock(new wxBitmap), @@ -69,24 +70,35 @@ PresetBundle::PresetBundle() : this->filaments.default_preset().compatible_printers_condition(); this->filaments.default_preset().inherits(); - this->printers.default_preset().config.optptr("printer_settings_id", true); - this->printers.default_preset().config.optptr("printer_vendor", true); - this->printers.default_preset().config.optptr("printer_model", true); - this->printers.default_preset().config.optptr("printer_variant", true); - this->printers.default_preset().config.optptr("default_print_profile", true); - this->printers.default_preset().config.option("default_filament_profile", true)->values = { "" }; - this->printers.default_preset().inherits(); + this->sla_materials.default_preset().config.optptr("sla_material_settings_id", true); + this->sla_materials.default_preset().compatible_printers_condition(); + this->sla_materials.default_preset().inherits(); + + this->printers.add_default_preset(Preset::sla_printer_options(), static_cast(SLAFullPrintConfig::defaults()), "- default SLA -"); + this->printers.preset(1).printer_technology() = ptSLA; + for (size_t i = 0; i < 2; ++ i) { + Preset &preset = this->printers.preset(i); + preset.config.optptr("printer_settings_id", true); + preset.config.optptr("printer_vendor", true); + preset.config.optptr("printer_model", true); + preset.config.optptr("printer_variant", true); + preset.config.optptr("default_print_profile", true); + preset.config.option("default_filament_profile", true)->values = { "" }; + preset.inherits(); + } // Load the default preset bitmaps. - this->prints .load_bitmap_default("cog.png"); - this->filaments.load_bitmap_default("spool.png"); - this->printers .load_bitmap_default("printer_empty.png"); + this->prints .load_bitmap_default("cog.png"); + this->filaments .load_bitmap_default("spool.png"); + this->sla_materials.load_bitmap_default("package_green.png"); + this->printers .load_bitmap_default("printer_empty.png"); this->load_compatible_bitmaps(); // Re-activate the default presets, so their "edited" preset copies will be updated with the additional configuration values above. - this->prints .select_preset(0); - this->filaments.select_preset(0); - this->printers .select_preset(0); + this->prints .select_preset(0); + this->filaments .select_preset(0); + this->sla_materials.select_preset(0); + this->printers .select_preset(0); this->project_config.apply_only(FullPrintConfig::defaults(), s_project_options); } @@ -113,13 +125,15 @@ void PresetBundle::reset(bool delete_files) { // Clear the existing presets, delete their respective files. this->vendors.clear(); - this->prints .reset(delete_files); - this->filaments.reset(delete_files); - this->printers .reset(delete_files); + this->prints .reset(delete_files); + this->filaments .reset(delete_files); + this->sla_materials.reset(delete_files); + this->printers .reset(delete_files); this->filament_presets.clear(); - this->filament_presets.emplace_back(this->filaments.get_selected_preset().name); + this->filament_presets.emplace_back(this->filaments.get_selected_preset_name()); this->obsolete_presets.prints.clear(); this->obsolete_presets.filaments.clear(); + this->obsolete_presets.sla_materials.clear(); this->obsolete_presets.printers.clear(); } @@ -135,11 +149,13 @@ void PresetBundle::setup_directories() data_dir / "presets", data_dir / "presets" / "print", data_dir / "presets" / "filament", + data_dir / "presets" / "sla_material", data_dir / "presets" / "printer" #else // Store the print/filament/printer presets at the same location as the upstream Slic3r. data_dir / "print", data_dir / "filament", + data_dir / "sla_material", data_dir / "printer" #endif }; @@ -175,6 +191,11 @@ void PresetBundle::load_presets(const AppConfig &config) } catch (const std::runtime_error &err) { errors_cummulative += err.what(); } + try { + this->sla_materials.load_presets(dir_user_presets, "sla_material"); + } catch (const std::runtime_error &err) { + errors_cummulative += err.what(); + } try { this->printers.load_presets(dir_user_presets, "printer"); } catch (const std::runtime_error &err) { @@ -238,13 +259,16 @@ std::string PresetBundle::load_system_presets() std::vector PresetBundle::merge_presets(PresetBundle &&other) { this->vendors.insert(other.vendors.begin(), other.vendors.end()); - std::vector duplicate_prints = this->prints .merge_presets(std::move(other.prints), this->vendors); - std::vector duplicate_filaments = this->filaments.merge_presets(std::move(other.filaments), this->vendors); - std::vector duplicate_printers = this->printers .merge_presets(std::move(other.printers), this->vendors); - append(this->obsolete_presets.prints, std::move(other.obsolete_presets.prints)); - append(this->obsolete_presets.filaments, std::move(other.obsolete_presets.filaments)); - append(this->obsolete_presets.printers, std::move(other.obsolete_presets.printers)); + std::vector duplicate_prints = this->prints .merge_presets(std::move(other.prints), this->vendors); + std::vector duplicate_filaments = this->filaments .merge_presets(std::move(other.filaments), this->vendors); + std::vector duplicate_sla_materials = this->sla_materials.merge_presets(std::move(other.sla_materials), this->vendors); + std::vector duplicate_printers = this->printers .merge_presets(std::move(other.printers), this->vendors); + append(this->obsolete_presets.prints, std::move(other.obsolete_presets.prints)); + append(this->obsolete_presets.filaments, std::move(other.obsolete_presets.filaments)); + append(this->obsolete_presets.sla_materials, std::move(other.obsolete_presets.sla_materials)); + append(this->obsolete_presets.printers, std::move(other.obsolete_presets.printers)); append(duplicate_prints, std::move(duplicate_filaments)); + append(duplicate_prints, std::move(duplicate_sla_materials)); append(duplicate_prints, std::move(duplicate_printers)); return duplicate_prints; } @@ -275,9 +299,10 @@ void PresetBundle::load_selections(const AppConfig &config) this->load_installed_printers(config); // Parse the initial print / filament / printer profile names. - std::string initial_print_profile_name = remove_ini_suffix(config.get("presets", "print")); - std::string initial_filament_profile_name = remove_ini_suffix(config.get("presets", "filament")); - std::string initial_printer_profile_name = remove_ini_suffix(config.get("presets", "printer")); + std::string initial_print_profile_name = remove_ini_suffix(config.get("presets", "print")); + std::string initial_filament_profile_name = remove_ini_suffix(config.get("presets", "filament")); + std::string initial_sla_material_profile_name = remove_ini_suffix(config.get("presets", "sla_material")); + std::string initial_printer_profile_name = remove_ini_suffix(config.get("presets", "printer")); // Activate print / filament / printer profiles from the config. // If the printer profile enumerated by the config are not visible, select an alternate preset. @@ -285,21 +310,24 @@ void PresetBundle::load_selections(const AppConfig &config) // will be selected by the following call of this->update_compatible_with_printer(true). prints.select_preset_by_name_strict(initial_print_profile_name); filaments.select_preset_by_name_strict(initial_filament_profile_name); + sla_materials.select_preset_by_name_strict(initial_sla_material_profile_name); printers.select_preset_by_name(initial_printer_profile_name, true); - // Load the names of the other filament profiles selected for a multi-material printer. - auto *nozzle_diameter = dynamic_cast(printers.get_selected_preset().config.option("nozzle_diameter")); - size_t num_extruders = nozzle_diameter->values.size(); - this->filament_presets = { initial_filament_profile_name }; - for (unsigned int i = 1; i < (unsigned int)num_extruders; ++ i) { - char name[64]; - sprintf(name, "filament_%d", i); - if (! config.has("presets", name)) - break; - this->filament_presets.emplace_back(remove_ini_suffix(config.get("presets", name))); + if (printers.get_selected_preset().printer_technology() == ptFFF){ + // Load the names of the other filament profiles selected for a multi-material printer. + auto *nozzle_diameter = dynamic_cast(printers.get_selected_preset().config.option("nozzle_diameter")); + size_t num_extruders = nozzle_diameter->values.size(); + this->filament_presets = { initial_filament_profile_name }; + for (unsigned int i = 1; i < (unsigned int)num_extruders; ++i) { + char name[64]; + sprintf(name, "filament_%d", i); + if (!config.has("presets", name)) + break; + this->filament_presets.emplace_back(remove_ini_suffix(config.get("presets", name))); + } + // Do not define the missing filaments, so that the update_compatible_with_printer() will use the preferred filaments. + this->filament_presets.resize(num_extruders, ""); } - // Do not define the missing filaments, so that the update_compatible_with_printer() will use the preferred filaments. - this->filament_presets.resize(num_extruders, ""); // Update visibility of presets based on their compatibility with the active printer. // Always try to select a compatible print and filament preset to the current printer preset, @@ -313,25 +341,33 @@ void PresetBundle::load_selections(const AppConfig &config) void PresetBundle::export_selections(AppConfig &config) { assert(filament_presets.size() >= 1); - assert(filament_presets.size() > 1 || filaments.get_selected_preset().name == filament_presets.front()); + assert(filament_presets.size() > 1 || filaments.get_selected_preset_name() == filament_presets.front()); config.clear_section("presets"); - config.set("presets", "print", prints.get_selected_preset().name); - config.set("presets", "filament", filament_presets.front()); + config.set("presets", "print", prints.get_selected_preset_name()); + config.set("presets", "filament", filament_presets.front()); for (int i = 1; i < filament_presets.size(); ++i) { char name[64]; sprintf(name, "filament_%d", i); config.set("presets", name, filament_presets[i]); } - config.set("presets", "printer", printers.get_selected_preset().name); + config.set("presets", "sla_material", sla_materials.get_selected_preset_name()); + config.set("presets", "printer", printers.get_selected_preset_name()); } void PresetBundle::export_selections(PlaceholderParser &pp) { assert(filament_presets.size() >= 1); - assert(filament_presets.size() > 1 || filaments.get_selected_preset().name == filament_presets.front()); - pp.set("print_preset", prints.get_selected_preset().name); - pp.set("filament_preset", filament_presets); - pp.set("printer_preset", printers.get_selected_preset().name); + assert(filament_presets.size() > 1 || filaments.get_selected_preset_name() == filament_presets.front()); + switch (printers.get_edited_preset().printer_technology()) { + case ptFFF: + pp.set("print_preset", prints.get_selected_preset().name); + pp.set("filament_preset", filament_presets); + break; + case ptSLA: + pp.set("sla_material_preset", sla_materials.get_selected_preset().name); + break; + } + pp.set("printer_preset", printers.get_selected_preset().name); } bool PresetBundle::load_compatible_bitmaps() @@ -349,32 +385,43 @@ bool PresetBundle::load_compatible_bitmaps() bool loaded_lock_open = m_bitmapLockOpen->LoadFile( wxString::FromUTF8(Slic3r::var(path_bitmap_lock_open).c_str()), wxBITMAP_TYPE_PNG); if (loaded_compatible) { - prints .set_bitmap_compatible(m_bitmapCompatible); - filaments.set_bitmap_compatible(m_bitmapCompatible); + prints .set_bitmap_compatible(m_bitmapCompatible); + filaments .set_bitmap_compatible(m_bitmapCompatible); + sla_materials.set_bitmap_compatible(m_bitmapCompatible); // printers .set_bitmap_compatible(m_bitmapCompatible); } if (loaded_incompatible) { - prints .set_bitmap_incompatible(m_bitmapIncompatible); - filaments.set_bitmap_incompatible(m_bitmapIncompatible); -// printers .set_bitmap_incompatible(m_bitmapIncompatible); + prints .set_bitmap_incompatible(m_bitmapIncompatible); + filaments .set_bitmap_incompatible(m_bitmapIncompatible); + sla_materials.set_bitmap_incompatible(m_bitmapIncompatible); +// printers .set_bitmap_incompatible(m_bitmapIncompatible); } if (loaded_lock) { - prints .set_bitmap_lock(m_bitmapLock); - filaments.set_bitmap_lock(m_bitmapLock); - printers .set_bitmap_lock(m_bitmapLock); + prints .set_bitmap_lock(m_bitmapLock); + filaments .set_bitmap_lock(m_bitmapLock); + sla_materials.set_bitmap_lock(m_bitmapLock); + printers .set_bitmap_lock(m_bitmapLock); } if (loaded_lock_open) { - prints .set_bitmap_lock_open(m_bitmapLock); - filaments.set_bitmap_lock_open(m_bitmapLock); - printers .set_bitmap_lock_open(m_bitmapLock); + prints .set_bitmap_lock_open(m_bitmapLock); + filaments .set_bitmap_lock_open(m_bitmapLock); + sla_materials.set_bitmap_lock_open(m_bitmapLock); + printers .set_bitmap_lock_open(m_bitmapLock); } return loaded_compatible && loaded_incompatible && loaded_lock && loaded_lock_open; } DynamicPrintConfig PresetBundle::full_config() const +{ + return (this->printers.get_edited_preset().printer_technology() == ptFFF) ? + this->full_fff_config() : + this->full_sla_config(); +} + +DynamicPrintConfig PresetBundle::full_fff_config() const { DynamicPrintConfig out; - out.apply(FullPrintConfig()); + out.apply(FullPrintConfig::defaults()); out.apply(this->prints.get_edited_preset().config); // Add the default filament preset to have the "filament_preset_id" defined. out.apply(this->filaments.default_preset().config); @@ -466,6 +513,48 @@ DynamicPrintConfig PresetBundle::full_config() const return out; } +DynamicPrintConfig PresetBundle::full_sla_config() const +{ + DynamicPrintConfig out; + out.apply(SLAFullPrintConfig::defaults()); + out.apply(this->sla_materials.get_edited_preset().config); + out.apply(this->printers.get_edited_preset().config); + // There are no project configuration values as of now, the project_config is reserved for FFF printers. +// out.apply(this->project_config); + + // Collect the "compatible_printers_condition" and "inherits" values over all presets (sla_materials, printers) into a single vector. + std::vector compatible_printers_condition; + std::vector inherits; + compatible_printers_condition.emplace_back(this->/*prints*/sla_materials.get_edited_preset().compatible_printers_condition()); + inherits .emplace_back(this->/*prints*/sla_materials.get_edited_preset().inherits()); + inherits .emplace_back(this->printers.get_edited_preset().inherits()); + + // These two value types clash between the print and filament profiles. They should be renamed. + out.erase("compatible_printers"); + out.erase("compatible_printers_condition"); + out.erase("inherits"); + + out.option("sla_material_settings_id", true)->value = this->sla_materials.get_selected_preset().name; + out.option("printer_settings_id", true)->value = this->printers.get_selected_preset().name; + + // Serialize the collected "compatible_printers_condition" and "inherits" fields. + // There will be 1 + num_exturders fields for "inherits" and 2 + num_extruders for "compatible_printers_condition" stored. + // The vector will not be stored if all fields are empty strings. + auto add_if_some_non_empty = [&out](std::vector &&values, const std::string &key) { + bool nonempty = false; + for (const std::string &v : values) + if (! v.empty()) { + nonempty = true; + break; + } + if (nonempty) + out.set_key_value(key, new ConfigOptionStrings(std::move(values))); + }; + add_if_some_non_empty(std::move(compatible_printers_condition), "compatible_printers_condition_cummulative"); + add_if_some_non_empty(std::move(inherits), "inherits_cummulative"); + return out; +} + // Load an external config file containing the print, filament and printer presets. // Instead of a config file, a G-code may be loaded containing the full set of parameters. // In the future the configuration will likely be read from an AMF file as well. @@ -530,6 +619,8 @@ void PresetBundle::load_config_string(const char* str, const char* source_filena // Load a config file from a boost property_tree. This is a private method called from load_config_file. void PresetBundle::load_config_file_config(const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config) { + PrinterTechnology printer_technology = Preset::printer_technology(config); + // The "compatible_printers" field should not have been exported into a config.ini or a G-code anyway, // but some of the alpha versions of Slic3r did. { @@ -541,8 +632,10 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool } } - size_t num_extruders = std::min(config.option("nozzle_diameter" )->values.size(), - config.option("filament_diameter")->values.size()); + size_t num_extruders = (printer_technology == ptFFF) ? + std::min(config.option("nozzle_diameter" )->values.size(), + config.option("filament_diameter")->values.size()) : + 0; // Make a copy of the "compatible_printers_condition_cummulative" and "inherits_cummulative" vectors, which // accumulate values over all presets (print, filaments, printers). // These values will be distributed into their particular presets when loading. @@ -553,7 +646,8 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool compatible_printers_condition_values.resize(num_extruders + 2, std::string()); inherits_values.resize(num_extruders + 2, std::string()); // The "default_filament_profile" will be later extracted into the printer profile. - config.option("default_filament_profile", true)->values.resize(num_extruders, std::string()); + if (printer_technology == ptFFF) + config.option("default_filament_profile", true)->values.resize(num_extruders, std::string()); // 1) Create a name from the file name. // Keep the suffix (.ini, .gcode, .amf, .3mf etc) to differentiate it from the normal profiles. @@ -562,81 +656,83 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool // 2) If the loading succeeded, split and load the config into print / filament / printer settings. // First load the print and printer presets. for (size_t i_group = 0; i_group < 2; ++ i_group) { - PresetCollection &presets = (i_group == 0) ? this->prints : this->printers; + PresetCollection &presets = (i_group == 0) ? ((printer_technology == ptFFF) ? this->prints : this->sla_materials) : this->printers; // Split the "compatible_printers_condition" and "inherits" values one by one from a single vector to the print & printer profiles. size_t idx = (i_group == 0) ? 0 : num_extruders + 1; inherits = inherits_values[idx]; compatible_printers_condition = compatible_printers_condition_values[idx]; if (is_external) presets.load_external_preset(name_or_path, name, - config.opt_string((i_group == 0) ? "print_settings_id" : "printer_settings_id", true), + config.opt_string((i_group == 0) ? ((printer_technology == ptFFF) ? "print_settings_id" : "sla_material_id") : "printer_settings_id", true), config); else presets.load_preset(presets.path_from_name(name), name, config).save(); } - // 3) Now load the filaments. If there are multiple filament presets, split them and load them. - auto old_filament_profile_names = config.option("filament_settings_id", true); - old_filament_profile_names->values.resize(num_extruders, std::string()); + if (Preset::printer_technology(config) == ptFFF) { + // 3) Now load the filaments. If there are multiple filament presets, split them and load them. + auto old_filament_profile_names = config.option("filament_settings_id", true); + old_filament_profile_names->values.resize(num_extruders, std::string()); - if (num_extruders <= 1) { - // Split the "compatible_printers_condition" and "inherits" from the cummulative vectors to separate filament presets. - inherits = inherits_values[1]; - compatible_printers_condition = compatible_printers_condition_values[1]; - if (is_external) - this->filaments.load_external_preset(name_or_path, name, old_filament_profile_names->values.front(), config); - else - this->filaments.load_preset(this->filaments.path_from_name(name), name, config).save(); - this->filament_presets.clear(); - this->filament_presets.emplace_back(name); - } else { - // Split the filament presets, load each of them separately. - std::vector configs(num_extruders, this->filaments.default_preset().config); - // loop through options and scatter them into configs. - for (const t_config_option_key &key : this->filaments.default_preset().config.keys()) { - const ConfigOption *other_opt = config.option(key); - if (other_opt == nullptr) - continue; - if (other_opt->is_scalar()) { - for (size_t i = 0; i < configs.size(); ++ i) - configs[i].option(key, false)->set(other_opt); - } else if (key != "compatible_printers") { - for (size_t i = 0; i < configs.size(); ++ i) - static_cast(configs[i].option(key, false))->set_at(other_opt, 0, i); - } - } - // Load the configs into this->filaments and make them active. - this->filament_presets.clear(); - for (size_t i = 0; i < configs.size(); ++ i) { - DynamicPrintConfig &cfg = configs[i]; + if (num_extruders <= 1) { // Split the "compatible_printers_condition" and "inherits" from the cummulative vectors to separate filament presets. - cfg.opt_string("compatible_printers_condition", true) = compatible_printers_condition_values[i + 1]; - cfg.opt_string("inherits", true) = inherits_values[i + 1]; - // Load all filament presets, but only select the first one in the preset dialog. - Preset *loaded = nullptr; + inherits = inherits_values[1]; + compatible_printers_condition = compatible_printers_condition_values[1]; if (is_external) - loaded = &this->filaments.load_external_preset(name_or_path, name, - (i < old_filament_profile_names->values.size()) ? old_filament_profile_names->values[i] : "", - std::move(cfg), i == 0); - else { - // Used by the config wizard when creating a custom setup. - // Therefore this block should only be called for a single extruder. - char suffix[64]; - if (i == 0) - suffix[0] = 0; - else - sprintf(suffix, "%d", i); - std::string new_name = name + suffix; - loaded = &this->filaments.load_preset(this->filaments.path_from_name(new_name), - new_name, std::move(cfg), i == 0); - loaded->save(); + this->filaments.load_external_preset(name_or_path, name, old_filament_profile_names->values.front(), config); + else + this->filaments.load_preset(this->filaments.path_from_name(name), name, config).save(); + this->filament_presets.clear(); + this->filament_presets.emplace_back(name); + } else { + // Split the filament presets, load each of them separately. + std::vector configs(num_extruders, this->filaments.default_preset().config); + // loop through options and scatter them into configs. + for (const t_config_option_key &key : this->filaments.default_preset().config.keys()) { + const ConfigOption *other_opt = config.option(key); + if (other_opt == nullptr) + continue; + if (other_opt->is_scalar()) { + for (size_t i = 0; i < configs.size(); ++ i) + configs[i].option(key, false)->set(other_opt); + } else if (key != "compatible_printers") { + for (size_t i = 0; i < configs.size(); ++ i) + static_cast(configs[i].option(key, false))->set_at(other_opt, 0, i); + } + } + // Load the configs into this->filaments and make them active. + this->filament_presets.clear(); + for (size_t i = 0; i < configs.size(); ++ i) { + DynamicPrintConfig &cfg = configs[i]; + // Split the "compatible_printers_condition" and "inherits" from the cummulative vectors to separate filament presets. + cfg.opt_string("compatible_printers_condition", true) = compatible_printers_condition_values[i + 1]; + cfg.opt_string("inherits", true) = inherits_values[i + 1]; + // Load all filament presets, but only select the first one in the preset dialog. + Preset *loaded = nullptr; + if (is_external) + loaded = &this->filaments.load_external_preset(name_or_path, name, + (i < old_filament_profile_names->values.size()) ? old_filament_profile_names->values[i] : "", + std::move(cfg), i == 0); + else { + // Used by the config wizard when creating a custom setup. + // Therefore this block should only be called for a single extruder. + char suffix[64]; + if (i == 0) + suffix[0] = 0; + else + sprintf(suffix, "%d", i); + std::string new_name = name + suffix; + loaded = &this->filaments.load_preset(this->filaments.path_from_name(new_name), + new_name, std::move(cfg), i == 0); + loaded->save(); + } + this->filament_presets.emplace_back(loaded->name); } - this->filament_presets.emplace_back(loaded->name); } - } - // 4) Load the project config values (the per extruder wipe matrix etc). - this->project_config.apply_only(config, s_project_options); + // 4) Load the project config values (the per extruder wipe matrix etc). + this->project_config.apply_only(config, s_project_options); + } this->update_compatible_with_printer(false); } @@ -691,9 +787,10 @@ void PresetBundle::load_config_file_config_bundle(const std::string &path, const collection_dst.load_preset(path, preset_name_dst, std::move(preset_src->config), activate).is_external = true; return preset_name_dst; }; - load_one(this->prints, tmp_bundle.prints, tmp_bundle.prints .get_selected_preset().name, true); - load_one(this->filaments, tmp_bundle.filaments, tmp_bundle.filaments.get_selected_preset().name, true); - load_one(this->printers, tmp_bundle.printers, tmp_bundle.printers .get_selected_preset().name, true); + load_one(this->prints, tmp_bundle.prints, tmp_bundle.prints .get_selected_preset().name, true); + load_one(this->filaments, tmp_bundle.filaments, tmp_bundle.filaments .get_selected_preset().name, true); + load_one(this->sla_materials, tmp_bundle.sla_materials, tmp_bundle.sla_materials.get_selected_preset().name, true); + load_one(this->printers, tmp_bundle.printers, tmp_bundle.printers .get_selected_preset().name, true); this->update_multi_material_filament_presets(); for (size_t i = 1; i < std::min(tmp_bundle.filament_presets.size(), this->filament_presets.size()); ++ i) this->filament_presets[i] = load_one(this->filaments, tmp_bundle.filaments, tmp_bundle.filament_presets[i], false); @@ -817,6 +914,7 @@ static void flatten_configbundle_hierarchy(boost::property_tree::ptree &tree) { flatten_configbundle_hierarchy(tree, "print"); flatten_configbundle_hierarchy(tree, "filament"); + flatten_configbundle_hierarchy(tree, "sla_material"); flatten_configbundle_hierarchy(tree, "printer"); } @@ -853,9 +951,11 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla // Parse the obsolete preset names, to be deleted when upgrading from the old configuration structure. std::vector loaded_prints; std::vector loaded_filaments; + std::vector loaded_sla_materials; std::vector loaded_printers; std::string active_print; std::vector active_filaments; + std::string active_sla_material; std::string active_printer; size_t presets_loaded = 0; for (const auto §ion : tree) { @@ -870,6 +970,10 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla presets = &this->filaments; loaded = &loaded_filaments; preset_name = section.first.substr(9); + } else if (boost::starts_with(section.first, "sla_material:")) { + presets = &this->sla_materials; + loaded = &loaded_sla_materials; + preset_name = section.first.substr(9); } else if (boost::starts_with(section.first, "printer:")) { presets = &this->printers; loaded = &loaded_printers; @@ -886,6 +990,8 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla active_filaments.resize(idx + 1, std::string()); active_filaments[idx] = kvp.second.data(); } + } else if (kvp.first == "sla_material") { + active_sla_material = kvp.second.data(); } else if (kvp.first == "printer") { active_printer = kvp.second.data(); } @@ -899,6 +1005,8 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla dst = &this->obsolete_presets.prints; else if (kvp.first == "filament") dst = &this->obsolete_presets.filaments; + else if (kvp.first == "sla_material") + dst = &this->obsolete_presets.sla_materials; else if (kvp.first == "printer") dst = &this->obsolete_presets.printers; if (dst) @@ -999,6 +1107,8 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla if ((flags & LOAD_CFGBNDLE_SYSTEM) == 0) { if (! active_print.empty()) prints.select_preset_by_name(active_print, true); + if (! active_sla_material.empty()) + sla_materials.select_preset_by_name(active_sla_material, true); if (! active_printer.empty()) printers.select_preset_by_name(active_printer, true); // Activate the first filament preset. @@ -1015,6 +1125,9 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla void PresetBundle::update_multi_material_filament_presets() { + if (printers.get_edited_preset().printer_technology() != ptFFF) + return; + // Verify and select the filament presets. auto *nozzle_diameter = static_cast(printers.get_edited_preset().config.option("nozzle_diameter")); size_t num_extruders = nozzle_diameter->values.size(); @@ -1055,36 +1168,51 @@ void PresetBundle::update_multi_material_filament_presets() void PresetBundle::update_compatible_with_printer(bool select_other_if_incompatible) { const Preset &printer_preset = this->printers.get_edited_preset(); - const std::string &prefered_print_profile = printer_preset.config.opt_string("default_print_profile"); - const std::vector &prefered_filament_profiles = printer_preset.config.option("default_filament_profile")->values; - prefered_print_profile.empty() ? - this->prints.update_compatible_with_printer(printer_preset, select_other_if_incompatible) : - this->prints.update_compatible_with_printer(printer_preset, select_other_if_incompatible, - [&prefered_print_profile](const std::string& profile_name){ return profile_name == prefered_print_profile; }); - prefered_filament_profiles.empty() ? - this->filaments.update_compatible_with_printer(printer_preset, select_other_if_incompatible) : - this->filaments.update_compatible_with_printer(printer_preset, select_other_if_incompatible, - [&prefered_filament_profiles](const std::string& profile_name) - { return std::find(prefered_filament_profiles.begin(), prefered_filament_profiles.end(), profile_name) != prefered_filament_profiles.end(); }); - if (select_other_if_incompatible) { - // Verify validity of the current filament presets. - this->filament_presets.front() = this->filaments.get_edited_preset().name; - for (size_t idx = 1; idx < this->filament_presets.size(); ++ idx) { - std::string &filament_name = this->filament_presets[idx]; - Preset *preset = this->filaments.find_preset(filament_name, false); - if (preset == nullptr || ! preset->is_compatible) { - // Pick a compatible profile. If there are prefered_filament_profiles, use them. - if (prefered_filament_profiles.empty()) - filament_name = this->filaments.first_compatible().name; - else { - const std::string &preferred = (idx < prefered_filament_profiles.size()) ? - prefered_filament_profiles[idx] : prefered_filament_profiles.front(); - filament_name = this->filaments.first_compatible( - [&preferred](const std::string& profile_name){ return profile_name == preferred; }).name; + + switch (printers.get_edited_preset().printer_technology()) { + case ptFFF: + { + const std::string &prefered_print_profile = printer_preset.config.opt_string("default_print_profile"); + const std::vector &prefered_filament_profiles = printer_preset.config.option("default_filament_profile")->values; + prefered_print_profile.empty() ? + this->prints.update_compatible_with_printer(printer_preset, select_other_if_incompatible) : + this->prints.update_compatible_with_printer(printer_preset, select_other_if_incompatible, + [&prefered_print_profile](const std::string& profile_name){ return profile_name == prefered_print_profile; }); + prefered_filament_profiles.empty() ? + this->filaments.update_compatible_with_printer(printer_preset, select_other_if_incompatible) : + this->filaments.update_compatible_with_printer(printer_preset, select_other_if_incompatible, + [&prefered_filament_profiles](const std::string& profile_name) + { return std::find(prefered_filament_profiles.begin(), prefered_filament_profiles.end(), profile_name) != prefered_filament_profiles.end(); }); + if (select_other_if_incompatible) { + // Verify validity of the current filament presets. + this->filament_presets.front() = this->filaments.get_edited_preset().name; + for (size_t idx = 1; idx < this->filament_presets.size(); ++ idx) { + std::string &filament_name = this->filament_presets[idx]; + Preset *preset = this->filaments.find_preset(filament_name, false); + if (preset == nullptr || ! preset->is_compatible) { + // Pick a compatible profile. If there are prefered_filament_profiles, use them. + if (prefered_filament_profiles.empty()) + filament_name = this->filaments.first_compatible().name; + else { + const std::string &preferred = (idx < prefered_filament_profiles.size()) ? + prefered_filament_profiles[idx] : prefered_filament_profiles.front(); + filament_name = this->filaments.first_compatible( + [&preferred](const std::string& profile_name){ return profile_name == preferred; }).name; + } } } } } + case ptSLA: + { + const std::string &prefered_print_profile = printer_preset.config.opt_string("default_print_profile"); + const std::vector &prefered_filament_profiles = printer_preset.config.option("default_filament_profile")->values; + prefered_print_profile.empty() ? + this->sla_materials.update_compatible_with_printer(printer_preset, select_other_if_incompatible) : + this->sla_materials.update_compatible_with_printer(printer_preset, select_other_if_incompatible, + [&prefered_print_profile](const std::string& profile_name){ return profile_name == prefered_print_profile; }); + } + } } void PresetBundle::export_configbundle(const std::string &path) //, const DynamicPrintConfig &settings @@ -1111,6 +1239,7 @@ void PresetBundle::export_configbundle(const std::string &path) //, const Dynami // Export the names of the active presets. c << std::endl << "[presets]" << std::endl; c << "print = " << this->prints.get_selected_preset().name << std::endl; + c << "sla_material = " << this->sla_materials.get_selected_preset().name << std::endl; c << "printer = " << this->printers.get_selected_preset().name << std::endl; for (size_t i = 0; i < this->filament_presets.size(); ++ i) { char suffix[64]; @@ -1170,7 +1299,7 @@ bool PresetBundle::parse_color(const std::string &scolor, unsigned char *rgb_out void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, wxBitmapComboBox *ui) { - if (ui == nullptr) + if (ui == nullptr || this->printers.get_edited_preset().printer_technology() == ptSLA) return; unsigned char rgb[3]; @@ -1265,6 +1394,7 @@ void PresetBundle::set_default_suppressed(bool default_suppressed) { prints.set_default_suppressed(default_suppressed); filaments.set_default_suppressed(default_suppressed); + sla_materials.set_default_suppressed(default_suppressed); printers.set_default_suppressed(default_suppressed); } diff --git a/xs/src/slic3r/GUI/PresetBundle.hpp b/xs/src/slic3r/GUI/PresetBundle.hpp index a5c5682f9..68ec534da 100644 --- a/xs/src/slic3r/GUI/PresetBundle.hpp +++ b/xs/src/slic3r/GUI/PresetBundle.hpp @@ -40,6 +40,7 @@ public: PresetCollection prints; PresetCollection filaments; + PresetCollection sla_materials; PresetCollection printers; // Filament preset names for a multi-extruder or multi-material print. // extruders.size() should be the same as printers.get_edited_preset().config.nozzle_diameter.size() @@ -57,12 +58,13 @@ public: struct ObsoletePresets { std::vector prints; std::vector filaments; + std::vector sla_materials; std::vector printers; }; ObsoletePresets obsolete_presets; bool has_defauls_only() const - { return prints.size() <= 1 && filaments.size() <= 1 && printers.size() <= 1; } + { return prints.has_defaults_only() && filaments.has_defaults_only() && printers.has_defaults_only(); } DynamicPrintConfig full_config() const; @@ -146,6 +148,9 @@ private: void load_config_file_config_bundle(const std::string &path, const boost::property_tree::ptree &tree); bool load_compatible_bitmaps(); + DynamicPrintConfig full_fff_config() const; + DynamicPrintConfig full_sla_config() const; + // Indicator, that the preset is compatible with the selected printer. wxBitmap *m_bitmapCompatible; // Indicator, that the preset is NOT compatible with the selected printer. diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp index bde4fdc34..07785e818 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -214,7 +214,7 @@ void Tab::load_initial_data() m_tt_non_system = m_presets->get_selected_preset_parent() ? &m_tt_value_unlock : &m_ttg_white_bullet_ns; } -PageShp Tab::add_options_page(const wxString& title, const std::string& icon, bool is_extruder_pages/* = false*/) +Slic3r::GUI::PageShp Tab::add_options_page(const wxString& title, const std::string& icon, bool is_extruder_pages /*= false*/) { // Index of icon in an icon list $self->{icons}. auto icon_idx = 0; @@ -238,7 +238,8 @@ PageShp Tab::add_options_page(const wxString& title, const std::string& icon, bo page->SetScrollbars(1, 1, 1, 1); page->Hide(); m_hsizer->Add(page.get(), 1, wxEXPAND | wxLEFT, 5); - if (!is_extruder_pages) + + if (!is_extruder_pages) m_pages.push_back(page); page->set_config(m_config); @@ -313,10 +314,10 @@ void Tab::update_changed_ui() if (m_postpone_update_ui) return; - const bool is_printer_type = (name() == "printer"); - auto dirty_options = m_presets->current_dirty_options(is_printer_type); - auto nonsys_options = m_presets->current_different_from_parent_options(is_printer_type); - if (is_printer_type){ + const bool deep_compare = (m_name == "printer" || m_name == "sla_material"); + auto dirty_options = m_presets->current_dirty_options(deep_compare); + auto nonsys_options = m_presets->current_different_from_parent_options(deep_compare); + if (name() == "printer"){ TabPrinter* tab = static_cast(this); if (tab->m_initial_extruders_count != tab->m_extruders_count) dirty_options.emplace_back("extruders_count"); @@ -397,7 +398,7 @@ void Tab::init_options_list() } template -void add_correct_opts_to_options_list(const std::string &opt_key, std::map& map, TabPrinter *tab, const int& value) +void add_correct_opts_to_options_list(const std::string &opt_key, std::map& map, Tab *tab, const int& value) { T *opt_cur = static_cast(tab->m_config->option(opt_key)); for (int i = 0; i < opt_cur->values.size(); i++) @@ -429,6 +430,30 @@ void TabPrinter::init_options_list() m_options_list.emplace("extruders_count", m_opt_status_value); } +void TabSLAMaterial::init_options_list() +{ + if (!m_options_list.empty()) + m_options_list.clear(); + + for (const auto opt_key : m_config->keys()) + { + if (opt_key == "compatible_printers"){ + m_options_list.emplace(opt_key, m_opt_status_value); + continue; + } + switch (m_config->option(opt_key)->type()) + { + case coInts: add_correct_opts_to_options_list(opt_key, m_options_list, this, m_opt_status_value); break; + case coBools: add_correct_opts_to_options_list(opt_key, m_options_list, this, m_opt_status_value); break; + case coFloats: add_correct_opts_to_options_list(opt_key, m_options_list, this, m_opt_status_value); break; + case coStrings: add_correct_opts_to_options_list(opt_key, m_options_list, this, m_opt_status_value); break; + case coPercents:add_correct_opts_to_options_list(opt_key, m_options_list, this, m_opt_status_value); break; + case coPoints: add_correct_opts_to_options_list(opt_key, m_options_list, this, m_opt_status_value); break; + default: m_options_list.emplace(opt_key, m_opt_status_value); break; + } + } +} + void Tab::get_sys_and_mod_flags(const std::string& opt_key, bool& sys_page, bool& modified_page) { auto opt = m_options_list.find(opt_key); @@ -649,6 +674,15 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) int val = boost::any_cast(value); event.SetInt(val); } + + if (opt_key == "printer_technology") + { + int val = boost::any_cast(value); + event.SetInt(val); + g_wxMainFrame->ProcessWindowEvent(event); + return; + } + g_wxMainFrame->ProcessWindowEvent(event); } if (opt_key == "fill_density") @@ -677,9 +711,10 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) update(); } - // Show/hide the 'purging volumes' button void Tab::update_wiping_button_visibility() { + if (get_preset_bundle()->printers.get_selected_preset().printer_technology() == ptSLA) + return; // ys_FIXME bool wipe_tower_enabled = dynamic_cast( (m_preset_bundle->prints.get_edited_preset().config ).option("wipe_tower"))->value; bool multiple_extruders = dynamic_cast((m_preset_bundle->printers.get_edited_preset().config).option("nozzle_diameter"))->values.size() > 1; bool single_extruder_mm = dynamic_cast( (m_preset_bundle->printers.get_edited_preset().config).option("single_extruder_multi_material"))->value; @@ -1007,6 +1042,9 @@ void TabPrint::reload_config(){ void TabPrint::update() { + if (get_preset_bundle()->printers.get_selected_preset().printer_technology() == ptSLA) + return; // ys_FIXME + Freeze(); double fill_density = m_config->option("fill_density")->value; @@ -1366,6 +1404,9 @@ void TabFilament::reload_config(){ void TabFilament::update() { + if (get_preset_bundle()->printers.get_selected_preset().printer_technology() == ptSLA) + return; // ys_FIXME + Freeze(); wxString text = from_u8(PresetHints::cooling_description(m_presets->get_edited_preset())); m_cooling_description_line->SetText(text); @@ -1411,6 +1452,17 @@ void TabPrinter::build() m_presets = &m_preset_bundle->printers; load_initial_data(); + m_printer_technology = m_presets->get_selected_preset().printer_technology(); + + m_presets->get_selected_preset().printer_technology() == ptSLA ? build_sla() : build_fff(); + +// on_value_change("printer_technology", m_printer_technology); // to update show/hide preset ComboBoxes +} + +void TabPrinter::build_fff() +{ + if (!m_pages.empty()) + m_pages.resize(0); // to avoid redundant memory allocation / deallocation during extruders count changing m_pages.reserve(30); @@ -1697,6 +1749,76 @@ void TabPrinter::build() update_serial_ports(); } +void TabPrinter::build_sla() +{ + if (!m_pages.empty()) + m_pages.resize(0); + auto page = add_options_page(_(L("General")), "printer_empty.png"); + auto optgroup = page->new_optgroup(_(L("Size and coordinates"))); + + Line line{ _(L("Bed shape")), "" }; + line.widget = [this](wxWindow* parent){ + auto btn = new wxButton(parent, wxID_ANY, _(L(" Set ")) + dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT); + // btn->SetFont(Slic3r::GUI::small_font); + btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("printer_empty.png")), wxBITMAP_TYPE_PNG)); + + auto sizer = new wxBoxSizer(wxHORIZONTAL); + sizer->Add(btn); + + btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e) + { + auto dlg = new BedShapeDialog(this); + dlg->build_dialog(m_config->option("bed_shape")); + if (dlg->ShowModal() == wxID_OK){ + load_key_value("bed_shape", dlg->GetValue()); + update_changed_ui(); + } + })); + + return sizer; + }; + optgroup->append_line(line, &m_colored_Label); + optgroup->append_single_option_line("max_print_height"); + + optgroup = page->new_optgroup(_(L("Display"))); + optgroup->append_single_option_line("display_width"); + optgroup->append_single_option_line("display_height"); + + auto option = optgroup->get_option("display_pixels_x"); + line = { _(option.opt.full_label), "" }; + line.append_option(option); + line.append_option(optgroup->get_option("display_pixels_y")); + optgroup->append_line(line); + + optgroup = page->new_optgroup(_(L("Corrections"))); + line = Line{ m_config->def()->get("printer_correction")->full_label, "" }; + std::vector axes{ "X", "Y", "Z" }; + int id = 0; + for (auto& axis : axes) { + auto opt = optgroup->get_option("printer_correction", id); + opt.opt.label = axis; + line.append_option(opt); + ++id; + } + optgroup->append_line(line); + + page = add_options_page(_(L("Notes")), "note.png"); + optgroup = page->new_optgroup(_(L("Notes")), 0); + option = optgroup->get_option("printer_notes"); + option.opt.full_width = true; + option.opt.height = 250; + optgroup->append_single_option_line(option); + + page = add_options_page(_(L("Dependencies")), "wrench.png"); + optgroup = page->new_optgroup(_(L("Profile dependencies"))); + line = Line{ "", "" }; + line.full_width = 1; + line.widget = [this](wxWindow* parent) { + return description_line_widget(parent, &m_parent_preset_description_line); + }; + optgroup->append_line(line); +} + void TabPrinter::update_serial_ports(){ Field *field = get_field("serial_port"); Choice *choice = static_cast(field); @@ -1888,7 +2010,38 @@ void TabPrinter::on_preset_loaded() extruders_count_changed(extruders_count); } -void TabPrinter::update(){ +void TabPrinter::update_pages() +{ + // update m_pages ONLY if printer technology is changed + if (m_presets->get_edited_preset().printer_technology() == m_printer_technology) + return; + + // hide all old pages + for (auto& el : m_pages) + el.get()->Hide(); + + // set m_pages to m_pages_(technology before changing) + m_printer_technology == ptFFF ? m_pages.swap(m_pages_fff) : m_pages.swap(m_pages_sla); + + // build Tab according to the technology, if it's not exist jet OR + // set m_pages_(technology after changing) to m_pages + if (m_presets->get_edited_preset().printer_technology() == ptFFF) + m_pages_fff.empty() ? build_fff() : m_pages.swap(m_pages_fff); + else + m_pages_sla.empty() ? build_sla() : m_pages.swap(m_pages_sla); + + rebuild_page_tree(true); + + on_value_change("printer_technology", m_presets->get_edited_preset().printer_technology()); // to update show/hide preset ComboBoxes +} + +void TabPrinter::update() +{ + m_presets->get_edited_preset().printer_technology() == ptFFF ? update_fff() : update_sla(); +} + +void TabPrinter::update_fff() +{ Freeze(); bool en; @@ -1991,20 +2144,25 @@ void TabPrinter::update(){ Thaw(); } +void TabPrinter::update_sla(){ ; } + // Initialize the UI from the current preset void Tab::load_current_preset() { auto preset = m_presets->get_edited_preset(); (preset.is_default || preset.is_system) ? 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(); + + update(); + // For the printer profile, generate the extruder pages. + if (preset.printer_technology() == ptFFF) + on_preset_loaded(); + // Reload preset pages with the new configuration values. + reload_config(); + m_bmp_non_system = m_presets->get_selected_preset_parent() ? &m_bmp_value_unlock : &m_bmp_white_bullet; m_ttg_non_system = m_presets->get_selected_preset_parent() ? &m_ttg_value_unlock : &m_ttg_white_bullet_ns; - m_tt_non_system = m_presets->get_selected_preset_parent() ? &m_tt_value_unlock : &m_ttg_white_bullet_ns; + m_tt_non_system = m_presets->get_selected_preset_parent() ? &m_tt_value_unlock : &m_ttg_white_bullet_ns; m_undo_to_sys_btn->Enable(!preset.is_default); @@ -2016,7 +2174,28 @@ void Tab::load_current_preset() // checking out if this Tab exists till this moment if (!checked_tab(this)) return; - update_tab_ui(); + update_tab_ui(); + + // update show/hide tabs + if (m_name == "printer"){ + PrinterTechnology& printer_technology = m_presets->get_edited_preset().printer_technology(); + if (printer_technology != static_cast(this)->m_printer_technology) + { + for (auto& tab : get_preset_tabs()){ + if (tab.technology != printer_technology) + { + int page_id = get_tab_panel()->FindPage(tab.panel); + get_tab_panel()->GetPage(page_id)->Show(false); + get_tab_panel()->RemovePage(page_id); + } + else + get_tab_panel()->InsertPage(get_tab_panel()->FindPage(this), tab.panel, tab.panel->title()); + } + + static_cast(this)->m_printer_technology = printer_technology; + } + } + on_presets_changed(); if (name() == "print") @@ -2034,7 +2213,7 @@ void Tab::load_current_preset() } //Regerenerate content of the page tree. -void Tab::rebuild_page_tree() +void Tab::rebuild_page_tree(bool tree_sel_change_event /*= false*/) { Freeze(); // get label of the currently selected item @@ -2049,9 +2228,9 @@ void Tab::rebuild_page_tree() m_treectrl->SetItemTextColour(itemId, p->get_item_colour()); if (p->title() == selected) { if (!(p->title() == _(L("Machine limits")) || p->title() == _(L("Single extruder MM setup")))) // These Pages have to be updated inside OnTreeSelChange - m_disable_tree_sel_changed_event = 1; + m_disable_tree_sel_changed_event = !tree_sel_change_event; m_treectrl->SelectItem(itemId); - m_disable_tree_sel_changed_event = 0; + m_disable_tree_sel_changed_event = false; have_selection = 1; } } @@ -2066,48 +2245,53 @@ void Tab::rebuild_page_tree() // 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(const std::string& preset_name /*= ""*/) +void Tab::select_preset(std::string preset_name /*= ""*/) { - std::string name = preset_name; - 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; + if (preset_name.empty()) + preset_name = m_presets->default_preset().name; + auto current_dirty = m_presets->current_is_dirty(); + auto printer_tab = m_presets->name() == "printer"; + auto canceled = false; m_reload_dependent_tabs = {}; - if (!force && current_dirty && !may_discard_current_dirty_preset()) { + if (current_dirty && !may_discard_current_dirty_preset()) { canceled = true; - } else if(printer_tab) { + } 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); + // + // With the introduction of the SLA printer types, we need to support switching between + // the FFF and SLA printers. + const Preset &new_printer_preset = *m_presets->find_preset(preset_name, true); + PrinterTechnology old_printer_technology = m_presets->get_edited_preset().printer_technology(); + PrinterTechnology new_printer_technology = new_printer_preset.printer_technology(); + struct PresetUpdate { + std::string name; + PresetCollection *presets; + PrinterTechnology technology; + bool old_preset_dirty; + bool new_preset_compatible; + }; + std::vector updates = { + { "print", &m_preset_bundle->prints, ptFFF }, + { "filament", &m_preset_bundle->filaments, ptFFF }, + { "sla_material", &m_preset_bundle->sla_materials, ptSLA } + }; + for (PresetUpdate &pu : updates) { + pu.old_preset_dirty = (old_printer_technology == pu.technology) && pu.presets->current_is_dirty(); + pu.new_preset_compatible = (new_printer_technology == pu.technology) && pu.presets->get_edited_preset().is_compatible_with_printer(new_printer_preset); + if (! canceled) + canceled = pu.old_preset_dirty && ! pu.new_preset_compatible && ! may_discard_current_dirty_preset(pu.presets, preset_name); } - if (!canceled) { - if (!print_preset_compatible) { + if (! canceled) { + for (PresetUpdate &pu : updates) { // 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 (pu.technology == new_printer_technology) + m_reload_dependent_tabs.emplace_back(pu.name); + if (pu.old_preset_dirty) + pu.presets->discard_current_changes(); } } } @@ -2116,19 +2300,20 @@ void Tab::select_preset(const std::string& preset_name /*= ""*/) // 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); + } else { + if (current_dirty) + m_presets->discard_current_changes() ; + m_presets->select_preset_by_name(preset_name, false); // 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. + if (printer_tab) + static_cast(this)->update_pages(); load_current_preset(); } - } // If the current preset is dirty, the user is asked whether the changes may be discarded. @@ -2770,5 +2955,71 @@ void SavePresetWindow::accept() } } +void TabSLAMaterial::build() +{ + m_presets = &m_preset_bundle->sla_materials; + load_initial_data(); + + auto page = add_options_page(_(L("Material")), "package_green.png"); + + auto optgroup = page->new_optgroup(_(L("Layers"))); + optgroup->append_single_option_line("layer_height"); + optgroup->append_single_option_line("initial_layer_height"); + + optgroup = page->new_optgroup(_(L("Exposure"))); + optgroup->append_single_option_line("exposure_time"); + optgroup->append_single_option_line("initial_exposure_time"); + + optgroup = page->new_optgroup(_(L("Corrections"))); + optgroup->label_width = 190; + std::vector corrections = { "material_correction_printing", "material_correction_curing" }; + std::vector axes{ "X", "Y", "Z" }; + for (auto& opt_key : corrections){ + auto line = Line{ m_config->def()->get(opt_key)->full_label, "" }; + int id = 0; + for (auto& axis : axes) { + auto opt = optgroup->get_option(opt_key, id); + opt.opt.label = axis; + opt.opt.width = 60; + line.append_option(opt); + ++id; + } + optgroup->append_line(line); + } + + page = add_options_page(_(L("Notes")), "note.png"); + optgroup = page->new_optgroup(_(L("Notes")), 0); + optgroup->label_width = 0; + Option option = optgroup->get_option("material_notes"); + option.opt.full_width = true; + option.opt.height = 250; + optgroup->append_single_option_line(option); + + page = add_options_page(_(L("Dependencies")), "wrench.png"); + optgroup = page->new_optgroup(_(L("Profile dependencies"))); + auto line = Line { _(L("Compatible printers")), "" }; + line.widget = [this](wxWindow* parent){ + return compatible_printers_widget(parent, &m_compatible_printers_checkbox, &m_compatible_printers_btn); + }; + optgroup->append_line(line, &m_colored_Label); + + option = optgroup->get_option("compatible_printers_condition"); + option.opt.full_width = true; + optgroup->append_single_option_line(option); + + line = Line{ "", "" }; + line.full_width = 1; + line.widget = [this](wxWindow* parent) { + return description_line_widget(parent, &m_parent_preset_description_line); + }; + optgroup->append_line(line); +} + +void TabSLAMaterial::update() +{ + if (get_preset_bundle()->printers.get_selected_preset().printer_technology() == ptFFF) + return; // ys_FIXME +} + } // GUI } // Slic3r diff --git a/xs/src/slic3r/GUI/Tab.hpp b/xs/src/slic3r/GUI/Tab.hpp index 230fe659e..353277d64 100644 --- a/xs/src/slic3r/GUI/Tab.hpp +++ b/xs/src/slic3r/GUI/Tab.hpp @@ -218,8 +218,8 @@ public: void create_preset_tab(PresetBundle *preset_bundle); void load_current_preset(); - void rebuild_page_tree(); - void select_preset(const std::string& preset_name = ""); + void rebuild_page_tree(bool tree_sel_change_event = false); + void select_preset(std::string preset_name = ""); bool may_discard_current_dirty_preset(PresetCollection* presets = nullptr, const std::string& new_printer_name = ""); wxSizer* compatible_printers_widget(wxWindow* parent, wxCheckBox** checkbox, wxButton** btn); @@ -319,6 +319,9 @@ class TabPrinter : public Tab bool m_use_silent_mode = false; void append_option_line(ConfigOptionsGroupShp optgroup, const std::string opt_key); bool m_rebuild_kinematics_page = false; + + std::vector m_pages_fff; + std::vector m_pages_sla; public: wxButton* m_serial_test_btn; wxButton* m_print_host_test_btn; @@ -329,12 +332,19 @@ public: size_t m_initial_extruders_count; size_t m_sys_extruders_count; + PrinterTechnology m_printer_technology = ptFFF; + TabPrinter() {} TabPrinter(wxNotebook* parent, bool no_controller) : Tab(parent, _(L("Printer Settings")), "printer", no_controller) {} ~TabPrinter(){} void build() override; - void update() override; + void build_fff(); + void build_sla(); + void update() override; + void update_fff(); + void update_sla(); + void update_pages(); // update m_pages according to printer technology void update_serial_ports(); void extruders_count_changed(size_t extruders_count); PageShp build_kinematics_page(); @@ -343,6 +353,19 @@ public: void init_options_list() override; }; +class TabSLAMaterial : public Tab +{ +public: + TabSLAMaterial() {} + TabSLAMaterial(wxNotebook* parent, bool no_controller) : + Tab(parent, _(L("SLA Material Settings")), "sla_material", no_controller) {} + ~TabSLAMaterial(){} + + void build() override; + void update() override; + void init_options_list() override; +}; + class SavePresetWindow :public wxDialog { public: diff --git a/xs/src/slic3r/Utils/PresetUpdater.cpp b/xs/src/slic3r/Utils/PresetUpdater.cpp index 6e23ab421..2e423dc5e 100644 --- a/xs/src/slic3r/Utils/PresetUpdater.cpp +++ b/xs/src/slic3r/Utils/PresetUpdater.cpp @@ -447,6 +447,7 @@ void PresetUpdater::priv::perform_updates(Updates &&updates, bool snapshot) cons for (const auto &name : bundle.obsolete_presets.prints) { obsolete_remover("print", name); } for (const auto &name : bundle.obsolete_presets.filaments) { obsolete_remover("filament", name); } + for (const auto &name : bundle.obsolete_presets.filaments) { obsolete_remover("sla_material", name); } for (const auto &name : bundle.obsolete_presets.printers) { obsolete_remover("printer", name); } } } diff --git a/xs/xsp/GUI_Preset.xsp b/xs/xsp/GUI_Preset.xsp index 2c63db10c..99d23a142 100644 --- a/xs/xsp/GUI_Preset.xsp +++ b/xs/xsp/GUI_Preset.xsp @@ -32,7 +32,6 @@ %name{Slic3r::GUI::PresetCollection} class PresetCollection { Ref preset(size_t idx) %code%{ RETVAL = &THIS->preset(idx); %}; - Ref default_preset() %code%{ RETVAL = &THIS->default_preset(); %}; size_t size() const; size_t num_visible() const; std::string name() const; @@ -133,6 +132,7 @@ PresetCollection::arrayref() Ref print() %code%{ RETVAL = &THIS->prints; %}; Ref filament() %code%{ RETVAL = &THIS->filaments; %}; + Ref sla_material() %code%{ RETVAL = &THIS->sla_materials; %}; Ref printer() %code%{ RETVAL = &THIS->printers; %}; Ref project_config() %code%{ RETVAL = &THIS->project_config; %};