diff --git a/example/scatter/main.cpp b/example/scatter/main.cpp index e1ed334..ac6a1d4 100644 --- a/example/scatter/main.cpp +++ b/example/scatter/main.cpp @@ -14,20 +14,38 @@ int main(int argc, char *argv[]) // Create chart widget QChartView *chartWidget = new QChartView(); - // Create scatter series with simple test data + // Add scatter series with simple test data QScatterSeries *scatter = new QScatterSeries(); - *scatter << QPointF(0.5, 2.0) - << QPointF(1.0, 2.5) - << QPointF(1.5, 2.0) - << QPointF(2.0, 2.5); + *scatter << QPointF(0.5, 5.0) + << QPointF(1.0, 4.5) + << QPointF(1.0, 5.5) + << QPointF(1.5, 5.0) + << QPointF(2.0, 4.5) + << QPointF(2.0, 5.5) + << QPointF(2.5, 5.0); chartWidget->addSeries(scatter); - // Add another scatter series with more complex data with random component + // Add another scatter series + // - more data with random component QScatterSeries *scatter2 = new QScatterSeries(); - for (qreal i(0.0); i < 20; i += 0.5) + for (qreal i(0.0); i < 20; i += 0.05) { (*scatter2) << QPointF(i + (qreal)(rand() % 100) / 100.0, - i + (qreal)(rand() % 100) / 100.0); + i + (qreal)(rand() % 100) / 100.0); + } chartWidget->addSeries(scatter2); + // Custom pen and brush (not those defined by the chart theme) + // - uses opaque color + QColor color("#2685BF"); + color.setAlpha(80); + QBrush brush(Qt::SolidPattern); + brush.setColor(color); + scatter2->setMarkerBrush(brush); + QPen pen; + pen.setColor(color); + pen.setWidth(2); + scatter2->setMarkerPen(pen); + // use a rectangle as the marker shape + scatter2->setMarkerShape(QScatterSeries::MarkerShapeRectangle); // Use the chart widget as the central widget QMainWindow w; diff --git a/src/chartpresenter.cpp b/src/chartpresenter.cpp index ffa95ff..07463b1 100644 --- a/src/chartpresenter.cpp +++ b/src/chartpresenter.cpp @@ -127,9 +127,6 @@ void ChartPresenter::handleSeriesAdded(QChartSeries* series) QObject::connect(m_dataset, SIGNAL(domainChanged(const Domain&)), scatterPresenter, SLOT(handleDomainChanged(const Domain&))); m_chartTheme->decorate(scatterPresenter, scatterSeries, m_chartItems.count()); -// scatterSeries->d->m_theme = m_chartTheme->themeForSeries(); -// scatterSeries->d->setParentItem(this); -// scatterSeries->d->m_boundingRect = m_rect.adjusted(margin(),margin(), -margin(), -margin()); m_chartItems.insert(scatterSeries, scatterPresenter); break; } diff --git a/src/charttheme.cpp b/src/charttheme.cpp index 08d3e2a..0a19336 100644 --- a/src/charttheme.cpp +++ b/src/charttheme.cpp @@ -104,6 +104,14 @@ void ChartTheme::decorate(ChartItem* item, QChartSeries* series,int count) decorate(i,s,count); break; } + case QChartSeries::SeriesTypeScatter: { + QScatterSeries* s = qobject_cast(series); + Q_ASSERT(s); + ScatterPresenter* i = static_cast(item); + Q_ASSERT(i); + decorate(i, s, count); + break; + } case QChartSeries::SeriesTypePie: { QPieSeries* s = static_cast(series); PiePresenter* i = static_cast(item); @@ -179,16 +187,16 @@ void ChartTheme::decorate(ScatterPresenter* presenter, QScatterSeries* series, i Q_ASSERT(presenter); Q_ASSERT(series); - presenter->m_markerPen.setColor(m_seriesColor.at(count % m_seriesColor.size())); + QColor color = m_seriesColor.at(count % m_seriesColor.size()); + // TODO: define alpha in the theme? or in the series? + color.setAlpha(120); + + QBrush brush(color, Qt::SolidPattern); + presenter->m_markerBrush = brush; -// QPen pen; -// if(pen != series->pen()){ -// item->setPen(series->pen()); -// return; -// } -// pen.setColor(m_seriesColor.at(count%m_seriesColor.size())); -// pen.setWidthF(2); -// item->setPen(pen); + QPen pen(brush, 1); + pen.setColor(color); + presenter->m_markerPen = pen; } void ChartTheme::decorate(PiePresenter* item, QPieSeries* series, int /*count*/) diff --git a/src/scatterseries/qscatterseries.cpp b/src/scatterseries/qscatterseries.cpp index 987364a..d9811d2 100644 --- a/src/scatterseries/qscatterseries.cpp +++ b/src/scatterseries/qscatterseries.cpp @@ -5,8 +5,14 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE QScatterSeriesPrivate::QScatterSeriesPrivate() : - m_data(QList()) + m_data(QList()), + m_markerPen(QPen()), + m_markerBrush(QBrush()), + m_markerShape(QScatterSeries::MarkerShapeDefault) { + // Initialize pen color to invalid to use a theme color by default + m_markerPen.setColor(QColor::Invalid); + m_markerBrush.setColor(QColor::Invalid); } QScatterSeries::QScatterSeries(QObject *parent) : @@ -54,6 +60,26 @@ QPen QScatterSeries::markerPen() return d->m_markerPen; } +void QScatterSeries::setMarkerBrush(QBrush brush) +{ + d->m_markerBrush = brush; +} + +QBrush QScatterSeries::markerBrush() +{ + return d->m_markerBrush; +} + +void QScatterSeries::setMarkerShape(MarkerShape shape) +{ + d->m_markerShape = shape; +} + +QScatterSeries::MarkerShape QScatterSeries::markerShape() +{ + return (QScatterSeries::MarkerShape) d->m_markerShape; +} + #include "moc_qscatterseries.cpp" QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/scatterseries/qscatterseries.h b/src/scatterseries/qscatterseries.h index acbb619..ef65037 100644 --- a/src/scatterseries/qscatterseries.h +++ b/src/scatterseries/qscatterseries.h @@ -11,8 +11,21 @@ class QScatterSeriesPrivate; class QTCOMMERCIALCHART_EXPORT QScatterSeries : public QChartSeries { Q_OBJECT + +public: + enum MarkerShape { + // TODO: to be defined by the graphics design + // TODO: marker shapes: "x", star, rectangle, tilted rect, triangle, circle, dot + MarkerShapeDefault = 0, + MarkerShapePoint, + MarkerShapeX, + MarkerShapeRectangle, + MarkerShapeTiltedRectangle, + MarkerShapeTriangle, + MarkerShapeCircle + }; + public: - //QScatterSeries(QSeriesData *data, QObject *chart); QScatterSeries(QObject *parent = 0); ~QScatterSeries(); @@ -25,17 +38,20 @@ public: QScatterSeries& operator << (const QPointF &value); void setData(QList data); QList data(); - - //TODO? void insertData(int index, QPointF data); + //TODO: insertData? void setMarkerPen(QPen pen); QPen markerPen(); - // TODO: marker shapes: "x", star, rectangle, tilted rect, triangle, circle, dot - //void setMarkerShape(MarkerShape shape); + void setMarkerBrush(QBrush brush); + QBrush markerBrush(); + void setMarkerShape(MarkerShape shape); + MarkerShape markerShape(); + // TODO: marker size? Q_SIGNALS: - // TODO: move to PIMPL? + // TODO: move to PIMPL for simplicity or does the user ever need these signals? // TODO: more finegrained signaling for performance reasons + // (check QPieSeries implementation with change sets) void changed(); //public Q_SLOTS: diff --git a/src/scatterseries/scatterpresenter.cpp b/src/scatterseries/scatterpresenter.cpp index b10da79..0e25348 100644 --- a/src/scatterseries/scatterpresenter.cpp +++ b/src/scatterseries/scatterpresenter.cpp @@ -43,31 +43,48 @@ void ScatterPresenter::handleModelChanged() void ScatterPresenter::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/) { - // TODO: The opacity should be user definable? - //brush.setColor(QColor(255, 82, 0, 100)); - //if (m_series->markerPen().isValid()) { - if (false) { - QPen pen = painter->pen(); - QBrush brush = pen.brush(); - brush.setColor(m_series->markerPen().color()); - pen.setBrush(brush); - pen.setWidth(4); - painter->setPen(pen); - } - else { - // TODO: fix this - QPen pen = painter->pen(); - QBrush brush = pen.brush(); - brush.setColor(m_markerPen.color()); - pen.setBrush(brush); - pen.setWidth(4); - painter->setPen(pen); + // TODO: Optimization: avoid setting on every paint method call? + // The custom settings in series override those defined by the theme + if (m_series->markerPen().color().isValid()) { + painter->setPen(m_series->markerPen()); + painter->setBrush(m_series->markerBrush()); + } else { + painter->setPen(m_markerPen); + painter->setBrush(m_markerBrush); } + int shape = m_series->markerShape(); + for (int i(0); i < m_scenex.count() && i < m_sceney.count(); i++) { if (scene()->width() > m_scenex.at(i) && scene()->height() > m_sceney.at(i)) - //painter->drawArc(m_scenex.at(i), m_sceney.at(i), 2, 2, 0, 5760); - painter->drawPoint(m_scenex.at(i), m_sceney.at(i)); + // Paint a shape + switch (shape) { + case QScatterSeries::MarkerShapeDefault: + // Fallthrough, defaults to circle + case QScatterSeries::MarkerShapeCircle: + painter->drawChord(m_scenex.at(i), m_sceney.at(i), 9, 9, 0, 5760); + break; + case QScatterSeries::MarkerShapePoint: + painter->drawPoint(m_scenex.at(i), m_sceney.at(i)); + break; + case QScatterSeries::MarkerShapeRectangle: + painter->drawRect(m_scenex.at(i), m_sceney.at(i), 9, 9); + break; + case QScatterSeries::MarkerShapeTiltedRectangle: + // TODO: + static const QPointF points[4] = { + QPointF(-1.0 + m_scenex.at(i), 0.0 + m_sceney.at(i)), + QPointF(0.0 + m_scenex.at(i), 1.0 + m_sceney.at(i)), + QPointF(1.0 + m_scenex.at(i), 0.0 + m_sceney.at(i)), + QPointF(0.0 + m_scenex.at(i), -1.0 + m_sceney.at(i)) + }; + painter->drawPolygon(points, 4); + break; + default: + // TODO: implement the rest of the shapes + Q_ASSERT(false); + break; + } } } diff --git a/src/scatterseries/scatterpresenter_p.h b/src/scatterseries/scatterpresenter_p.h index b6d75be..a5f5a2a 100644 --- a/src/scatterseries/scatterpresenter_p.h +++ b/src/scatterseries/scatterpresenter_p.h @@ -40,6 +40,7 @@ public: QList m_sceney; Domain m_visibleChartArea; QPen m_markerPen; + QBrush m_markerBrush; }; QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/scatterseries/scatterseries_p.h b/src/scatterseries/scatterseries_p.h index cbe256f..8ca522e 100644 --- a/src/scatterseries/scatterseries_p.h +++ b/src/scatterseries/scatterseries_p.h @@ -18,6 +18,8 @@ public: public: QList m_data; QPen m_markerPen; + QBrush m_markerBrush; + int m_markerShape; }; QTCOMMERCIALCHART_END_NAMESPACE