]> git.mxchange.org Git - simgear.git/blob - simgear/canvas/elements/CanvasElement.hxx
Canvas: improved clipping and new property clip-frame.
[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        * Create an canvas Element
162        *
163        * @tparam Derived    Type of element (needs to derive from Element)
164        */
165       template<typename Derived>
166       static
167       typename boost::enable_if<
168         boost::is_base_of<Element, Derived>,
169         ElementPtr
170       >::type create( const CanvasWeakPtr& canvas,
171                       const SGPropertyNode_ptr& node,
172                       const Style& style,
173                       Element* parent )
174       {
175         ElementPtr el( new Derived(canvas, node, style, parent) );
176         el->setSelf(el);
177         return el;
178       }
179
180     protected:
181
182       enum Attributes
183       {
184         BLEND_FUNC      = 1,
185         SCISSOR_COORDS  = BLEND_FUNC << 1,
186         LAST_ATTRIBUTE  = SCISSOR_COORDS << 1
187       };
188
189       enum TransformType
190       {
191         TT_NONE,
192         TT_MATRIX,
193         TT_TRANSLATE,
194         TT_ROTATE,
195         TT_SCALE
196       };
197
198       class RelativeScissor;
199
200       CanvasWeakPtr _canvas;
201       Element      *_parent;
202
203       uint32_t _attributes_dirty;
204
205       bool _transform_dirty;
206       osg::observer_ptr<osg::MatrixTransform> _transform;
207       std::vector<TransformType>              _transform_types;
208
209       Style                             _style;
210       std::vector<SGPropertyNode_ptr>   _bounding_box;
211       RelativeScissor                  *_scissor;
212
213       typedef std::vector<EventListener> Listener;
214       typedef std::map<Event::Type, Listener> ListenerMap;
215
216       ListenerMap _listener;
217
218       typedef std::map<std::string, StyleInfo> StyleSetters;
219       static StyleSetters       _style_setters;
220
221       static void staticInit();
222
223       Element( const CanvasWeakPtr& canvas,
224                const SGPropertyNode_ptr& node,
225                const Style& parent_style,
226                Element* parent );
227
228       /**
229        * Returns false on first call and true on any successive call. Use to
230        * perform initialization tasks which are only required once per element
231        * type.
232        *
233        * @tparam Derived    (Derived) class type
234        */
235       template<class Derived>
236       static bool isInit()
237       {
238         static bool is_init = false;
239         if( is_init )
240           return true;
241
242         is_init = true;
243         return false;
244       }
245
246       /**
247        * Register a function for setting a style specified by the given property
248        *
249        * @param name    Property name
250        * @param type    Interpolation type
251        * @param setter  Setter function
252        *
253        * @tparam T1         Type of value used to retrieve value from property
254        *                    node
255        * @tparam T2         Type of value the setter function expects
256        * @tparam Derived    Type of class the setter can be applied to
257        *
258        * @note T1 needs to be convertible to T2
259        */
260       template<
261         typename T1,
262         typename T2,
263         class Derived
264       >
265       static
266       StyleSetter
267       addStyle( const std::string& name,
268                 const std::string& type,
269                 const boost::function<void (Derived&, T2)>& setter,
270                 bool inheritable = true )
271       {
272         StyleInfo& style_info = _style_setters[ name ];
273         if( !type.empty() )
274         {
275           if( !style_info.type.empty() && type != style_info.type )
276             SG_LOG
277             (
278               SG_GENERAL,
279               SG_WARN,
280               "changing animation type for '" << name << "': "
281                 << style_info.type << " -> " << type
282             );
283
284           style_info.type = type;
285         }
286         // TODO check if changed?
287         style_info.inheritable = inheritable;
288
289         StyleSetter* style = &style_info.setter;
290         while( style->next )
291           style = style->next;
292         if( style->func )
293           style = style->next = new StyleSetter;
294
295         style->func = boost::bind
296         (
297           &type_match<Derived>::call,
298           _1,
299           _2,
300           bindStyleSetter<T1>(name, setter)
301         );
302         return *style;
303       }
304
305       template<
306         typename T,
307         class Derived
308       >
309       static
310       StyleSetter
311       addStyle( const std::string& name,
312                 const std::string& type,
313                 const boost::function<void (Derived&, T)>& setter,
314                 bool inheritable = true )
315       {
316         return addStyle<T, T>(name, type, setter, inheritable);
317       }
318
319       template<
320         typename T,
321         class Derived
322       >
323       static
324       StyleSetter
325       addStyle( const std::string& name,
326                 const std::string& type,
327                 void (Derived::*setter)(T),
328                 bool inheritable = true )
329       {
330         return addStyle<T, T>
331         (
332           name,
333           type,
334           boost::function<void (Derived&, T)>(setter),
335           inheritable
336         );
337       }
338
339       template<
340         typename T1,
341         typename T2,
342         class Derived
343       >
344       static
345       StyleSetterFunc
346       addStyle( const std::string& name,
347                 const std::string& type,
348                 void (Derived::*setter)(T2),
349                 bool inheritable = true )
350       {
351         return addStyle<T1>
352         (
353           name,
354           type,
355           boost::function<void (Derived&, T2)>(setter),
356           inheritable
357         );
358       }
359
360       template<
361         class Derived
362       >
363       static
364       StyleSetter
365       addStyle( const std::string& name,
366                 const std::string& type,
367                 void (Derived::*setter)(const std::string&),
368                 bool inheritable = true )
369       {
370         return addStyle<const char*, const std::string&>
371         (
372           name,
373           type,
374           boost::function<void (Derived&, const std::string&)>(setter),
375           inheritable
376         );
377       }
378
379       template<
380         typename T,
381         class Derived,
382         class Other,
383         class OtherRef
384       >
385       static
386       StyleSetter
387       addStyle( const std::string& name,
388                 const std::string& type,
389                 void (Other::*setter)(T),
390                 OtherRef Derived::*instance_ref,
391                 bool inheritable = true )
392       {
393         return addStyle<T, T>
394         (
395           name,
396           type,
397           bindOther(setter, instance_ref),
398           inheritable
399         );
400       }
401
402       template<
403         typename T1,
404         typename T2,
405         class Derived,
406         class Other,
407         class OtherRef
408       >
409       static
410       StyleSetter
411       addStyle( const std::string& name,
412                 const std::string& type,
413                 void (Other::*setter)(T2),
414                 OtherRef Derived::*instance_ref,
415                 bool inheritable = true )
416       {
417         return addStyle<T1>
418         (
419           name,
420           type,
421           bindOther(setter, instance_ref),
422           inheritable
423         );
424       }
425
426       template<
427         typename T1,
428         typename T2,
429         class Derived,
430         class Other,
431         class OtherRef
432       >
433       static
434       StyleSetter
435       addStyle( const std::string& name,
436                 const std::string& type,
437                 const boost::function<void (Other&, T2)>& setter,
438                 OtherRef Derived::*instance_ref,
439                 bool inheritable = true )
440       {
441         return addStyle<T1>
442         (
443           name,
444           type,
445           bindOther(setter, instance_ref),
446           inheritable
447         );
448       }
449
450       template<
451         class Derived,
452         class Other,
453         class OtherRef
454       >
455       static
456       StyleSetter
457       addStyle( const std::string& name,
458                 const std::string& type,
459                 void (Other::*setter)(const std::string&),
460                 OtherRef Derived::*instance_ref,
461                 bool inheritable = true )
462       {
463         return addStyle<const char*, const std::string&>
464         (
465           name,
466           type,
467           boost::function<void (Other&, const std::string&)>(setter),
468           instance_ref,
469           inheritable
470         );
471       }
472
473       template<typename T, class Derived, class Other, class OtherRef>
474       static
475       boost::function<void (Derived&, T)>
476       bindOther( void (Other::*setter)(T), OtherRef Derived::*instance_ref )
477       {
478         return boost::bind(setter, boost::bind(instance_ref, _1), _2);
479       }
480
481       template<typename T, class Derived, class Other, class OtherRef>
482       static
483       boost::function<void (Derived&, T)>
484       bindOther( const boost::function<void (Other&, T)>& setter,
485                  OtherRef Derived::*instance_ref )
486       {
487         return boost::bind
488         (
489           setter,
490           boost::bind
491           (
492             &reference_from_pointer<Other, OtherRef>,
493             boost::bind(instance_ref, _1)
494           ),
495           _2
496         );
497       }
498
499       template<typename T1, typename T2, class Derived>
500       static
501       StyleSetterFuncUnchecked
502       bindStyleSetter( const std::string& name,
503                        const boost::function<void (Derived&, T2)>& setter )
504       {
505         return boost::bind
506         (
507           setter,
508           // We will only call setters with Derived instances, so we can safely
509           // cast here.
510           boost::bind(&derived_cast<Derived>, _1),
511           boost::bind(&getValue<T1>, _2)
512         );
513       }
514
515       bool isStyleEmpty(const SGPropertyNode* child) const;
516       bool canApplyStyle(const SGPropertyNode* child) const;
517       bool setStyleImpl( const SGPropertyNode* child,
518                          const StyleInfo* style_info = 0 );
519
520       const StyleInfo* getStyleInfo(const std::string& name) const;
521       const StyleSetter* getStyleSetter(const std::string& name) const;
522       const SGPropertyNode* getParentStyle(const SGPropertyNode* child) const;
523
524       virtual void childAdded(SGPropertyNode * child)  {}
525       virtual void childRemoved(SGPropertyNode * child){}
526       virtual void childChanged(SGPropertyNode * child){}
527
528       void setDrawable(osg::Drawable* drawable);
529
530       /**
531        * Get stateset of drawable if available or use transform otherwise
532        */
533       osg::StateSet* getOrCreateStateSet();
534
535       void setupStyle();
536
537     private:
538
539       osg::ref_ptr<osg::Drawable> _drawable;
540
541       Element(const Element&);// = delete
542
543       template<class Derived>
544       static Derived& derived_cast(Element& el)
545       {
546         return static_cast<Derived&>(el);
547       }
548
549       template<class T, class SharedPtr>
550       static T& reference_from_pointer(const SharedPtr& p)
551       {
552         return *get_pointer(p);
553       }
554
555       /**
556        * Helper to call a function only of the element type can be converted to
557        * the required type.
558        *
559        * @return Whether the function has been called
560        */
561       template<class Derived>
562       struct type_match
563       {
564         static bool call( Element& el,
565                           const SGPropertyNode* prop,
566                           const StyleSetterFuncUnchecked& func )
567         {
568           Derived* d = dynamic_cast<Derived*>(&el);
569           if( !d )
570             return false;
571           func(*d, prop);
572           return true;
573         }
574       };
575   };
576
577 } // namespace canvas
578
579   template<>
580   struct enum_traits<canvas::Element::ReferenceFrame>
581   {
582     static const char* name()
583     {
584       return "canvas::Element::ReferenceFrame";
585     }
586
587     static canvas::Element::ReferenceFrame defVal()
588     {
589       return canvas::Element::GLOBAL;
590     }
591
592     static bool validate(int frame)
593     {
594       return frame >= canvas::Element::GLOBAL
595           && frame <= canvas::Element::LOCAL;
596     }
597   };
598
599 } // namespace simgear
600
601 #endif /* CANVAS_ELEMENT_HXX_ */