Code

cad07fbd6ed3435cb6b87e2e31baf3a50152357c
[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 "helper/action.h"
30 #include "inkscape.h"
32 enum {
33     SS_FILL,
34     SS_STROKE
35 };
37 static void style_swatch_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
38                                        gchar const *old_value, gchar const *new_value,
39                                        bool is_interactive, gpointer data)
40 {
41     Inkscape::UI::Widget::StyleSwatch *ss = (Inkscape::UI::Widget::StyleSwatch *) data;
43     if (!strcmp (name, "style")) { // FIXME: watching only for the style attr, no CSS attrs
44         SPCSSAttr *css = sp_repr_css_attr_inherited(repr, "style");
45         ss->setStyle (css);
46     }
47 }
50 static Inkscape::XML::NodeEventVector style_swatch_repr_events =
51 {
52     NULL, /* child_added */
53     NULL, /* child_removed */
54     style_swatch_attr_changed,
55     NULL, /* content_changed */
56     NULL  /* order_changed */
57 };
60 static void style_swatch_tool_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
61                                        gchar const *old_value, gchar const *new_value,
62                                        bool is_interactive, gpointer data)
63 {
64     Inkscape::UI::Widget::StyleSwatch *ss = (Inkscape::UI::Widget::StyleSwatch *) data;
65  
66     if (!strcmp (name, "usecurrent")) { // FIXME: watching only for the style attr, no CSS attrs
67         if (!strcmp (new_value, "1")) {
68             ss->setWatched (inkscape_get_repr(INKSCAPE, "desktop"), inkscape_get_repr(INKSCAPE, ss->_tool_path));
69         } else {
70             ss->setWatched (inkscape_get_repr(INKSCAPE, ss->_tool_path), NULL);
71         }
72         // UGLY HACK: we have to reconnect to the watched tool repr again, retrieving it from the stored
73         // tool_path, because the actual repr keeps shifting with each change, no idea why
74         ss->setWatchedTool(ss->_tool_path, false); 
75     }
76 }
78 static Inkscape::XML::NodeEventVector style_swatch_tool_repr_events =
79 {
80     NULL, /* child_added */
81     NULL, /* child_removed */
82     style_swatch_tool_attr_changed,
83     NULL, /* content_changed */
84     NULL  /* order_changed */
85 };
87 namespace Inkscape {
88 namespace UI {
89 namespace Widget {
91 StyleSwatch::StyleSwatch(SPCSSAttr *css, gchar const *main_tip)
92     : 
93       _tool_path(NULL),
94       _css (NULL),
96       _watched(NULL),
97       _watched_tool(NULL),
99       _table(2, 6),
101       _sw_unit(NULL),
103       _tooltips ()
105     _label[SS_FILL].set_markup(_("Fill:"));
106     _label[SS_STROKE].set_markup(_("Stroke:"));
108     for (int i = SS_FILL; i <= SS_STROKE; i++) {
109         _label[i].set_alignment(0.0, 0.5);
110         _label[i].set_padding(0, 0);
112         _color_preview[i] = new Inkscape::UI::Widget::ColorPreview (0);
113     }
115     _opacity_value.set_alignment(0.0, 0.5);
116     _opacity_value.set_padding(0, 0);
118     _table.set_col_spacings (2);
119     _table.set_row_spacings (0);
121     _stroke.pack_start(_place[SS_STROKE]);
122     _stroke_width_place.add(_stroke_width);
123     _stroke.pack_start(_stroke_width_place, Gtk::PACK_SHRINK);
125     _table.attach(_label[SS_FILL], 0,1, 0,1, Gtk::FILL, Gtk::SHRINK);
126     _table.attach(_label[SS_STROKE], 0,1, 1,2, Gtk::FILL, Gtk::SHRINK);
128     _table.attach(_place[SS_FILL], 1,2, 0,1);
129     _table.attach(_stroke, 1,2, 1,2);
131     _opacity_place.add(_opacity_value);
132     _table.attach(_opacity_place, 2,3, 0,2, Gtk::SHRINK, Gtk::SHRINK);
134     _swatch.add(_table);
135     pack_start(_swatch, true, true, 0);
137     set_size_request (STYLE_SWATCH_WIDTH, -1);
139     sp_set_font_size_smaller (GTK_WIDGET(_opacity_value.gobj()));
140     sp_set_font_size_smaller (GTK_WIDGET(_stroke_width.gobj()));
141     for (int i = SS_FILL; i <= SS_STROKE; i++) {
142         sp_set_font_size_smaller (GTK_WIDGET(_value[i].gobj()));
143         sp_set_font_size_smaller (GTK_WIDGET(_place[i].gobj()));
144         sp_set_font_size_smaller (GTK_WIDGET(_label[i].gobj()));
145     }
147     setStyle (css);
149     _swatch.signal_button_press_event().connect(sigc::mem_fun(*this, &StyleSwatch::on_click));
151     _tooltips.set_tip(_swatch, main_tip);
154 void StyleSwatch::setClickVerb(sp_verb_t verb_t) {
155     _verb_t = verb_t;
158 void StyleSwatch::setDesktop(SPDesktop *desktop) {
159     _desktop = desktop;
162 bool 
163 StyleSwatch::on_click(GdkEventButton *event)
165     if (this->_desktop && this->_verb_t != SP_VERB_NONE) {
166         Inkscape::Verb *verb = Inkscape::Verb::get(this->_verb_t);
167         SPAction *action = verb->get_action((Inkscape::UI::View::View *) this->_desktop);
168         sp_action_perform (action, NULL);
169         return true;
170     }
171     return false;
174 StyleSwatch::~StyleSwatch()
176     if (_css) 
177         sp_repr_css_attr_unref (_css);
179     for (int i = SS_FILL; i <= SS_STROKE; i++) {
180         delete _color_preview[i];
181     }
183     if (_watched) {
184         sp_repr_remove_listener_by_data(_watched, this);
185         Inkscape::GC::release(_watched);
186         _watched = NULL;
187     }
189     if (_watched_tool) {
190         sp_repr_remove_listener_by_data(_watched_tool, this);
191         Inkscape::GC::release(_watched_tool);
192         _watched_tool = NULL;
193         _tool_path = NULL;
194     }
197 void
198 StyleSwatch::setWatched(Inkscape::XML::Node *watched, Inkscape::XML::Node *secondary)
200     if (_watched) {
201         sp_repr_remove_listener_by_data(_watched, this);
202         Inkscape::GC::release(_watched);
203         _watched = NULL;
204     }
206     if (watched) {
207         _watched = watched;
208         Inkscape::GC::anchor(_watched);
209         sp_repr_add_listener(_watched, &style_swatch_repr_events, this);
210         sp_repr_synthesize_events(_watched, &style_swatch_repr_events, this);
212         // If desktop's last-set style is empty, a tool uses its own fixed style even if set to use
213         // last-set (so long as it's empty). To correctly show this, we're passed the second repr,
214         // that of the tool prefs node, from which we now setStyle if the watched repr's style is
215         // empty.
216         if (secondary) {
217             SPCSSAttr *css = sp_repr_css_attr_inherited(watched, "style");
218             if (!css->attributeList()) { // is css empty?
219                 SPCSSAttr *css_secondary = sp_repr_css_attr_inherited(secondary, "style");
220                 this->setStyle (css_secondary);
221             }
222         }
223     }
226 void
227 StyleSwatch::setWatchedTool(const char *path, bool synthesize)
229     if (_watched_tool) {
230         sp_repr_remove_listener_by_data(_watched_tool, this);
231         Inkscape::GC::release(_watched_tool);
232         _watched_tool = NULL;
233         _tool_path = NULL;
234     }
236     if (path) {
237         _tool_path = (char *) path;
238         Inkscape::XML::Node *watched_tool = inkscape_get_repr(INKSCAPE, path);
239         if (watched_tool) {
240             _watched_tool = watched_tool;
241             Inkscape::GC::anchor(_watched_tool);
242             sp_repr_add_listener(_watched_tool, &style_swatch_tool_repr_events, this);
243             if (synthesize) {
244                 sp_repr_synthesize_events(_watched_tool, &style_swatch_tool_repr_events, this);
245             }
246         }
247     }
252 void
253 StyleSwatch::setStyle(SPCSSAttr *css)
255     if (_css) 
256         sp_repr_css_attr_unref (_css);
258     if (!css)
259         return;
261     _css = sp_repr_css_attr_new();
262     sp_repr_css_merge(_css, css);
264     gchar const *css_string = sp_repr_css_write_string (_css);
265     SPStyle *temp_spstyle = sp_style_new(SP_ACTIVE_DOCUMENT);
266     if (css_string)
267         sp_style_merge_from_style_string (temp_spstyle, css_string);
269     setStyle (temp_spstyle);
271     sp_style_unref (temp_spstyle);
274 void
275 StyleSwatch::setStyle(SPStyle *query)
277     _place[SS_FILL].remove();
278     _place[SS_STROKE].remove();
280     bool has_stroke = true;
282     for (int i = SS_FILL; i <= SS_STROKE; i++) {
283         Gtk::EventBox *place = &(_place[i]);
285         SPIPaint *paint;
286         if (i == SS_FILL) {
287             paint = &(query->fill);
288         } else {
289             paint = &(query->stroke);
290         }
292         if (paint->set && paint->type == SP_PAINT_TYPE_COLOR) {
293             guint32 color = sp_color_get_rgba32_falpha (&(paint->value.color), 
294                                                         SP_SCALE24_TO_FLOAT ((i == SS_FILL)? query->fill_opacity.value : query->stroke_opacity.value));
295             ((Inkscape::UI::Widget::ColorPreview*)_color_preview[i])->setRgba32 (color);
296             _color_preview[i]->show_all();
297             place->add(*_color_preview[i]);
298             gchar *tip;
299             if (i == SS_FILL) {
300                 tip = g_strdup_printf (_("Fill: %06x/%.3g"), color >> 8, SP_RGBA32_A_F(color));
301             } else {
302                 tip = g_strdup_printf (_("Stroke: %06x/%.3g"), color >> 8, SP_RGBA32_A_F(color));
303             }
304             _tooltips.set_tip(*place, tip);
305             g_free (tip);
306         } else if (paint->set && paint->type == SP_PAINT_TYPE_PAINTSERVER) {
307             SPPaintServer *server = (i == SS_FILL)? SP_STYLE_FILL_SERVER (query) : SP_STYLE_STROKE_SERVER (query);
309             if (SP_IS_LINEARGRADIENT (server)) {
310                 _value[i].set_markup(_("L Gradient"));
311                 place->add(_value[i]);
312                 _tooltips.set_tip(*place, (i == SS_FILL)? (_("Linear gradient fill")) : (_("Linear gradient stroke")));
313             } else if (SP_IS_RADIALGRADIENT (server)) {
314                 _value[i].set_markup(_("R Gradient"));
315                 place->add(_value[i]);
316                 _tooltips.set_tip(*place, (i == SS_FILL)? (_("Radial gradient fill")) : (_("Radial gradient stroke")));
317             } else if (SP_IS_PATTERN (server)) {
318                 _value[i].set_markup(_("Pattern"));
319                 place->add(_value[i]);
320                 _tooltips.set_tip(*place, (i == SS_FILL)? (_("Pattern fill")) : (_("Pattern stroke")));
321             }
323         } else if (paint->set && paint->type == SP_PAINT_TYPE_NONE) {
324             _value[i].set_markup(_("<i>None</i>"));
325             place->add(_value[i]);
326             _tooltips.set_tip(*place, (i == SS_FILL)? (_("No fill")) : (_("No stroke")));
327             if (i == SS_STROKE) has_stroke = false;
328         } else if (!paint->set) {
329             _value[i].set_markup(_("<b>Unset</b>"));
330             place->add(_value[i]);
331             _tooltips.set_tip(*place, (i == SS_FILL)? (_("Unset fill")) : (_("Unset stroke")));
332             if (i == SS_STROKE) has_stroke = false;
333         }
334     }
336 // Now query stroke_width
337     if (has_stroke) {
338         double w;
339         if (_sw_unit) {
340             w = sp_pixels_get_units(query->stroke_width.computed, *_sw_unit);
341         } else {
342             w = query->stroke_width.computed;
343         }
345         {
346             gchar *str = g_strdup_printf(" %.3g", w);
347             _stroke_width.set_markup(str);
348             g_free (str);
349         }
350         {
351             gchar *str = g_strdup_printf(_("Stroke width: %.5g%s"), 
352                                          w, 
353                                          _sw_unit? sp_unit_get_abbreviation(_sw_unit) : "px");
354             _tooltips.set_tip(_stroke_width_place, str);
355             g_free (str);
356         }
357     } else {
358         _tooltips.unset_tip(_stroke_width_place);
359         _stroke_width.set_markup ("");
360     }
362     gdouble op = SP_SCALE24_TO_FLOAT(query->opacity.value);
363     if (op != 1) {
364         {
365             gchar *str;
366             if (op == 0)
367                 str = g_strdup_printf(_("O:%.3g"), op);
368             else 
369                 str = g_strdup_printf(_("O:.%d"), (int) (op*10));
370             _opacity_value.set_markup (str);
371             g_free (str);
372         }
373         {
374             gchar *str = g_strdup_printf(_("Opacity: %.3g"), op);
375             _tooltips.set_tip(_opacity_place, str);
376             g_free (str);
377         }
378     } else {
379         _tooltips.unset_tip(_opacity_place);
380         _opacity_value.set_markup ("");
381     }
383     show_all();
386 } // namespace Widget
387 } // namespace UI
388 } // namespace Inkscape
390 /* 
391   Local Variables:
392   mode:c++
393   c-file-style:"stroustrup"
394   c-file-offsets:((innamespace . 0)(inline-open . 0))
395   indent-tabs-mode:nil
396   fill-column:99
397   End:
398 */
399 // vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :