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