]> git.mxchange.org Git - simgear.git/blob - simgear/canvas/elements/CanvasElement.hxx
Restructure Canvas/PropertyBasedElement
[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     protected:
141
142       enum Attributes
143       {
144         BLEND_FUNC = 0x0001,
145         LAST_ATTRIBUTE  = BLEND_FUNC << 1
146       };
147
148       enum TransformType
149       {
150         TT_NONE,
151         TT_MATRIX,
152         TT_TRANSLATE,
153         TT_ROTATE,
154         TT_SCALE
155       };
156
157       CanvasWeakPtr _canvas;
158       Element      *_parent;
159
160       uint32_t _attributes_dirty;
161
162       bool _transform_dirty;
163       osg::observer_ptr<osg::MatrixTransform> _transform;
164       std::vector<TransformType>              _transform_types;
165
166       Style                             _style;
167       std::vector<SGPropertyNode_ptr>   _bounding_box;
168
169       typedef std::vector<EventListenerPtr> Listener;
170       typedef std::map<Event::Type, Listener> ListenerMap;
171
172       ListenerMap _listener;
173
174       typedef std::map<std::string, StyleInfo> StyleSetters;
175       static StyleSetters       _style_setters;
176
177       Element( const CanvasWeakPtr& canvas,
178                const SGPropertyNode_ptr& node,
179                const Style& parent_style,
180                Element* parent );
181
182       /**
183        * Returns false on first call and true on any successive call. Use to
184        * perform initialization tasks which are only required once per element
185        * type.
186        *
187        * @tparam Derived    (Derived) class type
188        */
189       template<class Derived>
190       bool isInit() const
191       {
192         static bool is_init = false;
193         if( is_init )
194           return true;
195
196         is_init = true;
197         return false;
198       }
199
200       /**
201        * Register a function for setting a style specified by the given property
202        *
203        * @param name    Property name
204        * @param type    Interpolation type
205        * @param setter  Setter function
206        *
207        * @tparam T1         Type of value used to retrieve value from property
208        *                    node
209        * @tparam T2         Type of value the setter function expects
210        * @tparam Derived    Type of class the setter can be applied to
211        *
212        * @note T1 needs to be convertible to T2
213        */
214       template<
215         typename T1,
216         typename T2,
217         class Derived
218       >
219       StyleSetter
220       addStyle( const std::string& name,
221                 const std::string& type,
222                 const boost::function<void (Derived&, T2)>& setter )
223       {
224         StyleInfo& style_info = _style_setters[ name ];
225         if( !type.empty() )
226         {
227           if( !style_info.type.empty() && type != style_info.type )
228             SG_LOG
229             (
230               SG_GENERAL,
231               SG_WARN,
232               "changing animation type for '" << name << "': "
233                 << style_info.type << " -> " << type
234             );
235
236           style_info.type = type;
237         }
238
239         StyleSetter* style = &style_info.setter;
240         while( style->next )
241           style = style->next;
242         if( style->func )
243           style = style->next = new StyleSetter;
244
245         style->func = boost::bind
246         (
247           &type_match<Derived>::call,
248           _1,
249           _2,
250           bindStyleSetter<T1>(name, setter)
251         );
252         return *style;
253       }
254
255       template<
256         typename T,
257         class Derived
258       >
259       StyleSetter
260       addStyle( const std::string& name,
261                 const std::string& type,
262                 const boost::function<void (Derived&, T)>& setter )
263       {
264         return addStyle<T, T>(name, type, setter);
265       }
266
267       template<
268         typename T,
269         class Derived
270       >
271       StyleSetter
272       addStyle( const std::string& name,
273                 const std::string& type,
274                 void (Derived::*setter)(T) )
275       {
276         return addStyle<T, T>
277         (
278           name,
279           type,
280           boost::function<void (Derived&, T)>(setter)
281         );
282       }
283
284       template<
285         typename T1,
286         typename T2,
287         class Derived
288       >
289       StyleSetterFunc
290       addStyle( const std::string& name,
291                 const std::string& type,
292                 void (Derived::*setter)(T2) )
293       {
294         return addStyle<T1>
295         (
296           name,
297           type,
298           boost::function<void (Derived&, T2)>(setter)
299         );
300       }
301
302       template<
303         class Derived
304       >
305       StyleSetter
306       addStyle( const std::string& name,
307                 const std::string& type,
308                 void (Derived::*setter)(const std::string&) )
309       {
310         return addStyle<const char*, const std::string&>
311         (
312           name,
313           type,
314           boost::function<void (Derived&, const std::string&)>(setter)
315         );
316       }
317
318       template<
319         typename T,
320         class Derived,
321         class Other,
322         class OtherRef
323       >
324       StyleSetter
325       addStyle( const std::string& name,
326                 const std::string& type,
327                 void (Other::*setter)(T),
328                 OtherRef Derived::*instance_ref )
329       {
330         return addStyle<T, T>(name, type, bindOther(setter, instance_ref));
331       }
332
333       template<
334         typename T1,
335         typename T2,
336         class Derived,
337         class Other,
338         class OtherRef
339       >
340       StyleSetter
341       addStyle( const std::string& name,
342                 const std::string& type,
343                 void (Other::*setter)(T2),
344                 OtherRef Derived::*instance_ref )
345       {
346         return addStyle<T1>(name, type, bindOther(setter, instance_ref));
347       }
348
349       template<
350         typename T1,
351         typename T2,
352         class Derived,
353         class Other,
354         class OtherRef
355       >
356       StyleSetter
357       addStyle( const std::string& name,
358                 const std::string& type,
359                 const boost::function<void (Other&, T2)>& setter,
360                 OtherRef Derived::*instance_ref )
361       {
362         return addStyle<T1>(name, type, bindOther(setter, instance_ref));
363       }
364
365       template<
366         class Derived,
367         class Other,
368         class OtherRef
369       >
370       StyleSetter
371       addStyle( const std::string& name,
372                 const std::string& type,
373                 void (Other::*setter)(const std::string&),
374                 OtherRef Derived::*instance_ref )
375       {
376         return addStyle<const char*, const std::string&>
377         (
378           name,
379           type,
380           boost::function<void (Other&, const std::string&)>(setter),
381           instance_ref
382         );
383       }
384
385       template<typename T, class Derived, class Other, class OtherRef>
386       boost::function<void (Derived&, T)>
387       bindOther( void (Other::*setter)(T), OtherRef Derived::*instance_ref )
388       {
389         return boost::bind(setter, boost::bind(instance_ref, _1), _2);
390       }
391
392       template<typename T, class Derived, class Other, class OtherRef>
393       boost::function<void (Derived&, T)>
394       bindOther( const boost::function<void (Other&, T)>& setter,
395                  OtherRef Derived::*instance_ref )
396       {
397         return boost::bind
398         (
399           setter,
400           boost::bind
401           (
402             &reference_from_pointer<Other, OtherRef>,
403             boost::bind(instance_ref, _1)
404           ),
405           _2
406         );
407       }
408
409       template<typename T1, typename T2, class Derived>
410       StyleSetterFuncUnchecked
411       bindStyleSetter( const std::string& name,
412                        const boost::function<void (Derived&, T2)>& setter )
413       {
414         return boost::bind
415         (
416           setter,
417           // We will only call setters with Derived instances, so we can safely
418           // cast here.
419           boost::bind(&derived_cast<Derived>, _1),
420           boost::bind(&getValue<T1>, _2)
421         );
422       }
423
424       virtual void childAdded(SGPropertyNode * child)  {}
425       virtual void childRemoved(SGPropertyNode * child){}
426       virtual void childChanged(SGPropertyNode * child){}
427
428       void setDrawable(osg::Drawable* drawable);
429
430       /**
431        * Get stateset of drawable if available or use transform otherwise
432        */
433       osg::StateSet* getOrCreateStateSet();
434
435       void setupStyle();
436
437     private:
438
439       osg::ref_ptr<osg::Drawable> _drawable;
440
441       Element(const Element&);// = delete
442
443       template<class Derived>
444       static Derived& derived_cast(Element& el)
445       {
446         return static_cast<Derived&>(el);
447       }
448
449       template<class T, class SharedPtr>
450       static T& reference_from_pointer(const SharedPtr& p)
451       {
452         return *get_pointer(p);
453       }
454
455       /**
456        * Helper to call a function only of the element type can be converted to
457        * the required type.
458        *
459        * @return Whether the function has been called
460        */
461       template<class Derived>
462       struct type_match
463       {
464         static bool call( Element& el,
465                           const SGPropertyNode* prop,
466                           const StyleSetterFuncUnchecked& func )
467         {
468           Derived* d = dynamic_cast<Derived*>(&el);
469           if( !d )
470             return false;
471           func(*d, prop);
472           return true;
473         }
474       };
475   };
476
477 } // namespace canvas
478 } // namespace simgear
479
480 #endif /* CANVAS_ELEMENT_HXX_ */