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

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