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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtgraphs/src/graphs2d/piechart/qpieseries.cpp