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;
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 ()
103 {
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);
146 }
148 StyleSwatch::~StyleSwatch()
149 {
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 }
169 }
171 void
172 StyleSwatch::setWatched(Inkscape::XML::Node *watched, Inkscape::XML::Node *secondary)
173 {
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 }
198 }
200 void
201 StyleSwatch::setWatchedTool(const char *path, bool synthesize)
202 {
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 }
223 }
226 void
227 StyleSwatch::setStyle(SPCSSAttr *css)
228 {
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);
246 }
248 void
249 StyleSwatch::setStyle(SPStyle *query)
250 {
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(_("<i>None</i>"));
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(_("<b>Unset</b>"));
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(_("O:%.3g"), op);
342 else
343 str = g_strdup_printf(_("O:.%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();
358 }
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 :