/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2014 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include using namespace osgUI; Widget::Widget(): _focusBehaviour(FOCUS_FOLLOWS_POINTER), _hasEventFocus(false), _graphicsInitialized(false), _autoFillBackground(false), _visible(true), _enabled(true) { setNumChildrenRequiringEventTraversal(1); } Widget::Widget(const Widget& widget, const osg::CopyOp& copyop): osg::Group(), _focusBehaviour(widget._focusBehaviour), _hasEventFocus(false), _graphicsInitialized(false), _alignmentSettings(osg::clone(widget._alignmentSettings.get(), copyop)), _frameSettings(osg::clone(widget._frameSettings.get(), copyop)), _textSettings(osg::clone(widget._textSettings.get(), copyop)), _autoFillBackground(widget._autoFillBackground), _visible(widget._visible), _enabled(widget._enabled) { setNumChildrenRequiringEventTraversal(1); } void Widget::setExtents(const osg::BoundingBoxf& bb) { _extents = bb; } void Widget::updateFocus(osg::NodeVisitor& nv) { osgGA::EventVisitor* ev = dynamic_cast(&nv); osgGA::GUIActionAdapter* aa = ev ? ev->getActionAdapter() : 0; if (ev && aa) { // OSG_NOTICE<<"updateFocus"<getEvents(); for(osgGA::EventQueue::Events::iterator itr = events.begin(); itr != events.end(); ++itr) { osgGA::GUIEventAdapter* ea = (*itr)->asGUIEventAdapter(); if (ea) { int numButtonsPressed = 0; if (ea->getEventType()==osgGA::GUIEventAdapter::PUSH) { if (ea->getButtonMask()&osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON) ++numButtonsPressed; if (ea->getButtonMask()&osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON) ++numButtonsPressed; if (ea->getButtonMask()&osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON) ++numButtonsPressed; } bool previousFocus = _hasEventFocus; if (_focusBehaviour==CLICK_TO_FOCUS) { if (ea->getEventType()==osgGA::GUIEventAdapter::PUSH) { if (numButtonsPressed==1) { osg::Vec3d intersection; bool withinWidget = computeExtentsPositionInLocalCoordinates(ev, ea, intersection); if (withinWidget) _hasEventFocus = true; else _hasEventFocus = false; } } } else if (_focusBehaviour==FOCUS_FOLLOWS_POINTER) { bool checkWithinWidget = false; if (!_hasEventFocus) { checkWithinWidget = (ea->getEventType()!=osgGA::GUIEventAdapter::FRAME) && ea->getButtonMask()==0; } else { // if mouse move or mouse release check to see if mouse still within widget to retain focus if (ea->getEventType()==osgGA::GUIEventAdapter::MOVE) { checkWithinWidget = true; } else if (ea->getEventType()==osgGA::GUIEventAdapter::RELEASE) { // if no buttons pressed then check if (ea->getButtonMask()==0) checkWithinWidget = true; } } if (checkWithinWidget) { osg::Vec3d intersection; bool withinWidget = computeExtentsPositionInLocalCoordinates(ev, ea, intersection); _hasEventFocus = withinWidget; } } if (_hasEventFocus && (ea->getEventType()==osgGA::GUIEventAdapter::PUSH || ea->getEventType()==osgGA::GUIEventAdapter::SCROLL) ) { osgViewer::View* view = dynamic_cast(aa); if (view && view->getCameraManipulator()) { view->getCameraManipulator()->finishAnimation(); view->requestContinuousUpdate( false ); } } if (previousFocus != _hasEventFocus) { if (_hasEventFocus) { enter(); } else { leave(); } } } } } } void Widget::setHasEventFocus(bool focus) { if (_hasEventFocus == focus) return; _hasEventFocus = focus; if (_hasEventFocus) enter(); else leave(); } bool Widget::getHasEventFocus() const { return _hasEventFocus; } void Widget::enter() { if (!runCallbacks("enter")) enterImplementation(); } void Widget::enterImplementation() { OSG_NOTICE<<"Widget::enter()"<(&nv); if (ev) { if (_visible && _enabled) { updateFocus(nv); // OSG_NOTICE<<"EventTraversal getHasEventFocus()="<getEvents(); for(osgGA::EventQueue::Events::iterator itr = events.begin(); itr != events.end(); ++itr) { if (handle(ev, itr->get()) || widgetsWithFocusSetHandled) { (*itr)->setHandled(true); ev->setEventHandled(true); } } GraphicsSubgraphMap::iterator itr = _graphicsSubgraphMap.begin(); while(itr!= _graphicsSubgraphMap.end() && itr->first<=0) { itr->second->accept(nv); ++itr; } osg::Group::traverse(nv); while(itr!= _graphicsSubgraphMap.end()) { itr->second->accept(nv); ++itr; } } } else if (_visible || (nv.getVisitorType()!=osg::NodeVisitor::UPDATE_VISITOR && nv.getVisitorType()!=osg::NodeVisitor::CULL_VISITOR && nv.getVisitorType()!=osg::NodeVisitor::INTERSECTION_VISITOR) ) { osgUtil::CullVisitor* cv = (nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR) ? dynamic_cast(&nv) : 0; if (cv && _widgetStateSet.valid()) cv->pushStateSet(_widgetStateSet.get()); GraphicsSubgraphMap::iterator itr = _graphicsSubgraphMap.begin(); while(itr!= _graphicsSubgraphMap.end() && itr->first<=0) { itr->second->accept(nv); ++itr; } Group::traverse(nv); while(itr!= _graphicsSubgraphMap.end()) { itr->second->accept(nv); ++itr; } if (cv && _widgetStateSet.valid()) cv->popStateSet(); } } bool Widget::handle(osgGA::EventVisitor* ev, osgGA::Event* event) { // currently lua scripting takes a ref count so messes up handling of NodeVisitor's created on stack, // so don't attempt to call the sctipt. if (ev->referenceCount()!=0) { osg::Parameters inputParameters, outputParameters; inputParameters.push_back(ev); inputParameters.push_back(event); if (runCallbacks("handle",inputParameters, outputParameters)) { if (outputParameters.size()>=1) { osg::BoolValueObject* bvo = dynamic_cast(outputParameters[0].get()); return bvo ? bvo->getValue() : false; } } } return handleImplementation(ev, event); } bool Widget::handleImplementation(osgGA::EventVisitor* ev, osgGA::Event* event) { return false; } void Widget::dirty() { _graphicsInitialized = false; } void Widget::createGraphics() { if (!runCallbacks("createGraphics")) createGraphicsImplementation(); } void Widget::createGraphicsImplementation() { _graphicsInitialized = true; } osg::BoundingSphere Widget::computeBound() const { osg::BoundingSphere bs; if (_extents.valid()) bs.expandBy(_extents); bs.expandBy(Group::computeBound()); return bs; } void Widget::resizeGLObjectBuffers(unsigned int maxSize) { for(GraphicsSubgraphMap::iterator itr = _graphicsSubgraphMap.begin(); itr != _graphicsSubgraphMap.end(); ++itr) { itr->second->resizeGLObjectBuffers(maxSize); } Group::resizeGLObjectBuffers(maxSize); } void Widget::releaseGLObjects(osg::State* state) const { for(GraphicsSubgraphMap::const_iterator itr = _graphicsSubgraphMap.begin(); itr != _graphicsSubgraphMap.end(); ++itr) { itr->second->releaseGLObjects(state); } Group::releaseGLObjects(state); } bool Widget::computePositionInLocalCoordinates(osgGA::EventVisitor* ev, osgGA::GUIEventAdapter* event, osg::Vec3d& 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"<(parent); unsigned int lhs_index = parent->getChildIndex(*itr_lhs); double lhs_sort_value = static_cast(lhs_index)/static_cast(parent->getNumChildren()); unsigned int rhs_index = parent->getChildIndex(*itr_rhs); double rhs_sort_value = (static_cast(rhs_index)+epsilon)/static_cast(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_valuegetActionAdapter() : 0; osgUtil::LineSegmentIntersector::Intersections source_intersections; if (aa && aa->computeIntersections(*event, ev->getNodePath(), source_intersections, traversalMask)) { typedef std::vector 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; } bool Widget::computeExtentsPositionInLocalCoordinates(osgGA::EventVisitor* ev, osgGA::GUIEventAdapter* event, osg::Vec3d& localPosition, bool withinExtents) const { //OSG_NOTICE<<"Widget::computeExtentsPositionInLocalCoordinates(()"<getNumPointerData()>=1) { const osgGA::PointerData* pd = event->getPointerData(event->getNumPointerData()-1); camera = dynamic_cast(pd->object.get()); if (camera) { x = pd->getXnormalized(); y = pd->getYnormalized(); } } //OSG_NOTICE<<" camera = "<0.0) return false; double r = ds/(ds-de); //OSG_NOTICE<<" r = "<