]> git.mxchange.org Git - simgear.git/blob - simgear/canvas/elements/CanvasElement.hxx
Update doxgen config and some comments.
[simgear.git] / simgear / canvas / elements / CanvasElement.hxx
1 ///@file 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   /**
45    * Baseclass for Elements displayed inside a Canvas.
46    */
47   class Element:
48     public PropertyBasedElement
49   {
50     public:
51
52       /**
53        * Store pointer to window as user data
54        */
55       class OSGUserData:
56         public osg::Referenced
57       {
58         public:
59           ElementPtr element;
60           OSGUserData(ElementPtr element);
61       };
62
63       typedef boost::function<bool(Element&, const SGPropertyNode*)>
64               StyleSetterFunc;
65       typedef boost::function<void(Element&, const SGPropertyNode*)>
66               StyleSetterFuncUnchecked;
67       struct StyleSetter:
68         public SGReferenced
69       {
70         StyleSetterFunc func;
71         SGSharedPtr<StyleSetter> next;
72       };
73       struct StyleInfo
74       {
75         StyleSetter setter; ///< Function(s) for setting this style
76         std::string type;   ///< Interpolation type
77         bool inheritable;   ///< Whether children can inherit this style from
78                             ///  their parents
79       };
80
81       /**
82        * Coordinate reference frame (eg. "clip" property)
83        */
84       enum ReferenceFrame
85       {
86         GLOBAL, ///< Global coordinates
87         PARENT, ///< Coordinates relative to parent coordinate frame
88         LOCAL   ///< Coordinates relative to local coordinates (parent
89                 ///  coordinates with local transformations applied)
90       };
91
92       /**
93        *
94        */
95       virtual ~Element() = 0;
96       virtual void onDestroy();
97
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       template<class T>
111       void setDataProp( const std::string& name,
112                         const T& val )
113       {
114         const std::string& attr = dataPropToAttrName(name);
115         if( !attr.empty() )
116           set<T>(attr, val);
117         else
118           SG_LOG(SG_GENERAL, SG_WARN, "Invalid data-prop name: " << name);
119       }
120
121       template<class T>
122       T getDataProp( const std::string& name,
123                      const T& def = T() )
124       {
125         const std::string& attr = dataPropToAttrName(name);
126         if( !attr.empty() )
127           return get<T>(attr, def);
128         else
129           SG_LOG(SG_GENERAL, SG_WARN, "Invalid data-prop name: " << name);
130
131         return def;
132       }
133
134       virtual bool accept(EventVisitor& visitor);
135       virtual bool ascend(EventVisitor& visitor);
136       virtual bool traverse(EventVisitor& visitor);
137
138       virtual bool handleEvent(EventPtr event);
139       bool dispatchEvent(EventPtr event);
140
141       /**
142        *
143        * @param global_pos Position in global (canvas) coordinate frame
144        * @param parent_pos Position in parent coordinate frame
145        * @param local_pos  Position in local (element) coordinate frame
146        */
147       virtual bool hitBound( const osg::Vec2f& global_pos,
148                              const osg::Vec2f& parent_pos,
149                              const osg::Vec2f& local_pos ) const;
150
151       /**
152        * Set visibility of the element.
153        */
154       void setVisible(bool visible);
155
156       /**
157        * Get whether the element is visible or hidden.
158        */
159       bool isVisible() const;
160
161       osg::MatrixTransform* getMatrixTransform();
162       osg::MatrixTransform const* getMatrixTransform() const;
163
164       /**
165        * Transform position to local coordinages.
166        */
167       osg::Vec2f posToLocal(const osg::Vec2f& pos) const;
168
169       virtual void childAdded( SGPropertyNode * parent,
170                                SGPropertyNode * child );
171       virtual void childRemoved( SGPropertyNode * parent,
172                                  SGPropertyNode * child );
173       virtual void valueChanged(SGPropertyNode * child);
174
175       virtual bool setStyle( const SGPropertyNode* child,
176                              const StyleInfo* style_info = 0 );
177
178       /**
179        * Set clipping shape
180        *
181        * @note Only "rect(<top>, <right>, <bottom>, <left>)" is supported
182        * @see http://www.w3.org/TR/CSS21/visufx.html#propdef-clip
183        */
184       void setClip(const std::string& clip);
185
186       /**
187        * Clipping coordinates reference frame
188        */
189       void setClipFrame(ReferenceFrame rf);
190
191       /**
192        * Get bounding box (may not be as tight as bounding box returned by
193        * #getTightBounds)
194        */
195       osg::BoundingBox getBoundingBox() const;
196
197       /**
198        * Get tight bounding box (child points are transformed to elements
199        * coordinate space before calculating the bounding box).
200        */
201       osg::BoundingBox getTightBoundingBox() const;
202
203       /**
204        * Get bounding box with children/drawables transformed by passed matrix
205        */
206       virtual osg::BoundingBox getTransformedBounds(const osg::Matrix& m) const;
207
208       /**
209        * Get the transformation matrix (product of all transforms)
210        */
211       osg::Matrix getMatrix() const;
212
213       /**
214        * Create an canvas Element
215        *
216        * @tparam Derived    Type of element (needs to derive from Element)
217        */
218       template<typename Derived>
219       static
220       typename boost::enable_if<
221         boost::is_base_of<Element, Derived>,
222         ElementPtr
223       >::type create( const CanvasWeakPtr& canvas,
224                       const SGPropertyNode_ptr& node,
225                       const Style& style = Style(),
226                       Element* parent = NULL )
227       {
228         return ElementPtr( new Derived(canvas, node, style, parent) );
229       }
230
231       static std::string dataPropToAttrName(const std::string& name);
232       static std::string attrToDataPropName(const std::string& name);
233
234     protected:
235
236       enum Attributes
237       {
238         TRANSFORM       = 1,
239         BLEND_FUNC      = TRANSFORM << 1,
240         SCISSOR_COORDS  = BLEND_FUNC << 1,
241         LAST_ATTRIBUTE  = SCISSOR_COORDS << 1
242       };
243
244       enum TransformType
245       {
246         TT_NONE,
247         TT_MATRIX,
248         TT_TRANSLATE,
249         TT_ROTATE,
250         TT_SCALE
251       };
252
253       class RelativeScissor;
254
255       CanvasWeakPtr _canvas;
256       Element      *_parent;
257
258       mutable uint32_t _attributes_dirty;
259
260       osg::observer_ptr<osg::MatrixTransform> _transform;
261       std::vector<TransformType>              _transform_types;
262
263       Style             _style;
264       RelativeScissor  *_scissor;
265
266       typedef std::vector<EventListener> Listener;
267       typedef std::map<int, Listener> ListenerMap;
268
269       ListenerMap _listener;
270
271       typedef std::map<std::string, StyleInfo> StyleSetters;
272       static StyleSetters _style_setters;
273
274       static void staticInit();
275
276       Element( const CanvasWeakPtr& canvas,
277                const SGPropertyNode_ptr& node,
278                const Style& parent_style,
279                Element* parent );
280
281       /**
282        * Returns false on first call and true on any successive call. Use to
283        * perform initialization tasks which are only required once per element
284        * type.
285        *
286        * @tparam Derived    (Derived) class type
287        */
288       template<class Derived>
289       static bool isInit()
290       {
291         static bool is_init = false;
292         if( is_init )
293           return true;
294
295         is_init = true;
296         return false;
297       }
298
299       /**
300        * Register a function for setting a style specified by the given property
301        *
302        * @param name    Property name
303        * @param type    Interpolation type
304        * @param setter  Setter function
305        *
306        * @tparam T1         Type of value used to retrieve value from property
307        *                    node
308        * @tparam T2         Type of value the setter function expects
309        * @tparam Derived    Type of class the setter can be applied to
310        *
311        * @note T1 needs to be convertible to T2
312        */
313       template<
314         typename T1,
315         typename T2,
316         class Derived
317       >
318       static
319       StyleSetter
320       addStyle( const std::string& name,
321                 const std::string& type,
322                 const boost::function<void (Derived&, T2)>& setter,
323                 bool inheritable = true )
324       {
325         StyleInfo& style_info = _style_setters[ name ];
326         if( !type.empty() )
327         {
328           if( !style_info.type.empty() && type != style_info.type )
329             SG_LOG
330             (
331               SG_GENERAL,
332               SG_WARN,
333               "changing animation type for '" << name << "': "
334                 << style_info.type << " -> " << type
335             );
336
337           style_info.type = type;
338         }
339         // TODO check if changed?
340         style_info.inheritable = inheritable;
341
342         StyleSetter* style = &style_info.setter;
343         while( style->next )
344           style = style->next;
345         if( style->func )
346           style = style->next = new StyleSetter;
347
348         style->func = boost::bind
349         (
350           &type_match<Derived>::call,
351           _1,
352           _2,
353           bindStyleSetter<T1>(name, setter)
354         );
355         return *style;
356       }
357
358       template<
359         typename T,
360         class Derived
361       >
362       static
363       StyleSetter
364       addStyle( const std::string& name,
365                 const std::string& type,
366                 const boost::function<void (Derived&, T)>& setter,
367                 bool inheritable = true )
368       {
369         return addStyle<T, T>(name, type, setter, inheritable);
370       }
371
372       template<
373         typename T,
374         class Derived
375       >
376       static
377       StyleSetter
378       addStyle( const std::string& name,
379                 const std::string& type,
380                 void (Derived::*setter)(T),
381                 bool inheritable = true )
382       {
383         return addStyle<T, T>
384         (
385           name,
386           type,
387           boost::function<void (Derived&, T)>(setter),
388           inheritable
389         );
390       }
391
392       template<
393         typename T1,
394         typename T2,
395         class Derived
396       >
397       static
398       StyleSetterFunc
399       addStyle( const std::string& name,
400                 const std::string& type,
401                 void (Derived::*setter)(T2),
402                 bool inheritable = true )
403       {
404         return addStyle<T1>
405         (
406           name,
407           type,
408           boost::function<void (Derived&, T2)>(setter),
409           inheritable
410         );
411       }
412
413       template<
414         class Derived
415       >
416       static
417       StyleSetter
418       addStyle( const std::string& name,
419                 const std::string& type,
420                 void (Derived::*setter)(const std::string&),
421                 bool inheritable = true )
422       {
423         return addStyle<const char*, const std::string&>
424         (
425           name,
426           type,
427           boost::function<void (Derived&, const std::string&)>(setter),
428           inheritable
429         );
430       }
431
432       template<
433         typename T,
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                 void (Other::*setter)(T),
443                 OtherRef Derived::*instance_ref,
444                 bool inheritable = true )
445       {
446         return addStyle<T, T>
447         (
448           name,
449           type,
450           bindOther(setter, instance_ref),
451           inheritable
452         );
453       }
454
455       template<
456         typename T1,
457         typename T2,
458         class Derived,
459         class Other,
460         class OtherRef
461       >
462       static
463       StyleSetter
464       addStyle( const std::string& name,
465                 const std::string& type,
466                 void (Other::*setter)(T2),
467                 OtherRef Derived::*instance_ref,
468                 bool inheritable = true )
469       {
470         return addStyle<T1>
471         (
472           name,
473           type,
474           bindOther(setter, instance_ref),
475           inheritable
476         );
477       }
478
479       template<
480         typename T1,
481         typename T2,
482         class Derived,
483         class Other,
484         class OtherRef
485       >
486       static
487       StyleSetter
488       addStyle( const std::string& name,
489                 const std::string& type,
490                 const boost::function<void (Other&, T2)>& setter,
491                 OtherRef Derived::*instance_ref,
492                 bool inheritable = true )
493       {
494         return addStyle<T1>
495         (
496           name,
497           type,
498           bindOther(setter, instance_ref),
499           inheritable
500         );
501       }
502
503       template<
504         class Derived,
505         class Other,
506         class OtherRef
507       >
508       static
509       StyleSetter
510       addStyle( const std::string& name,
511                 const std::string& type,
512                 void (Other::*setter)(const std::string&),
513                 OtherRef Derived::*instance_ref,
514                 bool inheritable = true )
515       {
516         return addStyle<const char*, const std::string&>
517         (
518           name,
519           type,
520           boost::function<void (Other&, const std::string&)>(setter),
521           instance_ref,
522           inheritable
523         );
524       }
525
526       template<typename T, class Derived, class Other, class OtherRef>
527       static
528       boost::function<void (Derived&, T)>
529       bindOther( void (Other::*setter)(T), OtherRef Derived::*instance_ref )
530       {
531         return boost::bind(setter, boost::bind(instance_ref, _1), _2);
532       }
533
534       template<typename T, class Derived, class Other, class OtherRef>
535       static
536       boost::function<void (Derived&, T)>
537       bindOther( const boost::function<void (Other&, T)>& setter,
538                  OtherRef Derived::*instance_ref )
539       {
540         return boost::bind
541         (
542           setter,
543           boost::bind
544           (
545             &reference_from_pointer<Other, OtherRef>,
546             boost::bind(instance_ref, _1)
547           ),
548           _2
549         );
550       }
551
552       template<typename T1, typename T2, class Derived>
553       static
554       StyleSetterFuncUnchecked
555       bindStyleSetter( const std::string& name,
556                        const boost::function<void (Derived&, T2)>& setter )
557       {
558         return boost::bind
559         (
560           setter,
561           // We will only call setters with Derived instances, so we can safely
562           // cast here.
563           boost::bind(&derived_cast<Derived>, _1),
564           boost::bind(&getValue<T1>, _2)
565         );
566       }
567
568       bool isStyleEmpty(const SGPropertyNode* child) const;
569       bool canApplyStyle(const SGPropertyNode* child) const;
570       bool setStyleImpl( const SGPropertyNode* child,
571                          const StyleInfo* style_info = 0 );
572
573       const StyleInfo* getStyleInfo(const std::string& name) const;
574       const StyleSetter* getStyleSetter(const std::string& name) const;
575       const SGPropertyNode* getParentStyle(const SGPropertyNode* child) const;
576
577       virtual void childAdded(SGPropertyNode * child)  {}
578       virtual void childRemoved(SGPropertyNode * child){}
579       virtual void childChanged(SGPropertyNode * child){}
580
581       void setDrawable(osg::Drawable* drawable);
582
583       /**
584        * Get stateset of drawable if available or use transform otherwise
585        */
586       osg::StateSet* getOrCreateStateSet();
587
588       void setupStyle();
589
590     private:
591
592       osg::ref_ptr<osg::Drawable> _drawable;
593
594       Element(const Element&);// = delete
595
596       template<class Derived>
597       static Derived& derived_cast(Element& el)
598       {
599         return static_cast<Derived&>(el);
600       }
601
602       template<class T, class SharedPtr>
603       static T& reference_from_pointer(const SharedPtr& p)
604       {
605         return *get_pointer(p);
606       }
607
608       /**
609        * Helper to call a function only of the element type can be converted to
610        * the required type.
611        *
612        * @return Whether the function has been called
613        */
614       template<class Derived>
615       struct type_match
616       {
617         static bool call( Element& el,
618                           const SGPropertyNode* prop,
619                           const StyleSetterFuncUnchecked& func )
620         {
621           Derived* d = dynamic_cast<Derived*>(&el);
622           if( !d )
623             return false;
624           func(*d, prop);
625           return true;
626         }
627       };
628   };
629
630 } // namespace canvas
631
632   template<>
633   struct enum_traits<canvas::Element::ReferenceFrame>
634   {
635     static const char* name()
636     {
637       return "canvas::Element::ReferenceFrame";
638     }
639
640     static canvas::Element::ReferenceFrame defVal()
641     {
642       return canvas::Element::GLOBAL;
643     }
644
645     static bool validate(int frame)
646     {
647       return frame >= canvas::Element::GLOBAL
648           && frame <= canvas::Element::LOCAL;
649     }
650   };
651
652 } // namespace simgear
653
654 #endif /* CANVAS_ELEMENT_HXX_ */