1 /** \file
2 * Parameters for extensions.
3 */
5 /*
6 * Author:
7 * Ted Gould <ted@gould.cx>
8 * Johan Engelen <johan@shouraizou.nl>
9 *
10 * Copyright (C) 2005-2007 Authors
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
19 #ifdef linux // does the dollar sign need escaping when passed as string parameter?
20 # define ESCAPE_DOLLAR_COMMANDLINE
21 #endif
23 #include <gtkmm/adjustment.h>
24 #include <gtkmm/box.h>
25 #include <gtkmm/spinbutton.h>
27 #include <glibmm/i18n.h>
29 #include <xml/node.h>
31 #include "extension.h"
32 #include "prefs-utils.h"
33 #include "document-private.h"
34 #include "sp-object.h"
36 #include "parameter.h"
37 #include "paramnotebook.h"
38 #include "paramenum.h"
39 #include "paramradiobutton.h"
41 /** \brief The root directory in the preferences database for extension
42 related parameters. */
43 #define PREF_DIR "extensions"
45 namespace Inkscape {
46 namespace Extension {
48 /** \brief A description parameter */
49 class ParamDescription : public Parameter {
50 private:
51 /** \brief Internal value. */
52 gchar * _value;
53 public:
54 ParamDescription(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml);
55 Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal);
56 };
58 /** \brief A boolean parameter */
59 class ParamBool : public Parameter {
60 private:
61 /** \brief Internal value. */
62 bool _value;
63 public:
64 ParamBool(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml);
65 /** \brief Returns \c _value */
66 bool get (const SPDocument * doc, const Inkscape::XML::Node * node) { return _value; }
67 bool set (bool in, SPDocument * doc, Inkscape::XML::Node * node);
68 Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal);
69 Glib::ustring * string (void);
70 };
72 /** \brief Use the superclass' allocator and set the \c _value */
73 ParamBool::ParamBool (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
74 Parameter(name, guitext, desc, scope, ext), _value(false)
75 {
76 const char * defaultval = NULL;
77 if (sp_repr_children(xml) != NULL)
78 defaultval = sp_repr_children(xml)->content();
80 if (defaultval != NULL && (!strcmp(defaultval, "TRUE") || !strcmp(defaultval, "true") || !strcmp(defaultval, "1"))) {
81 _value = true;
82 } else {
83 _value = false;
84 }
86 gchar * pref_name = this->pref_name();
87 _value = (bool)prefs_get_int_attribute(PREF_DIR, pref_name, _value);
88 g_free(pref_name);
90 return;
91 }
93 class ParamInt : public Parameter {
94 private:
95 /** \brief Internal value. */
96 int _value;
97 int _min;
98 int _max;
99 public:
100 ParamInt (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml);
101 /** \brief Returns \c _value */
102 int get (const SPDocument * doc, const Inkscape::XML::Node * node) { return _value; }
103 int set (int in, SPDocument * doc, Inkscape::XML::Node * node);
104 int max (void) { return _max; }
105 int min (void) { return _min; }
106 Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal);
107 Glib::ustring * string (void);
108 };
110 /** \brief Use the superclass' allocator and set the \c _value */
111 ParamInt::ParamInt (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
112 Parameter(name, guitext, desc, scope, ext), _value(0), _min(0), _max(10)
113 {
114 const char * defaultval = NULL;
115 if (sp_repr_children(xml) != NULL)
116 defaultval = sp_repr_children(xml)->content();
117 if (defaultval != NULL) {
118 _value = atoi(defaultval);
119 }
121 const char * maxval = xml->attribute("max");
122 if (maxval != NULL)
123 _max = atoi(maxval);
125 const char * minval = xml->attribute("min");
126 if (minval != NULL)
127 _min = atoi(minval);
129 /* We're handling this by just killing both values */
130 if (_max < _min) {
131 _max = 10;
132 _min = 0;
133 }
135 gchar * pref_name = this->pref_name();
136 _value = prefs_get_int_attribute(PREF_DIR, pref_name, _value);
137 g_free(pref_name);
139 // std::cout << "New Int:: value: " << _value << " max: " << _max << " min: " << _min << std::endl;
141 if (_value > _max) _value = _max;
142 if (_value < _min) _value = _min;
144 return;
145 }
147 class ParamFloat : public Parameter {
148 private:
149 /** \brief Internal value. */
150 float _value;
151 float _min;
152 float _max;
153 public:
154 ParamFloat (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml);
155 /** \brief Returns \c _value */
156 float get (const SPDocument * doc, const Inkscape::XML::Node * node) { return _value; }
157 float set (float in, SPDocument * doc, Inkscape::XML::Node * node);
158 float max (void) { return _max; }
159 float min (void) { return _min; }
160 Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal);
161 Glib::ustring * string (void);
162 };
164 /** \brief Use the superclass' allocator and set the \c _value */
165 ParamFloat::ParamFloat (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
166 Parameter(name, guitext, desc, scope, ext), _value(0.0), _min(0.0), _max(10.0)
167 {
168 const char * defaultval = NULL;
169 if (sp_repr_children(xml) != NULL)
170 defaultval = sp_repr_children(xml)->content();
171 if (defaultval != NULL) {
172 _value = atof(defaultval);
173 }
175 const char * maxval = xml->attribute("max");
176 if (maxval != NULL)
177 _max = atof(maxval);
179 const char * minval = xml->attribute("min");
180 if (minval != NULL)
181 _min = atof(minval);
183 /* We're handling this by just killing both values */
184 if (_max < _min) {
185 _max = 10.0;
186 _min = 0.0;
187 }
189 gchar * pref_name = this->pref_name();
190 _value = prefs_get_double_attribute(PREF_DIR, pref_name, _value);
191 g_free(pref_name);
193 // std::cout << "New Float:: value: " << _value << " max: " << _max << " min: " << _min << std::endl;
195 if (_value > _max) _value = _max;
196 if (_value < _min) _value = _min;
198 return;
199 }
201 class ParamString : public Parameter {
202 private:
203 /** \brief Internal value. This should point to a string that has
204 been allocated in memory. And should be free'd. */
205 gchar * _value;
206 public:
207 ParamString(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml);
208 ~ParamString(void);
209 /** \brief Returns \c _value, with a \i const to protect it. */
210 const gchar * get (const SPDocument * doc, const Inkscape::XML::Node * node) { return _value; }
211 const gchar * set (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node);
212 Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal);
213 Glib::ustring * string (void);
214 };
216 class ParamEnum : public Parameter {
217 private:
218 class Choice {
219 public:
220 gchar * _gui_name;
221 gchar * _value;
222 Choice(gchar * gui_name, gchar * value) : _gui_name(NULL), _value(NULL) {
223 if (gui_name != NULL)
224 _gui_name = g_strdup(_(gui_name));
225 if (value != NULL)
226 _value = g_strdup(value);
227 return;
228 };
229 ~Choice (void) {
230 g_free(_gui_name);
231 g_free(_value);
232 };
233 }; /* class Choice */
234 /** \brief Internal value. This should point to a string that has
235 been allocated in memory. And should be free'd. */
236 Choice * _current_choice;
237 typedef std::list<Choice *> choice_list_t;
238 choice_list_t _choice_list;
239 public:
240 ParamEnum(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml);
241 ~ParamEnum(void);
242 /** \brief Returns \c _value, with a \i const to protect it. */
243 const gchar * get (const SPDocument * doc, const Inkscape::XML::Node * node) { return _current_choice != NULL ? _current_choice->_value : NULL; }
244 const gchar * set (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node);
245 Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal);
246 Glib::ustring * string (void);
247 }; /* class ParamEnum */
250 /**
251 \return None
252 \brief This function creates a parameter that can be used later. This
253 is typically done in the creation of the extension and defined
254 in the XML file describing the extension (it's private so people
255 have to use the system) :)
256 \param in_repr The XML describing the parameter
258 This function first grabs all of the data out of the Repr and puts
259 it into local variables. Actually, these are just pointers, and the
260 data is not duplicated so we need to be careful with it. If there
261 isn't a name or a type in the XML, then no parameter is created as
262 the function just returns.
264 From this point on, we're pretty committed as we've allocated an
265 object and we're starting to fill it. The name is set first, and
266 is created with a strdup to actually allocate memory for it. Then
267 there is a case statement (roughly because strcmp requires 'ifs')
268 based on what type of parameter this is. Depending which type it
269 is, the value is interpreted differently, but they are relatively
270 straight forward. In all cases the value is set to the default
271 value from the XML and the type is set to the interpreted type.
272 */
273 Parameter *
274 Parameter::make (Inkscape::XML::Node * in_repr, Inkscape::Extension::Extension * in_ext)
275 {
276 const char * name;
277 const char * type;
278 const char * guitext;
279 const char * desc;
280 const char * scope_str;
281 Parameter::_scope_t scope = Parameter::SCOPE_USER;
283 name = in_repr->attribute("name");
284 type = in_repr->attribute("type");
285 guitext = in_repr->attribute("gui-text");
286 if (guitext == NULL)
287 guitext = in_repr->attribute("_gui-text");
288 desc = in_repr->attribute("gui-description");
289 if (desc == NULL)
290 desc = in_repr->attribute("_gui-description");
291 scope_str = in_repr->attribute("scope");
293 /* In this case we just don't have enough information */
294 if (name == NULL || type == NULL) {
295 return NULL;
296 }
298 if (scope_str != NULL) {
299 if (!strcmp(scope_str, "user")) {
300 scope = Parameter::SCOPE_USER;
301 } else if (!strcmp(scope_str, "document")) {
302 scope = Parameter::SCOPE_DOCUMENT;
303 } else if (!strcmp(scope_str, "node")) {
304 scope = Parameter::SCOPE_NODE;
305 }
306 }
308 Parameter * param = NULL;
309 if (!strcmp(type, "boolean")) {
310 param = new ParamBool(name, guitext, desc, scope, in_ext, in_repr);
311 } else if (!strcmp(type, "int")) {
312 param = new ParamInt(name, guitext, desc, scope, in_ext, in_repr);
313 } else if (!strcmp(type, "float")) {
314 param = new ParamFloat(name, guitext, desc, scope, in_ext, in_repr);
315 } else if (!strcmp(type, "string")) {
316 param = new ParamString(name, guitext, desc, scope, in_ext, in_repr);
317 } else if (!strcmp(type, "description")) {
318 param = new ParamDescription(name, guitext, desc, scope, in_ext, in_repr);
319 } else if (!strcmp(type, "enum")) {
320 param = new ParamComboBox(name, guitext, desc, scope, in_ext, in_repr);
321 } else if (!strcmp(type, "notebook")) {
322 param = new ParamNotebook(name, guitext, desc, scope, in_ext, in_repr);
323 } else if (!strcmp(type, "optiongroup")) {
324 param = new ParamRadioButton(name, guitext, desc, scope, in_ext, in_repr);
325 }
327 /* Note: param could equal NULL */
328 return param;
329 }
331 /** \brief A function to set the \c _value
332 \param in The value to set to
333 \param doc A document that should be used to set the value.
334 \param node The node where the value may be placed
336 This function sets the internal value, but it also sets the value
337 in the preferences structure. To put it in the right place, \c PREF_DIR
338 and \c pref_name() are used.
339 */
340 bool
341 ParamBool::set (bool in, SPDocument * doc, Inkscape::XML::Node * node)
342 {
343 _value = in;
345 gchar * prefname = this->pref_name();
346 prefs_set_int_attribute(PREF_DIR, prefname, _value == true ? 1 : 0);
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.
360 */
361 int
362 ParamInt::set (int in, SPDocument * doc, Inkscape::XML::Node * node)
363 {
364 _value = in;
365 if (_value > _max) _value = _max;
366 if (_value < _min) _value = _min;
368 gchar * prefname = this->pref_name();
369 prefs_set_int_attribute(PREF_DIR, prefname, _value);
370 g_free(prefname);
372 return _value;
373 }
375 /** \brief A function to set the \c _value
376 \param in The value to set to
377 \param doc A document that should be used to set the value.
378 \param node The node where the value may be placed
380 This function sets the internal value, but it also sets the value
381 in the preferences structure. To put it in the right place, \c PREF_DIR
382 and \c pref_name() are used.
383 */
384 float
385 ParamFloat::set (float in, SPDocument * doc, Inkscape::XML::Node * node)
386 {
387 _value = in;
388 if (_value > _max) _value = _max;
389 if (_value < _min) _value = _min;
391 gchar * prefname = this->pref_name();
392 prefs_set_double_attribute(PREF_DIR, prefname, _value);
393 g_free(prefname);
395 return _value;
396 }
398 /** \brief A function to set the \c _value
399 \param in The value to set to
400 \param doc A document that should be used to set the value.
401 \param node The node where the value may be placed
403 This function sets the internal value, but it also sets the value
404 in the preferences structure. To put it in the right place, \c PREF_DIR
405 and \c pref_name() are used.
407 To copy the data into _value the old memory must be free'd first.
408 It is important to note that \c g_free handles \c NULL just fine. Then
409 the passed in value is duplicated using \c g_strdup().
410 */
411 const gchar *
412 ParamString::set (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node)
413 {
414 if (in == NULL) return NULL; /* Can't have NULL string */
416 if (_value != NULL)
417 g_free(_value);
418 _value = g_strdup(in);
420 gchar * prefname = this->pref_name();
421 prefs_set_string_attribute(PREF_DIR, prefname, _value);
422 g_free(prefname);
424 return _value;
425 }
427 /** \brief Wrapper to cast to the object and use it's function. */
428 bool
429 Parameter::get_bool (const SPDocument * doc, const Inkscape::XML::Node * node)
430 {
431 ParamBool * boolpntr;
432 boolpntr = dynamic_cast<ParamBool *>(this);
433 if (boolpntr == NULL)
434 throw Extension::param_wrong_type();
435 return boolpntr->get(doc, node);
436 }
438 /** \brief Wrapper to cast to the object and use it's function. */
439 int
440 Parameter::get_int (const SPDocument * doc, const Inkscape::XML::Node * node)
441 {
442 ParamInt * intpntr;
443 intpntr = dynamic_cast<ParamInt *>(this);
444 if (intpntr == NULL)
445 throw Extension::param_wrong_type();
446 return intpntr->get(doc, node);
447 }
449 /** \brief Wrapper to cast to the object and use it's function. */
450 float
451 Parameter::get_float (const SPDocument * doc, const Inkscape::XML::Node * node)
452 {
453 ParamFloat * floatpntr;
454 floatpntr = dynamic_cast<ParamFloat *>(this);
455 if (floatpntr == NULL)
456 throw Extension::param_wrong_type();
457 return floatpntr->get(doc, node);
458 }
460 /** \brief Wrapper to cast to the object and use it's function. */
461 const gchar *
462 Parameter::get_string (const SPDocument * doc, const Inkscape::XML::Node * node)
463 {
464 ParamString * stringpntr;
465 stringpntr = dynamic_cast<ParamString *>(this);
466 if (stringpntr == NULL)
467 throw Extension::param_wrong_type();
468 return stringpntr->get(doc, node);
469 }
471 /** \brief Wrapper to cast to the object and use it's function. */
472 bool
473 Parameter::set_bool (bool in, SPDocument * doc, Inkscape::XML::Node * node)
474 {
475 ParamBool * boolpntr;
476 boolpntr = dynamic_cast<ParamBool *>(this);
477 if (boolpntr == NULL)
478 throw Extension::param_wrong_type();
479 return boolpntr->set(in, doc, node);
480 }
482 /** \brief Wrapper to cast to the object and use it's function. */
483 int
484 Parameter::set_int (int in, SPDocument * doc, Inkscape::XML::Node * node)
485 {
486 ParamInt * intpntr;
487 intpntr = dynamic_cast<ParamInt *>(this);
488 if (intpntr == NULL)
489 throw Extension::param_wrong_type();
490 return intpntr->set(in, doc, node);
491 }
493 /** \brief Wrapper to cast to the object and use it's function. */
494 float
495 Parameter::set_float (float in, SPDocument * doc, Inkscape::XML::Node * node)
496 {
497 ParamFloat * floatpntr;
498 floatpntr = dynamic_cast<ParamFloat *>(this);
499 if (floatpntr == NULL)
500 throw Extension::param_wrong_type();
501 return floatpntr->set(in, doc, node);
502 }
504 /** \brief Wrapper to cast to the object and use it's function. */
505 const gchar *
506 Parameter::set_string (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node)
507 {
508 ParamString * stringpntr;
509 stringpntr = dynamic_cast<ParamString *>(this);
510 if (stringpntr == NULL)
511 throw Extension::param_wrong_type();
512 return stringpntr->set(in, doc, node);
513 }
515 /** \brief Initialize the object, to do that, copy the data. */
516 ParamString::ParamString (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
517 Parameter(name, guitext, desc, scope, ext), _value(NULL)
518 {
519 const char * defaultval = NULL;
520 if (sp_repr_children(xml) != NULL)
521 defaultval = sp_repr_children(xml)->content();
523 gchar * pref_name = this->pref_name();
524 const gchar * paramval = prefs_get_string_attribute(PREF_DIR, pref_name);
525 g_free(pref_name);
527 if (paramval != NULL)
528 defaultval = paramval;
529 if (defaultval != NULL)
530 _value = g_strdup(defaultval);
532 return;
533 }
535 /** \brief Free the allocated data. */
536 ParamString::~ParamString(void)
537 {
538 g_free(_value);
539 }
541 /** \brief Oop, now that we need a parameter, we need it's name. */
542 Parameter::Parameter (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext) :
543 extension(ext), _name(NULL), _desc(NULL), _scope(scope), _text(NULL)
544 {
545 if (name != NULL)
546 _name = g_strdup(name);
547 if (desc != NULL) {
548 _desc = g_strdup(desc);
549 // printf("Adding description: '%s' on '%s'\n", _desc, _name);
550 }
553 if (guitext != NULL)
554 _text = g_strdup(guitext);
555 else
556 _text = g_strdup(name);
558 return;
559 }
561 /** \brief Just free the allocated name. */
562 Parameter::~Parameter (void)
563 {
564 g_free(_name);
565 g_free(_text);
566 }
568 /** \brief Build the name to write the parameter from the extension's
569 ID and the name of this parameter. */
570 gchar *
571 Parameter::pref_name (void)
572 {
573 return g_strdup_printf("%s.%s", extension->get_id(), _name);
574 }
576 Inkscape::XML::Node *
577 Parameter::find_child (Inkscape::XML::Node * adult)
578 {
579 return sp_repr_lookup_child(adult, "name", _name);
580 }
582 Inkscape::XML::Node *
583 Parameter::new_child (Inkscape::XML::Node * parent)
584 {
585 Inkscape::XML::Node * retval;
586 retval = parent->document()->createElement("inkscape:extension-param");
587 retval->setAttribute("name", _name);
589 parent->appendChild(retval);
590 return retval;
591 }
593 Inkscape::XML::Node *
594 Parameter::document_param_node (SPDocument * doc)
595 {
596 Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
597 Inkscape::XML::Node * defs = SP_OBJECT_REPR(SP_DOCUMENT_DEFS(doc));
598 Inkscape::XML::Node * params = NULL;
600 GQuark const name_quark = g_quark_from_string("inkscape:extension-params");
602 for (Inkscape::XML::Node * child = defs->firstChild();
603 child != NULL;
604 child = child->next()) {
605 if ((GQuark)child->code() == name_quark &&
606 !strcmp(child->attribute("extension"), extension->get_id())) {
607 params = child;
608 break;
609 }
610 }
612 if (params == NULL) {
613 params = xml_doc->createElement("inkscape:extension-param");
614 params->setAttribute("extension", extension->get_id());
615 defs->appendChild(params);
616 }
618 return params;
619 }
621 /** \brief Basically, if there is no widget pass a NULL. */
622 Gtk::Widget *
623 Parameter::get_widget (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal)
624 {
625 return NULL;
626 }
628 /** \brief If I'm not sure which it is, just don't return a value. */
629 Glib::ustring *
630 Parameter::string (void)
631 {
632 Glib::ustring * mystring = new Glib::ustring("");
633 return mystring;
634 }
636 /** \brief A class to make an adjustment that uses Extension params */
637 class ParamFloatAdjustment : public Gtk::Adjustment {
638 /** The parameter to adjust */
639 ParamFloat * _pref;
640 SPDocument * _doc;
641 Inkscape::XML::Node * _node;
642 sigc::signal<void> * _changeSignal;
643 public:
644 /** \brief Make the adjustment using an extension and the string
645 describing the parameter. */
646 ParamFloatAdjustment (ParamFloat * param, SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal) :
647 Gtk::Adjustment(0.0, param->min(), param->max(), 0.1), _pref(param), _doc(doc), _node(node), _changeSignal(changeSignal) {
648 this->set_value(_pref->get(NULL, NULL) /* \todo fix */);
649 this->signal_value_changed().connect(sigc::mem_fun(this, &ParamFloatAdjustment::val_changed));
650 return;
651 };
653 void val_changed (void);
654 }; /* class ParamFloatAdjustment */
656 /** \brief A function to respond to the value_changed signal from the
657 adjustment.
659 This function just grabs the value from the adjustment and writes
660 it to the parameter. Very simple, but yet beautiful.
661 */
662 void
663 ParamFloatAdjustment::val_changed (void)
664 {
665 //std::cout << "Value Changed to: " << this->get_value() << std::endl;
666 _pref->set(this->get_value(), _doc, _node);
667 if (_changeSignal != NULL) {
668 _changeSignal->emit();
669 }
670 return;
671 }
673 /** \brief A class to make an adjustment that uses Extension params */
674 class ParamIntAdjustment : public Gtk::Adjustment {
675 /** The parameter to adjust */
676 ParamInt * _pref;
677 SPDocument * _doc;
678 Inkscape::XML::Node * _node;
679 sigc::signal<void> * _changeSignal;
680 public:
681 /** \brief Make the adjustment using an extension and the string
682 describing the parameter. */
683 ParamIntAdjustment (ParamInt * param, SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal) :
684 Gtk::Adjustment(0.0, param->min(), param->max(), 1.0), _pref(param), _doc(doc), _node(node), _changeSignal(changeSignal) {
685 this->set_value(_pref->get(NULL, NULL) /* \todo fix */);
686 this->signal_value_changed().connect(sigc::mem_fun(this, &ParamIntAdjustment::val_changed));
687 return;
688 };
690 void val_changed (void);
691 }; /* class ParamIntAdjustment */
693 /** \brief A function to respond to the value_changed signal from the
694 adjustment.
696 This function just grabs the value from the adjustment and writes
697 it to the parameter. Very simple, but yet beautiful.
698 */
699 void
700 ParamIntAdjustment::val_changed (void)
701 {
702 //std::cout << "Value Changed to: " << this->get_value() << std::endl;
703 _pref->set((int)this->get_value(), _doc, _node);
704 if (_changeSignal != NULL) {
705 _changeSignal->emit();
706 }
707 return;
708 }
710 /**
711 \brief Creates a Float Adjustment for a float parameter
713 Builds a hbox with a label and a float adjustment in it.
714 */
715 Gtk::Widget *
716 ParamFloat::get_widget (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal)
717 {
718 Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4));
720 Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_LEFT));
721 label->show();
722 hbox->pack_start(*label, true, true);
724 ParamFloatAdjustment * fadjust = Gtk::manage(new ParamFloatAdjustment(this, doc, node, changeSignal));
725 Gtk::SpinButton * spin = Gtk::manage(new Gtk::SpinButton(*fadjust, 0.1, 1));
726 spin->show();
727 hbox->pack_start(*spin, false, false);
729 hbox->show();
731 return dynamic_cast<Gtk::Widget *>(hbox);
732 }
734 /**
735 \brief Creates a Int Adjustment for a int parameter
737 Builds a hbox with a label and a int adjustment in it.
738 */
739 Gtk::Widget *
740 ParamInt::get_widget (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal)
741 {
742 Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4));
744 Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_LEFT));
745 label->show();
746 hbox->pack_start(*label, true, true);
748 ParamIntAdjustment * fadjust = Gtk::manage(new ParamIntAdjustment(this, doc, node, changeSignal));
749 Gtk::SpinButton * spin = Gtk::manage(new Gtk::SpinButton(*fadjust, 1.0, 0));
750 spin->show();
751 hbox->pack_start(*spin, false, false);
753 hbox->show();
755 return dynamic_cast<Gtk::Widget *>(hbox);
756 }
758 /** \brief A check button which is Param aware. It works with the
759 parameter to change it's value as the check button changes
760 value. */
761 class ParamBoolCheckButton : public Gtk::CheckButton {
762 private:
763 /** \brief Param to change */
764 ParamBool * _pref;
765 SPDocument * _doc;
766 Inkscape::XML::Node * _node;
767 sigc::signal<void> * _changeSignal;
768 public:
769 /** \brief Initialize the check button
770 \param param Which parameter to adjust on changing the check button
772 This function sets the value of the checkbox to be that of the
773 parameter, and then sets up a callback to \c on_toggle.
774 */
775 ParamBoolCheckButton (ParamBool * param, SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal) :
776 Gtk::CheckButton(), _pref(param), _doc(doc), _node(node), _changeSignal(changeSignal) {
777 this->set_active(_pref->get(NULL, NULL) /**\todo fix */);
778 this->signal_toggled().connect(sigc::mem_fun(this, &ParamBoolCheckButton::on_toggle));
779 return;
780 }
781 void on_toggle (void);
782 };
784 /**
785 \brief A function to respond to the check box changing
787 Adjusts the value of the preference to match that in the check box.
788 */
789 void
790 ParamBoolCheckButton::on_toggle (void)
791 {
792 _pref->set(this->get_active(), NULL /**\todo fix this */, NULL);
793 if (_changeSignal != NULL) {
794 _changeSignal->emit();
795 }
796 return;
797 }
799 /**
800 \brief Creates a bool check button for a bool parameter
802 Builds a hbox with a label and a check button in it.
803 */
804 Gtk::Widget *
805 ParamBool::get_widget (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal)
806 {
807 Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4));
809 Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_LEFT));
810 label->show();
811 hbox->pack_start(*label, true, true);
813 ParamBoolCheckButton * checkbox = new ParamBoolCheckButton(this, doc, node, changeSignal);
814 checkbox->show();
815 hbox->pack_start(*checkbox, false, false);
817 hbox->show();
819 return dynamic_cast<Gtk::Widget *>(hbox);
820 }
822 /** \brief A special category of Gtk::Entry to handle string parameteres */
823 class ParamStringEntry : public Gtk::Entry {
824 private:
825 ParamString * _pref;
826 SPDocument * _doc;
827 Inkscape::XML::Node * _node;
828 sigc::signal<void> * _changeSignal;
829 public:
830 /** \brief Build a string preference for the given parameter
831 \param pref Where to get the string from, and where to put it
832 when it changes.
833 */
834 ParamStringEntry (ParamString * pref, SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal) :
835 Gtk::Entry(), _pref(pref), _doc(doc), _node(node), _changeSignal(changeSignal) {
836 if (_pref->get(NULL, NULL) != NULL)
837 this->set_text(Glib::ustring(_pref->get(NULL, NULL)));
838 this->signal_changed().connect(sigc::mem_fun(this, &ParamStringEntry::changed_text));
839 };
840 void changed_text (void);
841 };
843 /** \brief Respond to the text box changing
845 This function responds to the box changing by grabbing the value
846 from the text box and putting it in the parameter.
847 */
848 void
849 ParamStringEntry::changed_text (void)
850 {
851 Glib::ustring data = this->get_text();
852 _pref->set(data.c_str(), _doc, _node);
853 if (_changeSignal != NULL) {
854 _changeSignal->emit();
855 }
856 return;
857 }
859 /**
860 \brief Creates a text box for the string parameter
862 Builds a hbox with a label and a text box in it.
863 */
864 Gtk::Widget *
865 ParamString::get_widget (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal)
866 {
867 Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4));
869 Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_LEFT));
870 label->show();
871 hbox->pack_start(*label, false, false);
873 ParamStringEntry * textbox = new ParamStringEntry(this, doc, node, changeSignal);
874 textbox->show();
875 hbox->pack_start(*textbox, true, true);
877 hbox->show();
879 return dynamic_cast<Gtk::Widget *>(hbox);
880 }
882 /** \brief Return 'true' or 'false' */
883 Glib::ustring *
884 ParamBool::string (void)
885 {
886 Glib::ustring * mystring;
888 if (_value)
889 mystring = new Glib::ustring("true");
890 else
891 mystring = new Glib::ustring("false");
893 return mystring;
894 }
896 /** \brief Return the value as a string */
897 Glib::ustring *
898 ParamInt::string (void)
899 {
900 char startstring[32];
901 sprintf(startstring, "%d", _value);
902 Glib::ustring * mystring = new Glib::ustring(startstring);
903 return mystring;
904 }
906 /** \brief Return the value as a string */
907 Glib::ustring *
908 ParamFloat::string (void)
909 {
910 char startstring[G_ASCII_DTOSTR_BUF_SIZE];
911 g_ascii_dtostr(startstring, G_ASCII_DTOSTR_BUF_SIZE, _value);
912 Glib::ustring * mystring = new Glib::ustring(startstring);
913 return mystring;
914 }
916 /** \brief Return the value as a string */
917 Glib::ustring *
918 ParamString::string (void)
919 {
920 if (_value == NULL)
921 return new Glib::ustring("");
923 // FIXME: I think the string should NOT be escaped. Just put between "..."
924 // Otherwise \frac{1}{2} will become \\frac{1}{2} and then the LaTeX effect won't work....
925 //gchar * esc = g_strescape(_value, NULL);
926 Glib::ustring escaped(_value);
927 //g_free(esc);
929 #ifdef ESCAPE_DOLLAR_COMMANDLINE // escape the dollar sign
930 Glib::ustring::iterator i;
931 for (i = escaped.begin(); i != escaped.end(); ++i) {
932 if ( *i == '$') {
933 i = escaped.insert(i, '\\');
934 i++;
935 }
936 }
937 #endif
939 Glib::ustring * mystring = new Glib::ustring("");
940 *mystring += "\"";
941 *mystring += escaped;
942 *mystring += "\"";
944 return mystring;
945 }
947 /** \brief Create a label for the description */
948 Gtk::Widget *
949 ParamDescription::get_widget (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal)
950 {
951 Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_value)));
952 label->set_line_wrap();
953 label->show();
955 Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4));
956 hbox->pack_start(*label, true, true, 5);
957 hbox->show();
959 return hbox;
960 }
962 /** \brief Initialize the object, to do that, copy the data. */
963 ParamDescription::ParamDescription (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
964 Parameter(name, guitext, desc, scope, ext), _value(NULL)
965 {
966 // printf("Building Description\n");
967 const char * defaultval = NULL;
968 if (sp_repr_children(xml) != NULL)
969 defaultval = sp_repr_children(xml)->content();
971 if (defaultval != NULL)
972 _value = g_strdup(defaultval);
974 return;
975 }
977 ParamEnum::ParamEnum (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
978 Parameter(name, guitext, desc, scope, ext), _current_choice(NULL)
979 {
980 return;
981 }
983 ParamEnum::~ParamEnum (void)
984 {
986 }
988 /** \brief Return the value as a string */
989 Glib::ustring *
990 ParamEnum::string (void)
991 {
992 Glib::ustring * mystring = new Glib::ustring("");
993 *mystring += this->get(NULL, NULL);
994 return mystring;
995 }
997 Gtk::Widget *
998 ParamEnum::get_widget (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal)
999 {
1000 return NULL;
1001 }
1003 const gchar *
1004 ParamEnum::set (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node)
1005 {
1006 return NULL;
1007 }
1010 } /* namespace Extension */
1011 } /* namespace Inkscape */
1013 /*
1014 Local Variables:
1015 mode:c++
1016 c-file-style:"stroustrup"
1017 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1018 indent-tabs-mode:nil
1019 fill-column:99
1020 End:
1021 */
1022 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :