]> git.mxchange.org Git - simgear.git/blob - simgear/canvas/elements/CanvasElement.hxx
136fd5fc3a03ccd08faccbff5414500a406602a4
[simgear.git] / simgear / canvas / elements / CanvasElement.hxx
1 // Interface for 2D Canvas elements
2 //
3 // Copyright (C) 2012  Thomas Geymayer <tomgey@gmail.com>
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Library General Public
7 // License as published by the Free Software Foundation; either
8 // version 2 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // Library General Public License for more details.
14 //
15 // You should have received a copy of the GNU Library General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
18
19 #ifndef CANVAS_ELEMENT_HXX_
20 #define CANVAS_ELEMENT_HXX_
21
22 #include <simgear/canvas/canvas_fwd.hxx>
23 #include <simgear/canvas/CanvasEvent.hxx>
24 #include <simgear/props/PropertyBasedElement.hxx>
25 #include <simgear/misc/stdint.hxx> // for uint32_t
26 #include <simgear/nasal/cppbind/Ghost.hxx>
27
28 #include <osg/BoundingBox>
29 #include <osg/MatrixTransform>
30
31 #include <boost/bind.hpp>
32 #include <boost/function.hpp>
33
34 namespace osg
35 {
36   class Drawable;
37 }
38
39 namespace simgear
40 {
41 namespace canvas
42 {
43
44   class Element:
45     public PropertyBasedElement
46   {
47     public:
48       typedef boost::function<bool(Element&, const SGPropertyNode*)>
49               StyleSetterFunc;
50       typedef boost::function<void(Element&, const SGPropertyNode*)>
51               StyleSetterFuncUnchecked;
52       struct StyleSetter:
53         public SGReferenced
54       {
55         StyleSetterFunc func;
56         SGSharedPtr<StyleSetter> next;
57       };
58       struct StyleInfo
59       {
60         StyleSetter setter; ///!< Function(s) for setting this style
61         std::string type;   ///!< Interpolation type
62       };
63
64       /**
65        * Remove the property listener of the element.
66        *
67        * You will need to call the appropriate methods (#childAdded,
68        * #childRemoved, #valueChanged) yourself to ensure the element still
69        * receives the needed events.
70        */
71       void removeListener();
72
73       /**
74        *
75        */
76       virtual ~Element() = 0;
77
78       ElementWeakPtr getWeakPtr() const;
79
80       /**
81        * Called every frame to update internal state
82        *
83        * @param dt  Frame time in seconds
84        */
85       virtual void update(double dt);
86
87       naRef addEventListener(const nasal::CallContext& ctx);
88       virtual void clearEventListener();
89
90       virtual bool accept(EventVisitor& visitor);
91       virtual bool ascend(EventVisitor& visitor);
92       virtual bool traverse(EventVisitor& visitor);
93
94       virtual bool handleEvent(canvas::EventPtr event);
95
96       virtual bool hitBound( const osg::Vec2f& pos,
97                              const osg::Vec2f& local_pos ) const;
98
99       /**
100        * Get whether the element is visible or hidden (Can be changed with
101        * setting property "visible" accordingly).
102        */
103       bool isVisible() const;
104
105       osg::ref_ptr<osg::MatrixTransform> getMatrixTransform();
106
107       virtual void childAdded( SGPropertyNode * parent,
108                                SGPropertyNode * child );
109       virtual void childRemoved( SGPropertyNode * parent,
110                                  SGPropertyNode * child );
111       virtual void valueChanged(SGPropertyNode * child);
112
113       virtual bool setStyle(const SGPropertyNode* child);
114
115       /**
116        * Set clipping shape
117        *
118        * @note Only "rect(<top>, <right>, <bottom>, <left>)" is supported
119        * @see http://www.w3.org/TR/CSS21/visufx.html#propdef-clip
120        */
121       void setClip(const std::string& clip);
122
123       /**
124        * Write the given bounding box to the property tree
125        */
126       void setBoundingBox(const osg::BoundingBox& bb);
127
128       /**
129        * Get bounding box with children/drawables transformed by passed matrix
130        */
131       virtual osg::BoundingBox getTransformedBounds(const osg::Matrix& m) const;
132
133     protected:
134
135       enum Attributes
136       {
137         BLEND_FUNC = 0x0001,
138         LAST_ATTRIBUTE  = BLEND_FUNC << 1
139       };
140
141       enum TransformType
142       {
143         TT_NONE,
144         TT_MATRIX,
145         TT_TRANSLATE,
146         TT_ROTATE,
147         TT_SCALE
148       };
149
150       CanvasWeakPtr _canvas;
151       Element      *_parent;
152
153       uint32_t _attributes_dirty;
154
155       bool _transform_dirty;
156       osg::ref_ptr<osg::MatrixTransform>    _transform;
157       std::vector<TransformType>            _transform_types;
158
159       Style                             _style;
160       std::vector<SGPropertyNode_ptr>   _bounding_box;
161
162       typedef std::vector<EventListenerPtr> Listener;
163       typedef std::map<Event::Type, Listener> ListenerMap;
164
165       ListenerMap _listener;
166
167       typedef std::map<std::string, StyleInfo> StyleSetters;
168       static StyleSetters       _style_setters;
169
170       Element( const CanvasWeakPtr& canvas,
171                const SGPropertyNode_ptr& node,
172                const Style& parent_style,
173                Element* parent );
174
175       /**
176        * Returns false on first call and true on any successive call. Use to
177        * perform initialization tasks which are only required once per element
178        * type.
179        *
180        * @tparam Derived    (Derived) class type
181        */
182       template<class Derived>
183       bool isInit() const
184       {
185         static bool is_init = false;
186         if( is_init )
187           return true;
188
189         is_init = true;
190         return false;
191       }
192
193       /**
194        * Register a function for setting a style specified by the given property
195        *
196        * @param name    Property name
197        * @param type    Interpolation type
198        * @param setter  Setter function
199        *
200        * @tparam T1         Type of value used to retrieve value from property
201        *                    node
202        * @tparam T2         Type of value the setter function expects
203        * @tparam Derived    Type of class the setter can be applied to
204        *
205        * @note T1 needs to be convertible to T2
206        */
207       template<
208         typename T1,
209         typename T2,
210         class Derived
211       >
212       StyleSetter
213       addStyle( const std::string& name,
214                 const std::string& type,
215                 const boost::function<void (Derived&, T2)>& setter )
216       {
217         StyleInfo& style_info = _style_setters[ name ];
218         if( !type.empty() )
219         {
220           if( !style_info.type.empty() && type != style_info.type )
221             SG_LOG
222             (
223               SG_GENERAL,
224               SG_WARN,
225               "changing animation type for '" << name << "': "
226                 << style_info.type << " -> " << type
227             );
228
229           style_info.type = type;
230         }
231
232         StyleSetter* style = &style_info.setter;
233         while( style->next )
234           style = style->next;
235         if( style->func )
236           style = style->next = new StyleSetter;
237
238         style->func = boost::bind
239         (
240           &type_match<Derived>::call,
241           _1,
242           _2,
243           bindStyleSetter<T1>(name, setter)
244         );
245         return *style;
246       }
247
248       template<
249         typename T,
250         class Derived
251       >
252       StyleSetter
253       addStyle( const std::string& name,
254                 const std::string& type,
255                 const boost::function<void (Derived&, T)>& setter )
256       {
257         return addStyle<T, T>(name, type, setter);
258       }
259
260       template<
261         typename T,
262         class Derived
263       >
264       StyleSetter
265       addStyle( const std::string& name,
266                 const std::string& type,
267                 void (Derived::*setter)(T) )
268       {
269         return addStyle<T, T>
270         (
271           name,
272           type,
273           boost::function<void (Derived&, T)>(setter)
274         );
275       }
276
277       template<
278         typename T1,
279         typename T2,
280         class Derived
281       >
282       StyleSetterFunc
283       addStyle( const std::string& name,
284                 const std::string& type,
285                 void (Derived::*setter)(T2) )
286       {
287         return addStyle<T1>
288         (
289           name,
290           type,
291           boost::function<void (Derived&, T2)>(setter)
292         );
293       }
294
295       template<
296         class Derived
297       >
298       StyleSetter
299       addStyle( const std::string& name,
300                 const std::string& type,
301                 void (Derived::*setter)(const std::string&) )
302       {
303         return addStyle<const char*, const std::string&>
304         (
305           name,
306           type,
307           boost::function<void (Derived&, const std::string&)>(setter)
308         );
309       }
310
311       template<
312         typename T,
313         class Derived,
314         class Other,
315         class OtherRef
316       >
317       StyleSetter
318       addStyle( const std::string& name,
319                 const std::string& type,
320                 void (Other::*setter)(T),
321                 OtherRef Derived::*instance_ref )
322       {
323         return addStyle<T, T>(name, type, bindOther(setter, instance_ref));
324       }
325
326       template<
327         typename T1,
328         typename T2,
329         class Derived,
330         class Other,
331         class OtherRef
332       >
333       StyleSetter
334       addStyle( const std::string& name,
335                 const std::string& type,
336                 void (Other::*setter)(T2),
337                 OtherRef Derived::*instance_ref )
338       {
339         return addStyle<T1>(name, type, bindOther(setter, instance_ref));
340       }
341
342       template<
343         typename T1,
344         typename T2,
345         class Derived,
346         class Other,
347         class OtherRef
348       >
349       StyleSetter
350       addStyle( const std::string& name,
351                 const std::string& type,
352                 const boost::function<void (Other&, T2)>& setter,
353                 OtherRef Derived::*instance_ref )
354       {
355         return addStyle<T1>(name, type, bindOther(setter, instance_ref));
356       }
357
358       template<
359         class Derived,
360         class Other,
361         class OtherRef
362       >
363       StyleSetter
364       addStyle( const std::string& name,
365                 const std::string& type,
366                 void (Other::*setter)(const std::string&),
367                 OtherRef Derived::*instance_ref )
368       {
369         return addStyle<const char*, const std::string&>
370         (
371           name,
372           type,
373           boost::function<void (Other&, const std::string&)>(setter),
374           instance_ref
375         );
376       }
377
378       template<typename T, class Derived, class Other, class OtherRef>
379       boost::function<void (Derived&, T)>
380       bindOther( void (Other::*setter)(T), OtherRef Derived::*instance_ref )
381       {
382         return boost::bind(setter, boost::bind(instance_ref, _1), _2);
383       }
384
385       template<typename T, class Derived, class Other, class OtherRef>
386       boost::function<void (Derived&, T)>
387       bindOther( const boost::function<void (Other&, T)>& setter,
388                  OtherRef Derived::*instance_ref )
389       {
390         return boost::bind
391         (
392           setter,
393           boost::bind
394           (
395             &reference_from_pointer<Other, OtherRef>,
396             boost::bind(instance_ref, _1)
397           ),
398           _2
399         );
400       }
401
402       template<typename T1, typename T2, class Derived>
403       StyleSetterFuncUnchecked
404       bindStyleSetter( const std::string& name,
405                        const boost::function<void (Derived&, T2)>& setter )
406       {
407         return boost::bind
408         (
409           setter,
410           // We will only call setters with Derived instances, so we can safely
411           // cast here.
412           boost::bind(&derived_cast<Derived>, _1),
413           boost::bind(&getValue<T1>, _2)
414         );
415       }
416
417       virtual void childAdded(SGPropertyNode * child)  {}
418       virtual void childRemoved(SGPropertyNode * child){}
419       virtual void childChanged(SGPropertyNode * child){}
420
421       void setDrawable(osg::Drawable* drawable);
422
423       /**
424        * Get stateset of drawable if available or use transform otherwise
425        */
426       osg::StateSet* getOrCreateStateSet();
427
428       void setupStyle();
429
430     private:
431
432       osg::ref_ptr<osg::Drawable> _drawable;
433
434       Element(const Element&);// = delete
435
436       template<class Derived>
437       static Derived& derived_cast(Element& el)
438       {
439         return static_cast<Derived&>(el);
440       }
441
442       template<class T, class SharedPtr>
443       static T& reference_from_pointer(const SharedPtr& p)
444       {
445         return *get_pointer(p);
446       }
447
448       /**
449        * Helper to call a function only of the element type can be converted to
450        * the required type.
451        *
452        * @return Whether the function has been called
453        */
454       template<class Derived>
455       struct type_match
456       {
457         static bool call( Element& el,
458                           const SGPropertyNode* prop,
459                           const StyleSetterFuncUnchecked& func )
460         {
461           Derived* d = dynamic_cast<Derived*>(&el);
462           if( !d )
463             return false;
464           func(*d, prop);
465           return true;
466         }
467       };
468   };
469
470 } // namespace canvas
471 } // namespace simgear
472
473 #endif /* CANVAS_ELEMENT_HXX_ */