scatterpresenter.cpp
150 lines
| 4.9 KiB
| text/x-c
|
CppLexer
|
r194 | #include "scatterpresenter_p.h" | ||
|
r158 | #include "qscatterseries.h" | ||
|
r375 | #include "chartpresenter_p.h" | ||
|
r158 | #include <QPen> | ||
#include <QPainter> | ||||
#include <QGraphicsScene> | ||||
|
r316 | #include <QGraphicsSceneMouseEvent> | ||
|
r346 | #include <QGraphicsDropShadowEffect> | ||
|
r158 | #include <QDebug> | ||
|
r278 | #include <QTime> | ||
|
r158 | |||
QTCOMMERCIALCHART_BEGIN_NAMESPACE | ||||
ScatterPresenter::ScatterPresenter(QScatterSeries *series, QGraphicsObject *parent) : | ||||
ChartItem(parent), | ||||
m_series(series), | ||||
m_boundingRect(), | ||||
m_visibleChartArea() | ||||
{ | ||||
if (parent) | ||||
m_boundingRect = parent->boundingRect(); | ||||
if (series) { | ||||
connect(series, SIGNAL(changed()), this, SLOT(handleModelChanged())); | ||||
} | ||||
|
r346 | |||
|
r375 | setZValue(ChartPresenter::ScatterSeriesZValue); | ||
// TODO: how to draw a drop shadow? | ||||
// QGraphicsDropShadowEffect *dropShadow = new QGraphicsDropShadowEffect(); | ||||
// dropShadow->setOffset(2.0); | ||||
// dropShadow->setBlurRadius(2.0); | ||||
// setGraphicsEffect(dropShadow); | ||||
|
r158 | } | ||
void ScatterPresenter::handleDomainChanged(const Domain& domain) | ||||
{ | ||||
m_visibleChartArea = domain; | ||||
changeGeometry(); | ||||
} | ||||
void ScatterPresenter::handleGeometryChanged(const QRectF& rect) | ||||
{ | ||||
|
r394 | m_boundingRect = rect.translated(-rect.topLeft()); | ||
|
r158 | changeGeometry(); | ||
|
r394 | setPos(rect.topLeft()); | ||
|
r158 | } | ||
void ScatterPresenter::handleModelChanged() | ||||
{ | ||||
// TODO: more fine grained modelChanged signaling | ||||
changeGeometry(); | ||||
} | ||||
void ScatterPresenter::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/) | ||||
{ | ||||
|
r278 | painter->save(); | ||
painter->setClipRect(m_boundingRect); | ||||
|
r375 | // TODO: how to draw a drop shadow? | ||
// Now using a custom implementation for drop shadow instead of QGraphicsDropShadowEffect. | ||||
// It seems QGraphicsDropShadowEffect is quite heavy, at least on windows without open gl. | ||||
QPen dropShadowPen(QColor(0, 0, 0, 70)); | ||||
dropShadowPen.setWidth(3); | ||||
painter->setPen(dropShadowPen); | ||||
painter->setBrush(dropShadowPen.color()); | ||||
// painter->setRenderHint(QPainter::Antialiasing); | ||||
painter->drawPath(m_path.translated(2, 2)); | ||||
|
r278 | // Paint the shape | ||
|
r316 | // The custom settings in series override those defined by the theme | ||
|
r278 | QPen pen = m_markerPen; | ||
|
r358 | if (m_series->pen().color().isValid()) | ||
pen = m_series->pen(); | ||||
|
r375 | painter->setPen(pen); | ||
|
r358 | if (m_series->brush().color().isValid()) | ||
painter->setBrush(m_series->brush()); | ||||
|
r261 | else | ||
|
r195 | painter->setBrush(m_markerBrush); | ||
|
r375 | |||
// If either pen or brush is opaque, we need to draw the polygons one-by-one | ||||
if (painter->pen().color().alpha() < 255 || painter->brush().color().alpha() < 255) { | ||||
foreach (QPolygonF pol, m_path.toSubpathPolygons()) | ||||
painter->drawPolygon(pol); | ||||
} else { | ||||
painter->drawPath(m_path); | ||||
} | ||||
|
r316 | |||
|
r278 | painter->restore(); | ||
|
r158 | } | ||
|
r300 | void ScatterPresenter::mousePressEvent(QGraphicsSceneMouseEvent *event) | ||
{ | ||||
|
r394 | // Empty implementation to grab mouse release events for this item | ||
Q_UNUSED(event) | ||||
} | ||||
|
r316 | |||
|
r394 | void ScatterPresenter::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) | ||
{ | ||||
QPointF clickedPoint( | ||||
m_visibleChartArea.m_minX + (event->lastPos().x() / m_boundingRect.width()) * m_visibleChartArea.spanX(), | ||||
m_visibleChartArea.m_maxY - (event->lastPos().y() / m_boundingRect.height()) * m_visibleChartArea.spanY()); | ||||
emit clicked(clickedPoint); | ||||
|
r300 | } | ||
|
r158 | void ScatterPresenter::changeGeometry() | ||
{ | ||||
if (m_boundingRect.isValid()) { | ||||
prepareGeometryChange(); | ||||
qreal scalex = m_boundingRect.width() / m_visibleChartArea.spanX(); | ||||
qreal scaley = m_boundingRect.height() / m_visibleChartArea.spanY(); | ||||
|
r358 | int shape = m_series->shape(); | ||
|
r316 | m_path = QPainterPath(); | ||
|
r375 | m_path.setFillRule(Qt::WindingFill); | ||
|
r397 | const qreal size = m_series->size(); | ||
|
r316 | |||
|
r158 | foreach (QPointF point, m_series->data()) { | ||
|
r316 | // Convert relative coordinates to absolute pixel coordinates that can be used for drawing | ||
|
r394 | qreal x = point.x() * scalex - m_visibleChartArea.m_minX * scalex - size / 2; | ||
qreal y = m_boundingRect.height() - point.y() * scaley + m_visibleChartArea.m_minY * scaley - size / 2; | ||||
|
r316 | |||
|
r394 | if (x < scene()->width() && y < scene()->height()) { | ||
|
r316 | switch (shape) { | ||
case QScatterSeries::MarkerShapeDefault: | ||||
// Fallthrough, defaults to circle | ||||
case QScatterSeries::MarkerShapeCircle: | ||||
|
r394 | m_path.addEllipse(x, y, size, size); | ||
|
r316 | break; | ||
case QScatterSeries::MarkerShapeRectangle: | ||||
|
r394 | m_path.addRect(x, y, size, size); | ||
|
r316 | break; | ||
case QScatterSeries::MarkerShapeTiltedRectangle: { | ||||
|
r358 | // TODO: tilt the rectangle | ||
|
r394 | m_path.addRect(x, y, size, size); | ||
|
r316 | break; | ||
} | ||||
default: | ||||
// TODO: implement the rest of the shapes | ||||
Q_ASSERT(false); | ||||
break; | ||||
} | ||||
} | ||||
|
r158 | } | ||
} | ||||
} | ||||
|
r194 | #include "moc_scatterpresenter_p.cpp" | ||
|
r158 | |||
QTCOMMERCIALCHART_END_NAMESPACE | ||||