9cf5aa32b39606a9d866f567275f29f83ed6ed05
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 "dialogs/object-properties.h"
31 #include "xml/repr.h"
32 #include "document.h"
33 #include "widgets/widget-sizes.h"
34 #include "widgets/spinbutton-events.h"
35 #include "svg/svg-color.h"
36 #include "svg/css-ostringstream.h"
37 #include "helper/units.h"
38 #include "verbs.h"
39 #include <display/sp-canvas.h>
41 static gdouble const _sw_presets[] = { 32 , 16 , 10 , 8 , 6 , 4 , 3 , 2 , 1.5 , 1 , 0.75 , 0.5 , 0.25 , 0.1 };
42 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"};
44 static void
45 ss_selection_changed (Inkscape::Selection *, gpointer data)
46 {
47 Inkscape::UI::Widget::SelectedStyle *ss = (Inkscape::UI::Widget::SelectedStyle *) data;
48 ss->update();
49 }
51 static void
52 ss_selection_modified (Inkscape::Selection *selection, guint flags, gpointer data)
53 {
54 ss_selection_changed (selection, data);
55 }
57 static void
58 ss_subselection_changed (gpointer dragger, gpointer data)
59 {
60 ss_selection_changed (NULL, data);
61 }
63 namespace Inkscape {
64 namespace UI {
65 namespace Widget {
68 typedef struct {
69 SelectedStyle* parent;
70 int item;
71 } DropTracker;
73 /* Drag and Drop */
74 typedef enum {
75 APP_X_COLOR
76 } ui_drop_target_info;
78 static GtkTargetEntry ui_drop_target_entries [] = {
79 {"application/x-color", 0, APP_X_COLOR}
80 };
82 #define ENTRIES_SIZE(n) sizeof(n)/sizeof(n[0])
83 static guint nui_drop_target_entries = ENTRIES_SIZE(ui_drop_target_entries);
86 SelectedStyle::SelectedStyle(bool layout)
87 : _desktop (NULL),
89 _table(2, 6),
90 _fill_label (_("F:")),
91 _stroke_label (_("S:")),
92 _opacity_label (_("O:")),
93 _fill_place (),
94 _stroke_place (),
96 _fill_flag_place (),
97 _stroke_flag_place (),
99 _opacity_place (),
100 _opacity_adjustment (100, 0.0, 100, 1.0, 10.0),
101 _opacity_sb (0.02, 0),
103 _stroke (),
104 _stroke_width (""),
106 _opacity_blocked (false),
108 _popup_px(_sw_group),
109 _popup_pt(_sw_group),
110 _popup_mm(_sw_group),
112 _sw_unit(NULL),
114 _tooltips ()
116 {
117 _drop[0] = _drop[1] = 0;
118 _dropEnabled[0] = _dropEnabled[1] = false;
120 _fill_label.set_alignment(0.0, 0.5);
121 _fill_label.set_padding(0, 0);
122 _stroke_label.set_alignment(0.0, 0.5);
123 _stroke_label.set_padding(0, 0);
124 _opacity_label.set_alignment(0.0, 0.5);
125 _opacity_label.set_padding(0, 0);
127 _table.set_col_spacings (2);
128 _table.set_row_spacings (0);
130 for (int i = SS_FILL; i <= SS_STROKE; i++) {
132 _na[i].set_markup (_("N/A"));
133 sp_set_font_size_smaller (GTK_WIDGET(_na[i].gobj()));
134 _na[i].show_all();
135 __na[i] = (_("Nothing selected"));
137 _none[i].set_markup (_("None"));
138 sp_set_font_size_smaller (GTK_WIDGET(_none[i].gobj()));
139 _none[i].show_all();
140 __none[i] = (i == SS_FILL)? (_("No fill")) : (_("No stroke"));
142 _pattern[i].set_markup (_("Pattern"));
143 sp_set_font_size_smaller (GTK_WIDGET(_pattern[i].gobj()));
144 _pattern[i].show_all();
145 __pattern[i] = (i == SS_FILL)? (_("Pattern fill")) : (_("Pattern stroke"));
147 _lgradient[i].set_markup (_("L Gradient"));
148 sp_set_font_size_smaller (GTK_WIDGET(_lgradient[i].gobj()));
149 _lgradient[i].show_all();
150 __lgradient[i] = (i == SS_FILL)? (_("Linear gradient fill")) : (_("Linear gradient stroke"));
152 _rgradient[i].set_markup (_("R Gradient"));
153 sp_set_font_size_smaller (GTK_WIDGET(_rgradient[i].gobj()));
154 _rgradient[i].show_all();
155 __rgradient[i] = (i == SS_FILL)? (_("Radial gradient fill")) : (_("Radial gradient stroke"));
157 _many[i].set_markup (_("Different"));
158 sp_set_font_size_smaller (GTK_WIDGET(_many[i].gobj()));
159 _many[i].show_all();
160 __many[i] = (i == SS_FILL)? (_("Different fills")) : (_("Different strokes"));
162 _unset[i].set_markup (_("Unset"));
163 sp_set_font_size_smaller (GTK_WIDGET(_unset[i].gobj()));
164 _unset[i].show_all();
165 __unset[i] = (i == SS_FILL)? (_("Unset fill")) : (_("Unset stroke"));
167 _color_preview[i] = new Inkscape::UI::Widget::ColorPreview (0);
168 __color[i] = (i == SS_FILL)? (_("Flat color fill")) : (_("Flat color stroke"));
170 // TRANSLATOR COMMENT: A means "Averaged"
171 _averaged[i].set_markup (_("<b>a</b>"));
172 sp_set_font_size_smaller (GTK_WIDGET(_averaged[i].gobj()));
173 _averaged[i].show_all();
174 __averaged[i] = (i == SS_FILL)? (_("Fill is averaged over selected objects")) : (_("Stroke is averaged over selected objects"));
176 // TRANSLATOR COMMENT: M means "Multiple"
177 _multiple[i].set_markup (_("<b>m</b>"));
178 sp_set_font_size_smaller (GTK_WIDGET(_multiple[i].gobj()));
179 _multiple[i].show_all();
180 __multiple[i] = (i == SS_FILL)? (_("Multiple selected objects have the same fill")) : (_("Multiple selected objects have the same stroke"));
182 _popup_edit[i].add(*(new Gtk::Label((i == SS_FILL)? _("Edit fill...") : _("Edit stroke..."), 0.0, 0.5)));
183 _popup_edit[i].signal_activate().connect(sigc::mem_fun(*this,
184 (i == SS_FILL)? &SelectedStyle::on_fill_edit : &SelectedStyle::on_stroke_edit ));
186 _popup_lastused[i].add(*(new Gtk::Label(_("Last set color"), 0.0, 0.5)));
187 _popup_lastused[i].signal_activate().connect(sigc::mem_fun(*this,
188 (i == SS_FILL)? &SelectedStyle::on_fill_lastused : &SelectedStyle::on_stroke_lastused ));
190 _popup_lastselected[i].add(*(new Gtk::Label(_("Last selected color"), 0.0, 0.5)));
191 _popup_lastselected[i].signal_activate().connect(sigc::mem_fun(*this,
192 (i == SS_FILL)? &SelectedStyle::on_fill_lastselected : &SelectedStyle::on_stroke_lastselected ));
194 _popup_invert[i].add(*(new Gtk::Label(_("Invert"), 0.0, 0.5)));
195 _popup_invert[i].signal_activate().connect(sigc::mem_fun(*this,
196 (i == SS_FILL)? &SelectedStyle::on_fill_invert : &SelectedStyle::on_stroke_invert ));
198 _popup_white[i].add(*(new Gtk::Label(_("White"), 0.0, 0.5)));
199 _popup_white[i].signal_activate().connect(sigc::mem_fun(*this,
200 (i == SS_FILL)? &SelectedStyle::on_fill_white : &SelectedStyle::on_stroke_white ));
202 _popup_black[i].add(*(new Gtk::Label(_("Black"), 0.0, 0.5)));
203 _popup_black[i].signal_activate().connect(sigc::mem_fun(*this,
204 (i == SS_FILL)? &SelectedStyle::on_fill_black : &SelectedStyle::on_stroke_black ));
206 _popup_copy[i].add(*(new Gtk::Label(_("Copy color"), 0.0, 0.5)));
207 _popup_copy[i].signal_activate().connect(sigc::mem_fun(*this,
208 (i == SS_FILL)? &SelectedStyle::on_fill_copy : &SelectedStyle::on_stroke_copy ));
210 _popup_paste[i].add(*(new Gtk::Label(_("Paste color"), 0.0, 0.5)));
211 _popup_paste[i].signal_activate().connect(sigc::mem_fun(*this,
212 (i == SS_FILL)? &SelectedStyle::on_fill_paste : &SelectedStyle::on_stroke_paste ));
214 _popup_swap[i].add(*(new Gtk::Label(_("Swap fill and stroke"), 0.0, 0.5)));
215 _popup_swap[i].signal_activate().connect(sigc::mem_fun(*this,
216 &SelectedStyle::on_fillstroke_swap));
218 _popup_opaque[i].add(*(new Gtk::Label((i == SS_FILL)? _("Make fill opaque") : _("Make stroke opaque"), 0.0, 0.5)));
219 _popup_opaque[i].signal_activate().connect(sigc::mem_fun(*this,
220 (i == SS_FILL)? &SelectedStyle::on_fill_opaque : &SelectedStyle::on_stroke_opaque ));
222 //TRANSLATORS COMMENT: unset is a verb here
223 _popup_unset[i].add(*(new Gtk::Label((i == SS_FILL)? _("Unset fill") : _("Unset stroke"), 0.0, 0.5)));
224 _popup_unset[i].signal_activate().connect(sigc::mem_fun(*this,
225 (i == SS_FILL)? &SelectedStyle::on_fill_unset : &SelectedStyle::on_stroke_unset ));
227 _popup_remove[i].add(*(new Gtk::Label((i == SS_FILL)? _("Remove fill") : _("Remove stroke"), 0.0, 0.5)));
228 _popup_remove[i].signal_activate().connect(sigc::mem_fun(*this,
229 (i == SS_FILL)? &SelectedStyle::on_fill_remove : &SelectedStyle::on_stroke_remove ));
231 _popup[i].attach(_popup_edit[i], 0,1, 0,1);
232 _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 1,2);
233 _popup[i].attach(_popup_lastused[i], 0,1, 2,3);
234 _popup[i].attach(_popup_lastselected[i], 0,1, 3,4);
235 _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 4,5);
236 _popup[i].attach(_popup_invert[i], 0,1, 5,6);
237 _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 6,7);
238 _popup[i].attach(_popup_white[i], 0,1, 7,8);
239 _popup[i].attach(_popup_black[i], 0,1, 8,9);
240 _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 9,10);
241 _popup[i].attach(_popup_copy[i], 0,1, 10,11);
242 _popup_copy[i].set_sensitive(false);
243 _popup[i].attach(_popup_paste[i], 0,1, 11,12);
244 _popup[i].attach(_popup_swap[i], 0,1, 12,13);
245 _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 13,14);
246 _popup[i].attach(_popup_opaque[i], 0,1, 14,15);
247 _popup[i].attach(_popup_unset[i], 0,1, 15,16);
248 _popup[i].attach(_popup_remove[i], 0,1, 16,17);
249 _popup[i].show_all();
251 _mode[i] = SS_NA;
252 }
254 {
255 _popup_px.add(*(new Gtk::Label(_("px"), 0.0, 0.5)));
256 _popup_px.signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::on_popup_px));
257 _popup_sw.attach(_popup_px, 0,1, 0,1);
259 _popup_pt.add(*(new Gtk::Label(_("pt"), 0.0, 0.5)));
260 _popup_pt.signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::on_popup_pt));
261 _popup_sw.attach(_popup_pt, 0,1, 1,2);
263 _popup_mm.add(*(new Gtk::Label(_("mm"), 0.0, 0.5)));
264 _popup_mm.signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::on_popup_mm));
265 _popup_sw.attach(_popup_mm, 0,1, 2,3);
267 _popup_sw.attach(*(new Gtk::SeparatorMenuItem()), 0,1, 3,4);
269 for (guint i = 0; i < G_N_ELEMENTS(_sw_presets_str); ++i) {
270 Gtk::MenuItem *mi = Gtk::manage(new Gtk::MenuItem());
271 mi->add(*(new Gtk::Label(_sw_presets_str[i], 0.0, 0.5)));
272 mi->signal_activate().connect(sigc::bind<int>(sigc::mem_fun(*this, &SelectedStyle::on_popup_preset), i));
273 _popup_sw.attach(*mi, 0,1, 4+i, 5+i);
274 }
276 guint i = G_N_ELEMENTS(_sw_presets_str) + 5;
278 _popup_sw.attach(*(new Gtk::SeparatorMenuItem()), 0,1, i,i+1);
280 _popup_sw_remove.add(*(new Gtk::Label(_("Remove"), 0.0, 0.5)));
281 _popup_sw_remove.signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::on_stroke_remove));
282 _popup_sw.attach(_popup_sw_remove, 0,1, i+1,i+2);
284 _popup_sw.show_all();
285 }
287 _fill_place.signal_button_press_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_fill_click));
288 _stroke_place.signal_button_press_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_stroke_click));
289 _opacity_place.signal_button_press_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_opacity_click));
290 _stroke_width_place.signal_button_press_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_sw_click));
292 _opacity_sb.signal_populate_popup().connect(sigc::mem_fun(*this, &SelectedStyle::on_opacity_menu));
293 _opacity_sb.signal_value_changed().connect(sigc::mem_fun(*this, &SelectedStyle::on_opacity_changed));
295 _fill_place.add(_na[SS_FILL]);
296 _tooltips.set_tip(_fill_place, __na[SS_FILL]);
298 _stroke_place.add(_na[SS_STROKE]);
299 _tooltips.set_tip(_stroke_place, __na[SS_STROKE]);
301 _stroke.pack_start(_stroke_place);
302 _stroke_width_place.add(_stroke_width);
303 _stroke.pack_start(_stroke_width_place, Gtk::PACK_SHRINK);
305 _opacity_sb.set_adjustment(_opacity_adjustment);
306 sp_set_font_size_smaller (GTK_WIDGET(_opacity_sb.gobj()));
307 _opacity_sb.set_size_request (SELECTED_STYLE_SB_WIDTH, -1);
308 _opacity_sb.set_sensitive (false);
310 _table.attach(_fill_label, 0,1, 0,1, Gtk::SHRINK, Gtk::SHRINK);
311 _table.attach(_stroke_label, 0,1, 1,2, Gtk::SHRINK, Gtk::SHRINK);
313 _table.attach(_fill_flag_place, 1,2, 0,1, Gtk::SHRINK, Gtk::SHRINK);
314 _table.attach(_stroke_flag_place, 1,2, 1,2, Gtk::SHRINK, Gtk::SHRINK);
316 _table.attach(_fill_place, 2,3, 0,1);
317 _table.attach(_stroke, 2,3, 1,2);
319 _opacity_place.add(_opacity_label);
320 _table.attach(_opacity_place, 4,5, 0,2, Gtk::SHRINK, Gtk::SHRINK);
321 _table.attach(_opacity_sb, 5,6, 0,2, Gtk::SHRINK, Gtk::SHRINK);
323 pack_start(_table, true, true, 2);
325 set_size_request (SELECTED_STYLE_WIDTH, -1);
327 sp_set_font_size_smaller (GTK_WIDGET(_opacity_label.gobj()));
328 sp_set_font_size_smaller (GTK_WIDGET(_opacity_sb.gobj()));
329 sp_set_font_size_smaller (GTK_WIDGET(_fill_place.gobj()));
330 sp_set_font_size_smaller (GTK_WIDGET(_fill_flag_place.gobj()));
331 sp_set_font_size_smaller (GTK_WIDGET(_stroke_place.gobj()));
332 sp_set_font_size_smaller (GTK_WIDGET(_stroke_flag_place.gobj()));
333 sp_set_font_size_smaller (GTK_WIDGET(_stroke_width.gobj()));
334 sp_set_font_size_smaller (GTK_WIDGET(_fill_label.gobj()));
335 sp_set_font_size_smaller (GTK_WIDGET(_stroke_label.gobj()));
337 _drop[SS_FILL] = new DropTracker();
338 ((DropTracker*)_drop[SS_FILL])->parent = this;
339 ((DropTracker*)_drop[SS_FILL])->item = SS_FILL;
341 _drop[SS_STROKE] = new DropTracker();
342 ((DropTracker*)_drop[SS_STROKE])->parent = this;
343 ((DropTracker*)_drop[SS_STROKE])->item = SS_STROKE;
345 g_signal_connect(_stroke_place.gobj(),
346 "drag_data_received",
347 G_CALLBACK(dragDataReceived),
348 _drop[SS_STROKE]);
350 g_signal_connect(_fill_place.gobj(),
351 "drag_data_received",
352 G_CALLBACK(dragDataReceived),
353 _drop[SS_FILL]);
354 }
356 SelectedStyle::~SelectedStyle()
357 {
358 selection_changed_connection->disconnect();
359 delete selection_changed_connection;
360 selection_modified_connection->disconnect();
361 delete selection_modified_connection;
362 subselection_changed_connection->disconnect();
363 delete subselection_changed_connection;
365 for (int i = SS_FILL; i <= SS_STROKE; i++) {
366 delete _color_preview[i];
367 }
369 delete (DropTracker*)_drop[SS_FILL];
370 delete (DropTracker*)_drop[SS_STROKE];
371 }
373 void
374 SelectedStyle::setDesktop(SPDesktop *desktop)
375 {
376 _desktop = desktop;
377 gtk_object_set_data (GTK_OBJECT(_opacity_sb.gobj()), "dtw", _desktop->canvas);
379 Inkscape::Selection *selection = sp_desktop_selection (desktop);
381 selection_changed_connection = new sigc::connection (selection->connectChanged(
382 sigc::bind (
383 sigc::ptr_fun(&ss_selection_changed),
384 this )
385 ));
386 selection_modified_connection = new sigc::connection (selection->connectModified(
387 sigc::bind (
388 sigc::ptr_fun(&ss_selection_modified),
389 this )
390 ));
391 subselection_changed_connection = new sigc::connection (desktop->connectToolSubselectionChanged(
392 sigc::bind (
393 sigc::ptr_fun(&ss_subselection_changed),
394 this )
395 ));
397 //_sw_unit = (SPUnit *) sp_desktop_namedview(desktop)->doc_units;
398 }
400 void SelectedStyle::dragDataReceived( GtkWidget *widget,
401 GdkDragContext *drag_context,
402 gint x, gint y,
403 GtkSelectionData *data,
404 guint info,
405 guint event_time,
406 gpointer user_data )
407 {
408 DropTracker* tracker = (DropTracker*)user_data;
410 switch ( (int)tracker->item ) {
411 case SS_FILL:
412 case SS_STROKE:
413 {
414 if ( data->length == 8 ) {
415 gchar c[64];
416 // Careful about endian issues.
417 guint16* dataVals = (guint16*)data->data;
418 sp_svg_write_color( c, 64,
419 SP_RGBA32_U_COMPOSE(
420 0x0ff & (dataVals[0] >> 8),
421 0x0ff & (dataVals[1] >> 8),
422 0x0ff & (dataVals[2] >> 8),
423 0xff // can't have transparency in the color itself
424 //0x0ff & (data->data[3] >> 8),
425 ));
426 SPCSSAttr *css = sp_repr_css_attr_new();
427 sp_repr_css_set_property( css, (tracker->item == SS_FILL) ? "fill":"stroke", c );
428 sp_desktop_set_style( tracker->parent->_desktop, css );
429 sp_repr_css_attr_unref( css );
430 sp_document_done( sp_desktop_document(tracker->parent->_desktop) , SP_VERB_NONE,
431 _("Drop color"));
432 }
433 }
434 break;
435 }
436 }
438 void SelectedStyle::on_fill_remove() {
439 SPCSSAttr *css = sp_repr_css_attr_new ();
440 sp_repr_css_set_property (css, "fill", "none");
441 sp_desktop_set_style (_desktop, css, true, true);
442 sp_repr_css_attr_unref (css);
443 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
444 _("Remove fill"));
445 }
447 void SelectedStyle::on_stroke_remove() {
448 SPCSSAttr *css = sp_repr_css_attr_new ();
449 sp_repr_css_set_property (css, "stroke", "none");
450 sp_desktop_set_style (_desktop, css, true, true);
451 sp_repr_css_attr_unref (css);
452 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
453 _("Remove stroke"));
454 }
456 void SelectedStyle::on_fill_unset() {
457 SPCSSAttr *css = sp_repr_css_attr_new ();
458 sp_repr_css_unset_property (css, "fill");
459 sp_desktop_set_style (_desktop, css, true, true);
460 sp_repr_css_attr_unref (css);
461 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
462 _("Unset fill"));
463 }
465 void SelectedStyle::on_stroke_unset() {
466 SPCSSAttr *css = sp_repr_css_attr_new ();
467 sp_repr_css_unset_property (css, "stroke");
468 sp_desktop_set_style (_desktop, css, true, true);
469 sp_repr_css_attr_unref (css);
470 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
471 _("Unset stroke"));
472 }
474 void SelectedStyle::on_fill_opaque() {
475 SPCSSAttr *css = sp_repr_css_attr_new ();
476 sp_repr_css_set_property (css, "fill-opacity", "1");
477 sp_desktop_set_style (_desktop, css, true);
478 sp_repr_css_attr_unref (css);
479 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
480 _("Make fill opaque"));
481 }
483 void SelectedStyle::on_stroke_opaque() {
484 SPCSSAttr *css = sp_repr_css_attr_new ();
485 sp_repr_css_set_property (css, "stroke-opacity", "1");
486 sp_desktop_set_style (_desktop, css, true);
487 sp_repr_css_attr_unref (css);
488 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
489 _("Make fill opaque"));
490 }
492 void SelectedStyle::on_fill_lastused() {
493 SPCSSAttr *css = sp_repr_css_attr_new ();
494 guint32 color = sp_desktop_get_color(_desktop, true);
495 gchar c[64];
496 sp_svg_write_color (c, 64, color);
497 sp_repr_css_set_property (css, "fill", c);
498 sp_desktop_set_style (_desktop, css);
499 sp_repr_css_attr_unref (css);
500 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
501 _("Apply last set color to fill"));
502 }
504 void SelectedStyle::on_stroke_lastused() {
505 SPCSSAttr *css = sp_repr_css_attr_new ();
506 guint32 color = sp_desktop_get_color(_desktop, false);
507 gchar c[64];
508 sp_svg_write_color (c, 64, color);
509 sp_repr_css_set_property (css, "stroke", c);
510 sp_desktop_set_style (_desktop, css);
511 sp_repr_css_attr_unref (css);
512 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
513 _("Apply last set color to stroke"));
514 }
516 void SelectedStyle::on_fill_lastselected() {
517 SPCSSAttr *css = sp_repr_css_attr_new ();
518 gchar c[64];
519 sp_svg_write_color (c, 64, _lastselected[SS_FILL]);
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 selected color to fill"));
525 }
527 void SelectedStyle::on_stroke_lastselected() {
528 SPCSSAttr *css = sp_repr_css_attr_new ();
529 gchar c[64];
530 sp_svg_write_color (c, 64, _lastselected[SS_STROKE]);
531 sp_repr_css_set_property (css, "stroke", c);
532 sp_desktop_set_style (_desktop, css);
533 sp_repr_css_attr_unref (css);
534 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
535 _("Apply last selected color to stroke"));
536 }
538 void SelectedStyle::on_fill_invert() {
539 SPCSSAttr *css = sp_repr_css_attr_new ();
540 guint32 color = _thisselected[SS_FILL];
541 gchar c[64];
542 if (_mode[SS_FILL] != SS_COLOR) return;
543 sp_svg_write_color (c, 64,
544 SP_RGBA32_U_COMPOSE(
545 (255 - SP_RGBA32_R_U(color)),
546 (255 - SP_RGBA32_G_U(color)),
547 (255 - SP_RGBA32_B_U(color)),
548 SP_RGBA32_A_U(color)
549 )
550 );
551 sp_repr_css_set_property (css, "fill", c);
552 sp_desktop_set_style (_desktop, css);
553 sp_repr_css_attr_unref (css);
554 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
555 _("Invert fill"));
556 }
558 void SelectedStyle::on_stroke_invert() {
559 SPCSSAttr *css = sp_repr_css_attr_new ();
560 guint32 color = _thisselected[SS_STROKE];
561 gchar c[64];
562 if (_mode[SS_STROKE] != SS_COLOR) return;
563 sp_svg_write_color (c, 64,
564 SP_RGBA32_U_COMPOSE(
565 (255 - SP_RGBA32_R_U(color)),
566 (255 - SP_RGBA32_G_U(color)),
567 (255 - SP_RGBA32_B_U(color)),
568 SP_RGBA32_A_U(color)
569 )
570 );
571 sp_repr_css_set_property (css, "stroke", c);
572 sp_desktop_set_style (_desktop, css);
573 sp_repr_css_attr_unref (css);
574 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
575 _("Invert stroke"));
576 }
578 void SelectedStyle::on_fill_white() {
579 SPCSSAttr *css = sp_repr_css_attr_new ();
580 gchar c[64];
581 sp_svg_write_color (c, 64, 0xffffffff);
582 sp_repr_css_set_property (css, "fill", c);
583 sp_repr_css_set_property (css, "fill-opacity", "1");
584 sp_desktop_set_style (_desktop, css);
585 sp_repr_css_attr_unref (css);
586 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
587 _("White fill"));
588 }
590 void SelectedStyle::on_stroke_white() {
591 SPCSSAttr *css = sp_repr_css_attr_new ();
592 gchar c[64];
593 sp_svg_write_color (c, 64, 0xffffffff);
594 sp_repr_css_set_property (css, "stroke", c);
595 sp_repr_css_set_property (css, "stroke-opacity", "1");
596 sp_desktop_set_style (_desktop, css);
597 sp_repr_css_attr_unref (css);
598 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
599 _("White stroke"));
600 }
602 void SelectedStyle::on_fill_black() {
603 SPCSSAttr *css = sp_repr_css_attr_new ();
604 gchar c[64];
605 sp_svg_write_color (c, 64, 0x000000ff);
606 sp_repr_css_set_property (css, "fill", c);
607 sp_repr_css_set_property (css, "fill-opacity", "1.0");
608 sp_desktop_set_style (_desktop, css);
609 sp_repr_css_attr_unref (css);
610 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
611 _("Black fill"));
612 }
614 void SelectedStyle::on_stroke_black() {
615 SPCSSAttr *css = sp_repr_css_attr_new ();
616 gchar c[64];
617 sp_svg_write_color (c, 64, 0x000000ff);
618 sp_repr_css_set_property (css, "stroke", c);
619 sp_repr_css_set_property (css, "stroke-opacity", "1.0");
620 sp_desktop_set_style (_desktop, css);
621 sp_repr_css_attr_unref (css);
622 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
623 _("Black stroke"));
624 }
626 void SelectedStyle::on_fill_copy() {
627 if (_mode[SS_FILL] == SS_COLOR) {
628 gchar c[64];
629 sp_svg_write_color (c, 64, _thisselected[SS_FILL]);
630 Glib::ustring text;
631 text += c;
632 if (!text.empty()) {
633 Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
634 refClipboard->set_text(text);
635 }
636 }
637 }
639 void SelectedStyle::on_stroke_copy() {
640 if (_mode[SS_STROKE] == SS_COLOR) {
641 gchar c[64];
642 sp_svg_write_color (c, 64, _thisselected[SS_STROKE]);
643 Glib::ustring text;
644 text += c;
645 if (!text.empty()) {
646 Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
647 refClipboard->set_text(text);
648 }
649 }
650 }
652 void SelectedStyle::on_fill_paste() {
653 Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
654 Glib::ustring const text = refClipboard->wait_for_text();
656 if (!text.empty()) {
657 guint32 color = sp_svg_read_color(text.c_str(), 0x000000ff); // impossible value, as SVG color cannot have opacity
658 if (color == 0x000000ff) // failed to parse color string
659 return;
661 SPCSSAttr *css = sp_repr_css_attr_new ();
662 sp_repr_css_set_property (css, "fill", text.c_str());
663 sp_desktop_set_style (_desktop, css);
664 sp_repr_css_attr_unref (css);
665 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
666 _("Paste fill"));
667 }
668 }
670 void SelectedStyle::on_stroke_paste() {
671 Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
672 Glib::ustring const text = refClipboard->wait_for_text();
674 if (!text.empty()) {
675 guint32 color = sp_svg_read_color(text.c_str(), 0x000000ff); // impossible value, as SVG color cannot have opacity
676 if (color == 0x000000ff) // failed to parse color string
677 return;
679 SPCSSAttr *css = sp_repr_css_attr_new ();
680 sp_repr_css_set_property (css, "stroke", text.c_str());
681 sp_desktop_set_style (_desktop, css);
682 sp_repr_css_attr_unref (css);
683 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
684 _("Paste stroke"));
685 }
686 }
688 void SelectedStyle::on_fillstroke_swap() {
689 SPCSSAttr *css = sp_repr_css_attr_new ();
691 switch (_mode[SS_FILL]) {
692 case SS_NA:
693 case SS_MANY:
694 break;
695 case SS_NONE:
696 sp_repr_css_set_property (css, "stroke", "none");
697 break;
698 case SS_UNSET:
699 sp_repr_css_unset_property (css, "stroke");
700 break;
701 case SS_COLOR:
702 gchar c[64];
703 sp_svg_write_color (c, 64, _thisselected[SS_FILL]);
704 sp_repr_css_set_property (css, "stroke", c);
705 break;
706 case SS_LGRADIENT:
707 case SS_RGRADIENT:
708 case SS_PATTERN:
709 sp_repr_css_set_property (css, "stroke", _paintserver_id[SS_FILL].c_str());
710 break;
711 }
713 switch (_mode[SS_STROKE]) {
714 case SS_NA:
715 case SS_MANY:
716 break;
717 case SS_NONE:
718 sp_repr_css_set_property (css, "fill", "none");
719 break;
720 case SS_UNSET:
721 sp_repr_css_unset_property (css, "fill");
722 break;
723 case SS_COLOR:
724 gchar c[64];
725 sp_svg_write_color (c, 64, _thisselected[SS_STROKE]);
726 sp_repr_css_set_property (css, "fill", c);
727 break;
728 case SS_LGRADIENT:
729 case SS_RGRADIENT:
730 case SS_PATTERN:
731 sp_repr_css_set_property (css, "fill", _paintserver_id[SS_STROKE].c_str());
732 break;
733 }
735 sp_desktop_set_style (_desktop, css);
736 sp_repr_css_attr_unref (css);
737 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
738 _("Swap fill and stroke"));
739 }
741 void SelectedStyle::on_fill_edit() {
742 sp_object_properties_fill();
743 }
745 void SelectedStyle::on_stroke_edit() {
746 sp_object_properties_stroke();
747 }
749 bool
750 SelectedStyle::on_fill_click(GdkEventButton *event)
751 {
752 if (event->button == 1) { // click, open fill&stroke
753 sp_object_properties_fill();
754 } else if (event->button == 3) { // right-click, popup menu
755 _popup[SS_FILL].popup(event->button, event->time);
756 } else if (event->button == 2) { // middle click, toggle none/lastcolor
757 if (_mode[SS_FILL] == SS_NONE) {
758 on_fill_lastused();
759 } else {
760 on_fill_remove();
761 }
762 }
763 return true;
764 }
766 bool
767 SelectedStyle::on_stroke_click(GdkEventButton *event)
768 {
769 if (event->button == 1) { // click, open fill&stroke
770 sp_object_properties_stroke();
771 } else if (event->button == 3) { // right-click, popup menu
772 _popup[SS_STROKE].popup(event->button, event->time);
773 } else if (event->button == 2) { // middle click, toggle none/lastcolor
774 if (_mode[SS_STROKE] == SS_NONE) {
775 on_stroke_lastused();
776 } else {
777 on_stroke_remove();
778 }
779 }
780 return true;
781 }
783 bool
784 SelectedStyle::on_sw_click(GdkEventButton *event)
785 {
786 if (event->button == 1) { // click, open fill&stroke
787 sp_object_properties_stroke_style ();
788 } else if (event->button == 3) { // right-click, popup menu
789 _popup_sw.popup(event->button, event->time);
790 } else if (event->button == 2) { // middle click, toggle none/lastwidth?
791 //
792 }
793 return true;
794 }
796 bool
797 SelectedStyle::on_opacity_click(GdkEventButton *event)
798 {
799 if (event->button == 2) { // middle click
800 const char* opacity = _opacity_sb.get_value() < 50? "0.5" : (_opacity_sb.get_value() == 100? "0" : "1");
801 SPCSSAttr *css = sp_repr_css_attr_new ();
802 sp_repr_css_set_property (css, "opacity", opacity);
803 sp_desktop_set_style (_desktop, css);
804 sp_repr_css_attr_unref (css);
805 sp_document_done (sp_desktop_document (_desktop), SP_VERB_DIALOG_FILL_STROKE,
806 _("Change opacity"));
807 return true;
808 }
810 return false;
811 }
813 void SelectedStyle::on_popup_px() {
814 _sw_unit = (SPUnit *) &(sp_unit_get_by_id(SP_UNIT_PX));
815 update();
816 }
817 void SelectedStyle::on_popup_pt() {
818 _sw_unit = (SPUnit *) &(sp_unit_get_by_id(SP_UNIT_PT));
819 update();
820 }
821 void SelectedStyle::on_popup_mm() {
822 _sw_unit = (SPUnit *) &(sp_unit_get_by_id(SP_UNIT_MM));
823 update();
824 }
826 void SelectedStyle::on_popup_preset(int i) {
827 SPCSSAttr *css = sp_repr_css_attr_new ();
828 gdouble w;
829 if (_sw_unit) {
830 w = sp_units_get_pixels (_sw_presets[i], *_sw_unit);
831 } else {
832 w = _sw_presets[i];
833 }
834 Inkscape::CSSOStringStream os;
835 os << w;
836 sp_repr_css_set_property (css, "stroke-width", os.str().c_str());
837 // FIXME: update dash patterns!
838 sp_desktop_set_style (_desktop, css, true);
839 sp_repr_css_attr_unref (css);
840 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_SWATCHES,
841 _("Change stroke width"));
842 }
844 void
845 SelectedStyle::update()
846 {
847 if (_desktop == NULL)
848 return;
850 // create temporary style
851 SPStyle *query = sp_style_new ();
853 for (int i = SS_FILL; i <= SS_STROKE; i++) {
854 Gtk::EventBox *place = (i == SS_FILL)? &_fill_place : &_stroke_place;
855 Gtk::EventBox *flag_place = (i == SS_FILL)? &_fill_flag_place : &_stroke_flag_place;
857 place->remove();
858 flag_place->remove();
860 _tooltips.unset_tip(*place);
861 _tooltips.unset_tip(*flag_place);
863 _mode[i] = SS_NA;
864 _paintserver_id[i].clear();
866 _popup_copy[i].set_sensitive(false);
868 // query style from desktop. This returns a result flag and fills query with the style of subselection, if any, or selection
869 int result = sp_desktop_query_style (_desktop, query,
870 (i == SS_FILL)? QUERY_STYLE_PROPERTY_FILL : QUERY_STYLE_PROPERTY_STROKE);
871 switch (result) {
872 case QUERY_STYLE_NOTHING:
873 place->add(_na[i]);
874 _tooltips.set_tip(*place, __na[i]);
875 _mode[i] = SS_NA;
876 if ( _dropEnabled[i] ) {
877 gtk_drag_dest_unset( GTK_WIDGET((i==SS_FILL) ? _fill_place.gobj():_stroke_place.gobj()) );
878 _dropEnabled[i] = false;
879 }
880 break;
881 case QUERY_STYLE_SINGLE:
882 case QUERY_STYLE_MULTIPLE_AVERAGED:
883 case QUERY_STYLE_MULTIPLE_SAME:
884 if ( !_dropEnabled[i] ) {
885 gtk_drag_dest_set( GTK_WIDGET( (i==SS_FILL) ? _fill_place.gobj():_stroke_place.gobj()),
886 GTK_DEST_DEFAULT_ALL,
887 ui_drop_target_entries,
888 nui_drop_target_entries,
889 GdkDragAction(GDK_ACTION_COPY | GDK_ACTION_MOVE) );
890 _dropEnabled[i] = true;
891 }
892 SPIPaint *paint;
893 if (i == SS_FILL) {
894 paint = &(query->fill);
895 } else {
896 paint = &(query->stroke);
897 }
898 if (paint->set && paint->type == SP_PAINT_TYPE_COLOR) {
899 guint32 color = sp_color_get_rgba32_falpha (&(paint->value.color),
900 SP_SCALE24_TO_FLOAT ((i == SS_FILL)? query->fill_opacity.value : query->stroke_opacity.value));
901 _lastselected[i] = _thisselected[i];
902 _thisselected[i] = color | 0xff; // only color, opacity === 1
903 ((Inkscape::UI::Widget::ColorPreview*)_color_preview[i])->setRgba32 (color);
904 _color_preview[i]->show_all();
905 place->add(*_color_preview[i]);
906 gchar c_string[64];
907 g_snprintf (c_string, 64, "%06x/%.3g", color >> 8, SP_RGBA32_A_F(color));
908 _tooltips.set_tip(*place, __color[i] + ": " + c_string);
909 _mode[i] = SS_COLOR;
910 _popup_copy[i].set_sensitive(true);
912 } else if (paint->set && paint->type == SP_PAINT_TYPE_PAINTSERVER) {
913 SPPaintServer *server = (i == SS_FILL)? SP_STYLE_FILL_SERVER (query) : SP_STYLE_STROKE_SERVER (query);
914 if ( server ) {
915 Inkscape::XML::Node *srepr = SP_OBJECT_REPR(server);
916 _paintserver_id[i] += "url(#";
917 _paintserver_id[i] += srepr->attribute("id");
918 _paintserver_id[i] += ")";
920 if (SP_IS_LINEARGRADIENT (server)) {
921 place->add(_lgradient[i]);
922 _tooltips.set_tip(*place, __lgradient[i]);
923 _mode[i] = SS_LGRADIENT;
924 } else if (SP_IS_RADIALGRADIENT (server)) {
925 place->add(_rgradient[i]);
926 _tooltips.set_tip(*place, __rgradient[i]);
927 _mode[i] = SS_RGRADIENT;
928 } else if (SP_IS_PATTERN (server)) {
929 place->add(_pattern[i]);
930 _tooltips.set_tip(*place, __pattern[i]);
931 _mode[i] = SS_PATTERN;
932 }
933 } else {
934 g_warning ("file %s: line %d: Unknown paint server", __FILE__, __LINE__);
935 }
937 } else if (paint->set && paint->type == SP_PAINT_TYPE_NONE) {
938 place->add(_none[i]);
939 _tooltips.set_tip(*place, __none[i]);
940 _mode[i] = SS_NONE;
941 } else if (!paint->set) {
942 place->add(_unset[i]);
943 _tooltips.set_tip(*place, __unset[i]);
944 _mode[i] = SS_UNSET;
945 }
946 if (result == QUERY_STYLE_MULTIPLE_AVERAGED) {
947 flag_place->add(_averaged[i]);
948 _tooltips.set_tip(*flag_place, __averaged[i]);
949 } else if (result == QUERY_STYLE_MULTIPLE_SAME) {
950 flag_place->add(_multiple[i]);
951 _tooltips.set_tip(*flag_place, __multiple[i]);
952 }
953 break;
954 case QUERY_STYLE_MULTIPLE_DIFFERENT:
955 place->add(_many[i]);
956 _tooltips.set_tip(*place, __many[i]);
957 _mode[i] = SS_MANY;
958 break;
959 default:
960 break;
961 }
962 }
964 // Now query opacity
965 _tooltips.unset_tip(_opacity_place);
966 _tooltips.unset_tip(_opacity_sb);
968 int result = sp_desktop_query_style (_desktop, query, QUERY_STYLE_PROPERTY_MASTEROPACITY);
970 switch (result) {
971 case QUERY_STYLE_NOTHING:
972 _tooltips.set_tip(_opacity_place, _("Nothing selected"));
973 _tooltips.set_tip(_opacity_sb, _("Nothing selected"));
974 _opacity_sb.set_sensitive(false);
975 break;
976 case QUERY_STYLE_SINGLE:
977 case QUERY_STYLE_MULTIPLE_AVERAGED:
978 case QUERY_STYLE_MULTIPLE_SAME:
979 _tooltips.set_tip(_opacity_place, _("Master opacity, %"));
980 _tooltips.set_tip(_opacity_sb, _("Master opacity, %"));
981 if (_opacity_blocked) break;
982 _opacity_blocked = true;
983 _opacity_sb.set_sensitive(true);
984 _opacity_adjustment.set_value(SP_SCALE24_TO_FLOAT(query->opacity.value) * 100);
985 _opacity_blocked = false;
986 break;
987 }
989 // Now query stroke_width
990 int result_sw = sp_desktop_query_style (_desktop, query, QUERY_STYLE_PROPERTY_STROKEWIDTH);
991 switch (result_sw) {
992 case QUERY_STYLE_NOTHING:
993 _stroke_width.set_markup("");
994 break;
995 case QUERY_STYLE_SINGLE:
996 case QUERY_STYLE_MULTIPLE_AVERAGED:
997 case QUERY_STYLE_MULTIPLE_SAME:
998 {
999 double w;
1000 if (_sw_unit) {
1001 w = sp_pixels_get_units(query->stroke_width.computed, *_sw_unit);
1002 } else {
1003 w = query->stroke_width.computed;
1004 }
1005 {
1006 gchar *str = g_strdup_printf(" %.3g", w);
1007 _stroke_width.set_markup(str);
1008 g_free (str);
1009 }
1010 {
1011 gchar *str = g_strdup_printf(_("Stroke width: %.5g%s%s"),
1012 w,
1013 _sw_unit? sp_unit_get_abbreviation(_sw_unit) : "px",
1014 (result_sw == QUERY_STYLE_MULTIPLE_AVERAGED)?
1015 _(" (averaged)") : "");
1016 _tooltips.set_tip(_stroke_width_place, str);
1017 g_free (str);
1018 }
1019 break;
1020 }
1021 default:
1022 break;
1023 }
1025 g_free (query);
1026 }
1028 void SelectedStyle::opacity_0(void) {_opacity_sb.set_value(0);}
1029 void SelectedStyle::opacity_025(void) {_opacity_sb.set_value(25);}
1030 void SelectedStyle::opacity_05(void) {_opacity_sb.set_value(50);}
1031 void SelectedStyle::opacity_075(void) {_opacity_sb.set_value(75);}
1032 void SelectedStyle::opacity_1(void) {_opacity_sb.set_value(100);}
1034 void SelectedStyle::on_opacity_menu (Gtk::Menu *menu) {
1036 Glib::ListHandle<Gtk::Widget *> children = menu->get_children();
1037 for (Glib::ListHandle<Gtk::Widget *>::iterator iter = children.begin(); iter != children.end(); iter++) {
1038 menu->remove(*(*iter));
1039 }
1041 {
1042 Gtk::MenuItem *item = new Gtk::MenuItem;
1043 item->add(*(new Gtk::Label(_("0 (transparent)"), 0, 0)));
1044 item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_0 ));
1045 menu->add(*item);
1046 }
1047 {
1048 Gtk::MenuItem *item = new Gtk::MenuItem;
1049 item->add(*(new Gtk::Label("25%", 0, 0)));
1050 item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_025 ));
1051 menu->add(*item);
1052 }
1053 {
1054 Gtk::MenuItem *item = new Gtk::MenuItem;
1055 item->add(*(new Gtk::Label("50%", 0, 0)));
1056 item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_05 ));
1057 menu->add(*item);
1058 }
1059 {
1060 Gtk::MenuItem *item = new Gtk::MenuItem;
1061 item->add(*(new Gtk::Label("75%", 0, 0)));
1062 item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_075 ));
1063 menu->add(*item);
1064 }
1065 {
1066 Gtk::MenuItem *item = new Gtk::MenuItem;
1067 item->add(*(new Gtk::Label(_("100% (opaque)"), 0, 0)));
1068 item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_1 ));
1069 menu->add(*item);
1070 }
1072 menu->show_all();
1073 }
1075 void SelectedStyle::on_opacity_changed () {
1076 if (_opacity_blocked)
1077 return;
1078 _opacity_blocked = true;
1079 SPCSSAttr *css = sp_repr_css_attr_new ();
1080 Inkscape::CSSOStringStream os;
1081 os << CLAMP ((_opacity_adjustment.get_value() / 100), 0.0, 1.0);
1082 sp_repr_css_set_property (css, "opacity", os.str().c_str());
1083 // FIXME: workaround for GTK breakage: display interruptibility sometimes results in GTK
1084 // sending multiple value-changed events. As if when Inkscape interrupts redraw for main loop
1085 // iterations, GTK discovers that this callback hasn't finished yet, and for some weird reason
1086 // decides to add yet another value-changed event to the queue. Totally braindead if you ask
1087 // me. As a result, scrolling the spinbutton once results in runaway change until it hits 1.0
1088 // or 0.0. (And no, this is not a race with ::update, I checked that.)
1089 // Sigh. So we disable interruptibility while we're setting the new value.
1090 sp_canvas_force_full_redraw_after_interruptions(sp_desktop_canvas(_desktop), 0);
1091 sp_desktop_set_style (_desktop, css);
1092 sp_repr_css_attr_unref (css);
1093 sp_document_maybe_done (sp_desktop_document (_desktop), "fillstroke:opacity", SP_VERB_DIALOG_FILL_STROKE,
1094 _("Change opacity"));
1095 // resume interruptibility
1096 sp_canvas_end_forced_full_redraws(sp_desktop_canvas(_desktop));
1097 spinbutton_defocus(GTK_OBJECT(_opacity_sb.gobj()));
1098 _opacity_blocked = false;
1099 }
1101 } // namespace Widget
1102 } // namespace UI
1103 } // namespace Inkscape
1105 /*
1106 Local Variables:
1107 mode:c++
1108 c-file-style:"stroustrup"
1109 c-file-offsets:((innamespace . 0)(inline-open . 0))
1110 indent-tabs-mode:nil
1111 fill-column:99
1112 End:
1113 */
1114 // vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :