From 018b9855f394271fa20f3e65fc1ca71c90f32384 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Mon, 12 Aug 2013 14:26:41 +0300 Subject: Add some missing data manipulation methods to bar proxy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit + Related widget example changes + Changed shadow perspective to get rid of some artifacts + Accessor for sample space size Change-Id: I7c4d7038479b65016209624d8e2ea77794210005 Reviewed-by: Tomi Korpipää --- examples/widget/chart.cpp | 61 +++++++++++++++++++++++++++ examples/widget/chart.h | 5 +++ examples/widget/main.cpp | 40 ++++++++++++++++++ src/datavis3d/data/qbardataproxy.cpp | 70 +++++++++++++++++++++++++++++-- src/datavis3d/data/qbardataproxy.h | 42 ++++++++++++++----- src/datavis3d/data/qbardataproxy_p.h | 3 ++ src/datavis3d/engine/bars3dcontroller.cpp | 12 ++++++ src/datavis3d/engine/bars3dcontroller_p.h | 1 + src/datavis3d/engine/bars3drenderer.cpp | 2 +- src/datavis3d/engine/q3dbars.cpp | 5 +++ src/datavis3d/engine/q3dbars.h | 1 + 11 files changed, 228 insertions(+), 14 deletions(-) diff --git a/examples/widget/chart.cpp b/examples/widget/chart.cpp index d1038839..bd282b44 100644 --- a/examples/widget/chart.cpp +++ b/examples/widget/chart.cpp @@ -208,6 +208,67 @@ void ChartModifier::addRows() qDebug() << "Added" << m_rowCount << "rows, time:" << timer.elapsed(); } +void ChartModifier::changeItem() +{ + // TODO fix to use actual selected item, for now just assume some row/column are selected + int row = qMin(4, (m_chart->dataProxy()->rowCount() - 1)); + if (row >= 0) { + int column = qMin(4, (m_chart->dataProxy()->rowAt(row)->size() - 1)); + if (column >= 0) { + QBarDataItem *item = new QBarDataItem(); + item->setValue(qreal(rand() % 100)); + m_chart->dataProxy()->setItem(row, column, item); + } + } +} + +void ChartModifier::changeRow() +{ + // TODO fix to use actual selected item, for now just assume some is selected + int row = qMin(4, (m_chart->dataProxy()->rowCount() - 1)); + if (row >= 0) { + QBarDataRow *newRow = new QBarDataRow(m_chart->dataProxy()->rowAt(row)->size()); + for (int i = 0; i < newRow->size(); i++) + (*newRow)[i].setValue(qreal(rand() % 100)); + m_chart->dataProxy()->setRow(row, newRow); + } +} + +void ChartModifier::changeRows() +{ + // TODO fix to use actual selected item, for now just assume some is selected + int row = qMin(4, (m_chart->dataProxy()->rowCount() - 1)); + if (row >= 0) { + int startRow = qMax(row - 2, 0); + QBarDataArray *newArray = new QBarDataArray; + for (int i = startRow; i <= row; i++ ) { + QBarDataRow *newRow = new QBarDataRow(m_chart->dataProxy()->rowAt(i)->size()); + for (int j = 0; j < newRow->size(); j++) + (*newRow)[j].setValue(qreal(rand() % 100)); + newArray->append(newRow); + } + m_chart->dataProxy()->setRows(startRow, newArray); + } +} + +void ChartModifier::removeRow() +{ + // TODO fix to use actual selected item, for now just assume some is selected + int row = qMin(4, (m_chart->dataProxy()->rowCount() - 1)); + if (row >= 0) + m_chart->dataProxy()->removeRows(row, 1); +} + +void ChartModifier::removeRows() +{ + // TODO fix to use actual selected item, for now just assume some is selected + int row = qMin(4, (m_chart->dataProxy()->rowCount() - 1)); + if (row >= 0) { + int startRow = qMax(row - 2, 0); + m_chart->dataProxy()->removeRows(startRow, 3); + } +} + void ChartModifier::changeStyle() { static int model = 0; diff --git a/examples/widget/chart.h b/examples/widget/chart.h index e42257ce..c4f21d7d 100644 --- a/examples/widget/chart.h +++ b/examples/widget/chart.h @@ -59,6 +59,11 @@ public: void addDataSet(); void addRow(); void addRows(); + void changeItem(); + void changeRow(); + void changeRows(); + void removeRow(); + void removeRows(); void changeStyle(); void changePresetCamera(); void changeTheme(); diff --git a/examples/widget/main.cpp b/examples/widget/main.cpp index 9614cc0f..1c537de5 100644 --- a/examples/widget/main.cpp +++ b/examples/widget/main.cpp @@ -82,6 +82,26 @@ int main(int argc, char **argv) multiDataButton->setText(QStringLiteral("Insert many rows of data")); multiDataButton->setEnabled(false); + QPushButton *changeSingleDataButton = new QPushButton(widget); + changeSingleDataButton->setText(QStringLiteral("Change selected bar value")); + changeSingleDataButton->setEnabled(false); + + QPushButton *changeRowButton = new QPushButton(widget); + changeRowButton->setText(QStringLiteral("Change selected row values")); + changeRowButton->setEnabled(false); + + QPushButton *changeRowsButton = new QPushButton(widget); + changeRowsButton->setText(QStringLiteral("Change three rows from selected")); + changeRowsButton->setEnabled(false); + + QPushButton *removeRowButton = new QPushButton(widget); + removeRowButton->setText(QStringLiteral("Remove selected row")); + removeRowButton->setEnabled(false); + + QPushButton *removeRowsButton = new QPushButton(widget); + removeRowsButton->setText(QStringLiteral("remove three rows from selected")); + removeRowsButton->setEnabled(false); + QPushButton *themeButton = new QPushButton(widget); themeButton->setText(QStringLiteral("Change theme")); @@ -190,6 +210,11 @@ int main(int argc, char **argv) vLayout->addWidget(sampleSliderZ, 1, Qt::AlignTop); vLayout->addWidget(dataButton, 0, Qt::AlignTop); vLayout->addWidget(multiDataButton, 0, Qt::AlignTop); + vLayout->addWidget(changeSingleDataButton, 0, Qt::AlignTop); + vLayout->addWidget(changeRowButton, 0, Qt::AlignTop); + vLayout->addWidget(changeRowsButton, 0, Qt::AlignTop); + vLayout->addWidget(removeRowButton, 0, Qt::AlignTop); + vLayout->addWidget(removeRowsButton, 0, Qt::AlignTop); vLayout->addWidget(themeButton, 0, Qt::AlignTop); vLayout->addWidget(labelButton, 0, Qt::AlignTop); vLayout->addWidget(styleButton, 0, Qt::AlignTop); @@ -243,6 +268,11 @@ int main(int argc, char **argv) &ChartModifier::changeTransparency); QObject::connect(dataButton, &QPushButton::clicked, modifier, &ChartModifier::addRow); QObject::connect(multiDataButton, &QPushButton::clicked, modifier, &ChartModifier::addRows); + QObject::connect(changeSingleDataButton, &QPushButton::clicked, modifier, &ChartModifier::changeItem); + QObject::connect(changeRowButton, &QPushButton::clicked, modifier, &ChartModifier::changeRow); + QObject::connect(changeRowsButton, &QPushButton::clicked, modifier, &ChartModifier::changeRows); + QObject::connect(removeRowButton, &QPushButton::clicked, modifier, &ChartModifier::removeRow); + QObject::connect(removeRowsButton, &QPushButton::clicked, modifier, &ChartModifier::removeRows); QObject::connect(selectionButton, &QPushButton::clicked, modifier, &ChartModifier::changeSelectionMode); @@ -267,6 +297,16 @@ int main(int argc, char **argv) &QPushButton::setEnabled); QObject::connect(staticCheckBox, &QCheckBox::stateChanged, multiDataButton, &QPushButton::setEnabled); + QObject::connect(staticCheckBox, &QCheckBox::stateChanged, changeSingleDataButton, + &QPushButton::setEnabled); + QObject::connect(staticCheckBox, &QCheckBox::stateChanged, changeRowButton, + &QPushButton::setEnabled); + QObject::connect(staticCheckBox, &QCheckBox::stateChanged, changeRowsButton, + &QPushButton::setEnabled); + QObject::connect(staticCheckBox, &QCheckBox::stateChanged, removeRowButton, + &QPushButton::setEnabled); + QObject::connect(staticCheckBox, &QCheckBox::stateChanged, removeRowsButton, + &QPushButton::setEnabled); QObject::connect(staticCheckBox, &QCheckBox::stateChanged, sampleSliderX, &QSlider::setEnabled); QObject::connect(staticCheckBox, &QCheckBox::stateChanged, sampleSliderZ, diff --git a/src/datavis3d/data/qbardataproxy.cpp b/src/datavis3d/data/qbardataproxy.cpp index f27e3407..651551cc 100644 --- a/src/datavis3d/data/qbardataproxy.cpp +++ b/src/datavis3d/data/qbardataproxy.cpp @@ -71,6 +71,19 @@ void QBarDataProxy::setRow(int rowIndex, QBarDataRow *row) emit rowsChanged(rowIndex, 1); } +void QBarDataProxy::setRows(int rowIndex, QBarDataArray *rows) +{ + int count = rows->size(); + dptr()->setRows(rowIndex, rows); + emit rowsChanged(rowIndex, count); +} + +void QBarDataProxy::setItem(int rowIndex, int columnIndex, QBarDataItem *item) +{ + dptr()->setItem(rowIndex, columnIndex, item); + emit itemChanged(rowIndex, columnIndex); +} + int QBarDataProxy::addRow(QBarDataRow *row) { int addIndex = dptr()->addRow(row); @@ -99,6 +112,14 @@ void QBarDataProxy::insertRows(int rowIndex, QBarDataArray *rows) emit rowsInserted(rowIndex, insertCount); } +void QBarDataProxy::removeRows(int rowIndex, int removeCount) +{ + if (rowIndex < rowCount()) { + dptr()->removeRows(rowIndex, removeCount); + emit rowsRemoved(rowIndex, removeCount); + } +} + // Mutexing data accessors should be done by user, if needed int QBarDataProxy::rowCount() { @@ -112,12 +133,18 @@ const QBarDataArray *QBarDataProxy::array() const const QBarDataRow *QBarDataProxy::rowAt(int rowIndex) const { - return dptrc()->m_dataArray[rowIndex]; + const QBarDataArray &dataArray = dptrc()->m_dataArray; + Q_ASSERT(rowIndex >= 0 && rowIndex < dataArray.size()); + return dataArray[rowIndex]; } const QBarDataItem *QBarDataProxy::itemAt(int rowIndex, int columnIndex) const { - return &dptrc()->m_dataArray[rowIndex]->at(columnIndex); + const QBarDataArray &dataArray = dptrc()->m_dataArray; + Q_ASSERT(rowIndex >= 0 && rowIndex < dataArray.size()); + const QBarDataRow &dataRow = *dataArray[rowIndex]; + Q_ASSERT(columnIndex >= 0 && columnIndex < dataRow.size()); + return &dataRow.at(columnIndex); } QBarDataProxyPrivate *QBarDataProxy::dptr() @@ -162,10 +189,33 @@ bool QBarDataProxyPrivate::resetArray(QBarDataArray *newArray) void QBarDataProxyPrivate::setRow(int rowIndex, QBarDataRow *row) { QMutexLocker locker(&m_mutex); + Q_ASSERT(rowIndex >= 0 && rowIndex < m_dataArray.size()); clearRow(rowIndex); m_dataArray[rowIndex] = row; } +void QBarDataProxyPrivate::setRows(int rowIndex, QBarDataArray *rows) +{ + QMutexLocker locker(&m_mutex); + Q_ASSERT(rowIndex >= 0 && (rowIndex + rows->size()) <= m_dataArray.size()); + for (int i = 0; i < rows->size(); i++) { + clearRow(rowIndex); + m_dataArray[rowIndex] = rows->at(i); + rowIndex++; + } + delete rows; +} + +void QBarDataProxyPrivate::setItem(int rowIndex, int columnIndex, QBarDataItem *item) +{ + QMutexLocker locker(&m_mutex); + Q_ASSERT(rowIndex >= 0 && rowIndex < m_dataArray.size()); + QBarDataRow &row = *m_dataArray[rowIndex]; + Q_ASSERT(columnIndex < row.size()); + row[columnIndex] = *item; + delete item; +} + int QBarDataProxyPrivate::addRow(QBarDataRow *row) { QMutexLocker locker(&m_mutex); @@ -187,17 +237,31 @@ int QBarDataProxyPrivate::addRows(QBarDataArray *rows) void QBarDataProxyPrivate::insertRow(int rowIndex, QBarDataRow *row) { QMutexLocker locker(&m_mutex); + Q_ASSERT(rowIndex >= 0 && rowIndex <= m_dataArray.size()); m_dataArray.insert(rowIndex, row); } void QBarDataProxyPrivate::insertRows(int rowIndex, QBarDataArray *rows) { QMutexLocker locker(&m_mutex); + Q_ASSERT(rowIndex >= 0 && rowIndex <= m_dataArray.size()); for (int i = 0; i < rows->size(); i++) - m_dataArray.insert(rowIndex, rows->at(i)); + m_dataArray.insert(rowIndex++, rows->at(i)); delete rows; } +void QBarDataProxyPrivate::removeRows(int rowIndex, int removeCount) +{ + QMutexLocker locker(&m_mutex); + Q_ASSERT(rowIndex >= 0); + int maxRemoveCount = m_dataArray.size() - rowIndex; + removeCount = qMin(removeCount, maxRemoveCount); + for (int i = 0; i < removeCount; i++) { + clearRow(rowIndex); + m_dataArray.removeAt(rowIndex); + } +} + // Protected & private functions. Do not mutex as these are used from mutexed functions. void QBarDataProxyPrivate::clearRow(int rowIndex) diff --git a/src/datavis3d/data/qbardataproxy.h b/src/datavis3d/data/qbardataproxy.h index 02b8376d..c3217483 100644 --- a/src/datavis3d/data/qbardataproxy.h +++ b/src/datavis3d/data/qbardataproxy.h @@ -77,7 +77,7 @@ public: const QBarDataItem *itemAt(int rowIndex, int columnIndex) const; // Row and column in said row need to exist or this crashes // The data array is a list of list (rows) of QBarDataItem instances. - // Each row can contain different amount of items. + // Each row can contain different amount of items or even be null. // All array/item manipulation functions are internally protected by data mutex. @@ -88,33 +88,55 @@ public: // TODO Should data manipulation/access methods be protected rather than public to enforce subclassing use of proxy? // TODO Leaving them public gives user more options. - // QBarDataProxy takes ownership of all QBarDataArrays, QBarDataRows, and QBarDataItems passed to it. - // The pointers passed to it are not guaranteed to be valid after the calls. + // QBarDataProxy takes ownership of all QBarDataArrays, QBarDataRows, and QBarDataItems + // passed to it. The pointers passed to it are not guaranteed to be valid after the calls + // and should not be used to modify data further. // Clears the existing array and sets it data to new array. void resetArray(QBarDataArray *newArray); + // Change existing rows void setRow(int rowIndex, QBarDataRow *row); - // TODO? void setColumn(int columnIndex, QBarDataRow *column); - // TODO void setItem(int rowIndex, int columnIndex, QBarDataItem *item); + void setRows(int rowIndex, QBarDataArray *rows); + + // Setting a column is comparatively inefficient as it changes all rows. + // Can resize rows that are shorter than columnIndex. + // TODO void setColumn(int columnIndex, QBarDataRow *column); + // TODO void setColumns(int columnIndex, QBarDataArray *columns); + + // Change single item + void setItem(int rowIndex, int columnIndex, QBarDataItem *item); + // Change block of items + // TODO setItems(int rowIndex, int columnIndex, QBarDataArray *items); int addRow(QBarDataRow *row); // returns the index of added row int addRows(QBarDataArray *rows); // returns the index of first added row - // TODO? int addColumns(QBarDataArray *columns); // returns the index of first added column + // TODO int addColumn(QBarDataRow *column); // returns the index of the added column + // TODO int addColumns(QBarDataArray *columns); // returns the index of the first added column + // If rowIndex is equal to array size, rows are added to end of the array. void insertRow(int rowIndex, QBarDataRow *row); void insertRows(int rowIndex, QBarDataArray *rows); - // TODO? void insertColumns(int columnIndex, QBarDataArray *columns); + // TODO void insertColumn(int columnIndex, QBarDataRow *column); + // TODO void insertColumns(int columnIndex, QBarDataArray *columns); - // TODO void removeRows(int rowIndex, int removeCount); - // TODO? void removeColumns(int columnIndex, int removeCount); + // Attempting to remove rows past the end of the array does nothing. + void removeRows(int rowIndex, int removeCount); + // TODO void removeColumns(int columnIndex, int removeCount); signals: void arrayReset(); void rowsAdded(int startIndex, int count); void rowsChanged(int startIndex, int count); - void rowsRemoved(int startIndex, int count); // Index may be over current array size if removed from end + // Index is the current array size if rows were removed from the end of the array + void rowsRemoved(int startIndex, int count); void rowsInserted(int startIndex, int count); + // TODO void columnsChanged(int startIndex, int count); + // TODO void columnsAdded(int startIndex, int count); + // TODO void columnsRemoved(int startIndex, int count); + // TODO void columnsInserted(int startIndex, int count); + void itemChanged(int rowIndex, int columnIndex); + // TODO void itemsChanged(int rowIndex, int columnIndex, int rowCount, int columnCount); protected: QBarDataProxyPrivate *dptr(); diff --git a/src/datavis3d/data/qbardataproxy_p.h b/src/datavis3d/data/qbardataproxy_p.h index c9dec1e4..2325a1c1 100644 --- a/src/datavis3d/data/qbardataproxy_p.h +++ b/src/datavis3d/data/qbardataproxy_p.h @@ -67,10 +67,13 @@ public: bool resetArray(QBarDataArray *newArray); void setRow(int rowIndex, QBarDataRow *row); + void setRows(int rowIndex, QBarDataArray *rows); + void setItem(int rowIndex, int columnIndex, QBarDataItem *item); int addRow(QBarDataRow *row); int addRows(QBarDataArray *rows); void insertRow(int rowIndex, QBarDataRow *row); void insertRows(int rowIndex, QBarDataArray *rows); + void removeRows(int rowIndex, int removeCount); QPair limitValues(int startRow, int startColumn, int rowCount, int columnCount); diff --git a/src/datavis3d/engine/bars3dcontroller.cpp b/src/datavis3d/engine/bars3dcontroller.cpp index 1c72b575..6eee2fcc 100644 --- a/src/datavis3d/engine/bars3dcontroller.cpp +++ b/src/datavis3d/engine/bars3dcontroller.cpp @@ -269,6 +269,7 @@ void Bars3dController::setDataProxy(QBarDataProxy *proxy) QObject::connect(m_data, &QBarDataProxy::rowsChanged, this, &Bars3dController::handleRowsChanged); QObject::connect(m_data, &QBarDataProxy::rowsRemoved, this, &Bars3dController::handleRowsRemoved); QObject::connect(m_data, &QBarDataProxy::rowsInserted, this, &Bars3dController::handleRowsInserted); + QObject::connect(m_data, &QBarDataProxy::itemChanged, this, &Bars3dController::handleItemChanged); adjustValueAxisRange(); m_valuesDirty = true; @@ -330,6 +331,17 @@ void Bars3dController::handleRowsInserted(int startIndex, int count) m_valuesDirty = true; } +void Bars3dController::handleItemChanged(int rowIndex, int columnIndex) +{ + Q_UNUSED(rowIndex) + Q_UNUSED(columnIndex) + // TODO check if affects data window + // TODO should update slice instead of deactivating? + setSlicingActive(false); + adjustValueAxisRange(); + m_valuesDirty = true; +} + void Bars3dController::handleAxisAutoAdjustRangeChanged(bool autoAdjust) { Q_UNUSED(autoAdjust) diff --git a/src/datavis3d/engine/bars3dcontroller_p.h b/src/datavis3d/engine/bars3dcontroller_p.h index eeae402b..3fbf7383 100644 --- a/src/datavis3d/engine/bars3dcontroller_p.h +++ b/src/datavis3d/engine/bars3dcontroller_p.h @@ -180,6 +180,7 @@ public slots: void handleRowsChanged(int startIndex, int count); void handleRowsRemoved(int startIndex, int count); void handleRowsInserted(int startIndex, int count); + void handleItemChanged(int rowIndex, int columnIndex); virtual void handleAxisAutoAdjustRangeChanged(bool autoAdjust); diff --git a/src/datavis3d/engine/bars3drenderer.cpp b/src/datavis3d/engine/bars3drenderer.cpp index 662e7c17..9340d556 100644 --- a/src/datavis3d/engine/bars3drenderer.cpp +++ b/src/datavis3d/engine/bars3drenderer.cpp @@ -617,7 +617,7 @@ void Bars3dRenderer::drawScene(CameraHelper *camera, // Set the depth projection matrix #ifndef USE_WIDER_SHADOWS // Use this for perspective shadows - depthProjectionMatrix.perspective(15.0f, (GLfloat)m_mainViewPort.width() + depthProjectionMatrix.perspective(20.0f, (GLfloat)m_mainViewPort.width() / (GLfloat)m_mainViewPort.height(), 3.0f, 100.0f); #else // Use these for orthographic shadows diff --git a/src/datavis3d/engine/q3dbars.cpp b/src/datavis3d/engine/q3dbars.cpp index 33df8d2a..f7688530 100644 --- a/src/datavis3d/engine/q3dbars.cpp +++ b/src/datavis3d/engine/q3dbars.cpp @@ -250,6 +250,11 @@ void Q3DBars::setupSampleSpace(int samplesRow, int samplesColumn) d_ptr->m_shared->setupSampleSpace(samplesRow, samplesColumn); } +QSize Q3DBars::sampleSpace() +{ + return QSize(d_ptr->m_shared->rowCount(), d_ptr->m_shared->columnCount()); +} + /*! * \a preset Move camera to a predefined position from \c CameraPreset. * diff --git a/src/datavis3d/engine/q3dbars.h b/src/datavis3d/engine/q3dbars.h index a5284960..aea82b9e 100644 --- a/src/datavis3d/engine/q3dbars.h +++ b/src/datavis3d/engine/q3dbars.h @@ -85,6 +85,7 @@ public: // how many samples per row and column, and names for axes // TODO: This defines the data window, needs additional parameters startRow, startColumn void setupSampleSpace(int samplesRow, int samplesColumn); + QSize sampleSpace(); // TODO: Return QRect once data window properly implemented? // Select preset camera placement void setCameraPreset(CameraPreset preset); -- cgit v1.2.3