Code

Warning cleanup
[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 "libnr/n-art-bpath-2geom.h"
31 #include "display/curve.h"
32 #include <gtkmm.h>
34 #include <exception>
36 #include <2geom/sbasis-to-bezier.h>
37 #include <2geom/matrix.h>
38 #include <2geom/pathvector.h>
40 // include effects:
41 #include "live_effects/lpe-patternalongpath.h"
42 #include "live_effects/lpe-bendpath.h"
43 #include "live_effects/lpe-sketch.h"
44 #include "live_effects/lpe-vonkoch.h"
45 #include "live_effects/lpe-knot.h"
46 #include "live_effects/lpe-test-doEffect-stack.h"
47 #include "live_effects/lpe-gears.h"
48 #include "live_effects/lpe-curvestitch.h"
49 #include "live_effects/lpe-circle_with_radius.h"
50 #include "live_effects/lpe-perspective_path.h"
51 #include "live_effects/lpe-spiro.h"
52 #include "live_effects/lpe-lattice.h"
53 #include "live_effects/lpe-envelope.h"
54 #include "live_effects/lpe-constructgrid.h"
55 #include "live_effects/lpe-perp_bisector.h"
56 #include "live_effects/lpe-tangent_to_curve.h"
57 #include "live_effects/lpe-mirror_symmetry.h"
58 #include "live_effects/lpe-circle_3pts.h"
59 #include "live_effects/lpe-angle_bisector.h"
60 #include "live_effects/lpe-parallel.h"
61 #include "live_effects/lpe-copy_rotate.h"
62 #include "live_effects/lpe-offset.h"
63 #include "live_effects/lpe-ruler.h"
64 #include "live_effects/lpe-boolops.h"
65 #include "live_effects/lpe-interpolate.h"
66 #include "live_effects/lpe-text_label.h"
67 #include "live_effects/lpe-path_length.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     {MIRROR_SYMMETRY,       N_("Mirror symmetry"),         "mirror_symmetry"},
92     {OFFSET,                N_("Offset"),                  "offset"},
93     {PARALLEL,              N_("Parallel"),                "parallel"},
94     {PATH_LENGTH,           N_("Path length"),             "path_length"},
95     {PATTERN_ALONG_PATH,    N_("Pattern Along Path"),      "skeletal"},   // for historic reasons, this effect is called skeletal(strokes) in Inkscape:SVG
96     {PERP_BISECTOR,         N_("Perpendicular bisector"),  "perp_bisector"},
97     {PERSPECTIVE_PATH,      N_("Perspective path"),        "perspective_path"},
98     {COPY_ROTATE,           N_("Rotate copies"),           "copy_rotate"},
99     {RULER,                 N_("Ruler"),                   "ruler"},
100     {SKETCH,                N_("Sketch"),                  "sketch"},
101     {SPIRO,                 N_("Spiro spline"),            "spiro"},
102     {CURVE_STITCH,          N_("Stitch Sub-Paths"),        "curvestitching"},
103     {TANGENT_TO_CURVE,      N_("Tangent to curve"),        "tangent_to_curve"},
104     {TEXT_LABEL,            N_("Text label"),              "text_label"},
105     {VONKOCH,               N_("VonKoch"),                 "vonkoch"},
106 };
107 const Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData));
109 Effect*
110 Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj)
112     Effect* neweffect = NULL;
113     switch (lpenr) {
114         case PATTERN_ALONG_PATH:
115             neweffect = static_cast<Effect*> ( new LPEPatternAlongPath(lpeobj) );
116             break;
117         case FREEHAND_SHAPE:
118             neweffect = static_cast<Effect*> ( new LPEFreehandShape(lpeobj) );
119             break;
120         case BEND_PATH:
121             neweffect = static_cast<Effect*> ( new LPEBendPath(lpeobj) );
122             break;
123         case SKETCH:
124             neweffect = static_cast<Effect*> ( new LPESketch(lpeobj) );
125             break;
126         case VONKOCH:
127             neweffect = static_cast<Effect*> ( new LPEVonKoch(lpeobj) );
128             break;
129         case KNOT:
130             neweffect = static_cast<Effect*> ( new LPEKnot(lpeobj) );
131             break;
132 #ifdef LPE_ENABLE_TEST_EFFECTS
133         case DOEFFECTSTACK_TEST:
134             neweffect = static_cast<Effect*> ( new LPEdoEffectStackTest(lpeobj) );
135             break;
136 #endif
137         case GEARS:
138             neweffect = static_cast<Effect*> ( new LPEGears(lpeobj) );
139             break;
140         case CURVE_STITCH:
141             neweffect = static_cast<Effect*> ( new LPECurveStitch(lpeobj) );
142             break;
143         case LATTICE:
144             neweffect = static_cast<Effect*> ( new LPELattice(lpeobj) );
145             break;
146         case ENVELOPE:
147             neweffect = static_cast<Effect*> ( new LPEEnvelope(lpeobj) );
148             break;
149         case CIRCLE_WITH_RADIUS:
150             neweffect = static_cast<Effect*> ( new LPECircleWithRadius(lpeobj) );
151             break;
152         case PERSPECTIVE_PATH:
153             neweffect = static_cast<Effect*> ( new LPEPerspectivePath(lpeobj) );
154             break;
155         case SPIRO:
156             neweffect = static_cast<Effect*> ( new LPESpiro(lpeobj) );
157             break;
158         case CONSTRUCT_GRID:
159             neweffect = static_cast<Effect*> ( new LPEConstructGrid(lpeobj) );
160             break;
161         case PERP_BISECTOR:
162             neweffect = static_cast<Effect*> ( new LPEPerpBisector(lpeobj) );
163             break;
164         case TANGENT_TO_CURVE:
165             neweffect = static_cast<Effect*> ( new LPETangentToCurve(lpeobj) );
166             break;
167         case MIRROR_SYMMETRY:
168             neweffect = static_cast<Effect*> ( new LPEMirrorSymmetry(lpeobj) );
169             break;
170         case CIRCLE_3PTS:
171             neweffect = static_cast<Effect*> ( new LPECircle3Pts(lpeobj) );
172             break;
173         case ANGLE_BISECTOR:
174             neweffect = static_cast<Effect*> ( new LPEAngleBisector(lpeobj) );
175             break;
176         case PARALLEL:
177             neweffect = static_cast<Effect*> ( new LPEParallel(lpeobj) );
178             break;
179         case COPY_ROTATE:
180             neweffect = static_cast<Effect*> ( new LPECopyRotate(lpeobj) );
181             break;
182         case OFFSET:
183             neweffect = static_cast<Effect*> ( new LPEOffset(lpeobj) );
184             break;
185         case RULER:
186             neweffect = static_cast<Effect*> ( new LPERuler(lpeobj) );
187             break;
188         case BOOLOPS:
189             neweffect = static_cast<Effect*> ( new LPEBoolops(lpeobj) );
190             break;
191         case INTERPOLATE:
192             neweffect = static_cast<Effect*> ( new LPEInterpolate(lpeobj) );
193             break;
194         case TEXT_LABEL:
195             neweffect = static_cast<Effect*> ( new LPETextLabel(lpeobj) );
196             break;
197         case PATH_LENGTH:
198             neweffect = static_cast<Effect*> ( new LPEPathLength(lpeobj) );
199             break;
200         default:
201             g_warning("LivePathEffect::Effect::New   called with invalid patheffect type (%d)", lpenr);
202             neweffect = NULL;
203             break;
204     }
206     if (neweffect) {
207         neweffect->readallParameters(SP_OBJECT_REPR(lpeobj));
208     }
210     return neweffect;
213 void
214 Effect::createAndApply(const char* name, SPDocument *doc, SPItem *item)
216     // Path effect definition
217     Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
218     Inkscape::XML::Node *repr = xml_doc->createElement("inkscape:path-effect");
219     repr->setAttribute("effect", name);
221     SP_OBJECT_REPR(SP_DOCUMENT_DEFS(doc))->addChild(repr, NULL); // adds to <defs> and assigns the 'id' attribute
222     const gchar * repr_id = repr->attribute("id");
223     Inkscape::GC::release(repr);
225     gchar *href = g_strdup_printf("#%s", repr_id);
226     sp_lpe_item_add_path_effect(SP_LPE_ITEM(item), href, true);
227     g_free(href);
230 void
231 Effect::createAndApply(EffectType type, SPDocument *doc, SPItem *item)
233     createAndApply(LPETypeConverter.get_key(type).c_str(), doc, item);
236 Effect::Effect(LivePathEffectObject *lpeobject)
237     : oncanvasedit_it(0),
238       is_visible(_("Is visible?"), _("If unchecked, the effect remains applied to the object but is temporarily disabled on canvas"), "is_visible", &wr, this, true),
239       done_pathparam_set(false),
240       show_orig_path(false),
241       lpeobj(lpeobject),
242       concatenate_before_pwd2(false),
243       provides_own_flash_paths(true) // is automatically set to false if providesOwnFlashPaths() is not overridden
245     registerParameter( dynamic_cast<Parameter *>(&is_visible) );
248 Effect::~Effect()
252 Glib::ustring
253 Effect::getName()
255     if (lpeobj->effecttype_set && LPETypeConverter.is_valid_id(lpeobj->effecttype) )
256         return Glib::ustring( _(LPETypeConverter.get_label(lpeobj->effecttype).c_str()) );
257     else
258         return Glib::ustring( _("No effect") );
261 EffectType
262 Effect::effectType() {
263     return lpeobj->effecttype;
266 /**
267  * Is performed a single time when the effect is freshly applied to a path
268  */
269 void
270 Effect::doOnApply (SPLPEItem */*lpeitem*/)
274 /**
275  * Is performed each time before the effect is updated.
276  */
277 void
278 Effect::doBeforeEffect (SPLPEItem */*lpeitem*/)
280     //Do nothing for simple effects
283 /**
284  * Effects can have a parameter path set before they are applied by accepting a nonzero number of
285  * mouse clicks. This method activates the pen context, which waits for the specified number of
286  * clicks. Override Effect::acceptsNumParams() to return the number of expected mouse clicks.
287  */
288 void
289 Effect::doAcceptPathPreparations(SPLPEItem *lpeitem)
291     // switch to pen context
292     SPDesktop *desktop = inkscape_active_desktop(); // TODO: Is there a better method to find the item's desktop?
293     if (!tools_isactive(desktop, TOOLS_FREEHAND_PEN)) {
294         tools_switch(desktop, TOOLS_FREEHAND_PEN);
295     }
297     SPEventContext *ec = desktop->event_context;
298     SPPenContext *pc = SP_PEN_CONTEXT(ec);
299     pc->expecting_clicks_for_LPE = this->acceptsNumParams();
300     pc->waiting_LPE = this;
301     pc->waiting_item = lpeitem;
302     pc->polylines_only = true;
304     ec->desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE,
305         g_strdup_printf(_("Please specify a parameter path for the LPE '%s' with %d mouse clicks"),
306                         getName().c_str(), acceptsNumParams()));
309 void
310 Effect::writeParamsToSVG() {
311     std::vector<Inkscape::LivePathEffect::Parameter *>::iterator p;
312     for (p = param_vector.begin(); p != param_vector.end(); ++p) {
313         (*p)->write_to_SVG();
314     }
317 /**
318  * If the effect expects a path parameter (specified by a number of mouse clicks) before it is
319  * applied, this is the method that processes the resulting path. Override it to customize it for
320  * your LPE. But don't forget to call the parent method so that done_pathparam_set is set to true!
321  */
322 void
323 Effect::acceptParamPath (SPPath */*param_path*/) {
324     done_pathparam_set = true;
327 /*
328  *  Here be the doEffect function chain:
329  */
330 void
331 Effect::doEffect (SPCurve * curve)
333     std::vector<Geom::Path> orig_pathv = curve->get_pathvector();
335     std::vector<Geom::Path> result_pathv = doEffect_path(orig_pathv);
337     curve->set_pathvector(result_pathv);
340 std::vector<Geom::Path>
341 Effect::doEffect_path (std::vector<Geom::Path> const & path_in)
343     std::vector<Geom::Path> path_out;
345     if ( !concatenate_before_pwd2 ) {
346         // default behavior
347         for (unsigned int i=0; i < path_in.size(); i++) {
348             Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in = path_in[i].toPwSb();
349             Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_out = doEffect_pwd2(pwd2_in);
350             std::vector<Geom::Path> path = Geom::path_from_piecewise( pwd2_out, LPE_CONVERSION_TOLERANCE);
351             // add the output path vector to the already accumulated vector:
352             for (unsigned int j=0; j < path.size(); j++) {
353                 path_out.push_back(path[j]);
354             }
355         }
356     } else {
357       // concatenate the path into possibly discontinuous pwd2
358         Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in;
359         for (unsigned int i=0; i < path_in.size(); i++) {
360             pwd2_in.concat( path_in[i].toPwSb() );
361         }
362         Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_out = doEffect_pwd2(pwd2_in);
363         path_out = Geom::path_from_piecewise( pwd2_out, LPE_CONVERSION_TOLERANCE);
364     }
366     return path_out;
369 Geom::Piecewise<Geom::D2<Geom::SBasis> >
370 Effect::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
372     g_warning("Effect has no doEffect implementation");
373     return pwd2_in;
376 void
377 Effect::readallParameters(Inkscape::XML::Node * repr)
379     std::vector<Parameter *>::iterator it = param_vector.begin();
380     while (it != param_vector.end()) {
381         Parameter * param = *it;
382         const gchar * key = param->param_key.c_str();
383         const gchar * value = repr->attribute(key);
384         if (value) {
385             bool accepted = param->param_readSVGValue(value);
386             if (!accepted) {
387                 g_warning("Effect::readallParameters - '%s' not accepted for %s", value, key);
388             }
389         } else {
390             // set default value
391             param->param_set_default();
392         }
394         it++;
395     }
398 /* This function does not and SHOULD NOT write to XML */
399 void
400 Effect::setParameter(const gchar * key, const gchar * new_value)
402     Parameter * param = getParameter(key);
403     if (param) {
404         if (new_value) {
405             bool accepted = param->param_readSVGValue(new_value);
406             if (!accepted) {
407                 g_warning("Effect::setParameter - '%s' not accepted for %s", new_value, key);
408             }
409         } else {
410             // set default value
411             param->param_set_default();
412         }
413     }
416 void
417 Effect::registerParameter(Parameter * param)
419     param_vector.push_back(param);
422 // TODO: should we provide a way to alter the handle's appearance?
423 void
424 Effect::registerKnotHolderHandle(KnotHolderEntity* entity, const char* descr)
426     kh_entity_vector.push_back(std::make_pair(entity, descr));
429 /**
430  * Add all registered LPE knotholder handles to the knotholder
431  */
432 void
433 Effect::addHandles(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) {
434     using namespace Inkscape::LivePathEffect;
436     // add handles provided by the effect itself
437     addKnotHolderEntities(knotholder, desktop, item);
439     // add handles provided by the effect's parameters (if any)
440     for (std::vector<Parameter *>::iterator p = param_vector.begin(); p != param_vector.end(); ++p) {
441         (*p)->addKnotHolderEntities(knotholder, desktop, item);
442     }
445 void
446 Effect::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) {
447     // TODO: The entities in kh_entity_vector are already instantiated during the call
448     //       to registerKnotHolderHandle(), but they are recreated here. Also, we must not
449     //       delete them when the knotholder is destroyed, whence the clumsy function
450     //       isDeletable(). If we could create entities of different classes dynamically,
451     //       this would be much nicer. How to do this?
452     std::vector<std::pair<KnotHolderEntity*, const char*> >::iterator i;
453     for (i = kh_entity_vector.begin(); i != kh_entity_vector.end(); ++i) {
454         KnotHolderEntity *entity = i->first;
455         const char *descr = i->second;
457         entity->create(desktop, item, knotholder, descr);
458         knotholder->add(entity);
459     }
462 /**
463  * Return a vector of PathVectors which contain all helperpaths that should be drawn by the effect.
464  * This is the function called by external code like SPLPEItem.
465  */
466 std::vector<Geom::PathVector>
467 Effect::getHelperPaths(SPLPEItem *lpeitem)
469     std::vector<Geom::PathVector> hp_vec;
471     if (!SP_IS_SHAPE(lpeitem)) {
472         g_print ("How to handle helperpaths for non-shapes?\n");
473         return hp_vec;
474     }
476     // TODO: we can probably optimize this by using a lot more references
477     //       rather than copying PathVectors all over the place
478     if (show_orig_path) {
479         // add original path to helperpaths
480         SPCurve* curve = sp_shape_get_curve (SP_SHAPE(lpeitem));
481         hp_vec.push_back(curve->get_pathvector());
482     }
484     // add other helperpaths provided by the effect itself
485     addCanvasIndicators(lpeitem, hp_vec);
487     // add helperpaths provided by the effect's parameters
488     for (std::vector<Parameter *>::iterator p = param_vector.begin(); p != param_vector.end(); ++p) {
489         (*p)->addCanvasIndicators(lpeitem, hp_vec);
490     }
492     return hp_vec;
495 /**
496  * Add possible canvas indicators (i.e., helperpaths other than the original path) to \a hp_vec
497  * This function should be overwritten by derived effects if they want to provide their own helperpaths.
498  */
499 void
500 Effect::addCanvasIndicators(SPLPEItem */*lpeitem*/, std::vector<Geom::PathVector> &/*hp_vec*/)
505 /**
506  * This *creates* a new widget, management of deletion should be done by the caller
507  */
508 Gtk::Widget *
509 Effect::newWidget(Gtk::Tooltips * tooltips)
511     // use manage here, because after deletion of Effect object, others might still be pointing to this widget.
512     Gtk::VBox * vbox = Gtk::manage( new Gtk::VBox() );
514     vbox->set_border_width(5);
516     std::vector<Parameter *>::iterator it = param_vector.begin();
517     while (it != param_vector.end()) {
518         Parameter * param = *it;
519         Gtk::Widget * widg = param->param_newWidget(tooltips);
520         Glib::ustring * tip = param->param_getTooltip();
521         if (widg) {
522            vbox->pack_start(*widg, true, true, 2);
523             if (tip != NULL) {
524                 tooltips->set_tip(*widg, *tip);
525             }
526         }
528         it++;
529     }
531     return dynamic_cast<Gtk::Widget *>(vbox);
535 Inkscape::XML::Node *
536 Effect::getRepr()
538     return SP_OBJECT_REPR(lpeobj);
541 SPDocument *
542 Effect::getSPDoc()
544     if (SP_OBJECT_DOCUMENT(lpeobj) == NULL) g_message("Effect::getSPDoc() returns NULL");
545     return SP_OBJECT_DOCUMENT(lpeobj);
548 Parameter *
549 Effect::getParameter(const char * key)
551     Glib::ustring stringkey(key);
553     std::vector<Parameter *>::iterator it = param_vector.begin();
554     while (it != param_vector.end()) {
555         Parameter * param = *it;
556         if ( param->param_key == key) {
557             return param;
558         }
560         it++;
561     }
563     return NULL;
566 Parameter *
567 Effect::getNextOncanvasEditableParam()
569     if (param_vector.size() == 0) // no parameters
570         return NULL;
572     oncanvasedit_it++;
573     if (oncanvasedit_it >= static_cast<int>(param_vector.size())) {
574         oncanvasedit_it = 0;
575     }
576     int old_it = oncanvasedit_it;
578     do {
579         Parameter * param = param_vector[oncanvasedit_it];
580         if(param && param->oncanvas_editable) {
581             return param;
582         } else {
583             oncanvasedit_it++;
584             if (oncanvasedit_it == static_cast<int>(param_vector.size())) {  // loop round the map
585                 oncanvasedit_it = 0;
586             }
587         }
588     } while (oncanvasedit_it != old_it); // iterate until complete loop through map has been made
590     return NULL;
593 void
594 Effect::editNextParamOncanvas(SPItem * item, SPDesktop * desktop)
596     if (!desktop) return;
598     Parameter * param = getNextOncanvasEditableParam();
599     if (param) {
600         param->param_editOncanvas(item, desktop);
601         gchar *message = g_strdup_printf(_("Editing parameter <b>%s</b>."), param->param_label.c_str());
602         desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, message);
603         g_free(message);
604     } else {
605         desktop->messageStack()->flash( Inkscape::WARNING_MESSAGE,
606                                         _("None of the applied path effect's parameters can be edited on-canvas.") );
607     }
610 /* This function should reset the defaults and is used for example to initialize an effect right after it has been applied to a path
611 * 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!
612 */
613 void
614 Effect::resetDefaults(SPItem * /*item*/)
616     // do nothing for simple effects
619 void
620 Effect::setup_nodepath(Inkscape::NodePath::Path *np)
622     np->helperpath_rgba = 0xff0000ff;
623     np->helperpath_width = 1.0;
626 void
627 Effect::transform_multiply(Geom::Matrix const& postmul, bool set)
629     // cycle through all parameters. Most parameters will not need transformation, but path and point params do.
630     for (std::vector<Parameter *>::iterator it = param_vector.begin(); it != param_vector.end(); it++) {
631         Parameter * param = *it;
632         param->param_transform_multiply(postmul, set);
633     }
636 // TODO: take _all_ parameters into account, not only PointParams
637 bool
638 Effect::providesKnotholder()
640     // does the effect actively provide any knotholder entities of its own?
641     if (kh_entity_vector.size() > 0)
642         return true;
644     // otherwise: are there any PointParams?
645     for (std::vector<Parameter *>::iterator p = param_vector.begin(); p != param_vector.end(); ++p) {
646 //        if ( Inkscape::LivePathEffect::PointParam *pointparam = dynamic_cast<Inkscape::LivePathEffect::PointParam*>(*p) ) {
647         if (dynamic_cast<Inkscape::LivePathEffect::PointParam*>(*p)) {
648             return true;
649         }
650     }
652     return false;
655 } /* namespace LivePathEffect */
657 } /* namespace Inkscape */
659 /*
660   Local Variables:
661   mode:c++
662   c-file-style:"stroustrup"
663   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
664   indent-tabs-mode:nil
665   fill-column:99
666   End:
667 */
668 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :