1 #ifndef slic3r_Preset_hpp_ 2 #define slic3r_Preset_hpp_ 3 4 #include <deque> 5 #include <set> 6 #include <unordered_map> 7 8 #include <boost/filesystem/path.hpp> 9 #include <boost/property_tree/ptree_fwd.hpp> 10 11 #include "PrintConfig.hpp" 12 #include "Semver.hpp" 13 14 namespace Slic3r { 15 16 class AppConfig; 17 class PresetBundle; 18 19 enum ConfigFileType 20 { 21 CONFIG_FILE_TYPE_UNKNOWN, 22 CONFIG_FILE_TYPE_APP_CONFIG, 23 CONFIG_FILE_TYPE_CONFIG, 24 CONFIG_FILE_TYPE_CONFIG_BUNDLE, 25 }; 26 27 extern ConfigFileType guess_config_file_type(const boost::property_tree::ptree &tree); 28 29 class VendorProfile 30 { 31 public: 32 std::string name; 33 std::string id; 34 Semver config_version; 35 std::string config_update_url; 36 std::string changelog_url; 37 38 struct PrinterVariant { PrinterVariantSlic3r::VendorProfile::PrinterVariant39 PrinterVariant() {} PrinterVariantSlic3r::VendorProfile::PrinterVariant40 PrinterVariant(const std::string &name) : name(name) {} 41 std::string name; 42 }; 43 44 struct PrinterModel { PrinterModelSlic3r::VendorProfile::PrinterModel45 PrinterModel() {} 46 std::string id; 47 std::string name; 48 PrinterTechnology technology; 49 std::string family; 50 std::vector<PrinterVariant> variants; 51 std::vector<std::string> default_materials; 52 // Vendor & Printer Model specific print bed model & texture. 53 std::string bed_model; 54 std::string bed_texture; 55 variantSlic3r::VendorProfile::PrinterModel56 PrinterVariant* variant(const std::string &name) { 57 for (auto &v : this->variants) 58 if (v.name == name) 59 return &v; 60 return nullptr; 61 } 62 variantSlic3r::VendorProfile::PrinterModel63 const PrinterVariant* variant(const std::string &name) const { return const_cast<PrinterModel*>(this)->variant(name); } 64 }; 65 std::vector<PrinterModel> models; 66 67 std::set<std::string> default_filaments; 68 std::set<std::string> default_sla_materials; 69 VendorProfile()70 VendorProfile() {} VendorProfile(std::string id)71 VendorProfile(std::string id) : id(std::move(id)) {} 72 valid() const73 bool valid() const { return ! name.empty() && ! id.empty() && config_version.valid(); } 74 75 // Load VendorProfile from an ini file. 76 // If `load_all` is false, only the header with basic info (name, version, URLs) is loaded. 77 static VendorProfile from_ini(const boost::filesystem::path &path, bool load_all=true); 78 static VendorProfile from_ini(const boost::property_tree::ptree &tree, const boost::filesystem::path &path, bool load_all=true); 79 num_variants() const80 size_t num_variants() const { size_t n = 0; for (auto &model : models) n += model.variants.size(); return n; } 81 std::vector<std::string> families() const; 82 operator <(const VendorProfile & rhs) const83 bool operator< (const VendorProfile &rhs) const { return this->id < rhs.id; } operator ==(const VendorProfile & rhs) const84 bool operator==(const VendorProfile &rhs) const { return this->id == rhs.id; } 85 }; 86 87 class Preset; 88 89 // Helper to hold a profile with its vendor definition, where the vendor definition may have been extracted from a parent system preset. 90 // The parent preset is only accessible through PresetCollection, therefore to allow definition of the various is_compatible_with methods 91 // outside of the PresetCollection, this composite is returned by PresetCollection::get_preset_with_vendor_profile() when needed. 92 struct PresetWithVendorProfile { PresetWithVendorProfileSlic3r::PresetWithVendorProfile93 PresetWithVendorProfile(const Preset &preset, const VendorProfile *vendor) : preset(preset), vendor(vendor) {} 94 const Preset &preset; 95 const VendorProfile *vendor; 96 }; 97 98 // Note: it is imporant that map is used here rather than unordered_map, 99 // because we need iterators to not be invalidated, 100 // because Preset and the ConfigWizard hold pointers to VendorProfiles. 101 // XXX: maybe set is enough (cf. changes in Wizard) 102 typedef std::map<std::string, VendorProfile> VendorMap; 103 104 class Preset 105 { 106 public: 107 enum Type 108 { 109 TYPE_INVALID, 110 TYPE_PRINT, 111 TYPE_SLA_PRINT, 112 TYPE_FILAMENT, 113 TYPE_SLA_MATERIAL, 114 TYPE_PRINTER, 115 // This type is here to support PresetConfigSubstitutions for physical printers, however it does not belong to the Preset class, 116 // PhysicalPrinter class is used instead. 117 TYPE_PHYSICAL_PRINTER, 118 }; 119 Preset(Type type,const std::string & name,bool is_default=false)120 Preset(Type type, const std::string &name, bool is_default = false) : type(type), is_default(is_default), name(name) {} 121 122 Type type = TYPE_INVALID; 123 124 // The preset represents a "default" set of properties, 125 // pulled from the default values of the PrintConfig (see PrintConfigDef for their definitions). 126 bool is_default; 127 // External preset points to a configuration, which has been loaded but not imported 128 // into the Slic3r default configuration location. 129 bool is_external = false; 130 // System preset is read-only. 131 bool is_system = false; 132 // Preset is visible, if it is associated with a printer model / variant that is enabled in the AppConfig 133 // or if it has no printer model / variant association. 134 // Also the "default" preset is only visible, if it is the only preset in the list. 135 bool is_visible = true; 136 // Has this preset been modified? 137 bool is_dirty = false; 138 // Is this preset compatible with the currently active printer? 139 bool is_compatible = true; 140 is_user() const141 bool is_user() const { return ! this->is_default && ! this->is_system; } 142 143 // Name of the preset, usually derived form the file name. 144 std::string name; 145 // File name of the preset. This could be a Print / Filament / Printer preset, 146 // or a Configuration file bundling the Print + Filament + Printer presets (in that case is_external and possibly is_system will be true), 147 // or it could be a G-code (again, is_external will be true). 148 std::string file; 149 // If this is a system profile, then there should be a vendor data available to display at the UI. 150 const VendorProfile *vendor = nullptr; 151 152 // Has this profile been loaded? 153 bool loaded = false; 154 155 // Configuration data, loaded from a file, or set from the defaults. 156 DynamicPrintConfig config; 157 158 // Alias of the preset 159 std::string alias; 160 // List of profile names, from which this profile was renamed at some point of time. 161 // This list is then used to match profiles by their names when loaded from .gcode, .3mf, .amf, 162 // and to match the "inherits" field of user profiles with updated system profiles. 163 std::vector<std::string> renamed_from; 164 165 void save(); 166 167 // Return a label of this preset, consisting of a name and a "(modified)" suffix, if this preset is dirty. 168 std::string label() const; 169 170 // Set the is_dirty flag if the provided config is different from the active one. set_dirty(const DynamicPrintConfig & config)171 void set_dirty(const DynamicPrintConfig &config) { this->is_dirty = ! this->config.diff(config).empty(); } set_dirty(bool dirty=true)172 void set_dirty(bool dirty = true) { this->is_dirty = dirty; } reset_dirty()173 void reset_dirty() { this->is_dirty = false; } 174 175 // Returns the name of the preset, from which this preset inherits. inherits(DynamicPrintConfig & cfg)176 static std::string& inherits(DynamicPrintConfig &cfg) { return cfg.option<ConfigOptionString>("inherits", true)->value; } inherits()177 std::string& inherits() { return Preset::inherits(this->config); } inherits() const178 const std::string& inherits() const { return Preset::inherits(const_cast<Preset*>(this)->config); } 179 180 // Returns the "compatible_prints_condition". compatible_prints_condition(DynamicPrintConfig & cfg)181 static std::string& compatible_prints_condition(DynamicPrintConfig &cfg) { return cfg.option<ConfigOptionString>("compatible_prints_condition", true)->value; } compatible_prints_condition()182 std::string& compatible_prints_condition() { 183 assert(this->type == TYPE_FILAMENT || this->type == TYPE_SLA_MATERIAL); 184 return Preset::compatible_prints_condition(this->config); 185 } compatible_prints_condition() const186 const std::string& compatible_prints_condition() const { return const_cast<Preset*>(this)->compatible_prints_condition(); } 187 188 // Returns the "compatible_printers_condition". compatible_printers_condition(DynamicPrintConfig & cfg)189 static std::string& compatible_printers_condition(DynamicPrintConfig &cfg) { return cfg.option<ConfigOptionString>("compatible_printers_condition", true)->value; } compatible_printers_condition()190 std::string& compatible_printers_condition() { 191 assert(this->type == TYPE_PRINT || this->type == TYPE_SLA_PRINT || this->type == TYPE_FILAMENT || this->type == TYPE_SLA_MATERIAL); 192 return Preset::compatible_printers_condition(this->config); 193 } compatible_printers_condition() const194 const std::string& compatible_printers_condition() const { return const_cast<Preset*>(this)->compatible_printers_condition(); } 195 196 // Return a printer technology, return ptFFF if the printer technology is not set. printer_technology(const DynamicPrintConfig & cfg)197 static PrinterTechnology printer_technology(const DynamicPrintConfig &cfg) { 198 auto *opt = cfg.option<ConfigOptionEnum<PrinterTechnology>>("printer_technology"); 199 // The following assert may trigger when importing some legacy profile, 200 // but it is safer to keep it here to capture the cases where the "printer_technology" key is queried, where it should not. 201 // assert(opt != nullptr); 202 return (opt == nullptr) ? ptFFF : opt->value; 203 } printer_technology() const204 PrinterTechnology printer_technology() const { return Preset::printer_technology(this->config); } 205 // This call returns a reference, it may add a new entry into the DynamicPrintConfig. printer_technology_ref()206 PrinterTechnology& printer_technology_ref() { return this->config.option<ConfigOptionEnum<PrinterTechnology>>("printer_technology", true)->value; } 207 208 // Set is_visible according to application config 209 void set_visible_from_appconfig(const AppConfig &app_config); 210 211 // Resize the extruder specific fields, initialize them with the content of the 1st extruder. set_num_extruders(unsigned int n)212 void set_num_extruders(unsigned int n) { this->config.set_num_extruders(n); } 213 214 // Sort lexicographically by a preset name. The preset name shall be unique across a single PresetCollection. operator <(const Preset & other) const215 bool operator<(const Preset &other) const { return this->name < other.name; } 216 217 static const std::vector<std::string>& print_options(); 218 static const std::vector<std::string>& filament_options(); 219 // Printer options contain the nozzle options. 220 static const std::vector<std::string>& printer_options(); 221 // Nozzle options of the printer options. 222 static const std::vector<std::string>& nozzle_options(); 223 // Printer machine limits, those are contained in printer_options(). 224 static const std::vector<std::string>& machine_limits_options(); 225 226 static const std::vector<std::string>& sla_printer_options(); 227 static const std::vector<std::string>& sla_material_options(); 228 static const std::vector<std::string>& sla_print_options(); 229 230 static void update_suffix_modified(const std::string& new_suffix_modified); 231 static const std::string& suffix_modified(); 232 static std::string remove_suffix_modified(const std::string& name); 233 static void normalize(DynamicPrintConfig &config); 234 // Report configuration fields, which are misplaced into a wrong group, remove them from the config. 235 static std::string remove_invalid_keys(DynamicPrintConfig &config, const DynamicPrintConfig &default_config); 236 237 protected: 238 friend class PresetCollection; 239 friend class PresetBundle; 240 }; 241 242 bool is_compatible_with_print (const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_print, const PresetWithVendorProfile &active_printer); 243 bool is_compatible_with_printer(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_printer, const DynamicPrintConfig *extra_config); 244 bool is_compatible_with_printer(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_printer); 245 246 enum class PresetSelectCompatibleType { 247 // Never select a compatible preset if the newly selected profile is not compatible. 248 Never, 249 // Only select a compatible preset if the active profile used to be compatible, but it is no more. 250 OnlyIfWasCompatible, 251 // Always select a compatible preset if the active profile is no more compatible. 252 Always 253 }; 254 255 // Substitutions having been performed during parsing a single configuration file. 256 struct PresetConfigSubstitutions { 257 // User readable preset name. 258 std::string preset_name; 259 // Type of the preset (Print / Filament / Printer ...) 260 Preset::Type preset_type; 261 enum class Source { 262 UserFile, 263 ConfigBundle, 264 }; 265 Source preset_source; 266 // Source of the preset. It may be empty in case of a ConfigBundle being loaded. 267 std::string preset_file; 268 // What config value has been substituted with what. 269 ConfigSubstitutions substitutions; 270 }; 271 272 // Substitutions having been performed during parsing a set of configuration files, for example when starting up 273 // PrusaSlicer and reading the user Print / Filament / Printer profiles. 274 using PresetsConfigSubstitutions = std::vector<PresetConfigSubstitutions>; 275 276 // Collections of presets of the same type (one of the Print, Filament or Printer type). 277 class PresetCollection 278 { 279 public: 280 // Initialize the PresetCollection with the "- default -" preset. 281 PresetCollection(Preset::Type type, const std::vector<std::string> &keys, const Slic3r::StaticPrintConfig &defaults, const std::string &default_name = "- default -"); 282 ~PresetCollection(); 283 284 typedef std::deque<Preset>::iterator Iterator; 285 typedef std::deque<Preset>::const_iterator ConstIterator; begin()286 Iterator begin() { return m_presets.begin() + m_num_default_presets; } begin() const287 ConstIterator begin() const { return m_presets.cbegin() + m_num_default_presets; } cbegin() const288 ConstIterator cbegin() const { return m_presets.cbegin() + m_num_default_presets; } end()289 Iterator end() { return m_presets.end(); } end() const290 ConstIterator end() const { return m_presets.cend(); } cend() const291 ConstIterator cend() const { return m_presets.cend(); } 292 293 void reset(bool delete_files); 294 type() const295 Preset::Type type() const { return m_type; } 296 // Name, to be used on the screen and in error messages. Not localized. 297 std::string name() const; 298 // Name, to be used as a section name in config bundle, and as a folder name for presets. 299 std::string section_name() const; operator ()() const300 const std::deque<Preset>& operator()() const { return m_presets; } 301 302 // Add default preset at the start of the collection, increment the m_default_preset counter. 303 void add_default_preset(const std::vector<std::string> &keys, const Slic3r::StaticPrintConfig &defaults, const std::string &preset_name); 304 305 // Load ini files of the particular type from the provided directory path. 306 void load_presets(const std::string &dir_path, const std::string &subdir, PresetsConfigSubstitutions& substitutions, ForwardCompatibilitySubstitutionRule rule); 307 308 // Load a preset from an already parsed config file, insert it into the sorted sequence of presets 309 // and select it, losing previous modifications. 310 Preset& load_preset(const std::string &path, const std::string &name, const DynamicPrintConfig &config, bool select = true); 311 Preset& load_preset(const std::string &path, const std::string &name, DynamicPrintConfig &&config, bool select = true); 312 313 // Returns a loaded preset, returns true if an existing preset was selected AND modified from config. 314 // In that case the successive filament loaded for a multi material printer should not be modified, but 315 // an external preset should be created instead. 316 enum class LoadAndSelect { 317 // Never select 318 Never, 319 // Always select 320 Always, 321 // Select a profile only if it was modified. 322 OnlyIfModified, 323 }; 324 std::pair<Preset*, bool> load_external_preset( 325 // Path to the profile source file (a G-code, an AMF or 3MF file, a config file) 326 const std::string &path, 327 // Name of the profile, derived from the source file name. 328 const std::string &name, 329 // Original name of the profile, extracted from the loaded config. Empty, if the name has not been stored. 330 const std::string &original_name, 331 // Config to initialize the preset from. 332 const DynamicPrintConfig &config, 333 // Select the preset after loading? 334 LoadAndSelect select = LoadAndSelect::Always); 335 336 // Save the preset under a new name. If the name is different from the old one, 337 // a new preset is stored into the list of presets. 338 // All presets are marked as not modified and the new preset is activated. 339 void save_current_preset(const std::string &new_name, bool detach = false); 340 341 // Delete the current preset, activate the first visible preset. 342 // returns true if the preset was deleted successfully. 343 bool delete_current_preset(); 344 // Delete the current preset, activate the first visible preset. 345 // returns true if the preset was deleted successfully. 346 bool delete_preset(const std::string& name); 347 348 // Enable / disable the "- default -" preset. 349 void set_default_suppressed(bool default_suppressed); is_default_suppressed() const350 bool is_default_suppressed() const { return m_default_suppressed; } 351 352 // Select a preset. If an invalid index is provided, the first visible preset is selected. 353 Preset& select_preset(size_t idx); 354 // Return the selected preset, without the user modifications applied. get_selected_preset()355 Preset& get_selected_preset() { return m_presets[m_idx_selected]; } get_selected_preset() const356 const Preset& get_selected_preset() const { return m_presets[m_idx_selected]; } get_selected_idx() const357 size_t get_selected_idx() const { return m_idx_selected; } 358 // Returns the name of the selected preset, or an empty string if no preset is selected. get_selected_preset_name() const359 std::string get_selected_preset_name() const { return (m_idx_selected == size_t(-1)) ? std::string() : this->get_selected_preset().name; } 360 // For the current edited preset, return the parent preset if there is one. 361 // If there is no parent preset, nullptr is returned. 362 // The parent preset may be a system preset or a user preset, which will be 363 // reflected by the UI. 364 const Preset* get_selected_preset_parent() const; 365 // Get parent preset for a child preset, based on the "inherits" field of a child, 366 // where the "inherits" profile name is searched for in both m_presets and m_map_system_profile_renamed. 367 const Preset* get_preset_parent(const Preset& child) const; 368 // Return the selected preset including the user modifications. get_edited_preset()369 Preset& get_edited_preset() { return m_edited_preset; } get_edited_preset() const370 const Preset& get_edited_preset() const { return m_edited_preset; } 371 372 // Return vendor of the first parent profile, for which the vendor is defined, or null if such profile does not exist. 373 PresetWithVendorProfile get_preset_with_vendor_profile(const Preset &preset) const; get_edited_preset_with_vendor_profile() const374 PresetWithVendorProfile get_edited_preset_with_vendor_profile() const { return this->get_preset_with_vendor_profile(this->get_edited_preset()); } 375 376 const std::string& get_preset_name_by_alias(const std::string& alias) const; 377 const std::string* get_preset_name_renamed(const std::string &old_name) const; 378 379 // used to update preset_choice from Tab get_presets() const380 const std::deque<Preset>& get_presets() const { return m_presets; } get_idx_selected()381 size_t get_idx_selected() { return m_idx_selected; } 382 static const std::string& get_suffix_modified(); 383 384 // Return a preset possibly with modifications. default_preset(size_t idx=0)385 Preset& default_preset(size_t idx = 0) { assert(idx < m_num_default_presets); return m_presets[idx]; } default_preset(size_t idx=0) const386 const Preset& default_preset(size_t idx = 0) const { assert(idx < m_num_default_presets); return m_presets[idx]; } default_preset_for(const DynamicPrintConfig &) const387 virtual const Preset& default_preset_for(const DynamicPrintConfig & /* config */) const { return this->default_preset(); } 388 // Return a preset by an index. If the preset is active, a temporary copy is returned. preset(size_t idx)389 Preset& preset(size_t idx) { return (idx == m_idx_selected) ? m_edited_preset : m_presets[idx]; } preset(size_t idx) const390 const Preset& preset(size_t idx) const { return const_cast<PresetCollection*>(this)->preset(idx); } discard_current_changes()391 void discard_current_changes() { m_presets[m_idx_selected].reset_dirty(); m_edited_preset = m_presets[m_idx_selected]; } 392 393 // Return a preset by its name. If the preset is active, a temporary copy is returned. 394 // If a preset is not found by its name, null is returned. 395 Preset* find_preset(const std::string &name, bool first_visible_if_not_found = false); find_preset(const std::string & name,bool first_visible_if_not_found=false) const396 const Preset* find_preset(const std::string &name, bool first_visible_if_not_found = false) const 397 { return const_cast<PresetCollection*>(this)->find_preset(name, first_visible_if_not_found); } 398 399 size_t first_visible_idx() const; 400 // Return index of the first compatible preset. Certainly at least the '- default -' preset shall be compatible. 401 // If one of the prefered_alternates is compatible, select it. 402 template<typename PreferedCondition> first_compatible_idx(PreferedCondition prefered_condition) const403 size_t first_compatible_idx(PreferedCondition prefered_condition) const 404 { 405 size_t i = m_default_suppressed ? m_num_default_presets : 0; 406 size_t n = this->m_presets.size(); 407 size_t i_compatible = n; 408 int match_quality = -1; 409 for (; i < n; ++ i) 410 // Since we use the filament selection from Wizard, it's needed to control the preset visibility too 411 if (m_presets[i].is_compatible && m_presets[i].is_visible) { 412 int this_match_quality = prefered_condition(m_presets[i]); 413 if (this_match_quality > match_quality) { 414 if (match_quality == std::numeric_limits<int>::max()) 415 // Better match will not be found. 416 return i; 417 // Store the first compatible profile with highest match quality into i_compatible. 418 i_compatible = i; 419 match_quality = this_match_quality; 420 } 421 } 422 return (i_compatible == n) ? 423 // No compatible preset found, return the default preset. 424 0 : 425 // Compatible preset found. 426 i_compatible; 427 } 428 // Return index of the first compatible preset. Certainly at least the '- default -' preset shall be compatible. __anon9cc1ea150102(const Preset&) 429 size_t first_compatible_idx() const { return this->first_compatible_idx([](const Preset&) -> int { return 0; }); } 430 431 // Return index of the first visible preset. Certainly at least the '- default -' preset shall be visible. 432 // Return the first visible preset. Certainly at least the '- default -' preset shall be visible. first_visible()433 Preset& first_visible() { return this->preset(this->first_visible_idx()); } first_visible() const434 const Preset& first_visible() const { return this->preset(this->first_visible_idx()); } first_compatible()435 Preset& first_compatible() { return this->preset(this->first_compatible_idx()); } 436 template<typename PreferedCondition> first_compatible(PreferedCondition prefered_condition)437 Preset& first_compatible(PreferedCondition prefered_condition) { return this->preset(this->first_compatible_idx(prefered_condition)); } first_compatible() const438 const Preset& first_compatible() const { return this->preset(this->first_compatible_idx()); } 439 440 // Return number of presets including the "- default -" preset. size() const441 size_t size() const { return m_presets.size(); } has_defaults_only() const442 bool has_defaults_only() const { return m_presets.size() <= m_num_default_presets; } 443 444 // For Print / Filament presets, disable those, which are not compatible with the printer. 445 template<typename PreferedCondition> update_compatible(const PresetWithVendorProfile & active_printer,const PresetWithVendorProfile * active_print,PresetSelectCompatibleType select_other_if_incompatible,PreferedCondition prefered_condition)446 void update_compatible(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, PresetSelectCompatibleType select_other_if_incompatible, PreferedCondition prefered_condition) 447 { 448 if (this->update_compatible_internal(active_printer, active_print, select_other_if_incompatible) == (size_t)-1) 449 // Find some other compatible preset, or the "-- default --" preset. 450 this->select_preset(this->first_compatible_idx(prefered_condition)); 451 } update_compatible(const PresetWithVendorProfile & active_printer,const PresetWithVendorProfile * active_print,PresetSelectCompatibleType select_other_if_incompatible)452 void update_compatible(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, PresetSelectCompatibleType select_other_if_incompatible) 453 { this->update_compatible(active_printer, active_print, select_other_if_incompatible, [](const Preset&) -> int { return 0; }); } 454 num_visible() const455 size_t num_visible() const { return std::count_if(m_presets.begin(), m_presets.end(), [](const Preset &preset){return preset.is_visible;}); } 456 457 // Compare the content of get_selected_preset() with get_edited_preset() configs, return true if they differ. current_is_dirty() const458 bool current_is_dirty() const { return ! this->current_dirty_options().empty(); } 459 // Compare the content of get_selected_preset() with get_edited_preset() configs, return the list of keys where they differ. current_dirty_options(const bool deep_compare=false) const460 std::vector<std::string> current_dirty_options(const bool deep_compare = false) const 461 { return dirty_options(&this->get_edited_preset(), &this->get_selected_preset(), deep_compare); } 462 // Compare the content of get_selected_preset() with get_edited_preset() configs, return the list of keys where they differ. current_different_from_parent_options(const bool deep_compare=false) const463 std::vector<std::string> current_different_from_parent_options(const bool deep_compare = false) const 464 { return dirty_options(&this->get_edited_preset(), this->get_selected_preset_parent(), deep_compare); } 465 466 // Return a sorted list of system preset names. 467 // Used for validating the "inherits" flag when importing user's config bundles. 468 // Returns names of all system presets including the former names of these presets. 469 std::vector<std::string> system_preset_names() const; 470 471 // Update a dirty flag of the current preset 472 // Return true if the dirty flag changed. 473 bool update_dirty(); 474 475 // Select a profile by its name. Return true if the selection changed. 476 // Without force, the selection is only updated if the index changes. 477 // With force, the changes are reverted if the new index is the same as the old index. 478 bool select_preset_by_name(const std::string &name, bool force); 479 480 // Generate a file path from a profile name. Add the ".ini" suffix if it is missing. 481 std::string path_from_name(const std::string &new_name) const; 482 num_default_presets()483 size_t num_default_presets() { return m_num_default_presets; } 484 485 protected: 486 // Select a preset, if it exists. If it does not exist, select an invalid (-1) index. 487 // This is a temporary state, which shall be fixed immediately by the following step. 488 bool select_preset_by_name_strict(const std::string &name); 489 490 // Merge one vendor's presets with the other vendor's presets, report duplicates. 491 std::vector<std::string> merge_presets(PresetCollection &&other, const VendorMap &new_vendors); 492 493 // Update m_map_alias_to_profile_name from loaded system profiles. 494 void update_map_alias_to_profile_name(); 495 496 // Update m_map_system_profile_renamed from loaded system profiles. 497 void update_map_system_profile_renamed(); 498 499 private: 500 PresetCollection(); 501 PresetCollection(const PresetCollection &other); 502 PresetCollection& operator=(const PresetCollection &other); 503 504 // Find a preset position in the sorted list of presets. 505 // The "-- default -- " preset is always the first, so it needs 506 // to be handled differently. 507 // If a preset does not exist, an iterator is returned indicating where to insert a preset with the same name. find_preset_internal(const std::string & name)508 std::deque<Preset>::iterator find_preset_internal(const std::string &name) 509 { 510 auto it = Slic3r::lower_bound_by_predicate(m_presets.begin() + m_num_default_presets, m_presets.end(), [&name](const auto& l) { return l.name < name; }); 511 if (it == m_presets.end() || it->name != name) { 512 // Preset has not been not found in the sorted list of non-default presets. Try the defaults. 513 for (size_t i = 0; i < m_num_default_presets; ++ i) 514 if (m_presets[i].name == name) { 515 it = m_presets.begin() + i; 516 break; 517 } 518 } 519 return it; 520 } find_preset_internal(const std::string & name) const521 std::deque<Preset>::const_iterator find_preset_internal(const std::string &name) const 522 { return const_cast<PresetCollection*>(this)->find_preset_internal(name); } find_preset_renamed(const std::string & name)523 std::deque<Preset>::iterator find_preset_renamed(const std::string &name) { 524 auto it_renamed = m_map_system_profile_renamed.find(name); 525 auto it = (it_renamed == m_map_system_profile_renamed.end()) ? m_presets.end() : this->find_preset_internal(it_renamed->second); 526 assert((it_renamed == m_map_system_profile_renamed.end()) || (it != m_presets.end() && it->name == it_renamed->second)); 527 return it; 528 } find_preset_renamed(const std::string & name) const529 std::deque<Preset>::const_iterator find_preset_renamed(const std::string &name) const 530 { return const_cast<PresetCollection*>(this)->find_preset_renamed(name); } 531 532 size_t update_compatible_internal(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, PresetSelectCompatibleType unselect_if_incompatible); 533 534 static std::vector<std::string> dirty_options(const Preset *edited, const Preset *reference, const bool is_printer_type = false); 535 536 // Type of this PresetCollection: TYPE_PRINT, TYPE_FILAMENT or TYPE_PRINTER. 537 Preset::Type m_type; 538 // List of presets, starting with the "- default -" preset. 539 // Use deque to force the container to allocate an object per each entry, 540 // so that the addresses of the presets don't change during resizing of the container. 541 std::deque<Preset> m_presets; 542 // System profiles may have aliases. Map to the full profile name. 543 std::vector<std::pair<std::string, std::string>> m_map_alias_to_profile_name; 544 // Map from old system profile name to a current system profile name. 545 std::map<std::string, std::string> m_map_system_profile_renamed; 546 // Initially this preset contains a copy of the selected preset. Later on, this copy may be modified by the user. 547 Preset m_edited_preset; 548 // Selected preset. 549 size_t m_idx_selected; 550 // Is the "- default -" preset suppressed? 551 bool m_default_suppressed = true; 552 size_t m_num_default_presets = 0; 553 554 // Path to the directory to store the config files into. 555 std::string m_dir_path; 556 557 // to access select_preset_by_name_strict() 558 friend class PresetBundle; 559 }; 560 561 // Printer supports the FFF and SLA technologies, with different set of configuration values, 562 // therefore this PresetCollection needs to handle two defaults. 563 class PrinterPresetCollection : public PresetCollection 564 { 565 public: PrinterPresetCollection(Preset::Type type,const std::vector<std::string> & keys,const Slic3r::StaticPrintConfig & defaults,const std::string & default_name="- default -")566 PrinterPresetCollection(Preset::Type type, const std::vector<std::string> &keys, const Slic3r::StaticPrintConfig &defaults, const std::string &default_name = "- default -") : 567 PresetCollection(type, keys, defaults, default_name) {} 568 const Preset& default_preset_for(const DynamicPrintConfig &config) const override; 569 570 const Preset* find_by_model_id(const std::string &model_id) const; 571 }; 572 573 namespace PresetUtils { 574 // PrinterModel of a system profile, from which this preset is derived, or null if it is not derived from a system profile. 575 const VendorProfile::PrinterModel* system_printer_model(const Preset &preset); 576 std::string system_printer_bed_model(const Preset& preset); 577 std::string system_printer_bed_texture(const Preset& preset); 578 } // namespace PresetUtils 579 580 581 ////////////////////////////////////////////////////////////////////// 582 583 class PhysicalPrinter 584 { 585 public: 586 PhysicalPrinter(const std::string& name, const DynamicPrintConfig &default_config); 587 PhysicalPrinter(const std::string& name, const DynamicPrintConfig &default_config, const Preset& preset); 588 void set_name(const std::string &name); 589 590 // Name of the Physical Printer, usually derived form the file name. 591 std::string name; 592 // File name of the Physical Printer. 593 std::string file; 594 // Configuration data, loaded from a file, or set from the defaults. 595 DynamicPrintConfig config; 596 // set of presets used with this physical printer 597 std::set<std::string> preset_names; 598 599 // Has this profile been loaded? 600 bool loaded = false; 601 602 static std::string separator(); 603 static const std::vector<std::string>& printer_options(); 604 static const std::vector<std::string>& print_host_options(); 605 static std::vector<std::string> presets_with_print_host_information(const PrinterPresetCollection& printer_presets); 606 static bool has_print_host_information(const DynamicPrintConfig& config); 607 608 const std::set<std::string>& get_preset_names() const; 609 610 bool has_empty_config() const; 611 void update_preset_names_in_config(); 612 save()613 void save() { this->config.save(this->file); } 614 void save(const std::string& file_name_from, const std::string& file_name_to); 615 616 void update_from_preset(const Preset& preset); 617 void update_from_config(const DynamicPrintConfig &new_config); 618 619 // add preset to the preset_names 620 // return false, if preset with this name is already exist in the set 621 bool add_preset(const std::string& preset_name); 622 bool delete_preset(const std::string& preset_name); 623 void reset_presets(); 624 625 // Return a printer technology, return ptFFF if the printer technology is not set. printer_technology(const DynamicPrintConfig & cfg)626 static PrinterTechnology printer_technology(const DynamicPrintConfig& cfg) { 627 auto* opt = cfg.option<ConfigOptionEnum<PrinterTechnology>>("printer_technology"); 628 // The following assert may trigger when importing some legacy profile, 629 // but it is safer to keep it here to capture the cases where the "printer_technology" key is queried, where it should not. 630 return (opt == nullptr) ? ptFFF : opt->value; 631 } printer_technology() const632 PrinterTechnology printer_technology() const { return printer_technology(this->config); } 633 634 // Sort lexicographically by a preset name. The preset name shall be unique across a single PresetCollection. operator <(const PhysicalPrinter & other) const635 bool operator<(const PhysicalPrinter& other) const { return this->name < other.name; } 636 637 // get full printer name included a name of the preset 638 std::string get_full_name(std::string preset_name) const; 639 640 // get printer name from the full name uncluded preset name 641 static std::string get_short_name(std::string full_name); 642 643 // get preset name from the full name uncluded printer name 644 static std::string get_preset_name(std::string full_name); 645 646 protected: 647 friend class PhysicalPrinterCollection; 648 }; 649 650 651 // --------------------------------- 652 // *** PhysicalPrinterCollection *** 653 // --------------------------------- 654 655 // Collections of physical printers 656 class PhysicalPrinterCollection 657 { 658 public: 659 PhysicalPrinterCollection(const std::vector<std::string>& keys); ~PhysicalPrinterCollection()660 ~PhysicalPrinterCollection() {} 661 662 typedef std::deque<PhysicalPrinter>::iterator Iterator; 663 typedef std::deque<PhysicalPrinter>::const_iterator ConstIterator; begin()664 Iterator begin() { return m_printers.begin(); } begin() const665 ConstIterator begin() const { return m_printers.cbegin(); } cbegin() const666 ConstIterator cbegin() const { return m_printers.cbegin(); } end()667 Iterator end() { return m_printers.end(); } end() const668 ConstIterator end() const { return m_printers.cend(); } cend() const669 ConstIterator cend() const { return m_printers.cend(); } 670 empty() const671 bool empty() const {return m_printers.empty(); } 672 reset(bool delete_files)673 void reset(bool delete_files) {}; 674 operator ()() const675 const std::deque<PhysicalPrinter>& operator()() const { return m_printers; } 676 677 // Load ini files of the particular type from the provided directory path. 678 void load_printers(const std::string& dir_path, const std::string& subdir, PresetsConfigSubstitutions& substitutions, ForwardCompatibilitySubstitutionRule rule); 679 void load_printers_from_presets(PrinterPresetCollection &printer_presets); 680 // Load printer from the loaded configuration 681 void load_printer(const std::string& path, const std::string& name, DynamicPrintConfig&& config, bool select, bool save=false); 682 683 // Save the printer under a new name. If the name is different from the old one, 684 // a new printer is stored into the list of printers. 685 // New printer is activated. 686 void save_printer(PhysicalPrinter& printer, const std::string& renamed_from = ""); 687 688 // Delete the current preset, activate the first visible preset. 689 // returns true if the preset was deleted successfully. 690 bool delete_printer(const std::string& name); 691 // Delete the selected preset 692 // returns true if the preset was deleted successfully. 693 bool delete_selected_printer(); 694 // Delete preset_name preset from all printers: 695 // If there is last preset for the printer and first_check== false, then delete this printer 696 // returns true if all presets were deleted successfully. 697 bool delete_preset_from_printers(const std::string& preset_name); 698 699 // Get list of printers which have more than one preset and "preset_name" preset is one of them 700 std::vector<std::string> get_printers_with_preset( const std::string &preset_name); 701 // Get list of printers which has only "preset_name" preset 702 std::vector<std::string> get_printers_with_only_preset( const std::string &preset_name); 703 704 // Return the selected preset, without the user modifications applied. get_selected_printer()705 PhysicalPrinter& get_selected_printer() { return m_printers[m_idx_selected]; } get_selected_printer() const706 const PhysicalPrinter& get_selected_printer() const { return m_printers[m_idx_selected]; } 707 get_selected_idx() const708 size_t get_selected_idx() const { return m_idx_selected; } 709 // Returns the name of the selected preset, or an empty string if no preset is selected. get_selected_printer_name() const710 std::string get_selected_printer_name() const { return (m_idx_selected == size_t(-1)) ? std::string() : this->get_selected_printer().name; } 711 // Returns the config of the selected printer, or nullptr if no printer is selected. get_selected_printer_config()712 DynamicPrintConfig* get_selected_printer_config() { return (m_idx_selected == size_t(-1)) ? nullptr : &(this->get_selected_printer().config); } 713 // Returns the config of the selected printer, or nullptr if no printer is selected. get_selected_printer_technology()714 PrinterTechnology get_selected_printer_technology() { return (m_idx_selected == size_t(-1)) ? PrinterTechnology::ptAny : this->get_selected_printer().printer_technology(); } 715 716 // Each physical printer can have a several related preset, 717 // so, use the next functions to get an exact names of selections in the list: 718 // Returns the full name of the selected printer, or an empty string if no preset is selected. 719 std::string get_selected_full_printer_name() const; 720 // Returns the printer model of the selected preset, or an empty string if no preset is selected. get_selected_printer_preset_name() const721 std::string get_selected_printer_preset_name() const { return (m_idx_selected == size_t(-1)) ? std::string() : m_selected_preset; } 722 723 // Select printer by the full printer name, which contains name of printer, separator and name of selected preset 724 // If full_name doesn't contain name of selected preset, then select first preset in the list for this printer 725 void select_printer(const std::string& full_name); 726 void select_printer(const PhysicalPrinter& printer); 727 void select_printer(const std::string& printer_name, const std::string& preset_name); 728 bool has_selection() const; 729 void unselect_printer() ; 730 bool is_selected(ConstIterator it, const std::string &preset_name) const; 731 732 // Return a printer by an index. If the printer is active, a temporary copy is returned. printer(size_t idx)733 PhysicalPrinter& printer(size_t idx) { return m_printers[idx]; } printer(size_t idx) const734 const PhysicalPrinter& printer(size_t idx) const { return const_cast<PhysicalPrinterCollection*>(this)->printer(idx); } 735 736 // Return a preset by its name. If the preset is active, a temporary copy is returned. 737 // If a preset is not found by its name, null is returned. 738 // It is possible case (in)sensitive search 739 PhysicalPrinter* find_printer(const std::string& name, bool case_sensitive_search = true); find_printer(const std::string & name,bool case_sensitive_search=true) const740 const PhysicalPrinter* find_printer(const std::string& name, bool case_sensitive_search = true) const 741 { 742 return const_cast<PhysicalPrinterCollection*>(this)->find_printer(name, case_sensitive_search); 743 } 744 745 // Generate a file path from a profile name. Add the ".ini" suffix if it is missing. 746 std::string path_from_name(const std::string& new_name) const; 747 default_config() const748 const DynamicPrintConfig& default_config() const { return m_default_config; } 749 750 private: 751 PhysicalPrinterCollection& operator=(const PhysicalPrinterCollection& other); 752 753 // Find a physical printer position in the sorted list of printers. 754 // The name of a printer should be unique and case insensitive 755 // Use this functions with case_sensitive_search = false, when you need case insensitive search 756 std::deque<PhysicalPrinter>::iterator find_printer_internal(const std::string& name, bool case_sensitive_search = true); find_printer_internal(const std::string & name,bool case_sensitive_search=true) const757 std::deque<PhysicalPrinter>::const_iterator find_printer_internal(const std::string& name, bool case_sensitive_search = true) const 758 { 759 return const_cast<PhysicalPrinterCollection*>(this)->find_printer_internal(name); 760 } 761 762 PhysicalPrinter* find_printer_with_same_config( const DynamicPrintConfig &config); 763 764 // List of printers 765 // Use deque to force the container to allocate an object per each entry, 766 // so that the addresses of the presets don't change during resizing of the container. 767 std::deque<PhysicalPrinter> m_printers; 768 769 // Default config for a physical printer containing all key/value pairs of PhysicalPrinter::printer_options(). 770 DynamicPrintConfig m_default_config; 771 772 // Selected printer. 773 size_t m_idx_selected = size_t(-1); 774 // The name of the preset which is currently select for this printer 775 std::string m_selected_preset; 776 777 // Path to the directory to store the config files into. 778 std::string m_dir_path; 779 }; 780 781 782 } // namespace Slic3r 783 784 #endif /* slic3r_Preset_hpp_ */ 785