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>
28 #include <glibmm/i18n.h>
30 #include "xml/node.h"
31 #include "extension/extension.h"
32 #include "preferences.h"
33 #include "document-private.h"
34 #include "sp-object.h"
36 #include "radiobutton.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,
63 const gchar * guitext,
64 const gchar * desc,
65 const Parameter::_scope_t scope,
66 bool gui_hidden,
67 const gchar * gui_tip,
68 Inkscape::Extension::Extension * ext,
69 Inkscape::XML::Node * xml,
70 AppearanceMode mode) :
71 Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext),
72 _value(0),
73 _mode(mode),
74 choices(0)
75 {
76 // Read XML tree to add enumeration items:
77 // printf("Extension Constructor: ");
78 if (xml != NULL) {
79 Inkscape::XML::Node *child_repr = sp_repr_children(xml);
80 while (child_repr != NULL) {
81 char const * chname = child_repr->name();
82 if (!strcmp(chname, INKSCAPE_EXTENSION_NS "option") || !strcmp(chname, INKSCAPE_EXTENSION_NS "_option")) {
83 Glib::ustring * newguitext = NULL;
84 Glib::ustring * newvalue = NULL;
85 const char * contents = sp_repr_children(child_repr)->content();
87 if (contents != NULL) {
88 // don't translate when 'item' but do translate when '_option'
89 if (!strcmp(chname, INKSCAPE_EXTENSION_NS "_option")) {
90 if (child_repr->attribute("msgctxt") != NULL) {
91 newguitext = new Glib::ustring(g_dpgettext2(NULL, child_repr->attribute("msgctxt"), contents));
92 } else {
93 newguitext = new Glib::ustring(_(contents));
94 }
95 } else {
96 newguitext = new Glib::ustring(contents);
97 }
98 } else
99 continue;
103 const char * val = child_repr->attribute("value");
104 if (val != NULL)
105 newvalue = new Glib::ustring(val);
106 else
107 newvalue = new Glib::ustring(contents);
109 if ( (newguitext) && (newvalue) ) { // logical error if this is not true here
110 choices = g_slist_append( choices, new optionentry(newvalue, newguitext) );
111 }
112 }
113 child_repr = sp_repr_next(child_repr);
114 }
115 }
117 // Initialize _value with the default value from xml
118 // for simplicity : default to the contents of the first xml-child
119 const char * defaultval = NULL;
120 if (choices)
121 defaultval = ((optionentry*) choices->data)->value->c_str();
123 gchar * pref_name = this->pref_name();
124 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
125 Glib::ustring paramval = prefs->getString(extension_pref_root + pref_name);
126 g_free(pref_name);
128 if (!paramval.empty())
129 defaultval = paramval.data();
130 if (defaultval != NULL)
131 _value = g_strdup(defaultval); // allocate space for _value
133 return;
134 }
136 ParamRadioButton::~ParamRadioButton (void)
137 {
138 //destroy choice strings
139 for (GSList * list = choices; list != NULL; list = g_slist_next(list)) {
140 delete (reinterpret_cast<optionentry *>(list->data));
141 }
142 g_slist_free(choices);
144 g_free(_value);
145 }
148 /** \brief A function to set the \c _value
149 \param in The value to set
150 \param doc A document that should be used to set the value.
151 \param node The node where the value may be placed
153 This function sets ONLY the internal value, but it also sets the value
154 in the preferences structure. To put it in the right place, \c PREF_DIR
155 and \c pref_name() are used.
157 To copy the data into _value the old memory must be free'd first.
158 It is important to note that \c g_free handles \c NULL just fine. Then
159 the passed in value is duplicated using \c g_strdup().
160 */
161 const gchar *
162 ParamRadioButton::set (const gchar * in, SPDocument * /*doc*/, Inkscape::XML::Node * /*node*/)
163 {
164 if (in == NULL) return NULL; /* Can't have NULL string */
166 Glib::ustring * settext = NULL;
167 for (GSList * list = choices; list != NULL; list = g_slist_next(list)) {
168 optionentry * entr = reinterpret_cast<optionentry *>(list->data);
169 if ( !entr->guitext->compare(in) ) {
170 settext = entr->value;
171 break; // break out of for loop
172 }
173 }
174 if (settext) {
175 if (_value != NULL) g_free(_value);
176 _value = g_strdup(settext->c_str());
177 gchar * prefname = this->pref_name();
178 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
179 prefs->setString(extension_pref_root + prefname, _value);
180 g_free(prefname);
181 }
183 return _value;
184 }
187 /**
188 \brief A function to get the current value of the parameter in a string form
189 \return A string with the 'value' as command line argument
190 */
191 void
192 ParamRadioButton::string (std::string &string)
193 {
194 string += _value;
195 return;
196 }
198 /** \brief A special radiobutton class to use in ParamRadioButton */
199 class ParamRadioButtonWdg : public Gtk::RadioButton {
200 private:
201 ParamRadioButton * _pref;
202 SPDocument * _doc;
203 Inkscape::XML::Node * _node;
204 sigc::signal<void> * _changeSignal;
205 public:
206 /** \brief Build a string preference for the given parameter
207 \param pref Where to put the radiobutton's string when it is selected.
208 */
209 ParamRadioButtonWdg ( Gtk::RadioButtonGroup& group, const Glib::ustring& label,
210 ParamRadioButton * pref, SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal ) :
211 Gtk::RadioButton(group, label), _pref(pref), _doc(doc), _node(node), _changeSignal(changeSignal) {
212 add_changesignal();
213 };
214 ParamRadioButtonWdg ( const Glib::ustring& label,
215 ParamRadioButton * pref, SPDocument * doc, Inkscape::XML::Node * node , sigc::signal<void> * changeSignal) :
216 Gtk::RadioButton(label), _pref(pref), _doc(doc), _node(node), _changeSignal(changeSignal) {
217 add_changesignal();
218 };
219 void add_changesignal() {
220 this->signal_toggled().connect(sigc::mem_fun(this, &ParamRadioButtonWdg::changed));
221 };
222 void changed (void);
223 };
225 /** \brief Respond to the selected radiobutton changing
227 This function responds to the radiobutton selection changing by grabbing the value
228 from the text box and putting it in the parameter.
229 */
230 void
231 ParamRadioButtonWdg::changed (void)
232 {
233 if (this->get_active()) {
234 Glib::ustring data = this->get_label();
235 _pref->set(data.c_str(), _doc, _node);
236 }
237 if (_changeSignal != NULL) {
238 _changeSignal->emit();
239 }
240 }
243 class ComboWdg : public Gtk::ComboBoxText {
244 public:
245 ComboWdg(ParamRadioButton* base, SPDocument * doc, Inkscape::XML::Node * node) :
246 Gtk::ComboBoxText(),
247 base(base),
248 doc(doc),
249 node(node)
250 {
251 }
252 virtual ~ComboWdg() {}
254 protected:
255 ParamRadioButton* base;
256 SPDocument* doc;
257 Inkscape::XML::Node* node;
259 virtual void on_changed() {
260 if ( base ) {
261 base->set(get_active_text().c_str(), doc, node);
262 }
263 }
264 };
266 /**
267 \brief Creates a combobox widget for an enumeration parameter
268 */
269 Gtk::Widget *
270 ParamRadioButton::get_widget (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal)
271 {
272 if (_gui_hidden) return NULL;
274 Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4));
275 Gtk::VBox * vbox = Gtk::manage(new Gtk::VBox(false, 0));
277 Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_LEFT, Gtk::ALIGN_TOP));
278 label->show();
279 hbox->pack_start(*label, false, false);
281 Gtk::ComboBoxText* cbt = 0;
282 bool comboSet = false;
283 if (_mode == MINIMAL) {
284 cbt = Gtk::manage(new ComboWdg(this, doc, node));
285 cbt->show();
286 vbox->pack_start(*cbt, false, false);
287 }
289 // add choice strings as radiobuttons
290 // and select last selected option (_value)
291 Gtk::RadioButtonGroup group;
292 for (GSList * list = choices; list != NULL; list = g_slist_next(list)) {
293 optionentry * entr = reinterpret_cast<optionentry *>(list->data);
294 Glib::ustring * text = entr->guitext;
295 switch ( _mode ) {
296 case MINIMAL:
297 {
298 cbt->append_text(*text);
299 if (!entr->value->compare(_value)) {
300 cbt->set_active_text(*text);
301 comboSet = true;
302 }
303 }
304 break;
305 case COMPACT:
306 case FULL:
307 {
308 ParamRadioButtonWdg * radio = Gtk::manage(new ParamRadioButtonWdg(group, *text, this, doc, node, changeSignal));
309 radio->show();
310 vbox->pack_start(*radio, true, true);
311 if (!entr->value->compare(_value)) {
312 radio->set_active();
313 }
314 }
315 break;
316 }
317 }
319 if ( (_mode == MINIMAL) && !comboSet) {
320 cbt->set_active(0);
321 }
323 vbox->show();
324 hbox->pack_end(*vbox, false, false);
325 hbox->show();
328 return dynamic_cast<Gtk::Widget *>(hbox);
329 }
332 } /* namespace Extension */
333 } /* namespace Inkscape */
335 /*
336 Local Variables:
337 mode:c++
338 c-file-style:"stroustrup"
339 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
340 indent-tabs-mode:nil
341 fill-column:99
342 End:
343 */
344 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :