##// END OF EJS Templates
Donut support simplified. Examples updated
Marek Rosa -
r1838:886026b75e22
parent child
Show More
@@ -1,363 +1,359
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20 #include "mainwidget.h"
21 21 #include "customslice.h"
22 22 #include "pentool.h"
23 23 #include "brushtool.h"
24 24 #include <QPushButton>
25 25 #include <QComboBox>
26 26 #include <QCheckBox>
27 27 #include <QLineEdit>
28 28 #include <QGroupBox>
29 29 #include <QDoubleSpinBox>
30 30 #include <QFormLayout>
31 31 #include <QFontDialog>
32 32 #include <QChartView>
33 33 #include <QPieSeries>
34 34
35 35 QTCOMMERCIALCHART_USE_NAMESPACE
36 36
37 37 MainWidget::MainWidget(QWidget* parent)
38 38 :QWidget(parent),
39 m_slice(0)
39 m_slice(0)
40 40 {
41 41 // create chart
42 42 QChart *chart = new QChart;
43 43 chart->setTitle("Piechart customization");
44 44 chart->setAnimationOptions(QChart::AllAnimations);
45 45
46 46 // create series
47 47 m_series = new QPieSeries();
48 48 *m_series << new CustomSlice("Slice 1", 10.0);
49 49 *m_series << new CustomSlice("Slice 2", 20.0);
50 50 *m_series << new CustomSlice("Slice 3", 30.0);
51 51 *m_series << new CustomSlice("Slice 4", 40.0);
52 52 *m_series << new CustomSlice("Slice 5", 50.0);
53 53 m_series->setLabelsVisible();
54 54 chart->addSeries(m_series);
55 55
56 56 connect(m_series, SIGNAL(clicked(QPieSlice*)), this, SLOT(handleSliceClicked(QPieSlice*)));
57 57
58 58 // chart settings
59 59 m_themeComboBox = new QComboBox();
60 60 m_themeComboBox->addItem("Light", QChart::ChartThemeLight);
61 61 m_themeComboBox->addItem("BlueCerulean", QChart::ChartThemeBlueCerulean);
62 62 m_themeComboBox->addItem("Dark", QChart::ChartThemeDark);
63 63 m_themeComboBox->addItem("BrownSand", QChart::ChartThemeBrownSand);
64 64 m_themeComboBox->addItem("BlueNcs", QChart::ChartThemeBlueNcs);
65 65 m_themeComboBox->addItem("High Contrast", QChart::ChartThemeHighContrast);
66 66 m_themeComboBox->addItem("Blue Icy", QChart::ChartThemeBlueIcy);
67 67
68 68 m_aaCheckBox = new QCheckBox();
69 69 m_animationsCheckBox = new QCheckBox();
70 70 m_animationsCheckBox->setCheckState(Qt::Checked);
71 71
72 72 m_legendCheckBox = new QCheckBox();
73 73
74 74 QFormLayout* chartSettingsLayout = new QFormLayout();
75 75 chartSettingsLayout->addRow("Theme", m_themeComboBox);
76 76 chartSettingsLayout->addRow("Antialiasing", m_aaCheckBox);
77 77 chartSettingsLayout->addRow("Animations", m_animationsCheckBox);
78 78 chartSettingsLayout->addRow("Legend", m_legendCheckBox);
79 79 QGroupBox* chartSettings = new QGroupBox("Chart");
80 80 chartSettings->setLayout(chartSettingsLayout);
81 81
82 82 connect(m_themeComboBox, SIGNAL(currentIndexChanged(int)), this ,SLOT(updateChartSettings()));
83 83 connect(m_aaCheckBox, SIGNAL(toggled(bool)), this ,SLOT(updateChartSettings()));
84 84 connect(m_animationsCheckBox, SIGNAL(toggled(bool)), this ,SLOT(updateChartSettings()));
85 85 connect(m_legendCheckBox, SIGNAL(toggled(bool)), this ,SLOT(updateChartSettings()));
86 86
87 87 // series settings
88 88 m_hPosition = new QDoubleSpinBox();
89 89 m_hPosition->setMinimum(0.0);
90 90 m_hPosition->setMaximum(1.0);
91 91 m_hPosition->setSingleStep(0.1);
92 92 m_hPosition->setValue(m_series->horizontalPosition());
93 93
94 94 m_vPosition = new QDoubleSpinBox();
95 95 m_vPosition->setMinimum(0.0);
96 96 m_vPosition->setMaximum(1.0);
97 97 m_vPosition->setSingleStep(0.1);
98 98 m_vPosition->setValue(m_series->verticalPosition());
99 99
100 100 m_sizeFactor = new QDoubleSpinBox();
101 101 m_sizeFactor->setMinimum(0.0);
102 102 m_sizeFactor->setMaximum(1.0);
103 103 m_sizeFactor->setSingleStep(0.1);
104 104 m_sizeFactor->setValue(m_series->pieSize());
105 105
106 106 m_startAngle = new QDoubleSpinBox();
107 107 m_startAngle->setMinimum(-720);
108 108 m_startAngle->setMaximum(720);
109 109 m_startAngle->setValue(m_series->pieStartAngle());
110 110 m_startAngle->setSingleStep(1);
111 111
112 112 m_endAngle = new QDoubleSpinBox();
113 113 m_endAngle->setMinimum(-720);
114 114 m_endAngle->setMaximum(720);
115 115 m_endAngle->setValue(m_series->pieEndAngle());
116 116 m_endAngle->setSingleStep(1);
117 117
118 m_isDonut = new QCheckBox();
119
120 m_donutInnerSize = new QDoubleSpinBox();
121 m_donutInnerSize->setMinimum(0.0);
122 m_donutInnerSize->setMaximum(1.0);
123 m_donutInnerSize->setSingleStep(0.1);
124 m_donutInnerSize->setValue(m_series->donutInnerSize());
118 m_holeSize = new QDoubleSpinBox();
119 m_holeSize->setMinimum(0.0);
120 m_holeSize->setMaximum(1.0);
121 m_holeSize->setSingleStep(0.1);
122 m_holeSize->setValue(m_series->holeSize());
125 123
126 124 QPushButton *appendSlice = new QPushButton("Append slice");
127 125 QPushButton *insertSlice = new QPushButton("Insert slice");
128 126 QPushButton *removeSlice = new QPushButton("Remove selected slice");
129 127
130 128 QFormLayout* seriesSettingsLayout = new QFormLayout();
131 129 seriesSettingsLayout->addRow("Horizontal position", m_hPosition);
132 130 seriesSettingsLayout->addRow("Vertical position", m_vPosition);
133 131 seriesSettingsLayout->addRow("Size factor", m_sizeFactor);
134 132 seriesSettingsLayout->addRow("Start angle", m_startAngle);
135 133 seriesSettingsLayout->addRow("End angle", m_endAngle);
136 seriesSettingsLayout->addRow("Is donut", m_isDonut);
137 seriesSettingsLayout->addRow("Donut inner size", m_donutInnerSize);
134 seriesSettingsLayout->addRow("Hole size", m_holeSize);
138 135 seriesSettingsLayout->addRow(appendSlice);
139 136 seriesSettingsLayout->addRow(insertSlice);
140 137 seriesSettingsLayout->addRow(removeSlice);
141 138 QGroupBox* seriesSettings = new QGroupBox("Series");
142 139 seriesSettings->setLayout(seriesSettingsLayout);
143 140
144 141 connect(m_vPosition, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings()));
145 142 connect(m_hPosition, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings()));
146 143 connect(m_sizeFactor, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings()));
147 144 connect(m_startAngle, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings()));
148 145 connect(m_endAngle, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings()));
149 connect(m_isDonut, SIGNAL(toggled(bool)), this, SLOT(updateSerieSettings()));
150 connect(m_donutInnerSize, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings()));
146 connect(m_holeSize, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings()));
151 147 connect(appendSlice, SIGNAL(clicked()), this, SLOT(appendSlice()));
152 148 connect(insertSlice, SIGNAL(clicked()), this, SLOT(insertSlice()));
153 149 connect(removeSlice, SIGNAL(clicked()), this, SLOT(removeSlice()));
154 150
155 151 // slice settings
156 152 m_sliceName = new QLineEdit("<click a slice>");
157 153 m_sliceName->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
158 154 m_sliceValue = new QDoubleSpinBox();
159 155 m_sliceValue->setMaximum(1000);
160 156 m_sliceLabelVisible = new QCheckBox();
161 157 m_sliceLabelArmFactor = new QDoubleSpinBox();
162 158 m_sliceLabelArmFactor->setSingleStep(0.01);
163 159 m_sliceExploded = new QCheckBox();
164 160 m_sliceExplodedFactor = new QDoubleSpinBox();
165 161 m_sliceExplodedFactor->setSingleStep(0.01);
166 162 m_pen = new QPushButton();
167 163 m_penTool = new PenTool("Slice pen", this);
168 164 m_brush = new QPushButton();
169 165 m_brushTool = new BrushTool("Slice brush", this);
170 166 m_font = new QPushButton();
171 167 m_labelBrush = new QPushButton();
172 168 m_labelBrushTool = new BrushTool("Label brush", this);
173 169 m_labelPosition = new QComboBox(this);
174 170 m_labelPosition->addItem("Outside", QPieSlice::LabelOutside);
175 171 m_labelPosition->addItem("Inside horizontal", QPieSlice::LabelInsideHorizontal);
176 172 m_labelPosition->addItem("Inside tangential", QPieSlice::LabelInsideTangential);
177 173 m_labelPosition->addItem("Inside normal", QPieSlice::LabelInsideNormal);
178 174
179 175 QFormLayout* sliceSettingsLayout = new QFormLayout();
180 176 sliceSettingsLayout->addRow("Label", m_sliceName);
181 177 sliceSettingsLayout->addRow("Value", m_sliceValue);
182 178 sliceSettingsLayout->addRow("Pen", m_pen);
183 179 sliceSettingsLayout->addRow("Brush", m_brush);
184 180 sliceSettingsLayout->addRow("Label visible", m_sliceLabelVisible);
185 181 sliceSettingsLayout->addRow("Label font", m_font);
186 182 sliceSettingsLayout->addRow("Label brush", m_labelBrush);
187 183 sliceSettingsLayout->addRow("Label position", m_labelPosition);
188 184 sliceSettingsLayout->addRow("Label arm length", m_sliceLabelArmFactor);
189 185 sliceSettingsLayout->addRow("Exploded", m_sliceExploded);
190 186 sliceSettingsLayout->addRow("Explode distance", m_sliceExplodedFactor);
191 187 QGroupBox* sliceSettings = new QGroupBox("Selected slice");
192 188 sliceSettings->setLayout(sliceSettingsLayout);
193 189
194 190 connect(m_sliceName, SIGNAL(textChanged(QString)), this, SLOT(updateSliceSettings()));
195 191 connect(m_sliceValue, SIGNAL(valueChanged(double)), this, SLOT(updateSliceSettings()));
196 192 connect(m_pen, SIGNAL(clicked()), m_penTool, SLOT(show()));
197 193 connect(m_penTool, SIGNAL(changed()), this, SLOT(updateSliceSettings()));
198 194 connect(m_brush, SIGNAL(clicked()), m_brushTool, SLOT(show()));
199 195 connect(m_brushTool, SIGNAL(changed()), this, SLOT(updateSliceSettings()));
200 196 connect(m_font, SIGNAL(clicked()), this, SLOT(showFontDialog()));
201 197 connect(m_labelBrush, SIGNAL(clicked()), m_labelBrushTool, SLOT(show()));
202 198 connect(m_labelBrushTool, SIGNAL(changed()), this, SLOT(updateSliceSettings()));
203 199 connect(m_sliceLabelVisible, SIGNAL(toggled(bool)), this, SLOT(updateSliceSettings()));
204 200 connect(m_sliceLabelVisible, SIGNAL(toggled(bool)), this, SLOT(updateSliceSettings()));
205 201 connect(m_sliceLabelArmFactor, SIGNAL(valueChanged(double)), this, SLOT(updateSliceSettings()));
206 202 connect(m_sliceExploded, SIGNAL(toggled(bool)), this, SLOT(updateSliceSettings()));
207 203 connect(m_sliceExplodedFactor, SIGNAL(valueChanged(double)), this, SLOT(updateSliceSettings()));
208 204 connect(m_labelPosition, SIGNAL(currentIndexChanged(int)), this, SLOT(updateSliceSettings()));
209 205
210 206 // create chart view
211 207 m_chartView = new QChartView(chart);
212 208
213 209 // create main layout
214 210 QVBoxLayout *settingsLayout = new QVBoxLayout();
215 211 settingsLayout->addWidget(chartSettings);
216 212 settingsLayout->addWidget(seriesSettings);
217 213 settingsLayout->addWidget(sliceSettings);
218 214 settingsLayout->addStretch();
219 215
220 216 QGridLayout* baseLayout = new QGridLayout();
221 217 baseLayout->addLayout(settingsLayout, 0, 0);
222 218 baseLayout->addWidget(m_chartView, 0, 1);
223 219 setLayout(baseLayout);
224 220
225 221 updateSerieSettings();
226 222 updateChartSettings();
227 223 }
228 224
229 225
230 226 void MainWidget::updateChartSettings()
231 227 {
232 228 QChart::ChartTheme theme = (QChart::ChartTheme) m_themeComboBox->itemData(m_themeComboBox->currentIndex()).toInt();
233 229 m_chartView->chart()->setTheme(theme);
234 230 m_chartView->setRenderHint(QPainter::Antialiasing, m_aaCheckBox->isChecked());
235 231
236 232 if (m_animationsCheckBox->checkState() == Qt::Checked)
237 233 m_chartView->chart()->setAnimationOptions(QChart::AllAnimations);
238 234 else
239 235 m_chartView->chart()->setAnimationOptions(QChart::NoAnimation);
240 236
241 237 if (m_legendCheckBox->checkState() == Qt::Checked)
242 238 m_chartView->chart()->legend()->show();
243 239 else
244 240 m_chartView->chart()->legend()->hide();
245 241 }
246 242
247 243 void MainWidget::updateSerieSettings()
248 244 {
249 245 m_series->setHorizontalPosition(m_hPosition->value());
250 246 m_series->setVerticalPosition(m_vPosition->value());
251 247 m_series->setPieSize(m_sizeFactor->value());
248 m_holeSize->setMaximum(m_sizeFactor->value());
252 249 m_series->setPieStartAngle(m_startAngle->value());
253 250 m_series->setPieEndAngle(m_endAngle->value());
254 m_series->setDonut(m_isDonut->isChecked());
255 m_series->setDonutInnerSize(m_donutInnerSize->value());
251 m_series->setHoleSize(m_holeSize->value());
256 252 }
257 253
258 254 void MainWidget::updateSliceSettings()
259 255 {
260 256 if (!m_slice)
261 257 return;
262 258
263 259 m_slice->setLabel(m_sliceName->text());
264 260
265 261 m_slice->setValue(m_sliceValue->value());
266 262
267 263 m_slice->setPen(m_penTool->pen());
268 264 m_slice->setBrush(m_brushTool->brush());
269 265
270 266 m_slice->setLabelBrush(m_labelBrushTool->brush());
271 267 m_slice->setLabelVisible(m_sliceLabelVisible->isChecked());
272 268 m_slice->setLabelArmLengthFactor(m_sliceLabelArmFactor->value());
273 269 m_slice->setLabelPosition((QPieSlice::LabelPosition)m_labelPosition->currentIndex()); // assumes that index is in sync with the enum
274 270
275 271 m_slice->setExploded(m_sliceExploded->isChecked());
276 272 m_slice->setExplodeDistanceFactor(m_sliceExplodedFactor->value());
277 273 }
278 274
279 275 void MainWidget::handleSliceClicked(QPieSlice* slice)
280 276 {
281 277 m_slice = static_cast<CustomSlice*>(slice);
282 278
283 279 // name
284 280 m_sliceName->blockSignals(true);
285 281 m_sliceName->setText(slice->label());
286 282 m_sliceName->blockSignals(false);
287 283
288 284 // value
289 285 m_sliceValue->blockSignals(true);
290 286 m_sliceValue->setValue(slice->value());
291 287 m_sliceValue->blockSignals(false);
292 288
293 289 // pen
294 290 m_pen->setText(PenTool::name(m_slice->pen()));
295 291 m_penTool->setPen(m_slice->pen());
296 292
297 293 // brush
298 294 m_brush->setText(m_slice->originalBrush().color().name());
299 295 m_brushTool->setBrush(m_slice->originalBrush());
300 296
301 297 // label
302 298 m_labelBrush->setText(BrushTool::name(m_slice->labelBrush()));
303 299 m_labelBrushTool->setBrush(m_slice->labelBrush());
304 300 m_font->setText(slice->labelFont().toString());
305 301 m_sliceLabelVisible->blockSignals(true);
306 302 m_sliceLabelVisible->setChecked(slice->isLabelVisible());
307 303 m_sliceLabelVisible->blockSignals(false);
308 304 m_sliceLabelArmFactor->blockSignals(true);
309 305 m_sliceLabelArmFactor->setValue(slice->labelArmLengthFactor());
310 306 m_sliceLabelArmFactor->blockSignals(false);
311 307 m_labelPosition->blockSignals(true);
312 308 m_labelPosition->setCurrentIndex(slice->labelPosition()); // assumes that index is in sync with the enum
313 309 m_labelPosition->blockSignals(false);
314 310
315 311 // exploded
316 312 m_sliceExploded->blockSignals(true);
317 313 m_sliceExploded->setChecked(slice->isExploded());
318 314 m_sliceExploded->blockSignals(false);
319 315 m_sliceExplodedFactor->blockSignals(true);
320 316 m_sliceExplodedFactor->setValue(slice->explodeDistanceFactor());
321 317 m_sliceExplodedFactor->blockSignals(false);
322 318 }
323 319
324 320 void MainWidget::showFontDialog()
325 321 {
326 322 if (!m_slice)
327 323 return;
328 324
329 325 QFontDialog dialog(m_slice->labelFont());
330 326 dialog.show();
331 327 dialog.exec();
332 328
333 329 m_slice->setLabelFont(dialog.currentFont());
334 330 m_font->setText(dialog.currentFont().toString());
335 331 }
336 332
337 333 void MainWidget::appendSlice()
338 334 {
339 335 *m_series << new CustomSlice("Slice " + QString::number(m_series->count()+1), 10.0);
340 336 }
341 337
342 338 void MainWidget::insertSlice()
343 339 {
344 340 if (!m_slice)
345 341 return;
346 342
347 343 int i = m_series->slices().indexOf(m_slice);
348 344
349 345 m_series->insert(i, new CustomSlice("Slice " + QString::number(m_series->count()+1), 10.0));
350 346 }
351 347
352 348 void MainWidget::removeSlice()
353 349 {
354 350 if (!m_slice)
355 351 return;
356 352
357 353 m_sliceName->setText("<click a slice>");
358 354
359 355 m_series->remove(m_slice);
360 356 m_slice = 0;
361 357 }
362 358
363 359 #include "moc_mainwidget.cpp"
@@ -1,94 +1,93
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20 #ifndef MAINWIDGET_H
21 21 #define MAINWIDGET_H
22 22
23 23 #include <QWidget>
24 24 #include <QChartGlobal>
25 25
26 26 class QLineEdit;
27 27 class QPushButton;
28 28 class QCheckBox;
29 29 class QComboBox;
30 30 class QDoubleSpinBox;
31 31 class PenTool;
32 32 class BrushTool;
33 33 class CustomSlice;
34 34
35 35 QTCOMMERCIALCHART_BEGIN_NAMESPACE
36 36 class QChartView;
37 37 class QPieSeries;
38 38 class QPieSlice;
39 39 QTCOMMERCIALCHART_END_NAMESPACE
40 40
41 41 QTCOMMERCIALCHART_USE_NAMESPACE
42 42
43 43 class MainWidget : public QWidget
44 44 {
45 45 Q_OBJECT
46 46
47 47 public:
48 48 explicit MainWidget(QWidget* parent = 0);
49 49
50 50 public Q_SLOTS:
51 51 void updateChartSettings();
52 52 void updateSerieSettings();
53 53 void updateSliceSettings();
54 54 void handleSliceClicked(QPieSlice* slice);
55 55 void showFontDialog();
56 56 void appendSlice();
57 57 void insertSlice();
58 58 void removeSlice();
59 59
60 60 private:
61 61 QComboBox *m_themeComboBox;
62 62 QCheckBox *m_aaCheckBox;
63 63 QCheckBox *m_animationsCheckBox;
64 64 QCheckBox *m_legendCheckBox;
65 65
66 66 QChartView* m_chartView;
67 67 QPieSeries* m_series;
68 68 CustomSlice* m_slice;
69 69
70 70 QDoubleSpinBox* m_hPosition;
71 71 QDoubleSpinBox* m_vPosition;
72 72 QDoubleSpinBox* m_sizeFactor;
73 73 QDoubleSpinBox* m_startAngle;
74 74 QDoubleSpinBox* m_endAngle;
75 QCheckBox* m_isDonut;
76 QDoubleSpinBox* m_donutInnerSize;
75 QDoubleSpinBox* m_holeSize;
77 76
78 77 QLineEdit* m_sliceName;
79 78 QDoubleSpinBox* m_sliceValue;
80 79 QCheckBox* m_sliceLabelVisible;
81 80 QDoubleSpinBox* m_sliceLabelArmFactor;
82 81 QCheckBox* m_sliceExploded;
83 82 QDoubleSpinBox* m_sliceExplodedFactor;
84 83 QPushButton *m_brush;
85 84 BrushTool *m_brushTool;
86 85 QPushButton *m_pen;
87 86 PenTool *m_penTool;
88 87 QPushButton *m_font;
89 88 QPushButton *m_labelBrush;
90 89 QComboBox *m_labelPosition;
91 90 BrushTool *m_labelBrushTool;
92 91 };
93 92
94 93 #endif // MAINWIDGET_H
@@ -1,105 +1,108
1 1 #include "widget.h"
2 2 #include <QChartView>
3 #include <QChart>
4 #include <QLegend>
3 5 #include <QPieSeries>
4 6 #include <QPieSlice>
5 7 #include <QTime>
6 8 #include <QGridLayout>
7 9 #include <QTimer>
8 10
9 11 QTCOMMERCIALCHART_USE_NAMESPACE
10 12
11 13 Widget::Widget(QWidget *parent)
12 14 : QWidget(parent)
13 15 {
14 16 setMinimumSize(800, 600);
15 17 qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
16 18
17 19 //! [1]
18 20 QChartView *chartView = new QChartView;
19 21 chartView->setRenderHint(QPainter::Antialiasing);
20 chartView->chart()->setAnimationOptions(QChart::AllAnimations);
22 QChart *chart = chartView->chart();
23 chart->setAnimationOptions(QChart::AllAnimations);
24 chart->legend()->setVisible(false);
21 25 //! [1]
22 26
23 27 //! [2]
24 28 qreal minSize = 0.1;
25 29 qreal maxSize = 0.9;
26 int donutsCount = 5;
30 int donutCount = 5;
27 31 //! [2]
28 32
29 33 //! [3]
30 for (int i = 0; i < donutsCount; i++) {
34 for (int i = 0; i < donutCount; i++) {
31 35 QPieSeries *donut = new QPieSeries;
32 donut->setDonut();
33 36 int sliceCount = 3 + qrand() % 3;
34 37 for (int j = 0; j < sliceCount; j++) {
35 38 qreal value = 100 + qrand() % 100;
36 39 QPieSlice *slice = new QPieSlice(QString("%1").arg(value), value);
37 40 slice->setLabelVisible(true);
38 41 slice->setLabelColor(Qt::white);
39 42 slice->setLabelPosition(QPieSlice::LabelInsideTangential);
40 43 connect(slice, SIGNAL(hovered(bool)), this, SLOT(explodeSlice(bool)));
41 44 donut->append(slice);
42 donut->setDonutInnerSize(minSize + i * (maxSize - minSize) / donutsCount);
43 donut->setPieSize(minSize + (i + 1) * (maxSize - minSize) / donutsCount);
45 donut->setHoleSize(minSize + i * (maxSize - minSize) / donutCount);
46 donut->setPieSize(minSize + (i + 1) * (maxSize - minSize) / donutCount);
44 47 }
45 48 m_donuts.append(donut);
46 49 chartView->chart()->addSeries(donut);
47 50 }
48 51 //! [3]
49 52
50 53 // create main layout
51 54 //! [4]
52 55 QGridLayout* mainLayout = new QGridLayout;
53 56 mainLayout->addWidget(chartView, 1, 1);
54 57 setLayout(mainLayout);
55 58 //! [4]
56 59
57 60 //! [5]
58 61 updateTimer = new QTimer(this);
59 62 connect(updateTimer, SIGNAL(timeout()), this, SLOT(updateRotation()));
60 63 updateTimer->start(1250);
61 64 //! [5]
62 65 }
63 66
64 67 Widget::~Widget()
65 68 {
66 69
67 70 }
68 71
69 72 //! [6]
70 73 void Widget::updateRotation()
71 74 {
72 75 for (int i = 0; i < m_donuts.count(); i++) {
73 76 QPieSeries *donut = m_donuts.at(i);
74 77 qreal phaseShift = -50 + qrand() % 100;
75 78 donut->setPieStartAngle(donut->pieStartAngle() + phaseShift);
76 79 donut->setPieEndAngle(donut->pieEndAngle() + phaseShift);
77 80 }
78 81 }
79 82 //! [6]
80 83
81 84 //! [7]
82 85 void Widget::explodeSlice(bool exploded)
83 86 {
84 87 QPieSlice *slice = qobject_cast<QPieSlice *>(sender());
85 88 if (exploded) {
86 89 updateTimer->stop();
87 90 qreal sliceStartAngle = slice->startAngle();
88 91 qreal sliceEndAngle = slice->startAngle() + slice->angleSpan();
89 92
90 93 QPieSeries *donut = slice->series();
91 94 qreal seriesIndex = m_donuts.indexOf(donut);
92 95 for (int i = seriesIndex + 1; i < m_donuts.count(); i++) {
93 96 m_donuts.at(i)->setPieStartAngle(sliceEndAngle);
94 97 m_donuts.at(i)->setPieEndAngle(360 + sliceStartAngle);
95 98 }
96 99 } else {
97 100 for (int i = 0; i < m_donuts.count(); i++) {
98 101 m_donuts.at(i)->setPieStartAngle(0);
99 102 m_donuts.at(i)->setPieEndAngle(360);
100 103 }
101 104 updateTimer->start();
102 105 }
103 106 slice->setExploded(exploded);
104 107 }
105 108 //! [7]
@@ -1,136 +1,138
1 1 #include "widget.h"
2 2 #include <QGridLayout>
3
4 3 #include <QPieSlice>
5 4 #include <QTime>
6 5 #include <QChartView>
6 #include <QChart>
7 #include <QLegend>
7 8 #include <QTimer>
8 9
9 10 QTCOMMERCIALCHART_USE_NAMESPACE
10 11
11 12 Widget::Widget(QWidget *parent)
12 13 : QWidget(parent),
13 14 mainData(0)
14 15 {
15 16 setMinimumSize(800, 600);
16 17 qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
17 18
18 19 //! [1]
19 20 QChartView *chartView = new QChartView;
20 21 chartView->setRenderHint(QPainter::Antialiasing);
21 chartView->chart()->setAnimationOptions(QChart::AllAnimations);
22 QChart *chart = chartView->chart();
23 chart->setAnimationOptions(QChart::AllAnimations);
24 chart->legend()->setVisible(false);
22 25 //! [1]
23 26
24 27 //! [2]
25 28 mainData = new QPieSeries;
26 29 mainData->setPieSize(0.6);
27 30 //! [2]
28 31
29 32 //! [3]
30 33 for (int j = 0; j < 4; j++) {
31 34 // create new slice for the mainData
32 35 QPieSlice *slice = new QPieSlice;
33 36 slice->setLabelColor(Qt::white);
34 37 mainData->append(slice);
35 38
36 39 // create a new detailed data for the slice
37 40 QPieSeries *donut = new QPieSeries;
38 donut->setDonut();
39 donut->setDonutInnerSize(mainData->pieSize());
41 donut->setHoleSize(mainData->pieSize());
40 42 donut->setPieSize(mainData->pieSize() + 0.15);
41 43
42 44 // when mainData slice is redrawn make sure the detailed data slices are aligned with it
43 45 connect(slice, SIGNAL(startAngleChanged()), this, SLOT(updatedStartAngle()));
44 46 connect(slice, SIGNAL(angleSpanChanged()), this, SLOT(updatedAngleSpan()));
45 47
46 48 // create the detailed data
47 49 for (int j = 0; j < 3; j++) {
48 50 qreal value = 10 + qrand() % 100;
49 51 QPieSlice *slice = new QPieSlice(QString("%1").arg(value), value);
50 52 donut->append(slice);
51 53 }
52 54 donut->setLabelsPosition(QPieSlice::LabelOutside);
53 55 donut->setLabelsVisible();
54 56 detailedData.append(donut);
55 57
56 58 // update the value and label of mainData
57 59 slice->setValue(donut->sum());
58 60 slice->setLabel(QString("%1").arg(donut->sum()));
59 61 }
60 62 //! [3]
61 63
62 64 //! [4]
63 65 mainData->setLabelsVisible();
64 66 mainData->setLabelsPosition(QPieSlice::LabelInsideHorizontal);
65 67 chartView->chart()->addSeries(mainData);
66 68 for (int i = 0; i < detailedData.count(); i++)
67 69 chartView->chart()->addSeries(detailedData.at(i));
68 70 //! [4]
69 71
70 72 //! [5]
71 73 // create main layout
72 74 QGridLayout* mainLayout = new QGridLayout;
73 75 mainLayout->addWidget(chartView, 1, 1);
74 76 setLayout(mainLayout);
75 77 //! [5]
76 78
77 79 //! [6]
78 80 // modify the value of one detailed slice every 2.5 sec
79 81 QTimer *updateTimer = new QTimer(this);
80 82 connect(updateTimer, SIGNAL(timeout()), this, SLOT(highlight()));
81 83 updateTimer->start(2500);
82 84 //! [6]
83 85 }
84 86
85 87 Widget::~Widget()
86 88 {
87 89
88 90 }
89 91
90 92 //! [7]
91 93 void Widget::updatedStartAngle()
92 94 {
93 95 // when the mainData slice has been updated the detailed data QPieSeries object as well
94 96 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
95 97 QPieSeries *detailsDonut = detailedData.at(slice->series()->slices().indexOf(slice));
96 98 detailsDonut->setPieStartAngle(slice->startAngle());
97 99 }
98 100
99 101 void Widget::updatedAngleSpan()
100 102 {
101 103 // when the mainData slice has been updated the detailed data QPieSeries object as well
102 104 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
103 105 QPieSeries *detailsDonut = detailedData.at(slice->series()->slices().indexOf(slice));
104 106 detailsDonut->setPieEndAngle(slice->startAngle() + slice->angleSpan());
105 107 }
106 108 //! [7]
107 109
108 110 //! [8]
109 111 void Widget::highlight()
110 112 {
111 113 // choose one random detailed data slice to be updated.
112 114 detailIndex = qrand() % mainData->count();
113 115 sliceIndex = qrand() % detailedData.at(detailIndex)->count();
114 116
115 117 // set the slice to exploded to make the change easier to observe
116 118 detailedData.at(detailIndex)->slices().at(sliceIndex)->setExploded();
117 119
118 120 // give the user time to focus on the slice that will be changed
119 121 QTimer::singleShot(1000, this, SLOT(updateRotation()));
120 122 }
121 123
122 124 void Widget::updateRotation()
123 125 {
124 126 // update the selected slice
125 127 qreal newValue = 10 + qrand() % 100;
126 128 detailedData.at(detailIndex)->slices().at(sliceIndex)->setValue(newValue);
127 129 detailedData.at(detailIndex)->slices().at(sliceIndex)->setLabel(QString("%1").arg(newValue));
128 130
129 131 // update the mainData slice with a new sum of the detailed data values
130 132 mainData->slices().at(detailIndex)->setValue(detailedData.at(detailIndex)->sum());
131 133 mainData->slices().at(detailIndex)->setLabel(QString("%1").arg(detailedData.at(detailIndex)->sum()));
132 134
133 135 // change the explode state of the selected slice back to normal
134 136 detailedData.at(detailIndex)->slices().at(sliceIndex)->setExploded(false);
135 137 }
136 138 //! [8]
@@ -1,107 +1,107
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "pieanimation_p.h"
22 22 #include "piesliceanimation_p.h"
23 23 #include "piechartitem_p.h"
24 24 #include <QTimer>
25 25
26 26 QTCOMMERCIALCHART_BEGIN_NAMESPACE
27 27
28 28 PieAnimation::PieAnimation(PieChartItem *item)
29 29 :ChartAnimation(item),
30 30 m_item(item)
31 31 {
32 32 }
33 33
34 34 PieAnimation::~PieAnimation()
35 35 {
36 36 }
37 37
38 38 ChartAnimation* PieAnimation::updateValue(PieSliceItem *sliceItem, const PieSliceData &sliceData)
39 39 {
40 40 PieSliceAnimation *animation = m_animations.value(sliceItem);
41 41 Q_ASSERT(animation);
42 42 animation->stop();
43 43
44 44 animation->updateValue(sliceData);
45 45 animation->setDuration(ChartAnimationDuration);
46 46 animation->setEasingCurve(QEasingCurve::OutQuart);
47 47
48 48 return animation;
49 49 }
50 50
51 51 ChartAnimation* PieAnimation::addSlice(PieSliceItem *sliceItem, const PieSliceData &sliceData, bool startupAnimation)
52 52 {
53 53 PieSliceAnimation *animation = new PieSliceAnimation(sliceItem);
54 54 m_animations.insert(sliceItem, animation);
55 55
56 56 PieSliceData startValue = sliceData;
57 57 startValue.m_radius = 0;
58 58 if (startupAnimation)
59 59 startValue.m_startAngle = 0;
60 60 else
61 61 startValue.m_startAngle = sliceData.m_startAngle + (sliceData.m_angleSpan / 2);
62 62 startValue.m_angleSpan = 0;
63 63
64 if (sliceData.m_donut)
65 startValue.m_radius = sliceData.m_innerRadius;
64 if (sliceData.m_holeRadius > 0)
65 startValue.m_radius = sliceData.m_holeRadius;
66 66
67 67 animation->setValue(startValue, sliceData);
68 68 animation->setDuration(ChartAnimationDuration);
69 69 animation->setEasingCurve(QEasingCurve::OutQuart);
70 70
71 71 return animation;
72 72 }
73 73
74 74 ChartAnimation* PieAnimation::removeSlice(PieSliceItem *sliceItem)
75 75 {
76 76 PieSliceAnimation *animation = m_animations.value(sliceItem);
77 77 Q_ASSERT(animation);
78 78 animation->stop();
79 79
80 80 PieSliceData endValue = animation->currentSliceValue();
81 if (endValue.m_donut)
82 endValue.m_radius = endValue.m_innerRadius;
81 if (endValue.m_holeRadius > 0)
82 endValue.m_radius = endValue.m_holeRadius;
83 83 else
84 84 endValue.m_radius = 0;
85 85 endValue.m_startAngle = endValue.m_startAngle + endValue.m_angleSpan;
86 86 endValue.m_angleSpan = 0;
87 87 endValue.m_isLabelVisible = false;
88 88
89 89 animation->updateValue(endValue);
90 90 animation->setDuration(ChartAnimationDuration);
91 91 animation->setEasingCurve(QEasingCurve::OutQuart);
92 92
93 93 // PieSliceItem is the parent of PieSliceAnimation so the animation will be deleted as well..
94 94 connect(animation, SIGNAL(finished()), sliceItem, SLOT(deleteLater()));
95 95 m_animations.remove(sliceItem);
96 96
97 97 return animation;
98 98 }
99 99
100 100 void PieAnimation::updateCurrentValue(const QVariant &)
101 101 {
102 102 // nothing to do...
103 103 }
104 104
105 105 #include "moc_pieanimation_p.cpp"
106 106
107 107 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,126 +1,126
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "piesliceanimation_p.h"
22 22 #include "piechartitem_p.h"
23 23
24 24 Q_DECLARE_METATYPE(QTCOMMERCIALCHART_NAMESPACE::PieSliceData)
25 25
26 26 QTCOMMERCIALCHART_BEGIN_NAMESPACE
27 27
28 28 qreal linearPos(qreal start, qreal end, qreal pos)
29 29 {
30 30 return start + ((end - start) * pos);
31 31 }
32 32
33 33 QPointF linearPos(QPointF start, QPointF end, qreal pos)
34 34 {
35 35 qreal x = linearPos(start.x(), end.x(), pos);
36 36 qreal y = linearPos(start.y(), end.y(), pos);
37 37 return QPointF(x, y);
38 38 }
39 39
40 40 QPen linearPos(QPen start, QPen end, qreal pos)
41 41 {
42 42 QColor c;
43 43 c.setRedF(linearPos(start.color().redF(), end.color().redF(), pos));
44 44 c.setGreenF(linearPos(start.color().greenF(), end.color().greenF(), pos));
45 45 c.setBlueF(linearPos(start.color().blueF(), end.color().blueF(), pos));
46 46 end.setColor(c);
47 47 return end;
48 48 }
49 49
50 50 QBrush linearPos(QBrush start, QBrush end, qreal pos)
51 51 {
52 52 QColor c;
53 53 c.setRedF(linearPos(start.color().redF(), end.color().redF(), pos));
54 54 c.setGreenF(linearPos(start.color().greenF(), end.color().greenF(), pos));
55 55 c.setBlueF(linearPos(start.color().blueF(), end.color().blueF(), pos));
56 56 end.setColor(c);
57 57 return end;
58 58 }
59 59
60 60 PieSliceAnimation::PieSliceAnimation(PieSliceItem *sliceItem)
61 61 :ChartAnimation(sliceItem),
62 62 m_sliceItem(sliceItem)
63 63 {
64 64 }
65 65
66 66 PieSliceAnimation::~PieSliceAnimation()
67 67 {
68 68 }
69 69
70 70 void PieSliceAnimation::setValue(const PieSliceData &startValue, const PieSliceData &endValue)
71 71 {
72 72 if (state() != QAbstractAnimation::Stopped)
73 73 stop();
74 74
75 75 m_currentValue = startValue;
76 76
77 77 setKeyValueAt(0.0, qVariantFromValue(startValue));
78 78 setKeyValueAt(1.0, qVariantFromValue(endValue));
79 79 }
80 80
81 81 void PieSliceAnimation::updateValue(const PieSliceData &endValue)
82 82 {
83 83 if (state() != QAbstractAnimation::Stopped)
84 84 stop();
85 85
86 86 setKeyValueAt(0.0, qVariantFromValue(m_currentValue));
87 87 setKeyValueAt(1.0, qVariantFromValue(endValue));
88 88 }
89 89
90 90 PieSliceData PieSliceAnimation::currentSliceValue()
91 91 {
92 92 // NOTE:
93 93 // We must use an internal current value because QVariantAnimation::currentValue() is updated
94 94 // before the animation is actually started. So if we get 2 updateValue() calls in a row the currentValue()
95 95 // will have the end value set from the first call and the second call will interpolate that instead of
96 96 // the original current value as it was before the first call.
97 97 return m_currentValue;
98 98 }
99 99
100 100 QVariant PieSliceAnimation::interpolated(const QVariant &start, const QVariant &end, qreal progress) const
101 101 {
102 102 PieSliceData startValue = qVariantValue<PieSliceData>(start);
103 103 PieSliceData endValue = qVariantValue<PieSliceData>(end);
104 104
105 105 PieSliceData result;
106 106 result = endValue;
107 107 result.m_center = linearPos(startValue.m_center, endValue.m_center, progress);
108 108 result.m_radius = linearPos(startValue.m_radius, endValue.m_radius, progress);
109 109 result.m_startAngle = linearPos(startValue.m_startAngle, endValue.m_startAngle, progress);
110 110 result.m_angleSpan = linearPos(startValue.m_angleSpan, endValue.m_angleSpan, progress);
111 111 result.m_slicePen = linearPos(startValue.m_slicePen, endValue.m_slicePen, progress);
112 112 result.m_sliceBrush = linearPos(startValue.m_sliceBrush, endValue.m_sliceBrush, progress);
113 result.m_innerRadius = linearPos(startValue.m_innerRadius, endValue.m_innerRadius, progress);
113 result.m_holeRadius = linearPos(startValue.m_holeRadius, endValue.m_holeRadius, progress);
114 114
115 115 return qVariantFromValue(result);
116 116 }
117 117
118 118 void PieSliceAnimation::updateCurrentValue(const QVariant &value)
119 119 {
120 120 if (state() != QAbstractAnimation::Stopped) { //workaround
121 121 m_currentValue = qVariantValue<PieSliceData>(value);
122 122 m_sliceItem->setLayout(m_currentValue);
123 123 }
124 124 }
125 125
126 126 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,243 +1,242
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "piechartitem_p.h"
22 22 #include "piesliceitem_p.h"
23 23 #include "qpieslice.h"
24 24 #include "qpieslice_p.h"
25 25 #include "qpieseries.h"
26 26 #include "qpieseries_p.h"
27 27 #include "chartpresenter_p.h"
28 28 #include "chartdataset_p.h"
29 29 #include "pieanimation_p.h"
30 30 #include <QPainter>
31 31 #include <QTimer>
32 32
33 33 QTCOMMERCIALCHART_BEGIN_NAMESPACE
34 34
35 35 PieChartItem::PieChartItem(QPieSeries *series, ChartPresenter* presenter)
36 36 :ChartItem(presenter),
37 37 m_series(series),
38 38 m_animation(0)
39 39 {
40 40 Q_ASSERT(series);
41 41
42 42 QPieSeriesPrivate *p = QPieSeriesPrivate::fromSeries(series);
43 43 connect(series, SIGNAL(visibleChanged()), this, SLOT(handleSeriesVisibleChanged()));
44 44 connect(series, SIGNAL(added(QList<QPieSlice*>)), this, SLOT(handleSlicesAdded(QList<QPieSlice*>)));
45 45 connect(series, SIGNAL(removed(QList<QPieSlice*>)), this, SLOT(handleSlicesRemoved(QList<QPieSlice*>)));
46 46 connect(p, SIGNAL(horizontalPositionChanged()), this, SLOT(updateLayout()));
47 47 connect(p, SIGNAL(verticalPositionChanged()), this, SLOT(updateLayout()));
48 48 connect(p, SIGNAL(pieSizeChanged()), this, SLOT(updateLayout()));
49 49 connect(p, SIGNAL(calculatedDataChanged()), this, SLOT(updateLayout()));
50 50
51 51 // Note: the following does not affect as long as the item does not have anything to paint
52 52 setZValue(ChartPresenter::PieSeriesZValue);
53 53
54 54 // Note: will not create slice items until we have a proper rectangle to draw on.
55 55 }
56 56
57 57 PieChartItem::~PieChartItem()
58 58 {
59 59 // slices deleted automatically through QGraphicsItem
60 60 }
61 61
62 62 void PieChartItem::setAnimation(PieAnimation* animation)
63 63 {
64 64 m_animation=animation;
65 65 }
66 66
67 67 ChartAnimation* PieChartItem::animation() const
68 68 {
69 69 return m_animation;
70 70 }
71 71
72 72 void PieChartItem::handleGeometryChanged(const QRectF& rect)
73 73 {
74 74 prepareGeometryChange();
75 75 m_rect = rect;
76 76 updateLayout();
77 77
78 78 // This is for delayed initialization of the slice items during startup.
79 79 // It ensures that startup animation originates from the correct position.
80 80 if (m_sliceItems.isEmpty())
81 81 handleSlicesAdded(m_series->slices());
82 82 }
83 83
84 84 void PieChartItem::handleDomainChanged(qreal minX, qreal maxX, qreal minY, qreal maxY)
85 85 {
86 86 Q_UNUSED(minX);
87 87 Q_UNUSED(maxX);
88 88 Q_UNUSED(minY);
89 89 Q_UNUSED(maxY);
90 90 // does not apply to pie
91 91 }
92 92
93 93 void PieChartItem::handleDomainUpdated()
94 94 {
95 95 // does not apply to pie
96 96 }
97 97
98 98 void PieChartItem::rangeXChanged(qreal min, qreal max, int tickXCount)
99 99 {
100 100 Q_UNUSED(min);
101 101 Q_UNUSED(max);
102 102 Q_UNUSED(tickXCount);
103 103 // does not apply to pie
104 104 }
105 105
106 106 void PieChartItem::rangeYChanged(qreal min, qreal max, int tickYCount)
107 107 {
108 108 Q_UNUSED(min);
109 109 Q_UNUSED(max);
110 110 Q_UNUSED(tickYCount);
111 111 // does not apply to pie
112 112 }
113 113
114 114 void PieChartItem::updateLayout()
115 115 {
116 116 // find pie center coordinates
117 117 m_pieCenter.setX(m_rect.left() + (m_rect.width() * m_series->horizontalPosition()));
118 118 m_pieCenter.setY(m_rect.top() + (m_rect.height() * m_series->verticalPosition()));
119 119
120 120 // find maximum radius for pie
121 121 m_pieRadius = m_rect.height() / 2;
122 122 if (m_rect.width() < m_rect.height())
123 123 m_pieRadius = m_rect.width() / 2;
124 124
125 m_donutInnerRadius = m_pieRadius;
125 m_holeSize = m_pieRadius;
126 126 // apply size factor
127 127 m_pieRadius *= m_series->pieSize();
128 m_donutInnerRadius *= m_series->donutInnerSize();
128 m_holeSize *= m_series->holeSize();
129 129
130 130 // set layouts for existing slice items
131 131 foreach (QPieSlice* slice, m_series->slices()) {
132 132 PieSliceItem *sliceItem = m_sliceItems.value(slice);
133 133 if (sliceItem) {
134 134 PieSliceData sliceData = updateSliceGeometry(slice);
135 135 if (m_animation){
136 136 presenter()->startAnimation(m_animation->updateValue(sliceItem, sliceData));
137 137 }
138 138 else
139 139 sliceItem->setLayout(sliceData);
140 140 }
141 141 }
142 142
143 143 update();
144 144 }
145 145
146 146 void PieChartItem::handleSlicesAdded(QList<QPieSlice*> slices)
147 147 {
148 148 // delay creating slice items until there is a proper rectangle
149 149 if (!m_rect.isValid() && m_sliceItems.isEmpty())
150 150 return;
151 151
152 152 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series));
153 153
154 154 bool startupAnimation = m_sliceItems.isEmpty();
155 155
156 156 foreach (QPieSlice *slice, slices) {
157 157 PieSliceItem* sliceItem = new PieSliceItem(this);
158 158 m_sliceItems.insert(slice, sliceItem);
159 159
160 160 // Note: no need to connect to slice valueChanged() etc.
161 161 // This is handled through calculatedDataChanged signal.
162 162 connect(slice, SIGNAL(labelChanged()), this, SLOT(handleSliceChanged()));
163 163 connect(slice, SIGNAL(labelVisibleChanged()), this, SLOT(handleSliceChanged()));
164 164 connect(slice, SIGNAL(penChanged()), this, SLOT(handleSliceChanged()));
165 165 connect(slice, SIGNAL(brushChanged()), this, SLOT(handleSliceChanged()));
166 166 connect(slice, SIGNAL(labelBrushChanged()), this, SLOT(handleSliceChanged()));
167 167 connect(slice, SIGNAL(labelFontChanged()), this, SLOT(handleSliceChanged()));
168 168
169 169 QPieSlicePrivate *p = QPieSlicePrivate::fromSlice(slice);
170 170 connect(p, SIGNAL(labelPositionChanged()), this, SLOT(handleSliceChanged()));
171 171 connect(p, SIGNAL(explodedChanged()), this, SLOT(handleSliceChanged()));
172 172 connect(p, SIGNAL(labelArmLengthFactorChanged()), this, SLOT(handleSliceChanged()));
173 173 connect(p, SIGNAL(explodeDistanceFactorChanged()), this, SLOT(handleSliceChanged()));
174 174
175 175 connect(sliceItem, SIGNAL(clicked(Qt::MouseButtons)), slice, SIGNAL(clicked()));
176 176 connect(sliceItem, SIGNAL(hovered(bool)), slice, SIGNAL(hovered(bool)));
177 177
178 178 PieSliceData sliceData = updateSliceGeometry(slice);
179 179 if (m_animation)
180 180 presenter()->startAnimation(m_animation->addSlice(sliceItem, sliceData, startupAnimation));
181 181 else
182 182 sliceItem->setLayout(sliceData);
183 183 }
184 184 }
185 185
186 186 void PieChartItem::handleSlicesRemoved(QList<QPieSlice*> slices)
187 187 {
188 188 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series));
189 189
190 190 foreach (QPieSlice *slice, slices) {
191 191
192 192 PieSliceItem *sliceItem = m_sliceItems.value(slice);
193 193
194 194 // this can happen if you call append() & remove() in a row so that PieSliceItem is not even created
195 195 if (!sliceItem)
196 196 continue;
197 197
198 198 m_sliceItems.remove(slice);
199 199
200 200 if (m_animation)
201 201 presenter()->startAnimation(m_animation->removeSlice(sliceItem)); // animator deletes the PieSliceItem
202 202 else
203 203 delete sliceItem;
204 204 }
205 205 }
206 206
207 207 void PieChartItem::handleSliceChanged()
208 208 {
209 209 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
210 210 if (!slice) {
211 211 QPieSlicePrivate* slicep = qobject_cast<QPieSlicePrivate *>(sender());
212 212 slice = slicep->q_ptr;
213 213 }
214 214 Q_ASSERT(m_sliceItems.contains(slice));
215 215
216 216 PieSliceItem *sliceItem = m_sliceItems.value(slice);
217 217 PieSliceData sliceData = updateSliceGeometry(slice);
218 218 if (m_animation)
219 219 presenter()->startAnimation(m_animation->updateValue(sliceItem, sliceData));
220 220 else
221 221 sliceItem->setLayout(sliceData);
222 222
223 223 update();
224 224 }
225 225
226 226 void PieChartItem::handleSeriesVisibleChanged()
227 227 {
228 228 setVisible(m_series->isVisible());
229 229 }
230 230
231 231 PieSliceData PieChartItem::updateSliceGeometry(QPieSlice *slice)
232 232 {
233 233 PieSliceData &sliceData = QPieSlicePrivate::fromSlice(slice)->m_data;
234 234 sliceData.m_center = PieSliceItem::sliceCenter(m_pieCenter, m_pieRadius, slice);
235 235 sliceData.m_radius = m_pieRadius;
236 sliceData.m_donut = m_series->donut();
237 sliceData.m_innerRadius = m_donutInnerRadius;
236 sliceData.m_holeRadius = m_holeSize;
238 237 return sliceData;
239 238 }
240 239
241 240 #include "moc_piechartitem_p.cpp"
242 241
243 242 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,88 +1,88
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 // W A R N I N G
22 22 // -------------
23 23 //
24 24 // This file is not part of the QtCommercial Chart API. It exists purely as an
25 25 // implementation detail. This header file may change from version to
26 26 // version without notice, or even be removed.
27 27 //
28 28 // We mean it.
29 29
30 30 #ifndef PIECHARTITEM_H
31 31 #define PIECHARTITEM_H
32 32
33 33 #include "qpieseries.h"
34 34 #include "chartitem_p.h"
35 35 #include "piesliceitem_p.h"
36 36
37 37 class QGraphicsItem;
38 38 QTCOMMERCIALCHART_BEGIN_NAMESPACE
39 39 class QPieSlice;
40 40 class ChartPresenter;
41 41 class PieAnimation;
42 42
43 43 class PieChartItem : public ChartItem
44 44 {
45 45 Q_OBJECT
46 46
47 47 public:
48 48 explicit PieChartItem(QPieSeries *series, ChartPresenter *presenter);
49 49 ~PieChartItem();
50 50
51 51 // from QGraphicsItem
52 52 QRectF boundingRect() const { return m_rect; }
53 53 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) {}
54 54
55 55 public Q_SLOTS:
56 56 // from Chart
57 57 virtual void handleGeometryChanged(const QRectF &rect);
58 58 virtual void handleDomainChanged(qreal minX, qreal maxX, qreal minY, qreal maxY);
59 59 virtual void handleDomainUpdated();
60 60 virtual void rangeXChanged(qreal min, qreal max, int tickXCount);
61 61 virtual void rangeYChanged(qreal min, qreal max, int tickYCount);
62 62
63 63 void updateLayout();
64 64 void handleSlicesAdded(QList<QPieSlice*> slices);
65 65 void handleSlicesRemoved(QList<QPieSlice*> slices);
66 66 void handleSliceChanged();
67 67 void handleSeriesVisibleChanged();
68 68
69 69 void setAnimation(PieAnimation* animation);
70 70 ChartAnimation* animation() const;
71 71
72 72 private:
73 73 PieSliceData updateSliceGeometry(QPieSlice *slice);
74 74
75 75 private:
76 76 QHash<QPieSlice*, PieSliceItem*> m_sliceItems;
77 77 QPieSeries *m_series;
78 78 QRectF m_rect;
79 79 QPointF m_pieCenter;
80 80 qreal m_pieRadius;
81 qreal m_donutInnerRadius;
81 qreal m_holeSize;
82 82 PieAnimation* m_animation;
83 83
84 84 };
85 85
86 86 QTCOMMERCIALCHART_END_NAMESPACE
87 87
88 88 #endif // PIECHARTITEM_H
@@ -1,148 +1,146
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 // W A R N I N G
22 22 // -------------
23 23 //
24 24 // This file is not part of the QtCommercial Chart API. It exists purely as an
25 25 // implementation detail. This header file may change from version to
26 26 // version without notice, or even be removed.
27 27 //
28 28 // We mean it.
29 29
30 30 #ifndef PIESLICEDATA_P_H
31 31 #define PIESLICEDATA_P_H
32 32
33 33 #include "qchartglobal.h"
34 34 #include "qpieslice.h"
35 35 #include <QPen>
36 36 #include <QBrush>
37 37
38 38 QTCOMMERCIALCHART_BEGIN_NAMESPACE
39 39
40 40 template <class T>
41 41 class Themed : public T
42 42 {
43 43 public:
44 44 Themed():m_isThemed(true) {}
45 45
46 46 inline T &operator=(const T &other) { return T::operator =(other); }
47 47
48 48 inline bool operator!=(const T &other) const { return T::operator !=(other); }
49 49 inline bool operator!=(const Themed &other) const
50 50 {
51 51 if (T::operator !=(other))
52 52 return true;
53 53
54 54 if (m_isThemed != other.m_isThemed)
55 55 return true;
56 56
57 57 return false;
58 58 }
59 59
60 60 inline void setThemed(bool state) { m_isThemed = state; }
61 61 inline bool isThemed() const { return m_isThemed; }
62 62
63 63 private:
64 64 bool m_isThemed;
65 65 };
66 66
67 67 class PieSliceData
68 68 {
69 69 public:
70 70 PieSliceData()
71 71 {
72 72 m_value = 0;
73 73
74 74 m_isExploded = false;
75 75 m_explodeDistanceFactor = 0.15;
76 76
77 77 m_isLabelVisible = false;
78 78 m_labelPosition = QPieSlice::LabelOutside;
79 79 m_labelArmLengthFactor = 0.15;
80 80
81 81 m_percentage = 0;
82 82 m_radius = 0;
83 83 m_startAngle = 0;
84 84 m_angleSpan = 0;
85 85
86 m_donut = false;
87 m_innerRadius = 0;
86 m_holeRadius = 0;
88 87 }
89 88
90 89 bool operator!=(const PieSliceData &other) const
91 90 {
92 91 if (!qFuzzyIsNull(m_value - other.m_value))
93 92 return true;
94 93
95 94 if (m_slicePen != other.m_slicePen ||
96 95 m_sliceBrush != other.m_sliceBrush)
97 96 return true;
98 97
99 98 if (m_isExploded != other.m_isExploded ||
100 99 !qFuzzyIsNull(m_explodeDistanceFactor - other.m_explodeDistanceFactor))
101 100 return true;
102 101
103 102 if (m_isLabelVisible != other.m_isLabelVisible ||
104 103 m_labelText != other.m_labelText ||
105 104 m_labelFont != other.m_labelFont ||
106 105 m_labelPosition != other.m_labelPosition ||
107 106 !qFuzzyIsNull(m_labelArmLengthFactor - other.m_labelArmLengthFactor) ||
108 107 m_labelBrush != other.m_labelBrush)
109 108 return true;
110 109
111 110 if (!qFuzzyIsNull(m_percentage - other.m_percentage) ||
112 111 m_center != other.m_center ||
113 112 !qFuzzyIsNull(m_radius - other.m_radius) ||
114 113 !qFuzzyIsNull(m_startAngle - other.m_startAngle) ||
115 114 !qFuzzyIsNull(m_angleSpan - other.m_angleSpan))
116 115 return true;
117 116
118 117 return false;
119 118 }
120 119
121 120 qreal m_value;
122 121
123 122 Themed<QPen> m_slicePen;
124 123 Themed<QBrush> m_sliceBrush;
125 124
126 125 bool m_isExploded;
127 126 qreal m_explodeDistanceFactor;
128 127
129 128 bool m_isLabelVisible;
130 129 QString m_labelText;
131 130 Themed<QFont> m_labelFont;
132 131 QPieSlice::LabelPosition m_labelPosition;
133 132 qreal m_labelArmLengthFactor;
134 133 Themed<QBrush> m_labelBrush;
135 134
136 135 qreal m_percentage;
137 136 QPointF m_center;
138 137 qreal m_radius;
139 138 qreal m_startAngle;
140 139 qreal m_angleSpan;
141 140
142 bool m_donut;
143 qreal m_innerRadius;
141 qreal m_holeRadius;
144 142 };
145 143
146 144 QTCOMMERCIALCHART_END_NAMESPACE
147 145
148 146 #endif // PIESLICEDATA_P_H
@@ -1,275 +1,275
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "piesliceitem_p.h"
22 22 #include "piechartitem_p.h"
23 23 #include "qpieseries.h"
24 24 #include "qpieslice.h"
25 25 #include "chartpresenter_p.h"
26 26 #include <QPainter>
27 27 #include <qmath.h>
28 28 #include <QGraphicsSceneEvent>
29 29 #include <QTime>
30 30 #include <QDebug>
31 31
32 32 QTCOMMERCIALCHART_BEGIN_NAMESPACE
33 33
34 34 QPointF offset(qreal angle, qreal length)
35 35 {
36 36 qreal dx = qSin(angle*(M_PI/180)) * length;
37 37 qreal dy = qCos(angle*(M_PI/180)) * length;
38 38 return QPointF(dx, -dy);
39 39 }
40 40
41 41 PieSliceItem::PieSliceItem(QGraphicsItem* parent)
42 42 :QGraphicsObject(parent),
43 43 m_hovered(false)
44 44 {
45 45 setAcceptHoverEvents(true);
46 46 setAcceptedMouseButtons(Qt::MouseButtonMask);
47 47 setZValue(ChartPresenter::PieSeriesZValue);
48 48 }
49 49
50 50 PieSliceItem::~PieSliceItem()
51 51 {
52 52 // If user is hovering over the slice and it gets destroyed we do
53 53 // not get a hover leave event. So we must emit the signal here.
54 54 if (m_hovered)
55 55 emit hovered(false);
56 56 }
57 57
58 58 QRectF PieSliceItem::boundingRect() const
59 59 {
60 60 return m_boundingRect;
61 61 }
62 62
63 63 QPainterPath PieSliceItem::shape() const
64 64 {
65 65 // Don't include the label and label arm.
66 66 // This is used to detect a mouse clicks. We do not want clicks from label.
67 67 return m_slicePath;
68 68 }
69 69
70 70 void PieSliceItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
71 71 {
72 72 painter->save();
73 73 painter->setClipRect(parentItem()->boundingRect());
74 74 painter->setPen(m_data.m_slicePen);
75 75 painter->setBrush(m_data.m_sliceBrush);
76 76 painter->drawPath(m_slicePath);
77 77 painter->restore();
78 78
79 79 if (m_data.m_isLabelVisible) {
80 80 painter->save();
81 81
82 82 // Pen for label arm not defined in the QPieSeries api, let's use brush's color instead
83 83 // Also, the drawText actually uses the pen color for the text color (unlike QGraphicsSimpleTextItem)
84 84 painter->setPen(m_data.m_labelBrush.color());
85 85 painter->setBrush(m_data.m_labelBrush);
86 86 painter->setFont(m_data.m_labelFont);
87 87
88 88 switch (m_data.m_labelPosition)
89 89 {
90 90 case QPieSlice::LabelOutside:
91 91 painter->setClipRect(parentItem()->boundingRect());
92 92 painter->strokePath(m_labelArmPath, m_data.m_labelBrush.color());
93 93 painter->drawText(m_labelTextRect, Qt::AlignCenter, m_data.m_labelText);
94 94 break;
95 95 case QPieSlice::LabelInsideHorizontal:
96 96 painter->setClipPath(m_slicePath);
97 97 painter->drawText(m_labelTextRect, Qt::AlignCenter, m_data.m_labelText);
98 98 break;
99 99 case QPieSlice::LabelInsideTangential:
100 100 painter->setClipPath(m_slicePath);
101 101 painter->translate(m_labelTextRect.center());
102 102 painter->rotate(m_data.m_startAngle + m_data.m_angleSpan / 2);
103 103 painter->drawText(-m_labelTextRect.width() / 2, -m_labelTextRect.height() / 2, m_labelTextRect.width(), m_labelTextRect.height(), Qt::AlignCenter, m_data.m_labelText);
104 104 break;
105 105 case QPieSlice::LabelInsideNormal:
106 106 painter->setClipPath(m_slicePath);
107 107 painter->translate(m_labelTextRect.center());
108 108 if (m_data.m_startAngle + m_data.m_angleSpan / 2 < 180)
109 109 painter->rotate(m_data.m_startAngle + m_data.m_angleSpan / 2 - 90);
110 110 else
111 111 painter->rotate(m_data.m_startAngle + m_data.m_angleSpan / 2 + 90);
112 112 painter->drawText(-m_labelTextRect.width() / 2, -m_labelTextRect.height() / 2, m_labelTextRect.width(), m_labelTextRect.height(), Qt::AlignCenter, m_data.m_labelText);
113 113 break;
114 114 }
115 115
116 116 painter->restore();
117 117 }
118 118 }
119 119
120 120 void PieSliceItem::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
121 121 {
122 122 m_hovered = true;
123 123 emit hovered(true);
124 124 }
125 125
126 126 void PieSliceItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
127 127 {
128 128 m_hovered = false;
129 129 emit hovered(false);
130 130 }
131 131
132 132 void PieSliceItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
133 133 {
134 134 emit clicked(event->buttons());
135 135 QGraphicsItem::mousePressEvent(event);
136 136 }
137 137
138 138 void PieSliceItem::setLayout(const PieSliceData &sliceData)
139 139 {
140 140 m_data = sliceData;
141 141 updateGeometry();
142 142 update();
143 143 }
144 144
145 145 void PieSliceItem::updateGeometry()
146 146 {
147 147 if (m_data.m_radius <= 0)
148 148 return;
149 149
150 150 prepareGeometryChange();
151 151
152 152 // slice path
153 153 qreal centerAngle;
154 154 QPointF armStart;
155 155 m_slicePath = slicePath(m_data.m_center, m_data.m_radius, m_data.m_startAngle, m_data.m_angleSpan, &centerAngle, &armStart);
156 156
157 157 // text rect
158 158 QFontMetricsF fm(m_data.m_labelFont);
159 159 m_labelTextRect = QRectF(0, 0, fm.width(m_data.m_labelText), fm.height());
160 160
161 161 // label arm path
162 162 QPointF labelTextStart;
163 163 m_labelArmPath = labelArmPath(armStart, centerAngle, m_data.m_radius * m_data.m_labelArmLengthFactor, m_labelTextRect.width(), &labelTextStart);
164 164
165 165 // text position
166 166 switch (m_data.m_labelPosition)
167 167 {
168 168 case QPieSlice::LabelOutside:
169 169 m_labelTextRect.moveBottomLeft(labelTextStart);
170 170 break;
171 171 case QPieSlice::LabelInsideHorizontal:
172 172 case QPieSlice::LabelInsideTangential:
173 173 case QPieSlice::LabelInsideNormal:{
174 174 QPointF textCenter;
175 if (m_data.m_donut)
176 textCenter = m_data.m_center + offset(centerAngle, m_data.m_innerRadius + (m_data.m_radius - m_data.m_innerRadius) / 2);
175 if (m_data.m_holeRadius > 0)
176 textCenter = m_data.m_center + offset(centerAngle, m_data.m_holeRadius + (m_data.m_radius - m_data.m_holeRadius) / 2);
177 177 else
178 178 textCenter = m_data.m_center + offset(centerAngle, m_data.m_radius / 2);
179 179 m_labelTextRect.moveCenter(textCenter);
180 180 break;
181 181 }
182 182 }
183 183
184 184 // bounding rect
185 185 if (m_data.m_isLabelVisible)
186 186 m_boundingRect = m_slicePath.boundingRect().united(m_labelArmPath.boundingRect()).united(m_labelTextRect);
187 187 else
188 188 m_boundingRect = m_slicePath.boundingRect();
189 189 }
190 190
191 191 QPointF PieSliceItem::sliceCenter(QPointF point, qreal radius, QPieSlice *slice)
192 192 {
193 193 if (slice->isExploded()) {
194 194 qreal centerAngle = slice->startAngle() + (slice->angleSpan()/2);
195 195 qreal len = radius * slice->explodeDistanceFactor();
196 196 point += offset(centerAngle, len);
197 197 }
198 198 return point;
199 199 }
200 200
201 201 QPainterPath PieSliceItem::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal *centerAngle, QPointF* armStart)
202 202 {
203 203 // calculate center angle
204 204 *centerAngle = startAngle + (angleSpan/2);
205 205
206 206 // calculate slice rectangle
207 207 QRectF rect(center.x()-radius, center.y()-radius, radius*2, radius*2);
208 208
209 209 // slice path
210 210 QPainterPath path;
211 if (m_data.m_donut) {
212 QRectF insideRect(center.x() - m_data.m_innerRadius, center.y()-m_data.m_innerRadius, m_data.m_innerRadius*2, m_data.m_innerRadius*2);
211 if (m_data.m_holeRadius > 0) {
212 QRectF insideRect(center.x() - m_data.m_holeRadius, center.y()-m_data.m_holeRadius, m_data.m_holeRadius*2, m_data.m_holeRadius*2);
213 213 path.arcMoveTo(rect, -startAngle + 90);
214 214 path.arcTo(rect, -startAngle + 90, -angleSpan);
215 215 path.arcTo(insideRect, -startAngle + 90 - angleSpan, angleSpan);
216 216 path.closeSubpath();
217 217 } else {
218 218 path.moveTo(rect.center());
219 219 path.arcTo(rect, -startAngle + 90, -angleSpan);
220 220 path.closeSubpath();
221 221 }
222 222
223 223 // calculate label arm start point
224 224 *armStart = center;
225 225 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
226 226
227 227 return path;
228 228 }
229 229
230 230 QPainterPath PieSliceItem::labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF *textStart)
231 231 {
232 232 // Normalize the angle to 0-360 range
233 233 // NOTE: We are using int here on purpose. Depenging on platform and hardware
234 234 // qreal can be a double, float or something the user gives to the Qt configure
235 235 // (QT_COORD_TYPE). Compilers do not seem to support modulo for double or float
236 236 // but there are fmod() and fmodf() functions for that. So instead of some #ifdef
237 237 // that might break we just use int. Precision for this is just fine for our needs.
238 238 int normalized = angle * 10.0;
239 239 normalized = normalized % 3600;
240 240 if (normalized < 0)
241 241 normalized += 3600;
242 242 angle = (qreal) normalized / 10.0;
243 243
244 244 // prevent label arm pointing straight down because it will look bad
245 245 if (angle < 180 && angle > 170)
246 246 angle = 170;
247 247 if (angle > 180 && angle < 190)
248 248 angle = 190;
249 249
250 250 // line from slice to label
251 251 QPointF parm1 = start + offset(angle, length);
252 252
253 253 // line to underline the label
254 254 QPointF parm2 = parm1;
255 255 if (angle < 180) { // arm swings the other way on the left side
256 256 parm2 += QPointF(textWidth, 0);
257 257 *textStart = parm1;
258 258 }
259 259 else {
260 260 parm2 += QPointF(-textWidth,0);
261 261 *textStart = parm2;
262 262 }
263 263
264 264 QPainterPath path;
265 265 path.moveTo(start);
266 266 path.lineTo(parm1);
267 267 path.lineTo(parm2);
268 268
269 269 return path;
270 270 }
271 271
272 272 #include "moc_piesliceitem_p.cpp"
273 273
274 274 QTCOMMERCIALCHART_END_NAMESPACE
275 275
@@ -1,897 +1,872
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "qpieseries.h"
22 22 #include "qpieseries_p.h"
23 23 #include "qpieslice.h"
24 24 #include "qpieslice_p.h"
25 25 #include "pieslicedata_p.h"
26 26 #include "chartdataset_p.h"
27 27 #include "charttheme_p.h"
28 28 #include "legendmarker_p.h"
29 29 #include "qabstractaxis.h"
30 30 #include "pieanimation_p.h"
31 31
32 32 QTCOMMERCIALCHART_BEGIN_NAMESPACE
33 33
34 34 /*!
35 35 \class QPieSeries
36 36 \brief Pie series API for QtCommercial Charts
37 37
38 38 The pie series defines a pie chart which consists of pie slices which are defined as QPieSlice objects.
39 39 The slices can have any values as the QPieSeries will calculate its relative value to the sum of all slices.
40 40 The actual slice size is determined by that relative value.
41 41
42 42 Pie size and position on the chart is controlled by using relative values which range from 0.0 to 1.0
43 43 These relate to the actual chart rectangle.
44 44
45 45 By default the pie is defined as a full pie but it can also be a partial pie.
46 46 This can be done by setting a starting angle and angle span to the series.
47 47 Full pie is 360 degrees where 0 is at 12 a'clock.
48 48
49 49 See the \l {PieChart Example} {pie chart example} to learn how to create a simple pie chart.
50 50 \image examples_piechart.png
51 51 */
52 52 /*!
53 53 \qmlclass PieSeries QPieSeries
54 54 \inherits AbstractSeries
55 55
56 56 The following QML shows how to create a simple pie chart.
57 57
58 58 \snippet ../demos/qmlchart/qml/qmlchart/View1.qml 1
59 59
60 60 \beginfloatleft
61 61 \image demos_qmlchart1.png
62 62 \endfloat
63 63 \clearfloat
64 64 */
65 65
66 66 /*!
67 67 \property QPieSeries::horizontalPosition
68 68 \brief Defines the horizontal position of the pie.
69 69
70 70 The value is a relative value to the chart rectangle where:
71 71
72 72 \list
73 73 \o 0.0 is the absolute left.
74 74 \o 1.0 is the absolute right.
75 75 \endlist
76 76 Default value is 0.5 (center).
77 77 \sa verticalPosition
78 78 */
79 79
80 80 /*!
81 81 \qmlproperty real PieSeries::horizontalPosition
82 82
83 83 Defines the horizontal position of the pie.
84 84
85 85 The value is a relative value to the chart rectangle where:
86 86
87 87 \list
88 88 \o 0.0 is the absolute left.
89 89 \o 1.0 is the absolute right.
90 90 \endlist
91 91 Default value is 0.5 (center).
92 92 \sa verticalPosition
93 93 */
94 94
95 95 /*!
96 96 \property QPieSeries::verticalPosition
97 97 \brief Defines the vertical position of the pie.
98 98
99 99 The value is a relative value to the chart rectangle where:
100 100
101 101 \list
102 102 \o 0.0 is the absolute top.
103 103 \o 1.0 is the absolute bottom.
104 104 \endlist
105 105 Default value is 0.5 (center).
106 106 \sa horizontalPosition
107 107 */
108 108
109 109 /*!
110 110 \qmlproperty real PieSeries::verticalPosition
111 111
112 112 Defines the vertical position of the pie.
113 113
114 114 The value is a relative value to the chart rectangle where:
115 115
116 116 \list
117 117 \o 0.0 is the absolute top.
118 118 \o 1.0 is the absolute bottom.
119 119 \endlist
120 120 Default value is 0.5 (center).
121 121 \sa horizontalPosition
122 122 */
123 123
124 124 /*!
125 125 \property QPieSeries::size
126 126 \brief Defines the pie size.
127 127
128 128 The value is a relative value to the chart rectangle where:
129 129
130 130 \list
131 131 \o 0.0 is the minimum size (pie not drawn).
132 132 \o 1.0 is the maximum size that can fit the chart.
133 133 \endlist
134 134
135 When setting this property the donutInnerSize property is adjusted if necessary, to ensure that the inner size is not greater than the outer size.
135 When setting this property the holeSize property is adjusted if necessary, to ensure that the hole size is not greater than the outer size.
136 136
137 137 Default value is 0.7.
138 138 */
139 139
140 140 /*!
141 141 \qmlproperty real PieSeries::size
142 142
143 143 Defines the pie size.
144 144
145 145 The value is a relative value to the chart rectangle where:
146 146
147 147 \list
148 148 \o 0.0 is the minimum size (pie not drawn).
149 149 \o 1.0 is the maximum size that can fit the chart.
150 150 \endlist
151 151
152 152 Default value is 0.7.
153 153 */
154 154
155 155 /*!
156 \property QPieSeries::donutInnerSize
157 \brief Defines the donut inner size.
156 \property QPieSeries::holeSize
157 \brief Defines the donut hole size.
158 158
159 159 The value is a relative value to the chart rectangle where:
160 160
161 161 \list
162 \o 0.0 is the minimum size (pie not drawn).
162 \o 0.0 is the minimum size (full pie drawn, without any hole inside).
163 163 \o 1.0 is the maximum size that can fit the chart. (donut has no width)
164 164 \endlist
165 165
166 166 The value is never greater then size property.
167 Default value is 0.5.
167 Default value is 0.0.
168 168 */
169 169
170 170 /*!
171 \qmlproperty real PieSeries::donutInnerSize
171 \qmlproperty real PieSeries::holeSize
172 172
173 Defines the donut inner size.
173 Defines the donut hole size.
174 174
175 175 The value is a relative value to the chart rectangle where:
176 176
177 177 \list
178 \o 0.0 is the minimum size (donut is a pie).
178 \o 0.0 is the minimum size (full pie drawn, without any hole inside).
179 179 \o 1.0 is the maximum size that can fit the chart. (donut has no width)
180 180 \endlist
181 181
182 182 When setting this property the size property is adjusted if necessary, to ensure that the inner size is not greater than the outer size.
183 183
184 Default value is 0.5.
184 Default value is 0.0.
185 185 */
186 186
187 187 /*!
188 188 \property QPieSeries::startAngle
189 189 \brief Defines the starting angle of the pie.
190 190
191 191 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
192 192
193 193 Default is value is 0.
194 194 */
195 195
196 196 /*!
197 197 \qmlproperty real PieSeries::startAngle
198 198
199 199 Defines the starting angle of the pie.
200 200
201 201 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
202 202
203 203 Default is value is 0.
204 204 */
205 205
206 206 /*!
207 207 \property QPieSeries::endAngle
208 208 \brief Defines the ending angle of the pie.
209 209
210 210 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
211 211
212 212 Default is value is 360.
213 213 */
214 214
215 215 /*!
216 216 \qmlproperty real PieSeries::endAngle
217 217
218 218 Defines the ending angle of the pie.
219 219
220 220 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
221 221
222 222 Default is value is 360.
223 223 */
224 224
225 225 /*!
226 226 \property QPieSeries::count
227 227
228 228 Number of slices in the series.
229 229 */
230 230
231 231 /*!
232 232 \qmlproperty int PieSeries::count
233 233
234 234 Number of slices in the series.
235 235 */
236 236
237 237 /*!
238 \property QPieSeries::donut
239
240 Defines whether the series should be drawn as a donut
241 */
242
243 /*!
244 \qmlproperty int PieSeries::donut
245
246 Defines whether the series should be drawn as a donut
247 */
248
249 /*!
250 238 \fn void QPieSeries::countChanged()
251 239 Emitted when the slice count has changed.
252 240 \sa count
253 241 */
254 242 /*!
255 243 \qmlsignal PieSeries::onCountChanged()
256 244 Emitted when the slice count has changed.
257 245 */
258 246
259 247 /*!
260 248 \property QPieSeries::sum
261 249
262 250 Sum of all slices.
263 251
264 252 The series keeps track of the sum of all slices it holds.
265 253 */
266 254
267 255 /*!
268 256 \qmlproperty real PieSeries::sum
269 257
270 258 Sum of all slices.
271 259
272 260 The series keeps track of the sum of all slices it holds.
273 261 */
274 262
275 263 /*!
276 264 \fn void QPieSeries::sumChanged()
277 265 Emitted when the sum of all slices has changed.
278 266 \sa sum
279 267 */
280 268 /*!
281 269 \qmlsignal PieSeries::onSumChanged()
282 270 Emitted when the sum of all slices has changed. This may happen for example if you add or remove slices, or if you
283 271 change value of a slice.
284 272 */
285 273
286 274 /*!
287 275 \fn void QPieSeries::added(QList<QPieSlice*> slices)
288 276
289 277 This signal is emitted when \a slices have been added to the series.
290 278
291 279 \sa append(), insert()
292 280 */
293 281 /*!
294 282 \qmlsignal PieSeries::onAdded(PieSlice slice)
295 283 Emitted when \a slice has been added to the series.
296 284 */
297 285
298 286 /*!
299 287 \fn void QPieSeries::removed(QList<QPieSlice*> slices)
300 288 This signal is emitted when \a slices have been removed from the series.
301 289 \sa remove()
302 290 */
303 291 /*!
304 292 \qmlsignal PieSeries::onRemoved(PieSlice slice)
305 293 Emitted when \a slice has been removed from the series.
306 294 */
307 295
308 296 /*!
309 297 \fn void QPieSeries::clicked(QPieSlice* slice)
310 298 This signal is emitted when a \a slice has been clicked.
311 299 \sa QPieSlice::clicked()
312 300 */
313 301 /*!
314 302 \qmlsignal PieSeries::onClicked(PieSlice slice)
315 303 This signal is emitted when a \a slice has been clicked.
316 304 */
317 305
318 306 /*!
319 307 \fn void QPieSeries::hovered(QPieSlice* slice, bool state)
320 308 This signal is emitted when user has hovered over or away from the \a slice.
321 309 \a state is true when user has hovered over the slice and false when hover has moved away from the slice.
322 310 \sa QPieSlice::hovered()
323 311 */
324 312 /*!
325 313 \qmlsignal PieSeries::onHovered(PieSlice slice, bool state)
326 314 This signal is emitted when user has hovered over or away from the \a slice. \a state is true when user has hovered
327 315 over the slice and false when hover has moved away from the slice.
328 316 */
329 317
330 318 /*!
331 319 \qmlmethod PieSlice PieSeries::at(int index)
332 320 Returns slice at \a index. Returns null if the index is not valid.
333 321 */
334 322
335 323 /*!
336 324 \qmlmethod PieSlice PieSeries::find(string label)
337 325 Returns the first slice with \a label. Returns null if the index is not valid.
338 326 */
339 327
340 328 /*!
341 329 \qmlmethod PieSlice PieSeries::append(string label, real value)
342 330 Adds a new slice with \a label and \a value to the pie.
343 331 */
344 332
345 333 /*!
346 334 \qmlmethod bool PieSeries::remove(PieSlice slice)
347 335 Removes the \a slice from the pie. Returns true if the removal was successfull, false otherwise.
348 336 */
349 337
350 338 /*!
351 339 \qmlmethod PieSeries::clear()
352 340 Removes all slices from the pie.
353 341 */
354 342
355 343 /*!
356 344 Constructs a series object which is a child of \a parent.
357 345 */
358 346 QPieSeries::QPieSeries(QObject *parent) :
359 347 QAbstractSeries(*new QPieSeriesPrivate(this),parent)
360 348 {
361 349
362 350 }
363 351
364 352 /*!
365 353 Destroys the series and its slices.
366 354 */
367 355 QPieSeries::~QPieSeries()
368 356 {
369 357 // NOTE: d_prt destroyed by QObject
370 358 }
371 359
372 360 /*!
373 361 Returns QChartSeries::SeriesTypePie.
374 362 */
375 363 QAbstractSeries::SeriesType QPieSeries::type() const
376 364 {
377 365 return QAbstractSeries::SeriesTypePie;
378 366 }
379 367
380 368 /*!
381 369 Appends a single \a slice to the series.
382 370 Slice ownership is passed to the series.
383 371
384 372 Returns true if append was succesfull.
385 373 */
386 374 bool QPieSeries::append(QPieSlice* slice)
387 375 {
388 376 return append(QList<QPieSlice*>() << slice);
389 377 }
390 378
391 379 /*!
392 380 Appends an array of \a slices to the series.
393 381 Slice ownership is passed to the series.
394 382
395 383 Returns true if append was successfull.
396 384 */
397 385 bool QPieSeries::append(QList<QPieSlice*> slices)
398 386 {
399 387 Q_D(QPieSeries);
400 388
401 389 if (slices.count() == 0)
402 390 return false;
403 391
404 392 foreach (QPieSlice* s, slices) {
405 393 if (!s || d->m_slices.contains(s))
406 394 return false;
407 395 if (s->series()) // already added to some series
408 396 return false;
409 397 }
410 398
411 399 foreach (QPieSlice* s, slices) {
412 400 s->setParent(this);
413 401 QPieSlicePrivate::fromSlice(s)->m_series = this;
414 402 d->m_slices << s;
415 403 }
416 404
417 405 d->updateDerivativeData();
418 406
419 407 foreach (QPieSlice* s, slices) {
420 408 connect(s, SIGNAL(valueChanged()), d, SLOT(sliceValueChanged()));
421 409 connect(s, SIGNAL(clicked()), d, SLOT(sliceClicked()));
422 410 connect(s, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
423 411 }
424 412
425 413 emit added(slices);
426 414 emit countChanged();
427 415
428 416 return true;
429 417 }
430 418
431 419 /*!
432 420 Appends a single \a slice to the series and returns a reference to the series.
433 421 Slice ownership is passed to the series.
434 422 */
435 423 QPieSeries& QPieSeries::operator << (QPieSlice* slice)
436 424 {
437 425 append(slice);
438 426 return *this;
439 427 }
440 428
441 429
442 430 /*!
443 431 Appends a single slice to the series with give \a value and \a label.
444 432 Slice ownership is passed to the series.
445 433 */
446 434 QPieSlice* QPieSeries::append(QString label, qreal value)
447 435 {
448 436 QPieSlice* slice = new QPieSlice(label, value);
449 437 append(slice);
450 438 return slice;
451 439 }
452 440
453 441 /*!
454 442 Inserts a single \a slice to the series before the slice at \a index position.
455 443 Slice ownership is passed to the series.
456 444
457 445 Returns true if insert was successfull.
458 446 */
459 447 bool QPieSeries::insert(int index, QPieSlice* slice)
460 448 {
461 449 Q_D(QPieSeries);
462 450
463 451 if (index < 0 || index > d->m_slices.count())
464 452 return false;
465 453
466 454 if (!slice || d->m_slices.contains(slice))
467 455 return false;
468 456
469 457 if (slice->series()) // already added to some series
470 458 return false;
471 459
472 460 slice->setParent(this);
473 461 QPieSlicePrivate::fromSlice(slice)->m_series = this;
474 462 d->m_slices.insert(index, slice);
475 463
476 464 d->updateDerivativeData();
477 465
478 466 connect(slice, SIGNAL(valueChanged()), d, SLOT(sliceValueChanged()));
479 467 connect(slice, SIGNAL(clicked()), d, SLOT(sliceClicked()));
480 468 connect(slice, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
481 469
482 470 emit added(QList<QPieSlice*>() << slice);
483 471 emit countChanged();
484 472
485 473 return true;
486 474 }
487 475
488 476 /*!
489 477 Removes a single \a slice from the series and deletes the slice.
490 478
491 479 Do not reference the pointer after this call.
492 480
493 481 Returns true if remove was successfull.
494 482 */
495 483 bool QPieSeries::remove(QPieSlice* slice)
496 484 {
497 485 Q_D(QPieSeries);
498 486
499 487 if (!d->m_slices.removeOne(slice))
500 488 return false;
501 489
502 490 d->updateDerivativeData();
503 491
504 492 emit removed(QList<QPieSlice*>() << slice);
505 493 emit countChanged();
506 494
507 495 delete slice;
508 496 slice = 0;
509 497
510 498 return true;
511 499 }
512 500
513 501 /*!
514 502 Takes a single \a slice from the series. Does not destroy the slice object.
515 503
516 504 NOTE: The series remains as the slice's parent object. You must set the
517 505 parent object to take full ownership.
518 506
519 507 Returns true if take was successfull.
520 508 */
521 509 bool QPieSeries::take(QPieSlice* slice)
522 510 {
523 511 Q_D(QPieSeries);
524 512
525 513 if (!d->m_slices.removeOne(slice))
526 514 return false;
527 515
528 516 QPieSlicePrivate::fromSlice(slice)->m_series = 0;
529 517
530 518 d->updateDerivativeData();
531 519
532 520 emit removed(QList<QPieSlice*>() << slice);
533 521 emit countChanged();
534 522
535 523 return true;
536 524 }
537 525
538 526 /*!
539 527 Clears all slices from the series.
540 528 */
541 529 void QPieSeries::clear()
542 530 {
543 531 Q_D(QPieSeries);
544 532 if (d->m_slices.count() == 0)
545 533 return;
546 534
547 535 QList<QPieSlice*> slices = d->m_slices;
548 536 foreach (QPieSlice* s, d->m_slices) {
549 537 d->m_slices.removeOne(s);
550 538 delete s;
551 539 }
552 540
553 541 d->updateDerivativeData();
554 542
555 543 emit removed(slices);
556 544 emit countChanged();
557 545 }
558 546
559 547 /*!
560 548 Returns a list of slices that belong to this series.
561 549 */
562 550 QList<QPieSlice*> QPieSeries::slices() const
563 551 {
564 552 Q_D(const QPieSeries);
565 553 return d->m_slices;
566 554 }
567 555
568 556 /*!
569 557 returns the number of the slices in this series.
570 558 */
571 559 int QPieSeries::count() const
572 560 {
573 561 Q_D(const QPieSeries);
574 562 return d->m_slices.count();
575 563 }
576 564
577 565 /*!
578 566 Returns true is the series is empty.
579 567 */
580 568 bool QPieSeries::isEmpty() const
581 569 {
582 570 Q_D(const QPieSeries);
583 571 return d->m_slices.isEmpty();
584 572 }
585 573
586 574 /*!
587 575 Returns the sum of all slice values in this series.
588 576
589 577 \sa QPieSlice::value(), QPieSlice::setValue(), QPieSlice::percentage()
590 578 */
591 579 qreal QPieSeries::sum() const
592 580 {
593 581 Q_D(const QPieSeries);
594 582 return d->m_sum;
595 583 }
596 584
597 void QPieSeries::setDonut(bool donut)
598 {
599 Q_D(QPieSeries);
600 d->m_donutChart = donut;
601 d->updateDerivativeData();
602 }
603
604 bool QPieSeries::donut() const
605 {
606 Q_D(const QPieSeries);
607 return d->m_donutChart;
608 }
609
610 void QPieSeries::setDonutInnerSize(qreal innerSize)
585 void QPieSeries::setHoleSize(qreal holeSize)
611 586 {
612 587 Q_D(QPieSeries);
613 innerSize = qBound((qreal)0.0, innerSize, (qreal)1.0);
614 d->setSizes(innerSize, qMax(d->m_pieRelativeSize, innerSize));
588 holeSize = qBound((qreal)0.0, holeSize, (qreal)1.0);
589 d->setSizes(holeSize, qMax(d->m_pieRelativeSize, holeSize));
615 590 }
616 591
617 qreal QPieSeries::donutInnerSize() const
592 qreal QPieSeries::holeSize() const
618 593 {
619 594 Q_D(const QPieSeries);
620 return d->m_donutRelativeInnerSize;
595 return d->m_holeRelativeSize;
621 596 }
622 597
623 598 void QPieSeries::setHorizontalPosition(qreal relativePosition)
624 599 {
625 600 Q_D(QPieSeries);
626 601
627 602 if (relativePosition < 0.0)
628 603 relativePosition = 0.0;
629 604 if (relativePosition > 1.0)
630 605 relativePosition = 1.0;
631 606
632 607 if (!qFuzzyIsNull(d->m_pieRelativeHorPos - relativePosition)) {
633 608 d->m_pieRelativeHorPos = relativePosition;
634 609 emit d->horizontalPositionChanged();
635 610 }
636 611 }
637 612
638 613 qreal QPieSeries::horizontalPosition() const
639 614 {
640 615 Q_D(const QPieSeries);
641 616 return d->m_pieRelativeHorPos;
642 617 }
643 618
644 619 void QPieSeries::setVerticalPosition(qreal relativePosition)
645 620 {
646 621 Q_D(QPieSeries);
647 622
648 623 if (relativePosition < 0.0)
649 624 relativePosition = 0.0;
650 625 if (relativePosition > 1.0)
651 626 relativePosition = 1.0;
652 627
653 628 if (!qFuzzyIsNull(d->m_pieRelativeVerPos - relativePosition)) {
654 629 d->m_pieRelativeVerPos = relativePosition;
655 630 emit d->verticalPositionChanged();
656 631 }
657 632 }
658 633
659 634 qreal QPieSeries::verticalPosition() const
660 635 {
661 636 Q_D(const QPieSeries);
662 637 return d->m_pieRelativeVerPos;
663 638 }
664 639
665 640 void QPieSeries::setPieSize(qreal relativeSize)
666 641 {
667 642 Q_D(QPieSeries);
668 643 relativeSize = qBound((qreal)0.0, relativeSize, (qreal)1.0);
669 d->setSizes(qMin(d->m_donutRelativeInnerSize, relativeSize), relativeSize);
644 d->setSizes(qMin(d->m_holeRelativeSize, relativeSize), relativeSize);
670 645
671 646 }
672 647
673 648 qreal QPieSeries::pieSize() const
674 649 {
675 650 Q_D(const QPieSeries);
676 651 return d->m_pieRelativeSize;
677 652 }
678 653
679 654
680 655 void QPieSeries::setPieStartAngle(qreal angle)
681 656 {
682 657 Q_D(QPieSeries);
683 658 if (qFuzzyIsNull(d->m_pieStartAngle - angle))
684 659 return;
685 660 d->m_pieStartAngle = angle;
686 661 d->updateDerivativeData();
687 662 emit d->pieStartAngleChanged();
688 663 }
689 664
690 665 qreal QPieSeries::pieStartAngle() const
691 666 {
692 667 Q_D(const QPieSeries);
693 668 return d->m_pieStartAngle;
694 669 }
695 670
696 671 /*!
697 672 Sets the end angle of the pie.
698 673
699 674 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
700 675
701 676 \a angle must be greater than start angle.
702 677
703 678 \sa pieEndAngle(), pieStartAngle(), setPieStartAngle()
704 679 */
705 680 void QPieSeries::setPieEndAngle(qreal angle)
706 681 {
707 682 Q_D(QPieSeries);
708 683 if (qFuzzyIsNull(d->m_pieEndAngle - angle))
709 684 return;
710 685 d->m_pieEndAngle = angle;
711 686 d->updateDerivativeData();
712 687 emit d->pieEndAngleChanged();
713 688 }
714 689
715 690 /*!
716 691 Returns the end angle of the pie.
717 692
718 693 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
719 694
720 695 \sa setPieEndAngle(), pieStartAngle(), setPieStartAngle()
721 696 */
722 697 qreal QPieSeries::pieEndAngle() const
723 698 {
724 699 Q_D(const QPieSeries);
725 700 return d->m_pieEndAngle;
726 701 }
727 702
728 703 /*!
729 704 Sets the all the slice labels \a visible or invisible.
730 705
731 706 Note that this affects only the current slices in the series.
732 707 If user adds a new slice the default label visibility is false.
733 708
734 709 \sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible()
735 710 */
736 711 void QPieSeries::setLabelsVisible(bool visible)
737 712 {
738 713 Q_D(QPieSeries);
739 714 foreach (QPieSlice* s, d->m_slices)
740 715 s->setLabelVisible(visible);
741 716 }
742 717
743 718 /*!
744 719 Sets the all the slice labels \a position
745 720
746 721 Note that this affects only the current slices in the series.
747 722 If user adds a new slice the default label position is LabelOutside
748 723
749 724 \sa QPieSlice::labelPosition(), QPieSlice::setLabelPosition()
750 725 */
751 726 void QPieSeries::setLabelsPosition(QPieSlice::LabelPosition position)
752 727 {
753 728 Q_D(QPieSeries);
754 729 foreach (QPieSlice* s, d->m_slices)
755 730 s->setLabelPosition(position);
756 731 }
757 732
758 733 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
759 734
760 735
761 736 QPieSeriesPrivate::QPieSeriesPrivate(QPieSeries *parent) :
762 737 QAbstractSeriesPrivate(parent),
763 738 m_pieRelativeHorPos(0.5),
764 739 m_pieRelativeVerPos(0.5),
765 740 m_pieRelativeSize(0.7),
766 741 m_pieStartAngle(0),
767 742 m_pieEndAngle(360),
768 743 m_sum(0),
769 m_donutChart(false),
770 m_donutRelativeInnerSize(0.5)
744 // m_donutChart(false),
745 m_holeRelativeSize(0.0)
771 746 {
772 747 }
773 748
774 749 QPieSeriesPrivate::~QPieSeriesPrivate()
775 750 {
776 751 }
777 752
778 753 void QPieSeriesPrivate::updateDerivativeData()
779 754 {
780 755 // calculate sum of all slices
781 756 qreal sum = 0;
782 757 foreach (QPieSlice* s, m_slices)
783 758 sum += s->value();
784 759
785 760 if (!qFuzzyIsNull(m_sum - sum)) {
786 761 m_sum = sum;
787 762 emit q_func()->sumChanged();
788 763 }
789 764
790 765 // nothing to show..
791 766 if (qFuzzyIsNull(m_sum))
792 767 return;
793 768
794 769 // update slice attributes
795 770 qreal sliceAngle = m_pieStartAngle;
796 771 qreal pieSpan = m_pieEndAngle - m_pieStartAngle;
797 772 QVector<QPieSlice*> changed;
798 773 foreach (QPieSlice* s, m_slices) {
799 774 QPieSlicePrivate *d = QPieSlicePrivate::fromSlice(s);
800 775 d->setPercentage(s->value() / m_sum);
801 776 d->setStartAngle(sliceAngle);
802 777 d->setAngleSpan(pieSpan * s->percentage());
803 778 sliceAngle += s->angleSpan();
804 779 }
805 780
806 781
807 782 emit calculatedDataChanged();
808 783 }
809 784
810 785 void QPieSeriesPrivate::setSizes(qreal innerSize, qreal outerSize)
811 786 {
812 787 bool changed = false;
813 788
814 if (!qFuzzyIsNull(m_donutRelativeInnerSize - innerSize)) {
815 m_donutRelativeInnerSize = innerSize;
789 if (!qFuzzyIsNull(m_holeRelativeSize - innerSize)) {
790 m_holeRelativeSize = innerSize;
816 791 changed = true;
817 792 }
818 793
819 794 if (!qFuzzyIsNull(m_pieRelativeSize - outerSize)) {
820 795 m_pieRelativeSize = outerSize;
821 796 changed = true;
822 797 }
823 798
824 799 if (changed)
825 800 emit pieSizeChanged();
826 801 }
827 802
828 803 QPieSeriesPrivate* QPieSeriesPrivate::fromSeries(QPieSeries *series)
829 804 {
830 805 return series->d_func();
831 806 }
832 807
833 808 void QPieSeriesPrivate::sliceValueChanged()
834 809 {
835 810 Q_ASSERT(m_slices.contains(qobject_cast<QPieSlice *>(sender())));
836 811 updateDerivativeData();
837 812 }
838 813
839 814 void QPieSeriesPrivate::sliceClicked()
840 815 {
841 816 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
842 817 Q_ASSERT(m_slices.contains(slice));
843 818 Q_Q(QPieSeries);
844 819 emit q->clicked(slice);
845 820 }
846 821
847 822 void QPieSeriesPrivate::sliceHovered(bool state)
848 823 {
849 824 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
850 825 Q_ASSERT(m_slices.contains(slice));
851 826 Q_Q(QPieSeries);
852 827 emit q->hovered(slice, state);
853 828 }
854 829
855 830 void QPieSeriesPrivate::scaleDomain(Domain& domain)
856 831 {
857 832 Q_UNUSED(domain);
858 833 // does not apply to pie
859 834 }
860 835
861 836 ChartElement* QPieSeriesPrivate::createGraphics(ChartPresenter* presenter)
862 837 {
863 838 Q_Q(QPieSeries);
864 839 PieChartItem* pie = new PieChartItem(q,presenter);
865 840 if(presenter->animationOptions().testFlag(QChart::SeriesAnimations)) {
866 841 pie->setAnimation(new PieAnimation(pie));
867 842 }
868 843 presenter->chartTheme()->decorate(q, presenter->dataSet()->seriesIndex(q));
869 844 return pie;
870 845 }
871 846
872 847 QList<LegendMarker*> QPieSeriesPrivate::createLegendMarker(QLegend* legend)
873 848 {
874 849 Q_Q(QPieSeries);
875 850 QList<LegendMarker*> markers;
876 851 foreach(QPieSlice* slice, q->slices()) {
877 852 PieLegendMarker* marker = new PieLegendMarker(q,slice,legend);
878 853 markers << marker;
879 854 }
880 855 return markers;
881 856 }
882 857
883 858 void QPieSeriesPrivate::initializeAxis(QAbstractAxis* axis)
884 859 {
885 860 Q_UNUSED(axis);
886 861 }
887 862
888 863 QAbstractAxis::AxisType QPieSeriesPrivate::defaultAxisType(Qt::Orientation orientation) const
889 864 {
890 865 Q_UNUSED(orientation);
891 866 return QAbstractAxis::AxisTypeNoAxis;
892 867 }
893 868
894 869 #include "moc_qpieseries.cpp"
895 870 #include "moc_qpieseries_p.cpp"
896 871
897 872 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,107 +1,104
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #ifndef PIESERIES_H
22 22 #define PIESERIES_H
23 23
24 24 #include <qabstractseries.h>
25 25 #include <QPieSlice>
26 26
27 27 QTCOMMERCIALCHART_BEGIN_NAMESPACE
28 28 class QPieSeriesPrivate;
29 29 //class QPieSlice;
30 30
31 31 class QTCOMMERCIALCHART_EXPORT QPieSeries : public QAbstractSeries
32 32 {
33 33 Q_OBJECT
34 34 Q_PROPERTY(qreal horizontalPosition READ horizontalPosition WRITE setHorizontalPosition)
35 35 Q_PROPERTY(qreal verticalPosition READ verticalPosition WRITE setVerticalPosition)
36 36 Q_PROPERTY(qreal size READ pieSize WRITE setPieSize)
37 37 Q_PROPERTY(qreal startAngle READ pieStartAngle WRITE setPieStartAngle)
38 38 Q_PROPERTY(qreal endAngle READ pieEndAngle WRITE setPieEndAngle)
39 39 Q_PROPERTY(int count READ count NOTIFY countChanged)
40 40 Q_PROPERTY(qreal sum READ sum NOTIFY sumChanged)
41 Q_PROPERTY(qreal donutInnerSize READ donutInnerSize WRITE setDonutInnerSize)
42 Q_PROPERTY(bool donut READ donut WRITE setDonut)
41 Q_PROPERTY(qreal holeSize READ holeSize WRITE setHoleSize)
42 // Q_PROPERTY(bool donut READ donut WRITE setDonut)
43 43
44 44 public:
45 45 explicit QPieSeries(QObject *parent = 0);
46 46 virtual ~QPieSeries();
47 47
48 48 QAbstractSeries::SeriesType type() const;
49 49
50 50 bool append(QPieSlice* slice);
51 51 bool append(QList<QPieSlice*> slices);
52 52 QPieSeries& operator << (QPieSlice* slice);
53 53 QPieSlice* append(QString label, qreal value);
54 54
55 55 bool insert(int index, QPieSlice* slice);
56 56
57 57 bool remove(QPieSlice* slice);
58 58 bool take(QPieSlice* slice);
59 59 void clear();
60 60
61 61 QList<QPieSlice*> slices() const;
62 62 int count() const;
63 63
64 64 bool isEmpty() const;
65 65
66 66 qreal sum() const;
67 67
68 void setDonut(bool donut = true);
69 bool donut() const;
70
71 void setDonutInnerSize(qreal innerSize);
72 qreal donutInnerSize() const;
68 void setHoleSize(qreal holeSize);
69 qreal holeSize() const;
73 70
74 71 void setHorizontalPosition(qreal relativePosition);
75 72 qreal horizontalPosition() const;
76 73
77 74 void setVerticalPosition(qreal relativePosition);
78 75 qreal verticalPosition() const;
79 76
80 77 void setPieSize(qreal relativeSize);
81 78 qreal pieSize() const;
82 79
83 80 void setPieStartAngle(qreal startAngle);
84 81 qreal pieStartAngle() const;
85 82
86 83 void setPieEndAngle(qreal endAngle);
87 84 qreal pieEndAngle() const;
88 85
89 86 void setLabelsVisible(bool visible = true);
90 87 void setLabelsPosition(QPieSlice::LabelPosition position);
91 88
92 89 Q_SIGNALS:
93 90 void added(QList<QPieSlice*> slices);
94 91 void removed(QList<QPieSlice*> slices);
95 92 void clicked(QPieSlice* slice);
96 93 void hovered(QPieSlice* slice, bool state);
97 94 void countChanged();
98 95 void sumChanged();
99 96
100 97 private:
101 98 Q_DECLARE_PRIVATE(QPieSeries)
102 99 Q_DISABLE_COPY(QPieSeries)
103 100 };
104 101
105 102 QTCOMMERCIALCHART_END_NAMESPACE
106 103
107 104 #endif // PIESERIES_H
@@ -1,89 +1,88
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 // W A R N I N G
22 22 // -------------
23 23 //
24 24 // This file is not part of the QtCommercial Chart API. It exists purely as an
25 25 // implementation detail. This header file may change from version to
26 26 // version without notice, or even be removed.
27 27 //
28 28 // We mean it.
29 29
30 30 #ifndef QPIESERIES_P_H
31 31 #define QPIESERIES_P_H
32 32
33 33 #include "qpieseries.h"
34 34 #include "qabstractseries_p.h"
35 35
36 36 QTCOMMERCIALCHART_BEGIN_NAMESPACE
37 37 class QLegendPrivate;
38 38
39 39 class QPieSeriesPrivate : public QAbstractSeriesPrivate
40 40 {
41 41 Q_OBJECT
42 42
43 43 public:
44 44 QPieSeriesPrivate(QPieSeries *parent);
45 45 ~QPieSeriesPrivate();
46 46
47 47 void scaleDomain(Domain& domain);
48 48 ChartElement* createGraphics(ChartPresenter *presenter);
49 49 QList<LegendMarker*> createLegendMarker(QLegend *legend);
50 50 void initializeAxis(QAbstractAxis* axis);
51 51 QAbstractAxis::AxisType defaultAxisType(Qt::Orientation orientation) const;
52 52
53 53 void updateDerivativeData();
54 54 void setSizes(qreal innerSize, qreal outerSize);
55 55
56 56 static QPieSeriesPrivate* fromSeries(QPieSeries *series);
57 57
58 58 signals:
59 59 void calculatedDataChanged();
60 60 void pieSizeChanged();
61 61 void pieStartAngleChanged();
62 62 void pieEndAngleChanged();
63 63 void horizontalPositionChanged();
64 64 void verticalPositionChanged();
65 65
66 66 public Q_SLOTS:
67 67 void sliceValueChanged();
68 68 void sliceClicked();
69 69 void sliceHovered(bool state);
70 70
71 71 private:
72 72 QList<QPieSlice*> m_slices;
73 73 qreal m_pieRelativeHorPos;
74 74 qreal m_pieRelativeVerPos;
75 75 qreal m_pieRelativeSize;
76 76 qreal m_pieStartAngle;
77 77 qreal m_pieEndAngle;
78 78 qreal m_sum;
79 bool m_donutChart;
80 qreal m_donutRelativeInnerSize;
79 qreal m_holeRelativeSize;
81 80
82 81 private:
83 82 friend class QLegendPrivate;
84 83 Q_DECLARE_PUBLIC(QPieSeries)
85 84 };
86 85
87 86 QTCOMMERCIALCHART_END_NAMESPACE
88 87
89 88 #endif // QPIESERIES_P_H
@@ -1,640 +1,638
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include <QtTest/QtTest>
22 22 #include <qchartview.h>
23 23 #include <qchart.h>
24 24 #include <qpieseries.h>
25 25 #include <qpieslice.h>
26 26 #include <qpiemodelmapper.h>
27 27 #include <QStandardItemModel>
28 28 #include <tst_definitions.h>
29 29
30 30 QTCOMMERCIALCHART_USE_NAMESPACE
31 31
32 32 Q_DECLARE_METATYPE(QPieSlice*)
33 33 Q_DECLARE_METATYPE(QList<QPieSlice*>)
34 34
35 35 class tst_qpieseries : public QObject
36 36 {
37 37 Q_OBJECT
38 38
39 39 public slots:
40 40 void initTestCase();
41 41 void cleanupTestCase();
42 42 void init();
43 43 void cleanup();
44 44
45 45 private slots:
46 46 void properties();
47 47 void append();
48 48 void appendAnimated();
49 49 void insert();
50 50 void insertAnimated();
51 51 void remove();
52 52 void removeAnimated();
53 53 void take();
54 54 void takeAnimated();
55 55 void calculatedValues();
56 56 void clickedSignal();
57 57 void hoverSignal();
58 58 void sliceSeries();
59 59 void destruction();
60 60
61 61 private:
62 62 void verifyCalculatedData(const QPieSeries &series, bool *ok);
63 63
64 64 private:
65 65 QChartView *m_view;
66 66 QPieSeries *m_series;
67 67 };
68 68
69 69 void tst_qpieseries::initTestCase()
70 70 {
71 71 qRegisterMetaType<QPieSlice*>("QPieSlice*");
72 72 qRegisterMetaType<QList<QPieSlice*> >("QList<QPieSlice*>");
73 73 }
74 74
75 75 void tst_qpieseries::cleanupTestCase()
76 76 {
77 77 }
78 78
79 79 void tst_qpieseries::init()
80 80 {
81 81 m_view = new QChartView();
82 82 m_series = new QPieSeries(m_view);
83 83 m_view->show();
84 84 QTest::qWaitForWindowShown(m_view);
85 85
86 86 }
87 87
88 88 void tst_qpieseries::cleanup()
89 89 {
90 90 delete m_view;
91 91 m_view = 0;
92 92 m_series = 0;
93 93 }
94 94
95 95 void tst_qpieseries::properties()
96 96 {
97 97 QSignalSpy countSpy(m_series, SIGNAL(countChanged()));
98 98 QSignalSpy sumSpy(m_series, SIGNAL(sumChanged()));
99 99
100 100 QVERIFY(m_series->type() == QAbstractSeries::SeriesTypePie);
101 101 QVERIFY(m_series->count() == 0);
102 102 QVERIFY(m_series->isEmpty());
103 103 QCOMPARE(m_series->sum(), 0.0);
104 104 QCOMPARE(m_series->horizontalPosition(), 0.5);
105 105 QCOMPARE(m_series->verticalPosition(), 0.5);
106 106 QCOMPARE(m_series->pieSize(), 0.7);
107 107 QCOMPARE(m_series->pieStartAngle(), 0.0);
108 108 QCOMPARE(m_series->pieEndAngle(), 360.0);
109 109
110 110 m_series->append("s1", 1);
111 111 m_series->append("s2", 1);
112 112 m_series->append("s3", 1);
113 113 m_series->insert(1, new QPieSlice("s4", 1));
114 114 m_series->remove(m_series->slices().first());
115 115 QCOMPARE(m_series->count(), 3);
116 116 QCOMPARE(m_series->sum(), 3.0);
117 117 m_series->clear();
118 118 QCOMPARE(m_series->count(), 0);
119 119 QCOMPARE(m_series->sum(), 0.0);
120 120 QCOMPARE(countSpy.count(), 6);
121 121 QCOMPARE(sumSpy.count(), 6);
122 122
123 123 m_series->setPieSize(-1.0);
124 124 QCOMPARE(m_series->pieSize(), 0.0);
125 125 m_series->setPieSize(0.0);
126 126 m_series->setPieSize(0.9);
127 127 m_series->setPieSize(2.0);
128 128 QCOMPARE(m_series->pieSize(), 1.0);
129 129
130 130 m_series->setPieSize(0.7);
131 131 QCOMPARE(m_series->pieSize(), 0.7);
132 m_series->setDonut();
133 QVERIFY(m_series->donut());
134 132
135 m_series->setDonutInnerSize(-1.0);
136 QCOMPARE(m_series->donutInnerSize(), 0.0);
137 m_series->setDonutInnerSize(0.5);
138 QCOMPARE(m_series->donutInnerSize(), 0.5);
133 m_series->setHoleSize(-1.0);
134 QCOMPARE(m_series->holeSize(), 0.0);
135 m_series->setHoleSize(0.5);
136 QCOMPARE(m_series->holeSize(), 0.5);
139 137
140 m_series->setDonutInnerSize(0.8);
141 QCOMPARE(m_series->donutInnerSize(), 0.8);
138 m_series->setHoleSize(0.8);
139 QCOMPARE(m_series->holeSize(), 0.8);
142 140 QCOMPARE(m_series->pieSize(), 0.8);
143 141
144 142 m_series->setPieSize(0.4);
145 143 QCOMPARE(m_series->pieSize(), 0.4);
146 QCOMPARE(m_series->donutInnerSize(), 0.4);
144 QCOMPARE(m_series->holeSize(), 0.4);
147 145
148 146 m_series->setPieStartAngle(0);
149 147 m_series->setPieStartAngle(-180);
150 148 m_series->setPieStartAngle(180);
151 149 QCOMPARE(m_series->pieStartAngle(), 180.0);
152 150
153 151 m_series->setPieEndAngle(360);
154 152 m_series->setPieEndAngle(-180);
155 153 m_series->setPieEndAngle(180);
156 154 QCOMPARE(m_series->pieEndAngle(), 180.0);
157 155
158 156 m_series->setHorizontalPosition(0.5);
159 157 m_series->setHorizontalPosition(-1.0);
160 158 QCOMPARE(m_series->horizontalPosition(), 0.0);
161 159 m_series->setHorizontalPosition(1.0);
162 160 m_series->setHorizontalPosition(2.0);
163 161 QCOMPARE(m_series->horizontalPosition(), 1.0);
164 162
165 163 m_series->setVerticalPosition(0.5);
166 164 m_series->setVerticalPosition(-1.0);
167 165 QCOMPARE(m_series->verticalPosition(), 0.0);
168 166 m_series->setVerticalPosition(1.0);
169 167 m_series->setVerticalPosition(2.0);
170 168 QCOMPARE(m_series->verticalPosition(), 1.0);
171 169 }
172 170
173 171 void tst_qpieseries::append()
174 172 {
175 173 m_view->chart()->addSeries(m_series);
176 174 QSignalSpy addedSpy(m_series, SIGNAL(added(QList<QPieSlice*>)));
177 175
178 176 // append pointer
179 177 QPieSlice *slice1 = 0;
180 178 QVERIFY(!m_series->append(slice1));
181 179 slice1 = new QPieSlice("slice 1", 1);
182 180 QVERIFY(m_series->append(slice1));
183 181 QVERIFY(!m_series->append(slice1));
184 182 QCOMPARE(m_series->count(), 1);
185 183 QCOMPARE(addedSpy.count(), 1);
186 184 QList<QPieSlice*> added = qvariant_cast<QList<QPieSlice*> >(addedSpy.at(0).at(0));
187 185 QCOMPARE(added.count(), 1);
188 186 QCOMPARE(added.first(), slice1);
189 187
190 188 // try to append same slice to another series
191 189 QPieSeries series2;
192 190 QVERIFY(!series2.append(slice1));
193 191
194 192 // append pointer list
195 193 QList<QPieSlice *> list;
196 194 QVERIFY(!m_series->append(list));
197 195 list << (QPieSlice *) 0;
198 196 QVERIFY(!m_series->append(list));
199 197 list.clear();
200 198 list << new QPieSlice("slice 2", 2);
201 199 list << new QPieSlice("slice 3", 3);
202 200 QVERIFY(m_series->append(list));
203 201 QVERIFY(!m_series->append(list));
204 202 QCOMPARE(m_series->count(), 3);
205 203 QCOMPARE(addedSpy.count(), 2);
206 204 added = qvariant_cast<QList<QPieSlice*> >(addedSpy.at(1).at(0));
207 205 QCOMPARE(added.count(), 2);
208 206 QCOMPARE(added, list);
209 207
210 208 // append operator
211 209 QPieSlice *slice4 = new QPieSlice("slice 4", 4);
212 210 *m_series << slice4;
213 211 *m_series << slice1; // fails because already added
214 212 QCOMPARE(m_series->count(), 4);
215 213 QCOMPARE(addedSpy.count(), 3);
216 214 added = qvariant_cast<QList<QPieSlice*> >(addedSpy.at(2).at(0));
217 215 QCOMPARE(added.count(), 1);
218 216 QCOMPARE(added.first(), slice4);
219 217
220 218 // append with params
221 219 QPieSlice *slice5 = m_series->append("slice 5", 5);
222 220 QVERIFY(slice5 != 0);
223 221 QCOMPARE(slice5->value(), 5.0);
224 222 QCOMPARE(slice5->label(), QString("slice 5"));
225 223 QCOMPARE(m_series->count(), 5);
226 224 QCOMPARE(addedSpy.count(), 4);
227 225 added = qvariant_cast<QList<QPieSlice*> >(addedSpy.at(3).at(0));
228 226 QCOMPARE(added.count(), 1);
229 227 QCOMPARE(added.first(), slice5);
230 228
231 229 // check slices
232 230 QVERIFY(!m_series->isEmpty());
233 231 for (int i=0; i<m_series->count(); i++) {
234 232 QCOMPARE(m_series->slices().at(i)->value(), (qreal) i+1);
235 233 QCOMPARE(m_series->slices().at(i)->label(), QString("slice ") + QString::number(i+1));
236 234 }
237 235 }
238 236
239 237 void tst_qpieseries::appendAnimated()
240 238 {
241 239 m_view->chart()->setAnimationOptions(QChart::AllAnimations);
242 240 append();
243 241 }
244 242
245 243 void tst_qpieseries::insert()
246 244 {
247 245 m_view->chart()->addSeries(m_series);
248 246 QSignalSpy addedSpy(m_series, SIGNAL(added(QList<QPieSlice*>)));
249 247
250 248 // insert one slice
251 249 QPieSlice *slice1 = 0;
252 250 QVERIFY(!m_series->insert(0, slice1));
253 251 slice1 = new QPieSlice("slice 1", 1);
254 252 QVERIFY(!m_series->insert(-1, slice1));
255 253 QVERIFY(!m_series->insert(5, slice1));
256 254 QVERIFY(m_series->insert(0, slice1));
257 255 QVERIFY(!m_series->insert(0, slice1));
258 256 QCOMPARE(m_series->count(), 1);
259 257 QCOMPARE(addedSpy.count(), 1);
260 258 QList<QPieSlice*> added = qvariant_cast<QList<QPieSlice*> >(addedSpy.at(0).at(0));
261 259 QCOMPARE(added.count(), 1);
262 260 QCOMPARE(added.first(), slice1);
263 261
264 262 // try to insert same slice to another series
265 263 QPieSeries series2;
266 264 QVERIFY(!series2.insert(0, slice1));
267 265
268 266 // add some more slices
269 267 QPieSlice *slice2 = m_series->append("slice 2", 2);
270 268 QPieSlice *slice4 = m_series->append("slice 4", 4);
271 269 QCOMPARE(m_series->count(), 3);
272 270 QCOMPARE(addedSpy.count(), 3);
273 271 added = qvariant_cast<QList<QPieSlice*> >(addedSpy.at(1).at(0));
274 272 QCOMPARE(added.count(), 1);
275 273 QCOMPARE(added.first(), slice2);
276 274 added = qvariant_cast<QList<QPieSlice*> >(addedSpy.at(2).at(0));
277 275 QCOMPARE(added.count(), 1);
278 276 QCOMPARE(added.first(), slice4);
279 277
280 278 // insert between slices
281 279 QPieSlice *slice3 = new QPieSlice("slice 3", 3);
282 280 m_series->insert(2, slice3);
283 281 QCOMPARE(m_series->count(), 4);
284 282 QCOMPARE(addedSpy.count(), 4);
285 283 added = qvariant_cast<QList<QPieSlice*> >(addedSpy.at(3).at(0));
286 284 QCOMPARE(added.count(), 1);
287 285 QCOMPARE(added.first(), slice3);
288 286
289 287 // check slices
290 288 for (int i=0; i<m_series->count(); i++) {
291 289 QCOMPARE(m_series->slices().at(i)->value(), (qreal) i+1);
292 290 QCOMPARE(m_series->slices().at(i)->label(), QString("slice ") + QString::number(i+1));
293 291 QVERIFY(m_series->slices().at(i)->parent() == m_series);
294 292 }
295 293 }
296 294
297 295 void tst_qpieseries::insertAnimated()
298 296 {
299 297 m_view->chart()->setAnimationOptions(QChart::AllAnimations);
300 298 insert();
301 299 }
302 300
303 301 void tst_qpieseries::remove()
304 302 {
305 303 m_view->chart()->addSeries(m_series);
306 304 QSignalSpy removedSpy(m_series, SIGNAL(removed(QList<QPieSlice*>)));
307 305
308 306 // add some slices
309 307 QPieSlice *slice1 = m_series->append("slice 1", 1);
310 308 QPieSlice *slice2 = m_series->append("slice 2", 2);
311 309 QPieSlice *slice3 = m_series->append("slice 3", 3);
312 310 QSignalSpy spy1(slice1, SIGNAL(destroyed()));
313 311 QSignalSpy spy2(slice2, SIGNAL(destroyed()));
314 312 QSignalSpy spy3(slice3, SIGNAL(destroyed()));
315 313 QCOMPARE(m_series->count(), 3);
316 314
317 315 // null pointer remove
318 316 QVERIFY(!m_series->remove(0));
319 317
320 318 // remove first
321 319 QVERIFY(m_series->remove(slice1));
322 320 QVERIFY(!m_series->remove(slice1));
323 321 QCOMPARE(m_series->count(), 2);
324 322 QCOMPARE(m_series->slices().at(0)->label(), slice2->label());
325 323 QCOMPARE(removedSpy.count(), 1);
326 324 QList<QPieSlice*> removed = qvariant_cast<QList<QPieSlice*> >(removedSpy.at(0).at(0));
327 325 QCOMPARE(removed.count(), 1);
328 326 QCOMPARE(removed.first(), slice1);
329 327
330 328 // remove all
331 329 m_series->clear();
332 330 QVERIFY(m_series->isEmpty());
333 331 QVERIFY(m_series->slices().isEmpty());
334 332 QCOMPARE(m_series->count(), 0);
335 333 QCOMPARE(removedSpy.count(), 2);
336 334 removed = qvariant_cast<QList<QPieSlice*> >(removedSpy.at(1).at(0));
337 335 QCOMPARE(removed.count(), 2);
338 336 QCOMPARE(removed.first(), slice2);
339 337 QCOMPARE(removed.last(), slice3);
340 338
341 339 // check that slices were actually destroyed
342 340 TRY_COMPARE(spy1.count(), 1);
343 341 TRY_COMPARE(spy2.count(), 1);
344 342 TRY_COMPARE(spy3.count(), 1);
345 343 }
346 344
347 345 void tst_qpieseries::removeAnimated()
348 346 {
349 347 m_view->chart()->setAnimationOptions(QChart::AllAnimations);
350 348 remove();
351 349 }
352 350
353 351 void tst_qpieseries::take()
354 352 {
355 353 m_view->chart()->addSeries(m_series);
356 354 QSignalSpy removedSpy(m_series, SIGNAL(removed(QList<QPieSlice*>)));
357 355
358 356 // add some slices
359 357 QPieSlice *slice1 = m_series->append("slice 1", 1);
360 358 QPieSlice *slice2 = m_series->append("slice 2", 2);
361 359 m_series->append("slice 3", 3);
362 360 QSignalSpy spy1(slice1, SIGNAL(destroyed()));
363 361 QCOMPARE(m_series->count(), 3);
364 362
365 363 // null pointer remove
366 364 QVERIFY(!m_series->take(0));
367 365
368 366 // take first
369 367 QVERIFY(m_series->take(slice1));
370 368 TRY_COMPARE(spy1.count(), 0);
371 369 QVERIFY(slice1->parent() == m_series); // series is still the parent object
372 370 QVERIFY(!m_series->take(slice1));
373 371 QCOMPARE(m_series->count(), 2);
374 372 QCOMPARE(m_series->slices().at(0)->label(), slice2->label());
375 373 QCOMPARE(removedSpy.count(), 1);
376 374 QList<QPieSlice*> removed = qvariant_cast<QList<QPieSlice*> >(removedSpy.at(0).at(0));
377 375 QCOMPARE(removed.count(), 1);
378 376 QCOMPARE(removed.first(), slice1);
379 377 }
380 378
381 379 void tst_qpieseries::takeAnimated()
382 380 {
383 381 m_view->chart()->setAnimationOptions(QChart::AllAnimations);
384 382 take();
385 383 }
386 384
387 385 void tst_qpieseries::calculatedValues()
388 386 {
389 387 m_view->chart()->addSeries(m_series);
390 388
391 389 QPieSlice *slice1 = new QPieSlice("slice 1", 1);
392 390 QSignalSpy percentageSpy(slice1, SIGNAL(percentageChanged()));
393 391 QSignalSpy startAngleSpy(slice1, SIGNAL(startAngleChanged()));
394 392 QSignalSpy angleSpanSpy(slice1, SIGNAL(angleSpanChanged()));
395 393
396 394 // add a slice
397 395 m_series->append(slice1);
398 396 bool ok;
399 397 verifyCalculatedData(*m_series, &ok);
400 398 if (!ok)
401 399 return;
402 400 QCOMPARE(percentageSpy.count(), 1);
403 401 QCOMPARE(startAngleSpy.count(), 0);
404 402 QCOMPARE(angleSpanSpy.count(), 1);
405 403
406 404 // add some more slices
407 405 QList<QPieSlice *> list;
408 406 list << new QPieSlice("slice 2", 2);
409 407 list << new QPieSlice("slice 3", 3);
410 408 m_series->append(list);
411 409 verifyCalculatedData(*m_series, &ok);
412 410 if (!ok)
413 411 return;
414 412 QCOMPARE(percentageSpy.count(), 2);
415 413 QCOMPARE(startAngleSpy.count(), 0);
416 414 QCOMPARE(angleSpanSpy.count(), 2);
417 415
418 416 // remove a slice
419 417 m_series->remove(list.first()); // remove slice 2
420 418 verifyCalculatedData(*m_series, &ok);
421 419 if (!ok)
422 420 return;
423 421 QCOMPARE(percentageSpy.count(), 3);
424 422 QCOMPARE(startAngleSpy.count(), 0);
425 423 QCOMPARE(angleSpanSpy.count(), 3);
426 424
427 425 // insert a slice
428 426 m_series->insert(0, new QPieSlice("Slice 4", 4));
429 427 verifyCalculatedData(*m_series, &ok);
430 428 if (!ok)
431 429 return;
432 430 QCOMPARE(percentageSpy.count(), 4);
433 431 QCOMPARE(startAngleSpy.count(), 1);
434 432 QCOMPARE(angleSpanSpy.count(), 4);
435 433
436 434 // modify pie angles
437 435 m_series->setPieStartAngle(-90);
438 436 m_series->setPieEndAngle(90);
439 437 verifyCalculatedData(*m_series, &ok);
440 438 if (!ok)
441 439 return;
442 440 QCOMPARE(percentageSpy.count(), 4);
443 441 QCOMPARE(startAngleSpy.count(), 3);
444 442 QCOMPARE(angleSpanSpy.count(), 6);
445 443
446 444 // clear all
447 445 m_series->clear();
448 446 verifyCalculatedData(*m_series, &ok);
449 447 if (!ok)
450 448 return;
451 449 QCOMPARE(percentageSpy.count(), 4);
452 450 QCOMPARE(startAngleSpy.count(), 3);
453 451 QCOMPARE(angleSpanSpy.count(), 6);
454 452 }
455 453
456 454 void tst_qpieseries::verifyCalculatedData(const QPieSeries &series, bool *ok)
457 455 {
458 456 *ok = false;
459 457
460 458 qreal sum = 0;
461 459 foreach (const QPieSlice *slice, series.slices())
462 460 sum += slice->value();
463 461 QCOMPARE(series.sum(), sum);
464 462
465 463 qreal startAngle = series.pieStartAngle();
466 464 qreal pieAngleSpan = series.pieEndAngle() - series.pieStartAngle();
467 465 foreach (const QPieSlice *slice, series.slices()) {
468 466 qreal ratio = slice->value() / sum;
469 467 qreal sliceSpan = pieAngleSpan * ratio;
470 468 QCOMPARE(slice->startAngle(), startAngle);
471 469 QCOMPARE(slice->angleSpan(), sliceSpan);
472 470 QCOMPARE(slice->percentage(), ratio);
473 471 startAngle += sliceSpan;
474 472 }
475 473
476 474 if (!series.isEmpty())
477 475 QCOMPARE(series.slices().last()->startAngle() + series.slices().last()->angleSpan(), series.pieEndAngle());
478 476
479 477 *ok = true;
480 478 }
481 479
482 480
483 481 void tst_qpieseries::clickedSignal()
484 482 {
485 483 // add some slices
486 484 QPieSlice *s1 = m_series->append("slice 1", 1);
487 485 QPieSlice *s2 = m_series->append("slice 2", 1);
488 486 QPieSlice *s3 = m_series->append("slice 3", 1);
489 487 QPieSlice *s4 = m_series->append("slice 4", 1);
490 488 QSignalSpy clickSpy(m_series, SIGNAL(clicked(QPieSlice*)));
491 489
492 490 // add series to the chart
493 491 m_view->chart()->legend()->setVisible(false);
494 492 m_view->resize(200, 200);
495 493 m_view->chart()->addSeries(m_series);
496 494 m_view->show();
497 495 QTest::qWaitForWindowShown(m_view);
498 496
499 497 // if you devide the chart in four equal tiles these
500 498 // are the center points of those tiles
501 499 QPoint p1(90.25, 90);
502 500 QPoint p2(150, 90);
503 501 QPoint p3(90, 150);
504 502 QPoint p4(150, 150);
505 503
506 504 QPoint center(120, 120);
507 505
508 506 m_series->setPieSize(1.0);
509 507 QTest::mouseClick(m_view->viewport(), Qt::LeftButton, 0, p1);
510 508 QTest::mouseClick(m_view->viewport(), Qt::LeftButton, 0, p2);
511 509 QTest::mouseClick(m_view->viewport(), Qt::LeftButton, 0, p3);
512 510 QTest::mouseClick(m_view->viewport(), Qt::LeftButton, 0, p4);
513 511 QTest::mouseClick(m_view->viewport(), Qt::LeftButton, 0, center);
514 512 TRY_COMPARE(clickSpy.count(), 5); // all hit
515 513 QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(0).at(0)), s4);
516 514 QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(1).at(0)), s1);
517 515 QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(2).at(0)), s3);
518 516 QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(3).at(0)), s2);
519 517 clickSpy.clear();
520 518
521 519 m_series->setPieSize(0.5);
522 520 m_series->setVerticalPosition(0.25);
523 521 m_series->setHorizontalPosition(0.25);
524 522 QTest::mouseClick(m_view->viewport(), Qt::LeftButton, 0, p1); // hits
525 523 QTest::mouseClick(m_view->viewport(), Qt::LeftButton, 0, p2);
526 524 QTest::mouseClick(m_view->viewport(), Qt::LeftButton, 0, p3);
527 525 QTest::mouseClick(m_view->viewport(), Qt::LeftButton, 0, p4);
528 526 QTest::mouseClick(m_view->viewport(), Qt::LeftButton, 0, center);
529 527 TRY_COMPARE(clickSpy.count(), 1);
530 528 clickSpy.clear();
531 529
532 530 m_series->setVerticalPosition(0.25);
533 531 m_series->setHorizontalPosition(0.75);
534 532 QTest::mouseClick(m_view->viewport(), Qt::LeftButton, 0, p1);
535 533 QTest::mouseClick(m_view->viewport(), Qt::LeftButton, 0, p2); // hits
536 534 QTest::mouseClick(m_view->viewport(), Qt::LeftButton, 0, p3);
537 535 QTest::mouseClick(m_view->viewport(), Qt::LeftButton, 0, p4);
538 536 QTest::mouseClick(m_view->viewport(), Qt::LeftButton, 0, center);
539 537 TRY_COMPARE(clickSpy.count(), 1);
540 538 clickSpy.clear();
541 539
542 540 m_series->setVerticalPosition(0.75);
543 541 m_series->setHorizontalPosition(0.25);
544 542 QTest::mouseClick(m_view->viewport(), Qt::LeftButton, 0, p1);
545 543 QTest::mouseClick(m_view->viewport(), Qt::LeftButton, 0, p2);
546 544 QTest::mouseClick(m_view->viewport(), Qt::LeftButton, 0, p3); // hits
547 545 QTest::mouseClick(m_view->viewport(), Qt::LeftButton, 0, p4);
548 546 QTest::mouseClick(m_view->viewport(), Qt::LeftButton, 0, center);
549 547 TRY_COMPARE(clickSpy.count(), 1);
550 548 clickSpy.clear();
551 549
552 550 m_series->setVerticalPosition(0.75);
553 551 m_series->setHorizontalPosition(0.75);
554 552 QTest::mouseClick(m_view->viewport(), Qt::LeftButton, 0, p1);
555 553 QTest::mouseClick(m_view->viewport(), Qt::LeftButton, 0, p2);
556 554 QTest::mouseClick(m_view->viewport(), Qt::LeftButton, 0, p3);
557 555 QTest::mouseClick(m_view->viewport(), Qt::LeftButton, 0, p4); // hits
558 556 QTest::mouseClick(m_view->viewport(), Qt::LeftButton, 0, center);
559 557 TRY_COMPARE(clickSpy.count(), 1);
560 558 clickSpy.clear();
561 559 }
562 560
563 561 void tst_qpieseries::hoverSignal()
564 562 {
565 563 // add some slices
566 564 m_series->setPieSize(1.0);
567 565 QPieSlice *s1 = m_series->append("slice 1", 1);
568 566 m_series->append("slice 2", 2);
569 567 m_series->append("slice 3", 3);
570 568
571 569 // add series to the chart
572 570 m_view->chart()->legend()->setVisible(false);
573 571 m_view->resize(200, 200);
574 572 m_view->chart()->addSeries(m_series);
575 573 m_view->show();
576 574 QTest::qWaitForWindowShown(m_view);
577 575
578 576 // first move to right top corner
579 577 QTest::mouseMove(m_view->viewport(), QPoint(200, 0));
580 578 QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
581 579
582 580 // move inside the slice
583 581 // pie rectangle: QRectF(60,60 121x121)
584 582 QSignalSpy hoverSpy(m_series, SIGNAL(hovered(QPieSlice*,bool)));
585 583 QTest::mouseMove(m_view->viewport(), QPoint(139, 85));
586 584 TRY_COMPARE(hoverSpy.count(), 1);
587 585 QCOMPARE(qvariant_cast<QPieSlice*>(hoverSpy.at(0).at(0)), s1);
588 586 QCOMPARE(qvariant_cast<bool>(hoverSpy.at(0).at(1)), true);
589 587
590 588 // move outside the slice
591 589 QTest::mouseMove(m_view->viewport(), QPoint(200, 0));
592 590 TRY_COMPARE(hoverSpy.count(), 2);
593 591 QCOMPARE(qvariant_cast<QPieSlice*>(hoverSpy.at(1).at(0)), s1);
594 592 QCOMPARE(qvariant_cast<bool>(hoverSpy.at(1).at(1)), false);
595 593 }
596 594
597 595 void tst_qpieseries::sliceSeries()
598 596 {
599 597 QPieSlice *slice = new QPieSlice();
600 598 QVERIFY(!slice->series());
601 599 delete slice;
602 600
603 601 slice = new QPieSlice(m_series);
604 602 QVERIFY(!slice->series());
605 603
606 604 m_series->append(slice);
607 605 QCOMPARE(slice->series(), m_series);
608 606
609 607 slice = new QPieSlice();
610 608 m_series->insert(0, slice);
611 609 QCOMPARE(slice->series(), m_series);
612 610
613 611 m_series->take(slice);
614 612 QCOMPARE(slice->series(), (QPieSeries*) 0);
615 613 }
616 614
617 615 void tst_qpieseries::destruction()
618 616 {
619 617 // add some slices
620 618 QPieSlice *slice1 = m_series->append("slice 1", 1);
621 619 QPieSlice *slice2 = m_series->append("slice 2", 2);
622 620 QPieSlice *slice3 = m_series->append("slice 3", 3);
623 621 QSignalSpy spy1(slice1, SIGNAL(destroyed()));
624 622 QSignalSpy spy2(slice2, SIGNAL(destroyed()));
625 623 QSignalSpy spy3(slice3, SIGNAL(destroyed()));
626 624
627 625 // destroy series
628 626 delete m_series;
629 627 m_series = 0;
630 628
631 629 // check that series has destroyed its slices
632 630 QCOMPARE(spy1.count(), 1);
633 631 QCOMPARE(spy2.count(), 1);
634 632 QCOMPARE(spy3.count(), 1);
635 633 }
636 634
637 635 QTEST_MAIN(tst_qpieseries)
638 636
639 637 #include "tst_qpieseries.moc"
640 638
General Comments 0
You need to be logged in to leave comments. Login now