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:
Robert Osfield 2014-06-11 10:55:33 +00:00
parent 89ca694684
commit 86a9a45525
5 changed files with 192 additions and 22 deletions

View File

@ -38,6 +38,8 @@ public:
virtual bool handle(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 void dirty();

View File

@ -17,6 +17,7 @@
#include <osgText/Font>
#include <osgText/Text>
#include <osg/Notify>
#include <osg/ValueObject>
#include <osg/io_utils>
using namespace osgUI;
@ -53,6 +54,7 @@ bool ComboBox::handleImplementation(osgGA::EventVisitor* ev, osgGA::Event* event
return true;
}
break;
case(osgGA::GUIEventAdapter::KEYDOWN):
if (ea->getKey()==osgGA::GUIEventAdapter::KEY_Down)
{
@ -66,14 +68,70 @@ bool ComboBox::handleImplementation(osgGA::EventVisitor* ev, osgGA::Event* event
}
break;
case(osgGA::GUIEventAdapter::PUSH):
{
OSG_NOTICE<<"Button pressed "<<std::endl;
// 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;
}
case(osgGA::GUIEventAdapter::RELEASE):
OSG_NOTICE<<"Button release "<<std::endl;
break;
default:
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());
unsigned int index = 0;
for(Items::iterator itr = _items.begin();
itr != _items.end();
++itr)
++itr, ++index)
{
Item* item = itr->get();
OSG_NOTICE<<"Creating item "<<item->getText()<<", "<<item->getColor()<<std::endl;
@ -139,6 +198,8 @@ void ComboBox::createGraphicsImplementation()
// setup graphics for popup
{
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->getText().empty()) group->addChild( style->createText(popupItemExtents, getAlignmentSettings(), getTextSettings(), item->getText()) );
_popup->addChild(group.get());

View File

@ -32,7 +32,7 @@ Popup::Popup(const osgUI::Popup& dialog, const osg::CopyOp& copyop):
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();
if (!ea) return false;
@ -70,7 +70,7 @@ void Popup::createGraphicsImplementation()
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) );

View File

@ -61,6 +61,7 @@ osg::Node* Style::createPanel(const osg::BoundingBox& extents, const osg::Vec4&
{
OSG_NOTICE<<"Creating Panel"<<std::endl;
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
geometry->setName("Panel");
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
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::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
geometry->setName("DepthSetPanel");
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
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::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
geometry->setName("Frame");
float topScale = 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::ref_ptr<osgText::Text> textDrawable = new osgText::Text;
textDrawable->setName("Text");
textDrawable->setText(text);
textDrawable->setPosition( osg::Vec3(extents.xMin(), extents.yMin(), extents.zMin()) );

View File

@ -23,6 +23,8 @@
#include <osgGA/EventVisitor>
#include <osgGA/GUIActionAdapter>
#include <algorithm>
using namespace osgUI;
Widget::Widget():
@ -271,22 +273,6 @@ bool Widget::handleImplementation(osgGA::EventVisitor* ev, osgGA::Event* event)
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()
{
_graphicsInitialized = false;
@ -304,8 +290,10 @@ void Widget::createGraphicsImplementation()
osg::BoundingSphere Widget::computeBound() const
{
if (_extents.valid()) return osg::BoundingSphere(_extents);
else return osg::Group::computeBound();
osg::BoundingSphere bs;
if (_extents.valid()) bs.expandBy(_extents);
bs.expandBy(Group::computeBound());
return bs;
}
void Widget::resizeGLObjectBuffers(unsigned int maxSize)
@ -331,4 +319,119 @@ void Widget::releaseGLObjects(osg::State* state) const
}
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;
}