Preset.hpp 43 KB

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