Code

Filter effects dialog:
[inkscape.git] / src / extension / parameter.cpp
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)
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;
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)
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;
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)
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;
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)
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;
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)
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;
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)
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;
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)
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;
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)
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);
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)
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);
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)
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);
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)
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);
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)
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);
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)
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);
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)
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);
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)
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);
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)
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;
535 /** \brief  Free the allocated data. */
536 ParamString::~ParamString(void)
538     g_free(_value);
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)
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;
561 /** \brief  Just free the allocated name. */
562 Parameter::~Parameter (void)
564     g_free(_name);
565     g_free(_text);
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)
573     return g_strdup_printf("%s.%s", extension->get_id(), _name);
576 Inkscape::XML::Node *
577 Parameter::find_child (Inkscape::XML::Node * adult)
579     return sp_repr_lookup_child(adult, "name", _name);
582 Inkscape::XML::Node *
583 Parameter::new_child (Inkscape::XML::Node * parent)
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;
593 Inkscape::XML::Node *
594 Parameter::document_param_node (SPDocument * doc)
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;
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)
625     return NULL;
628 /** \brief  If I'm not sure which it is, just don't return a value. */
629 Glib::ustring *
630 Parameter::string (void)
632     Glib::ustring * mystring = new Glib::ustring("");
633     return mystring;
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)
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;
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)
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;
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)
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);
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)
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);
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)
792     _pref->set(this->get_active(), NULL /**\todo fix this */, NULL);
793     if (_changeSignal != NULL) {
794         _changeSignal->emit();
795     }
796     return;
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)
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);
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)
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;
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)
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);
882 /** \brief  Return 'true' or 'false' */
883 Glib::ustring *
884 ParamBool::string (void)
886     Glib::ustring * mystring;
888     if (_value)
889         mystring = new Glib::ustring("true");
890     else
891         mystring = new Glib::ustring("false");
893     return mystring;
896 /** \brief  Return the value as a string */
897 Glib::ustring *
898 ParamInt::string (void)
900     char startstring[32];
901     sprintf(startstring, "%d", _value);
902     Glib::ustring * mystring = new Glib::ustring(startstring);
903     return mystring;
906 /** \brief  Return the value as a string */
907 Glib::ustring *
908 ParamFloat::string (void)
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;
916 /** \brief  Return the value as a string */
917 Glib::ustring *
918 ParamString::string (void)
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);
928     
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 += "\"";
943     
944     return mystring;
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)
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;
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)
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;
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)
980     return;
983 ParamEnum::~ParamEnum (void)
988 /** \brief  Return the value as a string */
989 Glib::ustring *
990 ParamEnum::string (void)
992     Glib::ustring * mystring = new Glib::ustring("");
993     *mystring += this->get(NULL, NULL);
994     return mystring;
997 Gtk::Widget *
998 ParamEnum::get_widget (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal)
1000     return NULL;
1003 const gchar *
1004 ParamEnum::set (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node)
1006     return NULL;
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 :