1 ///@file 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 * Baseclass for Elements displayed inside a Canvas.
48 public PropertyBasedElement
53 * Store pointer to window as user data
56 public osg::Referenced
60 OSGUserData(ElementPtr element);
63 typedef boost::function<bool(Element&, const SGPropertyNode*)>
65 typedef boost::function<void(Element&, const SGPropertyNode*)>
66 StyleSetterFuncUnchecked;
71 SGSharedPtr<StyleSetter> next;
75 StyleSetter setter; ///< Function(s) for setting this style
76 std::string type; ///< Interpolation type
77 bool inheritable; ///< Whether children can inherit this style from
82 * Coordinate reference frame (eg. "clip" property)
86 GLOBAL, ///< Global coordinates
87 PARENT, ///< Coordinates relative to parent coordinate frame
88 LOCAL ///< Coordinates relative to local coordinates (parent
89 /// coordinates with local transformations applied)
95 virtual ~Element() = 0;
96 virtual void onDestroy();
98 ElementPtr getParent();
101 * Called every frame to update internal state
103 * @param dt Frame time in seconds
105 virtual void update(double dt);
107 bool addEventListener(const std::string& type, const EventListener& cb);
108 virtual void clearEventListener();
111 void setDataProp( const std::string& name,
114 const std::string& attr = dataPropToAttrName(name);
118 SG_LOG(SG_GENERAL, SG_WARN, "Invalid data-prop name: " << name);
122 T getDataProp( const std::string& name,
125 const std::string& attr = dataPropToAttrName(name);
127 return get<T>(attr, def);
129 SG_LOG(SG_GENERAL, SG_WARN, "Invalid data-prop name: " << name);
134 virtual bool accept(EventVisitor& visitor);
135 virtual bool ascend(EventVisitor& visitor);
136 virtual bool traverse(EventVisitor& visitor);
138 virtual bool handleEvent(EventPtr event);
139 bool dispatchEvent(EventPtr event);
143 * @param global_pos Position in global (canvas) coordinate frame
144 * @param parent_pos Position in parent coordinate frame
145 * @param local_pos Position in local (element) coordinate frame
147 virtual bool hitBound( const osg::Vec2f& global_pos,
148 const osg::Vec2f& parent_pos,
149 const osg::Vec2f& local_pos ) const;
152 * Set visibility of the element.
154 void setVisible(bool visible);
157 * Get whether the element is visible or hidden.
159 bool isVisible() const;
161 osg::MatrixTransform* getMatrixTransform();
162 osg::MatrixTransform const* getMatrixTransform() const;
165 * Transform position to local coordinages.
167 osg::Vec2f posToLocal(const osg::Vec2f& pos) const;
169 virtual void childAdded( SGPropertyNode * parent,
170 SGPropertyNode * child );
171 virtual void childRemoved( SGPropertyNode * parent,
172 SGPropertyNode * child );
173 virtual void valueChanged(SGPropertyNode * child);
175 virtual bool setStyle( const SGPropertyNode* child,
176 const StyleInfo* style_info = 0 );
181 * @note Only "rect(<top>, <right>, <bottom>, <left>)" is supported
182 * @see http://www.w3.org/TR/CSS21/visufx.html#propdef-clip
184 void setClip(const std::string& clip);
187 * Clipping coordinates reference frame
189 void setClipFrame(ReferenceFrame rf);
192 * Get bounding box (may not be as tight as bounding box returned by
195 osg::BoundingBox getBoundingBox() const;
198 * Get tight bounding box (child points are transformed to elements
199 * coordinate space before calculating the bounding box).
201 osg::BoundingBox getTightBoundingBox() const;
204 * Get bounding box with children/drawables transformed by passed matrix
206 virtual osg::BoundingBox getTransformedBounds(const osg::Matrix& m) const;
209 * Get the transformation matrix (product of all transforms)
211 osg::Matrix getMatrix() const;
214 * Create an canvas Element
216 * @tparam Derived Type of element (needs to derive from Element)
218 template<typename Derived>
220 typename boost::enable_if<
221 boost::is_base_of<Element, Derived>,
223 >::type create( const CanvasWeakPtr& canvas,
224 const SGPropertyNode_ptr& node,
225 const Style& style = Style(),
226 Element* parent = NULL )
228 return ElementPtr( new Derived(canvas, node, style, parent) );
231 static std::string dataPropToAttrName(const std::string& name);
232 static std::string attrToDataPropName(const std::string& name);
239 BLEND_FUNC = TRANSFORM << 1,
240 SCISSOR_COORDS = BLEND_FUNC << 1,
241 LAST_ATTRIBUTE = SCISSOR_COORDS << 1
253 class RelativeScissor;
255 CanvasWeakPtr _canvas;
258 mutable uint32_t _attributes_dirty;
260 osg::observer_ptr<osg::MatrixTransform> _transform;
261 std::vector<TransformType> _transform_types;
264 RelativeScissor *_scissor;
266 typedef std::vector<EventListener> Listener;
267 typedef std::map<int, Listener> ListenerMap;
269 ListenerMap _listener;
271 typedef std::map<std::string, StyleInfo> StyleSetters;
272 static StyleSetters _style_setters;
274 static void staticInit();
276 Element( const CanvasWeakPtr& canvas,
277 const SGPropertyNode_ptr& node,
278 const Style& parent_style,
282 * Returns false on first call and true on any successive call. Use to
283 * perform initialization tasks which are only required once per element
286 * @tparam Derived (Derived) class type
288 template<class Derived>
291 static bool is_init = false;
300 * Register a function for setting a style specified by the given property
302 * @param name Property name
303 * @param type Interpolation type
304 * @param setter Setter function
306 * @tparam T1 Type of value used to retrieve value from property
308 * @tparam T2 Type of value the setter function expects
309 * @tparam Derived Type of class the setter can be applied to
311 * @note T1 needs to be convertible to T2
320 addStyle( const std::string& name,
321 const std::string& type,
322 const boost::function<void (Derived&, T2)>& setter,
323 bool inheritable = true )
325 StyleInfo& style_info = _style_setters[ name ];
328 if( !style_info.type.empty() && type != style_info.type )
333 "changing animation type for '" << name << "': "
334 << style_info.type << " -> " << type
337 style_info.type = type;
339 // TODO check if changed?
340 style_info.inheritable = inheritable;
342 StyleSetter* style = &style_info.setter;
346 style = style->next = new StyleSetter;
348 style->func = boost::bind
350 &type_match<Derived>::call,
353 bindStyleSetter<T1>(name, setter)
364 addStyle( const std::string& name,
365 const std::string& type,
366 const boost::function<void (Derived&, T)>& setter,
367 bool inheritable = true )
369 return addStyle<T, T>(name, type, setter, inheritable);
378 addStyle( const std::string& name,
379 const std::string& type,
380 void (Derived::*setter)(T),
381 bool inheritable = true )
383 return addStyle<T, T>
387 boost::function<void (Derived&, T)>(setter),
399 addStyle( const std::string& name,
400 const std::string& type,
401 void (Derived::*setter)(T2),
402 bool inheritable = true )
408 boost::function<void (Derived&, T2)>(setter),
418 addStyle( const std::string& name,
419 const std::string& type,
420 void (Derived::*setter)(const std::string&),
421 bool inheritable = true )
423 return addStyle<const char*, const std::string&>
427 boost::function<void (Derived&, const std::string&)>(setter),
440 addStyle( const std::string& name,
441 const std::string& type,
442 void (Other::*setter)(T),
443 OtherRef Derived::*instance_ref,
444 bool inheritable = true )
446 return addStyle<T, T>
450 bindOther(setter, instance_ref),
464 addStyle( const std::string& name,
465 const std::string& type,
466 void (Other::*setter)(T2),
467 OtherRef Derived::*instance_ref,
468 bool inheritable = true )
474 bindOther(setter, instance_ref),
488 addStyle( const std::string& name,
489 const std::string& type,
490 const boost::function<void (Other&, T2)>& setter,
491 OtherRef Derived::*instance_ref,
492 bool inheritable = true )
498 bindOther(setter, instance_ref),
510 addStyle( const std::string& name,
511 const std::string& type,
512 void (Other::*setter)(const std::string&),
513 OtherRef Derived::*instance_ref,
514 bool inheritable = true )
516 return addStyle<const char*, const std::string&>
520 boost::function<void (Other&, const std::string&)>(setter),
526 template<typename T, class Derived, class Other, class OtherRef>
528 boost::function<void (Derived&, T)>
529 bindOther( void (Other::*setter)(T), OtherRef Derived::*instance_ref )
531 return boost::bind(setter, boost::bind(instance_ref, _1), _2);
534 template<typename T, class Derived, class Other, class OtherRef>
536 boost::function<void (Derived&, T)>
537 bindOther( const boost::function<void (Other&, T)>& setter,
538 OtherRef Derived::*instance_ref )
545 &reference_from_pointer<Other, OtherRef>,
546 boost::bind(instance_ref, _1)
552 template<typename T1, typename T2, class Derived>
554 StyleSetterFuncUnchecked
555 bindStyleSetter( const std::string& name,
556 const boost::function<void (Derived&, T2)>& setter )
561 // We will only call setters with Derived instances, so we can safely
563 boost::bind(&derived_cast<Derived>, _1),
564 boost::bind(&getValue<T1>, _2)
568 bool isStyleEmpty(const SGPropertyNode* child) const;
569 bool canApplyStyle(const SGPropertyNode* child) const;
570 bool setStyleImpl( const SGPropertyNode* child,
571 const StyleInfo* style_info = 0 );
573 const StyleInfo* getStyleInfo(const std::string& name) const;
574 const StyleSetter* getStyleSetter(const std::string& name) const;
575 const SGPropertyNode* getParentStyle(const SGPropertyNode* child) const;
577 virtual void childAdded(SGPropertyNode * child) {}
578 virtual void childRemoved(SGPropertyNode * child){}
579 virtual void childChanged(SGPropertyNode * child){}
581 void setDrawable(osg::Drawable* drawable);
584 * Get stateset of drawable if available or use transform otherwise
586 osg::StateSet* getOrCreateStateSet();
592 osg::ref_ptr<osg::Drawable> _drawable;
594 Element(const Element&);// = delete
596 template<class Derived>
597 static Derived& derived_cast(Element& el)
599 return static_cast<Derived&>(el);
602 template<class T, class SharedPtr>
603 static T& reference_from_pointer(const SharedPtr& p)
605 return *get_pointer(p);
609 * Helper to call a function only of the element type can be converted to
612 * @return Whether the function has been called
614 template<class Derived>
617 static bool call( Element& el,
618 const SGPropertyNode* prop,
619 const StyleSetterFuncUnchecked& func )
621 Derived* d = dynamic_cast<Derived*>(&el);
630 } // namespace canvas
633 struct enum_traits<canvas::Element::ReferenceFrame>
635 static const char* name()
637 return "canvas::Element::ReferenceFrame";
640 static canvas::Element::ReferenceFrame defVal()
642 return canvas::Element::GLOBAL;
645 static bool validate(int frame)
647 return frame >= canvas::Element::GLOBAL
648 && frame <= canvas::Element::LOCAL;
652 } // namespace simgear
654 #endif /* CANVAS_ELEMENT_HXX_ */