]> git.mxchange.org Git - flightgear.git/commitdiff
Canvas: Forward mouse events to elements.
authorThomas Geymayer <thomas.geymayer@student.tugraz.at>
Fri, 10 Aug 2012 11:11:06 +0000 (13:11 +0200)
committerThomas Geymayer <thomas.geymayer@student.tugraz.at>
Fri, 10 Aug 2012 11:11:06 +0000 (13:11 +0200)
 - Use bounding box intersections to determine which element is
   hit.
 - Transform mouse coordinates to local coordinates.
 - Try to get osgText bounding box correct (or at least better)

src/Canvas/MouseEvent.hxx
src/Canvas/canvas.cxx
src/Canvas/elements/element.cxx
src/Canvas/elements/element.hxx
src/Canvas/elements/group.cxx
src/Canvas/elements/group.hxx
src/Canvas/elements/text.cxx

index 0bd5d44a07d42fc12efe972e838efbe158b736ff..c9b8c4d1c819eb0bc1a85b336caea4d98dd241e8 100644 (file)
@@ -36,13 +36,17 @@ namespace canvas
         dx(0), dy(0),
         button(-1),
         state(-1),
-        mod(-1)
+        mod(-1),
+        scroll(osgGA::GUIEventAdapter::SCROLL_NONE)
       {}
 
+      osg::Vec2f getPos() const { return osg::Vec2f(x, y); }
+      osg::Vec3f getPos3() const { return osg::Vec3f(x, y, 0); }
+
       EventType   type;
-      int         x, y,
-                  dx, dy,
-                  button, //<! Button for this event
+      float       x, y,
+                  dx, dy;
+      int         button, //<! Button for this event
                   state,  //<! Current button state
                   mod;    //<! Keyboard modifier state
       Scroll      scroll;
index 086ace05c4cf48418fa0ecd93577c612215c21b4..25ce15e8c27440b75555656cb3543d78eec11e99 100644 (file)
@@ -279,7 +279,8 @@ bool Canvas::handleMouseEvent(const canvas::MouseEvent& event)
   _mouse_scroll = event.scroll;
   // Always set event type last because all listeners are attached to it
   _mouse_event = event.type;
-  return true;
+
+  return _root_group->handleMouseEvent(event);
 }
 
 //------------------------------------------------------------------------------
index 01fbf1a5de98f198c49f874c01d4f64a47723486..040670a430e6b126c37963593d3dc7b9c24d565c 100644 (file)
@@ -17,6 +17,7 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 #include "element.hxx"
+#include <Canvas/MouseEvent.hxx>
 #include <Canvas/property_helper.hxx>
 
 #include <osg/Drawable>
@@ -124,6 +125,31 @@ namespace canvas
     }
   }
 
+  //----------------------------------------------------------------------------
+  bool Element::handleMouseEvent(const canvas::MouseEvent& event)
+  {
+    // Transform event to local coordinates
+    const osg::Matrixd& m = _transform->getInverseMatrix();
+    canvas::MouseEvent local_event = event;
+    local_event.x = m(0, 0) * event.x + m(1, 0) * event.y + m(3, 0);
+    local_event.y = m(0, 1) * event.x + m(1, 1) * event.y + m(3, 1);
+
+    // Drawables have a bounding box...
+    if( _drawable )
+    {
+      if( !_drawable->getBound().contains(local_event.getPos3()) )
+        return false;
+    }
+    // ... for other elements, i.e. groups only a bounding sphere is available
+    else if( !_transform->getBound().contains(local_event.getPos3()) )
+      return false;
+
+    local_event.dx = m(0, 0) * event.dx + m(1, 0) * event.dy;
+    local_event.dy = m(0, 1) * event.dx + m(1, 1) * event.dy;
+
+    return handleLocalMouseEvent(local_event);
+  }
+
   //----------------------------------------------------------------------------
   osg::ref_ptr<osg::MatrixTransform> Element::getMatrixTransform()
   {
@@ -239,6 +265,16 @@ namespace canvas
     );
   }
 
+  //----------------------------------------------------------------------------
+  bool Element::handleLocalMouseEvent(const canvas::MouseEvent& event)
+  {
+    std::cout << _node->getPath()
+              << " local: pos=(" << event.x << "|" << event.y << ") "
+              <<         "d=(" << event.dx << "|" << event.dx << ")"
+              << std::endl;
+    return true;
+  }
+
   //----------------------------------------------------------------------------
   void Element::setDrawable( osg::Drawable* drawable )
   {
index 642060434d0c6521025f10ddd9292dd37028b8dc..782b5d1fb6a989e5163e7961f04f3d2851ff205b 100644 (file)
@@ -31,6 +31,7 @@ namespace osg
 namespace canvas
 {
 
+  class MouseEvent;
   class Element:
     public SGPropertyChangeListener
   {
@@ -44,6 +45,8 @@ namespace canvas
        */
       virtual void update(double dt);
 
+      virtual bool handleMouseEvent(const canvas::MouseEvent& event);
+
       osg::ref_ptr<osg::MatrixTransform> getMatrixTransform();
 
       virtual void childAdded( SGPropertyNode * parent,
@@ -85,6 +88,8 @@ namespace canvas
 
       Element(SGPropertyNode_ptr node, uint32_t attributes_used = 0);
 
+      virtual bool handleLocalMouseEvent(const canvas::MouseEvent& event);
+
       virtual void childAdded(SGPropertyNode * child)  {}
       virtual void childRemoved(SGPropertyNode * child){}
       virtual void childChanged(SGPropertyNode * child){}
index 473ecc2f557b835b26f7cd07a116dab390ee3067..eef81587c1ecc2a958b93bfa2cce67bbe20e59d6 100644 (file)
@@ -22,6 +22,8 @@
 #include "text.hxx"
 #include "CanvasImage.hxx"
 
+#include <boost/foreach.hpp>
+
 namespace canvas
 {
 
@@ -41,19 +43,31 @@ namespace canvas
   //----------------------------------------------------------------------------
   void Group::update(double dt)
   {
-    for( ChildMap::iterator child = _children.begin();
-         child != _children.end();
-         ++child )
-      child->second->update(dt);
+    BOOST_FOREACH( ChildList::value_type child, _children )
+      child.second->update(dt);
 
     Element::update(dt);
   }
 
+  //----------------------------------------------------------------------------
+  bool Group::handleLocalMouseEvent(const canvas::MouseEvent& event)
+  {
+    // Iterate in reverse order as last child is displayed on top
+    BOOST_REVERSE_FOREACH( ChildList::value_type child, _children )
+    {
+      if( child.second->handleMouseEvent(event) )
+        return true;
+    }
+    return false;
+  }
+
   //----------------------------------------------------------------------------
   void Group::childAdded(SGPropertyNode* child)
   {
     boost::shared_ptr<Element> element;
 
+    // TODO create map of child factories and use also to check for element
+    //      on deletion in ::childRemoved
     if( child->getNameString() == "text" )
       element.reset( new Text(child) );
     else if( child->getNameString() == "group" )
@@ -64,24 +78,44 @@ namespace canvas
       element.reset( new Path(child) );
     else if( child->getNameString() == "image" )
       element.reset( new Image(child) );
-    
+
     if( !element )
       return;
 
     // Add to osg scene graph...
     _transform->addChild( element->getMatrixTransform() );
-    _children[ child ] = element;
+    _children.push_back( ChildList::value_type(child, element) );
   }
 
+  //----------------------------------------------------------------------------
+  struct ChildFinder
+  {
+    public:
+      ChildFinder(SGPropertyNode *node):
+        _node(node)
+      {}
+
+      bool operator()(const Group::ChildList::value_type& el) const
+      {
+        return el.first == _node;
+      }
+
+    private:
+      SGPropertyNode *_node;
+  };
+
   //----------------------------------------------------------------------------
   void Group::childRemoved(SGPropertyNode* node)
   {
     if(    node->getNameString() == "text"
         || node->getNameString() == "group"
         || node->getNameString() == "map"
-        || node->getNameString() == "path" )
+        || node->getNameString() == "path"
+        || node->getNameString() == "image" )
     {
-      ChildMap::iterator child = _children.find(node);
+      ChildFinder pred(node);
+      ChildList::iterator child =
+        std::find_if(_children.begin(), _children.end(), pred);
 
       if( child == _children.end() )
         SG_LOG
index 1c07847f919c993655fd93b30ba47a2f8e724909..af64f70dc634a9659382bbb435c85e9be73c7483 100644 (file)
@@ -21,7 +21,7 @@
 
 #include "element.hxx"
 #include <boost/shared_ptr.hpp>
-#include <map>
+#include <list>
 
 namespace canvas
 {
@@ -32,14 +32,21 @@ namespace canvas
     public Element
   {
     public:
+      typedef std::list< std::pair< const SGPropertyNode*,
+                                    ElementPtr
+                                  >
+                       > ChildList;
+
       Group(SGPropertyNode_ptr node);
       virtual ~Group();
 
       virtual void update(double dt);
 
     protected:
-      typedef std::map<const SGPropertyNode*, ElementPtr> ChildMap;
-      ChildMap _children;
+
+      ChildList _children;
+
+      virtual bool handleLocalMouseEvent(const canvas::MouseEvent& event);
 
       virtual void childAdded(SGPropertyNode * child);
       virtual void childRemoved(SGPropertyNode * child);
index 518e7837881869e0b38d2545bff6ae3f87e600ce..3171acc7f852ca1017a1e2cc792b68fe16533405 100644 (file)
@@ -31,6 +31,8 @@ namespace canvas
   {
     public:
       osg::Vec2 handleHit(float x, float y);
+
+      virtual osg::BoundingBox computeBound() const;
   };
 
   //----------------------------------------------------------------------------
@@ -112,6 +114,21 @@ namespace canvas
     );
   }
 
+  //----------------------------------------------------------------------------
+  osg::BoundingBox Text::TextOSG::computeBound() const
+  {
+    osg::BoundingBox bb = osgText::Text::computeBound();
+    if( !bb.valid() )
+      return bb;
+
+    // TODO bounding box still doesn't seem always right (eg. with center
+    //      horizontal alignment not completely accurate)
+    bb._min.y() += _offset.y();
+    bb._max.y() += _offset.y();
+
+    return bb;
+  }
+
   //----------------------------------------------------------------------------
   Text::Text(SGPropertyNode_ptr node):
     Element(node, COLOR | COLOR_FILL | BOUNDING_BOX),