76c3506af0fbf94400341b9537ed84cc87c6db26
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 * Copyright (C) 2008 Jon A. Cruz
13 *
14 * Released under GNU GPL, read the file 'COPYING' for more information
15 */
17 #ifdef HAVE_CONFIG_H
18 # include "config.h"
19 #endif
22 #include <gtkmm/box.h>
23 #include <gtkmm/comboboxtext.h>
24 #include <gtkmm/radiobutton.h>
25 #include <gtkmm/radiobuttongroup.h>
26 #include <gtkmm/tooltips.h>
27 #include <gtkmm/label.h>
29 #include <glibmm/i18n.h>
31 #include <xml/node.h>
33 #include <extension/extension.h>
34 #include "prefs-utils.h"
35 #include "document-private.h"
36 #include "sp-object.h"
38 #include "radiobutton.h"
40 /** \brief The root directory in the preferences database for extension
41 related parameters. */
42 #define PREF_DIR "extensions"
44 namespace Inkscape {
45 namespace Extension {
47 /* For internal use only.
48 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. */
49 class optionentry {
50 public:
51 optionentry (Glib::ustring * val, Glib::ustring * text) {
52 value = val;
53 guitext = text;
54 }
55 ~optionentry() {
56 delete value;
57 delete guitext;
58 }
60 Glib::ustring * value;
61 Glib::ustring * guitext;
62 };
64 ParamRadioButton::ParamRadioButton (const gchar * name,
65 const gchar * guitext,
66 const gchar * desc,
67 const Parameter::_scope_t scope,
68 bool gui_hidden,
69 const gchar * gui_tip,
70 Inkscape::Extension::Extension * ext,
71 Inkscape::XML::Node * xml,
72 AppearanceMode mode) :
73 Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext),
74 _value(0),
75 _mode(mode),
76 choices(0)
77 {
78 // Read XML tree to add enumeration items:
79 // printf("Extension Constructor: ");
80 if (xml != NULL) {
81 Inkscape::XML::Node *child_repr = sp_repr_children(xml);
82 while (child_repr != NULL) {
83 char const * chname = child_repr->name();
84 if (!strcmp(chname, INKSCAPE_EXTENSION_NS "option") || !strcmp(chname, INKSCAPE_EXTENSION_NS "_option")) {
85 Glib::ustring * newguitext = NULL;
86 Glib::ustring * newvalue = NULL;
87 const char * contents = sp_repr_children(child_repr)->content();
88 if (contents != NULL)
89 // don't translate when 'option' but do translate when '_option'
90 newguitext = new Glib::ustring( !strcmp(chname, "_option") ? _(contents) : contents );
91 else
92 continue;
94 const char * val = child_repr->attribute("value");
95 if (val != NULL)
96 newvalue = new Glib::ustring(val);
97 else
98 newvalue = new Glib::ustring(contents);
100 if ( (newguitext) && (newvalue) ) { // logical error if this is not true here
101 choices = g_slist_append( choices, new optionentry(newvalue, newguitext) );
102 }
103 }
104 child_repr = sp_repr_next(child_repr);
105 }
106 }
108 // Initialize _value with the default value from xml
109 // for simplicity : default to the contents of the first xml-child
110 const char * defaultval = NULL;
111 if (choices)
112 defaultval = ((optionentry*) choices->data)->value->c_str();
114 gchar * pref_name = this->pref_name();
115 const gchar * paramval = prefs_get_string_attribute(PREF_DIR, pref_name);
116 g_free(pref_name);
118 if (paramval != NULL)
119 defaultval = paramval;
120 if (defaultval != NULL)
121 _value = g_strdup(defaultval); // allocate space for _value
123 return;
124 }
126 ParamRadioButton::~ParamRadioButton (void)
127 {
128 //destroy choice strings
129 for (GSList * list = choices; list != NULL; list = g_slist_next(list)) {
130 delete (reinterpret_cast<optionentry *>(list->data));
131 }
132 g_slist_free(choices);
134 g_free(_value);
135 }
138 /** \brief A function to set the \c _value
139 \param in The value to set
140 \param doc A document that should be used to set the value.
141 \param node The node where the value may be placed
143 This function sets ONLY the internal value, but it also sets the value
144 in the preferences structure. To put it in the right place, \c PREF_DIR
145 and \c pref_name() are used.
147 To copy the data into _value the old memory must be free'd first.
148 It is important to note that \c g_free handles \c NULL just fine. Then
149 the passed in value is duplicated using \c g_strdup().
150 */
151 const gchar *
152 ParamRadioButton::set (const gchar * in, SPDocument * /*doc*/, Inkscape::XML::Node * /*node*/)
153 {
154 if (in == NULL) return NULL; /* Can't have NULL string */
156 Glib::ustring * settext = NULL;
157 for (GSList * list = choices; list != NULL; list = g_slist_next(list)) {
158 optionentry * entr = reinterpret_cast<optionentry *>(list->data);
159 if ( !entr->guitext->compare(in) ) {
160 settext = entr->value;
161 break; // break out of for loop
162 }
163 }
164 if (settext) {
165 if (_value != NULL) g_free(_value);
166 _value = g_strdup(settext->c_str());
167 gchar * prefname = this->pref_name();
168 prefs_set_string_attribute(PREF_DIR, prefname, _value);
169 g_free(prefname);
170 }
172 return _value;
173 }
176 /**
177 \brief A function to get the current value of the parameter in a string form
178 \return A string with the 'value' as command line argument
179 */
180 void
181 ParamRadioButton::string (std::string &string)
182 {
183 string += _value;
184 return;
185 }
187 /** \brief A special radiobutton class to use in ParamRadioButton */
188 class ParamRadioButtonWdg : public Gtk::RadioButton {
189 private:
190 ParamRadioButton * _pref;
191 SPDocument * _doc;
192 Inkscape::XML::Node * _node;
193 sigc::signal<void> * _changeSignal;
194 public:
195 /** \brief Build a string preference for the given parameter
196 \param pref Where to put the radiobutton's string when it is selected.
197 */
198 ParamRadioButtonWdg ( Gtk::RadioButtonGroup& group, const Glib::ustring& label,
199 ParamRadioButton * pref, SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal ) :
200 Gtk::RadioButton(group, label), _pref(pref), _doc(doc), _node(node), _changeSignal(changeSignal) {
201 add_changesignal();
202 };
203 ParamRadioButtonWdg ( const Glib::ustring& label,
204 ParamRadioButton * pref, SPDocument * doc, Inkscape::XML::Node * node , sigc::signal<void> * changeSignal) :
205 Gtk::RadioButton(label), _pref(pref), _doc(doc), _node(node), _changeSignal(changeSignal) {
206 add_changesignal();
207 };
208 void add_changesignal() {
209 this->signal_toggled().connect(sigc::mem_fun(this, &ParamRadioButtonWdg::changed));
210 };
211 void changed (void);
212 };
214 /** \brief Respond to the selected radiobutton changing
216 This function responds to the radiobutton selection changing by grabbing the value
217 from the text box and putting it in the parameter.
218 */
219 void
220 ParamRadioButtonWdg::changed (void)
221 {
222 if (this->get_active()) {
223 Glib::ustring data = this->get_label();
224 _pref->set(data.c_str(), _doc, _node);
225 }
226 if (_changeSignal != NULL) {
227 _changeSignal->emit();
228 }
229 }
232 class ComboWdg : public Gtk::ComboBoxText {
233 public:
234 ComboWdg(ParamRadioButton* base, SPDocument * doc, Inkscape::XML::Node * node) :
235 Gtk::ComboBoxText(),
236 base(base),
237 doc(doc),
238 node(node)
239 {
240 }
241 virtual ~ComboWdg() {}
243 protected:
244 ParamRadioButton* base;
245 SPDocument* doc;
246 Inkscape::XML::Node* node;
248 virtual void on_changed() {
249 if ( base ) {
250 base->set(get_active_text().c_str(), doc, node);
251 }
252 }
253 };
255 /**
256 \brief Creates a combobox widget for an enumeration parameter
257 */
258 Gtk::Widget *
259 ParamRadioButton::get_widget (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal)
260 {
261 if (_gui_hidden) return NULL;
263 Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4));
264 Gtk::VBox * vbox = Gtk::manage(new Gtk::VBox(false, 0));
266 Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_LEFT, Gtk::ALIGN_TOP));
267 label->show();
268 hbox->pack_start(*label, false, false);
270 Gtk::ComboBoxText* cbt = 0;
271 bool comboSet = false;
272 if (_mode == MINIMAL) {
273 cbt = Gtk::manage(new ComboWdg(this, doc, node));
274 cbt->show();
275 vbox->pack_start(*cbt, false, false);
276 }
278 // add choice strings as radiobuttons
279 // and select last selected option (_value)
280 Gtk::RadioButtonGroup group;
281 for (GSList * list = choices; list != NULL; list = g_slist_next(list)) {
282 optionentry * entr = reinterpret_cast<optionentry *>(list->data);
283 Glib::ustring * text = entr->guitext;
284 switch ( _mode ) {
285 case MINIMAL:
286 {
287 cbt->append_text(*text);
288 if (!entr->value->compare(_value)) {
289 cbt->set_active_text(*text);
290 comboSet = true;
291 }
292 }
293 break;
294 case COMPACT:
295 case FULL:
296 {
297 ParamRadioButtonWdg * radio = Gtk::manage(new ParamRadioButtonWdg(group, *text, this, doc, node, changeSignal));
298 radio->show();
299 vbox->pack_start(*radio, true, true);
300 if (!entr->value->compare(_value)) {
301 radio->set_active();
302 }
303 }
304 break;
305 }
306 }
308 if ( (_mode == MINIMAL) && !comboSet) {
309 cbt->set_active(0);
310 }
312 vbox->show();
313 hbox->pack_end(*vbox, false, false);
314 hbox->show();
317 return dynamic_cast<Gtk::Widget *>(hbox);
318 }
321 } /* namespace Extension */
322 } /* namespace Inkscape */
324 /*
325 Local Variables:
326 mode:c++
327 c-file-style:"stroustrup"
328 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
329 indent-tabs-mode:nil
330 fill-column:99
331 End:
332 */
333 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :