summaryrefslogtreecommitdiffstats
path: root/src/graphs/qml/qquickgraphsbars.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/graphs/qml/qquickgraphsbars.cpp')
-rw-r--r--src/graphs/qml/qquickgraphsbars.cpp1331
1 files changed, 1331 insertions, 0 deletions
diff --git a/src/graphs/qml/qquickgraphsbars.cpp b/src/graphs/qml/qquickgraphsbars.cpp
new file mode 100644
index 00000000..d358e6de
--- /dev/null
+++ b/src/graphs/qml/qquickgraphsbars.cpp
@@ -0,0 +1,1331 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qquickgraphsbars_p.h"
+#include "quickgraphstexturedata_p.h"
+#include "bars3dcontroller_p.h"
+#include "declarativescene_p.h"
+#include "qbar3dseries_p.h"
+#include "qvalue3daxis_p.h"
+#include "qcategory3daxis_p.h"
+#include "q3dcamera_p.h"
+#include <QtCore/QMutexLocker>
+#include <QColor>
+
+#include <QtQuick3D/private/qquick3drepeater_p.h>
+#include <QtQuick3D/private/qquick3dprincipledmaterial_p.h>
+#include "quickgraphstexturedata_p.h"
+#include <QtQuick3D/private/qquick3dcustommaterial_p.h>
+
+QQuickGraphsBars::QQuickGraphsBars(QQuickItem *parent)
+ : QQuickGraphsItem(parent),
+ m_barsController(0),
+ m_cachedRowCount(0),
+ m_cachedColumnCount(0),
+ m_minRow(0),
+ m_maxRow(0),
+ m_minCol(0),
+ m_maxCol(0),
+ m_newRows(0),
+ m_newCols(0),
+ m_maxSceneSize(40.0f),
+ m_rowWidth(0),
+ m_columnDepth(0),
+ m_maxDimension(0),
+ m_scaleFactor(0),
+ m_xScaleFactor(1.0f),
+ m_zScaleFactor(1.0f),
+ m_cachedBarSeriesMargin(0.0f, 0.0f),
+ m_hasNegativeValues(false),
+ m_noZeroInRange(false),
+ m_actualFloorLevel(0.0f),
+ m_heightNormalizer(1.0f),
+ m_backgroundAdjustment(0.0f),
+ m_selectedBarSeries(0),
+ m_selectedBarCoord(Bars3DController::invalidSelectionPosition()),
+ m_selectedBarPos(0.0f, 0.0f, 0.0f),
+ m_keepSeriesUniform(false),
+ m_seriesScaleX(0.0f),
+ m_seriesScaleZ(0.0f),
+ m_seriesStep(0.0f),
+ m_seriesStart(0.0f),
+ m_zeroPosition(0.0f),
+ m_visibleSeriesCount(0)
+{
+ setAcceptedMouseButtons(Qt::AllButtons);
+ setFlags(ItemHasContents);
+ // Create the shared component on the main GUI thread.
+ m_barsController = new Bars3DController(boundingRect().toRect(), new Declarative3DScene);
+ setSharedController(m_barsController);
+
+ QQuick3DSceneEnvironment *scene = environment();
+ scene->setBackgroundMode(QQuick3DSceneEnvironment::QQuick3DEnvironmentBackgroundTypes::Color);
+ scene->setClearColor(Qt::blue);
+
+ QObject::connect(m_barsController, &Bars3DController::primarySeriesChanged,
+ this, &QQuickGraphsBars::primarySeriesChanged);
+ QObject::connect(m_barsController, &Bars3DController::selectedSeriesChanged,
+ this, &QQuickGraphsBars::selectedSeriesChanged);
+ QObject::connect(m_barsController, &Abstract3DController::optimizationHintsChanged,
+ this, &QQuickGraphsBars::handleOptimizationHintsChanged);
+}
+
+QQuickGraphsBars::~QQuickGraphsBars()
+{
+ QMutexLocker locker(m_nodeMutex.data());
+ const QMutexLocker locker2(mutex());
+ delete m_barsController;
+ m_barModelsMap.clear();
+}
+
+QCategory3DAxis *QQuickGraphsBars::rowAxis() const
+{
+ return static_cast<QCategory3DAxis *>(m_barsController->axisZ());
+}
+
+void QQuickGraphsBars::setRowAxis(QCategory3DAxis *axis)
+{
+ m_barsController->setAxisZ(axis);
+}
+
+QValue3DAxis *QQuickGraphsBars::valueAxis() const
+{
+ return static_cast<QValue3DAxis *>(m_barsController->axisY());
+}
+
+void QQuickGraphsBars::setValueAxis(QValue3DAxis *axis)
+{
+ m_barsController->setAxisY(axis);
+ if (segmentLineRepeaterY()) {
+ int segmentCount = 0;
+ int subSegmentCount = 0;
+ int gridLineCount = 0;
+ int subGridLineCount = 0;
+ if (axis->type() & QAbstract3DAxis::AxisTypeValue) {
+ QValue3DAxis *valueAxis = static_cast<QValue3DAxis *>(axis);
+ segmentCount = valueAxis->segmentCount();
+ subSegmentCount = valueAxis->subSegmentCount();
+ gridLineCount = 2 * (segmentCount + 1);
+ subGridLineCount = 2 * (segmentCount * (subSegmentCount - 1));
+ } else if (axis->type() & QAbstract3DAxis::AxisTypeCategory) {
+ gridLineCount = axis->labels().size();
+ }
+ segmentLineRepeaterY()->setModel(gridLineCount);
+ subsegmentLineRepeaterY()->setModel(subGridLineCount);
+ repeaterY()->setModel(2 * axis->labels().size());
+ }
+}
+
+QCategory3DAxis *QQuickGraphsBars::columnAxis() const
+{
+ return static_cast<QCategory3DAxis *>(m_barsController->axisX());
+}
+
+void QQuickGraphsBars::setColumnAxis(QCategory3DAxis *axis)
+{
+ m_barsController->setAxisX(axis);
+}
+
+void QQuickGraphsBars::setMultiSeriesUniform(bool uniform)
+{
+ if (uniform != isMultiSeriesUniform()) {
+ m_barsController->setMultiSeriesScaling(uniform);
+ emit multiSeriesUniformChanged(uniform);
+ }
+}
+
+bool QQuickGraphsBars::isMultiSeriesUniform() const
+{
+ return m_barsController->multiSeriesScaling();
+}
+
+void QQuickGraphsBars::setBarThickness(float thicknessRatio)
+{
+ if (thicknessRatio != barThickness()) {
+ m_barsController->setBarSpecs(thicknessRatio, barSpacing(),
+ isBarSpacingRelative());
+ emit barThicknessChanged(thicknessRatio);
+ }
+}
+
+float QQuickGraphsBars::barThickness() const
+{
+ return m_barsController->barThickness();
+}
+
+void QQuickGraphsBars::setBarSpacing(const QSizeF &spacing)
+{
+ if (spacing != barSpacing()) {
+ m_barsController->setBarSpecs(barThickness(), spacing, isBarSpacingRelative());
+ emit barSpacingChanged(spacing);
+ }
+}
+
+QSizeF QQuickGraphsBars::barSpacing() const
+{
+ return m_barsController->barSpacing();
+}
+
+void QQuickGraphsBars::setBarSpacingRelative(bool relative)
+{
+ if (relative != isBarSpacingRelative()) {
+ m_barsController->setBarSpecs(barThickness(), barSpacing(), relative);
+ emit barSpacingRelativeChanged(relative);
+ }
+}
+
+bool QQuickGraphsBars::isBarSpacingRelative() const
+{
+ return m_barsController->isBarSpecRelative();
+}
+
+void QQuickGraphsBars::setBarSeriesMargin(const QSizeF &margin)
+{
+ if (margin != barSeriesMargin()) {
+ m_barsController->setBarSeriesMargin(margin);
+ emit barSeriesMarginChanged(barSeriesMargin());
+ }
+}
+
+QSizeF QQuickGraphsBars::barSeriesMargin() const
+{
+ return m_barsController->barSeriesMargin();
+}
+
+QQmlListProperty<QBar3DSeries> QQuickGraphsBars::seriesList()
+{
+ return QQmlListProperty<QBar3DSeries>(this, this,
+ &QQuickGraphsBars::appendSeriesFunc,
+ &QQuickGraphsBars::countSeriesFunc,
+ &QQuickGraphsBars::atSeriesFunc,
+ &QQuickGraphsBars::clearSeriesFunc);
+}
+
+void QQuickGraphsBars::appendSeriesFunc(QQmlListProperty<QBar3DSeries> *list, QBar3DSeries *series)
+{
+ reinterpret_cast<QQuickGraphsBars *>(list->data)->addSeries(series);
+}
+
+qsizetype QQuickGraphsBars::countSeriesFunc(QQmlListProperty<QBar3DSeries> *list)
+{
+ return reinterpret_cast<QQuickGraphsBars *>(list->data)->m_barsController->barSeriesList().size();
+}
+
+QBar3DSeries *QQuickGraphsBars::atSeriesFunc(QQmlListProperty<QBar3DSeries> *list, qsizetype index)
+{
+ return reinterpret_cast<QQuickGraphsBars *>(list->data)->m_barsController->barSeriesList().at(index);
+}
+
+void QQuickGraphsBars::clearSeriesFunc(QQmlListProperty<QBar3DSeries> *list)
+{
+ QQuickGraphsBars *declBars = reinterpret_cast<QQuickGraphsBars *>(list->data);
+ QList<QBar3DSeries *> realList = declBars->m_barsController->barSeriesList();
+ int count = realList.size();
+ for (int i = 0; i < count; i++)
+ declBars->removeSeries(realList.at(i));
+}
+
+void QQuickGraphsBars::addSeries(QBar3DSeries *series)
+{
+ m_barsController->addSeries(series);
+ connectSeries(series);
+ if (series->selectedBar() != invalidSelectionPosition())
+ updateSelectedBar();
+}
+
+void QQuickGraphsBars::removeSeries(QBar3DSeries *series)
+{
+ m_barsController->removeSeries(series);
+ series->setParent(this); // Reparent as removing will leave series parentless
+}
+
+void QQuickGraphsBars::insertSeries(int index, QBar3DSeries *series)
+{
+ m_barsController->insertSeries(index, series);
+}
+
+void QQuickGraphsBars::setPrimarySeries(QBar3DSeries *series)
+{
+ m_barsController->setPrimarySeries(series);
+}
+
+QBar3DSeries *QQuickGraphsBars::primarySeries() const
+{
+ return m_barsController->primarySeries();
+}
+
+QBar3DSeries *QQuickGraphsBars::selectedSeries() const
+{
+ return m_barsController->selectedSeries();
+}
+
+void QQuickGraphsBars::setFloorLevel(float level)
+{
+ if (level != floorLevel()) {
+ m_barsController->setFloorLevel(level);
+ emit floorLevelChanged(level);
+ }
+}
+
+float QQuickGraphsBars::floorLevel() const
+{
+ return m_barsController->floorLevel();
+}
+
+void QQuickGraphsBars::componentComplete()
+{
+ QQuickGraphsItem::componentComplete();
+
+ auto wallBackground = background();
+ QUrl wallUrl = QUrl(QStringLiteral("defaultMeshes/backgroundNoFloorMesh"));
+ wallBackground->setSource(wallUrl);
+ setBackground(wallBackground);
+
+ QUrl floorUrl = QUrl(QStringLiteral(":/defaultMeshes/planeMesh"));
+ m_floorBackground = new QQuick3DModel();
+ m_floorBackgroundScale = new QQuick3DNode();
+ m_floorBackgroundRotation = new QQuick3DNode();
+
+ m_floorBackgroundScale->setParent(rootNode());
+ m_floorBackgroundScale->setParentItem(rootNode());
+
+ m_floorBackgroundRotation->setParent(m_floorBackgroundScale);
+ m_floorBackgroundRotation->setParentItem(m_floorBackgroundScale);
+
+ m_floorBackground->setObjectName("Floor Background");
+ m_floorBackground->setParent(m_floorBackgroundRotation);
+ m_floorBackground->setParentItem(m_floorBackgroundRotation);
+
+ m_floorBackground->setSource(floorUrl);
+
+ QValue3DAxis *axisY = static_cast<QValue3DAxis *>(m_barsController->axisY());
+ m_helperAxisY.setFormatter(axisY->formatter());
+
+ setFloorGridInRange(true);
+ setVerticalSegmentLine(false);
+}
+
+void QQuickGraphsBars::synchData()
+{
+ if (!m_noZeroInRange) {
+ m_barsController->m_scene->activeCamera()->d_ptr->setMinYRotation(-90.0f);
+ m_barsController->m_scene->activeCamera()->d_ptr->setMaxYRotation(90.0f);
+ } else {
+ if ((m_hasNegativeValues && !m_helperAxisY.isReversed())
+ || (!m_hasNegativeValues && m_helperAxisY.isReversed())) {
+ m_barsController->m_scene->activeCamera()->d_ptr->setMinYRotation(-90.0f);
+ m_barsController->m_scene->activeCamera()->d_ptr->setMaxYRotation(0.0f);
+ } else {
+ m_barsController->m_scene->activeCamera()->d_ptr->setMinYRotation(0.0f);
+ m_barsController->m_scene->activeCamera()->d_ptr->setMaxYRotation(90.0f);
+ }
+ }
+ if (m_barsController->m_changeTracker.barSpecsChanged || !m_cachedBarThickness.isValid()) {
+ updateBarSpecs(m_barsController->m_barThicknessRatio, m_barsController->m_barSpacing,
+ m_barsController->m_isBarSpecRelative);
+ m_barsController->m_changeTracker.barSpecsChanged = false;
+ }
+
+ // Floor level update requires data update, so do before abstract sync
+ if (m_barsController->m_changeTracker.floorLevelChanged) {
+ updateFloorLevel(m_barsController->m_floorLevel);
+ m_barsController->m_changeTracker.floorLevelChanged = false;
+ }
+
+ if (m_barsController->m_changeTracker.barSeriesMarginChanged) {
+ updateBarSeriesMargin(barSeriesMargin());
+ m_barsController->m_changeTracker.barSeriesMarginChanged = false;
+ }
+
+ auto axisY = static_cast<QValue3DAxis *>(m_barsController->axisY());
+ axisY->formatter()->d_ptr->recalculate();
+ m_helperAxisY.setFormatter(axisY->formatter());
+
+ QQuickGraphsItem::synchData();
+
+ // Needs to be done after data is set, as it needs to know the visual array.
+ if (m_barsController->m_changeTracker.selectedBarChanged) {
+ if (m_barsController->m_selectedBar != m_selectedBarCoord || m_barsController->m_selectedBarSeries != m_selectedBarSeries)
+ setSelectedBar(m_barsController->m_selectedBarSeries, m_barsController->m_selectedBar);
+ updateSelectedBar();
+ m_barsController->m_changeTracker.selectedBarChanged = false;
+ }
+
+ QMatrix4x4 modelMatrix;
+
+ // Draw floor
+ m_floorBackground->setPickable(false);
+ m_floorBackgroundScale->setScale(scaleWithBackground());
+ modelMatrix.scale(scaleWithBackground());
+ m_floorBackgroundScale->setPosition(QVector3D(0.0f, -m_backgroundAdjustment, 0.0f));
+
+ QQuaternion m_xRightAngleRotation(QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, 90.0f));
+ QQuaternion m_xRightAngleRotationNeg(QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, -90.0f));
+
+ if (isYFlipped()) {
+ m_floorBackgroundRotation->setRotation(m_xRightAngleRotation);
+ modelMatrix.rotate(m_xRightAngleRotation);
+ } else {
+ m_floorBackgroundRotation->setRotation(m_xRightAngleRotationNeg);
+ modelMatrix.rotate(m_xRightAngleRotationNeg);
+ }
+
+ auto bgFloor = m_floorBackground;
+ bgFloor->setPickable(false);
+ QQmlListReference materialsRefF(bgFloor, "materials");
+ QQuick3DPrincipledMaterial * bgMatFloor;
+
+ if (!materialsRefF.size()) {
+ bgMatFloor = new QQuick3DPrincipledMaterial();
+ bgMatFloor->setParent(this);
+ bgMatFloor->setRoughness(.3f);
+ bgMatFloor->setEmissiveFactor(QVector3D(.075f, .075f, .075f));
+ materialsRefF.append(bgMatFloor);
+ } else {
+ bgMatFloor = static_cast<QQuick3DPrincipledMaterial *>(materialsRefF.at(0));
+ }
+ Q3DTheme *theme = m_barsController->activeTheme();
+ bgMatFloor->setBaseColor(theme->backgroundColor());
+
+ if (m_axisRangeChanged) {
+ updateGrid();
+ updateLabels();
+ m_axisRangeChanged = false;
+ }
+}
+
+void QQuickGraphsBars::updateParameters() {
+ m_minRow = m_barsController->m_axisZ->min();
+ m_maxRow = m_barsController->m_axisZ->max();
+ m_minCol = m_barsController->m_axisX->min();
+ m_maxCol = m_barsController->m_axisX->max();
+ m_newRows = m_maxRow - m_minRow + 1;
+ m_newCols = m_maxCol - m_minCol + 1;
+
+ if (m_cachedRowCount!= m_newRows || m_cachedColumnCount != m_newCols) {
+ // Force update for selection related items
+ if (isSliceEnabled() && m_barsController->isSlicingActive()) {
+ setSliceEnabled(false);
+ setSliceActivatedChanged(true);
+ }
+
+ m_cachedColumnCount = m_newCols;
+ m_cachedRowCount = m_newRows;
+
+ // Calculate max scene size
+ float sceneRatio = qMin(float(m_newCols) / float(m_newRows),
+ float(m_newRows) / float(m_newCols));
+ m_maxSceneSize = 2.0f * qSqrt(sceneRatio * m_newCols * m_newRows);
+
+ if (m_cachedBarThickness.isValid())
+ calculateSceneScalingFactors();
+ }
+
+ m_axisRangeChanged = true;
+ createSliceView();
+ update();
+}
+
+void QQuickGraphsBars::updateFloorLevel(float level)
+{
+ setFloorLevel(level);
+ calculateHeightAdjustment();
+}
+
+void QQuickGraphsBars::updateGraph()
+{
+ QList<QBar3DSeries *> barSeriesList = m_barsController->barSeriesList();
+ calculateSceneScalingFactors();
+
+ if (m_barsController->m_changedSeriesList.size()) {
+ for (auto series : m_barsController->barSeriesList()) {
+ if (m_barModelsMap.contains(series))
+ removeDataItems(series);
+ }
+ }
+ generateBars(barSeriesList);
+ int visualIndex = 0;
+ for (auto barSeries : m_barsController->barSeriesList()) {
+ if (barSeries->isVisible()) {
+ updateBarVisuality(barSeries, visualIndex);
+ updateBarPositions(barSeries);
+ updateBarVisuals(barSeries);
+ ++visualIndex;
+ }
+ else
+ updateBarVisuality(barSeries, -1);
+ }
+}
+
+void QQuickGraphsBars::updateAxisRange(float min, float max)
+{
+ QQuickGraphsItem::updateAxisRange(min, max);
+
+ m_helperAxisY.setMin(min);
+ m_helperAxisY.setMax(max);
+
+ calculateHeightAdjustment();
+}
+
+void QQuickGraphsBars::updateAxisReversed(bool enable)
+{
+ m_helperAxisY.setReversed(enable);
+ calculateHeightAdjustment();
+}
+
+void QQuickGraphsBars::calculateSceneScalingFactors()
+{
+ m_rowWidth = (m_cachedColumnCount * m_cachedBarSpacing.width()) * 0.5f;
+ m_columnDepth = (m_cachedRowCount * m_cachedBarSpacing.height()) * 0.5f;
+ m_maxDimension = qMax(m_rowWidth, m_columnDepth);
+ m_scaleFactor = qMin((m_cachedColumnCount *(m_maxDimension / m_maxSceneSize)),
+ (m_cachedRowCount * (m_maxDimension / m_maxSceneSize)));
+
+ // Single bar scaling
+ m_xScale = m_cachedBarThickness.width() / m_scaleFactor;
+ m_zScale = m_cachedBarThickness.height() / m_scaleFactor;
+
+ // Adjust scaling according to margin
+ m_xScale = m_xScale - m_xScale * m_cachedBarSeriesMargin.width();
+ m_zScale = m_zScale - m_zScale * m_cachedBarSeriesMargin.height();
+
+ // Whole graph scale factors
+ m_xScaleFactor = m_rowWidth / m_scaleFactor;
+ m_zScaleFactor = m_columnDepth / m_scaleFactor;
+
+ if (m_requestedMargin < 0.0f) {
+ m_hBackgroundMargin = 0.0f;
+ m_vBackgroundMargin = 0.0f;
+ } else {
+ m_hBackgroundMargin = m_requestedMargin;
+ m_vBackgroundMargin = m_requestedMargin;
+ }
+
+ m_scaleXWithBackground = m_xScaleFactor + m_hBackgroundMargin;
+ m_scaleYWithBackground = 1.0f + m_vBackgroundMargin;
+ m_scaleZWithBackground = m_zScaleFactor + m_hBackgroundMargin;
+
+ auto scale = QVector3D(m_xScaleFactor, 1.0f, m_zScaleFactor);
+ setScaleWithBackground(scale);
+ setBackgroundScaleMargin({m_hBackgroundMargin, m_vBackgroundMargin, m_hBackgroundMargin});
+ setScale(scale);
+
+ m_helperAxisX.setScale(m_scaleXWithBackground * 2);
+ m_helperAxisY.setScale(m_yScale);
+ m_helperAxisZ.setScale(-m_scaleZWithBackground * 2);
+ m_helperAxisX.setTranslate(-m_xScale);
+ m_helperAxisY.setTranslate(0.0f);
+}
+
+void QQuickGraphsBars::calculateHeightAdjustment()
+{
+ m_minHeight = m_helperAxisY.min();
+ m_maxHeight = m_helperAxisY.max();
+ float newAdjustment = 1.0f;
+ m_actualFloorLevel = qBound(m_minHeight, floorLevel(), m_maxHeight);
+ float maxAbs = qFabs(m_maxHeight - m_actualFloorLevel);
+
+ // Check if we have negative values
+ if (m_minHeight < m_actualFloorLevel)
+ m_hasNegativeValues = true;
+ else if (m_minHeight >= m_actualFloorLevel)
+ m_hasNegativeValues = false;
+
+ if (m_maxHeight < m_actualFloorLevel) {
+ m_heightNormalizer = float(qFabs(m_minHeight) - qFabs(m_maxHeight));
+ maxAbs = qFabs(m_maxHeight) - qFabs(m_minHeight);
+ } else {
+ m_heightNormalizer = float(m_maxHeight - m_minHeight);
+ }
+
+ // Height fractions are used in gradient calculations and are therefore doubled
+ // Note that if max or min is exactly zero, we still consider it outside the range
+ if (m_maxHeight <= m_actualFloorLevel || m_minHeight >= m_actualFloorLevel) {
+ m_noZeroInRange = true;
+ m_gradientFraction = 2.0f;
+ } else {
+ m_noZeroInRange = false;
+ float minAbs = qFabs(m_minHeight - m_actualFloorLevel);
+ m_gradientFraction = qMax(minAbs, maxAbs) / m_heightNormalizer * 2.0f;
+ }
+
+ // Calculate translation adjustment for background floor
+ newAdjustment = (qBound(0.0f, (maxAbs / m_heightNormalizer), 1.0f) - 0.5f) * 2.0f;
+ if (m_helperAxisY.isReversed())
+ newAdjustment = -newAdjustment;
+
+ if (newAdjustment != m_backgroundAdjustment)
+ m_backgroundAdjustment = newAdjustment;
+}
+
+void QQuickGraphsBars::calculateSeriesStartPosition()
+{
+ m_seriesStart = -((float(m_visibleSeriesCount) - 1.0f) * 0.5f)
+ * (m_seriesStep - (m_seriesStep * m_cachedBarSeriesMargin.width()));
+}
+
+QVector3D QQuickGraphsBars::calculateCategoryLabelPosition(QAbstract3DAxis *axis,
+ QVector3D labelPosition, int index)
+{
+ QVector3D ret = labelPosition;
+ if (axis->orientation() == QAbstract3DAxis::AxisOrientationX) {
+ float xPos = (index + 0.5f) * m_cachedBarSpacing.width();
+ ret.setX((xPos - m_rowWidth) / m_scaleFactor);
+ }
+ if (axis->orientation() == QAbstract3DAxis::AxisOrientationZ) {
+ float zPos = (index + 0.5f) * m_cachedBarSpacing.height();
+ ret.setZ((m_columnDepth - zPos) / m_scaleFactor);
+ }
+ ret.setY(-m_backgroundAdjustment);
+ return ret;
+}
+
+float QQuickGraphsBars::calculateCategoryGridLinePosition(QAbstract3DAxis *axis, int index)
+{
+ float ret = 0.0f;
+ if (axis->orientation() == QAbstract3DAxis::AxisOrientationZ) {
+ float colPos = index * -(m_cachedBarSpacing.height() / m_scaleFactor);
+ ret = colPos + scale().z();
+ }
+ if (axis->orientation() == QAbstract3DAxis::AxisOrientationX) {
+ float rowPos = index * (m_cachedBarSpacing.width() / m_scaleFactor);
+ ret = rowPos - scale().x();
+ }
+ if (axis->orientation() == QAbstract3DAxis::AxisOrientationY)
+ ret = -m_backgroundAdjustment;
+ return ret;
+}
+
+void QQuickGraphsBars::handleAxisXChanged(QAbstract3DAxis *axis)
+{
+ emit columnAxisChanged(static_cast<QCategory3DAxis *>(axis));
+}
+
+void QQuickGraphsBars::handleAxisYChanged(QAbstract3DAxis *axis)
+{
+ emit valueAxisChanged(static_cast<QValue3DAxis *>(axis));
+}
+
+void QQuickGraphsBars::handleAxisZChanged(QAbstract3DAxis *axis)
+{
+ emit rowAxisChanged(static_cast<QCategory3DAxis *>(axis));
+}
+
+void QQuickGraphsBars::handleSeriesMeshChanged(QAbstract3DSeries::Mesh mesh)
+{
+ QList<QBar3DSeries *> barSeriesList = m_barsController->barSeriesList();
+ m_meshType = mesh;
+ if (m_barsController->optimizationHints() == QAbstract3DGraph::OptimizationDefault) {
+ for (auto series : m_barsController->barSeriesList()) {
+ if (m_barModelsMap.contains(series))
+ removeDataItems(series);
+ }
+ generateBars(barSeriesList);
+ } else if (m_barsController->optimizationHints() == QAbstract3DGraph::OptimizationStatic) {
+ resetClickedStatus();
+// m_instancingRootItem->setSource(QUrl(getMeshFileName()));
+ m_selectionIndicator->setSource(QUrl(getMeshFileName()));
+ m_barsController->markDataDirty();
+ m_barsController->markSeriesVisualsDirty();
+ generateBars(barSeriesList);
+ }
+}
+
+void QQuickGraphsBars::handleOptimizationHintsChanged(QAbstract3DGraph::OptimizationHints hints)
+{
+ Q_UNUSED(hints);
+// setup();
+}
+
+void QQuickGraphsBars::handleMeshSmoothChanged(bool enable)
+{
+ QList<QBar3DSeries *> barSeriesList = m_barsController->barSeriesList();
+ m_smooth = enable;
+
+ if (m_barsController->optimizationHints() == QAbstract3DGraph::OptimizationDefault) {
+ for (auto series : m_barsController->barSeriesList()) {
+ if (m_barModelsMap.contains(series))
+ removeDataItems(series);
+ }
+ generateBars(barSeriesList);
+ } else if (m_barsController->optimizationHints() == QAbstract3DGraph::OptimizationStatic) {
+ resetClickedStatus();
+// m_instancingRootItem->setSource(QUrl(getMeshFileName()));
+ m_selectionIndicator->setSource(QUrl(getMeshFileName()));
+ m_barsController->markDataDirty();
+ m_barsController->markSeriesVisualsDirty();
+ generateBars(barSeriesList);
+ }
+}
+
+void QQuickGraphsBars::handleRowCountChanged()
+{
+ QCategory3DAxis *categoryAxisZ = static_cast<QCategory3DAxis *>(m_barsController->axisZ());
+ segmentLineRepeaterZ()->setModel(categoryAxisZ->labels().size());
+ repeaterZ()->setModel(categoryAxisZ->labels().size());
+ updateParameters();
+}
+
+void QQuickGraphsBars::handleColCountChanged()
+{
+ QCategory3DAxis *categoryAxisX = static_cast<QCategory3DAxis *>(m_barsController->axisX());
+ segmentLineRepeaterX()->setModel(categoryAxisX->labels().size());
+ repeaterX()->setModel(categoryAxisX->labels().size());
+ updateParameters();
+}
+
+void QQuickGraphsBars::connectSeries(QBar3DSeries *series)
+{
+ m_meshType = series->mesh();
+ m_smooth = series->isMeshSmooth();
+
+ QObject::connect(series, &QBar3DSeries::meshChanged, this,
+ &QQuickGraphsBars::handleSeriesMeshChanged);
+ QObject::connect(series, &QBar3DSeries::meshSmoothChanged, this,
+ &QQuickGraphsBars::handleMeshSmoothChanged);
+ QObject::connect(series->dataProxy(), &QBarDataProxy::rowCountChanged, this,
+ &QQuickGraphsBars::handleRowCountChanged);
+ QObject::connect(series->dataProxy(), &QBarDataProxy::colCountChanged, this,
+ &QQuickGraphsBars::handleColCountChanged);
+}
+
+void QQuickGraphsBars::disconnectSeries(QBar3DSeries *series)
+{
+ QObject::disconnect(series, 0, this, 0);
+}
+
+void QQuickGraphsBars::generateBars(QList<QBar3DSeries *> &barSeriesList)
+{
+ int seriesCount = barSeriesList.size();
+ m_visibleSeriesCount = 0;
+ for (int i = 0; i < seriesCount; i++) {
+ QBar3DSeries *barSeries = static_cast<QBar3DSeries *>(barSeriesList[i]);
+ QVector<BarModel *> *barList = m_barModelsMap.value(barSeries);
+ if (!barList) {
+ barList = new QVector<BarModel *>;
+ m_barModelsMap[barSeries] = barList;
+ }
+ if (barList->isEmpty()) {
+ QQuick3DTexture *texture = createTexture();
+ texture->setParent(this);
+ auto gradient = barSeries->baseGradient();
+ auto textureData = static_cast<QuickGraphsTextureData *>(texture->textureData());
+ textureData->createGradient(gradient);
+
+ bool visible = barSeries->isVisible();
+ int minRow = m_barsController->m_axisZ->min();
+ int dataRowCount = 0;
+ int dataColCount = 0;
+
+ const QBarDataArray *array = barSeries->dataProxy()->array();
+ QBarDataProxy *dataProxy = barSeries->dataProxy();
+ dataRowCount = dataProxy->rowCount();
+ dataColCount = dataProxy->colCount();
+ int dataRowIndex = minRow;
+
+ while (dataRowIndex < dataRowCount) {
+ const QBarDataRow *dataRow = array->at(dataRowIndex);
+ Q_ASSERT(dataRow->size() == dataColCount);
+ for (int i = 0; i < dataColCount; i++) {
+ QBarDataItem *dataItem = const_cast <QBarDataItem *> (&(dataRow->at(i)));
+ auto scene = QQuick3DViewport::scene();
+ QQuick3DModel *model = createDataItem(scene);
+ model->setVisible(visible);
+
+ BarModel *barModel = new BarModel();
+ barModel->model = model;
+ barModel->barItem = dataItem;
+ barModel->coord = QPoint(dataRowIndex, i);
+ barModel->texture = texture;
+
+ if (!barList->contains(barModel))
+ barList->append(barModel);
+ }
+ ++dataRowIndex;
+ }
+ }
+ if (barSeries->isVisible())
+ m_visibleSeriesCount++;
+ }
+}
+
+QQuick3DModel *QQuickGraphsBars::createDataItem(QQuick3DNode *scene)
+{
+ auto model = new QQuick3DModel();
+ model->setParent(scene);
+ model->setParentItem(scene);
+ model->setObjectName(QStringLiteral("BarModel"));
+ QString fileName = getMeshFileName();
+ model->setSource(QUrl(fileName));
+ return model;
+}
+
+QString QQuickGraphsBars::getMeshFileName()
+{
+ QString fileName;
+ QString smoothString = QStringLiteral("Smooth");
+ switch (m_meshType) {
+ case QAbstract3DSeries::MeshSphere:
+ fileName = QStringLiteral("defaultMeshes/sphereMesh");
+ break;
+ case QAbstract3DSeries::MeshBar:
+ case QAbstract3DSeries::MeshCube:
+ fileName = QStringLiteral("defaultMeshes/barMesh");
+ break;
+ case QAbstract3DSeries::MeshPyramid:
+ fileName = QStringLiteral("defaultMeshes/pyramidMesh");
+ break;
+ case QAbstract3DSeries::MeshCone:
+ fileName = QStringLiteral("defaultMeshes/coneMesh");
+ break;
+ case QAbstract3DSeries::MeshCylinder:
+ fileName = QStringLiteral("defaultMeshes/cylinderMesh");
+ break;
+ case QAbstract3DSeries::MeshBevelBar:
+ case QAbstract3DSeries::MeshBevelCube:
+ fileName = QStringLiteral("defaultMeshes/bevelBarMesh");
+ break;
+ default:
+ fileName = QStringLiteral("defaultMeshes/sphereMesh");
+ }
+ if (m_smooth && m_meshType != QAbstract3DSeries::MeshPoint)
+ fileName += smoothString;
+
+ fixMeshFileName(fileName, m_meshType);
+
+ return fileName;
+}
+
+void QQuickGraphsBars::fixMeshFileName(QString &fileName, QAbstract3DSeries::Mesh meshType)
+{
+ if (!m_barsController->activeTheme()->isBackgroundEnabled()
+ && meshType != QAbstract3DSeries::MeshSphere) {
+ fileName.append(QStringLiteral("Full"));
+ }
+}
+
+void QQuickGraphsBars::updateBarVisuality(QBar3DSeries *series, int visualIndex)
+{
+ QVector<BarModel *> barList = *m_barModelsMap.value(series);
+ for (int i = 0; i < barList.count(); i++) {
+ if (barList.at(i)->model->visible() != series->isVisible() && isSliceEnabled()) {
+ setSliceEnabled(false);
+ setSliceActivatedChanged(true);
+ }
+ barList.at(i)->visualIndex = visualIndex;
+ barList.at(i)->model->setVisible(series->isVisible());
+ }
+ setSelectedBar(m_selectedBarSeries, m_selectedBarCoord);
+ itemLabel()->setVisible(false);
+}
+
+void QQuickGraphsBars::updateBarPositions(QBar3DSeries *series)
+{
+ QBarDataProxy *dataProxy = series->dataProxy();
+ int dataRowCount = 0;
+ int dataColCount = 0;
+
+
+ m_seriesScaleX = 1.0f / float(m_visibleSeriesCount);
+ m_seriesStep = 1.0f / float(m_visibleSeriesCount);
+ m_seriesStart = -((float(m_visibleSeriesCount) - 1.0f) * 0.5f)
+ * (m_seriesStep - (m_seriesStep * m_cachedBarSeriesMargin.width()));
+
+ if (m_keepSeriesUniform)
+ m_seriesScaleZ = m_seriesScaleX;
+ else
+ m_seriesScaleZ = 1.0f;
+
+ m_meshRotation = dataProxy->series()->meshRotation();
+ m_zeroPosition = m_helperAxisY.itemPositionAt(m_actualFloorLevel);
+
+ QVector<BarModel *> barList = *m_barModelsMap.value(series);
+ if (m_barsController->optimizationHints() == QAbstract3DGraph::OptimizationDefault) {
+ for (int i = 0; i < barList.count(); i++) {
+ QBarDataItem *item = const_cast<QBarDataItem *>((barList.at(i)->barItem));
+ QQuick3DModel *model = barList.at(i)->model;
+ float value = item->value();
+ float heightValue = m_helperAxisY.itemPositionAt(value);
+
+ if (m_noZeroInRange) {
+ if (m_hasNegativeValues) {
+ heightValue = -1.0f + heightValue;
+ if (heightValue > 0.0f)
+ heightValue = 0.0f;
+ } else {
+ if (heightValue < 0.0f)
+ heightValue = 0.0f;
+ }
+ } else {
+ heightValue -= m_zeroPosition;
+ }
+
+ if (m_helperAxisY.isReversed())
+ heightValue = -heightValue;
+
+ float angle = item->rotation();
+
+ if (angle) {
+ model->setRotation(
+ QQuaternion::fromAxisAndAngle(
+ upVector, angle));
+ } else {
+ model->setRotation(QQuaternion());
+ }
+
+ if (heightValue < 0.f) {
+ const QVector3D rot = model->eulerRotation();
+ model->setEulerRotation(QVector3D(-180.f, rot.y(), rot.z()));
+ }
+
+ float seriesPos = m_seriesStart + m_seriesStep
+ * (barList.at(i)->visualIndex - (barList.at(i)->visualIndex
+ * m_cachedBarSeriesMargin.width())) + 0.5f;
+
+
+ float colPos = (dataColCount + seriesPos) * m_cachedBarSpacing.width();
+ float xPos = (colPos - m_rowWidth) / m_scaleFactor;
+ float rowPos = (dataRowCount + 0.5f) * (m_cachedBarSpacing.height());
+ float zPos = (m_columnDepth - rowPos) / m_scaleFactor;
+
+ barList.at(i)->heightValue = heightValue;
+ model->setPosition(QVector3D(xPos, heightValue - m_backgroundAdjustment, zPos));
+ model->setScale(QVector3D(m_xScale * m_seriesScaleX, qAbs(heightValue),
+ m_zScale * m_seriesScaleZ));
+
+ if (heightValue == 0) {
+ model->setPickable(false);
+ model->setVisible(false);
+ } else {
+ model->setPickable(true);
+ }
+
+ if (dataColCount < dataProxy->colCount() - 1) {
+ ++dataColCount;
+ } else {
+ dataColCount = 0;
+ if (dataRowCount < dataProxy->rowCount() - 1)
+ ++dataRowCount;
+ else
+ dataRowCount = 0;
+ }
+ }
+ }
+}
+
+void QQuickGraphsBars::updateBarVisuals(QBar3DSeries *series)
+{
+ QVector<BarModel *> barList = *m_barModelsMap.value(series);
+ bool useGradient = series->d_ptr->isUsingGradient();
+
+ if (useGradient) {
+ if (!m_hasHighlightTexture) {
+ m_highlightTexture = createTexture();
+ m_highlightTexture->setParent(this);
+ m_hasHighlightTexture = true;
+ }
+ auto highlightGradient = series->singleHighlightGradient();
+ auto highlightTextureData = static_cast<QuickGraphsTextureData *>(m_highlightTexture->textureData());
+ highlightTextureData->createGradient(highlightGradient);
+ } else {
+ if (m_hasHighlightTexture) {
+ m_highlightTexture->deleteLater();
+ m_hasHighlightTexture = false;
+ }
+ }
+
+ bool rangeGradient = (useGradient && series->d_ptr->m_colorStyle == Q3DTheme::ColorStyleRangeGradient)
+ ? true : false;
+
+ if (m_barsController->optimizationHints() == QAbstract3DGraph::OptimizationDefault) {
+ if (!rangeGradient) {
+ for (int i = 0; i < barList.count(); i++) {
+ QQuick3DModel *model = barList.at(i)->model;
+ updateItemMaterial(model, useGradient, rangeGradient);
+ updatePrincipledMaterial(model, series->baseColor(), useGradient, false,
+ barList.at(i)->texture);
+ }
+ } else {
+ for (int i = 0; i < barList.count(); i++) {
+ QQuick3DModel *model = barList.at(i)->model;
+ updateItemMaterial(model, useGradient, rangeGradient);
+ updateCustomMaterial(model, barList.at(i)->texture);
+ }
+ }
+ }
+}
+
+void QQuickGraphsBars::updateItemMaterial(QQuick3DModel *item, bool useGradient, bool rangeGradient)
+{
+ Q_UNUSED(useGradient);
+ QQmlListReference materialsRef(item, "materials");
+ if (!rangeGradient) {
+ if (materialsRef.size()) {
+ if (!qobject_cast<QQuick3DPrincipledMaterial *>(materialsRef.at(0))) {
+ auto principledMaterial = new QQuick3DPrincipledMaterial();
+ principledMaterial->setParent(this);
+ auto oldCustomMaterial = materialsRef.at(0);
+ materialsRef.replace(0, principledMaterial);
+ delete oldCustomMaterial;
+ }
+ } else {
+ auto principledMaterial = new QQuick3DPrincipledMaterial();
+ principledMaterial->setParent(this);
+ materialsRef.append(principledMaterial);
+ }
+ } else {
+ if (materialsRef.size()) {
+ if (!qobject_cast<QQuick3DCustomMaterial *>(materialsRef.at(0))) {
+ auto customMaterial = createQmlCustomMaterial(QStringLiteral(":/materials/RangeGradientMaterial"));
+ auto oldPrincipledMaterial = materialsRef.at(0);
+ materialsRef.replace(0, customMaterial);
+ delete oldPrincipledMaterial;
+ }
+ } else {
+ auto customMaterial = createQmlCustomMaterial(QStringLiteral(":/materials/RangeGradientMaterial"));
+ materialsRef.append(customMaterial);
+ }
+ }
+}
+
+void QQuickGraphsBars::updateCustomMaterial(QQuick3DModel *item, bool isHighlight,
+ QQuick3DTexture *texture)
+{
+ QQmlListReference materialsRef(item, "materials");
+ auto customMaterial = static_cast<QQuick3DCustomMaterial *>(materialsRef.at(0));
+ QVariant textureInputAsVariant = customMaterial->property("custex");
+ QQuick3DShaderUtilsTextureInput *textureInput = textureInputAsVariant.value<QQuick3DShaderUtilsTextureInput *>();
+
+ if (!isHighlight)
+ textureInput->setTexture(texture);
+ else
+ textureInput->setTexture(m_highlightTexture);
+
+ float rangeGradientYScaler = 0.5f / m_yScale;
+ float value = (item->y() + m_yScale) * rangeGradientYScaler;
+ customMaterial->setProperty("gradientPos", value);
+}
+
+void QQuickGraphsBars::updatePrincipledMaterial(QQuick3DModel *model, const QColor &color,
+ bool useGradient, bool isHighlight,
+ QQuick3DTexture *texture)
+{
+ QQmlListReference materialsRef(model, "materials");
+ auto principledMaterial = static_cast<QQuick3DPrincipledMaterial *>(materialsRef.at(0));
+ principledMaterial->setParent(this);
+
+ if (useGradient) {
+ principledMaterial->setBaseColor(QColor(Qt::white));
+ if (!isHighlight)
+ principledMaterial->setBaseColorMap(texture);
+ else
+ principledMaterial->setBaseColorMap(m_highlightTexture);
+ } else {
+ principledMaterial->setBaseColor(color);
+ }
+}
+
+void QQuickGraphsBars::removeDataItems(QBar3DSeries *series)
+{
+ if (m_barModelsMap.value(series)->isEmpty())
+ return;
+ QVector<BarModel *> barList = *m_barModelsMap.value(series);
+ for (int i = 0; i < barList.count(); i++) {
+ barList.at(i)->model->setPickable(false);
+ barList.at(i)->model->setVisible(false);
+ QQmlListReference materialsRef(barList.at(i)->model, "materials");
+ if (materialsRef.size()) {
+ auto material = materialsRef.at(0);
+ delete material;
+ }
+ delete barList.at(i)->model;
+ }
+ m_barModelsMap.remove(series);
+ setSelectedBar(m_selectedBarSeries, m_selectedBarCoord);
+ itemLabel()->setVisible(false);
+}
+
+QQuick3DTexture *QQuickGraphsBars::createTexture()
+{
+ QQuick3DTexture *texture = new QQuick3DTexture();
+ texture->setParent(this);
+ texture->setRotationUV(-90.0f);
+ texture->setHorizontalTiling(QQuick3DTexture::ClampToEdge);
+ texture->setVerticalTiling(QQuick3DTexture::ClampToEdge);
+ QuickGraphsTextureData *textureData = new QuickGraphsTextureData();
+ textureData->setParent(texture);
+ textureData->setParentItem(texture);
+ texture->setTextureData(textureData);
+
+ return texture;
+}
+
+bool QQuickGraphsBars::handleMousePressedEvent(QMouseEvent *event)
+{
+ QQuickGraphsItem::handleMousePressedEvent(event);
+
+ if (Qt::LeftButton == event->button()) {
+ auto mousePos = event->pos();
+ QList<QQuick3DPickResult> pickResults = pickAll(mousePos.x(), mousePos.y());
+ auto selectionMode = m_barsController->selectionMode();
+ QQuick3DModel *selectedModel = nullptr;
+ if (!selectionMode.testFlag(QAbstract3DGraph::SelectionNone)) {
+ for (const auto &picked : std::as_const(pickResults)) {
+ if (picked.objectHit()->visible()) {
+ if (picked.objectHit() == backgroundBB() || picked.objectHit() == background()) {
+ resetClickedStatus();
+ continue;
+ } else if (picked.objectHit()->objectName().contains(QStringLiteral("BarModel"))) {
+ selectedModel = picked.objectHit();
+ break;
+ }
+ }
+ }
+
+ if (selectedModel) {
+ QBar3DSeries *series = 0;
+ QPoint coord = m_barsController->invalidSelectionPosition();
+ for (auto it = m_barModelsMap.begin(); it != m_barModelsMap.end(); it++) {
+ if (!it.key()->isVisible())
+ continue;
+ for (int i = 0; i < it.value()->count(); i++) {
+ QQuick3DModel *model = it.value()->at(i)->model;
+ if (model == selectedModel) {
+ series = it.key();
+ coord = it.value()->at(i)->coord;
+ }
+ }
+ }
+ setSelectedBar(series, coord);
+ } else {
+ resetClickedStatus();
+ }
+ }
+ }
+
+ return true;
+}
+
+void QQuickGraphsBars::setSelectedBar(QBar3DSeries *series, const QPoint &coord)
+{
+ if (!m_barModelsMap.contains(series))
+ series = 0;
+
+ if (coord != m_selectedBarCoord || series != m_selectedBarSeries) {
+ m_selectedBarSeries = series;
+ m_selectedBarCoord = coord;
+ if (isSliceEnabled()) {
+ m_barsController->setSlicingActive(true);
+ setSliceActivatedChanged(true);
+ }
+
+ // Clear selection from other series and finally set new selection to the specified series
+ for (auto it = m_barModelsMap.begin(); it != m_barModelsMap.end(); it++) {
+ if (it.key() != m_selectedBarSeries)
+ it.key()->dptr()->setSelectedBar(invalidSelectionPosition());
+ }
+ if (m_selectedBarSeries) {
+ m_selectedBarSeries->dptr()->setSelectedBar(m_selectedBarCoord);
+ m_barsController->setSelectedBar(m_selectedBarCoord, m_selectedBarSeries, false);
+ }
+ }
+}
+
+void QQuickGraphsBars::updateSelectedBar()
+{
+ bool visible = false;
+ if (m_selectedBarSeries) {
+ for (auto it = m_barModelsMap.begin(); it != m_barModelsMap.end(); it++) {
+ QVector<BarModel *> barList = *it.value();
+ for (int i = 0; i < barList.count(); i++) {
+ Bars3DController::SelectionType selectionType =
+ isSelected(barList.at(i)->coord.x(), barList.at(i)->coord.y(), it.key());
+ switch (selectionType) {
+ case Bars3DController::SelectionItem: {
+ updatePrincipledMaterial(barList.at(i)->model,
+ m_selectedBarSeries->singleHighlightColor(),
+ m_selectedBarSeries->d_ptr->isUsingGradient(), true,
+ barList.at(i)->texture);
+
+ m_selectedBarPos = barList.at(i)->model->position();
+ visible = m_selectedBarSeries->isVisible() && !m_selectedBarPos.isNull();
+ QString label = (m_selectedBarSeries->dptr()->itemLabel());
+
+ if (barList.at(i)->heightValue >= 0.0f) {
+ m_selectedBarPos.setY(m_selectedBarPos.y() + barList.at(i)->heightValue
+ + 0.2f);
+ } else {
+ m_selectedBarPos.setY(m_selectedBarPos.y() + barList.at(i)->heightValue
+ - 0.2f);
+ }
+
+ itemLabel()->setPosition(m_selectedBarPos);
+ itemLabel()->setProperty("labelText", label);
+ itemLabel()->setEulerRotation(
+ QVector3D(-m_barsController->scene()->activeCamera()->yRotation(),
+ -m_barsController->scene()->activeCamera()->xRotation(),
+ 0));
+
+ if (isSliceEnabled()) {
+ sliceItemLabel()->setPosition(QVector3D((m_selectedBarPos.x() + .05f),
+ (m_selectedBarPos.y() + .5f), 0.0f));
+ sliceItemLabel()->setScale(sliceItemLabel()->scale() / 1.5f);
+ sliceItemLabel()->setProperty("labelText", label);
+ sliceItemLabel()->setEulerRotation(QVector3D(0.0f, 0.0f, 90.0f));
+ sliceItemLabel()->setVisible(true);
+ }
+
+ break;
+ }
+ case Bars3DController::SelectionRow: {
+ updatePrincipledMaterial(barList.at(i)->model,
+ m_selectedBarSeries->multiHighlightColor(),
+ m_selectedBarSeries->d_ptr->isUsingGradient(), true,
+ barList.at(i)->texture);
+ break;
+ }
+ case Bars3DController::SelectionColumn: {
+ updatePrincipledMaterial(barList.at(i)->model,
+ m_selectedBarSeries->multiHighlightColor(),
+ m_selectedBarSeries->d_ptr->isUsingGradient(), true,
+ barList.at(i)->texture);
+ }
+ default:
+ break;
+ }
+ }
+ }
+ }
+ itemLabel()->setVisible(visible);
+}
+
+Abstract3DController::SelectionType QQuickGraphsBars::isSelected(int row, int bar,
+ QBar3DSeries *series)
+{
+ Bars3DController::SelectionType isSelectedType = Bars3DController::SelectionNone;
+ auto selectionMode = m_barsController->selectionMode();
+ if ((selectionMode.testFlag(QAbstract3DGraph::SelectionMultiSeries)
+ && m_selectedBarSeries) || series == m_selectedBarSeries) {
+ if (row == m_selectedBarCoord.x() && bar == m_selectedBarCoord.y()
+ && (selectionMode.testFlag(QAbstract3DGraph::SelectionItem))) {
+ isSelectedType = Bars3DController::SelectionItem;
+ } else if (row == m_selectedBarCoord.x()
+ && (selectionMode.testFlag(QAbstract3DGraph::SelectionRow))) {
+ isSelectedType = Bars3DController::SelectionRow;
+ } else if (bar == m_selectedBarCoord.y()
+ && (selectionMode.testFlag(QAbstract3DGraph::SelectionColumn))) {
+ isSelectedType = Bars3DController::SelectionColumn;
+ }
+ }
+
+ return isSelectedType;
+}
+
+void QQuickGraphsBars::resetClickedStatus()
+{
+ m_barsController->m_isSeriesVisualsDirty = true;
+ m_selectedBarPos = QVector3D(0.0f, 0.0f, 0.0f);
+ m_selectedBarCoord = Bars3DController::invalidSelectionPosition();
+ m_selectedBarSeries = 0;
+ m_barsController->clearSelection();
+}
+
+void QQuickGraphsBars::updateSliceGraph()
+{
+ QQuickGraphsItem::updateSliceGraph();
+
+ if (!sliceView()->isVisible()) {
+ if (!m_sliceViewBars.isEmpty()) {
+ for (int i = 0; i < m_sliceViewBars.count(); i++) {
+ m_sliceViewBars.at(i)->model->setPickable(false);
+ m_sliceViewBars.at(i)->model->setVisible(false);
+ QQmlListReference materialsRef(m_sliceViewBars.at(i)->model, "materials");
+ if (materialsRef.size()) {
+ auto material = materialsRef.at(0);
+ delete material;
+ }
+ delete m_sliceViewBars.at(i)->model;
+ }
+ m_sliceViewBars.clear();
+ }
+ return;
+ }
+
+ auto selectionMode = m_barsController->selectionMode();
+ QVector<BarModel *> barList = *m_barModelsMap.value(m_selectedBarSeries);
+ if (selectionMode.testFlag(QAbstract3DGraph::SelectionRow)) {
+ for (int col = 0; col < m_selectedBarSeries->dataProxy()->colCount(); col++) {
+ auto index = (m_selectedBarCoord.x() * m_selectedBarSeries->dataProxy()->colCount()) + col;
+
+ QQuick3DViewport *sliceParent = sliceView();
+ QQuick3DModel *model = createDataItem(sliceParent->scene());
+
+ BarModel *barModel = new BarModel();
+ barModel->model = model;
+ barModel->model->setVisible(sliceView()->isVisible());
+
+ QQuick3DTexture *texture = createTexture();
+ texture->setParent(barModel->model);
+ texture->setParentItem(barModel->model);
+ auto gradient = m_selectedBarSeries->baseGradient();
+ auto textureData = static_cast<QuickGraphsTextureData *>(texture->textureData());
+ textureData->createGradient(gradient);
+
+ barModel->texture = texture;
+ barModel->barItem = barList.at(index)->barItem;
+ barModel->coord = barList.at(index)->coord;
+ barModel->visualIndex = barList.at(index)->visualIndex;
+ barModel->heightValue = barList.at(index)->heightValue;
+
+ barModel->model->setPosition(QVector3D(barList.at(index)->model->x(),
+ barList.at(index)->model->y(), 0.0f));
+ barModel->model->setScale(barList.at(index)->model->scale());
+
+ bool useGradient = m_selectedBarSeries->d_ptr->isUsingGradient();
+ bool rangeGradient = (useGradient && m_selectedBarSeries->d_ptr->m_colorStyle ==
+ Q3DTheme::ColorStyleRangeGradient) ? true : false;
+
+ updateItemMaterial(barModel->model, useGradient, rangeGradient);
+ updatePrincipledMaterial(barModel->model,
+ m_selectedBarSeries->baseColor(),
+ m_selectedBarSeries->d_ptr->isUsingGradient(), false,
+ barModel->texture);
+
+ m_sliceViewBars.append(barModel);
+ }
+ }
+}
+
+void QQuickGraphsBars::updateBarSpecs(float thicknessRatio, const QSizeF &spacing, bool relative)
+{
+ // Convert ratio to QSizeF, as we need it in that format for autoscaling calculations
+ m_cachedBarThickness.setWidth(1.0);
+ m_cachedBarThickness.setHeight(1.0f / thicknessRatio);
+
+ if (relative) {
+ m_cachedBarSpacing.setWidth((m_cachedBarThickness.width() * 2)
+ * (spacing.width() + 1.0f));
+ m_cachedBarSpacing.setHeight((m_cachedBarThickness.height() * 2)
+ * (spacing.height() + 1.0f));
+ } else {
+ m_cachedBarSpacing = m_cachedBarThickness * 2 + spacing * 2;
+ }
+
+ m_axisRangeChanged = true;
+ // Slice mode doesn't update correctly without this
+ if (isSliceEnabled() && m_barsController->isSlicingActive()) {
+ setSliceEnabled(false);
+ setSliceActivatedChanged(true);
+ }
+
+ // Calculate here and at setting sample space
+ calculateSceneScalingFactors();
+}
+
+void QQuickGraphsBars::updateBarSeriesMargin(const QSizeF &margin)
+{
+ m_cachedBarSeriesMargin = margin;
+ calculateSeriesStartPosition();
+ calculateSceneScalingFactors();
+ m_barsController->m_isSeriesVisualsDirty = true;
+}