diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index e065360aa..e3f24d229 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -227,44 +227,6 @@ t_config_option_keys ConfigBase::diff(const ConfigBase &other) const return diff; } -template -void add_correct_opts_to_diff(const std::string &opt_key, t_config_option_keys& vec, const ConfigBase &other, const ConfigBase *this_c) -{ - const T* opt_init = static_cast(other.option(opt_key)); - const T* opt_cur = static_cast(this_c->option(opt_key)); - int opt_init_max_id = opt_init->values.size() - 1; - for (int i = 0; i < opt_cur->values.size(); i++) - { - int init_id = i <= opt_init_max_id ? i : 0; - if (opt_cur->values[i] != opt_init->values[init_id]) - vec.emplace_back(opt_key + "#" + std::to_string(i)); - } -} - -t_config_option_keys ConfigBase::deep_diff(const ConfigBase &other) const -{ - t_config_option_keys diff; - for (const t_config_option_key &opt_key : this->keys()) { - const ConfigOption *this_opt = this->option(opt_key); - const ConfigOption *other_opt = other.option(opt_key); - if (this_opt != nullptr && other_opt != nullptr && *this_opt != *other_opt) - { - if (opt_key == "bed_shape"){ diff.emplace_back(opt_key); continue; } - switch (other_opt->type()) - { - case coInts: add_correct_opts_to_diff(opt_key, diff, other, this); break; - case coBools: add_correct_opts_to_diff(opt_key, diff, other, this); break; - case coFloats: add_correct_opts_to_diff(opt_key, diff, other, this); break; - case coStrings: add_correct_opts_to_diff(opt_key, diff, other, this); break; - case coPercents:add_correct_opts_to_diff(opt_key, diff, other, this); break; - case coPoints: add_correct_opts_to_diff(opt_key, diff, other, this); break; - default: diff.emplace_back(opt_key); break; - } - } - } - return diff; -} - t_config_option_keys ConfigBase::equal(const ConfigBase &other) const { t_config_option_keys equal; diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index 04cc45768..b5a44e176 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -1105,9 +1105,6 @@ public: void apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false); bool equals(const ConfigBase &other) const { return this->diff(other).empty(); } t_config_option_keys diff(const ConfigBase &other) const; - // Use deep_diff to correct return of changed options, - // considering individual options for each extruder - t_config_option_keys deep_diff(const ConfigBase &other) const; t_config_option_keys equal(const ConfigBase &other) const; std::string serialize(const t_config_option_key &opt_key) const; // Set a configuration value from a string, it will call an overridable handle_legacy() diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 7be2f2098..9a6635f40 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1666,7 +1666,7 @@ void GCode::append_full_config(const Print& print, std::string& str) "print_settings_id", "filament_settings_id", "sla_print_settings_id", "sla_material_settings_id", "printer_settings_id", "printer_model", "printer_variant", "default_print_profile", "default_filament_profile", "default_sla_print_profile", "default_sla_material_profile", - "compatible_printers_condition_cummulative", "inherits_cummulative" }) { + "compatible_prints_condition_cummulative", "compatible_printers_condition_cummulative", "inherits_cummulative" }) { const ConfigOption *opt = full_config.option(key); if (opt != nullptr) str += std::string("; ") + key + " = " + opt->serialize() + "\n"; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index f9fa99902..d86ddc25b 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -211,10 +211,25 @@ void PrintConfigDef::init_fff_params() def->mode = comExpert; def->default_value = new ConfigOptionString(); + def = this->add("compatible_prints", coStrings); + def->label = L("Compatible print profiles"); + def->mode = comAdvanced; + def->default_value = new ConfigOptionStrings(); + + def = this->add("compatible_prints_condition", coString); + def->label = L("Compatible print profiles condition"); + def->tooltip = L("A boolean expression using the configuration values of an active print profile. " + "If this expression evaluates to true, this profile is considered compatible " + "with the active print profile."); + def->mode = comExpert; + def->default_value = new ConfigOptionString(); + // The following value is to be stored into the project file (AMF, 3MF, Config ...) // and it contains a sum of "compatible_printers_condition" values over the print and filament profiles. def = this->add("compatible_printers_condition_cummulative", coStrings); def->default_value = new ConfigOptionStrings(); + def = this->add("compatible_prints_condition_cummulative", coStrings); + def->default_value = new ConfigOptionStrings(); def = this->add("complete_objects", coBool); def->label = L("Complete individual objects"); diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index 7e2d4ce95..c4f1ac0d3 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -154,7 +154,7 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt config.set_key_value(opt_key, new ConfigOptionString(boost::any_cast(value))); break; case coStrings:{ - if (opt_key.compare("compatible_printers") == 0) { + if (opt_key == "compatible_prints" || opt_key == "compatible_printers") { config.option(opt_key)->values = boost::any_cast>(value); } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 661b1bfd9..53afbe0db 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1547,7 +1547,6 @@ void Plater::priv::remove(size_t obj_idx) this->canvas3D->enable_layers_editing(false); model.delete_object(obj_idx); -// print.delete_object(obj_idx); // Delete object from Sidebar list sidebar->obj_list()->delete_object_from_list(obj_idx); diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index 38d8ef96c..c50c7113b 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -193,7 +193,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_prints" || key == "compatible_printers") continue; auto *opt = config.option(key, false); /*assert(opt != nullptr); @@ -238,6 +238,25 @@ std::string Preset::label() const return this->name + (this->is_dirty ? g_suffix_modified : ""); } +bool Preset::is_compatible_with_print(const Preset &active_print) const +{ + auto &condition = this->compatible_prints_condition(); + auto *compatible_prints = dynamic_cast(this->config.option("compatible_prints")); + bool has_compatible_prints = compatible_prints != nullptr && ! compatible_prints->values.empty(); + if (! has_compatible_prints && ! condition.empty()) { + try { + return PlaceholderParser::evaluate_boolean_expression(condition, active_print.config); + } catch (const std::runtime_error &err) { + //FIXME in case of an error, return "compatible with everything". + printf("Preset::is_compatible_with_print - parsing error of compatible_prints_condition %s:\n%s\n", active_print.name.c_str(), err.what()); + return true; + } + } + return this->is_default || active_print.name.empty() || ! has_compatible_prints || + std::find(compatible_prints->values.begin(), compatible_prints->values.end(), active_print.name) != + compatible_prints->values.end(); +} + bool Preset::is_compatible_with_printer(const Preset &active_printer, const DynamicPrintConfig *extra_config) const { auto &condition = this->compatible_printers_condition(); @@ -267,9 +286,12 @@ bool Preset::is_compatible_with_printer(const Preset &active_printer) const return this->is_compatible_with_printer(active_printer, &config); } -bool Preset::update_compatible_with_printer(const Preset &active_printer, const DynamicPrintConfig *extra_config) +bool Preset::update_compatible(const Preset &active_printer, const DynamicPrintConfig *extra_config, const Preset *active_print) { - return this->is_compatible = is_compatible_with_printer(active_printer, extra_config); + this->is_compatible = is_compatible_with_printer(active_printer, extra_config); + if (active_print != nullptr) + this->is_compatible &= is_compatible_with_print(*active_print); + return this->is_compatible; } void Preset::set_visible_from_appconfig(const AppConfig &app_config) @@ -306,7 +328,7 @@ const std::vector& Preset::print_options() "top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "bridge_flow_ratio", "clip_multipart_objects", "elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging", "single_extruder_multi_material_priming", - "compatible_printers", "compatible_printers_condition","inherits" + "compatible_printers", "compatible_printers_condition", "inherits" }; return s_opts; } @@ -320,7 +342,8 @@ const std::vector& Preset::filament_options() "filament_cooling_initial_speed", "filament_cooling_final_speed", "filament_ramming_parameters", "filament_minimal_purge_on_wipe_tower", "temperature", "first_layer_temperature", "bed_temperature", "first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed", "max_fan_speed", "bridge_fan_speed", "disable_fan_first_layers", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed", - "start_filament_gcode", "end_filament_gcode","compatible_printers", "compatible_printers_condition", "inherits" + "start_filament_gcode", "end_filament_gcode", + "compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits" }; return s_opts; } @@ -405,8 +428,8 @@ const std::vector& Preset::sla_material_options() "material_correction_printing", "material_correction_curing", "material_notes", "default_sla_material_profile", - "compatible_printers", - "compatible_printers_condition", "inherits" + "compatible_prints", "compatible_prints_condition", + "compatible_printers", "compatible_printers_condition", "inherits" }; } return s_opts; @@ -539,7 +562,8 @@ static bool profile_print_params_same(const DynamicPrintConfig &cfg1, const Dyna t_config_option_keys diff = cfg1.diff(cfg2); // 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", + for (const char *key : { "compatible_prints", "compatible_prints_condition", + "compatible_printers", "compatible_printers_condition", "inherits", "print_settings_id", "filament_settings_id", "sla_print_settings_id", "sla_material_settings_id", "printer_settings_id", "printer_model", "printer_variant", "default_print_profile", "default_filament_profile", "default_sla_print_profile", "default_sla_material_profile" }) diff.erase(std::remove(diff.begin(), diff.end(), key), diff.end()); @@ -755,7 +779,7 @@ void PresetCollection::set_default_suppressed(bool default_suppressed) } } -size_t PresetCollection::update_compatible_with_printer_internal(const Preset &active_printer, bool unselect_if_incompatible) +size_t PresetCollection::update_compatible_internal(const Preset &active_printer, const Preset *active_print, bool unselect_if_incompatible) { DynamicPrintConfig config; config.set_key_value("printer_preset", new ConfigOptionString(active_printer.name)); @@ -766,7 +790,7 @@ size_t PresetCollection::update_compatible_with_printer_internal(const Preset &a bool selected = idx_preset == m_idx_selected; Preset &preset_selected = m_presets[idx_preset]; Preset &preset_edited = selected ? m_edited_preset : preset_selected; - if (! preset_edited.update_compatible_with_printer(active_printer, &config) && + if (! preset_edited.update_compatible(active_printer, &config, active_print) && selected && unselect_if_incompatible) m_idx_selected = -1; if (selected) @@ -797,7 +821,7 @@ void PresetCollection::update_platter_ui(GUI::PresetComboBox *ui) const Preset &selected_preset = this->get_selected_preset(); // Show wide icons if the currently selected preset is not compatible with the current printer, // and draw a red flag in front of the selected preset. - bool wide_icons = !selected_preset.is_compatible && m_bitmap_incompatible != nullptr; + bool wide_icons = ! selected_preset.is_compatible && m_bitmap_incompatible != nullptr; std::map nonsys_presets; wxString selected = ""; @@ -950,17 +974,59 @@ bool PresetCollection::update_dirty_ui(wxBitmapComboBox *ui) return was_dirty != is_dirty; } +template +void add_correct_opts_to_diff(const std::string &opt_key, t_config_option_keys& vec, const ConfigBase &other, const ConfigBase &this_c) +{ + const T* opt_init = static_cast(other.option(opt_key)); + const T* opt_cur = static_cast(this_c.option(opt_key)); + int opt_init_max_id = opt_init->values.size() - 1; + for (int i = 0; i < opt_cur->values.size(); i++) + { + int init_id = i <= opt_init_max_id ? i : 0; + if (opt_cur->values[i] != opt_init->values[init_id]) + vec.emplace_back(opt_key + "#" + std::to_string(i)); + } +} + +// Use deep_diff to correct return of changed options, considering individual options for each extruder. +inline t_config_option_keys deep_diff(const ConfigBase &config_this, const ConfigBase &config_other) +{ + t_config_option_keys diff; + for (const t_config_option_key &opt_key : config_this.keys()) { + const ConfigOption *this_opt = config_this.option(opt_key); + const ConfigOption *other_opt = config_other.option(opt_key); + if (this_opt != nullptr && other_opt != nullptr && *this_opt != *other_opt) + { + if (opt_key == "bed_shape" || opt_key == "compatible_prints" || opt_key == "compatible_printers") { + diff.emplace_back(opt_key); + continue; + } + switch (other_opt->type()) + { + case coInts: add_correct_opts_to_diff(opt_key, diff, config_other, config_this); break; + case coBools: add_correct_opts_to_diff(opt_key, diff, config_other, config_this); break; + case coFloats: add_correct_opts_to_diff(opt_key, diff, config_other, config_this); break; + case coStrings: add_correct_opts_to_diff(opt_key, diff, config_other, config_this); break; + case coPercents:add_correct_opts_to_diff(opt_key, diff, config_other, config_this); break; + case coPoints: add_correct_opts_to_diff(opt_key, diff, config_other, config_this); break; + default: diff.emplace_back(opt_key); break; + } + } + } + return diff; +} + 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 = deep_compare ? - reference->config.deep_diff(edited->config) : + deep_diff(reference->config, edited->config) : reference->config.diff(edited->config); // The "compatible_printers" option key is handled differently from the others: // It is not mandatory. If the key is missing, it means it is compatible with any printer. // If the key exists and it is empty, it means it is compatible with no printer. - std::initializer_list optional_keys { "compatible_printers" }; + std::initializer_list optional_keys { "compatible_prints", "compatible_printers" }; for (auto &opt_key : optional_keys) { if (reference->config.has(opt_key) != edited->config.has(opt_key)) changed.emplace_back(opt_key); @@ -1054,10 +1120,12 @@ std::vector PresetCollection::merge_presets(PresetCollection &&othe std::string PresetCollection::name() const { switch (this->type()) { - case Preset::TYPE_PRINT: return "print"; - case Preset::TYPE_FILAMENT: return "filament"; - case Preset::TYPE_PRINTER: return "printer"; - default: return "invalid"; + case Preset::TYPE_PRINT: return "print"; + case Preset::TYPE_FILAMENT: return "filament"; + case Preset::TYPE_SLA_PRINT: return "SLA print"; + case Preset::TYPE_SLA_MATERIAL: return "SLA material"; + case Preset::TYPE_PRINTER: return "printer"; + default: return "invalid"; } } diff --git a/src/slic3r/GUI/Preset.hpp b/src/slic3r/GUI/Preset.hpp index fc459d8dd..96230ad2b 100644 --- a/src/slic3r/GUI/Preset.hpp +++ b/src/slic3r/GUI/Preset.hpp @@ -6,8 +6,8 @@ #include #include -#include "../../libslic3r/libslic3r.h" -#include "../../libslic3r/PrintConfig.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/PrintConfig.hpp" #include "slic3r/Utils/Semver.hpp" class wxBitmap; @@ -136,6 +136,7 @@ public: void set_dirty(bool dirty = true) { this->is_dirty = dirty; } void reset_dirty() { this->is_dirty = false; } + bool is_compatible_with_print(const Preset &active_print) const; bool is_compatible_with_printer(const Preset &active_printer, const DynamicPrintConfig *extra_config) const; bool is_compatible_with_printer(const Preset &active_printer) const; @@ -144,17 +145,28 @@ public: std::string& inherits() { return Preset::inherits(this->config); } const std::string& inherits() const { return Preset::inherits(const_cast(this)->config); } + // Returns the "compatible_prints_condition". + static std::string& compatible_prints_condition(DynamicPrintConfig &cfg) { return cfg.option("compatible_prints_condition", true)->value; } + std::string& compatible_prints_condition() { + assert(this->type == TYPE_FILAMENT || this->type == TYPE_SLA_MATERIAL); + return Preset::compatible_prints_condition(this->config); + } + const std::string& compatible_prints_condition() const { return const_cast(this)->compatible_prints_condition(); } + // Returns the "compatible_printers_condition". static std::string& compatible_printers_condition(DynamicPrintConfig &cfg) { return cfg.option("compatible_printers_condition", true)->value; } - 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); } + std::string& compatible_printers_condition() { + assert(this->type == TYPE_PRINT || this->type == TYPE_SLA_PRINT || this->type == TYPE_FILAMENT || this->type == TYPE_SLA_MATERIAL); + return Preset::compatible_printers_condition(this->config); + } + const std::string& compatible_printers_condition() const { return const_cast(this)->compatible_printers_condition(); } 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); + bool update_compatible(const Preset &active_printer, const DynamicPrintConfig *extra_config, const Preset *active_print = nullptr); // Set is_visible according to application config void set_visible_from_appconfig(const AppConfig &app_config); @@ -333,14 +345,14 @@ public: // For Print / Filament presets, disable those, which are not compatible with the printer. template - void update_compatible_with_printer(const Preset &active_printer, bool select_other_if_incompatible, PreferedCondition prefered_condition) + void update_compatible(const Preset &active_printer, const Preset *active_print, bool select_other_if_incompatible, PreferedCondition prefered_condition) { - if (this->update_compatible_with_printer_internal(active_printer, select_other_if_incompatible) == (size_t)-1) + if (this->update_compatible_internal(active_printer, active_print, select_other_if_incompatible) == (size_t)-1) // Find some other compatible preset, or the "-- default --" preset. this->select_preset(this->first_compatible_idx(prefered_condition)); } - void update_compatible_with_printer(const Preset &active_printer, bool select_other_if_incompatible) - { this->update_compatible_with_printer(active_printer, select_other_if_incompatible, [](const std::string&){return true;}); } + void update_compatible(const Preset &active_printer, const Preset *active_print, bool select_other_if_incompatible) + { this->update_compatible(active_printer, active_print, select_other_if_incompatible, [](const std::string&){return true;}); } size_t num_visible() const { return std::count_if(m_presets.begin(), m_presets.end(), [](const Preset &preset){return preset.is_visible;}); } @@ -408,7 +420,7 @@ private: std::deque::const_iterator find_preset_internal(const std::string &name) const { return const_cast(this)->find_preset_internal(name); } - size_t update_compatible_with_printer_internal(const Preset &active_printer, bool unselect_if_incompatible); + size_t update_compatible_internal(const Preset &active_printer, const Preset *active_print, bool unselect_if_incompatible); static std::vector dirty_options(const Preset *edited, const Preset *reference, const bool is_printer_type = false); diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index f2a0b69a0..2917a3622 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -227,7 +227,7 @@ void PresetBundle::load_presets(const AppConfig &config) errors_cummulative += err.what(); } this->update_multi_material_filament_presets(); - this->update_compatible_with_printer(false); + this->update_compatible(false); if (! errors_cummulative.empty()) throw std::runtime_error(errors_cummulative); @@ -336,7 +336,7 @@ void PresetBundle::load_selections(const AppConfig &config) // Activate print / filament / printer profiles from the config. // If the printer profile enumerated by the config are not visible, select an alternate preset. // Do not select alternate profiles for the print / filament profiles as those presets - // will be selected by the following call of this->update_compatible_with_printer(true). + // will be selected by the following call of this->update_compatible(true). printers.select_preset_by_name(initial_printer_profile_name, true); PrinterTechnology printer_technology = printers.get_selected_preset().printer_technology(); if (printer_technology == ptFFF) { @@ -363,7 +363,7 @@ void PresetBundle::load_selections(const AppConfig &config) 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. + // Do not define the missing filaments, so that the update_compatible() will use the preferred filaments. this->filament_presets.resize(num_extruders, ""); } @@ -371,7 +371,7 @@ void PresetBundle::load_selections(const AppConfig &config) // Always try to select a compatible print and filament preset to the current printer preset, // as the application may have been closed with an active "external" preset, which does not // exist. - this->update_compatible_with_printer(true); + this->update_compatible(true); this->update_multi_material_filament_presets(); } @@ -459,6 +459,7 @@ DynamicPrintConfig PresetBundle::full_fff_config() const 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 compatible_prints_condition; std::vector inherits; compatible_printers_condition.emplace_back(this->prints.get_edited_preset().compatible_printers_condition()); inherits .emplace_back(this->prints.get_edited_preset().inherits()); @@ -466,6 +467,7 @@ DynamicPrintConfig PresetBundle::full_fff_config() const if (num_extruders <= 1) { out.apply(this->filaments.get_edited_preset().config); compatible_printers_condition.emplace_back(this->filaments.get_edited_preset().compatible_printers_condition()); + compatible_prints_condition .emplace_back(this->filaments.get_edited_preset().compatible_prints_condition()); inherits .emplace_back(this->filaments.get_edited_preset().inherits()); } else { // Retrieve filament presets and build a single config object for them. @@ -478,13 +480,14 @@ DynamicPrintConfig PresetBundle::full_fff_config() const filament_configs.emplace_back(&this->filaments.first_visible().config); for (const DynamicPrintConfig *cfg : filament_configs) { compatible_printers_condition.emplace_back(Preset::compatible_printers_condition(*const_cast(cfg))); + compatible_prints_condition .emplace_back(Preset::compatible_prints_condition(*const_cast(cfg))); inherits .emplace_back(Preset::inherits(*const_cast(cfg))); } // 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") + if (key == "compatible_prints" || key == "compatible_printers") continue; // Get a destination option. ConfigOption *opt_dst = out.option(key, false); @@ -505,7 +508,9 @@ DynamicPrintConfig PresetBundle::full_fff_config() const // Don't store the "compatible_printers_condition" for the printer profile, there is none. inherits.emplace_back(this->printers.get_edited_preset().inherits()); - // These two value types clash between the print and filament profiles. They should be renamed. + // These value types clash between the print and filament profiles. They should be renamed. + out.erase("compatible_prints"); + out.erase("compatible_prints_condition"); out.erase("compatible_printers"); out.erase("compatible_printers_condition"); out.erase("inherits"); @@ -536,6 +541,7 @@ DynamicPrintConfig PresetBundle::full_fff_config() const 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(compatible_prints_condition), "compatible_prints_condition_cummulative"); add_if_some_non_empty(std::move(inherits), "inherits_cummulative"); out.option("printer_technology", true)->value = ptFFF; @@ -554,11 +560,13 @@ DynamicPrintConfig PresetBundle::full_sla_config() const // Collect the "compatible_printers_condition" and "inherits" values over all presets (sla_prints, sla_materials, printers) into a single vector. std::vector compatible_printers_condition; + std::vector compatible_prints_condition; std::vector inherits; - compatible_printers_condition.emplace_back(this->/*prints*/sla_prints.get_edited_preset().compatible_printers_condition()); - inherits .emplace_back(this->/*prints*/sla_prints.get_edited_preset().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()); + compatible_printers_condition.emplace_back(this->sla_prints.get_edited_preset().compatible_printers_condition()); + inherits .emplace_back(this->sla_prints.get_edited_preset().inherits()); + compatible_printers_condition.emplace_back(this->sla_materials.get_edited_preset().compatible_printers_condition()); + compatible_prints_condition .emplace_back(this->sla_materials.get_edited_preset().compatible_prints_condition()); + inherits .emplace_back(this->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. @@ -584,6 +592,7 @@ DynamicPrintConfig PresetBundle::full_sla_config() const 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(compatible_prints_condition), "compatible_prints_condition_cummulative"); add_if_some_non_empty(std::move(inherits), "inherits_cummulative"); out.option("printer_technology", true)->value = ptSLA; @@ -664,10 +673,13 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool // accumulate values over all presets (print, filaments, printers). // These values will be distributed into their particular presets when loading. std::vector compatible_printers_condition_values = std::move(config.option("compatible_printers_condition_cummulative", true)->values); + std::vector compatible_prints_condition_values = std::move(config.option("compatible_prints_condition_cummulative", true)->values); std::vector inherits_values = std::move(config.option("inherits_cummulative", true)->values); std::string &compatible_printers_condition = Preset::compatible_printers_condition(config); + std::string &compatible_prints_condition = Preset::compatible_prints_condition(config); std::string &inherits = Preset::inherits(config); compatible_printers_condition_values.resize(num_extruders + 2, std::string()); + compatible_prints_condition_values.resize(num_extruders, std::string()); inherits_values.resize(num_extruders + 2, std::string()); // The "default_filament_profile" will be later extracted into the printer profile. switch (printer_technology) { @@ -689,11 +701,16 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool // First load the print and printer presets. auto load_preset = - [&config, &inherits, &inherits_values, &compatible_printers_condition, &compatible_printers_condition_values, is_external, &name, &name_or_path] + [&config, &inherits, &inherits_values, + &compatible_printers_condition, &compatible_printers_condition_values, + &compatible_prints_condition, &compatible_prints_condition_values, + is_external, &name, &name_or_path] (PresetCollection &presets, size_t idx, const std::string &key) { // Split the "compatible_printers_condition" and "inherits" values one by one from a single vector to the print & printer profiles. inherits = inherits_values[idx]; compatible_printers_condition = compatible_printers_condition_values[idx]; + if (idx > 0 && idx - 1 < compatible_prints_condition_values.size()) + compatible_prints_condition = compatible_prints_condition_values[idx - 1]; if (is_external) presets.load_external_preset(name_or_path, name, config.opt_string(key, true), config); else @@ -714,6 +731,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool // 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]; + 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); @@ -734,7 +752,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool 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") { + } else if (key != "compatible_printers" && key != "compatible_prints") { for (size_t i = 0; i < configs.size(); ++ i) static_cast(configs[i].option(key, false))->set_at(other_opt, 0, i); } @@ -745,6 +763,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool 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("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; @@ -779,7 +798,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool break; } - this->update_compatible_with_printer(false); + this->update_compatible(false); } // Load the active configuration of a config bundle from a boost property_tree. This is a private method called from load_config_file. @@ -841,7 +860,7 @@ void PresetBundle::load_config_file_config_bundle(const std::string &path, const 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); - this->update_compatible_with_printer(false); + this->update_compatible(false); } // Process the Config Bundle loaded as a Boost property tree. @@ -1176,7 +1195,7 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla this->update_multi_material_filament_presets(); for (size_t i = 0; i < std::min(this->filament_presets.size(), active_filaments.size()); ++ i) this->filament_presets[i] = filaments.find_preset(active_filaments[i], true)->name; - this->update_compatible_with_printer(false); + this->update_compatible(false); } return presets_loaded; @@ -1224,24 +1243,25 @@ void PresetBundle::update_multi_material_filament_presets() } } -void PresetBundle::update_compatible_with_printer(bool select_other_if_incompatible) +void PresetBundle::update_compatible(bool select_other_if_incompatible) { - const Preset &printer_preset = this->printers.get_edited_preset(); + const Preset &printer_preset = this->printers.get_edited_preset(); switch (printers.get_edited_preset().printer_technology()) { case ptFFF: { assert(printer_preset.config.has("default_print_profile")); assert(printer_preset.config.has("default_filament_profile")); + const Preset &print_preset = this->prints.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, + this->prints.update_compatible(printer_preset, nullptr, select_other_if_incompatible) : + this->prints.update_compatible(printer_preset, nullptr, 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, + this->filaments.update_compatible(printer_preset, &print_preset, select_other_if_incompatible) : + this->filaments.update_compatible(printer_preset, &print_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) { @@ -1269,15 +1289,16 @@ void PresetBundle::update_compatible_with_printer(bool select_other_if_incompati { assert(printer_preset.config.has("default_sla_print_profile")); assert(printer_preset.config.has("default_sla_material_profile")); + const Preset &sla_print_preset = this->sla_prints.get_edited_preset(); const std::string &prefered_sla_print_profile = printer_preset.config.opt_string("default_sla_print_profile"); (prefered_sla_print_profile.empty()) ? - this->sla_prints.update_compatible_with_printer(printer_preset, select_other_if_incompatible) : - this->sla_prints.update_compatible_with_printer(printer_preset, select_other_if_incompatible, + this->sla_prints.update_compatible(printer_preset, nullptr, select_other_if_incompatible) : + this->sla_prints.update_compatible(printer_preset, nullptr, select_other_if_incompatible, [&prefered_sla_print_profile](const std::string& profile_name){ return profile_name == prefered_sla_print_profile; }); const std::string &prefered_sla_material_profile = printer_preset.config.opt_string("default_sla_material_profile"); prefered_sla_material_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, + this->sla_materials.update_compatible(printer_preset, &sla_print_preset, select_other_if_incompatible) : + this->sla_materials.update_compatible(printer_preset, &sla_print_preset, select_other_if_incompatible, [&prefered_sla_material_profile](const std::string& profile_name){ return profile_name == prefered_sla_material_profile; }); break; } diff --git a/src/slic3r/GUI/PresetBundle.hpp b/src/slic3r/GUI/PresetBundle.hpp index 930a9e9b8..c43a67b40 100644 --- a/src/slic3r/GUI/PresetBundle.hpp +++ b/src/slic3r/GUI/PresetBundle.hpp @@ -117,11 +117,11 @@ public: void update_multi_material_filament_presets(); // Update the is_compatible flag of all print and filament presets depending on whether they are marked - // as compatible with the currently selected printer. + // as compatible with the currently selected printer (and print in case of filament presets). // Also updates the is_visible flag of each preset. // If select_other_if_incompatible is true, then the print or filament preset is switched to some compatible // preset if the current print or filament preset is not compatible. - void update_compatible_with_printer(bool select_other_if_incompatible); + void update_compatible(bool select_other_if_incompatible); static bool parse_color(const std::string &scolor, unsigned char *rgb_out); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 259571585..5f6891eea 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1,8 +1,8 @@ -#include "../../libslic3r/GCodeSender.hpp" +#include "libslic3r/GCodeSender.hpp" #include "Tab.hpp" #include "PresetBundle.hpp" #include "PresetHints.hpp" -#include "../../libslic3r/Utils.hpp" +#include "libslic3r/Utils.hpp" #include "slic3r/Utils/Http.hpp" #include "slic3r/Utils/PrintHost.hpp" @@ -37,6 +37,26 @@ namespace GUI { wxDEFINE_EVENT(EVT_TAB_VALUE_CHANGED, wxCommandEvent); wxDEFINE_EVENT(EVT_TAB_PRESETS_CHANGED, SimpleEvent); +Tab::Tab(wxNotebook* parent, const wxString& title, const char* name) : + m_parent(parent), m_title(title), m_name(name) +{ + Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBK_LEFT | wxTAB_TRAVERSAL, name); + set_type(); + + m_compatible_printers.type = Preset::TYPE_PRINTER; + m_compatible_printers.key_list = "compatible_printers"; + m_compatible_printers.key_condition = "compatible_printers_condition"; + m_compatible_printers.dialog_title = _(L("Compatible printers")); + m_compatible_printers.dialog_label = _(L("Select the printers this profile is compatible with.")); + + m_compatible_prints.type = Preset::TYPE_PRINT; + m_compatible_prints.key_list = "compatible_prints"; + m_compatible_prints.key_condition = "compatible_prints_condition"; + m_compatible_prints.dialog_title = _(L("Compatible print profiles")); + m_compatible_prints.dialog_label = _(L("Select the print profiles this profile is compatible with.")); + + wxGetApp().tabs_list.push_back(this); +} void Tab::set_type() { @@ -45,7 +65,7 @@ void Tab::set_type() else if (m_name == "filament") { m_type = Slic3r::Preset::TYPE_FILAMENT; } else if (m_name == "sla_material") { m_type = Slic3r::Preset::TYPE_SLA_MATERIAL; } else if (m_name == "printer") { m_type = Slic3r::Preset::TYPE_PRINTER; } - else { m_type = Slic3r::Preset::TYPE_INVALID; } + else { m_type = Slic3r::Preset::TYPE_INVALID; assert(false); } } // sub new @@ -290,7 +310,7 @@ void Tab::update_labels_colour() else color = &m_modified_label_clr; } - if (opt.first == "bed_shape" || opt.first == "compatible_printers") { + if (opt.first == "bed_shape" || opt.first == "compatible_prints" || opt.first == "compatible_printers") { if (m_colored_Label != nullptr) { m_colored_Label->SetForegroundColour(*color); m_colored_Label->Refresh(true); @@ -332,7 +352,7 @@ void Tab::update_changed_ui() 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") { + if (m_type == Slic3r::Preset::TYPE_PRINTER) { TabPrinter* tab = static_cast(this); if (tab->m_initial_extruders_count != tab->m_extruders_count) dirty_options.emplace_back("extruders_count"); @@ -378,7 +398,7 @@ void Tab::update_changed_ui() icon = &m_bmp_white_bullet; tt = &m_tt_white_bullet; } - if (opt.first == "bed_shape" || opt.first == "compatible_printers") { + if (opt.first == "bed_shape" || opt.first == "compatible_prints" || opt.first == "compatible_printers") { if (m_colored_Label != nullptr) { m_colored_Label->SetForegroundColour(*color); m_colored_Label->Refresh(true); @@ -452,7 +472,7 @@ void TabSLAMaterial::init_options_list() for (const auto opt_key : m_config->keys()) { - if (opt_key == "compatible_printers") { + if (opt_key == "compatible_prints" || opt_key == "compatible_printers") { m_options_list.emplace(opt_key, m_opt_status_value); continue; } @@ -473,7 +493,7 @@ void Tab::get_sys_and_mod_flags(const std::string& opt_key, bool& sys_page, bool { auto opt = m_options_list.find(opt_key); if (sys_page) sys_page = (opt->second & osSystemValue) != 0; - if (!modified_page) modified_page = (opt->second & osInitValue) == 0; + modified_page |= (opt->second & osInitValue) == 0; } void Tab::update_changed_tree_ui() @@ -497,11 +517,13 @@ void Tab::update_changed_tree_ui() } } if (title == _("Dependencies")) { - if (name() != "printer") - get_sys_and_mod_flags("compatible_printers", sys_page, modified_page); - else { - sys_page = m_presets->get_selected_preset_parent() ? true:false; + if (m_type == Slic3r::Preset::TYPE_PRINTER) { + sys_page = m_presets->get_selected_preset_parent() != nullptr; modified_page = false; + } else { + if (m_type == Slic3r::Preset::TYPE_FILAMENT || m_type == Slic3r::Preset::TYPE_SLA_MATERIAL) + get_sys_and_mod_flags("compatible_prints", sys_page, modified_page); + get_sys_and_mod_flags("compatible_printers", sys_page, modified_page); } } for (auto group : page->m_optgroups) @@ -574,18 +596,26 @@ void Tab::on_roll_back_value(const bool to_sys /*= true*/) } } - if (group->title == _("Profile dependencies") && name() != "printer") { - if ((m_options_list["compatible_printers"] & os) == 0) { + if (group->title == _("Profile dependencies")) { + if (m_type != Slic3r::Preset::TYPE_PRINTER && (m_options_list["compatible_printers"] & os) == 0) { to_sys ? group->back_to_sys_value("compatible_printers") : group->back_to_initial_value("compatible_printers"); load_key_value("compatible_printers", true/*some value*/, true); bool is_empty = m_config->option("compatible_printers")->values.empty(); - m_compatible_printers_checkbox->SetValue(is_empty); - is_empty ? m_compatible_printers_btn->Disable() : m_compatible_printers_btn->Enable(); + m_compatible_printers.checkbox->SetValue(is_empty); + is_empty ? m_compatible_printers.btn->Disable() : m_compatible_printers.btn->Enable(); + } + if ((m_type == Slic3r::Preset::TYPE_PRINT || m_type == Slic3r::Preset::TYPE_SLA_PRINT) && (m_options_list["compatible_prints"] & os) == 0) { + to_sys ? group->back_to_sys_value("compatible_prints") : group->back_to_initial_value("compatible_prints"); + load_key_value("compatible_prints", true/*some value*/, true); + + bool is_empty = m_config->option("compatible_prints")->values.empty(); + m_compatible_prints.checkbox->SetValue(is_empty); + is_empty ? m_compatible_prints.btn->Disable() : m_compatible_prints.btn->Enable(); } } - for (t_opt_map::iterator it = group->m_opt_map.begin(); it != group->m_opt_map.end(); ++it) { - const std::string& opt_key = it->first; + for (auto kvp : group->m_opt_map) { + const std::string& opt_key = kvp.first; if ((m_options_list[opt_key] & os) == 0) to_sys ? group->back_to_sys_value(opt_key) : group->back_to_initial_value(opt_key); } @@ -687,10 +717,10 @@ void Tab::load_key_value(const std::string& opt_key, const boost::any& value, bo { if (!saved_value) change_opt_value(*m_config, opt_key, value); // Mark the print & filament enabled if they are compatible with the currently selected preset. - if (opt_key.compare("compatible_printers") == 0) { + if (opt_key == "compatible_printers" || opt_key == "compatible_prints") { // Don't select another profile if this profile happens to become incompatible. - m_preset_bundle->update_compatible_with_printer(false); - } + m_preset_bundle->update_compatible(false); + } m_presets->update_dirty_ui(m_presets_choice); on_presets_changed(); update(); @@ -760,14 +790,12 @@ void Tab::update_wiping_button_visibility() { // to uddate number of "filament" selection boxes when the number of extruders change. void Tab::on_presets_changed() { - if (m_type == Slic3r::Preset::TYPE_PRINTER && !m_dependent_tabs.empty()) { - // Printer selected at the Printer tab, update "compatible" marks at the print and filament selectors. - for (auto t: m_dependent_tabs) - { - // If the printer tells us that the print or filament/sla_material preset has been switched or invalidated, - // refresh the print or filament/sla_material tab page. - wxGetApp().get_tab(t)->load_current_preset(); - } + // Printer selected at the Printer tab, update "compatible" marks at the print and filament selectors. + for (auto t: m_dependent_tabs) + { + // If the printer tells us that the print or filament/sla_material preset has been switched or invalidated, + // refresh the print or filament/sla_material tab page. + wxGetApp().get_tab(t)->load_current_preset(); } wxCommandEvent event(EVT_TAB_PRESETS_CHANGED); @@ -796,9 +824,9 @@ void Tab::update_preset_description_line() if (parent && parent->vendor) { description_line += "\n\n" + _(L("Additional information:")) + "\n"; - description_line += "\t" + _(L("vendor")) + ": " + (name()=="printer" ? "\n\t\t" : "") + parent->vendor->name + + description_line += "\t" + _(L("vendor")) + ": " + (m_type == Slic3r::Preset::TYPE_PRINTER ? "\n\t\t" : "") + parent->vendor->name + ", ver: " + parent->vendor->config_version.to_string(); - if (name() == "printer") { + if (m_type == Slic3r::Preset::TYPE_PRINTER) { const std::string &printer_model = preset.config.opt_string("printer_model"); if (! printer_model.empty()) description_line += "\n\n\t" + _(L("printer model")) + ": \n\t\t" + printer_model; @@ -860,14 +888,6 @@ void Tab::update_frequently_changed_parameters() update_wiping_button_visibility(); } -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); -} - void TabPrint::build() { m_presets = &m_preset_bundle->prints; @@ -1072,12 +1092,11 @@ void TabPrint::build() page = add_options_page(_(L("Dependencies")), "wrench.png"); optgroup = page->new_optgroup(_(L("Profile dependencies"))); - line = optgroup->create_single_option_line("compatible_printers");//{ _(L("Compatible printers")), "" }; - line.widget = [this](wxWindow* parent) { - return compatible_printers_widget(parent, &m_compatible_printers_checkbox, &m_compatible_printers_btn); + line = optgroup->create_single_option_line("compatible_printers"); + line.widget = [this](wxWindow* parent) { + return compatible_widget_create(parent, m_compatible_printers); }; 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); @@ -1093,7 +1112,7 @@ void TabPrint::build() // Reload current config (aka presets->edited_preset->config) into the UI fields. void TabPrint::reload_config() { - reload_compatible_printers_widget(); + this->compatible_widget_reload(m_compatible_printers); Tab::reload_config(); } @@ -1208,11 +1227,11 @@ void TabPrint::update() } } if (!str_fill_pattern.empty()) { - auto external_fill_pattern = m_config->def()->get("external_fill_pattern")->enum_values; + const std::vector &external_fill_pattern = m_config->def()->get("external_fill_pattern")->enum_values; bool correct_100p_fill = false; - for (auto fill : external_fill_pattern) + for (const std::string &fill : external_fill_pattern) { - if (str_fill_pattern.compare(fill) == 0) + if (str_fill_pattern == fill) correct_100p_fill = true; } // get fill_pattern name from enum_labels for using this one at dialog_msg @@ -1439,16 +1458,25 @@ void TabFilament::build() page = add_options_page(_(L("Dependencies")), "wrench.png"); optgroup = page->new_optgroup(_(L("Profile dependencies"))); - line = optgroup->create_single_option_line("compatible_printers");//{ _(L("Compatible printers")), "" }; - line.widget = [this](wxWindow* parent) { - return compatible_printers_widget(parent, &m_compatible_printers_checkbox, &m_compatible_printers_btn); + + line = optgroup->create_single_option_line("compatible_printers"); + line.widget = [this](wxWindow* parent) { + return compatible_widget_create(parent, m_compatible_printers); }; 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 = optgroup->create_single_option_line("compatible_prints"); + line.widget = [this](wxWindow* parent) { + return compatible_widget_create(parent, m_compatible_prints); + }; + optgroup->append_line(line, &m_colored_Label); + option = optgroup->get_option("compatible_prints_condition"); + option.opt.full_width = true; + optgroup->append_single_option_line(option); + line = Line{ "", "" }; line.full_width = 1; line.widget = [this](wxWindow* parent) { @@ -1460,7 +1488,8 @@ void TabFilament::build() // Reload current config (aka presets->edited_preset->config) into the UI fields. void TabFilament::reload_config() { - reload_compatible_printers_widget(); + this->compatible_widget_reload(m_compatible_printers); + this->compatible_widget_reload(m_compatible_prints); Tab::reload_config(); } @@ -1575,10 +1604,10 @@ void TabPrinter::build_fff() optgroup->m_on_change = [this, optgroup](t_config_option_key opt_key, boost::any value) { size_t extruders_count = boost::any_cast(optgroup->get_value("extruders_count")); wxTheApp->CallAfter([this, opt_key, value, extruders_count]() { - if (opt_key.compare("extruders_count")==0 || opt_key.compare("single_extruder_multi_material")==0) { + if (opt_key == "extruders_count" || opt_key == "single_extruder_multi_material") { extruders_count_changed(extruders_count); update_dirty(); - if (opt_key.compare("single_extruder_multi_material")==0) // the single_extruder_multimaterial was added to force pages + if (opt_key == "single_extruder_multi_material") // the single_extruder_multimaterial was added to force pages on_value_change(opt_key, value); // rebuild - let's make sure the on_value_change is not skipped } else { @@ -1734,7 +1763,7 @@ void TabPrinter::build_fff() optgroup->m_on_change = [this, optgroup](t_config_option_key opt_key, boost::any value) { wxTheApp->CallAfter([this, opt_key, value]() { - if (opt_key.compare("silent_mode") == 0) { + if (opt_key == "silent_mode") { bool val = boost::any_cast(value); if (m_use_silent_mode != val) { m_rebuild_kinematics_page = true; @@ -2351,13 +2380,31 @@ void Tab::select_preset(std::string preset_name) // If no name is provided, select the "-- default --" preset. 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; + bool current_dirty = m_presets->current_is_dirty(); + bool print_tab = m_presets->type() == Preset::TYPE_PRINT || m_presets->type() == Preset::TYPE_SLA_PRINT; + bool printer_tab = m_presets->type() == Preset::TYPE_PRINTER; + bool canceled = false; // m_reload_dependent_tabs = {}; m_dependent_tabs = {}; if (current_dirty && !may_discard_current_dirty_preset()) { canceled = true; + } else if (print_tab) { + // Before switching the print profile to a new one, verify, whether the currently active filament or SLA material + // are compatible with the new print. + // If it is not compatible and the current filament or SLA material are dirty, let user decide + // whether to discard the changes or keep the current print selection. + PrinterTechnology printer_technology = m_preset_bundle->printers.get_edited_preset().printer_technology(); + PresetCollection &dependent = (printer_technology == ptFFF) ? m_preset_bundle->filaments : m_preset_bundle->sla_materials; + bool old_preset_dirty = dependent.current_is_dirty(); + bool new_preset_compatible = dependent.get_edited_preset().is_compatible_with_print(*m_presets->find_preset(preset_name, true)); + if (! canceled) + canceled = old_preset_dirty && ! new_preset_compatible && ! may_discard_current_dirty_preset(&dependent, preset_name); + if (! canceled) { + // The preset will be switched to a different, compatible preset, or the '-- default --'. + m_dependent_tabs.emplace_back((printer_technology == ptFFF) ? Preset::Type::TYPE_FILAMENT : Preset::Type::TYPE_SLA_MATERIAL); + if (old_preset_dirty) + dependent.discard_current_changes(); + } } 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. @@ -2409,13 +2456,13 @@ void Tab::select_preset(std::string preset_name) on_presets_changed(); } else { if (current_dirty) - m_presets->discard_current_changes() ; + 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); + if (current_dirty || print_tab || printer_tab) + m_preset_bundle->update_compatible(true); // Initialize the UI from the current preset. if (printer_tab) static_cast(this)->update_pages(); @@ -2449,13 +2496,20 @@ bool Tab::may_discard_current_dirty_preset(PresetCollection* presets /*= nullptr } // Show a confirmation dialog with the list of dirty options. std::string changes = ""; - for (auto changed_name : option_names) + for (const std::string &changed_name : option_names) changes += tab + changed_name + "\n"; - auto message = (!new_printer_name.empty()) ? - name + _(L("\n\nis not compatible with printer\n")) +tab + new_printer_name+ _(L("\n\nand it has the following unsaved changes:")) : - name + _(L("\n\nhas the following unsaved changes:")); + std::string message = name + "\n\n"; + if (new_printer_name.empty()) + message += _(L("has the following unsaved changes:")); + else { + message += (m_type == Slic3r::Preset::TYPE_PRINTER) ? + _(L("is not compatible with printer")) : + _(L("is not compatible with print profile")); + message += std::string("\n") + tab + new_printer_name + "\n\n"; + message += _(L("and it has the following unsaved changes:")); + } auto confirm = new wxMessageDialog(parent(), - message + "\n" +changes +_(L("\n\nDiscard changes and continue anyway?")), + message + "\n" + changes + _(L("\n\nDiscard changes and continue anyway?")), _(L("Unsaved Changes")), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION); return confirm->ShowModal() == wxID_YES; } @@ -2579,7 +2633,7 @@ void Tab::save_preset(std::string name /*= ""*/) // Save the preset into Slic3r::data_dir / presets / section_name / preset_name.ini m_presets->save_current_preset(name); // Mark the print & filament enabled if they are compatible with the currently selected preset. - m_preset_bundle->update_compatible_with_printer(false); + m_preset_bundle->update_compatible(false); // Add the new item into the UI component, remove dirty flags and activate the saved item. update_tab_ui(); // Update the selection boxes at the platter. @@ -2636,7 +2690,7 @@ void Tab::update_ui_from_settings() // Show the 'show / hide presets' button only for the print and filament tabs, and only if enabled // in application preferences. m_show_btn_incompatible_presets = wxGetApp().app_config->get("show_incompatible_presets")[0] == '1' ? true : false; - bool show = m_show_btn_incompatible_presets && m_presets->name().compare("printer") != 0; + bool show = m_show_btn_incompatible_presets && m_type != Slic3r::Preset::TYPE_PRINTER; Layout(); show ? m_btn_hide_incompatible_presets->Show() : m_btn_hide_incompatible_presets->Hide(); // If the 'show / hide presets' button is hidden, hide the incompatible presets. @@ -2652,50 +2706,53 @@ void Tab::update_ui_from_settings() } // Return a callback to create a Tab widget to mark the preferences as compatible / incompatible to the current printer. -wxSizer* Tab::compatible_printers_widget(wxWindow* parent, wxCheckBox** checkbox, wxButton** btn) +wxSizer* Tab::compatible_widget_create(wxWindow* parent, PresetDependencies &deps) { - *checkbox = new wxCheckBox(parent, wxID_ANY, _(L("All"))); - *btn = new wxButton(parent, wxID_ANY, _(L(" Set "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT); + deps.checkbox = new wxCheckBox(parent, wxID_ANY, _(L("All"))); + deps.btn = new wxButton(parent, wxID_ANY, _(L(" Set "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT); - (*btn)->SetBitmap(wxBitmap(from_u8(Slic3r::var("printer_empty.png")), wxBITMAP_TYPE_PNG)); + deps.btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("printer_empty.png")), wxBITMAP_TYPE_PNG)); auto sizer = new wxBoxSizer(wxHORIZONTAL); - sizer->Add((*checkbox), 0, wxALIGN_CENTER_VERTICAL); - sizer->Add((*btn), 0, wxALIGN_CENTER_VERTICAL); + sizer->Add((deps.checkbox), 0, wxALIGN_CENTER_VERTICAL); + sizer->Add((deps.btn), 0, wxALIGN_CENTER_VERTICAL); - (*checkbox)->Bind(wxEVT_CHECKBOX, ([=](wxCommandEvent e) + deps.checkbox->Bind(wxEVT_CHECKBOX, ([this, &deps](wxCommandEvent e) { - (*btn)->Enable(!(*checkbox)->GetValue()); + deps.btn->Enable(! deps.checkbox->GetValue()); // 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()); - update_changed_ui(); + if (deps.checkbox->GetValue()) + this->load_key_value(deps.key_list, std::vector {}); + this->get_field(deps.key_condition)->toggle(deps.checkbox->GetValue()); + this->update_changed_ui(); }) ); - (*btn)->Bind(wxEVT_BUTTON, ([this, parent, checkbox, btn](wxCommandEvent e) + deps.btn->Bind(wxEVT_BUTTON, ([this, parent, &deps](wxCommandEvent e) { - // # Collect names of non-default non-external printer profiles. - PresetCollection *printers = &m_preset_bundle->printers; + // Collect names of non-default non-external profiles. + PrinterTechnology printer_technology = m_preset_bundle->printers.get_edited_preset().printer_technology(); + PresetCollection &depending_presets = (deps.type == Preset::TYPE_PRINTER) ? m_preset_bundle->printers : + (printer_technology == ptFFF) ? m_preset_bundle->prints : m_preset_bundle->sla_prints; wxArrayString presets; - for (size_t idx = 0; idx < printers->size(); ++idx) + for (size_t idx = 0; idx < depending_presets.size(); ++ idx) { - Preset& preset = printers->preset(idx); - if (!preset.is_default && !preset.is_external && !preset.is_system) - presets.Add(preset.name); + Preset& preset = depending_presets.preset(idx); + bool add = ! preset.is_default && ! preset.is_external; + if (add && deps.type == Preset::TYPE_PRINTER) + // Only add printers with the same technology as the active printer. + add &= preset.printer_technology() == printer_technology; + if (add) + presets.Add(from_u8(preset.name)); } - wxMultiChoiceDialog dlg(parent, - _(L("Select the printers this profile is compatible with.")), - _(L("Compatible printers")), presets); - // # Collect and set indices of printers marked as compatible. + wxMultiChoiceDialog dlg(parent, deps.dialog_title, deps.dialog_label, presets); + // Collect and set indices of depending_presets marked as compatible. wxArrayInt selections; - auto *compatible_printers = dynamic_cast(m_config->option("compatible_printers")); + auto *compatible_printers = dynamic_cast(m_config->option(deps.key_list)); if (compatible_printers != nullptr || !compatible_printers->values.empty()) for (auto preset_name : compatible_printers->values) for (size_t idx = 0; idx < presets.GetCount(); ++idx) - if (presets[idx].compare(preset_name) == 0) - { + if (presets[idx] == preset_name) { selections.Add(idx); break; } @@ -2708,15 +2765,23 @@ wxSizer* Tab::compatible_printers_widget(wxWindow* parent, wxCheckBox** checkbox for (auto idx : selections) value.push_back(presets[idx].ToStdString()); if (value.empty()) { - (*checkbox)->SetValue(1); - (*btn)->Disable(); + deps.checkbox->SetValue(1); + deps.btn->Disable(); } - // All printers have been made compatible with this preset. - load_key_value("compatible_printers", value); - update_changed_ui(); + // All depending_presets have been made compatible with this preset. + this->load_key_value(deps.key_list, value); + this->update_changed_ui(); } })); - return sizer; + return sizer; +} + +void Tab::compatible_widget_reload(PresetDependencies &deps) +{ + bool has_any = ! m_config->option(deps.key_list)->values.empty(); + has_any ? deps.btn->Enable() : deps.btn->Disable(); + deps.checkbox->SetValue(! has_any); + this->get_field(deps.key_condition)->toggle(! has_any); } void Tab::fill_icon_descriptions() @@ -2929,7 +2994,7 @@ void SavePresetWindow::accept() _(L("the following postfix are not allowed:")) + "\n\t" + //unusable_postfix); wxString::FromUTF8(unusable_postfix.c_str())); } - else if (m_chosen_name.compare("- default -") == 0) { + else if (m_chosen_name == "- default -") { show_error(this, _(L("The supplied name is not available."))); } else { @@ -2980,16 +3045,24 @@ void TabSLAMaterial::build() page = add_options_page(_(L("Dependencies")), "wrench.png"); optgroup = page->new_optgroup(_(L("Profile dependencies"))); - Line line = optgroup->create_single_option_line("compatible_printers");//Line { _(L("Compatible printers")), "" }; + Line line = optgroup->create_single_option_line("compatible_printers"); line.widget = [this](wxWindow* parent) { - return compatible_printers_widget(parent, &m_compatible_printers_checkbox, &m_compatible_printers_btn); + return compatible_widget_create(parent, m_compatible_printers); }; 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 = optgroup->create_single_option_line("compatible_prints"); + line.widget = [this](wxWindow* parent) { + return compatible_widget_create(parent, m_compatible_prints); + }; + optgroup->append_line(line, &m_colored_Label); + option = optgroup->get_option("compatible_prints_condition"); + option.opt.full_width = true; + optgroup->append_single_option_line(option); + line = Line{ "", "" }; line.full_width = 1; line.widget = [this](wxWindow* parent) { @@ -2998,6 +3071,14 @@ void TabSLAMaterial::build() optgroup->append_line(line); } +// Reload current config (aka presets->edited_preset->config) into the UI fields. +void TabSLAMaterial::reload_config() +{ + this->compatible_widget_reload(m_compatible_printers); + this->compatible_widget_reload(m_compatible_prints); + Tab::reload_config(); +} + void TabSLAMaterial::update() { if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF) @@ -3052,7 +3133,7 @@ void TabSLAPrint::build() optgroup = page->new_optgroup(_(L("Profile dependencies"))); Line line = optgroup->create_single_option_line("compatible_printers");//Line { _(L("Compatible printers")), "" }; line.widget = [this](wxWindow* parent) { - return compatible_printers_widget(parent, &m_compatible_printers_checkbox, &m_compatible_printers_btn); + return compatible_widget_create(parent, m_compatible_printers); }; optgroup->append_line(line, &m_colored_Label); @@ -3068,6 +3149,13 @@ void TabSLAPrint::build() optgroup->append_line(line); } +// Reload current config (aka presets->edited_preset->config) into the UI fields. +void TabSLAPrint::reload_config() +{ + this->compatible_widget_reload(m_compatible_printers); + Tab::reload_config(); +} + void TabSLAPrint::update() { if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF) diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 5ed6549bf..fb9bac7ac 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -122,8 +122,19 @@ protected: wxBoxSizer* m_left_sizer; wxTreeCtrl* m_treectrl; wxImageList* m_icons; - wxCheckBox* m_compatible_printers_checkbox; - wxButton* m_compatible_printers_btn; + + struct PresetDependencies { + Preset::Type type = Preset::TYPE_INVALID; + wxCheckBox *checkbox = nullptr; + wxButton *btn = nullptr; + std::string key_list; // "compatible_printers" + std::string key_condition; + std::string dialog_title; + std::string dialog_label; + }; + PresetDependencies m_compatible_printers; + PresetDependencies m_compatible_prints; + wxButton* m_undo_btn; wxButton* m_undo_to_sys_btn; wxButton* m_question_btn; @@ -199,13 +210,7 @@ public: wxStaticText* m_colored_Label = nullptr; public: - Tab() {} - Tab(wxNotebook* parent, const wxString& title, const char* name) : - m_parent(parent), m_title(title), m_name(name) { - Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBK_LEFT | wxTAB_TRAVERSAL, name); - set_type(); - wxGetApp().tabs_list.push_back(this); - } + Tab(wxNotebook* parent, const wxString& title, const char* name); ~Tab() { wxGetApp().delete_tab_from_list(this); } @@ -223,10 +228,6 @@ public: void select_preset(std::string preset_name = ""); bool may_discard_current_dirty_preset(PresetCollection* presets = nullptr, const std::string& new_printer_name = ""); bool may_switch_to_SLA_preset(); - wxSizer* compatible_printers_widget(wxWindow* parent, wxCheckBox** checkbox, wxButton** btn); - - void load_key_value(const std::string& opt_key, const boost::any& value, bool saved_value = false); - void reload_compatible_printers_widget(); void OnTreeSelChange(wxTreeEvent& event); void OnKeyDown(wxKeyEvent& event); @@ -270,7 +271,12 @@ public: void on_value_change(const std::string& opt_key, const boost::any& value); void update_wiping_button_visibility(); + protected: + wxSizer* compatible_widget_create(wxWindow* parent, PresetDependencies &deps); + void compatible_widget_reload(PresetDependencies &deps); + void load_key_value(const std::string& opt_key, const boost::any& value, bool saved_value = false); + void on_presets_changed(); void update_preset_description_line(); void update_frequently_changed_parameters(); @@ -278,11 +284,9 @@ protected: void set_tooltips_text(); }; -//Slic3r::GUI::Tab::Print; class TabPrint : public Tab { public: - TabPrint() {} TabPrint(wxNotebook* parent) : Tab(parent, _(L("Print Settings")), "print") {} ~TabPrint() {} @@ -296,14 +300,11 @@ public: void OnActivate() override; bool supports_printer_technology(const PrinterTechnology tech) override { return tech == ptFFF; } }; - -//Slic3r::GUI::Tab::Filament; class TabFilament : public Tab { ogStaticText* m_volumetric_speed_description_line; ogStaticText* m_cooling_description_line; public: - TabFilament() {} TabFilament(wxNotebook* parent) : Tab(parent, _(L("Filament Settings")), "filament") {} ~TabFilament() {} @@ -315,7 +316,6 @@ public: bool supports_printer_technology(const PrinterTechnology tech) override { return tech == ptFFF; } }; -//Slic3r::GUI::Tab::Printer; class TabPrinter : public Tab { bool m_has_single_extruder_MM_page = false; @@ -337,7 +337,6 @@ public: PrinterTechnology m_printer_technology = ptFFF; - TabPrinter() {} TabPrinter(wxNotebook* parent) : Tab(parent, _(L("Printer Settings")), "printer") {} ~TabPrinter() {} @@ -360,12 +359,12 @@ public: class TabSLAMaterial : public Tab { public: - TabSLAMaterial() {} TabSLAMaterial(wxNotebook* parent) : Tab(parent, _(L("SLA Material Settings")), "sla_material") {} ~TabSLAMaterial() {} void build() override; + void reload_config() override; void update() override; void init_options_list() override; bool supports_printer_technology(const PrinterTechnology tech) override { return tech == ptSLA; } @@ -374,11 +373,11 @@ public: class TabSLAPrint : public Tab { public: - TabSLAPrint() {} TabSLAPrint(wxNotebook* parent) : Tab(parent, _(L("SLA Print Settings")), "sla_print") {} ~TabSLAPrint() {} - void build() override; + void build() override; + void reload_config() override; void update() override; // void init_options_list() override; bool supports_printer_technology(const PrinterTechnology tech) override { return tech == ptSLA; }