summaryrefslogtreecommitdiffstats
path: root/src/datavisualization/engine/qabstract3dgraph.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/datavisualization/engine/qabstract3dgraph.cpp')
-rw-r--r--src/datavisualization/engine/qabstract3dgraph.cpp512
1 files changed, 512 insertions, 0 deletions
diff --git a/src/datavisualization/engine/qabstract3dgraph.cpp b/src/datavisualization/engine/qabstract3dgraph.cpp
new file mode 100644
index 00000000..d8146149
--- /dev/null
+++ b/src/datavisualization/engine/qabstract3dgraph.cpp
@@ -0,0 +1,512 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "qabstract3dgraph.h"
+#include "qabstract3dgraph_p.h"
+#include "abstract3dcontroller_p.h"
+#include "qabstract3dinputhandler_p.h"
+#include "q3dscene_p.h"
+#include "qutils.h"
+
+#include <QGuiApplication>
+#include <QOpenGLContext>
+#include <QOpenGLPaintDevice>
+#include <QPainter>
+
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+/*!
+ * \class QAbstract3DGraph
+ * \inmodule QtDataVisualization
+ * \brief The QAbstract3DGraph class provides a window and render loop for graphs.
+ * \since Qt Data Visualization 1.0
+ *
+ * This class subclasses a QWindow and provides render loop for graphs inheriting it.
+ *
+ * You should not need to use this class directly, but one of its subclasses instead.
+ *
+ * Anti-aliasing is turned on by default on C++, except in OpenGL ES2
+ * environments, where anti-aliasing is not supported by Qt Data Visualization.
+ * To specify non-default anti-aliasing for a graph, give a custom surface format as
+ * a constructor parameter. You can use the convenience function \c QtDataVisualization::qDefaultSurfaceFormat()
+ * to create the surface format object.
+ *
+ * \note QAbstract3DGraph sets window flag \c Qt::FramelessWindowHint on by default. If you want to display
+ * graph windows as standalone windows with regular window frame, clear this flag after constructing
+ * the graph. For example:
+ *
+ * \code
+ * Q3DBars *graphWindow = new Q3DBars;
+ * graphWindow->setFlags(graphWindow->flags() ^ Qt::FramelessWindowHint);
+ * \endcode
+ *
+ * \sa Q3DBars, Q3DScatter, Q3DSurface, {Qt Data Visualization C++ Classes}
+ */
+
+/*!
+ \enum QAbstract3DGraph::SelectionFlag
+
+ Item selection modes. Values of this enumeration can be combined with OR operator.
+
+ \value SelectionNone
+ Selection mode disabled.
+ \value SelectionItem
+ Selection highlights a single item.
+ \value SelectionRow
+ Selection highlights a single row.
+ \value SelectionItemAndRow
+ Combination flag for highlighting both item and row with different colors.
+ \value SelectionColumn
+ Selection highlights a single column.
+ \value SelectionItemAndColumn
+ Combination flag for highlighting both item and column with different colors.
+ \value SelectionRowAndColumn
+ Combination flag for highlighting both row and column.
+ \value SelectionItemRowAndColumn
+ Combination flag for highlighting item, row, and column.
+ \value SelectionSlice
+ Setting this mode flag indicates that the graph should take care of the slice view handling
+ automatically. If you wish to control the slice view yourself via Q3DScene, do not set this
+ flag. When setting this mode flag, either \c SelectionRow or \c SelectionColumn must also
+ be set, but not both. Slicing is supported by Q3DBars and Q3DSurface only.
+ \value SelectionMultiSeries
+ Setting this mode means that items for all series at same position are highlighted, instead
+ of just the selected item. The actual selection in the other series doesn't change.
+ Multi-series selection is only supported for Q3DBars.
+*/
+
+/*!
+ \enum QAbstract3DGraph::ShadowQuality
+
+ Quality of shadows.
+
+ \value ShadowQualityNone
+ Shadows are disabled.
+ \value ShadowQualityLow
+ Shadows are rendered in low quality.
+ \value ShadowQualityMedium
+ Shadows are rendered in medium quality.
+ \value ShadowQualityHigh
+ Shadows are rendered in high quality.
+ \value ShadowQualitySoftLow
+ Shadows are rendered in low quality with softened edges.
+ \value ShadowQualitySoftMedium
+ Shadows are rendered in medium quality with softened edges.
+ \value ShadowQualitySoftHigh
+ Shadows are rendered in high quality with softened edges.
+*/
+
+/*!
+ * \internal
+ */
+QAbstract3DGraph::QAbstract3DGraph(QAbstract3DGraphPrivate *d, const QSurfaceFormat *format,
+ QWindow *parent)
+ : QWindow(parent),
+ d_ptr(d)
+{
+ qRegisterMetaType<QAbstract3DGraph::ShadowQuality>("QAbstract3DGraph::ShadowQuality");
+
+ // Default to frameless window, as typically graphs are not toplevel
+ setFlags(flags() | Qt::FramelessWindowHint);
+
+ QSurfaceFormat surfaceFormat;
+ if (format) {
+ surfaceFormat = *format;
+ // Make sure renderable type is correct
+#if !defined(QT_OPENGL_ES_2)
+ surfaceFormat.setRenderableType(QSurfaceFormat::OpenGL);
+#else
+ surfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES);
+#endif
+ } else {
+ surfaceFormat = qDefaultSurfaceFormat();
+ }
+
+ d_ptr->m_context = new QOpenGLContext(this);
+ setSurfaceType(QWindow::OpenGLSurface);
+ setFormat(surfaceFormat);
+
+ create();
+
+ d_ptr->m_context->setFormat(requestedFormat());
+ d_ptr->m_context->create();
+ d_ptr->m_context->makeCurrent(this);
+
+ initializeOpenGLFunctions();
+
+ const GLubyte *shaderVersion = glGetString(GL_SHADING_LANGUAGE_VERSION);
+#ifndef QT_NO_DEBUG
+ const GLubyte *openGLVersion = glGetString(GL_VERSION);
+ qDebug() << "OpenGL version:" << (const char *)openGLVersion;
+ qDebug() << "GLSL version:" << (const char *)shaderVersion;
+#endif
+
+#if !defined(QT_OPENGL_ES_2)
+ // If we have real OpenGL, GLSL version must be 1.2 or over. Quit if not.
+ QStringList splitversionstr = QString::fromLatin1((const char *)shaderVersion).split(QChar::fromLatin1(' '));
+ if (splitversionstr[0].toFloat() < 1.2)
+ qFatal("GLSL version must be 1.20 or higher. Try installing latest display drivers.");
+#else
+ Q_UNUSED(shaderVersion)
+#endif
+
+ d_ptr->renderLater();
+}
+
+/*!
+ * Destroys QAbstract3DGraph.
+ */
+QAbstract3DGraph::~QAbstract3DGraph()
+{
+}
+
+/*!
+ * Adds the given \a inputHandler to the graph. The input handlers added via addInputHandler
+ * are not taken in to use directly. Only the ownership of the \a inputHandler is given to the graph.
+ * The \a inputHandler must not be null or already added to another graph.
+ *
+ * \sa releaseInputHandler(), setActiveInputHandler()
+ */
+void QAbstract3DGraph::addInputHandler(QAbstract3DInputHandler *inputHandler)
+{
+ d_ptr->m_visualController->addInputHandler(inputHandler);
+}
+
+/*!
+ * Releases the ownership of the \a inputHandler back to the caller, if it was added to this graph.
+ * If the released \a inputHandler is in use there will be no input handler active after this call.
+ *
+ * If the default input handler is released and added back later, it behaves as any other input handler would.
+ *
+ * \sa addInputHandler(), setActiveInputHandler()
+ */
+void QAbstract3DGraph::releaseInputHandler(QAbstract3DInputHandler *inputHandler)
+{
+ d_ptr->m_visualController->releaseInputHandler(inputHandler);
+}
+
+/*!
+ * \property QAbstract3DGraph::activeInputHandler
+ *
+ * The active \a inputHandler used in the graph. Implicitly calls addInputHandler() to transfer
+ * ownership of the \a inputHandler to this graph.
+ *
+ * If the \a inputHandler is null, no input handler will be active after this call.
+ *
+ * \sa addInputHandler(), releaseInputHandler()
+ */
+void QAbstract3DGraph::setActiveInputHandler(QAbstract3DInputHandler *inputHandler)
+{
+ d_ptr->m_visualController->setActiveInputHandler(inputHandler);
+}
+
+QAbstract3DInputHandler *QAbstract3DGraph::activeInputHandler()
+{
+ return d_ptr->m_visualController->activeInputHandler();
+}
+
+/*!
+ * \return list of all added input handlers.
+ *
+ * \sa addInputHandler()
+ */
+QList<QAbstract3DInputHandler *> QAbstract3DGraph::inputHandlers() const
+{
+ return d_ptr->m_visualController->inputHandlers();
+}
+
+/*!
+ * Adds the given \a theme to the graph. The themes added via addTheme are not taken in to use
+ * directly. Only the ownership of the a\ theme is given to the graph.
+ * The \a theme must not be null or already added to another graph.
+ *
+ * \sa releaseTheme(), setActiveTheme()
+ */
+void QAbstract3DGraph::addTheme(Q3DTheme *theme)
+{
+ d_ptr->m_visualController->addTheme(theme);
+}
+
+/*!
+ * Releases the ownership of the \a theme back to the caller, if it was added to this graph.
+ * If the released \a theme is in use, a new default theme will be created and set active.
+ *
+ * If the default theme is released and added back later, it behaves as any other theme would.
+ *
+ * \sa addTheme(), setActiveTheme()
+ */
+void QAbstract3DGraph::releaseTheme(Q3DTheme *theme)
+{
+ d_ptr->m_visualController->releaseTheme(theme);
+}
+
+/*!
+ * \property QAbstract3DGraph::activeTheme
+ *
+ * The active \a theme to be used for the graph. Implicitly calls addTheme() to transfer ownership
+ * of the \a theme to this graph.
+ * If the \a theme is null, a temporary default theme is created. This temporary theme is destroyed
+ * if any theme is explicitly set later.
+ * Properties of the \a theme can be modified even after setting it, and the modifications take
+ * effect immediately.
+ */
+void QAbstract3DGraph::setActiveTheme(Q3DTheme *theme)
+{
+ d_ptr->m_visualController->setActiveTheme(theme);
+}
+
+
+Q3DTheme *QAbstract3DGraph::activeTheme() const
+{
+ return d_ptr->m_visualController->activeTheme();
+}
+
+/*!
+ * \return list of all added themes.
+ *
+ * \sa addTheme()
+ */
+QList<Q3DTheme *> QAbstract3DGraph::themes() const
+{
+ return d_ptr->m_visualController->themes();
+}
+
+/*!
+ * \property QAbstract3DGraph::selectionMode
+ *
+ * Sets selection \a mode to a combination of SelectionFlags. It is preset to
+ * \c SelectionItem by default.
+ * Different graph types support different selection modes. See SelectionFlags
+ * documentation for details.
+ */
+void QAbstract3DGraph::setSelectionMode(SelectionFlags mode)
+{
+ d_ptr->m_visualController->setSelectionMode(mode);
+}
+
+QAbstract3DGraph::SelectionFlags QAbstract3DGraph::selectionMode() const
+{
+ return d_ptr->m_visualController->selectionMode();
+}
+
+/*!
+ * \property QAbstract3DGraph::shadowQuality
+ *
+ * Sets shadow \a quality to one of ShadowQuality. It is preset to
+ * \c ShadowQualityMedium by default.
+ *
+ * \note If setting ShadowQuality of a certain level fails, a level is lowered
+ * until it is successful and shadowQualityChanged signal is emitted for each time the change is
+ * done.
+ */
+void QAbstract3DGraph::setShadowQuality(ShadowQuality quality)
+{
+ d_ptr->m_visualController->setShadowQuality(quality);
+}
+
+QAbstract3DGraph::ShadowQuality QAbstract3DGraph::shadowQuality() const
+{
+ return d_ptr->m_visualController->shadowQuality();
+}
+
+/*!
+ * \property QAbstract3DGraph::scene
+ *
+ * This property contains the read only Q3DScene that can be used to access for example a camera object.
+ */
+Q3DScene *QAbstract3DGraph::scene() const
+{
+ return d_ptr->m_visualController->scene();
+}
+
+/*!
+ * Clears selection from all attached series.
+ */
+void QAbstract3DGraph::clearSelection()
+{
+ d_ptr->m_visualController->clearSelection();
+}
+
+/*!
+ * \internal
+ */
+bool QAbstract3DGraph::event(QEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::UpdateRequest:
+ d_ptr->renderNow();
+ return true;
+ case QEvent::TouchBegin:
+ case QEvent::TouchCancel:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ d_ptr->m_visualController->touchEvent(static_cast<QTouchEvent *>(event));
+ return true;
+ default:
+ return QWindow::event(event);
+ }
+}
+
+/*!
+ * \internal
+ */
+void QAbstract3DGraph::resizeEvent(QResizeEvent *event)
+{
+ Q_UNUSED(event);
+
+ Q3DScene *scene = d_ptr->m_visualController->scene();
+ scene->d_ptr->setWindowSize(QSize(width(), height()));
+ scene->d_ptr->setViewport(QRect(0, 0, width(), height()));
+}
+
+/*!
+ * \internal
+ */
+void QAbstract3DGraph::exposeEvent(QExposeEvent *event)
+{
+ Q_UNUSED(event);
+
+ if (isExposed())
+ d_ptr->renderNow();
+}
+
+/*!
+ * \internal
+ */
+void QAbstract3DGraph::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ d_ptr->m_visualController->mouseDoubleClickEvent(event);
+}
+
+/*!
+ * \internal
+ */
+void QAbstract3DGraph::touchEvent(QTouchEvent *event)
+{
+ d_ptr->m_visualController->touchEvent(event);
+}
+
+/*!
+ * \internal
+ */
+void QAbstract3DGraph::mousePressEvent(QMouseEvent *event)
+{
+ d_ptr->m_visualController->mousePressEvent(event, event->pos());
+}
+
+/*!
+ * \internal
+ */
+void QAbstract3DGraph::mouseReleaseEvent(QMouseEvent *event)
+{
+ d_ptr->m_visualController->mouseReleaseEvent(event, event->pos());
+}
+
+/*!
+ * \internal
+ */
+void QAbstract3DGraph::mouseMoveEvent(QMouseEvent *event)
+{
+ d_ptr->m_visualController->mouseMoveEvent(event, event->pos());
+}
+
+/*!
+ * \internal
+ */
+void QAbstract3DGraph::wheelEvent(QWheelEvent *event)
+{
+ d_ptr->m_visualController->wheelEvent(event);
+}
+
+QAbstract3DGraphPrivate::QAbstract3DGraphPrivate(QAbstract3DGraph *q)
+ : QObject(0),
+ q_ptr(q),
+ m_updatePending(false),
+ m_visualController(0),
+ m_devicePixelRatio(1.f)
+{
+}
+
+QAbstract3DGraphPrivate::~QAbstract3DGraphPrivate()
+{
+ delete m_visualController;
+}
+
+void QAbstract3DGraphPrivate::setVisualController(Abstract3DController *controller)
+{
+ m_visualController = controller;
+
+ QObject::connect(m_visualController, &Abstract3DController::activeInputHandlerChanged, q_ptr,
+ &QAbstract3DGraph::activeInputHandlerChanged);
+ QObject::connect(m_visualController, &Abstract3DController::activeThemeChanged, q_ptr,
+ &QAbstract3DGraph::activeThemeChanged);
+ QObject::connect(m_visualController, &Abstract3DController::selectionModeChanged, q_ptr,
+ &QAbstract3DGraph::selectionModeChanged);
+ QObject::connect(m_visualController, &Abstract3DController::shadowQualityChanged, q_ptr,
+ &QAbstract3DGraph::shadowQualityChanged);
+ QObject::connect(m_visualController, &Abstract3DController::needRender, this,
+ &QAbstract3DGraphPrivate::renderLater);
+
+ QObject::connect(m_visualController, &Abstract3DController::axisXChanged, this,
+ &QAbstract3DGraphPrivate::handleAxisXChanged);
+ QObject::connect(m_visualController, &Abstract3DController::axisYChanged, this,
+ &QAbstract3DGraphPrivate::handleAxisYChanged);
+ QObject::connect(m_visualController, &Abstract3DController::axisZChanged, this,
+ &QAbstract3DGraphPrivate::handleAxisZChanged);
+}
+
+void QAbstract3DGraphPrivate::handleDevicePixelRatioChange()
+{
+ if (q_ptr->devicePixelRatio() == m_devicePixelRatio || !m_visualController)
+ return;
+
+ m_devicePixelRatio = q_ptr->devicePixelRatio();
+ m_visualController->scene()->setDevicePixelRatio(m_devicePixelRatio);
+}
+
+void QAbstract3DGraphPrivate::render()
+{
+ handleDevicePixelRatioChange();
+ m_visualController->synchDataToRenderer();
+ m_visualController->render();
+}
+
+void QAbstract3DGraphPrivate::renderLater()
+{
+ if (!m_updatePending) {
+ m_updatePending = true;
+ QCoreApplication::postEvent(q_ptr, new QEvent(QEvent::UpdateRequest));
+ }
+}
+
+void QAbstract3DGraphPrivate::renderNow()
+{
+ if (!q_ptr->isExposed())
+ return;
+
+ m_updatePending = false;
+
+ m_context->makeCurrent(q_ptr);
+
+ render();
+
+ m_context->swapBuffers(q_ptr);
+}
+
+QT_END_NAMESPACE_DATAVISUALIZATION