Code

LPE STACKING!
authorjohanengelen <johanengelen@users.sourceforge.net>
Fri, 30 May 2008 20:36:13 +0000 (20:36 +0000)
committerjohanengelen <johanengelen@users.sourceforge.net>
Fri, 30 May 2008 20:36:13 +0000 (20:36 +0000)
(many thanks to the french students who made this.)

25 files changed:
src/live_effects/CMakeLists.txt
src/live_effects/Makefile_insert
src/live_effects/effect.cpp
src/live_effects/effect.h
src/live_effects/lpe-bendpath.cpp
src/live_effects/lpe-bendpath.h
src/live_effects/lpe-perp_bisector.cpp
src/live_effects/lpe-perspective_path.cpp
src/live_effects/lpe-perspective_path.h
src/live_effects/lpe-tangent_to_curve.cpp
src/live_effects/lpeobject-reference.cpp
src/live_effects/lpeobject-reference.h
src/nodepath.cpp
src/object-edit.cpp
src/path-chemistry.cpp
src/selection-chemistry.cpp
src/shape-editor.cpp
src/sp-item-group.cpp
src/sp-item.cpp
src/sp-lpe-item.cpp
src/sp-lpe-item.h
src/sp-path.cpp
src/ui/clipboard.cpp
src/ui/dialog/livepatheffect-editor.cpp
src/ui/dialog/livepatheffect-editor.h

index 28d54d87c79ee045f91f994e00803a0f8842536b..7d3221357ffd78978c028a1eef17b65dd339f0ca 100644 (file)
@@ -13,13 +13,13 @@ lpe-constructgrid.h
 lpe-curvestitch.cpp
 lpe-curvestitch.h
 lpe-envelope.cpp
-lpe-envelope.h
 lpe-gears.cpp
 lpe-gears.h
 lpegroupbbox.cpp
 lpegroupbbox.h
 lpe-knot.cpp
 lpe-knot.h
+lpe-lattice.cpp
 lpeobject.cpp
 lpeobject.h
 lpeobject-reference.cpp
@@ -46,3 +46,4 @@ spiro.cpp
 spiro.h
 )
 
+
index 4629a4d02c60f98bc418d2db51a4a3218843aeda..ea49aa269a4334661aa70f333e3dc46b86c995f9 100644 (file)
@@ -32,8 +32,16 @@ live_effects_liblive_effects_a_SOURCES = \
        live_effects/lpe-gears.h        \
        live_effects/lpe-test-doEffect-stack.cpp        \
        live_effects/lpe-test-doEffect-stack.h  \
+       live_effects/lpe-lattice.cpp    \
+       live_effects/lpe-lattice.h      \
+       live_effects/lpe-envelope.cpp   \
+       live_effects/lpe-envelope.h     \
        live_effects/lpe-spiro.cpp      \
        live_effects/lpe-spiro.h        \
+       live_effects/lpe-tangent_to_curve.cpp   \
+       live_effects/lpe-tangent_to_curve.h     \
+       live_effects/lpe-perp_bisector.cpp      \
+       live_effects/lpe-perp_bisector.h        \
        live_effects/spiro.h    \
        live_effects/spiro.cpp  \
        live_effects/bezctx.h   \
@@ -42,11 +50,6 @@ live_effects_liblive_effects_a_SOURCES = \
        live_effects/lpe-circle_with_radius.cpp \
        live_effects/lpe-circle_with_radius.h   \
        live_effects/lpe-perspective_path.cpp   \
-       live_effects/lpe-perspective_path.h             \
-       live_effects/lpe-envelope.cpp   \
-       live_effects/lpe-envelope.h     \
-       live_effects/lpe-perp_bisector.cpp      \
-       live_effects/lpe-perp_bisector.h        \
-       live_effects/lpe-tangent_to_curve.cpp   \
-       live_effects/lpe-tangent_to_curve.h
+       live_effects/lpe-perspective_path.h
+
 
index 906955575599d13fac395f6764148d2b7d9cc9c8..f968ec5c086e2436857300062319b754acb46f77 100644 (file)
@@ -43,8 +43,9 @@
 #include "live_effects/lpe-circle_with_radius.h"
 #include "live_effects/lpe-perspective_path.h"
 #include "live_effects/lpe-spiro.h"
-#include "live_effects/lpe-constructgrid.h"
+#include "live_effects/lpe-lattice.h"
 #include "live_effects/lpe-envelope.h"
+#include "live_effects/lpe-constructgrid.h"
 #include "live_effects/lpe-perp_bisector.h"
 #include "live_effects/lpe-tangent_to_curve.h"
 // end of includes
@@ -66,14 +67,15 @@ const Util::EnumData<EffectType> LPETypeData[INVALID_LPE] = {
     {DOEFFECTSTACK_TEST,    N_("doEffect stack test"),   "doeffectstacktest"},
 #endif
     {GEARS,                 N_("Gears"),                 "gears"},
-    {CURVE_STITCH,          N_("Stitch Sub-Paths"),      "curvestitching"},
+    {CURVE_STITCH,          N_("Stitch Sub-Paths"),       "curvestitching"},
     {CIRCLE_WITH_RADIUS,    N_("Circle (center+radius)"), "circle_with_radius"},
     {PERSPECTIVE_PATH,      N_("Perspective path"),      "perspective_path"},
     {SPIRO,      N_("Spiro spline"),      "spiro"},
-    {CONSTRUCT_GRID,        N_("Construct grid"),        "construct_grid"},
+    {LATTICE,               N_("Lattice Deformation"),   "lattice"},
     {ENVELOPE,              N_("Envelope Deformation"),  "envelope"},
+    {CONSTRUCT_GRID,        N_("Construct grid"),        "construct_grid"},
     {PERP_BISECTOR, N_("Perpendicular bisector"), "perp_bisector"},
-    {TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"},
+    {TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"}
 };
 const Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, INVALID_LPE);
 
@@ -108,6 +110,12 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj)
         case CURVE_STITCH:
             neweffect = static_cast<Effect*> ( new LPECurveStitch(lpeobj) );
             break;
+        case LATTICE:
+            neweffect = static_cast<Effect*> ( new LPELattice(lpeobj) );
+            break;
+        case ENVELOPE:
+            neweffect = static_cast<Effect*> ( new LPEEnvelope(lpeobj) );
+            break;
         case CIRCLE_WITH_RADIUS:
             neweffect = static_cast<Effect*> ( new LPECircleWithRadius(lpeobj) );
             break;
@@ -120,9 +128,6 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj)
         case CONSTRUCT_GRID:
             neweffect = static_cast<Effect*> ( new LPEConstructGrid(lpeobj) );
             break;
-        case ENVELOPE:
-            neweffect = static_cast<Effect*> ( new LPEEnvelope(lpeobj) );
-            break;
         case PERP_BISECTOR:
             neweffect = static_cast<Effect*> ( new LPEPerpBisector(lpeobj) );
             break;
index 1255595d0522fa8804cf9679f08a0c435c1af6cf..d5a49d71ed8235e4195d87b9eed11a8940b7dd7d 100644 (file)
@@ -66,8 +66,9 @@ enum EffectType {
     CIRCLE_WITH_RADIUS,
     PERSPECTIVE_PATH,
     SPIRO,
-    CONSTRUCT_GRID,
+    LATTICE,
     ENVELOPE,
+    CONSTRUCT_GRID,
     PERP_BISECTOR,
     TANGENT_TO_CURVE,
     INVALID_LPE // This must be last
index 6b9fbbb97eaedb8712735680e297f884ffdb487c..282ea82706f44738eaa1d974fde3367564afdfd8 100644 (file)
@@ -68,8 +68,6 @@ LPEBendPath::LPEBendPath(LivePathEffectObject *lpeobject) :
     prop_scale.param_set_increments(0.01, 0.10);
 
     concatenate_before_pwd2 = true;
-
-    groupSpecialBehavior = false;
 }
 
 LPEBendPath::~LPEBendPath()
@@ -80,12 +78,8 @@ LPEBendPath::~LPEBendPath()
 void
 LPEBendPath::doBeforeEffect (SPLPEItem *lpeitem)
 {
-    if(SP_IS_GROUP(lpeitem))
-    {
-        groupSpecialBehavior = true;
-
-        original_bbox(lpeitem);
-    }
+    // get the item bounding box
+    original_bbox(lpeitem);
 }
 
 Geom::Piecewise<Geom::D2<Geom::SBasis> >
@@ -105,11 +99,6 @@ LPEBendPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd
     Piecewise<SBasis> y = vertical_pattern.get_value() ? Piecewise<SBasis>(patternd2[0]) : Piecewise<SBasis>(patternd2[1]);
 
 //We use the group bounding box size or the path bbox size to translate well x and y
-    if(groupSpecialBehavior == false)
-    {
-        boundingbox_X = bounds_exact(x);
-        boundingbox_Y = bounds_exact(y);
-    }
     x-= vertical_pattern.get_value() ? boundingbox_Y.min() : boundingbox_X.min();
     y-= vertical_pattern.get_value() ? boundingbox_X.middle() : boundingbox_Y.middle();
 
index e05112de9fc1da46c2759413a873c620f34648c0..1d3a9861ef8793e5307b87496232acf0616c14b8 100644 (file)
@@ -47,8 +47,6 @@ private:
     BoolParam scale_y_rel;
     BoolParam    vertical_pattern;
 
-    bool groupSpecialBehavior;    
-
     void on_pattern_pasted();
 
     LPEBendPath(const LPEBendPath&);
index b31ad669635c1aeb7cc86b49b2f3c174c92f3047..52a21fbaf48edfc6ad2b98d71573ecdfa9573d4d 100644 (file)
-#define INKSCAPE_LPE_PERP_BISECTOR_CPP
-/** \file
- * LPE <perp_bisector> implementation.
- */
-/*
- * Authors:
- *   Maximilian Albert
- *   Johan Engelen
- *
- * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
- * Copyright (C) Maximilin Albert 2008 <maximilian.albert@gmail.com>
- *
- * Released under GNU GPL, read the file 'COPYING' for more information
- */
-
-#include "live_effects/lpe-perp_bisector.h"
-#include "display/curve.h"
-#include <libnr/n-art-bpath.h>
-#include "sp-path.h"
-#include "line-geometry.h"
-
-#include <2geom/path.h>
-
-namespace Inkscape {
-namespace LivePathEffect {
-
-/* FIXME: We should arguably make these member functions of LPEPerpBisector.
-          Is there an easy way to register member functions with knotholder?
- */
-NR::Point bisector_left_end_get(SPItem *item) {
-    Inkscape::LivePathEffect::LPEPerpBisector *lpe =
-        (Inkscape::LivePathEffect::LPEPerpBisector *) sp_lpe_item_get_livepatheffect(SP_LPE_ITEM(item));
-
-    return NR::Point(lpe->C);
-}
-
-NR::Point bisector_right_end_get(SPItem *item) {
-    Inkscape::LivePathEffect::LPEPerpBisector *lpe =
-        (Inkscape::LivePathEffect::LPEPerpBisector *) sp_lpe_item_get_livepatheffect(SP_LPE_ITEM(item));
-
-    return NR::Point(lpe->D);
-}
-
-void
-bisector_end_set(SPItem *item, NR::Point const &p, bool left) {
-    Inkscape::LivePathEffect::LPEPerpBisector *lpe =
-        (Inkscape::LivePathEffect::LPEPerpBisector *) sp_lpe_item_get_livepatheffect(SP_LPE_ITEM(item));
-
-    double lambda = Geom::nearest_point(p.to_2geom(), lpe->M, lpe->perp_dir);
-    if (left) {
-        lpe->C = lpe->M + lpe->perp_dir * lambda;
-        lpe->length_left.param_set_value(lambda);
-    } else {
-        lpe->D = lpe->M + lpe->perp_dir * lambda;
-        lpe->length_right.param_set_value(-lambda);
-    }
-
-    sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), true);
-}
-
-void
-bisector_left_end_set(SPItem *item, NR::Point const &p, NR::Point const &/*origin*/, guint /*state*/) {
-    bisector_end_set(item, p);
-}
-
-void
-bisector_right_end_set(SPItem *item, NR::Point const &p, NR::Point const &/*origin*/, guint /*state*/) {
-    bisector_end_set(item, p, false);
-}
-
-NR::Point path_start_get(SPItem *item) {
-    Inkscape::LivePathEffect::LPEPerpBisector *lpe =
-        (Inkscape::LivePathEffect::LPEPerpBisector *) sp_lpe_item_get_livepatheffect(SP_LPE_ITEM(item));
-
-    return NR::Point(lpe->A);
-}
-
-NR::Point path_end_get(SPItem *item) {
-    Inkscape::LivePathEffect::LPEPerpBisector *lpe =
-        (Inkscape::LivePathEffect::LPEPerpBisector *) sp_lpe_item_get_livepatheffect(SP_LPE_ITEM(item));
-
-    return NR::Point(lpe->B);
-}
-
-void
-path_set_start_end(SPItem *item, NR::Point const &p, bool start) {
-    SPCurve* curve = sp_path_get_curve_for_edit (SP_PATH(item)); // TODO: Should we use sp_shape_get_curve()?
-    NR::Matrix const i2d (sp_item_i2d_affine (SP_ITEM(item)));
-
-    Geom::Point A, B;
-    if (start) {
-        A = p.to_2geom();
-        B = (curve->last_point()).to_2geom();
-    } else {
-        A = (curve->first_point()).to_2geom();
-        B = (p.to_2geom());
-    }
-
-    SPCurve *c = new SPCurve();
-    c->moveto(A);
-    c->lineto(B);
-    sp_path_set_original_curve(SP_PATH(item), c, TRUE, true);
-    c->unref();
-}
-
-void path_start_set(SPItem *item, NR::Point const &p, NR::Point const &/*origin*/, guint /*state*/) {
-    path_set_start_end(item, p);
-}
-
-void path_end_set(SPItem *item, NR::Point const &p, NR::Point const &/*origin*/, guint /*state*/) {
-    path_set_start_end(item, p, false);
-}
-
-LPEPerpBisector::LPEPerpBisector(LivePathEffectObject *lpeobject) :
-    Effect(lpeobject),
-    length_left(_("Length left"), _("Specifies the left end of the bisector"), "length-left", &wr, this, 200),
-    length_right(_("Length right"), _("Specifies the right end of the bisector"), "length-right", &wr, this, 200),
-    A(0,0), B(0,0), M(0,0), C(0,0), D(0,0), perp_dir(0,0)
-{
-    // register all your parameters here, so Inkscape knows which parameters this effect has:
-    registerParameter( dynamic_cast<Parameter *>(&length_left) );
-    registerParameter( dynamic_cast<Parameter *>(&length_right) );
-
-    registerKnotHolderHandle(path_start_set, path_start_get);
-    registerKnotHolderHandle(path_end_set, path_end_get);
-    registerKnotHolderHandle(bisector_left_end_set, bisector_left_end_get);
-    registerKnotHolderHandle(bisector_right_end_set, bisector_right_end_get);
-}
-
-LPEPerpBisector::~LPEPerpBisector()
-{
-}
-
-void
-LPEPerpBisector::doOnApply (SPLPEItem *lpeitem)
-{
-    /* make the path a straight line */
-    SPCurve* curve = sp_path_get_curve_for_edit (SP_PATH(lpeitem)); // TODO: Should we use sp_shape_get_curve()?
-
-    Geom::Point A((curve->first_point()).to_2geom());
-    Geom::Point B((curve->last_point()).to_2geom());
-
-    SPCurve *c = new SPCurve();
-    c->moveto(A);
-    c->lineto(B);
-    // TODO: Why doesn't sp_path_set_original_curve(SP_PATH(lpeitem), c, TRUE, true) work?
-    SP_PATH(lpeitem)->original_curve = c->ref();
-    c->unref();
-}
-
-
-Geom::Piecewise<Geom::D2<Geom::SBasis> >
-LPEPerpBisector::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
-{
-    using namespace Geom;
-
-    Piecewise<D2<SBasis> > output;
-
-    A = pwd2_in.firstValue();
-    B = pwd2_in.lastValue();
-    M = (A + B)/2;
-
-    perp_dir = unit_vector((B - A).ccw());
-
-    C = M + perp_dir * length_left;
-    D = M - perp_dir * length_right;
-
-    output = Piecewise<D2<SBasis> >(D2<SBasis>(Linear(C[X], D[X]), Linear(C[Y], D[Y])));
-
-    return output;
-}
-
-/* ######################## */
-
-} //namespace LivePathEffect
-} /* 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 :
+#define INKSCAPE_LPE_PERP_BISECTOR_CPP\r
+/** \file\r
+ * LPE <perp_bisector> implementation.\r
+ */\r
+/*\r
+ * Authors:\r
+ *   Maximilian Albert\r
+ *   Johan Engelen\r
+ *\r
+ * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>\r
+ * Copyright (C) Maximilin Albert 2008 <maximilian.albert@gmail.com>\r
+ *\r
+ * Released under GNU GPL, read the file 'COPYING' for more information\r
+ */\r
+\r
+#include "live_effects/lpe-perp_bisector.h"\r
+#include "display/curve.h"\r
+#include <libnr/n-art-bpath.h>\r
+#include "sp-path.h"\r
+#include "line-geometry.h"\r
+#include "sp-lpe-item.h"\r
+#include <2geom/path.h>\r
+\r
+namespace Inkscape {\r
+namespace LivePathEffect {\r
+\r
+/* FIXME: We should make these member functions of LPEPerpBisector.\r
+          Is there an easy way to register member functions with knotholder?\r
+   KNOWN BUG: Because of the above, this effect does not work well when in an LPE stack\r
+ */\r
+NR::Point bisector_left_end_get(SPItem *item) {\r
+    Inkscape::LivePathEffect::LPEPerpBisector *lpe =\r
+        dynamic_cast<Inkscape::LivePathEffect::LPEPerpBisector *> (sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item)));\r
+\r
+    if (lpe)\r
+        return NR::Point(lpe->C);\r
+    else\r
+        return NR::Point(0,0);\r
+}\r
+\r
+NR::Point bisector_right_end_get(SPItem *item) {\r
+    Inkscape::LivePathEffect::LPEPerpBisector *lpe =\r
+        dynamic_cast<Inkscape::LivePathEffect::LPEPerpBisector *> (sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item)));\r
+\r
+    if (lpe)\r
+        return NR::Point(lpe->D);\r
+    else\r
+        return NR::Point(0,0);\r
+}\r
+\r
+void\r
+bisector_end_set(SPItem *item, NR::Point const &p, bool left) {\r
+    Inkscape::LivePathEffect::LPEPerpBisector *lpe =\r
+        dynamic_cast<Inkscape::LivePathEffect::LPEPerpBisector *> (sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item)));\r
+\r
+    if (!lpe)\r
+        return;\r
+\r
+    double lambda = Geom::nearest_point(p.to_2geom(), lpe->M, lpe->perp_dir);\r
+    if (left) {\r
+        lpe->C = lpe->M + lpe->perp_dir * lambda;\r
+        lpe->length_left.param_set_value(lambda);\r
+    } else {\r
+        lpe->D = lpe->M + lpe->perp_dir * lambda;\r
+        lpe->length_right.param_set_value(-lambda);\r
+    }\r
+\r
+    // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating.\r
+    sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), true, true);\r
+}\r
+\r
+void\r
+bisector_left_end_set(SPItem *item, NR::Point const &p, NR::Point const &/*origin*/, guint /*state*/) {\r
+    bisector_end_set(item, p);\r
+}\r
+\r
+void\r
+bisector_right_end_set(SPItem *item, NR::Point const &p, NR::Point const &/*origin*/, guint /*state*/) {\r
+    bisector_end_set(item, p, false);\r
+}\r
+\r
+NR::Point path_start_get(SPItem *item) {\r
+    Inkscape::LivePathEffect::LPEPerpBisector *lpe =\r
+        dynamic_cast<Inkscape::LivePathEffect::LPEPerpBisector *> (sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item)));\r
+\r
+    if (lpe)\r
+        return NR::Point(lpe->A);\r
+    else\r
+        return NR::Point(0,0);\r
+}\r
+\r
+NR::Point path_end_get(SPItem *item) {\r
+    Inkscape::LivePathEffect::LPEPerpBisector *lpe =\r
+        dynamic_cast<Inkscape::LivePathEffect::LPEPerpBisector *> (sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item)));\r
+\r
+    if (lpe)\r
+        return NR::Point(lpe->B);\r
+    else\r
+        return NR::Point(0,0);\r
+}\r
+\r
+void\r
+path_set_start_end(SPItem *item, NR::Point const &p, bool start) {\r
+    SPCurve* curve = sp_path_get_curve_for_edit (SP_PATH(item)); // TODO: Should we use sp_shape_get_curve()?\r
+    NR::Matrix const i2d (sp_item_i2d_affine (SP_ITEM(item)));\r
+\r
+    Geom::Point A, B;\r
+    if (start) {\r
+        A = p.to_2geom();\r
+        B = (curve->last_point()).to_2geom();\r
+    } else {\r
+        A = (curve->first_point()).to_2geom();\r
+        B = (p.to_2geom());\r
+    }\r
+\r
+    SPCurve *c = new SPCurve();\r
+    c->moveto(A);\r
+    c->lineto(B);\r
+    sp_path_set_original_curve(SP_PATH(item), c, TRUE, true);\r
+    c->unref();\r
+}\r
+\r
+void path_start_set(SPItem *item, NR::Point const &p, NR::Point const &/*origin*/, guint /*state*/) {\r
+    path_set_start_end(item, p);\r
+}\r
+\r
+void path_end_set(SPItem *item, NR::Point const &p, NR::Point const &/*origin*/, guint /*state*/) {\r
+    path_set_start_end(item, p, false);\r
+}\r
+\r
+LPEPerpBisector::LPEPerpBisector(LivePathEffectObject *lpeobject) :\r
+    Effect(lpeobject),\r
+    length_left(_("Length left"), _("Specifies the left end of the bisector"), "length-left", &wr, this, 200),\r
+    length_right(_("Length right"), _("Specifies the right end of the bisector"), "length-right", &wr, this, 200),\r
+    A(0,0), B(0,0), M(0,0), C(0,0), D(0,0), perp_dir(0,0)\r
+{\r
+    // register all your parameters here, so Inkscape knows which parameters this effect has:\r
+    registerParameter( dynamic_cast<Parameter *>(&length_left) );\r
+    registerParameter( dynamic_cast<Parameter *>(&length_right) );\r
+\r
+    registerKnotHolderHandle(path_start_set, path_start_get);\r
+    registerKnotHolderHandle(path_end_set, path_end_get);\r
+    registerKnotHolderHandle(bisector_left_end_set, bisector_left_end_get);\r
+    registerKnotHolderHandle(bisector_right_end_set, bisector_right_end_get);\r
+}\r
+\r
+LPEPerpBisector::~LPEPerpBisector()\r
+{\r
+}\r
+\r
+void\r
+LPEPerpBisector::doOnApply (SPLPEItem *lpeitem)\r
+{\r
+    /* make the path a straight line */\r
+    SPCurve* curve = sp_path_get_curve_for_edit (SP_PATH(lpeitem)); // TODO: Should we use sp_shape_get_curve()?\r
+\r
+    Geom::Point A((curve->first_point()).to_2geom());\r
+    Geom::Point B((curve->last_point()).to_2geom());\r
+\r
+    SPCurve *c = new SPCurve();\r
+    c->moveto(A);\r
+    c->lineto(B);\r
+    // TODO: Why doesn't sp_path_set_original_curve(SP_PATH(lpeitem), c, TRUE, true) work?\r
+    SP_PATH(lpeitem)->original_curve = c->ref();\r
+    c->unref();\r
+}\r
+\r
+\r
+Geom::Piecewise<Geom::D2<Geom::SBasis> >\r
+LPEPerpBisector::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)\r
+{\r
+    using namespace Geom;\r
+\r
+    Piecewise<D2<SBasis> > output;\r
+\r
+    A = pwd2_in.firstValue();\r
+    B = pwd2_in.lastValue();\r
+    M = (A + B)/2;\r
+\r
+    perp_dir = unit_vector((B - A).ccw());\r
+\r
+    C = M + perp_dir * length_left;\r
+    D = M - perp_dir * length_right;\r
+\r
+    output = Piecewise<D2<SBasis> >(D2<SBasis>(Linear(C[X], D[X]), Linear(C[Y], D[Y])));\r
+\r
+    return output;\r
+}\r
+\r
+/* ######################## */\r
+\r
+} //namespace LivePathEffect\r
+} /* namespace Inkscape */\r
+\r
+/*\r
+  Local Variables:\r
+  mode:c++\r
+  c-file-style:"stroustrup"\r
+  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
+  indent-tabs-mode:nil\r
+  fill-column:99\r
+  End:\r
+*/\r
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :\r
index 57bc458a945da28f879206e0b0b566866c170199..cf6d1cecd91ce583f588ed013239abd98d840196 100644 (file)
@@ -59,8 +59,6 @@ LPEPerspectivePath::LPEPerspectivePath(LivePathEffectObject *lpeobject) :
     Proj::TransfMat3x4 pmat = persp->tmat;
 
     pmat.copy_tmat(tmat);
-    
-    groupSpecialBehavior = false;
 }
 
 LPEPerspectivePath::~LPEPerspectivePath()
@@ -71,14 +69,9 @@ LPEPerspectivePath::~LPEPerspectivePath()
 void
 LPEPerspectivePath::doBeforeEffect (SPLPEItem *lpeitem)
 {
-    if(SP_IS_GROUP(lpeitem))
-    {
-        groupSpecialBehavior = true;
-        original_bbox(lpeitem);
-    }    
+    original_bbox(lpeitem, true); 
 }
 
-
 Geom::Piecewise<Geom::D2<Geom::SBasis> >
 LPEPerspectivePath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
 {
@@ -93,14 +86,9 @@ LPEPerspectivePath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > cons
     D2<Piecewise<SBasis> > B = make_cuts_independant(path_a_pw);
     Piecewise<SBasis> preimage[4];
 
-    if(!groupSpecialBehavior)
-    {
-        boundingbox_X = bounds_fast(pwd2_in)[0];
-        boundingbox_Y = bounds_fast(pwd2_in)[1];
-    }
-
     Geom::Point orig = Geom::Point(uses_plane_xy ? boundingbox_X.max() : boundingbox_X.min(),
                                    boundingbox_Y.middle());
+
     //Geom::Point orig = Geom::Point(bounds_X.min(), bounds_Y.middle());
     //orig = Geom::Point(orig[X], sp_document_height(inkscape_active_document()) - orig[Y]);
 
index a2f451e6558d412e0348a2cae18f75ac6b984c9e..02dcf23258b1156fc1884bb28c02bd203f4054b2 100644 (file)
@@ -48,8 +48,6 @@ private:
 
     std::vector<Geom::Point> handles;
     double tmat[3][4];
-    
-    bool groupSpecialBehavior;
 };
 
 } //namespace LivePathEffect
index 65948837fc3fb745f3738c5e0af9689e6cd6208f..6293ba2334b259bb2f5bf7a001a9073caaaa3d62 100644 (file)
-#define INKSCAPE_LPE_TANGENT_TO_CURVE_CPP
-/** \file
- * Implementation of tangent-to-curve LPE.
- */
-
-/*
- * Authors:
- *   Johan Engelen
- *   Maximilian Albert
- *
- * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
- * Copyright (C) Maximilian Albert 2008 <maximilian.albert@gmail.com>
- *
- * Released under GNU GPL, read the file 'COPYING' for more information
- */
-
-#include "live_effects/lpe-tangent_to_curve.h"
-// FIXME: The following are only needed to convert the path's SPCurve* to pwd2.
-//        There must be a more convenient way to achieve this.
-#include "sp-path.h"
-#include "display/curve.h"
-#include "libnr/n-art-bpath-2geom.h"
-
-#include <2geom/path.h>
-#include <2geom/transforms.h>
-
-namespace Inkscape {
-namespace LivePathEffect {
-
-/* FIXME: We should arguably make these member functions of LPETangentToCurve.
-          Is there an easy way to register member functions with knotholder?
- */
-NR::Point attach_pt_get(SPItem *item) {
-    Inkscape::LivePathEffect::LPETangentToCurve *lpe =
-        (Inkscape::LivePathEffect::LPETangentToCurve *) sp_lpe_item_get_livepatheffect(SP_LPE_ITEM(item));
-
-    return lpe->ptA;
-}
-
-void attach_pt_set(SPItem *item, NR::Point const &p, NR::Point const &origin, guint state) {
-    Inkscape::LivePathEffect::LPETangentToCurve *lpe =
-        (Inkscape::LivePathEffect::LPETangentToCurve *) sp_lpe_item_get_livepatheffect(SP_LPE_ITEM(item));
-
-    using namespace Geom;
-
-    // FIXME: There must be a better way of converting the path's SPCurve* to pwd2.
-    SPCurve *curve = sp_path_get_curve_for_edit (SP_PATH(item));
-    const NArtBpath *bpath = curve->get_bpath();
-    Piecewise<D2<SBasis> > pwd2;
-    std::vector<Geom::Path> pathv = BPath_to_2GeomPath(bpath);
-    for (unsigned int i=0; i < pathv.size(); i++) {
-        pwd2.concat(pathv[i].toPwSb());
-    }
-
-    double t0 = nearest_point(p.to_2geom(), pwd2);
-    lpe->t_attach.param_set_value(t0);
-
-    sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), true);
-}
-
-NR::Point left_end_get(SPItem *item) {
-    Inkscape::LivePathEffect::LPETangentToCurve *lpe =
-        (Inkscape::LivePathEffect::LPETangentToCurve *) sp_lpe_item_get_livepatheffect(SP_LPE_ITEM(item));
-
-    return lpe->C;
-}
-
-NR::Point right_end_get(SPItem *item) {
-    Inkscape::LivePathEffect::LPETangentToCurve *lpe =
-        (Inkscape::LivePathEffect::LPETangentToCurve *) sp_lpe_item_get_livepatheffect(SP_LPE_ITEM(item));
-
-    return lpe->D;
-}
-
-void left_end_set(SPItem *item, NR::Point const &p, NR::Point const &origin, guint state) {
-    Inkscape::LivePathEffect::LPETangentToCurve *lpe =
-        (Inkscape::LivePathEffect::LPETangentToCurve *) sp_lpe_item_get_livepatheffect(SP_LPE_ITEM(item));
-
-    double lambda = Geom::nearest_point(p.to_2geom(), lpe->ptA, lpe->derivA);
-    lpe->length_left.param_set_value(-lambda);
-
-    sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), true);
-}
-
-void right_end_set(SPItem *item, NR::Point const &p, NR::Point const &origin, guint state) {
-    Inkscape::LivePathEffect::LPETangentToCurve *lpe =
-        (Inkscape::LivePathEffect::LPETangentToCurve *) sp_lpe_item_get_livepatheffect(SP_LPE_ITEM(item));
-
-    double lambda = Geom::nearest_point(p.to_2geom(), lpe->ptA, lpe->derivA);
-    lpe->length_right.param_set_value(lambda);
-
-    sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), true);
-}
-
-LPETangentToCurve::LPETangentToCurve(LivePathEffectObject *lpeobject) :
-    Effect(lpeobject),
-    t_attach(_("Location along curve"), _("Location of the point of attachment along the curve (between 0.0 and number-of-segments)"), "t_attach", &wr, this, 0.5),
-    length_left(_("Length left"), _("Specifies the left end of the tangent"), "length-left", &wr, this, 150),
-    length_right(_("Length right"), _("Specifies the right end of the tangent"), "length-right", &wr, this, 150),
-    angle(_("Angle"), _("Additional angle between tangent and curve"), "angle", &wr, this, 0.0)
-{
-    registerParameter( dynamic_cast<Parameter *>(&t_attach) );
-    registerParameter( dynamic_cast<Parameter *>(&length_left) );
-    registerParameter( dynamic_cast<Parameter *>(&length_right) );
-    registerParameter( dynamic_cast<Parameter *>(&angle) );
-    registerKnotHolderHandle(attach_pt_set, attach_pt_get);
-    registerKnotHolderHandle(left_end_set, left_end_get);
-    registerKnotHolderHandle(right_end_set, right_end_get);
-}
-
-LPETangentToCurve::~LPETangentToCurve()
-{
-}
-
-Geom::Piecewise<Geom::D2<Geom::SBasis> >
-LPETangentToCurve::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
-{
-    using namespace Geom;
-    Piecewise<D2<SBasis> > output;
-
-    ptA = pwd2_in.valueAt(t_attach);
-    derivA = unit_vector(derivative(pwd2_in).valueAt(t_attach));
-
-    // TODO: Why are positive angles measured clockwise, not counterclockwise?
-    Geom::Rotate rot(Geom::Rotate::from_degrees(-angle));
-    derivA = derivA * rot;
-
-    C = ptA - derivA * length_left;
-    D = ptA + derivA * length_right;
-
-    output = Piecewise<D2<SBasis> >(D2<SBasis>(Linear(C[X], D[X]), Linear(C[Y], D[Y])));
-
-    return output;
-}
-
-} //namespace LivePathEffect
-} /* 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 :
+#define INKSCAPE_LPE_TANGENT_TO_CURVE_CPP\r
+/** \file\r
+ * Implementation of tangent-to-curve LPE.\r
+ */\r
+\r
+/*\r
+ * Authors:\r
+ *   Johan Engelen\r
+ *   Maximilian Albert\r
+ *\r
+ * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>\r
+ * Copyright (C) Maximilian Albert 2008 <maximilian.albert@gmail.com>\r
+ *\r
+ * Released under GNU GPL, read the file 'COPYING' for more information\r
+ */\r
+\r
+#include "live_effects/lpe-tangent_to_curve.h"\r
+// FIXME: The following are only needed to convert the path's SPCurve* to pwd2.\r
+//        There must be a more convenient way to achieve this.\r
+#include "sp-path.h"\r
+#include "display/curve.h"\r
+#include "libnr/n-art-bpath-2geom.h"\r
+\r
+#include <2geom/path.h>\r
+#include <2geom/transforms.h>\r
+\r
+namespace Inkscape {\r
+namespace LivePathEffect {\r
+\r
+/* FIXME: We should make these member functions of LPETangentToCurve.\r
+          Is there an easy way to register member functions with knotholder?\r
+    KNOWN BUG: Because of the above, this effect does not work well when in an LPE stack\r
+*/\r
+NR::Point attach_pt_get(SPItem *item) {\r
+    Inkscape::LivePathEffect::LPETangentToCurve *lpe =\r
+        dynamic_cast<Inkscape::LivePathEffect::LPETangentToCurve *> (sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item)));\r
+\r
+    if (lpe)\r
+        return lpe->ptA;\r
+    else\r
+        return NR::Point(0,0);\r
+}\r
+\r
+void attach_pt_set(SPItem *item, NR::Point const &p, NR::Point const &origin, guint state) {\r
+    Inkscape::LivePathEffect::LPETangentToCurve *lpe =\r
+        dynamic_cast<Inkscape::LivePathEffect::LPETangentToCurve *> (sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item)));\r
+\r
+    if (!lpe)\r
+        return;\r
+\r
+    using namespace Geom;\r
+\r
+    // FIXME: There must be a better way of converting the path's SPCurve* to pwd2.\r
+    SPCurve *curve = sp_path_get_curve_for_edit (SP_PATH(item));\r
+    const NArtBpath *bpath = curve->get_bpath();\r
+    Piecewise<D2<SBasis> > pwd2;\r
+    std::vector<Geom::Path> pathv = BPath_to_2GeomPath(bpath);\r
+    for (unsigned int i=0; i < pathv.size(); i++) {\r
+        pwd2.concat(pathv[i].toPwSb());\r
+    }\r
+\r
+    double t0 = nearest_point(p.to_2geom(), pwd2);\r
+    lpe->t_attach.param_set_value(t0);\r
+\r
+    // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating.\r
+    sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), true, true);\r
+}\r
+\r
+NR::Point left_end_get(SPItem *item) {\r
+    Inkscape::LivePathEffect::LPETangentToCurve *lpe =\r
+        dynamic_cast<Inkscape::LivePathEffect::LPETangentToCurve *> (sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item)));\r
+\r
+    if (lpe)\r
+        return lpe->C;\r
+    else\r
+        return NR::Point(0,0);\r
+}\r
+\r
+NR::Point right_end_get(SPItem *item) {\r
+    Inkscape::LivePathEffect::LPETangentToCurve *lpe =\r
+        dynamic_cast<Inkscape::LivePathEffect::LPETangentToCurve *> (sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item)));\r
+\r
+    if (lpe)\r
+        return lpe->D;\r
+    else\r
+        return NR::Point(0,0);\r
+}\r
+\r
+void left_end_set(SPItem *item, NR::Point const &p, NR::Point const &origin, guint state) {\r
+    Inkscape::LivePathEffect::LPETangentToCurve *lpe =\r
+        dynamic_cast<Inkscape::LivePathEffect::LPETangentToCurve *> (sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item)));\r
+\r
+    if (!lpe)\r
+        return;\r
+\r
+    double lambda = Geom::nearest_point(p.to_2geom(), lpe->ptA, lpe->derivA);\r
+    lpe->length_left.param_set_value(-lambda);\r
+\r
+    // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating.\r
+    sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), true, true);\r
+}\r
+\r
+void right_end_set(SPItem *item, NR::Point const &p, NR::Point const &origin, guint state) {\r
+    Inkscape::LivePathEffect::LPETangentToCurve *lpe =\r
+        dynamic_cast<Inkscape::LivePathEffect::LPETangentToCurve *> (sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item)));\r
+\r
+    if (!lpe)\r
+        return;\r
+\r
+    double lambda = Geom::nearest_point(p.to_2geom(), lpe->ptA, lpe->derivA);\r
+    lpe->length_right.param_set_value(lambda);\r
+\r
+    // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating.\r
+    sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), true, true);\r
+}\r
+\r
+LPETangentToCurve::LPETangentToCurve(LivePathEffectObject *lpeobject) :\r
+    Effect(lpeobject),\r
+    t_attach(_("Location along curve"), _("Location of the point of attachment along the curve (between 0.0 and number-of-segments)"), "t_attach", &wr, this, 0.5),\r
+    length_left(_("Length left"), _("Specifies the left end of the tangent"), "length-left", &wr, this, 150),\r
+    length_right(_("Length right"), _("Specifies the right end of the tangent"), "length-right", &wr, this, 150),\r
+    angle(_("Angle"), _("Additional angle between tangent and curve"), "angle", &wr, this, 0.0)\r
+{\r
+    registerParameter( dynamic_cast<Parameter *>(&t_attach) );\r
+    registerParameter( dynamic_cast<Parameter *>(&length_left) );\r
+    registerParameter( dynamic_cast<Parameter *>(&length_right) );\r
+    registerParameter( dynamic_cast<Parameter *>(&angle) );\r
+    registerKnotHolderHandle(attach_pt_set, attach_pt_get);\r
+    registerKnotHolderHandle(left_end_set, left_end_get);\r
+    registerKnotHolderHandle(right_end_set, right_end_get);\r
+}\r
+\r
+LPETangentToCurve::~LPETangentToCurve()\r
+{\r
+}\r
+\r
+Geom::Piecewise<Geom::D2<Geom::SBasis> >\r
+LPETangentToCurve::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)\r
+{\r
+    using namespace Geom;\r
+    Piecewise<D2<SBasis> > output;\r
+\r
+    ptA = pwd2_in.valueAt(t_attach);\r
+    derivA = unit_vector(derivative(pwd2_in).valueAt(t_attach));\r
+\r
+    // TODO: Why are positive angles measured clockwise, not counterclockwise?\r
+    Geom::Rotate rot(Geom::Rotate::from_degrees(-angle));\r
+    derivA = derivA * rot;\r
+\r
+    C = ptA - derivA * length_left;\r
+    D = ptA + derivA * length_right;\r
+\r
+    output = Piecewise<D2<SBasis> >(D2<SBasis>(Linear(C[X], D[X]), Linear(C[Y], D[Y])));\r
+\r
+    return output;\r
+}\r
+\r
+} //namespace LivePathEffect\r
+} /* namespace Inkscape */\r
+\r
+/*\r
+  Local Variables:\r
+  mode:c++\r
+  c-file-style:"stroustrup"\r
+  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
+  indent-tabs-mode:nil\r
+  fill-column:99\r
+  End:\r
+*/\r
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :\r
index 34005e79199fa17ffcc5cb1cdcf910bb792ded4d..8a8dd94da0c18381263c8b053ddec28ece2b6845 100644 (file)
@@ -59,7 +59,7 @@ bool LPEObjectReference::_acceptObject(SPObject * const obj) const
 }
 
 void
-LPEObjectReference::link(char *to)
+LPEObjectReference::link(const char *to)
 {
     if ( to == NULL ) {
         quit_listening();
index 6a2f75327c9b7dd66ac8552e63b3569b0951a6cf..e5f7556f1668d138b899344c475c0ffc715caa07 100644 (file)
@@ -41,7 +41,7 @@ public:
     sigc::connection _delete_connection;
     sigc::connection _changed_connection;
 
-    void            link(char* to);
+    void            link(const char* to);
     void            unlink(void);
     void            start_listening(LivePathEffectObject* to);
     void            quit_listening(void);
index ff442fd702aad76cfa8ba8f524b26e137e57311f..e827f9fb07dafa522d5c39433d58eefd700fa48c 100644 (file)
@@ -51,6 +51,7 @@
 #include <cstring>
 #include <string>
 #include "live_effects/lpeobject.h"
+#include "live_effects/effect.h"
 #include "live_effects/parameter/parameter.h"
 #include "util/mathfns.h"
 #include "display/snap-indicator.h"
@@ -236,9 +237,9 @@ Inkscape::NodePath::Path *sp_nodepath_new(SPDesktop *desktop, SPObject *object,
         if ( sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(np->object)) ) {
             np->repr_key = g_strdup("inkscape:original-d");
 
-            LivePathEffectObject *lpeobj = sp_lpe_item_get_livepatheffectobject(SP_LPE_ITEM(np->object));
-            if (lpeobj && lpeobj->lpe) {
-                lpeobj->lpe->setup_nodepath(np);
+            Inkscape::LivePathEffect::Effect* lpe = sp_lpe_item_get_current_lpe(SP_LPE_ITEM(np->object));
+            if (lpe) {
+                lpe->setup_nodepath(np);
             }
         } else {
             np->repr_key = g_strdup("d");
index 091c997348abc04b930e8173ddd435b50037d93f..ecd6227f42cc781088b11d48e13a978098ba230b 100644 (file)
@@ -63,8 +63,12 @@ static SPKnotHolder *sp_lpe_knot_holder(SPItem *item, SPDesktop *desktop)
 {
     SPKnotHolder *knot_holder = sp_knot_holder_new(desktop, item, NULL);
 
-    Inkscape::LivePathEffect::Effect *effect = sp_lpe_item_get_livepatheffect(SP_LPE_ITEM(item));
-    effect->addHandles(knot_holder);
+    Inkscape::LivePathEffect::Effect *effect = sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item));
+    if (!effect) {
+        g_error("sp_lpe_knot_holder: logical error, this method cannot be called with item having an LPE");
+    } else {
+        effect->addHandles(knot_holder);
+    }
 
     return knot_holder;
 }
@@ -72,12 +76,11 @@ static SPKnotHolder *sp_lpe_knot_holder(SPItem *item, SPDesktop *desktop)
 SPKnotHolder *
 sp_item_knot_holder(SPItem *item, SPDesktop *desktop)
 {
-    if (sp_lpe_item_has_path_effect(SP_LPE_ITEM(item)) &&
-        sp_lpe_item_get_livepatheffect(SP_LPE_ITEM(item))->isVisible() &&
-        sp_lpe_item_get_livepatheffect(SP_LPE_ITEM(item))->providesKnotholder()) {
+    if (sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item)) &&
+        sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item))->isVisible() &&
+        sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item))->providesKnotholder()) {
         return sp_lpe_knot_holder(item, desktop);
-    } else
-    if (SP_IS_RECT(item)) {
+    } else if (SP_IS_RECT(item)) {
         return sp_rect_knot_holder(item, desktop);
     } else if (SP_IS_BOX3D(item)) {
         return box3d_knot_holder(item, desktop);
index 5b57e326efb52a0f6b357aac3e7adbb54d33f286..996ae3fd5203afc8521730305ee0fb363620766f 100644 (file)
@@ -368,7 +368,7 @@ sp_item_list_to_curves(const GSList *items, GSList **selected, GSList **to_selec
         }
         
         if (SP_IS_GROUP(item)) {
-            sp_lpe_item_remove_path_effect(SP_LPE_ITEM(item), true);
+            sp_lpe_item_remove_all_path_effects(SP_LPE_ITEM(item), true);
             GSList *item_list = sp_item_group_item_list(SP_GROUP(item));
             
             GSList *item_to_select = NULL;
index 0f89464411e395c9a6235bdd24fd5d1b80b54418..9c826c949a8ad38706e8f6341213dcd697a102c8 100644 (file)
@@ -893,7 +893,7 @@ void sp_selection_paste_livepatheffect()
 void sp_selection_remove_livepatheffect_impl(SPItem *item)
 {
     if ( item && SP_IS_LPE_ITEM(item) ) {
-        sp_lpe_item_remove_path_effect(SP_LPE_ITEM(item), false);
+        sp_lpe_item_remove_all_path_effects(SP_LPE_ITEM(item), false);
     }
 }
 
index 40e92e0dd0033565fa7b314b5e1e6f2481348db7..1d60671aad089cf5d0595e740504b6122e4b5b3e 100644 (file)
@@ -191,9 +191,9 @@ void ShapeEditor::set_item(SPItem *item) {
 
     if (item) {
         SPLPEItem *lpeitem = SP_LPE_ITEM(item);
-        if (!sp_lpe_item_has_path_effect(lpeitem) ||
-            !sp_lpe_item_get_livepatheffect(lpeitem)->isVisible() ||
-            !sp_lpe_item_get_livepatheffect(lpeitem)->providesKnotholder()) {
+        if (!sp_lpe_item_get_current_lpe(lpeitem) ||   // if returns NULL, the whole expression evaluates to true and C++ will not call the otherwise crashing 2 functions below
+            !sp_lpe_item_get_current_lpe(lpeitem)->isVisible() ||
+            !sp_lpe_item_get_current_lpe(lpeitem)->providesKnotholder()) {
             // only create nodepath if the item either doesn't have an LPE
             // or the LPE is invisible or it doesn't provide a knotholder itself
             this->nodepath =
index acdf8aa36628914359d6e401d532b3ec0592fd3d..20efd8fe72c76e4c370d84f51eb9e015b1ab8bdb 100644 (file)
@@ -23,6 +23,7 @@
 #include <string>
 
 #include "display/nr-arena-group.h"
+#include "display/curve.h"
 #include "libnr/nr-matrix-ops.h"
 #include "libnr/nr-matrix-fns.h"
 #include "xml/repr.h"
@@ -42,6 +43,8 @@
 #include "inkscape.h"
 #include "desktop-handles.h"
 #include "selection.h"
+#include "live_effects/lpeobject.h"
+#include "live_effects/lpeobject-reference.h"
 
 static void sp_group_class_init (SPGroupClass *klass);
 static void sp_group_init (SPGroup *group);
@@ -66,6 +69,7 @@ static void sp_group_hide (SPItem * item, unsigned int key);
 static void sp_group_snappoints (SPItem const *item, SnapPointsIter p);
 
 static void sp_group_update_patheffect(SPLPEItem *lpeitem, bool write);
+static void sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup);
 
 static SPLPEItemClass * parent_class;
 
@@ -207,6 +211,9 @@ sp_group_update (SPObject *object, SPCtx *ctx, unsigned int flags)
 static void
 sp_group_modified (SPObject *object, guint flags)
 {
+    if (((SPObjectClass *) (parent_class))->modified)
+        ((SPObjectClass *) (parent_class))->modified (object, flags);
+
     SP_GROUP(object)->group->onModified(flags);
 }
 
@@ -364,7 +371,7 @@ sp_item_group_ungroup (SPGroup *group, GSList **children, bool do_done)
             gitem = SP_ITEM(group);
         }
 
-        sp_lpe_item_remove_path_effect(SP_LPE_ITEM(group), false);
+        sp_lpe_item_remove_all_path_effects(SP_LPE_ITEM(group), false);
 
        /* Step 1 - generate lists of children objects */
        GSList *items = NULL;
@@ -802,7 +809,7 @@ void CGroup::onOrderChanged (Inkscape::XML::Node *child, Inkscape::XML::Node *,
 }
 
 static void
-sp_group_update_patheffect (SPLPEItem *lpeitem, bool /*write*/)
+sp_group_update_patheffect (SPLPEItem *lpeitem, bool write)
 {
 #ifdef GROUP_VERBOSE
     g_message("sp_group_update_patheffect: %p\n", lpeitem);
@@ -814,11 +821,51 @@ sp_group_update_patheffect (SPLPEItem *lpeitem, bool /*write*/)
     for ( GSList const *iter = item_list; iter; iter = iter->next ) {
         SPObject *subitem = static_cast<SPObject *>(iter->data);
         if (SP_IS_LPE_ITEM(subitem)) {
-            sp_lpe_item_update_patheffect(SP_LPE_ITEM(subitem), true);
+            if (SP_LPE_ITEM_CLASS (G_OBJECT_GET_CLASS (subitem))->update_patheffect) {
+                SP_LPE_ITEM_CLASS (G_OBJECT_GET_CLASS (subitem))->update_patheffect (SP_LPE_ITEM(subitem), write);
+            }
+        }
+    }
+    
+    if (sp_lpe_item_has_path_effect(lpeitem) && sp_lpe_item_path_effects_enabled(lpeitem)) {
+        for (PathEffectList::iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); it++)
+        {
+            LivePathEffectObject *lpeobj = (*it)->lpeobject;
+            lpeobj->lpe->doBeforeEffect(lpeitem);
         }
+        
+        sp_group_perform_patheffect(SP_GROUP(lpeitem), SP_GROUP(lpeitem));
     }
 }
 
+static void
+sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup)
+{
+    GSList const *item_list = sp_item_group_item_list(SP_GROUP(group));
+    for ( GSList const *iter = item_list; iter; iter = iter->next ) {
+        SPObject *subitem = static_cast<SPObject *>(iter->data);
+        if (SP_IS_GROUP(subitem)) {
+            sp_group_perform_patheffect(SP_GROUP(subitem), topgroup);
+        } else if (SP_IS_SHAPE(subitem)) {
+            SPCurve * c = sp_shape_get_curve(SP_SHAPE(subitem));
+            sp_lpe_item_perform_path_effect(SP_LPE_ITEM(topgroup), c);
+            sp_shape_set_curve(SP_SHAPE(subitem), c, TRUE);
+            
+            Inkscape::XML::Node *repr = SP_OBJECT_REPR(subitem);
+                NArtBpath *abp = c->first_bpath();
+                if (abp) {
+                    gchar *str = sp_svg_write_path(abp);
+                    repr->setAttribute("d", str);
+                    g_free(str);
+                } else {
+                   repr->setAttribute("d", "");
+                }
+
+                c->unref();
+        }
+    }
+}
 
 /*
   Local Variables:
index 0ab8566eb9479e369760d50616807107da370c23..be6be4f63895e3decb6e28799070726c8dce2b84 100644 (file)
@@ -71,6 +71,7 @@
 
 #include "live_effects/lpeobject.h"
 #include "live_effects/effect.h"
+#include "live_effects/lpeobject-reference.h"
 
 #define noSP_ITEM_DEBUG_IDLE
 
@@ -1296,15 +1297,21 @@ sp_item_adjust_livepatheffect (SPItem *item, NR::Matrix const &postmul, bool set
 
     SPLPEItem *lpeitem = SP_LPE_ITEM (item);
     if ( sp_lpe_item_has_path_effect(lpeitem) ) {
-        LivePathEffectObject *lpeobj = sp_lpe_item_get_livepatheffectobject(lpeitem);
-        LivePathEffectObject *new_lpeobj = lpeobj->fork_private_if_necessary();
-        if (new_lpeobj != lpeobj) {
-            sp_lpe_item_set_path_effect(lpeitem, new_lpeobj);
-        }
-
-        Inkscape::LivePathEffect::Effect * effect = sp_lpe_item_get_livepatheffect(lpeitem);
-        if (effect) {
-            effect->transform_multiply (to_2geom(postmul), set);
+        PathEffectList effect_list =  sp_lpe_item_get_effect_list(lpeitem);
+        for (PathEffectList::iterator it = effect_list.begin(); it != effect_list.end(); it++)
+        {
+            // If the path effect is used by 2 or more items, fork it
+            // so that each object has its own independent copy of the effect
+            LivePathEffectObject *lpeobj = (*it)->lpeobject;
+            LivePathEffectObject *new_lpeobj = lpeobj->fork_private_if_necessary();
+            if (new_lpeobj != lpeobj) {
+                sp_lpe_item_replace_path_effect(lpeitem, lpeobj, new_lpeobj);
+            }
+        
+            if (lpeobj->lpe) {
+                Inkscape::LivePathEffect::Effect * effect = lpeobj->lpe;
+                effect->transform_multiply(to_2geom(postmul), set);
+            }
         }
     }
 }
index f16b455ddf33fe3d8c1a4efb283aa5bef57e853b..12473f770d5848601e55cdf55d1ab7a2f37deb26 100644 (file)
@@ -30,6 +30,8 @@
 #include "xml/repr.h"
 #include "uri.h"
 
+#include <algorithm>
+
 /* LPEItem base class */
 
 static void sp_lpe_item_class_init(SPLPEItemClass *klass);
@@ -46,11 +48,16 @@ static Inkscape::XML::Node *sp_lpe_item_write(SPObject *object, Inkscape::XML::N
 static void sp_lpe_item_child_added (SPObject * object, Inkscape::XML::Node * child, Inkscape::XML::Node * ref);
 static void sp_lpe_item_remove_child (SPObject * object, Inkscape::XML::Node * child);
 
+static void sp_lpe_item_enable_path_effects(SPLPEItem *lpeitem, bool enable);
+
 static void lpeobject_ref_changed(SPObject *old_ref, SPObject *ref, SPLPEItem *lpeitem);
 static void lpeobject_ref_modified(SPObject *href, guint flags, SPLPEItem *lpeitem);
 
 static void sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem);
 static void sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem);
+typedef std::list<std::string> HRefList;
+static std::string patheffectlist_write_svg(PathEffectList const & list);
+static std::string hreflist_write_svg(HRefList const & list);
 
 static SPItemClass *parent_class;
 
@@ -77,7 +84,7 @@ sp_lpe_item_get_type()
 
 static void
 sp_lpe_item_class_init(SPLPEItemClass *klass)
-{    
+{
     GObjectClass *gobject_class;
     SPObjectClass *sp_object_class;
 
@@ -95,14 +102,18 @@ sp_lpe_item_class_init(SPLPEItemClass *klass)
     sp_object_class->write = sp_lpe_item_write;
     sp_object_class->child_added = sp_lpe_item_child_added;
     sp_object_class->remove_child = sp_lpe_item_remove_child;
-    
+
     klass->update_patheffect = NULL;
 }
 
 static void
 sp_lpe_item_init(SPLPEItem *lpeitem)
 {
-    lpeitem->path_effect_ref  = new Inkscape::LivePathEffect::LPEObjectReference(SP_OBJECT(lpeitem));
+    lpeitem->path_effects_enabled = 1;
+
+    lpeitem->path_effect_list = new PathEffectList();
+    lpeitem->current_path_effect = NULL;
+
     new (&lpeitem->lpe_modified_connection) sigc::connection();
 }
 
@@ -112,6 +123,8 @@ sp_lpe_item_finalize(GObject *object)
     if (((GObjectClass *) (parent_class))->finalize) {
         (* ((GObjectClass *) (parent_class))->finalize)(object);
     }
+
+    delete SP_LPE_ITEM(object)->path_effect_list;
 }
 
 /**
@@ -122,10 +135,8 @@ sp_lpe_item_finalize(GObject *object)
 static void
 sp_lpe_item_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
 {
-    SP_LPE_ITEM(object)->path_effect_ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(lpeobject_ref_changed), SP_LPE_ITEM(object)));
-
     sp_object_read_attr(object, "inkscape:path-effect");
-    
+
     if (((SPObjectClass *) parent_class)->build) {
         ((SPObjectClass *) parent_class)->build(object, document, repr);
     }
@@ -140,8 +151,6 @@ sp_lpe_item_release(SPObject *object)
     SPLPEItem *lpeitem;
     lpeitem = (SPLPEItem *) object;
 
-    lpeitem->path_effect_ref->detach();
-
     lpeitem->lpe_modified_connection.disconnect();
     lpeitem->lpe_modified_connection.~connection();
 
@@ -159,22 +168,48 @@ sp_lpe_item_set(SPObject *object, unsigned int key, gchar const *value)
 
     switch (key) {
         case SP_ATTR_INKSCAPE_PATH_EFFECT:
-            if ( value && lpeitem->path_effect_ref->lpeobject_href 
-                 && streq(value, lpeitem->path_effect_ref->lpeobject_href) ) {
-                /* No change, do nothing. */
-            } else {
-                if (value) {
-                    // Now do the attaching, which emits the changed signal.
-                    try {
-                        lpeitem->path_effect_ref->link((gchar*)value);
-                    } catch (Inkscape::BadURIException &e) {
-                        g_warning("%s", e.what());
-                        lpeitem->path_effect_ref->detach();
+            {
+                lpeitem->current_path_effect = NULL;
+
+                // Disable the path effects while populating the LPE list
+                 sp_lpe_item_enable_path_effects(lpeitem, false);
+
+                // Clear the path effect list
+                PathEffectList::iterator it = lpeitem->path_effect_list->begin();
+                while ( it != lpeitem->path_effect_list->end() )
+                {
+                    (*it)->unlink();
+                    delete *it;
+                    it = lpeitem->path_effect_list->erase(it);
+                }
+
+                // Parse the contents of "value" to rebuild the path effect reference list
+                if ( value ) {
+                    std::istringstream iss(value);
+                    std::string href;
+                    while (std::getline(iss, href, ';'))
+                    {
+                        Inkscape::LivePathEffect::LPEObjectReference *path_effect_ref;
+                        path_effect_ref = new Inkscape::LivePathEffect::LPEObjectReference(SP_OBJECT(lpeitem));
+                        path_effect_ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(lpeobject_ref_changed), SP_LPE_ITEM(object)));
+                        // Now do the attaching, which emits the changed signal.
+                        // Fixme, it should not do this changed signal and updating before all effects are added to the path_effect_list
+                        try {
+                            path_effect_ref->link(href.c_str());
+                        } catch (Inkscape::BadURIException &e) {
+                            g_warning("BadURIException: %s", e.what());
+                            path_effect_ref->unlink();
+                            delete path_effect_ref;
+                            path_effect_ref = NULL;
+                        }
+
+                        if (path_effect_ref) {
+                            lpeitem->path_effect_list->push_back(path_effect_ref);
+                        }
                     }
-                } else {
-                    // Detach, which emits the changed signal.
-                    lpeitem->path_effect_ref->detach();
                 }
+
+                sp_lpe_item_enable_path_effects(lpeitem, true);
             }
             break;
         default:
@@ -202,9 +237,14 @@ sp_lpe_item_update(SPObject *object, SPCtx *ctx, guint flags)
 static void
 sp_lpe_item_modified (SPObject *object, unsigned int flags)
 {
-       if (((SPObjectClass *) (parent_class))->modified) {
-         (* ((SPObjectClass *) (parent_class))->modified) (object, flags);
-       }
+
+    if (SP_IS_GROUP(object) && (flags & SP_OBJECT_MODIFIED_FLAG) && (flags & SP_OBJECT_USER_MODIFIED_FLAG_B)) {
+        sp_lpe_item_update_patheffect(SP_LPE_ITEM(object), true, true);
+    }
+
+    if (((SPObjectClass *) (parent_class))->modified) {
+        (* ((SPObjectClass *) (parent_class))->modified) (object, flags);
+    }
 }
 
 /**
@@ -216,7 +256,8 @@ sp_lpe_item_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
     SPLPEItem *lpeitem = (SPLPEItem *) object;
 
     if ( sp_lpe_item_has_path_effect(lpeitem) ) {
-        repr->setAttribute("inkscape:path-effect", lpeitem->path_effect_ref->lpeobject_href);
+        std::string href = patheffectlist_write_svg(*lpeitem->path_effect_list);
+        repr->setAttribute("inkscape:path-effect", href.c_str());
     } else {
         repr->setAttribute("inkscape:path-effect", NULL);
     }
@@ -228,51 +269,32 @@ sp_lpe_item_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
     return repr;
 }
 
-
-LivePathEffectObject *
-sp_lpe_item_get_livepatheffectobject(SPLPEItem *lpeitem) {
-    if (!lpeitem) return NULL;
-
-    if (sp_lpe_item_has_path_effect(lpeitem)) {
-        return lpeitem->path_effect_ref->lpeobject;
-    } else {
-        return NULL;
-    }
-}
-
-Inkscape::LivePathEffect::Effect *
-sp_lpe_item_get_livepatheffect(SPLPEItem *lpeitem) {
-    if (!lpeitem) return NULL;
-
-    LivePathEffectObject * lpeobj = sp_lpe_item_get_livepatheffectobject(lpeitem);
-    if (lpeobj)
-        return lpeobj->lpe;
-    else
-        return NULL;
-}
-
 void sp_lpe_item_perform_path_effect(SPLPEItem *lpeitem, SPCurve *curve) {
     if (!lpeitem) return;
     if (!curve) return;
 
-    if (sp_lpe_item_has_path_effect(lpeitem)) {
-        LivePathEffectObject *lpeobj = sp_lpe_item_get_livepatheffectobject(lpeitem);
-        if (lpeobj->lpe->isVisible()) {
-            lpeobj->lpe->doBeforeEffect(lpeitem);
-            lpeobj->lpe->doEffect(curve);
+    if (sp_lpe_item_has_path_effect(lpeitem) && sp_lpe_item_path_effects_enabled(lpeitem)) {
+        for (PathEffectList::iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); ++it)
+        {
+            LivePathEffectObject *lpeobj = (*it)->lpeobject;
+
+            if (lpeobj->lpe->isVisible()) {
+                // Groups have their doBeforeEffect called elsewhere
+                if (!SP_IS_GROUP(lpeitem)) {
+                    lpeobj->lpe->doBeforeEffect(lpeitem);
+                }
+
+                lpeobj->lpe->doEffect(curve);
+            }
         }
     }
-
-    SPObject *parent = lpeitem->parent;
-    if (parent && SP_IS_LPE_ITEM(parent))
-        sp_lpe_item_perform_path_effect(SP_LPE_ITEM(parent), curve);
 }
 
 /**
  * Calls any registered handlers for the update_patheffect action
  */
 void
-sp_lpe_item_update_patheffect (SPLPEItem *lpeitem, bool write)
+sp_lpe_item_update_patheffect (SPLPEItem *lpeitem, bool wholetree, bool write)
 {
 #ifdef SHAPE_VERBOSE
     g_message("sp_lpe_item_update_patheffect: %p\n", lpeitem);
@@ -280,8 +302,23 @@ sp_lpe_item_update_patheffect (SPLPEItem *lpeitem, bool write)
     g_return_if_fail (lpeitem != NULL);
     g_return_if_fail (SP_IS_LPE_ITEM (lpeitem));
 
-    if (SP_LPE_ITEM_CLASS (G_OBJECT_GET_CLASS (lpeitem))->update_patheffect) {
-        SP_LPE_ITEM_CLASS (G_OBJECT_GET_CLASS (lpeitem))->update_patheffect (lpeitem, write);
+    SPLPEItem *top;
+
+    if (wholetree) {
+        SPObject *prev_parent = lpeitem;
+        SPObject *parent = prev_parent->parent;
+        while (parent && SP_IS_LPE_ITEM(parent) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(parent))) {
+            prev_parent = parent;
+            parent = prev_parent->parent;
+        }
+        top = SP_LPE_ITEM(prev_parent);
+    }
+    else {
+        top = lpeitem;
+    }
+
+    if (SP_LPE_ITEM_CLASS (G_OBJECT_GET_CLASS (top))->update_patheffect) {
+        SP_LPE_ITEM_CLASS (G_OBJECT_GET_CLASS (top))->update_patheffect (top, write);
     }
 }
 
@@ -308,7 +345,7 @@ lpeobject_ref_changed(SPObject *old_ref, SPObject *ref, SPLPEItem *lpeitem)
 static void
 lpeobject_ref_modified(SPObject */*href*/, guint /*flags*/, SPLPEItem *lpeitem)
 {
-    sp_lpe_item_update_patheffect (lpeitem, true);
+    sp_lpe_item_update_patheffect (lpeitem, true, true);
 }
 
 static void
@@ -345,63 +382,137 @@ sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem)
     }
     else if (SP_IS_PATH(lpeitem)) {
         Inkscape::XML::Node *repr = SP_OBJECT_REPR(lpeitem);
-        if (!sp_lpe_item_has_path_effect_recursive(lpeitem) 
+        if (!sp_lpe_item_has_path_effect_recursive(lpeitem)
                 && repr->attribute("inkscape:original-d")) {
             repr->setAttribute("d", repr->attribute("inkscape:original-d"));
             repr->setAttribute("inkscape:original-d", NULL);
         }
         else {
-            sp_lpe_item_update_patheffect(lpeitem, true);
+            sp_lpe_item_update_patheffect(lpeitem, true, true);
         }
     }
 }
 
-void sp_lpe_item_set_path_effect(SPLPEItem *lpeitem, gchar *value, bool reset)
+void sp_lpe_item_add_path_effect(SPLPEItem *lpeitem, gchar *value, bool reset)
 {
-    if (!value) {
-        sp_lpe_item_remove_path_effect(lpeitem, false);
-    } else {
-        SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", value);
-        
-        // Ask the path effect to reset itself if it doesn't have parameters yet
-        if (lpeitem->path_effect_ref) {
-            LivePathEffectObject *lpeobj = lpeitem->path_effect_ref->lpeobject;
-            if (lpeobj && lpeobj->lpe) {
-                if(reset) {
-                    // has to be called when all the subitems have their lpes applied
-                    lpeobj->lpe->resetDefaults(lpeitem);
-                }
-                // perform this once when the effect is applied
-               lpeobj->lpe->doOnApply(SP_LPE_ITEM(lpeitem));
-            }
+    if (value) {
+        // Apply the path effects here because in the casse of a group, lpe->resetDefaults
+        // needs that all the subitems have their effects applied
+        sp_lpe_item_update_patheffect(lpeitem, false, true);
+
+        // Disable the path effects while preparing the new lpe
+        sp_lpe_item_enable_path_effects(lpeitem, false);
+
+        // Add the new reference to the list of LPE references
+        HRefList hreflist;
+        for (PathEffectList::const_iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); ++it)
+        {
+            hreflist.push_back( std::string((*it)->lpeobject_href) );
         }
-        
+        hreflist.push_back( std::string(value) );
+        std::string hrefs = hreflist_write_svg(hreflist);
+
+        SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", hrefs.c_str());
+
         // make sure there is an original-d for paths!!!
         sp_lpe_item_create_original_path_recursive(lpeitem);
+
+        LivePathEffectObject *lpeobj = lpeitem->path_effect_list->back()->lpeobject;
+        if (lpeobj && lpeobj->lpe) {
+            // Ask the path effect to reset itself if it doesn't have parameters yet
+            if (reset) {
+                // has to be called when all the subitems have their lpes applied
+                lpeobj->lpe->resetDefaults(lpeitem);
+            }
+        }
+
+        //Enable the path effects now that everything is ready to apply the new path effect
+        sp_lpe_item_enable_path_effects(lpeitem, true);
+
+        // Apply the path effect
+        sp_lpe_item_update_patheffect(lpeitem, true, true);
     }
 }
 
-void sp_lpe_item_set_path_effect(SPLPEItem *lpeitem, LivePathEffectObject * new_lpeobj)
+void sp_lpe_item_add_path_effect(SPLPEItem *lpeitem, LivePathEffectObject * new_lpeobj)
 {
     const gchar * repr_id = SP_OBJECT_REPR(new_lpeobj)->attribute("id");
     gchar *hrefstr = g_strdup_printf("#%s", repr_id);
-    sp_lpe_item_set_path_effect(lpeitem, hrefstr, false);
+    sp_lpe_item_add_path_effect(lpeitem, hrefstr, false);
     g_free(hrefstr);
 }
 
-void sp_lpe_item_remove_path_effect(SPLPEItem *lpeitem, bool keep_paths)
+void sp_lpe_item_remove_current_path_effect(SPLPEItem *lpeitem, bool keep_paths)
 {
-    Inkscape::XML::Node *repr = SP_OBJECT_REPR(lpeitem);
-    repr->setAttribute("inkscape:path-effect", NULL);
-    
+    Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem);
+    if (!lperef)
+        return;
+
+    PathEffectList new_list = *lpeitem->path_effect_list;
+    new_list.remove(lperef); //current lpe ref is always our 'own' pointer from the path_effect_list
+    std::string r = patheffectlist_write_svg(new_list);
+
+    SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str());
+
     if (!keep_paths) {
         sp_lpe_item_cleanup_original_path_recursive(lpeitem);
     }
 }
 
+void sp_lpe_item_remove_all_path_effects(SPLPEItem *lpeitem, bool keep_paths)
+{
+    SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", NULL);
+
+    if (!keep_paths) {
+        sp_lpe_item_cleanup_original_path_recursive(lpeitem);
+    }
+}
+
+void sp_lpe_item_down_current_path_effect(SPLPEItem *lpeitem)
+{
+    Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem);
+    if (!lperef)
+        return;
+
+    PathEffectList new_list = *lpeitem->path_effect_list;
+    PathEffectList::iterator cur_it = find( new_list.begin(), new_list.end(), lperef );
+    if (cur_it != new_list.end()) {
+        PathEffectList::iterator down_it = cur_it;
+        down_it++;
+        if (down_it != new_list.end()) { // perhaps current effect is already last effect
+            std::iter_swap(cur_it, down_it);
+        }
+    }
+    std::string r = patheffectlist_write_svg(new_list);
+    SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str());
+
+    sp_lpe_item_cleanup_original_path_recursive(lpeitem);
+}
+
+void sp_lpe_item_up_current_path_effect(SPLPEItem *lpeitem)
+{
+    Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem);
+    if (!lperef)
+        return;
+
+    PathEffectList new_list = *lpeitem->path_effect_list;
+    PathEffectList::iterator cur_it = find( new_list.begin(), new_list.end(), lperef );
+    if (cur_it != new_list.end() && cur_it != new_list.begin()) {
+        PathEffectList::iterator up_it = cur_it;
+        up_it--;
+        std::iter_swap(cur_it, up_it);
+    }
+    std::string r = patheffectlist_write_svg(new_list);
+
+    SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str());
+
+    sp_lpe_item_cleanup_original_path_recursive(lpeitem);
+}
+
+
 bool sp_lpe_item_has_path_effect(SPLPEItem *lpeitem)
 {
-    return lpeitem->path_effect_ref && lpeitem->path_effect_ref->lpeobject;
+    return !lpeitem->path_effect_list->empty();
 }
 
 bool sp_lpe_item_has_path_effect_recursive(SPLPEItem *lpeitem)
@@ -417,9 +528,9 @@ bool sp_lpe_item_has_path_effect_recursive(SPLPEItem *lpeitem)
 
 void sp_lpe_item_edit_next_param_oncanvas(SPLPEItem *lpeitem, SPDesktop *dt)
 {
-    LivePathEffectObject *lpeobj = sp_lpe_item_get_livepatheffectobject(lpeitem);
-    if (lpeobj && lpeobj->lpe) {
-        lpeobj->lpe->editNextParamOncanvas(SP_ITEM(lpeitem), dt);
+    Inkscape::LivePathEffect::LPEObjectReference *lperef = sp_lpe_item_get_current_lpereference(lpeitem);
+    if (lperef && lperef->lpeobject && lperef->lpeobject->lpe) {
+        lperef->lpeobject->lpe->editNextParamOncanvas(SP_ITEM(lpeitem), dt);
     }
 }
 
@@ -428,7 +539,7 @@ sp_lpe_item_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape:
 {
     if (((SPObjectClass *) (parent_class))->child_added)
         (* ((SPObjectClass *) (parent_class))->child_added) (object, child, ref);
-        
+
     if (SP_IS_LPE_ITEM(object) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(object))) {
         SPObject *ochild = sp_object_get_child_by_repr(object, child);
         if ( ochild && SP_IS_LPE_ITEM(ochild) ) {
@@ -451,6 +562,114 @@ sp_lpe_item_remove_child (SPObject * object, Inkscape::XML::Node * child)
         (* ((SPObjectClass *) (parent_class))->remove_child) (object, child);
 }
 
+static std::string patheffectlist_write_svg(PathEffectList const & list)
+{
+    HRefList hreflist;
+    for (PathEffectList::const_iterator it = list.begin(); it != list.end(); ++it)
+    {
+        hreflist.push_back( std::string((*it)->lpeobject_href) );
+    }
+    return hreflist_write_svg(hreflist);
+}
+
+/**
+ *  THE function that should be used to generate any patheffectlist string.
+ * one of the methods to change the effect list:
+ *  - create temporary href list
+ *  - populate the templist with the effects from the old list that you want to have and their order
+ *  - call this function with temp list as param
+ */
+static std::string hreflist_write_svg(HRefList const & list)
+{
+    std::string r;
+    bool semicolon_first = false;
+    for (HRefList::const_iterator it = list.begin(); it != list.end(); ++it)
+    {
+        if (semicolon_first) {
+            r += ';';
+        }
+        semicolon_first = true;
+
+        r += (*it);
+    }
+    return r;
+}
+
+// Return a copy of the effect list
+PathEffectList sp_lpe_item_get_effect_list(SPLPEItem *lpeitem)
+{
+    return *lpeitem->path_effect_list;
+}
+
+Inkscape::LivePathEffect::LPEObjectReference* sp_lpe_item_get_current_lpereference(SPLPEItem *lpeitem)
+{
+    if (!lpeitem->current_path_effect && !lpeitem->path_effect_list->empty())
+        sp_lpe_item_set_current_path_effect(lpeitem, lpeitem->path_effect_list->back());
+
+    return lpeitem->current_path_effect;
+}
+
+Inkscape::LivePathEffect::Effect* sp_lpe_item_get_current_lpe(SPLPEItem *lpeitem)
+{
+    Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem);
+
+    if (lperef && lperef->lpeobject)
+        return lperef->lpeobject->lpe;
+    else
+        return NULL;
+}
+
+bool sp_lpe_item_set_current_path_effect(SPLPEItem *lpeitem, Inkscape::LivePathEffect::LPEObjectReference* lperef)
+{
+    for (PathEffectList::iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); it++) {
+        if ((*it)->lpeobject_repr == lperef->lpeobject_repr) {
+            lpeobject_ref_changed(NULL, (*it)->lpeobject, SP_LPE_ITEM(lpeitem)); // FIXME: explain why this is here?
+            lpeitem->current_path_effect = (*it);  // current_path_effect should always be a pointer from the path_effect_list !
+            return true;
+        }
+    }
+
+    return false;
+}
+
+void sp_lpe_item_replace_path_effect(SPLPEItem *lpeitem, LivePathEffectObject * old_lpeobj,
+                                        LivePathEffectObject * new_lpeobj)
+{
+    HRefList hreflist;
+    for (PathEffectList::const_iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); ++it)
+    {
+        if ((*it)->lpeobject == old_lpeobj) {
+            const gchar * repr_id = SP_OBJECT_REPR(new_lpeobj)->attribute("id");
+            gchar *hrefstr = g_strdup_printf("#%s", repr_id);
+            hreflist.push_back( std::string(hrefstr) );
+            g_free(hrefstr);
+        }
+        else {
+            hreflist.push_back( std::string((*it)->lpeobject_href) );
+        }
+    }
+    std::string r = hreflist_write_svg(hreflist);
+    SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str());
+}
+
+// Enable or disable the path effects of the item.
+// The counter allows nested calls
+static void sp_lpe_item_enable_path_effects(SPLPEItem *lpeitem, bool enable)
+{
+    if (enable) {
+        lpeitem->path_effects_enabled++;
+    }
+    else {
+        lpeitem->path_effects_enabled--;
+    }
+}
+
+// Are the path effects enabled on this item ?
+bool sp_lpe_item_path_effects_enabled(SPLPEItem *lpeitem)
+{
+    return lpeitem->path_effects_enabled > 0;
+}
+
 /*
   Local Variables:
   mode:c++
index 7d85bb2be854a934ccfea298a8b8cbc6c9c58995..3aba7b8a7a4aa16de87c5ae5a16e8c7e709bb819 100644 (file)
@@ -17,6 +17,8 @@
 #include "sp-item.h"
 #include "display/display-forward.h"
 
+#include <list>
+
 #define SP_TYPE_LPE_ITEM (sp_lpe_item_get_type())
 #define SP_LPE_ITEM(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_LPE_ITEM, SPLPEItem))
 #define SP_LPE_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_LPE_ITEM, SPLPEItemClass))
@@ -31,8 +33,14 @@ namespace LivePathEffect{
 };
 };
 
+typedef std::list<Inkscape::LivePathEffect::LPEObjectReference *> PathEffectList;
+
 struct SPLPEItem : public SPItem {
-    Inkscape::LivePathEffect::LPEObjectReference *path_effect_ref;
+    int path_effects_enabled;
+
+    PathEffectList* path_effect_list;
+    Inkscape::LivePathEffect::LPEObjectReference* current_path_effect;
+
     sigc::connection lpe_modified_connection;
 };
 
@@ -44,16 +52,24 @@ struct SPLPEItemClass {
 
 GType sp_lpe_item_get_type();
 
-LivePathEffectObject * sp_lpe_item_get_livepatheffectobject(SPLPEItem *lpeitem);
-Inkscape::LivePathEffect::Effect * sp_lpe_item_get_livepatheffect(SPLPEItem *lpeitem);
-void sp_lpe_item_update_patheffect (SPLPEItem *lpeitem, bool write);
+void sp_lpe_item_update_patheffect (SPLPEItem *lpeitem, bool wholetree, bool write);
 void sp_lpe_item_perform_path_effect(SPLPEItem *lpeitem, SPCurve *curve);
-void sp_lpe_item_set_path_effect(SPLPEItem *lpeitem, gchar *value, bool reset);
-void sp_lpe_item_set_path_effect(SPLPEItem *lpeitem, LivePathEffectObject * new_lpeobj);
-void sp_lpe_item_remove_path_effect(SPLPEItem *lpeitem, bool keep_paths);
+void sp_lpe_item_add_path_effect(SPLPEItem *lpeitem, gchar *value, bool reset);
+void sp_lpe_item_add_path_effect(SPLPEItem *lpeitem, LivePathEffectObject * new_lpeobj);
+void sp_lpe_item_replace_path_effect(SPLPEItem *lpeitem, LivePathEffectObject * old_lpeobj,
+                                        LivePathEffectObject * new_lpeobj);
+void sp_lpe_item_remove_all_path_effects(SPLPEItem *lpeitem, bool keep_paths);
+void sp_lpe_item_remove_current_path_effect(SPLPEItem *lpeitem, bool keep_paths);
+void sp_lpe_item_down_current_path_effect(SPLPEItem *lpeitem);
+void sp_lpe_item_up_current_path_effect(SPLPEItem *lpeitem);
 bool sp_lpe_item_has_path_effect(SPLPEItem *lpeitem);
 bool sp_lpe_item_has_path_effect_recursive(SPLPEItem *lpeitem);
 void sp_lpe_item_edit_next_param_oncanvas(SPLPEItem *lpeitem, SPDesktop *dt);
+PathEffectList sp_lpe_item_get_effect_list(SPLPEItem *lpeitem);
+Inkscape::LivePathEffect::LPEObjectReference* sp_lpe_item_get_current_lpereference(SPLPEItem *lpeitem);
+Inkscape::LivePathEffect::Effect* sp_lpe_item_get_current_lpe(SPLPEItem *lpeitem);
+bool sp_lpe_item_set_current_path_effect(SPLPEItem *lpeitem, Inkscape::LivePathEffect::LPEObjectReference* lperef);
+bool sp_lpe_item_path_effects_enabled(SPLPEItem *lpeitem);
 
 #endif /* !SP_LPE_ITEM_H_SEEN */
 
index 4654b1b131645bcc78902b33b7588730347813d4..b2e26efa03a91e7b36fad69b85acb3643d195b8f 100644 (file)
@@ -464,7 +464,7 @@ sp_path_set_original_curve (SPPath *path, SPCurve *curve, unsigned int owner, bo
             path->original_curve = curve->copy();
         }
     }
-    sp_path_update_patheffect(path, write);
+    sp_lpe_item_update_patheffect(path, true, write);
     SP_OBJECT(path)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
 }
 
index fff6e3b097af9cf9cff0008b5fcea2ea61355b6d..2d38f5ccd227909ed44b289618749aa962f99972 100644 (file)
@@ -61,6 +61,7 @@
 #include "sp-textpath.h"
 #include "sp-rect.h"
 #include "live_effects/lpeobject.h"
+#include "live_effects/lpeobject-reference.h"
 #include "live_effects/parameter/path.h"
 #include "svg/svg.h" // for sp_svg_transform_write, used in _copySelection
 #include "svg/css-ostringstream.h" // used in _parseColor
@@ -560,10 +561,14 @@ void ClipboardManagerImpl::_copyUsedDefs(SPItem *item)
         }
     }
     // For lpe items, copy liveeffect if applicable
+    // TODO: copy the whole effect stack. now it only copies current selected effect
     if (SP_IS_LPE_ITEM(item)) {
         SPLPEItem *lpeitem = SP_LPE_ITEM (item);
         if (sp_lpe_item_has_path_effect(lpeitem)) {
-            _copyNode(SP_OBJECT_REPR(SP_OBJECT(sp_lpe_item_get_livepatheffectobject(lpeitem))), _doc, _defs);
+            Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem);
+            if (lperef && lperef->lpeobject) {
+                _copyNode(SP_OBJECT_REPR(SP_OBJECT(lperef->lpeobject)), _doc, _defs);
+            }
         }
     }
     // For 3D boxes, copy perspectives
@@ -900,7 +905,7 @@ void ClipboardManagerImpl::_applyPathEffect(SPItem *item, gchar const *effect)
         if (!obj) return;
         // if the effect is not used by anyone, we might as well take it
         LivePathEffectObject *lpeobj = LIVEPATHEFFECT(obj)->fork_private_if_necessary(1);
-        sp_lpe_item_set_path_effect(lpeitem, lpeobj);
+        sp_lpe_item_add_path_effect(lpeitem, lpeobj);
     }
 }
 
index 43cdb726cd002078a636861f99e1b78c799cb321..c92d015f53f1e67e41b7e66c3a942405ca00557c 100644 (file)
@@ -23,6 +23,7 @@
 #include "sp-item-group.h"
 #include "sp-path.h"
 #include "sp-rect.h"
+#include "sp-lpe-item.h"
 #include "path-chemistry.h"
 #include "live_effects/effect.h"
 #include "live_effects/lpeobject.h"
 #include "document-private.h"
 #include "xml/node.h"
 #include "xml/document.h"
+#include <gtkmm/stock.h>
+#include <gtkmm/toolbar.h>
+
+#include "live_effects/lpeobject-reference.h"
 
 namespace Inkscape {
 class Application;
@@ -59,38 +64,88 @@ static void lpeeditor_selection_changed (Inkscape::Selection * selection, gpoint
 LivePathEffectEditor::LivePathEffectEditor() 
     : UI::Widget::Panel("", "dialogs.livepatheffect", SP_VERB_DIALOG_LIVE_PATH_EFFECT),
       combo_effecttype(Inkscape::LivePathEffect::LPETypeConverter),
-      button_apply(_("_Apply"), _("Apply chosen effect to selection")),
-      button_remove(_("_Remove"), _("Remove effect from selection")),
       effectwidget(NULL),
       explain_label("", Gtk::ALIGN_CENTER),
       effectapplication_frame(_("Apply new effect")),
       effectcontrol_frame(_("Current effect")),
-      current_desktop(NULL)
+      effectlist_frame(_("Effect list")),
+      button_up(Gtk::Stock::GO_UP),
+      button_down(Gtk::Stock::GO_DOWN),
+      button_apply(Gtk::Stock::ADD),
+      button_remove(Gtk::Stock::REMOVE),
+      current_desktop(NULL),
+      current_lpeitem(NULL)
 {
     Gtk::Box *contents = _getContents();
     contents->set_spacing(4);
 
+    //Add the TreeView, inside a ScrolledWindow, with the button underneath:
+    scrolled_window.add(effectlist_view);
+    //Only show the scrollbars when they are necessary:
+    scrolled_window.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
+
     effectapplication_hbox.set_spacing(4);
     effectcontrol_vbox.set_spacing(4);
+    effectlist_vbox.set_spacing(4);
 
     effectapplication_hbox.pack_start(combo_effecttype, true, true);
     effectapplication_hbox.pack_start(button_apply, true, true);
     effectapplication_frame.add(effectapplication_hbox);
 
+    effectlist_vbox.pack_start(scrolled_window, Gtk::PACK_EXPAND_WIDGET);
+    effectlist_vbox.pack_end(toolbar, Gtk::PACK_SHRINK);
+   // effectlist_vbox.pack_end(button_hbox, Gtk::PACK_SHRINK);
+    effectlist_frame.add(effectlist_vbox);
+
     effectcontrol_vbox.pack_start(explain_label, true, true);
-    effectcontrol_vbox.pack_end(button_remove, true, true);
     effectcontrol_frame.add(effectcontrol_vbox);
 
+ //   button_hbox.pack_start(button_up, true, true);
+ //   button_hbox.pack_start(button_down, true, true);
+ //   button_hbox.pack_end(button_remove, true, true);
+       toolbar.set_toolbar_style(Gtk::TOOLBAR_ICONS);  
+ // Add toolbar items to toolbar
+  toolbar.append(button_up);
+  toolbar.append(button_down);
+  toolbar.append(button_remove);
+
+  
+  // Add toolbar
+  //add_toolbar(toolbar);
+  toolbar.show_all(); //Show the toolbar and all its child widgets.
+
+      
+    //Create the Tree model:
+    effectlist_store = Gtk::ListStore::create(columns);
+    effectlist_view.set_model(effectlist_store);
+
+    effectlist_view.set_rules_hint();
+    effectlist_view.set_headers_clickable(true);
+    effectlist_view.set_headers_visible(true);
+
+    // Handle tree selections
+    effectlist_selection = effectlist_view.get_selection();
+    effectlist_selection->signal_changed().connect( sigc::mem_fun(*this, &LivePathEffectEditor::on_effect_selection_changed) );
+
+    effectlist_view.set_headers_visible(false);
+    //Add the TreeView's view columns:
+    effectlist_view.append_column("Effect", columns.col_name);
+
+
     contents->pack_start(effectapplication_frame, false, false);
+    contents->pack_start(effectlist_frame, true, true);
     contents->pack_start(effectcontrol_frame, false, false);
 
     // connect callback functions to buttons
     button_apply.signal_clicked().connect(sigc::mem_fun(*this, &LivePathEffectEditor::onApply));
     button_remove.signal_clicked().connect(sigc::mem_fun(*this, &LivePathEffectEditor::onRemove));
 
+    button_up.signal_clicked().connect(sigc::mem_fun(*this, &LivePathEffectEditor::onUp));
+    button_down.signal_clicked().connect(sigc::mem_fun(*this, &LivePathEffectEditor::onDown));
+
     show_all_children();
 
-    button_remove.hide();
+    //button_remove.hide();
 }
 
 LivePathEffectEditor::~LivePathEffectEditor() 
@@ -136,7 +191,7 @@ LivePathEffectEditor::showText(Glib::ustring const &str)
     }
 
     explain_label.set_label(str);
-    button_remove.hide();
+    //button_remove.hide();
 
     // fixme: do resizing of dialog ?
 }
@@ -147,21 +202,33 @@ LivePathEffectEditor::set_sensitize_all(bool sensitive)
     combo_effecttype.set_sensitive(sensitive);
     button_apply.set_sensitive(sensitive);
     button_remove.set_sensitive(sensitive);
+    effectlist_view.set_sensitive(sensitive);
+    button_up.set_sensitive(sensitive);
+    button_down.set_sensitive(sensitive);
 }
 
+
 void
 LivePathEffectEditor::onSelectionChanged(Inkscape::Selection *sel)
 {
+    effectlist_store->clear();
+    current_lpeitem = NULL;
+
     if ( sel && !sel->isEmpty() ) {
         SPItem *item = sel->singleItem();
         if ( item ) {
             if ( SP_IS_LPE_ITEM(item) ) {
                 SPLPEItem *lpeitem = SP_LPE_ITEM(item);
-                LivePathEffectObject *lpeobj = sp_lpe_item_get_livepatheffectobject(lpeitem);
+
+                effect_list_update(lpeitem);
+
+                current_lpeitem = lpeitem;
+                
                 set_sensitize_all(true);
-                if (lpeobj) {
-                    if (lpeobj->lpe) {
-                        showParams(lpeobj->lpe);
+                if ( sp_lpe_item_has_path_effect(lpeitem) ) {
+                    Inkscape::LivePathEffect::Effect *lpe = sp_lpe_item_get_current_lpe(lpeitem);
+                    if (lpe) {
+                        showParams(lpe);
                     } else {
                         showText(_("Unknown effect is applied"));
                     }
@@ -185,6 +252,22 @@ LivePathEffectEditor::onSelectionChanged(Inkscape::Selection *sel)
     }
 }
 
+void
+LivePathEffectEditor::effect_list_update(SPLPEItem *lpeitem)
+{
+    effectlist_store->clear();
+    
+    PathEffectList effectlist = sp_lpe_item_get_effect_list(lpeitem);
+    PathEffectList::iterator it;
+    for( it = effectlist.begin() ; it!=effectlist.end(); it++ )
+    {
+         Gtk::TreeModel::Row row = *(effectlist_store->append());
+         row[columns.col_name] = (*it)->lpeobject->lpe->getName();
+         row[columns.lperef] = *it;
+    }
+}
+
+
 void 
 LivePathEffectEditor::setDesktop(SPDesktop *desktop)
 {
@@ -247,7 +330,7 @@ LivePathEffectEditor::onApply()
             Inkscape::GC::release(repr);
 
             gchar *href = g_strdup_printf("#%s", repr_id);
-            sp_lpe_item_set_path_effect(SP_LPE_ITEM(item), href, true);
+            sp_lpe_item_add_path_effect(SP_LPE_ITEM(item), href, true);
             g_free(href);
 
             sp_document_done(doc, SP_VERB_DIALOG_LIVE_PATH_EFFECT, 
@@ -265,15 +348,67 @@ LivePathEffectEditor::onRemove()
     if ( sel && !sel->isEmpty() ) {
         SPItem *item = sel->singleItem();
         if ( item && SP_IS_LPE_ITEM(item) ) {
-            sp_lpe_item_remove_path_effect(SP_LPE_ITEM(item), false);
-            showText(_("No effect applied"));
-            button_remove.set_sensitive(false);
+            sp_lpe_item_remove_current_path_effect(SP_LPE_ITEM(item), false);
+            
+            sp_document_done ( sp_desktop_document (current_desktop), SP_VERB_DIALOG_LIVE_PATH_EFFECT, 
+                               _("Remove path effect") );
+
+            effect_list_update(SP_LPE_ITEM(item));
+        }
+    }
+}
+
+void LivePathEffectEditor::onUp()
+{
+       Inkscape::Selection *sel = _getSelection();
+    if ( sel && !sel->isEmpty() ) {
+        SPItem *item = sel->singleItem();
+        if ( item && SP_IS_LPE_ITEM(item) ) {
+            
+                       sp_lpe_item_up_current_path_effect(SP_LPE_ITEM(item));
+            
+            sp_document_done ( sp_desktop_document (current_desktop), SP_VERB_DIALOG_LIVE_PATH_EFFECT, 
+                               _("Remove path effect") );
+
+            effect_list_update(SP_LPE_ITEM(item));
+        }
+    }
+       
+}
+
+void LivePathEffectEditor::onDown()
+{
+       Inkscape::Selection *sel = _getSelection();
+    if ( sel && !sel->isEmpty() ) {
+        SPItem *item = sel->singleItem();
+        if ( item && SP_IS_LPE_ITEM(item) ) {
+            
+                       sp_lpe_item_down_current_path_effect(SP_LPE_ITEM(item));
+            
             sp_document_done ( sp_desktop_document (current_desktop), SP_VERB_DIALOG_LIVE_PATH_EFFECT, 
                                _("Remove path effect") );
+
+            effect_list_update(SP_LPE_ITEM(item));
         }
     }
 }
 
+void LivePathEffectEditor::on_effect_selection_changed()
+{
+    Glib::RefPtr<Gtk::TreeSelection> sel = effectlist_view.get_selection();
+    if (sel->count_selected_rows () == 0)
+        return;
+
+    Gtk::TreeModel::iterator it = sel->get_selected();
+    LivePathEffect::LPEObjectReference * lperef = (*it)[columns.lperef];
+
+    if (lperef && current_lpeitem) {
+        sp_lpe_item_set_current_path_effect(current_lpeitem, lperef);
+        showParams(lperef->lpeobject->lpe);
+    }
+}
+
+
 } // namespace Dialog
 } // namespace UI
 } // namespace Inkscape
index dc96fc313761230f75efc9eba01d5eb9b2d4ed6b..e2c7da3220bc6bb2421dcc38ea6bc68245e1cfaa 100644 (file)
 #include <gtkmm/tooltips.h>
 #include "ui/widget/combo-enums.h"
 #include "live_effects/effect.h"
+#include "live_effects/lpeobject-reference.h"
+#include <gtkmm/liststore.h>
+#include <gtkmm/treeview.h>
+#include <gtkmm/scrolledwindow.h>
+#include <gtkmm/buttonbox.h>
+#include <gtkmm/toolbar.h>
+
 
 class SPDesktop;
 
@@ -37,6 +44,7 @@ public:
     static LivePathEffectEditor &getInstance() { return *new LivePathEffectEditor(); }
 
     void onSelectionChanged(Inkscape::Selection *sel);
+    virtual void on_effect_selection_changed();
     void setDesktop(SPDesktop *desktop);
 
 private:
@@ -47,22 +55,60 @@ private:
     void showParams(LivePathEffect::Effect* effect);
     void showText(Glib::ustring const &str);
 
+   // void add_entry(const char* name );
+    void effect_list_update(SPLPEItem *lpeitem);
+
     // callback methods for buttons on grids page.
     void onApply();
     void onRemove();
 
+    void onUp();
+    void onDown();
+
+    class ModelColumns : public Gtk::TreeModel::ColumnRecord
+    {
+         public:
+         ModelColumns()
+         {
+            add(col_name);
+            add(lperef);
+         }
+
+         Gtk::TreeModelColumn<Glib::ustring> col_name;
+         Gtk::TreeModelColumn<LivePathEffect::LPEObjectReference *> lperef;
+     };
+
     Inkscape::UI::Widget::ComboBoxEnum<LivePathEffect::EffectType> combo_effecttype;
-    Inkscape::UI::Widget::Button button_apply;
-    Inkscape::UI::Widget::Button button_remove;
+    
     Gtk::Widget * effectwidget;
     Gtk::Label explain_label;
     Gtk::Frame effectapplication_frame;
     Gtk::Frame effectcontrol_frame;
+    Gtk::Frame effectlist_frame;
     Gtk::HBox effectapplication_hbox;
     Gtk::VBox effectcontrol_vbox;
+    Gtk::VBox effectlist_vbox;
     Gtk::Tooltips tooltips;
+    ModelColumns columns;
+    Gtk::ScrolledWindow scrolled_window;
+    Gtk::TreeView effectlist_view;
+    Glib::RefPtr<Gtk::ListStore> effectlist_store;
+    Glib::RefPtr<Gtk::TreeSelection> effectlist_selection;
+    
+    Gtk::Toolbar toolbar;
+    Gtk::ToolButton button_up;
+    Gtk::ToolButton button_down;
+    Gtk::Button button_apply;
+    Gtk::ToolButton button_remove;
+    /*Gtk::HButtonBox button_hbox;
+    Gtk::Button        button_up;
+    Gtk::Button        button_down;
+    Gtk::Button button_apply;
+    Gtk::Button button_remove;*/
 
     SPDesktop * current_desktop;
+    
+    SPLPEItem * current_lpeitem;
 
     LivePathEffectEditor(LivePathEffectEditor const &d);
     LivePathEffectEditor& operator=(LivePathEffectEditor const &d);