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