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:
parent
288e7fa5ca
commit
544784ca85
7 changed files with 120 additions and 16 deletions
|
@ -36,13 +36,17 @@ namespace canvas
|
||||||
dx(0), dy(0),
|
dx(0), dy(0),
|
||||||
button(-1),
|
button(-1),
|
||||||
state(-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;
|
EventType type;
|
||||||
int x, y,
|
float x, y,
|
||||||
dx, dy,
|
dx, dy;
|
||||||
button, //<! Button for this event
|
int button, //<! Button for this event
|
||||||
state, //<! Current button state
|
state, //<! Current button state
|
||||||
mod; //<! Keyboard modifier state
|
mod; //<! Keyboard modifier state
|
||||||
Scroll scroll;
|
Scroll scroll;
|
||||||
|
|
|
@ -279,7 +279,8 @@ bool Canvas::handleMouseEvent(const canvas::MouseEvent& event)
|
||||||
_mouse_scroll = event.scroll;
|
_mouse_scroll = event.scroll;
|
||||||
// Always set event type last because all listeners are attached to it
|
// Always set event type last because all listeners are attached to it
|
||||||
_mouse_event = event.type;
|
_mouse_event = event.type;
|
||||||
return true;
|
|
||||||
|
return _root_group->handleMouseEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
#include "element.hxx"
|
#include "element.hxx"
|
||||||
|
#include <Canvas/MouseEvent.hxx>
|
||||||
#include <Canvas/property_helper.hxx>
|
#include <Canvas/property_helper.hxx>
|
||||||
|
|
||||||
#include <osg/Drawable>
|
#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()
|
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 )
|
void Element::setDrawable( osg::Drawable* drawable )
|
||||||
{
|
{
|
||||||
|
|
|
@ -31,6 +31,7 @@ namespace osg
|
||||||
namespace canvas
|
namespace canvas
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class MouseEvent;
|
||||||
class Element:
|
class Element:
|
||||||
public SGPropertyChangeListener
|
public SGPropertyChangeListener
|
||||||
{
|
{
|
||||||
|
@ -44,6 +45,8 @@ namespace canvas
|
||||||
*/
|
*/
|
||||||
virtual void update(double dt);
|
virtual void update(double dt);
|
||||||
|
|
||||||
|
virtual bool handleMouseEvent(const canvas::MouseEvent& event);
|
||||||
|
|
||||||
osg::ref_ptr<osg::MatrixTransform> getMatrixTransform();
|
osg::ref_ptr<osg::MatrixTransform> getMatrixTransform();
|
||||||
|
|
||||||
virtual void childAdded( SGPropertyNode * parent,
|
virtual void childAdded( SGPropertyNode * parent,
|
||||||
|
@ -85,6 +88,8 @@ namespace canvas
|
||||||
|
|
||||||
Element(SGPropertyNode_ptr node, uint32_t attributes_used = 0);
|
Element(SGPropertyNode_ptr node, uint32_t attributes_used = 0);
|
||||||
|
|
||||||
|
virtual bool handleLocalMouseEvent(const canvas::MouseEvent& event);
|
||||||
|
|
||||||
virtual void childAdded(SGPropertyNode * child) {}
|
virtual void childAdded(SGPropertyNode * child) {}
|
||||||
virtual void childRemoved(SGPropertyNode * child){}
|
virtual void childRemoved(SGPropertyNode * child){}
|
||||||
virtual void childChanged(SGPropertyNode * child){}
|
virtual void childChanged(SGPropertyNode * child){}
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
#include "text.hxx"
|
#include "text.hxx"
|
||||||
#include "CanvasImage.hxx"
|
#include "CanvasImage.hxx"
|
||||||
|
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
namespace canvas
|
namespace canvas
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -41,19 +43,31 @@ namespace canvas
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Group::update(double dt)
|
void Group::update(double dt)
|
||||||
{
|
{
|
||||||
for( ChildMap::iterator child = _children.begin();
|
BOOST_FOREACH( ChildList::value_type child, _children )
|
||||||
child != _children.end();
|
child.second->update(dt);
|
||||||
++child )
|
|
||||||
child->second->update(dt);
|
|
||||||
|
|
||||||
Element::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)
|
void Group::childAdded(SGPropertyNode* child)
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Element> element;
|
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" )
|
if( child->getNameString() == "text" )
|
||||||
element.reset( new Text(child) );
|
element.reset( new Text(child) );
|
||||||
else if( child->getNameString() == "group" )
|
else if( child->getNameString() == "group" )
|
||||||
|
@ -64,24 +78,44 @@ namespace canvas
|
||||||
element.reset( new Path(child) );
|
element.reset( new Path(child) );
|
||||||
else if( child->getNameString() == "image" )
|
else if( child->getNameString() == "image" )
|
||||||
element.reset( new Image(child) );
|
element.reset( new Image(child) );
|
||||||
|
|
||||||
if( !element )
|
if( !element )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Add to osg scene graph...
|
// Add to osg scene graph...
|
||||||
_transform->addChild( element->getMatrixTransform() );
|
_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)
|
void Group::childRemoved(SGPropertyNode* node)
|
||||||
{
|
{
|
||||||
if( node->getNameString() == "text"
|
if( node->getNameString() == "text"
|
||||||
|| node->getNameString() == "group"
|
|| node->getNameString() == "group"
|
||||||
|| node->getNameString() == "map"
|
|| 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() )
|
if( child == _children.end() )
|
||||||
SG_LOG
|
SG_LOG
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
#include "element.hxx"
|
#include "element.hxx"
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
#include <map>
|
#include <list>
|
||||||
|
|
||||||
namespace canvas
|
namespace canvas
|
||||||
{
|
{
|
||||||
|
@ -32,14 +32,21 @@ namespace canvas
|
||||||
public Element
|
public Element
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
typedef std::list< std::pair< const SGPropertyNode*,
|
||||||
|
ElementPtr
|
||||||
|
>
|
||||||
|
> ChildList;
|
||||||
|
|
||||||
Group(SGPropertyNode_ptr node);
|
Group(SGPropertyNode_ptr node);
|
||||||
virtual ~Group();
|
virtual ~Group();
|
||||||
|
|
||||||
virtual void update(double dt);
|
virtual void update(double dt);
|
||||||
|
|
||||||
protected:
|
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 childAdded(SGPropertyNode * child);
|
||||||
virtual void childRemoved(SGPropertyNode * child);
|
virtual void childRemoved(SGPropertyNode * child);
|
||||||
|
|
|
@ -31,6 +31,8 @@ namespace canvas
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
osg::Vec2 handleHit(float x, float y);
|
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):
|
Text::Text(SGPropertyNode_ptr node):
|
||||||
Element(node, COLOR | COLOR_FILL | BOUNDING_BOX),
|
Element(node, COLOR | COLOR_FILL | BOUNDING_BOX),
|
||||||
|
|
Loading…
Add table
Reference in a new issue