1 #define INKSCAPE_LIVEPATHEFFECT_CPP\r
2 \r
3 /*\r
4 * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>\r
5 *\r
6 * Released under GNU GPL, read the file 'COPYING' for more information\r
7 */\r
8 \r
9 #include "display/display-forward.h"\r
10 #include "xml/node-event-vector.h"\r
11 #include "sp-object.h"\r
12 #include "attributes.h"\r
13 \r
14 #include "desktop.h"\r
15 \r
16 #include "document.h"\r
17 #include <glibmm/i18n.h>\r
18 \r
19 #include "live_effects/effect.h"\r
20 #include "live_effects/lpeobject.h"\r
21 #include "live_effects/parameter/parameter.h"\r
22 #include <glibmm/ustring.h>\r
23 #include "live_effects/n-art-bpath-2geom.h"\r
24 #include "display/curve.h"\r
25 #include <2geom/sbasis-to-bezier.h>\r
26 #include <gtkmm.h>\r
27 \r
28 // include effects:\r
29 #include "live_effects/lpe-skeletalstrokes.h"\r
30 #include "live_effects/lpe-slant.h"\r
31 #include "live_effects/lpe-test-doEffect-stack.h"\r
32 #include "live_effects/lpe-gears.h"\r
33 #include "live_effects/lpe-curvestitch.h"\r
34 \r
35 namespace Inkscape {\r
36 \r
37 namespace LivePathEffect {\r
38 \r
39 const Util::EnumData<EffectType> LPETypeData[INVALID_LPE] = {\r
40 // {constant defined in effect.h, _("name of your effect"), "name of your effect in SVG"}\r
41 {SKELETAL_STROKES, _("Path along path"), "skeletal"},\r
42 #ifdef LPE_ENABLE_TEST_EFFECTS\r
43 {SLANT, _("Slant"), "slant"},\r
44 {DOEFFECTSTACK_TEST, _("doEffect stack test"), "doeffectstacktest"},\r
45 #endif\r
46 {GEARS, _("Gears"), "gears"},\r
47 {CURVE_STITCH, _("Curve stitching"), "curvestitching"},\r
48 };\r
49 const Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, INVALID_LPE);\r
50 \r
51 Effect*\r
52 Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj)\r
53 {\r
54 Effect* neweffect = NULL;\r
55 switch (lpenr) {\r
56 case SKELETAL_STROKES:\r
57 neweffect = (Effect*) new LPESkeletalStrokes(lpeobj);\r
58 break;\r
59 #ifdef LPE_ENABLE_TEST_EFFECTS\r
60 case SLANT:\r
61 neweffect = (Effect*) new LPESlant(lpeobj);\r
62 break;\r
63 case DOEFFECTSTACK_TEST:\r
64 neweffect = (Effect*) new LPEdoEffectStackTest(lpeobj);\r
65 break;\r
66 #endif\r
67 case GEARS:\r
68 neweffect = (Effect*) new LPEGears(lpeobj);\r
69 break;\r
70 case CURVE_STITCH:\r
71 neweffect = (Effect*) new LPECurveStitch(lpeobj);\r
72 break;\r
73 default:\r
74 g_warning("LivePathEffect::Effect::New called with invalid patheffect type (%d)", lpenr);\r
75 neweffect = NULL;\r
76 break;\r
77 }\r
78 \r
79 if (neweffect) {\r
80 neweffect->readallParameters(SP_OBJECT_REPR(lpeobj));\r
81 }\r
82 \r
83 return neweffect;\r
84 }\r
85 \r
86 Effect::Effect(LivePathEffectObject *lpeobject)\r
87 {\r
88 vbox = NULL;\r
89 tooltips = NULL;\r
90 lpeobj = lpeobject;\r
91 }\r
92 \r
93 Effect::~Effect()\r
94 {\r
95 if (tooltips) {\r
96 delete tooltips;\r
97 }\r
98 }\r
99 \r
100 Glib::ustring \r
101 Effect::getName()\r
102 {\r
103 if (lpeobj->effecttype_set && lpeobj->effecttype < INVALID_LPE)\r
104 return Glib::ustring( LPETypeConverter.get_label(lpeobj->effecttype) );\r
105 else\r
106 return Glib::ustring( _("No effect") );\r
107 }\r
108 \r
109 /*\r
110 * Here be the doEffect function chain:\r
111 */\r
112 void\r
113 Effect::doEffect (SPCurve * curve)\r
114 {\r
115 NArtBpath *new_bpath = doEffect(SP_CURVE_BPATH(curve));\r
116 \r
117 if (new_bpath) { // FIXME, add function to SPCurve to change bpath? or a copy function?\r
118 if (curve->_bpath) {\r
119 g_free(curve->_bpath); //delete old bpath\r
120 }\r
121 curve->_bpath = new_bpath;\r
122 }\r
123 }\r
124 \r
125 NArtBpath *\r
126 Effect::doEffect (NArtBpath * path_in)\r
127 {\r
128 std::vector<Geom::Path> orig_pathv = BPath_to_2GeomPath(path_in);\r
129 \r
130 std::vector<Geom::Path> result_pathv = doEffect(orig_pathv);\r
131 \r
132 NArtBpath *new_bpath = BPath_from_2GeomPath(result_pathv);\r
133 \r
134 return new_bpath;\r
135 }\r
136 \r
137 std::vector<Geom::Path>\r
138 Effect::doEffect (std::vector<Geom::Path> & path_in)\r
139 {\r
140 Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in;\r
141 \r
142 for (unsigned int i=0; i < path_in.size(); i++) {\r
143 pwd2_in.concat( path_in[i].toPwSb() );\r
144 }\r
145 \r
146 Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_out = doEffect(pwd2_in);\r
147 \r
148 std::vector<Geom::Path> path_out = Geom::path_from_piecewise( pwd2_out, LPE_CONVERSION_TOLERANCE);\r
149 \r
150 return path_out;\r
151 }\r
152 \r
153 Geom::Piecewise<Geom::D2<Geom::SBasis> >\r
154 Effect::doEffect (Geom::Piecewise<Geom::D2<Geom::SBasis> > & pwd2_in)\r
155 {\r
156 g_warning("Effect has no doEffect implementation");\r
157 return pwd2_in;\r
158 }\r
159 \r
160 void\r
161 Effect::readallParameters(Inkscape::XML::Node * repr)\r
162 {\r
163 param_map_type::iterator it = param_map.begin();\r
164 while (it != param_map.end()) {\r
165 const gchar * key = (*it).first.c_str();\r
166 const gchar * value = repr->attribute(key);\r
167 if(value) {\r
168 setParameter(repr, key, NULL, value);\r
169 }\r
170 it++;\r
171 }\r
172 }\r
173 \r
174 void\r
175 Effect::setParameter(Inkscape::XML::Node * repr, const gchar * key, const gchar * old_value, const gchar * new_value)\r
176 {\r
177 Glib::ustring stringkey(key);\r
178 \r
179 param_map_type::iterator it = param_map.find(stringkey);\r
180 if (it != param_map.end()) {\r
181 if (new_value) {\r
182 bool accepted = it->second->param_readSVGValue(new_value);\r
183 if (!accepted) { \r
184 g_warning("Effect::setParameter - '%s' not accepted for %s", new_value, key);\r
185 // change was not accepted, so change it back.\r
186 // think: can this backfire and create infinite loop when started with unacceptable old_value?\r
187 // repr->setAttribute(key, old_value);\r
188 }\r
189 } else {\r
190 // set default value\r
191 it->second->param_set_default();\r
192 }\r
193 }\r
194 }\r
195 \r
196 void\r
197 Effect::registerParameter(Parameter * param)\r
198 {\r
199 param_map[param->param_key] = param; // inserts or updates\r
200 }\r
201 \r
202 Gtk::Widget *\r
203 Effect::getWidget()\r
204 {\r
205 if (!vbox) {\r
206 vbox = Gtk::manage( new Gtk::VBox() ); // use manage here, because after deletion of Effect object, others might still be pointing to this widget.\r
207 //if (!tooltips)\r
208 tooltips = new Gtk::Tooltips();\r
209 \r
210 vbox->set_border_width(5);\r
211 \r
212 param_map_type::iterator it = param_map.begin();\r
213 while (it != param_map.end()) {\r
214 Parameter * param = it->second;\r
215 Gtk::Widget * widg = param->param_getWidget();\r
216 Glib::ustring * tip = param->param_getTooltip();\r
217 if (widg) {\r
218 vbox->pack_start(*widg, true, true, 2);\r
219 if (tip != NULL) {\r
220 tooltips->set_tip(*widg, *tip);\r
221 }\r
222 }\r
223 \r
224 it++;\r
225 }\r
226 }\r
227 \r
228 return dynamic_cast<Gtk::Widget *>(vbox);\r
229 }\r
230 \r
231 \r
232 Inkscape::XML::Node * \r
233 Effect::getRepr()\r
234 {\r
235 return SP_OBJECT_REPR(lpeobj);\r
236 }\r
237 \r
238 SPDocument * \r
239 Effect::getSPDoc()\r
240 {\r
241 if (SP_OBJECT_DOCUMENT(lpeobj) == NULL) g_message("Effect::getSPDoc() returns NULL");\r
242 return SP_OBJECT_DOCUMENT(lpeobj);\r
243 }\r
244 \r
245 \r
246 } /* namespace LivePathEffect */\r
247 \r
248 } /* namespace Inkscape */\r
249 \r
250 /*\r
251 Local Variables:\r
252 mode:c++\r
253 c-file-style:"stroustrup"\r
254 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
255 indent-tabs-mode:nil\r
256 fill-column:99\r
257 End:\r
258 */\r
259 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :\r