| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the Qt Data Visualization module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:GPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 3 or (at your option) any later version |
| ** approved by the KDE Free Qt Foundation. The licenses are as published by |
| ** the Free Software Foundation and appearing in the file LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "abstractdeclarative_p.h" |
| #include "declarativetheme_p.h" |
| #include "declarativerendernode_p.h" |
| #include <QtGui/QGuiApplication> |
| #if defined(Q_OS_IOS) |
| #include <QtCore/QTimer> |
| #endif |
| #if defined(Q_OS_OSX) |
| #include <qpa/qplatformnativeinterface.h> |
| #endif |
| |
| #if !defined(Q_OS_MAC) && !defined(Q_OS_ANDROID) && !defined(Q_OS_WINRT) |
| #define USE_SHARED_CONTEXT |
| #else |
| #include "glstatestore_p.h" |
| #endif |
| |
| QT_BEGIN_NAMESPACE_DATAVISUALIZATION |
| |
| static QList<const QQuickWindow *> clearList; |
| static QHash<AbstractDeclarative *, QQuickWindow *> graphWindowList; |
| static QHash<QQuickWindow *, bool> windowClearList; |
| |
| AbstractDeclarative::AbstractDeclarative(QQuickItem *parent) : |
| QQuickItem(parent), |
| m_controller(0), |
| m_contextWindow(0), |
| m_renderMode(RenderIndirect), |
| m_samples(0), |
| m_windowSamples(0), |
| m_initialisedSize(0, 0), |
| m_contextOrStateStore(0), |
| m_qtContext(0), |
| m_mainThread(QThread::currentThread()), |
| m_contextThread(0) |
| { |
| m_nodeMutex = QSharedPointer<QMutex>::create(); |
| |
| connect(this, &QQuickItem::windowChanged, this, &AbstractDeclarative::handleWindowChanged); |
| |
| // Set contents to false in case we are in qml designer to make component look nice |
| m_runningInDesigner = QGuiApplication::applicationDisplayName() == "Qml2Puppet"; |
| setFlag(ItemHasContents, !m_runningInDesigner); |
| } |
| |
| AbstractDeclarative::~AbstractDeclarative() |
| { |
| destroyContext(); |
| |
| disconnect(this, 0, this, 0); |
| checkWindowList(0); |
| |
| // Make sure not deleting locked mutex |
| QMutexLocker locker(&m_mutex); |
| locker.unlock(); |
| |
| m_nodeMutex.clear(); |
| } |
| |
| void AbstractDeclarative::setRenderingMode(AbstractDeclarative::RenderingMode mode) |
| { |
| if (mode == m_renderMode) |
| return; |
| |
| RenderingMode previousMode = m_renderMode; |
| |
| m_renderMode = mode; |
| |
| QQuickWindow *win = window(); |
| |
| switch (mode) { |
| case RenderDirectToBackground: |
| // Intentional flowthrough |
| case RenderDirectToBackground_NoClear: |
| m_initialisedSize = QSize(0, 0); |
| if (previousMode == RenderIndirect) { |
| update(); |
| setFlag(ItemHasContents, false); |
| if (win) { |
| QObject::connect(win, &QQuickWindow::beforeRendering, this, |
| &AbstractDeclarative::render, Qt::DirectConnection); |
| checkWindowList(win); |
| setAntialiasing(m_windowSamples > 0); |
| if (m_windowSamples != m_samples) |
| emit msaaSamplesChanged(m_windowSamples); |
| } |
| } |
| break; |
| case RenderIndirect: |
| m_initialisedSize = QSize(0, 0); |
| setFlag(ItemHasContents, !m_runningInDesigner); |
| update(); |
| if (win) { |
| QObject::disconnect(win, &QQuickWindow::beforeRendering, this, |
| &AbstractDeclarative::render); |
| checkWindowList(win); |
| } |
| setAntialiasing(m_samples > 0); |
| if (m_windowSamples != m_samples) |
| emit msaaSamplesChanged(m_samples); |
| break; |
| } |
| |
| updateWindowParameters(); |
| |
| emit renderingModeChanged(mode); |
| } |
| |
| AbstractDeclarative::RenderingMode AbstractDeclarative::renderingMode() const |
| { |
| return m_renderMode; |
| } |
| |
| QSGNode *AbstractDeclarative::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) |
| { |
| QSize boundingSize = boundingRect().size().toSize() * m_controller->scene()->devicePixelRatio(); |
| if (m_runningInDesigner || boundingSize.width() <= 0 || boundingSize.height() <= 0 |
| || m_controller.isNull() || !window()) { |
| delete oldNode; |
| return 0; |
| } |
| DeclarativeRenderNode *node = static_cast<DeclarativeRenderNode *>(oldNode); |
| |
| if (!node) { |
| node = new DeclarativeRenderNode(this, m_nodeMutex); |
| node->setController(m_controller.data()); |
| node->setQuickWindow(window()); |
| } |
| |
| node->setSize(boundingSize); |
| node->setSamples(m_samples); |
| node->update(); |
| node->markDirty(QSGNode::DirtyMaterial); |
| |
| return node; |
| } |
| |
| Declarative3DScene* AbstractDeclarative::scene() const |
| { |
| return static_cast<Declarative3DScene *>(m_controller->scene()); |
| } |
| |
| void AbstractDeclarative::setTheme(Q3DTheme *theme) |
| { |
| m_controller->setActiveTheme(theme, isComponentComplete()); |
| } |
| |
| Q3DTheme *AbstractDeclarative::theme() const |
| { |
| return m_controller->activeTheme(); |
| } |
| |
| void AbstractDeclarative::clearSelection() |
| { |
| m_controller->clearSelection(); |
| } |
| |
| void AbstractDeclarative::setSelectionMode(SelectionFlags mode) |
| { |
| int intmode = int(mode); |
| m_controller->setSelectionMode(QAbstract3DGraph::SelectionFlags(intmode)); |
| } |
| |
| AbstractDeclarative::SelectionFlags AbstractDeclarative::selectionMode() const |
| { |
| int intmode = int(m_controller->selectionMode()); |
| return SelectionFlags(intmode); |
| } |
| |
| void AbstractDeclarative::setShadowQuality(ShadowQuality quality) |
| { |
| m_controller->setShadowQuality(QAbstract3DGraph::ShadowQuality(quality)); |
| } |
| |
| AbstractDeclarative::ShadowQuality AbstractDeclarative::shadowQuality() const |
| { |
| return ShadowQuality(m_controller->shadowQuality()); |
| } |
| |
| bool AbstractDeclarative::shadowsSupported() const |
| { |
| return m_controller->shadowsSupported(); |
| } |
| |
| int AbstractDeclarative::addCustomItem(QCustom3DItem *item) |
| { |
| return m_controller->addCustomItem(item); |
| } |
| |
| void AbstractDeclarative::removeCustomItems() |
| { |
| m_controller->deleteCustomItems(); |
| } |
| |
| void AbstractDeclarative::removeCustomItem(QCustom3DItem *item) |
| { |
| m_controller->deleteCustomItem(item); |
| } |
| |
| void AbstractDeclarative::removeCustomItemAt(const QVector3D &position) |
| { |
| m_controller->deleteCustomItem(position); |
| } |
| |
| void AbstractDeclarative::releaseCustomItem(QCustom3DItem *item) |
| { |
| m_controller->releaseCustomItem(item); |
| } |
| |
| int AbstractDeclarative::selectedLabelIndex() const |
| { |
| return m_controller->selectedLabelIndex(); |
| } |
| |
| QAbstract3DAxis *AbstractDeclarative::selectedAxis() const |
| { |
| return m_controller->selectedAxis(); |
| } |
| |
| int AbstractDeclarative::selectedCustomItemIndex() const |
| { |
| return m_controller->selectedCustomItemIndex(); |
| } |
| |
| QCustom3DItem *AbstractDeclarative::selectedCustomItem() const |
| { |
| return m_controller->selectedCustomItem(); |
| } |
| |
| QQmlListProperty<QCustom3DItem> AbstractDeclarative::customItemList() |
| { |
| return QQmlListProperty<QCustom3DItem>(this, this, |
| &AbstractDeclarative::appendCustomItemFunc, |
| &AbstractDeclarative::countCustomItemFunc, |
| &AbstractDeclarative::atCustomItemFunc, |
| &AbstractDeclarative::clearCustomItemFunc); |
| } |
| |
| void AbstractDeclarative::appendCustomItemFunc(QQmlListProperty<QCustom3DItem> *list, |
| QCustom3DItem *item) |
| { |
| AbstractDeclarative *decl = reinterpret_cast<AbstractDeclarative *>(list->data); |
| decl->addCustomItem(item); |
| } |
| |
| int AbstractDeclarative::countCustomItemFunc(QQmlListProperty<QCustom3DItem> *list) |
| { |
| return reinterpret_cast<AbstractDeclarative *>(list->data)->m_controller->m_customItems.size(); |
| } |
| |
| QCustom3DItem *AbstractDeclarative::atCustomItemFunc(QQmlListProperty<QCustom3DItem> *list, |
| int index) |
| { |
| return reinterpret_cast<AbstractDeclarative *>(list->data)->m_controller->m_customItems.at(index); |
| } |
| |
| void AbstractDeclarative::clearCustomItemFunc(QQmlListProperty<QCustom3DItem> *list) |
| { |
| AbstractDeclarative *decl = reinterpret_cast<AbstractDeclarative *>(list->data); |
| decl->removeCustomItems(); |
| } |
| |
| void AbstractDeclarative::setSharedController(Abstract3DController *controller) |
| { |
| Q_ASSERT(controller); |
| m_controller = controller; |
| |
| if (!m_controller->isOpenGLES()) |
| m_samples = 4; |
| setAntialiasing(m_samples > 0); |
| |
| // Reset default theme, as the default C++ theme is Q3DTheme, not DeclarativeTheme3D. |
| DeclarativeTheme3D *defaultTheme = new DeclarativeTheme3D; |
| defaultTheme->d_ptr->setDefaultTheme(true); |
| defaultTheme->setType(Q3DTheme::ThemeQt); |
| m_controller->setActiveTheme(defaultTheme); |
| |
| QObject::connect(m_controller.data(), &Abstract3DController::shadowQualityChanged, this, |
| &AbstractDeclarative::handleShadowQualityChange); |
| QObject::connect(m_controller.data(), &Abstract3DController::activeInputHandlerChanged, this, |
| &AbstractDeclarative::inputHandlerChanged); |
| QObject::connect(m_controller.data(), &Abstract3DController::activeThemeChanged, this, |
| &AbstractDeclarative::themeChanged); |
| QObject::connect(m_controller.data(), &Abstract3DController::selectionModeChanged, this, |
| &AbstractDeclarative::handleSelectionModeChange); |
| QObject::connect(m_controller.data(), &Abstract3DController::elementSelected, this, |
| &AbstractDeclarative::handleSelectedElementChange); |
| |
| QObject::connect(m_controller.data(), &Abstract3DController::axisXChanged, this, |
| &AbstractDeclarative::handleAxisXChanged); |
| QObject::connect(m_controller.data(), &Abstract3DController::axisYChanged, this, |
| &AbstractDeclarative::handleAxisYChanged); |
| QObject::connect(m_controller.data(), &Abstract3DController::axisZChanged, this, |
| &AbstractDeclarative::handleAxisZChanged); |
| |
| QObject::connect(m_controller.data(), &Abstract3DController::measureFpsChanged, this, |
| &AbstractDeclarative::measureFpsChanged); |
| QObject::connect(m_controller.data(), &Abstract3DController::currentFpsChanged, this, |
| &AbstractDeclarative::currentFpsChanged); |
| |
| QObject::connect(m_controller.data(), &Abstract3DController::orthoProjectionChanged, this, |
| &AbstractDeclarative::orthoProjectionChanged); |
| |
| QObject::connect(m_controller.data(), &Abstract3DController::aspectRatioChanged, this, |
| &AbstractDeclarative::aspectRatioChanged); |
| QObject::connect(m_controller.data(), &Abstract3DController::optimizationHintsChanged, this, |
| &AbstractDeclarative::handleOptimizationHintChange); |
| QObject::connect(m_controller.data(), &Abstract3DController::polarChanged, this, |
| &AbstractDeclarative::polarChanged); |
| QObject::connect(m_controller.data(), &Abstract3DController::radialLabelOffsetChanged, this, |
| &AbstractDeclarative::radialLabelOffsetChanged); |
| QObject::connect(m_controller.data(), &Abstract3DController::horizontalAspectRatioChanged, this, |
| &AbstractDeclarative::horizontalAspectRatioChanged); |
| QObject::connect(m_controller.data(), &Abstract3DController::reflectionChanged, this, |
| &AbstractDeclarative::reflectionChanged); |
| QObject::connect(m_controller.data(), &Abstract3DController::reflectivityChanged, this, |
| &AbstractDeclarative::reflectivityChanged); |
| QObject::connect(m_controller.data(), &Abstract3DController::localeChanged, this, |
| &AbstractDeclarative::localeChanged); |
| QObject::connect(m_controller.data(), &Abstract3DController::queriedGraphPositionChanged, this, |
| &AbstractDeclarative::queriedGraphPositionChanged); |
| QObject::connect(m_controller.data(), &Abstract3DController::marginChanged, this, |
| &AbstractDeclarative::marginChanged); |
| } |
| |
| void AbstractDeclarative::activateOpenGLContext(QQuickWindow *window) |
| { |
| // We can assume we are not in middle of AbstractDeclarative destructor when we are here, |
| // since m_context creation is always done when this function is called from |
| // synchDataToRenderer(), which blocks main thread -> no need to mutex. |
| if (!m_contextOrStateStore || !m_qtContext || m_contextWindow != window) { |
| QOpenGLContext *currentContext = QOpenGLContext::currentContext(); |
| |
| // Note: Changing graph to different window when using multithreaded renderer will break! |
| |
| delete m_contextOrStateStore; |
| |
| m_contextThread = QThread::currentThread(); |
| m_contextWindow = window; |
| m_qtContext = currentContext; |
| |
| #ifdef USE_SHARED_CONTEXT |
| m_context = new QOpenGLContext(); |
| m_context->setFormat(m_qtContext->format()); |
| m_context->setShareContext(m_qtContext); |
| m_context->create(); |
| m_context->makeCurrent(window); |
| #else |
| // Shared contexts don't work properly in some platforms, so just store the |
| // context state on those |
| m_stateStore = new GLStateStore(QOpenGLContext::currentContext()); |
| m_stateStore->storeGLState(); |
| #endif |
| m_controller->initializeOpenGL(); |
| |
| // Make sure context / state store gets deleted. |
| QObject::connect(m_contextThread, &QThread::finished, this, |
| &AbstractDeclarative::destroyContext, Qt::DirectConnection); |
| } else { |
| #ifdef USE_SHARED_CONTEXT |
| m_context->makeCurrent(window); |
| #else |
| m_stateStore->storeGLState(); |
| #endif |
| } |
| } |
| |
| void AbstractDeclarative::doneOpenGLContext(QQuickWindow *window) |
| { |
| #ifdef USE_SHARED_CONTEXT |
| m_qtContext->makeCurrent(window); |
| #else |
| Q_UNUSED(window) |
| m_stateStore->restoreGLState(); |
| #endif |
| } |
| |
| void AbstractDeclarative::synchDataToRenderer() |
| { |
| if (m_renderMode == RenderDirectToBackground && clearList.size()) |
| clearList.clear(); |
| |
| QQuickWindow *win = window(); |
| activateOpenGLContext(win); |
| m_controller->synchDataToRenderer(); |
| doneOpenGLContext(win); |
| } |
| |
| int AbstractDeclarative::msaaSamples() const |
| { |
| if (m_renderMode == RenderIndirect) |
| return m_samples; |
| else |
| return m_windowSamples; |
| } |
| |
| void AbstractDeclarative::setMsaaSamples(int samples) |
| { |
| if (m_renderMode != RenderIndirect) { |
| qWarning("Multisampling cannot be adjusted in this render mode"); |
| } else { |
| if (m_controller->isOpenGLES()) { |
| if (samples > 0) |
| qWarning("Multisampling is not supported in OpenGL ES2"); |
| } else if (m_samples != samples) { |
| m_samples = samples; |
| setAntialiasing(m_samples > 0); |
| emit msaaSamplesChanged(samples); |
| update(); |
| } |
| } |
| } |
| |
| void AbstractDeclarative::handleWindowChanged(QQuickWindow *window) |
| { |
| checkWindowList(window); |
| |
| if (!window) |
| return; |
| |
| #if defined(Q_OS_OSX) |
| bool previousVisibility = window->isVisible(); |
| // Enable touch events for Mac touchpads |
| window->setVisible(true); |
| typedef void * (*EnableTouch)(QWindow*, bool); |
| EnableTouch enableTouch = |
| (EnableTouch)QGuiApplication::platformNativeInterface()->nativeResourceFunctionForIntegration("registertouchwindow"); |
| if (enableTouch) |
| enableTouch(window, true); |
| window->setVisible(previousVisibility); |
| #endif |
| |
| connect(window, &QObject::destroyed, this, &AbstractDeclarative::windowDestroyed); |
| |
| int oldWindowSamples = m_windowSamples; |
| m_windowSamples = window->format().samples(); |
| if (m_windowSamples < 0) |
| m_windowSamples = 0; |
| |
| connect(window, &QQuickWindow::beforeSynchronizing, |
| this, &AbstractDeclarative::synchDataToRenderer, |
| Qt::DirectConnection); |
| |
| if (m_renderMode == RenderDirectToBackground_NoClear |
| || m_renderMode == RenderDirectToBackground) { |
| connect(window, &QQuickWindow::beforeRendering, this, &AbstractDeclarative::render, |
| Qt::DirectConnection); |
| setAntialiasing(m_windowSamples > 0); |
| if (m_windowSamples != oldWindowSamples) |
| emit msaaSamplesChanged(m_windowSamples); |
| } |
| |
| connect(m_controller.data(), &Abstract3DController::needRender, window, &QQuickWindow::update); |
| |
| updateWindowParameters(); |
| |
| #if defined(Q_OS_IOS) |
| // Scenegraph render cycle in iOS sometimes misses update after beforeSynchronizing signal. |
| // This ensures we don't end up displaying the graph without any data, in case update is |
| // skipped after synchDataToRenderer. |
| QTimer::singleShot(0, window, SLOT(update())); |
| #endif |
| } |
| |
| void AbstractDeclarative::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) |
| { |
| QQuickItem::geometryChanged(newGeometry, oldGeometry); |
| |
| m_cachedGeometry = newGeometry; |
| |
| updateWindowParameters(); |
| } |
| |
| void AbstractDeclarative::itemChange(ItemChange change, const ItemChangeData & value) |
| { |
| QQuickItem::itemChange(change, value); |
| updateWindowParameters(); |
| } |
| |
| void AbstractDeclarative::updateWindowParameters() |
| { |
| const QMutexLocker locker(&m_mutex); |
| |
| // Update the device pixel ratio, window size and bounding box |
| QQuickWindow *win = window(); |
| if (win && !m_controller.isNull()) { |
| Q3DScene *scene = m_controller->scene(); |
| if (win->devicePixelRatio() != scene->devicePixelRatio()) { |
| scene->setDevicePixelRatio(win->devicePixelRatio()); |
| win->update(); |
| } |
| |
| bool directRender = m_renderMode == RenderDirectToBackground |
| || m_renderMode == RenderDirectToBackground_NoClear; |
| QSize windowSize; |
| |
| if (directRender) |
| windowSize = win->size(); |
| else |
| windowSize = m_cachedGeometry.size().toSize(); |
| |
| if (windowSize != scene->d_ptr->windowSize()) { |
| scene->d_ptr->setWindowSize(windowSize); |
| win->update(); |
| } |
| |
| if (directRender) { |
| // Origin mapping is needed when rendering directly to background |
| QPointF point = QQuickItem::mapToScene(QPointF(0.0, 0.0)); |
| scene->d_ptr->setViewport(QRect(point.x() + 0.5f, point.y() + 0.5f, |
| m_cachedGeometry.width() + 0.5f, |
| m_cachedGeometry.height() + 0.5f)); |
| } else { |
| // No translation needed when rendering to FBO |
| scene->d_ptr->setViewport(QRect(0.0, 0.0, m_cachedGeometry.width() + 0.5f, |
| m_cachedGeometry.height() + 0.5f)); |
| } |
| } |
| } |
| |
| void AbstractDeclarative::handleSelectionModeChange(QAbstract3DGraph::SelectionFlags mode) |
| { |
| int intmode = int(mode); |
| emit selectionModeChanged(SelectionFlags(intmode)); |
| } |
| |
| void AbstractDeclarative::handleShadowQualityChange(QAbstract3DGraph::ShadowQuality quality) |
| { |
| emit shadowQualityChanged(ShadowQuality(quality)); |
| } |
| |
| void AbstractDeclarative::handleSelectedElementChange(QAbstract3DGraph::ElementType type) |
| { |
| emit selectedElementChanged(ElementType(type)); |
| } |
| |
| void AbstractDeclarative::handleOptimizationHintChange(QAbstract3DGraph::OptimizationHints hints) |
| { |
| int intHints = int(hints); |
| emit optimizationHintsChanged(OptimizationHints(intHints)); |
| } |
| |
| void AbstractDeclarative::render() |
| { |
| updateWindowParameters(); |
| |
| // If we're not rendering directly to the background, return |
| if (m_renderMode != RenderDirectToBackground && m_renderMode != RenderDirectToBackground_NoClear) |
| return; |
| |
| // Clear the background once per window as that is not done by default |
| QQuickWindow *win = window(); |
| activateOpenGLContext(win); |
| QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); |
| if (m_renderMode == RenderDirectToBackground && !clearList.contains(win)) { |
| clearList.append(win); |
| QColor clearColor = win->color(); |
| funcs->glClearColor(clearColor.redF(), clearColor.greenF(), clearColor.blueF(), 1.0f); |
| funcs->glClear(GL_COLOR_BUFFER_BIT); |
| } |
| |
| if (isVisible()) { |
| funcs->glDepthMask(GL_TRUE); |
| funcs->glEnable(GL_DEPTH_TEST); |
| funcs->glDepthFunc(GL_LESS); |
| funcs->glEnable(GL_CULL_FACE); |
| funcs->glCullFace(GL_BACK); |
| funcs->glDisable(GL_BLEND); |
| |
| m_controller->render(); |
| |
| funcs->glEnable(GL_BLEND); |
| } |
| doneOpenGLContext(win); |
| } |
| |
| QAbstract3DInputHandler* AbstractDeclarative::inputHandler() const |
| { |
| return m_controller->activeInputHandler(); |
| } |
| |
| void AbstractDeclarative::setInputHandler(QAbstract3DInputHandler *inputHandler) |
| { |
| m_controller->setActiveInputHandler(inputHandler); |
| } |
| |
| void AbstractDeclarative::mouseDoubleClickEvent(QMouseEvent *event) |
| { |
| m_controller->mouseDoubleClickEvent(event); |
| } |
| |
| void AbstractDeclarative::touchEvent(QTouchEvent *event) |
| { |
| m_controller->touchEvent(event); |
| window()->update(); |
| } |
| |
| void AbstractDeclarative::mousePressEvent(QMouseEvent *event) |
| { |
| QPoint mousePos = event->pos(); |
| m_controller->mousePressEvent(event, mousePos); |
| } |
| |
| void AbstractDeclarative::mouseReleaseEvent(QMouseEvent *event) |
| { |
| QPoint mousePos = event->pos(); |
| m_controller->mouseReleaseEvent(event, mousePos); |
| } |
| |
| void AbstractDeclarative::mouseMoveEvent(QMouseEvent *event) |
| { |
| QPoint mousePos = event->pos(); |
| m_controller->mouseMoveEvent(event, mousePos); |
| } |
| |
| #if QT_CONFIG(wheelevent) |
| void AbstractDeclarative::wheelEvent(QWheelEvent *event) |
| { |
| m_controller->wheelEvent(event); |
| } |
| #endif |
| |
| void AbstractDeclarative::checkWindowList(QQuickWindow *window) |
| { |
| QQuickWindow *oldWindow = graphWindowList.value(this); |
| |
| graphWindowList[this] = window; |
| |
| if (oldWindow != window && oldWindow) { |
| QObject::disconnect(oldWindow, &QObject::destroyed, this, |
| &AbstractDeclarative::windowDestroyed); |
| QObject::disconnect(oldWindow, &QQuickWindow::beforeSynchronizing, this, |
| &AbstractDeclarative::synchDataToRenderer); |
| QObject::disconnect(oldWindow, &QQuickWindow::beforeRendering, this, |
| &AbstractDeclarative::render); |
| if (!m_controller.isNull()) { |
| QObject::disconnect(m_controller.data(), &Abstract3DController::needRender, |
| oldWindow, &QQuickWindow::update); |
| } |
| } |
| |
| QList<QQuickWindow *> windowList; |
| |
| foreach (AbstractDeclarative *graph, graphWindowList.keys()) { |
| if (graph->m_renderMode == RenderDirectToBackground |
| || graph->m_renderMode == RenderDirectToBackground_NoClear) { |
| windowList.append(graphWindowList.value(graph)); |
| } |
| } |
| |
| if (oldWindow && !windowList.contains(oldWindow) |
| && windowClearList.contains(oldWindow)) { |
| // Return window clear value |
| oldWindow->setClearBeforeRendering(windowClearList.value(oldWindow)); |
| windowClearList.remove(oldWindow); |
| } |
| |
| if (!window) { |
| graphWindowList.remove(this); |
| return; |
| } |
| |
| if ((m_renderMode == RenderDirectToBackground |
| || m_renderMode == RenderDirectToBackground_NoClear) |
| && !windowClearList.contains(window)) { |
| // Save old clear value |
| windowClearList[window] = window->clearBeforeRendering(); |
| // Disable clearing of the window as we render underneath |
| window->setClearBeforeRendering(false); |
| } |
| } |
| |
| void AbstractDeclarative::setMeasureFps(bool enable) |
| { |
| m_controller->setMeasureFps(enable); |
| } |
| |
| bool AbstractDeclarative::measureFps() const |
| { |
| return m_controller->measureFps(); |
| } |
| |
| qreal AbstractDeclarative::currentFps() const |
| { |
| return m_controller->currentFps(); |
| } |
| |
| void AbstractDeclarative::setOrthoProjection(bool enable) |
| { |
| m_controller->setOrthoProjection(enable); |
| } |
| |
| bool AbstractDeclarative::isOrthoProjection() const |
| { |
| return m_controller->isOrthoProjection(); |
| } |
| |
| AbstractDeclarative::ElementType AbstractDeclarative::selectedElement() const |
| { |
| return ElementType(m_controller->selectedElement()); |
| } |
| |
| void AbstractDeclarative::setAspectRatio(qreal ratio) |
| { |
| m_controller->setAspectRatio(ratio); |
| } |
| |
| qreal AbstractDeclarative::aspectRatio() const |
| { |
| return m_controller->aspectRatio(); |
| } |
| |
| void AbstractDeclarative::setOptimizationHints(OptimizationHints hints) |
| { |
| int intmode = int(hints); |
| m_controller->setOptimizationHints(QAbstract3DGraph::OptimizationHints(intmode)); |
| } |
| |
| AbstractDeclarative::OptimizationHints AbstractDeclarative::optimizationHints() const |
| { |
| int intmode = int(m_controller->optimizationHints()); |
| return OptimizationHints(intmode); |
| } |
| |
| void AbstractDeclarative::setPolar(bool enable) |
| { |
| m_controller->setPolar(enable); |
| } |
| |
| bool AbstractDeclarative::isPolar() const |
| { |
| return m_controller->isPolar(); |
| } |
| |
| void AbstractDeclarative::setRadialLabelOffset(float offset) |
| { |
| m_controller->setRadialLabelOffset(offset); |
| } |
| |
| float AbstractDeclarative::radialLabelOffset() const |
| { |
| return m_controller->radialLabelOffset(); |
| } |
| |
| void AbstractDeclarative::setHorizontalAspectRatio(qreal ratio) |
| { |
| m_controller->setHorizontalAspectRatio(ratio); |
| } |
| |
| qreal AbstractDeclarative::horizontalAspectRatio() const |
| { |
| return m_controller->horizontalAspectRatio(); |
| } |
| |
| void AbstractDeclarative::setReflection(bool enable) |
| { |
| m_controller->setReflection(enable); |
| } |
| |
| bool AbstractDeclarative::isReflection() const |
| { |
| return m_controller->reflection(); |
| } |
| |
| void AbstractDeclarative::setReflectivity(qreal reflectivity) |
| { |
| m_controller->setReflectivity(reflectivity); |
| } |
| |
| qreal AbstractDeclarative::reflectivity() const |
| { |
| return m_controller->reflectivity(); |
| } |
| |
| void AbstractDeclarative::setLocale(const QLocale &locale) |
| { |
| m_controller->setLocale(locale); |
| } |
| |
| QLocale AbstractDeclarative::locale() const |
| { |
| return m_controller->locale(); |
| } |
| |
| QVector3D AbstractDeclarative::queriedGraphPosition() const |
| { |
| return m_controller->queriedGraphPosition(); |
| } |
| |
| void AbstractDeclarative::setMargin(qreal margin) |
| { |
| m_controller->setMargin(margin); |
| } |
| |
| qreal AbstractDeclarative::margin() const |
| { |
| return m_controller->margin(); |
| } |
| |
| void AbstractDeclarative::windowDestroyed(QObject *obj) |
| { |
| // Remove destroyed window from window lists |
| QQuickWindow *win = static_cast<QQuickWindow *>(obj); |
| QQuickWindow *oldWindow = graphWindowList.value(this); |
| |
| if (win == oldWindow) |
| graphWindowList.remove(this); |
| |
| windowClearList.remove(win); |
| } |
| |
| void AbstractDeclarative::destroyContext() |
| { |
| if (m_contextThread && m_contextThread != m_mainThread) { |
| if (m_contextOrStateStore) |
| m_contextOrStateStore->deleteLater(); |
| } else { |
| delete m_contextOrStateStore; |
| } |
| m_contextOrStateStore = 0; |
| |
| if (m_contextThread) { |
| QObject::disconnect(m_contextThread, &QThread::finished, this, |
| &AbstractDeclarative::destroyContext); |
| m_contextThread = 0; |
| } |
| } |
| |
| QT_END_NAMESPACE_DATAVISUALIZATION |