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