##// END OF EJS Templates
Added handling for pieslice add/remove to legend
sauimone -
r637:e242f9df3ad1
parent child
Show More
@@ -1,342 +1,465
1 1 #include "qchartglobal.h"
2 2 #include "qlegend.h"
3 3 #include "qseries.h"
4 4 #include "legendmarker_p.h"
5 5 #include "qxyseries.h"
6 6 #include "qlineseries.h"
7 7 #include "qareaseries.h"
8 8 #include "qscatterseries.h"
9 9 #include "qsplineseries.h"
10 10 #include "qbarseries.h"
11 11 #include "qstackedbarseries.h"
12 12 #include "qpercentbarseries.h"
13 13 #include "qbarset.h"
14 14 #include "qpieseries.h"
15 15 #include "qpieslice.h"
16 16 #include "chartpresenter_p.h"
17 17 #include <QPainter>
18 18 #include <QPen>
19 19
20 20 #include <QGraphicsSceneEvent>
21 21
22 22 QTCOMMERCIALCHART_BEGIN_NAMESPACE
23 23
24 24 QLegend::QLegend(QGraphicsItem *parent)
25 25 : QGraphicsObject(parent)
26 26 ,mPos(0,0)
27 27 ,mSize(0,0)
28 28 ,mMinimumSize(50,20) // TODO: magic numbers
29 29 ,mMaximumSize(150,100)
30 30 ,mBackgroundBrush(Qt::darkGray) // TODO: from theme?
31 31 ,mPreferredLayout(QLegend::PreferredLayoutVertical)
32 32 {
33 33 // setVisible(false);
34 34 setZValue(ChartPresenter::LegendZValue);
35 35 }
36 36
37 37 void QLegend::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
38 38 {
39 39 Q_UNUSED(option)
40 40 Q_UNUSED(widget)
41 41
42 42 painter->setOpacity(0.5);
43 43 painter->setBrush(mBackgroundBrush);
44 44 painter->drawRect(boundingRect());
45 45 }
46 46
47 47 QRectF QLegend::boundingRect() const
48 48 {
49 49 return QRectF(mPos,mSize);
50 50 }
51 51
52 52 void QLegend::setBackgroundBrush(const QBrush& brush)
53 53 {
54 54 mBackgroundBrush = brush;
55 55 }
56 56
57 57 QBrush QLegend::backgroundBrush() const
58 58 {
59 59 return mBackgroundBrush;
60 60 }
61 61
62 62 void QLegend::setPreferredLayout(QLegend::PreferredLayout preferred)
63 63 {
64 64 mPreferredLayout = preferred;
65 65 layoutChanged();
66 66 }
67 67
68 68 QSizeF QLegend::maximumSize() const
69 69 {
70 70 return mMaximumSize;
71 71 }
72 72
73 73 void QLegend::setMaximumSize(const QSizeF size)
74 74 {
75 75 mMaximumSize = size;
76 76 }
77 77
78 78 void QLegend::setSize(const QSizeF size)
79 79 {
80 80 mSize = size;
81 81 if (mSize.width() > mMaximumSize.width()) {
82 82 mSize.setWidth(mMaximumSize.width());
83 83 }
84 84 if (mSize.height() > mMaximumSize.height()) {
85 85 mSize.setHeight(mMaximumSize.height());
86 86 }
87 87 }
88 88
89 89 void QLegend::setPos(const QPointF &pos)
90 90 {
91 91 mPos = pos;
92 92 }
93 93
94 94 void QLegend::handleSeriesAdded(QSeries* series, Domain* domain)
95 95 {
96 96 Q_UNUSED(domain)
97 97
98 98 mSeriesList.append(series);
99 99 createMarkers(series);
100 connectSeries(series);
100 101 layoutChanged();
101 102 }
102 103
103 104 void QLegend::handleSeriesRemoved(QSeries* series)
104 105 {
106 disconnectSeries(series);
107
105 108 if (series->type() == QSeries::SeriesTypeArea)
106 109 {
107 110 // This is special case. Area series has upper and lower series, which each have markers
108 111 QAreaSeries* s = static_cast<QAreaSeries*> (series);
109 112 deleteMarkers(s->upperSeries());
110 113 deleteMarkers(s->lowerSeries());
111 114 } else {
112 115 deleteMarkers(series);
113 116 }
114 117
115 118 mSeriesList.removeOne(series);
116 119 layoutChanged();
117 120 }
118 121
122 void QLegend::handleAdded(QList<QPieSlice*> slices)
123 {
124 QPieSeries* series = static_cast<QPieSeries*> (sender());
125 foreach(QPieSlice* s, slices) {
126 LegendMarker* marker = new LegendMarker(series,s,this);
127 marker->setName(s->label());
128 marker->setBrush(s->sliceBrush());
129 connect(marker,SIGNAL(clicked(QPieSlice*,Qt::MouseButton)),this,SIGNAL(clicked(QPieSlice*,Qt::MouseButton)));
130 connect(s,SIGNAL(changed()),marker,SLOT(changed()));
131 connect(s,SIGNAL(destroyed()),marker,SLOT(deleteLater()));
132 mMarkers.append(marker);
133 childItems().append(marker);
134 }
135 layoutChanged();
136 }
137
138 void QLegend::handleMarkerDestroyed()
139 {
140 // TODO: what if more than one markers are destroyed and we update layout after first one?
141 LegendMarker* m = static_cast<LegendMarker*> (sender());
142 mMarkers.removeOne(m);
143 layoutChanged();
144 }
145
146 void QLegend::connectSeries(QSeries *series)
147 {
148 // Connect relevant signals from series
149 switch (series->type())
150 {
151 case QSeries::SeriesTypeLine: {
152 // QLineSeries* lineSeries = static_cast<QLineSeries*>(series);
153 break;
154 }
155 case QSeries::SeriesTypeArea: {
156 // QAreaSeries* areaSeries = static_cast<QAreaSeries*>(series);
157 break;
158 }
159 case QSeries::SeriesTypeBar: {
160 // QBarSeries* barSeries = static_cast<QBarSeries*>(series);
161 break;
162 }
163 case QSeries::SeriesTypeStackedBar: {
164 // QStackedBarSeries* stackedBarSeries = static_cast<QStackedBarSeries*>(series);
165 break;
166 }
167 case QSeries::SeriesTypePercentBar: {
168 // QPercentBarSeries* percentBarSeries = static_cast<QPercentBarSeries*>(series);
169 break;
170 }
171 case QSeries::SeriesTypeScatter: {
172 // QScatterSeries *scatterSeries = static_cast<QScatterSeries *>(series);
173 break;
174 }
175 case QSeries::SeriesTypePie: {
176 QPieSeries *pieSeries = static_cast<QPieSeries *>(series);
177 connect(pieSeries,SIGNAL(added(QList<QPieSlice*>)),this,SLOT(handleAdded(QList<QPieSlice*>)));
178 // connect(pieSeries,SIGNAL(removed(QList<QPieSlice*>)),this,SLOT(handleRemoved(QList<QPieSlice*>)));
179 break;
180 }
181 case QSeries::SeriesTypeSpline: {
182 // QSplineSeries* splineSeries = static_cast<QSplineSeries*>(series);
183 break;
184 }
185 default: {
186 qDebug()<< "QLegend::connectSeries" << series->type() << "not implemented.";
187 break;
188 }
189 }
190 }
191
192 void QLegend::disconnectSeries(QSeries *series)
193 {
194 // Connect relevant signals from series
195 switch (series->type())
196 {
197 case QSeries::SeriesTypeLine: {
198 // QLineSeries* lineSeries = static_cast<QLineSeries*>(series);
199 break;
200 }
201 case QSeries::SeriesTypeArea: {
202 // QAreaSeries* areaSeries = static_cast<QAreaSeries*>(series);
203 break;
204 }
205 case QSeries::SeriesTypeBar: {
206 // QBarSeries* barSeries = static_cast<QBarSeries*>(series);
207 break;
208 }
209 case QSeries::SeriesTypeStackedBar: {
210 // QStackedBarSeries* stackedBarSeries = static_cast<QStackedBarSeries*>(series);
211 break;
212 }
213 case QSeries::SeriesTypePercentBar: {
214 // QPercentBarSeries* percentBarSeries = static_cast<QPercentBarSeries*>(series);
215 break;
216 }
217 case QSeries::SeriesTypeScatter: {
218 // QScatterSeries *scatterSeries = static_cast<QScatterSeries *>(series);
219 break;
220 }
221 case QSeries::SeriesTypePie: {
222 QPieSeries *pieSeries = static_cast<QPieSeries *>(series);
223 disconnect(pieSeries,SIGNAL(added(QList<QPieSlice*>)),this,SLOT(handleAdded(QList<QPieSlice*>)));
224 // disconnect(pieSeries,SIGNAL(removed(QList<QPieSlice*>)),this,SLOT(handleRemoved(QList<QPieSlice*>)));
225 break;
226 }
227 case QSeries::SeriesTypeSpline: {
228 // QSplineSeries* splineSeries = static_cast<QSplineSeries*>(series);
229 break;
230 }
231 default: {
232 qDebug()<< "QLegend::disconnectSeries" << series->type() << "not implemented.";
233 break;
234 }
235 }
236 }
237
119 238 void QLegend::createMarkers(QSeries *series)
120 239 {
121 240 switch (series->type())
122 241 {
123 242 case QSeries::SeriesTypeLine: {
124 243 QLineSeries* lineSeries = static_cast<QLineSeries*>(series);
125 244 appendMarkers(lineSeries);
126 245 break;
127 246 }
128 247 case QSeries::SeriesTypeArea: {
129 248 QAreaSeries* areaSeries = static_cast<QAreaSeries*>(series);
130 249 appendMarkers(areaSeries->upperSeries());
131 250 if(areaSeries->lowerSeries())
132 251 appendMarkers(areaSeries->lowerSeries());
133 252 break;
134 253 }
135 254
136 255 case QSeries::SeriesTypeBar: {
137 256 QBarSeries* barSeries = static_cast<QBarSeries*>(series);
138 257 appendMarkers(barSeries);
139 258 break;
140 259 }
141 260
142 261 case QSeries::SeriesTypeStackedBar: {
143 262 QStackedBarSeries* stackedBarSeries = static_cast<QStackedBarSeries*>(series);
144 263 appendMarkers(stackedBarSeries);
145 264 break;
146 265 }
147 266
148 267 case QSeries::SeriesTypePercentBar: {
149 268 QPercentBarSeries* percentBarSeries = static_cast<QPercentBarSeries*>(series);
150 269 appendMarkers(percentBarSeries);
151 270 break;
152 271 }
153 272
154 273 case QSeries::SeriesTypeScatter: {
155 274 QScatterSeries *scatterSeries = static_cast<QScatterSeries *>(series);
156 275 appendMarkers(scatterSeries);
157 276 break;
158 277 }
159 278
160 279 case QSeries::SeriesTypePie: {
161 280 QPieSeries *pieSeries = static_cast<QPieSeries *>(series);
162 281 appendMarkers(pieSeries);
163 282 break;
164 283 }
165 284
166 285 case QSeries::SeriesTypeSpline: {
167 286 QSplineSeries* splineSeries = static_cast<QSplineSeries*>(series);
168 287 appendMarkers(splineSeries);
169 288 break;
170 289 }
171 290 default: {
172 291 qDebug()<< "QLegend::createMarkers" << series->type() << "not implemented.";
173 292 break;
174 293 }
175 294 }
176 295 }
177 296
178 297 void QLegend::appendMarkers(QXYSeries* series)
179 298 {
180 299 LegendMarker* marker = new LegendMarker(series,this);
181 300 marker->setName(series->name());
182 301 marker->setBrush(series->brush());
183 302 connect(marker,SIGNAL(clicked(QSeries*,Qt::MouseButton)),this,SIGNAL(clicked(QSeries*,Qt::MouseButton)));
303 connect(marker,SIGNAL(destroyed()),this,SLOT(handleMarkerDestroyed()));
184 304 mMarkers.append(marker);
185 305 childItems().append(marker);
186 306 }
187 307
188 308 void QLegend::appendMarkers(QBarSeries *series)
189 309 {
190 310 foreach(QBarSet* s, series->barSets()) {
191 311 LegendMarker* marker = new LegendMarker(series,s,this);
192 312 marker->setName(s->name());
193 313 marker->setBrush(s->brush());
194 314 connect(marker,SIGNAL(clicked(QBarSet*,Qt::MouseButton)),this,SIGNAL(clicked(QBarSet*,Qt::MouseButton)));
195 315 connect(s,SIGNAL(changed()),marker,SLOT(changed()));
316 connect(marker,SIGNAL(destroyed()),this,SLOT(handleMarkerDestroyed()));
196 317 mMarkers.append(marker);
197 318 childItems().append(marker);
198 319 }
199 320 }
200 321
201 322 void QLegend::appendMarkers(QPieSeries *series)
202 323 {
203 324 foreach(QPieSlice* s, series->slices()) {
204 325 LegendMarker* marker = new LegendMarker(series,s,this);
205 326 marker->setName(s->label());
206 327 marker->setBrush(s->sliceBrush());
207 328 connect(marker,SIGNAL(clicked(QPieSlice*,Qt::MouseButton)),this,SIGNAL(clicked(QPieSlice*,Qt::MouseButton)));
208 329 connect(s,SIGNAL(changed()),marker,SLOT(changed()));
330 connect(s,SIGNAL(destroyed()),marker,SLOT(deleteLater()));
331 connect(marker,SIGNAL(destroyed()),this,SLOT(handleMarkerDestroyed()));
209 332 mMarkers.append(marker);
210 333 childItems().append(marker);
211 334 }
212 335 }
213 336
214 337 void QLegend::deleteMarkers(QSeries *series)
215 338 {
216 339 // Search all markers that belong to given series and delete them.
217 340 foreach (LegendMarker *m, mMarkers) {
218 341 if (m->series() == series) {
219 342 mMarkers.removeOne(m);
220 343 delete m;
221 344 }
222 345 }
223 346 }
224 347
225 348 void QLegend::layoutChanged()
226 349 {
227 350 // Calculate layout for markers and text
228 351 if (mMarkers.count() <= 0) {
229 352 // Nothing to do
230 353 return;
231 354 }
232 355
233 356 // Find out widest item.
234 357 qreal itemMaxWidth = 0;
235 358 qreal itemMaxHeight = 0;
236 359 foreach (LegendMarker* m, mMarkers) {
237 360 if (m->boundingRect().width() > itemMaxWidth) {
238 361 itemMaxWidth = m->boundingRect().width();
239 362 }
240 363 if (m->boundingRect().height() > itemMaxHeight) {
241 364 itemMaxHeight = m->boundingRect().height();
242 365 }
243 366 }
244 367
245 368 int maxHorizontalItems = boundingRect().width() / itemMaxWidth;
246 369 int maxVerticalItems = boundingRect().height() / itemMaxHeight;
247 370
248 371 if (mMarkers.count() > maxHorizontalItems * maxVerticalItems) {
249 372 // TODO: overlapping layout
250 373 qDebug() << "Warning. Not enough space to layout all legend items properly.";
251 374 }
252 375
253 376 qreal margin = 5;
254 377 qreal totalWidth = 0;
255 378 qreal totalHeight = 0;
256 379 switch (mPreferredLayout)
257 380 {
258 381 case QLegend::PreferredLayoutHorizontal: {
259 382 /*
260 383 qreal xStep = mMaximumSize.width() / (mMarkers.count()+1);
261 384 if (xStep > itemMaxWidth) {
262 385 xStep = itemMaxWidth;
263 386 }
264 387 qreal yStep = mMaximumSize.height() / (mMarkers.count()+1);
265 388 if (yStep > itemMaxHeight) {
266 389 yStep = itemMaxHeight;
267 390 }*/
268 391 qreal xStep = itemMaxWidth;
269 392 qreal yStep = itemMaxHeight;
270 393 qreal x = mPos.x() + margin;
271 394 qreal y = mPos.y() + margin;
272 395 int row = 1;
273 396 int column = 0;
274 397 int maxRows = 1;
275 398 int maxColumns = 1;
276 399 foreach (LegendMarker* m, mMarkers) {
277 400 maxRows = row;
278 401 m->setPos(x,y);
279 402 x += xStep;
280 403 column++;
281 404 if (column > maxColumns) {
282 405 maxColumns = column;
283 406 }
284 407 if ((x + itemMaxWidth + margin*2) > (mPos.x() + mMaximumSize.width())) {
285 408 x = mPos.x() + margin;
286 409 y += yStep;
287 410 row++;
288 411 column = 0;
289 412 }
290 413 }
291 414 totalWidth = maxColumns * itemMaxWidth + margin * 2;
292 415 totalHeight = maxRows * itemMaxHeight + margin * 2;
293 416 break;
294 417 }
295 418 case QLegend::PreferredLayoutVertical: {
296 419 /*
297 420 qreal xStep = mMaximumSize.width() / (mMarkers.count()+1);
298 421 if (xStep > itemMaxWidth) {
299 422 xStep = itemMaxWidth;
300 423 }
301 424 qreal yStep = mMaximumSize.height() / (mMarkers.count()+1);
302 425 if (yStep > itemMaxHeight) {
303 426 yStep = itemMaxHeight;
304 427 }*/
305 428 qreal xStep = itemMaxWidth;
306 429 qreal yStep = itemMaxHeight;
307 430 qreal x = mPos.x() + margin;
308 431 qreal y = mPos.y() + margin;
309 432 int row = 0;
310 433 int column = 1;
311 434 int maxRows = 1;
312 435 int maxColumns = 1;
313 436 foreach (LegendMarker* m, mMarkers) {
314 437 maxColumns = column;
315 438 m->setPos(x,y);
316 439 y += yStep;
317 440 row++;
318 441 if (row > maxRows) {
319 442 maxRows = row;
320 443 }
321 444 if ((y + itemMaxHeight + margin*2) > (mPos.y() + mMaximumSize.height())) {
322 445 y = mPos.y() + margin;
323 446 x += xStep;
324 447 column++;
325 448 row = 0;
326 449 }
327 450 }
328 451 totalWidth = maxColumns * itemMaxWidth + margin * 2;
329 452 totalHeight = maxRows * itemMaxHeight + margin * 2;
330 453 break;
331 454 }
332 455 default: {
333 456 break;
334 457 }
335 458 }
336 459
337 460 mSize.setWidth(totalWidth);
338 461 mSize.setHeight(totalHeight);
339 462 }
340 463
341 464 #include "moc_qlegend.cpp"
342 465 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,80 +1,85
1 1 #ifndef QLEGEND_H
2 2 #define QLEGEND_H
3 3
4 4 #include "qchartglobal.h"
5 5 #include "qseries.h"
6 6 #include <QGraphicsObject>
7 7
8 8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9 9
10 10 class Domain;
11 11 class LegendMarker;
12 12 class QPieSlice;
13 13 class QXYSeries;
14 14 class QBarSet;
15 15 class QBarSeries;
16 16 class QPieSeries;
17 17
18 18 class QTCOMMERCIALCHART_EXPORT QLegend : public QGraphicsObject
19 19 {
20 20 Q_OBJECT
21 21 public:
22 22
23 23 enum PreferredLayout {
24 24 PreferredLayoutHorizontal,
25 25 PreferredLayoutVertical
26 26 };
27 27
28 28 explicit QLegend(QGraphicsItem *parent = 0);
29 29
30 30 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
31 31 QRectF boundingRect() const;
32 32
33 33 void setBackgroundBrush(const QBrush& brush);
34 34 QBrush backgroundBrush() const;
35 35
36 36 void setPreferredLayout(QLegend::PreferredLayout preferred);
37 37
38 38 QSizeF maximumSize() const;
39 39 void setMaximumSize(const QSizeF size);
40 40
41 41 void setSize(const QSizeF size);
42 42 void setPos(const QPointF &pos);
43 43
44 44 signals:
45 45 // for interactions.
46 46 void clicked(QSeries* series, Qt::MouseButton button);
47 47 void clicked(QBarSet* barset, Qt::MouseButton button);
48 48 void clicked(QPieSlice* slice, Qt::MouseButton button);
49 49
50 50 public slots:
51 51 void handleSeriesAdded(QSeries* series,Domain* domain);
52 52 void handleSeriesRemoved(QSeries* series);
53 void handleAdded(QList<QPieSlice*> slices);
54 // void handleRemoved(QList<QPieSlice*> slices);
55 void handleMarkerDestroyed();
53 56
54 57 private:
55 58 // PIMPL --->
59 void connectSeries(QSeries* series);
60 void disconnectSeries(QSeries* series);
56 61 void createMarkers(QSeries* series);
57 62 void appendMarkers(QXYSeries* series); // All line series are derived from QXYSeries, so this works for now
58 63 void appendMarkers(QBarSeries* series);
59 64 void appendMarkers(QPieSeries* series);
60 65 void deleteMarkers(QSeries* series);
61 void layoutChanged(); // TODO: rename this to layoutChanged and remove original layoutChanged, when ready
66 void layoutChanged();
62 67 // <--- PIMPL
63 68
64 69
65 70 // QRectF mBoundingRect;
66 71 QPointF mPos;
67 72 QSizeF mSize;
68 73 QSizeF mMinimumSize;
69 74 QSizeF mMaximumSize;
70 75
71 76 QList<QSeries*> mSeriesList;
72 77 QList<LegendMarker*> mMarkers;
73 78
74 79 QBrush mBackgroundBrush;
75 80 QLegend::PreferredLayout mPreferredLayout;
76 81 };
77 82
78 83 QTCOMMERCIALCHART_END_NAMESPACE
79 84
80 85 #endif // QLEGEND_H
General Comments 0
You need to be logged in to leave comments. Login now