/**************************************************************************** ** ** Copyright (C) 2013 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 "abstract3dcontroller_p.h" #include "camerahelper_p.h" #include "q3dabstractaxis_p.h" #include "q3dvalueaxis.h" #include "q3dcategoryaxis.h" #include "abstract3drenderer_p.h" #include "q3dcamera.h" #include "q3dlight.h" #include "qabstractdataproxy_p.h" #include "qabstract3dinputhandler_p.h" #if defined(Q_OS_ANDROID) #include "qtouch3dinputhandler.h" #else #include "q3dinputhandler.h" #endif #include QT_DATAVISUALIZATION_BEGIN_NAMESPACE Abstract3DController::Abstract3DController(QRect boundRect, QObject *parent) : QObject(parent), m_boundingRect(boundRect.x(), boundRect.y(), boundRect.width(), boundRect.height()), m_horizontalRotation(-45.0f), m_verticalRotation(15.0f), m_theme(), m_font(QFont(QStringLiteral("Arial"))), m_selectionMode(QDataVis::ModeItem), m_shadowQuality(QDataVis::ShadowMedium), m_labelTransparency(QDataVis::TransparencyNoBackground), m_isBackgroundEnabled(true), m_isGridEnabled(true), m_scene(new Q3DScene()), m_activeInputHandler(0), m_axisX(0), m_axisY(0), m_axisZ(0), m_renderer(0), m_isDataDirty(true), m_data(0), m_renderPending(false) { m_theme.useColorTheme(QDataVis::ThemeSystem); // Populate the scene m_scene->light()->setPosition(defaultLightPos); // Create initial default input handler QAbstract3DInputHandler *inputHandler; #if defined(Q_OS_ANDROID) inputHandler = new QTouch3DInputHandler(); #else inputHandler = new Q3DInputHandler(); #endif inputHandler->d_ptr->m_isDefaultHandler = true; setActiveInputHandler(inputHandler); } Abstract3DController::~Abstract3DController() { // Renderer can be in another thread, don't delete it directly in that case if (m_renderer && m_renderer->thread() != QThread::currentThread()) m_renderer->deleteLater(); else delete m_renderer; delete m_scene; } void Abstract3DController::setRenderer(Abstract3DRenderer *renderer) { m_renderer = renderer; } void Abstract3DController::synchDataToRenderer() { // If we don't have a renderer, don't do anything if (!m_renderer) return; m_renderer->updateScene(m_scene); if (m_changeTracker.positionChanged) { m_renderer->updatePosition(m_boundingRect); m_changeTracker.positionChanged = false; } if (m_changeTracker.themeChanged) { m_renderer->updateTheme(m_theme); m_changeTracker.themeChanged = false; } if (m_changeTracker.fontChanged) { m_renderer->updateFont(m_font); m_changeTracker.fontChanged = false; } if (m_changeTracker.labelTransparencyChanged) { m_renderer->updateLabelTransparency(m_labelTransparency); m_changeTracker.labelTransparencyChanged = false; } if (m_changeTracker.boundingRectChanged || m_changeTracker.sizeChanged) { m_renderer->updateBoundingRect(m_boundingRect); m_changeTracker.boundingRectChanged = false; m_changeTracker.sizeChanged = false; } if (m_changeTracker.shadowQualityChanged) { m_renderer->updateShadowQuality(m_shadowQuality); m_changeTracker.shadowQualityChanged = false; } if (m_changeTracker.selectionModeChanged) { m_renderer->updateSelectionMode(m_selectionMode); m_changeTracker.selectionModeChanged = false; } if (m_changeTracker.objFileChanged) { m_renderer->updateMeshFileName(m_objFile); m_changeTracker.objFileChanged = false; } if (m_changeTracker.gridEnabledChanged) { m_renderer->updateGridEnabled(m_isGridEnabled); m_changeTracker.gridEnabledChanged = false; } if (m_changeTracker.backgroundEnabledChanged) { m_renderer->updateBackgroundEnabled(m_isBackgroundEnabled); m_changeTracker.backgroundEnabledChanged = false; } if (m_changeTracker.axisXTypeChanged) { m_renderer->updateAxisType(Q3DAbstractAxis::AxisOrientationX, m_axisX->type()); m_changeTracker.axisXTypeChanged = false; } if (m_changeTracker.axisYTypeChanged) { m_renderer->updateAxisType(Q3DAbstractAxis::AxisOrientationY, m_axisY->type()); m_changeTracker.axisYTypeChanged = false; } if (m_changeTracker.axisZTypeChanged) { m_renderer->updateAxisType(Q3DAbstractAxis::AxisOrientationZ, m_axisZ->type()); m_changeTracker.axisZTypeChanged = false; } if (m_changeTracker.axisXTitleChanged) { m_renderer->updateAxisTitle(Q3DAbstractAxis::AxisOrientationX, m_axisX->title()); m_changeTracker.axisXTitleChanged = false; } if (m_changeTracker.axisYTitleChanged) { m_renderer->updateAxisTitle(Q3DAbstractAxis::AxisOrientationY, m_axisY->title()); m_changeTracker.axisYTitleChanged = false; } if (m_changeTracker.axisZTitleChanged) { m_renderer->updateAxisTitle(Q3DAbstractAxis::AxisOrientationZ, m_axisZ->title()); m_changeTracker.axisZTitleChanged = false; } if (m_changeTracker.axisXLabelsChanged) { m_renderer->updateAxisLabels(Q3DAbstractAxis::AxisOrientationX, m_axisX->labels()); m_changeTracker.axisXLabelsChanged = false; } if (m_changeTracker.axisYLabelsChanged) { m_renderer->updateAxisLabels(Q3DAbstractAxis::AxisOrientationY, m_axisY->labels()); m_changeTracker.axisYLabelsChanged = false; } if (m_changeTracker.axisZLabelsChanged) { m_renderer->updateAxisLabels(Q3DAbstractAxis::AxisOrientationZ, m_axisZ->labels()); m_changeTracker.axisZLabelsChanged = false; } if (m_changeTracker.axisXRangeChanged) { m_changeTracker.axisXRangeChanged = false; if (m_axisX->type() & Q3DAbstractAxis::AxisTypeValue) { Q3DValueAxis *valueAxisX = static_cast(m_axisX); m_renderer->updateAxisRange(Q3DAbstractAxis::AxisOrientationX, valueAxisX->min(), valueAxisX->max()); } } if (m_changeTracker.axisYRangeChanged) { m_changeTracker.axisYRangeChanged = false; if (m_axisY->type() & Q3DAbstractAxis::AxisTypeValue) { Q3DValueAxis *valueAxisY = static_cast(m_axisY); m_renderer->updateAxisRange(Q3DAbstractAxis::AxisOrientationY, valueAxisY->min(), valueAxisY->max()); } } if (m_changeTracker.axisZRangeChanged) { m_changeTracker.axisZRangeChanged = false; if (m_axisZ->type() & Q3DAbstractAxis::AxisTypeValue) { Q3DValueAxis *valueAxisZ = static_cast(m_axisZ); m_renderer->updateAxisRange(Q3DAbstractAxis::AxisOrientationZ, valueAxisZ->min(), valueAxisZ->max()); } } if (m_changeTracker.axisXSegmentCountChanged) { m_changeTracker.axisXSegmentCountChanged = false; if (m_axisX->type() & Q3DAbstractAxis::AxisTypeValue) { Q3DValueAxis *valueAxisX = static_cast(m_axisX); m_renderer->updateAxisSegmentCount(Q3DAbstractAxis::AxisOrientationX, valueAxisX->segmentCount()); } } if (m_changeTracker.axisYSegmentCountChanged) { m_changeTracker.axisYSegmentCountChanged = false; if (m_axisY->type() & Q3DAbstractAxis::AxisTypeValue) { Q3DValueAxis *valueAxisY = static_cast(m_axisY); m_renderer->updateAxisSegmentCount(Q3DAbstractAxis::AxisOrientationY, valueAxisY->segmentCount()); } } if (m_changeTracker.axisZSegmentCountChanged) { m_changeTracker.axisZSegmentCountChanged = false; if (m_axisZ->type() & Q3DAbstractAxis::AxisTypeValue) { Q3DValueAxis *valueAxisZ = static_cast(m_axisZ); m_renderer->updateAxisSegmentCount(Q3DAbstractAxis::AxisOrientationZ, valueAxisZ->segmentCount()); } } if (m_changeTracker.axisXSubSegmentCountChanged) { m_changeTracker.axisXSubSegmentCountChanged = false; if (m_axisX->type() & Q3DAbstractAxis::AxisTypeValue) { Q3DValueAxis *valueAxisX = static_cast(m_axisX); m_renderer->updateAxisSubSegmentCount(Q3DAbstractAxis::AxisOrientationX, valueAxisX->subSegmentCount()); } } if (m_changeTracker.axisYSubSegmentCountChanged) { m_changeTracker.axisYSubSegmentCountChanged = false; if (m_axisY->type() & Q3DAbstractAxis::AxisTypeValue) { Q3DValueAxis *valueAxisY = static_cast(m_axisY); m_renderer->updateAxisSubSegmentCount(Q3DAbstractAxis::AxisOrientationY, valueAxisY->subSegmentCount()); } } if (m_changeTracker.axisZSubSegmentCountChanged) { m_changeTracker.axisZSubSegmentCountChanged = false; if (m_axisZ->type() & Q3DAbstractAxis::AxisTypeValue) { Q3DValueAxis *valueAxisZ = static_cast(m_axisZ); m_renderer->updateAxisSubSegmentCount(Q3DAbstractAxis::AxisOrientationZ, valueAxisZ->subSegmentCount()); } } if (m_changeTracker.axisXLabelFormatChanged) { m_changeTracker.axisXLabelFormatChanged = false; if (m_axisX->type() & Q3DAbstractAxis::AxisTypeValue) { Q3DValueAxis *valueAxisX = static_cast(m_axisX); m_renderer->updateAxisLabelFormat(Q3DAbstractAxis::AxisOrientationX, valueAxisX->labelFormat()); } } if (m_changeTracker.axisYLabelFormatChanged) { m_changeTracker.axisYLabelFormatChanged = false; if (m_axisY->type() & Q3DAbstractAxis::AxisTypeValue) { Q3DValueAxis *valueAxisY = static_cast(m_axisY); m_renderer->updateAxisLabelFormat(Q3DAbstractAxis::AxisOrientationY, valueAxisY->labelFormat()); } } if (m_changeTracker.axisZLabelFormatChanged) { m_changeTracker.axisZLabelFormatChanged = false; if (m_axisZ->type() & Q3DAbstractAxis::AxisTypeValue) { Q3DValueAxis *valueAxisZ = static_cast(m_axisZ); m_renderer->updateAxisLabelFormat(Q3DAbstractAxis::AxisOrientationZ, valueAxisZ->labelFormat()); } } } void Abstract3DController::render(const GLuint defaultFboHandle) { m_renderPending = false; // If not initialized, do nothing. if (!m_renderer) return; m_renderer->render(defaultFboHandle); #ifdef DISPLAY_RENDER_SPEED // To get meaningful framerate, don't just do render on demand. emitNeedRender(); #endif } void Abstract3DController::mouseDoubleClickEvent(QMouseEvent *event) { m_activeInputHandler->mouseDoubleClickEvent(event); emitNeedRender(); } void Abstract3DController::touchEvent(QTouchEvent *event) { m_activeInputHandler->touchEvent(event); emitNeedRender(); } void Abstract3DController::mousePressEvent(QMouseEvent *event, const QPoint &mousePos) { m_activeInputHandler->mousePressEvent(event, mousePos); emitNeedRender(); } void Abstract3DController::mouseReleaseEvent(QMouseEvent *event, const QPoint &mousePos) { m_activeInputHandler->mouseReleaseEvent(event, mousePos); emitNeedRender(); } void Abstract3DController::mouseMoveEvent(QMouseEvent *event, const QPoint &mousePos) { m_activeInputHandler->mouseMoveEvent(event, mousePos); emitNeedRender(); } void Abstract3DController::wheelEvent(QWheelEvent *event) { m_activeInputHandler->wheelEvent(event); emitNeedRender(); } void Abstract3DController::setSize(const int width, const int height) { m_boundingRect.setWidth(width); m_boundingRect.setHeight(height); m_scene->setViewportSize(width, height); m_changeTracker.boundingRectChanged = true; emitNeedRender(); } const QSize Abstract3DController::size() { return m_boundingRect.size(); } const QRect Abstract3DController::boundingRect() { return m_boundingRect; } void Abstract3DController::setBoundingRect(const QRect boundingRect) { m_boundingRect = boundingRect; m_scene->setViewport(boundingRect); m_changeTracker.boundingRectChanged = true; emitNeedRender(); } void Abstract3DController::setWidth(const int width) { m_boundingRect.setWidth(width); m_scene->setViewportSize(width, m_scene->viewport().height()); m_changeTracker.sizeChanged = true; emitNeedRender(); } int Abstract3DController::width() { return m_boundingRect.width(); } void Abstract3DController::setHeight(const int height) { m_boundingRect.setHeight(height); m_scene->setViewportSize(m_scene->viewport().width(), height); m_changeTracker.sizeChanged = true; emitNeedRender(); } int Abstract3DController::height() { return m_boundingRect.height(); } void Abstract3DController::setX(const int x) { m_boundingRect.setX(x); m_changeTracker.positionChanged = true; emitNeedRender(); } int Abstract3DController::x() { return m_boundingRect.x(); } void Abstract3DController::setY(const int y) { m_boundingRect.setY(y); m_changeTracker.positionChanged = true; emitNeedRender(); } int Abstract3DController::y() { return m_boundingRect.y(); } QRect Abstract3DController::mainViewport() const { return m_scene->mainViewport(); } void Abstract3DController::setMainViewport(const QRect &mainViewport) { m_scene->setMainViewport(mainViewport); } QRect Abstract3DController::sliceViewport() const { return m_scene->sliceViewport(); } void Abstract3DController::setSliceViewport(const QRect &sliceViewport) { m_scene->setSliceViewport(sliceViewport); } void Abstract3DController::setAxisX(Q3DAbstractAxis *axis) { setAxisHelper(Q3DAbstractAxis::AxisOrientationX, axis, &m_axisX); } Q3DAbstractAxis *Abstract3DController::axisX() { return m_axisX; } void Abstract3DController::setAxisY(Q3DAbstractAxis *axis) { setAxisHelper(Q3DAbstractAxis::AxisOrientationY, axis, &m_axisY); } Q3DAbstractAxis *Abstract3DController::axisY() { return m_axisY; } void Abstract3DController::setAxisZ(Q3DAbstractAxis *axis) { setAxisHelper(Q3DAbstractAxis::AxisOrientationZ, axis, &m_axisZ); } Q3DAbstractAxis *Abstract3DController::axisZ() { return m_axisZ; } void Abstract3DController::addAxis(Q3DAbstractAxis *axis) { Q_ASSERT(axis); Abstract3DController *owner = qobject_cast(axis->parent()); if (owner != this) { Q_ASSERT_X(!owner, "addAxis", "Axis already attached to a graph."); axis->setParent(this); } if (!m_axes.contains(axis)) m_axes.append(axis); } void Abstract3DController::releaseAxis(Q3DAbstractAxis *axis) { if (axis && m_axes.contains(axis)) { // Clear the default status from released default axes if (axis->d_ptr->isDefaultAxis()) axis->d_ptr->setDefaultAxis(false); // If the axis is in use, replace it with a temporary one switch (axis->orientation()) { case Q3DAbstractAxis::AxisOrientationX: setAxisX(0); break; case Q3DAbstractAxis::AxisOrientationY: setAxisY(0); break; case Q3DAbstractAxis::AxisOrientationZ: setAxisZ(0); break; default: break; } m_axes.removeAll(axis); axis->setParent(0); } } QList Abstract3DController::axes() const { return m_axes; } QAbstractDataProxy *Abstract3DController::activeDataProxy() const { return m_data; } void Abstract3DController::addDataProxy(QAbstractDataProxy *proxy) { Q_ASSERT(proxy); Abstract3DController *owner = qobject_cast(proxy->parent()); if (owner != this) { Q_ASSERT_X(!owner, "addDataProxy", "Proxy already attached to a graph."); proxy->setParent(this); } if (!m_dataProxies.contains(proxy)) m_dataProxies.append(proxy); } void Abstract3DController::releaseDataProxy(QAbstractDataProxy *proxy) { if (proxy && m_dataProxies.contains(proxy)) { // Clear the default status from released default proxies if (proxy->d_ptr->isDefaultProxy()) proxy->d_ptr->setDefaultProxy(false); // If the proxy is in use, replace it with a temporary one if (m_data == proxy) setActiveDataProxy(0); m_dataProxies.removeAll(proxy); proxy->setParent(0); } } QList Abstract3DController::dataProxies() const { return m_dataProxies; } void Abstract3DController::setActiveDataProxy(QAbstractDataProxy *proxy) { // If existing proxy is the default proxy, delete it if (m_data) { if (m_data->d_ptr->isDefaultProxy()) { m_dataProxies.removeAll(m_data); delete m_data; } else { // Disconnect the old proxy from use QObject::disconnect(m_data, 0, this, 0); } } // Assume ownership and activate addDataProxy(proxy); m_data = proxy; m_isDataDirty = true; emitNeedRender(); } void Abstract3DController::addInputHandler(QAbstract3DInputHandler *inputHandler) { Q_ASSERT(inputHandler); Abstract3DController *owner = qobject_cast(inputHandler->parent()); if (owner != this) { Q_ASSERT_X(!owner, "addInputHandler", "Input handler already attached to another component."); inputHandler->setParent(this); } if (!m_inputHandlers.contains(inputHandler)) m_inputHandlers.append(inputHandler); } void Abstract3DController::releaseInputHandler(QAbstract3DInputHandler *inputHandler) { if (inputHandler && m_inputHandlers.contains(inputHandler)) { // Clear the default status from released default input handler if (inputHandler->d_ptr->m_isDefaultHandler) inputHandler->d_ptr->m_isDefaultHandler = false; // If the input handler is in use, remove it if (m_activeInputHandler == inputHandler) setActiveInputHandler(0); m_inputHandlers.removeAll(inputHandler); inputHandler->setParent(0); } } void Abstract3DController::setActiveInputHandler(QAbstract3DInputHandler *inputHandler) { // If existing input handler is the default input handler, delete it if (m_activeInputHandler) { if (m_activeInputHandler->d_ptr->m_isDefaultHandler) { m_inputHandlers.removeAll(m_activeInputHandler); delete m_activeInputHandler; } else { // Disconnect the old input handler from the scene m_activeInputHandler->setScene(0); } } // Assume ownership and connect to this controller's scene addInputHandler(inputHandler); m_activeInputHandler = inputHandler; if (m_activeInputHandler) m_activeInputHandler->setScene(m_scene); } QAbstract3DInputHandler* Abstract3DController::activeInputHandler() { return m_activeInputHandler; } int Abstract3DController::zoomLevel() { return m_scene->camera()->zoomLevel(); } void Abstract3DController::setZoomLevel(int zoomLevel) { m_scene->camera()->setZoomLevel(zoomLevel); m_changeTracker.zoomLevelChanged = true; emitNeedRender(); } void Abstract3DController::setCameraPreset(QDataVis::CameraPreset preset) { m_scene->camera()->setCameraPreset(preset); emitNeedRender(); } QDataVis::CameraPreset Abstract3DController::cameraPreset() const { return m_scene->camera()->cameraPreset(); } void Abstract3DController::setCameraPosition(GLfloat horizontal, GLfloat vertical, GLint distance) { m_horizontalRotation = qBound(-180.0f, horizontal, 180.0f); m_verticalRotation = qBound(0.0f, vertical, 90.0f); m_scene->camera()->setZoomLevel(qBound(10, distance, 500)); m_scene->camera()->setRotations(QPointF(m_horizontalRotation, m_verticalRotation)); //qDebug() << "camera rotation set to" << m_horizontalRotation << m_verticalRotation; emitNeedRender(); } void Abstract3DController::setObjectColor(const QColor &baseColor, bool uniform) { m_theme.m_baseColor = baseColor; m_theme.m_uniformColor = uniform; m_changeTracker.themeChanged = true; emitNeedRender(); } QColor Abstract3DController::objectColor() const { return m_theme.m_baseColor; } void Abstract3DController::setColorTheme(QDataVis::ColorTheme colorTheme) { m_theme.useColorTheme(colorTheme); m_changeTracker.themeChanged = true; emitNeedRender(); } Theme Abstract3DController::theme() { return m_theme; } void Abstract3DController::setFont(const QFont &font) { m_font = font; m_changeTracker.fontChanged = true; emitNeedRender(); } QFont Abstract3DController::font() { return m_font; } void Abstract3DController::setSelectionMode(QDataVis::SelectionMode mode) { m_selectionMode = mode; m_changeTracker.selectionModeChanged = true; emitNeedRender(); } QDataVis::SelectionMode Abstract3DController::selectionMode() { return m_selectionMode; } void Abstract3DController::setShadowQuality(QDataVis::ShadowQuality quality) { m_shadowQuality = quality; m_changeTracker.shadowQualityChanged = true; emit shadowQualityChanged(m_shadowQuality); emitNeedRender(); } QDataVis::ShadowQuality Abstract3DController::shadowQuality() { return m_shadowQuality; } void Abstract3DController::setLabelTransparency(QDataVis::LabelTransparency transparency) { m_labelTransparency = transparency; m_changeTracker.labelTransparencyChanged = true; emitNeedRender(); } QDataVis::LabelTransparency Abstract3DController::labelTransparency() { return m_labelTransparency; } void Abstract3DController::setBackgroundEnabled(bool enable) { m_isBackgroundEnabled = enable; m_changeTracker.backgroundEnabledChanged = true; emitNeedRender(); } bool Abstract3DController::backgroundEnabled() { return m_isBackgroundEnabled; } void Abstract3DController::setGridEnabled(bool enable) { m_isGridEnabled = enable; m_changeTracker.gridEnabledChanged = true; emitNeedRender(); } bool Abstract3DController::gridEnabled() { return m_isGridEnabled; } bool Abstract3DController::isSlicingActive() { return m_scene->isSlicingActivated(); } void Abstract3DController::setSlicingActive(bool isSlicing) { m_scene->setSlicingActivated(isSlicing); emitNeedRender(); } QDataVis::InputState Abstract3DController::inputState() { return m_activeInputHandler->inputState(); } QPoint Abstract3DController::inputPosition() { return m_activeInputHandler->inputPosition(); } void Abstract3DController::setMeshFileName(const QString &fileName) { m_objFile = fileName; m_changeTracker.objFileChanged = true; emitNeedRender(); } QString Abstract3DController::meshFileName() { return m_objFile; } Q3DScene *Abstract3DController::scene() { return m_scene; } void Abstract3DController::handleAxisTitleChanged(const QString &title) { Q_UNUSED(title) handleAxisTitleChangedBySender(sender()); } void Abstract3DController::handleAxisTitleChangedBySender(QObject *sender) { if (sender == m_axisX) m_changeTracker.axisXTitleChanged = true; else if (sender == m_axisY) m_changeTracker.axisYTitleChanged = true; else if (sender == m_axisZ) m_changeTracker.axisZTitleChanged = true; else qWarning() << __FUNCTION__ << "invoked for invalid axis"; emitNeedRender(); } void Abstract3DController::handleAxisLabelsChanged() { handleAxisLabelsChangedBySender(sender()); } void Abstract3DController::handleAxisLabelsChangedBySender(QObject *sender) { if (sender == m_axisX) m_changeTracker.axisXLabelsChanged = true; else if (sender == m_axisY) m_changeTracker.axisYLabelsChanged = true; else if (sender == m_axisZ) m_changeTracker.axisZLabelsChanged = true; else qWarning() << __FUNCTION__ << "invoked for invalid axis"; emitNeedRender(); } void Abstract3DController::handleAxisRangeChanged(qreal min, qreal max) { Q_UNUSED(min) Q_UNUSED(max) handleAxisRangeChangedBySender(sender()); } void Abstract3DController::handleAxisRangeChangedBySender(QObject *sender) { if (sender == m_axisX) { m_isDataDirty = true; m_changeTracker.axisXRangeChanged = true; } else if (sender == m_axisY) { m_isDataDirty = true; m_changeTracker.axisYRangeChanged = true; } else if (sender == m_axisZ) { m_isDataDirty = true; m_changeTracker.axisZRangeChanged = true; } else { qWarning() << __FUNCTION__ << "invoked for invalid axis"; } emitNeedRender(); } void Abstract3DController::handleAxisSegmentCountChanged(int count) { Q_UNUSED(count) handleAxisSegmentCountChangedBySender(sender()); } void Abstract3DController::handleAxisSegmentCountChangedBySender(QObject *sender) { if (sender == m_axisX) m_changeTracker.axisXSegmentCountChanged = true; else if (sender == m_axisY) m_changeTracker.axisYSegmentCountChanged = true; else if (sender == m_axisZ) m_changeTracker.axisZSegmentCountChanged = true; else qWarning() << __FUNCTION__ << "invoked for invalid axis"; emitNeedRender(); } void Abstract3DController::handleAxisSubSegmentCountChanged(int count) { Q_UNUSED(count) handleAxisSubSegmentCountChangedBySender(sender()); } void Abstract3DController::handleAxisSubSegmentCountChangedBySender(QObject *sender) { if (sender == m_axisX) m_changeTracker.axisXSubSegmentCountChanged = true; else if (sender == m_axisY) m_changeTracker.axisYSubSegmentCountChanged = true; else if (sender == m_axisZ) m_changeTracker.axisZSubSegmentCountChanged = true; else qWarning() << __FUNCTION__ << "invoked for invalid axis"; emitNeedRender(); } void Abstract3DController::handleAxisAutoAdjustRangeChanged(bool autoAdjust) { QObject *sender = QObject::sender(); if (sender != m_axisX && sender != m_axisY && sender != m_axisZ) return; Q3DAbstractAxis *axis = static_cast(sender); handleAxisAutoAdjustRangeChangedInOrientation(axis->orientation(), autoAdjust); } void Abstract3DController::handleAxisLabelFormatChanged(const QString &format) { Q_UNUSED(format) handleAxisLabelFormatChangedBySender(sender()); } void Abstract3DController::handleAxisLabelFormatChangedBySender(QObject *sender) { // Label format changing needs to dirty the data so that labels are reset. if (sender == m_axisX) { m_isDataDirty = true; m_changeTracker.axisXLabelFormatChanged = true; } else if (sender == m_axisY) { m_isDataDirty = true; m_changeTracker.axisYLabelFormatChanged = true; } else if (sender == m_axisZ) { m_isDataDirty = true; m_changeTracker.axisZLabelFormatChanged = true; } else { qWarning() << __FUNCTION__ << "invoked for invalid axis"; } emitNeedRender(); } void Abstract3DController::setAxisHelper(Q3DAbstractAxis::AxisOrientation orientation, Q3DAbstractAxis *axis, Q3DAbstractAxis **axisPtr) { // Setting null axis indicates using default axis if (!axis) axis = createDefaultAxis(orientation); // If old axis is default axis, delete it Q3DAbstractAxis *oldAxis = *axisPtr; if (oldAxis) { if (oldAxis->d_ptr->isDefaultAxis()) { m_axes.removeAll(oldAxis); delete oldAxis; oldAxis = 0; } else { // Disconnect the old axis from use QObject::disconnect(oldAxis, 0, this, 0); oldAxis->d_ptr->setOrientation(Q3DAbstractAxis::AxisOrientationNone); } } // Assume ownership addAxis(axis); // Connect the new axis *axisPtr = axis; axis->d_ptr->setOrientation(orientation); QObject::connect(axis, &Q3DAbstractAxis::titleChanged, this, &Abstract3DController::handleAxisTitleChanged); QObject::connect(axis, &Q3DAbstractAxis::labelsChanged, this, &Abstract3DController::handleAxisLabelsChanged); if (orientation == Q3DAbstractAxis::AxisOrientationX) m_changeTracker.axisXTypeChanged = true; else if (orientation == Q3DAbstractAxis::AxisOrientationY) m_changeTracker.axisYTypeChanged = true; else if (orientation == Q3DAbstractAxis::AxisOrientationZ) m_changeTracker.axisZTypeChanged = true; handleAxisTitleChangedBySender(axis); handleAxisLabelsChangedBySender(axis); if (axis->type() & Q3DAbstractAxis::AxisTypeValue) { Q3DValueAxis *valueAxis = static_cast(axis); QObject::connect(valueAxis, &Q3DValueAxis::rangeChanged, this, &Abstract3DController::handleAxisRangeChanged); QObject::connect(valueAxis, &Q3DValueAxis::segmentCountChanged, this, &Abstract3DController::handleAxisSegmentCountChanged); QObject::connect(valueAxis, &Q3DValueAxis::subSegmentCountChanged, this, &Abstract3DController::handleAxisSubSegmentCountChanged); QObject::connect(valueAxis, &Q3DValueAxis::autoAdjustRangeChanged, this, &Abstract3DController::handleAxisAutoAdjustRangeChanged); QObject::connect(valueAxis, &Q3DValueAxis::labelFormatChanged, this, &Abstract3DController::handleAxisLabelFormatChanged); handleAxisRangeChangedBySender(valueAxis); handleAxisSegmentCountChangedBySender(valueAxis); handleAxisSubSegmentCountChangedBySender(valueAxis); handleAxisAutoAdjustRangeChangedInOrientation(valueAxis->orientation(), valueAxis->isAutoAdjustRange()); handleAxisLabelFormatChangedBySender(valueAxis); } } Q3DAbstractAxis *Abstract3DController::createDefaultAxis(Q3DAbstractAxis::AxisOrientation orientation) { Q_UNUSED(orientation) // The default default axis is a value axis. If the chart type has a different default axis // for some orientation, this function needs to be overridden. Q3DAbstractAxis *defaultAxis = createDefaultValueAxis(); return defaultAxis; } Q3DValueAxis *Abstract3DController::createDefaultValueAxis() { // Default value axis has single segment, empty label format, and auto scaling // TODO: Grid should be also hidden, but that is not currently controlled by axis Q3DValueAxis *defaultAxis = new Q3DValueAxis; defaultAxis->setSegmentCount(1); defaultAxis->setSubSegmentCount(1); defaultAxis->setAutoAdjustRange(true); defaultAxis->setLabelFormat(QString()); defaultAxis->d_ptr->setDefaultAxis(true); return defaultAxis; } Q3DCategoryAxis *Abstract3DController::createDefaultCategoryAxis() { // Default category axis has no labels // TODO: Grid should be also hidden, but that is not currently controlled by axis. Q3DCategoryAxis *defaultAxis = new Q3DCategoryAxis; defaultAxis->d_ptr->setDefaultAxis(true); return defaultAxis; } void Abstract3DController::emitNeedRender() { if (!m_renderPending) { emit needRender(); m_renderPending = true; } } QT_DATAVISUALIZATION_END_NAMESPACE