##// END OF EJS Templates
Refactor graphical side of pie to simplify the implementation.
Jani Honkonen -
r1074:22571433397b
parent child
Show More
@@ -1,301 +1,294
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "chartanimator_p.h"
22 22 #include "axisanimation_p.h"
23 23 #include "xyanimation_p.h"
24 24 #include "splineanimation_p.h"
25 25 #include "xychartitem_p.h"
26 26 #include "pieanimation_p.h"
27 27 #include "baranimation_p.h"
28 28 #include "barchartitem_p.h"
29 29 #include "areachartitem_p.h"
30 30 #include "splinechartitem_p.h"
31 31 #include "scatterchartitem_p.h"
32 32 #include <QTimer>
33 33
34 34 Q_DECLARE_METATYPE(QVector<QPointF>)
35 35 Q_DECLARE_METATYPE(QVector<qreal>)
36 36 Q_DECLARE_METATYPE(QVector<QRectF>)
37 37
38 38 QTCOMMERCIALCHART_BEGIN_NAMESPACE
39 39
40 40 const static int duration = 1000;
41 41
42 42 ChartAnimator::ChartAnimator(QObject *parent):QObject(parent),
43 43 m_state(ShowState)
44 44 {
45 45 }
46 46
47 47 ChartAnimator::~ChartAnimator()
48 48 {
49 49 }
50 50
51 51 void ChartAnimator::addAnimation(ChartAxis *item)
52 52 {
53 53 ChartAnimation *animation = m_animations.value(item);
54 54
55 55 if (!animation) {
56 56 animation = new AxisAnimation(item);
57 57 m_animations.insert(item, animation);
58 58 }
59 59
60 60 item->setAnimator(this);
61 61 }
62 62
63 63 void ChartAnimator::addAnimation(SplineChartItem *item)
64 64 {
65 65 ChartAnimation *animation = m_animations.value(item);
66 66
67 67 if (!animation) {
68 68 animation = new SplineAnimation(item);
69 69 m_animations.insert(item, animation);
70 70 }
71 71
72 72 item->setAnimator(this);
73 73 }
74 74
75 75 void ChartAnimator::addAnimation(ScatterChartItem *item)
76 76 {
77 77 ChartAnimation *animation = m_animations.value(item);
78 78
79 79 if (!animation) {
80 80 animation = new XYAnimation(item);
81 81 m_animations.insert(item, animation);
82 82 }
83 83
84 84 item->setAnimator(this);
85 85 }
86 86
87 87 void ChartAnimator::addAnimation(LineChartItem *item)
88 88 {
89 89 ChartAnimation *animation = m_animations.value(item);
90 90
91 91 if (!animation) {
92 92 animation = new XYAnimation(item);
93 93 m_animations.insert(item, animation);
94 94 }
95 95
96 96 item->setAnimator(this);
97 97 }
98 98
99 99 void ChartAnimator::addAnimation(PieChartItem *item)
100 100 {
101 101 ChartAnimation *animation = m_animations.value(item);
102 102
103 103 if (!animation) {
104 104 animation = new PieAnimation(item);
105 105 m_animations.insert(item, animation);
106 106 }
107 107
108 108 item->setAnimator(this);
109 109 }
110 110
111 111 void ChartAnimator::addAnimation(BarChartItem *item)
112 112 {
113 113 ChartAnimation *animation = m_animations.value(item);
114 114
115 115 if (!animation) {
116 116 animation = new BarAnimation(item);
117 117 m_animations.insert(item, animation);
118 118 }
119 119
120 120 item->setAnimator(this);
121 121 }
122 122
123 123
124 124 void ChartAnimator::removeAnimation(Chart *item)
125 125 {
126 126 item->setAnimator(0);
127 127 m_animations.remove(item);
128 128 }
129 129
130 130 void ChartAnimator::updateLayout(ChartAxis *item , QVector<qreal> &newLayout)
131 131 {
132 132 AxisAnimation *animation = static_cast<AxisAnimation*>(m_animations.value(item));
133 133
134 134 Q_ASSERT(animation);
135 135
136 136 QVector<qreal> oldLayout = item->layout();
137 137
138 138 if (newLayout.count() == 0)
139 139 return;
140 140
141 141 switch (m_state) {
142 142 case ZoomOutState: {
143 143 QRectF rect = item->geometry();
144 144 oldLayout.resize(newLayout.count());
145 145
146 146 for(int i = 0, j = oldLayout.count() - 1; i < (oldLayout.count() + 1) / 2; ++i, --j) {
147 147 oldLayout[i] = item->axisType() == ChartAxis::X_AXIS ? rect.left() : rect.bottom();
148 148 oldLayout[j] = item->axisType() == ChartAxis::X_AXIS ? rect.right() : rect.top();
149 149 }
150 150 }
151 151 break;
152 152 case ZoomInState: {
153 153 int index = qMin(oldLayout.count() * (item->axisType() == ChartAxis::X_AXIS ? m_point.x() : (1 - m_point.y())), newLayout.count() - 1.0);
154 154 oldLayout.resize(newLayout.count());
155 155
156 156 for(int i = 0; i < oldLayout.count(); i++)
157 157 oldLayout[i]= oldLayout[index];
158 158 }
159 159 break;
160 160 case ScrollDownState:
161 161 case ScrollRightState: {
162 162 oldLayout.resize(newLayout.count());
163 163
164 164 for(int i = 0, j = i + 1; i < oldLayout.count() - 1; ++i, ++j)
165 165 oldLayout[i]= oldLayout[j];
166 166 }
167 167 break;
168 168 case ScrollUpState:
169 169 case ScrollLeftState: {
170 170 oldLayout.resize(newLayout.count());
171 171
172 172 for(int i = oldLayout.count() - 1, j = i - 1; i > 0; --i, --j)
173 173 oldLayout[i]= oldLayout[j];
174 174 }
175 175 break;
176 176 default: {
177 177 oldLayout.resize(newLayout.count());
178 178 QRectF rect = item->geometry();
179 179 for(int i = 0, j = oldLayout.count() - 1; i < oldLayout.count(); ++i, --j)
180 180 oldLayout[i] = item->axisType() == ChartAxis::X_AXIS ? rect.left() : rect.top();
181 181 }
182 182 break;
183 183 }
184 184
185 185
186 186 if (animation->state() != QAbstractAnimation::Stopped)
187 187 animation->stop();
188 188
189 189 animation->setDuration(duration);
190 190 animation->setEasingCurve(QEasingCurve::OutQuart);
191 191 QVariantAnimation::KeyValues value;
192 192 animation->setKeyValues(value); //workaround for wrong interpolation call
193 193 animation->setKeyValueAt(0.0, qVariantFromValue(oldLayout));
194 194 animation->setKeyValueAt(1.0, qVariantFromValue(newLayout));
195 195
196 196 QTimer::singleShot(0, animation, SLOT(start()));
197 197 }
198 198
199 199 void ChartAnimator::updateLayout(SplineChartItem *item, QVector<QPointF> &oldPoints, QVector<QPointF> &newPoints, QVector<QPointF> &oldControlPoints, QVector<QPointF> &newControlPoints, int index)
200 200 {
201 201 SplineAnimation *animation = static_cast<SplineAnimation *>(m_animations.value(item));
202 202
203 203 Q_ASSERT(animation);
204 204
205 205 if (newPoints.count() < 2 || newControlPoints.count() < 2)
206 206 return;
207 207
208 208 bool empty = oldPoints.count() == 0;
209 209
210 210
211 211 if (animation->state() != QAbstractAnimation::Stopped)
212 212 animation->stop();
213 213
214 214 animation->setDuration(duration);
215 215 if (!empty)
216 216 animation->setAnimationType(ChartAnimation::MoveDownAnimation);
217 217 else
218 218 animation->setAnimationType(ChartAnimation::LineDrawAnimation);
219 219
220 220 animation->setEasingCurve(QEasingCurve::OutQuart);
221 221 animation->setValues(oldPoints, newPoints, oldControlPoints, newControlPoints, index);
222 222
223 223 QTimer::singleShot(0, animation, SLOT(start()));
224 224 }
225 225
226 226
227 227 void ChartAnimator::updateLayout(XYChartItem *item, QVector<QPointF> &oldPoints, QVector<QPointF> &newPoints, int index)
228 228 {
229 229 XYAnimation *animation = static_cast<XYAnimation *>(m_animations.value(item));
230 230
231 231 Q_ASSERT(animation);
232 232
233 233 if (newPoints.count() == 0)
234 234 return;
235 235
236 236 bool empty = oldPoints.count() == 0;
237 237
238 238
239 239 if (animation->state() != QAbstractAnimation::Stopped)
240 240 animation->stop();
241 241
242 242 animation->setDuration(duration);
243 243 if (!empty)
244 244 animation->setAnimationType(ChartAnimation::MoveDownAnimation);
245 245 else
246 246 animation->setAnimationType(ChartAnimation::LineDrawAnimation);
247 247
248 248 animation->setEasingCurve(QEasingCurve::OutQuart);
249 249 animation->setValues(oldPoints, newPoints, index);
250 250
251 251 QTimer::singleShot(0, animation, SLOT(start()));
252 252 }
253 253
254 void ChartAnimator::addAnimation(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData, bool isEmpty)
254 void ChartAnimator::addAnimation(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData, bool startupAnimation)
255 255 {
256 256 PieAnimation *animation = static_cast<PieAnimation *>(m_animations.value(item));
257 257 Q_ASSERT(animation);
258 animation->addSlice(sliceItem, sliceData, isEmpty);
258 animation->addSlice(sliceItem, sliceData, startupAnimation);
259 259 }
260 260
261 261 void ChartAnimator::removeAnimation(PieChartItem *item, PieSliceItem *sliceItem)
262 262 {
263 263 PieAnimation *animation = static_cast<PieAnimation *>(m_animations.value(item));
264 264 Q_ASSERT(animation);
265 265 animation->removeSlice(sliceItem);
266 266 }
267 267
268 void ChartAnimator::updateLayout(PieChartItem *item, const PieLayout &layout)
269 {
270 PieAnimation *animation = static_cast<PieAnimation *>(m_animations.value(item));
271 Q_ASSERT(animation);
272 animation->updateValues(layout);
273 }
274
275 void ChartAnimator::updateLayout(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData)
268 void ChartAnimator::updateAnimation(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData)
276 269 {
277 270 PieAnimation *animation = static_cast<PieAnimation *>(m_animations.value(item));
278 271 Q_ASSERT(animation);
279 272 animation->updateValue(sliceItem, sliceData);
280 273 }
281 274
282 275 void ChartAnimator::updateLayout(BarChartItem *item, const QVector<QRectF> &oldLayout, const QVector<QRectF> &newLayout)
283 276 {
284 277 BarAnimation *animation = static_cast<BarAnimation *>(m_animations.value(item));
285 278 Q_ASSERT(animation);
286 279 animation->setDuration(duration);
287 280 animation->setKeyValueAt(0.0, qVariantFromValue(oldLayout));
288 281 animation->setKeyValueAt(1.0, qVariantFromValue(newLayout));
289 282 QTimer::singleShot(0, animation, SLOT(start()));
290 283 }
291 284
292 285
293 286 void ChartAnimator::setState(State state, const QPointF &point)
294 287 {
295 288 m_state = state;
296 289 m_point = point;
297 290 }
298 291
299 292 #include "moc_chartanimator_p.cpp"
300 293
301 294 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,79 +1,78
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #ifndef CHARTANIMATOR_P_H
22 22 #define CHARTANIMATOR_P_H
23 23
24 24 #include "qchartglobal.h"
25 25 #include "chartanimation_p.h"
26 26 #include "piechartitem_p.h"
27 27 #include "barchartitem_p.h"
28 28 #include <QPointF>
29 29
30 30 QTCOMMERCIALCHART_BEGIN_NAMESPACE
31 31
32 32 class ChartItem;
33 33 class ChartAxis;
34 34 class AreaChartItem;
35 35 class SplineChartItem;
36 36 class ScatterChartItem;
37 37 class LineChartItem;
38 38 class XYChartItem;
39 39
40 40 class ChartAnimator : public QObject
41 41 {
42 42 Q_OBJECT
43 43 public:
44 44 enum State{ShowState, ScrollUpState, ScrollDownState, ScrollLeftState, ScrollRightState, ZoomInState, ZoomOutState};
45 45
46 46 ChartAnimator(QObject *parent = 0);
47 47 virtual ~ChartAnimator();
48 48
49 49 void addAnimation(ChartAxis *item);
50 50 void addAnimation(PieChartItem *item);
51 51 void addAnimation(ScatterChartItem *item);
52 52 void addAnimation(LineChartItem *item);
53 53 void addAnimation(SplineChartItem *item);
54 54 void addAnimation(BarChartItem *item);
55 55 void removeAnimation(Chart *item);
56 56
57 57 void animationStarted();
58 58 void updateLayout(XYChartItem *item, QVector<QPointF> &oldLayout, QVector<QPointF> &newLayout, int index);
59 59 void updateLayout(SplineChartItem *item, QVector<QPointF> &oldPoints, QVector<QPointF> &newPoints, QVector<QPointF> &oldControlPoints, QVector<QPointF> &newContorlPoints, int index);
60 60 void updateLayout(ChartAxis *item, QVector<qreal> &layout);
61 61
62 62 void addAnimation(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData, bool isEmpty);
63 63 void removeAnimation(PieChartItem *item, PieSliceItem *sliceItem);
64 void updateLayout(PieChartItem *item, const PieLayout &layout);
65 void updateLayout(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData);
64 void updateAnimation(PieChartItem *item, PieSliceItem *sliceItem, const PieSliceData &sliceData);
66 65
67 66 void updateLayout(BarChartItem *item, const QVector<QRectF> &oldLayout, const QVector<QRectF> &newLayout);
68 67
69 68 void setState(State state,const QPointF &point = QPointF());
70 69
71 70 private:
72 71 QMap<Chart *, ChartAnimation *> m_animations;
73 72 State m_state;
74 73 QPointF m_point;
75 74 };
76 75
77 76 QTCOMMERCIALCHART_END_NAMESPACE
78 77
79 78 #endif
@@ -1,106 +1,100
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "pieanimation_p.h"
22 22 #include "piesliceanimation_p.h"
23 23 #include "piechartitem_p.h"
24 24 #include <QParallelAnimationGroup>
25 25 #include <QTimer>
26 26
27 27 QTCOMMERCIALCHART_BEGIN_NAMESPACE
28 28
29 29 PieAnimation::PieAnimation(PieChartItem *item)
30 30 :ChartAnimation(item),
31 31 m_item(item)
32 32 {
33 33 }
34 34
35 35 PieAnimation::~PieAnimation()
36 36 {
37 37 }
38 38
39 void PieAnimation::updateValues(const PieLayout &newValues)
40 {
41 foreach (PieSliceItem *s, newValues.keys())
42 updateValue(s, newValues.value(s));
43 }
44
45 39 void PieAnimation::updateValue(PieSliceItem *sliceItem, const PieSliceData &sliceData)
46 40 {
47 41 PieSliceAnimation *animation = m_animations.value(sliceItem);
48 42 Q_ASSERT(animation);
49 43 animation->stop();
50 44
51 45 animation->updateValue(sliceData);
52 46 animation->setDuration(1000);
53 47 animation->setEasingCurve(QEasingCurve::OutQuart);
54 48
55 49 QTimer::singleShot(0, animation, SLOT(start()));
56 50 }
57 51
58 void PieAnimation::addSlice(PieSliceItem *sliceItem, const PieSliceData &sliceData, bool isEmpty)
52 void PieAnimation::addSlice(PieSliceItem *sliceItem, const PieSliceData &sliceData, bool startupAnimation)
59 53 {
60 54 PieSliceAnimation *animation = new PieSliceAnimation(sliceItem);
61 55 m_animations.insert(sliceItem, animation);
62 56
63 57 PieSliceData startValue = sliceData;
64 58 startValue.m_radius = 0;
65 if (isEmpty)
59 if (startupAnimation)
66 60 startValue.m_startAngle = 0;
67 61 else
68 62 startValue.m_startAngle = sliceData.m_startAngle + (sliceData.m_angleSpan / 2);
69 63 startValue.m_angleSpan = 0;
70 64 animation->setValue(startValue, sliceData);
71 65
72 66 animation->setDuration(1000);
73 67 animation->setEasingCurve(QEasingCurve::OutQuart);
74 68 QTimer::singleShot(0, animation, SLOT(start()));
75 69 }
76 70
77 71 void PieAnimation::removeSlice(PieSliceItem *sliceItem)
78 72 {
79 73 PieSliceAnimation *animation = m_animations.value(sliceItem);
80 74 Q_ASSERT(animation);
81 75 animation->stop();
82 76
83 77 PieSliceData endValue = animation->currentSliceValue();
84 78 endValue.m_radius = 0;
85 79 endValue.m_startAngle = endValue.m_startAngle + endValue.m_angleSpan;
86 80 endValue.m_angleSpan = 0;
87 81
88 82 animation->updateValue(endValue);
89 83 animation->setDuration(1000);
90 84 animation->setEasingCurve(QEasingCurve::OutQuart);
91 85
92 86 // PieSliceItem is the parent of PieSliceAnimation so the animation will be deleted as well..
93 87 connect(animation, SIGNAL(finished()), sliceItem, SLOT(deleteLater()));
94 88 m_animations.remove(sliceItem);
95 89
96 90 QTimer::singleShot(0, animation, SLOT(start()));
97 91 }
98 92
99 93 void PieAnimation::updateCurrentValue(const QVariant &)
100 94 {
101 95 // nothing to do...
102 96 }
103 97
104 98 #include "moc_pieanimation_p.cpp"
105 99
106 100 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,54 +1,53
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #ifndef PIEANIMATION_P_H
22 22 #define PIEANIMATION_P_H
23 23
24 24 #include "chartanimation_p.h"
25 25 #include "piechartitem_p.h"
26 26 #include "piesliceanimation_p.h"
27 27
28 28 QTCOMMERCIALCHART_BEGIN_NAMESPACE
29 29
30 30 class PieChartItem;
31 31
32 32 class PieAnimation : public ChartAnimation
33 33 {
34 34 Q_OBJECT
35 35
36 36 public:
37 37 PieAnimation(PieChartItem *item);
38 38 ~PieAnimation();
39 void updateValues(const PieLayout &newValues);
40 39 void updateValue(PieSliceItem *sliceItem, const PieSliceData &newValue);
41 void addSlice(PieSliceItem *sliceItem, const PieSliceData &endValue, bool isEmpty);
40 void addSlice(PieSliceItem *sliceItem, const PieSliceData &endValue, bool startupAnimation);
42 41 void removeSlice(PieSliceItem *sliceItem);
43 42
44 43 public: // from QVariantAnimation
45 44 void updateCurrentValue(const QVariant &value);
46 45
47 46 private:
48 47 PieChartItem *m_item;
49 48 QHash<PieSliceItem *, PieSliceAnimation *> m_animations;
50 49 };
51 50
52 51 QTCOMMERCIALCHART_END_NAMESPACE
53 52
54 53 #endif
@@ -1,127 +1,125
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "piesliceanimation_p.h"
22 22 #include "piechartitem_p.h"
23 23
24 24 Q_DECLARE_METATYPE(QTCOMMERCIALCHART_NAMESPACE::PieSliceData)
25 25
26 26 QTCOMMERCIALCHART_BEGIN_NAMESPACE
27 27
28 28 qreal linearPos(qreal start, qreal end, qreal pos)
29 29 {
30 30 return start + ((end - start) * pos);
31 31 }
32 32
33 33 QPointF linearPos(QPointF start, QPointF end, qreal pos)
34 34 {
35 35 qreal x = linearPos(start.x(), end.x(), pos);
36 36 qreal y = linearPos(start.y(), end.y(), pos);
37 37 return QPointF(x, y);
38 38 }
39 39
40 40 QPen linearPos(QPen start, QPen end, qreal pos)
41 41 {
42 42 QColor c;
43 43 c.setRedF(linearPos(start.color().redF(), end.color().redF(), pos));
44 44 c.setGreenF(linearPos(start.color().greenF(), end.color().greenF(), pos));
45 45 c.setBlueF(linearPos(start.color().blueF(), end.color().blueF(), pos));
46 46 end.setColor(c);
47 47 return end;
48 48 }
49 49
50 50 QBrush linearPos(QBrush start, QBrush end, qreal pos)
51 51 {
52 52 QColor c;
53 53 c.setRedF(linearPos(start.color().redF(), end.color().redF(), pos));
54 54 c.setGreenF(linearPos(start.color().greenF(), end.color().greenF(), pos));
55 55 c.setBlueF(linearPos(start.color().blueF(), end.color().blueF(), pos));
56 56 end.setColor(c);
57 57 return end;
58 58 }
59 59
60 60 PieSliceAnimation::PieSliceAnimation(PieSliceItem *sliceItem)
61 61 :QVariantAnimation(sliceItem),
62 62 m_sliceItem(sliceItem)
63 63 {
64 64 }
65 65
66 66 PieSliceAnimation::~PieSliceAnimation()
67 67 {
68 68 }
69 69
70 70 void PieSliceAnimation::setValue(const PieSliceData &startValue, const PieSliceData &endValue)
71 71 {
72 72 if (state() != QAbstractAnimation::Stopped)
73 73 stop();
74 74
75 75 m_currentValue = startValue;
76 76
77 77 setKeyValueAt(0.0, qVariantFromValue(startValue));
78 78 setKeyValueAt(1.0, qVariantFromValue(endValue));
79 79 }
80 80
81 81 void PieSliceAnimation::updateValue(const PieSliceData &endValue)
82 82 {
83 83 if (state() != QAbstractAnimation::Stopped)
84 84 stop();
85 85
86 86 setKeyValueAt(0.0, qVariantFromValue(m_currentValue));
87 87 setKeyValueAt(1.0, qVariantFromValue(endValue));
88 88 }
89 89
90 90 PieSliceData PieSliceAnimation::currentSliceValue()
91 91 {
92 92 // NOTE:
93 93 // We must use an internal current value because QVariantAnimation::currentValue() is updated
94 94 // before the animation is actually started. So if we get 2 updateValue() calls in a row the currentValue()
95 95 // will have the end value set from the first call and the second call will interpolate that instead of
96 96 // the original current value as it was before the first call.
97 97 return m_currentValue;
98 98 }
99 99
100 100 QVariant PieSliceAnimation::interpolated(const QVariant &start, const QVariant &end, qreal progress) const
101 101 {
102 102 PieSliceData startValue = qVariantValue<PieSliceData>(start);
103 103 PieSliceData endValue = qVariantValue<PieSliceData>(end);
104 104
105 105 PieSliceData result;
106 106 result = endValue;
107 107 result.m_center = linearPos(startValue.m_center, endValue.m_center, progress);
108 108 result.m_radius = linearPos(startValue.m_radius, endValue.m_radius, progress);
109 109 result.m_startAngle = linearPos(startValue.m_startAngle, endValue.m_startAngle, progress);
110 110 result.m_angleSpan = linearPos(startValue.m_angleSpan, endValue.m_angleSpan, progress);
111 111 result.m_slicePen = linearPos(startValue.m_slicePen, endValue.m_slicePen, progress);
112 112 result.m_sliceBrush = linearPos(startValue.m_sliceBrush, endValue.m_sliceBrush, progress);
113 113
114 114 return qVariantFromValue(result);
115 115 }
116 116
117 117 void PieSliceAnimation::updateCurrentValue(const QVariant &value)
118 118 {
119 119 if (state() != QAbstractAnimation::Stopped) { //workaround
120 120 m_currentValue = qVariantValue<PieSliceData>(value);
121 m_sliceItem->setSliceData(m_currentValue);
122 m_sliceItem->updateGeometry();
123 m_sliceItem->update();
121 m_sliceItem->setLayout(m_currentValue);
124 122 }
125 123 }
126 124
127 125 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,208 +1,160
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "piechartitem_p.h"
22 22 #include "piesliceitem_p.h"
23 23 #include "qpieslice.h"
24 24 #include "qpieseries.h"
25 25 #include "qpieseries_p.h"
26 26 #include "chartpresenter_p.h"
27 27 #include "chartdataset_p.h"
28 28 #include "chartanimator_p.h"
29 29 #include <QPainter>
30 30 #include <QTimer>
31 31
32 32 QTCOMMERCIALCHART_BEGIN_NAMESPACE
33 33
34 34 PieChartItem::PieChartItem(QPieSeries *series, ChartPresenter* presenter)
35 35 :ChartItem(presenter),
36 36 m_series(series)
37 37 {
38 38 Q_ASSERT(series);
39 39
40 40 QPieSeriesPrivate *d = QPieSeriesPrivate::seriesData(*series);
41 41 connect(d, SIGNAL(added(QList<QPieSlice*>)), this, SLOT(handleSlicesAdded(QList<QPieSlice*>)));
42 42 connect(d, SIGNAL(removed(QList<QPieSlice*>)), this, SLOT(handleSlicesRemoved(QList<QPieSlice*>)));
43 connect(d, SIGNAL(piePositionChanged()), this, SLOT(handlePieLayoutChanged()));
44 connect(d, SIGNAL(pieSizeChanged()), this, SLOT(handlePieLayoutChanged()));
43 connect(d, SIGNAL(piePositionChanged()), this, SLOT(updateLayout()));
44 connect(d, SIGNAL(pieSizeChanged()), this, SLOT(updateLayout()));
45 45
46 46 QTimer::singleShot(0, this, SLOT(initialize())); // TODO: get rid of this
47 47
48 48 // Note: the following does not affect as long as the item does not have anything to paint
49 49 setZValue(ChartPresenter::PieSeriesZValue);
50 50 }
51 51
52 52 PieChartItem::~PieChartItem()
53 53 {
54 54 // slices deleted automatically through QGraphicsItem
55 55 }
56 56
57 void PieChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
57 void PieChartItem::handleGeometryChanged(const QRectF& rect)
58 58 {
59 Q_UNUSED(painter)
60 // TODO: paint shadows for all components
61 // - get paths from items & merge & offset and draw with shadow color?
62 //painter->setBrush(QBrush(Qt::red));
63 //painter->drawRect(m_debugRect);
59 prepareGeometryChange();
60 m_rect = rect;
61 updateLayout();
64 62 }
65 63
66 64 void PieChartItem::initialize()
67 65 {
68 66 handleSlicesAdded(m_series->slices());
69 67 }
70 68
71 void PieChartItem::handleSlicesAdded(QList<QPieSlice*> slices)
69 void PieChartItem::updateLayout()
72 70 {
73 bool isEmpty = m_slices.isEmpty();
71 // find pie center coordinates
72 m_pieCenter.setX(m_rect.left() + (m_rect.width() * m_series->horizontalPosition()));
73 m_pieCenter.setY(m_rect.top() + (m_rect.height() * m_series->verticalPosition()));
74 74
75 // find maximum radius for pie
76 m_pieRadius = m_rect.height() / 2;
77 if (m_rect.width() < m_rect.height())
78 m_pieRadius = m_rect.width() / 2;
79
80 // apply size factor
81 m_pieRadius *= m_series->pieSize();
82
83 // set layouts for existing slice items
84 foreach (QPieSlice* slice, m_series->slices()) {
85 PieSliceItem *sliceItem = m_sliceItems.value(slice);
86 if (sliceItem) {
87 PieSliceData sliceData = updateSliceGeometry(slice);
88 if (animator())
89 animator()->updateAnimation(this, sliceItem, sliceData);
90 else
91 sliceItem->setLayout(sliceData);
92 }
93 }
94
95 update();
96 }
97
98 void PieChartItem::handleSlicesAdded(QList<QPieSlice*> slices)
99 {
75 100 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series));
76 101
77 foreach (QPieSlice *s, slices) {
78 PieSliceItem* item = new PieSliceItem(this);
79 m_slices.insert(s, item);
80 connect(s, SIGNAL(changed()), this, SLOT(handleSliceChanged()));
81 connect(item, SIGNAL(clicked(Qt::MouseButtons)), s, SIGNAL(clicked()));
82 connect(item, SIGNAL(hovered(bool)), s, SIGNAL(hovered(bool)));
102 bool startupAnimation = m_sliceItems.isEmpty();
83 103
84 PieSliceData data = sliceData(s);
104 foreach (QPieSlice *slice, slices) {
105 PieSliceItem* sliceItem = new PieSliceItem(this);
106 m_sliceItems.insert(slice, sliceItem);
107 connect(slice, SIGNAL(changed()), this, SLOT(handleSliceChanged()));
108 connect(sliceItem, SIGNAL(clicked(Qt::MouseButtons)), slice, SIGNAL(clicked()));
109 connect(sliceItem, SIGNAL(hovered(bool)), slice, SIGNAL(hovered(bool)));
85 110
111 PieSliceData sliceData = updateSliceGeometry(slice);
86 112 if (animator())
87 animator()->addAnimation(this, item, data, isEmpty);
113 animator()->addAnimation(this, sliceItem, sliceData, startupAnimation);
88 114 else
89 setLayout(item, data);
115 sliceItem->setLayout(sliceData);
90 116 }
91 117 }
92 118
93 119 void PieChartItem::handleSlicesRemoved(QList<QPieSlice*> slices)
94 120 {
95 121 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series));
96 122
97 123 foreach (QPieSlice *slice, slices) {
98
99 PieSliceItem *item = m_slices.value(slice);
100 Q_ASSERT(item);
101 m_slices.remove(slice);
124 PieSliceItem *sliceItem = m_sliceItems.value(slice);
125 Q_ASSERT(sliceItem);
126 m_sliceItems.remove(slice);
102 127
103 128 if (animator())
104 animator()->removeAnimation(this, item); // animator deletes the PieSliceItem
129 animator()->removeAnimation(this, sliceItem); // animator deletes the PieSliceItem
105 130 else
106 delete item;
131 delete sliceItem;
107 132 }
108 133 }
109 134
110 void PieChartItem::handlePieLayoutChanged()
111 {
112 PieLayout layout = calculateLayout();
113 applyLayout(layout);
114 update();
115 }
116
117 135 void PieChartItem::handleSliceChanged()
118 136 {
119 137 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
120 Q_ASSERT(m_slices.contains(slice));
121 PieSliceData data = sliceData(slice);
122 updateLayout(m_slices.value(slice), data);
123 update();
124 }
125
126 void PieChartItem::handleDomainChanged(qreal, qreal, qreal, qreal)
127 {
128 // TODO
129 }
130
131 void PieChartItem::handleGeometryChanged(const QRectF& rect)
132 {
133 prepareGeometryChange();
134 m_rect = rect;
135 handlePieLayoutChanged();
136 }
137
138 void PieChartItem::calculatePieLayout()
139 {
140 // find pie center coordinates
141 m_pieCenter.setX(m_rect.left() + (m_rect.width() * m_series->horizontalPosition()));
142 m_pieCenter.setY(m_rect.top() + (m_rect.height() * m_series->verticalPosition()));
138 Q_ASSERT(m_sliceItems.contains(slice));
143 139
144 // find maximum radius for pie
145 m_pieRadius = m_rect.height() / 2;
146 if (m_rect.width() < m_rect.height())
147 m_pieRadius = m_rect.width() / 2;
140 PieSliceItem *sliceItem = m_sliceItems.value(slice);
141 PieSliceData sliceData = updateSliceGeometry(slice);
142 if (animator())
143 animator()->updateAnimation(this, sliceItem, sliceData);
144 else
145 sliceItem->setLayout(sliceData);
148 146
149 // apply size factor
150 m_pieRadius *= m_series->pieSize();
147 update();
151 148 }
152 149
153 PieSliceData PieChartItem::sliceData(QPieSlice *slice)
150 PieSliceData PieChartItem::updateSliceGeometry(QPieSlice *slice)
154 151 {
155 // TODO: This function is kid of useless now. Refactor.
156 PieSliceData sliceData = PieSliceData::data(slice);
152 PieSliceData &sliceData = PieSliceData::data(slice);
157 153 sliceData.m_center = PieSliceItem::sliceCenter(m_pieCenter, m_pieRadius, slice);
158 154 sliceData.m_radius = m_pieRadius;
159 155 return sliceData;
160 156 }
161 157
162 PieLayout PieChartItem::calculateLayout()
163 {
164 calculatePieLayout();
165 PieLayout layout;
166 foreach (QPieSlice* s, m_series->slices()) {
167 if (m_slices.contains(s)) // calculate layout only for those slices that are already visible
168 layout.insert(m_slices.value(s), sliceData(s));
169 }
170 return layout;
171 }
172
173 void PieChartItem::applyLayout(const PieLayout &layout)
174 {
175 if (animator())
176 animator()->updateLayout(this, layout);
177 else
178 setLayout(layout);
179 }
180
181 void PieChartItem::updateLayout(PieSliceItem *sliceItem, const PieSliceData &sliceData)
182 {
183 if (animator())
184 animator()->updateLayout(this, sliceItem, sliceData);
185 else
186 setLayout(sliceItem, sliceData);
187 }
188
189 void PieChartItem::setLayout(const PieLayout &layout)
190 {
191 foreach (PieSliceItem *item, layout.keys()) {
192 item->setSliceData(layout.value(item));
193 item->updateGeometry();
194 item->update();
195 }
196 }
197
198 void PieChartItem::setLayout(PieSliceItem *sliceItem, const PieSliceData &sliceData)
199 {
200 Q_ASSERT(sliceItem);
201 sliceItem->setSliceData(sliceData);
202 sliceItem->updateGeometry();
203 sliceItem->update();
204 }
205
206 158 #include "moc_piechartitem_p.cpp"
207 159
208 160 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,77 +1,72
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #ifndef PIECHARTITEM_H
22 22 #define PIECHARTITEM_H
23 23
24 24 #include "qpieseries.h"
25 25 #include "chartitem_p.h"
26 26 #include "piesliceitem_p.h"
27 27
28 28 class QGraphicsItem;
29 29 QTCOMMERCIALCHART_BEGIN_NAMESPACE
30 30 class QPieSlice;
31 31 class ChartPresenter;
32 32
33 typedef QHash<PieSliceItem*, PieSliceData> PieLayout;
34
35 33 class PieChartItem : public ChartItem
36 34 {
37 35 Q_OBJECT
38 36
39 37 public:
40 // TODO: use a generic data class instead of x and y
41 PieChartItem(QPieSeries *series, ChartPresenter *presenter);
38 explicit PieChartItem(QPieSeries *series, ChartPresenter *presenter);
42 39 ~PieChartItem();
43 40
44 public: // from QGraphicsItem
41 // from QGraphicsItem
45 42 QRectF boundingRect() const { return m_rect; }
46 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
43 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) {}
47 44
48 45 public Q_SLOTS:
46 // from Chart
47 virtual void handleGeometryChanged(const QRectF &rect);
48 // TODO: Do we have actual need for these at all? What is the use case for pie?
49 //virtual void handleDomainChanged(qreal minX, qreal maxX, qreal minY, qreal maxY);
50 //virtual void rangeXChanged(qreal min, qreal max, int tickXCount);
51 //virtual void rangeYChanged(qreal min, qreal max, int tickYCount);
52
49 53 void initialize();
54 void updateLayout();
50 55 void handleSlicesAdded(QList<QPieSlice*> slices);
51 56 void handleSlicesRemoved(QList<QPieSlice*> slices);
52 void handlePieLayoutChanged();
53 57 void handleSliceChanged();
54 void handleDomainChanged(qreal, qreal, qreal, qreal);
55 void handleGeometryChanged(const QRectF& rect);
56 58
57 public:
58 void calculatePieLayout();
59 PieSliceData sliceData(QPieSlice *slice);
60 PieLayout calculateLayout();
61 void applyLayout(const PieLayout &layout);
62 void updateLayout(PieSliceItem *sliceItem, const PieSliceData &sliceData);
63 void setLayout(const PieLayout &layout);
64 void setLayout(PieSliceItem *sliceItem, const PieSliceData &sliceData);
59 private:
60 PieSliceData updateSliceGeometry(QPieSlice *slice);
65 61
66 62 private:
67 friend class PieSliceItem;
68 QHash<QPieSlice*, PieSliceItem*> m_slices;
63 QHash<QPieSlice*, PieSliceItem*> m_sliceItems;
69 64 QPieSeries *m_series;
70 65 QRectF m_rect;
71 66 QPointF m_pieCenter;
72 67 qreal m_pieRadius;
73 68 };
74 69
75 70 QTCOMMERCIALCHART_END_NAMESPACE
76 71
77 72 #endif // PIECHARTITEM_H
@@ -1,212 +1,214
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "piesliceitem_p.h"
22 22 #include "piechartitem_p.h"
23 23 #include "qpieseries.h"
24 24 #include "qpieslice.h"
25 25 #include "chartpresenter_p.h"
26 26 #include <QPainter>
27 27 #include <qmath.h>
28 28 #include <QGraphicsSceneEvent>
29 29 #include <QTime>
30 30
31 31 QTCOMMERCIALCHART_BEGIN_NAMESPACE
32 32
33 33 #define PI 3.14159265 // TODO: is this defined in some header?
34 34
35 35 QPointF offset(qreal angle, qreal length)
36 36 {
37 37 qreal dx = qSin(angle*(PI/180)) * length;
38 38 qreal dy = qCos(angle*(PI/180)) * length;
39 39 return QPointF(dx, -dy);
40 40 }
41 41
42 42 PieSliceItem::PieSliceItem(QGraphicsItem* parent)
43 43 :QGraphicsObject(parent)
44 44 {
45 45 setAcceptHoverEvents(true);
46 46 setAcceptedMouseButtons(Qt::MouseButtonMask);
47 47 setZValue(ChartPresenter::PieSeriesZValue);
48 48 }
49 49
50 50 PieSliceItem::~PieSliceItem()
51 51 {
52 52
53 53 }
54 54
55 55 QRectF PieSliceItem::boundingRect() const
56 56 {
57 57 return m_boundingRect;
58 58 }
59 59
60 60 QPainterPath PieSliceItem::shape() const
61 61 {
62 62 // Don't include the label and label arm.
63 63 // This is used to detect a mouse clicks. We do not want clicks from label.
64 64 return m_slicePath;
65 65 }
66 66
67 67 void PieSliceItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
68 68 {
69 69 painter->save();
70 70 painter->setClipRect(parentItem()->boundingRect());
71 71 painter->setPen(m_data.m_slicePen);
72 72 painter->setBrush(m_data.m_sliceBrush);
73 73 painter->drawPath(m_slicePath);
74 74 painter->restore();
75 75
76 76 if (m_data.m_isLabelVisible) {
77 77 painter->setClipRect(parentItem()->boundingRect());
78 78 painter->setPen(m_data.m_labelPen);
79 79 painter->drawPath(m_labelArmPath);
80 80 // the pen color will affect the font color as well
81 81 painter->setFont(m_data.m_labelFont);
82 82 painter->drawText(m_labelTextRect.bottomLeft(), m_data.m_labelText);
83 83 }
84 84 }
85 85
86 86 void PieSliceItem::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
87 87 {
88 88 emit hovered(true);
89 89 }
90 90
91 91 void PieSliceItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
92 92 {
93 93 emit hovered(false);
94 94 }
95 95
96 96 void PieSliceItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
97 97 {
98 98 emit clicked(event->buttons());
99 99 }
100 100
101 void PieSliceItem::setSliceData(PieSliceData sliceData)
101 void PieSliceItem::setLayout(const PieSliceData &sliceData)
102 102 {
103 103 m_data = sliceData;
104 updateGeometry();
105 update();
104 106 }
105 107
106 108 void PieSliceItem::updateGeometry()
107 109 {
108 110 if (m_data.m_radius <= 0)
109 111 return;
110 112
111 113 prepareGeometryChange();
112 114
113 115 // update slice path
114 116 qreal centerAngle;
115 117 QPointF armStart;
116 118 m_slicePath = slicePath(m_data.m_center, m_data.m_radius, m_data.m_startAngle, m_data.m_angleSpan, &centerAngle, &armStart);
117 119
118 120 // update text rect
119 121 m_labelTextRect = labelTextRect(m_data.m_labelFont, m_data.m_labelText);
120 122
121 123 // update label arm path
122 124 QPointF labelTextStart;
123 125 m_labelArmPath = labelArmPath(armStart, centerAngle, m_data.m_radius * m_data.m_labelArmLengthFactor, m_labelTextRect.width(), &labelTextStart);
124 126
125 127 // update text position
126 128 m_labelTextRect.moveBottomLeft(labelTextStart);
127 129
128 130 // update bounding rect
129 131 if (m_data.m_isLabelVisible)
130 132 m_boundingRect = m_slicePath.boundingRect().united(m_labelArmPath.boundingRect()).united(m_labelTextRect);
131 133 else
132 134 m_boundingRect = m_slicePath.boundingRect();
133 135 }
134 136
135 137 QPointF PieSliceItem::sliceCenter(QPointF point, qreal radius, QPieSlice *slice)
136 138 {
137 139 if (slice->isExploded()) {
138 140 qreal centerAngle = slice->startAngle() + ((slice->endAngle() - slice->startAngle())/2);
139 141 qreal len = radius * slice->explodeDistanceFactor();
140 142 qreal dx = qSin(centerAngle*(PI/180)) * len;
141 143 qreal dy = -qCos(centerAngle*(PI/180)) * len;
142 144 point += QPointF(dx, dy);
143 145 }
144 146 return point;
145 147 }
146 148
147 149 QPainterPath PieSliceItem::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal *centerAngle, QPointF* armStart)
148 150 {
149 151 // calculate center angle
150 152 *centerAngle = startAngle + (angleSpan/2);
151 153
152 154 // calculate slice rectangle
153 155 QRectF rect(center.x()-radius, center.y()-radius, radius*2, radius*2);
154 156
155 157 // slice path
156 158 // TODO: draw the shape so that it might have a hole in the center
157 159 QPainterPath path;
158 160 path.moveTo(rect.center());
159 161 path.arcTo(rect, -startAngle + 90, -angleSpan);
160 162 path.closeSubpath();
161 163
162 164 // calculate label arm start point
163 165 *armStart = center;
164 166 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
165 167
166 168 return path;
167 169 }
168 170
169 171 QPainterPath PieSliceItem::labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF *textStart)
170 172 {
171 173 // prevent label arm pointing straight down because it will look bad
172 174 if (angle < 180 && angle > 170)
173 175 angle = 170;
174 176 if (angle > 180 && angle < 190)
175 177 angle = 190;
176 178
177 179 // line from slice to label
178 180 qreal dx = qSin(angle*(PI/180)) * length;
179 181 qreal dy = -qCos(angle*(PI/180)) * length;
180 182 QPointF parm1 = start + QPointF(dx, dy);
181 183
182 184 // line to underline the label
183 185 QPointF parm2 = parm1;
184 186 if (angle < 180) { // arm swings the other way on the left side
185 187 parm2 += QPointF(textWidth, 0);
186 188 *textStart = parm1;
187 189 }
188 190 else {
189 191 parm2 += QPointF(-textWidth,0);
190 192 *textStart = parm2;
191 193 }
192 194
193 195 // elevate the text position a bit so that it does not hit the line
194 196 *textStart += QPointF(0, -3);
195 197
196 198 QPainterPath path;
197 199 path.moveTo(start);
198 200 path.lineTo(parm1);
199 201 path.lineTo(parm2);
200 202
201 203 return path;
202 204 }
203 205
204 206 QRectF PieSliceItem::labelTextRect(QFont font, QString text)
205 207 {
206 208 QFontMetricsF fm(font);
207 209 return fm.boundingRect(text);
208 210 }
209 211
210 212 #include "moc_piesliceitem_p.cpp"
211 213
212 214 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,78 +1,79
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #ifndef PIESLICEITEM_H
22 22 #define PIESLICEITEM_H
23 23
24 24 #include "qchartglobal.h"
25 25 #include "charttheme_p.h"
26 26 #include "qpieseries.h"
27 27 #include "pieslicedata_p.h"
28 28 #include <QGraphicsItem>
29 29 #include <QRectF>
30 30 #include <QColor>
31 31 #include <QPen>
32 32
33 33 #define PIESLICE_LABEL_GAP 5
34 34
35 35 QTCOMMERCIALCHART_BEGIN_NAMESPACE
36 36 class PieChartItem;
37 37 class PieSliceLabel;
38 38 class QPieSlice;
39 39
40 40 class PieSliceItem : public QGraphicsObject
41 41 {
42 42 Q_OBJECT
43 43
44 44 public:
45 45 PieSliceItem(QGraphicsItem* parent = 0);
46 46 ~PieSliceItem();
47 47
48 public: // from QGraphicsItem
48 // from QGraphicsItem
49 49 QRectF boundingRect() const;
50 50 QPainterPath shape() const;
51 51 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
52 52 void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
53 53 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
54 54 void mousePressEvent(QGraphicsSceneMouseEvent *event);
55 55
56 void setLayout(const PieSliceData &sliceData);
57 static QPointF sliceCenter(QPointF point, qreal radius, QPieSlice *slice);
58
56 59 Q_SIGNALS:
57 60 void clicked(Qt::MouseButtons buttons);
58 61 void hovered(bool state);
59 62
60 public:
61 void setSliceData(PieSliceData sliceData);
63 private:
62 64 void updateGeometry();
63 static QPointF sliceCenter(QPointF point, qreal radius, QPieSlice *slice);
64 65 QPainterPath slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal *centerAngle, QPointF *armStart);
65 66 QPainterPath labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF *textStart);
66 67 QRectF labelTextRect(QFont font, QString text);
67 68
68 69 private:
69 70 PieSliceData m_data;
70 71 QRectF m_boundingRect;
71 72 QPainterPath m_slicePath;
72 73 QPainterPath m_labelArmPath;
73 74 QRectF m_labelTextRect;
74 75 };
75 76
76 77 QTCOMMERCIALCHART_END_NAMESPACE
77 78
78 79 #endif // PIESLICEITEM_H
General Comments 0
You need to be logged in to leave comments. Login now