##// END OF EJS Templates
Use signals from pieseries, visible hover and exploding slices
Jani Honkonen -
r157:036a0ec8efe0
parent child
Show More
@@ -1,33 +1,33
1 1 #include <QtGui/QApplication>
2 2 #include <QMainWindow>
3 3 #include <cmath>
4 4 #include <qchartglobal.h>
5 5 #include <qchartview.h>
6 6 #include <qpieseries.h>
7 7
8 8 QTCOMMERCIALCHART_USE_NAMESPACE
9 9
10 10 int main(int argc, char *argv[])
11 11 {
12 12 QApplication a(argc, argv);
13 13
14 14 // Create widget and scatter series
15 15 QChartView *chartWidget = new QChartView();
16 16 QPieSeries *series = qobject_cast<QPieSeries *>(chartWidget->createSeries(QChartSeries::SeriesTypePie));
17 17 Q_ASSERT(series);
18 18
19 19 // Add test data to the series
20 series->add(QPieSlice(1, "test1", Qt::red));
20 series->add(QPieSlice(1, "test1", Qt::red, true));
21 21 series->add(QPieSlice(2, "test2", Qt::green));
22 22 series->add(QPieSlice(3, "test3", Qt::blue));
23 series->add(QPieSlice(4, "test4", Qt::darkRed));
23 series->add(QPieSlice(4, "test4", Qt::darkRed, true));
24 24 series->add(QPieSlice(5, "test5", Qt::darkGreen));
25 25
26 26 // Use the chart widget as the central widget
27 27 QMainWindow w;
28 28 w.resize(640, 480);
29 29 w.setCentralWidget(chartWidget);
30 30 w.show();
31 31
32 32 return a.exec();
33 33 }
@@ -1,272 +1,272
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 //series
7 7 #include "barchartseries.h"
8 8 #include "stackedbarchartseries.h"
9 9 #include "percentbarchartseries.h"
10 10 #include "qlinechartseries.h"
11 11 #include "qpieseries.h"
12 12 //items
13 13 #include "axisitem_p.h"
14 14 #include "bargroup.h"
15 15 #include "stackedbargroup.h"
16 16 #include "linechartitem_p.h"
17 17 #include "percentbargroup.h"
18 18 #include "linechartanimationitem_p.h"
19 19 #include "piepresenter.h"
20 20
21 21 QTCOMMERCIALCHART_BEGIN_NAMESPACE
22 22
23 23 ChartPresenter::ChartPresenter(QChart* chart,ChartDataSet* dataset):QObject(chart),
24 24 m_chart(chart),
25 25 m_dataset(dataset),
26 26 m_chartTheme(0),
27 27 m_domainIndex(0),
28 28 m_marginSize(0),
29 29 m_axisX(new QChartAxis(this)),
30 30 m_axisY(new QChartAxis(this)),
31 31 m_rect(QRectF(QPoint(0,0),m_chart->size()))
32 32 {
33 33 setChartTheme(QChart::ChartThemeDefault);
34 34 m_axisItems[m_axisX] = new AxisItem(m_axisX,AxisItem::X_AXIS,m_chart);
35 35 m_axisItems[m_axisY] = new AxisItem(m_axisY,AxisItem::Y_AXIS,m_chart);
36 36 createConnections();
37 37 }
38 38
39 39 ChartPresenter::~ChartPresenter()
40 40 {
41 41 }
42 42
43 43 void ChartPresenter::createConnections()
44 44 {
45 45 QObject::connect(m_chart,SIGNAL(geometryChanged()),this,SLOT(handleGeometryChanged()));
46 46 QObject::connect(m_dataset,SIGNAL(seriesAdded(QChartSeries*)),this,SLOT(handleSeriesAdded(QChartSeries*)));
47 47
48 48 QMapIterator<QChartAxis*,AxisItem*> i(m_axisItems);
49 49
50 50 while (i.hasNext()) {
51 51 i.next();
52 52 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),i.value(),SLOT(handleGeometryChanged(const QRectF&)));
53 53 QObject::connect(m_dataset,SIGNAL(domainChanged(const Domain&)),i.value(),SLOT(handleDomainChanged(const Domain&)));
54 54 }
55 55 }
56 56
57 57 void ChartPresenter::handleGeometryChanged()
58 58 {
59 59 m_rect = QRectF(QPoint(0,0),m_chart->size());
60 60 m_rect.adjust(m_marginSize,m_marginSize, -m_marginSize, -m_marginSize);
61 61 Q_ASSERT(m_rect.isValid());
62 62 emit geometryChanged(m_rect);
63 63 }
64 64
65 65 int ChartPresenter::margin() const
66 66 {
67 67 return m_marginSize;
68 68 }
69 69
70 70 void ChartPresenter::setMargin(int margin)
71 71 {
72 72 m_marginSize = margin;
73 73 }
74 74
75 75 void ChartPresenter::handleSeriesAdded(QChartSeries* series)
76 76 {
77 77 switch(series->type())
78 78 {
79 79 case QChartSeries::SeriesTypeLine: {
80 80 QLineChartSeries* lineSeries = static_cast<QLineChartSeries*>(series);
81 81 LineChartItem* item = new LineChartAnimationItem(this,lineSeries,m_chart);
82 82 m_chartTheme->decorate(item,lineSeries,m_chartItems.count());
83 83 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),item,SLOT(handleGeometryChanged(const QRectF&)));
84 84 QObject::connect(m_dataset,SIGNAL(domainChanged(const Domain&)),item,SLOT(handleDomainChanged(const Domain&)));
85 85 QObject::connect(lineSeries,SIGNAL(changed(int)),item,SLOT(handleModelChanged(int)));
86 86 m_chartItems.insert(series,item);
87 87 break;
88 88 }
89 89
90 90 case QChartSeries::SeriesTypeBar: {
91 91 BarChartSeries* barSeries = static_cast<BarChartSeries*>(series);
92 92 BarGroup* item = new BarGroup(*barSeries,m_chart);
93 93 m_chartTheme->decorate(item,barSeries,m_chartItems.count());
94 94 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),item,SLOT(handleGeometryChanged(const QRectF&)));
95 95 QObject::connect(m_dataset,SIGNAL(domainChanged(const Domain&)),item,SLOT(handleDomainChanged(const Domain&)));
96 96 QObject::connect(barSeries,SIGNAL(changed(int)),item,SLOT(handleModelChanged(int)));
97 97 m_chartItems.insert(series,item);
98 98 // m_axisXItem->setVisible(false);
99 99 break;
100 100 }
101 101
102 102 case QChartSeries::SeriesTypeStackedBar: {
103 103
104 104 StackedBarChartSeries* stackedBarSeries = static_cast<StackedBarChartSeries*>(series);
105 105 StackedBarGroup* item = new StackedBarGroup(*stackedBarSeries,m_chart);
106 106 m_chartTheme->decorate(item,stackedBarSeries,m_chartItems.count());
107 107 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),item,SLOT(handleGeometryChanged(const QRectF&)));
108 108 QObject::connect(m_dataset,SIGNAL(domainChanged(const Domain&)),item,SLOT(handleDomainChanged(const Domain&)));
109 109 QObject::connect(stackedBarSeries,SIGNAL(changed(int)),item,SLOT(handleModelChanged(int)));
110 110 m_chartItems.insert(series,item);
111 111 break;
112 112 }
113 113
114 114 case QChartSeries::SeriesTypePercentBar: {
115 115
116 116 PercentBarChartSeries* percentBarSeries = static_cast<PercentBarChartSeries*>(series);
117 117 PercentBarGroup* item = new PercentBarGroup(*percentBarSeries,m_chart);
118 118 m_chartTheme->decorate(item,percentBarSeries ,m_chartItems.count());
119 119 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),item,SLOT(handleGeometryChanged(const QRectF&)));
120 120 QObject::connect(m_dataset,SIGNAL(domainChanged(const Domain&)),item,SLOT(handleDomainChanged(const Domain&)));
121 121 QObject::connect(percentBarSeries,SIGNAL(changed(int)),item,SLOT(handleModelChanged(int)));
122 122 m_chartItems.insert(series,item);
123 123 break;
124 124 }
125 125 /*
126 126 case QChartSeries::SeriesTypeScatter: {
127 127 QScatterSeries *scatterSeries = qobject_cast<QScatterSeries *>(series);
128 128 scatterSeries->d->m_theme = m_chartTheme->themeForSeries();
129 129 scatterSeries->d->setParentItem(this);
130 130 scatterSeries->d->m_boundingRect = m_rect.adjusted(margin(),margin(), -margin(), -margin());
131 131 m_chartItems << scatterSeries->d;
132 132 m_chartTheme->addObserver(scatterSeries->d);
133 133
134 134 foreach (qreal x, scatterSeries->d->m_x) {
135 135 domain.m_minX = qMin(domain.m_minX, x);
136 136 domain.m_maxX = qMax(domain.m_maxX, x);
137 137 }
138 138 foreach (qreal y, scatterSeries->d->m_y) {
139 139 domain.m_minY = qMin(domain.m_minY, y);
140 140 domain.m_maxY = qMax(domain.m_maxY, y);
141 141 }
142 142
143 143 break;
144 144 }
145 145 */
146 146
147 147 case QChartSeries::SeriesTypePie: {
148 148 QPieSeries *pieSeries = qobject_cast<QPieSeries *>(series);
149 149 PiePresenter* pie = new PiePresenter(m_chart, pieSeries);
150 pieSeries->m_piePresenter = pie; // TODO: remove this pointer passing use signals&slots
150 QObject::connect(pieSeries, SIGNAL(changed(const PieChangeSet&)), pie, SLOT(handleSeriesChanged(const PieChangeSet&)));
151 151 QObject::connect(this, SIGNAL(geometryChanged(const QRectF&)), pie, SLOT(handleGeometryChanged(const QRectF&)));
152 152 QObject::connect(m_dataset, SIGNAL(domainChanged(const Domain&)), pie, SLOT(handleDomainChanged(const Domain&)));
153 153 m_chartItems.insert(series, pie);
154 154 break;
155 155 }
156 156
157 157 default: {
158 158 qDebug()<< "Series type" << series->type() << "not implemented.";
159 159 break;
160 160 }
161 161 }
162 162
163 163 if(m_rect.isValid()) emit geometryChanged(m_rect);
164 164 }
165 165
166 166 void ChartPresenter::handleSeriesChanged(QChartSeries* series)
167 167 {
168 168 //TODO:
169 169 }
170 170
171 171 void ChartPresenter::zoomInToRect(const QRectF& rect)
172 172 {
173 173 if(!rect.isValid()) return;
174 174 QRectF r = rect.normalized();
175 175 r.translate(-m_marginSize, -m_marginSize);
176 176 Domain domain (m_dataset->domain().subDomain(r,m_rect.width(),m_rect.height()));
177 177 m_dataset->addDomain(domain);
178 178 }
179 179
180 180 void ChartPresenter::zoomIn()
181 181 {
182 182 if (!m_dataset->nextDomain()) {
183 183 QRectF rect = m_rect;
184 184 rect.setWidth(rect.width()/2);
185 185 rect.setHeight(rect.height()/2);
186 186 rect.moveCenter(m_rect.center());
187 187 Domain domain (m_dataset->domain().subDomain(rect,m_rect.width(),m_rect.height()));
188 188 m_dataset->addDomain(domain);
189 189 }
190 190 }
191 191
192 192 void ChartPresenter::zoomOut()
193 193 {
194 194 m_dataset->previousDomain();
195 195 }
196 196
197 197 void ChartPresenter::zoomReset()
198 198 {
199 199 m_dataset->clearDomains();
200 200 }
201 201
202 202 void ChartPresenter::setChartTheme(QChart::ChartTheme theme)
203 203 {
204 204 delete m_chartTheme;
205 205
206 206 m_chartTheme = ChartTheme::createTheme(theme);
207 207
208 208 m_chartTheme->decorate(m_chart);
209 209 QMapIterator<QChartSeries*,ChartItem*> i(m_chartItems);
210 210
211 211 int index=0;
212 212 while (i.hasNext()) {
213 213 i.next();
214 214 index++;
215 215 m_chartTheme->decorate(i.value(),i.key(),index);
216 216 }
217 217 }
218 218
219 219
220 220 QChart::ChartTheme ChartPresenter::chartTheme()
221 221 {
222 222 return m_chartTheme->id();
223 223 }
224 224
225 225 QChartAxis* ChartPresenter::axisX()
226 226 {
227 227 return m_axisX;
228 228 }
229 229
230 230 QChartAxis* ChartPresenter::axisY()
231 231 {
232 232 return m_axisY;
233 233 }
234 234
235 235 QChartAxis* ChartPresenter::addAxisX()
236 236 {
237 237 //only one axis
238 238 if(m_axisX==0){
239 239 m_axisX = new QChartAxis(this);
240 240 m_axisItems[m_axisX] = new AxisItem(m_axisX,AxisItem::X_AXIS,m_chart);
241 241 }
242 242 return m_axisX;
243 243 }
244 244
245 245 QChartAxis* ChartPresenter::addAxisY()
246 246 {
247 247 if(m_axisY==0){
248 248 m_axisY = new QChartAxis(this);
249 249 m_axisItems[m_axisY] = new AxisItem(m_axisY,AxisItem::Y_AXIS,m_chart);
250 250 return m_axisY;
251 251 }
252 252
253 253 QChartAxis* axis = new QChartAxis(this);
254 254 m_axisItems[axis] = new AxisItem(axis,AxisItem::Y_AXIS,m_chart);
255 255 return axis;
256 256 }
257 257
258 258 void ChartPresenter::removeAxis(QChartAxis* axis)
259 259 {
260 260 AxisItem* item = m_axisItems.take(axis);
261 261 if(item){
262 262 delete item;
263 263 delete axis;
264 264 }
265 265 //reset pointers to default ones
266 266 if(axis == m_axisX) m_axisX=0;
267 267 else if(axis == m_axisY) m_axisY=0;
268 268 }
269 269
270 270 #include "moc_chartpresenter_p.cpp"
271 271
272 272 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,112 +1,113
1 1
2 2 #include "piepresenter.h"
3 3 #include "pieslice.h"
4 4 #include <QDebug>
5 5
6 6 QTCOMMERCIALCHART_BEGIN_NAMESPACE
7 7
8 8 PiePresenter::PiePresenter(QGraphicsItem *parent, QPieSeries *series) :
9 9 ChartItem(parent),
10 10 m_pieSeries(series)
11 11 {
12 12 Q_ASSERT(parent);
13 13 Q_ASSERT(series);
14 14 m_rect = parentItem()->boundingRect();
15 15 setAcceptHoverEvents(true);
16 16 }
17 17
18 18 PiePresenter::~PiePresenter()
19 19 {
20 20 while (m_slices.count())
21 21 delete m_slices.takeLast();
22 22 }
23 23
24 void PiePresenter::seriesChanged()
24 void PiePresenter::handleSeriesChanged(const PieChangeSet& changeSet)
25 25 {
26 26 const qreal fullPie = 360;
27 27 qreal total = 0;
28 28
29 29 // calculate total
30 30 foreach (QPieSlice sliceData, m_pieSeries->slices())
31 31 total += sliceData.m_value;
32 32
33 33 // TODO: no need to create new slices in case size changed; we should re-use the existing ones
34 34 while (m_slices.count())
35 35 delete m_slices.takeLast();
36 36
37 37 // create slices
38 38 qreal angle = 0;
39 39 for (int i=0; i<m_pieSeries->count(); i++) {
40 40 QPieSlice sliceData = m_pieSeries->slice(i);
41 41 qreal span = sliceData.m_value / total * fullPie;
42 42 PieSlice *slice = new PieSlice(this, i, angle, span);
43 43 m_slices.append(slice);
44 44 angle += span;
45 45 }
46
47 resize();
48 46 }
49 47
50 void PiePresenter::resize()
48 void PiePresenter::updateGeometry()
51 49 {
50 prepareGeometryChange();
51
52 52 m_pieRect = m_rect;
53 53
54 54 if (m_pieRect.width() < m_pieRect.height()) {
55 m_pieRect.setWidth(m_pieRect.width() * m_pieSeries->m_sizeFactor);
55 m_pieRect.setWidth(m_pieRect.width() * m_pieSeries->sizeFactor());
56 56 m_pieRect.setHeight(m_pieRect.width());
57 57 m_pieRect.moveCenter(m_rect.center());
58 58 } else {
59 m_pieRect.setHeight(m_pieRect.height() * m_pieSeries->m_sizeFactor);
59 m_pieRect.setHeight(m_pieRect.height() * m_pieSeries->sizeFactor());
60 60 m_pieRect.setWidth(m_pieRect.height());
61 61 m_pieRect.moveCenter(m_rect.center());
62 62 }
63 63
64 switch (m_pieSeries->m_position) {
64 switch (m_pieSeries->position()) {
65 65 case QPieSeries::PiePositionTopLeft: {
66 66 m_pieRect.setHeight(m_pieRect.height() / 2);
67 67 m_pieRect.setWidth(m_pieRect.height());
68 68 m_pieRect.moveCenter(QPointF(m_rect.center().x() / 2, m_rect.center().y() / 2));
69 69 break;
70 70 }
71 71 case QPieSeries::PiePositionTopRight: {
72 72 m_pieRect.setHeight(m_pieRect.height() / 2);
73 73 m_pieRect.setWidth(m_pieRect.height());
74 74 m_pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, m_rect.center().y() / 2));
75 75 break;
76 76 }
77 77 case QPieSeries::PiePositionBottomLeft: {
78 78 m_pieRect.setHeight(m_pieRect.height() / 2);
79 79 m_pieRect.setWidth(m_pieRect.height());
80 80 m_pieRect.moveCenter(QPointF(m_rect.center().x() / 2, (m_rect.center().y() / 2) * 3));
81 81 break;
82 82 }
83 83 case QPieSeries::PiePositionBottomRight: {
84 84 m_pieRect.setHeight(m_pieRect.height() / 2);
85 85 m_pieRect.setWidth(m_pieRect.height());
86 86 m_pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, (m_rect.center().y() / 2) * 3));
87 87 break;
88 88 }
89 89 default:
90 90 break;
91 91 }
92 92
93 93 qDebug() << "presentation rect:" << m_rect;
94 94 qDebug() << "pie rect:" << m_pieRect;
95 foreach (PieSlice *slice, m_slices)
96 slice->updateGeometry();
95 97 }
96 98
97 99 void PiePresenter::handleDomainChanged(const Domain& domain)
98 100 {
99 101 // TODO
100 102 }
101 103
102 104 void PiePresenter::handleGeometryChanged(const QRectF& rect)
103 105 {
104 // TODO: allow user setting the size?
105 // TODO: allow user defining the margins?
106 m_rect.setSize(rect.size());
107 resize();
106 m_rect = rect;
107 updateGeometry();
108
108 109 }
109 110
110 111 #include "moc_piepresenter.cpp"
111 112
112 113 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,43 +1,43
1 1 #ifndef PIEPRESENTER_H
2 2 #define PIEPRESENTER_H
3 3
4 4 #include "chartitem_p.h"
5 5 #include "qpieseries.h"
6 6
7 7 class QGraphicsItem;
8 8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9 9 class PieSlice;
10 10
11 11 class PiePresenter : public QObject, public ChartItem
12 12 {
13 13 Q_OBJECT
14 14
15 15 public:
16 16 // TODO: use a generic data class instead of x and y
17 17 PiePresenter(QGraphicsItem *parent, QPieSeries *series);
18 18 ~PiePresenter();
19 19
20 public: // from ChartItem
20 public: // from QGraphicsItem
21 21 QRectF boundingRect() const { return m_rect; }
22 22 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) {}
23 23
24 24 public:
25 void seriesChanged();
26 void resize();
25 void updateGeometry();
27 26 QRectF pieRect() const { return m_pieRect; }
28 27
29 28 public Q_SLOTS:
29 void handleSeriesChanged(const PieChangeSet& changeSet);
30 30 void handleDomainChanged(const Domain& domain);
31 31 void handleGeometryChanged(const QRectF& rect);
32 32
33 33 private:
34 34 friend class PieSlice;
35 35 QList<PieSlice*> m_slices;
36 36 QPieSeries *m_pieSeries;
37 37 QRectF m_rect;
38 38 QRectF m_pieRect;
39 39 };
40 40
41 41 QTCOMMERCIALCHART_END_NAMESPACE
42 42
43 43 #endif // PIEPRESENTER_H
@@ -1,91 +1,124
1 1 #include "pieslice.h"
2 2 #include "piepresenter.h"
3 #include "qpieseries.h"
3 4 #include <QPainter>
4 5 #include <QDebug>
6 #include <qmath.h>
5 7
6 8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
7 9
8 PieSlice::PieSlice(PiePresenter *piePresentation, int seriesIndex, qreal startAngle, qreal span)
9 :QGraphicsItem(piePresentation),
10 #define PI 3.14159265
11 #define EXPLODE_OFFSET 20
12
13 QPointF offset(qreal angle, qreal length)
14 {
15 qreal dx = qSin(angle*(PI/180)) * length;
16 qreal dy = qCos(angle*(PI/180)) * length;
17 return QPointF(dx, -dy);
18 }
19
20 PieSlice::PieSlice(PiePresenter *presenter, int seriesIndex, qreal startAngle, qreal span)
21 :QGraphicsItem(presenter),
22 m_label(new QGraphicsTextItem(this)),
10 23 m_seriesIndex(seriesIndex),
11 24 m_startAngle(startAngle),
12 25 m_span(span)
13 26 {
14 Q_ASSERT(piePresentation);
27 Q_ASSERT(presenter);
15 28 setAcceptHoverEvents(true);
16 29 setAcceptedMouseButtons(Qt::LeftButton);
30 updateGeometry();
31
32 // TODO: use themes
33 m_pen = QPen(Qt::black);
34 m_brush = QBrush(sliceData().m_color);
17 35 }
18 36
19 37 PieSlice::~PieSlice()
20 38 {
21 39 }
22 40
23 41 QRectF PieSlice::boundingRect() const
24 42 {
25 return shape().boundingRect();
43 return m_rect;
26 44 }
27 45
28 46 QPainterPath PieSlice::shape() const
29 47 {
30 QRectF rect = (static_cast<PiePresenter*>(parentItem()))->pieRect();
31 qreal angle = (-m_startAngle) + (90);
32 qreal span = -m_span;
33
34 QPainterPath path;
35 path.moveTo(rect.center());
36 path.arcTo(rect, angle, span);
37
38 // TODO: draw the shape so that it might have a hole in the center
39 // - Sin & Cos will be needed to find inner/outer arc endpoints
40
41 // dx, dy are offsets from the center
42 //qreal l = boundingRect().height();
43 //qreal dx = qSin(angle*(M_PI/180)) * l;
44 //qreal dy = qCos(angle*(M_PI/180)) * l;
45
46 // TODO: exploded slice?
47
48 return path;
48 return m_path;
49 49 }
50 50
51 51 void PieSlice::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
52 52 {
53 53 painter->setRenderHint(QPainter::Antialiasing);
54 // TODO: how to map theme settings to a pie slice? Now we
55 //painter->setPen(m_theme.linePen);
56 // TODO:
57
58 QPieSlice data = (static_cast<PiePresenter*>(parentItem()))->m_pieSeries->slice(m_seriesIndex);
59 painter->setBrush(data.m_color);
60 54
61
62 //painter->setBrush(m_theme.linePen.color());
63
64 // From Qt docs:
65 // The startAngle and spanAngle must be specified in 1/16th of a degree, i.e. a full circle equals 5760 (16 * 360).
66 // Positive values for the angles mean counter-clockwise while negative values mean the clockwise direction.
67 // Zero degrees is at the 3 o'clock position.
68 //
69 // For sake of simplicity convert this so that zero degrees is at 12 o'clock and full circle is 360.
70 //qreal angle = (-m_startAngle*16) + (90*16);
71 //qreal span = -m_span*16;
72 //painter->drawPie(boundingRect(), angle, span);
73
74 painter->drawPath(shape());
55 // TODO: themes
56 painter->setPen(m_pen);
57 painter->setBrush(m_brush);
58 painter->drawPath(m_path);
75 59
76 60 // Draw the label
77 61 // TODO: do this better
78 painter->drawText(boundingRect().center(), data.m_label);
62 //QTextItem text;
63 painter->drawText(m_center, sliceData().m_label);
79 64 }
80 65
81 66 void PieSlice::hoverEnterEvent(QGraphicsSceneHoverEvent * event)
82 67 {
83 68 QGraphicsItem::hoverEnterEvent(event);
84 qDebug() << "hover" << m_seriesIndex << m_startAngle << m_span;
69 m_brush = QBrush(sliceData().m_color.lighter());
70 update();
71 }
72
73 void PieSlice::hoverLeaveEvent(QGraphicsSceneHoverEvent * event)
74 {
75 QGraphicsItem::hoverLeaveEvent(event);
76 m_brush = QBrush(sliceData().m_color);
77 update();
85 78 }
86 79
87 80 void PieSlice::mousePressEvent(QGraphicsSceneMouseEvent *event)
88 81 {
89 82 QGraphicsItem::mousePressEvent(event);
83 QPieSlice data = sliceData();
84 data.m_isExploded = !data.m_isExploded;
85 (static_cast<PiePresenter*>(parentItem()))->m_pieSeries->update(m_seriesIndex, data);
86 }
87
88 void PieSlice::updateGeometry()
89 {
90 prepareGeometryChange();
91
92 PiePresenter *presenter = static_cast<PiePresenter*>(parentItem());
93 QRectF rect = presenter->pieRect();
94 rect.adjust(EXPLODE_OFFSET, EXPLODE_OFFSET, -EXPLODE_OFFSET ,-EXPLODE_OFFSET);
95
96 qreal centerAngle = m_startAngle + (m_span/2);
97
98 if (presenter->m_pieSeries->slice(m_seriesIndex).m_isExploded) {
99 QPointF d = offset((centerAngle), EXPLODE_OFFSET);
100 rect.translate(d.x(), d.y());
101 }
102
103 qreal angle = (-m_startAngle) + (90);
104 qreal span = -m_span;
105
106 QPainterPath path;
107 path.moveTo(rect.center());
108 path.arcTo(rect, angle, span);
109
110 // TODO: draw the shape so that it might have a hole in the center
111
112 m_path = path;
113 m_rect = path.boundingRect();
114
115 qreal radius = rect.height() / 2;
116 m_center = rect.center() + offset(centerAngle, radius / 2);
90 117 }
118
119 QPieSlice PieSlice::sliceData()
120 {
121 return (static_cast<PiePresenter*>(parentItem()))->m_pieSeries->slice(m_seriesIndex);
122 }
123
91 124 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,36 +1,49
1 1 #ifndef PIESLICE_H
2 2 #define PIESLICE_H
3 3
4 4 #include "qchartglobal.h"
5 5 #include "charttheme_p.h"
6 #include "qpieseries.h"
6 7 #include <QGraphicsItem>
7 8 #include <QRectF>
8 9 #include <QColor>
10 #include <QPen>
9 11
10 12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
11 13 class PiePresenter;
12 14
13 15 class PieSlice : public QGraphicsItem
14 16 {
15 17 public:
16 PieSlice(PiePresenter *piePresentation, int seriesIndex, qreal startAngle, qreal span);
18 PieSlice(PiePresenter *piePresenter, int seriesIndex, qreal startAngle, qreal span);
17 19 ~PieSlice();
18 20
19 21 public: // from QGraphicsItem
20 22 QRectF boundingRect() const;
21 23 QPainterPath shape() const;
22 24 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
23 25 void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
26 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
24 27 void mousePressEvent(QGraphicsSceneMouseEvent *event);
25 28
29 public:
30 void updateGeometry();
31
32 private:
33 QPieSlice sliceData();
34
26 35 private:
36 QGraphicsTextItem* m_label;
27 37 int m_seriesIndex;
28 38 qreal m_startAngle;
29 39 qreal m_span;
40 QPainterPath m_path;
30 41 QRectF m_rect;
31 //SeriesTheme m_theme;
42 QPointF m_center;
43 QPen m_pen;
44 QBrush m_brush;
32 45 };
33 46
34 47 QTCOMMERCIALCHART_END_NAMESPACE
35 48
36 49 #endif // PIESLICE_H
@@ -1,93 +1,87
1 1 #include "qpieseries.h"
2 2 #include "piepresenter.h"
3 3 #include "pieslice.h"
4 4 #include <QDebug>
5 5
6 6 QTCOMMERCIALCHART_BEGIN_NAMESPACE
7 7
8 8 QPieSeries::QPieSeries(QObject *parent) :
9 9 QChartSeries(parent),
10 m_piePresenter(0),
11 10 m_sizeFactor(1.0),
12 11 m_position(PiePositionMaximized)
13 12 {
14 13 }
15 14
16 15 QPieSeries::~QPieSeries()
17 16 {
18 17
19 18 }
20 19
21 20 void QPieSeries::set(QList<QPieSlice> slices)
22 21 {
23 m_slices = slices;
24 if (m_piePresenter) {
25 m_piePresenter->seriesChanged();
26 m_piePresenter->update();
22 PieChangeSet changeSet;
23
24 for (int i=slices.count(); i<m_slices.count(); i++)
25 changeSet.m_removed << i;
26
27 for (int i=0; i<slices.count(); i++) {
28 if (i < m_slices.count())
29 changeSet.m_changed << i;
30 else
31 changeSet.m_added << i;
27 32 }
33
34 m_slices = slices;
35 emit changed(changeSet);
28 36 }
29 37
30 38 void QPieSeries::add(QList<QPieSlice> slices)
31 39 {
40 PieChangeSet changeSet;
41 for (int i=0; i<slices.count(); i++)
42 changeSet.m_added << m_slices.count() + i;
43
32 44 m_slices += slices;
33 if (m_piePresenter) {
34 m_piePresenter->seriesChanged();
35 // TODO: m_piePresenter->seriesAppended()??
36 m_piePresenter->update();
37 }
45 emit changed(changeSet);
38 46 }
39 47
40 48 void QPieSeries::add(QPieSlice slice)
41 49 {
42 50 add(QList<QPieSlice>() << slice);
43 51 }
44 52
45 53 QPieSlice QPieSeries::slice(int index) const
46 54 {
47 55 if ((index >= 0) && (index < m_slices.count()))
48 56 return m_slices.at(index);
49 57 return QPieSlice();
50 58 }
51 59
52 60 bool QPieSeries::update(int index, QPieSlice slice)
53 61 {
54 62 if ((index >= 0) && (index < m_slices.count())) {
55 63 m_slices[index] = slice;
56 if (m_piePresenter) {
57 m_piePresenter->seriesChanged();
58 // TODO: for a nice animation we need something like
59 // m_piePresenter->sliceChanged(index, oldslice, newslice)
60 m_piePresenter->update();
61 }
64 PieChangeSet changeSet;
65 changeSet.m_changed << index;
66 emit changed(changeSet);
62 67 return true;
63 68 }
64 69 return false;
65 70 }
66 71
67 72 void QPieSeries::setSizeFactor(qreal factor)
68 73 {
69 74 if (factor > 0.0)
70 75 m_sizeFactor = factor;
71
72 if (m_piePresenter) {
73 m_piePresenter->resize();
74 m_piePresenter->update();
75 // TODO: do we have to update the parent item also?
76 // - potential issue: what if this function is called from the parent context?
77 }
76 emit sizeFactorChanged();
78 77 }
79 78
80 79 void QPieSeries::setPosition(PiePosition position)
81 80 {
82 81 m_position = position;
83 if (m_piePresenter) {
84 m_piePresenter->resize();
85 m_piePresenter->update();
86 // TODO: do we have to update the parent item also?
87 // - potential issue: what if this function is called from the parent context?
88 }
82 emit positionChanged();
89 83 }
90 84
91 85 #include "moc_qpieseries.cpp"
92 86
93 87 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,86 +1,95
1 1 #ifndef PIESERIES_H
2 2 #define PIESERIES_H
3 3
4 4 #include "qchartseries.h"
5 5 #include <QObject>
6 6 #include <QRectF>
7 7 #include <QColor>
8 8
9 9 class QGraphicsObject;
10 10 QTCOMMERCIALCHART_BEGIN_NAMESPACE
11 11 class PiePresenter;
12 12 class PieSlice;
13 13
14 14 class QPieSlice
15 15 {
16 16 public:
17 17 QPieSlice()
18 18 :m_value(0), m_label("<empty>"), m_color(Qt::white), m_isExploded(false) {}
19 19
20 20 QPieSlice(qreal value, QString label, QColor color, bool exploded = false)
21 21 :m_value(value), m_label(label), m_color(color), m_isExploded(exploded) {}
22 22 public:
23 23 qreal m_value;
24 24 QString m_label;
25 25 QColor m_color;
26 26 bool m_isExploded;
27 27 };
28 28
29 class PieChangeSet
30 {
31 public:
32 QList<int> m_added;
33 QList<int> m_removed;
34 QList<int> m_changed;
35 };
36
29 37 class QTCOMMERCIALCHART_EXPORT QPieSeries : public QChartSeries
30 38 {
31 39 Q_OBJECT
32 40
33 41 public:
34 42 enum PiePosition {
35 43 PiePositionMaximized = 0,
36 44 PiePositionTopLeft,
37 45 PiePositionTopRight,
38 46 PiePositionBottomLeft,
39 47 PiePositionBottomRight
40 48 };
41 49
42 50 public:
43 51 QPieSeries(QObject *parent = 0);
44 52 ~QPieSeries();
45 53
46 54 public: // from QChartSeries
47 55 QChartSeriesType type() const { return QChartSeries::SeriesTypePie; }
48 56
49 57 public:
50 58 void set(QList<QPieSlice> slices);
51 59 void add(QList<QPieSlice> slices);
52 60 void add(QPieSlice slice);
53 61
54 62 int count() const { return m_slices.count(); }
55 63
56 64 QList<QPieSlice> slices() const { return m_slices; }
57 65 QPieSlice slice(int index) const;
58 66 bool update(int index, QPieSlice slice);
59 67
60 68 // TODO: convenience functions
61 69 //void updateValue(int sliceIndex, qreal value);
62 70 //void updateLabel(int sliceIndex, QString label);
63 71 //void updateColor(int sliceIndex, QColor color);
64 72 //void updateExploded(int slizeIndex, bool exploded);
65 73
66 74 void setSizeFactor(qreal sizeFactor);
67 75 qreal sizeFactor() const { return m_sizeFactor; }
68 76
69 77 void setPosition(PiePosition position);
70 78 PiePosition position() const { return m_position; }
71 79
80 Q_SIGNALS:
81 void changed(const PieChangeSet& changeSet);
82 void sizeFactorChanged();
83 void positionChanged();
84
72 85 private:
73 86 Q_DISABLE_COPY(QPieSeries)
74 87 // TODO: use PIML
75 friend class ChartPresenter;
76 friend class ChartDataSet;
77 friend class PiePresenter;
78 PiePresenter *m_piePresenter;
79 88 QList<QPieSlice> m_slices;
80 89 qreal m_sizeFactor;
81 90 PiePosition m_position;
82 91 };
83 92
84 93 QTCOMMERCIALCHART_END_NAMESPACE
85 94
86 95 #endif // PIESERIES_H
General Comments 0
You need to be logged in to leave comments. Login now