Code

76c3506af0fbf94400341b9537ed84cc87c6db26
[inkscape.git] / src / extension / param / radiobutton.cpp
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;
126 ParamRadioButton::~ParamRadioButton (void)
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);
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*/)
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;
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)
183     string += _value;
184     return;
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)
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     }
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)
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);
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 :