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"));
68 } else {
69 ss->setWatched (inkscape_get_repr(INKSCAPE, ss->_tool_path));
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 std::cout << " =============remove\n";
165 sp_repr_remove_listener_by_data(_watched_tool, this);
166 Inkscape::GC::release(_watched_tool);
167 _watched_tool = NULL;
168 _tool_path = NULL;
169 }
170 }
172 void
173 StyleSwatch::setWatched(Inkscape::XML::Node *watched)
174 {
175 if (_watched) {
176 sp_repr_remove_listener_by_data(_watched, this);
177 Inkscape::GC::release(_watched);
178 _watched = NULL;
179 }
181 if (watched) {
182 _watched = watched;
183 Inkscape::GC::anchor(_watched);
184 sp_repr_add_listener(_watched, &style_swatch_repr_events, this);
185 sp_repr_synthesize_events(_watched, &style_swatch_repr_events, this);
186 }
187 }
189 void
190 StyleSwatch::setWatchedTool(const char *path, bool synthesize)
191 {
192 if (_watched_tool) {
193 sp_repr_remove_listener_by_data(_watched_tool, this);
194 Inkscape::GC::release(_watched_tool);
195 _watched_tool = NULL;
196 _tool_path = NULL;
197 }
199 if (path) {
200 _tool_path = (char *) path;
201 Inkscape::XML::Node *watched_tool = inkscape_get_repr(INKSCAPE, path);
202 if (watched_tool) {
203 _watched_tool = watched_tool;
204 Inkscape::GC::anchor(_watched_tool);
205 sp_repr_add_listener(_watched_tool, &style_swatch_tool_repr_events, this);
206 if (synthesize) {
207 sp_repr_synthesize_events(_watched_tool, &style_swatch_tool_repr_events, this);
208 }
209 }
210 }
212 }
215 void
216 StyleSwatch::setStyle(SPCSSAttr *css)
217 {
218 if (_css)
219 sp_repr_css_attr_unref (_css);
221 if (!css)
222 return;
224 _css = sp_repr_css_attr_new();
225 sp_repr_css_merge(_css, css);
227 gchar const *css_string = sp_repr_css_write_string (_css);
228 SPStyle *temp_spstyle = sp_style_new();
229 if (css_string)
230 sp_style_merge_from_style_string (temp_spstyle, css_string);
232 setStyle (temp_spstyle);
234 sp_style_unref (temp_spstyle);
235 }
237 void
238 StyleSwatch::setStyle(SPStyle *query)
239 {
240 _place[SS_FILL].remove();
241 _place[SS_STROKE].remove();
243 bool has_stroke = true;
245 for (int i = SS_FILL; i <= SS_STROKE; i++) {
246 Gtk::EventBox *place = &(_place[i]);
248 SPIPaint *paint;
249 if (i == SS_FILL) {
250 paint = &(query->fill);
251 } else {
252 paint = &(query->stroke);
253 }
255 if (paint->set && paint->type == SP_PAINT_TYPE_COLOR) {
256 guint32 color = sp_color_get_rgba32_falpha (&(paint->value.color),
257 SP_SCALE24_TO_FLOAT ((i == SS_FILL)? query->fill_opacity.value : query->stroke_opacity.value));
258 ((Inkscape::UI::Widget::ColorPreview*)_color_preview[i])->setRgba32 (color);
259 _color_preview[i]->show_all();
260 place->add(*_color_preview[i]);
261 gchar *tip;
262 if (i == SS_FILL) {
263 tip = g_strdup_printf ("Fill: %06x/%.3g", color >> 8, SP_RGBA32_A_F(color));
264 } else {
265 tip = g_strdup_printf ("Stroke: %06x/%.3g", color >> 8, SP_RGBA32_A_F(color));
266 }
267 _tooltips.set_tip(*place, tip);
268 g_free (tip);
269 } else if (paint->set && paint->type == SP_PAINT_TYPE_PAINTSERVER) {
270 SPPaintServer *server = (i == SS_FILL)? SP_STYLE_FILL_SERVER (query) : SP_STYLE_STROKE_SERVER (query);
272 if (SP_IS_LINEARGRADIENT (server)) {
273 _value[i].set_markup(_("L Gradient"));
274 place->add(_value[i]);
275 _tooltips.set_tip(*place, (i == SS_FILL)? (_("Linear gradient fill")) : (_("Linear gradient stroke")));
276 } else if (SP_IS_RADIALGRADIENT (server)) {
277 _value[i].set_markup(_("R Gradient"));
278 place->add(_value[i]);
279 _tooltips.set_tip(*place, (i == SS_FILL)? (_("Radial gradient fill")) : (_("Radial gradient stroke")));
280 } else if (SP_IS_PATTERN (server)) {
281 _value[i].set_markup(_("Pattern"));
282 place->add(_value[i]);
283 _tooltips.set_tip(*place, (i == SS_FILL)? (_("Pattern fill")) : (_("Pattern stroke")));
284 }
286 } else if (paint->set && paint->type == SP_PAINT_TYPE_NONE) {
287 _value[i].set_markup(_("None"));
288 place->add(_value[i]);
289 _tooltips.set_tip(*place, (i == SS_FILL)? (_("No fill")) : (_("No stroke")));
290 if (i == SS_STROKE) has_stroke = false;
291 } else if (!paint->set) {
292 _value[i].set_markup(_("Unset"));
293 place->add(_value[i]);
294 _tooltips.set_tip(*place, (i == SS_FILL)? (_("Unset fill")) : (_("Unset stroke")));
295 if (i == SS_STROKE) has_stroke = false;
296 }
297 }
299 // Now query stroke_width
300 if (has_stroke) {
301 double w;
302 if (_sw_unit) {
303 w = sp_pixels_get_units(query->stroke_width.computed, *_sw_unit);
304 } else {
305 w = query->stroke_width.computed;
306 }
308 {
309 gchar *str = g_strdup_printf(" %.3g", w);
310 _stroke_width.set_markup(str);
311 g_free (str);
312 }
313 {
314 gchar *str = g_strdup_printf(_("Stroke width: %.5g%s"),
315 w,
316 _sw_unit? sp_unit_get_abbreviation(_sw_unit) : "px");
317 _tooltips.set_tip(_stroke_width_place, str);
318 g_free (str);
319 }
320 } else {
321 _tooltips.unset_tip(_stroke_width_place);
322 _stroke_width.set_markup ("");
323 }
325 gdouble op = SP_SCALE24_TO_FLOAT(query->opacity.value);
326 if (op != 1) {
327 {
328 gchar *str;
329 if (op == 0)
330 str = g_strdup_printf(_("0:%.3g"), op);
331 else
332 str = g_strdup_printf(_("0:.%d"), (int) (op*10));
333 _opacity_value.set_markup (str);
334 g_free (str);
335 }
336 {
337 gchar *str = g_strdup_printf(_("Opacity: %.3g"), op);
338 _tooltips.set_tip(_opacity_place, str);
339 g_free (str);
340 }
341 } else {
342 _tooltips.unset_tip(_opacity_place);
343 _opacity_value.set_markup ("");
344 }
346 show_all();
347 }
349 } // namespace Widget
350 } // namespace UI
351 } // namespace Inkscape
353 /*
354 Local Variables:
355 mode:c++
356 c-file-style:"stroustrup"
357 c-file-offsets:((innamespace . 0)(inline-open . 0))
358 indent-tabs-mode:nil
359 fill-column:99
360 End:
361 */
362 // vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :