From d58c8b1bbd8fffc8de12d1bb20c95b4317c61ccf Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Wed, 1 Feb 2023 15:31:10 +0100 Subject: [PATCH] Refactor of ConfigDef / ConfigOptionDef / PrintConfigDef / Field and other UI elements to handle enums in a generic way. Needs a review by @yusanka --- src/libslic3r/Config.cpp | 35 +- src/libslic3r/Config.hpp | 281 ++++++++++-- src/libslic3r/Print.cpp | 4 +- src/libslic3r/PrintConfig.cpp | 524 +++++++++-------------- src/slic3r/GUI/ConfigManipulation.cpp | 92 ++-- src/slic3r/GUI/ConfigWizard.cpp | 15 +- src/slic3r/GUI/Field.cpp | 122 ++---- src/slic3r/GUI/GUI.cpp | 33 +- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 6 +- src/slic3r/GUI/PhysicalPrinterDialog.cpp | 23 +- src/slic3r/GUI/Plater.cpp | 20 +- src/slic3r/GUI/Preferences.cpp | 28 +- src/slic3r/GUI/Search.cpp | 2 +- src/slic3r/GUI/UnsavedChangesDialog.cpp | 28 +- 14 files changed, 627 insertions(+), 586 deletions(-) diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index 2cfb0740c..51870e93d 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -268,7 +268,7 @@ ConfigOption* ConfigOptionDef::create_empty_option() const // case coPoint3s: return new ConfigOptionPoint3s(); case coBool: return new ConfigOptionBool(); case coBools: return new ConfigOptionBools(); - case coEnum: return new ConfigOptionEnumGeneric(this->enum_keys_map); + case coEnum: return new ConfigOptionEnumGeneric(this->enum_def->m_enum_keys_map); default: throw ConfigurationError(std::string("Unknown option type for option ") + this->label); } } @@ -279,7 +279,7 @@ ConfigOption* ConfigOptionDef::create_default_option() const if (this->default_value) return (this->default_value->type() == coEnum) ? // Special case: For a DynamicConfig, convert a templated enum to a generic enum. - new ConfigOptionEnumGeneric(this->enum_keys_map, this->default_value->getInt()) : + new ConfigOptionEnumGeneric(this->enum_def->m_enum_keys_map, this->default_value->getInt()) : this->default_value->clone(); return this->create_empty_option(); } @@ -303,6 +303,31 @@ ConfigOptionDef* ConfigDef::add_nullable(const t_config_option_key &opt_key, Con return def; } +void ConfigDef::finalize() +{ + // Validate & finalize open & closed enums. + for (std::pair &kvp : options) { + ConfigOptionDef& def = kvp.second; + if (def.type == coEnum) { + assert(def.enum_def); + assert(def.enum_def->is_valid_closed_enum()); + assert(def.gui_type != ConfigOptionDef::GUIType::i_enum_open && + def.gui_type != ConfigOptionDef::GUIType::f_enum_open && + def.gui_type != ConfigOptionDef::GUIType::select_open); + def.enum_def->finalize_closed_enum(); + } else if (def.gui_type == ConfigOptionDef::GUIType::i_enum_open || def.gui_type == ConfigOptionDef::GUIType::f_enum_open || + def.gui_type == ConfigOptionDef::GUIType::select_open) { + assert(def.enum_def); + assert(def.enum_def->is_valid_open_enum()); + assert(def.gui_type != ConfigOptionDef::GUIType::i_enum_open || def.type == coInt || def.type == coInts); + assert(def.gui_type != ConfigOptionDef::GUIType::f_enum_open || def.type == coFloat || def.type == coPercent || def.type == coFloatOrPercent); + assert(def.gui_type != ConfigOptionDef::GUIType::select_open || def.type == coString || def.type == coStrings); + } else { + assert(! def.enum_def); + } + } +} + std::ostream& ConfigDef::print_cli_help(std::ostream& out, bool show_defaults, std::function filter) const { // prepare a function for wrapping text @@ -378,8 +403,8 @@ std::ostream& ConfigDef::print_cli_help(std::ostream& out, bool show_defaults, s descr += " ("; if (!def.sidetext.empty()) { descr += def.sidetext + ", "; - } else if (!def.enum_values.empty()) { - descr += boost::algorithm::join(def.enum_values, ", ") + "; "; + } else if (def.enum_def->has_values()) { + descr += boost::algorithm::join(def.enum_def->values(), ", ") + "; "; } descr += "default: " + def.default_value->serialize() + ")"; } @@ -1142,7 +1167,7 @@ bool DynamicConfig::read_cli(int argc, const char* const argv[], t_config_option } const t_config_option_key &opt_key = it->second; - const ConfigOptionDef &optdef = this->def()->options.at(opt_key); + const ConfigOptionDef &optdef = *this->option_def(opt_key); // If the option type expects a value and it was not already provided, // look for it in the next token. diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index c0c7abba0..f0f37c277 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include "libslic3r.h" @@ -226,6 +227,7 @@ enum ForwardCompatibilitySubstitutionRule EnableSilentDisableSystem, }; +class ConfigDef; class ConfigOption; class ConfigOptionDef; // For forward definition of ConfigOption in ConfigOptionUniquePtr, we have to define a custom deleter. @@ -1547,7 +1549,7 @@ public: return false; } - // Map from an enum name to an enum integer value. + // Map from an enum integer value to name. static const t_config_enum_names& get_enum_names(); // Map from an enum name to an enum integer value. static const t_config_enum_values& get_enum_values(); @@ -1619,6 +1621,177 @@ private: template void serialize(Archive& ar) { ar(cereal::base_class(this)); } }; +// Definition of values / labels for a combo box. +// Mostly used for closed enums (when type == coEnum), but may be used for +// open enums with ints resp. floats, if gui_type is set to GUIType::i_enum_open" resp. GUIType::f_enum_open. +class ConfigOptionEnumDef { +public: + bool has_values() const { return ! m_values.empty(); } + bool has_labels() const { return ! m_labels.empty(); } + const std::vector& values() const { return m_values; } + const std::string& value(int idx) const { return m_values[idx]; } + // Used for open enums (gui_type is set to GUIType::i_enum_open" resp. GUIType::f_enum_open). + // If values not defined, use labels. + const std::vector& enums() const { + assert(this->is_valid_open_enum()); + return this->has_values() ? m_values : m_labels; + } + // Used for closed enums. If labels are not defined, use values instead. + const std::vector& labels() const { return this->has_labels() ? m_labels : m_values; } + const std::string& label(int idx) const { return this->labels()[idx]; } + + // Look up a closed enum value of this combo box based on an index of the combo box value / label. + // Such a mapping should always succeed. + int index_to_enum(int index) const { + // It has to be a closed enum, thus values have to be defined. + assert(this->is_valid_closed_enum()); + assert(index >= 0 && index < int(m_values.size())); + if (m_values_ordinary) + return index; + else { + auto it = m_enum_keys_map->find(m_values[index]); + assert(it != m_enum_keys_map->end()); + return it->second; + } + } + + // Look up an index of value / label of this combo box based on enum value. + // Such a mapping may fail, thus an optional is returned. + std::optional enum_to_index(int enum_val) const { + assert(this->is_valid_closed_enum()); + assert(enum_val >= 0 && enum_val < int(m_enum_names->size())); + if (m_values_ordinary) + return { enum_val }; + else { + auto it = std::find(m_values.begin(), m_values.end(), (*m_enum_names)[enum_val]); + return it == m_values.end() ? std::optional{} : std::optional{ int(it - m_values.begin()) }; + } + } + + // Look up an index of value / label of this combo box based on value string. + std::optional value_to_index(const std::string &value) const { + assert(this->is_valid_open_enum() || this->is_valid_closed_enum()); + auto it = std::find(m_values.begin(), m_values.end(), value); + return it == m_values.end() ? + std::optional{} : std::optional{ it - m_values.begin() }; + } + + // Look up an index of label of this combo box. Used for open enums. + std::optional label_to_index(const std::string &value) const { + assert(is_valid_open_enum()); + const auto &ls = this->labels(); + auto it = std::find(ls.begin(), ls.end(), value); + return it == ls.end() ? + std::optional{} : std::optional{ it - ls.begin() }; + } + + std::optional> enum_to_value(int enum_val) const { + assert(this->is_valid_closed_enum()); + auto opt = this->enum_to_index(enum_val); + return opt.has_value() ? + std::optional>{ this->value(opt.value()) } : + std::optional>{}; + } + + std::optional> enum_to_label(int enum_val) const { + assert(this->is_valid_closed_enum()); + auto opt = this->enum_to_index(enum_val); + return opt.has_value() ? + std::optional>{ this->label(opt.value()) } : + std::optional>{}; + } + +#ifndef NDEBUG + bool is_valid_closed_enum() const { + return m_enum_names != nullptr && m_enum_keys_map != nullptr && + ! m_values.empty() && (m_labels.empty() || m_values.size() == m_labels.size()); + } + bool is_valid_open_enum() const { + return m_enum_names == nullptr && m_enum_keys_map == nullptr && + (! m_values.empty() || ! m_labels.empty()) && (m_values.empty() || m_labels.empty() || m_values.size() == m_labels.size()); + } +#endif // NDEBUG + + void clear() { + m_values_ordinary = false; + m_enum_names = nullptr; + m_enum_keys_map = nullptr; + m_values.clear(); + m_labels.clear(); + } + + ConfigOptionEnumDef* clone() const { return new ConfigOptionEnumDef{ *this }; } + +private: + friend ConfigDef; + friend ConfigOptionDef; + + // Only allow ConfigOptionEnumDef() to be created from ConfigOptionDef. + ConfigOptionEnumDef() = default; + + void set_values(const std::vector &v) { + m_values = v; + assert(m_labels.empty() || m_labels.size() == m_values.size()); + } + void set_values(const std::initializer_list il) { + m_values.clear(); + m_values.reserve(il.size()); + for (const std::string_view p : il) + m_values.emplace_back(p); + assert(m_labels.empty() || m_labels.size() == m_values.size()); + } + void set_values(const std::initializer_list> il) { + m_values.clear(); + m_values.reserve(il.size()); + m_labels.clear(); + m_labels.reserve(il.size()); + for (const std::pair p : il) { + m_values.emplace_back(p.first); + m_labels.emplace_back(p.second); + } + } + void set_labels(const std::initializer_list il) { + m_labels.clear(); + m_labels.reserve(il.size()); + for (const std::string_view p : il) + m_labels.emplace_back(p); + assert(m_values.empty() || m_labels.size() == m_values.size()); + } + void finalize_closed_enum() { + assert(this->is_valid_closed_enum()); + // Check whether def.enum_values contains all the values of def.enum_keys_map and + // that they are sorted by their ordinary values. + m_values_ordinary = true; + for (const std::pair& key : *m_enum_keys_map) { + assert(key.second >= 0); + if (key.second >= this->values().size() || this->value(key.second) != key.first) { + m_values_ordinary = false; + break; + } + } + } + + std::vector m_values; + std::vector m_labels; + // If true, then enum_values are sorted and they contain all the values, thus the UI element ordinary + // to enum value could be converted directly. + bool m_values_ordinary { false }; + + template + void set_enum_map() + { + m_enum_names = &ConfigOptionEnum::get_enum_names(); + m_enum_keys_map = &ConfigOptionEnum::get_enum_values(); + } + + // For enums (when type == coEnum). Maps enums to enum names. + // Initialized by ConfigOptionEnum::get_enum_names() + const t_config_enum_names* m_enum_names{ nullptr }; + // For enums (when type == coEnum). Maps enum_values to enums. + // Initialized by ConfigOptionEnum::get_enum_values() + const t_config_enum_values* m_enum_keys_map{ nullptr }; +}; + // Definition of a configuration value for the purpose of GUI presentation, editing, value mapping and config file handling. class ConfigOptionDef { @@ -1629,10 +1802,10 @@ public: i_enum_open, // Open enums, float value could be one of the enumerated values or something else. f_enum_open, + // Open enums, string value could be one of the enumerated values or something else. + select_open, // Color picker, string value. color, - // ??? - select_open, // Currently unused. slider, // Static text @@ -1683,7 +1856,7 @@ public: case coPoint3: { auto opt = new ConfigOptionPoint3(); archive(*opt); return opt; } case coBool: { auto opt = new ConfigOptionBool(); archive(*opt); return opt; } case coBools: { auto opt = new ConfigOptionBools(); archive(*opt); return opt; } - case coEnum: { auto opt = new ConfigOptionEnumGeneric(this->enum_keys_map); archive(*opt); return opt; } + case coEnum: { auto opt = new ConfigOptionEnumGeneric(this->enum_def->m_enum_keys_map); archive(*opt); return opt; } default: throw ConfigurationError(std::string("ConfigOptionDef::load_option_from_archive(): Unknown option type for option ") + this->opt_key); } } @@ -1780,30 +1953,73 @@ public: // Sometimes a single value may well define multiple values in a "beginner" mode. // Currently used for aliasing "solid_layers" to "top_solid_layers", "bottom_solid_layers". std::vector shortcut; - // Definition of values / labels for a combo box. - // Mostly used for enums (when type == coEnum), but may be used for ints resp. floats, if gui_type is set to "i_enum_open" resp. "f_enum_open". - std::vector enum_values; - std::vector enum_labels; - // For enums (when type == coEnum). Maps enum_values to enums. - // Initialized by ConfigOptionEnum::get_enum_values() - const t_config_enum_values *enum_keys_map = nullptr; - void set_enum_values(std::initializer_list> il) { - enum_values.clear(); - enum_values.reserve(il.size()); - enum_labels.clear(); - enum_labels.reserve(il.size()); - for (const std::pair p : il) { - enum_values.emplace_back(p.first); - enum_labels.emplace_back(p.second); - } + Slic3r::clonable_ptr enum_def; + + void set_enum_values(const std::initializer_list il) { + this->enum_def_new(); + enum_def->set_values(il); + } + + void set_enum_values(GUIType gui_type, const std::initializer_list il) { + this->enum_def_new(); + assert(gui_type == GUIType::i_enum_open || gui_type == GUIType::f_enum_open || gui_type == GUIType::select_open); + this->gui_type = gui_type; + enum_def->set_values(il); + } + + void set_enum_values(const std::initializer_list> il) { + this->enum_def_new(); + enum_def->set_values(il); + } + + void set_enum_values(GUIType gui_type, const std::initializer_list> il) { + this->enum_def_new(); + assert(gui_type == GUIType::i_enum_open || gui_type == GUIType::f_enum_open); + this->gui_type = gui_type; + enum_def->set_values(il); + } + + template + void set_enum_values(Values &&values, Labels &&labels) { + this->enum_def_new(); + enum_def->set_values(std::move(values)); + enum_def->set_labels(std::move(labels)); + } + + void set_enum_labels(GUIType gui_type, const std::initializer_list il) { + this->enum_def_new(); + assert(gui_type == GUIType::i_enum_open || gui_type == GUIType::f_enum_open || gui_type == ConfigOptionDef::GUIType::select_open); + this->gui_type = gui_type; + enum_def->set_labels(il); + } + + template + void set_enum(std::initializer_list il) { + this->set_enum_values(il); + enum_def->set_enum_map(); + } + + template + void set_enum(std::initializer_list> il) { + this->set_enum_values(il); + enum_def->set_enum_map(); + } + + template + void set_enum(Values &&values, Labels &&labels) { + this->set_enum_values(std::move(values), std::move(labels)); + enum_def->set_enum_map(); + } + + template + void set_enum(Values &&values, const std::initializer_list labels) { + this->set_enum_values(std::move(values), labels); + enum_def->set_enum_map(); } bool has_enum_value(const std::string &value) const { - for (const std::string &v : enum_values) - if (v == value) - return true; - return false; + return enum_def && enum_def->value_to_index(value).has_value(); } // 0 is an invalid key. @@ -1815,6 +2031,14 @@ public: // Assign this key to cli to disable CLI for this option. static const constexpr char *nocli = "~~~noCLI"; + +private: + void enum_def_new() { + if (enum_def) + enum_def->clear(); + else + enum_def = Slic3r::clonable_ptr(new ConfigOptionEnumDef{}); + } }; inline bool operator<(const ConfigSubstitution &lhs, const ConfigSubstitution &rhs) throw() { @@ -1860,6 +2084,8 @@ public: protected: ConfigOptionDef* add(const t_config_option_key &opt_key, ConfigOptionType type); ConfigOptionDef* add_nullable(const t_config_option_key &opt_key, ConfigOptionType type); + // Finalize open / close enums, validate everything. + void finalize(); }; // A pure interface to resolving ConfigOptions. @@ -1969,7 +2195,12 @@ public: { return dynamic_cast(this->optptr(opt_key, create)); } template const T* opt(const t_config_option_key &opt_key) const { return dynamic_cast(this->optptr(opt_key)); } - + + // Get definition for a particular option. + // Returns null if such an option definition does not exist. + const ConfigOptionDef* option_def(const t_config_option_key &opt_key) const + { return this->def()->get(opt_key); } + // Apply all keys of other ConfigBase defined by this->def() to this ConfigBase. // An UnknownOptionException is thrown in case some option keys of other are not defined by this->def(), // or this ConfigBase is of a StaticConfig type and it does not support some of the keys, and ignore_nonexistent is not set. diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index e4cc8497f..186005810 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -653,10 +653,10 @@ std::string Print::validate(std::string* warning) const "If support is to be printed with the current extruder (support_material_extruder == 0 or support_material_interface_extruder == 0), " "all nozzles have to be of the same diameter."); } - if (this->has_wipe_tower()) { + if (this->has_wipe_tower() && object->config().support_material_style != smsOrganic) { if (object->config().support_material_contact_distance == 0) { // Soluble interface - if (object->config().support_material_contact_distance == 0 && ! object->config().support_material_synchronize_layers) + if (! object->config().support_material_synchronize_layers) return L("For the Wipe Tower to work with the soluble supports, the support layers need to be synchronized with the object layers."); } else { // Non-soluble interface diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index c0d065832..ea44ea4f6 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -243,6 +243,7 @@ PrintConfigDef::PrintConfigDef() assign_printer_technology_to_unknown(this->options, ptFFF); this->init_sla_params(); assign_printer_technology_to_unknown(this->options, ptSLA); + this->finalize(); } void PrintConfigDef::init_common_params() @@ -252,9 +253,7 @@ void PrintConfigDef::init_common_params() def = this->add("printer_technology", coEnum); def->label = L("Printer technology"); def->tooltip = L("Printer technology"); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_values.push_back("FFF"); - def->enum_values.push_back("SLA"); + def->set_enum({ "FFF", "SLA" }); def->set_default_value(new ConfigOptionEnum(ptFFF)); def = this->add("bed_shape", coPoints); @@ -293,10 +292,7 @@ void PrintConfigDef::init_common_params() def->label = L("Format of G-code thumbnails"); def->tooltip = L("Format of G-code thumbnails: PNG for best quality, JPG for smallest size, QOI for low memory firmware"); def->mode = comExpert; - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_values.push_back("PNG"); - def->enum_values.push_back("JPG"); - def->enum_values.push_back("QOI"); + def->set_enum({ "PNG", "JPG", "QOI" }); def->set_default_value(new ConfigOptionEnum(GCodeThumbnailsFormat::PNG)); def = this->add("layer_height", coFloat); @@ -338,7 +334,7 @@ void PrintConfigDef::init_common_params() def = this->add("printhost_port", coString); def->label = L("Printer"); def->tooltip = L("Name of the printer"); - def->gui_type = ConfigOptionDef::GUIType::select_open; +// def->gui_type = ConfigOptionDef::GUIType::select_open; def->mode = comAdvanced; def->cli = ConfigOptionDef::nocli; def->set_default_value(new ConfigOptionString("")); @@ -385,11 +381,10 @@ void PrintConfigDef::init_common_params() def = this->add("printhost_authorization_type", coEnum); def->label = L("Authorization Type"); // def->tooltip = L(""); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_values.push_back("key"); - def->enum_values.push_back("user"); - def->enum_labels.push_back(L("API key")); - def->enum_labels.push_back(L("HTTP digest")); + def->set_enum({ + { "key", L("API key") }, + { "user", L("HTTP digest") } + }); def->mode = comAdvanced; def->cli = ConfigOptionDef::nocli; def->set_default_value(new ConfigOptionEnum(atKeyPassword)); @@ -585,15 +580,12 @@ void PrintConfigDef::init_fff_params() def->label = L("Brim type"); def->category = L("Skirt and brim"); def->tooltip = L("The places where the brim will be printed around each object on the first layer."); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_values.emplace_back("no_brim"); - def->enum_values.emplace_back("outer_only"); - def->enum_values.emplace_back("inner_only"); - def->enum_values.emplace_back("outer_and_inner"); - def->enum_labels.emplace_back(L("No brim")); - def->enum_labels.emplace_back(L("Outer brim only")); - def->enum_labels.emplace_back(L("Inner brim only")); - def->enum_labels.emplace_back(L("Outer and inner brim")); + def->set_enum({ + { "no_brim", L("No brim") }, + { "outer_only", L("Outer brim only") }, + { "inner_only", L("Inner brim only") }, + { "outer_and_inner", L("Outer and inner brim") } + }); def->mode = comSimple; def->set_default_value(new ConfigOptionEnum(btOuterOnly)); @@ -774,8 +766,7 @@ void PrintConfigDef::init_fff_params() def->category = L("Infill"); def->tooltip = L("Fill pattern for top infill. This only affects the top visible layer, and not its adjacent solid shells."); def->cli = "top-fill-pattern|external-fill-pattern|solid-fill-pattern"; - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->set_enum_values({ + def->set_enum({ { "rectilinear", L("Rectilinear") }, { "monotonic", L("Monotonic") }, { "monotoniclines", L("Monotonic Lines") }, @@ -795,9 +786,7 @@ void PrintConfigDef::init_fff_params() def->category = L("Infill"); def->tooltip = L("Fill pattern for bottom infill. This only affects the bottom external visible layer, and not its adjacent solid shells."); def->cli = "bottom-fill-pattern|external-fill-pattern|solid-fill-pattern"; - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_values = def_top_fill_pattern->enum_values; - def->enum_labels = def_top_fill_pattern->enum_labels; + def->enum_def = Slic3r::clonable_ptr(def_top_fill_pattern->enum_def->clone()); def->aliases = def_top_fill_pattern->aliases; def->set_default_value(new ConfigOptionEnum(ipMonotonic)); @@ -851,18 +840,13 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionBool(false)); def = this->add("extruder", coInt); - def->gui_type = ConfigOptionDef::GUIType::i_enum_open; def->label = L("Extruder"); def->category = L("Extruders"); def->tooltip = L("The extruder to use (unless more specific extruder settings are specified). " "This value overrides perimeter and infill extruders, but not the support extruders."); def->min = 0; // 0 = inherit defaults - def->enum_labels.push_back(L("default")); // override label for item 0 - def->enum_labels.push_back("1"); - def->enum_labels.push_back("2"); - def->enum_labels.push_back("3"); - def->enum_labels.push_back("4"); - def->enum_labels.push_back("5"); + def->set_enum_labels(ConfigOptionDef::GUIType::i_enum_open, + { L("default"), "1", "2", "3", "4", "5" }); // override label for item 0 def = this->add("extruder_clearance_height", coFloat); def->label = L("Height"); @@ -1096,29 +1080,29 @@ void PrintConfigDef::init_fff_params() def = this->add("filament_type", coStrings); def->label = L("Filament type"); def->tooltip = L("The filament material type for use in custom G-codes."); - def->gui_type = ConfigOptionDef::GUIType::f_enum_open; def->gui_flags = "show_value"; - def->enum_values.push_back("PLA"); - def->enum_values.push_back("PET"); - def->enum_values.push_back("ABS"); - def->enum_values.push_back("ASA"); - def->enum_values.push_back("FLEX"); - def->enum_values.push_back("HIPS"); - def->enum_values.push_back("EDGE"); - def->enum_values.push_back("NGEN"); - def->enum_values.push_back("PA"); - def->enum_values.push_back("NYLON"); - def->enum_values.push_back("PVA"); - def->enum_values.push_back("PC"); - def->enum_values.push_back("PP"); - def->enum_values.push_back("PEI"); - def->enum_values.push_back("PEEK"); - def->enum_values.push_back("PEKK"); - def->enum_values.push_back("POM"); - def->enum_values.push_back("PSU"); - def->enum_values.push_back("PVDF"); - def->enum_values.push_back("SCAFF"); - + def->set_enum_values(ConfigOptionDef::GUIType::select_open, { + "PLA", + "PET", + "ABS", + "ASA", + "FLEX", + "HIPS", + "EDGE", + "NGEN", + "PA", + "NYLON", + "PVA", + "PC", + "PP", + "PEI", + "PEEK", + "PEKK", + "POM", + "PSU", + "PVDF", + "SCAFF" + }); def->mode = comAdvanced; def->set_default_value(new ConfigOptionStrings { "PLA" }); @@ -1166,7 +1150,6 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionFloat(45)); def = this->add("fill_density", coPercent); - def->gui_type = ConfigOptionDef::GUIType::f_enum_open; def->gui_flags = "show_value"; def->label = L("Fill density"); def->category = L("Infill"); @@ -1174,75 +1157,47 @@ void PrintConfigDef::init_fff_params() def->sidetext = L("%"); def->min = 0; def->max = 100; - def->enum_values.push_back("0"); - def->enum_values.push_back("5"); - def->enum_values.push_back("10"); - def->enum_values.push_back("15"); - def->enum_values.push_back("20"); - def->enum_values.push_back("25"); - def->enum_values.push_back("30"); - def->enum_values.push_back("40"); - def->enum_values.push_back("50"); - def->enum_values.push_back("60"); - def->enum_values.push_back("70"); - def->enum_values.push_back("80"); - def->enum_values.push_back("90"); - def->enum_values.push_back("100"); - def->enum_labels.push_back("0%"); - def->enum_labels.push_back("5%"); - def->enum_labels.push_back("10%"); - def->enum_labels.push_back("15%"); - def->enum_labels.push_back("20%"); - def->enum_labels.push_back("25%"); - def->enum_labels.push_back("30%"); - def->enum_labels.push_back("40%"); - def->enum_labels.push_back("50%"); - def->enum_labels.push_back("60%"); - def->enum_labels.push_back("70%"); - def->enum_labels.push_back("80%"); - def->enum_labels.push_back("90%"); - def->enum_labels.push_back("100%"); + def->set_enum_values(ConfigOptionDef::GUIType::f_enum_open, { + { "0", "0%" }, + { "5", "5%" }, + { "10", "10%" }, + { "15", "15%" }, + { "20", "20%" }, + { "25", "25%" }, + { "30", "30%" }, + { "40", "40%" }, + { "50", "50%" }, + { "60", "60%" }, + { "70", "70%" }, + { "80", "80%" }, + { "90", "90%" }, + { "100", "100%" } + }); def->set_default_value(new ConfigOptionPercent(20)); def = this->add("fill_pattern", coEnum); def->label = L("Fill pattern"); def->category = L("Infill"); def->tooltip = L("Fill pattern for general low-density infill."); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_values.push_back("rectilinear"); - def->enum_values.push_back("alignedrectilinear"); - def->enum_values.push_back("grid"); - def->enum_values.push_back("triangles"); - def->enum_values.push_back("stars"); - def->enum_values.push_back("cubic"); - def->enum_values.push_back("line"); - def->enum_values.push_back("concentric"); - def->enum_values.push_back("honeycomb"); - def->enum_values.push_back("3dhoneycomb"); - def->enum_values.push_back("gyroid"); - def->enum_values.push_back("hilbertcurve"); - def->enum_values.push_back("archimedeanchords"); - def->enum_values.push_back("octagramspiral"); - def->enum_values.push_back("adaptivecubic"); - def->enum_values.push_back("supportcubic"); - def->enum_values.push_back("lightning"); - def->enum_labels.push_back(L("Rectilinear")); - def->enum_labels.push_back(L("Aligned Rectilinear")); - def->enum_labels.push_back(L("Grid")); - def->enum_labels.push_back(L("Triangles")); - def->enum_labels.push_back(L("Stars")); - def->enum_labels.push_back(L("Cubic")); - def->enum_labels.push_back(L("Line")); - def->enum_labels.push_back(L("Concentric")); - def->enum_labels.push_back(L("Honeycomb")); - def->enum_labels.push_back(L("3D Honeycomb")); - def->enum_labels.push_back(L("Gyroid")); - def->enum_labels.push_back(L("Hilbert Curve")); - def->enum_labels.push_back(L("Archimedean Chords")); - def->enum_labels.push_back(L("Octagram Spiral")); - def->enum_labels.push_back(L("Adaptive Cubic")); - def->enum_labels.push_back(L("Support Cubic")); - def->enum_labels.push_back(L("Lightning")); + def->set_enum({ + { "rectilinear", L("Rectilinear") }, + { "alignedrectilinear", L("Aligned Rectilinear") }, + { "grid", L("Grid") }, + { "triangles", L("Triangles")}, + { "stars", L("Stars")}, + { "cubic", L("Cubic")}, + { "line", L("Line")}, + { "concentric", L("Concentric")}, + { "honeycomb", L("Honeycomb")}, + { "3dhoneycomb", L("3D Honeycomb")}, + { "gyroid", L("Gyroid")}, + { "hilbertcurve", L("Hilbert Curve")}, + { "archimedeanchords", L("Archimedean Chords")}, + { "octagramspiral", L("Octagram Spiral")}, + { "adaptivecubic", L("Adaptive Cubic")}, + { "supportcubic", L("Support Cubic")}, + { "lightning", L("Lightning")} + }); def->set_default_value(new ConfigOptionEnum(ipStars)); def = this->add("first_layer_acceleration", coFloat); @@ -1343,14 +1298,11 @@ void PrintConfigDef::init_fff_params() def->label = L("Fuzzy Skin"); def->category = L("Fuzzy Skin"); def->tooltip = L("Fuzzy skin type."); - - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_values.push_back("none"); - def->enum_values.push_back("external"); - def->enum_values.push_back("all"); - def->enum_labels.push_back(L("None")); - def->enum_labels.push_back(L("Outside walls")); - def->enum_labels.push_back(L("All walls")); + def->set_enum({ + { "none", L("None") }, + { "external", L("Outside walls") }, + { "all", L("All walls") } + }); def->mode = comSimple; def->set_default_value(new ConfigOptionEnum(FuzzySkinType::None)); @@ -1404,31 +1356,20 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("Some G/M-code commands, including temperature control and others, are not universal. " "Set this option to your printer's firmware to get a compatible output. " "The \"No extrusion\" flavor prevents PrusaSlicer from exporting any extrusion value at all."); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_values.push_back("reprap"); - def->enum_values.push_back("reprapfirmware"); - def->enum_values.push_back("repetier"); - def->enum_values.push_back("teacup"); - def->enum_values.push_back("makerware"); - def->enum_values.push_back("marlin"); - def->enum_values.push_back("marlin2"); - def->enum_values.push_back("sailfish"); - def->enum_values.push_back("mach3"); - def->enum_values.push_back("machinekit"); - def->enum_values.push_back("smoothie"); - def->enum_values.push_back("no-extrusion"); - def->enum_labels.push_back("RepRap/Sprinter"); - def->enum_labels.push_back("RepRapFirmware"); - def->enum_labels.push_back("Repetier"); - def->enum_labels.push_back("Teacup"); - def->enum_labels.push_back("MakerWare (MakerBot)"); - def->enum_labels.push_back("Marlin (legacy)"); - def->enum_labels.push_back("Marlin 2"); - def->enum_labels.push_back("Sailfish (MakerBot)"); - def->enum_labels.push_back("Mach3/LinuxCNC"); - def->enum_labels.push_back("Machinekit"); - def->enum_labels.push_back("Smoothie"); - def->enum_labels.push_back(L("No extrusion")); + def->set_enum({ + { "reprap", "RepRap/Sprinter" }, + { "reprapfirmware", "RepRapFirmware" }, + { "repetier", "Repetier" }, + { "teacup", "Teacup" }, + { "makerware", "MakerWare (MakerBot)" }, + { "marlin", "Marlin (legacy)" }, + { "marlin2", "Marlin 2" }, + { "sailfish", "Sailfish (MakerBot)" }, + { "mach3", "Mach3/LinuxCNC" }, + { "machinekit", "Machinekit" }, + { "smoothie", "Smoothie" }, + { "no-extrusion", L("No extrusion") } + }); def->mode = comExpert; def->set_default_value(new ConfigOptionEnum(gcfRepRapSprinter)); @@ -1486,19 +1427,14 @@ void PrintConfigDef::init_fff_params() def->sidetext = L("mm or %"); def->ratio_over = "infill_extrusion_width"; def->max_literal = 1000; - def->gui_type = ConfigOptionDef::GUIType::f_enum_open; - def->enum_values.push_back("0"); - def->enum_values.push_back("1"); - def->enum_values.push_back("2"); - def->enum_values.push_back("5"); - def->enum_values.push_back("10"); - def->enum_values.push_back("1000"); - def->enum_labels.push_back(L("0 (no open anchors)")); - def->enum_labels.push_back(L("1 mm")); - def->enum_labels.push_back(L("2 mm")); - def->enum_labels.push_back(L("5 mm")); - def->enum_labels.push_back(L("10 mm")); - def->enum_labels.push_back(L("1000 (unlimited)")); + def->set_enum_values(ConfigOptionDef::GUIType::f_enum_open, { + { "0", L("0 (no open anchors)") }, + { "1", L("1 mm") }, + { "2", L("2 mm") }, + { "5", L("5 mm") }, + { "10", L("10 mm") }, + { "1000", L("1000 (unlimited)") } + }); def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloatOrPercent(600, true)); @@ -1514,14 +1450,14 @@ void PrintConfigDef::init_fff_params() def->sidetext = def_infill_anchor_min->sidetext; def->ratio_over = def_infill_anchor_min->ratio_over; def->max_literal = def_infill_anchor_min->max_literal; - def->gui_type = def_infill_anchor_min->gui_type; - def->enum_values = def_infill_anchor_min->enum_values; - def->enum_labels.push_back(L("0 (not anchored)")); - def->enum_labels.push_back(L("1 mm")); - def->enum_labels.push_back(L("2 mm")); - def->enum_labels.push_back(L("5 mm")); - def->enum_labels.push_back(L("10 mm")); - def->enum_labels.push_back(L("1000 (unlimited)")); + def->set_enum_values(ConfigOptionDef::GUIType::f_enum_open, { + { "0", L("0 (not anchored)") }, + { "1", L("1 mm") }, + { "2", L("2 mm") }, + { "5", L("5 mm") }, + { "10", L("10 mm") }, + { "1000", L("1000 (unlimited)") } + }); def->mode = def_infill_anchor_min->mode; def->set_default_value(new ConfigOptionFloatOrPercent(50, false)); @@ -1625,13 +1561,11 @@ void PrintConfigDef::init_fff_params() def->label = L("Ironing Type"); def->category = L("Ironing"); def->tooltip = L("Ironing Type"); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_values.push_back("top"); - def->enum_values.push_back("topmost"); - def->enum_values.push_back("solid"); - def->enum_labels.push_back(L("All top surfaces")); - def->enum_labels.push_back(L("Topmost surface only")); - def->enum_labels.push_back(L("All solid surfaces")); + def->set_enum({ + { "top", L("All top surfaces") }, + { "topmost", L("Topmost surface only") }, + { "solid", L("All solid surfaces") } + }); def->mode = comAdvanced; def->set_default_value(new ConfigOptionEnum(IroningType::TopSurfaces)); @@ -1695,13 +1629,11 @@ void PrintConfigDef::init_fff_params() def->full_label = L("Purpose of Machine Limits"); def->category = L("Machine limits"); def->tooltip = L("How to apply the Machine Limits"); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_values.push_back("emit_to_gcode"); - def->enum_values.push_back("time_estimate_only"); - def->enum_values.push_back("ignore"); - def->enum_labels.push_back(L("Emit to G-code")); - def->enum_labels.push_back(L("Use for time estimate")); - def->enum_labels.push_back(L("Ignore")); + def->set_enum({ + { "emit_to_gcode", L("Emit to G-code") }, + { "time_estimate_only", L("Use for time estimate") }, + { "ignore", L("Ignore") } + }); def->mode = comAdvanced; def->set_default_value(new ConfigOptionEnum(MachineLimitsUsage::TimeEstimateOnly)); @@ -1947,23 +1879,16 @@ void PrintConfigDef::init_fff_params() def->label = L("Host Type"); def->tooltip = L("Slic3r can upload G-code files to a printer host. This field must contain " "the kind of the host."); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_values.push_back("prusalink"); - def->enum_values.push_back("prusaconnect"); - def->enum_values.push_back("octoprint"); - def->enum_values.push_back("duet"); - def->enum_values.push_back("flashair"); - def->enum_values.push_back("astrobox"); - def->enum_values.push_back("repetier"); - def->enum_values.push_back("mks"); - def->enum_labels.push_back("PrusaLink"); - def->enum_labels.push_back("PrusaConnect"); - def->enum_labels.push_back("OctoPrint"); - def->enum_labels.push_back("Duet"); - def->enum_labels.push_back("FlashAir"); - def->enum_labels.push_back("AstroBox"); - def->enum_labels.push_back("Repetier"); - def->enum_labels.push_back("MKS"); + def->set_enum({ + { "prusalink", "PrusaLink" }, + { "prusaconnect", "PrusaConnect" }, + { "octoprint", "OctoPrint" }, + { "duet", "Duet" }, + { "flashair", "FlashAir" }, + { "astrobox", "AstroBox" }, + { "repetier", "Repetier" }, + { "mks", "MKS" } + }); def->mode = comAdvanced; def->cli = ConfigOptionDef::nocli; def->set_default_value(new ConfigOptionEnum(htPrusaLink)); @@ -2296,15 +2221,12 @@ void PrintConfigDef::init_fff_params() def->label = L("Seam position"); def->category = L("Layers and Perimeters"); def->tooltip = L("Position of perimeters starting points."); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_values.push_back("random"); - def->enum_values.push_back("nearest"); - def->enum_values.push_back("aligned"); - def->enum_values.push_back("rear"); - def->enum_labels.push_back(L("Random")); - def->enum_labels.push_back(L("Nearest")); - def->enum_labels.push_back(L("Aligned")); - def->enum_labels.push_back(L("Rear")); + def->set_enum({ + { "random", L("Random") }, + { "nearest", L("Nearest") }, + { "aligned", L("Aligned") }, + { "rear", L("Rear") } + }); def->mode = comSimple; def->set_default_value(new ConfigOptionEnum(spAligned)); @@ -2356,13 +2278,11 @@ void PrintConfigDef::init_fff_params() "Enabled = skirt is as tall as the highest printed object.\n" "Limited = skirt is as tall as specified by skirt_height.\n" "This is useful to protect an ABS or ASA print from warping and detaching from print bed due to wind draft."); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_values.push_back("disabled"); - def->enum_values.push_back("limited"); - def->enum_values.push_back("enabled"); - def->enum_labels.push_back(L("Disabled")); - def->enum_labels.push_back(L("Limited")); - def->enum_labels.push_back(L("Enabled")); + def->set_enum({ + { "disabled", L("Disabled") }, + { "limited", L("Limited") }, + { "enabled", L("Enabled") } + }); def->mode = comAdvanced; def->set_default_value(new ConfigOptionEnum(dsDisabled)); @@ -2579,13 +2499,11 @@ void PrintConfigDef::init_fff_params() def->label = L("Slicing Mode"); def->category = L("Advanced"); def->tooltip = L("Use \"Even-odd\" for 3DLabPrint airplane models. Use \"Close holes\" to close all holes in the model."); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_values.push_back("regular"); - def->enum_values.push_back("even_odd"); - def->enum_values.push_back("close_holes"); - def->enum_labels.push_back(L("Regular")); - def->enum_labels.push_back(L("Even-odd")); - def->enum_labels.push_back(L("Close holes")); + def->set_enum({ + { "regular", L("Regular") }, + { "even_odd", L("Even-odd") }, + { "close_holes", L("Close holes") } + }); def->mode = comAdvanced; def->set_default_value(new ConfigOptionEnum(SlicingMode::Regular)); @@ -2634,7 +2552,6 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionBool(false)); def = this->add("support_material_contact_distance", coFloat); - def->gui_type = ConfigOptionDef::GUIType::f_enum_open; def->label = L("Top contact Z distance"); def->category = L("Support material"); def->tooltip = L("The vertical distance between object and support material interface. " @@ -2642,30 +2559,27 @@ void PrintConfigDef::init_fff_params() "for the first object layer."); def->sidetext = L("mm"); // def->min = 0; - def->enum_values.push_back("0"); - def->enum_values.push_back("0.1"); - def->enum_values.push_back("0.2"); - def->enum_labels.push_back(L("0 (soluble)")); - def->enum_labels.push_back(L("0.1 (detachable)")); - def->enum_labels.push_back(L("0.2 (detachable)")); + def->set_enum_values(ConfigOptionDef::GUIType::f_enum_open, { + { "0", L("0 (soluble)") }, + { "0.1", L("0.1 (detachable)") }, + { "0.2", L("0.2 (detachable)") } + }); def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(0.2)); def = this->add("support_material_bottom_contact_distance", coFloat); - def->gui_type = ConfigOptionDef::GUIType::f_enum_open; def->label = L("Bottom contact Z distance"); def->category = L("Support material"); def->tooltip = L("The vertical distance between the object top surface and the support material interface. " "If set to zero, support_material_contact_distance will be used for both top and bottom contact Z distances."); def->sidetext = L("mm"); // def->min = 0; - def->enum_values.push_back("0"); - def->enum_values.push_back("0.1"); - def->enum_values.push_back("0.2"); //TRN To be shown in Print Settings "Bottom contact Z distance". Have to be as short as possible - def->enum_labels.push_back(L("Same as top")); - def->enum_labels.push_back("0.1"); - def->enum_labels.push_back("0.2"); + def->set_enum_values(ConfigOptionDef::GUIType::f_enum_open, { + { "0", L("Same as top") }, + { "0.1", "0.1" }, + { "0.2", "0.2" } + }); def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(0)); @@ -2720,36 +2634,35 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionInt(1)); auto support_material_interface_layers = def = this->add("support_material_interface_layers", coInt); - def->gui_type = ConfigOptionDef::GUIType::i_enum_open; def->label = L("Top interface layers"); def->category = L("Support material"); def->tooltip = L("Number of interface layers to insert between the object(s) and support material."); def->sidetext = L("layers"); def->min = 0; - def->enum_values.push_back("0"); - def->enum_values.push_back("1"); - def->enum_values.push_back("2"); - def->enum_values.push_back("3"); - def->enum_labels.push_back(L("0 (off)")); - def->enum_labels.push_back(L("1 (light)")); - def->enum_labels.push_back(L("2 (default)")); - def->enum_labels.push_back(L("3 (heavy)")); + def->set_enum_values(ConfigOptionDef::GUIType::i_enum_open, { + { "0", L("0 (off)") }, + { "1", L("1 (light)") }, + { "2", L("2 (default)") }, + { "3", L("3 (heavy)") } + }); def->mode = comAdvanced; def->set_default_value(new ConfigOptionInt(3)); def = this->add("support_material_bottom_interface_layers", coInt); - def->gui_type = ConfigOptionDef::GUIType::i_enum_open; def->label = L("Bottom interface layers"); def->category = L("Support material"); def->tooltip = L("Number of interface layers to insert between the object(s) and support material. " "Set to -1 to use support_material_interface_layers"); def->sidetext = L("layers"); def->min = -1; - def->enum_values.push_back("-1"); - append(def->enum_values, support_material_interface_layers->enum_values); //TRN To be shown in Print Settings "Bottom interface layers". Have to be as short as possible - def->enum_labels.push_back(L("Same as top")); - append(def->enum_labels, support_material_interface_layers->enum_labels); + def->set_enum_values(ConfigOptionDef::GUIType::i_enum_open, { + { "-1", L("Same as top") }, + { "0", L("0 (off)") }, + { "1", L("1 (light)") }, + { "2", L("2 (default)") }, + { "3", L("3 (heavy)") } + }); def->mode = comAdvanced; def->set_default_value(new ConfigOptionInt(-1)); @@ -2787,13 +2700,11 @@ void PrintConfigDef::init_fff_params() def->label = L("Pattern"); def->category = L("Support material"); def->tooltip = L("Pattern used to generate support material."); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_values.push_back("rectilinear"); - def->enum_values.push_back("rectilinear-grid"); - def->enum_values.push_back("honeycomb"); - def->enum_labels.push_back(L("Rectilinear")); - def->enum_labels.push_back(L("Rectilinear grid")); - def->enum_labels.push_back(L("Honeycomb")); + def->set_enum({ + { "rectilinear", L("Rectilinear") }, + { "rectilinear-grid", L("Rectilinear grid") }, + { "honeycomb", L("Honeycomb") } + }); def->mode = comAdvanced; def->set_default_value(new ConfigOptionEnum(smpRectilinear)); @@ -2803,13 +2714,11 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("Pattern used to generate support material interface. " "Default pattern for non-soluble support interface is Rectilinear, " "while default pattern for soluble support interface is Concentric."); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_values.push_back("auto"); - def->enum_values.push_back("rectilinear"); - def->enum_values.push_back("concentric"); - def->enum_labels.push_back(L("Default")); - def->enum_labels.push_back(L("Rectilinear")); - def->enum_labels.push_back(L("Concentric")); + def->set_enum({ + { "auto", L("Default") }, + { "rectilinear", L("Rectilinear") }, + { "concentric", L("Concentric") } + }); def->mode = comAdvanced; def->set_default_value(new ConfigOptionEnum(smipRectilinear)); @@ -2837,8 +2746,7 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("Style and shape of the support towers. Projecting the supports into a regular grid " "will create more stable supports, while snug support towers will save material and reduce " "object scarring."); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->set_enum_values({ + def->set_enum({ { "grid", L("Grid") }, { "snug", L("Snug") }, { "organic", L("Organic") } @@ -3207,11 +3115,10 @@ void PrintConfigDef::init_fff_params() "very thin areas is used gap-fill. " "Arachne engine produces perimeters with variable extrusion width. " "This setting also affects the Concentric infill."); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_values.push_back("classic"); - def->enum_values.push_back("arachne"); - def->enum_labels.push_back(L("Classic")); - def->enum_labels.push_back(L("Arachne")); + def->set_enum({ + { "classic", L("Classic") }, + { "arachne", L("Arachne") } + }); def->mode = comAdvanced; def->set_default_value(new ConfigOptionEnum(PerimeterGeneratorType::Arachne)); @@ -3434,13 +3341,9 @@ void PrintConfigDef::init_sla_support_params(const std::string &prefix) " Can be zig-zag, cross (double zig-zag) or dynamic which" " will automatically switch between the first two depending" " on the distance of the two pillars."); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_values = ConfigOptionEnum::get_enum_names(); - def->enum_labels = ConfigOptionEnum::get_enum_names(); - def->enum_labels[0] = L("Zig-Zag"); - def->enum_labels[1] = L("Cross"); - def->enum_labels[2] = L("Dynamic"); + def->set_enum( + ConfigOptionEnum::get_enum_names(), + { L("Zig-Zag"), L("Cross"), L("Dynamic") }); def->mode = comAdvanced; def->set_default_value(new ConfigOptionEnum(SLAPillarConnectionMode::dynamic)); @@ -3602,11 +3505,10 @@ void PrintConfigDef::init_sla_params() def->tooltip = L("Set the actual LCD display orientation inside the SLA printer." " Portrait mode will flip the meaning of display width and height parameters" " and the output images will be rotated by 90 degrees."); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_values.push_back("landscape"); - def->enum_values.push_back("portrait"); - def->enum_labels.push_back(L("Landscape")); - def->enum_labels.push_back(L("Portrait")); + def->set_enum({ + { "landscape", L("Landscape") }, + { "portrait", L("Portrait") } + }); def->mode = comExpert; def->set_default_value(new ConfigOptionEnum(sladoPortrait)); @@ -3718,13 +3620,9 @@ void PrintConfigDef::init_sla_params() def = this->add("material_type", coString); def->label = L("SLA material type"); def->tooltip = L("SLA material type"); - def->gui_type = ConfigOptionDef::GUIType::f_enum_open; // TODO: ??? def->gui_flags = "show_value"; - def->enum_values.push_back("Tough"); - def->enum_values.push_back("Flexible"); - def->enum_values.push_back("Casting"); - def->enum_values.push_back("Dental"); - def->enum_values.push_back("Heat-resistant"); + def->set_enum_values(ConfigOptionDef::GUIType::select_open, + { "Tough", "Flexible", "Casting", "Dental", "Heat-resistant" }); def->set_default_value(new ConfigOptionString("Tough")); def = this->add("initial_layer_height", coFloat); @@ -3898,12 +3796,10 @@ void PrintConfigDef::init_sla_params() def = this->add("support_tree_type", coEnum); def->label = L("Support tree type"); def->tooltip = L("Support tree building strategy"); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_values = ConfigOptionEnum::get_enum_names(); - def->enum_labels = ConfigOptionEnum::get_enum_names(); - def->enum_labels[0] = L("Default"); - def->enum_labels[1] = L("Branching (experimental)"); - // TODO: def->enum_labels[2] = L("Organic"); + def->set_enum( + ConfigOptionEnum::get_enum_names(), + { L("Default"), L("Branching (experimental)") }); + // TODO: def->enum_def->labels[2] = L("Organic"); def->mode = comSimple; def->set_default_value(new ConfigOptionEnum(sla::SupportTreeType::Default)); @@ -4107,13 +4003,11 @@ void PrintConfigDef::init_sla_params() def->tooltip = L( "A slower printing profile might be necessary when using materials with higher viscosity " "or with some hollowed parts. It slows down the tilt movement and adds a delay before exposure."); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_values.push_back("slow"); - def->enum_values.push_back("fast"); - def->enum_values.push_back("high_viscosity"); - def->enum_labels.push_back(L("Slow")); - def->enum_labels.push_back(L("Fast")); - def->enum_labels.push_back(L("High viscosity")); + def->set_enum({ + { "slow", L("Slow") }, + { "fast", L("Fast") }, + { "high_viscosity", L("High viscosity") } + }); def->mode = comAdvanced; def->set_default_value(new ConfigOptionEnum(slamsFast)); @@ -4126,7 +4020,7 @@ void PrintConfigDef::init_sla_params() def->label = L("SLA output precision"); def->tooltip = L("Minimum resolution in nanometers"); def->sidetext = L("mm"); - def->min = SCALING_FACTOR; + def->min = float(SCALING_FACTOR); def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(0.001)); } @@ -4794,13 +4688,11 @@ CLIMiscConfigDef::CLIMiscConfigDef() def->tooltip = L("This version of PrusaSlicer may not understand configurations produced by the newest PrusaSlicer versions. " "For example, newer PrusaSlicer may extend the list of supported firmware flavors. One may decide to " "bail out or to substitute an unknown value with a default silently or verbosely."); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_values.push_back("disable"); - def->enum_values.push_back("enable"); - def->enum_values.push_back("enable_silent"); - def->enum_labels.push_back(L("Bail out on unknown configuration values")); - def->enum_labels.push_back(L("Enable reading unknown configuration values by verbosely substituting them with defaults.")); - def->enum_labels.push_back(L("Enable reading unknown configuration values by silently substituting them with defaults.")); + def->set_enum({ + { "disable", L("Bail out on unknown configuration values") }, + { "enable", L("Enable reading unknown configuration values by verbosely substituting them with defaults.") }, + { "enable_silent", L("Enable reading unknown configuration values by silently substituting them with defaults.") } + }); def->set_default_value(new ConfigOptionEnum(ForwardCompatibilitySubstitutionRule::Enable)); def = this->add("load", coStrings); diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index d442a8646..b4c98fcb1 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -116,44 +116,48 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con } } - if (config->opt_bool("wipe_tower") && config->opt_bool("support_material") && - config->opt_float("support_material_contact_distance") > 0. && - (config->opt_int("support_material_extruder") != 0 || config->opt_int("support_material_interface_extruder") != 0)) { - wxString msg_text = _(L("The Wipe Tower currently supports the non-soluble supports only\n" - "if they are printed with the current extruder without triggering a tool change.\n" - "(both support_material_extruder and support_material_interface_extruder need to be set to 0).")); - if (is_global_config) - msg_text += "\n\n" + _(L("Shall I adjust those settings in order to enable the Wipe Tower?")); - MessageDialog dialog (m_msg_dlg_parent, msg_text, _(L("Wipe Tower")), - wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); - DynamicPrintConfig new_conf = *config; - auto answer = dialog.ShowModal(); - if (!is_global_config || answer == wxID_YES) { - new_conf.set_key_value("support_material_extruder", new ConfigOptionInt(0)); - new_conf.set_key_value("support_material_interface_extruder", new ConfigOptionInt(0)); - } - else - new_conf.set_key_value("wipe_tower", new ConfigOptionBool(false)); - apply(config, &new_conf); - } + auto style = config->opt_enum("support_material_style"); - if (config->opt_bool("wipe_tower") && config->opt_bool("support_material") && - config->opt_float("support_material_contact_distance") == 0 && - !config->opt_bool("support_material_synchronize_layers")) { - wxString msg_text = _(L("For the Wipe Tower to work with the soluble supports, the support layers\n" - "need to be synchronized with the object layers.")); - if (is_global_config) - msg_text += "\n\n" + _(L("Shall I synchronize support layers in order to enable the Wipe Tower?")); - MessageDialog dialog(m_msg_dlg_parent, msg_text, _(L("Wipe Tower")), - wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); - DynamicPrintConfig new_conf = *config; - auto answer = dialog.ShowModal(); - if (!is_global_config || answer == wxID_YES) { - new_conf.set_key_value("support_material_synchronize_layers", new ConfigOptionBool(true)); + if (config->opt_bool("wipe_tower") && config->opt_bool("support_material") && + // Organic supports are always synchronized with object layers as of now. + config->opt_enum("support_material_style") != smsOrganic) { + if (config->opt_float("support_material_contact_distance") == 0) { + if (!config->opt_bool("support_material_synchronize_layers")) { + wxString msg_text = _(L("For the Wipe Tower to work with the soluble supports, the support layers\n" + "need to be synchronized with the object layers.")); + if (is_global_config) + msg_text += "\n\n" + _(L("Shall I synchronize support layers in order to enable the Wipe Tower?")); + MessageDialog dialog(m_msg_dlg_parent, msg_text, _(L("Wipe Tower")), + wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); + DynamicPrintConfig new_conf = *config; + auto answer = dialog.ShowModal(); + if (!is_global_config || answer == wxID_YES) { + new_conf.set_key_value("support_material_synchronize_layers", new ConfigOptionBool(true)); + } + else + new_conf.set_key_value("wipe_tower", new ConfigOptionBool(false)); + apply(config, &new_conf); + } + } else { + if ((config->opt_int("support_material_extruder") != 0 || config->opt_int("support_material_interface_extruder") != 0)) { + wxString msg_text = _(L("The Wipe Tower currently supports the non-soluble supports only\n" + "if they are printed with the current extruder without triggering a tool change.\n" + "(both support_material_extruder and support_material_interface_extruder need to be set to 0).")); + if (is_global_config) + msg_text += "\n\n" + _(L("Shall I adjust those settings in order to enable the Wipe Tower?")); + MessageDialog dialog (m_msg_dlg_parent, msg_text, _(L("Wipe Tower")), + wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); + DynamicPrintConfig new_conf = *config; + auto answer = dialog.ShowModal(); + if (!is_global_config || answer == wxID_YES) { + new_conf.set_key_value("support_material_extruder", new ConfigOptionInt(0)); + new_conf.set_key_value("support_material_interface_extruder", new ConfigOptionInt(0)); + } + else + new_conf.set_key_value("wipe_tower", new ConfigOptionBool(false)); + apply(config, &new_conf); + } } - else - new_conf.set_key_value("wipe_tower", new ConfigOptionBool(false)); - apply(config, &new_conf); } // Check "support_material" and "overhangs" relations only on global settings level @@ -183,18 +187,14 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con } if (config->option("fill_density")->value == 100) { - std::string fill_pattern = config->option>("fill_pattern")->serialize(); - const auto &top_fill_pattern_values = config->def()->get("top_fill_pattern")->enum_values; - bool correct_100p_fill = std::find(top_fill_pattern_values.begin(), top_fill_pattern_values.end(), fill_pattern) != top_fill_pattern_values.end(); - if (!correct_100p_fill) { + const int fill_pattern = config->option>("fill_pattern")->value; + if (bool correct_100p_fill = config->option_def("top_fill_pattern")->enum_def->enum_to_index(fill_pattern).has_value(); + ! correct_100p_fill) { // get fill_pattern name from enum_labels for using this one at dialog_msg - const ConfigOptionDef *fill_pattern_def = config->def()->get("fill_pattern"); + const ConfigOptionDef *fill_pattern_def = config->option_def("fill_pattern"); assert(fill_pattern_def != nullptr); - auto it_pattern = std::find(fill_pattern_def->enum_values.begin(), fill_pattern_def->enum_values.end(), fill_pattern); - assert(it_pattern != fill_pattern_def->enum_values.end()); - if (it_pattern != fill_pattern_def->enum_values.end()) { - wxString msg_text = GUI::format_wxstr(_L("The %1% infill pattern is not supposed to work at 100%% density."), - _(fill_pattern_def->enum_labels[it_pattern - fill_pattern_def->enum_values.begin()])); + if (auto label = fill_pattern_def->enum_def->enum_to_label(fill_pattern); label.has_value()) { + wxString msg_text = GUI::format_wxstr(_L("The %1% infill pattern is not supposed to work at 100%% density."), _(label.value())); if (is_global_config) msg_text += "\n\n" + _L("Shall I switch to rectilinear fill pattern?"); MessageDialog dialog(m_msg_dlg_parent, msg_text, _L("Infill"), diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 0296fb154..be1e02b84 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -1129,16 +1129,15 @@ void PageMaterials::sort_list_data(StringList* list, bool add_All_item, bool mat else other_profiles.push_back(data); } - if(material_type_ordering) { + if (material_type_ordering) { const ConfigOptionDef* def = print_config_def.get("filament_type"); - std::vectorenum_values = def->enum_values; size_t end_of_sorted = 0; - for (size_t vals = 0; vals < enum_values.size(); vals++) { + for (const std::string &value : def->enum_def->values()) { for (size_t profs = end_of_sorted; profs < other_profiles.size(); profs++) { // find instead compare because PET vs PETG - if (other_profiles[profs].get().find(enum_values[vals]) != std::string::npos) { + if (other_profiles[profs].get().find(value) != std::string::npos) { //swap if(profs != end_of_sorted) { std::reference_wrapper aux = other_profiles[end_of_sorted]; @@ -1660,14 +1659,14 @@ PageFirmware::PageFirmware(ConfigWizard *parent) append_text(_(gcode_opt.tooltip)); wxArrayString choices; - choices.Alloc(gcode_opt.enum_labels.size()); - for (const auto &label : gcode_opt.enum_labels) { + choices.Alloc(gcode_opt.enum_def->labels().size()); + for (const auto &label : gcode_opt.enum_def->labels()) { choices.Add(label); } gcode_picker = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, choices); wxGetApp().UpdateDarkUI(gcode_picker); - const auto &enum_values = gcode_opt.enum_values; + const auto &enum_values = gcode_opt.enum_def->values(); auto needle = enum_values.cend(); if (gcode_opt.default_value) { needle = std::find(enum_values.cbegin(), enum_values.cend(), gcode_opt.default_value->serialize()); @@ -1684,7 +1683,7 @@ PageFirmware::PageFirmware(ConfigWizard *parent) void PageFirmware::apply_custom_config(DynamicPrintConfig &config) { auto sel = gcode_picker->GetSelection(); - if (sel >= 0 && (size_t)sel < gcode_opt.enum_labels.size()) { + if (sel >= 0 && (size_t)sel < gcode_opt.enum_def->labels().size()) { auto *opt = new ConfigOptionEnum(static_cast(sel)); config.set_key_value("gcode_flavor", opt); } diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index e8788715e..2b9bcfab6 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -1021,16 +1021,10 @@ void Choice::BUILD() { // recast as a wxWindow to fit the calling convention window = dynamic_cast(temp); - if (! m_opt.enum_labels.empty() || ! m_opt.enum_values.empty()) { - if (m_opt.enum_labels.empty()) { - // Append non-localized enum_values - for (auto el : m_opt.enum_values) - temp->Append(el); - } else { - // Append localized enum_labels - for (auto el : m_opt.enum_labels) - temp->Append(_(el)); - } + if (auto &labels = m_opt.enum_def->labels(); ! labels.empty()) { + bool localized = m_opt.enum_def->has_labels(); + for (const std::string &el : labels) + temp->Append(localized ? _(wxString::FromUTF8(el)) : wxString::FromUTF8(el)); set_selection(); } @@ -1141,33 +1135,23 @@ void Choice::set_selection() } if (!text_value.IsEmpty()) { - size_t idx = 0; - for (auto el : m_opt.enum_values) { - if (el == text_value) - break; - ++idx; - } - idx == m_opt.enum_values.size() ? field->SetValue(text_value) : field->SetSelection(idx); + if (auto opt = m_opt.enum_def->value_to_index(into_u8(text_value)); opt.has_value()) + // This enum has a value field of the same content as text_value. Select it. + field->SetSelection(opt.value()); + else + field->SetValue(text_value); } } void Choice::set_value(const std::string& value, bool change_event) //! Redundant? { m_disable_change_event = !change_event; - - size_t idx=0; - for (auto el : m_opt.enum_values) - { - if (el == value) - break; - ++idx; - } - choice_ctrl* field = dynamic_cast(window); - idx == m_opt.enum_values.size() ? - field->SetValue(value) : - field->SetSelection(idx); - + if (auto opt = m_opt.enum_def->value_to_index(value); opt.has_value()) + // This enum has a value field of the same content as text_value. Select it. + field->SetSelection(opt.value()); + else + field->SetValue(value); m_disable_change_event = false; } @@ -1184,27 +1168,17 @@ void Choice::set_value(const boost::any& value, bool change_event) case coFloatOrPercent: case coString: case coStrings: { - wxString text_value; - if (m_opt.type == coInt) - text_value = wxString::Format(_T("%i"), int(boost::any_cast(value))); - else - text_value = boost::any_cast(value); - size_t idx = 0; - const std::vector& enums = m_opt.enum_values.empty() ? m_opt.enum_labels : m_opt.enum_values; - for (auto el : enums) - { - if (el == text_value) - break; - ++idx; - } - if (idx == enums.size()) { + wxString text_value = m_opt.type == coInt ? + wxString::Format(_T("%i"), int(boost::any_cast(value))) : + boost::any_cast(value); + if (auto idx = m_opt.enum_def->label_to_index(into_u8(text_value)); idx.has_value()) { + field->SetSelection(idx.value()); + } else { // For editable Combobox under OSX is needed to set selection to -1 explicitly, // otherwise selection doesn't be changed field->SetSelection(-1); field->SetValue(text_value); } - else - field->SetSelection(idx); if (!m_value.empty() && m_opt.opt_key == "fill_density") { // If m_value was changed before, then update m_value here too to avoid case @@ -1217,36 +1191,9 @@ void Choice::set_value(const boost::any& value, bool change_event) break; } case coEnum: { - int val = boost::any_cast(value); - if (m_opt_id == "top_fill_pattern" || m_opt_id == "bottom_fill_pattern" || m_opt_id == "fill_pattern") - { - std::string key; - const t_config_enum_values& map_names = ConfigOptionEnum::get_enum_values(); - for (auto it : map_names) - if (val == it.second) { - key = it.first; - break; - } - - const std::vector& values = m_opt.enum_values; - auto it = std::find(values.begin(), values.end(), key); - val = it == values.end() ? 0 : it - values.begin(); - } - else if (m_opt_id == "support_material_style") - { - std::string key; - const t_config_enum_values& map_names = ConfigOptionEnum::get_enum_values(); - for (auto it : map_names) - if (val == it.second) { - key = it.first; - break; - } - - const std::vector& values = m_opt.enum_values; - auto it = std::find(values.begin(), values.end(), key); - val = it == values.end() ? 0 : it - values.begin(); - } - field->SetSelection(val); + auto val = m_opt.enum_def->enum_to_index(boost::any_cast(value)); + assert(val.has_value()); + field->SetSelection(val.has_value() ? val.value() : 0); break; } default: @@ -1309,28 +1256,21 @@ boost::any& Choice::get_value() return m_value = boost::any(ret_str); if (m_opt.type == coEnum) - { - if (m_opt_id == "top_fill_pattern" || m_opt_id == "bottom_fill_pattern" || m_opt_id == "fill_pattern") { - const std::string& key = m_opt.enum_values[field->GetSelection()]; - m_value = int(ConfigOptionEnum::get_enum_values().at(key)); - } else if (m_opt_id == "support_material_style") { - m_value = int(ConfigOptionEnum::get_enum_values().at(m_opt.enum_values[field->GetSelection()])); - } - else - m_value = field->GetSelection(); - } + // Closed enum: The combo box item index returned by the field must be convertible to an enum value. + m_value = m_opt.enum_def->index_to_enum(field->GetSelection()); else if (m_opt.gui_type == ConfigOptionDef::GUIType::f_enum_open || m_opt.gui_type == ConfigOptionDef::GUIType::i_enum_open) { + // Open enum: The combo box item index returned by the field const int ret_enum = field->GetSelection(); - if (ret_enum < 0 || m_opt.enum_values.empty() || m_opt.type == coStrings || - (ret_str != m_opt.enum_values[ret_enum] && ret_str != _(m_opt.enum_labels[ret_enum]))) + if (ret_enum < 0 || ! m_opt.enum_def->has_values() || m_opt.type == coStrings || + (into_u8(ret_str) != m_opt.enum_def->value(ret_enum) && ret_str != _(m_opt.enum_def->label(ret_enum)))) // modifies ret_string! get_value_by_opt_type(ret_str); else if (m_opt.type == coFloatOrPercent) - m_value = m_opt.enum_values[ret_enum]; + m_value = m_opt.enum_def->value(ret_enum); else if (m_opt.type == coInt) - m_value = atoi(m_opt.enum_values[ret_enum].c_str()); + m_value = atoi(m_opt.enum_def->value(ret_enum).c_str()); else - m_value = string_to_double_decimal_point(m_opt.enum_values[ret_enum]); + m_value = string_to_double_decimal_point(m_opt.enum_def->value(ret_enum)); } else // modifies ret_string! diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index 199a1e8d7..c7c5056d0 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -280,34 +280,11 @@ static void add_config_substitutions(const ConfigSubstitutions& conf_substitutio switch (def->type) { case coEnum: { - const std::vector& labels = def->enum_labels; - const std::vector& values = def->enum_values; - int val = conf_substitution.new_value->getInt(); - - bool is_infill = def->opt_key == "top_fill_pattern" || - def->opt_key == "bottom_fill_pattern" || - def->opt_key == "fill_pattern" || - def->opt_key == "support_material_style"; - - // Each infill doesn't use all list of infill declared in PrintConfig.hpp. - // So we should "convert" val to the correct one - if (is_infill) { - for (const auto& key_val : *def->enum_keys_map) - if ((int)key_val.second == val) { - auto it = std::find(values.begin(), values.end(), key_val.first); - if (it == values.end()) - break; - auto idx = it - values.begin(); - new_val = wxString("\"") + values[idx] + "\"" + " (" + from_u8(_utf8(labels[idx])) + ")"; - break; - } - if (new_val.IsEmpty()) { - assert(false); - new_val = _L("Undefined"); - } - } - else - new_val = wxString("\"") + values[val] + "\"" + " (" + from_u8(_utf8(labels[val])) + ")"; + auto opt = def->enum_def->enum_to_index(conf_substitution.new_value->getInt()); + new_val = opt.has_value() ? + wxString("\"") + def->enum_def->value(opt.value()) + "\"" + " (" + + _(wxString::FromUTF8(def->enum_def->label(opt.value()))) + ")" : + _L("Undefined"); break; } case coBool: diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 7add6075b..d04a9cf2f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -511,14 +511,14 @@ GLGizmoHollow::get_config_options(const std::vector& keys) const for (const std::string& key : keys) { if (object_cfg.has(key)) - out.emplace_back(object_cfg.option(key), &object_cfg.def()->options.at(key)); // at() needed for const map + out.emplace_back(object_cfg.option(key), object_cfg.option_def(key)); else if (print_cfg.has(key)) - out.emplace_back(print_cfg.option(key), &print_cfg.def()->options.at(key)); + out.emplace_back(print_cfg.option(key), print_cfg.option_def(key)); else { // we must get it from defaults if (default_cfg == nullptr) default_cfg.reset(DynamicPrintConfig::new_from_defaults_keys(keys)); - out.emplace_back(default_cfg->option(key), &default_cfg->def()->options.at(key)); + out.emplace_back(default_cfg->option(key), default_cfg->option_def(key)); } } diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.cpp b/src/slic3r/GUI/PhysicalPrinterDialog.cpp index e3aff63ca..8237ddd99 100644 --- a/src/slic3r/GUI/PhysicalPrinterDialog.cpp +++ b/src/slic3r/GUI/PhysicalPrinterDialog.cpp @@ -613,32 +613,33 @@ void PhysicalPrinterDialog::update_host_type(bool printer_change) // Append localized enum_labels - assert(ht->m_opt.enum_labels.size() == ht->m_opt.enum_values.size()); - for (size_t i = 0; i < ht->m_opt.enum_labels.size(); i++) { - if (ht->m_opt.enum_values[i] == "prusalink"){ - link.label = _(ht->m_opt.enum_labels[i]); + assert(ht->m_opt.enum_def->labels().size() == ht->m_opt.enum_def->values().size()); + for (size_t i = 0; i < ht->m_opt.enum_def->labels().size(); ++ i) { + wxString label = _(ht->m_opt.enum_def->label(i)); + if (const std::string &value = ht->m_opt.enum_def->value(i); + value == "prusalink") { + link.label = label; if (!link.supported) continue; - } - if (ht->m_opt.enum_values[i] == "prusaconnect") { - connect.label = _(ht->m_opt.enum_labels[i]); + } else if (value == "prusaconnect") { + connect.label = label; if (!connect.supported) continue; } - types.Add(_(ht->m_opt.enum_labels[i])); + types.Add(label); } Choice* choice = dynamic_cast(ht); choice->set_values(types); int index_in_choice = (printer_change ? 0 : last_in_conf); choice->set_value(index_in_choice); - if (link.supported && link.label == _(ht->m_opt.enum_labels[index_in_choice])) + if (link.supported && link.label == _(ht->m_opt.enum_def->label(index_in_choice))) m_config->set_key_value("host_type", new ConfigOptionEnum(htPrusaLink)); - else if (link.supported && link.label == _(ht->m_opt.enum_labels[index_in_choice])) + else if (link.supported && link.label == _(ht->m_opt.enum_def->label(index_in_choice))) m_config->set_key_value("host_type", new ConfigOptionEnum(htPrusaConnect)); else { - int host_type = std::clamp(index_in_choice + ((int)ht->m_opt.enum_values.size() - (int)types.size()), 0, (int)ht->m_opt.enum_values.size() - 1); + int host_type = std::clamp(index_in_choice + ((int)ht->m_opt.enum_def->values().size() - (int)types.size()), 0, (int)ht->m_opt.enum_def->values().size() - 1); PrintHostType type = static_cast(host_type); m_config->set_key_value("host_type", new ConfigOptionEnum(type)); } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 2fd8ddd39..7c91b7dac 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -433,12 +433,13 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) : ConfigOptionDef support_def; support_def.label = L("Supports"); support_def.type = coStrings; - support_def.gui_type = ConfigOptionDef::GUIType::select_open; support_def.tooltip = L("Select what kind of support do you need"); - support_def.enum_labels.push_back(L("None")); - support_def.enum_labels.push_back(L("Support on build plate only")); - support_def.enum_labels.push_back(L("For support enforcers only")); - support_def.enum_labels.push_back(L("Everywhere")); + support_def.set_enum_labels(ConfigOptionDef::GUIType::select_open, { + L("None"), + L("Support on build plate only"), + L("For support enforcers only"), + L("Everywhere") + }); support_def.set_default_value(new ConfigOptionStrings{ "None" }); Option option = Option(support_def, "support"); option.opt.full_width = true; @@ -587,11 +588,12 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) : ConfigOptionDef pad_def; pad_def.label = L("Pad"); pad_def.type = coStrings; - pad_def.gui_type = ConfigOptionDef::GUIType::select_open; pad_def.tooltip = L("Select what kind of pad do you need"); - pad_def.enum_labels.push_back(L("None")); - pad_def.enum_labels.push_back(L("Below object")); - pad_def.enum_labels.push_back(L("Around object")); + pad_def.set_enum_labels(ConfigOptionDef::GUIType::select_open, { + L("None"), + L("Below object"), + L("Around object") + }); pad_def.set_default_value(new ConfigOptionStrings{ "Below object" }); option = Option(pad_def, "pad"); option.opt.full_width = true; diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index a7eb46753..61229ba43 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -165,23 +165,20 @@ static void append_bool_option( std::shared_ptr optgroup, wxGetApp().sidebar().get_searcher().add_key(opt_key, Preset::TYPE_PREFERENCES, optgroup->config_category(), L("Preferences")); } +template static void append_enum_option( std::shared_ptr optgroup, const std::string& opt_key, const std::string& label, const std::string& tooltip, const ConfigOption* def_val, - const t_config_enum_values *enum_keys_map, - std::initializer_list enum_values, - std::initializer_list enum_labels, + std::initializer_list> enum_values, ConfigOptionMode mode = comSimple) { ConfigOptionDef def = {opt_key, coEnum }; def.label = label; def.tooltip = tooltip; def.mode = mode; - def.enum_keys_map = enum_keys_map; - def.enum_values = std::vector(enum_values); - def.enum_labels = std::vector(enum_labels); + def.set_enum(enum_values); def.set_default_value(def_val); Option option(def, opt_key); @@ -210,7 +207,7 @@ static void append_string_option(std::shared_ptr optgroup, wxGetApp().sidebar().get_searcher().add_key(opt_key, Preset::TYPE_PREFERENCES, optgroup->config_category(), L("Preferences")); } -static void append_preferences_option_to_searcer(std::shared_ptr optgroup, +static void append_preferences_option_to_searcher(std::shared_ptr optgroup, const std::string& opt_key, const wxString& label) { @@ -547,13 +544,14 @@ void PreferencesDialog::build() L("If enabled, useful hints are displayed at startup."), app_config->get("show_hints") == "1"); - append_enum_option(m_optgroup_gui, "notify_release", + append_enum_option(m_optgroup_gui, "notify_release", L("Notify about new releases"), L("You will be notified about new release after startup acordingly: All = Regular release and alpha / beta releases. Release only = regular release."), new ConfigOptionEnum(static_cast(s_keys_map_NotifyReleaseMode.at(app_config->get("notify_release")))), - &ConfigOptionEnum::get_enum_values(), - {"all", "release", "none"}, - {L("All"), L("Release only"), L("None")}); + { { "all", L("All") }, + { "release", L("Release only") }, + { "none", L("None") } + }); m_optgroup_gui->append_separator(); @@ -1026,7 +1024,7 @@ void PreferencesDialog::create_settings_mode_widget() sizer->Add(stb_sizer, 1, wxALIGN_CENTER_VERTICAL); m_optgroup_gui->sizer->Add(sizer, 0, wxEXPAND | wxTOP, em_unit()); - append_preferences_option_to_searcer(m_optgroup_gui, opt_key, title); + append_preferences_option_to_searcher(m_optgroup_gui, opt_key, title); } void PreferencesDialog::create_settings_text_color_widget() @@ -1050,7 +1048,7 @@ void PreferencesDialog::create_settings_text_color_widget() m_optgroup_gui->sizer->Add(sizer, 0, wxEXPAND | wxTOP, em_unit()); - append_preferences_option_to_searcer(m_optgroup_gui, opt_key, title); + append_preferences_option_to_searcher(m_optgroup_gui, opt_key, title); } void PreferencesDialog::create_settings_mode_color_widget() @@ -1077,7 +1075,7 @@ void PreferencesDialog::create_settings_mode_color_widget() m_optgroup_gui->sizer->Add(sizer, 0, wxEXPAND | wxTOP, em_unit()); - append_preferences_option_to_searcer(m_optgroup_gui, opt_key, title); + append_preferences_option_to_searcher(m_optgroup_gui, opt_key, title); } void PreferencesDialog::create_downloader_path_sizer() @@ -1096,7 +1094,7 @@ void PreferencesDialog::create_downloader_path_sizer() m_optgroup_other->sizer->Add(sizer, 0, wxEXPAND | wxTOP, em_unit()); - append_preferences_option_to_searcer(m_optgroup_other, opt_key, title); + append_preferences_option_to_searcher(m_optgroup_other, opt_key, title); } void PreferencesDialog::init_highlighter(const t_config_option_key& opt_key) diff --git a/src/slic3r/GUI/Search.cpp b/src/slic3r/GUI/Search.cpp index 6ad4af3a1..5ef18b7c9 100644 --- a/src/slic3r/GUI/Search.cpp +++ b/src/slic3r/GUI/Search.cpp @@ -111,7 +111,7 @@ void OptionsSearcher::append_options(DynamicPrintConfig* config, Preset::Type ty for (std::string opt_key : config->keys()) { - const ConfigOptionDef& opt = config->def()->options.at(opt_key); + const ConfigOptionDef& opt = *config->option_def(opt_key); if (opt.mode > mode) continue; diff --git a/src/slic3r/GUI/UnsavedChangesDialog.cpp b/src/slic3r/GUI/UnsavedChangesDialog.cpp index 11517bf10..06cba39fe 100644 --- a/src/slic3r/GUI/UnsavedChangesDialog.cpp +++ b/src/slic3r/GUI/UnsavedChangesDialog.cpp @@ -1056,27 +1056,6 @@ bool UnsavedChangesDialog::save(PresetCollection* dependent_presets, bool show_s return true; } -wxString get_string_from_enum(const std::string& opt_key, const DynamicPrintConfig& config, bool is_infill = false) -{ - const ConfigOptionDef& def = config.def()->options.at(opt_key); - const std::vector& names = def.enum_labels.empty() ? def.enum_values : def.enum_labels; - int val = config.option(opt_key)->getInt(); - - // Each infill doesn't use all list of infill declared in PrintConfig.hpp. - // So we should "convert" val to the correct one - if (is_infill) { - for (auto key_val : *def.enum_keys_map) - if (int(key_val.second) == val) { - auto it = std::find(def.enum_values.begin(), def.enum_values.end(), key_val.first); - if (it == def.enum_values.end()) - return ""; - return from_u8(_utf8(names[it - def.enum_values.begin()])); - } - return _L("Undef"); - } - return from_u8(_utf8(names[val])); -} - static size_t get_id_from_opt_key(std::string opt_key) { int pos = opt_key.find("#"); @@ -1214,11 +1193,8 @@ static wxString get_string_value(std::string opt_key, const DynamicPrintConfig& return out; } case coEnum: { - return get_string_from_enum(opt_key, config, - opt_key == "top_fill_pattern" || - opt_key == "bottom_fill_pattern" || - opt_key == "fill_pattern" || - opt_key == "support_material_style"); + auto opt = config.option_def(opt_key)->enum_def->enum_to_label(config.option(opt_key)->getInt()); + return opt.has_value() ? _(wxString::FromUTF8(opt.value())) : _L("Undef"); } case coPoints: { if (opt_key == "bed_shape") {