Code

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