8710162fd7f70d5249816bcd959efececf0464b7
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 "event-context.h"
42 #include "message-context.h"
43 #include "verbs.h"
44 #include "color.h"
45 #include <display/sp-canvas.h>
47 static gdouble const _sw_presets[] = { 32 , 16 , 10 , 8 , 6 , 4 , 3 , 2 , 1.5 , 1 , 0.75 , 0.5 , 0.25 , 0.1 };
48 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"};
50 static void
51 ss_selection_changed (Inkscape::Selection *, gpointer data)
52 {
53 Inkscape::UI::Widget::SelectedStyle *ss = (Inkscape::UI::Widget::SelectedStyle *) data;
54 ss->update();
55 }
57 static void
58 ss_selection_modified (Inkscape::Selection *selection, guint flags, gpointer data)
59 {
60 ss_selection_changed (selection, data);
61 }
63 static void
64 ss_subselection_changed (gpointer dragger, gpointer data)
65 {
66 ss_selection_changed (NULL, data);
67 }
69 namespace Inkscape {
70 namespace UI {
71 namespace Widget {
74 typedef struct {
75 SelectedStyle* parent;
76 int item;
77 } DropTracker;
79 /* Drag and Drop */
80 typedef enum {
81 APP_X_COLOR
82 } ui_drop_target_info;
84 static GtkTargetEntry ui_drop_target_entries [] = {
85 {"application/x-color", 0, APP_X_COLOR}
86 };
88 #define ENTRIES_SIZE(n) sizeof(n)/sizeof(n[0])
89 static guint nui_drop_target_entries = ENTRIES_SIZE(ui_drop_target_entries);
92 SelectedStyle::SelectedStyle(bool layout)
93 : _desktop (NULL),
95 _table(2, 6),
96 _fill_label (_("Fill:")),
97 _stroke_label (_("Stroke:")),
98 _opacity_label (_("O:")),
100 _fill_place (SS_FILL),
101 _stroke_place (SS_STROKE),
103 _fill_flag_place (),
104 _stroke_flag_place (),
106 _opacity_place (),
107 _opacity_adjustment (100, 0.0, 100, 1.0, 10.0),
108 _opacity_sb (0.02, 0),
110 _stroke (),
111 _stroke_width (""),
113 _opacity_blocked (false),
115 _popup_px(_sw_group),
116 _popup_pt(_sw_group),
117 _popup_mm(_sw_group),
119 _sw_unit(NULL),
121 _tooltips ()
123 {
124 _drop[0] = _drop[1] = 0;
125 _dropEnabled[0] = _dropEnabled[1] = false;
127 _fill_label.set_alignment(0.0, 0.5);
128 _fill_label.set_padding(0, 0);
129 _stroke_label.set_alignment(0.0, 0.5);
130 _stroke_label.set_padding(0, 0);
131 _opacity_label.set_alignment(0.0, 0.5);
132 _opacity_label.set_padding(0, 0);
134 _table.set_col_spacings (2);
135 _table.set_row_spacings (0);
137 for (int i = SS_FILL; i <= SS_STROKE; i++) {
139 _na[i].set_markup (_("N/A"));
140 sp_set_font_size_smaller (GTK_WIDGET(_na[i].gobj()));
141 _na[i].show_all();
142 __na[i] = (_("Nothing selected"));
144 _none[i].set_markup (_("<i>None</i>"));
145 sp_set_font_size_smaller (GTK_WIDGET(_none[i].gobj()));
146 _none[i].show_all();
147 __none[i] = (i == SS_FILL)? (_("No fill")) : (_("No stroke"));
149 _pattern[i].set_markup (_("Pattern"));
150 sp_set_font_size_smaller (GTK_WIDGET(_pattern[i].gobj()));
151 _pattern[i].show_all();
152 __pattern[i] = (i == SS_FILL)? (_("Pattern fill")) : (_("Pattern stroke"));
154 _lgradient[i].set_markup (_("<b>L</b>"));
155 sp_set_font_size_smaller (GTK_WIDGET(_lgradient[i].gobj()));
156 _lgradient[i].show_all();
157 __lgradient[i] = (i == SS_FILL)? (_("Linear gradient fill")) : (_("Linear gradient stroke"));
159 _gradient_preview_l[i] = GTK_WIDGET(sp_gradient_image_new (NULL));
160 _gradient_box_l[i].pack_start(_lgradient[i]);
161 _gradient_box_l[i].pack_start(*(Glib::wrap(_gradient_preview_l[i])));
162 _gradient_box_l[i].show_all();
164 _rgradient[i].set_markup (_("<b>R</b>"));
165 sp_set_font_size_smaller (GTK_WIDGET(_rgradient[i].gobj()));
166 _rgradient[i].show_all();
167 __rgradient[i] = (i == SS_FILL)? (_("Radial gradient fill")) : (_("Radial gradient stroke"));
169 _gradient_preview_r[i] = GTK_WIDGET(sp_gradient_image_new (NULL));
170 _gradient_box_r[i].pack_start(_rgradient[i]);
171 _gradient_box_r[i].pack_start(*(Glib::wrap(_gradient_preview_r[i])));
172 _gradient_box_r[i].show_all();
174 _many[i].set_markup (_("Different"));
175 sp_set_font_size_smaller (GTK_WIDGET(_many[i].gobj()));
176 _many[i].show_all();
177 __many[i] = (i == SS_FILL)? (_("Different fills")) : (_("Different strokes"));
179 _unset[i].set_markup (_("<b>Unset</b>"));
180 sp_set_font_size_smaller (GTK_WIDGET(_unset[i].gobj()));
181 _unset[i].show_all();
182 __unset[i] = (i == SS_FILL)? (_("Unset fill")) : (_("Unset stroke"));
184 _color_preview[i] = new Inkscape::UI::Widget::ColorPreview (0);
185 __color[i] = (i == SS_FILL)? (_("Flat color fill")) : (_("Flat color stroke"));
187 // TRANSLATOR COMMENT: A means "Averaged"
188 _averaged[i].set_markup (_("<b>a</b>"));
189 sp_set_font_size_smaller (GTK_WIDGET(_averaged[i].gobj()));
190 _averaged[i].show_all();
191 __averaged[i] = (i == SS_FILL)? (_("Fill is averaged over selected objects")) : (_("Stroke is averaged over selected objects"));
193 // TRANSLATOR COMMENT: M means "Multiple"
194 _multiple[i].set_markup (_("<b>m</b>"));
195 sp_set_font_size_smaller (GTK_WIDGET(_multiple[i].gobj()));
196 _multiple[i].show_all();
197 __multiple[i] = (i == SS_FILL)? (_("Multiple selected objects have the same fill")) : (_("Multiple selected objects have the same stroke"));
199 _popup_edit[i].add(*(new Gtk::Label((i == SS_FILL)? _("Edit fill...") : _("Edit stroke..."), 0.0, 0.5)));
200 _popup_edit[i].signal_activate().connect(sigc::mem_fun(*this,
201 (i == SS_FILL)? &SelectedStyle::on_fill_edit : &SelectedStyle::on_stroke_edit ));
203 _popup_lastused[i].add(*(new Gtk::Label(_("Last set color"), 0.0, 0.5)));
204 _popup_lastused[i].signal_activate().connect(sigc::mem_fun(*this,
205 (i == SS_FILL)? &SelectedStyle::on_fill_lastused : &SelectedStyle::on_stroke_lastused ));
207 _popup_lastselected[i].add(*(new Gtk::Label(_("Last selected color"), 0.0, 0.5)));
208 _popup_lastselected[i].signal_activate().connect(sigc::mem_fun(*this,
209 (i == SS_FILL)? &SelectedStyle::on_fill_lastselected : &SelectedStyle::on_stroke_lastselected ));
211 _popup_invert[i].add(*(new Gtk::Label(_("Invert"), 0.0, 0.5)));
212 _popup_invert[i].signal_activate().connect(sigc::mem_fun(*this,
213 (i == SS_FILL)? &SelectedStyle::on_fill_invert : &SelectedStyle::on_stroke_invert ));
215 _popup_white[i].add(*(new Gtk::Label(_("White"), 0.0, 0.5)));
216 _popup_white[i].signal_activate().connect(sigc::mem_fun(*this,
217 (i == SS_FILL)? &SelectedStyle::on_fill_white : &SelectedStyle::on_stroke_white ));
219 _popup_black[i].add(*(new Gtk::Label(_("Black"), 0.0, 0.5)));
220 _popup_black[i].signal_activate().connect(sigc::mem_fun(*this,
221 (i == SS_FILL)? &SelectedStyle::on_fill_black : &SelectedStyle::on_stroke_black ));
223 _popup_copy[i].add(*(new Gtk::Label(_("Copy color"), 0.0, 0.5)));
224 _popup_copy[i].signal_activate().connect(sigc::mem_fun(*this,
225 (i == SS_FILL)? &SelectedStyle::on_fill_copy : &SelectedStyle::on_stroke_copy ));
227 _popup_paste[i].add(*(new Gtk::Label(_("Paste color"), 0.0, 0.5)));
228 _popup_paste[i].signal_activate().connect(sigc::mem_fun(*this,
229 (i == SS_FILL)? &SelectedStyle::on_fill_paste : &SelectedStyle::on_stroke_paste ));
231 _popup_swap[i].add(*(new Gtk::Label(_("Swap fill and stroke"), 0.0, 0.5)));
232 _popup_swap[i].signal_activate().connect(sigc::mem_fun(*this,
233 &SelectedStyle::on_fillstroke_swap));
235 _popup_opaque[i].add(*(new Gtk::Label((i == SS_FILL)? _("Make fill opaque") : _("Make stroke opaque"), 0.0, 0.5)));
236 _popup_opaque[i].signal_activate().connect(sigc::mem_fun(*this,
237 (i == SS_FILL)? &SelectedStyle::on_fill_opaque : &SelectedStyle::on_stroke_opaque ));
239 //TRANSLATORS COMMENT: unset is a verb here
240 _popup_unset[i].add(*(new Gtk::Label((i == SS_FILL)? _("Unset fill") : _("Unset stroke"), 0.0, 0.5)));
241 _popup_unset[i].signal_activate().connect(sigc::mem_fun(*this,
242 (i == SS_FILL)? &SelectedStyle::on_fill_unset : &SelectedStyle::on_stroke_unset ));
244 _popup_remove[i].add(*(new Gtk::Label((i == SS_FILL)? _("Remove fill") : _("Remove stroke"), 0.0, 0.5)));
245 _popup_remove[i].signal_activate().connect(sigc::mem_fun(*this,
246 (i == SS_FILL)? &SelectedStyle::on_fill_remove : &SelectedStyle::on_stroke_remove ));
248 _popup[i].attach(_popup_edit[i], 0,1, 0,1);
249 _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 1,2);
250 _popup[i].attach(_popup_lastused[i], 0,1, 2,3);
251 _popup[i].attach(_popup_lastselected[i], 0,1, 3,4);
252 _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 4,5);
253 _popup[i].attach(_popup_invert[i], 0,1, 5,6);
254 _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 6,7);
255 _popup[i].attach(_popup_white[i], 0,1, 7,8);
256 _popup[i].attach(_popup_black[i], 0,1, 8,9);
257 _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 9,10);
258 _popup[i].attach(_popup_copy[i], 0,1, 10,11);
259 _popup_copy[i].set_sensitive(false);
260 _popup[i].attach(_popup_paste[i], 0,1, 11,12);
261 _popup[i].attach(_popup_swap[i], 0,1, 12,13);
262 _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 13,14);
263 _popup[i].attach(_popup_opaque[i], 0,1, 14,15);
264 _popup[i].attach(_popup_unset[i], 0,1, 15,16);
265 _popup[i].attach(_popup_remove[i], 0,1, 16,17);
266 _popup[i].show_all();
268 _mode[i] = SS_NA;
269 }
271 {
272 _popup_px.add(*(new Gtk::Label(_("px"), 0.0, 0.5)));
273 _popup_px.signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::on_popup_px));
274 _popup_sw.attach(_popup_px, 0,1, 0,1);
276 _popup_pt.add(*(new Gtk::Label(_("pt"), 0.0, 0.5)));
277 _popup_pt.signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::on_popup_pt));
278 _popup_sw.attach(_popup_pt, 0,1, 1,2);
280 _popup_mm.add(*(new Gtk::Label(_("mm"), 0.0, 0.5)));
281 _popup_mm.signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::on_popup_mm));
282 _popup_sw.attach(_popup_mm, 0,1, 2,3);
284 _popup_sw.attach(*(new Gtk::SeparatorMenuItem()), 0,1, 3,4);
286 for (guint i = 0; i < G_N_ELEMENTS(_sw_presets_str); ++i) {
287 Gtk::MenuItem *mi = Gtk::manage(new Gtk::MenuItem());
288 mi->add(*(new Gtk::Label(_sw_presets_str[i], 0.0, 0.5)));
289 mi->signal_activate().connect(sigc::bind<int>(sigc::mem_fun(*this, &SelectedStyle::on_popup_preset), i));
290 _popup_sw.attach(*mi, 0,1, 4+i, 5+i);
291 }
293 guint i = G_N_ELEMENTS(_sw_presets_str) + 5;
295 _popup_sw.attach(*(new Gtk::SeparatorMenuItem()), 0,1, i,i+1);
297 _popup_sw_remove.add(*(new Gtk::Label(_("Remove"), 0.0, 0.5)));
298 _popup_sw_remove.signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::on_stroke_remove));
299 _popup_sw.attach(_popup_sw_remove, 0,1, i+1,i+2);
301 _popup_sw.show_all();
302 }
304 _fill_place.signal_button_release_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_fill_click));
305 _stroke_place.signal_button_release_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_stroke_click));
306 _opacity_place.signal_button_press_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_opacity_click));
307 _stroke_width_place.signal_button_press_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_sw_click));
309 _opacity_sb.signal_populate_popup().connect(sigc::mem_fun(*this, &SelectedStyle::on_opacity_menu));
310 _opacity_sb.signal_value_changed().connect(sigc::mem_fun(*this, &SelectedStyle::on_opacity_changed));
312 _fill_place.add(_na[SS_FILL]);
313 _tooltips.set_tip(_fill_place, __na[SS_FILL]);
315 _stroke_place.add(_na[SS_STROKE]);
316 _tooltips.set_tip(_stroke_place, __na[SS_STROKE]);
318 _stroke.pack_start(_stroke_place);
319 _stroke_width_place.add(_stroke_width);
320 _stroke.pack_start(_stroke_width_place, Gtk::PACK_SHRINK);
322 _opacity_sb.set_adjustment(_opacity_adjustment);
323 sp_set_font_size_smaller (GTK_WIDGET(_opacity_sb.gobj()));
324 _opacity_sb.set_size_request (SELECTED_STYLE_SB_WIDTH, -1);
325 _opacity_sb.set_sensitive (false);
327 _table.attach(_fill_label, 0,1, 0,1, Gtk::FILL, Gtk::SHRINK);
328 _table.attach(_stroke_label, 0,1, 1,2, Gtk::FILL, Gtk::SHRINK);
330 _table.attach(_fill_flag_place, 1,2, 0,1, Gtk::SHRINK, Gtk::SHRINK);
331 _table.attach(_stroke_flag_place, 1,2, 1,2, Gtk::SHRINK, Gtk::SHRINK);
333 _table.attach(_fill_place, 2,3, 0,1);
334 _table.attach(_stroke, 2,3, 1,2);
336 _opacity_place.add(_opacity_label);
337 _table.attach(_opacity_place, 4,5, 0,2, Gtk::SHRINK, Gtk::SHRINK);
338 _table.attach(_opacity_sb, 5,6, 0,2, Gtk::SHRINK, Gtk::SHRINK);
340 pack_start(_table, true, true, 2);
342 set_size_request (SELECTED_STYLE_WIDTH, -1);
344 sp_set_font_size_smaller (GTK_WIDGET(_opacity_label.gobj()));
345 sp_set_font_size_smaller (GTK_WIDGET(_opacity_sb.gobj()));
346 sp_set_font_size_smaller (GTK_WIDGET(_fill_place.gobj()));
347 sp_set_font_size_smaller (GTK_WIDGET(_fill_flag_place.gobj()));
348 sp_set_font_size_smaller (GTK_WIDGET(_stroke_place.gobj()));
349 sp_set_font_size_smaller (GTK_WIDGET(_stroke_flag_place.gobj()));
350 sp_set_font_size_smaller (GTK_WIDGET(_stroke_width.gobj()));
351 sp_set_font_size_smaller (GTK_WIDGET(_fill_label.gobj()));
352 sp_set_font_size_smaller (GTK_WIDGET(_stroke_label.gobj()));
354 _drop[SS_FILL] = new DropTracker();
355 ((DropTracker*)_drop[SS_FILL])->parent = this;
356 ((DropTracker*)_drop[SS_FILL])->item = SS_FILL;
358 _drop[SS_STROKE] = new DropTracker();
359 ((DropTracker*)_drop[SS_STROKE])->parent = this;
360 ((DropTracker*)_drop[SS_STROKE])->item = SS_STROKE;
362 g_signal_connect(_stroke_place.gobj(),
363 "drag_data_received",
364 G_CALLBACK(dragDataReceived),
365 _drop[SS_STROKE]);
367 g_signal_connect(_fill_place.gobj(),
368 "drag_data_received",
369 G_CALLBACK(dragDataReceived),
370 _drop[SS_FILL]);
372 _fill_place.parent = this;
373 _stroke_place.parent = this;
374 }
376 SelectedStyle::~SelectedStyle()
377 {
378 selection_changed_connection->disconnect();
379 delete selection_changed_connection;
380 selection_modified_connection->disconnect();
381 delete selection_modified_connection;
382 subselection_changed_connection->disconnect();
383 delete subselection_changed_connection;
385 for (int i = SS_FILL; i <= SS_STROKE; i++) {
386 delete _color_preview[i];
387 // FIXME: do we need this? the destroy methods are not exported
388 //sp_gradient_image_destroy(GTK_OBJECT(_gradient_preview_l[i]));
389 //sp_gradient_image_destroy(GTK_OBJECT(_gradient_preview_r[i]));
390 }
392 delete (DropTracker*)_drop[SS_FILL];
393 delete (DropTracker*)_drop[SS_STROKE];
394 }
396 void
397 SelectedStyle::setDesktop(SPDesktop *desktop)
398 {
399 _desktop = desktop;
400 gtk_object_set_data (GTK_OBJECT(_opacity_sb.gobj()), "dtw", _desktop->canvas);
402 Inkscape::Selection *selection = sp_desktop_selection (desktop);
404 selection_changed_connection = new sigc::connection (selection->connectChanged(
405 sigc::bind (
406 sigc::ptr_fun(&ss_selection_changed),
407 this )
408 ));
409 selection_modified_connection = new sigc::connection (selection->connectModified(
410 sigc::bind (
411 sigc::ptr_fun(&ss_selection_modified),
412 this )
413 ));
414 subselection_changed_connection = new sigc::connection (desktop->connectToolSubselectionChanged(
415 sigc::bind (
416 sigc::ptr_fun(&ss_subselection_changed),
417 this )
418 ));
420 //_sw_unit = (SPUnit *) sp_desktop_namedview(desktop)->doc_units;
421 }
423 void SelectedStyle::dragDataReceived( GtkWidget *widget,
424 GdkDragContext *drag_context,
425 gint x, gint y,
426 GtkSelectionData *data,
427 guint info,
428 guint event_time,
429 gpointer user_data )
430 {
431 DropTracker* tracker = (DropTracker*)user_data;
433 switch ( (int)tracker->item ) {
434 case SS_FILL:
435 case SS_STROKE:
436 {
437 if ( data->length == 8 ) {
438 gchar c[64];
439 // Careful about endian issues.
440 guint16* dataVals = (guint16*)data->data;
441 sp_svg_write_color( c, sizeof(c),
442 SP_RGBA32_U_COMPOSE(
443 0x0ff & (dataVals[0] >> 8),
444 0x0ff & (dataVals[1] >> 8),
445 0x0ff & (dataVals[2] >> 8),
446 0xff // can't have transparency in the color itself
447 //0x0ff & (data->data[3] >> 8),
448 ));
449 SPCSSAttr *css = sp_repr_css_attr_new();
450 sp_repr_css_set_property( css, (tracker->item == SS_FILL) ? "fill":"stroke", c );
451 sp_desktop_set_style( tracker->parent->_desktop, css );
452 sp_repr_css_attr_unref( css );
453 sp_document_done( sp_desktop_document(tracker->parent->_desktop) , SP_VERB_NONE,
454 _("Drop color"));
455 }
456 }
457 break;
458 }
459 }
461 void SelectedStyle::on_fill_remove() {
462 SPCSSAttr *css = sp_repr_css_attr_new ();
463 sp_repr_css_set_property (css, "fill", "none");
464 sp_desktop_set_style (_desktop, css, true, true);
465 sp_repr_css_attr_unref (css);
466 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
467 _("Remove fill"));
468 }
470 void SelectedStyle::on_stroke_remove() {
471 SPCSSAttr *css = sp_repr_css_attr_new ();
472 sp_repr_css_set_property (css, "stroke", "none");
473 sp_desktop_set_style (_desktop, css, true, true);
474 sp_repr_css_attr_unref (css);
475 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
476 _("Remove stroke"));
477 }
479 void SelectedStyle::on_fill_unset() {
480 SPCSSAttr *css = sp_repr_css_attr_new ();
481 sp_repr_css_unset_property (css, "fill");
482 sp_desktop_set_style (_desktop, css, true, true);
483 sp_repr_css_attr_unref (css);
484 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
485 _("Unset fill"));
486 }
488 void SelectedStyle::on_stroke_unset() {
489 SPCSSAttr *css = sp_repr_css_attr_new ();
490 sp_repr_css_unset_property (css, "stroke");
491 sp_repr_css_unset_property (css, "stroke-opacity");
492 sp_repr_css_unset_property (css, "stroke-width");
493 sp_repr_css_unset_property (css, "stroke-miterlimit");
494 sp_repr_css_unset_property (css, "stroke-linejoin");
495 sp_repr_css_unset_property (css, "stroke-linecap");
496 sp_repr_css_unset_property (css, "stroke-dashoffset");
497 sp_repr_css_unset_property (css, "stroke-dasharray");
498 sp_desktop_set_style (_desktop, css, true, true);
499 sp_repr_css_attr_unref (css);
500 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
501 _("Unset stroke"));
502 }
504 void SelectedStyle::on_fill_opaque() {
505 SPCSSAttr *css = sp_repr_css_attr_new ();
506 sp_repr_css_set_property (css, "fill-opacity", "1");
507 sp_desktop_set_style (_desktop, css, true);
508 sp_repr_css_attr_unref (css);
509 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
510 _("Make fill opaque"));
511 }
513 void SelectedStyle::on_stroke_opaque() {
514 SPCSSAttr *css = sp_repr_css_attr_new ();
515 sp_repr_css_set_property (css, "stroke-opacity", "1");
516 sp_desktop_set_style (_desktop, css, true);
517 sp_repr_css_attr_unref (css);
518 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
519 _("Make fill opaque"));
520 }
522 void SelectedStyle::on_fill_lastused() {
523 SPCSSAttr *css = sp_repr_css_attr_new ();
524 guint32 color = sp_desktop_get_color(_desktop, true);
525 gchar c[64];
526 sp_svg_write_color (c, sizeof(c), color);
527 sp_repr_css_set_property (css, "fill", c);
528 sp_desktop_set_style (_desktop, css);
529 sp_repr_css_attr_unref (css);
530 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
531 _("Apply last set color to fill"));
532 }
534 void SelectedStyle::on_stroke_lastused() {
535 SPCSSAttr *css = sp_repr_css_attr_new ();
536 guint32 color = sp_desktop_get_color(_desktop, false);
537 gchar c[64];
538 sp_svg_write_color (c, sizeof(c), color);
539 sp_repr_css_set_property (css, "stroke", c);
540 sp_desktop_set_style (_desktop, css);
541 sp_repr_css_attr_unref (css);
542 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
543 _("Apply last set color to stroke"));
544 }
546 void SelectedStyle::on_fill_lastselected() {
547 SPCSSAttr *css = sp_repr_css_attr_new ();
548 gchar c[64];
549 sp_svg_write_color (c, sizeof(c), _lastselected[SS_FILL]);
550 sp_repr_css_set_property (css, "fill", c);
551 sp_desktop_set_style (_desktop, css);
552 sp_repr_css_attr_unref (css);
553 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
554 _("Apply last selected color to fill"));
555 }
557 void SelectedStyle::on_stroke_lastselected() {
558 SPCSSAttr *css = sp_repr_css_attr_new ();
559 gchar c[64];
560 sp_svg_write_color (c, sizeof(c), _lastselected[SS_STROKE]);
561 sp_repr_css_set_property (css, "stroke", c);
562 sp_desktop_set_style (_desktop, css);
563 sp_repr_css_attr_unref (css);
564 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
565 _("Apply last selected color to stroke"));
566 }
568 void SelectedStyle::on_fill_invert() {
569 SPCSSAttr *css = sp_repr_css_attr_new ();
570 guint32 color = _thisselected[SS_FILL];
571 gchar c[64];
572 if (_mode[SS_FILL] != SS_COLOR) return;
573 sp_svg_write_color (c, sizeof(c),
574 SP_RGBA32_U_COMPOSE(
575 (255 - SP_RGBA32_R_U(color)),
576 (255 - SP_RGBA32_G_U(color)),
577 (255 - SP_RGBA32_B_U(color)),
578 SP_RGBA32_A_U(color)
579 )
580 );
581 sp_repr_css_set_property (css, "fill", c);
582 sp_desktop_set_style (_desktop, css);
583 sp_repr_css_attr_unref (css);
584 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
585 _("Invert fill"));
586 }
588 void SelectedStyle::on_stroke_invert() {
589 SPCSSAttr *css = sp_repr_css_attr_new ();
590 guint32 color = _thisselected[SS_STROKE];
591 gchar c[64];
592 if (_mode[SS_STROKE] != SS_COLOR) return;
593 sp_svg_write_color (c, sizeof(c),
594 SP_RGBA32_U_COMPOSE(
595 (255 - SP_RGBA32_R_U(color)),
596 (255 - SP_RGBA32_G_U(color)),
597 (255 - SP_RGBA32_B_U(color)),
598 SP_RGBA32_A_U(color)
599 )
600 );
601 sp_repr_css_set_property (css, "stroke", c);
602 sp_desktop_set_style (_desktop, css);
603 sp_repr_css_attr_unref (css);
604 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
605 _("Invert stroke"));
606 }
608 void SelectedStyle::on_fill_white() {
609 SPCSSAttr *css = sp_repr_css_attr_new ();
610 gchar c[64];
611 sp_svg_write_color (c, sizeof(c), 0xffffffff);
612 sp_repr_css_set_property (css, "fill", c);
613 sp_repr_css_set_property (css, "fill-opacity", "1");
614 sp_desktop_set_style (_desktop, css);
615 sp_repr_css_attr_unref (css);
616 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
617 _("White fill"));
618 }
620 void SelectedStyle::on_stroke_white() {
621 SPCSSAttr *css = sp_repr_css_attr_new ();
622 gchar c[64];
623 sp_svg_write_color (c, sizeof(c), 0xffffffff);
624 sp_repr_css_set_property (css, "stroke", c);
625 sp_repr_css_set_property (css, "stroke-opacity", "1");
626 sp_desktop_set_style (_desktop, css);
627 sp_repr_css_attr_unref (css);
628 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
629 _("White stroke"));
630 }
632 void SelectedStyle::on_fill_black() {
633 SPCSSAttr *css = sp_repr_css_attr_new ();
634 gchar c[64];
635 sp_svg_write_color (c, sizeof(c), 0x000000ff);
636 sp_repr_css_set_property (css, "fill", c);
637 sp_repr_css_set_property (css, "fill-opacity", "1.0");
638 sp_desktop_set_style (_desktop, css);
639 sp_repr_css_attr_unref (css);
640 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
641 _("Black fill"));
642 }
644 void SelectedStyle::on_stroke_black() {
645 SPCSSAttr *css = sp_repr_css_attr_new ();
646 gchar c[64];
647 sp_svg_write_color (c, sizeof(c), 0x000000ff);
648 sp_repr_css_set_property (css, "stroke", c);
649 sp_repr_css_set_property (css, "stroke-opacity", "1.0");
650 sp_desktop_set_style (_desktop, css);
651 sp_repr_css_attr_unref (css);
652 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
653 _("Black stroke"));
654 }
656 void SelectedStyle::on_fill_copy() {
657 if (_mode[SS_FILL] == SS_COLOR) {
658 gchar c[64];
659 sp_svg_write_color (c, sizeof(c), _thisselected[SS_FILL]);
660 Glib::ustring text;
661 text += c;
662 if (!text.empty()) {
663 Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
664 refClipboard->set_text(text);
665 }
666 }
667 }
669 void SelectedStyle::on_stroke_copy() {
670 if (_mode[SS_STROKE] == SS_COLOR) {
671 gchar c[64];
672 sp_svg_write_color (c, sizeof(c), _thisselected[SS_STROKE]);
673 Glib::ustring text;
674 text += c;
675 if (!text.empty()) {
676 Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
677 refClipboard->set_text(text);
678 }
679 }
680 }
682 void SelectedStyle::on_fill_paste() {
683 Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
684 Glib::ustring const text = refClipboard->wait_for_text();
686 if (!text.empty()) {
687 guint32 color = sp_svg_read_color(text.c_str(), 0x000000ff); // impossible value, as SVG color cannot have opacity
688 if (color == 0x000000ff) // failed to parse color string
689 return;
691 SPCSSAttr *css = sp_repr_css_attr_new ();
692 sp_repr_css_set_property (css, "fill", text.c_str());
693 sp_desktop_set_style (_desktop, css);
694 sp_repr_css_attr_unref (css);
695 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
696 _("Paste fill"));
697 }
698 }
700 void SelectedStyle::on_stroke_paste() {
701 Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
702 Glib::ustring const text = refClipboard->wait_for_text();
704 if (!text.empty()) {
705 guint32 color = sp_svg_read_color(text.c_str(), 0x000000ff); // impossible value, as SVG color cannot have opacity
706 if (color == 0x000000ff) // failed to parse color string
707 return;
709 SPCSSAttr *css = sp_repr_css_attr_new ();
710 sp_repr_css_set_property (css, "stroke", text.c_str());
711 sp_desktop_set_style (_desktop, css);
712 sp_repr_css_attr_unref (css);
713 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
714 _("Paste stroke"));
715 }
716 }
718 void SelectedStyle::on_fillstroke_swap() {
719 SPCSSAttr *css = sp_repr_css_attr_new ();
721 switch (_mode[SS_FILL]) {
722 case SS_NA:
723 case SS_MANY:
724 break;
725 case SS_NONE:
726 sp_repr_css_set_property (css, "stroke", "none");
727 break;
728 case SS_UNSET:
729 sp_repr_css_unset_property (css, "stroke");
730 break;
731 case SS_COLOR:
732 gchar c[64];
733 sp_svg_write_color (c, sizeof(c), _thisselected[SS_FILL]);
734 sp_repr_css_set_property (css, "stroke", c);
735 break;
736 case SS_LGRADIENT:
737 case SS_RGRADIENT:
738 case SS_PATTERN:
739 sp_repr_css_set_property (css, "stroke", _paintserver_id[SS_FILL].c_str());
740 break;
741 }
743 switch (_mode[SS_STROKE]) {
744 case SS_NA:
745 case SS_MANY:
746 break;
747 case SS_NONE:
748 sp_repr_css_set_property (css, "fill", "none");
749 break;
750 case SS_UNSET:
751 sp_repr_css_unset_property (css, "fill");
752 break;
753 case SS_COLOR:
754 gchar c[64];
755 sp_svg_write_color (c, sizeof(c), _thisselected[SS_STROKE]);
756 sp_repr_css_set_property (css, "fill", c);
757 break;
758 case SS_LGRADIENT:
759 case SS_RGRADIENT:
760 case SS_PATTERN:
761 sp_repr_css_set_property (css, "fill", _paintserver_id[SS_STROKE].c_str());
762 break;
763 }
765 sp_desktop_set_style (_desktop, css);
766 sp_repr_css_attr_unref (css);
767 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
768 _("Swap fill and stroke"));
769 }
771 void SelectedStyle::on_fill_edit() {
772 if (Dialog::FillAndStroke *dialog = dynamic_cast<Dialog::FillAndStroke *>(
773 _desktop->_dlg_mgr->getDialog("FillAndStroke")))
774 dialog->showPageFill();
775 }
777 void SelectedStyle::on_stroke_edit() {
778 if (Dialog::FillAndStroke *dialog = dynamic_cast<Dialog::FillAndStroke *>(
779 _desktop->_dlg_mgr->getDialog("FillAndStroke")))
780 dialog->showPageStrokePaint();
781 }
783 bool
784 SelectedStyle::on_fill_click(GdkEventButton *event)
785 {
786 if (event->button == 1) { // click, open fill&stroke
788 if (Dialog::FillAndStroke *dialog = dynamic_cast<Dialog::FillAndStroke *>(
789 _desktop->_dlg_mgr->getDialog("FillAndStroke")))
790 dialog->showPageFill();
792 } else if (event->button == 3) { // right-click, popup menu
793 _popup[SS_FILL].popup(event->button, event->time);
794 } else if (event->button == 2) { // middle click, toggle none/lastcolor
795 if (_mode[SS_FILL] == SS_NONE) {
796 on_fill_lastused();
797 } else {
798 on_fill_remove();
799 }
800 }
801 return true;
802 }
804 bool
805 SelectedStyle::on_stroke_click(GdkEventButton *event)
806 {
807 if (event->button == 1) { // click, open fill&stroke
808 if (Dialog::FillAndStroke *dialog = dynamic_cast<Dialog::FillAndStroke *>(
809 _desktop->_dlg_mgr->getDialog("FillAndStroke")))
810 dialog->showPageStrokePaint();
811 } else if (event->button == 3) { // right-click, popup menu
812 _popup[SS_STROKE].popup(event->button, event->time);
813 } else if (event->button == 2) { // middle click, toggle none/lastcolor
814 if (_mode[SS_STROKE] == SS_NONE) {
815 on_stroke_lastused();
816 } else {
817 on_stroke_remove();
818 }
819 }
820 return true;
821 }
823 bool
824 SelectedStyle::on_sw_click(GdkEventButton *event)
825 {
826 if (event->button == 1) { // click, open fill&stroke
827 if (Dialog::FillAndStroke *dialog = dynamic_cast<Dialog::FillAndStroke *>(
828 _desktop->_dlg_mgr->getDialog("FillAndStroke")))
829 dialog->showPageStrokeStyle();
830 } else if (event->button == 3) { // right-click, popup menu
831 _popup_sw.popup(event->button, event->time);
832 } else if (event->button == 2) { // middle click, toggle none/lastwidth?
833 //
834 }
835 return true;
836 }
838 bool
839 SelectedStyle::on_opacity_click(GdkEventButton *event)
840 {
841 if (event->button == 2) { // middle click
842 const char* opacity = _opacity_sb.get_value() < 50? "0.5" : (_opacity_sb.get_value() == 100? "0" : "1");
843 SPCSSAttr *css = sp_repr_css_attr_new ();
844 sp_repr_css_set_property (css, "opacity", opacity);
845 sp_desktop_set_style (_desktop, css);
846 sp_repr_css_attr_unref (css);
847 sp_document_done (sp_desktop_document (_desktop), SP_VERB_DIALOG_FILL_STROKE,
848 _("Change opacity"));
849 return true;
850 }
852 return false;
853 }
855 void SelectedStyle::on_popup_px() {
856 _sw_unit = (SPUnit *) &(sp_unit_get_by_id(SP_UNIT_PX));
857 update();
858 }
859 void SelectedStyle::on_popup_pt() {
860 _sw_unit = (SPUnit *) &(sp_unit_get_by_id(SP_UNIT_PT));
861 update();
862 }
863 void SelectedStyle::on_popup_mm() {
864 _sw_unit = (SPUnit *) &(sp_unit_get_by_id(SP_UNIT_MM));
865 update();
866 }
868 void SelectedStyle::on_popup_preset(int i) {
869 SPCSSAttr *css = sp_repr_css_attr_new ();
870 gdouble w;
871 if (_sw_unit) {
872 w = sp_units_get_pixels (_sw_presets[i], *_sw_unit);
873 } else {
874 w = _sw_presets[i];
875 }
876 Inkscape::CSSOStringStream os;
877 os << w;
878 sp_repr_css_set_property (css, "stroke-width", os.str().c_str());
879 // FIXME: update dash patterns!
880 sp_desktop_set_style (_desktop, css, true);
881 sp_repr_css_attr_unref (css);
882 sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_SWATCHES,
883 _("Change stroke width"));
884 }
886 void
887 SelectedStyle::update()
888 {
889 if (_desktop == NULL)
890 return;
892 // create temporary style
893 SPStyle *query = sp_style_new (sp_desktop_document(_desktop));
895 for (int i = SS_FILL; i <= SS_STROKE; i++) {
896 Gtk::EventBox *place = (i == SS_FILL)? &_fill_place : &_stroke_place;
897 Gtk::EventBox *flag_place = (i == SS_FILL)? &_fill_flag_place : &_stroke_flag_place;
899 place->remove();
900 flag_place->remove();
902 _tooltips.unset_tip(*place);
903 _tooltips.unset_tip(*flag_place);
905 _mode[i] = SS_NA;
906 _paintserver_id[i].clear();
908 _popup_copy[i].set_sensitive(false);
910 // query style from desktop. This returns a result flag and fills query with the style of subselection, if any, or selection
911 int result = sp_desktop_query_style (_desktop, query,
912 (i == SS_FILL)? QUERY_STYLE_PROPERTY_FILL : QUERY_STYLE_PROPERTY_STROKE);
913 switch (result) {
914 case QUERY_STYLE_NOTHING:
915 place->add(_na[i]);
916 _tooltips.set_tip(*place, __na[i]);
917 _mode[i] = SS_NA;
918 if ( _dropEnabled[i] ) {
919 gtk_drag_dest_unset( GTK_WIDGET((i==SS_FILL) ? _fill_place.gobj():_stroke_place.gobj()) );
920 _dropEnabled[i] = false;
921 }
922 break;
923 case QUERY_STYLE_SINGLE:
924 case QUERY_STYLE_MULTIPLE_AVERAGED:
925 case QUERY_STYLE_MULTIPLE_SAME:
926 if ( !_dropEnabled[i] ) {
927 gtk_drag_dest_set( GTK_WIDGET( (i==SS_FILL) ? _fill_place.gobj():_stroke_place.gobj()),
928 GTK_DEST_DEFAULT_ALL,
929 ui_drop_target_entries,
930 nui_drop_target_entries,
931 GdkDragAction(GDK_ACTION_COPY | GDK_ACTION_MOVE) );
932 _dropEnabled[i] = true;
933 }
934 SPIPaint *paint;
935 if (i == SS_FILL) {
936 paint = &(query->fill);
937 } else {
938 paint = &(query->stroke);
939 }
940 if (paint->set && paint->isPaintserver()) {
941 SPPaintServer *server = (i == SS_FILL)? SP_STYLE_FILL_SERVER (query) : SP_STYLE_STROKE_SERVER (query);
942 if ( server ) {
943 Inkscape::XML::Node *srepr = SP_OBJECT_REPR(server);
944 _paintserver_id[i] += "url(#";
945 _paintserver_id[i] += srepr->attribute("id");
946 _paintserver_id[i] += ")";
948 if (SP_IS_LINEARGRADIENT (server)) {
949 SPGradient *vector = sp_gradient_get_vector(SP_GRADIENT(server), false);
950 sp_gradient_image_set_gradient ((SPGradientImage *) _gradient_preview_l[i], vector);
951 place->add(_gradient_box_l[i]);
952 _tooltips.set_tip(*place, __lgradient[i]);
953 _mode[i] = SS_LGRADIENT;
954 } else if (SP_IS_RADIALGRADIENT (server)) {
955 SPGradient *vector = sp_gradient_get_vector(SP_GRADIENT(server), false);
956 sp_gradient_image_set_gradient ((SPGradientImage *) _gradient_preview_r[i], vector);
957 place->add(_gradient_box_r[i]);
958 _tooltips.set_tip(*place, __rgradient[i]);
959 _mode[i] = SS_RGRADIENT;
960 } else if (SP_IS_PATTERN (server)) {
961 place->add(_pattern[i]);
962 _tooltips.set_tip(*place, __pattern[i]);
963 _mode[i] = SS_PATTERN;
964 }
965 } else {
966 g_warning ("file %s: line %d: Unknown paint server", __FILE__, __LINE__);
967 }
968 } else if (paint->set && paint->isColor()) {
969 guint32 color = paint->value.color.toRGBA32(
970 SP_SCALE24_TO_FLOAT ((i == SS_FILL)? query->fill_opacity.value : query->stroke_opacity.value));
971 _lastselected[i] = _thisselected[i];
972 _thisselected[i] = color | 0xff; // only color, opacity === 1
973 ((Inkscape::UI::Widget::ColorPreview*)_color_preview[i])->setRgba32 (color);
974 _color_preview[i]->show_all();
975 place->add(*_color_preview[i]);
976 gchar c_string[64];
977 g_snprintf (c_string, 64, "%06x/%.3g", color >> 8, SP_RGBA32_A_F(color));
978 _tooltips.set_tip(*place, __color[i] + ": " + c_string + _(", drag to adjust"));
979 _mode[i] = SS_COLOR;
980 _popup_copy[i].set_sensitive(true);
982 } else if (paint->set && paint->isNone()) {
983 place->add(_none[i]);
984 _tooltips.set_tip(*place, __none[i]);
985 _mode[i] = SS_NONE;
986 } else if (!paint->set) {
987 place->add(_unset[i]);
988 _tooltips.set_tip(*place, __unset[i]);
989 _mode[i] = SS_UNSET;
990 }
991 if (result == QUERY_STYLE_MULTIPLE_AVERAGED) {
992 flag_place->add(_averaged[i]);
993 _tooltips.set_tip(*flag_place, __averaged[i]);
994 } else if (result == QUERY_STYLE_MULTIPLE_SAME) {
995 flag_place->add(_multiple[i]);
996 _tooltips.set_tip(*flag_place, __multiple[i]);
997 }
998 break;
999 case QUERY_STYLE_MULTIPLE_DIFFERENT:
1000 place->add(_many[i]);
1001 _tooltips.set_tip(*place, __many[i]);
1002 _mode[i] = SS_MANY;
1003 break;
1004 default:
1005 break;
1006 }
1007 }
1009 // Now query opacity
1010 _tooltips.unset_tip(_opacity_place);
1011 _tooltips.unset_tip(_opacity_sb);
1013 int result = sp_desktop_query_style (_desktop, query, QUERY_STYLE_PROPERTY_MASTEROPACITY);
1015 switch (result) {
1016 case QUERY_STYLE_NOTHING:
1017 _tooltips.set_tip(_opacity_place, _("Nothing selected"));
1018 _tooltips.set_tip(_opacity_sb, _("Nothing selected"));
1019 _opacity_sb.set_sensitive(false);
1020 break;
1021 case QUERY_STYLE_SINGLE:
1022 case QUERY_STYLE_MULTIPLE_AVERAGED:
1023 case QUERY_STYLE_MULTIPLE_SAME:
1024 _tooltips.set_tip(_opacity_place, _("Opacity, %"));
1025 _tooltips.set_tip(_opacity_sb, _("Opacity, %"));
1026 if (_opacity_blocked) break;
1027 _opacity_blocked = true;
1028 _opacity_sb.set_sensitive(true);
1029 _opacity_adjustment.set_value(SP_SCALE24_TO_FLOAT(query->opacity.value) * 100);
1030 _opacity_blocked = false;
1031 break;
1032 }
1034 // Now query stroke_width
1035 int result_sw = sp_desktop_query_style (_desktop, query, QUERY_STYLE_PROPERTY_STROKEWIDTH);
1036 switch (result_sw) {
1037 case QUERY_STYLE_NOTHING:
1038 _stroke_width.set_markup("");
1039 break;
1040 case QUERY_STYLE_SINGLE:
1041 case QUERY_STYLE_MULTIPLE_AVERAGED:
1042 case QUERY_STYLE_MULTIPLE_SAME:
1043 {
1044 double w;
1045 if (_sw_unit) {
1046 w = sp_pixels_get_units(query->stroke_width.computed, *_sw_unit);
1047 } else {
1048 w = query->stroke_width.computed;
1049 }
1050 {
1051 gchar *str = g_strdup_printf(" %.3g", w);
1052 _stroke_width.set_markup(str);
1053 g_free (str);
1054 }
1055 {
1056 gchar *str = g_strdup_printf(_("Stroke width: %.5g%s%s"),
1057 w,
1058 _sw_unit? sp_unit_get_abbreviation(_sw_unit) : "px",
1059 (result_sw == QUERY_STYLE_MULTIPLE_AVERAGED)?
1060 _(" (averaged)") : "");
1061 _tooltips.set_tip(_stroke_width_place, str);
1062 g_free (str);
1063 }
1064 break;
1065 }
1066 default:
1067 break;
1068 }
1070 sp_style_unref(query);
1071 }
1073 void SelectedStyle::opacity_0(void) {_opacity_sb.set_value(0);}
1074 void SelectedStyle::opacity_025(void) {_opacity_sb.set_value(25);}
1075 void SelectedStyle::opacity_05(void) {_opacity_sb.set_value(50);}
1076 void SelectedStyle::opacity_075(void) {_opacity_sb.set_value(75);}
1077 void SelectedStyle::opacity_1(void) {_opacity_sb.set_value(100);}
1079 void SelectedStyle::on_opacity_menu (Gtk::Menu *menu) {
1081 Glib::ListHandle<Gtk::Widget *> children = menu->get_children();
1082 for (Glib::ListHandle<Gtk::Widget *>::iterator iter = children.begin(); iter != children.end(); iter++) {
1083 menu->remove(*(*iter));
1084 }
1086 {
1087 Gtk::MenuItem *item = new Gtk::MenuItem;
1088 item->add(*(new Gtk::Label(_("0 (transparent)"), 0, 0)));
1089 item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_0 ));
1090 menu->add(*item);
1091 }
1092 {
1093 Gtk::MenuItem *item = new Gtk::MenuItem;
1094 item->add(*(new Gtk::Label("25%", 0, 0)));
1095 item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_025 ));
1096 menu->add(*item);
1097 }
1098 {
1099 Gtk::MenuItem *item = new Gtk::MenuItem;
1100 item->add(*(new Gtk::Label("50%", 0, 0)));
1101 item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_05 ));
1102 menu->add(*item);
1103 }
1104 {
1105 Gtk::MenuItem *item = new Gtk::MenuItem;
1106 item->add(*(new Gtk::Label("75%", 0, 0)));
1107 item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_075 ));
1108 menu->add(*item);
1109 }
1110 {
1111 Gtk::MenuItem *item = new Gtk::MenuItem;
1112 item->add(*(new Gtk::Label(_("100% (opaque)"), 0, 0)));
1113 item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_1 ));
1114 menu->add(*item);
1115 }
1117 menu->show_all();
1118 }
1120 void SelectedStyle::on_opacity_changed () {
1121 if (_opacity_blocked)
1122 return;
1123 _opacity_blocked = true;
1124 SPCSSAttr *css = sp_repr_css_attr_new ();
1125 Inkscape::CSSOStringStream os;
1126 os << CLAMP ((_opacity_adjustment.get_value() / 100), 0.0, 1.0);
1127 sp_repr_css_set_property (css, "opacity", os.str().c_str());
1128 // FIXME: workaround for GTK breakage: display interruptibility sometimes results in GTK
1129 // sending multiple value-changed events. As if when Inkscape interrupts redraw for main loop
1130 // iterations, GTK discovers that this callback hasn't finished yet, and for some weird reason
1131 // decides to add yet another value-changed event to the queue. Totally braindead if you ask
1132 // me. As a result, scrolling the spinbutton once results in runaway change until it hits 1.0
1133 // or 0.0. (And no, this is not a race with ::update, I checked that.)
1134 // Sigh. So we disable interruptibility while we're setting the new value.
1135 sp_canvas_force_full_redraw_after_interruptions(sp_desktop_canvas(_desktop), 0);
1136 sp_desktop_set_style (_desktop, css);
1137 sp_repr_css_attr_unref (css);
1138 sp_document_maybe_done (sp_desktop_document (_desktop), "fillstroke:opacity", SP_VERB_DIALOG_FILL_STROKE,
1139 _("Change opacity"));
1140 // resume interruptibility
1141 sp_canvas_end_forced_full_redraws(sp_desktop_canvas(_desktop));
1142 spinbutton_defocus(GTK_OBJECT(_opacity_sb.gobj()));
1143 _opacity_blocked = false;
1144 }
1146 RotateableSwatch::RotateableSwatch(guint mode) {
1147 fillstroke = mode;
1148 startcolor_set = false;
1149 undokey = "ssrot1";
1150 }
1152 RotateableSwatch::~RotateableSwatch() {
1153 }
1155 double
1156 RotateableSwatch::color_adjust(float *hsl, double by, guint32 cc, guint modifier)
1157 {
1158 sp_color_rgb_to_hsl_floatv (hsl, SP_RGBA32_R_F(cc), SP_RGBA32_G_F(cc), SP_RGBA32_B_F(cc));
1160 double diff = 0;
1161 if (modifier == 2) { // saturation
1162 double old = hsl[1];
1163 if (by > 0) {
1164 hsl[1] += by * (1 - hsl[1]);
1165 } else {
1166 hsl[1] += by * (hsl[1]);
1167 }
1168 diff = hsl[1] - old;
1169 } else if (modifier == 1) { // lightness
1170 double old = hsl[2];
1171 if (by > 0) {
1172 hsl[2] += by * (1 - hsl[2]);
1173 } else {
1174 hsl[2] += by * (hsl[2]);
1175 }
1176 diff = hsl[2] - old;
1177 } else { // hue
1178 double old = hsl[0];
1179 hsl[0] += by/2;
1180 while (hsl[0] < 0)
1181 hsl[0] += 1;
1182 while (hsl[0] > 1)
1183 hsl[0] -= 1;
1184 diff = hsl[0] - old;
1185 }
1187 float rgb[3];
1188 sp_color_hsl_to_rgb_floatv (rgb, hsl[0], hsl[1], hsl[2]);
1190 gchar c[64];
1191 sp_svg_write_color (c, sizeof(c),
1192 SP_RGBA32_U_COMPOSE(
1193 (SP_COLOR_F_TO_U(rgb[0])),
1194 (SP_COLOR_F_TO_U(rgb[1])),
1195 (SP_COLOR_F_TO_U(rgb[2])),
1196 0xff
1197 )
1198 );
1200 SPCSSAttr *css = sp_repr_css_attr_new ();
1201 if (fillstroke == SS_FILL)
1202 sp_repr_css_set_property (css, "fill", c);
1203 else
1204 sp_repr_css_set_property (css, "stroke", c);
1205 sp_desktop_set_style (parent->getDesktop(), css);
1206 sp_repr_css_attr_unref (css);
1207 return diff;
1208 }
1210 void
1211 RotateableSwatch::do_motion(double by, guint modifier) {
1212 if (parent->_mode[fillstroke] != SS_COLOR)
1213 return;
1215 guint32 cc;
1216 if (!startcolor_set) {
1217 cc = startcolor = parent->_thisselected[fillstroke];
1218 startcolor_set = true;
1219 } else {
1220 cc = startcolor;
1221 }
1223 float hsl[3];
1224 double diff = color_adjust(hsl, by, cc, modifier);
1226 if (modifier == 2) { // saturation
1227 sp_document_maybe_done (sp_desktop_document(parent->getDesktop()), undokey,
1228 SP_VERB_DIALOG_FILL_STROKE, ("Adjust saturation"));
1229 double ch = hsl[1];
1230 parent->getDesktop()->event_context->_message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("Adusting <b>saturation</b>: was %.3g, now <b>%.3g</b> (diff %.3g); without modifiers to adjust hue, with <b>Ctrl</b> to adjust lightness"), ch - diff, ch, diff);
1232 } else if (modifier == 1) { // lightness
1233 sp_document_maybe_done (sp_desktop_document(parent->getDesktop()), undokey,
1234 SP_VERB_DIALOG_FILL_STROKE, ("Adjust lightness"));
1235 double ch = hsl[2];
1236 parent->getDesktop()->event_context->_message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("Adusting <b>lightness</b> was %.3g, now <b>%.3g</b> (diff %.3g); without modifiers to adjust hue, with <b>Shift</b> to adjust saturation"), ch - diff, ch, diff);
1238 } else { // hue
1239 sp_document_maybe_done (sp_desktop_document(parent->getDesktop()), undokey,
1240 SP_VERB_DIALOG_FILL_STROKE, ("Adjust hue"));
1241 double ch = hsl[0];
1242 parent->getDesktop()->event_context->_message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("Adusting <b>hue</b> was %.3g, now <b>%.3g</b> (diff %.3g); with <b>Shift</b> to adjust saturation, with <b>Ctrl</b> to adjust lightness"), ch - diff, ch, diff);
1243 }
1244 }
1246 void
1247 RotateableSwatch::do_release(double by, guint modifier) {
1248 if (parent->_mode[fillstroke] != SS_COLOR)
1249 return;
1251 float hsl[3];
1252 color_adjust(hsl, by, startcolor, modifier);
1254 if (modifier == 2) { // saturation
1255 sp_document_maybe_done (sp_desktop_document(parent->getDesktop()), undokey,
1256 SP_VERB_DIALOG_FILL_STROKE, ("Adjust saturation"));
1258 } else if (modifier == 1) { // lightness
1259 sp_document_maybe_done (sp_desktop_document(parent->getDesktop()), undokey,
1260 SP_VERB_DIALOG_FILL_STROKE, ("Adjust lightness"));
1262 } else { // hue
1263 sp_document_maybe_done (sp_desktop_document(parent->getDesktop()), undokey,
1264 SP_VERB_DIALOG_FILL_STROKE, ("Adjust hue"));
1265 }
1267 if (!strcmp(undokey, "ssrot1")) {
1268 undokey = "ssrot2";
1269 } else {
1270 undokey = "ssrot1";
1271 }
1273 parent->getDesktop()->event_context->_message_context->clear();
1274 startcolor_set = false;
1275 }
1278 } // namespace Widget
1279 } // namespace UI
1280 } // namespace Inkscape
1282 /*
1283 Local Variables:
1284 mode:c++
1285 c-file-style:"stroustrup"
1286 c-file-offsets:((innamespace . 0)(inline-open . 0))
1287 indent-tabs-mode:nil
1288 fill-column:99
1289 End:
1290 */
1291 // vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :