##// END OF EJS Templates
Fix mouse event interception by scatter chart....
Miikka Heikkinen -
r2747:31ef05db7ba9
parent child
Show More
@@ -1,252 +1,251
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2014 Digia Plc
3 ** Copyright (C) 2014 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.io
5 ** For any questions to Digia, please use contact form at http://qt.io
6 **
6 **
7 ** This file is part of the Qt Charts module.
7 ** This file is part of the Qt Charts module.
8 **
8 **
9 ** Licensees holding valid commercial license for Qt may use this file in
9 ** Licensees holding valid commercial license for Qt may use this file in
10 ** accordance with the Qt License Agreement provided with the Software
10 ** accordance with the Qt License Agreement provided with the Software
11 ** or, alternatively, in accordance with the terms contained in a written
11 ** or, alternatively, in accordance with the terms contained in a written
12 ** agreement between you and Digia.
12 ** agreement between you and Digia.
13 **
13 **
14 ** If you have questions regarding the use of this file, please use
14 ** If you have questions regarding the use of this file, please use
15 ** contact form at http://qt.io
15 ** contact form at http://qt.io
16 **
16 **
17 ****************************************************************************/
17 ****************************************************************************/
18
18
19 #include <private/scatterchartitem_p.h>
19 #include <private/scatterchartitem_p.h>
20 #include <QtCharts/QScatterSeries>
20 #include <QtCharts/QScatterSeries>
21 #include <private/qscatterseries_p.h>
21 #include <private/qscatterseries_p.h>
22 #include <private/chartpresenter_p.h>
22 #include <private/chartpresenter_p.h>
23 #include <private/abstractdomain_p.h>
23 #include <private/abstractdomain_p.h>
24 #include <QtCharts/QChart>
24 #include <QtCharts/QChart>
25 #include <QtGui/QPainter>
25 #include <QtGui/QPainter>
26 #include <QtWidgets/QGraphicsScene>
26 #include <QtWidgets/QGraphicsScene>
27 #include <QtCore/QDebug>
27 #include <QtCore/QDebug>
28 #include <QtWidgets/QGraphicsSceneMouseEvent>
28 #include <QtWidgets/QGraphicsSceneMouseEvent>
29
29
30 QT_CHARTS_BEGIN_NAMESPACE
30 QT_CHARTS_BEGIN_NAMESPACE
31
31
32 ScatterChartItem::ScatterChartItem(QScatterSeries *series, QGraphicsItem *item)
32 ScatterChartItem::ScatterChartItem(QScatterSeries *series, QGraphicsItem *item)
33 : XYChart(series,item),
33 : XYChart(series,item),
34 m_series(series),
34 m_series(series),
35 m_items(this),
35 m_items(this),
36 m_visible(true),
36 m_visible(true),
37 m_shape(QScatterSeries::MarkerShapeRectangle),
37 m_shape(QScatterSeries::MarkerShapeRectangle),
38 m_size(15),
38 m_size(15),
39 m_pointLabelsVisible(false),
39 m_pointLabelsVisible(false),
40 m_pointLabelsFormat(series->pointLabelsFormat()),
40 m_pointLabelsFormat(series->pointLabelsFormat()),
41 m_pointLabelsFont(series->pointLabelsFont()),
41 m_pointLabelsFont(series->pointLabelsFont()),
42 m_pointLabelsColor(series->pointLabelsColor()),
42 m_pointLabelsColor(series->pointLabelsColor()),
43 m_mousePressed(false)
43 m_mousePressed(false)
44 {
44 {
45 QObject::connect(m_series->d_func(), SIGNAL(updated()), this, SLOT(handleUpdated()));
45 QObject::connect(m_series->d_func(), SIGNAL(updated()), this, SLOT(handleUpdated()));
46 QObject::connect(m_series, SIGNAL(visibleChanged()), this, SLOT(handleUpdated()));
46 QObject::connect(m_series, SIGNAL(visibleChanged()), this, SLOT(handleUpdated()));
47 QObject::connect(m_series, SIGNAL(opacityChanged()), this, SLOT(handleUpdated()));
47 QObject::connect(m_series, SIGNAL(opacityChanged()), this, SLOT(handleUpdated()));
48 QObject::connect(series, SIGNAL(pointLabelsFormatChanged(QString)),
48 QObject::connect(series, SIGNAL(pointLabelsFormatChanged(QString)),
49 this, SLOT(handleUpdated()));
49 this, SLOT(handleUpdated()));
50 QObject::connect(series, SIGNAL(pointLabelsVisibilityChanged(bool)),
50 QObject::connect(series, SIGNAL(pointLabelsVisibilityChanged(bool)),
51 this, SLOT(handleUpdated()));
51 this, SLOT(handleUpdated()));
52 QObject::connect(series, SIGNAL(pointLabelsFontChanged(QFont)), this, SLOT(handleUpdated()));
52 QObject::connect(series, SIGNAL(pointLabelsFontChanged(QFont)), this, SLOT(handleUpdated()));
53 QObject::connect(series, SIGNAL(pointLabelsColorChanged(QColor)), this, SLOT(handleUpdated()));
53 QObject::connect(series, SIGNAL(pointLabelsColorChanged(QColor)), this, SLOT(handleUpdated()));
54
54
55 setZValue(ChartPresenter::ScatterSeriesZValue);
55 setZValue(ChartPresenter::ScatterSeriesZValue);
56 setFlags(QGraphicsItem::ItemClipsChildrenToShape);
56 setFlags(QGraphicsItem::ItemClipsChildrenToShape);
57 setFlag(QGraphicsItem::ItemIsSelectable);
58
57
59 handleUpdated();
58 handleUpdated();
60
59
61 m_items.setHandlesChildEvents(false);
60 m_items.setHandlesChildEvents(false);
62 }
61 }
63
62
64 QRectF ScatterChartItem::boundingRect() const
63 QRectF ScatterChartItem::boundingRect() const
65 {
64 {
66 return m_rect;
65 return m_rect;
67 }
66 }
68
67
69 void ScatterChartItem::createPoints(int count)
68 void ScatterChartItem::createPoints(int count)
70 {
69 {
71 for (int i = 0; i < count; ++i) {
70 for (int i = 0; i < count; ++i) {
72
71
73 QGraphicsItem *item = 0;
72 QGraphicsItem *item = 0;
74
73
75 switch (m_shape) {
74 switch (m_shape) {
76 case QScatterSeries::MarkerShapeCircle: {
75 case QScatterSeries::MarkerShapeCircle: {
77 item = new CircleMarker(0, 0, m_size, m_size, this);
76 item = new CircleMarker(0, 0, m_size, m_size, this);
78 const QRectF &rect = item->boundingRect();
77 const QRectF &rect = item->boundingRect();
79 item->setPos(-rect.width() / 2, -rect.height() / 2);
78 item->setPos(-rect.width() / 2, -rect.height() / 2);
80 break;
79 break;
81 }
80 }
82 case QScatterSeries::MarkerShapeRectangle:
81 case QScatterSeries::MarkerShapeRectangle:
83 item = new RectangleMarker(0, 0, m_size, m_size, this);
82 item = new RectangleMarker(0, 0, m_size, m_size, this);
84 item->setPos(-m_size / 2, -m_size / 2);
83 item->setPos(-m_size / 2, -m_size / 2);
85 break;
84 break;
86 default:
85 default:
87 qWarning() << "Unsupported marker type";
86 qWarning() << "Unsupported marker type";
88 break;
87 break;
89 }
88 }
90 m_items.addToGroup(item);
89 m_items.addToGroup(item);
91 }
90 }
92 }
91 }
93
92
94 void ScatterChartItem::deletePoints(int count)
93 void ScatterChartItem::deletePoints(int count)
95 {
94 {
96 QList<QGraphicsItem *> items = m_items.childItems();
95 QList<QGraphicsItem *> items = m_items.childItems();
97
96
98 for (int i = 0; i < count; ++i) {
97 for (int i = 0; i < count; ++i) {
99 QGraphicsItem *item = items.takeLast();
98 QGraphicsItem *item = items.takeLast();
100 m_markerMap.remove(item);
99 m_markerMap.remove(item);
101 delete(item);
100 delete(item);
102 }
101 }
103 }
102 }
104
103
105 void ScatterChartItem::markerSelected(QGraphicsItem *marker)
104 void ScatterChartItem::markerSelected(QGraphicsItem *marker)
106 {
105 {
107 emit XYChart::clicked(m_markerMap[marker]);
106 emit XYChart::clicked(m_markerMap[marker]);
108 }
107 }
109
108
110 void ScatterChartItem::markerHovered(QGraphicsItem *marker, bool state)
109 void ScatterChartItem::markerHovered(QGraphicsItem *marker, bool state)
111 {
110 {
112 emit XYChart::hovered(m_markerMap[marker], state);
111 emit XYChart::hovered(m_markerMap[marker], state);
113 }
112 }
114
113
115 void ScatterChartItem::markerPressed(QGraphicsItem *marker)
114 void ScatterChartItem::markerPressed(QGraphicsItem *marker)
116 {
115 {
117 emit XYChart::pressed(m_markerMap[marker]);
116 emit XYChart::pressed(m_markerMap[marker]);
118 }
117 }
119
118
120 void ScatterChartItem::markerReleased(QGraphicsItem *marker)
119 void ScatterChartItem::markerReleased(QGraphicsItem *marker)
121 {
120 {
122 emit XYChart::released(m_markerMap[marker]);
121 emit XYChart::released(m_markerMap[marker]);
123 }
122 }
124
123
125 void ScatterChartItem::markerDoubleClicked(QGraphicsItem *marker)
124 void ScatterChartItem::markerDoubleClicked(QGraphicsItem *marker)
126 {
125 {
127 emit XYChart::doubleClicked(m_markerMap[marker]);
126 emit XYChart::doubleClicked(m_markerMap[marker]);
128 }
127 }
129
128
130 void ScatterChartItem::updateGeometry()
129 void ScatterChartItem::updateGeometry()
131 {
130 {
132
131
133 const QVector<QPointF>& points = geometryPoints();
132 const QVector<QPointF>& points = geometryPoints();
134
133
135 if (points.size() == 0) {
134 if (points.size() == 0) {
136 deletePoints(m_items.childItems().count());
135 deletePoints(m_items.childItems().count());
137 return;
136 return;
138 }
137 }
139
138
140 int diff = m_items.childItems().size() - points.size();
139 int diff = m_items.childItems().size() - points.size();
141
140
142 if (diff > 0)
141 if (diff > 0)
143 deletePoints(diff);
142 deletePoints(diff);
144 else if (diff < 0)
143 else if (diff < 0)
145 createPoints(-diff);
144 createPoints(-diff);
146
145
147 if (diff != 0)
146 if (diff != 0)
148 handleUpdated();
147 handleUpdated();
149
148
150 QList<QGraphicsItem *> items = m_items.childItems();
149 QList<QGraphicsItem *> items = m_items.childItems();
151
150
152 QRectF clipRect(QPointF(0,0),domain()->size());
151 QRectF clipRect(QPointF(0,0),domain()->size());
153
152
154 // Only zoom in if the clipRect fits inside int limits. QWidget::update() uses
153 // Only zoom in if the clipRect fits inside int limits. QWidget::update() uses
155 // a region that has to be compatible with QRect.
154 // a region that has to be compatible with QRect.
156 if (clipRect.height() <= INT_MAX
155 if (clipRect.height() <= INT_MAX
157 && clipRect.width() <= INT_MAX) {
156 && clipRect.width() <= INT_MAX) {
158 QVector<bool> offGridStatus = offGridStatusVector();
157 QVector<bool> offGridStatus = offGridStatusVector();
159 const int seriesLastIndex = m_series->count() - 1;
158 const int seriesLastIndex = m_series->count() - 1;
160
159
161 for (int i = 0; i < points.size(); i++) {
160 for (int i = 0; i < points.size(); i++) {
162 QGraphicsItem *item = items.at(i);
161 QGraphicsItem *item = items.at(i);
163 const QPointF &point = points.at(i);
162 const QPointF &point = points.at(i);
164 const QRectF &rect = item->boundingRect();
163 const QRectF &rect = item->boundingRect();
165 // During remove animation series may have different number of points,
164 // During remove animation series may have different number of points,
166 // so ensure we don't go over the index. Animation handling itself ensures that
165 // so ensure we don't go over the index. Animation handling itself ensures that
167 // if there is actually no points in the series, then it won't generate a fake point,
166 // if there is actually no points in the series, then it won't generate a fake point,
168 // so we can be assured there is always at least one point in m_series here.
167 // so we can be assured there is always at least one point in m_series here.
169 // Note that marker map values can be technically incorrect during the animation,
168 // Note that marker map values can be technically incorrect during the animation,
170 // if it was caused by an insert, but this shouldn't be a problem as the points are
169 // if it was caused by an insert, but this shouldn't be a problem as the points are
171 // fake anyway. After remove animation stops, geometry is updated to correct one.
170 // fake anyway. After remove animation stops, geometry is updated to correct one.
172 m_markerMap[item] = m_series->at(qMin(seriesLastIndex, i));
171 m_markerMap[item] = m_series->at(qMin(seriesLastIndex, i));
173 item->setPos(point.x() - rect.width() / 2, point.y() - rect.height() / 2);
172 item->setPos(point.x() - rect.width() / 2, point.y() - rect.height() / 2);
174
173
175 if (!m_visible || offGridStatus.at(i))
174 if (!m_visible || offGridStatus.at(i))
176 item->setVisible(false);
175 item->setVisible(false);
177 else
176 else
178 item->setVisible(true);
177 item->setVisible(true);
179 }
178 }
180
179
181 prepareGeometryChange();
180 prepareGeometryChange();
182 m_rect = clipRect;
181 m_rect = clipRect;
183 }
182 }
184 }
183 }
185
184
186 void ScatterChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
185 void ScatterChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
187 {
186 {
188 Q_UNUSED(option)
187 Q_UNUSED(option)
189 Q_UNUSED(widget)
188 Q_UNUSED(widget)
190
189
191 QRectF clipRect = QRectF(QPointF(0, 0), domain()->size());
190 QRectF clipRect = QRectF(QPointF(0, 0), domain()->size());
192
191
193 painter->save();
192 painter->save();
194 painter->setClipRect(clipRect);
193 painter->setClipRect(clipRect);
195
194
196 if (m_pointLabelsVisible) {
195 if (m_pointLabelsVisible) {
197 m_series->d_func()->drawSeriesPointLabels(painter, m_points,
196 m_series->d_func()->drawSeriesPointLabels(painter, m_points,
198 m_series->markerSize() / 2
197 m_series->markerSize() / 2
199 + m_series->pen().width());
198 + m_series->pen().width());
200 }
199 }
201
200
202 painter->restore();
201 painter->restore();
203 }
202 }
204
203
205 void ScatterChartItem::setPen(const QPen &pen)
204 void ScatterChartItem::setPen(const QPen &pen)
206 {
205 {
207 foreach (QGraphicsItem *item , m_items.childItems())
206 foreach (QGraphicsItem *item , m_items.childItems())
208 static_cast<QAbstractGraphicsShapeItem*>(item)->setPen(pen);
207 static_cast<QAbstractGraphicsShapeItem*>(item)->setPen(pen);
209 }
208 }
210
209
211 void ScatterChartItem::setBrush(const QBrush &brush)
210 void ScatterChartItem::setBrush(const QBrush &brush)
212 {
211 {
213 foreach (QGraphicsItem *item , m_items.childItems())
212 foreach (QGraphicsItem *item , m_items.childItems())
214 static_cast<QAbstractGraphicsShapeItem*>(item)->setBrush(brush);
213 static_cast<QAbstractGraphicsShapeItem*>(item)->setBrush(brush);
215 }
214 }
216
215
217 void ScatterChartItem::handleUpdated()
216 void ScatterChartItem::handleUpdated()
218 {
217 {
219 int count = m_items.childItems().count();
218 int count = m_items.childItems().count();
220
219
221 if (count == 0)
220 if (count == 0)
222 return;
221 return;
223
222
224 bool recreate = m_visible != m_series->isVisible()
223 bool recreate = m_visible != m_series->isVisible()
225 || m_size != m_series->markerSize()
224 || m_size != m_series->markerSize()
226 || m_shape != m_series->markerShape();
225 || m_shape != m_series->markerShape();
227
226
228 m_visible = m_series->isVisible();
227 m_visible = m_series->isVisible();
229 m_size = m_series->markerSize();
228 m_size = m_series->markerSize();
230 m_shape = m_series->markerShape();
229 m_shape = m_series->markerShape();
231 setOpacity(m_series->opacity());
230 setOpacity(m_series->opacity());
232 m_pointLabelsFormat = m_series->pointLabelsFormat();
231 m_pointLabelsFormat = m_series->pointLabelsFormat();
233 m_pointLabelsVisible = m_series->pointLabelsVisible();
232 m_pointLabelsVisible = m_series->pointLabelsVisible();
234 m_pointLabelsFont = m_series->pointLabelsFont();
233 m_pointLabelsFont = m_series->pointLabelsFont();
235 m_pointLabelsColor = m_series->pointLabelsColor();
234 m_pointLabelsColor = m_series->pointLabelsColor();
236
235
237 if (recreate) {
236 if (recreate) {
238 deletePoints(count);
237 deletePoints(count);
239 createPoints(count);
238 createPoints(count);
240
239
241 // Updating geometry is now safe, because it won't call handleUpdated unless it creates/deletes points
240 // Updating geometry is now safe, because it won't call handleUpdated unless it creates/deletes points
242 updateGeometry();
241 updateGeometry();
243 }
242 }
244
243
245 setPen(m_series->pen());
244 setPen(m_series->pen());
246 setBrush(m_series->brush());
245 setBrush(m_series->brush());
247 update();
246 update();
248 }
247 }
249
248
250 #include "moc_scatterchartitem_p.cpp"
249 #include "moc_scatterchartitem_p.cpp"
251
250
252 QT_CHARTS_END_NAMESPACE
251 QT_CHARTS_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now