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