Code

Filter effects dialog:
[inkscape.git] / src / ui / dialog / filter-effects-dialog.cpp
index 18610f613b6dcb37962d6a6331c14ee6d826a7eb..fbab4a73b4be5869718db788d535983625dab776 100644 (file)
@@ -169,10 +169,12 @@ void FilterEffectsDialog::FilterModifier::remove_filter()
 
 void FilterEffectsDialog::FilterModifier::duplicate_filter()
 {
-    SPFilter *filter = get_selected_filter();
+    SPFilterfilter = get_selected_filter();
 
     if(filter) {
-        //SPFilter *dupfilter = filter_duplicate(sp_desktop_document(SP_ACTIVE_DESKTOP), filter);
+        Inkscape::XML::Node* repr = SP_OBJECT_REPR(filter), *parent = repr->parent();
+        repr = repr->duplicate(repr->document());
+        parent->appendChild(repr);
 
         sp_document_done(filter->document, SP_VERB_DIALOG_FILTER_EFFECTS, _("Duplicate filter"));
 
@@ -229,7 +231,7 @@ void FilterEffectsDialog::CellRendererConnection::get_size_vfunc(
         (*width) = size * primlist.primitive_count();
     if(height) {
         // Scale the height depending on the number of inputs, unless it's
-        // the first primitive, in which case their are no connections
+        // the first primitive, in which case there are no connections
         SPFilterPrimitive* prim = (SPFilterPrimitive*)_primitive.get_value();
         (*height) = primlist.is_first(prim) ? size : size * input_count(prim);
     }
@@ -243,8 +245,7 @@ FilterEffectsDialog::PrimitiveList::PrimitiveList(FilterEffectsDialog& d)
 
     _model = Gtk::ListStore::create(_columns);
 
-    // TODO: reenable this once it is possible to modify the order in the backend
-    //set_reorderable(true);
+    set_reorderable(true);
 
     set_model(_model);
     append_column(_("_Type"), _columns.type);
@@ -509,6 +510,8 @@ bool FilterEffectsDialog::PrimitiveList::on_button_press_event(GdkEventButton* e
     Gtk::TreeViewColumn* col;
     const int x = (int)e->x, y = (int)e->y;
     int cx, cy;
+
+    _drag_prim = 0;
     
     if(get_path_at_pos(x, y, path, col, cx, cy)) {
         Gtk::TreeIter iter = _model->get_iter(path);
@@ -521,9 +524,15 @@ bool FilterEffectsDialog::PrimitiveList::on_button_press_event(GdkEventButton* e
 
             queue_draw();
         }
+        _drag_prim = (*iter)[_columns.primitive];
     }
 
-    return Gtk::TreeView::on_button_press_event(e);
+    if(_in_drag) {
+        get_selection()->select(path);
+        return true;
+    }
+    else
+        return Gtk::TreeView::on_button_press_event(e);
 }
 
 bool FilterEffectsDialog::PrimitiveList::on_motion_notify_event(GdkEventMotion* e)
@@ -590,18 +599,65 @@ bool FilterEffectsDialog::PrimitiveList::on_button_release_event(GdkEventButton*
         return Gtk::TreeView::on_button_release_event(e);
 }
 
+// Checks all of prim's inputs, removes any that use result
+void check_single_connection(SPFilterPrimitive* prim, const int result)
+{
+    if(prim && result >= 0) {
+
+        if(prim->image_in == result)
+            SP_OBJECT_REPR(prim)->setAttribute("in", 0);
+
+        if(SP_IS_FEBLEND(prim)) {
+            if(SP_FEBLEND(prim)->in2 == result)
+                SP_OBJECT_REPR(prim)->setAttribute("in2", 0);
+        }
+        else if(SP_IS_FECOMPOSITE(prim)) {
+            if(SP_FECOMPOSITE(prim)->in2 == result)
+                SP_OBJECT_REPR(prim)->setAttribute("in2", 0);
+        }
+    }
+}
+
+// Remove any connections going to/from prim_iter that forward-reference other primitives
+void FilterEffectsDialog::PrimitiveList::sanitize_connections(const Gtk::TreeIter& prim_iter)
+{
+    SPFilterPrimitive *prim = (*prim_iter)[_columns.primitive];
+    bool before = true;
+
+    for(Gtk::TreeIter iter = _model->children().begin();
+        iter != _model->children().end(); ++iter) {
+        if(iter == prim_iter)
+            before = false;
+        else {
+            SPFilterPrimitive* cur_prim = (*iter)[_columns.primitive];
+            if(before)
+                check_single_connection(cur_prim, prim->image_out);
+            else
+                check_single_connection(prim, cur_prim->image_out);
+        }
+    }
+}
+
 // Reorder the filter primitives to match the list order
 void FilterEffectsDialog::PrimitiveList::on_drag_end(const Glib::RefPtr<Gdk::DragContext>&)
 {
     SPFilter* filter = _dialog._filter_modifier.get_selected_filter();
+    int ndx = 0;
 
     for(Gtk::TreeModel::iterator iter = _model->children().begin();
-        iter != _model->children().end(); ++iter) {
+        iter != _model->children().end(); ++iter, ++ndx) {
         SPFilterPrimitive* prim = (*iter)[_columns.primitive];
-        if(prim)
-            ;//reorder_primitive(filter, prim->repr->position(), ndx); /* FIXME */
+        if(prim) {
+            SP_OBJECT_REPR(prim)->setPosition(ndx);
+            if(_drag_prim == prim) {
+                sanitize_connections(iter);
+                get_selection()->select(iter);
+            }
+        }
     }
 
+    filter->requestModified(SP_OBJECT_MODIFIED_FLAG);
+
     sp_document_done(filter->document, SP_VERB_DIALOG_FILTER_EFFECTS, _("Reorder filter primitive"));
 }
 
@@ -666,6 +722,82 @@ void FilterEffectsDialog::SettingsGroup::add_setting(std::vector<Gtk::Widget*>&
     add_setting_generic(*hb, label);
 }
 
+/*** ConvolveMatrix ***/
+FilterEffectsDialog::ConvolveMatrixColumns::ConvolveMatrixColumns()
+{
+    cols.resize(5);
+    for(unsigned i = 0; i < cols.size(); ++i)
+        add(cols[i]);
+}
+
+FilterEffectsDialog::ConvolveMatrix::ConvolveMatrix()
+{
+    _model = Gtk::ListStore::create(_columns);
+    set_model(_model);
+    set_headers_visible(false);
+}
+
+sigc::signal<void>& FilterEffectsDialog::ConvolveMatrix::signal_changed()
+{
+    return _signal_changed;
+}
+
+Glib::ustring FilterEffectsDialog::ConvolveMatrix::get_value() const
+{
+    std::ostringstream os;
+
+    for(Gtk::TreeIter iter = _model->children().begin();
+        iter != _model->children().end(); ++iter) {
+        for(unsigned c = 0; c < get_columns().size(); ++c) {
+            os << (*iter)[_columns.cols[c]] << " ";
+        }
+    }
+
+    return os.str();
+}
+
+void FilterEffectsDialog::ConvolveMatrix::update(SPFeConvolveMatrix* conv)
+{
+    if(conv) {
+        int cols, rows;
+
+        cols = (int)conv->order.getNumber();
+        if(cols > 5)
+            cols = 5;
+        rows = conv->order.optNumber_set ? (int)conv->order.getOptNumber() : cols;
+
+        update(conv, cols, rows);
+    }
+}
+
+void FilterEffectsDialog::ConvolveMatrix::update(SPFeConvolveMatrix* conv, const int rows, const int cols)
+{
+    _model->clear();
+
+    remove_all_columns();
+
+    if(conv) {
+        int ndx = 0;
+
+        for(int i = 0; i < cols; ++i) {
+            append_column_numeric_editable("", _columns.cols[i], "%.2f");
+            dynamic_cast<Gtk::CellRendererText*>(get_column(i)->get_first_cell_renderer())->signal_edited().connect(
+                sigc::mem_fun(*this, &ConvolveMatrix::rebind));
+        }
+
+        for(int r = 0; r < rows; ++r) {
+            Gtk::TreeRow row = *(_model->append());
+            for(int c = 0; c < cols; ++c, ++ndx)
+                row[_columns.cols[c]] = ndx < (int)conv->kernelMatrix.size() ? conv->kernelMatrix[ndx] : 0;
+        }
+    }
+}
+
+void FilterEffectsDialog::ConvolveMatrix::rebind(const Glib::ustring&, const Glib::ustring&)
+{
+    _signal_changed();
+}
+
 /*** FilterEffectsDialog ***/
 
 FilterEffectsDialog::FilterEffectsDialog() 
@@ -685,6 +817,10 @@ FilterEffectsDialog::FilterEffectsDialog()
       _composite_k2(0, -10, 10, 1, 0.01, 1),
       _composite_k3(0, -10, 10, 1, 0.01, 1),
       _composite_k4(0, -10, 10, 1, 0.01, 1),
+      _convolve_orderx(1, 0),
+      _convolve_ordery(1, 0),
+      _convolve_divisor(1, 0.01, 10, 1, 0.01, 1),
+      _convolve_bias(0, -10, 10, 1, 0.01, 1),
       _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),
@@ -768,6 +904,25 @@ void FilterEffectsDialog::init_settings_widgets()
     _composite.add_setting(_composite_k4, SP_ATTR_K4, _("K4"));
 
     _convolvematrix.init(this, _settings_labels);
+    _convolvematrix.add_setting_generic(_convolve_orderx, _("Rows"));
+    _convolve_orderx.set_range(1, 5);
+    _convolve_orderx.get_adjustment()->set_step_increment(1);
+    _convolve_orderx.signal_value_changed().connect(
+        sigc::bind(sigc::mem_fun(*this, &FilterEffectsDialog::set_attr_special), SP_ATTR_ORDER));
+    _convolvematrix.add_setting_generic(_convolve_ordery, _("Columns"));
+    _convolve_ordery.set_range(1, 5);
+    _convolve_ordery.get_adjustment()->set_step_increment(1);
+    _convolve_ordery.signal_value_changed().connect(
+        sigc::bind(sigc::mem_fun(*this, &FilterEffectsDialog::set_attr_special), SP_ATTR_ORDER));
+    Gtk::ScrolledWindow* sw = Gtk::manage(new Gtk::ScrolledWindow);
+    sw->add(_convolve_kernelmatrix);
+    sw->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
+    sw->set_shadow_type(Gtk::SHADOW_IN);
+    _convolvematrix.add_setting_generic(*sw, _("Kernel"));
+    _convolve_kernelmatrix.signal_changed().connect(
+        sigc::bind(sigc::mem_fun(*this, &FilterEffectsDialog::set_attr_special), SP_ATTR_KERNELMATRIX));
+    //_convolvematrix.add_setting(_convolve_divisor, SP_ATTR_DIVISOR, _("Divisor"));
+    //_convolvematrix.add_setting(_convolve_bias, SP_ATTR_BIAS, _("Bias"));
     
     _diffuselighting.init(this, _settings_labels);
 
@@ -862,6 +1017,7 @@ void FilterEffectsDialog::set_attr_special(const SPAttributeEnum attr)
 {
     Glib::ustring val;
     FilterPrimitiveInput input_id;
+    std::ostringstream os;
 
     switch(attr) {
         case SP_ATTR_IN:
@@ -881,6 +1037,18 @@ void FilterEffectsDialog::set_attr_special(const SPAttributeEnum attr)
                 val = FPInputConverter.get_key(input_id);
             }
             break;
+        case SP_ATTR_ORDER:
+        {
+            int x = (int)(_convolve_orderx.get_value() + 0.5f);
+            int y = (int)(_convolve_ordery.get_value() + 0.5f);
+            os << x << " " << y;
+            val = os.str();
+            _convolve_kernelmatrix.update(SP_FECONVOLVEMATRIX(_primitive_list.get_selected()), x, y);
+            break;
+        }
+        case SP_ATTR_KERNELMATRIX:
+            val = _convolve_kernelmatrix.get_value();
+            break;
         default:
             return;
     }
@@ -953,8 +1121,13 @@ void FilterEffectsDialog::update_settings_view()
             _composite_k3.set_value(comp->k3);
             _composite_k4.set_value(comp->k4);
         }
-        else if(tid == NR::NR_FILTER_CONVOLVEMATRIX)
+        else if(tid == NR::NR_FILTER_CONVOLVEMATRIX) {
             _convolvematrix.show_all();
+            SPFeConvolveMatrix* conv = SP_FECONVOLVEMATRIX(prim);
+            _convolve_orderx.set_value(conv->order.getNumber());
+            _convolve_ordery.set_value(conv->order.optNumber_set ? conv->order.getOptNumber() : conv->order.getNumber());
+            _convolve_kernelmatrix.update(conv);
+        }
         else if(tid == NR::NR_FILTER_DIFFUSELIGHTING)
             _diffuselighting.show_all();
         else if(tid == NR::NR_FILTER_DISPLACEMENTMAP) {