effect.cpp revision 8791d7447034c34fdedc50f261bf5c89c34e59f5
1634N/A#define INKSCAPE_LIVEPATHEFFECT_CPP
1634N/A
1508N/A/*
691N/A * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
691N/A *
1508N/A * Released under GNU GPL, read the file 'COPYING' for more information
691N/A */
691N/A
1508N/A#include "live_effects/effect.h"
691N/A
691N/A#include "xml/node-event-vector.h"
691N/A#include "sp-object.h"
691N/A#include "attributes.h"
691N/A#include "message-stack.h"
691N/A#include "desktop.h"
1634N/A#include "inkscape.h"
1265N/A#include "document.h"
1265N/A#include "document-private.h"
691N/A#include "xml/document.h"
691N/A#include <glibmm/i18n.h>
691N/A#include "pen-context.h"
1333N/A#include "tools-switch.h"
1333N/A#include "message-stack.h"
691N/A#include "desktop.h"
1333N/A#include "nodepath.h"
1333N/A
1333N/A#include "live_effects/lpeobject.h"
1333N/A#include "live_effects/parameter/parameter.h"
1333N/A#include <glibmm/ustring.h>
1333N/A#include "display/curve.h"
1333N/A#include <gtkmm.h>
1333N/A
1333N/A#include <exception>
1333N/A
1333N/A#include <2geom/sbasis-to-bezier.h>
691N/A#include <2geom/matrix.h>
1333N/A#include <2geom/pathvector.h>
1265N/A
1265N/A// include effects:
1333N/A#include "live_effects/lpe-patternalongpath.h"
1333N/A#include "live_effects/lpe-bendpath.h"
1333N/A#include "live_effects/lpe-sketch.h"
1333N/A#include "live_effects/lpe-vonkoch.h"
1333N/A#include "live_effects/lpe-knot.h"
1265N/A#include "live_effects/lpe-test-doEffect-stack.h"
1265N/A#include "live_effects/lpe-gears.h"
1333N/A#include "live_effects/lpe-curvestitch.h"
691N/A#include "live_effects/lpe-circle_with_radius.h"
1333N/A#include "live_effects/lpe-perspective_path.h"
1333N/A#include "live_effects/lpe-spiro.h"
1333N/A#include "live_effects/lpe-lattice.h"
1333N/A#include "live_effects/lpe-envelope.h"
1333N/A#include "live_effects/lpe-constructgrid.h"
1333N/A#include "live_effects/lpe-perp_bisector.h"
1333N/A#include "live_effects/lpe-tangent_to_curve.h"
691N/A#include "live_effects/lpe-mirror_symmetry.h"
1333N/A#include "live_effects/lpe-circle_3pts.h"
1333N/A#include "live_effects/lpe-angle_bisector.h"
1333N/A#include "live_effects/lpe-parallel.h"
1634N/A#include "live_effects/lpe-copy_rotate.h"
1634N/A#include "live_effects/lpe-offset.h"
1333N/A#include "live_effects/lpe-ruler.h"
1634N/A#include "live_effects/lpe-boolops.h"
1333N/A#include "live_effects/lpe-interpolate.h"
1333N/A#include "live_effects/lpe-text_label.h"
691N/A#include "live_effects/lpe-path_length.h"
1333N/A#include "live_effects/lpe-line_segment.h"
1333N/A// end of includes
1634N/A
1634N/Anamespace Inkscape {
1634N/A
1634N/Anamespace LivePathEffect {
1333N/A
1634N/Aconst Util::EnumData<EffectType> LPETypeData[] = {
1333N/A // {constant defined in effect.h, N_("name of your effect"), "name of your effect in SVG"}
691N/A {ANGLE_BISECTOR, N_("Angle bisector"), "angle_bisector"},
1333N/A {BEND_PATH, N_("Bend"), "bend_path"},
1333N/A {BOOLOPS, N_("Boolops"), "boolops"},
1333N/A {CIRCLE_WITH_RADIUS, N_("Circle (center+radius)"), "circle_with_radius"},
1634N/A {CIRCLE_3PTS, N_("Circle through 3 points"), "circle_3pts"},
1634N/A {CONSTRUCT_GRID, N_("Construct grid"), "construct_grid"},
1333N/A#ifdef LPE_ENABLE_TEST_EFFECTS
1634N/A {DOEFFECTSTACK_TEST, N_("doEffect stack test"), "doeffectstacktest"},
1333N/A#endif
1333N/A {ENVELOPE, N_("Envelope Deformation"), "envelope"},
691N/A {FREEHAND_SHAPE, N_("Freehand Shape"), "freehand_shape"}, // this is actually a special type of PatternAlongPath, used to paste shapes in pen/pencil tool
1333N/A {GEARS, N_("Gears"), "gears"},
1333N/A {INTERPOLATE, N_("Interpolate Sub-Paths"), "interpolate"},
1333N/A {KNOT, N_("Knot"), "knot"},
1333N/A {LATTICE, N_("Lattice Deformation"), "lattice"},
1634N/A {LINE_SEGMENT, N_("Line Segment"), "line_segment"},
1634N/A {MIRROR_SYMMETRY, N_("Mirror symmetry"), "mirror_symmetry"},
1333N/A {OFFSET, N_("Offset"), "offset"},
1634N/A {PARALLEL, N_("Parallel"), "parallel"},
1333N/A {PATH_LENGTH, N_("Path length"), "path_length"},
1333N/A {PATTERN_ALONG_PATH, N_("Pattern Along Path"), "skeletal"}, // for historic reasons, this effect is called skeletal(strokes) in Inkscape:SVG
1333N/A {PERP_BISECTOR, N_("Perpendicular bisector"), "perp_bisector"},
1634N/A {PERSPECTIVE_PATH, N_("Perspective path"), "perspective_path"},
1634N/A {COPY_ROTATE, N_("Rotate copies"), "copy_rotate"},
1634N/A {RULER, N_("Ruler"), "ruler"},
1333N/A {SKETCH, N_("Sketch"), "sketch"},
691N/A {SPIRO, N_("Spiro spline"), "spiro"},
1265N/A {CURVE_STITCH, N_("Stitch Sub-Paths"), "curvestitching"},
691N/A {TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"},
1333N/A {TEXT_LABEL, N_("Text label"), "text_label"},
1333N/A {VONKOCH, N_("VonKoch"), "vonkoch"},
1333N/A};
1634N/Aconst Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData));
1333N/A
1333N/Aint
1333N/AEffect::acceptsNumClicks(EffectType type) {
1333N/A switch (type) {
691N/A case ANGLE_BISECTOR: return 3;
1265N/A case CIRCLE_3PTS: return 3;
691N/A case CIRCLE_WITH_RADIUS: return 2;
1634N/A case LINE_SEGMENT: return 2;
1508N/A case PERP_BISECTOR: return 2;
1508N/A default: return 0;
1508N/A }
691N/A}
691N/A
1634N/AEffect*
1634N/AEffect::New(EffectType lpenr, LivePathEffectObject *lpeobj)
1634N/A{
1508N/A Effect* neweffect = NULL;
1508N/A switch (lpenr) {
1508N/A case PATTERN_ALONG_PATH:
1508N/A neweffect = static_cast<Effect*> ( new LPEPatternAlongPath(lpeobj) );
1508N/A break;
1508N/A case FREEHAND_SHAPE:
1508N/A neweffect = static_cast<Effect*> ( new LPEFreehandShape(lpeobj) );
1508N/A break;
1634N/A case BEND_PATH:
1508N/A neweffect = static_cast<Effect*> ( new LPEBendPath(lpeobj) );
1508N/A break;
1508N/A case SKETCH:
1508N/A neweffect = static_cast<Effect*> ( new LPESketch(lpeobj) );
1508N/A break;
1508N/A case VONKOCH:
1634N/A neweffect = static_cast<Effect*> ( new LPEVonKoch(lpeobj) );
1634N/A break;
1634N/A case KNOT:
1634N/A neweffect = static_cast<Effect*> ( new LPEKnot(lpeobj) );
1634N/A break;
1508N/A#ifdef LPE_ENABLE_TEST_EFFECTS
1508N/A case DOEFFECTSTACK_TEST:
1508N/A neweffect = static_cast<Effect*> ( new LPEdoEffectStackTest(lpeobj) );
1508N/A break;
1508N/A#endif
1508N/A case GEARS:
1508N/A neweffect = static_cast<Effect*> ( new LPEGears(lpeobj) );
1508N/A break;
1634N/A case CURVE_STITCH:
1508N/A neweffect = static_cast<Effect*> ( new LPECurveStitch(lpeobj) );
1508N/A break;
1508N/A case LATTICE:
1508N/A neweffect = static_cast<Effect*> ( new LPELattice(lpeobj) );
1508N/A break;
1508N/A case ENVELOPE:
1508N/A neweffect = static_cast<Effect*> ( new LPEEnvelope(lpeobj) );
1508N/A break;
1634N/A case CIRCLE_WITH_RADIUS:
1508N/A neweffect = static_cast<Effect*> ( new LPECircleWithRadius(lpeobj) );
1508N/A break;
1508N/A case PERSPECTIVE_PATH:
1508N/A neweffect = static_cast<Effect*> ( new LPEPerspectivePath(lpeobj) );
1508N/A break;
1508N/A case SPIRO:
1508N/A neweffect = static_cast<Effect*> ( new LPESpiro(lpeobj) );
1508N/A break;
1508N/A case CONSTRUCT_GRID:
1508N/A neweffect = static_cast<Effect*> ( new LPEConstructGrid(lpeobj) );
1508N/A break;
1634N/A case PERP_BISECTOR:
1508N/A neweffect = static_cast<Effect*> ( new LPEPerpBisector(lpeobj) );
1265N/A break;
1265N/A case TANGENT_TO_CURVE:
1265N/A neweffect = static_cast<Effect*> ( new LPETangentToCurve(lpeobj) );
1265N/A break;
1265N/A case MIRROR_SYMMETRY:
1508N/A neweffect = static_cast<Effect*> ( new LPEMirrorSymmetry(lpeobj) );
1265N/A break;
1508N/A case CIRCLE_3PTS:
1265N/A neweffect = static_cast<Effect*> ( new LPECircle3Pts(lpeobj) );
1265N/A break;
1634N/A case ANGLE_BISECTOR:
1508N/A neweffect = static_cast<Effect*> ( new LPEAngleBisector(lpeobj) );
1333N/A break;
1333N/A case PARALLEL:
1333N/A neweffect = static_cast<Effect*> ( new LPEParallel(lpeobj) );
1333N/A break;
1333N/A case COPY_ROTATE:
1333N/A neweffect = static_cast<Effect*> ( new LPECopyRotate(lpeobj) );
1333N/A break;
1333N/A case OFFSET:
1333N/A neweffect = static_cast<Effect*> ( new LPEOffset(lpeobj) );
1508N/A break;
1634N/A case RULER:
1634N/A neweffect = static_cast<Effect*> ( new LPERuler(lpeobj) );
1508N/A break;
1508N/A case BOOLOPS:
1508N/A neweffect = static_cast<Effect*> ( new LPEBoolops(lpeobj) );
1508N/A break;
1508N/A case INTERPOLATE:
1508N/A neweffect = static_cast<Effect*> ( new LPEInterpolate(lpeobj) );
1508N/A break;
1508N/A case TEXT_LABEL:
1508N/A neweffect = static_cast<Effect*> ( new LPETextLabel(lpeobj) );
1508N/A break;
1508N/A case PATH_LENGTH:
1508N/A neweffect = static_cast<Effect*> ( new LPEPathLength(lpeobj) );
1508N/A break;
1508N/A case LINE_SEGMENT:
1508N/A neweffect = static_cast<Effect*> ( new LPELineSegment(lpeobj) );
1508N/A break;
1508N/A default:
1508N/A g_warning("LivePathEffect::Effect::New called with invalid patheffect type (%d)", lpenr);
1508N/A neweffect = NULL;
1508N/A break;
1508N/A }
1508N/A
1508N/A if (neweffect) {
1508N/A neweffect->readallParameters(SP_OBJECT_REPR(lpeobj));
1508N/A }
1508N/A
1508N/A return neweffect;
1508N/A}
1508N/A
1508N/Avoid
1508N/AEffect::createAndApply(const char* name, SPDocument *doc, SPItem *item)
1508N/A{
1508N/A // Path effect definition
1508N/A Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
1508N/A Inkscape::XML::Node *repr = xml_doc->createElement("inkscape:path-effect");
1508N/A repr->setAttribute("effect", name);
1508N/A
1508N/A SP_OBJECT_REPR(SP_DOCUMENT_DEFS(doc))->addChild(repr, NULL); // adds to <defs> and assigns the 'id' attribute
1508N/A const gchar * repr_id = repr->attribute("id");
1508N/A Inkscape::GC::release(repr);
1508N/A
1508N/A gchar *href = g_strdup_printf("#%s", repr_id);
1508N/A sp_lpe_item_add_path_effect(SP_LPE_ITEM(item), href, true);
1508N/A g_free(href);
1508N/A}
1508N/A
1508N/Avoid
1508N/AEffect::createAndApply(EffectType type, SPDocument *doc, SPItem *item)
1508N/A{
1508N/A createAndApply(LPETypeConverter.get_key(type).c_str(), doc, item);
1508N/A}
1508N/A
1508N/AEffect::Effect(LivePathEffectObject *lpeobject)
1508N/A : oncanvasedit_it(0),
1508N/A is_visible(_("Is visible?"), _("If unchecked, the effect remains applied to the object but is temporarily disabled on canvas"), "is_visible", &wr, this, true),
1508N/A show_orig_path(false),
1508N/A lpeobj(lpeobject),
1508N/A concatenate_before_pwd2(false),
1508N/A provides_own_flash_paths(true), // is automatically set to false if providesOwnFlashPaths() is not overridden
1508N/A is_ready(false) // is automatically set to false if providesOwnFlashPaths() is not overridden
1508N/A{
1508N/A registerParameter( dynamic_cast<Parameter *>(&is_visible) );
1508N/A}
1508N/A
1508N/AEffect::~Effect()
1508N/A{
1508N/A}
1508N/A
1508N/AGlib::ustring
1508N/AEffect::getName()
1508N/A{
1508N/A if (lpeobj->effecttype_set && LPETypeConverter.is_valid_id(lpeobj->effecttype) )
1508N/A return Glib::ustring( _(LPETypeConverter.get_label(lpeobj->effecttype).c_str()) );
1508N/A else
1508N/A return Glib::ustring( _("No effect") );
1508N/A}
1508N/A
1508N/AEffectType
1508N/AEffect::effectType() {
1508N/A return lpeobj->effecttype;
1508N/A}
1508N/A
1508N/A/**
1508N/A * Is performed a single time when the effect is freshly applied to a path
1508N/A */
1508N/Avoid
1508N/AEffect::doOnApply (SPLPEItem */*lpeitem*/)
1508N/A{
1634N/A}
1508N/A
1508N/A/**
1634N/A * Is performed each time before the effect is updated.
1508N/A */
1508N/Avoid
1508N/AEffect::doBeforeEffect (SPLPEItem */*lpeitem*/)
1508N/A{
1634N/A //Do nothing for simple effects
1508N/A}
1508N/A
1508N/A/**
1508N/A * Effects can have a parameter path set before they are applied by accepting a nonzero number of
1508N/A * mouse clicks. This method activates the pen context, which waits for the specified number of
1508N/A * clicks. Override Effect::acceptsNumClicks() to return the number of expected mouse clicks.
1508N/A */
1508N/Avoid
1508N/AEffect::doAcceptPathPreparations(SPLPEItem *lpeitem)
1508N/A{
1508N/A // switch to pen context
1508N/A SPDesktop *desktop = inkscape_active_desktop(); // TODO: Is there a better method to find the item's desktop?
1634N/A if (!tools_isactive(desktop, TOOLS_FREEHAND_PEN)) {
1333N/A tools_switch(desktop, TOOLS_FREEHAND_PEN);
1508N/A }
1508N/A
1508N/A SPEventContext *ec = desktop->event_context;
1508N/A SPPenContext *pc = SP_PEN_CONTEXT(ec);
1508N/A pc->expecting_clicks_for_LPE = this->acceptsNumClicks();
1333N/A pc->waiting_LPE = this;
1508N/A pc->waiting_item = lpeitem;
1634N/A pc->polylines_only = true;
1634N/A
1634N/A ec->desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE,
1508N/A g_strdup_printf(_("Please specify a parameter path for the LPE '%s' with %d mouse clicks"),
1508N/A getName().c_str(), acceptsNumClicks()));
1508N/A}
1508N/A
1508N/Avoid
1508N/AEffect::writeParamsToSVG() {
1508N/A std::vector<Inkscape::LivePathEffect::Parameter *>::iterator p;
1508N/A for (p = param_vector.begin(); p != param_vector.end(); ++p) {
1508N/A (*p)->write_to_SVG();
1508N/A }
1634N/A}
1508N/A
1508N/A/**
1508N/A * If the effect expects a path parameter (specified by a number of mouse clicks) before it is
1508N/A * applied, this is the method that processes the resulting path. Override it to customize it for
1508N/A * your LPE. But don't forget to call the parent method so that is_ready is set to true!
1508N/A */
1508N/Avoid
1508N/AEffect::acceptParamPath (SPPath */*param_path*/) {
1634N/A setReady();
1634N/A}
1508N/A
1508N/A/*
1508N/A * Here be the doEffect function chain:
1508N/A */
1508N/Avoid
1508N/AEffect::doEffect (SPCurve * curve)
1634N/A{
1634N/A std::vector<Geom::Path> orig_pathv = curve->get_pathvector();
1508N/A
1508N/A std::vector<Geom::Path> result_pathv = doEffect_path(orig_pathv);
1508N/A
1508N/A curve->set_pathvector(result_pathv);
1508N/A}
1508N/A
1508N/Astd::vector<Geom::Path>
1508N/AEffect::doEffect_path (std::vector<Geom::Path> const & path_in)
1508N/A{
1508N/A std::vector<Geom::Path> path_out;
1508N/A
1508N/A if ( !concatenate_before_pwd2 ) {
1634N/A // default behavior
1634N/A for (unsigned int i=0; i < path_in.size(); i++) {
1634N/A Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in = path_in[i].toPwSb();
1634N/A Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_out = doEffect_pwd2(pwd2_in);
1634N/A std::vector<Geom::Path> path = Geom::path_from_piecewise( pwd2_out, LPE_CONVERSION_TOLERANCE);
1634N/A // add the output path vector to the already accumulated vector:
1634N/A for (unsigned int j=0; j < path.size(); j++) {
1634N/A path_out.push_back(path[j]);
1634N/A }
1634N/A }
1634N/A } else {
1634N/A // concatenate the path into possibly discontinuous pwd2
1634N/A Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in;
1634N/A for (unsigned int i=0; i < path_in.size(); i++) {
1634N/A pwd2_in.concat( path_in[i].toPwSb() );
1634N/A }
1634N/A Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_out = doEffect_pwd2(pwd2_in);
1634N/A path_out = Geom::path_from_piecewise( pwd2_out, LPE_CONVERSION_TOLERANCE);
1634N/A }
1634N/A
1634N/A return path_out;
1634N/A}
1634N/A
1634N/AGeom::Piecewise<Geom::D2<Geom::SBasis> >
1634N/AEffect::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
1634N/A{
1634N/A g_warning("Effect has no doEffect implementation");
1549N/A return pwd2_in;
1634N/A}
1634N/A
1634N/Avoid
1634N/AEffect::readallParameters(Inkscape::XML::Node * repr)
1634N/A{
1634N/A std::vector<Parameter *>::iterator it = param_vector.begin();
1634N/A while (it != param_vector.end()) {
1634N/A Parameter * param = *it;
1634N/A const gchar * key = param->param_key.c_str();
1634N/A const gchar * value = repr->attribute(key);
1634N/A if (value) {
1634N/A bool accepted = param->param_readSVGValue(value);
1634N/A if (!accepted) {
1634N/A g_warning("Effect::readallParameters - '%s' not accepted for %s", value, key);
1634N/A }
1634N/A } else {
1634N/A // set default value
1634N/A param->param_set_default();
1634N/A }
1634N/A
1634N/A it++;
1634N/A }
1634N/A}
1634N/A
1634N/A/* This function does not and SHOULD NOT write to XML */
1634N/Avoid
1634N/AEffect::setParameter(const gchar * key, const gchar * new_value)
1634N/A{
1634N/A Parameter * param = getParameter(key);
1634N/A if (param) {
1634N/A if (new_value) {
1634N/A bool accepted = param->param_readSVGValue(new_value);
1634N/A if (!accepted) {
1634N/A g_warning("Effect::setParameter - '%s' not accepted for %s", new_value, key);
1634N/A }
1634N/A } else {
1634N/A // set default value
1634N/A param->param_set_default();
1634N/A }
1634N/A }
1634N/A}
1634N/A
1634N/Avoid
1634N/AEffect::registerParameter(Parameter * param)
1634N/A{
1634N/A param_vector.push_back(param);
1634N/A}
1634N/A
1634N/A// TODO: should we provide a way to alter the handle's appearance?
1634N/Avoid
1634N/AEffect::registerKnotHolderHandle(KnotHolderEntity* entity, const char* descr)
1634N/A{
1634N/A kh_entity_vector.push_back(std::make_pair(entity, descr));
1634N/A}
1634N/A
1634N/A/**
1634N/A * Add all registered LPE knotholder handles to the knotholder
1634N/A */
1634N/Avoid
1634N/AEffect::addHandles(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) {
1634N/A using namespace Inkscape::LivePathEffect;
1634N/A
1634N/A // add handles provided by the effect itself
1549N/A addKnotHolderEntities(knotholder, desktop, item);
1634N/A
1634N/A // add handles provided by the effect's parameters (if any)
1634N/A for (std::vector<Parameter *>::iterator p = param_vector.begin(); p != param_vector.end(); ++p) {
1634N/A (*p)->addKnotHolderEntities(knotholder, desktop, item);
1634N/A }
1634N/A}
1634N/A
1634N/Avoid
1634N/AEffect::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) {
1634N/A // TODO: The entities in kh_entity_vector are already instantiated during the call
1634N/A // to registerKnotHolderHandle(), but they are recreated here. Also, we must not
1634N/A // delete them when the knotholder is destroyed, whence the clumsy function
1634N/A // isDeletable(). If we could create entities of different classes dynamically,
1634N/A // this would be much nicer. How to do this?
1634N/A std::vector<std::pair<KnotHolderEntity*, const char*> >::iterator i;
1549N/A for (i = kh_entity_vector.begin(); i != kh_entity_vector.end(); ++i) {
1549N/A KnotHolderEntity *entity = i->first;
1634N/A const char *descr = i->second;
1549N/A
1634N/A entity->create(desktop, item, knotholder, descr);
1634N/A knotholder->add(entity);
1634N/A }
1634N/A}
1634N/A
1634N/A/**
1634N/A * Return a vector of PathVectors which contain all helperpaths that should be drawn by the effect.
1634N/A * This is the function called by external code like SPLPEItem.
1634N/A */
1549N/Astd::vector<Geom::PathVector>
1634N/AEffect::getHelperPaths(SPLPEItem *lpeitem)
1549N/A{
1634N/A std::vector<Geom::PathVector> hp_vec;
1634N/A
1549N/A if (!SP_IS_SHAPE(lpeitem)) {
1549N/A g_print ("How to handle helperpaths for non-shapes?\n");
1549N/A return hp_vec;
1549N/A }
1549N/A
1634N/A // TODO: we can probably optimize this by using a lot more references
1634N/A // rather than copying PathVectors all over the place
1634N/A if (show_orig_path) {
1634N/A // add original path to helperpaths
1634N/A SPCurve* curve = sp_shape_get_curve (SP_SHAPE(lpeitem));
1634N/A hp_vec.push_back(curve->get_pathvector());
1634N/A }
1634N/A
1634N/A // add other helperpaths provided by the effect itself
1634N/A addCanvasIndicators(lpeitem, hp_vec);
1634N/A
1634N/A // add helperpaths provided by the effect's parameters
1634N/A for (std::vector<Parameter *>::iterator p = param_vector.begin(); p != param_vector.end(); ++p) {
1634N/A (*p)->addCanvasIndicators(lpeitem, hp_vec);
1634N/A }
1549N/A
1634N/A return hp_vec;
1634N/A}
1634N/A
1634N/A/**
1634N/A * Add possible canvas indicators (i.e., helperpaths other than the original path) to \a hp_vec
1634N/A * This function should be overwritten by derived effects if they want to provide their own helperpaths.
1634N/A */
1634N/Avoid
1634N/AEffect::addCanvasIndicators(SPLPEItem */*lpeitem*/, std::vector<Geom::PathVector> &/*hp_vec*/)
1634N/A{
1634N/A}
1634N/A
1549N/A
1549N/A/**
1549N/A * This *creates* a new widget, management of deletion should be done by the caller
1549N/A */
1549N/AGtk::Widget *
1549N/AEffect::newWidget(Gtk::Tooltips * tooltips)
1549N/A{
1634N/A // use manage here, because after deletion of Effect object, others might still be pointing to this widget.
1549N/A Gtk::VBox * vbox = Gtk::manage( new Gtk::VBox() );
1549N/A
1634N/A vbox->set_border_width(5);
1634N/A
1634N/A std::vector<Parameter *>::iterator it = param_vector.begin();
1634N/A while (it != param_vector.end()) {
1634N/A Parameter * param = *it;
1549N/A Gtk::Widget * widg = param->param_newWidget(tooltips);
1549N/A Glib::ustring * tip = param->param_getTooltip();
1634N/A if (widg) {
1549N/A vbox->pack_start(*widg, true, true, 2);
1634N/A if (tip != NULL) {
1634N/A tooltips->set_tip(*widg, *tip);
1634N/A }
1634N/A }
1634N/A
1634N/A it++;
1634N/A }
1634N/A
1634N/A return dynamic_cast<Gtk::Widget *>(vbox);
1634N/A}
1634N/A
1634N/A
1634N/AInkscape::XML::Node *
1634N/AEffect::getRepr()
1634N/A{
1634N/A return SP_OBJECT_REPR(lpeobj);
1634N/A}
1634N/A
1634N/ASPDocument *
1634N/AEffect::getSPDoc()
1549N/A{
1634N/A if (SP_OBJECT_DOCUMENT(lpeobj) == NULL) g_message("Effect::getSPDoc() returns NULL");
return SP_OBJECT_DOCUMENT(lpeobj);
}
Parameter *
Effect::getParameter(const char * key)
{
Glib::ustring stringkey(key);
std::vector<Parameter *>::iterator it = param_vector.begin();
while (it != param_vector.end()) {
Parameter * param = *it;
if ( param->param_key == key) {
return param;
}
it++;
}
return NULL;
}
Parameter *
Effect::getNextOncanvasEditableParam()
{
if (param_vector.size() == 0) // no parameters
return NULL;
oncanvasedit_it++;
if (oncanvasedit_it >= static_cast<int>(param_vector.size())) {
oncanvasedit_it = 0;
}
int old_it = oncanvasedit_it;
do {
Parameter * param = param_vector[oncanvasedit_it];
if(param && param->oncanvas_editable) {
return param;
} else {
oncanvasedit_it++;
if (oncanvasedit_it == static_cast<int>(param_vector.size())) { // loop round the map
oncanvasedit_it = 0;
}
}
} while (oncanvasedit_it != old_it); // iterate until complete loop through map has been made
return NULL;
}
void
Effect::editNextParamOncanvas(SPItem * item, SPDesktop * desktop)
{
if (!desktop) return;
Parameter * param = getNextOncanvasEditableParam();
if (param) {
param->param_editOncanvas(item, desktop);
gchar *message = g_strdup_printf(_("Editing parameter <b>%s</b>."), param->param_label.c_str());
desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, message);
g_free(message);
} else {
desktop->messageStack()->flash( Inkscape::WARNING_MESSAGE,
_("None of the applied path effect's parameters can be edited on-canvas.") );
}
}
/* This function should reset the defaults and is used for example to initialize an effect right after it has been applied to a path
* 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!
*/
void
Effect::resetDefaults(SPItem * /*item*/)
{
// do nothing for simple effects
}
void
Effect::setup_nodepath(Inkscape::NodePath::Path *np)
{
np->helperpath_rgba = 0xff0000ff;
np->helperpath_width = 1.0;
}
void
Effect::transform_multiply(Geom::Matrix const& postmul, bool set)
{
// cycle through all parameters. Most parameters will not need transformation, but path and point params do.
for (std::vector<Parameter *>::iterator it = param_vector.begin(); it != param_vector.end(); it++) {
Parameter * param = *it;
param->param_transform_multiply(postmul, set);
}
}
// TODO: take _all_ parameters into account, not only PointParams
bool
Effect::providesKnotholder()
{
// does the effect actively provide any knotholder entities of its own?
if (kh_entity_vector.size() > 0)
return true;
// otherwise: are there any PointParams?
for (std::vector<Parameter *>::iterator p = param_vector.begin(); p != param_vector.end(); ++p) {
// if ( Inkscape::LivePathEffect::PointParam *pointparam = dynamic_cast<Inkscape::LivePathEffect::PointParam*>(*p) ) {
if (dynamic_cast<Inkscape::LivePathEffect::PointParam*>(*p)) {
return true;
}
}
return false;
}
} /* namespace LivePathEffect */
} /* namespace Inkscape */
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :