From d12f993ca802ff02091d6a5141d2847641bc65a8 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Wed, 20 Nov 2013 14:49:06 +0200 Subject: Multi series selection part 2: scatter Task-number: QTRD-2556 Change-Id: I9ee193141dff6603b47db28b0ed0682db6f914c8 Reviewed-by: Mika Salmela --- src/datavisualization/data/qabstract3dseries_p.h | 1 + src/datavisualization/data/qbar3dseries.cpp | 17 +++-- src/datavisualization/data/qbar3dseries.h | 1 + src/datavisualization/data/qscatter3dseries.cpp | 45 +++++++++++- src/datavisualization/data/qscatter3dseries.h | 6 ++ src/datavisualization/data/qscatter3dseries_p.h | 3 + src/datavisualization/engine/bars3dcontroller.cpp | 33 ++++----- src/datavisualization/engine/bars3dcontroller_p.h | 2 +- src/datavisualization/engine/bars3drenderer.cpp | 17 +++-- src/datavisualization/engine/q3dbars.cpp | 2 +- src/datavisualization/engine/q3dscatter.cpp | 21 +----- src/datavisualization/engine/q3dscatter.h | 5 -- .../engine/scatter3dcontroller.cpp | 84 +++++++++++++--------- .../engine/scatter3dcontroller_p.h | 18 +++-- src/datavisualization/engine/scatter3drenderer.cpp | 66 +++++++++++++---- src/datavisualization/engine/scatter3drenderer_p.h | 9 ++- src/datavisualizationqml2/declarativescatter.cpp | 12 ---- src/datavisualizationqml2/declarativescatter_p.h | 5 -- src/datavisualizationqml2/declarativeseries.cpp | 5 ++ src/datavisualizationqml2/declarativeseries_p.h | 1 + 20 files changed, 218 insertions(+), 135 deletions(-) (limited to 'src') diff --git a/src/datavisualization/data/qabstract3dseries_p.h b/src/datavisualization/data/qabstract3dseries_p.h index 2851c8e0..a82c3554 100644 --- a/src/datavisualization/data/qabstract3dseries_p.h +++ b/src/datavisualization/data/qabstract3dseries_p.h @@ -67,6 +67,7 @@ private: friend class Surface3DController; friend class Scatter3DController; friend class QBar3DSeries; + friend class QScatter3DSeries; }; QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/data/qbar3dseries.cpp b/src/datavisualization/data/qbar3dseries.cpp index febbd97e..ac292e5e 100644 --- a/src/datavisualization/data/qbar3dseries.cpp +++ b/src/datavisualization/data/qbar3dseries.cpp @@ -138,10 +138,10 @@ QBarDataProxy *QBar3DSeries::dataProxy() const /*! * \property Q3DBars::selectedBar * - * Selects a bar in a \a position. The position is the (row, column) position in + * Selects a bar at the \a position. The \a position is the (row, column) position in * the data array of the series. * Only one bar can be selected at a time. - * To clear selection, specify an illegal \a position, e.g. (-1, -1). + * To clear selection, set invalidSelectionPosition() as the \a position. * If this series is added to a graph, the graph can adjust the selection according to user * interaction or if it becomes invalid. Selecting a bar on another added series will also * clear the selection. @@ -160,6 +160,15 @@ QPoint QBar3DSeries::selectedBar() const return dptrc()->m_selectedBar; } +/*! + * \return an invalid position for selection. Set this position to selectedBar property if you + * want to clear the selection. + */ +QPoint QBar3DSeries::invalidSelectionPosition() const +{ + return Bars3DController::invalidSelectionPosition(); +} + /*! * \internal */ @@ -180,7 +189,7 @@ const QBar3DSeriesPrivate *QBar3DSeries::dptrc() const QBar3DSeriesPrivate::QBar3DSeriesPrivate(QBar3DSeries *q) : QAbstract3DSeriesPrivate(q, QAbstract3DSeries::SeriesTypeBar), - m_selectedBar(Bars3DController::noSelectionPoint()) + m_selectedBar(Bars3DController::invalidSelectionPosition()) { m_itemLabelFormat = QStringLiteral("@valueTitle: @valueLabel"); } @@ -206,7 +215,6 @@ void QBar3DSeriesPrivate::setDataProxy(QAbstractDataProxy *proxy) void QBar3DSeriesPrivate::connectControllerAndProxy(Abstract3DController *newController) { QBarDataProxy *barDataProxy = static_cast(m_dataProxy); - Bars3DController *controller = static_cast(newController); if (m_controller && barDataProxy) { // Disconnect old controller/old proxy @@ -215,6 +223,7 @@ void QBar3DSeriesPrivate::connectControllerAndProxy(Abstract3DController *newCon } if (newController && barDataProxy) { + Bars3DController *controller = static_cast(newController); QObject::connect(barDataProxy, &QBarDataProxy::arrayReset, controller, &Bars3DController::handleArrayReset); QObject::connect(barDataProxy, &QBarDataProxy::rowsAdded, controller, diff --git a/src/datavisualization/data/qbar3dseries.h b/src/datavisualization/data/qbar3dseries.h index ec1754d1..ddc52170 100644 --- a/src/datavisualization/data/qbar3dseries.h +++ b/src/datavisualization/data/qbar3dseries.h @@ -42,6 +42,7 @@ public: void setSelectedBar(const QPoint &position); QPoint selectedBar() const; + QPoint invalidSelectionPosition() const; signals: void dataProxyChanged(QBarDataProxy *proxy); diff --git a/src/datavisualization/data/qscatter3dseries.cpp b/src/datavisualization/data/qscatter3dseries.cpp index f0374339..aff0f33c 100644 --- a/src/datavisualization/data/qscatter3dseries.cpp +++ b/src/datavisualization/data/qscatter3dseries.cpp @@ -125,6 +125,39 @@ QScatterDataProxy *QScatter3DSeries::dataProxy() const return static_cast(d_ptr->dataProxy()); } +/*! + * \property QScatter3DSeries::selectedItem + * + * Selects an item at the \a index. The \a index is the index in the data array of the series. + * Only one item can be selected at a time. + * To clear selection, set invalidSelectionIndex() as the \a index. + * If this series is added to a graph, the graph can adjust the selection according to user + * interaction or if it becomes invalid. Selecting an item on another added series will also + * clear the selection. + */ +void QScatter3DSeries::setSelectedItem(int index) +{ + // Don't do this in private to avoid loops, as that is used for callback from controller. + if (d_ptr->m_controller) + static_cast(d_ptr->m_controller)->setSelectedItem(index, this); + else + dptr()->setSelectedItem(index); +} + +int QScatter3DSeries::selectedItem() const +{ + return dptrc()->m_selectedItem; +} + +/*! + * \return an invalid index for selection. Set this index to selectedItem property if you + * want to clear the selection. + */ +int QScatter3DSeries::invalidSelectionIndex() const +{ + return Scatter3DController::invalidSelectionIndex(); +} + /*! * \internal */ @@ -144,7 +177,8 @@ const QScatter3DSeriesPrivate *QScatter3DSeries::dptrc() const // QScatter3DSeriesPrivate QScatter3DSeriesPrivate::QScatter3DSeriesPrivate(QScatter3DSeries *q) - : QAbstract3DSeriesPrivate(q, QAbstract3DSeries::SeriesTypeScatter) + : QAbstract3DSeriesPrivate(q, QAbstract3DSeries::SeriesTypeScatter), + m_selectedItem(Scatter3DController::invalidSelectionIndex()) { m_itemLabelFormat = QStringLiteral("@valueTitle: @valueLabel"); } @@ -179,7 +213,6 @@ void QScatter3DSeriesPrivate::connectControllerAndProxy(Abstract3DController *ne if (newController && scatterDataProxy) { Scatter3DController *controller = static_cast(newController); - QObject::connect(scatterDataProxy, &QScatterDataProxy::arrayReset, controller, &Scatter3DController::handleArrayReset); QObject::connect(scatterDataProxy, &QScatterDataProxy::itemsAdded, @@ -196,4 +229,12 @@ void QScatter3DSeriesPrivate::connectControllerAndProxy(Abstract3DController *ne } } +void QScatter3DSeriesPrivate::setSelectedItem(int index) +{ + if (index != m_selectedItem) { + m_selectedItem = index; + emit qptr()->selectedItemChanged(m_selectedItem); + } +} + QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/data/qscatter3dseries.h b/src/datavisualization/data/qscatter3dseries.h index bb24f79a..8c28f3a6 100644 --- a/src/datavisualization/data/qscatter3dseries.h +++ b/src/datavisualization/data/qscatter3dseries.h @@ -30,6 +30,7 @@ class QT_DATAVISUALIZATION_EXPORT QScatter3DSeries : public QAbstract3DSeries { Q_OBJECT Q_PROPERTY(QScatterDataProxy *dataProxy READ dataProxy WRITE setDataProxy NOTIFY dataProxyChanged) + Q_PROPERTY(int selectedItem READ selectedItem WRITE setSelectedItem NOTIFY selectedItemChanged) public: explicit QScatter3DSeries(QObject *parent = 0); @@ -39,8 +40,13 @@ public: void setDataProxy(QScatterDataProxy *proxy); QScatterDataProxy *dataProxy() const; + void setSelectedItem(int index); + int selectedItem() const; + Q_INVOKABLE int invalidSelectionIndex() const; + signals: void dataProxyChanged(QScatterDataProxy *proxy); + void selectedItemChanged(int index); protected: explicit QScatter3DSeries(QScatter3DSeriesPrivate *d, QObject *parent = 0); diff --git a/src/datavisualization/data/qscatter3dseries_p.h b/src/datavisualization/data/qscatter3dseries_p.h index b839af2e..0cf47bce 100644 --- a/src/datavisualization/data/qscatter3dseries_p.h +++ b/src/datavisualization/data/qscatter3dseries_p.h @@ -44,8 +44,11 @@ public: virtual void setDataProxy(QAbstractDataProxy *proxy); virtual void connectControllerAndProxy(Abstract3DController *newController); + void setSelectedItem(int index); + private: QScatter3DSeries *qptr(); + int m_selectedItem; private: friend class QScatter3DSeries; diff --git a/src/datavisualization/engine/bars3dcontroller.cpp b/src/datavisualization/engine/bars3dcontroller.cpp index 995633a8..b1cf8338 100644 --- a/src/datavisualization/engine/bars3dcontroller.cpp +++ b/src/datavisualization/engine/bars3dcontroller.cpp @@ -32,7 +32,7 @@ QT_DATAVISUALIZATION_BEGIN_NAMESPACE Bars3DController::Bars3DController(QRect boundRect) : Abstract3DController(boundRect), - m_selectedBar(noSelectionPoint()), + m_selectedBar(invalidSelectionPosition()), m_selectedBarSeries(0), m_isBarSpecRelative(true), m_barThicknessRatio(1.0f), @@ -179,11 +179,7 @@ void Bars3DController::handleDataColumnLabelsChanged() void Bars3DController::handleBarClicked(const QPoint &position, QBar3DSeries *series) { - // Series may already have been removed, so check it before setting the selection. - if (m_seriesList.contains(series)) - setSelectedBar(position, series); - else - setSelectedBar(noSelectionPoint(), 0); + setSelectedBar(position, series); // TODO: pass clicked to parent. (QTRD-2517) // TODO: Also hover needed? (QTRD-2131) @@ -206,7 +202,7 @@ void Bars3DController::handleSeriesVisibilityChangedBySender(QObject *sender) setSelectedBar(m_selectedBar, m_selectedBarSeries); } -QPoint Bars3DController::noSelectionPoint() +QPoint Bars3DController::invalidSelectionPosition() { static QPoint noSelectionPos(-1, -1); return noSelectionPos; @@ -240,7 +236,7 @@ void Bars3DController::addSeries(QAbstract3DSeries *series) } QBar3DSeries *barSeries = static_cast(series); - if (barSeries->selectedBar() != noSelectionPoint()) + if (barSeries->selectedBar() != invalidSelectionPosition()) setSelectedBar(barSeries->selectedBar(), barSeries); } @@ -249,7 +245,7 @@ void Bars3DController::removeSeries(QAbstract3DSeries *series) bool firstRemoved = (m_seriesList.size() && m_seriesList.at(0) == series); if (m_selectedBarSeries == series) - setSelectedBar(noSelectionPoint(), 0); + setSelectedBar(invalidSelectionPosition(), 0); Abstract3DController::removeSeries(series); @@ -365,6 +361,10 @@ void Bars3DController::setSelectedBar(const QPoint &position, QBar3DSeries *seri // If the selection targets non-existent bar, clear selection instead. QPoint pos = position; + // Series may already have been removed, so check it before setting the selection. + if (!m_seriesList.contains(series)) + series = 0; + adjustSelectionPosition(pos, series); if (selectionMode().testFlag(QDataVis::SelectionSlice)) { @@ -383,14 +383,15 @@ void Bars3DController::setSelectedBar(const QPoint &position, QBar3DSeries *seri m_selectedBar = pos; m_selectedBarSeries = series; m_changeTracker.selectedBarChanged = true; - // Clear selection from other series and set the new selection to the affected series + + // Clear selection from other series and finally set new selection to the specified series foreach (QAbstract3DSeries *otherSeries, m_seriesList) { QBar3DSeries *barSeries = static_cast(otherSeries); if (barSeries != m_selectedBarSeries) - barSeries->dptr()->setSelectedBar(noSelectionPoint()); - else - barSeries->dptr()->setSelectedBar(m_selectedBar); + barSeries->dptr()->setSelectedBar(invalidSelectionPosition()); } + if (m_selectedBarSeries) + m_selectedBarSeries->dptr()->setSelectedBar(m_selectedBar); emitNeedRender(); } @@ -449,15 +450,15 @@ void Bars3DController::adjustSelectionPosition(QPoint &pos, const QBar3DSeries * proxy = series->dataProxy(); if (!proxy) - pos = noSelectionPoint(); + pos = invalidSelectionPosition(); - if (pos != noSelectionPoint()) { + if (pos != invalidSelectionPosition()) { int maxRow = proxy->rowCount() - 1; int maxCol = (pos.x() <= maxRow && pos.x() >= 0 && proxy->rowAt(pos.x())) ? proxy->rowAt(pos.x())->size() - 1 : -1; if (pos.x() < 0 || pos.x() > maxRow || pos.y() < 0 || pos.y() > maxCol) - pos = noSelectionPoint(); + pos = invalidSelectionPosition(); } } diff --git a/src/datavisualization/engine/bars3dcontroller_p.h b/src/datavisualization/engine/bars3dcontroller_p.h index 4da6c730..e9f39541 100644 --- a/src/datavisualization/engine/bars3dcontroller_p.h +++ b/src/datavisualization/engine/bars3dcontroller_p.h @@ -96,7 +96,7 @@ public: virtual void handleAxisAutoAdjustRangeChangedInOrientation(Q3DAbstractAxis::AxisOrientation orientation, bool autoAdjust); virtual void handleSeriesVisibilityChangedBySender(QObject *sender); - static QPoint noSelectionPoint(); + static QPoint invalidSelectionPosition(); virtual void setAxisX(Q3DAbstractAxis *axis); virtual void setAxisZ(Q3DAbstractAxis *axis); diff --git a/src/datavisualization/engine/bars3drenderer.cpp b/src/datavisualization/engine/bars3drenderer.cpp index 7682f389..6c5d49c2 100644 --- a/src/datavisualization/engine/bars3drenderer.cpp +++ b/src/datavisualization/engine/bars3drenderer.cpp @@ -86,10 +86,10 @@ Bars3DRenderer::Bars3DRenderer(Bars3DController *controller) m_scaleZ(0), m_scaleFactor(0), m_maxSceneSize(40.0f), - m_visualSelectedBarPos(Bars3DController::noSelectionPoint()), + m_visualSelectedBarPos(Bars3DController::invalidSelectionPosition()), m_visualSelectedBarSeriesIndex(-1), m_hasHeightAdjustmentChanged(true), - m_selectedBarPos(Bars3DController::noSelectionPoint()), + m_selectedBarPos(Bars3DController::invalidSelectionPosition()), m_selectedBarSeries(0), m_noZeroInRange(false), m_seriesScale(0.0f), @@ -1025,7 +1025,7 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) BarRenderItem *selectedBar(0); QVector3D modelScaler(m_scaleX * m_seriesScale, 0.0f, m_scaleZ); - bool somethingSelected = (m_visualSelectedBarPos != Bars3DController::noSelectionPoint()); + bool somethingSelected = (m_visualSelectedBarPos != Bars3DController::invalidSelectionPosition()); for (int row = startRow; row != stopRow; row += stepRow) { for (int bar = startBar; bar != stopBar; bar += stepBar) { float seriesPos = m_seriesStart; @@ -1843,10 +1843,10 @@ void Bars3DRenderer::updateSelectedBar(const QPoint &position, const QBar3DSerie m_selectedBarPos = position; m_selectedBarSeries = series; m_selectionDirty = true; + m_visualSelectedBarSeriesIndex = -1; if (m_renderingArrays.isEmpty()) { - m_visualSelectedBarPos = Bars3DController::noSelectionPoint(); - m_visualSelectedBarSeriesIndex = -1; + m_visualSelectedBarPos = Bars3DController::invalidSelectionPosition(); return; } @@ -1855,7 +1855,6 @@ void Bars3DRenderer::updateSelectedBar(const QPoint &position, const QBar3DSerie int maxX = m_renderingArrays.at(0).size() - 1; int maxZ = maxX >= 0 ? m_renderingArrays.at(0).at(0).size() - 1 : -1; - m_visualSelectedBarSeriesIndex = -1; for (int i = 0; i < m_visibleSeriesList.size(); i++) { if (m_visibleSeriesList.at(i).series() == series) { m_visualSelectedBarSeriesIndex = i; @@ -1863,10 +1862,10 @@ void Bars3DRenderer::updateSelectedBar(const QPoint &position, const QBar3DSerie } } - if (m_selectedBarPos == Bars3DController::noSelectionPoint() + if (m_selectedBarPos == Bars3DController::invalidSelectionPosition() || adjustedX < 0 || adjustedX > maxX || adjustedZ < 0 || adjustedZ > maxZ) { - m_visualSelectedBarPos = Bars3DController::noSelectionPoint(); + m_visualSelectedBarPos = Bars3DController::invalidSelectionPosition(); } else { m_visualSelectedBarPos = QPoint(adjustedX, adjustedZ); } @@ -2028,7 +2027,7 @@ QPoint Bars3DRenderer::selectionColorToArrayPosition(const QVector3D &selectionC { QPoint position; if (selectionColor == selectionSkipColor) { - position = Bars3DController::noSelectionPoint(); + position = Bars3DController::invalidSelectionPosition(); } else { position = QPoint(int(selectionColor.x() + int(m_axisCacheX.min())), int(selectionColor.y()) + int(m_axisCacheZ.min())); diff --git a/src/datavisualization/engine/q3dbars.cpp b/src/datavisualization/engine/q3dbars.cpp index 60d827bd..6fef5be4 100644 --- a/src/datavisualization/engine/q3dbars.cpp +++ b/src/datavisualization/engine/q3dbars.cpp @@ -149,7 +149,7 @@ Q3DBars::~Q3DBars() * so the rows and columns of all series must match for the visualized data to be meaningful. * If the graph has multiple visible series, only the first one added will * generate the row or column labels on the axes in cases where the labels are not explicitly set - * to the axes. If newly added series has specified a selected bar, it will be highlighted and + * to the axes. If the newly added series has specified a selected bar, it will be highlighted and * any existing selection will be cleared. Only one added series can have an active selection. */ void Q3DBars::addSeries(QBar3DSeries *series) diff --git a/src/datavisualization/engine/q3dscatter.cpp b/src/datavisualization/engine/q3dscatter.cpp index 7aaa0e6b..c01b5747 100644 --- a/src/datavisualization/engine/q3dscatter.cpp +++ b/src/datavisualization/engine/q3dscatter.cpp @@ -102,8 +102,6 @@ Q3DScatter::Q3DScatter() &Q3DScatter::gridVisibleChanged); QObject::connect(d_ptr->m_shared, &Abstract3DController::backgroundVisibleChanged, this, &Q3DScatter::backgroundVisibleChanged); - QObject::connect(d_ptr->m_shared, &Scatter3DController::selectedItemIndexChanged, this, - &Q3DScatter::selectedItemIndexChanged); QObject::connect(d_ptr->m_shared, &Abstract3DController::colorStyleChanged, this, &Q3DScatter::colorStyleChanged); QObject::connect(d_ptr->m_shared, &Abstract3DController::objectColorChanged, this, @@ -131,7 +129,8 @@ Q3DScatter::~Q3DScatter() /*! * Adds the \a series to the graph. A graph can contain multiple series, but has only one set of - * axes. + * axes. If the newly added series has specified a selected item, it will be highlighted and + * any existing selection will be cleared. Only one added series can have an active selection. */ void Q3DScatter::addSeries(QScatter3DSeries *series) { @@ -368,22 +367,6 @@ bool Q3DScatter::isBackgroundVisible() const return d_ptr->m_shared->backgroundEnabled(); } -/*! - * \property Q3DScatter::selectedItemIndex - * - * Selects an item in the \a index. Only one item can be selected at a time. - * To clear selection, specify an illegal \a index, e.g. -1. - */ -void Q3DScatter::setSelectedItemIndex(int index) -{ - d_ptr->m_shared->setSelectedItemIndex(index); -} - -int Q3DScatter::selectedItemIndex() const -{ - return d_ptr->m_shared->selectedItemIndex(); -} - /*! * \property Q3DScatter::shadowQuality * diff --git a/src/datavisualization/engine/q3dscatter.h b/src/datavisualization/engine/q3dscatter.h index 2f403ce1..5f3a1024 100644 --- a/src/datavisualization/engine/q3dscatter.h +++ b/src/datavisualization/engine/q3dscatter.h @@ -44,7 +44,6 @@ class QT_DATAVISUALIZATION_EXPORT Q3DScatter : public Q3DWindow Q_PROPERTY(QtDataVisualization::QDataVis::Theme theme READ theme WRITE setTheme NOTIFY themeChanged) Q_PROPERTY(bool gridVisible READ isGridVisible WRITE setGridVisible NOTIFY gridVisibleChanged) Q_PROPERTY(bool backgroundVisible READ isBackgroundVisible WRITE setBackgroundVisible NOTIFY backgroundVisibleChanged) - Q_PROPERTY(int selectedItemIndex READ selectedItemIndex WRITE setSelectedItemIndex NOTIFY selectedItemIndexChanged) Q_PROPERTY(Q3DScene* scene READ scene) Q_PROPERTY(QtDataVisualization::QDataVis::ColorStyle colorStyle READ colorStyle WRITE setColorStyle NOTIFY colorStyleChanged) Q_PROPERTY(QColor itemColor READ itemColor WRITE setItemColor NOTIFY itemColorChanged) @@ -90,9 +89,6 @@ public: void setBackgroundVisible(bool visible); bool isBackgroundVisible() const; - void setSelectedItemIndex(int index); - int selectedItemIndex() const; - void setShadowQuality(QDataVis::ShadowQuality quality); QDataVis::ShadowQuality shadowQuality() const; @@ -131,7 +127,6 @@ signals: void themeChanged(QDataVis::Theme theme); void gridVisibleChanged(bool visible); void backgroundVisibleChanged(bool visible); - void selectedItemIndexChanged(int index); void colorStyleChanged(QDataVis::ColorStyle style); void itemColorChanged(QColor color); void itemGradientChanged(QLinearGradient gradient); diff --git a/src/datavisualization/engine/scatter3dcontroller.cpp b/src/datavisualization/engine/scatter3dcontroller.cpp index 11a2d03f..27d1b609 100644 --- a/src/datavisualization/engine/scatter3dcontroller.cpp +++ b/src/datavisualization/engine/scatter3dcontroller.cpp @@ -32,7 +32,8 @@ QT_DATAVISUALIZATION_BEGIN_NAMESPACE Scatter3DController::Scatter3DController(QRect boundRect) : Abstract3DController(boundRect), m_renderer(0), - m_selectedItemIndex(noSelectionIndex()) + m_selectedItem(invalidSelectionIndex()), + m_selectedItemSeries(0) { // Default object type; specific to scatter setObjectType(QDataVis::MeshStyleSpheres, false); @@ -72,9 +73,9 @@ void Scatter3DController::synchDataToRenderer() return; // Notify changes to renderer - if (m_changeTracker.selectedItemIndexChanged) { - m_renderer->updateSelectedItemIndex(m_selectedItemIndex); - m_changeTracker.selectedItemIndexChanged = false; + if (m_changeTracker.selectedItemChanged) { + m_renderer->updateSelectedItem(m_selectedItem, m_selectedItemSeries); + m_changeTracker.selectedItemChanged = false; } } @@ -86,24 +87,25 @@ void Scatter3DController::addSeries(QAbstract3DSeries *series) Abstract3DController::addSeries(series); - if (firstAdded) { + if (firstAdded) adjustValueAxisRange(); - // TODO: Temp until selection by series is properly implemented - setSelectedItemIndex(noSelectionIndex()); - } + + QScatter3DSeries *scatterSeries = static_cast(series); + if (scatterSeries->selectedItem() != invalidSelectionIndex()) + setSelectedItem(scatterSeries->selectedItem(), scatterSeries); } void Scatter3DController::removeSeries(QAbstract3DSeries *series) { bool firstRemoved = (m_seriesList.size() && m_seriesList.at(0) == series); + if (m_selectedItemSeries == series) + setSelectedItem(invalidSelectionIndex(), 0); + Abstract3DController::removeSeries(series); - if (firstRemoved) { + if (firstRemoved) adjustValueAxisRange(); - // TODO: Temp until selection by series is properly implemented - setSelectedItemIndex(noSelectionIndex()); - } } QList Scatter3DController::scatterSeriesList() @@ -123,7 +125,7 @@ void Scatter3DController::handleArrayReset() { adjustValueAxisRange(); m_isDataDirty = true; - setSelectedItemIndex(m_selectedItemIndex); + setSelectedItem(m_selectedItem, m_selectedItemSeries); emitNeedRender(); } @@ -154,9 +156,10 @@ void Scatter3DController::handleItemsRemoved(int startIndex, int count) // TODO should dirty only affected values? adjustValueAxisRange(); m_isDataDirty = true; - QScatterDataProxy *proxy = qobject_cast(sender()); - if (!proxy || startIndex >= proxy->itemCount()) - setSelectedItemIndex(noSelectionIndex()); + + // Clear selection unless it is still valid + setSelectedItem(m_selectedItem, m_selectedItemSeries); + emitNeedRender(); } @@ -170,9 +173,10 @@ void Scatter3DController::handleItemsInserted(int startIndex, int count) emitNeedRender(); } -void Scatter3DController::handleItemClicked(int index) +void Scatter3DController::handleItemClicked(int index, QScatter3DSeries *series) { - setSelectedItemIndex(index); + setSelectedItem(index, series); + // TODO: pass clicked to parent. (QTRD-2517) // TODO: Also hover needed? (QTRD-2131) } @@ -190,7 +194,7 @@ void Scatter3DController::handleAxisRangeChangedBySender(QObject *sender) Abstract3DController::handleAxisRangeChangedBySender(sender); // Update selected index - may be moved offscreen - setSelectedItemIndex(m_selectedItemIndex); + setSelectedItem(m_selectedItem, m_selectedItemSeries); } void Scatter3DController::setObjectType(QDataVis::MeshStyle style, bool smooth) @@ -222,28 +226,42 @@ void Scatter3DController::setSelectionMode(QDataVis::SelectionFlags mode) qWarning("Unsupported selection mode - only none and item selection modes are supported."); return; } + Abstract3DController::setSelectionMode(mode); } -void Scatter3DController::setSelectedItemIndex(int index) +void Scatter3DController::setSelectedItem(int index, QScatter3DSeries *series) { - // TODO: Support for multiple sets. Just remove the item count test for now - if (index < 0 /*|| index >= static_cast(m_data)->itemCount()*/) - index = noSelectionIndex(); - - if (index != m_selectedItemIndex) { - m_selectedItemIndex = index; - m_changeTracker.selectedItemIndexChanged = true; - emit selectedItemIndexChanged(index); + const QScatterDataProxy *proxy = 0; + + // Series may already have been removed, so check it before setting the selection. + if (!m_seriesList.contains(series)) + series = 0; + + if (series) + proxy = series->dataProxy(); + + if (!proxy || index < 0 || index >= proxy->itemCount()) + index = invalidSelectionIndex(); + + if (index != m_selectedItem || series != m_selectedItemSeries) { + m_selectedItem = index; + m_selectedItemSeries = series; + m_changeTracker.selectedItemChanged = true; + + // Clear selection from other series and finally set new selection to the specified series + foreach (QAbstract3DSeries *otherSeries, m_seriesList) { + QScatter3DSeries *scatterSeries = static_cast(otherSeries); + if (scatterSeries != m_selectedItemSeries) + scatterSeries->dptr()->setSelectedItem(invalidSelectionIndex()); + } + if (m_selectedItemSeries) + m_selectedItemSeries->dptr()->setSelectedItem(m_selectedItem); + emitNeedRender(); } } -int Scatter3DController::selectedItemIndex() const -{ - return m_selectedItemIndex; -} - void Scatter3DController::adjustValueAxisRange() { QVector3D minLimits; diff --git a/src/datavisualization/engine/scatter3dcontroller_p.h b/src/datavisualization/engine/scatter3dcontroller_p.h index a75b61ac..349b226a 100644 --- a/src/datavisualization/engine/scatter3dcontroller_p.h +++ b/src/datavisualization/engine/scatter3dcontroller_p.h @@ -41,10 +41,10 @@ class QScatterDataProxy; class QScatter3DSeries; struct Scatter3DChangeBitField { - bool selectedItemIndexChanged : 1; + bool selectedItemChanged : 1; Scatter3DChangeBitField() : - selectedItemIndexChanged(true) + selectedItemChanged(true) { } }; @@ -58,7 +58,9 @@ private: // Rendering Scatter3DRenderer *m_renderer; - int m_selectedItemIndex; + int m_selectedItem; + QScatter3DSeries *m_selectedItemSeries; // Points to the series for which the bar is selected + // in single series selection cases. public: explicit Scatter3DController(QRect rect); @@ -72,9 +74,8 @@ public: // Change selection mode void setSelectionMode(QDataVis::SelectionFlags mode); - void setSelectedItemIndex(int index); - int selectedItemIndex() const; - static inline int noSelectionIndex() { return -1; } + void setSelectedItem(int index, QScatter3DSeries *series); + static inline int invalidSelectionIndex() { return -1; } void synchDataToRenderer(); @@ -93,10 +94,7 @@ public slots: void handleItemsInserted(int startIndex, int count); // Renderer callback handlers - void handleItemClicked(int index); - -signals: - void selectedItemIndexChanged(int index); + void handleItemClicked(int index, QScatter3DSeries *series); private: void adjustValueAxisRange(); diff --git a/src/datavisualization/engine/scatter3drenderer.cpp b/src/datavisualization/engine/scatter3drenderer.cpp index 2abb4fe9..5f03f982 100644 --- a/src/datavisualization/engine/scatter3drenderer.cpp +++ b/src/datavisualization/engine/scatter3drenderer.cpp @@ -80,6 +80,10 @@ Scatter3DRenderer::Scatter3DRenderer(Scatter3DController *controller) m_shadowQualityMultiplier(3), m_heightNormalizer(1.0f), m_scaleFactor(0), + m_selectedItemIndex(Scatter3DController::invalidSelectionIndex()), + m_selectedItemTotalIndex(Scatter3DController::invalidSelectionIndex()), + m_selectedItemSeriesIndex(Scatter3DController::invalidSelectionIndex()), + m_selectedSeries(0), m_areaSize(QSizeF(0.0, 0.0)), m_dotSizeScale(1.0f), m_hasHeightAdjustmentChanged(true), @@ -180,7 +184,8 @@ void Scatter3DRenderer::updateData() } } m_dotSizeScale = (GLfloat)qBound(0.01, (2.0 / qSqrt((qreal)totalDataSize)), 0.1); - m_selectedItem = 0; + + updateSelectedItem(m_selectedItemIndex, m_selectedSeries); } void Scatter3DRenderer::updateScene(Q3DScene *scene) @@ -342,6 +347,7 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) modelMatrix.translate(item.translation()); if (!m_drawingPoints) { modelMatrix.scale(modelScaler); + // TODO: Remove all references to item size? //modelMatrix.scale(QVector3D(widthMultiplier * item.size() + widthScaler, // heightMultiplier * item.size() + heightScaler, // depthMultiplier * item.size() + depthScaler)); @@ -451,6 +457,7 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) modelMatrix.translate(item.translation()); if (!m_drawingPoints) { modelMatrix.scale(modelScaler); + // TODO: Remove all references to item size? //modelMatrix.scale(QVector3D(widthMultiplier * item.size() + widthScaler, // heightMultiplier * item.size() + heightScaler, // depthMultiplier * item.size() + depthScaler)); @@ -494,7 +501,10 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) // Read color under cursor QVector3D clickedColor = Utils::getSelection(m_inputPosition, m_cachedBoundingRect.height()); - emit itemClicked(selectionColorToIndex(clickedColor)); + int clickedIndex = 0; + QScatter3DSeries *clickedSeries = 0; + selectionColorToSeriesAndIndex(clickedColor, clickedIndex, clickedSeries); + emit itemClicked(clickedIndex, clickedSeries); glBindFramebuffer(GL_FRAMEBUFFER, defaultFboHandle); @@ -556,7 +566,6 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) // Draw dots bool dotSelectionFound = false; ScatterRenderItem *selectedItem(0); - int selectedSeriesIndex(0); int dotNo = 0; for (int series = 0; series < seriesCount; series++) { @@ -577,6 +586,7 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) if (!m_drawingPoints) { modelMatrix.scale(modelScaler); itModelMatrix.scale(modelScaler); + // TODO: Remove all references to item size? //modelMatrix.scale(QVector3D(widthMultiplier * item.size() + widthScaler, // heightMultiplier * item.size() + heightScaler, // depthMultiplier * item.size() + depthScaler)); @@ -596,7 +606,7 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) gradientTexture = m_objectGradientTexture; GLfloat lightStrength = m_cachedTheme.m_lightStrength; - if (m_cachedSelectionMode > QDataVis::SelectionNone && (m_selectedItemIndex == dotNo)) { + if (m_cachedSelectionMode > QDataVis::SelectionNone && (m_selectedItemTotalIndex == dotNo)) { if (m_cachedColorStyle == QDataVis::ColorStyleUniform || m_drawingPoints) dotColor = Utils::vectorFromColor(m_cachedSingleHighlightColor); else @@ -604,7 +614,6 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) lightStrength = m_cachedTheme.m_highlightLightStrength; // Insert data to ScatterRenderItem. We have no ownership, don't delete the previous one selectedItem = &item; - selectedSeriesIndex = series; dotSelectionFound = true; } @@ -1359,7 +1368,7 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) static const QString yLabelTag(QStringLiteral("@yLabel")); static const QString zLabelTag(QStringLiteral("@zLabel")); - labelText = m_visibleSeriesList[selectedSeriesIndex].itemLabelFormat(); + labelText = m_visibleSeriesList[m_selectedItemSeriesIndex].itemLabelFormat(); labelText.replace(xTitleTag, m_axisCacheX.title()); labelText.replace(yTitleTag, m_axisCacheY.title()); @@ -1410,12 +1419,30 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) // Release label shader m_labelShader->release(); + + m_selectionDirty = false; } -void Scatter3DRenderer::updateSelectedItemIndex(int index) +void Scatter3DRenderer::updateSelectedItem(int index, const QScatter3DSeries *series) { m_selectionDirty = true; - m_selectedItemIndex = index; + m_selectedSeries = series; + m_selectedItemIndex = Scatter3DController::invalidSelectionIndex(); + m_selectedItemTotalIndex = Scatter3DController::invalidSelectionIndex(); + m_selectedItemSeriesIndex = Scatter3DController::invalidSelectionIndex(); + + if (!m_renderingArrays.isEmpty() && index != Scatter3DController::invalidSelectionIndex()) { + int totalIndex = 0; + for (int i = 0; i < m_visibleSeriesList.size(); i++) { + if (m_visibleSeriesList.at(i).series() == series) { + m_selectedItemSeriesIndex = i; + m_selectedItemIndex = index; + m_selectedItemTotalIndex = index + totalIndex; + break; + } + totalIndex += m_renderingArrays.at(i).size(); + } + } } void Scatter3DRenderer::handleResize() @@ -1656,17 +1683,26 @@ QVector3D Scatter3DRenderer::indexToSelectionColor(GLint index) return QVector3D(dotIdxRed, dotIdxGreen, dotIdxBlue); } -int Scatter3DRenderer::selectionColorToIndex(const QVector3D &color) +void Scatter3DRenderer::selectionColorToSeriesAndIndex(const QVector3D &color, int &index, QScatter3DSeries *&series) { - int selectedIndex; - if (color == selectionSkipColor) { - selectedIndex = Scatter3DController::noSelectionIndex(); - } else { - selectedIndex = int(color.x()) + if (color != selectionSkipColor) { + index = int(color.x()) + (int(color.y()) << 8) + (int(color.z()) << 16); + // Find the series and adjust the index accordingly + for (int i = 0; i < m_renderingArrays.size(); i++) { + if (index < m_renderingArrays.at(i).size()) { + series = static_cast(m_visibleSeriesList.at(i).series()); + return; // Valid found and already set to return parameters, so we can return + } else { + index -= m_renderingArrays.at(i).size(); + } + } } - return selectedIndex; + + // No valid match found + index = Scatter3DController::invalidSelectionIndex(); + series = 0; } QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/engine/scatter3drenderer_p.h b/src/datavisualization/engine/scatter3drenderer_p.h index bba790a1..6f8f9cbd 100644 --- a/src/datavisualization/engine/scatter3drenderer_p.h +++ b/src/datavisualization/engine/scatter3drenderer_p.h @@ -82,6 +82,9 @@ private: GLfloat m_heightNormalizer; GLfloat m_scaleFactor; int m_selectedItemIndex; + int m_selectedItemTotalIndex; + int m_selectedItemSeriesIndex; + const QScatter3DSeries *m_selectedSeries; QSizeF m_areaSize; GLfloat m_dotSizeScale; QVector3D m_translationOffset; @@ -139,14 +142,14 @@ public slots: // Overloaded from abstract renderer virtual void updateAxisRange(Q3DAbstractAxis::AxisOrientation orientation, qreal min, qreal max); - void updateSelectedItemIndex(int index); + void updateSelectedItem(int index, const QScatter3DSeries *series); signals: - void itemClicked(int index); + void itemClicked(int index, QScatter3DSeries *series); private: QVector3D indexToSelectionColor(GLint index); - int selectionColorToIndex(const QVector3D &color); + void selectionColorToSeriesAndIndex(const QVector3D &color, int &index, QScatter3DSeries *&series); }; QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualizationqml2/declarativescatter.cpp b/src/datavisualizationqml2/declarativescatter.cpp index 1a05c425..b71fb820 100644 --- a/src/datavisualizationqml2/declarativescatter.cpp +++ b/src/datavisualizationqml2/declarativescatter.cpp @@ -41,8 +41,6 @@ DeclarativeScatter::DeclarativeScatter(QQuickItem *parent) m_shared = new Scatter3DController(boundingRect().toRect()); setSharedController(m_shared); - QObject::connect(m_shared, &Scatter3DController::selectedItemIndexChanged, this, - &DeclarativeScatter::selectedItemIndexChanged); QObject::connect(m_shared, &Abstract3DController::meshFileNameChanged, this, &DeclarativeScatter::meshFileNameChanged); } @@ -159,16 +157,6 @@ QString DeclarativeScatter::meshFileName() const return m_shared->meshFileName(); } -void DeclarativeScatter::setSelectedItemIndex(int index) -{ - m_shared->setSelectedItemIndex(index); -} - -int DeclarativeScatter::selectedItemIndex() const -{ - return m_shared->selectedItemIndex(); -} - QQmlListProperty DeclarativeScatter::seriesList() { return QQmlListProperty(this, this, diff --git a/src/datavisualizationqml2/declarativescatter_p.h b/src/datavisualizationqml2/declarativescatter_p.h index 20455b29..d42c3b23 100644 --- a/src/datavisualizationqml2/declarativescatter_p.h +++ b/src/datavisualizationqml2/declarativescatter_p.h @@ -52,7 +52,6 @@ class DeclarativeScatter : public AbstractDeclarative Q_PROPERTY(QtDataVisualization::QDataVis::MeshStyle objectType READ objectType WRITE setObjectType NOTIFY meshFileNameChanged) Q_PROPERTY(bool objectSmoothingEnabled READ isObjectSmoothingEnabled WRITE setObjectSmoothingEnabled NOTIFY meshFileNameChanged) Q_PROPERTY(QString meshFileName READ meshFileName WRITE setMeshFileName NOTIFY meshFileNameChanged) - Q_PROPERTY(int selectedItemIndex READ selectedItemIndex WRITE setSelectedItemIndex NOTIFY selectedItemIndexChanged) Q_PROPERTY(QQmlListProperty seriesList READ seriesList) Q_CLASSINFO("DefaultProperty", "seriesList") @@ -78,9 +77,6 @@ public: void setMeshFileName(const QString &objFileName); QString meshFileName() const; - void setSelectedItemIndex(int index); - int selectedItemIndex() const; - QQmlListProperty seriesList(); static void appendSeriesFunc(QQmlListProperty *list, QScatter3DSeries *series); static int countSeriesFunc(QQmlListProperty *list); @@ -90,7 +86,6 @@ public: Q_INVOKABLE void removeSeries(QScatter3DSeries *series); signals: - void selectedItemIndexChanged(int index); void meshFileNameChanged(QString filename); protected: diff --git a/src/datavisualizationqml2/declarativeseries.cpp b/src/datavisualizationqml2/declarativeseries.cpp index 8b7c0584..56601f83 100644 --- a/src/datavisualizationqml2/declarativeseries.cpp +++ b/src/datavisualizationqml2/declarativeseries.cpp @@ -57,6 +57,11 @@ QPointF DeclarativeBar3DSeries::selectedBar() const return QBar3DSeries::selectedBar(); } +QPointF DeclarativeBar3DSeries::invalidSelectionPosition() const +{ + return QPointF(QBar3DSeries::invalidSelectionPosition()); +} + DeclarativeScatter3DSeries::DeclarativeScatter3DSeries(QObject *parent) : QScatter3DSeries(parent) { diff --git a/src/datavisualizationqml2/declarativeseries_p.h b/src/datavisualizationqml2/declarativeseries_p.h index ac45ec3e..72b7cbcb 100644 --- a/src/datavisualizationqml2/declarativeseries_p.h +++ b/src/datavisualizationqml2/declarativeseries_p.h @@ -54,6 +54,7 @@ public: void setSelectedBar(const QPointF &position); QPointF selectedBar() const; + Q_INVOKABLE QPointF invalidSelectionPosition() const; signals: void selectedBarChanged(QPointF position); -- cgit v1.2.3