1 /** \file
2 * Parameters for extensions.
3 */
5 /*
6 * Author:
7 * Ted Gould <ted@gould.cx>
8 *
9 * Copyright (C) 2006 Johan Engelen <johan@shouraizou.nl>
10 * Copyright (C) 2005-2006 Author
11 *
12 * Released under GNU GPL, read the file 'COPYING' for more information
13 */
15 #ifdef HAVE_CONFIG_H
16 # include "config.h"
17 #endif
20 #include <gtkmm/adjustment.h>
21 #include <gtkmm/box.h>
22 #include <gtkmm/spinbutton.h>
24 #include <glibmm/i18n.h>
26 #include <xml/node.h>
28 #include "extension.h"
29 #include "prefs-utils.h"
30 #include "document-private.h"
31 #include "sp-object.h"
33 #include "parameter.h"
34 #include "paramnotebook.h"
35 #include "paramenum.h"
36 #include "paramradiobutton.h"
38 /** \brief The root directory in the preferences database for extension
39 related parameters. */
40 #define PREF_DIR "extensions"
42 namespace Inkscape {
43 namespace Extension {
45 /** \brief A description parameter */
46 class ParamDescription : public Parameter {
47 private:
48 /** \brief Internal value. */
49 gchar * _value;
50 public:
51 ParamDescription(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml);
52 Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node);
53 };
55 /** \brief A boolean parameter */
56 class ParamBool : public Parameter {
57 private:
58 /** \brief Internal value. */
59 bool _value;
60 public:
61 ParamBool(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml);
62 /** \brief Returns \c _value */
63 bool get (const SPDocument * doc, const Inkscape::XML::Node * node) { return _value; }
64 bool set (bool in, SPDocument * doc, Inkscape::XML::Node * node);
65 Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node);
66 Glib::ustring * string (void);
67 };
69 /** \brief Use the superclass' allocator and set the \c _value */
70 ParamBool::ParamBool (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
71 Parameter(name, guitext, desc, scope, ext), _value(false)
72 {
73 const char * defaultval = NULL;
74 if (sp_repr_children(xml) != NULL)
75 defaultval = sp_repr_children(xml)->content();
77 if (defaultval != NULL && (!strcmp(defaultval, "TRUE") || !strcmp(defaultval, "true") || !strcmp(defaultval, "1"))) {
78 _value = true;
79 } else {
80 _value = false;
81 }
83 gchar * pref_name = this->pref_name();
84 _value = (bool)prefs_get_int_attribute(PREF_DIR, pref_name, _value);
85 g_free(pref_name);
87 return;
88 }
90 class ParamInt : public Parameter {
91 private:
92 /** \brief Internal value. */
93 int _value;
94 int _min;
95 int _max;
96 public:
97 ParamInt (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml);
98 /** \brief Returns \c _value */
99 int get (const SPDocument * doc, const Inkscape::XML::Node * node) { return _value; }
100 int set (int in, SPDocument * doc, Inkscape::XML::Node * node);
101 int max (void) { return _max; }
102 int min (void) { return _min; }
103 Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node);
104 Glib::ustring * string (void);
105 };
107 /** \brief Use the superclass' allocator and set the \c _value */
108 ParamInt::ParamInt (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
109 Parameter(name, guitext, desc, scope, ext), _value(0), _min(0), _max(10)
110 {
111 const char * defaultval = NULL;
112 if (sp_repr_children(xml) != NULL)
113 defaultval = sp_repr_children(xml)->content();
114 if (defaultval != NULL) {
115 _value = atoi(defaultval);
116 }
118 const char * maxval = xml->attribute("max");
119 if (maxval != NULL)
120 _max = atoi(maxval);
122 const char * minval = xml->attribute("min");
123 if (minval != NULL)
124 _min = atoi(minval);
126 /* We're handling this by just killing both values */
127 if (_max < _min) {
128 _max = 10;
129 _min = 0;
130 }
132 gchar * pref_name = this->pref_name();
133 _value = prefs_get_int_attribute(PREF_DIR, pref_name, _value);
134 g_free(pref_name);
136 // std::cout << "New Int:: value: " << _value << " max: " << _max << " min: " << _min << std::endl;
138 if (_value > _max) _value = _max;
139 if (_value < _min) _value = _min;
141 return;
142 }
144 class ParamFloat : public Parameter {
145 private:
146 /** \brief Internal value. */
147 float _value;
148 float _min;
149 float _max;
150 public:
151 ParamFloat (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml);
152 /** \brief Returns \c _value */
153 float get (const SPDocument * doc, const Inkscape::XML::Node * node) { return _value; }
154 float set (float in, SPDocument * doc, Inkscape::XML::Node * node);
155 float max (void) { return _max; }
156 float min (void) { return _min; }
157 Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node);
158 Glib::ustring * string (void);
159 };
161 /** \brief Use the superclass' allocator and set the \c _value */
162 ParamFloat::ParamFloat (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
163 Parameter(name, guitext, desc, scope, ext), _value(0.0), _min(0.0), _max(10.0)
164 {
165 const char * defaultval = NULL;
166 if (sp_repr_children(xml) != NULL)
167 defaultval = sp_repr_children(xml)->content();
168 if (defaultval != NULL) {
169 _value = atof(defaultval);
170 }
172 const char * maxval = xml->attribute("max");
173 if (maxval != NULL)
174 _max = atof(maxval);
176 const char * minval = xml->attribute("min");
177 if (minval != NULL)
178 _min = atof(minval);
180 /* We're handling this by just killing both values */
181 if (_max < _min) {
182 _max = 10.0;
183 _min = 0.0;
184 }
186 gchar * pref_name = this->pref_name();
187 _value = prefs_get_double_attribute(PREF_DIR, pref_name, _value);
188 g_free(pref_name);
190 // std::cout << "New Float:: value: " << _value << " max: " << _max << " min: " << _min << std::endl;
192 if (_value > _max) _value = _max;
193 if (_value < _min) _value = _min;
195 return;
196 }
198 class ParamString : public Parameter {
199 private:
200 /** \brief Internal value. This should point to a string that has
201 been allocated in memory. And should be free'd. */
202 gchar * _value;
203 public:
204 ParamString(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml);
205 ~ParamString(void);
206 /** \brief Returns \c _value, with a \i const to protect it. */
207 const gchar * get (const SPDocument * doc, const Inkscape::XML::Node * node) { return _value; }
208 const gchar * set (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node);
209 Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node);
210 Glib::ustring * string (void);
211 };
213 class ParamEnum : public Parameter {
214 private:
215 class Choice {
216 public:
217 gchar * _gui_name;
218 gchar * _value;
219 Choice(gchar * gui_name, gchar * value) : _gui_name(NULL), _value(NULL) {
220 if (gui_name != NULL)
221 _gui_name = g_strdup(_(gui_name));
222 if (value != NULL)
223 _value = g_strdup(value);
224 return;
225 };
226 ~Choice (void) {
227 g_free(_gui_name);
228 g_free(_value);
229 };
230 }; /* class Choice */
231 /** \brief Internal value. This should point to a string that has
232 been allocated in memory. And should be free'd. */
233 Choice * _current_choice;
234 typedef std::list<Choice *> choice_list_t;
235 choice_list_t _choice_list;
236 public:
237 ParamEnum(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml);
238 ~ParamEnum(void);
239 /** \brief Returns \c _value, with a \i const to protect it. */
240 const gchar * get (const SPDocument * doc, const Inkscape::XML::Node * node) { return _current_choice != NULL ? _current_choice->_value : NULL; }
241 const gchar * set (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node);
242 Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node);
243 Glib::ustring * string (void);
244 }; /* class ParamEnum */
247 /**
248 \return None
249 \brief This function creates a parameter that can be used later. This
250 is typically done in the creation of the extension and defined
251 in the XML file describing the extension (it's private so people
252 have to use the system) :)
253 \param in_repr The XML describing the parameter
255 This function first grabs all of the data out of the Repr and puts
256 it into local variables. Actually, these are just pointers, and the
257 data is not duplicated so we need to be careful with it. If there
258 isn't a name or a type in the XML, then no parameter is created as
259 the function just returns.
261 From this point on, we're pretty committed as we've allocated an
262 object and we're starting to fill it. The name is set first, and
263 is created with a strdup to actually allocate memory for it. Then
264 there is a case statement (roughly because strcmp requires 'ifs')
265 based on what type of parameter this is. Depending which type it
266 is, the value is interpreted differently, but they are relatively
267 straight forward. In all cases the value is set to the default
268 value from the XML and the type is set to the interpreted type.
269 */
270 Parameter *
271 Parameter::make (Inkscape::XML::Node * in_repr, Inkscape::Extension::Extension * in_ext)
272 {
273 const char * name;
274 const char * type;
275 const char * guitext;
276 const char * desc;
277 const char * scope_str;
278 Parameter::_scope_t scope = Parameter::SCOPE_USER;
280 name = in_repr->attribute("name");
281 type = in_repr->attribute("type");
282 guitext = in_repr->attribute("gui-text");
283 if (guitext == NULL)
284 guitext = in_repr->attribute("_gui-text");
285 desc = in_repr->attribute("gui-description");
286 if (desc == NULL)
287 desc = in_repr->attribute("_gui-description");
288 scope_str = in_repr->attribute("scope");
290 /* In this case we just don't have enough information */
291 if (name == NULL || type == NULL) {
292 return NULL;
293 }
295 if (scope_str != NULL) {
296 if (!strcmp(scope_str, "user")) {
297 scope = Parameter::SCOPE_USER;
298 } else if (!strcmp(scope_str, "document")) {
299 scope = Parameter::SCOPE_DOCUMENT;
300 } else if (!strcmp(scope_str, "node")) {
301 scope = Parameter::SCOPE_NODE;
302 }
303 }
305 Parameter * param = NULL;
306 if (!strcmp(type, "boolean")) {
307 param = new ParamBool(name, guitext, desc, scope, in_ext, in_repr);
308 } else if (!strcmp(type, "int")) {
309 param = new ParamInt(name, guitext, desc, scope, in_ext, in_repr);
310 } else if (!strcmp(type, "float")) {
311 param = new ParamFloat(name, guitext, desc, scope, in_ext, in_repr);
312 } else if (!strcmp(type, "string")) {
313 param = new ParamString(name, guitext, desc, scope, in_ext, in_repr);
314 } else if (!strcmp(type, "description")) {
315 param = new ParamDescription(name, guitext, desc, scope, in_ext, in_repr);
316 } else if (!strcmp(type, "enum")) {
317 param = new ParamComboBox(name, guitext, desc, scope, in_ext, in_repr);
318 } else if (!strcmp(type, "notebook")) {
319 param = new ParamNotebook(name, guitext, desc, scope, in_ext, in_repr);
320 } else if (!strcmp(type, "optiongroup")) {
321 param = new ParamRadioButton(name, guitext, desc, scope, in_ext, in_repr);
322 }
324 /* Note: param could equal NULL */
325 return param;
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 bool
338 ParamBool::set (bool in, SPDocument * doc, Inkscape::XML::Node * node)
339 {
340 _value = in;
342 gchar * prefname = this->pref_name();
343 prefs_set_int_attribute(PREF_DIR, prefname, _value == true ? 1 : 0);
344 g_free(prefname);
346 return _value;
347 }
349 /** \brief A function to set the \c _value
350 \param in The value to set to
351 \param doc A document that should be used to set the value.
352 \param node The node where the value may be placed
354 This function sets the internal value, but it also sets the value
355 in the preferences structure. To put it in the right place, \c PREF_DIR
356 and \c pref_name() are used.
357 */
358 int
359 ParamInt::set (int in, SPDocument * doc, Inkscape::XML::Node * node)
360 {
361 _value = in;
362 if (_value > _max) _value = _max;
363 if (_value < _min) _value = _min;
365 gchar * prefname = this->pref_name();
366 prefs_set_int_attribute(PREF_DIR, prefname, _value);
367 g_free(prefname);
369 return _value;
370 }
372 /** \brief A function to set the \c _value
373 \param in The value to set to
374 \param doc A document that should be used to set the value.
375 \param node The node where the value may be placed
377 This function sets the internal value, but it also sets the value
378 in the preferences structure. To put it in the right place, \c PREF_DIR
379 and \c pref_name() are used.
380 */
381 float
382 ParamFloat::set (float in, SPDocument * doc, Inkscape::XML::Node * node)
383 {
384 _value = in;
385 if (_value > _max) _value = _max;
386 if (_value < _min) _value = _min;
388 gchar * prefname = this->pref_name();
389 prefs_set_double_attribute(PREF_DIR, prefname, _value);
390 g_free(prefname);
392 return _value;
393 }
395 /** \brief A function to set the \c _value
396 \param in The value to set to
397 \param doc A document that should be used to set the value.
398 \param node The node where the value may be placed
400 This function sets the internal value, but it also sets the value
401 in the preferences structure. To put it in the right place, \c PREF_DIR
402 and \c pref_name() are used.
404 To copy the data into _value the old memory must be free'd first.
405 It is important to note that \c g_free handles \c NULL just fine. Then
406 the passed in value is duplicated using \c g_strdup().
407 */
408 const gchar *
409 ParamString::set (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node)
410 {
411 if (in == NULL) return NULL; /* Can't have NULL string */
413 if (_value != NULL)
414 g_free(_value);
415 _value = g_strdup(in);
417 gchar * prefname = this->pref_name();
418 prefs_set_string_attribute(PREF_DIR, prefname, _value);
419 g_free(prefname);
421 return _value;
422 }
424 /** \brief Wrapper to cast to the object and use it's function. */
425 bool
426 Parameter::get_bool (const SPDocument * doc, const 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->get(doc, node);
433 }
435 /** \brief Wrapper to cast to the object and use it's function. */
436 int
437 Parameter::get_int (const SPDocument * doc, const 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->get(doc, node);
444 }
446 /** \brief Wrapper to cast to the object and use it's function. */
447 float
448 Parameter::get_float (const SPDocument * doc, const 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->get(doc, node);
455 }
457 /** \brief Wrapper to cast to the object and use it's function. */
458 const gchar *
459 Parameter::get_string (const SPDocument * doc, const 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->get(doc, node);
466 }
468 /** \brief Wrapper to cast to the object and use it's function. */
469 bool
470 Parameter::set_bool (bool in, SPDocument * doc, Inkscape::XML::Node * node)
471 {
472 ParamBool * boolpntr;
473 boolpntr = dynamic_cast<ParamBool *>(this);
474 if (boolpntr == NULL)
475 throw Extension::param_wrong_type();
476 return boolpntr->set(in, doc, node);
477 }
479 /** \brief Wrapper to cast to the object and use it's function. */
480 int
481 Parameter::set_int (int in, SPDocument * doc, Inkscape::XML::Node * node)
482 {
483 ParamInt * intpntr;
484 intpntr = dynamic_cast<ParamInt *>(this);
485 if (intpntr == NULL)
486 throw Extension::param_wrong_type();
487 return intpntr->set(in, doc, node);
488 }
490 /** \brief Wrapper to cast to the object and use it's function. */
491 float
492 Parameter::set_float (float in, SPDocument * doc, Inkscape::XML::Node * node)
493 {
494 ParamFloat * floatpntr;
495 floatpntr = dynamic_cast<ParamFloat *>(this);
496 if (floatpntr == NULL)
497 throw Extension::param_wrong_type();
498 return floatpntr->set(in, doc, node);
499 }
501 /** \brief Wrapper to cast to the object and use it's function. */
502 const gchar *
503 Parameter::set_string (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node)
504 {
505 ParamString * stringpntr;
506 stringpntr = dynamic_cast<ParamString *>(this);
507 if (stringpntr == NULL)
508 throw Extension::param_wrong_type();
509 return stringpntr->set(in, doc, node);
510 }
512 /** \brief Initialize the object, to do that, copy the data. */
513 ParamString::ParamString (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
514 Parameter(name, guitext, desc, scope, ext), _value(NULL)
515 {
516 const char * defaultval = NULL;
517 if (sp_repr_children(xml) != NULL)
518 defaultval = sp_repr_children(xml)->content();
520 gchar * pref_name = this->pref_name();
521 const gchar * paramval = prefs_get_string_attribute(PREF_DIR, pref_name);
522 g_free(pref_name);
524 if (paramval != NULL)
525 defaultval = paramval;
526 if (defaultval != NULL)
527 _value = g_strdup(defaultval);
529 return;
530 }
532 /** \brief Free the allocated data. */
533 ParamString::~ParamString(void)
534 {
535 g_free(_value);
536 }
538 /** \brief Oop, now that we need a parameter, we need it's name. */
539 Parameter::Parameter (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext) :
540 extension(ext), _name(NULL), _desc(NULL), _scope(scope), _text(NULL)
541 {
542 if (name != NULL)
543 _name = g_strdup(name);
544 if (desc != NULL) {
545 _desc = g_strdup(desc);
546 // printf("Adding description: '%s' on '%s'\n", _desc, _name);
547 }
550 if (guitext != NULL)
551 _text = g_strdup(guitext);
552 else
553 _text = g_strdup(name);
555 return;
556 }
558 /** \brief Just free the allocated name. */
559 Parameter::~Parameter (void)
560 {
561 g_free(_name);
562 g_free(_text);
563 }
565 /** \brief Build the name to write the parameter from the extension's
566 ID and the name of this parameter. */
567 gchar *
568 Parameter::pref_name (void)
569 {
570 return g_strdup_printf("%s.%s", extension->get_id(), _name);
571 }
573 Inkscape::XML::Node *
574 Parameter::find_child (Inkscape::XML::Node * adult)
575 {
576 return sp_repr_lookup_child(adult, "name", _name);
577 }
579 Inkscape::XML::Node *
580 Parameter::new_child (Inkscape::XML::Node * parent)
581 {
582 Inkscape::XML::Node * retval;
583 retval = parent->document()->createElement("inkscape:extension-param");
584 retval->setAttribute("name", _name);
586 parent->appendChild(retval);
587 return retval;
588 }
590 Inkscape::XML::Node *
591 Parameter::document_param_node (SPDocument * doc)
592 {
593 Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
594 Inkscape::XML::Node * defs = SP_OBJECT_REPR(SP_DOCUMENT_DEFS(doc));
595 Inkscape::XML::Node * params = NULL;
597 GQuark const name_quark = g_quark_from_string("inkscape:extension-params");
599 for (Inkscape::XML::Node * child = defs->firstChild();
600 child != NULL;
601 child = child->next()) {
602 if ((GQuark)child->code() == name_quark &&
603 !strcmp(child->attribute("extension"), extension->get_id())) {
604 params = child;
605 break;
606 }
607 }
609 if (params == NULL) {
610 params = xml_doc->createElement("inkscape:extension-param");
611 params->setAttribute("extension", extension->get_id());
612 defs->appendChild(params);
613 }
615 return params;
616 }
618 /** \brief Basically, if there is no widget pass a NULL. */
619 Gtk::Widget *
620 Parameter::get_widget (SPDocument * doc, Inkscape::XML::Node * node)
621 {
622 return NULL;
623 }
625 /** \brief If I'm not sure which it is, just don't return a value. */
626 Glib::ustring *
627 Parameter::string (void)
628 {
629 Glib::ustring * mystring = new Glib::ustring("");
630 return mystring;
631 }
633 /** \brief A class to make an adjustment that uses Extension params */
634 class ParamFloatAdjustment : public Gtk::Adjustment {
635 /** The parameter to adjust */
636 ParamFloat * _pref;
637 SPDocument * _doc;
638 Inkscape::XML::Node * _node;
639 public:
640 /** \brief Make the adjustment using an extension and the string
641 describing the parameter. */
642 ParamFloatAdjustment (ParamFloat * param, SPDocument * doc, Inkscape::XML::Node * node) :
643 Gtk::Adjustment(0.0, param->min(), param->max(), 0.1), _pref(param), _doc(doc), _node(node) {
644 this->set_value(_pref->get(NULL, NULL) /* \todo fix */);
645 this->signal_value_changed().connect(sigc::mem_fun(this, &ParamFloatAdjustment::val_changed));
646 return;
647 };
649 void val_changed (void);
650 }; /* class ParamFloatAdjustment */
652 /** \brief A function to respond to the value_changed signal from the
653 adjustment.
655 This function just grabs the value from the adjustment and writes
656 it to the parameter. Very simple, but yet beautiful.
657 */
658 void
659 ParamFloatAdjustment::val_changed (void)
660 {
661 // std::cout << "Value Changed to: " << this->get_value() << std::endl;
662 _pref->set(this->get_value(), _doc, _node);
663 return;
664 }
666 /** \brief A class to make an adjustment that uses Extension params */
667 class ParamIntAdjustment : public Gtk::Adjustment {
668 /** The parameter to adjust */
669 ParamInt * _pref;
670 SPDocument * _doc;
671 Inkscape::XML::Node * _node;
672 public:
673 /** \brief Make the adjustment using an extension and the string
674 describing the parameter. */
675 ParamIntAdjustment (ParamInt * param, SPDocument * doc, Inkscape::XML::Node * node) :
676 Gtk::Adjustment(0.0, param->min(), param->max(), 1.0), _pref(param), _doc(doc), _node(node) {
677 this->set_value(_pref->get(NULL, NULL) /* \todo fix */);
678 this->signal_value_changed().connect(sigc::mem_fun(this, &ParamIntAdjustment::val_changed));
679 return;
680 };
682 void val_changed (void);
683 }; /* class ParamIntAdjustment */
685 /** \brief A function to respond to the value_changed signal from the
686 adjustment.
688 This function just grabs the value from the adjustment and writes
689 it to the parameter. Very simple, but yet beautiful.
690 */
691 void
692 ParamIntAdjustment::val_changed (void)
693 {
694 // std::cout << "Value Changed to: " << this->get_value() << std::endl;
695 _pref->set((int)this->get_value(), _doc, _node);
696 return;
697 }
699 /**
700 \brief Creates a Float Adjustment for a float parameter
702 Builds a hbox with a label and a float adjustment in it.
703 */
704 Gtk::Widget *
705 ParamFloat::get_widget (SPDocument * doc, Inkscape::XML::Node * node)
706 {
707 Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4));
709 Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_LEFT));
710 label->show();
711 hbox->pack_start(*label, true, true);
713 ParamFloatAdjustment * fadjust = Gtk::manage(new ParamFloatAdjustment(this, doc, node));
714 Gtk::SpinButton * spin = Gtk::manage(new Gtk::SpinButton(*fadjust, 0.1, 1));
715 spin->show();
716 hbox->pack_start(*spin, false, false);
718 hbox->show();
720 return dynamic_cast<Gtk::Widget *>(hbox);
721 }
723 /**
724 \brief Creates a Int Adjustment for a int parameter
726 Builds a hbox with a label and a int adjustment in it.
727 */
728 Gtk::Widget *
729 ParamInt::get_widget (SPDocument * doc, Inkscape::XML::Node * node)
730 {
731 Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4));
733 Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_LEFT));
734 label->show();
735 hbox->pack_start(*label, true, true);
737 ParamIntAdjustment * fadjust = Gtk::manage(new ParamIntAdjustment(this, doc, node));
738 Gtk::SpinButton * spin = Gtk::manage(new Gtk::SpinButton(*fadjust, 1.0, 0));
739 spin->show();
740 hbox->pack_start(*spin, false, false);
742 hbox->show();
744 return dynamic_cast<Gtk::Widget *>(hbox);
745 }
747 /** \brief A check button which is Param aware. It works with the
748 parameter to change it's value as the check button changes
749 value. */
750 class ParamBoolCheckButton : public Gtk::CheckButton {
751 private:
752 /** \brief Param to change */
753 ParamBool * _pref;
754 SPDocument * _doc;
755 Inkscape::XML::Node * _node;
756 public:
757 /** \brief Initialize the check button
758 \param param Which parameter to adjust on changing the check button
760 This function sets the value of the checkbox to be that of the
761 parameter, and then sets up a callback to \c on_toggle.
762 */
763 ParamBoolCheckButton (ParamBool * param, SPDocument * doc, Inkscape::XML::Node * node) :
764 Gtk::CheckButton(), _pref(param), _doc(doc), _node(node) {
765 this->set_active(_pref->get(NULL, NULL) /**\todo fix */);
766 this->signal_toggled().connect(sigc::mem_fun(this, &ParamBoolCheckButton::on_toggle));
767 return;
768 }
769 void on_toggle (void);
770 };
772 /**
773 \brief A function to respond to the check box changing
775 Adjusts the value of the preference to match that in the check box.
776 */
777 void
778 ParamBoolCheckButton::on_toggle (void)
779 {
780 _pref->set(this->get_active(), NULL /**\todo fix this */, NULL);
781 return;
782 }
784 /**
785 \brief Creates a bool check button for a bool parameter
787 Builds a hbox with a label and a check button in it.
788 */
789 Gtk::Widget *
790 ParamBool::get_widget (SPDocument * doc, Inkscape::XML::Node * node)
791 {
792 Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4));
794 Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_LEFT));
795 label->show();
796 hbox->pack_start(*label, true, true);
798 ParamBoolCheckButton * checkbox = new ParamBoolCheckButton(this, doc, node);
799 checkbox->show();
800 hbox->pack_start(*checkbox, false, false);
802 hbox->show();
804 return dynamic_cast<Gtk::Widget *>(hbox);
805 }
807 /** \brief A special category of Gtk::Entry to handle string parameteres */
808 class ParamStringEntry : public Gtk::Entry {
809 private:
810 ParamString * _pref;
811 SPDocument * _doc;
812 Inkscape::XML::Node * _node;
813 public:
814 /** \brief Build a string preference for the given parameter
815 \param pref Where to get the string from, and where to put it
816 when it changes.
817 */
818 ParamStringEntry (ParamString * pref, SPDocument * doc, Inkscape::XML::Node * node) :
819 Gtk::Entry(), _pref(pref), _doc(doc), _node(node) {
820 if (_pref->get(NULL, NULL) != NULL)
821 this->set_text(Glib::ustring(_pref->get(NULL, NULL)));
822 this->signal_changed().connect(sigc::mem_fun(this, &ParamStringEntry::changed_text));
823 };
824 void changed_text (void);
825 };
827 /** \brief Respond to the text box changing
829 This function responds to the box changing by grabbing the value
830 from the text box and putting it in the parameter.
831 */
832 void
833 ParamStringEntry::changed_text (void)
834 {
835 Glib::ustring data = this->get_text();
836 _pref->set(data.c_str(), _doc, _node);
837 return;
838 }
840 /**
841 \brief Creates a text box for the string parameter
843 Builds a hbox with a label and a text box in it.
844 */
845 Gtk::Widget *
846 ParamString::get_widget (SPDocument * doc, Inkscape::XML::Node * node)
847 {
848 Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4));
850 Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_LEFT));
851 label->show();
852 hbox->pack_start(*label, false, false);
854 ParamStringEntry * textbox = new ParamStringEntry(this, doc, node);
855 textbox->show();
856 hbox->pack_start(*textbox, true, true);
858 hbox->show();
860 return dynamic_cast<Gtk::Widget *>(hbox);
861 }
863 /** \brief Return 'true' or 'false' */
864 Glib::ustring *
865 ParamBool::string (void)
866 {
867 Glib::ustring * mystring;
869 if (_value)
870 mystring = new Glib::ustring("true");
871 else
872 mystring = new Glib::ustring("false");
874 return mystring;
875 }
877 /** \brief Return the value as a string */
878 Glib::ustring *
879 ParamInt::string (void)
880 {
881 char startstring[32];
882 sprintf(startstring, "%d", _value);
883 Glib::ustring * mystring = new Glib::ustring(startstring);
884 return mystring;
885 }
887 /** \brief Return the value as a string */
888 Glib::ustring *
889 ParamFloat::string (void)
890 {
891 char startstring[G_ASCII_DTOSTR_BUF_SIZE];
892 g_ascii_dtostr(startstring, G_ASCII_DTOSTR_BUF_SIZE, _value);
893 Glib::ustring * mystring = new Glib::ustring(startstring);
894 return mystring;
895 }
897 /** \brief Return the value as a string */
898 Glib::ustring *
899 ParamString::string (void)
900 {
901 Glib::ustring * mystring = new Glib::ustring("");
902 *mystring += "\"";
903 *mystring += _value;
904 *mystring += "\"";
905 return mystring;
906 }
908 /** \brief Create a label for the description */
909 Gtk::Widget *
910 ParamDescription::get_widget (SPDocument * doc, Inkscape::XML::Node * node)
911 {
912 Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_value)));
913 label->set_line_wrap();
914 label->show();
916 Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4));
917 hbox->pack_start(*label, true, true, 5);
918 hbox->show();
920 return hbox;
921 }
923 /** \brief Initialize the object, to do that, copy the data. */
924 ParamDescription::ParamDescription (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
925 Parameter(name, guitext, desc, scope, ext), _value(NULL)
926 {
927 // printf("Building Description\n");
928 const char * defaultval = NULL;
929 if (sp_repr_children(xml) != NULL)
930 defaultval = sp_repr_children(xml)->content();
932 if (defaultval != NULL)
933 _value = g_strdup(defaultval);
935 return;
936 }
938 ParamEnum::ParamEnum (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
939 Parameter(name, guitext, desc, scope, ext), _current_choice(NULL)
940 {
941 return;
942 }
944 ParamEnum::~ParamEnum (void)
945 {
947 }
949 /** \brief Return the value as a string */
950 Glib::ustring *
951 ParamEnum::string (void)
952 {
953 Glib::ustring * mystring = new Glib::ustring("");
954 *mystring += "\"";
955 *mystring += this->get(NULL, NULL);
956 *mystring += "\"";
957 return mystring;
958 }
960 Gtk::Widget *
961 ParamEnum::get_widget (SPDocument * doc, Inkscape::XML::Node * node)
962 {
963 return NULL;
964 }
966 const gchar *
967 ParamEnum::set (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node)
968 {
969 return NULL;
970 }
973 } /* namespace Extension */
974 } /* namespace Inkscape */
976 /*
977 Local Variables:
978 mode:c++
979 c-file-style:"stroustrup"
980 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
981 indent-tabs-mode:nil
982 fill-column:99
983 End:
984 */
985 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :