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

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