diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index c7e0c5040..8d3d6b5f2 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -731,8 +731,9 @@ static bool profile_print_params_same(const DynamicPrintConfig &cfg_old, const D // Load a preset from an already parsed config file, insert it into the sorted sequence of presets // and select it, losing previous modifications. -// In case -Preset& PresetCollection::load_external_preset( +// Only a single profile could be edited at at the same time, which introduces complexity when loading +// filament profiles for multi-extruder printers. +std::pair PresetCollection::load_external_preset( // Path to the profile source file (a G-code, an AMF or 3MF file, a config file) const std::string &path, // Name of the profile, derived from the source file name. @@ -742,14 +743,23 @@ Preset& PresetCollection::load_external_preset( // Config to initialize the preset from. const DynamicPrintConfig &config, // Select the preset after loading? - bool select) + LoadAndSelect select) { // Load the preset over a default preset, so that the missing fields are filled in from the default preset. DynamicPrintConfig cfg(this->default_preset_for(config).config); cfg.apply_only(config, cfg.keys(), true); + std::string &inherits = Preset::inherits(cfg); + if (select == LoadAndSelect::Never) { + // Some filament profile has been selected and modified already. + // Check whether this profile is equal to the modified edited profile. + const Preset &edited = this->get_edited_preset(); + if ((edited.name == original_name || edited.name == inherits) && profile_print_params_same(edited.config, cfg)) + // Just point to that already selected and edited profile. + return std::make_pair(&(*this->find_preset_internal(edited.name)), false); + } // Is there a preset already loaded with the name stored inside the config? - std::deque::iterator it = this->find_preset_internal(original_name); - bool found = it != m_presets.end() && it->name == original_name; + std::deque::iterator it = this->find_preset_internal(original_name); + bool found = it != m_presets.end() && it->name == original_name; if (! found) { // Try to match the original_name against the "renamed_from" profile names of loaded system profiles. it = this->find_preset_renamed(original_name); @@ -757,19 +767,40 @@ Preset& PresetCollection::load_external_preset( } if (found && profile_print_params_same(it->config, cfg)) { // The preset exists and it matches the values stored inside config. - if (select) + if (select == LoadAndSelect::Always) this->select_preset(it - m_presets.begin()); - return *it; + return std::make_pair(&(*it), false); } - // Update the "inherits" field. - std::string &inherits = Preset::inherits(cfg); - if (found && inherits.empty()) { - // There is a profile with the same name already loaded. Should we update the "inherits" field? - if (it->vendor == nullptr) - inherits = it->inherits(); - else - inherits = it->name; + if (! found && select != LoadAndSelect::Never && ! inherits.empty()) { + // Try to use a system profile as a base to select the system profile + // and override its settings with the loaded ones. + assert(it == m_presets.end()); + it = this->find_preset_internal(inherits); + found = it != m_presets.end() && it->name == inherits; + if (found && profile_print_params_same(it->config, cfg)) { + // The system preset exists and it matches the values stored inside config. + if (select == LoadAndSelect::Always) + this->select_preset(it - m_presets.begin()); + return std::make_pair(&(*it), false); + } } + if (found) { + if (select != LoadAndSelect::Never) { + // Select the existing preset and override it with new values, so that + // the differences will be shown in the preset editor against the referenced profile. + this->select_preset(it - m_presets.begin()); + this->get_edited_preset().config.apply(config); + this->update_dirty(); + assert(this->get_edited_preset().is_dirty); + return std::make_pair(&(*it), this->get_edited_preset().is_dirty); + } + if (inherits.empty()) { + // Update the "inherits" field. + // There is a profile with the same name already loaded. Should we update the "inherits" field? + inherits = it->vendor ? it->name : it->inherits(); + } + } + // The external preset does not match an internal preset, load the external preset. std::string new_name; for (size_t idx = 0;; ++ idx) { @@ -790,19 +821,19 @@ Preset& PresetCollection::load_external_preset( break; if (profile_print_params_same(it->config, cfg)) { // The preset exists and it matches the values stored inside config. - if (select) + if (select == LoadAndSelect::Always) this->select_preset(it - m_presets.begin()); - return *it; + return std::make_pair(&(*it), false); } // Form another profile name. } // Insert a new profile. - Preset &preset = this->load_preset(path, new_name, std::move(cfg), select); + Preset &preset = this->load_preset(path, new_name, std::move(cfg), select == LoadAndSelect::Always); preset.is_external = true; if (&this->get_selected_preset() == &preset) this->get_edited_preset().is_external = true; - return preset; + return std::make_pair(&preset, false); } Preset& PresetCollection::load_preset(const std::string &path, const std::string &name, DynamicPrintConfig &&config, bool select) diff --git a/src/libslic3r/Preset.hpp b/src/libslic3r/Preset.hpp index 6409eee7c..c54dd3fd8 100644 --- a/src/libslic3r/Preset.hpp +++ b/src/libslic3r/Preset.hpp @@ -287,7 +287,18 @@ public: Preset& load_preset(const std::string &path, const std::string &name, const DynamicPrintConfig &config, bool select = true); Preset& load_preset(const std::string &path, const std::string &name, DynamicPrintConfig &&config, bool select = true); - Preset& load_external_preset( + // Returns a loaded preset, returns true if an existing preset was selected AND modified from config. + // In that case the successive filament loaded for a multi material printer should not be modified, but + // an external preset should be created instead. + enum class LoadAndSelect { + // Never select + Never, + // Always select + Always, + // Select a profile only if it was modified. + OnlyIfModified, + }; + std::pair load_external_preset( // Path to the profile source file (a G-code, an AMF or 3MF file, a config file) const std::string &path, // Name of the profile, derived from the source file name. @@ -297,7 +308,7 @@ public: // Config to initialize the preset from. const DynamicPrintConfig &config, // Select the preset after loading? - bool select = true); + LoadAndSelect select = LoadAndSelect::Always); // Save the preset under a new name. If the name is different from the old one, // a new preset is stored into the list of presets. diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index 44df000c3..b020f874e 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -49,7 +49,7 @@ PresetBundle::PresetBundle() : // initialized based on PrintConfigDef(), but to empty values (zeros, empty vectors, empty strings). // // "compatible_printers", "compatible_printers_condition", "inherits", - // "print_settings_id", "filament_settings_id", "printer_settings_id", + // "print_settings_id", "filament_settings_id", "printer_settings_id", "printer_settings_id" // "printer_vendor", "printer_model", "printer_variant", "default_print_profile", "default_filament_profile" // Create the ID config keys, as they are not part of the Static print config classes. @@ -586,6 +586,7 @@ DynamicPrintConfig PresetBundle::full_fff_config() const out.option("print_settings_id", true)->value = this->prints.get_selected_preset_name(); out.option("filament_settings_id", true)->values = this->filament_presets; out.option("printer_settings_id", true)->value = this->printers.get_selected_preset_name(); + out.option("physical_printer_settings_id", true)->value = this->physical_printers.get_selected_printer_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. @@ -637,6 +638,7 @@ DynamicPrintConfig PresetBundle::full_sla_config() const out.option("sla_print_settings_id", true)->value = this->sla_prints.get_selected_preset_name(); 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(); + out.option("physical_printer_settings_id", true)->value = this->physical_printers.get_selected_printer_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. @@ -712,6 +714,7 @@ void PresetBundle::load_config_file(const std::string &path) } // Load a config file from a boost property_tree. This is a private method called from load_config_file. +// is_external == false on if called from ConfigWizard void PresetBundle::load_config_file_config(const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config) { PrinterTechnology printer_technology = Preset::printer_technology(config); @@ -798,14 +801,17 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool compatible_prints_condition = compatible_prints_condition_values.front(); Preset *loaded = nullptr; if (is_external) { - loaded = &this->filaments.load_external_preset(name_or_path, name, old_filament_profile_names->values.front(), config); + auto [aloaded, modified] = this->filaments.load_external_preset(name_or_path, name, old_filament_profile_names->values.front(), config); + loaded = aloaded; } else { - loaded = &this->filaments.load_preset(this->filaments.path_from_name(name), name, config); + // called from Config Wizard. + loaded= &this->filaments.load_preset(this->filaments.path_from_name(name), name, config); loaded->save(); } this->filament_presets.clear(); this->filament_presets.emplace_back(loaded->name); } else { + assert(is_external); // 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. @@ -826,6 +832,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool // To avoid incorrect selection of the first filament preset (means a value of Preset->m_idx_selected) // in a case when next added preset take a place of previosly selected preset, // we should add presets from last to first + bool any_modified = false; for (int i = (int)configs.size()-1; i >= 0; i--) { DynamicPrintConfig &cfg = configs[i]; // Split the "compatible_printers_condition" and "inherits" from the cummulative vectors to separate filament presets. @@ -833,24 +840,15 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool cfg.opt_string("compatible_prints_condition", true) = compatible_prints_condition_values[i]; 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 < int(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", (int)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(); - } + auto [loaded, modified] = this->filaments.load_external_preset(name_or_path, name, + (i < int(old_filament_profile_names->values.size())) ? old_filament_profile_names->values[i] : "", + std::move(cfg), + i == 0 ? + PresetCollection::LoadAndSelect::Always : + any_modified ? + PresetCollection::LoadAndSelect::Never : + PresetCollection::LoadAndSelect::OnlyIfModified); + any_modified |= modified; this->filament_presets[i] = loaded->name; } } @@ -864,10 +862,23 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool load_preset(this->sla_materials, 1, "sla_material_settings_id"); load_preset(this->printers, 2, "printer_settings_id"); break; - default: break; + default: + break; } this->update_compatible(PresetSelectCompatibleType::Never); + + const std::string &physical_printer = config.option("physical_printer_settings_id", true)->value; + if (this->printers.get_edited_preset().is_external || physical_printer.empty()) { + this->physical_printers.unselect_printer(); + } else { + // Activate the physical printer profile if possible. + PhysicalPrinter *pp = this->physical_printers.find_printer(physical_printer, true); + if (pp != nullptr && std::find(pp->preset_names.begin(), pp->preset_names.end(), this->printers.get_edited_preset().name) != pp->preset_names.end()) + this->physical_printers.select_printer(*pp); + else + this->physical_printers.unselect_printer(); + } } // Load the active configuration of a config bundle from a boost property_tree. This is a private method called from load_config_file. diff --git a/src/libslic3r/PresetBundle.hpp b/src/libslic3r/PresetBundle.hpp index 609e25e2c..5d7cc84ba 100644 --- a/src/libslic3r/PresetBundle.hpp +++ b/src/libslic3r/PresetBundle.hpp @@ -70,7 +70,7 @@ public: // Load user configuration and store it into the user profiles. // This method is called by the configuration wizard. - void load_config(const std::string &name, DynamicPrintConfig config) + void load_config_from_wizard(const std::string &name, DynamicPrintConfig config) { this->load_config_file_config(name, false, std::move(config)); } // Load configuration that comes from a model file containing configuration, such as 3MF et al. diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index a8d4b2ea0..e71890852 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -596,9 +596,10 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ #endif /* _DEBUG */ // Normalize the config. - new_full_config.option("print_settings_id", true); - new_full_config.option("filament_settings_id", true); - new_full_config.option("printer_settings_id", true); + new_full_config.option("print_settings_id", true); + new_full_config.option("filament_settings_id", true); + new_full_config.option("printer_settings_id", true); + new_full_config.option("physical_printer_settings_id", true); new_full_config.normalize_fdm(); // Find modified keys of the various configs. Resolve overrides extruder retract values by filament profiles. @@ -627,9 +628,10 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ if (! full_config_diff.empty()) { update_apply_status(this->invalidate_step(psGCodeExport)); // Set the profile aliases for the PrintBase::output_filename() - m_placeholder_parser.set("print_preset", new_full_config.option("print_settings_id")->clone()); - m_placeholder_parser.set("filament_preset", new_full_config.option("filament_settings_id")->clone()); - m_placeholder_parser.set("printer_preset", new_full_config.option("printer_settings_id")->clone()); + m_placeholder_parser.set("print_preset", new_full_config.option("print_settings_id")->clone()); + m_placeholder_parser.set("filament_preset", new_full_config.option("filament_settings_id")->clone()); + m_placeholder_parser.set("printer_preset", new_full_config.option("printer_settings_id")->clone()); + m_placeholder_parser.set("physical_printer_preset", new_full_config.option("physical_printer_settings_id")->clone()); // We want the filament overrides to be applied over their respective extruder parameters by the PlaceholderParser. // see "Placeholders do not respect filament overrides." GH issue #3649 m_placeholder_parser.apply_config(filament_overrides); diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index fe64e8aa6..42edcafde 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1680,6 +1680,10 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionString("")); def->cli = ConfigOptionDef::nocli; + def = this->add("physical_printer_settings_id", coString); + def->set_default_value(new ConfigOptionString("")); + def->cli = ConfigOptionDef::nocli; + def = this->add("raft_layers", coInt); def->label = L("Raft layers"); def->category = L("Support material"); diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index f36e48aa6..65fac73f3 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -193,9 +193,10 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con #endif /* _DEBUG */ // Normalize the config. - config.option("sla_print_settings_id", true); - config.option("sla_material_settings_id", true); - config.option("printer_settings_id", true); + config.option("sla_print_settings_id", true); + config.option("sla_material_settings_id", true); + config.option("printer_settings_id", true); + config.option("physical_printer_settings_id", true); // Collect changes to print config. t_config_option_keys print_diff = m_print_config.diff(config); t_config_option_keys printer_diff = m_printer_config.diff(config); @@ -228,9 +229,10 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con // update_apply_status(this->invalidate_step(slapsRasterize)); m_placeholder_parser.apply_config(config); // Set the profile aliases for the PrintBase::output_filename() - m_placeholder_parser.set("print_preset", config.option("sla_print_settings_id")->clone()); - m_placeholder_parser.set("material_preset", config.option("sla_material_settings_id")->clone()); - m_placeholder_parser.set("printer_preset", config.option("printer_settings_id")->clone()); + m_placeholder_parser.set("print_preset", config.option("sla_print_settings_id")->clone()); + m_placeholder_parser.set("material_preset", config.option("sla_material_settings_id")->clone()); + m_placeholder_parser.set("printer_preset", config.option("printer_settings_id")->clone()); + m_placeholder_parser.set("physical_printer_preset", config.option("physical_printer_settings_id")->clone()); } // It is also safe to change m_config now after this->invalidate_state_by_config_options() call. diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 18e89f114..c0bfbe141 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -2457,7 +2457,7 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese page_temps->apply_custom_config(*custom_config); const std::string profile_name = page_custom->profile_name(); - preset_bundle->load_config(profile_name, *custom_config); + preset_bundle->load_config_from_wizard(profile_name, *custom_config); } // Update the selections from the compatibilty.