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 Glib::ustring * string (void);
50 };
52 /** \brief A boolean parameter */
53 class ParamBool : public Parameter {
54 private:
55 /** \brief Internal value. */
56 bool _value;
57 public:
58 ParamBool(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml);
59 /** \brief Returns \c _value */
60 bool get (const SPDocument * doc, const Inkscape::XML::Node * node) { return _value; }
61 bool set (bool in, SPDocument * doc, Inkscape::XML::Node * node);
62 Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node);
63 Glib::ustring * string (void);
64 };
66 /** \brief Use the superclass' allocator and set the \c _value */
67 ParamBool::ParamBool (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
68 Parameter(name, guitext, desc, scope, ext), _value(false)
69 {
70 const char * defaultval = NULL;
71 if (sp_repr_children(xml) != NULL)
72 defaultval = sp_repr_children(xml)->content();
74 if (defaultval != NULL && (!strcmp(defaultval, "TRUE") || !strcmp(defaultval, "true") || !strcmp(defaultval, "1"))) {
75 _value = true;
76 } else {
77 _value = false;
78 }
80 gchar * pref_name = this->pref_name();
81 _value = (bool)prefs_get_int_attribute(PREF_DIR, pref_name, _value);
82 g_free(pref_name);
84 return;
85 }
87 class ParamInt : public Parameter {
88 private:
89 /** \brief Internal value. */
90 int _value;
91 int _min;
92 int _max;
93 public:
94 ParamInt (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml);
95 /** \brief Returns \c _value */
96 int get (const SPDocument * doc, const Inkscape::XML::Node * node) { return _value; }
97 int set (int in, SPDocument * doc, Inkscape::XML::Node * node);
98 int max (void) { return _max; }
99 int min (void) { return _min; }
100 Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node);
101 Glib::ustring * string (void);
102 };
104 /** \brief Use the superclass' allocator and set the \c _value */
105 ParamInt::ParamInt (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
106 Parameter(name, guitext, desc, scope, ext), _value(0), _min(0), _max(10)
107 {
108 const char * defaultval = NULL;
109 if (sp_repr_children(xml) != NULL)
110 defaultval = sp_repr_children(xml)->content();
111 if (defaultval != NULL) {
112 _value = atoi(defaultval);
113 }
115 const char * maxval = xml->attribute("max");
116 if (maxval != NULL)
117 _max = atoi(maxval);
119 const char * minval = xml->attribute("min");
120 if (minval != NULL)
121 _min = atoi(minval);
123 /* We're handling this by just killing both values */
124 if (_max < _min) {
125 _max = 10;
126 _min = 0;
127 }
129 gchar * pref_name = this->pref_name();
130 _value = prefs_get_int_attribute(PREF_DIR, pref_name, _value);
131 g_free(pref_name);
133 // std::cout << "New Int:: value: " << _value << " max: " << _max << " min: " << _min << std::endl;
135 if (_value > _max) _value = _max;
136 if (_value < _min) _value = _min;
138 return;
139 }
141 class ParamFloat : public Parameter {
142 private:
143 /** \brief Internal value. */
144 float _value;
145 float _min;
146 float _max;
147 public:
148 ParamFloat (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml);
149 /** \brief Returns \c _value */
150 float get (const SPDocument * doc, const Inkscape::XML::Node * node) { return _value; }
151 float set (float in, SPDocument * doc, Inkscape::XML::Node * node);
152 float max (void) { return _max; }
153 float min (void) { return _min; }
154 Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node);
155 Glib::ustring * string (void);
156 };
158 /** \brief Use the superclass' allocator and set the \c _value */
159 ParamFloat::ParamFloat (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
160 Parameter(name, guitext, desc, scope, ext), _value(0.0), _min(0.0), _max(10.0)
161 {
162 const char * defaultval = NULL;
163 if (sp_repr_children(xml) != NULL)
164 defaultval = sp_repr_children(xml)->content();
165 if (defaultval != NULL) {
166 _value = atof(defaultval);
167 }
169 const char * maxval = xml->attribute("max");
170 if (maxval != NULL)
171 _max = atof(maxval);
173 const char * minval = xml->attribute("min");
174 if (minval != NULL)
175 _min = atof(minval);
177 /* We're handling this by just killing both values */
178 if (_max < _min) {
179 _max = 10.0;
180 _min = 0.0;
181 }
183 gchar * pref_name = this->pref_name();
184 _value = prefs_get_double_attribute(PREF_DIR, pref_name, _value);
185 g_free(pref_name);
187 // std::cout << "New Float:: value: " << _value << " max: " << _max << " min: " << _min << std::endl;
189 if (_value > _max) _value = _max;
190 if (_value < _min) _value = _min;
192 return;
193 }
195 class ParamString : public Parameter {
196 private:
197 /** \brief Internal value. This should point to a string that has
198 been allocated in memory. And should be free'd. */
199 gchar * _value;
200 public:
201 ParamString(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml);
202 ~ParamString(void);
203 /** \brief Returns \c _value, with a \i const to protect it. */
204 const gchar * get (const SPDocument * doc, const Inkscape::XML::Node * node) { return _value; }
205 const gchar * set (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node);
206 Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node);
207 Glib::ustring * string (void);
208 };
210 /**
211 \return None
212 \brief This function creates a parameter that can be used later. This
213 is typically done in the creation of the extension and defined
214 in the XML file describing the extension (it's private so people
215 have to use the system) :)
216 \param in_repr The XML describing the parameter
218 This function first grabs all of the data out of the Repr and puts
219 it into local variables. Actually, these are just pointers, and the
220 data is not duplicated so we need to be careful with it. If there
221 isn't a name or a type in the XML, then no parameter is created as
222 the function just returns.
224 From this point on, we're pretty committed as we've allocated an
225 object and we're starting to fill it. The name is set first, and
226 is created with a strdup to actually allocate memory for it. Then
227 there is a case statement (roughly because strcmp requires 'ifs')
228 based on what type of parameter this is. Depending which type it
229 is, the value is interpreted differently, but they are relatively
230 straight forward. In all cases the value is set to the default
231 value from the XML and the type is set to the interpreted type.
232 */
233 Parameter *
234 Parameter::make (Inkscape::XML::Node * in_repr, Inkscape::Extension::Extension * in_ext)
235 {
236 const char * name;
237 const char * type;
238 const char * guitext;
239 const char * desc;
240 const char * scope_str;
241 Parameter::_scope_t scope = Parameter::SCOPE_USER;
243 name = in_repr->attribute("name");
244 type = in_repr->attribute("type");
245 guitext = in_repr->attribute("gui-text");
246 if (guitext == NULL)
247 guitext = in_repr->attribute("_gui-text");
248 desc = in_repr->attribute("gui-description");
249 if (desc == NULL)
250 desc = in_repr->attribute("_gui-description");
251 scope_str = in_repr->attribute("scope");
253 /* In this case we just don't have enough information */
254 if (name == NULL || type == NULL) {
255 return NULL;
256 }
258 if (scope_str != NULL) {
259 if (!strcmp(scope_str, "user")) {
260 scope = Parameter::SCOPE_USER;
261 } else if (!strcmp(scope_str, "document")) {
262 scope = Parameter::SCOPE_DOCUMENT;
263 } else if (!strcmp(scope_str, "node")) {
264 scope = Parameter::SCOPE_NODE;
265 }
266 }
268 Parameter * param = NULL;
269 if (!strcmp(type, "boolean")) {
270 param = new ParamBool(name, guitext, desc, scope, in_ext, in_repr);
271 } else if (!strcmp(type, "int")) {
272 param = new ParamInt(name, guitext, desc, scope, in_ext, in_repr);
273 } else if (!strcmp(type, "float")) {
274 param = new ParamFloat(name, guitext, desc, scope, in_ext, in_repr);
275 } else if (!strcmp(type, "string")) {
276 param = new ParamString(name, guitext, desc, scope, in_ext, in_repr);
277 } else if (!strcmp(type, "description")) {
278 param = new ParamDescription(name, guitext, desc, scope, in_ext, in_repr);
279 }
281 /* Note: param could equal NULL */
282 return param;
283 }
285 /** \brief A function to set the \c _value
286 \param in The value to set to
287 \param doc A document that should be used to set the value.
288 \param node The node where the value may be placed
290 This function sets the internal value, but it also sets the value
291 in the preferences structure. To put it in the right place, \c PREF_DIR
292 and \c pref_name() are used.
293 */
294 bool
295 ParamBool::set (bool in, SPDocument * doc, Inkscape::XML::Node * node)
296 {
297 _value = in;
299 gchar * prefname = this->pref_name();
300 prefs_set_int_attribute(PREF_DIR, prefname, _value == true ? 1 : 0);
301 g_free(prefname);
303 return _value;
304 }
306 /** \brief A function to set the \c _value
307 \param in The value to set to
308 \param doc A document that should be used to set the value.
309 \param node The node where the value may be placed
311 This function sets the internal value, but it also sets the value
312 in the preferences structure. To put it in the right place, \c PREF_DIR
313 and \c pref_name() are used.
314 */
315 int
316 ParamInt::set (int in, SPDocument * doc, Inkscape::XML::Node * node)
317 {
318 _value = in;
319 if (_value > _max) _value = _max;
320 if (_value < _min) _value = _min;
322 gchar * prefname = this->pref_name();
323 prefs_set_int_attribute(PREF_DIR, prefname, _value);
324 g_free(prefname);
326 return _value;
327 }
329 /** \brief A function to set the \c _value
330 \param in The value to set to
331 \param doc A document that should be used to set the value.
332 \param node The node where the value may be placed
334 This function sets the internal value, but it also sets the value
335 in the preferences structure. To put it in the right place, \c PREF_DIR
336 and \c pref_name() are used.
337 */
338 float
339 ParamFloat::set (float in, SPDocument * doc, Inkscape::XML::Node * node)
340 {
341 _value = in;
342 if (_value > _max) _value = _max;
343 if (_value < _min) _value = _min;
345 gchar * prefname = this->pref_name();
346 prefs_set_double_attribute(PREF_DIR, prefname, _value);
347 g_free(prefname);
349 return _value;
350 }
352 /** \brief A function to set the \c _value
353 \param in The value to set to
354 \param doc A document that should be used to set the value.
355 \param node The node where the value may be placed
357 This function sets the internal value, but it also sets the value
358 in the preferences structure. To put it in the right place, \c PREF_DIR
359 and \c pref_name() are used.
361 To copy the data into _value the old memory must be free'd first.
362 It is important to note that \c g_free handles \c NULL just fine. Then
363 the passed in value is duplicated using \c g_strdup().
364 */
365 const gchar *
366 ParamString::set (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node)
367 {
368 if (in == NULL) return NULL; /* Can't have NULL string */
370 if (_value != NULL)
371 g_free(_value);
372 _value = g_strdup(in);
374 gchar * prefname = this->pref_name();
375 prefs_set_string_attribute(PREF_DIR, prefname, _value);
376 g_free(prefname);
378 return _value;
379 }
381 /** \brief Wrapper to cast to the object and use it's function. */
382 bool
383 Parameter::get_bool (const SPDocument * doc, const Inkscape::XML::Node * node)
384 {
385 ParamBool * boolpntr;
386 boolpntr = dynamic_cast<ParamBool *>(this);
387 if (boolpntr == NULL)
388 throw Extension::param_wrong_type();
389 return boolpntr->get(doc, node);
390 }
392 /** \brief Wrapper to cast to the object and use it's function. */
393 int
394 Parameter::get_int (const SPDocument * doc, const Inkscape::XML::Node * node)
395 {
396 ParamInt * intpntr;
397 intpntr = dynamic_cast<ParamInt *>(this);
398 if (intpntr == NULL)
399 throw Extension::param_wrong_type();
400 return intpntr->get(doc, node);
401 }
403 /** \brief Wrapper to cast to the object and use it's function. */
404 float
405 Parameter::get_float (const SPDocument * doc, const Inkscape::XML::Node * node)
406 {
407 ParamFloat * floatpntr;
408 floatpntr = dynamic_cast<ParamFloat *>(this);
409 if (floatpntr == NULL)
410 throw Extension::param_wrong_type();
411 return floatpntr->get(doc, node);
412 }
414 /** \brief Wrapper to cast to the object and use it's function. */
415 const gchar *
416 Parameter::get_string (const SPDocument * doc, const Inkscape::XML::Node * node)
417 {
418 ParamString * stringpntr;
419 stringpntr = dynamic_cast<ParamString *>(this);
420 if (stringpntr == NULL)
421 throw Extension::param_wrong_type();
422 return stringpntr->get(doc, node);
423 }
425 /** \brief Wrapper to cast to the object and use it's function. */
426 bool
427 Parameter::set_bool (bool in, SPDocument * doc, Inkscape::XML::Node * node)
428 {
429 ParamBool * boolpntr;
430 boolpntr = dynamic_cast<ParamBool *>(this);
431 if (boolpntr == NULL)
432 throw Extension::param_wrong_type();
433 return boolpntr->set(in, doc, node);
434 }
436 /** \brief Wrapper to cast to the object and use it's function. */
437 int
438 Parameter::set_int (int in, SPDocument * doc, Inkscape::XML::Node * node)
439 {
440 ParamInt * intpntr;
441 intpntr = dynamic_cast<ParamInt *>(this);
442 if (intpntr == NULL)
443 throw Extension::param_wrong_type();
444 return intpntr->set(in, doc, node);
445 }
447 /** \brief Wrapper to cast to the object and use it's function. */
448 float
449 Parameter::set_float (float in, SPDocument * doc, Inkscape::XML::Node * node)
450 {
451 ParamFloat * floatpntr;
452 floatpntr = dynamic_cast<ParamFloat *>(this);
453 if (floatpntr == NULL)
454 throw Extension::param_wrong_type();
455 return floatpntr->set(in, doc, node);
456 }
458 /** \brief Wrapper to cast to the object and use it's function. */
459 const gchar *
460 Parameter::set_string (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node)
461 {
462 ParamString * stringpntr;
463 stringpntr = dynamic_cast<ParamString *>(this);
464 if (stringpntr == NULL)
465 throw Extension::param_wrong_type();
466 return stringpntr->set(in, doc, node);
467 }
469 /** \brief Initialize the object, to do that, copy the data. */
470 ParamString::ParamString (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
471 Parameter(name, guitext, desc, scope, ext), _value(NULL)
472 {
473 const char * defaultval = NULL;
474 if (sp_repr_children(xml) != NULL)
475 defaultval = sp_repr_children(xml)->content();
477 gchar * pref_name = this->pref_name();
478 const gchar * paramval = prefs_get_string_attribute(PREF_DIR, pref_name);
479 g_free(pref_name);
481 if (paramval != NULL)
482 defaultval = paramval;
483 if (defaultval != NULL)
484 _value = g_strdup(defaultval);
486 return;
487 }
489 /** \brief Free the allocated data. */
490 ParamString::~ParamString(void)
491 {
492 g_free(_value);
493 }
495 /** \brief Oop, now that we need a parameter, we need it's name. */
496 Parameter::Parameter (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext) :
497 extension(ext), _name(NULL), _desc(NULL), _scope(scope), _text(NULL)
498 {
499 if (name != NULL)
500 _name = g_strdup(name);
501 if (desc != NULL) {
502 _desc = g_strdup(desc);
503 // printf("Adding description: '%s' on '%s'\n", _desc, _name);
504 }
507 if (guitext != NULL)
508 _text = g_strdup(guitext);
509 else
510 _text = g_strdup(name);
512 return;
513 }
515 /** \brief Just free the allocated name. */
516 Parameter::~Parameter (void)
517 {
518 g_free(_name);
519 g_free(_text);
520 }
522 /** \brief Build the name to write the parameter from the extension's
523 ID and the name of this parameter. */
524 gchar *
525 Parameter::pref_name (void)
526 {
527 return g_strdup_printf("%s.%s", extension->get_id(), _name);
528 }
530 Inkscape::XML::Node *
531 Parameter::find_child (Inkscape::XML::Node * adult)
532 {
533 return sp_repr_lookup_child(adult, "name", _name);
534 }
536 Inkscape::XML::Node *
537 Parameter::new_child (Inkscape::XML::Node * parent)
538 {
539 Inkscape::XML::Node * retval;
540 retval = sp_repr_new("inkscape:extension-param");
541 retval->setAttribute("name", _name);
543 parent->appendChild(retval);
544 return retval;
545 }
547 Inkscape::XML::Node *
548 Parameter::document_param_node (SPDocument * doc)
549 {
550 Inkscape::XML::Node * defs = SP_OBJECT_REPR(SP_DOCUMENT_DEFS(doc));
551 Inkscape::XML::Node * params = NULL;
553 GQuark const name_quark = g_quark_from_string("inkscape:extension-params");
555 for (Inkscape::XML::Node * child = defs->firstChild();
556 child != NULL;
557 child = child->next()) {
558 if ((GQuark)child->code() == name_quark &&
559 !strcmp(child->attribute("extension"), extension->get_id())) {
560 params = child;
561 break;
562 }
563 }
565 if (params == NULL) {
566 params = sp_repr_new("inkscape:extension-param");
567 params->setAttribute("extension", extension->get_id());
568 defs->appendChild(params);
569 }
571 return params;
572 }
574 /** \brief Basically, if there is no widget pass a NULL. */
575 Gtk::Widget *
576 Parameter::get_widget (SPDocument * doc, Inkscape::XML::Node * node)
577 {
578 return NULL;
579 }
581 /** \brief If I'm not sure which it is, just don't return a value. */
582 Glib::ustring *
583 Parameter::string (void)
584 {
585 Glib::ustring * mystring = new Glib::ustring("");
586 return mystring;
587 }
589 /** \brief A class to make an adjustment that uses Extension params */
590 class ParamFloatAdjustment : public Gtk::Adjustment {
591 /** The parameter to adjust */
592 ParamFloat * _pref;
593 SPDocument * _doc;
594 Inkscape::XML::Node * _node;
595 public:
596 /** \brief Make the adjustment using an extension and the string
597 describing the parameter. */
598 ParamFloatAdjustment (ParamFloat * param, SPDocument * doc, Inkscape::XML::Node * node) :
599 Gtk::Adjustment(0.0, param->min(), param->max(), 0.1), _pref(param), _doc(doc), _node(node) {
600 this->set_value(_pref->get(NULL, NULL) /* \todo fix */);
601 this->signal_value_changed().connect(sigc::mem_fun(this, &ParamFloatAdjustment::val_changed));
602 return;
603 };
605 void val_changed (void);
606 }; /* class ParamFloatAdjustment */
608 /** \brief A function to respond to the value_changed signal from the
609 adjustment.
611 This function just grabs the value from the adjustment and writes
612 it to the parameter. Very simple, but yet beautiful.
613 */
614 void
615 ParamFloatAdjustment::val_changed (void)
616 {
617 // std::cout << "Value Changed to: " << this->get_value() << std::endl;
618 _pref->set(this->get_value(), _doc, _node);
619 return;
620 }
622 /** \brief A class to make an adjustment that uses Extension params */
623 class ParamIntAdjustment : public Gtk::Adjustment {
624 /** The parameter to adjust */
625 ParamInt * _pref;
626 SPDocument * _doc;
627 Inkscape::XML::Node * _node;
628 public:
629 /** \brief Make the adjustment using an extension and the string
630 describing the parameter. */
631 ParamIntAdjustment (ParamInt * param, SPDocument * doc, Inkscape::XML::Node * node) :
632 Gtk::Adjustment(0.0, param->min(), param->max(), 1.0), _pref(param), _doc(doc), _node(node) {
633 this->set_value(_pref->get(NULL, NULL) /* \todo fix */);
634 this->signal_value_changed().connect(sigc::mem_fun(this, &ParamIntAdjustment::val_changed));
635 return;
636 };
638 void val_changed (void);
639 }; /* class ParamIntAdjustment */
641 /** \brief A function to respond to the value_changed signal from the
642 adjustment.
644 This function just grabs the value from the adjustment and writes
645 it to the parameter. Very simple, but yet beautiful.
646 */
647 void
648 ParamIntAdjustment::val_changed (void)
649 {
650 // std::cout << "Value Changed to: " << this->get_value() << std::endl;
651 _pref->set((int)this->get_value(), _doc, _node);
652 return;
653 }
655 /**
656 \brief Creates a Float Adjustment for a float parameter
658 Builds a hbox with a label and a float adjustment in it.
659 */
660 Gtk::Widget *
661 ParamFloat::get_widget (SPDocument * doc, Inkscape::XML::Node * node)
662 {
663 Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox());
665 Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_LEFT));
666 label->show();
667 hbox->pack_start(*label, true, true);
669 ParamFloatAdjustment * fadjust = Gtk::manage(new ParamFloatAdjustment(this, doc, node));
670 Gtk::SpinButton * spin = Gtk::manage(new Gtk::SpinButton(*fadjust, 0.1, 1));
671 spin->show();
672 hbox->pack_start(*spin, false, false);
674 hbox->show();
676 return dynamic_cast<Gtk::Widget *>(hbox);
677 }
679 /**
680 \brief Creates a Int Adjustment for a int parameter
682 Builds a hbox with a label and a int adjustment in it.
683 */
684 Gtk::Widget *
685 ParamInt::get_widget (SPDocument * doc, Inkscape::XML::Node * node)
686 {
687 Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox());
689 Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_LEFT));
690 label->show();
691 hbox->pack_start(*label, true, true);
693 ParamIntAdjustment * fadjust = Gtk::manage(new ParamIntAdjustment(this, doc, node));
694 Gtk::SpinButton * spin = Gtk::manage(new Gtk::SpinButton(*fadjust, 1.0, 0));
695 spin->show();
696 hbox->pack_start(*spin, false, false);
698 hbox->show();
700 return dynamic_cast<Gtk::Widget *>(hbox);
701 }
703 /** \brief A check button which is Param aware. It works with the
704 parameter to change it's value as the check button changes
705 value. */
706 class ParamBoolCheckButton : public Gtk::CheckButton {
707 private:
708 /** \brief Param to change */
709 ParamBool * _pref;
710 SPDocument * _doc;
711 Inkscape::XML::Node * _node;
712 public:
713 /** \brief Initialize the check button
714 \param param Which parameter to adjust on changing the check button
716 This function sets the value of the checkbox to be that of the
717 parameter, and then sets up a callback to \c on_toggle.
718 */
719 ParamBoolCheckButton (ParamBool * param, SPDocument * doc, Inkscape::XML::Node * node) :
720 Gtk::CheckButton(), _pref(param), _doc(doc), _node(node) {
721 this->set_active(_pref->get(NULL, NULL) /**\todo fix */);
722 this->signal_toggled().connect(sigc::mem_fun(this, &ParamBoolCheckButton::on_toggle));
723 return;
724 }
725 void on_toggle (void);
726 };
728 /**
729 \brief A function to respond to the check box changing
731 Adjusts the value of the preference to match that in the check box.
732 */
733 void
734 ParamBoolCheckButton::on_toggle (void)
735 {
736 _pref->set(this->get_active(), NULL /**\todo fix this */, NULL);
737 return;
738 }
740 /**
741 \brief Creates a bool check button for a bool parameter
743 Builds a hbox with a label and a check button in it.
744 */
745 Gtk::Widget *
746 ParamBool::get_widget (SPDocument * doc, Inkscape::XML::Node * node)
747 {
748 Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox());
750 Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_LEFT));
751 label->show();
752 hbox->pack_start(*label, true, true);
754 ParamBoolCheckButton * checkbox = new ParamBoolCheckButton(this, doc, node);
755 checkbox->show();
756 hbox->pack_start(*checkbox, false, false);
758 hbox->show();
760 return dynamic_cast<Gtk::Widget *>(hbox);
761 }
763 /** \brief A special category of Gtk::Entry to handle string parameteres */
764 class ParamStringEntry : public Gtk::Entry {
765 private:
766 ParamString * _pref;
767 SPDocument * _doc;
768 Inkscape::XML::Node * _node;
769 public:
770 /** \brief Build a string preference for the given parameter
771 \param pref Where to get the string from, and where to put it
772 when it changes.
773 */
774 ParamStringEntry (ParamString * pref, SPDocument * doc, Inkscape::XML::Node * node) :
775 Gtk::Entry(), _pref(pref), _doc(doc), _node(node) {
776 if (_pref->get(NULL, NULL) != NULL)
777 this->set_text(Glib::ustring(_pref->get(NULL, NULL)));
778 this->signal_changed().connect(sigc::mem_fun(this, &ParamStringEntry::changed_text));
779 };
780 void changed_text (void);
781 };
783 /** \brief Respond to the text box changing
785 This function responds to the box changing by grabbing the value
786 from the text box and putting it in the parameter.
787 */
788 void
789 ParamStringEntry::changed_text (void)
790 {
791 Glib::ustring data = this->get_text();
792 _pref->set(data.c_str(), _doc, _node);
793 return;
794 }
796 /**
797 \brief Creates a text box for the string parameter
799 Builds a hbox with a label and a text box in it.
800 */
801 Gtk::Widget *
802 ParamString::get_widget (SPDocument * doc, Inkscape::XML::Node * node)
803 {
804 Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox());
806 Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_LEFT));
807 label->show();
808 hbox->pack_start(*label, true, true);
810 ParamStringEntry * textbox = new ParamStringEntry(this, doc, node);
811 textbox->show();
812 hbox->pack_start(*textbox, false, false);
814 hbox->show();
816 return dynamic_cast<Gtk::Widget *>(hbox);
817 }
819 /** \brief Return 'true' or 'false' */
820 Glib::ustring *
821 ParamBool::string (void)
822 {
823 Glib::ustring * mystring;
825 if (_value)
826 mystring = new Glib::ustring("true");
827 else
828 mystring = new Glib::ustring("false");
830 return mystring;
831 }
833 /** \brief Return the value as a string */
834 Glib::ustring *
835 ParamInt::string (void)
836 {
837 char startstring[32];
838 sprintf(startstring, "%d", _value);
839 Glib::ustring * mystring = new Glib::ustring(startstring);
840 return mystring;
841 }
843 /** \brief Return the value as a string */
844 Glib::ustring *
845 ParamFloat::string (void)
846 {
847 char startstring[G_ASCII_DTOSTR_BUF_SIZE];
848 g_ascii_dtostr(startstring, G_ASCII_DTOSTR_BUF_SIZE, _value);
849 Glib::ustring * mystring = new Glib::ustring(startstring);
850 return mystring;
851 }
853 /** \brief Return the value as a string */
854 Glib::ustring *
855 ParamString::string (void)
856 {
857 Glib::ustring * mystring = new Glib::ustring("");
858 *mystring += "\"";
859 *mystring += _value;
860 *mystring += "\"";
861 return mystring;
862 }
864 /** \brief Return the value as a string */
865 Glib::ustring *
866 ParamDescription::string (void)
867 {
868 Glib::ustring * mystring = new Glib::ustring("");
869 *mystring += "\"";
870 *mystring += _value;
871 *mystring += "\"";
872 return mystring;
873 }
875 /** \brief Create a label for the description */
876 Gtk::Widget *
877 ParamDescription::get_widget (SPDocument * doc, Inkscape::XML::Node * node)
878 {
879 Gtk::Label * label = Gtk::manage(new Gtk::Label(_value));
880 label->set_line_wrap();
881 label->show();
883 Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox());
884 hbox->pack_start(*label, true, true, 5);
885 hbox->show();
887 return hbox;
888 }
890 /** \brief Initialize the object, to do that, copy the data. */
891 ParamDescription::ParamDescription (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
892 Parameter(name, guitext, desc, scope, ext), _value(NULL)
893 {
894 // printf("Building Description\n");
895 const char * defaultval = NULL;
896 if (sp_repr_children(xml) != NULL)
897 defaultval = sp_repr_children(xml)->content();
899 if (defaultval != NULL)
900 _value = g_strdup(defaultval);
902 return;
903 }
906 } /* namespace Extension */
907 } /* namespace Inkscape */
909 /*
910 Local Variables:
911 mode:c++
912 c-file-style:"stroustrup"
913 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
914 indent-tabs-mode:nil
915 fill-column:99
916 End:
917 */
918 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :