a2e57d6000a315003ab097d31408d0af5e857d30
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"
39 static gdouble const _sw_presets[] = { 32 , 16 , 10 , 8 , 6 , 4 , 3 , 2 , 1.5 , 1 , 0.75 , 0.5 , 0.25 , 0.1 };
40 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"};
42 static void
43 ss_selection_changed (Inkscape::Selection *, gpointer data)
44 {
45 Inkscape::UI::Widget::SelectedStyle *ss = (Inkscape::UI::Widget::SelectedStyle *) data;
46 ss->update();
47 }
49 static void
50 ss_selection_modified (Inkscape::Selection *selection, guint flags, gpointer data)
51 {
52 ss_selection_changed (selection, data);
53 }
55 static void
56 ss_subselection_changed (gpointer dragger, gpointer data)
57 {
58 ss_selection_changed (NULL, data);
59 }
61 namespace Inkscape {
62 namespace UI {
63 namespace Widget {
66 typedef struct {
67 SelectedStyle* parent;
68 int item;
69 } DropTracker;
71 /* Drag and Drop */
72 typedef enum {
73 APP_X_COLOR
74 } ui_drop_target_info;
76 static GtkTargetEntry ui_drop_target_entries [] = {
77 {"application/x-color", 0, APP_X_COLOR}
78 };
80 #define ENTRIES_SIZE(n) sizeof(n)/sizeof(n[0])
81 static guint nui_drop_target_entries = ENTRIES_SIZE(ui_drop_target_entries);
84 SelectedStyle::SelectedStyle(bool layout)
85 : _desktop (NULL),
87 _table(2, 6),
88 _fill_label (_("F:")),
89 _stroke_label (_("S:")),
90 _opacity_label (_("O:")),
91 _fill_place (),
92 _stroke_place (),
94 _fill_flag_place (),
95 _stroke_flag_place (),
97 _opacity_place (),
98 _opacity_adjustment (1.0, 0.0, 1.0, 0.01, 0.1),
99 _opacity_sb (0.02, 2),
101 _stroke (),
102 _stroke_width (""),
104 _opacity_blocked (false),
106 _popup_px(_sw_group),
107 _popup_pt(_sw_group),
108 _popup_mm(_sw_group),
110 _sw_unit(NULL),
112 _tooltips ()
114 {
115 _drop[0] = _drop[1] = 0;
116 _dropEnabled[0] = _dropEnabled[1] = false;
118 _fill_label.set_alignment(0.0, 0.5);
119 _fill_label.set_padding(0, 0);
120 _stroke_label.set_alignment(0.0, 0.5);
121 _stroke_label.set_padding(0, 0);
122 _opacity_label.set_alignment(0.0, 0.5);
123 _opacity_label.set_padding(0, 0);
125 _table.set_col_spacings (2);
126 _table.set_row_spacings (0);
128 for (int i = SS_FILL; i <= SS_STROKE; i++) {
130 _na[i].set_markup (_("N/A"));
131 sp_set_font_size_smaller (GTK_WIDGET(_na[i].gobj()));
132 _na[i].show_all();
133 __na[i] = (_("Nothing selected"));
135 _none[i].set_markup (_("None"));
136 sp_set_font_size_smaller (GTK_WIDGET(_none[i].gobj()));
137 _none[i].show_all();
138 __none[i] = (i == SS_FILL)? (_("No fill")) : (_("No stroke"));
140 _pattern[i].set_markup (_("Pattern"));
141 sp_set_font_size_smaller (GTK_WIDGET(_pattern[i].gobj()));
142 _pattern[i].show_all();
143 __pattern[i] = (i == SS_FILL)? (_("Pattern fill")) : (_("Pattern stroke"));
145 _lgradient[i].set_markup (_("L Gradient"));
146 sp_set_font_size_smaller (GTK_WIDGET(_lgradient[i].gobj()));
147 _lgradient[i].show_all();
148 __lgradient[i] = (i == SS_FILL)? (_("Linear gradient fill")) : (_("Linear gradient stroke"));
150 _rgradient[i].set_markup (_("R Gradient"));
151 sp_set_font_size_smaller (GTK_WIDGET(_rgradient[i].gobj()));
152 _rgradient[i].show_all();
153 __rgradient[i] = (i == SS_FILL)? (_("Radial gradient fill")) : (_("Radial gradient stroke"));
155 _many[i].set_markup (_("Different"));
156 sp_set_font_size_smaller (GTK_WIDGET(_many[i].gobj()));
157 _many[i].show_all();
158 __many[i] = (i == SS_FILL)? (_("Different fills")) : (_("Different strokes"));
160 _unset[i].set_markup (_("Unset"));
161 sp_set_font_size_smaller (GTK_WIDGET(_unset[i].gobj()));
162 _unset[i].show_all();
163 __unset[i] = (i == SS_FILL)? (_("Unset fill")) : (_("Unset stroke"));
165 _color_preview[i] = new Inkscape::UI::Widget::ColorPreview (0);
166 __color[i] = (i == SS_FILL)? (_("Flat color fill")) : (_("Flat color stroke"));
168 // TRANSLATOR COMMENT: A means "Averaged"
169 _averaged[i].set_markup (_("<b>a</b>"));
170 sp_set_font_size_smaller (GTK_WIDGET(_averaged[i].gobj()));
171 _averaged[i].show_all();
172 __averaged[i] = (i == SS_FILL)? (_("Fill is averaged over selected objects")) : (_("Stroke is averaged over selected objects"));
174 // TRANSLATOR COMMENT: M means "Multiple"
175 _multiple[i].set_markup (_("<b>m</b>"));
176 sp_set_font_size_smaller (GTK_WIDGET(_multiple[i].gobj()));
177 _multiple[i].show_all();
178 __multiple[i] = (i == SS_FILL)? (_("Multiple selected objects have the same fill")) : (_("Multiple selected objects have the same stroke"));
180 _popup_edit[i].add(*(new Gtk::Label((i == SS_FILL)? _("Edit fill...") : _("Edit stroke..."), 0.0, 0.5)));
181 _popup_edit[i].signal_activate().connect(sigc::mem_fun(*this,
182 (i == SS_FILL)? &SelectedStyle::on_fill_edit : &SelectedStyle::on_stroke_edit ));
184 _popup_lastused[i].add(*(new Gtk::Label(_("Last set color"), 0.0, 0.5)));
185 _popup_lastused[i].signal_activate().connect(sigc::mem_fun(*this,
186 (i == SS_FILL)? &SelectedStyle::on_fill_lastused : &SelectedStyle::on_stroke_lastused ));
188 _popup_lastselected[i].add(*(new Gtk::Label(_("Last selected color"), 0.0, 0.5)));
189 _popup_lastselected[i].signal_activate().connect(sigc::mem_fun(*this,
190 (i == SS_FILL)? &SelectedStyle::on_fill_lastselected : &SelectedStyle::on_stroke_lastselected ));
192 _popup_invert[i].add(*(new Gtk::Label(_("Invert"), 0.0, 0.5)));
193 _popup_invert[i].signal_activate().connect(sigc::mem_fun(*this,
194 (i == SS_FILL)? &SelectedStyle::on_fill_invert : &SelectedStyle::on_stroke_invert ));
196 _popup_white[i].add(*(new Gtk::Label(_("White"), 0.0, 0.5)));
197 _popup_white[i].signal_activate().connect(sigc::mem_fun(*this,
198 (i == SS_FILL)? &SelectedStyle::on_fill_white : &SelectedStyle::on_stroke_white ));
200 _popup_black[i].add(*(new Gtk::Label(_("Black"), 0.0, 0.5)));
201 _popup_black[i].signal_activate().connect(sigc::mem_fun(*this,
202 (i == SS_FILL)? &SelectedStyle::on_fill_black : &SelectedStyle::on_stroke_black ));
204 _popup_copy[i].add(*(new Gtk::Label(_("Copy color"), 0.0, 0.5)));
205 _popup_copy[i].signal_activate().connect(sigc::mem_fun(*this,
206 (i == SS_FILL)? &SelectedStyle::on_fill_copy : &SelectedStyle::on_stroke_copy ));
208 _popup_paste[i].add(*(new Gtk::Label(_("Paste color"), 0.0, 0.5)));
209 _popup_paste[i].signal_activate().connect(sigc::mem_fun(*this,
210 (i == SS_FILL)? &SelectedStyle::on_fill_paste : &SelectedStyle::on_stroke_paste ));
212 _popup_swap[i].add(*(new Gtk::Label(_("Swap fill and stroke"), 0.0, 0.5)));
213 _popup_swap[i].signal_activate().connect(sigc::mem_fun(*this,
214 &SelectedStyle::on_fillstroke_swap));
216 _popup_opaque[i].add(*(new Gtk::Label((i == SS_FILL)? _("Make fill opaque") : _("Make stroke opaque"), 0.0, 0.5)));
217 _popup_opaque[i].signal_activate().connect(sigc::mem_fun(*this,
218 (i == SS_FILL)? &SelectedStyle::on_fill_opaque : &SelectedStyle::on_stroke_opaque ));
220 //TRANSLATORS COMMENT: unset is a verb here
221 _popup_unset[i].add(*(new Gtk::Label((i == SS_FILL)? _("Unset fill") : _("Unset stroke"), 0.0, 0.5)));
222 _popup_unset[i].signal_activate().connect(sigc::mem_fun(*this,
223 (i == SS_FILL)? &SelectedStyle::on_fill_unset : &SelectedStyle::on_stroke_unset ));
225 _popup_remove[i].add(*(new Gtk::Label((i == SS_FILL)? _("Remove fill") : _("Remove stroke"), 0.0, 0.5)));
226 _popup_remove[i].signal_activate().connect(sigc::mem_fun(*this,
227 (i == SS_FILL)? &SelectedStyle::on_fill_remove : &SelectedStyle::on_stroke_remove ));
229 _popup[i].attach(_popup_edit[i], 0,1, 0,1);
230 _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 1,2);
231 _popup[i].attach(_popup_lastused[i], 0,1, 2,3);
232 _popup[i].attach(_popup_lastselected[i], 0,1, 3,4);
233 _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 4,5);
234 _popup[i].attach(_popup_invert[i], 0,1, 5,6);
235 _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 6,7);
236 _popup[i].attach(_popup_white[i], 0,1, 7,8);
237 _popup[i].attach(_popup_black[i], 0,1, 8,9);
238 _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 9,10);
239 _popup[i].attach(_popup_copy[i], 0,1, 10,11);
240 _popup_copy[i].set_sensitive(false);
241 _popup[i].attach(_popup_paste[i], 0,1, 11,12);
242 _popup[i].attach(_popup_swap[i], 0,1, 12,13);
243 _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 13,14);
244 _popup[i].attach(_popup_opaque[i], 0,1, 14,15);
245 _popup[i].attach(_popup_unset[i], 0,1, 15,16);
246 _popup[i].attach(_popup_remove[i], 0,1, 16,17);
247 _popup[i].show_all();
249 _mode[i] = SS_NA;
250 }
252 {
253 _popup_px.add(*(new Gtk::Label(_("px"), 0.0, 0.5)));
254 _popup_px.signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::on_popup_px));
255 _popup_sw.attach(_popup_px, 0,1, 0,1);
257 _popup_pt.add(*(new Gtk::Label(_("pt"), 0.0, 0.5)));
258 _popup_pt.signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::on_popup_pt));
259 _popup_sw.attach(_popup_pt, 0,1, 1,2);
261 _popup_mm.add(*(new Gtk::Label(_("mm"), 0.0, 0.5)));
262 _popup_mm.signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::on_popup_mm));
263 _popup_sw.attach(_popup_mm, 0,1, 2,3);
265 _popup_sw.attach(*(new Gtk::SeparatorMenuItem()), 0,1, 3,4);
267 for (guint i = 0; i < G_N_ELEMENTS(_sw_presets_str); ++i) {
268 Gtk::MenuItem *mi = Gtk::manage(new Gtk::MenuItem());
269 mi->add(*(new Gtk::Label(_sw_presets_str[i], 0.0, 0.5)));
270 mi->signal_activate().connect(sigc::bind<int>(sigc::mem_fun(*this, &SelectedStyle::on_popup_preset), i));
271 _popup_sw.attach(*mi, 0,1, 4+i, 5+i);
272 }
274 guint i = G_N_ELEMENTS(_sw_presets_str) + 5;
276 _popup_sw.attach(*(new Gtk::SeparatorMenuItem()), 0,1, i,i+1);
278 _popup_sw_remove.add(*(new Gtk::Label(_("Remove"), 0.0, 0.5)));
279 _popup_sw_remove.signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::on_stroke_remove));
280 _popup_sw.attach(_popup_sw_remove, 0,1, i+1,i+2);
282 _popup_sw.show_all();
283 }
285 _fill_place.signal_button_press_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_fill_click));
286 _stroke_place.signal_button_press_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_stroke_click));
287 _opacity_place.signal_button_press_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_opacity_click));
288 _stroke_width_place.signal_button_press_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_sw_click));
290 _opacity_sb.signal_populate_popup().connect(sigc::mem_fun(*this, &SelectedStyle::on_opacity_menu));
291 _opacity_sb.signal_value_changed().connect(sigc::mem_fun(*this, &SelectedStyle::on_opacity_changed));
293 _fill_place.add(_na[SS_FILL]);
294 _tooltips.set_tip(_fill_place, __na[SS_FILL]);
296 _stroke_place.add(_na[SS_STROKE]);
297 _tooltips.set_tip(_stroke_place, __na[SS_STROKE]);
299 _stroke.pack_start(_stroke_place);
300 _stroke_width_place.add(_stroke_width);
301 _stroke.pack_start(_stroke_width_place, Gtk::PACK_SHRINK);
303 _opacity_sb.set_adjustment(_opacity_adjustment);
304 sp_set_font_size_smaller (GTK_WIDGET(_opacity_sb.gobj()));
305 _opacity_sb.set_size_request (SELECTED_STYLE_SB_WIDTH, -1);
306 _opacity_sb.set_sensitive (false);
308 _table.attach(_fill_label, 0,1, 0,1, Gtk::SHRINK, Gtk::SHRINK);
309 _table.attach(_stroke_label, 0,1, 1,2, Gtk::SHRINK, Gtk::SHRINK);
311 _table.attach(_fill_flag_place, 1,2, 0,1, Gtk::SHRINK, Gtk::SHRINK);
312 _table.attach(_stroke_flag_place, 1,2, 1,2, Gtk::SHRINK, Gtk::SHRINK);
314 _table.attach(_fill_place, 2,3, 0,1);
315 _table.attach(_stroke, 2,3, 1,2);
317 _opacity_place.add(_opacity_label);
318 _table.attach(_opacity_place, 4,5, 0,2, Gtk::SHRINK, Gtk::SHRINK);
319 _table.attach(_opacity_sb, 5,6, 0,2, Gtk::SHRINK, Gtk::SHRINK);
321 pack_start(_table, true, true, 2);
323 set_size_request (SELECTED_STYLE_WIDTH, -1);
325 sp_set_font_size_smaller (GTK_WIDGET(_opacity_label.gobj()));
326 sp_set_font_size_smaller (GTK_WIDGET(_opacity_sb.gobj()));
327 sp_set_font_size_smaller (GTK_WIDGET(_fill_place.gobj()));
328 sp_set_font_size_smaller (GTK_WIDGET(_fill_flag_place.gobj()));
329 sp_set_font_size_smaller (GTK_WIDGET(_stroke_place.gobj()));
330 sp_set_font_size_smaller (GTK_WIDGET(_stroke_flag_place.gobj()));
331 sp_set_font_size_smaller (GTK_WIDGET(_stroke_width.gobj()));
332 sp_set_font_size_smaller (GTK_WIDGET(_fill_label.gobj()));
333 sp_set_font_size_smaller (GTK_WIDGET(_stroke_label.gobj()));
335 _drop[SS_FILL] = new DropTracker();
336 ((DropTracker*)_drop[SS_FILL])->parent = this;
337 ((DropTracker*)_drop[SS_FILL])->item = SS_FILL;
339 _drop[SS_STROKE] = new DropTracker();
340 ((DropTracker*)_drop[SS_STROKE])->parent = this;
341 ((DropTracker*)_drop[SS_STROKE])->item = SS_STROKE;
343 g_signal_connect(_stroke_place.gobj(),
344 "drag_data_received",
345 G_CALLBACK(dragDataReceived),
346 _drop[SS_STROKE]);
348 g_signal_connect(_fill_place.gobj(),
349 "drag_data_received",
350 G_CALLBACK(dragDataReceived),
351 _drop[SS_FILL]);
352 }
354 SelectedStyle::~SelectedStyle()
355 {
356 selection_changed_connection->disconnect();
357 delete selection_changed_connection;
358 selection_modified_connection->disconnect();
359 delete selection_modified_connection;
360 subselection_changed_connection->disconnect();
361 delete subselection_changed_connection;
363 for (int i = SS_FILL; i <= SS_STROKE; i++) {
364 delete _color_preview[i];
365 }
367 delete (DropTracker*)_drop[SS_FILL];
368 delete (DropTracker*)_drop[SS_STROKE];
369 }
371 void
372 SelectedStyle::setDesktop(SPDesktop *desktop)
373 {
374 _desktop = desktop;
375 gtk_object_set_data (GTK_OBJECT(_opacity_sb.gobj()), "dtw", _desktop->canvas);
377 Inkscape::Selection *selection = sp_desktop_selection (desktop);
379 selection_changed_connection = new sigc::connection (selection->connectChanged(
380 sigc::bind (
381 sigc::ptr_fun(&ss_selection_changed),
382 this )
383 ));
384 selection_modified_connection = new sigc::connection (selection->connectModified(
385 sigc::bind (
386 sigc::ptr_fun(&ss_selection_modified),
387 this )
388 ));
389 subselection_changed_connection = new sigc::connection (desktop->connectToolSubselectionChanged(
390 sigc::bind (
391 sigc::ptr_fun(&ss_subselection_changed),
392 this )
393 ));
395 //_sw_unit = (SPUnit *) sp_desktop_namedview(desktop)->doc_units;
396 }
398 void SelectedStyle::dragDataReceived( GtkWidget *widget,
399 GdkDragContext *drag_context,
400 gint x, gint y,
401 GtkSelectionData *data,
402 guint info,
403 guint event_time,
404 gpointer user_data )
405 {
406 DropTracker* tracker = (DropTracker*)user_data;
408 switch ( (int)tracker->item ) {
409 case SS_FILL:
410 case SS_STROKE:
411 {
412 if ( data->length == 8 ) {
413 gchar c[64];
414 // Careful about endian issues.
415 guint16* dataVals = (guint16*)data->data;
416 sp_svg_write_color( c, 64,
417 SP_RGBA32_U_COMPOSE(
418 0x0ff & (dataVals[0] >> 8),
419 0x0ff & (dataVals[1] >> 8),
420 0x0ff & (dataVals[2] >> 8),
421 0xff // can't have transparency in the color itself
422 //0x0ff & (data->data[3] >> 8),
423 ));
424 SPCSSAttr *css = sp_repr_css_attr_new();
425 sp_repr_css_set_property( css, (tracker->item == SS_FILL) ? "fill":"stroke", c );
426 sp_desktop_set_style( tracker->parent->_desktop, css );
427 sp_repr_css_attr_unref( css );
428 sp_document_done( sp_desktop_document(tracker->parent->_desktop) );
429 }
430 }
431 break;
432 }
433 }
435 void SelectedStyle::on_fill_remove() {
436 SPCSSAttr *css = sp_repr_css_attr_new ();
437 sp_repr_css_set_property (css, "fill", "none");
438 sp_desktop_set_style (_desktop, css, true, true);
439 sp_repr_css_attr_unref (css);
440 sp_document_done (sp_desktop_document(_desktop));
441 }
443 void SelectedStyle::on_stroke_remove() {
444 SPCSSAttr *css = sp_repr_css_attr_new ();
445 sp_repr_css_set_property (css, "stroke", "none");
446 sp_desktop_set_style (_desktop, css, true, true);
447 sp_repr_css_attr_unref (css);
448 sp_document_done (sp_desktop_document(_desktop));
449 }
451 void SelectedStyle::on_fill_unset() {
452 SPCSSAttr *css = sp_repr_css_attr_new ();
453 sp_repr_css_unset_property (css, "fill");
454 sp_desktop_set_style (_desktop, css, true, true);
455 sp_repr_css_attr_unref (css);
456 sp_document_done (sp_desktop_document(_desktop));
457 }
459 void SelectedStyle::on_stroke_unset() {
460 SPCSSAttr *css = sp_repr_css_attr_new ();
461 sp_repr_css_unset_property (css, "stroke");
462 sp_desktop_set_style (_desktop, css, true, true);
463 sp_repr_css_attr_unref (css);
464 sp_document_done (sp_desktop_document(_desktop));
465 }
467 void SelectedStyle::on_fill_opaque() {
468 SPCSSAttr *css = sp_repr_css_attr_new ();
469 sp_repr_css_set_property (css, "fill-opacity", "1");
470 sp_desktop_set_style (_desktop, css, true);
471 sp_repr_css_attr_unref (css);
472 sp_document_done (sp_desktop_document(_desktop));
473 }
475 void SelectedStyle::on_stroke_opaque() {
476 SPCSSAttr *css = sp_repr_css_attr_new ();
477 sp_repr_css_set_property (css, "stroke-opacity", "1");
478 sp_desktop_set_style (_desktop, css, true);
479 sp_repr_css_attr_unref (css);
480 sp_document_done (sp_desktop_document(_desktop));
481 }
483 void SelectedStyle::on_fill_lastused() {
484 SPCSSAttr *css = sp_repr_css_attr_new ();
485 guint32 color = sp_desktop_get_color(_desktop, true);
486 gchar c[64];
487 sp_svg_write_color (c, 64, color);
488 sp_repr_css_set_property (css, "fill", c);
489 sp_desktop_set_style (_desktop, css);
490 sp_repr_css_attr_unref (css);
491 sp_document_done (sp_desktop_document(_desktop));
492 }
494 void SelectedStyle::on_stroke_lastused() {
495 SPCSSAttr *css = sp_repr_css_attr_new ();
496 guint32 color = sp_desktop_get_color(_desktop, false);
497 gchar c[64];
498 sp_svg_write_color (c, 64, color);
499 sp_repr_css_set_property (css, "stroke", c);
500 sp_desktop_set_style (_desktop, css);
501 sp_repr_css_attr_unref (css);
502 sp_document_done (sp_desktop_document(_desktop));
503 }
505 void SelectedStyle::on_fill_lastselected() {
506 SPCSSAttr *css = sp_repr_css_attr_new ();
507 gchar c[64];
508 sp_svg_write_color (c, 64, _lastselected[SS_FILL]);
509 sp_repr_css_set_property (css, "fill", c);
510 sp_desktop_set_style (_desktop, css);
511 sp_repr_css_attr_unref (css);
512 sp_document_done (sp_desktop_document(_desktop));
513 }
515 void SelectedStyle::on_stroke_lastselected() {
516 SPCSSAttr *css = sp_repr_css_attr_new ();
517 gchar c[64];
518 sp_svg_write_color (c, 64, _lastselected[SS_STROKE]);
519 sp_repr_css_set_property (css, "stroke", c);
520 sp_desktop_set_style (_desktop, css);
521 sp_repr_css_attr_unref (css);
522 sp_document_done (sp_desktop_document(_desktop));
523 }
525 void SelectedStyle::on_fill_invert() {
526 SPCSSAttr *css = sp_repr_css_attr_new ();
527 guint32 color = _thisselected[SS_FILL];
528 gchar c[64];
529 if (_mode[SS_FILL] != SS_COLOR) return;
530 sp_svg_write_color (c, 64,
531 SP_RGBA32_U_COMPOSE(
532 (255 - SP_RGBA32_R_U(color)),
533 (255 - SP_RGBA32_G_U(color)),
534 (255 - SP_RGBA32_B_U(color)),
535 SP_RGBA32_A_U(color)
536 )
537 );
538 sp_repr_css_set_property (css, "fill", c);
539 sp_desktop_set_style (_desktop, css);
540 sp_repr_css_attr_unref (css);
541 sp_document_done (sp_desktop_document(_desktop));
542 }
544 void SelectedStyle::on_stroke_invert() {
545 SPCSSAttr *css = sp_repr_css_attr_new ();
546 guint32 color = _thisselected[SS_STROKE];
547 gchar c[64];
548 if (_mode[SS_STROKE] != SS_COLOR) return;
549 sp_svg_write_color (c, 64,
550 SP_RGBA32_U_COMPOSE(
551 (255 - SP_RGBA32_R_U(color)),
552 (255 - SP_RGBA32_G_U(color)),
553 (255 - SP_RGBA32_B_U(color)),
554 SP_RGBA32_A_U(color)
555 )
556 );
557 sp_repr_css_set_property (css, "stroke", c);
558 sp_desktop_set_style (_desktop, css);
559 sp_repr_css_attr_unref (css);
560 sp_document_done (sp_desktop_document(_desktop));
561 }
563 void SelectedStyle::on_fill_white() {
564 SPCSSAttr *css = sp_repr_css_attr_new ();
565 gchar c[64];
566 sp_svg_write_color (c, 64, 0xffffffff);
567 sp_repr_css_set_property (css, "fill", c);
568 sp_repr_css_set_property (css, "fill-opacity", "1");
569 sp_desktop_set_style (_desktop, css);
570 sp_repr_css_attr_unref (css);
571 sp_document_done (sp_desktop_document(_desktop));
572 }
574 void SelectedStyle::on_stroke_white() {
575 SPCSSAttr *css = sp_repr_css_attr_new ();
576 gchar c[64];
577 sp_svg_write_color (c, 64, 0xffffffff);
578 sp_repr_css_set_property (css, "stroke", c);
579 sp_repr_css_set_property (css, "stroke-opacity", "1");
580 sp_desktop_set_style (_desktop, css);
581 sp_repr_css_attr_unref (css);
582 sp_document_done (sp_desktop_document(_desktop));
583 }
585 void SelectedStyle::on_fill_black() {
586 SPCSSAttr *css = sp_repr_css_attr_new ();
587 gchar c[64];
588 sp_svg_write_color (c, 64, 0x000000ff);
589 sp_repr_css_set_property (css, "fill", c);
590 sp_repr_css_set_property (css, "fill-opacity", "1.0");
591 sp_desktop_set_style (_desktop, css);
592 sp_repr_css_attr_unref (css);
593 sp_document_done (sp_desktop_document(_desktop));
594 }
596 void SelectedStyle::on_stroke_black() {
597 SPCSSAttr *css = sp_repr_css_attr_new ();
598 gchar c[64];
599 sp_svg_write_color (c, 64, 0x000000ff);
600 sp_repr_css_set_property (css, "stroke", c);
601 sp_repr_css_set_property (css, "stroke-opacity", "1.0");
602 sp_desktop_set_style (_desktop, css);
603 sp_repr_css_attr_unref (css);
604 sp_document_done (sp_desktop_document(_desktop));
605 }
607 void SelectedStyle::on_fill_copy() {
608 if (_mode[SS_FILL] == SS_COLOR) {
609 gchar c[64];
610 sp_svg_write_color (c, 64, _thisselected[SS_FILL]);
611 Glib::ustring text;
612 text += c;
613 if (!text.empty()) {
614 Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
615 refClipboard->set_text(text);
616 }
617 }
618 }
620 void SelectedStyle::on_stroke_copy() {
621 if (_mode[SS_STROKE] == SS_COLOR) {
622 gchar c[64];
623 sp_svg_write_color (c, 64, _thisselected[SS_STROKE]);
624 Glib::ustring text;
625 text += c;
626 if (!text.empty()) {
627 Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
628 refClipboard->set_text(text);
629 }
630 }
631 }
633 void SelectedStyle::on_fill_paste() {
634 Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
635 Glib::ustring const text = refClipboard->wait_for_text();
637 if (!text.empty()) {
638 guint32 color = sp_svg_read_color(text.c_str(), 0x000000ff); // impossible value, as SVG color cannot have opacity
639 if (color == 0x000000ff) // failed to parse color string
640 return;
642 SPCSSAttr *css = sp_repr_css_attr_new ();
643 sp_repr_css_set_property (css, "fill", text.c_str());
644 sp_desktop_set_style (_desktop, css);
645 sp_repr_css_attr_unref (css);
646 sp_document_done (sp_desktop_document(_desktop));
647 }
648 }
650 void SelectedStyle::on_stroke_paste() {
651 Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
652 Glib::ustring const text = refClipboard->wait_for_text();
654 if (!text.empty()) {
655 guint32 color = sp_svg_read_color(text.c_str(), 0x000000ff); // impossible value, as SVG color cannot have opacity
656 if (color == 0x000000ff) // failed to parse color string
657 return;
659 SPCSSAttr *css = sp_repr_css_attr_new ();
660 sp_repr_css_set_property (css, "stroke", text.c_str());
661 sp_desktop_set_style (_desktop, css);
662 sp_repr_css_attr_unref (css);
663 sp_document_done (sp_desktop_document(_desktop));
664 }
665 }
667 void SelectedStyle::on_fillstroke_swap() {
668 SPCSSAttr *css = sp_repr_css_attr_new ();
670 g_message("on_fillstroke_swap()");
672 switch (_mode[SS_FILL]) {
673 case SS_NA:
674 case SS_MANY:
675 break;
676 case SS_NONE:
677 sp_repr_css_set_property (css, "stroke", "none");
678 break;
679 case SS_UNSET:
680 sp_repr_css_unset_property (css, "stroke");
681 break;
682 case SS_COLOR:
683 gchar c[64];
684 sp_svg_write_color (c, 64, _thisselected[SS_FILL]);
685 sp_repr_css_set_property (css, "stroke", c);
686 break;
687 case SS_LGRADIENT:
688 case SS_RGRADIENT:
689 case SS_PATTERN:
690 sp_repr_css_set_property (css, "stroke", _paintserver_id[SS_FILL].c_str());
691 break;
692 }
694 switch (_mode[SS_STROKE]) {
695 case SS_NA:
696 case SS_MANY:
697 break;
698 case SS_NONE:
699 sp_repr_css_set_property (css, "fill", "none");
700 break;
701 case SS_UNSET:
702 sp_repr_css_unset_property (css, "fill");
703 break;
704 case SS_COLOR:
705 gchar c[64];
706 sp_svg_write_color (c, 64, _thisselected[SS_STROKE]);
707 sp_repr_css_set_property (css, "fill", c);
708 break;
709 case SS_LGRADIENT:
710 case SS_RGRADIENT:
711 case SS_PATTERN:
712 sp_repr_css_set_property (css, "fill", _paintserver_id[SS_STROKE].c_str());
713 break;
714 }
716 sp_desktop_set_style (_desktop, css);
717 sp_repr_css_attr_unref (css);
718 sp_document_done (sp_desktop_document(_desktop));
719 }
721 void SelectedStyle::on_fill_edit() {
722 sp_object_properties_fill();
723 }
725 void SelectedStyle::on_stroke_edit() {
726 sp_object_properties_stroke();
727 }
729 bool
730 SelectedStyle::on_fill_click(GdkEventButton *event)
731 {
732 if (event->button == 1) { // click, open fill&stroke
733 sp_object_properties_fill();
734 } else if (event->button == 3) { // right-click, popup menu
735 _popup[SS_FILL].popup(event->button, event->time);
736 } else if (event->button == 2) { // middle click, toggle none/lastcolor
737 if (_mode[SS_FILL] == SS_NONE) {
738 on_fill_lastused();
739 } else {
740 on_fill_remove();
741 }
742 }
743 return true;
744 }
746 bool
747 SelectedStyle::on_stroke_click(GdkEventButton *event)
748 {
749 if (event->button == 1) { // click, open fill&stroke
750 sp_object_properties_stroke();
751 } else if (event->button == 3) { // right-click, popup menu
752 _popup[SS_STROKE].popup(event->button, event->time);
753 } else if (event->button == 2) { // middle click, toggle none/lastcolor
754 if (_mode[SS_STROKE] == SS_NONE) {
755 on_stroke_lastused();
756 } else {
757 on_stroke_remove();
758 }
759 }
760 return true;
761 }
763 bool
764 SelectedStyle::on_sw_click(GdkEventButton *event)
765 {
766 if (event->button == 1) { // click, open fill&stroke
767 sp_object_properties_stroke_style ();
768 } else if (event->button == 3) { // right-click, popup menu
769 _popup_sw.popup(event->button, event->time);
770 } else if (event->button == 2) { // middle click, toggle none/lastwidth?
771 //
772 }
773 return true;
774 }
776 bool
777 SelectedStyle::on_opacity_click(GdkEventButton *event)
778 {
779 if (event->button == 2) { // middle click
780 const char* opacity = _opacity_sb.get_value() < 0.5? "0.5" : (_opacity_sb.get_value() == 1? "0" : "1");
781 SPCSSAttr *css = sp_repr_css_attr_new ();
782 sp_repr_css_set_property (css, "opacity", opacity);
783 sp_desktop_set_style (_desktop, css);
784 sp_repr_css_attr_unref (css);
785 sp_document_done (sp_desktop_document (_desktop));
786 return true;
787 }
789 return false;
790 }
792 void SelectedStyle::on_popup_px() {
793 _sw_unit = (SPUnit *) &(sp_unit_get_by_id(SP_UNIT_PX));
794 update();
795 }
796 void SelectedStyle::on_popup_pt() {
797 _sw_unit = (SPUnit *) &(sp_unit_get_by_id(SP_UNIT_PT));
798 update();
799 }
800 void SelectedStyle::on_popup_mm() {
801 _sw_unit = (SPUnit *) &(sp_unit_get_by_id(SP_UNIT_MM));
802 update();
803 }
805 void SelectedStyle::on_popup_preset(int i) {
806 SPCSSAttr *css = sp_repr_css_attr_new ();
807 gdouble w;
808 if (_sw_unit) {
809 w = sp_units_get_pixels (_sw_presets[i], *_sw_unit);
810 } else {
811 w = _sw_presets[i];
812 }
813 Inkscape::CSSOStringStream os;
814 os << w;
815 sp_repr_css_set_property (css, "stroke-width", os.str().c_str());
816 sp_desktop_set_style (_desktop, css, true);
817 sp_repr_css_attr_unref (css);
818 sp_document_done (sp_desktop_document(_desktop));
819 }
821 void
822 SelectedStyle::update()
823 {
824 if (_desktop == NULL)
825 return;
827 // create temporary style
828 SPStyle *query = sp_style_new ();
830 for (int i = SS_FILL; i <= SS_STROKE; i++) {
831 Gtk::EventBox *place = (i == SS_FILL)? &_fill_place : &_stroke_place;
832 Gtk::EventBox *flag_place = (i == SS_FILL)? &_fill_flag_place : &_stroke_flag_place;
834 place->remove();
835 flag_place->remove();
837 _tooltips.unset_tip(*place);
838 _tooltips.unset_tip(*flag_place);
840 _mode[i] = SS_NA;
841 _paintserver_id[i].clear();
843 _popup_copy[i].set_sensitive(false);
845 // query style from desktop. This returns a result flag and fills query with the style of subselection, if any, or selection
846 int result = sp_desktop_query_style (_desktop, query,
847 (i == SS_FILL)? QUERY_STYLE_PROPERTY_FILL : QUERY_STYLE_PROPERTY_STROKE);
848 switch (result) {
849 case QUERY_STYLE_NOTHING:
850 place->add(_na[i]);
851 _tooltips.set_tip(*place, __na[i]);
852 _mode[i] = SS_NA;
853 if ( _dropEnabled[i] ) {
854 gtk_drag_dest_unset( GTK_WIDGET((i==SS_FILL) ? _fill_place.gobj():_stroke_place.gobj()) );
855 _dropEnabled[i] = false;
856 }
857 break;
858 case QUERY_STYLE_SINGLE:
859 case QUERY_STYLE_MULTIPLE_AVERAGED:
860 case QUERY_STYLE_MULTIPLE_SAME:
861 if ( !_dropEnabled[i] ) {
862 gtk_drag_dest_set( GTK_WIDGET( (i==SS_FILL) ? _fill_place.gobj():_stroke_place.gobj()),
863 GTK_DEST_DEFAULT_ALL,
864 ui_drop_target_entries,
865 nui_drop_target_entries,
866 GdkDragAction(GDK_ACTION_COPY | GDK_ACTION_MOVE) );
867 _dropEnabled[i] = true;
868 }
869 SPIPaint *paint;
870 if (i == SS_FILL) {
871 paint = &(query->fill);
872 } else {
873 paint = &(query->stroke);
874 }
875 if (paint->set && paint->type == SP_PAINT_TYPE_COLOR) {
876 guint32 color = sp_color_get_rgba32_falpha (&(paint->value.color),
877 SP_SCALE24_TO_FLOAT ((i == SS_FILL)? query->fill_opacity.value : query->stroke_opacity.value));
878 _lastselected[i] = _thisselected[i];
879 _thisselected[i] = color | 0xff; // only color, opacity === 1
880 ((Inkscape::UI::Widget::ColorPreview*)_color_preview[i])->setRgba32 (color);
881 _color_preview[i]->show_all();
882 place->add(*_color_preview[i]);
883 gchar c_string[64];
884 g_snprintf (c_string, 64, "%06x/%.3g", color >> 8, SP_RGBA32_A_F(color));
885 _tooltips.set_tip(*place, __color[i] + ": " + c_string);
886 _mode[i] = SS_COLOR;
887 _popup_copy[i].set_sensitive(true);
889 } else if (paint->set && paint->type == SP_PAINT_TYPE_PAINTSERVER) {
890 SPPaintServer *server = (i == SS_FILL)? SP_STYLE_FILL_SERVER (query) : SP_STYLE_STROKE_SERVER (query);
891 if ( server ) {
892 Inkscape::XML::Node *srepr = SP_OBJECT_REPR(server);
893 _paintserver_id[i] += "url(#";
894 _paintserver_id[i] += srepr->attribute("id");
895 _paintserver_id[i] += ")";
897 if (SP_IS_LINEARGRADIENT (server)) {
898 place->add(_lgradient[i]);
899 _tooltips.set_tip(*place, __lgradient[i]);
900 _mode[i] = SS_LGRADIENT;
901 } else if (SP_IS_RADIALGRADIENT (server)) {
902 place->add(_rgradient[i]);
903 _tooltips.set_tip(*place, __rgradient[i]);
904 _mode[i] = SS_RGRADIENT;
905 } else if (SP_IS_PATTERN (server)) {
906 place->add(_pattern[i]);
907 _tooltips.set_tip(*place, __pattern[i]);
908 _mode[i] = SS_PATTERN;
909 }
910 } else {
911 g_warning ("file %s: line %d: Unknown paint server", __FILE__, __LINE__);
912 }
914 } else if (paint->set && paint->type == SP_PAINT_TYPE_NONE) {
915 place->add(_none[i]);
916 _tooltips.set_tip(*place, __none[i]);
917 _mode[i] = SS_NONE;
918 } else if (!paint->set) {
919 place->add(_unset[i]);
920 _tooltips.set_tip(*place, __unset[i]);
921 _mode[i] = SS_UNSET;
922 }
923 if (result == QUERY_STYLE_MULTIPLE_AVERAGED) {
924 flag_place->add(_averaged[i]);
925 _tooltips.set_tip(*flag_place, __averaged[i]);
926 } else if (result == QUERY_STYLE_MULTIPLE_SAME) {
927 flag_place->add(_multiple[i]);
928 _tooltips.set_tip(*flag_place, __multiple[i]);
929 }
930 break;
931 case QUERY_STYLE_MULTIPLE_DIFFERENT:
932 place->add(_many[i]);
933 _tooltips.set_tip(*place, __many[i]);
934 _mode[i] = SS_MANY;
935 break;
936 default:
937 break;
938 }
939 }
941 // Now query opacity
942 _tooltips.unset_tip(_opacity_place);
944 int result = sp_desktop_query_style (_desktop, query, QUERY_STYLE_PROPERTY_MASTEROPACITY);
946 switch (result) {
947 case QUERY_STYLE_NOTHING:
948 _tooltips.set_tip(_opacity_place, _("Nothing selected"));
949 _opacity_sb.set_sensitive(false);
950 break;
951 case QUERY_STYLE_SINGLE:
952 case QUERY_STYLE_MULTIPLE_AVERAGED:
953 case QUERY_STYLE_MULTIPLE_SAME:
954 _tooltips.set_tip(_opacity_place, _("Master opacity"));
955 _opacity_blocked = true;
956 _opacity_sb.set_sensitive(true);
957 _opacity_adjustment.set_value(SP_SCALE24_TO_FLOAT(query->opacity.value));
958 _opacity_blocked = false;
959 break;
960 }
962 // Now query stroke_width
963 int result_sw = sp_desktop_query_style (_desktop, query, QUERY_STYLE_PROPERTY_STROKEWIDTH);
964 switch (result_sw) {
965 case QUERY_STYLE_NOTHING:
966 _stroke_width.set_markup("");
967 break;
968 case QUERY_STYLE_SINGLE:
969 case QUERY_STYLE_MULTIPLE_AVERAGED:
970 case QUERY_STYLE_MULTIPLE_SAME:
971 {
972 double w;
973 if (_sw_unit) {
974 w = sp_pixels_get_units(query->stroke_width.computed, *_sw_unit);
975 } else {
976 w = query->stroke_width.computed;
977 }
978 {
979 gchar *str = g_strdup_printf(" %.3g", w);
980 _stroke_width.set_markup(str);
981 g_free (str);
982 }
983 {
984 gchar *str = g_strdup_printf(_("Stroke width: %.5g%s%s"),
985 w,
986 _sw_unit? sp_unit_get_abbreviation(_sw_unit) : "px",
987 (result_sw == QUERY_STYLE_MULTIPLE_AVERAGED)?
988 _(" (averaged)") : "");
989 _tooltips.set_tip(_stroke_width_place, str);
990 g_free (str);
991 }
992 break;
993 }
994 default:
995 break;
996 }
998 g_free (query);
999 }
1001 void SelectedStyle::opacity_0(void) {_opacity_sb.set_value(0);}
1002 void SelectedStyle::opacity_025(void) {_opacity_sb.set_value(0.25);}
1003 void SelectedStyle::opacity_05(void) {_opacity_sb.set_value(0.5);}
1004 void SelectedStyle::opacity_075(void) {_opacity_sb.set_value(0.75);}
1005 void SelectedStyle::opacity_1(void) {_opacity_sb.set_value(1.0);}
1007 void SelectedStyle::on_opacity_menu (Gtk::Menu *menu) {
1009 Glib::ListHandle<Gtk::Widget *> children = menu->get_children();
1010 for (Glib::ListHandle<Gtk::Widget *>::iterator iter = children.begin(); iter != children.end(); iter++) {
1011 menu->remove(*(*iter));
1012 }
1014 {
1015 Gtk::MenuItem *item = new Gtk::MenuItem;
1016 item->add(*(new Gtk::Label(_("0 (transparent)"), 0, 0)));
1017 item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_0 ));
1018 menu->add(*item);
1019 }
1020 {
1021 Gtk::MenuItem *item = new Gtk::MenuItem;
1022 item->add(*(new Gtk::Label("0.25", 0, 0)));
1023 item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_025 ));
1024 menu->add(*item);
1025 }
1026 {
1027 Gtk::MenuItem *item = new Gtk::MenuItem;
1028 item->add(*(new Gtk::Label("0.5", 0, 0)));
1029 item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_05 ));
1030 menu->add(*item);
1031 }
1032 {
1033 Gtk::MenuItem *item = new Gtk::MenuItem;
1034 item->add(*(new Gtk::Label("0.75", 0, 0)));
1035 item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_075 ));
1036 menu->add(*item);
1037 }
1038 {
1039 Gtk::MenuItem *item = new Gtk::MenuItem;
1040 item->add(*(new Gtk::Label(_("1.0 (opaque)"), 0, 0)));
1041 item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_1 ));
1042 menu->add(*item);
1043 }
1045 menu->show_all();
1046 }
1048 void SelectedStyle::on_opacity_changed () {
1049 if (_opacity_blocked)
1050 return;
1051 _opacity_blocked = true;
1052 SPCSSAttr *css = sp_repr_css_attr_new ();
1053 Inkscape::CSSOStringStream os;
1054 os << CLAMP (_opacity_adjustment.get_value(), 0.0, 1.0);
1055 sp_repr_css_set_property (css, "opacity", os.str().c_str());
1056 sp_desktop_set_style (_desktop, css);
1057 sp_repr_css_attr_unref (css);
1058 sp_document_maybe_done (sp_desktop_document (_desktop), "fillstroke:opacity");
1059 spinbutton_defocus(GTK_OBJECT(_opacity_sb.gobj()));
1060 _opacity_blocked = false;
1061 }
1063 } // namespace Widget
1064 } // namespace UI
1065 } // namespace Inkscape
1067 /*
1068 Local Variables:
1069 mode:c++
1070 c-file-style:"stroustrup"
1071 c-file-offsets:((innamespace . 0)(inline-open . 0))
1072 indent-tabs-mode:nil
1073 fill-column:99
1074 End:
1075 */
1076 // vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :