diff --git a/examples/osgQtWidgets/osgQtWidgets.cpp b/examples/osgQtWidgets/osgQtWidgets.cpp index 861be0af0..0e1603147 100644 --- a/examples/osgQtWidgets/osgQtWidgets.cpp +++ b/examples/osgQtWidgets/osgQtWidgets.cpp @@ -107,25 +107,25 @@ protected: }; -//We would need to document the following somewhere in order to guide people on +//We would need to document the following somewhere in order to guide people on //what they need to use... // //---------------------------------------------- //There are two angles to consider. // -//1. If someone wants a widget in their Qt app to be an OSG-rendered scene, they -//need GraphicsWindowQt (in the osgViewerQtContext example) or QOSGWidget (in the -//osgViewerQt example). These two allow both OSG and Qt to manage their threads -//in a way which is optimal to them. We've used QOSGWidget in the past and had -//trouble when Qt tried to overlay other widgets over the QOSGWidget (since OSG -//did its rendering independently of Qt, it would overwrite what Qt had drawn). I -//haven't tried GraphicsWindowQt yet, but I expect since it uses QGLWidget, it -//will result in Qt knowing when OSG has drawn and be able to do overlays at the +//1. If someone wants a widget in their Qt app to be an OSG-rendered scene, they +//need GraphicsWindowQt (in the osgViewerQtContext example) or QOSGWidget (in the +//osgViewerQt example). These two allow both OSG and Qt to manage their threads +//in a way which is optimal to them. We've used QOSGWidget in the past and had +//trouble when Qt tried to overlay other widgets over the QOSGWidget (since OSG +//did its rendering independently of Qt, it would overwrite what Qt had drawn). I +//haven't tried GraphicsWindowQt yet, but I expect since it uses QGLWidget, it +//will result in Qt knowing when OSG has drawn and be able to do overlays at the //right time. Eventually GraphicsWindowQt can be brought into osgViewer I imagine... // -//2. If someone wants to bring Qt widgets inside their OSG scene (to do HUDs or -//an interface on a computer screen which is inside the 3D scene, or even -//floating Qt widgets, for example). That's where QGraphicsViewAdapter + +//2. If someone wants to bring Qt widgets inside their OSG scene (to do HUDs or +//an interface on a computer screen which is inside the 3D scene, or even +//floating Qt widgets, for example). That's where QGraphicsViewAdapter + //QWidgetImage will be useful. //---------------------------------------------- @@ -160,7 +160,7 @@ int main(int argc, char **argv) bool useLabel = false; if (arguments.read("--useLabel")) useLabel = true; - // true = make a Qt window with the same content to compare to + // true = make a Qt window with the same content to compare to // QWebViewImage/QWidgetImage // false = use QWebViewImage/QWidgetImage (depending on useWidgetImage) bool sanityCheck = false; @@ -183,9 +183,9 @@ int main(int argc, char **argv) //------------------------------------------------------------------- // QWebViewImage test //------------------------------------------------------------------- - // Note: When the last few issues with QWidgetImage are fixed, - // QWebViewImage and this if() {} section can be removed since - // QWidgetImage can display a QWebView just like QWebViewImage. Use + // Note: When the last few issues with QWidgetImage are fixed, + // QWebViewImage and this if() {} section can be removed since + // QWidgetImage can display a QWebView just like QWebViewImage. Use // --useWidgetImage --useBrowser to see that in action. if (!sanityCheck) @@ -193,7 +193,7 @@ int main(int argc, char **argv) osg::ref_ptr image = new osgQt::QWebViewImage; if (arguments.argc()>1) image->navigateTo((arguments[1])); - else image->navigateTo("http://www.youtube.com/"); + else image->navigateTo("http://www.openscenegraph.org/"); osgWidget::GeometryHints hints(osg::Vec3(0.0f,0.0f,0.0f), osg::Vec3(1.0f,0.0f,0.0f), @@ -208,7 +208,7 @@ int main(int argc, char **argv) } else { - // Sanity check, do the same thing as QGraphicsViewAdapter but in + // Sanity check, do the same thing as QGraphicsViewAdapter but in // a separate Qt window. QWebPage* webPage = new QWebPage; webPage->settings()->setAttribute(QWebSettings::JavascriptEnabled, true); @@ -218,7 +218,7 @@ int main(int argc, char **argv) webView->setPage(webPage); if (arguments.argc()>1) webView->load(QUrl(arguments[1])); - else webView->load(QUrl("http://www.youtube.com/")); + else webView->load(QUrl("http://www.openscenegraph.org/")); QGraphicsScene* graphicsScene = new QGraphicsScene; graphicsScene->addWidget(webView); @@ -240,14 +240,16 @@ int main(int argc, char **argv) // QWidgetImage test //------------------------------------------------------------------- // QWidgetImage still has some issues, some examples are: - // - // 1. Editing in the QTextEdit doesn't work. Also when started with - // --useBrowser, editing in the search field on YouTube doesn't - // work. But that same search field when using QWebViewImage - // works... And editing in the text field in the pop-up getInteger - // dialog works too. All these cases use QGraphicsViewAdapter + // + // 1. Editing in the QTextEdit doesn't work. Also when started with + // --useBrowser, editing in the search field on YouTube doesn't + // work. But that same search field when using QWebViewImage + // works... And editing in the text field in the pop-up getInteger + // dialog works too. All these cases use QGraphicsViewAdapter // under the hood, so why do some work and others don't? // + // <<< FIXED, need TextEditorInteraction >>> + // // a) osgQtBrowser --useWidgetImage [--fullscreen] (optional) // b) Try to click in the QTextEdit and type, or to select text // and drag-and-drop it somewhere else in the QTextEdit. These @@ -259,11 +261,11 @@ int main(int argc, char **argv) // g) osgQtBrowser // h) Try the operation in f), it works. // - // 2. Operations on floating windows (--numFloatingWindows 1 or more). - // Moving by dragging the titlebar, clicking the close button, - // resizing them, none of these work. I wonder if it's because the - // OS manages those functions (they're functions of the window - // decorations) so we need to do something special for that? But + // 2. Operations on floating windows (--numFloatingWindows 1 or more). + // Moving by dragging the titlebar, clicking the close button, + // resizing them, none of these work. I wonder if it's because the + // OS manages those functions (they're functions of the window + // decorations) so we need to do something special for that? But // in --sanityCheck mode they work. // // a) osgQtBrowser --useWidgetImage --numFloatingWindows 1 [--fullscreen] @@ -272,35 +274,37 @@ int main(int argc, char **argv) // c) osgQtBrowser --useWidgetImage --numFloatingWindows 1 --sanityCheck // d) Try the operations in b), all they work. // e) osgQtBrowser --useWidgetImage [--fullscreen] - // f) Click the button so that the getInteger() dialog is - // displayed, then try to move that dialog or close it with the + // f) Click the button so that the getInteger() dialog is + // displayed, then try to move that dialog or close it with the // close button, these don't work. // g) osgQtBrowser --useWidgetImage --sanityCheck // h) Try the operation in f), it works. // - // 3. (Minor) The QGraphicsView's scrollbars don't appear when - // using QWidgetImage or QWebViewImage. QGraphicsView is a + // 3. (Minor) The QGraphicsView's scrollbars don't appear when + // using QWidgetImage or QWebViewImage. QGraphicsView is a // QAbstractScrollArea and it should display scrollbars as soon as // the scene is too large to fit the view. // + // <<< FIXED >>> + // // a) osgQtBrowser --useWidgetImage --fullscreen // b) Resize the OSG window so it's smaller than the QTextEdit. // Scrollbars should appear but don't. // c) osgQtBrowser --useWidgetImage --sanityCheck - // d) Try the operation in b), scrollbars appear. Even if you have - // floating windows (by clicking the button or by adding - // --numFloatingWindows 1) and move them outside the view, - // scrollbars appear too. You can't test that case in OSG for + // d) Try the operation in b), scrollbars appear. Even if you have + // floating windows (by clicking the button or by adding + // --numFloatingWindows 1) and move them outside the view, + // scrollbars appear too. You can't test that case in OSG for // now because of problem 2 above, but that's pretty cool. // - // 4. (Minor) In sanity check mode, the widget added to the + // 4. (Minor) In sanity check mode, the widget added to the // QGraphicsView is centered. With QGraphicsViewAdapter, it is not. // // a) osgQtBrowser --useWidgetImage [--fullscreen] // b) The QTextEdit and button are not in the center of the image // generated by the QGraphicsViewAdapter. // c) osgQtBrowser --useWidgetImage --sanityCheck - // d) The QTextEdit and button are in the center of the + // d) The QTextEdit and button are in the center of the // QGraphicsView. @@ -346,7 +350,7 @@ int main(int argc, char **argv) { QTextEdit* textEdit = new QTextEdit(text); textEdit->setReadOnly(false); - textEdit->setTextInteractionFlags(Qt::TextEditable); + textEdit->setTextInteractionFlags(Qt::TextEditorInteraction); QPalette palette = textEdit->palette(); palette.setColor(QPalette::Highlight, Qt::darkBlue); @@ -388,7 +392,7 @@ int main(int argc, char **argv) texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); mt->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - osgViewer::InteractiveImageHandler* handler; + osgViewer::InteractiveImageHandler* handler; if (inScene) { mt->setMatrix(osg::Matrix::rotate(osg::Vec3(0,1,0), osg::Vec3(0,0,1))); @@ -398,9 +402,9 @@ int main(int argc, char **argv) } else // fullscreen { - // The HUD camera's viewport needs to follow the size of the + // The HUD camera's viewport needs to follow the size of the // window. MyInteractiveImageHandler will make sure of this. - // As for the quad and the camera's projection, setting the + // As for the quad and the camera's projection, setting the // projection resize policy to FIXED takes care of them, so // they can stay the same: (0,1,0,1) with a quad that fits. @@ -429,13 +433,13 @@ int main(int argc, char **argv) overlay->addChild(mt); root->addChild(overlay); - + quad->setEventCallback(handler); quad->setCullCallback(handler); } else { - // Sanity check, do the same thing as QWidgetImage and + // Sanity check, do the same thing as QWidgetImage and // QGraphicsViewAdapter but in a separate Qt window. graphicsScene = new QGraphicsScene; diff --git a/include/osgQt/QGraphicsViewAdapter b/include/osgQt/QGraphicsViewAdapter index 7b9659ac1..8a8a483c3 100644 --- a/include/osgQt/QGraphicsViewAdapter +++ b/include/osgQt/QGraphicsViewAdapter @@ -52,6 +52,7 @@ class OSGQT_EXPORT QGraphicsViewAdapter : public QObject void clearWriteBuffer(); + bool requiresRendering() const { return _requiresRendering; } void render(); void assignImage(unsigned int i); @@ -61,6 +62,12 @@ class OSGQT_EXPORT QGraphicsViewAdapter : public QObject void setBackgroundColor(QColor color) { _backgroundColor = color; } QColor getBackgroundColor() const { return _backgroundColor; } + /** The 'background widget' will ignore mouse/keyboard events and let following handlers handle them + It is mainly used for integrating scene graph and full-screen UIs + */ + void setBackgroundWidget(QWidget* w) { _backgroundWidget = w; } + QWidget* getBackgroundWidget() { return _backgroundWidget; } + QGraphicsView* getQGraphicsView() { return _graphicsView; } QGraphicsScene* getQGraphicsScene() { return _graphicsScene; } @@ -71,6 +78,7 @@ class OSGQT_EXPORT QGraphicsViewAdapter : public QObject QWidget* getWidgetAt(const QPoint& pos); osg::observer_ptr _image; + QWidget* _backgroundWidget; int _previousButtonMask; int _previousMouseX; @@ -78,6 +86,7 @@ class OSGQT_EXPORT QGraphicsViewAdapter : public QObject int _previousQtMouseX; int _previousQtMouseY; bool _previousSentEvent; + bool _requiresRendering; int _width; int _height; diff --git a/include/osgQt/QWebViewImage b/include/osgQt/QWebViewImage index be16446f5..de9e383aa 100644 --- a/include/osgQt/QWebViewImage +++ b/include/osgQt/QWebViewImage @@ -66,9 +66,12 @@ class QWebViewImage : public osgWidget::BrowserImage void render() { - _adapter->render(); + if (_adapter->requiresRendering()) _adapter->render(); } + virtual bool requiresUpdateCall() const { return true; } + virtual void update( osg::NodeVisitor* nv ) { render(); } + virtual bool sendFocusHint(bool focus) { QFocusEvent event(focus ? QEvent::FocusIn : QEvent::FocusOut, Qt::OtherFocusReason); diff --git a/include/osgQt/QWidgetImage b/include/osgQt/QWidgetImage index 8f1dd851b..89e4b2a4a 100644 --- a/include/osgQt/QWidgetImage +++ b/include/osgQt/QWidgetImage @@ -29,6 +29,8 @@ class OSGQT_EXPORT QWidgetImage : public osg::Image QWidget* getQWidget() { return _widget; } QGraphicsViewAdapter* getQGraphicsViewAdapter() { return _adapter; } + virtual bool requiresUpdateCall() const { return true; } + virtual void update( osg::NodeVisitor* nv ) { render(); } void clearWriteBuffer(); diff --git a/src/osgQt/QGraphicsViewAdapter.cpp b/src/osgQt/QGraphicsViewAdapter.cpp index b4a43cd93..b248153ea 100644 --- a/src/osgQt/QGraphicsViewAdapter.cpp +++ b/src/osgQt/QGraphicsViewAdapter.cpp @@ -67,9 +67,13 @@ const QImage::Format s_imageFormat = QImage::Format_ARGB32_Premultiplied; QGraphicsViewAdapter::QGraphicsViewAdapter(osg::Image* image, QWidget* widget): _image(image), + _backgroundWidget(0), + _previousMouseX(-1), + _previousMouseY(-1), _previousQtMouseX(-1), _previousQtMouseY(-1), _previousSentEvent(false), + _requiresRendering(false), _qtKeyModifiers(Qt::NoModifier), _backgroundColor(255, 255, 255), _widget(widget) @@ -115,13 +119,13 @@ QGraphicsViewAdapter::QGraphicsViewAdapter(osg::Image* image, QWidget* widget): void QGraphicsViewAdapter::repaintRequestedSlot(const QList&) { // OSG_NOTICE<<"QGraphicsViewAdapter::repaintRequestedSlot"<itemAt(pos); - if(item && item->contains(item->mapFromScene(pos))) + if(item /*&& item->contains(item->mapFromScene(pos))*/) { - QGraphicsProxyWidget* p = dynamic_cast(item); + QGraphicsProxyWidget* p = qgraphicsitem_cast(item); if(p) { childAt = p->widget(); @@ -292,6 +296,14 @@ QWidget* QGraphicsViewAdapter::getWidgetAt(const QPoint& pos) { childAt = c; } + + // Widgets like QTextEdit will automatically add child scroll area widgets + // that will be selected by childAt(), we have to change to parents at that moment + // Hardcoded by the internal widget's name 'qt_scrollarea_viewport' at present + if (childAt->objectName() == "qt_scrollarea_viewport") + { + childAt = childAt->parentWidget(); + } return childAt; } } @@ -305,7 +317,17 @@ bool QGraphicsViewAdapter::sendPointerEvent(int x, int y, int buttonMask) QPoint pos(_previousQtMouseX, _previousQtMouseY); - if (getWidgetAt(pos) != NULL || (_previousSentEvent && buttonMask != 0)) + QWidget* targetWidget = getWidgetAt(pos); + OSG_INFO << "Get " << (targetWidget ? targetWidget->metaObject()->className() : std::string("NULL")) + << " at global pos " << x << ", " << y << std::endl; + + if (_backgroundWidget && _backgroundWidget == targetWidget) + { + // Mouse is at background widget, so ignore such events + return false; + } + + if (targetWidget != NULL || (_previousSentEvent && buttonMask != 0)) { QCoreApplication::postEvent(this, new MyQPointerEvent(x,y,buttonMask)); OSG_INFO<<"sendPointerEvent("<mapFromGlobal(globalPos); @@ -376,10 +398,11 @@ bool QGraphicsViewAdapter::handlePointerEvent(int x, int y, int buttonMask) if (eventType==QEvent::MouseButtonPress) { _image->sendFocusHint(true); + if (targetWidget) targetWidget->setFocus(Qt::MouseFocusReason); } QMouseEvent event(eventType, globalPos, qtButton, qtMouseButtons, 0); - QCoreApplication::sendEvent(_graphicsView->viewport(), &event ); + QCoreApplication::sendEvent(_graphicsView->viewport(), &event); _previousButtonMask = buttonMask; } @@ -398,7 +421,14 @@ bool QGraphicsViewAdapter::handlePointerEvent(int x, int y, int buttonMask) bool QGraphicsViewAdapter::sendKeyEvent(int key, bool keyDown) { QPoint pos(_previousQtMouseX, _previousQtMouseY); - if (getWidgetAt(pos) != NULL) + QWidget* targetWidget = getWidgetAt(pos); + if (_backgroundWidget && _backgroundWidget == targetWidget) + { + // Mouse is at background widget, so ignore such events + return false; + } + + if (targetWidget != NULL) { QCoreApplication::postEvent(this, new MyQKeyEvent(key,keyDown)); return true; @@ -489,6 +519,7 @@ void QGraphicsViewAdapter::render() { OSG_INFO<<"Current write = "<<_currentWrite<render(); + if (_adapter->requiresRendering()) _adapter->render(); } void QWidgetImage::scaleImage(int s,int t,int /*r*/, GLenum /*newDataType*/) diff --git a/src/osgViewer/ViewerEventHandlers.cpp b/src/osgViewer/ViewerEventHandlers.cpp index 2ef8e838c..9159788bc 100644 --- a/src/osgViewer/ViewerEventHandlers.cpp +++ b/src/osgViewer/ViewerEventHandlers.cpp @@ -719,6 +719,12 @@ InteractiveImageHandler::InteractiveImageHandler(osg::Image* image, osg::Texture bool InteractiveImageHandler::mousePosition(osgViewer::View* view, osg::NodeVisitor* nv, const osgGA::GUIEventAdapter& ea, int& x, int &y) const { if (!view) return false; + if (_fullscreen) + { + x = ea.getX(); + y = ea.getY(); + return true; + } osgUtil::LineSegmentIntersector::Intersections intersections; bool foundIntersection = (nv==0) ? view->computeIntersections(ea, intersections) :