Code

initial filter UI code drop from Nick
authormental <mental@users.sourceforge.net>
Sun, 24 Jun 2007 18:42:18 +0000 (18:42 +0000)
committermental <mental@users.sourceforge.net>
Sun, 24 Jun 2007 18:42:18 +0000 (18:42 +0000)
24 files changed:
src/desktop-style.cpp
src/desktop-style.h
src/dialogs/object-properties.cpp
src/display/nr-filter-blend.h
src/filter-chemistry.cpp
src/filter-chemistry.h
src/menus-skeleton.h
src/style.h
src/ui/dialog/Makefile_insert
src/ui/dialog/dialog-manager.cpp
src/ui/dialog/fill-and-stroke.cpp
src/ui/dialog/filter-effects-dialog.cpp [new file with mode: 0644]
src/ui/dialog/filter-effects-dialog.h [new file with mode: 0644]
src/ui/stock.cpp
src/ui/stock.h
src/ui/view/edit-widget.cpp
src/ui/widget/Makefile_insert
src/ui/widget/filter-effect-chooser.cpp [new file with mode: 0644]
src/ui/widget/filter-effect-chooser.h [new file with mode: 0644]
src/ui/widget/filter-effect-enums.h [new file with mode: 0644]
src/ui/widget/spin-slider.cpp [new file with mode: 0644]
src/ui/widget/spin-slider.h [new file with mode: 0644]
src/verbs.cpp
src/verbs.h

index 95abdfa5bc6c04d4316b2e288d5d9a44399697c7..5685dc4d6502208c853848a1e6dbff5d5b1c525f 100644 (file)
@@ -24,6 +24,7 @@
 #include "style.h"
 #include "prefs-utils.h"
 #include "sp-use.h"
+#include "sp-feblend.h"
 #include "sp-filter.h"
 #include "sp-gaussian-blur.h"
 #include "sp-flowtext.h"
@@ -1010,6 +1011,84 @@ objects_query_fontfamily (GSList *objects, SPStyle *style_res)
     }
 }
 
+int
+objects_query_blend (GSList *objects, SPStyle *style_res)
+{
+    const int empty_prev = -2;
+    const int complex_filter = 5;
+    int blend = 0;
+    float blend_prev = empty_prev;
+    bool same_blend = true;
+    guint items = 0;
+    
+    for (GSList const *i = objects; i != NULL; i = i->next) {
+        SPObject *obj = SP_OBJECT (i->data);
+        SPStyle *style = SP_OBJECT_STYLE (obj);
+        if(!style || !SP_IS_ITEM(obj)) continue;
+
+        items++;
+
+        //if object has a filter
+        if (style->filter.set && style->filter.filter) {
+            int blurcount = 0;
+            int blendcount = 0;
+
+            // determine whether filter is simple (blend and/or blur) or complex
+            for(SPObject *primitive_obj = style->filter.filter->children;
+                primitive_obj && SP_IS_FILTER_PRIMITIVE(primitive_obj);
+                primitive_obj = primitive_obj->next) {
+                SPFilterPrimitive *primitive = SP_FILTER_PRIMITIVE(primitive_obj);
+                if(SP_IS_FEBLEND(primitive))
+                    ++blendcount;
+                else if(SP_IS_GAUSSIANBLUR(primitive))
+                    ++blurcount;
+                else {
+                    blurcount = complex_filter;
+                    break;
+                }
+            }
+
+            // simple filter
+            if(blurcount == 1 || blendcount == 1) {
+                for(SPObject *primitive_obj = style->filter.filter->children;
+                    primitive_obj && SP_IS_FILTER_PRIMITIVE(primitive_obj);
+                    primitive_obj = primitive_obj->next) {
+                    if(SP_IS_FEBLEND(primitive_obj)) {
+                        SPFeBlend *spblend = SP_FEBLEND(primitive_obj);
+                        blend = spblend->blend_mode;
+                    }
+                }
+            }
+            else {
+                blend = complex_filter;
+            }
+        }
+        // defaults to blend mode = "normal"
+        else {
+            blend = 0;
+        }
+
+        if(blend_prev != empty_prev && blend_prev != blend)
+            same_blend = false;
+        blend_prev = blend;
+    }
+
+    if (items > 0) {
+        style_res->filter_blend_mode.value = blend;
+    }
+
+    if (items == 0) {
+        return QUERY_STYLE_NOTHING;
+    } else if (items == 1) {
+        return QUERY_STYLE_SINGLE;
+    } else {
+        if(same_blend)
+            return QUERY_STYLE_MULTIPLE_SAME;
+        else
+            return QUERY_STYLE_MULTIPLE_DIFFERENT;
+    }
+}
+
 /**
  * Write to style_res the average blurring of a list of objects.
  */
@@ -1111,6 +1190,8 @@ sp_desktop_query_style_from_list (GSList *list, SPStyle *style, int property)
     } else if (property == QUERY_STYLE_PROPERTY_FONTNUMBERS) {
         return objects_query_fontnumbers (list, style);
 
+    } else if (property == QUERY_STYLE_PROPERTY_BLEND) {
+        return objects_query_blend (list, style);
     } else if (property == QUERY_STYLE_PROPERTY_BLUR) {
         return objects_query_blur (list, style);
     }
index 112fe1372a4ab94ed8bd50cf1dd935629dd5b911..3f201aa285ce03d4cda9ff9c64295065fe1047d8 100644 (file)
@@ -47,7 +47,8 @@ enum { // which property was queried (add when you need more)
     QUERY_STYLE_PROPERTY_FONTSTYLE, // font style 
     QUERY_STYLE_PROPERTY_FONTNUMBERS, // size, spacings
     QUERY_STYLE_PROPERTY_MASTEROPACITY, // opacity
-       QUERY_STYLE_PROPERTY_BLUR // blur
+    QUERY_STYLE_PROPERTY_BLEND, // blend
+    QUERY_STYLE_PROPERTY_BLUR // blur
 };
 
 void sp_desktop_apply_css_recursive(SPObject *o, SPCSSAttr *css, bool skip_lines);
index fbc9ab83fc432292aa2d5f39e87001ac64ef9e3c..b4358e5e54960e60a012edd5870728bceb1590da 100644 (file)
@@ -25,6 +25,7 @@
 #include "helper/window.h"
 #include "widgets/sp-widget.h"
 #include "widgets/icon.h"
+#include "desktop.h"
 #include "macros.h"
 #include "inkscape.h"
 #include "fill-style.h"
@@ -44,6 +45,8 @@
 #include "document.h"
 #include "document-private.h"
 #include <selection.h>
+#include <ui/dialog/dialog-manager.h>
+#include "ui/widget/filter-effect-chooser.h"
 #include "xml/repr.h"
 #include "display/sp-canvas.h"
 
@@ -59,7 +62,9 @@ static gchar *prefs_path = "dialogs.fillstroke";
 static void sp_fillstroke_selection_modified ( Inkscape::Application *inkscape, Inkscape::Selection *selection, guint flags, GtkObject *base );
 static void sp_fillstroke_selection_changed ( Inkscape::Application *inkscape, Inkscape::Selection *selection, GtkObject *base );
 static void sp_fillstroke_opacity_changed (GtkAdjustment *a, SPWidget *dlg);
-static void sp_fillstroke_blur_changed (GtkAdjustment *a, SPWidget *dlg);
+
+using Inkscape::UI::Widget::SimpleFilterModifier;
+static void sp_fillstroke_blend_blur_changed (SimpleFilterModifier *);
 
 static void
 sp_object_properties_dialog_destroy (GtkObject *object, gpointer data)
@@ -187,35 +192,21 @@ sp_object_properties_dialog (void)
         }
 
 
-        /* Blur */
+        /* Filter Effects (gtkmm) */
+        GtkWidget *al_fe = gtk_alignment_new(1, 1, 1, 1);
+        gtk_alignment_set_padding(GTK_ALIGNMENT(al_fe), 0, 0, 4, 0);
+        SimpleFilterModifier *cb_fe = Gtk::manage(new SimpleFilterModifier);
+        g_object_set_data(G_OBJECT(dlg), "filter_modifier", cb_fe);
+        cb_fe->signal_selection_changed().connect(
+            sigc::bind(sigc::ptr_fun(sp_fillstroke_blend_blur_changed), cb_fe));
+        cb_fe->signal_blend_blur_changed().connect(
+            sigc::bind(sigc::ptr_fun(sp_fillstroke_blend_blur_changed), cb_fe));
+        gtk_container_add(GTK_CONTAINER(al_fe), GTK_WIDGET(cb_fe->gobj()));
+        
         GtkWidget *b_vb = gtk_vbox_new (FALSE, 0);
         gtk_box_pack_start (GTK_BOX (vb), b_vb, FALSE, FALSE, 2);
         gtk_object_set_data (GTK_OBJECT (dlg), "blur", b_vb);
-
-        GtkWidget *blur_l_hb = gtk_hbox_new (FALSE, 4);
-        GtkWidget *blur_l = gtk_label_new_with_mnemonic (_("_Blur, %"));
-        gtk_misc_set_alignment (GTK_MISC (blur_l), 0.0, 1.0);
-        gtk_box_pack_start (GTK_BOX (blur_l_hb), blur_l, FALSE, FALSE, 4);
-        gtk_box_pack_start (GTK_BOX (b_vb), blur_l_hb, FALSE, FALSE, 0);
-
-        GtkWidget *blur_hb = gtk_hbox_new (FALSE, 4);
-        gtk_box_pack_start (GTK_BOX (b_vb), blur_hb, FALSE, FALSE, 0);
-
-        GtkObject *blur_a = gtk_adjustment_new (0.0, 0.0, 100.0, 1.0, 1.0, 0.0);
-        gtk_object_set_data(GTK_OBJECT(dlg), "blur_adjustment", blur_a);
-
-        GtkWidget *blur_s = gtk_hscale_new (GTK_ADJUSTMENT (blur_a));
-        gtk_scale_set_draw_value (GTK_SCALE (blur_s), FALSE);
-        gtk_box_pack_start (GTK_BOX (blur_hb), blur_s, TRUE, TRUE, 4);
-        gtk_label_set_mnemonic_widget (GTK_LABEL(blur_l), blur_s);
-
-        GtkWidget *blur_sb = gtk_spin_button_new (GTK_ADJUSTMENT (blur_a), 0.01, 1);
-        gtk_box_pack_start (GTK_BOX (blur_hb), blur_sb, FALSE, FALSE, 0);
-
-        gtk_signal_connect ( blur_a, "value_changed",
-                             GTK_SIGNAL_FUNC (sp_fillstroke_blur_changed),
-                             dlg );
-                             
+        gtk_box_pack_start (GTK_BOX (b_vb), al_fe, FALSE, FALSE, 0);
         gtk_widget_show_all (b_vb);
 
 
@@ -329,31 +320,46 @@ sp_fillstroke_selection_changed ( Inkscape::Application *inkscape,
             break;
     }
 
+    SimpleFilterModifier *mod = (SimpleFilterModifier*)g_object_get_data(G_OBJECT(dlg), "filter_modifier");
 
-    GtkWidget *b = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (dlg), "blur"));
-    GtkAdjustment *bluradjustment = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(dlg), "blur_adjustment"));
-
-    //query now for current average blurring of selection
-    int blur_result = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_BLUR);
-    switch (blur_result) {
-        case QUERY_STYLE_NOTHING: //no blurring
-            gtk_widget_set_sensitive (b, FALSE);
+    //query now for current filter mode and average blurring of selection
+    const int blend_result = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_BLEND);
+    switch(blend_result) {
+        case QUERY_STYLE_NOTHING:
+            mod->set_sensitive(false);
             break;
         case QUERY_STYLE_SINGLE:
-        case QUERY_STYLE_MULTIPLE_AVERAGED:
-        case QUERY_STYLE_MULTIPLE_SAME: 
-            NR::Maybe<NR::Rect> bbox = sp_desktop_selection(SP_ACTIVE_DESKTOP)->bounds();
-            if (bbox) {
-                double perimeter = bbox->extent(NR::X) + bbox->extent(NR::Y);
-                gtk_widget_set_sensitive (b, TRUE);
-                //update blur widget value
-                float radius = query->filter_gaussianBlur_deviation.value;
-                float percent = radius * 400 / perimeter; // so that for a square, 100% == half side
-                gtk_adjustment_set_value(bluradjustment, percent);
-            }
+        case QUERY_STYLE_MULTIPLE_SAME:
+            mod->set_blend_mode(query->filter_blend_mode.value);
+            mod->set_sensitive(true);
+            break;
+        case QUERY_STYLE_MULTIPLE_DIFFERENT:
+            // TODO: set text
+            mod->set_sensitive(false);
             break;
     }
-    
+
+    if(blend_result == QUERY_STYLE_SINGLE || blend_result == QUERY_STYLE_MULTIPLE_SAME) {
+        int blur_result = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_BLUR);
+        switch (blur_result) {
+            case QUERY_STYLE_NOTHING: //no blurring
+                mod->set_blur_sensitive(false);
+                break;
+            case QUERY_STYLE_SINGLE:
+            case QUERY_STYLE_MULTIPLE_AVERAGED:
+            case QUERY_STYLE_MULTIPLE_SAME: 
+                NR::Maybe<NR::Rect> bbox = sp_desktop_selection(SP_ACTIVE_DESKTOP)->bounds();
+                if (bbox) {
+                    double perimeter = bbox->extent(NR::X) + bbox->extent(NR::Y);
+                    mod->set_blur_sensitive(true);
+                    //update blur widget value
+                    float radius = query->filter_gaussianBlur_deviation.value;
+                    float percent = radius * 400 / perimeter; // so that for a square, 100% == half side
+                    mod->set_blur_value(percent);
+                }
+                break;
+        }
+    }
     
     g_free (query);
     gtk_object_set_data (GTK_OBJECT (dlg), "blocked", GUINT_TO_POINTER (FALSE));
@@ -391,9 +397,8 @@ sp_fillstroke_opacity_changed (GtkAdjustment *a, SPWidget *base)
     gtk_object_set_data (GTK_OBJECT (dlg), "blocked", GUINT_TO_POINTER (FALSE));
 }
 
-
 static void
-sp_fillstroke_blur_changed (GtkAdjustment *a, SPWidget *base)
+sp_fillstroke_blend_blur_changed (SimpleFilterModifier *m)
 {
     //if dialog is locked, return 
     if (gtk_object_get_data (GTK_OBJECT (dlg), "blocked"))
@@ -424,24 +429,32 @@ sp_fillstroke_blur_changed (GtkAdjustment *a, SPWidget *base)
     SPDocument *document = sp_desktop_document (desktop);
 
     double perimeter = bbox->extent(NR::X) + bbox->extent(NR::Y);
-    double radius = a->value * perimeter / 400;
+    const Glib::ustring blendmode = m->get_blend_mode();
+    double radius = m->get_blur_value() * perimeter / 400;
+
+    SPFilter *filter = m->get_selected_filter();
+    const bool remfilter = (blendmode == "normal" && radius == 0) || (blendmode == "filter" && !filter);
         
-    //apply created filter to every selected item
-    for (GSList const *i = items; i != NULL; i = i->next) {
-    
-        SPItem * item = SP_ITEM(i->data);
-        SPStyle *style = SP_OBJECT_STYLE(item);
-        g_assert(style != NULL);
-
-        if (radius == 0.0) {
-            remove_filter_gaussian_blur(item);
-        } else {
-            SPFilter *constructed = modify_filter_gaussian_blur_from_item(document, item, radius); 
-            sp_style_set_property_url (SP_OBJECT(item), "filter", SP_OBJECT(constructed), false);
+    if(blendmode != "filter" || filter) {
+        //apply created filter to every selected item
+        for (GSList const *i = items; i != NULL; i = i->next) {
+            SPItem * item = SP_ITEM(i->data);
+            SPStyle *style = SP_OBJECT_STYLE(item);
+            g_assert(style != NULL);
+            
+            if(remfilter) {
+                remove_filter (item, false);
+            }
+            else {
+                if(blendmode != "filter")
+                    filter = new_filter_simple_from_item(document, item, blendmode.c_str(), radius);
+                sp_style_set_property_url (SP_OBJECT(item), "filter", SP_OBJECT(filter), false);
+            }
+            
+            //request update
+            SP_OBJECT(item)->requestDisplayUpdate(( SP_OBJECT_MODIFIED_FLAG |
+                                                    SP_OBJECT_STYLE_MODIFIED_FLAG ));
         }
-        //request update
-        SP_OBJECT(item)->requestDisplayUpdate(( SP_OBJECT_MODIFIED_FLAG |
-                                            SP_OBJECT_STYLE_MODIFIED_FLAG ));
     }
 
     sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "fillstroke:blur", SP_VERB_DIALOG_FILL_STROKE,  _("Change blur"));
index 4787e336e7d56fa21b742bb84ebc334959d816ee..ffed2cd033e148177e9be1261e509b438d020bdb 100644 (file)
@@ -28,7 +28,8 @@ enum FilterBlendMode {
     BLEND_MULTIPLY,
     BLEND_SCREEN,
     BLEND_DARKEN,
-    BLEND_LIGHTEN
+    BLEND_LIGHTEN,
+    BLEND_ENDMODE
 };
 
 class FilterBlend : public FilterPrimitive {
index fb4064a7e50e6568800ab8cf1ccf845a7b1856f0..336ac357619807cd86a6fe39d13ff22a5f0dcc36 100644 (file)
@@ -18,6 +18,7 @@
 #include "document-private.h"
 #include "desktop-style.h"
 
+#include "sp-feblend.h"
 #include "sp-filter.h"
 #include "sp-gaussian-blur.h"
 #include "svg/css-ostringstream.h"
@@ -82,6 +83,55 @@ static void set_filter_area(Inkscape::XML::Node *repr, gdouble radius,
     }
 }
 
+SPFilter *new_filter(SPDocument *document)
+{
+    g_return_val_if_fail(document != NULL, NULL);
+
+    SPDefs *defs = (SPDefs *) SP_DOCUMENT_DEFS(document);
+
+    Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document);
+
+    // create a new filter
+    Inkscape::XML::Node *repr;
+    repr = xml_doc->createElement("svg:filter");
+
+    // Append the new filter node to defs
+    SP_OBJECT_REPR(defs)->appendChild(repr);
+    Inkscape::GC::release(repr);
+
+    // get corresponding object
+    SPFilter *f = SP_FILTER( document->getObjectByRepr(repr) );
+    
+    
+    g_assert(f != NULL);
+    g_assert(SP_IS_FILTER(f));
+
+    return f;
+}
+
+SPFilterPrimitive *
+filter_add_primitive(SPFilter *filter, const gchar *type)
+{
+    Inkscape::XML::Document *xml_doc = sp_document_repr_doc(filter->document);
+
+    //create filter primitive node
+    Inkscape::XML::Node *repr;
+    repr = xml_doc->createElement(type);
+    repr->setAttribute("inkscape:collect", "always");
+
+    //set primitive as child of filter node
+    filter->repr->appendChild(repr);
+    Inkscape::GC::release(repr);
+    
+    // get corresponding object
+    SPFilterPrimitive *prim = SP_FILTER_PRIMITIVE( filter->document->getObjectByRepr(repr) );
+    g_assert(prim != NULL);
+    g_assert(SP_IS_FILTER_PRIMITIVE(prim));
+
+    return prim;
+}
+
 /**
  * Creates a filter with blur primitive of specified radius for an item with the given matrix expansion, width and height
  */
@@ -134,11 +184,85 @@ new_filter_gaussian_blur (SPDocument *document, gdouble radius, double expansion
     return f;
 }
 
+
+/**
+ * Creates a simple filter with a blend primitive and a blur primitive of specified radius for
+ * an item with the given matrix expansion, width and height
+ */
+SPFilter *
+new_filter_blend_gaussian_blur (SPDocument *document, const char *blendmode, gdouble radius, double expansion,
+                                double expansionX, double expansionY, double width, double height)
+{
+    g_return_val_if_fail(document != NULL, NULL);
+
+    SPDefs *defs = (SPDefs *) SP_DOCUMENT_DEFS(document);
+
+    Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document);
+
+    // create a new filter
+    Inkscape::XML::Node *repr;
+    repr = xml_doc->createElement("svg:filter");
+    repr->setAttribute("inkscape:collect", "always");
+
+    // Append the new filter node to defs
+    SP_OBJECT_REPR(defs)->appendChild(repr);
+    Inkscape::GC::release(repr);
+    // get corresponding object
+    SPFilter *f = SP_FILTER( document->getObjectByRepr(repr) );
+
+    // Blend primitive
+    if(strcmp(blendmode, "normal")) {
+        Inkscape::XML::Node *b_repr;
+        b_repr = xml_doc->createElement("svg:feBlend");
+        b_repr->setAttribute("inkscape::collect", "always");
+        b_repr->setAttribute("mode", blendmode);
+
+        // set feBlend as child of filter node
+        repr->appendChild(b_repr);
+        Inkscape::GC::release(b_repr);
+
+        SPFeBlend *b = SP_FEBLEND(document->getObjectByRepr(b_repr));
+        g_assert(b != NULL);
+        g_assert(SP_IS_FEBLEND(b));
+    }
+    // Gaussian blur primitive
+    if(radius != 0) {
+        set_filter_area(repr, radius, expansion, expansionX, expansionY, width, height);
+
+        //create feGaussianBlur node
+        Inkscape::XML::Node *b_repr;
+        b_repr = xml_doc->createElement("svg:feGaussianBlur");
+        b_repr->setAttribute("inkscape:collect", "always");
+        
+        double stdDeviation = radius;
+        if (expansion != 0)
+            stdDeviation /= expansion;
+        
+        //set stdDeviation attribute
+        sp_repr_set_svg_double(b_repr, "stdDeviation", stdDeviation);
+     
+        //set feGaussianBlur as child of filter node
+        repr->appendChild(b_repr);
+        Inkscape::GC::release(b_repr);
+
+        SPGaussianBlur *b = SP_GAUSSIANBLUR( document->getObjectByRepr(b_repr) );
+        g_assert(b != NULL);
+        g_assert(SP_IS_GAUSSIANBLUR(b));
+    }
+    
+    g_assert(f != NULL);
+    g_assert(SP_IS_FILTER(f));
+    return f;
+}
+
 /**
- * Creates a filter with blur primitive of specified radius for the given item
+ * Creates a simple filter for the given item with blend and blur primitives, using the
+ * specified mode and radius, respectively
  */
 SPFilter *
-new_filter_gaussian_blur_from_item (SPDocument *document, SPItem *item, gdouble radius)
+new_filter_simple_from_item (SPDocument *document, SPItem *item, const char *mode, gdouble radius)
 {
     NR::Maybe<NR::Rect> const r = sp_item_bbox_desktop(item);
 
@@ -153,7 +277,7 @@ new_filter_gaussian_blur_from_item (SPDocument *document, SPItem *item, gdouble
 
     NR::Matrix i2d = sp_item_i2d_affine (item);
 
-    return (new_filter_gaussian_blur (document, radius, i2d.expansion(), i2d.expansionX(), i2d.expansionY(), width, height));
+    return (new_filter_blend_gaussian_blur (document, mode, radius, i2d.expansion(), i2d.expansionX(), i2d.expansionY(), width, height));
 }
 
 /**
@@ -170,7 +294,7 @@ modify_filter_gaussian_blur_from_item(SPDocument *document, SPItem *item,
                                       gdouble radius)
 {
     if (!item->style || !item->style->filter.set) {
-        return new_filter_gaussian_blur_from_item(document, item, radius);
+        //return new_filter_gaussian_blur_from_item(document, item, radius);
     }
 
     SPFilter *filter = SP_FILTER(item->style->filter.filter);
index b727536adaf645a81f34e4de513d9a619c748fd2..125c527b290e9e6d1c37ab7113a1ea53c04dc159 100644 (file)
 #include "forward.h"
 #include "sp-filter.h"
 
+SPFilterPrimitive *filter_add_primitive(SPFilter *filter, const gchar *type);
+SPFilter *new_filter (SPDocument *document);
 SPFilter *new_filter_gaussian_blur (SPDocument *document, gdouble stdDeviation, double expansion, double expansionX, double expansionY, double width, double height);
-SPFilter *new_filter_gaussian_blur_from_item (SPDocument *document, SPItem *item, gdouble stdDeviation);
+SPFilter *new_filter_simple_from_item (SPDocument *document, SPItem *item, const char *mode, gdouble stdDeviation);
 SPFilter *modify_filter_gaussian_blur_from_item (SPDocument *document, SPItem *item, gdouble stdDeviation);
 void remove_filter (SPObject *item, bool recursive);
 void remove_filter_gaussian_blur (SPObject *item);
index 722d8a11e3ddb765f513e28bb42d6559fe867ea4..f560deeb0803bd2dd566cfdf07a862d5f599d870 100644 (file)
@@ -229,6 +229,7 @@ static char const menus_skeleton[] =
 "       <verb verb-id=\"EffectLast\" />\n"
 "       <verb verb-id=\"EffectLastPref\" />\n"
 "       <separator/>\n"
+"       <verb verb-id=\"DialogFilterEffects\" />\n"
 "       <effects-list/>\n"
 "   </submenu>\n"
 #ifdef WITH_INKBOARD
index 4538626beb22f62da20be513c8d007c5cd630847..544bde55778251ae3c9bf978c7cbd67ae3b5757a 100644 (file)
@@ -336,6 +336,8 @@ struct SPStyle {
     /** Filter effect */
     SPIFilter filter;
 
+    SPIEnum filter_blend_mode;
+
    /** normally not used, but duplicates the Gaussian blur deviation (if any) from the attached
         filter when the style is used for querying */
     SPILength filter_gaussianBlur_deviation;
index 2b04d3e45c7093e5389e7e52fde230b4b2ce9a1d..c1cb65d295e4020a7ed582ea716d42dc63957445 100644 (file)
@@ -24,6 +24,8 @@ ui_dialog_libuidialog_a_SOURCES =             \
        ui/dialog/filedialog.h                  \
        ui/dialog/fill-and-stroke.cpp           \
        ui/dialog/fill-and-stroke.h             \
+       ui/dialog/filter-effects-dialog.h       \
+       ui/dialog/filter-effects-dialog.cpp     \
        ui/dialog/find.cpp                      \
        ui/dialog/find.h                        \
        ui/dialog/inkscape-preferences.cpp      \
index d685f2e59bab7bd9ad65c9699870feab692db62a..6b02776102238e9d2c25c2a2bdfc03b26c11df4d 100644 (file)
@@ -23,6 +23,7 @@
 #include "ui/dialog/export.h"
 #include "ui/dialog/extension-editor.h"
 #include "ui/dialog/fill-and-stroke.h"
+#include "ui/dialog/filter-effects-dialog.h"
 #include "ui/dialog/find.h"
 #include "ui/dialog/inkscape-preferences.h"
 #include "ui/dialog/layer-editor.h"
@@ -75,6 +76,7 @@ DialogManager::DialogManager() {
     registerFactory("Export",              &create<Export>);
     registerFactory("ExtensionEditor",     &create<ExtensionEditor>);
     registerFactory("FillAndStroke",       &create<FillAndStroke>);
+    registerFactory("FilterEffectsDialog", &create<FilterEffectsDialog>);
     registerFactory("Find",                &create<Find>);
     registerFactory("InkscapePreferences", &create<InkscapePreferences>);
     registerFactory("LayerEditor",         &create<LayerEditor>);
index 6206c4345139d74dc7c8bb4188cc8fb0de708f19..3559e3685433a74f986fc9dd628a2fa0f907efcb 100644 (file)
@@ -183,8 +183,8 @@ FillAndStroke::_blurValueChanged()
         if (radius == 0.0) {
             remove_filter (item, false);
         } else {
-            SPFilter *constructed = new_filter_gaussian_blur_from_item(document, item, radius); 
-            sp_style_set_property_url (SP_OBJECT(item), "filter", SP_OBJECT(constructed), false);
+            //SPFilter *constructed = new_filter_gaussian_blur_from_item(document, item, radius); 
+            //sp_style_set_property_url (SP_OBJECT(item), "filter", SP_OBJECT(constructed), false);
         }
         //request update
         SP_OBJECT(item)->requestDisplayUpdate(( SP_OBJECT_MODIFIED_FLAG |
diff --git a/src/ui/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp
new file mode 100644 (file)
index 0000000..1d14d69
--- /dev/null
@@ -0,0 +1,636 @@
+/**
+ * \brief Filter Effects dialog
+ *
+ * Authors:
+ *   Nicholas Bishop <nicholasbishop@gmail.org>
+ *
+ * Copyright (C) 2007 Authors
+ *
+ * Released under GNU GPL.  Read the file 'COPYING' for more information.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <gtk/gtktreeview.h>
+#include <gtkmm/cellrenderertext.h>
+#include <gtkmm/paned.h>
+#include <gtkmm/scale.h>
+#include <gtkmm/scrolledwindow.h>
+#include <gtkmm/spinbutton.h>
+#include <gtkmm/stock.h>
+#include <glibmm/i18n.h>
+
+#include "application/application.h"
+#include "application/editor.h"
+#include "desktop.h"
+#include "desktop-handles.h"
+#include "dialog-manager.h"
+#include "document.h"
+#include "filter-chemistry.h"
+#include "filter-effects-dialog.h"
+#include "inkscape.h"
+#include "sp-filter-primitive.h"
+#include "sp-gaussian-blur.h"
+#include "sp-feoffset.h"
+#include "verbs.h"
+#include "xml/node.h"
+#include "xml/repr.h"
+#include <sstream>
+
+#include <iostream>
+
+namespace Inkscape {
+namespace UI {
+namespace Dialog {
+
+Glib::RefPtr<Gtk::Menu> create_popup_menu(Gtk::Widget& parent, sigc::slot<void> dup,
+                                          sigc::slot<void> rem)
+{
+    Glib::RefPtr<Gtk::Menu> menu(new Gtk::Menu);
+
+    menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("_Duplicate"), dup));
+    Gtk::MenuItem* mi = Gtk::manage(new Gtk::ImageMenuItem(Gtk::Stock::REMOVE));
+    menu->append(*mi);
+    mi->signal_activate().connect(rem);
+    mi->show();
+    menu->accelerate(parent);
+
+    return menu;
+}
+
+static void try_id_change(SPObject* ob, const Glib::ustring& text)
+{
+    // FIXME: this needs more serious error checking...
+    if(ob && !SP_ACTIVE_DOCUMENT->getObjectById(text.c_str())) {
+        SPException ex;
+        SP_EXCEPTION_INIT(&ex);
+        sp_object_setAttribute(ob, "id", text.c_str(), &ex);
+        sp_document_done(SP_ACTIVE_DOCUMENT, SP_VERB_DIALOG_FILTER_EFFECTS, _("Set object ID"));
+    }
+}
+
+/*** FilterModifier ***/
+FilterEffectsDialog::FilterModifier::FilterModifier()
+    : _add(Gtk::Stock::ADD)
+{
+    Gtk::ScrolledWindow* sw = Gtk::manage(new Gtk::ScrolledWindow);
+    pack_start(*sw);
+    pack_start(_add, false, false);
+    sw->add(_list);
+
+    _list.set_model(_model);
+    _list.append_column_editable(_("_Filter"), _columns.id);
+    ((Gtk::CellRendererText*)_list.get_column(0)->get_first_cell_renderer())->
+        signal_edited().connect(sigc::mem_fun(*this, &FilterEffectsDialog::FilterModifier::filter_name_edited));
+
+    sw->set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
+    sw->set_shadow_type(Gtk::SHADOW_IN);
+    show_all_children();
+    _add.signal_clicked().connect(sigc::mem_fun(*this, &FilterModifier::add_filter));
+    _list.signal_button_press_event().connect_notify(
+        sigc::mem_fun(*this, &FilterModifier::filter_list_button_press));
+    _menu = create_popup_menu(*this, sigc::mem_fun(*this, &FilterModifier::duplicate_filter),
+                              sigc::mem_fun(*this, &FilterModifier::remove_filter));
+
+    update_filters();
+}
+
+Glib::SignalProxy0<void> FilterEffectsDialog::FilterModifier::signal_selection_changed()
+{
+    return _list.get_selection()->signal_changed();
+}
+
+SPFilter* FilterEffectsDialog::FilterModifier::get_selected_filter()
+{
+    if(_list.get_selection()) {
+        Gtk::TreeModel::iterator i = _list.get_selection()->get_selected();
+
+        if(i)
+            return (*i)[_columns.filter];
+    }
+
+    return 0;
+}
+
+void FilterEffectsDialog::FilterModifier::select_filter(const SPFilter* filter)
+{
+    if(filter) {
+        for(Gtk::TreeModel::iterator i = _model->children().begin();
+            i != _model->children().end(); ++i) {
+            if((*i)[_columns.filter] == filter) {
+                _list.get_selection()->select(i);
+                break;
+            }
+        }
+    }
+}
+
+void FilterEffectsDialog::FilterModifier::filter_list_button_press(GdkEventButton* event)
+{
+    if((event->type == GDK_BUTTON_PRESS) && (event->button == 3)) {
+        const bool sensitive = get_selected_filter() != NULL;
+        _menu->items()[0].set_sensitive(sensitive);
+        _menu->items()[1].set_sensitive(sensitive);
+        _menu->popup(event->button, event->time);
+    }
+}
+
+void FilterEffectsDialog::FilterModifier::add_filter()
+{
+    SPDocument* doc = sp_desktop_document(SP_ACTIVE_DESKTOP);
+    SPFilter* filter = new_filter(doc);
+
+    update_filters();
+
+    select_filter(filter);
+
+    sp_document_done(doc, SP_VERB_DIALOG_FILTER_EFFECTS, _("Add filter"));
+}
+
+void FilterEffectsDialog::FilterModifier::remove_filter()
+{
+    SPFilter *filter = get_selected_filter();
+
+    if(filter) {
+        SPDocument* doc = filter->document;
+        sp_repr_unparent(filter->repr);
+
+        sp_document_done(doc, SP_VERB_DIALOG_FILTER_EFFECTS, _("Remove filter"));
+
+        update_filters();
+    }
+}
+
+void FilterEffectsDialog::FilterModifier::duplicate_filter()
+{
+    SPFilter *filter = get_selected_filter();
+
+    if(filter) {
+        //SPFilter *dupfilter = filter_duplicate(sp_desktop_document(SP_ACTIVE_DESKTOP), filter);
+
+        sp_document_done(filter->document, SP_VERB_DIALOG_FILTER_EFFECTS, _("Duplicate filter"));
+
+        update_filters();
+    }
+}
+
+void FilterEffectsDialog::FilterModifier::filter_name_edited(const Glib::ustring& path, const Glib::ustring& text)
+{
+    Gtk::TreeModel::iterator i = _model->get_iter(path);
+
+    if(i)
+        try_id_change((SPObject*)(*i)[_columns.filter], text);
+}
+
+/*** SettingsFrame ***/
+FilterEffectsDialog::SettingsFrame::SettingsFrame()
+    : _where(0)
+{
+     set_col_spacings(12);
+     show();
+}
+
+void FilterEffectsDialog::SettingsFrame::init(Gtk::VBox& box)
+{
+    box.pack_start(*this, false, false);
+}
+
+void FilterEffectsDialog::SettingsFrame::add_setting(Gtk::Widget& w, const Glib::ustring& label)
+{
+    Gtk::Label *lbl = new Gtk::Label(label + ":", Gtk::ALIGN_LEFT);
+
+    attach(*Gtk::manage(lbl), 0, 1, _where, _where + 1, Gtk::FILL, Gtk::FILL);
+    attach(w, 1, 2, _where, _where + 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL);
+
+    lbl->show();
+    w.show();
+
+    ++_where;
+}
+
+/*** FilterEffectsDialog ***/
+
+FilterEffectsDialog::FilterEffectsDialog() 
+    : Dialog ("dialogs.filtereffects", SP_VERB_DIALOG_FILTER_EFFECTS),
+      _add_primitive_type(FPConverter),
+      _add_primitive(Gtk::Stock::ADD),
+      _empty_settings("No primitive selected", Gtk::ALIGN_LEFT),
+      _blend_mode(BlendModeConverter),
+      _gaussianblur_stddeviation(1, 0, 100, 1, 0.01, 1),
+      _morphology_radius(1, 0, 100, 1, 0.01, 1),
+      _offset_dx(0, -100, 100, 1, 0.01, 1),
+      _offset_dy(0, -100, 100, 1, 0.01, 1),
+      _turbulence_basefrequency(1, 0, 100, 1, 0.01, 1),
+      _turbulence_numoctaves(1, 0, 100, 1, 0.01, 1),
+      _turbulence_seed(1, 0, 100, 1, 0.01, 1)
+{
+    // Initialize widget hierarchy
+    Gtk::HPaned* hpaned = Gtk::manage(new Gtk::HPaned);
+    Gtk::VBox* vb_prims = Gtk::manage(new Gtk::VBox);
+    Gtk::ScrolledWindow* sw_prims = Gtk::manage(new Gtk::ScrolledWindow);
+    Gtk::HBox* hb_prims = Gtk::manage(new Gtk::HBox);
+    Gtk::Frame* fr_settings = Gtk::manage(new Gtk::Frame("<b>Settings</b>"));
+    Gtk::Alignment* al_settings = Gtk::manage(new Gtk::Alignment);
+    get_vbox()->add(*hpaned);
+    hpaned->pack1(_filter_modifier);
+    hpaned->pack2(*vb_prims);
+    vb_prims->pack_start(*sw_prims);
+    vb_prims->pack_start(*hb_prims, false, false);
+    sw_prims->add(_primitive_list);
+    hb_prims->pack_end(_add_primitive, false, false);
+    hb_prims->pack_end(_add_primitive_type, false, false);
+    get_vbox()->pack_start(*fr_settings, false, false);
+    fr_settings->add(*al_settings);
+    al_settings->add(_settings);
+
+    // Primitive list
+    _primitive_model = Gtk::ListStore::create(_primitive_columns);
+    _primitive_list.set_reorderable(true);
+    _primitive_list.set_model(_primitive_model);
+    //_primitive_list.append_column_editable(_("_Primitive"), _primitive_columns.id);
+    _primitive_list.append_column("Type", _primitive_columns.type);
+    ((Gtk::CellRendererText*)_primitive_list.get_column(0)->get_first_cell_renderer())->
+        signal_edited().connect(sigc::mem_fun(*this, &FilterEffectsDialog::primitive_name_edited));
+    _filter_modifier.signal_selection_changed().connect(
+        sigc::mem_fun(*this, &FilterEffectsDialog::update_primitive_list));
+    _primitive_list.get_selection()->signal_changed().connect(
+        sigc::mem_fun(*this, &FilterEffectsDialog::update_settings_view));
+    _primitive_list.signal_button_press_event().connect_notify(
+        sigc::mem_fun(*this, &FilterEffectsDialog::primitive_list_button_press));
+    _primitive_list.signal_drag_end().connect(
+        sigc::mem_fun(*this, &FilterEffectsDialog::primitive_list_drag_end));
+
+    // Other widgets
+    sw_prims->set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
+    sw_prims->set_shadow_type(Gtk::SHADOW_IN);
+    al_settings->set_padding(0, 0, 12, 0);
+    fr_settings->set_shadow_type(Gtk::SHADOW_NONE);
+    ((Gtk::Label*)fr_settings->get_label_widget())->set_use_markup();
+    _add_primitive.signal_clicked().connect(sigc::mem_fun(*this, &FilterEffectsDialog::add_primitive));
+    _primitive_menu = create_popup_menu(*this, sigc::mem_fun(*this, &FilterEffectsDialog::duplicate_primitive),
+                                        sigc::mem_fun(*this, &FilterEffectsDialog::remove_primitive));
+    
+    show_all_children();
+    init_settings_widgets();
+    update_primitive_list();
+    update_settings_view();
+}
+
+FilterEffectsDialog::~FilterEffectsDialog()
+{
+}
+
+void FilterEffectsDialog::primitive_list_button_press(GdkEventButton* event)
+{
+    if((event->type == GDK_BUTTON_PRESS) && (event->button == 3)) {
+        const bool sensitive = get_selected_primitive() != NULL;
+        _primitive_menu->items()[0].set_sensitive(sensitive);
+        _primitive_menu->items()[1].set_sensitive(sensitive);
+        _primitive_menu->popup(event->button, event->time);
+    }
+}
+
+// Reorder the filter primitives to match the list order
+void FilterEffectsDialog::primitive_list_drag_end(const Glib::RefPtr<Gdk::DragContext>&)
+{
+    int ndx = 0;
+    SPFilter* filter = _filter_modifier.get_selected_filter();
+
+    for(Gtk::TreeModel::iterator iter = _primitive_model->children().begin();
+        iter != _primitive_model->children().end(); ++iter) {
+        SPFilterPrimitive* prim = (*iter)[_primitive_columns.primitive];
+        if(prim)
+            ;//reorder_primitive(filter, prim->repr->position(), ndx); /* FIXME */
+        std::cout << prim->repr->position();
+    }
+
+    sp_document_done(filter->document, SP_VERB_DIALOG_FILTER_EFFECTS, _("Reorder filter primitive"));
+}
+
+void FilterEffectsDialog::init_settings_widgets()
+{
+    _empty_settings.set_sensitive(false);
+    _settings.pack_start(_empty_settings);
+
+    _blend.init(_settings);
+    _blend.add_setting(_blend_mode, "Mode");
+    _blend_mode.signal_changed().connect(
+        sigc::bind(sigc::mem_fun(*this, &FilterEffectsDialog::set_attr), SP_ATTR_MODE));
+
+    _colormatrix.init(_settings);
+    _colormatrix.add_setting(_colormatrix_type, "Type");
+
+    _componenttransfer.init(_settings);
+
+    _composite.init(_settings);
+
+    _convolvematrix.init(_settings);
+    
+    _diffuselighting.init(_settings);
+
+    _displacementmap.init(_settings);
+
+    _flood.init(_settings);
+
+    _gaussianblur.init(_settings);
+    _gaussianblur.add_setting(_gaussianblur_stddeviation, "Standard Deviation");
+    _gaussianblur_stddeviation.signal_value_changed().connect(
+        sigc::bind(sigc::mem_fun(*this, &FilterEffectsDialog::set_attr), SP_ATTR_STDDEVIATION));
+
+    _image.init(_settings);
+    
+    _merge.init(_settings);
+
+    _morphology.init(_settings);
+    _morphology.add_setting(_morphology_operator, "Operator");
+    _morphology.add_setting(_morphology_radius, "Radius");
+
+    _offset.init(_settings);
+    _offset.add_setting(_offset_dx, "Delta X");
+    _offset_dx.signal_value_changed().connect(
+        sigc::bind(sigc::mem_fun(*this, &FilterEffectsDialog::set_attr), SP_ATTR_DX));
+    _offset.add_setting(_offset_dy, "Delta Y");
+    _offset_dy.signal_value_changed().connect(
+        sigc::bind(sigc::mem_fun(*this, &FilterEffectsDialog::set_attr), SP_ATTR_DY));
+
+    _specularlighting.init(_settings);
+
+    _tile.init(_settings);
+
+    _turbulence.init(_settings);
+    _turbulence.add_setting(_turbulence_basefrequency, "Base Frequency");
+    _turbulence.add_setting(_turbulence_numoctaves, "Octaves");
+    _turbulence.add_setting(_turbulence_seed, "Seed");
+    _turbulence.add_setting(_turbulence_stitchtiles, "Stitch Tiles");
+    _turbulence.add_setting(_turbulence_type, "Type");    
+}
+
+void FilterEffectsDialog::add_primitive()
+{
+    SPFilter* filter = _filter_modifier.get_selected_filter();
+    const EnumData<NR::FilterPrimitiveType>* data = _add_primitive_type.get_active_data();
+    
+    if(filter && data) {
+        SPFilterPrimitive* prim = filter_add_primitive(filter, data->name.c_str());
+
+        // Set default values
+        switch(data->id) {
+            case NR::NR_FILTER_BLEND:
+                sp_object_set(prim, SP_ATTR_MODE, BlendModeConverter.get_name(NR::BLEND_NORMAL).c_str());
+                break;
+            case NR::NR_FILTER_COLORMATRIX:
+                break;
+            case NR::NR_FILTER_COMPONENTTRANSFER:
+                break;
+            case NR::NR_FILTER_COMPOSITE:
+                break;
+            case NR::NR_FILTER_CONVOLVEMATRIX:
+                break;
+            case NR::NR_FILTER_DIFFUSELIGHTING:
+                break;
+            case NR::NR_FILTER_DISPLACEMENTMAP:
+                break;
+            case NR::NR_FILTER_FLOOD:
+                break;
+            case NR::NR_FILTER_GAUSSIANBLUR:
+                sp_object_set(prim, SP_ATTR_STDDEVIATION, "1");
+                break;
+            case NR::NR_FILTER_IMAGE:
+                break;
+            case NR::NR_FILTER_MERGE:
+                break;
+            case NR::NR_FILTER_MORPHOLOGY:
+                break;
+            case NR::NR_FILTER_OFFSET:
+                sp_object_set(prim, SP_ATTR_DX, "0");
+                sp_object_set(prim, SP_ATTR_DY, "0");
+                break;
+            case NR::NR_FILTER_SPECULARLIGHTING:
+                break;
+            case NR::NR_FILTER_TILE:
+                break;
+            case NR::NR_FILTER_TURBULENCE:
+                break;
+            default:
+                break;
+        }
+
+        update_primitive_list();
+        select_primitive(prim);
+
+        sp_document_done(filter->document, SP_VERB_DIALOG_FILTER_EFFECTS, _("Add filter primitive"));
+    }
+}
+
+void FilterEffectsDialog::remove_primitive()
+{
+    Gtk::TreeModel::iterator i = _primitive_list.get_selection()->get_selected();
+
+    if(i) {
+        SPFilterPrimitive* prim = (*i)[_primitive_columns.primitive];
+       
+        sp_repr_unparent(prim->repr);
+
+        sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_DIALOG_FILTER_EFFECTS,
+                         _("Remove filter primitive"));
+
+        update_primitive_list();
+    }
+}
+
+void FilterEffectsDialog::duplicate_primitive()
+{
+    SPFilter* filter = _filter_modifier.get_selected_filter();
+    SPFilterPrimitive* origprim = get_selected_primitive();
+
+    if(filter && origprim) {
+        Inkscape::XML::Node *repr;
+        repr = SP_OBJECT_REPR(origprim)->duplicate(SP_OBJECT_REPR(origprim)->document());
+        SP_OBJECT_REPR(filter)->appendChild(repr);
+
+        sp_document_done(filter->document, SP_VERB_DIALOG_FILTER_EFFECTS, _("Duplicate filter primitive"));
+
+        update_primitive_list();
+    }
+}
+
+// Edits the id of the primitive at path
+void FilterEffectsDialog::primitive_name_edited(const Glib::ustring& path, const Glib::ustring& text)
+{
+    Gtk::TreeModel::iterator i = _primitive_model->get_iter(path);
+
+    if(i)
+        try_id_change((*i)[_primitive_columns.primitive], text);
+}
+  
+void FilterEffectsDialog::set_attr(const SPAttributeEnum attr)
+{
+    Gtk::TreeModel::iterator i = _primitive_list.get_selection()->get_selected();
+
+    if(i) {
+        SPFilter *filter = _filter_modifier.get_selected_filter();
+        SPFilterPrimitive* prim = (*i)[_primitive_columns.primitive];
+        std::ostringstream os;
+        Glib::ustring val;
+
+        if(attr == SP_ATTR_MODE) {
+            val = _blend_mode.get_active_data()->name;
+        }
+        else if(attr == SP_ATTR_STDDEVIATION) {
+            os << _gaussianblur_stddeviation.get_value();
+            val = os.str();
+        }
+        else if(attr == SP_ATTR_DX) {
+            os << _offset_dx.get_value();
+            val = os.str();
+        }
+        else if(attr == SP_ATTR_DY) {
+            os << _offset_dy.get_value();
+            val = os.str();
+        }
+
+        sp_object_set(prim, attr, val.c_str());
+        filter->requestModified(SP_OBJECT_MODIFIED_FLAG);
+
+        sp_document_done(filter->document, SP_VERB_DIALOG_FILTER_EFFECTS, _("Set filter primitive attribute"));
+    }
+}
+
+/* Add all filter primitives in the current to the list.
+   Keeps the same selection if possible, otherwise selects the first element */
+void FilterEffectsDialog::update_primitive_list()
+{
+    SPFilter* f = _filter_modifier.get_selected_filter();
+    const SPFilterPrimitive* active_prim = get_selected_primitive();
+    bool active_found = false;
+
+    _primitive_model->clear();
+
+    if(f) {
+        _primitive_box.set_sensitive(true);
+
+        for(SPObject *prim_obj = f->children;
+                prim_obj && SP_IS_FILTER_PRIMITIVE(prim_obj);
+                prim_obj = prim_obj->next) {
+            SPFilterPrimitive *prim = SP_FILTER_PRIMITIVE(prim_obj);
+            if(prim) {
+                Gtk::TreeModel::Row row = *_primitive_model->append();
+                row[_primitive_columns.primitive] = prim;
+                row[_primitive_columns.type_id] = FPConverter.get_id_from_name(prim->repr->name());
+                row[_primitive_columns.type] = FPConverter.get_label(row[_primitive_columns.type_id]);
+                row[_primitive_columns.id] = SP_OBJECT_ID(prim);
+
+                if(prim == active_prim) {
+                    _primitive_list.get_selection()->select(row);
+                    active_found = true;
+                }
+            }
+        }
+
+        if(!active_found && _primitive_model->children().begin())
+            _primitive_list.get_selection()->select(_primitive_model->children().begin());
+    }
+    else {
+        _primitive_box.set_sensitive(false);
+    }
+}
+
+void FilterEffectsDialog::update_settings_view()
+{
+    SPFilterPrimitive* prim = get_selected_primitive();
+
+    // Hide all the settings except for common
+    Glib::ListHandle<Widget*> c = _settings.get_children();
+    for(Glib::ListHandle<Widget*>::iterator iter = c.begin();
+        iter != c.end(); ++iter) {
+        (*iter)->hide();
+    }
+
+    _settings.set_sensitive(false);
+    _empty_settings.show();
+
+    if(prim) {
+        const NR::FilterPrimitiveType tid = FPConverter.get_id_from_name(prim->repr->name());
+        if(tid == NR::NR_FILTER_BLEND) {
+            _blend.show();
+            const gchar* val = prim->repr->attribute("mode");
+            if(val)
+                _blend_mode.set_active(BlendModeConverter.get_id_from_name(val));
+        }
+        else if(tid == NR::NR_FILTER_COLORMATRIX)
+            _colormatrix.show();
+        else if(tid == NR::NR_FILTER_COMPONENTTRANSFER)
+            _componenttransfer.show();
+        else if(tid == NR::NR_FILTER_COMPOSITE)
+            _composite.show();
+        else if(tid == NR::NR_FILTER_CONVOLVEMATRIX)
+            _convolvematrix.show();
+        else if(tid == NR::NR_FILTER_DIFFUSELIGHTING)
+            _diffuselighting.show();
+        else if(tid == NR::NR_FILTER_DISPLACEMENTMAP)
+            _displacementmap.show();
+        else if(tid == NR::NR_FILTER_FLOOD)
+            _flood.show();
+        else if(tid == NR::NR_FILTER_GAUSSIANBLUR) {
+            _gaussianblur.show();
+            _gaussianblur_stddeviation.set_value(((SPGaussianBlur*)prim)->stdDeviation.getNumber());
+        }
+        else if(tid == NR::NR_FILTER_IMAGE)
+            _image.show();
+        else if(tid == NR::NR_FILTER_MERGE)
+            _merge.show();
+        else if(tid == NR::NR_FILTER_MORPHOLOGY)
+            _morphology.show();
+        else if(tid == NR::NR_FILTER_OFFSET) {
+            _offset.show();
+            _offset_dx.set_value(((SPFeOffset*)prim)->dx);
+            _offset_dy.set_value(((SPFeOffset*)prim)->dy);
+        }
+        else if(tid == NR::NR_FILTER_SPECULARLIGHTING)
+            _specularlighting.show();
+        else if(tid == NR::NR_FILTER_TILE)
+            _tile.show();
+        else if(tid == NR::NR_FILTER_TURBULENCE)
+            _turbulence.show();
+
+        _settings.set_sensitive(true);
+        _empty_settings.hide();
+    }
+}
+
+SPFilterPrimitive* FilterEffectsDialog::get_selected_primitive()
+{
+    if(_filter_modifier.get_selected_filter()) {
+        Gtk::TreeModel::iterator i = _primitive_list.get_selection()->get_selected();
+        if(i)
+            return (*i)[_primitive_columns.primitive];
+    }
+
+    return 0;
+}
+
+void FilterEffectsDialog::select_primitive(SPFilterPrimitive* prim)
+{
+    for(Gtk::TreeIter i = _primitive_model->children().begin();
+        i != _primitive_model->children().end(); ++i) {
+        if((*i)[_primitive_columns.primitive] == prim)
+            _primitive_list.get_selection()->select(i);
+    }
+}
+
+} // namespace Dialog
+} // namespace UI
+} // namespace Inkscape
+
+/*
+  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/dialog/filter-effects-dialog.h b/src/ui/dialog/filter-effects-dialog.h
new file mode 100644 (file)
index 0000000..3438348
--- /dev/null
@@ -0,0 +1,193 @@
+/**
+ * \brief Filter Effects dialog
+ *
+ * Authors:
+ *   Nicholas Bishop <nicholasbishop@gmail.com>
+ *
+ * Copyright (C) 2007 Authors
+ *
+ * Released under GNU GPL.  Read the file 'COPYING' for more information.
+ */
+
+#ifndef INKSCAPE_UI_DIALOG_FILTER_EFFECTS_H
+#define INKSCAPE_UI_DIALOG_FILTER_EFFECTS_H
+
+#include <gtkmm/adjustment.h>
+#include <gtkmm/alignment.h>
+#include <gtkmm/box.h>
+#include <gtkmm/buttonbox.h>
+#include <gtkmm/comboboxtext.h>
+#include <gtkmm/drawingarea.h>
+#include <gtkmm/frame.h>
+#include <gtkmm/liststore.h>
+#include <gtkmm/menu.h>
+#include <gtkmm/treeview.h>
+
+#include "attributes.h"
+#include "dialog.h"
+#include "sp-filter.h"
+#include "ui/widget/filter-effect-chooser.h"
+#include "ui/widget/notebook-page.h"
+#include "ui/widget/spin-slider.h"
+
+using namespace Inkscape::UI::Widget;
+
+namespace Inkscape {
+namespace UI {
+namespace Dialog {
+
+class FilterEffectsDialog : public Dialog {
+public:
+    FilterEffectsDialog();
+    virtual ~FilterEffectsDialog();
+
+    static FilterEffectsDialog *create() { return new FilterEffectsDialog(); }
+private:
+    class FilterModifier : public Gtk::VBox, public FilterEffectChooser
+    {
+    public:
+        FilterModifier();
+
+        virtual SPFilter* get_selected_filter();
+        virtual void select_filter(const SPFilter*);
+        virtual Glib::SignalProxy0<void> signal_selection_changed();
+    private:
+        void filter_list_button_press(GdkEventButton*);
+        void add_filter();
+        void remove_filter();
+        void duplicate_filter();
+        void filter_name_edited(const Glib::ustring& path, const Glib::ustring& text);
+
+        Gtk::TreeView _list;
+        Gtk::Button _add;
+        Glib::RefPtr<Gtk::Menu> _menu;
+    };
+
+    class PrimitiveColumns : public Gtk::TreeModel::ColumnRecord
+    {
+    public:
+        PrimitiveColumns()
+        {
+            add(primitive);
+            add(type_id);
+            add(type);
+            add(id);
+        }
+
+        Gtk::TreeModelColumn<SPFilterPrimitive*> primitive;
+        Gtk::TreeModelColumn<NR::FilterPrimitiveType> type_id;
+        Gtk::TreeModelColumn<Glib::ustring> type;
+        Gtk::TreeModelColumn<Glib::ustring> id;
+    };
+
+    class SettingsFrame : public Gtk::Table
+    {
+    public:
+        SettingsFrame();
+
+        void init(Gtk::VBox& box);
+        void add_setting(Gtk::Widget& w, const Glib::ustring& label);
+    private:
+        Gtk::Alignment _alignment;
+        Gtk::Table _table;
+        int _where;
+    };
+
+    void init_settings_widgets();
+
+    // Handlers
+    void add_primitive();
+    void remove_primitive();
+    void duplicate_primitive();
+    void primitive_name_edited(const Glib::ustring& path, const Glib::ustring& text);
+    void primitive_list_button_press(GdkEventButton* event);
+    void primitive_list_drag_end(const Glib::RefPtr<Gdk::DragContext>&);
+
+    void set_attr(const SPAttributeEnum);
+    void update_settings_view();
+    void update_primitive_list();
+
+    SPFilterPrimitive* get_selected_primitive();
+    void select_primitive(SPFilterPrimitive *prim);
+
+    // Filter effect selection
+    FilterModifier _filter_modifier;
+
+    // View/add primitives
+    Gtk::VBox _primitive_box;
+    Gtk::TreeView _primitive_list;
+    Glib::RefPtr<Gtk::ListStore> _primitive_model;
+    PrimitiveColumns _primitive_columns;
+    Glib::RefPtr<Gtk::Menu> _primitive_menu;
+    UI::Widget::ComboBoxEnum<NR::FilterPrimitiveType> _add_primitive_type;
+    Gtk::Button _add_primitive;
+
+    // Right pane (filter effect primitive settings)
+    Gtk::VBox _settings;
+    Gtk::Label _empty_settings;
+
+    SettingsFrame _blend;
+    UI::Widget::ComboBoxEnum<NR::FilterBlendMode> _blend_mode;
+
+    SettingsFrame _colormatrix;
+    Gtk::ComboBoxText _colormatrix_type;
+
+    SettingsFrame _componenttransfer;
+
+    SettingsFrame _composite;
+
+    SettingsFrame _convolvematrix;
+
+    SettingsFrame _diffuselighting;
+
+    SettingsFrame _displacementmap;
+
+    SettingsFrame _flood;
+
+    SettingsFrame _gaussianblur;
+    SpinSlider _gaussianblur_stddeviation;
+
+    SettingsFrame _image;
+
+    SettingsFrame _merge;
+
+    SettingsFrame _morphology;
+    Gtk::ComboBoxText _morphology_operator;
+    SpinSlider _morphology_radius;
+
+    SettingsFrame _offset;
+    SpinSlider _offset_dx;
+    SpinSlider _offset_dy;
+
+    SettingsFrame _specularlighting;
+
+    SettingsFrame _tile;
+
+    SettingsFrame _turbulence;
+    SpinSlider _turbulence_basefrequency;
+    SpinSlider _turbulence_numoctaves;
+    SpinSlider _turbulence_seed;
+    Gtk::ComboBoxText _turbulence_stitchtiles;
+    Gtk::ComboBoxText _turbulence_type;
+
+
+    FilterEffectsDialog(FilterEffectsDialog const &d);
+    FilterEffectsDialog& operator=(FilterEffectsDialog const &d);
+};
+
+} // namespace Dialog
+} // namespace UI
+} // namespace Inkscape
+
+#endif // INKSCAPE_UI_DIALOG_FILTER_EFFECTS_H
+
+/*
+  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 :
index 7ceb86660e0107bdb5e7122473ca78808202e3bf..03e491340614c70ccee815bff957ca489ef0bff9 100644 (file)
@@ -83,6 +83,7 @@ Gtk::StockID const LAYER_TO_BOTTOM("layer-to-bottom");
 // Object menu
 Gtk::StockID const FILL_STROKE("fill-stroke");
 Gtk::StockID const OBJECT_PROPERTIES("object-properties");
+Gtk::StockID const FILTER_EFFECTS("filter-effects");
 Gtk::StockID const GROUP("group");
 Gtk::StockID const UNGROUP("upgroup");
 Gtk::StockID const RAISE("raise");
index 069ab66f315abe66b4e12965cd92448af7aafc00..733edacdb50a54139b0a856d7f8c2bd0f92a3c83 100644 (file)
@@ -86,6 +86,7 @@ extern Gtk::StockID const LAYER_TO_BOTTOM;
 // Object menu
 extern Gtk::StockID const FILL_STROKE;
 extern Gtk::StockID const OBJECT_PROPERTIES;
+extern Gtk::StockID const FILTER_EFFECTS;
 extern Gtk::StockID const GROUP;
 extern Gtk::StockID const UNGROUP;
 extern Gtk::StockID const RAISE;
index ca298cd5dbd4f3ed4c648a711fa34864aec44e87..8e423c8fbf140b5ada637cd6c30e068ada4ea29c 100644 (file)
@@ -635,6 +635,9 @@ EditWidget::initMenuActions()
                                       Stock::OBJECT_PROPERTIES),
                   sigc::mem_fun(*this, &EditWidget::onDialogObjectProperties));
 
+    _act_grp->add(Gtk::Action::create("FilterEffects",
+                                      Stock::FILTER_EFFECTS));
+
     _act_grp->add(Gtk::Action::create("Group",
                                       Stock::GROUP, Glib::ustring(),
                                       _("PLACEHOLDER, do not translate")));
index 30d52de01446a84b71cddffbe508d903e79c6b73..72fb9cfc25723e8c8a213d32eca5940f50c17ede 100644 (file)
@@ -18,6 +18,9 @@ ui_widget_libuiwidget_a_SOURCES =     \
        ui/widget/entity-entry.h        \
        ui/widget/entry.cpp      \
        ui/widget/entry.h        \
+       ui/widget/filter-effect-chooser.h \
+       ui/widget/filter-effect-chooser.cpp \
+       ui/widget/filter-effect-enums.h \
        ui/widget/handlebox.cpp         \
        ui/widget/handlebox.h           \
        ui/widget/icon-widget.cpp       \
@@ -48,6 +51,8 @@ ui_widget_libuiwidget_a_SOURCES =     \
        ui/widget/scalar.h              \
        ui/widget/selected-style.h      \
        ui/widget/selected-style.cpp    \
+       ui/widget/spin-slider.h         \
+       ui/widget/spin-slider.cpp       \
        ui/widget/style-swatch.h        \
        ui/widget/style-swatch.cpp      \
        ui/widget/svg-canvas.cpp        \
diff --git a/src/ui/widget/filter-effect-chooser.cpp b/src/ui/widget/filter-effect-chooser.cpp
new file mode 100644 (file)
index 0000000..fd8f46e
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * Filter effect selection selection widget
+ *
+ * Author:
+ *   Nicholas Bishop <nicholasbishop@gmail.com>
+ *
+ * Copyright (C) 2007 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <glibmm/i18n.h>
+
+#include "desktop.h"
+#include "desktop-handles.h"
+#include "document.h"
+#include "filter-effect-chooser.h"
+#include "inkscape.h"
+#include "ui/dialog/dialog-manager.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+FilterEffectChooser::FilterEffectChooser()
+{
+    _model = Gtk::ListStore::create(_columns);
+
+    g_signal_connect(G_OBJECT(INKSCAPE), "activate_desktop",
+                     G_CALLBACK(&FilterEffectChooser::on_activate_desktop), this);
+
+
+    on_activate_desktop(INKSCAPE, SP_ACTIVE_DESKTOP, this);
+}
+
+void FilterEffectChooser::on_activate_desktop(Inkscape::Application*, SPDesktop* desktop, FilterEffectChooser* fec)
+{
+    fec->update_filters();
+
+    fec->_doc_replaced.disconnect();
+    fec->_doc_replaced = desktop->connectDocumentReplaced(
+        sigc::mem_fun(fec, &FilterEffectChooser::on_document_replaced));
+
+    fec->_resource_changed.disconnect();
+    fec->_resource_changed =
+        sp_document_resources_changed_connect(sp_desktop_document(desktop), "filter",
+                                              sigc::mem_fun(fec, &FilterEffectChooser::update_filters));
+}
+
+void FilterEffectChooser::on_document_replaced(SPDesktop* desktop, SPDocument* document)
+{
+    update_filters();
+}
+
+/* Add all filters in the document to the combobox.
+   Keeps the same selection if possible, otherwise selects the first element */
+void FilterEffectChooser::update_filters()
+{
+    SPDesktop* desktop = SP_ACTIVE_DESKTOP;
+    SPDocument* document = sp_desktop_document(desktop);
+    const GSList* filters = sp_document_get_resource_list(document, "filter");
+
+    _model->clear();
+
+    for(const GSList *l = filters; l; l = l->next) {
+        Gtk::TreeModel::Row row = *_model->append();
+        SPFilter* f = (SPFilter*)l->data;
+        row[_columns.filter] = f;
+        const gchar* id = SP_OBJECT_ID(f);
+        row[_columns.id] = id ? id : "";
+    }
+}
+
+SimpleFilterModifier::SimpleFilterModifier()
+    : _lb_blend(_("_Blend mode:")),
+      _lb_blur(_("B_lur:"), Gtk::ALIGN_LEFT),
+      _lb_filter(_("F_ilter:"), Gtk::ALIGN_LEFT),
+      _blend(BlendModeConverter),
+      _blur(0, 0, 100, 1, 0.01, 1),
+      _edit_filters(_("_Edit"))
+{
+    add(_hb_blend);
+    add(_vb_blur);
+    add(_hb_filter);
+    _hb_blend.pack_start(_lb_blend, false, false);
+    _hb_blend.pack_start(_blend);
+    _vb_blur.add(_lb_blur);
+    _vb_blur.add(_blur);
+    _hb_filter.pack_start(_lb_filter, false, false);
+    _hb_filter.pack_start(_hb_filter_sub);
+    _hb_filter_sub.add(_filter);
+    _hb_filter_sub.add(_edit_filters);
+
+    show_all_children();
+
+    signal_show().connect(sigc::mem_fun(*this, &SimpleFilterModifier::blend_mode_changed));
+    _hb_blend.set_spacing(12);
+    _hb_filter.set_spacing(12);
+    _lb_blend.set_use_underline();
+    _lb_blend.set_mnemonic_widget(_blend);
+    _lb_blur.set_use_underline();
+    _lb_blur.set_mnemonic_widget(_blur.get_scale());
+    _lb_filter.set_use_underline();
+    _lb_filter.set_mnemonic_widget(_filter);
+    _blend.add_row("Filter");
+    _blend.signal_changed().connect(sigc::mem_fun(*this, &SimpleFilterModifier::blend_mode_changed));
+    _blend.signal_changed().connect(signal_blend_blur_changed());
+    _blur.signal_value_changed().connect(signal_blend_blur_changed());
+    _filter.set_model(_model);
+    _filter.pack_start(_columns.id);
+    _edit_filters.signal_clicked().connect(sigc::mem_fun(*this, &SimpleFilterModifier::show_filter_dialog));
+    _edit_filters.set_use_underline();
+
+    update_filters();
+}
+
+Glib::SignalProxy0<void> SimpleFilterModifier::signal_selection_changed()
+{
+    return _filter.signal_changed();
+}
+
+SPFilter* SimpleFilterModifier::get_selected_filter()
+{
+    Gtk::TreeModel::iterator i = _filter.get_active();
+
+    if(i)
+        return (*i)[_columns.filter];
+
+    return 0;
+}
+
+void SimpleFilterModifier::select_filter(const SPFilter* filter)
+{
+    if(filter) {
+        for(Gtk::TreeModel::iterator i = _model->children().begin();
+            i != _model->children().end(); ++i) {
+            if((*i)[_columns.filter] == filter) {
+                _filter.set_active(i);
+                break;
+            }
+        }
+    }
+}
+
+sigc::signal<void>& SimpleFilterModifier::signal_blend_blur_changed()
+{
+    return _signal_blend_blur_changed;
+}
+
+const Glib::ustring SimpleFilterModifier::get_blend_mode()
+{
+    return _blend.get_active_row_number() == 5 ? "filter" : _blend.get_active_data()->name;
+}
+
+void SimpleFilterModifier::set_blend_mode(const int val)
+{
+    _blend.set_active(val);
+}
+
+double SimpleFilterModifier::get_blur_value() const
+{
+    return _blur.get_value();
+}
+
+void SimpleFilterModifier::set_blur_value(const double val)
+{
+    _blur.set_value(val);
+}
+
+void SimpleFilterModifier::set_blur_sensitive(const bool s)
+{
+    _blur.set_sensitive(s);
+}
+
+void SimpleFilterModifier::update_filters()
+{
+    const SPFilter* active_filter = get_selected_filter();
+
+    FilterEffectChooser::update_filters();
+
+    if(_model->children().empty()) {
+        // Set state if no filters exist
+        Gtk::TreeModel::Row row = *_model->prepend();
+        row[_columns.filter] = 0;
+        row[_columns.id] = "None";
+        _filter.set_sensitive(false);
+        _filter.set_active(0);
+    }
+    else {
+        _filter.set_sensitive(true);
+        select_filter(active_filter);
+    }
+}
+
+void SimpleFilterModifier::show_filter_dialog()
+{
+    SP_ACTIVE_DESKTOP->_dlg_mgr->showDialog("FilterEffectsDialog");
+}
+
+void SimpleFilterModifier::blend_mode_changed()
+{
+    if(_blend.get_active_row_number() == 5) {
+        _vb_blur.hide();
+        _hb_filter.show();
+    }
+    else {
+        _hb_filter.hide();
+        _vb_blur.show();
+    }
+}
+
+/*** From filter-effect-enums.h ***/
+const EnumData<NR::FilterPrimitiveType> FPData[NR::NR_FILTER_ENDPRIMITIVETYPE] = {
+    {NR::NR_FILTER_BLEND,             _("Blend"),              "svg:feBlend"},
+    {NR::NR_FILTER_COLORMATRIX,       _("Color Matrix"),       "svg:feColorMatrix"},
+    {NR::NR_FILTER_COMPONENTTRANSFER, _("Component Transfer"), "svg:feComponentTransfer"},
+    {NR::NR_FILTER_COMPOSITE,         _("Composite"),          "svg:feComposite"},
+    {NR::NR_FILTER_CONVOLVEMATRIX,    _("Convolve Matrix"),    "svg:feConvolveMatrix"},
+    {NR::NR_FILTER_DIFFUSELIGHTING,   _("Diffuse Lighting"),   "svg:feDiffuseLighting"},
+    {NR::NR_FILTER_DISPLACEMENTMAP,   _("Displacement Map"),   "svg:feDisplacementMap"},
+    {NR::NR_FILTER_FLOOD,             _("Flood"),              "svg:feFlood"},
+    {NR::NR_FILTER_GAUSSIANBLUR,      _("Gaussian Blur"),      "svg:feGaussianBlur"},
+    {NR::NR_FILTER_IMAGE,             _("Image"),              "svg:feImage"},
+    {NR::NR_FILTER_MERGE,             _("Merge"),              "svg:feMerge"},
+    {NR::NR_FILTER_MORPHOLOGY,        _("Morphology"),         "svg:feMorphology"},
+    {NR::NR_FILTER_OFFSET,            _("Offset"),             "svg:feOffset"},
+    {NR::NR_FILTER_SPECULARLIGHTING,  _("Specular Lighting"),  "svg:feSpecularLighting"},
+    {NR::NR_FILTER_TILE,              _("Tile"),               "svg:feTile"},
+    {NR::NR_FILTER_TURBULENCE,        _("Turbulence"),         "svg:feTurbulence"}
+};
+const Converter<NR::FilterPrimitiveType> FPConverter(FPData, NR::NR_FILTER_ENDPRIMITIVETYPE);
+const EnumData<NR::FilterBlendMode> BlendModeData[NR::BLEND_ENDMODE] = {
+    {NR::BLEND_NORMAL, _("Normal"), "normal"},
+    {NR::BLEND_MULTIPLY, _("Multiply"), "multiply"},
+    {NR::BLEND_SCREEN, _("Screen"), "screen"},
+    {NR::BLEND_DARKEN, _("Darken"), "darken"},
+    {NR::BLEND_LIGHTEN, _("Lighten"), "lighten"}
+};
+const Converter<NR::FilterBlendMode> BlendModeConverter(BlendModeData, NR::BLEND_ENDMODE);
+
+}
+}
+}
+
+/*
+  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/filter-effect-chooser.h b/src/ui/widget/filter-effect-chooser.h
new file mode 100644 (file)
index 0000000..182ce45
--- /dev/null
@@ -0,0 +1,120 @@
+#ifndef __FILTER_EFFECT_CHOOSER_H__
+#define __FILTER_EFFECT_CHOOSER_H__
+
+/*
+ * Filter effect selection selection widget
+ *
+ * Author:
+ *   Nicholas Bishop <nicholasbishop@gmail.com>
+ *
+ * Copyright (C) 2007 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <gtkmm/box.h>
+#include <gtkmm/combobox.h>
+#include <gtkmm/liststore.h>
+#include <gtkmm/treeview.h>
+
+#include "filter-effect-enums.h"
+#include "labelled.h"
+#include "spin-slider.h"
+#include "sp-filter.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+class FilterEffectChooser
+{
+public:
+    virtual ~FilterEffectChooser() {}
+
+    virtual Glib::SignalProxy0<void> signal_selection_changed() = 0;
+    virtual SPFilter* get_selected_filter() = 0;
+    virtual void select_filter(const SPFilter*) = 0;
+protected:
+    FilterEffectChooser();
+
+    class Columns : public Gtk::TreeModel::ColumnRecord
+    {
+    public:
+        Columns()
+        {
+            add(filter);
+            add(id);
+        }
+
+        Gtk::TreeModelColumn<SPFilter*> filter;
+        Gtk::TreeModelColumn<Glib::ustring> id;
+    };
+
+    virtual void update_filters();
+
+    Glib::RefPtr<Gtk::ListStore> _model;
+    Columns _columns;
+private:
+    static void on_activate_desktop(Inkscape::Application*, SPDesktop*, FilterEffectChooser*);
+    void on_document_replaced(SPDesktop*, SPDocument*);
+
+    sigc::connection _doc_replaced;
+    sigc::connection _resource_changed;
+
+    Gtk::TreeView::Column _filter_column;
+};
+
+/* Allows basic control over feBlend and feGaussianBlur effects,
+   with an option to use the full filter effect controls. */
+class SimpleFilterModifier : public Gtk::VBox, public FilterEffectChooser
+{
+public:
+    SimpleFilterModifier();
+
+    virtual Glib::SignalProxy0<void> signal_selection_changed();
+    virtual SPFilter* get_selected_filter();
+    virtual void select_filter(const SPFilter*);
+
+    sigc::signal<void>& signal_blend_blur_changed();
+
+    const Glib::ustring get_blend_mode();
+    // Uses blend mode enum values, or -1 for a complex filter
+    void set_blend_mode(const int);
+
+    double get_blur_value() const;
+    void set_blur_value(const double);
+    void set_blur_sensitive(const bool);
+protected:
+    virtual void update_filters();
+private:
+    void show_filter_dialog();
+    void blend_mode_changed();
+
+    Gtk::HBox _hb_blend;
+    Gtk::VBox _vb_blur;
+    Gtk::HBox _hb_filter, _hb_filter_sub;
+    Gtk::Label _lb_blend, _lb_blur, _lb_filter;
+    ComboBoxEnum<NR::FilterBlendMode> _blend;
+    SpinSlider _blur;
+    Gtk::ComboBox _filter;
+    Gtk::Button _edit_filters;
+
+    sigc::signal<void> _signal_blend_blur_changed;
+};
+
+}
+}
+}
+
+#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 :
diff --git a/src/ui/widget/filter-effect-enums.h b/src/ui/widget/filter-effect-enums.h
new file mode 100644 (file)
index 0000000..3ac68a1
--- /dev/null
@@ -0,0 +1,156 @@
+/**
+ * \brief Simplified management of enumerations for filter effects
+ *
+ * Authors:
+ *   Nicholas Bishop <nicholasbishop@gmail.com>
+ *
+ * Copyright (C) 2007 Authors
+ *
+ * Released under GNU GPL.  Read the file 'COPYING' for more information.
+ */
+
+#ifndef INKSCAPE_UI_WIDGET_FILTER_EFFECT_ENUMS_H
+#define INKSCAPE_UI_WIDGET_FILTER_EFFECT_ENUMS_H
+
+#include "display/nr-filter-blend.h"
+#include "display/nr-filter-types.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+template<typename E> struct EnumData
+{
+    E id;
+    const Glib::ustring label;
+    const Glib::ustring name;
+};
+
+template<typename E> class Converter
+{
+public:
+    typedef EnumData<E> Data;
+
+    Converter(const EnumData<E>* cd, const int endval)
+        : end(endval), _data(cd)
+    {}
+
+    E get_id_from_label(const Glib::ustring& label) const
+    {
+        for(int i = 0; i < end; ++i) {
+            if(_data[i].label == label)
+                return (E)i;
+        }
+
+        return (E)0;
+    }
+
+    E get_id_from_name(const Glib::ustring& name) const
+    {
+        for(int i = 0; i < end; ++i) {
+            if(_data[i].name == name)
+                return (E)i;
+        }
+
+        return (E)0;
+    }
+
+    const Glib::ustring& get_label(const E e) const
+    {
+        return _data[e].label;
+    }
+
+    const Glib::ustring& get_name(const E e) const
+    {
+        return _data[e].name;
+    }
+
+    const EnumData<E>& data(const int i) const
+    {
+        return _data[i];
+    }
+
+    const int end;
+private:
+    const EnumData<E>* _data;
+};
+
+template<typename E> class ComboBoxEnum : public Gtk::ComboBox
+{
+public:
+    ComboBoxEnum(const Converter<E>& c)
+        : _converter(c)
+    {
+        _model = Gtk::ListStore::create(_columns);
+        set_model(_model);
+
+        pack_start(_columns.label);
+
+        // Initialize list
+        for(int i = 0; i < _converter.end; ++i) {
+            Gtk::TreeModel::Row row = *_model->append();
+            const EnumData<E>* data = &_converter.data(i);
+            row[_columns.data] = data;
+            row[_columns.label] = _converter.get_label(data->id);
+        }
+
+        set_active(0);
+    }
+    
+    const EnumData<E>* get_active_data()
+    {
+        Gtk::TreeModel::iterator i = this->get_active();
+        if(i)
+            return (*i)[_columns.data];
+        return 0;
+    }
+
+    void add_row(const Glib::ustring& s)
+    {
+        Gtk::TreeModel::Row row = *_model->append();
+        row[_columns.data] = 0;
+        row[_columns.label] = s;
+    }
+private:
+    class Columns : public Gtk::TreeModel::ColumnRecord
+    {
+    public:
+        Columns()
+        {
+            add(data);
+            add(label);
+        }
+
+        Gtk::TreeModelColumn<const EnumData<E>*> data;
+        Gtk::TreeModelColumn<Glib::ustring> label;
+    };
+
+    Columns _columns;
+    Glib::RefPtr<Gtk::ListStore> _model;
+    const Converter<E>& _converter;
+};
+
+/*** Filter Primitives ***/
+extern const EnumData<NR::FilterPrimitiveType> FPData[NR::NR_FILTER_ENDPRIMITIVETYPE];
+extern const Converter<NR::FilterPrimitiveType> FPConverter;
+
+/*** feBlend Mode ***/
+extern const EnumData<NR::FilterBlendMode> BlendModeData[NR::BLEND_ENDMODE];
+extern const Converter<NR::FilterBlendMode> BlendModeConverter;
+
+}
+}
+}
+
+#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 :
diff --git a/src/ui/widget/spin-slider.cpp b/src/ui/widget/spin-slider.cpp
new file mode 100644 (file)
index 0000000..678b8e3
--- /dev/null
@@ -0,0 +1,87 @@
+/**
+ * \brief Groups an HScale and a SpinButton together using the same Adjustment
+ *
+ * Author:
+ *   Nicholas Bishop <nicholasbishop@gmail.com>
+ *
+ * Copyright (C) 2007 Author
+ *
+ * Released under GNU GPL.  Read the file 'COPYING' for more information.
+ */
+
+#include "spin-slider.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+
+SpinSlider::SpinSlider(double value, double lower, double upper, double step_inc,
+                       double climb_rate, int digits)
+    : _adjustment(value, lower, upper, step_inc),
+      _scale(_adjustment), _spin(_adjustment, climb_rate, digits)
+{
+    pack_start(_scale);
+    pack_start(_spin, false, false);
+
+    _scale.set_draw_value(false);
+
+    show_all_children();
+}
+
+Glib::SignalProxy0<void> SpinSlider::signal_value_changed()
+{
+    return _adjustment.signal_value_changed();
+}
+
+double SpinSlider::get_value() const
+{
+    return _adjustment.get_value();
+}
+
+void SpinSlider::set_value(const double val)
+{
+    _adjustment.set_value(val);
+}
+
+const Gtk::Adjustment& SpinSlider::get_adjustment() const
+{
+    return _adjustment;
+}
+Gtk::Adjustment& SpinSlider::get_adjustment()
+{
+    return _adjustment;
+}
+
+const Gtk::HScale& SpinSlider::get_scale() const
+{
+    return _scale;
+}
+Gtk::HScale& SpinSlider::get_scale()
+{
+    return _scale;
+}
+
+const Gtk::SpinButton& SpinSlider::get_spin_button() const
+{
+    return _spin;
+}
+Gtk::SpinButton& SpinSlider::get_spin_button()
+{
+    return _spin;
+}
+
+} // namespace Widget
+} // namespace UI
+} // namespace Inkscape
+
+/* 
+  Local Variables:
+  mode:c++
+  c-file-style:"stroustrup"
+  c-file-offsets:((innamespace . 0)(inline-open . 0))
+  indent-tabs-mode:nil
+  fill-column:99
+  End:
+*/
+// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/ui/widget/spin-slider.h b/src/ui/widget/spin-slider.h
new file mode 100644 (file)
index 0000000..50bd1dc
--- /dev/null
@@ -0,0 +1,64 @@
+/**
+ * \brief Groups an HScale and a SpinButton together using the same Adjustment
+ *
+ * Author:
+ *   Nicholas Bishop <nicholasbishop@gmail.com>
+ *
+ * Copyright (C) 2007 Author
+ *
+ * Released under GNU GPL.  Read the file 'COPYING' for more information.
+ */
+
+#ifndef INKSCAPE_UI_WIDGET_SPIN_SLIDER_H
+#define INKSCAPE_UI_WIDGET_SPIN_SLIDER_H
+
+#include <gtkmm/adjustment.h>
+#include <gtkmm/box.h>
+#include <gtkmm/scale.h>
+#include <gtkmm/spinbutton.h>
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+class SpinSlider : public Gtk::HBox
+{
+public:
+    SpinSlider(double value, double lower, double upper, double step_inc,
+              double climb_rate, int digits);
+
+    // Shortcuts to _adjustment
+    Glib::SignalProxy0<void> signal_value_changed();
+    double get_value() const;
+    void set_value(const double);
+
+    const Gtk::Adjustment& get_adjustment() const;
+    Gtk::Adjustment& get_adjustment();
+    
+    const Gtk::HScale& get_scale() const;
+    Gtk::HScale& get_scale();
+
+    const Gtk::SpinButton& get_spin_button() const;
+    Gtk::SpinButton& get_spin_button();
+private:
+    Gtk::Adjustment _adjustment;
+    Gtk::HScale _scale;
+    Gtk::SpinButton _spin;
+};
+
+} // namespace Widget
+} // namespace UI
+} // namespace Inkscape
+
+#endif // INKSCAPE_UI_WIDGET_SPIN_SLIDER_H
+
+/* 
+  Local Variables:
+  mode:c++
+  c-file-style:"stroustrup"
+  c-file-offsets:((innamespace . 0)(inline-open . 0))
+  indent-tabs-mode:nil
+  fill-column:99
+  End:
+*/
+// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
index 04a49f37c4bd3a58d9ad03275d5e548d96a5f974..5a05407762a7d4f3e8f262f4fad141c44345a07c 100644 (file)
@@ -1725,6 +1725,9 @@ DialogVerb::perform(SPAction *action, void *data, void *pdata)
         case SP_VERB_DIALOG_LAYERS:
             show_panel( Inkscape::UI::Dialogs::LayersPanel::getInstance(), "dialogs.layers", SP_VERB_DIALOG_LAYERS );
             break;
+        case SP_VERB_DIALOG_FILTER_EFFECTS:
+            dt->_dlg_mgr->showDialog("FilterEffectsDialog");
+            break;
         default:
             break;
     }
@@ -2500,6 +2503,8 @@ Verb *Verb::_base_verbs[] = {
                    N_("Query information about extensions"), NULL),
     new DialogVerb(SP_VERB_DIALOG_LAYERS, "DialogLayers", N_("Layer_s..."),
                    N_("View Layers"), "layers"),
+    new DialogVerb(SP_VERB_DIALOG_FILTER_EFFECTS, "DialogFilterEffects", N_("Filter Effects..."),
+                   N_("Manage SVG filter effects"), NULL),
 
     /* Help */
     new HelpVerb(SP_VERB_HELP_KEYS, "HelpKeys", N_("_Keys and Mouse"),
index f8e25f94df78782cda5398f69500ba791778405c..aa589e36dd99a6647f2ddf5c0424097c9fa2a587 100644 (file)
@@ -214,6 +214,7 @@ enum {
     SP_VERB_DIALOG_INPUT,
     SP_VERB_DIALOG_EXTENSIONEDITOR,
     SP_VERB_DIALOG_LAYERS,
+    SP_VERB_DIALOG_FILTER_EFFECTS,
     /* Help */
     SP_VERB_HELP_KEYS,
     SP_VERB_HELP_ABOUT_EXTENSIONS,