#include <simgear/canvas/CanvasEvent.hxx>
#include <simgear/props/PropertyBasedElement.hxx>
#include <simgear/misc/stdint.hxx> // for uint32_t
-#include <simgear/nasal/cppbind/Ghost.hxx>
#include <osg/BoundingBox>
#include <osg/MatrixTransform>
#include <boost/bind.hpp>
#include <boost/function.hpp>
+#include <boost/type_traits/is_base_of.hpp>
namespace osg
{
public PropertyBasedElement
{
public:
- typedef boost::function<void(const SGPropertyNode*)> StyleSetter;
- typedef std::map<std::string, StyleSetter> StyleSetters;
/**
- * Remove the property listener of the element.
- *
- * You will need to call the appropriate methods (#childAdded,
- * #childRemoved, #valueChanged) yourself to ensure the element still
- * receives the needed events.
+ * Store pointer to window as user data
*/
- void removeListener();
+ class OSGUserData:
+ public osg::Referenced
+ {
+ public:
+ ElementPtr element;
+ OSGUserData(ElementPtr element);
+ };
+
+ typedef boost::function<bool(Element&, const SGPropertyNode*)>
+ StyleSetterFunc;
+ typedef boost::function<void(Element&, const SGPropertyNode*)>
+ StyleSetterFuncUnchecked;
+ struct StyleSetter:
+ public SGReferenced
+ {
+ StyleSetterFunc func;
+ SGSharedPtr<StyleSetter> next;
+ };
+ struct StyleInfo
+ {
+ StyleSetter setter; ///!< Function(s) for setting this style
+ std::string type; ///!< Interpolation type
+ bool inheritable; ///!< Whether children can inherit this style from
+ /// their parents
+ };
+
+ /**
+ * Coordinate reference frame (eg. "clip" property)
+ */
+ enum ReferenceFrame
+ {
+ GLOBAL, ///!< Global coordinates
+ PARENT, ///!< Coordinates relative to parent coordinate frame
+ LOCAL ///!< Coordinates relative to local coordinates (parent
+ /// coordinates with local transformations applied)
+ };
/**
*
*/
virtual ~Element() = 0;
+ virtual void setSelf(const PropertyBasedElementPtr& self);
+ virtual void onDestroy();
+
ElementWeakPtr getWeakPtr() const;
+ ElementPtr getParent();
/**
* Called every frame to update internal state
*/
virtual void update(double dt);
- naRef addEventListener(const nasal::CallContext& ctx);
+ bool addEventListener(const std::string& type, const EventListener& cb);
+ virtual void clearEventListener();
virtual bool accept(EventVisitor& visitor);
virtual bool ascend(EventVisitor& visitor);
virtual bool traverse(EventVisitor& visitor);
- void callListeners(const canvas::EventPtr& event);
+ virtual bool handleEvent(canvas::EventPtr event);
- virtual bool hitBound( const osg::Vec2f& pos,
+ /**
+ *
+ * @param global_pos Position in global (canvas) coordinate frame
+ * @param parent_pos Position in parent coordinate frame
+ * @param local_pos Position in local (element) coordinate frame
+ */
+ virtual bool hitBound( const osg::Vec2f& global_pos,
+ const osg::Vec2f& parent_pos,
const osg::Vec2f& local_pos ) const;
/**
- * Get whether the element is visible or hidden (Can be changed with
- * setting property "visible" accordingly).
+ * Set visibility of the element.
+ */
+ void setVisible(bool visible);
+
+ /**
+ * Get whether the element is visible or hidden.
*/
bool isVisible() const;
- osg::ref_ptr<osg::MatrixTransform> getMatrixTransform();
+ osg::MatrixTransform* getMatrixTransform();
+ osg::MatrixTransform const* getMatrixTransform() const;
+
+ /**
+ * Transform position to local coordinages.
+ */
+ osg::Vec2f posToLocal(const osg::Vec2f& pos) const;
virtual void childAdded( SGPropertyNode * parent,
SGPropertyNode * child );
SGPropertyNode * child );
virtual void valueChanged(SGPropertyNode * child);
- virtual bool setStyle(const SGPropertyNode* child);
+ virtual bool setStyle( const SGPropertyNode* child,
+ const StyleInfo* style_info = 0 );
/**
* Set clipping shape
*/
void setClip(const std::string& clip);
+ /**
+ * Clipping coordinates reference frame
+ */
+ void setClipFrame(ReferenceFrame rf);
+
/**
* Write the given bounding box to the property tree
*/
*/
virtual osg::BoundingBox getTransformedBounds(const osg::Matrix& m) const;
+ /**
+ * Get the transformation matrix (product of all transforms)
+ */
+ osg::Matrix getMatrix() const;
+
+ /**
+ * Create an canvas Element
+ *
+ * @tparam Derived Type of element (needs to derive from Element)
+ */
+ template<typename Derived>
+ static
+ typename boost::enable_if<
+ boost::is_base_of<Element, Derived>,
+ ElementPtr
+ >::type create( const CanvasWeakPtr& canvas,
+ const SGPropertyNode_ptr& node,
+ const Style& style,
+ Element* parent )
+ {
+ ElementPtr el( new Derived(canvas, node, style, parent) );
+ el->setSelf(el);
+ return el;
+ }
+
protected:
enum Attributes
{
- LAST_ATTRIBUTE = 0x0001
+ TRANSFORM = 1,
+ BLEND_FUNC = TRANSFORM << 1,
+ SCISSOR_COORDS = BLEND_FUNC << 1,
+ LAST_ATTRIBUTE = SCISSOR_COORDS << 1
};
enum TransformType
TT_SCALE
};
+ class RelativeScissor;
+
CanvasWeakPtr _canvas;
Element *_parent;
- uint32_t _attributes_dirty;
+ mutable uint32_t _attributes_dirty;
- bool _transform_dirty;
- osg::ref_ptr<osg::MatrixTransform> _transform;
- std::vector<TransformType> _transform_types;
+ osg::observer_ptr<osg::MatrixTransform> _transform;
+ std::vector<TransformType> _transform_types;
Style _style;
- StyleSetters _style_setters;
std::vector<SGPropertyNode_ptr> _bounding_box;
+ RelativeScissor *_scissor;
- typedef std::vector<EventListenerPtr> Listener;
+ typedef std::vector<EventListener> Listener;
typedef std::map<Event::Type, Listener> ListenerMap;
ListenerMap _listener;
+ typedef std::map<std::string, StyleInfo> StyleSetters;
+ static StyleSetters _style_setters;
+
+ static void staticInit();
+
Element( const CanvasWeakPtr& canvas,
const SGPropertyNode_ptr& node,
const Style& parent_style,
Element* parent );
- template<typename T, class C1, class C2>
- Element::StyleSetter
- addStyle(const std::string& name, void (C1::*setter)(T), C2 instance)
+ /**
+ * Returns false on first call and true on any successive call. Use to
+ * perform initialization tasks which are only required once per element
+ * type.
+ *
+ * @tparam Derived (Derived) class type
+ */
+ template<class Derived>
+ static bool isInit()
+ {
+ static bool is_init = false;
+ if( is_init )
+ return true;
+
+ is_init = true;
+ return false;
+ }
+
+ /**
+ * Register a function for setting a style specified by the given property
+ *
+ * @param name Property name
+ * @param type Interpolation type
+ * @param setter Setter function
+ *
+ * @tparam T1 Type of value used to retrieve value from property
+ * node
+ * @tparam T2 Type of value the setter function expects
+ * @tparam Derived Type of class the setter can be applied to
+ *
+ * @note T1 needs to be convertible to T2
+ */
+ template<
+ typename T1,
+ typename T2,
+ class Derived
+ >
+ static
+ StyleSetter
+ addStyle( const std::string& name,
+ const std::string& type,
+ const boost::function<void (Derived&, T2)>& setter,
+ bool inheritable = true )
+ {
+ StyleInfo& style_info = _style_setters[ name ];
+ if( !type.empty() )
+ {
+ if( !style_info.type.empty() && type != style_info.type )
+ SG_LOG
+ (
+ SG_GENERAL,
+ SG_WARN,
+ "changing animation type for '" << name << "': "
+ << style_info.type << " -> " << type
+ );
+
+ style_info.type = type;
+ }
+ // TODO check if changed?
+ style_info.inheritable = inheritable;
+
+ StyleSetter* style = &style_info.setter;
+ while( style->next )
+ style = style->next;
+ if( style->func )
+ style = style->next = new StyleSetter;
+
+ style->func = boost::bind
+ (
+ &type_match<Derived>::call,
+ _1,
+ _2,
+ bindStyleSetter<T1>(name, setter)
+ );
+ return *style;
+ }
+
+ template<
+ typename T,
+ class Derived
+ >
+ static
+ StyleSetter
+ addStyle( const std::string& name,
+ const std::string& type,
+ const boost::function<void (Derived&, T)>& setter,
+ bool inheritable = true )
+ {
+ return addStyle<T, T>(name, type, setter, inheritable);
+ }
+
+ template<
+ typename T,
+ class Derived
+ >
+ static
+ StyleSetter
+ addStyle( const std::string& name,
+ const std::string& type,
+ void (Derived::*setter)(T),
+ bool inheritable = true )
+ {
+ return addStyle<T, T>
+ (
+ name,
+ type,
+ boost::function<void (Derived&, T)>(setter),
+ inheritable
+ );
+ }
+
+ template<
+ typename T1,
+ typename T2,
+ class Derived
+ >
+ static
+ StyleSetterFunc
+ addStyle( const std::string& name,
+ const std::string& type,
+ void (Derived::*setter)(T2),
+ bool inheritable = true )
+ {
+ return addStyle<T1>
+ (
+ name,
+ type,
+ boost::function<void (Derived&, T2)>(setter),
+ inheritable
+ );
+ }
+
+ template<
+ class Derived
+ >
+ static
+ StyleSetter
+ addStyle( const std::string& name,
+ const std::string& type,
+ void (Derived::*setter)(const std::string&),
+ bool inheritable = true )
+ {
+ return addStyle<const char*, const std::string&>
+ (
+ name,
+ type,
+ boost::function<void (Derived&, const std::string&)>(setter),
+ inheritable
+ );
+ }
+
+ template<
+ typename T,
+ class Derived,
+ class Other,
+ class OtherRef
+ >
+ static
+ StyleSetter
+ addStyle( const std::string& name,
+ const std::string& type,
+ void (Other::*setter)(T),
+ OtherRef Derived::*instance_ref,
+ bool inheritable = true )
+ {
+ return addStyle<T, T>
+ (
+ name,
+ type,
+ bindOther(setter, instance_ref),
+ inheritable
+ );
+ }
+
+ template<
+ typename T1,
+ typename T2,
+ class Derived,
+ class Other,
+ class OtherRef
+ >
+ static
+ StyleSetter
+ addStyle( const std::string& name,
+ const std::string& type,
+ void (Other::*setter)(T2),
+ OtherRef Derived::*instance_ref,
+ bool inheritable = true )
{
- return _style_setters[ name ] =
- bindStyleSetter<T>(name, setter, instance);
+ return addStyle<T1>
+ (
+ name,
+ type,
+ bindOther(setter, instance_ref),
+ inheritable
+ );
}
- template<typename T1, typename T2, class C1, class C2>
- Element::StyleSetter
- addStyle(const std::string& name, void (C1::*setter)(T2), C2 instance)
+ template<
+ typename T1,
+ typename T2,
+ class Derived,
+ class Other,
+ class OtherRef
+ >
+ static
+ StyleSetter
+ addStyle( const std::string& name,
+ const std::string& type,
+ const boost::function<void (Other&, T2)>& setter,
+ OtherRef Derived::*instance_ref,
+ bool inheritable = true )
{
- return _style_setters[ name ] =
- bindStyleSetter<T1>(name, setter, instance);
+ return addStyle<T1>
+ (
+ name,
+ type,
+ bindOther(setter, instance_ref),
+ inheritable
+ );
}
- template<class C1, class C2>
- Element::StyleSetter
+ template<
+ class Derived,
+ class Other,
+ class OtherRef
+ >
+ static
+ StyleSetter
addStyle( const std::string& name,
- void (C1::*setter)(const std::string&),
- C2 instance )
+ const std::string& type,
+ void (Other::*setter)(const std::string&),
+ OtherRef Derived::*instance_ref,
+ bool inheritable = true )
+ {
+ return addStyle<const char*, const std::string&>
+ (
+ name,
+ type,
+ boost::function<void (Other&, const std::string&)>(setter),
+ instance_ref,
+ inheritable
+ );
+ }
+
+ template<typename T, class Derived, class Other, class OtherRef>
+ static
+ boost::function<void (Derived&, T)>
+ bindOther( void (Other::*setter)(T), OtherRef Derived::*instance_ref )
+ {
+ return boost::bind(setter, boost::bind(instance_ref, _1), _2);
+ }
+
+ template<typename T, class Derived, class Other, class OtherRef>
+ static
+ boost::function<void (Derived&, T)>
+ bindOther( const boost::function<void (Other&, T)>& setter,
+ OtherRef Derived::*instance_ref )
{
- return _style_setters[ name ] =
- bindStyleSetter<const char*>(name, setter, instance);
+ return boost::bind
+ (
+ setter,
+ boost::bind
+ (
+ &reference_from_pointer<Other, OtherRef>,
+ boost::bind(instance_ref, _1)
+ ),
+ _2
+ );
}
- template<typename T1, typename T2, class C1, class C2>
- Element::StyleSetter
+ template<typename T1, typename T2, class Derived>
+ static
+ StyleSetterFuncUnchecked
bindStyleSetter( const std::string& name,
- void (C1::*setter)(T2),
- C2 instance )
+ const boost::function<void (Derived&, T2)>& setter )
{
- return boost::bind(setter, instance, boost::bind(&getValue<T1>, _1));
+ return boost::bind
+ (
+ setter,
+ // We will only call setters with Derived instances, so we can safely
+ // cast here.
+ boost::bind(&derived_cast<Derived>, _1),
+ boost::bind(&getValue<T1>, _2)
+ );
}
+ bool isStyleEmpty(const SGPropertyNode* child) const;
+ bool canApplyStyle(const SGPropertyNode* child) const;
+ bool setStyleImpl( const SGPropertyNode* child,
+ const StyleInfo* style_info = 0 );
+
+ const StyleInfo* getStyleInfo(const std::string& name) const;
+ const StyleSetter* getStyleSetter(const std::string& name) const;
+ const SGPropertyNode* getParentStyle(const SGPropertyNode* child) const;
+
virtual void childAdded(SGPropertyNode * child) {}
virtual void childRemoved(SGPropertyNode * child){}
virtual void childChanged(SGPropertyNode * child){}
osg::ref_ptr<osg::Drawable> _drawable;
Element(const Element&);// = delete
+
+ template<class Derived>
+ static Derived& derived_cast(Element& el)
+ {
+ return static_cast<Derived&>(el);
+ }
+
+ template<class T, class SharedPtr>
+ static T& reference_from_pointer(const SharedPtr& p)
+ {
+ return *get_pointer(p);
+ }
+
+ /**
+ * Helper to call a function only of the element type can be converted to
+ * the required type.
+ *
+ * @return Whether the function has been called
+ */
+ template<class Derived>
+ struct type_match
+ {
+ static bool call( Element& el,
+ const SGPropertyNode* prop,
+ const StyleSetterFuncUnchecked& func )
+ {
+ Derived* d = dynamic_cast<Derived*>(&el);
+ if( !d )
+ return false;
+ func(*d, prop);
+ return true;
+ }
+ };
};
} // namespace canvas
+
+ template<>
+ struct enum_traits<canvas::Element::ReferenceFrame>
+ {
+ static const char* name()
+ {
+ return "canvas::Element::ReferenceFrame";
+ }
+
+ static canvas::Element::ReferenceFrame defVal()
+ {
+ return canvas::Element::GLOBAL;
+ }
+
+ static bool validate(int frame)
+ {
+ return frame >= canvas::Element::GLOBAL
+ && frame <= canvas::Element::LOCAL;
+ }
+ };
+
} // namespace simgear
#endif /* CANVAS_ELEMENT_HXX_ */