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