Code

remove many unnecessary to_2geom and from_2geom calls
[inkscape.git] / src / ui / dialog / filter-effects-dialog.cpp
index 73d6d013e442970a6c8bff4f75e0807c285c04e1..d577a6cc427b787a64b8d24b114adf255f99f6d9 100644 (file)
@@ -3,6 +3,8 @@
  *
  * Authors:
  *   Nicholas Bishop <nicholasbishop@gmail.org>
+ *   Rodrigo Kumpera <kumpera@gmail.com>
+ *   Felipe C. da S. Sanches <felipe.sanches@gmail.com>
  *
  * Copyright (C) 2007 Authors
  *
@@ -22,6 +24,7 @@
 #include <gtkmm/scrolledwindow.h>
 #include <gtkmm/spinbutton.h>
 #include <gtkmm/stock.h>
+#include <gtkmm/tooltips.h>
 #include <glibmm/i18n.h>
 
 #include "application/application.h"
 #include "desktop.h"
 #include "desktop-handles.h"
 #include "dialog-manager.h"
+#include "dir-util.h"
 #include "document.h"
 #include "filter-chemistry.h"
 #include "filter-effects-dialog.h"
 #include "filter-enums.h"
 #include "inkscape.h"
+#include "path-prefix.h"
+#include "prefs-utils.h"
 #include "selection.h"
 #include "sp-feblend.h"
 #include "sp-fecolormatrix.h"
 
 #include "style.h"
 #include "svg/svg-color.h"
+#include "ui/dialog/filedialog.h"
 #include "verbs.h"
 #include "xml/node.h"
 #include "xml/node-observer.h"
 #include "xml/repr.h"
 #include <sstream>
 
+#include "io/sys.h"
 #include <iostream>
 
 using namespace NR;
@@ -128,14 +136,15 @@ private:
 class CheckButtonAttr : public Gtk::CheckButton, public AttrWidget
 {
 public:
-    CheckButtonAttr(const Glib::ustring& label,
+    CheckButtonAttr(bool def, const Glib::ustring& label,
                     const Glib::ustring& tv, const Glib::ustring& fv,
-                    const SPAttributeEnum a)
+                    const SPAttributeEnum a, char* tip_text)
         : Gtk::CheckButton(label),
-          AttrWidget(a),
+          AttrWidget(a, def),
           _true_val(tv), _false_val(fv)
     {
         signal_toggled().connect(signal_attr_changed().make_slot());
+        if (tip_text) _tt.set_tip(*this, tip_text);
     }
 
     Glib::ustring get_as_attribute() const
@@ -151,6 +160,8 @@ public:
                 set_active(true);
             else if(_false_val == val)
                 set_active(false);
+        } else {
+            set_active(get_default()->as_bool());
         }
     }
 private:
@@ -161,10 +172,11 @@ class SpinButtonAttr : public Gtk::SpinButton, public AttrWidget
 {
 public:
     SpinButtonAttr(double lower, double upper, double step_inc,
-                   double climb_rate, int digits, const SPAttributeEnum a)
+                   double climb_rate, int digits, const SPAttributeEnum a, double def, char* tip_text)
         : Gtk::SpinButton(climb_rate, digits),
-          AttrWidget(a)
+          AttrWidget(a, def)
     {
+        if (tip_text) _tt.set_tip(*this, tip_text);
         set_range(lower, upper);
         set_increments(step_inc, step_inc * 5);
 
@@ -174,19 +186,49 @@ public:
     Glib::ustring get_as_attribute() const
     {
         const double val = get_value();
-        
+
         if(get_digits() == 0)
             return Glib::Ascii::dtostr((int)val);
         else
             return Glib::Ascii::dtostr(val);
     }
-    
+
     void set_from_attribute(SPObject* o)
     {
         const gchar* val = attribute_value(o);
-        if(val)
+        if(val){
             set_value(Glib::Ascii::strtod(val));
+        } else {
+            set_value(get_default()->as_double());
+        }
+    }
+};
+
+template< typename T> class ComboWithTooltip : public Gtk::EventBox
+{
+public:
+    ComboWithTooltip<T>(T default_value, const Util::EnumDataConverter<T>& c, const SPAttributeEnum a = SP_ATTR_INVALID, char* tip_text = NULL)
+    {
+        if (tip_text) {
+            _tt.set_tip(*this, tip_text);
+        }
+        combo = new ComboBoxEnum<T>(default_value, c, a);
+        add(*combo);
+        show_all();
     }
+
+    ~ComboWithTooltip()
+    {
+        delete combo;
+    }
+
+    ComboBoxEnum<T>* get_attrwidget()
+    {
+        return combo;
+    }
+private:
+    Gtk::Tooltips _tt;
+    ComboBoxEnum<T>* combo;
 };
 
 // Contains an arbitrary number of spin buttons that use seperate attributes
@@ -194,10 +236,12 @@ class MultiSpinButton : public Gtk::HBox
 {
 public:
     MultiSpinButton(double lower, double upper, double step_inc,
-                    double climb_rate, int digits, std::vector<SPAttributeEnum> attrs)
+                    double climb_rate, int digits, std::vector<SPAttributeEnum> attrs, std::vector<double> default_values, std::vector<char*> tip_text)
     {
+        g_assert(attrs.size()==default_values.size());
+        g_assert(attrs.size()==tip_text.size());
         for(unsigned i = 0; i < attrs.size(); ++i) {
-            _spins.push_back(new SpinButtonAttr(lower, upper, step_inc, climb_rate, digits, attrs[i]));
+            _spins.push_back(new SpinButtonAttr(lower, upper, step_inc, climb_rate, digits, attrs[i], default_values[i], tip_text[i]));
             pack_start(*_spins.back(), false, false);
         }
     }
@@ -220,11 +264,13 @@ private:
 class DualSpinButton : public Gtk::HBox, public AttrWidget
 {
 public:
-    DualSpinButton(double lower, double upper, double step_inc,
-                   double climb_rate, int digits, const SPAttributeEnum a)
-        : AttrWidget(a),
+    DualSpinButton(char* def, double lower, double upper, double step_inc,
+                   double climb_rate, int digits, const SPAttributeEnum a, char* tt1, char* tt2)
+        : AttrWidget(a, def), //TO-DO: receive default num-opt-num as parameter in the constructor
           _s1(climb_rate, digits), _s2(climb_rate, digits)
     {
+        if (tt1) _tt.set_tip(_s1, tt1);
+        if (tt2) _tt.set_tip(_s2, tt2);
         _s1.set_range(lower, upper);
         _s2.set_range(lower, upper);
         _s1.set_increments(step_inc, step_inc * 5);
@@ -251,7 +297,7 @@ public:
     {
         double v1 = _s1.get_value();
         double v2 = _s2.get_value();
-        
+
         if(_s1.get_digits() == 0) {
             v1 = (int)v1;
             v2 = (int)v2;
@@ -263,12 +309,15 @@ public:
     virtual void set_from_attribute(SPObject* o)
     {
         const gchar* val = attribute_value(o);
+        NumberOptNumber n;
         if(val) {
-            NumberOptNumber n;
             n.set(val);
-            _s1.set_value(n.getNumber());
-            _s2.set_value(n.getOptNumber());
+        } else {
+            n.set(get_default()->as_charptr());
         }
+        _s1.set_value(n.getNumber());
+        _s2.set_value(n.getOptNumber());
+
     }
 private:
     Gtk::SpinButton _s1, _s2;
@@ -277,22 +326,23 @@ private:
 class ColorButton : public Gtk::ColorButton, public AttrWidget
 {
 public:
-    ColorButton(const SPAttributeEnum a)
-        : AttrWidget(a)
+    ColorButton(unsigned int def, const SPAttributeEnum a, char* tip_text)
+        : AttrWidget(a, def)
     {
         signal_color_set().connect(signal_attr_changed().make_slot());
+        if (tip_text) _tt.set_tip(*this, tip_text);
 
         Gdk::Color col;
         col.set_rgb(65535, 65535, 65535);
         set_color(col);
     }
-    
+
     // Returns the color in 'rgb(r,g,b)' form.
     Glib::ustring get_as_attribute() const
     {
         std::ostringstream os;
         const Gdk::Color c = get_color();
-        const int r = c.get_red() / 257, g = c.get_green() / 257, b = c.get_blue() / 257;
+        const int r = c.get_red() / 257, g = c.get_green() / 257, b = c.get_blue() / 257;//TO-DO: verify this. This sounds a lot strange! shouldn't it be 256?
         os << "rgb(" << r << "," << g << "," << b << ")";
         return os.str();
     }
@@ -301,13 +351,16 @@ public:
     void set_from_attribute(SPObject* o)
     {
         const gchar* val = attribute_value(o);
+        guint32 i = 0;
         if(val) {
-            const guint32 i = sp_svg_read_color(val, 0xFFFFFFFF);
-            const int r = SP_RGBA32_R_U(i), g = SP_RGBA32_G_U(i), b = SP_RGBA32_B_U(i);
-            Gdk::Color col;
-            col.set_rgb(r * 257, g * 257, b * 257);
-            set_color(col);
+            i = sp_svg_read_color(val, 0xFFFFFFFF);
+        } else {
+            i = (guint32) get_default()->as_uint();
         }
+        const int r = SP_RGBA32_R_U(i), g = SP_RGBA32_G_U(i), b = SP_RGBA32_B_U(i);
+        Gdk::Color col;
+        col.set_rgb(r * 256, g * 256, b * 256);
+        set_color(col);
     }
 };
 
@@ -315,7 +368,7 @@ public:
 class FilterEffectsDialog::MatrixAttr : public Gtk::Frame, public AttrWidget
 {
 public:
-    MatrixAttr(const SPAttributeEnum a)
+    MatrixAttr(const SPAttributeEnum a, char* tip_text = NULL)
         : AttrWidget(a), _locked(false)
     {
         _model = Gtk::ListStore::create(_columns);
@@ -324,6 +377,7 @@ public:
         _tree.show();
         add(_tree);
         set_shadow_type(Gtk::SHADOW_IN);
+        if (tip_text) _tt.set_tip(_tree, tip_text);
     }
 
     std::vector<double> get_values() const
@@ -354,17 +408,17 @@ public:
     Glib::ustring get_as_attribute() const
     {
         std::ostringstream os;
-        
+
         for(Gtk::TreeIter iter = _model->children().begin();
             iter != _model->children().end(); ++iter) {
             for(unsigned c = 0; c < _tree.get_columns().size(); ++c) {
                 os << (*iter)[_columns.cols[c]] << " ";
             }
         }
-        
+
         return os.str();
     }
-    
+
     void set_from_attribute(SPObject* o)
     {
         if(o) {
@@ -423,8 +477,9 @@ private:
 
             for(int r = 0; r < rows; ++r) {
                 Gtk::TreeRow row = *(_model->append());
+                // Default to identity matrix
                 for(int c = 0; c < cols; ++c, ++ndx)
-                    row[_columns.cols[c]] = ndx < (int)values->size() ? (*values)[ndx] : 0;
+                    row[_columns.cols[c]] = ndx < (int)values->size() ? (*values)[ndx] : (r == c ? 1 : 0);
             }
         }
     }
@@ -448,7 +503,7 @@ class FilterEffectsDialog::ColorMatrixValues : public Gtk::Frame, public AttrWid
 public:
     ColorMatrixValues()
         : AttrWidget(SP_ATTR_VALUES),
-          _matrix(SP_ATTR_VALUES),
+          _matrix(SP_ATTR_VALUES, _("This matrix determines a linear transform on colour space. Each line affects one of the color components. Each column determines how much of each color component from the input is passed to the output. The last column does not depend on input colors, so can be used to adjust a constant component value.")),
           _saturation(0, 0, 1, 0.1, 0.01, 2, SP_ATTR_VALUES),
           _angle(0, 0, 360, 0.1, 0.01, 1, SP_ATTR_VALUES),
           _label(_("None"), Gtk::ALIGN_LEFT),
@@ -543,6 +598,128 @@ private:
     double _angle_store;
 };
 
+static Inkscape::UI::Dialog::FileOpenDialog * selectFeImageFileInstance = NULL;
+
+//Displays a chooser for feImage input
+//It may be a filename or the id for an SVG Element
+//described in xlink:href syntax
+class FileOrElementChooser : public Gtk::HBox, public AttrWidget
+{
+public:
+    FileOrElementChooser(const SPAttributeEnum a)
+        : AttrWidget(a)
+    {
+        pack_start(_entry, false, false);
+        pack_start(_fromFile, false, false);
+        pack_start(_fromSVGElement, false, false);
+
+        _fromFile.set_label(_("Image File"));
+        _fromFile.signal_clicked().connect(sigc::mem_fun(*this, &FileOrElementChooser::select_file));
+
+        _fromSVGElement.set_label(_("Selected SVG Element"));
+        _fromSVGElement.signal_clicked().connect(sigc::mem_fun(*this, &FileOrElementChooser::select_svg_element));
+
+        _entry.signal_changed().connect(signal_attr_changed().make_slot());
+
+        show_all();
+
+    }
+
+    // Returns the element in xlink:href form.
+    Glib::ustring get_as_attribute() const
+    {
+        return _entry.get_text();
+    }
+
+
+    void set_from_attribute(SPObject* o)
+    {
+        const gchar* val = attribute_value(o);
+        if(val) {
+            _entry.set_text(val);
+        } else {
+            _entry.set_text("");
+        }
+    }
+
+    void set_desktop(SPDesktop* d){
+        _desktop = d;
+    }
+
+private:
+    void select_svg_element(){
+        Inkscape::Selection* sel = sp_desktop_selection(_desktop);
+        if (sel->isEmpty()) return;
+        Inkscape::XML::Node* node = (Inkscape::XML::Node*) g_slist_nth_data((GSList *)sel->reprList(), 0);
+        if (!node || !node->matchAttributeName("id")) return;
+
+        std::ostringstream xlikhref;
+        xlikhref << "#" << node->attribute("id");
+        _entry.set_text(xlikhref.str());
+    }
+
+    void select_file(){
+
+        //# Get the current directory for finding files
+        Glib::ustring open_path;
+        char *attr = (char *)prefs_get_string_attribute("dialogs.open", "path");
+        if (attr)
+            open_path = attr;
+
+        //# Test if the open_path directory exists
+        if (!Inkscape::IO::file_test(open_path.c_str(),
+                  (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
+            open_path = "";
+
+        //# If no open path, default to our home directory
+        if (open_path.size() < 1)
+            {
+            open_path = g_get_home_dir();
+            open_path.append(G_DIR_SEPARATOR_S);
+            }
+
+        //# Create a dialog if we don't already have one
+        if (!selectFeImageFileInstance) {
+            selectFeImageFileInstance =
+                  Inkscape::UI::Dialog::FileOpenDialog::create(
+                     *_desktop->getToplevel(),
+                     open_path,
+                     Inkscape::UI::Dialog::SVG_TYPES,/*TODO: any image, not justy svg*/
+                     (char const *)_("Select an image to be used as feImage input"));
+        }
+
+        //# Show the dialog
+        bool const success = selectFeImageFileInstance->show();
+        if (!success)
+            return;
+
+        //# User selected something.  Get name and type
+        Glib::ustring fileName = selectFeImageFileInstance->getFilename();
+
+        if (fileName.size() > 0) {
+
+            Glib::ustring newFileName = Glib::filename_to_utf8(fileName);
+
+            if ( newFileName.size() > 0)
+                fileName = newFileName;
+            else
+                g_warning( "ERROR CONVERTING OPEN FILENAME TO UTF-8" );
+
+            open_path = fileName;
+            open_path.append(G_DIR_SEPARATOR_S);
+            prefs_set_string_attribute("dialogs.open", "path", open_path.c_str());
+
+            _entry.set_text(fileName);
+        }
+        return;
+    }
+
+    Gtk::Entry _entry;
+    Gtk::Button _fromFile;
+    Gtk::Button _fromSVGElement;
+    SPDesktop* _desktop;
+};
+
 class FilterEffectsDialog::Settings
 {
 public:
@@ -553,11 +730,13 @@ public:
     {
         _groups.resize(_max_types);
         _attrwidgets.resize(_max_types);
+        _size_group = Gtk::SizeGroup::create(Gtk::SIZE_GROUP_HORIZONTAL);
 
         for(int i = 0; i < _max_types; ++i) {
             _groups[i] = new Gtk::VBox;
-            b.add(*_groups[i]);
+            b.pack_start(*_groups[i], false, false);
         }
+        _current_type = 0;
     }
 
     ~Settings()
@@ -596,32 +775,44 @@ public:
         _current_type = t;
     }
 
+    void add_no_params()
+    {
+        Gtk::Label* lbl = Gtk::manage(new Gtk::Label(_("This SVG filter effect does not require any parameters.")));
+        add_widget(lbl, "");
+    }
+
+    void add_notimplemented()
+    {
+        Gtk::Label* lbl = Gtk::manage(new Gtk::Label(_("This SVG filter effect is not yet implemented in Inkscape.")));
+        add_widget(lbl, "");
+    }
+
     // LightSource
     LightSourceControl* add_lightsource();
 
     // CheckBox
-    CheckButtonAttr* add_checkbutton(const SPAttributeEnum attr, const Glib::ustring& label,
-                                     const Glib::ustring& tv, const Glib::ustring& fv)
+    CheckButtonAttr* add_checkbutton(bool def, const SPAttributeEnum attr, const Glib::ustring& label,
+                                     const Glib::ustring& tv, const Glib::ustring& fv, char* tip_text = NULL)
     {
-        CheckButtonAttr* cb = new CheckButtonAttr(label, tv, fv, attr);
+        CheckButtonAttr* cb = new CheckButtonAttr(def, label, tv, fv, attr, tip_text);
         add_widget(cb, "");
         add_attr_widget(cb);
         return cb;
     }
 
     // ColorButton
-    ColorButton* add_color(const SPAttributeEnum attr, const Glib::ustring& label)
+    ColorButton* add_color(unsigned int def, const SPAttributeEnum attr, const Glib::ustring& label, char* tip_text = NULL)
     {
-        ColorButton* col = new ColorButton(attr);
+        ColorButton* col = new ColorButton(def, attr, tip_text);
         add_widget(col, label);
         add_attr_widget(col);
         return col;
     }
 
     // Matrix
-    MatrixAttr* add_matrix(const SPAttributeEnum attr, const Glib::ustring& label)
+    MatrixAttr* add_matrix(const SPAttributeEnum attr, const Glib::ustring& label, char* tip_text)
     {
-        MatrixAttr* conv = new MatrixAttr(attr);
+        MatrixAttr* conv = new MatrixAttr(attr, tip_text);
         add_widget(conv, label);
         add_attr_widget(conv);
         return conv;
@@ -630,17 +821,17 @@ public:
     // ColorMatrixValues
     ColorMatrixValues* add_colormatrixvalues(const Glib::ustring& label)
     {
-        ColorMatrixValues* cmv = new ColorMatrixValues;
+        ColorMatrixValues* cmv = new ColorMatrixValues();
         add_widget(cmv, label);
         add_attr_widget(cmv);
         return cmv;
     }
 
     // SpinSlider
-    SpinSlider* add_spinslider(const SPAttributeEnum attr, const Glib::ustring& label,
-                         const double lo, const double hi, const double step_inc, const double climb, const int digits)
+    SpinSlider* add_spinslider(double def, const SPAttributeEnum attr, const Glib::ustring& label,
+                         const double lo, const double hi, const double step_inc, const double climb, const int digits, char* tip_text = NULL)
     {
-        SpinSlider* spinslider = new SpinSlider(lo, lo, hi, step_inc, climb, digits, attr);
+        SpinSlider* spinslider = new SpinSlider(def, lo, hi, step_inc, climb, digits, attr, tip_text);
         add_widget(spinslider, label);
         add_attr_widget(spinslider);
         return spinslider;
@@ -649,67 +840,99 @@ public:
     // DualSpinSlider
     DualSpinSlider* add_dualspinslider(const SPAttributeEnum attr, const Glib::ustring& label,
                                        const double lo, const double hi, const double step_inc,
-                                       const double climb, const int digits)
+                                       const double climb, const int digits, char* tip_text1 = NULL, char* tip_text2 = NULL)
     {
-        DualSpinSlider* dss = new DualSpinSlider(lo, lo, hi, step_inc, climb, digits, attr);
+        DualSpinSlider* dss = new DualSpinSlider(lo, lo, hi, step_inc, climb, digits, attr, tip_text1, tip_text2);
         add_widget(dss, label);
         add_attr_widget(dss);
         return dss;
     }
 
     // DualSpinButton
-    DualSpinButton* add_dualspinbutton(const SPAttributeEnum attr, const Glib::ustring& label,
+    DualSpinButton* add_dualspinbutton(char* defalt_value, const SPAttributeEnum attr, const Glib::ustring& label,
                                        const double lo, const double hi, const double step_inc,
-                                       const double climb, const int digits)
+                                       const double climb, const int digits, char* tip1 = NULL, char* tip2 = NULL)
     {
-        DualSpinButton* dsb = new DualSpinButton(lo, hi, step_inc, climb, digits, attr);
+        DualSpinButton* dsb = new DualSpinButton(defalt_value, lo, hi, step_inc, climb, digits, attr, tip1, tip2);
         add_widget(dsb, label);
         add_attr_widget(dsb);
         return dsb;
     }
 
     // MultiSpinButton
-    MultiSpinButton* add_multispinbutton(const SPAttributeEnum attr1, const SPAttributeEnum attr2,
+    MultiSpinButton* add_multispinbutton(double def1, double def2, const SPAttributeEnum attr1, const SPAttributeEnum attr2,
                                          const Glib::ustring& label, const double lo, const double hi,
-                                         const double step_inc, const double climb, const int digits)
+                                         const double step_inc, const double climb, const int digits, char* tip1 = NULL, char* tip2 = NULL)
     {
         std::vector<SPAttributeEnum> attrs;
         attrs.push_back(attr1);
         attrs.push_back(attr2);
-        MultiSpinButton* msb = new MultiSpinButton(lo, hi, step_inc, climb, digits, attrs);
+
+        std::vector<double> default_values;
+        default_values.push_back(def1);
+        default_values.push_back(def2);
+
+        std::vector<char*> tips;
+        tips.push_back(tip1);
+        tips.push_back(tip2);
+
+        MultiSpinButton* msb = new MultiSpinButton(lo, hi, step_inc, climb, digits, attrs, default_values, tips);
         add_widget(msb, label);
         for(unsigned i = 0; i < msb->get_spinbuttons().size(); ++i)
             add_attr_widget(msb->get_spinbuttons()[i]);
         return msb;
     }
-    MultiSpinButton* add_multispinbutton(const SPAttributeEnum attr1, const SPAttributeEnum attr2,
+    MultiSpinButton* add_multispinbutton(double def1, double def2, double def3, const SPAttributeEnum attr1, const SPAttributeEnum attr2,
                                          const SPAttributeEnum attr3, const Glib::ustring& label, const double lo,
-                                         const double hi, const double step_inc, const double climb, const int digits)
+                                         const double hi, const double step_inc, const double climb, const int digits, char* tip1 = NULL, char* tip2 = NULL, char* tip3 = NULL)
     {
         std::vector<SPAttributeEnum> attrs;
         attrs.push_back(attr1);
         attrs.push_back(attr2);
         attrs.push_back(attr3);
-        MultiSpinButton* msb = new MultiSpinButton(lo, hi, step_inc, climb, digits, attrs);
+
+        std::vector<double> default_values;
+        default_values.push_back(def1);
+        default_values.push_back(def2);
+        default_values.push_back(def3);
+
+        std::vector<char*> tips;
+        tips.push_back(tip1);
+        tips.push_back(tip2);
+        tips.push_back(tip3);
+
+        MultiSpinButton* msb = new MultiSpinButton(lo, hi, step_inc, climb, digits, attrs, default_values, tips);
         add_widget(msb, label);
         for(unsigned i = 0; i < msb->get_spinbuttons().size(); ++i)
             add_attr_widget(msb->get_spinbuttons()[i]);
         return msb;
     }
 
+    // FileOrElementChooser
+    FileOrElementChooser* add_fileorelement(const SPAttributeEnum attr, const Glib::ustring& label)
+    {
+        FileOrElementChooser* foech = new FileOrElementChooser(attr);
+        foech->set_desktop(_dialog.getDesktop());
+        add_widget(foech, label);
+        add_attr_widget(foech);
+        return foech;
+    }
+
     // ComboBoxEnum
-    template<typename T> ComboBoxEnum<T>* add_combo(const SPAttributeEnum attr,
+    template<typename T> ComboBoxEnum<T>* add_combo(T default_value, const SPAttributeEnum attr,
                                   const Glib::ustring& label,
-                                  const Util::EnumDataConverter<T>& conv)
+                                  const Util::EnumDataConverter<T>& conv, char* tip_text = NULL)
     {
-        ComboBoxEnum<T>* combo = new ComboBoxEnum<T>(conv, attr);
+        ComboWithTooltip<T>* combo = new ComboWithTooltip<T>(default_value, conv, attr, tip_text);
         add_widget(combo, label);
-        add_attr_widget(combo);
-        return combo;
+        add_attr_widget(combo->get_attrwidget());
+        return combo->get_attrwidget();
     }
 private:
+    Gtk::Tooltips _tt;
+
     void add_attr_widget(AttrWidget* a)
-    {    
+    {
         _attrwidgets[_current_type].push_back(a);
         a->signal_attr_changed().connect(sigc::bind(_set_attr_slot, a));
     }
@@ -721,14 +944,14 @@ private:
         Gtk::Label *lbl = 0;
         Gtk::HBox *hb = Gtk::manage(new Gtk::HBox);
         hb->set_spacing(12);
-        
+
         if(label != "") {
             lbl = Gtk::manage(new Gtk::Label(label + (label == "" ? "" : ":"), Gtk::ALIGN_LEFT));
             hb->pack_start(*lbl, false, false);
-            _dialog._sizegroup->add_widget(*lbl);
+            _size_group->add_widget(*lbl);
             lbl->show();
         }
-        
+
         hb->pack_start(*w);
         _groups[_current_type]->pack_start(*hb);
         hb->show();
@@ -736,10 +959,10 @@ private:
     }
 
     std::vector<Gtk::VBox*> _groups;
-
+    Glib::RefPtr<Gtk::SizeGroup> _size_group;
     FilterEffectsDialog& _dialog;
     SetAttrSlot _set_attr_slot;
-    std::vector<std::vector<AttrWidget*> > _attrwidgets;
+    std::vector<std::vector< AttrWidget*> > _attrwidgets;
     int _current_type, _max_types;
 };
 
@@ -768,18 +991,20 @@ public:
         // FIXME: these range values are complete crap
 
         _settings.type(LIGHT_DISTANT);
-        _settings.add_spinslider(SP_ATTR_AZIMUTH, _("Azimuth"), 0, 360, 1, 1, 0);
-        _settings.add_spinslider(SP_ATTR_ELEVATION, _("Elevation"), 0, 360, 1, 1, 0);
+        _settings.add_spinslider(0, SP_ATTR_AZIMUTH, _("Azimuth"), 0, 360, 1, 1, 0, _("Direction angle for the light source on the XY plane, in degrees"));
+        _settings.add_spinslider(0, SP_ATTR_ELEVATION, _("Elevation"), 0, 360, 1, 1, 0, _("Direction angle for the light source on the YZ plane, in degrees"));
 
         _settings.type(LIGHT_POINT);
-        _settings.add_multispinbutton(SP_ATTR_X, SP_ATTR_Y, SP_ATTR_Z, _("Location"), -99999, 99999, 1, 100, 0);
+        _settings.add_multispinbutton(/*default x:*/ (double) 0, /*default y:*/ (double) 0, /*default z:*/ (double) 0, SP_ATTR_X, SP_ATTR_Y, SP_ATTR_Z, _("Location"), -99999, 99999, 1, 100, 0, _("X coordinate"), _("Y coordinate"), _("Z coordinate"));
 
         _settings.type(LIGHT_SPOT);
-        _settings.add_multispinbutton(SP_ATTR_X, SP_ATTR_Y, SP_ATTR_Z, _("Location"), -99999, 99999, 1, 100, 0);
-        _settings.add_multispinbutton(SP_ATTR_POINTSATX, SP_ATTR_POINTSATY, SP_ATTR_POINTSATZ,
-                                      _("Points At"), -99999, 99999, 1, 100, 0);
-        _settings.add_spinslider(SP_ATTR_SPECULAREXPONENT, _("Specular Exponent"), 1, 100, 1, 1, 0);
-        _settings.add_spinslider(SP_ATTR_LIMITINGCONEANGLE, _("Cone Angle"), 1, 100, 1, 1, 0);
+        _settings.add_multispinbutton(/*default x:*/ (double) 0, /*default y:*/ (double) 0, /*default z:*/ (double) 0, SP_ATTR_X, SP_ATTR_Y, SP_ATTR_Z, _("Location"), -99999, 99999, 1, 100, 0, _("X coordinate"), _("Y coordinate"), _("Z coordinate"));
+        _settings.add_multispinbutton(/*default x:*/ (double) 0, /*default y:*/ (double) 0, /*default z:*/ (double) 0,
+                                      SP_ATTR_POINTSATX, SP_ATTR_POINTSATY, SP_ATTR_POINTSATZ,
+                                      _("Points At"), -99999, 99999, 1, 100, 0, _("X coordinate"), _("Y coordinate"), _("Z coordinate"));
+        _settings.add_spinslider(1, SP_ATTR_SPECULAREXPONENT, _("Specular Exponent"), 1, 100, 1, 1, 0, _("Exponent value controlling the focus for the light source"));
+        //TODO: here I have used 100 degrees as default value. But spec says that if not specified, no limiting cone is applied. So, there should be a way for the user to set a "no limiting cone" option.
+        _settings.add_spinslider(100, SP_ATTR_LIMITINGCONEANGLE, _("Cone Angle"), 1, 100, 1, 1, 0, _("This is the angle between the spot light axis (i.e. the axis between the light source and the point to which it is pointing at) and the spot light cone. No light is projected outside this cone."));
     }
 
     Gtk::VBox& get_box()
@@ -799,7 +1024,7 @@ protected:
         _locked = true;
 
         SPObject* child = o->children;
-        
+
         if(SP_IS_FEDISTANTLIGHT(child))
             _light_source.set_active(0);
         else if(SP_IS_FEPOINTLIGHT(child))
@@ -852,7 +1077,7 @@ private:
         _box.hide_all();
         _box.show();
         _light_box.show_all();
-        
+
         SPFilterPrimitive* prim = _dialog._primitive_list.get_selected();
         if(prim && prim->children)
             _settings.show_and_update(_light_source.get_active_data()->id, prim->children);
@@ -892,7 +1117,7 @@ Glib::RefPtr<Gtk::Menu> create_popup_menu(Gtk::Widget& parent, sigc::slot<void>
 
 /*** FilterModifier ***/
 FilterEffectsDialog::FilterModifier::FilterModifier(FilterEffectsDialog& d)
-    : _dialog(d), _add(Gtk::Stock::ADD), _observer(new SignalObserver)
+    : _dialog(d), _add(Gtk::Stock::NEW), _observer(new SignalObserver)
 {
     Gtk::ScrolledWindow* sw = Gtk::manage(new Gtk::ScrolledWindow);
     pack_start(*sw);
@@ -901,18 +1126,20 @@ FilterEffectsDialog::FilterModifier::FilterModifier(FilterEffectsDialog& d)
 
     _model = Gtk::ListStore::create(_columns);
     _list.set_model(_model);
-    const int selcol = _list.append_column("", _cell_sel);
+    _cell_toggle.set_active(true);
+    const int selcol = _list.append_column("", _cell_toggle);
     Gtk::TreeViewColumn* col = _list.get_column(selcol - 1);
     if(col)
-       col->add_attribute(_cell_sel.property_sel(), _columns.sel);
-    _list.append_column(_("_Filter"), _columns.label);
+       col->add_attribute(_cell_toggle.property_active(), _columns.sel);
+    _list.append_column_editable(_("_Filter"), _columns.label);
+    ((Gtk::CellRendererText*)_list.get_column(1)->get_first_cell_renderer())->
+        signal_edited().connect(sigc::mem_fun(*this, &FilterEffectsDialog::FilterModifier::on_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));
+    _cell_toggle.signal_toggled().connect(sigc::mem_fun(*this, &FilterModifier::on_selection_toggled));
     _list.signal_button_release_event().connect_notify(
         sigc::mem_fun(*this, &FilterModifier::filter_list_button_release));
     _menu = create_popup_menu(*this, sigc::mem_fun(*this, &FilterModifier::duplicate_filter),
@@ -929,7 +1156,7 @@ FilterEffectsDialog::FilterModifier::FilterModifier(FilterEffectsDialog& d)
     g_signal_connect(G_OBJECT(INKSCAPE), "activate_desktop",
                      G_CALLBACK(&FilterModifier::on_activate_desktop), this);
 
-    on_activate_desktop(INKSCAPE, SP_ACTIVE_DESKTOP, this);
+    on_activate_desktop(INKSCAPE, d.getDesktop(), this);
     update_filters();
 }
 
@@ -939,46 +1166,8 @@ FilterEffectsDialog::FilterModifier::~FilterModifier()
    _doc_replaced.disconnect();
 }
 
-FilterEffectsDialog::FilterModifier::CellRendererSel::CellRendererSel()
-    : Glib::ObjectBase(typeid(CellRendererSel)),
-      _size(10),
-      _sel(*this, "sel", 0)
-{}
-
-void FilterEffectsDialog::FilterModifier::CellRendererSel::get_size_vfunc(
-    Gtk::Widget&, const Gdk::Rectangle*, int* x, int* y, int* w, int* h) const
-{
-    if(x)
-        (*x) = 0;
-    if(y)
-        (*y) = 0;
-    if(w)
-        (*w) = _size;
-    if(h)
-        (*h) = _size;
-}
-
-void FilterEffectsDialog::FilterModifier::CellRendererSel::render_vfunc(
-    const Glib::RefPtr<Gdk::Drawable>& win, Gtk::Widget& widget, const Gdk::Rectangle& bg_area,
-    const Gdk::Rectangle& cell_area, const Gdk::Rectangle& expose_area, Gtk::CellRendererState flags)
-{
-    const int sel = _sel.get_value();
-
-    if(sel > 0) {
-        const int s = _size - 2;
-        const int w = cell_area.get_width();
-        const int h = cell_area.get_height();
-        const int x = cell_area.get_x() + w / 2 - s / 2;
-        const int y = cell_area.get_y() + h / 2 - s / 2;
-
-        win->draw_rectangle(widget.get_style()->get_text_gc(Gtk::STATE_NORMAL), (sel == 1), x, y, s, s);
-    }
-}
-
 void FilterEffectsDialog::FilterModifier::on_activate_desktop(Application*, SPDesktop* desktop, FilterModifier* me)
 {
-    me->update_filters();
-
     me->_doc_replaced.disconnect();
     me->_doc_replaced = desktop->connectDocumentReplaced(
         sigc::mem_fun(me, &FilterModifier::on_document_replaced));
@@ -987,11 +1176,15 @@ void FilterEffectsDialog::FilterModifier::on_activate_desktop(Application*, SPDe
     me->_resource_changed =
         sp_document_resources_changed_connect(sp_desktop_document(desktop), "filter",
                                               sigc::mem_fun(me, &FilterModifier::update_filters));
+
+    me->_dialog.setDesktop(desktop);
+
+    me->update_filters();
 }
 
 
 // When the selection changes, show the active filter(s) in the dialog
-void FilterEffectsDialog::FilterModifier::on_inkscape_change_selection(Application *inkscape,
+void FilterEffectsDialog::FilterModifier::on_inkscape_change_selection(Application */*inkscape*/,
                                                                        Selection *sel,
                                                                        FilterModifier* fm)
 {
@@ -999,6 +1192,10 @@ void FilterEffectsDialog::FilterModifier::on_inkscape_change_selection(Applicati
         fm->update_selection(sel);
 }
 
+// Update each filter's sel property based on the current object selection;
+//  If the filter is not used by any selected object, sel = 0,
+//  otherwise sel is set to the total number of filters in use by selected objects
+//  If only one filter is in use, it is selected
 void FilterEffectsDialog::FilterModifier::update_selection(Selection *sel)
 {
     std::set<SPObject*> used;
@@ -1035,11 +1232,58 @@ void FilterEffectsDialog::FilterModifier::on_filter_selection_changed()
     signal_filter_changed()();
 }
 
+void FilterEffectsDialog::FilterModifier::on_name_edited(const Glib::ustring& path, const Glib::ustring& text)
+{
+    Gtk::TreeModel::iterator iter = _model->get_iter(path);
+
+    if(iter) {
+        SPFilter* filter = (*iter)[_columns.filter];
+        filter->setLabel(text.c_str());
+        sp_document_done(filter->document, SP_VERB_DIALOG_FILTER_EFFECTS, _("Rename filter"));
+        if(iter)
+            (*iter)[_columns.label] = text;
+    }
+}
+
+void FilterEffectsDialog::FilterModifier::on_selection_toggled(const Glib::ustring& path)
+{
+    Gtk::TreeIter iter = _model->get_iter(path);
+
+    if(iter) {
+        SPDesktop *desktop = _dialog.getDesktop();
+        SPDocument *doc = sp_desktop_document(desktop);
+        SPFilter* filter = (*iter)[_columns.filter];
+        Inkscape::Selection *sel = sp_desktop_selection(desktop);
+
+        /* If this filter is the only one used in the selection, unset it */
+        if((*iter)[_columns.sel] == 1)
+            filter = 0;
+
+        GSList const *items = sel->itemList();
+
+        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(filter)
+                sp_style_set_property_url(SP_OBJECT(item), "filter", SP_OBJECT(filter), false);
+            else
+                ::remove_filter(item, false);
+
+            SP_OBJECT(item)->requestDisplayUpdate((SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG ));
+        }
+
+        update_selection(sel);
+        sp_document_done(doc, SP_VERB_DIALOG_FILTER_EFFECTS,  _("Apply filter"));
+    }
+}
+
 /* Add all filters in the document to the combobox.
    Keeps the same selection if possible, otherwise selects the first element */
 void FilterEffectsDialog::FilterModifier::update_filters()
 {
-    SPDesktop* desktop = SP_ACTIVE_DESKTOP;
+    SPDesktop* desktop = _dialog.getDesktop();
     SPDocument* document = sp_desktop_document(desktop);
     const GSList* filters = sp_document_get_resource_list(document, "filter");
 
@@ -1055,6 +1299,7 @@ void FilterEffectsDialog::FilterModifier::update_filters()
     }
 
     update_selection(desktop->selection);
+    _dialog.update_filter_general_settings_view();
 }
 
 SPFilter* FilterEffectsDialog::FilterModifier::get_selected_filter()
@@ -1082,31 +1327,6 @@ void FilterEffectsDialog::FilterModifier::select_filter(const SPFilter* filter)
     }
 }
 
-void FilterEffectsDialog::FilterModifier::filter_list_button_press(GdkEventButton* e)
-{
-    // Double-click
-    if(e->type == GDK_2BUTTON_PRESS) {
-        SPDesktop *desktop = SP_ACTIVE_DESKTOP;
-        SPDocument *doc = sp_desktop_document(desktop);
-        SPFilter* filter = get_selected_filter();
-        Inkscape::Selection *sel = sp_desktop_selection(desktop);
-
-        GSList const *items = sel->itemList();
-
-        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);
-            
-            sp_style_set_property_url(SP_OBJECT(item), "filter", SP_OBJECT(filter), false);
-            SP_OBJECT(item)->requestDisplayUpdate((SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG ));
-        }
-
-        update_selection(sel);
-        sp_document_done(doc, SP_VERB_DIALOG_FILTER_EFFECTS,  _("Apply filter"));
-    }
-}
-
 void FilterEffectsDialog::FilterModifier::filter_list_button_release(GdkEventButton* event)
 {
     if((event->type == GDK_BUTTON_RELEASE) && (event->button == 3)) {
@@ -1119,7 +1339,7 @@ void FilterEffectsDialog::FilterModifier::filter_list_button_release(GdkEventBut
 
 void FilterEffectsDialog::FilterModifier::add_filter()
 {
-    SPDocument* doc = sp_desktop_document(SP_ACTIVE_DESKTOP);
+    SPDocument* doc = sp_desktop_document(_dialog.getDesktop());
     SPFilter* filter = new_filter(doc);
 
     const int count = _model->children().size();
@@ -1165,29 +1385,7 @@ void FilterEffectsDialog::FilterModifier::duplicate_filter()
 
 void FilterEffectsDialog::FilterModifier::rename_filter()
 {
-    SPFilter* filter = get_selected_filter();
-    Gtk::Window *window = dynamic_cast<Gtk::Window *>(_dialog.get_vbox()->get_ancestor(GTK_TYPE_WINDOW));
-    Gtk::Dialog m("", *window, true);
-    m.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
-    m.add_button(_("_Rename"), Gtk::RESPONSE_OK);
-    m.set_default_response(Gtk::RESPONSE_OK);
-    Gtk::Label lbl(_("Filter name:"));
-    Gtk::Entry entry;
-    entry.set_text(filter->label() ? filter->label() : "");
-    Gtk::HBox hb;
-    hb.add(lbl);
-    hb.add(entry);
-    hb.set_spacing(12);
-    hb.show_all();
-    m.get_vbox()->add(hb);
-    const int res = m.run();
-    if(res == Gtk::RESPONSE_OK) {
-        filter->setLabel(entry.get_text().c_str());
-        sp_document_done(filter->document, SP_VERB_DIALOG_FILTER_EFFECTS, _("Rename filter"));
-        Gtk::TreeIter iter = _list.get_selection()->get_selected();
-        if(iter)
-            (*iter)[_columns.label] = entry.get_text();
-    }
+    _list.set_cursor(_model->get_path(_list.get_selection()->get_selected()), *_list.get_column(1), true);
 }
 
 FilterEffectsDialog::CellRendererConnection::CellRendererConnection()
@@ -1211,7 +1409,7 @@ int FilterEffectsDialog::CellRendererConnection::get_text_width() const
 }
 
 void FilterEffectsDialog::CellRendererConnection::get_size_vfunc(
-    Gtk::Widget& widget, const Gdk::Rectangle* cell_area,
+    Gtk::Widget& widget, const Gdk::Rectangle* /*cell_area*/,
     int* x_offset, int* y_offset, int* width, int* height) const
 {
     PrimitiveList& primlist = dynamic_cast<PrimitiveList&>(widget);
@@ -1236,6 +1434,8 @@ FilterEffectsDialog::PrimitiveList::PrimitiveList(FilterEffectsDialog& d)
       _in_drag(0),
       _observer(new SignalObserver)
 {
+    d.signal_expose_event().connect(sigc::mem_fun(*this, &PrimitiveList::on_expose_signal));
+
     add_events(Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK);
     signal_expose_event().connect(sigc::mem_fun(*this, &PrimitiveList::on_expose_signal));
 
@@ -1244,7 +1444,7 @@ FilterEffectsDialog::PrimitiveList::PrimitiveList(FilterEffectsDialog& d)
     set_reorderable(true);
 
     set_model(_model);
-    append_column(_("_Type"), _columns.type);
+    append_column(_("_Effect"), _columns.type);
 
     _observer->signal_changed().connect(signal_primitive_changed().make_slot());
     get_selection()->signal_changed().connect(sigc::mem_fun(*this, &PrimitiveList::on_primitive_selection_changed));
@@ -1269,8 +1469,8 @@ int FilterEffectsDialog::PrimitiveList::init_text()
     _vertical_layout = Pango::Layout::create(context);
 
     int maxfont = 0;
-    for(int i = 0; i < FPInputConverter.end; ++i) {
-        _vertical_layout->set_text(FPInputConverter.get_label((FilterPrimitiveInput)i));
+    for(unsigned int i = 0; i < FPInputConverter._length; ++i) {
+        _vertical_layout->set_text(_(FPInputConverter.get_label((FilterPrimitiveInput)i).c_str()));
         int fontw, fonth;
         _vertical_layout->get_pixel_size(fontw, fonth);
         if(fonth > maxfont)
@@ -1304,7 +1504,7 @@ void FilterEffectsDialog::PrimitiveList::update()
 
     if(f) {
         _dialog._primitive_box.set_sensitive(true);
-
+        _dialog.update_filter_general_settings_view();
         for(SPObject *prim_obj = f->children;
                 prim_obj && SP_IS_FILTER_PRIMITIVE(prim_obj);
                 prim_obj = prim_obj->next) {
@@ -1313,7 +1513,7 @@ void FilterEffectsDialog::PrimitiveList::update()
                 Gtk::TreeModel::Row row = *_model->append();
                 row[_columns.primitive] = prim;
                 row[_columns.type_id] = FPConverter.get_id_from_key(prim->repr->name());
-                row[_columns.type] = FPConverter.get_label(row[_columns.type_id]);
+                row[_columns.type] = _(FPConverter.get_label(row[_columns.type_id]).c_str());
                 row[_columns.id] = SP_OBJECT_ID(prim);
 
                 if(prim == active_prim) {
@@ -1325,6 +1525,8 @@ void FilterEffectsDialog::PrimitiveList::update()
 
         if(!active_found && _model->children().begin())
             get_selection()->select(_model->children().begin());
+
+        columns_autosize();
     }
     else {
         _dialog._primitive_box.set_sensitive(false);
@@ -1356,7 +1558,21 @@ void FilterEffectsDialog::PrimitiveList::select(SPFilterPrimitive* prim)
     }
 }
 
+void FilterEffectsDialog::PrimitiveList::remove_selected()
+{
+    SPFilterPrimitive* prim = get_selected();
+
+    if(prim) {
+        _observer->set(0);
+
+        sp_repr_unparent(prim->repr);
+
+        sp_document_done(sp_desktop_document(_dialog.getDesktop()), SP_VERB_DIALOG_FILTER_EFFECTS,
+                         _("Remove filter primitive"));
 
+        update();
+    }
+}
 
 bool FilterEffectsDialog::PrimitiveList::on_expose_signal(GdkEventExpose* e)
 {
@@ -1377,9 +1593,9 @@ bool FilterEffectsDialog::PrimitiveList::on_expose_signal(GdkEventExpose* e)
         int vis_x, vis_y;
         tree_to_widget_coords(vis.get_x(), vis.get_y(), vis_x, vis_y);
 
-        text_start_x = rct.get_x() + rct.get_width() - _connection_cell.get_text_width() * (FPInputConverter.end + 1) + 1;
-        for(int i = 0; i < FPInputConverter.end; ++i) {
-            _vertical_layout->set_text(FPInputConverter.get_label((FilterPrimitiveInput)i));
+        text_start_x = rct.get_x() + rct.get_width() - _connection_cell.get_text_width() * (FPInputConverter._length + 1) + 1;
+        for(unsigned int i = 0; i < FPInputConverter._length; ++i) {
+            _vertical_layout->set_text(_(FPInputConverter.get_label((FilterPrimitiveInput)i).c_str()));
             const int x = text_start_x + _connection_cell.get_text_width() * (i + 1);
             get_bin_window()->draw_rectangle(get_style()->get_bg_gc(Gtk::STATE_NORMAL), true, x, vis_y, _connection_cell.get_text_width(), vis.get_height());
             get_bin_window()->draw_layout(get_style()->get_text_gc(Gtk::STATE_NORMAL), x + 1, vis_y, _vertical_layout);
@@ -1405,7 +1621,7 @@ bool FilterEffectsDialog::PrimitiveList::on_expose_signal(GdkEventExpose* e)
         get_bin_window()->draw_line(darkgc, outline_x, y - 1, outline_x, y + h);
 
         std::vector<Gdk::Point> con_poly;
-        int con_drag_y;
+        int con_drag_y = 0;
         bool inside;
         const SPFilterPrimitive* row_prim = (*row)[_columns.primitive];
         const int inputs = input_count(row_prim);
@@ -1465,31 +1681,51 @@ void FilterEffectsDialog::PrimitiveList::draw_connection(const Gtk::TreeIter& in
                                                          const int text_start_x, const int x1, const int y1,
                                                          const int row_count)
 {
-    int src_id;
-    const Gtk::TreeIter res = find_result(input, attr, src_id);
-    Glib::RefPtr<Gdk::GC> gc = get_style()->get_black_gc();
-    
-    if(res == input) {
+    int src_id = 0;
+    Gtk::TreeIter res = find_result(input, attr, src_id);
+    Glib::RefPtr<Gdk::GC> darkgc = get_style()->get_black_gc();
+    Glib::RefPtr<Gdk::GC> lightgc = get_style()->get_dark_gc(Gtk::STATE_NORMAL);
+    Glib::RefPtr<Gdk::GC> gc;
+
+    const bool is_first = input == get_model()->children().begin();
+    const bool is_merge = SP_IS_FEMERGE((SPFilterPrimitive*)(*input)[_columns.primitive]);
+    const bool use_default = !res && !is_merge;
+
+    if(res == input || (use_default && is_first)) {
         // Draw straight connection to a standard input
+        // Draw a lighter line for an implicit connection to a standard input
         const int tw = _connection_cell.get_text_width();
         gint end_x = text_start_x + tw * (src_id + 1) + (int)(tw * 0.5f) + 1;
+        gc = (use_default && is_first) ? lightgc : darkgc;
         get_bin_window()->draw_rectangle(gc, true, end_x-2, y1-2, 5, 5);
         get_bin_window()->draw_line(gc, x1, y1, end_x, y1);
     }
-    else if(res != _model->children().end()) {
-        Gdk::Rectangle rct;
+    else {
+        // Draw an 'L'-shaped connection to another filter primitive
+        // If no connection is specified, draw a light connection to the previous primitive
+        gc = use_default ? lightgc : darkgc;
 
-        get_cell_area(get_model()->get_path(_model->children().begin()), *get_column(1), rct);
-        const int fheight = CellRendererConnection::size;
+        if(use_default) {
+            res = input;
+            --res;
+        }
 
-        get_cell_area(get_model()->get_path(res), *get_column(1), rct);
-        const int row_index = find_index(res);
-        const int x2 = rct.get_x() + fheight * (row_count - row_index) - fheight / 2;
-        const int y2 = rct.get_y() + rct.get_height();
+        if(res) {
+            Gdk::Rectangle rct;
 
-        // Draw an 'L'-shaped connection to another filter primitive
-        get_bin_window()->draw_line(gc, x1, y1, x2, y1);
-        get_bin_window()->draw_line(gc, x2, y1, x2, y2);
+            get_cell_area(get_model()->get_path(_model->children().begin()), *get_column(1), rct);
+            const int fheight = CellRendererConnection::size;
+
+            get_cell_area(get_model()->get_path(res), *get_column(1), rct);
+            const int row_index = find_index(res);
+            const int x2 = rct.get_x() + fheight * (row_count - row_index) - fheight / 2;
+            const int y2 = rct.get_y() + rct.get_height();
+
+            // Draw a bevelled 'L'-shaped connection
+            get_bin_window()->draw_line(get_style()->get_black_gc(), x1, y1, x2-fheight/4, y1);
+            get_bin_window()->draw_line(get_style()->get_black_gc(), x2-fheight/4, y1, x2, y1-fheight/4);
+            get_bin_window()->draw_line(get_style()->get_black_gc(), x2, y1-fheight/4, x2, y2);
+        }
     }
 }
 
@@ -1523,14 +1759,19 @@ const Gtk::TreeIter FilterEffectsDialog::PrimitiveList::find_result(const Gtk::T
 {
     SPFilterPrimitive* prim = (*start)[_columns.primitive];
     Gtk::TreeIter target = _model->children().end();
-    int image;
+    int image = 0;
 
     if(SP_IS_FEMERGE(prim)) {
         int c = 0;
+        bool found = false;
         for(const SPObject* o = prim->firstChild(); o; o = o->next, ++c) {
-            if(c == attr && SP_IS_FEMERGENODE(o))
+            if(c == attr && SP_IS_FEMERGENODE(o)) {
                 image = SP_FEMERGENODE(o)->input;
+                found = true;
+            }
         }
+        if(!found)
+            return target;
     }
     else {
         if(attr == SP_ATTR_IN)
@@ -1581,7 +1822,7 @@ bool FilterEffectsDialog::PrimitiveList::on_button_press_event(GdkEventButton* e
     int cx, cy;
 
     _drag_prim = 0;
-    
+
     if(get_path_at_pos(x, y, path, col, cx, cy)) {
         Gtk::TreeIter iter = _model->get_iter(path);
         std::vector<Gdk::Point> points;
@@ -1595,7 +1836,7 @@ bool FilterEffectsDialog::PrimitiveList::on_button_press_event(GdkEventButton* e
                 break;
             }
         }
-        
+
         queue_draw();
     }
 
@@ -1648,23 +1889,25 @@ bool FilterEffectsDialog::PrimitiveList::on_button_release_event(GdkEventButton*
         Gtk::TreePath path;
         Gtk::TreeViewColumn* col;
         int cx, cy;
-        
+
         if(get_path_at_pos((int)e->x, (int)e->y, path, col, cx, cy)) {
             const gchar *in_val = 0;
             Glib::ustring result;
             Gtk::TreeIter target_iter = _model->get_iter(path);
             target = (*target_iter)[_columns.primitive];
+            col = get_column(1);
 
             Gdk::Rectangle rct;
             get_cell_area(path, *col, rct);
             const int twidth = _connection_cell.get_text_width();
-            const int sources_x = rct.get_width() - twidth * FPInputConverter.end;
+            const int sources_x = rct.get_width() - twidth * FPInputConverter._length;
             if(cx > sources_x) {
                 int src = (cx - sources_x) / twidth;
-                if(src < 0)
+                if (src < 0) {
                     src = 0;
-                else if(src >= FPInputConverter.end)
-                    src = FPInputConverter.end - 1;
+                } else if(src >= static_cast<int>(FPInputConverter._length)) {
+                    src = FPInputConverter._length - 1;
+                }
                 result = FPInputConverter.get_key((FilterPrimitiveInput)src);
                 in_val = result.c_str();
             }
@@ -1677,7 +1920,7 @@ bool FilterEffectsDialog::PrimitiveList::on_button_release_event(GdkEventButton*
                         // Make sure the target has a result
                         const gchar *gres = repr->attribute("result");
                         if(!gres) {
-                            result = "result" + Glib::Ascii::dtostr(SP_FILTER(prim->parent)->_image_number_next);
+                            result = sp_filter_get_new_result_name(SP_FILTER(prim->parent));
                             repr->setAttribute("result", result.c_str());
                             in_val = result.c_str();
                         }
@@ -1787,7 +2030,7 @@ void FilterEffectsDialog::PrimitiveList::sanitize_connections(const Gtk::TreeIte
 }
 
 // Reorder the filter primitives to match the list order
-void FilterEffectsDialog::PrimitiveList::on_drag_end(const Glib::RefPtr<Gdk::DragContext>& dc)
+void FilterEffectsDialog::PrimitiveList::on_drag_end(const Glib::RefPtr<Gdk::DragContext>& /*dc*/)
 {
     SPFilter* filter = _dialog._filter_modifier.get_selected_filter();
     int ndx = 0;
@@ -1844,62 +2087,79 @@ int FilterEffectsDialog::PrimitiveList::primitive_count() const
 
 /*** FilterEffectsDialog ***/
 
-FilterEffectsDialog::FilterEffectsDialog(Behavior::BehaviorFactory behavior_factory) 
-    : Dialog (behavior_factory, "dialogs.filtereffects", SP_VERB_DIALOG_FILTER_EFFECTS),
-      _filter_modifier(*this),
-      _primitive_list(*this),
+FilterEffectsDialog::FilterEffectsDialog()
+    : UI::Widget::Panel("", "dialogs.filtereffects", SP_VERB_DIALOG_FILTER_EFFECTS),
       _add_primitive_type(FPConverter),
-      _add_primitive(Gtk::Stock::ADD),
-      _empty_settings(_("No primitive selected"), Gtk::ALIGN_LEFT),
+      _add_primitive(_("Add Effect:")),
+      _empty_settings(_("No effect selected"), Gtk::ALIGN_LEFT),
+      _no_filter_selected(_("No filter selected"), Gtk::ALIGN_LEFT),
+      _settings_initialized(false),
       _locked(false),
-      _attr_lock(false)
+      _attr_lock(false),
+      _filter_modifier(*this),
+      _primitive_list(*this)
 {
-    _settings = new Settings(*this, _settings_box, sigc::mem_fun(*this, &FilterEffectsDialog::set_attr_direct),
+    _settings = new Settings(*this, _settings_tab1, sigc::mem_fun(*this, &FilterEffectsDialog::set_attr_direct),
                              NR_FILTER_ENDPRIMITIVETYPE);
+    _filter_general_settings = new Settings(*this, _settings_tab2, sigc::mem_fun(*this, &FilterEffectsDialog::set_filternode_attr),
+                             1);
     _sizegroup = Gtk::SizeGroup::create(Gtk::SIZE_GROUP_HORIZONTAL);
     _sizegroup->set_ignore_hidden();
-        
+
+    _add_primitive_type.remove_row(NR_FILTER_TILE);
+    _add_primitive_type.remove_row(NR_FILTER_COMPONENTTRANSFER);
+
     // Initialize widget hierarchy
     Gtk::HPaned* hpaned = Gtk::manage(new Gtk::HPaned);
     Gtk::ScrolledWindow* sw_prims = Gtk::manage(new Gtk::ScrolledWindow);
+    Gtk::HBox* infobox = Gtk::manage(new Gtk::HBox(/*homogeneous:*/false, /*spacing:*/4));
     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);
+
+    _getContents()->add(*hpaned);
     hpaned->pack1(_filter_modifier);
     hpaned->pack2(_primitive_box);
     _primitive_box.pack_start(*sw_prims);
     _primitive_box.pack_start(*hb_prims, false, false);
+    _primitive_box.pack_start(*infobox,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_box);
+    infobox->pack_start(_infobox_icon, false, false);
+    infobox->pack_start(_infobox_desc, false, false);
+    _infobox_desc.set_line_wrap(true);
+    _infobox_desc.set_size_request(200, -1);
+
+    hb_prims->pack_start(_add_primitive, false, false);
+    hb_prims->pack_start(_add_primitive_type, false, false);
+    _getContents()->pack_start(_settings_tabs, false, false);
+    _settings_tabs.append_page(_settings_tab1, _("Effect parameters"));
+    _settings_tabs.append_page(_settings_tab2, _("Filter General Settings"));
 
     _primitive_list.signal_primitive_changed().connect(
         sigc::mem_fun(*this, &FilterEffectsDialog::update_settings_view));
     _filter_modifier.signal_filter_changed().connect(
         sigc::mem_fun(_primitive_list, &PrimitiveList::update));
 
+    _add_primitive_type.signal_changed().connect(
+        sigc::mem_fun(*this, &FilterEffectsDialog::update_primitive_infobox));
+
     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();
+//    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_list.set_menu(create_popup_menu(*this, sigc::mem_fun(*this, &FilterEffectsDialog::duplicate_primitive),
-                                               sigc::mem_fun(*this, &FilterEffectsDialog::remove_primitive)));
-    
+                                               sigc::mem_fun(_primitive_list, &PrimitiveList::remove_selected)));
+
     show_all_children();
     init_settings_widgets();
     _primitive_list.update();
-    update_settings_view();
+    update_primitive_infobox();
 }
 
 FilterEffectsDialog::~FilterEffectsDialog()
 {
     delete _settings;
+    delete _filter_general_settings;
 }
 
 void FilterEffectsDialog::set_attrs_locked(const bool l)
@@ -1907,93 +2167,122 @@ void FilterEffectsDialog::set_attrs_locked(const bool l)
     _locked = l;
 }
 
+void FilterEffectsDialog::show_all_vfunc()
+{
+    UI::Widget::Panel::show_all_vfunc();
+
+    update_settings_view();
+}
+
 void FilterEffectsDialog::init_settings_widgets()
 {
     // TODO: Find better range/climb-rate/digits values for the SpinSliders,
     //       most of the current values are complete guesses!
 
     _empty_settings.set_sensitive(false);
-    _settings_box.pack_start(_empty_settings);
+    _settings_tab1.pack_start(_empty_settings);
+
+    _no_filter_selected.set_sensitive(false);
+    _settings_tab2.pack_start(_no_filter_selected);
+    _settings_initialized = true;
+
+    _filter_general_settings->type(0);
+    _filter_general_settings->add_multispinbutton(/*default x:*/ (double) -0.1, /*default y:*/ (double) -0.1, SP_ATTR_X, SP_ATTR_Y, _("Coordinates"), -100, 100, 0.01, 0.1, 2, _("X coordinate of the left corners of filter effects region"), _("Y coordinate of the upper corners of filter effects region"));
+    _filter_general_settings->add_multispinbutton(/*default width:*/ (double) 1.2, /*default height:*/ (double) 1.2, SP_ATTR_WIDTH, SP_ATTR_HEIGHT, _("Dimensions"), 0, 1000, 0.01, 0.1, 2, _("Width of filter effects region"), _("Height of filter effects region"));
 
     _settings->type(NR_FILTER_BLEND);
-    _settings->add_combo(SP_ATTR_MODE, _("Mode"), BlendModeConverter);
+    _settings->add_combo(BLEND_NORMAL, SP_ATTR_MODE, _("Mode"), BlendModeConverter);
 
     _settings->type(NR_FILTER_COLORMATRIX);
-    ComboBoxEnum<FilterColorMatrixType>* colmat = _settings->add_combo(SP_ATTR_TYPE, _("Type"), ColorMatrixTypeConverter);
+    ComboBoxEnum<FilterColorMatrixType>* colmat = _settings->add_combo(COLORMATRIX_MATRIX, SP_ATTR_TYPE, _("Type"), ColorMatrixTypeConverter, _("Indicates the type of matrix operation. The keyword 'matrix' indicates that a full 5x4 matrix of values will be provided. The other keywords represent convenience shortcuts to allow commonly used color operations to be performed without specifying a complete matrix."));
     _color_matrix_values = _settings->add_colormatrixvalues(_("Value(s)"));
     colmat->signal_attr_changed().connect(sigc::mem_fun(*this, &FilterEffectsDialog::update_color_matrix));
 
     _settings->type(NR_FILTER_COMPONENTTRANSFER);
-    _settings->add_combo(SP_ATTR_TYPE, _("Type"), ComponentTransferTypeConverter);
+    _settings->add_notimplemented();
+    //TRANSLATORS: for info on "Slope" and "Intercept", see http://id.mind.net/~zona/mmts/functionInstitute/linearFunctions/lsif.html
+    /*_settings->add_combo(COMPONENTTRANSFER_TYPE_IDENTITY, SP_ATTR_TYPE, _("Type"), ComponentTransferTypeConverter);
     _ct_slope = _settings->add_spinslider(SP_ATTR_SLOPE, _("Slope"), -100, 100, 1, 0.01, 1);
     _ct_intercept = _settings->add_spinslider(SP_ATTR_INTERCEPT, _("Intercept"), -100, 100, 1, 0.01, 1);
     _ct_amplitude = _settings->add_spinslider(SP_ATTR_AMPLITUDE, _("Amplitude"), 0, 100, 1, 0.01, 1);
     _ct_exponent = _settings->add_spinslider(SP_ATTR_EXPONENT, _("Exponent"), 0, 100, 1, 0.01, 1);
-    _ct_offset = _settings->add_spinslider(SP_ATTR_OFFSET, _("Offset"), -100, 100, 1, 0.01, 1);
+    _ct_offset = _settings->add_spinslider(SP_ATTR_OFFSET, _("Offset"), -100, 100, 1, 0.01, 1);*/
 
     _settings->type(NR_FILTER_COMPOSITE);
-    _settings->add_combo(SP_ATTR_OPERATOR, _("Operator"), CompositeOperatorConverter);
-    _k1 = _settings->add_spinslider(SP_ATTR_K1, _("K1"), -10, 10, 1, 0.01, 1);
-    _k2 = _settings->add_spinslider(SP_ATTR_K2, _("K2"), -10, 10, 1, 0.01, 1);
-    _k3 = _settings->add_spinslider(SP_ATTR_K3, _("K3"), -10, 10, 1, 0.01, 1);
-    _k4 = _settings->add_spinslider(SP_ATTR_K4, _("K4"), -10, 10, 1, 0.01, 1);
+    _settings->add_combo(COMPOSITE_OVER, SP_ATTR_OPERATOR, _("Operator"), CompositeOperatorConverter);
+    _k1 = _settings->add_spinslider(0, SP_ATTR_K1, _("K1"), -10, 10, 0.1, 0.01, 2, _("If the arithmetic operation is chosen, each result pixel is computed using the formula k1*i1*i2 + k2*i1 + k3*i2 + k4 where i1 and i2 are the pixel values of the first and second inputs respectively."));
+    _k2 = _settings->add_spinslider(0, SP_ATTR_K2, _("K2"), -10, 10, 0.1, 0.01, 2, _("If the arithmetic operation is chosen, each result pixel is computed using the formula k1*i1*i2 + k2*i1 + k3*i2 + k4 where i1 and i2 are the pixel values of the first and second inputs respectively."));
+    _k3 = _settings->add_spinslider(0, SP_ATTR_K3, _("K3"), -10, 10, 0.1, 0.01, 2, _("If the arithmetic operation is chosen, each result pixel is computed using the formula k1*i1*i2 + k2*i1 + k3*i2 + k4 where i1 and i2 are the pixel values of the first and second inputs respectively."));
+    _k4 = _settings->add_spinslider(0, SP_ATTR_K4, _("K4"), -10, 10, 0.1, 0.01, 2, _("If the arithmetic operation is chosen, each result pixel is computed using the formula k1*i1*i2 + k2*i1 + k3*i2 + k4 where i1 and i2 are the pixel values of the first and second inputs respectively."));
 
     _settings->type(NR_FILTER_CONVOLVEMATRIX);
-    _convolve_order = _settings->add_dualspinbutton(SP_ATTR_ORDER, _("Size"), 1, 5, 1, 1, 0);
-    _convolve_target = _settings->add_multispinbutton(SP_ATTR_TARGETX, SP_ATTR_TARGETY, _("Target"), 0, 4, 1, 1, 0);
-    _convolve_matrix = _settings->add_matrix(SP_ATTR_KERNELMATRIX, _("Kernel"));
+    _convolve_order = _settings->add_dualspinbutton((char*)"3", SP_ATTR_ORDER, _("Size"), 1, 5, 1, 1, 0, _("width of the convolve matrix"), _("height of the convolve matrix"));
+    _convolve_target = _settings->add_multispinbutton(/*default x:*/ (double) 0, /*default y:*/ (double) 0, SP_ATTR_TARGETX, SP_ATTR_TARGETY, _("Target"), 0, 4, 1, 1, 0, _("X coordinate of the target point in the convolve matrix. The convolution is applied to pixels around this point."), _("Y coordinate of the target point in the convolve matrix. The convolution is applied to pixels around this point."));
+    //TRANSLATORS: for info on "Kernel", see http://en.wikipedia.org/wiki/Kernel_(matrix)
+    _convolve_matrix = _settings->add_matrix(SP_ATTR_KERNELMATRIX, _("Kernel"), _("This matrix describes the convolve operation that is applied to the input image in order to calculate the pixel colors at the output. Different arrangements of values in this matrix result in various possible visual effects. An identity matrix would lead to a motion blur effect (parallel to the matrix diagonal) while a matrix filled with a constant non-zero value would lead to a common blur effect."));
     _convolve_order->signal_attr_changed().connect(sigc::mem_fun(*this, &FilterEffectsDialog::convolve_order_changed));
-    _settings->add_spinslider(SP_ATTR_DIVISOR, _("Divisor"), 0.01, 10, 1, 0.01, 1);
-    _settings->add_spinslider(SP_ATTR_BIAS, _("Bias"), -10, 10, 1, 0.01, 1);
-    _settings->add_combo(SP_ATTR_EDGEMODE, _("Edge Mode"), ConvolveMatrixEdgeModeConverter);
+    //TODO: svg spec: The default value is the sum of all values in kernelMatrix, with the exception that if the sum is zero, then the divisor is set to 1.
+    _settings->add_spinslider(1, SP_ATTR_DIVISOR, _("Divisor"), 1, 20, 1, 0.1, 2, _("After applying the kernelMatrix to the input image to yield a number, that number is divided by divisor to yield the final destination color value. A divisor that is the sum of all the matrix values tends to have an evening effect on the overall color intensity of the result."));
+    _settings->add_spinslider(0, SP_ATTR_BIAS, _("Bias"), -10, 10, 1, 0.01, 1, _("This value is added to each component. This is useful to define a constant value as the zero response of the filter."));
+    _settings->add_combo(CONVOLVEMATRIX_EDGEMODE_DUPLICATE, SP_ATTR_EDGEMODE, _("Edge Mode"), ConvolveMatrixEdgeModeConverter, _("Determines how to extend the input image as necessary with color values so that the matrix operations can be applied when the kernel is positioned at or near the edge of the input image."));
+    _settings->add_checkbutton(false, SP_ATTR_PRESERVEALPHA, _("Preserve Alpha"), "true", "false", _("If set, the alpha channel won't be altered by this filter primitive."));
 
     _settings->type(NR_FILTER_DIFFUSELIGHTING);
-    _settings->add_color(SP_PROP_LIGHTING_COLOR, _("Diffuse Color"));
-    _settings->add_spinslider(SP_ATTR_SURFACESCALE, _("Surface Scale"), -10, 10, 1, 0.01, 1);
-    _settings->add_spinslider(SP_ATTR_DIFFUSECONSTANT, _("Constant"), 0, 100, 1, 0.01, 1);
+    _settings->add_color(/*default: white*/ 0xffffffff, SP_PROP_LIGHTING_COLOR, _("Diffuse Color"), _("Defines the color of the light source"));
+    _settings->add_spinslider(1, SP_ATTR_SURFACESCALE, _("Surface Scale"), -1000, 1000, 1, 0.01, 1, _("This value amplifies the heights of the bump map defined by the input alpha channel"));
+    _settings->add_spinslider(1, SP_ATTR_DIFFUSECONSTANT, _("Constant"), 0, 100, 0.1, 0.01, 2, _("This constant affects the Phong lighting model."));
     _settings->add_dualspinslider(SP_ATTR_KERNELUNITLENGTH, _("Kernel Unit Length"), 0.01, 10, 1, 0.01, 1);
     _settings->add_lightsource();
 
     _settings->type(NR_FILTER_DISPLACEMENTMAP);
-    _settings->add_spinslider(SP_ATTR_SCALE, _("Scale"), 0, 100, 1, 0.01, 1);
-    _settings->add_combo(SP_ATTR_XCHANNELSELECTOR, _("X Channel"), DisplacementMapChannelConverter);
-    _settings->add_combo(SP_ATTR_YCHANNELSELECTOR, _("Y Channel"), DisplacementMapChannelConverter);
+    _settings->add_spinslider(0, SP_ATTR_SCALE, _("Scale"), 0, 100, 1, 0.01, 1, _("This defines the intensity of the displacement effect."));
+    _settings->add_combo(DISPLACEMENTMAP_CHANNEL_ALPHA, SP_ATTR_XCHANNELSELECTOR, _("X displacement"), DisplacementMapChannelConverter, _("Color component that controls the displacement in the X direction"));
+    _settings->add_combo(DISPLACEMENTMAP_CHANNEL_ALPHA, SP_ATTR_YCHANNELSELECTOR, _("Y displacement"), DisplacementMapChannelConverter, _("Color component that controls the displacement in the Y direction"));
 
     _settings->type(NR_FILTER_FLOOD);
-    _settings->add_color(SP_PROP_FLOOD_COLOR, _("Flood Color"));
-    _settings->add_spinslider(SP_PROP_FLOOD_OPACITY, _("Opacity"), 0, 1, 0.1, 0.01, 2);
-    
+    _settings->add_color(/*default: black*/ 0, SP_PROP_FLOOD_COLOR, _("Flood Color"), _("The whole filter region will be filled with this color."));
+    _settings->add_spinslider(1, SP_PROP_FLOOD_OPACITY, _("Opacity"), 0, 1, 0.1, 0.01, 2);
+
     _settings->type(NR_FILTER_GAUSSIANBLUR);
-    _settings->add_dualspinslider(SP_ATTR_STDDEVIATION, _("Standard Deviation"), 0.01, 100, 1, 0.01, 1);
+    _settings->add_dualspinslider(SP_ATTR_STDDEVIATION, _("Standard Deviation"), 0.01, 100, 1, 0.01, 1, _("The standard deviation for the blur operation."));
+
+    _settings->type(NR_FILTER_MERGE);
+    _settings->add_no_params();
 
     _settings->type(NR_FILTER_MORPHOLOGY);
-    _settings->add_combo(SP_ATTR_OPERATOR, _("Operator"), MorphologyOperatorConverter);
+    _settings->add_combo(MORPHOLOGY_OPERATOR_ERODE, SP_ATTR_OPERATOR, _("Operator"), MorphologyOperatorConverter, _("Erode: performs \"thinning\" of input image.\nDilate: performs \"fattenning\" of input image."));
     _settings->add_dualspinslider(SP_ATTR_RADIUS, _("Radius"), 0, 100, 1, 0.01, 1);
 
+    _settings->type(NR_FILTER_IMAGE);
+    _settings->add_fileorelement(SP_ATTR_XLINK_HREF, _("Source of Image"));
+
     _settings->type(NR_FILTER_OFFSET);
-    _settings->add_spinslider(SP_ATTR_DX, _("Delta X"), -100, 100, 1, 0.01, 1);
-    _settings->add_spinslider(SP_ATTR_DY, _("Delta Y"), -100, 100, 1, 0.01, 1);
+    _settings->add_spinslider(0, SP_ATTR_DX, _("Delta X"), -100, 100, 1, 0.01, 1, _("This is how far the input image gets shifted to the right"));
+    _settings->add_spinslider(0, SP_ATTR_DY, _("Delta Y"), -100, 100, 1, 0.01, 1, _("This is how far the input image gets shifted downwards"));
 
     _settings->type(NR_FILTER_SPECULARLIGHTING);
-    _settings->add_color(SP_PROP_LIGHTING_COLOR, _("Specular Color"));
-    _settings->add_spinslider(SP_ATTR_SURFACESCALE, _("Surface Scale"), -10, 10, 1, 0.01, 1);
-    _settings->add_spinslider(SP_ATTR_SPECULARCONSTANT, _("Constant"), 0, 100, 1, 0.01, 1);
-    _settings->add_spinslider(SP_ATTR_SPECULAREXPONENT, _("Exponent"), 1, 128, 1, 0.01, 1);
+    _settings->add_color(/*default: white*/ 0xffffffff, SP_PROP_LIGHTING_COLOR, _("Specular Color"), _("Defines the color of the light source"));
+    _settings->add_spinslider(1, SP_ATTR_SURFACESCALE, _("Surface Scale"), -1000, 1000, 1, 0.01, 1, _("This value amplifies the heights of the bump map defined by the input alpha channel"));
+    _settings->add_spinslider(1, SP_ATTR_SPECULARCONSTANT, _("Constant"), 0, 100, 0.1, 0.01, 2, _("This constant affects the Phong lighting model."));
+    _settings->add_spinslider(1, SP_ATTR_SPECULAREXPONENT, _("Exponent"), 1, 128, 1, 0.01, 1, _("Exponent for specular term, larger is more \"shiny\"."));
     _settings->add_dualspinslider(SP_ATTR_KERNELUNITLENGTH, _("Kernel Unit Length"), 0.01, 10, 1, 0.01, 1);
     _settings->add_lightsource();
 
+    _settings->type(NR_FILTER_TILE);
+    _settings->add_notimplemented();
+
     _settings->type(NR_FILTER_TURBULENCE);
-    _settings->add_checkbutton(SP_ATTR_STITCHTILES, _("Stitch Tiles"), "stitch", "noStitch");
-    _settings->add_combo(SP_ATTR_TYPE, _("Type"), TurbulenceTypeConverter);
-    _settings->add_dualspinslider(SP_ATTR_BASEFREQUENCY, _("Base Frequency"), 0, 100, 1, 0.01, 1);
-    _settings->add_spinslider(SP_ATTR_NUMOCTAVES, _("Octaves"), 1, 10, 1, 1, 0);
-    _settings->add_spinslider(SP_ATTR_SEED, _("Seed"), 0, 1000, 1, 1, 0);
+//    _settings->add_checkbutton(false, SP_ATTR_STITCHTILES, _("Stitch Tiles"), "stitch", "noStitch");
+    _settings->add_combo(TURBULENCE_TURBULENCE, SP_ATTR_TYPE, _("Type"), TurbulenceTypeConverter, _("Indicates whether the filter primitive should perform a noise or turbulence function."));
+    _settings->add_dualspinslider(SP_ATTR_BASEFREQUENCY, _("Base Frequency"), 0, 0.4, 0.001, 0.01, 3);
+    _settings->add_spinslider(1, SP_ATTR_NUMOCTAVES, _("Octaves"), 1, 10, 1, 1, 0);
+    _settings->add_spinslider(0, SP_ATTR_SEED, _("Seed"), 0, 1000, 1, 1, 0, _("The starting number for the pseudo random number generator."));
 }
 
 void FilterEffectsDialog::add_primitive()
 {
     SPFilter* filter = _filter_modifier.get_selected_filter();
-    
+
     if(filter) {
         SPFilterPrimitive* prim = filter_add_primitive(filter, _add_primitive_type.get_active_data()->id);
 
@@ -2003,17 +2292,83 @@ void FilterEffectsDialog::add_primitive()
     }
 }
 
-void FilterEffectsDialog::remove_primitive()
+void FilterEffectsDialog::update_primitive_infobox()
 {
-    SPFilterPrimitive* prim = _primitive_list.get_selected();
-
-    if(prim) {
-        sp_repr_unparent(prim->repr);
-
-        sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_DIALOG_FILTER_EFFECTS,
-                         _("Remove filter primitive"));
-
-        _primitive_list.update();
+    if (prefs_get_int_attribute ("options.showfiltersinfobox", "value", 1)){
+        _infobox_icon.show();
+        _infobox_desc.show();
+    } else {
+        _infobox_icon.hide();
+        _infobox_desc.hide();
+    }
+    switch(_add_primitive_type.get_active_data()->id){
+        case(NR::NR_FILTER_BLEND):
+            _infobox_icon.set(g_strdup_printf("%s/feBlend-icon.png", INKSCAPE_PIXMAPDIR));
+            _infobox_desc.set_markup(_("The <b>feBlend</b> filter primitive provides 4 image blending modes: screen, multiply, darken and lighten."));
+            break;
+        case(NR::NR_FILTER_COLORMATRIX):
+            _infobox_icon.set(g_strdup_printf("%s/feColorMatrix-icon.png", INKSCAPE_PIXMAPDIR));
+            _infobox_desc.set_markup(_("The <b>feColorMatrix</b> filter primitive applies a matrix transformation to colour of each rendered pixel. This allows for effects like turning object to grayscale, modifying colour saturation and changing colour hue."));
+            break;
+        case(NR::NR_FILTER_COMPONENTTRANSFER):
+            _infobox_icon.set(g_strdup_printf("%s/feComponentTransfer-icon.png", INKSCAPE_PIXMAPDIR));
+            _infobox_desc.set_markup(_("The <b>feComponentTransfer</b> filter primitive manipulates the input's color components (red, green, blue, and alpha) according to particular transfer functions, allowing operations like brightness and contrast adjustment, color balance, and thresholding."));
+            break;
+        case(NR::NR_FILTER_COMPOSITE):
+            _infobox_icon.set(g_strdup_printf("%s/feComposite-icon.png", INKSCAPE_PIXMAPDIR));
+            _infobox_desc.set_markup(_("The <b>feComposite</b> filter primitive composites two images using one of the Porter-Duff blending modes or the aritmetic mode described in SVG standard. Porter-Duff blending modes are essentially logical operations between the corresponding pixel values of the images."));
+            break;
+        case(NR::NR_FILTER_CONVOLVEMATRIX):
+            _infobox_icon.set(g_strdup_printf("%s/feConvolveMatrix-icon.png", INKSCAPE_PIXMAPDIR));
+            _infobox_desc.set_markup(_("The <b>feConvolveMatrix</b> lets you specify a Convolution to be applied on the image. Common effects created using convolution matrices are blur, sharpening, embossing and edge detection. Note that while gaussian blur can be created using this filter primitive, the special gaussian blur primitive is faster and resolution-independent."));
+            break;
+        case(NR::NR_FILTER_DIFFUSELIGHTING):
+            _infobox_icon.set(g_strdup_printf("%s/feDiffuseLighting-icon.png", INKSCAPE_PIXMAPDIR));
+            _infobox_desc.set_markup(_("The <b>feDiffuseLighting</b> and feSpecularLighting filter primitives create \"embossed\" shadings.  The input's alpha channel is used to provide depth information: higher opacity areas are raised toward the viewer and lower opacity areas recede away from the viewer."));
+            break;
+        case(NR::NR_FILTER_DISPLACEMENTMAP):
+            _infobox_icon.set(g_strdup_printf("%s/feDisplacementMap-icon.png", INKSCAPE_PIXMAPDIR));
+            _infobox_desc.set_markup(_("The <b>feDisplacementMap</b> filter primitive displaces the pixels in the first input using the second input as a displacement map, that shows from how far the pixel should come from. Classical examples are whirl and pinch effects."));
+            break;
+        case(NR::NR_FILTER_FLOOD):
+            _infobox_icon.set(g_strdup_printf("%s/feFlood-icon.png", INKSCAPE_PIXMAPDIR));
+            _infobox_desc.set_markup(_("The <b>feFlood</b> filter primitive fills the region with a given color and opacity.  It is usually used as an input to other filters to apply color to a graphic."));
+            break;
+        case(NR::NR_FILTER_GAUSSIANBLUR):
+            _infobox_icon.set(g_strdup_printf("%s/feGaussianBlur-icon.png", INKSCAPE_PIXMAPDIR));
+            _infobox_desc.set_markup(_("The <b>feGaussianBlur</b> filter primitive uniformly blurs its input.  It is commonly used together with feOffset to create a drop shadow effect."));
+            break;
+        case(NR::NR_FILTER_IMAGE):
+            _infobox_icon.set(g_strdup_printf("%s/feImage-icon.png", INKSCAPE_PIXMAPDIR));
+            _infobox_desc.set_markup(_("The <b>feImage</b> filter primitive fills the region with an external image or another part of the document."));
+            break;
+        case(NR::NR_FILTER_MERGE):
+            _infobox_icon.set(g_strdup_printf("%s/feMerge-icon.png", INKSCAPE_PIXMAPDIR));
+            _infobox_desc.set_markup(_("The <b>feMerge</b> filter primitive composites several temporary images inside the filter primitive to a single image. It uses normal alpha compositing for this. This is equivalent to using several feBlend primitives in 'normal' mode or several feComposite primitives in 'over' mode."));
+            break;
+        case(NR::NR_FILTER_MORPHOLOGY):
+            _infobox_icon.set(g_strdup_printf("%s/feMorphology-icon.png", INKSCAPE_PIXMAPDIR));
+            _infobox_desc.set_markup(_("The <b>feMorphology</b> filter primitive provides erode and dilate effects. For single-colour objects erode makes the object thinner and dilate makes it thicker."));
+            break;
+        case(NR::NR_FILTER_OFFSET):
+            _infobox_icon.set(g_strdup_printf("%s/feOffset-icon.png", INKSCAPE_PIXMAPDIR));
+            _infobox_desc.set_markup(_("The <b>feOffset</b> filter primitive offsets the image by an user-defined amount. For example, this is useful for drop shadows, where the shadow is in a slightly different position than the actual object."));
+            break;
+        case(NR::NR_FILTER_SPECULARLIGHTING):
+            _infobox_icon.set(g_strdup_printf("%s/feSpecularLighting-icon.png", INKSCAPE_PIXMAPDIR));
+            _infobox_desc.set_markup(_("The feDiffuseLighting and <b>feSpecularLighting</b> filter primitives create \"embossed\" shadings.  The input's alpha channel is used to provide depth information: higher opacity areas are raised toward the viewer and lower opacity areas recede away from the viewer."));
+            break;
+        case(NR::NR_FILTER_TILE):
+            _infobox_icon.set(g_strdup_printf("%s/feTile-icon.png", INKSCAPE_PIXMAPDIR));
+            _infobox_desc.set_markup(_("The <b>feTile</b> filter primitive tiles a region with its input graphic"));
+            break;
+        case(NR::NR_FILTER_TURBULENCE):
+            _infobox_icon.set(g_strdup_printf("%s/feTurbulence-icon.png", INKSCAPE_PIXMAPDIR));
+            _infobox_desc.set_markup(_("The <b>feTurbulence</b> filter primitive renders Perlin noise. This kind of noise is useful in simulating several nature phenomena like clouds, fire and smoke and in generating complex textures like marble or granite."));
+            break;
+        default:
+            g_assert(false);
+            break;
     }
 }
 
@@ -2045,6 +2400,20 @@ void FilterEffectsDialog::set_attr_direct(const AttrWidget* input)
     set_attr(_primitive_list.get_selected(), input->get_attribute(), input->get_as_attribute().c_str());
 }
 
+void FilterEffectsDialog::set_filternode_attr(const AttrWidget* input)
+{
+    if(!_locked) {
+        _attr_lock = true;
+        SPFilter *filter = _filter_modifier.get_selected_filter();
+        const gchar* name = (const gchar*)sp_attribute_name(input->get_attribute());
+        if (filter && name && SP_OBJECT_REPR(filter)){
+            SP_OBJECT_REPR(filter)->setAttribute(name, input->get_as_attribute().c_str());
+            filter->requestModified(SP_OBJECT_MODIFIED_FLAG);
+        }
+        _attr_lock = false;
+    }
+}
+
 void FilterEffectsDialog::set_child_attr_direct(const AttrWidget* input)
 {
     set_attr(_primitive_list.get_selected()->children, input->get_attribute(), input->get_as_attribute().c_str());
@@ -2073,6 +2442,29 @@ void FilterEffectsDialog::set_attr(SPObject* o, const SPAttributeEnum attr, cons
     }
 }
 
+void FilterEffectsDialog::update_filter_general_settings_view()
+{
+    if(_settings_initialized != true) return;
+
+    if(!_locked) {
+        _attr_lock = true;
+
+        SPFilter* filter = _filter_modifier.get_selected_filter();
+
+        if(filter) {
+            _filter_general_settings->show_and_update(0, filter);
+            _no_filter_selected.hide();
+        }
+        else {
+            std::vector<Gtk::Widget*> vect = _settings_tab2.get_children();
+            vect[0]->hide_all();
+            _no_filter_selected.show();
+        }
+
+        _attr_lock = false;
+    }
+}
+
 void FilterEffectsDialog::update_settings_view()
 {
     update_settings_sensitivity();
@@ -2080,17 +2472,40 @@ void FilterEffectsDialog::update_settings_view()
     if(_attr_lock)
         return;
 
+//First Tab
+
+    std::vector<Gtk::Widget*> vect1 = _settings_tab1.get_children();
+    for(unsigned int i=0; i<vect1.size(); i++) vect1[i]->hide_all();
+    _empty_settings.show();
+
+    if (prefs_get_int_attribute ("options.showfiltersinfobox", "value", 1)){
+        _infobox_icon.show();
+        _infobox_desc.show();
+    } else {
+        _infobox_icon.hide();
+        _infobox_desc.hide();
+    }
+
     SPFilterPrimitive* prim = _primitive_list.get_selected();
 
     if(prim) {
         _settings->show_and_update(FPConverter.get_id_from_key(prim->repr->name()), prim);
         _empty_settings.hide();
     }
-    else {
-        _settings_box.hide_all();
-        _settings_box.show();
-        _empty_settings.show();
+
+//Second Tab
+
+    std::vector<Gtk::Widget*> vect2 = _settings_tab2.get_children();
+    vect2[0]->hide_all();
+    _no_filter_selected.show();
+
+    SPFilter* filter = _filter_modifier.get_selected_filter();
+
+    if(filter) {
+        _filter_general_settings->show_and_update(0, filter);
+        _no_filter_selected.hide();
     }
+
 }
 
 void FilterEffectsDialog::update_settings_sensitivity()
@@ -2102,17 +2517,21 @@ void FilterEffectsDialog::update_settings_sensitivity()
     _k3->set_sensitive(use_k);
     _k4->set_sensitive(use_k);
 
+// Component transfer not yet implemented
+/*
     if(SP_IS_FECOMPONENTTRANSFER(prim)) {
         SPFeComponentTransfer* ct = SP_FECOMPONENTTRANSFER(prim);
         const bool linear = ct->type == COMPONENTTRANSFER_TYPE_LINEAR;
         const bool gamma = ct->type == COMPONENTTRANSFER_TYPE_GAMMA;
-        //_ct_table->set_sensitive(ct->type == COMPONENTTRANSFER_TYPE_TABLE || ct->type == COMPONENTTRANSFER_TYPE_DISCRETE);
+
+        _ct_table->set_sensitive(ct->type == COMPONENTTRANSFER_TYPE_TABLE || ct->type == COMPONENTTRANSFER_TYPE_DISCRETE);
         _ct_slope->set_sensitive(linear);
         _ct_intercept->set_sensitive(linear);
         _ct_amplitude->set_sensitive(gamma);
         _ct_exponent->set_sensitive(gamma);
         _ct_offset->set_sensitive(gamma);
     }
+*/
 }
 
 void FilterEffectsDialog::update_color_matrix()