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