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