Implemented more robust intersection handling for mouse interactions. Wired up even handling of ComboBox popup.
git-svn-id: http://svn.openscenegraph.org/osg/OpenSceneGraph/trunk@14250 16af8721-9629-0410-8352-f15c8da7e697
This commit is contained in:
parent
89ca694684
commit
86a9a45525
@ -38,6 +38,8 @@ public:
|
|||||||
virtual bool handle(osgGA::EventVisitor* ev, osgGA::Event* event);
|
virtual bool handle(osgGA::EventVisitor* ev, osgGA::Event* event);
|
||||||
virtual bool handleImplementation(osgGA::EventVisitor* ev, osgGA::Event* event);
|
virtual bool handleImplementation(osgGA::EventVisitor* ev, osgGA::Event* event);
|
||||||
|
|
||||||
|
typedef std::vector<osgUtil::LineSegmentIntersector::Intersection> Intersections;
|
||||||
|
virtual bool computeIntersections(osgGA::EventVisitor* ev, osgGA::GUIEventAdapter* event, Intersections& intersections, osg::Node::NodeMask traversalMask = 0xffffffff) const;
|
||||||
virtual bool computePositionInLocalCoordinates(osgGA::EventVisitor* ev, osgGA::GUIEventAdapter* event, osg::Vec3& localPosition) const;
|
virtual bool computePositionInLocalCoordinates(osgGA::EventVisitor* ev, osgGA::GUIEventAdapter* event, osg::Vec3& localPosition) const;
|
||||||
|
|
||||||
virtual void dirty();
|
virtual void dirty();
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <osgText/Font>
|
#include <osgText/Font>
|
||||||
#include <osgText/Text>
|
#include <osgText/Text>
|
||||||
#include <osg/Notify>
|
#include <osg/Notify>
|
||||||
|
#include <osg/ValueObject>
|
||||||
#include <osg/io_utils>
|
#include <osg/io_utils>
|
||||||
|
|
||||||
using namespace osgUI;
|
using namespace osgUI;
|
||||||
@ -53,6 +54,7 @@ bool ComboBox::handleImplementation(osgGA::EventVisitor* ev, osgGA::Event* event
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case(osgGA::GUIEventAdapter::KEYDOWN):
|
case(osgGA::GUIEventAdapter::KEYDOWN):
|
||||||
if (ea->getKey()==osgGA::GUIEventAdapter::KEY_Down)
|
if (ea->getKey()==osgGA::GUIEventAdapter::KEY_Down)
|
||||||
{
|
{
|
||||||
@ -66,14 +68,70 @@ bool ComboBox::handleImplementation(osgGA::EventVisitor* ev, osgGA::Event* event
|
|||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case(osgGA::GUIEventAdapter::PUSH):
|
case(osgGA::GUIEventAdapter::PUSH):
|
||||||
|
{
|
||||||
OSG_NOTICE<<"Button pressed "<<std::endl;
|
OSG_NOTICE<<"Button pressed "<<std::endl;
|
||||||
// toggle visibility of popup.
|
// toggle visibility of popup.
|
||||||
if (_popup) _popup->setVisible(!_popup->getVisible());
|
osgUI::Widget::Intersections intersections;
|
||||||
|
osgGA::GUIActionAdapter* aa = ev ? ev->getActionAdapter() : 0;
|
||||||
|
osgGA::GUIEventAdapter* ea = event ? event->asGUIEventAdapter() : 0;
|
||||||
|
// if ((aa && ea) && aa->computeIntersections(*ea, ev->getNodePath(), intersections))
|
||||||
|
if ((aa && ea) && computeIntersections(ev, ea, intersections))
|
||||||
|
{
|
||||||
|
OSG_NOTICE<<"ComboBox intersections { "<<std::endl;
|
||||||
|
for(osgUI::Widget::Intersections::const_iterator itr =intersections.begin();
|
||||||
|
itr!=intersections.end();
|
||||||
|
++itr)
|
||||||
|
{
|
||||||
|
const osgUtil::LineSegmentIntersector::Intersection& hit = *itr;
|
||||||
|
OSG_NOTICE<<" hit:drawable "<<hit.drawable.get()<<", "<<hit.drawable->getName()<<std::endl;
|
||||||
|
OSG_NOTICE<<" NodePath::size() "<<hit.nodePath.size()<<std::endl;
|
||||||
|
}
|
||||||
|
OSG_NOTICE<<"}"<<std::endl;
|
||||||
|
|
||||||
|
const osgUtil::LineSegmentIntersector::Intersection& hit = *intersections.begin();
|
||||||
|
osg::Vec3d localPosition = hit.getLocalIntersectPoint();
|
||||||
|
if (_extents.contains(localPosition, 1e-6))
|
||||||
|
{
|
||||||
|
OSG_NOTICE<<"ComboBox button"<<std::endl;
|
||||||
|
_popup->setVisible(!_popup->getVisible());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_popup->getVisible() && _popup->getExtents().contains(localPosition, 1e-6))
|
||||||
|
{
|
||||||
|
OSG_NOTICE<<"In pop up"<<std::endl;
|
||||||
|
OSG_NOTICE<<" hit:drawable "<<hit.drawable.get()<<std::endl;
|
||||||
|
OSG_NOTICE<<" NodePath::size() "<<hit.nodePath.size()<<std::endl;
|
||||||
|
|
||||||
|
unsigned int index=_items.size();
|
||||||
|
for(osg::NodePath::const_reverse_iterator itr = hit.nodePath.rbegin();
|
||||||
|
itr != hit.nodePath.rend();
|
||||||
|
++itr)
|
||||||
|
{
|
||||||
|
if ((*itr)==this) break;
|
||||||
|
if ((*itr)->getUserValue("index",index)) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index<_items.size())
|
||||||
|
{
|
||||||
|
OSG_NOTICE<<" index selected "<<index<<std::endl;
|
||||||
|
setCurrentItem(index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OSG_NOTICE<<" No index selected "<<std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
_popup->setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case(osgGA::GUIEventAdapter::RELEASE):
|
case(osgGA::GUIEventAdapter::RELEASE):
|
||||||
OSG_NOTICE<<"Button release "<<std::endl;
|
OSG_NOTICE<<"Button release "<<std::endl;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -121,9 +179,10 @@ void ComboBox::createGraphicsImplementation()
|
|||||||
|
|
||||||
osg::BoundingBox popupItemExtents(_extents.xMin()+margin, popupTop-margin-itemHeight, _extents.zMin(), _extents.xMin()+itemWidth, popupTop-margin, _extents.zMax());
|
osg::BoundingBox popupItemExtents(_extents.xMin()+margin, popupTop-margin-itemHeight, _extents.zMin(), _extents.xMin()+itemWidth, popupTop-margin, _extents.zMax());
|
||||||
|
|
||||||
|
unsigned int index = 0;
|
||||||
for(Items::iterator itr = _items.begin();
|
for(Items::iterator itr = _items.begin();
|
||||||
itr != _items.end();
|
itr != _items.end();
|
||||||
++itr)
|
++itr, ++index)
|
||||||
{
|
{
|
||||||
Item* item = itr->get();
|
Item* item = itr->get();
|
||||||
OSG_NOTICE<<"Creating item "<<item->getText()<<", "<<item->getColor()<<std::endl;
|
OSG_NOTICE<<"Creating item "<<item->getText()<<", "<<item->getColor()<<std::endl;
|
||||||
@ -139,6 +198,8 @@ void ComboBox::createGraphicsImplementation()
|
|||||||
// setup graphics for popup
|
// setup graphics for popup
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::Group> group = new osg::Group;
|
osg::ref_ptr<osg::Group> group = new osg::Group;
|
||||||
|
group->setUserValue("index",index);
|
||||||
|
|
||||||
if (item->getColor().a()!=0.0f) group->addChild( style->createPanel(popupItemExtents, item->getColor()) );
|
if (item->getColor().a()!=0.0f) group->addChild( style->createPanel(popupItemExtents, item->getColor()) );
|
||||||
if (!item->getText().empty()) group->addChild( style->createText(popupItemExtents, getAlignmentSettings(), getTextSettings(), item->getText()) );
|
if (!item->getText().empty()) group->addChild( style->createText(popupItemExtents, getAlignmentSettings(), getTextSettings(), item->getText()) );
|
||||||
_popup->addChild(group.get());
|
_popup->addChild(group.get());
|
||||||
|
@ -32,7 +32,7 @@ Popup::Popup(const osgUI::Popup& dialog, const osg::CopyOp& copyop):
|
|||||||
|
|
||||||
bool Popup::handleImplementation(osgGA::EventVisitor* ev, osgGA::Event* event)
|
bool Popup::handleImplementation(osgGA::EventVisitor* ev, osgGA::Event* event)
|
||||||
{
|
{
|
||||||
OSG_NOTICE<<"Popup::handleImplementation"<<std::endl;
|
// OSG_NOTICE<<"Popup::handleImplementation"<<std::endl;
|
||||||
|
|
||||||
osgGA::GUIEventAdapter* ea = event->asGUIEventAdapter();
|
osgGA::GUIEventAdapter* ea = event->asGUIEventAdapter();
|
||||||
if (!ea) return false;
|
if (!ea) return false;
|
||||||
@ -70,7 +70,7 @@ void Popup::createGraphicsImplementation()
|
|||||||
|
|
||||||
Style* style = (getStyle()!=0) ? getStyle() : Style::instance().get();
|
Style* style = (getStyle()!=0) ? getStyle() : Style::instance().get();
|
||||||
|
|
||||||
osg::Vec4 dialogBackgroundColor(0.8,0.8,0.8,1.0);
|
osg::Vec4 dialogBackgroundColor(0.9,0.9,0.9,1.0);
|
||||||
|
|
||||||
_transform->addChild( style->createPanel(_extents, dialogBackgroundColor) );
|
_transform->addChild( style->createPanel(_extents, dialogBackgroundColor) );
|
||||||
|
|
||||||
|
@ -61,6 +61,7 @@ osg::Node* Style::createPanel(const osg::BoundingBox& extents, const osg::Vec4&
|
|||||||
{
|
{
|
||||||
OSG_NOTICE<<"Creating Panel"<<std::endl;
|
OSG_NOTICE<<"Creating Panel"<<std::endl;
|
||||||
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
|
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
|
||||||
|
geometry->setName("Panel");
|
||||||
|
|
||||||
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
|
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
|
||||||
geometry->setVertexArray(vertices.get());
|
geometry->setVertexArray(vertices.get());
|
||||||
@ -83,6 +84,7 @@ osg::Node* Style::createPanel(const osg::BoundingBox& extents, const osg::Vec4&
|
|||||||
osg::Node* Style::createDepthSetPanel(const osg::BoundingBox& extents)
|
osg::Node* Style::createDepthSetPanel(const osg::BoundingBox& extents)
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
|
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
|
||||||
|
geometry->setName("DepthSetPanel");
|
||||||
|
|
||||||
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
|
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
|
||||||
geometry->setVertexArray(vertices.get());
|
geometry->setVertexArray(vertices.get());
|
||||||
@ -104,6 +106,7 @@ osg::Node* Style::createDepthSetPanel(const osg::BoundingBox& extents)
|
|||||||
osg::Node* Style::createFrame(const osg::BoundingBox& extents, const FrameSettings* frameSettings, const osg::Vec4& color)
|
osg::Node* Style::createFrame(const osg::BoundingBox& extents, const FrameSettings* frameSettings, const osg::Vec4& color)
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
|
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
|
||||||
|
geometry->setName("Frame");
|
||||||
|
|
||||||
float topScale = 1.0f;
|
float topScale = 1.0f;
|
||||||
float bottomScale = 1.0f;
|
float bottomScale = 1.0f;
|
||||||
@ -219,6 +222,7 @@ osg::Node* Style::createFrame(const osg::BoundingBox& extents, const FrameSettin
|
|||||||
osg::Node* Style::createText(const osg::BoundingBox& extents, const AlignmentSettings* as, const TextSettings* ts, const std::string& text)
|
osg::Node* Style::createText(const osg::BoundingBox& extents, const AlignmentSettings* as, const TextSettings* ts, const std::string& text)
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osgText::Text> textDrawable = new osgText::Text;
|
osg::ref_ptr<osgText::Text> textDrawable = new osgText::Text;
|
||||||
|
textDrawable->setName("Text");
|
||||||
|
|
||||||
textDrawable->setText(text);
|
textDrawable->setText(text);
|
||||||
textDrawable->setPosition( osg::Vec3(extents.xMin(), extents.yMin(), extents.zMin()) );
|
textDrawable->setPosition( osg::Vec3(extents.xMin(), extents.yMin(), extents.zMin()) );
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
#include <osgGA/EventVisitor>
|
#include <osgGA/EventVisitor>
|
||||||
#include <osgGA/GUIActionAdapter>
|
#include <osgGA/GUIActionAdapter>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
using namespace osgUI;
|
using namespace osgUI;
|
||||||
|
|
||||||
Widget::Widget():
|
Widget::Widget():
|
||||||
@ -271,22 +273,6 @@ bool Widget::handleImplementation(osgGA::EventVisitor* ev, osgGA::Event* event)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Widget::computePositionInLocalCoordinates(osgGA::EventVisitor* ev, osgGA::GUIEventAdapter* event, osg::Vec3& localPosition) const
|
|
||||||
{
|
|
||||||
osgGA::GUIActionAdapter* aa = ev ? ev->getActionAdapter() : 0;
|
|
||||||
osgUtil::LineSegmentIntersector::Intersections intersections;
|
|
||||||
if (aa && aa->computeIntersections(*event, ev->getNodePath(), intersections))
|
|
||||||
{
|
|
||||||
localPosition = intersections.begin()->getLocalIntersectPoint();
|
|
||||||
|
|
||||||
return (_extents.contains(localPosition, 1e-6));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Widget::dirty()
|
void Widget::dirty()
|
||||||
{
|
{
|
||||||
_graphicsInitialized = false;
|
_graphicsInitialized = false;
|
||||||
@ -304,8 +290,10 @@ void Widget::createGraphicsImplementation()
|
|||||||
|
|
||||||
osg::BoundingSphere Widget::computeBound() const
|
osg::BoundingSphere Widget::computeBound() const
|
||||||
{
|
{
|
||||||
if (_extents.valid()) return osg::BoundingSphere(_extents);
|
osg::BoundingSphere bs;
|
||||||
else return osg::Group::computeBound();
|
if (_extents.valid()) bs.expandBy(_extents);
|
||||||
|
bs.expandBy(Group::computeBound());
|
||||||
|
return bs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::resizeGLObjectBuffers(unsigned int maxSize)
|
void Widget::resizeGLObjectBuffers(unsigned int maxSize)
|
||||||
@ -331,4 +319,119 @@ void Widget::releaseGLObjects(osg::State* state) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
Group::releaseGLObjects(state);
|
Group::releaseGLObjects(state);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Widget::computePositionInLocalCoordinates(osgGA::EventVisitor* ev, osgGA::GUIEventAdapter* event, osg::Vec3& localPosition) const
|
||||||
|
{
|
||||||
|
osgGA::GUIActionAdapter* aa = ev ? ev->getActionAdapter() : 0;
|
||||||
|
osgUtil::LineSegmentIntersector::Intersections intersections;
|
||||||
|
if (aa && aa->computeIntersections(*event, ev->getNodePath(), intersections))
|
||||||
|
{
|
||||||
|
localPosition = intersections.begin()->getLocalIntersectPoint();
|
||||||
|
|
||||||
|
return (_extents.contains(localPosition, 1e-6));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SortTraversalOrder
|
||||||
|
{
|
||||||
|
bool operator() (const osgUtil::LineSegmentIntersector::Intersection* lhs, const osgUtil::LineSegmentIntersector::Intersection* rhs) const
|
||||||
|
{
|
||||||
|
double epsilon = 1e-6;
|
||||||
|
if (lhs->ratio > (rhs->ratio+epsilon)) return true;
|
||||||
|
if (lhs->ratio < (rhs->ratio-epsilon)) return false;
|
||||||
|
|
||||||
|
const osg::NodePath& np_lhs = lhs->nodePath;
|
||||||
|
const osg::NodePath& np_rhs = rhs->nodePath;
|
||||||
|
|
||||||
|
osg::NodePath::const_iterator itr_lhs = np_lhs.begin();
|
||||||
|
osg::NodePath::const_iterator end_lhs = np_lhs.end();
|
||||||
|
osg::NodePath::const_iterator itr_rhs = np_rhs.begin();
|
||||||
|
osg::NodePath::const_iterator end_rhs = np_rhs.end();
|
||||||
|
const osg::Group* parent = 0;
|
||||||
|
|
||||||
|
while(itr_lhs!=end_lhs && itr_rhs!=end_rhs)
|
||||||
|
{
|
||||||
|
if (*itr_lhs == *itr_rhs)
|
||||||
|
{
|
||||||
|
parent = (*itr_lhs)->asGroup();
|
||||||
|
++itr_lhs;
|
||||||
|
++itr_rhs;
|
||||||
|
}
|
||||||
|
else if (parent==0)
|
||||||
|
{
|
||||||
|
OSG_NOTICE<<"SortTraversalOrder::operator() NodePath has no parent, just have to use default less than operator for Intersection"<<std::endl;
|
||||||
|
return (*lhs)<(*rhs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const osgUI::Widget* widget = dynamic_cast<const osgUI::Widget*>(parent);
|
||||||
|
|
||||||
|
unsigned int lhs_index = parent->getChildIndex(*itr_lhs);
|
||||||
|
double lhs_sort_value = static_cast<double>(lhs_index)/static_cast<double>(parent->getNumChildren());
|
||||||
|
|
||||||
|
unsigned int rhs_index = parent->getChildIndex(*itr_rhs);
|
||||||
|
double rhs_sort_value = (static_cast<double>(rhs_index)+epsilon)/static_cast<double>(parent->getNumChildren());
|
||||||
|
|
||||||
|
if (widget)
|
||||||
|
{
|
||||||
|
const osgUI::Widget::GraphicsSubgraphMap& gsm = widget->getGraphicsSubgraphMap();
|
||||||
|
for(osgUI::Widget::GraphicsSubgraphMap::const_iterator itr=gsm.begin();
|
||||||
|
itr!=gsm.end();
|
||||||
|
++itr)
|
||||||
|
{
|
||||||
|
if (itr->second==(*itr_lhs)) lhs_sort_value = itr->first;
|
||||||
|
if (itr->second==(*itr_rhs)) rhs_sort_value = itr->first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lhs_sort_value>rhs_sort_value) return true;
|
||||||
|
if (lhs_sort_value<rhs_sort_value) return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool Widget::computeIntersections(osgGA::EventVisitor* ev, osgGA::GUIEventAdapter* event, Intersections& intersections, osg::Node::NodeMask traversalMask) const
|
||||||
|
{
|
||||||
|
osgGA::GUIActionAdapter* aa = ev ? ev->getActionAdapter() : 0;
|
||||||
|
osgUtil::LineSegmentIntersector::Intersections source_intersections;
|
||||||
|
if (aa && aa->computeIntersections(*event, ev->getNodePath(), source_intersections, traversalMask))
|
||||||
|
{
|
||||||
|
typedef std::vector<const osgUtil::LineSegmentIntersector::Intersection*> IntersectionPointerList;
|
||||||
|
IntersectionPointerList intersectionsToSort;
|
||||||
|
|
||||||
|
// populate the temporay vector of poiners to the original intersection pointers.
|
||||||
|
for(osgUtil::LineSegmentIntersector::Intersections::iterator itr = source_intersections.begin();
|
||||||
|
itr != source_intersections.end();
|
||||||
|
++itr)
|
||||||
|
{
|
||||||
|
if (itr->drawable->getName()!="DepthSetPanel")
|
||||||
|
{
|
||||||
|
intersectionsToSort.push_back(&(*itr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort the pointer list into order based on child traversal order, to be consistent with osgUI rendering order.
|
||||||
|
std::sort(intersectionsToSort.begin(), intersectionsToSort.end(), SortTraversalOrder());
|
||||||
|
|
||||||
|
// copy the pointers to final Intersection container
|
||||||
|
for(IntersectionPointerList::iterator itr = intersectionsToSort.begin();
|
||||||
|
itr != intersectionsToSort.end();
|
||||||
|
++itr)
|
||||||
|
{
|
||||||
|
intersections.push_back(*(*itr));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user