##// END OF EJS Templates
QPieSlice: angle() -> startAngle(), angleSpan() -> endAngle()
Jani Honkonen -
r355:b889b21eeadf
parent child
Show More
@@ -1,210 +1,210
1 1
2 2 #include "piepresenter_p.h"
3 3 #include "pieslice_p.h"
4 4 #include "qpieslice.h"
5 5 #include "pieslicelabel_p.h"
6 6 #include "qpieseries.h"
7 7 #include <qmath.h>
8 8 #include <QDebug>
9 9 #include <QFontMetrics>
10 10
11 11
12 12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
13 13
14 14 PiePresenter::PiePresenter(QGraphicsItem *parent, QPieSeries *series)
15 15 :ChartItem(parent),
16 16 m_series(series)
17 17 {
18 18 Q_ASSERT(series);
19 19 connect(series, SIGNAL(changed(const QPieSeries::ChangeSet&)), this, SLOT(handleSeriesChanged(const QPieSeries::ChangeSet&)));
20 20 connect(series, SIGNAL(sizeFactorChanged()), this, SLOT(updateGeometry()));
21 21 connect(series, SIGNAL(positionChanged()), this, SLOT(updateGeometry()));
22 22
23 23 if (m_series->count()) {
24 24 QPieSeries::ChangeSet changeSet;
25 25 changeSet.appendAdded(m_series->m_slices);
26 26 handleSeriesChanged(changeSet);
27 27 }
28 28 }
29 29
30 30 PiePresenter::~PiePresenter()
31 31 {
32 32 // slices deleted automatically through QGraphicsItem
33 33 }
34 34
35 35 void PiePresenter::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
36 36 {
37 37 // TODO: paint shadows for all components
38 38 // - get paths from items & merge & offset and draw with shadow color?
39 39 }
40 40
41 41 void PiePresenter::handleSeriesChanged(const QPieSeries::ChangeSet& changeSet)
42 42 {
43 43 //qDebug() << "PiePresenter::handleSeriesChanged()";
44 44 //qDebug() << " added : " << changeSet.added();
45 45 //qDebug() << " changed: " << changeSet.changed();
46 46 //qDebug() << " removed: " << changeSet.removed();
47 47
48 48 foreach (QPieSlice* s, changeSet.added())
49 49 addSlice(s);
50 50
51 51 foreach (QPieSlice* s, changeSet.changed())
52 52 updateSlice(s);
53 53
54 54 foreach (QPieSlice* s, changeSet.removed())
55 55 deleteSlice(s);
56 56
57 57 // every change possibly changes the actual pie size
58 58 updateGeometry();
59 59 }
60 60
61 61 void PiePresenter::handleDomainChanged(const Domain& domain)
62 62 {
63 63 // TODO
64 64 }
65 65
66 66 void PiePresenter::handleGeometryChanged(const QRectF& rect)
67 67 {
68 68 m_rect = rect;
69 69 prepareGeometryChange();
70 70 updateGeometry();
71 71 }
72 72
73 73 void PiePresenter::updateGeometry()
74 74 {
75 75 if (!m_rect.isValid() || m_rect.isEmpty())
76 76 return;
77 77
78 78 // calculate maximum rectangle for pie
79 79 QRectF pieRect = m_rect;
80 80 if (pieRect.width() < pieRect.height()) {
81 81 pieRect.setWidth(pieRect.width() * m_series->sizeFactor());
82 82 pieRect.setHeight(pieRect.width());
83 83 pieRect.moveCenter(m_rect.center());
84 84 } else {
85 85 pieRect.setHeight(pieRect.height() * m_series->sizeFactor());
86 86 pieRect.setWidth(pieRect.height());
87 87 pieRect.moveCenter(m_rect.center());
88 88 }
89 89
90 90 // position the pie rectangle
91 91 switch (m_series->position()) {
92 92 case QPieSeries::PiePositionTopLeft: {
93 93 pieRect.setHeight(pieRect.height() / 2);
94 94 pieRect.setWidth(pieRect.height());
95 95 pieRect.moveCenter(QPointF(m_rect.center().x() / 2, m_rect.center().y() / 2));
96 96 break;
97 97 }
98 98 case QPieSeries::PiePositionTopRight: {
99 99 pieRect.setHeight(pieRect.height() / 2);
100 100 pieRect.setWidth(pieRect.height());
101 101 pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, m_rect.center().y() / 2));
102 102 break;
103 103 }
104 104 case QPieSeries::PiePositionBottomLeft: {
105 105 pieRect.setHeight(pieRect.height() / 2);
106 106 pieRect.setWidth(pieRect.height());
107 107 pieRect.moveCenter(QPointF(m_rect.center().x() / 2, (m_rect.center().y() / 2) * 3));
108 108 break;
109 109 }
110 110 case QPieSeries::PiePositionBottomRight: {
111 111 pieRect.setHeight(pieRect.height() / 2);
112 112 pieRect.setWidth(pieRect.height());
113 113 pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, (m_rect.center().y() / 2) * 3));
114 114 break;
115 115 }
116 116 default:
117 117 break;
118 118 }
119 119
120 120 // calculate how much space we need around the pie rectangle (labels & exploding)
121 121 qreal delta = 0;
122 122 qreal pieRadius = pieRect.height() / 2;
123 123 foreach (QPieSlice* s, m_series->m_slices) {
124 124
125 125 // calculate the farthest point in the slice from the pie center
126 qreal centerAngle = s->angle() + (s->angleSpan() / 2);
126 qreal centerAngle = s->m_startAngle + (s->m_angleSpan / 2);
127 127 qreal len = pieRadius + s->labelArmLength() + s->explodeDistance();
128 128 QPointF dp(qSin(centerAngle*(PI/180)) * len, -qCos(centerAngle*(PI/180)) * len);
129 129 QPointF p = pieRect.center() + dp;
130 130
131 131 // TODO: consider the label text
132 132
133 133 // calculate how much the radius must get smaller to fit that point in the base rectangle
134 134 qreal dt = m_rect.top() - p.y();
135 135 if (dt > delta) delta = dt;
136 136 qreal dl = m_rect.left() - p.x();
137 137 if (dl > delta) delta = dl;
138 138 qreal dr = p.x() - m_rect.right();
139 139 if (dr > delta) delta = dr;
140 140 qreal db = p.y() - m_rect.bottom();
141 141 if (db > delta) delta = db;
142 142
143 143 //if (!m_rect.contains(p)) qDebug() << s->label() << dt << dl << dr << db << "delta" << delta;
144 144 }
145 145
146 146 // shrink the pie rectangle so that everything outside it fits the base rectangle
147 147 pieRect.adjust(delta, delta, -delta, -delta);
148 148
149 149 // update slices
150 150 if (m_pieRect != pieRect) {
151 151 m_pieRect = pieRect;
152 152 //qDebug() << "PiePresenter::updateGeometry()" << m_rect << m_pieRect;
153 153 foreach (PieSlice* s, m_slices.values()) {
154 154 s->setPieRect(m_pieRect);
155 155 s->updateGeometry();
156 156 s->update();
157 157 }
158 158 }
159 159 }
160 160
161 161 void PiePresenter::addSlice(QPieSlice* sliceData)
162 162 {
163 163 //qDebug() << "PiePresenter::addSlice()" << sliceData;
164 164
165 165 if (m_slices.keys().contains(sliceData)) {
166 166 Q_ASSERT(0); // TODO: how to handle this nicely?
167 167 return;
168 168 }
169 169
170 170 // create slice
171 171 PieSlice *slice = new PieSlice(this);
172 172 slice->setPieRect(m_pieRect);
173 173 slice->updateData(sliceData);
174 174 slice->updateGeometry();
175 175 slice->update();
176 176 m_slices.insert(sliceData, slice);
177 177
178 178 // connect signals
179 179 connect(slice, SIGNAL(clicked()), sliceData, SIGNAL(clicked()));
180 180 connect(slice, SIGNAL(hoverEnter()), sliceData, SIGNAL(hoverEnter()));
181 181 connect(slice, SIGNAL(hoverLeave()), sliceData, SIGNAL(hoverLeave()));
182 182 }
183 183
184 184 void PiePresenter::updateSlice(QPieSlice* sliceData)
185 185 {
186 186 //qDebug() << "PiePresenter::updateSlice()" << sliceData;
187 187
188 188 if (!m_slices.contains(sliceData)) {
189 189 Q_ASSERT(0); // TODO: how to handle this nicely?
190 190 return;
191 191 }
192 192
193 193 m_slices[sliceData]->updateData(sliceData);
194 194 }
195 195
196 196 void PiePresenter::deleteSlice(QPieSlice* sliceData)
197 197 {
198 198 //qDebug() << "PiePresenter::deleteSlice()" << sliceData;
199 199
200 200 if (!m_slices.contains(sliceData)) {
201 201 Q_ASSERT(0); // TODO: how to handle this nicely?
202 202 return;
203 203 }
204 204
205 205 delete m_slices.take(sliceData);
206 206 }
207 207
208 208 #include "moc_piepresenter_p.cpp"
209 209
210 210 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,135 +1,135
1 1 #include "pieslice_p.h"
2 2 #include "pieslicelabel_p.h"
3 3 #include "piepresenter_p.h"
4 4 #include "qpieseries.h"
5 5 #include "qpieslice.h"
6 6 #include <QPainter>
7 7 #include <QDebug>
8 8 #include <qmath.h>
9 9 #include <QGraphicsSceneEvent>
10 10 #include <QTime>
11 11
12 12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
13 13
14 14 QPointF offset(qreal angle, qreal length)
15 15 {
16 16 qreal dx = qSin(angle*(PI/180)) * length;
17 17 qreal dy = qCos(angle*(PI/180)) * length;
18 18 return QPointF(dx, -dy);
19 19 }
20 20
21 21 PieSlice::PieSlice(QGraphicsItem* parent)
22 22 :QGraphicsObject(parent),
23 23 m_slicelabel(new PieSliceLabel(this)),
24 m_angle(0),
24 m_startAngle(0),
25 25 m_angleSpan(0),
26 26 m_isExploded(false),
27 27 m_explodeDistance(0)
28 28 {
29 29 setAcceptHoverEvents(true);
30 30 setAcceptedMouseButtons(Qt::LeftButton);
31 31 }
32 32
33 33 PieSlice::~PieSlice()
34 34 {
35 35
36 36 }
37 37
38 38 QRectF PieSlice::boundingRect() const
39 39 {
40 40 return m_path.boundingRect();
41 41 }
42 42
43 43 QPainterPath PieSlice::shape() const
44 44 {
45 45 return m_path;
46 46 }
47 47
48 48 void PieSlice::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
49 49 {
50 50 painter->setPen(m_pen);
51 51 painter->setBrush(m_brush);
52 52 painter->drawPath(m_path);
53 53 }
54 54
55 55 void PieSlice::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
56 56 {
57 57 emit hoverEnter();
58 58 }
59 59
60 60 void PieSlice::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
61 61 {
62 62 emit hoverLeave();
63 63 }
64 64
65 65 void PieSlice::mousePressEvent(QGraphicsSceneMouseEvent* /*event*/)
66 66 {
67 67 emit clicked();
68 68 }
69 69
70 70 void PieSlice::setPieRect(QRectF rect)
71 71 {
72 72 m_pieRect = rect;
73 73 }
74 74
75 75 void PieSlice::updateGeometry()
76 76 {
77 77 if (!m_pieRect.isValid() || m_pieRect.isEmpty())
78 78 return;
79 79
80 80 prepareGeometryChange();
81 81
82 82 // calculate center angle
83 qreal centerAngle = m_angle + (m_angleSpan/2);
83 qreal centerAngle = m_startAngle + (m_angleSpan/2);
84 84
85 85 // adjust rect for exploding
86 86 QRectF rect = m_pieRect;
87 87 if (m_isExploded) {
88 88 qreal dx = qSin(centerAngle*(PI/180)) * m_explodeDistance;
89 89 qreal dy = -qCos(centerAngle*(PI/180)) * m_explodeDistance;
90 90 rect.translate(dx, dy);
91 91 }
92 92
93 93 // update slice path
94 94 // TODO: draw the shape so that it might have a hole in the center
95 95 QPainterPath path;
96 96 path.moveTo(rect.center());
97 path.arcTo(rect, -m_angle + 90, -m_angleSpan);
97 path.arcTo(rect, -m_startAngle + 90, -m_angleSpan);
98 98 path.closeSubpath();
99 99 m_path = path;
100 100
101 101 // update label position
102 102 qreal radius = rect.height() / 2;
103 103 QPointF edgeCenter = rect.center() + offset(centerAngle, radius + 5);
104 104 m_slicelabel->setArmStartPoint(edgeCenter);
105 105 m_slicelabel->setArmAngle(centerAngle);
106 106 m_slicelabel->updateGeometry();
107 107 m_slicelabel->update();
108 108
109 109 //qDebug() << "PieSlice::updateGeometry" << m_slicelabel->text() << boundingRect() << m_angle << m_span;
110 110 }
111 111
112 112 void PieSlice::updateData(const QPieSlice* sliceData)
113 113 {
114 114 // TODO: compare what has changes to avoid unneccesary geometry updates
115 115
116 m_angle = sliceData->angle();
117 m_angleSpan = sliceData->angleSpan();
116 m_startAngle = sliceData->startAngle();
117 m_angleSpan = sliceData->m_angleSpan;
118 118 m_isExploded = sliceData->isExploded();
119 119 m_explodeDistance = sliceData->explodeDistance(); // TODO: expose to public API
120 120 m_pen = sliceData->pen();
121 121 m_brush = sliceData->brush();
122 122
123 123 m_slicelabel->setVisible(sliceData->isLabelVisible());
124 124 m_slicelabel->setText(sliceData->label());
125 125 m_slicelabel->setPen(sliceData->labelPen());
126 126 m_slicelabel->setFont(sliceData->labelFont());
127 127 m_slicelabel->setArmLength(sliceData->labelArmLength());
128 128
129 129 updateGeometry();
130 130 update();
131 131 }
132 132
133 133 #include "moc_pieslice_p.cpp"
134 134
135 135 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,64 +1,64
1 1 #ifndef PIESLICE_H
2 2 #define PIESLICE_H
3 3
4 4 #include "qchartglobal.h"
5 5 #include "charttheme_p.h"
6 6 #include "qpieseries.h"
7 7 #include <QGraphicsItem>
8 8 #include <QRectF>
9 9 #include <QColor>
10 10 #include <QPen>
11 11
12 12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
13 13 class PiePresenter;
14 14 class PieSliceLabel;
15 15 class QPieSlice;
16 16
17 17 class PieSlice : public QGraphicsObject
18 18 {
19 19 Q_OBJECT
20 20
21 21 public:
22 22 PieSlice(QGraphicsItem* parent = 0);
23 23 ~PieSlice();
24 24
25 25 public: // from QGraphicsItem
26 26 QRectF boundingRect() const;
27 27 QPainterPath shape() const;
28 28 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
29 29 void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
30 30 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
31 31 void mousePressEvent(QGraphicsSceneMouseEvent *event);
32 32
33 33 Q_SIGNALS:
34 34 void clicked();
35 35 void hoverEnter();
36 36 void hoverLeave();
37 37
38 38 public Q_SLOTS:
39 39 void setPieRect(QRectF rect);
40 40 void updateGeometry();
41 41 void updateData(const QPieSlice *sliceData);
42 42
43 43 public:
44 44 PieSliceLabel* label() { return m_slicelabel; }
45 45
46 46 private:
47 47 PieSliceLabel* m_slicelabel;
48 48
49 49 QRectF m_pieRect;
50 50 QPainterPath m_path;
51 51
52 qreal m_angle;
52 qreal m_startAngle;
53 53 qreal m_angleSpan;
54 54
55 55 bool m_isExploded;
56 56 qreal m_explodeDistance;
57 57
58 58 QPen m_pen;
59 59 QBrush m_brush;
60 60 };
61 61
62 62 QTCOMMERCIALCHART_END_NAMESPACE
63 63
64 64 #endif // PIESLICE_H
@@ -1,534 +1,534
1 1 #include "qpieseries.h"
2 2 #include "qpieslice.h"
3 3 #include <QDebug>
4 4
5 5 QTCOMMERCIALCHART_BEGIN_NAMESPACE
6 6
7 7
8 8 /*!
9 9 \class QPieSeries::ChangeSet
10 10 \brief Defines the changes in the series.
11 11
12 12 Contains the changes that have occurred in the series. Lists of added, changed and removed slices.
13 13
14 14 \sa QPieSeries::changed()
15 15 */
16 16
17 17 /*!
18 18 \internal
19 19 */
20 20 void QPieSeries::ChangeSet::appendAdded(QPieSlice* slice)
21 21 {
22 22 if (!m_added.contains(slice))
23 23 m_added << slice;
24 24 }
25 25
26 26 /*!
27 27 \internal
28 28 */
29 29 void QPieSeries::ChangeSet::appendAdded(QList<QPieSlice*> slices)
30 30 {
31 31 foreach (QPieSlice* s, slices)
32 32 appendAdded(s);
33 33 }
34 34
35 35 /*!
36 36 \internal
37 37 */
38 38 void QPieSeries::ChangeSet::appendChanged(QPieSlice* slice)
39 39 {
40 40 if (!m_changed.contains(slice))
41 41 m_changed << slice;
42 42 }
43 43
44 44 /*!
45 45 \internal
46 46 */
47 47 void QPieSeries::ChangeSet::appendRemoved(QPieSlice* slice)
48 48 {
49 49 if (!m_removed.contains(slice))
50 50 m_removed << slice;
51 51 }
52 52
53 53 /*!
54 54 Returns a list of slices that have been added to the series.
55 55 \sa QPieSeries::changed()
56 56 */
57 57 QList<QPieSlice*> QPieSeries::ChangeSet::added() const
58 58 {
59 59 return m_added;
60 60 }
61 61
62 62 /*!
63 63 Returns a list of slices that have been changed in the series.
64 64 \sa QPieSeries::changed()
65 65 */
66 66 QList<QPieSlice*> QPieSeries::ChangeSet::changed() const
67 67 {
68 68 return m_changed;
69 69 }
70 70
71 71 /*!
72 72 Returns a list of slices that have been removed from the series.
73 73 \sa QPieSeries::changed()
74 74 */
75 75 QList<QPieSlice*> QPieSeries::ChangeSet::removed() const
76 76 {
77 77 return m_removed;
78 78 }
79 79
80 80
81 81 /*!
82 82 Returns true if there are no added/changed or removed slices in the change set.
83 83 */
84 84 bool QPieSeries::ChangeSet::isEmpty() const
85 85 {
86 86 if (m_added.count() || m_changed.count() || m_removed.count())
87 87 return false;
88 88 return true;
89 89 }
90 90
91 91 /*!
92 92 \enum QPieSeries::PiePosition
93 93
94 94 This enum describes pie position within its bounding rectangle
95 95
96 96 \value PiePositionMaximized
97 97 \value PiePositionTopLeft
98 98 \value PiePositionTopRight
99 99 \value PiePositionBottomLeft
100 100 \value PiePositionBottomRight
101 101 */
102 102
103 103 /*!
104 104 \class QPieSeries
105 105 \brief Pie series API for QtCommercial Charts
106 106
107 107 The pie series defines a pie chart which consists of pie slices which are QPieSlice objects.
108 108 The slices can have any values as the QPieSeries will calculate its relative value to the sum of all slices.
109 109 The actual slice size (span) is determined by that relative value.
110 110
111 111 By default the pie is defined as full but it can be a partial pie.
112 112 This can be done by setting a starting angle and angle span to the series.
113 113
114 114 Example on how to create a chart with pie series:
115 115 \snippet ../example/piechart/main.cpp 1
116 116
117 117 To help with the most common user intercation scenarions there some convenience functions. Specifically
118 118 exploding and higlighting:
119 119 \snippet ../example/piechart/main.cpp 2
120 120
121 121 */
122 122
123 123 /*!
124 124 Constructs a series object which is a child of \a parent.
125 125 */
126 126 QPieSeries::QPieSeries(QObject *parent) :
127 127 QChartSeries(parent),
128 128 m_sizeFactor(1.0),
129 129 m_position(PiePositionMaximized),
130 130 m_pieStartAngle(0),
131 131 m_pieAngleSpan(360)
132 132 {
133 133
134 134 }
135 135
136 136 /*!
137 137 Destroys the object. Note that adding series to QChart transfers the ownership to the chart.
138 138 */
139 139 QPieSeries::~QPieSeries()
140 140 {
141 141
142 142 }
143 143
144 144 /*!
145 145 Returns QChartSeries::SeriesTypePie.
146 146 */
147 147 QChartSeries::QChartSeriesType QPieSeries::type() const
148 148 {
149 149 return QChartSeries::SeriesTypePie;
150 150 }
151 151
152 152 /*!
153 153 \internal \a data
154 154 */
155 155 bool QPieSeries::setData(QList<qreal> data)
156 156 {
157 157 // TODO: remove this function
158 158 QList<QPieSlice*> slices;
159 159 foreach (qreal value, data)
160 160 slices << new QPieSlice(value, QString::number(value));
161 161 replace(slices);
162 162 return true;
163 163 }
164 164
165 165 /*!
166 166 Sets an array of \a slices to the series replacing the existing slices.
167 167 Slice ownership is passed to the series.
168 168 */
169 169 void QPieSeries::replace(QList<QPieSlice*> slices)
170 170 {
171 171 clear();
172 172 add(slices);
173 173 }
174 174
175 175 /*!
176 176 Adds an array of \a slices to the series.
177 177 Slice ownership is passed to the series.
178 178 */
179 179 void QPieSeries::add(QList<QPieSlice*> slices)
180 180 {
181 181 ChangeSet changeSet;
182 182 foreach (QPieSlice* s, slices) {
183 183 s->setParent(this);
184 184 m_slices << s;
185 185 changeSet.appendAdded(s);
186 186 }
187 187
188 188 updateDerivativeData();
189 189
190 190 foreach (QPieSlice* s, slices) {
191 191 connect(s, SIGNAL(changed()), this, SLOT(sliceChanged()));
192 192 connect(s, SIGNAL(clicked()), this, SLOT(sliceClicked()));
193 193 connect(s, SIGNAL(hoverEnter()), this, SLOT(sliceHoverEnter()));
194 194 connect(s, SIGNAL(hoverLeave()), this, SLOT(sliceHoverLeave()));
195 195 }
196 196
197 197 emit changed(changeSet);
198 198 }
199 199
200 200 /*!
201 201 Adds a single \a slice to the series.
202 202 Slice ownership is passed to the series.
203 203 */
204 204 void QPieSeries::add(QPieSlice* slice)
205 205 {
206 206 add(QList<QPieSlice*>() << slice);
207 207 }
208 208
209 209
210 210 /*!
211 211 Adds a single slice to the series with give \a value and \a name.
212 212 Slice ownership is passed to the series.
213 213 */
214 214 QPieSlice* QPieSeries::add(qreal value, QString name)
215 215 {
216 216 QPieSlice* slice = new QPieSlice(value, name);
217 217 add(slice);
218 218 return slice;
219 219 }
220 220
221 221 /*!
222 222 Removes a single \a slice from the series and deletes the slice.
223 223
224 224 Do not reference this pointer after this call.
225 225 */
226 226 void QPieSeries::remove(QPieSlice* slice)
227 227 {
228 228 if (!m_slices.removeOne(slice)) {
229 229 Q_ASSERT(0); // TODO: how should this be reported?
230 230 return;
231 231 }
232 232
233 233 ChangeSet changeSet;
234 234 changeSet.appendRemoved(slice);
235 235 emit changed(changeSet);
236 236
237 237 delete slice;
238 238 slice = NULL;
239 239
240 240 updateDerivativeData();
241 241 }
242 242
243 243 /*!
244 244 Clears all slices from the series.
245 245 */
246 246 void QPieSeries::clear()
247 247 {
248 248 if (m_slices.count() == 0)
249 249 return;
250 250
251 251 ChangeSet changeSet;
252 252 foreach (QPieSlice* s, m_slices) {
253 253 changeSet.appendRemoved(s);
254 254 m_slices.removeOne(s);
255 255 delete s;
256 256 }
257 257 emit changed(changeSet);
258 258 updateDerivativeData();
259 259 }
260 260
261 261 /*!
262 262 Counts the number of the slices in this series.
263 263 */
264 264 int QPieSeries::count() const
265 265 {
266 266 return m_slices.count();
267 267 }
268 268
269 269 /*!
270 270 Returns a list of slices that belong to this series.
271 271 */
272 272 QList<QPieSlice*> QPieSeries::slices() const
273 273 {
274 274 return m_slices;
275 275 }
276 276
277 277 /*!
278 278 Sets the size \a factor of the pie. 1.0 is the default value.
279 279 Note that the pie will not grow beyond its absolute maximum size.
280 280 In practice its use is to make the pie appear smaller.
281 281 \sa sizeFactor()
282 282 */
283 283 void QPieSeries::setSizeFactor(qreal factor)
284 284 {
285 285 if (factor < 0.0)
286 286 return;
287 287
288 288 if (m_sizeFactor != factor) {
289 289 m_sizeFactor = factor;
290 290 emit sizeFactorChanged();
291 291 }
292 292 }
293 293
294 294 /*!
295 295 Gets the size factor of the pie.
296 296 \sa setSizeFactor()
297 297 */
298 298 qreal QPieSeries::sizeFactor() const
299 299 {
300 300 return m_sizeFactor;
301 301 }
302 302
303 303 /*!
304 304 Sets the \a position of the pie within its bounding rectangle.
305 305 \sa PiePosition, position()
306 306 */
307 307 void QPieSeries::setPosition(PiePosition position)
308 308 {
309 309 if (m_position != position) {
310 310 m_position = position;
311 311 emit positionChanged();
312 312 }
313 313 }
314 314
315 315 /*!
316 316 Gets the position of the pie within its bounding rectangle.
317 317 \sa PiePosition, setPosition()
318 318 */
319 319 QPieSeries::PiePosition QPieSeries::position() const
320 320 {
321 321 return m_position;
322 322 }
323 323
324 324
325 325 /*!
326 326 Sets the \a startAngle and \a angleSpan of this series.
327 327
328 328 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
329 329 */
330 330 void QPieSeries::setSpan(qreal startAngle, qreal angleSpan)
331 331 {
332 332 if (startAngle >= 0 && startAngle < 360 &&
333 333 angleSpan > 0 && angleSpan <= 360) {
334 334 m_pieStartAngle = startAngle;
335 335 m_pieAngleSpan = angleSpan;
336 336 updateDerivativeData();
337 337 }
338 338 }
339 339
340 340 /*!
341 341 Sets the all the slice labels \a visible or invisible.
342 342
343 343 \sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible()
344 344 */
345 345 void QPieSeries::setLabelsVisible(bool visible)
346 346 {
347 347 foreach (QPieSlice* s, m_slices)
348 348 s->setLabelVisible(visible);
349 349 }
350 350
351 351 /*!
352 352 Convenience method for exploding a slice when user clicks the pie. Set \a enable to true to
353 353 explode slices by clicking.
354 354
355 355 \sa QPieSlice::isExploded(), QPieSlice::setExploded(), QPieSlice::setExplodeDistance()
356 356 */
357 357 void QPieSeries::enableClickExplodes(bool enable)
358 358 {
359 359 if (enable)
360 360 connect(this, SIGNAL(clicked(QPieSlice*)), this, SLOT(toggleExploded(QPieSlice*)));
361 361 else
362 362 disconnect(this, SLOT(toggleExploded(QPieSlice*)));
363 363 }
364 364
365 365 /*!
366 366 Convenience method for highlighting a slice when user hovers over the slice.
367 367 It changes the slice color to be lighter and shows the label of the slice.
368 368 Set \a enable to true to highlight a slice when user hovers on top of it.
369 369
370 370 \sa QPieSlice::isExploded(), QPieSlice::setExploded()
371 371 */
372 372
373 373 void QPieSeries::enableHoverHighlight(bool enable)
374 374 {
375 375 if (enable) {
376 376 connect(this, SIGNAL(hoverEnter(QPieSlice*)), this, SLOT(highlightOn(QPieSlice*)));
377 377 connect(this, SIGNAL(hoverLeave(QPieSlice*)), this, SLOT(highlightOff(QPieSlice*)));
378 378 } else {
379 379 disconnect(this, SLOT(hoverEnter(QPieSlice*)));
380 380 disconnect(this, SLOT(hoverLeave(QPieSlice*)));
381 381 }
382 382 }
383 383
384 384 /*!
385 385 \fn void QPieSeries::changed(const QPieSeries::ChangeSet& changeSet)
386 386
387 387 This signal emitted when something has changed in the series.
388 388 The \a changeSet contains the details of which slices have been added, changed or removed.
389 389
390 390 \sa QPieSeries::ChangeSet, QPieSlice::changed()
391 391 */
392 392
393 393 /*!
394 394 \fn void QPieSeries::clicked(QPieSlice* slice)
395 395
396 396 This signal is emitted when a \a slice has been clicked.
397 397
398 398 \sa QPieSlice::clicked()
399 399 */
400 400
401 401 /*!
402 402 \fn void QPieSeries::hoverEnter(QPieSlice* slice)
403 403
404 404 This signal is emitted when user has hovered over a \a slice.
405 405
406 406 \sa QPieSlice::hoverEnter()
407 407 */
408 408
409 409 /*!
410 410 \fn void QPieSeries::hoverLeave(QPieSlice* slice)
411 411
412 412 This signal is emitted when user has hovered away from a \a slice.
413 413
414 414 \sa QPieSlice::hoverLeave()
415 415 */
416 416
417 417 /*!
418 418 \fn void QPieSeries::sizeFactorChanged()
419 419
420 420 This signal is emitted when size factor has been changed.
421 421
422 422 \sa sizeFactor(), setSizeFactor()
423 423 */
424 424
425 425 /*!
426 426 \fn void QPieSeries::positionChanged()
427 427
428 428 This signal is emitted when position of the pie has been changed.
429 429
430 430 \sa position(), setPosition()
431 431 */
432 432
433 433 void QPieSeries::sliceChanged()
434 434 {
435 435 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
436 436 Q_ASSERT(m_slices.contains(slice));
437 437
438 438 ChangeSet changeSet;
439 439 changeSet.appendChanged(slice);
440 440 emit changed(changeSet);
441 441
442 442 updateDerivativeData();
443 443 }
444 444
445 445 void QPieSeries::sliceClicked()
446 446 {
447 447 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
448 448 Q_ASSERT(m_slices.contains(slice));
449 449 emit clicked(slice);
450 450 }
451 451
452 452 void QPieSeries::sliceHoverEnter()
453 453 {
454 454 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
455 455 Q_ASSERT(m_slices.contains(slice));
456 456 emit hoverEnter(slice);
457 457 }
458 458
459 459 void QPieSeries::sliceHoverLeave()
460 460 {
461 461 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
462 462 Q_ASSERT(m_slices.contains(slice));
463 463 emit hoverLeave(slice);
464 464 }
465 465
466 466 void QPieSeries::toggleExploded(QPieSlice* slice)
467 467 {
468 468 Q_ASSERT(slice);
469 469 slice->setExploded(!slice->isExploded());
470 470 }
471 471
472 472 void QPieSeries::highlightOn(QPieSlice* slice)
473 473 {
474 474 Q_ASSERT(slice);
475 475 QColor c = slice->brush().color().lighter();
476 476 slice->setBrush(c);
477 477 slice->setLabelVisible(true);
478 478 }
479 479
480 480 void QPieSeries::highlightOff(QPieSlice* slice)
481 481 {
482 482 Q_ASSERT(slice);
483 483 QColor c = slice->brush().color().darker(150);
484 484 slice->setBrush(c);
485 485 slice->setLabelVisible(false);
486 486 }
487 487
488 488 void QPieSeries::updateDerivativeData()
489 489 {
490 490 m_total = 0;
491 491
492 492 // nothing to do?
493 493 if (m_slices.count() == 0)
494 494 return;
495 495
496 496 // calculate total
497 497 foreach (QPieSlice* s, m_slices)
498 498 m_total += s->value();
499 499
500 500 // we must have some values
501 501 Q_ASSERT(m_total > 0); // TODO: is this the correct way to handle this?
502 502
503 503 // update slice attributes
504 504 qreal sliceAngle = m_pieStartAngle;
505 505 foreach (QPieSlice* s, m_slices) {
506 506
507 507 bool changed = false;
508 508
509 509 qreal percentage = s->value() / m_total;
510 510 if (s->m_percentage != percentage) {
511 511 s->m_percentage = percentage;
512 512 changed = true;
513 513 }
514 514
515 515 qreal sliceSpan = m_pieAngleSpan * percentage;
516 516 if (s->m_angleSpan != sliceSpan) {
517 517 s->m_angleSpan = sliceSpan;
518 518 changed = true;
519 519 }
520 520
521 if (s->m_angle != sliceAngle) {
522 s->m_angle = sliceAngle;
521 if (s->m_startAngle != sliceAngle) {
522 s->m_startAngle = sliceAngle;
523 523 changed = true;
524 524 }
525 525 sliceAngle += sliceSpan;
526 526
527 527 if (changed)
528 528 emit s->changed();
529 529 }
530 530 }
531 531
532 532 #include "moc_qpieseries.cpp"
533 533
534 534 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,375 +1,375
1 1 #include "qpieslice.h"
2 2
3 3 QTCOMMERCIALCHART_BEGIN_NAMESPACE
4 4
5 5 #define DEFAULT_PEN_COLOR Qt::black
6 6 #define DEFAULT_BRUSH_COLOR Qt::white
7 7 #define DEFAULT_LABEL_ARM_LENGTH 40
8 8 #define DEFAULT_EXPOLODE_DISTANCE 20
9 9
10 10 /*!
11 11 \class QPieSlice
12 12 \brief Defines a slice in pie series.
13 13
14 14 Holds all the data of a single slice in a QPieSeries and provides the means
15 15 to modify slice data and customize the visual appearance of the slice.
16 16
17 17 It also provides the means to customize user interaction with the slice by
18 18 providing signals for clicking and hover events.
19 19 */
20 20
21 21 /*!
22 22 \property QPieSlice::label
23 23
24 24 Label of the slice.
25 25 */
26 26
27 27 /*!
28 28 \property QPieSlice::value
29 29
30 30 Value of the slice.
31 31 */
32 32
33 33 /*!
34 34 Constructs an empty slice with a \a parent.
35 35
36 36 Note that QPieSeries takes ownership of the slice when it is set/added.
37 37
38 38 \sa QPieSeries::set(), QPieSeries::add()
39 39 */
40 40 QPieSlice::QPieSlice(QObject *parent)
41 41 :QObject(parent),
42 42 m_value(0),
43 43 m_isLabelVisible(false),
44 44 m_isExploded(false),
45 45 m_explodeDistance(DEFAULT_EXPOLODE_DISTANCE),
46 46 m_percentage(0),
47 m_angle(0),
47 m_startAngle(0),
48 48 m_angleSpan(0),
49 49 m_pen(DEFAULT_PEN_COLOR),
50 50 m_brush(DEFAULT_BRUSH_COLOR),
51 51 m_labelPen(DEFAULT_PEN_COLOR),
52 52 m_labelArmLength(DEFAULT_LABEL_ARM_LENGTH)
53 53 {
54 54
55 55 }
56 56
57 57 /*!
58 58 Constructs an empty slice with given \a value, \a label and a \a parent.
59 59 Note that QPieSeries takes ownership of the slice when it is set/added.
60 60 \sa QPieSeries::set(), QPieSeries::add()
61 61 */
62 62 QPieSlice::QPieSlice(qreal value, QString label, QObject *parent)
63 63 :QObject(parent),
64 64 m_value(value),
65 65 m_label(label),
66 66 m_isLabelVisible(false),
67 67 m_isExploded(false),
68 68 m_explodeDistance(DEFAULT_EXPOLODE_DISTANCE),
69 69 m_percentage(0),
70 m_angle(0),
70 m_startAngle(0),
71 71 m_angleSpan(0),
72 72 m_pen(DEFAULT_PEN_COLOR),
73 73 m_brush(DEFAULT_BRUSH_COLOR),
74 74 m_labelPen(DEFAULT_PEN_COLOR),
75 75 m_labelArmLength(DEFAULT_LABEL_ARM_LENGTH)
76 76 {
77 77
78 78 }
79 79
80 80 /*!
81 81 Destroys the slice.
82 82 User should not delete the slice if it has been added to the series.
83 83 */
84 84 QPieSlice::~QPieSlice()
85 85 {
86 86
87 87 }
88 88
89 89 /*!
90 90 Gets the value of the slice.
91 91 Note that all values in the series
92 92 \sa setValue()
93 93 */
94 94 qreal QPieSlice::value() const
95 95 {
96 96 return m_value;
97 97 }
98 98
99 99 /*!
100 100 Gets the label of the slice.
101 101 \sa setLabel()
102 102 */
103 103 QString QPieSlice::label() const
104 104 {
105 105 return m_label;
106 106 }
107 107
108 108 /*!
109 109 Returns true if label is set as visible.
110 110 \sa setLabelVisible()
111 111 */
112 112 bool QPieSlice::isLabelVisible() const
113 113 {
114 114 return m_isLabelVisible;
115 115 }
116 116
117 117 /*!
118 118 Returns true if slice is exloded from the pie.
119 119 \sa setExploded()
120 120 */
121 121 bool QPieSlice::isExploded() const
122 122 {
123 123 return m_isExploded;
124 124 }
125 125
126 126 /*!
127 127 Returns the explosion distance of the slice.
128 128 Default value is 20.
129 129 \sa setExplodeDistance()
130 130 */
131 131 qreal QPieSlice::explodeDistance() const
132 132 {
133 133 return m_explodeDistance;
134 134 }
135 135
136 136 /*!
137 137 Returns the percentage of this slice compared to all slices in the same series.
138 138
139 139 Updated internally after the slice is added to the series.
140 140 */
141 141 qreal QPieSlice::percentage() const
142 142 {
143 143 return m_percentage;
144 144 }
145 145
146 146 /*!
147 147 Returns the starting angle of this slice in the series it belongs to.
148 148
149 149 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
150 150
151 151 Updated internally after the slice is added to the series.
152 152 */
153 qreal QPieSlice::angle() const
153 qreal QPieSlice::startAngle() const
154 154 {
155 return m_angle;
155 return m_startAngle;
156 156 }
157 157
158 158 /*!
159 Returns the angle span of this slice in the series it belongs to.
159 Returns the end angle of this slice in the series it belongs to.
160 160
161 161 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
162 162
163 163 Updated internally after the slice is added to the series.
164 164 */
165 qreal QPieSlice::angleSpan() const
165 qreal QPieSlice::endAngle() const
166 166 {
167 return m_angleSpan;
167 return m_startAngle + m_angleSpan;
168 168 }
169 169
170 170 /*!
171 171 Returns the pen used to draw this slice.
172 172 \sa setPen()
173 173 */
174 174 QPen QPieSlice::pen() const
175 175 {
176 176 return m_pen;
177 177 }
178 178
179 179 /*!
180 180 Returns the brush used to draw this slice.
181 181 \sa setBrush()
182 182 */
183 183 QBrush QPieSlice::brush() const
184 184 {
185 185 return m_brush;
186 186 }
187 187
188 188 /*!
189 189 Returns the pen used to draw label in this slice.
190 190 \sa setLabelPen()
191 191 */
192 192 QPen QPieSlice::labelPen() const
193 193 {
194 194 return m_labelPen;
195 195 }
196 196
197 197 /*!
198 198 Returns the font used to draw label in this slice.
199 199 \sa setLabelFont()
200 200 */
201 201 QFont QPieSlice::labelFont() const
202 202 {
203 203 return m_labelFont;
204 204 }
205 205
206 206 /*!
207 207 Returns the label arm lenght used in this slice.
208 208 Default value is 40 pixels.
209 209 \sa setLabelArmLength()
210 210 */
211 211 qreal QPieSlice::labelArmLength() const
212 212 {
213 213 return m_labelArmLength;
214 214 }
215 215
216 216 /*!
217 217 \fn void QPieSlice::clicked()
218 218
219 219 This signal is emitted when user has clicked the slice.
220 220
221 221 \sa QPieSeries::clicked()
222 222 */
223 223
224 224 /*!
225 225 \fn void QPieSlice::hoverEnter()
226 226
227 227 This signal is emitted when user has hovered over the slice.
228 228
229 229 \sa QPieSeries::hoverEnter()
230 230 */
231 231
232 232 /*!
233 233 \fn void QPieSlice::hoverLeave()
234 234
235 235 This signal is emitted when user has hovered away from the slice.
236 236
237 237 \sa QPieSeries::hoverLeave()
238 238 */
239 239
240 240 /*!
241 241 \fn void QPieSlice::changed()
242 242
243 243 This signal emitted when something has changed in the slice.
244 244
245 245 \sa QPieSeries::changed()
246 246 */
247 247
248 248 /*!
249 249 Sets the value of this slice.
250 250 \sa value()
251 251 */
252 252 void QPieSlice::setValue(qreal value)
253 253 {
254 254 if (m_value != value) {
255 255 m_value = value;
256 256 emit changed();
257 257 }
258 258 }
259 259
260 260 /*!
261 261 Sets the \a label of the slice.
262 262 \sa label()
263 263 */
264 264 void QPieSlice::setLabel(QString label)
265 265 {
266 266 if (m_label != label) {
267 267 m_label = label;
268 268 emit changed();
269 269 }
270 270 }
271 271
272 272 /*!
273 273 Sets the label \a visible in this slice.
274 274 \sa isLabelVisible(), QPieSeries::setLabelsVisible()
275 275 */
276 276 void QPieSlice::setLabelVisible(bool visible)
277 277 {
278 278 if (m_isLabelVisible != visible) {
279 279 m_isLabelVisible = visible;
280 280 emit changed();
281 281 }
282 282 }
283 283
284 284 /*!
285 285 Sets this slice \a exploded.
286 286 \sa isExploded(), setExplodeDistance(), QPieSeries::enableClickExplodes()
287 287 */
288 288 void QPieSlice::setExploded(bool exploded)
289 289 {
290 290 if (m_isExploded != exploded) {
291 291 m_isExploded = exploded;
292 292 emit changed();
293 293 }
294 294 }
295 295
296 296 /*!
297 297 Sets the explosion \a distance of this slice.
298 298 It is the distance the slice is moved away from the pie center.
299 299 \sa explodeDistance(), isExploded(), QPieSeries::enableClickExplodes()
300 300 */
301 301 void QPieSlice::setExplodeDistance(qreal distance)
302 302 {
303 303 if (m_explodeDistance != distance) {
304 304 m_explodeDistance = distance;
305 305 emit changed();
306 306 }
307 307 }
308 308
309 309 /*!
310 310 Sets the \a pen used to draw this slice.
311 311 Note that applying a theme will override this.
312 312 \sa pen()
313 313 */
314 314 void QPieSlice::setPen(QPen pen)
315 315 {
316 316 if (m_pen != pen) {
317 317 m_pen = pen;
318 318 emit changed();
319 319 }
320 320 }
321 321
322 322 /*!
323 323 Sets the \a brush used to draw this slice.
324 324 Note that applying a theme will override this.
325 325 \sa brush()
326 326 */
327 327 void QPieSlice::setBrush(QBrush brush)
328 328 {
329 329 if (m_brush != brush) {
330 330 m_brush = brush;
331 331 emit changed();
332 332 }
333 333 }
334 334
335 335 /*!
336 336 Sets the \a pen used to draw the label in this slice.
337 337 Note that applying a theme will override this.
338 338 \sa labelPen()
339 339 */
340 340 void QPieSlice::setLabelPen(QPen pen)
341 341 {
342 342 if (m_labelPen != pen) {
343 343 m_labelPen = pen;
344 344 emit changed();
345 345 }
346 346 }
347 347
348 348 /*!
349 349 Sets the \a font used to draw the label in this slice.
350 350 Note that applying a theme will override this.
351 351 \sa labelFont()
352 352 */
353 353 void QPieSlice::setLabelFont(QFont font)
354 354 {
355 355 if (m_labelFont != font) {
356 356 m_labelFont = font;
357 357 emit changed();
358 358 }
359 359 }
360 360
361 361 /*!
362 362 Sets the label arm \a length used to draw the label in this slice.
363 363 \sa labelArmLength()
364 364 */
365 365 void QPieSlice::setLabelArmLength(qreal length)
366 366 {
367 367 if (m_labelArmLength != length) {
368 368 m_labelArmLength = length;
369 369 emit changed();
370 370 }
371 371 }
372 372
373 373 #include "moc_qpieslice.cpp"
374 374
375 375 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,96 +1,97
1 1 #ifndef QPIESLICE_H
2 2 #define QPIESLICE_H
3 3
4 4 #include <qchartglobal.h>
5 5 #include <QObject>
6 6 #include <QPen>
7 7 #include <QBrush>
8 8 #include <QFont>
9 9
10 10 QTCOMMERCIALCHART_BEGIN_NAMESPACE
11 11
12 12 class QTCOMMERCIALCHART_EXPORT QPieSlice : public QObject
13 13 {
14 14 Q_OBJECT
15 15 Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY changed)
16 16 Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY changed)
17 17
18 18 public:
19 19 QPieSlice(QObject *parent = 0);
20 20 QPieSlice(qreal value, QString label, QObject *parent = 0);
21 21 virtual ~QPieSlice();
22 22
23 23 // data
24 24 qreal value() const;
25 25 QString label() const;
26 26 bool isLabelVisible() const;
27 27 bool isExploded() const;
28 28 qreal explodeDistance() const;
29 29
30 30 // generated data
31 31 qreal percentage() const;
32 qreal angle() const;
33 qreal angleSpan() const;
32 qreal startAngle() const;
33 qreal endAngle() const;
34 34
35 35 // customization
36 36 QPen pen() const;
37 37 QBrush brush() const;
38 38 QPen labelPen() const;
39 39 QFont labelFont() const;
40 40 qreal labelArmLength() const;
41 41
42 42 Q_SIGNALS:
43 43 void clicked();
44 44 void hoverEnter();
45 45 void hoverLeave();
46 46 void changed();
47 47
48 48 public Q_SLOTS:
49 49
50 50 // data
51 51 void setLabel(QString label);
52 52 void setLabelVisible(bool visible);
53 53 void setValue(qreal value);
54 54 void setExploded(bool exploded);
55 55 void setExplodeDistance(qreal distance);
56 56
57 57 // customization
58 58 void setPen(QPen pen);
59 59 void setBrush(QBrush brush);
60 60 void setLabelFont(QFont font);
61 61 void setLabelPen(QPen pen);
62 62 void setLabelArmLength(qreal len);
63 63
64 64 // TODO: label position in general
65 65 // setLabelFlags(inside|outside|labelArmOn|labelArmOff|???)
66 66 // setLabelOrientation(horizontal|vertical|same as slice center angle|???)
67 67
68 68 private:
69 69
70 70 // TODO: use private class
71 71 friend class QPieSeries;
72 72 friend class PiePresenter;
73 friend class PieSlice;
73 74
74 75 // data
75 76 qreal m_value;
76 77 QString m_label;
77 78 bool m_isLabelVisible;
78 79 bool m_isExploded;
79 80 qreal m_explodeDistance;
80 81
81 82 // generated data
82 83 qreal m_percentage;
83 qreal m_angle;
84 qreal m_startAngle;
84 85 qreal m_angleSpan;
85 86
86 87 // customization
87 88 QPen m_pen;
88 89 QBrush m_brush;
89 90 QPen m_labelPen;
90 91 QFont m_labelFont;
91 92 qreal m_labelArmLength;
92 93 };
93 94
94 95 QTCOMMERCIALCHART_END_NAMESPACE
95 96
96 97 #endif // QPIESLICE_H
General Comments 0
You need to be logged in to leave comments. Login now