mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 12:11:15 -06:00 
			
		
		
		
	WIP: Nullable configuration value concept, implemented for
ConfigOptionFloatsNullable, ConfigOptionIntsNullable, ConfigOptionPercentsNullable, ConfigOptionBoolsNullable. retract override values were added to the Filament profile: vector of floats: "retract_length", "retract_lift", "retract_lift_above", "retract_lift_below", "retract_speed", "deretract_speed", "retract_restart_extra", "retract_before_travel", vector of bools: "retract_layer_change", "wipe" vector of percents: "retract_before_wipe"
This commit is contained in:
		
							parent
							
								
									bb604242aa
								
							
						
					
					
						commit
						3b1a44c084
					
				
					 7 changed files with 348 additions and 182 deletions
				
			
		|  | @ -102,7 +102,7 @@ protected: | |||
|         #ifndef BOOST_NOWIDE_DO_LENGTH_MBSTATE_CONST | ||||
|         return from - save_from; | ||||
|         #else | ||||
|         return save_max - max; | ||||
|         return int(save_max - max); | ||||
|         #endif | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -211,25 +211,35 @@ std::vector<std::string> ConfigOptionDef::cli_args(const std::string &key) const | |||
| 
 | ||||
| ConfigOption* ConfigOptionDef::create_empty_option() const | ||||
| { | ||||
|     switch (this->type) { | ||||
|     case coFloat:           return new ConfigOptionFloat(); | ||||
|     case coFloats:          return new ConfigOptionFloats(); | ||||
|     case coInt:             return new ConfigOptionInt(); | ||||
|     case coInts:            return new ConfigOptionInts(); | ||||
|     case coString:          return new ConfigOptionString(); | ||||
|     case coStrings:         return new ConfigOptionStrings(); | ||||
|     case coPercent:         return new ConfigOptionPercent(); | ||||
|     case coPercents:        return new ConfigOptionPercents(); | ||||
|     case coFloatOrPercent:  return new ConfigOptionFloatOrPercent(); | ||||
|     case coPoint:           return new ConfigOptionPoint(); | ||||
|     case coPoints:          return new ConfigOptionPoints(); | ||||
|     case coPoint3:          return new ConfigOptionPoint3(); | ||||
| //    case coPoint3s:         return new ConfigOptionPoint3s();
 | ||||
|     case coBool:            return new ConfigOptionBool(); | ||||
|     case coBools:           return new ConfigOptionBools(); | ||||
|     case coEnum:            return new ConfigOptionEnumGeneric(this->enum_keys_map); | ||||
|     default:                throw std::runtime_error(std::string("Unknown option type for option ") + this->label); | ||||
|     } | ||||
| 	if (this->nullable) { | ||||
| 	    switch (this->type) { | ||||
| 	    case coFloats:          return new ConfigOptionFloatsNullable(); | ||||
| 	    case coInts:            return new ConfigOptionIntsNullable(); | ||||
| 	    case coPercents:        return new ConfigOptionPercentsNullable(); | ||||
| 	    case coBools:           return new ConfigOptionBoolsNullable(); | ||||
| 	    default:                throw std::runtime_error(std::string("Unknown option type for nullable option ") + this->label); | ||||
| 	    } | ||||
| 	} else { | ||||
| 	    switch (this->type) { | ||||
| 	    case coFloat:           return new ConfigOptionFloat(); | ||||
| 	    case coFloats:          return new ConfigOptionFloats(); | ||||
| 	    case coInt:             return new ConfigOptionInt(); | ||||
| 	    case coInts:            return new ConfigOptionInts(); | ||||
| 	    case coString:          return new ConfigOptionString(); | ||||
| 	    case coStrings:         return new ConfigOptionStrings(); | ||||
| 	    case coPercent:         return new ConfigOptionPercent(); | ||||
| 	    case coPercents:        return new ConfigOptionPercents(); | ||||
| 	    case coFloatOrPercent:  return new ConfigOptionFloatOrPercent(); | ||||
| 	    case coPoint:           return new ConfigOptionPoint(); | ||||
| 	    case coPoints:          return new ConfigOptionPoints(); | ||||
| 	    case coPoint3:          return new ConfigOptionPoint3(); | ||||
| 	//    case coPoint3s:         return new ConfigOptionPoint3s();
 | ||||
| 	    case coBool:            return new ConfigOptionBool(); | ||||
| 	    case coBools:           return new ConfigOptionBools(); | ||||
| 	    case coEnum:            return new ConfigOptionEnumGeneric(this->enum_keys_map); | ||||
| 	    default:                throw std::runtime_error(std::string("Unknown option type for option ") + this->label); | ||||
| 	    } | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| ConfigOption* ConfigOptionDef::create_default_option() const | ||||
|  | @ -254,6 +264,13 @@ ConfigOptionDef* ConfigDef::add(const t_config_option_key &opt_key, ConfigOption | |||
|     return opt; | ||||
| } | ||||
| 
 | ||||
| ConfigOptionDef* ConfigDef::add_nullable(const t_config_option_key &opt_key, ConfigOptionType type) | ||||
| { | ||||
| 	ConfigOptionDef *def = this->add(opt_key, type); | ||||
| 	def->nullable = true; | ||||
| 	return def; | ||||
| } | ||||
| 
 | ||||
| std::string ConfigOptionDef::nocli = "~~~noCLI"; | ||||
| 
 | ||||
| std::ostream& ConfigDef::print_cli_help(std::ostream& out, bool show_defaults, std::function<bool(const ConfigOptionDef &)> filter) const | ||||
|  | @ -642,6 +659,17 @@ void ConfigBase::save(const std::string &file) const | |||
|     c.close(); | ||||
| } | ||||
| 
 | ||||
| // Set all the nullable values to nils.
 | ||||
| void ConfigBase::null_nullables() | ||||
| { | ||||
|     for (const std::string &opt_key : this->keys()) { | ||||
|         ConfigOption *opt = this->optptr(opt_key, false); | ||||
|         assert(opt != nullptr); | ||||
|         if (opt->nullable()) | ||||
|         	opt->deserialize("nil"); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool DynamicConfig::operator==(const DynamicConfig &rhs) const | ||||
| { | ||||
|     auto it1     = this->options.begin(); | ||||
|  | @ -655,6 +683,19 @@ bool DynamicConfig::operator==(const DynamicConfig &rhs) const | |||
|     return it1 == it1_end && it2 == it2_end; | ||||
| } | ||||
| 
 | ||||
| // Remove options with all nil values, those are optional and it does not help to hold them.
 | ||||
| size_t DynamicConfig::remove_nil_options() | ||||
| { | ||||
| 	size_t cnt_removed = 0; | ||||
| 	for (auto it = options.begin(); it != options.end();) | ||||
| 		if (it->second->is_nil()) { | ||||
| 			it = options.erase(it); | ||||
| 			++ cnt_removed; | ||||
| 		} else | ||||
| 			++ it; | ||||
| 	return cnt_removed; | ||||
| } | ||||
| 
 | ||||
| ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key, bool create) | ||||
| { | ||||
|     auto it = options.find(opt_key); | ||||
|  | @ -838,18 +879,22 @@ CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionVector<Slic3r::Vec2d>) | |||
| CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionVector<unsigned char>) | ||||
| CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionFloat) | ||||
| CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionFloats) | ||||
| CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionFloatsNullable) | ||||
| CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionInt) | ||||
| CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionInts) | ||||
| CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionIntsNullable) | ||||
| CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionString) | ||||
| CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionStrings) | ||||
| CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPercent) | ||||
| CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPercents) | ||||
| CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPercentsNullable) | ||||
| CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionFloatOrPercent) | ||||
| CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPoint) | ||||
| CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPoints) | ||||
| CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPoint3) | ||||
| CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionBool) | ||||
| CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionBools) | ||||
| CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionBoolsNullable) | ||||
| CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionEnumGeneric) | ||||
| CEREAL_REGISTER_TYPE(Slic3r::ConfigBase) | ||||
| CEREAL_REGISTER_TYPE(Slic3r::DynamicConfig) | ||||
|  | @ -868,17 +913,21 @@ CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVectorBase, Slic3r::Con | |||
| CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVectorBase, Slic3r::ConfigOptionVector<unsigned char>) | ||||
| CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<double>, Slic3r::ConfigOptionFloat) | ||||
| CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<double>, Slic3r::ConfigOptionFloats) | ||||
| CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<double>, Slic3r::ConfigOptionFloatsNullable) | ||||
| CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<int>, Slic3r::ConfigOptionInt) | ||||
| CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<int>, Slic3r::ConfigOptionInts) | ||||
| CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<int>, Slic3r::ConfigOptionIntsNullable) | ||||
| CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<std::string>, Slic3r::ConfigOptionString) | ||||
| CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<std::string>, Slic3r::ConfigOptionStrings) | ||||
| CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionFloat, Slic3r::ConfigOptionPercent) | ||||
| CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionFloats, Slic3r::ConfigOptionPercents) | ||||
| CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionFloats, Slic3r::ConfigOptionPercentsNullable) | ||||
| CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionPercent, Slic3r::ConfigOptionFloatOrPercent) | ||||
| CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<Slic3r::Vec2d>, Slic3r::ConfigOptionPoint) | ||||
| CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<Slic3r::Vec2d>, Slic3r::ConfigOptionPoints) | ||||
| CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<Slic3r::Vec3d>, Slic3r::ConfigOptionPoint3) | ||||
| CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<bool>, Slic3r::ConfigOptionBool) | ||||
| CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<unsigned char>, Slic3r::ConfigOptionBools) | ||||
| CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<unsigned char>, Slic3r::ConfigOptionBoolsNullable) | ||||
| CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionInt, Slic3r::ConfigOptionEnumGeneric) | ||||
| CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigBase, Slic3r::DynamicConfig) | ||||
|  |  | |||
|  | @ -15,6 +15,7 @@ | |||
| #include "clonable_ptr.hpp" | ||||
| #include "Point.hpp" | ||||
| 
 | ||||
| #include <boost/algorithm/string/trim.hpp> | ||||
| #include <boost/format.hpp> | ||||
| #include <boost/property_tree/ptree.hpp> | ||||
| 
 | ||||
|  | @ -124,6 +125,10 @@ public: | |||
|     bool                        operator!=(const ConfigOption &rhs) const { return ! (*this == rhs); } | ||||
|     bool                        is_scalar()     const { return (int(this->type()) & int(coVectorType)) == 0; } | ||||
|     bool                        is_vector()     const { return ! this->is_scalar(); } | ||||
|     // If this option is nullable, then it may have its value or values set to nil.
 | ||||
|     virtual bool 				nullable()		const { return false; } | ||||
|     // A scalar is nil, or all values of a vector are nil.
 | ||||
|     virtual bool 				is_nil() 		const { return false; } | ||||
| }; | ||||
| 
 | ||||
| typedef ConfigOption*       ConfigOptionPtr; | ||||
|  | @ -345,26 +350,35 @@ private: | |||
| 	template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionSingle<double>>(this)); } | ||||
| }; | ||||
| 
 | ||||
| class ConfigOptionFloats : public ConfigOptionVector<double> | ||||
| template<bool NULLABLE> | ||||
| class ConfigOptionFloatsTempl : public ConfigOptionVector<double> | ||||
| { | ||||
| public: | ||||
|     ConfigOptionFloats() : ConfigOptionVector<double>() {} | ||||
|     explicit ConfigOptionFloats(size_t n, double value) : ConfigOptionVector<double>(n, value) {} | ||||
|     explicit ConfigOptionFloats(std::initializer_list<double> il) : ConfigOptionVector<double>(std::move(il)) {} | ||||
|     explicit ConfigOptionFloats(const std::vector<double> &vec) : ConfigOptionVector<double>(vec) {} | ||||
|     explicit ConfigOptionFloats(std::vector<double> &&vec) : ConfigOptionVector<double>(std::move(vec)) {} | ||||
|     ConfigOptionFloatsTempl() : ConfigOptionVector<double>() {} | ||||
|     explicit ConfigOptionFloatsTempl(size_t n, double value) : ConfigOptionVector<double>(n, value) {} | ||||
|     explicit ConfigOptionFloatsTempl(std::initializer_list<double> il) : ConfigOptionVector<double>(std::move(il)) {} | ||||
|     explicit ConfigOptionFloatsTempl(const std::vector<double> &vec) : ConfigOptionVector<double>(vec) {} | ||||
|     explicit ConfigOptionFloatsTempl(std::vector<double> &&vec) : ConfigOptionVector<double>(std::move(vec)) {} | ||||
| 
 | ||||
|     static ConfigOptionType static_type() { return coFloats; } | ||||
|     ConfigOptionType        type()  const override { return static_type(); } | ||||
|     ConfigOption*           clone() const override { return new ConfigOptionFloats(*this); } | ||||
|     bool                    operator==(const ConfigOptionFloats &rhs) const { return this->values == rhs.values; } | ||||
|     ConfigOption*           clone() const override { return new ConfigOptionFloatsTempl(*this); } | ||||
|     bool                    operator==(const ConfigOptionFloatsTempl &rhs) const { return this->values == rhs.values; } | ||||
|     // Could a special "nil" value be stored inside the vector, indicating undefined value?
 | ||||
|     bool 					nullable() const override { return NULLABLE; } | ||||
|     // Special "nil" value to be stored into the vector if this->supports_nil().
 | ||||
|     static double 			nil_value() { return std::numeric_limits<double>::quiet_NaN(); } | ||||
|     // A scalar is nil, or all values of a vector are nil.
 | ||||
|     virtual bool 			is_nil() const override { for (auto v : this->values) if (! std::isnan(v)) return false; return true; } | ||||
|     bool 					is_nil(size_t idx) const { return std::isnan(v->values[idx]); } | ||||
| 
 | ||||
|     std::string serialize() const override | ||||
|     { | ||||
|         std::ostringstream ss; | ||||
|         for (std::vector<double>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) { | ||||
|             if (it - this->values.begin() != 0) ss << ","; | ||||
|             ss << *it; | ||||
|         for (const double &v : this->values) { | ||||
|             if (&v != &this->values.front()) | ||||
|             	ss << ","; | ||||
|         	serialize_single_value(ss, v); | ||||
|         } | ||||
|         return ss.str(); | ||||
|     } | ||||
|  | @ -373,14 +387,14 @@ public: | |||
|     { | ||||
|         std::vector<std::string> vv; | ||||
|         vv.reserve(this->values.size()); | ||||
|         for (std::vector<double>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) { | ||||
|         for (const double v : this->values) { | ||||
|             std::ostringstream ss; | ||||
|             ss << *it; | ||||
|         	serialize_single_value(ss, v); | ||||
|             vv.push_back(ss.str()); | ||||
|         } | ||||
|         return vv; | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     bool deserialize(const std::string &str, bool append = false) override | ||||
|     { | ||||
|         if (! append) | ||||
|  | @ -388,25 +402,49 @@ public: | |||
|         std::istringstream is(str); | ||||
|         std::string item_str; | ||||
|         while (std::getline(is, item_str, ',')) { | ||||
|             std::istringstream iss(item_str); | ||||
|             double value; | ||||
|             iss >> value; | ||||
|             this->values.push_back(value); | ||||
|         	boost::trim(item_str); | ||||
|         	if (item_str == "nil") { | ||||
|         		if (NULLABLE) | ||||
|         			this->values.push_back(nil_value()); | ||||
|         		else | ||||
|         			std::runtime_error("Deserializing nil into a non-nullable object"); | ||||
|         	} else { | ||||
| 	            std::istringstream iss(item_str); | ||||
| 	            double value; | ||||
| 	            iss >> value; | ||||
| 	            this->values.push_back(value); | ||||
| 	        } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     ConfigOptionFloats& operator=(const ConfigOption *opt) | ||||
|     ConfigOptionFloatsTempl& operator=(const ConfigOption *opt) | ||||
|     {    | ||||
|         this->set(opt); | ||||
|         return *this; | ||||
|     } | ||||
| 
 | ||||
| protected: | ||||
| 	void serialize_single_value(std::ostringstream &ss, const double v) const { | ||||
|         	if (std::isfinite(v)) | ||||
| 	            ss << v; | ||||
| 	        else if (std::isnan(v)) { | ||||
|         		if (NULLABLE) | ||||
|         			ss << "nil"; | ||||
|         		else | ||||
|         			std::runtime_error("Serializing NaN"); | ||||
|         	} else | ||||
|         		std::runtime_error("Serializing invalid number");		 | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	friend class cereal::access; | ||||
| 	template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionVector<double>>(this)); } | ||||
| }; | ||||
| 
 | ||||
| using ConfigOptionFloats 		 = ConfigOptionFloatsTempl<false>; | ||||
| using ConfigOptionFloatsNullable = ConfigOptionFloatsTempl<true>; | ||||
| 
 | ||||
| class ConfigOptionInt : public ConfigOptionSingle<int> | ||||
| { | ||||
| public: | ||||
|  | @ -447,35 +485,45 @@ private: | |||
| 	template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionSingle<int>>(this)); } | ||||
| }; | ||||
| 
 | ||||
| class ConfigOptionInts : public ConfigOptionVector<int> | ||||
| template<bool NULLABLE> | ||||
| class ConfigOptionIntsTempl : public ConfigOptionVector<int> | ||||
| { | ||||
| public: | ||||
|     ConfigOptionInts() : ConfigOptionVector<int>() {} | ||||
|     explicit ConfigOptionInts(size_t n, int value) : ConfigOptionVector<int>(n, value) {} | ||||
|     explicit ConfigOptionInts(std::initializer_list<int> il) : ConfigOptionVector<int>(std::move(il)) {} | ||||
|     ConfigOptionIntsTempl() : ConfigOptionVector<int>() {} | ||||
|     explicit ConfigOptionIntsTempl(size_t n, int value) : ConfigOptionVector<int>(n, value) {} | ||||
|     explicit ConfigOptionIntsTempl(std::initializer_list<int> il) : ConfigOptionVector<int>(std::move(il)) {} | ||||
| 
 | ||||
|     static ConfigOptionType static_type() { return coInts; } | ||||
|     ConfigOptionType        type()  const override { return static_type(); } | ||||
|     ConfigOption*           clone() const override { return new ConfigOptionInts(*this); } | ||||
|     ConfigOptionInts&       operator=(const ConfigOption *opt) { this->set(opt); return *this; } | ||||
|     bool                    operator==(const ConfigOptionInts &rhs) const { return this->values == rhs.values; } | ||||
|     ConfigOption*           clone() const override { return new ConfigOptionIntsTempl(*this); } | ||||
|     ConfigOptionIntsTempl&  operator=(const ConfigOption *opt) { this->set(opt); return *this; } | ||||
|     bool                    operator==(const ConfigOptionIntsTempl &rhs) const { return this->values == rhs.values; } | ||||
|     // Could a special "nil" value be stored inside the vector, indicating undefined value?
 | ||||
|     bool 					nullable() const override { return NULLABLE; } | ||||
|     // Special "nil" value to be stored into the vector if this->supports_nil().
 | ||||
|     static int	 			nil_value() { return std::numeric_limits<int>::max(); } | ||||
|     // A scalar is nil, or all values of a vector are nil.
 | ||||
|     virtual bool 			is_nil() const override { for (auto v : this->values) if (v != nil_value()) return false; return true; } | ||||
|     bool 					is_nil(size_t idx) const { return v->values[idx] == nil_value(); } | ||||
| 
 | ||||
|     std::string serialize() const override { | ||||
|     std::string serialize() const override | ||||
|     { | ||||
|         std::ostringstream ss; | ||||
|         for (std::vector<int>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) { | ||||
|             if (it - this->values.begin() != 0) ss << ","; | ||||
|             ss << *it; | ||||
|         for (const int &v : this->values) { | ||||
|             if (&v != &this->values.front()) | ||||
|             	ss << ","; | ||||
|         	serialize_single_value(ss, v); | ||||
|         } | ||||
|         return ss.str(); | ||||
|     } | ||||
|      | ||||
|     std::vector<std::string> vserialize() const override  | ||||
|     std::vector<std::string> vserialize() const override | ||||
|     { | ||||
|         std::vector<std::string> vv; | ||||
|         vv.reserve(this->values.size()); | ||||
|         for (std::vector<int>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) { | ||||
|         for (const int v : this->values) { | ||||
|             std::ostringstream ss; | ||||
|             ss << *it; | ||||
|         	serialize_single_value(ss, v); | ||||
|             vv.push_back(ss.str()); | ||||
|         } | ||||
|         return vv; | ||||
|  | @ -488,19 +536,40 @@ public: | |||
|         std::istringstream is(str); | ||||
|         std::string item_str; | ||||
|         while (std::getline(is, item_str, ',')) { | ||||
|             std::istringstream iss(item_str); | ||||
|             int value; | ||||
|             iss >> value; | ||||
|             this->values.push_back(value); | ||||
|         	boost::trim(item_str); | ||||
|         	if (item_str == "nil") { | ||||
|         		if (NULLABLE) | ||||
|         			this->values.push_back(nil_value()); | ||||
|         		else | ||||
|         			std::runtime_error("Deserializing nil into a non-nullable object"); | ||||
|         	} else { | ||||
| 	            std::istringstream iss(item_str); | ||||
| 	            int value; | ||||
| 	            iss >> value; | ||||
| 	            this->values.push_back(value); | ||||
| 	        } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
| 	void serialize_single_value(std::ostringstream &ss, const int v) const { | ||||
| 			if (v == nil_value()) { | ||||
|         		if (NULLABLE) | ||||
|         			ss << "nil"; | ||||
|         		else | ||||
|         			std::runtime_error("Serializing NaN"); | ||||
|         	} else | ||||
|         		ss << v; | ||||
| 	} | ||||
| 
 | ||||
| 	friend class cereal::access; | ||||
| 	template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionVector<int>>(this)); } | ||||
| }; | ||||
| 
 | ||||
| using ConfigOptionInts   	   = ConfigOptionIntsTempl<false>; | ||||
| using ConfigOptionIntsNullable = ConfigOptionIntsTempl<true>; | ||||
| 
 | ||||
| class ConfigOptionString : public ConfigOptionSingle<std::string> | ||||
| { | ||||
| public: | ||||
|  | @ -603,64 +672,61 @@ private: | |||
| 	template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionFloat>(this)); } | ||||
| }; | ||||
| 
 | ||||
| class ConfigOptionPercents : public ConfigOptionFloats | ||||
| template<bool NULLABLE> | ||||
| class ConfigOptionPercentsTempl : public ConfigOptionFloatsTempl<NULLABLE> | ||||
| { | ||||
| public: | ||||
|     ConfigOptionPercents() : ConfigOptionFloats() {} | ||||
|     explicit ConfigOptionPercents(size_t n, double value) : ConfigOptionFloats(n, value) {} | ||||
|     explicit ConfigOptionPercents(std::initializer_list<double> il) : ConfigOptionFloats(std::move(il)) {} | ||||
|     ConfigOptionPercentsTempl() : ConfigOptionFloatsTempl<NULLABLE>() {} | ||||
|     explicit ConfigOptionPercentsTempl(size_t n, double value) : ConfigOptionFloatsTempl<NULLABLE>(n, value) {} | ||||
|     explicit ConfigOptionPercentsTempl(std::initializer_list<double> il) : ConfigOptionFloatsTempl<NULLABLE>(std::move(il)) {} | ||||
| 	explicit ConfigOptionPercentsTempl(const std::vector<double>& vec) : ConfigOptionFloatsTempl<NULLABLE>(vec) {} | ||||
| 	explicit ConfigOptionPercentsTempl(std::vector<double>&& vec) : ConfigOptionFloatsTempl<NULLABLE>(std::move(vec)) {} | ||||
| 
 | ||||
|     static ConfigOptionType static_type() { return coPercents; } | ||||
|     ConfigOptionType        type()  const override { return static_type(); } | ||||
|     ConfigOption*           clone() const override { return new ConfigOptionPercents(*this); } | ||||
|     ConfigOptionPercents&   operator=(const ConfigOption *opt) { this->set(opt); return *this; } | ||||
|     bool                    operator==(const ConfigOptionPercents &rhs) const { return this->values == rhs.values; } | ||||
|     ConfigOption*           clone() const override { return new ConfigOptionPercentsTempl(*this); } | ||||
|     ConfigOptionPercentsTempl&   operator=(const ConfigOption *opt) { this->set(opt); return *this; } | ||||
|     bool                    operator==(const ConfigOptionPercentsTempl &rhs) const { return this->values == rhs.values; } | ||||
| 
 | ||||
|     std::string serialize() const override | ||||
|     { | ||||
|         std::ostringstream ss; | ||||
|         for (const auto &v : this->values) { | ||||
|             if (&v != &this->values.front()) ss << ","; | ||||
|             ss << v << "%"; | ||||
|         for (const double &v : this->values) { | ||||
|             if (&v != &this->values.front()) | ||||
|             	ss << ","; | ||||
| 			this->serialize_single_value(ss, v); | ||||
| 			if (! std::isnan(v)) | ||||
| 				ss << "%"; | ||||
|         } | ||||
|         std::string str = ss.str(); | ||||
|         return str; | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     std::vector<std::string> vserialize() const override | ||||
|     { | ||||
|         std::vector<std::string> vv; | ||||
|         vv.reserve(this->values.size()); | ||||
|         for (const auto v : this->values) { | ||||
|         for (const double v : this->values) { | ||||
|             std::ostringstream ss; | ||||
|             ss << v; | ||||
|             std::string sout = ss.str() + "%"; | ||||
|             vv.push_back(sout); | ||||
| 			this->serialize_single_value(ss, v); | ||||
| 			if (! std::isnan(v)) | ||||
| 				ss << "%"; | ||||
|             vv.push_back(ss.str()); | ||||
|         } | ||||
|         return vv; | ||||
|     } | ||||
| 
 | ||||
|     bool deserialize(const std::string &str, bool append = false) override | ||||
|     { | ||||
|         if (! append) | ||||
|             this->values.clear(); | ||||
|         std::istringstream is(str); | ||||
|         std::string item_str; | ||||
|         while (std::getline(is, item_str, ',')) { | ||||
|             std::istringstream iss(item_str); | ||||
|             double value; | ||||
|             // don't try to parse the trailing % since it's optional
 | ||||
|             iss >> value; | ||||
|             this->values.push_back(value); | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|     // The float's deserialize function shall ignore the trailing optional %.
 | ||||
|     // bool deserialize(const std::string &str, bool append = false) override;
 | ||||
| 
 | ||||
| private: | ||||
| 	friend class cereal::access; | ||||
| 	template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionFloats>(this)); } | ||||
| 	template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionFloatsTempl<NULLABLE>>(this)); } | ||||
| }; | ||||
| 
 | ||||
| using ConfigOptionPercents 	   		= ConfigOptionPercentsTempl<false>; | ||||
| using ConfigOptionPercentsNullable 	= ConfigOptionPercentsTempl<true>; | ||||
| 
 | ||||
| class ConfigOptionFloatOrPercent : public ConfigOptionPercent | ||||
| { | ||||
| public: | ||||
|  | @ -887,18 +953,28 @@ private: | |||
| 	template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionSingle<bool>>(this)); } | ||||
| }; | ||||
| 
 | ||||
| class ConfigOptionBools : public ConfigOptionVector<unsigned char> | ||||
| template<bool NULLABLE> | ||||
| class ConfigOptionBoolsTempl : public ConfigOptionVector<unsigned char> | ||||
| { | ||||
| public: | ||||
|     ConfigOptionBools() : ConfigOptionVector<unsigned char>() {} | ||||
|     explicit ConfigOptionBools(size_t n, bool value) : ConfigOptionVector<unsigned char>(n, (unsigned char)value) {} | ||||
|     explicit ConfigOptionBools(std::initializer_list<bool> il) { values.reserve(il.size()); for (bool b : il) values.emplace_back((unsigned char)b); } | ||||
|     ConfigOptionBoolsTempl() : ConfigOptionVector<unsigned char>() {} | ||||
|     explicit ConfigOptionBoolsTempl(size_t n, bool value) : ConfigOptionVector<unsigned char>(n, (unsigned char)value) {} | ||||
|     explicit ConfigOptionBoolsTempl(std::initializer_list<bool> il) { values.reserve(il.size()); for (bool b : il) values.emplace_back((unsigned char)b); } | ||||
| 	explicit ConfigOptionBoolsTempl(const std::vector<unsigned char>& vec) : ConfigOptionVector<unsigned char>(vec) {} | ||||
| 	explicit ConfigOptionBoolsTempl(std::vector<unsigned char>&& vec) : ConfigOptionVector<unsigned char>(std::move(vec)) {} | ||||
| 
 | ||||
|     static ConfigOptionType static_type() { return coBools; } | ||||
|     ConfigOptionType        type()  const override { return static_type(); } | ||||
|     ConfigOption*           clone() const override { return new ConfigOptionBools(*this); } | ||||
|     ConfigOptionBools&      operator=(const ConfigOption *opt) { this->set(opt); return *this; } | ||||
|     bool                    operator==(const ConfigOptionBools &rhs) const { return this->values == rhs.values; } | ||||
|     ConfigOption*           clone() const override { return new ConfigOptionBoolsTempl(*this); } | ||||
|     ConfigOptionBoolsTempl& operator=(const ConfigOption *opt) { this->set(opt); return *this; } | ||||
|     bool                    operator==(const ConfigOptionBoolsTempl &rhs) const { return this->values == rhs.values; } | ||||
|     // Could a special "nil" value be stored inside the vector, indicating undefined value?
 | ||||
|     bool 					nullable() const override { return NULLABLE; } | ||||
|     // Special "nil" value to be stored into the vector if this->supports_nil().
 | ||||
|     static unsigned char	nil_value() { return std::numeric_limits<unsigned char>::max(); } | ||||
|     // A scalar is nil, or all values of a vector are nil.
 | ||||
|     virtual bool 			is_nil() const override { for (auto v : this->values) if (v != nil_value()) return false; return true; } | ||||
|     bool 					is_nil(size_t idx) const { return v->values[idx] == nil_value(); } | ||||
| 
 | ||||
|     bool& get_at(size_t i) { | ||||
|         assert(! this->values.empty()); | ||||
|  | @ -911,19 +987,20 @@ public: | |||
|     std::string serialize() const override | ||||
|     { | ||||
|         std::ostringstream ss; | ||||
|         for (std::vector<unsigned char>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) { | ||||
|             if (it - this->values.begin() != 0) ss << ","; | ||||
|             ss << (*it ? "1" : "0"); | ||||
|         } | ||||
|         for (const unsigned char &v : this->values) { | ||||
|             if (&v != &this->values.front()) | ||||
|             	ss << ","; | ||||
| 			this->serialize_single_value(ss, v); | ||||
| 		} | ||||
|         return ss.str(); | ||||
|     } | ||||
|      | ||||
|     std::vector<std::string> vserialize() const override | ||||
|     { | ||||
|         std::vector<std::string> vv; | ||||
|         for (std::vector<unsigned char>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) { | ||||
|             std::ostringstream ss; | ||||
|             ss << (*it ? "1" : "0"); | ||||
|         for (const unsigned char v : this->values) { | ||||
| 			std::ostringstream ss; | ||||
| 			this->serialize_single_value(ss, v); | ||||
|             vv.push_back(ss.str()); | ||||
|         } | ||||
|         return vv; | ||||
|  | @ -936,16 +1013,37 @@ public: | |||
|         std::istringstream is(str); | ||||
|         std::string item_str; | ||||
|         while (std::getline(is, item_str, ',')) { | ||||
|             this->values.push_back(item_str.compare("1") == 0); | ||||
|         	boost::trim(item_str); | ||||
|         	if (item_str == "nil") { | ||||
|         		if (NULLABLE) | ||||
|         			this->values.push_back(nil_value()); | ||||
|         		else | ||||
|         			std::runtime_error("Deserializing nil into a non-nullable object"); | ||||
|         	} else | ||||
|         		this->values.push_back(item_str.compare("1") == 0);	 | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
| protected: | ||||
| 	void serialize_single_value(std::ostringstream &ss, const unsigned char v) const { | ||||
|         	if (v == nil_value()) { | ||||
|         		if (NULLABLE) | ||||
|         			ss << "nil"; | ||||
|         		else | ||||
|         			std::runtime_error("Serializing NaN"); | ||||
|         	} else | ||||
|         		ss << (v ? "1" : "0"); | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	friend class cereal::access; | ||||
| 	template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionVector<unsigned char>>(this)); } | ||||
| }; | ||||
| 
 | ||||
| using ConfigOptionBools    	    = ConfigOptionBoolsTempl<false>; | ||||
| using ConfigOptionBoolsNullable = ConfigOptionBoolsTempl<true>; | ||||
| 
 | ||||
| // Map from an enum integer value to an enum name.
 | ||||
| typedef std::vector<std::string>  t_config_enum_names; | ||||
| // Map from an enum name to an enum integer value.
 | ||||
|  | @ -1096,6 +1194,8 @@ public: | |||
| 	t_config_option_key 				opt_key; | ||||
|     // What type? bool, int, string etc.
 | ||||
|     ConfigOptionType                    type            = coNone; | ||||
| 	// If a type is nullable, then it accepts a "nil" value (scalar) or "nil" values (vector).
 | ||||
| 	bool								nullable		= false; | ||||
|     // Default value of this option. The default value object is owned by ConfigDef, it is released in its destructor.
 | ||||
|     Slic3r::clonable_ptr<const ConfigOption> default_value; | ||||
|     void 								set_default_value(const ConfigOption* ptr) { this->default_value = Slic3r::clonable_ptr<const ConfigOption>(ptr); } | ||||
|  | @ -1107,45 +1207,65 @@ public: | |||
|     ConfigOption*						create_default_option() const; | ||||
| 
 | ||||
|     template<class Archive> ConfigOption* load_option_from_archive(Archive &archive) const { | ||||
| 	    switch (this->type) { | ||||
| 	    case coFloat:           { auto opt = new ConfigOptionFloat();  			archive(*opt); return opt; } | ||||
| 	    case coFloats:          { auto opt = new ConfigOptionFloats(); 			archive(*opt); return opt; } | ||||
| 	    case coInt:             { auto opt = new ConfigOptionInt();    			archive(*opt); return opt; } | ||||
| 	    case coInts:            { auto opt = new ConfigOptionInts();   			archive(*opt); return opt; } | ||||
| 	    case coString:          { auto opt = new ConfigOptionString(); 			archive(*opt); return opt; } | ||||
| 	    case coStrings:         { auto opt = new ConfigOptionStrings(); 		archive(*opt); return opt; } | ||||
| 	    case coPercent:         { auto opt = new ConfigOptionPercent(); 		archive(*opt); return opt; } | ||||
| 	    case coPercents:        { auto opt = new ConfigOptionPercents(); 		archive(*opt); return opt; } | ||||
| 	    case coFloatOrPercent:  { auto opt = new ConfigOptionFloatOrPercent(); 	archive(*opt); return opt; } | ||||
| 	    case coPoint:           { auto opt = new ConfigOptionPoint(); 			archive(*opt); return opt; } | ||||
| 	    case coPoints:          { auto opt = new ConfigOptionPoints(); 			archive(*opt); return opt; } | ||||
| 	    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; } | ||||
| 	    default:                throw std::runtime_error(std::string("ConfigOptionDef::load_option_from_archive(): Unknown option type for option ") + this->opt_key); | ||||
| 	    } | ||||
|     	if (this->nullable) { | ||||
| 		    switch (this->type) { | ||||
| 		    case coFloats:          { auto opt = new ConfigOptionFloatsNullable();	archive(*opt); return opt; } | ||||
| 		    case coInts:            { auto opt = new ConfigOptionIntsNullable();	archive(*opt); return opt; } | ||||
| 		    case coPercents:        { auto opt = new ConfigOptionPercentsNullable();archive(*opt); return opt; } | ||||
| 		    case coBools:           { auto opt = new ConfigOptionBoolsNullable();	archive(*opt); return opt; } | ||||
| 		    default:                throw std::runtime_error(std::string("ConfigOptionDef::load_option_from_archive(): Unknown nullable option type for option ") + this->opt_key); | ||||
| 		    } | ||||
|     	} else { | ||||
| 		    switch (this->type) { | ||||
| 		    case coFloat:           { auto opt = new ConfigOptionFloat();  			archive(*opt); return opt; } | ||||
| 		    case coFloats:          { auto opt = new ConfigOptionFloats(); 			archive(*opt); return opt; } | ||||
| 		    case coInt:             { auto opt = new ConfigOptionInt();    			archive(*opt); return opt; } | ||||
| 		    case coInts:            { auto opt = new ConfigOptionInts();   			archive(*opt); return opt; } | ||||
| 		    case coString:          { auto opt = new ConfigOptionString(); 			archive(*opt); return opt; } | ||||
| 		    case coStrings:         { auto opt = new ConfigOptionStrings(); 		archive(*opt); return opt; } | ||||
| 		    case coPercent:         { auto opt = new ConfigOptionPercent(); 		archive(*opt); return opt; } | ||||
| 		    case coPercents:        { auto opt = new ConfigOptionPercents(); 		archive(*opt); return opt; } | ||||
| 		    case coFloatOrPercent:  { auto opt = new ConfigOptionFloatOrPercent(); 	archive(*opt); return opt; } | ||||
| 		    case coPoint:           { auto opt = new ConfigOptionPoint(); 			archive(*opt); return opt; } | ||||
| 		    case coPoints:          { auto opt = new ConfigOptionPoints(); 			archive(*opt); return opt; } | ||||
| 		    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; } | ||||
| 		    default:                throw std::runtime_error(std::string("ConfigOptionDef::load_option_from_archive(): Unknown option type for option ") + this->opt_key); | ||||
| 		    } | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|     template<class Archive> ConfigOption* save_option_to_archive(Archive &archive, const ConfigOption *opt) const { | ||||
| 	    switch (this->type) { | ||||
| 	    case coFloat:           archive(*static_cast<const ConfigOptionFloat*>(opt));  			break; | ||||
| 	    case coFloats:          archive(*static_cast<const ConfigOptionFloats*>(opt)); 			break; | ||||
| 	    case coInt:             archive(*static_cast<const ConfigOptionInt*>(opt)); 	 		break; | ||||
| 	    case coInts:            archive(*static_cast<const ConfigOptionInts*>(opt)); 	 		break; | ||||
| 	    case coString:          archive(*static_cast<const ConfigOptionString*>(opt)); 			break; | ||||
| 	    case coStrings:         archive(*static_cast<const ConfigOptionStrings*>(opt)); 		break; | ||||
| 	    case coPercent:         archive(*static_cast<const ConfigOptionPercent*>(opt)); 		break; | ||||
| 	    case coPercents:        archive(*static_cast<const ConfigOptionPercents*>(opt)); 		break; | ||||
| 	    case coFloatOrPercent:  archive(*static_cast<const ConfigOptionFloatOrPercent*>(opt));	break; | ||||
| 	    case coPoint:           archive(*static_cast<const ConfigOptionPoint*>(opt)); 			break; | ||||
| 	    case coPoints:          archive(*static_cast<const ConfigOptionPoints*>(opt)); 			break; | ||||
| 	    case coPoint3:          archive(*static_cast<const ConfigOptionPoint3*>(opt)); 			break; | ||||
| 	    case coBool:            archive(*static_cast<const ConfigOptionBool*>(opt)); 			break; | ||||
| 	    case coBools:           archive(*static_cast<const ConfigOptionBools*>(opt)); 			break; | ||||
| 	    case coEnum:            archive(*static_cast<const ConfigOptionEnumGeneric*>(opt)); 	break; | ||||
| 	    default:                throw std::runtime_error(std::string("ConfigOptionDef::save_option_to_archive(): Unknown option type for option ") + this->opt_key); | ||||
| 	    } | ||||
|     	if (this->nullable) { | ||||
| 		    switch (this->type) { | ||||
| 		    case coFloats:          archive(*static_cast<const ConfigOptionFloatsNullable*>(opt));  break; | ||||
| 		    case coInts:            archive(*static_cast<const ConfigOptionIntsNullable*>(opt));    break; | ||||
| 		    case coPercents:        archive(*static_cast<const ConfigOptionPercentsNullable*>(opt));break; | ||||
| 		    case coBools:           archive(*static_cast<const ConfigOptionBoolsNullable*>(opt)); 	break; | ||||
| 		    default:                throw std::runtime_error(std::string("ConfigOptionDef::save_option_to_archive(): Unknown nullable option type for option ") + this->opt_key); | ||||
| 		    } | ||||
| 		} else { | ||||
| 		    switch (this->type) { | ||||
| 		    case coFloat:           archive(*static_cast<const ConfigOptionFloat*>(opt));  			break; | ||||
| 		    case coFloats:          archive(*static_cast<const ConfigOptionFloats*>(opt)); 			break; | ||||
| 		    case coInt:             archive(*static_cast<const ConfigOptionInt*>(opt)); 	 		break; | ||||
| 		    case coInts:            archive(*static_cast<const ConfigOptionInts*>(opt)); 	 		break; | ||||
| 		    case coString:          archive(*static_cast<const ConfigOptionString*>(opt)); 			break; | ||||
| 		    case coStrings:         archive(*static_cast<const ConfigOptionStrings*>(opt)); 		break; | ||||
| 		    case coPercent:         archive(*static_cast<const ConfigOptionPercent*>(opt)); 		break; | ||||
| 		    case coPercents:        archive(*static_cast<const ConfigOptionPercents*>(opt)); 		break; | ||||
| 		    case coFloatOrPercent:  archive(*static_cast<const ConfigOptionFloatOrPercent*>(opt));	break; | ||||
| 		    case coPoint:           archive(*static_cast<const ConfigOptionPoint*>(opt)); 			break; | ||||
| 		    case coPoints:          archive(*static_cast<const ConfigOptionPoints*>(opt)); 			break; | ||||
| 		    case coPoint3:          archive(*static_cast<const ConfigOptionPoint3*>(opt)); 			break; | ||||
| 		    case coBool:            archive(*static_cast<const ConfigOptionBool*>(opt)); 			break; | ||||
| 		    case coBools:           archive(*static_cast<const ConfigOptionBools*>(opt)); 			break; | ||||
| 		    case coEnum:            archive(*static_cast<const ConfigOptionEnumGeneric*>(opt)); 	break; | ||||
| 		    default:                throw std::runtime_error(std::string("ConfigOptionDef::save_option_to_archive(): Unknown option type for option ") + this->opt_key); | ||||
| 		    } | ||||
| 		} | ||||
| 		// Make the compiler happy, shut up the warnings.
 | ||||
| 		return nullptr; | ||||
| 	} | ||||
|  | @ -1263,6 +1383,7 @@ 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); | ||||
| }; | ||||
| 
 | ||||
| // An abstract configuration store.
 | ||||
|  | @ -1347,6 +1468,9 @@ public: | |||
|     void load(const boost::property_tree::ptree &tree); | ||||
|     void save(const std::string &file) const; | ||||
| 
 | ||||
| 	// Set all the nullable values to nils.
 | ||||
|     void null_nullables(); | ||||
| 
 | ||||
| private: | ||||
|     // Set a configuration value from a string.
 | ||||
|     bool set_deserialize_raw(const t_config_option_key &opt_key_src, const std::string &str, bool append); | ||||
|  | @ -1444,6 +1568,9 @@ public: | |||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     // Remove options with all nil values, those are optional and it does not help to hold them.
 | ||||
|     size_t remove_nil_options(); | ||||
| 
 | ||||
|     // Allow DynamicConfig to be instantiated on ints own without a definition.
 | ||||
|     // If the definition is not defined, the method requiring the definition will throw NoDefinitionException.
 | ||||
|     const ConfigDef*        def() const override { return nullptr; }; | ||||
|  |  | |||
|  | @ -1783,47 +1783,7 @@ std::string Print::output_filename(const std::string &filename_base) const | |||
|     DynamicConfig config = this->finished() ? this->print_statistics().config() : this->print_statistics().placeholders(); | ||||
|     return this->PrintBase::output_filename(m_config.output_filename_format.value, ".gcode", filename_base, &config); | ||||
| } | ||||
| /*
 | ||||
| // Shorten the dhms time by removing the seconds, rounding the dhm to full minutes
 | ||||
| // and removing spaces.
 | ||||
| static std::string short_time(const std::string &time) | ||||
| { | ||||
|     // Parse the dhms time format.
 | ||||
|     int days    = 0; | ||||
|     int hours   = 0; | ||||
|     int minutes = 0; | ||||
|     int seconds = 0; | ||||
|     if (time.find('d') != std::string::npos) | ||||
|         ::sscanf(time.c_str(), "%dd %dh %dm %ds", &days, &hours, &minutes, &seconds); | ||||
|     else if (time.find('h') != std::string::npos) | ||||
|         ::sscanf(time.c_str(), "%dh %dm %ds", &hours, &minutes, &seconds); | ||||
|     else if (time.find('m') != std::string::npos) | ||||
|         ::sscanf(time.c_str(), "%dm %ds", &minutes, &seconds); | ||||
|     else if (time.find('s') != std::string::npos) | ||||
|         ::sscanf(time.c_str(), "%ds", &seconds); | ||||
|     // Round to full minutes.
 | ||||
|     if (days + hours + minutes > 0 && seconds >= 30) { | ||||
|         if (++ minutes == 60) { | ||||
|             minutes = 0; | ||||
|             if (++ hours == 24) { | ||||
|                 hours = 0; | ||||
|                 ++ days; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     // Format the dhm time.
 | ||||
|     char buffer[64]; | ||||
|     if (days > 0) | ||||
|         ::sprintf(buffer, "%dd%dh%dm", days, hours, minutes); | ||||
|     else if (hours > 0) | ||||
|         ::sprintf(buffer, "%dh%dm", hours, minutes); | ||||
|     else if (minutes > 0) | ||||
|         ::sprintf(buffer, "%dm", minutes); | ||||
|     else | ||||
|         ::sprintf(buffer, "%ds", seconds); | ||||
|     return buffer; | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| DynamicConfig PrintStatistics::config() const | ||||
| { | ||||
|     DynamicConfig config; | ||||
|  |  | |||
|  | @ -2228,6 +2228,30 @@ void PrintConfigDef::init_fff_params() | |||
|     def->sidetext = L("mm"); | ||||
|     def->mode = comAdvanced; | ||||
|     def->set_default_value(new ConfigOptionFloat(0)); | ||||
| 
 | ||||
|     // Declare retract values for filament profile, overriding the printer's extruder profile.
 | ||||
|     for (const char *opt_key : { | ||||
|     	// floats
 | ||||
| 		"retract_length", "retract_lift", "retract_lift_above", "retract_lift_below", "retract_speed", "deretract_speed", "retract_restart_extra", "retract_before_travel",  | ||||
| 		// bools
 | ||||
| 		"retract_layer_change", "wipe", | ||||
| 		// percents
 | ||||
| 		"retract_before_wipe"}) { | ||||
|     	auto it_opt = options.find(opt_key); | ||||
|     	assert(it_opt != options.end()); | ||||
|     	def = this->add_nullable(std::string("filament_") + opt_key, it_opt->second.type); | ||||
|     	def->label 		= it_opt->second.label; | ||||
|     	def->full_label = it_opt->second.full_label; | ||||
|     	def->tooltip 	= it_opt->second.tooltip; | ||||
|     	def->sidetext   = it_opt->second.sidetext; | ||||
|     	def->mode       = it_opt->second.mode; | ||||
|     	switch (def->type) { | ||||
|     	case coFloats   : def->set_default_value(new ConfigOptionFloatsNullable  (static_cast<const ConfigOptionFloats*  >(it_opt->second.default_value.get())->values)); break; | ||||
|     	case coPercents : def->set_default_value(new ConfigOptionPercentsNullable(static_cast<const ConfigOptionPercents*>(it_opt->second.default_value.get())->values)); break; | ||||
|     	case coBools    : def->set_default_value(new ConfigOptionBoolsNullable   (static_cast<const ConfigOptionBools*   >(it_opt->second.default_value.get())->values)); break; | ||||
|     	default: assert(false); | ||||
|     	} | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void PrintConfigDef::init_sla_params() | ||||
|  | @ -2987,7 +3011,7 @@ std::string FullPrintConfig::validate() | |||
|         } | ||||
|         case coFloats: | ||||
|         case coPercents: | ||||
|             for (double v : static_cast<const ConfigOptionFloats*>(opt)->values) | ||||
|             for (double v : static_cast<const ConfigOptionVector<double>*>(opt)->values) | ||||
|                 if (v < optdef->min || v > optdef->max) { | ||||
|                     out_of_range = true; | ||||
|                     break; | ||||
|  | @ -3000,7 +3024,7 @@ std::string FullPrintConfig::validate() | |||
|             break; | ||||
|         } | ||||
|         case coInts: | ||||
|             for (int v : static_cast<const ConfigOptionInts*>(opt)->values) | ||||
|             for (int v : static_cast<const ConfigOptionVector<int>*>(opt)->values) | ||||
|                 if (v < optdef->min || v > optdef->max) { | ||||
|                     out_of_range = true; | ||||
|                     break; | ||||
|  |  | |||
|  | @ -400,6 +400,10 @@ const std::vector<std::string>& Preset::filament_options() | |||
|         "temperature", "first_layer_temperature", "bed_temperature", "first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed", | ||||
|         "max_fan_speed", "bridge_fan_speed", "disable_fan_first_layers", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed", | ||||
|         "start_filament_gcode", "end_filament_gcode", | ||||
|         // Retract overrides
 | ||||
| 		"filament_retract_length", "filament_retract_lift", "filament_retract_lift_above", "filament_retract_lift_below", "filament_retract_speed", "filament_deretract_speed", "filament_retract_restart_extra", "filament_retract_before_travel",  | ||||
| 		"filament_retract_layer_change", "filament_wipe", "filament_retract_before_wipe", | ||||
| 		// Profile compatibility
 | ||||
|         "compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits" | ||||
|     }; | ||||
|     return s_opts; | ||||
|  |  | |||
|  | @ -72,6 +72,8 @@ PresetBundle::PresetBundle() : | |||
|     this->filaments.default_preset().config.option<ConfigOptionStrings>("filament_settings_id", true)->values = { "" }; | ||||
|     this->filaments.default_preset().compatible_printers_condition(); | ||||
|     this->filaments.default_preset().inherits(); | ||||
| 	// Set all the nullable values to nils.
 | ||||
| 	this->filaments.default_preset().config.null_nullables(); | ||||
| 
 | ||||
|     this->sla_materials.default_preset().config.optptr("sla_material_settings_id", true); | ||||
|     this->sla_materials.default_preset().compatible_printers_condition(); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv