1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Authors:
4  *   Johan Engelen <j.b.c.engelen@utwente.nl>
5  *   bulia byak <buliabyak@users.sf.net>
6  *   Bryce W. Harrington <bryce@bryceharrington.org>
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *   Jon Phillips <jon@rejon.org>
9  *   Ralf Stephan <ralf@ark.in-berlin.de> (Gtkmm)
10  *   Abhishek Sharma
11  *
12  * Copyright (C) 2000 - 2007 Authors
13  *
14  * Released under GNU GPL v2+, read the file 'COPYING' for more information.
15  */
16 
17 #include "registered-widget.h"
18 
19 #include <gtkmm/radiobutton.h>
20 
21 #include "verbs.h"
22 
23 #include "object/sp-root.h"
24 
25 #include "svg/svg-color.h"
26 #include "svg/stringstream.h"
27 
28 #include <glibmm/i18n.h>
29 
30 namespace Inkscape {
31 namespace UI {
32 namespace Widget {
33 
34 /*#########################################
35  * Registered CHECKBUTTON
36  */
37 
~RegisteredCheckButton()38 RegisteredCheckButton::~RegisteredCheckButton()
39 {
40     _toggled_connection.disconnect();
41 }
42 
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,char const * active_str,char const * inactive_str)43 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, char const *active_str, char const *inactive_str)
44     : RegisteredWidget<Gtk::CheckButton>()
45     , _active_str(active_str)
46     , _inactive_str(inactive_str)
47 {
48     init_parent(key, wr, repr_in, doc_in);
49 
50     setProgrammatically = false;
51 
52     set_tooltip_text (tip);
53     Gtk::Label *l = new Gtk::Label();
54     l->set_markup(label);
55     l->set_use_underline (true);
56     add (*manage (l));
57 
58     if(right) set_halign(Gtk::ALIGN_END);
59     else      set_halign(Gtk::ALIGN_START);
60 
61     set_valign(Gtk::ALIGN_CENTER);
62     _toggled_connection = signal_toggled().connect (sigc::mem_fun (*this, &RegisteredCheckButton::on_toggled));
63 }
64 
65 void
setActive(bool b)66 RegisteredCheckButton::setActive (bool b)
67 {
68     setProgrammatically = true;
69     set_active (b);
70     //The slave button is greyed out if the master button is unchecked
71     for (std::list<Gtk::Widget*>::const_iterator i = _slavewidgets.begin(); i != _slavewidgets.end(); ++i) {
72         (*i)->set_sensitive(b);
73     }
74     setProgrammatically = false;
75 }
76 
77 void
on_toggled()78 RegisteredCheckButton::on_toggled()
79 {
80     if (setProgrammatically) {
81         setProgrammatically = false;
82         return;
83     }
84 
85     if (_wr->isUpdating())
86         return;
87     _wr->setUpdating (true);
88 
89     write_to_xml(get_active() ? _active_str : _inactive_str);
90     //The slave button is greyed out if the master button is unchecked
91     for (std::list<Gtk::Widget*>::const_iterator i = _slavewidgets.begin(); i != _slavewidgets.end(); ++i) {
92         (*i)->set_sensitive(get_active());
93     }
94 
95     _wr->setUpdating (false);
96 }
97 
98 /*#########################################
99  * Registered TOGGLEBUTTON
100  */
101 
~RegisteredToggleButton()102 RegisteredToggleButton::~RegisteredToggleButton()
103 {
104     _toggled_connection.disconnect();
105 }
106 
RegisteredToggleButton(const Glib::ustring &,const Glib::ustring & tip,const Glib::ustring & key,Registry & wr,bool right,Inkscape::XML::Node * repr_in,SPDocument * doc_in,char const * icon_active,char const * icon_inactive)107 RegisteredToggleButton::RegisteredToggleButton (const Glib::ustring& /*label*/, const Glib::ustring& tip, const Glib::ustring& key, Registry& wr, bool right, Inkscape::XML::Node* repr_in, SPDocument *doc_in, char const *icon_active, char const *icon_inactive)
108     : RegisteredWidget<Gtk::ToggleButton>()
109 {
110     init_parent(key, wr, repr_in, doc_in);
111     setProgrammatically = false;
112     set_tooltip_text (tip);
113 
114     if(right) set_halign(Gtk::ALIGN_END);
115     else      set_halign(Gtk::ALIGN_START);
116 
117     set_valign(Gtk::ALIGN_CENTER);
118     _toggled_connection = signal_toggled().connect (sigc::mem_fun (*this, &RegisteredToggleButton::on_toggled));
119 }
120 
121 void
setActive(bool b)122 RegisteredToggleButton::setActive (bool b)
123 {
124     setProgrammatically = true;
125     set_active (b);
126     //The slave button is greyed out if the master button is untoggled
127     for (std::list<Gtk::Widget*>::const_iterator i = _slavewidgets.begin(); i != _slavewidgets.end(); ++i) {
128         (*i)->set_sensitive(b);
129     }
130     setProgrammatically = false;
131 }
132 
133 void
on_toggled()134 RegisteredToggleButton::on_toggled()
135 {
136     if (setProgrammatically) {
137         setProgrammatically = false;
138         return;
139     }
140 
141     if (_wr->isUpdating())
142         return;
143     _wr->setUpdating (true);
144 
145     write_to_xml(get_active() ? "true" : "false");
146     //The slave button is greyed out if the master button is untoggled
147     for (std::list<Gtk::Widget*>::const_iterator i = _slavewidgets.begin(); i != _slavewidgets.end(); ++i) {
148         (*i)->set_sensitive(get_active());
149     }
150 
151     _wr->setUpdating (false);
152 }
153 
154 /*#########################################
155  * Registered UNITMENU
156  */
157 
~RegisteredUnitMenu()158 RegisteredUnitMenu::~RegisteredUnitMenu()
159 {
160     _changed_connection.disconnect();
161 }
162 
RegisteredUnitMenu(const Glib::ustring & label,const Glib::ustring & key,Registry & wr,Inkscape::XML::Node * repr_in,SPDocument * doc_in)163 RegisteredUnitMenu::RegisteredUnitMenu (const Glib::ustring& label, const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in, SPDocument *doc_in)
164     :  RegisteredWidget<Labelled> (label, "" /*tooltip*/, new UnitMenu())
165 {
166     init_parent(key, wr, repr_in, doc_in);
167 
168     getUnitMenu()->setUnitType (UNIT_TYPE_LINEAR);
169     _changed_connection = getUnitMenu()->signal_changed().connect (sigc::mem_fun (*this, &RegisteredUnitMenu::on_changed));
170 }
171 
172 void
setUnit(Glib::ustring unit)173 RegisteredUnitMenu::setUnit (Glib::ustring unit)
174 {
175     getUnitMenu()->setUnit(unit);
176 }
177 
178 void
on_changed()179 RegisteredUnitMenu::on_changed()
180 {
181     if (_wr->isUpdating())
182         return;
183 
184     Inkscape::SVGOStringStream os;
185     os << getUnitMenu()->getUnitAbbr();
186 
187     _wr->setUpdating (true);
188 
189     write_to_xml(os.str().c_str());
190 
191     _wr->setUpdating (false);
192 }
193 
194 
195 /*#########################################
196  * Registered SCALARUNIT
197  */
198 
~RegisteredScalarUnit()199 RegisteredScalarUnit::~RegisteredScalarUnit()
200 {
201     _value_changed_connection.disconnect();
202 }
203 
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,RSU_UserUnits user_units)204 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, RSU_UserUnits user_units)
205     : RegisteredWidget<ScalarUnit>(label, tip, UNIT_TYPE_LINEAR, "", "", rum.getUnitMenu()),
206       _um(nullptr)
207 {
208     init_parent(key, wr, repr_in, doc_in);
209 
210     setProgrammatically = false;
211 
212     initScalar (-1e6, 1e6);
213     setUnit (rum.getUnitMenu()->getUnitAbbr());
214     setDigits (2);
215     _um = rum.getUnitMenu();
216     _user_units = user_units;
217     _value_changed_connection = signal_value_changed().connect (sigc::mem_fun (*this, &RegisteredScalarUnit::on_value_changed));
218 }
219 
220 
221 void
on_value_changed()222 RegisteredScalarUnit::on_value_changed()
223 {
224     if (setProgrammatically) {
225         setProgrammatically = false;
226         return;
227     }
228 
229     if (_wr->isUpdating())
230         return;
231 
232     _wr->setUpdating (true);
233 
234     Inkscape::SVGOStringStream os;
235     if (_user_units != RSU_none) {
236         // Output length in 'user units', taking into account scale in 'x' or 'y'.
237         double scale = 1.0;
238         if (doc) {
239             SPRoot *root = doc->getRoot();
240             if (root->viewBox_set) {
241                 // check to see if scaling is uniform
242                 if(Geom::are_near((root->viewBox.width() * root->height.computed) / (root->width.computed * root->viewBox.height()), 1.0, Geom::EPSILON)) {
243                     scale = (root->viewBox.width() / root->width.computed + root->viewBox.height() / root->height.computed)/2.0;
244                 } else if (_user_units == RSU_x) {
245                     scale = root->viewBox.width() / root->width.computed;
246                 } else {
247                     scale = root->viewBox.height() / root->height.computed;
248                 }
249             }
250         }
251         os << getValue("px") * scale;
252     } else {
253         // Output using unit identifiers.
254         os << getValue("");
255         if (_um)
256             os << _um->getUnitAbbr();
257     }
258 
259     write_to_xml(os.str().c_str());
260     _wr->setUpdating (false);
261 }
262 
263 
264 /*#########################################
265  * Registered SCALAR
266  */
267 
~RegisteredScalar()268 RegisteredScalar::~RegisteredScalar()
269 {
270     _value_changed_connection.disconnect();
271 }
272 
RegisteredScalar(const Glib::ustring & label,const Glib::ustring & tip,const Glib::ustring & key,Registry & wr,Inkscape::XML::Node * repr_in,SPDocument * doc_in)273 RegisteredScalar::RegisteredScalar ( const Glib::ustring& label, const Glib::ustring& tip,
274                          const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in,
275                          SPDocument * doc_in )
276     : RegisteredWidget<Scalar>(label, tip)
277 {
278     init_parent(key, wr, repr_in, doc_in);
279 
280     setProgrammatically = false;
281     setRange (-1e6, 1e6);
282     setDigits (2);
283     setIncrements(0.1, 1.0);
284     _value_changed_connection = signal_value_changed().connect (sigc::mem_fun (*this, &RegisteredScalar::on_value_changed));
285 }
286 
287 void
on_value_changed()288 RegisteredScalar::on_value_changed()
289 {
290     if (setProgrammatically) {
291         setProgrammatically = false;
292         return;
293     }
294     if (_wr->isUpdating()) {
295         return;
296     }
297     _wr->setUpdating (true);
298 
299     Inkscape::SVGOStringStream os;
300     //Force exact 0 if decimals over to 6
301     double val = getValue() < 1e-6 && getValue() > -1e-6?0.0:getValue();
302     os << val;
303     //TODO: Test is ok remove this sensitives
304     //also removed in registered text and in registered random
305     //set_sensitive(false);
306     write_to_xml(os.str().c_str());
307     //set_sensitive(true);
308     _wr->setUpdating (false);
309 }
310 
311 
312 /*#########################################
313  * Registered TEXT
314  */
315 
~RegisteredText()316 RegisteredText::~RegisteredText()
317 {
318     _activate_connection.disconnect();
319 }
320 
RegisteredText(const Glib::ustring & label,const Glib::ustring & tip,const Glib::ustring & key,Registry & wr,Inkscape::XML::Node * repr_in,SPDocument * doc_in)321 RegisteredText::RegisteredText ( const Glib::ustring& label, const Glib::ustring& tip,
322                          const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in,
323                          SPDocument * doc_in )
324     : RegisteredWidget<Text>(label, tip)
325 {
326     init_parent(key, wr, repr_in, doc_in);
327 
328     setProgrammatically = false;
329     _activate_connection = signal_activate().connect (sigc::mem_fun (*this, &RegisteredText::on_activate));
330 }
331 
332 void
on_activate()333 RegisteredText::on_activate()
334 {
335     if (setProgrammatically) {
336         setProgrammatically = false;
337         return;
338     }
339 
340     if (_wr->isUpdating()) {
341         return;
342     }
343     _wr->setUpdating (true);
344     Glib::ustring str(getText());
345     Inkscape::SVGOStringStream os;
346     os << str;
347     write_to_xml(os.str().c_str());
348     _wr->setUpdating (false);
349 }
350 
351 
352 /*#########################################
353  * Registered COLORPICKER
354  */
355 
RegisteredColorPicker(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)356 RegisteredColorPicker::RegisteredColorPicker(const Glib::ustring& label,
357                                              const Glib::ustring& title,
358                                              const Glib::ustring& tip,
359                                              const Glib::ustring& ckey,
360                                              const Glib::ustring& akey,
361                                              Registry& wr,
362                                              Inkscape::XML::Node* repr_in,
363                                              SPDocument *doc_in)
364     : RegisteredWidget<LabelledColorPicker> (label, title, tip, 0, true)
365 {
366     init_parent("", wr, repr_in, doc_in);
367 
368     _ckey = ckey;
369     _akey = akey;
370     _changed_connection = connectChanged (sigc::mem_fun (*this, &RegisteredColorPicker::on_changed));
371 }
372 
~RegisteredColorPicker()373 RegisteredColorPicker::~RegisteredColorPicker()
374 {
375     _changed_connection.disconnect();
376 }
377 
378 void
setRgba32(guint32 rgba)379 RegisteredColorPicker::setRgba32 (guint32 rgba)
380 {
381     LabelledColorPicker::setRgba32 (rgba);
382 }
383 
384 void
closeWindow()385 RegisteredColorPicker::closeWindow()
386 {
387     LabelledColorPicker::closeWindow();
388 }
389 
390 void
on_changed(guint32 rgba)391 RegisteredColorPicker::on_changed (guint32 rgba)
392 {
393     if (_wr->isUpdating())
394         return;
395 
396     _wr->setUpdating (true);
397 
398     // Use local repr here. When repr is specified, use that one, but
399     // if repr==NULL, get the repr of namedview of active desktop.
400     Inkscape::XML::Node *local_repr = repr;
401     SPDocument *local_doc = doc;
402     if (!local_repr) {
403         SPDesktop *dt = _wr->desktop();
404         if (!dt) {
405             _wr->setUpdating(false);
406             return;
407         }
408         local_repr = dt->getNamedView()->getRepr();
409         local_doc = dt->getDocument();
410     }
411     gchar c[32];
412     if (_akey == _ckey + "_opacity_LPE") { //For LPE parameter we want stored with alpha
413         sprintf(c, "#%08x", rgba);
414     } else {
415         sp_svg_write_color(c, sizeof(c), rgba);
416     }
417     bool saved = DocumentUndo::getUndoSensitive(local_doc);
418     DocumentUndo::setUndoSensitive(local_doc, false);
419     local_repr->setAttribute(_ckey, c);
420     sp_repr_set_css_double(local_repr, _akey.c_str(), (rgba & 0xff) / 255.0);
421     DocumentUndo::setUndoSensitive(local_doc, saved);
422 
423     local_doc->setModifiedSinceSave();
424     DocumentUndo::done(local_doc, SP_VERB_NONE,
425                        /* TODO: annotate */ "registered-widget.cpp: RegisteredColorPicker::on_changed");
426 
427     _wr->setUpdating (false);
428 }
429 
430 
431 /*#########################################
432  * Registered SUFFIXEDINTEGER
433  */
434 
~RegisteredSuffixedInteger()435 RegisteredSuffixedInteger::~RegisteredSuffixedInteger()
436 {
437     _changed_connection.disconnect();
438 }
439 
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)440 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)
441     : RegisteredWidget<Scalar>(label, tip, 0, suffix),
442       setProgrammatically(false)
443 {
444     init_parent(key, wr, repr_in, doc_in);
445 
446     setRange (0, 1e6);
447     setDigits (0);
448     setIncrements(1, 10);
449 
450     _changed_connection = signal_value_changed().connect (sigc::mem_fun(*this, &RegisteredSuffixedInteger::on_value_changed));
451 }
452 
453 void
on_value_changed()454 RegisteredSuffixedInteger::on_value_changed()
455 {
456     if (setProgrammatically) {
457         setProgrammatically = false;
458         return;
459     }
460 
461     if (_wr->isUpdating())
462         return;
463 
464     _wr->setUpdating (true);
465 
466     Inkscape::SVGOStringStream os;
467     os << getValue();
468 
469     write_to_xml(os.str().c_str());
470 
471     _wr->setUpdating (false);
472 }
473 
474 
475 /*#########################################
476  * Registered RADIOBUTTONPAIR
477  */
478 
~RegisteredRadioButtonPair()479 RegisteredRadioButtonPair::~RegisteredRadioButtonPair()
480 {
481     _changed_connection.disconnect();
482 }
483 
RegisteredRadioButtonPair(const Glib::ustring & label,const Glib::ustring & label1,const Glib::ustring & label2,const Glib::ustring & tip1,const Glib::ustring & tip2,const Glib::ustring & key,Registry & wr,Inkscape::XML::Node * repr_in,SPDocument * doc_in)484 RegisteredRadioButtonPair::RegisteredRadioButtonPair (const Glib::ustring& label,
485         const Glib::ustring& label1, const Glib::ustring& label2,
486         const Glib::ustring& tip1, const Glib::ustring& tip2,
487         const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in, SPDocument *doc_in)
488     : RegisteredWidget<Gtk::Box>(),
489       _rb1(nullptr),
490       _rb2(nullptr)
491 {
492     init_parent(key, wr, repr_in, doc_in);
493 
494     setProgrammatically = false;
495 
496     set_orientation(Gtk::ORIENTATION_HORIZONTAL);
497     add(*Gtk::manage(new Gtk::Label(label)));
498     _rb1 = Gtk::manage(new Gtk::RadioButton(label1, true));
499     add (*_rb1);
500     Gtk::RadioButtonGroup group = _rb1->get_group();
501     _rb2 = Gtk::manage(new Gtk::RadioButton(group, label2, true));
502     add (*_rb2);
503     _rb2->set_active();
504     _rb1->set_tooltip_text(tip1);
505     _rb2->set_tooltip_text(tip2);
506     _changed_connection = _rb1->signal_toggled().connect (sigc::mem_fun (*this, &RegisteredRadioButtonPair::on_value_changed));
507 }
508 
509 void
setValue(bool second)510 RegisteredRadioButtonPair::setValue (bool second)
511 {
512     if (!_rb1 || !_rb2)
513         return;
514 
515     setProgrammatically = true;
516     if (second) {
517         _rb2->set_active();
518     } else {
519         _rb1->set_active();
520     }
521 }
522 
523 void
on_value_changed()524 RegisteredRadioButtonPair::on_value_changed()
525 {
526     if (setProgrammatically) {
527         setProgrammatically = false;
528         return;
529     }
530 
531     if (_wr->isUpdating())
532         return;
533 
534     _wr->setUpdating (true);
535 
536     bool second = _rb2->get_active();
537     write_to_xml(second ? "true" : "false");
538 
539     _wr->setUpdating (false);
540 }
541 
542 
543 /*#########################################
544  * Registered POINT
545  */
546 
~RegisteredPoint()547 RegisteredPoint::~RegisteredPoint()
548 {
549     _value_x_changed_connection.disconnect();
550     _value_y_changed_connection.disconnect();
551 }
552 
RegisteredPoint(const Glib::ustring & label,const Glib::ustring & tip,const Glib::ustring & key,Registry & wr,Inkscape::XML::Node * repr_in,SPDocument * doc_in)553 RegisteredPoint::RegisteredPoint ( const Glib::ustring& label, const Glib::ustring& tip,
554                         const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in,
555                         SPDocument* doc_in )
556     : RegisteredWidget<Point> (label, tip)
557 {
558     init_parent(key, wr, repr_in, doc_in);
559 
560     setRange (-1e6, 1e6);
561     setDigits (2);
562     setIncrements(0.1, 1.0);
563     _value_x_changed_connection = signal_x_value_changed().connect (sigc::mem_fun (*this, &RegisteredPoint::on_value_changed));
564     _value_y_changed_connection = signal_y_value_changed().connect (sigc::mem_fun (*this, &RegisteredPoint::on_value_changed));
565 }
566 
567 void
on_value_changed()568 RegisteredPoint::on_value_changed()
569 {
570     if (setProgrammatically()) {
571         clearProgrammatically();
572         return;
573     }
574 
575     if (_wr->isUpdating())
576         return;
577 
578     _wr->setUpdating (true);
579 
580     Inkscape::SVGOStringStream os;
581     os << getXValue() << "," << getYValue();
582 
583     write_to_xml(os.str().c_str());
584 
585     _wr->setUpdating (false);
586 }
587 
588 /*#########################################
589  * Registered TRANSFORMEDPOINT
590  */
591 
~RegisteredTransformedPoint()592 RegisteredTransformedPoint::~RegisteredTransformedPoint()
593 {
594     _value_x_changed_connection.disconnect();
595     _value_y_changed_connection.disconnect();
596 }
597 
RegisteredTransformedPoint(const Glib::ustring & label,const Glib::ustring & tip,const Glib::ustring & key,Registry & wr,Inkscape::XML::Node * repr_in,SPDocument * doc_in)598 RegisteredTransformedPoint::RegisteredTransformedPoint ( const Glib::ustring& label, const Glib::ustring& tip,
599                         const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in,
600                         SPDocument* doc_in )
601     : RegisteredWidget<Point> (label, tip),
602       to_svg(Geom::identity())
603 {
604     init_parent(key, wr, repr_in, doc_in);
605 
606     setRange (-1e6, 1e6);
607     setDigits (2);
608     setIncrements(0.1, 1.0);
609     _value_x_changed_connection = signal_x_value_changed().connect (sigc::mem_fun (*this, &RegisteredTransformedPoint::on_value_changed));
610     _value_y_changed_connection = signal_y_value_changed().connect (sigc::mem_fun (*this, &RegisteredTransformedPoint::on_value_changed));
611 }
612 
613 void
setValue(Geom::Point const & p)614 RegisteredTransformedPoint::setValue(Geom::Point const & p)
615 {
616     Geom::Point new_p = p * to_svg.inverse();
617     Point::setValue(new_p);  // the Point widget should display things in canvas coordinates
618 }
619 
620 void
setTransform(Geom::Affine const & canvas_to_svg)621 RegisteredTransformedPoint::setTransform(Geom::Affine const & canvas_to_svg)
622 {
623     // check if matrix is singular / has inverse
624     if ( ! canvas_to_svg.isSingular() ) {
625         to_svg = canvas_to_svg;
626     } else {
627         // set back to default
628         to_svg = Geom::identity();
629     }
630 }
631 
632 void
on_value_changed()633 RegisteredTransformedPoint::on_value_changed()
634 {
635     if (setProgrammatically()) {
636         clearProgrammatically();
637         return;
638     }
639 
640     if (_wr->isUpdating())
641         return;
642 
643     _wr->setUpdating (true);
644 
645     Geom::Point pos = getValue() * to_svg;
646 
647     Inkscape::SVGOStringStream os;
648     os << pos;
649 
650     write_to_xml(os.str().c_str());
651 
652     _wr->setUpdating (false);
653 }
654 
655 /*#########################################
656  * Registered TRANSFORMEDPOINT
657  */
658 
~RegisteredVector()659 RegisteredVector::~RegisteredVector()
660 {
661     _value_x_changed_connection.disconnect();
662     _value_y_changed_connection.disconnect();
663 }
664 
RegisteredVector(const Glib::ustring & label,const Glib::ustring & tip,const Glib::ustring & key,Registry & wr,Inkscape::XML::Node * repr_in,SPDocument * doc_in)665 RegisteredVector::RegisteredVector ( const Glib::ustring& label, const Glib::ustring& tip,
666                         const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in,
667                         SPDocument* doc_in )
668     : RegisteredWidget<Point> (label, tip),
669       _polar_coords(false)
670 {
671     init_parent(key, wr, repr_in, doc_in);
672 
673     setRange (-1e6, 1e6);
674     setDigits (2);
675     setIncrements(0.1, 1.0);
676     _value_x_changed_connection = signal_x_value_changed().connect (sigc::mem_fun (*this, &RegisteredVector::on_value_changed));
677     _value_y_changed_connection = signal_y_value_changed().connect (sigc::mem_fun (*this, &RegisteredVector::on_value_changed));
678 }
679 
680 void
setValue(Geom::Point const & p)681 RegisteredVector::setValue(Geom::Point const & p)
682 {
683     if (!_polar_coords) {
684         Point::setValue(p);
685     } else {
686         Geom::Point polar;
687         polar[Geom::X] = atan2(p) *180/M_PI;
688         polar[Geom::Y] = p.length();
689         Point::setValue(polar);
690     }
691 }
692 
693 void
setValue(Geom::Point const & p,Geom::Point const & origin)694 RegisteredVector::setValue(Geom::Point const & p, Geom::Point const & origin)
695 {
696     RegisteredVector::setValue(p);
697     _origin = origin;
698 }
699 
setPolarCoords(bool polar_coords)700 void RegisteredVector::setPolarCoords(bool polar_coords)
701 {
702     _polar_coords = polar_coords;
703     if (polar_coords) {
704         xwidget.setLabelText(_("Angle:"));
705         ywidget.setLabelText(_("Distance:"));
706     } else {
707         xwidget.setLabelText(_("X:"));
708         ywidget.setLabelText(_("Y:"));
709     }
710 }
711 
712 void
on_value_changed()713 RegisteredVector::on_value_changed()
714 {
715     if (setProgrammatically()) {
716         clearProgrammatically();
717         return;
718     }
719 
720     if (_wr->isUpdating())
721         return;
722 
723     _wr->setUpdating (true);
724 
725     Geom::Point origin = _origin;
726     Geom::Point vector = getValue();
727     if (_polar_coords) {
728         vector = Geom::Point::polar(vector[Geom::X]*M_PI/180, vector[Geom::Y]);
729     }
730 
731     Inkscape::SVGOStringStream os;
732     os << origin << " , " << vector;
733 
734     write_to_xml(os.str().c_str());
735 
736     _wr->setUpdating (false);
737 }
738 
739 /*#########################################
740  * Registered RANDOM
741  */
742 
~RegisteredRandom()743 RegisteredRandom::~RegisteredRandom()
744 {
745     _value_changed_connection.disconnect();
746     _reseeded_connection.disconnect();
747 }
748 
RegisteredRandom(const Glib::ustring & label,const Glib::ustring & tip,const Glib::ustring & key,Registry & wr,Inkscape::XML::Node * repr_in,SPDocument * doc_in)749 RegisteredRandom::RegisteredRandom ( const Glib::ustring& label, const Glib::ustring& tip,
750                          const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in,
751                          SPDocument * doc_in )
752     : RegisteredWidget<Random> (label, tip)
753 {
754     init_parent(key, wr, repr_in, doc_in);
755 
756     setProgrammatically = false;
757     setRange (-1e6, 1e6);
758     setDigits (2);
759     setIncrements(0.1, 1.0);
760     _value_changed_connection = signal_value_changed().connect (sigc::mem_fun (*this, &RegisteredRandom::on_value_changed));
761     _reseeded_connection = signal_reseeded.connect(sigc::mem_fun(*this, &RegisteredRandom::on_value_changed));
762 }
763 
764 void
setValue(double val,long startseed)765 RegisteredRandom::setValue (double val, long startseed)
766 {
767     Scalar::setValue (val);
768     setStartSeed(startseed);
769 }
770 
771 void
on_value_changed()772 RegisteredRandom::on_value_changed()
773 {
774     if (setProgrammatically) {
775         setProgrammatically = false;
776         return;
777     }
778 
779     if (_wr->isUpdating()) {
780         return;
781     }
782     _wr->setUpdating (true);
783 
784     Inkscape::SVGOStringStream os;
785     //Force exact 0 if decimals over to 6
786     double val = getValue() < 1e-6 && getValue() > -1e-6?0.0:getValue();
787     os << val << ';' << getStartSeed();
788     write_to_xml(os.str().c_str());
789     _wr->setUpdating (false);
790 }
791 
792 /*#########################################
793  * Registered FONT-BUTTON
794  */
795 
~RegisteredFontButton()796 RegisteredFontButton::~RegisteredFontButton()
797 {
798     _signal_font_set.disconnect();
799 }
800 
RegisteredFontButton(const Glib::ustring & label,const Glib::ustring & tip,const Glib::ustring & key,Registry & wr,Inkscape::XML::Node * repr_in,SPDocument * doc_in)801 RegisteredFontButton::RegisteredFontButton ( const Glib::ustring& label, const Glib::ustring& tip,
802                         const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in,
803                         SPDocument* doc_in )
804     : RegisteredWidget<FontButton>(label, tip)
805 {
806     init_parent(key, wr, repr_in, doc_in);
807     _signal_font_set =  signal_font_value_changed().connect (sigc::mem_fun (*this, &RegisteredFontButton::on_value_changed));
808 }
809 
810 void
setValue(Glib::ustring fontspec)811 RegisteredFontButton::setValue (Glib::ustring fontspec)
812 {
813     FontButton::setValue(fontspec);
814 }
815 
816 void
on_value_changed()817 RegisteredFontButton::on_value_changed()
818 {
819 
820     if (_wr->isUpdating())
821         return;
822 
823     _wr->setUpdating (true);
824 
825     Inkscape::SVGOStringStream os;
826     os << getValue();
827 
828     write_to_xml(os.str().c_str());
829 
830     _wr->setUpdating (false);
831 }
832 
833 } // namespace Dialog
834 } // namespace UI
835 } // namespace Inkscape
836 
837 /*
838   Local Variables:
839   mode:c++
840   c-file-style:"stroustrup"
841   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
842   indent-tabs-mode:nil
843   fill-column:99
844   End:
845 */
846 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
847