1 /** \file
2 *
3 *
4 * Authors:
5 * Johan Engelen <j.b.c.engelen@utwente.nl>
6 * bulia byak <buliabyak@users.sf.net>
7 * Bryce W. Harrington <bryce@bryceharrington.org>
8 * Lauris Kaplinski <lauris@kaplinski.com>
9 * Jon Phillips <jon@rejon.org>
10 * Ralf Stephan <ralf@ark.in-berlin.de> (Gtkmm)
11 *
12 * Copyright (C) 2000 - 2007 Authors
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 "ui/widget/color-picker.h"
23 #include "ui/widget/registry.h"
24 #include "ui/widget/scalar-unit.h"
25 #include "ui/widget/point.h"
26 #include "ui/widget/random.h"
27 #include "widgets/spinbutton-events.h"
29 #include "helper/units.h"
30 #include "xml/repr.h"
31 #include "svg/svg-color.h"
32 #include "svg/stringstream.h"
34 #include "inkscape.h"
35 #include "document.h"
36 #include "desktop-handles.h"
37 #include "sp-namedview.h"
39 #include "registered-widget.h"
40 #include "verbs.h"
42 // for interruptability bug:
43 #include "display/sp-canvas.h"
45 namespace Inkscape {
46 namespace UI {
47 namespace Widget {
49 //===================================================
51 //---------------------------------------------------
54 void
55 RegisteredWidget::write_to_xml(const char * svgstr)
56 {
57 // Use local repr here. When repr is specified, use that one, but
58 // if repr==NULL, get the repr of namedview of active desktop.
59 Inkscape::XML::Node *local_repr = repr;
60 SPDocument *local_doc = doc;
61 if (!local_repr) {
62 // no repr specified, use active desktop's namedview's repr
63 SPDesktop* dt = SP_ACTIVE_DESKTOP;
64 local_repr = SP_OBJECT_REPR (sp_desktop_namedview(dt));
65 local_doc = sp_desktop_document(dt);
66 }
68 bool saved = sp_document_get_undo_sensitive (local_doc);
69 sp_document_set_undo_sensitive (local_doc, false);
71 if (!write_undo) local_repr->setAttribute(_key.c_str(), svgstr);
72 local_doc->rroot->setAttribute("sodipodi:modified", "true");
74 sp_document_set_undo_sensitive (local_doc, saved);
75 if (write_undo) {
76 local_repr->setAttribute(_key.c_str(), svgstr);
77 sp_document_done (local_doc, event_type, event_description);
78 }
79 }
82 //====================================================
84 RegisteredCheckButton::RegisteredCheckButton()
85 : _button(0),
86 setProgrammatically(false)
87 {
88 }
90 RegisteredCheckButton::~RegisteredCheckButton()
91 {
92 _toggled_connection.disconnect();
93 if (_button) delete _button;
94 }
96 void
97 RegisteredCheckButton::init (const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, Registry& wr, bool right, Inkscape::XML::Node* repr_in, SPDocument *doc_in)
98 {
99 init_parent(key, wr, repr_in, doc_in);
101 _button = new Gtk::CheckButton;
102 _tt.set_tip (*_button, tip);
103 Gtk::Label *l = new Gtk::Label (label);
104 l->set_use_underline (true);
105 _button->add (*manage (l));
106 _button->set_alignment (right? 1.0 : 0.0, 0.5);
107 _toggled_connection = _button->signal_toggled().connect (sigc::mem_fun (*this, &RegisteredCheckButton::on_toggled));
108 }
110 void
111 RegisteredCheckButton::setActive (bool b)
112 {
113 // FIXME: for some reason, this function is also called when user clicks. then setProgrammatically should not be set!
114 setProgrammatically = true;
115 _button->set_active (b);
116 //The slave button is greyed out if the master button is unchecked
117 for (std::list<Gtk::ToggleButton*>::const_iterator i = _slavebuttons.begin(); i != _slavebuttons.end(); i++) {
118 (*i)->set_sensitive(b);
119 }
120 }
122 void
123 RegisteredCheckButton::on_toggled()
124 {
125 if (setProgrammatically) {
126 setProgrammatically = false;
127 return;
128 }
130 if (_wr->isUpdating())
131 return;
133 _wr->setUpdating (true);
135 write_to_xml(_button->get_active() ? "true" : "false");
136 //The slave button is greyed out if the master button is unchecked
137 for (std::list<Gtk::ToggleButton*>::const_iterator i = _slavebuttons.begin(); i != _slavebuttons.end(); i++) {
138 (*i)->set_sensitive(_button->get_active());
139 }
141 _wr->setUpdating (false);
142 }
144 RegisteredUnitMenu::RegisteredUnitMenu()
145 : _label(0), _sel(0)
146 {
147 }
149 RegisteredUnitMenu::~RegisteredUnitMenu()
150 {
151 _changed_connection.disconnect();
152 if (_label) delete _label;
153 if (_sel) delete _sel;
154 }
156 void
157 RegisteredUnitMenu::init (const Glib::ustring& label, const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in, SPDocument *doc_in)
158 {
159 init_parent(key, wr, repr_in, doc_in);
161 _label = new Gtk::Label (label, 1.0, 0.5);
162 _label->set_use_underline (true);
163 _sel = new UnitMenu ();
164 _label->set_mnemonic_widget (*_sel);
165 _sel->setUnitType (UNIT_TYPE_LINEAR);
166 _changed_connection = _sel->signal_changed().connect (sigc::mem_fun (*this, &RegisteredUnitMenu::on_changed));
167 }
169 void
170 RegisteredUnitMenu::setUnit (const SPUnit* unit)
171 {
172 _sel->setUnit (sp_unit_get_abbreviation (unit));
173 }
175 void
176 RegisteredUnitMenu::on_changed()
177 {
178 if (_wr->isUpdating())
179 return;
181 Inkscape::SVGOStringStream os;
182 os << _sel->getUnitAbbr();
184 _wr->setUpdating (true);
186 write_to_xml(os.str().c_str());
188 _wr->setUpdating (false);
189 }
192 RegisteredScalarUnit::RegisteredScalarUnit()
193 : _widget(0), _um(0)
194 {
195 }
197 RegisteredScalarUnit::~RegisteredScalarUnit()
198 {
199 if (_widget) delete _widget;
200 _value_changed_connection.disconnect();
201 }
203 void
204 RegisteredScalarUnit::init (const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, const RegisteredUnitMenu &rum, Registry& wr, Inkscape::XML::Node* repr_in, SPDocument *doc_in)
205 {
206 init_parent(key, wr, repr_in, doc_in);
208 _widget = new ScalarUnit (label, tip, UNIT_TYPE_LINEAR, "", "", rum._sel);
209 _widget->initScalar (-1e6, 1e6);
210 _widget->setUnit (rum._sel->getUnitAbbr());
211 _widget->setDigits (2);
212 _um = rum._sel;
213 _value_changed_connection = _widget->signal_value_changed().connect (sigc::mem_fun (*this, &RegisteredScalarUnit::on_value_changed));
214 }
216 ScalarUnit*
217 RegisteredScalarUnit::getSU()
218 {
219 return _widget;
220 }
222 void
223 RegisteredScalarUnit::setValue (double val)
224 {
225 _widget->setValue (val);
226 }
228 void
229 RegisteredScalarUnit::on_value_changed()
230 {
231 if (_widget->setProgrammatically) {
232 _widget->setProgrammatically = false;
233 return;
234 }
236 if (_wr->isUpdating())
237 return;
239 _wr->setUpdating (true);
241 Inkscape::SVGOStringStream os;
242 os << _widget->getValue("");
243 if (_um)
244 os << _um->getUnitAbbr();
246 write_to_xml(os.str().c_str());
248 _wr->setUpdating (false);
249 }
252 RegisteredScalar::RegisteredScalar()
253 {
254 _widget = NULL;
255 }
257 RegisteredScalar::~RegisteredScalar()
258 {
259 if (_widget)
260 delete _widget;
262 _value_changed_connection.disconnect();
263 }
265 void
266 RegisteredScalar::init ( const Glib::ustring& label, const Glib::ustring& tip,
267 const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in,
268 SPDocument * doc_in )
269 {
270 init_parent(key, wr, repr_in, doc_in);
272 _widget = new Scalar (label, tip);
273 _widget->setRange (-1e6, 1e6);
274 _widget->setDigits (2);
275 _widget->setIncrements(0.1, 1.0);
276 _value_changed_connection = _widget->signal_value_changed().connect (sigc::mem_fun (*this, &RegisteredScalar::on_value_changed));
277 }
279 Scalar*
280 RegisteredScalar::getS()
281 {
282 return _widget;
283 }
285 void
286 RegisteredScalar::setValue (double val)
287 {
288 _widget->setValue (val);
289 }
291 void
292 RegisteredScalar::on_value_changed()
293 {
294 if (_widget->setProgrammatically) {
295 _widget->setProgrammatically = false;
296 return;
297 }
299 if (_wr->isUpdating()) {
300 return;
301 }
302 _wr->setUpdating (true);
304 Inkscape::SVGOStringStream os;
305 os << _widget->getValue();
307 _widget->set_sensitive(false);
308 write_to_xml(os.str().c_str());
309 _widget->set_sensitive(true);
311 _wr->setUpdating (false);
312 }
315 RegisteredColorPicker::RegisteredColorPicker()
316 : _label(0), _cp(0)
317 {
318 }
320 RegisteredColorPicker::~RegisteredColorPicker()
321 {
322 _changed_connection.disconnect();
323 if (_cp) delete _cp;
324 if (_label) delete _label;
325 }
327 void
328 RegisteredColorPicker::init (const Glib::ustring& label, const Glib::ustring& title, const Glib::ustring& tip, const Glib::ustring& ckey, const Glib::ustring& akey, Registry& wr, Inkscape::XML::Node* repr_in, SPDocument *doc_in)
329 {
330 init_parent("", wr, repr_in, doc_in);
332 _label = new Gtk::Label (label, 1.0, 0.5);
333 _label->set_use_underline (true);
334 _cp = new ColorPicker (title,tip,0,true);
335 _label->set_mnemonic_widget (*_cp);
336 _ckey = ckey;
337 _akey = akey;
338 _changed_connection = _cp->connectChanged (sigc::mem_fun (*this, &RegisteredColorPicker::on_changed));
339 }
341 void
342 RegisteredColorPicker::setRgba32 (guint32 rgba)
343 {
344 _cp->setRgba32 (rgba);
345 }
347 void
348 RegisteredColorPicker::closeWindow()
349 {
350 _cp->closeWindow();
351 }
353 void
354 RegisteredColorPicker::on_changed (guint32 rgba)
355 {
356 if (_wr->isUpdating())
357 return;
359 _wr->setUpdating (true);
361 // Use local repr here. When repr is specified, use that one, but
362 // if repr==NULL, get the repr of namedview of active desktop.
363 Inkscape::XML::Node *local_repr = repr;
364 SPDocument *local_doc = doc;
365 if (!local_repr) {
366 // no repr specified, use active desktop's namedview's repr
367 SPDesktop *dt = SP_ACTIVE_DESKTOP;
368 if (!dt)
369 return;
370 local_repr = SP_OBJECT_REPR (sp_desktop_namedview(dt));
371 local_doc = sp_desktop_document(dt);
372 }
374 gchar c[32];
375 sp_svg_write_color(c, sizeof(c), rgba);
376 bool saved = sp_document_get_undo_sensitive (local_doc);
377 sp_document_set_undo_sensitive (local_doc, false);
378 local_repr->setAttribute(_ckey.c_str(), c);
379 sp_repr_set_css_double(local_repr, _akey.c_str(), (rgba & 0xff) / 255.0);
380 local_doc->rroot->setAttribute("sodipodi:modified", "true");
381 sp_document_set_undo_sensitive (local_doc, saved);
382 sp_document_done (local_doc, SP_VERB_NONE,
383 /* TODO: annotate */ "registered-widget.cpp: RegisteredColorPicker::on_changed");
385 _wr->setUpdating (false);
386 }
388 RegisteredSuffixedInteger::RegisteredSuffixedInteger()
389 : _label(0),
390 setProgrammatically(false),
391 _sb(0),
392 _adj(0.0,0.0,100.0,1.0,1.0,1.0),
393 _suffix(0)
394 {
395 }
397 RegisteredSuffixedInteger::~RegisteredSuffixedInteger()
398 {
399 _changed_connection.disconnect();
400 if (_label) delete _label;
401 if (_suffix) delete _suffix;
402 if (_sb) delete _sb;
403 }
405 void
406 RegisteredSuffixedInteger::init (const Glib::ustring& label, const Glib::ustring& suffix, const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in, SPDocument *doc_in)
407 {
408 init_parent(key, wr, repr_in, doc_in);
410 _label = new Gtk::Label (label);
411 _label->set_alignment (1.0, 0.5);
412 _label->set_use_underline();
413 _sb = new Gtk::SpinButton (_adj, 1.0, 0);
414 _label->set_mnemonic_widget (*_sb);
415 _suffix = new Gtk::Label (suffix);
416 _hbox.pack_start (*_sb, true, true, 0);
417 _hbox.pack_start (*_suffix, false, false, 0);
419 _changed_connection = _adj.signal_value_changed().connect (sigc::mem_fun(*this, &RegisteredSuffixedInteger::on_value_changed));
420 }
422 void
423 RegisteredSuffixedInteger::setValue (int i)
424 {
425 setProgrammatically = true;
426 _adj.set_value (i);
427 }
429 void
430 RegisteredSuffixedInteger::on_value_changed()
431 {
432 if (setProgrammatically) {
433 setProgrammatically = false;
434 return;
435 }
437 if (_wr->isUpdating())
438 return;
440 _wr->setUpdating (true);
442 Inkscape::SVGOStringStream os;
443 int value = int(_adj.get_value());
444 os << value;
446 write_to_xml(os.str().c_str());
448 _wr->setUpdating (false);
449 }
451 RegisteredRadioButtonPair::RegisteredRadioButtonPair()
452 : _hbox(0),
453 setProgrammatically(false)
454 {
455 }
457 RegisteredRadioButtonPair::~RegisteredRadioButtonPair()
458 {
459 _changed_connection.disconnect();
460 }
462 void
463 RegisteredRadioButtonPair::init (const Glib::ustring& label,
464 const Glib::ustring& label1, const Glib::ustring& label2,
465 const Glib::ustring& tip1, const Glib::ustring& tip2,
466 const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in, SPDocument *doc_in)
467 {
468 init_parent(key, wr, repr_in, doc_in);
470 _hbox = new Gtk::HBox;
471 _hbox->add (*manage (new Gtk::Label (label)));
472 _rb1 = manage (new Gtk::RadioButton (label1, true));
473 _hbox->add (*_rb1);
474 Gtk::RadioButtonGroup group = _rb1->get_group();
475 _rb2 = manage (new Gtk::RadioButton (group, label2, true));
476 _hbox->add (*_rb2);
477 _rb2->set_active();
478 _tt.set_tip (*_rb1, tip1);
479 _tt.set_tip (*_rb2, tip2);
480 _changed_connection = _rb1->signal_toggled().connect (sigc::mem_fun (*this, &RegisteredRadioButtonPair::on_value_changed));
481 }
483 void
484 RegisteredRadioButtonPair::setValue (bool second)
485 {
486 setProgrammatically = true;
487 if (second) _rb2->set_active();
488 else _rb1->set_active();
489 }
491 void
492 RegisteredRadioButtonPair::on_value_changed()
493 {
494 if (setProgrammatically) {
495 setProgrammatically = false;
496 return;
497 }
499 if (_wr->isUpdating())
500 return;
502 _wr->setUpdating (true);
504 bool second = _rb2->get_active();
505 write_to_xml(second ? "true" : "false");
507 _wr->setUpdating (false);
508 }
510 /*#########################################
511 * Registered POINT
512 */
514 RegisteredPoint::RegisteredPoint()
515 {
516 _widget = NULL;
517 }
519 RegisteredPoint::~RegisteredPoint()
520 {
521 if (_widget)
522 delete _widget;
524 _value_x_changed_connection.disconnect();
525 _value_y_changed_connection.disconnect();
526 }
528 void
529 RegisteredPoint::init ( const Glib::ustring& label, const Glib::ustring& tip,
530 const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in,
531 SPDocument* doc_in )
532 {
533 init_parent(key, wr, repr_in, doc_in);
535 _widget = new Point (label, tip);
536 _widget->setRange (-1e6, 1e6);
537 _widget->setDigits (2);
538 _widget->setIncrements(0.1, 1.0);
539 _value_x_changed_connection = _widget->signal_x_value_changed().connect (sigc::mem_fun (*this, &RegisteredPoint::on_value_changed));
540 _value_y_changed_connection = _widget->signal_y_value_changed().connect (sigc::mem_fun (*this, &RegisteredPoint::on_value_changed));
541 }
543 Point*
544 RegisteredPoint::getPoint()
545 {
546 return _widget;
547 }
549 void
550 RegisteredPoint::setValue (double xval, double yval)
551 {
552 _widget->setValue(xval, yval);
553 }
555 void
556 RegisteredPoint::on_value_changed()
557 {
558 if (_widget->setProgrammatically()) {
559 _widget->clearProgrammatically();
560 return;
561 }
563 if (_wr->isUpdating())
564 return;
566 _wr->setUpdating (true);
568 Inkscape::SVGOStringStream os;
569 os << _widget->getXValue() << "," << _widget->getYValue();
571 write_to_xml(os.str().c_str());
573 _wr->setUpdating (false);
574 }
576 /*#########################################
577 * Registered RANDOM
578 */
580 RegisteredRandom::RegisteredRandom()
581 {
582 _widget = NULL;
583 }
585 RegisteredRandom::~RegisteredRandom()
586 {
587 if (_widget)
588 delete _widget;
590 _value_changed_connection.disconnect();
591 _reseeded_connection.disconnect();
592 }
594 void
595 RegisteredRandom::init ( const Glib::ustring& label, const Glib::ustring& tip,
596 const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in,
597 SPDocument * doc_in )
598 {
599 init_parent(key, wr, repr_in, doc_in);
601 _widget = new Random (label, tip);
602 _widget->setRange (-1e6, 1e6);
603 _widget->setDigits (2);
604 _widget->setIncrements(0.1, 1.0);
605 _value_changed_connection = _widget->signal_value_changed().connect (sigc::mem_fun (*this, &RegisteredRandom::on_value_changed));
606 _reseeded_connection = _widget->signal_reseeded.connect(sigc::mem_fun(*this, &RegisteredRandom::on_value_changed));
607 }
609 Random*
610 RegisteredRandom::getR()
611 {
612 return _widget;
613 }
615 void
616 RegisteredRandom::setValue (double val, long startseed)
617 {
618 _widget->setValue (val);
619 _widget->setStartSeed(startseed);
620 }
622 void
623 RegisteredRandom::on_value_changed()
624 {
625 if (_widget->setProgrammatically) {
626 _widget->setProgrammatically = false;
627 return;
628 }
630 if (_wr->isUpdating())
631 return;
632 _wr->setUpdating (true);
634 // FIXME: gtk bug?
635 // disable interruptibility: see http://inkscape.svn.sourceforge.net/viewvc/inkscape/inkscape/trunk/src/ui/widget/selected-style.cpp?r1=13149&r2=13257&sortby=date
636 SPDesktop* dt = SP_ACTIVE_DESKTOP;
637 sp_canvas_force_full_redraw_after_interruptions(sp_desktop_canvas(dt), 0);
639 Inkscape::SVGOStringStream os;
640 os << _widget->getValue() << ';' << _widget->getStartSeed();
642 write_to_xml(os.str().c_str());
644 // resume interruptibility
645 sp_canvas_end_forced_full_redraws(sp_desktop_canvas(dt));
647 _wr->setUpdating (false);
648 }
651 } // namespace Dialog
652 } // namespace UI
653 } // namespace Inkscape
655 /*
656 Local Variables:
657 mode:c++
658 c-file-style:"stroustrup"
659 c-file-offsets:((innamespace . 0)(inline-open . 0))
660 indent-tabs-mode:nil
661 fill-column:99
662 End:
663 */
664 // vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :