2 /// Interface for 2D Canvas elements
4 // Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Library General Public
8 // License as published by the Free Software Foundation; either
9 // version 2 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Library General Public License for more details.
16 // You should have received a copy of the GNU Library General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #ifndef CANVAS_ELEMENT_HXX_
21 #define CANVAS_ELEMENT_HXX_
23 #include <simgear/canvas/canvas_fwd.hxx>
24 #include <simgear/canvas/CanvasEvent.hxx>
25 #include <simgear/props/PropertyBasedElement.hxx>
26 #include <simgear/misc/stdint.hxx> // for uint32_t
28 #include <osg/BoundingBox>
29 #include <osg/MatrixTransform>
31 #include <boost/bind.hpp>
32 #include <boost/function.hpp>
33 #include <boost/type_traits/is_base_of.hpp>
46 * Base class for Elements displayed inside a Canvas.
49 public PropertyBasedElement
54 * Store pointer to window as user data
57 public osg::Referenced
61 OSGUserData(ElementPtr element);
64 typedef boost::function<bool(Element&, const SGPropertyNode*)>
66 typedef boost::function<void(Element&, const SGPropertyNode*)>
67 StyleSetterFuncUnchecked;
72 SGSharedPtr<StyleSetter> next;
76 StyleSetter setter; ///< Function(s) for setting this style
77 std::string type; ///< Interpolation type
78 bool inheritable; ///< Whether children can inherit this style from
83 * Coordinate reference frame (eg. "clip" property)
87 GLOBAL, ///< Global coordinates
88 PARENT, ///< Coordinates relative to parent coordinate frame
89 LOCAL ///< Coordinates relative to local coordinates (parent
90 /// coordinates with local transformations applied)
96 virtual ~Element() = 0;
97 virtual void onDestroy();
99 ElementPtr getParent() const;
100 CanvasWeakPtr getCanvas() const;
103 * Called every frame to update internal state
105 * @param dt Frame time in seconds
107 virtual void update(double dt);
109 bool addEventListener(const std::string& type, const EventListener& cb);
110 virtual void clearEventListener();
112 /// Get (keyboard) input focus.
115 virtual bool accept(EventVisitor& visitor);
116 virtual bool ascend(EventVisitor& visitor);
117 virtual bool traverse(EventVisitor& visitor);
119 /// Get the number of event handlers for the given type
120 size_t numEventHandler(int type) const;
122 virtual bool handleEvent(const EventPtr& event);
123 bool dispatchEvent(const EventPtr& event);
127 * @param global_pos Position in global (canvas) coordinate frame
128 * @param parent_pos Position in parent coordinate frame
129 * @param local_pos Position in local (element) coordinate frame
131 virtual bool hitBound( const osg::Vec2f& global_pos,
132 const osg::Vec2f& parent_pos,
133 const osg::Vec2f& local_pos ) const;
136 * Set visibility of the element.
138 virtual void setVisible(bool visible);
141 * Get whether the element is visible or hidden.
143 virtual bool isVisible() const;
145 osg::MatrixTransform* getMatrixTransform();
146 osg::MatrixTransform const* getMatrixTransform() const;
149 * Transform position to local coordinages.
151 osg::Vec2f posToLocal(const osg::Vec2f& pos) const;
153 virtual void childAdded( SGPropertyNode * parent,
154 SGPropertyNode * child );
155 virtual void childRemoved( SGPropertyNode * parent,
156 SGPropertyNode * child );
157 virtual void valueChanged(SGPropertyNode * child);
159 virtual bool setStyle( const SGPropertyNode* child,
160 const StyleInfo* style_info = 0 );
165 * @note Only "rect(<top>, <right>, <bottom>, <left>)" is supported
166 * @see http://www.w3.org/TR/CSS21/visufx.html#propdef-clip
168 void setClip(const std::string& clip);
171 * Clipping coordinates reference frame
173 void setClipFrame(ReferenceFrame rf);
176 * Get bounding box (may not be as tight as bounding box returned by
177 * #getTightBoundingBox)
179 osg::BoundingBox getBoundingBox() const;
182 * Get tight bounding box (child points are transformed to elements
183 * coordinate space before calculating the bounding box).
185 osg::BoundingBox getTightBoundingBox() const;
188 * Get bounding box with children/drawables transformed by passed matrix
190 virtual osg::BoundingBox getTransformedBounds(const osg::Matrix& m) const;
193 * Get the transformation matrix (product of all transforms)
195 osg::Matrix getMatrix() const;
198 * Create an canvas Element
200 * @tparam Derived Type of element (needs to derive from Element)
202 template<typename Derived>
204 typename boost::enable_if<
205 boost::is_base_of<Element, Derived>,
207 >::type create( const CanvasWeakPtr& canvas,
208 const SGPropertyNode_ptr& node,
209 const Style& style = Style(),
210 Element* parent = NULL )
212 return ElementPtr( new Derived(canvas, node, style, parent) );
220 BLEND_FUNC = TRANSFORM << 1,
221 LAST_ATTRIBUTE = BLEND_FUNC << 1
233 class RelativeScissor;
235 CanvasWeakPtr _canvas;
238 mutable uint32_t _attributes_dirty;
240 osg::observer_ptr<osg::MatrixTransform> _transform;
241 std::vector<TransformType> _transform_types;
244 RelativeScissor *_scissor;
246 typedef std::vector<EventListener> Listener;
247 typedef std::map<int, Listener> ListenerMap;
249 ListenerMap _listener;
251 typedef std::map<std::string, StyleInfo> StyleSetters;
252 static StyleSetters _style_setters;
254 static void staticInit();
256 Element( const CanvasWeakPtr& canvas,
257 const SGPropertyNode_ptr& node,
258 const Style& parent_style,
262 * Returns false on first call and true on any successive call. Use to
263 * perform initialization tasks which are only required once per element
266 * @tparam Derived (Derived) class type
268 template<class Derived>
271 static bool is_init = false;
280 * Register a function for setting a style specified by the given property
282 * @param name Property name
283 * @param type Interpolation type
284 * @param setter Setter function
285 * @param inheritable If this style propagates to child elements
287 * @tparam T1 Type of value used to retrieve value from property
289 * @tparam T2 Type of value the setter function expects
290 * @tparam Derived Type of class the setter can be applied to
292 * @note T1 needs to be convertible to T2
301 addStyle( const std::string& name,
302 const std::string& type,
303 const boost::function<void (Derived&, T2)>& setter,
304 bool inheritable = true )
306 StyleInfo& style_info = _style_setters[ name ];
309 if( !style_info.type.empty() && type != style_info.type )
314 "changing animation type for '" << name << "': "
315 << style_info.type << " -> " << type
318 style_info.type = type;
320 // TODO check if changed?
321 style_info.inheritable = inheritable;
323 StyleSetter* style = &style_info.setter;
327 style = style->next = new StyleSetter;
329 style->func = boost::bind
331 &type_match<Derived>::call,
334 bindStyleSetter<T1>(name, setter)
345 addStyle( const std::string& name,
346 const std::string& type,
347 const boost::function<void (Derived&, T)>& setter,
348 bool inheritable = true )
350 return addStyle<T, T>(name, type, setter, inheritable);
359 addStyle( const std::string& name,
360 const std::string& type,
361 void (Derived::*setter)(T),
362 bool inheritable = true )
364 return addStyle<T, T>
368 boost::function<void (Derived&, T)>(setter),
380 addStyle( const std::string& name,
381 const std::string& type,
382 void (Derived::*setter)(T2),
383 bool inheritable = true )
389 boost::function<void (Derived&, T2)>(setter),
399 addStyle( const std::string& name,
400 const std::string& type,
401 void (Derived::*setter)(const std::string&),
402 bool inheritable = true )
404 return addStyle<const char*, const std::string&>
408 boost::function<void (Derived&, const std::string&)>(setter),
421 addStyle( const std::string& name,
422 const std::string& type,
423 void (Other::*setter)(T),
424 OtherRef Derived::*instance_ref,
425 bool inheritable = true )
427 return addStyle<T, T>
431 bindOther(setter, instance_ref),
445 addStyle( const std::string& name,
446 const std::string& type,
447 void (Other::*setter)(T2),
448 OtherRef Derived::*instance_ref,
449 bool inheritable = true )
455 bindOther(setter, instance_ref),
469 addStyle( const std::string& name,
470 const std::string& type,
471 const boost::function<void (Other&, T2)>& setter,
472 OtherRef Derived::*instance_ref,
473 bool inheritable = true )
479 bindOther(setter, instance_ref),
491 addStyle( const std::string& name,
492 const std::string& type,
493 void (Other::*setter)(const std::string&),
494 OtherRef Derived::*instance_ref,
495 bool inheritable = true )
497 return addStyle<const char*, const std::string&>
501 boost::function<void (Other&, const std::string&)>(setter),
507 template<typename T, class Derived, class Other, class OtherRef>
509 boost::function<void (Derived&, T)>
510 bindOther( void (Other::*setter)(T), OtherRef Derived::*instance_ref )
512 return boost::bind(setter, boost::bind(instance_ref, _1), _2);
515 template<typename T, class Derived, class Other, class OtherRef>
517 boost::function<void (Derived&, T)>
518 bindOther( const boost::function<void (Other&, T)>& setter,
519 OtherRef Derived::*instance_ref )
526 &reference_from_pointer<Other, OtherRef>,
527 boost::bind(instance_ref, _1)
533 template<typename T1, typename T2, class Derived>
535 StyleSetterFuncUnchecked
536 bindStyleSetter( const std::string& name,
537 const boost::function<void (Derived&, T2)>& setter )
542 // We will only call setters with Derived instances, so we can safely
544 boost::bind(&derived_cast<Derived>, _1),
545 boost::bind(&getValue<T1>, _2)
549 bool isStyleEmpty(const SGPropertyNode* child) const;
550 bool canApplyStyle(const SGPropertyNode* child) const;
551 bool setStyleImpl( const SGPropertyNode* child,
552 const StyleInfo* style_info = 0 );
554 const StyleInfo* getStyleInfo(const std::string& name) const;
555 const StyleSetter* getStyleSetter(const std::string& name) const;
556 const SGPropertyNode* getParentStyle(const SGPropertyNode* child) const;
558 virtual void childAdded(SGPropertyNode * child) {}
559 virtual void childRemoved(SGPropertyNode * child){}
560 virtual void childChanged(SGPropertyNode * child){}
562 void setDrawable(osg::Drawable* drawable);
565 * Get stateset of drawable if available or use transform otherwise
567 virtual osg::StateSet* getOrCreateStateSet();
573 osg::ref_ptr<osg::Drawable> _drawable;
575 Element(const Element&);// = delete
577 template<class Derived>
578 static Derived& derived_cast(Element& el)
580 return static_cast<Derived&>(el);
583 template<class T, class SharedPtr>
584 static T& reference_from_pointer(const SharedPtr& p)
586 return *get_pointer(p);
590 * Helper to call a function only of the element type can be converted to
593 * @return Whether the function has been called
595 template<class Derived>
598 static bool call( Element& el,
599 const SGPropertyNode* prop,
600 const StyleSetterFuncUnchecked& func )
602 Derived* d = dynamic_cast<Derived*>(&el);
611 } // namespace canvas
614 struct enum_traits<canvas::Element::ReferenceFrame>
616 static const char* name()
618 return "canvas::Element::ReferenceFrame";
621 static canvas::Element::ReferenceFrame defVal()
623 return canvas::Element::GLOBAL;
626 static bool validate(int frame)
628 return frame >= canvas::Element::GLOBAL
629 && frame <= canvas::Element::LOCAL;
633 } // namespace simgear
635 #endif /* CANVAS_ELEMENT_HXX_ */