##// END OF EJS Templates
Rename piepresenter -> piechartitem
Jani Honkonen -
r568:9b365faaa041
parent child
Show More
@@ -1,401 +1,401
1 1 #include "qchart.h"
2 2 #include "qchartaxis.h"
3 3 #include "chartpresenter_p.h"
4 4 #include "chartdataset_p.h"
5 5 #include "charttheme_p.h"
6 6 #include "chartanimator_p.h"
7 7 //series
8 8 #include "qbarseries.h"
9 9 #include "qstackedbarseries.h"
10 10 #include "qpercentbarseries.h"
11 11 #include "qlineseries.h"
12 12 #include "qareaseries.h"
13 13 #include "qpieseries.h"
14 14 #include "qscatterseries.h"
15 15 #include "qsplineseries.h"
16 16 //items
17 17 #include "axisitem_p.h"
18 18 #include "areachartitem_p.h"
19 19 #include "barpresenter_p.h"
20 20 #include "stackedbarpresenter_p.h"
21 21 #include "percentbarpresenter_p.h"
22 22 #include "linechartitem_p.h"
23 #include "piepresenter_p.h"
23 #include "piechartitem_p.h"
24 24 #include "scatterchartitem_p.h"
25 25 #include "splinechartitem_p.h"
26 26
27 27 QTCOMMERCIALCHART_BEGIN_NAMESPACE
28 28
29 29 ChartPresenter::ChartPresenter(QChart* chart,ChartDataSet* dataset):QObject(chart),
30 30 m_chart(chart),
31 31 m_animator(0),
32 32 m_dataset(dataset),
33 33 m_chartTheme(0),
34 34 m_zoomIndex(0),
35 35 m_marginSize(0),
36 36 m_rect(QRectF(QPoint(0,0),m_chart->size())),
37 37 m_options(QChart::NoAnimation)
38 38 {
39 39 createConnections();
40 40 setChartTheme(QChart::ChartThemeDefault);
41 41 }
42 42
43 43 ChartPresenter::~ChartPresenter()
44 44 {
45 45 delete m_chartTheme;
46 46 }
47 47
48 48 void ChartPresenter::createConnections()
49 49 {
50 50 QObject::connect(m_chart,SIGNAL(geometryChanged()),this,SLOT(handleGeometryChanged()));
51 51 QObject::connect(m_dataset,SIGNAL(seriesAdded(QSeries*,Domain*)),this,SLOT(handleSeriesAdded(QSeries*,Domain*)));
52 52 QObject::connect(m_dataset,SIGNAL(seriesRemoved(QSeries*)),this,SLOT(handleSeriesRemoved(QSeries*)));
53 53 QObject::connect(m_dataset,SIGNAL(axisAdded(QChartAxis*,Domain*)),this,SLOT(handleAxisAdded(QChartAxis*,Domain*)));
54 54 QObject::connect(m_dataset,SIGNAL(axisRemoved(QChartAxis*)),this,SLOT(handleAxisRemoved(QChartAxis*)));
55 55 }
56 56
57 57
58 58 QRectF ChartPresenter::geometry() const
59 59 {
60 60 return m_rect;
61 61 }
62 62
63 63 void ChartPresenter::handleGeometryChanged()
64 64 {
65 65 QRectF rect(QPoint(0,0),m_chart->size());
66 66 rect.adjust(m_marginSize,m_marginSize, -m_marginSize, -m_marginSize);
67 67
68 68 //rewrite zoom stack
69 69 for(int i=0;i<m_zoomStack.count();i++){
70 70 QRectF r = m_zoomStack[i];
71 71 qreal w = rect.width()/m_rect.width();
72 72 qreal h = rect.height()/m_rect.height();
73 73 QPointF tl = r.topLeft();
74 74 tl.setX(tl.x()*w);
75 75 tl.setY(tl.y()*h);
76 76 QPointF br = r.bottomRight();
77 77 br.setX(br.x()*w);
78 78 br.setY(br.y()*h);
79 79 r.setTopLeft(tl);
80 80 r.setBottomRight(br);
81 81 m_zoomStack[i]=r;
82 82 }
83 83
84 84 m_rect = rect;
85 85 Q_ASSERT(m_rect.isValid());
86 86 emit geometryChanged(m_rect);
87 87 }
88 88
89 89 int ChartPresenter::margin() const
90 90 {
91 91 return m_marginSize;
92 92 }
93 93
94 94 void ChartPresenter::setMargin(int margin)
95 95 {
96 96 m_marginSize = margin;
97 97 }
98 98
99 99 void ChartPresenter::handleAxisAdded(QChartAxis* axis,Domain* domain)
100 100 {
101 101 AxisItem* item = new AxisItem(axis,this,axis==m_dataset->axisX()?AxisItem::X_AXIS : AxisItem::Y_AXIS,m_chart);
102 102
103 103 if(m_options.testFlag(QChart::GridAxisAnimations)){
104 104 m_animator->addAnimation(item);
105 105 }
106 106
107 107 if(axis==m_dataset->axisX()){
108 108 m_chartTheme->decorate(axis,true);
109 109 QObject::connect(domain,SIGNAL(rangeXChanged(qreal,qreal,int)),item,SLOT(handleRangeChanged(qreal,qreal,int)));
110 110 //initialize
111 111 item->handleRangeChanged(domain->minX(),domain->maxX(),domain->tickXCount());
112 112
113 113 }
114 114 else{
115 115 m_chartTheme->decorate(axis,false);
116 116 QObject::connect(domain,SIGNAL(rangeYChanged(qreal,qreal,int)),item,SLOT(handleRangeChanged(qreal,qreal,int)));
117 117 //initialize
118 118 item->handleRangeChanged(domain->minY(),domain->maxY(),domain->tickYCount());
119 119 }
120 120
121 121 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),item,SLOT(handleGeometryChanged(const QRectF&)));
122 122 //initialize
123 123 item->handleGeometryChanged(m_rect);
124 124 m_axisItems.insert(axis, item);
125 125 }
126 126
127 127 void ChartPresenter::handleAxisRemoved(QChartAxis* axis)
128 128 {
129 129 AxisItem* item = m_axisItems.take(axis);
130 130 Q_ASSERT(item);
131 131 if(m_animator) m_animator->removeAnimation(item);
132 132 delete item;
133 133 }
134 134
135 135
136 136 void ChartPresenter::handleSeriesAdded(QSeries* series,Domain* domain)
137 137 {
138 138 ChartItem *item = 0 ;
139 139
140 140 switch(series->type())
141 141 {
142 142 case QSeries::SeriesTypeLine: {
143 143
144 144 QLineSeries* lineSeries = static_cast<QLineSeries*>(series);
145 145 LineChartItem* line = new LineChartItem(lineSeries,m_chart);
146 146 if(m_options.testFlag(QChart::SeriesAnimations)) {
147 147 m_animator->addAnimation(line);
148 148 }
149 149 m_chartTheme->decorate(lineSeries, m_dataset->seriesIndex(series));
150 150 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),line,SLOT(handleGeometryChanged(const QRectF&)));
151 151 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),line,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
152 152 item = line;
153 153 break;
154 154 }
155 155
156 156 case QSeries::SeriesTypeArea: {
157 157
158 158 QAreaSeries* areaSeries = static_cast<QAreaSeries*>(series);
159 159 AreaChartItem* area = new AreaChartItem(areaSeries,m_chart);
160 160 if(m_options.testFlag(QChart::SeriesAnimations)) {
161 161 m_animator->addAnimation(area->upperLineItem());
162 162 if(areaSeries->lowerSeries()) m_animator->addAnimation(area->lowerLineItem());
163 163 }
164 164 m_chartTheme->decorate(areaSeries, m_dataset->seriesIndex(series));
165 165 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),area,SLOT(handleGeometryChanged(const QRectF&)));
166 166 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),area,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
167 167 item=area;
168 168 break;
169 169 }
170 170
171 171 case QSeries::SeriesTypeBar: {
172 172 QBarSeries* barSeries = static_cast<QBarSeries*>(series);
173 173 BarPresenter* bar = new BarPresenter(barSeries,m_chart);
174 174 if(m_options.testFlag(QChart::SeriesAnimations)) {
175 175 // m_animator->addAnimation(bar);
176 176 }
177 177 m_chartTheme->decorate(bar, barSeries, m_dataset->seriesIndex(barSeries));
178 178 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),bar,SLOT(handleGeometryChanged(const QRectF&)));
179 179 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),bar,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
180 180 item=bar;
181 181 break;
182 182 }
183 183
184 184 case QSeries::SeriesTypeStackedBar: {
185 185 QStackedBarSeries* stackedBarSeries = static_cast<QStackedBarSeries*>(series);
186 186 StackedBarPresenter* bar = new StackedBarPresenter(stackedBarSeries,m_chart);
187 187 if(m_options.testFlag(QChart::SeriesAnimations)) {
188 188 // m_animator->addAnimation(bar);
189 189 }
190 190 m_chartTheme->decorate(bar, stackedBarSeries, m_dataset->seriesIndex(stackedBarSeries));
191 191 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),bar,SLOT(handleGeometryChanged(const QRectF&)));
192 192 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),bar,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
193 193 item=bar;
194 194 break;
195 195 }
196 196
197 197 case QSeries::SeriesTypePercentBar: {
198 198 QPercentBarSeries* percentBarSeries = static_cast<QPercentBarSeries*>(series);
199 199 PercentBarPresenter* bar = new PercentBarPresenter(percentBarSeries,m_chart);
200 200 if(m_options.testFlag(QChart::SeriesAnimations)) {
201 201 // m_animator->addAnimation(bar);
202 202 }
203 203 m_chartTheme->decorate(bar, percentBarSeries, m_dataset->seriesIndex(percentBarSeries));
204 204 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),bar,SLOT(handleGeometryChanged(const QRectF&)));
205 205 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),bar,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
206 206 item=bar;
207 207 break;
208 208 }
209 209
210 210 case QSeries::SeriesTypeScatter: {
211 211 QScatterSeries *scatterSeries = static_cast<QScatterSeries *>(series);
212 212 ScatterChartItem *scatter = new ScatterChartItem(scatterSeries, m_chart);
213 213 if(m_options.testFlag(QChart::SeriesAnimations)) {
214 214 m_animator->addAnimation(scatter);
215 215 }
216 216 m_chartTheme->decorate(scatterSeries, m_dataset->seriesIndex(series));
217 217 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),scatter,SLOT(handleGeometryChanged(const QRectF&)));
218 218 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),scatter,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
219 219 item = scatter;
220 220 break;
221 221 }
222 222
223 223 case QSeries::SeriesTypePie: {
224 224 QPieSeries *pieSeries = static_cast<QPieSeries *>(series);
225 PiePresenter* pie = new PiePresenter(m_chart, pieSeries);
225 PieChartItem* pie = new PieChartItem(m_chart, pieSeries);
226 226 if(m_options.testFlag(QChart::SeriesAnimations)) {
227 227 // m_animator->addAnimation(pie);
228 228 }
229 229 m_chartTheme->decorate(pie, pieSeries, m_dataset->seriesIndex(series));
230 230 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),pie,SLOT(handleGeometryChanged(const QRectF&)));
231 231 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),pie,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
232 232 // Hide all from background when there is only piechart
233 233 // TODO: refactor this ugly code... should be one setting for this
234 234 if (m_chartItems.count() == 0) {
235 235 m_chart->axisX()->hide();
236 236 m_chart->axisY()->hide();
237 237 m_chart->setChartBackgroundBrush(Qt::transparent);
238 238 }
239 239 item=pie;
240 240 break;
241 241 }
242 242
243 243 case QSeries::SeriesTypeSpline: {
244 244 QSplineSeries* splineSeries = static_cast<QSplineSeries*>(series);
245 245 SplineChartItem* spline = new SplineChartItem(splineSeries, m_chart);
246 246 if(m_options.testFlag(QChart::SeriesAnimations)) {
247 247 m_animator->addAnimation(spline);
248 248 }
249 249 m_chartTheme->decorate(splineSeries, m_dataset->seriesIndex(series));
250 250 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),spline,SLOT(handleGeometryChanged(const QRectF&)));
251 251 QObject::connect(domain,SIGNAL(domainChanged(qreal,qreal,qreal,qreal)),spline,SLOT(handleDomainChanged(qreal,qreal,qreal,qreal)));
252 252 item=spline;
253 253 break;
254 254 }
255 255 default: {
256 256 qDebug()<< "Series type" << series->type() << "not implemented.";
257 257 break;
258 258 }
259 259 }
260 260
261 261 //initialize
262 262 item->handleDomainChanged(domain->minX(),domain->maxX(),domain->minY(),domain->maxY());
263 263 if(m_rect.isValid()) item->handleGeometryChanged(m_rect);
264 264 m_chartItems.insert(series,item);
265 265 zoomReset();
266 266 }
267 267
268 268 void ChartPresenter::handleSeriesRemoved(QSeries* series)
269 269 {
270 270 ChartItem* item = m_chartItems.take(series);
271 271 Q_ASSERT(item);
272 272 if(m_animator) {
273 273 //small hack to handle area animations
274 274 if(series->type()==QSeries::SeriesTypeArea){
275 275 QAreaSeries* areaSeries = static_cast<QAreaSeries*>(series);
276 276 AreaChartItem* area = static_cast<AreaChartItem*>(item);
277 277 m_animator->removeAnimation(area->upperLineItem());
278 278 if(areaSeries->lowerSeries()) m_animator->addAnimation(area->lowerLineItem());
279 279 }else
280 280 m_animator->removeAnimation(item);
281 281 }
282 282 delete item;
283 283 }
284 284
285 285 void ChartPresenter::setChartTheme(QChart::ChartTheme theme)
286 286 {
287 287 if(m_chartTheme && m_chartTheme->id() == theme) return;
288 288 delete m_chartTheme;
289 289 m_chartTheme = ChartTheme::createTheme(theme);
290 290 m_chartTheme->decorate(m_chart);
291 291 m_chartTheme->decorate(m_chart->legend());
292 292 resetAllElements();
293 293 }
294 294
295 295 QChart::ChartTheme ChartPresenter::chartTheme()
296 296 {
297 297 return m_chartTheme->id();
298 298 }
299 299
300 300 void ChartPresenter::setAnimationOptions(QChart::AnimationOptions options)
301 301 {
302 302 if(m_options!=options) {
303 303
304 304 m_options=options;
305 305
306 306 if(m_options!=QChart::NoAnimation && !m_animator) {
307 307 m_animator= new ChartAnimator(this);
308 308
309 309 }
310 310 resetAllElements();
311 311 }
312 312
313 313 }
314 314
315 315 void ChartPresenter::resetAllElements()
316 316 {
317 317 QList<QChartAxis*> axisList = m_axisItems.uniqueKeys();
318 318 QList<QSeries*> seriesList = m_chartItems.uniqueKeys();
319 319
320 320 foreach(QChartAxis* axis, axisList) {
321 321 handleAxisRemoved(axis);
322 322 handleAxisAdded(axis,m_dataset->domain(axis));
323 323 }
324 324 foreach(QSeries* series, seriesList) {
325 325 handleSeriesRemoved(series);
326 326 handleSeriesAdded(series,m_dataset->domain(series));
327 327 }
328 328 }
329 329
330 330 void ChartPresenter::zoomIn()
331 331 {
332 332 QRectF rect = geometry();
333 333 rect.setWidth(rect.width()/2);
334 334 rect.setHeight(rect.height()/2);
335 335 rect.moveCenter(geometry().center());
336 336 zoomIn(rect);
337 337 }
338 338
339 339 void ChartPresenter::zoomIn(const QRectF& rect)
340 340 {
341 341 QRectF r = rect.normalized();
342 342 r.translate(-m_marginSize, -m_marginSize);
343 343 if(m_animator) {
344 344
345 345 QPointF point(r.center().x()/geometry().width(),r.center().y()/geometry().height());
346 346 m_animator->setState(ChartAnimator::ZoomInState,point);
347 347 }
348 348 m_dataset->zoomInDomain(r,geometry().size());
349 349 m_zoomStack<<r;
350 350 m_zoomIndex++;
351 351 if(m_animator) {
352 352 m_animator->setState(ChartAnimator::ShowState);
353 353 }
354 354 }
355 355
356 356 void ChartPresenter::zoomOut()
357 357 {
358 358 if(m_zoomIndex==0) return;
359 359 if(m_animator)
360 360 {
361 361 m_animator->setState(ChartAnimator::ZoomOutState);
362 362 }
363 363 m_dataset->zoomOutDomain(m_zoomStack[m_zoomIndex-1],geometry().size());
364 364 m_zoomIndex--;
365 365 m_zoomStack.resize(m_zoomIndex);
366 366 if(m_animator){
367 367 m_animator->setState(ChartAnimator::ShowState);
368 368 }
369 369 }
370 370
371 371 void ChartPresenter::zoomReset()
372 372 {
373 373 m_zoomIndex=0;
374 374 m_zoomStack.resize(m_zoomIndex);
375 375 }
376 376
377 377 void ChartPresenter::scroll(int dx,int dy)
378 378 {
379 379 if(m_animator){
380 380 if(dx<0) m_animator->setState(ChartAnimator::ScrollLeftState,QPointF());
381 381 if(dx>0) m_animator->setState(ChartAnimator::ScrollRightState,QPointF());
382 382 if(dy<0) m_animator->setState(ChartAnimator::ScrollUpState,QPointF());
383 383 if(dy>0) m_animator->setState(ChartAnimator::ScrollDownState,QPointF());
384 384 }
385 385
386 386 m_dataset->scrollDomain(dx,dy,geometry().size());
387 387
388 388 if(m_animator){
389 389 m_animator->setState(ChartAnimator::ShowState);
390 390 }
391 391 }
392 392
393 393 QChart::AnimationOptions ChartPresenter::animationOptions() const
394 394 {
395 395 return m_options;
396 396 }
397 397
398 398
399 399 #include "moc_chartpresenter_p.cpp"
400 400
401 401 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,305 +1,305
1 1 #include "charttheme_p.h"
2 2 #include "qchart.h"
3 3 #include "qlegend.h"
4 4 #include "qchartaxis.h"
5 5 #include <QTime>
6 6
7 7 //series
8 8 #include "qbarset.h"
9 9 #include "qbarseries.h"
10 10 #include "qstackedbarseries.h"
11 11 #include "qpercentbarseries.h"
12 12 #include "qlineseries.h"
13 13 #include "qareaseries.h"
14 14 #include "qscatterseries.h"
15 15 #include "qpieseries.h"
16 16 #include "qpieslice.h"
17 17 #include "qsplineseries.h"
18 18
19 19 //items
20 20 #include "axisitem_p.h"
21 21 #include "barpresenter_p.h"
22 22 #include "stackedbarpresenter_p.h"
23 23 #include "percentbarpresenter_p.h"
24 24 #include "linechartitem_p.h"
25 25 #include "areachartitem_p.h"
26 26 #include "scatterchartitem_p.h"
27 #include "piepresenter_p.h"
27 #include "piechartitem_p.h"
28 28 #include "splinechartitem_p.h"
29 29
30 30 //themes
31 31 #include "chartthemedefault_p.h"
32 32 #include "chartthemevanilla_p.h"
33 33 #include "chartthemeicy_p.h"
34 34 #include "chartthemegrayscale_p.h"
35 35 #include "chartthemescientific_p.h"
36 36
37 37
38 38 QTCOMMERCIALCHART_BEGIN_NAMESPACE
39 39
40 40 ChartTheme::ChartTheme(QChart::ChartTheme id)
41 41 {
42 42 m_id = id;
43 43 qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
44 44 }
45 45
46 46
47 47 ChartTheme* ChartTheme::createTheme(QChart::ChartTheme theme)
48 48 {
49 49 switch(theme) {
50 50 case QChart::ChartThemeVanilla:
51 51 return new ChartThemeVanilla();
52 52 case QChart::ChartThemeIcy:
53 53 return new ChartThemeIcy();
54 54 case QChart::ChartThemeGrayscale:
55 55 return new ChartThemeGrayscale();
56 56 case QChart::ChartThemeScientific:
57 57 return new ChartThemeScientific();
58 58 default:
59 59 return new ChartThemeDefault();
60 60 }
61 61 }
62 62
63 63 void ChartTheme::decorate(QChart* chart)
64 64 {
65 65 chart->setChartBackgroundBrush(m_backgroundGradient);
66 66 chart->setChartTitleFont(m_masterFont);
67 67 }
68 68
69 69 void ChartTheme::decorate(QLegend* legend)
70 70 {
71 71 legend->setBackgroundBrush(m_backgroundGradient);
72 72 }
73 73
74 74 void ChartTheme::decorate(QAreaSeries* series, int index)
75 75 {
76 76 QPen pen;
77 77 QBrush brush;
78 78
79 79 if (pen == series->pen()){
80 80 pen.setColor(colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 1.0));
81 81 pen.setWidthF(2);
82 82 series->setPen(pen);
83 83 }
84 84
85 85 if (brush == series->brush()) {
86 86 QBrush brush(m_seriesColors.at(index % m_seriesColors.size()));
87 87 series->setBrush(brush);
88 88 }
89 89 }
90 90
91 91
92 92 void ChartTheme::decorate(QLineSeries* series,int index)
93 93 {
94 94 QPen pen;
95 95 if(pen == series->pen()){
96 96 pen.setColor(m_seriesColors.at(index%m_seriesColors.size()));
97 97 pen.setWidthF(2);
98 98 series->setPen(pen);
99 99 }
100 100 }
101 101
102 102 void ChartTheme::decorate(BarPresenter* item, QBarSeries* series,int index)
103 103 {
104 104 QList<QBarSet*> sets = series->barSets();
105 105 for (int i=0; i<sets.count(); i++) {
106 106 qreal pos = 0.5;
107 107 if (sets.count() > 1)
108 108 pos = (qreal) i / (qreal) (sets.count() - 1);
109 109 QColor c = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), pos);
110 110 sets.at(i)->setBrush(QBrush(c));
111 111
112 112 // Pick label color as far as possible from bar color (within gradient).
113 113 // 0.3 is magic number that was picked as value that gave enough contrast with icy theme gradient :)
114 114 // TODO: better picking of label color?
115 115 if (pos < 0.3) {
116 116 c = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 1);
117 117 } else {
118 118 c = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 0);
119 119 }
120 120 sets.at(i)->setFloatingValuePen(QPen(c));
121 121 }
122 122 }
123 123
124 124 void ChartTheme::decorate(StackedBarPresenter* item, QStackedBarSeries* series,int index)
125 125 {
126 126 QList<QBarSet*> sets = series->barSets();
127 127 for (int i=0; i<sets.count(); i++) {
128 128 qreal pos = 0.5;
129 129 if (sets.count() > 1)
130 130 pos = (qreal) i / (qreal) (sets.count() - 1);
131 131 QColor c = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), pos);
132 132 sets.at(i)->setBrush(QBrush(c));
133 133
134 134 if (pos < 0.3) {
135 135 c = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 1);
136 136 } else {
137 137 c = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 0);
138 138 }
139 139 sets.at(i)->setFloatingValuePen(QPen(c));
140 140 }
141 141 }
142 142
143 143 void ChartTheme::decorate(PercentBarPresenter* item, QPercentBarSeries* series,int index)
144 144 {
145 145 QList<QBarSet*> sets = series->barSets();
146 146 for (int i=0; i<sets.count(); i++) {
147 147 qreal pos = 0.5;
148 148 if (sets.count() > 1)
149 149 pos = (qreal) i / (qreal) (sets.count() - 1);
150 150 QColor c = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), pos);
151 151 sets.at(i)->setBrush(QBrush(c));
152 152
153 153 if (pos < 0.3) {
154 154 c = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 1);
155 155 } else {
156 156 c = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 0);
157 157 }
158 158 sets.at(i)->setFloatingValuePen(QPen(c));
159 159 }
160 160 }
161 161
162 162 void ChartTheme::decorate(QScatterSeries* series, int index)
163 163 {
164 164
165 165 QPen pen;
166 166 QBrush brush;
167 167
168 168 if (pen == series->pen()) {
169 169 pen.setColor(colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 1.0));
170 170 pen.setWidthF(2);
171 171 series->setPen(pen);
172 172 }
173 173
174 174 if (brush == series->brush()) {
175 175 QBrush brush(m_seriesColors.at(index % m_seriesColors.size()));
176 176 series->setBrush(brush);
177 177 }
178 178 }
179 179
180 void ChartTheme::decorate(PiePresenter* item, QPieSeries* series, int index)
180 void ChartTheme::decorate(PieChartItem* item, QPieSeries* series, int index)
181 181 {
182 182 // Get color for a slice from a gradient linearly, beginning from the start of the gradient
183 183 for (int i(0); i < series->slices().count(); i++) {
184 184 qreal pos = (qreal) i / (qreal) series->count();
185 185 QColor penColor = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 0.1);
186 186 series->slices().at(i)->setSlicePen(penColor);
187 187 QColor brushColor = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), pos);
188 188 series->slices().at(i)->setSliceBrush(brushColor);
189 189 }
190 190 }
191 191
192 192 void ChartTheme::decorate(QSplineSeries* series, int index)
193 193 {
194 194 QPen pen;
195 195
196 196 if(pen == series->pen()){
197 197 pen.setColor(m_seriesColors.at(index%m_seriesColors.size()));
198 198 pen.setWidthF(2);
199 199 series->setPen(pen);
200 200 }
201 201 }
202 202
203 203 void ChartTheme::decorate(QChartAxis* axis,bool axisX)
204 204 {
205 205 if (axis->isAxisVisible()) {
206 206 axis->setLabelsBrush(m_axisLabelBrush);
207 207 axis->setLabelsPen(m_axisLabelPen);
208 208 // TODO: check the axis type (x or y) should define whether to show the shades or not
209 209 if (m_backgroundShades == BackgroundShadesBoth
210 210 || (m_backgroundShades == BackgroundShadesVertical && axisX)
211 211 || (m_backgroundShades == BackgroundShadesHorizontal && !axisX)) {
212 212 axis->setShadesPen(m_backgroundShadesPen);
213 213 axis->setShadesBrush(m_backgroundShadesBrush);
214 214 } else {
215 215 // The shades not supposed to be shown for this axis, clear possible brush and pen
216 216 axis->setShadesPen(Qt::NoPen);
217 217 axis->setShadesBrush(Qt::NoBrush);
218 218 }
219 219 axis->setAxisPen(m_axisLinePen);
220 220 axis->setGridLinePen(m_gridLinePen);
221 221 axis->setLabelsFont(m_masterFont);
222 222 }
223 223 }
224 224
225 225 void ChartTheme::generateSeriesGradients()
226 226 {
227 227 // Generate gradients in HSV color space
228 228 foreach (QColor color, m_seriesColors) {
229 229 QLinearGradient g;
230 230 qreal h = color.hsvHueF();
231 231 qreal s = color.hsvSaturationF();
232 232
233 233 // TODO: tune the algorithm to give nice results with most base colors defined in
234 234 // most themes. The rest of the gradients we can define manually in theme specific
235 235 // implementation.
236 236 QColor start = color;
237 237 start.setHsvF(h, 0.05, 0.95);
238 238 g.setColorAt(0.0, start);
239 239
240 240 g.setColorAt(0.5, color);
241 241
242 242 QColor end = color;
243 243 end.setHsvF(h, s, 0.25);
244 244 g.setColorAt(1.0, end);
245 245
246 246 m_seriesGradients << g;
247 247 }
248 248 }
249 249
250 250
251 251 QColor ChartTheme::colorAt(const QColor &start, const QColor &end, qreal pos)
252 252 {
253 253 Q_ASSERT(pos >=0.0 && pos <= 1.0);
254 254 qreal r = start.redF() + ((end.redF() - start.redF()) * pos);
255 255 qreal g = start.greenF() + ((end.greenF() - start.greenF()) * pos);
256 256 qreal b = start.blueF() + ((end.blueF() - start.blueF()) * pos);
257 257 QColor c;
258 258 c.setRgbF(r, g, b);
259 259 return c;
260 260 }
261 261
262 262 QColor ChartTheme::colorAt(const QGradient &gradient, qreal pos)
263 263 {
264 264 Q_ASSERT(pos >=0 && pos <= 1.0);
265 265
266 266 // another possibility:
267 267 // http://stackoverflow.com/questions/3306786/get-intermediate-color-from-a-gradient
268 268
269 269 QGradientStops stops = gradient.stops();
270 270 int count = stops.count();
271 271
272 272 // find previous stop relative to position
273 273 QGradientStop prev = stops.first();
274 274 for (int i=0; i<count; i++) {
275 275 QGradientStop stop = stops.at(i);
276 276 if (pos > stop.first)
277 277 prev = stop;
278 278
279 279 // given position is actually a stop position?
280 280 if (pos == stop.first) {
281 281 //qDebug() << "stop color" << pos;
282 282 return stop.second;
283 283 }
284 284 }
285 285
286 286 // find next stop relative to position
287 287 QGradientStop next = stops.last();
288 288 for (int i=count-1; i>=0; i--) {
289 289 QGradientStop stop = stops.at(i);
290 290 if (pos < stop.first)
291 291 next = stop;
292 292 }
293 293
294 294 //qDebug() << "prev" << prev.first << "pos" << pos << "next" << next.first;
295 295
296 296 qreal range = next.first - prev.first;
297 297 qreal posDelta = pos - prev.first;
298 298 qreal relativePos = posDelta / range;
299 299
300 300 //qDebug() << "range" << range << "posDelta" << posDelta << "relativePos" << relativePos;
301 301
302 302 return colorAt(prev.second, next.second, relativePos);
303 303 }
304 304
305 305 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,81 +1,81
1 1 #ifndef CHARTTHEME_H
2 2 #define CHARTTHEME_H
3 3
4 4 #include "qchartglobal.h"
5 5 #include "qchart.h"
6 6 #include <QColor>
7 7 #include <QGradientStops>
8 8
9 9 QTCOMMERCIALCHART_BEGIN_NAMESPACE
10 10
11 11 class ChartItem;
12 12 class QSeries;
13 13 class LineChartItem;
14 14 class QLineSeries;
15 15 class BarPresenter;
16 16 class QBarSeries;
17 17 class StackedBarPresenter;
18 18 class QStackedBarSeries;
19 19 class QPercentBarSeries;
20 20 class PercentBarPresenter;
21 21 class QScatterSeries;
22 22 class ScatterChartItem;
23 class PiePresenter;
23 class PieChartItem;
24 24 class QPieSeries;
25 25 class SplineChartItem;
26 26 class QSplineSeries;
27 27 class AreaChartItem;
28 28 class QAreaSeries;
29 29
30 30 class ChartTheme
31 31 {
32 32 public:
33 33 enum BackgroundShadesMode {
34 34 BackgroundShadesNone = 0,
35 35 BackgroundShadesVertical,
36 36 BackgroundShadesHorizontal,
37 37 BackgroundShadesBoth
38 38 };
39 39
40 40 protected:
41 41 explicit ChartTheme(QChart::ChartTheme id = QChart::ChartThemeDefault);
42 42 public:
43 43 static ChartTheme* createTheme(QChart::ChartTheme theme);
44 44 QChart::ChartTheme id() const {return m_id;}
45 45 void decorate(QChart* chart);
46 46 void decorate(QLegend* legend);
47 47 //void decorate(ChartItem* item, QSeries* series,int index);
48 48 void decorate(BarPresenter* item, QBarSeries* series, int index);
49 49 void decorate(StackedBarPresenter* item, QStackedBarSeries* series, int index);
50 50 void decorate(PercentBarPresenter* item, QPercentBarSeries* series, int index);
51 51 void decorate(QLineSeries* series, int index);
52 52 void decorate(QAreaSeries* series, int index);
53 53 void decorate(QScatterSeries* series, int index);
54 void decorate(PiePresenter* item, QPieSeries* series, int index);
54 void decorate(PieChartItem* item, QPieSeries* series, int index);
55 55 void decorate(QSplineSeries* series, int index);
56 56 void decorate(QChartAxis* axis, bool axisX);
57 57
58 58 public: // utils
59 59 void generateSeriesGradients();
60 60 static QColor colorAt(const QColor &start, const QColor &end, qreal pos);
61 61 static QColor colorAt(const QGradient &gradient, qreal pos);
62 62
63 63 protected:
64 64 QChart::ChartTheme m_id;
65 65 QList<QColor> m_seriesColors;
66 66 QList<QGradient> m_seriesGradients;
67 67 QLinearGradient m_backgroundGradient;
68 68
69 69 QFont m_masterFont;
70 70 QPen m_axisLinePen;
71 71 QBrush m_axisLabelBrush;
72 72 QPen m_axisLabelPen;
73 73 QPen m_backgroundShadesPen;
74 74 QBrush m_backgroundShadesBrush;
75 75 BackgroundShadesMode m_backgroundShades;
76 76 QPen m_gridLinePen;
77 77 };
78 78
79 79 QTCOMMERCIALCHART_END_NAMESPACE
80 80
81 81 #endif // CHARTTHEME_H
@@ -1,16 +1,16
1 1 INCLUDEPATH += $$PWD
2 2 DEPENDPATH += $$PWD
3 3
4 4 SOURCES += \
5 5 $$PWD/qpieseries.cpp \
6 6 $$PWD/pieslice.cpp \
7 $$PWD/piepresenter.cpp \
7 $$PWD/piechartitem.cpp \
8 8 $$PWD/qpieslice.cpp
9 9
10 10 PRIVATE_HEADERS += \
11 $$PWD/piepresenter_p.h \
11 $$PWD/piechartitem_p.h \
12 12 $$PWD/pieslice_p.h \
13 13
14 14 PUBLIC_HEADERS += \
15 15 $$PWD/qpieseries.h \
16 16 $$PWD/qpieslice.h
@@ -1,143 +1,143
1 #include "piepresenter_p.h"
1 #include "piechartitem_p.h"
2 2 #include "pieslice_p.h"
3 3 #include "qpieslice.h"
4 4 #include "qpieseries.h"
5 5 #include "chartpresenter_p.h"
6 6 #include <QDebug>
7 7 #include <QPainter>
8 8
9 9
10 10 QTCOMMERCIALCHART_BEGIN_NAMESPACE
11 11
12 PiePresenter::PiePresenter(QGraphicsItem *parent, QPieSeries *series)
12 PieChartItem::PieChartItem(QGraphicsItem *parent, QPieSeries *series)
13 13 :ChartItem(parent),
14 14 m_series(series)
15 15 {
16 16 Q_ASSERT(series);
17 17 connect(series, SIGNAL(changed()), this, SLOT(handleSeriesChanged()));
18 18
19 19 // Note: the following does not affect as long as the item does not have anything to paint
20 20 setZValue(ChartPresenter::PieSeriesZValue);
21 21 }
22 22
23 PiePresenter::~PiePresenter()
23 PieChartItem::~PieChartItem()
24 24 {
25 25 // slices deleted automatically through QGraphicsItem
26 26 }
27 27
28 void PiePresenter::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
28 void PieChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
29 29 {
30 30 // TODO: paint shadows for all components
31 31 // - get paths from items & merge & offset and draw with shadow color?
32 32 //painter->setBrush(QBrush(Qt::red));
33 33 //painter->drawRect(m_debugRect);
34 34 }
35 35
36 void PiePresenter::handleSeriesChanged()
36 void PieChartItem::handleSeriesChanged()
37 37 {
38 38 QVector<PieSliceLayout> sliceLayout = calculateLayout();
39 39 applyLayout(sliceLayout);
40 40 update();
41 41 }
42 42
43 void PiePresenter::handleSliceChanged()
43 void PieChartItem::handleSliceChanged()
44 44 {
45 45 // TODO: optimize don't need to handle all slices
46 46 QVector<PieSliceLayout> sliceLayout = calculateLayout();
47 47 applyLayout(sliceLayout);
48 48 update();
49 49 }
50 50
51 void PiePresenter::handleDomainChanged(qreal, qreal, qreal, qreal)
51 void PieChartItem::handleDomainChanged(qreal, qreal, qreal, qreal)
52 52 {
53 53 // TODO
54 54 }
55 55
56 void PiePresenter::handleGeometryChanged(const QRectF& rect)
56 void PieChartItem::handleGeometryChanged(const QRectF& rect)
57 57 {
58 58 prepareGeometryChange();
59 59 m_rect = rect;
60 60 QVector<PieSliceLayout> sliceLayout = calculateLayout();
61 61 applyLayout(sliceLayout);
62 62 update();
63 63 }
64 64
65 65
66 QVector<PieSliceLayout> PiePresenter::calculateLayout()
66 QVector<PieSliceLayout> PieChartItem::calculateLayout()
67 67 {
68 68 // find pie center coordinates
69 69 QPointF center;
70 70 center.setX(m_rect.left() + (m_rect.width() * m_series->pieHorizontalPosition()));
71 71 center.setY(m_rect.top() + (m_rect.height() * m_series->pieVerticalPosition()));
72 72
73 73 // find maximum radius for pie
74 74 qreal radius = m_rect.height() / 2;
75 75 if (m_rect.width() < m_rect.height())
76 76 radius = m_rect.width() / 2;
77 77
78 78 // apply size factor
79 79 radius *= m_series->pieSize();
80 80
81 81 QVector<PieSliceLayout> layout;
82 82 foreach (QPieSlice* s, m_series->slices()) {
83 83 PieSliceLayout sliceLayout;
84 84 sliceLayout.m_data = s;
85 85 sliceLayout.m_center = PieSlice::sliceCenter(center, radius, s);
86 86 sliceLayout.m_radius = radius;
87 87 sliceLayout.m_startAngle = s->startAngle();
88 88 sliceLayout.m_angleSpan = s->m_angleSpan;
89 89 layout << sliceLayout;
90 90 }
91 91
92 92 return layout;
93 93 }
94 94
95 void PiePresenter::applyLayout(const QVector<PieSliceLayout> &layout)
95 void PieChartItem::applyLayout(const QVector<PieSliceLayout> &layout)
96 96 {
97 97 //if(m_animator)
98 98 // m_animator->applyLayout(this,points);
99 99 //else
100 100 setLayout(layout);
101 101 }
102 102
103 void PiePresenter::setLayout(const QVector<PieSliceLayout> &layout)
103 void PieChartItem::setLayout(const QVector<PieSliceLayout> &layout)
104 104 {
105 105 foreach (PieSliceLayout l, layout) {
106 106
107 107 // find slice
108 108 PieSlice *slice = m_slices.value(l.m_data);
109 109 if (!slice) {
110 110 // add a new slice
111 111 slice = new PieSlice(this);
112 112 m_slices.insert(l.m_data, slice);
113 113
114 114 // connect signals
115 115 connect(l.m_data, SIGNAL(changed()), this, SLOT(handleSliceChanged()));
116 116 connect(slice, SIGNAL(clicked()), l.m_data, SIGNAL(clicked()));
117 117 connect(slice, SIGNAL(hoverEnter()), l.m_data, SIGNAL(hoverEnter()));
118 118 connect(slice, SIGNAL(hoverLeave()), l.m_data, SIGNAL(hoverLeave()));
119 119 }
120 120
121 121 // update
122 122 slice->setLayout(l);
123 123 slice->updateGeometry();
124 124 slice->update();
125 125 }
126 126
127 127 // delete slices
128 128 foreach (QPieSlice *s, m_slices.keys()) {
129 129
130 130 bool found = false;
131 131 foreach (PieSliceLayout l, layout) {
132 132 if (l.m_data == s)
133 133 found = true;
134 134 }
135 135
136 136 if (!found)
137 137 delete m_slices.take(s);
138 138 }
139 139 }
140 140
141 #include "moc_piepresenter_p.cpp"
141 #include "moc_piechartitem_p.cpp"
142 142
143 143 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,48 +1,48
1 #ifndef PIEPRESENTER_H
2 #define PIEPRESENTER_H
1 #ifndef PIECHARTITEM_H
2 #define PIECHARTITEM_H
3 3
4 4 #include "qpieseries.h"
5 5 #include "chartitem_p.h"
6 6 #include "pieslice_p.h"
7 7
8 8 class QGraphicsItem;
9 9 QTCOMMERCIALCHART_BEGIN_NAMESPACE
10 10 class QPieSlice;
11 11
12 class PiePresenter : public QObject, public ChartItem
12 class PieChartItem : public QObject, public ChartItem
13 13 {
14 14 Q_OBJECT
15 15
16 16 public:
17 17 // TODO: use a generic data class instead of x and y
18 PiePresenter(QGraphicsItem *parent, QPieSeries *series);
19 ~PiePresenter();
18 PieChartItem(QGraphicsItem *parent, QPieSeries *series);
19 ~PieChartItem();
20 20
21 21 public: // from QGraphicsItem
22 22 QRectF boundingRect() const { return m_rect; }
23 23 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
24 24
25 25 public Q_SLOTS:
26 26 void handleSeriesChanged();
27 27 void handleSliceChanged();
28 28 void handleDomainChanged(qreal, qreal, qreal, qreal);
29 29 void handleGeometryChanged(const QRectF& rect);
30 30
31 31 private:
32 32 QVector<PieSliceLayout> calculateLayout();
33 33 void applyLayout(const QVector<PieSliceLayout> &layout);
34 34 void setLayout(const QVector<PieSliceLayout> &layout);
35 35
36 36 private:
37 37 friend class PieSlice;
38 38 QHash<QPieSlice*, PieSlice*> m_slices;
39 39 QPieSeries *m_series;
40 40 QRectF m_rect;
41 41 QPointF m_pieCenter;
42 42 qreal m_pieRadius;
43 43 QRectF m_debugRect;
44 44 };
45 45
46 46 QTCOMMERCIALCHART_END_NAMESPACE
47 47
48 #endif // PIEPRESENTER_H
48 #endif // PIECHARTITEM_H
@@ -1,208 +1,208
1 1 #include "pieslice_p.h"
2 #include "piepresenter_p.h"
2 #include "piechartitem_p.h"
3 3 #include "qpieseries.h"
4 4 #include "qpieslice.h"
5 5 #include "chartpresenter_p.h"
6 6 #include <QPainter>
7 7 #include <QDebug>
8 8 #include <qmath.h>
9 9 #include <QGraphicsSceneEvent>
10 10 #include <QTime>
11 11
12 12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
13 13
14 14 #define PI 3.14159265 // TODO: is this defined in some header?
15 15
16 16 QPointF offset(qreal angle, qreal length)
17 17 {
18 18 qreal dx = qSin(angle*(PI/180)) * length;
19 19 qreal dy = qCos(angle*(PI/180)) * length;
20 20 return QPointF(dx, -dy);
21 21 }
22 22
23 23 PieSlice::PieSlice(QGraphicsItem* parent)
24 24 :QGraphicsObject(parent),
25 25 m_startAngle(0),
26 26 m_angleSpan(0),
27 27 m_isExploded(false),
28 28 m_explodeDistanceFactor(0),
29 29 m_labelVisible(false),
30 30 m_labelArmLengthFactor(0)
31 31 {
32 32 setAcceptHoverEvents(true);
33 33 setAcceptedMouseButtons(Qt::LeftButton);
34 34 setZValue(ChartPresenter::PieSeriesZValue);
35 35 }
36 36
37 37 PieSlice::~PieSlice()
38 38 {
39 39
40 40 }
41 41
42 42 QRectF PieSlice::boundingRect() const
43 43 {
44 44 return m_slicePath.boundingRect();
45 45 }
46 46
47 47 QPainterPath PieSlice::shape() const
48 48 {
49 49 // Don't include the label and label arm.
50 50 // This is used to detect a mouse clicks. We do not want clicks from label.
51 51 return m_slicePath;
52 52 }
53 53
54 54 void PieSlice::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
55 55 {
56 56 painter->setClipRect(parentItem()->boundingRect());
57 57
58 58 painter->save();
59 59 painter->setPen(m_slicePen);
60 60 painter->setBrush(m_sliceBrush);
61 61 painter->drawPath(m_slicePath);
62 62 painter->restore();
63 63
64 64 if (m_labelVisible) {
65 65 painter->save();
66 66 painter->setPen(m_labelArmPen);
67 67 painter->drawPath(m_labelArmPath);
68 68 painter->restore();
69 69
70 70 painter->setFont(m_labelFont);
71 71 painter->drawText(m_labelTextRect.bottomLeft(), m_labelText);
72 72 }
73 73 }
74 74
75 75 void PieSlice::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
76 76 {
77 77 emit hoverEnter();
78 78 }
79 79
80 80 void PieSlice::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
81 81 {
82 82 emit hoverLeave();
83 83 }
84 84
85 85 void PieSlice::mousePressEvent(QGraphicsSceneMouseEvent* /*event*/)
86 86 {
87 87 emit clicked();
88 88 }
89 89
90 90 void PieSlice::setLayout(PieSliceLayout layout)
91 91 {
92 92 m_layout = layout;
93 93 updateData(layout.m_data);
94 94 }
95 95
96 96 void PieSlice::updateGeometry()
97 97 {
98 98 if (m_layout.m_radius <= 0)
99 99 return;
100 100
101 101 prepareGeometryChange();
102 102
103 103 // update slice path
104 104 qreal centerAngle;
105 105 QPointF armStart;
106 106 m_slicePath = slicePath(m_layout.m_center, m_layout.m_radius, m_startAngle, m_angleSpan, &centerAngle, &armStart);
107 107
108 108 // update text rect
109 109 m_labelTextRect = labelTextRect(m_labelFont, m_labelText);
110 110
111 111 // update label arm path
112 112 QPointF labelTextStart;
113 113 m_labelArmPath = labelArmPath(armStart, centerAngle, m_layout.m_radius * m_labelArmLengthFactor, m_labelTextRect.width(), &labelTextStart);
114 114
115 115 // update text position
116 116 m_labelTextRect.moveBottomLeft(labelTextStart);
117 117
118 118 //qDebug() << "PieSlice::updateGeometry" << m_labelText << boundingRect() << m_startAngle << m_startAngle + m_angleSpan;
119 119 }
120 120
121 121 void PieSlice::updateData(const QPieSlice* sliceData)
122 122 {
123 123 // TODO: compare what has changes to avoid unneccesary geometry updates
124 124
125 125 m_startAngle = sliceData->startAngle();
126 126 m_angleSpan = sliceData->m_angleSpan;
127 127 m_isExploded = sliceData->isExploded();
128 128 m_explodeDistanceFactor = sliceData->explodeDistanceFactor();
129 129 m_slicePen = sliceData->slicePen();
130 130 m_sliceBrush = sliceData->sliceBrush();
131 131
132 132 m_labelVisible = sliceData->isLabelVisible();
133 133 m_labelText = sliceData->label();
134 134 m_labelFont = sliceData->labelFont();
135 135 m_labelArmLengthFactor = sliceData->labelArmLengthFactor();
136 136 m_labelArmPen = sliceData->labelArmPen();
137 137 }
138 138
139 139 QPointF PieSlice::sliceCenter(QPointF point, qreal radius, QPieSlice *slice)
140 140 {
141 141 if (slice->isExploded()) {
142 142 qreal centerAngle = slice->startAngle() + (slice->m_angleSpan/2);
143 143 qreal len = radius * slice->explodeDistanceFactor();
144 144 qreal dx = qSin(centerAngle*(PI/180)) * len;
145 145 qreal dy = -qCos(centerAngle*(PI/180)) * len;
146 146 point += QPointF(dx, dy);
147 147 }
148 148 return point;
149 149 }
150 150
151 151 QPainterPath PieSlice::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal* centerAngle, QPointF* armStart)
152 152 {
153 153 // calculate center angle
154 154 *centerAngle = startAngle + (angleSpan/2);
155 155
156 156 // calculate slice rectangle
157 157 QRectF rect(center.x()-radius, center.y()-radius, radius*2, radius*2);
158 158
159 159 // slice path
160 160 // TODO: draw the shape so that it might have a hole in the center
161 161 QPainterPath path;
162 162 path.moveTo(rect.center());
163 163 path.arcTo(rect, -startAngle + 90, -angleSpan);
164 164 path.closeSubpath();
165 165
166 166 // calculate label arm start point
167 167 *armStart = center;
168 168 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
169 169
170 170 return path;
171 171 }
172 172
173 173 QPainterPath PieSlice::labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF* textStart)
174 174 {
175 175 qreal dx = qSin(angle*(PI/180)) * length;
176 176 qreal dy = -qCos(angle*(PI/180)) * length;
177 177 QPointF parm1 = start + QPointF(dx, dy);
178 178
179 179 QPointF parm2 = parm1;
180 180 if (angle < 180) { // arm swings the other way on the left side
181 181 parm2 += QPointF(textWidth, 0);
182 182 *textStart = parm1;
183 183 }
184 184 else {
185 185 parm2 += QPointF(-textWidth,0);
186 186 *textStart = parm2;
187 187 }
188 188
189 189 // elevate the text position a bit so that it does not hit the line
190 190 *textStart += QPointF(0, -5);
191 191
192 192 QPainterPath path;
193 193 path.moveTo(start);
194 194 path.lineTo(parm1);
195 195 path.lineTo(parm2);
196 196
197 197 return path;
198 198 }
199 199
200 200 QRectF PieSlice::labelTextRect(QFont font, QString text)
201 201 {
202 202 QFontMetricsF fm(font);
203 203 return fm.boundingRect(text);
204 204 }
205 205
206 206 #include "moc_pieslice_p.cpp"
207 207
208 208 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,82 +1,82
1 1 #ifndef PIESLICE_H
2 2 #define PIESLICE_H
3 3
4 4 #include "qchartglobal.h"
5 5 #include "charttheme_p.h"
6 6 #include "qpieseries.h"
7 7 #include <QGraphicsItem>
8 8 #include <QRectF>
9 9 #include <QColor>
10 10 #include <QPen>
11 11
12 12 #define PIESLICE_LABEL_GAP 5
13 13
14 14 QTCOMMERCIALCHART_BEGIN_NAMESPACE
15 class PiePresenter;
15 class PieChartItem;
16 16 class PieSliceLabel;
17 17 class QPieSlice;
18 18
19 19 class PieSliceLayout
20 20 {
21 21 public:
22 22 QPieSlice* m_data;
23 23 QPointF m_center;
24 24 qreal m_radius;
25 25 qreal m_startAngle;
26 26 qreal m_angleSpan;
27 27 };
28 28
29 29 class PieSlice : public QGraphicsObject
30 30 {
31 31 Q_OBJECT
32 32
33 33 public:
34 34 PieSlice(QGraphicsItem* parent = 0);
35 35 ~PieSlice();
36 36
37 37 public: // from QGraphicsItem
38 38 QRectF boundingRect() const;
39 39 QPainterPath shape() const;
40 40 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
41 41 void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
42 42 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
43 43 void mousePressEvent(QGraphicsSceneMouseEvent *event);
44 44
45 45 Q_SIGNALS:
46 46 void clicked();
47 47 void hoverEnter();
48 48 void hoverLeave();
49 49
50 50 public:
51 51 void setLayout(PieSliceLayout layout);
52 52 void updateGeometry();
53 53 void updateData(const QPieSlice *sliceData);
54 54 static QPointF sliceCenter(QPointF point, qreal radius, QPieSlice *slice);
55 55 static QPainterPath slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal* centerAngle, QPointF* armStart);
56 56 static QPainterPath labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF* textStart);
57 57 static QRectF labelTextRect(QFont font, QString text);
58 58
59 59 private:
60 60 PieSliceLayout m_layout;
61 61
62 62 QPainterPath m_slicePath;
63 63 qreal m_startAngle;
64 64 qreal m_angleSpan;
65 65 bool m_isExploded;
66 66 qreal m_explodeDistanceFactor;
67 67 bool m_labelVisible;
68 68 QPen m_slicePen;
69 69 QBrush m_sliceBrush;
70 70
71 71 QPainterPath m_labelArmPath;
72 72 qreal m_labelArmLengthFactor;
73 73 QPen m_labelArmPen;
74 74
75 75 QRectF m_labelTextRect;
76 76 QFont m_labelFont;
77 77 QString m_labelText;
78 78 };
79 79
80 80 QTCOMMERCIALCHART_END_NAMESPACE
81 81
82 82 #endif // PIESLICE_H
@@ -1,129 +1,129
1 1 #ifndef PIESERIES_H
2 2 #define PIESERIES_H
3 3
4 4 #include "qseries.h"
5 5 #include <QObject>
6 6 #include <QRectF>
7 7 #include <QColor>
8 8 #include <QPen>
9 9 #include <QBrush>
10 10 #include <QSignalMapper>
11 11
12 12 class QGraphicsObject;
13 13 QTCOMMERCIALCHART_BEGIN_NAMESPACE
14 class PiePresenter;
14 class PieChartItem;
15 15 class PieSlice;
16 16 class QPieSlice;
17 17
18 18 class QTCOMMERCIALCHART_EXPORT QPieSeries : public QSeries
19 19 {
20 20 Q_OBJECT
21 21
22 22 public:
23 23
24 24 class ChangeSet
25 25 {
26 26 public:
27 27
28 28 // TODO: these should not really be exposed to the public API
29 29 void appendAdded(QPieSlice* slice);
30 30 void appendAdded(QList<QPieSlice*> slices);
31 31 void appendChanged(QPieSlice* slice);
32 32 void appendRemoved(QPieSlice* slice);
33 33
34 34 QList<QPieSlice*> added() const;
35 35 QList<QPieSlice*> changed() const;
36 36 QList<QPieSlice*> removed() const;
37 37
38 38 bool isEmpty() const;
39 39
40 40 private:
41 41 QList<QPieSlice*> m_added;
42 42 QList<QPieSlice*> m_changed;
43 43 QList<QPieSlice*> m_removed;
44 44 };
45 45
46 46 public:
47 47 QPieSeries(QObject *parent = 0);
48 48 virtual ~QPieSeries();
49 49
50 50 public: // from QChartSeries
51 51 QSeriesType type() const;
52 52
53 53 public:
54 54
55 55 // slice setters
56 56 void add(QPieSlice* slice);
57 57 void add(QList<QPieSlice*> slices);
58 58 void replace(QList<QPieSlice*> slices);
59 59 void remove(QPieSlice* slice);
60 60 void clear();
61 61
62 62 // sluce getters
63 63 QList<QPieSlice*> slices() const;
64 64
65 65 // calculated data
66 66 int count() const;
67 67 qreal total() const;
68 68
69 69 // pie customization
70 70 void setPiePosition(qreal relativeHorizontalPosition, qreal relativeVerticalPosition);
71 71 qreal pieHorizontalPosition() const;
72 72 qreal pieVerticalPosition() const;
73 73 void setPieSize(qreal relativeSize);
74 74 qreal pieSize() const;
75 75 void setPieStartAngle(qreal startAngle);
76 76 qreal pieStartAngle() const;
77 77 void setPieEndAngle(qreal endAngle);
78 78 qreal pieEndAngle() const;
79 79
80 80 // convenience function
81 81 QPieSeries& operator << (QPieSlice* slice);
82 82 QPieSlice* add(qreal value, QString name);
83 83 void setLabelsVisible(bool visible = true);
84 84
85 85 // TODO: find slices?
86 86 // QList<QPieSlice*> findByValue(qreal value);
87 87 // ...
88 88
89 89 // TODO: sorting slices?
90 90 // void sort(QPieSeries::SortByValue|label|??)
91 91
92 92 // TODO: general graphics customization
93 93 // setDrawStyle(2d|3d)
94 94 // setDropShadows
95 95
96 96 Q_SIGNALS:
97 97 void clicked(QPieSlice* slice);
98 98 void hoverEnter(QPieSlice* slice);
99 99 void hoverLeave(QPieSlice* slice);
100 100 void changed(); // TODO: hide this in PIMPL
101 101
102 102 private Q_SLOTS: // TODO: should be private and not visible in the interface at all
103 103 void sliceChanged();
104 104 void sliceClicked();
105 105 void sliceHoverEnter();
106 106 void sliceHoverLeave();
107 107
108 108 private:
109 109 void updateDerivativeData();
110 110
111 111 private:
112 112 Q_DISABLE_COPY(QPieSeries)
113 113
114 114 // TODO: use PIML
115 friend class PiePresenter;
115 friend class PieChartItem;
116 116 friend class PieSlice;
117 117
118 118 QList<QPieSlice*> m_slices;
119 119 qreal m_pieRelativeHorPos;
120 120 qreal m_pieRelativeVerPos;
121 121 qreal m_pieRelativeSize;
122 122 qreal m_pieStartAngle;
123 123 qreal m_pieEndAngle;
124 124 qreal m_total;
125 125 };
126 126
127 127 QTCOMMERCIALCHART_END_NAMESPACE
128 128
129 129 #endif // PIESERIES_H
@@ -1,91 +1,91
1 1 #ifndef QPIESLICE_H
2 2 #define QPIESLICE_H
3 3
4 4 #include <qchartglobal.h>
5 5 #include <QObject>
6 6 #include <QPen>
7 7 #include <QBrush>
8 8 #include <QFont>
9 9
10 10 QTCOMMERCIALCHART_BEGIN_NAMESPACE
11 11
12 12 class QTCOMMERCIALCHART_EXPORT QPieSlice : public QObject
13 13 {
14 14 Q_OBJECT
15 15 Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY changed)
16 16 Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY changed)
17 17
18 18 public:
19 19 QPieSlice(QObject *parent = 0);
20 20 QPieSlice(qreal value, QString label, QObject *parent = 0);
21 21 virtual ~QPieSlice();
22 22
23 23 // data
24 24 void setValue(qreal value);
25 25 qreal value() const;
26 26 void setLabel(QString label);
27 27 QString label() const;
28 28 void setLabelVisible(bool visible);
29 29 bool isLabelVisible() const;
30 30 void setExploded(bool exploded);
31 31 bool isExploded() const;
32 32 void setExplodeDistanceFactor(qreal factor);
33 33 qreal explodeDistanceFactor() const;
34 34
35 35 // generated data
36 36 qreal percentage() const;
37 37 qreal startAngle() const;
38 38 qreal endAngle() const;
39 39
40 40 // customization
41 41 void setSlicePen(const QPen &pen);
42 42 QPen slicePen() const;
43 43 void setSliceBrush(const QBrush &brush);
44 44 QBrush sliceBrush() const;
45 45 void setLabelArmPen(const QPen &pen);
46 46 QPen labelArmPen() const;
47 47 void setLabelFont(const QFont &font);
48 48 QFont labelFont() const;
49 49 void setLabelArmLengthFactor(qreal factor);
50 50 qreal labelArmLengthFactor() const;
51 51
52 52 // TODO: label position in general
53 53 // setLabelFlags(inside|outside|labelArmOn|labelArmOff|???)
54 54 // setLabelOrientation(horizontal|vertical|same as slice center angle|???)
55 55
56 56 Q_SIGNALS:
57 57 void clicked();
58 58 void hoverEnter();
59 59 void hoverLeave();
60 60 void changed();
61 61
62 62 private:
63 63
64 64 // TODO: use private class
65 65 friend class QPieSeries;
66 friend class PiePresenter;
66 friend class PieChartItem;
67 67 friend class PieSlice;
68 68
69 69 // data
70 70 qreal m_value;
71 71 QString m_label;
72 72 bool m_isLabelVisible;
73 73 bool m_isExploded;
74 74 qreal m_explodeDistanceFactor;
75 75
76 76 // generated data
77 77 qreal m_percentage;
78 78 qreal m_startAngle;
79 79 qreal m_angleSpan;
80 80
81 81 // customization
82 82 QPen m_slicePen;
83 83 QBrush m_sliceBrush;
84 84 QFont m_labelFont;
85 85 QPen m_labelArmPen;
86 86 qreal m_labelArmLengthFactor;
87 87 };
88 88
89 89 QTCOMMERCIALCHART_END_NAMESPACE
90 90
91 91 #endif // QPIESLICE_H
General Comments 0
You need to be logged in to leave comments. Login now