]> git.mxchange.org Git - simgear.git/blob - simgear/canvas/elements/CanvasElement.hxx
Canvas: simplify code by using new nasal function conversion.
[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
27 #include <osg/BoundingBox>
28 #include <osg/MatrixTransform>
29
30 #include <boost/bind.hpp>
31 #include <boost/function.hpp>
32 #include <boost/type_traits/is_base_of.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
49       /**
50        * Store pointer to window as user data
51        */
52       class OSGUserData:
53         public osg::Referenced
54       {
55         public:
56           ElementPtr element;
57           OSGUserData(ElementPtr element);
58       };
59
60       typedef boost::function<bool(Element&, const SGPropertyNode*)>
61               StyleSetterFunc;
62       typedef boost::function<void(Element&, const SGPropertyNode*)>
63               StyleSetterFuncUnchecked;
64       struct StyleSetter:
65         public SGReferenced
66       {
67         StyleSetterFunc func;
68         SGSharedPtr<StyleSetter> next;
69       };
70       struct StyleInfo
71       {
72         StyleSetter setter; ///!< Function(s) for setting this style
73         std::string type;   ///!< Interpolation type
74         bool inheritable;   ///!< Whether children can inherit this style from
75                             ///   their parents
76       };
77
78       /**
79        *
80        */
81       virtual ~Element() = 0;
82
83       virtual void setSelf(const PropertyBasedElementPtr& self);
84       virtual void onDestroy();
85
86       ElementWeakPtr getWeakPtr() const;
87
88       /**
89        * Called every frame to update internal state
90        *
91        * @param dt  Frame time in seconds
92        */
93       virtual void update(double dt);
94
95       bool addEventListener(const std::string& type, const EventListener& cb);
96       virtual void clearEventListener();
97
98       virtual bool accept(EventVisitor& visitor);
99       virtual bool ascend(EventVisitor& visitor);
100       virtual bool traverse(EventVisitor& visitor);
101
102       virtual bool handleEvent(canvas::EventPtr event);
103
104       virtual bool hitBound( const osg::Vec2f& pos,
105                              const osg::Vec2f& local_pos ) const;
106
107       /**
108        * Get whether the element is visible or hidden (Can be changed with
109        * setting property "visible" accordingly).
110        */
111       bool isVisible() const;
112
113       osg::MatrixTransform* getMatrixTransform();
114       osg::MatrixTransform const* getMatrixTransform() const;
115
116       virtual void childAdded( SGPropertyNode * parent,
117                                SGPropertyNode * child );
118       virtual void childRemoved( SGPropertyNode * parent,
119                                  SGPropertyNode * child );
120       virtual void valueChanged(SGPropertyNode * child);
121
122       virtual bool setStyle( const SGPropertyNode* child,
123                              const StyleInfo* style_info = 0 );
124
125       /**
126        * Set clipping shape
127        *
128        * @note Only "rect(<top>, <right>, <bottom>, <left>)" is supported
129        * @see http://www.w3.org/TR/CSS21/visufx.html#propdef-clip
130        */
131       void setClip(const std::string& clip);
132
133       /**
134        * Write the given bounding box to the property tree
135        */
136       void setBoundingBox(const osg::BoundingBox& bb);
137
138       /**
139        * Get bounding box with children/drawables transformed by passed matrix
140        */
141       virtual osg::BoundingBox getTransformedBounds(const osg::Matrix& m) const;
142
143       /**
144        * Create an canvas Element
145        *
146        * @tparam Derived    Type of element (needs to derive from Element)
147        */
148       template<typename Derived>
149       static
150       typename boost::enable_if<
151         boost::is_base_of<Element, Derived>,
152         ElementPtr
153       >::type create( const CanvasWeakPtr& canvas,
154                       const SGPropertyNode_ptr& node,
155                       const Style& style,
156                       Element* parent )
157       {
158         ElementPtr el( new Derived(canvas, node, style, parent) );
159         el->setSelf(el);
160         return el;
161       }
162
163     protected:
164
165       enum Attributes
166       {
167         BLEND_FUNC = 0x0001,
168         LAST_ATTRIBUTE  = BLEND_FUNC << 1
169       };
170
171       enum TransformType
172       {
173         TT_NONE,
174         TT_MATRIX,
175         TT_TRANSLATE,
176         TT_ROTATE,
177         TT_SCALE
178       };
179
180       CanvasWeakPtr _canvas;
181       Element      *_parent;
182
183       uint32_t _attributes_dirty;
184
185       bool _transform_dirty;
186       osg::observer_ptr<osg::MatrixTransform> _transform;
187       std::vector<TransformType>              _transform_types;
188
189       Style                             _style;
190       std::vector<SGPropertyNode_ptr>   _bounding_box;
191
192       typedef std::vector<EventListener> Listener;
193       typedef std::map<Event::Type, Listener> ListenerMap;
194
195       ListenerMap _listener;
196
197       typedef std::map<std::string, StyleInfo> StyleSetters;
198       static StyleSetters       _style_setters;
199
200       static void staticInit();
201
202       Element( const CanvasWeakPtr& canvas,
203                const SGPropertyNode_ptr& node,
204                const Style& parent_style,
205                Element* parent );
206
207       /**
208        * Returns false on first call and true on any successive call. Use to
209        * perform initialization tasks which are only required once per element
210        * type.
211        *
212        * @tparam Derived    (Derived) class type
213        */
214       template<class Derived>
215       static bool isInit()
216       {
217         static bool is_init = false;
218         if( is_init )
219           return true;
220
221         is_init = true;
222         return false;
223       }
224
225       /**
226        * Register a function for setting a style specified by the given property
227        *
228        * @param name    Property name
229        * @param type    Interpolation type
230        * @param setter  Setter function
231        *
232        * @tparam T1         Type of value used to retrieve value from property
233        *                    node
234        * @tparam T2         Type of value the setter function expects
235        * @tparam Derived    Type of class the setter can be applied to
236        *
237        * @note T1 needs to be convertible to T2
238        */
239       template<
240         typename T1,
241         typename T2,
242         class Derived
243       >
244       static
245       StyleSetter
246       addStyle( const std::string& name,
247                 const std::string& type,
248                 const boost::function<void (Derived&, T2)>& setter,
249                 bool inheritable = true )
250       {
251         StyleInfo& style_info = _style_setters[ name ];
252         if( !type.empty() )
253         {
254           if( !style_info.type.empty() && type != style_info.type )
255             SG_LOG
256             (
257               SG_GENERAL,
258               SG_WARN,
259               "changing animation type for '" << name << "': "
260                 << style_info.type << " -> " << type
261             );
262
263           style_info.type = type;
264         }
265         // TODO check if changed?
266         style_info.inheritable = inheritable;
267
268         StyleSetter* style = &style_info.setter;
269         while( style->next )
270           style = style->next;
271         if( style->func )
272           style = style->next = new StyleSetter;
273
274         style->func = boost::bind
275         (
276           &type_match<Derived>::call,
277           _1,
278           _2,
279           bindStyleSetter<T1>(name, setter)
280         );
281         return *style;
282       }
283
284       template<
285         typename T,
286         class Derived
287       >
288       static
289       StyleSetter
290       addStyle( const std::string& name,
291                 const std::string& type,
292                 const boost::function<void (Derived&, T)>& setter,
293                 bool inheritable = true )
294       {
295         return addStyle<T, T>(name, type, setter, inheritable);
296       }
297
298       template<
299         typename T,
300         class Derived
301       >
302       static
303       StyleSetter
304       addStyle( const std::string& name,
305                 const std::string& type,
306                 void (Derived::*setter)(T),
307                 bool inheritable = true )
308       {
309         return addStyle<T, T>
310         (
311           name,
312           type,
313           boost::function<void (Derived&, T)>(setter),
314           inheritable
315         );
316       }
317
318       template<
319         typename T1,
320         typename T2,
321         class Derived
322       >
323       static
324       StyleSetterFunc
325       addStyle( const std::string& name,
326                 const std::string& type,
327                 void (Derived::*setter)(T2),
328                 bool inheritable = true )
329       {
330         return addStyle<T1>
331         (
332           name,
333           type,
334           boost::function<void (Derived&, T2)>(setter),
335           inheritable
336         );
337       }
338
339       template<
340         class Derived
341       >
342       static
343       StyleSetter
344       addStyle( const std::string& name,
345                 const std::string& type,
346                 void (Derived::*setter)(const std::string&),
347                 bool inheritable = true )
348       {
349         return addStyle<const char*, const std::string&>
350         (
351           name,
352           type,
353           boost::function<void (Derived&, const std::string&)>(setter),
354           inheritable
355         );
356       }
357
358       template<
359         typename T,
360         class Derived,
361         class Other,
362         class OtherRef
363       >
364       static
365       StyleSetter
366       addStyle( const std::string& name,
367                 const std::string& type,
368                 void (Other::*setter)(T),
369                 OtherRef Derived::*instance_ref,
370                 bool inheritable = true )
371       {
372         return addStyle<T, T>
373         (
374           name,
375           type,
376           bindOther(setter, instance_ref),
377           inheritable
378         );
379       }
380
381       template<
382         typename T1,
383         typename T2,
384         class Derived,
385         class Other,
386         class OtherRef
387       >
388       static
389       StyleSetter
390       addStyle( const std::string& name,
391                 const std::string& type,
392                 void (Other::*setter)(T2),
393                 OtherRef Derived::*instance_ref,
394                 bool inheritable = true )
395       {
396         return addStyle<T1>
397         (
398           name,
399           type,
400           bindOther(setter, instance_ref),
401           inheritable
402         );
403       }
404
405       template<
406         typename T1,
407         typename T2,
408         class Derived,
409         class Other,
410         class OtherRef
411       >
412       static
413       StyleSetter
414       addStyle( const std::string& name,
415                 const std::string& type,
416                 const boost::function<void (Other&, T2)>& setter,
417                 OtherRef Derived::*instance_ref,
418                 bool inheritable = true )
419       {
420         return addStyle<T1>
421         (
422           name,
423           type,
424           bindOther(setter, instance_ref),
425           inheritable
426         );
427       }
428
429       template<
430         class Derived,
431         class Other,
432         class OtherRef
433       >
434       static
435       StyleSetter
436       addStyle( const std::string& name,
437                 const std::string& type,
438                 void (Other::*setter)(const std::string&),
439                 OtherRef Derived::*instance_ref,
440                 bool inheritable = true )
441       {
442         return addStyle<const char*, const std::string&>
443         (
444           name,
445           type,
446           boost::function<void (Other&, const std::string&)>(setter),
447           instance_ref,
448           inheritable
449         );
450       }
451
452       template<typename T, class Derived, class Other, class OtherRef>
453       static
454       boost::function<void (Derived&, T)>
455       bindOther( void (Other::*setter)(T), OtherRef Derived::*instance_ref )
456       {
457         return boost::bind(setter, boost::bind(instance_ref, _1), _2);
458       }
459
460       template<typename T, class Derived, class Other, class OtherRef>
461       static
462       boost::function<void (Derived&, T)>
463       bindOther( const boost::function<void (Other&, T)>& setter,
464                  OtherRef Derived::*instance_ref )
465       {
466         return boost::bind
467         (
468           setter,
469           boost::bind
470           (
471             &reference_from_pointer<Other, OtherRef>,
472             boost::bind(instance_ref, _1)
473           ),
474           _2
475         );
476       }
477
478       template<typename T1, typename T2, class Derived>
479       static
480       StyleSetterFuncUnchecked
481       bindStyleSetter( const std::string& name,
482                        const boost::function<void (Derived&, T2)>& setter )
483       {
484         return boost::bind
485         (
486           setter,
487           // We will only call setters with Derived instances, so we can safely
488           // cast here.
489           boost::bind(&derived_cast<Derived>, _1),
490           boost::bind(&getValue<T1>, _2)
491         );
492       }
493
494       bool isStyleEmpty(const SGPropertyNode* child) const;
495       bool canApplyStyle(const SGPropertyNode* child) const;
496       bool setStyleImpl( const SGPropertyNode* child,
497                          const StyleInfo* style_info = 0 );
498
499       const StyleInfo* getStyleInfo(const std::string& name) const;
500       const StyleSetter* getStyleSetter(const std::string& name) const;
501       const SGPropertyNode* getParentStyle(const SGPropertyNode* child) const;
502
503       virtual void childAdded(SGPropertyNode * child)  {}
504       virtual void childRemoved(SGPropertyNode * child){}
505       virtual void childChanged(SGPropertyNode * child){}
506
507       void setDrawable(osg::Drawable* drawable);
508
509       /**
510        * Get stateset of drawable if available or use transform otherwise
511        */
512       osg::StateSet* getOrCreateStateSet();
513
514       void setupStyle();
515
516     private:
517
518       osg::ref_ptr<osg::Drawable> _drawable;
519
520       Element(const Element&);// = delete
521
522       template<class Derived>
523       static Derived& derived_cast(Element& el)
524       {
525         return static_cast<Derived&>(el);
526       }
527
528       template<class T, class SharedPtr>
529       static T& reference_from_pointer(const SharedPtr& p)
530       {
531         return *get_pointer(p);
532       }
533
534       /**
535        * Helper to call a function only of the element type can be converted to
536        * the required type.
537        *
538        * @return Whether the function has been called
539        */
540       template<class Derived>
541       struct type_match
542       {
543         static bool call( Element& el,
544                           const SGPropertyNode* prop,
545                           const StyleSetterFuncUnchecked& func )
546         {
547           Derived* d = dynamic_cast<Derived*>(&el);
548           if( !d )
549             return false;
550           func(*d, prop);
551           return true;
552         }
553       };
554   };
555
556 } // namespace canvas
557 } // namespace simgear
558
559 #endif /* CANVAS_ELEMENT_HXX_ */