Code

fix 1480934
[inkscape.git] / src / ui / widget / style-swatch.cpp
1 /**
2  * \brief Static style swatch (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 "style-swatch.h"
18 #include "widgets/spw-utilities.h"
19 #include "ui/widget/color-preview.h"
21 #include "style.h"
22 #include "sp-linear-gradient-fns.h"
23 #include "sp-radial-gradient-fns.h"
24 #include "sp-pattern.h"
25 #include "xml/repr.h"
26 #include "xml/node-event-vector.h"
27 #include "widgets/widget-sizes.h"
28 #include "helper/units.h"
29 #include "inkscape.h"
31 enum {
32     SS_FILL,
33     SS_STROKE
34 };
36 static void style_swatch_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
37                                        gchar const *old_value, gchar const *new_value,
38                                        bool is_interactive, gpointer data)
39 {
40     Inkscape::UI::Widget::StyleSwatch *ss = (Inkscape::UI::Widget::StyleSwatch *) data;
42     if (!strcmp (name, "style")) { // FIXME: watching only for the style attr, no CSS attrs
43         SPCSSAttr *css = sp_repr_css_attr_inherited(repr, "style");
44         ss->setStyle (css);
45     }
46 }
49 static Inkscape::XML::NodeEventVector style_swatch_repr_events =
50 {
51     NULL, /* child_added */
52     NULL, /* child_removed */
53     style_swatch_attr_changed,
54     NULL, /* content_changed */
55     NULL  /* order_changed */
56 };
59 static void style_swatch_tool_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
60                                        gchar const *old_value, gchar const *new_value,
61                                        bool is_interactive, gpointer data)
62 {
63     Inkscape::UI::Widget::StyleSwatch *ss = (Inkscape::UI::Widget::StyleSwatch *) data;
64  
65     if (!strcmp (name, "usecurrent")) { // FIXME: watching only for the style attr, no CSS attrs
66         if (!strcmp (new_value, "1")) {
67             ss->setWatched (inkscape_get_repr(INKSCAPE, "desktop"), inkscape_get_repr(INKSCAPE, ss->_tool_path));
68         } else {
69             ss->setWatched (inkscape_get_repr(INKSCAPE, ss->_tool_path), NULL);
70         }
71         // UGLY HACK: we have to reconnect to the watched tool repr again, retrieving it from the stored
72         // tool_path, because the actual repr keeps shifting with each change, no idea why
73         ss->setWatchedTool(ss->_tool_path, false); 
74     }
75 }
77 static Inkscape::XML::NodeEventVector style_swatch_tool_repr_events =
78 {
79     NULL, /* child_added */
80     NULL, /* child_removed */
81     style_swatch_tool_attr_changed,
82     NULL, /* content_changed */
83     NULL  /* order_changed */
84 };
86 namespace Inkscape {
87 namespace UI {
88 namespace Widget {
90 StyleSwatch::StyleSwatch(SPCSSAttr *css)
91     : 
92       _tool_path(NULL),
93       _css (NULL),
95       _watched(NULL),
96       _watched_tool(NULL),
98       _table(2, 6),
100       _sw_unit(NULL),
102       _tooltips ()
104     _label[SS_FILL].set_markup(_("F:"));
105     _label[SS_STROKE].set_markup(_("S:"));
107     for (int i = SS_FILL; i <= SS_STROKE; i++) {
108         _label[i].set_alignment(0.0, 0.5);
109         _label[i].set_padding(0, 0);
111         _color_preview[i] = new Inkscape::UI::Widget::ColorPreview (0);
112     }
114     _opacity_value.set_alignment(0.0, 0.5);
115     _opacity_value.set_padding(0, 0);
117     _table.set_col_spacings (2);
118     _table.set_row_spacings (0);
120     _stroke.pack_start(_place[SS_STROKE]);
121     _stroke_width_place.add(_stroke_width);
122     _stroke.pack_start(_stroke_width_place, Gtk::PACK_SHRINK);
124     _table.attach(_label[SS_FILL], 0,1, 0,1, Gtk::SHRINK, Gtk::SHRINK);
125     _table.attach(_label[SS_STROKE], 0,1, 1,2, Gtk::SHRINK, Gtk::SHRINK);
127     _table.attach(_place[SS_FILL], 1,2, 0,1);
128     _table.attach(_stroke, 1,2, 1,2);
130     _opacity_place.add(_opacity_value);
131     _table.attach(_opacity_place, 2,3, 0,2, Gtk::SHRINK, Gtk::SHRINK);
133     pack_start(_table, true, true, 0);
135     set_size_request (STYLE_SWATCH_WIDTH, -1);
137     sp_set_font_size_smaller (GTK_WIDGET(_opacity_value.gobj()));
138     sp_set_font_size_smaller (GTK_WIDGET(_stroke_width.gobj()));
139     for (int i = SS_FILL; i <= SS_STROKE; i++) {
140         sp_set_font_size_smaller (GTK_WIDGET(_value[i].gobj()));
141         sp_set_font_size_smaller (GTK_WIDGET(_place[i].gobj()));
142         sp_set_font_size_smaller (GTK_WIDGET(_label[i].gobj()));
143     }
145     setStyle (css);
148 StyleSwatch::~StyleSwatch()
150     if (_css) 
151         sp_repr_css_attr_unref (_css);
153     for (int i = SS_FILL; i <= SS_STROKE; i++) {
154         delete _color_preview[i];
155     }
157     if (_watched) {
158         sp_repr_remove_listener_by_data(_watched, this);
159         Inkscape::GC::release(_watched);
160         _watched = NULL;
161     }
163     if (_watched_tool) {
164         sp_repr_remove_listener_by_data(_watched_tool, this);
165         Inkscape::GC::release(_watched_tool);
166         _watched_tool = NULL;
167         _tool_path = NULL;
168     }
171 void
172 StyleSwatch::setWatched(Inkscape::XML::Node *watched, Inkscape::XML::Node *secondary)
174     if (_watched) {
175         sp_repr_remove_listener_by_data(_watched, this);
176         Inkscape::GC::release(_watched);
177         _watched = NULL;
178     }
180     if (watched) {
181         _watched = watched;
182         Inkscape::GC::anchor(_watched);
183         sp_repr_add_listener(_watched, &style_swatch_repr_events, this);
184         sp_repr_synthesize_events(_watched, &style_swatch_repr_events, this);
186         // If desktop's last-set style is empty, a tool uses its own fixed style even if set to use
187         // last-set (so long as it's empty). To correctly show this, we're passed the second repr,
188         // that of the tool prefs node, from which we now setStyle if the watched repr's style is
189         // empty.
190         if (secondary) {
191             SPCSSAttr *css = sp_repr_css_attr_inherited(watched, "style");
192             if (!css->attributeList()) { // is css empty?
193                 SPCSSAttr *css_secondary = sp_repr_css_attr_inherited(secondary, "style");
194                 this->setStyle (css_secondary);
195             }
196         }
197     }
200 void
201 StyleSwatch::setWatchedTool(const char *path, bool synthesize)
203     if (_watched_tool) {
204         sp_repr_remove_listener_by_data(_watched_tool, this);
205         Inkscape::GC::release(_watched_tool);
206         _watched_tool = NULL;
207         _tool_path = NULL;
208     }
210     if (path) {
211         _tool_path = (char *) path;
212         Inkscape::XML::Node *watched_tool = inkscape_get_repr(INKSCAPE, path);
213         if (watched_tool) {
214             _watched_tool = watched_tool;
215             Inkscape::GC::anchor(_watched_tool);
216             sp_repr_add_listener(_watched_tool, &style_swatch_tool_repr_events, this);
217             if (synthesize) {
218                 sp_repr_synthesize_events(_watched_tool, &style_swatch_tool_repr_events, this);
219             }
220         }
221     }
226 void
227 StyleSwatch::setStyle(SPCSSAttr *css)
229     if (_css) 
230         sp_repr_css_attr_unref (_css);
232     if (!css)
233         return;
235     _css = sp_repr_css_attr_new();
236     sp_repr_css_merge(_css, css);
238     gchar const *css_string = sp_repr_css_write_string (_css);
239     SPStyle *temp_spstyle = sp_style_new();
240     if (css_string)
241         sp_style_merge_from_style_string (temp_spstyle, css_string);
243     setStyle (temp_spstyle);
245     sp_style_unref (temp_spstyle);
248 void
249 StyleSwatch::setStyle(SPStyle *query)
251     _place[SS_FILL].remove();
252     _place[SS_STROKE].remove();
254     bool has_stroke = true;
256     for (int i = SS_FILL; i <= SS_STROKE; i++) {
257         Gtk::EventBox *place = &(_place[i]);
259         SPIPaint *paint;
260         if (i == SS_FILL) {
261             paint = &(query->fill);
262         } else {
263             paint = &(query->stroke);
264         }
266         if (paint->set && paint->type == SP_PAINT_TYPE_COLOR) {
267             guint32 color = sp_color_get_rgba32_falpha (&(paint->value.color), 
268                                                         SP_SCALE24_TO_FLOAT ((i == SS_FILL)? query->fill_opacity.value : query->stroke_opacity.value));
269             ((Inkscape::UI::Widget::ColorPreview*)_color_preview[i])->setRgba32 (color);
270             _color_preview[i]->show_all();
271             place->add(*_color_preview[i]);
272             gchar *tip;
273             if (i == SS_FILL) {
274                 tip = g_strdup_printf ("Fill: %06x/%.3g", color >> 8, SP_RGBA32_A_F(color));
275             } else {
276                 tip = g_strdup_printf ("Stroke: %06x/%.3g", color >> 8, SP_RGBA32_A_F(color));
277             }
278             _tooltips.set_tip(*place, tip);
279             g_free (tip);
280         } else if (paint->set && paint->type == SP_PAINT_TYPE_PAINTSERVER) {
281             SPPaintServer *server = (i == SS_FILL)? SP_STYLE_FILL_SERVER (query) : SP_STYLE_STROKE_SERVER (query);
283             if (SP_IS_LINEARGRADIENT (server)) {
284                 _value[i].set_markup(_("L Gradient"));
285                 place->add(_value[i]);
286                 _tooltips.set_tip(*place, (i == SS_FILL)? (_("Linear gradient fill")) : (_("Linear gradient stroke")));
287             } else if (SP_IS_RADIALGRADIENT (server)) {
288                 _value[i].set_markup(_("R Gradient"));
289                 place->add(_value[i]);
290                 _tooltips.set_tip(*place, (i == SS_FILL)? (_("Radial gradient fill")) : (_("Radial gradient stroke")));
291             } else if (SP_IS_PATTERN (server)) {
292                 _value[i].set_markup(_("Pattern"));
293                 place->add(_value[i]);
294                 _tooltips.set_tip(*place, (i == SS_FILL)? (_("Pattern fill")) : (_("Pattern stroke")));
295             }
297         } else if (paint->set && paint->type == SP_PAINT_TYPE_NONE) {
298             _value[i].set_markup(_("None"));
299             place->add(_value[i]);
300             _tooltips.set_tip(*place, (i == SS_FILL)? (_("No fill")) : (_("No stroke")));
301             if (i == SS_STROKE) has_stroke = false;
302         } else if (!paint->set) {
303             _value[i].set_markup(_("Unset"));
304             place->add(_value[i]);
305             _tooltips.set_tip(*place, (i == SS_FILL)? (_("Unset fill")) : (_("Unset stroke")));
306             if (i == SS_STROKE) has_stroke = false;
307         }
308     }
310 // Now query stroke_width
311     if (has_stroke) {
312         double w;
313         if (_sw_unit) {
314             w = sp_pixels_get_units(query->stroke_width.computed, *_sw_unit);
315         } else {
316             w = query->stroke_width.computed;
317         }
319         {
320             gchar *str = g_strdup_printf(" %.3g", w);
321             _stroke_width.set_markup(str);
322             g_free (str);
323         }
324         {
325             gchar *str = g_strdup_printf(_("Stroke width: %.5g%s"), 
326                                          w, 
327                                          _sw_unit? sp_unit_get_abbreviation(_sw_unit) : "px");
328             _tooltips.set_tip(_stroke_width_place, str);
329             g_free (str);
330         }
331     } else {
332         _tooltips.unset_tip(_stroke_width_place);
333         _stroke_width.set_markup ("");
334     }
336     gdouble op = SP_SCALE24_TO_FLOAT(query->opacity.value);
337     if (op != 1) {
338         {
339             gchar *str;
340             if (op == 0)
341                 str = g_strdup_printf(_("0:%.3g"), op);
342             else 
343                 str = g_strdup_printf(_("0:.%d"), (int) (op*10));
344             _opacity_value.set_markup (str);
345             g_free (str);
346         }
347         {
348             gchar *str = g_strdup_printf(_("Opacity: %.3g"), op);
349             _tooltips.set_tip(_opacity_place, str);
350             g_free (str);
351         }
352     } else {
353         _tooltips.unset_tip(_opacity_place);
354         _opacity_value.set_markup ("");
355     }
357     show_all();
360 } // namespace Widget
361 } // namespace UI
362 } // namespace Inkscape
364 /* 
365   Local Variables:
366   mode:c++
367   c-file-style:"stroustrup"
368   c-file-offsets:((innamespace . 0)(inline-open . 0))
369   indent-tabs-mode:nil
370   fill-column:99
371   End:
372 */
373 // vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :