Code

c808289b21b6133f6f494cd555b988990f07d7ba
[inkscape.git] / src / ui / widget / selected-style.cpp
1 /**
2  * \brief Selected style indicator (fill, stroke, opacity)
3  *
4  * Author:
5  *   buliabyak@gmail.com
6  *
7  * Copyright (C) 2005 author
8  *
9  * Released under GNU GPL.  Read the file 'COPYING' for more information.
10  */
12 #ifdef HAVE_CONFIG_H
13 # include <config.h>
14 #endif
17 #include "selected-style.h"
19 #include "widgets/spw-utilities.h"
20 #include "ui/widget/color-preview.h"
22 #include "selection.h"
23 #include "desktop-handles.h"
24 #include "style.h"
25 #include "desktop-style.h"
26 #include "sp-linear-gradient-fns.h"
27 #include "sp-radial-gradient-fns.h"
28 #include "sp-pattern.h"
29 #include "dialogs/object-properties.h"
30 #include "xml/repr.h"
31 #include "document.h"
32 #include "widgets/widget-sizes.h"
33 #include "widgets/spinbutton-events.h"
34 #include "svg/svg.h"
35 #include "svg/css-ostringstream.h"
36 #include "helper/units.h"
38 static gdouble const _sw_presets[]     = { 32 ,  16 ,  10 ,  8 ,  6 ,  4 ,  3 ,  2 ,  1.5 ,  1 ,  0.75 ,  0.5 ,  0.25 ,  0.1 };
39 static gchar* const _sw_presets_str[] = {"32", "16", "10", "8", "6", "4", "3", "2", "1.5", "1", "0.75", "0.5", "0.25", "0.1"};
41 static void 
42 ss_selection_changed (Inkscape::Selection *, gpointer data)
43 {
44     Inkscape::UI::Widget::SelectedStyle *ss = (Inkscape::UI::Widget::SelectedStyle *) data;
45     ss->update();
46 }
48 static void
49 ss_selection_modified (Inkscape::Selection *selection, guint flags, gpointer data)
50 {
51     ss_selection_changed (selection, data);
52 }
54 static void
55 ss_subselection_changed (gpointer dragger, gpointer data)
56 {
57     ss_selection_changed (NULL, data);
58 }
60 namespace Inkscape {
61 namespace UI {
62 namespace Widget {
64 SelectedStyle::SelectedStyle(bool layout)
65     : _desktop (NULL),
67       _table(2, 6),
68       _fill_label (_("F:")),
69       _stroke_label (_("S:")),
70       _opacity_label (_("O:")),
71       _fill_place (),
72       _stroke_place (),
74       _fill_flag_place (),
75       _stroke_flag_place (),
77       _opacity_place (),
78       _opacity_adjustment (1.0, 0.0, 1.0, 0.01, 0.1),
79       _opacity_sb (0.02, 2),
81       _stroke (),
82       _stroke_width (""),
84       _opacity_blocked (false),
86       _popup_px(_sw_group),
87       _popup_pt(_sw_group),
88       _popup_mm(_sw_group),
90       _sw_unit(NULL),
92       _tooltips ()
93 {
94     _fill_label.set_alignment(0.0, 0.5);
95     _fill_label.set_padding(0, 0);
96     _stroke_label.set_alignment(0.0, 0.5);
97     _stroke_label.set_padding(0, 0);
98     _opacity_label.set_alignment(0.0, 0.5);
99     _opacity_label.set_padding(0, 0);
101     _table.set_col_spacings (2);
102     _table.set_row_spacings (0);
104     for (int i = SS_FILL; i <= SS_STROKE; i++) {
106         _na[i].set_markup (_("N/A"));
107         sp_set_font_size_smaller (GTK_WIDGET(_na[i].gobj()));
108         _na[i].show_all();
109         __na[i] = (_("Nothing selected"));
111         _none[i].set_markup (_("None"));
112         sp_set_font_size_smaller (GTK_WIDGET(_none[i].gobj()));
113         _none[i].show_all();
114         __none[i] = (i == SS_FILL)? (_("No fill")) : (_("No stroke"));
116         _pattern[i].set_markup (_("Pattern"));
117         sp_set_font_size_smaller (GTK_WIDGET(_pattern[i].gobj()));
118         _pattern[i].show_all();
119         __pattern[i] = (i == SS_FILL)? (_("Pattern fill")) : (_("Pattern stroke"));
121         _lgradient[i].set_markup (_("L Gradient"));
122         sp_set_font_size_smaller (GTK_WIDGET(_lgradient[i].gobj()));
123         _lgradient[i].show_all();
124         __lgradient[i] = (i == SS_FILL)? (_("Linear gradient fill")) : (_("Linear gradient stroke"));
126         _rgradient[i].set_markup (_("R Gradient"));
127         sp_set_font_size_smaller (GTK_WIDGET(_rgradient[i].gobj()));
128         _rgradient[i].show_all();
129         __rgradient[i] = (i == SS_FILL)? (_("Radial gradient fill")) : (_("Radial gradient stroke"));
131         _many[i].set_markup (_("Different"));
132         sp_set_font_size_smaller (GTK_WIDGET(_many[i].gobj()));
133         _many[i].show_all();
134         __many[i] = (i == SS_FILL)? (_("Different fills")) : (_("Different strokes"));
136         _unset[i].set_markup (_("Unset"));
137         sp_set_font_size_smaller (GTK_WIDGET(_unset[i].gobj()));
138         _unset[i].show_all();
139         __unset[i] = (i == SS_FILL)? (_("Unset fill")) : (_("Unset stroke"));
141         _color_preview[i] = new Inkscape::UI::Widget::ColorPreview (0);
142         __color[i] = (i == SS_FILL)? (_("Flat color fill")) : (_("Flat color stroke"));
144         // TRANSLATOR COMMENT: A means "Averaged"
145         _averaged[i].set_markup (_("<b>a</b>"));
146         sp_set_font_size_smaller (GTK_WIDGET(_averaged[i].gobj()));
147         _averaged[i].show_all();
148         __averaged[i] = (i == SS_FILL)? (_("Fill is averaged over selected objects")) : (_("Stroke is averaged over selected objects"));
150         // TRANSLATOR COMMENT: M means "Multiple"
151         _multiple[i].set_markup (_("<b>m</b>"));
152         sp_set_font_size_smaller (GTK_WIDGET(_multiple[i].gobj()));
153         _multiple[i].show_all();
154         __multiple[i] = (i == SS_FILL)? (_("Multiple selected objects have the same fill")) : (_("Multiple selected objects have the same stroke"));
156         _popup_edit[i].add(*(new Gtk::Label((i == SS_FILL)? _("Edit fill...") : _("Edit stroke..."), 0.0, 0.5)));
157         _popup_edit[i].signal_activate().connect(sigc::mem_fun(*this, 
158                                (i == SS_FILL)? &SelectedStyle::on_fill_edit : &SelectedStyle::on_stroke_edit ));
160         _popup_lastused[i].add(*(new Gtk::Label(_("Last set color"), 0.0, 0.5)));
161         _popup_lastused[i].signal_activate().connect(sigc::mem_fun(*this, 
162                                (i == SS_FILL)? &SelectedStyle::on_fill_lastused : &SelectedStyle::on_stroke_lastused ));
164         _popup_lastselected[i].add(*(new Gtk::Label(_("Last selected color"), 0.0, 0.5)));
165         _popup_lastselected[i].signal_activate().connect(sigc::mem_fun(*this, 
166                                (i == SS_FILL)? &SelectedStyle::on_fill_lastselected : &SelectedStyle::on_stroke_lastselected ));
168         _popup_invert[i].add(*(new Gtk::Label(_("Invert"), 0.0, 0.5)));
169         _popup_invert[i].signal_activate().connect(sigc::mem_fun(*this, 
170                                (i == SS_FILL)? &SelectedStyle::on_fill_invert : &SelectedStyle::on_stroke_invert ));
172         _popup_white[i].add(*(new Gtk::Label(_("White"), 0.0, 0.5)));
173         _popup_white[i].signal_activate().connect(sigc::mem_fun(*this, 
174                                (i == SS_FILL)? &SelectedStyle::on_fill_white : &SelectedStyle::on_stroke_white ));
176         _popup_black[i].add(*(new Gtk::Label(_("Black"), 0.0, 0.5)));
177         _popup_black[i].signal_activate().connect(sigc::mem_fun(*this, 
178                                (i == SS_FILL)? &SelectedStyle::on_fill_black : &SelectedStyle::on_stroke_black ));
180         _popup_copy[i].add(*(new Gtk::Label(_("Copy color"), 0.0, 0.5)));
181         _popup_copy[i].signal_activate().connect(sigc::mem_fun(*this, 
182                                (i == SS_FILL)? &SelectedStyle::on_fill_copy : &SelectedStyle::on_stroke_copy ));
184         _popup_paste[i].add(*(new Gtk::Label(_("Paste color"), 0.0, 0.5)));
185         _popup_paste[i].signal_activate().connect(sigc::mem_fun(*this, 
186                                (i == SS_FILL)? &SelectedStyle::on_fill_paste : &SelectedStyle::on_stroke_paste ));
188         _popup_swap[i].add(*(new Gtk::Label(_("Swap fill and stroke"), 0.0, 0.5)));
189         _popup_swap[i].signal_activate().connect(sigc::mem_fun(*this, 
190                                &SelectedStyle::on_fillstroke_swap));
192         _popup_opaque[i].add(*(new Gtk::Label((i == SS_FILL)? _("Make fill opaque") : _("Make stroke opaque"), 0.0, 0.5)));
193         _popup_opaque[i].signal_activate().connect(sigc::mem_fun(*this, 
194                                (i == SS_FILL)? &SelectedStyle::on_fill_opaque : &SelectedStyle::on_stroke_opaque ));
196         //TRANSLATORS COMMENT: unset is a verb here
197         _popup_unset[i].add(*(new Gtk::Label((i == SS_FILL)? _("Unset fill") : _("Unset stroke"), 0.0, 0.5)));
198         _popup_unset[i].signal_activate().connect(sigc::mem_fun(*this, 
199                                (i == SS_FILL)? &SelectedStyle::on_fill_unset : &SelectedStyle::on_stroke_unset ));
201         _popup_remove[i].add(*(new Gtk::Label((i == SS_FILL)? _("Remove fill") : _("Remove stroke"), 0.0, 0.5)));
202         _popup_remove[i].signal_activate().connect(sigc::mem_fun(*this, 
203                                (i == SS_FILL)? &SelectedStyle::on_fill_remove : &SelectedStyle::on_stroke_remove ));
205         _popup[i].attach(_popup_edit[i], 0,1, 0,1);
206           _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 1,2);
207         _popup[i].attach(_popup_lastused[i], 0,1, 2,3);
208         _popup[i].attach(_popup_lastselected[i], 0,1, 3,4);
209           _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 4,5);
210         _popup[i].attach(_popup_invert[i], 0,1, 5,6);
211           _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 6,7);
212         _popup[i].attach(_popup_white[i], 0,1, 7,8);
213         _popup[i].attach(_popup_black[i], 0,1, 8,9);
214           _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 9,10);
215         _popup[i].attach(_popup_copy[i], 0,1, 10,11);
216         _popup_copy[i].set_sensitive(false);
217         _popup[i].attach(_popup_paste[i], 0,1, 11,12);
218         _popup[i].attach(_popup_swap[i], 0,1, 12,13);
219           _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 13,14); 
220         _popup[i].attach(_popup_opaque[i], 0,1, 14,15);
221         _popup[i].attach(_popup_unset[i], 0,1, 15,16);
222         _popup[i].attach(_popup_remove[i], 0,1, 16,17);
223         _popup[i].show_all();
225         _mode[i] = SS_NA;
226     }
228     {
229         _popup_px.add(*(new Gtk::Label(_("px"), 0.0, 0.5)));
230         _popup_px.signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::on_popup_px));
231         _popup_sw.attach(_popup_px, 0,1, 0,1);
233         _popup_pt.add(*(new Gtk::Label(_("pt"), 0.0, 0.5)));
234         _popup_pt.signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::on_popup_pt));
235         _popup_sw.attach(_popup_pt, 0,1, 1,2);
237         _popup_mm.add(*(new Gtk::Label(_("mm"), 0.0, 0.5)));
238         _popup_mm.signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::on_popup_mm));
239         _popup_sw.attach(_popup_mm, 0,1, 2,3);
241         _popup_sw.attach(*(new Gtk::SeparatorMenuItem()), 0,1, 3,4);
243         for (guint i = 0; i < G_N_ELEMENTS(_sw_presets_str); ++i) {
244             Gtk::MenuItem *mi = Gtk::manage(new Gtk::MenuItem());
245             mi->add(*(new Gtk::Label(_sw_presets_str[i], 0.0, 0.5)));
246             mi->signal_activate().connect(sigc::bind<int>(sigc::mem_fun(*this, &SelectedStyle::on_popup_preset), i));
247             _popup_sw.attach(*mi, 0,1, 4+i, 5+i);
248         }
250         guint i = G_N_ELEMENTS(_sw_presets_str) + 5;
252         _popup_sw.attach(*(new Gtk::SeparatorMenuItem()), 0,1, i,i+1);
254         _popup_sw_remove.add(*(new Gtk::Label(_("Remove"), 0.0, 0.5)));
255         _popup_sw_remove.signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::on_stroke_remove));
256         _popup_sw.attach(_popup_sw_remove, 0,1, i+1,i+2);
258         _popup_sw.show_all();
259     }
261     _fill_place.signal_button_press_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_fill_click));
262     _stroke_place.signal_button_press_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_stroke_click));
263     _opacity_place.signal_button_press_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_opacity_click));
264     _stroke_width_place.signal_button_press_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_sw_click));
266     _opacity_sb.signal_populate_popup().connect(sigc::mem_fun(*this, &SelectedStyle::on_opacity_menu));
267     _opacity_sb.signal_value_changed().connect(sigc::mem_fun(*this, &SelectedStyle::on_opacity_changed));
269     _fill_place.add(_na[SS_FILL]);
270     _tooltips.set_tip(_fill_place, __na[SS_FILL]);
272     _stroke_place.add(_na[SS_STROKE]);
273     _tooltips.set_tip(_stroke_place, __na[SS_STROKE]);
275     _stroke.pack_start(_stroke_place);
276     _stroke_width_place.add(_stroke_width);
277     _stroke.pack_start(_stroke_width_place, Gtk::PACK_SHRINK);
279     _opacity_sb.set_adjustment(_opacity_adjustment);
280     sp_set_font_size_smaller (GTK_WIDGET(_opacity_sb.gobj()));
281     _opacity_sb.set_size_request (SELECTED_STYLE_SB_WIDTH, -1);
282     _opacity_sb.set_sensitive (false);
284     _table.attach(_fill_label, 0,1, 0,1, Gtk::SHRINK, Gtk::SHRINK);
285     _table.attach(_stroke_label, 0,1, 1,2, Gtk::SHRINK, Gtk::SHRINK);
287     _table.attach(_fill_flag_place, 1,2, 0,1, Gtk::SHRINK, Gtk::SHRINK);
288     _table.attach(_stroke_flag_place, 1,2, 1,2, Gtk::SHRINK, Gtk::SHRINK);
290     _table.attach(_fill_place, 2,3, 0,1);
291     _table.attach(_stroke, 2,3, 1,2);
293     _opacity_place.add(_opacity_label);
294     _table.attach(_opacity_place, 4,5, 0,2, Gtk::SHRINK, Gtk::SHRINK);
295     _table.attach(_opacity_sb, 5,6, 0,2, Gtk::SHRINK, Gtk::SHRINK);
297     pack_start(_table, true, true, 2);
299     set_size_request (SELECTED_STYLE_WIDTH, -1);
301     sp_set_font_size_smaller (GTK_WIDGET(_opacity_label.gobj()));
302     sp_set_font_size_smaller (GTK_WIDGET(_opacity_sb.gobj()));
303     sp_set_font_size_smaller (GTK_WIDGET(_fill_place.gobj()));
304     sp_set_font_size_smaller (GTK_WIDGET(_fill_flag_place.gobj()));
305     sp_set_font_size_smaller (GTK_WIDGET(_stroke_place.gobj()));
306     sp_set_font_size_smaller (GTK_WIDGET(_stroke_flag_place.gobj()));
307     sp_set_font_size_smaller (GTK_WIDGET(_stroke_width.gobj()));
308     sp_set_font_size_smaller (GTK_WIDGET(_fill_label.gobj()));
309     sp_set_font_size_smaller (GTK_WIDGET(_stroke_label.gobj()));
312 SelectedStyle::~SelectedStyle()
314     selection_changed_connection->disconnect();
315     delete selection_changed_connection;
316     selection_modified_connection->disconnect();
317     delete selection_modified_connection;
318     subselection_changed_connection->disconnect();
319     delete subselection_changed_connection;
321     for (int i = SS_FILL; i <= SS_STROKE; i++) {
322         delete _color_preview[i];
323     }
326 void
327 SelectedStyle::setDesktop(SPDesktop *desktop)
329     _desktop = desktop;
330     gtk_object_set_data (GTK_OBJECT(_opacity_sb.gobj()), "dtw", _desktop->canvas);
332     Inkscape::Selection *selection = SP_DT_SELECTION (desktop);
334     selection_changed_connection = new sigc::connection (selection->connectChanged(
335         sigc::bind (
336             sigc::ptr_fun(&ss_selection_changed),
337             this )
338     ));
339     selection_modified_connection = new sigc::connection (selection->connectModified(
340         sigc::bind (
341             sigc::ptr_fun(&ss_selection_modified),
342             this )
343     ));
344     subselection_changed_connection = new sigc::connection (desktop->connectToolSubselectionChanged(
345         sigc::bind (
346             sigc::ptr_fun(&ss_subselection_changed),
347             this )
348     ));
350     //_sw_unit = (SPUnit *) SP_DT_NAMEDVIEW(desktop)->doc_units;
353 void SelectedStyle::on_fill_remove() {
354     SPCSSAttr *css = sp_repr_css_attr_new ();
355     sp_repr_css_set_property (css, "fill", "none");
356     sp_desktop_set_style (_desktop, css, true, false); // do not write to current, to preserve current color
357     sp_repr_css_attr_unref (css);
358     sp_document_done (SP_DT_DOCUMENT(_desktop));
361 void SelectedStyle::on_stroke_remove() {
362     SPCSSAttr *css = sp_repr_css_attr_new ();
363     sp_repr_css_set_property (css, "stroke", "none");
364     sp_desktop_set_style (_desktop, css, true, false); // do not write to current, to preserve current color
365     sp_repr_css_attr_unref (css);
366     sp_document_done (SP_DT_DOCUMENT(_desktop));
369 void SelectedStyle::on_fill_unset() {
370     SPCSSAttr *css = sp_repr_css_attr_new ();
371     sp_repr_css_unset_property (css, "fill");
372     sp_desktop_set_style (_desktop, css, true, false); // do not write to current, to preserve current color
373     sp_repr_css_attr_unref (css);
374     sp_document_done (SP_DT_DOCUMENT(_desktop));
377 void SelectedStyle::on_stroke_unset() {
378     SPCSSAttr *css = sp_repr_css_attr_new ();
379     sp_repr_css_unset_property (css, "stroke");
380     sp_desktop_set_style (_desktop, css, true, false); // do not write to current, to preserve current color
381     sp_repr_css_attr_unref (css);
382     sp_document_done (SP_DT_DOCUMENT(_desktop));
385 void SelectedStyle::on_fill_opaque() {
386     SPCSSAttr *css = sp_repr_css_attr_new ();
387     sp_repr_css_set_property (css, "fill-opacity", "1");
388     sp_desktop_set_style (_desktop, css, true);
389     sp_repr_css_attr_unref (css);
390     sp_document_done (SP_DT_DOCUMENT(_desktop));
393 void SelectedStyle::on_stroke_opaque() {
394     SPCSSAttr *css = sp_repr_css_attr_new ();
395     sp_repr_css_set_property (css, "stroke-opacity", "1");
396     sp_desktop_set_style (_desktop, css, true);
397     sp_repr_css_attr_unref (css);
398     sp_document_done (SP_DT_DOCUMENT(_desktop));
401 void SelectedStyle::on_fill_lastused() {
402     SPCSSAttr *css = sp_repr_css_attr_new ();
403     guint32 color = sp_desktop_get_color(_desktop, true);
404     gchar c[64];
405     sp_svg_write_color (c, 64, color);
406     sp_repr_css_set_property (css, "fill", c);
407     sp_desktop_set_style (_desktop, css);
408     sp_repr_css_attr_unref (css);
409     sp_document_done (SP_DT_DOCUMENT(_desktop));
412 void SelectedStyle::on_stroke_lastused() {
413     SPCSSAttr *css = sp_repr_css_attr_new ();
414     guint32 color = sp_desktop_get_color(_desktop, false);
415     gchar c[64];
416     sp_svg_write_color (c, 64, color);
417     sp_repr_css_set_property (css, "stroke", c);
418     sp_desktop_set_style (_desktop, css);
419     sp_repr_css_attr_unref (css);
420     sp_document_done (SP_DT_DOCUMENT(_desktop));
423 void SelectedStyle::on_fill_lastselected() {
424     SPCSSAttr *css = sp_repr_css_attr_new ();
425     gchar c[64];
426     sp_svg_write_color (c, 64, _lastselected[SS_FILL]);
427     sp_repr_css_set_property (css, "fill", c);
428     sp_desktop_set_style (_desktop, css);
429     sp_repr_css_attr_unref (css);
430     sp_document_done (SP_DT_DOCUMENT(_desktop));
433 void SelectedStyle::on_stroke_lastselected() {
434     SPCSSAttr *css = sp_repr_css_attr_new ();
435     gchar c[64];
436     sp_svg_write_color (c, 64, _lastselected[SS_STROKE]);
437     sp_repr_css_set_property (css, "stroke", c);
438     sp_desktop_set_style (_desktop, css);
439     sp_repr_css_attr_unref (css);
440     sp_document_done (SP_DT_DOCUMENT(_desktop));
443 void SelectedStyle::on_fill_invert() {
444     SPCSSAttr *css = sp_repr_css_attr_new ();
445     guint32 color = _thisselected[SS_FILL];
446     gchar c[64];
447     if (_mode[SS_FILL] != SS_COLOR) return;
448     sp_svg_write_color (c, 64,
449         SP_RGBA32_U_COMPOSE(
450                 (255 - SP_RGBA32_R_U(color)),
451                 (255 - SP_RGBA32_G_U(color)),
452                 (255 - SP_RGBA32_B_U(color)),
453                 SP_RGBA32_A_U(color)
454         )
455     );
456     sp_repr_css_set_property (css, "fill", c);
457     sp_desktop_set_style (_desktop, css);
458     sp_repr_css_attr_unref (css);
459     sp_document_done (SP_DT_DOCUMENT(_desktop));
462 void SelectedStyle::on_stroke_invert() {
463     SPCSSAttr *css = sp_repr_css_attr_new ();
464     guint32 color = _thisselected[SS_STROKE];
465     gchar c[64];
466     if (_mode[SS_STROKE] != SS_COLOR) return;
467     sp_svg_write_color (c, 64,
468         SP_RGBA32_U_COMPOSE(
469                 (255 - SP_RGBA32_R_U(color)),
470                 (255 - SP_RGBA32_G_U(color)),
471                 (255 - SP_RGBA32_B_U(color)),
472                 SP_RGBA32_A_U(color)
473         )
474     );
475     sp_repr_css_set_property (css, "stroke", c);
476     sp_desktop_set_style (_desktop, css);
477     sp_repr_css_attr_unref (css);
478     sp_document_done (SP_DT_DOCUMENT(_desktop));
479
481 void SelectedStyle::on_fill_white() {
482     SPCSSAttr *css = sp_repr_css_attr_new ();
483     gchar c[64];
484     sp_svg_write_color (c, 64, 0xffffffff);
485     sp_repr_css_set_property (css, "fill", c);
486     sp_repr_css_set_property (css, "fill-opacity", "1");
487     sp_desktop_set_style (_desktop, css);
488     sp_repr_css_attr_unref (css);
489     sp_document_done (SP_DT_DOCUMENT(_desktop));
492 void SelectedStyle::on_stroke_white() {
493     SPCSSAttr *css = sp_repr_css_attr_new ();
494     gchar c[64];
495     sp_svg_write_color (c, 64, 0xffffffff);
496     sp_repr_css_set_property (css, "stroke", c);
497     sp_repr_css_set_property (css, "stroke-opacity", "1");
498     sp_desktop_set_style (_desktop, css);
499     sp_repr_css_attr_unref (css);
500     sp_document_done (SP_DT_DOCUMENT(_desktop));
503 void SelectedStyle::on_fill_black() {
504     SPCSSAttr *css = sp_repr_css_attr_new ();
505     gchar c[64];
506     sp_svg_write_color (c, 64, 0x000000ff);
507     sp_repr_css_set_property (css, "fill", c);
508     sp_repr_css_set_property (css, "fill-opacity", "1.0");
509     sp_desktop_set_style (_desktop, css);
510     sp_repr_css_attr_unref (css);
511     sp_document_done (SP_DT_DOCUMENT(_desktop));
514 void SelectedStyle::on_stroke_black() {
515     SPCSSAttr *css = sp_repr_css_attr_new ();
516     gchar c[64];
517     sp_svg_write_color (c, 64, 0x000000ff);
518     sp_repr_css_set_property (css, "stroke", c);
519     sp_repr_css_set_property (css, "stroke-opacity", "1.0");
520     sp_desktop_set_style (_desktop, css);
521     sp_repr_css_attr_unref (css);
522     sp_document_done (SP_DT_DOCUMENT(_desktop));
525 void SelectedStyle::on_fill_copy() {
526     if (_mode[SS_FILL] == SS_COLOR) {
527         gchar c[64];
528         sp_svg_write_color (c, 64, _thisselected[SS_FILL]);
529         Glib::ustring text;
530         text += c;
531         if (!text.empty()) {
532             Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
533             refClipboard->set_text(text);
534         }
535     }
538 void SelectedStyle::on_stroke_copy() {
539     if (_mode[SS_STROKE] == SS_COLOR) {
540         gchar c[64];
541         sp_svg_write_color (c, 64, _thisselected[SS_STROKE]);
542         Glib::ustring text;
543         text += c;
544         if (!text.empty()) {
545             Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
546             refClipboard->set_text(text);
547         }
548     }
551 void SelectedStyle::on_fill_paste() {
552     Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
553     Glib::ustring const text = refClipboard->wait_for_text();
555     if (!text.empty()) {
556         guint32 color = sp_svg_read_color(text.c_str(), 0x000000ff); // impossible value, as SVG color cannot have opacity
557         if (color == 0x000000ff) // failed to parse color string
558             return;
560         SPCSSAttr *css = sp_repr_css_attr_new ();
561         sp_repr_css_set_property (css, "fill", text.c_str());
562         sp_desktop_set_style (_desktop, css);
563         sp_repr_css_attr_unref (css);
564         sp_document_done (SP_DT_DOCUMENT(_desktop));
565     }
568 void SelectedStyle::on_stroke_paste() {
569     Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
570     Glib::ustring const text = refClipboard->wait_for_text();
572     if (!text.empty()) {
573         guint32 color = sp_svg_read_color(text.c_str(), 0x000000ff); // impossible value, as SVG color cannot have opacity
574         if (color == 0x000000ff) // failed to parse color string
575             return;
577         SPCSSAttr *css = sp_repr_css_attr_new ();
578         sp_repr_css_set_property (css, "stroke", text.c_str());
579         sp_desktop_set_style (_desktop, css);
580         sp_repr_css_attr_unref (css);
581         sp_document_done (SP_DT_DOCUMENT(_desktop));
582     }
585 void SelectedStyle::on_fillstroke_swap() {
586     SPCSSAttr *css = sp_repr_css_attr_new ();
588     switch (_mode[SS_FILL]) {
589     case SS_NA:
590     case SS_MANY:
591         break;
592     case SS_NONE:
593         sp_repr_css_set_property (css, "stroke", "none");
594         break;
595     case SS_UNSET:
596         sp_repr_css_unset_property (css, "stroke");
597         break;
598     case SS_COLOR:
599         gchar c[64];
600         sp_svg_write_color (c, 64, _thisselected[SS_FILL]);
601         sp_repr_css_set_property (css, "stroke", c);
602         break;
603     case SS_LGRADIENT:
604     case SS_RGRADIENT:
605     case SS_PATTERN:
606         sp_repr_css_set_property (css, "stroke", _paintserver_id[SS_FILL].c_str());
607         break;
608     }
610     switch (_mode[SS_STROKE]) {
611     case SS_NA:
612     case SS_MANY:
613         break;
614     case SS_NONE:
615         sp_repr_css_set_property (css, "fill", "none");
616         break;
617     case SS_UNSET:
618         sp_repr_css_unset_property (css, "fill");
619         break;
620     case SS_COLOR:
621         gchar c[64];
622         sp_svg_write_color (c, 64, _thisselected[SS_STROKE]);
623         sp_repr_css_set_property (css, "fill", c);
624         break;
625     case SS_LGRADIENT:
626     case SS_RGRADIENT:
627     case SS_PATTERN:
628         sp_repr_css_set_property (css, "fill", _paintserver_id[SS_STROKE].c_str());
629         break;
630     }
632     sp_desktop_set_style (_desktop, css);
633     sp_repr_css_attr_unref (css);
634     sp_document_done (SP_DT_DOCUMENT(_desktop));
637 void SelectedStyle::on_fill_edit() {
638     sp_object_properties_fill();
641 void SelectedStyle::on_stroke_edit() {
642     sp_object_properties_stroke();
645 bool 
646 SelectedStyle::on_fill_click(GdkEventButton *event)
648     if (event->button == 1) { // click, open fill&stroke
649         sp_object_properties_fill();
650     } else if (event->button == 3) { // right-click, popup menu
651         _popup[SS_FILL].popup(event->button, event->time);
652     } else if (event->button == 2) { // middle click, toggle none/lastcolor
653         if (_mode[SS_FILL] == SS_NONE) {
654             on_fill_lastused();
655         } else {
656             on_fill_remove();
657         }
658     }
659     return true;
662 bool 
663 SelectedStyle::on_stroke_click(GdkEventButton *event)
665     if (event->button == 1) { // click, open fill&stroke
666         sp_object_properties_stroke();
667     } else if (event->button == 3) { // right-click, popup menu
668         _popup[SS_STROKE].popup(event->button, event->time);
669     } else if (event->button == 2) { // middle click, toggle none/lastcolor
670         if (_mode[SS_STROKE] == SS_NONE) {
671             on_stroke_lastused();
672         } else {
673             on_stroke_remove();
674         }
675     }
676     return true;
679 bool 
680 SelectedStyle::on_sw_click(GdkEventButton *event)
682     if (event->button == 1) { // click, open fill&stroke
683         sp_object_properties_stroke_style ();
684     } else if (event->button == 3) { // right-click, popup menu
685         _popup_sw.popup(event->button, event->time);
686     } else if (event->button == 2) { // middle click, toggle none/lastwidth?
687         //
688     }
689     return true;
692 bool 
693 SelectedStyle::on_opacity_click(GdkEventButton *event)
695     if (event->button == 2) { // middle click
696         const char* opacity = _opacity_sb.get_value() < 0.5? "0.5" : (_opacity_sb.get_value() == 1? "0" : "1");
697         SPCSSAttr *css = sp_repr_css_attr_new ();
698         sp_repr_css_set_property (css, "opacity", opacity);
699         sp_desktop_set_style (_desktop, css);
700         sp_repr_css_attr_unref (css);
701         sp_document_done (SP_DT_DOCUMENT (_desktop));
702         return true;
703     }
705     return false;
708 void SelectedStyle::on_popup_px() {
709     _sw_unit = (SPUnit *) &(sp_unit_get_by_id(SP_UNIT_PX));
710     update();
712 void SelectedStyle::on_popup_pt() {
713     _sw_unit = (SPUnit *) &(sp_unit_get_by_id(SP_UNIT_PT));
714     update();
716 void SelectedStyle::on_popup_mm() {
717     _sw_unit = (SPUnit *) &(sp_unit_get_by_id(SP_UNIT_MM));
718     update();
721 void SelectedStyle::on_popup_preset(int i) {
722     SPCSSAttr *css = sp_repr_css_attr_new ();
723     gdouble w;
724     if (_sw_unit) {
725         w = sp_units_get_pixels (_sw_presets[i], *_sw_unit);
726     } else {
727         w = _sw_presets[i];
728     }
729     Inkscape::CSSOStringStream os;
730     os << w;
731     sp_repr_css_set_property (css, "stroke-width", os.str().c_str());
732     sp_desktop_set_style (_desktop, css, true);
733     sp_repr_css_attr_unref (css);
734     sp_document_done (SP_DT_DOCUMENT(_desktop));
737 void
738 SelectedStyle::update()
740     if (_desktop == NULL)
741         return;
743     // create temporary style
744     SPStyle *query = sp_style_new ();
746     for (int i = SS_FILL; i <= SS_STROKE; i++) {
747         Gtk::EventBox *place = (i == SS_FILL)? &_fill_place : &_stroke_place;
748         Gtk::EventBox *flag_place = (i == SS_FILL)? &_fill_flag_place : &_stroke_flag_place;
750         place->remove();
751         flag_place->remove();
753         _tooltips.unset_tip(*place);
754         _tooltips.unset_tip(*flag_place);
756         _mode[i] = SS_NA;
757         _paintserver_id[i].clear();
759         _popup_copy[i].set_sensitive(false);
761         // query style from desktop. This returns a result flag and fills query with the style of subselection, if any, or selection
762         int result = sp_desktop_query_style (_desktop, query, 
763                                              (i == SS_FILL)? QUERY_STYLE_PROPERTY_FILL : QUERY_STYLE_PROPERTY_STROKE);
764         switch (result) {
765         case QUERY_STYLE_NOTHING:
766             place->add(_na[i]);
767             _tooltips.set_tip(*place, __na[i]);
768             _mode[i] = SS_NA;
769             break;
770         case QUERY_STYLE_SINGLE:
771         case QUERY_STYLE_MULTIPLE_AVERAGED:
772         case QUERY_STYLE_MULTIPLE_SAME: 
773             SPIPaint *paint;
774             if (i == SS_FILL) {
775                 paint = &(query->fill);
776             } else {
777                 paint = &(query->stroke);
778             }
779             if (paint->set && paint->type == SP_PAINT_TYPE_COLOR) {
780                 guint32 color = sp_color_get_rgba32_falpha (&(paint->value.color), 
781                                      SP_SCALE24_TO_FLOAT ((i == SS_FILL)? query->fill_opacity.value : query->stroke_opacity.value));
782                 _lastselected[i] = _thisselected[i];
783                 _thisselected[i] = color | 0xff; // only color, opacity === 1
784                 ((Inkscape::UI::Widget::ColorPreview*)_color_preview[i])->setRgba32 (color);
785                 _color_preview[i]->show_all();
786                 place->add(*_color_preview[i]);
787                 gchar c_string[64];
788                 g_snprintf (c_string, 64, "%06x/%.3g", color >> 8, SP_RGBA32_A_F(color));
789                 _tooltips.set_tip(*place, __color[i] + ": " + c_string);
790                 _mode[i] = SS_COLOR;
791                 _popup_copy[i].set_sensitive(true);
793             } else if (paint->set && paint->type == SP_PAINT_TYPE_PAINTSERVER) {
794                 SPPaintServer *server = (i == SS_FILL)? SP_STYLE_FILL_SERVER (query) : SP_STYLE_STROKE_SERVER (query);
796                 Inkscape::XML::Node *srepr = SP_OBJECT_REPR(server);
797                 _paintserver_id[i] += "url(#";
798                 _paintserver_id[i] += srepr->attribute("id");
799                 _paintserver_id[i] += ")";
801                 if (SP_IS_LINEARGRADIENT (server)) {
802                     place->add(_lgradient[i]);
803                     _tooltips.set_tip(*place, __lgradient[i]);
804                     _mode[i] = SS_LGRADIENT;
805                 } else if (SP_IS_RADIALGRADIENT (server)) {
806                     place->add(_rgradient[i]);
807                     _tooltips.set_tip(*place, __rgradient[i]);
808                     _mode[i] = SS_RGRADIENT;
809                 } else if (SP_IS_PATTERN (server)) {
810                     place->add(_pattern[i]);
811                     _tooltips.set_tip(*place, __pattern[i]);
812                     _mode[i] = SS_PATTERN;
813                 }
815             } else if (paint->set && paint->type == SP_PAINT_TYPE_NONE) {
816                 place->add(_none[i]);
817                 _tooltips.set_tip(*place, __none[i]);
818                 _mode[i] = SS_NONE;
819             } else if (!paint->set) {
820                 place->add(_unset[i]);
821                 _tooltips.set_tip(*place, __unset[i]);
822                 _mode[i] = SS_UNSET;
823             }
824             if (result == QUERY_STYLE_MULTIPLE_AVERAGED) {
825                 flag_place->add(_averaged[i]);
826                 _tooltips.set_tip(*flag_place, __averaged[i]);
827             } else if (result == QUERY_STYLE_MULTIPLE_SAME) {
828                 flag_place->add(_multiple[i]);
829                 _tooltips.set_tip(*flag_place, __multiple[i]);
830             }
831             break;
832         case QUERY_STYLE_MULTIPLE_DIFFERENT:
833             place->add(_many[i]);
834             _tooltips.set_tip(*place, __many[i]);
835             _mode[i] = SS_MANY;
836             break;
837         default:
838             break;
839         }
840     }
842 // Now query opacity
843     _tooltips.unset_tip(_opacity_place);
845     int result = sp_desktop_query_style (_desktop, query, QUERY_STYLE_PROPERTY_MASTEROPACITY);
847     switch (result) {
848     case QUERY_STYLE_NOTHING:
849         _tooltips.set_tip(_opacity_place, _("Nothing selected"));
850         _opacity_sb.set_sensitive(false);
851         break;
852     case QUERY_STYLE_SINGLE:
853     case QUERY_STYLE_MULTIPLE_AVERAGED:
854     case QUERY_STYLE_MULTIPLE_SAME:
855         _tooltips.set_tip(_opacity_place, _("Master opacity"));
856         _opacity_blocked = true;
857         _opacity_sb.set_sensitive(true);
858         _opacity_adjustment.set_value(SP_SCALE24_TO_FLOAT(query->opacity.value));
859         _opacity_blocked = false;
860         break;
861     }
863 // Now query stroke_width
864     int result_sw = sp_desktop_query_style (_desktop, query, QUERY_STYLE_PROPERTY_STROKEWIDTH);
865     switch (result_sw) {
866     case QUERY_STYLE_NOTHING:
867         _stroke_width.set_markup("");
868         break;
869     case QUERY_STYLE_SINGLE:
870     case QUERY_STYLE_MULTIPLE_AVERAGED:
871     case QUERY_STYLE_MULTIPLE_SAME: 
872     {
873         double w;
874         if (_sw_unit) {
875             w = sp_pixels_get_units(query->stroke_width.computed, *_sw_unit);
876         } else {
877             w = query->stroke_width.computed;
878         }
879         {
880             gchar *str = g_strdup_printf(" %.3g", w);
881             _stroke_width.set_markup(str);
882             g_free (str);
883         }
884         {
885             gchar *str = g_strdup_printf(_("Stroke width: %.5g%s%s"), 
886                                          w, 
887                                          _sw_unit? sp_unit_get_abbreviation(_sw_unit) : "px", 
888                                          (result_sw == QUERY_STYLE_MULTIPLE_AVERAGED)?
889                                          _(" (averaged)") : "");
890             _tooltips.set_tip(_stroke_width_place, str);
891             g_free (str);
892         }
893         break;
894     }
895     default:
896         break;
897     }
899     g_free (query);
902 void SelectedStyle::opacity_0(void) {_opacity_sb.set_value(0);}
903 void SelectedStyle::opacity_025(void) {_opacity_sb.set_value(0.25);}
904 void SelectedStyle::opacity_05(void) {_opacity_sb.set_value(0.5);}
905 void SelectedStyle::opacity_075(void) {_opacity_sb.set_value(0.75);}
906 void SelectedStyle::opacity_1(void) {_opacity_sb.set_value(1.0);}
908 void SelectedStyle::on_opacity_menu (Gtk::Menu *menu) {
910     Glib::ListHandle<Gtk::Widget *> children = menu->get_children();
911     for (Glib::ListHandle<Gtk::Widget *>::iterator iter = children.begin(); iter != children.end(); iter++) {
912         menu->remove(*(*iter));
913     }
915     {
916         Gtk::MenuItem *item = new Gtk::MenuItem;
917         item->add(*(new Gtk::Label(_("0 (transparent)"), 0, 0)));
918         item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_0 ));
919         menu->add(*item);
920     }
921     {
922         Gtk::MenuItem *item = new Gtk::MenuItem;
923         item->add(*(new Gtk::Label("0.25", 0, 0)));
924         item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_025 ));
925         menu->add(*item);
926     }
927     {
928         Gtk::MenuItem *item = new Gtk::MenuItem;
929         item->add(*(new Gtk::Label("0.5", 0, 0)));
930         item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_05 ));
931         menu->add(*item);
932     }
933     {
934         Gtk::MenuItem *item = new Gtk::MenuItem;
935         item->add(*(new Gtk::Label("0.75", 0, 0)));
936         item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_075 ));
937         menu->add(*item);
938     }
939     {
940         Gtk::MenuItem *item = new Gtk::MenuItem;
941         item->add(*(new Gtk::Label(_("1.0 (opaque)"), 0, 0)));
942         item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_1 ));
943         menu->add(*item);
944     }
946     menu->show_all();
949 void SelectedStyle::on_opacity_changed () {
950     if (_opacity_blocked)
951         return;
952     _opacity_blocked = true;
953     SPCSSAttr *css = sp_repr_css_attr_new ();
954     Inkscape::CSSOStringStream os;
955     os << CLAMP (_opacity_adjustment.get_value(), 0.0, 1.0);
956     sp_repr_css_set_property (css, "opacity", os.str().c_str());
957     sp_desktop_set_style (_desktop, css);
958     sp_repr_css_attr_unref (css);
959     sp_document_maybe_done (SP_DT_DOCUMENT (_desktop), "fillstroke:opacity");
960     spinbutton_defocus(GTK_OBJECT(_opacity_sb.gobj()));
961     _opacity_blocked = false;
964 } // namespace Widget
965 } // namespace UI
966 } // namespace Inkscape
968 /* 
969   Local Variables:
970   mode:c++
971   c-file-style:"stroustrup"
972   c-file-offsets:((innamespace . 0)(inline-open . 0))
973   indent-tabs-mode:nil
974   fill-column:99
975   End:
976 */
977 // vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :