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()));
310 }
312 SelectedStyle::~SelectedStyle()
313 {
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 }
324 }
326 void
327 SelectedStyle::setDesktop(SPDesktop *desktop)
328 {
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;
351 }
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));
359 }
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));
367 }
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));
375 }
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));
383 }
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));
391 }
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));
399 }
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));
410 }
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));
421 }
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));
431 }
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));
441 }
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));
460 }
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));
490 }
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));
501 }
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));
512 }
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));
523 }
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 }
536 }
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 }
549 }
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 }
566 }
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 }
583 }
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));
635 }
637 void SelectedStyle::on_fill_edit() {
638 sp_object_properties_fill();
639 }
641 void SelectedStyle::on_stroke_edit() {
642 sp_object_properties_stroke();
643 }
645 bool
646 SelectedStyle::on_fill_click(GdkEventButton *event)
647 {
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;
660 }
662 bool
663 SelectedStyle::on_stroke_click(GdkEventButton *event)
664 {
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;
677 }
679 bool
680 SelectedStyle::on_sw_click(GdkEventButton *event)
681 {
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;
690 }
692 bool
693 SelectedStyle::on_opacity_click(GdkEventButton *event)
694 {
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;
706 }
708 void SelectedStyle::on_popup_px() {
709 _sw_unit = (SPUnit *) &(sp_unit_get_by_id(SP_UNIT_PX));
710 update();
711 }
712 void SelectedStyle::on_popup_pt() {
713 _sw_unit = (SPUnit *) &(sp_unit_get_by_id(SP_UNIT_PT));
714 update();
715 }
716 void SelectedStyle::on_popup_mm() {
717 _sw_unit = (SPUnit *) &(sp_unit_get_by_id(SP_UNIT_MM));
718 update();
719 }
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));
735 }
737 void
738 SelectedStyle::update()
739 {
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);
900 }
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();
947 }
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;
962 }
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 :