scatterchartitem.cpp
207 lines
| 6.2 KiB
| text/x-c
|
CppLexer
|
r794 | /**************************************************************************** | ||
|
r1218 | ** | ||
|
r2432 | ** Copyright (C) 2013 Digia Plc | ||
|
r1218 | ** All rights reserved. | ||
** For any questions to Digia, please use contact form at http://qt.digia.com | ||||
** | ||||
** This file is part of the Qt Commercial Charts Add-on. | ||||
** | ||||
** $QT_BEGIN_LICENSE$ | ||||
** Licensees holding valid Qt Commercial licenses may use this file in | ||||
** accordance with the Qt Commercial License Agreement provided with the | ||||
** Software or, alternatively, in accordance with the terms contained in | ||||
** a written agreement between you and Digia. | ||||
** | ||||
** If you have questions regarding the use of this file, please use | ||||
** contact form at http://qt.digia.com | ||||
** $QT_END_LICENSE$ | ||||
** | ||||
****************************************************************************/ | ||||
|
r794 | |||
|
r470 | #include "scatterchartitem_p.h" | ||
#include "qscatterseries.h" | ||||
|
r938 | #include "qscatterseries_p.h" | ||
|
r470 | #include "chartpresenter_p.h" | ||
|
r2275 | #include "abstractdomain_p.h" | ||
|
r2483 | #include "qchart.h" | ||
|
r470 | #include <QPainter> | ||
#include <QGraphicsScene> | ||||
|
r996 | #include <QDebug> | ||
|
r1218 | #include <QGraphicsSceneMouseEvent> | ||
|
r470 | |||
QTCOMMERCIALCHART_BEGIN_NAMESPACE | ||||
|
r2483 | ScatterChartItem::ScatterChartItem(QScatterSeries *series, QGraphicsItem *item) | ||
|
r2273 | : XYChart(series,item), | ||
|
r2097 | m_series(series), | ||
m_items(this), | ||||
m_visible(true), | ||||
m_shape(QScatterSeries::MarkerShapeRectangle), | ||||
m_size(15) | ||||
|
r470 | { | ||
|
r2097 | QObject::connect(m_series->d_func(), SIGNAL(updated()), this, SLOT(handleUpdated())); | ||
|
r1349 | QObject::connect(m_series, SIGNAL(visibleChanged()), this, SLOT(handleUpdated())); | ||
|
r2067 | QObject::connect(m_series, SIGNAL(opacityChanged()), this, SLOT(handleUpdated())); | ||
|
r470 | |||
setZValue(ChartPresenter::ScatterSeriesZValue); | ||||
setFlags(QGraphicsItem::ItemClipsChildrenToShape); | ||||
handleUpdated(); | ||||
|
r541 | m_items.setHandlesChildEvents(false); | ||
|
r470 | } | ||
QRectF ScatterChartItem::boundingRect() const | ||||
{ | ||||
return m_rect; | ||||
} | ||||
void ScatterChartItem::createPoints(int count) | ||||
{ | ||||
for (int i = 0; i < count; ++i) { | ||||
|
r689 | QGraphicsItem *item = 0; | ||
|
r470 | |||
switch (m_shape) { | ||||
|
r2097 | case QScatterSeries::MarkerShapeCircle: { | ||
item = new CircleMarker(0, 0, m_size, m_size, this); | ||||
|
r2104 | const QRectF &rect = item->boundingRect(); | ||
|
r2097 | item->setPos(-rect.width() / 2, -rect.height() / 2); | ||
break; | ||||
|
r2131 | } | ||
|
r2104 | case QScatterSeries::MarkerShapeRectangle: | ||
|
r2097 | item = new RectangleMarker(0, 0, m_size, m_size, this); | ||
item->setPos(-m_size / 2, -m_size / 2); | ||||
break; | ||||
default: | ||||
qWarning() << "Unsupported marker type"; | ||||
|
r1218 | break; | ||
|
r470 | } | ||
m_items.addToGroup(item); | ||||
} | ||||
} | ||||
void ScatterChartItem::deletePoints(int count) | ||||
{ | ||||
QList<QGraphicsItem *> items = m_items.childItems(); | ||||
for (int i = 0; i < count; ++i) { | ||||
|
r2104 | QGraphicsItem *item = items.takeLast(); | ||
|
r1763 | m_markerMap.remove(item); | ||
delete(item); | ||||
|
r470 | } | ||
} | ||||
|
r1763 | void ScatterChartItem::markerSelected(QGraphicsItem *marker) | ||
|
r470 | { | ||
|
r2483 | emit XYChart::clicked(m_markerMap[marker]); | ||
|
r470 | } | ||
|
r2261 | void ScatterChartItem::markerHovered(QGraphicsItem *marker, bool state) | ||
{ | ||||
|
r2483 | emit XYChart::hovered(m_markerMap[marker], state); | ||
|
r2261 | } | ||
|
r1217 | void ScatterChartItem::updateGeometry() | ||
|
r470 | { | ||
|
r1217 | |||
const QVector<QPointF>& points = geometryPoints(); | ||||
|
r2097 | if (points.size() == 0) { | ||
|
r1085 | deletePoints(m_items.childItems().count()); | ||
|
r545 | return; | ||
} | ||||
|
r470 | |||
|
r869 | int diff = m_items.childItems().size() - points.size(); | ||
|
r470 | |||
|
r2097 | if (diff > 0) | ||
|
r470 | deletePoints(diff); | ||
|
r2097 | else if (diff < 0) | ||
|
r470 | createPoints(-diff); | ||
|
r2097 | if (diff != 0) | ||
handleUpdated(); | ||||
|
r470 | |||
|
r2104 | QList<QGraphicsItem *> items = m_items.childItems(); | ||
|
r470 | |||
|
r2273 | QRectF clipRect(QPointF(0,0),domain()->size()); | ||
|
r2483 | QVector<bool> offGridStatus = offGridStatusVector(); | ||
|
r2489 | const int seriesLastIndex = m_series->count() - 1; | ||
|
r2483 | |||
|
r847 | for (int i = 0; i < points.size(); i++) { | ||
|
r2104 | QGraphicsItem *item = items.at(i); | ||
const QPointF &point = points.at(i); | ||||
const QRectF &rect = item->boundingRect(); | ||||
|
r2492 | // During remove animation series may have different number of points, | ||
|
r2489 | // so ensure we don't go over the index. Animation handling itself ensures that | ||
// if there is actually no points in the series, then it won't generate a fake point, | ||||
// so we can be assured there is always at least one point in m_series here. | ||||
// Note that marker map values can be technically incorrect during the animation, | ||||
// if it was caused by an insert, but this shouldn't be a problem as the points are | ||||
|
r2492 | // fake anyway. After remove animation stops, geometry is updated to correct one. | ||
|
r2491 | m_markerMap[item] = m_series->at(qMin(seriesLastIndex, i)); | ||
|
r2097 | item->setPos(point.x() - rect.width() / 2, point.y() - rect.height() / 2); | ||
|
r2483 | |||
if (!m_visible || offGridStatus.at(i)) | ||||
|
r470 | item->setVisible(false); | ||
|
r2097 | else | ||
|
r470 | item->setVisible(true); | ||
} | ||||
prepareGeometryChange(); | ||||
|
r2273 | m_rect = clipRect; | ||
|
r470 | } | ||
void ScatterChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) | ||||
{ | ||||
|
r611 | Q_UNUSED(painter) | ||
Q_UNUSED(option) | ||||
Q_UNUSED(widget) | ||||
|
r470 | } | ||
|
r2104 | void ScatterChartItem::setPen(const QPen &pen) | ||
|
r470 | { | ||
|
r2097 | foreach (QGraphicsItem *item , m_items.childItems()) | ||
|
r1763 | static_cast<QAbstractGraphicsShapeItem*>(item)->setPen(pen); | ||
|
r470 | } | ||
|
r2104 | void ScatterChartItem::setBrush(const QBrush &brush) | ||
|
r470 | { | ||
|
r2097 | foreach (QGraphicsItem *item , m_items.childItems()) | ||
|
r1763 | static_cast<QAbstractGraphicsShapeItem*>(item)->setBrush(brush); | ||
|
r470 | } | ||
void ScatterChartItem::handleUpdated() | ||||
{ | ||||
int count = m_items.childItems().count(); | ||||
|
r2097 | if (count == 0) | ||
return; | ||||
|
r470 | |||
|
r1346 | bool recreate = m_visible != m_series->isVisible() | ||
|
r2097 | || m_size != m_series->markerSize() | ||
|| m_shape != m_series->markerShape(); | ||||
|
r470 | |||
|
r1346 | m_visible = m_series->isVisible(); | ||
|
r1276 | m_size = m_series->markerSize(); | ||
m_shape = m_series->markerShape(); | ||||
|
r2067 | setOpacity(m_series->opacity()); | ||
|
r470 | |||
|
r2407 | if (recreate) { | ||
|
r2477 | // TODO: optimize handleUpdate to recreate points only in case shape changed | ||
|
r470 | deletePoints(count); | ||
createPoints(count); | ||||
|
r1276 | |||
// Updating geometry is now safe, because it won't call handleUpdated unless it creates/deletes points | ||||
updateGeometry(); | ||||
|
r470 | } | ||
setPen(m_series->pen()); | ||||
setBrush(m_series->brush()); | ||||
|
r1305 | update(); | ||
|
r470 | } | ||
#include "moc_scatterchartitem_p.cpp" | ||||
QTCOMMERCIALCHART_END_NAMESPACE | ||||