Code

LPE: add on-canvas editing of path parameters!
[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 "display/display-forward.h"
10 #include "xml/node-event-vector.h"
11 #include "sp-object.h"
12 #include "attributes.h"
13 #include "message-stack.h"
14 #include "desktop.h"
15 #include "inkscape.h"
16 #include "document.h"
17 #include <glibmm/i18n.h>
19 #include "live_effects/effect.h"
20 #include "live_effects/lpeobject.h"
21 #include "live_effects/parameter/parameter.h"
22 #include <glibmm/ustring.h>
23 #include "live_effects/n-art-bpath-2geom.h"
24 #include "display/curve.h"
25 #include <2geom/sbasis-to-bezier.h>
26 #include <gtkmm.h>
28 #include <exception>
30 // include effects:
31 #include "live_effects/lpe-skeletalstrokes.h"
32 #include "live_effects/lpe-slant.h"
33 #include "live_effects/lpe-test-doEffect-stack.h"
34 #include "live_effects/lpe-gears.h"
35 #include "live_effects/lpe-curvestitch.h"
37 namespace Inkscape {
39 namespace LivePathEffect {
41 const Util::EnumData<EffectType> LPETypeData[INVALID_LPE] = {
42     // {constant defined in effect.h, N_("name of your effect"), "name of your effect in SVG"}
43     {SKELETAL_STROKES,      N_("Path along path"),      "skeletal"},
44 #ifdef LPE_ENABLE_TEST_EFFECTS
45     {SLANT,                 N_("Slant"),                 "slant"},
46     {DOEFFECTSTACK_TEST,    N_("doEffect stack test"),   "doeffectstacktest"},
47 #endif
48     {GEARS,                 N_("Gears"),                 "gears"},
49     {CURVE_STITCH,          N_("Curve stitching"),       "curvestitching"},
50 };
51 const Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, INVALID_LPE);
53 Effect*
54 Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj)
55 {
56     Effect* neweffect = NULL;
57     switch (lpenr) {
58         case SKELETAL_STROKES:
59             neweffect = (Effect*) new LPESkeletalStrokes(lpeobj);
60             break;
61 #ifdef LPE_ENABLE_TEST_EFFECTS
62             case SLANT:
63             neweffect = (Effect*) new LPESlant(lpeobj);
64             break;
65         case DOEFFECTSTACK_TEST:
66             neweffect = (Effect*) new LPEdoEffectStackTest(lpeobj);
67             break;
68 #endif
69         case GEARS:
70             neweffect = (Effect*) new LPEGears(lpeobj);
71             break;
72         case CURVE_STITCH:
73             neweffect = (Effect*) new LPECurveStitch(lpeobj);
74             break;
75         default:
76             g_warning("LivePathEffect::Effect::New   called with invalid patheffect type (%d)", lpenr);
77             neweffect = NULL;
78             break;
79     }
81     if (neweffect) {
82         neweffect->readallParameters(SP_OBJECT_REPR(lpeobj));
83     }
85     return neweffect;
86 }
88 Effect::Effect(LivePathEffectObject *lpeobject)
89 {
90     vbox = NULL;
91     tooltips = NULL;
92     lpeobj = lpeobject;
93 }
95 Effect::~Effect()
96 {
97     if (tooltips) {
98         delete tooltips;
99     }
102 Glib::ustring 
103 Effect::getName()
105     if (lpeobj->effecttype_set && lpeobj->effecttype < INVALID_LPE)
106         return Glib::ustring( _(LPETypeConverter.get_label(lpeobj->effecttype).c_str()) );
107     else
108         return Glib::ustring( _("No effect") );
111 /*
112  *  Here be the doEffect function chain:
113  */
114 void
115 Effect::doEffect (SPCurve * curve)
117     NArtBpath *new_bpath = doEffect(SP_CURVE_BPATH(curve));
119     if (new_bpath && new_bpath != SP_CURVE_BPATH(curve)) {        // FIXME, add function to SPCurve to change bpath? or a copy function?
120         if (curve->_bpath) {
121             g_free(curve->_bpath); //delete old bpath
122         }
123         curve->_bpath = new_bpath;
124     }
127 NArtBpath *
128 Effect::doEffect (NArtBpath * path_in)
130     try {
131         std::vector<Geom::Path> orig_pathv = BPath_to_2GeomPath(path_in);
133         std::vector<Geom::Path> result_pathv = doEffect(orig_pathv);
135         NArtBpath *new_bpath = BPath_from_2GeomPath(result_pathv);
137         return new_bpath;
138     }
139     catch (std::exception e) {
140         g_warning("An exception occurred during execution of an LPE - %s", e.what());
141         SP_ACTIVE_DESKTOP->messageStack()->flash( Inkscape::WARNING_MESSAGE,
142             _("An exception occurred during execution of a Path Effect.") );
144         NArtBpath *path_out;
146         unsigned ret = 0;
147         while ( path_in[ret].code != NR_END ) {
148             ++ret;
149         }
150         unsigned len = ++ret;
152         path_out = g_new(NArtBpath, len);
153         memcpy(path_out, path_in, len * sizeof(NArtBpath));
154         return path_out;
155     }
158 std::vector<Geom::Path>
159 Effect::doEffect (std::vector<Geom::Path> & path_in)
161     Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in;
163     for (unsigned int i=0; i < path_in.size(); i++) {
164         pwd2_in.concat( path_in[i].toPwSb() );
165     }
167     Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_out = doEffect(pwd2_in);
169     std::vector<Geom::Path> path_out = Geom::path_from_piecewise( pwd2_out, LPE_CONVERSION_TOLERANCE);
171     return path_out;
174 Geom::Piecewise<Geom::D2<Geom::SBasis> >
175 Effect::doEffect (Geom::Piecewise<Geom::D2<Geom::SBasis> > & pwd2_in)
177     g_warning("Effect has no doEffect implementation");
178     return pwd2_in;
181 void
182 Effect::readallParameters(Inkscape::XML::Node * repr)
184     param_map_type::iterator it = param_map.begin();
185     while (it != param_map.end()) {
186         const gchar * key = (*it).first.c_str();
187         const gchar * value = repr->attribute(key);
188         if(value) {
189             setParameter(key, value);
190         }
191         it++;
192     }
195 /* This function does not and SHOULD NOT write to XML */
196 void
197 Effect::setParameter(const gchar * key, const gchar * new_value)
199     Glib::ustring stringkey(key);
201     param_map_type::iterator it = param_map.find(stringkey);
202     if (it != param_map.end()) {
203         if (new_value) {
204             bool accepted = it->second->param_readSVGValue(new_value);
205             if (!accepted) { 
206                 g_warning("Effect::setParameter - '%s' not accepted for %s", new_value, key);
207             }
208         } else {
209             // set default value
210             it->second->param_set_default();
211         }
212     }
215 void
216 Effect::registerParameter(Parameter * param)
218     param_map[param->param_key] = param; // inserts or updates
221 Gtk::Widget *
222 Effect::getWidget()
224     if (!vbox) {
225         vbox = Gtk::manage( new Gtk::VBox() ); // use manage here, because after deletion of Effect object, others might still be pointing to this widget.
226         //if (!tooltips)
227             tooltips = new Gtk::Tooltips();
229         vbox->set_border_width(5);
231         param_map_type::iterator it = param_map.begin();
232         while (it != param_map.end()) {
233             Parameter * param = it->second;
234             Gtk::Widget * widg = param->param_getWidget();
235             Glib::ustring * tip = param->param_getTooltip();
236             if (widg) {
237                vbox->pack_start(*widg, true, true, 2);
238                 if (tip != NULL) {
239                     tooltips->set_tip(*widg, *tip);
240                 }
241             }
243             it++;
244         }
245     }
247     return dynamic_cast<Gtk::Widget *>(vbox);
251 Inkscape::XML::Node * 
252 Effect::getRepr()
254     return SP_OBJECT_REPR(lpeobj);
257 SPDocument * 
258 Effect::getSPDoc()
260     if (SP_OBJECT_DOCUMENT(lpeobj) == NULL) g_message("Effect::getSPDoc() returns NULL");
261     return SP_OBJECT_DOCUMENT(lpeobj);
265 } /* namespace LivePathEffect */
267 } /* namespace Inkscape */
269 /*
270   Local Variables:
271   mode:c++
272   c-file-style:"stroustrup"
273   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
274   indent-tabs-mode:nil
275   fill-column:99
276   End:
277 */
278 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :