1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2014 Robert Osfield
2  *
3  * This library is open source and may be redistributed and/or modified under
4  * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5  * (at your option) any later version.  The full license is in LICENSE file
6  * included with this distribution, and on the openscenegraph.org website.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * OpenSceneGraph Public License for more details.
12 */
13 
14 
15 #include <osg/Geode>
16 #include <osg/ScriptEngine>
17 #include <osg/Geometry>
18 #include <osg/MatrixTransform>
19 #include <osg/ValueObject>
20 #include <osg/io_utils>
21 
22 #include <osgUI/Widget>
23 #include <osgGA/EventVisitor>
24 #include <osgGA/GUIActionAdapter>
25 #include <osgViewer/View>
26 
27 #include <algorithm>
28 
29 using namespace osgUI;
30 
Widget()31 Widget::Widget():
32     _focusBehaviour(FOCUS_FOLLOWS_POINTER),
33     _hasEventFocus(false),
34     _graphicsInitialized(false),
35     _autoFillBackground(false),
36     _visible(true),
37     _enabled(true)
38 {
39     setNumChildrenRequiringEventTraversal(1);
40 }
41 
Widget(const Widget & widget,const osg::CopyOp & copyop)42 Widget::Widget(const Widget& widget, const osg::CopyOp& copyop):
43     osg::Group(),
44     _focusBehaviour(widget._focusBehaviour),
45     _hasEventFocus(false),
46     _graphicsInitialized(false),
47     _alignmentSettings(osg::clone(widget._alignmentSettings.get(), copyop)),
48     _frameSettings(osg::clone(widget._frameSettings.get(), copyop)),
49     _textSettings(osg::clone(widget._textSettings.get(), copyop)),
50     _autoFillBackground(widget._autoFillBackground),
51     _visible(widget._visible),
52     _enabled(widget._enabled)
53 {
54     setNumChildrenRequiringEventTraversal(1);
55 }
56 
setExtents(const osg::BoundingBoxf & bb)57 void Widget::setExtents(const osg::BoundingBoxf& bb)
58 {
59     _extents = bb;
60 }
61 
updateFocus(osg::NodeVisitor & nv)62 void Widget::updateFocus(osg::NodeVisitor& nv)
63 {
64     osgGA::EventVisitor* ev = dynamic_cast<osgGA::EventVisitor*>(&nv);
65     osgGA::GUIActionAdapter* aa = ev ? ev->getActionAdapter() : 0;
66     if (ev && aa)
67     {
68         // OSG_NOTICE<<"updateFocus"<<std::endl;
69 
70         osgGA::EventQueue::Events& events = ev->getEvents();
71         for(osgGA::EventQueue::Events::iterator itr = events.begin();
72             itr != events.end();
73             ++itr)
74         {
75             osgGA::GUIEventAdapter* ea = (*itr)->asGUIEventAdapter();
76             if (ea)
77             {
78                 int numButtonsPressed = 0;
79                 if (ea->getEventType()==osgGA::GUIEventAdapter::PUSH)
80                 {
81                     if (ea->getButtonMask()&osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON) ++numButtonsPressed;
82                     if (ea->getButtonMask()&osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON) ++numButtonsPressed;
83                     if (ea->getButtonMask()&osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON) ++numButtonsPressed;
84                 }
85 
86                 bool previousFocus = _hasEventFocus;
87                 if (_focusBehaviour==CLICK_TO_FOCUS)
88                 {
89                     if (ea->getEventType()==osgGA::GUIEventAdapter::PUSH)
90                     {
91                         if (numButtonsPressed==1)
92                         {
93                             osg::Vec3d intersection;
94                             bool withinWidget = computeExtentsPositionInLocalCoordinates(ev, ea, intersection);
95 
96                             if (withinWidget) _hasEventFocus = true;
97                             else _hasEventFocus = false;
98                         }
99                     }
100                 }
101                 else if (_focusBehaviour==FOCUS_FOLLOWS_POINTER)
102                 {
103                     bool checkWithinWidget = false;
104                     if (!_hasEventFocus)
105                     {
106                         checkWithinWidget = (ea->getEventType()!=osgGA::GUIEventAdapter::FRAME) && ea->getButtonMask()==0;
107                     }
108                     else
109                     {
110                         // if mouse move or mouse release check to see if mouse still within widget to retain focus
111                         if (ea->getEventType()==osgGA::GUIEventAdapter::MOVE)
112                         {
113                             checkWithinWidget = true;
114                         }
115                         else if (ea->getEventType()==osgGA::GUIEventAdapter::RELEASE)
116                         {
117                             // if no buttons pressed then check
118                             if (ea->getButtonMask()==0) checkWithinWidget = true;
119                         }
120                     }
121 
122                     if (checkWithinWidget)
123                     {
124                         osg::Vec3d intersection;
125                         bool withinWidget = computeExtentsPositionInLocalCoordinates(ev, ea, intersection);
126 
127                         _hasEventFocus = withinWidget;
128                     }
129                 }
130 
131                 if (_hasEventFocus && (ea->getEventType()==osgGA::GUIEventAdapter::PUSH || ea->getEventType()==osgGA::GUIEventAdapter::SCROLL) )
132                 {
133                     osgViewer::View* view = dynamic_cast<osgViewer::View*>(aa);
134                     if (view && view->getCameraManipulator())
135                     {
136                         view->getCameraManipulator()->finishAnimation();
137                         view->requestContinuousUpdate( false );
138                     }
139                 }
140 
141 
142                 if (previousFocus != _hasEventFocus)
143                 {
144                     if (_hasEventFocus)
145                     {
146                         enter();
147 
148                     }
149                     else
150                     {
151                         leave();
152                     }
153                 }
154 
155             }
156         }
157     }
158 }
159 
setHasEventFocus(bool focus)160 void Widget::setHasEventFocus(bool focus)
161 {
162     if (_hasEventFocus == focus) return;
163 
164     _hasEventFocus = focus;
165 
166     if (_hasEventFocus) enter();
167     else leave();
168 }
169 
getHasEventFocus() const170 bool Widget::getHasEventFocus() const
171 {
172     return _hasEventFocus;
173 }
174 
enter()175 void Widget::enter()
176 {
177     if (!runCallbacks("enter")) enterImplementation();
178 }
179 
enterImplementation()180 void Widget::enterImplementation()
181 {
182     OSG_NOTICE<<"Widget::enter()"<<std::endl;
183 }
184 
leave()185 void Widget::leave()
186 {
187     if (!runCallbacks("leave")) leaveImplementation();
188 }
189 
leaveImplementation()190 void Widget::leaveImplementation()
191 {
192     OSG_NOTICE<<"Widget::leave()"<<std::endl;
193 }
194 
traverse(osg::NodeVisitor & nv)195 void Widget::traverse(osg::NodeVisitor& nv)
196 {
197     if (nv.referenceCount()!=0)
198     {
199         osg::Parameters inputParameters, outputParameters;
200         inputParameters.push_back(&nv);
201         if (runCallbacks("traverse",inputParameters, outputParameters)) return;
202     }
203 
204     traverseImplementation(nv);
205 
206 }
207 
traverseImplementation(osg::NodeVisitor & nv)208 void Widget::traverseImplementation(osg::NodeVisitor& nv)
209 {
210     if (!_graphicsInitialized && nv.getVisitorType()!=osg::NodeVisitor::CULL_VISITOR) createGraphics();
211 
212     osgGA::EventVisitor* ev = dynamic_cast<osgGA::EventVisitor*>(&nv);
213     if (ev)
214     {
215         if (_visible && _enabled)
216         {
217 
218             updateFocus(nv);
219 
220             // OSG_NOTICE<<"EventTraversal getHasEventFocus()="<<getHasEventFocus()<<std::endl;
221 
222             // signify that event has been taken by widget with focus
223 
224             bool widgetsWithFocusSetHandled = getHasEventFocus();
225 
226             osgGA::EventQueue::Events& events = ev->getEvents();
227             for(osgGA::EventQueue::Events::iterator itr = events.begin();
228                 itr != events.end();
229                 ++itr)
230             {
231                 if (handle(ev, itr->get()) || widgetsWithFocusSetHandled)
232                 {
233                     (*itr)->setHandled(true);
234                     ev->setEventHandled(true);
235                 }
236             }
237 
238             GraphicsSubgraphMap::iterator itr = _graphicsSubgraphMap.begin();
239             while(itr!= _graphicsSubgraphMap.end() && itr->first<=0)
240             {
241                 itr->second->accept(nv);
242                 ++itr;
243             }
244 
245             osg::Group::traverse(nv);
246 
247             while(itr!= _graphicsSubgraphMap.end())
248             {
249                 itr->second->accept(nv);
250                 ++itr;
251             }
252 
253         }
254     }
255     else if (_visible ||
256             (nv.getVisitorType()!=osg::NodeVisitor::UPDATE_VISITOR && nv.getVisitorType()!=osg::NodeVisitor::CULL_VISITOR && nv.getVisitorType()!=osg::NodeVisitor::INTERSECTION_VISITOR) )
257     {
258         osgUtil::CullVisitor* cv = (nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR) ? dynamic_cast<osgUtil::CullVisitor*>(&nv) : 0;
259         if (cv && _widgetStateSet.valid()) cv->pushStateSet(_widgetStateSet.get());
260 
261         GraphicsSubgraphMap::iterator itr = _graphicsSubgraphMap.begin();
262         while(itr!= _graphicsSubgraphMap.end() && itr->first<=0)
263         {
264             itr->second->accept(nv);
265             ++itr;
266         }
267 
268         Group::traverse(nv);
269 
270         while(itr!= _graphicsSubgraphMap.end())
271         {
272             itr->second->accept(nv);
273             ++itr;
274         }
275 
276         if (cv && _widgetStateSet.valid()) cv->popStateSet();
277     }
278 }
279 
handle(osgGA::EventVisitor * ev,osgGA::Event * event)280 bool Widget::handle(osgGA::EventVisitor* ev, osgGA::Event* event)
281 {
282     // currently lua scripting takes a ref count so messes up handling of NodeVisitor's created on stack,
283     // so don't attempt to call the sctipt.
284     if (ev->referenceCount()!=0)
285     {
286         osg::Parameters inputParameters, outputParameters;
287         inputParameters.push_back(ev);
288         inputParameters.push_back(event);
289         if (runCallbacks("handle",inputParameters, outputParameters))
290         {
291             if (outputParameters.size()>=1)
292             {
293                 osg::BoolValueObject* bvo = dynamic_cast<osg::BoolValueObject*>(outputParameters[0].get());
294                 return bvo ? bvo->getValue() : false;
295             }
296         }
297     }
298 
299     return handleImplementation(ev, event);
300 }
301 
handleImplementation(osgGA::EventVisitor * ev,osgGA::Event * event)302 bool Widget::handleImplementation(osgGA::EventVisitor* ev, osgGA::Event* event)
303 {
304     return false;
305 }
306 
dirty()307 void Widget::dirty()
308 {
309     _graphicsInitialized = false;
310 }
311 
createGraphics()312 void Widget::createGraphics()
313 {
314     if (!runCallbacks("createGraphics")) createGraphicsImplementation();
315 }
316 
createGraphicsImplementation()317 void Widget::createGraphicsImplementation()
318 {
319     _graphicsInitialized = true;
320 }
321 
computeBound() const322 osg::BoundingSphere Widget::computeBound() const
323 {
324     osg::BoundingSphere bs;
325     if (_extents.valid()) bs.expandBy(_extents);
326     bs.expandBy(Group::computeBound());
327     return bs;
328 }
329 
resizeGLObjectBuffers(unsigned int maxSize)330 void Widget::resizeGLObjectBuffers(unsigned int maxSize)
331 {
332     for(GraphicsSubgraphMap::iterator itr = _graphicsSubgraphMap.begin();
333         itr !=  _graphicsSubgraphMap.end();
334         ++itr)
335     {
336         itr->second->resizeGLObjectBuffers(maxSize);
337     }
338 
339     Group::resizeGLObjectBuffers(maxSize);
340 }
341 
342 
releaseGLObjects(osg::State * state) const343 void Widget::releaseGLObjects(osg::State* state) const
344 {
345     for(GraphicsSubgraphMap::const_iterator itr = _graphicsSubgraphMap.begin();
346         itr !=  _graphicsSubgraphMap.end();
347         ++itr)
348     {
349         itr->second->releaseGLObjects(state);
350     }
351 
352     Group::releaseGLObjects(state);
353 
354 
355 }
356 
computePositionInLocalCoordinates(osgGA::EventVisitor * ev,osgGA::GUIEventAdapter * event,osg::Vec3d & localPosition) const357 bool Widget::computePositionInLocalCoordinates(osgGA::EventVisitor* ev, osgGA::GUIEventAdapter* event, osg::Vec3d& localPosition) const
358 {
359     osgGA::GUIActionAdapter* aa = ev ? ev->getActionAdapter() : 0;
360     osgUtil::LineSegmentIntersector::Intersections intersections;
361     if (aa && aa->computeIntersections(*event, ev->getNodePath(), intersections))
362     {
363         localPosition = intersections.begin()->getLocalIntersectPoint();
364 
365         return (_extents.contains(localPosition, 1e-6));
366     }
367     else
368     {
369         return false;
370     }
371 }
372 
373 struct SortTraversalOrder
374 {
operator ()SortTraversalOrder375     bool operator() (const osgUtil::LineSegmentIntersector::Intersection* lhs, const osgUtil::LineSegmentIntersector::Intersection* rhs) const
376     {
377         double epsilon = 1e-6;
378         if (lhs->ratio > (rhs->ratio+epsilon)) return true;
379         if (lhs->ratio < (rhs->ratio-epsilon)) return false;
380 
381         const osg::NodePath& np_lhs = lhs->nodePath;
382         const osg::NodePath& np_rhs = rhs->nodePath;
383 
384         osg::NodePath::const_iterator itr_lhs = np_lhs.begin();
385         osg::NodePath::const_iterator end_lhs = np_lhs.end();
386         osg::NodePath::const_iterator itr_rhs = np_rhs.begin();
387         osg::NodePath::const_iterator end_rhs = np_rhs.end();
388         const osg::Group* parent = 0;
389 
390         while(itr_lhs!=end_lhs && itr_rhs!=end_rhs)
391         {
392             if (*itr_lhs == *itr_rhs)
393             {
394                 parent = (*itr_lhs)->asGroup();
395                 ++itr_lhs;
396                 ++itr_rhs;
397             }
398             else if (parent==0)
399             {
400                 OSG_NOTICE<<"SortTraversalOrder::operator() NodePath has no parent, just have to use default less than operator for Intersection"<<std::endl;
401                 return (*lhs)<(*rhs);
402             }
403             else
404             {
405                 const osgUI::Widget* widget = dynamic_cast<const osgUI::Widget*>(parent);
406 
407                 unsigned int lhs_index = parent->getChildIndex(*itr_lhs);
408                 double lhs_sort_value = static_cast<double>(lhs_index)/static_cast<double>(parent->getNumChildren());
409 
410                 unsigned int rhs_index = parent->getChildIndex(*itr_rhs);
411                 double rhs_sort_value = (static_cast<double>(rhs_index)+epsilon)/static_cast<double>(parent->getNumChildren());
412 
413                 if (widget)
414                 {
415                     const osgUI::Widget::GraphicsSubgraphMap& gsm = widget->getGraphicsSubgraphMap();
416                     for(osgUI::Widget::GraphicsSubgraphMap::const_iterator itr=gsm.begin();
417                         itr!=gsm.end();
418                         ++itr)
419                     {
420                         if (itr->second==(*itr_lhs)) lhs_sort_value = itr->first;
421                         if (itr->second==(*itr_rhs)) rhs_sort_value = itr->first;
422                     }
423                 }
424 
425                 if (lhs_sort_value>rhs_sort_value) return true;
426                 if (lhs_sort_value<rhs_sort_value) return false;
427 
428             }
429         }
430 
431         return false;
432     }
433 };
434 
computeIntersections(osgGA::EventVisitor * ev,osgGA::GUIEventAdapter * event,Intersections & intersections,osg::Node::NodeMask traversalMask) const435 bool Widget::computeIntersections(osgGA::EventVisitor* ev, osgGA::GUIEventAdapter* event, Intersections& intersections, osg::Node::NodeMask traversalMask) const
436 {
437     osgGA::GUIActionAdapter* aa = ev ? ev->getActionAdapter() : 0;
438     osgUtil::LineSegmentIntersector::Intersections source_intersections;
439     if (aa && aa->computeIntersections(*event, ev->getNodePath(), source_intersections, traversalMask))
440     {
441         typedef std::vector<const osgUtil::LineSegmentIntersector::Intersection*> IntersectionPointerList;
442         IntersectionPointerList intersectionsToSort;
443 
444         // populate the temporay vector of poiners to the original intersection pointers.
445         for(osgUtil::LineSegmentIntersector::Intersections::iterator itr = source_intersections.begin();
446             itr != source_intersections.end();
447             ++itr)
448         {
449             if (itr->drawable->getName()!="DepthSetPanel")
450             {
451                 intersectionsToSort.push_back(&(*itr));
452             }
453         }
454 
455         // sort the pointer list into order based on child traversal order, to be consistent with osgUI rendering order.
456         std::sort(intersectionsToSort.begin(), intersectionsToSort.end(), SortTraversalOrder());
457 
458         // copy the pointers to final Intersection container
459         for(IntersectionPointerList::iterator itr = intersectionsToSort.begin();
460             itr != intersectionsToSort.end();
461             ++itr)
462         {
463             intersections.push_back(*(*itr));
464         }
465         return true;
466     }
467     return false;
468 }
469 
470 
computeExtentsPositionInLocalCoordinates(osgGA::EventVisitor * ev,osgGA::GUIEventAdapter * event,osg::Vec3d & localPosition,bool withinExtents) const471 bool Widget::computeExtentsPositionInLocalCoordinates(osgGA::EventVisitor* ev, osgGA::GUIEventAdapter* event, osg::Vec3d& localPosition, bool withinExtents) const
472 {
473     //OSG_NOTICE<<"Widget::computeExtentsPositionInLocalCoordinates(()"<<std::endl;
474     const osg::Camera* camera = 0;
475     double x=0.0, y=0.0;
476     if (event->getNumPointerData()>=1)
477     {
478         const osgGA::PointerData* pd = event->getPointerData(event->getNumPointerData()-1);
479         camera = dynamic_cast<const osg::Camera*>(pd->object.get());
480         if (camera)
481         {
482             x = pd->getXnormalized();
483             y = pd->getYnormalized();
484         }
485     }
486     //OSG_NOTICE<<"   camera = "<<camera<<", x = "<<x<<", y="<<y<<std::endl;
487     if (!camera) return false;
488 
489     const osg::NodePath& nodePath = ev->getNodePath();
490 
491     osg::Matrixd matrix;
492     if (nodePath.size()>1)
493     {
494         osg::NodePath prunedNodePath(nodePath.begin(),nodePath.end()-1);
495         matrix = osg::computeLocalToWorld(prunedNodePath);
496     }
497 
498     matrix.postMult(camera->getViewMatrix());
499     matrix.postMult(camera->getProjectionMatrix());
500 
501     double zNear = -1.0;
502     double zFar = 1.0;
503 
504     osg::Matrixd inverse;
505     inverse.invert(matrix);
506 
507     osg::Vec3d startVertex = osg::Vec3d(x,y,zNear) * inverse;
508     osg::Vec3d endVertex = osg::Vec3d(x,y,zFar) * inverse;
509 
510     //OSG_NOTICE<<"   startVertex("<<startVertex<<"(, endVertex("<<endVertex<<")"<<std::endl;
511 
512 
513     osg::Plane plane(0.0, 0.0, 1.0, _extents.zMax());
514 
515     //OSG_NOTICE<<"   plane("<<plane<<")"<<std::endl;
516     double ds = plane.distance(startVertex);
517     double de = plane.distance(endVertex);
518     if (ds*de>0.0) return false;
519 
520     double r = ds/(ds-de);
521     //OSG_NOTICE<<"   r = "<<r<<std::endl;
522 
523     osg::Vec3d intersection = startVertex + (endVertex-startVertex)*r;
524     //OSG_NOTICE<<"    intersection = "<<intersection<<std::endl;
525     localPosition = intersection;
526 
527     return withinExtents ? _extents.contains(localPosition, 1e-6) : true;
528 }
529