Extend SGPickCallback to allow passing more information to callbacks
This commit is contained in:
@@ -9,6 +9,7 @@ set(HEADERS
|
||||
CanvasEventTypes.hxx
|
||||
CanvasEventVisitor.hxx
|
||||
CanvasMgr.hxx
|
||||
CanvasObjectPlacement.hxx
|
||||
CanvasPlacement.hxx
|
||||
CanvasSystemAdapter.hxx
|
||||
MouseEvent.hxx
|
||||
@@ -23,6 +24,7 @@ set(SOURCES
|
||||
CanvasEventManager.cxx
|
||||
CanvasEventVisitor.cxx
|
||||
CanvasMgr.cxx
|
||||
CanvasObjectPlacement.cxx
|
||||
CanvasPlacement.cxx
|
||||
ODGauge.cxx
|
||||
VGInitOperation.cxx
|
||||
|
||||
244
simgear/canvas/CanvasObjectPlacement.cxx
Normal file
244
simgear/canvas/CanvasObjectPlacement.cxx
Normal file
@@ -0,0 +1,244 @@
|
||||
// Canvas placement for placing a canvas texture onto osg objects.
|
||||
//
|
||||
// It also provides a SGPickCallback for passing mouse events to the canvas and
|
||||
// manages emissive lighting of the placed canvas.
|
||||
//
|
||||
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#include "Canvas.hxx"
|
||||
#include "CanvasObjectPlacement.hxx"
|
||||
#include "MouseEvent.hxx"
|
||||
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/scene/util/SGPickCallback.hxx>
|
||||
|
||||
#include <osgGA/GUIEventAdapter>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
/**
|
||||
* Handle picking events on object with a canvas placed onto
|
||||
*/
|
||||
class ObjectPickCallback:
|
||||
public SGPickCallback
|
||||
{
|
||||
public:
|
||||
|
||||
ObjectPickCallback(const CanvasWeakPtr& canvas):
|
||||
_canvas(canvas)
|
||||
{}
|
||||
|
||||
virtual bool needsUV() const { return true; }
|
||||
|
||||
virtual bool buttonPressed( int,
|
||||
const osgGA::GUIEventAdapter& ea,
|
||||
const Info& info )
|
||||
{
|
||||
MouseEventPtr event(new MouseEvent(ea));
|
||||
updatePosFromUV(event, info.uv);
|
||||
|
||||
if( ea.getEventType() == osgGA::GUIEventAdapter::SCROLL )
|
||||
{
|
||||
event->type = Event::WHEEL;
|
||||
event->delta.set(0,0);
|
||||
switch( ea.getScrollingMotion() )
|
||||
{
|
||||
case osgGA::GUIEventAdapter::SCROLL_UP:
|
||||
event->delta.y() = 1;
|
||||
break;
|
||||
case osgGA::GUIEventAdapter::SCROLL_DOWN:
|
||||
event->delta.y() = -1;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
event->type = Event::MOUSE_DOWN;
|
||||
}
|
||||
|
||||
return handleEvent(event);
|
||||
}
|
||||
|
||||
virtual void buttonReleased( int,
|
||||
const osgGA::GUIEventAdapter& ea,
|
||||
const Info* info )
|
||||
{
|
||||
if( ea.getEventType() != osgGA::GUIEventAdapter::RELEASE )
|
||||
return;
|
||||
|
||||
MouseEventPtr event(new MouseEvent(ea));
|
||||
event->type = Event::MOUSE_UP;
|
||||
updatePosFromUV(event, info ? info->uv : SGVec2d(-1,-1));
|
||||
|
||||
handleEvent(event);
|
||||
}
|
||||
|
||||
virtual void mouseMoved( const osgGA::GUIEventAdapter& ea,
|
||||
const Info* info )
|
||||
{
|
||||
// drag (currently only with LMB)
|
||||
if( ea.getEventType() != osgGA::GUIEventAdapter::DRAG )
|
||||
return;
|
||||
|
||||
MouseEventPtr event(new MouseEvent(ea));
|
||||
event->type = Event::DRAG;
|
||||
updatePosFromUV(event, info ? info->uv : SGVec2d(-1,-1));
|
||||
|
||||
handleEvent(event);
|
||||
}
|
||||
|
||||
virtual bool hover( const osg::Vec2d& windowPos,
|
||||
const Info& info )
|
||||
{
|
||||
// TODO somehow get more info about event (time, modifiers, pressed
|
||||
// buttons, ...)
|
||||
MouseEventPtr event(new MouseEvent);
|
||||
event->type = Event::MOUSE_MOVE;
|
||||
event->screen_pos = windowPos;
|
||||
updatePosFromUV(event, info.uv);
|
||||
|
||||
return handleEvent(event);
|
||||
}
|
||||
|
||||
virtual void mouseLeave( const osg::Vec2d& windowPos )
|
||||
{
|
||||
MouseEventPtr event(new MouseEvent);
|
||||
event->type = Event::MOUSE_LEAVE;
|
||||
event->screen_pos = windowPos;
|
||||
|
||||
handleEvent(event);
|
||||
}
|
||||
|
||||
protected:
|
||||
CanvasWeakPtr _canvas;
|
||||
osg::Vec2f _last_pos,
|
||||
_last_delta;
|
||||
|
||||
void updatePosFromUV(const MouseEventPtr& event, const SGVec2d& uv)
|
||||
{
|
||||
CanvasPtr canvas = _canvas.lock();
|
||||
if( !canvas )
|
||||
return;
|
||||
|
||||
osg::Vec2d pos( uv.x() * canvas->getViewWidth(),
|
||||
(1 - uv.y()) * canvas->getViewHeight() );
|
||||
|
||||
_last_delta = pos - _last_pos;
|
||||
_last_pos = pos;
|
||||
|
||||
event->client_pos = pos;
|
||||
event->delta = _last_delta;
|
||||
}
|
||||
|
||||
bool handleEvent(const MouseEventPtr& event)
|
||||
{
|
||||
CanvasPtr canvas = _canvas.lock();
|
||||
if( !canvas )
|
||||
return false;
|
||||
|
||||
return canvas->handleMouseEvent(event);
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
ObjectPlacement::ObjectPlacement( SGPropertyNode* node,
|
||||
const GroupPtr& group,
|
||||
const CanvasWeakPtr& canvas ):
|
||||
Placement(node),
|
||||
_group(group),
|
||||
_canvas(canvas)
|
||||
{
|
||||
// TODO make more generic and extendable for more properties
|
||||
if( node->hasValue("emission") )
|
||||
setEmission( node->getFloatValue("emission") );
|
||||
if( node->hasValue("capture-events") )
|
||||
setCaptureEvents( node->getBoolValue("capture-events") );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
ObjectPlacement::~ObjectPlacement()
|
||||
{
|
||||
assert( _group->getNumChildren() == 1 );
|
||||
osg::Node *child = _group->getChild(0);
|
||||
|
||||
if( _group->getNumParents() )
|
||||
{
|
||||
osg::Group *parent = _group->getParent(0);
|
||||
parent->addChild(child);
|
||||
parent->removeChild(_group);
|
||||
}
|
||||
|
||||
_group->removeChild(child);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void ObjectPlacement::setEmission(float emit)
|
||||
{
|
||||
emit = SGMiscf::clip(emit, 0, 1);
|
||||
|
||||
if( !_material )
|
||||
{
|
||||
_material = new osg::Material;
|
||||
_material->setColorMode(osg::Material::OFF);
|
||||
_material->setDataVariance(osg::Object::DYNAMIC);
|
||||
_group->getOrCreateStateSet()
|
||||
->setAttribute(_material, ( osg::StateAttribute::ON
|
||||
| osg::StateAttribute::OVERRIDE ) );
|
||||
}
|
||||
|
||||
_material->setEmission(
|
||||
osg::Material::FRONT_AND_BACK,
|
||||
osg::Vec4(emit, emit, emit, emit)
|
||||
);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void ObjectPlacement::setCaptureEvents(bool enable)
|
||||
{
|
||||
if( !enable && _scene_user_data )
|
||||
return;
|
||||
|
||||
if( enable && !_pick_cb )
|
||||
_pick_cb = new ObjectPickCallback(_canvas);
|
||||
|
||||
_scene_user_data = SGSceneUserData::getOrCreateSceneUserData(_group);
|
||||
_scene_user_data->setPickCallback(enable ? _pick_cb.get() : 0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool ObjectPlacement::childChanged(SGPropertyNode* node)
|
||||
{
|
||||
if( node->getParent() != _node )
|
||||
return false;
|
||||
|
||||
if( node->getNameString() == "emission" )
|
||||
setEmission( node->getFloatValue() );
|
||||
else if( node->getNameString() == "capture-events" )
|
||||
setCaptureEvents( node->getBoolValue() );
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
75
simgear/canvas/CanvasObjectPlacement.hxx
Normal file
75
simgear/canvas/CanvasObjectPlacement.hxx
Normal file
@@ -0,0 +1,75 @@
|
||||
// Canvas placement for placing a canvas texture onto osg objects.
|
||||
//
|
||||
// It also provides a SGPickCallback for passing mouse events to the canvas and
|
||||
// manages emissive lighting of the placed canvas.
|
||||
//
|
||||
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef CANVAS_PICK_PLACEMENT_HXX_
|
||||
#define CANVAS_OBJECT_PLACEMENT_HXX_
|
||||
|
||||
#include "CanvasPlacement.hxx"
|
||||
#include "canvas_fwd.hxx"
|
||||
|
||||
#include <simgear/scene/util/SGSceneUserData.hxx>
|
||||
#include <osg/Material>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
class ObjectPlacement:
|
||||
public Placement
|
||||
{
|
||||
public:
|
||||
|
||||
typedef osg::ref_ptr<osg::Group> GroupPtr;
|
||||
typedef osg::ref_ptr<osg::Material> MaterialPtr;
|
||||
|
||||
ObjectPlacement( SGPropertyNode* node,
|
||||
const GroupPtr& group,
|
||||
const CanvasWeakPtr& canvas );
|
||||
virtual ~ObjectPlacement();
|
||||
|
||||
/**
|
||||
* Set emissive lighting of the object the canvas is placed on.
|
||||
*/
|
||||
void setEmission(float emit);
|
||||
|
||||
/**
|
||||
* Set whether pick events should be captured.
|
||||
*/
|
||||
void setCaptureEvents(bool enable);
|
||||
|
||||
virtual bool childChanged(SGPropertyNode* child);
|
||||
|
||||
protected:
|
||||
typedef SGSharedPtr<SGPickCallback> PickCallbackPtr;
|
||||
typedef osg::ref_ptr<SGSceneUserData> SGSceneUserDataPtr;
|
||||
|
||||
GroupPtr _group;
|
||||
MaterialPtr _material;
|
||||
CanvasWeakPtr _canvas;
|
||||
PickCallbackPtr _pick_cb;
|
||||
SGSceneUserDataPtr _scene_user_data;
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
|
||||
#endif /* CANVAS_PICK_PLACEMENT_HXX_ */
|
||||
@@ -38,6 +38,15 @@ namespace canvas
|
||||
click_count(0)
|
||||
{}
|
||||
|
||||
MouseEvent(const osgGA::GUIEventAdapter& ea):
|
||||
button(ea.getButton()),
|
||||
state(ea.getButtonMask()),
|
||||
mod(ea.getModKeyMask()),
|
||||
click_count(0)
|
||||
{
|
||||
time = ea.getTime();
|
||||
}
|
||||
|
||||
osg::Vec2f getScreenPos() const { return screen_pos; }
|
||||
osg::Vec2f getClientPos() const { return client_pos; }
|
||||
osg::Vec2f getDelta() const { return delta; }
|
||||
|
||||
@@ -54,17 +54,17 @@ static void readOptionalBindingList(const SGPropertyNode* aNode, SGPropertyNode*
|
||||
}
|
||||
|
||||
|
||||
osg::Vec2d eventToWindowCoords(const osgGA::GUIEventAdapter* ea)
|
||||
osg::Vec2d eventToWindowCoords(const osgGA::GUIEventAdapter& ea)
|
||||
{
|
||||
using namespace osg;
|
||||
const GraphicsContext* gc = ea->getGraphicsContext();
|
||||
const GraphicsContext* gc = ea.getGraphicsContext();
|
||||
const GraphicsContext::Traits* traits = gc->getTraits() ;
|
||||
// Scale x, y to the dimensions of the window
|
||||
double x = (((ea->getX() - ea->getXmin()) / (ea->getXmax() - ea->getXmin()))
|
||||
double x = (((ea.getX() - ea.getXmin()) / (ea.getXmax() - ea.getXmin()))
|
||||
* (double)traits->width);
|
||||
double y = (((ea->getY() - ea->getYmin()) / (ea->getYmax() - ea->getYmin()))
|
||||
double y = (((ea.getY() - ea.getYmin()) / (ea.getYmax() - ea.getYmin()))
|
||||
* (double)traits->height);
|
||||
if (ea->getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS)
|
||||
if (ea.getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS)
|
||||
y = (double)traits->height - y;
|
||||
|
||||
return osg::Vec2d(x, y);
|
||||
@@ -100,7 +100,9 @@ osg::Vec2d eventToWindowCoords(const osgGA::GUIEventAdapter* ea)
|
||||
_hover = readBindingList(hoverNode->getChildren("binding"), modelRoot);
|
||||
}
|
||||
|
||||
virtual bool buttonPressed(int button, const osgGA::GUIEventAdapter* ea, const Info&)
|
||||
virtual bool buttonPressed( int button,
|
||||
const osgGA::GUIEventAdapter&,
|
||||
const Info& )
|
||||
{
|
||||
if (_buttons.find(button) == _buttons.end()) {
|
||||
return false;
|
||||
@@ -110,7 +112,9 @@ osg::Vec2d eventToWindowCoords(const osgGA::GUIEventAdapter* ea)
|
||||
_repeatTime = -_repeatInterval; // anti-bobble: delay start of repeat
|
||||
return true;
|
||||
}
|
||||
virtual void buttonReleased(int keyModState)
|
||||
virtual void buttonReleased( int keyModState,
|
||||
const osgGA::GUIEventAdapter&,
|
||||
const Info* )
|
||||
{
|
||||
SG_UNUSED(keyModState);
|
||||
fireBindingList(_bindingsUp);
|
||||
@@ -129,7 +133,8 @@ osg::Vec2d eventToWindowCoords(const osgGA::GUIEventAdapter* ea)
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool hover(const osg::Vec2d& windowPos, const Info& info)
|
||||
virtual bool hover( const osg::Vec2d& windowPos,
|
||||
const Info& )
|
||||
{
|
||||
if (_hover.empty()) {
|
||||
return false;
|
||||
@@ -256,7 +261,9 @@ public:
|
||||
_squaredDown = dot(_toDown, _toDown);
|
||||
}
|
||||
|
||||
virtual bool buttonPressed(int button, const osgGA::GUIEventAdapter* ea, const Info& info)
|
||||
virtual bool buttonPressed( int button,
|
||||
const osgGA::GUIEventAdapter&,
|
||||
const Info& info )
|
||||
{
|
||||
SGVec3d loc(info.local);
|
||||
SG_LOG(SG_INPUT, SG_DEBUG, "VNC pressed " << button << ": " << loc);
|
||||
@@ -270,7 +277,9 @@ public:
|
||||
return vv.wasSuccessful();
|
||||
|
||||
}
|
||||
virtual void buttonReleased(int keyModState)
|
||||
virtual void buttonReleased( int keyModState,
|
||||
const osgGA::GUIEventAdapter&,
|
||||
const Info* )
|
||||
{
|
||||
SG_UNUSED(keyModState);
|
||||
SG_LOG(SG_INPUT, SG_DEBUG, "VNC release");
|
||||
@@ -544,11 +553,13 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool buttonPressed(int button, const osgGA::GUIEventAdapter* ea, const Info&)
|
||||
virtual bool buttonPressed( int button,
|
||||
const osgGA::GUIEventAdapter& ea,
|
||||
const Info& )
|
||||
{
|
||||
// the 'be nice to Mac / laptop' users option; alt-clicking spins the
|
||||
// opposite direction. Should make this configurable
|
||||
if ((button == 0) && (ea->getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_ALT)) {
|
||||
if ((button == 0) && (ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_ALT)) {
|
||||
button = 1;
|
||||
}
|
||||
|
||||
@@ -571,7 +582,9 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void buttonReleased(int keyModState)
|
||||
virtual void buttonReleased( int keyModState,
|
||||
const osgGA::GUIEventAdapter&,
|
||||
const Info* )
|
||||
{
|
||||
// for *clicks*, we only fire on button release
|
||||
if (!_hasDragged) {
|
||||
@@ -592,7 +605,8 @@ public:
|
||||
return _dragDirection;
|
||||
}
|
||||
|
||||
virtual void mouseMoved(const osgGA::GUIEventAdapter* ea)
|
||||
virtual void mouseMoved( const osgGA::GUIEventAdapter& ea,
|
||||
const Info* )
|
||||
{
|
||||
_mousePos = eventToWindowCoords(ea);
|
||||
osg::Vec2d deltaMouse = _mousePos - _lastFirePos;
|
||||
@@ -618,7 +632,7 @@ public:
|
||||
if (fabs(delta) >= 1.0) {
|
||||
// determine direction from sign of delta
|
||||
Direction dir = (delta > 0.0) ? DIRECTION_INCREASE : DIRECTION_DECREASE;
|
||||
fire(ea->getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_SHIFT, dir);
|
||||
fire(ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_SHIFT, dir);
|
||||
_lastFirePos = _mousePos;
|
||||
}
|
||||
}
|
||||
@@ -636,7 +650,8 @@ public:
|
||||
} // of repeat iteration
|
||||
}
|
||||
|
||||
virtual bool hover(const osg::Vec2d& windowPos, const Info& info)
|
||||
virtual bool hover( const osg::Vec2d& windowPos,
|
||||
const Info& )
|
||||
{
|
||||
if (_hover.empty()) {
|
||||
return false;
|
||||
|
||||
@@ -52,19 +52,41 @@ public:
|
||||
{ }
|
||||
|
||||
virtual ~SGPickCallback() {}
|
||||
virtual bool buttonPressed(int button, const osgGA::GUIEventAdapter* event, const Info& info)
|
||||
|
||||
// TODO maybe better provide a single callback to handle all events
|
||||
virtual bool buttonPressed( int button,
|
||||
const osgGA::GUIEventAdapter& ea,
|
||||
const Info& info )
|
||||
{ return false; }
|
||||
|
||||
virtual void update(double dt, int keyModState)
|
||||
{ }
|
||||
|
||||
virtual void buttonReleased(int keyModState)
|
||||
|
||||
/**
|
||||
* @param info Can be null if no info is available (eg. mouse not over 3d
|
||||
* object anymore)
|
||||
*/
|
||||
virtual void buttonReleased( int keyModState,
|
||||
const osgGA::GUIEventAdapter& ea,
|
||||
const Info* info )
|
||||
{ }
|
||||
|
||||
virtual void mouseMoved(const osgGA::GUIEventAdapter* event)
|
||||
/**
|
||||
* @param info Can be null if no info is available (eg. mouse not over 3d
|
||||
* object anymore)
|
||||
*/
|
||||
virtual void mouseMoved( const osgGA::GUIEventAdapter& ea,
|
||||
const Info* info )
|
||||
{ }
|
||||
|
||||
virtual bool hover(const osg::Vec2d& windowPos, const Info& info)
|
||||
/**
|
||||
* The mouse is not hovering anymore over the element.
|
||||
*/
|
||||
virtual void mouseLeave(const osg::Vec2d& windowPos)
|
||||
{ }
|
||||
|
||||
virtual bool hover( const osg::Vec2d& windowPos,
|
||||
const Info& info )
|
||||
{ return false; }
|
||||
|
||||
virtual Priority getPriority() const
|
||||
|
||||
Reference in New Issue
Block a user