Code

Implement cross-architecture print dialog using cairo and PNG backends.
[inkscape.git] / src / ui / widget / style-swatch.cpp
index 5d4623c194972ca60225b341651352cdd5426afd..e5e8d5d78065738fa43b7625118c983c55f3aab0 100644 (file)
 #include "sp-radial-gradient-fns.h"
 #include "sp-pattern.h"
 #include "xml/repr.h"
+#include "xml/node-event-vector.h"
 #include "widgets/widget-sizes.h"
 #include "helper/units.h"
+#include "helper/action.h"
+#include "inkscape.h"
 
 enum {
     SS_FILL,
     SS_STROKE
 };
 
+static void style_swatch_attr_changed( Inkscape::XML::Node *repr, gchar const *name,
+                                       gchar const */*old_value*/, gchar const */*new_value*/,
+                                       bool /*is_interactive*/, gpointer data)
+{
+    Inkscape::UI::Widget::StyleSwatch *ss = (Inkscape::UI::Widget::StyleSwatch *) data;
+
+    if (!strcmp (name, "style")) { // FIXME: watching only for the style attr, no CSS attrs
+        SPCSSAttr *css = sp_repr_css_attr_inherited(repr, "style");
+        ss->setStyle (css);
+    }
+}
+
+
+static Inkscape::XML::NodeEventVector style_swatch_repr_events =
+{
+    NULL, /* child_added */
+    NULL, /* child_removed */
+    style_swatch_attr_changed,
+    NULL, /* content_changed */
+    NULL  /* order_changed */
+};
+
+
+static void style_swatch_tool_attr_changed( Inkscape::XML::Node */*repr*/, gchar const *name,
+                                            gchar const */*old_value*/, gchar const *new_value,
+                                            bool /*is_interactive*/, gpointer data)
+{
+    Inkscape::UI::Widget::StyleSwatch *ss = (Inkscape::UI::Widget::StyleSwatch *) data;
+
+    if (!strcmp (name, "usecurrent")) { // FIXME: watching only for the style attr, no CSS attrs
+        if (!strcmp (new_value, "1")) {
+            ss->setWatched (inkscape_get_repr(INKSCAPE, "desktop"), inkscape_get_repr(INKSCAPE, ss->_tool_path));
+        } else {
+            ss->setWatched (inkscape_get_repr(INKSCAPE, ss->_tool_path), NULL);
+        }
+        // UGLY HACK: we have to reconnect to the watched tool repr again, retrieving it from the stored
+        // tool_path, because the actual repr keeps shifting with each change, no idea why
+        ss->setWatchedTool(ss->_tool_path, false);
+    }
+}
+
+static Inkscape::XML::NodeEventVector style_swatch_tool_repr_events =
+{
+    NULL, /* child_added */
+    NULL, /* child_removed */
+    style_swatch_tool_attr_changed,
+    NULL, /* content_changed */
+    NULL  /* order_changed */
+};
 
 namespace Inkscape {
 namespace UI {
 namespace Widget {
 
-StyleSwatch::StyleSwatch(SPCSSAttr *css)
-    : _css (NULL),
+StyleSwatch::StyleSwatch(SPCSSAttr *css, gchar const *main_tip)
+    :
+      _tool_path(NULL),
+      _css (NULL),
+
+      _watched(NULL),
+      _watched_tool(NULL),
 
       _table(2, 6),
 
@@ -45,8 +102,8 @@ StyleSwatch::StyleSwatch(SPCSSAttr *css)
 
       _tooltips ()
 {
-    _label[SS_FILL].set_markup(_("F:"));
-    _label[SS_STROKE].set_markup(_("S:"));
+    _label[SS_FILL].set_markup(_("Fill:"));
+    _label[SS_STROKE].set_markup(_("Stroke:"));
 
     for (int i = SS_FILL; i <= SS_STROKE; i++) {
         _label[i].set_alignment(0.0, 0.5);
@@ -65,8 +122,8 @@ StyleSwatch::StyleSwatch(SPCSSAttr *css)
     _stroke_width_place.add(_stroke_width);
     _stroke.pack_start(_stroke_width_place, Gtk::PACK_SHRINK);
 
-    _table.attach(_label[SS_FILL], 0,1, 0,1, Gtk::SHRINK, Gtk::SHRINK);
-    _table.attach(_label[SS_STROKE], 0,1, 1,2, Gtk::SHRINK, Gtk::SHRINK);
+    _table.attach(_label[SS_FILL], 0,1, 0,1, Gtk::FILL, Gtk::SHRINK);
+    _table.attach(_label[SS_STROKE], 0,1, 1,2, Gtk::FILL, Gtk::SHRINK);
 
     _table.attach(_place[SS_FILL], 1,2, 0,1);
     _table.attach(_stroke, 1,2, 1,2);
@@ -74,7 +131,8 @@ StyleSwatch::StyleSwatch(SPCSSAttr *css)
     _opacity_place.add(_opacity_value);
     _table.attach(_opacity_place, 2,3, 0,2, Gtk::SHRINK, Gtk::SHRINK);
 
-    pack_start(_table, true, true, 0);
+    _swatch.add(_table);
+    pack_start(_swatch, true, true, 0);
 
     set_size_request (STYLE_SWATCH_WIDTH, -1);
 
@@ -87,29 +145,126 @@ StyleSwatch::StyleSwatch(SPCSSAttr *css)
     }
 
     setStyle (css);
+
+    _swatch.signal_button_press_event().connect(sigc::mem_fun(*this, &StyleSwatch::on_click));
+
+    _tooltips.set_tip(_swatch, main_tip);
+}
+
+void StyleSwatch::setClickVerb(sp_verb_t verb_t) {
+    _verb_t = verb_t;
+}
+
+void StyleSwatch::setDesktop(SPDesktop *desktop) {
+    _desktop = desktop;
+}
+
+bool
+StyleSwatch::on_click(GdkEventButton */*event*/)
+{
+    if (this->_desktop && this->_verb_t != SP_VERB_NONE) {
+        Inkscape::Verb *verb = Inkscape::Verb::get(this->_verb_t);
+        SPAction *action = verb->get_action((Inkscape::UI::View::View *) this->_desktop);
+        sp_action_perform (action, NULL);
+        return true;
+    }
+    return false;
 }
 
 StyleSwatch::~StyleSwatch()
 {
-    if (_css) 
+    if (_css)
         sp_repr_css_attr_unref (_css);
 
     for (int i = SS_FILL; i <= SS_STROKE; i++) {
         delete _color_preview[i];
     }
+
+    if (_watched) {
+        sp_repr_remove_listener_by_data(_watched, this);
+        Inkscape::GC::release(_watched);
+        _watched = NULL;
+    }
+
+    if (_watched_tool) {
+        sp_repr_remove_listener_by_data(_watched_tool, this);
+        Inkscape::GC::release(_watched_tool);
+        _watched_tool = NULL;
+        _tool_path = NULL;
+    }
+}
+
+void
+StyleSwatch::setWatched(Inkscape::XML::Node *watched, Inkscape::XML::Node *secondary)
+{
+    if (_watched) {
+        sp_repr_remove_listener_by_data(_watched, this);
+        Inkscape::GC::release(_watched);
+        _watched = NULL;
+    }
+
+    if (watched) {
+        _watched = watched;
+        Inkscape::GC::anchor(_watched);
+        sp_repr_add_listener(_watched, &style_swatch_repr_events, this);
+        sp_repr_synthesize_events(_watched, &style_swatch_repr_events, this);
+
+        // If desktop's last-set style is empty, a tool uses its own fixed style even if set to use
+        // last-set (so long as it's empty). To correctly show this, we're passed the second repr,
+        // that of the tool prefs node, from which we now setStyle if the watched repr's style is
+        // empty.
+        if (secondary) {
+            SPCSSAttr *css = sp_repr_css_attr_inherited(watched, "style");
+            if (!css->attributeList()) { // is css empty?
+                SPCSSAttr *css_secondary = sp_repr_css_attr_inherited(secondary, "style");
+                this->setStyle (css_secondary);
+            }
+        }
+    }
 }
 
+void
+StyleSwatch::setWatchedTool(const char *path, bool synthesize)
+{
+    if (_watched_tool) {
+        sp_repr_remove_listener_by_data(_watched_tool, this);
+        Inkscape::GC::release(_watched_tool);
+        _watched_tool = NULL;
+        _tool_path = NULL;
+    }
+
+    if (path) {
+        _tool_path = (char *) path;
+        Inkscape::XML::Node *watched_tool = inkscape_get_repr(INKSCAPE, path);
+        if (watched_tool) {
+            _watched_tool = watched_tool;
+            Inkscape::GC::anchor(_watched_tool);
+            sp_repr_add_listener(_watched_tool, &style_swatch_tool_repr_events, this);
+            if (synthesize) {
+                sp_repr_synthesize_events(_watched_tool, &style_swatch_tool_repr_events, this);
+            }
+        }
+    }
+
+}
+
+
 void
 StyleSwatch::setStyle(SPCSSAttr *css)
 {
-    if (_css) 
+    if (_css)
         sp_repr_css_attr_unref (_css);
+
+    if (!css)
+        return;
+
     _css = sp_repr_css_attr_new();
     sp_repr_css_merge(_css, css);
 
     gchar const *css_string = sp_repr_css_write_string (_css);
-    SPStyle *temp_spstyle = sp_style_new();
-    sp_style_merge_from_style_string (temp_spstyle, css_string);
+    SPStyle *temp_spstyle = sp_style_new(SP_ACTIVE_DOCUMENT);
+    if (css_string)
+        sp_style_merge_from_style_string (temp_spstyle, css_string);
 
     setStyle (temp_spstyle);
 
@@ -134,21 +289,7 @@ StyleSwatch::setStyle(SPStyle *query)
             paint = &(query->stroke);
         }
 
-        if (paint->set && paint->type == SP_PAINT_TYPE_COLOR) {
-            guint32 color = sp_color_get_rgba32_falpha (&(paint->value.color), 
-                                                        SP_SCALE24_TO_FLOAT ((i == SS_FILL)? query->fill_opacity.value : query->stroke_opacity.value));
-            ((Inkscape::UI::Widget::ColorPreview*)_color_preview[i])->setRgba32 (color);
-            _color_preview[i]->show_all();
-            place->add(*_color_preview[i]);
-            gchar *tip;
-            if (i == SS_FILL) {
-                tip = g_strdup_printf ("Fill: %06x/%.3g", color >> 8, SP_RGBA32_A_F(color));
-            } else {
-                tip = g_strdup_printf ("Stroke: %06x/%.3g", color >> 8, SP_RGBA32_A_F(color));
-            }
-            _tooltips.set_tip(*place, tip);
-            g_free (tip);
-        } else if (paint->set && paint->type == SP_PAINT_TYPE_PAINTSERVER) {
+        if (paint->set && paint->isPaintserver()) {
             SPPaintServer *server = (i == SS_FILL)? SP_STYLE_FILL_SERVER (query) : SP_STYLE_STROKE_SERVER (query);
 
             if (SP_IS_LINEARGRADIENT (server)) {
@@ -165,13 +306,26 @@ StyleSwatch::setStyle(SPStyle *query)
                 _tooltips.set_tip(*place, (i == SS_FILL)? (_("Pattern fill")) : (_("Pattern stroke")));
             }
 
-        } else if (paint->set && paint->type == SP_PAINT_TYPE_NONE) {
-            _value[i].set_markup(_("None"));
+        } else if (paint->set && paint->isColor()) {
+            guint32 color = paint->value.color.toRGBA32( SP_SCALE24_TO_FLOAT ((i == SS_FILL)? query->fill_opacity.value : query->stroke_opacity.value) );
+            ((Inkscape::UI::Widget::ColorPreview*)_color_preview[i])->setRgba32 (color);
+            _color_preview[i]->show_all();
+            place->add(*_color_preview[i]);
+            gchar *tip;
+            if (i == SS_FILL) {
+                tip = g_strdup_printf (_("Fill: %06x/%.3g"), color >> 8, SP_RGBA32_A_F(color));
+            } else {
+                tip = g_strdup_printf (_("Stroke: %06x/%.3g"), color >> 8, SP_RGBA32_A_F(color));
+            }
+            _tooltips.set_tip(*place, tip);
+            g_free (tip);
+        } else if (paint->set && paint->isNone()) {
+            _value[i].set_markup(_("<i>None</i>"));
             place->add(_value[i]);
             _tooltips.set_tip(*place, (i == SS_FILL)? (_("No fill")) : (_("No stroke")));
             if (i == SS_STROKE) has_stroke = false;
         } else if (!paint->set) {
-            _value[i].set_markup(_("Unset"));
+            _value[i].set_markup(_("<b>Unset</b>"));
             place->add(_value[i]);
             _tooltips.set_tip(*place, (i == SS_FILL)? (_("Unset fill")) : (_("Unset stroke")));
             if (i == SS_STROKE) has_stroke = false;
@@ -193,8 +347,8 @@ StyleSwatch::setStyle(SPStyle *query)
             g_free (str);
         }
         {
-            gchar *str = g_strdup_printf(_("Stroke width: %.5g%s"), 
-                                         w, 
+            gchar *str = g_strdup_printf(_("Stroke width: %.5g%s"),
+                                         w,
                                          _sw_unit? sp_unit_get_abbreviation(_sw_unit) : "px");
             _tooltips.set_tip(_stroke_width_place, str);
             g_free (str);
@@ -209,9 +363,9 @@ StyleSwatch::setStyle(SPStyle *query)
         {
             gchar *str;
             if (op == 0)
-                str = g_strdup_printf(_("0:%.3g"), op);
-            else 
-                str = g_strdup_printf(_("0:.%d"), (int) (op*10));
+                str = g_strdup_printf(_("O:%.3g"), op);
+            else
+                str = g_strdup_printf(_("O:.%d"), (int) (op*10));
             _opacity_value.set_markup (str);
             g_free (str);
         }
@@ -232,7 +386,7 @@ StyleSwatch::setStyle(SPStyle *query)
 } // namespace UI
 } // namespace Inkscape
 
-/* 
+/*
   Local Variables:
   mode:c++
   c-file-style:"stroustrup"