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),
|
||||
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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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){}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
|
|
Loading…
Add table
Reference in a new issue