1 /*
2 This file is a part of the RepSnapper project.
3 Copyright (C) 2010 Michael Meeks
4 Copyright (C) 2013 martin.dieringer@gmx.de
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include <cstdlib>
22 #include <gtkmm.h>
23 #include "settings.h"
24
25 #include <stdafx.h>
26
27 #include "infill.h"
28 /*
29 * How settings are intended to work:
30 *
31 * Settings is a subclass of Glib::KeyFile.
32 *
33 * Glade Builder Widgets are named as <Group>.<Key>, so automatically
34 * converted to KeyFile settings. This works for most settings, but
35 * there are exceptions...
36 *
37 * All default setting values have to be at least in the default .conf file
38 *
39 * A redraw is done on every change made by the GUI.
40 */
41
42 #ifdef WIN32
43 # define DEFAULT_COM_PORT "COM0"
44 #else
45 # define DEFAULT_COM_PORT "/dev/ttyUSB0"
46 #endif
47
48 const string serialspeeds[] = { "9600", "19200", "38400", "57600", "115200", "230400", "250000" };
49
50
51 // convert GUI name to group/key
splitpoint(const string & glade_name,string & group,string & key)52 bool splitpoint(const string &glade_name, string &group, string &key) {
53 int pos = glade_name.find(".");
54 if (pos==(int)std::string::npos) return false;
55 group = glade_name.substr(0,pos);
56 key = glade_name.substr(pos+1);
57 return true;
58 }
59
60
set_up_combobox(Gtk::ComboBox * combo,vector<string> values)61 void set_up_combobox(Gtk::ComboBox *combo, vector<string> values)
62 {
63 if (combo->get_model())
64 return;
65 Gtk::TreeModelColumn<Glib::ustring> column;
66 Gtk::TreeModelColumnRecord record;
67 record.add(column);
68 Glib::RefPtr<Gtk::ListStore> store = Gtk::ListStore::create(record);
69 combo->pack_start (column);
70 combo->set_model(store);
71 for (uint i=0; i<values.size(); i++) {
72 //cerr << " adding " << values[i] << endl;
73 store->append()->set_value(0, Glib::ustring(values[i].c_str()));
74 }
75 #if GTK_VERSION_GE(2, 24)
76 if (!combo->get_has_entry())
77 #endif
78 combo->set_active(0);
79 //cerr << "ok" << endl;
80 }
81
combobox_get_active_value(Gtk::ComboBox * combo)82 string combobox_get_active_value(Gtk::ComboBox *combo){
83 #if GTK_VERSION_GE(2, 24)
84 if (combo->get_has_entry())
85 {
86 Gtk::Entry *entry = combo->get_entry();
87 if (entry)
88 return string(entry->get_text());
89 } else
90 #endif
91 {
92 uint c = combo->get_active_row_number();
93 Glib::ustring rval;
94 combo->get_model()->children()[c].get_value(0,rval);
95 return string(rval);
96 }
97 cerr << "could not get combobox active value" << endl;
98 return "";
99 }
100
combobox_set_to(Gtk::ComboBox * combo,string value)101 bool combobox_set_to(Gtk::ComboBox *combo, string value)
102 {
103 Glib::ustring val(value);
104 Glib::RefPtr<Gtk::TreeModel> model = combo->get_model();
105 uint nch = model->children().size();
106 Glib::ustring rval;
107 Glib::ustring gvalue(value.c_str());
108 #if GTK_VERSION_GE(2, 24)
109 if (combo->get_has_entry())
110 {
111 Gtk::Entry *entry = combo->get_entry();
112 if (entry) {
113 entry->set_text(value);
114 return true;
115 }
116 }
117 else
118 #endif
119 {
120 for (uint c=0; c < nch; c++) {
121 Gtk::TreeRow row = model->children()[c];
122 row.get_value(0,rval);
123 if (rval== gvalue) {
124 combo->set_active(c);
125 return true;
126 }
127 }
128 }
129 cerr << "value " << value << " not found in combobox" << endl;
130 return false;
131 }
132
133
134
135 /////////////////////////////////////////////////////////////////
136
137
138
Settings()139 Settings::Settings ()
140 {
141 set_defaults();
142 m_user_changed = false;
143 inhibit_callback = false;
144 }
145
~Settings()146 Settings::~Settings()
147 {
148 }
149
150 // merge into current settings
merge(const Glib::KeyFile & keyfile)151 void Settings::merge (const Glib::KeyFile &keyfile)
152 {
153 vector< Glib::ustring > groups = keyfile.get_groups();
154 for (uint g = 0; g < groups.size(); g++) {
155 vector< Glib::ustring > keys = keyfile.get_keys(groups[g]);
156 for (uint k = 0; k < keys.size(); k++) {
157 set_value(groups[g], keys[k], keyfile.get_value(groups[g], keys[k]));
158 }
159 }
160 }
161 // always merge when loading settings
load_from_file(string file)162 bool Settings::load_from_file (string file) {
163 Glib::KeyFile k;
164 if (!k.load_from_file(file)) return false;
165 merge(k);
166 return true;
167 }
load_from_data(string data)168 bool Settings::load_from_data (string data) {
169 Glib::KeyFile k;
170 if (!k.load_from_file(data)) return false;
171 merge(k);
172 return true;
173 }
174
175
176
177 // make "ExtruderN" group, if i<0 (not given), use current selected Extruder number
numberedExtruder(const string & group,int num) const178 string Settings::numberedExtruder(const string &group, int num) const {
179 if (group == "Extruder") {
180 ostringstream oss; oss << "Extruder" << num;
181 //cerr << "call for " << oss.str() << endl;
182 return oss.str();
183 }
184 return group;
185 }
186
get_colour(const string & group,const string & name) const187 Vector4f Settings::get_colour(const string &group, const string &name) const {
188 vector<double> s = get_double_list(group, name);
189 return Vector4f(s[0],s[1],s[2],s[3]);
190 }
191
set_colour(const string & group,const string & name,const Vector4f & value)192 void Settings::set_colour (const string &group, const string &name,
193 const Vector4f &value) {
194 Glib::KeyFile::set_double_list(group, name, value);
195 }
196
197
198 void
assign_from(Settings * pSettings)199 Settings::assign_from(Settings *pSettings)
200 {
201 this->load_from_data(pSettings->to_data());
202 m_user_changed = false;
203 m_signal_visual_settings_changed.emit();
204 m_signal_update_settings_gui.emit();
205 }
206
set_defaults()207 void Settings::set_defaults ()
208 {
209
210 filename = "";
211
212 set_string("Global","SettingsName","Default Settings");
213 set_string("Global","SettingsImage","");
214
215 set_string("Global","Version",VERSION);
216
217 set_string("GCode","Start",
218 "; This code is sent to the printer at the beginning.\n"
219 "; Adjust it to your needs.\n"
220 "; \n"
221 "; GCode generated by RepSnapper:\n"
222 "; http://reprap.org/wiki/RepSnapper_Manual:Introduction\n"
223 "G21 ; metric coordinates\n"
224 "G90 ; absolute positioning\n"
225 "T0 ; select new extruder\n"
226 "G28 ; go home\n"
227 "G92 E0 ; set extruder home\n"
228 "G1 X5 Y5 F500 ; move away 5 mm from 0.0, to use the same reset for each layer\n\n");
229 set_string("GCode","Layer","");
230 set_string("GCode","End",
231 "; This code is sent to the printer after the print.\n"
232 "; Adjust it to your needs.\n"
233 "G1 X0 Y0 F2000.0 ; feed for start of next move\n"
234 "M104 S0.0 ; heater off\n");
235
236
237
238 // Extruders.clear();
239 // Extruders.push_back(Extruder);
240
241 // The vectors map each to 3 spin boxes, one per dimension
242 set_double("Hardware","Volume.X", 200);
243 set_double("Hardware","Volume.Y", 200);
244 set_double("Hardware","Volume.Z", 140);
245 set_double("Hardware","PrintMargin.X", 10);
246 set_double("Hardware","PrintMargin.Y", 10);
247 set_double("Hardware","PrintMargin.Z", 0);
248
249 set_boolean("Misc","SpeedsAreMMperSec",true);
250 }
251
252
253 // make old single coordinate colours to lists
convert_old_colour(const string & group,const string & key)254 void Settings::convert_old_colour (const string &group, const string &key) {
255 try {
256 cerr << "converting "<< group << "." <<key <<endl;
257 const double c[5] = { get_double(group, key+"R"),
258 get_double(group, key+"G"),
259 get_double(group, key+"B"),
260 get_double(group, key+"A"),0};
261 set_double_list(group,key,c);
262 remove_key(group, key+"R");
263 remove_key(group, key+"G");
264 remove_key(group, key+"B");
265 remove_key(group, key+"A");
266 } catch (const Glib::KeyFileError &err) {
267 }
268 }
269
load_settings(Glib::RefPtr<Gio::File> file)270 void Settings::load_settings (Glib::RefPtr<Gio::File> file)
271 {
272 inhibit_callback = true;
273 filename = file->get_path();
274
275 // set_defaults();
276
277 if (has_group("Extruder"))
278 remove_group("Extruder"); // avoid converting old if merging new file
279
280 try {
281 if (!load_from_file (filename)) {
282 std::cout << _("Failed to load settings from file '") << filename << "\n";
283 return;
284 }
285 } catch (const Glib::KeyFileError &err) {
286 std::cout << _("Exception ") << err.what() << _(" loading settings from file '") << filename << "\n";
287 return;
288 }
289
290 std::cerr << _("Parsing config from '") << filename << "\n";
291
292 // convert old colour handling:
293 vector< Glib::ustring > groups = get_groups();
294 for (uint g = 0; g < groups.size(); g++) {
295 //cerr << "["<<groups[g] << "] " ;
296 vector< Glib::ustring > keys = get_keys(groups[g]);
297 for (uint k = 0; k < keys.size(); k++) {
298 int n = keys[k].length();
299 int c = keys[k].find("Colour");
300 if (c >= 0 && c < n-6 && keys[k].substr(c+6,1) == "R")
301 convert_old_colour(groups[g],keys[k].substr(0,c+6));
302 }
303 }
304
305 // convert old user buttons:
306 std::vector<std::string> CustomButtonLabels;
307 std::vector<std::string> CustomButtonGCodes;
308 if (has_group("UserButtons")) {
309 CustomButtonLabels = get_string_list("UserButtons","Labels");
310 CustomButtonGCodes = get_string_list("UserButtons","GCodes");
311 }
312 try {
313 vector< Glib::ustring > keys = get_keys("CustomButtons");
314 for (uint k = 0; k < keys.size(); k++) {
315 bool havekey = false;
316 for (uint o = 0; o < CustomButtonLabels.size(); o++) {
317 if (CustomButtonLabels[o] == keys[k]) {
318 CustomButtonGCodes[o] = get_string("CustomButtons",keys[k]);
319 havekey = true;
320 break;
321 }
322 }
323 if (!havekey) {
324 CustomButtonLabels.push_back(keys[k]);
325 CustomButtonGCodes.push_back(get_string("CustomButtons",keys[k]));
326 }
327 }
328 remove_group("CustomButtons");
329 } catch (Glib::KeyFileError &err) {}
330 if (!has_group("UserButtons")) {
331 set_string_list("UserButtons","Labels",CustomButtonLabels);
332 set_string_list("UserButtons","GCodes",CustomButtonGCodes);
333 }
334
335 // convert old extruders, now we count "Extruder0", "Extruder1" ...
336 // instead of "Extruder", "Extruder2" ...
337 if (has_group("Extruder")) { // have old Extruders
338 uint ne = getNumExtruders() + 1; // +1 because "Extruder" is not counted
339 if (has_group("Extruder0")) ne--; // already have "new" Extruders
340 copyGroup("Extruder","Extruder0");
341 if (ne > 1) {
342 for (uint k = 2; k < ne+1; k++) // copy 2,3,4,... to 1,2,3,...
343 copyGroup(numberedExtruder("Extruder",k),
344 numberedExtruder("Extruder",k-1));
345 remove_group(numberedExtruder("Extruder",ne));
346 }
347 remove_group("Extruder");
348 }
349 uint ne = getNumExtruders();
350 for (uint k = 0; k < ne; k++) {
351 if (!has_key(numberedExtruder("Extruder",k), "OffsetX"))
352 set_double(numberedExtruder("Extruder",k), "OffsetX", 0);
353 if (!has_key(numberedExtruder("Extruder",k), "OffsetY"))
354 set_double(numberedExtruder("Extruder",k), "OffsetY", 0);
355 }
356 SelectExtruder(0);
357
358 if ( ( has_group("Misc") &&
359 !has_key("Misc","SpeedsAreMMperSec") ) ||
360 !get_boolean("Misc","SpeedsAreMMperSec") )
361 cout << "!!!" << endl << _("\tThe config file has old speed settings (mm/min).\n\t Adjust them to mm/sec\n\t or use RepSnapper from 2.0 to 2.2 to convert them automatically.") << "!!!" << endl;
362 set_boolean("Misc","SpeedsAreMMperSec",true);
363
364 inhibit_callback = false;
365 m_user_changed = false;
366 m_signal_visual_settings_changed.emit();
367 m_signal_update_settings_gui.emit();
368 }
369
370
save_settings(Glib::RefPtr<Gio::File> file)371 void Settings::save_settings(Glib::RefPtr<Gio::File> file)
372 {
373 inhibit_callback = true;
374 set_string("Global","Version",VERSION);
375
376 remove_group("Extruder"); // is only temporary
377
378 Glib::ustring contents = to_data();
379 // cerr << contents << endl;
380 Glib::file_set_contents (file->get_path(), contents);
381
382 SelectExtruder(selectedExtruder); // reload default extruder
383
384 inhibit_callback = false;
385 // all changes safely saved
386 m_user_changed = false;
387 }
388
set_to_gui(Builder & builder,const string & group,const string & key)389 void Settings::set_to_gui (Builder &builder,
390 const string &group, const string &key)
391 {
392 inhibit_callback = true;
393 Glib::ustring glade_name = group + "." + key;
394 // inhibit warning for settings not defined in glade UI:
395 if (!builder->get_object (glade_name)) {
396 //cerr << glade_name << _(" not defined in GUI!")<< endl;
397 return;
398 }
399
400 Gtk::Widget *w = NULL;
401 builder->get_widget (glade_name, w);
402 if (!w) {
403 std::cerr << _("Missing user interface item ") << glade_name << "\n";
404 return;
405 }
406 Gtk::CheckButton *check = dynamic_cast<Gtk::CheckButton *>(w);
407 if (check) {
408 check->set_active (get_boolean(group,key));
409 return;
410 }
411 Gtk::SpinButton *spin = dynamic_cast<Gtk::SpinButton *>(w);
412 if (spin) {
413 spin->set_value (get_double(group,key));
414 return;
415 }
416 Gtk::Range *range = dynamic_cast<Gtk::Range *>(w);
417 if (range) {
418 range->set_value (get_double(group,key));
419 return;
420 }
421 Gtk::ComboBox *combo = dynamic_cast<Gtk::ComboBox *>(w);
422 if (combo) {
423 if (glade_name == "Hardware.SerialSpeed") // has real value
424 combobox_set_to(combo, get_string(group,key));
425 else // has index
426 combo->set_active(get_integer(group,key));
427 return;
428 }
429 Gtk::Entry *entry = dynamic_cast<Gtk::Entry *>(w);
430 if (entry) {
431 entry->set_text (get_string(group,key));
432 return;
433 }
434 Gtk::Expander *exp = dynamic_cast<Gtk::Expander *>(w);
435 if (exp) {
436 exp->set_expanded (get_boolean(group,key));
437 return;
438 }
439 Gtk::ColorButton *col = dynamic_cast<Gtk::ColorButton *>(w);
440 if(col) {
441 vector<double> c = get_double_list(group,key);
442 Gdk::Color co; co.set_rgb_p(c[0],c[1],c[2]);
443 col->set_use_alpha(true);
444 col->set_color(co);
445 col->set_alpha(c[3] * 65535.0);
446 return;
447 }
448 Gtk::TextView *tv = dynamic_cast<Gtk::TextView *>(w);
449 if (tv) {
450 tv->get_buffer()->set_text(get_string(group,key));
451 return;
452 }
453
454 cerr << "set_to_gui of "<< glade_name << " not done!" << endl;
455 }
456
457
get_from_gui(Builder & builder,const string & glade_name)458 void Settings::get_from_gui (Builder &builder, const string &glade_name)
459 {
460 if (inhibit_callback) return;
461 if (!builder->get_object (glade_name)) {
462 cerr << "no such object " << glade_name << endl;
463 return;
464 }
465 Gtk::Widget *w = NULL;
466 builder->get_widget (glade_name, w);
467 string group, key;
468 if (!splitpoint(glade_name, group, key)) return;
469 while (w) { // for using break ...
470 //cerr << "get " << group << "." << key << " from gui"<< endl;
471 m_user_changed = true; // is_changed;
472 Gtk::CheckButton *check = dynamic_cast<Gtk::CheckButton *>(w);
473 if (check) {
474 set_boolean(group, key, check->get_active());
475 break;
476 }
477 Gtk::SpinButton *spin = dynamic_cast<Gtk::SpinButton *>(w);
478 if (spin) {
479 set_double(group, key, spin->get_value());
480 break;
481 }
482 Gtk::Range *range = dynamic_cast<Gtk::Range *>(w);
483 if (range) {
484 set_double(group, key, range->get_value());
485 break;
486 }
487 Gtk::ComboBox *combo = dynamic_cast<Gtk::ComboBox *>(w);
488 if (combo) {
489 if (glade_name == "Hardware.SerialSpeed") // has real value
490 set_string(group,key,combobox_get_active_value(combo));
491 else
492 set_integer(group,key,combo->get_active_row_number ());
493 break;
494 }
495 Gtk::Entry *e = dynamic_cast<Gtk::Entry *>(w);
496 if (e) {
497 set_string(group,key,e->get_text());
498 break;
499 }
500 Gtk::Expander *exp = dynamic_cast<Gtk::Expander *>(w);
501 if (exp) {
502 set_boolean(group,key,exp->get_expanded());
503 break;
504 }
505 Gtk::ColorButton *cb = dynamic_cast<Gtk::ColorButton *>(w);
506 if (cb) {
507 get_colour_from_gui(builder, glade_name);
508 break;
509 }
510 Gtk::TextView *tv = dynamic_cast<Gtk::TextView *>(w);
511 if (tv) {
512 set_string(group,key,tv->get_buffer()->get_text());
513 break;
514 }
515 cerr << _("Did not get setting from ") << glade_name << endl;
516 m_user_changed = false;
517 break;
518 }
519 if (m_user_changed) {
520 // update currently edited extruder
521 if (glade_name.substr(0,8) == "Extruder") {
522 copyGroup("Extruder",numberedExtruder("Extruder", selectedExtruder));
523 // if selected for support, disable support for other extruders
524 if (key == "UseForSupport" && get_boolean(group,key) ) {
525 for (uint i = 0; i < getNumExtruders(); i++) {
526 if (i != selectedExtruder) {
527 set_boolean(numberedExtruder("Extruder", i), key, false);
528 }
529 }
530 }
531 }
532 m_signal_visual_settings_changed.emit();
533 }
534 }
535
536
537
get_colour_from_gui(Builder & builder,const string & glade_name)538 void Settings::get_colour_from_gui (Builder &builder, const string &glade_name)
539 {
540 string group,key;
541 if (!splitpoint(glade_name, group,key)) return;
542 Gdk::Color c;
543 Gtk::ColorButton *w = NULL;
544 builder->get_widget (glade_name, w);
545 if (!w) return;
546
547 c = w->get_color();
548
549 // FIXME: detect 'changed' etc.
550 vector<double> d(4);
551 d[0] = c.get_red_p();
552 d[1] = c.get_green_p();
553 d[2] = c.get_blue_p();
554 d[3] = (float) (w->get_alpha()) / 65535.0;
555
556 set_double_list(group, key, d);
557
558 m_signal_visual_settings_changed.emit();
559 }
560
561
562 // whole group or all groups
set_to_gui(Builder & builder,const string filter)563 void Settings::set_to_gui (Builder &builder, const string filter)
564 {
565 inhibit_callback = true;
566 vector< Glib::ustring > groups = get_groups();
567 for (uint g = 0; g < groups.size(); g++) {
568 vector< Glib::ustring > keys = get_keys(groups[g]);
569 for (uint k = 0; k < keys.size(); k++) {
570 set_to_gui(builder, groups[g], keys[k]);
571 }
572 }
573
574 //set_filltypes_to_gui (builder);
575
576 if (filter == "" || filter == "Misc") {
577 Gtk::Window *pWindow = NULL;
578 builder->get_widget("main_window", pWindow);
579 try {
580 int w = get_integer("Misc","WindowWidth");
581 int h = get_integer("Misc","WindowHeight");
582 if (pWindow && w > 0 && h > 0) pWindow->resize(w,h);
583 int x = get_integer("Misc","WindowPosX");
584 int y = get_integer("Misc","WindowPosY");
585 if (pWindow && x > 0 && y > 0) pWindow->move(x,y);
586 } catch (const Glib::KeyFileError &err) {
587 std::cout << _("Exception ") << err.what() << _(" loading setting\n");
588 }
589 }
590
591 // Set serial speed. Find the row that holds this value
592 if (filter == "" || filter == "Hardware") {
593 Gtk::ComboBox *portspeed = NULL;
594 builder->get_widget ("Hardware.SerialSpeed", portspeed);
595 if (portspeed) {
596 std::ostringstream ostr;
597 ostr << get_integer("Hardware","SerialSpeed");
598 //cerr << "portspeed " << get_integer("Hardware","SerialSpeed") << endl;
599 combobox_set_to(portspeed, ostr.str());
600 }
601 }
602 inhibit_callback = false;
603 }
604
605
connect_to_ui(Builder & builder)606 void Settings::connect_to_ui (Builder &builder)
607 {
608 if (has_group("Ranges")) {
609 vector<string> ranges = get_keys("Ranges");
610 for (uint i = 0; i < ranges.size(); i++) {
611 // get min, max, increment, page-incr.
612 vector<double> vals = get_double_list("Ranges", ranges[i]);
613 Gtk::Widget *w = NULL;
614 try {
615 builder->get_widget (ranges[i], w);
616 if (!w) {
617 std::cerr << "Missing user interface item " << ranges[i] << "\n";
618 continue;
619 }
620 Gtk::SpinButton *spin = dynamic_cast<Gtk::SpinButton *>(w);
621 if (spin) {
622 spin->set_range (vals[0],vals[1]);
623 spin->set_increments (vals[2],vals[3]);
624 continue;
625 }
626 Gtk::Range *range = dynamic_cast<Gtk::Range *>(w); // sliders etc.
627 if (range) {
628 range->set_range (vals[0],vals[1]);
629 range->set_increments (vals[2],vals[3]);
630 continue;
631 }
632 } catch (Glib::Exception &ex) {
633 }
634 }
635 }
636
637 // add signal callbacks to GUI elements
638 vector< Glib::ustring > groups = get_groups();
639 for (uint g = 0; g < groups.size(); g++) {
640 if (groups[g] == "Ranges") continue; // done that above
641 vector< Glib::ustring > keys = get_keys(groups[g]);
642 for (uint k = 0; k < keys.size(); k++) {
643 string glade_name = groups[g] + "." + keys[k];
644 if (!builder->get_object (glade_name))
645 continue;
646 Gtk::Widget *w = NULL;
647 try {
648 builder->get_widget (glade_name, w);
649 if (!w) {
650 std::cerr << "Missing user interface item " << glade_name << "\n";
651 continue;
652 }
653 Gtk::CheckButton *check = dynamic_cast<Gtk::CheckButton *>(w);
654 if (check) {
655 check->signal_toggled().connect
656 (sigc::bind(sigc::bind<string>(sigc::mem_fun(*this, &Settings::get_from_gui), glade_name), builder));
657 continue;
658 }
659 Gtk::SpinButton *spin = dynamic_cast<Gtk::SpinButton *>(w);
660 if (spin) {
661 spin->signal_value_changed().connect
662 (sigc::bind(sigc::bind<string>(sigc::mem_fun(*this, &Settings::get_from_gui), glade_name), builder)) ;
663 continue;
664 }
665 Gtk::Range *range = dynamic_cast<Gtk::Range *>(w);
666 if (range) {
667 range->signal_value_changed().connect
668 (sigc::bind(sigc::bind<string>(sigc::mem_fun(*this, &Settings::get_from_gui), glade_name), builder));
669 continue;
670 }
671 Gtk::ComboBox *combo = dynamic_cast<Gtk::ComboBox *>(w);
672 if (combo) {
673 if (glade_name == "Hardware.SerialSpeed") { // Serial port speed
674 vector<string> speeds(serialspeeds,
675 serialspeeds+sizeof(serialspeeds)/sizeof(string));
676 set_up_combobox(combo, speeds);
677 } else if (glade_name.find("Filltype")!=std::string::npos) { // Infill types
678 uint nfills = sizeof(InfillNames)/sizeof(string);
679 vector<string> infills(InfillNames,InfillNames+nfills);
680 set_up_combobox(combo,infills);
681 }
682 combo->signal_changed().connect
683 (sigc::bind(sigc::bind<string>(sigc::mem_fun(*this, &Settings::get_from_gui), glade_name), builder));
684 continue;
685 }
686 Gtk::Entry *e = dynamic_cast<Gtk::Entry *>(w);
687 if (e) {
688 e->signal_changed().connect
689 (sigc::bind(sigc::bind<string>(sigc::mem_fun(*this, &Settings::get_from_gui), glade_name), builder));
690 continue;
691 }
692 Gtk::Expander *exp = dynamic_cast<Gtk::Expander *>(w);
693 if (exp) {
694 exp->property_expanded().signal_changed().connect
695 (sigc::bind(sigc::bind<string>(sigc::mem_fun(*this, &Settings::get_from_gui), glade_name), builder));
696 continue;
697 }
698 Gtk::ColorButton *cb = dynamic_cast<Gtk::ColorButton *>(w);
699 if (cb) {
700 cb->signal_color_set().connect
701 (sigc::bind(sigc::bind<string>(sigc::mem_fun(*this, &Settings::get_from_gui), glade_name), builder));
702 continue;
703 }
704 Gtk::TextView *tv = dynamic_cast<Gtk::TextView *>(w);
705 if (tv) {
706 tv->get_buffer()->signal_changed().connect
707 (sigc::bind(sigc::bind<string>(sigc::mem_fun(*this, &Settings::get_from_gui), glade_name), builder));
708 continue;
709 }
710 } catch (Glib::Exception &ex) {
711 }
712 }
713 }
714
715
716 /* Update UI with defaults */
717 m_signal_update_settings_gui.emit();
718 }
719
720
721 // extrusion ratio for round-edge lines
RoundedLinewidthCorrection(double extr_width,double layerheight)722 double Settings::RoundedLinewidthCorrection(double extr_width,
723 double layerheight)
724 {
725 double factor = 1 + (M_PI/4.-1) * layerheight/extr_width;
726 // assume 2 half circles at edges
727 // /-------------------\ //
728 // | | //
729 // \-------------------/ //
730 //cerr << "round factor " << factor << endl;
731 return factor;
732 }
733
GetExtrudedMaterialWidth(double layerheight) const734 double Settings::GetExtrudedMaterialWidth(double layerheight) const
735 {
736 // ExtrudedMaterialWidthRatio is preset by user
737 return min(max(get_double("Extruder","MinimumLineWidth"),
738 get_double("Extruder","ExtrudedMaterialWidthRatio") * layerheight),
739 get_double("Extruder","MaximumLineWidth"));
740 }
741
742 // TODO This depends whether lines are packed or not - ellipsis/rectangle
743
744 // how much mm filament material per extruded line length mm -> E gcode
GetExtrusionPerMM(double layerheight) const745 double Settings::GetExtrusionPerMM(double layerheight) const
746 {
747 double f = get_double("Extruder","ExtrusionFactor"); // overall factor
748 if (get_boolean("Extruder","CalibrateInput")) { // means we use input filament diameter
749 const double matWidth = GetExtrudedMaterialWidth(layerheight); // this is the goal
750 // otherwise we just work back from the extruded diameter for now.
751 const double filamentdiameter = get_double("Extruder","FilamentDiameter");
752 f *= (matWidth * matWidth) / (filamentdiameter * filamentdiameter);
753 } // else: we work in terms of output anyway;
754
755 return f;
756 }
757
758 // return infill distance in mm
GetInfillDistance(double layerthickness,float percent) const759 double Settings::GetInfillDistance(double layerthickness, float percent) const
760 {
761 double fullInfillDistance = GetExtrudedMaterialWidth(layerthickness);
762 if (percent == 0) return 10000000;
763 return fullInfillDistance * (100./percent);
764 }
765
getNumExtruders() const766 uint Settings::getNumExtruders() const
767 {
768 vector< Glib::ustring > groups = get_groups();
769 uint num=0;
770 for (uint g = 0; g < groups.size(); g++)
771 if (groups[g].substr(0,8) == "Extruder"
772 && groups[g].length() > 8 ) // count only numbered
773 num++;
774 return num;
775 }
776
get_extruder_letters() const777 std::vector<char> Settings::get_extruder_letters() const
778 {
779 uint num = getNumExtruders();
780 std::vector<char> letters(num);
781 for (uint i = 0; i < num; i++)
782 letters[i] = get_string(numberedExtruder("Extruder",i),"GCLetter")[0];
783 return letters;
784 }
785
GetSupportExtruder() const786 uint Settings::GetSupportExtruder() const
787 {
788 uint num = getNumExtruders();
789 for (uint i = 0; i < num; i++)
790 if (get_boolean(numberedExtruder("Extruder",i),"UseForSupport"))
791 return i;
792 return 0;
793 }
794
get_extruder_offset(uint num) const795 Vector3d Settings::get_extruder_offset(uint num) const
796 {
797 string ext = numberedExtruder("Extruder",num);
798 return Vector3d(get_double(ext, "OffsetX"),
799 get_double(ext, "OffsetY"), 0.);
800 }
801
802
copyGroup(const string & from,const string & to)803 void Settings::copyGroup(const string &from, const string &to)
804 {
805 vector<string> keys = get_keys(from);
806 for (uint i = 0; i < keys.size(); i++)
807 set_value(to, keys[i], get_value(from, keys[i]));
808 }
809
810 // create new
CopyExtruder(uint num)811 void Settings::CopyExtruder(uint num)
812 {
813 uint total = getNumExtruders();
814 string from = numberedExtruder("Extruder",num);
815 string to = numberedExtruder("Extruder",total);
816 copyGroup(from, to);
817 }
RemoveExtruder(uint num)818 void Settings::RemoveExtruder(uint num)
819 {
820 ostringstream oss; oss << "Extruder"<<num;
821 remove_group(oss.str());
822 }
SelectExtruder(uint num,Builder * builder)823 void Settings::SelectExtruder(uint num, Builder *builder)
824 {
825 if (num >= getNumExtruders()) return;
826 selectedExtruder = num;
827 copyGroup(numberedExtruder("Extruder",num),"Extruder");
828 // show Extruder settings on gui
829 if (builder) {
830 set_to_gui(*builder, "Extruder");
831 }
832 }
833
getBasicTransformation(Matrix4d T) const834 Matrix4d Settings::getBasicTransformation(Matrix4d T) const
835 {
836 Vector3d t;
837 T.get_translation(t);
838 const Vector3d margin = getPrintMargin();
839 double rsize = get_double("Raft","Size") * (get_boolean("Raft","Enable")?1:0);
840 t+= Vector3d(margin.x() + rsize, margin.y() + rsize, 0);
841 T.set_translation(t);
842 return T;
843 }
844
845
getPrintVolume() const846 Vector3d Settings::getPrintVolume() const
847 {
848 return Vector3d (get_double("Hardware","Volume.X"),
849 get_double("Hardware","Volume.Y"),
850 get_double("Hardware","Volume.Z"));
851
852 }
getPrintMargin() const853 Vector3d Settings::getPrintMargin() const
854 {
855 Vector3d margin(get_double("Hardware","PrintMargin.X"),
856 get_double("Hardware","PrintMargin.Y"),
857 get_double("Hardware","PrintMargin.Z"));
858 Vector3d maxoff = Vector3d::ZERO;
859 uint num = getNumExtruders();
860 for (uint i = 0; i < num ; i++) {
861 string ext = numberedExtruder("Extruder",i);
862 double offx = 0, offy = 0;
863 try {
864 offx = abs(get_double(ext, "OffsetX"));
865 offy = abs(get_double(ext, "OffsetY"));
866 } catch (const Glib::KeyFileError &err) {
867 }
868 if (offx > abs(maxoff.x())) maxoff.x() = offx;
869 if (offy > abs(maxoff.y())) maxoff.y() = offy;
870 }
871 if (get_boolean("Slicing","Skirt")) {
872 double distance = get_double("Slicing","SkirtDistance");
873 maxoff += Vector3d(distance, distance, 0);
874 }
875 return margin + maxoff;
876 }
877
878
879 // Locate it in relation to ourselves ...
get_image_path()880 std::string Settings::get_image_path()
881 {
882 std::string basename = Glib::path_get_dirname(filename);
883 return Glib::build_filename (basename, get_string("Global","Image"));
884 }
885
886
887
set_user_button(const string & name,const string & gcode)888 bool Settings::set_user_button(const string &name, const string &gcode) {
889 try {
890 vector<string> buttonlabels = get_string_list("UserButtons","Labels");
891 vector<string> buttongcodes = get_string_list("UserButtons","GCodes");
892 for (uint i = 0; i < buttonlabels.size(); i++){
893 if (buttonlabels[i] == name) {
894 // change button
895 buttongcodes[i] = gcode;
896 set_string_list("UserButtons","GCodes",buttongcodes);
897 } else {
898 // add button
899 buttonlabels.push_back(name);
900 buttongcodes.push_back(gcode);
901 set_string_list("UserButtons","Labels",buttonlabels);
902 set_string_list("UserButtons","GCodes",buttongcodes);
903 }
904 }
905 } catch (const Glib::KeyFileError &err) {
906 }
907 return true;
908 }
909
get_user_gcode(const string & name)910 string Settings::get_user_gcode(const string &name) {
911 try {
912 vector<string> buttonlabels = get_string_list("UserButtons","Labels");
913 vector<string> buttongcodes = get_string_list("UserButtons","GCodes");
914 for (uint i = 0; i < buttonlabels.size(); i++){
915 if (buttonlabels[i] == name)
916 return buttongcodes[i];
917 }
918 } catch (const Glib::KeyFileError &err) {
919 }
920 return "";
921 }
922
del_user_button(const string & name)923 bool Settings::del_user_button(const string &name) {
924 try {
925 vector<string> buttonlabels = get_string_list("UserButtons","Labels");
926 vector<string> buttongcodes = get_string_list("UserButtons","GCodes");
927 for (uint i = 0; i < buttonlabels.size(); i++){
928 if (buttonlabels[i] == name) {
929 buttonlabels.erase(buttonlabels.begin()+i);
930 buttongcodes.erase(buttongcodes.begin()+i);
931 return true;
932 }
933 }
934 } catch (const Glib::KeyFileError &err) {
935 }
936 return false;
937 }
938
939