22cd30828fa8d3b419352a8fd04ca419434d277c
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
16 #include <gtk/gtkdnd.h>
18 #include "selected-style.h"
20 #include "widgets/spw-utilities.h"
21 #include "ui/widget/color-preview.h"
23 #include "selection.h"
24 #include "desktop-handles.h"
25 #include "style.h"
26 #include "desktop-style.h"
27 #include "sp-linear-gradient-fns.h"
28 #include "sp-radial-gradient-fns.h"
29 #include "sp-pattern.h"
30 #include "ui/dialog/dialog-manager.h"
31 #include "ui/dialog/fill-and-stroke.h"
32 #include "xml/repr.h"
33 #include "document.h"
34 #include "widgets/widget-sizes.h"
35 #include "widgets/spinbutton-events.h"
36 #include "widgets/gradient-image.h"
37 #include "sp-gradient.h"
38 #include "svg/svg-color.h"
39 #include "svg/css-ostringstream.h"
40 #include "helper/units.h"
41 #include "verbs.h"
42 #include <display/sp-canvas.h>
44 static gdouble const _sw_presets[] = { 32 , 16 , 10 , 8 , 6 , 4 , 3 , 2 , 1.5 , 1 , 0.75 , 0.5 , 0.25 , 0.1 };
45 static gchar const *const _sw_presets_str[] = {"32", "16", "10", "8", "6", "4", "3", "2", "1.5", "1", "0.75", "0.5", "0.25", "0.1"};
47 static void
48 ss_selection_changed (Inkscape::Selection *, gpointer data)
49 {
50 Inkscape::UI::Widget::SelectedStyle *ss = (Inkscape::UI::Widget::SelectedStyle *) data;
51 ss->update();
52 }
54 static void
55 ss_selection_modified (Inkscape::Selection *selection, guint flags, gpointer data)
56 {
57 ss_selection_changed (selection, data);
58 }
60 static void
61 ss_subselection_changed (gpointer dragger, gpointer data)
62 {
63 ss_selection_changed (NULL, data);
64 }
66 namespace Inkscape {
67 namespace UI {
68 namespace Widget {
71 typedef struct {
72 SelectedStyle* parent;
73 int item;
74 } DropTracker;
76 /* Drag and Drop */
77 typedef enum {
78 APP_X_COLOR
79 } ui_drop_target_info;
81 static GtkTargetEntry ui_drop_target_entries [] = {
82 {"application/x-color", 0, APP_X_COLOR}
83 };
85 #define ENTRIES_SIZE(n) sizeof(n)/sizeof(n[0])
86 static guint nui_drop_target_entries = ENTRIES_SIZE(ui_drop_target_entries);
89 SelectedStyle::SelectedStyle(bool layout)
90 : _desktop (NULL),
92 _table(2, 6),
93 _fill_label (_("Fill:")),
94 _stroke_label (_("Stroke:")),
95 _opacity_label (_("O:")),
96 _fill_place (),
97 _stroke_place (),
99 _fill_flag_place (),
100 _stroke_flag_place (),
102 _opacity_place (),
103 _opacity_adjustment (100, 0.0, 100, 1.0, 10.0),
104 _opacity_sb (0.02, 0),
106 _stroke (),
107 _stroke_width (""),
109 _opacity_blocked (false),
111 _popup_px(_sw_group),
112 _popup_pt(_sw_group),
113 _popup_mm(_sw_group),
115 _sw_unit(NULL),
117 _tooltips ()
119 {
120 _drop[0] = _drop[1] = 0;
121 _dropEnabled[0] = _dropEnabled[1] = false;
123 _fill_label.set_alignment(0.0, 0.5);
124 _fill_label.set_padding(0, 0);
125 _stroke_label.set_alignment(0.0, 0.5);
126 _stroke_label.set_padding(0, 0);
127 _opacity_label.set_alignment(0.0, 0.5);
128 _opacity_label.set_padding(0, 0);
130 _table.set_col_spacings (2);
131 _table.set_row_spacings (0);
133 for (int i = SS_FILL; i <= SS_STROKE; i++) {
135 _na[i].set_markup (_("N/A"));
136 sp_set_font_size_smaller (GTK_WIDGET(_na[i].gobj()));
137 _na[i].show_all();
138 __na[i] = (_("Nothing selected"));
140 _none[i].set_markup (_("<i>None</i>"));
141 sp_set_font_size_smaller (GTK_WIDGET(_none[i].gobj()));
142 _none[i].show_all();
143 __none[i] = (i == SS_FILL)? (_("No fill")) : (_("No stroke"));
145 _pattern[i].set_markup (_("Pattern"));
146 sp_set_font_size_smaller (GTK_WIDGET(_pattern[i].gobj()));
147 _pattern[i].show_all();
148 __pattern[i] = (i == SS_FILL)? (_("Pattern fill")) : (_("Pattern stroke"));
150 _lgradient[i].set_markup (_("<b>L</b>"));
151 sp_set_font_size_smaller (GTK_WIDGET(_lgradient[i].gobj()));
152 _lgradient[i].show_all();
153 __lgradient[i] = (i == SS_FILL)? (_("Linear gradient fill")) : (_("Linear gradient stroke"));
155 _gradient_preview_l[i] = GTK_WIDGET(sp_gradient_image_new (NULL));
156 _gradient_box_l[i].pack_start(_lgradient[i]);
157 _gradient_box_l[i].pack_start(*(Glib::wrap(_gradient_preview_l[i])));
158 _gradient_box_l[i].show_all();
160 _rgradient[i].set_markup (_("<b>R</b>"));
161 sp_set_font_size_smaller (GTK_WIDGET(_rgradient[i].gobj()));
162 _rgradient[i].show_all();
163 __rgradient[i] = (i == SS_FILL)? (_("Radial gradient fill")) : (_("Radial gradient stroke"));
165 _gradient_preview_r[i] = GTK_WIDGET(sp_gradient_image_new (NULL));
166 _gradient_box_r[i].pack_start(_rgradient[i]);
167 _gradient_box_r[i].pack_start(*(Glib::wrap(_gradient_preview_r[i])));
168 _gradient_box_r[i].show_all();
170 _many[i].set_markup (_("Different"));
171 sp_set_font_size_smaller (GTK_WIDGET(_many[i].gobj()));
172 _many[i].show_all();
173 __many[i] = (i == SS_FILL)? (_("Different fills")) : (_("Different strokes"));
175 _unset[i].set_markup (_("<b>Unset</b>"));
176 sp_set_font_size_smaller (GTK_WIDGET(_unset[i].gobj()));
177 _unset[i].show_all();
178 __unset[i] = (i == SS_FILL)? (_("Unset fill")) : (_("Unset stroke"));
180 _color_preview[i] = new Inkscape::UI::Widget::ColorPreview (0);
181 __color[i] = (i == SS_FILL)? (_("Flat color fill")) : (_("Flat color stroke"));
183 // TRANSLATOR COMMENT: A means "Averaged"
184 _averaged[i].set_markup (_("<b>a</b>"));
185 sp_set_font_size_smaller (GTK_WIDGET(_averaged[i].gobj()));
186 _averaged[i].show_all();
187 __averaged[i] = (i == SS_FILL)? (_("Fill is averaged over selected objects")) : (_("Stroke is averaged over selected objects"));
189 // TRANSLATOR COMMENT: M means "Multiple"
190 _multiple[i].set_markup (_("<b>m</b>"));
191 sp_set_font_size_smaller (GTK_WIDGET(_multiple[i].gobj()));
192 _multiple[i].show_all();
193 __multiple[i] = (i == SS_FILL)? (_("Multiple selected objects have the same fill")) : (_("Multiple selected objects have the same stroke"));
195 _popup_edit[i].add(*(new Gtk::Label((i == SS_FILL)? _("Edit fill...") : _("Edit stroke..."), 0.0, 0.5)));
196 _popup_edit[i].signal_activate().connect(sigc::mem_fun(*this,
197 (i == SS_FILL)? &SelectedStyle::on_fill_edit : &SelectedStyle::on_stroke_edit ));
199 _popup_lastused[i].add(*(new Gtk::Label(_("Last set color"), 0.0, 0.5)));
200 _popup_lastused[i].signal_activate().connect(sigc::mem_fun(*this,
201 (i == SS_FILL)? &SelectedStyle::on_fill_lastused : &SelectedStyle::on_stroke_lastused ));
203 _popup_lastselected[i].add(*(new Gtk::Label(_("Last selected color"), 0.0, 0.5)));
204 _popup_lastselected[i].signal_activate().connect(sigc::mem_fun(*this,
205 (i == SS_FILL)? &SelectedStyle::on_fill_lastselected : &SelectedStyle::on_stroke_lastselected ));
207 _popup_invert[i].add(*(new Gtk::Label(_("Invert"), 0.0, 0.5)));
208 _popup_invert[i].signal_activate().connect(sigc::mem_fun(*this,
209 (i == SS_FILL)? &SelectedStyle::on_fill_invert : &SelectedStyle::on_stroke_invert ));
211 _popup_white[i].add(*(new Gtk::Label(_("White"), 0.0, 0.5)));
212 _popup_white[i].signal_activate().connect(sigc::mem_fun(*this,
213 (i == SS_FILL)? &SelectedStyle::on_fill_white : &SelectedStyle::on_stroke_white ));
215 _popup_black[i].add(*(new Gtk::Label(_("Black"), 0.0, 0.5)));
216 _popup_black[i].signal_activate().connect(sigc::mem_fun(*this,
217 (i == SS_FILL)? &SelectedStyle::on_fill_black : &SelectedStyle::on_stroke_black ));
219 _popup_copy[i].add(*(new Gtk::Label(_("Copy color"), 0.0, 0.5)));
220 _popup_copy[i].signal_activate().connect(sigc::mem_fun(*this,
221 (i == SS_FILL)? &SelectedStyle::on_fill_copy : &SelectedStyle::on_stroke_copy ));
223 _popup_paste[i].add(*(new Gtk::Label(_("Paste color"), 0.0, 0.5)));
224 _popup_paste[i].signal_activate().connect(sigc::mem_fun(*this,
225 (i == SS_FILL)? &SelectedStyle::on_fill_paste : &SelectedStyle::on_stroke_paste ));
227 _popup_swap[i].add(*(new Gtk::Label(_("Swap fill and stroke"), 0.0, 0.5)));
228 _popup_swap[i].signal_activate().connect(sigc::mem_fun(*this,
229 &SelectedStyle::on_fillstroke_swap));
231 _popup_opaque[i].add(*(new Gtk::Label((i == SS_FILL)? _("Make fill opaque") : _("Make stroke opaque"), 0.0, 0.5)));
232 _popup_opaque[i].signal_activate().connect(sigc::mem_fun(*this,
233 (i == SS_FILL)? &SelectedStyle::on_fill_opaque : &SelectedStyle::on_stroke_opaque ));
235 //TRANSLATORS COMMENT: unset is a verb here
236 _popup_unset[i].add(*(new Gtk::Label((i == SS_FILL)? _("Unset fill") : _("Unset stroke"), 0.0, 0.5)));
237 _popup_unset[i].signal_activate().connect(sigc::mem_fun(*this,
238 (i == SS_FILL)? &SelectedStyle::on_fill_unset : &SelectedStyle::on_stroke_unset ));
240 _popup_remove[i].add(*(new Gtk::Label((i == SS_FILL)? _("Remove fill") : _("Remove stroke"), 0.0, 0.5)));
241 _popup_remove[i].signal_activate().connect(sigc::mem_fun(*this,
242 (i == SS_FILL)? &SelectedStyle::on_fill_remove : &SelectedStyle::on_stroke_remove ));
244 _popup[i].attach(_popup_edit[i], 0,1, 0,1);
245 _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 1,2);
246 _popup[i].attach(_popup_lastused[i], 0,1, 2,3);
247 _popup[i].attach(_popup_lastselected[i], 0,1, 3,4);
248 _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 4,5);
249 _popup[i].attach(_popup_invert[i], 0,1, 5,6);
250 _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 6,7);
251 _popup[i].attach(_popup_white[i], 0,1, 7,8);
252 _popup[i].attach(_popup_black[i], 0,1, 8,9);
253 _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 9,10);
254 _popup[i].attach(_popup_copy[i], 0,1, 10,11);
255 _popup_copy[i].set_sensitive(false);
256 _popup[i].attach(_popup_paste[i], 0,1, 11,12);
257 _popup[i].attach(_popup_swap[i], 0,1, 12,13);
258 _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 13,14);
259 _popup[i].attach(_popup_opaque[i], 0,1, 14,15);
260 _popup[i].attach(_popup_unset[i], 0,1, 15,16);
261 _popup[i].attach(_popup_remove[i], 0,1, 16,17);
262 _popup[i].show_all();
264 _mode[i] = SS_NA;
265 }
267 {
268 _popup_px.add(*(new Gtk::Label(_("px"), 0.0, 0.5)));
269 _popup_px.signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::on_popup_px));
270 _popup_sw.attach(_popup_px, 0,1, 0,1);
272 _popup_pt.add(*(new Gtk::Label(_("pt"), 0.0, 0.5)));
273 _popup_pt.signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::on_popup_pt));
274 _popup_sw.attach(_popup_pt, 0,1, 1,2);
276 _popup_mm.add(*(new Gtk::Label(_("mm"), 0.0, 0.5)));
277 _popup_mm.signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::on_popup_mm));
278 _popup_sw.attach(_popup_mm, 0,1, 2,3);
280 _popup_sw.attach(*(new Gtk::SeparatorMenuItem()), 0,1, 3,4);
282 for (guint i = 0; i < G_N_ELEMENTS(_sw_presets_str); ++i) {
283 Gtk::MenuItem *mi = Gtk::manage(new Gtk::MenuItem());
284 mi->add(*(new Gtk::Label(_sw_presets_str[i], 0.0, 0.5)));
285 mi->signal_activate().connect(sigc::bind<int>(sigc::mem_fun(*this, &SelectedStyle::on_popup_preset), i));
286 _popup_sw.attach(*mi, 0,1, 4+i, 5+i);
287 }
289 guint i = G_N_ELEMENTS(_sw_presets_str) + 5;
291 _popup_sw.attach(*(new Gtk::SeparatorMenuItem()), 0,1, i,i+1);
293 _popup_sw_remove.add(*(new Gtk::Label(_("Remove"), 0.0, 0.5)));
294 _popup_sw_remove.signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::on_stroke_remove));
295 _popup_sw.attach(_popup_sw_remove, 0,1, i+1,i+2);
297 _popup_sw.show_all();
298 }
300 _fill_place.signal_button_press_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_fill_click));
301 _stroke_place.signal_button_press_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_stroke_click));
302 _opacity_place.signal_button_press_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_opacity_click));
303 _stroke_width_place.signal_button_press_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_sw_click));
305 _opacity_sb.signal_populate_popup().connect(sigc::mem_fun(*this, &SelectedStyle::on_opacity_menu));
306 _opacity_sb.signal_value_changed().connect(sigc::mem_fun(*this, &SelectedStyle::on_opacity_changed));
308 _fill_place.add(_na[SS_FILL]);
309 _tooltips.set_tip(_fill_place, __na[SS_FILL]);
311 _stroke_place.add(_na[SS_STROKE]);
312 _tooltips.set_tip(_stroke_place, __na[SS_STROKE]);
314 _stroke.pack_start(_stroke_place);
315 _stroke_width_place.add(_stroke_width);
316 _stroke.pack_start(_stroke_width_place, Gtk::PACK_SHRINK);
318 _opacity_sb.set_adjustment(_opacity_adjustment);
319 sp_set_font_size_smaller (GTK_WIDGET(_opacity_sb.gobj()));
320 _opacity_sb.set_size_request (SELECTED_STYLE_SB_WIDTH, -1);
321 _opacity_sb.set_sensitive (false);
323 _table.attach(_fill_label, 0,1, 0,1, Gtk::FILL, Gtk::SHRINK);
324 _table.attach(_stroke_label, 0,1, 1,2, Gtk::FILL, Gtk::SHRINK);
326 _table.attach(_fill_flag_place, 1,2, 0,1, Gtk::SHRINK, Gtk::SHRINK);
327 _table.attach(_stroke_flag_place, 1,2, 1,2, Gtk::SHRINK, Gtk::SHRINK);
329 _table.attach(_fill_place, 2,3, 0,1);
330 _table.attach(_stroke, 2,3, 1,2);
332 _opacity_place.add(_opacity_label);
333 _table.attach(_opacity_place, 4,5, 0,2, Gtk::SHRINK, Gtk::SHRINK);
334 _table.attach(_opacity_sb, 5,6, 0,2, Gtk::SHRINK, Gtk::SHRINK);
336 pack_start(_table, true, true, 2);
338 set_size_request (SELECTED_STYLE_WIDTH, -1);
340 sp_set_font_size_smaller (GTK_WIDGET(_opacity_label.gobj()));
341 sp_set_font_size_smaller (GTK_WIDGET(_opacity_sb.gobj()));
342 sp_set_font_size_smaller (GTK_WIDGET(_fill_place.gobj()));
343 sp_set_font_size_smaller (GTK_WIDGET(_fill_flag_place.gobj()));
344 sp_set_font_size_smaller (GTK_WIDGET(_stroke_place.gobj()));
345 sp_set_font_size_smaller (GTK_WIDGET(_stroke_flag_place.gobj()));
346 sp_set_font_size_smaller (GTK_WIDGET(_stroke_width.gobj()));
347 sp_set_font_size_smaller (GTK_WIDGET(_fill_label.gobj()));
348 sp_set_font_size_smaller (GTK_WIDGET(_stroke_label.gobj()));
350 _drop[SS_FILL] = new DropTracker();
351 ((DropTracker*)_drop[SS_FILL])->parent = this;
352 ((DropTracker*)_drop[SS_FILL])->item = SS_FILL;
354 _drop[SS_STROKE] = new DropTracker();
355 ((DropTracker*)_drop[SS_STROKE])->parent = this;
356 ((DropTracker*)_drop[SS_STROKE])->item = SS_STROKE;
358 g_signal_connect(_stroke_place.gobj(),
359 "drag_data_received",
360 G_CALLBACK(dragDataReceived),
361 _drop[SS_STROKE]);
363 g_signal_connect(_fill_place.gobj(),
364 "drag_data_received",
365 G_CALLBACK(dragDataReceived),
366 _drop[SS_FILL]);
367 }
369 SelectedStyle::~SelectedStyle()
370 {
371 selection_changed_connection->disconnect();
372 delete selection_changed_connection;
373 selection_modified_connection->disconnect();
374 delete selection_modified_connection;
375 subselection_changed_connection->disconnect();
376 delete subselection_changed_connection;
378 for (int i = SS_FILL; i <= SS_STROKE; i++) {
379 delete _color_preview[i];
380 // FIXME: do we need this? the destroy methods are not exported
381 //sp_gradient_image_destroy(GTK_OBJECT(_gradient_preview_l[i]));
382 //sp_gradient_image_destroy(GTK_OBJECT(_gradient_preview_r[i]));
383 }
385 delete (DropTracker*)_drop[SS_FILL];
386 delete (DropTracker*)_drop[SS_STROKE];
387 }
389 void
390 SelectedStyle::setDesktop(SPDesktop *desktop)
391 {
392 _desktop = desktop;
393 gtk_object_set_data (GTK_OBJECT(_opacity_sb.gobj()), "dtw", _desktop->canvas);
395 Inkscape::Selection *selection = sp_desktop_selection (desktop);
397 selection_changed_connection = new sigc::connection (selection->connectChanged(
398 sigc::bind (
399 sigc::ptr_fun(&ss_selection_changed),
400 this )
401 ));
402 selection_modified_connection = new sigc::connection (selection->connectModified(
403 sigc::bind (
404 sigc::ptr_fun(&ss_selection_modified),
405 this )
406 ));
407 subselection_changed_connection = new sigc::connection (desktop->connectToolSubselectionChanged(
408 sigc::bind (
409 sigc::ptr_fun(&ss_subselection_changed),
410 this )
411 ));
413 //_sw_unit = (SPUnit *) sp_desktop_namedview(desktop)->doc_units;
414 }
416 void SelectedStyle::dragDataReceived( GtkWidget *widget,
417 GdkDragContext *drag_context,
418 gint x, gint y,
419 GtkSelectionData *data,
420 guint info,
421 guint event_time,
422 gpointer user_data )
423 {
424 DropTracker* tracker = (DropTracker*)user_data;
426 switch ( (int)tracker->item ) {
427 case SS_FILL:
428 case SS_STROKE:
429 {
430 if ( data->length == 8 ) {
431 gchar c[64];
432 // Careful about endian issues.
433 guint16* dataVals = (guint16*)data->data;
434 sp_svg_write_color( c, sizeof(c),
435 SP_RGBA32_U_COMPOSE(
436 0x0ff & (dataVals[0] >> 8),
437 0x0ff & (dataVals[1] >> 8),
438 0x0ff & (dataVals[2] >> 8),
439 0xff // can't have transparency in the color itself
440 //0x0ff & (data->data[3] >> 8),
441 ));
442 SPCSSAttr *css = sp_repr_css_attr_new();
443 sp_repr_css_set_property( css, (tracker->item == SS_FILL) ? "fill":"stroke", c );
444 sp_desktop_set_style( tracker->parent->_desktop, css );
445 sp_repr_css_attr_unref( css );
446 sp_document_done( sp_desktop_document(tracker->parent->_desktop) , SP_VERB_NONE,
447 _("Drop color"));
448 }
449 }
450 break;
451 }
452 }
454 void SelectedStyle::on_fill_remove() {
455 SPCSSAttr *css = sp_repr_css_attr_new ();
456 sp_repr_css_set_property (css, "fill", "none");
457 sp_desktop_set_style (_desktop, css, true, true);
458 sp_repr_css_attr_unref (css);
459 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
460 _("Remove fill"));
461 }
463 void SelectedStyle::on_stroke_remove() {
464 SPCSSAttr *css = sp_repr_css_attr_new ();
465 sp_repr_css_set_property (css, "stroke", "none");
466 sp_desktop_set_style (_desktop, css, true, true);
467 sp_repr_css_attr_unref (css);
468 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
469 _("Remove stroke"));
470 }
472 void SelectedStyle::on_fill_unset() {
473 SPCSSAttr *css = sp_repr_css_attr_new ();
474 sp_repr_css_unset_property (css, "fill");
475 sp_desktop_set_style (_desktop, css, true, true);
476 sp_repr_css_attr_unref (css);
477 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
478 _("Unset fill"));
479 }
481 void SelectedStyle::on_stroke_unset() {
482 SPCSSAttr *css = sp_repr_css_attr_new ();
483 sp_repr_css_unset_property (css, "stroke");
484 sp_repr_css_unset_property (css, "stroke-opacity");
485 sp_repr_css_unset_property (css, "stroke-width");
486 sp_repr_css_unset_property (css, "stroke-miterlimit");
487 sp_repr_css_unset_property (css, "stroke-linejoin");
488 sp_repr_css_unset_property (css, "stroke-linecap");
489 sp_repr_css_unset_property (css, "stroke-dashoffset");
490 sp_repr_css_unset_property (css, "stroke-dasharray");
491 sp_desktop_set_style (_desktop, css, true, true);
492 sp_repr_css_attr_unref (css);
493 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
494 _("Unset stroke"));
495 }
497 void SelectedStyle::on_fill_opaque() {
498 SPCSSAttr *css = sp_repr_css_attr_new ();
499 sp_repr_css_set_property (css, "fill-opacity", "1");
500 sp_desktop_set_style (_desktop, css, true);
501 sp_repr_css_attr_unref (css);
502 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
503 _("Make fill opaque"));
504 }
506 void SelectedStyle::on_stroke_opaque() {
507 SPCSSAttr *css = sp_repr_css_attr_new ();
508 sp_repr_css_set_property (css, "stroke-opacity", "1");
509 sp_desktop_set_style (_desktop, css, true);
510 sp_repr_css_attr_unref (css);
511 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
512 _("Make fill opaque"));
513 }
515 void SelectedStyle::on_fill_lastused() {
516 SPCSSAttr *css = sp_repr_css_attr_new ();
517 guint32 color = sp_desktop_get_color(_desktop, true);
518 gchar c[64];
519 sp_svg_write_color (c, sizeof(c), color);
520 sp_repr_css_set_property (css, "fill", c);
521 sp_desktop_set_style (_desktop, css);
522 sp_repr_css_attr_unref (css);
523 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
524 _("Apply last set color to fill"));
525 }
527 void SelectedStyle::on_stroke_lastused() {
528 SPCSSAttr *css = sp_repr_css_attr_new ();
529 guint32 color = sp_desktop_get_color(_desktop, false);
530 gchar c[64];
531 sp_svg_write_color (c, sizeof(c), color);
532 sp_repr_css_set_property (css, "stroke", c);
533 sp_desktop_set_style (_desktop, css);
534 sp_repr_css_attr_unref (css);
535 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
536 _("Apply last set color to stroke"));
537 }
539 void SelectedStyle::on_fill_lastselected() {
540 SPCSSAttr *css = sp_repr_css_attr_new ();
541 gchar c[64];
542 sp_svg_write_color (c, sizeof(c), _lastselected[SS_FILL]);
543 sp_repr_css_set_property (css, "fill", c);
544 sp_desktop_set_style (_desktop, css);
545 sp_repr_css_attr_unref (css);
546 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
547 _("Apply last selected color to fill"));
548 }
550 void SelectedStyle::on_stroke_lastselected() {
551 SPCSSAttr *css = sp_repr_css_attr_new ();
552 gchar c[64];
553 sp_svg_write_color (c, sizeof(c), _lastselected[SS_STROKE]);
554 sp_repr_css_set_property (css, "stroke", c);
555 sp_desktop_set_style (_desktop, css);
556 sp_repr_css_attr_unref (css);
557 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
558 _("Apply last selected color to stroke"));
559 }
561 void SelectedStyle::on_fill_invert() {
562 SPCSSAttr *css = sp_repr_css_attr_new ();
563 guint32 color = _thisselected[SS_FILL];
564 gchar c[64];
565 if (_mode[SS_FILL] != SS_COLOR) return;
566 sp_svg_write_color (c, sizeof(c),
567 SP_RGBA32_U_COMPOSE(
568 (255 - SP_RGBA32_R_U(color)),
569 (255 - SP_RGBA32_G_U(color)),
570 (255 - SP_RGBA32_B_U(color)),
571 SP_RGBA32_A_U(color)
572 )
573 );
574 sp_repr_css_set_property (css, "fill", c);
575 sp_desktop_set_style (_desktop, css);
576 sp_repr_css_attr_unref (css);
577 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
578 _("Invert fill"));
579 }
581 void SelectedStyle::on_stroke_invert() {
582 SPCSSAttr *css = sp_repr_css_attr_new ();
583 guint32 color = _thisselected[SS_STROKE];
584 gchar c[64];
585 if (_mode[SS_STROKE] != SS_COLOR) return;
586 sp_svg_write_color (c, sizeof(c),
587 SP_RGBA32_U_COMPOSE(
588 (255 - SP_RGBA32_R_U(color)),
589 (255 - SP_RGBA32_G_U(color)),
590 (255 - SP_RGBA32_B_U(color)),
591 SP_RGBA32_A_U(color)
592 )
593 );
594 sp_repr_css_set_property (css, "stroke", c);
595 sp_desktop_set_style (_desktop, css);
596 sp_repr_css_attr_unref (css);
597 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
598 _("Invert stroke"));
599 }
601 void SelectedStyle::on_fill_white() {
602 SPCSSAttr *css = sp_repr_css_attr_new ();
603 gchar c[64];
604 sp_svg_write_color (c, sizeof(c), 0xffffffff);
605 sp_repr_css_set_property (css, "fill", c);
606 sp_repr_css_set_property (css, "fill-opacity", "1");
607 sp_desktop_set_style (_desktop, css);
608 sp_repr_css_attr_unref (css);
609 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
610 _("White fill"));
611 }
613 void SelectedStyle::on_stroke_white() {
614 SPCSSAttr *css = sp_repr_css_attr_new ();
615 gchar c[64];
616 sp_svg_write_color (c, sizeof(c), 0xffffffff);
617 sp_repr_css_set_property (css, "stroke", c);
618 sp_repr_css_set_property (css, "stroke-opacity", "1");
619 sp_desktop_set_style (_desktop, css);
620 sp_repr_css_attr_unref (css);
621 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
622 _("White stroke"));
623 }
625 void SelectedStyle::on_fill_black() {
626 SPCSSAttr *css = sp_repr_css_attr_new ();
627 gchar c[64];
628 sp_svg_write_color (c, sizeof(c), 0x000000ff);
629 sp_repr_css_set_property (css, "fill", c);
630 sp_repr_css_set_property (css, "fill-opacity", "1.0");
631 sp_desktop_set_style (_desktop, css);
632 sp_repr_css_attr_unref (css);
633 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
634 _("Black fill"));
635 }
637 void SelectedStyle::on_stroke_black() {
638 SPCSSAttr *css = sp_repr_css_attr_new ();
639 gchar c[64];
640 sp_svg_write_color (c, sizeof(c), 0x000000ff);
641 sp_repr_css_set_property (css, "stroke", c);
642 sp_repr_css_set_property (css, "stroke-opacity", "1.0");
643 sp_desktop_set_style (_desktop, css);
644 sp_repr_css_attr_unref (css);
645 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
646 _("Black stroke"));
647 }
649 void SelectedStyle::on_fill_copy() {
650 if (_mode[SS_FILL] == SS_COLOR) {
651 gchar c[64];
652 sp_svg_write_color (c, sizeof(c), _thisselected[SS_FILL]);
653 Glib::ustring text;
654 text += c;
655 if (!text.empty()) {
656 Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
657 refClipboard->set_text(text);
658 }
659 }
660 }
662 void SelectedStyle::on_stroke_copy() {
663 if (_mode[SS_STROKE] == SS_COLOR) {
664 gchar c[64];
665 sp_svg_write_color (c, sizeof(c), _thisselected[SS_STROKE]);
666 Glib::ustring text;
667 text += c;
668 if (!text.empty()) {
669 Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
670 refClipboard->set_text(text);
671 }
672 }
673 }
675 void SelectedStyle::on_fill_paste() {
676 Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
677 Glib::ustring const text = refClipboard->wait_for_text();
679 if (!text.empty()) {
680 guint32 color = sp_svg_read_color(text.c_str(), 0x000000ff); // impossible value, as SVG color cannot have opacity
681 if (color == 0x000000ff) // failed to parse color string
682 return;
684 SPCSSAttr *css = sp_repr_css_attr_new ();
685 sp_repr_css_set_property (css, "fill", text.c_str());
686 sp_desktop_set_style (_desktop, css);
687 sp_repr_css_attr_unref (css);
688 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
689 _("Paste fill"));
690 }
691 }
693 void SelectedStyle::on_stroke_paste() {
694 Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
695 Glib::ustring const text = refClipboard->wait_for_text();
697 if (!text.empty()) {
698 guint32 color = sp_svg_read_color(text.c_str(), 0x000000ff); // impossible value, as SVG color cannot have opacity
699 if (color == 0x000000ff) // failed to parse color string
700 return;
702 SPCSSAttr *css = sp_repr_css_attr_new ();
703 sp_repr_css_set_property (css, "stroke", text.c_str());
704 sp_desktop_set_style (_desktop, css);
705 sp_repr_css_attr_unref (css);
706 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
707 _("Paste stroke"));
708 }
709 }
711 void SelectedStyle::on_fillstroke_swap() {
712 SPCSSAttr *css = sp_repr_css_attr_new ();
714 switch (_mode[SS_FILL]) {
715 case SS_NA:
716 case SS_MANY:
717 break;
718 case SS_NONE:
719 sp_repr_css_set_property (css, "stroke", "none");
720 break;
721 case SS_UNSET:
722 sp_repr_css_unset_property (css, "stroke");
723 break;
724 case SS_COLOR:
725 gchar c[64];
726 sp_svg_write_color (c, sizeof(c), _thisselected[SS_FILL]);
727 sp_repr_css_set_property (css, "stroke", c);
728 break;
729 case SS_LGRADIENT:
730 case SS_RGRADIENT:
731 case SS_PATTERN:
732 sp_repr_css_set_property (css, "stroke", _paintserver_id[SS_FILL].c_str());
733 break;
734 }
736 switch (_mode[SS_STROKE]) {
737 case SS_NA:
738 case SS_MANY:
739 break;
740 case SS_NONE:
741 sp_repr_css_set_property (css, "fill", "none");
742 break;
743 case SS_UNSET:
744 sp_repr_css_unset_property (css, "fill");
745 break;
746 case SS_COLOR:
747 gchar c[64];
748 sp_svg_write_color (c, sizeof(c), _thisselected[SS_STROKE]);
749 sp_repr_css_set_property (css, "fill", c);
750 break;
751 case SS_LGRADIENT:
752 case SS_RGRADIENT:
753 case SS_PATTERN:
754 sp_repr_css_set_property (css, "fill", _paintserver_id[SS_STROKE].c_str());
755 break;
756 }
758 sp_desktop_set_style (_desktop, css);
759 sp_repr_css_attr_unref (css);
760 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
761 _("Swap fill and stroke"));
762 }
764 void SelectedStyle::on_fill_edit() {
765 if (Dialog::FillAndStroke *dialog = dynamic_cast<Dialog::FillAndStroke *>(
766 _desktop->_dlg_mgr->getDialog("FillAndStroke")))
767 dialog->showPageFill();
768 }
770 void SelectedStyle::on_stroke_edit() {
771 if (Dialog::FillAndStroke *dialog = dynamic_cast<Dialog::FillAndStroke *>(
772 _desktop->_dlg_mgr->getDialog("FillAndStroke")))
773 dialog->showPageStrokePaint();
774 }
776 bool
777 SelectedStyle::on_fill_click(GdkEventButton *event)
778 {
779 if (event->button == 1) { // click, open fill&stroke
781 if (Dialog::FillAndStroke *dialog = dynamic_cast<Dialog::FillAndStroke *>(
782 _desktop->_dlg_mgr->getDialog("FillAndStroke")))
783 dialog->showPageFill();
785 } else if (event->button == 3) { // right-click, popup menu
786 _popup[SS_FILL].popup(event->button, event->time);
787 } else if (event->button == 2) { // middle click, toggle none/lastcolor
788 if (_mode[SS_FILL] == SS_NONE) {
789 on_fill_lastused();
790 } else {
791 on_fill_remove();
792 }
793 }
794 return true;
795 }
797 bool
798 SelectedStyle::on_stroke_click(GdkEventButton *event)
799 {
800 if (event->button == 1) { // click, open fill&stroke
801 if (Dialog::FillAndStroke *dialog = dynamic_cast<Dialog::FillAndStroke *>(
802 _desktop->_dlg_mgr->getDialog("FillAndStroke")))
803 dialog->showPageStrokePaint();
804 } else if (event->button == 3) { // right-click, popup menu
805 _popup[SS_STROKE].popup(event->button, event->time);
806 } else if (event->button == 2) { // middle click, toggle none/lastcolor
807 if (_mode[SS_STROKE] == SS_NONE) {
808 on_stroke_lastused();
809 } else {
810 on_stroke_remove();
811 }
812 }
813 return true;
814 }
816 bool
817 SelectedStyle::on_sw_click(GdkEventButton *event)
818 {
819 if (event->button == 1) { // click, open fill&stroke
820 if (Dialog::FillAndStroke *dialog = dynamic_cast<Dialog::FillAndStroke *>(
821 _desktop->_dlg_mgr->getDialog("FillAndStroke")))
822 dialog->showPageStrokeStyle();
823 } else if (event->button == 3) { // right-click, popup menu
824 _popup_sw.popup(event->button, event->time);
825 } else if (event->button == 2) { // middle click, toggle none/lastwidth?
826 //
827 }
828 return true;
829 }
831 bool
832 SelectedStyle::on_opacity_click(GdkEventButton *event)
833 {
834 if (event->button == 2) { // middle click
835 const char* opacity = _opacity_sb.get_value() < 50? "0.5" : (_opacity_sb.get_value() == 100? "0" : "1");
836 SPCSSAttr *css = sp_repr_css_attr_new ();
837 sp_repr_css_set_property (css, "opacity", opacity);
838 sp_desktop_set_style (_desktop, css);
839 sp_repr_css_attr_unref (css);
840 sp_document_done (sp_desktop_document (_desktop), SP_VERB_DIALOG_FILL_STROKE,
841 _("Change opacity"));
842 return true;
843 }
845 return false;
846 }
848 void SelectedStyle::on_popup_px() {
849 _sw_unit = (SPUnit *) &(sp_unit_get_by_id(SP_UNIT_PX));
850 update();
851 }
852 void SelectedStyle::on_popup_pt() {
853 _sw_unit = (SPUnit *) &(sp_unit_get_by_id(SP_UNIT_PT));
854 update();
855 }
856 void SelectedStyle::on_popup_mm() {
857 _sw_unit = (SPUnit *) &(sp_unit_get_by_id(SP_UNIT_MM));
858 update();
859 }
861 void SelectedStyle::on_popup_preset(int i) {
862 SPCSSAttr *css = sp_repr_css_attr_new ();
863 gdouble w;
864 if (_sw_unit) {
865 w = sp_units_get_pixels (_sw_presets[i], *_sw_unit);
866 } else {
867 w = _sw_presets[i];
868 }
869 Inkscape::CSSOStringStream os;
870 os << w;
871 sp_repr_css_set_property (css, "stroke-width", os.str().c_str());
872 // FIXME: update dash patterns!
873 sp_desktop_set_style (_desktop, css, true);
874 sp_repr_css_attr_unref (css);
875 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_SWATCHES,
876 _("Change stroke width"));
877 }
879 void
880 SelectedStyle::update()
881 {
882 if (_desktop == NULL)
883 return;
885 // create temporary style
886 SPStyle *query = sp_style_new (sp_desktop_document(_desktop));
888 for (int i = SS_FILL; i <= SS_STROKE; i++) {
889 Gtk::EventBox *place = (i == SS_FILL)? &_fill_place : &_stroke_place;
890 Gtk::EventBox *flag_place = (i == SS_FILL)? &_fill_flag_place : &_stroke_flag_place;
892 place->remove();
893 flag_place->remove();
895 _tooltips.unset_tip(*place);
896 _tooltips.unset_tip(*flag_place);
898 _mode[i] = SS_NA;
899 _paintserver_id[i].clear();
901 _popup_copy[i].set_sensitive(false);
903 // query style from desktop. This returns a result flag and fills query with the style of subselection, if any, or selection
904 int result = sp_desktop_query_style (_desktop, query,
905 (i == SS_FILL)? QUERY_STYLE_PROPERTY_FILL : QUERY_STYLE_PROPERTY_STROKE);
906 switch (result) {
907 case QUERY_STYLE_NOTHING:
908 place->add(_na[i]);
909 _tooltips.set_tip(*place, __na[i]);
910 _mode[i] = SS_NA;
911 if ( _dropEnabled[i] ) {
912 gtk_drag_dest_unset( GTK_WIDGET((i==SS_FILL) ? _fill_place.gobj():_stroke_place.gobj()) );
913 _dropEnabled[i] = false;
914 }
915 break;
916 case QUERY_STYLE_SINGLE:
917 case QUERY_STYLE_MULTIPLE_AVERAGED:
918 case QUERY_STYLE_MULTIPLE_SAME:
919 if ( !_dropEnabled[i] ) {
920 gtk_drag_dest_set( GTK_WIDGET( (i==SS_FILL) ? _fill_place.gobj():_stroke_place.gobj()),
921 GTK_DEST_DEFAULT_ALL,
922 ui_drop_target_entries,
923 nui_drop_target_entries,
924 GdkDragAction(GDK_ACTION_COPY | GDK_ACTION_MOVE) );
925 _dropEnabled[i] = true;
926 }
927 SPIPaint *paint;
928 if (i == SS_FILL) {
929 paint = &(query->fill);
930 } else {
931 paint = &(query->stroke);
932 }
933 if (paint->set && paint->isPaintserver()) {
934 SPPaintServer *server = (i == SS_FILL)? SP_STYLE_FILL_SERVER (query) : SP_STYLE_STROKE_SERVER (query);
935 if ( server ) {
936 Inkscape::XML::Node *srepr = SP_OBJECT_REPR(server);
937 _paintserver_id[i] += "url(#";
938 _paintserver_id[i] += srepr->attribute("id");
939 _paintserver_id[i] += ")";
941 if (SP_IS_LINEARGRADIENT (server)) {
942 SPGradient *vector = sp_gradient_get_vector(SP_GRADIENT(server), false);
943 sp_gradient_image_set_gradient ((SPGradientImage *) _gradient_preview_l[i], vector);
944 place->add(_gradient_box_l[i]);
945 _tooltips.set_tip(*place, __lgradient[i]);
946 _mode[i] = SS_LGRADIENT;
947 } else if (SP_IS_RADIALGRADIENT (server)) {
948 SPGradient *vector = sp_gradient_get_vector(SP_GRADIENT(server), false);
949 sp_gradient_image_set_gradient ((SPGradientImage *) _gradient_preview_r[i], vector);
950 place->add(_gradient_box_r[i]);
951 _tooltips.set_tip(*place, __rgradient[i]);
952 _mode[i] = SS_RGRADIENT;
953 } else if (SP_IS_PATTERN (server)) {
954 place->add(_pattern[i]);
955 _tooltips.set_tip(*place, __pattern[i]);
956 _mode[i] = SS_PATTERN;
957 }
958 } else {
959 g_warning ("file %s: line %d: Unknown paint server", __FILE__, __LINE__);
960 }
961 } else if (paint->set && paint->isColor()) {
962 guint32 color = paint->value.color.toRGBA32(
963 SP_SCALE24_TO_FLOAT ((i == SS_FILL)? query->fill_opacity.value : query->stroke_opacity.value));
964 _lastselected[i] = _thisselected[i];
965 _thisselected[i] = color | 0xff; // only color, opacity === 1
966 ((Inkscape::UI::Widget::ColorPreview*)_color_preview[i])->setRgba32 (color);
967 _color_preview[i]->show_all();
968 place->add(*_color_preview[i]);
969 gchar c_string[64];
970 g_snprintf (c_string, 64, "%06x/%.3g", color >> 8, SP_RGBA32_A_F(color));
971 _tooltips.set_tip(*place, __color[i] + ": " + c_string);
972 _mode[i] = SS_COLOR;
973 _popup_copy[i].set_sensitive(true);
975 } else if (paint->set && paint->isNone()) {
976 place->add(_none[i]);
977 _tooltips.set_tip(*place, __none[i]);
978 _mode[i] = SS_NONE;
979 } else if (!paint->set) {
980 place->add(_unset[i]);
981 _tooltips.set_tip(*place, __unset[i]);
982 _mode[i] = SS_UNSET;
983 }
984 if (result == QUERY_STYLE_MULTIPLE_AVERAGED) {
985 flag_place->add(_averaged[i]);
986 _tooltips.set_tip(*flag_place, __averaged[i]);
987 } else if (result == QUERY_STYLE_MULTIPLE_SAME) {
988 flag_place->add(_multiple[i]);
989 _tooltips.set_tip(*flag_place, __multiple[i]);
990 }
991 break;
992 case QUERY_STYLE_MULTIPLE_DIFFERENT:
993 place->add(_many[i]);
994 _tooltips.set_tip(*place, __many[i]);
995 _mode[i] = SS_MANY;
996 break;
997 default:
998 break;
999 }
1000 }
1002 // Now query opacity
1003 _tooltips.unset_tip(_opacity_place);
1004 _tooltips.unset_tip(_opacity_sb);
1006 int result = sp_desktop_query_style (_desktop, query, QUERY_STYLE_PROPERTY_MASTEROPACITY);
1008 switch (result) {
1009 case QUERY_STYLE_NOTHING:
1010 _tooltips.set_tip(_opacity_place, _("Nothing selected"));
1011 _tooltips.set_tip(_opacity_sb, _("Nothing selected"));
1012 _opacity_sb.set_sensitive(false);
1013 break;
1014 case QUERY_STYLE_SINGLE:
1015 case QUERY_STYLE_MULTIPLE_AVERAGED:
1016 case QUERY_STYLE_MULTIPLE_SAME:
1017 _tooltips.set_tip(_opacity_place, _("Master opacity, %"));
1018 _tooltips.set_tip(_opacity_sb, _("Master opacity, %"));
1019 if (_opacity_blocked) break;
1020 _opacity_blocked = true;
1021 _opacity_sb.set_sensitive(true);
1022 _opacity_adjustment.set_value(SP_SCALE24_TO_FLOAT(query->opacity.value) * 100);
1023 _opacity_blocked = false;
1024 break;
1025 }
1027 // Now query stroke_width
1028 int result_sw = sp_desktop_query_style (_desktop, query, QUERY_STYLE_PROPERTY_STROKEWIDTH);
1029 switch (result_sw) {
1030 case QUERY_STYLE_NOTHING:
1031 _stroke_width.set_markup("");
1032 break;
1033 case QUERY_STYLE_SINGLE:
1034 case QUERY_STYLE_MULTIPLE_AVERAGED:
1035 case QUERY_STYLE_MULTIPLE_SAME:
1036 {
1037 double w;
1038 if (_sw_unit) {
1039 w = sp_pixels_get_units(query->stroke_width.computed, *_sw_unit);
1040 } else {
1041 w = query->stroke_width.computed;
1042 }
1043 {
1044 gchar *str = g_strdup_printf(" %.3g", w);
1045 _stroke_width.set_markup(str);
1046 g_free (str);
1047 }
1048 {
1049 gchar *str = g_strdup_printf(_("Stroke width: %.5g%s%s"),
1050 w,
1051 _sw_unit? sp_unit_get_abbreviation(_sw_unit) : "px",
1052 (result_sw == QUERY_STYLE_MULTIPLE_AVERAGED)?
1053 _(" (averaged)") : "");
1054 _tooltips.set_tip(_stroke_width_place, str);
1055 g_free (str);
1056 }
1057 break;
1058 }
1059 default:
1060 break;
1061 }
1063 sp_style_unref(query);
1064 }
1066 void SelectedStyle::opacity_0(void) {_opacity_sb.set_value(0);}
1067 void SelectedStyle::opacity_025(void) {_opacity_sb.set_value(25);}
1068 void SelectedStyle::opacity_05(void) {_opacity_sb.set_value(50);}
1069 void SelectedStyle::opacity_075(void) {_opacity_sb.set_value(75);}
1070 void SelectedStyle::opacity_1(void) {_opacity_sb.set_value(100);}
1072 void SelectedStyle::on_opacity_menu (Gtk::Menu *menu) {
1074 Glib::ListHandle<Gtk::Widget *> children = menu->get_children();
1075 for (Glib::ListHandle<Gtk::Widget *>::iterator iter = children.begin(); iter != children.end(); iter++) {
1076 menu->remove(*(*iter));
1077 }
1079 {
1080 Gtk::MenuItem *item = new Gtk::MenuItem;
1081 item->add(*(new Gtk::Label(_("0 (transparent)"), 0, 0)));
1082 item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_0 ));
1083 menu->add(*item);
1084 }
1085 {
1086 Gtk::MenuItem *item = new Gtk::MenuItem;
1087 item->add(*(new Gtk::Label("25%", 0, 0)));
1088 item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_025 ));
1089 menu->add(*item);
1090 }
1091 {
1092 Gtk::MenuItem *item = new Gtk::MenuItem;
1093 item->add(*(new Gtk::Label("50%", 0, 0)));
1094 item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_05 ));
1095 menu->add(*item);
1096 }
1097 {
1098 Gtk::MenuItem *item = new Gtk::MenuItem;
1099 item->add(*(new Gtk::Label("75%", 0, 0)));
1100 item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_075 ));
1101 menu->add(*item);
1102 }
1103 {
1104 Gtk::MenuItem *item = new Gtk::MenuItem;
1105 item->add(*(new Gtk::Label(_("100% (opaque)"), 0, 0)));
1106 item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_1 ));
1107 menu->add(*item);
1108 }
1110 menu->show_all();
1111 }
1113 void SelectedStyle::on_opacity_changed () {
1114 if (_opacity_blocked)
1115 return;
1116 _opacity_blocked = true;
1117 SPCSSAttr *css = sp_repr_css_attr_new ();
1118 Inkscape::CSSOStringStream os;
1119 os << CLAMP ((_opacity_adjustment.get_value() / 100), 0.0, 1.0);
1120 sp_repr_css_set_property (css, "opacity", os.str().c_str());
1121 // FIXME: workaround for GTK breakage: display interruptibility sometimes results in GTK
1122 // sending multiple value-changed events. As if when Inkscape interrupts redraw for main loop
1123 // iterations, GTK discovers that this callback hasn't finished yet, and for some weird reason
1124 // decides to add yet another value-changed event to the queue. Totally braindead if you ask
1125 // me. As a result, scrolling the spinbutton once results in runaway change until it hits 1.0
1126 // or 0.0. (And no, this is not a race with ::update, I checked that.)
1127 // Sigh. So we disable interruptibility while we're setting the new value.
1128 sp_canvas_force_full_redraw_after_interruptions(sp_desktop_canvas(_desktop), 0);
1129 sp_desktop_set_style (_desktop, css);
1130 sp_repr_css_attr_unref (css);
1131 sp_document_maybe_done (sp_desktop_document (_desktop), "fillstroke:opacity", SP_VERB_DIALOG_FILL_STROKE,
1132 _("Change opacity"));
1133 // resume interruptibility
1134 sp_canvas_end_forced_full_redraws(sp_desktop_canvas(_desktop));
1135 spinbutton_defocus(GTK_OBJECT(_opacity_sb.gobj()));
1136 _opacity_blocked = false;
1137 }
1139 } // namespace Widget
1140 } // namespace UI
1141 } // namespace Inkscape
1143 /*
1144 Local Variables:
1145 mode:c++
1146 c-file-style:"stroustrup"
1147 c-file-offsets:((innamespace . 0)(inline-open . 0))
1148 indent-tabs-mode:nil
1149 fill-column:99
1150 End:
1151 */
1152 // vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :