##// END OF EJS Templates
Explicitly update GLWidget when we set new points...
Miikka Heikkinen -
r2865:672ea1cb191f
parent child
Show More
@@ -1,574 +1,577
1 1 /******************************************************************************
2 2 **
3 3 ** Copyright (C) 2015 The Qt Company Ltd.
4 4 ** Contact: http://www.qt.io/licensing/
5 5 **
6 6 ** This file is part of the Qt Charts module.
7 7 **
8 8 ** $QT_BEGIN_LICENSE:COMM$
9 9 **
10 10 ** Commercial License Usage
11 11 ** Licensees holding valid commercial Qt licenses may use this file in
12 12 ** accordance with the commercial license agreement provided with the
13 13 ** Software or, alternatively, in accordance with the terms contained in
14 14 ** a written agreement between you and The Qt Company. For licensing terms
15 15 ** and conditions see http://www.qt.io/terms-conditions. For further
16 16 ** information use the contact form at http://www.qt.io/contact-us.
17 17 **
18 18 ** $QT_END_LICENSE$
19 19 **
20 20 ******************************************************************************/
21 21 #include <private/chartpresenter_p.h>
22 22 #include <QtCharts/QChart>
23 23 #include <private/chartitem_p.h>
24 24 #include <private/qchart_p.h>
25 25 #include <QtCharts/QAbstractAxis>
26 26 #include <private/qabstractaxis_p.h>
27 27 #include <private/chartdataset_p.h>
28 28 #include <private/chartanimation_p.h>
29 29 #include <private/qabstractseries_p.h>
30 30 #include <QtCharts/QAreaSeries>
31 31 #include <private/chartaxiselement_p.h>
32 32 #include <private/chartbackground_p.h>
33 33 #include <private/cartesianchartlayout_p.h>
34 34 #include <private/polarchartlayout_p.h>
35 35 #include <private/charttitle_p.h>
36 36 #include <QtCore/QTimer>
37 37 #include <QtGui/QTextDocument>
38 38 #include <QtWidgets/QGraphicsScene>
39 39 #include <QtWidgets/QGraphicsView>
40 40
41 41 QT_CHARTS_BEGIN_NAMESPACE
42 42
43 43 ChartPresenter::ChartPresenter(QChart *chart, QChart::ChartType type)
44 44 : QObject(chart),
45 45 m_chart(chart),
46 46 m_options(QChart::NoAnimation),
47 47 m_animationDuration(ChartAnimationDuration),
48 48 m_animationCurve(QEasingCurve::OutQuart),
49 49 m_state(ShowState),
50 50 m_background(0),
51 51 m_plotAreaBackground(0),
52 52 m_title(0),
53 53 m_localizeNumbers(false)
54 54 #ifndef QT_NO_OPENGL
55 55 , m_glWidget(0)
56 56 , m_glUseWidget(true)
57 57 #endif
58 58 {
59 59 if (type == QChart::ChartTypeCartesian)
60 60 m_layout = new CartesianChartLayout(this);
61 61 else if (type == QChart::ChartTypePolar)
62 62 m_layout = new PolarChartLayout(this);
63 63 Q_ASSERT(m_layout);
64 64 }
65 65
66 66 ChartPresenter::~ChartPresenter()
67 67 {
68 68 #ifndef QT_NO_OPENGL
69 69 delete m_glWidget.data();
70 70 #endif
71 71 }
72 72
73 73 void ChartPresenter::setGeometry(const QRectF rect)
74 74 {
75 75 if (m_rect != rect) {
76 76 m_rect = rect;
77 77 foreach (ChartItem *chart, m_chartItems) {
78 78 chart->domain()->setSize(rect.size());
79 79 chart->setPos(rect.topLeft());
80 80 }
81 81 #ifndef QT_NO_OPENGL
82 82 if (!m_glWidget.isNull())
83 83 m_glWidget->setGeometry(m_rect.toRect());
84 84 #endif
85 85 emit plotAreaChanged(m_rect);
86 86 }
87 87 }
88 88
89 89 QRectF ChartPresenter::geometry() const
90 90 {
91 91 return m_rect;
92 92 }
93 93
94 94 void ChartPresenter::handleAxisAdded(QAbstractAxis *axis)
95 95 {
96 96 axis->d_ptr->initializeGraphics(rootItem());
97 97 axis->d_ptr->initializeAnimations(m_options, m_animationDuration, m_animationCurve);
98 98 ChartAxisElement *item = axis->d_ptr->axisItem();
99 99 item->setPresenter(this);
100 100 item->setThemeManager(m_chart->d_ptr->m_themeManager);
101 101 m_axisItems<<item;
102 102 m_axes<<axis;
103 103 m_layout->invalidate();
104 104 }
105 105
106 106 void ChartPresenter::handleAxisRemoved(QAbstractAxis *axis)
107 107 {
108 108 ChartAxisElement *item = axis->d_ptr->m_item.take();
109 109 if (item->animation())
110 110 item->animation()->stopAndDestroyLater();
111 111 item->hide();
112 112 item->disconnect();
113 113 item->deleteLater();
114 114 m_axisItems.removeAll(item);
115 115 m_axes.removeAll(axis);
116 116 m_layout->invalidate();
117 117 }
118 118
119 119
120 120 void ChartPresenter::handleSeriesAdded(QAbstractSeries *series)
121 121 {
122 122 series->d_ptr->initializeGraphics(rootItem());
123 123 series->d_ptr->initializeAnimations(m_options, m_animationDuration, m_animationCurve);
124 124 series->d_ptr->setPresenter(this);
125 125 ChartItem *chart = series->d_ptr->chartItem();
126 126 chart->setPresenter(this);
127 127 chart->setThemeManager(m_chart->d_ptr->m_themeManager);
128 128 chart->setDataSet(m_chart->d_ptr->m_dataset);
129 129 chart->domain()->setSize(m_rect.size());
130 130 chart->setPos(m_rect.topLeft());
131 131 chart->handleDomainUpdated(); //this could be moved to intializeGraphics when animator is refactored
132 132 m_chartItems<<chart;
133 133 m_series<<series;
134 134 m_layout->invalidate();
135 135 }
136 136
137 137 void ChartPresenter::handleSeriesRemoved(QAbstractSeries *series)
138 138 {
139 139 ChartItem *chart = series->d_ptr->m_item.take();
140 140 chart->hide();
141 141 chart->disconnect();
142 142 chart->deleteLater();
143 143 if (chart->animation())
144 144 chart->animation()->stopAndDestroyLater();
145 145 m_chartItems.removeAll(chart);
146 146 m_series.removeAll(series);
147 147 m_layout->invalidate();
148 148 }
149 149
150 150 void ChartPresenter::setAnimationOptions(QChart::AnimationOptions options)
151 151 {
152 152 if (m_options != options) {
153 153 QChart::AnimationOptions oldOptions = m_options;
154 154 m_options = options;
155 155 if (options.testFlag(QChart::SeriesAnimations) != oldOptions.testFlag(QChart::SeriesAnimations)) {
156 156 foreach (QAbstractSeries *series, m_series)
157 157 series->d_ptr->initializeAnimations(m_options, m_animationDuration,
158 158 m_animationCurve);
159 159 }
160 160 if (options.testFlag(QChart::GridAxisAnimations) != oldOptions.testFlag(QChart::GridAxisAnimations)) {
161 161 foreach (QAbstractAxis *axis, m_axes)
162 162 axis->d_ptr->initializeAnimations(m_options, m_animationDuration, m_animationCurve);
163 163 }
164 164 m_layout->invalidate(); // So that existing animations don't just stop halfway
165 165 }
166 166 }
167 167
168 168 void ChartPresenter::setAnimationDuration(int msecs)
169 169 {
170 170 if (m_animationDuration != msecs) {
171 171 m_animationDuration = msecs;
172 172 foreach (QAbstractSeries *series, m_series)
173 173 series->d_ptr->initializeAnimations(m_options, m_animationDuration, m_animationCurve);
174 174 foreach (QAbstractAxis *axis, m_axes)
175 175 axis->d_ptr->initializeAnimations(m_options, m_animationDuration, m_animationCurve);
176 176 m_layout->invalidate(); // So that existing animations don't just stop halfway
177 177 }
178 178 }
179 179
180 180 void ChartPresenter::setAnimationEasingCurve(const QEasingCurve &curve)
181 181 {
182 182 if (m_animationCurve != curve) {
183 183 m_animationCurve = curve;
184 184 foreach (QAbstractSeries *series, m_series)
185 185 series->d_ptr->initializeAnimations(m_options, m_animationDuration, m_animationCurve);
186 186 foreach (QAbstractAxis *axis, m_axes)
187 187 axis->d_ptr->initializeAnimations(m_options, m_animationDuration, m_animationCurve);
188 188 m_layout->invalidate(); // So that existing animations don't just stop halfway
189 189 }
190 190 }
191 191
192 192 void ChartPresenter::setState(State state,QPointF point)
193 193 {
194 194 m_state=state;
195 195 m_statePoint=point;
196 196 }
197 197
198 198 QChart::AnimationOptions ChartPresenter::animationOptions() const
199 199 {
200 200 return m_options;
201 201 }
202 202
203 203 void ChartPresenter::createBackgroundItem()
204 204 {
205 205 if (!m_background) {
206 206 m_background = new ChartBackground(rootItem());
207 207 m_background->setPen(Qt::NoPen); // Theme doesn't touch pen so don't use default
208 208 m_background->setBrush(QChartPrivate::defaultBrush());
209 209 m_background->setZValue(ChartPresenter::BackgroundZValue);
210 210 }
211 211 }
212 212
213 213 void ChartPresenter::createPlotAreaBackgroundItem()
214 214 {
215 215 if (!m_plotAreaBackground) {
216 216 if (m_chart->chartType() == QChart::ChartTypeCartesian)
217 217 m_plotAreaBackground = new QGraphicsRectItem(rootItem());
218 218 else
219 219 m_plotAreaBackground = new QGraphicsEllipseItem(rootItem());
220 220 // Use transparent pen instead of Qt::NoPen, as Qt::NoPen causes
221 221 // antialising artifacts with axis lines for some reason.
222 222 m_plotAreaBackground->setPen(QPen(Qt::transparent));
223 223 m_plotAreaBackground->setBrush(Qt::NoBrush);
224 224 m_plotAreaBackground->setZValue(ChartPresenter::PlotAreaZValue);
225 225 m_plotAreaBackground->setVisible(false);
226 226 }
227 227 }
228 228
229 229 void ChartPresenter::createTitleItem()
230 230 {
231 231 if (!m_title) {
232 232 m_title = new ChartTitle(rootItem());
233 233 m_title->setZValue(ChartPresenter::BackgroundZValue);
234 234 }
235 235 }
236 236
237 237 void ChartPresenter::startAnimation(ChartAnimation *animation)
238 238 {
239 239 animation->stop();
240 240 QTimer::singleShot(0, animation, SLOT(startChartAnimation()));
241 241 }
242 242
243 243 void ChartPresenter::setBackgroundBrush(const QBrush &brush)
244 244 {
245 245 createBackgroundItem();
246 246 m_background->setBrush(brush);
247 247 m_layout->invalidate();
248 248 }
249 249
250 250 QBrush ChartPresenter::backgroundBrush() const
251 251 {
252 252 if (!m_background)
253 253 return QBrush();
254 254 return m_background->brush();
255 255 }
256 256
257 257 void ChartPresenter::setBackgroundPen(const QPen &pen)
258 258 {
259 259 createBackgroundItem();
260 260 m_background->setPen(pen);
261 261 m_layout->invalidate();
262 262 }
263 263
264 264 QPen ChartPresenter::backgroundPen() const
265 265 {
266 266 if (!m_background)
267 267 return QPen();
268 268 return m_background->pen();
269 269 }
270 270
271 271 void ChartPresenter::setBackgroundRoundness(qreal diameter)
272 272 {
273 273 createBackgroundItem();
274 274 m_background->setDiameter(diameter);
275 275 m_layout->invalidate();
276 276 }
277 277
278 278 qreal ChartPresenter::backgroundRoundness() const
279 279 {
280 280 if (!m_background)
281 281 return 0;
282 282 return m_background->diameter();
283 283 }
284 284
285 285 void ChartPresenter::setPlotAreaBackgroundBrush(const QBrush &brush)
286 286 {
287 287 createPlotAreaBackgroundItem();
288 288 m_plotAreaBackground->setBrush(brush);
289 289 m_layout->invalidate();
290 290 }
291 291
292 292 QBrush ChartPresenter::plotAreaBackgroundBrush() const
293 293 {
294 294 if (!m_plotAreaBackground)
295 295 return QBrush();
296 296 return m_plotAreaBackground->brush();
297 297 }
298 298
299 299 void ChartPresenter::setPlotAreaBackgroundPen(const QPen &pen)
300 300 {
301 301 createPlotAreaBackgroundItem();
302 302 m_plotAreaBackground->setPen(pen);
303 303 m_layout->invalidate();
304 304 }
305 305
306 306 QPen ChartPresenter::plotAreaBackgroundPen() const
307 307 {
308 308 if (!m_plotAreaBackground)
309 309 return QPen();
310 310 return m_plotAreaBackground->pen();
311 311 }
312 312
313 313 void ChartPresenter::setTitle(const QString &title)
314 314 {
315 315 createTitleItem();
316 316 m_title->setText(title);
317 317 m_layout->invalidate();
318 318 }
319 319
320 320 QString ChartPresenter::title() const
321 321 {
322 322 if (!m_title)
323 323 return QString();
324 324 return m_title->text();
325 325 }
326 326
327 327 void ChartPresenter::setTitleFont(const QFont &font)
328 328 {
329 329 createTitleItem();
330 330 m_title->setFont(font);
331 331 m_layout->invalidate();
332 332 }
333 333
334 334 QFont ChartPresenter::titleFont() const
335 335 {
336 336 if (!m_title)
337 337 return QFont();
338 338 return m_title->font();
339 339 }
340 340
341 341 void ChartPresenter::setTitleBrush(const QBrush &brush)
342 342 {
343 343 createTitleItem();
344 344 m_title->setDefaultTextColor(brush.color());
345 345 m_layout->invalidate();
346 346 }
347 347
348 348 QBrush ChartPresenter::titleBrush() const
349 349 {
350 350 if (!m_title)
351 351 return QBrush();
352 352 return QBrush(m_title->defaultTextColor());
353 353 }
354 354
355 355 void ChartPresenter::setBackgroundVisible(bool visible)
356 356 {
357 357 createBackgroundItem();
358 358 m_background->setVisible(visible);
359 359 }
360 360
361 361
362 362 bool ChartPresenter::isBackgroundVisible() const
363 363 {
364 364 if (!m_background)
365 365 return false;
366 366 return m_background->isVisible();
367 367 }
368 368
369 369 void ChartPresenter::setPlotAreaBackgroundVisible(bool visible)
370 370 {
371 371 createPlotAreaBackgroundItem();
372 372 m_plotAreaBackground->setVisible(visible);
373 373 }
374 374
375 375 bool ChartPresenter::isPlotAreaBackgroundVisible() const
376 376 {
377 377 if (!m_plotAreaBackground)
378 378 return false;
379 379 return m_plotAreaBackground->isVisible();
380 380 }
381 381
382 382 void ChartPresenter::setBackgroundDropShadowEnabled(bool enabled)
383 383 {
384 384 createBackgroundItem();
385 385 m_background->setDropShadowEnabled(enabled);
386 386 }
387 387
388 388 bool ChartPresenter::isBackgroundDropShadowEnabled() const
389 389 {
390 390 if (!m_background)
391 391 return false;
392 392 return m_background->isDropShadowEnabled();
393 393 }
394 394
395 395 void ChartPresenter::setLocalizeNumbers(bool localize)
396 396 {
397 397 m_localizeNumbers = localize;
398 398 m_layout->invalidate();
399 399 }
400 400
401 401 void ChartPresenter::setLocale(const QLocale &locale)
402 402 {
403 403 m_locale = locale;
404 404 m_layout->invalidate();
405 405 }
406 406
407 407 AbstractChartLayout *ChartPresenter::layout()
408 408 {
409 409 return m_layout;
410 410 }
411 411
412 412 QLegend *ChartPresenter::legend()
413 413 {
414 414 return m_chart->legend();
415 415 }
416 416
417 417 void ChartPresenter::setVisible(bool visible)
418 418 {
419 419 m_chart->setVisible(visible);
420 420 }
421 421
422 422 ChartBackground *ChartPresenter::backgroundElement()
423 423 {
424 424 return m_background;
425 425 }
426 426
427 427 QAbstractGraphicsShapeItem *ChartPresenter::plotAreaElement()
428 428 {
429 429 return m_plotAreaBackground;
430 430 }
431 431
432 432 QList<ChartAxisElement *> ChartPresenter::axisItems() const
433 433 {
434 434 return m_axisItems;
435 435 }
436 436
437 437 QList<ChartItem *> ChartPresenter::chartItems() const
438 438 {
439 439 return m_chartItems;
440 440 }
441 441
442 442 ChartTitle *ChartPresenter::titleElement()
443 443 {
444 444 return m_title;
445 445 }
446 446
447 447 QRectF ChartPresenter::textBoundingRect(const QFont &font, const QString &text, qreal angle)
448 448 {
449 449 static QGraphicsTextItem dummyTextItem;
450 450 static bool initMargin = true;
451 451 if (initMargin) {
452 452 dummyTextItem.document()->setDocumentMargin(textMargin());
453 453 initMargin = false;
454 454 }
455 455
456 456 dummyTextItem.setFont(font);
457 457 dummyTextItem.setHtml(text);
458 458 QRectF boundingRect = dummyTextItem.boundingRect();
459 459
460 460 // Take rotation into account
461 461 if (angle) {
462 462 QTransform transform;
463 463 transform.rotate(angle);
464 464 boundingRect = transform.mapRect(boundingRect);
465 465 }
466 466
467 467 return boundingRect;
468 468 }
469 469
470 470 // boundingRect parameter returns the rotated bounding rect of the text
471 471 QString ChartPresenter::truncatedText(const QFont &font, const QString &text, qreal angle,
472 472 qreal maxWidth, qreal maxHeight, QRectF &boundingRect)
473 473 {
474 474 QString truncatedString(text);
475 475 boundingRect = textBoundingRect(font, truncatedString, angle);
476 476 if (boundingRect.width() > maxWidth || boundingRect.height() > maxHeight) {
477 477 // It can be assumed that almost any amount of string manipulation is faster
478 478 // than calculating one bounding rectangle, so first prepare a list of truncated strings
479 479 // to try.
480 480 static QRegExp truncateMatcher(QStringLiteral("&#?[0-9a-zA-Z]*;$"));
481 481
482 482 QVector<QString> testStrings(text.length());
483 483 int count(0);
484 484 static QLatin1Char closeTag('>');
485 485 static QLatin1Char openTag('<');
486 486 static QLatin1Char semiColon(';');
487 487 static QLatin1String ellipsis("...");
488 488 while (truncatedString.length() > 1) {
489 489 int chopIndex(-1);
490 490 int chopCount(1);
491 491 QChar lastChar(truncatedString.at(truncatedString.length() - 1));
492 492
493 493 if (lastChar == closeTag)
494 494 chopIndex = truncatedString.lastIndexOf(openTag);
495 495 else if (lastChar == semiColon)
496 496 chopIndex = truncateMatcher.indexIn(truncatedString, 0);
497 497
498 498 if (chopIndex != -1)
499 499 chopCount = truncatedString.length() - chopIndex;
500 500 truncatedString.chop(chopCount);
501 501 testStrings[count] = truncatedString + ellipsis;
502 502 count++;
503 503 }
504 504
505 505 // Binary search for best fit
506 506 int minIndex(0);
507 507 int maxIndex(count - 1);
508 508 int bestIndex(count);
509 509 QRectF checkRect;
510 510
511 511 while (maxIndex >= minIndex) {
512 512 int mid = (maxIndex + minIndex) / 2;
513 513 checkRect = textBoundingRect(font, testStrings.at(mid), angle);
514 514 if (checkRect.width() > maxWidth || checkRect.height() > maxHeight) {
515 515 // Checked index too large, all under this are also too large
516 516 minIndex = mid + 1;
517 517 } else {
518 518 // Checked index fits, all over this also fit
519 519 maxIndex = mid - 1;
520 520 bestIndex = mid;
521 521 boundingRect = checkRect;
522 522 }
523 523 }
524 524 // Default to "..." if nothing fits
525 525 if (bestIndex == count) {
526 526 boundingRect = textBoundingRect(font, ellipsis, angle);
527 527 truncatedString = ellipsis;
528 528 } else {
529 529 truncatedString = testStrings.at(bestIndex);
530 530 }
531 531 }
532 532
533 533 return truncatedString;
534 534 }
535 535
536 536 QString ChartPresenter::numberToString(double value, char f, int prec)
537 537 {
538 538 if (m_localizeNumbers)
539 539 return m_locale.toString(value, f, prec);
540 540 else
541 541 return QString::number(value, f, prec);
542 542 }
543 543
544 544 QString ChartPresenter::numberToString(int value)
545 545 {
546 546 if (m_localizeNumbers)
547 547 return m_locale.toString(value);
548 548 else
549 549 return QString::number(value);
550 550 }
551 551
552 void ChartPresenter::ensureGLWidget()
552 void ChartPresenter::updateGLWidget()
553 553 {
554 554 #ifndef QT_NO_OPENGL
555 555 // GLWidget pointer is wrapped in QPointer as its parent is not in our control, and therefore
556 556 // can potentially get deleted unexpectedly.
557 557 if (m_glWidget.isNull() && m_glUseWidget && m_chart->scene()) {
558 558 // Find the view of the scene. If the scene has multiple views, only the first view is
559 559 // chosen.
560 560 QList<QGraphicsView *> views = m_chart->scene()->views();
561 561 if (views.size()) {
562 562 QGraphicsView *firstView = views.at(0);
563 563 m_glWidget = new GLWidget(m_chart->d_ptr->m_dataset->glXYSeriesDataManager(),
564 564 firstView);
565 565 m_glWidget->setGeometry(m_rect.toRect());
566 566 m_glWidget->show();
567 567 }
568 568 }
569 // Make sure we update the widget in a timely manner
570 if (!m_glWidget.isNull())
571 m_glWidget->update();
569 572 #endif
570 573 }
571 574
572 575 #include "moc_chartpresenter_p.cpp"
573 576
574 577 QT_CHARTS_END_NAMESPACE
@@ -1,212 +1,212
1 1 /******************************************************************************
2 2 **
3 3 ** Copyright (C) 2015 The Qt Company Ltd.
4 4 ** Contact: http://www.qt.io/licensing/
5 5 **
6 6 ** This file is part of the Qt Charts module.
7 7 **
8 8 ** $QT_BEGIN_LICENSE:COMM$
9 9 **
10 10 ** Commercial License Usage
11 11 ** Licensees holding valid commercial Qt licenses may use this file in
12 12 ** accordance with the commercial license agreement provided with the
13 13 ** Software or, alternatively, in accordance with the terms contained in
14 14 ** a written agreement between you and The Qt Company. For licensing terms
15 15 ** and conditions see http://www.qt.io/terms-conditions. For further
16 16 ** information use the contact form at http://www.qt.io/contact-us.
17 17 **
18 18 ** $QT_END_LICENSE$
19 19 **
20 20 ******************************************************************************/
21 21
22 22 // W A R N I N G
23 23 // -------------
24 24 //
25 25 // This file is not part of the Qt Chart API. It exists purely as an
26 26 // implementation detail. This header file may change from version to
27 27 // version without notice, or even be removed.
28 28 //
29 29 // We mean it.
30 30
31 31 #ifndef CHARTPRESENTER_H
32 32 #define CHARTPRESENTER_H
33 33
34 34 #include <QtCharts/QChartGlobal>
35 35 #include <QtCharts/QChart> //because of QChart::ChartThemeId
36 36 #include <private/glwidget_p.h>
37 37 #include <QtCore/QRectF>
38 38 #include <QtCore/QMargins>
39 39 #include <QtCore/QLocale>
40 40 #include <QtCore/QPointer>
41 41 #include <QtCore/QEasingCurve>
42 42
43 43 QT_CHARTS_BEGIN_NAMESPACE
44 44
45 45 class ChartItem;
46 46 class AxisItem;
47 47 class QAbstractSeries;
48 48 class ChartDataSet;
49 49 class AbstractDomain;
50 50 class ChartAxisElement;
51 51 class ChartAnimator;
52 52 class ChartBackground;
53 53 class ChartTitle;
54 54 class ChartAnimation;
55 55 class AbstractChartLayout;
56 56
57 57 class ChartPresenter: public QObject
58 58 {
59 59 Q_OBJECT
60 60 public:
61 61 enum ZValues {
62 62 BackgroundZValue = -1,
63 63 PlotAreaZValue,
64 64 ShadesZValue,
65 65 GridZValue,
66 66 AxisZValue,
67 67 SeriesZValue,
68 68 LineChartZValue = SeriesZValue,
69 69 SplineChartZValue = SeriesZValue,
70 70 BarSeriesZValue = SeriesZValue,
71 71 ScatterSeriesZValue = SeriesZValue,
72 72 PieSeriesZValue = SeriesZValue,
73 73 BoxPlotSeriesZValue = SeriesZValue,
74 74 LegendZValue,
75 75 TopMostZValue
76 76 };
77 77
78 78 enum State {
79 79 ShowState,
80 80 ScrollUpState,
81 81 ScrollDownState,
82 82 ScrollLeftState,
83 83 ScrollRightState,
84 84 ZoomInState,
85 85 ZoomOutState
86 86 };
87 87
88 88 ChartPresenter(QChart *chart, QChart::ChartType type);
89 89 virtual ~ChartPresenter();
90 90
91 91
92 92 void setGeometry(QRectF rect);
93 93 QRectF geometry() const;
94 94
95 95 QGraphicsItem *rootItem(){ return m_chart; }
96 96 ChartBackground *backgroundElement();
97 97 QAbstractGraphicsShapeItem *plotAreaElement();
98 98 ChartTitle *titleElement();
99 99 QList<ChartAxisElement *> axisItems() const;
100 100 QList<ChartItem *> chartItems() const;
101 101
102 102 QLegend *legend();
103 103
104 104 void setBackgroundBrush(const QBrush &brush);
105 105 QBrush backgroundBrush() const;
106 106
107 107 void setBackgroundPen(const QPen &pen);
108 108 QPen backgroundPen() const;
109 109
110 110 void setBackgroundRoundness(qreal diameter);
111 111 qreal backgroundRoundness() const;
112 112
113 113 void setPlotAreaBackgroundBrush(const QBrush &brush);
114 114 QBrush plotAreaBackgroundBrush() const;
115 115
116 116 void setPlotAreaBackgroundPen(const QPen &pen);
117 117 QPen plotAreaBackgroundPen() const;
118 118
119 119 void setTitle(const QString &title);
120 120 QString title() const;
121 121
122 122 void setTitleFont(const QFont &font);
123 123 QFont titleFont() const;
124 124
125 125 void setTitleBrush(const QBrush &brush);
126 126 QBrush titleBrush() const;
127 127
128 128 void setBackgroundVisible(bool visible);
129 129 bool isBackgroundVisible() const;
130 130
131 131 void setPlotAreaBackgroundVisible(bool visible);
132 132 bool isPlotAreaBackgroundVisible() const;
133 133
134 134 void setBackgroundDropShadowEnabled(bool enabled);
135 135 bool isBackgroundDropShadowEnabled() const;
136 136
137 137 void setLocalizeNumbers(bool localize);
138 138 inline bool localizeNumbers() const { return m_localizeNumbers; }
139 139 void setLocale(const QLocale &locale);
140 140 inline const QLocale &locale() const { return m_locale; }
141 141
142 142 void setVisible(bool visible);
143 143
144 144 void setAnimationOptions(QChart::AnimationOptions options);
145 145 QChart::AnimationOptions animationOptions() const;
146 146 void setAnimationDuration(int msecs);
147 147 int animationDuration() const { return m_animationDuration; }
148 148 void setAnimationEasingCurve(const QEasingCurve &curve);
149 149 QEasingCurve animationEasingCurve() const { return m_animationCurve; }
150 150
151 151 void startAnimation(ChartAnimation *animation);
152 152
153 153 void setState(State state,QPointF point);
154 154 State state() const { return m_state; }
155 155 QPointF statePoint() const { return m_statePoint; }
156 156 AbstractChartLayout *layout();
157 157
158 158 QChart::ChartType chartType() const { return m_chart->chartType(); }
159 159 QChart *chart() { return m_chart; }
160 160
161 161 static QRectF textBoundingRect(const QFont &font, const QString &text, qreal angle = 0.0);
162 162 static QString truncatedText(const QFont &font, const QString &text, qreal angle,
163 163 qreal maxWidth, qreal maxHeight, QRectF &boundingRect);
164 164 inline static qreal textMargin() { return qreal(0.5); }
165 165
166 166 QString numberToString(double value, char f = 'g', int prec = 6);
167 167 QString numberToString(int value);
168 168
169 void ensureGLWidget();
169 void updateGLWidget();
170 170 void glSetUseWidget(bool enable) { m_glUseWidget = enable; }
171 171
172 172 private:
173 173 void createBackgroundItem();
174 174 void createPlotAreaBackgroundItem();
175 175 void createTitleItem();
176 176
177 177 public Q_SLOTS:
178 178 void handleSeriesAdded(QAbstractSeries *series);
179 179 void handleSeriesRemoved(QAbstractSeries *series);
180 180 void handleAxisAdded(QAbstractAxis *axis);
181 181 void handleAxisRemoved(QAbstractAxis *axis);
182 182
183 183 Q_SIGNALS:
184 184 void plotAreaChanged(const QRectF &plotArea);
185 185
186 186 private:
187 187 QChart *m_chart;
188 188 QList<ChartItem *> m_chartItems;
189 189 QList<ChartAxisElement *> m_axisItems;
190 190 QList<QAbstractSeries *> m_series;
191 191 QList<QAbstractAxis *> m_axes;
192 192 QChart::AnimationOptions m_options;
193 193 int m_animationDuration;
194 194 QEasingCurve m_animationCurve;
195 195 State m_state;
196 196 QPointF m_statePoint;
197 197 AbstractChartLayout *m_layout;
198 198 ChartBackground *m_background;
199 199 QAbstractGraphicsShapeItem *m_plotAreaBackground;
200 200 ChartTitle *m_title;
201 201 QRectF m_rect;
202 202 bool m_localizeNumbers;
203 203 QLocale m_locale;
204 204 #ifndef QT_NO_OPENGL
205 205 QPointer<GLWidget> m_glWidget;
206 206 #endif
207 207 bool m_glUseWidget;
208 208 };
209 209
210 210 QT_CHARTS_END_NAMESPACE
211 211
212 212 #endif /* CHARTPRESENTER_H */
@@ -1,238 +1,238
1 1 /******************************************************************************
2 2 **
3 3 ** Copyright (C) 2015 The Qt Company Ltd.
4 4 ** Contact: http://www.qt.io/licensing/
5 5 **
6 6 ** This file is part of the Qt Charts module.
7 7 **
8 8 ** $QT_BEGIN_LICENSE:COMM$
9 9 **
10 10 ** Commercial License Usage
11 11 ** Licensees holding valid commercial Qt licenses may use this file in
12 12 ** accordance with the commercial license agreement provided with the
13 13 ** Software or, alternatively, in accordance with the terms contained in
14 14 ** a written agreement between you and The Qt Company. For licensing terms
15 15 ** and conditions see http://www.qt.io/terms-conditions. For further
16 16 ** information use the contact form at http://www.qt.io/contact-us.
17 17 **
18 18 ** $QT_END_LICENSE$
19 19 **
20 20 ******************************************************************************/
21 21
22 22 #include <private/xychart_p.h>
23 23 #include <QtCharts/QXYSeries>
24 24 #include <private/qxyseries_p.h>
25 25 #include <private/chartpresenter_p.h>
26 26 #include <private/abstractdomain_p.h>
27 27 #include <private/chartdataset_p.h>
28 28 #include <private/glxyseriesdata_p.h>
29 29 #include <QtCharts/QXYModelMapper>
30 30 #include <private/qabstractaxis_p.h>
31 31 #include <QtGui/QPainter>
32 32 #include <QtCore/QAbstractItemModel>
33 33
34 34
35 35 QT_CHARTS_BEGIN_NAMESPACE
36 36
37 37 XYChart::XYChart(QXYSeries *series, QGraphicsItem *item):
38 38 ChartItem(series->d_func(),item),
39 39 m_series(series),
40 40 m_animation(0),
41 41 m_dirty(true)
42 42 {
43 43 QObject::connect(series, SIGNAL(pointReplaced(int)), this, SLOT(handlePointReplaced(int)));
44 44 QObject::connect(series, SIGNAL(pointsReplaced()), this, SLOT(handlePointsReplaced()));
45 45 QObject::connect(series, SIGNAL(pointAdded(int)), this, SLOT(handlePointAdded(int)));
46 46 QObject::connect(series, SIGNAL(pointRemoved(int)), this, SLOT(handlePointRemoved(int)));
47 47 QObject::connect(series, SIGNAL(pointsRemoved(int, int)), this, SLOT(handlePointsRemoved(int, int)));
48 48 QObject::connect(this, SIGNAL(clicked(QPointF)), series, SIGNAL(clicked(QPointF)));
49 49 QObject::connect(this, SIGNAL(hovered(QPointF,bool)), series, SIGNAL(hovered(QPointF,bool)));
50 50 QObject::connect(this, SIGNAL(pressed(QPointF)), series, SIGNAL(pressed(QPointF)));
51 51 QObject::connect(this, SIGNAL(released(QPointF)), series, SIGNAL(released(QPointF)));
52 52 QObject::connect(this, SIGNAL(doubleClicked(QPointF)), series, SIGNAL(doubleClicked(QPointF)));
53 53 }
54 54
55 55 void XYChart::setGeometryPoints(const QVector<QPointF> &points)
56 56 {
57 57 m_points = points;
58 58 }
59 59
60 60 void XYChart::setAnimation(XYAnimation *animation)
61 61 {
62 62 m_animation = animation;
63 63 }
64 64
65 65 void XYChart::setDirty(bool dirty)
66 66 {
67 67 m_dirty = dirty;
68 68 }
69 69
70 70 // Returns a vector with same size as geometryPoints vector, indicating
71 71 // the off grid status of points.
72 72 QVector<bool> XYChart::offGridStatusVector()
73 73 {
74 74 qreal minX = domain()->minX();
75 75 qreal maxX = domain()->maxX();
76 76 qreal minY = domain()->minY();
77 77 qreal maxY = domain()->maxY();
78 78
79 79 QVector<bool> returnVector;
80 80 returnVector.resize(m_points.size());
81 81 // During remove animation series may have different number of points,
82 82 // so ensure we don't go over the index. No need to check for zero points, this
83 83 // will not be called in such a situation.
84 84 const int seriesLastIndex = m_series->count() - 1;
85 85
86 86 for (int i = 0; i < m_points.size(); i++) {
87 87 const QPointF &seriesPoint = m_series->at(qMin(seriesLastIndex, i));
88 88 if (seriesPoint.x() < minX
89 89 || seriesPoint.x() > maxX
90 90 || seriesPoint.y() < minY
91 91 || seriesPoint.y() > maxY) {
92 92 returnVector[i] = true;
93 93 } else {
94 94 returnVector[i] = false;
95 95 }
96 96 }
97 97 return returnVector;
98 98 }
99 99
100 100 void XYChart::updateChart(QVector<QPointF> &oldPoints, QVector<QPointF> &newPoints, int index)
101 101 {
102 102
103 103 if (m_animation) {
104 104 m_animation->setup(oldPoints, newPoints, index);
105 105 m_points = newPoints;
106 106 setDirty(false);
107 107 presenter()->startAnimation(m_animation);
108 108 } else {
109 109 m_points = newPoints;
110 110 updateGeometry();
111 111 }
112 112 }
113 113
114 114 void XYChart::updateGlChart()
115 115 {
116 presenter()->ensureGLWidget();
117 116 dataSet()->glXYSeriesDataManager()->setPoints(m_series, domain());
117 presenter()->updateGLWidget();
118 118 updateGeometry();
119 119 }
120 120
121 121 //handlers
122 122
123 123 void XYChart::handlePointAdded(int index)
124 124 {
125 125 Q_ASSERT(index < m_series->count());
126 126 Q_ASSERT(index >= 0);
127 127
128 128 if (m_series->useOpenGL()) {
129 129 updateGlChart();
130 130 } else {
131 131 QVector<QPointF> points;
132 132 if (m_dirty || m_points.isEmpty()) {
133 133 points = domain()->calculateGeometryPoints(m_series->pointsVector());
134 134 } else {
135 135 points = m_points;
136 136 QPointF point = domain()->calculateGeometryPoint(m_series->pointsVector().at(index),
137 137 m_validData);
138 138 if (!m_validData)
139 139 m_points.clear();
140 140 else
141 141 points.insert(index, point);
142 142 }
143 143 updateChart(m_points, points, index);
144 144 }
145 145 }
146 146
147 147 void XYChart::handlePointRemoved(int index)
148 148 {
149 149 Q_ASSERT(index <= m_series->count());
150 150 Q_ASSERT(index >= 0);
151 151
152 152 if (m_series->useOpenGL()) {
153 153 updateGlChart();
154 154 } else {
155 155 QVector<QPointF> points;
156 156 if (m_dirty || m_points.isEmpty()) {
157 157 points = domain()->calculateGeometryPoints(m_series->pointsVector());
158 158 } else {
159 159 points = m_points;
160 160 points.remove(index);
161 161 }
162 162 updateChart(m_points, points, index);
163 163 }
164 164 }
165 165
166 166 void XYChart::handlePointsRemoved(int index, int count)
167 167 {
168 168 Q_ASSERT(index <= m_series->count());
169 169 Q_ASSERT(index >= 0);
170 170
171 171 if (m_series->useOpenGL()) {
172 172 updateGlChart();
173 173 } else {
174 174 QVector<QPointF> points;
175 175 if (m_dirty || m_points.isEmpty()) {
176 176 points = domain()->calculateGeometryPoints(m_series->pointsVector());
177 177 } else {
178 178 points = m_points;
179 179 points.remove(index, count);
180 180 }
181 181 updateChart(m_points, points, index);
182 182 }
183 183 }
184 184
185 185 void XYChart::handlePointReplaced(int index)
186 186 {
187 187 Q_ASSERT(index < m_series->count());
188 188 Q_ASSERT(index >= 0);
189 189
190 190 if (m_series->useOpenGL()) {
191 191 updateGlChart();
192 192 } else {
193 193 QVector<QPointF> points;
194 194 if (m_dirty || m_points.isEmpty()) {
195 195 points = domain()->calculateGeometryPoints(m_series->pointsVector());
196 196 } else {
197 197 QPointF point = domain()->calculateGeometryPoint(m_series->pointsVector().at(index),
198 198 m_validData);
199 199 if (!m_validData)
200 200 m_points.clear();
201 201 points = m_points;
202 202 if (m_validData)
203 203 points.replace(index, point);
204 204 }
205 205 updateChart(m_points, points, index);
206 206 }
207 207 }
208 208
209 209 void XYChart::handlePointsReplaced()
210 210 {
211 211 if (m_series->useOpenGL()) {
212 212 updateGlChart();
213 213 } else {
214 214 // All the points were replaced -> recalculate
215 215 QVector<QPointF> points = domain()->calculateGeometryPoints(m_series->pointsVector());
216 216 updateChart(m_points, points, -1);
217 217 }
218 218 }
219 219
220 220 void XYChart::handleDomainUpdated()
221 221 {
222 222 if (m_series->useOpenGL()) {
223 223 updateGlChart();
224 224 } else {
225 225 if (isEmpty()) return;
226 226 QVector<QPointF> points = domain()->calculateGeometryPoints(m_series->pointsVector());
227 227 updateChart(m_points, points);
228 228 }
229 229 }
230 230
231 231 bool XYChart::isEmpty()
232 232 {
233 233 return domain()->isEmpty() || m_series->points().isEmpty();
234 234 }
235 235
236 236 #include "moc_xychart_p.cpp"
237 237
238 238 QT_CHARTS_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now