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 | |
9 | QT_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 | */ |
373 | QPieSeries::QPieSeries(QObject *parent) |
374 | : QAbstractSeries(*(new QPieSeriesPrivate()), parent) |
375 | {} |
376 | |
377 | QPieSeries::~QPieSeries() {} |
378 | |
379 | /*! |
380 | \reimp |
381 | |
382 | Returns the type of the series. |
383 | */ |
384 | QAbstractSeries::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 | */ |
392 | QPieSlice *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 | */ |
404 | QPieSlice *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 | */ |
418 | bool 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 | */ |
453 | void 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 | */ |
485 | bool 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 | */ |
501 | bool 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 | */ |
543 | bool 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 | */ |
580 | bool 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 | */ |
591 | bool 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 | */ |
628 | QPieSeries &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 | */ |
640 | QPieSlice *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 | */ |
658 | bool 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 | */ |
696 | bool 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 | */ |
723 | bool 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 | */ |
744 | void 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 | */ |
766 | QList<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 | */ |
775 | qsizetype 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 | */ |
784 | bool 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 | */ |
795 | qreal QPieSeries::sum() const |
796 | { |
797 | Q_D(const QPieSeries); |
798 | return d->m_sum; |
799 | } |
800 | |
801 | void 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 | |
818 | qreal QPieSeries::horizontalPosition() const |
819 | { |
820 | Q_D(const QPieSeries); |
821 | return d->m_pieRelativeHorPos; |
822 | } |
823 | |
824 | void 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 | |
841 | qreal QPieSeries::verticalPosition() const |
842 | { |
843 | Q_D(const QPieSeries); |
844 | return d->m_pieRelativeVerPos; |
845 | } |
846 | |
847 | void 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 | |
854 | qreal 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 | */ |
869 | void 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 | */ |
887 | qreal 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 | */ |
902 | void 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 | */ |
920 | qreal QPieSeries::endAngle() const |
921 | { |
922 | Q_D(const QPieSeries); |
923 | return d->m_pieEndAngle; |
924 | } |
925 | |
926 | void 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 | */ |
943 | void 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 | */ |
958 | void QPieSeries::setLabelsPosition(QPieSlice::LabelPosition position) |
959 | { |
960 | Q_D(QPieSeries); |
961 | for (QPieSlice *s : d->m_slices) |
962 | s->setLabelPosition(position); |
963 | } |
964 | |
965 | void 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 | |
973 | QPieSeries::QPieSeries(QPieSeriesPrivate &dd, QObject *parent) |
974 | : QAbstractSeries(dd, parent) |
975 | {} |
976 | |
977 | void 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 | |
984 | qreal QPieSeries::holeSize() const |
985 | { |
986 | Q_D(const QPieSeries); |
987 | return d->m_holeRelativeSize; |
988 | } |
989 | |
990 | QPieSeriesPrivate::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 | |
1000 | void 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 | |
1032 | void QPieSeriesPrivate::updateLabels() |
1033 | { |
1034 | Q_Q(QPieSeries); |
1035 | |
1036 | emit q->update(); |
1037 | } |
1038 | |
1039 | void 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 | |
1053 | QT_END_NAMESPACE |
1054 |
Definitions
- QPieSeries
- ~QPieSeries
- type
- at
- find
- replace
- removeMultiple
- remove
- replace
- replace
- append
- append
- operator <<
- append
- insert
- remove
- take
- clear
- slices
- count
- isEmpty
- sum
- setHorizontalPosition
- horizontalPosition
- setVerticalPosition
- verticalPosition
- setPieSize
- pieSize
- setStartAngle
- startAngle
- setEndAngle
- endAngle
- componentComplete
- setLabelsVisible
- setLabelsPosition
- handleSliceChange
- QPieSeries
- setHoleSize
- holeSize
- QPieSeriesPrivate
- updateData
- updateLabels
Learn to use CMake with our Intro Training
Find out more