1 // Interface for 2D Canvas elements
3 // Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
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.
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.
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
19 #ifndef CANVAS_ELEMENT_HXX_
20 #define CANVAS_ELEMENT_HXX_
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
27 #include <osg/BoundingBox>
28 #include <osg/MatrixTransform>
30 #include <boost/bind.hpp>
31 #include <boost/function.hpp>
32 #include <boost/type_traits/is_base_of.hpp>
45 public PropertyBasedElement
50 * Store pointer to window as user data
53 public osg::Referenced
57 OSGUserData(ElementPtr element);
60 typedef boost::function<bool(Element&, const SGPropertyNode*)>
62 typedef boost::function<void(Element&, const SGPropertyNode*)>
63 StyleSetterFuncUnchecked;
68 SGSharedPtr<StyleSetter> next;
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
79 * Coordinate reference frame (eg. "clip" property)
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)
92 virtual ~Element() = 0;
93 virtual void onDestroy();
95 ElementPtr getParent();
98 * Called every frame to update internal state
100 * @param dt Frame time in seconds
102 virtual void update(double dt);
104 bool addEventListener(const std::string& type, const EventListener& cb);
105 virtual void clearEventListener();
107 virtual bool accept(EventVisitor& visitor);
108 virtual bool ascend(EventVisitor& visitor);
109 virtual bool traverse(EventVisitor& visitor);
111 virtual bool handleEvent(EventPtr event);
112 bool dispatchEvent(EventPtr event);
116 * @param global_pos Position in global (canvas) coordinate frame
117 * @param parent_pos Position in parent coordinate frame
118 * @param local_pos Position in local (element) coordinate frame
120 virtual bool hitBound( const osg::Vec2f& global_pos,
121 const osg::Vec2f& parent_pos,
122 const osg::Vec2f& local_pos ) const;
125 * Set visibility of the element.
127 void setVisible(bool visible);
130 * Get whether the element is visible or hidden.
132 bool isVisible() const;
134 osg::MatrixTransform* getMatrixTransform();
135 osg::MatrixTransform const* getMatrixTransform() const;
138 * Transform position to local coordinages.
140 osg::Vec2f posToLocal(const osg::Vec2f& pos) const;
142 virtual void childAdded( SGPropertyNode * parent,
143 SGPropertyNode * child );
144 virtual void childRemoved( SGPropertyNode * parent,
145 SGPropertyNode * child );
146 virtual void valueChanged(SGPropertyNode * child);
148 virtual bool setStyle( const SGPropertyNode* child,
149 const StyleInfo* style_info = 0 );
154 * @note Only "rect(<top>, <right>, <bottom>, <left>)" is supported
155 * @see http://www.w3.org/TR/CSS21/visufx.html#propdef-clip
157 void setClip(const std::string& clip);
160 * Clipping coordinates reference frame
162 void setClipFrame(ReferenceFrame rf);
165 * Get bounding box (may not be as tight as bounding box returned by
168 osg::BoundingBox getBoundingBox() const;
171 * Get tight bounding box (child points are transformed to elements
172 * coordinate space before calculating the bounding box).
174 osg::BoundingBox getTightBoundingBox() const;
177 * Get bounding box with children/drawables transformed by passed matrix
179 virtual osg::BoundingBox getTransformedBounds(const osg::Matrix& m) const;
182 * Get the transformation matrix (product of all transforms)
184 osg::Matrix getMatrix() const;
187 * Create an canvas Element
189 * @tparam Derived Type of element (needs to derive from Element)
191 template<typename Derived>
193 typename boost::enable_if<
194 boost::is_base_of<Element, Derived>,
196 >::type create( const CanvasWeakPtr& canvas,
197 const SGPropertyNode_ptr& node,
201 return ElementPtr( new Derived(canvas, node, style, parent) );
209 BLEND_FUNC = TRANSFORM << 1,
210 SCISSOR_COORDS = BLEND_FUNC << 1,
211 LAST_ATTRIBUTE = SCISSOR_COORDS << 1
223 class RelativeScissor;
225 CanvasWeakPtr _canvas;
228 mutable uint32_t _attributes_dirty;
230 osg::observer_ptr<osg::MatrixTransform> _transform;
231 std::vector<TransformType> _transform_types;
234 RelativeScissor *_scissor;
236 typedef std::vector<EventListener> Listener;
237 typedef std::map<int, Listener> ListenerMap;
239 ListenerMap _listener;
241 typedef std::map<std::string, StyleInfo> StyleSetters;
242 static StyleSetters _style_setters;
244 static void staticInit();
246 Element( const CanvasWeakPtr& canvas,
247 const SGPropertyNode_ptr& node,
248 const Style& parent_style,
252 * Returns false on first call and true on any successive call. Use to
253 * perform initialization tasks which are only required once per element
256 * @tparam Derived (Derived) class type
258 template<class Derived>
261 static bool is_init = false;
270 * Register a function for setting a style specified by the given property
272 * @param name Property name
273 * @param type Interpolation type
274 * @param setter Setter function
276 * @tparam T1 Type of value used to retrieve value from property
278 * @tparam T2 Type of value the setter function expects
279 * @tparam Derived Type of class the setter can be applied to
281 * @note T1 needs to be convertible to T2
290 addStyle( const std::string& name,
291 const std::string& type,
292 const boost::function<void (Derived&, T2)>& setter,
293 bool inheritable = true )
295 StyleInfo& style_info = _style_setters[ name ];
298 if( !style_info.type.empty() && type != style_info.type )
303 "changing animation type for '" << name << "': "
304 << style_info.type << " -> " << type
307 style_info.type = type;
309 // TODO check if changed?
310 style_info.inheritable = inheritable;
312 StyleSetter* style = &style_info.setter;
316 style = style->next = new StyleSetter;
318 style->func = boost::bind
320 &type_match<Derived>::call,
323 bindStyleSetter<T1>(name, setter)
334 addStyle( const std::string& name,
335 const std::string& type,
336 const boost::function<void (Derived&, T)>& setter,
337 bool inheritable = true )
339 return addStyle<T, T>(name, type, setter, inheritable);
348 addStyle( const std::string& name,
349 const std::string& type,
350 void (Derived::*setter)(T),
351 bool inheritable = true )
353 return addStyle<T, T>
357 boost::function<void (Derived&, T)>(setter),
369 addStyle( const std::string& name,
370 const std::string& type,
371 void (Derived::*setter)(T2),
372 bool inheritable = true )
378 boost::function<void (Derived&, T2)>(setter),
388 addStyle( const std::string& name,
389 const std::string& type,
390 void (Derived::*setter)(const std::string&),
391 bool inheritable = true )
393 return addStyle<const char*, const std::string&>
397 boost::function<void (Derived&, const std::string&)>(setter),
410 addStyle( const std::string& name,
411 const std::string& type,
412 void (Other::*setter)(T),
413 OtherRef Derived::*instance_ref,
414 bool inheritable = true )
416 return addStyle<T, T>
420 bindOther(setter, instance_ref),
434 addStyle( const std::string& name,
435 const std::string& type,
436 void (Other::*setter)(T2),
437 OtherRef Derived::*instance_ref,
438 bool inheritable = true )
444 bindOther(setter, instance_ref),
458 addStyle( const std::string& name,
459 const std::string& type,
460 const boost::function<void (Other&, T2)>& setter,
461 OtherRef Derived::*instance_ref,
462 bool inheritable = true )
468 bindOther(setter, instance_ref),
480 addStyle( const std::string& name,
481 const std::string& type,
482 void (Other::*setter)(const std::string&),
483 OtherRef Derived::*instance_ref,
484 bool inheritable = true )
486 return addStyle<const char*, const std::string&>
490 boost::function<void (Other&, const std::string&)>(setter),
496 template<typename T, class Derived, class Other, class OtherRef>
498 boost::function<void (Derived&, T)>
499 bindOther( void (Other::*setter)(T), OtherRef Derived::*instance_ref )
501 return boost::bind(setter, boost::bind(instance_ref, _1), _2);
504 template<typename T, class Derived, class Other, class OtherRef>
506 boost::function<void (Derived&, T)>
507 bindOther( const boost::function<void (Other&, T)>& setter,
508 OtherRef Derived::*instance_ref )
515 &reference_from_pointer<Other, OtherRef>,
516 boost::bind(instance_ref, _1)
522 template<typename T1, typename T2, class Derived>
524 StyleSetterFuncUnchecked
525 bindStyleSetter( const std::string& name,
526 const boost::function<void (Derived&, T2)>& setter )
531 // We will only call setters with Derived instances, so we can safely
533 boost::bind(&derived_cast<Derived>, _1),
534 boost::bind(&getValue<T1>, _2)
538 bool isStyleEmpty(const SGPropertyNode* child) const;
539 bool canApplyStyle(const SGPropertyNode* child) const;
540 bool setStyleImpl( const SGPropertyNode* child,
541 const StyleInfo* style_info = 0 );
543 const StyleInfo* getStyleInfo(const std::string& name) const;
544 const StyleSetter* getStyleSetter(const std::string& name) const;
545 const SGPropertyNode* getParentStyle(const SGPropertyNode* child) const;
547 virtual void childAdded(SGPropertyNode * child) {}
548 virtual void childRemoved(SGPropertyNode * child){}
549 virtual void childChanged(SGPropertyNode * child){}
551 void setDrawable(osg::Drawable* drawable);
554 * Get stateset of drawable if available or use transform otherwise
556 osg::StateSet* getOrCreateStateSet();
562 osg::ref_ptr<osg::Drawable> _drawable;
564 Element(const Element&);// = delete
566 template<class Derived>
567 static Derived& derived_cast(Element& el)
569 return static_cast<Derived&>(el);
572 template<class T, class SharedPtr>
573 static T& reference_from_pointer(const SharedPtr& p)
575 return *get_pointer(p);
579 * Helper to call a function only of the element type can be converted to
582 * @return Whether the function has been called
584 template<class Derived>
587 static bool call( Element& el,
588 const SGPropertyNode* prop,
589 const StyleSetterFuncUnchecked& func )
591 Derived* d = dynamic_cast<Derived*>(&el);
600 } // namespace canvas
603 struct enum_traits<canvas::Element::ReferenceFrame>
605 static const char* name()
607 return "canvas::Element::ReferenceFrame";
610 static canvas::Element::ReferenceFrame defVal()
612 return canvas::Element::GLOBAL;
615 static bool validate(int frame)
617 return frame >= canvas::Element::GLOBAL
618 && frame <= canvas::Element::LOCAL;
622 } // namespace simgear
624 #endif /* CANVAS_ELEMENT_HXX_ */