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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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