Code

Add option do deactivate knotholder handles for LPEs (useful if they interfere with...
[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 (center+radius)"),   "circle_with_radius"},
80     {CIRCLE_3PTS,           N_("Circle through 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 ANGLE_BISECTOR: return 3;
114         case CIRCLE_3PTS: return 3;
115         case CIRCLE_WITH_RADIUS: return 2;
116         case LINE_SEGMENT: return 2;
117         case PERP_BISECTOR: return 2;
118         default: return 0;
119     }
122 Effect*
123 Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj)
125     Effect* neweffect = NULL;
126     switch (lpenr) {
127         case PATTERN_ALONG_PATH:
128             neweffect = static_cast<Effect*> ( new LPEPatternAlongPath(lpeobj) );
129             break;
130         case FREEHAND_SHAPE:
131             neweffect = static_cast<Effect*> ( new LPEFreehandShape(lpeobj) );
132             break;
133         case BEND_PATH:
134             neweffect = static_cast<Effect*> ( new LPEBendPath(lpeobj) );
135             break;
136         case SKETCH:
137             neweffect = static_cast<Effect*> ( new LPESketch(lpeobj) );
138             break;
139         case VONKOCH:
140             neweffect = static_cast<Effect*> ( new LPEVonKoch(lpeobj) );
141             break;
142         case KNOT:
143             neweffect = static_cast<Effect*> ( new LPEKnot(lpeobj) );
144             break;
145 #ifdef LPE_ENABLE_TEST_EFFECTS
146         case DOEFFECTSTACK_TEST:
147             neweffect = static_cast<Effect*> ( new LPEdoEffectStackTest(lpeobj) );
148             break;
149 #endif
150         case GEARS:
151             neweffect = static_cast<Effect*> ( new LPEGears(lpeobj) );
152             break;
153         case CURVE_STITCH:
154             neweffect = static_cast<Effect*> ( new LPECurveStitch(lpeobj) );
155             break;
156         case LATTICE:
157             neweffect = static_cast<Effect*> ( new LPELattice(lpeobj) );
158             break;
159         case ENVELOPE:
160             neweffect = static_cast<Effect*> ( new LPEEnvelope(lpeobj) );
161             break;
162         case CIRCLE_WITH_RADIUS:
163             neweffect = static_cast<Effect*> ( new LPECircleWithRadius(lpeobj) );
164             break;
165         case PERSPECTIVE_PATH:
166             neweffect = static_cast<Effect*> ( new LPEPerspectivePath(lpeobj) );
167             break;
168         case SPIRO:
169             neweffect = static_cast<Effect*> ( new LPESpiro(lpeobj) );
170             break;
171         case CONSTRUCT_GRID:
172             neweffect = static_cast<Effect*> ( new LPEConstructGrid(lpeobj) );
173             break;
174         case PERP_BISECTOR:
175             neweffect = static_cast<Effect*> ( new LPEPerpBisector(lpeobj) );
176             break;
177         case TANGENT_TO_CURVE:
178             neweffect = static_cast<Effect*> ( new LPETangentToCurve(lpeobj) );
179             break;
180         case MIRROR_SYMMETRY:
181             neweffect = static_cast<Effect*> ( new LPEMirrorSymmetry(lpeobj) );
182             break;
183         case CIRCLE_3PTS:
184             neweffect = static_cast<Effect*> ( new LPECircle3Pts(lpeobj) );
185             break;
186         case ANGLE_BISECTOR:
187             neweffect = static_cast<Effect*> ( new LPEAngleBisector(lpeobj) );
188             break;
189         case PARALLEL:
190             neweffect = static_cast<Effect*> ( new LPEParallel(lpeobj) );
191             break;
192         case COPY_ROTATE:
193             neweffect = static_cast<Effect*> ( new LPECopyRotate(lpeobj) );
194             break;
195         case OFFSET:
196             neweffect = static_cast<Effect*> ( new LPEOffset(lpeobj) );
197             break;
198         case RULER:
199             neweffect = static_cast<Effect*> ( new LPERuler(lpeobj) );
200             break;
201         case BOOLOPS:
202             neweffect = static_cast<Effect*> ( new LPEBoolops(lpeobj) );
203             break;
204         case INTERPOLATE:
205             neweffect = static_cast<Effect*> ( new LPEInterpolate(lpeobj) );
206             break;
207         case TEXT_LABEL:
208             neweffect = static_cast<Effect*> ( new LPETextLabel(lpeobj) );
209             break;
210         case PATH_LENGTH:
211             neweffect = static_cast<Effect*> ( new LPEPathLength(lpeobj) );
212             break;
213         case LINE_SEGMENT:
214             neweffect = static_cast<Effect*> ( new LPELineSegment(lpeobj) );
215             break;
216         default:
217             g_warning("LivePathEffect::Effect::New   called with invalid patheffect type (%d)", lpenr);
218             neweffect = NULL;
219             break;
220     }
222     if (neweffect) {
223         neweffect->readallParameters(SP_OBJECT_REPR(lpeobj));
224     }
226     return neweffect;
229 void
230 Effect::createAndApply(const char* name, SPDocument *doc, SPItem *item)
232     // Path effect definition
233     Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
234     Inkscape::XML::Node *repr = xml_doc->createElement("inkscape:path-effect");
235     repr->setAttribute("effect", name);
237     SP_OBJECT_REPR(SP_DOCUMENT_DEFS(doc))->addChild(repr, NULL); // adds to <defs> and assigns the 'id' attribute
238     const gchar * repr_id = repr->attribute("id");
239     Inkscape::GC::release(repr);
241     gchar *href = g_strdup_printf("#%s", repr_id);
242     sp_lpe_item_add_path_effect(SP_LPE_ITEM(item), href, true);
243     g_free(href);
246 void
247 Effect::createAndApply(EffectType type, SPDocument *doc, SPItem *item)
249     createAndApply(LPETypeConverter.get_key(type).c_str(), doc, item);
252 Effect::Effect(LivePathEffectObject *lpeobject)
253     : oncanvasedit_it(0),
254       is_visible(_("Is visible?"), _("If unchecked, the effect remains applied to the object but is temporarily disabled on canvas"), "is_visible", &wr, this, true),
255       deactivate_knotholder(_("Deactivate knotholder?"), _("Check this to deactivate knotholder handles (useful if they interfere with node handles during editing)"), "deactivate_knotholder", &wr, this, false),
256       show_orig_path(false),
257       lpeobj(lpeobject),
258       concatenate_before_pwd2(false),
259       provides_own_flash_paths(true), // is automatically set to false if providesOwnFlashPaths() is not overridden
260       is_ready(false) // is automatically set to false if providesOwnFlashPaths() is not overridden
262     registerParameter( dynamic_cast<Parameter *>(&is_visible) );
263     registerParameter( dynamic_cast<Parameter *>(&deactivate_knotholder) );
266 Effect::~Effect()
270 Glib::ustring
271 Effect::getName()
273     if (lpeobj->effecttype_set && LPETypeConverter.is_valid_id(lpeobj->effecttype) )
274         return Glib::ustring( _(LPETypeConverter.get_label(lpeobj->effecttype).c_str()) );
275     else
276         return Glib::ustring( _("No effect") );
279 EffectType
280 Effect::effectType() {
281     return lpeobj->effecttype;
284 /**
285  * Is performed a single time when the effect is freshly applied to a path
286  */
287 void
288 Effect::doOnApply (SPLPEItem */*lpeitem*/)
292 /**
293  * Is performed each time before the effect is updated.
294  */
295 void
296 Effect::doBeforeEffect (SPLPEItem */*lpeitem*/)
298     //Do nothing for simple effects
301 /**
302  * Effects can have a parameter path set before they are applied by accepting a nonzero number of
303  * mouse clicks. This method activates the pen context, which waits for the specified number of
304  * clicks. Override Effect::acceptsNumClicks() to return the number of expected mouse clicks.
305  */
306 void
307 Effect::doAcceptPathPreparations(SPLPEItem *lpeitem)
309     // switch to pen context
310     SPDesktop *desktop = inkscape_active_desktop(); // TODO: Is there a better method to find the item's desktop?
311     if (!tools_isactive(desktop, TOOLS_FREEHAND_PEN)) {
312         tools_switch(desktop, TOOLS_FREEHAND_PEN);
313     }
315     SPEventContext *ec = desktop->event_context;
316     SPPenContext *pc = SP_PEN_CONTEXT(ec);
317     pc->expecting_clicks_for_LPE = this->acceptsNumClicks();
318     pc->waiting_LPE = this;
319     pc->waiting_item = lpeitem;
320     pc->polylines_only = true;
322     ec->desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE,
323         g_strdup_printf(_("Please specify a parameter path for the LPE '%s' with %d mouse clicks"),
324                         getName().c_str(), acceptsNumClicks()));
327 void
328 Effect::writeParamsToSVG() {
329     std::vector<Inkscape::LivePathEffect::Parameter *>::iterator p;
330     for (p = param_vector.begin(); p != param_vector.end(); ++p) {
331         (*p)->write_to_SVG();
332     }
335 /**
336  * If the effect expects a path parameter (specified by a number of mouse clicks) before it is
337  * applied, this is the method that processes the resulting path. Override it to customize it for
338  * your LPE. But don't forget to call the parent method so that is_ready is set to true!
339  */
340 void
341 Effect::acceptParamPath (SPPath */*param_path*/) {
342     setReady();
345 /*
346  *  Here be the doEffect function chain:
347  */
348 void
349 Effect::doEffect (SPCurve * curve)
351     std::vector<Geom::Path> orig_pathv = curve->get_pathvector();
353     std::vector<Geom::Path> result_pathv = doEffect_path(orig_pathv);
355     curve->set_pathvector(result_pathv);
358 std::vector<Geom::Path>
359 Effect::doEffect_path (std::vector<Geom::Path> const & path_in)
361     std::vector<Geom::Path> path_out;
363     if ( !concatenate_before_pwd2 ) {
364         // default behavior
365         for (unsigned int i=0; i < path_in.size(); i++) {
366             Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in = path_in[i].toPwSb();
367             Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_out = doEffect_pwd2(pwd2_in);
368             std::vector<Geom::Path> path = Geom::path_from_piecewise( pwd2_out, LPE_CONVERSION_TOLERANCE);
369             // add the output path vector to the already accumulated vector:
370             for (unsigned int j=0; j < path.size(); j++) {
371                 path_out.push_back(path[j]);
372             }
373         }
374     } else {
375       // concatenate the path into possibly discontinuous pwd2
376         Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in;
377         for (unsigned int i=0; i < path_in.size(); i++) {
378             pwd2_in.concat( path_in[i].toPwSb() );
379         }
380         Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_out = doEffect_pwd2(pwd2_in);
381         path_out = Geom::path_from_piecewise( pwd2_out, LPE_CONVERSION_TOLERANCE);
382     }
384     return path_out;
387 Geom::Piecewise<Geom::D2<Geom::SBasis> >
388 Effect::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
390     g_warning("Effect has no doEffect implementation");
391     return pwd2_in;
394 void
395 Effect::readallParameters(Inkscape::XML::Node * repr)
397     std::vector<Parameter *>::iterator it = param_vector.begin();
398     while (it != param_vector.end()) {
399         Parameter * param = *it;
400         const gchar * key = param->param_key.c_str();
401         const gchar * value = repr->attribute(key);
402         if (value) {
403             bool accepted = param->param_readSVGValue(value);
404             if (!accepted) {
405                 g_warning("Effect::readallParameters - '%s' not accepted for %s", value, key);
406             }
407         } else {
408             // set default value
409             param->param_set_default();
410         }
412         it++;
413     }
416 /* This function does not and SHOULD NOT write to XML */
417 void
418 Effect::setParameter(const gchar * key, const gchar * new_value)
420     Parameter * param = getParameter(key);
421     if (param) {
422         if (new_value) {
423             bool accepted = param->param_readSVGValue(new_value);
424             if (!accepted) {
425                 g_warning("Effect::setParameter - '%s' not accepted for %s", new_value, key);
426             }
427         } else {
428             // set default value
429             param->param_set_default();
430         }
431     }
434 void
435 Effect::registerParameter(Parameter * param)
437     param_vector.push_back(param);
440 // TODO: should we provide a way to alter the handle's appearance?
441 void
442 Effect::registerKnotHolderHandle(KnotHolderEntity* entity, const char* descr)
444     kh_entity_vector.push_back(std::make_pair(entity, descr));
447 /**
448  * Add all registered LPE knotholder handles to the knotholder
449  */
450 void
451 Effect::addHandles(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) {
452     using namespace Inkscape::LivePathEffect;
454     if (deactivate_knotholder)
455         return;
457     // add handles provided by the effect itself
458     addKnotHolderEntities(knotholder, desktop, item);
460     // add handles provided by the effect's parameters (if any)
461     for (std::vector<Parameter *>::iterator p = param_vector.begin(); p != param_vector.end(); ++p) {
462         (*p)->addKnotHolderEntities(knotholder, desktop, item);
463     }
466 void
467 Effect::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) {
468     // TODO: The entities in kh_entity_vector are already instantiated during the call
469     //       to registerKnotHolderHandle(), but they are recreated here. Also, we must not
470     //       delete them when the knotholder is destroyed, whence the clumsy function
471     //       isDeletable(). If we could create entities of different classes dynamically,
472     //       this would be much nicer. How to do this?
473     std::vector<std::pair<KnotHolderEntity*, const char*> >::iterator i;
474     for (i = kh_entity_vector.begin(); i != kh_entity_vector.end(); ++i) {
475         KnotHolderEntity *entity = i->first;
476         const char *descr = i->second;
478         entity->create(desktop, item, knotholder, descr);
479         knotholder->add(entity);
480     }
483 /**
484  * Return a vector of PathVectors which contain all helperpaths that should be drawn by the effect.
485  * This is the function called by external code like SPLPEItem.
486  */
487 std::vector<Geom::PathVector>
488 Effect::getHelperPaths(SPLPEItem *lpeitem)
490     std::vector<Geom::PathVector> hp_vec;
492     if (!SP_IS_SHAPE(lpeitem)) {
493         g_print ("How to handle helperpaths for non-shapes?\n");
494         return hp_vec;
495     }
497     // TODO: we can probably optimize this by using a lot more references
498     //       rather than copying PathVectors all over the place
499     if (show_orig_path) {
500         // add original path to helperpaths
501         SPCurve* curve = sp_shape_get_curve (SP_SHAPE(lpeitem));
502         hp_vec.push_back(curve->get_pathvector());
503     }
505     // add other helperpaths provided by the effect itself
506     addCanvasIndicators(lpeitem, hp_vec);
508     // add helperpaths provided by the effect's parameters
509     for (std::vector<Parameter *>::iterator p = param_vector.begin(); p != param_vector.end(); ++p) {
510         (*p)->addCanvasIndicators(lpeitem, hp_vec);
511     }
513     return hp_vec;
516 /**
517  * Add possible canvas indicators (i.e., helperpaths other than the original path) to \a hp_vec
518  * This function should be overwritten by derived effects if they want to provide their own helperpaths.
519  */
520 void
521 Effect::addCanvasIndicators(SPLPEItem */*lpeitem*/, std::vector<Geom::PathVector> &/*hp_vec*/)
526 /**
527  * This *creates* a new widget, management of deletion should be done by the caller
528  */
529 Gtk::Widget *
530 Effect::newWidget(Gtk::Tooltips * tooltips)
532     // use manage here, because after deletion of Effect object, others might still be pointing to this widget.
533     Gtk::VBox * vbox = Gtk::manage( new Gtk::VBox() );
535     vbox->set_border_width(5);
537     std::vector<Parameter *>::iterator it = param_vector.begin();
538     while (it != param_vector.end()) {
539         Parameter * param = *it;
540         Gtk::Widget * widg = param->param_newWidget(tooltips);
541         Glib::ustring * tip = param->param_getTooltip();
542         if (widg) {
543            vbox->pack_start(*widg, true, true, 2);
544             if (tip != NULL) {
545                 tooltips->set_tip(*widg, *tip);
546             }
547         }
549         it++;
550     }
552     return dynamic_cast<Gtk::Widget *>(vbox);
556 Inkscape::XML::Node *
557 Effect::getRepr()
559     return SP_OBJECT_REPR(lpeobj);
562 SPDocument *
563 Effect::getSPDoc()
565     if (SP_OBJECT_DOCUMENT(lpeobj) == NULL) g_message("Effect::getSPDoc() returns NULL");
566     return SP_OBJECT_DOCUMENT(lpeobj);
569 Parameter *
570 Effect::getParameter(const char * key)
572     Glib::ustring stringkey(key);
574     std::vector<Parameter *>::iterator it = param_vector.begin();
575     while (it != param_vector.end()) {
576         Parameter * param = *it;
577         if ( param->param_key == key) {
578             return param;
579         }
581         it++;
582     }
584     return NULL;
587 Parameter *
588 Effect::getNextOncanvasEditableParam()
590     if (param_vector.size() == 0) // no parameters
591         return NULL;
593     oncanvasedit_it++;
594     if (oncanvasedit_it >= static_cast<int>(param_vector.size())) {
595         oncanvasedit_it = 0;
596     }
597     int old_it = oncanvasedit_it;
599     do {
600         Parameter * param = param_vector[oncanvasedit_it];
601         if(param && param->oncanvas_editable) {
602             return param;
603         } else {
604             oncanvasedit_it++;
605             if (oncanvasedit_it == static_cast<int>(param_vector.size())) {  // loop round the map
606                 oncanvasedit_it = 0;
607             }
608         }
609     } while (oncanvasedit_it != old_it); // iterate until complete loop through map has been made
611     return NULL;
614 void
615 Effect::editNextParamOncanvas(SPItem * item, SPDesktop * desktop)
617     if (!desktop) return;
619     Parameter * param = getNextOncanvasEditableParam();
620     if (param) {
621         param->param_editOncanvas(item, desktop);
622         gchar *message = g_strdup_printf(_("Editing parameter <b>%s</b>."), param->param_label.c_str());
623         desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, message);
624         g_free(message);
625     } else {
626         desktop->messageStack()->flash( Inkscape::WARNING_MESSAGE,
627                                         _("None of the applied path effect's parameters can be edited on-canvas.") );
628     }
631 /* This function should reset the defaults and is used for example to initialize an effect right after it has been applied to a path
632 * 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!
633 */
634 void
635 Effect::resetDefaults(SPItem * /*item*/)
637     // do nothing for simple effects
640 void
641 Effect::setup_nodepath(Inkscape::NodePath::Path *np)
643     np->helperpath_rgba = 0xff0000ff;
644     np->helperpath_width = 1.0;
647 void
648 Effect::transform_multiply(Geom::Matrix const& postmul, bool set)
650     // cycle through all parameters. Most parameters will not need transformation, but path and point params do.
651     for (std::vector<Parameter *>::iterator it = param_vector.begin(); it != param_vector.end(); it++) {
652         Parameter * param = *it;
653         param->param_transform_multiply(postmul, set);
654     }
657 // TODO: take _all_ parameters into account, not only PointParams
658 bool
659 Effect::providesKnotholder()
661     // does the effect actively provide any knotholder entities of its own?
662     if (kh_entity_vector.size() > 0)
663         return true;
665     // otherwise: are there any PointParams?
666     for (std::vector<Parameter *>::iterator p = param_vector.begin(); p != param_vector.end(); ++p) {
667 //        if ( Inkscape::LivePathEffect::PointParam *pointparam = dynamic_cast<Inkscape::LivePathEffect::PointParam*>(*p) ) {
668         if (dynamic_cast<Inkscape::LivePathEffect::PointParam*>(*p)) {
669             return true;
670         }
671     }
673     return false;
676 } /* namespace LivePathEffect */
678 } /* namespace Inkscape */
680 /*
681   Local Variables:
682   mode:c++
683   c-file-style:"stroustrup"
684   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
685   indent-tabs-mode:nil
686   fill-column:99
687   End:
688 */
689 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :