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 }
100 }
102 Glib::ustring
103 Effect::getName()
104 {
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") );
109 }
111 /*
112 * Here be the doEffect function chain:
113 */
114 void
115 Effect::doEffect (SPCurve * curve)
116 {
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 }
125 }
127 NArtBpath *
128 Effect::doEffect (NArtBpath * path_in)
129 {
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 }
156 }
158 std::vector<Geom::Path>
159 Effect::doEffect (std::vector<Geom::Path> & path_in)
160 {
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;
172 }
174 Geom::Piecewise<Geom::D2<Geom::SBasis> >
175 Effect::doEffect (Geom::Piecewise<Geom::D2<Geom::SBasis> > & pwd2_in)
176 {
177 g_warning("Effect has no doEffect implementation");
178 return pwd2_in;
179 }
181 void
182 Effect::readallParameters(Inkscape::XML::Node * repr)
183 {
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 }
193 }
195 /* This function does not and SHOULD NOT write to XML */
196 void
197 Effect::setParameter(const gchar * key, const gchar * new_value)
198 {
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 }
213 }
215 void
216 Effect::registerParameter(Parameter * param)
217 {
218 param_map[param->param_key] = param; // inserts or updates
219 }
221 Gtk::Widget *
222 Effect::getWidget()
223 {
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);
248 }
251 Inkscape::XML::Node *
252 Effect::getRepr()
253 {
254 return SP_OBJECT_REPR(lpeobj);
255 }
257 SPDocument *
258 Effect::getSPDoc()
259 {
260 if (SP_OBJECT_DOCUMENT(lpeobj) == NULL) g_message("Effect::getSPDoc() returns NULL");
261 return SP_OBJECT_DOCUMENT(lpeobj);
262 }
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 :