summaryrefslogtreecommitdiffstats
path: root/src/ui
diff options
context:
space:
mode:
authorMenTaLguY <mental@rydia.net>2007-06-24 18:42:18 +0000
committermental <mental@users.sourceforge.net>2007-06-24 18:42:18 +0000
commit76c45c245203714154525b3847af05dbd6ec4fb6 (patch)
treebaa78a89a82b4ee2520f72830f44c6c5d2c23d7f /src/ui
parentmerge OpenFont license support (diff)
downloadinkscape-76c45c245203714154525b3847af05dbd6ec4fb6.tar.gz
inkscape-76c45c245203714154525b3847af05dbd6ec4fb6.zip
initial filter UI code drop from Nick
(bzr r3095)
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/dialog/Makefile_insert2
-rw-r--r--src/ui/dialog/dialog-manager.cpp2
-rw-r--r--src/ui/dialog/fill-and-stroke.cpp4
-rw-r--r--src/ui/dialog/filter-effects-dialog.cpp636
-rw-r--r--src/ui/dialog/filter-effects-dialog.h193
-rw-r--r--src/ui/stock.cpp1
-rw-r--r--src/ui/stock.h1
-rw-r--r--src/ui/view/edit-widget.cpp3
-rw-r--r--src/ui/widget/Makefile_insert5
-rw-r--r--src/ui/widget/filter-effect-chooser.cpp254
-rw-r--r--src/ui/widget/filter-effect-chooser.h120
-rw-r--r--src/ui/widget/filter-effect-enums.h156
-rw-r--r--src/ui/widget/spin-slider.cpp87
-rw-r--r--src/ui/widget/spin-slider.h64
14 files changed, 1526 insertions, 2 deletions
diff --git a/src/ui/dialog/Makefile_insert b/src/ui/dialog/Makefile_insert
index 2b04d3e45..c1cb65d29 100644
--- a/src/ui/dialog/Makefile_insert
+++ b/src/ui/dialog/Makefile_insert
@@ -24,6 +24,8 @@ ui_dialog_libuidialog_a_SOURCES = \
ui/dialog/filedialog.h \
ui/dialog/fill-and-stroke.cpp \
ui/dialog/fill-and-stroke.h \
+ ui/dialog/filter-effects-dialog.h \
+ ui/dialog/filter-effects-dialog.cpp \
ui/dialog/find.cpp \
ui/dialog/find.h \
ui/dialog/inkscape-preferences.cpp \
diff --git a/src/ui/dialog/dialog-manager.cpp b/src/ui/dialog/dialog-manager.cpp
index d685f2e59..6b0277610 100644
--- a/src/ui/dialog/dialog-manager.cpp
+++ b/src/ui/dialog/dialog-manager.cpp
@@ -23,6 +23,7 @@
#include "ui/dialog/export.h"
#include "ui/dialog/extension-editor.h"
#include "ui/dialog/fill-and-stroke.h"
+#include "ui/dialog/filter-effects-dialog.h"
#include "ui/dialog/find.h"
#include "ui/dialog/inkscape-preferences.h"
#include "ui/dialog/layer-editor.h"
@@ -75,6 +76,7 @@ DialogManager::DialogManager() {
registerFactory("Export", &create<Export>);
registerFactory("ExtensionEditor", &create<ExtensionEditor>);
registerFactory("FillAndStroke", &create<FillAndStroke>);
+ registerFactory("FilterEffectsDialog", &create<FilterEffectsDialog>);
registerFactory("Find", &create<Find>);
registerFactory("InkscapePreferences", &create<InkscapePreferences>);
registerFactory("LayerEditor", &create<LayerEditor>);
diff --git a/src/ui/dialog/fill-and-stroke.cpp b/src/ui/dialog/fill-and-stroke.cpp
index 6206c4345..3559e3685 100644
--- a/src/ui/dialog/fill-and-stroke.cpp
+++ b/src/ui/dialog/fill-and-stroke.cpp
@@ -183,8 +183,8 @@ FillAndStroke::_blurValueChanged()
if (radius == 0.0) {
remove_filter (item, false);
} else {
- SPFilter *constructed = new_filter_gaussian_blur_from_item(document, item, radius);
- sp_style_set_property_url (SP_OBJECT(item), "filter", SP_OBJECT(constructed), false);
+ //SPFilter *constructed = new_filter_gaussian_blur_from_item(document, item, radius);
+ //sp_style_set_property_url (SP_OBJECT(item), "filter", SP_OBJECT(constructed), false);
}
//request update
SP_OBJECT(item)->requestDisplayUpdate(( SP_OBJECT_MODIFIED_FLAG |
diff --git a/src/ui/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp
new file mode 100644
index 000000000..1d14d69f4
--- /dev/null
+++ b/src/ui/dialog/filter-effects-dialog.cpp
@@ -0,0 +1,636 @@
+/**
+ * \brief Filter Effects dialog
+ *
+ * Authors:
+ * Nicholas Bishop <nicholasbishop@gmail.org>
+ *
+ * Copyright (C) 2007 Authors
+ *
+ * Released under GNU GPL. Read the file 'COPYING' for more information.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <gtk/gtktreeview.h>
+#include <gtkmm/cellrenderertext.h>
+#include <gtkmm/paned.h>
+#include <gtkmm/scale.h>
+#include <gtkmm/scrolledwindow.h>
+#include <gtkmm/spinbutton.h>
+#include <gtkmm/stock.h>
+#include <glibmm/i18n.h>
+
+#include "application/application.h"
+#include "application/editor.h"
+#include "desktop.h"
+#include "desktop-handles.h"
+#include "dialog-manager.h"
+#include "document.h"
+#include "filter-chemistry.h"
+#include "filter-effects-dialog.h"
+#include "inkscape.h"
+#include "sp-filter-primitive.h"
+#include "sp-gaussian-blur.h"
+#include "sp-feoffset.h"
+#include "verbs.h"
+#include "xml/node.h"
+#include "xml/repr.h"
+#include <sstream>
+
+#include <iostream>
+
+namespace Inkscape {
+namespace UI {
+namespace Dialog {
+
+Glib::RefPtr<Gtk::Menu> create_popup_menu(Gtk::Widget& parent, sigc::slot<void> dup,
+ sigc::slot<void> rem)
+{
+ Glib::RefPtr<Gtk::Menu> menu(new Gtk::Menu);
+
+ menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("_Duplicate"), dup));
+ Gtk::MenuItem* mi = Gtk::manage(new Gtk::ImageMenuItem(Gtk::Stock::REMOVE));
+ menu->append(*mi);
+ mi->signal_activate().connect(rem);
+ mi->show();
+ menu->accelerate(parent);
+
+ return menu;
+}
+
+static void try_id_change(SPObject* ob, const Glib::ustring& text)
+{
+ // FIXME: this needs more serious error checking...
+ if(ob && !SP_ACTIVE_DOCUMENT->getObjectById(text.c_str())) {
+ SPException ex;
+ SP_EXCEPTION_INIT(&ex);
+ sp_object_setAttribute(ob, "id", text.c_str(), &ex);
+ sp_document_done(SP_ACTIVE_DOCUMENT, SP_VERB_DIALOG_FILTER_EFFECTS, _("Set object ID"));
+ }
+}
+
+/*** FilterModifier ***/
+FilterEffectsDialog::FilterModifier::FilterModifier()
+ : _add(Gtk::Stock::ADD)
+{
+ Gtk::ScrolledWindow* sw = Gtk::manage(new Gtk::ScrolledWindow);
+ pack_start(*sw);
+ pack_start(_add, false, false);
+ sw->add(_list);
+
+ _list.set_model(_model);
+ _list.append_column_editable(_("_Filter"), _columns.id);
+ ((Gtk::CellRendererText*)_list.get_column(0)->get_first_cell_renderer())->
+ signal_edited().connect(sigc::mem_fun(*this, &FilterEffectsDialog::FilterModifier::filter_name_edited));
+
+ sw->set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
+ sw->set_shadow_type(Gtk::SHADOW_IN);
+ show_all_children();
+ _add.signal_clicked().connect(sigc::mem_fun(*this, &FilterModifier::add_filter));
+ _list.signal_button_press_event().connect_notify(
+ sigc::mem_fun(*this, &FilterModifier::filter_list_button_press));
+ _menu = create_popup_menu(*this, sigc::mem_fun(*this, &FilterModifier::duplicate_filter),
+ sigc::mem_fun(*this, &FilterModifier::remove_filter));
+
+ update_filters();
+}
+
+Glib::SignalProxy0<void> FilterEffectsDialog::FilterModifier::signal_selection_changed()
+{
+ return _list.get_selection()->signal_changed();
+}
+
+SPFilter* FilterEffectsDialog::FilterModifier::get_selected_filter()
+{
+ if(_list.get_selection()) {
+ Gtk::TreeModel::iterator i = _list.get_selection()->get_selected();
+
+ if(i)
+ return (*i)[_columns.filter];
+ }
+
+ return 0;
+}
+
+void FilterEffectsDialog::FilterModifier::select_filter(const SPFilter* filter)
+{
+ if(filter) {
+ for(Gtk::TreeModel::iterator i = _model->children().begin();
+ i != _model->children().end(); ++i) {
+ if((*i)[_columns.filter] == filter) {
+ _list.get_selection()->select(i);
+ break;
+ }
+ }
+ }
+}
+
+void FilterEffectsDialog::FilterModifier::filter_list_button_press(GdkEventButton* event)
+{
+ if((event->type == GDK_BUTTON_PRESS) && (event->button == 3)) {
+ const bool sensitive = get_selected_filter() != NULL;
+ _menu->items()[0].set_sensitive(sensitive);
+ _menu->items()[1].set_sensitive(sensitive);
+ _menu->popup(event->button, event->time);
+ }
+}
+
+void FilterEffectsDialog::FilterModifier::add_filter()
+{
+ SPDocument* doc = sp_desktop_document(SP_ACTIVE_DESKTOP);
+ SPFilter* filter = new_filter(doc);
+
+ update_filters();
+
+ select_filter(filter);
+
+ sp_document_done(doc, SP_VERB_DIALOG_FILTER_EFFECTS, _("Add filter"));
+}
+
+void FilterEffectsDialog::FilterModifier::remove_filter()
+{
+ SPFilter *filter = get_selected_filter();
+
+ if(filter) {
+ SPDocument* doc = filter->document;
+ sp_repr_unparent(filter->repr);
+
+ sp_document_done(doc, SP_VERB_DIALOG_FILTER_EFFECTS, _("Remove filter"));
+
+ update_filters();
+ }
+}
+
+void FilterEffectsDialog::FilterModifier::duplicate_filter()
+{
+ SPFilter *filter = get_selected_filter();
+
+ if(filter) {
+ //SPFilter *dupfilter = filter_duplicate(sp_desktop_document(SP_ACTIVE_DESKTOP), filter);
+
+ sp_document_done(filter->document, SP_VERB_DIALOG_FILTER_EFFECTS, _("Duplicate filter"));
+
+ update_filters();
+ }
+}
+
+void FilterEffectsDialog::FilterModifier::filter_name_edited(const Glib::ustring& path, const Glib::ustring& text)
+{
+ Gtk::TreeModel::iterator i = _model->get_iter(path);
+
+ if(i)
+ try_id_change((SPObject*)(*i)[_columns.filter], text);
+}
+
+/*** SettingsFrame ***/
+FilterEffectsDialog::SettingsFrame::SettingsFrame()
+ : _where(0)
+{
+ set_col_spacings(12);
+ show();
+}
+
+void FilterEffectsDialog::SettingsFrame::init(Gtk::VBox& box)
+{
+ box.pack_start(*this, false, false);
+}
+
+void FilterEffectsDialog::SettingsFrame::add_setting(Gtk::Widget& w, const Glib::ustring& label)
+{
+ Gtk::Label *lbl = new Gtk::Label(label + ":", Gtk::ALIGN_LEFT);
+
+ attach(*Gtk::manage(lbl), 0, 1, _where, _where + 1, Gtk::FILL, Gtk::FILL);
+ attach(w, 1, 2, _where, _where + 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL);
+
+ lbl->show();
+ w.show();
+
+ ++_where;
+}
+
+/*** FilterEffectsDialog ***/
+
+FilterEffectsDialog::FilterEffectsDialog()
+ : Dialog ("dialogs.filtereffects", SP_VERB_DIALOG_FILTER_EFFECTS),
+ _add_primitive_type(FPConverter),
+ _add_primitive(Gtk::Stock::ADD),
+ _empty_settings("No primitive selected", Gtk::ALIGN_LEFT),
+ _blend_mode(BlendModeConverter),
+ _gaussianblur_stddeviation(1, 0, 100, 1, 0.01, 1),
+ _morphology_radius(1, 0, 100, 1, 0.01, 1),
+ _offset_dx(0, -100, 100, 1, 0.01, 1),
+ _offset_dy(0, -100, 100, 1, 0.01, 1),
+ _turbulence_basefrequency(1, 0, 100, 1, 0.01, 1),
+ _turbulence_numoctaves(1, 0, 100, 1, 0.01, 1),
+ _turbulence_seed(1, 0, 100, 1, 0.01, 1)
+{
+ // Initialize widget hierarchy
+ Gtk::HPaned* hpaned = Gtk::manage(new Gtk::HPaned);
+ Gtk::VBox* vb_prims = Gtk::manage(new Gtk::VBox);
+ Gtk::ScrolledWindow* sw_prims = Gtk::manage(new Gtk::ScrolledWindow);
+ Gtk::HBox* hb_prims = Gtk::manage(new Gtk::HBox);
+ Gtk::Frame* fr_settings = Gtk::manage(new Gtk::Frame("<b>Settings</b>"));
+ Gtk::Alignment* al_settings = Gtk::manage(new Gtk::Alignment);
+ get_vbox()->add(*hpaned);
+ hpaned->pack1(_filter_modifier);
+ hpaned->pack2(*vb_prims);
+ vb_prims->pack_start(*sw_prims);
+ vb_prims->pack_start(*hb_prims, false, false);
+ sw_prims->add(_primitive_list);
+ hb_prims->pack_end(_add_primitive, false, false);
+ hb_prims->pack_end(_add_primitive_type, false, false);
+ get_vbox()->pack_start(*fr_settings, false, false);
+ fr_settings->add(*al_settings);
+ al_settings->add(_settings);
+
+ // Primitive list
+ _primitive_model = Gtk::ListStore::create(_primitive_columns);
+ _primitive_list.set_reorderable(true);
+ _primitive_list.set_model(_primitive_model);
+ //_primitive_list.append_column_editable(_("_Primitive"), _primitive_columns.id);
+ _primitive_list.append_column("Type", _primitive_columns.type);
+ ((Gtk::CellRendererText*)_primitive_list.get_column(0)->get_first_cell_renderer())->
+ signal_edited().connect(sigc::mem_fun(*this, &FilterEffectsDialog::primitive_name_edited));
+ _filter_modifier.signal_selection_changed().connect(
+ sigc::mem_fun(*this, &FilterEffectsDialog::update_primitive_list));
+ _primitive_list.get_selection()->signal_changed().connect(
+ sigc::mem_fun(*this, &FilterEffectsDialog::update_settings_view));
+ _primitive_list.signal_button_press_event().connect_notify(
+ sigc::mem_fun(*this, &FilterEffectsDialog::primitive_list_button_press));
+ _primitive_list.signal_drag_end().connect(
+ sigc::mem_fun(*this, &FilterEffectsDialog::primitive_list_drag_end));
+
+ // Other widgets
+ sw_prims->set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
+ sw_prims->set_shadow_type(Gtk::SHADOW_IN);
+ al_settings->set_padding(0, 0, 12, 0);
+ fr_settings->set_shadow_type(Gtk::SHADOW_NONE);
+ ((Gtk::Label*)fr_settings->get_label_widget())->set_use_markup();
+ _add_primitive.signal_clicked().connect(sigc::mem_fun(*this, &FilterEffectsDialog::add_primitive));
+ _primitive_menu = create_popup_menu(*this, sigc::mem_fun(*this, &FilterEffectsDialog::duplicate_primitive),
+ sigc::mem_fun(*this, &FilterEffectsDialog::remove_primitive));
+
+ show_all_children();
+ init_settings_widgets();
+ update_primitive_list();
+ update_settings_view();
+}
+
+FilterEffectsDialog::~FilterEffectsDialog()
+{
+}
+
+void FilterEffectsDialog::primitive_list_button_press(GdkEventButton* event)
+{
+ if((event->type == GDK_BUTTON_PRESS) && (event->button == 3)) {
+ const bool sensitive = get_selected_primitive() != NULL;
+ _primitive_menu->items()[0].set_sensitive(sensitive);
+ _primitive_menu->items()[1].set_sensitive(sensitive);
+ _primitive_menu->popup(event->button, event->time);
+ }
+}
+
+// Reorder the filter primitives to match the list order
+void FilterEffectsDialog::primitive_list_drag_end(const Glib::RefPtr<Gdk::DragContext>&)
+{
+ int ndx = 0;
+ SPFilter* filter = _filter_modifier.get_selected_filter();
+
+ for(Gtk::TreeModel::iterator iter = _primitive_model->children().begin();
+ iter != _primitive_model->children().end(); ++iter) {
+ SPFilterPrimitive* prim = (*iter)[_primitive_columns.primitive];
+ if(prim)
+ ;//reorder_primitive(filter, prim->repr->position(), ndx); /* FIXME */
+ std::cout << prim->repr->position();
+ }
+
+ sp_document_done(filter->document, SP_VERB_DIALOG_FILTER_EFFECTS, _("Reorder filter primitive"));
+}
+
+void FilterEffectsDialog::init_settings_widgets()
+{
+ _empty_settings.set_sensitive(false);
+ _settings.pack_start(_empty_settings);
+
+ _blend.init(_settings);
+ _blend.add_setting(_blend_mode, "Mode");
+ _blend_mode.signal_changed().connect(
+ sigc::bind(sigc::mem_fun(*this, &FilterEffectsDialog::set_attr), SP_ATTR_MODE));
+
+ _colormatrix.init(_settings);
+ _colormatrix.add_setting(_colormatrix_type, "Type");
+
+ _componenttransfer.init(_settings);
+
+ _composite.init(_settings);
+
+ _convolvematrix.init(_settings);
+
+ _diffuselighting.init(_settings);
+
+ _displacementmap.init(_settings);
+
+ _flood.init(_settings);
+
+ _gaussianblur.init(_settings);
+ _gaussianblur.add_setting(_gaussianblur_stddeviation, "Standard Deviation");
+ _gaussianblur_stddeviation.signal_value_changed().connect(
+ sigc::bind(sigc::mem_fun(*this, &FilterEffectsDialog::set_attr), SP_ATTR_STDDEVIATION));
+
+ _image.init(_settings);
+
+ _merge.init(_settings);
+
+ _morphology.init(_settings);
+ _morphology.add_setting(_morphology_operator, "Operator");
+ _morphology.add_setting(_morphology_radius, "Radius");
+
+ _offset.init(_settings);
+ _offset.add_setting(_offset_dx, "Delta X");
+ _offset_dx.signal_value_changed().connect(
+ sigc::bind(sigc::mem_fun(*this, &FilterEffectsDialog::set_attr), SP_ATTR_DX));
+ _offset.add_setting(_offset_dy, "Delta Y");
+ _offset_dy.signal_value_changed().connect(
+ sigc::bind(sigc::mem_fun(*this, &FilterEffectsDialog::set_attr), SP_ATTR_DY));
+
+ _specularlighting.init(_settings);
+
+ _tile.init(_settings);
+
+ _turbulence.init(_settings);
+ _turbulence.add_setting(_turbulence_basefrequency, "Base Frequency");
+ _turbulence.add_setting(_turbulence_numoctaves, "Octaves");
+ _turbulence.add_setting(_turbulence_seed, "Seed");
+ _turbulence.add_setting(_turbulence_stitchtiles, "Stitch Tiles");
+ _turbulence.add_setting(_turbulence_type, "Type");
+}
+
+void FilterEffectsDialog::add_primitive()
+{
+ SPFilter* filter = _filter_modifier.get_selected_filter();
+ const EnumData<NR::FilterPrimitiveType>* data = _add_primitive_type.get_active_data();
+
+ if(filter && data) {
+ SPFilterPrimitive* prim = filter_add_primitive(filter, data->name.c_str());
+
+ // Set default values
+ switch(data->id) {
+ case NR::NR_FILTER_BLEND:
+ sp_object_set(prim, SP_ATTR_MODE, BlendModeConverter.get_name(NR::BLEND_NORMAL).c_str());
+ break;
+ case NR::NR_FILTER_COLORMATRIX:
+ break;
+ case NR::NR_FILTER_COMPONENTTRANSFER:
+ break;
+ case NR::NR_FILTER_COMPOSITE:
+ break;
+ case NR::NR_FILTER_CONVOLVEMATRIX:
+ break;
+ case NR::NR_FILTER_DIFFUSELIGHTING:
+ break;
+ case NR::NR_FILTER_DISPLACEMENTMAP:
+ break;
+ case NR::NR_FILTER_FLOOD:
+ break;
+ case NR::NR_FILTER_GAUSSIANBLUR:
+ sp_object_set(prim, SP_ATTR_STDDEVIATION, "1");
+ break;
+ case NR::NR_FILTER_IMAGE:
+ break;
+ case NR::NR_FILTER_MERGE:
+ break;
+ case NR::NR_FILTER_MORPHOLOGY:
+ break;
+ case NR::NR_FILTER_OFFSET:
+ sp_object_set(prim, SP_ATTR_DX, "0");
+ sp_object_set(prim, SP_ATTR_DY, "0");
+ break;
+ case NR::NR_FILTER_SPECULARLIGHTING:
+ break;
+ case NR::NR_FILTER_TILE:
+ break;
+ case NR::NR_FILTER_TURBULENCE:
+ break;
+ default:
+ break;
+ }
+
+ update_primitive_list();
+ select_primitive(prim);
+
+ sp_document_done(filter->document, SP_VERB_DIALOG_FILTER_EFFECTS, _("Add filter primitive"));
+ }
+}
+
+void FilterEffectsDialog::remove_primitive()
+{
+ Gtk::TreeModel::iterator i = _primitive_list.get_selection()->get_selected();
+
+ if(i) {
+ SPFilterPrimitive* prim = (*i)[_primitive_columns.primitive];
+
+ sp_repr_unparent(prim->repr);
+
+ sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_DIALOG_FILTER_EFFECTS,
+ _("Remove filter primitive"));
+
+ update_primitive_list();
+ }
+}
+
+void FilterEffectsDialog::duplicate_primitive()
+{
+ SPFilter* filter = _filter_modifier.get_selected_filter();
+ SPFilterPrimitive* origprim = get_selected_primitive();
+
+ if(filter && origprim) {
+ Inkscape::XML::Node *repr;
+ repr = SP_OBJECT_REPR(origprim)->duplicate(SP_OBJECT_REPR(origprim)->document());
+ SP_OBJECT_REPR(filter)->appendChild(repr);
+
+ sp_document_done(filter->document, SP_VERB_DIALOG_FILTER_EFFECTS, _("Duplicate filter primitive"));
+
+ update_primitive_list();
+ }
+}
+
+// Edits the id of the primitive at path
+void FilterEffectsDialog::primitive_name_edited(const Glib::ustring& path, const Glib::ustring& text)
+{
+ Gtk::TreeModel::iterator i = _primitive_model->get_iter(path);
+
+ if(i)
+ try_id_change((*i)[_primitive_columns.primitive], text);
+}
+
+void FilterEffectsDialog::set_attr(const SPAttributeEnum attr)
+{
+ Gtk::TreeModel::iterator i = _primitive_list.get_selection()->get_selected();
+
+ if(i) {
+ SPFilter *filter = _filter_modifier.get_selected_filter();
+ SPFilterPrimitive* prim = (*i)[_primitive_columns.primitive];
+ std::ostringstream os;
+ Glib::ustring val;
+
+ if(attr == SP_ATTR_MODE) {
+ val = _blend_mode.get_active_data()->name;
+ }
+ else if(attr == SP_ATTR_STDDEVIATION) {
+ os << _gaussianblur_stddeviation.get_value();
+ val = os.str();
+ }
+ else if(attr == SP_ATTR_DX) {
+ os << _offset_dx.get_value();
+ val = os.str();
+ }
+ else if(attr == SP_ATTR_DY) {
+ os << _offset_dy.get_value();
+ val = os.str();
+ }
+
+ sp_object_set(prim, attr, val.c_str());
+ filter->requestModified(SP_OBJECT_MODIFIED_FLAG);
+
+ sp_document_done(filter->document, SP_VERB_DIALOG_FILTER_EFFECTS, _("Set filter primitive attribute"));
+ }
+}
+
+/* Add all filter primitives in the current to the list.
+ Keeps the same selection if possible, otherwise selects the first element */
+void FilterEffectsDialog::update_primitive_list()
+{
+ SPFilter* f = _filter_modifier.get_selected_filter();
+ const SPFilterPrimitive* active_prim = get_selected_primitive();
+ bool active_found = false;
+
+ _primitive_model->clear();
+
+ if(f) {
+ _primitive_box.set_sensitive(true);
+
+ for(SPObject *prim_obj = f->children;
+ prim_obj && SP_IS_FILTER_PRIMITIVE(prim_obj);
+ prim_obj = prim_obj->next) {
+ SPFilterPrimitive *prim = SP_FILTER_PRIMITIVE(prim_obj);
+ if(prim) {
+ Gtk::TreeModel::Row row = *_primitive_model->append();
+ row[_primitive_columns.primitive] = prim;
+ row[_primitive_columns.type_id] = FPConverter.get_id_from_name(prim->repr->name());
+ row[_primitive_columns.type] = FPConverter.get_label(row[_primitive_columns.type_id]);
+ row[_primitive_columns.id] = SP_OBJECT_ID(prim);
+
+ if(prim == active_prim) {
+ _primitive_list.get_selection()->select(row);
+ active_found = true;
+ }
+ }
+ }
+
+ if(!active_found && _primitive_model->children().begin())
+ _primitive_list.get_selection()->select(_primitive_model->children().begin());
+ }
+ else {
+ _primitive_box.set_sensitive(false);
+ }
+}
+
+void FilterEffectsDialog::update_settings_view()
+{
+ SPFilterPrimitive* prim = get_selected_primitive();
+
+ // Hide all the settings except for common
+ Glib::ListHandle<Widget*> c = _settings.get_children();
+ for(Glib::ListHandle<Widget*>::iterator iter = c.begin();
+ iter != c.end(); ++iter) {
+ (*iter)->hide();
+ }
+
+ _settings.set_sensitive(false);
+ _empty_settings.show();
+
+ if(prim) {
+ const NR::FilterPrimitiveType tid = FPConverter.get_id_from_name(prim->repr->name());
+ if(tid == NR::NR_FILTER_BLEND) {
+ _blend.show();
+ const gchar* val = prim->repr->attribute("mode");
+ if(val)
+ _blend_mode.set_active(BlendModeConverter.get_id_from_name(val));
+ }
+ else if(tid == NR::NR_FILTER_COLORMATRIX)
+ _colormatrix.show();
+ else if(tid == NR::NR_FILTER_COMPONENTTRANSFER)
+ _componenttransfer.show();
+ else if(tid == NR::NR_FILTER_COMPOSITE)
+ _composite.show();
+ else if(tid == NR::NR_FILTER_CONVOLVEMATRIX)
+ _convolvematrix.show();
+ else if(tid == NR::NR_FILTER_DIFFUSELIGHTING)
+ _diffuselighting.show();
+ else if(tid == NR::NR_FILTER_DISPLACEMENTMAP)
+ _displacementmap.show();
+ else if(tid == NR::NR_FILTER_FLOOD)
+ _flood.show();
+ else if(tid == NR::NR_FILTER_GAUSSIANBLUR) {
+ _gaussianblur.show();
+ _gaussianblur_stddeviation.set_value(((SPGaussianBlur*)prim)->stdDeviation.getNumber());
+ }
+ else if(tid == NR::NR_FILTER_IMAGE)
+ _image.show();
+ else if(tid == NR::NR_FILTER_MERGE)
+ _merge.show();
+ else if(tid == NR::NR_FILTER_MORPHOLOGY)
+ _morphology.show();
+ else if(tid == NR::NR_FILTER_OFFSET) {
+ _offset.show();
+ _offset_dx.set_value(((SPFeOffset*)prim)->dx);
+ _offset_dy.set_value(((SPFeOffset*)prim)->dy);
+ }
+ else if(tid == NR::NR_FILTER_SPECULARLIGHTING)
+ _specularlighting.show();
+ else if(tid == NR::NR_FILTER_TILE)
+ _tile.show();
+ else if(tid == NR::NR_FILTER_TURBULENCE)
+ _turbulence.show();
+
+ _settings.set_sensitive(true);
+ _empty_settings.hide();
+ }
+}
+
+SPFilterPrimitive* FilterEffectsDialog::get_selected_primitive()
+{
+ if(_filter_modifier.get_selected_filter()) {
+ Gtk::TreeModel::iterator i = _primitive_list.get_selection()->get_selected();
+ if(i)
+ return (*i)[_primitive_columns.primitive];
+ }
+
+ return 0;
+}
+
+void FilterEffectsDialog::select_primitive(SPFilterPrimitive* prim)
+{
+ for(Gtk::TreeIter i = _primitive_model->children().begin();
+ i != _primitive_model->children().end(); ++i) {
+ if((*i)[_primitive_columns.primitive] == prim)
+ _primitive_list.get_selection()->select(i);
+ }
+}
+
+} // namespace Dialog
+} // namespace UI
+} // namespace Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/ui/dialog/filter-effects-dialog.h b/src/ui/dialog/filter-effects-dialog.h
new file mode 100644
index 000000000..3438348d5
--- /dev/null
+++ b/src/ui/dialog/filter-effects-dialog.h
@@ -0,0 +1,193 @@
+/**
+ * \brief Filter Effects dialog
+ *
+ * Authors:
+ * Nicholas Bishop <nicholasbishop@gmail.com>
+ *
+ * Copyright (C) 2007 Authors
+ *
+ * Released under GNU GPL. Read the file 'COPYING' for more information.
+ */
+
+#ifndef INKSCAPE_UI_DIALOG_FILTER_EFFECTS_H
+#define INKSCAPE_UI_DIALOG_FILTER_EFFECTS_H
+
+#include <gtkmm/adjustment.h>
+#include <gtkmm/alignment.h>
+#include <gtkmm/box.h>
+#include <gtkmm/buttonbox.h>
+#include <gtkmm/comboboxtext.h>
+#include <gtkmm/drawingarea.h>
+#include <gtkmm/frame.h>
+#include <gtkmm/liststore.h>
+#include <gtkmm/menu.h>
+#include <gtkmm/treeview.h>
+
+#include "attributes.h"
+#include "dialog.h"
+#include "sp-filter.h"
+#include "ui/widget/filter-effect-chooser.h"
+#include "ui/widget/notebook-page.h"
+#include "ui/widget/spin-slider.h"
+
+using namespace Inkscape::UI::Widget;
+
+namespace Inkscape {
+namespace UI {
+namespace Dialog {
+
+class FilterEffectsDialog : public Dialog {
+public:
+ FilterEffectsDialog();
+ virtual ~FilterEffectsDialog();
+
+ static FilterEffectsDialog *create() { return new FilterEffectsDialog(); }
+private:
+ class FilterModifier : public Gtk::VBox, public FilterEffectChooser
+ {
+ public:
+ FilterModifier();
+
+ virtual SPFilter* get_selected_filter();
+ virtual void select_filter(const SPFilter*);
+ virtual Glib::SignalProxy0<void> signal_selection_changed();
+ private:
+ void filter_list_button_press(GdkEventButton*);
+ void add_filter();
+ void remove_filter();
+ void duplicate_filter();
+ void filter_name_edited(const Glib::ustring& path, const Glib::ustring& text);
+
+ Gtk::TreeView _list;
+ Gtk::Button _add;
+ Glib::RefPtr<Gtk::Menu> _menu;
+ };
+
+ class PrimitiveColumns : public Gtk::TreeModel::ColumnRecord
+ {
+ public:
+ PrimitiveColumns()
+ {
+ add(primitive);
+ add(type_id);
+ add(type);
+ add(id);
+ }
+
+ Gtk::TreeModelColumn<SPFilterPrimitive*> primitive;
+ Gtk::TreeModelColumn<NR::FilterPrimitiveType> type_id;
+ Gtk::TreeModelColumn<Glib::ustring> type;
+ Gtk::TreeModelColumn<Glib::ustring> id;
+ };
+
+ class SettingsFrame : public Gtk::Table
+ {
+ public:
+ SettingsFrame();
+
+ void init(Gtk::VBox& box);
+ void add_setting(Gtk::Widget& w, const Glib::ustring& label);
+ private:
+ Gtk::Alignment _alignment;
+ Gtk::Table _table;
+ int _where;
+ };
+
+ void init_settings_widgets();
+
+ // Handlers
+ void add_primitive();
+ void remove_primitive();
+ void duplicate_primitive();
+ void primitive_name_edited(const Glib::ustring& path, const Glib::ustring& text);
+ void primitive_list_button_press(GdkEventButton* event);
+ void primitive_list_drag_end(const Glib::RefPtr<Gdk::DragContext>&);
+
+ void set_attr(const SPAttributeEnum);
+ void update_settings_view();
+ void update_primitive_list();
+
+ SPFilterPrimitive* get_selected_primitive();
+ void select_primitive(SPFilterPrimitive *prim);
+
+ // Filter effect selection
+ FilterModifier _filter_modifier;
+
+ // View/add primitives
+ Gtk::VBox _primitive_box;
+ Gtk::TreeView _primitive_list;
+ Glib::RefPtr<Gtk::ListStore> _primitive_model;
+ PrimitiveColumns _primitive_columns;
+ Glib::RefPtr<Gtk::Menu> _primitive_menu;
+ UI::Widget::ComboBoxEnum<NR::FilterPrimitiveType> _add_primitive_type;
+ Gtk::Button _add_primitive;
+
+ // Right pane (filter effect primitive settings)
+ Gtk::VBox _settings;
+ Gtk::Label _empty_settings;
+
+ SettingsFrame _blend;
+ UI::Widget::ComboBoxEnum<NR::FilterBlendMode> _blend_mode;
+
+ SettingsFrame _colormatrix;
+ Gtk::ComboBoxText _colormatrix_type;
+
+ SettingsFrame _componenttransfer;
+
+ SettingsFrame _composite;
+
+ SettingsFrame _convolvematrix;
+
+ SettingsFrame _diffuselighting;
+
+ SettingsFrame _displacementmap;
+
+ SettingsFrame _flood;
+
+ SettingsFrame _gaussianblur;
+ SpinSlider _gaussianblur_stddeviation;
+
+ SettingsFrame _image;
+
+ SettingsFrame _merge;
+
+ SettingsFrame _morphology;
+ Gtk::ComboBoxText _morphology_operator;
+ SpinSlider _morphology_radius;
+
+ SettingsFrame _offset;
+ SpinSlider _offset_dx;
+ SpinSlider _offset_dy;
+
+ SettingsFrame _specularlighting;
+
+ SettingsFrame _tile;
+
+ SettingsFrame _turbulence;
+ SpinSlider _turbulence_basefrequency;
+ SpinSlider _turbulence_numoctaves;
+ SpinSlider _turbulence_seed;
+ Gtk::ComboBoxText _turbulence_stitchtiles;
+ Gtk::ComboBoxText _turbulence_type;
+
+
+ FilterEffectsDialog(FilterEffectsDialog const &d);
+ FilterEffectsDialog& operator=(FilterEffectsDialog const &d);
+};
+
+} // namespace Dialog
+} // namespace UI
+} // namespace Inkscape
+
+#endif // INKSCAPE_UI_DIALOG_FILTER_EFFECTS_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/ui/stock.cpp b/src/ui/stock.cpp
index 7ceb86660..03e491340 100644
--- a/src/ui/stock.cpp
+++ b/src/ui/stock.cpp
@@ -83,6 +83,7 @@ Gtk::StockID const LAYER_TO_BOTTOM("layer-to-bottom");
// Object menu
Gtk::StockID const FILL_STROKE("fill-stroke");
Gtk::StockID const OBJECT_PROPERTIES("object-properties");
+Gtk::StockID const FILTER_EFFECTS("filter-effects");
Gtk::StockID const GROUP("group");
Gtk::StockID const UNGROUP("upgroup");
Gtk::StockID const RAISE("raise");
diff --git a/src/ui/stock.h b/src/ui/stock.h
index 069ab66f3..733edacdb 100644
--- a/src/ui/stock.h
+++ b/src/ui/stock.h
@@ -86,6 +86,7 @@ extern Gtk::StockID const LAYER_TO_BOTTOM;
// Object menu
extern Gtk::StockID const FILL_STROKE;
extern Gtk::StockID const OBJECT_PROPERTIES;
+extern Gtk::StockID const FILTER_EFFECTS;
extern Gtk::StockID const GROUP;
extern Gtk::StockID const UNGROUP;
extern Gtk::StockID const RAISE;
diff --git a/src/ui/view/edit-widget.cpp b/src/ui/view/edit-widget.cpp
index ca298cd5d..8e423c8fb 100644
--- a/src/ui/view/edit-widget.cpp
+++ b/src/ui/view/edit-widget.cpp
@@ -635,6 +635,9 @@ EditWidget::initMenuActions()
Stock::OBJECT_PROPERTIES),
sigc::mem_fun(*this, &EditWidget::onDialogObjectProperties));
+ _act_grp->add(Gtk::Action::create("FilterEffects",
+ Stock::FILTER_EFFECTS));
+
_act_grp->add(Gtk::Action::create("Group",
Stock::GROUP, Glib::ustring(),
_("PLACEHOLDER, do not translate")));
diff --git a/src/ui/widget/Makefile_insert b/src/ui/widget/Makefile_insert
index 30d52de01..72fb9cfc2 100644
--- a/src/ui/widget/Makefile_insert
+++ b/src/ui/widget/Makefile_insert
@@ -18,6 +18,9 @@ ui_widget_libuiwidget_a_SOURCES = \
ui/widget/entity-entry.h \
ui/widget/entry.cpp \
ui/widget/entry.h \
+ ui/widget/filter-effect-chooser.h \
+ ui/widget/filter-effect-chooser.cpp \
+ ui/widget/filter-effect-enums.h \
ui/widget/handlebox.cpp \
ui/widget/handlebox.h \
ui/widget/icon-widget.cpp \
@@ -48,6 +51,8 @@ ui_widget_libuiwidget_a_SOURCES = \
ui/widget/scalar.h \
ui/widget/selected-style.h \
ui/widget/selected-style.cpp \
+ ui/widget/spin-slider.h \
+ ui/widget/spin-slider.cpp \
ui/widget/style-swatch.h \
ui/widget/style-swatch.cpp \
ui/widget/svg-canvas.cpp \
diff --git a/src/ui/widget/filter-effect-chooser.cpp b/src/ui/widget/filter-effect-chooser.cpp
new file mode 100644
index 000000000..fd8f46e04
--- /dev/null
+++ b/src/ui/widget/filter-effect-chooser.cpp
@@ -0,0 +1,254 @@
+/*
+ * Filter effect selection selection widget
+ *
+ * Author:
+ * Nicholas Bishop <nicholasbishop@gmail.com>
+ *
+ * Copyright (C) 2007 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <glibmm/i18n.h>
+
+#include "desktop.h"
+#include "desktop-handles.h"
+#include "document.h"
+#include "filter-effect-chooser.h"
+#include "inkscape.h"
+#include "ui/dialog/dialog-manager.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+FilterEffectChooser::FilterEffectChooser()
+{
+ _model = Gtk::ListStore::create(_columns);
+
+ g_signal_connect(G_OBJECT(INKSCAPE), "activate_desktop",
+ G_CALLBACK(&FilterEffectChooser::on_activate_desktop), this);
+
+
+ on_activate_desktop(INKSCAPE, SP_ACTIVE_DESKTOP, this);
+}
+
+void FilterEffectChooser::on_activate_desktop(Inkscape::Application*, SPDesktop* desktop, FilterEffectChooser* fec)
+{
+ fec->update_filters();
+
+ fec->_doc_replaced.disconnect();
+ fec->_doc_replaced = desktop->connectDocumentReplaced(
+ sigc::mem_fun(fec, &FilterEffectChooser::on_document_replaced));
+
+ fec->_resource_changed.disconnect();
+ fec->_resource_changed =
+ sp_document_resources_changed_connect(sp_desktop_document(desktop), "filter",
+ sigc::mem_fun(fec, &FilterEffectChooser::update_filters));
+}
+
+void FilterEffectChooser::on_document_replaced(SPDesktop* desktop, SPDocument* document)
+{
+ update_filters();
+}
+
+/* Add all filters in the document to the combobox.
+ Keeps the same selection if possible, otherwise selects the first element */
+void FilterEffectChooser::update_filters()
+{
+ SPDesktop* desktop = SP_ACTIVE_DESKTOP;
+ SPDocument* document = sp_desktop_document(desktop);
+ const GSList* filters = sp_document_get_resource_list(document, "filter");
+
+ _model->clear();
+
+ for(const GSList *l = filters; l; l = l->next) {
+ Gtk::TreeModel::Row row = *_model->append();
+ SPFilter* f = (SPFilter*)l->data;
+ row[_columns.filter] = f;
+ const gchar* id = SP_OBJECT_ID(f);
+ row[_columns.id] = id ? id : "";
+ }
+}
+
+SimpleFilterModifier::SimpleFilterModifier()
+ : _lb_blend(_("_Blend mode:")),
+ _lb_blur(_("B_lur:"), Gtk::ALIGN_LEFT),
+ _lb_filter(_("F_ilter:"), Gtk::ALIGN_LEFT),
+ _blend(BlendModeConverter),
+ _blur(0, 0, 100, 1, 0.01, 1),
+ _edit_filters(_("_Edit"))
+{
+ add(_hb_blend);
+ add(_vb_blur);
+ add(_hb_filter);
+ _hb_blend.pack_start(_lb_blend, false, false);
+ _hb_blend.pack_start(_blend);
+ _vb_blur.add(_lb_blur);
+ _vb_blur.add(_blur);
+ _hb_filter.pack_start(_lb_filter, false, false);
+ _hb_filter.pack_start(_hb_filter_sub);
+ _hb_filter_sub.add(_filter);
+ _hb_filter_sub.add(_edit_filters);
+
+ show_all_children();
+
+ signal_show().connect(sigc::mem_fun(*this, &SimpleFilterModifier::blend_mode_changed));
+ _hb_blend.set_spacing(12);
+ _hb_filter.set_spacing(12);
+ _lb_blend.set_use_underline();
+ _lb_blend.set_mnemonic_widget(_blend);
+ _lb_blur.set_use_underline();
+ _lb_blur.set_mnemonic_widget(_blur.get_scale());
+ _lb_filter.set_use_underline();
+ _lb_filter.set_mnemonic_widget(_filter);
+ _blend.add_row("Filter");
+ _blend.signal_changed().connect(sigc::mem_fun(*this, &SimpleFilterModifier::blend_mode_changed));
+ _blend.signal_changed().connect(signal_blend_blur_changed());
+ _blur.signal_value_changed().connect(signal_blend_blur_changed());
+ _filter.set_model(_model);
+ _filter.pack_start(_columns.id);
+ _edit_filters.signal_clicked().connect(sigc::mem_fun(*this, &SimpleFilterModifier::show_filter_dialog));
+ _edit_filters.set_use_underline();
+
+ update_filters();
+}
+
+Glib::SignalProxy0<void> SimpleFilterModifier::signal_selection_changed()
+{
+ return _filter.signal_changed();
+}
+
+SPFilter* SimpleFilterModifier::get_selected_filter()
+{
+ Gtk::TreeModel::iterator i = _filter.get_active();
+
+ if(i)
+ return (*i)[_columns.filter];
+
+ return 0;
+}
+
+void SimpleFilterModifier::select_filter(const SPFilter* filter)
+{
+ if(filter) {
+ for(Gtk::TreeModel::iterator i = _model->children().begin();
+ i != _model->children().end(); ++i) {
+ if((*i)[_columns.filter] == filter) {
+ _filter.set_active(i);
+ break;
+ }
+ }
+ }
+}
+
+sigc::signal<void>& SimpleFilterModifier::signal_blend_blur_changed()
+{
+ return _signal_blend_blur_changed;
+}
+
+const Glib::ustring SimpleFilterModifier::get_blend_mode()
+{
+ return _blend.get_active_row_number() == 5 ? "filter" : _blend.get_active_data()->name;
+}
+
+void SimpleFilterModifier::set_blend_mode(const int val)
+{
+ _blend.set_active(val);
+}
+
+double SimpleFilterModifier::get_blur_value() const
+{
+ return _blur.get_value();
+}
+
+void SimpleFilterModifier::set_blur_value(const double val)
+{
+ _blur.set_value(val);
+}
+
+void SimpleFilterModifier::set_blur_sensitive(const bool s)
+{
+ _blur.set_sensitive(s);
+}
+
+void SimpleFilterModifier::update_filters()
+{
+ const SPFilter* active_filter = get_selected_filter();
+
+ FilterEffectChooser::update_filters();
+
+ if(_model->children().empty()) {
+ // Set state if no filters exist
+ Gtk::TreeModel::Row row = *_model->prepend();
+ row[_columns.filter] = 0;
+ row[_columns.id] = "None";
+ _filter.set_sensitive(false);
+ _filter.set_active(0);
+ }
+ else {
+ _filter.set_sensitive(true);
+ select_filter(active_filter);
+ }
+}
+
+void SimpleFilterModifier::show_filter_dialog()
+{
+ SP_ACTIVE_DESKTOP->_dlg_mgr->showDialog("FilterEffectsDialog");
+}
+
+void SimpleFilterModifier::blend_mode_changed()
+{
+ if(_blend.get_active_row_number() == 5) {
+ _vb_blur.hide();
+ _hb_filter.show();
+ }
+ else {
+ _hb_filter.hide();
+ _vb_blur.show();
+ }
+}
+
+/*** From filter-effect-enums.h ***/
+const EnumData<NR::FilterPrimitiveType> FPData[NR::NR_FILTER_ENDPRIMITIVETYPE] = {
+ {NR::NR_FILTER_BLEND, _("Blend"), "svg:feBlend"},
+ {NR::NR_FILTER_COLORMATRIX, _("Color Matrix"), "svg:feColorMatrix"},
+ {NR::NR_FILTER_COMPONENTTRANSFER, _("Component Transfer"), "svg:feComponentTransfer"},
+ {NR::NR_FILTER_COMPOSITE, _("Composite"), "svg:feComposite"},
+ {NR::NR_FILTER_CONVOLVEMATRIX, _("Convolve Matrix"), "svg:feConvolveMatrix"},
+ {NR::NR_FILTER_DIFFUSELIGHTING, _("Diffuse Lighting"), "svg:feDiffuseLighting"},
+ {NR::NR_FILTER_DISPLACEMENTMAP, _("Displacement Map"), "svg:feDisplacementMap"},
+ {NR::NR_FILTER_FLOOD, _("Flood"), "svg:feFlood"},
+ {NR::NR_FILTER_GAUSSIANBLUR, _("Gaussian Blur"), "svg:feGaussianBlur"},
+ {NR::NR_FILTER_IMAGE, _("Image"), "svg:feImage"},
+ {NR::NR_FILTER_MERGE, _("Merge"), "svg:feMerge"},
+ {NR::NR_FILTER_MORPHOLOGY, _("Morphology"), "svg:feMorphology"},
+ {NR::NR_FILTER_OFFSET, _("Offset"), "svg:feOffset"},
+ {NR::NR_FILTER_SPECULARLIGHTING, _("Specular Lighting"), "svg:feSpecularLighting"},
+ {NR::NR_FILTER_TILE, _("Tile"), "svg:feTile"},
+ {NR::NR_FILTER_TURBULENCE, _("Turbulence"), "svg:feTurbulence"}
+};
+const Converter<NR::FilterPrimitiveType> FPConverter(FPData, NR::NR_FILTER_ENDPRIMITIVETYPE);
+const EnumData<NR::FilterBlendMode> BlendModeData[NR::BLEND_ENDMODE] = {
+ {NR::BLEND_NORMAL, _("Normal"), "normal"},
+ {NR::BLEND_MULTIPLY, _("Multiply"), "multiply"},
+ {NR::BLEND_SCREEN, _("Screen"), "screen"},
+ {NR::BLEND_DARKEN, _("Darken"), "darken"},
+ {NR::BLEND_LIGHTEN, _("Lighten"), "lighten"}
+};
+const Converter<NR::FilterBlendMode> BlendModeConverter(BlendModeData, NR::BLEND_ENDMODE);
+
+}
+}
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/filter-effect-chooser.h b/src/ui/widget/filter-effect-chooser.h
new file mode 100644
index 000000000..182ce45ef
--- /dev/null
+++ b/src/ui/widget/filter-effect-chooser.h
@@ -0,0 +1,120 @@
+#ifndef __FILTER_EFFECT_CHOOSER_H__
+#define __FILTER_EFFECT_CHOOSER_H__
+
+/*
+ * Filter effect selection selection widget
+ *
+ * Author:
+ * Nicholas Bishop <nicholasbishop@gmail.com>
+ *
+ * Copyright (C) 2007 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <gtkmm/box.h>
+#include <gtkmm/combobox.h>
+#include <gtkmm/liststore.h>
+#include <gtkmm/treeview.h>
+
+#include "filter-effect-enums.h"
+#include "labelled.h"
+#include "spin-slider.h"
+#include "sp-filter.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+class FilterEffectChooser
+{
+public:
+ virtual ~FilterEffectChooser() {}
+
+ virtual Glib::SignalProxy0<void> signal_selection_changed() = 0;
+ virtual SPFilter* get_selected_filter() = 0;
+ virtual void select_filter(const SPFilter*) = 0;
+protected:
+ FilterEffectChooser();
+
+ class Columns : public Gtk::TreeModel::ColumnRecord
+ {
+ public:
+ Columns()
+ {
+ add(filter);
+ add(id);
+ }
+
+ Gtk::TreeModelColumn<SPFilter*> filter;
+ Gtk::TreeModelColumn<Glib::ustring> id;
+ };
+
+ virtual void update_filters();
+
+ Glib::RefPtr<Gtk::ListStore> _model;
+ Columns _columns;
+private:
+ static void on_activate_desktop(Inkscape::Application*, SPDesktop*, FilterEffectChooser*);
+ void on_document_replaced(SPDesktop*, SPDocument*);
+
+ sigc::connection _doc_replaced;
+ sigc::connection _resource_changed;
+
+ Gtk::TreeView::Column _filter_column;
+};
+
+/* Allows basic control over feBlend and feGaussianBlur effects,
+ with an option to use the full filter effect controls. */
+class SimpleFilterModifier : public Gtk::VBox, public FilterEffectChooser
+{
+public:
+ SimpleFilterModifier();
+
+ virtual Glib::SignalProxy0<void> signal_selection_changed();
+ virtual SPFilter* get_selected_filter();
+ virtual void select_filter(const SPFilter*);
+
+ sigc::signal<void>& signal_blend_blur_changed();
+
+ const Glib::ustring get_blend_mode();
+ // Uses blend mode enum values, or -1 for a complex filter
+ void set_blend_mode(const int);
+
+ double get_blur_value() const;
+ void set_blur_value(const double);
+ void set_blur_sensitive(const bool);
+protected:
+ virtual void update_filters();
+private:
+ void show_filter_dialog();
+ void blend_mode_changed();
+
+ Gtk::HBox _hb_blend;
+ Gtk::VBox _vb_blur;
+ Gtk::HBox _hb_filter, _hb_filter_sub;
+ Gtk::Label _lb_blend, _lb_blur, _lb_filter;
+ ComboBoxEnum<NR::FilterBlendMode> _blend;
+ SpinSlider _blur;
+ Gtk::ComboBox _filter;
+ Gtk::Button _edit_filters;
+
+ sigc::signal<void> _signal_blend_blur_changed;
+};
+
+}
+}
+}
+
+#endif
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/filter-effect-enums.h b/src/ui/widget/filter-effect-enums.h
new file mode 100644
index 000000000..3ac68a16f
--- /dev/null
+++ b/src/ui/widget/filter-effect-enums.h
@@ -0,0 +1,156 @@
+/**
+ * \brief Simplified management of enumerations for filter effects
+ *
+ * Authors:
+ * Nicholas Bishop <nicholasbishop@gmail.com>
+ *
+ * Copyright (C) 2007 Authors
+ *
+ * Released under GNU GPL. Read the file 'COPYING' for more information.
+ */
+
+#ifndef INKSCAPE_UI_WIDGET_FILTER_EFFECT_ENUMS_H
+#define INKSCAPE_UI_WIDGET_FILTER_EFFECT_ENUMS_H
+
+#include "display/nr-filter-blend.h"
+#include "display/nr-filter-types.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+template<typename E> struct EnumData
+{
+ E id;
+ const Glib::ustring label;
+ const Glib::ustring name;
+};
+
+template<typename E> class Converter
+{
+public:
+ typedef EnumData<E> Data;
+
+ Converter(const EnumData<E>* cd, const int endval)
+ : end(endval), _data(cd)
+ {}
+
+ E get_id_from_label(const Glib::ustring& label) const
+ {
+ for(int i = 0; i < end; ++i) {
+ if(_data[i].label == label)
+ return (E)i;
+ }
+
+ return (E)0;
+ }
+
+ E get_id_from_name(const Glib::ustring& name) const
+ {
+ for(int i = 0; i < end; ++i) {
+ if(_data[i].name == name)
+ return (E)i;
+ }
+
+ return (E)0;
+ }
+
+ const Glib::ustring& get_label(const E e) const
+ {
+ return _data[e].label;
+ }
+
+ const Glib::ustring& get_name(const E e) const
+ {
+ return _data[e].name;
+ }
+
+ const EnumData<E>& data(const int i) const
+ {
+ return _data[i];
+ }
+
+ const int end;
+private:
+ const EnumData<E>* _data;
+};
+
+template<typename E> class ComboBoxEnum : public Gtk::ComboBox
+{
+public:
+ ComboBoxEnum(const Converter<E>& c)
+ : _converter(c)
+ {
+ _model = Gtk::ListStore::create(_columns);
+ set_model(_model);
+
+ pack_start(_columns.label);
+
+ // Initialize list
+ for(int i = 0; i < _converter.end; ++i) {
+ Gtk::TreeModel::Row row = *_model->append();
+ const EnumData<E>* data = &_converter.data(i);
+ row[_columns.data] = data;
+ row[_columns.label] = _converter.get_label(data->id);
+ }
+
+ set_active(0);
+ }
+
+ const EnumData<E>* get_active_data()
+ {
+ Gtk::TreeModel::iterator i = this->get_active();
+ if(i)
+ return (*i)[_columns.data];
+ return 0;
+ }
+
+ void add_row(const Glib::ustring& s)
+ {
+ Gtk::TreeModel::Row row = *_model->append();
+ row[_columns.data] = 0;
+ row[_columns.label] = s;
+ }
+private:
+ class Columns : public Gtk::TreeModel::ColumnRecord
+ {
+ public:
+ Columns()
+ {
+ add(data);
+ add(label);
+ }
+
+ Gtk::TreeModelColumn<const EnumData<E>*> data;
+ Gtk::TreeModelColumn<Glib::ustring> label;
+ };
+
+ Columns _columns;
+ Glib::RefPtr<Gtk::ListStore> _model;
+ const Converter<E>& _converter;
+};
+
+/*** Filter Primitives ***/
+extern const EnumData<NR::FilterPrimitiveType> FPData[NR::NR_FILTER_ENDPRIMITIVETYPE];
+extern const Converter<NR::FilterPrimitiveType> FPConverter;
+
+/*** feBlend Mode ***/
+extern const EnumData<NR::FilterBlendMode> BlendModeData[NR::BLEND_ENDMODE];
+extern const Converter<NR::FilterBlendMode> BlendModeConverter;
+
+}
+}
+}
+
+#endif
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/spin-slider.cpp b/src/ui/widget/spin-slider.cpp
new file mode 100644
index 000000000..678b8e372
--- /dev/null
+++ b/src/ui/widget/spin-slider.cpp
@@ -0,0 +1,87 @@
+/**
+ * \brief Groups an HScale and a SpinButton together using the same Adjustment
+ *
+ * Author:
+ * Nicholas Bishop <nicholasbishop@gmail.com>
+ *
+ * Copyright (C) 2007 Author
+ *
+ * Released under GNU GPL. Read the file 'COPYING' for more information.
+ */
+
+#include "spin-slider.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+
+SpinSlider::SpinSlider(double value, double lower, double upper, double step_inc,
+ double climb_rate, int digits)
+ : _adjustment(value, lower, upper, step_inc),
+ _scale(_adjustment), _spin(_adjustment, climb_rate, digits)
+{
+ pack_start(_scale);
+ pack_start(_spin, false, false);
+
+ _scale.set_draw_value(false);
+
+ show_all_children();
+}
+
+Glib::SignalProxy0<void> SpinSlider::signal_value_changed()
+{
+ return _adjustment.signal_value_changed();
+}
+
+double SpinSlider::get_value() const
+{
+ return _adjustment.get_value();
+}
+
+void SpinSlider::set_value(const double val)
+{
+ _adjustment.set_value(val);
+}
+
+const Gtk::Adjustment& SpinSlider::get_adjustment() const
+{
+ return _adjustment;
+}
+Gtk::Adjustment& SpinSlider::get_adjustment()
+{
+ return _adjustment;
+}
+
+const Gtk::HScale& SpinSlider::get_scale() const
+{
+ return _scale;
+}
+Gtk::HScale& SpinSlider::get_scale()
+{
+ return _scale;
+}
+
+const Gtk::SpinButton& SpinSlider::get_spin_button() const
+{
+ return _spin;
+}
+Gtk::SpinButton& SpinSlider::get_spin_button()
+{
+ return _spin;
+}
+
+} // namespace Widget
+} // namespace UI
+} // namespace Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/ui/widget/spin-slider.h b/src/ui/widget/spin-slider.h
new file mode 100644
index 000000000..50bd1dc04
--- /dev/null
+++ b/src/ui/widget/spin-slider.h
@@ -0,0 +1,64 @@
+/**
+ * \brief Groups an HScale and a SpinButton together using the same Adjustment
+ *
+ * Author:
+ * Nicholas Bishop <nicholasbishop@gmail.com>
+ *
+ * Copyright (C) 2007 Author
+ *
+ * Released under GNU GPL. Read the file 'COPYING' for more information.
+ */
+
+#ifndef INKSCAPE_UI_WIDGET_SPIN_SLIDER_H
+#define INKSCAPE_UI_WIDGET_SPIN_SLIDER_H
+
+#include <gtkmm/adjustment.h>
+#include <gtkmm/box.h>
+#include <gtkmm/scale.h>
+#include <gtkmm/spinbutton.h>
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+class SpinSlider : public Gtk::HBox
+{
+public:
+ SpinSlider(double value, double lower, double upper, double step_inc,
+ double climb_rate, int digits);
+
+ // Shortcuts to _adjustment
+ Glib::SignalProxy0<void> signal_value_changed();
+ double get_value() const;
+ void set_value(const double);
+
+ const Gtk::Adjustment& get_adjustment() const;
+ Gtk::Adjustment& get_adjustment();
+
+ const Gtk::HScale& get_scale() const;
+ Gtk::HScale& get_scale();
+
+ const Gtk::SpinButton& get_spin_button() const;
+ Gtk::SpinButton& get_spin_button();
+private:
+ Gtk::Adjustment _adjustment;
+ Gtk::HScale _scale;
+ Gtk::SpinButton _spin;
+};
+
+} // namespace Widget
+} // namespace UI
+} // namespace Inkscape
+
+#endif // INKSCAPE_UI_WIDGET_SPIN_SLIDER_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :