1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include <QtCharts/QPieSlice>
5#include <private/qpieslice_p.h>
6
7QT_BEGIN_NAMESPACE
8
9/*!
10 \class QPieSlice
11 \inmodule QtCharts
12 \brief The QPieSlice class represents a single slice in a pie series.
13
14 A pie slice has a value and a label. When the slice is added to a pie series, the
15 QPieSeries object calculates the percentage of the slice compared with the sum of
16 all slices in the series to determine the actual size of the slice in the chart.
17
18 By default, the label is hidden. If it is visible, it can be either located outside
19 the slice and connected to it with an arm or centered inside the slice either
20 horizontally or in parallel with the tangential or normal of the slice's arc.
21
22 By default, the visual appearance of the slice is set by a theme, but the theme can be
23 overridden by specifying slice properties. However, if the theme is changed after the
24 slices are customized, all customization will be lost.
25
26 To enable user interaction with the pie chart, some basic signals are emitted when
27 users click pie slices or hover the mouse over them.
28
29 \sa QPieSeries
30*/
31
32/*!
33 \qmltype PieSlice
34 \instantiates QPieSlice
35 \inqmlmodule QtCharts
36
37 \brief Represents a single slice in a pie series.
38
39 A pie slice has a value and a label. When the slice is added to a pie series, the
40 PieSeries type calculates the percentage of the slice compared with the sum of
41 all slices in the series to determine the actual size of the slice in the chart.
42
43 By default, the label is hidden. If it is visible, it can be either located outside
44 the slice and connected to it with an arm or centered inside the slice either
45 horizontally or in parallel with the tangential or normal of the slice's arc.
46
47 By default, the visual appearance of the slice is set by a theme, but the theme can be
48 overridden by specifying slice properties. However, if the theme is changed after the
49 slices are customized, all customization will be lost.
50
51 The PieSlice type should be used as a child of a PieSeries type. For example:
52
53 Alternatively, slices can be added to a pie series by using the \l{PieSeries::append()}
54 {PieSeries.append()} method.
55
56 In that case, \l{PieSeries::at()}{PieSeries.at()} or \l {PieSeries::find}
57 {PieSeries.find} can be used to access the properties of an individual PieSlice instance.
58 \sa PieSeries
59*/
60
61/*!
62 \enum QPieSlice::LabelPosition
63
64 This enum describes the position of the slice label.
65
66 \value LabelOutside
67 The label is located outside the slice connected to it with an arm.
68 This is the default value.
69 \value LabelInsideHorizontal
70 The label is centered within the slice and laid out horizontally.
71 \value LabelInsideTangential
72 The label is centered within the slice and rotated to be parallel with
73 the tangential of the slice's arc.
74 \value LabelInsideNormal
75 The label is centered within the slice and rotated to be parallel with
76 the normal of the slice's arc.
77 */
78
79/*!
80 \property QPieSlice::label
81 \brief The label of the slice.
82 \note The string can be HTML formatted.
83 \sa labelVisible, labelBrush, labelFont, labelArmLengthFactor
84*/
85/*!
86 \qmlproperty string PieSlice::label
87 The label of the slice.
88 \note The string can be HTML formatted.
89*/
90
91/*!
92 \fn void QPieSlice::labelChanged()
93 This signal is emitted when the slice label changes.
94 \sa label
95*/
96
97/*!
98 \property QPieSlice::value
99 \brief The value of the slice.
100 \note A negative value is converted to a positive value.
101 \sa percentage(), QPieSeries::sum()
102*/
103/*!
104 \qmlproperty real PieSlice::value
105 The value of the slice.
106
107 \note A negative value is converted to a positive value.
108*/
109
110/*!
111 \fn void QPieSlice::valueChanged()
112 This signal is emitted when the slice value changes.
113 \sa value
114*/
115
116/*!
117 \property QPieSlice::labelVisible
118 \brief The visibility of the slice label. By default, the label is not visible.
119 \sa label, labelBrush, labelFont, labelArmLengthFactor
120*/
121/*!
122 \qmlproperty bool PieSlice::labelVisible
123 The visibility of the slice label. By default, the label is not visible.
124*/
125
126/*!
127 \fn void QPieSlice::labelVisibleChanged()
128 This signal is emitted when the visibility of the slice label changes.
129 \sa labelVisible
130*/
131
132/*!
133 \property QPieSlice::exploded
134 \brief Whether the slice is separated from the pie.
135 \sa explodeDistanceFactor
136*/
137/*!
138 \qmlproperty bool PieSlice::exploded
139 Whether the slice is separated from the pie.
140 \sa explodeDistanceFactor
141*/
142
143/*!
144 \property QPieSlice::pen
145 \brief The pen used to draw the slice border.
146*/
147
148/*!
149 \fn void QPieSlice::penChanged()
150 This signal is emitted when the pen used to draw the slice border changes.
151 \sa pen
152*/
153
154/*!
155 \property QPieSlice::borderColor
156 \brief The color used to draw the slice border.
157 This is a convenience property for modifying the slice pen.
158 \sa pen, borderWidth
159*/
160/*!
161 \qmlproperty color PieSlice::borderColor
162 The color used to draw the slice border (pen color).
163 \sa borderWidth
164*/
165
166/*!
167 \fn void QPieSlice::borderColorChanged()
168 This signal is emitted when the slice border color changes.
169 \sa pen, borderColor
170*/
171
172/*!
173 \property QPieSlice::borderWidth
174 \brief The width of the slice border.
175 This is a convenience property for modifying the slice pen.
176 \sa pen, borderColor
177*/
178/*!
179 \qmlproperty int PieSlice::borderWidth
180 The width of the slice border.
181 This is a convenience property for modifying the slice pen.
182 \sa borderColor
183*/
184
185/*!
186 \fn void QPieSlice::borderWidthChanged()
187 This signal is emitted when the slice border width changes.
188 \sa pen, borderWidth
189*/
190
191/*!
192 \property QPieSlice::brush
193 \brief The brush used to fill the slice.
194*/
195
196/*!
197 \fn void QPieSlice::brushChanged()
198 This signal is emitted when the brush used to fill the slice changes.
199 \sa brush
200*/
201
202/*!
203 \qmlproperty string PieSlice::brushFilename
204 The name of the file used as a brush for the slice.
205*/
206
207/*!
208 \property QPieSlice::color
209 \brief The fill (brush) color of the slice.
210 This is a convenience property for modifying the slice brush.
211 \sa brush
212*/
213/*!
214 \qmlproperty color PieSlice::color
215 The fill (brush) color of the slice.
216*/
217
218/*!
219 \fn void QPieSlice::colorChanged()
220 This signal is emitted when the slice color changes.
221 \sa brush
222*/
223
224/*!
225 \property QPieSlice::labelBrush
226 \brief The brush used to draw the label and label arm of the slice.
227 \sa label, labelVisible, labelFont, labelArmLengthFactor
228*/
229
230/*!
231 \fn void QPieSlice::labelBrushChanged()
232 This signal is emitted when the label brush of the slice changes.
233 \sa labelBrush
234*/
235
236/*!
237 \property QPieSlice::labelColor
238 \brief The color used to draw the slice label.
239 This is a convenience property for modifying the slice label brush.
240 \sa labelBrush
241*/
242/*!
243 \qmlproperty color PieSlice::labelColor
244 The color used to draw the slice label.
245*/
246
247/*!
248 \fn void QPieSlice::labelColorChanged()
249 This signal is emitted when the slice label color changes.
250 \sa labelColor
251*/
252
253/*!
254 \property QPieSlice::labelFont
255 \brief The font used for drawing the label text.
256 \sa label, labelVisible, labelArmLengthFactor
257*/
258
259/*!
260 \fn void QPieSlice::labelFontChanged()
261 This signal is emitted when the label font of the slice changes.
262 \sa labelFont
263*/
264
265/*!
266 \qmlproperty font PieSlice::labelFont
267
268 The font used for the slice label.
269
270 For more information, see \l [QML]{font}.
271
272 \sa labelVisible, labelPosition
273*/
274
275/*!
276 \property QPieSlice::labelPosition
277 \brief The position of the slice label.
278 \sa label, labelVisible
279*/
280/*!
281 \qmlproperty enumeration PieSlice::labelPosition
282
283 Describes the position of the slice label.
284
285 \value PieSlice.LabelOutside
286 The label is located outside the slice connected to it with an arm.
287 This is the default value.
288 \value PieSlice.LabelInsideHorizontal
289 The label is centered within the slice and laid out horizontally.
290 \value PieSlice.LabelInsideTangential
291 The label is centered within the slice and rotated to be parallel with
292 the tangential of the slice's arc.
293 \value PieSlice.LabelInsideNormal
294 The label is centered within the slice and rotated to be parallel with
295 the normal of the slice's arc.
296
297 \sa labelVisible
298*/
299
300/*!
301 \property QPieSlice::labelArmLengthFactor
302 \brief The length of the label arm.
303 The factor is relative to the pie radius. For example:
304 \list
305 \li 1.0 means that the length is the same as the radius.
306 \li 0.5 means that the length is half of the radius.
307 \endlist
308 By default, the arm length is 0.15
309 \sa label, labelVisible, labelBrush, labelFont
310*/
311/*!
312 \qmlproperty real PieSlice::labelArmLengthFactor
313 The length of the label arm.
314 The factor is relative to the pie radius. For example:
315 \list
316 \li 1.0 means that the length is the same as the radius.
317 \li 0.5 means that the length is half of the radius.
318 \endlist
319 By default, the arm length is 0.15
320
321 \sa labelVisible
322*/
323
324/*!
325 \property QPieSlice::explodeDistanceFactor
326 \brief Determines how far away from the pie the slice is exploded.
327 \list
328 \li 1.0 means that the distance is the same as the radius.
329 \li 0.5 means that the distance is half of the radius.
330 \endlist
331 By default, the distance is 0.15
332 \sa exploded
333*/
334/*!
335 \qmlproperty real PieSlice::explodeDistanceFactor
336 Determines how far away from the pie the slice is exploded.
337 \list
338 \li 1.0 means that the distance is the same as the radius.
339 \li 0.5 means that the distance is half of the radius.
340 \endlist
341 By default, the distance is 0.15
342
343 \sa exploded
344*/
345
346/*!
347 \property QPieSlice::percentage
348 \brief The percentage of the slice compared to the sum of all slices in the series.
349 The actual value ranges from 0.0 to 1.0.
350 Updated automatically once the slice is added to the series.
351 \sa value, QPieSeries::sum
352*/
353/*!
354 \qmlproperty real PieSlice::percentage
355 The percentage of the slice compared to the sum of all slices in the series.
356 The actual value ranges from 0.0 to 1.0.
357 Updated automatically once the slice is added to the series.
358*/
359
360/*!
361 \fn void QPieSlice::percentageChanged()
362 This signal is emitted when the percentage of the slice changes.
363 \sa percentage
364*/
365
366/*!
367 \property QPieSlice::startAngle
368 \brief The starting angle of this slice in the series it belongs to.
369 A full pie is 360 degrees, where 0 degrees is at 12 a'clock.
370 Updated automatically once the slice is added to the series.
371*/
372/*!
373 \qmlproperty real PieSlice::startAngle
374 The starting angle of this slice in the series it belongs to.
375 A full pie is 360 degrees, where 0 degrees is at 12 a'clock.
376 Updated automatically once the slice is added to the series.
377*/
378
379/*!
380 \fn void QPieSlice::startAngleChanged()
381 This signal is emitted when the starting angle of the slice changes.
382 \sa startAngle
383*/
384
385/*!
386 \property QPieSlice::angleSpan
387 \brief The span of the slice in degrees.
388 A full pie is 360 degrees, where 0 degrees is at 12 a'clock.
389 Updated automatically once the slice is added to the series.
390*/
391/*!
392 \qmlproperty real PieSlice::angleSpan
393 The span of the slice in degrees.
394 A full pie is 360 degrees, where 0 degrees is at 12 a'clock.
395 Updated automatically once the slice is added to the series.
396*/
397
398/*!
399 \fn void QPieSlice::angleSpanChanged()
400 This signal is emitted when the angle span of the slice changes.
401 \sa angleSpan
402*/
403
404/*!
405 \fn void QPieSlice::clicked()
406 This signal is emitted when the slice is clicked.
407 \sa QPieSeries::clicked()
408*/
409/*!
410 \qmlsignal PieSlice::clicked()
411 This signal is emitted when the slice is clicked.
412
413 The corresponding signal handler is \c onClicked().
414*/
415
416/*!
417 \fn void QPieSlice::pressed()
418 This signal is emitted when the user clicks the slice and holds down the mouse button.
419 \sa QPieSeries::pressed()
420*/
421/*!
422 \qmlsignal PieSlice::pressed()
423 This signal is emitted when user clicks the slice and holds down the mouse button.
424
425 The corresponding signal handler is \c onPressed().
426*/
427
428/*!
429 \fn void QPieSlice::released()
430 This signal is emitted when the user releases the mouse press on the slice.
431 \sa QPieSeries::released()
432*/
433/*!
434 \qmlsignal PieSlice::released()
435 This signal is emitted when the user releases the mouse press on the slice.
436
437 The corresponding signal handler is \c onReleased().
438*/
439
440/*!
441 \fn void QPieSlice::doubleClicked()
442 This signal is emitted when user double-clicks the slice.
443 \sa QPieSeries::doubleClicked()
444*/
445/*!
446 \qmlsignal PieSlice::doubleClicked()
447 This signal is emitted when user double-clicks the slice.
448
449 The corresponding signal handler is \c onDoubleClicked().
450*/
451
452/*!
453 \fn void QPieSlice::hovered(bool state)
454 This signal is emitted when a mouse is hovered over the slice. When the mouse
455 moves over the slice, \a state turns \c true, and when the mouse moves away
456 again, it turns \c false.
457 \sa QPieSeries::hovered()
458*/
459/*!
460 \qmlsignal PieSlice::hovered(bool state)
461 This signal is emitted when a mouse is hovered over the slice. When the mouse
462 moves over the slice, \a state turns \c true, and when the mouse moves away
463 again, it turns \c false.
464
465 The corresponding signal handler is \c onHovered().
466*/
467
468/*!
469 Constructs an empty slice with the parent \a parent.
470 \sa QPieSeries::append(), QPieSeries::insert()
471*/
472QPieSlice::QPieSlice(QObject *parent)
473 : QObject(parent),
474 d_ptr(new QPieSlicePrivate(this))
475{
476
477}
478
479/*!
480 Constructs an empty slice with the specified \a value, \a label, and \a parent.
481 \sa QPieSeries::append(), QPieSeries::insert()
482*/
483QPieSlice::QPieSlice(QString label, qreal value, QObject *parent)
484 : QObject(parent),
485 d_ptr(new QPieSlicePrivate(this))
486{
487 setValue(value);
488 setLabel(label);
489}
490
491/*!
492 Removes the slice. The slice should not be removed if it has been added to a series.
493*/
494QPieSlice::~QPieSlice()
495{
496
497}
498
499void QPieSlice::setLabel(QString label)
500{
501 if (d_ptr->m_data.m_labelText != label) {
502 d_ptr->m_data.m_labelText = label;
503 emit labelChanged();
504 }
505}
506
507QString QPieSlice::label() const
508{
509 return d_ptr->m_data.m_labelText;
510}
511
512void QPieSlice::setValue(qreal value)
513{
514 value = qAbs(t: value); // negative values not allowed
515 if (!qFuzzyCompare(p1: d_ptr->m_data.m_value, p2: value)) {
516 d_ptr->m_data.m_value = value;
517 emit valueChanged();
518 }
519}
520
521qreal QPieSlice::value() const
522{
523 return d_ptr->m_data.m_value;
524}
525
526void QPieSlice::setLabelVisible(bool visible)
527{
528 if (d_ptr->m_data.m_isLabelVisible != visible) {
529 d_ptr->m_data.m_isLabelVisible = visible;
530 emit labelVisibleChanged();
531 }
532}
533
534bool QPieSlice::isLabelVisible() const
535{
536 return d_ptr->m_data.m_isLabelVisible;
537}
538
539void QPieSlice::setExploded(bool exploded)
540{
541 if (d_ptr->m_data.m_isExploded != exploded) {
542 d_ptr->m_data.m_isExploded = exploded;
543 emit d_ptr->explodedChanged();
544 }
545}
546
547QPieSlice::LabelPosition QPieSlice::labelPosition()
548{
549 return d_ptr->m_data.m_labelPosition;
550}
551
552void QPieSlice::setLabelPosition(LabelPosition position)
553{
554 if (d_ptr->m_data.m_labelPosition != position) {
555 d_ptr->m_data.m_labelPosition = position;
556 emit d_ptr->labelPositionChanged();
557 }
558}
559
560bool QPieSlice::isExploded() const
561{
562 return d_ptr->m_data.m_isExploded;
563}
564
565void QPieSlice::setPen(const QPen &pen)
566{
567 d_ptr->setPen(pen, themed: false);
568}
569
570QPen QPieSlice::pen() const
571{
572 return d_ptr->m_data.m_slicePen;
573}
574
575QColor QPieSlice::borderColor()
576{
577 return pen().color();
578}
579
580void QPieSlice::setBorderColor(QColor color)
581{
582 QPen p = pen();
583 if (color != p.color()) {
584 p.setColor(color);
585 setPen(p);
586 }
587}
588
589int QPieSlice::borderWidth()
590{
591 return pen().width();
592}
593
594void QPieSlice::setBorderWidth(int width)
595{
596 QPen p = pen();
597 if (width != p.width()) {
598 p.setWidth(width);
599 setPen(p);
600 }
601}
602
603void QPieSlice::setBrush(const QBrush &brush)
604{
605 d_ptr->setBrush(brush, themed: false);
606}
607
608QBrush QPieSlice::brush() const
609{
610 return d_ptr->m_data.m_sliceBrush;
611}
612
613QColor QPieSlice::color()
614{
615 return brush().color();
616}
617
618void QPieSlice::setColor(QColor color)
619{
620 QBrush b = brush();
621
622 if (b == QBrush())
623 b.setStyle(Qt::SolidPattern);
624 b.setColor(color);
625 setBrush(b);
626}
627
628void QPieSlice::setLabelBrush(const QBrush &brush)
629{
630 d_ptr->setLabelBrush(brush, themed: false);
631}
632
633QBrush QPieSlice::labelBrush() const
634{
635 return d_ptr->m_data.m_labelBrush;
636}
637
638QColor QPieSlice::labelColor()
639{
640 return labelBrush().color();
641}
642
643void QPieSlice::setLabelColor(QColor color)
644{
645 QBrush b = labelBrush();
646 if (color != b.color()) {
647 b.setColor(color);
648 setLabelBrush(b);
649 }
650}
651
652void QPieSlice::setLabelFont(const QFont &font)
653{
654 d_ptr->setLabelFont(font, themed: false);
655}
656
657QFont QPieSlice::labelFont() const
658{
659 return d_ptr->m_data.m_labelFont;
660}
661
662void QPieSlice::setLabelArmLengthFactor(qreal factor)
663{
664 if (!qFuzzyCompare(p1: d_ptr->m_data.m_labelArmLengthFactor, p2: factor)) {
665 d_ptr->m_data.m_labelArmLengthFactor = factor;
666 emit d_ptr->labelArmLengthFactorChanged();
667 }
668}
669
670qreal QPieSlice::labelArmLengthFactor() const
671{
672 return d_ptr->m_data.m_labelArmLengthFactor;
673}
674
675void QPieSlice::setExplodeDistanceFactor(qreal factor)
676{
677 if (!qFuzzyCompare(p1: d_ptr->m_data.m_explodeDistanceFactor, p2: factor)) {
678 d_ptr->m_data.m_explodeDistanceFactor = factor;
679 emit d_ptr->explodeDistanceFactorChanged();
680 }
681}
682
683qreal QPieSlice::explodeDistanceFactor() const
684{
685 return d_ptr->m_data.m_explodeDistanceFactor;
686}
687
688qreal QPieSlice::percentage() const
689{
690 return d_ptr->m_data.m_percentage;
691}
692
693qreal QPieSlice::startAngle() const
694{
695 return d_ptr->m_data.m_startAngle;
696}
697
698qreal QPieSlice::angleSpan() const
699{
700 return d_ptr->m_data.m_angleSpan;
701}
702
703/*!
704 Returns the series that this slice belongs to.
705
706 \sa QPieSeries::append()
707*/
708QPieSeries *QPieSlice::series() const
709{
710 return d_ptr->m_series;
711}
712
713QPieSlicePrivate::QPieSlicePrivate(QPieSlice *parent)
714 : QObject(parent),
715 q_ptr(parent),
716 m_series(0)
717{
718
719}
720
721QPieSlicePrivate::~QPieSlicePrivate()
722{
723
724}
725
726QPieSlicePrivate *QPieSlicePrivate::fromSlice(QPieSlice *slice)
727{
728 return slice->d_func();
729}
730
731void QPieSlicePrivate::setPen(const QPen &pen, bool themed)
732{
733 if (m_data.m_slicePen != pen) {
734
735 QPen oldPen = m_data.m_slicePen;
736
737 m_data.m_slicePen = pen;
738 m_data.m_slicePen.setThemed(themed);
739
740 emit q_ptr->penChanged();
741 if (oldPen.color() != pen.color())
742 emit q_ptr->borderColorChanged();
743 if (oldPen.width() != pen.width())
744 emit q_ptr->borderWidthChanged();
745 }
746}
747
748void QPieSlicePrivate::setBrush(const QBrush &brush, bool themed)
749{
750 if (m_data.m_sliceBrush != brush) {
751
752 QBrush oldBrush = m_data.m_sliceBrush;
753
754 m_data.m_sliceBrush = brush;
755 m_data.m_sliceBrush.setThemed(themed);
756
757 emit q_ptr->brushChanged();
758 if (oldBrush.color() != brush.color())
759 emit q_ptr->colorChanged();
760 }
761}
762
763void QPieSlicePrivate::setLabelBrush(const QBrush &brush, bool themed)
764{
765 if (m_data.m_labelBrush != brush) {
766
767 QBrush oldBrush = m_data.m_labelBrush;
768
769 m_data.m_labelBrush = brush;
770 m_data.m_labelBrush.setThemed(themed);
771
772 emit q_ptr->labelBrushChanged();
773 if (oldBrush.color() != brush.color())
774 emit q_ptr->labelColorChanged();
775 }
776}
777
778void QPieSlicePrivate::setLabelFont(const QFont &font, bool themed)
779{
780 if (m_data.m_labelFont != font) {
781 m_data.m_labelFont = font;
782 m_data.m_labelFont.setThemed(themed);
783 emit q_ptr->labelFontChanged();
784 }
785}
786
787void QPieSlicePrivate::setPercentage(qreal percentage)
788{
789 if (!qFuzzyCompare(p1: m_data.m_percentage, p2: percentage)) {
790 m_data.m_percentage = percentage;
791 emit q_ptr->percentageChanged();
792 }
793}
794
795void QPieSlicePrivate::setStartAngle(qreal angle)
796{
797 if (!qFuzzyCompare(p1: m_data.m_startAngle, p2: angle)) {
798 m_data.m_startAngle = angle;
799 emit q_ptr->startAngleChanged();
800 }
801}
802
803void QPieSlicePrivate::setAngleSpan(qreal span)
804{
805 if (!qFuzzyCompare(p1: m_data.m_angleSpan, p2: span)) {
806 m_data.m_angleSpan = span;
807 emit q_ptr->angleSpanChanged();
808 }
809}
810
811QT_END_NAMESPACE
812
813#include "moc_qpieslice.cpp"
814#include "moc_qpieslice_p.cpp"
815

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