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