Code

* don't strech buttons on lpe dialog when resizing the dialog
[inkscape.git] / src / ui / dialog / filter-effects-dialog.cpp
index 72ee9968451a21f3d8502ae947fac272f41bf081..b3dd1a7d0091301a5a841191f93be9e17f83e616 100644 (file)
 #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;
@@ -292,7 +297,7 @@ public:
     {
         std::ostringstream os;
         const Gdk::Color c = get_color();
-        const int r = (c.get_red() + 1) / 256 - 1, g = (c.get_green() + 1) / 256 - 1, b = (c.get_blue() + 1) / 256 - 1;
+        const int r = c.get_red() / 257, g = c.get_green() / 257, b = c.get_blue() / 257;
         os << "rgb(" << r << "," << g << "," << b << ")";
         return os.str();
     }
@@ -303,9 +308,9 @@ public:
         const gchar* val = attribute_value(o);
         if(val) {
             const guint32 i = sp_svg_read_color(val, 0xFFFFFFFF);
-            const int r = SP_RGBA32_R_U(i) + 1, g = SP_RGBA32_G_U(i) + 1, b = SP_RGBA32_B_U(i) + 1;
+            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 - 1, g * 256 - 1, b * 256 - 1);
+            col.set_rgb(r * 257, g * 257, b * 257);
             set_color(col);
         }
     }
@@ -423,8 +428,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);
             }
         }
     }
@@ -543,6 +549,126 @@ 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);
+        }
+    }
+
+    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:
@@ -596,6 +722,13 @@ public:
         _current_type = t;
     }
 
+    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();
 
@@ -667,7 +800,7 @@ public:
         add_attr_widget(dsb);
         return dsb;
     }
-
+    
     // MultiSpinButton
     MultiSpinButton* add_multispinbutton(const SPAttributeEnum attr1, const SPAttributeEnum attr2,
                                          const Glib::ustring& label, const double lo, const double hi,
@@ -696,6 +829,16 @@ public:
             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,
@@ -751,7 +894,7 @@ public:
         : AttrWidget(SP_ATTR_INVALID),
           _dialog(d),
           _settings(d, _box, sigc::mem_fun(_dialog, &FilterEffectsDialog::set_child_attr_direct), LIGHT_ENDSOURCE),
-          _light_label("Light Source:", Gtk::ALIGN_LEFT),
+          _light_label(_("Light Source:"), Gtk::ALIGN_LEFT),
           _light_source(LightSourceConverter),
           _locked(false)
     {
@@ -892,7 +1035,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,24 +1044,26 @@ 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),
                               sigc::mem_fun(*this, &FilterModifier::remove_filter));
     _menu->items().push_back(Gtk::Menu_Helpers::MenuElem(
-                                 _("R_ename"), sigc::mem_fun(*this, &FilterModifier::rename_filter)));
+                                 _("R_ename"), sigc::mem_fun(*this, &FilterModifier::rename_filter)));          
     _menu->accelerate(*this);
 
     _list.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &FilterModifier::on_filter_selection_changed));
@@ -929,7 +1074,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 +1084,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 +1094,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 +1110,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 +1150,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");
 
@@ -1082,31 +1244,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 +1256,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,28 +1302,7 @@ void FilterEffectsDialog::FilterModifier::duplicate_filter()
 
 void FilterEffectsDialog::FilterModifier::rename_filter()
 {
-    SPFilter* filter = get_selected_filter();
-    Gtk::Dialog m("", _dialog, 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()
@@ -1210,7 +1326,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);
@@ -1235,6 +1351,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));
 
@@ -1243,7 +1361,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,7 +1387,7 @@ int FilterEffectsDialog::PrimitiveList::init_text()
 
     int maxfont = 0;
     for(int i = 0; i < FPInputConverter.end; ++i) {
-        _vertical_layout->set_text(FPInputConverter.get_label((FilterPrimitiveInput)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)
@@ -1312,7 +1430,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) {
@@ -1324,6 +1442,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);
@@ -1355,7 +1475,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)
 {
@@ -1378,7 +1512,7 @@ bool FilterEffectsDialog::PrimitiveList::on_expose_signal(GdkEventExpose* e)
 
         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));
+            _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);
@@ -1464,31 +1598,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();
+    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) {
+    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;
-
-        get_cell_area(get_model()->get_path(_model->children().begin()), *get_column(1), rct);
-        const int fheight = CellRendererConnection::size;
+    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(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(use_default) {
+            res = input;
+            --res;
+        }
 
-        // 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);
+        if(res) {
+            Gdk::Rectangle rct;
+            
+            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);            
+        }
     }
 }
 
@@ -1526,10 +1680,15 @@ const Gtk::TreeIter FilterEffectsDialog::PrimitiveList::find_result(const Gtk::T
 
     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)
@@ -1786,7 +1945,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,12 +2003,12 @@ int FilterEffectsDialog::PrimitiveList::primitive_count() const
 /*** FilterEffectsDialog ***/
 
 FilterEffectsDialog::FilterEffectsDialog() 
-    : Dialog ("dialogs.filtereffects", SP_VERB_DIALOG_FILTER_EFFECTS),
+    : UI::Widget::Panel("", "dialogs.filtereffects", SP_VERB_DIALOG_FILTER_EFFECTS),
       _filter_modifier(*this),
       _primitive_list(*this),
       _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),
       _locked(false),
       _attr_lock(false)
 {
@@ -1857,30 +2016,42 @@ FilterEffectsDialog::FilterEffectsDialog()
                              NR_FILTER_ENDPRIMITIVETYPE);
     _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);
     Gtk::HBox* hb_prims = Gtk::manage(new Gtk::HBox);
-    Gtk::Frame* fr_settings = Gtk::manage(new Gtk::Frame(_("<b>Settings</b>")));
+    Gtk::Frame* fr_settings = Gtk::manage(new Gtk::Frame(_("<b>Effect parameters</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(*infobox,false, false);    
     _primitive_box.pack_start(*hb_prims, false, false);
     sw_prims->add(_primitive_list);
-    hb_prims->pack_end(_add_primitive, false, false);
+    infobox->pack_start(_infobox_icon, false, false);
+    infobox->pack_end(_infobox_desc, false, false);
+    _infobox_desc.set_line_wrap(true);
+    
     hb_prims->pack_end(_add_primitive_type, false, false);
-    get_vbox()->pack_start(*fr_settings, false, false);
+    hb_prims->pack_end(_add_primitive, false, false);
+    _getContents()->pack_start(*fr_settings, false, false);
     fr_settings->add(*al_settings);
     al_settings->add(_settings_box);
-
+    
     _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);
@@ -1888,12 +2059,12 @@ FilterEffectsDialog::FilterEffectsDialog()
     ((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()
@@ -1906,6 +2077,13 @@ 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,
@@ -1923,33 +2101,35 @@ void FilterEffectsDialog::init_settings_widgets()
     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();
+    /*_settings->add_combo(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);
+    _k1 = _settings->add_spinslider(SP_ATTR_K1, _("K1"), -10, 10, 0.1, 0.01, 2);
+    _k2 = _settings->add_spinslider(SP_ATTR_K2, _("K2"), -10, 10, 0.1, 0.01, 2);
+    _k3 = _settings->add_spinslider(SP_ATTR_K3, _("K3"), -10, 10, 0.1, 0.01, 2);
+    _k4 = _settings->add_spinslider(SP_ATTR_K4, _("K4"), -10, 10, 0.1, 0.01, 2);
 
     _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->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_DIVISOR, _("Divisor"), 1, 20, 1, 0.1, 2);
     _settings->add_spinslider(SP_ATTR_BIAS, _("Bias"), -10, 10, 1, 0.01, 1);
     _settings->add_combo(SP_ATTR_EDGEMODE, _("Edge Mode"), ConvolveMatrixEdgeModeConverter);
+    _settings->add_checkbutton(SP_ATTR_PRESERVEALPHA, _("Preserve Alpha"), "true", "false");
 
     _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_spinslider(SP_ATTR_SURFACESCALE, _("Surface Scale"), -1000, 1000, 1, 0.01, 1);
+    _settings->add_spinslider(SP_ATTR_DIFFUSECONSTANT, _("Constant"), 0, 100, 0.1, 0.01, 2);
     _settings->add_dualspinslider(SP_ATTR_KERNELUNITLENGTH, _("Kernel Unit Length"), 0.01, 10, 1, 0.01, 1);
     _settings->add_lightsource();
 
@@ -1969,22 +2149,30 @@ void FilterEffectsDialog::init_settings_widgets()
     _settings->add_combo(SP_ATTR_OPERATOR, _("Operator"), MorphologyOperatorConverter);
     _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->add_multispinbutton(SP_ATTR_X, SP_ATTR_Y, _("Coordinates"), -10000, 10000, 1, 1, 0);
+    _settings->add_multispinbutton(SP_ATTR_WIDTH, SP_ATTR_HEIGHT, _("Dimensions"), 0, 10000, 1, 1, 0);
+    
     _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->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_SURFACESCALE, _("Surface Scale"), -1000, 1000, 1, 0.01, 1);
+    _settings->add_spinslider(SP_ATTR_SPECULARCONSTANT, _("Constant"), 0, 100, 0.1, 0.01, 2);
     _settings->add_spinslider(SP_ATTR_SPECULAREXPONENT, _("Exponent"), 1, 128, 1, 0.01, 1);
     _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_dualspinslider(SP_ATTR_BASEFREQUENCY, _("Base Frequency"), 0, 1, 0.001, 0.01, 3);
     _settings->add_spinslider(SP_ATTR_NUMOCTAVES, _("Octaves"), 1, 10, 1, 1, 0);
     _settings->add_spinslider(SP_ATTR_SEED, _("Seed"), 0, 1000, 1, 1, 0);
 }
@@ -1992,7 +2180,7 @@ void FilterEffectsDialog::init_settings_widgets()
 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);
 
@@ -2002,17 +2190,73 @@ 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();
+    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;
     }
 }
 
@@ -2105,12 +2349,14 @@ void FilterEffectsDialog::update_settings_sensitivity()
         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);
+
+        // Component transfer not yet implemented
+        /*_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);
+        _ct_offset->set_sensitive(gamma);*/
     }
 }