Code

fixing wrong includes
[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 "display/display-forward.h"
12 #include "xml/node-event-vector.h"
13 #include "sp-object.h"
14 #include "attributes.h"
15 #include "message-stack.h"
16 #include "desktop.h"
17 #include "inkscape.h"
18 #include "document.h"
19 #include <glibmm/i18n.h>
21 #include "live_effects/lpeobject.h"
22 #include "live_effects/parameter/parameter.h"
23 #include <glibmm/ustring.h>
24 #include "live_effects/n-art-bpath-2geom.h"
25 #include "display/curve.h"
26 #include <gtkmm.h>
28 #include <exception>
30 #include <2geom/sbasis-to-bezier.h>
31 #include <2geom/matrix.h>
34 // include effects:
35 #include "live_effects/lpe-skeletalstrokes.h"
36 #include "live_effects/lpe-pathalongpath.h"
37 //here!!
38 #include "live_effects/lpe-sketch.h"
39 #include "live_effects/lpe-vonkoch.h"
40 #include "live_effects/lpe-knot.h"
41 #include "live_effects/lpe-slant.h"
42 #include "live_effects/lpe-test-doEffect-stack.h"
43 #include "live_effects/lpe-gears.h"
44 #include "live_effects/lpe-curvestitch.h"
46 #include "nodepath.h"
48 namespace Inkscape {
50 namespace LivePathEffect {
52 const Util::EnumData<EffectType> LPETypeData[INVALID_LPE] = {
53     // {constant defined in effect.h, N_("name of your effect"), "name of your effect in SVG"}
54     {PATH_ALONG_PATH,       N_("Bend Path"),             "bend_path"},
55     {SKELETAL_STROKES,      N_("Pattern Along Path"),    "skeletal"},
56     {SKETCH,                N_("Sketch"),                "sketch"},
57     {VONKOCH,               N_("VonKoch"),               "vonkoch"},
58     {KNOT,                  N_("Knot"),                  "knot"},
59 #ifdef LPE_ENABLE_TEST_EFFECTS
60     {SLANT,                 N_("Slant"),                 "slant"},
61     {DOEFFECTSTACK_TEST,    N_("doEffect stack test"),   "doeffectstacktest"},
62 #endif
63     {GEARS,                 N_("Gears"),                 "gears"},
64     {CURVE_STITCH,          N_("Stitch Sub-Paths"),       "curvestitching"},
65 };
66 const Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, INVALID_LPE);
68 Effect*
69 Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj)
70 {
71     Effect* neweffect = NULL;
72     switch (lpenr) {
73         case SKELETAL_STROKES:
74             neweffect = (Effect*) new LPESkeletalStrokes(lpeobj);
75             break;
76         case PATH_ALONG_PATH:
77             neweffect = (Effect*) new LPEPathAlongPath(lpeobj);
78             break;
79 //here!!
80         case SKETCH:
81             neweffect = (Effect*) new LPESketch(lpeobj);
82             break;
83         case VONKOCH:
84             neweffect = (Effect*) new LPEVonKoch(lpeobj);
85             break;
86         case KNOT:
87             neweffect = (Effect*) new LPEKnot(lpeobj);
88             break;
89 #ifdef LPE_ENABLE_TEST_EFFECTS
90             case SLANT:
91             neweffect = (Effect*) new LPESlant(lpeobj);
92             break;
93         case DOEFFECTSTACK_TEST:
94             neweffect = (Effect*) new LPEdoEffectStackTest(lpeobj);
95             break;
96 #endif
97         case GEARS:
98             neweffect = (Effect*) new LPEGears(lpeobj);
99             break;
100         case CURVE_STITCH:
101             neweffect = (Effect*) new LPECurveStitch(lpeobj);
102             break;
103         default:
104             g_warning("LivePathEffect::Effect::New   called with invalid patheffect type (%d)", lpenr);
105             neweffect = NULL;
106             break;
107     }
109     if (neweffect) {
110         neweffect->readallParameters(SP_OBJECT_REPR(lpeobj));
111     }
113     return neweffect;
116 Effect::Effect(LivePathEffectObject *lpeobject)
118     lpeobj = lpeobject;
119     oncanvasedit_it = 0;
122 Effect::~Effect()
126 Glib::ustring
127 Effect::getName()
129     if (lpeobj->effecttype_set && lpeobj->effecttype < INVALID_LPE)
130         return Glib::ustring( _(LPETypeConverter.get_label(lpeobj->effecttype).c_str()) );
131     else
132         return Glib::ustring( _("No effect") );
135 /*
136  *  Here be the doEffect function chain:
137  */
138 void
139 Effect::doEffect (SPCurve * curve)
141     NArtBpath *new_bpath = doEffect_nartbpath(SP_CURVE_BPATH(curve));
143     if (new_bpath && new_bpath != SP_CURVE_BPATH(curve)) {        // FIXME, add function to SPCurve to change bpath? or a copy function?
144         if (curve->_bpath) {
145             g_free(curve->_bpath); //delete old bpath
146         }
147         curve->_bpath = new_bpath;
148     }
151 NArtBpath *
152 Effect::doEffect_nartbpath (NArtBpath * path_in)
154     try {
155         std::vector<Geom::Path> orig_pathv = BPath_to_2GeomPath(path_in);
157         std::vector<Geom::Path> result_pathv = doEffect_path(orig_pathv);
159         NArtBpath *new_bpath = BPath_from_2GeomPath(result_pathv);
161         return new_bpath;
162     }
163     catch (std::exception & e) {
164         g_warning("Exception during LPE %s execution. \n %s", getName().c_str(), e.what());
165         SP_ACTIVE_DESKTOP->messageStack()->flash( Inkscape::WARNING_MESSAGE,
166             _("An exception occurred during execution of the Path Effect.") );
168         NArtBpath *path_out;
170         unsigned ret = 0;
171         while ( path_in[ret].code != NR_END ) {
172             ++ret;
173         }
174         unsigned len = ++ret;
176         path_out = g_new(NArtBpath, len);
177         memcpy(path_out, path_in, len * sizeof(NArtBpath));
178         return path_out;
179     }
182 std::vector<Geom::Path>
183 Effect::doEffect_path (std::vector<Geom::Path> & path_in)
185     Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in;
187     for (unsigned int i=0; i < path_in.size(); i++) {
188         pwd2_in.concat( path_in[i].toPwSb() );
189     }
191     Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_out = doEffect_pwd2(pwd2_in);
193     std::vector<Geom::Path> path_out = Geom::path_from_piecewise( pwd2_out, LPE_CONVERSION_TOLERANCE);
195     return path_out;
198 Geom::Piecewise<Geom::D2<Geom::SBasis> >
199 Effect::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > & pwd2_in)
201     g_warning("Effect has no doEffect implementation");
202     return pwd2_in;
205 void
206 Effect::readallParameters(Inkscape::XML::Node * repr)
208     std::vector<Parameter *>::iterator it = param_vector.begin();
209     while (it != param_vector.end()) {
210         Parameter * param = *it;
211         const gchar * key = param->param_key.c_str();
212         const gchar * value = repr->attribute(key);
213         if (value) {
214             bool accepted = param->param_readSVGValue(value);
215             if (!accepted) { 
216                 g_warning("Effect::readallParameters - '%s' not accepted for %s", value, key);
217             }
218         } else {
219             // set default value
220             param->param_set_default();
221         }
223         it++;
224     }
227 /* This function does not and SHOULD NOT write to XML */
228 void
229 Effect::setParameter(const gchar * key, const gchar * new_value)
231     Parameter * param = getParameter(key);
232     if (param) {
233         if (new_value) {
234             bool accepted = param->param_readSVGValue(new_value);
235             if (!accepted) { 
236                 g_warning("Effect::setParameter - '%s' not accepted for %s", new_value, key);
237             }
238         } else {
239             // set default value
240             param->param_set_default();
241         }
242     }
245 void
246 Effect::registerParameter(Parameter * param)
248     param_vector.push_back(param);
251 /**
252 * This *creates* a new widget, management of deletion should be done by the caller
253 */
254 Gtk::Widget *
255 Effect::newWidget(Gtk::Tooltips * tooltips)
257     // use manage here, because after deletion of Effect object, others might still be pointing to this widget.
258     Gtk::VBox * vbox = Gtk::manage( new Gtk::VBox() );
260     vbox->set_border_width(5);
262     std::vector<Parameter *>::iterator it = param_vector.begin();
263     while (it != param_vector.end()) {
264         Parameter * param = *it;
265         Gtk::Widget * widg = param->param_newWidget(tooltips);
266         Glib::ustring * tip = param->param_getTooltip();
267         if (widg) {
268            vbox->pack_start(*widg, true, true, 2);
269             if (tip != NULL) {
270                 tooltips->set_tip(*widg, *tip);
271             }
272         }
274         it++;
275     }
277     return dynamic_cast<Gtk::Widget *>(vbox);
281 Inkscape::XML::Node *
282 Effect::getRepr()
284     return SP_OBJECT_REPR(lpeobj);
287 SPDocument *
288 Effect::getSPDoc()
290     if (SP_OBJECT_DOCUMENT(lpeobj) == NULL) g_message("Effect::getSPDoc() returns NULL");
291     return SP_OBJECT_DOCUMENT(lpeobj);
294 Parameter *
295 Effect::getParameter(const char * key)
297     Glib::ustring stringkey(key);
299     std::vector<Parameter *>::iterator it = param_vector.begin();
300     while (it != param_vector.end()) {
301         Parameter * param = *it;
302         if ( param->param_key == key) {
303             return param;
304         }
306         it++;
307     }
309     return NULL;
312 Parameter *
313 Effect::getNextOncanvasEditableParam()
315     oncanvasedit_it++;
316     if (oncanvasedit_it == static_cast<int>(param_vector.size())) {
317         oncanvasedit_it = 0;
318     }
319     int old_it = oncanvasedit_it;
321     do {
322         Parameter * param = param_vector[oncanvasedit_it];
323         if(param && param->oncanvas_editable) {
324             return param;
325         } else {
326             oncanvasedit_it++;
327             if (oncanvasedit_it == static_cast<int>(param_vector.size())) {  // loop round the map
328                 oncanvasedit_it = 0;
329             }
330         }
331     } while (oncanvasedit_it != old_it); // iterate until complete loop through map has been made
333     return NULL;
336 void
337 Effect::editNextParamOncanvas(SPItem * item, SPDesktop * desktop)
339     if (!desktop) return;
341     Parameter * param = getNextOncanvasEditableParam();
342     if (param) {
343         param->param_editOncanvas(item, desktop);
344         gchar *message = g_strdup_printf(_("Editing parameter <b>%s</b>."), param->param_label.c_str());
345         desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, message);
346         g_free(message);
347     } else {
348         desktop->messageStack()->flash( Inkscape::WARNING_MESSAGE,
349                                         _("None of the applied path effect's parameters can be edited on-canvas.") );
350     }
353 /* This function should reset the defaults and is used for example to initialize an effect right after it has been applied to a path
354 * 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!
355 */
356 void
357 Effect::resetDefaults(SPItem * /*item*/)
359     // do nothing for simple effects
362 void
363 Effect::setup_nodepath(Inkscape::NodePath::Path *np)
365     np->show_helperpath = true;
366     np->helperpath_rgba = 0xff0000ff;
367     np->helperpath_width = 1.0;
370 void
371 Effect::transform_multiply(Geom::Matrix const& postmul, bool set)
373     // cycle through all parameters. Most parameters will not need transformation, but path and point params do.
374     for (std::vector<Parameter *>::iterator it = param_vector.begin(); it != param_vector.end(); it++) {
375         Parameter * param = *it;
376         param->param_transform_multiply(postmul, set);
377     }
380 } /* namespace LivePathEffect */
382 } /* namespace Inkscape */
384 /*
385   Local Variables:
386   mode:c++
387   c-file-style:"stroustrup"
388   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
389   indent-tabs-mode:nil
390   fill-column:99
391   End:
392 */
393 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :