Code

Fix [ 1835591 ] Reproducible crash on opening the attached file
[inkscape.git] / src / ui / widget / registered-widget.cpp
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));
110 void
111 RegisteredCheckButton::setActive (bool b)
113     setProgrammatically = true;
114     _button->set_active (b);
115     //The slave button is greyed out if the master button is unchecked
116     for (std::list<Gtk::ToggleButton*>::const_iterator i = _slavebuttons.begin(); i != _slavebuttons.end(); i++) {
117         (*i)->set_sensitive(b);
118     }
119     setProgrammatically = false;
122 void
123 RegisteredCheckButton::on_toggled()
125     if (setProgrammatically) {
126         setProgrammatically = false;
127         return;
128     }
130     if (_wr->isUpdating())
131         return;
132     _wr->setUpdating (true);
134     write_to_xml(_button->get_active() ? "true" : "false");
135     //The slave button is greyed out if the master button is unchecked
136     for (std::list<Gtk::ToggleButton*>::const_iterator i = _slavebuttons.begin(); i != _slavebuttons.end(); i++) {
137         (*i)->set_sensitive(_button->get_active());
138     }
140     _wr->setUpdating (false);
143 RegisteredUnitMenu::RegisteredUnitMenu()
144 : _label(0), _sel(0)
148 RegisteredUnitMenu::~RegisteredUnitMenu()
150     _changed_connection.disconnect();
151     if (_label) delete _label;
152     if (_sel) delete _sel;
155 void
156 RegisteredUnitMenu::init (const Glib::ustring& label, const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in, SPDocument *doc_in)
158     init_parent(key, wr, repr_in, doc_in);
160     _label = new Gtk::Label (label, 1.0, 0.5);
161     _label->set_use_underline (true);
162     _sel = new UnitMenu ();
163     _label->set_mnemonic_widget (*_sel);
164     _sel->setUnitType (UNIT_TYPE_LINEAR);
165     _changed_connection = _sel->signal_changed().connect (sigc::mem_fun (*this, &RegisteredUnitMenu::on_changed));
168 void
169 RegisteredUnitMenu::setUnit (const SPUnit* unit)
171     _sel->setUnit (sp_unit_get_abbreviation (unit));
174 void
175 RegisteredUnitMenu::on_changed()
177     if (_wr->isUpdating())
178         return;
180     Inkscape::SVGOStringStream os;
181     os << _sel->getUnitAbbr();
183     _wr->setUpdating (true);
185     write_to_xml(os.str().c_str());
187     _wr->setUpdating (false);
191 RegisteredScalarUnit::RegisteredScalarUnit()
192 : _widget(0), _um(0)
196 RegisteredScalarUnit::~RegisteredScalarUnit()
198     if (_widget) delete _widget;
199     _value_changed_connection.disconnect();
202 void
203 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     init_parent(key, wr, repr_in, doc_in);
207     _widget = new ScalarUnit (label, tip, UNIT_TYPE_LINEAR, "", "", rum._sel);
208     _widget->initScalar (-1e6, 1e6);
209     _widget->setUnit (rum._sel->getUnitAbbr());
210     _widget->setDigits (2);
211     _um = rum._sel;
212     _value_changed_connection = _widget->signal_value_changed().connect (sigc::mem_fun (*this, &RegisteredScalarUnit::on_value_changed));
215 ScalarUnit*
216 RegisteredScalarUnit::getSU()
218     return _widget;
221 void
222 RegisteredScalarUnit::setValue (double val)
224     if (_widget)
225         _widget->setValue (val);
228 void
229 RegisteredScalarUnit::on_value_changed()
231 g_message("on_value_changed");
232     if (_widget->setProgrammatically) {
233         _widget->setProgrammatically = false;
234         return;
235     }
236 g_message("on_value_changed1");
238     if (_wr->isUpdating())
239         return;
241     _wr->setUpdating (true);
243     Inkscape::SVGOStringStream os;
244     os << _widget->getValue("");
245     if (_um)
246         os << _um->getUnitAbbr();
248     write_to_xml(os.str().c_str());
250     _wr->setUpdating (false);
254 RegisteredScalar::RegisteredScalar()
256     _widget = NULL;
259 RegisteredScalar::~RegisteredScalar()
261     if (_widget) 
262         delete _widget;
264     _value_changed_connection.disconnect();
267 void
268 RegisteredScalar::init ( const Glib::ustring& label, const Glib::ustring& tip, 
269                          const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in,
270                          SPDocument * doc_in )
272     init_parent(key, wr, repr_in, doc_in);
274     _widget = new Scalar (label, tip);
275     _widget->setRange (-1e6, 1e6);
276     _widget->setDigits (2);
277     _widget->setIncrements(0.1, 1.0);
278     _value_changed_connection = _widget->signal_value_changed().connect (sigc::mem_fun (*this, &RegisteredScalar::on_value_changed));
281 Scalar*
282 RegisteredScalar::getS()
284     return _widget;
287 void
288 RegisteredScalar::setValue (double val)
290     if (_widget)
291         _widget->setValue (val);
294 void
295 RegisteredScalar::on_value_changed()
297     if (_widget->setProgrammatically) {
298         _widget->setProgrammatically = false;
299         return;
300     }
302     if (_wr->isUpdating()) {
303         return;
304     }
305     _wr->setUpdating (true);
307     Inkscape::SVGOStringStream os;
308     os << _widget->getValue();
310     _widget->set_sensitive(false);
311     write_to_xml(os.str().c_str());
312     _widget->set_sensitive(true);
314     _wr->setUpdating (false);
318 RegisteredColorPicker::RegisteredColorPicker()
319 : _label(0), _cp(0)
323 RegisteredColorPicker::~RegisteredColorPicker()
325     _changed_connection.disconnect();
326     if (_cp) delete _cp;
327     if (_label) delete _label;
330 void
331 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)
333     init_parent("", wr, repr_in, doc_in);
335     _label = new Gtk::Label (label, 1.0, 0.5);
336     _label->set_use_underline (true);
337     _cp = new ColorPicker (title,tip,0,true);
338     _label->set_mnemonic_widget (*_cp);
339     _ckey = ckey;
340     _akey = akey;
341     _changed_connection = _cp->connectChanged (sigc::mem_fun (*this, &RegisteredColorPicker::on_changed));
344 void
345 RegisteredColorPicker::setRgba32 (guint32 rgba)
347     _cp->setRgba32 (rgba);
350 void
351 RegisteredColorPicker::closeWindow()
353     _cp->closeWindow();
356 void
357 RegisteredColorPicker::on_changed (guint32 rgba)
359     if (_wr->isUpdating())
360         return;
362     _wr->setUpdating (true);
364     // Use local repr here. When repr is specified, use that one, but
365     // if repr==NULL, get the repr of namedview of active desktop.
366     Inkscape::XML::Node *local_repr = repr;
367     SPDocument *local_doc = doc;
368     if (!local_repr) {
369         // no repr specified, use active desktop's namedview's repr
370         SPDesktop *dt = SP_ACTIVE_DESKTOP;
371         if (!dt)
372             return;
373         local_repr = SP_OBJECT_REPR (sp_desktop_namedview(dt));
374         local_doc = sp_desktop_document(dt);
375     }
377     gchar c[32];
378     sp_svg_write_color(c, sizeof(c), rgba);
379     bool saved = sp_document_get_undo_sensitive (local_doc);
380     sp_document_set_undo_sensitive (local_doc, false);
381     local_repr->setAttribute(_ckey.c_str(), c);
382     sp_repr_set_css_double(local_repr, _akey.c_str(), (rgba & 0xff) / 255.0);
383     local_doc->rroot->setAttribute("sodipodi:modified", "true");
384     sp_document_set_undo_sensitive (local_doc, saved);
385     sp_document_done (local_doc, SP_VERB_NONE,
386                       /* TODO: annotate */ "registered-widget.cpp: RegisteredColorPicker::on_changed");
388     _wr->setUpdating (false);
391 RegisteredSuffixedInteger::RegisteredSuffixedInteger()
392 : _label(0),
393   setProgrammatically(false),
394   _sb(0),
395   _adj(0.0,0.0,100.0,1.0,1.0,1.0),
396   _suffix(0)
400 RegisteredSuffixedInteger::~RegisteredSuffixedInteger()
402     _changed_connection.disconnect();
403     if (_label) delete _label;
404     if (_suffix) delete _suffix;
405     if (_sb) delete _sb;
408 void
409 RegisteredSuffixedInteger::init (const Glib::ustring& label, const Glib::ustring& suffix, const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in, SPDocument *doc_in)
411     init_parent(key, wr, repr_in, doc_in);
413     _label = new Gtk::Label (label);
414     _label->set_alignment (1.0, 0.5);
415     _label->set_use_underline();
416     _sb = new Gtk::SpinButton (_adj, 1.0, 0);
417     _sb->set_numeric();
418     _label->set_mnemonic_widget (*_sb);
419     _suffix = new Gtk::Label (suffix);
420     _hbox.pack_start (*_sb, true, true, 0);
421     _hbox.pack_start (*_suffix, false, false, 0);
423     _changed_connection = _adj.signal_value_changed().connect (sigc::mem_fun(*this, &RegisteredSuffixedInteger::on_value_changed));
426 void
427 RegisteredSuffixedInteger::setValue (int i)
429     setProgrammatically = true;
430     _adj.set_value (i);
433 void
434 RegisteredSuffixedInteger::on_value_changed()
436     if (setProgrammatically) {
437         setProgrammatically = false;
438         return;
439     }
441     if (_wr->isUpdating())
442         return;
444     _wr->setUpdating (true);
446     Inkscape::SVGOStringStream os;
447     int value = int(_adj.get_value());
448     os << value;
450     write_to_xml(os.str().c_str());
452     _wr->setUpdating (false);
455 RegisteredRadioButtonPair::RegisteredRadioButtonPair()
456 : _hbox(0),
457    setProgrammatically(false)
461 RegisteredRadioButtonPair::~RegisteredRadioButtonPair()
463     _changed_connection.disconnect();
466 void
467 RegisteredRadioButtonPair::init (const Glib::ustring& label,
468 const Glib::ustring& label1, const Glib::ustring& label2,
469 const Glib::ustring& tip1, const Glib::ustring& tip2,
470 const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in, SPDocument *doc_in)
472     init_parent(key, wr, repr_in, doc_in);
474     _hbox = new Gtk::HBox;
475     _hbox->add (*manage (new Gtk::Label (label)));
476     _rb1 = manage (new Gtk::RadioButton (label1, true));
477     _hbox->add (*_rb1);
478     Gtk::RadioButtonGroup group = _rb1->get_group();
479     _rb2 = manage (new Gtk::RadioButton (group, label2, true));
480     _hbox->add (*_rb2);
481     _rb2->set_active();
482     _tt.set_tip (*_rb1, tip1);
483     _tt.set_tip (*_rb2, tip2);
484     _changed_connection = _rb1->signal_toggled().connect (sigc::mem_fun (*this, &RegisteredRadioButtonPair::on_value_changed));
487 void
488 RegisteredRadioButtonPair::setValue (bool second)
490     if (!_rb1 || !_rb2)
491         return;
493     setProgrammatically = true;
494     if (second) {
495         _rb2->set_active();
496     } else {
497         _rb1->set_active();
498     }
501 void
502 RegisteredRadioButtonPair::on_value_changed()
504     if (setProgrammatically) {
505         setProgrammatically = false;
506         return;
507     }
509     if (_wr->isUpdating())
510         return;
512     _wr->setUpdating (true);
514     bool second = _rb2->get_active();
515     write_to_xml(second ? "true" : "false");
517     _wr->setUpdating (false);
520 /*#########################################
521  * Registered POINT
522  */
524 RegisteredPoint::RegisteredPoint()
526     _widget = NULL;
529 RegisteredPoint::~RegisteredPoint()
531     if (_widget) 
532         delete _widget;
534     _value_x_changed_connection.disconnect();
535     _value_y_changed_connection.disconnect();
538 void
539 RegisteredPoint::init ( const Glib::ustring& label, const Glib::ustring& tip, 
540                         const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in, 
541                         SPDocument* doc_in )
543     init_parent(key, wr, repr_in, doc_in);
545     _widget = new Point (label, tip);
546     _widget->setRange (-1e6, 1e6);
547     _widget->setDigits (2);
548     _widget->setIncrements(0.1, 1.0);
549     _value_x_changed_connection = _widget->signal_x_value_changed().connect (sigc::mem_fun (*this, &RegisteredPoint::on_value_changed));
550     _value_y_changed_connection = _widget->signal_y_value_changed().connect (sigc::mem_fun (*this, &RegisteredPoint::on_value_changed));
553 Point*
554 RegisteredPoint::getPoint()
556     return _widget;
559 void
560 RegisteredPoint::setValue (double xval, double yval)
562     if (_widget)
563         _widget->setValue(xval, yval);
566 void
567 RegisteredPoint::on_value_changed()
569     if (_widget->setProgrammatically()) {
570         _widget->clearProgrammatically();
571         return;
572     }
574     if (_wr->isUpdating())
575         return;
577     _wr->setUpdating (true);
579     Inkscape::SVGOStringStream os;
580     os << _widget->getXValue() << "," << _widget->getYValue();
582     write_to_xml(os.str().c_str());
584     _wr->setUpdating (false);
587 /*#########################################
588  * Registered RANDOM
589  */
591 RegisteredRandom::RegisteredRandom()
593     _widget = NULL;
596 RegisteredRandom::~RegisteredRandom()
598     if (_widget) 
599         delete _widget;
601     _value_changed_connection.disconnect();
602     _reseeded_connection.disconnect();
605 void
606 RegisteredRandom::init ( const Glib::ustring& label, const Glib::ustring& tip, 
607                          const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in,
608                          SPDocument * doc_in )
610     init_parent(key, wr, repr_in, doc_in);
612     _widget = new Random (label, tip);
613     _widget->setRange (-1e6, 1e6);
614     _widget->setDigits (2);
615     _widget->setIncrements(0.1, 1.0);
616     _value_changed_connection = _widget->signal_value_changed().connect (sigc::mem_fun (*this, &RegisteredRandom::on_value_changed));
617     _reseeded_connection = _widget->signal_reseeded.connect(sigc::mem_fun(*this, &RegisteredRandom::on_value_changed));
620 Random*
621 RegisteredRandom::getR()
623     return _widget;
626 void
627 RegisteredRandom::setValue (double val, long startseed)
629     if (!_widget)
630         return;
632     _widget->setValue (val);
633     _widget->setStartSeed(startseed);
636 void
637 RegisteredRandom::on_value_changed()
639     if (_widget->setProgrammatically) {
640         _widget->setProgrammatically = false;
641         return;
642     }
644     if (_wr->isUpdating()) {
645         return;
646     }
647     _wr->setUpdating (true);
649     Inkscape::SVGOStringStream os;
650     os << _widget->getValue() << ';' << _widget->getStartSeed();
652     _widget->set_sensitive(false);
653     write_to_xml(os.str().c_str());
654     _widget->set_sensitive(true);
656     _wr->setUpdating (false);
660 } // namespace Dialog
661 } // namespace UI
662 } // namespace Inkscape
664 /*
665   Local Variables:
666   mode:c++
667   c-file-style:"stroustrup"
668   c-file-offsets:((innamespace . 0)(inline-open . 0))
669   indent-tabs-mode:nil
670   fill-column:99
671   End:
672 */
673 // vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :