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 <QtCharts/QPieSeries>
7#include <private/qpieseries_p.h>
8#include <QtCharts/QPieSlice>
9#include <private/qpieslice_p.h>
10#include <private/pieslicedata_p.h>
11#include <private/chartdataset_p.h>
12#include <private/charttheme_p.h>
13#include <QtCharts/QAbstractAxis>
14#include <private/pieanimation_p.h>
15#include <private/charthelpers_p.h>
16
17#include <QtCharts/QPieLegendMarker>
18
19QT_BEGIN_NAMESPACE
20
21/*!
22 \class QPieSeries
23 \inmodule QtCharts
24 \brief The QPieSeries class presents data in pie charts.
25
26 A pie series consists of slices that are defined as QPieSlice objects.
27 The slices can have any values as the QPieSeries object calculates
28 the percentage of a slice compared with the sum of all slices in the series
29 to determine the actual size of the slice in the chart.
30
31 Pie size and position on the chart are controlled by using relative values
32 that range from 0.0 to 1.0.
33 These relate to the actual chart rectangle.
34
35 By default, the pie is defined as a full pie. A partial pie can be created
36 by setting a starting angle and angle span for the series.
37 A full pie is 360 degrees, where 0 is at 12 a'clock.
38
39 See the \l {Charts with Widgets Gallery} to learn how to use QPieSeries.
40 \image examples_piechart.png
41 \image examples_donutchart.png
42
43 \sa QPieSlice, QChart
44*/
45/*!
46 \qmltype PieSeries
47 \nativetype QPieSeries
48 \inqmlmodule QtCharts
49
50 \inherits AbstractSeries
51
52 \brief Presents data in pie charts.
53
54 A pie series consists of slices that are defined using the PieSlice type.
55 The slices can have any values as the PieSeries type calculates
56 the percentage of a slice compared with the sum of all slices in the series
57 to determine the actual size of the slice in the chart.
58
59 Pie size and position on the chart are controlled by using relative values
60 that range from 0.0 to 1.0.
61 These relate to the actual chart rectangle.
62
63 By default, the pie is defined as a full pie. A partial pie can be created
64 by setting a starting angle and angle span for the series.
65 A full pie is 360 degrees, where 0 is at 12 a'clock.
66
67 The following QML example shows how to create a simple pie chart.
68
69 \snippet qmlchartsgallery/qml/PieChart.qml 1
70
71 \beginfloatleft
72 \image examples_qmlchart1.png
73 \endfloat
74 \clearfloat
75
76 \sa PieSlice, ChartView
77*/
78
79/*!
80 \property QPieSeries::horizontalPosition
81 \brief The horizontal position of the pie.
82
83 The value is relative to the chart rectangle, so that:
84
85 \list
86 \li 0.0 is the absolute left.
87 \li 1.0 is the absolute right.
88 \endlist
89 The default value is 0.5 (center).
90 \sa verticalPosition
91*/
92
93/*!
94 \qmlproperty real PieSeries::horizontalPosition
95
96 The horizontal position of the pie.
97
98 The value is relative to the chart rectangle, so that:
99
100 \list
101 \li 0.0 is the absolute left.
102 \li 1.0 is the absolute right.
103 \endlist
104 The default value is 0.5 (center).
105 \sa verticalPosition
106*/
107
108/*!
109 \property QPieSeries::verticalPosition
110 \brief The vertical position of the pie.
111
112 The value is relative to the chart rectangle, so that:
113
114 \list
115 \li 0.0 is the absolute top.
116 \li 1.0 is the absolute bottom.
117 \endlist
118 The default value is 0.5 (center).
119 \sa horizontalPosition
120*/
121
122/*!
123 \qmlproperty real PieSeries::verticalPosition
124
125 The vertical position of the pie.
126
127 The value is relative to the chart rectangle, so that:
128
129 \list
130 \li 0.0 is the absolute top.
131 \li 1.0 is the absolute bottom.
132 \endlist
133 The default value is 0.5 (center).
134 \sa horizontalPosition
135*/
136
137/*!
138 \property QPieSeries::size
139 \brief The pie size.
140
141 The value is relative to the chart rectangle, so that:
142
143 \list
144 \li 0.0 is the minimum size (pie not drawn).
145 \li 1.0 is the maximum size that can fit the chart.
146 \endlist
147
148 When setting this property, the holeSize property is adjusted if necessary,
149 to ensure that the hole size is not greater than the pie size.
150
151 The default value is 0.7.
152*/
153
154/*!
155 \qmlproperty real PieSeries::size
156
157 The pie size.
158
159 The value is relative to the chart rectangle, so that:
160
161 \list
162 \li 0.0 is the minimum size (pie not drawn).
163 \li 1.0 is the maximum size that can fit the chart.
164 \endlist
165
166 When setting this property, the holeSize property is adjusted if necessary,
167 to ensure that the hole size is not greater than the pie size.
168
169 The default value is 0.7.
170*/
171
172/*!
173 \property QPieSeries::holeSize
174 \brief The donut hole size.
175
176 The value is relative to the chart rectangle, so that:
177
178 \list
179 \li 0.0 is the minimum size (full pie drawn without a hole).
180 \li 1.0 is the maximum size that can fit the chart (the donut has no width).
181 \endlist
182
183 When setting this property, the \l size property is adjusted if necessary,
184 to ensure that the hole size is not greater than the pie size.
185
186 The default value is 0.0.
187*/
188
189/*!
190 \qmlproperty real PieSeries::holeSize
191
192 The donut hole size.
193
194 The value is relative to the chart rectangle, so that:
195
196 \list
197 \li 0.0 is the minimum size (full pie drawn without a hole).
198 \li 1.0 is the maximum size that can fit the chart (the donut has no width).
199 \endlist
200
201 When setting this property, the \l size property is adjusted if necessary,
202 to ensure that the hole size is not greater than the pie size.
203
204 The default value is 0.0.
205*/
206
207/*!
208 \property QPieSeries::startAngle
209 \brief The starting angle of the pie.
210
211 A full pie is 360 degrees, where 0 degrees is at 12 a'clock.
212
213 The default value is 0.
214*/
215
216/*!
217 \qmlproperty real PieSeries::startAngle
218
219 The starting angle of the pie.
220
221 A full pie is 360 degrees, where 0 degrees is at 12 a'clock.
222
223 The default value is 0.
224*/
225
226/*!
227 \property QPieSeries::endAngle
228 \brief The ending angle of the pie.
229
230 A full pie is 360 degrees, where 0 degrees is at 12 a'clock.
231
232 The default value is 360.
233*/
234
235/*!
236 \qmlproperty real PieSeries::endAngle
237
238 The ending angle of the pie.
239
240 A full pie is 360 degrees, where 0 degrees is at 12 a'clock.
241
242 The default value is 360.
243*/
244
245/*!
246 \property QPieSeries::count
247
248 \brief The number of slices in the series.
249*/
250
251/*!
252 \qmlproperty int PieSeries::count
253
254 The number of slices in the series.
255*/
256
257/*!
258 \fn void QPieSeries::countChanged()
259 This signal is emitted when the slice count changes.
260 \sa count
261*/
262
263/*!
264 \property QPieSeries::sum
265
266 \brief The sum of all slices.
267
268 The series keeps track of the sum of all the slices it holds.
269*/
270
271/*!
272 \qmlproperty real PieSeries::sum
273
274 The sum of all slices.
275
276 The series keeps track of the sum of all the slices it holds.
277*/
278
279/*!
280 \fn void QPieSeries::sumChanged()
281 This signal is emitted when the sum of all slices changes.
282 \sa sum
283*/
284
285/*!
286 \fn void QPieSeries::added(const QList<QPieSlice*> &slices)
287
288 This signal is emitted when the slices specified by \a slices are added to the series.
289
290 \sa append(), insert()
291*/
292/*!
293 \qmlsignal PieSeries::added(list<PieSlice> slices)
294 This signal is emitted when the slices specified by \a slices are added to the series.
295
296 The corresponding signal handler is \c onAdded.
297*/
298
299/*!
300 \fn void QPieSeries::removed(const QList<QPieSlice*> &slices)
301 This signal is emitted when the slices specified by \a slices are removed from the series.
302 \sa remove()
303*/
304/*!
305 \qmlsignal PieSeries::removed(list<PieSlice> slices)
306 This signal is emitted when the slices specified by \a slices are removed from the series.
307
308 The corresponding signal handler is \c onRemoved.
309*/
310
311/*!
312 \qmlsignal PieSeries::sliceAdded(PieSlice slice)
313 This signal is emitted when the slice specified by \a slice is added to the series.
314
315 The corresponding signal handler is \c onSliceAdded.
316*/
317
318/*!
319 \qmlsignal PieSeries::sliceRemoved(PieSlice slice)
320 This signal is emitted when the slice specified by \a slice is removed from the series.
321
322 The corresponding signal handler is \c onSliceRemoved.
323*/
324
325/*!
326 \fn void QPieSeries::clicked(QPieSlice *slice)
327 This signal is emitted when the slice specified by \a slice is clicked.
328 \sa QPieSlice::clicked()
329*/
330/*!
331 \qmlsignal PieSeries::clicked(PieSlice slice)
332 This signal is emitted when the slice specified by \a slice is clicked.
333
334 The corresponding signal handler is \c onClicked.
335*/
336
337/*!
338 \fn void QPieSeries::pressed(QPieSlice *slice)
339 This signal is emitted when the user clicks the slice specified by \a slice
340 and holds down the mouse button.
341 \sa QPieSlice::pressed()
342*/
343/*!
344 \qmlsignal PieSeries::pressed(PieSlice slice)
345 This signal is emitted when the user clicks the slice specified by \a slice
346 and holds down the mouse button.
347
348 The corresponding signal handler is \c onPressed.
349*/
350
351/*!
352 \fn void QPieSeries::released(QPieSlice *slice)
353 This signal is emitted when the user releases the mouse press on the slice
354 specified by \a slice.
355 \sa QPieSlice::released()
356*/
357/*!
358 \qmlsignal PieSeries::released(PieSlice slice)
359 This signal is emitted when the user releases the mouse press on the slice
360 specified by \a slice.
361
362 The corresponding signal handler is \c onReleased.
363*/
364
365/*!
366 \fn void QPieSeries::doubleClicked(QPieSlice *slice)
367 This signal is emitted when the slice specified by \a slice is double-clicked.
368 \sa QPieSlice::doubleClicked()
369*/
370/*!
371 \qmlsignal PieSeries::doubleClicked(PieSlice slice)
372 This signal is emitted when the slice specified by \a slice is double-clicked.
373
374 The corresponding signal handler is \c onDoubleClicked.
375*/
376
377/*!
378 \fn void QPieSeries::hovered(QPieSlice* slice, bool state)
379 This signal is emitted when a mouse is hovered over the slice specified by
380 \a slice. When the mouse moves over the slice, \a state turns \c true, and
381 when the mouse moves away again, it turns \c false.
382 \sa QPieSlice::hovered()
383*/
384/*!
385 \qmlsignal PieSeries::hovered(PieSlice slice, bool state)
386 This signal is emitted when a mouse is hovered over the slice specified by
387 \a slice. When the mouse moves over the slice, \a state turns \c true, and
388 when the mouse moves away again, it turns \c false.
389
390 The corresponding signal handler is \c onHovered.
391*/
392
393/*!
394 \qmlmethod PieSlice PieSeries::at(int index)
395 Returns the slice at the position specified by \a index. Returns null if the
396 index is not valid.
397*/
398
399/*!
400 \qmlmethod PieSlice PieSeries::find(string label)
401 Returns the first slice that has the label \a label. Returns null if the label
402 is not found.
403*/
404
405/*!
406 \qmlmethod PieSlice PieSeries::append(string label, real value)
407 Adds a new slice with the label \a label and the value \a value to the pie.
408*/
409
410/*!
411 \qmlmethod bool PieSeries::remove(PieSlice slice)
412 Removes the slice specified by \a slice from the pie. Returns \c true if the
413 removal was successful, \c false otherwise.
414*/
415
416/*!
417 \qmlmethod PieSeries::clear()
418 Removes all slices from the pie.
419*/
420
421/*!
422 Constructs a series object that is a child of \a parent.
423*/
424QPieSeries::QPieSeries(QObject *parent)
425 : QAbstractSeries(*new QPieSeriesPrivate(this), parent)
426{
427 Q_D(QPieSeries);
428 QObject::connect(sender: this, SIGNAL(countChanged()), receiver: d, SIGNAL(countChanged()));
429}
430
431/*!
432 Removes the pie series and its slices.
433*/
434QPieSeries::~QPieSeries()
435{
436 // NOTE: d_prt destroyed by QObject
437 clear();
438}
439
440/*!
441 \reimp
442
443 Returns the type of the series.
444*/
445QAbstractSeries::SeriesType QPieSeries::type() const
446{
447 return QAbstractSeries::SeriesTypePie;
448}
449
450/*!
451 Appends the slice specified by \a slice to the series.
452 Slice ownership is passed to the series.
453
454 Returns \c true if appending succeeds.
455*/
456bool QPieSeries::append(QPieSlice *slice)
457{
458 return append(slices: QList<QPieSlice *>() << slice);
459}
460
461/*!
462 Appends the array of slices specified by \a slices to the series.
463 Slice ownership is passed to the series.
464
465 Returns \c true if appending succeeds.
466*/
467bool QPieSeries::append(const QList<QPieSlice *> &slices)
468{
469 Q_D(QPieSeries);
470
471 if (slices.size() == 0)
472 return false;
473
474 for (auto *s : slices) {
475 if (!s || d->m_slices.contains(t: s))
476 return false;
477 if (s->series()) // already added to some series
478 return false;
479 if (!isValidValue(value: s->value()))
480 return false;
481 }
482
483 for (auto *s : slices) {
484 s->setParent(this);
485 QPieSlicePrivate::fromSlice(slice: s)->m_series = this;
486 d->m_slices << s;
487 }
488
489 d->updateDerivativeData();
490
491 for (auto *s : slices) {
492 connect(sender: s, SIGNAL(valueChanged()), receiver: d, SLOT(sliceValueChanged()));
493 connect(sender: s, SIGNAL(clicked()), receiver: d, SLOT(sliceClicked()));
494 connect(sender: s, SIGNAL(hovered(bool)), receiver: d, SLOT(sliceHovered(bool)));
495 connect(sender: s, SIGNAL(pressed()), receiver: d, SLOT(slicePressed()));
496 connect(sender: s, SIGNAL(released()), receiver: d, SLOT(sliceReleased()));
497 connect(sender: s, SIGNAL(doubleClicked()), receiver: d, SLOT(sliceDoubleClicked()));
498 }
499
500 emit added(slices);
501 emit countChanged();
502
503 return true;
504}
505
506/*!
507 Appends the slice specified by \a slice to the series and returns a reference to the series.
508 Slice ownership is passed to the series.
509*/
510QPieSeries &QPieSeries::operator << (QPieSlice *slice)
511{
512 append(slice);
513 return *this;
514}
515
516
517/*!
518 Appends a single slice with the specified \a value and \a label to the series.
519 Slice ownership is passed to the series.
520 Returns null if \a value is \c NaN, \c Inf, or \c -Inf and adds nothing to the
521 series.
522*/
523QPieSlice *QPieSeries::append(const QString &label, qreal value)
524{
525 if (isValidValue(value)) {
526 QPieSlice *slice = new QPieSlice(label, value);
527 append(slice);
528 return slice;
529 } else {
530 return 0;
531 }
532}
533
534/*!
535 Inserts the slice specified by \a slice to the series before the slice at
536 the position specified by \a index.
537 Slice ownership is passed to the series.
538
539 Returns \c true if inserting succeeds.
540*/
541bool QPieSeries::insert(int index, QPieSlice *slice)
542{
543 Q_D(QPieSeries);
544
545 if (index < 0 || index > d->m_slices.size())
546 return false;
547
548 if (!slice || d->m_slices.contains(t: slice))
549 return false;
550
551 if (slice->series()) // already added to some series
552 return false;
553
554 if (!isValidValue(value: slice->value()))
555 return false;
556
557 slice->setParent(this);
558 QPieSlicePrivate::fromSlice(slice)->m_series = this;
559 d->m_slices.insert(i: index, t: slice);
560
561 d->updateDerivativeData();
562
563 connect(sender: slice, SIGNAL(valueChanged()), receiver: d, SLOT(sliceValueChanged()));
564 connect(sender: slice, SIGNAL(clicked()), receiver: d, SLOT(sliceClicked()));
565 connect(sender: slice, SIGNAL(hovered(bool)), receiver: d, SLOT(sliceHovered(bool)));
566 connect(sender: slice, SIGNAL(pressed()), receiver: d, SLOT(slicePressed()));
567 connect(sender: slice, SIGNAL(released()), receiver: d, SLOT(sliceReleased()));
568 connect(sender: slice, SIGNAL(doubleClicked()), receiver: d, SLOT(sliceDoubleClicked()));
569
570 emit added(slices: QList<QPieSlice *>() << slice);
571 emit countChanged();
572
573 return true;
574}
575
576/*!
577 Removes a single slice, specified by \a slice, from the series and deletes it
578 permanently.
579
580 The pointer cannot be referenced after this call.
581
582 Returns \c true if the removal succeeds.
583*/
584bool QPieSeries::remove(QPieSlice *slice)
585{
586 Q_D(QPieSeries);
587
588 if (!d->m_slices.removeOne(t: slice))
589 return false;
590
591 d->updateDerivativeData();
592
593 emit removed(slices: QList<QPieSlice *>() << slice);
594 emit countChanged();
595
596 delete slice;
597 slice = 0;
598
599 return true;
600}
601
602/*!
603 Takes a single slice, specified by \a slice, from the series. Does not delete
604 the slice object.
605
606 \note The series remains the slice's parent object. You must set the
607 parent object to take full ownership.
608
609 Returns \c true if the take operation was successful.
610*/
611bool QPieSeries::take(QPieSlice *slice)
612{
613 Q_D(QPieSeries);
614
615 if (!d->m_slices.removeOne(t: slice))
616 return false;
617
618 QPieSlicePrivate::fromSlice(slice)->m_series = 0;
619 slice->disconnect(receiver: d);
620
621 d->updateDerivativeData();
622
623 emit removed(slices: QList<QPieSlice *>() << slice);
624 emit countChanged();
625
626 return true;
627}
628
629/*!
630 Clears all slices from the series.
631*/
632void QPieSeries::clear()
633{
634 Q_D(QPieSeries);
635 if (d->m_slices.size() == 0)
636 return;
637
638 QList<QPieSlice *> slices = d->m_slices;
639 foreach (QPieSlice *s, d->m_slices)
640 d->m_slices.removeOne(t: s);
641
642 d->updateDerivativeData();
643
644 emit removed(slices);
645 emit countChanged();
646
647 foreach (QPieSlice *s, slices)
648 delete s;
649}
650
651/*!
652 Returns a list of slices that belong to this series.
653*/
654QList<QPieSlice *> QPieSeries::slices() const
655{
656 Q_D(const QPieSeries);
657 return d->m_slices;
658}
659
660/*!
661 Returns the number of the slices in this series.
662*/
663int QPieSeries::count() const
664{
665 Q_D(const QPieSeries);
666 return d->m_slices.size();
667}
668
669/*!
670 Returns \c true if the series is empty.
671*/
672bool QPieSeries::isEmpty() const
673{
674 Q_D(const QPieSeries);
675 return d->m_slices.isEmpty();
676}
677
678/*!
679 Returns the sum of all slice values in this series.
680
681 \sa QPieSlice::value(), QPieSlice::setValue(), QPieSlice::percentage()
682*/
683qreal QPieSeries::sum() const
684{
685 Q_D(const QPieSeries);
686 return d->m_sum;
687}
688
689void QPieSeries::setHoleSize(qreal holeSize)
690{
691 Q_D(QPieSeries);
692 holeSize = qBound(min: (qreal)0.0, val: holeSize, max: (qreal)1.0);
693 d->setSizes(innerSize: holeSize, outerSize: qMax(a: d->m_pieRelativeSize, b: holeSize));
694}
695
696qreal QPieSeries::holeSize() const
697{
698 Q_D(const QPieSeries);
699 return d->m_holeRelativeSize;
700}
701
702void QPieSeries::setHorizontalPosition(qreal relativePosition)
703{
704 Q_D(QPieSeries);
705
706 if (relativePosition < 0.0)
707 relativePosition = 0.0;
708 if (relativePosition > 1.0)
709 relativePosition = 1.0;
710
711 if (!qFuzzyCompare(p1: d->m_pieRelativeHorPos, p2: relativePosition)) {
712 d->m_pieRelativeHorPos = relativePosition;
713 emit d->horizontalPositionChanged();
714 }
715}
716
717qreal QPieSeries::horizontalPosition() const
718{
719 Q_D(const QPieSeries);
720 return d->m_pieRelativeHorPos;
721}
722
723void QPieSeries::setVerticalPosition(qreal relativePosition)
724{
725 Q_D(QPieSeries);
726
727 if (relativePosition < 0.0)
728 relativePosition = 0.0;
729 if (relativePosition > 1.0)
730 relativePosition = 1.0;
731
732 if (!qFuzzyCompare(p1: d->m_pieRelativeVerPos, p2: relativePosition)) {
733 d->m_pieRelativeVerPos = relativePosition;
734 emit d->verticalPositionChanged();
735 }
736}
737
738qreal QPieSeries::verticalPosition() const
739{
740 Q_D(const QPieSeries);
741 return d->m_pieRelativeVerPos;
742}
743
744void QPieSeries::setPieSize(qreal relativeSize)
745{
746 Q_D(QPieSeries);
747 relativeSize = qBound(min: (qreal)0.0, val: relativeSize, max: (qreal)1.0);
748 d->setSizes(innerSize: qMin(a: d->m_holeRelativeSize, b: relativeSize), outerSize: relativeSize);
749
750}
751
752qreal QPieSeries::pieSize() const
753{
754 Q_D(const QPieSeries);
755 return d->m_pieRelativeSize;
756}
757
758
759void QPieSeries::setPieStartAngle(qreal angle)
760{
761 Q_D(QPieSeries);
762 if (qFuzzyCompare(p1: d->m_pieStartAngle, p2: angle))
763 return;
764 d->m_pieStartAngle = angle;
765 d->updateDerivativeData();
766 emit d->pieStartAngleChanged();
767}
768
769qreal QPieSeries::pieStartAngle() const
770{
771 Q_D(const QPieSeries);
772 return d->m_pieStartAngle;
773}
774
775/*!
776 Sets the end angle of the pie.
777
778 A full pie is 360 degrees, where 0 degrees is at 12 a'clock.
779
780 \a angle must be greater than the start angle.
781
782 \sa pieEndAngle(), pieStartAngle(), setPieStartAngle()
783*/
784void QPieSeries::setPieEndAngle(qreal angle)
785{
786 Q_D(QPieSeries);
787 if (qFuzzyCompare(p1: d->m_pieEndAngle, p2: angle))
788 return;
789 d->m_pieEndAngle = angle;
790 d->updateDerivativeData();
791 emit d->pieEndAngleChanged();
792}
793
794/*!
795 Returns the end angle of the pie.
796
797 A full pie is 360 degrees, where 0 degrees is at 12 a'clock.
798
799 \sa setPieEndAngle(), pieStartAngle(), setPieStartAngle()
800*/
801qreal QPieSeries::pieEndAngle() const
802{
803 Q_D(const QPieSeries);
804 return d->m_pieEndAngle;
805}
806
807/*!
808 Sets the visibility of all slice labels to \a visible.
809
810 \note This function affects only the current slices in the series.
811 If a new slice is added, the default label visibility is \c false.
812
813 \sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible()
814*/
815void QPieSeries::setLabelsVisible(bool visible)
816{
817 Q_D(QPieSeries);
818 foreach (QPieSlice *s, d->m_slices)
819 s->setLabelVisible(visible);
820}
821
822/*!
823 Sets the position of all the slice labels to \a position.
824
825 \note This function affects only the current slices in the series.
826 If a new slice is added, the default label position is QPieSlice::LabelOutside.
827
828 \sa QPieSlice::labelPosition(), QPieSlice::setLabelPosition()
829*/
830void QPieSeries::setLabelsPosition(QPieSlice::LabelPosition position)
831{
832 Q_D(QPieSeries);
833 foreach (QPieSlice *s, d->m_slices)
834 s->setLabelPosition(position);
835}
836
837///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
838
839
840QPieSeriesPrivate::QPieSeriesPrivate(QPieSeries *parent) :
841 QAbstractSeriesPrivate(parent),
842 m_pieRelativeHorPos(0.5),
843 m_pieRelativeVerPos(0.5),
844 m_pieRelativeSize(0.7),
845 m_pieStartAngle(0),
846 m_pieEndAngle(360),
847 m_sum(0),
848 m_holeRelativeSize(0.0)
849{
850}
851
852QPieSeriesPrivate::~QPieSeriesPrivate()
853{
854}
855
856void QPieSeriesPrivate::updateDerivativeData()
857{
858 // calculate sum of all slices
859 qreal sum = 0;
860 foreach (QPieSlice *s, m_slices)
861 sum += s->value();
862
863 if (!qFuzzyCompare(p1: m_sum, p2: sum)) {
864 m_sum = sum;
865 emit q_func()->sumChanged();
866 }
867
868 // nothing to show..
869 if (qFuzzyCompare(p1: m_sum, p2: 0))
870 return;
871
872 // update slice attributes
873 qreal sliceAngle = m_pieStartAngle;
874 qreal pieSpan = m_pieEndAngle - m_pieStartAngle;
875 QList<QPieSlice *> changed;
876 foreach (QPieSlice *s, m_slices) {
877 QPieSlicePrivate *d = QPieSlicePrivate::fromSlice(slice: s);
878 d->setPercentage(s->value() / m_sum);
879 d->setStartAngle(sliceAngle);
880 d->setAngleSpan(pieSpan * s->percentage());
881 sliceAngle += s->angleSpan();
882 }
883
884
885 emit calculatedDataChanged();
886}
887
888void QPieSeriesPrivate::setSizes(qreal innerSize, qreal outerSize)
889{
890 bool changed = false;
891
892 if (!qFuzzyCompare(p1: m_holeRelativeSize, p2: innerSize)) {
893 m_holeRelativeSize = innerSize;
894 changed = true;
895 }
896
897 if (!qFuzzyCompare(p1: m_pieRelativeSize, p2: outerSize)) {
898 m_pieRelativeSize = outerSize;
899 changed = true;
900 }
901
902 if (changed)
903 emit pieSizeChanged();
904}
905
906QPieSeriesPrivate *QPieSeriesPrivate::fromSeries(QPieSeries *series)
907{
908 return series->d_func();
909}
910
911void QPieSeriesPrivate::sliceValueChanged()
912{
913 Q_ASSERT(m_slices.contains(qobject_cast<QPieSlice *>(sender())));
914 updateDerivativeData();
915}
916
917void QPieSeriesPrivate::sliceClicked()
918{
919 QPieSlice *slice = qobject_cast<QPieSlice *>(object: sender());
920 Q_ASSERT(m_slices.contains(slice));
921 Q_Q(QPieSeries);
922 emit q->clicked(slice);
923}
924
925void QPieSeriesPrivate::sliceHovered(bool state)
926{
927 QPieSlice *slice = qobject_cast<QPieSlice *>(object: sender());
928 if (!m_slices.isEmpty()) {
929 Q_ASSERT(m_slices.contains(slice));
930 Q_Q(QPieSeries);
931 emit q->hovered(slice, state);
932 }
933}
934
935void QPieSeriesPrivate::slicePressed()
936{
937 QPieSlice *slice = qobject_cast<QPieSlice *>(object: sender());
938 Q_ASSERT(m_slices.contains(slice));
939 Q_Q(QPieSeries);
940 emit q->pressed(slice);
941}
942
943void QPieSeriesPrivate::sliceReleased()
944{
945 QPieSlice *slice = qobject_cast<QPieSlice *>(object: sender());
946 Q_ASSERT(m_slices.contains(slice));
947 Q_Q(QPieSeries);
948 emit q->released(slice);
949}
950
951void QPieSeriesPrivate::sliceDoubleClicked()
952{
953 QPieSlice *slice = qobject_cast<QPieSlice *>(object: sender());
954 Q_ASSERT(m_slices.contains(slice));
955 Q_Q(QPieSeries);
956 emit q->doubleClicked(slice);
957}
958
959void QPieSeriesPrivate::initializeDomain()
960{
961 // does not apply to pie
962}
963
964void QPieSeriesPrivate::initializeGraphics(QGraphicsItem* parent)
965{
966 Q_Q(QPieSeries);
967 PieChartItem *pie = new PieChartItem(q,parent);
968 m_item.reset(p: pie);
969 QAbstractSeriesPrivate::initializeGraphics(parent);
970}
971
972void QPieSeriesPrivate::initializeAnimations(QChart::AnimationOptions options,
973 int duration, QEasingCurve &curve)
974{
975 PieChartItem *item = static_cast<PieChartItem *>(m_item.get());
976 Q_ASSERT(item);
977 if (item->animation())
978 item->animation()->stopAndDestroyLater();
979
980 if (options.testFlag(flag: QChart::SeriesAnimations))
981 item->setAnimation(new PieAnimation(item, duration, curve));
982 else
983 item->setAnimation(0);
984 QAbstractSeriesPrivate::initializeAnimations(options, duration, curve);
985}
986
987QList<QLegendMarker*> QPieSeriesPrivate::createLegendMarkers(QLegend* legend)
988{
989 Q_Q(QPieSeries);
990 QList<QLegendMarker*> markers;
991 const auto slices = q->slices();
992 for (QPieSlice *slice : slices) {
993 QPieLegendMarker* marker = new QPieLegendMarker(q,slice,legend);
994 markers << marker;
995 }
996 return markers;
997}
998
999void QPieSeriesPrivate::initializeAxes()
1000{
1001
1002}
1003
1004QAbstractAxis::AxisType QPieSeriesPrivate::defaultAxisType(Qt::Orientation orientation) const
1005{
1006 Q_UNUSED(orientation);
1007 return QAbstractAxis::AxisTypeNoAxis;
1008}
1009
1010QAbstractAxis* QPieSeriesPrivate::createDefaultAxis(Qt::Orientation orientation) const
1011{
1012 Q_UNUSED(orientation);
1013 return 0;
1014}
1015
1016void QPieSeriesPrivate::initializeTheme(int index, ChartTheme* theme, bool forced)
1017{
1018 //Q_Q(QPieSeries);
1019 //const QList<QColor>& colors = theme->seriesColors();
1020 const QList<QGradient>& gradients = theme->seriesGradients();
1021
1022 for (int i(0); i < m_slices.size(); i++) {
1023
1024 QColor penColor = ChartThemeManager::colorAt(gradient: gradients.at(i: index % gradients.size()), pos: 0.0);
1025
1026 // Get color for a slice from a gradient linearly, beginning from the start of the gradient
1027 qreal pos = (qreal)(i + 1) / (qreal) m_slices.size();
1028 QColor brushColor = ChartThemeManager::colorAt(gradient: gradients.at(i: index % gradients.size()), pos);
1029
1030 QPieSlice *s = m_slices.at(i);
1031 QPieSlicePrivate *d = QPieSlicePrivate::fromSlice(slice: s);
1032
1033 if (forced || d->m_data.m_slicePen.isThemed())
1034 d->setPen(pen: penColor, themed: true);
1035
1036 if (forced || d->m_data.m_sliceBrush.isThemed())
1037 d->setBrush(brush: brushColor, themed: true);
1038
1039 if (forced || d->m_data.m_labelBrush.isThemed())
1040 d->setLabelBrush(brush: theme->labelBrush().color(), themed: true);
1041
1042 if (forced || d->m_data.m_labelFont.isThemed())
1043 d->setLabelFont(font: theme->labelFont(), themed: true);
1044 }
1045}
1046
1047QT_END_NAMESPACE
1048
1049#include "moc_qpieseries.cpp"
1050#include "moc_qpieseries_p.cpp"
1051

source code of qtcharts/src/charts/piechart/qpieseries.cpp