summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLukas Kosinski <lukasz@scythe-studio.com>2021-05-26 18:56:40 +0200
committerLukas Kosinski <lukasz@scythe-studio.com>2021-06-01 16:04:27 +0200
commit1a0063ed1523ca7511e1801957c377b5bf40af27 (patch)
tree618136c85ce11412d72746dd018f38c63f212724 /src
parente8d6da6363d894a5d1c6f8bf164818913a1041eb (diff)
QBarSet: Support for bars selection
This feature allows user to mark desired bars as selected. Selected bars can have other color than other bars. The changes were made in abstractbarchartitem and qbarset. The idea is to add more interactivity to bar charts. Task-number: QTBUG-89445 Change-Id: I7db178c5e85c1872be9f1d7117c1ecd9299edde7 Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/charts/barchart/abstractbarchartitem.cpp7
-rw-r--r--src/charts/barchart/qabstractbarseries.cpp10
-rw-r--r--src/charts/barchart/qbarset.cpp232
-rw-r--r--src/charts/barchart/qbarset.h17
-rw-r--r--src/charts/barchart/qbarset_p.h6
-rw-r--r--src/charts/xychart/qxyseries.cpp42
6 files changed, 302 insertions, 12 deletions
diff --git a/src/charts/barchart/abstractbarchartitem.cpp b/src/charts/barchart/abstractbarchartitem.cpp
index 707ec361..d85a3dfd 100644
--- a/src/charts/barchart/abstractbarchartitem.cpp
+++ b/src/charts/barchart/abstractbarchartitem.cpp
@@ -265,6 +265,7 @@ void AbstractBarChartItem::handleUpdatedBars()
for (int set = 0; set < setCount; set++) {
QBarSet *barSet = m_series->d_func()->barsetAt(set);
+
QBarSetPrivate *barSetP = barSet->d_ptr.data();
const bool setVisualsDirty = barSetP->visualsDirty();
const bool setLabelsDirty = barSetP->labelsDirty();
@@ -277,7 +278,11 @@ void AbstractBarChartItem::handleUpdatedBars()
Bar *bar = bars.at(i);
if (seriesVisualsDirty || setVisualsDirty || bar->visualsDirty()) {
bar->setPen(barSetP->m_pen);
- bar->setBrush(barSetP->m_brush);
+ if (barSet->isBarSelected(i) && barSetP->m_selectedColor.isValid())
+ bar->setBrush(barSetP->m_selectedColor);
+ else
+ bar->setBrush(barSetP->m_brush);
+
bar->setVisualsDirty(false);
bar->update();
}
diff --git a/src/charts/barchart/qabstractbarseries.cpp b/src/charts/barchart/qabstractbarseries.cpp
index 8a68c24a..bbf30329 100644
--- a/src/charts/barchart/qabstractbarseries.cpp
+++ b/src/charts/barchart/qabstractbarseries.cpp
@@ -971,6 +971,8 @@ bool QAbstractBarSeriesPrivate::append(QBarSet *set)
this, &QAbstractBarSeriesPrivate::handleSetValueAdd);
QObject::connect(set->d_ptr.data(), &QBarSetPrivate::valueRemoved,
this, &QAbstractBarSeriesPrivate::handleSetValueRemove);
+ connect(set, &QBarSet::selectedBarsChanged,
+ this, &QAbstractBarSeriesPrivate::updatedBars);
emit restructuredBars(); // this notifies barchartitem
return true;
@@ -990,6 +992,8 @@ bool QAbstractBarSeriesPrivate::remove(QBarSet *set)
this, &QAbstractBarSeriesPrivate::handleSetValueAdd);
QObject::disconnect(set->d_ptr.data(), &QBarSetPrivate::valueRemoved,
this, &QAbstractBarSeriesPrivate::handleSetValueRemove);
+ disconnect(set, &QBarSet::selectedBarsChanged,
+ this, &QAbstractBarSeriesPrivate::updatedBars);
emit restructuredBars(); // this notifies barchartitem
return true;
@@ -1014,6 +1018,8 @@ bool QAbstractBarSeriesPrivate::append(const QList<QBarSet *> &sets)
this, &QAbstractBarSeriesPrivate::handleSetValueAdd);
QObject::connect(set->d_ptr.data(), &QBarSetPrivate::valueRemoved,
this, &QAbstractBarSeriesPrivate::handleSetValueRemove);
+ connect(set, &QBarSet::selectedBarsChanged,
+ this, &QAbstractBarSeriesPrivate::updatedBars);
}
emit restructuredBars(); // this notifies barchartitem
@@ -1042,6 +1048,8 @@ bool QAbstractBarSeriesPrivate::remove(const QList<QBarSet *> &sets)
this, &QAbstractBarSeriesPrivate::handleSetValueAdd);
QObject::disconnect(set->d_ptr.data(), &QBarSetPrivate::valueRemoved,
this, &QAbstractBarSeriesPrivate::handleSetValueRemove);
+ disconnect(set, &QBarSet::selectedBarsChanged,
+ this, &QAbstractBarSeriesPrivate::updatedBars);
}
emit restructuredBars(); // this notifies barchartitem
@@ -1063,6 +1071,8 @@ bool QAbstractBarSeriesPrivate::insert(int index, QBarSet *set)
this, &QAbstractBarSeriesPrivate::handleSetValueAdd);
QObject::connect(set->d_ptr.data(), &QBarSetPrivate::valueRemoved,
this, &QAbstractBarSeriesPrivate::handleSetValueRemove);
+ disconnect(set, &QBarSet::selectedBarsChanged,
+ this, &QAbstractBarSeriesPrivate::updatedBars);
emit restructuredBars(); // this notifies barchartitem
return true;
diff --git a/src/charts/barchart/qbarset.cpp b/src/charts/barchart/qbarset.cpp
index e7bb8b0d..faccf07f 100644
--- a/src/charts/barchart/qbarset.cpp
+++ b/src/charts/barchart/qbarset.cpp
@@ -407,7 +407,25 @@ QBarSet &QBarSet::operator << (const qreal &value)
void QBarSet::insert(const int index, const qreal value)
{
d_ptr->insert(index, value);
+
+ bool callSignal = false;
+ if (!d_ptr->m_selectedBars.isEmpty()) {
+ // if value was inserted we need to move already selected bars by 1
+ QSet<int> selectedAfterInsert;
+ for (const auto &value : qAsConst(d_ptr->m_selectedBars)) {
+ if (value >= index) {
+ selectedAfterInsert << value + 1;
+ callSignal = true;
+ } else {
+ selectedAfterInsert << value;
+ }
+ }
+ d_ptr->m_selectedBars = selectedAfterInsert;
+ }
+
emit valuesAdded(index, 1);
+ if (callSignal)
+ emit selectedBarsChanged(selectedBars());
}
/*!
@@ -659,6 +677,172 @@ void QBarSet::setLabelColor(QColor color)
}
}
+/*!
+ Returns the color of the selected bars.
+
+ This is the fill (brush) color of bars marked as selected. If not specified,
+ value of QBarSet::color is used as default.
+ \sa color
+ \since 6.2
+*/
+QColor QBarSet::selectedColor() const
+{
+ return d_ptr->m_selectedColor;
+}
+
+/*!
+ Sets the color of the selected bars.
+ \sa selectedColor
+ \since 6.2
+*/
+void QBarSet::setSelectedColor(const QColor &color)
+{
+ if (d_ptr->m_selectedColor != color) {
+ d_ptr->m_selectedColor = color;
+ d_ptr->setLabelsDirty(true);
+ emit d_ptr->updatedBars();
+ emit selectedColorChanged(color);
+ }
+}
+
+/*!
+ Returns \c true if the bar at the given \a index is among selected bars and \c false otherwise.
+ \note Selected bars are drawn using the selected color if it was specified using QBarSet::setSelectedColor.
+ \sa selectedBars(), setBarSelected(), setSelectedColor()
+ \since 6.2
+ */
+bool QBarSet::isBarSelected(int index) const
+{
+ return d_ptr->isBarSelected(index);
+}
+
+/*!
+ Marks the bar at \a index as selected.
+ \note Emits QBarSet::selectedBarsChanged.
+ \sa setBarSelected()
+ \since 6.2
+ */
+void QBarSet::selectBar(int index)
+{
+ setBarSelected(index, true);
+}
+
+/*!
+ Deselects the bar at \a index.
+ \note Emits QBarSet::selectedBarsChanged.
+ \sa setBarSelected()
+ \since 6.2
+ */
+void QBarSet::deselectBar(int index)
+{
+ setBarSelected(index, false);
+}
+
+/*!
+ Marks the bar at \a index as either selected or deselected as specified by \a selected.
+ \note Selected bars are drawn using the selected color if it was specified. Emits QBarSet::selectedBarsChanged.
+ \sa setSelectedColor()
+ \since 6.2
+ */
+void QBarSet::setBarSelected(int index, bool selected)
+{
+ bool callSignal = false;
+ d_ptr->setBarSelected(index, selected, callSignal);
+
+ if (callSignal)
+ emit selectedBarsChanged(selectedBars());
+}
+
+/*!
+ Marks all bars in the series as selected.
+ \note Emits QBarSet::selectedBarsChanged.
+ \sa setBarSelected()
+ \since 6.2
+ */
+void QBarSet::selectAllBars()
+{
+ bool callSignal = false;
+ for (int i = 0; i < d_ptr->m_values.count(); ++i)
+ d_ptr->setBarSelected(i, true, callSignal);
+
+ if (callSignal)
+ emit selectedBarsChanged(selectedBars());
+}
+
+/*!
+ Deselects all bars in the series.
+ \note Emits QBarSet::selectedBarsChanged.
+ \sa setBarSelected()
+ \since 6.2
+ */
+void QBarSet::deselectAllBars()
+{
+ bool callSignal = false;
+ for (int i = 0; i < d_ptr->m_values.count(); ++i)
+ d_ptr->setBarSelected(i, false, callSignal);
+
+ if (callSignal)
+ emit selectedBarsChanged(selectedBars());
+}
+
+/*!
+ Marks multiple bars passed in an \a indexes list as selected.
+ \note Emits QBarSet::selectedBarsChanged.
+ \sa setBarSelected()
+ \since 6.2
+ */
+void QBarSet::selectBars(const QList<int> &indexes)
+{
+ bool callSignal = false;
+ for (const int &index : indexes)
+ d_ptr->setBarSelected(index, true, callSignal);
+
+ if (callSignal)
+ emit selectedBarsChanged(selectedBars());
+}
+
+/*!
+ Marks multiple bars passed in an \a indexes list as deselected.
+ \note Emits QBarSet::selectedBarsChanged.
+ \sa setBarSelected()
+ \since 6.2
+ */
+void QBarSet::deselectBars(const QList<int> &indexes)
+{
+ bool callSignal = false;
+ for (const int &index : indexes)
+ d_ptr->setBarSelected(index, false, callSignal);
+
+ if (callSignal)
+ emit selectedBarsChanged(selectedBars());
+}
+
+/*!
+ Changes the selection state of bars at the given \a indexes to the opposite one.
+ \note Emits QBarSet::selectedBarsChanged.
+ \sa setBarSelected()
+ \since 6.2
+ */
+void QBarSet::toggleSelection(const QList<int> &indexes)
+{
+ bool callSignal = false;
+ for (const int &index : indexes)
+ d_ptr->setBarSelected(index, !isBarSelected(index), callSignal);
+
+ if (callSignal)
+ emit selectedBarsChanged(selectedBars());
+}
+
+/*!
+ Returns a list of bars marked as selected.
+ \sa setBarSelected()
+ \since 6.2
+ */
+QList<int> QBarSet::selectedBars() const
+{
+ return QList<int>(d_ptr->m_selectedBars.begin(), d_ptr->m_selectedBars.end());
+}
+
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
QBarSetPrivate::QBarSetPrivate(const QString label, QBarSet *parent) : QObject(parent),
@@ -732,7 +916,29 @@ int QBarSetPrivate::remove(const int index, const int count)
m_values.removeAt(index);
c++;
}
+
+ bool callSignal = false;
+ if (!m_selectedBars.empty()) {
+ QSet<int> selectedAfterRemoving;
+
+ for (const int &selectedBarIndex : qAsConst(m_selectedBars)) {
+ if (selectedBarIndex < index) {
+ selectedAfterRemoving << selectedBarIndex;
+ } else if (selectedBarIndex >= index + removeCount) {
+ selectedAfterRemoving << selectedBarIndex - removeCount;
+ callSignal = true;
+ } else {
+ callSignal = true;
+ }
+ }
+
+ m_selectedBars = selectedAfterRemoving;
+ }
+
emit valueRemoved(index, removeCount);
+ if (callSignal)
+ emit q_ptr->selectedBarsChanged(q_ptr->selectedBars());
+
return removeCount;
}
@@ -756,6 +962,32 @@ qreal QBarSetPrivate::value(const int index)
return m_values.at(index).y();
}
+void QBarSetPrivate::setBarSelected(int index, bool selected, bool &callSignal)
+{
+ if (index < 0 || index > m_values.count() - 1)
+ return;
+
+ if (selected) {
+ if (!isBarSelected(index)) {
+ m_selectedBars << index;
+ callSignal = true;
+ }
+ } else {
+ if (isBarSelected(index)) {
+ m_selectedBars.remove(index);
+ callSignal = true;
+ }
+ }
+
+ if (callSignal)
+ setVisualsDirty(true);
+}
+
+bool QBarSetPrivate::isBarSelected(int index) const
+{
+ return m_selectedBars.contains(index);
+}
+
QT_END_NAMESPACE
#include "moc_qbarset.cpp"
diff --git a/src/charts/barchart/qbarset.h b/src/charts/barchart/qbarset.h
index 30938b28..597d8e88 100644
--- a/src/charts/barchart/qbarset.h
+++ b/src/charts/barchart/qbarset.h
@@ -91,6 +91,20 @@ public:
QColor labelColor();
void setLabelColor(QColor color);
+ QColor selectedColor() const;
+ void setSelectedColor(const QColor &color);
+
+ bool isBarSelected(int index) const;
+ void selectBar(int index);
+ void deselectBar(int index);
+ void setBarSelected(int index, bool selected);
+ void selectAllBars();
+ void deselectAllBars();
+ void selectBars(const QList<int> &indexes);
+ void deselectBars(const QList<int> &indexes);
+ void toggleSelection(const QList<int> &indexes);
+ QList<int> selectedBars() const;
+
Q_SIGNALS:
void clicked(int index);
void hovered(bool status, int index);
@@ -105,11 +119,14 @@ Q_SIGNALS:
void colorChanged(QColor color);
void borderColorChanged(QColor color);
void labelColorChanged(QColor color);
+ Q_REVISION(6, 2) void selectedColorChanged(const QColor &color);
void valuesAdded(int index, int count);
void valuesRemoved(int index, int count);
void valueChanged(int index);
+ Q_REVISION(6, 2) void selectedBarsChanged(const QList<int> &indexes);
+
private:
QScopedPointer<QBarSetPrivate> d_ptr;
Q_DISABLE_COPY(QBarSet)
diff --git a/src/charts/barchart/qbarset_p.h b/src/charts/barchart/qbarset_p.h
index 5770af68..3669dc8f 100644
--- a/src/charts/barchart/qbarset_p.h
+++ b/src/charts/barchart/qbarset_p.h
@@ -45,6 +45,7 @@
#include <QtGui/QPen>
#include <QtGui/QBrush>
#include <QtGui/QFont>
+#include <QSet>
QT_BEGIN_NAMESPACE
@@ -74,6 +75,9 @@ public:
void setLabelsDirty(bool dirty) { m_labelsDirty = dirty; }
bool labelsDirty() const { return m_labelsDirty; }
+ void setBarSelected(int index, bool selected, bool &callSignal);
+ bool isBarSelected(int index) const;
+
Q_SIGNALS:
void updatedBars();
void valueChanged(int index);
@@ -84,10 +88,12 @@ public:
QBarSet * const q_ptr;
QString m_label;
QList<QPointF> m_values;
+ QSet<int> m_selectedBars;
QPen m_pen;
QBrush m_brush;
QBrush m_labelBrush;
QFont m_labelFont;
+ QColor m_selectedColor;
bool m_visualsDirty;
bool m_labelsDirty;
diff --git a/src/charts/xychart/qxyseries.cpp b/src/charts/xychart/qxyseries.cpp
index bc7d5b55..fb4e4138 100644
--- a/src/charts/xychart/qxyseries.cpp
+++ b/src/charts/xychart/qxyseries.cpp
@@ -1100,9 +1100,14 @@ void QXYSeries::remove(const QPointF &point)
void QXYSeries::remove(int index)
{
Q_D(QXYSeries);
- deselectPoint(index);
d->m_points.remove(index);
+
+ bool callSignal = false;
+ d->setPointSelected(index, false, callSignal);
+
emit pointRemoved(index);
+ if (callSignal)
+ emit selectedPointsChanged();
}
/*!
@@ -1116,15 +1121,29 @@ void QXYSeries::removePoints(int index, int count)
// remove(qreal, qreal) overload in some implicit casting cases.
Q_D(QXYSeries);
if (count > 0) {
+ d->m_points.remove(index, count);
+
+ bool callSignal = false;
if (!d->m_selectedPoints.empty()) {
- QList<int> indexes;
- for (int i = index; i < index + count; ++i)
- indexes << i;
- deselectPoints(indexes);
+ QSet<int> selectedAfterRemoving;
+
+ for (const int &selectedPointIndex : qAsConst(d->m_selectedPoints)) {
+ if (selectedPointIndex < index) {
+ selectedAfterRemoving << selectedPointIndex;
+ } else if (selectedPointIndex >= index + count) {
+ selectedAfterRemoving << selectedPointIndex - count;
+ callSignal = true;
+ } else {
+ callSignal = true;
+ }
+ }
+
+ d->m_selectedPoints = selectedAfterRemoving;
}
- d->m_points.remove(index, count);
emit pointsRemoved(index, count);
+ if (callSignal)
+ emit selectedPointsChanged();
}
}
@@ -1139,11 +1158,13 @@ void QXYSeries::insert(int index, const QPointF &point)
if (isValidValue(point)) {
index = qMax(0, qMin(index, d->m_points.size()));
+ d->m_points.insert(index, point);
+
+ bool callSignal = false;
if (!d->m_selectedPoints.isEmpty()) {
// if point was inserted we need to move already selected points by 1
QSet<int> selectedAfterInsert;
- bool callSignal = false;
- for (const auto &value : d->m_selectedPoints) {
+ for (const auto &value : qAsConst(d->m_selectedPoints)) {
if (value >= index) {
selectedAfterInsert << value + 1;
callSignal = true;
@@ -1152,12 +1173,11 @@ void QXYSeries::insert(int index, const QPointF &point)
}
}
d->m_selectedPoints = selectedAfterInsert;
- if (callSignal)
- emit selectedPointsChanged();
}
- d->m_points.insert(index, point);
emit pointAdded(index);
+ if (callSignal)
+ emit selectedPointsChanged();
}
}