Code

* don't strech buttons on lpe dialog when resizing the dialog
[inkscape.git] / src / ui / dialog / filter-effects-dialog.cpp
index f2c40b968252c16001d18635f00ce97edd82597b..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;
@@ -545,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:
@@ -676,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,
@@ -705,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,
@@ -1883,7 +2017,6 @@ FilterEffectsDialog::FilterEffectsDialog()
     _sizegroup = Gtk::SizeGroup::create(Gtk::SIZE_GROUP_HORIZONTAL);
     _sizegroup->set_ignore_hidden();
 
-    _add_primitive_type.remove_row(NR_FILTER_IMAGE);
     _add_primitive_type.remove_row(NR_FILTER_TILE);
     _add_primitive_type.remove_row(NR_FILTER_COMPONENTTRANSFER);
         
@@ -2017,8 +2150,10 @@ void FilterEffectsDialog::init_settings_widgets()
     _settings->add_dualspinslider(SP_ATTR_RADIUS, _("Radius"), 0, 100, 1, 0.01, 1);
 
     _settings->type(NR_FILTER_IMAGE);
-    _settings->add_notimplemented();
-
+    _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);
@@ -2060,15 +2195,15 @@ void FilterEffectsDialog::update_primitive_infobox()
     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 gives us 4 image blending modes: screen, multiply, darken and lighten."));
+            _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(_(""));
+            _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));
@@ -2080,7 +2215,7 @@ void FilterEffectsDialog::update_primitive_infobox()
             break;
         case(NR::NR_FILTER_DIFFUSELIGHTING):
             _infobox_icon.set(g_strdup_printf("%s/feDiffuseLighting-icon.png", INKSCAPE_PIXMAPDIR));
-            _infobox_desc.set_markup(_("Filter primitives <b>feDiffuseLighting</b> and feSpecularLighting create lighting maps for the object in input image. These filters use alpha channel of input image as a height map: the more opaque given point in input image is, the nearer spectator it is considered to be."));
+            _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));
@@ -2088,15 +2223,15 @@ void FilterEffectsDialog::update_primitive_infobox()
             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 its region with a given color and opacity. It can be used as an auxiliary tool, usualy in combination with other filter primitives, in order to facilitate some common color handling operations."));
+            _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 gives an out-of-focus aspect to images. It is commonly used toghether with feOffset in order to create a drop shadow effect."));
+            _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(_(""));
+            _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));
@@ -2112,11 +2247,11 @@ void FilterEffectsDialog::update_primitive_infobox()
             break;
         case(NR::NR_FILTER_SPECULARLIGHTING):
             _infobox_icon.set(g_strdup_printf("%s/feSpecularLighting-icon.png", INKSCAPE_PIXMAPDIR));
-            _infobox_desc.set_markup(_("Filter primitives feDiffuseLighting and <b>feSpecularLighting</b> create lighting maps for the object in input image. These filters use alpha channel of input image as a height map: the more opaque given point in input image is, the nearer spectator it is considered to be."));
+            _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(_(""));
+            _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));