1 /** \file
2 * Parameters for extensions.
3 */
5 /*
6 * Authors:
7 * Ted Gould <ted@gould.cx>
8 *
9 * Copyright (C) 2005-2006 Authors
10 *
11 * Released under GNU GPL, read the file 'COPYING' for more information
12 */
14 #ifdef HAVE_CONFIG_H
15 # include "config.h"
16 #endif
19 #include <gtkmm/adjustment.h>
20 #include <gtkmm/box.h>
21 #include <gtkmm/spinbutton.h>
23 #include <glibmm/i18n.h>
25 #include <xml/node.h>
27 #include "extension.h"
28 #include "prefs-utils.h"
29 #include "document-private.h"
30 #include "sp-object.h"
32 #include "parameter.h"
34 /** \brief The root directory in the preferences database for extension
35 related parameters. */
36 #define PREF_DIR "extensions"
38 namespace Inkscape {
39 namespace Extension {
41 /** \brief A description parameter */
42 class ParamDescription : public Parameter {
43 private:
44 /** \brief Internal value. */
45 gchar * _value;
46 public:
47 ParamDescription(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml);
48 Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node);
49 };
51 /** \brief A boolean parameter */
52 class ParamBool : public Parameter {
53 private:
54 /** \brief Internal value. */
55 bool _value;
56 public:
57 ParamBool(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml);
58 /** \brief Returns \c _value */
59 bool get (const SPDocument * doc, const Inkscape::XML::Node * node) { return _value; }
60 bool set (bool in, SPDocument * doc, Inkscape::XML::Node * node);
61 Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node);
62 Glib::ustring * string (void);
63 };
65 /** \brief Use the superclass' allocator and set the \c _value */
66 ParamBool::ParamBool (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
67 Parameter(name, guitext, desc, scope, ext), _value(false)
68 {
69 const char * defaultval = NULL;
70 if (sp_repr_children(xml) != NULL)
71 defaultval = sp_repr_children(xml)->content();
73 if (defaultval != NULL && (!strcmp(defaultval, "TRUE") || !strcmp(defaultval, "true") || !strcmp(defaultval, "1"))) {
74 _value = true;
75 } else {
76 _value = false;
77 }
79 gchar * pref_name = this->pref_name();
80 _value = (bool)prefs_get_int_attribute(PREF_DIR, pref_name, _value);
81 g_free(pref_name);
83 return;
84 }
86 class ParamInt : public Parameter {
87 private:
88 /** \brief Internal value. */
89 int _value;
90 int _min;
91 int _max;
92 public:
93 ParamInt (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml);
94 /** \brief Returns \c _value */
95 int get (const SPDocument * doc, const Inkscape::XML::Node * node) { return _value; }
96 int set (int in, SPDocument * doc, Inkscape::XML::Node * node);
97 int max (void) { return _max; }
98 int min (void) { return _min; }
99 Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node);
100 Glib::ustring * string (void);
101 };
103 /** \brief Use the superclass' allocator and set the \c _value */
104 ParamInt::ParamInt (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
105 Parameter(name, guitext, desc, scope, ext), _value(0), _min(0), _max(10)
106 {
107 const char * defaultval = NULL;
108 if (sp_repr_children(xml) != NULL)
109 defaultval = sp_repr_children(xml)->content();
110 if (defaultval != NULL) {
111 _value = atoi(defaultval);
112 }
114 const char * maxval = xml->attribute("max");
115 if (maxval != NULL)
116 _max = atoi(maxval);
118 const char * minval = xml->attribute("min");
119 if (minval != NULL)
120 _min = atoi(minval);
122 /* We're handling this by just killing both values */
123 if (_max < _min) {
124 _max = 10;
125 _min = 0;
126 }
128 gchar * pref_name = this->pref_name();
129 _value = prefs_get_int_attribute(PREF_DIR, pref_name, _value);
130 g_free(pref_name);
132 // std::cout << "New Int:: value: " << _value << " max: " << _max << " min: " << _min << std::endl;
134 if (_value > _max) _value = _max;
135 if (_value < _min) _value = _min;
137 return;
138 }
140 class ParamFloat : public Parameter {
141 private:
142 /** \brief Internal value. */
143 float _value;
144 float _min;
145 float _max;
146 public:
147 ParamFloat (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml);
148 /** \brief Returns \c _value */
149 float get (const SPDocument * doc, const Inkscape::XML::Node * node) { return _value; }
150 float set (float in, SPDocument * doc, Inkscape::XML::Node * node);
151 float max (void) { return _max; }
152 float min (void) { return _min; }
153 Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node);
154 Glib::ustring * string (void);
155 };
157 /** \brief Use the superclass' allocator and set the \c _value */
158 ParamFloat::ParamFloat (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
159 Parameter(name, guitext, desc, scope, ext), _value(0.0), _min(0.0), _max(10.0)
160 {
161 const char * defaultval = NULL;
162 if (sp_repr_children(xml) != NULL)
163 defaultval = sp_repr_children(xml)->content();
164 if (defaultval != NULL) {
165 _value = atof(defaultval);
166 }
168 const char * maxval = xml->attribute("max");
169 if (maxval != NULL)
170 _max = atof(maxval);
172 const char * minval = xml->attribute("min");
173 if (minval != NULL)
174 _min = atof(minval);
176 /* We're handling this by just killing both values */
177 if (_max < _min) {
178 _max = 10.0;
179 _min = 0.0;
180 }
182 gchar * pref_name = this->pref_name();
183 _value = prefs_get_double_attribute(PREF_DIR, pref_name, _value);
184 g_free(pref_name);
186 // std::cout << "New Float:: value: " << _value << " max: " << _max << " min: " << _min << std::endl;
188 if (_value > _max) _value = _max;
189 if (_value < _min) _value = _min;
191 return;
192 }
194 class ParamString : public Parameter {
195 private:
196 /** \brief Internal value. This should point to a string that has
197 been allocated in memory. And should be free'd. */
198 gchar * _value;
199 public:
200 ParamString(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml);
201 ~ParamString(void);
202 /** \brief Returns \c _value, with a \i const to protect it. */
203 const gchar * get (const SPDocument * doc, const Inkscape::XML::Node * node) { return _value; }
204 const gchar * set (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node);
205 Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node);
206 Glib::ustring * string (void);
207 };
209 /**
210 \return None
211 \brief This function creates a parameter that can be used later. This
212 is typically done in the creation of the extension and defined
213 in the XML file describing the extension (it's private so people
214 have to use the system) :)
215 \param in_repr The XML describing the parameter
217 This function first grabs all of the data out of the Repr and puts
218 it into local variables. Actually, these are just pointers, and the
219 data is not duplicated so we need to be careful with it. If there
220 isn't a name or a type in the XML, then no parameter is created as
221 the function just returns.
223 From this point on, we're pretty committed as we've allocated an
224 object and we're starting to fill it. The name is set first, and
225 is created with a strdup to actually allocate memory for it. Then
226 there is a case statement (roughly because strcmp requires 'ifs')
227 based on what type of parameter this is. Depending which type it
228 is, the value is interpreted differently, but they are relatively
229 straight forward. In all cases the value is set to the default
230 value from the XML and the type is set to the interpreted type.
231 */
232 Parameter *
233 Parameter::make (Inkscape::XML::Node * in_repr, Inkscape::Extension::Extension * in_ext)
234 {
235 const char * name;
236 const char * type;
237 const char * guitext;
238 const char * desc;
239 const char * scope_str;
240 Parameter::_scope_t scope = Parameter::SCOPE_USER;
242 name = in_repr->attribute("name");
243 type = in_repr->attribute("type");
244 guitext = in_repr->attribute("gui-text");
245 if (guitext == NULL)
246 guitext = in_repr->attribute("_gui-text");
247 desc = in_repr->attribute("gui-description");
248 if (desc == NULL)
249 desc = in_repr->attribute("_gui-description");
250 scope_str = in_repr->attribute("scope");
252 /* In this case we just don't have enough information */
253 if (name == NULL || type == NULL) {
254 return NULL;
255 }
257 if (scope_str != NULL) {
258 if (!strcmp(scope_str, "user")) {
259 scope = Parameter::SCOPE_USER;
260 } else if (!strcmp(scope_str, "document")) {
261 scope = Parameter::SCOPE_DOCUMENT;
262 } else if (!strcmp(scope_str, "node")) {
263 scope = Parameter::SCOPE_NODE;
264 }
265 }
267 Parameter * param = NULL;
268 if (!strcmp(type, "boolean")) {
269 param = new ParamBool(name, guitext, desc, scope, in_ext, in_repr);
270 } else if (!strcmp(type, "int")) {
271 param = new ParamInt(name, guitext, desc, scope, in_ext, in_repr);
272 } else if (!strcmp(type, "float")) {
273 param = new ParamFloat(name, guitext, desc, scope, in_ext, in_repr);
274 } else if (!strcmp(type, "string")) {
275 param = new ParamString(name, guitext, desc, scope, in_ext, in_repr);
276 } else if (!strcmp(type, "description")) {
277 param = new ParamDescription(name, guitext, desc, scope, in_ext, in_repr);
278 }
280 /* Note: param could equal NULL */
281 return param;
282 }
284 /** \brief A function to set the \c _value
285 \param in The value to set to
286 \param doc A document that should be used to set the value.
287 \param node The node where the value may be placed
289 This function sets the internal value, but it also sets the value
290 in the preferences structure. To put it in the right place, \c PREF_DIR
291 and \c pref_name() are used.
292 */
293 bool
294 ParamBool::set (bool in, SPDocument * doc, Inkscape::XML::Node * node)
295 {
296 _value = in;
298 gchar * prefname = this->pref_name();
299 prefs_set_int_attribute(PREF_DIR, prefname, _value == true ? 1 : 0);
300 g_free(prefname);
302 return _value;
303 }
305 /** \brief A function to set the \c _value
306 \param in The value to set to
307 \param doc A document that should be used to set the value.
308 \param node The node where the value may be placed
310 This function sets the internal value, but it also sets the value
311 in the preferences structure. To put it in the right place, \c PREF_DIR
312 and \c pref_name() are used.
313 */
314 int
315 ParamInt::set (int in, SPDocument * doc, Inkscape::XML::Node * node)
316 {
317 _value = in;
318 if (_value > _max) _value = _max;
319 if (_value < _min) _value = _min;
321 gchar * prefname = this->pref_name();
322 prefs_set_int_attribute(PREF_DIR, prefname, _value);
323 g_free(prefname);
325 return _value;
326 }
328 /** \brief A function to set the \c _value
329 \param in The value to set to
330 \param doc A document that should be used to set the value.
331 \param node The node where the value may be placed
333 This function sets the internal value, but it also sets the value
334 in the preferences structure. To put it in the right place, \c PREF_DIR
335 and \c pref_name() are used.
336 */
337 float
338 ParamFloat::set (float in, SPDocument * doc, Inkscape::XML::Node * node)
339 {
340 _value = in;
341 if (_value > _max) _value = _max;
342 if (_value < _min) _value = _min;
344 gchar * prefname = this->pref_name();
345 prefs_set_double_attribute(PREF_DIR, prefname, _value);
346 g_free(prefname);
348 return _value;
349 }
351 /** \brief A function to set the \c _value
352 \param in The value to set to
353 \param doc A document that should be used to set the value.
354 \param node The node where the value may be placed
356 This function sets the internal value, but it also sets the value
357 in the preferences structure. To put it in the right place, \c PREF_DIR
358 and \c pref_name() are used.
360 To copy the data into _value the old memory must be free'd first.
361 It is important to note that \c g_free handles \c NULL just fine. Then
362 the passed in value is duplicated using \c g_strdup().
363 */
364 const gchar *
365 ParamString::set (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node)
366 {
367 if (in == NULL) return NULL; /* Can't have NULL string */
369 if (_value != NULL)
370 g_free(_value);
371 _value = g_strdup(in);
373 gchar * prefname = this->pref_name();
374 prefs_set_string_attribute(PREF_DIR, prefname, _value);
375 g_free(prefname);
377 return _value;
378 }
380 /** \brief Wrapper to cast to the object and use it's function. */
381 bool
382 Parameter::get_bool (const SPDocument * doc, const Inkscape::XML::Node * node)
383 {
384 ParamBool * boolpntr;
385 boolpntr = dynamic_cast<ParamBool *>(this);
386 if (boolpntr == NULL)
387 throw Extension::param_wrong_type();
388 return boolpntr->get(doc, node);
389 }
391 /** \brief Wrapper to cast to the object and use it's function. */
392 int
393 Parameter::get_int (const SPDocument * doc, const Inkscape::XML::Node * node)
394 {
395 ParamInt * intpntr;
396 intpntr = dynamic_cast<ParamInt *>(this);
397 if (intpntr == NULL)
398 throw Extension::param_wrong_type();
399 return intpntr->get(doc, node);
400 }
402 /** \brief Wrapper to cast to the object and use it's function. */
403 float
404 Parameter::get_float (const SPDocument * doc, const Inkscape::XML::Node * node)
405 {
406 ParamFloat * floatpntr;
407 floatpntr = dynamic_cast<ParamFloat *>(this);
408 if (floatpntr == NULL)
409 throw Extension::param_wrong_type();
410 return floatpntr->get(doc, node);
411 }
413 /** \brief Wrapper to cast to the object and use it's function. */
414 const gchar *
415 Parameter::get_string (const SPDocument * doc, const Inkscape::XML::Node * node)
416 {
417 ParamString * stringpntr;
418 stringpntr = dynamic_cast<ParamString *>(this);
419 if (stringpntr == NULL)
420 throw Extension::param_wrong_type();
421 return stringpntr->get(doc, node);
422 }
424 /** \brief Wrapper to cast to the object and use it's function. */
425 bool
426 Parameter::set_bool (bool in, SPDocument * doc, Inkscape::XML::Node * node)
427 {
428 ParamBool * boolpntr;
429 boolpntr = dynamic_cast<ParamBool *>(this);
430 if (boolpntr == NULL)
431 throw Extension::param_wrong_type();
432 return boolpntr->set(in, doc, node);
433 }
435 /** \brief Wrapper to cast to the object and use it's function. */
436 int
437 Parameter::set_int (int in, SPDocument * doc, Inkscape::XML::Node * node)
438 {
439 ParamInt * intpntr;
440 intpntr = dynamic_cast<ParamInt *>(this);
441 if (intpntr == NULL)
442 throw Extension::param_wrong_type();
443 return intpntr->set(in, doc, node);
444 }
446 /** \brief Wrapper to cast to the object and use it's function. */
447 float
448 Parameter::set_float (float in, SPDocument * doc, Inkscape::XML::Node * node)
449 {
450 ParamFloat * floatpntr;
451 floatpntr = dynamic_cast<ParamFloat *>(this);
452 if (floatpntr == NULL)
453 throw Extension::param_wrong_type();
454 return floatpntr->set(in, doc, node);
455 }
457 /** \brief Wrapper to cast to the object and use it's function. */
458 const gchar *
459 Parameter::set_string (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node)
460 {
461 ParamString * stringpntr;
462 stringpntr = dynamic_cast<ParamString *>(this);
463 if (stringpntr == NULL)
464 throw Extension::param_wrong_type();
465 return stringpntr->set(in, doc, node);
466 }
468 /** \brief Initialize the object, to do that, copy the data. */
469 ParamString::ParamString (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
470 Parameter(name, guitext, desc, scope, ext), _value(NULL)
471 {
472 const char * defaultval = NULL;
473 if (sp_repr_children(xml) != NULL)
474 defaultval = sp_repr_children(xml)->content();
476 gchar * pref_name = this->pref_name();
477 const gchar * paramval = prefs_get_string_attribute(PREF_DIR, pref_name);
478 g_free(pref_name);
480 if (paramval != NULL)
481 defaultval = paramval;
482 if (defaultval != NULL)
483 _value = g_strdup(defaultval);
485 return;
486 }
488 /** \brief Free the allocated data. */
489 ParamString::~ParamString(void)
490 {
491 g_free(_value);
492 }
494 /** \brief Oop, now that we need a parameter, we need it's name. */
495 Parameter::Parameter (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext) :
496 extension(ext), _name(NULL), _desc(NULL), _scope(scope), _text(NULL)
497 {
498 if (name != NULL)
499 _name = g_strdup(name);
500 if (desc != NULL) {
501 _desc = g_strdup(desc);
502 // printf("Adding description: '%s' on '%s'\n", _desc, _name);
503 }
506 if (guitext != NULL)
507 _text = g_strdup(guitext);
508 else
509 _text = g_strdup(name);
511 return;
512 }
514 /** \brief Just free the allocated name. */
515 Parameter::~Parameter (void)
516 {
517 g_free(_name);
518 g_free(_text);
519 }
521 /** \brief Build the name to write the parameter from the extension's
522 ID and the name of this parameter. */
523 gchar *
524 Parameter::pref_name (void)
525 {
526 return g_strdup_printf("%s.%s", extension->get_id(), _name);
527 }
529 Inkscape::XML::Node *
530 Parameter::find_child (Inkscape::XML::Node * adult)
531 {
532 return sp_repr_lookup_child(adult, "name", _name);
533 }
535 Inkscape::XML::Node *
536 Parameter::new_child (Inkscape::XML::Node * parent)
537 {
538 Inkscape::XML::Node * retval;
539 retval = sp_repr_new("inkscape:extension-param");
540 retval->setAttribute("name", _name);
542 parent->appendChild(retval);
543 return retval;
544 }
546 Inkscape::XML::Node *
547 Parameter::document_param_node (SPDocument * doc)
548 {
549 Inkscape::XML::Node * defs = SP_OBJECT_REPR(SP_DOCUMENT_DEFS(doc));
550 Inkscape::XML::Node * params = NULL;
552 GQuark const name_quark = g_quark_from_string("inkscape:extension-params");
554 for (Inkscape::XML::Node * child = defs->firstChild();
555 child != NULL;
556 child = child->next()) {
557 if ((GQuark)child->code() == name_quark &&
558 !strcmp(child->attribute("extension"), extension->get_id())) {
559 params = child;
560 break;
561 }
562 }
564 if (params == NULL) {
565 params = sp_repr_new("inkscape:extension-param");
566 params->setAttribute("extension", extension->get_id());
567 defs->appendChild(params);
568 }
570 return params;
571 }
573 /** \brief Basically, if there is no widget pass a NULL. */
574 Gtk::Widget *
575 Parameter::get_widget (SPDocument * doc, Inkscape::XML::Node * node)
576 {
577 return NULL;
578 }
580 /** \brief If I'm not sure which it is, just don't return a value. */
581 Glib::ustring *
582 Parameter::string (void)
583 {
584 Glib::ustring * mystring = new Glib::ustring("");
585 return mystring;
586 }
588 /** \brief A class to make an adjustment that uses Extension params */
589 class ParamFloatAdjustment : public Gtk::Adjustment {
590 /** The parameter to adjust */
591 ParamFloat * _pref;
592 SPDocument * _doc;
593 Inkscape::XML::Node * _node;
594 public:
595 /** \brief Make the adjustment using an extension and the string
596 describing the parameter. */
597 ParamFloatAdjustment (ParamFloat * param, SPDocument * doc, Inkscape::XML::Node * node) :
598 Gtk::Adjustment(0.0, param->min(), param->max(), 0.1), _pref(param), _doc(doc), _node(node) {
599 this->set_value(_pref->get(NULL, NULL) /* \todo fix */);
600 this->signal_value_changed().connect(sigc::mem_fun(this, &ParamFloatAdjustment::val_changed));
601 return;
602 };
604 void val_changed (void);
605 }; /* class ParamFloatAdjustment */
607 /** \brief A function to respond to the value_changed signal from the
608 adjustment.
610 This function just grabs the value from the adjustment and writes
611 it to the parameter. Very simple, but yet beautiful.
612 */
613 void
614 ParamFloatAdjustment::val_changed (void)
615 {
616 // std::cout << "Value Changed to: " << this->get_value() << std::endl;
617 _pref->set(this->get_value(), _doc, _node);
618 return;
619 }
621 /** \brief A class to make an adjustment that uses Extension params */
622 class ParamIntAdjustment : public Gtk::Adjustment {
623 /** The parameter to adjust */
624 ParamInt * _pref;
625 SPDocument * _doc;
626 Inkscape::XML::Node * _node;
627 public:
628 /** \brief Make the adjustment using an extension and the string
629 describing the parameter. */
630 ParamIntAdjustment (ParamInt * param, SPDocument * doc, Inkscape::XML::Node * node) :
631 Gtk::Adjustment(0.0, param->min(), param->max(), 1.0), _pref(param), _doc(doc), _node(node) {
632 this->set_value(_pref->get(NULL, NULL) /* \todo fix */);
633 this->signal_value_changed().connect(sigc::mem_fun(this, &ParamIntAdjustment::val_changed));
634 return;
635 };
637 void val_changed (void);
638 }; /* class ParamIntAdjustment */
640 /** \brief A function to respond to the value_changed signal from the
641 adjustment.
643 This function just grabs the value from the adjustment and writes
644 it to the parameter. Very simple, but yet beautiful.
645 */
646 void
647 ParamIntAdjustment::val_changed (void)
648 {
649 // std::cout << "Value Changed to: " << this->get_value() << std::endl;
650 _pref->set((int)this->get_value(), _doc, _node);
651 return;
652 }
654 /**
655 \brief Creates a Float Adjustment for a float parameter
657 Builds a hbox with a label and a float adjustment in it.
658 */
659 Gtk::Widget *
660 ParamFloat::get_widget (SPDocument * doc, Inkscape::XML::Node * node)
661 {
662 Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox());
664 Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_LEFT));
665 label->show();
666 hbox->pack_start(*label, true, true);
668 ParamFloatAdjustment * fadjust = Gtk::manage(new ParamFloatAdjustment(this, doc, node));
669 Gtk::SpinButton * spin = Gtk::manage(new Gtk::SpinButton(*fadjust, 0.1, 1));
670 spin->show();
671 hbox->pack_start(*spin, false, false);
673 hbox->show();
675 return dynamic_cast<Gtk::Widget *>(hbox);
676 }
678 /**
679 \brief Creates a Int Adjustment for a int parameter
681 Builds a hbox with a label and a int adjustment in it.
682 */
683 Gtk::Widget *
684 ParamInt::get_widget (SPDocument * doc, Inkscape::XML::Node * node)
685 {
686 Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox());
688 Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_LEFT));
689 label->show();
690 hbox->pack_start(*label, true, true);
692 ParamIntAdjustment * fadjust = Gtk::manage(new ParamIntAdjustment(this, doc, node));
693 Gtk::SpinButton * spin = Gtk::manage(new Gtk::SpinButton(*fadjust, 1.0, 0));
694 spin->show();
695 hbox->pack_start(*spin, false, false);
697 hbox->show();
699 return dynamic_cast<Gtk::Widget *>(hbox);
700 }
702 /** \brief A check button which is Param aware. It works with the
703 parameter to change it's value as the check button changes
704 value. */
705 class ParamBoolCheckButton : public Gtk::CheckButton {
706 private:
707 /** \brief Param to change */
708 ParamBool * _pref;
709 SPDocument * _doc;
710 Inkscape::XML::Node * _node;
711 public:
712 /** \brief Initialize the check button
713 \param param Which parameter to adjust on changing the check button
715 This function sets the value of the checkbox to be that of the
716 parameter, and then sets up a callback to \c on_toggle.
717 */
718 ParamBoolCheckButton (ParamBool * param, SPDocument * doc, Inkscape::XML::Node * node) :
719 Gtk::CheckButton(), _pref(param), _doc(doc), _node(node) {
720 this->set_active(_pref->get(NULL, NULL) /**\todo fix */);
721 this->signal_toggled().connect(sigc::mem_fun(this, &ParamBoolCheckButton::on_toggle));
722 return;
723 }
724 void on_toggle (void);
725 };
727 /**
728 \brief A function to respond to the check box changing
730 Adjusts the value of the preference to match that in the check box.
731 */
732 void
733 ParamBoolCheckButton::on_toggle (void)
734 {
735 _pref->set(this->get_active(), NULL /**\todo fix this */, NULL);
736 return;
737 }
739 /**
740 \brief Creates a bool check button for a bool parameter
742 Builds a hbox with a label and a check button in it.
743 */
744 Gtk::Widget *
745 ParamBool::get_widget (SPDocument * doc, Inkscape::XML::Node * node)
746 {
747 Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox());
749 Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_LEFT));
750 label->show();
751 hbox->pack_start(*label, true, true);
753 ParamBoolCheckButton * checkbox = new ParamBoolCheckButton(this, doc, node);
754 checkbox->show();
755 hbox->pack_start(*checkbox, false, false);
757 hbox->show();
759 return dynamic_cast<Gtk::Widget *>(hbox);
760 }
762 /** \brief A special category of Gtk::Entry to handle string parameteres */
763 class ParamStringEntry : public Gtk::Entry {
764 private:
765 ParamString * _pref;
766 SPDocument * _doc;
767 Inkscape::XML::Node * _node;
768 public:
769 /** \brief Build a string preference for the given parameter
770 \param pref Where to get the string from, and where to put it
771 when it changes.
772 */
773 ParamStringEntry (ParamString * pref, SPDocument * doc, Inkscape::XML::Node * node) :
774 Gtk::Entry(), _pref(pref), _doc(doc), _node(node) {
775 if (_pref->get(NULL, NULL) != NULL)
776 this->set_text(Glib::ustring(_pref->get(NULL, NULL)));
777 this->signal_changed().connect(sigc::mem_fun(this, &ParamStringEntry::changed_text));
778 };
779 void changed_text (void);
780 };
782 /** \brief Respond to the text box changing
784 This function responds to the box changing by grabbing the value
785 from the text box and putting it in the parameter.
786 */
787 void
788 ParamStringEntry::changed_text (void)
789 {
790 Glib::ustring data = this->get_text();
791 _pref->set(data.c_str(), _doc, _node);
792 return;
793 }
795 /**
796 \brief Creates a text box for the string parameter
798 Builds a hbox with a label and a text box in it.
799 */
800 Gtk::Widget *
801 ParamString::get_widget (SPDocument * doc, Inkscape::XML::Node * node)
802 {
803 Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox());
805 Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_LEFT));
806 label->show();
807 hbox->pack_start(*label, true, true);
809 ParamStringEntry * textbox = new ParamStringEntry(this, doc, node);
810 textbox->show();
811 hbox->pack_start(*textbox, false, false);
813 hbox->show();
815 return dynamic_cast<Gtk::Widget *>(hbox);
816 }
818 /** \brief Return 'true' or 'false' */
819 Glib::ustring *
820 ParamBool::string (void)
821 {
822 Glib::ustring * mystring;
824 if (_value)
825 mystring = new Glib::ustring("true");
826 else
827 mystring = new Glib::ustring("false");
829 return mystring;
830 }
832 /** \brief Return the value as a string */
833 Glib::ustring *
834 ParamInt::string (void)
835 {
836 char startstring[32];
837 sprintf(startstring, "%d", _value);
838 Glib::ustring * mystring = new Glib::ustring(startstring);
839 return mystring;
840 }
842 /** \brief Return the value as a string */
843 Glib::ustring *
844 ParamFloat::string (void)
845 {
846 char startstring[G_ASCII_DTOSTR_BUF_SIZE];
847 g_ascii_dtostr(startstring, G_ASCII_DTOSTR_BUF_SIZE, _value);
848 Glib::ustring * mystring = new Glib::ustring(startstring);
849 return mystring;
850 }
852 /** \brief Return the value as a string */
853 Glib::ustring *
854 ParamString::string (void)
855 {
856 Glib::ustring * mystring = new Glib::ustring("");
857 *mystring += "\"";
858 *mystring += _value;
859 *mystring += "\"";
860 return mystring;
861 }
863 /** \brief Create a label for the description */
864 Gtk::Widget *
865 ParamDescription::get_widget (SPDocument * doc, Inkscape::XML::Node * node)
866 {
867 Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_value)));
868 label->set_line_wrap();
869 label->show();
871 Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox());
872 hbox->pack_start(*label, true, true, 5);
873 hbox->show();
875 return hbox;
876 }
878 /** \brief Initialize the object, to do that, copy the data. */
879 ParamDescription::ParamDescription (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
880 Parameter(name, guitext, desc, scope, ext), _value(NULL)
881 {
882 // printf("Building Description\n");
883 const char * defaultval = NULL;
884 if (sp_repr_children(xml) != NULL)
885 defaultval = sp_repr_children(xml)->content();
887 if (defaultval != NULL)
888 _value = g_strdup(defaultval);
890 return;
891 }
894 } /* namespace Extension */
895 } /* namespace Inkscape */
897 /*
898 Local Variables:
899 mode:c++
900 c-file-style:"stroustrup"
901 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
902 indent-tabs-mode:nil
903 fill-column:99
904 End:
905 */
906 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :