1
0
Fork 0

Canvas: Forward mouse events to elements.

- 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)
This commit is contained in:
Thomas Geymayer 2012-08-10 13:11:06 +02:00
parent 288e7fa5ca
commit 544784ca85
7 changed files with 120 additions and 16 deletions

View 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;

View 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);
}
//------------------------------------------------------------------------------

View 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 )
{

View 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){}

View 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" )
@ -70,18 +84,38 @@ namespace canvas
// 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

View 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);

View 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),