##// END OF EJS Templates
Add animations to pie. Works but has some visual issues when adding slices.
Jani Honkonen -
r618:249071e508d1
parent child
Show More
@@ -0,0 +1,94
1 #include "PieAnimation_p.h"
2 #include "piesliceanimation_p.h"
3 #include "piechartitem_p.h"
4 #include <QParallelAnimationGroup>
5 #include <QTimer>
6
7 QTCOMMERCIALCHART_BEGIN_NAMESPACE
8
9 PieAnimation::PieAnimation(PieChartItem *item)
10 :ChartAnimation(item),
11 m_item(item)
12 {
13 }
14
15 PieAnimation::~PieAnimation()
16 {
17 }
18
19 void PieAnimation::setValues(QVector<PieSliceLayout>& newValues)
20 {
21 PieSliceAnimation *animation = 0;
22
23 foreach (PieSliceLayout endLayout, newValues) {
24 animation = m_animations.value(endLayout.m_data);
25 if (animation) {
26 // existing slice
27 animation->stop();
28 animation->updateValue(endLayout);
29 } else {
30 // new slice
31 animation = new PieSliceAnimation(m_item);
32 m_animations.insert(endLayout.m_data, animation);
33 PieSliceLayout startLayout = endLayout;
34 startLayout.m_radius = 0;
35 //startLayout.m_startAngle = 0;
36 //startLayout.m_angleSpan = 0;
37 animation->setValue(startLayout, endLayout);
38 }
39 animation->setDuration(1000);
40 animation->setEasingCurve(QEasingCurve::OutQuart);
41 QTimer::singleShot(0, animation, SLOT(start())); // TODO: use sequential animation?
42 }
43
44 foreach (QPieSlice *s, m_animations.keys()) {
45 bool isFound = false;
46 foreach (PieSliceLayout layout, newValues) {
47 if (s == layout.m_data)
48 isFound = true;
49 }
50 if (!isFound) {
51 // slice has been deleted
52 animation = m_animations.value(s);
53 animation->stop();
54 PieSliceLayout endLayout = m_animations.value(s)->currentSliceValue();
55 endLayout.m_radius = 0;
56 // TODO: find the actual angle where this slice disappears
57 endLayout.m_startAngle = endLayout.m_startAngle + endLayout.m_angleSpan;
58 endLayout.m_angleSpan = 0;
59 animation->updateValue(endLayout);
60 animation->setDuration(1000);
61 animation->setEasingCurve(QEasingCurve::OutQuart);
62 connect(animation, SIGNAL(finished()), this, SLOT(destroySliceAnimationComplete()));
63 QTimer::singleShot(0, animation, SLOT(start()));
64 }
65 }
66 }
67
68 void PieAnimation::updateValue(PieSliceLayout& endLayout)
69 {
70 PieSliceAnimation *animation = m_animations.value(endLayout.m_data);
71 Q_ASSERT(animation);
72 animation->stop();
73 animation->updateValue(endLayout);
74 animation->setDuration(1000);
75 animation->setEasingCurve(QEasingCurve::OutQuart);
76 QTimer::singleShot(0, animation, SLOT(start()));
77 }
78
79 void PieAnimation::updateCurrentValue(const QVariant &)
80 {
81 // nothing to do...
82 }
83
84 void PieAnimation::destroySliceAnimationComplete()
85 {
86 PieSliceAnimation *animation = static_cast<PieSliceAnimation*>(sender());
87 QPieSlice *slice = m_animations.key(animation);
88 m_item->destroySlice(slice);
89 delete m_animations.take(slice);
90 }
91
92 #include "moc_pieanimation_p.cpp"
93
94 QTCOMMERCIALCHART_END_NAMESPACE
@@ -0,0 +1,35
1 #ifndef PIEANIMATION_P_H_
2 #define PIEANIMATION_P_H_
3
4 #include "chartanimation_p.h"
5 #include "piechartitem_p.h"
6 #include "piesliceanimation_p.h"
7
8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9
10 class PieChartItem;
11
12 class PieAnimation : public ChartAnimation
13 {
14 Q_OBJECT
15
16 public:
17 PieAnimation(PieChartItem *item);
18 ~PieAnimation();
19 void setValues(QVector<PieSliceLayout>& newValues);
20 void updateValue(PieSliceLayout& newValue);
21
22 public: // from QVariantAnimation
23 void updateCurrentValue(const QVariant &value);
24
25 public Q_SLOTS:
26 void destroySliceAnimationComplete();
27
28 private:
29 PieChartItem *m_item;
30 QHash<QPieSlice*, PieSliceAnimation*> m_animations;
31 };
32
33 QTCOMMERCIALCHART_END_NAMESPACE
34
35 #endif
@@ -0,0 +1,77
1 #include "PieSliceAnimation_p.h"
2 #include "piechartitem_p.h"
3 #include "qpieslice.h"
4
5 Q_DECLARE_METATYPE(QtCommercialChart::PieSliceLayout)
6
7 QTCOMMERCIALCHART_BEGIN_NAMESPACE
8
9 qreal linearPos(qreal start, qreal end, qreal pos)
10 {
11 return start + ((end - start) * pos);
12 }
13
14 QPointF linearPos(QPointF start, QPointF end, qreal pos)
15 {
16 qreal x = linearPos(start.x(), end.x(), pos);
17 qreal y = linearPos(start.y(), end.y(), pos);
18 return QPointF(x, y);
19 }
20
21 PieSliceAnimation::PieSliceAnimation(PieChartItem *item)
22 :QVariantAnimation(item),
23 m_item(item)
24 {
25 }
26
27 PieSliceAnimation::~PieSliceAnimation()
28 {
29 }
30
31 void PieSliceAnimation::setValue(PieSliceLayout& startValue, PieSliceLayout& endValue)
32 {
33 if (state() != QAbstractAnimation::Stopped)
34 stop();
35
36 setKeyValueAt(0.0, qVariantFromValue(startValue));
37 setKeyValueAt(1.0, qVariantFromValue(endValue));
38 }
39
40 void PieSliceAnimation::updateValue(PieSliceLayout& endValue)
41 {
42 if (state() != QAbstractAnimation::Stopped)
43 stop();
44
45 //qDebug() << "PieSliceAnimation::updateValue()" << endValue.m_data->label() << currentSliceValue().m_startAngle << endValue.m_startAngle;
46
47 setKeyValueAt(0.0, qVariantFromValue(currentSliceValue()));
48 setKeyValueAt(1.0, qVariantFromValue(endValue));
49 }
50
51 PieSliceLayout PieSliceAnimation::currentSliceValue()
52 {
53 return qVariantValue<PieSliceLayout>(currentValue());
54 }
55
56 QVariant PieSliceAnimation::interpolated(const QVariant &start, const QVariant &end, qreal progress) const
57 {
58 PieSliceLayout startValue = qVariantValue<PieSliceLayout>(start);
59 PieSliceLayout endValue = qVariantValue<PieSliceLayout>(end);
60
61 PieSliceLayout result;
62 result = endValue;
63 result.m_center = linearPos(startValue.m_center, endValue.m_center, progress);
64 result.m_radius = linearPos(startValue.m_radius, endValue.m_radius, progress);
65 result.m_startAngle = linearPos(startValue.m_startAngle, endValue.m_startAngle, progress);
66 result.m_angleSpan = linearPos(startValue.m_angleSpan, endValue.m_angleSpan, progress);
67
68 return qVariantFromValue(result);
69 }
70
71 void PieSliceAnimation::updateCurrentValue(const QVariant &value)
72 {
73 if (state() != QAbstractAnimation::Stopped) //workaround
74 m_item->setLayout(qVariantValue<PieSliceLayout>(value));
75 }
76
77 QTCOMMERCIALCHART_END_NAMESPACE
@@ -0,0 +1,30
1 #ifndef PIESLICEANIMATION_P_H_
2 #define PIESLICEANIMATION_P_H_
3
4 #include "piechartitem_p.h"
5 #include <QVariantAnimation>
6
7 QTCOMMERCIALCHART_BEGIN_NAMESPACE
8
9 class PieChartItem;
10
11 class PieSliceAnimation : public QVariantAnimation
12 {
13 public:
14 PieSliceAnimation(PieChartItem *item);
15 ~PieSliceAnimation();
16 void setValue(PieSliceLayout& startValue, PieSliceLayout& endValue);
17 void updateValue(PieSliceLayout& endValue);
18 PieSliceLayout currentSliceValue();
19
20 protected:
21 QVariant interpolated(const QVariant &start, const QVariant &end, qreal progress) const;
22 void updateCurrentValue(const QVariant &value);
23
24 private:
25 PieChartItem *m_item;
26 };
27
28 QTCOMMERCIALCHART_END_NAMESPACE
29
30 #endif
@@ -1,560 +1,582
1 1 #include <QtGui/QApplication>
2 2 #include <QMainWindow>
3 3 #include <qchartglobal.h>
4 4 #include <qchartview.h>
5 5 #include <qpieseries.h>
6 6 #include <qpieslice.h>
7 7 #include <QGridLayout>
8 8 #include <QFormLayout>
9 9 #include <QComboBox>
10 10 #include <QSpinBox>
11 11 #include <QCheckBox>
12 12 #include <QGroupBox>
13 13 #include <QLabel>
14 14 #include <QPushButton>
15 15 #include <QColorDialog>
16 16 #include <QFontDialog>
17 17
18 18 QTCOMMERCIALCHART_USE_NAMESPACE
19 19
20 20 class PenTool : public QWidget
21 21 {
22 22 Q_OBJECT
23 23
24 24 public:
25 25 explicit PenTool(QString title, QWidget *parent = 0)
26 26 :QWidget(parent)
27 27 {
28 28 setWindowTitle(title);
29 29 setWindowFlags(Qt::Tool);
30 30
31 31 m_colorButton = new QPushButton();
32 32
33 33 m_widthSpinBox = new QDoubleSpinBox();
34 34
35 35 m_styleCombo = new QComboBox();
36 36 m_styleCombo->addItem("NoPen");
37 37 m_styleCombo->addItem("SolidLine");
38 38 m_styleCombo->addItem("DashLine");
39 39 m_styleCombo->addItem("DotLine");
40 40 m_styleCombo->addItem("DashDotLine");
41 41 m_styleCombo->addItem("DashDotDotLine");
42 42
43 43 m_capStyleCombo = new QComboBox();
44 44 m_capStyleCombo->addItem("FlatCap", Qt::FlatCap);
45 45 m_capStyleCombo->addItem("SquareCap", Qt::SquareCap);
46 46 m_capStyleCombo->addItem("RoundCap", Qt::RoundCap);
47 47
48 48 m_joinStyleCombo = new QComboBox();
49 49 m_joinStyleCombo->addItem("MiterJoin", Qt::MiterJoin);
50 50 m_joinStyleCombo->addItem("BevelJoin", Qt::BevelJoin);
51 51 m_joinStyleCombo->addItem("RoundJoin", Qt::RoundJoin);
52 52 m_joinStyleCombo->addItem("SvgMiterJoin", Qt::SvgMiterJoin);
53 53
54 54 QFormLayout *layout = new QFormLayout();
55 55 layout->addRow("Color", m_colorButton);
56 56 layout->addRow("Width", m_widthSpinBox);
57 57 layout->addRow("Style", m_styleCombo);
58 58 layout->addRow("Cap style", m_capStyleCombo);
59 59 layout->addRow("Join style", m_joinStyleCombo);
60 60 setLayout(layout);
61 61
62 62 connect(m_colorButton, SIGNAL(clicked()), this, SLOT(showColorDialog()));
63 63 connect(m_widthSpinBox, SIGNAL(valueChanged(double)), this, SLOT(updateWidth(double)));
64 64 connect(m_styleCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateStyle(int)));
65 65 connect(m_capStyleCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateCapStyle(int)));
66 66 connect(m_joinStyleCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateJoinStyle(int)));
67 67 }
68 68
69 69 void setPen(QPen pen)
70 70 {
71 71 m_pen = pen;
72 72 m_colorButton->setText(m_pen.color().name());
73 73 m_widthSpinBox->setValue(m_pen.widthF());
74 74 m_styleCombo->setCurrentIndex(m_pen.style()); // index matches the enum
75 75 m_capStyleCombo->setCurrentIndex(m_capStyleCombo->findData(m_pen.capStyle()));
76 76 m_joinStyleCombo->setCurrentIndex(m_joinStyleCombo->findData(m_pen.joinStyle()));
77 77 }
78 78
79 79 QPen pen() const
80 80 {
81 81 return m_pen;
82 82 }
83 83
84 84 QString name()
85 85 {
86 86 return name(m_pen);
87 87 }
88 88
89 89 static QString name(const QPen &pen)
90 90 {
91 91 return pen.color().name() + ":" + QString::number(pen.widthF());
92 92 }
93 93
94 94 Q_SIGNALS:
95 95 void changed();
96 96
97 97 public Q_SLOTS:
98 98
99 99 void showColorDialog()
100 100 {
101 101 QColorDialog dialog(m_pen.color());
102 102 dialog.show();
103 103 dialog.exec();
104 104 m_pen.setColor(dialog.selectedColor());
105 105 m_colorButton->setText(m_pen.color().name());
106 106 emit changed();
107 107 }
108 108
109 109 void updateWidth(double width)
110 110 {
111 111 if (width != m_pen.widthF()) {
112 112 m_pen.setWidthF(width);
113 113 emit changed();
114 114 }
115 115 }
116 116
117 117 void updateStyle(int style)
118 118 {
119 119 if (m_pen.style() != style) {
120 120 m_pen.setStyle((Qt::PenStyle) style);
121 121 emit changed();
122 122 }
123 123 }
124 124
125 125 void updateCapStyle(int index)
126 126 {
127 127 Qt::PenCapStyle capStyle = (Qt::PenCapStyle) m_capStyleCombo->itemData(index).toInt();
128 128 if (m_pen.capStyle() != capStyle) {
129 129 m_pen.setCapStyle(capStyle);
130 130 emit changed();
131 131 }
132 132 }
133 133
134 134 void updateJoinStyle(int index)
135 135 {
136 136 Qt::PenJoinStyle joinStyle = (Qt::PenJoinStyle) m_joinStyleCombo->itemData(index).toInt();
137 137 if (m_pen.joinStyle() != joinStyle) {
138 138 m_pen.setJoinStyle(joinStyle);
139 139 emit changed();
140 140 }
141 141 }
142 142
143 143 private:
144 144 QPen m_pen;
145 145 QPushButton *m_colorButton;
146 146 QDoubleSpinBox *m_widthSpinBox;
147 147 QComboBox *m_styleCombo;
148 148 QComboBox *m_capStyleCombo;
149 149 QComboBox *m_joinStyleCombo;
150 150 };
151 151
152 152 class BrushTool : public QWidget
153 153 {
154 154 Q_OBJECT
155 155
156 156 public:
157 157 explicit BrushTool(QString title, QWidget *parent = 0)
158 158 :QWidget(parent)
159 159 {
160 160 setWindowTitle(title);
161 161 setWindowFlags(Qt::Tool);
162 162
163 163 m_colorButton = new QPushButton();
164 164 m_styleCombo = new QComboBox();
165 165 m_styleCombo->addItem("Nobrush", Qt::NoBrush);
166 166 m_styleCombo->addItem("Solidpattern", Qt::SolidPattern);
167 167 m_styleCombo->addItem("Dense1pattern", Qt::Dense1Pattern);
168 168 m_styleCombo->addItem("Dense2attern", Qt::Dense2Pattern);
169 169 m_styleCombo->addItem("Dense3Pattern", Qt::Dense3Pattern);
170 170 m_styleCombo->addItem("Dense4Pattern", Qt::Dense4Pattern);
171 171 m_styleCombo->addItem("Dense5Pattern", Qt::Dense5Pattern);
172 172 m_styleCombo->addItem("Dense6Pattern", Qt::Dense6Pattern);
173 173 m_styleCombo->addItem("Dense7Pattern", Qt::Dense7Pattern);
174 174 m_styleCombo->addItem("HorPattern", Qt::HorPattern);
175 175 m_styleCombo->addItem("VerPattern", Qt::VerPattern);
176 176 m_styleCombo->addItem("CrossPattern", Qt::CrossPattern);
177 177 m_styleCombo->addItem("BDiagPattern", Qt::BDiagPattern);
178 178 m_styleCombo->addItem("FDiagPattern", Qt::FDiagPattern);
179 179 m_styleCombo->addItem("DiagCrossPattern", Qt::DiagCrossPattern);
180 180
181 181 QFormLayout *layout = new QFormLayout();
182 182 layout->addRow("Color", m_colorButton);
183 183 layout->addRow("Style", m_styleCombo);
184 184 setLayout(layout);
185 185
186 186 connect(m_colorButton, SIGNAL(clicked()), this, SLOT(showColorDialog()));
187 187 connect(m_styleCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateStyle()));
188 188 }
189 189
190 190 void setBrush(QBrush brush)
191 191 {
192 192 m_brush = brush;
193 193 m_colorButton->setText(m_brush.color().name());
194 194 m_styleCombo->setCurrentIndex(m_brush.style()); // index matches the enum
195 195 }
196 196
197 197 QBrush brush() const
198 198 {
199 199 return m_brush;
200 200 }
201 201
202 202 QString name()
203 203 {
204 204 return name(m_brush);
205 205 }
206 206
207 207 static QString name(const QBrush &brush)
208 208 {
209 209 return brush.color().name();
210 210 }
211 211
212 212 Q_SIGNALS:
213 213 void changed();
214 214
215 215 public Q_SLOTS:
216 216
217 217 void showColorDialog()
218 218 {
219 219 QColorDialog dialog(m_brush.color());
220 220 dialog.show();
221 221 dialog.exec();
222 222 m_brush.setColor(dialog.selectedColor());
223 223 m_colorButton->setText(m_brush.color().name());
224 224 emit changed();
225 225 }
226 226
227 227 void updateStyle()
228 228 {
229 229 Qt::BrushStyle style = (Qt::BrushStyle) m_styleCombo->itemData(m_styleCombo->currentIndex()).toInt();
230 230 if (m_brush.style() != style) {
231 231 m_brush.setStyle(style);
232 232 emit changed();
233 233 }
234 234 }
235 235
236 236 private:
237 237 QBrush m_brush;
238 238 QPushButton *m_colorButton;
239 239 QComboBox *m_styleCombo;
240 240 };
241 241
242 242 class CustomSlice : public QPieSlice
243 243 {
244 244 Q_OBJECT
245 245 public:
246 246 CustomSlice(qreal value, QString label)
247 247 :QPieSlice(value, label)
248 248 {
249 249 connect(this, SIGNAL(hoverEnter()), this, SLOT(handleHoverEnter()));
250 250 connect(this, SIGNAL(hoverLeave()), this, SLOT(handleHoverLeave()));
251 251 }
252 252
253 253 public:
254 254 QBrush originalBrush()
255 255 {
256 256 return m_originalBrush;
257 257 }
258 258
259 259 public Q_SLOTS:
260 260
261 261 void handleHoverEnter()
262 262 {
263 263 QBrush brush = this->sliceBrush();
264 264 m_originalBrush = brush;
265 265 brush.setColor(brush.color().lighter());
266 266 setSliceBrush(brush);
267 267 }
268 268
269 269 void handleHoverLeave()
270 270 {
271 271 setSliceBrush(m_originalBrush);
272 272 }
273 273
274 274 private:
275 275 QBrush m_originalBrush;
276 276 };
277 277
278 278 class MainWidget : public QWidget
279 279 {
280 280 Q_OBJECT
281 281
282 282 public:
283 283 explicit MainWidget(QWidget* parent = 0)
284 284 :QWidget(parent),
285 285 m_slice(0)
286 286 {
287 287 // create chart
288 288 m_chartView = new QChartView();
289 289 m_chartView->setChartTitle("Piechart customization");
290 m_chartView->setAnimationOptions(QChart::AllAnimations);
290 291
291 292 // create series
292 293 m_series = new QPieSeries();
293 294 *m_series << new CustomSlice(10.0, "Slice 1");
294 295 *m_series << new CustomSlice(20.0, "Slice 2");
295 296 *m_series << new CustomSlice(30.0, "Slice 3");
296 297 *m_series << new CustomSlice(40.0, "Slice 4");
297 298 *m_series << new CustomSlice(50.0, "Slice 5");
298 299 m_chartView->addSeries(m_series);
299 300
300 301 connect(m_series, SIGNAL(clicked(QPieSlice*)), this, SLOT(handleSliceClicked(QPieSlice*)));
301 302
302 303 // chart settings
303 304 m_themeComboBox = new QComboBox();
304 305 m_themeComboBox->addItem("Default", QChart::ChartThemeDefault);
305 306 m_themeComboBox->addItem("Vanilla", QChart::ChartThemeVanilla);
306 307 m_themeComboBox->addItem("Icy", QChart::ChartThemeIcy);
307 308 m_themeComboBox->addItem("Grayscale", QChart::ChartThemeGrayscale);
308 309 m_themeComboBox->addItem("Scientific", QChart::ChartThemeScientific);
309 310
310 311 m_aaCheckBox = new QCheckBox();
311 312
312 313 QFormLayout* chartSettingsLayout = new QFormLayout();
313 314 chartSettingsLayout->addRow("Theme", m_themeComboBox);
314 315 chartSettingsLayout->addRow("Antialiasing", m_aaCheckBox);
315 316 QGroupBox* chartSettings = new QGroupBox("Chart");
316 317 chartSettings->setLayout(chartSettingsLayout);
317 318
318 319 connect(m_themeComboBox, SIGNAL(currentIndexChanged(int)), this ,SLOT(updateChartSettings()));
319 320 connect(m_aaCheckBox, SIGNAL(toggled(bool)), this ,SLOT(updateChartSettings()));
320 321
321 322 // series settings
322 323 m_hPosition = new QDoubleSpinBox();
323 324 m_hPosition->setMinimum(0.0);
324 325 m_hPosition->setMaximum(1.0);
325 326 m_hPosition->setSingleStep(0.1);
326 327 m_hPosition->setValue(m_series->pieHorizontalPosition());
327 328
328 329 m_vPosition = new QDoubleSpinBox();
329 330 m_vPosition->setMinimum(0.0);
330 331 m_vPosition->setMaximum(1.0);
331 332 m_vPosition->setSingleStep(0.1);
332 333 m_vPosition->setValue(m_series->pieVerticalPosition());
333 334
334 335 m_sizeFactor = new QDoubleSpinBox();
335 336 m_sizeFactor->setMinimum(0.0);
336 337 m_sizeFactor->setMaximum(1.0);
337 338 m_sizeFactor->setSingleStep(0.1);
338 339 m_sizeFactor->setValue(m_series->pieSize());
339 340
340 341 m_startAngle = new QDoubleSpinBox();
341 342 m_startAngle->setMinimum(0.0);
342 343 m_startAngle->setMaximum(360);
343 344 m_startAngle->setValue(m_series->pieStartAngle());
344 345 m_startAngle->setSingleStep(1);
345 346
346 347 m_endAngle = new QDoubleSpinBox();
347 348 m_endAngle->setMinimum(0.0);
348 349 m_endAngle->setMaximum(360);
349 350 m_endAngle->setValue(m_series->pieEndAngle());
350 351 m_endAngle->setSingleStep(1);
351 352
353 QPushButton *addSlice = new QPushButton("Add slice");
354
352 355 QFormLayout* seriesSettingsLayout = new QFormLayout();
353 356 seriesSettingsLayout->addRow("Horizontal position", m_hPosition);
354 357 seriesSettingsLayout->addRow("Vertical position", m_vPosition);
355 358 seriesSettingsLayout->addRow("Size factor", m_sizeFactor);
356 359 seriesSettingsLayout->addRow("Start angle", m_startAngle);
357 360 seriesSettingsLayout->addRow("End angle", m_endAngle);
361 seriesSettingsLayout->addRow(addSlice);
358 362 QGroupBox* seriesSettings = new QGroupBox("Series");
359 363 seriesSettings->setLayout(seriesSettingsLayout);
360 364
361 365 connect(m_vPosition, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings()));
362 366 connect(m_hPosition, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings()));
363 367 connect(m_sizeFactor, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings()));
364 368 connect(m_startAngle, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings()));
365 369 connect(m_endAngle, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings()));
370 connect(addSlice, SIGNAL(clicked()), this, SLOT(addSlice()));
366 371
367 372 // slice settings
368 373 m_sliceName = new QLabel("<click a slice>");
369 374 m_sliceValue = new QDoubleSpinBox();
370 375 m_sliceValue->setMaximum(1000);
371 376 m_sliceLabelVisible = new QCheckBox();
372 377 m_sliceLabelArmFactor = new QDoubleSpinBox();
373 378 m_sliceLabelArmFactor->setSingleStep(0.01);
374 379 m_sliceExploded = new QCheckBox();
375 380 m_sliceExplodedFactor = new QDoubleSpinBox();
376 381 m_sliceExplodedFactor->setSingleStep(0.01);
377 382 m_pen = new QPushButton();
378 383 m_penTool = new PenTool("Slice pen", this);
379 384 m_brush = new QPushButton();
380 385 m_brushTool = new BrushTool("Slice brush", this);
381 386 m_font = new QPushButton();
382 387 m_labelArmPen = new QPushButton();
383 388 m_labelArmPenTool = new PenTool("Label arm pen", this);
389 QPushButton *removeSlice = new QPushButton("Remove slice");
384 390
385 391 QFormLayout* sliceSettingsLayout = new QFormLayout();
386 392 sliceSettingsLayout->addRow("Selected", m_sliceName);
387 393 sliceSettingsLayout->addRow("Value", m_sliceValue);
388 394 sliceSettingsLayout->addRow("Pen", m_pen);
389 395 sliceSettingsLayout->addRow("Brush", m_brush);
390 396 sliceSettingsLayout->addRow("Label visible", m_sliceLabelVisible);
391 397 sliceSettingsLayout->addRow("Label font", m_font);
392 398 sliceSettingsLayout->addRow("Label arm pen", m_labelArmPen);
393 399 sliceSettingsLayout->addRow("Label arm length", m_sliceLabelArmFactor);
394 400 sliceSettingsLayout->addRow("Exploded", m_sliceExploded);
395 401 sliceSettingsLayout->addRow("Explode distance", m_sliceExplodedFactor);
402 sliceSettingsLayout->addRow(removeSlice);
396 403 QGroupBox* sliceSettings = new QGroupBox("Slice");
397 404 sliceSettings->setLayout(sliceSettingsLayout);
398 405
399 406 connect(m_sliceValue, SIGNAL(valueChanged(double)), this, SLOT(updateSliceSettings()));
400 407 connect(m_pen, SIGNAL(clicked()), m_penTool, SLOT(show()));
401 408 connect(m_penTool, SIGNAL(changed()), this, SLOT(updateSliceSettings()));
402 409 connect(m_brush, SIGNAL(clicked()), m_brushTool, SLOT(show()));
403 410 connect(m_brushTool, SIGNAL(changed()), this, SLOT(updateSliceSettings()));
404 411 connect(m_font, SIGNAL(clicked()), this, SLOT(showFontDialog()));
405 412 connect(m_labelArmPen, SIGNAL(clicked()), m_labelArmPenTool, SLOT(show()));
406 413 connect(m_labelArmPenTool, SIGNAL(changed()), this, SLOT(updateSliceSettings()));
407 414 connect(m_sliceLabelVisible, SIGNAL(toggled(bool)), this, SLOT(updateSliceSettings()));
408 415 connect(m_sliceLabelVisible, SIGNAL(toggled(bool)), this, SLOT(updateSliceSettings()));
409 416 connect(m_sliceLabelArmFactor, SIGNAL(valueChanged(double)), this, SLOT(updateSliceSettings()));
410 417 connect(m_sliceExploded, SIGNAL(toggled(bool)), this, SLOT(updateSliceSettings()));
411 418 connect(m_sliceExplodedFactor, SIGNAL(valueChanged(double)), this, SLOT(updateSliceSettings()));
419 connect(removeSlice, SIGNAL(clicked()), this, SLOT(removeSlice()));
412 420
413 421 // create main layout
414 422 QVBoxLayout *settingsLayout = new QVBoxLayout();
415 423 settingsLayout->addWidget(chartSettings);
416 424 settingsLayout->addWidget(seriesSettings);
417 425 settingsLayout->addWidget(sliceSettings);
418 426 settingsLayout->addStretch();
419 427
420 428 QGridLayout* baseLayout = new QGridLayout();
421 429 baseLayout->addLayout(settingsLayout, 0, 0);
422 430 baseLayout->addWidget(m_chartView, 0, 1);
423 431 setLayout(baseLayout);
424 432
425 433 updateSerieSettings();
426 434 }
427 435
428 436 public Q_SLOTS:
429 437
430 438 void updateChartSettings()
431 439 {
432 440 QChart::ChartTheme theme = (QChart::ChartTheme) m_themeComboBox->itemData(m_themeComboBox->currentIndex()).toInt();
433 441 m_chartView->setChartTheme(theme);
434 442 m_chartView->setRenderHint(QPainter::Antialiasing, m_aaCheckBox->isChecked());
435 443 }
436 444
437 445 void updateSerieSettings()
438 446 {
439 447 m_series->setPiePosition(m_vPosition->value(), m_hPosition->value());
440 448 m_series->setPieSize(m_sizeFactor->value());
441 449 m_series->setPieStartAngle(m_startAngle->value());
442 450 m_series->setPieEndAngle(m_endAngle->value());
443 451 }
444 452
445 453 void updateSliceSettings()
446 454 {
447 455 if (!m_slice)
448 456 return;
449 457
450 458 m_slice->setValue(m_sliceValue->value());
451 459
452 460 m_slice->setSlicePen(m_penTool->pen());
453 461 m_slice->setSliceBrush(m_brushTool->brush());
454 462
455 463 m_slice->setLabelArmPen(m_labelArmPenTool->pen());
456 464 m_slice->setLabelVisible(m_sliceLabelVisible->isChecked());
457 465 m_slice->setLabelArmLengthFactor(m_sliceLabelArmFactor->value());
458 466
459 467 m_slice->setExploded(m_sliceExploded->isChecked());
460 468 m_slice->setExplodeDistanceFactor(m_sliceExplodedFactor->value());
461 469 }
462 470
463 471 void handleSliceClicked(QPieSlice* slice)
464 472 {
465 473 m_slice = static_cast<CustomSlice*>(slice);
466 474
467 475 // name
468 476 m_sliceName->setText(slice->label());
469 477
470 478 // value
471 479 m_sliceValue->blockSignals(true);
472 480 m_sliceValue->setValue(slice->value());
473 481 m_sliceValue->blockSignals(false);
474 482
475 483 // pen
476 484 m_pen->setText(PenTool::name(m_slice->slicePen()));
477 485 m_penTool->setPen(m_slice->slicePen());
478 486
479 487 // brush
480 488 m_brush->setText(m_slice->originalBrush().color().name());
481 489 m_brushTool->setBrush(m_slice->originalBrush());
482 490
483 491 // label
484 492 m_labelArmPen->setText(PenTool::name(m_slice->labelArmPen()));
485 493 m_labelArmPenTool->setPen(m_slice->labelArmPen());
486 494 m_font->setText(slice->labelFont().toString());
487 495 m_sliceLabelVisible->blockSignals(true);
488 496 m_sliceLabelVisible->setChecked(slice->isLabelVisible());
489 497 m_sliceLabelVisible->blockSignals(false);
490 498 m_sliceLabelArmFactor->blockSignals(true);
491 499 m_sliceLabelArmFactor->setValue(slice->labelArmLengthFactor());
492 500 m_sliceLabelArmFactor->blockSignals(false);
493 501
494 502 // exploded
495 503 m_sliceExploded->blockSignals(true);
496 504 m_sliceExploded->setChecked(slice->isExploded());
497 505 m_sliceExploded->blockSignals(false);
498 506 m_sliceExplodedFactor->blockSignals(true);
499 507 m_sliceExplodedFactor->setValue(slice->explodeDistanceFactor());
500 508 m_sliceExplodedFactor->blockSignals(false);
501 509 }
502 510
503 511 void showFontDialog()
504 512 {
505 513 if (!m_slice)
506 514 return;
507 515
508 516 QFontDialog dialog(m_slice->labelFont());
509 517 dialog.show();
510 518 dialog.exec();
511 519
512 520 m_slice->setLabelFont(dialog.currentFont());
513 521 m_font->setText(dialog.currentFont().toString());
514 522 }
515 523
524 void addSlice()
525 {
526 *m_series << new CustomSlice(10.0, "Slice " + QString::number(m_series->count()));
527 }
528
529 void removeSlice()
530 {
531 if (!m_slice)
532 return;
533
534 m_series->remove(m_slice);
535 m_slice = 0;
536 }
537
516 538 private:
517 539 QComboBox *m_themeComboBox;
518 540 QCheckBox *m_aaCheckBox;
519 541
520 542 QChartView* m_chartView;
521 543 QPieSeries* m_series;
522 544 CustomSlice* m_slice;
523 545
524 546 QDoubleSpinBox* m_hPosition;
525 547 QDoubleSpinBox* m_vPosition;
526 548 QDoubleSpinBox* m_sizeFactor;
527 549 QDoubleSpinBox* m_startAngle;
528 550 QDoubleSpinBox* m_endAngle;
529 551
530 552 QLabel* m_sliceName;
531 553 QDoubleSpinBox* m_sliceValue;
532 554 QCheckBox* m_sliceLabelVisible;
533 555 QDoubleSpinBox* m_sliceLabelArmFactor;
534 556 QCheckBox* m_sliceExploded;
535 557 QDoubleSpinBox* m_sliceExplodedFactor;
536 558 QPushButton *m_brush;
537 559 BrushTool *m_brushTool;
538 560 QPushButton *m_pen;
539 561 PenTool *m_penTool;
540 562 QPushButton *m_font;
541 563 QPushButton *m_labelArmPen;
542 564 PenTool *m_labelArmPenTool;
543 565 };
544 566
545 567 int main(int argc, char *argv[])
546 568 {
547 569 QApplication a(argc, argv);
548 570
549 571 QMainWindow window;
550 572
551 573 MainWidget* widget = new MainWidget();
552 574
553 575 window.setCentralWidget(widget);
554 576 window.resize(900, 600);
555 577 window.show();
556 578
557 579 return a.exec();
558 580 }
559 581
560 582 #include "main.moc"
@@ -1,13 +1,17
1 1 INCLUDEPATH += $$PWD
2 2 DEPENDPATH += $$PWD
3 3
4 4 SOURCES += \
5 5 $$PWD/axisanimation.cpp \
6 6 $$PWD/chartanimator.cpp \
7 $$PWD/xyanimation.cpp
7 $$PWD/xyanimation.cpp \
8 $$PWD/pieanimation.cpp \
9 $$PWD/piesliceanimation.cpp
8 10
9 11 PRIVATE_HEADERS += \
10 12 $$PWD/axisanimation_p.h \
11 13 $$PWD/chartanimator_p.h \
12 14 $$PWD/chartanimation_p.h \
13 $$PWD/xyanimation_p.h No newline at end of file
15 $$PWD/xyanimation_p.h \
16 $$PWD/pieanimation_p.h \
17 $$PWD/piesliceanimation_p.h
@@ -1,180 +1,207
1 1 #include "chartanimator_p.h"
2 2 #include "axisanimation_p.h"
3 3 #include "xyanimation_p.h"
4 4 #include "xychartitem_p.h"
5 #include "pieanimation_p.h"
5 6 #include "areachartitem_p.h"
6 7 #include <QTimer>
7 8
8 9 Q_DECLARE_METATYPE(QVector<QPointF>)
9 10 Q_DECLARE_METATYPE(QVector<qreal>)
10 11
11 12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
12 13
13 14 const static int duration = 1000;
14 15
15 16 ChartAnimator::ChartAnimator(QObject *parent):QObject(parent)
16 17 {
17 18 }
18 19
19 20 ChartAnimator::~ChartAnimator()
20 21 {
21 22 }
22 23
23 24 void ChartAnimator::addAnimation(AxisItem* item)
24 25 {
25 26 ChartAnimation* animation = m_animations.value(item);
26 27
27 28 if(!animation) {
28 29 animation = new AxisAnimation(item);
29 30 m_animations.insert(item,animation);
30 31 }
31 32
32 33 item->setAnimator(this);
33 34 }
34 35
35 36 void ChartAnimator::addAnimation(XYChartItem* item)
36 37 {
37 38 ChartAnimation* animation = m_animations.value(item);
38 39
39 40 if(!animation) {
40 41 animation = new XYAnimation(item);
41 42 m_animations.insert(item,animation);
42 43 }
43 44
44 45 item->setAnimator(this);
45 46 }
46 47
48 void ChartAnimator::addAnimation(PieChartItem* item)
49 {
50 ChartAnimation* animation = m_animations.value(item);
51
52 if(!animation) {
53 animation = new PieAnimation(item);
54 m_animations.insert(item,animation);
55 }
56
57 item->setAnimator(this);
58 }
59
47 60 void ChartAnimator::removeAnimation(ChartItem* item)
48 61 {
49 62 item->setAnimator(0);
50 63 m_animations.remove(item);
51 64 }
52 65
53 66 void ChartAnimator::applyLayout(AxisItem* item , QVector<qreal>& newLayout)
54 67 {
55 68 AxisAnimation* animation = static_cast<AxisAnimation*>(m_animations.value(item));
56 69
57 70 Q_ASSERT(animation);
58 71
59 72 QVector<qreal> oldLayout = item->layout();
60 73
61 74 if(newLayout.count()==0) return;
62 75
63 76 switch(m_state)
64 77 {
65 78 case ZoomOutState: {
66 79 QRectF rect = item->geometry();
67 80 oldLayout.resize(newLayout.count());
68 81
69 82 for(int i=0,j=oldLayout.count()-1;i<(oldLayout.count()+1)/2;i++,j--)
70 83 {
71 84 oldLayout[i]= item->axisType()==AxisItem::X_AXIS?rect.left():rect.bottom();
72 85 oldLayout[j]= item->axisType()==AxisItem::X_AXIS?rect.right():rect.top();
73 86 }
74 87 }
75 88 break;
76 89 case ZoomInState: {
77 90 int index = qMin(oldLayout.count()*(item->axisType()==AxisItem::X_AXIS?m_point.x():(1 -m_point.y())),newLayout.count()-1.0);
78 91 oldLayout.resize(newLayout.count());
79 92
80 93 for(int i=0;i<oldLayout.count();i++)
81 94 {
82 95 oldLayout[i]= oldLayout[index];
83 96 }
84 97 }
85 98 break;
86 99 case ScrollDownState:
87 100 case ScrollRightState: {
88 101 oldLayout.resize(newLayout.count());
89 102
90 103 for(int i=0, j=i+1;i<oldLayout.count()-1;i++,j++)
91 104 {
92 105 oldLayout[i]= oldLayout[j];
93 106 }
94 107 }
95 108 break;
96 109 case ScrollUpState:
97 110 case ScrollLeftState: {
98 111 oldLayout.resize(newLayout.count());
99 112
100 113 for(int i=oldLayout.count()-1, j=i-1;i>0;i--,j--)
101 114 {
102 115 oldLayout[i]= oldLayout[j];
103 116 }
104 117 }
105 118 break;
106 119 default: {
107 120 oldLayout.resize(newLayout.count());
108 121 QRectF rect = item->geometry();
109 122 for(int i=0, j=oldLayout.count()-1;i<oldLayout.count();i++,j--)
110 123 {
111 124 oldLayout[i]= item->axisType()==AxisItem::X_AXIS?rect.left():rect.top();
112 125 }
113 126 }
114 127 break;
115 128 }
116 129
117 130
118 131 if(animation->state()!=QAbstractAnimation::Stopped) {
119 132 animation->stop();
120 133 }
121 134
122 135 animation->setDuration(duration);
123 136 animation->setEasingCurve(QEasingCurve::OutQuart);
124 137 QVariantAnimation::KeyValues value;
125 138 animation->setKeyValues(value); //workaround for wrong interpolation call
126 139 animation->setKeyValueAt(0.0, qVariantFromValue(oldLayout));
127 140 animation->setKeyValueAt(1.0, qVariantFromValue(newLayout));
128 141
129 142 QTimer::singleShot(0,animation,SLOT(start()));
130 143 }
131 144
132 145 void ChartAnimator::applyLayout(XYChartItem* item, QVector<QPointF>& newPoints)
133 146 {
134 147
135 148 XYAnimation* animation = static_cast<XYAnimation*>(m_animations.value(item));
136 149
137 150 Q_ASSERT(animation);
138 151
139 152 QVector<QPointF> oldPoints = item->points();
140 153
141 154 if(newPoints.count()==0) return;
142 155
143 156 bool empty = oldPoints.count()==0;
144 157 oldPoints.resize(newPoints.size());
145 158
146 159 if(animation->state()!=QAbstractAnimation::Stopped) {
147 160 animation->stop();
148 161 }
149 162
150 163 animation->setDuration(duration);
151 164 if(!empty)
152 165 animation->setAnimationType(XYAnimation::MoveDownAnimation);
153 166 else
154 167 animation->setAnimationType(XYAnimation::LineDrawAnimation);
155 168 animation->setEasingCurve(QEasingCurve::OutQuart);
156 169 animation->setValues(oldPoints,newPoints);
157 170 QTimer::singleShot(0,animation,SLOT(start()));
158 171 }
159 172
160 173 void ChartAnimator::updateLayout(XYChartItem* item, QVector<QPointF>& newPoints)
161 174 {
162 175 XYAnimation* animation = static_cast<XYAnimation*>(m_animations.value(item));
163 176
164 177 Q_ASSERT(animation);
165 178
166 179 animation->setDuration(duration);
167 180 animation->setAnimationType(XYAnimation::MoveDownAnimation);
168 181 animation->setEasingCurve(QEasingCurve::OutQuart);
169 182 animation->updateValues(newPoints);
170 183
171 184 QTimer::singleShot(0,animation,SLOT(start()));
172 185 }
173 186
187 void ChartAnimator::applyLayout(PieChartItem* item, QVector<PieSliceLayout> &layout)
188 {
189 PieAnimation* animation = static_cast<PieAnimation*>(m_animations.value(item));
190 Q_ASSERT(animation);
191 animation->setValues(layout);
192 }
193
194 void ChartAnimator::updateLayout(PieChartItem* item, PieSliceLayout &layout)
195 {
196 PieAnimation* animation = static_cast<PieAnimation*>(m_animations.value(item));
197 Q_ASSERT(animation);
198 animation->updateValue(layout);
199 }
200
174 201 void ChartAnimator::setState(State state,const QPointF& point)
175 202 {
176 203 m_state=state;
177 204 m_point=point;
178 205 }
179 206
180 207 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,43 +1,48
1 1 #ifndef CHARTANIMATOR_P_H_
2 2 #define CHARTANIMATOR_P_H_
3 3 #include "qchartglobal.h"
4 4 #include "chartanimation_p.h"
5 #include "piechartitem_p.h"
5 6 #include <QPointF>
6 7
7 8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
8 9
9 10 class ChartItem;
10 11 class XYChartItem;
11 12 class AxisItem;
12 13 class AreaChartItem;
13 14
14 15
15 16 class ChartAnimator : public QObject {
16 17
17 18 public:
18 19 //TODO: this should be flags in case of two state at the time
19 20 enum State{ShowState, ScrollUpState, ScrollDownState, ScrollLeftState,ScrollRightState,ZoomInState,ZoomOutState};
20 21 ChartAnimator(QObject *parent = 0);
21 22 virtual ~ChartAnimator();
22 23
23 24 void addAnimation(AxisItem* item);
24 25 void addAnimation(XYChartItem* item);
26 void addAnimation(PieChartItem* item);
25 27
26 28 void removeAnimation(ChartItem* item);
27 29
28 30 void animationStarted();
29 31 void applyLayout(XYChartItem* item, QVector<QPointF>& layout);
30 32 void updateLayout(XYChartItem* item, QVector<QPointF>& layout);
31 33 void applyLayout(AxisItem* item, QVector<qreal>& layout);
32 34
35 void applyLayout(PieChartItem* item, QVector<PieSliceLayout> &layout);
36 void updateLayout(PieChartItem* item, PieSliceLayout &layout);
37
33 38 void setState(State state,const QPointF& point = QPointF());
34 39
35 40 private:
36 41 QMap<ChartItem*,ChartAnimation*> m_animations;
37 42 State m_state;
38 43 QPointF m_point;
39 44 };
40 45
41 46 QTCOMMERCIALCHART_END_NAMESPACE
42 47
43 48 #endif
@@ -1,401 +1,401
1 1 #include "qchart.h"
2 2 #include "qchartaxis.h"
3 3 #include "chartpresenter_p.h"
4 4 #include "chartdataset_p.h"
5 5 #include "charttheme_p.h"
6 6 #include "chartanimator_p.h"
7 7 //series
8 8 #include "qbarseries.h"
9 9 #include "qstackedbarseries.h"
10 10 #include "qpercentbarseries.h"
11 11 #include "qlineseries.h"
12 12 #include "qareaseries.h"
13 13 #include "qpieseries.h"
14 14 #include "qscatterseries.h"
15 15 #include "qsplineseries.h"
16 16 //items
17 17 #include "axisitem_p.h"
18 18 #include "areachartitem_p.h"
19 19 #include "barpresenter_p.h"
20 20 #include "stackedbarpresenter_p.h"
21 21 #include "percentbarpresenter_p.h"
22 22 #include "linechartitem_p.h"
23 23 #include "piechartitem_p.h"
24 24 #include "scatterchartitem_p.h"
25 25 #include "splinechartitem_p.h"
26 26
27 27 QTCOMMERCIALCHART_BEGIN_NAMESPACE
28 28
29 29 ChartPresenter::ChartPresenter(QChart* chart,ChartDataSet* dataset):QObject(chart),
30 30 m_chart(chart),
31 31 m_animator(0),
32 32 m_dataset(dataset),
33 33 m_chartTheme(0),
34 34 m_zoomIndex(0),
35 35 m_marginSize(0),
36 36 m_rect(QRectF(QPoint(0,0),m_chart->size())),
37 37 m_options(QChart::NoAnimation)
38 38 {
39 39 createConnections();
40 40 setChartTheme(QChart::ChartThemeDefault);
41 41 }
42 42
43 43 ChartPresenter::~ChartPresenter()
44 44 {
45 45 delete m_chartTheme;
46 46 }
47 47
48 48 void ChartPresenter::createConnections()
49 49 {
50 50 QObject::connect(m_chart,SIGNAL(geometryChanged()),this,SLOT(handleGeometryChanged()));
51 51 QObject::connect(m_dataset,SIGNAL(seriesAdded(QSeries*,Domain*)),this,SLOT(handleSeriesAdded(QSeries*,Domain*)));
52 52 QObject::connect(m_dataset,SIGNAL(seriesRemoved(QSeries*)),this,SLOT(handleSeriesRemoved(QSeries*)));
53 53 QObject::connect(m_dataset,SIGNAL(axisAdded(QChartAxis*,Domain*)),this,SLOT(handleAxisAdded(QChartAxis*,Domain*)));
54 54 QObject::connect(m_dataset,SIGNAL(axisRemoved(QChartAxis*)),this,SLOT(handleAxisRemoved(QChartAxis*)));
55 55 }
56 56
57 57
58 58 QRectF ChartPresenter::geometry() const
59 59 {
60 60 return m_rect;
61 61 }
62 62
63 63 void ChartPresenter::handleGeometryChanged()
64 64 {
65 65 QRectF rect(QPoint(0,0),m_chart->size());
66 66 rect.adjust(m_marginSize,m_marginSize, -m_marginSize, -m_marginSize);
67 67
68 68 //rewrite zoom stack
69 69 for(int i=0;i<m_zoomStack.count();i++){
70 70 QRectF r = m_zoomStack[i];
71 71 qreal w = rect.width()/m_rect.width();
72 72 qreal h = rect.height()/m_rect.height();
73 73 QPointF tl = r.topLeft();
74 74 tl.setX(tl.x()*w);
75 75 tl.setY(tl.y()*h);
76 76 QPointF br = r.bottomRight();
77 77 br.setX(br.x()*w);
78 78 br.setY(br.y()*h);
79 79 r.setTopLeft(tl);
80 80 r.setBottomRight(br);
81 81 m_zoomStack[i]=r;
82 82 }
83 83
84 84 m_rect = rect;
85 85 Q_ASSERT(m_rect.isValid());
86 86 emit geometryChanged(m_rect);
87 87 }
88 88
89 89 int ChartPresenter::margin() const
90 90 {
91 91 return m_marginSize;
92 92 }
93 93
94 94 void ChartPresenter::setMargin(int margin)
95 95 {
96 96 m_marginSize = margin;
97 97 }
98 98
99 99 void ChartPresenter::handleAxisAdded(QChartAxis* axis,Domain* domain)
100 100 {
101 101 AxisItem* item = new AxisItem(axis,this,axis==m_dataset->axisX()?AxisItem::X_AXIS : AxisItem::Y_AXIS,m_chart);
102 102
103 103 if(m_options.testFlag(QChart::GridAxisAnimations)){
104 104 m_animator->addAnimation(item);
105 105 }
106 106
107 107 if(axis==m_dataset->axisX()){
108 108 m_chartTheme->decorate(axis,true);
109 109 QObject::connect(domain,SIGNAL(rangeXChanged(qreal,qreal,int)),item,SLOT(handleRangeChanged(qreal,qreal,int)));
110 110 //initialize
111 111 item->handleRangeChanged(domain->minX(),domain->maxX(),domain->tickXCount());
112 112
113 113 }
114 114 else{
115 115 m_chartTheme->decorate(axis,false);
116 116 QObject::connect(domain,SIGNAL(rangeYChanged(qreal,qreal,int)),item,SLOT(handleRangeChanged(qreal,qreal,int)));
117 117 //initialize
118 118 item->handleRangeChanged(domain->minY(),domain->maxY(),domain->tickYCount());
119 119 }
120 120
121 121 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),item,SLOT(handleGeometryChanged(const QRectF&)));
122 122 //initialize
123 123 item->handleGeometryChanged(m_rect);
124 124 m_axisItems.insert(axis, item);
125 125 }
126 126
127 127 void ChartPresenter::handleAxisRemoved(QChartAxis* axis)
128 128 {
129 129 AxisItem* item = m_axisItems.take(axis);
130 130 Q_ASSERT(item);
131 131 if(m_animator) m_animator->removeAnimation(item);
132 132 delete item;
133 133 }
134 134
135 135
136 136 void ChartPresenter::handleSeriesAdded(QSeries* series,Domain* domain)
137 137 {
138 138 ChartItem *item = 0 ;
139 139
140 140 switch(series->type())
141 141 {
142 142 case QSeries::SeriesTypeLine: {
143 143
144 144 QLineSeries* lineSeries = static_cast<QLineSeries*>(series);
145 145 LineChartItem* line = new LineChartItem(lineSeries,m_chart);
146 146 if(m_options.testFlag(QChart::SeriesAnimations)) {
147 147 m_animator->addAnimation(line);
148 148 }
149 149 m_chartTheme->decorate(lineSeries, m_dataset->seriesIndex(series));
150 150 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),line,SLOT(handleGeometryChanged(const QRectF&)));
151 151 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),line,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
152 152 item = line;
153 153 break;
154 154 }
155 155
156 156 case QSeries::SeriesTypeArea: {
157 157
158 158 QAreaSeries* areaSeries = static_cast<QAreaSeries*>(series);
159 159 AreaChartItem* area = new AreaChartItem(areaSeries,m_chart);
160 160 if(m_options.testFlag(QChart::SeriesAnimations)) {
161 161 m_animator->addAnimation(area->upperLineItem());
162 162 if(areaSeries->lowerSeries()) m_animator->addAnimation(area->lowerLineItem());
163 163 }
164 164 m_chartTheme->decorate(areaSeries, m_dataset->seriesIndex(series));
165 165 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),area,SLOT(handleGeometryChanged(const QRectF&)));
166 166 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),area,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
167 167 item=area;
168 168 break;
169 169 }
170 170
171 171 case QSeries::SeriesTypeBar: {
172 172 QBarSeries* barSeries = static_cast<QBarSeries*>(series);
173 173 BarPresenter* bar = new BarPresenter(barSeries,m_chart);
174 174 if(m_options.testFlag(QChart::SeriesAnimations)) {
175 175 // m_animator->addAnimation(bar);
176 176 }
177 177 m_chartTheme->decorate(barSeries, m_dataset->seriesIndex(barSeries));
178 178 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),bar,SLOT(handleGeometryChanged(const QRectF&)));
179 179 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),bar,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
180 180 item=bar;
181 181 break;
182 182 }
183 183
184 184 case QSeries::SeriesTypeStackedBar: {
185 185 QStackedBarSeries* stackedBarSeries = static_cast<QStackedBarSeries*>(series);
186 186 StackedBarPresenter* bar = new StackedBarPresenter(stackedBarSeries,m_chart);
187 187 if(m_options.testFlag(QChart::SeriesAnimations)) {
188 188 // m_animator->addAnimation(bar);
189 189 }
190 190 m_chartTheme->decorate(stackedBarSeries, m_dataset->seriesIndex(stackedBarSeries));
191 191 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),bar,SLOT(handleGeometryChanged(const QRectF&)));
192 192 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),bar,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
193 193 item=bar;
194 194 break;
195 195 }
196 196
197 197 case QSeries::SeriesTypePercentBar: {
198 198 QPercentBarSeries* percentBarSeries = static_cast<QPercentBarSeries*>(series);
199 199 PercentBarPresenter* bar = new PercentBarPresenter(percentBarSeries,m_chart);
200 200 if(m_options.testFlag(QChart::SeriesAnimations)) {
201 201 // m_animator->addAnimation(bar);
202 202 }
203 203 m_chartTheme->decorate(percentBarSeries, m_dataset->seriesIndex(percentBarSeries));
204 204 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),bar,SLOT(handleGeometryChanged(const QRectF&)));
205 205 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),bar,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
206 206 item=bar;
207 207 break;
208 208 }
209 209
210 210 case QSeries::SeriesTypeScatter: {
211 211 QScatterSeries *scatterSeries = static_cast<QScatterSeries *>(series);
212 212 ScatterChartItem *scatter = new ScatterChartItem(scatterSeries, m_chart);
213 213 if(m_options.testFlag(QChart::SeriesAnimations)) {
214 214 m_animator->addAnimation(scatter);
215 215 }
216 216 m_chartTheme->decorate(scatterSeries, m_dataset->seriesIndex(series));
217 217 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),scatter,SLOT(handleGeometryChanged(const QRectF&)));
218 218 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),scatter,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
219 219 item = scatter;
220 220 break;
221 221 }
222 222
223 223 case QSeries::SeriesTypePie: {
224 224 QPieSeries *pieSeries = static_cast<QPieSeries *>(series);
225 225 PieChartItem* pie = new PieChartItem(m_chart, pieSeries);
226 226 if(m_options.testFlag(QChart::SeriesAnimations)) {
227 // m_animator->addAnimation(pie);
227 m_animator->addAnimation(pie);
228 228 }
229 229 m_chartTheme->decorate(pieSeries, m_dataset->seriesIndex(series));
230 230 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),pie,SLOT(handleGeometryChanged(const QRectF&)));
231 231 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),pie,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
232 232 // Hide all from background when there is only piechart
233 233 // TODO: refactor this ugly code... should be one setting for this
234 234 if (m_chartItems.count() == 0) {
235 235 m_chart->axisX()->hide();
236 236 m_chart->axisY()->hide();
237 237 m_chart->setChartBackgroundBrush(Qt::transparent);
238 238 }
239 239 item=pie;
240 240 break;
241 241 }
242 242
243 243 case QSeries::SeriesTypeSpline: {
244 244 QSplineSeries* splineSeries = static_cast<QSplineSeries*>(series);
245 245 SplineChartItem* spline = new SplineChartItem(splineSeries, m_chart);
246 246 if(m_options.testFlag(QChart::SeriesAnimations)) {
247 247 m_animator->addAnimation(spline);
248 248 }
249 249 m_chartTheme->decorate(splineSeries, m_dataset->seriesIndex(series));
250 250 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),spline,SLOT(handleGeometryChanged(const QRectF&)));
251 251 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),spline,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
252 252 item=spline;
253 253 break;
254 254 }
255 255 default: {
256 256 qDebug()<< "Series type" << series->type() << "not implemented.";
257 257 break;
258 258 }
259 259 }
260 260
261 261 //initialize
262 262 item->handleDomainChanged(domain->minX(),domain->maxX(),domain->minY(),domain->maxY());
263 263 if(m_rect.isValid()) item->handleGeometryChanged(m_rect);
264 264 m_chartItems.insert(series,item);
265 265 zoomReset();
266 266 }
267 267
268 268 void ChartPresenter::handleSeriesRemoved(QSeries* series)
269 269 {
270 270 ChartItem* item = m_chartItems.take(series);
271 271 Q_ASSERT(item);
272 272 if(m_animator) {
273 273 //small hack to handle area animations
274 274 if(series->type()==QSeries::SeriesTypeArea){
275 275 QAreaSeries* areaSeries = static_cast<QAreaSeries*>(series);
276 276 AreaChartItem* area = static_cast<AreaChartItem*>(item);
277 277 m_animator->removeAnimation(area->upperLineItem());
278 278 if(areaSeries->lowerSeries()) m_animator->addAnimation(area->lowerLineItem());
279 279 }else
280 280 m_animator->removeAnimation(item);
281 281 }
282 282 delete item;
283 283 }
284 284
285 285 void ChartPresenter::setChartTheme(QChart::ChartTheme theme)
286 286 {
287 287 if(m_chartTheme && m_chartTheme->id() == theme) return;
288 288 delete m_chartTheme;
289 289 m_chartTheme = ChartTheme::createTheme(theme);
290 290 m_chartTheme->decorate(m_chart);
291 291 m_chartTheme->decorate(m_chart->legend());
292 292 resetAllElements();
293 293 }
294 294
295 295 QChart::ChartTheme ChartPresenter::chartTheme()
296 296 {
297 297 return m_chartTheme->id();
298 298 }
299 299
300 300 void ChartPresenter::setAnimationOptions(QChart::AnimationOptions options)
301 301 {
302 302 if(m_options!=options) {
303 303
304 304 m_options=options;
305 305
306 306 if(m_options!=QChart::NoAnimation && !m_animator) {
307 307 m_animator= new ChartAnimator(this);
308 308
309 309 }
310 310 resetAllElements();
311 311 }
312 312
313 313 }
314 314
315 315 void ChartPresenter::resetAllElements()
316 316 {
317 317 QList<QChartAxis*> axisList = m_axisItems.uniqueKeys();
318 318 QList<QSeries*> seriesList = m_chartItems.uniqueKeys();
319 319
320 320 foreach(QChartAxis* axis, axisList) {
321 321 handleAxisRemoved(axis);
322 322 handleAxisAdded(axis,m_dataset->domain(axis));
323 323 }
324 324 foreach(QSeries* series, seriesList) {
325 325 handleSeriesRemoved(series);
326 326 handleSeriesAdded(series,m_dataset->domain(series));
327 327 }
328 328 }
329 329
330 330 void ChartPresenter::zoomIn()
331 331 {
332 332 QRectF rect = geometry();
333 333 rect.setWidth(rect.width()/2);
334 334 rect.setHeight(rect.height()/2);
335 335 rect.moveCenter(geometry().center());
336 336 zoomIn(rect);
337 337 }
338 338
339 339 void ChartPresenter::zoomIn(const QRectF& rect)
340 340 {
341 341 QRectF r = rect.normalized();
342 342 r.translate(-m_marginSize, -m_marginSize);
343 343 if(m_animator) {
344 344
345 345 QPointF point(r.center().x()/geometry().width(),r.center().y()/geometry().height());
346 346 m_animator->setState(ChartAnimator::ZoomInState,point);
347 347 }
348 348 m_dataset->zoomInDomain(r,geometry().size());
349 349 m_zoomStack<<r;
350 350 m_zoomIndex++;
351 351 if(m_animator) {
352 352 m_animator->setState(ChartAnimator::ShowState);
353 353 }
354 354 }
355 355
356 356 void ChartPresenter::zoomOut()
357 357 {
358 358 if(m_zoomIndex==0) return;
359 359 if(m_animator)
360 360 {
361 361 m_animator->setState(ChartAnimator::ZoomOutState);
362 362 }
363 363 m_dataset->zoomOutDomain(m_zoomStack[m_zoomIndex-1],geometry().size());
364 364 m_zoomIndex--;
365 365 m_zoomStack.resize(m_zoomIndex);
366 366 if(m_animator){
367 367 m_animator->setState(ChartAnimator::ShowState);
368 368 }
369 369 }
370 370
371 371 void ChartPresenter::zoomReset()
372 372 {
373 373 m_zoomIndex=0;
374 374 m_zoomStack.resize(m_zoomIndex);
375 375 }
376 376
377 377 void ChartPresenter::scroll(int dx,int dy)
378 378 {
379 379 if(m_animator){
380 380 if(dx<0) m_animator->setState(ChartAnimator::ScrollLeftState,QPointF());
381 381 if(dx>0) m_animator->setState(ChartAnimator::ScrollRightState,QPointF());
382 382 if(dy<0) m_animator->setState(ChartAnimator::ScrollUpState,QPointF());
383 383 if(dy>0) m_animator->setState(ChartAnimator::ScrollDownState,QPointF());
384 384 }
385 385
386 386 m_dataset->scrollDomain(dx,dy,geometry().size());
387 387
388 388 if(m_animator){
389 389 m_animator->setState(ChartAnimator::ShowState);
390 390 }
391 391 }
392 392
393 393 QChart::AnimationOptions ChartPresenter::animationOptions() const
394 394 {
395 395 return m_options;
396 396 }
397 397
398 398
399 399 #include "moc_chartpresenter_p.cpp"
400 400
401 401 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,144 +1,185
1 1 #include "piechartitem_p.h"
2 2 #include "pieslice_p.h"
3 3 #include "qpieslice.h"
4 4 #include "qpieseries.h"
5 5 #include "chartpresenter_p.h"
6 #include "chartanimator_p.h"
6 7 #include <QDebug>
7 8 #include <QPainter>
8 9
9 10
10 11 QTCOMMERCIALCHART_BEGIN_NAMESPACE
11 12
12 13 PieChartItem::PieChartItem(QGraphicsItem *parent, QPieSeries *series)
13 14 :ChartItem(parent),
14 15 m_series(series)
15 16 {
16 17 Q_ASSERT(series);
17 18 connect(series, SIGNAL(changed()), this, SLOT(handleSeriesChanged()));
18 19
19 20 // Note: the following does not affect as long as the item does not have anything to paint
20 21 setZValue(ChartPresenter::PieSeriesZValue);
21 22 }
22 23
23 24 PieChartItem::~PieChartItem()
24 25 {
25 26 // slices deleted automatically through QGraphicsItem
26 27 }
27 28
28 29 void PieChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
29 30 {
30 31 Q_UNUSED(painter)
31 32 // TODO: paint shadows for all components
32 33 // - get paths from items & merge & offset and draw with shadow color?
33 34 //painter->setBrush(QBrush(Qt::red));
34 35 //painter->drawRect(m_debugRect);
35 36 }
36 37
37 38 void PieChartItem::handleSeriesChanged()
38 39 {
39 QVector<PieSliceLayout> sliceLayout = calculateLayout();
40 applyLayout(sliceLayout);
40 QVector<PieSliceLayout> layout = calculateLayout();
41 applyLayout(layout);
41 42 update();
42 43 }
43 44
44 45 void PieChartItem::handleSliceChanged()
45 46 {
46 // TODO: optimize don't need to handle all slices
47 QVector<PieSliceLayout> sliceLayout = calculateLayout();
48 applyLayout(sliceLayout);
47 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
48 Q_ASSERT(m_slices.contains(slice));
49
50 //qDebug() << "PieChartItem::handleSliceChanged" << slice->label();
51
52 // TODO: Optimize. No need to calculate everything.
53 QVector<PieSliceLayout> layout = calculateLayout();
54 foreach (PieSliceLayout sl, layout) {
55 if (sl.m_data == slice)
56 updateLayout(sl);
57 }
49 58 update();
50 59 }
51 60
52 61 void PieChartItem::handleDomainChanged(qreal, qreal, qreal, qreal)
53 62 {
54 63 // TODO
55 64 }
56 65
57 66 void PieChartItem::handleGeometryChanged(const QRectF& rect)
58 67 {
59 68 prepareGeometryChange();
60 69 m_rect = rect;
61 70 QVector<PieSliceLayout> sliceLayout = calculateLayout();
62 71 applyLayout(sliceLayout);
63 72 update();
64 73 }
65 74
66 75
67 76 QVector<PieSliceLayout> PieChartItem::calculateLayout()
68 77 {
69 78 // find pie center coordinates
70 79 QPointF center;
71 80 center.setX(m_rect.left() + (m_rect.width() * m_series->pieHorizontalPosition()));
72 81 center.setY(m_rect.top() + (m_rect.height() * m_series->pieVerticalPosition()));
73 82
74 83 // find maximum radius for pie
75 84 qreal radius = m_rect.height() / 2;
76 85 if (m_rect.width() < m_rect.height())
77 86 radius = m_rect.width() / 2;
78 87
79 88 // apply size factor
80 89 radius *= m_series->pieSize();
81 90
82 91 QVector<PieSliceLayout> layout;
83 92 foreach (QPieSlice* s, m_series->slices()) {
84 93 PieSliceLayout sliceLayout;
85 94 sliceLayout.m_data = s;
86 95 sliceLayout.m_center = PieSlice::sliceCenter(center, radius, s);
87 96 sliceLayout.m_radius = radius;
88 97 sliceLayout.m_startAngle = s->startAngle();
89 98 sliceLayout.m_angleSpan = s->m_angleSpan;
90 99 layout << sliceLayout;
91 100 }
92 101
93 102 return layout;
94 103 }
95 104
96 void PieChartItem::applyLayout(const QVector<PieSliceLayout> &layout)
105 void PieChartItem::applyLayout(QVector<PieSliceLayout> &layout)
97 106 {
98 //if(m_animator)
99 // m_animator->applyLayout(this,points);
100 //else
101 setLayout(layout);
107 if (m_animator)
108 m_animator->applyLayout(this, layout);
109 else
110 setLayout(layout);
102 111 }
103 112
104 void PieChartItem::setLayout(const QVector<PieSliceLayout> &layout)
113 void PieChartItem::updateLayout(PieSliceLayout &layout)
114 {
115 if (m_animator)
116 m_animator->updateLayout(this, layout);
117 else
118 setLayout(layout);
119 }
120
121 void PieChartItem::setLayout(QVector<PieSliceLayout> &layout)
105 122 {
106 123 foreach (PieSliceLayout l, layout) {
107 124
108 125 // find slice
109 126 PieSlice *slice = m_slices.value(l.m_data);
110 127 if (!slice) {
111 128 // add a new slice
112 129 slice = new PieSlice(this);
113 130 m_slices.insert(l.m_data, slice);
114 131
115 132 // connect signals
116 133 connect(l.m_data, SIGNAL(changed()), this, SLOT(handleSliceChanged()));
117 134 connect(slice, SIGNAL(clicked()), l.m_data, SIGNAL(clicked()));
118 135 connect(slice, SIGNAL(hoverEnter()), l.m_data, SIGNAL(hoverEnter()));
119 136 connect(slice, SIGNAL(hoverLeave()), l.m_data, SIGNAL(hoverLeave()));
120 137 }
121 138
122 139 // update
123 140 slice->setLayout(l);
124 141 slice->updateGeometry();
125 142 slice->update();
126 143 }
127 144
128 145 // delete slices
129 146 foreach (QPieSlice *s, m_slices.keys()) {
130 147
131 148 bool found = false;
132 149 foreach (PieSliceLayout l, layout) {
133 150 if (l.m_data == s)
134 151 found = true;
135 152 }
136 153
137 154 if (!found)
138 delete m_slices.take(s);
155 destroySlice(s);
156 }
157 }
158
159 void PieChartItem::setLayout(PieSliceLayout &layout)
160 {
161 // find slice
162 PieSlice *slice = m_slices.value(layout.m_data);
163 if (!slice) {
164 slice = new PieSlice(this);
165 m_slices.insert(layout.m_data, slice);
166 connect(layout.m_data, SIGNAL(changed()), this, SLOT(handleSliceChanged()));
167 connect(slice, SIGNAL(clicked()), layout.m_data, SIGNAL(clicked()));
168 connect(slice, SIGNAL(hoverEnter()), layout.m_data, SIGNAL(hoverEnter()));
169 connect(slice, SIGNAL(hoverLeave()), layout.m_data, SIGNAL(hoverLeave()));
139 170 }
171 slice->setLayout(layout);
172 if (m_series->m_slices.contains(layout.m_data)) // Slice has been deleted if not found. Animations ongoing...
173 slice->updateData(layout.m_data);
174 slice->updateGeometry();
175 slice->update();
176 }
177
178 void PieChartItem::destroySlice(QPieSlice *slice)
179 {
180 delete m_slices.take(slice);
140 181 }
141 182
142 183 #include "moc_piechartitem_p.cpp"
143 184
144 185 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,48 +1,51
1 1 #ifndef PIECHARTITEM_H
2 2 #define PIECHARTITEM_H
3 3
4 4 #include "qpieseries.h"
5 5 #include "chartitem_p.h"
6 6 #include "pieslice_p.h"
7 7
8 8 class QGraphicsItem;
9 9 QTCOMMERCIALCHART_BEGIN_NAMESPACE
10 10 class QPieSlice;
11 11
12 12 class PieChartItem : public QObject, public ChartItem
13 13 {
14 14 Q_OBJECT
15 15
16 16 public:
17 17 // TODO: use a generic data class instead of x and y
18 18 PieChartItem(QGraphicsItem *parent, QPieSeries *series);
19 19 ~PieChartItem();
20 20
21 21 public: // from QGraphicsItem
22 22 QRectF boundingRect() const { return m_rect; }
23 23 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
24 24
25 25 public Q_SLOTS:
26 26 void handleSeriesChanged();
27 27 void handleSliceChanged();
28 28 void handleDomainChanged(qreal, qreal, qreal, qreal);
29 29 void handleGeometryChanged(const QRectF& rect);
30 30
31 private:
31 public:
32 32 QVector<PieSliceLayout> calculateLayout();
33 void applyLayout(const QVector<PieSliceLayout> &layout);
34 void setLayout(const QVector<PieSliceLayout> &layout);
33 void applyLayout(QVector<PieSliceLayout> &layout);
34 void updateLayout(PieSliceLayout &layout);
35 void setLayout(QVector<PieSliceLayout> &layout);
36 void setLayout(PieSliceLayout &layout);
37 void destroySlice(QPieSlice *slice);
35 38
36 39 private:
37 40 friend class PieSlice;
38 41 QHash<QPieSlice*, PieSlice*> m_slices;
39 42 QPieSeries *m_series;
40 43 QRectF m_rect;
41 44 QPointF m_pieCenter;
42 45 qreal m_pieRadius;
43 46 QRectF m_debugRect;
44 47 };
45 48
46 49 QTCOMMERCIALCHART_END_NAMESPACE
47 50
48 51 #endif // PIECHARTITEM_H
@@ -1,208 +1,203
1 1 #include "pieslice_p.h"
2 2 #include "piechartitem_p.h"
3 3 #include "qpieseries.h"
4 4 #include "qpieslice.h"
5 5 #include "chartpresenter_p.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 #define PI 3.14159265 // TODO: is this defined in some header?
15 15
16 16 QPointF offset(qreal angle, qreal length)
17 17 {
18 18 qreal dx = qSin(angle*(PI/180)) * length;
19 19 qreal dy = qCos(angle*(PI/180)) * length;
20 20 return QPointF(dx, -dy);
21 21 }
22 22
23 23 PieSlice::PieSlice(QGraphicsItem* parent)
24 24 :QGraphicsObject(parent),
25 m_startAngle(0),
26 m_angleSpan(0),
27 25 m_isExploded(false),
28 26 m_explodeDistanceFactor(0),
29 27 m_labelVisible(false),
30 28 m_labelArmLengthFactor(0)
31 29 {
32 30 setAcceptHoverEvents(true);
33 31 setAcceptedMouseButtons(Qt::LeftButton);
34 32 setZValue(ChartPresenter::PieSeriesZValue);
35 33 }
36 34
37 35 PieSlice::~PieSlice()
38 36 {
39 37
40 38 }
41 39
42 40 QRectF PieSlice::boundingRect() const
43 41 {
44 return m_slicePath.boundingRect();
42 return m_slicePath.boundingRect().united(m_labelTextRect);
45 43 }
46 44
47 45 QPainterPath PieSlice::shape() const
48 46 {
49 47 // Don't include the label and label arm.
50 48 // This is used to detect a mouse clicks. We do not want clicks from label.
51 49 return m_slicePath;
52 50 }
53 51
54 52 void PieSlice::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
55 53 {
56 54 painter->setClipRect(parentItem()->boundingRect());
57 55
58 56 painter->save();
59 57 painter->setPen(m_slicePen);
60 58 painter->setBrush(m_sliceBrush);
61 59 painter->drawPath(m_slicePath);
62 60 painter->restore();
63 61
64 62 if (m_labelVisible) {
65 63 painter->save();
66 64 painter->setPen(m_labelArmPen);
67 65 painter->drawPath(m_labelArmPath);
68 66 painter->restore();
69 67
70 68 painter->setFont(m_labelFont);
71 69 painter->drawText(m_labelTextRect.bottomLeft(), m_labelText);
72 70 }
73 71 }
74 72
75 73 void PieSlice::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
76 74 {
77 75 emit hoverEnter();
78 76 }
79 77
80 78 void PieSlice::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
81 79 {
82 80 emit hoverLeave();
83 81 }
84 82
85 83 void PieSlice::mousePressEvent(QGraphicsSceneMouseEvent* /*event*/)
86 84 {
87 85 emit clicked();
88 86 }
89 87
90 88 void PieSlice::setLayout(PieSliceLayout layout)
91 89 {
92 90 m_layout = layout;
93 updateData(layout.m_data);
94 91 }
95 92
96 93 void PieSlice::updateGeometry()
97 94 {
98 95 if (m_layout.m_radius <= 0)
99 96 return;
100 97
101 98 prepareGeometryChange();
102 99
103 100 // update slice path
104 101 qreal centerAngle;
105 102 QPointF armStart;
106 m_slicePath = slicePath(m_layout.m_center, m_layout.m_radius, m_startAngle, m_angleSpan, &centerAngle, &armStart);
103 m_slicePath = slicePath(m_layout.m_center, m_layout.m_radius, m_layout.m_startAngle, m_layout.m_angleSpan, &centerAngle, &armStart);
107 104
108 105 // update text rect
109 106 m_labelTextRect = labelTextRect(m_labelFont, m_labelText);
110 107
111 108 // update label arm path
112 109 QPointF labelTextStart;
113 110 m_labelArmPath = labelArmPath(armStart, centerAngle, m_layout.m_radius * m_labelArmLengthFactor, m_labelTextRect.width(), &labelTextStart);
114 111
115 112 // update text position
116 113 m_labelTextRect.moveBottomLeft(labelTextStart);
117 114
118 115 //qDebug() << "PieSlice::updateGeometry" << m_labelText << boundingRect() << m_startAngle << m_startAngle + m_angleSpan;
119 116 }
120 117
121 118 void PieSlice::updateData(const QPieSlice* sliceData)
122 119 {
123 120 // TODO: compare what has changes to avoid unneccesary geometry updates
124 121
125 m_startAngle = sliceData->startAngle();
126 m_angleSpan = sliceData->m_angleSpan;
127 122 m_isExploded = sliceData->isExploded();
128 123 m_explodeDistanceFactor = sliceData->explodeDistanceFactor();
129 124 m_slicePen = sliceData->slicePen();
130 125 m_sliceBrush = sliceData->sliceBrush();
131 126
132 127 m_labelVisible = sliceData->isLabelVisible();
133 128 m_labelText = sliceData->label();
134 129 m_labelFont = sliceData->labelFont();
135 130 m_labelArmLengthFactor = sliceData->labelArmLengthFactor();
136 131 m_labelArmPen = sliceData->labelArmPen();
137 132 }
138 133
139 134 QPointF PieSlice::sliceCenter(QPointF point, qreal radius, QPieSlice *slice)
140 135 {
141 136 if (slice->isExploded()) {
142 137 qreal centerAngle = slice->startAngle() + (slice->m_angleSpan/2);
143 138 qreal len = radius * slice->explodeDistanceFactor();
144 139 qreal dx = qSin(centerAngle*(PI/180)) * len;
145 140 qreal dy = -qCos(centerAngle*(PI/180)) * len;
146 141 point += QPointF(dx, dy);
147 142 }
148 143 return point;
149 144 }
150 145
151 146 QPainterPath PieSlice::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal* centerAngle, QPointF* armStart)
152 147 {
153 148 // calculate center angle
154 149 *centerAngle = startAngle + (angleSpan/2);
155 150
156 151 // calculate slice rectangle
157 152 QRectF rect(center.x()-radius, center.y()-radius, radius*2, radius*2);
158 153
159 154 // slice path
160 155 // TODO: draw the shape so that it might have a hole in the center
161 156 QPainterPath path;
162 157 path.moveTo(rect.center());
163 158 path.arcTo(rect, -startAngle + 90, -angleSpan);
164 159 path.closeSubpath();
165 160
166 161 // calculate label arm start point
167 162 *armStart = center;
168 163 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
169 164
170 165 return path;
171 166 }
172 167
173 168 QPainterPath PieSlice::labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF* textStart)
174 169 {
175 170 qreal dx = qSin(angle*(PI/180)) * length;
176 171 qreal dy = -qCos(angle*(PI/180)) * length;
177 172 QPointF parm1 = start + QPointF(dx, dy);
178 173
179 174 QPointF parm2 = parm1;
180 175 if (angle < 180) { // arm swings the other way on the left side
181 176 parm2 += QPointF(textWidth, 0);
182 177 *textStart = parm1;
183 178 }
184 179 else {
185 180 parm2 += QPointF(-textWidth,0);
186 181 *textStart = parm2;
187 182 }
188 183
189 184 // elevate the text position a bit so that it does not hit the line
190 185 *textStart += QPointF(0, -5);
191 186
192 187 QPainterPath path;
193 188 path.moveTo(start);
194 189 path.lineTo(parm1);
195 190 path.lineTo(parm2);
196 191
197 192 return path;
198 193 }
199 194
200 195 QRectF PieSlice::labelTextRect(QFont font, QString text)
201 196 {
202 197 QFontMetricsF fm(font);
203 198 return fm.boundingRect(text);
204 199 }
205 200
206 201 #include "moc_pieslice_p.cpp"
207 202
208 203 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,82 +1,80
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 #define PIESLICE_LABEL_GAP 5
13 13
14 14 QTCOMMERCIALCHART_BEGIN_NAMESPACE
15 15 class PieChartItem;
16 16 class PieSliceLabel;
17 17 class QPieSlice;
18 18
19 19 class PieSliceLayout
20 20 {
21 21 public:
22 QPieSlice* m_data;
22 QPieSlice* m_data; // TODO: get rid of this
23 23 QPointF m_center;
24 24 qreal m_radius;
25 25 qreal m_startAngle;
26 26 qreal m_angleSpan;
27 27 };
28 28
29 29 class PieSlice : public QGraphicsObject
30 30 {
31 31 Q_OBJECT
32 32
33 33 public:
34 34 PieSlice(QGraphicsItem* parent = 0);
35 35 ~PieSlice();
36 36
37 37 public: // from QGraphicsItem
38 38 QRectF boundingRect() const;
39 39 QPainterPath shape() const;
40 40 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
41 41 void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
42 42 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
43 43 void mousePressEvent(QGraphicsSceneMouseEvent *event);
44 44
45 45 Q_SIGNALS:
46 46 void clicked();
47 47 void hoverEnter();
48 48 void hoverLeave();
49 49
50 50 public:
51 51 void setLayout(PieSliceLayout layout);
52 52 void updateGeometry();
53 53 void updateData(const QPieSlice *sliceData);
54 54 static QPointF sliceCenter(QPointF point, qreal radius, QPieSlice *slice);
55 55 static QPainterPath slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal* centerAngle, QPointF* armStart);
56 56 static QPainterPath labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF* textStart);
57 57 static QRectF labelTextRect(QFont font, QString text);
58 58
59 59 private:
60 60 PieSliceLayout m_layout;
61 61
62 62 QPainterPath m_slicePath;
63 qreal m_startAngle;
64 qreal m_angleSpan;
65 63 bool m_isExploded;
66 64 qreal m_explodeDistanceFactor;
67 65 bool m_labelVisible;
68 66 QPen m_slicePen;
69 67 QBrush m_sliceBrush;
70 68
71 69 QPainterPath m_labelArmPath;
72 70 qreal m_labelArmLengthFactor;
73 71 QPen m_labelArmPen;
74 72
75 73 QRectF m_labelTextRect;
76 74 QFont m_labelFont;
77 75 QString m_labelText;
78 76 };
79 77
80 78 QTCOMMERCIALCHART_END_NAMESPACE
81 79
82 80 #endif // PIESLICE_H
@@ -1,643 +1,649
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 \class QPieSeries
93 93 \brief Pie series API for QtCommercial Charts
94 94
95 95 The pie series defines a pie chart which consists of pie slices which are QPieSlice objects.
96 96 The slices can have any values as the QPieSeries will calculate its relative value to the sum of all slices.
97 97 The actual slice size is determined by that relative value.
98 98
99 99 By default the pie is defined as a full pie but it can be a partial pie.
100 100 This can be done by setting a starting angle and angle span to the series.
101 101 */
102 102
103 103 /*!
104 104 Constructs a series object which is a child of \a parent.
105 105 */
106 106 QPieSeries::QPieSeries(QObject *parent) :
107 107 QSeries(parent),
108 108 m_pieRelativeHorPos(0.5),
109 109 m_pieRelativeVerPos(0.5),
110 110 m_pieRelativeSize(0.7),
111 111 m_pieStartAngle(0),
112 112 m_pieEndAngle(360),
113 113 m_total(0)
114 114 {
115 115
116 116 }
117 117
118 118 /*!
119 119 Destroys the object. Note that adding series to QChart transfers the ownership to the chart.
120 120 */
121 121 QPieSeries::~QPieSeries()
122 122 {
123 123
124 124 }
125 125
126 126 /*!
127 127 Returns QChartSeries::SeriesTypePie.
128 128 */
129 129 QSeries::QSeriesType QPieSeries::type() const
130 130 {
131 131 return QSeries::SeriesTypePie;
132 132 }
133 133
134 134 /*!
135 135 Sets an array of \a slices to the series replacing the existing slices.
136 136 Slice ownership is passed to the series.
137 137 */
138 138 void QPieSeries::replace(QList<QPieSlice*> slices)
139 139 {
140 140 clear();
141 141 add(slices);
142 142 }
143 143
144 144 /*!
145 145 Adds an array of \a slices to the series.
146 146 Slice ownership is passed to the series.
147 147 */
148 148 void QPieSeries::add(QList<QPieSlice*> slices)
149 149 {
150 150 foreach (QPieSlice* s, slices) {
151 151 s->setParent(this);
152 152 m_slices << s;
153 153 }
154 154
155 155 updateDerivativeData();
156 156
157 157 foreach (QPieSlice* s, slices) {
158 158 connect(s, SIGNAL(changed()), this, SLOT(sliceChanged()));
159 159 connect(s, SIGNAL(clicked()), this, SLOT(sliceClicked()));
160 160 connect(s, SIGNAL(hoverEnter()), this, SLOT(sliceHoverEnter()));
161 161 connect(s, SIGNAL(hoverLeave()), this, SLOT(sliceHoverLeave()));
162 162 }
163 163
164 164 emit changed();
165 165 }
166 166
167 167 /*!
168 168 Adds a single \a slice to the series.
169 169 Slice ownership is passed to the series.
170 170 */
171 171 void QPieSeries::add(QPieSlice* slice)
172 172 {
173 173 add(QList<QPieSlice*>() << slice);
174 174 }
175 175
176 176 /*!
177 177 Adds a single \a slice to the series and returns a reference to the series.
178 178 Slice ownership is passed to the series.
179 179 */
180 180 QPieSeries& QPieSeries::operator << (QPieSlice* slice)
181 181 {
182 182 add(slice);
183 183 return *this;
184 184 }
185 185
186 186
187 187 /*!
188 188 Adds a single slice to the series with give \a value and \a name.
189 189 Slice ownership is passed to the series.
190 190 */
191 191 QPieSlice* QPieSeries::add(qreal value, QString name)
192 192 {
193 193 QPieSlice* slice = new QPieSlice(value, name);
194 194 add(slice);
195 195 return slice;
196 196 }
197 197
198 198 void QPieSeries::insert(int i, QPieSlice* slice)
199 199 {
200 200 Q_ASSERT(i <= m_slices.count());
201 201 slice->setParent(this);
202 202 m_slices.insert(i, slice);
203 203
204 204 updateDerivativeData();
205 205
206 206 connect(slice, SIGNAL(changed()), this, SLOT(sliceChanged()));
207 207 connect(slice, SIGNAL(clicked()), this, SLOT(sliceClicked()));
208 208 connect(slice, SIGNAL(hoverEnter()), this, SLOT(sliceHoverEnter()));
209 209 connect(slice, SIGNAL(hoverLeave()), this, SLOT(sliceHoverLeave()));
210 210
211 211 emit changed();
212 212 }
213 213
214 214 /*!
215 215 Removes a single \a slice from the series and deletes the slice.
216 216
217 217 Do not reference this pointer after this call.
218 218 */
219 219 void QPieSeries::remove(QPieSlice* slice)
220 220 {
221 221 if (!m_slices.removeOne(slice)) {
222 222 Q_ASSERT(0); // TODO: how should this be reported?
223 223 return;
224 224 }
225 225 emit changed();
226 226
227 227 updateDerivativeData();
228 228
229 229 delete slice;
230 230 slice = NULL;
231 231 }
232 232
233 233 /*!
234 234 Clears all slices from the series.
235 235 */
236 236 void QPieSeries::clear()
237 237 {
238 238 if (m_slices.count() == 0)
239 239 return;
240 240
241 241 foreach (QPieSlice* s, m_slices) {
242 242 m_slices.removeOne(s);
243 243 delete s;
244 244 }
245 245
246 246 emit changed();
247 247
248 248 updateDerivativeData();
249 249 }
250 250
251 251 /*!
252 252 Counts the number of the slices in this series.
253 253 */
254 254 int QPieSeries::count() const
255 255 {
256 256 return m_slices.count();
257 257 }
258 258
259 259 /*!
260 260 Returns a list of slices that belong to this series.
261 261 */
262 262 QList<QPieSlice*> QPieSeries::slices() const
263 263 {
264 264 return m_slices;
265 265 }
266 266
267 267 /*!
268 268 Sets the center position of the pie by \a relativeHorizontalPosition and \a relativeVerticalPosition.
269 269
270 270 The factors are relative to the chart rectangle where:
271 271
272 272 \a relativeHorizontalPosition 0.0 means the absolute left.
273 273 \a relativeHorizontalPosition 1.0 means the absolute right.
274 274 \a relativeVerticalPosition 0.0 means the absolute top.
275 275 \a relativeVerticalPosition 1.0 means the absolute bottom.
276 276
277 277 By default both values are 0.5 which puts the pie in the middle of the chart rectangle.
278 278
279 279 \sa pieHorizontalPosition(), pieVerticalPosition(), setPieSize()
280 280 */
281 281 void QPieSeries::setPiePosition(qreal relativeHorizontalPosition, qreal relativeVerticalPosition)
282 282 {
283 283 if (relativeHorizontalPosition < 0.0 || relativeHorizontalPosition > 1.0 ||
284 284 relativeVerticalPosition < 0.0 || relativeVerticalPosition > 1.0)
285 285 return;
286 286
287 287 if (m_pieRelativeHorPos != relativeHorizontalPosition || m_pieRelativeVerPos != relativeVerticalPosition) {
288 288 m_pieRelativeHorPos = relativeHorizontalPosition;
289 289 m_pieRelativeVerPos = relativeVerticalPosition;
290 290 emit changed();
291 291 }
292 292 }
293 293
294 294 /*!
295 295 Gets the horizontal position of the pie.
296 296
297 297 The returned value is relative to the chart rectangle where:
298 298
299 299 0.0 means the absolute left.
300 300 1.0 means the absolute right.
301 301
302 302 By default it is 0.5 which puts the pie in the horizontal middle of the chart rectangle.
303 303
304 304 \sa setPiePosition(), pieVerticalPosition(), setPieSize()
305 305 */
306 306 qreal QPieSeries::pieHorizontalPosition() const
307 307 {
308 308 return m_pieRelativeHorPos;
309 309 }
310 310
311 311 /*!
312 312 Gets the vertical position position of the pie.
313 313
314 314 The returned value is relative to the chart rectangle where:
315 315
316 316 0.0 means the absolute top.
317 317 1.0 means the absolute bottom.
318 318
319 319 By default it is 0.5 which puts the pie in the vertical middle of the chart rectangle.
320 320
321 321 \sa setPiePosition(), pieHorizontalPosition(), setPieSize()
322 322 */
323 323 qreal QPieSeries::pieVerticalPosition() const
324 324 {
325 325 return m_pieRelativeVerPos;
326 326 }
327 327
328 328 /*!
329 329 Sets the relative size of the pie.
330 330
331 331 The \a relativeSize is defined so that the 1.0 is the maximum that can fit the given chart rectangle.
332 332
333 333 Default value is 0.7.
334 334
335 335 \sa pieSize(), setPiePosition(), pieVerticalPosition(), pieHorizontalPosition()
336 336 */
337 337 void QPieSeries::setPieSize(qreal relativeSize)
338 338 {
339 339 if (relativeSize < 0.0 || relativeSize > 1.0)
340 340 return;
341 341
342 342 if (m_pieRelativeSize != relativeSize) {
343 343 m_pieRelativeSize = relativeSize;
344 344 emit changed();
345 345 }
346 346 }
347 347
348 348 /*!
349 349 Gets the relative size of the pie.
350 350
351 351 The size is defined so that the 1.0 is the maximum that can fit the given chart rectangle.
352 352
353 353 Default value is 0.7.
354 354
355 355 \sa setPieSize(), setPiePosition(), pieVerticalPosition(), pieHorizontalPosition()
356 356 */
357 357 qreal QPieSeries::pieSize() const
358 358 {
359 359 return m_pieRelativeSize;
360 360 }
361 361
362 362
363 363 /*!
364 364 Sets the end angle of the pie.
365 365
366 366 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
367 367
368 368 \a angle must be less than pie end angle. Default value is 0.
369 369
370 370 \sa pieStartAngle(), pieEndAngle(), setPieEndAngle()
371 371 */
372 372 void QPieSeries::setPieStartAngle(qreal angle)
373 373 {
374 374 if (angle >= 0 && angle <= 360 && angle != m_pieStartAngle && angle <= m_pieEndAngle) {
375 375 m_pieStartAngle = angle;
376 376 updateDerivativeData();
377 377 }
378 378 }
379 379
380 380 /*!
381 381 Gets the start angle of the pie.
382 382
383 383 Full pie is 360 degrees where 0 degrees is at 12 a'clock. Default value is 360.
384 384
385 385 \sa setPieStartAngle(), pieEndAngle(), setPieEndAngle()
386 386 */
387 387 qreal QPieSeries::pieStartAngle() const
388 388 {
389 389 return m_pieStartAngle;
390 390 }
391 391
392 392 /*!
393 393 Sets the end angle of the pie.
394 394
395 395 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
396 396
397 397 \a angle must be greater than start angle.
398 398
399 399 \sa pieEndAngle(), pieStartAngle(), setPieStartAngle()
400 400 */
401 401 void QPieSeries::setPieEndAngle(qreal angle)
402 402 {
403 403 if (angle >= 0 && angle <= 360 && angle != m_pieEndAngle && angle >= m_pieStartAngle) {
404 404 m_pieEndAngle = angle;
405 405 updateDerivativeData();
406 406 }
407 407 }
408 408
409 409 /*!
410 410 Returns the end angle of the pie.
411 411
412 412 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
413 413
414 414 \sa setPieEndAngle(), pieStartAngle(), setPieStartAngle()
415 415 */
416 416 qreal QPieSeries::pieEndAngle() const
417 417 {
418 418 return m_pieEndAngle;
419 419 }
420 420
421 421 /*!
422 422 Sets the all the slice labels \a visible or invisible.
423 423
424 424 \sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible()
425 425 */
426 426 void QPieSeries::setLabelsVisible(bool visible)
427 427 {
428 428 foreach (QPieSlice* s, m_slices)
429 429 s->setLabelVisible(visible);
430 430 }
431 431
432 432 /*!
433 433 Returns the sum of all slice values in this series.
434 434
435 435 \sa QPieSlice::value(), QPieSlice::setValue()
436 436 */
437 437 qreal QPieSeries::total() const
438 438 {
439 439 return m_total;
440 440 }
441 441
442 442 /*!
443 443 \fn void QPieSeries::changed()
444 444
445 445 This signal emitted when something has changed in the series.
446 446
447 447 \sa QPieSeries::ChangeSet, QPieSlice::changed()
448 448 */
449 449
450 450 /*!
451 451 \fn void QPieSeries::clicked(QPieSlice* slice)
452 452
453 453 This signal is emitted when a \a slice has been clicked.
454 454
455 455 \sa QPieSlice::clicked()
456 456 */
457 457
458 458 /*!
459 459 \fn void QPieSeries::hoverEnter(QPieSlice* slice)
460 460
461 461 This signal is emitted when user has hovered over a \a slice.
462 462
463 463 \sa QPieSlice::hoverEnter()
464 464 */
465 465
466 466 /*!
467 467 \fn void QPieSeries::hoverLeave(QPieSlice* slice)
468 468
469 469 This signal is emitted when user has hovered away from a \a slice.
470 470
471 471 \sa QPieSlice::hoverLeave()
472 472 */
473 473
474 474 void QPieSeries::sliceChanged()
475 475 {
476 476 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
477 477 Q_ASSERT(m_slices.contains(slice));
478 478 updateDerivativeData();
479 479 }
480 480
481 481 void QPieSeries::sliceClicked()
482 482 {
483 483 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
484 484 Q_ASSERT(m_slices.contains(slice));
485 485 emit clicked(slice);
486 486 }
487 487
488 488 void QPieSeries::sliceHoverEnter()
489 489 {
490 490 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
491 491 Q_ASSERT(m_slices.contains(slice));
492 492 emit hoverEnter(slice);
493 493 }
494 494
495 495 void QPieSeries::sliceHoverLeave()
496 496 {
497 497 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
498 498 Q_ASSERT(m_slices.contains(slice));
499 499 emit hoverLeave(slice);
500 500 }
501 501
502 502 void QPieSeries::updateDerivativeData()
503 503 {
504 504 m_total = 0;
505 505
506 506 // nothing to do?
507 507 if (m_slices.count() == 0)
508 508 return;
509 509
510 510 // calculate total
511 511 foreach (QPieSlice* s, m_slices)
512 512 m_total += s->value();
513 513
514 // TODO: emit totalChanged?
515
514 516 // we must have some values
515 517 if (m_total == 0) {
516 518 qDebug() << "QPieSeries::updateDerivativeData() total == 0";
517 519 Q_ASSERT(m_total > 0); // TODO: is this the correct way to handle this?
518 520 }
519 521
520 522 // update slice attributes
521 523 qreal sliceAngle = m_pieStartAngle;
522 524 qreal pieSpan = m_pieEndAngle - m_pieStartAngle;
525 QVector<QPieSlice*> changed;
523 526 foreach (QPieSlice* s, m_slices) {
524 527
525 bool changed = false;
528 bool isChanged = false;
526 529
527 530 qreal percentage = s->value() / m_total;
528 531 if (s->m_percentage != percentage) {
529 532 s->m_percentage = percentage;
530 changed = true;
533 isChanged = true;
531 534 }
532 535
533 536 qreal sliceSpan = pieSpan * percentage;
534 537 if (s->m_angleSpan != sliceSpan) {
535 538 s->m_angleSpan = sliceSpan;
536 changed = true;
539 isChanged = true;
537 540 }
538 541
539 542 if (s->m_startAngle != sliceAngle) {
540 543 s->m_startAngle = sliceAngle;
541 changed = true;
544 isChanged = true;
542 545 }
543 546 sliceAngle += sliceSpan;
544 547
545 if (changed)
546 emit s->changed();
548 if (isChanged)
549 changed << s;
547 550 }
551
552 foreach (QPieSlice* s, changed)
553 emit s->changed();
548 554 }
549 555
550 556 bool QPieSeries::setModel(QAbstractItemModel* model)
551 557 {
552 558 // disconnect signals from old model
553 559 if(m_model)
554 560 {
555 561 disconnect(m_model,SIGNAL(dataChanged(QModelIndex,QModelIndex)), 0, 0);
556 562 disconnect(m_model,SIGNAL(rowsInserted(QModelIndex, int, int)), 0, 0);
557 563 disconnect(m_model, SIGNAL(rowsRemoved(QModelIndex, int, int)), 0, 0);
558 564 }
559 565
560 566 // set new model if not NULL and connect necessary signals from it
561 567 if(model)
562 568 {
563 569 m_model = model;
564 570 connect(m_model,SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(modelUpdated(QModelIndex, QModelIndex)));
565 571 connect(m_model,SIGNAL(rowsInserted(QModelIndex, int, int)), this, SLOT(modelDataAdded(QModelIndex,int,int)));
566 572 connect(m_model, SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SLOT(modelDataRemoved(QModelIndex,int,int)));
567 573 }
568 574
569 575 return true;
570 576 }
571 577
572 578 void QPieSeries::setModelMapping(int modelValuesLine, int modelLabelsLine, Qt::Orientation orientation)
573 579 {
574 580 m_mapValues = modelValuesLine;
575 581 m_mapLabels = modelLabelsLine;
576 582 m_mapOrientation = orientation;
577 583
578 584 if (m_model == NULL)
579 585 return;
580 586
581 587 if (m_mapOrientation == Qt::Vertical)
582 588 for (int i = 0; i < m_model->rowCount(); i++)
583 589 add(m_model->data(m_model->index(i, m_mapValues), Qt::DisplayRole).toDouble(), m_model->data(m_model->index(i, m_mapLabels), Qt::DisplayRole).toString());
584 590 else
585 591 for (int i = 0; i < m_model->columnCount(); i++)
586 592 add(m_model->data(m_model->index(m_mapValues, i), Qt::DisplayRole).toDouble(), m_model->data(m_model->index(m_mapLabels, i), Qt::DisplayRole).toString());
587 593
588 594
589 595 }
590 596
591 597 void QPieSeries::modelUpdated(QModelIndex topLeft, QModelIndex bottomRight)
592 598 {
593 599 Q_UNUSED(bottomRight)
594 600
595 601 if (m_mapOrientation == Qt::Vertical)
596 602 {
597 603 // slices().at(topLeft.row())->setValue(m_model->data(m_model->index(topLeft.row(), topLeft.column()), Qt::DisplayRole).toDouble());
598 604 if (topLeft.column() == m_mapValues)
599 605 slices().at(topLeft.row())->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble());
600 606 else if (topLeft.column() == m_mapLabels)
601 607 slices().at(topLeft.row())->setLabel(m_model->data(topLeft, Qt::DisplayRole).toString());
602 608 }
603 609 else
604 610 {
605 611 // slices().at(topLeft.column())->setValue(m_model->data(m_model->index(topLeft.row(), topLeft.column()), Qt::DisplayRole).toDouble());
606 612 if (topLeft.column() == m_mapValues)
607 613 slices().at(topLeft.column())->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble());
608 614 else if (topLeft.column() == m_mapLabels)
609 615 slices().at(topLeft.column())->setLabel(m_model->data(topLeft, Qt::DisplayRole).toString());
610 616 }
611 617 }
612 618
613 619 void QPieSeries::modelDataAdded(QModelIndex parent, int start, int end)
614 620 {
615 621 Q_UNUSED(parent)
616 622 Q_UNUSED(end)
617 623
618 624 QPieSlice* newSlice = new QPieSlice;
619 625 newSlice->setLabelVisible(true);
620 626 if (m_mapOrientation == Qt::Vertical)
621 627 {
622 628 newSlice->setValue(m_model->data(m_model->index(start, m_mapValues), Qt::DisplayRole).toDouble());
623 629 newSlice->setLabel(m_model->data(m_model->index(start, m_mapLabels), Qt::DisplayRole).toString());
624 630 }
625 631 else
626 632 {
627 633 newSlice->setValue(m_model->data(m_model->index(m_mapValues, start), Qt::DisplayRole).toDouble());
628 634 newSlice->setLabel(m_model->data(m_model->index(m_mapLabels, start), Qt::DisplayRole).toString());
629 635 }
630 636
631 637 insert(start, newSlice);
632 638 }
633 639
634 640 void QPieSeries::modelDataRemoved(QModelIndex parent, int start, int end)
635 641 {
636 642 Q_UNUSED(parent)
637 643 Q_UNUSED(end)
638 644 remove(slices().at(start));
639 645 }
640 646
641 647 #include "moc_qpieseries.cpp"
642 648
643 649 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,144 +1,145
1 1 #ifndef PIESERIES_H
2 2 #define PIESERIES_H
3 3
4 4 #include "qseries.h"
5 5 #include <QObject>
6 6 #include <QRectF>
7 7 #include <QColor>
8 8 #include <QPen>
9 9 #include <QBrush>
10 10 #include <QSignalMapper>
11 11
12 12 class QGraphicsObject;
13 13 QTCOMMERCIALCHART_BEGIN_NAMESPACE
14 14 class PieChartItem;
15 15 class PieSlice;
16 16 class QPieSlice;
17 17
18 18 class QTCOMMERCIALCHART_EXPORT QPieSeries : public QSeries
19 19 {
20 20 Q_OBJECT
21 21
22 22 public:
23 23
24 24 class ChangeSet
25 25 {
26 26 public:
27 27
28 28 // TODO: these should not really be exposed to the public API
29 29 void appendAdded(QPieSlice* slice);
30 30 void appendAdded(QList<QPieSlice*> slices);
31 31 void appendChanged(QPieSlice* slice);
32 32 void appendRemoved(QPieSlice* slice);
33 33
34 34 QList<QPieSlice*> added() const;
35 35 QList<QPieSlice*> changed() const;
36 36 QList<QPieSlice*> removed() const;
37 37
38 38 bool isEmpty() const;
39 39
40 40 private:
41 41 QList<QPieSlice*> m_added;
42 42 QList<QPieSlice*> m_changed;
43 43 QList<QPieSlice*> m_removed;
44 44 };
45 45
46 46 public:
47 47 QPieSeries(QObject *parent = 0);
48 48 virtual ~QPieSeries();
49 49
50 50 public: // from QChartSeries
51 51 QSeriesType type() const;
52 52
53 53 public:
54 54
55 55 // slice setters
56 56 void add(QPieSlice* slice);
57 57 void add(QList<QPieSlice*> slices);
58 58 void insert(int i, QPieSlice* slice);
59 59 void replace(QList<QPieSlice*> slices);
60 60 void remove(QPieSlice* slice);
61 61 void clear();
62 62
63 63 // sluce getters
64 64 QList<QPieSlice*> slices() const;
65 65
66 66 // calculated data
67 67 int count() const;
68 68 qreal total() const;
69 69
70 70 // pie customization
71 71 void setPiePosition(qreal relativeHorizontalPosition, qreal relativeVerticalPosition);
72 72 qreal pieHorizontalPosition() const;
73 73 qreal pieVerticalPosition() const;
74 74 void setPieSize(qreal relativeSize);
75 75 qreal pieSize() const;
76 76 void setPieStartAngle(qreal startAngle);
77 77 qreal pieStartAngle() const;
78 78 void setPieEndAngle(qreal endAngle);
79 79 qreal pieEndAngle() const;
80 80
81 81 // convenience function
82 82 QPieSeries& operator << (QPieSlice* slice);
83 83 QPieSlice* add(qreal value, QString name);
84 84 void setLabelsVisible(bool visible = true);
85 85
86 86 // data from model
87 87 bool setModel(QAbstractItemModel* model);
88 88 void setModelMapping(int modelValuesLine, int modelLabelsLine, Qt::Orientation orientation = Qt::Vertical);
89 89
90 90 // TODO: find slices?
91 91 // QList<QPieSlice*> findByValue(qreal value);
92 92 // ...
93 93
94 94 // TODO: sorting slices?
95 95 // void sort(QPieSeries::SortByValue|label|??)
96 96
97 97 // TODO: general graphics customization
98 98 // setDrawStyle(2d|3d)
99 99 // setDropShadows
100 100
101 101 Q_SIGNALS:
102 102 void clicked(QPieSlice* slice);
103 103 void hoverEnter(QPieSlice* slice);
104 104 void hoverLeave(QPieSlice* slice);
105 105 void changed(); // TODO: hide this in PIMPL
106 106
107 107 private Q_SLOTS: // TODO: should be private and not visible in the interface at all
108 108 void sliceChanged();
109 109 void sliceClicked();
110 110 void sliceHoverEnter();
111 111 void sliceHoverLeave();
112 112
113 113 // slots for updating pie when data in model changes
114 114 void modelUpdated(QModelIndex topLeft, QModelIndex bottomRight);
115 115 void modelDataAdded(QModelIndex parent, int start, int end);
116 116 void modelDataRemoved(QModelIndex parent, int start, int end);
117 117
118 118 private:
119 119 void updateDerivativeData();
120 120
121 121 private:
122 122 Q_DISABLE_COPY(QPieSeries)
123 123
124 124 // TODO: use PIML
125 125 friend class PieChartItem;
126 126 friend class PieSlice;
127 friend class QPieSlice;
127 128
128 129 QList<QPieSlice*> m_slices;
129 130 qreal m_pieRelativeHorPos;
130 131 qreal m_pieRelativeVerPos;
131 132 qreal m_pieRelativeSize;
132 133 qreal m_pieStartAngle;
133 134 qreal m_pieEndAngle;
134 135 qreal m_total;
135 136
136 137 // model map
137 138 int m_mapValues;
138 139 int m_mapLabels;
139 140 Qt::Orientation m_mapOrientation;
140 141 };
141 142
142 143 QTCOMMERCIALCHART_END_NAMESPACE
143 144
144 145 #endif // PIESERIES_H
@@ -1,401 +1,407
1 1 #include "qpieslice.h"
2 #include "qpieseries.h"
2 3
3 4 QTCOMMERCIALCHART_BEGIN_NAMESPACE
4 5
5 6 #define DEFAULT_PEN_COLOR Qt::black
6 7 #define DEFAULT_BRUSH_COLOR Qt::white
7 8 #define DEFAULT_LABEL_ARM_LENGTH_FACTOR 0.15
8 9 #define DEFAULT_EXPOLODE_DISTANCE_FACTOR 0.15
9 10
10 11 /*!
11 12 \class QPieSlice
12 13 \brief Defines a slice in pie series.
13 14
14 15 Holds all the data of a single slice in a QPieSeries and provides the means
15 16 to modify slice data and customize the visual appearance of the slice.
16 17
17 18 It also provides the means to customize user interaction with the slice by
18 19 providing signals for clicking and hover events.
19 20 */
20 21
21 22 /*!
22 23 \property QPieSlice::label
23 24
24 25 Label of the slice.
25 26 */
26 27
27 28 /*!
28 29 \property QPieSlice::value
29 30
30 31 Value of the slice.
31 32 */
32 33
33 34 /*!
34 35 Constructs an empty slice with a \a parent.
35 36
36 37 Note that QPieSeries takes ownership of the slice when it is set/added.
37 38
38 39 \sa QPieSeries::replace(), QPieSeries::add()
39 40 */
40 41 QPieSlice::QPieSlice(QObject *parent)
41 42 :QObject(parent),
42 43 m_value(0),
43 44 m_isLabelVisible(false),
44 45 m_isExploded(false),
45 46 m_explodeDistanceFactor(DEFAULT_EXPOLODE_DISTANCE_FACTOR),
46 47 m_percentage(0),
47 48 m_startAngle(0),
48 49 m_angleSpan(0),
49 50 m_slicePen(DEFAULT_PEN_COLOR),
50 51 m_sliceBrush(DEFAULT_BRUSH_COLOR),
51 52 m_labelArmPen(DEFAULT_PEN_COLOR),
52 53 m_labelArmLengthFactor(DEFAULT_LABEL_ARM_LENGTH_FACTOR)
53 54 {
54 55
55 56 }
56 57
57 58 /*!
58 59 Constructs an empty slice with given \a value, \a label and a \a parent.
59 60 Note that QPieSeries takes ownership of the slice when it is set/added.
60 61 \sa QPieSeries::replace(), QPieSeries::add()
61 62 */
62 63 QPieSlice::QPieSlice(qreal value, QString label, QObject *parent)
63 64 :QObject(parent),
64 65 m_value(value),
65 66 m_label(label),
66 67 m_isLabelVisible(false),
67 68 m_isExploded(false),
68 69 m_explodeDistanceFactor(DEFAULT_EXPOLODE_DISTANCE_FACTOR),
69 70 m_percentage(0),
70 71 m_startAngle(0),
71 72 m_angleSpan(0),
72 73 m_slicePen(DEFAULT_PEN_COLOR),
73 74 m_sliceBrush(DEFAULT_BRUSH_COLOR),
74 75 m_labelArmPen(DEFAULT_PEN_COLOR),
75 76 m_labelArmLengthFactor(DEFAULT_LABEL_ARM_LENGTH_FACTOR)
76 77 {
77 78
78 79 }
79 80
80 81 /*!
81 82 Destroys the slice.
82 83 User should not delete the slice if it has been added to the series.
83 84 */
84 85 QPieSlice::~QPieSlice()
85 86 {
86 87
87 88 }
88 89
89 90 /*!
90 91 Gets the value of the slice.
91 92 Note that all values in the series
92 93 \sa setValue()
93 94 */
94 95 qreal QPieSlice::value() const
95 96 {
96 97 return m_value;
97 98 }
98 99
99 100 /*!
100 101 Gets the label of the slice.
101 102 \sa setLabel()
102 103 */
103 104 QString QPieSlice::label() const
104 105 {
105 106 return m_label;
106 107 }
107 108
108 109 /*!
109 110 Returns true if label is set as visible.
110 111 \sa setLabelVisible()
111 112 */
112 113 bool QPieSlice::isLabelVisible() const
113 114 {
114 115 return m_isLabelVisible;
115 116 }
116 117
117 118 /*!
118 119 Returns true if slice is exloded from the pie.
119 120 \sa setExploded(), setExplodeDistanceFactor()
120 121 */
121 122 bool QPieSlice::isExploded() const
122 123 {
123 124 return m_isExploded;
124 125 }
125 126
126 127 /*!
127 128 Returns the explode distance factor.
128 129
129 130 The factor is relative to pie radius. For example:
130 131 1.0 means the distance is the same as the radius.
131 132 0.5 means the distance is half of the radius.
132 133
133 134 Default value is 0.15.
134 135
135 136 \sa setExplodeDistanceFactor()
136 137 */
137 138 qreal QPieSlice::explodeDistanceFactor() const
138 139 {
139 140 return m_explodeDistanceFactor;
140 141 }
141 142
142 143 /*!
143 144 Returns the percentage of this slice compared to all slices in the same series.
144 145 The returned value ranges from 0 to 1.0.
145 146
146 147 Updated internally after the slice is added to the series.
147 148 */
148 149 qreal QPieSlice::percentage() const
149 150 {
150 151 return m_percentage;
151 152 }
152 153
153 154 /*!
154 155 Returns the starting angle of this slice in the series it belongs to.
155 156
156 157 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
157 158
158 159 Updated internally after the slice is added to the series.
159 160 */
160 161 qreal QPieSlice::startAngle() const
161 162 {
162 163 return m_startAngle;
163 164 }
164 165
165 166 /*!
166 167 Returns the end angle of this slice in the series it belongs to.
167 168
168 169 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
169 170
170 171 Updated internally after the slice is added to the series.
171 172 */
172 173 qreal QPieSlice::endAngle() const
173 174 {
174 175 return m_startAngle + m_angleSpan;
175 176 }
176 177
177 178 /*!
178 179 Returns the pen used to draw this slice.
179 180 \sa setSlicePen()
180 181 */
181 182 QPen QPieSlice::slicePen() const
182 183 {
183 184 return m_slicePen;
184 185 }
185 186
186 187 /*!
187 188 Returns the brush used to draw this slice.
188 189 \sa setSliceBrush()
189 190 */
190 191 QBrush QPieSlice::sliceBrush() const
191 192 {
192 193 return m_sliceBrush;
193 194 }
194 195
195 196 /*!
196 197 Returns the pen used to draw label arm in this slice.
197 198 \sa setLabelArmPen()
198 199 */
199 200 QPen QPieSlice::labelArmPen() const
200 201 {
201 202 return m_labelArmPen;
202 203 }
203 204
204 205 /*!
205 206 Returns the font used to draw label in this slice.
206 207 \sa setLabelFont()
207 208 */
208 209 QFont QPieSlice::labelFont() const
209 210 {
210 211 return m_labelFont;
211 212 }
212 213
213 214 /*!
214 215 Gets the label arm lenght factor.
215 216
216 217 The factor is relative to pie radius. For example:
217 218 1.0 means the length is the same as the radius.
218 219 0.5 means the length is half of the radius.
219 220
220 221 Default value is 0.15
221 222
222 223 \sa setLabelArmLengthFactor()
223 224 */
224 225 qreal QPieSlice::labelArmLengthFactor() const
225 226 {
226 227 return m_labelArmLengthFactor;
227 228 }
228 229
229 230 /*!
230 231 \fn void QPieSlice::clicked()
231 232
232 233 This signal is emitted when user has clicked the slice.
233 234
234 235 \sa QPieSeries::clicked()
235 236 */
236 237
237 238 /*!
238 239 \fn void QPieSlice::hoverEnter()
239 240
240 241 This signal is emitted when user has hovered over the slice.
241 242
242 243 \sa QPieSeries::hoverEnter()
243 244 */
244 245
245 246 /*!
246 247 \fn void QPieSlice::hoverLeave()
247 248
248 249 This signal is emitted when user has hovered away from the slice.
249 250
250 251 \sa QPieSeries::hoverLeave()
251 252 */
252 253
253 254 /*!
254 255 \fn void QPieSlice::changed()
255 256
256 257 This signal emitted when something has changed in the slice.
257 258
258 259 \sa QPieSeries::changed()
259 260 */
260 261
261 262 /*!
262 263 Sets the \a value of this slice.
263 264 \sa value()
264 265 */
265 266 void QPieSlice::setValue(qreal value)
266 267 {
267 268 if (m_value != value) {
268 269 m_value = value;
269 emit changed();
270
271 QPieSeries *series = qobject_cast<QPieSeries*>(parent());
272 if (series)
273 series->updateDerivativeData(); // will emit changed()
274 else
275 emit changed();
270 276 }
271 277 }
272 278
273 279 /*!
274 280 Sets the \a label of the slice.
275 281 \sa label()
276 282 */
277 283 void QPieSlice::setLabel(QString label)
278 284 {
279 285 if (m_label != label) {
280 286 m_label = label;
281 287 emit changed();
282 288 }
283 289 }
284 290
285 291 /*!
286 292 Sets the label \a visible in this slice.
287 293 \sa isLabelVisible(), QPieSeries::setLabelsVisible()
288 294 */
289 295 void QPieSlice::setLabelVisible(bool visible)
290 296 {
291 297 if (m_isLabelVisible != visible) {
292 298 m_isLabelVisible = visible;
293 299 emit changed();
294 300 }
295 301 }
296 302
297 303 /*!
298 304 Sets this slice \a exploded.
299 305 \sa isExploded(), explodeDistanceFactor()
300 306 */
301 307 void QPieSlice::setExploded(bool exploded)
302 308 {
303 309 if (m_isExploded != exploded) {
304 310 m_isExploded = exploded;
305 311 emit changed();
306 312 }
307 313 }
308 314
309 315 /*!
310 316 Sets the explode distance \a factor.
311 317
312 318 The factor is relative to pie radius. For example:
313 319 1.0 means the distance is the same as the radius.
314 320 0.5 means the distance is half of the radius.
315 321
316 322 Default value is 0.15
317 323
318 324 \sa explodeDistanceFactor()
319 325 */
320 326 void QPieSlice::setExplodeDistanceFactor(qreal factor)
321 327 {
322 328 if (m_explodeDistanceFactor != factor) {
323 329 m_explodeDistanceFactor = factor;
324 330 emit changed();
325 331 }
326 332 }
327 333
328 334 /*!
329 335 Sets the \a pen used to draw this slice.
330 336 Note that applying a theme will override this.
331 337 \sa slicePen()
332 338 */
333 339 void QPieSlice::setSlicePen(const QPen &pen)
334 340 {
335 341 if (m_slicePen != pen) {
336 342 m_slicePen = pen;
337 343 emit changed();
338 344 }
339 345 }
340 346
341 347 /*!
342 348 Sets the \a brush used to draw this slice.
343 349 Note that applying a theme will override this.
344 350 \sa sliceBrush()
345 351 */
346 352 void QPieSlice::setSliceBrush(const QBrush &brush)
347 353 {
348 354 if (m_sliceBrush != brush) {
349 355 m_sliceBrush = brush;
350 356 emit changed();
351 357 }
352 358 }
353 359
354 360 /*!
355 361 Sets the \a pen used to draw the label arm in this slice.
356 362 Note that applying a theme will override this.
357 363 \sa labelArmPen()
358 364 */
359 365 void QPieSlice::setLabelArmPen(const QPen &pen)
360 366 {
361 367 if (m_labelArmPen != pen) {
362 368 m_labelArmPen = pen;
363 369 emit changed();
364 370 }
365 371 }
366 372
367 373 /*!
368 374 Sets the \a font used to draw the label in this slice.
369 375 Note that applying a theme will override this.
370 376 \sa labelFont()
371 377 */
372 378 void QPieSlice::setLabelFont(const QFont &font)
373 379 {
374 380 if (m_labelFont != font) {
375 381 m_labelFont = font;
376 382 emit changed();
377 383 }
378 384 }
379 385
380 386 /*!
381 387 Sets the label arm lenght \a factor.
382 388
383 389 The factor is relative to pie radius. For example:
384 390 1.0 means the length is the same as the radius.
385 391 0.5 means the length is half of the radius.
386 392
387 393 Default value is 0.15
388 394
389 395 \sa labelArmLengthFactor()
390 396 */
391 397 void QPieSlice::setLabelArmLengthFactor(qreal factor)
392 398 {
393 399 if (m_labelArmLengthFactor != factor) {
394 400 m_labelArmLengthFactor = factor;
395 401 emit changed();
396 402 }
397 403 }
398 404
399 405 #include "moc_qpieslice.cpp"
400 406
401 407 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,91 +1,88
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 class QPieSeries;
11 12
12 13 class QTCOMMERCIALCHART_EXPORT QPieSlice : public QObject
13 14 {
14 15 Q_OBJECT
15 16 Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY changed)
16 17 Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY changed)
17 18
18 19 public:
19 20 QPieSlice(QObject *parent = 0);
20 21 QPieSlice(qreal value, QString label, QObject *parent = 0);
21 22 virtual ~QPieSlice();
22 23
23 24 // data
24 25 void setValue(qreal value);
25 26 qreal value() const;
26 27 void setLabel(QString label);
27 28 QString label() const;
28 29 void setLabelVisible(bool visible);
29 30 bool isLabelVisible() const;
30 31 void setExploded(bool exploded);
31 32 bool isExploded() const;
32 void setExplodeDistanceFactor(qreal factor);
33 qreal explodeDistanceFactor() const;
34 33
35 34 // generated data
36 35 qreal percentage() const;
37 36 qreal startAngle() const;
38 37 qreal endAngle() const;
39 38
40 39 // customization
41 40 void setSlicePen(const QPen &pen);
42 41 QPen slicePen() const;
43 42 void setSliceBrush(const QBrush &brush);
44 43 QBrush sliceBrush() const;
45 44 void setLabelArmPen(const QPen &pen);
46 45 QPen labelArmPen() const;
47 46 void setLabelFont(const QFont &font);
48 47 QFont labelFont() const;
49 48 void setLabelArmLengthFactor(qreal factor);
50 49 qreal labelArmLengthFactor() const;
51
52 // TODO: label position in general
53 // setLabelFlags(inside|outside|labelArmOn|labelArmOff|???)
54 // setLabelOrientation(horizontal|vertical|same as slice center angle|???)
50 void setExplodeDistanceFactor(qreal factor);
51 qreal explodeDistanceFactor() const;
55 52
56 53 Q_SIGNALS:
57 54 void clicked();
58 55 void hoverEnter();
59 56 void hoverLeave();
60 57 void changed();
61 58
62 59 private:
63 60
64 61 // TODO: use private class
65 62 friend class QPieSeries;
66 63 friend class PieChartItem;
67 64 friend class PieSlice;
68 65
69 66 // data
70 67 qreal m_value;
71 68 QString m_label;
72 69 bool m_isLabelVisible;
73 70 bool m_isExploded;
74 71 qreal m_explodeDistanceFactor;
75 72
76 73 // generated data
77 74 qreal m_percentage;
78 75 qreal m_startAngle;
79 76 qreal m_angleSpan;
80 77
81 78 // customization
82 79 QPen m_slicePen;
83 80 QBrush m_sliceBrush;
84 81 QFont m_labelFont;
85 82 QPen m_labelArmPen;
86 83 qreal m_labelArmLengthFactor;
87 84 };
88 85
89 86 QTCOMMERCIALCHART_END_NAMESPACE
90 87
91 88 #endif // QPIESLICE_H
General Comments 0
You need to be logged in to leave comments. Login now