From: mental Date: Sun, 24 Jun 2007 18:42:18 +0000 (+0000) Subject: initial filter UI code drop from Nick X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=6e369d7e74c36e07f5fb1e27d37923fbed7dd89c;p=inkscape.git initial filter UI code drop from Nick --- diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index 95abdfa5b..5685dc4d6 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -24,6 +24,7 @@ #include "style.h" #include "prefs-utils.h" #include "sp-use.h" +#include "sp-feblend.h" #include "sp-filter.h" #include "sp-gaussian-blur.h" #include "sp-flowtext.h" @@ -1010,6 +1011,84 @@ objects_query_fontfamily (GSList *objects, SPStyle *style_res) } } +int +objects_query_blend (GSList *objects, SPStyle *style_res) +{ + const int empty_prev = -2; + const int complex_filter = 5; + int blend = 0; + float blend_prev = empty_prev; + bool same_blend = true; + guint items = 0; + + for (GSList const *i = objects; i != NULL; i = i->next) { + SPObject *obj = SP_OBJECT (i->data); + SPStyle *style = SP_OBJECT_STYLE (obj); + if(!style || !SP_IS_ITEM(obj)) continue; + + items++; + + //if object has a filter + if (style->filter.set && style->filter.filter) { + int blurcount = 0; + int blendcount = 0; + + // determine whether filter is simple (blend and/or blur) or complex + for(SPObject *primitive_obj = style->filter.filter->children; + primitive_obj && SP_IS_FILTER_PRIMITIVE(primitive_obj); + primitive_obj = primitive_obj->next) { + SPFilterPrimitive *primitive = SP_FILTER_PRIMITIVE(primitive_obj); + if(SP_IS_FEBLEND(primitive)) + ++blendcount; + else if(SP_IS_GAUSSIANBLUR(primitive)) + ++blurcount; + else { + blurcount = complex_filter; + break; + } + } + + // simple filter + if(blurcount == 1 || blendcount == 1) { + for(SPObject *primitive_obj = style->filter.filter->children; + primitive_obj && SP_IS_FILTER_PRIMITIVE(primitive_obj); + primitive_obj = primitive_obj->next) { + if(SP_IS_FEBLEND(primitive_obj)) { + SPFeBlend *spblend = SP_FEBLEND(primitive_obj); + blend = spblend->blend_mode; + } + } + } + else { + blend = complex_filter; + } + } + // defaults to blend mode = "normal" + else { + blend = 0; + } + + if(blend_prev != empty_prev && blend_prev != blend) + same_blend = false; + blend_prev = blend; + } + + if (items > 0) { + style_res->filter_blend_mode.value = blend; + } + + if (items == 0) { + return QUERY_STYLE_NOTHING; + } else if (items == 1) { + return QUERY_STYLE_SINGLE; + } else { + if(same_blend) + return QUERY_STYLE_MULTIPLE_SAME; + else + return QUERY_STYLE_MULTIPLE_DIFFERENT; + } +} + /** * Write to style_res the average blurring of a list of objects. */ @@ -1111,6 +1190,8 @@ sp_desktop_query_style_from_list (GSList *list, SPStyle *style, int property) } else if (property == QUERY_STYLE_PROPERTY_FONTNUMBERS) { return objects_query_fontnumbers (list, style); + } else if (property == QUERY_STYLE_PROPERTY_BLEND) { + return objects_query_blend (list, style); } else if (property == QUERY_STYLE_PROPERTY_BLUR) { return objects_query_blur (list, style); } diff --git a/src/desktop-style.h b/src/desktop-style.h index 112fe1372..3f201aa28 100644 --- a/src/desktop-style.h +++ b/src/desktop-style.h @@ -47,7 +47,8 @@ enum { // which property was queried (add when you need more) QUERY_STYLE_PROPERTY_FONTSTYLE, // font style QUERY_STYLE_PROPERTY_FONTNUMBERS, // size, spacings QUERY_STYLE_PROPERTY_MASTEROPACITY, // opacity - QUERY_STYLE_PROPERTY_BLUR // blur + QUERY_STYLE_PROPERTY_BLEND, // blend + QUERY_STYLE_PROPERTY_BLUR // blur }; void sp_desktop_apply_css_recursive(SPObject *o, SPCSSAttr *css, bool skip_lines); diff --git a/src/dialogs/object-properties.cpp b/src/dialogs/object-properties.cpp index fbc9ab83f..b4358e5e5 100644 --- a/src/dialogs/object-properties.cpp +++ b/src/dialogs/object-properties.cpp @@ -25,6 +25,7 @@ #include "helper/window.h" #include "widgets/sp-widget.h" #include "widgets/icon.h" +#include "desktop.h" #include "macros.h" #include "inkscape.h" #include "fill-style.h" @@ -44,6 +45,8 @@ #include "document.h" #include "document-private.h" #include +#include +#include "ui/widget/filter-effect-chooser.h" #include "xml/repr.h" #include "display/sp-canvas.h" @@ -59,7 +62,9 @@ static gchar *prefs_path = "dialogs.fillstroke"; static void sp_fillstroke_selection_modified ( Inkscape::Application *inkscape, Inkscape::Selection *selection, guint flags, GtkObject *base ); static void sp_fillstroke_selection_changed ( Inkscape::Application *inkscape, Inkscape::Selection *selection, GtkObject *base ); static void sp_fillstroke_opacity_changed (GtkAdjustment *a, SPWidget *dlg); -static void sp_fillstroke_blur_changed (GtkAdjustment *a, SPWidget *dlg); + +using Inkscape::UI::Widget::SimpleFilterModifier; +static void sp_fillstroke_blend_blur_changed (SimpleFilterModifier *); static void sp_object_properties_dialog_destroy (GtkObject *object, gpointer data) @@ -187,35 +192,21 @@ sp_object_properties_dialog (void) } - /* Blur */ + /* Filter Effects (gtkmm) */ + GtkWidget *al_fe = gtk_alignment_new(1, 1, 1, 1); + gtk_alignment_set_padding(GTK_ALIGNMENT(al_fe), 0, 0, 4, 0); + SimpleFilterModifier *cb_fe = Gtk::manage(new SimpleFilterModifier); + g_object_set_data(G_OBJECT(dlg), "filter_modifier", cb_fe); + cb_fe->signal_selection_changed().connect( + sigc::bind(sigc::ptr_fun(sp_fillstroke_blend_blur_changed), cb_fe)); + cb_fe->signal_blend_blur_changed().connect( + sigc::bind(sigc::ptr_fun(sp_fillstroke_blend_blur_changed), cb_fe)); + gtk_container_add(GTK_CONTAINER(al_fe), GTK_WIDGET(cb_fe->gobj())); + GtkWidget *b_vb = gtk_vbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (vb), b_vb, FALSE, FALSE, 2); gtk_object_set_data (GTK_OBJECT (dlg), "blur", b_vb); - - GtkWidget *blur_l_hb = gtk_hbox_new (FALSE, 4); - GtkWidget *blur_l = gtk_label_new_with_mnemonic (_("_Blur, %")); - gtk_misc_set_alignment (GTK_MISC (blur_l), 0.0, 1.0); - gtk_box_pack_start (GTK_BOX (blur_l_hb), blur_l, FALSE, FALSE, 4); - gtk_box_pack_start (GTK_BOX (b_vb), blur_l_hb, FALSE, FALSE, 0); - - GtkWidget *blur_hb = gtk_hbox_new (FALSE, 4); - gtk_box_pack_start (GTK_BOX (b_vb), blur_hb, FALSE, FALSE, 0); - - GtkObject *blur_a = gtk_adjustment_new (0.0, 0.0, 100.0, 1.0, 1.0, 0.0); - gtk_object_set_data(GTK_OBJECT(dlg), "blur_adjustment", blur_a); - - GtkWidget *blur_s = gtk_hscale_new (GTK_ADJUSTMENT (blur_a)); - gtk_scale_set_draw_value (GTK_SCALE (blur_s), FALSE); - gtk_box_pack_start (GTK_BOX (blur_hb), blur_s, TRUE, TRUE, 4); - gtk_label_set_mnemonic_widget (GTK_LABEL(blur_l), blur_s); - - GtkWidget *blur_sb = gtk_spin_button_new (GTK_ADJUSTMENT (blur_a), 0.01, 1); - gtk_box_pack_start (GTK_BOX (blur_hb), blur_sb, FALSE, FALSE, 0); - - gtk_signal_connect ( blur_a, "value_changed", - GTK_SIGNAL_FUNC (sp_fillstroke_blur_changed), - dlg ); - + gtk_box_pack_start (GTK_BOX (b_vb), al_fe, FALSE, FALSE, 0); gtk_widget_show_all (b_vb); @@ -329,31 +320,46 @@ sp_fillstroke_selection_changed ( Inkscape::Application *inkscape, break; } + SimpleFilterModifier *mod = (SimpleFilterModifier*)g_object_get_data(G_OBJECT(dlg), "filter_modifier"); - GtkWidget *b = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (dlg), "blur")); - GtkAdjustment *bluradjustment = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(dlg), "blur_adjustment")); - - //query now for current average blurring of selection - int blur_result = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_BLUR); - switch (blur_result) { - case QUERY_STYLE_NOTHING: //no blurring - gtk_widget_set_sensitive (b, FALSE); + //query now for current filter mode and average blurring of selection + const int blend_result = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_BLEND); + switch(blend_result) { + case QUERY_STYLE_NOTHING: + mod->set_sensitive(false); break; case QUERY_STYLE_SINGLE: - case QUERY_STYLE_MULTIPLE_AVERAGED: - case QUERY_STYLE_MULTIPLE_SAME: - NR::Maybe bbox = sp_desktop_selection(SP_ACTIVE_DESKTOP)->bounds(); - if (bbox) { - double perimeter = bbox->extent(NR::X) + bbox->extent(NR::Y); - gtk_widget_set_sensitive (b, TRUE); - //update blur widget value - float radius = query->filter_gaussianBlur_deviation.value; - float percent = radius * 400 / perimeter; // so that for a square, 100% == half side - gtk_adjustment_set_value(bluradjustment, percent); - } + case QUERY_STYLE_MULTIPLE_SAME: + mod->set_blend_mode(query->filter_blend_mode.value); + mod->set_sensitive(true); + break; + case QUERY_STYLE_MULTIPLE_DIFFERENT: + // TODO: set text + mod->set_sensitive(false); break; } - + + if(blend_result == QUERY_STYLE_SINGLE || blend_result == QUERY_STYLE_MULTIPLE_SAME) { + int blur_result = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_BLUR); + switch (blur_result) { + case QUERY_STYLE_NOTHING: //no blurring + mod->set_blur_sensitive(false); + break; + case QUERY_STYLE_SINGLE: + case QUERY_STYLE_MULTIPLE_AVERAGED: + case QUERY_STYLE_MULTIPLE_SAME: + NR::Maybe bbox = sp_desktop_selection(SP_ACTIVE_DESKTOP)->bounds(); + if (bbox) { + double perimeter = bbox->extent(NR::X) + bbox->extent(NR::Y); + mod->set_blur_sensitive(true); + //update blur widget value + float radius = query->filter_gaussianBlur_deviation.value; + float percent = radius * 400 / perimeter; // so that for a square, 100% == half side + mod->set_blur_value(percent); + } + break; + } + } g_free (query); gtk_object_set_data (GTK_OBJECT (dlg), "blocked", GUINT_TO_POINTER (FALSE)); @@ -391,9 +397,8 @@ sp_fillstroke_opacity_changed (GtkAdjustment *a, SPWidget *base) gtk_object_set_data (GTK_OBJECT (dlg), "blocked", GUINT_TO_POINTER (FALSE)); } - static void -sp_fillstroke_blur_changed (GtkAdjustment *a, SPWidget *base) +sp_fillstroke_blend_blur_changed (SimpleFilterModifier *m) { //if dialog is locked, return if (gtk_object_get_data (GTK_OBJECT (dlg), "blocked")) @@ -424,24 +429,32 @@ sp_fillstroke_blur_changed (GtkAdjustment *a, SPWidget *base) SPDocument *document = sp_desktop_document (desktop); double perimeter = bbox->extent(NR::X) + bbox->extent(NR::Y); - double radius = a->value * perimeter / 400; + const Glib::ustring blendmode = m->get_blend_mode(); + double radius = m->get_blur_value() * perimeter / 400; + + SPFilter *filter = m->get_selected_filter(); + const bool remfilter = (blendmode == "normal" && radius == 0) || (blendmode == "filter" && !filter); - //apply created filter to every selected item - for (GSList const *i = items; i != NULL; i = i->next) { - - SPItem * item = SP_ITEM(i->data); - SPStyle *style = SP_OBJECT_STYLE(item); - g_assert(style != NULL); - - if (radius == 0.0) { - remove_filter_gaussian_blur(item); - } else { - SPFilter *constructed = modify_filter_gaussian_blur_from_item(document, item, radius); - sp_style_set_property_url (SP_OBJECT(item), "filter", SP_OBJECT(constructed), false); + if(blendmode != "filter" || filter) { + //apply created filter to every selected item + for (GSList const *i = items; i != NULL; i = i->next) { + SPItem * item = SP_ITEM(i->data); + SPStyle *style = SP_OBJECT_STYLE(item); + g_assert(style != NULL); + + if(remfilter) { + remove_filter (item, false); + } + else { + if(blendmode != "filter") + filter = new_filter_simple_from_item(document, item, blendmode.c_str(), radius); + sp_style_set_property_url (SP_OBJECT(item), "filter", SP_OBJECT(filter), false); + } + + //request update + SP_OBJECT(item)->requestDisplayUpdate(( SP_OBJECT_MODIFIED_FLAG | + SP_OBJECT_STYLE_MODIFIED_FLAG )); } - //request update - SP_OBJECT(item)->requestDisplayUpdate(( SP_OBJECT_MODIFIED_FLAG | - SP_OBJECT_STYLE_MODIFIED_FLAG )); } sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "fillstroke:blur", SP_VERB_DIALOG_FILL_STROKE, _("Change blur")); diff --git a/src/display/nr-filter-blend.h b/src/display/nr-filter-blend.h index 4787e336e..ffed2cd03 100644 --- a/src/display/nr-filter-blend.h +++ b/src/display/nr-filter-blend.h @@ -28,7 +28,8 @@ enum FilterBlendMode { BLEND_MULTIPLY, BLEND_SCREEN, BLEND_DARKEN, - BLEND_LIGHTEN + BLEND_LIGHTEN, + BLEND_ENDMODE }; class FilterBlend : public FilterPrimitive { diff --git a/src/filter-chemistry.cpp b/src/filter-chemistry.cpp index fb4064a7e..336ac3576 100644 --- a/src/filter-chemistry.cpp +++ b/src/filter-chemistry.cpp @@ -18,6 +18,7 @@ #include "document-private.h" #include "desktop-style.h" +#include "sp-feblend.h" #include "sp-filter.h" #include "sp-gaussian-blur.h" #include "svg/css-ostringstream.h" @@ -82,6 +83,55 @@ static void set_filter_area(Inkscape::XML::Node *repr, gdouble radius, } } +SPFilter *new_filter(SPDocument *document) +{ + g_return_val_if_fail(document != NULL, NULL); + + SPDefs *defs = (SPDefs *) SP_DOCUMENT_DEFS(document); + + Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document); + + // create a new filter + Inkscape::XML::Node *repr; + repr = xml_doc->createElement("svg:filter"); + + // Append the new filter node to defs + SP_OBJECT_REPR(defs)->appendChild(repr); + Inkscape::GC::release(repr); + + // get corresponding object + SPFilter *f = SP_FILTER( document->getObjectByRepr(repr) ); + + + g_assert(f != NULL); + g_assert(SP_IS_FILTER(f)); + + return f; +} + +SPFilterPrimitive * +filter_add_primitive(SPFilter *filter, const gchar *type) +{ + Inkscape::XML::Document *xml_doc = sp_document_repr_doc(filter->document); + + //create filter primitive node + Inkscape::XML::Node *repr; + repr = xml_doc->createElement(type); + repr->setAttribute("inkscape:collect", "always"); + + //set primitive as child of filter node + filter->repr->appendChild(repr); + Inkscape::GC::release(repr); + + // get corresponding object + SPFilterPrimitive *prim = SP_FILTER_PRIMITIVE( filter->document->getObjectByRepr(repr) ); + + g_assert(prim != NULL); + g_assert(SP_IS_FILTER_PRIMITIVE(prim)); + + return prim; +} + /** * Creates a filter with blur primitive of specified radius for an item with the given matrix expansion, width and height */ @@ -134,11 +184,85 @@ new_filter_gaussian_blur (SPDocument *document, gdouble radius, double expansion return f; } + +/** + * Creates a simple filter with a blend primitive and a blur primitive of specified radius for + * an item with the given matrix expansion, width and height + */ +SPFilter * +new_filter_blend_gaussian_blur (SPDocument *document, const char *blendmode, gdouble radius, double expansion, + double expansionX, double expansionY, double width, double height) +{ + g_return_val_if_fail(document != NULL, NULL); + + SPDefs *defs = (SPDefs *) SP_DOCUMENT_DEFS(document); + + Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document); + + // create a new filter + Inkscape::XML::Node *repr; + repr = xml_doc->createElement("svg:filter"); + repr->setAttribute("inkscape:collect", "always"); + + // Append the new filter node to defs + SP_OBJECT_REPR(defs)->appendChild(repr); + Inkscape::GC::release(repr); + + // get corresponding object + SPFilter *f = SP_FILTER( document->getObjectByRepr(repr) ); + + // Blend primitive + if(strcmp(blendmode, "normal")) { + Inkscape::XML::Node *b_repr; + b_repr = xml_doc->createElement("svg:feBlend"); + b_repr->setAttribute("inkscape::collect", "always"); + b_repr->setAttribute("mode", blendmode); + + // set feBlend as child of filter node + repr->appendChild(b_repr); + Inkscape::GC::release(b_repr); + + SPFeBlend *b = SP_FEBLEND(document->getObjectByRepr(b_repr)); + g_assert(b != NULL); + g_assert(SP_IS_FEBLEND(b)); + } + // Gaussian blur primitive + if(radius != 0) { + set_filter_area(repr, radius, expansion, expansionX, expansionY, width, height); + + //create feGaussianBlur node + Inkscape::XML::Node *b_repr; + b_repr = xml_doc->createElement("svg:feGaussianBlur"); + b_repr->setAttribute("inkscape:collect", "always"); + + double stdDeviation = radius; + if (expansion != 0) + stdDeviation /= expansion; + + //set stdDeviation attribute + sp_repr_set_svg_double(b_repr, "stdDeviation", stdDeviation); + + //set feGaussianBlur as child of filter node + repr->appendChild(b_repr); + Inkscape::GC::release(b_repr); + + SPGaussianBlur *b = SP_GAUSSIANBLUR( document->getObjectByRepr(b_repr) ); + g_assert(b != NULL); + g_assert(SP_IS_GAUSSIANBLUR(b)); + } + + g_assert(f != NULL); + g_assert(SP_IS_FILTER(f)); + + return f; +} + /** - * Creates a filter with blur primitive of specified radius for the given item + * Creates a simple filter for the given item with blend and blur primitives, using the + * specified mode and radius, respectively */ SPFilter * -new_filter_gaussian_blur_from_item (SPDocument *document, SPItem *item, gdouble radius) +new_filter_simple_from_item (SPDocument *document, SPItem *item, const char *mode, gdouble radius) { NR::Maybe const r = sp_item_bbox_desktop(item); @@ -153,7 +277,7 @@ new_filter_gaussian_blur_from_item (SPDocument *document, SPItem *item, gdouble NR::Matrix i2d = sp_item_i2d_affine (item); - return (new_filter_gaussian_blur (document, radius, i2d.expansion(), i2d.expansionX(), i2d.expansionY(), width, height)); + return (new_filter_blend_gaussian_blur (document, mode, radius, i2d.expansion(), i2d.expansionX(), i2d.expansionY(), width, height)); } /** @@ -170,7 +294,7 @@ modify_filter_gaussian_blur_from_item(SPDocument *document, SPItem *item, gdouble radius) { if (!item->style || !item->style->filter.set) { - return new_filter_gaussian_blur_from_item(document, item, radius); + //return new_filter_gaussian_blur_from_item(document, item, radius); } SPFilter *filter = SP_FILTER(item->style->filter.filter); diff --git a/src/filter-chemistry.h b/src/filter-chemistry.h index b727536ad..125c527b2 100644 --- a/src/filter-chemistry.h +++ b/src/filter-chemistry.h @@ -17,8 +17,10 @@ #include "forward.h" #include "sp-filter.h" +SPFilterPrimitive *filter_add_primitive(SPFilter *filter, const gchar *type); +SPFilter *new_filter (SPDocument *document); SPFilter *new_filter_gaussian_blur (SPDocument *document, gdouble stdDeviation, double expansion, double expansionX, double expansionY, double width, double height); -SPFilter *new_filter_gaussian_blur_from_item (SPDocument *document, SPItem *item, gdouble stdDeviation); +SPFilter *new_filter_simple_from_item (SPDocument *document, SPItem *item, const char *mode, gdouble stdDeviation); SPFilter *modify_filter_gaussian_blur_from_item (SPDocument *document, SPItem *item, gdouble stdDeviation); void remove_filter (SPObject *item, bool recursive); void remove_filter_gaussian_blur (SPObject *item); diff --git a/src/menus-skeleton.h b/src/menus-skeleton.h index 722d8a11e..f560deeb0 100644 --- a/src/menus-skeleton.h +++ b/src/menus-skeleton.h @@ -229,6 +229,7 @@ static char const menus_skeleton[] = " \n" " \n" " \n" +" \n" " \n" " \n" #ifdef WITH_INKBOARD diff --git a/src/style.h b/src/style.h index 4538626be..544bde557 100644 --- a/src/style.h +++ b/src/style.h @@ -336,6 +336,8 @@ struct SPStyle { /** Filter effect */ SPIFilter filter; + SPIEnum filter_blend_mode; + /** normally not used, but duplicates the Gaussian blur deviation (if any) from the attached filter when the style is used for querying */ SPILength filter_gaussianBlur_deviation; 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); registerFactory("ExtensionEditor", &create); registerFactory("FillAndStroke", &create); + registerFactory("FilterEffectsDialog", &create); registerFactory("Find", &create); registerFactory("InkscapePreferences", &create); registerFactory("LayerEditor", &create); 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 + * + * Copyright (C) 2007 Authors + * + * Released under GNU GPL. Read the file 'COPYING' for more information. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + +#include + +namespace Inkscape { +namespace UI { +namespace Dialog { + +Glib::RefPtr create_popup_menu(Gtk::Widget& parent, sigc::slot dup, + sigc::slot rem) +{ + Glib::RefPtr 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 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("Settings")); + 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&) +{ + 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* 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 c = _settings.get_children(); + for(Glib::ListHandle::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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 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 _menu; + }; + + class PrimitiveColumns : public Gtk::TreeModel::ColumnRecord + { + public: + PrimitiveColumns() + { + add(primitive); + add(type_id); + add(type); + add(id); + } + + Gtk::TreeModelColumn primitive; + Gtk::TreeModelColumn type_id; + Gtk::TreeModelColumn type; + Gtk::TreeModelColumn 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&); + + 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 _primitive_model; + PrimitiveColumns _primitive_columns; + Glib::RefPtr _primitive_menu; + UI::Widget::ComboBoxEnum _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 _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 + * + * Copyright (C) 2007 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include + +#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 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& 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 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 FPConverter(FPData, NR::NR_FILTER_ENDPRIMITIVETYPE); +const EnumData 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 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 + * + * Copyright (C) 2007 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include +#include +#include +#include + +#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 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 filter; + Gtk::TreeModelColumn id; + }; + + virtual void update_filters(); + + Glib::RefPtr _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 signal_selection_changed(); + virtual SPFilter* get_selected_filter(); + virtual void select_filter(const SPFilter*); + + sigc::signal& 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 _blend; + SpinSlider _blur; + Gtk::ComboBox _filter; + Gtk::Button _edit_filters; + + sigc::signal _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 + * + * 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 struct EnumData +{ + E id; + const Glib::ustring label; + const Glib::ustring name; +}; + +template class Converter +{ +public: + typedef EnumData Data; + + Converter(const EnumData* 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& data(const int i) const + { + return _data[i]; + } + + const int end; +private: + const EnumData* _data; +}; + +template class ComboBoxEnum : public Gtk::ComboBox +{ +public: + ComboBoxEnum(const Converter& 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* data = &_converter.data(i); + row[_columns.data] = data; + row[_columns.label] = _converter.get_label(data->id); + } + + set_active(0); + } + + const EnumData* 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*> data; + Gtk::TreeModelColumn label; + }; + + Columns _columns; + Glib::RefPtr _model; + const Converter& _converter; +}; + +/*** Filter Primitives ***/ +extern const EnumData FPData[NR::NR_FILTER_ENDPRIMITIVETYPE]; +extern const Converter FPConverter; + +/*** feBlend Mode ***/ +extern const EnumData BlendModeData[NR::BLEND_ENDMODE]; +extern const Converter 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 + * + * 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 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 + * + * 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 +#include +#include +#include + +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 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 : diff --git a/src/verbs.cpp b/src/verbs.cpp index 04a49f37c..5a0540776 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -1725,6 +1725,9 @@ DialogVerb::perform(SPAction *action, void *data, void *pdata) case SP_VERB_DIALOG_LAYERS: show_panel( Inkscape::UI::Dialogs::LayersPanel::getInstance(), "dialogs.layers", SP_VERB_DIALOG_LAYERS ); break; + case SP_VERB_DIALOG_FILTER_EFFECTS: + dt->_dlg_mgr->showDialog("FilterEffectsDialog"); + break; default: break; } @@ -2500,6 +2503,8 @@ Verb *Verb::_base_verbs[] = { N_("Query information about extensions"), NULL), new DialogVerb(SP_VERB_DIALOG_LAYERS, "DialogLayers", N_("Layer_s..."), N_("View Layers"), "layers"), + new DialogVerb(SP_VERB_DIALOG_FILTER_EFFECTS, "DialogFilterEffects", N_("Filter Effects..."), + N_("Manage SVG filter effects"), NULL), /* Help */ new HelpVerb(SP_VERB_HELP_KEYS, "HelpKeys", N_("_Keys and Mouse"), diff --git a/src/verbs.h b/src/verbs.h index f8e25f94d..aa589e36d 100644 --- a/src/verbs.h +++ b/src/verbs.h @@ -214,6 +214,7 @@ enum { SP_VERB_DIALOG_INPUT, SP_VERB_DIALOG_EXTENSIONEDITOR, SP_VERB_DIALOG_LAYERS, + SP_VERB_DIALOG_FILTER_EFFECTS, /* Help */ SP_VERB_HELP_KEYS, SP_VERB_HELP_ABOUT_EXTENSIONS,