4a71b26565dfc2e441b01289429628e2987d58dc
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 }
120 }
122 Effect*
123 Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj)
124 {
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;
227 }
229 void
230 Effect::createAndApply(const char* name, SPDocument *doc, SPItem *item)
231 {
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);
244 }
246 void
247 Effect::createAndApply(EffectType type, SPDocument *doc, SPItem *item)
248 {
249 createAndApply(LPETypeConverter.get_key(type).c_str(), doc, item);
250 }
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
261 {
262 registerParameter( dynamic_cast<Parameter *>(&is_visible) );
263 registerParameter( dynamic_cast<Parameter *>(&deactivate_knotholder) );
264 }
266 Effect::~Effect()
267 {
268 }
270 Glib::ustring
271 Effect::getName()
272 {
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") );
277 }
279 EffectType
280 Effect::effectType() {
281 return lpeobj->effecttype;
282 }
284 /**
285 * Is performed a single time when the effect is freshly applied to a path
286 */
287 void
288 Effect::doOnApply (SPLPEItem */*lpeitem*/)
289 {
290 }
292 /**
293 * Is performed each time before the effect is updated.
294 */
295 void
296 Effect::doBeforeEffect (SPLPEItem */*lpeitem*/)
297 {
298 //Do nothing for simple effects
299 }
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)
308 {
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()));
325 }
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 }
333 }
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();
343 }
345 /*
346 * Here be the doEffect function chain:
347 */
348 void
349 Effect::doEffect (SPCurve * curve)
350 {
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);
356 }
358 std::vector<Geom::Path>
359 Effect::doEffect_path (std::vector<Geom::Path> const & path_in)
360 {
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;
385 }
387 Geom::Piecewise<Geom::D2<Geom::SBasis> >
388 Effect::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
389 {
390 g_warning("Effect has no doEffect implementation");
391 return pwd2_in;
392 }
394 void
395 Effect::readallParameters(Inkscape::XML::Node * repr)
396 {
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 }
414 }
416 /* This function does not and SHOULD NOT write to XML */
417 void
418 Effect::setParameter(const gchar * key, const gchar * new_value)
419 {
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 }
432 }
434 void
435 Effect::registerParameter(Parameter * param)
436 {
437 param_vector.push_back(param);
438 }
440 // TODO: should we provide a way to alter the handle's appearance?
441 void
442 Effect::registerKnotHolderHandle(KnotHolderEntity* entity, const char* descr)
443 {
444 kh_entity_vector.push_back(std::make_pair(entity, descr));
445 }
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 }
464 }
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 }
481 }
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)
489 {
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;
514 }
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*/)
522 {
523 }
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)
531 {
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);
553 }
556 Inkscape::XML::Node *
557 Effect::getRepr()
558 {
559 return SP_OBJECT_REPR(lpeobj);
560 }
562 SPDocument *
563 Effect::getSPDoc()
564 {
565 if (SP_OBJECT_DOCUMENT(lpeobj) == NULL) g_message("Effect::getSPDoc() returns NULL");
566 return SP_OBJECT_DOCUMENT(lpeobj);
567 }
569 Parameter *
570 Effect::getParameter(const char * key)
571 {
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;
585 }
587 Parameter *
588 Effect::getNextOncanvasEditableParam()
589 {
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;
612 }
614 void
615 Effect::editNextParamOncanvas(SPItem * item, SPDesktop * desktop)
616 {
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 }
629 }
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*/)
636 {
637 // do nothing for simple effects
638 }
640 void
641 Effect::setup_nodepath(Inkscape::NodePath::Path *np)
642 {
643 np->helperpath_rgba = 0xff0000ff;
644 np->helperpath_width = 1.0;
645 }
647 void
648 Effect::transform_multiply(Geom::Matrix const& postmul, bool set)
649 {
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 }
655 }
657 // TODO: take _all_ parameters into account, not only PointParams
658 bool
659 Effect::providesKnotholder()
660 {
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;
674 }
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 :