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