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 * Abhishek Sharma
12 *
13 * Copyright (C) 2000 - 2007 Authors
14 *
15 * Released under GNU GPL. Read the file 'COPYING' for more information
16 */
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
22 #include "registered-widget.h"
24 #include "ui/widget/color-picker.h"
25 #include "ui/widget/registry.h"
26 #include "ui/widget/scalar-unit.h"
27 #include "ui/widget/point.h"
28 #include "ui/widget/random.h"
29 #include "widgets/spinbutton-events.h"
31 #include "helper/units.h"
32 #include "xml/repr.h"
33 #include "svg/svg-color.h"
34 #include "svg/stringstream.h"
36 #include "verbs.h"
38 // for interruptability bug:
39 #include "display/sp-canvas.h"
41 namespace Inkscape {
42 namespace UI {
43 namespace Widget {
45 /*#########################################
46 * Registered CHECKBUTTON
47 */
49 RegisteredCheckButton::~RegisteredCheckButton()
50 {
51 _toggled_connection.disconnect();
52 }
54 RegisteredCheckButton::RegisteredCheckButton (const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, Registry& wr, bool right, Inkscape::XML::Node* repr_in, SPDocument *doc_in)
55 : RegisteredWidget<Gtk::CheckButton>()
56 {
57 init_parent(key, wr, repr_in, doc_in);
59 setProgrammatically = false;
61 _tt.set_tip (*this, tip);
62 Gtk::Label *l = new Gtk::Label (label);
63 l->set_use_underline (true);
64 add (*manage (l));
65 set_alignment (right? 1.0 : 0.0, 0.5);
66 _toggled_connection = signal_toggled().connect (sigc::mem_fun (*this, &RegisteredCheckButton::on_toggled));
67 }
69 void
70 RegisteredCheckButton::setActive (bool b)
71 {
72 setProgrammatically = true;
73 set_active (b);
74 //The slave button is greyed out if the master button is unchecked
75 for (std::list<Gtk::Widget*>::const_iterator i = _slavewidgets.begin(); i != _slavewidgets.end(); i++) {
76 (*i)->set_sensitive(b);
77 }
78 setProgrammatically = false;
79 }
81 void
82 RegisteredCheckButton::on_toggled()
83 {
84 if (setProgrammatically) {
85 setProgrammatically = false;
86 return;
87 }
89 if (_wr->isUpdating())
90 return;
91 _wr->setUpdating (true);
93 write_to_xml(get_active() ? "true" : "false");
94 //The slave button is greyed out if the master button is unchecked
95 for (std::list<Gtk::Widget*>::const_iterator i = _slavewidgets.begin(); i != _slavewidgets.end(); i++) {
96 (*i)->set_sensitive(get_active());
97 }
99 _wr->setUpdating (false);
100 }
103 /*#########################################
104 * Registered UNITMENU
105 */
107 RegisteredUnitMenu::~RegisteredUnitMenu()
108 {
109 _changed_connection.disconnect();
110 }
112 RegisteredUnitMenu::RegisteredUnitMenu (const Glib::ustring& label, const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in, SPDocument *doc_in)
113 : RegisteredWidget<Labelled> (label, "" /*tooltip*/, new UnitMenu())
114 {
115 init_parent(key, wr, repr_in, doc_in);
117 getUnitMenu()->setUnitType (UNIT_TYPE_LINEAR);
118 _changed_connection = getUnitMenu()->signal_changed().connect (sigc::mem_fun (*this, &RegisteredUnitMenu::on_changed));
119 }
121 void
122 RegisteredUnitMenu::setUnit (const SPUnit* unit)
123 {
124 getUnitMenu()->setUnit (sp_unit_get_abbreviation (unit));
125 }
127 void
128 RegisteredUnitMenu::on_changed()
129 {
130 if (_wr->isUpdating())
131 return;
133 Inkscape::SVGOStringStream os;
134 os << getUnitMenu()->getUnitAbbr();
136 _wr->setUpdating (true);
138 write_to_xml(os.str().c_str());
140 _wr->setUpdating (false);
141 }
144 /*#########################################
145 * Registered SCALARUNIT
146 */
148 RegisteredScalarUnit::~RegisteredScalarUnit()
149 {
150 _value_changed_connection.disconnect();
151 }
153 RegisteredScalarUnit::RegisteredScalarUnit (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)
154 : RegisteredWidget<ScalarUnit>(label, tip, UNIT_TYPE_LINEAR, "", "", rum.getUnitMenu()),
155 _um(0)
156 {
157 init_parent(key, wr, repr_in, doc_in);
159 setProgrammatically = false;
161 initScalar (-1e6, 1e6);
162 setUnit (rum.getUnitMenu()->getUnitAbbr());
163 setDigits (2);
164 _um = rum.getUnitMenu();
165 _value_changed_connection = signal_value_changed().connect (sigc::mem_fun (*this, &RegisteredScalarUnit::on_value_changed));
166 }
169 void
170 RegisteredScalarUnit::on_value_changed()
171 {
172 if (setProgrammatically) {
173 setProgrammatically = false;
174 return;
175 }
177 if (_wr->isUpdating())
178 return;
180 _wr->setUpdating (true);
182 Inkscape::SVGOStringStream os;
183 os << getValue("");
184 if (_um)
185 os << _um->getUnitAbbr();
187 write_to_xml(os.str().c_str());
189 _wr->setUpdating (false);
190 }
193 /*#########################################
194 * Registered SCALAR
195 */
197 RegisteredScalar::~RegisteredScalar()
198 {
199 _value_changed_connection.disconnect();
200 }
202 RegisteredScalar::RegisteredScalar ( const Glib::ustring& label, const Glib::ustring& tip,
203 const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in,
204 SPDocument * doc_in )
205 : RegisteredWidget<Scalar>(label, tip)
206 {
207 init_parent(key, wr, repr_in, doc_in);
209 setProgrammatically = false;
211 setRange (-1e6, 1e6);
212 setDigits (2);
213 setIncrements(0.1, 1.0);
214 _value_changed_connection = signal_value_changed().connect (sigc::mem_fun (*this, &RegisteredScalar::on_value_changed));
215 }
217 void
218 RegisteredScalar::on_value_changed()
219 {
220 if (setProgrammatically) {
221 setProgrammatically = false;
222 return;
223 }
225 if (_wr->isUpdating()) {
226 return;
227 }
228 _wr->setUpdating (true);
230 Inkscape::SVGOStringStream os;
231 os << getValue();
233 set_sensitive(false);
234 write_to_xml(os.str().c_str());
235 set_sensitive(true);
237 _wr->setUpdating (false);
238 }
241 /*#########################################
242 * Registered TEXT
243 */
245 RegisteredText::~RegisteredText()
246 {
247 _activate_connection.disconnect();
248 }
250 RegisteredText::RegisteredText ( const Glib::ustring& label, const Glib::ustring& tip,
251 const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in,
252 SPDocument * doc_in )
253 : RegisteredWidget<Text>(label, tip)
254 {
255 init_parent(key, wr, repr_in, doc_in);
257 setProgrammatically = false;
259 setText("");
260 _activate_connection = signal_activate().connect (sigc::mem_fun (*this, &RegisteredText::on_activate));
261 }
263 void
264 RegisteredText::on_activate()
265 {
266 if (setProgrammatically) {
267 setProgrammatically = false;
268 return;
269 }
271 if (_wr->isUpdating()) {
272 return;
273 }
274 _wr->setUpdating (true);
276 Inkscape::SVGOStringStream os;
277 os << getText();
279 set_sensitive(false);
280 write_to_xml(os.str().c_str());
281 set_sensitive(true);
283 setText(os.str().c_str());
285 _wr->setUpdating (false);
286 }
289 /*#########################################
290 * Registered COLORPICKER
291 */
293 RegisteredColorPicker::RegisteredColorPicker(const Glib::ustring& label,
294 const Glib::ustring& title,
295 const Glib::ustring& tip,
296 const Glib::ustring& ckey,
297 const Glib::ustring& akey,
298 Registry& wr,
299 Inkscape::XML::Node* repr_in,
300 SPDocument *doc_in)
301 : RegisteredWidget<ColorPicker> (title, tip, 0, true)
302 {
303 init_parent("", wr, repr_in, doc_in);
305 _label = new Gtk::Label (label, 1.0, 0.5);
306 _label->set_use_underline (true);
307 _label->set_mnemonic_widget (*this);
308 _ckey = ckey;
309 _akey = akey;
310 _changed_connection = connectChanged (sigc::mem_fun (*this, &RegisteredColorPicker::on_changed));
311 }
313 RegisteredColorPicker::~RegisteredColorPicker()
314 {
315 _changed_connection.disconnect();
316 }
318 void
319 RegisteredColorPicker::setRgba32 (guint32 rgba)
320 {
321 ColorPicker::setRgba32 (rgba);
322 }
324 void
325 RegisteredColorPicker::closeWindow()
326 {
327 ColorPicker::closeWindow();
328 }
330 void
331 RegisteredColorPicker::on_changed (guint32 rgba)
332 {
333 if (_wr->isUpdating())
334 return;
336 _wr->setUpdating (true);
338 // Use local repr here. When repr is specified, use that one, but
339 // if repr==NULL, get the repr of namedview of active desktop.
340 Inkscape::XML::Node *local_repr = repr;
341 SPDocument *local_doc = doc;
342 if (!local_repr) {
343 // no repr specified, use active desktop's namedview's repr
344 SPDesktop *dt = SP_ACTIVE_DESKTOP;
345 if (!dt)
346 return;
347 local_repr = SP_OBJECT_REPR (sp_desktop_namedview(dt));
348 local_doc = sp_desktop_document(dt);
349 }
351 gchar c[32];
352 sp_svg_write_color(c, sizeof(c), rgba);
353 bool saved = DocumentUndo::getUndoSensitive(local_doc);
354 DocumentUndo::setUndoSensitive(local_doc, false);
355 local_repr->setAttribute(_ckey.c_str(), c);
356 sp_repr_set_css_double(local_repr, _akey.c_str(), (rgba & 0xff) / 255.0);
357 DocumentUndo::setUndoSensitive(local_doc, saved);
359 local_doc->setModifiedSinceSave();
360 DocumentUndo::done(local_doc, SP_VERB_NONE,
361 /* TODO: annotate */ "registered-widget.cpp: RegisteredColorPicker::on_changed");
363 _wr->setUpdating (false);
364 }
367 /*#########################################
368 * Registered SUFFIXEDINTEGER
369 */
371 RegisteredSuffixedInteger::~RegisteredSuffixedInteger()
372 {
373 _changed_connection.disconnect();
374 }
376 RegisteredSuffixedInteger::RegisteredSuffixedInteger (const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& suffix, const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in, SPDocument *doc_in)
377 : RegisteredWidget<Scalar>(label, tip, 0, suffix),
378 setProgrammatically(false)
379 {
380 init_parent(key, wr, repr_in, doc_in);
382 setRange (0, 1e6);
383 setDigits (0);
384 setIncrements(1, 10);
386 _changed_connection = signal_value_changed().connect (sigc::mem_fun(*this, &RegisteredSuffixedInteger::on_value_changed));
387 }
389 void
390 RegisteredSuffixedInteger::on_value_changed()
391 {
392 if (setProgrammatically) {
393 setProgrammatically = false;
394 return;
395 }
397 if (_wr->isUpdating())
398 return;
400 _wr->setUpdating (true);
402 Inkscape::SVGOStringStream os;
403 os << getValue();
405 write_to_xml(os.str().c_str());
407 _wr->setUpdating (false);
408 }
411 /*#########################################
412 * Registered RADIOBUTTONPAIR
413 */
415 RegisteredRadioButtonPair::~RegisteredRadioButtonPair()
416 {
417 _changed_connection.disconnect();
418 }
420 RegisteredRadioButtonPair::RegisteredRadioButtonPair (const Glib::ustring& label,
421 const Glib::ustring& label1, const Glib::ustring& label2,
422 const Glib::ustring& tip1, const Glib::ustring& tip2,
423 const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in, SPDocument *doc_in)
424 : RegisteredWidget<Gtk::HBox>(),
425 _rb1(NULL),
426 _rb2(NULL)
427 {
428 init_parent(key, wr, repr_in, doc_in);
430 setProgrammatically = false;
432 add (*manage (new Gtk::Label (label)));
433 _rb1 = manage (new Gtk::RadioButton (label1, true));
434 add (*_rb1);
435 Gtk::RadioButtonGroup group = _rb1->get_group();
436 _rb2 = manage (new Gtk::RadioButton (group, label2, true));
437 add (*_rb2);
438 _rb2->set_active();
439 _tt.set_tip (*_rb1, tip1);
440 _tt.set_tip (*_rb2, tip2);
441 _changed_connection = _rb1->signal_toggled().connect (sigc::mem_fun (*this, &RegisteredRadioButtonPair::on_value_changed));
442 }
444 void
445 RegisteredRadioButtonPair::setValue (bool second)
446 {
447 if (!_rb1 || !_rb2)
448 return;
450 setProgrammatically = true;
451 if (second) {
452 _rb2->set_active();
453 } else {
454 _rb1->set_active();
455 }
456 }
458 void
459 RegisteredRadioButtonPair::on_value_changed()
460 {
461 if (setProgrammatically) {
462 setProgrammatically = false;
463 return;
464 }
466 if (_wr->isUpdating())
467 return;
469 _wr->setUpdating (true);
471 bool second = _rb2->get_active();
472 write_to_xml(second ? "true" : "false");
474 _wr->setUpdating (false);
475 }
478 /*#########################################
479 * Registered POINT
480 */
482 RegisteredPoint::~RegisteredPoint()
483 {
484 _value_x_changed_connection.disconnect();
485 _value_y_changed_connection.disconnect();
486 }
488 RegisteredPoint::RegisteredPoint ( const Glib::ustring& label, const Glib::ustring& tip,
489 const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in,
490 SPDocument* doc_in )
491 : RegisteredWidget<Point> (label, tip)
492 {
493 init_parent(key, wr, repr_in, doc_in);
495 setRange (-1e6, 1e6);
496 setDigits (2);
497 setIncrements(0.1, 1.0);
498 _value_x_changed_connection = signal_x_value_changed().connect (sigc::mem_fun (*this, &RegisteredPoint::on_value_changed));
499 _value_y_changed_connection = signal_y_value_changed().connect (sigc::mem_fun (*this, &RegisteredPoint::on_value_changed));
500 }
502 void
503 RegisteredPoint::on_value_changed()
504 {
505 if (setProgrammatically()) {
506 clearProgrammatically();
507 return;
508 }
510 if (_wr->isUpdating())
511 return;
513 _wr->setUpdating (true);
515 Inkscape::SVGOStringStream os;
516 os << getXValue() << "," << getYValue();
518 write_to_xml(os.str().c_str());
520 _wr->setUpdating (false);
521 }
523 /*#########################################
524 * Registered TRANSFORMEDPOINT
525 */
527 RegisteredTransformedPoint::~RegisteredTransformedPoint()
528 {
529 _value_x_changed_connection.disconnect();
530 _value_y_changed_connection.disconnect();
531 }
533 RegisteredTransformedPoint::RegisteredTransformedPoint ( const Glib::ustring& label, const Glib::ustring& tip,
534 const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in,
535 SPDocument* doc_in )
536 : RegisteredWidget<Point> (label, tip),
537 to_svg(Geom::identity())
538 {
539 init_parent(key, wr, repr_in, doc_in);
541 setRange (-1e6, 1e6);
542 setDigits (2);
543 setIncrements(0.1, 1.0);
544 _value_x_changed_connection = signal_x_value_changed().connect (sigc::mem_fun (*this, &RegisteredTransformedPoint::on_value_changed));
545 _value_y_changed_connection = signal_y_value_changed().connect (sigc::mem_fun (*this, &RegisteredTransformedPoint::on_value_changed));
546 }
548 void
549 RegisteredTransformedPoint::setValue(Geom::Point const & p)
550 {
551 Geom::Point new_p = p * to_svg.inverse();
552 Point::setValue(new_p); // the Point widget should display things in canvas coordinates
553 }
555 void
556 RegisteredTransformedPoint::setTransform(Geom::Matrix const & canvas_to_svg)
557 {
558 // check if matrix is singular / has inverse
559 if ( ! canvas_to_svg.isSingular() ) {
560 to_svg = canvas_to_svg;
561 } else {
562 // set back to default
563 to_svg = Geom::identity();
564 }
565 }
567 void
568 RegisteredTransformedPoint::on_value_changed()
569 {
570 if (setProgrammatically()) {
571 clearProgrammatically();
572 return;
573 }
575 if (_wr->isUpdating())
576 return;
578 _wr->setUpdating (true);
580 Geom::Point pos = getValue() * to_svg;
582 Inkscape::SVGOStringStream os;
583 os << pos;
585 write_to_xml(os.str().c_str());
587 _wr->setUpdating (false);
588 }
590 /*#########################################
591 * Registered TRANSFORMEDPOINT
592 */
594 RegisteredVector::~RegisteredVector()
595 {
596 _value_x_changed_connection.disconnect();
597 _value_y_changed_connection.disconnect();
598 }
600 RegisteredVector::RegisteredVector ( const Glib::ustring& label, const Glib::ustring& tip,
601 const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in,
602 SPDocument* doc_in )
603 : RegisteredWidget<Point> (label, tip),
604 _polar_coords(false)
605 {
606 init_parent(key, wr, repr_in, doc_in);
608 setRange (-1e6, 1e6);
609 setDigits (2);
610 setIncrements(0.1, 1.0);
611 _value_x_changed_connection = signal_x_value_changed().connect (sigc::mem_fun (*this, &RegisteredVector::on_value_changed));
612 _value_y_changed_connection = signal_y_value_changed().connect (sigc::mem_fun (*this, &RegisteredVector::on_value_changed));
613 }
615 void
616 RegisteredVector::setValue(Geom::Point const & p)
617 {
618 if (!_polar_coords) {
619 Point::setValue(p);
620 } else {
621 Geom::Point polar;
622 polar[Geom::X] = atan2(p) *180/M_PI;
623 polar[Geom::Y] = p.length();
624 Point::setValue(polar);
625 }
626 }
628 void
629 RegisteredVector::setValue(Geom::Point const & p, Geom::Point const & origin)
630 {
631 RegisteredVector::setValue(p);
632 _origin = origin;
633 }
635 /**
636 * Changes the widgets text to polar coordinates. The SVG output will still be a normal carthesian vector.
637 * Careful: when calling getValue(), the return value's X-coord will be the angle, Y-value will be the distance/length.
638 * After changing the coords type (polar/non-polar), the value has to be reset (setValue).
639 */
640 void
641 RegisteredVector::setPolarCoords(bool polar_coords)
642 {
643 _polar_coords = polar_coords;
644 if (polar_coords) {
645 xwidget.setLabelText("Angle:");
646 ywidget.setLabelText("Distance:");
647 } else {
648 xwidget.setLabelText("X:");
649 ywidget.setLabelText("Y:");
650 }
651 }
653 void
654 RegisteredVector::on_value_changed()
655 {
656 if (setProgrammatically()) {
657 clearProgrammatically();
658 return;
659 }
661 if (_wr->isUpdating())
662 return;
664 _wr->setUpdating (true);
666 Geom::Point origin = _origin;
667 Geom::Point vector = getValue();
668 if (_polar_coords) {
669 vector = Geom::Point::polar(vector[Geom::X]*M_PI/180, vector[Geom::Y]);
670 }
672 Inkscape::SVGOStringStream os;
673 os << origin << " , " << vector;
675 write_to_xml(os.str().c_str());
677 _wr->setUpdating (false);
678 }
680 /*#########################################
681 * Registered RANDOM
682 */
684 RegisteredRandom::~RegisteredRandom()
685 {
686 _value_changed_connection.disconnect();
687 _reseeded_connection.disconnect();
688 }
690 RegisteredRandom::RegisteredRandom ( const Glib::ustring& label, const Glib::ustring& tip,
691 const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in,
692 SPDocument * doc_in )
693 : RegisteredWidget<Random> (label, tip)
694 {
695 init_parent(key, wr, repr_in, doc_in);
697 setProgrammatically = false;
699 setRange (-1e6, 1e6);
700 setDigits (2);
701 setIncrements(0.1, 1.0);
702 _value_changed_connection = signal_value_changed().connect (sigc::mem_fun (*this, &RegisteredRandom::on_value_changed));
703 _reseeded_connection = signal_reseeded.connect(sigc::mem_fun(*this, &RegisteredRandom::on_value_changed));
704 }
706 void
707 RegisteredRandom::setValue (double val, long startseed)
708 {
709 Scalar::setValue (val);
710 setStartSeed(startseed);
711 }
713 void
714 RegisteredRandom::on_value_changed()
715 {
716 if (setProgrammatically) {
717 setProgrammatically = false;
718 return;
719 }
721 if (_wr->isUpdating()) {
722 return;
723 }
724 _wr->setUpdating (true);
726 Inkscape::SVGOStringStream os;
727 os << getValue() << ';' << getStartSeed();
729 set_sensitive(false);
730 write_to_xml(os.str().c_str());
731 set_sensitive(true);
733 _wr->setUpdating (false);
734 }
736 } // namespace Dialog
737 } // namespace UI
738 } // namespace Inkscape
740 /*
741 Local Variables:
742 mode:c++
743 c-file-style:"stroustrup"
744 c-file-offsets:((innamespace . 0)(inline-open . 0))
745 indent-tabs-mode:nil
746 fill-column:99
747 End:
748 */
749 // vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :