Config.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. #ifndef slic3r_Config_hpp_
  2. #define slic3r_Config_hpp_
  3. #include <map>
  4. #include <climits>
  5. #include <cstdio>
  6. #include <cstdlib>
  7. #include <iostream>
  8. #include <stdexcept>
  9. #include <string>
  10. #include <vector>
  11. #include <myinit.h>
  12. #include "Point.hpp"
  13. namespace Slic3r {
  14. typedef std::string t_config_option_key;
  15. typedef std::vector<std::string> t_config_option_keys;
  16. class ConfigOption {
  17. public:
  18. virtual ~ConfigOption() {};
  19. virtual std::string serialize() const = 0;
  20. virtual bool deserialize(std::string str) = 0;
  21. virtual int getInt() const { return 0; };
  22. virtual void setInt(int val) {};
  23. };
  24. template <class T>
  25. class ConfigOptionVector
  26. {
  27. public:
  28. virtual ~ConfigOptionVector() {};
  29. std::vector<T> values;
  30. T get_at(size_t i) const {
  31. try {
  32. return this->values.at(i);
  33. } catch (const std::out_of_range& oor) {
  34. return this->values.front();
  35. }
  36. };
  37. };
  38. class ConfigOptionFloat : public ConfigOption
  39. {
  40. public:
  41. double value; // use double instead of float for preserving compatibility with values coming from Perl
  42. ConfigOptionFloat() : value(0) {};
  43. operator double() const { return this->value; };
  44. std::string serialize() const {
  45. std::ostringstream ss;
  46. ss << this->value;
  47. return ss.str();
  48. };
  49. bool deserialize(std::string str) {
  50. this->value = ::atof(str.c_str());
  51. return true;
  52. };
  53. };
  54. class ConfigOptionFloats : public ConfigOption, public ConfigOptionVector<double>
  55. {
  56. public:
  57. std::string serialize() const {
  58. std::ostringstream ss;
  59. for (std::vector<double>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
  60. if (it - this->values.begin() != 0) ss << ",";
  61. ss << *it;
  62. }
  63. return ss.str();
  64. };
  65. bool deserialize(std::string str) {
  66. this->values.clear();
  67. std::istringstream is(str);
  68. std::string item_str;
  69. while (std::getline(is, item_str, ',')) {
  70. this->values.push_back(::atof(item_str.c_str()));
  71. }
  72. return true;
  73. };
  74. };
  75. class ConfigOptionInt : public ConfigOption
  76. {
  77. public:
  78. int value;
  79. ConfigOptionInt() : value(0) {};
  80. operator int() const { return this->value; };
  81. int getInt() const { return this->value; };
  82. void setInt(int val) { this->value = val; };
  83. std::string serialize() const {
  84. std::ostringstream ss;
  85. ss << this->value;
  86. return ss.str();
  87. };
  88. bool deserialize(std::string str) {
  89. this->value = ::atoi(str.c_str());
  90. return true;
  91. };
  92. };
  93. class ConfigOptionInts : public ConfigOption, public ConfigOptionVector<int>
  94. {
  95. public:
  96. std::string serialize() const {
  97. std::ostringstream ss;
  98. for (std::vector<int>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
  99. if (it - this->values.begin() != 0) ss << ",";
  100. ss << *it;
  101. }
  102. return ss.str();
  103. };
  104. bool deserialize(std::string str) {
  105. this->values.clear();
  106. std::istringstream is(str);
  107. std::string item_str;
  108. while (std::getline(is, item_str, ',')) {
  109. this->values.push_back(::atoi(item_str.c_str()));
  110. }
  111. return true;
  112. };
  113. };
  114. class ConfigOptionString : public ConfigOption
  115. {
  116. public:
  117. std::string value;
  118. ConfigOptionString() : value("") {};
  119. operator std::string() const { return this->value; };
  120. std::string serialize() const {
  121. std::string str = this->value;
  122. // s/\R/\\n/g
  123. size_t pos = 0;
  124. while ((pos = str.find("\n", pos)) != std::string::npos || (pos = str.find("\r", pos)) != std::string::npos) {
  125. str.replace(pos, 1, "\\n");
  126. pos += 2; // length of "\\n"
  127. }
  128. return str;
  129. };
  130. bool deserialize(std::string str) {
  131. // s/\\n/\n/g
  132. size_t pos = 0;
  133. while ((pos = str.find("\\n", pos)) != std::string::npos) {
  134. str.replace(pos, 2, "\n");
  135. pos += 1; // length of "\n"
  136. }
  137. this->value = str;
  138. return true;
  139. };
  140. };
  141. // semicolon-separated strings
  142. class ConfigOptionStrings : public ConfigOption, public ConfigOptionVector<std::string>
  143. {
  144. public:
  145. std::string serialize() const {
  146. std::ostringstream ss;
  147. for (std::vector<std::string>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
  148. if (it - this->values.begin() != 0) ss << ";";
  149. ss << *it;
  150. }
  151. return ss.str();
  152. };
  153. bool deserialize(std::string str) {
  154. this->values.clear();
  155. std::istringstream is(str);
  156. std::string item_str;
  157. while (std::getline(is, item_str, ';')) {
  158. this->values.push_back(item_str);
  159. }
  160. return true;
  161. };
  162. };
  163. class ConfigOptionPercent : public ConfigOption
  164. {
  165. public:
  166. double value;
  167. ConfigOptionPercent() : value(0) {};
  168. double get_abs_value(double ratio_over) const {
  169. return ratio_over * this->value / 100;
  170. };
  171. std::string serialize() const {
  172. std::ostringstream ss;
  173. ss << this->value;
  174. std::string s(ss.str());
  175. s += "%";
  176. return s;
  177. };
  178. bool deserialize(std::string str) {
  179. // don't try to parse the trailing % since it's optional
  180. int res = sscanf(str.c_str(), "%lf", &this->value);
  181. return res == 1;
  182. };
  183. };
  184. class ConfigOptionFloatOrPercent : public ConfigOption
  185. {
  186. public:
  187. double value;
  188. bool percent;
  189. ConfigOptionFloatOrPercent() : value(0), percent(false) {};
  190. double get_abs_value(double ratio_over) const {
  191. if (this->percent) {
  192. return ratio_over * this->value / 100;
  193. } else {
  194. return this->value;
  195. }
  196. };
  197. std::string serialize() const {
  198. std::ostringstream ss;
  199. ss << this->value;
  200. std::string s(ss.str());
  201. if (this->percent) s += "%";
  202. return s;
  203. };
  204. bool deserialize(std::string str) {
  205. if (str.find_first_of("%") != std::string::npos) {
  206. int res = sscanf(str.c_str(), "%lf%%", &this->value);
  207. if (res == 0) return false;
  208. this->percent = true;
  209. } else {
  210. this->value = ::atof(str.c_str());
  211. this->percent = false;
  212. }
  213. return true;
  214. };
  215. };
  216. class ConfigOptionPoint : public ConfigOption
  217. {
  218. public:
  219. Pointf point;
  220. ConfigOptionPoint() : point(Pointf(0,0)) {};
  221. operator Pointf() const { return this->point; };
  222. std::string serialize() const {
  223. std::ostringstream ss;
  224. ss << this->point.x;
  225. ss << ",";
  226. ss << this->point.y;
  227. return ss.str();
  228. };
  229. bool deserialize(std::string str) {
  230. if (strncmp(str.c_str(), "0x", 2) == 0) {
  231. this->point.x = 0;
  232. int res = sscanf(str.c_str()+2, "%lf", &this->point.y);
  233. return res == 1;
  234. } else {
  235. int res = sscanf(str.c_str(), "%lf%*1[,x]%lf", &this->point.x, &this->point.y);
  236. return res == 2;
  237. }
  238. };
  239. };
  240. class ConfigOptionPoints : public ConfigOption, public ConfigOptionVector<Pointf>
  241. {
  242. public:
  243. std::string serialize() const {
  244. std::ostringstream ss;
  245. for (Pointfs::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
  246. if (it - this->values.begin() != 0) ss << ",";
  247. ss << it->x;
  248. ss << "x";
  249. ss << it->y;
  250. }
  251. return ss.str();
  252. };
  253. bool deserialize(std::string str) {
  254. std::vector<Pointf> values;
  255. std::istringstream is(str);
  256. std::string point_str;
  257. while (std::getline(is, point_str, ',')) {
  258. Pointf point;
  259. if (strncmp(point_str.c_str(), "0x", 2) == 0) {
  260. // if string starts with "0x", only apply sscanf() to the second coordinate
  261. // otherwise it would parse the string as a hex number
  262. point.x = 0;
  263. int res = sscanf(point_str.c_str()+2, "%lf", &point.y);
  264. if (res != 1) return false;
  265. } else {
  266. int res = sscanf(point_str.c_str(), "%lfx%lf", &point.x, &point.y);
  267. if (res != 2) return false;
  268. }
  269. values.push_back(point);
  270. }
  271. this->values = values;
  272. return true;
  273. };
  274. };
  275. class ConfigOptionBool : public ConfigOption
  276. {
  277. public:
  278. bool value;
  279. ConfigOptionBool() : value(false) {};
  280. operator bool() const { return this->value; };
  281. std::string serialize() const {
  282. return std::string(this->value ? "1" : "0");
  283. };
  284. bool deserialize(std::string str) {
  285. this->value = (str.compare("1") == 0);
  286. return true;
  287. };
  288. };
  289. class ConfigOptionBools : public ConfigOption, public ConfigOptionVector<bool>
  290. {
  291. public:
  292. std::string serialize() const {
  293. std::ostringstream ss;
  294. for (std::vector<bool>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
  295. if (it - this->values.begin() != 0) ss << ",";
  296. ss << (*it ? "1" : "0");
  297. }
  298. return ss.str();
  299. };
  300. bool deserialize(std::string str) {
  301. this->values.clear();
  302. std::istringstream is(str);
  303. std::string item_str;
  304. while (std::getline(is, item_str, ',')) {
  305. this->values.push_back(item_str.compare("1") == 0);
  306. }
  307. return true;
  308. };
  309. };
  310. typedef std::map<std::string,int> t_config_enum_values;
  311. template <class T>
  312. class ConfigOptionEnum : public ConfigOption
  313. {
  314. public:
  315. T value;
  316. operator T() const { return this->value; };
  317. std::string serialize() const {
  318. t_config_enum_values enum_keys_map = ConfigOptionEnum<T>::get_enum_values();
  319. for (t_config_enum_values::iterator it = enum_keys_map.begin(); it != enum_keys_map.end(); ++it) {
  320. if (it->second == static_cast<int>(this->value)) return it->first;
  321. }
  322. return "";
  323. };
  324. bool deserialize(std::string str) {
  325. t_config_enum_values enum_keys_map = ConfigOptionEnum<T>::get_enum_values();
  326. if (enum_keys_map.count(str) == 0) return false;
  327. this->value = static_cast<T>(enum_keys_map[str]);
  328. return true;
  329. };
  330. static t_config_enum_values get_enum_values();
  331. };
  332. /* We use this one in DynamicConfig objects, otherwise it's better to use
  333. the specialized ConfigOptionEnum<T> containers. */
  334. class ConfigOptionEnumGeneric : public ConfigOption
  335. {
  336. public:
  337. int value;
  338. t_config_enum_values* keys_map;
  339. operator int() const { return this->value; };
  340. std::string serialize() const {
  341. for (t_config_enum_values::iterator it = this->keys_map->begin(); it != this->keys_map->end(); ++it) {
  342. if (it->second == this->value) return it->first;
  343. }
  344. return "";
  345. };
  346. bool deserialize(std::string str) {
  347. if (this->keys_map->count(str) == 0) return false;
  348. this->value = (*this->keys_map)[str];
  349. return true;
  350. };
  351. };
  352. enum ConfigOptionType {
  353. coFloat,
  354. coFloats,
  355. coInt,
  356. coInts,
  357. coString,
  358. coStrings,
  359. coPercent,
  360. coFloatOrPercent,
  361. coPoint,
  362. coPoints,
  363. coBool,
  364. coBools,
  365. coEnum,
  366. };
  367. class ConfigOptionDef
  368. {
  369. public:
  370. ConfigOptionType type;
  371. std::string label;
  372. std::string full_label;
  373. std::string category;
  374. std::string tooltip;
  375. std::string sidetext;
  376. std::string cli;
  377. t_config_option_key ratio_over;
  378. bool multiline;
  379. bool full_width;
  380. bool readonly;
  381. int height;
  382. int width;
  383. int min;
  384. int max;
  385. std::vector<t_config_option_key> aliases;
  386. std::vector<t_config_option_key> shortcut;
  387. std::vector<std::string> enum_values;
  388. std::vector<std::string> enum_labels;
  389. t_config_enum_values enum_keys_map;
  390. ConfigOptionDef() : multiline(false), full_width(false), readonly(false),
  391. height(-1), width(-1), min(INT_MIN), max(INT_MAX) {};
  392. };
  393. typedef std::map<t_config_option_key,ConfigOptionDef> t_optiondef_map;
  394. class ConfigBase
  395. {
  396. public:
  397. t_optiondef_map* def;
  398. ConfigBase() : def(NULL) {};
  399. bool has(const t_config_option_key opt_key);
  400. virtual ConfigOption* option(const t_config_option_key opt_key, bool create = false) = 0;
  401. virtual const ConfigOption* option(const t_config_option_key opt_key) const = 0;
  402. virtual void keys(t_config_option_keys *keys) const = 0;
  403. void apply(const ConfigBase &other, bool ignore_nonexistent = false);
  404. std::string serialize(const t_config_option_key opt_key);
  405. bool set_deserialize(const t_config_option_key opt_key, std::string str);
  406. double get_abs_value(const t_config_option_key opt_key);
  407. double get_abs_value(const t_config_option_key opt_key, double ratio_over);
  408. #ifdef SLIC3RXS
  409. SV* as_hash();
  410. SV* get(t_config_option_key opt_key);
  411. SV* get_at(t_config_option_key opt_key, size_t i);
  412. bool set(t_config_option_key opt_key, SV* value);
  413. bool set_deserialize(const t_config_option_key opt_key, SV* str);
  414. #endif
  415. };
  416. class DynamicConfig : public ConfigBase
  417. {
  418. public:
  419. DynamicConfig() {};
  420. DynamicConfig(const DynamicConfig& other);
  421. DynamicConfig& operator= (DynamicConfig other);
  422. void swap(DynamicConfig &other);
  423. ~DynamicConfig();
  424. template<class T> T* opt(const t_config_option_key opt_key, bool create = false);
  425. ConfigOption* option(const t_config_option_key opt_key, bool create = false);
  426. const ConfigOption* option(const t_config_option_key opt_key) const;
  427. void keys(t_config_option_keys *keys) const;
  428. void erase(const t_config_option_key opt_key);
  429. private:
  430. typedef std::map<t_config_option_key,ConfigOption*> t_options_map;
  431. t_options_map options;
  432. };
  433. class StaticConfig : public ConfigBase
  434. {
  435. public:
  436. void keys(t_config_option_keys *keys) const;
  437. virtual ConfigOption* option(const t_config_option_key opt_key, bool create = false) = 0;
  438. const ConfigOption* option(const t_config_option_key opt_key) const;
  439. #ifdef SLIC3RXS
  440. bool set(t_config_option_key opt_key, SV* value);
  441. #endif
  442. };
  443. }
  444. #endif