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