Code

Color Matrix Filter:
[inkscape.git] / src / sp-path.cpp
index ee98cc15095c146dbe6a11026ce3c18b3694312e..8aed675900901ec04325d3d708a2e81b6a40058b 100644 (file)
@@ -18,9 +18,7 @@
 # include <config.h>
 #endif
 
-#if defined(WIN32) || defined(__APPLE__)
-# include <glibmm/i18n.h>
-#endif
+#include <glibmm/i18n.h>
 
 #include <display/curve.h>
 #include <libnr/n-art-bpath.h>
@@ -33,6 +31,8 @@
 
 #include "sp-path.h"
 
+#include "document.h"
+
 #define noPATH_VERBOSE
 
 static void sp_path_class_init(SPPathClass *klass);
@@ -48,6 +48,7 @@ static NR::Matrix sp_path_set_transform(SPItem *item, NR::Matrix const &xform);
 static gchar * sp_path_description(SPItem *item);
 
 static void sp_path_update(SPObject *object, SPCtx *ctx, guint flags);
+static void sp_path_update_patheffect(SPShape *shape, bool write);
 
 static SPShapeClass *parent_class;
 
@@ -86,6 +87,7 @@ sp_path_class_init(SPPathClass * klass)
     GObjectClass *gobject_class = (GObjectClass *) klass;
     SPObjectClass *sp_object_class = (SPObjectClass *) klass;
     SPItemClass *item_class = (SPItemClass *) klass;
+    SPShapeClass *shape_class = (SPShapeClass *) klass;
 
     parent_class = (SPShapeClass *)g_type_class_peek_parent(klass);
 
@@ -99,6 +101,8 @@ sp_path_class_init(SPPathClass * klass)
 
     item_class->description = sp_path_description;
     item_class->set_transform = sp_path_set_transform;
+
+    shape_class->update_patheffect = sp_path_update_patheffect;
 }
 
 
@@ -120,17 +124,24 @@ static gchar *
 sp_path_description(SPItem * item)
 {
     int count = sp_nodes_in_path(SP_PATH(item));
-    return g_strdup_printf(ngettext("<b>Path</b> (%i node)",
-                                    "<b>Path</b> (%i nodes)",count), count);
+    if (SP_SHAPE(item)->path_effect_href) {
+        return g_strdup_printf(ngettext("<b>Path</b> (%i node, path effect)",
+                                        "<b>Path</b> (%i nodes, path effect)",count), count);
+    } else {
+        return g_strdup_printf(ngettext("<b>Path</b> (%i node)",
+                                        "<b>Path</b> (%i nodes)",count), count);
+    }
 }
 
 /**
- * Initializes an SPPath.  Currently does nothing.
+ * Initializes an SPPath.
  */
 static void
 sp_path_init(SPPath *path)
 {
     new (&path->connEndPair) SPConnEndPair(path);
+
+    path->original_curve = NULL;
 }
 
 static void
@@ -148,14 +159,6 @@ sp_path_finalize(GObject *obj)
 static void
 sp_path_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
 {
-    sp_object_read_attr(object, "d");
-
-    /* d is a required attribute */
-    gchar const *d = sp_object_getAttribute(object, "d", NULL);
-    if (d == NULL) {
-        sp_object_set(object, sp_attribute_lookup("d"), "");
-    }
-
     /* Are these calls actually necessary? */
     sp_object_read_attr(object, "marker");
     sp_object_read_attr(object, "marker-start");
@@ -167,6 +170,15 @@ sp_path_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
     if (((SPObjectClass *) parent_class)->build) {
         ((SPObjectClass *) parent_class)->build(object, document, repr);
     }
+
+    sp_object_read_attr(object, "inkscape:original-d");
+    sp_object_read_attr(object, "d");
+
+    /* d is a required attribute */
+    gchar const *d = sp_object_getAttribute(object, "d", NULL);
+    if (d == NULL) {
+        sp_object_set(object, sp_attribute_lookup("d"), "");
+    }
 }
 
 static void
@@ -176,6 +188,10 @@ sp_path_release(SPObject *object)
 
     path->connEndPair.release();
 
+    if (path->original_curve) {
+        path->original_curve = sp_curve_unref (path->original_curve);
+    }
+
     if (((SPObjectClass *) parent_class)->release) {
         ((SPObjectClass *) parent_class)->release(object);
     }
@@ -191,18 +207,33 @@ sp_path_set(SPObject *object, unsigned int key, gchar const *value)
     SPPath *path = (SPPath *) object;
 
     switch (key) {
-        case SP_ATTR_D:
-            if (value) {
-                NArtBpath *bpath = sp_svg_read_path(value);
-                SPCurve *curve = sp_curve_new_from_bpath(bpath);
-                if (curve) {
-                    sp_shape_set_curve((SPShape *) path, curve, TRUE);
-                    sp_curve_unref(curve);
+        case SP_ATTR_INKSCAPE_ORIGINAL_D:
+                if (value) {
+                    NArtBpath *bpath = sp_svg_read_path(value);
+                    SPCurve *curve = sp_curve_new_from_bpath(bpath);
+                    if (curve) {
+                        sp_path_set_original_curve(path, curve, TRUE, true);
+                        sp_curve_unref(curve);
+                    }
+                } else {
+                    sp_path_set_original_curve(path, NULL, TRUE, true);
                 }
-            } else {
-                sp_shape_set_curve((SPShape *) path, NULL, TRUE);
+                object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+            break;
+       case SP_ATTR_D:
+            if (!((SPShape *) path)->path_effect_href) {
+                if (value) {
+                    NArtBpath *bpath = sp_svg_read_path(value);
+                    SPCurve *curve = sp_curve_new_from_bpath(bpath);
+                    if (curve) {
+                        sp_shape_set_curve((SPShape *) path, curve, TRUE);
+                        sp_curve_unref(curve);
+                    }
+                } else {
+                    sp_shape_set_curve((SPShape *) path, NULL, TRUE);
+                }
+                object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
             }
-            object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
             break;
         case SP_PROP_MARKER:
         case SP_PROP_MARKER_START:
@@ -234,7 +265,8 @@ sp_path_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
     SPShape *shape = (SPShape *) object;
 
     if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
-        repr = sp_repr_new("svg:path");
+        Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_OBJECT_DOCUMENT(object));
+        repr = xml_doc->createElement("svg:path");
     }
 
     if ( shape->curve != NULL ) {
@@ -250,6 +282,20 @@ sp_path_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
         repr->setAttribute("d", NULL);
     }
 
+    SPPath *path = (SPPath *) object;
+    if ( path->original_curve != NULL ) {
+        NArtBpath *abp = sp_curve_first_bpath(path->original_curve);
+        if (abp) {
+            gchar *str = sp_svg_write_path(abp);
+            repr->setAttribute("inkscape:original-d", str);
+            g_free(str);
+        } else {
+            repr->setAttribute("inkscape:original-d", "");
+        }
+    } else {
+        repr->setAttribute("inkscape:original-d", NULL);
+    }
+
     SP_PATH(shape)->connEndPair.writeRepr(repr);
 
     if (((SPObjectClass *)(parent_class))->write) {
@@ -282,19 +328,30 @@ static NR::Matrix
 sp_path_set_transform(SPItem *item, NR::Matrix const &xform)
 {
     SPShape *shape = (SPShape *) item;
+    SPPath *path = (SPPath *) item;
 
     if (!shape->curve) { // 0 nodes, nothing to transform
         return NR::identity();
     }
 
-    /* Transform the path */
-    NRBPath dpath, spath;
-    spath.path = SP_CURVE_BPATH(shape->curve);
-    nr_path_duplicate_transform(&dpath, &spath, xform);
-    SPCurve *curve = sp_curve_new_from_bpath(dpath.path);
-    if (curve) {
-        sp_shape_set_curve(shape, curve, TRUE);
-        sp_curve_unref(curve);
+    if (path->original_curve) { /* Transform the original-d path */
+        NRBPath dorigpath, sorigpath;
+        sorigpath.path = SP_CURVE_BPATH(path->original_curve);
+        nr_path_duplicate_transform(&dorigpath, &sorigpath, xform);
+        SPCurve *origcurve = sp_curve_new_from_bpath(dorigpath.path);
+        if (origcurve) {
+            sp_path_set_original_curve(path, origcurve, TRUE, true);
+            sp_curve_unref(origcurve);
+        }
+    } else {    /* Transform the path */
+        NRBPath dpath, spath;
+        spath.path = SP_CURVE_BPATH(shape->curve);
+        nr_path_duplicate_transform(&dpath, &spath, xform);
+        SPCurve *curve = sp_curve_new_from_bpath(dpath.path);
+        if (curve) {
+            sp_shape_set_curve(shape, curve, TRUE);
+            sp_curve_unref(curve);
+        }
     }
 
     // Adjust stroke
@@ -312,6 +369,88 @@ sp_path_set_transform(SPItem *item, NR::Matrix const &xform)
     return NR::identity();
 }
 
+static void
+sp_path_update_patheffect(SPShape *shape, bool write)
+{
+    SPPath *path = (SPPath *) shape;
+    if (path->original_curve) {
+        SPCurve *curve = sp_curve_copy (path->original_curve);
+        sp_shape_perform_path_effect(curve, shape);
+        sp_shape_set_curve(shape, curve, TRUE);
+        sp_curve_unref(curve);
+
+        if (write) {
+            // could also do SP_OBJECT(shape)->updateRepr();  but only the d attribute needs updating.
+            Inkscape::XML::Node *repr = SP_OBJECT_REPR(shape);
+            if ( shape->curve != NULL ) {
+                NArtBpath *abp = sp_curve_first_bpath(shape->curve);
+                if (abp) {
+                    gchar *str = sp_svg_write_path(abp);
+                    repr->setAttribute("d", str);
+                    g_free(str);
+                } else {
+                    repr->setAttribute("d", "");
+                }
+            } else {
+                repr->setAttribute("d", NULL);
+            }
+        }
+    } else {
+
+    }
+}
+
+
+/**
+ * Adds a original_curve to the path.  If owner is specified, a reference
+ * will be made, otherwise the curve will be copied into the path.
+ * Any existing curve in the path will be unreferenced first.
+ * This routine triggers reapplication of the an effect is present
+ * an also triggers a request to update the display. Does not write
+* result to XML when write=false.
+ */
+void
+sp_path_set_original_curve (SPPath *path, SPCurve *curve, unsigned int owner, bool write)
+{
+    if (path->original_curve) {
+        path->original_curve = sp_curve_unref (path->original_curve);
+    }
+    if (curve) {
+        if (owner) {
+            path->original_curve = sp_curve_ref (curve);
+        } else {
+            path->original_curve = sp_curve_copy (curve);
+        }
+    }
+    sp_path_update_patheffect(path, write);
+    SP_OBJECT(path)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+}
+
+/**
+ * Return duplicate of original_curve (if any exists) or NULL if there is no curve
+ */
+SPCurve *
+sp_path_get_original_curve (SPPath *path)
+{
+    if (path->original_curve) {
+        return sp_curve_copy (path->original_curve);
+    }
+    return NULL;
+}
+
+/**
+ * Return duplicate of edittable curve which is original_curve if it exists or
+ * shape->curve if not.
+ */
+SPCurve*
+sp_path_get_curve_for_edit (SPPath *path)
+{
+    if (path->original_curve) {
+        return sp_path_get_original_curve(path);
+    } else {
+        return sp_shape_get_curve( (SPShape *) path );
+    }
+}
 
 /*
   Local Variables: