Code

Merging from trunk
[inkscape.git] / src / live_effects / effect.cpp
1 #define INKSCAPE_LIVEPATHEFFECT_CPP
3 /*
4  * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
5  *
6  * Released under GNU GPL, read the file 'COPYING' for more information
7  */
9 #include "live_effects/effect.h"
11 #include "xml/node-event-vector.h"
12 #include "sp-object.h"
13 #include "attributes.h"
14 #include "message-stack.h"
15 #include "desktop.h"
16 #include "inkscape.h"
17 #include "document.h"
18 #include "document-private.h"
19 #include "xml/document.h"
20 #include <glibmm/i18n.h>
21 #include "pen-context.h"
22 #include "tools-switch.h"
23 #include "message-stack.h"
24 #include "desktop.h"
25 #include "nodepath.h"
27 #include "live_effects/lpeobject.h"
28 #include "live_effects/parameter/parameter.h"
29 #include <glibmm/ustring.h>
30 #include "display/curve.h"
31 #include <gtkmm.h>
33 #include <exception>
35 #include <2geom/sbasis-to-bezier.h>
36 #include <2geom/matrix.h>
37 #include <2geom/pathvector.h>
39 // include effects:
40 #include "live_effects/lpe-patternalongpath.h"
41 #include "live_effects/lpe-bendpath.h"
42 #include "live_effects/lpe-sketch.h"
43 #include "live_effects/lpe-vonkoch.h"
44 #include "live_effects/lpe-knot.h"
45 #include "live_effects/lpe-test-doEffect-stack.h"
46 #include "live_effects/lpe-gears.h"
47 #include "live_effects/lpe-curvestitch.h"
48 #include "live_effects/lpe-circle_with_radius.h"
49 #include "live_effects/lpe-perspective_path.h"
50 #include "live_effects/lpe-spiro.h"
51 #include "live_effects/lpe-lattice.h"
52 #include "live_effects/lpe-envelope.h"
53 #include "live_effects/lpe-constructgrid.h"
54 #include "live_effects/lpe-perp_bisector.h"
55 #include "live_effects/lpe-tangent_to_curve.h"
56 #include "live_effects/lpe-mirror_symmetry.h"
57 #include "live_effects/lpe-circle_3pts.h"
58 #include "live_effects/lpe-angle_bisector.h"
59 #include "live_effects/lpe-parallel.h"
60 #include "live_effects/lpe-copy_rotate.h"
61 #include "live_effects/lpe-offset.h"
62 #include "live_effects/lpe-ruler.h"
63 #include "live_effects/lpe-boolops.h"
64 #include "live_effects/lpe-interpolate.h"
65 #include "live_effects/lpe-text_label.h"
66 #include "live_effects/lpe-path_length.h"
67 #include "live_effects/lpe-line_segment.h"
68 // end of includes
70 namespace Inkscape {
72 namespace LivePathEffect {
74 const Util::EnumData<EffectType> LPETypeData[] = {
75     // {constant defined in effect.h, N_("name of your effect"), "name of your effect in SVG"}
76     {ANGLE_BISECTOR,        N_("Angle bisector"),          "angle_bisector"},
77     {BEND_PATH,             N_("Bend"),                     "bend_path"},
78     {BOOLOPS,               N_("Boolops"),                 "boolops"},
79     {CIRCLE_WITH_RADIUS,    N_("Circle (by center and radius)"),   "circle_with_radius"},
80     {CIRCLE_3PTS,           N_("Circle by 3 points"), "circle_3pts"},
81     {CONSTRUCT_GRID,        N_("Construct grid"),          "construct_grid"},
82 #ifdef LPE_ENABLE_TEST_EFFECTS
83     {DOEFFECTSTACK_TEST,    N_("doEffect stack test"),     "doeffectstacktest"},
84 #endif
85     {ENVELOPE,              N_("Envelope Deformation"),    "envelope"},
86     {FREEHAND_SHAPE,        N_("Freehand Shape"),          "freehand_shape"}, // this is actually a special type of PatternAlongPath, used to paste shapes in pen/pencil tool
87     {GEARS,                 N_("Gears"),                   "gears"},
88     {INTERPOLATE,           N_("Interpolate Sub-Paths"),   "interpolate"},
89     {KNOT,                  N_("Knot"),                    "knot"},
90     {LATTICE,               N_("Lattice Deformation"),     "lattice"},
91     {LINE_SEGMENT,          N_("Line Segment"),            "line_segment"},
92     {MIRROR_SYMMETRY,       N_("Mirror symmetry"),         "mirror_symmetry"},
93     {OFFSET,                N_("Offset"),                  "offset"},
94     {PARALLEL,              N_("Parallel"),                "parallel"},
95     {PATH_LENGTH,           N_("Path length"),             "path_length"},
96     {PATTERN_ALONG_PATH,    N_("Pattern Along Path"),      "skeletal"},   // for historic reasons, this effect is called skeletal(strokes) in Inkscape:SVG
97     {PERP_BISECTOR,         N_("Perpendicular bisector"),  "perp_bisector"},
98     {PERSPECTIVE_PATH,      N_("Perspective path"),        "perspective_path"},
99     {COPY_ROTATE,           N_("Rotate copies"),           "copy_rotate"},
100     {RULER,                 N_("Ruler"),                   "ruler"},
101     {SKETCH,                N_("Sketch"),                  "sketch"},
102     {SPIRO,                 N_("Spiro spline"),            "spiro"},
103     {CURVE_STITCH,          N_("Stitch Sub-Paths"),        "curvestitching"},
104     {TANGENT_TO_CURVE,      N_("Tangent to curve"),        "tangent_to_curve"},
105     {TEXT_LABEL,            N_("Text label"),              "text_label"},
106     {VONKOCH,               N_("VonKoch"),                 "vonkoch"},
107 };
108 const Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData));
110 int
111 Effect::acceptsNumClicks(EffectType type) {
112     switch (type) {
113         case INVALID_LPE: return -1; // in case we want to distinguish between invalid LPE and valid ones that expect zero clicks
114         case ANGLE_BISECTOR: return 3;
115         case CIRCLE_3PTS: return 3;
116         case CIRCLE_WITH_RADIUS: return 2;
117         case LINE_SEGMENT: return 2;
118         case PERP_BISECTOR: return 2;
119         default: return 0;
120     }
123 Effect*
124 Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj)
126     Effect* neweffect = NULL;
127     switch (lpenr) {
128         case PATTERN_ALONG_PATH:
129             neweffect = static_cast<Effect*> ( new LPEPatternAlongPath(lpeobj) );
130             break;
131         case FREEHAND_SHAPE:
132             neweffect = static_cast<Effect*> ( new LPEFreehandShape(lpeobj) );
133             break;
134         case BEND_PATH:
135             neweffect = static_cast<Effect*> ( new LPEBendPath(lpeobj) );
136             break;
137         case SKETCH:
138             neweffect = static_cast<Effect*> ( new LPESketch(lpeobj) );
139             break;
140         case VONKOCH:
141             neweffect = static_cast<Effect*> ( new LPEVonKoch(lpeobj) );
142             break;
143         case KNOT:
144             neweffect = static_cast<Effect*> ( new LPEKnot(lpeobj) );
145             break;
146 #ifdef LPE_ENABLE_TEST_EFFECTS
147         case DOEFFECTSTACK_TEST:
148             neweffect = static_cast<Effect*> ( new LPEdoEffectStackTest(lpeobj) );
149             break;
150 #endif
151         case GEARS:
152             neweffect = static_cast<Effect*> ( new LPEGears(lpeobj) );
153             break;
154         case CURVE_STITCH:
155             neweffect = static_cast<Effect*> ( new LPECurveStitch(lpeobj) );
156             break;
157         case LATTICE:
158             neweffect = static_cast<Effect*> ( new LPELattice(lpeobj) );
159             break;
160         case ENVELOPE:
161             neweffect = static_cast<Effect*> ( new LPEEnvelope(lpeobj) );
162             break;
163         case CIRCLE_WITH_RADIUS:
164             neweffect = static_cast<Effect*> ( new LPECircleWithRadius(lpeobj) );
165             break;
166         case PERSPECTIVE_PATH:
167             neweffect = static_cast<Effect*> ( new LPEPerspectivePath(lpeobj) );
168             break;
169         case SPIRO:
170             neweffect = static_cast<Effect*> ( new LPESpiro(lpeobj) );
171             break;
172         case CONSTRUCT_GRID:
173             neweffect = static_cast<Effect*> ( new LPEConstructGrid(lpeobj) );
174             break;
175         case PERP_BISECTOR:
176             neweffect = static_cast<Effect*> ( new LPEPerpBisector(lpeobj) );
177             break;
178         case TANGENT_TO_CURVE:
179             neweffect = static_cast<Effect*> ( new LPETangentToCurve(lpeobj) );
180             break;
181         case MIRROR_SYMMETRY:
182             neweffect = static_cast<Effect*> ( new LPEMirrorSymmetry(lpeobj) );
183             break;
184         case CIRCLE_3PTS:
185             neweffect = static_cast<Effect*> ( new LPECircle3Pts(lpeobj) );
186             break;
187         case ANGLE_BISECTOR:
188             neweffect = static_cast<Effect*> ( new LPEAngleBisector(lpeobj) );
189             break;
190         case PARALLEL:
191             neweffect = static_cast<Effect*> ( new LPEParallel(lpeobj) );
192             break;
193         case COPY_ROTATE:
194             neweffect = static_cast<Effect*> ( new LPECopyRotate(lpeobj) );
195             break;
196         case OFFSET:
197             neweffect = static_cast<Effect*> ( new LPEOffset(lpeobj) );
198             break;
199         case RULER:
200             neweffect = static_cast<Effect*> ( new LPERuler(lpeobj) );
201             break;
202         case BOOLOPS:
203             neweffect = static_cast<Effect*> ( new LPEBoolops(lpeobj) );
204             break;
205         case INTERPOLATE:
206             neweffect = static_cast<Effect*> ( new LPEInterpolate(lpeobj) );
207             break;
208         case TEXT_LABEL:
209             neweffect = static_cast<Effect*> ( new LPETextLabel(lpeobj) );
210             break;
211         case PATH_LENGTH:
212             neweffect = static_cast<Effect*> ( new LPEPathLength(lpeobj) );
213             break;
214         case LINE_SEGMENT:
215             neweffect = static_cast<Effect*> ( new LPELineSegment(lpeobj) );
216             break;
217         default:
218             g_warning("LivePathEffect::Effect::New   called with invalid patheffect type (%d)", lpenr);
219             neweffect = NULL;
220             break;
221     }
223     if (neweffect) {
224         neweffect->readallParameters(SP_OBJECT_REPR(lpeobj));
225     }
227     return neweffect;
230 void
231 Effect::createAndApply(const char* name, SPDocument *doc, SPItem *item)
233     // Path effect definition
234     Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
235     Inkscape::XML::Node *repr = xml_doc->createElement("inkscape:path-effect");
236     repr->setAttribute("effect", name);
238     SP_OBJECT_REPR(SP_DOCUMENT_DEFS(doc))->addChild(repr, NULL); // adds to <defs> and assigns the 'id' attribute
239     const gchar * repr_id = repr->attribute("id");
240     Inkscape::GC::release(repr);
242     gchar *href = g_strdup_printf("#%s", repr_id);
243     sp_lpe_item_add_path_effect(SP_LPE_ITEM(item), href, true);
244     g_free(href);
247 void
248 Effect::createAndApply(EffectType type, SPDocument *doc, SPItem *item)
250     createAndApply(LPETypeConverter.get_key(type).c_str(), doc, item);
253 Effect::Effect(LivePathEffectObject *lpeobject)
254     : oncanvasedit_it(0),
255       is_visible(_("Is visible?"), _("If unchecked, the effect remains applied to the object but is temporarily disabled on canvas"), "is_visible", &wr, this, true),
256       deactivate_knotholder(_("Deactivate knotholder?"), _("Check this to deactivate knotholder handles (useful if they interfere with node handles during editing)"), "deactivate_knotholder", &wr, this, false),
257       show_orig_path(false),
258       lpeobj(lpeobject),
259       concatenate_before_pwd2(false),
260       provides_own_flash_paths(true), // is automatically set to false if providesOwnFlashPaths() is not overridden
261       is_ready(false) // is automatically set to false if providesOwnFlashPaths() is not overridden
263     registerParameter( dynamic_cast<Parameter *>(&is_visible) );
264     registerParameter( dynamic_cast<Parameter *>(&deactivate_knotholder) );
267 Effect::~Effect()
271 Glib::ustring
272 Effect::getName()
274     if (lpeobj->effecttype_set && LPETypeConverter.is_valid_id(lpeobj->effecttype) )
275         return Glib::ustring( _(LPETypeConverter.get_label(lpeobj->effecttype).c_str()) );
276     else
277         return Glib::ustring( _("No effect") );
280 EffectType
281 Effect::effectType() {
282     return lpeobj->effecttype;
285 /**
286  * Is performed a single time when the effect is freshly applied to a path
287  */
288 void
289 Effect::doOnApply (SPLPEItem */*lpeitem*/)
293 /**
294  * Is performed each time before the effect is updated.
295  */
296 void
297 Effect::doBeforeEffect (SPLPEItem */*lpeitem*/)
299     //Do nothing for simple effects
302 /**
303  * Effects can have a parameter path set before they are applied by accepting a nonzero number of
304  * mouse clicks. This method activates the pen context, which waits for the specified number of
305  * clicks. Override Effect::acceptsNumClicks() to return the number of expected mouse clicks.
306  */
307 void
308 Effect::doAcceptPathPreparations(SPLPEItem *lpeitem)
310     // switch to pen context
311     SPDesktop *desktop = inkscape_active_desktop(); // TODO: Is there a better method to find the item's desktop?
312     if (!tools_isactive(desktop, TOOLS_FREEHAND_PEN)) {
313         tools_switch(desktop, TOOLS_FREEHAND_PEN);
314     }
316     SPEventContext *ec = desktop->event_context;
317     SPPenContext *pc = SP_PEN_CONTEXT(ec);
318     pc->expecting_clicks_for_LPE = this->acceptsNumClicks();
319     pc->waiting_LPE = this;
320     pc->waiting_item = lpeitem;
321     pc->polylines_only = true;
323     ec->desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE,
324         g_strdup_printf(_("Please specify a parameter path for the LPE '%s' with %d mouse clicks"),
325                         getName().c_str(), acceptsNumClicks()));
328 void
329 Effect::writeParamsToSVG() {
330     std::vector<Inkscape::LivePathEffect::Parameter *>::iterator p;
331     for (p = param_vector.begin(); p != param_vector.end(); ++p) {
332         (*p)->write_to_SVG();
333     }
336 /**
337  * If the effect expects a path parameter (specified by a number of mouse clicks) before it is
338  * applied, this is the method that processes the resulting path. Override it to customize it for
339  * your LPE. But don't forget to call the parent method so that is_ready is set to true!
340  */
341 void
342 Effect::acceptParamPath (SPPath */*param_path*/) {
343     setReady();
346 /*
347  *  Here be the doEffect function chain:
348  */
349 void
350 Effect::doEffect (SPCurve * curve)
352     std::vector<Geom::Path> orig_pathv = curve->get_pathvector();
354     std::vector<Geom::Path> result_pathv = doEffect_path(orig_pathv);
356     curve->set_pathvector(result_pathv);
359 std::vector<Geom::Path>
360 Effect::doEffect_path (std::vector<Geom::Path> const & path_in)
362     std::vector<Geom::Path> path_out;
364     if ( !concatenate_before_pwd2 ) {
365         // default behavior
366         for (unsigned int i=0; i < path_in.size(); i++) {
367             Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in = path_in[i].toPwSb();
368             Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_out = doEffect_pwd2(pwd2_in);
369             std::vector<Geom::Path> path = Geom::path_from_piecewise( pwd2_out, LPE_CONVERSION_TOLERANCE);
370             // add the output path vector to the already accumulated vector:
371             for (unsigned int j=0; j < path.size(); j++) {
372                 path_out.push_back(path[j]);
373             }
374         }
375     } else {
376       // concatenate the path into possibly discontinuous pwd2
377         Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in;
378         for (unsigned int i=0; i < path_in.size(); i++) {
379             pwd2_in.concat( path_in[i].toPwSb() );
380         }
381         Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_out = doEffect_pwd2(pwd2_in);
382         path_out = Geom::path_from_piecewise( pwd2_out, LPE_CONVERSION_TOLERANCE);
383     }
385     return path_out;
388 Geom::Piecewise<Geom::D2<Geom::SBasis> >
389 Effect::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
391     g_warning("Effect has no doEffect implementation");
392     return pwd2_in;
395 void
396 Effect::readallParameters(Inkscape::XML::Node * repr)
398     std::vector<Parameter *>::iterator it = param_vector.begin();
399     while (it != param_vector.end()) {
400         Parameter * param = *it;
401         const gchar * key = param->param_key.c_str();
402         const gchar * value = repr->attribute(key);
403         if (value) {
404             bool accepted = param->param_readSVGValue(value);
405             if (!accepted) {
406                 g_warning("Effect::readallParameters - '%s' not accepted for %s", value, key);
407             }
408         } else {
409             // set default value
410             param->param_set_default();
411         }
413         it++;
414     }
417 /* This function does not and SHOULD NOT write to XML */
418 void
419 Effect::setParameter(const gchar * key, const gchar * new_value)
421     Parameter * param = getParameter(key);
422     if (param) {
423         if (new_value) {
424             bool accepted = param->param_readSVGValue(new_value);
425             if (!accepted) {
426                 g_warning("Effect::setParameter - '%s' not accepted for %s", new_value, key);
427             }
428         } else {
429             // set default value
430             param->param_set_default();
431         }
432     }
435 void
436 Effect::registerParameter(Parameter * param)
438     param_vector.push_back(param);
441 // TODO: should we provide a way to alter the handle's appearance?
442 void
443 Effect::registerKnotHolderHandle(KnotHolderEntity* entity, const char* descr)
445     kh_entity_vector.push_back(std::make_pair(entity, descr));
448 /**
449  * Add all registered LPE knotholder handles to the knotholder
450  */
451 void
452 Effect::addHandles(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) {
453     using namespace Inkscape::LivePathEffect;
455     if (deactivate_knotholder)
456         return;
458     // add handles provided by the effect itself
459     addKnotHolderEntities(knotholder, desktop, item);
461     // add handles provided by the effect's parameters (if any)
462     for (std::vector<Parameter *>::iterator p = param_vector.begin(); p != param_vector.end(); ++p) {
463         (*p)->addKnotHolderEntities(knotholder, desktop, item);
464     }
467 void
468 Effect::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) {
469     // TODO: The entities in kh_entity_vector are already instantiated during the call
470     //       to registerKnotHolderHandle(), but they are recreated here. Also, we must not
471     //       delete them when the knotholder is destroyed, whence the clumsy function
472     //       isDeletable(). If we could create entities of different classes dynamically,
473     //       this would be much nicer. How to do this?
474     std::vector<std::pair<KnotHolderEntity*, const char*> >::iterator i;
475     for (i = kh_entity_vector.begin(); i != kh_entity_vector.end(); ++i) {
476         KnotHolderEntity *entity = i->first;
477         const char *descr = i->second;
479         entity->create(desktop, item, knotholder, descr);
480         knotholder->add(entity);
481     }
484 /**
485  * Return a vector of PathVectors which contain all helperpaths that should be drawn by the effect.
486  * This is the function called by external code like SPLPEItem.
487  */
488 std::vector<Geom::PathVector>
489 Effect::getHelperPaths(SPLPEItem *lpeitem)
491     std::vector<Geom::PathVector> hp_vec;
493     if (!SP_IS_SHAPE(lpeitem)) {
494         g_print ("How to handle helperpaths for non-shapes?\n");
495         return hp_vec;
496     }
498     // TODO: we can probably optimize this by using a lot more references
499     //       rather than copying PathVectors all over the place
500     if (show_orig_path) {
501         // add original path to helperpaths
502         SPCurve* curve = sp_shape_get_curve (SP_SHAPE(lpeitem));
503         hp_vec.push_back(curve->get_pathvector());
504     }
506     // add other helperpaths provided by the effect itself
507     addCanvasIndicators(lpeitem, hp_vec);
509     // add helperpaths provided by the effect's parameters
510     for (std::vector<Parameter *>::iterator p = param_vector.begin(); p != param_vector.end(); ++p) {
511         (*p)->addCanvasIndicators(lpeitem, hp_vec);
512     }
514     return hp_vec;
517 /**
518  * Add possible canvas indicators (i.e., helperpaths other than the original path) to \a hp_vec
519  * This function should be overwritten by derived effects if they want to provide their own helperpaths.
520  */
521 void
522 Effect::addCanvasIndicators(SPLPEItem */*lpeitem*/, std::vector<Geom::PathVector> &/*hp_vec*/)
527 /**
528  * This *creates* a new widget, management of deletion should be done by the caller
529  */
530 Gtk::Widget *
531 Effect::newWidget(Gtk::Tooltips * tooltips)
533     // use manage here, because after deletion of Effect object, others might still be pointing to this widget.
534     Gtk::VBox * vbox = Gtk::manage( new Gtk::VBox() );
536     vbox->set_border_width(5);
538     std::vector<Parameter *>::iterator it = param_vector.begin();
539     while (it != param_vector.end()) {
540         Parameter * param = *it;
541         Gtk::Widget * widg = param->param_newWidget(tooltips);
542         Glib::ustring * tip = param->param_getTooltip();
543         if (widg) {
544            vbox->pack_start(*widg, true, true, 2);
545             if (tip != NULL) {
546                 tooltips->set_tip(*widg, *tip);
547             }
548         }
550         it++;
551     }
553     return dynamic_cast<Gtk::Widget *>(vbox);
557 Inkscape::XML::Node *
558 Effect::getRepr()
560     return SP_OBJECT_REPR(lpeobj);
563 SPDocument *
564 Effect::getSPDoc()
566     if (SP_OBJECT_DOCUMENT(lpeobj) == NULL) g_message("Effect::getSPDoc() returns NULL");
567     return SP_OBJECT_DOCUMENT(lpeobj);
570 Parameter *
571 Effect::getParameter(const char * key)
573     Glib::ustring stringkey(key);
575     std::vector<Parameter *>::iterator it = param_vector.begin();
576     while (it != param_vector.end()) {
577         Parameter * param = *it;
578         if ( param->param_key == key) {
579             return param;
580         }
582         it++;
583     }
585     return NULL;
588 Parameter *
589 Effect::getNextOncanvasEditableParam()
591     if (param_vector.size() == 0) // no parameters
592         return NULL;
594     oncanvasedit_it++;
595     if (oncanvasedit_it >= static_cast<int>(param_vector.size())) {
596         oncanvasedit_it = 0;
597     }
598     int old_it = oncanvasedit_it;
600     do {
601         Parameter * param = param_vector[oncanvasedit_it];
602         if(param && param->oncanvas_editable) {
603             return param;
604         } else {
605             oncanvasedit_it++;
606             if (oncanvasedit_it == static_cast<int>(param_vector.size())) {  // loop round the map
607                 oncanvasedit_it = 0;
608             }
609         }
610     } while (oncanvasedit_it != old_it); // iterate until complete loop through map has been made
612     return NULL;
615 void
616 Effect::editNextParamOncanvas(SPItem * item, SPDesktop * desktop)
618     if (!desktop) return;
620     Parameter * param = getNextOncanvasEditableParam();
621     if (param) {
622         param->param_editOncanvas(item, desktop);
623         gchar *message = g_strdup_printf(_("Editing parameter <b>%s</b>."), param->param_label.c_str());
624         desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, message);
625         g_free(message);
626     } else {
627         desktop->messageStack()->flash( Inkscape::WARNING_MESSAGE,
628                                         _("None of the applied path effect's parameters can be edited on-canvas.") );
629     }
632 /* This function should reset the defaults and is used for example to initialize an effect right after it has been applied to a path
633 * The nice thing about this is that this function can use knowledge of the original path and set things accordingly for example to the size or origin of the original path!
634 */
635 void
636 Effect::resetDefaults(SPItem * /*item*/)
638     // do nothing for simple effects
641 void
642 Effect::setup_nodepath(Inkscape::NodePath::Path *np)
644     np->helperpath_rgba = 0xff0000ff;
645     np->helperpath_width = 1.0;
648 void
649 Effect::transform_multiply(Geom::Matrix const& postmul, bool set)
651     // cycle through all parameters. Most parameters will not need transformation, but path and point params do.
652     for (std::vector<Parameter *>::iterator it = param_vector.begin(); it != param_vector.end(); it++) {
653         Parameter * param = *it;
654         param->param_transform_multiply(postmul, set);
655     }
658 // TODO: take _all_ parameters into account, not only PointParams
659 bool
660 Effect::providesKnotholder()
662     // does the effect actively provide any knotholder entities of its own?
663     if (kh_entity_vector.size() > 0)
664         return true;
666     // otherwise: are there any PointParams?
667     for (std::vector<Parameter *>::iterator p = param_vector.begin(); p != param_vector.end(); ++p) {
668 //        if ( Inkscape::LivePathEffect::PointParam *pointparam = dynamic_cast<Inkscape::LivePathEffect::PointParam*>(*p) ) {
669         if (dynamic_cast<Inkscape::LivePathEffect::PointParam*>(*p)) {
670             return true;
671         }
672     }
674     return false;
677 } /* namespace LivePathEffect */
679 } /* namespace Inkscape */
681 /*
682   Local Variables:
683   mode:c++
684   c-file-style:"stroustrup"
685   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
686   indent-tabs-mode:nil
687   fill-column:99
688   End:
689 */
690 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :