From 1175dc95f688a8b17e75a7cdf5ef1b472905bede Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 26 Jun 2018 10:50:50 +0200 Subject: Storing and recovering the "compatible_printers_condition" and "inherits" fields from / to the AMF/3MF/Config files. The "compatible_printers_condition" are collected over all active profiles (one print, possibly multiple filament, and one printer profile) into a single vector. --- xs/src/libslic3r/Config.cpp | 5 +- xs/src/libslic3r/GCode.cpp | 5 +- xs/src/libslic3r/PrintConfig.cpp | 14 +++-- xs/src/slic3r/GUI/Preset.cpp | 32 +++++------ xs/src/slic3r/GUI/PresetBundle.cpp | 105 +++++++++++++++++++++++++++++++------ xs/src/slic3r/GUI/Tab.cpp | 8 +-- 6 files changed, 128 insertions(+), 41 deletions(-) (limited to 'xs') diff --git a/xs/src/libslic3r/Config.cpp b/xs/src/libslic3r/Config.cpp index 8c1349e08..4218fbcf9 100644 --- a/xs/src/libslic3r/Config.cpp +++ b/xs/src/libslic3r/Config.cpp @@ -188,7 +188,10 @@ void ConfigBase::apply_only(const ConfigBase &other, const t_config_option_keys throw UnknownOptionException(opt_key); } const ConfigOption *other_opt = other.option(opt_key); - if (other_opt != nullptr) + if (other_opt == nullptr) { + // The key was not found in the source config, therefore it will not be initialized! +// printf("Not found, therefore not initialized: %s\n", opt_key.c_str()); + } else my_opt->set(other_opt); } } diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 009493113..16f8ac736 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -1419,7 +1419,10 @@ void GCode::append_full_config(const Print& print, std::string& str) str += "; " + key + " = " + cfg->serialize(key) + "\n"; } const DynamicConfig &full_config = print.placeholder_parser.config(); - for (const char *key : { "print_settings_id", "filament_settings_id", "printer_settings_id" }) + for (const char *key : { + "print_settings_id", "filament_settings_id", "printer_settings_id", + "printer_model", "printer_variant", "default_print_profile", "default_filament_profile", + "compatible_printers_condition", "inherits" }) str += std::string("; ") + key + " = " + full_config.serialize(key) + "\n"; } diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 486e6fe18..02961493e 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -147,12 +147,15 @@ PrintConfigDef::PrintConfigDef() def->label = L("Compatible printers"); def->default_value = new ConfigOptionStrings(); - def = this->add("compatible_printers_condition", coString); + // The following value is defined as a vector of strings, so it could + // collect the "inherits" values over the print and filaments profiles + // when storing into a project file (AMF, 3MF, Config ...) + def = this->add("compatible_printers_condition", coStrings); def->label = L("Compatible printers condition"); def->tooltip = L("A boolean expression using the configuration values of an active printer profile. " "If this expression evaluates to true, this profile is considered compatible " "with the active printer profile."); - def->default_value = new ConfigOptionString(); + def->default_value = new ConfigOptionStrings { "" }; def = this->add("complete_objects", coBool); def->label = L("Complete individual objects"); @@ -819,12 +822,15 @@ PrintConfigDef::PrintConfigDef() def->min = 0; def->default_value = new ConfigOptionFloat(80); - def = this->add("inherits", coString); + // The following value is defined as a vector of strings, so it could + // collect the "inherits" values over the print and filaments profiles + // when storing into a project file (AMF, 3MF, Config ...) + def = this->add("inherits", coStrings); def->label = L("Inherits profile"); def->tooltip = L("Name of the profile, from which this profile inherits."); def->full_width = true; def->height = 50; - def->default_value = new ConfigOptionString(""); + def->default_value = new ConfigOptionStrings { "" }; def = this->add("interface_shells", coBool); def->label = L("Interface shells"); diff --git a/xs/src/slic3r/GUI/Preset.cpp b/xs/src/slic3r/GUI/Preset.cpp index d9774bfc2..120e1c9a7 100644 --- a/xs/src/slic3r/GUI/Preset.cpp +++ b/xs/src/slic3r/GUI/Preset.cpp @@ -180,7 +180,7 @@ void Preset::normalize(DynamicPrintConfig &config) size_t n = (nozzle_diameter == nullptr) ? 1 : nozzle_diameter->values.size(); const auto &defaults = FullPrintConfig::defaults(); for (const std::string &key : Preset::filament_options()) { - if (key == "compatible_printers") + if (key == "compatible_printers" || key == "compatible_printers_condition" || key == "inherits") continue; auto *opt = config.option(key, false); assert(opt != nullptr); @@ -234,12 +234,12 @@ std::string Preset::label() const bool Preset::is_compatible_with_printer(const Preset &active_printer, const DynamicPrintConfig *extra_config) const { - auto *condition = dynamic_cast(this->config.option("compatible_printers_condition")); + auto *condition = dynamic_cast(this->config.option("compatible_printers_condition")); auto *compatible_printers = dynamic_cast(this->config.option("compatible_printers")); bool has_compatible_printers = compatible_printers != nullptr && ! compatible_printers->values.empty(); - if (! has_compatible_printers && condition != nullptr && ! condition->value.empty()) { + if (! has_compatible_printers && condition != nullptr && ! condition->values.empty() && ! condition->values.front().empty()) { try { - return PlaceholderParser::evaluate_boolean_expression(condition->value, active_printer.config, extra_config); + return PlaceholderParser::evaluate_boolean_expression(condition->values.front(), active_printer.config, extra_config); } catch (const std::runtime_error &err) { //FIXME in case of an error, return "compatible with everything". printf("Preset::is_compatible_with_printer - parsing error of compatible_printers_condition %s:\n%s\n", active_printer.name.c_str(), err.what()); @@ -449,9 +449,8 @@ Preset& PresetCollection::load_external_preset( std::deque::iterator it = original_name.empty() ? m_presets.end() : this->find_preset_internal(original_name); if (it != m_presets.end()) { t_config_option_keys diff = it->config.diff(cfg); - //FIXME Following keys are either not updated in the preset (the *_settings_id), - // or not stored into the AMF/3MF/Config file, therefore they will most likely not match. - // Ignore these differences for now. + // Following keys are used by the UI, not by the slicing core, therefore they are not important + // when comparing profiles for equality. Ignore them. for (const char *key : { "compatible_printers", "compatible_printers_condition", "inherits", "print_settings_id", "filament_settings_id", "printer_settings_id", "printer_model", "printer_variant", "default_print_profile", "default_filament_profile" }) @@ -503,7 +502,10 @@ void PresetCollection::save_current_preset(const std::string &new_name) } else { // Creating a new preset. Preset &preset = *m_presets.insert(it, m_edited_preset); - std::string &inherits = preset.config.opt_string("inherits", true); + ConfigOptionStrings *opt_inherits = preset.config.option("inherits", true); + if (opt_inherits->values.empty()) + opt_inherits->values.emplace_back(std::string()); + std::string &inherits = opt_inherits->values.front(); std::string old_name = preset.name; preset.name = new_name; preset.file = this->path_from_name(new_name); @@ -556,20 +558,20 @@ bool PresetCollection::load_bitmap_default(const std::string &file_name) const Preset* PresetCollection::get_selected_preset_parent() const { - auto *inherits = dynamic_cast(this->get_edited_preset().config.option("inherits")); - if (inherits == nullptr || inherits->value.empty()) - return this->get_selected_preset().is_system ? &this->get_selected_preset() : nullptr; // nullptr; - const Preset* preset = this->find_preset(inherits->value, false); + auto *inherits = dynamic_cast(this->get_edited_preset().config.option("inherits")); + if (inherits == nullptr || inherits->values.empty() || inherits->values.front().empty()) + return this->get_selected_preset().is_system ? &this->get_selected_preset() : nullptr; + const Preset* preset = this->find_preset(inherits->values.front(), false); return (preset == nullptr || preset->is_default || preset->is_external) ? nullptr : preset; } const Preset* PresetCollection::get_preset_parent(const Preset& child) const { - auto *inherits = dynamic_cast(child.config.option("inherits")); - if (inherits == nullptr || inherits->value.empty()) + auto *inherits = dynamic_cast(child.config.option("inherits")); + if (inherits == nullptr || inherits->values.empty() || inherits->values.front().empty()) // return this->get_selected_preset().is_system ? &this->get_selected_preset() : nullptr; return nullptr; - const Preset* preset = this->find_preset(inherits->value, false); + const Preset* preset = this->find_preset(inherits->values.front(), false); return (preset == nullptr/* || preset->is_default */|| preset->is_external) ? nullptr : preset; } diff --git a/xs/src/slic3r/GUI/PresetBundle.cpp b/xs/src/slic3r/GUI/PresetBundle.cpp index 8f417fcfe..147975f16 100644 --- a/xs/src/slic3r/GUI/PresetBundle.cpp +++ b/xs/src/slic3r/GUI/PresetBundle.cpp @@ -52,26 +52,40 @@ PresetBundle::PresetBundle() : if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == nullptr) wxImage::AddHandler(new wxPNGHandler); - // Create the ID config keys, as they are not part of the Static print config classes. - this->prints.default_preset().config.opt_string("print_settings_id", true); - this->filaments.default_preset().config.option("filament_settings_id", true)->values.assign(1, std::string()); - this->printers.default_preset().config.opt_string("printer_settings_id", true); - // "compatible printers" are not mandatory yet. + // The following keys are handled by the UI, they do not have a counterpart in any StaticPrintConfig derived classes, + // therefore they need to be handled differently. As they have no counterpart in StaticPrintConfig, they are not being + // 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", + // "printer_vendor", "printer_model", "printer_variant", "default_print_profile", "default_filament_profile" + // //FIXME Rename "compatible_printers" and "compatible_printers_condition", as they are defined in both print and filament profiles, // therefore they are clashing when generating a a config file, G-code or AMF/3MF. -// this->filaments.default_preset().config.optptr("compatible_printers", true); -// this->filaments.default_preset().config.optptr("compatible_printers_condition", true); -// this->prints.default_preset().config.optptr("compatible_printers", true); -// this->prints.default_preset().config.optptr("compatible_printers_condition", true); - // Create the "printer_vendor", "printer_model" and "printer_variant" keys. + + // Create the ID config keys, as they are not part of the Static print config classes. + this->prints.default_preset().config.optptr("print_settings_id", true); + this->prints.default_preset().config.option("compatible_printers_condition", true)->values = { "" }; + this->prints.default_preset().config.option("inherits", true)->values = { "" }; + + this->filaments.default_preset().config.option("filament_settings_id", true)->values = { "" }; + this->filaments.default_preset().config.option("compatible_printers_condition", true)->values = { "" }; + this->filaments.default_preset().config.option("inherits", true)->values = { "" }; + + 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); - // Load the default preset bitmaps. + this->printers.default_preset().config.optptr("default_print_profile", true); + this->printers.default_preset().config.optptr("default_filament_profile", true); + this->printers.default_preset().config.option("inherits", true)->values = { "" }; + + // 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->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); @@ -370,9 +384,20 @@ DynamicPrintConfig PresetBundle::full_config() const auto *nozzle_diameter = dynamic_cast(out.option("nozzle_diameter")); size_t num_extruders = nozzle_diameter->values.size(); + // Collect the "compatible_printers_condition" and "inherits" values over all presets (print, filaments, printers) into a single vector. + std::vector compatible_printers_condition; + std::vector inherits; + auto append_config_string = [](const DynamicConfig &cfg, const std::string &key, std::vector &dst) { + const ConfigOptionStrings *opt = cfg.opt(key); + dst.emplace_back((opt == nullptr || opt->values.empty()) ? "" : opt->values.front()); + }; + append_config_string(this->prints.get_edited_preset().config, "compatible_printers_condition", compatible_printers_condition); + append_config_string(this->prints.get_edited_preset().config, "inherits", inherits); if (num_extruders <= 1) { out.apply(this->filaments.get_edited_preset().config); + append_config_string(this->filaments.get_edited_preset().config, "compatible_printers_condition", compatible_printers_condition); + append_config_string(this->filaments.get_edited_preset().config, "inherits", inherits); } else { // Retrieve filament presets and build a single config object for them. // First collect the filament configurations based on the user selection of this->filament_presets. @@ -382,11 +407,15 @@ DynamicPrintConfig PresetBundle::full_config() const filament_configs.emplace_back(&this->filaments.find_preset(filament_preset_name, true)->config); while (filament_configs.size() < num_extruders) filament_configs.emplace_back(&this->filaments.first_visible().config); + for (const DynamicPrintConfig *cfg : filament_configs) { + append_config_string(*cfg, "compatible_printers_condition", compatible_printers_condition); + append_config_string(*cfg, "inherits", inherits); + } // Option values to set a ConfigOptionVector from. std::vector filament_opts(num_extruders, nullptr); // loop through options and apply them to the resulting config. for (const t_config_option_key &key : this->filaments.default_preset().config.keys()) { - if (key == "compatible_printers" || key == "compatible_printers_condition") + if (key == "compatible_printers" || key == "compatible_printers_condition" || key == "inherits") continue; // Get a destination option. ConfigOption *opt_dst = out.option(key, false); @@ -404,9 +433,13 @@ DynamicPrintConfig PresetBundle::full_config() const } } - //FIXME These two value types clash between the print and filament profiles. They should be renamed. + // Don't store the "compatible_printers_condition" for the printer profile, there is none. + append_config_string(this->printers.get_edited_preset().config, "inherits", 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"); static const char *keys[] = { "perimeter", "infill", "solid_infill", "support_material", "support_material_interface" }; for (size_t i = 0; i < sizeof(keys) / sizeof(keys[0]); ++ i) { @@ -419,6 +452,22 @@ DynamicPrintConfig PresetBundle::full_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; + + // 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"); + add_if_some_non_empty(std::move(inherits), "inherits"); return out; } @@ -497,6 +546,20 @@ 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()); + // Make a copy of the "compatible_printers_condition" and "inherits" vectors, which + // accumulate values over all presets (print, filaments, printers). + // These values will be distributed into their particular presets when loading. + auto *compatible_printers_condition = config.option("compatible_printers_condition", true); + auto *inherits = config.option("inherits", true); + std::vector compatible_printers_condition_values = std::move(compatible_printers_condition->values); + std::vector inherits_values = std::move(inherits->values); + if (compatible_printers_condition_values.empty()) + compatible_printers_condition_values.emplace_back(std::string()); + if (inherits_values.empty()) + inherits_values.emplace_back(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. std::string name = is_external ? boost::filesystem::path(name_or_path).filename().string() : name_or_path; @@ -505,6 +568,11 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool // 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; + // 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->values = { (idx < inherits_values.size()) ? inherits_values[idx] : "" }; + if (i_group == 0) + compatible_printers_condition->values = { compatible_printers_condition_values.front() }; if (is_external) presets.load_external_preset(name_or_path, name, config.opt_string((i_group == 0) ? "print_settings_id" : "printer_settings_id"), @@ -513,10 +581,15 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool presets.load_preset(presets.path_from_name(name), name, config).save(); } + // Update the "compatible_printers_condition" and "inherits" vectors, so their number matches the number of extruders. + compatible_printers_condition_values.erase(compatible_printers_condition_values.begin()); + inherits_values.erase(inherits_values.begin()); + compatible_printers_condition_values.resize(num_extruders, std::string()); + inherits_values.resize(num_extruders, std::string()); + compatible_printers_condition->values = std::move(compatible_printers_condition_values); + inherits->values = std::move(inherits_values); + // 3) Now load the filaments. If there are multiple filament presets, split them and load them. - auto *nozzle_diameter = dynamic_cast(config.option("nozzle_diameter")); - auto *filament_diameter = dynamic_cast(config.option("filament_diameter")); - size_t num_extruders = std::min(nozzle_diameter->values.size(), filament_diameter->values.size()); const ConfigOptionStrings *old_filament_profile_names = config.option("filament_settings_id", false); assert(old_filament_profile_names != nullptr); if (num_extruders <= 1) { diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp index 6eabc2f47..3bfab54b3 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -803,7 +803,7 @@ void Tab::reload_compatible_printers_widget() bool has_any = !m_config->option("compatible_printers")->values.empty(); has_any ? m_compatible_printers_btn->Enable() : m_compatible_printers_btn->Disable(); m_compatible_printers_checkbox->SetValue(!has_any); - get_field("compatible_printers_condition")->toggle(!has_any); + get_field("compatible_printers_condition", 0)->toggle(!has_any); } void TabPrint::build() @@ -1014,7 +1014,7 @@ void TabPrint::build() }; optgroup->append_line(line, &m_colored_Label); - option = optgroup->get_option("compatible_printers_condition"); + option = optgroup->get_option("compatible_printers_condition", 0); option.opt.full_width = true; optgroup->append_single_option_line(option); @@ -1365,7 +1365,7 @@ void TabFilament::build() }; optgroup->append_line(line, &m_colored_Label); - option = optgroup->get_option("compatible_printers_condition"); + option = optgroup->get_option("compatible_printers_condition", 0); option.opt.full_width = true; optgroup->append_single_option_line(option); @@ -2240,7 +2240,7 @@ wxSizer* Tab::compatible_printers_widget(wxWindow* parent, wxCheckBox** checkbox // All printers have been made compatible with this preset. if ((*checkbox)->GetValue()) load_key_value("compatible_printers", std::vector {}); - get_field("compatible_printers_condition")->toggle((*checkbox)->GetValue()); + get_field("compatible_printers_condition", 0)->toggle((*checkbox)->GetValue()); update_changed_ui(); }) ); -- cgit v1.2.3