1 /** \file
2 * extension parameter for radiobuttons.
3 *
4 * It uses a Gtk:ComboBoxText widget in the extension UI.
5 */
7 /*
8 * Author:
9 * Johan Engelen <johan@shouraizou.nl>
10 *
11 * Copyright (C) 2006-2007 Johan Engelen
12 *
13 * Released under GNU GPL, read the file 'COPYING' for more information
14 */
16 #ifdef HAVE_CONFIG_H
17 # include "config.h"
18 #endif
21 #include <gtkmm/box.h>
22 #include <gtkmm/radiobutton.h>
23 #include <gtkmm/radiobuttongroup.h>
24 #include <gtkmm/tooltips.h>
25 #include <gtkmm/label.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 "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 /* For internal use only.
46 Note that value and guitext MUST be non-NULL. This is ensured by newing only at one location in the code where non-NULL checks are made. */
47 class optionentry {
48 public:
49 optionentry (Glib::ustring * val, Glib::ustring * text) {
50 value = val;
51 guitext = text;
52 }
53 ~optionentry() {
54 delete value;
55 delete guitext;
56 }
58 Glib::ustring * value;
59 Glib::ustring * guitext;
60 };
62 ParamRadioButton::ParamRadioButton (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
63 Parameter(name, guitext, desc, scope, ext)
64 {
65 choices = NULL;
66 _value = NULL;
68 // Read XML tree to add enumeration items:
69 // printf("Extension Constructor: ");
70 if (xml != NULL) {
71 Inkscape::XML::Node *child_repr = sp_repr_children(xml);
72 while (child_repr != NULL) {
73 char const * chname = child_repr->name();
74 if (!strcmp(chname, "option") || !strcmp(chname, "_option")) {
75 Glib::ustring * newguitext = NULL;
76 Glib::ustring * newvalue = NULL;
77 const char * contents = sp_repr_children(child_repr)->content();
78 if (contents != NULL)
79 newguitext = new Glib::ustring(contents);
80 else
81 continue;
83 const char * val = child_repr->attribute("value");
84 if (val != NULL)
85 newvalue = new Glib::ustring(val);
86 else
87 newvalue = new Glib::ustring(*newguitext);
89 if ( (newguitext) && (newvalue) ) { // logical error if this is not true here
90 choices = g_slist_append( choices, new optionentry(newvalue, newguitext) );
91 }
92 }
93 child_repr = sp_repr_next(child_repr);
94 }
95 }
97 // Initialize _value with the default value from xml
98 // for simplicity : default to the contents of the first xml-child
99 const char * defaultval = NULL;
100 if (choices)
101 defaultval = ((optionentry*) choices->data)->value->c_str();
103 gchar * pref_name = this->pref_name();
104 const gchar * paramval = prefs_get_string_attribute(PREF_DIR, pref_name);
105 g_free(pref_name);
107 if (paramval != NULL)
108 defaultval = paramval;
109 if (defaultval != NULL)
110 _value = g_strdup(defaultval); // allocate space for _value
112 return;
113 }
115 ParamRadioButton::~ParamRadioButton (void)
116 {
117 //destroy choice strings
118 for (GSList * list = choices; list != NULL; list = g_slist_next(list)) {
119 delete (reinterpret_cast<optionentry *>(list->data));
120 }
121 g_slist_free(choices);
123 g_free(_value);
124 }
127 /** \brief A function to set the \c _value
128 \param in The value to set
129 \param doc A document that should be used to set the value.
130 \param node The node where the value may be placed
132 This function sets ONLY the internal value, but it also sets the value
133 in the preferences structure. To put it in the right place, \c PREF_DIR
134 and \c pref_name() are used.
136 To copy the data into _value the old memory must be free'd first.
137 It is important to note that \c g_free handles \c NULL just fine. Then
138 the passed in value is duplicated using \c g_strdup().
139 */
140 const gchar *
141 ParamRadioButton::set (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node)
142 {
143 if (in == NULL) return NULL; /* Can't have NULL string */
145 Glib::ustring * settext = NULL;
146 for (GSList * list = choices; list != NULL; list = g_slist_next(list)) {
147 optionentry * entr = reinterpret_cast<optionentry *>(list->data);
148 if ( !entr->guitext->compare(in) ) {
149 settext = entr->value;
150 break; // break out of for loop
151 }
152 }
153 if (settext) {
154 if (_value != NULL) g_free(_value);
155 _value = g_strdup(settext->c_str());
156 gchar * prefname = this->pref_name();
157 prefs_set_string_attribute(PREF_DIR, prefname, _value);
158 g_free(prefname);
159 }
161 return _value;
162 }
165 /**
166 \brief A function to get the current value of the parameter in a string form
167 \return A string with the 'value' as command line argument
168 */
169 Glib::ustring *
170 ParamRadioButton::string (void)
171 {
172 Glib::ustring * param_string = new Glib::ustring("");
173 *param_string += _value;
174 return param_string;
175 }
177 /** \brief A special radiobutton class to use in ParamRadioButton */
178 class ParamRadioButtonWdg : public Gtk::RadioButton {
179 private:
180 ParamRadioButton * _pref;
181 SPDocument * _doc;
182 Inkscape::XML::Node * _node;
183 public:
184 /** \brief Build a string preference for the given parameter
185 \param pref Where to put the radiobutton's string when it is selected.
186 */
187 ParamRadioButtonWdg ( Gtk::RadioButtonGroup& group, const Glib::ustring& label,
188 ParamRadioButton * pref, SPDocument * doc, Inkscape::XML::Node * node ) :
189 Gtk::RadioButton(group, label), _pref(pref), _doc(doc), _node(node) {
190 add_changesignal();
191 };
192 ParamRadioButtonWdg ( const Glib::ustring& label,
193 ParamRadioButton * pref, SPDocument * doc, Inkscape::XML::Node * node ) :
194 Gtk::RadioButton(label), _pref(pref), _doc(doc), _node(node) {
195 add_changesignal();
196 };
197 void add_changesignal() {
198 this->signal_toggled().connect(sigc::mem_fun(this, &ParamRadioButtonWdg::changed));
199 };
200 void changed (void);
201 };
203 /** \brief Respond to the selected radiobutton changing
205 This function responds to the radiobutton selection changing by grabbing the value
206 from the text box and putting it in the parameter.
207 */
208 void
209 ParamRadioButtonWdg::changed (void)
210 {
211 if (this->get_active()) {
212 Glib::ustring data = this->get_label();
213 _pref->set(data.c_str(), _doc, _node);
214 }
215 }
219 /**
220 \brief Creates a combobox widget for an enumeration parameter
221 */
222 Gtk::Widget *
223 ParamRadioButton::get_widget (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal)
224 {
225 Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4));
226 Gtk::VBox * vbox = Gtk::manage(new Gtk::VBox(false, 0));
228 Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_LEFT, Gtk::ALIGN_TOP));
229 label->show();
230 hbox->pack_start(*label, false, false);
232 // add choice strings as radiobuttons
233 // and select last selected option (_value)
234 bool first = true;
235 ParamRadioButtonWdg * radio;
236 Gtk::RadioButtonGroup group;
237 for (GSList * list = choices; list != NULL; list = g_slist_next(list)) {
238 optionentry * entr = reinterpret_cast<optionentry *>(list->data);
239 Glib::ustring * text = entr->guitext;
240 if (first) {
241 radio = Gtk::manage(new ParamRadioButtonWdg(*text, this, doc, node));
242 group = radio->get_group();
243 first = false;
244 } else {
245 radio = Gtk::manage(new ParamRadioButtonWdg(group, *text, this, doc, node));
246 }
247 radio->show();
248 vbox->pack_start(*radio, true, true);
249 if (!entr->value->compare(_value)) {
250 radio->set_active();
251 }
252 }
254 vbox->show();
255 hbox->pack_end(*vbox, false, false);
256 hbox->show();
259 return dynamic_cast<Gtk::Widget *>(hbox);
260 }
263 } /* namespace Extension */
264 } /* namespace Inkscape */