]> git.mxchange.org Git - simgear.git/blobdiff - simgear/canvas/elements/CanvasElement.hxx
Canvas: Respect clipping while event handling.
[simgear.git] / simgear / canvas / elements / CanvasElement.hxx
index 65e84dbf339be344ba8dc215a69ec527e25d12c5..dc5e1bf7592985d125b588bc26470c5d4e770ead 100644 (file)
 #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
 {
@@ -45,6 +45,18 @@ namespace canvas
     public PropertyBasedElement
   {
     public:
+
+      /**
+       * Store pointer to window as user data
+       */
+      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*)>
@@ -59,23 +71,31 @@ namespace canvas
       {
         StyleSetter setter; ///!< Function(s) for setting this style
         std::string type;   ///!< Interpolation type
+        bool inheritable;   ///!< Whether children can inherit this style from
+                            ///   their parents
       };
 
       /**
-       * 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.
+       * Coordinate reference frame (eg. "clip" property)
        */
-      void removeListener();
+      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
@@ -84,7 +104,8 @@ namespace canvas
        */
       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);
@@ -92,16 +113,33 @@ namespace canvas
 
       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 );
@@ -109,7 +147,8 @@ namespace canvas
                                  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
@@ -119,6 +158,11 @@ namespace canvas
        */
       void setClip(const std::string& clip);
 
+      /**
+       * Clipping coordinates reference frame
+       */
+      void setClipFrame(ReferenceFrame rf);
+
       /**
        * Write the given bounding box to the property tree
        */
@@ -129,11 +173,39 @@ namespace canvas
        */
       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
@@ -145,19 +217,21 @@ namespace canvas
         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;
       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;
@@ -165,6 +239,8 @@ namespace canvas
       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,
@@ -178,7 +254,7 @@ namespace canvas
        * @tparam Derived    (Derived) class type
        */
       template<class Derived>
-      bool isInit() const
+      static bool isInit()
       {
         static bool is_init = false;
         if( is_init )
@@ -207,10 +283,12 @@ namespace canvas
         typename T2,
         class Derived
       >
+      static
       StyleSetter
       addStyle( const std::string& name,
                 const std::string& type,
-                const boost::function<void (Derived&, T2)>& setter )
+                const boost::function<void (Derived&, T2)>& setter,
+                bool inheritable = true )
       {
         StyleInfo& style_info = _style_setters[ name ];
         if( !type.empty() )
@@ -226,6 +304,8 @@ namespace canvas
 
           style_info.type = type;
         }
+        // TODO check if changed?
+        style_info.inheritable = inheritable;
 
         StyleSetter* style = &style_info.setter;
         while( style->next )
@@ -247,28 +327,33 @@ namespace canvas
         typename T,
         class Derived
       >
+      static
       StyleSetter
       addStyle( const std::string& name,
                 const std::string& type,
-                const boost::function<void (Derived&, T)>& setter )
+                const boost::function<void (Derived&, T)>& setter,
+                bool inheritable = true )
       {
-        return addStyle<T, T>(name, type, setter);
+        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) )
+                void (Derived::*setter)(T),
+                bool inheritable = true )
       {
         return addStyle<T, T>
         (
           name,
           type,
-          boost::function<void (Derived&, T)>(setter)
+          boost::function<void (Derived&, T)>(setter),
+          inheritable
         );
       }
 
@@ -277,32 +362,38 @@ namespace canvas
         typename T2,
         class Derived
       >
+      static
       StyleSetterFunc
       addStyle( const std::string& name,
                 const std::string& type,
-                void (Derived::*setter)(T2) )
+                void (Derived::*setter)(T2),
+                bool inheritable = true )
       {
         return addStyle<T1>
         (
           name,
           type,
-          boost::function<void (Derived&, T2)>(setter)
+          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&) )
+                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)
+          boost::function<void (Derived&, const std::string&)>(setter),
+          inheritable
         );
       }
 
@@ -312,13 +403,21 @@ namespace canvas
         class Other,
         class OtherRef
       >
+      static
       StyleSetter
       addStyle( const std::string& name,
                 const std::string& type,
                 void (Other::*setter)(T),
-                OtherRef Derived::*instance_ref )
+                OtherRef Derived::*instance_ref,
+                bool inheritable = true )
       {
-        return addStyle<T, T>(name, type, bindOther(setter, instance_ref));
+        return addStyle<T, T>
+        (
+          name,
+          type,
+          bindOther(setter, instance_ref),
+          inheritable
+        );
       }
 
       template<
@@ -328,13 +427,21 @@ namespace canvas
         class Other,
         class OtherRef
       >
+      static
       StyleSetter
       addStyle( const std::string& name,
                 const std::string& type,
                 void (Other::*setter)(T2),
-                OtherRef Derived::*instance_ref )
+                OtherRef Derived::*instance_ref,
+                bool inheritable = true )
       {
-        return addStyle<T1>(name, type, bindOther(setter, instance_ref));
+        return addStyle<T1>
+        (
+          name,
+          type,
+          bindOther(setter, instance_ref),
+          inheritable
+        );
       }
 
       template<
@@ -344,13 +451,21 @@ namespace canvas
         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 )
+                OtherRef Derived::*instance_ref,
+                bool inheritable = true )
       {
-        return addStyle<T1>(name, type, bindOther(setter, instance_ref));
+        return addStyle<T1>
+        (
+          name,
+          type,
+          bindOther(setter, instance_ref),
+          inheritable
+        );
       }
 
       template<
@@ -358,22 +473,26 @@ namespace canvas
         class Other,
         class OtherRef
       >
+      static
       StyleSetter
       addStyle( const std::string& name,
                 const std::string& type,
                 void (Other::*setter)(const std::string&),
-                OtherRef Derived::*instance_ref )
+                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
+          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 )
       {
@@ -381,6 +500,7 @@ namespace canvas
       }
 
       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 )
@@ -398,6 +518,7 @@ namespace canvas
       }
 
       template<typename T1, typename T2, class Derived>
+      static
       StyleSetterFuncUnchecked
       bindStyleSetter( const std::string& name,
                        const boost::function<void (Derived&, T2)>& setter )
@@ -412,6 +533,15 @@ namespace canvas
         );
       }
 
+      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){}
@@ -466,6 +596,27 @@ namespace canvas
   };
 
 } // 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_ */