diff options
51 files changed, 800 insertions, 560 deletions
diff --git a/examples/audiolevels/audiolevels.cpp b/examples/audiolevels/audiolevels.cpp index 0922e664..307240c5 100644 --- a/examples/audiolevels/audiolevels.cpp +++ b/examples/audiolevels/audiolevels.cpp @@ -44,7 +44,7 @@ AudioLevels::AudioLevels(Q3DBars *graph, QObject *parent) m_graph->valueAxis()->setSegmentCount(20); m_graph->valueAxis()->setLabelFormat(QStringLiteral("%d%%")); m_graph->setShadowQuality(QDataVis::ShadowQualityNone); - m_graph->setSelectionMode(QDataVis::SelectionModeNone); + m_graph->setSelectionMode(QDataVis::SelectionNone); m_graph->scene()->activeCamera()->setCameraPosition(-25.0, 10.0, 190.0); m_graph->setTheme(QDataVis::ThemeIsabelle); m_graph->setBarType(QDataVis::MeshStyleBars); diff --git a/examples/bars/graphmodifier.cpp b/examples/bars/graphmodifier.cpp index e2ace423..89c651ff 100644 --- a/examples/bars/graphmodifier.cpp +++ b/examples/bars/graphmodifier.cpp @@ -23,6 +23,7 @@ #include <QtDataVisualization/q3dscene.h> #include <QtDataVisualization/q3dcamera.h> #include <QTime> +#include <QComboBox> QT_DATAVISUALIZATION_USE_NAMESPACE @@ -167,7 +168,11 @@ void GraphModifier::changeLabelStyle() void GraphModifier::changeSelectionMode(int selectionMode) { - m_graph->setSelectionMode((QDataVis::SelectionMode)selectionMode); + QComboBox *comboBox = qobject_cast<QComboBox *>(sender()); + if (comboBox) { + int flags = comboBox->itemData(selectionMode).toInt(); + m_graph->setSelectionMode(QDataVis::SelectionFlags(flags)); + } } void GraphModifier::changeFont(const QFont &font) diff --git a/examples/bars/main.cpp b/examples/bars/main.cpp index 158244b4..fc3737f6 100644 --- a/examples/bars/main.cpp +++ b/examples/bars/main.cpp @@ -84,13 +84,30 @@ int main(int argc, char **argv) cameraButton->setText(QStringLiteral("Change camera preset")); QComboBox *selectionModeList = new QComboBox(widget); - selectionModeList->addItem(QStringLiteral("None")); - selectionModeList->addItem(QStringLiteral("Bar")); - selectionModeList->addItem(QStringLiteral("Bar and Row")); - selectionModeList->addItem(QStringLiteral("Bar and Column")); - selectionModeList->addItem(QStringLiteral("Bar, Row and Column")); - selectionModeList->addItem(QStringLiteral("Slice into Row")); - selectionModeList->addItem(QStringLiteral("Slice into Column")); + selectionModeList->addItem(QStringLiteral("None"), + int(QDataVis::SelectionNone)); + selectionModeList->addItem(QStringLiteral("Bar"), + int(QDataVis::SelectionItem)); + selectionModeList->addItem(QStringLiteral("Row"), + int(QDataVis::SelectionRow)); + selectionModeList->addItem(QStringLiteral("Bar and Row"), + int(QDataVis::SelectionItemAndRow)); + selectionModeList->addItem(QStringLiteral("Column"), + int(QDataVis::SelectionColumn)); + selectionModeList->addItem(QStringLiteral("Bar and Column"), + int(QDataVis::SelectionItemAndColumn)); + selectionModeList->addItem(QStringLiteral("Row and Column"), + int(QDataVis::SelectionRowAndColumn)); + selectionModeList->addItem(QStringLiteral("Bar, Row and Column"), + int(QDataVis::SelectionItemRowAndColumn)); + selectionModeList->addItem(QStringLiteral("Slice into Row"), + int(QDataVis::SelectionSlice | QDataVis::SelectionRow)); + selectionModeList->addItem(QStringLiteral("Slice into Row and Item"), + int(QDataVis::SelectionSlice | QDataVis::SelectionItemAndRow)); + selectionModeList->addItem(QStringLiteral("Slice into Column"), + int(QDataVis::SelectionSlice | QDataVis::SelectionColumn)); + selectionModeList->addItem(QStringLiteral("Slice into Column and Item"), + int(QDataVis::SelectionSlice | QDataVis::SelectionItemAndColumn)); selectionModeList->setCurrentIndex(1); QCheckBox *backgroundCheckBox = new QCheckBox(widget); diff --git a/examples/customproxy/rainfallgraph.cpp b/examples/customproxy/rainfallgraph.cpp index 3a9f820a..0327ecb9 100644 --- a/examples/customproxy/rainfallgraph.cpp +++ b/examples/customproxy/rainfallgraph.cpp @@ -69,7 +69,7 @@ RainfallGraph::RainfallGraph(Q3DBars *rainfall) m_graph->setFont(QFont("Century Gothic", 30)); // Set selection mode to bar and column - m_graph->setSelectionMode(QDataVis::SelectionModeSliceColumn); + m_graph->setSelectionMode(QDataVis::SelectionItemAndColumn | QDataVis::SelectionSlice); // Set theme m_graph->setTheme(QDataVis::ThemeArmyBlue); diff --git a/examples/itemmodel/doc/src/itemmodel.qdoc b/examples/itemmodel/doc/src/itemmodel.qdoc index 682ebb1f..6c192f6f 100644 --- a/examples/itemmodel/doc/src/itemmodel.qdoc +++ b/examples/itemmodel/doc/src/itemmodel.qdoc @@ -164,7 +164,7 @@ Now we'll find out what these were for. The first one connects a signal from Q3DBars to the GraphDataGenerator. Signal - Q3DBars::selectedBarPosChanged() is emitted when a bar is selected from the graph. We connect + Q3DBars::selectedBarChanged() is emitted when a bar is selected from the graph. We connect that to a method in the data generator that selects the same data item in the table widget: \snippet ../examples/itemmodel/main.cpp 13 diff --git a/examples/itemmodel/main.cpp b/examples/itemmodel/main.cpp index fac6b442..5964992d 100644 --- a/examples/itemmodel/main.cpp +++ b/examples/itemmodel/main.cpp @@ -90,7 +90,7 @@ GraphDataGenerator::GraphDataGenerator(Q3DBars *bargraph, QTableWidget *tableWid m_tableWidget->setColumnCount(m_columnCount); // Set selection mode to full - m_graph->setSelectionMode(QDataVis::SelectionModeItemRowAndColumn); + m_graph->setSelectionMode(QDataVis::SelectionItemRowAndColumn); // Hide axis labels by explicitly setting one empty string as label list m_graph->rowAxis()->setCategoryLabels(QStringList(QString())); @@ -101,7 +101,7 @@ GraphDataGenerator::GraphDataGenerator(Q3DBars *bargraph, QTableWidget *tableWid //! [6] // Set selection mode to slice row - m_graph->setSelectionMode(QDataVis::SelectionModeSliceRow); + m_graph->setSelectionMode(QDataVis::SelectionItemAndRow | QDataVis::SelectionSlice); // Set font m_graph->setFont(QFont("Impact", 20)); @@ -222,7 +222,7 @@ void GraphDataGenerator::selectedFromTable(int currentRow, int currentColumn, { Q_UNUSED(previousRow) Q_UNUSED(previousColumn) - m_graph->setSelectedBarPos(QPoint(currentRow, currentColumn)); + m_graph->setSelectedBar(QPoint(currentRow, currentColumn)); } //! [14] @@ -273,7 +273,7 @@ int main(int argc, char **argv) //! [3] GraphDataGenerator generator(graph, tableWidget); - QObject::connect(graph, &Q3DBars::selectedBarPosChanged, &generator, + QObject::connect(graph, &Q3DBars::selectedBarChanged, &generator, &GraphDataGenerator::selectFromTable); QObject::connect(tableWidget, &QTableWidget::currentCellChanged, &generator, &GraphDataGenerator::selectedFromTable); diff --git a/examples/qmlbars/qml/qmlbars/main.qml b/examples/qmlbars/qml/qmlbars/main.qml index 5b1cc006..3d8aa7e0 100644 --- a/examples/qmlbars/qml/qmlbars/main.qml +++ b/examples/qmlbars/qml/qmlbars/main.qml @@ -46,7 +46,7 @@ Item { width: dataView.width height: dataView.height shadowQuality: AbstractGraph3D.ShadowQualityMedium - selectionMode: AbstractGraph3D.SelectionModeItem + selectionMode: AbstractGraph3D.SelectionItem font.pointSize: 35 theme: AbstractGraph3D.ThemeRetro labelStyle: AbstractGraph3D.LabelStyleFromTheme @@ -59,7 +59,7 @@ Item { valueAxis: graphAxes.expenses itemLabelFormat: "@valueTitle for @colLabel, @rowLabel: @valueLabel" - onSelectedBarPosChanged: { + onSelectedBarChanged: { // Set tableView current row to selected bar var rowRole = graphData.proxy.rowLabels[position.x]; var colRole = graphData.proxy.columnLabels[position.y]; @@ -161,7 +161,7 @@ Item { onCurrentRowChanged: { var rowIndex = graphData.proxy.activeMapping.rowCategoryIndex(graphData.model.get(currentRow).year) var colIndex = graphData.proxy.activeMapping.columnCategoryIndex(graphData.model.get(currentRow).month) - testGraph.selectedBarPos = Qt.point(rowIndex, colIndex) + testGraph.selectedBar = Qt.point(rowIndex, colIndex) } //! [2] } diff --git a/examples/qmlsurface/qml/qmlsurface/main.qml b/examples/qmlsurface/qml/qmlsurface/main.qml index bc8d9499..b4ea17f6 100644 --- a/examples/qmlsurface/qml/qmlsurface/main.qml +++ b/examples/qmlsurface/qml/qmlsurface/main.qml @@ -51,7 +51,7 @@ Item { height: surfaceView.height theme: AbstractGraph3D.ThemeStoneMoss shadowQuality: AbstractGraph3D.ShadowQualityMedium - selectionMode: AbstractGraph3D.SelectionModeSliceRow + selectionMode: AbstractGraph3D.SelectionSlice | AbstractGraph3D.SelectionItemAndRow smoothSurfaceEnabled: true surfaceGridEnabled: false font.family: "STCaiyun" diff --git a/examples/surface/surfacegraph.h b/examples/surface/surfacegraph.h index ac297bf6..ff0e5fc4 100644 --- a/examples/surface/surfacegraph.h +++ b/examples/surface/surfacegraph.h @@ -37,10 +37,12 @@ public: void enableSqrtSinModel(); //! [0] - void toggleModeNone() { m_graph->setSelectionMode(QDataVis::SelectionModeNone); } - void toggleModeItem() { m_graph->setSelectionMode(QDataVis::SelectionModeItem); } - void toggleModeSliceRow() { m_graph->setSelectionMode(QDataVis::SelectionModeSliceRow); } - void toggleModeSliceColumn() { m_graph->setSelectionMode(QDataVis::SelectionModeSliceColumn); } + void toggleModeNone() { m_graph->setSelectionMode(QDataVis::SelectionNone); } + void toggleModeItem() { m_graph->setSelectionMode(QDataVis::SelectionItem); } + void toggleModeSliceRow() { m_graph->setSelectionMode(QDataVis::SelectionItemAndRow + | QDataVis::SelectionSlice); } + void toggleModeSliceColumn() { m_graph->setSelectionMode(QDataVis::SelectionItemAndColumn + | QDataVis::SelectionSlice); } //! [0] void setBlackToYellowGradient(); diff --git a/src/datavisualization/doc/src/qtdatavisualization-qml-bars3d.qdoc b/src/datavisualization/doc/src/qtdatavisualization-qml-bars3d.qdoc index 5e6ef522..5d2178cf 100644 --- a/src/datavisualization/doc/src/qtdatavisualization-qml-bars3d.qdoc +++ b/src/datavisualization/doc/src/qtdatavisualization-qml-bars3d.qdoc @@ -130,7 +130,7 @@ */ /*! - * \qmlproperty point Bars3D::selectedBarPos + * \qmlproperty point Bars3D::selectedBar * Position of the selected bar in data window. Only one bar can be selected at a time. * To clear selection, specify an illegal position, e.g. Qt.point(-1.0, -1.0). */ diff --git a/src/datavisualization/doc/src/qtdatavisualization.qdoc b/src/datavisualization/doc/src/qtdatavisualization.qdoc index 02c303d6..77596dfa 100644 --- a/src/datavisualization/doc/src/qtdatavisualization.qdoc +++ b/src/datavisualization/doc/src/qtdatavisualization.qdoc @@ -261,7 +261,7 @@ All visualization types support selecting a single data item - a bar, a scatter item, or a surface vertex - using mouse, touch, and programmatically via the graph APIs. The selected item is highlighted in the rendered graph, and selecting causes emission of a graph specific signal for this purpose, - for example, Q3DBars::selectedBarPosChanged(), which the application can handle. + for example, Q3DBars::selectedBarChanged(), which the application can handle. \note The surface graph doesn't have a fully implemented selection API yet. It only supports selection with mouse and touch in the technology preview version. diff --git a/src/datavisualization/engine/abstract3dcontroller.cpp b/src/datavisualization/engine/abstract3dcontroller.cpp index bfdc375e..5a9d8a7a 100644 --- a/src/datavisualization/engine/abstract3dcontroller.cpp +++ b/src/datavisualization/engine/abstract3dcontroller.cpp @@ -37,7 +37,7 @@ Abstract3DController::Abstract3DController(QRect boundRect, QObject *parent) : m_boundingRect(boundRect.x(), boundRect.y(), boundRect.width(), boundRect.height()), m_theme(), m_font(QFont(QStringLiteral("Arial"))), - m_selectionMode(QDataVis::SelectionModeItem), + m_selectionMode(QDataVis::SelectionItem), m_shadowQuality(QDataVis::ShadowQualityMedium), m_labelStyle(QDataVis::LabelStyleTransparent), m_isBackgroundEnabled(true), @@ -63,7 +63,7 @@ Abstract3DController::Abstract3DController(QRect boundRect, QObject *parent) : inputHandler->d_ptr->m_isDefaultHandler = true; setActiveInputHandler(inputHandler); connect(inputHandler, &QAbstract3DInputHandler::inputStateChanged, this, - &Abstract3DController::emitNeedRender); + &Abstract3DController::handleInputStateChanged); connect(m_scene, &Q3DScene::needRender, this, &Abstract3DController::emitNeedRender); } @@ -705,14 +705,16 @@ QFont Abstract3DController::font() return m_font; } -void Abstract3DController::setSelectionMode(QDataVis::SelectionMode mode) +void Abstract3DController::setSelectionMode(QDataVis::SelectionFlags mode) { - m_selectionMode = mode; - m_changeTracker.selectionModeChanged = true; - emitNeedRender(); + if (mode != m_selectionMode) { + m_selectionMode = mode; + m_changeTracker.selectionModeChanged = true; + emitNeedRender(); + } } -QDataVis::SelectionMode Abstract3DController::selectionMode() +QDataVis::SelectionFlags Abstract3DController::selectionMode() { return m_selectionMode; } @@ -927,6 +929,16 @@ void Abstract3DController::handleAxisLabelFormatChanged(const QString &format) handleAxisLabelFormatChangedBySender(sender()); } +void Abstract3DController::handleInputStateChanged(QDataVis::InputState state) +{ + // When in automatic slicing mode, input state change to overview disables slice mode + if (m_selectionMode.testFlag(QDataVis::SelectionSlice) + && state == QDataVis::InputStateOnOverview) { + setSlicingActive(false); + } + emitNeedRender(); +} + void Abstract3DController::handleAxisLabelFormatChangedBySender(QObject *sender) { // Label format changing needs to dirty the data so that labels are reset. diff --git a/src/datavisualization/engine/abstract3dcontroller_p.h b/src/datavisualization/engine/abstract3dcontroller_p.h index f17c6c4d..dd5a56ce 100644 --- a/src/datavisualization/engine/abstract3dcontroller_p.h +++ b/src/datavisualization/engine/abstract3dcontroller_p.h @@ -148,7 +148,7 @@ private: GLfloat m_verticalRotation; Theme m_theme; QFont m_font; - QDataVis::SelectionMode m_selectionMode; + QDataVis::SelectionFlags m_selectionMode; QDataVis::ShadowQuality m_shadowQuality; QDataVis::LabelStyle m_labelStyle; bool m_isBackgroundEnabled; @@ -254,8 +254,8 @@ public: virtual QFont font(); // Selection mode - virtual void setSelectionMode(QDataVis::SelectionMode mode); - virtual QDataVis::SelectionMode selectionMode(); + virtual void setSelectionMode(QDataVis::SelectionFlags mode); + virtual QDataVis::SelectionFlags selectionMode(); // Adjust shadow quality virtual void setShadowQuality(QDataVis::ShadowQuality quality); @@ -312,6 +312,7 @@ public slots: void handleAxisSubSegmentCountChanged(int count); void handleAxisAutoAdjustRangeChanged(bool autoAdjust); void handleAxisLabelFormatChanged(const QString &format); + void handleInputStateChanged(QDataVis::InputState state); signals: void shadowQualityChanged(QDataVis::ShadowQuality quality); diff --git a/src/datavisualization/engine/abstract3drenderer.cpp b/src/datavisualization/engine/abstract3drenderer.cpp index eef810df..a11363a9 100644 --- a/src/datavisualization/engine/abstract3drenderer.cpp +++ b/src/datavisualization/engine/abstract3drenderer.cpp @@ -37,10 +37,11 @@ Abstract3DRenderer::Abstract3DRenderer(Abstract3DController *controller) m_cachedBoundingRect(QRect(0,0,0,0)), m_cachedShadowQuality(QDataVis::ShadowQualityMedium), m_autoScaleAdjustment(1.0f), - m_cachedSelectionMode(QDataVis::SelectionModeNone), + m_cachedSelectionMode(QDataVis::SelectionNone), m_cachedIsGridEnabled(false), m_cachedIsBackgroundEnabled(false), - m_cachedScene(new Q3DScene()) + m_cachedScene(new Q3DScene()), + m_selectionDirty(true) #ifdef DISPLAY_RENDER_SPEED , m_isFirstFrame(true), m_numFrames(0) @@ -221,9 +222,10 @@ void Abstract3DRenderer::updateMeshFileName(const QString &objFileName) } } -void Abstract3DRenderer::updateSelectionMode(QDataVis::SelectionMode mode) +void Abstract3DRenderer::updateSelectionMode(QDataVis::SelectionFlags mode) { m_cachedSelectionMode = mode; + m_selectionDirty = true; } void Abstract3DRenderer::updateGridEnabled(bool enable) diff --git a/src/datavisualization/engine/abstract3drenderer_p.h b/src/datavisualization/engine/abstract3drenderer_p.h index 1c61ac07..b3ee6eac 100644 --- a/src/datavisualization/engine/abstract3drenderer_p.h +++ b/src/datavisualization/engine/abstract3drenderer_p.h @@ -42,6 +42,9 @@ QT_DATAVISUALIZATION_BEGIN_NAMESPACE +static const QVector3D selectionSkipColor = QVector3D(255.0f, 255.0f, 255.0f); // Selection texture's background color +static const QVector3D invalidColorVector = QVector3D(-1.0f, -1.0f, -1.0f); + class TextureHelper; class Theme; class Drawer; @@ -65,7 +68,7 @@ protected: QString m_cachedItemLabelFormat; QString m_cachedObjFile; - QDataVis::SelectionMode m_cachedSelectionMode; + QDataVis::SelectionFlags m_cachedSelectionMode; bool m_cachedIsGridEnabled; bool m_cachedIsBackgroundEnabled; @@ -76,6 +79,7 @@ protected: Q3DBox m_boundingBox; Q3DScene *m_cachedScene; + bool m_selectionDirty; #ifdef DISPLAY_RENDER_SPEED bool m_isFirstFrame; @@ -98,7 +102,7 @@ public: virtual void updateTheme(Theme theme); virtual void updateFont(const QFont &font); virtual void updateLabelStyle(QDataVis::LabelStyle style); - virtual void updateSelectionMode(QDataVis::SelectionMode newMode); + virtual void updateSelectionMode(QDataVis::SelectionFlags newMode); virtual void updateGridEnabled(bool enable); virtual void updateBackgroundEnabled(bool enable); virtual void updateMeshFileName(const QString &objFileName); diff --git a/src/datavisualization/engine/bars3dcontroller.cpp b/src/datavisualization/engine/bars3dcontroller.cpp index 2eea6c74..dc1a9401 100644 --- a/src/datavisualization/engine/bars3dcontroller.cpp +++ b/src/datavisualization/engine/bars3dcontroller.cpp @@ -31,7 +31,7 @@ QT_DATAVISUALIZATION_BEGIN_NAMESPACE Bars3DController::Bars3DController(QRect boundRect) : Abstract3DController(boundRect), - m_selectedBarPos(noSelectionPoint()), + m_selectedBar(noSelectionPoint()), m_isBarSpecRelative(true), m_barThicknessRatio(1.0f), m_barSpacing(QSizeF(1.0, 1.0)), @@ -65,8 +65,8 @@ void Bars3DController::initializeOpenGL() setRenderer(m_renderer); synchDataToRenderer(); - QObject::connect(m_renderer, &Bars3DRenderer::selectedBarPosChanged, this, - &Bars3DController::handleSelectedBarPosChanged, Qt::QueuedConnection); + QObject::connect(m_renderer, &Bars3DRenderer::barClicked, this, + &Bars3DController::handleBarClicked, Qt::QueuedConnection); emitNeedRender(); } @@ -83,9 +83,9 @@ void Bars3DController::synchDataToRenderer() m_changeTracker.barSpecsChanged = false; } - if (m_changeTracker.selectedBarPosChanged) { - m_renderer->updateSelectedBarPos(m_selectedBarPos); - m_changeTracker.selectedBarPosChanged = false; + if (m_changeTracker.selectedBarChanged) { + m_renderer->updateSelectedBar(m_selectedBar); + m_changeTracker.selectedBarChanged = false; } if (m_isDataDirty) { @@ -125,11 +125,10 @@ void Bars3DController::setActiveDataProxy(QAbstractDataProxy *proxy) QObject::connect(barDataProxy, &QBarDataProxy::columnLabelsChanged, this, &Bars3DController::handleDataColumnLabelsChanged); - scene()->setSlicingActive(false); adjustAxisRanges(); // Always clear selection on proxy change - setSelectedBarPos(noSelectionPoint()); + setSelectedBar(noSelectionPoint()); handleDataRowLabelsChanged(); handleDataColumnLabelsChanged(); @@ -139,11 +138,10 @@ void Bars3DController::setActiveDataProxy(QAbstractDataProxy *proxy) void Bars3DController::handleArrayReset() { - scene()->setSlicingActive(false); adjustAxisRanges(); m_isDataDirty = true; // Clear selection unless still valid - setSelectedBarPos(m_selectedBarPos); + setSelectedBar(m_selectedBar); emitNeedRender(); } @@ -151,8 +149,6 @@ void Bars3DController::handleRowsAdded(int startIndex, int count) { Q_UNUSED(startIndex) Q_UNUSED(count) - // TODO should update slice instead of deactivating? - scene()->setSlicingActive(false); adjustAxisRanges(); m_isDataDirty = true; emitNeedRender(); @@ -162,8 +158,6 @@ void Bars3DController::handleRowsChanged(int startIndex, int count) { Q_UNUSED(startIndex) Q_UNUSED(count) - // TODO should update slice instead of deactivating? - scene()->setSlicingActive(false); adjustAxisRanges(); m_isDataDirty = true; emitNeedRender(); @@ -173,13 +167,11 @@ void Bars3DController::handleRowsRemoved(int startIndex, int count) { Q_UNUSED(startIndex) Q_UNUSED(count) - // TODO should update slice instead of deactivating? - scene()->setSlicingActive(false); adjustAxisRanges(); m_isDataDirty = true; // Clear selection unless still valid - setSelectedBarPos(m_selectedBarPos); + setSelectedBar(m_selectedBar); emitNeedRender(); } @@ -188,8 +180,6 @@ void Bars3DController::handleRowsInserted(int startIndex, int count) { Q_UNUSED(startIndex) Q_UNUSED(count) - // TODO should update slice instead of deactivating? - scene()->setSlicingActive(false); adjustAxisRanges(); m_isDataDirty = true; emitNeedRender(); @@ -199,8 +189,6 @@ void Bars3DController::handleItemChanged(int rowIndex, int columnIndex) { Q_UNUSED(rowIndex) Q_UNUSED(columnIndex) - // TODO should update slice instead of deactivating? - scene()->setSlicingActive(false); adjustAxisRanges(); m_isDataDirty = true; emitNeedRender(); @@ -228,16 +216,11 @@ void Bars3DController::handleDataColumnLabelsChanged() } } -void Bars3DController::handleSelectedBarPosChanged(const QPoint &position) +void Bars3DController::handleBarClicked(const QPoint &position) { - QPoint pos = position; - if (pos == QPoint(255, 255)) - pos = noSelectionPoint(); - if (pos != m_selectedBarPos) { - m_selectedBarPos = pos; - emit selectedBarPosChanged(pos); - emitNeedRender(); - } + setSelectedBar(position); + // TODO: pass clicked to parent. (QTRD-2517) + // TODO: Also hover needed? (QTRD-2131) } void Bars3DController::handleAxisAutoAdjustRangeChangedInOrientation( @@ -270,12 +253,6 @@ void Bars3DController::handleAxisRangeChangedBySender(QObject *sender) { // Data window changed if (sender == m_axisX || sender == m_axisZ) { - // Disable zoom mode if we're in it (causes crash if not, as zoom selection is deleted) - scene()->setSlicingActive(false); - - // Clear selection unless still valid - setSelectedBarPos(m_selectedBarPos); - if (sender == m_axisX) handleDataRowLabelsChanged(); if (sender == m_axisZ) @@ -283,6 +260,9 @@ void Bars3DController::handleAxisRangeChangedBySender(QObject *sender) } Abstract3DController::handleAxisRangeChangedBySender(sender); + + // Update selected bar - may be moved offscreen + setSelectedBar(m_selectedBar); } void Bars3DController::setBarSpecs(GLfloat thicknessRatio, const QSizeF &spacing, bool relative) @@ -330,43 +310,62 @@ void Bars3DController::setBarType(QDataVis::MeshStyle style, bool smooth) Abstract3DController::setMeshFileName(objFile); } -void Bars3DController::setSelectionMode(QDataVis::SelectionMode mode) +void Bars3DController::setSelectionMode(QDataVis::SelectionFlags mode) { - // Disable zoom if selection mode changes - scene()->setSlicingActive(false); - Abstract3DController::setSelectionMode(mode); + if (mode.testFlag(QDataVis::SelectionSlice) + && (mode.testFlag(QDataVis::SelectionRow) == mode.testFlag(QDataVis::SelectionColumn))) { + qWarning("Must specify one of either row or column selection mode in conjunction with slicing mode."); + } else { + // When setting selection mode to a new slicing mode, activate slicing + if (mode != selectionMode()) { + bool isSlicing = mode.testFlag(QDataVis::SelectionSlice); + if (isSlicing && m_selectedBar != noSelectionPoint()) + scene()->setSlicingActive(true); + else + scene()->setSlicingActive(false); + } + + Abstract3DController::setSelectionMode(mode); + } } -void Bars3DController::setSelectedBarPos(const QPoint &position) +void Bars3DController::setSelectedBar(const QPoint &position) { - // If the selection is outside data window or targets non-existent - // bar, clear selection instead. + // If the selection targets non-existent bar, clear selection instead. QPoint pos = position; if (pos != noSelectionPoint()) { - int minRow = int(m_axisX->min()); - int maxRow = int(m_axisX->max()); - int minCol = int(m_axisZ->min()); - int maxCol = int(m_axisZ->max()); - - if (pos.x() < minRow || pos.x() > maxRow || pos.y() < minCol || pos.y() > maxCol - || pos.x() + minRow >= static_cast<QBarDataProxy *>(m_data)->rowCount() - || pos.y() + minCol >= static_cast<QBarDataProxy *>(m_data)->rowAt(pos.x())->size()) { + const QBarDataProxy *proxy = static_cast<const QBarDataProxy *>(m_data); + 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(); + } + + if (selectionMode().testFlag(QDataVis::SelectionSlice)) { + // If the selected bar is outside data window, or there is no selected bar, disable slicing + if (pos.x() < m_axisX->min() || pos.x() > m_axisX->max() + || pos.y() < m_axisZ->min() || pos.y() > m_axisZ->max()) { + scene()->setSlicingActive(false); + } else { + scene()->setSlicingActive(true); } + emitNeedRender(); } - if (pos != m_selectedBarPos) { - m_selectedBarPos = pos; - m_changeTracker.selectedBarPosChanged = true; - emit selectedBarPosChanged(pos); + if (pos != m_selectedBar) { + m_selectedBar = pos; + m_changeTracker.selectedBarChanged = true; + emit selectedBarChanged(pos); emitNeedRender(); } } -QPoint Bars3DController::selectedBarPos() const +QPoint Bars3DController::selectedBar() const { - return m_selectedBarPos; + return m_selectedBar; } void Bars3DController::adjustAxisRanges() diff --git a/src/datavisualization/engine/bars3dcontroller_p.h b/src/datavisualization/engine/bars3dcontroller_p.h index 8398dd81..2e751053 100644 --- a/src/datavisualization/engine/bars3dcontroller_p.h +++ b/src/datavisualization/engine/bars3dcontroller_p.h @@ -42,12 +42,12 @@ class QBarDataProxy; struct Bars3DChangeBitField { bool slicingActiveChanged : 1; bool barSpecsChanged : 1; - bool selectedBarPosChanged : 1; + bool selectedBarChanged : 1; Bars3DChangeBitField() : slicingActiveChanged(true), barSpecsChanged(true), - selectedBarPosChanged(true) + selectedBarChanged(true) { } }; @@ -60,7 +60,7 @@ private: Bars3DChangeBitField m_changeTracker; // Interaction - QPoint m_selectedBarPos; // Points to row & column in data window. + QPoint m_selectedBar; // Points to row & column in data window. // Look'n'feel bool m_isBarSpecRelative; @@ -86,15 +86,11 @@ public: GLfloat barThickness(); QSizeF barSpacing(); bool isBarSpecRelative(); - - // bar type; bars (=cubes), pyramids, cones, cylinders, etc. void setBarType(QDataVis::MeshStyle style, bool smooth = false); - // Change selection mode; single bar, bar and row, bar and column, or all - void setSelectionMode(QDataVis::SelectionMode mode); - - void setSelectedBarPos(const QPoint &position); - QPoint selectedBarPos() const; + void setSelectionMode(QDataVis::SelectionFlags mode); + void setSelectedBar(const QPoint &position); + QPoint selectedBar() const; virtual void setActiveDataProxy(QAbstractDataProxy *proxy); @@ -116,11 +112,10 @@ public slots: void handleItemChanged(int rowIndex, int columnIndex); void handleDataRowLabelsChanged(); void handleDataColumnLabelsChanged(); - - void handleSelectedBarPosChanged(const QPoint &position); + void handleBarClicked(const QPoint &position); signals: - void selectedBarPosChanged(QPoint position); + void selectedBarChanged(QPoint position); protected: virtual Q3DAbstractAxis *createDefaultAxis(Q3DAbstractAxis::AxisOrientation orientation); diff --git a/src/datavisualization/engine/bars3drenderer.cpp b/src/datavisualization/engine/bars3drenderer.cpp index 0b0ae9aa..8e8a4e93 100644 --- a/src/datavisualization/engine/bars3drenderer.cpp +++ b/src/datavisualization/engine/bars3drenderer.cpp @@ -42,7 +42,6 @@ QT_DATAVISUALIZATION_BEGIN_NAMESPACE const GLfloat labelMargin = 0.05f; const GLfloat gridLineWidth = 0.005f; -static QVector3D selectionSkipColor = QVector3D(255, 255, 255); // Selection texture's background color const int smallerVPSize = 5; Bars3DRenderer::Bars3DRenderer(Bars3DController *controller) @@ -51,6 +50,7 @@ Bars3DRenderer::Bars3DRenderer(Bars3DController *controller) m_cachedIsSlicingActivated(false), m_cachedRowCount(0), m_cachedColumnCount(0), + m_cachedInputState(QDataVis::InputStateNone), m_selectedBar(0), m_sliceSelection(0), m_sliceCache(0), @@ -85,9 +85,10 @@ Bars3DRenderer::Bars3DRenderer(Bars3DController *controller) m_scaleZ(0), m_scaleFactor(0), m_maxSceneSize(40.0f), - m_selection(selectionSkipColor), - m_previousSelection(selectionSkipColor), - m_hasHeightAdjustmentChanged(true) + m_visualSelectedBarPos(Bars3DController::noSelectionPoint()), + m_clickedBarColor(invalidColorVector), + m_hasHeightAdjustmentChanged(true), + m_selectedBarPos(Bars3DController::noSelectionPoint()) { initializeOpenGLFunctions(); initializeOpenGL(); @@ -207,6 +208,9 @@ void Bars3DRenderer::updateDataModel(QBarDataProxy *dataProxy) m_renderColumns = updateSize; m_renderRows = qMin((dataRowCount - minRow), m_renderItemArray.size()); + // Reset selected bar to update selection + updateSelectedBar(m_selectedBarPos); + Abstract3DRenderer::updateDataModel(dataProxy); } @@ -243,6 +247,15 @@ void Bars3DRenderer::render(GLuint defaultFboHandle) { bool slicingChanged = m_cachedIsSlicingActivated != m_cachedScene->isSlicingActive(); + // TODO: Can't call back to controller here! (QTRD-2216) + // TODO: Needs to be added to synchronization + QDataVis::InputState currentInputState = m_controller->inputState(); + if (currentInputState != m_cachedInputState) { + if (currentInputState == QDataVis::InputStateOnScene) + m_clickedBarColor = invalidColorVector; + m_cachedInputState = currentInputState; + } + // Handle GL state setup for FBO buffers and clearing of the render surface Abstract3DRenderer::render(defaultFboHandle); @@ -253,10 +266,9 @@ void Bars3DRenderer::render(GLuint defaultFboHandle) if (m_cachedIsSlicingActivated) drawSlicedScene(m_axisCacheX.titleItem(), m_axisCacheY.titleItem(), m_axisCacheZ.titleItem()); - // If slicing has been activated by this render pass, we need another render - // Also trigger another render always when slicing changes in general to ensure + // Trigger another render always when slicing changes in general to ensure // final draw is correct. - if (m_cachedIsSlicingActivated != m_cachedScene->isSlicingActive() || slicingChanged) + if (slicingChanged) emit needRender(); } @@ -313,6 +325,9 @@ void Bars3DRenderer::drawSlicedScene(const LabelItem &xLabel, QVector3D barHighlightColor(Utils::vectorFromColor(m_cachedTheme.m_highlightBarColor)); QVector3D rowHighlightColor(Utils::vectorFromColor(m_cachedTheme.m_highlightRowColor)); QVector3D columnHighlightColor(Utils::vectorFromColor(m_cachedTheme.m_highlightColumnColor)); + bool rowMode = m_cachedSelectionMode.testFlag(QDataVis::SelectionRow); + bool itemMode = m_cachedSelectionMode.testFlag(QDataVis::SelectionItem); + for (int bar = startBar; bar != stopBar; bar += stepBar) { BarRenderItem *item = m_sliceSelection->at(bar); if (!item) @@ -328,7 +343,7 @@ void Bars3DRenderer::drawSlicedScene(const LabelItem &xLabel, QMatrix4x4 itModelMatrix; GLfloat barPosY = negativesComp * item->translation().y() - barPosYAdjustment; - if (QDataVis::SelectionModeSliceRow == m_cachedSelectionMode) + if (rowMode) barPosX = item->translation().x(); else barPosX = -(item->translation().z()); // flip z; frontmost bar to the left @@ -341,23 +356,27 @@ void Bars3DRenderer::drawSlicedScene(const LabelItem &xLabel, #if 0 QVector3D baseColor; - if (m_selection.x() == item->position().x() && m_selection.y() == item->position().y()) + if (m_visualSelectedBarPos.x() == item->position().x() + && m_visualSelectedBarPos.y() == item->position().y()) { baseColor = barHighlightColor; - else if (QDataVis::SelectionModeSliceRow == m_cachedSelectionMode) + } else if (QDataVis::SelectionSliceRow == m_cachedSelectionMode) { baseColor = rowHighlightColor; - else + } else { baseColor = columnHighlightColor; + } QVector3D heightColor = Utils::vectorFromColor(m_cachedTheme.m_heightColor) * item->height(); QVector3D barColor = baseColor + heightColor; #else QVector3D barColor; - if (m_selection.x() == item->position().x() && m_selection.y() == item->position().y()) + if (itemMode && m_visualSelectedBarPos.x() == item->position().x() + && m_visualSelectedBarPos.y() == item->position().y()) { barColor = barHighlightColor; - else if (QDataVis::SelectionModeSliceRow == m_cachedSelectionMode) + } else if (rowMode) { barColor = rowHighlightColor; - else + } else { barColor = columnHighlightColor; + } #endif if (item->height() != 0) { @@ -394,6 +413,10 @@ void Bars3DRenderer::drawSlicedScene(const LabelItem &xLabel, QVector3D negativesRotation(0.0f, 0.0f, 90.0f); QVector3D sliceLabelRotation(0.0f, 0.0f, -45.0f); GLfloat negativesCompPow2 = negativesComp * negativesComp; + + // Labels in axis caches can be in inverted order depending in orientation + bool flipped = (m_xFlipped && rowMode) || (m_zFlipped && !rowMode); + for (int col = 0; col < stopBar; col++) { BarRenderItem *item = m_sliceSelection->at(col); // Draw values @@ -401,46 +424,53 @@ void Bars3DRenderer::drawSlicedScene(const LabelItem &xLabel, m_drawer->drawLabel(*item, item->sliceLabelItem(), viewMatrix, projectionMatrix, valuePositionComp, negativesRotation, item->height(), m_cachedSelectionMode, m_labelShader, m_labelObj, activeCamera, - false, false, Drawer::LabelOver, Qt::AlignTop); + false, false, Drawer::LabelOver, Qt::AlignTop, true); } else { m_drawer->drawLabel(*item, item->sliceLabelItem(), viewMatrix, projectionMatrix, valuePositionComp, zeroVector, negativesCompPow2 * item->height(), - m_cachedSelectionMode, m_labelShader, m_labelObj, activeCamera); + m_cachedSelectionMode, m_labelShader, m_labelObj, activeCamera, + false, false, Drawer::LabelOver, Qt::AlignCenter, true); } // Draw labels if (m_sliceCache->labelItems().size() > col) { - m_drawer->drawLabel(*item, *m_sliceCache->labelItems().at(col), viewMatrix, + int labelIndex = flipped ? m_sliceCache->labelItems().size() - 1 - col : col; + m_drawer->drawLabel(*item, *m_sliceCache->labelItems().at(labelIndex), viewMatrix, projectionMatrix, positionComp, sliceLabelRotation, item->height(), m_cachedSelectionMode, m_labelShader, - m_labelObj, activeCamera, false, false, Drawer::LabelBelow); + m_labelObj, activeCamera, false, false, Drawer::LabelBelow, + Qt::AlignCenter, true); } } // Draw labels for axes - if (QDataVis::SelectionModeSliceRow == m_cachedSelectionMode) { + if (rowMode) { if (m_sliceTitleItem) { m_drawer->drawLabel(*dummyItem, sliceSelectionLabel, viewMatrix, projectionMatrix, positionComp, zeroVector, 0, m_cachedSelectionMode, m_labelShader, - m_labelObj, activeCamera, false, false, Drawer::LabelTop); + m_labelObj, activeCamera, false, false, Drawer::LabelTop, + Qt::AlignCenter, true); } m_drawer->drawLabel(*dummyItem, zLabel, viewMatrix, projectionMatrix, positionComp, zeroVector, 0, m_cachedSelectionMode, m_labelShader, - m_labelObj, activeCamera, false, false, Drawer::LabelBottom); + m_labelObj, activeCamera, false, false, Drawer::LabelBottom, + Qt::AlignCenter, true); } else { m_drawer->drawLabel(*dummyItem, xLabel, viewMatrix, projectionMatrix, positionComp, zeroVector, 0, m_cachedSelectionMode, m_labelShader, - m_labelObj, activeCamera, false, false, Drawer::LabelBottom); + m_labelObj, activeCamera, false, false, Drawer::LabelBottom, + Qt::AlignCenter, true); if (m_sliceTitleItem) { m_drawer->drawLabel(*dummyItem, sliceSelectionLabel, viewMatrix, projectionMatrix, positionComp, zeroVector, 0, m_cachedSelectionMode, m_labelShader, - m_labelObj, activeCamera, false, false, Drawer::LabelTop); + m_labelObj, activeCamera, false, false, Drawer::LabelTop, + Qt::AlignCenter, true); } } m_drawer->drawLabel(*dummyItem, yLabel, viewMatrix, projectionMatrix, positionComp, QVector3D(0.0f, 0.0f, 90.0f), 0, m_cachedSelectionMode, m_labelShader, m_labelObj, activeCamera, - false, false, Drawer::LabelLeft); + false, false, Drawer::LabelLeft, Qt::AlignCenter, true); glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); @@ -532,6 +562,8 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) QMatrix4x4 projectionViewMatrix = projectionMatrix * viewMatrix; + bool rowMode = m_cachedSelectionMode.testFlag(QDataVis::SelectionRow); + #if !defined(QT_OPENGL_ES_2) if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { // Render scene into a depth texture for using with shadow mapping @@ -654,8 +686,10 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) } #endif + // TODO: Selection must be enabled currently to support clicked signal. (QTRD-2517) // Skip selection mode drawing if we're slicing or have no selection mode - if (!m_cachedIsSlicingActivated && m_cachedSelectionMode > QDataVis::SelectionModeNone) { + if (!m_cachedIsSlicingActivated && m_cachedSelectionMode > QDataVis::SelectionNone + && m_cachedInputState == QDataVis::InputStateOnScene) { // Bind selection shader m_selectionShader->bind(); @@ -724,9 +758,12 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) glEnable(GL_DITHER); // Read color under cursor - if (QDataVis::InputStateOnScene == m_controller->inputState()) { - m_selection = Utils::getSelection(m_controller->inputPosition(), - m_cachedBoundingRect.height()); + // TODO: Can't call back to controller here! (QTRD-2216) + QVector3D clickedColor = Utils::getSelection(m_controller->inputPosition(), + m_cachedBoundingRect.height()); + if (m_clickedBarColor == invalidColorVector) { + m_clickedBarColor = clickedColor; + emit barClicked(selectionColorToArrayPosition(m_clickedBarColor)); } glBindFramebuffer(GL_FRAMEBUFFER, defaultFboHandle); @@ -762,21 +799,20 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) m_barShader->setUniformValue(m_barShader->ambientS(), m_cachedTheme.m_ambientStrength); - bool selectionDirty = (m_selection != m_previousSelection - || (m_selection != selectionSkipColor - && QDataVis::InputStateOnScene == m_controller->inputState() - && !m_cachedIsSlicingActivated)); - if (selectionDirty) { - m_previousSelection = m_selection; - if (m_sliceSelection) { - if (!m_cachedIsSlicingActivated) { - m_sliceCache = 0; - m_sliceTitleItem = 0; - } - if (m_sliceSelection->size()) { + + // TODO: Can't call back to controller here! (QTRD-2216) + if (m_selectionDirty) { + if (m_cachedIsSlicingActivated) { + if (m_sliceSelection && m_sliceSelection->size()) { // Slice doesn't own its items, no need to delete them - just clear m_sliceSelection->clear(); } + // Set slice cache, i.e. axis cache from where slice labels are taken + if (rowMode) + m_sliceCache = &m_axisCacheZ; + else + m_sliceCache = &m_axisCacheX; + m_sliceTitleItem = 0; } } @@ -792,6 +828,7 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) bool barSelectionFound = false; BarRenderItem *selectedBar(0); QVector3D modelScaler(m_scaleX, 0.0f, m_scaleZ); + bool somethingSelected = (m_visualSelectedBarPos != Bars3DController::noSelectionPoint()); for (int row = startRow; row != stopRow; row += stepRow) { for (int bar = startBar; bar != stopBar; bar += stepBar) { BarRenderItem &item = m_renderItemArray[row][bar]; @@ -834,8 +871,10 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) GLfloat lightStrength = m_cachedTheme.m_lightStrength; GLfloat shadowLightStrength = adjustedLightStrength; - if (m_cachedSelectionMode > QDataVis::SelectionModeNone) { - Bars3DController::SelectionType selectionType = isSelected(row, bar); + if (m_cachedSelectionMode > QDataVis::SelectionNone) { + Bars3DController::SelectionType selectionType = Bars3DController::SelectionNone; + if (somethingSelected) + selectionType = isSelected(row, bar); switch (selectionType) { case Bars3DController::SelectionItem: { @@ -849,26 +888,11 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) item.setTranslation(modelMatrix.column(3).toVector3D()); barSelectionFound = true; } - if (selectionDirty && m_cachedSelectionMode >= QDataVis::SelectionModeSliceRow) { + if (m_selectionDirty && m_cachedIsSlicingActivated) { item.setTranslation(modelMatrix.column(3).toVector3D()); item.setPosition(QPoint(row, bar)); m_sliceSelection->append(&item); barSelectionFound = true; - if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow) { - if (m_axisCacheX.labelItems().size() > row) - m_sliceTitleItem = m_axisCacheX.labelItems().at(row); - if (!m_sliceCache) { - // m_sliceCache is the axis for labels, while title comes from different axis. - m_sliceCache = &m_axisCacheZ; - } - } else if (m_cachedSelectionMode == QDataVis::SelectionModeSliceColumn) { - if (m_axisCacheZ.labelItems().size() > bar) - m_sliceTitleItem = m_axisCacheZ.labelItems().at(bar); - if (!m_sliceCache) { - // m_sliceCache is the axis for labels, while title comes from different axis. - m_sliceCache = &m_axisCacheX; - } - } } break; } @@ -877,11 +901,14 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) barColor = rowHighlightColor; lightStrength = m_cachedTheme.m_highlightLightStrength; shadowLightStrength = adjustedHighlightStrength; - if (QDataVis::SelectionModeSliceRow == m_cachedSelectionMode) { + if (m_cachedIsSlicingActivated) { item.setTranslation(modelMatrix.column(3).toVector3D()); item.setPosition(QPoint(row, bar)); - if (selectionDirty && bar < m_renderColumns) + if (m_selectionDirty && bar < m_renderColumns) { + if (!m_sliceTitleItem && m_axisCacheX.labelItems().size() > row) + m_sliceTitleItem = m_axisCacheX.labelItems().at(row); m_sliceSelection->append(&item); + } } break; } @@ -890,11 +917,14 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) barColor = columnHighlightColor; lightStrength = m_cachedTheme.m_highlightLightStrength; shadowLightStrength = adjustedHighlightStrength; - if (QDataVis::SelectionModeSliceColumn == m_cachedSelectionMode) { + if (m_cachedIsSlicingActivated) { item.setTranslation(modelMatrix.column(3).toVector3D()); item.setPosition(QPoint(row, bar)); - if (selectionDirty && row < m_renderRows) + if (m_selectionDirty && row < m_renderRows) { + if (!m_sliceTitleItem && m_axisCacheZ.labelItems().size() > bar) + m_sliceTitleItem = m_axisCacheZ.labelItems().at(bar); m_sliceSelection->append(&item); + } } break; } @@ -938,9 +968,6 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) } } - if (selectionDirty) - emit selectedBarPosChanged(QPoint(int(m_selection.x()), int(m_selection.y()))); - // Release bar shader m_barShader->release(); @@ -1292,7 +1319,7 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) m_drawer->drawLabel(m_dummyBarRenderItem, axisLabelItem, viewMatrix, projectionMatrix, positionComp, labelRotation, 0, m_cachedSelectionMode, m_labelShader, m_labelObj, activeCamera, - true, true, Drawer::LabelMid, alignment); + true, true, Drawer::LabelMid, alignment, m_cachedIsSlicingActivated); } } labelRotation = QVector3D(-90.0f, 90.0f, 0.0f); @@ -1307,7 +1334,7 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) } alignment = m_zFlipped ? Qt::AlignRight : Qt::AlignLeft; - for (int column = 0; column != m_cachedColumnCount; column += 1) { + for (int column = 0; column != m_cachedColumnCount; column++) { if (m_axisCacheZ.labelItems().size() > column) { // Go through all columns and get position of max+1 or min-1 row, depending on z flip // We need only positions for them, labels have already been generated at QDataSetPrivate. Just add LabelItems @@ -1394,19 +1421,8 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) } glDisable(GL_POLYGON_OFFSET_FILL); - // Handle slice activation and selection label drawing - if (!barSelectionFound) { - // We have no ownership, don't delete. Just NULL the pointer. - m_selectedBar = NULL; - if (m_cachedIsSlicingActivated - && (m_selection == selectionSkipColor - || QDataVis::InputStateOnOverview == m_controller->inputState())) { - m_cachedScene->setSlicingActive(false); - } - } else if (m_cachedSelectionMode >= QDataVis::SelectionModeSliceRow && selectionDirty) { - // Activate slice mode - m_cachedScene->setSlicingActive(true); - + // Handle slice and bar label generation + if (m_cachedIsSlicingActivated && m_selectionDirty) { // Create label textures for (int col = 0; col < m_sliceSelection->size(); col++) { BarRenderItem *item = m_sliceSelection->at(col); @@ -1414,7 +1430,7 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) item->setSliceLabel(generateValueLabel(m_axisCacheY.labelFormat(), item->value())); m_drawer->generateLabelItem(item->sliceLabelItem(), item->sliceLabel()); } - } else { + } else if (barSelectionFound) { // Print value of selected bar glDisable(GL_DEPTH_TEST); // Draw the selection label @@ -1473,6 +1489,8 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) m_updateLabels = false; glEnable(GL_DEPTH_TEST); + } else { + m_selectedBar = 0; } glDisable(GL_TEXTURE_2D); @@ -1480,6 +1498,8 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) // Release label shader m_labelShader->release(); + + m_selectionDirty = false; } void Bars3DRenderer::handleResize() @@ -1536,20 +1556,6 @@ void Bars3DRenderer::updateAxisRange(Q3DAbstractAxis::AxisOrientation orientatio } } -void Bars3DRenderer::updateSelectionMode(QDataVis::SelectionMode mode) -{ - Abstract3DRenderer::updateSelectionMode(mode); - - // Create zoom selection if there isn't one - if (mode >= QDataVis::SelectionModeSliceRow && !m_sliceSelection) { - m_sliceSelection = new QList<BarRenderItem *>; - if (mode == QDataVis::SelectionModeSliceRow) - m_sliceSelection->reserve(m_cachedRowCount); - else - m_sliceSelection->reserve(m_cachedColumnCount); - } -} - void Bars3DRenderer::updateBackgroundEnabled(bool enable) { if (enable != m_cachedIsBackgroundEnabled) { @@ -1558,13 +1564,23 @@ void Bars3DRenderer::updateBackgroundEnabled(bool enable) } } -void Bars3DRenderer::updateSelectedBarPos(const QPoint &position) +void Bars3DRenderer::updateSelectedBar(const QPoint &position) { - if (position == Bars3DController::noSelectionPoint()) - m_selection = selectionSkipColor; - else - m_selection = QVector3D(position.x(), position.y(), 0); - emit needRender(); + m_selectedBarPos = position; + + int adjustedX = m_selectedBarPos.x() - int(m_axisCacheX.min()); + int adjustedZ = m_selectedBarPos.y() - int(m_axisCacheZ.min()); + int maxX = m_renderItemArray.size() - 1; + int maxZ = maxX >= 0 ? m_renderItemArray.at(0).size() - 1 : -1; + + if (m_selectedBarPos == Bars3DController::noSelectionPoint() + || adjustedX < 0 || adjustedX > maxX + || adjustedZ < 0 || adjustedZ > maxZ) { + m_visualSelectedBarPos = Bars3DController::noSelectionPoint(); + } else { + m_visualSelectedBarPos = QPoint(adjustedX, adjustedZ); + } + m_selectionDirty = true; } void Bars3DRenderer::updateShadowQuality(QDataVis::ShadowQuality quality) @@ -1684,41 +1700,33 @@ void Bars3DRenderer::calculateHeightAdjustment() Bars3DController::SelectionType Bars3DRenderer::isSelected(GLint row, GLint bar) { - //static QVector3D prevSel = m_selection; // TODO: For debugging Bars3DController::SelectionType isSelectedType = Bars3DController::SelectionNone; - if (m_selection == selectionSkipColor) - return isSelectedType; // skip window - - //#if !defined(QT_OPENGL_ES_2) - // QVector3D current = QVector3D((GLuint)row, (GLuint)bar, 0); - //#else - QVector3D current = QVector3D((GLubyte)row, (GLubyte)bar, 0); - //#endif - - // TODO: For debugging - //if (selection != prevSel) { - // qDebug() << "current" << current.x() << current .y() << current.z(); - // qDebug() << "selection" << selection.x() << selection .y() << selection.z(); - // prevSel = selection; - //} - if (current == m_selection) { + + if (row == m_visualSelectedBarPos.x() && bar == m_visualSelectedBarPos.y() + && (m_cachedSelectionMode.testFlag(QDataVis::SelectionItem))) { isSelectedType = Bars3DController::SelectionItem; - } - else if (current.y() == m_selection.y() - && (m_cachedSelectionMode == QDataVis::SelectionModeItemAndColumn - || m_cachedSelectionMode == QDataVis::SelectionModeItemRowAndColumn - || m_cachedSelectionMode == QDataVis::SelectionModeSliceColumn)) { - isSelectedType = Bars3DController::SelectionColumn; - } - else if (current.x() == m_selection.x() - && (m_cachedSelectionMode == QDataVis::SelectionModeItemAndRow - || m_cachedSelectionMode == QDataVis::SelectionModeItemRowAndColumn - || m_cachedSelectionMode == QDataVis::SelectionModeSliceRow)) { + } else if (row == m_visualSelectedBarPos.x() + && (m_cachedSelectionMode.testFlag(QDataVis::SelectionRow))) { isSelectedType = Bars3DController::SelectionRow; + } else if (bar == m_visualSelectedBarPos.y() + && (m_cachedSelectionMode.testFlag(QDataVis::SelectionColumn))) { + isSelectedType = Bars3DController::SelectionColumn; } return isSelectedType; } +QPoint Bars3DRenderer::selectionColorToArrayPosition(const QVector3D &selectionColor) +{ + QPoint position; + if (selectionColor == selectionSkipColor) { + position = Bars3DController::noSelectionPoint(); + } else { + position = QPoint(int(selectionColor.x() + int(m_axisCacheX.min())), + int(selectionColor.y()) + int(m_axisCacheZ.min())); + } + return position; +} + void Bars3DRenderer::updateSlicingActive(bool isSlicing) { if (isSlicing == m_cachedIsSlicingActivated) @@ -1726,6 +1734,9 @@ void Bars3DRenderer::updateSlicingActive(bool isSlicing) m_cachedIsSlicingActivated = isSlicing; + if (m_cachedIsSlicingActivated && !m_sliceSelection) + m_sliceSelection = new QList<BarRenderItem *>; + setViewPorts(); if (!m_cachedIsSlicingActivated) @@ -1734,6 +1745,8 @@ void Bars3DRenderer::updateSlicingActive(bool isSlicing) #if !defined(QT_OPENGL_ES_2) updateDepthBuffer(); // Re-init depth buffer as well #endif + + m_selectionDirty = true; } void Bars3DRenderer::setViewPorts() diff --git a/src/datavisualization/engine/bars3drenderer_p.h b/src/datavisualization/engine/bars3drenderer_p.h index dd80902a..5d186a7d 100644 --- a/src/datavisualization/engine/bars3drenderer_p.h +++ b/src/datavisualization/engine/bars3drenderer_p.h @@ -60,6 +60,7 @@ private: bool m_cachedIsSlicingActivated; int m_cachedRowCount; int m_cachedColumnCount; + QDataVis::InputState m_cachedInputState; // Internal state BarRenderItem *m_selectedBar; // points to renderitem array @@ -98,14 +99,13 @@ private: GLfloat m_scaleZ; GLfloat m_scaleFactor; GLfloat m_maxSceneSize; - QVector3D m_selection; - QVector3D m_previousSelection; + QPoint m_visualSelectedBarPos; // The selection id color int m_renderRows; int m_renderColumns; - + QVector3D m_clickedBarColor; + QPoint m_selectedBarPos; bool m_hasHeightAdjustmentChanged; BarRenderItem m_dummyBarRenderItem; - BarRenderItemArray m_renderItemArray; public: @@ -126,16 +126,15 @@ public slots: void updateBarSpecs(GLfloat thicknessRatio = 1.0f, const QSizeF &spacing = QSizeF(1.0, 1.0), bool relative = true); - void updateSelectionMode(QDataVis::SelectionMode newMode); void updateSlicingActive(bool isSlicing); void updateBackgroundEnabled(bool enable); - void updateSelectedBarPos(const QPoint &position); + void updateSelectedBar(const QPoint &position); // Overloaded from abstract renderer virtual void updateAxisRange(Q3DAbstractAxis::AxisOrientation orientation, qreal min, qreal max); signals: - void selectedBarPosChanged(QPoint position); + void barClicked(QPoint position); private: virtual void initShaders(const QString &vertexShader, const QString &fragmentShader); @@ -161,6 +160,7 @@ private: void calculateSceneScalingFactors(); void calculateHeightAdjustment(); Abstract3DController::SelectionType isSelected(GLint row, GLint bar); + QPoint selectionColorToArrayPosition(const QVector3D &selectionColor); Q_DISABLE_COPY(Bars3DRenderer) diff --git a/src/datavisualization/engine/drawer.cpp b/src/datavisualization/engine/drawer.cpp index 418dba77..61454bd8 100644 --- a/src/datavisualization/engine/drawer.cpp +++ b/src/datavisualization/engine/drawer.cpp @@ -164,11 +164,10 @@ void Drawer::drawSurfaceGrid(ShaderHelper *shader, SurfaceObject *object) void Drawer::drawLabel(const AbstractRenderItem &item, const LabelItem &labelItem, const QMatrix4x4 &viewmatrix, const QMatrix4x4 &projectionmatrix, const QVector3D &positionComp, const QVector3D &rotation, - GLfloat itemHeight, QDataVis::SelectionMode mode, + GLfloat itemHeight, QDataVis::SelectionFlags mode, ShaderHelper *shader, ObjectHelper *object, - const Q3DCamera *camera, - bool useDepth, bool rotateAlong, - LabelPosition position, Qt::AlignmentFlag alignment) + const Q3DCamera *camera, bool useDepth, bool rotateAlong, + LabelPosition position, Qt::AlignmentFlag alignment, bool isSlicing) { // Draw label if (!labelItem.textureId()) @@ -275,7 +274,7 @@ void Drawer::drawLabel(const AbstractRenderItem &item, const LabelItem &labelIte xPosition = item.translation().x(); if (useDepth) zPosition = item.translation().z(); - else if (QDataVis::SelectionModeSliceColumn == mode) + else if (mode.testFlag(QDataVis::SelectionColumn) && isSlicing) xPosition = -(item.translation().z()) + positionComp.z(); // flip first to left } diff --git a/src/datavisualization/engine/drawer_p.h b/src/datavisualization/engine/drawer_p.h index 89a4ce8c..933b20c7 100644 --- a/src/datavisualization/engine/drawer_p.h +++ b/src/datavisualization/engine/drawer_p.h @@ -80,11 +80,10 @@ public: void drawLabel(const AbstractRenderItem &item, const LabelItem &labelItem, const QMatrix4x4 &viewmatrix, const QMatrix4x4 &projectionmatrix, const QVector3D &positionComp, const QVector3D &rotation, GLfloat itemHeight, - QDataVis::SelectionMode mode, ShaderHelper *shader, ObjectHelper *object, - const Q3DCamera *camera, - bool useDepth = false, bool rotateAlong = false, + QDataVis::SelectionFlags mode, ShaderHelper *shader, ObjectHelper *object, + const Q3DCamera *camera, bool useDepth = false, bool rotateAlong = false, LabelPosition position = LabelOver, - Qt::AlignmentFlag alignment = Qt::AlignCenter); + Qt::AlignmentFlag alignment = Qt::AlignCenter, bool isSlicing = false); void generateSelectionLabelTexture(AbstractRenderItem *item); void generateLabelItem(LabelItem &item, const QString &text, int widestLabel = 0); diff --git a/src/datavisualization/engine/q3dbars.cpp b/src/datavisualization/engine/q3dbars.cpp index d6b48e03..086bfc82 100644 --- a/src/datavisualization/engine/q3dbars.cpp +++ b/src/datavisualization/engine/q3dbars.cpp @@ -102,8 +102,8 @@ Q3DBars::Q3DBars() { setVisualController(d_ptr->m_shared); d_ptr->m_shared->initializeOpenGL(); - QObject::connect(d_ptr->m_shared, &Bars3DController::selectedBarPosChanged, this, - &Q3DBars::selectedBarPosChanged); + QObject::connect(d_ptr->m_shared, &Bars3DController::selectedBarChanged, this, + &Q3DBars::selectedBarChanged); QObject::connect(d_ptr->m_shared, &Abstract3DController::needRender, this, &Q3DWindow::renderLater); } @@ -297,12 +297,12 @@ QColor Q3DBars::barColor() const * Sets bar selection \a mode to one of \c QDataVis::SelectionMode. It is preset to * \c QDataVis::SelectionModeItem by default. */ -void Q3DBars::setSelectionMode(QDataVis::SelectionMode mode) +void Q3DBars::setSelectionMode(QDataVis::SelectionFlags mode) { d_ptr->m_shared->setSelectionMode(mode); } -QDataVis::SelectionMode Q3DBars::selectionMode() const +QDataVis::SelectionFlags Q3DBars::selectionMode() const { return d_ptr->m_shared->selectionMode(); } @@ -398,20 +398,21 @@ bool Q3DBars::isBackgroundVisible() const } /*! - * \property Q3DBars::selectedBarPos + * \property Q3DBars::selectedBar * - * Selects a bar in a \a position. The position is the position in data window. + * Selects a bar in a \a position. The position is the (row, column) position in + * the data array of the active data proxy. * Only one bar can be selected at a time. * To clear selection, specify an illegal \a position, e.g. (-1, -1). */ -void Q3DBars::setSelectedBarPos(const QPoint &position) +void Q3DBars::setSelectedBar(const QPoint &position) { - d_ptr->m_shared->setSelectedBarPos(position); + d_ptr->m_shared->setSelectedBar(position); } -QPoint Q3DBars::selectedBarPos() const +QPoint Q3DBars::selectedBar() const { - return d_ptr->m_shared->selectedBarPos(); + return d_ptr->m_shared->selectedBar(); } /*! diff --git a/src/datavisualization/engine/q3dbars.h b/src/datavisualization/engine/q3dbars.h index d0ddf3fb..51c35257 100644 --- a/src/datavisualization/engine/q3dbars.h +++ b/src/datavisualization/engine/q3dbars.h @@ -35,7 +35,7 @@ class Q3DScene; class QT_DATAVISUALIZATION_EXPORT Q3DBars : public Q3DWindow { Q_OBJECT - Q_PROPERTY(QtDataVisualization::QDataVis::SelectionMode selectionMode READ selectionMode WRITE setSelectionMode) + Q_PROPERTY(QtDataVisualization::QDataVis::SelectionFlags selectionMode READ selectionMode WRITE setSelectionMode) Q_PROPERTY(QtDataVisualization::QDataVis::LabelStyle labelStyle READ labelStyle WRITE setLabelStyle) Q_PROPERTY(QtDataVisualization::QDataVis::ShadowQuality shadowQuality READ shadowQuality WRITE setShadowQuality NOTIFY shadowQualityChanged) Q_PROPERTY(qreal barThickness READ barThickness WRITE setBarThickness) @@ -45,14 +45,9 @@ class QT_DATAVISUALIZATION_EXPORT Q3DBars : public Q3DWindow Q_PROPERTY(QFont font READ font WRITE setFont) Q_PROPERTY(bool gridVisible READ isGridVisible WRITE setGridVisible) Q_PROPERTY(bool backgroundVisible READ isBackgroundVisible WRITE setBackgroundVisible) - Q_PROPERTY(QPoint selectedBarPos READ selectedBarPos WRITE setSelectedBarPos NOTIFY selectedBarPosChanged) + Q_PROPERTY(QPoint selectedBar READ selectedBar WRITE setSelectedBar NOTIFY selectedBarChanged) Q_PROPERTY(Q3DScene* scene READ scene) - Q_ENUMS(QtDataVisualization::QDataVis::SelectionMode) - Q_ENUMS(QtDataVisualization::QDataVis::ShadowQuality) - Q_ENUMS(QtDataVisualization::QDataVis::LabelStyle) - Q_ENUMS(QtDataVisualization::QDataVis::CameraPreset) - public: explicit Q3DBars(); ~Q3DBars(); @@ -76,8 +71,8 @@ public: void setMeshFileName(const QString &objFileName); QString meshFileName() const; - void setSelectionMode(QDataVis::SelectionMode mode); - QDataVis::SelectionMode selectionMode() const; + void setSelectionMode(QDataVis::SelectionFlags mode); + QDataVis::SelectionFlags selectionMode() const; void setFont(const QFont &font); QFont font() const; @@ -96,8 +91,8 @@ public: void setBackgroundVisible(bool visible); bool isBackgroundVisible() const; - void setSelectedBarPos(const QPoint &position); - QPoint selectedBarPos() const; + void setSelectedBar(const QPoint &position); + QPoint selectedBar() const; void setShadowQuality(QDataVis::ShadowQuality quality); QDataVis::ShadowQuality shadowQuality() const; @@ -120,7 +115,7 @@ public: signals: void shadowQualityChanged(QDataVis::ShadowQuality quality); - void selectedBarPosChanged(QPoint position); + void selectedBarChanged(QPoint position); protected: diff --git a/src/datavisualization/engine/q3dscatter.cpp b/src/datavisualization/engine/q3dscatter.cpp index fc95842a..aa67498e 100644 --- a/src/datavisualization/engine/q3dscatter.cpp +++ b/src/datavisualization/engine/q3dscatter.cpp @@ -232,12 +232,12 @@ QColor Q3DScatter::objectColor() const * Sets item selection \a mode to one of \c QDataVis::SelectionMode. It is preset to * \c QDataVis::SelectionModeItem by default. */ -void Q3DScatter::setSelectionMode(QDataVis::SelectionMode mode) +void Q3DScatter::setSelectionMode(QDataVis::SelectionFlags mode) { d_ptr->m_shared->setSelectionMode(mode); } -QDataVis::SelectionMode Q3DScatter::selectionMode() const +QDataVis::SelectionFlags Q3DScatter::selectionMode() const { return d_ptr->m_shared->selectionMode(); } diff --git a/src/datavisualization/engine/q3dscatter.h b/src/datavisualization/engine/q3dscatter.h index fdea604e..0241f439 100644 --- a/src/datavisualization/engine/q3dscatter.h +++ b/src/datavisualization/engine/q3dscatter.h @@ -35,7 +35,7 @@ class QScatterDataProxy; class QT_DATAVISUALIZATION_EXPORT Q3DScatter : public Q3DWindow { Q_OBJECT - Q_PROPERTY(QtDataVisualization::QDataVis::SelectionMode selectionMode READ selectionMode WRITE setSelectionMode) + Q_PROPERTY(QtDataVisualization::QDataVis::SelectionFlags selectionMode READ selectionMode WRITE setSelectionMode) Q_PROPERTY(QtDataVisualization::QDataVis::LabelStyle labelStyle READ labelStyle WRITE setLabelStyle) Q_PROPERTY(QtDataVisualization::QDataVis::ShadowQuality shadowQuality READ shadowQuality WRITE setShadowQuality) Q_PROPERTY(QString meshFileName READ meshFileName WRITE setMeshFileName) @@ -44,10 +44,6 @@ class QT_DATAVISUALIZATION_EXPORT Q3DScatter : public Q3DWindow Q_PROPERTY(bool backgroundVisible READ isBackgroundVisible WRITE setBackgroundVisible) Q_PROPERTY(int selectedItemIndex READ selectedItemIndex WRITE setSelectedItemIndex NOTIFY selectedItemIndexChanged) Q_PROPERTY(Q3DScene* scene READ scene) - Q_ENUMS(QtDataVisualization::QDataVis::SelectionMode) - Q_ENUMS(QtDataVisualization::QDataVis::ShadowQuality) - Q_ENUMS(QtDataVisualization::QDataVis::LabelStyle) - Q_ENUMS(QtDataVisualization::QDataVis::CameraPreset) public: explicit Q3DScatter(); @@ -63,8 +59,8 @@ public: void setMeshFileName(const QString &objFileName); QString meshFileName() const; - void setSelectionMode(QDataVis::SelectionMode mode); - QDataVis::SelectionMode selectionMode() const; + void setSelectionMode(QDataVis::SelectionFlags mode); + QDataVis::SelectionFlags selectionMode() const; void setFont(const QFont &font); QFont font() const; diff --git a/src/datavisualization/engine/q3dsurface.cpp b/src/datavisualization/engine/q3dsurface.cpp index 42260e8b..7b9e32bb 100644 --- a/src/datavisualization/engine/q3dsurface.cpp +++ b/src/datavisualization/engine/q3dsurface.cpp @@ -101,6 +101,8 @@ Q3DSurface::Q3DSurface() { setVisualController(d_ptr->m_shared); d_ptr->m_shared->initializeOpenGL(); + QObject::connect(d_ptr->m_shared, &Surface3DController::selectedPointChanged, this, + &Q3DSurface::selectedPointChanged); QObject::connect(d_ptr->m_shared, &Abstract3DController::needRender, this, &Q3DWindow::renderLater); } @@ -260,15 +262,16 @@ bool Q3DSurface::isSmoothSurfaceEnabled() const /*! * \property Q3DSurface::selectionMode * - * Sets point selection \a mode to one of \c QDataVis::SelectionMode. Surface supports SelectionModeItem, - * SelectionModeSliceRow and SelectionModeSliceColumn. It is preset to \c QDataVis::SelectionModeItem by default. + * Sets point selection \a mode to one of \c QDataVis::SelectionMode. Surface supports + * \c SelectionItem and \c SelectionSlice with either \c SelectionRow or \c SelectionColumn. + * It is preset to \c SelectionItem by default. */ -void Q3DSurface::setSelectionMode(QDataVis::SelectionMode mode) +void Q3DSurface::setSelectionMode(QDataVis::SelectionFlags mode) { d_ptr->m_shared->setSelectionMode(mode); } -QDataVis::SelectionMode Q3DSurface::selectionMode() const +QDataVis::SelectionFlags Q3DSurface::selectionMode() const { return d_ptr->m_shared->selectionMode(); } @@ -331,6 +334,24 @@ Q3DScene *Q3DSurface::scene() const } /*! + * \property Q3DSurface::selectedPoint + * + * Selects a surface grid point in a \a position. The position is the (row, column) position in + * the data array of the active data proxy. + * Only one point can be selected at a time. + * To clear selection, specify an illegal \a position, e.g. (-1, -1). + */ +void Q3DSurface::setSelectedPoint(const QPoint &position) +{ + d_ptr->m_shared->setSelectedPoint(position); +} + +QPoint Q3DSurface::selectedPoint() const +{ + return d_ptr->m_shared->selectedPoint(); +} + +/*! * \property Q3DSurface::labelStyle * * Sets label \a style to one of \c QDataVis::LabelStyle. It is preset to diff --git a/src/datavisualization/engine/q3dsurface.h b/src/datavisualization/engine/q3dsurface.h index 1b572a36..c131f245 100644 --- a/src/datavisualization/engine/q3dsurface.h +++ b/src/datavisualization/engine/q3dsurface.h @@ -34,7 +34,7 @@ class QSurfaceDataProxy; class QT_DATAVISUALIZATION_EXPORT Q3DSurface : public Q3DWindow { Q_OBJECT - Q_PROPERTY(QtDataVisualization::QDataVis::SelectionMode selectionMode READ selectionMode WRITE setSelectionMode) + Q_PROPERTY(QtDataVisualization::QDataVis::SelectionFlags selectionMode READ selectionMode WRITE setSelectionMode) Q_PROPERTY(QtDataVisualization::QDataVis::LabelStyle labelStyle READ labelStyle WRITE setLabelStyle) Q_PROPERTY(QtDataVisualization::QDataVis::Theme theme READ theme WRITE setTheme) Q_PROPERTY(QtDataVisualization::QDataVis::ShadowQuality shadowQuality READ shadowQuality WRITE setShadowQuality) @@ -45,10 +45,8 @@ class QT_DATAVISUALIZATION_EXPORT Q3DSurface : public Q3DWindow Q_PROPERTY(QLinearGradient gradient READ gradient WRITE setGradient) Q_PROPERTY(QFont font READ font WRITE setFont) Q_PROPERTY(Q3DScene* scene READ scene) - Q_ENUMS(QtDataVisualization::QDataVis::SelectionMode) - Q_ENUMS(QtDataVisualization::QDataVis::ShadowQuality) - Q_ENUMS(QtDataVisualization::QDataVis::LabelStyle) - Q_ENUMS(QtDataVisualization::QDataVis::CameraPreset) + Q_PROPERTY(QPoint selectedPoint READ selectedPoint WRITE setSelectedPoint NOTIFY selectedPointChanged) + public: explicit Q3DSurface(); @@ -69,8 +67,8 @@ public: void setSmoothSurfaceEnabled(bool enabled); bool isSmoothSurfaceEnabled() const; - void setSelectionMode(QDataVis::SelectionMode mode); - QDataVis::SelectionMode selectionMode() const; + void setSelectionMode(QDataVis::SelectionFlags mode); + QDataVis::SelectionFlags selectionMode() const; void setSurfaceGridEnabled(bool enabled); bool isSurfaceGridEnabled() const; @@ -101,9 +99,15 @@ public: Q3DScene *scene() const; + void setSelectedPoint(const QPoint &position); + QPoint selectedPoint() const; + void setLabelStyle(QDataVis::LabelStyle style); QDataVis::LabelStyle labelStyle() const; +signals: + void selectedPointChanged(QPoint position); + protected: void mouseDoubleClickEvent(QMouseEvent *event); void touchEvent(QTouchEvent *event); diff --git a/src/datavisualization/engine/scatter3dcontroller.cpp b/src/datavisualization/engine/scatter3dcontroller.cpp index 9f43d94e..ca16a34b 100644 --- a/src/datavisualization/engine/scatter3dcontroller.cpp +++ b/src/datavisualization/engine/scatter3dcontroller.cpp @@ -60,8 +60,8 @@ void Scatter3DController::initializeOpenGL() setRenderer(m_renderer); synchDataToRenderer(); - QObject::connect(m_renderer, &Scatter3DRenderer::selectedItemIndexChanged, this, - &Scatter3DController::handleSelectedItemIndexChanged, Qt::QueuedConnection); + QObject::connect(m_renderer, &Scatter3DRenderer::itemClicked, this, + &Scatter3DController::handleItemClicked, Qt::QueuedConnection); emitNeedRender(); } @@ -117,17 +117,15 @@ void Scatter3DController::setActiveDataProxy(QAbstractDataProxy *proxy) adjustValueAxisRange(); setSelectedItemIndex(noSelectionIndex()); - setSlicingActive(false); m_isDataDirty = true; emitNeedRender(); } void Scatter3DController::handleArrayReset() { - setSlicingActive(false); adjustValueAxisRange(); m_isDataDirty = true; - setSelectedItemIndex(noSelectionIndex()); + setSelectedItemIndex(m_selectedItemIndex); emitNeedRender(); } @@ -173,13 +171,11 @@ void Scatter3DController::handleItemsInserted(int startIndex, int count) emitNeedRender(); } -void Scatter3DController::handleSelectedItemIndexChanged(int index) +void Scatter3DController::handleItemClicked(int index) { - if (index != m_selectedItemIndex) { - m_selectedItemIndex = index; - emit selectedItemIndexChanged(index); - emitNeedRender(); - } + setSelectedItemIndex(index); + // TODO: pass clicked to parent. (QTRD-2517) + // TODO: Also hover needed? (QTRD-2131) } void Scatter3DController::handleAxisAutoAdjustRangeChangedInOrientation( @@ -190,6 +186,14 @@ void Scatter3DController::handleAxisAutoAdjustRangeChangedInOrientation( adjustValueAxisRange(); } +void Scatter3DController::handleAxisRangeChangedBySender(QObject *sender) +{ + Abstract3DController::handleAxisRangeChangedBySender(sender); + + // Update selected index - may be moved offscreen + setSelectedItemIndex(m_selectedItemIndex); +} + void Scatter3DController::setObjectType(QDataVis::MeshStyle style, bool smooth) { QString objFile; @@ -207,21 +211,18 @@ void Scatter3DController::setObjectType(QDataVis::MeshStyle style, bool smooth) Abstract3DController::setMeshFileName(objFile); } -void Scatter3DController::setSelectionMode(QDataVis::SelectionMode mode) +void Scatter3DController::setSelectionMode(QDataVis::SelectionFlags mode) { - if (mode > QDataVis::SelectionModeItem) { - qWarning("Unsupported selection mode."); + // We only support single item selection mode + if (int(mode ^ QDataVis::SelectionItem) != 0) { + qWarning("Unsupported selection mode - only item selection mode is supported."); return; } - // Disable zoom if selection mode changes - setSlicingActive(false); Abstract3DController::setSelectionMode(mode); } void Scatter3DController::setSelectedItemIndex(int index) { - // TODO If items not within axis ranges are culled from drawing, should they be - // TODO unselectable as well? if (index < 0 || index >= static_cast<QScatterDataProxy *>(m_data)->itemCount()) index = noSelectionIndex(); diff --git a/src/datavisualization/engine/scatter3dcontroller_p.h b/src/datavisualization/engine/scatter3dcontroller_p.h index 63735aca..a1eae9f3 100644 --- a/src/datavisualization/engine/scatter3dcontroller_p.h +++ b/src/datavisualization/engine/scatter3dcontroller_p.h @@ -71,7 +71,7 @@ public: void setObjectType(QDataVis::MeshStyle style, bool smooth = false); // Change selection mode - void setSelectionMode(QDataVis::SelectionMode mode); + void setSelectionMode(QDataVis::SelectionFlags mode); void setSelectedItemIndex(int index); int selectedItemIndex() const; @@ -82,6 +82,7 @@ public: void synchDataToRenderer(); virtual void handleAxisAutoAdjustRangeChangedInOrientation(Q3DAbstractAxis::AxisOrientation orientation, bool autoAdjust); + virtual void handleAxisRangeChangedBySender(QObject *sender); public slots: void handleArrayReset(); @@ -89,7 +90,7 @@ public slots: void handleItemsChanged(int startIndex, int count); void handleItemsRemoved(int startIndex, int count); void handleItemsInserted(int startIndex, int count); - void handleSelectedItemIndexChanged(int index); + void handleItemClicked(int index); signals: void selectedItemIndexChanged(int index); diff --git a/src/datavisualization/engine/scatter3drenderer.cpp b/src/datavisualization/engine/scatter3drenderer.cpp index 62163d6c..283020d0 100644 --- a/src/datavisualization/engine/scatter3drenderer.cpp +++ b/src/datavisualization/engine/scatter3drenderer.cpp @@ -49,7 +49,6 @@ const GLfloat labelMargin = 0.05f; // TODO: Make margin modifiable? const GLfloat backgroundMargin = 1.1f; // Margin for background (1.1f = make it 10% larger to avoid items being drawn inside background) const GLfloat gridLineWidth = 0.005f; -static QVector3D selectionSkipColor = QVector3D(255, 255, 255); // Selection texture's background color Scatter3DRenderer::Scatter3DRenderer(Scatter3DController *controller) : Abstract3DRenderer(controller), @@ -78,11 +77,11 @@ Scatter3DRenderer::Scatter3DRenderer(Scatter3DController *controller) m_shadowQualityMultiplier(3), m_heightNormalizer(1.0f), m_scaleFactor(0), - m_selection(selectionSkipColor), - m_previousSelection(selectionSkipColor), + m_clickedColor(invalidColorVector), m_areaSize(QSizeF(0.0, 0.0)), m_dotSizeScale(1.0f), - m_hasHeightAdjustmentChanged(true) + m_hasHeightAdjustmentChanged(true), + m_cachedInputState(QDataVis::InputStateNone) { initializeOpenGLFunctions(); initializeOpenGL(); @@ -195,6 +194,15 @@ void Scatter3DRenderer::updateScene(Q3DScene *scene) void Scatter3DRenderer::render(GLuint defaultFboHandle) { + // TODO: Can't call back to controller here! (QTRD-2216) + // TODO: Needs to be added to synchronization + QDataVis::InputState currentInputState = m_controller->inputState(); + if (currentInputState != m_cachedInputState) { + if (currentInputState == QDataVis::InputStateOnScene) + m_clickedColor = invalidColorVector; + m_cachedInputState = currentInputState; + } + // Handle GL state setup for FBO buffers and clearing of the render surface Abstract3DRenderer::render(defaultFboHandle); @@ -376,7 +384,9 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) #endif // Skip selection mode drawing if we have no selection mode - if (m_cachedSelectionMode > QDataVis::SelectionModeNone) { + // TODO: Can't call back to controller here! (QTRD-2216) + if (m_cachedSelectionMode > QDataVis::SelectionNone + && QDataVis::InputStateOnScene == m_controller->inputState()) { // Bind selection shader m_selectionShader->bind(); @@ -433,9 +443,12 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) glEnable(GL_DITHER); // Read color under cursor - if (QDataVis::InputStateOnScene == m_controller->inputState()) { - m_selection = Utils::getSelection(m_controller->inputPosition(), - m_cachedBoundingRect.height()); + // TODO: Can't call back to controller here! (QTRD-2216) + QVector3D clickedColor = Utils::getSelection(m_controller->inputPosition(), + m_cachedBoundingRect.height()); + if (m_clickedColor == invalidColorVector) { + m_clickedColor = clickedColor; + emit itemClicked(selectionColorToIndex(m_clickedColor)); } glBindFramebuffer(GL_FRAMEBUFFER, defaultFboHandle); @@ -471,20 +484,6 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) // Draw dots bool dotSelectionFound = false; - int selectedIndex; - if (m_selection == selectionSkipColor) { - selectedIndex = Scatter3DController::noSelectionIndex(); - } else { - selectedIndex = int(m_selection.x()) - + (int(m_selection.y()) << 8) - + (int(m_selection.z()) << 16); - } - - if (m_selection != m_previousSelection) { - emit selectedItemIndexChanged(selectedIndex); - m_previousSelection = m_selection; - } - ScatterRenderItem *selectedItem(0); QVector3D baseColor = Utils::vectorFromColor(m_cachedTheme.m_baseColor); @@ -524,7 +523,7 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) #endif GLfloat lightStrength = m_cachedTheme.m_lightStrength; - if (m_cachedSelectionMode > QDataVis::SelectionModeNone && (selectedIndex == dot)) { + if (m_cachedSelectionMode > QDataVis::SelectionNone && (m_selectedItemIndex == dot)) { dotColor = Utils::vectorFromColor(m_cachedTheme.m_highlightBarColor); lightStrength = m_cachedTheme.m_highlightLightStrength; // Insert data to ScatterRenderItem. We have no ownership, don't delete the previous one @@ -1312,10 +1311,8 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) void Scatter3DRenderer::updateSelectedItemIndex(int index) { - if (index == Scatter3DController::noSelectionIndex()) - m_selection = selectionSkipColor; - else - m_selection = indexToSelectionColor(index); + m_selectionDirty = true; + m_selectedItemIndex = index; } void Scatter3DRenderer::handleResize() @@ -1574,4 +1571,17 @@ QVector3D Scatter3DRenderer::indexToSelectionColor(GLint index) return QVector3D(dotIdxRed, dotIdxGreen, dotIdxBlue); } +int Scatter3DRenderer::selectionColorToIndex(const QVector3D &color) +{ + int selectedIndex; + if (color == selectionSkipColor) { + selectedIndex = Scatter3DController::noSelectionIndex(); + } else { + selectedIndex = int(color.x()) + + (int(color.y()) << 8) + + (int(color.z()) << 16); + } + return selectedIndex; +} + QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/engine/scatter3drenderer_p.h b/src/datavisualization/engine/scatter3drenderer_p.h index f444f891..4a1f0b30 100644 --- a/src/datavisualization/engine/scatter3drenderer_p.h +++ b/src/datavisualization/engine/scatter3drenderer_p.h @@ -84,8 +84,8 @@ private: GLint m_shadowQualityMultiplier; GLfloat m_heightNormalizer; GLfloat m_scaleFactor; - QVector3D m_selection; - QVector3D m_previousSelection; + QVector3D m_clickedColor; + int m_selectedItemIndex; QSizeF m_areaSize; GLfloat m_dotSizeScale; @@ -94,6 +94,8 @@ private: ScatterRenderItemArray m_renderItemArray; + QDataVis::InputState m_cachedInputState; + public: explicit Scatter3DRenderer(Scatter3DController *controller); ~Scatter3DRenderer(); @@ -143,11 +145,11 @@ public slots: void updateSelectedItemIndex(int index); signals: - void selectionUpdated(QVector3D selection); - void selectedItemIndexChanged(int index); + void itemClicked(int index); private: QVector3D indexToSelectionColor(GLint index); + int selectionColorToIndex(const QVector3D &color); }; QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/engine/surface3dcontroller.cpp b/src/datavisualization/engine/surface3dcontroller.cpp index 8d1bcf85..71b09efd 100644 --- a/src/datavisualization/engine/surface3dcontroller.cpp +++ b/src/datavisualization/engine/surface3dcontroller.cpp @@ -34,7 +34,8 @@ Surface3DController::Surface3DController(QRect rect) : Abstract3DController(rect), m_renderer(0), m_isSmoothSurfaceEnabled(false), - m_isSurfaceGridEnabled(true) + m_isSurfaceGridEnabled(true), + m_selectedPoint(noSelectionPoint()) { setActiveDataProxy(0); @@ -62,6 +63,8 @@ void Surface3DController::initializeOpenGL() m_renderer = new Surface3DRenderer(this); setRenderer(m_renderer); synchDataToRenderer(); + QObject::connect(m_renderer, &Surface3DRenderer::pointClicked, this, + &Surface3DController::handlePointClicked, Qt::QueuedConnection); emitNeedRender(); } @@ -91,6 +94,11 @@ void Surface3DController::synchDataToRenderer() m_changeTracker.surfaceGridChanged = false; } + if (m_changeTracker.selectedPointChanged) { + m_renderer->updateSelectedPoint(m_selectedPoint); + m_changeTracker.selectedPointChanged = false; + } + if (m_isDataDirty) { m_renderer->updateDataModel(static_cast<QSurfaceDataProxy *>(m_data)); m_isDataDirty = false; @@ -107,8 +115,16 @@ void Surface3DController::handleAxisAutoAdjustRangeChangedInOrientation(Q3DAbstr void Surface3DController::handleAxisRangeChangedBySender(QObject *sender) { - scene()->setSlicingActive(false); Abstract3DController::handleAxisRangeChangedBySender(sender); + + // Update selected point - may be moved offscreen + setSelectedPoint(m_selectedPoint); +} + +QPoint Surface3DController::noSelectionPoint() +{ + static QPoint noSelectionPoint(-1, -1); + return noSelectionPoint; } void Surface3DController::setSmoothSurface(bool enable) @@ -160,19 +176,88 @@ void Surface3DController::setGradientColorAt(qreal pos, const QColor &color) emitNeedRender(); } -void Surface3DController::setSelectionMode(QDataVis::SelectionMode mode) +void Surface3DController::setSelectionMode(QDataVis::SelectionFlags mode) { - if (!(mode == QDataVis::SelectionModeNone || mode == QDataVis::SelectionModeItem - || mode == QDataVis::SelectionModeSliceRow - || mode == QDataVis::SelectionModeSliceColumn)) { + // Currently surface only supports row and column modes when also slicing + if ((mode.testFlag(QDataVis::SelectionRow) || mode.testFlag(QDataVis::SelectionColumn)) + && !mode.testFlag(QDataVis::SelectionSlice)) { qWarning("Unsupported selection mode."); return; + } else if (mode.testFlag(QDataVis::SelectionSlice) + && (mode.testFlag(QDataVis::SelectionRow) == mode.testFlag(QDataVis::SelectionColumn))) { + qWarning("Must specify one of either row or column selection mode in conjunction with slicing mode."); + } else { + // When setting selection mode to a new slicing mode, activate slicing + if (mode != selectionMode()) { + bool isSlicing = mode.testFlag(QDataVis::SelectionSlice); + if (isSlicing && m_selectedPoint != noSelectionPoint()) + scene()->setSlicingActive(true); + else + scene()->setSlicingActive(false); + } + + Abstract3DController::setSelectionMode(mode); } - // Disable zoom if selection mode changes - setSlicingActive(false); - Abstract3DController::setSelectionMode(mode); } +void Surface3DController::setSelectedPoint(const QPoint &position) +{ + // If the selection targets non-existent point, clear selection instead. + QPoint pos = position; + + const QSurfaceDataProxy *proxy = static_cast<const QSurfaceDataProxy *>(m_data); + if (pos != noSelectionPoint()) { + int maxRow = proxy->rowCount() - 1; + int maxCol = proxy->columnCount() - 1; + + if (pos.x() < 0 || pos.x() > maxRow || pos.y() < 0 || pos.y() > maxCol) + pos = noSelectionPoint(); + } + + if (selectionMode().testFlag(QDataVis::SelectionSlice)) { + if (pos == noSelectionPoint()) { + scene()->setSlicingActive(false); + } else { + // If the selected point is outside data window, or there is no selected point, disable slicing + // TODO: (QTRD-2351) This logic doesn't match the renderer logic for non straight surfaces, + // but that logic needs to change anyway, so this is good for now. + float axisMinX = float(m_axisX->min()); + float axisMaxX = float(m_axisX->max()); + float axisMinZ = float(m_axisZ->min()); + float axisMaxZ = float(m_axisZ->max()); + + // Comparisons between float and double are not accurate, so fudge our comparison values + //a little to get all rows and columns into view that need to be visible. + const float fudgeFactor = 0.00001f; + float fudgedAxisXRange = (axisMaxX - axisMinX) * fudgeFactor; + float fudgedAxisZRange = (axisMaxZ - axisMinZ) * fudgeFactor; + axisMinX -= fudgedAxisXRange; + axisMinZ -= fudgedAxisZRange; + axisMaxX += fudgedAxisXRange; + axisMaxZ += fudgedAxisZRange; + QSurfaceDataItem item = proxy->array()->at(pos.x())->at(pos.y()); + if (item.x() < axisMinX || item.x() > axisMaxX + || item.z() < axisMinZ || item.z() > axisMaxZ) { + scene()->setSlicingActive(false); + } else { + scene()->setSlicingActive(true); + } + } + emitNeedRender(); + } + + if (pos != m_selectedPoint) { + m_selectedPoint = pos; + m_changeTracker.selectedPointChanged = true; + emit selectedPointChanged(pos); + emitNeedRender(); + } +} + +QPoint Surface3DController::selectedPoint() const +{ + return m_selectedPoint; +} void Surface3DController::setActiveDataProxy(QAbstractDataProxy *proxy) { @@ -191,20 +276,31 @@ void Surface3DController::setActiveDataProxy(QAbstractDataProxy *proxy) QObject::connect(surfaceDataProxy, &QSurfaceDataProxy::arrayReset, this, &Surface3DController::handleArrayReset); - scene()->setSlicingActive(false); adjustValueAxisRange(); + + // Always clear selection on proxy change + setSelectedPoint(noSelectionPoint()); + m_isDataDirty = true; emitNeedRender(); } void Surface3DController::handleArrayReset() { - scene()->setSlicingActive(false); adjustValueAxisRange(); m_isDataDirty = true; + // Clear selection unless still valid + setSelectedPoint(m_selectedPoint); emitNeedRender(); } +void Surface3DController::handlePointClicked(const QPoint &position) +{ + setSelectedPoint(position); + // TODO: pass clicked to parent. (QTRD-2517) + // TODO: Also hover needed? (QTRD-2131) +} + void Surface3DController::adjustValueAxisRange() { if (m_data) { diff --git a/src/datavisualization/engine/surface3dcontroller_p.h b/src/datavisualization/engine/surface3dcontroller_p.h index 0698c291..07d15f29 100644 --- a/src/datavisualization/engine/surface3dcontroller_p.h +++ b/src/datavisualization/engine/surface3dcontroller_p.h @@ -42,11 +42,13 @@ struct Surface3DChangeBitField { bool gradientColorChanged : 1; bool smoothStatusChanged : 1; bool surfaceGridChanged : 1; + bool selectedPointChanged : 1; Surface3DChangeBitField() : gradientColorChanged(true), smoothStatusChanged(true), - surfaceGridChanged(true) + surfaceGridChanged(true), + selectedPointChanged(true) { } }; @@ -57,12 +59,11 @@ class QT_DATAVISUALIZATION_EXPORT Surface3DController : public Abstract3DControl private: Surface3DChangeBitField m_changeTracker; - - // Rendering Surface3DRenderer *m_renderer; bool m_isSmoothSurfaceEnabled; bool m_isSurfaceGridEnabled; QLinearGradient m_userDefinedGradient; + QPoint m_selectedPoint; public: explicit Surface3DController(QRect rect); @@ -82,18 +83,25 @@ public: void setGradientColorAt(qreal pos, const QColor &color); - void setSelectionMode(QDataVis::SelectionMode mode); + void setSelectionMode(QDataVis::SelectionFlags mode); + + void setSelectedPoint(const QPoint &position); + QPoint selectedPoint() const; virtual void setActiveDataProxy(QAbstractDataProxy *proxy); virtual void handleAxisAutoAdjustRangeChangedInOrientation(Q3DAbstractAxis::AxisOrientation orientation, bool autoAdjust); virtual void handleAxisRangeChangedBySender(QObject *sender); + static QPoint noSelectionPoint(); + public slots: void handleArrayReset(); + void handlePointClicked(const QPoint &position); signals: void smoothSurfaceEnabledChanged(bool enable); + void selectedPointChanged(QPoint position); private: void adjustValueAxisRange(); diff --git a/src/datavisualization/engine/surface3drenderer.cpp b/src/datavisualization/engine/surface3drenderer.cpp index 68b88bec..3bbade38 100644 --- a/src/datavisualization/engine/surface3drenderer.cpp +++ b/src/datavisualization/engine/surface3drenderer.cpp @@ -56,6 +56,7 @@ const GLfloat gridLineWidth = 0.005f; const GLfloat sliceZScale = 0.1f; const GLfloat sliceUnits = 2.5f; const int subViewDivider = 5; +const uint invalidSelectionId = uint(-1); Surface3DRenderer::Surface3DRenderer(Surface3DController *controller) : Abstract3DRenderer(controller), @@ -63,6 +64,8 @@ Surface3DRenderer::Surface3DRenderer(Surface3DController *controller) m_labelStyle(QDataVis::LabelStyleFromTheme), m_font(QFont(QStringLiteral("Arial"))), m_isGridEnabled(true), + m_cachedIsSlicingActivated(false), + m_cachedInputState(QDataVis::InputStateNone), m_shader(0), m_depthShader(0), m_backgroundShader(0), @@ -107,9 +110,9 @@ Surface3DRenderer::Surface3DRenderer(Surface3DController *controller) m_yFlipped(false), m_sampleSpace(QRect(0, 0, 0, 0)), m_shadowQualityMultiplier(3), - m_cachedSelectionId(0), - m_selectionModeChanged(false), - m_hasHeightAdjustmentChanged(true) + m_clickedPointId(invalidSelectionId), + m_hasHeightAdjustmentChanged(true), + m_selectedPoint(Surface3DController::noSelectionPoint()) { // Check if flat feature is supported ShaderHelper tester(this, QStringLiteral(":/shaders/vertexSurfaceFlat"), @@ -252,19 +255,19 @@ void Surface3DRenderer::updateDataModel(QSurfaceDataProxy *dataProxy) } } - m_selectionActive = false; - m_cachedSelectionId = 0; for (int i = 0; i < m_sliceDataArray.size(); i++) delete m_sliceDataArray.at(i); m_sliceDataArray.clear(); + m_selectionDirty = true; + Abstract3DRenderer::updateDataModel(dataProxy); } -void Surface3DRenderer::updateSliceDataModel(int selectionId) +void Surface3DRenderer::updateSliceDataModel(const QPoint &point) { - int column = (selectionId - 1) % m_sampleSpace.width(); - int row = (selectionId - 1) / m_sampleSpace.width(); + int column = point.y(); + int row = point.x(); for (int i = 0; i < m_sliceDataArray.size(); i++) delete m_sliceDataArray.at(i); @@ -275,7 +278,7 @@ void Surface3DRenderer::updateSliceDataModel(int selectionId) qreal adjust = (0.025 * m_heightNormalizer) / 2.0; qreal stepDown = 2.0 * adjust; - if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow) { + if (m_cachedSelectionMode.testFlag(QDataVis::SelectionRow)) { QSurfaceDataRow *src = m_dataArray.at(row); sliceRow = new QSurfaceDataRow(src->size()); for (int i = 0; i < sliceRow->size(); i++) @@ -433,14 +436,22 @@ void Surface3DRenderer::updateScene(Q3DScene *scene) if (m_selectionPointer) m_selectionPointer->updateScene(m_cachedScene); + + updateSlicingActive(scene->isSlicingActive()); } void Surface3DRenderer::render(GLuint defaultFboHandle) { - bool slicingActivated = m_cachedScene->isSlicingActive(); - bool slicingChanged = m_cachedIsSlicingActivated != slicingActivated; - - updateSlicingActive(slicingActivated); + bool slicingChanged = m_cachedIsSlicingActivated != m_cachedScene->isSlicingActive(); + + // TODO: Can't call back to controller here! (QTRD-2216) + // TODO: Needs to be added to synchronization + QDataVis::InputState currentInputState = m_controller->inputState(); + if (currentInputState != m_cachedInputState) { + if (currentInputState == QDataVis::InputStateOnScene) + m_clickedPointId = invalidSelectionId; + m_cachedInputState = currentInputState; + } // Handle GL state setup for FBO buffers and clearing of the render surface Abstract3DRenderer::render(defaultFboHandle); @@ -448,18 +459,19 @@ void Surface3DRenderer::render(GLuint defaultFboHandle) // Draw the surface scene drawScene(defaultFboHandle); - // In slice mode; draw slice and render selection ball - if (m_cachedIsSlicingActivated) + // In slice mode; draw slice + if (m_cachedIsSlicingActivated && m_selectionActive) drawSlicedScene(); - // Render selection ball if not in slice mode - if (m_selectionPointer && m_selectionActive) + // Render selection ball + if (m_selectionPointer && m_selectionActive + && m_cachedSelectionMode.testFlag(QDataVis::SelectionItem)) { m_selectionPointer->render(defaultFboHandle); + } - // If slicing has been activated by this render pass, we need another render - // Also trigger another render always when slicing changes in general to ensure + // Trigger another render always when slicing changes in general to ensure // final draw is correct. - if (slicingActivated != m_cachedScene->isSlicingActive() || slicingChanged) + if (slicingChanged) emit needRender(); } @@ -487,14 +499,16 @@ void Surface3DRenderer::drawSlicedScene() QMatrix4x4 projectionViewMatrix = projectionMatrix * viewMatrix; + bool rowMode = m_cachedSelectionMode.testFlag(QDataVis::SelectionRow); + GLfloat scaleX = 0.0f; GLfloat scaleXBackground = 0.0f; GLfloat offset = 0.0f; - if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow) { + if (rowMode) { scaleX = m_surfaceScaleX; scaleXBackground = m_scaleXWithBackground; offset = m_surfaceOffsetX; - } else if (m_cachedSelectionMode == QDataVis::SelectionModeSliceColumn) { + } else { scaleX = m_surfaceScaleZ; scaleXBackground = m_scaleZWithBackground; offset = -m_surfaceOffsetZ; @@ -521,7 +535,7 @@ void Surface3DRenderer::drawSlicedScene() MVPMatrix = projectionViewMatrix * modelMatrix; QVector3D color; - if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow) + if (rowMode) color = Utils::vectorFromColor(m_cachedTheme.m_highlightRowColor); else color = Utils::vectorFromColor(m_cachedTheme.m_highlightColumnColor); @@ -611,7 +625,7 @@ void Surface3DRenderer::drawSlicedScene() int lastSegment; GLfloat lineStep; GLfloat linePos; - if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow) { + if (rowMode) { lineStep = -2.0f * aspectRatio * m_axisCacheX.subSegmentStep() / m_scaleFactor; lastSegment = m_axisCacheX.subSegmentCount() * m_axisCacheX.segmentCount(); linePos = m_scaleX; @@ -676,7 +690,7 @@ void Surface3DRenderer::drawSlicedScene() m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, positionComp, rotation, 0, m_cachedSelectionMode, m_labelShader, m_labelObj, m_cachedScene->activeCamera(), - true, true, Drawer::LabelMid, Qt::AlignRight); + true, true, Drawer::LabelMid, Qt::AlignRight, true); } labelNbr++; labelPos += posStep; @@ -685,7 +699,7 @@ void Surface3DRenderer::drawSlicedScene() // X Labels to ground int countLabelItems; int lastSegment; - if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow) { + if (rowMode) { posStep = 2.0f * aspectRatio * m_axisCacheX.segmentStep() / m_scaleFactor; labelPos = -m_scaleX; lastSegment = m_axisCacheX.segmentCount(); @@ -709,15 +723,15 @@ void Surface3DRenderer::drawSlicedScene() m_dummyRenderItem.setTranslation(labelTrans); LabelItem *axisLabelItem; - if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow) + if (rowMode) axisLabelItem = m_axisCacheX.labelItems().at(labelNbr); else axisLabelItem = m_axisCacheZ.labelItems().at(labelNbr); m_drawer->drawLabel(m_dummyRenderItem, *axisLabelItem, viewMatrix, projectionMatrix, - positionComp, rotation, 0, QDataVis::SelectionModeSliceRow, + positionComp, rotation, 0, QDataVis::SelectionRow, m_labelShader, m_labelObj, m_cachedScene->activeCamera(), - false, false, Drawer::LabelBelow, Qt::AlignTop); + false, false, Drawer::LabelBelow, Qt::AlignTop, true); } labelNbr++; labelPos += posStep; @@ -735,7 +749,6 @@ void Surface3DRenderer::drawSlicedScene() void Surface3DRenderer::drawScene(GLuint defaultFboHandle) { GLfloat backgroundRotation = 0; - uint selectionId = 0; // Specify viewport glViewport(m_mainViewPort.x(), m_mainViewPort.y(), @@ -880,15 +893,12 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) #endif } #endif - - bool selectionDirty = false; - // Enable texturing glEnable(GL_TEXTURE_2D); // Draw selection buffer - if (!m_cachedIsSlicingActivated && m_controller->inputState() == QDataVis::InputStateOnScene - && m_surfaceObj && m_cachedSelectionMode > QDataVis::SelectionModeNone) { + if (!m_cachedIsSlicingActivated && m_surfaceObj && m_cachedInputState == QDataVis::InputStateOnScene + && m_cachedSelectionMode > QDataVis::SelectionNone) { m_selectionShader->bind(); glBindFramebuffer(GL_FRAMEBUFFER, m_selectionFrameBuffer); glEnable(GL_DEPTH_TEST); // Needed, otherwise the depth render buffer is not used @@ -924,12 +934,16 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) // Put the RGBA value back to uint #if !defined(QT_OPENGL_ES_2) - selectionId = pixel[0] + pixel[1] * 256 + pixel[2] * 65536 + pixel[3] * 16777216; + uint selectionId = pixel[0] + pixel[1] * 256 + pixel[2] * 65536 + pixel[3] * 16777216; #else - selectionId = pixel[0] + pixel[1] * 256 + pixel[2] * 65536; + uint selectionId = pixel[0] + pixel[1] * 256 + pixel[2] * 65536; #endif - selectionDirty = true; + if (m_clickedPointId == invalidSelectionId) { + m_clickedPointId = selectionId; + QPoint newPoint = selectionIdToSurfacePoint(m_clickedPointId); + emit pointClicked(newPoint); + } } // Draw the surface @@ -1578,39 +1592,30 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) m_labelShader->release(); // Selection handling - if (m_selectionModeChanged || selectionDirty) { - if (selectionDirty) - m_cachedSelectionId = selectionId; - if (m_cachedSelectionMode == QDataVis::SelectionModeNone) { - m_cachedSelectionId = 0; - m_selectionActive = false; - } - if (m_cachedSelectionMode == QDataVis::SelectionModeItem) { - if (m_cachedSelectionId) - surfacePointSelected(m_cachedSelectionId); - else - m_selectionActive = false; - } - if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow - || m_cachedSelectionMode == QDataVis::SelectionModeSliceColumn) { - if (m_cachedSelectionId) { - updateSliceDataModel(m_cachedSelectionId); - m_cachedScene->setSlicingActive(true); - - surfacePointSelected(m_cachedSelectionId); - - emit needRender(); + if (m_selectionDirty) { + QPoint visiblePoint = Surface3DController::noSelectionPoint(); + if (m_selectedPoint != Surface3DController::noSelectionPoint()) { + int x = m_selectedPoint.x() - m_sampleSpace.y(); + int y = m_selectedPoint.y() - m_sampleSpace.x(); + if (x >= 0 && y >= 0 && x < m_sampleSpace.height() && y < m_sampleSpace.width() + && m_dataArray.size()) { + visiblePoint = QPoint(x, y); } } - m_selectionModeChanged = false; - } - if (m_controller->inputState() == QDataVis::InputStateOnOverview) { - if (m_cachedIsSlicingActivated) { - m_cachedScene->setSlicingActive(false); + if (m_cachedSelectionMode == QDataVis::SelectionNone + || visiblePoint == Surface3DController::noSelectionPoint()) { m_selectionActive = false; - m_cachedSelectionId = 0; + } else { + // TODO: Need separate selection ball for slice and main surface view QTRD-2515 + if (m_cachedIsSlicingActivated) + updateSliceDataModel(visiblePoint); + if (m_cachedSelectionMode.testFlag(QDataVis::SelectionItem)) + surfacePointSelected(visiblePoint); + m_selectionActive = true; } + + m_selectionDirty = false; } } @@ -1771,12 +1776,10 @@ bool Surface3DRenderer::updateSmoothStatus(bool enable) return m_cachedSmoothSurface; } -void Surface3DRenderer::updateSelectionMode(QDataVis::SelectionMode mode) +void Surface3DRenderer::updateSelectedPoint(const QPoint &position) { - if (mode != m_cachedSelectionMode) - m_selectionModeChanged = true; - - Abstract3DRenderer::updateSelectionMode(mode); + m_selectedPoint = position; + m_selectionDirty = true; } void Surface3DRenderer::updateSurfaceGridStatus(bool enable) @@ -1824,13 +1827,10 @@ void Surface3DRenderer::handleResize() Abstract3DRenderer::handleResize(); } -void Surface3DRenderer::surfacePointSelected(int id) +void Surface3DRenderer::surfacePointSelected(const QPoint &point) { - int column = (id - 1) % m_sampleSpace.width(); - int row = (id - 1) / m_sampleSpace.width(); - - if (row < 0 || column < 0 || m_dataArray.size() < row || m_dataArray.at(row)->size() < column) - return; + int row = point.x(); + int column = point.y(); qreal value = qreal(m_dataArray.at(row)->at(column).y()); @@ -1838,18 +1838,20 @@ void Surface3DRenderer::surfacePointSelected(int id) m_selectionPointer = new SelectionPointer(m_drawer); QVector3D pos; - if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow) { - pos = m_sliceSurfaceObj->vertexAt(column, 0); - pos *= QVector3D(m_surfaceScaleX, 1.0f, 0.0f); - pos += QVector3D(m_surfaceOffsetX, 0.0f, 0.0f); - m_selectionPointer->updateBoundingRect(m_sliceViewPort); - m_selectionPointer->updateSliceData(true, m_autoScaleAdjustment); - } else if (m_cachedSelectionMode == QDataVis::SelectionModeSliceColumn) { - pos = m_sliceSurfaceObj->vertexAt(row, 0); - pos *= QVector3D(m_surfaceScaleZ, 1.0f, 0.0f); - pos += QVector3D(-m_surfaceOffsetZ, 0.0f, 0.0f); - m_selectionPointer->updateBoundingRect(m_sliceViewPort); - m_selectionPointer->updateSliceData(true, m_autoScaleAdjustment); + if (m_cachedIsSlicingActivated) { + if (m_cachedSelectionMode.testFlag(QDataVis::SelectionRow)) { + pos = m_sliceSurfaceObj->vertexAt(column, 0); + pos *= QVector3D(m_surfaceScaleX, 1.0f, 0.0f); + pos += QVector3D(m_surfaceOffsetX, 0.0f, 0.0f); + m_selectionPointer->updateBoundingRect(m_sliceViewPort); + m_selectionPointer->updateSliceData(true, m_autoScaleAdjustment); + } else if (m_cachedSelectionMode.testFlag(QDataVis::SelectionColumn)) { + pos = m_sliceSurfaceObj->vertexAt(row, 0); + pos *= QVector3D(m_surfaceScaleZ, 1.0f, 0.0f); + pos += QVector3D(-m_surfaceOffsetZ, 0.0f, 0.0f); + m_selectionPointer->updateBoundingRect(m_sliceViewPort); + m_selectionPointer->updateSliceData(true, m_autoScaleAdjustment); + } } else { pos = m_surfaceObj->vertexAt(column, row); pos *= QVector3D(m_surfaceScaleX, 1.0f, m_surfaceScaleZ);; @@ -1861,9 +1863,14 @@ void Surface3DRenderer::surfacePointSelected(int id) m_selectionPointer->setPosition(pos); m_selectionPointer->setLabel(createSelectionLabel(value, column, row)); m_selectionPointer->updateScene(m_cachedScene); +} - //Put the selection pointer flag active - m_selectionActive = true; +// Maps selection Id to surface point in data array +QPoint Surface3DRenderer::selectionIdToSurfacePoint(uint id) +{ + int column = ((id - 1) % m_sampleSpace.width()) + m_sampleSpace.x(); + int row = ((id - 1) / m_sampleSpace.width()) + m_sampleSpace.y(); + return QPoint(row, column); } QString Surface3DRenderer::createSelectionLabel(qreal value, int column, int row) @@ -1968,6 +1975,8 @@ void Surface3DRenderer::updateSlicingActive(bool isSlicing) #if !defined(QT_OPENGL_ES_2) updateDepthBuffer(); // Re-init depth buffer as well #endif + + m_selectionDirty = true; } void Surface3DRenderer::setViewPorts() diff --git a/src/datavisualization/engine/surface3drenderer_p.h b/src/datavisualization/engine/surface3drenderer_p.h index c805e508..72a83692 100644 --- a/src/datavisualization/engine/surface3drenderer_p.h +++ b/src/datavisualization/engine/surface3drenderer_p.h @@ -70,6 +70,7 @@ public: private: bool m_cachedIsSlicingActivated; + QDataVis::InputState m_cachedInputState; // Internal attributes purely related to how the scene is drawn with GL. QRect m_mainViewPort; @@ -124,9 +125,9 @@ private: QRect m_sampleSpace; GLint m_shadowQualityMultiplier; QSizeF m_areaSize; - uint m_cachedSelectionId; - bool m_selectionModeChanged; + uint m_clickedPointId; bool m_hasHeightAdjustmentChanged; + QPoint m_selectedPoint; public: explicit Surface3DRenderer(Surface3DController *controller); @@ -146,11 +147,14 @@ public slots: void updateSurfaceGridStatus(bool enable); void updateSurfaceGradient(const QLinearGradient &gradient); void updateSlicingActive(bool isSlicing); - void updateSelectionMode(QDataVis::SelectionMode mode); + void updateSelectedPoint(const QPoint &position); + +signals: + void pointClicked(QPoint position); private: void setViewPorts(); - void updateSliceDataModel(int selectionId); + void updateSliceDataModel(const QPoint &point); virtual void updateShadowQuality(QDataVis::ShadowQuality quality); virtual void updateTextures(); virtual void initShaders(const QString &vertexShader, const QString &fragmentShader); @@ -172,11 +176,13 @@ private: void updateSelectionTexture(); void idToRGBA(uint id, uchar *r, uchar *g, uchar *b, uchar *a); void fillIdCorner(uchar *p, uchar r, uchar g, uchar b, uchar a, int stride); - void surfacePointSelected(int id); + void surfacePointSelected(const QPoint &point); + QPoint selectionIdToSurfacePoint(uint id); QString createSelectionLabel(qreal value, int column, int row); #if !defined(QT_OPENGL_ES_2) void updateDepthBuffer(); #endif + void emitSelectedPointChanged(QPoint position); Q_DISABLE_COPY(Surface3DRenderer) }; diff --git a/src/datavisualization/global/qdatavisualizationenums.h b/src/datavisualization/global/qdatavisualizationenums.h index 3d765ff2..22599fbb 100644 --- a/src/datavisualization/global/qdatavisualizationenums.h +++ b/src/datavisualization/global/qdatavisualizationenums.h @@ -31,9 +31,9 @@ class QT_DATAVISUALIZATION_EXPORT QDataVis : public QObject Q_ENUMS(MeshStyle) Q_ENUMS(CameraPreset) Q_ENUMS(Theme) - Q_ENUMS(SelectionMode) Q_ENUMS(ShadowQuality) Q_ENUMS(LabelStyle) + Q_FLAGS(SelectionFlag SelectionFlags) public: enum InputState { @@ -95,15 +95,18 @@ public: ThemeIsabelle }; - enum SelectionMode { - SelectionModeNone = 0, - SelectionModeItem, - SelectionModeItemAndRow, - SelectionModeItemAndColumn, - SelectionModeItemRowAndColumn, - SelectionModeSliceRow, - SelectionModeSliceColumn + enum SelectionFlag { + SelectionNone = 0, + SelectionItem = 1, + SelectionRow = 2, + SelectionItemAndRow = SelectionItem | SelectionRow, + SelectionColumn = 4, + SelectionItemAndColumn = SelectionItem | SelectionColumn, + SelectionRowAndColumn = SelectionRow | SelectionColumn, + SelectionItemRowAndColumn = SelectionItem | SelectionRow | SelectionColumn, + SelectionSlice = 8 }; + Q_DECLARE_FLAGS(SelectionFlags, SelectionFlag) enum ShadowQuality { ShadowQualityNone = 0, @@ -121,6 +124,8 @@ public: LabelStyleTransparent }; }; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QDataVis::SelectionFlags) } #endif diff --git a/src/datavisualization/global/qtdatavisualizationenums.qdoc b/src/datavisualization/global/qtdatavisualizationenums.qdoc index d448953d..c3569ee4 100644 --- a/src/datavisualization/global/qtdatavisualizationenums.qdoc +++ b/src/datavisualization/global/qtdatavisualizationenums.qdoc @@ -130,29 +130,31 @@ */ /*! - \enum QtDataVisualization::QDataVis::SelectionMode + \enum QtDataVisualization::QDataVis::SelectionFlag - Item selection modes. + Item selection modes. Values of this enumeration can be combined with OR operator. - \value SelectionModeNone + \value SelectionNone Selection mode disabled. - \value SelectionModeItem - Selection selects a single item. - \value SelectionModeItemAndRow - Selection selects a single item and highlights the row it is on. In Q3DBars only. - \value SelectionModeItemAndColumn - Selection selects a single item and highlights the column it is on. In Q3DBars only. - \value SelectionModeItemRowAndColumn - Selection selects a single item and highlights the row and the column it is on. In - Q3DBars only. - \value SelectionModeSliceRow - Selection selects a single item and displays the row it is on in a separate view. The - original view is shrunk into upper left corner. Original view is restored by clicking - on it. In Q3DBars only. - \value SelectionModeSliceColumn - Selection selects a single item and displays the column it is on in a separate view. The - original view is shrunk into upper left corner. Original view is restored by clicking - on it. In Q3DBars only. + \value SelectionItem + Selection highlights a single item. + \value SelectionRow + Selection highlights a single row. + \value SelectionItemAndRow + Combination flag for highlighting both item and row with different colors. + \value SelectionColumn + Selection highlights a single column. + \value SelectionItemAndColumn + Combination flag for highlighting both item and column with different colors. + \value SelectionRowAndColumn + Combination flag for highlighting both row and column. + \value SelectionItemRowAndColumn + Combination flag for highlighting item, row, and column. + \value SelectionSlice + Setting this mode flag indicates that the graph should take care of the slice view handling + automatically. If you wish to control the slice view yourself via Q3DScene, do not set this + flag. When setting this mode flag, either \c SelectionRow or \c SelectionColumn must also + be set, but not both. Slicing is supported by Q3DBars and Q3DSurface only. */ /*! diff --git a/src/datavisualizationqml2/abstractdeclarative.cpp b/src/datavisualizationqml2/abstractdeclarative.cpp index e853ff9c..d4b5c7b7 100644 --- a/src/datavisualizationqml2/abstractdeclarative.cpp +++ b/src/datavisualizationqml2/abstractdeclarative.cpp @@ -47,12 +47,12 @@ QDataVis::Theme AbstractDeclarative::theme() const return m_controller->theme().theme(); } -void AbstractDeclarative::setSelectionMode(QDataVis::SelectionMode mode) +void AbstractDeclarative::setSelectionMode(QDataVis::SelectionFlags mode) { m_controller->setSelectionMode(mode); } -QDataVis::SelectionMode AbstractDeclarative::selectionMode() const +QDataVis::SelectionFlags AbstractDeclarative::selectionMode() const { return m_controller->selectionMode(); } diff --git a/src/datavisualizationqml2/abstractdeclarative_p.h b/src/datavisualizationqml2/abstractdeclarative_p.h index 41d4a4da..842dbf4b 100644 --- a/src/datavisualizationqml2/abstractdeclarative_p.h +++ b/src/datavisualizationqml2/abstractdeclarative_p.h @@ -42,7 +42,7 @@ QT_DATAVISUALIZATION_BEGIN_NAMESPACE class AbstractDeclarative : public QQuickItem { Q_OBJECT - Q_PROPERTY(QtDataVisualization::QDataVis::SelectionMode selectionMode READ selectionMode WRITE setSelectionMode) + Q_PROPERTY(QtDataVisualization::QDataVis::SelectionFlags selectionMode READ selectionMode WRITE setSelectionMode) Q_PROPERTY(QtDataVisualization::QDataVis::LabelStyle labelStyle READ labelStyle WRITE setLabelStyle) Q_PROPERTY(QtDataVisualization::QDataVis::ShadowQuality shadowQuality READ shadowQuality WRITE setShadowQuality) Q_PROPERTY(Q3DScene* scene READ scene NOTIFY sceneChanged) @@ -52,11 +52,6 @@ class AbstractDeclarative : public QQuickItem Q_PROPERTY(bool gridVisible READ isGridVisible WRITE setGridVisible) Q_PROPERTY(bool backgroundVisible READ isBackgroundVisible WRITE setBackgroundVisible) Q_PROPERTY(QString itemLabelFormat READ itemLabelFormat WRITE setItemLabelFormat) - Q_ENUMS(QtDataVisualization::QDataVis::SelectionMode) - Q_ENUMS(QtDataVisualization::QDataVis::ShadowQuality) - Q_ENUMS(QtDataVisualization::QDataVis::LabelStyle) - Q_ENUMS(QtDataVisualization::QDataVis::CameraPreset) - Q_ENUMS(QtDataVisualization::QDataVis::Theme) public: explicit AbstractDeclarative(QQuickItem *parent = 0); @@ -70,8 +65,8 @@ public: virtual void setTheme(QDataVis::Theme theme); virtual QDataVis::Theme theme() const; - virtual void setSelectionMode(QDataVis::SelectionMode mode); - virtual QDataVis::SelectionMode selectionMode() const; + virtual void setSelectionMode(QDataVis::SelectionFlags mode); + virtual QDataVis::SelectionFlags selectionMode() const; virtual void setFont(const QFont &font); virtual QFont font() const; diff --git a/src/datavisualizationqml2/declarativebars.cpp b/src/datavisualizationqml2/declarativebars.cpp index 9ed80106..52b19807 100644 --- a/src/datavisualizationqml2/declarativebars.cpp +++ b/src/datavisualizationqml2/declarativebars.cpp @@ -41,8 +41,8 @@ DeclarativeBars::DeclarativeBars(QQuickItem *parent) // Create the shared component on the main GUI thread. m_shared = new Bars3DController(boundingRect().toRect()); AbstractDeclarative::setSharedController(m_shared); - QObject::connect(m_shared, &Bars3DController::selectedBarPosChanged, this, - &DeclarativeBars::selectedBarPosChanged); + QObject::connect(m_shared, &Bars3DController::selectedBarChanged, this, + &DeclarativeBars::selectedBarChanged); QItemModelBarDataProxy *proxy = new QItemModelBarDataProxy; m_shared->setActiveDataProxy(proxy); @@ -201,14 +201,14 @@ QString DeclarativeBars::meshFileName() const return m_shared->meshFileName(); } -void DeclarativeBars::setSelectedBarPos(const QPointF &position) +void DeclarativeBars::setSelectedBar(const QPointF &position) { - m_shared->setSelectedBarPos(position.toPoint()); + m_shared->setSelectedBar(position.toPoint()); } -QPointF DeclarativeBars::selectedBarPos() const +QPointF DeclarativeBars::selectedBar() const { - return QPointF(m_shared->selectedBarPos()); + return QPointF(m_shared->selectedBar()); } QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualizationqml2/declarativebars_p.h b/src/datavisualizationqml2/declarativebars_p.h index dfbf9934..f71d9ad3 100644 --- a/src/datavisualizationqml2/declarativebars_p.h +++ b/src/datavisualizationqml2/declarativebars_p.h @@ -57,7 +57,7 @@ class DeclarativeBars : public AbstractDeclarative Q_PROPERTY(bool barSpacingRelative READ isBarSpacingRelative WRITE setBarSpacingRelative) Q_PROPERTY(bool barSmoothingEnabled READ isBarSmoothingEnabled WRITE setBarSmoothingEnabled) Q_PROPERTY(QString meshFileName READ meshFileName WRITE setMeshFileName) - Q_PROPERTY(QPointF selectedBarPos READ selectedBarPos WRITE setSelectedBarPos NOTIFY selectedBarPosChanged) + Q_PROPERTY(QPointF selectedBar READ selectedBar WRITE setSelectedBar NOTIFY selectedBarChanged) Q_ENUMS(QtDataVisualization::QDataVis::MeshStyle) public: @@ -94,11 +94,11 @@ public: void setMeshFileName(const QString &objFileName); QString meshFileName() const; - void setSelectedBarPos(const QPointF &position); - QPointF selectedBarPos() const; + void setSelectedBar(const QPointF &position); + QPointF selectedBar() const; signals: - void selectedBarPosChanged(const QPointF &position); + void selectedBarChanged(const QPointF &position); protected: QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *); diff --git a/tests/barstest/chart.cpp b/tests/barstest/chart.cpp index ad27d83c..d71f60b4 100644 --- a/tests/barstest/chart.cpp +++ b/tests/barstest/chart.cpp @@ -42,7 +42,7 @@ GraphModifier::GraphModifier(Q3DBars *barchart) m_subSegments(3), m_minval(-20.0), // TODO Barchart Y-axis currently only properly supports zero-centered ranges m_maxval(20.0), - m_selectedBarPos(-1, -1), + m_selectedBar(-1, -1), m_autoAdjustingAxis(new Q3DValueAxis), m_fixedRangeAxis(new Q3DValueAxis), m_temperatureAxis(new Q3DValueAxis), @@ -142,7 +142,7 @@ void GraphModifier::restart(bool dynamicData) m_chart->setRowAxis(m_yearAxis); m_chart->setColumnAxis(m_monthAxis); - m_chart->setSelectionMode(QDataVis::SelectionModeItem); + m_chart->setSelectionMode(QDataVis::SelectionItem); } else { m_chart->setActiveDataProxy(m_genericData); @@ -152,7 +152,7 @@ void GraphModifier::restart(bool dynamicData) m_chart->setRowAxis(m_genericRowAxis); m_chart->setColumnAxis(m_genericColumnAxis); - m_chart->setSelectionMode(QDataVis::SelectionModeItem); + m_chart->setSelectionMode(QDataVis::SelectionItem); } } @@ -160,10 +160,10 @@ void GraphModifier::selectBar() { QPoint targetBar(5, 5); QPoint noSelection(-1, -1); - if (m_selectedBarPos != targetBar) - m_chart->setSelectedBarPos(targetBar); + if (m_selectedBar != targetBar) + m_chart->setSelectedBar(targetBar); else - m_chart->setSelectedBarPos(noSelection); + m_chart->setSelectedBar(noSelection); } void GraphModifier::swapAxis() @@ -317,7 +317,7 @@ void GraphModifier::insertRow() (*dataRow)[i].setValue(((i + 1) / (qreal)m_columnCount) * (qreal)(rand() % 100)); // TODO Needs to be changed to account for data window offset once it is implemented. - int row = qMax(m_selectedBarPos.x(), 0); + int row = qMax(m_selectedBar.x(), 0); QString label = QStringLiteral("Insert %1").arg(insertCounter++); m_chart->activeDataProxy()->insertRow(row, dataRow, label); } @@ -337,7 +337,7 @@ void GraphModifier::insertRows() } // TODO Needs to be changed to account for data window offset once it is implemented. - int row = qMax(m_selectedBarPos.x(), 0); + int row = qMax(m_selectedBar.x(), 0); m_chart->activeDataProxy()->insertRows(row, dataArray, labels); qDebug() << "Inserted" << m_rowCount << "rows, time:" << timer.elapsed(); } @@ -345,8 +345,8 @@ void GraphModifier::insertRows() void GraphModifier::changeItem() { // TODO Needs to be changed to account for data window offset once it is implemented. - int row = m_selectedBarPos.x(); - int column = m_selectedBarPos.y(); + int row = m_selectedBar.x(); + int column = m_selectedBar.y(); if (row >= 0 && column >= 0) { QBarDataItem item(qreal(rand() % 100)); m_chart->activeDataProxy()->setItem(row, column, item); @@ -356,7 +356,7 @@ void GraphModifier::changeItem() void GraphModifier::changeRow() { // TODO Needs to be changed to account for data window offset once it is implemented. - int row = m_selectedBarPos.x(); + int row = m_selectedBar.x(); if (row >= 0) { QBarDataRow *newRow = new QBarDataRow(m_chart->activeDataProxy()->rowAt(row)->size()); for (int i = 0; i < newRow->size(); i++) @@ -369,7 +369,7 @@ void GraphModifier::changeRow() void GraphModifier::changeRows() { // TODO Needs to be changed to account for data window offset once it is implemented. - int row = m_selectedBarPos.x(); + int row = m_selectedBar.x(); if (row >= 0) { int startRow = qMax(row - 2, 0); QBarDataArray newArray; @@ -388,7 +388,7 @@ void GraphModifier::changeRows() void GraphModifier::removeRow() { // TODO Needs to be changed to account for data window offset once it is implemented. - int row = m_selectedBarPos.x(); + int row = m_selectedBar.x(); if (row >= 0) m_chart->activeDataProxy()->removeRows(row, 1); } @@ -396,7 +396,7 @@ void GraphModifier::removeRow() void GraphModifier::removeRows() { // TODO Needs to be changed to account for data window offset once it is implemented. - int row = m_selectedBarPos.x(); + int row = m_selectedBar.x(); if (row >= 0) { int startRow = qMax(row - 2, 0); m_chart->activeDataProxy()->removeRows(startRow, 3); @@ -477,10 +477,10 @@ void GraphModifier::changeSelectionMode() { static int selectionMode = m_chart->selectionMode(); - if (++selectionMode > QDataVis::SelectionModeSliceColumn) - selectionMode = QDataVis::SelectionModeNone; + if (++selectionMode > (QDataVis::SelectionItemAndColumn | QDataVis::SelectionSlice)) + selectionMode = QDataVis::SelectionNone; - m_chart->setSelectionMode((QDataVis::SelectionMode)selectionMode); + m_chart->setSelectionMode((QDataVis::SelectionFlag)selectionMode); } void GraphModifier::changeFont(const QFont &font) @@ -507,7 +507,7 @@ void GraphModifier::shadowQualityUpdatedByVisual(QDataVis::ShadowQuality sq) void GraphModifier::handleSelectionChange(const QPoint &position) { - m_selectedBarPos = position; + m_selectedBar = position; qDebug() << "Selected bar position:" << position; } diff --git a/tests/barstest/chart.h b/tests/barstest/chart.h index e4e96ffb..6d33bacb 100644 --- a/tests/barstest/chart.h +++ b/tests/barstest/chart.h @@ -96,7 +96,7 @@ private: qreal m_maxval; QStringList m_months; QStringList m_years; - QPoint m_selectedBarPos; + QPoint m_selectedBar; Q3DValueAxis *m_autoAdjustingAxis; Q3DValueAxis *m_fixedRangeAxis; Q3DValueAxis *m_temperatureAxis; diff --git a/tests/barstest/main.cpp b/tests/barstest/main.cpp index 7742cb0e..0d3838a8 100644 --- a/tests/barstest/main.cpp +++ b/tests/barstest/main.cpp @@ -287,7 +287,7 @@ int main(int argc, char **argv) &QComboBox::setCurrentIndex); QObject::connect(widgetchart, &Q3DBars::shadowQualityChanged, modifier, &GraphModifier::shadowQualityUpdatedByVisual); - QObject::connect(widgetchart, &Q3DBars::selectedBarPosChanged, modifier, + QObject::connect(widgetchart, &Q3DBars::selectedBarChanged, modifier, &GraphModifier::handleSelectionChange); QObject::connect(fontSizeSlider, &QSlider::valueChanged, modifier, diff --git a/tests/kinectsurface/surfacedata.cpp b/tests/kinectsurface/surfacedata.cpp index b11be8d5..79489fc8 100644 --- a/tests/kinectsurface/surfacedata.cpp +++ b/tests/kinectsurface/surfacedata.cpp @@ -45,7 +45,7 @@ SurfaceData::SurfaceData(Q3DSurface *surface, Q3DScatter *scatter, Q3DBars *bars gradient.setColorAt(0.33, Qt::blue); gradient.setColorAt(0.67, Qt::red); gradient.setColorAt(1.0, Qt::yellow); - m_surface->setSelectionMode(QDataVis::SelectionModeNone); + m_surface->setSelectionMode(QDataVis::SelectionNone); m_surface->setGridVisible(false); m_surface->setGradient(gradient); m_surface->axisY()->setMax(255); @@ -57,7 +57,7 @@ SurfaceData::SurfaceData(Q3DSurface *surface, Q3DScatter *scatter, Q3DBars *bars // Initialize scatter m_scatter->setTheme(QDataVis::ThemeStoneMoss); - m_scatter->setSelectionMode(QDataVis::SelectionModeNone); + m_scatter->setSelectionMode(QDataVis::SelectionNone); m_scatter->setGridVisible(false); m_scatter->setObjectType(QDataVis::MeshStyleDots, false); m_scatter->setShadowQuality(QDataVis::ShadowQualitySoftLow); diff --git a/tests/qmlcamera/qml/qmlcamera/main.qml b/tests/qmlcamera/qml/qmlcamera/main.qml index 72d2a45f..dbe11b8e 100644 --- a/tests/qmlcamera/qml/qmlcamera/main.qml +++ b/tests/qmlcamera/qml/qmlcamera/main.qml @@ -46,7 +46,7 @@ Item { width: dataView.width height: dataView.height shadowQuality: Bars3D.ShadowQualityMedium - selectionMode: Bars3D.SelectionModeItem + selectionMode: Bars3D.SelectionItem font.pointSize: 35 theme: Bars3D.ThemeRetro labelStyle: Bars3D.LabelStyleFromTheme @@ -59,7 +59,7 @@ Item { valueAxis: chartAxes.expenses itemLabelFormat: "@valueTitle for @colLabel, @rowLabel: @valueLabel" - onSelectedBarPosChanged: { + onSelectedBarChanged: { // Set camControlArea current row to selected bar var rowRole = chartData.proxy.rowLabels[position.x]; var colRole = chartData.proxy.columnLabels[position.y]; diff --git a/tests/scattertest/scatterchart.cpp b/tests/scattertest/scatterchart.cpp index f23ee99d..48f1d999 100644 --- a/tests/scattertest/scatterchart.cpp +++ b/tests/scattertest/scatterchart.cpp @@ -48,6 +48,8 @@ ScatterDataModifier::ScatterDataModifier(Q3DScatter *scatter) proxy->setItemLabelFormat("@xTitle: @xLabel @yTitle: @yLabel @zTitle: @zLabel"); m_chart->setActiveDataProxy(proxy); + m_chart->setSelectionMode(QDataVis::SelectionItemAndColumn); + connect(&m_timer, &QTimer::timeout, this, &ScatterDataModifier::timeout); } diff --git a/tests/spectrum/spectrumapp/main.cpp b/tests/spectrum/spectrumapp/main.cpp index 3d2e2bf1..31bdb0f1 100644 --- a/tests/spectrum/spectrumapp/main.cpp +++ b/tests/spectrum/spectrumapp/main.cpp @@ -99,7 +99,7 @@ MainApp::MainApp(Q3DBars *window) // Set color scheme m_chart->setBarColor(QColor(Qt::red), false); // Disable selection - m_chart->setSelectionMode(QDataVis::SelectionModeNone); + m_chart->setSelectionMode(QDataVis::SelectionNone); QObject::connect(m_engine, &Engine::changedSpectrum, this, &MainApp::spectrumChanged); QObject::connect(m_engine, &Engine::stateChanged, this, &MainApp::stateChanged); m_restartTimer->setSingleShot(true); diff --git a/tests/surfacetest/graphmodifier.cpp b/tests/surfacetest/graphmodifier.cpp index d4e99031..bd6ec920 100644 --- a/tests/surfacetest/graphmodifier.cpp +++ b/tests/surfacetest/graphmodifier.cpp @@ -23,11 +23,12 @@ #include <qmath.h> #include <QLinearGradient> #include <QDebug> +#include <QComboBox> QT_DATAVISUALIZATION_USE_NAMESPACE //#define JITTER_PLANE -//#define WONKY_PLANE +#define WONKY_PLANE GraphModifier::GraphModifier(Q3DSurface *graph) : m_graph(graph), @@ -55,6 +56,7 @@ GraphModifier::GraphModifier(Q3DSurface *graph) changeStyle(); connect(&m_timer, &QTimer::timeout, this, &GraphModifier::timeout); + connect(m_graph, &Q3DSurface::selectedPointChanged, this, &GraphModifier::selectedPointChanged); } GraphModifier::~GraphModifier() @@ -137,6 +139,7 @@ void GraphModifier::togglePlane(bool enable) float halfZ = m_zCount / 2; float wonkyFactor = 0.01f; float maxStepX = 0.0f; + float add = 0.0f; for (float i = 0; i < m_zCount; i++) { QSurfaceDataRow *newRow = new QSurfaceDataRow(m_xCount); if (i < halfZ) { @@ -145,15 +148,17 @@ void GraphModifier::togglePlane(bool enable) } else { stepX -= wonkyFactor; } + add = 0.0f; for (float j = 0; j < m_xCount; j++) { (*newRow)[j].setPosition(QVector3D(j * stepX + minX, -0.04f, - i * stepZ + minZ)); + i * stepZ + minZ + add)); + add += 0.5f; } *m_planeArray << newRow; } - resetArrayAndSliders(m_planeArray, minZ, maxZ, minX, m_xCount * maxStepX + minZ); + resetArrayAndSliders(m_planeArray, minZ, maxZ + add, minX, m_xCount * maxStepX + minX); #else for (float i = 0; i < m_zCount; i++) { QSurfaceDataRow *newRow = new QSurfaceDataRow(m_xCount); @@ -303,6 +308,20 @@ void GraphModifier::changeStyle() style = QDataVis::LabelStyleOpaque; } +void GraphModifier::selectButtonClicked() +{ + int row = rand() % m_graph->activeDataProxy()->rowCount(); + int col = rand() % m_graph->activeDataProxy()->columnCount(); + + m_graph->setSelectedPoint(QPoint(row, col)); +} + +void GraphModifier::selectedPointChanged(const QPoint &point) +{ + QString labelText = QStringLiteral("Selected row: %1, column: %2").arg(point.x()).arg(point.y()); + m_selectionInfoLabel->setText(labelText); +} + void GraphModifier::changeTheme(int theme) { m_graph->setTheme((QDataVis::Theme)theme); @@ -347,26 +366,10 @@ void GraphModifier::changeShadowQuality(int quality) void GraphModifier::changeSelectionMode(int mode) { - switch (mode) { - case 0: - qDebug() << "QDataVis::SelectionModeNone"; - m_graph->setSelectionMode(QDataVis::SelectionModeNone); - break; - case 1: - qDebug() << "QDataVis::SelectionModeItem"; - m_graph->setSelectionMode(QDataVis::SelectionModeItem); - break; - case 2: - qDebug() << "QDataVis::SelectionModeSliceRow"; - m_graph->setSelectionMode(QDataVis::SelectionModeSliceRow); - break; - case 3: - qDebug() << "QDataVis::SelectionModeSliceColumn"; - m_graph->setSelectionMode(QDataVis::SelectionModeSliceColumn); - break; - default: - qDebug() << __FUNCTION__ << " Unsupported selection mode."; - break; + QComboBox *comboBox = qobject_cast<QComboBox *>(sender()); + if (comboBox) { + int flags = comboBox->itemData(mode).toInt(); + m_graph->setSelectionMode(QDataVis::SelectionFlags(flags)); } } diff --git a/tests/surfacetest/graphmodifier.h b/tests/surfacetest/graphmodifier.h index 83b1873b..ed94b372 100644 --- a/tests/surfacetest/graphmodifier.h +++ b/tests/surfacetest/graphmodifier.h @@ -23,6 +23,7 @@ #include <QtDataVisualization/QSurfaceDataProxy> #include <QSlider> #include <QTimer> +#include <QLabel> using namespace QtDataVisualization; @@ -61,6 +62,9 @@ public: void gradientPressed(); void changeFont(const QFont &font); void changeStyle(); + void selectButtonClicked(); + void setSelectionInfoLabel(QLabel *label) {m_selectionInfoLabel = label; } + void selectedPointChanged(const QPoint &point); public slots: void changeShadowQuality(int quality); @@ -90,6 +94,7 @@ private: qreal m_minZ; QTimer m_timer; QSurfaceDataArray *m_planeArray; + QLabel *m_selectionInfoLabel; }; #endif diff --git a/tests/surfacetest/main.cpp b/tests/surfacetest/main.cpp index 19f30e5d..e4283b3e 100644 --- a/tests/surfacetest/main.cpp +++ b/tests/surfacetest/main.cpp @@ -167,12 +167,37 @@ int main(int argc, char *argv[]) // shadowQuality->addItem(QStringLiteral("High Soft")); // shadowQuality->setCurrentIndex(3); QComboBox *selectionMode = new QComboBox(widget); - selectionMode->addItem(QStringLiteral("SelectionModeNone")); - selectionMode->addItem(QStringLiteral("SelectionModeItem")); - selectionMode->addItem(QStringLiteral("SelectionModeSliceRow")); - selectionMode->addItem(QStringLiteral("SelectionModeSliceColumn")); + selectionMode->addItem(QStringLiteral("None"), + int(QDataVis::SelectionNone)); + selectionMode->addItem(QStringLiteral("Item"), + int(QDataVis::SelectionItem)); + selectionMode->addItem(QStringLiteral("Row"), + int(QDataVis::SelectionRow)); + selectionMode->addItem(QStringLiteral("Item and Row"), + int(QDataVis::SelectionItemAndRow)); + selectionMode->addItem(QStringLiteral("Column"), + int(QDataVis::SelectionColumn)); + selectionMode->addItem(QStringLiteral("Item and Column"), + int(QDataVis::SelectionItemAndColumn)); + selectionMode->addItem(QStringLiteral("Row and Column"), + int(QDataVis::SelectionRowAndColumn)); + selectionMode->addItem(QStringLiteral("Item, Row and Column"), + int(QDataVis::SelectionItemRowAndColumn)); + selectionMode->addItem(QStringLiteral("Slice into Row"), + int(QDataVis::SelectionSlice | QDataVis::SelectionRow)); + selectionMode->addItem(QStringLiteral("Slice into Row and Item"), + int(QDataVis::SelectionSlice | QDataVis::SelectionItemAndRow)); + selectionMode->addItem(QStringLiteral("Slice into Column"), + int(QDataVis::SelectionSlice | QDataVis::SelectionColumn)); + selectionMode->addItem(QStringLiteral("Slice into Column and Item"), + int(QDataVis::SelectionSlice | QDataVis::SelectionItemAndColumn)); selectionMode->setCurrentIndex(1); + QPushButton *selectButton = new QPushButton(widget); + selectButton->setText(QStringLiteral("Select random point")); + + QLabel *selectionInfoLabel = new QLabel(widget); + // Add controls to the layout vLayout->addWidget(smoothCB); vLayout->addWidget(surfaceGridCB); @@ -200,6 +225,8 @@ int main(int argc, char *argv[]) // vLayout->addWidget(shadowQuality); vLayout->addWidget(new QLabel(QStringLiteral("Selection Mode"))); vLayout->addWidget(selectionMode); + vLayout->addWidget(selectButton); + vLayout->addWidget(selectionInfoLabel); widget->show(); @@ -242,6 +269,8 @@ int main(int argc, char *argv[]) // modifier, SLOT(changeShadowQuality(int))); QObject::connect(selectionMode, SIGNAL(currentIndexChanged(int)), modifier, SLOT(changeSelectionMode(int))); + QObject::connect(selectButton, &QPushButton::clicked, + modifier, &GraphModifier::selectButtonClicked); modifier->setGridSliderZ(gridSliderZ); modifier->setGridSliderX(gridSliderX); @@ -250,6 +279,7 @@ int main(int argc, char *argv[]) modifier->setAxisMinSliderX(axisMinSliderX); modifier->setAxisMinSliderZ(axisMinSliderZ); modifier->toggleGridSliderLock(gridSlidersLockCB->checkState()); + modifier->setSelectionInfoLabel(selectionInfoLabel); sqrtSinCB->setChecked(true); return app.exec(); |