##// END OF EJS Templates
Refactoring piechart API (and internals)
Jani Honkonen -
r174:0d781305aa75
parent child
Show More
@@ -0,0 +1,76
1 #include "pieslicelabel.h"
2 #include <QPainter>
3 #include <qmath.h>
4
5 QTCOMMERCIALCHART_BEGIN_NAMESPACE
6
7 #define PI 3.14159265
8
9 PieSliceLabel::PieSliceLabel(QGraphicsItem* parent)
10 :QGraphicsItem(parent)
11 {
12 m_pen = QPen(Qt::black);
13 }
14
15 PieSliceLabel::~PieSliceLabel()
16 {
17
18 }
19
20 QRectF PieSliceLabel::boundingRect() const
21 {
22 return m_rect;
23 }
24
25 QPainterPath PieSliceLabel::shape() const
26 {
27 return m_path;
28 }
29
30 void PieSliceLabel::paint(QPainter *painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
31 {
32 painter->setRenderHint(QPainter::Antialiasing);
33 painter->setPen(m_pen);
34 painter->drawPath(m_path);
35 }
36
37 void PieSliceLabel::updateGeometry(const QPointF& startPoint, qreal armAngle, qreal armLength)
38 {
39 prepareGeometryChange();
40
41 QPainterPath path;
42 path.moveTo(startPoint);
43
44 // draw arm
45 qreal dx = qSin(armAngle*(PI/180)) * armLength;
46 qreal dy = -qCos(armAngle*(PI/180)) * armLength;
47 QPointF p1 = startPoint + QPointF(dx, dy);
48 path.lineTo(p1);
49
50 QPointF p2 = p1;
51 QPointF pt = p1;
52 if (armAngle < 180) {
53 p2 += QPointF(50, 0);
54 } else {
55 p2 += QPointF(-50,0);
56 pt = p2;
57 }
58 path.lineTo(p2);
59
60 QFont font;
61 pt += QPointF(0,-2);
62 path.addText(pt, font, m_label);
63
64 m_path = path;
65 m_rect = path.boundingRect();
66 }
67
68 void PieSliceLabel::setLabel(QString label)
69 {
70 m_label = label;
71 // TODO: animation?
72 }
73
74
75
76 QTCOMMERCIALCHART_END_NAMESPACE
@@ -0,0 +1,36
1 #ifndef PIELABEL_H
2 #define PIELABEL_H
3
4 #include "qchartglobal.h"
5 #include <QGraphicsItem>
6 #include <QPen>
7
8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9
10 class PieSliceLabel : public QGraphicsItem
11 {
12 public:
13 PieSliceLabel(QGraphicsItem* parent = 0);
14 ~PieSliceLabel();
15
16 public: // from QGraphicsItem
17 QRectF boundingRect() const;
18 QPainterPath shape() const;
19 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
20
21 public:
22 void updateGeometry(const QPointF& startPoint, qreal armAngle, qreal armLength);
23 void setLabel(QString label);
24 QString label() const {return m_label;}
25 void setPen(QPen pen);
26
27 private:
28 QString m_label;
29 QPainterPath m_path;
30 QRectF m_rect;
31 QPen m_pen;
32 };
33
34 QTCOMMERCIALCHART_END_NAMESPACE
35
36 #endif // PIELABEL_H
@@ -1,33 +1,33
1 #include <QtGui/QApplication>
1 #include <QtGui/QApplication>
2 #include <QMainWindow>
2 #include <QMainWindow>
3 #include <cmath>
3 #include <cmath>
4 #include <qchartglobal.h>
4 #include <qchartglobal.h>
5 #include <qchartview.h>
5 #include <qchartview.h>
6 #include <qpieseries.h>
6 #include <qpieseries.h>
7
7
8 QTCOMMERCIALCHART_USE_NAMESPACE
8 QTCOMMERCIALCHART_USE_NAMESPACE
9
9
10 int main(int argc, char *argv[])
10 int main(int argc, char *argv[])
11 {
11 {
12 QApplication a(argc, argv);
12 QApplication a(argc, argv);
13
13
14 // Create widget and scatter series
14 // Create widget and scatter series
15 QChartView *chartWidget = new QChartView();
15 QChartView *chartWidget = new QChartView();
16 QPieSeries *series = qobject_cast<QPieSeries *>(chartWidget->createSeries(QChartSeries::SeriesTypePie));
16 QPieSeries *series = qobject_cast<QPieSeries *>(chartWidget->createSeries(QChartSeries::SeriesTypePie));
17 Q_ASSERT(series);
17 Q_ASSERT(series);
18
18
19 // Add test data to the series
19 // Add test data to the series
20 series->add(QPieSlice(1, "test1", Qt::red, true));
20 series->add(QPieSlice(1, "test1", true, true, QPen(Qt::red, 2), QBrush(Qt::red)));
21 series->add(QPieSlice(2, "test2", Qt::green));
21 series->add(QPieSlice(2, "test2"));
22 series->add(QPieSlice(3, "test3", Qt::blue));
22 series->add(QPieSlice(3, "test3"));
23 series->add(QPieSlice(4, "test4", Qt::darkRed, true));
23 series->add(QPieSlice(4, "test4"));
24 series->add(QPieSlice(5, "test5", Qt::darkGreen));
24 series->add(QPieSlice(5, "test5"));
25
25
26 // Use the chart widget as the central widget
26 // Use the chart widget as the central widget
27 QMainWindow w;
27 QMainWindow w;
28 w.resize(640, 480);
28 w.resize(640, 480);
29 w.setCentralWidget(chartWidget);
29 w.setCentralWidget(chartWidget);
30 w.show();
30 w.show();
31
31
32 return a.exec();
32 return a.exec();
33 }
33 }
@@ -1,212 +1,210
1 #include "charttheme_p.h"
1 #include "charttheme_p.h"
2 #include "qchart.h"
2 #include "qchart.h"
3
3
4
4
5 //series
5 //series
6 #include "barchartseries.h"
6 #include "barchartseries.h"
7 #include "stackedbarchartseries.h"
7 #include "stackedbarchartseries.h"
8 #include "percentbarchartseries.h"
8 #include "percentbarchartseries.h"
9 #include "qlinechartseries.h"
9 #include "qlinechartseries.h"
10 #include "qpieseries.h"
10 #include "qpieseries.h"
11
11
12 //items
12 //items
13 #include "axisitem_p.h"
13 #include "axisitem_p.h"
14 #include "bargroup.h"
14 #include "bargroup.h"
15 #include "stackedbargroup.h"
15 #include "stackedbargroup.h"
16 #include "linechartitem_p.h"
16 #include "linechartitem_p.h"
17 #include "percentbargroup.h"
17 #include "percentbargroup.h"
18 #include "piepresenter.h"
18 #include "piepresenter.h"
19
19
20 //themes
20 //themes
21 #include "chartthemevanilla_p.h"
21 #include "chartthemevanilla_p.h"
22 #include "chartthemeicy_p.h"
22 #include "chartthemeicy_p.h"
23 #include "chartthemegrayscale_p.h"
23 #include "chartthemegrayscale_p.h"
24 #include "chartthemescientific_p.h"
24 #include "chartthemescientific_p.h"
25
25
26
26
27 QTCOMMERCIALCHART_BEGIN_NAMESPACE
27 QTCOMMERCIALCHART_BEGIN_NAMESPACE
28
28
29 /* TODO
29 /* TODO
30 case QChart::ChartThemeUnnamed1:
30 case QChart::ChartThemeUnnamed1:
31 m_seriesThemes.append(SeriesTheme(QColor(QRgb(0xff3fa9f5)), 2));
31 m_seriesThemes.append(SeriesTheme(QColor(QRgb(0xff3fa9f5)), 2));
32 m_seriesThemes.append(SeriesTheme(QColor(QRgb(0xff7AC943)), 2));
32 m_seriesThemes.append(SeriesTheme(QColor(QRgb(0xff7AC943)), 2));
33 m_seriesThemes.append(SeriesTheme(QColor(QRgb(0xffFF931E)), 2));
33 m_seriesThemes.append(SeriesTheme(QColor(QRgb(0xffFF931E)), 2));
34 m_seriesThemes.append(SeriesTheme(QColor(QRgb(0xffFF1D25)), 2));
34 m_seriesThemes.append(SeriesTheme(QColor(QRgb(0xffFF1D25)), 2));
35 m_seriesThemes.append(SeriesTheme(QColor(QRgb(0xffFF7BAC)), 2));
35 m_seriesThemes.append(SeriesTheme(QColor(QRgb(0xffFF7BAC)), 2));
36
36
37 m_gradientStartColor = QColor(QRgb(0xfff3dc9e));
37 m_gradientStartColor = QColor(QRgb(0xfff3dc9e));
38 m_gradientEndColor = QColor(QRgb(0xffafafaf));
38 m_gradientEndColor = QColor(QRgb(0xffafafaf));
39 */
39 */
40
40
41 ChartTheme::ChartTheme(QChart::ChartTheme id)
41 ChartTheme::ChartTheme(QChart::ChartTheme id)
42 {
42 {
43 m_id = id;
43 m_id = id;
44 m_seriesColor.append(QRgb(0xff000000));
44 m_seriesColor.append(QRgb(0xff000000));
45 m_seriesColor.append(QRgb(0xff707070));
45 m_seriesColor.append(QRgb(0xff707070));
46 m_gradientStartColor = QColor(QRgb(0xffffffff));
46 m_gradientStartColor = QColor(QRgb(0xffffffff));
47 m_gradientEndColor = QColor(QRgb(0xffafafaf));
47 m_gradientEndColor = QColor(QRgb(0xffafafaf));
48 }
48 }
49
49
50
50
51 ChartTheme* ChartTheme::createTheme(QChart::ChartTheme theme)
51 ChartTheme* ChartTheme::createTheme(QChart::ChartTheme theme)
52 {
52 {
53 switch(theme) {
53 switch(theme) {
54 case QChart::ChartThemeDefault:
54 case QChart::ChartThemeDefault:
55 return new ChartTheme();
55 return new ChartTheme();
56 case QChart::ChartThemeVanilla:
56 case QChart::ChartThemeVanilla:
57 return new ChartThemeVanilla();
57 return new ChartThemeVanilla();
58 case QChart::ChartThemeIcy:
58 case QChart::ChartThemeIcy:
59 return new ChartThemeIcy();
59 return new ChartThemeIcy();
60 case QChart::ChartThemeGrayscale:
60 case QChart::ChartThemeGrayscale:
61 return new ChartThemeGrayscale();
61 return new ChartThemeGrayscale();
62 case QChart::ChartThemeScientific:
62 case QChart::ChartThemeScientific:
63 return new ChartThemeScientific();
63 return new ChartThemeScientific();
64 }
64 }
65 }
65 }
66
66
67 void ChartTheme::decorate(QChart* chart)
67 void ChartTheme::decorate(QChart* chart)
68 {
68 {
69 QLinearGradient backgroundGradient;
69 QLinearGradient backgroundGradient;
70 backgroundGradient.setColorAt(0.0, m_gradientStartColor);
70 backgroundGradient.setColorAt(0.0, m_gradientStartColor);
71 backgroundGradient.setColorAt(1.0, m_gradientEndColor);
71 backgroundGradient.setColorAt(1.0, m_gradientEndColor);
72 backgroundGradient.setCoordinateMode(QGradient::ObjectBoundingMode);
72 backgroundGradient.setCoordinateMode(QGradient::ObjectBoundingMode);
73 chart->setChartBackgroundBrush(backgroundGradient);
73 chart->setChartBackgroundBrush(backgroundGradient);
74 }
74 }
75 //TODO helper to by removed later
75 //TODO helper to by removed later
76 void ChartTheme::decorate(ChartItem* item, QChartSeries* series,int count)
76 void ChartTheme::decorate(ChartItem* item, QChartSeries* series,int count)
77 {
77 {
78 switch(series->type())
78 switch(series->type())
79 {
79 {
80 case QChartSeries::SeriesTypeLine: {
80 case QChartSeries::SeriesTypeLine: {
81 QLineChartSeries* s = static_cast<QLineChartSeries*>(series);
81 QLineChartSeries* s = static_cast<QLineChartSeries*>(series);
82 LineChartItem* i = static_cast<LineChartItem*>(item);
82 LineChartItem* i = static_cast<LineChartItem*>(item);
83 decorate(i,s,count);
83 decorate(i,s,count);
84 break;
84 break;
85 }
85 }
86 case QChartSeries::SeriesTypeBar: {
86 case QChartSeries::SeriesTypeBar: {
87 BarChartSeries* b = static_cast<BarChartSeries*>(series);
87 BarChartSeries* b = static_cast<BarChartSeries*>(series);
88 BarGroup* i = static_cast<BarGroup*>(item);
88 BarGroup* i = static_cast<BarGroup*>(item);
89 decorate(i,b,count);
89 decorate(i,b,count);
90 break;
90 break;
91 }
91 }
92 case QChartSeries::SeriesTypeStackedBar: {
92 case QChartSeries::SeriesTypeStackedBar: {
93 StackedBarChartSeries* s = static_cast<StackedBarChartSeries*>(series);
93 StackedBarChartSeries* s = static_cast<StackedBarChartSeries*>(series);
94 StackedBarGroup* i = static_cast<StackedBarGroup*>(item);
94 StackedBarGroup* i = static_cast<StackedBarGroup*>(item);
95 decorate(i,s,count);
95 decorate(i,s,count);
96 break;
96 break;
97 }
97 }
98 case QChartSeries::SeriesTypePercentBar: {
98 case QChartSeries::SeriesTypePercentBar: {
99 PercentBarChartSeries* s = static_cast<PercentBarChartSeries*>(series);
99 PercentBarChartSeries* s = static_cast<PercentBarChartSeries*>(series);
100 PercentBarGroup* i = static_cast<PercentBarGroup*>(item);
100 PercentBarGroup* i = static_cast<PercentBarGroup*>(item);
101 decorate(i,s,count);
101 decorate(i,s,count);
102 break;
102 break;
103 }
103 }
104 case QChartSeries::SeriesTypePie: {
104 case QChartSeries::SeriesTypePie: {
105 QPieSeries* s = static_cast<QPieSeries*>(series);
105 QPieSeries* s = static_cast<QPieSeries*>(series);
106 PiePresenter* i = static_cast<PiePresenter*>(item);
106 PiePresenter* i = static_cast<PiePresenter*>(item);
107 decorate(i,s,count);
107 decorate(i,s,count);
108 break;
108 break;
109 }
109 }
110 default:
110 default:
111 qDebug()<<"Wrong item to be decorated by theme";
111 qDebug()<<"Wrong item to be decorated by theme";
112 break;
112 break;
113 }
113 }
114
114
115 }
115 }
116
116
117 void ChartTheme::decorate(LineChartItem* item, QLineChartSeries* series,int count)
117 void ChartTheme::decorate(LineChartItem* item, QLineChartSeries* series,int count)
118 {
118 {
119 QPen pen;
119 QPen pen;
120 if(pen != series->pen()){
120 if(pen != series->pen()){
121 item->setPen(series->pen());
121 item->setPen(series->pen());
122 return;
122 return;
123 }
123 }
124 pen.setColor(m_seriesColor.at(count%m_seriesColor.size()));
124 pen.setColor(m_seriesColor.at(count%m_seriesColor.size()));
125 pen.setWidthF(2);
125 pen.setWidthF(2);
126 item->setPen(pen);
126 item->setPen(pen);
127 }
127 }
128
128
129 void ChartTheme::decorate(BarGroup* item, BarChartSeries* series,int count)
129 void ChartTheme::decorate(BarGroup* item, BarChartSeries* series,int count)
130 {
130 {
131 item->resetColors();
131 item->resetColors();
132 for (int i=0; i<m_seriesColor.count(); i++) {
132 for (int i=0; i<m_seriesColor.count(); i++) {
133 item->addColor(m_seriesColor.at(i));
133 item->addColor(m_seriesColor.at(i));
134 }
134 }
135 item->addColor(QColor(255,0,0,128));
135 item->addColor(QColor(255,0,0,128));
136 item->addColor(QColor(255,255,0,128));
136 item->addColor(QColor(255,255,0,128));
137 item->addColor(QColor(0,255,0,128));
137 item->addColor(QColor(0,255,0,128));
138 item->addColor(QColor(0,0,255,128));
138 item->addColor(QColor(0,0,255,128));
139 item->addColor(QColor(255,128,0,128));
139 item->addColor(QColor(255,128,0,128));
140 }
140 }
141
141
142 void ChartTheme::decorate(StackedBarGroup* item, StackedBarChartSeries* series,int count)
142 void ChartTheme::decorate(StackedBarGroup* item, StackedBarChartSeries* series,int count)
143 {
143 {
144 item->resetColors();
144 item->resetColors();
145 for (int i=0; i< m_seriesColor.count(); i++) {
145 for (int i=0; i< m_seriesColor.count(); i++) {
146 item->addColor(m_seriesColor.at(i));
146 item->addColor(m_seriesColor.at(i));
147 }
147 }
148 item->addColor(QColor(255,0,0,128));
148 item->addColor(QColor(255,0,0,128));
149 item->addColor(QColor(255,255,0,128));
149 item->addColor(QColor(255,255,0,128));
150 item->addColor(QColor(0,255,0,128));
150 item->addColor(QColor(0,255,0,128));
151 item->addColor(QColor(0,0,255,128));
151 item->addColor(QColor(0,0,255,128));
152 item->addColor(QColor(255,128,0,128));
152 item->addColor(QColor(255,128,0,128));
153 }
153 }
154
154
155 void ChartTheme::decorate(PercentBarGroup* item, PercentBarChartSeries* series,int count)
155 void ChartTheme::decorate(PercentBarGroup* item, PercentBarChartSeries* series,int count)
156 {
156 {
157 item->resetColors();
157 item->resetColors();
158 for (int i=0; i< m_seriesColor.count(); i++) {
158 for (int i=0; i< m_seriesColor.count(); i++) {
159 item->addColor(m_seriesColor.at(i));
159 item->addColor(m_seriesColor.at(i));
160 }
160 }
161 item->addColor(QColor(255,0,0,128));
161 item->addColor(QColor(255,0,0,128));
162 item->addColor(QColor(255,255,0,128));
162 item->addColor(QColor(255,255,0,128));
163 item->addColor(QColor(0,255,0,128));
163 item->addColor(QColor(0,255,0,128));
164 item->addColor(QColor(0,0,255,128));
164 item->addColor(QColor(0,0,255,128));
165 item->addColor(QColor(255,128,0,128));
165 item->addColor(QColor(255,128,0,128));
166 }
166 }
167
167
168 void ChartTheme::decorate(PiePresenter* item, QPieSeries* series, int /*count*/)
168 void ChartTheme::decorate(PiePresenter* item, QPieSeries* series, int /*count*/)
169 {
169 {
170 // create a list of slice colors based on current theme
170 // create a list of slice colors based on current theme
171 int i = 0;
171 int i = 0;
172 QList<QColor> colors;
172 QList<QColor> colors;
173 while (colors.count() < series->count()) {
173 while (colors.count() < series->count()) {
174
174
175 // get base color
175 // get base color
176 QColor c = m_seriesColor[i++];
176 QColor c = m_seriesColor[i++];
177 i = i % m_seriesColor.count();
177 i = i % m_seriesColor.count();
178
178
179 // -1 means achromatic color -> cannot manipulate lightness
179 // -1 means achromatic color -> cannot manipulate lightness
180 // TODO: find a better way to randomize lightness
180 // TODO: find a better way to randomize lightness
181 if (c.toHsv().hue() == -1)
181 if (c.toHsv().hue() == -1)
182 qWarning() << "ChartTheme::decorate() warning: achromatic theme color";
182 qWarning() << "ChartTheme::decorate() warning: achromatic theme color";
183
183
184 // randomize lightness
184 // randomize lightness
185 qreal f = 50 + (qrand() % 100); // 50 is 50% darker, 100 is the same, 150 is 50% lighter
185 qreal f = 50 + (qrand() % 100); // 50 is 50% darker, 100 is the same, 150 is 50% lighter
186 c = c.lighter(f);
186 c = c.lighter(f);
187
187
188 // find duplicates
188 // find duplicates
189 bool isUnique = true;
189 bool isUnique = true;
190 foreach (QColor color, colors) {
190 foreach (QColor color, colors) {
191 if (c == color)
191 if (c == color)
192 isUnique = false;
192 isUnique = false;
193 }
193 }
194
194
195 // add to array if unique
195 // add to array if unique
196 //if (isUnique)
196 //if (isUnique)
197 colors << c;
197 colors << c;
198 }
198 }
199
199
200 // finally update colors
200 // finally update colors
201 QList<QPieSlice> slices;
201 foreach (QPieSliceId id, series->ids()) {
202 for (int i=0; i<series->count(); i++) {
202 QPieSlice s = series->slice(id);
203 QPieSlice slice = series->slice(i);
203 s.setPen(QPen(Qt::black)); // TODO: get from theme
204 slice.m_color = colors.at(i);
204 s.setBrush(colors.takeFirst());
205 slices << slice;
205 series->update(s);
206 }
206 }
207
208 series->set(slices);
209 }
207 }
210
208
211
209
212 QTCOMMERCIALCHART_END_NAMESPACE
210 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,14 +1,16
1 INCLUDEPATH += $$PWD
1 INCLUDEPATH += $$PWD
2 DEPENDPATH += $$PWD
2 DEPENDPATH += $$PWD
3
3
4 SOURCES += \
4 SOURCES += \
5 $$PWD/qpieseries.cpp \
5 $$PWD/qpieseries.cpp \
6 $$PWD/pieslice.cpp \
6 $$PWD/pieslice.cpp \
7 $$PWD/piepresenter.cpp
7 $$PWD/piepresenter.cpp \
8 $$PWD/pieslicelabel.cpp
8
9
9 PRIVATE_HEADERS += \
10 PRIVATE_HEADERS += \
10 $$PWD/piepresenter.h \
11 $$PWD/piepresenter.h \
11 $$PWD/pieslice.h
12 $$PWD/pieslice.h \
13 $$PWD/pieslicelabel.h
12
14
13 PUBLIC_HEADERS += \
15 PUBLIC_HEADERS += \
14 $$PWD/qpieseries.h
16 $$PWD/qpieseries.h
@@ -1,127 +1,170
1
1
2 #include "piepresenter.h"
2 #include "piepresenter.h"
3 #include "pieslice.h"
3 #include "pieslice.h"
4 #include <QDebug>
4 #include <QDebug>
5 #include <QTime>
5 #include <QTime>
6
6
7 QTCOMMERCIALCHART_BEGIN_NAMESPACE
7 QTCOMMERCIALCHART_BEGIN_NAMESPACE
8
8
9 PiePresenter::PiePresenter(QGraphicsItem *parent, QPieSeries *series) :
9 PiePresenter::PiePresenter(QGraphicsItem *parent, QPieSeries *series)
10 ChartItem(parent),
10 :ChartItem(parent),
11 m_pieSeries(series)
11 m_series(series)
12 {
12 {
13 Q_ASSERT(parent);
14 Q_ASSERT(series);
13 Q_ASSERT(series);
15
14 connect(series, SIGNAL(changed(const QPieSeries::ChangeSet&)), this, SLOT(handleSeriesChanged(const QPieSeries::ChangeSet&)));
16 m_rect = parentItem()->boundingRect();
17 setAcceptHoverEvents(true);
18 qsrand(QTime::currentTime().msec()); // for random color generation
19
20 connect(series, SIGNAL(changed(const PieChangeSet&)), this, SLOT(handleSeriesChanged(const PieChangeSet&)));
21 connect(series, SIGNAL(sizeFactorChanged()), this, SLOT(updateGeometry()));
15 connect(series, SIGNAL(sizeFactorChanged()), this, SLOT(updateGeometry()));
22 connect(series, SIGNAL(positionChanged()), this, SLOT(updateGeometry()));
16 connect(series, SIGNAL(positionChanged()), this, SLOT(updateGeometry()));
23 }
17 }
24
18
25 PiePresenter::~PiePresenter()
19 PiePresenter::~PiePresenter()
26 {
20 {
27 while (m_slices.count())
21 // slices deleted automatically through QGraphicsItem
28 delete m_slices.takeLast();
29 }
22 }
30
23
31 void PiePresenter::handleSeriesChanged(const PieChangeSet& /*changeSet*/)
24 void PiePresenter::paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *)
32 {
25 {
33 const qreal fullPie = 360;
26 // TODO: paint shadows for all components
34 qreal total = 0;
27 // - get paths from items & merge & offset and draw with shadow color?
35
36 // calculate total and set random color if there is no color
37 for (int i=0; i<m_pieSeries->count(); i++) {
38 QPieSlice& slice = m_pieSeries->m_slices[i];
39 total += slice.m_value;
40 if (slice.m_color == QColor::Invalid) {
41 slice.m_color.setRed(qrand() % 255);
42 slice.m_color.setGreen(qrand() % 255);
43 slice.m_color.setBlue(qrand() % 255);
44 }
28 }
29
30 void PiePresenter::handleSeriesChanged(const QPieSeries::ChangeSet& changeSet)
31 {
32 qDebug() << "PiePresenter::handleSeriesChanged()";
33 qDebug() << " added : " << changeSet.m_added;
34 qDebug() << " changed: " << changeSet.m_changed;
35 qDebug() << " removed: " << changeSet.m_removed;
36
37 // ignore changeset when there are no visual slices
38 // changeset might not be valid about the added slices
39 if (m_slices.count() == 0) {
40 foreach (QPieSliceId id, m_series->m_slices.keys())
41 addSlice(id);
42 return;
45 }
43 }
46
44
47 // TODO: no need to create new slices in case size changed; we should re-use the existing ones
45 foreach (QPieSliceId id, changeSet.m_removed)
48 while (m_slices.count())
46 deleteSlice(id);
49 delete m_slices.takeLast();
50
47
51 // create slices
48 foreach (QPieSliceId id, changeSet.m_changed)
52 qreal angle = 0;
49 updateSlice(id);
53 for (int i=0; i<m_pieSeries->count(); i++) {
50
54 QPieSlice sliceData = m_pieSeries->slice(i);
51 foreach (QPieSliceId id, changeSet.m_added)
55 qreal span = sliceData.m_value / total * fullPie;
52 addSlice(id);
56 PieSlice *slice = new PieSlice(this, i, angle, span);
57 m_slices.append(slice);
58 angle += span;
59 }
60 }
53 }
61
54
62 void PiePresenter::updateGeometry()
55 void PiePresenter::updateGeometry()
63 {
56 {
64 prepareGeometryChange();
57 prepareGeometryChange();
65
58
66 m_pieRect = m_rect;
59 m_pieRect = m_rect;
67
60
68 if (m_pieRect.width() < m_pieRect.height()) {
61 if (m_pieRect.width() < m_pieRect.height()) {
69 m_pieRect.setWidth(m_pieRect.width() * m_pieSeries->sizeFactor());
62 m_pieRect.setWidth(m_pieRect.width() * m_series->sizeFactor());
70 m_pieRect.setHeight(m_pieRect.width());
63 m_pieRect.setHeight(m_pieRect.width());
71 m_pieRect.moveCenter(m_rect.center());
64 m_pieRect.moveCenter(m_rect.center());
72 } else {
65 } else {
73 m_pieRect.setHeight(m_pieRect.height() * m_pieSeries->sizeFactor());
66 m_pieRect.setHeight(m_pieRect.height() * m_series->sizeFactor());
74 m_pieRect.setWidth(m_pieRect.height());
67 m_pieRect.setWidth(m_pieRect.height());
75 m_pieRect.moveCenter(m_rect.center());
68 m_pieRect.moveCenter(m_rect.center());
76 }
69 }
77
70
78 switch (m_pieSeries->position()) {
71 switch (m_series->position()) {
79 case QPieSeries::PiePositionTopLeft: {
72 case QPieSeries::PiePositionTopLeft: {
80 m_pieRect.setHeight(m_pieRect.height() / 2);
73 m_pieRect.setHeight(m_pieRect.height() / 2);
81 m_pieRect.setWidth(m_pieRect.height());
74 m_pieRect.setWidth(m_pieRect.height());
82 m_pieRect.moveCenter(QPointF(m_rect.center().x() / 2, m_rect.center().y() / 2));
75 m_pieRect.moveCenter(QPointF(m_rect.center().x() / 2, m_rect.center().y() / 2));
83 break;
76 break;
84 }
77 }
85 case QPieSeries::PiePositionTopRight: {
78 case QPieSeries::PiePositionTopRight: {
86 m_pieRect.setHeight(m_pieRect.height() / 2);
79 m_pieRect.setHeight(m_pieRect.height() / 2);
87 m_pieRect.setWidth(m_pieRect.height());
80 m_pieRect.setWidth(m_pieRect.height());
88 m_pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, m_rect.center().y() / 2));
81 m_pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, m_rect.center().y() / 2));
89 break;
82 break;
90 }
83 }
91 case QPieSeries::PiePositionBottomLeft: {
84 case QPieSeries::PiePositionBottomLeft: {
92 m_pieRect.setHeight(m_pieRect.height() / 2);
85 m_pieRect.setHeight(m_pieRect.height() / 2);
93 m_pieRect.setWidth(m_pieRect.height());
86 m_pieRect.setWidth(m_pieRect.height());
94 m_pieRect.moveCenter(QPointF(m_rect.center().x() / 2, (m_rect.center().y() / 2) * 3));
87 m_pieRect.moveCenter(QPointF(m_rect.center().x() / 2, (m_rect.center().y() / 2) * 3));
95 break;
88 break;
96 }
89 }
97 case QPieSeries::PiePositionBottomRight: {
90 case QPieSeries::PiePositionBottomRight: {
98 m_pieRect.setHeight(m_pieRect.height() / 2);
91 m_pieRect.setHeight(m_pieRect.height() / 2);
99 m_pieRect.setWidth(m_pieRect.height());
92 m_pieRect.setWidth(m_pieRect.height());
100 m_pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, (m_rect.center().y() / 2) * 3));
93 m_pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, (m_rect.center().y() / 2) * 3));
101 break;
94 break;
102 }
95 }
103 default:
96 default:
104 break;
97 break;
105 }
98 }
106
99
107 qDebug() << "presentation rect:" << m_rect;
100 // update slice geometry
108 qDebug() << "pie rect:" << m_pieRect;
101 const qreal fullPie = 360;
109 foreach (PieSlice *slice, m_slices)
102 qreal angle = 0;
110 slice->updateGeometry();
103 foreach (QPieSliceId id, m_slices.keys()) {
104 qreal span = fullPie * m_series->slice(id).percentage();
105 m_slices[id]->updateGeometry(m_pieRect, angle, span);
106 angle += span;
107 }
108
109 //qDebug() << "PiePresenter::updateGeometry" << m_rect << m_pieRect;
111 }
110 }
112
111
113 void PiePresenter::handleDomainChanged(const Domain& domain)
112 void PiePresenter::handleDomainChanged(const Domain& domain)
114 {
113 {
115 // TODO
114 // TODO
116 }
115 }
117
116
118 void PiePresenter::handleGeometryChanged(const QRectF& rect)
117 void PiePresenter::handleGeometryChanged(const QRectF& rect)
119 {
118 {
120 m_rect = rect;
119 m_rect = rect;
121 updateGeometry();
120 updateGeometry();
121 }
122
123 void PiePresenter::addSlice(QPieSliceId id)
124 {
125 qDebug() << "PiePresenter::addSlice()" << id;
126
127 if (m_slices.contains(id)) {
128 qWarning() << "PiePresenter::addSlice(): slice already exists!" << id;
129 updateSlice(id);
130 return;
131 }
132
133 // create slice
134 PieSlice *slice = new PieSlice(id, m_series, this);
135 m_slices.insert(id, slice);
136
137 updateGeometry();
138 }
122
139
140 void PiePresenter::updateSlice(QPieSliceId id)
141 {
142 qDebug() << "PiePresenter::updateSlice()" << id;
143
144 // TODO: animation
145 if (m_slices.contains(id))
146 m_slices.value(id)->updateData();
147 else {
148 qWarning() << "PiePresenter::updateSlice(): slice does not exist!" << id;
149 addSlice(id);
150 }
151
152 updateGeometry();
153 }
154
155 void PiePresenter::deleteSlice(QPieSliceId id)
156 {
157 qDebug() << "PiePresenter::deleteSlice()" << id;
158
159 // TODO: animation
160 if (m_slices.contains(id))
161 delete m_slices.take(id);
162 else
163 qWarning() << "PiePresenter::deleteSlice(): slice does not exist!" << id;
164
165 updateGeometry();
123 }
166 }
124
167
125 #include "moc_piepresenter.cpp"
168 #include "moc_piepresenter.cpp"
126
169
127 QTCOMMERCIALCHART_END_NAMESPACE
170 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,43 +1,49
1 #ifndef PIEPRESENTER_H
1 #ifndef PIEPRESENTER_H
2 #define PIEPRESENTER_H
2 #define PIEPRESENTER_H
3
3
4 #include "chartitem_p.h"
4 #include "chartitem_p.h"
5 #include "qpieseries.h"
5 #include "qpieseries.h"
6 #include <QSignalMapper>
6
7
7 class QGraphicsItem;
8 class QGraphicsItem;
8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9 class PieSlice;
10 class PieSlice;
10
11
11 class PiePresenter : public QObject, public ChartItem
12 class PiePresenter : public QObject, public ChartItem
12 {
13 {
13 Q_OBJECT
14 Q_OBJECT
14
15
15 public:
16 public:
16 // TODO: use a generic data class instead of x and y
17 // TODO: use a generic data class instead of x and y
17 PiePresenter(QGraphicsItem *parent, QPieSeries *series);
18 PiePresenter(QGraphicsItem *parent, QPieSeries *series);
18 ~PiePresenter();
19 ~PiePresenter();
19
20
20 public: // from QGraphicsItem
21 public: // from QGraphicsItem
21 QRectF boundingRect() const { return m_rect; }
22 QRectF boundingRect() const { return m_rect; }
22 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) {}
23 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
23
24
24 public:
25 public:
25 QRectF pieRect() const { return m_pieRect; }
26 QRectF pieRect() const { return m_pieRect; }
26
27
27 public Q_SLOTS:
28 public Q_SLOTS:
28 void handleSeriesChanged(const PieChangeSet& changeSet);
29 void handleSeriesChanged(const QPieSeries::ChangeSet& changeSet);
29 void handleDomainChanged(const Domain& domain);
30 void handleDomainChanged(const Domain& domain);
30 void handleGeometryChanged(const QRectF& rect);
31 void handleGeometryChanged(const QRectF& rect);
31 void updateGeometry();
32 void updateGeometry();
32
33
33 private:
34 private:
35 void addSlice(QPieSliceId id);
36 void updateSlice(QPieSliceId id);
37 void deleteSlice(QPieSliceId id);
38
39 private:
34 friend class PieSlice;
40 friend class PieSlice;
35 QList<PieSlice*> m_slices;
41 QHash<QPieSliceId, PieSlice*> m_slices;
36 QPieSeries *m_pieSeries;
42 QPieSeries *m_series;
37 QRectF m_rect;
43 QRectF m_rect;
38 QRectF m_pieRect;
44 QRectF m_pieRect;
39 };
45 };
40
46
41 QTCOMMERCIALCHART_END_NAMESPACE
47 QTCOMMERCIALCHART_END_NAMESPACE
42
48
43 #endif // PIEPRESENTER_H
49 #endif // PIEPRESENTER_H
@@ -1,122 +1,135
1 #include "pieslice.h"
1 #include "pieslice.h"
2 #include "pieslicelabel.h"
2 #include "piepresenter.h"
3 #include "piepresenter.h"
3 #include "qpieseries.h"
4 #include "qpieseries.h"
4 #include <QPainter>
5 #include <QPainter>
5 #include <QDebug>
6 #include <QDebug>
6 #include <qmath.h>
7 #include <qmath.h>
7 #include <QGraphicsSceneEvent>
8 #include <QGraphicsSceneEvent>
9 #include <QTime>
8
10
9 QTCOMMERCIALCHART_BEGIN_NAMESPACE
11 QTCOMMERCIALCHART_BEGIN_NAMESPACE
10
12
11 #define PI 3.14159265
13 #define PI 3.14159265
12 #define EXPLODE_OFFSET 20
14 #define EXPLODE_OFFSET 20
13
15
14 QPointF offset(qreal angle, qreal length)
16 QPointF offset(qreal angle, qreal length)
15 {
17 {
16 qreal dx = qSin(angle*(PI/180)) * length;
18 qreal dx = qSin(angle*(PI/180)) * length;
17 qreal dy = qCos(angle*(PI/180)) * length;
19 qreal dy = qCos(angle*(PI/180)) * length;
18 return QPointF(dx, -dy);
20 return QPointF(dx, -dy);
19 }
21 }
20
22
21 PieSlice::PieSlice(PiePresenter *presenter, int seriesIndex, qreal startAngle, qreal span)
23 PieSlice::PieSlice(QPieSliceId id, QPieSeries *series, QGraphicsItem* parent)
22 :QGraphicsItem(presenter),
24 :QGraphicsObject(parent),
23 m_label(new QGraphicsTextItem(this)),
25 m_id(id),
24 m_seriesIndex(seriesIndex),
26 m_series(series),
25 m_startAngle(startAngle),
27 m_slicelabel(new PieSliceLabel(this)),
26 m_span(span)
28 m_isHovering(false)
27 {
29 {
28 Q_ASSERT(presenter);
30 Q_ASSERT(series);
29 setAcceptHoverEvents(true);
31 setAcceptHoverEvents(true);
30 setAcceptedMouseButtons(Qt::LeftButton);
32 setAcceptedMouseButtons(Qt::LeftButton);
31 updateGeometry();
33 updateData();
32
33 // TODO: use themes
34 m_pen = QPen(Qt::black);
35 m_brush = QBrush(sliceData().m_color);
36 }
34 }
37
35
38 PieSlice::~PieSlice()
36 PieSlice::~PieSlice()
39 {
37 {
38 qDebug() << "~PieSlice()" << m_id;
40 }
39 }
41
40
42 QRectF PieSlice::boundingRect() const
41 QRectF PieSlice::boundingRect() const
43 {
42 {
44 return m_rect;
43 return m_rect;
45 }
44 }
46
45
47 QPainterPath PieSlice::shape() const
46 QPainterPath PieSlice::shape() const
48 {
47 {
49 return m_path;
48 return m_path;
50 }
49 }
51
50
52 void PieSlice::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
51 void PieSlice::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
53 {
52 {
54 painter->setRenderHint(QPainter::Antialiasing);
53 // set hover brush
54 // TODO: what if we are using gradients...
55 QBrush brush = m_data.brush();
56 if (m_isHovering)
57 brush.setColor(brush.color().lighter());
55
58
56 // TODO: themes
59 painter->setRenderHint(QPainter::Antialiasing);
57 painter->setPen(m_pen);
60 painter->setPen(m_data.pen());
58 painter->setBrush(m_brush);
61 painter->setBrush(brush);
59 painter->drawPath(m_path);
62 painter->drawPath(m_path);
60
61 // Draw the label
62 // TODO: do this better
63 //QTextItem text;
64 painter->drawText(m_center, sliceData().m_label);
65 }
63 }
66
64
67 void PieSlice::hoverEnterEvent(QGraphicsSceneHoverEvent* event)
65 void PieSlice::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
68 {
66 {
69 m_brush = QBrush(sliceData().m_color.lighter());
67 m_isHovering = true;
70 update();
68 update();
69 // TODO: emit hoverEnter()
71 }
70 }
72
71
73 void PieSlice::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
72 void PieSlice::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
74 {
73 {
75 m_brush = QBrush(sliceData().m_color);
74 m_isHovering = false;
76 update();
75 update();
76 // TODO: emit hoverLeave()
77 }
77 }
78
78
79 void PieSlice::mousePressEvent(QGraphicsSceneMouseEvent* /*event*/)
79 void PieSlice::mousePressEvent(QGraphicsSceneMouseEvent* /*event*/)
80 {
80 {
81 QPieSlice data = sliceData();
81 // TODO: emit clicked
82 data.m_isExploded = !data.m_isExploded;
82 // TODO: should we let the user decide if this can be exploded?
83 (static_cast<PiePresenter*>(parentItem()))->m_pieSeries->update(m_seriesIndex, data);
83 m_data.setExploded(!m_data.isExploded());
84 m_series->update(m_data);
84 }
85 }
85
86
86 void PieSlice::updateGeometry()
87 void PieSlice::updateGeometry(QRectF rect, qreal startAngle, qreal span)
87 {
88 {
88 prepareGeometryChange();
89 prepareGeometryChange();
89
90
90 PiePresenter *presenter = static_cast<PiePresenter*>(parentItem());
91 // calculate center angle
91 QRectF rect = presenter->pieRect();
92 qreal centerAngle = startAngle + (span/2);
92 rect.adjust(EXPLODE_OFFSET, EXPLODE_OFFSET, -EXPLODE_OFFSET ,-EXPLODE_OFFSET);
93
93
94 qreal centerAngle = m_startAngle + (m_span/2);
94 // adjust rect for exploding
95
95 rect.adjust(EXPLODE_OFFSET, EXPLODE_OFFSET, -EXPLODE_OFFSET ,-EXPLODE_OFFSET);
96 if (presenter->m_pieSeries->slice(m_seriesIndex).m_isExploded) {
96 if (m_data.isExploded()) {
97 QPointF d = offset((centerAngle), EXPLODE_OFFSET);
97 QPointF d = offset((centerAngle), EXPLODE_OFFSET);
98 rect.translate(d.x(), d.y());
98 rect.translate(d.x(), d.y());
99 }
99 }
100
100
101 qreal angle = (-m_startAngle) + (90);
101 // update slice path
102 qreal span = -m_span;
102 // TODO: draw the shape so that it might have a hole in the center
103
104 QPainterPath path;
103 QPainterPath path;
105 path.moveTo(rect.center());
104 path.moveTo(rect.center());
106 path.arcTo(rect, angle, span);
105 path.arcTo(rect, -startAngle + 90, -span);
107
108 // TODO: draw the shape so that it might have a hole in the center
109
110 m_path = path;
106 m_path = path;
111 m_rect = path.boundingRect();
107 m_rect = path.boundingRect();
112
108
109 // update label position
113 qreal radius = rect.height() / 2;
110 qreal radius = rect.height() / 2;
114 m_center = rect.center() + offset(centerAngle, radius / 2);
111 QPointF edgeCenter = rect.center() + offset(centerAngle, radius + 5);
112 m_slicelabel->updateGeometry(edgeCenter, centerAngle, 50);
113
114 //qDebug() << "PieSlice::updateGeometry" << m_rect;
115 }
115 }
116
116
117 QPieSlice PieSlice::sliceData()
117 void PieSlice::updateData()
118 {
118 {
119 return (static_cast<PiePresenter*>(parentItem()))->m_pieSeries->slice(m_seriesIndex);
119 if (!m_series->m_slices.contains(m_id))
120 qWarning() << "PieSlice::updateData(): cannot find slice data!" << m_id;
121
122 QPieSlice data = m_series->slice(m_id);
123 // TODO: find out what has changed and trigger some animation
124 m_data = data;
125
126 update();
127
128 m_slicelabel->setLabel(m_data.label());
129 m_slicelabel->setVisible(m_data.isLabelVisible());
130 m_slicelabel->update();
120 }
131 }
121
132
133 #include "moc_pieslice.cpp"
134
122 QTCOMMERCIALCHART_END_NAMESPACE
135 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,49 +1,51
1 #ifndef PIESLICE_H
1 #ifndef PIESLICE_H
2 #define PIESLICE_H
2 #define PIESLICE_H
3
3
4 #include "qchartglobal.h"
4 #include "qchartglobal.h"
5 #include "charttheme_p.h"
5 #include "charttheme_p.h"
6 #include "qpieseries.h"
6 #include "qpieseries.h"
7 #include <QGraphicsItem>
7 #include <QGraphicsItem>
8 #include <QRectF>
8 #include <QRectF>
9 #include <QColor>
9 #include <QColor>
10 #include <QPen>
10 #include <QPen>
11
11
12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
13 class PiePresenter;
13 class PiePresenter;
14 class PieSliceLabel;
14
15
15 class PieSlice : public QGraphicsItem
16 class PieSlice : public QGraphicsObject
16 {
17 {
18 Q_OBJECT
19
17 public:
20 public:
18 PieSlice(PiePresenter *piePresenter, int seriesIndex, qreal startAngle, qreal span);
21 PieSlice(QPieSliceId id, QPieSeries *series, QGraphicsItem* parent = 0);
19 ~PieSlice();
22 ~PieSlice();
20
23
21 public: // from QGraphicsItem
24 public: // from QGraphicsItem
22 QRectF boundingRect() const;
25 QRectF boundingRect() const;
23 QPainterPath shape() const;
26 QPainterPath shape() const;
24 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
27 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
25 void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
28 void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
26 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
29 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
27 void mousePressEvent(QGraphicsSceneMouseEvent *event);
30 void mousePressEvent(QGraphicsSceneMouseEvent *event);
28
31
29 public:
32 Q_SIGNALS:
30 void updateGeometry();
33 void clicked();
31
34
32 private:
35 public:
33 QPieSlice sliceData();
36 void updateGeometry(QRectF rect, qreal startAngle, qreal span);
37 void updateData();
34
38
35 private:
39 private:
36 QGraphicsTextItem* m_label;
40 QPieSliceId m_id;
37 int m_seriesIndex;
41 QPieSeries* m_series;
38 qreal m_startAngle;
42 QPieSlice m_data;
39 qreal m_span;
43 PieSliceLabel* m_slicelabel;
40 QPainterPath m_path;
44 QPainterPath m_path;
41 QRectF m_rect;
45 QRectF m_rect;
42 QPointF m_center;
46 bool m_isHovering;
43 QPen m_pen;
44 QBrush m_brush;
45 };
47 };
46
48
47 QTCOMMERCIALCHART_END_NAMESPACE
49 QTCOMMERCIALCHART_END_NAMESPACE
48
50
49 #endif // PIESLICE_H
51 #endif // PIESLICE_H
@@ -1,109 +1,152
1 #include "qpieseries.h"
1 #include "qpieseries.h"
2 #include "piepresenter.h"
2 #include "piepresenter.h"
3 #include "pieslice.h"
3 #include "pieslice.h"
4 #include <QDebug>
4 #include <QDebug>
5
5
6 QTCOMMERCIALCHART_BEGIN_NAMESPACE
6 QTCOMMERCIALCHART_BEGIN_NAMESPACE
7
7
8 QPieSeries::QPieSeries(QObject *parent) :
8 QPieSeries::QPieSeries(QObject *parent) :
9 QChartSeries(parent),
9 QChartSeries(parent),
10 m_sizeFactor(1.0),
10 m_sizeFactor(1.0),
11 m_position(PiePositionMaximized)
11 m_position(PiePositionMaximized),
12 m_sliceIdSeed(0)
12 {
13 {
13 }
14 }
14
15
15 QPieSeries::~QPieSeries()
16 QPieSeries::~QPieSeries()
16 {
17 {
17
18
18 }
19 }
19
20
20 bool QPieSeries::setData(QList<qreal> data)
21 bool QPieSeries::setData(QList<qreal> data)
21 {
22 {
23 // TODO: remove this function
22 QList<QPieSlice> slices;
24 QList<QPieSlice> slices;
23 foreach (int value, data)
25 foreach (int value, data)
24 slices << QPieSlice(value, QString::number(value));
26 slices << QPieSlice(value, QString::number(value));
25 return set(slices);
27 return set(slices);
26 }
28 }
27
29
28 bool QPieSeries::set(QList<QPieSlice> slices)
30 bool QPieSeries::set(const QList<QPieSlice>& slices)
29 {
31 {
30 if (!slices.count())
32 if (!slices.count())
31 return false;
33 return false;
32
34
33 PieChangeSet changeSet;
35 ChangeSet changeSet;
34
36
35 for (int i=slices.count(); i<m_slices.count(); i++)
37 foreach (QPieSlice s, m_slices.values())
36 changeSet.m_removed << i;
38 changeSet.m_removed << s.id();
37
39
38 for (int i=0; i<slices.count(); i++) {
40 m_slices.clear();
39 if (i < m_slices.count())
41
40 changeSet.m_changed << i;
42 foreach (QPieSlice s, slices) {
41 else
43 s.m_id = generateSliceId();
42 changeSet.m_added << i;
44 m_slices.insert(s.id(), s);
45 changeSet.m_added << s.id();
43 }
46 }
44
47
45 m_slices = slices;
48 updateDerivativeData();
46 emit changed(changeSet);
49 emit changed(changeSet);
50
47 return true;
51 return true;
48 }
52 }
49
53
50 bool QPieSeries::add(QList<QPieSlice> slices)
54 bool QPieSeries::add(const QList<QPieSlice>& slices)
51 {
55 {
52 if (!slices.count())
56 if (!slices.count())
53 return false;
57 return false;
54
58
55 PieChangeSet changeSet;
59 ChangeSet changeSet;
56 for (int i=0; i<slices.count(); i++)
60 foreach (QPieSlice s, slices) {
57 changeSet.m_added << m_slices.count() + i;
61 s.m_id = generateSliceId();
62 m_slices.insert(s.id(), s);
63 changeSet.m_added << s.id();
64 }
58
65
59 m_slices += slices;
66 updateDerivativeData();
60 emit changed(changeSet);
67 emit changed(changeSet);
68
61 return true;
69 return true;
62 }
70 }
63
71
64 bool QPieSeries::add(QPieSlice slice)
72 bool QPieSeries::add(const QPieSlice& slice)
65 {
73 {
66 return add(QList<QPieSlice>() << slice);
74 return add(QList<QPieSlice>() << slice);
67 }
75 }
68
76
69 QPieSlice QPieSeries::slice(int index) const
77 bool QPieSeries::update(const QPieSlice& slice)
70 {
78 {
71 if ((index >= 0) && (index < m_slices.count()))
79 if (!m_slices.contains(slice.id()))
72 return m_slices.at(index);
80 return false; // series does not contain this slice
73 return QPieSlice();
81
82 m_slices[slice.id()] = slice;
83
84 ChangeSet changeSet;
85 changeSet.m_changed << slice.id();
86 updateDerivativeData();
87 emit changed(changeSet);
88
89 return true;
74 }
90 }
75
91
76 bool QPieSeries::update(int index, QPieSlice slice)
92 bool QPieSeries::remove(QPieSliceId id)
77 {
93 {
78 if ((index >= 0) && (index < m_slices.count())) {
94 if (!m_slices.contains(id))
79 m_slices[index] = slice;
95 return false; // series does not contain this slice
80 PieChangeSet changeSet;
96
81 changeSet.m_changed << index;
97 m_slices.remove(id);
98
99 ChangeSet changeSet;
100 changeSet.m_removed << id;
101 updateDerivativeData();
82 emit changed(changeSet);
102 emit changed(changeSet);
103
83 return true;
104 return true;
84 }
105 }
85 return false;
106
107 QPieSlice QPieSeries::slice(QPieSliceId id) const
108 {
109 return m_slices.value(id);
86 }
110 }
87
111
88 void QPieSeries::setSizeFactor(qreal factor)
112 void QPieSeries::setSizeFactor(qreal factor)
89 {
113 {
90 if (factor < 0.0)
114 if (factor < 0.0)
91 return;
115 return;
92
116
93 if (m_sizeFactor != factor) {
117 if (m_sizeFactor != factor) {
94 m_sizeFactor = factor;
118 m_sizeFactor = factor;
95 emit sizeFactorChanged();
119 emit sizeFactorChanged();
96 }
120 }
97 }
121 }
98
122
99 void QPieSeries::setPosition(PiePosition position)
123 void QPieSeries::setPosition(PiePosition position)
100 {
124 {
101 if (m_position != position) {
125 if (m_position != position) {
102 m_position = position;
126 m_position = position;
103 emit positionChanged();
127 emit positionChanged();
104 }
128 }
105 }
129 }
106
130
131 QPieSliceId QPieSeries::generateSliceId()
132 {
133 // Id is quint64 so it should be enough for us.
134 // Note that id is not unique between pie series.
135 return m_sliceIdSeed++;
136 }
137
138 void QPieSeries::updateDerivativeData()
139 {
140 m_total = 0;
141 foreach (const QPieSlice& s, m_slices.values())
142 m_total += s.value();
143
144 Q_ASSERT(m_total > 0); // TODO: remove this before release
145
146 foreach (QPieSliceId id, m_slices.keys())
147 m_slices[id].m_percentage = m_slices.value(id).value() / m_total;
148 }
149
107 #include "moc_qpieseries.cpp"
150 #include "moc_qpieseries.cpp"
108
151
109 QTCOMMERCIALCHART_END_NAMESPACE
152 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,97 +1,157
1 #ifndef PIESERIES_H
1 #ifndef PIESERIES_H
2 #define PIESERIES_H
2 #define PIESERIES_H
3
3
4 #include "qchartseries.h"
4 #include "qchartseries.h"
5 #include <QObject>
5 #include <QObject>
6 #include <QRectF>
6 #include <QRectF>
7 #include <QColor>
7 #include <QColor>
8 #include <QPen>
9 #include <QBrush>
8
10
9 class QGraphicsObject;
11 class QGraphicsObject;
10 QTCOMMERCIALCHART_BEGIN_NAMESPACE
12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
11 class PiePresenter;
13 class PiePresenter;
12 class PieSlice;
14 class PieSlice;
13
15
16 typedef quint64 QPieSliceId;
17
14 class QPieSlice
18 class QPieSlice
15 {
19 {
16 public:
20 public:
17 QPieSlice()
21 QPieSlice()
18 :m_value(0), m_label("<empty>"), m_color(QColor::Invalid), m_isExploded(false) {}
22 :m_id(-1), m_value(0), m_isLabelVisible(true), m_isExploded(false), m_percentage(0) {}
19
23
20 QPieSlice(qreal value, QString label = "<empty>", QColor color = QColor::Invalid, bool exploded = false)
24 QPieSlice(qreal value, QString label = QString(), bool labelVisible = true, bool exploded = false, QPen pen = QPen(), QBrush brush = QBrush())
21 :m_value(value), m_label(label), m_color(color), m_isExploded(exploded) {}
25 :m_id(-1), m_value(value), m_label(label), m_isLabelVisible(labelVisible), m_isExploded(exploded), m_pen(pen), m_brush(brush), m_percentage(0) {}
22 public:
26
27 QPieSliceId id() const { return m_id; }
28
29 void setValue(qreal value) { m_value = value; }
30 qreal value() const { return m_value; }
31
32 void setLabel(QString label) { m_label = label; }
33 QString label() const { return m_label; }
34
35 void setLabelVisible(bool visible) { m_isLabelVisible = visible; }
36 bool isLabelVisible() const { return m_isLabelVisible; }
37
38 void setExploded(bool exploded) { m_isExploded = exploded; }
39 bool isExploded() const { return m_isExploded; }
40
41 void setPen(QPen pen) { m_pen = pen; }
42 QPen pen() const { return m_pen; }
43
44 void setBrush(QBrush brush) { m_brush = brush; }
45 QBrush brush() const { return m_brush; }
46
47 qreal percentage() const { return m_percentage; }
48
49 private:
50
51 // TODO: use private class
52 friend class QPieSeries;
53
54 QPieSliceId m_id;
23 qreal m_value;
55 qreal m_value;
24 QString m_label;
56 QString m_label;
25 QColor m_color; // TODO: should we even define color here?
57 bool m_isLabelVisible;
26 bool m_isExploded;
58 bool m_isExploded;
27 };
28
59
29 class PieChangeSet
60 QPen m_pen;
30 {
61 QBrush m_brush;
31 public:
62
32 QList<int> m_added;
63 qreal m_percentage; // generated content
33 QList<int> m_removed;
34 QList<int> m_changed;
35 };
64 };
36
65
37 class QTCOMMERCIALCHART_EXPORT QPieSeries : public QChartSeries
66 class QTCOMMERCIALCHART_EXPORT QPieSeries : public QChartSeries
38 {
67 {
39 Q_OBJECT
68 Q_OBJECT
40
69
41 public:
70 public:
42 enum PiePosition {
71 enum PiePosition {
43 PiePositionMaximized = 0,
72 PiePositionMaximized = 0,
44 PiePositionTopLeft,
73 PiePositionTopLeft,
45 PiePositionTopRight,
74 PiePositionTopRight,
46 PiePositionBottomLeft,
75 PiePositionBottomLeft,
47 PiePositionBottomRight
76 PiePositionBottomRight
48 };
77 };
49
78
79 class ChangeSet
80 {
81 public:
82 QList<QPieSliceId> m_added;
83 QList<QPieSliceId> m_removed;
84 QList<QPieSliceId> m_changed;
85 };
86
50 public:
87 public:
51 QPieSeries(QObject *parent = 0);
88 QPieSeries(QObject *parent = 0);
52 ~QPieSeries();
89 ~QPieSeries();
53
90
54 public: // from QChartSeries
91 public: // from QChartSeries
55 QChartSeriesType type() const { return QChartSeries::SeriesTypePie; }
92 QChartSeriesType type() const { return QChartSeries::SeriesTypePie; }
56 virtual bool setData(QList<qreal> data);
93 virtual bool setData(QList<qreal> data); // TODO: remove this
57
94
58 public:
95 public:
59 bool set(QList<QPieSlice> slices);
96 // TODO: should we return id/bool or what?
60 bool add(QList<QPieSlice> slices);
97 // TODO: should we prefer passing a modifiable reference?
61 bool add(QPieSlice slice);
98 bool set(const QList<QPieSlice>& slices);
99 bool add(const QList<QPieSlice>& slices);
100 bool add(const QPieSlice& slice);
101 bool update(const QPieSlice& slice);
102 bool remove(QPieSliceId id);
62
103
63 int count() const { return m_slices.count(); }
104 int count() const { return m_slices.count(); }
64
105
65 QList<QPieSlice> slices() const { return m_slices; }
106 QList<QPieSlice> slices() const { return m_slices.values(); }
66 QPieSlice slice(int index) const;
107 QList<QPieSliceId> ids() const { return m_slices.keys(); }
67 bool update(int index, QPieSlice slice);
108 QPieSlice slice(QPieSliceId id) const;
109
110 // TODO: sorting?
68
111
69 // TODO: convenience functions
112 // TODO: convenience functions
70 //void updateValue(int sliceIndex, qreal value);
113 //void updateValue(int sliceIndex, qreal value);
71 //void updateLabel(int sliceIndex, QString label);
114 //void updateLabel(int sliceIndex, QString label);
72 //void updateColor(int sliceIndex, QColor color);
115 //void updateColor(int sliceIndex, QColor color);
73 //void updateExploded(int slizeIndex, bool exploded);
116 //void updateExploded(int slizeIndex, bool exploded);
74
117
118 // TODO: customization
119 // set/get pen/brush
120 // - for label
121 // - for whole pie/slice
122
75 void setSizeFactor(qreal sizeFactor);
123 void setSizeFactor(qreal sizeFactor);
76 qreal sizeFactor() const { return m_sizeFactor; }
124 qreal sizeFactor() const { return m_sizeFactor; }
77
125
78 void setPosition(PiePosition position);
126 void setPosition(PiePosition position);
79 PiePosition position() const { return m_position; }
127 PiePosition position() const { return m_position; }
80
128
81 Q_SIGNALS:
129 Q_SIGNALS:
82 void changed(const PieChangeSet& changeSet);
130 void changed(const QPieSeries::ChangeSet& changeSet);
83 void sizeFactorChanged();
131 void sizeFactorChanged();
84 void positionChanged();
132 void positionChanged();
133 //void sliceClicked(QPieSliceId id);
134 //void sliceHoverEnter(QPieSliceId id);
135 //void sliceHoverLeave(QPieSliceId id);
136
137 private:
138 QPieSliceId generateSliceId();
139 void updateDerivativeData();
85
140
86 private:
141 private:
87 Q_DISABLE_COPY(QPieSeries)
142 Q_DISABLE_COPY(QPieSeries)
88 friend class PiePresenter;
143
89 // TODO: use PIML
144 // TODO: use PIML
90 QList<QPieSlice> m_slices;
145 friend class PiePresenter;
146 friend class PieSlice;
147
148 QHash<QPieSliceId, QPieSlice> m_slices;
91 qreal m_sizeFactor;
149 qreal m_sizeFactor;
92 PiePosition m_position;
150 PiePosition m_position;
151 qreal m_total;
152 QPieSliceId m_sliceIdSeed;
93 };
153 };
94
154
95 QTCOMMERCIALCHART_END_NAMESPACE
155 QTCOMMERCIALCHART_END_NAMESPACE
96
156
97 #endif // PIESERIES_H
157 #endif // PIESERIES_H
General Comments 0
You need to be logged in to leave comments. Login now