Code

abstraction for style widget subjects
authormental <mental@users.sourceforge.net>
Tue, 1 Jan 2008 04:40:11 +0000 (04:40 +0000)
committermental <mental@users.sourceforge.net>
Tue, 1 Jan 2008 04:40:11 +0000 (04:40 +0000)
src/ui/widget/Makefile_insert
src/ui/widget/object-composite-settings.cpp
src/ui/widget/object-composite-settings.h
src/ui/widget/style-subject.cpp [new file with mode: 0644]
src/ui/widget/style-subject.h [new file with mode: 0644]

index 7661aeb8e5f5c838cab6cc1b20a0788b97714a41..fbbc686ab3dfbc19b38c4b080f1bc91969a430e9 100644 (file)
@@ -69,6 +69,8 @@ ui_widget_libuiwidget_a_SOURCES =     \
        ui/widget/selected-style.cpp    \
        ui/widget/spin-slider.h         \
        ui/widget/spin-slider.cpp       \
+       ui/widget/style-subject.h       \
+       ui/widget/style-subject.cpp     \
        ui/widget/style-swatch.h        \
        ui/widget/style-swatch.cpp      \
        ui/widget/svg-canvas.cpp        \
index 65458dc94ddbc33798db431b559922364b2468bd..b9a88b8daff9649d3bf21c5f118939c806c03847 100644 (file)
@@ -31,32 +31,23 @@ namespace Inkscape {
 namespace UI {
 namespace Widget {
 
-void ObjectCompositeSettings::on_selection_changed(
-  Inkscape::Application *inkscape,
-  Inkscape::Selection *selection,
+void ObjectCompositeSettings::_on_desktop_switch(
+  Inkscape::Application *application,
+  SPDesktop *desktop,
   ObjectCompositeSettings *w
 ) {
-    w->selectionChanged(inkscape, selection);
-}
-
-void ObjectCompositeSettings::on_selection_modified(
-  Inkscape::Application *inkscape,
-  Inkscape::Selection *selection,
-  guint /*flags*/,
-  ObjectCompositeSettings *w
-) {
-    w->selectionChanged(inkscape, selection);
+    w->_subject.setDesktop(desktop);
 }
 
 ObjectCompositeSettings::ObjectCompositeSettings()
-: _fe_vbox(false, 0),
-  _fe_alignment(1, 1, 1, 1),
-  _opacity_vbox(false, 0),
+: _opacity_vbox(false, 0),
   _opacity_label_box(false, 0),
   _opacity_label(_("Opacity, %"), 0.0, 1.0, true),
   _opacity_adjustment(100.0, 0.0, 100.0, 1.0, 1.0, 0.0),
   _opacity_hscale(_opacity_adjustment),
   _opacity_spin_button(_opacity_adjustment, 0.01, 1),
+  _fe_vbox(false, 0),
+  _fe_alignment(1, 1, 1, 1),
   _blocked(false)
 {
     // Filter Effects
@@ -76,50 +67,36 @@ ObjectCompositeSettings::ObjectCompositeSettings()
     _opacity_hscale.set_draw_value(false);
     _opacity_adjustment.signal_value_changed().connect(sigc::mem_fun(*this, &ObjectCompositeSettings::_opacityValueChanged));
 
-    _sel_changed = g_signal_connect ( G_OBJECT (INKSCAPE), "change_selection", G_CALLBACK (on_selection_changed), this );
-    _subsel_changed = g_signal_connect ( G_OBJECT (INKSCAPE), "change_subselection", G_CALLBACK (on_selection_changed), this );
-    _sel_modified = g_signal_connect ( G_OBJECT (INKSCAPE), "modify_selection", G_CALLBACK (on_selection_modified), this );
-    _desktop_activated = g_signal_connect ( G_OBJECT (INKSCAPE), "activate_desktop", G_CALLBACK (on_selection_changed), this );
-
-    selectionChanged(INKSCAPE, sp_desktop_selection(SP_ACTIVE_DESKTOP));
-
     show_all_children();
+
+    _desktop_activated = g_signal_connect ( G_OBJECT (INKSCAPE), "activate_desktop", G_CALLBACK (&ObjectCompositeSettings::_on_desktop_switch), this );
+    _subject.connectChanged(sigc::mem_fun(*this, &ObjectCompositeSettings::_subjectChanged));
+    _subject.setDesktop(SP_ACTIVE_DESKTOP);
 }
 
 ObjectCompositeSettings::~ObjectCompositeSettings() {
-    g_signal_handler_disconnect(G_OBJECT(INKSCAPE), _sel_changed);
-    g_signal_handler_disconnect(G_OBJECT(INKSCAPE), _subsel_changed);
-    g_signal_handler_disconnect(G_OBJECT(INKSCAPE), _sel_modified);
     g_signal_handler_disconnect(G_OBJECT(INKSCAPE), _desktop_activated);
 }
 
 void
 ObjectCompositeSettings::_blendBlurValueChanged()
 {
-    if (_blocked)
-        return;
-    _blocked = true;
-
-    //get desktop
-    SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+    SPDesktop *desktop = _subject.getDesktop();
     if (!desktop) {
         return;
     }
 
+    if (_blocked)
+        return;
+    _blocked = true;
+
     // FIXME: fix for GTK breakage, see comment in SelectedStyle::on_opacity_changed; here it results in crash 1580903
     sp_canvas_force_full_redraw_after_interruptions(sp_desktop_canvas(desktop), 0);
 
-    //get current selection
-    Inkscape::Selection *selection = sp_desktop_selection (desktop);
-
-    NR::Maybe<NR::Rect> bbox = selection->bounds();
+    NR::Maybe<NR::Rect> bbox = _subject.getBounds();
     if (!bbox) {
         return;
     }
-    //get list of selected items
-    GSList const *items = selection->itemList();
-    //get current document
-    SPDocument *document = sp_desktop_document (desktop);
 
     double perimeter = bbox->extent(NR::X) + bbox->extent(NR::Y);
 
@@ -130,13 +107,18 @@ ObjectCompositeSettings::_blendBlurValueChanged()
     const bool remfilter = (blendmode == "normal" && radius == 0) || (blendmode == "filter" && !filter);
 
     if(blendmode != "filter" || filter) {
+        SPDocument *document = sp_desktop_document (desktop);
+
         //apply created filter to every selected item
-        for (GSList const *i = items; i != NULL; i = i->next) {
-            SPItem * item = SP_ITEM(i->data);
+        for (StyleSubject::iterator i = _subject.begin() ; i != _subject.end() ; ++i ) {
+            if (!SP_IS_ITEM(*i)) {
+                continue;
+            }
+
+            SPItem * item = SP_ITEM(*i);
             SPStyle *style = SP_OBJECT_STYLE(item);
             g_assert(style != NULL);
 
-
             if(remfilter) {
                 remove_filter (item, false);
             }
@@ -163,12 +145,15 @@ ObjectCompositeSettings::_blendBlurValueChanged()
 void
 ObjectCompositeSettings::_opacityValueChanged()
 {
+    SPDesktop *desktop = _subject.getDesktop();
+    if (!desktop) {
+        return;
+    }
+
     if (_blocked)
         return;
     _blocked = true;
 
-    SPDesktop *desktop = SP_ACTIVE_DESKTOP;
-
     // FIXME: fix for GTK breakage, see comment in SelectedStyle::on_opacity_changed; here it results in crash 1580903
     // UPDATE: crash fixed in GTK+ 2.10.7 (bug 374378), remove this as soon as it's reasonably common
     // (though this only fixes the crash, not the multiple change events)
@@ -180,7 +165,7 @@ ObjectCompositeSettings::_opacityValueChanged()
     os << CLAMP (_opacity_adjustment.get_value() / 100, 0.0, 1.0);
     sp_repr_css_set_property (css, "opacity", os.str().c_str());
 
-    sp_desktop_set_style (desktop, css);
+    _subject.setCSS(css);
 
     sp_repr_css_attr_unref (css);
 
@@ -194,19 +179,18 @@ ObjectCompositeSettings::_opacityValueChanged()
 }
 
 void
-ObjectCompositeSettings::selectionChanged(Inkscape::Application */*inkscape*/,
-                                          Inkscape::Selection */*selection*/)
-{
+ObjectCompositeSettings::_subjectChanged() {
+    SPDesktop *desktop = _subject.getDesktop();
+    if (!desktop) {
+        return;
+    }
+
     if (_blocked)
         return;
     _blocked = true;
 
-    SPDesktop *desktop = SP_ACTIVE_DESKTOP;
-
-    // create temporary style
     SPStyle *query = sp_style_new (sp_desktop_document(desktop));
-    // query style from desktop into it. This returns a result flag and fills query with the style of subselection, if any, or selection
-    int result = sp_desktop_query_style (desktop, query, QUERY_STYLE_PROPERTY_MASTEROPACITY);
+    int result = _subject.queryStyle(query, QUERY_STYLE_PROPERTY_MASTEROPACITY);
 
     switch (result) {
         case QUERY_STYLE_NOTHING:
@@ -222,7 +206,7 @@ ObjectCompositeSettings::selectionChanged(Inkscape::Application */*inkscape*/,
     }
 
     //query now for current filter mode and average blurring of selection
-    const int blend_result = sp_desktop_query_style (desktop, query, QUERY_STYLE_PROPERTY_BLEND);
+    const int blend_result = _subject.queryStyle(query, QUERY_STYLE_PROPERTY_BLEND);
     switch(blend_result) {
         case QUERY_STYLE_NOTHING:
             _fe_cb.set_sensitive(false);
@@ -239,7 +223,7 @@ ObjectCompositeSettings::selectionChanged(Inkscape::Application */*inkscape*/,
     }
 
     if(blend_result == QUERY_STYLE_SINGLE || blend_result == QUERY_STYLE_MULTIPLE_SAME) {
-        int blur_result = sp_desktop_query_style (desktop, query, QUERY_STYLE_PROPERTY_BLUR);
+        int blur_result = _subject.queryStyle(query, QUERY_STYLE_PROPERTY_BLUR);
         switch (blur_result) {
             case QUERY_STYLE_NOTHING: //no blurring
                 _fe_cb.set_blur_sensitive(false);
@@ -247,7 +231,7 @@ ObjectCompositeSettings::selectionChanged(Inkscape::Application */*inkscape*/,
             case QUERY_STYLE_SINGLE:
             case QUERY_STYLE_MULTIPLE_AVERAGED:
             case QUERY_STYLE_MULTIPLE_SAME:
-                NR::Maybe<NR::Rect> bbox = sp_desktop_selection(desktop)->bounds();
+                NR::Maybe<NR::Rect> bbox = _subject.getBounds();
                 if (bbox) {
                     double perimeter = bbox->extent(NR::X) + bbox->extent(NR::Y);
                     _fe_cb.set_blur_sensitive(true);
index fa007685b4ce243c237b4d2a00773ac5ffbf62aa..6cbcc82af2a9759c841e7abf4d3bb0884c7571c5 100644 (file)
@@ -21,6 +21,7 @@
 #include <gtkmm/scale.h>
 
 #include "ui/widget/filter-effect-chooser.h"
+#include "ui/widget/style-subject.h"
 
 namespace Inkscape {
 namespace UI {
@@ -40,30 +41,20 @@ private:
     Gtk::HScale     _opacity_hscale;
     Gtk::SpinButton _opacity_spin_button;
 
+    StyleSubject::Selection _subject;
+
     SimpleFilterModifier _fe_cb;
     Gtk::VBox       _fe_vbox;
     Gtk::Alignment  _fe_alignment;
 
-    void selectionChanged(Inkscape::Application *inkscape,
-                          Inkscape::Selection *selection);
-
-    static void on_selection_changed(Inkscape::Application *inkscape,
-                                     Inkscape::Selection *selection,
-                                     ObjectCompositeSettings *w);
-
-    static void on_selection_modified(Inkscape::Application *inkscape,
-                                      Inkscape::Selection *selection,
-                                      guint flags,
-                                      ObjectCompositeSettings *w);
+    static void _on_desktop_switch(Inkscape::Application *application, SPDesktop *desktop, ObjectCompositeSettings *w);
+    void _subjectChanged();
 
     void _blendBlurValueChanged();
     void _opacityValueChanged();
 
     bool _blocked;
 
-    gulong _sel_changed;
-    gulong _subsel_changed;
-    gulong _sel_modified;
     gulong _desktop_activated;
 };
 
diff --git a/src/ui/widget/style-subject.cpp b/src/ui/widget/style-subject.cpp
new file mode 100644 (file)
index 0000000..f7864ac
--- /dev/null
@@ -0,0 +1,193 @@
+/**
+ * \brief Abstraction for different style widget operands
+ *
+ * Copyright (C) 2007 MenTaLguY <mental@rydia.net>
+ *
+ * Released under GNU GPL.  Read the file 'COPYING' for more information.
+ */
+
+#include "ui/widget/style-subject.h"
+
+#include "desktop.h"
+#include "sp-object.h"
+#include "xml/sp-css-attr.h"
+#include "desktop-style.h"
+#include "desktop-handles.h"
+#include "selection.h"
+#include "style.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+StyleSubject::StyleSubject() : _desktop(NULL) {
+}
+
+StyleSubject::~StyleSubject() {
+    setDesktop(NULL);
+}
+
+void StyleSubject::setDesktop(SPDesktop *desktop) {
+    if (desktop != _desktop) {
+        if (desktop) {
+            GC::anchor(desktop);
+        }
+        if (_desktop) {
+            GC::release(_desktop);
+        }
+        _desktop = desktop;
+        _afterDesktopSwitch(desktop);
+        _emitChanged();
+    }
+}
+
+StyleSubject::Selection::Selection() {
+}
+
+StyleSubject::Selection::~Selection() {
+}
+
+Inkscape::Selection *StyleSubject::Selection::_getSelection() const {
+    SPDesktop *desktop = getDesktop();
+    if (desktop) {
+        return sp_desktop_selection(desktop);
+    } else {
+        return NULL;
+    }
+}
+
+StyleSubject::iterator StyleSubject::Selection::begin() {
+    Inkscape::Selection *selection = _getSelection();
+    if (selection) {
+        return iterator(selection->list());
+    } else {
+        return iterator(NULL);
+    }
+}
+
+NR::Maybe<NR::Rect> StyleSubject::Selection::getBounds(SPItem::BBoxType type) {
+    Inkscape::Selection *selection = _getSelection();
+    if (selection) {
+        return selection->bounds(type);
+    } else {
+        return NR::Nothing();
+    }
+}
+
+int StyleSubject::Selection::queryStyle(SPStyle *query, int property) {
+    SPDesktop *desktop = getDesktop();
+    if (desktop) {
+        return sp_desktop_query_style(desktop, query, property);
+    } else {
+        return QUERY_STYLE_NOTHING;
+    }
+}
+
+void StyleSubject::Selection::_afterDesktopSwitch(SPDesktop *desktop) {
+    _sel_changed.disconnect();
+    _subsel_changed.disconnect();
+    _sel_modified.disconnect();
+    if (desktop) {
+        _subsel_changed = desktop->connectToolSubselectionChanged(sigc::hide(sigc::mem_fun(*this, &Selection::_emitChanged)));
+        Inkscape::Selection *selection = sp_desktop_selection(desktop);
+        if (selection) {
+            _sel_changed = selection->connectChanged(sigc::hide(sigc::mem_fun(*this, &Selection::_emitChanged)));
+            _sel_modified = selection->connectModified(sigc::hide(sigc::hide(sigc::mem_fun(*this, &Selection::_emitChanged))));
+        }
+    }
+}
+
+void StyleSubject::Selection::setCSS(SPCSSAttr *css) {
+    SPDesktop *desktop = getDesktop();
+    if (desktop) {
+        sp_desktop_set_style(desktop, css);
+    }
+}
+
+StyleSubject::CurrentLayer::CurrentLayer() {
+    _element.data = NULL;
+    _element.next = NULL;
+}
+
+StyleSubject::CurrentLayer::~CurrentLayer() {
+}
+
+void StyleSubject::CurrentLayer::_setLayer(SPObject *layer) {
+    _layer_release.disconnect();
+    _layer_modified.disconnect();
+    if (_element.data) {
+        sp_object_unref(static_cast<SPObject *>(_element.data), NULL);
+    }
+    _element.data = layer;
+    if (layer) {
+        sp_object_ref(layer, NULL);
+        _layer_release = layer->connectRelease(sigc::hide(sigc::bind(sigc::mem_fun(*this, &CurrentLayer::_setLayer), (SPObject *)NULL)));
+        _layer_modified = layer->connectModified(sigc::hide(sigc::hide(sigc::mem_fun(*this, &CurrentLayer::_emitChanged))));
+    }
+}
+
+SPObject *StyleSubject::CurrentLayer::_getLayer() const {
+    return static_cast<SPObject *>(_element.data);
+}
+
+GSList *StyleSubject::CurrentLayer::_getLayerSList() const {
+    if (_element.data) {
+        return &_element;
+    } else {
+        return NULL;
+    }
+}
+
+StyleSubject::iterator StyleSubject::CurrentLayer::begin() {
+    return iterator(_getLayerSList());
+}
+
+NR::Maybe<NR::Rect> StyleSubject::CurrentLayer::getBounds(SPItem::BBoxType type) {
+    SPObject *layer = _getLayer();
+    if (layer && SP_IS_ITEM(layer)) {
+        return sp_item_bbox_desktop(SP_ITEM(layer), type);
+    } else {
+        return NR::Nothing();
+    }
+}
+
+int StyleSubject::CurrentLayer::queryStyle(SPStyle *query, int property) {
+    GSList *list = _getLayerSList();
+    if (list) {
+        return sp_desktop_query_style_from_list(list, query, property);
+    } else {
+        return QUERY_STYLE_NOTHING;
+    }
+}
+
+void StyleSubject::CurrentLayer::setCSS(SPCSSAttr *css) {
+    SPObject *layer = _getLayer();
+    if (layer) {
+        sp_desktop_apply_css_recursive(layer, css, true);
+    }
+}
+
+void StyleSubject::CurrentLayer::_afterDesktopSwitch(SPDesktop *desktop) {
+    _layer_switched.disconnect();
+    if (desktop) {
+        _layer_switched = desktop->connectCurrentLayerChanged(sigc::mem_fun(*this, &CurrentLayer::_setLayer));
+        _setLayer(desktop->currentLayer());
+    } else {
+        _setLayer(NULL);
+    }
+}
+
+}
+}
+}
+
+/*
+  Local Variables:
+  mode:c++
+  c-file-style:"stroustrup"
+  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+  indent-tabs-mode:nil
+  fill-column:99
+  End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/style-subject.h b/src/ui/widget/style-subject.h
new file mode 100644 (file)
index 0000000..07ab64a
--- /dev/null
@@ -0,0 +1,123 @@
+/**
+ * \brief Abstraction for different style widget operands
+ *
+ * Copyright (C) 2007 MenTaLguY <mental@rydia.net>
+ *
+ * Released under GNU GPL.  Read the file 'COPYING' for more information.
+ */
+
+#ifndef SEEN_INKSCAPE_UI_WIDGET_STYLE_SUBJECT_H
+#define SEEN_INKSCAPE_UI_WIDGET_STYLE_SUBJECT_H
+
+#include "util/glib-list-iterators.h"
+#include "libnr/nr-maybe.h"
+#include "libnr/nr-rect.h"
+#include "sp-item.h"
+#include <sigc++/sigc++.h>
+
+class SPDesktop;
+class SPObject;
+class SPCSSAttr;
+class SPStyle;
+
+namespace Inkscape {
+class Selection;
+}
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+class StyleSubject {
+public:
+    class Selection;
+    class CurrentLayer;
+
+    typedef Util::GSListConstIterator<SPObject *> iterator;
+
+    StyleSubject();
+    virtual ~StyleSubject();
+
+    void setDesktop(SPDesktop *desktop);
+    SPDesktop *getDesktop() const { return _desktop; }
+
+    virtual iterator begin() = 0;
+    virtual iterator end() { return iterator(NULL); }
+    virtual NR::Maybe<NR::Rect> getBounds(SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX) = 0;
+    virtual int queryStyle(SPStyle *query, int property) = 0;
+    virtual void setCSS(SPCSSAttr *css) = 0;
+
+    sigc::connection connectChanged(sigc::signal<void>::slot_type slot) {
+        return _changed_signal.connect(slot);
+    }
+
+protected:
+    virtual void _afterDesktopSwitch(SPDesktop *desktop) {}
+    void _emitChanged() { _changed_signal.emit(); }
+
+private:
+    sigc::signal<void> _changed_signal;
+    SPDesktop *_desktop;
+};
+
+class StyleSubject::Selection : public StyleSubject {
+public:
+    Selection();
+    ~Selection();
+
+    virtual iterator begin();
+    virtual NR::Maybe<NR::Rect> getBounds(SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX);
+    virtual int queryStyle(SPStyle *query, int property);
+    virtual void setCSS(SPCSSAttr *css);
+
+protected:
+    virtual void _afterDesktopSwitch(SPDesktop *desktop);
+
+private:
+    Inkscape::Selection *_getSelection() const;
+
+    sigc::connection _sel_changed;
+    sigc::connection _subsel_changed;
+    sigc::connection _sel_modified;
+};
+
+class StyleSubject::CurrentLayer : public StyleSubject {
+public:
+    CurrentLayer();
+    ~CurrentLayer();
+
+    virtual iterator begin();
+    virtual NR::Maybe<NR::Rect> getBounds(SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX);
+    virtual int queryStyle(SPStyle *query, int property);
+    virtual void setCSS(SPCSSAttr *css);
+
+protected:
+    virtual void _afterDesktopSwitch(SPDesktop *desktop);
+
+private:
+    SPObject *_getLayer() const;
+    void _setLayer(SPObject *layer);
+    GSList *_getLayerSList() const;
+
+    sigc::connection _layer_switched;
+    sigc::connection _layer_release;
+    sigc::connection _layer_modified;
+    mutable GSList _element;
+};
+
+}
+}
+}
+
+#endif
+
+/*
+  Local Variables:
+  mode:c++
+  c-file-style:"stroustrup"
+  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+  indent-tabs-mode:nil
+  fill-column:99
+  End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :