diff options
Diffstat (limited to 'xs/src/libslic3r/Config.hpp')
-rw-r--r-- | xs/src/libslic3r/Config.hpp | 521 |
1 files changed, 521 insertions, 0 deletions
diff --git a/xs/src/libslic3r/Config.hpp b/xs/src/libslic3r/Config.hpp new file mode 100644 index 000000000..42d19c830 --- /dev/null +++ b/xs/src/libslic3r/Config.hpp @@ -0,0 +1,521 @@ +#ifndef slic3r_Config_hpp_ +#define slic3r_Config_hpp_ + +#include <map> +#include <climits> +#include <cstdio> +#include <cstdlib> +#include <iostream> +#include <stdexcept> +#include <string> +#include <vector> +#include <myinit.h> +#include "Point.hpp" + +namespace Slic3r { + +typedef std::string t_config_option_key; +typedef std::vector<std::string> t_config_option_keys; + +class ConfigOption { + public: + virtual ~ConfigOption() {}; + virtual std::string serialize() const = 0; + virtual bool deserialize(std::string str) = 0; + virtual int getInt() const { return 0; }; + virtual void setInt(int val) {}; +}; + +template <class T> +class ConfigOptionVector +{ + public: + virtual ~ConfigOptionVector() {}; + std::vector<T> values; + + T get_at(size_t i) const { + try { + return this->values.at(i); + } catch (const std::out_of_range& oor) { + return this->values.front(); + } + }; +}; + +class ConfigOptionFloat : public ConfigOption +{ + public: + double value; // use double instead of float for preserving compatibility with values coming from Perl + ConfigOptionFloat() : value(0) {}; + + operator double() const { return this->value; }; + + std::string serialize() const { + std::ostringstream ss; + ss << this->value; + return ss.str(); + }; + + bool deserialize(std::string str) { + this->value = ::atof(str.c_str()); + return true; + }; +}; + +class ConfigOptionFloats : public ConfigOption, public ConfigOptionVector<double> +{ + public: + + std::string serialize() const { + 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; + } + return ss.str(); + }; + + bool deserialize(std::string str) { + this->values.clear(); + std::istringstream is(str); + std::string item_str; + while (std::getline(is, item_str, ',')) { + this->values.push_back(::atof(item_str.c_str())); + } + return true; + }; +}; + +class ConfigOptionInt : public ConfigOption +{ + public: + int value; + ConfigOptionInt() : value(0) {}; + + operator int() const { return this->value; }; + int getInt() const { return this->value; }; + void setInt(int val) { this->value = val; }; + + std::string serialize() const { + std::ostringstream ss; + ss << this->value; + return ss.str(); + }; + + bool deserialize(std::string str) { + this->value = ::atoi(str.c_str()); + return true; + }; +}; + +class ConfigOptionInts : public ConfigOption, public ConfigOptionVector<int> +{ + public: + + std::string serialize() const { + 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; + } + return ss.str(); + }; + + bool deserialize(std::string str) { + this->values.clear(); + std::istringstream is(str); + std::string item_str; + while (std::getline(is, item_str, ',')) { + this->values.push_back(::atoi(item_str.c_str())); + } + return true; + }; +}; + +class ConfigOptionString : public ConfigOption +{ + public: + std::string value; + ConfigOptionString() : value("") {}; + + operator std::string() const { return this->value; }; + + std::string serialize() const { + std::string str = this->value; + + // s/\R/\\n/g + size_t pos = 0; + while ((pos = str.find("\n", pos)) != std::string::npos || (pos = str.find("\r", pos)) != std::string::npos) { + str.replace(pos, 1, "\\n"); + pos += 2; // length of "\\n" + } + + return str; + }; + + bool deserialize(std::string str) { + // s/\\n/\n/g + size_t pos = 0; + while ((pos = str.find("\\n", pos)) != std::string::npos) { + str.replace(pos, 2, "\n"); + pos += 1; // length of "\n" + } + + this->value = str; + return true; + }; +}; + +// semicolon-separated strings +class ConfigOptionStrings : public ConfigOption, public ConfigOptionVector<std::string> +{ + public: + + std::string serialize() const { + std::ostringstream ss; + for (std::vector<std::string>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) { + if (it - this->values.begin() != 0) ss << ";"; + ss << *it; + } + return ss.str(); + }; + + bool deserialize(std::string str) { + this->values.clear(); + std::istringstream is(str); + std::string item_str; + while (std::getline(is, item_str, ';')) { + this->values.push_back(item_str); + } + return true; + }; +}; + +class ConfigOptionPercent : public ConfigOption +{ + public: + double value; + ConfigOptionPercent() : value(0) {}; + + double get_abs_value(double ratio_over) const { + return ratio_over * this->value / 100; + }; + + std::string serialize() const { + std::ostringstream ss; + ss << this->value; + std::string s(ss.str()); + s += "%"; + return s; + }; + + bool deserialize(std::string str) { + // don't try to parse the trailing % since it's optional + int res = sscanf(str.c_str(), "%lf", &this->value); + return res == 1; + }; +}; + +class ConfigOptionFloatOrPercent : public ConfigOption +{ + public: + double value; + bool percent; + ConfigOptionFloatOrPercent() : value(0), percent(false) {}; + + double get_abs_value(double ratio_over) const { + if (this->percent) { + return ratio_over * this->value / 100; + } else { + return this->value; + } + }; + + std::string serialize() const { + std::ostringstream ss; + ss << this->value; + std::string s(ss.str()); + if (this->percent) s += "%"; + return s; + }; + + bool deserialize(std::string str) { + if (str.find_first_of("%") != std::string::npos) { + int res = sscanf(str.c_str(), "%lf%%", &this->value); + if (res == 0) return false; + this->percent = true; + } else { + this->value = ::atof(str.c_str()); + this->percent = false; + } + return true; + }; +}; + +class ConfigOptionPoint : public ConfigOption +{ + public: + Pointf point; + ConfigOptionPoint() : point(Pointf(0,0)) {}; + + operator Pointf() const { return this->point; }; + + std::string serialize() const { + std::ostringstream ss; + ss << this->point.x; + ss << ","; + ss << this->point.y; + return ss.str(); + }; + + bool deserialize(std::string str) { + if (strncmp(str.c_str(), "0x", 2) == 0) { + this->point.x = 0; + int res = sscanf(str.c_str()+2, "%lf", &this->point.y); + return res == 1; + } else { + int res = sscanf(str.c_str(), "%lf%*1[,x]%lf", &this->point.x, &this->point.y); + return res == 2; + } + }; +}; + +class ConfigOptionPoints : public ConfigOption, public ConfigOptionVector<Pointf> +{ + public: + + std::string serialize() const { + std::ostringstream ss; + for (Pointfs::const_iterator it = this->values.begin(); it != this->values.end(); ++it) { + if (it - this->values.begin() != 0) ss << ","; + ss << it->x; + ss << "x"; + ss << it->y; + } + return ss.str(); + }; + + bool deserialize(std::string str) { + std::vector<Pointf> values; + std::istringstream is(str); + std::string point_str; + while (std::getline(is, point_str, ',')) { + Pointf point; + if (strncmp(point_str.c_str(), "0x", 2) == 0) { + // if string starts with "0x", only apply sscanf() to the second coordinate + // otherwise it would parse the string as a hex number + point.x = 0; + int res = sscanf(point_str.c_str()+2, "%lf", &point.y); + if (res != 1) return false; + } else { + int res = sscanf(point_str.c_str(), "%lfx%lf", &point.x, &point.y); + if (res != 2) return false; + } + values.push_back(point); + } + this->values = values; + return true; + }; +}; + +class ConfigOptionBool : public ConfigOption +{ + public: + bool value; + ConfigOptionBool() : value(false) {}; + + operator bool() const { return this->value; }; + + std::string serialize() const { + return std::string(this->value ? "1" : "0"); + }; + + bool deserialize(std::string str) { + this->value = (str.compare("1") == 0); + return true; + }; +}; + +class ConfigOptionBools : public ConfigOption, public ConfigOptionVector<bool> +{ + public: + + std::string serialize() const { + std::ostringstream ss; + for (std::vector<bool>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) { + if (it - this->values.begin() != 0) ss << ","; + ss << (*it ? "1" : "0"); + } + return ss.str(); + }; + + bool deserialize(std::string str) { + this->values.clear(); + std::istringstream is(str); + std::string item_str; + while (std::getline(is, item_str, ',')) { + this->values.push_back(item_str.compare("1") == 0); + } + return true; + }; +}; + +typedef std::map<std::string,int> t_config_enum_values; + +template <class T> +class ConfigOptionEnum : public ConfigOption +{ + public: + T value; + + operator T() const { return this->value; }; + + std::string serialize() const { + t_config_enum_values enum_keys_map = ConfigOptionEnum<T>::get_enum_values(); + for (t_config_enum_values::iterator it = enum_keys_map.begin(); it != enum_keys_map.end(); ++it) { + if (it->second == static_cast<int>(this->value)) return it->first; + } + return ""; + }; + + bool deserialize(std::string str) { + t_config_enum_values enum_keys_map = ConfigOptionEnum<T>::get_enum_values(); + if (enum_keys_map.count(str) == 0) return false; + this->value = static_cast<T>(enum_keys_map[str]); + return true; + }; + + static t_config_enum_values get_enum_values(); +}; + +/* We use this one in DynamicConfig objects, otherwise it's better to use + the specialized ConfigOptionEnum<T> containers. */ +class ConfigOptionEnumGeneric : public ConfigOption +{ + public: + int value; + t_config_enum_values* keys_map; + + operator int() const { return this->value; }; + + std::string serialize() const { + for (t_config_enum_values::iterator it = this->keys_map->begin(); it != this->keys_map->end(); ++it) { + if (it->second == this->value) return it->first; + } + return ""; + }; + + bool deserialize(std::string str) { + if (this->keys_map->count(str) == 0) return false; + this->value = (*this->keys_map)[str]; + return true; + }; +}; + +enum ConfigOptionType { + coFloat, + coFloats, + coInt, + coInts, + coString, + coStrings, + coPercent, + coFloatOrPercent, + coPoint, + coPoints, + coBool, + coBools, + coEnum, +}; + +class ConfigOptionDef +{ + public: + ConfigOptionType type; + std::string gui_type; + std::string gui_flags; + std::string label; + std::string full_label; + std::string category; + std::string tooltip; + std::string sidetext; + std::string cli; + t_config_option_key ratio_over; + bool multiline; + bool full_width; + bool readonly; + int height; + int width; + int min; + int max; + std::vector<t_config_option_key> aliases; + std::vector<t_config_option_key> shortcut; + std::vector<std::string> enum_values; + std::vector<std::string> enum_labels; + t_config_enum_values enum_keys_map; + + ConfigOptionDef() : multiline(false), full_width(false), readonly(false), + height(-1), width(-1), min(INT_MIN), max(INT_MAX) {}; +}; + +typedef std::map<t_config_option_key,ConfigOptionDef> t_optiondef_map; + +class ConfigBase +{ + public: + t_optiondef_map* def; + + ConfigBase() : def(NULL) {}; + bool has(const t_config_option_key opt_key); + virtual ConfigOption* option(const t_config_option_key opt_key, bool create = false) = 0; + virtual const ConfigOption* option(const t_config_option_key opt_key) const = 0; + virtual void keys(t_config_option_keys *keys) const = 0; + void apply(const ConfigBase &other, bool ignore_nonexistent = false); + std::string serialize(const t_config_option_key opt_key); + bool set_deserialize(const t_config_option_key opt_key, std::string str); + double get_abs_value(const t_config_option_key opt_key); + double get_abs_value(const t_config_option_key opt_key, double ratio_over); + + #ifdef SLIC3RXS + SV* as_hash(); + SV* get(t_config_option_key opt_key); + SV* get_at(t_config_option_key opt_key, size_t i); + bool set(t_config_option_key opt_key, SV* value); + bool set_deserialize(const t_config_option_key opt_key, SV* str); + #endif +}; + +class DynamicConfig : public ConfigBase +{ + public: + DynamicConfig() {}; + DynamicConfig(const DynamicConfig& other); + DynamicConfig& operator= (DynamicConfig other); + void swap(DynamicConfig &other); + ~DynamicConfig(); + template<class T> T* opt(const t_config_option_key opt_key, bool create = false); + ConfigOption* option(const t_config_option_key opt_key, bool create = false); + const ConfigOption* option(const t_config_option_key opt_key) const; + void keys(t_config_option_keys *keys) const; + void erase(const t_config_option_key opt_key); + + private: + typedef std::map<t_config_option_key,ConfigOption*> t_options_map; + t_options_map options; +}; + +class StaticConfig : public ConfigBase +{ + public: + void keys(t_config_option_keys *keys) const; + virtual ConfigOption* option(const t_config_option_key opt_key, bool create = false) = 0; + const ConfigOption* option(const t_config_option_key opt_key) const; + + #ifdef SLIC3RXS + bool set(t_config_option_key opt_key, SV* value); + #endif +}; + +} + +#endif |