##// END OF EJS Templates
Make pie fit better inside its given rectangle. Label texts still go outside. Needs a bit more work...
Jani Honkonen -
r289:46889b1144e0
parent child
Show More
@@ -1,43 +1,40
1 #include <QtGui/QApplication>
1 #include <QtGui/QApplication>
2 #include <QMainWindow>
2 #include <QMainWindow>
3 #include <qchartglobal.h>
3 #include <qchartglobal.h>
4 #include <qchartview.h>
4 #include <qchartview.h>
5 #include <qpieseries.h>
5 #include <qpieseries.h>
6 #include <qpieslice.h>
6 #include <qpieslice.h>
7 #include "customslice.h"
7 #include "customslice.h"
8
8
9 QTCOMMERCIALCHART_USE_NAMESPACE
9 QTCOMMERCIALCHART_USE_NAMESPACE
10
10
11 int main(int argc, char *argv[])
11 int main(int argc, char *argv[])
12 {
12 {
13 QApplication a(argc, argv);
13 QApplication a(argc, argv);
14
14
15 QMainWindow window;
15 QMainWindow window;
16
16
17 QPieSeries *series = new QPieSeries();
17 QPieSeries *series = new QPieSeries();
18 series->add(5, "Slice 1");
18 series->add(5, "Slice 1");
19 series->add(2, "Slice 2");
19 series->add(2, "Slice 2");
20 series->add(3, "Slice 3");
20 series->add(3, "Slice 3");
21 series->add(4, "Slice 4");
21 series->add(4, "Slice 4");
22 series->add(5, "Slice 5");
22 series->add(5, "Slice 5");
23 series->add(6, "Slice 6");
23 series->add(6, "Slice 6");
24 series->add(7, "Slice 7");
24 series->add(7, "Slice 7");
25 series->add(new CustomSlice(8));
25 series->add(new CustomSlice(8));
26 series->enableClickExplodes(true);
26 series->enableClickExplodes(true);
27 series->enableHoverHighlight(true);
27 series->enableHoverHighlight(true);
28
28
29 foreach (QPieSlice*s, series->slices())
30 qDebug() << s->angle() << s->span() << s->percentage();
31
32 QChartView* chartView = new QChartView(&window);
29 QChartView* chartView = new QChartView(&window);
33 chartView->setRenderHint(QPainter::Antialiasing);
30 chartView->setRenderHint(QPainter::Antialiasing);
34 chartView->addSeries(series);
31 chartView->addSeries(series);
35 chartView->setChartTitle("simple piechart");
32 chartView->setChartTitle("simple piechart");
36 chartView->setChartTheme(QChart::ChartThemeIcy);
33 chartView->setChartTheme(QChart::ChartThemeIcy);
37
34
38 window.setCentralWidget(chartView);
35 window.setCentralWidget(chartView);
39 window.resize(600, 600);
36 window.resize(600, 600);
40 window.show();
37 window.show();
41
38
42 return a.exec();
39 return a.exec();
43 }
40 }
@@ -1,158 +1,210
1
1
2 #include "piepresenter.h"
2 #include "piepresenter.h"
3 #include "pieslice.h"
3 #include "pieslice.h"
4 #include "qpieslice.h"
4 #include "qpieslice.h"
5 #include "pieslicelabel.h"
6 #include "qpieseries.h"
7 #include <qmath.h>
5 #include <QDebug>
8 #include <QDebug>
6 #include <QTime>
9 #include <QFontMetrics>
10
7
11
8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9
13
10 PiePresenter::PiePresenter(QGraphicsItem *parent, QPieSeries *series)
14 PiePresenter::PiePresenter(QGraphicsItem *parent, QPieSeries *series)
11 :ChartItem(parent),
15 :ChartItem(parent),
12 m_series(series)
16 m_series(series)
13 {
17 {
14 Q_ASSERT(series);
18 Q_ASSERT(series);
15 connect(series, SIGNAL(changed(const QPieSeries::ChangeSet&)), this, SLOT(handleSeriesChanged(const QPieSeries::ChangeSet&)));
19 connect(series, SIGNAL(changed(const QPieSeries::ChangeSet&)), this, SLOT(handleSeriesChanged(const QPieSeries::ChangeSet&)));
16 connect(series, SIGNAL(sizeFactorChanged()), this, SLOT(updateGeometry()));
20 connect(series, SIGNAL(sizeFactorChanged()), this, SLOT(updateGeometry()));
17 connect(series, SIGNAL(positionChanged()), this, SLOT(updateGeometry()));
21 connect(series, SIGNAL(positionChanged()), this, SLOT(updateGeometry()));
22
23 if (m_series->count()) {
24 QPieSeries::ChangeSet changeSet;
25 changeSet.appendAdded(m_series->m_slices);
26 handleSeriesChanged(changeSet);
27 }
18 }
28 }
19
29
20 PiePresenter::~PiePresenter()
30 PiePresenter::~PiePresenter()
21 {
31 {
22 // slices deleted automatically through QGraphicsItem
32 // slices deleted automatically through QGraphicsItem
23 }
33 }
24
34
25 void PiePresenter::paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *)
35 void PiePresenter::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
26 {
36 {
27 // TODO: paint shadows for all components
37 // TODO: paint shadows for all components
28 // - get paths from items & merge & offset and draw with shadow color?
38 // - get paths from items & merge & offset and draw with shadow color?
29 }
39 }
30
40
31 void PiePresenter::handleSeriesChanged(const QPieSeries::ChangeSet& changeSet)
41 void PiePresenter::handleSeriesChanged(const QPieSeries::ChangeSet& changeSet)
32 {
42 {
33 //qDebug() << "PiePresenter::handleSeriesChanged()";
43 //qDebug() << "PiePresenter::handleSeriesChanged()";
34 //qDebug() << " added : " << changeSet.added();
44 //qDebug() << " added : " << changeSet.added();
35 //qDebug() << " changed: " << changeSet.changed();
45 //qDebug() << " changed: " << changeSet.changed();
36 //qDebug() << " removed: " << changeSet.removed();
46 //qDebug() << " removed: " << changeSet.removed();
37
47
38 // ignore changeset when there are no visual slices
48 foreach (QPieSlice* s, changeSet.added())
39 // changeset might not be valid about the added slices
49 addSlice(s);
40 if (m_slices.count() == 0) {
50
41 foreach (QPieSlice* s, m_series->m_slices)
51 foreach (QPieSlice* s, changeSet.changed())
42 addSlice(s);
52 updateSlice(s);
43 return;
44 }
45
53
46 foreach (QPieSlice* s, changeSet.removed())
54 foreach (QPieSlice* s, changeSet.removed())
47 deleteSlice(s);
55 deleteSlice(s);
48
56
49 foreach (QPieSlice* s, changeSet.added())
57 // every change possibly changes the actual pie size
50 addSlice(s);
58 updateGeometry();
51 }
59 }
52
60
53 void PiePresenter::handleDomainChanged(const Domain& domain)
61 void PiePresenter::handleDomainChanged(const Domain& domain)
54 {
62 {
55 // TODO
63 // TODO
56 }
64 }
57
65
58 void PiePresenter::handleGeometryChanged(const QRectF& rect)
66 void PiePresenter::handleGeometryChanged(const QRectF& rect)
59 {
67 {
60 m_rect = rect;
68 m_rect = rect;
69 prepareGeometryChange();
61 updateGeometry();
70 updateGeometry();
62 }
71 }
63
72
64 void PiePresenter::updateGeometry()
73 void PiePresenter::updateGeometry()
65 {
74 {
66 prepareGeometryChange();
75 if (!m_rect.isValid() || m_rect.isEmpty())
76 return;
67
77
78 // calculate maximum rectangle for pie
68 QRectF pieRect = m_rect;
79 QRectF pieRect = m_rect;
69
70 if (pieRect.width() < pieRect.height()) {
80 if (pieRect.width() < pieRect.height()) {
71 pieRect.setWidth(pieRect.width() * m_series->sizeFactor());
81 pieRect.setWidth(pieRect.width() * m_series->sizeFactor());
72 pieRect.setHeight(pieRect.width());
82 pieRect.setHeight(pieRect.width());
73 pieRect.moveCenter(m_rect.center());
83 pieRect.moveCenter(m_rect.center());
74 } else {
84 } else {
75 pieRect.setHeight(pieRect.height() * m_series->sizeFactor());
85 pieRect.setHeight(pieRect.height() * m_series->sizeFactor());
76 pieRect.setWidth(pieRect.height());
86 pieRect.setWidth(pieRect.height());
77 pieRect.moveCenter(m_rect.center());
87 pieRect.moveCenter(m_rect.center());
78 }
88 }
79
89
90 // position the pie rectangle
80 switch (m_series->position()) {
91 switch (m_series->position()) {
81 case QPieSeries::PiePositionTopLeft: {
92 case QPieSeries::PiePositionTopLeft: {
82 pieRect.setHeight(pieRect.height() / 2);
93 pieRect.setHeight(pieRect.height() / 2);
83 pieRect.setWidth(pieRect.height());
94 pieRect.setWidth(pieRect.height());
84 pieRect.moveCenter(QPointF(m_rect.center().x() / 2, m_rect.center().y() / 2));
95 pieRect.moveCenter(QPointF(m_rect.center().x() / 2, m_rect.center().y() / 2));
85 break;
96 break;
86 }
97 }
87 case QPieSeries::PiePositionTopRight: {
98 case QPieSeries::PiePositionTopRight: {
88 pieRect.setHeight(pieRect.height() / 2);
99 pieRect.setHeight(pieRect.height() / 2);
89 pieRect.setWidth(pieRect.height());
100 pieRect.setWidth(pieRect.height());
90 pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, m_rect.center().y() / 2));
101 pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, m_rect.center().y() / 2));
91 break;
102 break;
92 }
103 }
93 case QPieSeries::PiePositionBottomLeft: {
104 case QPieSeries::PiePositionBottomLeft: {
94 pieRect.setHeight(pieRect.height() / 2);
105 pieRect.setHeight(pieRect.height() / 2);
95 pieRect.setWidth(pieRect.height());
106 pieRect.setWidth(pieRect.height());
96 pieRect.moveCenter(QPointF(m_rect.center().x() / 2, (m_rect.center().y() / 2) * 3));
107 pieRect.moveCenter(QPointF(m_rect.center().x() / 2, (m_rect.center().y() / 2) * 3));
97 break;
108 break;
98 }
109 }
99 case QPieSeries::PiePositionBottomRight: {
110 case QPieSeries::PiePositionBottomRight: {
100 pieRect.setHeight(pieRect.height() / 2);
111 pieRect.setHeight(pieRect.height() / 2);
101 pieRect.setWidth(pieRect.height());
112 pieRect.setWidth(pieRect.height());
102 pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, (m_rect.center().y() / 2) * 3));
113 pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, (m_rect.center().y() / 2) * 3));
103 break;
114 break;
104 }
115 }
105 default:
116 default:
106 break;
117 break;
107 }
118 }
108
119
120 // calculate how much space we need around the pie rectangle (labels & exploding)
121 qreal delta = 0;
122 qreal pieRadius = pieRect.height() / 2;
123 foreach (QPieSlice* s, m_series->m_slices) {
124
125 // calculate the farthest point in the slice from the pie center
126 qreal centerAngle = s->angle() + (s->angleSpan() / 2);
127 qreal len = pieRadius + s->labelArmLength() + s->explodeDistance();
128 QPointF dp(qSin(centerAngle*(PI/180)) * len, -qCos(centerAngle*(PI/180)) * len);
129 QPointF p = pieRect.center() + dp;
130
131 // TODO: consider the label text
132
133 // calculate how much the radius must get smaller to fit that point in the base rectangle
134 qreal dt = m_rect.top() - p.y();
135 if (dt > delta) delta = dt;
136 qreal dl = m_rect.left() - p.x();
137 if (dl > delta) delta = dl;
138 qreal dr = p.x() - m_rect.right();
139 if (dr > delta) delta = dr;
140 qreal db = p.y() - m_rect.bottom();
141 if (db > delta) delta = db;
142
143 //if (!m_rect.contains(p)) qDebug() << s->label() << dt << dl << dr << db << "delta" << delta;
144 }
145
146 // shrink the pie rectangle so that everything outside it fits the base rectangle
147 pieRect.adjust(delta, delta, -delta, -delta);
148
149 // update slices
109 if (m_pieRect != pieRect) {
150 if (m_pieRect != pieRect) {
110 m_pieRect = pieRect;
151 m_pieRect = pieRect;
111 //qDebug() << "PiePresenter::updateGeometry()" << m_pieRect;
152 //qDebug() << "PiePresenter::updateGeometry()" << m_rect << m_pieRect;
112 foreach (PieSlice* s, m_slices.values()) {
153 foreach (PieSlice* s, m_slices.values()) {
113 s->setPieRect(m_pieRect);
154 s->setPieRect(m_pieRect);
114 s->updateGeometry();
155 s->updateGeometry();
156 s->update();
115 }
157 }
116 }
158 }
117 }
159 }
118
160
119 void PiePresenter::addSlice(QPieSlice* sliceData)
161 void PiePresenter::addSlice(QPieSlice* sliceData)
120 {
162 {
121 //qDebug() << "PiePresenter::addSlice()" << sliceData;
163 //qDebug() << "PiePresenter::addSlice()" << sliceData;
122
164
123 if (m_slices.keys().contains(sliceData)) {
165 if (m_slices.keys().contains(sliceData)) {
124 //qWarning() << "PiePresenter::addSlice(): slice already exists!" << sliceData;
166 Q_ASSERT(0); // TODO: how to handle this nicely?
125 Q_ASSERT(0);
126 return;
167 return;
127 }
168 }
128
169
129 // create slice
170 // create slice
130 PieSlice *slice = new PieSlice(this);
171 PieSlice *slice = new PieSlice(this);
131 slice->setPieRect(m_pieRect);
172 slice->setPieRect(m_pieRect);
132 slice->updateData(sliceData);
173 slice->updateData(sliceData);
133 slice->updateGeometry();
174 slice->updateGeometry();
134 slice->update();
175 slice->update();
135 m_slices.insert(sliceData, slice);
176 m_slices.insert(sliceData, slice);
136
177
137 // connect signals
178 // connect signals
138 connect(sliceData, SIGNAL(changed()), slice, SLOT(handleSliceDataChanged()));
139 connect(slice, SIGNAL(clicked()), sliceData, SIGNAL(clicked()));
179 connect(slice, SIGNAL(clicked()), sliceData, SIGNAL(clicked()));
140 connect(slice, SIGNAL(hoverEnter()), sliceData, SIGNAL(hoverEnter()));
180 connect(slice, SIGNAL(hoverEnter()), sliceData, SIGNAL(hoverEnter()));
141 connect(slice, SIGNAL(hoverLeave()), sliceData, SIGNAL(hoverLeave()));
181 connect(slice, SIGNAL(hoverLeave()), sliceData, SIGNAL(hoverLeave()));
142 }
182 }
143
183
184 void PiePresenter::updateSlice(QPieSlice* sliceData)
185 {
186 //qDebug() << "PiePresenter::updateSlice()" << sliceData;
187
188 if (!m_slices.contains(sliceData)) {
189 Q_ASSERT(0); // TODO: how to handle this nicely?
190 return;
191 }
192
193 m_slices[sliceData]->updateData(sliceData);
194 }
195
144 void PiePresenter::deleteSlice(QPieSlice* sliceData)
196 void PiePresenter::deleteSlice(QPieSlice* sliceData)
145 {
197 {
146 //qDebug() << "PiePresenter::deleteSlice()" << sliceData;
198 //qDebug() << "PiePresenter::deleteSlice()" << sliceData;
147
199
148 if (m_slices.contains(sliceData))
200 if (!m_slices.contains(sliceData)) {
149 delete m_slices.take(sliceData);
201 Q_ASSERT(0); // TODO: how to handle this nicely?
150 else {
202 return;
151 // nothing to remove
152 Q_ASSERT(0); // TODO: remove before release
153 }
203 }
204
205 delete m_slices.take(sliceData);
154 }
206 }
155
207
156 #include "moc_piepresenter.cpp"
208 #include "moc_piepresenter.cpp"
157
209
158 QTCOMMERCIALCHART_END_NAMESPACE
210 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,48 +1,51
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 #include <QSignalMapper>
7
7
8 class QGraphicsItem;
8 class QGraphicsItem;
9 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9 QTCOMMERCIALCHART_BEGIN_NAMESPACE
10 class PieSlice;
10 class PieSlice;
11
11
12 #define PI 3.14159265 // TODO: is this defined in some header?
13
12 class PiePresenter : public QObject, public ChartItem
14 class PiePresenter : public QObject, public ChartItem
13 {
15 {
14 Q_OBJECT
16 Q_OBJECT
15
17
16 public:
18 public:
17 // TODO: use a generic data class instead of x and y
19 // TODO: use a generic data class instead of x and y
18 PiePresenter(QGraphicsItem *parent, QPieSeries *series);
20 PiePresenter(QGraphicsItem *parent, QPieSeries *series);
19 ~PiePresenter();
21 ~PiePresenter();
20
22
21 public: // from QGraphicsItem
23 public: // from QGraphicsItem
22 QRectF boundingRect() const { return m_rect; }
24 QRectF boundingRect() const { return m_rect; }
23 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
25 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
24
26
25 public:
27 public:
26 QRectF pieRect() const { return m_pieRect; }
28 QRectF pieRect() const { return m_pieRect; }
27
29
28 public Q_SLOTS:
30 public Q_SLOTS:
29 void handleSeriesChanged(const QPieSeries::ChangeSet& changeSet);
31 void handleSeriesChanged(const QPieSeries::ChangeSet& changeSet);
30 void handleDomainChanged(const Domain& domain);
32 void handleDomainChanged(const Domain& domain);
31 void handleGeometryChanged(const QRectF& rect);
33 void handleGeometryChanged(const QRectF& rect);
32 void updateGeometry();
34 void updateGeometry();
33
35
34 private:
36 private:
35 void addSlice(QPieSlice* sliceData);
37 void addSlice(QPieSlice* sliceData);
38 void updateSlice(QPieSlice* sliceData);
36 void deleteSlice(QPieSlice* sliceData);
39 void deleteSlice(QPieSlice* sliceData);
37
40
38 private:
41 private:
39 friend class PieSlice;
42 friend class PieSlice;
40 QHash<QPieSlice*, PieSlice*> m_slices;
43 QHash<QPieSlice*, PieSlice*> m_slices;
41 QPieSeries *m_series;
44 QPieSeries *m_series;
42 QRectF m_rect;
45 QRectF m_rect;
43 QRectF m_pieRect;
46 QRectF m_pieRect;
44 };
47 };
45
48
46 QTCOMMERCIALCHART_END_NAMESPACE
49 QTCOMMERCIALCHART_END_NAMESPACE
47
50
48 #endif // PIEPRESENTER_H
51 #endif // PIEPRESENTER_H
@@ -1,140 +1,135
1 #include "pieslice.h"
1 #include "pieslice.h"
2 #include "pieslicelabel.h"
2 #include "pieslicelabel.h"
3 #include "piepresenter.h"
3 #include "piepresenter.h"
4 #include "qpieseries.h"
4 #include "qpieseries.h"
5 #include "qpieslice.h"
5 #include "qpieslice.h"
6 #include <QPainter>
6 #include <QPainter>
7 #include <QDebug>
7 #include <QDebug>
8 #include <qmath.h>
8 #include <qmath.h>
9 #include <QGraphicsSceneEvent>
9 #include <QGraphicsSceneEvent>
10 #include <QTime>
10 #include <QTime>
11
11
12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
13
13
14 #define PI 3.14159265
15 #define EXPLODE_OFFSET 20
16
17 QPointF offset(qreal angle, qreal length)
14 QPointF offset(qreal angle, qreal length)
18 {
15 {
19 qreal dx = qSin(angle*(PI/180)) * length;
16 qreal dx = qSin(angle*(PI/180)) * length;
20 qreal dy = qCos(angle*(PI/180)) * length;
17 qreal dy = qCos(angle*(PI/180)) * length;
21 return QPointF(dx, -dy);
18 return QPointF(dx, -dy);
22 }
19 }
23
20
24 PieSlice::PieSlice(QGraphicsItem* parent)
21 PieSlice::PieSlice(QGraphicsItem* parent)
25 :QGraphicsObject(parent),
22 :QGraphicsObject(parent),
26 m_slicelabel(new PieSliceLabel(this)),
23 m_slicelabel(new PieSliceLabel(this)),
27 m_angle(0),
24 m_angle(0),
28 m_span(0),
25 m_angleSpan(0),
29 m_isExploded(false)
26 m_isExploded(false),
27 m_explodeDistance(0)
30 {
28 {
31 setAcceptHoverEvents(true);
29 setAcceptHoverEvents(true);
32 setAcceptedMouseButtons(Qt::LeftButton);
30 setAcceptedMouseButtons(Qt::LeftButton);
33 }
31 }
34
32
35 PieSlice::~PieSlice()
33 PieSlice::~PieSlice()
36 {
34 {
37
35
38 }
36 }
39
37
40 QRectF PieSlice::boundingRect() const
38 QRectF PieSlice::boundingRect() const
41 {
39 {
42 return m_path.boundingRect();
40 return m_path.boundingRect();
43 }
41 }
44
42
45 QPainterPath PieSlice::shape() const
43 QPainterPath PieSlice::shape() const
46 {
44 {
47 return m_path;
45 return m_path;
48 }
46 }
49
47
50 void PieSlice::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
48 void PieSlice::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
51 {
49 {
52 painter->setPen(m_pen);
50 painter->setPen(m_pen);
53 painter->setBrush(m_brush);
51 painter->setBrush(m_brush);
54 painter->drawPath(m_path);
52 painter->drawPath(m_path);
55 }
53 }
56
54
57 void PieSlice::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
55 void PieSlice::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
58 {
56 {
59 emit hoverEnter();
57 emit hoverEnter();
60 }
58 }
61
59
62 void PieSlice::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
60 void PieSlice::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
63 {
61 {
64 emit hoverLeave();
62 emit hoverLeave();
65 }
63 }
66
64
67 void PieSlice::mousePressEvent(QGraphicsSceneMouseEvent* /*event*/)
65 void PieSlice::mousePressEvent(QGraphicsSceneMouseEvent* /*event*/)
68 {
66 {
69 emit clicked();
67 emit clicked();
70 }
68 }
71
69
72 void PieSlice::setPieRect(QRectF rect)
70 void PieSlice::setPieRect(QRectF rect)
73 {
71 {
74 m_pieRect = rect;
72 m_pieRect = rect;
75 }
73 }
76
74
77 void PieSlice::updateGeometry()
75 void PieSlice::updateGeometry()
78 {
76 {
77 if (!m_pieRect.isValid() || m_pieRect.isEmpty())
78 return;
79
79 prepareGeometryChange();
80 prepareGeometryChange();
80
81
81 // calculate center angle
82 // calculate center angle
82 qreal centerAngle = m_angle + (m_span/2);
83 qreal centerAngle = m_angle + (m_angleSpan/2);
83
84
84 // adjust rect for exploding
85 // adjust rect for exploding
85 QRectF rect = m_pieRect;
86 QRectF rect = m_pieRect;
86 rect.adjust(EXPLODE_OFFSET, EXPLODE_OFFSET, -EXPLODE_OFFSET ,-EXPLODE_OFFSET);
87 if (m_isExploded) {
87 if (m_isExploded) {
88 QPointF d = offset((centerAngle), EXPLODE_OFFSET);
88 qreal dx = qSin(centerAngle*(PI/180)) * m_explodeDistance;
89 rect.translate(d.x(), d.y());
89 qreal dy = -qCos(centerAngle*(PI/180)) * m_explodeDistance;
90 rect.translate(dx, dy);
90 }
91 }
91
92
92 // update slice path
93 // update slice path
93 // TODO: draw the shape so that it might have a hole in the center
94 // TODO: draw the shape so that it might have a hole in the center
94 QPainterPath path;
95 QPainterPath path;
95 path.moveTo(rect.center());
96 path.moveTo(rect.center());
96 path.arcTo(rect, -m_angle + 90, -m_span);
97 path.arcTo(rect, -m_angle + 90, -m_angleSpan);
97 path.closeSubpath();
98 path.closeSubpath();
98 m_path = path;
99 m_path = path;
99
100
100 // update label position
101 // update label position
101 qreal radius = rect.height() / 2;
102 qreal radius = rect.height() / 2;
102 QPointF edgeCenter = rect.center() + offset(centerAngle, radius + 5);
103 QPointF edgeCenter = rect.center() + offset(centerAngle, radius + 5);
103 m_slicelabel->setArmStartPoint(edgeCenter);
104 m_slicelabel->setArmStartPoint(edgeCenter);
104 m_slicelabel->setArmAngle(centerAngle);
105 m_slicelabel->setArmAngle(centerAngle);
105 m_slicelabel->updateGeometry();
106 m_slicelabel->updateGeometry();
107 m_slicelabel->update();
106
108
107 //qDebug() << "PieSlice::updateGeometry" << m_slicelabel->text() << boundingRect() << m_angle << m_span;
109 //qDebug() << "PieSlice::updateGeometry" << m_slicelabel->text() << boundingRect() << m_angle << m_span;
108 }
110 }
109
111
110 void PieSlice::handleSliceDataChanged()
111 {
112 QPieSlice *slice = qobject_cast<QPieSlice*>(sender());
113 Q_ASSERT(slice);
114 updateData(slice);
115 }
116
117 void PieSlice::updateData(const QPieSlice* sliceData)
112 void PieSlice::updateData(const QPieSlice* sliceData)
118 {
113 {
119 // TODO: compare what has changes to avoid unneccesary geometry updates
114 // TODO: compare what has changes to avoid unneccesary geometry updates
120
115
121 m_angle = sliceData->angle();
116 m_angle = sliceData->angle();
122 m_span = sliceData->span();
117 m_angleSpan = sliceData->angleSpan();
123 m_isExploded = sliceData->isExploded();
118 m_isExploded = sliceData->isExploded();
119 m_explodeDistance = sliceData->explodeDistance(); // TODO: expose to public API
124 m_pen = sliceData->pen();
120 m_pen = sliceData->pen();
125 m_brush = sliceData->brush();
121 m_brush = sliceData->brush();
126
122
127 m_slicelabel->setVisible(sliceData->isLabelVisible());
123 m_slicelabel->setVisible(sliceData->isLabelVisible());
128 m_slicelabel->setText(sliceData->label());
124 m_slicelabel->setText(sliceData->label());
129 m_slicelabel->setPen(sliceData->labelPen());
125 m_slicelabel->setPen(sliceData->labelPen());
130 m_slicelabel->setFont(sliceData->labelFont());
126 m_slicelabel->setFont(sliceData->labelFont());
131 m_slicelabel->setArmLength(sliceData->labelArmLenght());
127 m_slicelabel->setArmLength(sliceData->labelArmLength());
132
128
133 updateGeometry();
129 updateGeometry();
134 update();
130 update();
135 m_slicelabel->update();
136 }
131 }
137
132
138 #include "moc_pieslice.cpp"
133 #include "moc_pieslice.cpp"
139
134
140 QTCOMMERCIALCHART_END_NAMESPACE
135 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,60 +1,64
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 class PieSliceLabel;
15 class QPieSlice;
15 class QPieSlice;
16
16
17 class PieSlice : public QGraphicsObject
17 class PieSlice : public QGraphicsObject
18 {
18 {
19 Q_OBJECT
19 Q_OBJECT
20
20
21 public:
21 public:
22 PieSlice(QGraphicsItem* parent = 0);
22 PieSlice(QGraphicsItem* parent = 0);
23 ~PieSlice();
23 ~PieSlice();
24
24
25 public: // from QGraphicsItem
25 public: // from QGraphicsItem
26 QRectF boundingRect() const;
26 QRectF boundingRect() const;
27 QPainterPath shape() const;
27 QPainterPath shape() const;
28 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
28 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
29 void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
29 void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
30 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
30 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
31 void mousePressEvent(QGraphicsSceneMouseEvent *event);
31 void mousePressEvent(QGraphicsSceneMouseEvent *event);
32
32
33 Q_SIGNALS:
33 Q_SIGNALS:
34 void clicked();
34 void clicked();
35 void hoverEnter();
35 void hoverEnter();
36 void hoverLeave();
36 void hoverLeave();
37
37
38 public Q_SLOTS:
38 public Q_SLOTS:
39 void handleSliceDataChanged();
40 void setPieRect(QRectF rect);
39 void setPieRect(QRectF rect);
41 void updateGeometry();
40 void updateGeometry();
42 void updateData(const QPieSlice *sliceData);
41 void updateData(const QPieSlice *sliceData);
43
42
43 public:
44 PieSliceLabel* label() { return m_slicelabel; }
45
44 private:
46 private:
45 PieSliceLabel* m_slicelabel;
47 PieSliceLabel* m_slicelabel;
46
48
47 QRectF m_pieRect;
49 QRectF m_pieRect;
48 QPainterPath m_path;
50 QPainterPath m_path;
49
51
50 qreal m_angle;
52 qreal m_angle;
51 qreal m_span;
53 qreal m_angleSpan;
54
52 bool m_isExploded;
55 bool m_isExploded;
56 qreal m_explodeDistance;
53
57
54 QPen m_pen;
58 QPen m_pen;
55 QBrush m_brush;
59 QBrush m_brush;
56 };
60 };
57
61
58 QTCOMMERCIALCHART_END_NAMESPACE
62 QTCOMMERCIALCHART_END_NAMESPACE
59
63
60 #endif // PIESLICE_H
64 #endif // PIESLICE_H
@@ -1,299 +1,306
1 #include "qpieseries.h"
1 #include "qpieseries.h"
2 #include "qpieslice.h"
2 #include "qpieslice.h"
3 #include "piepresenter.h"
3 #include "piepresenter.h"
4 #include "pieslice.h"
4 #include "pieslice.h"
5 #include <QFontMetrics>
5 #include <QDebug>
6 #include <QDebug>
6
7
7 QTCOMMERCIALCHART_BEGIN_NAMESPACE
8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
8
9
9 void QPieSeries::ChangeSet::appendAdded(QPieSlice* slice)
10 void QPieSeries::ChangeSet::appendAdded(QPieSlice* slice)
10 {
11 {
11 if (!m_added.contains(slice))
12 if (!m_added.contains(slice))
12 m_added << slice;
13 m_added << slice;
13 }
14 }
14
15
16 void QPieSeries::ChangeSet::appendAdded(QList<QPieSlice*> slices)
17 {
18 foreach (QPieSlice* s, slices)
19 appendAdded(s);
20 }
21
15 void QPieSeries::ChangeSet::appendChanged(QPieSlice* slice)
22 void QPieSeries::ChangeSet::appendChanged(QPieSlice* slice)
16 {
23 {
17 if (!m_changed.contains(slice))
24 if (!m_changed.contains(slice))
18 m_changed << slice;
25 m_changed << slice;
19 }
26 }
20
27
21 void QPieSeries::ChangeSet::appendRemoved(QPieSlice* slice)
28 void QPieSeries::ChangeSet::appendRemoved(QPieSlice* slice)
22 {
29 {
23 if (!m_removed.contains(slice))
30 if (!m_removed.contains(slice))
24 m_removed << slice;
31 m_removed << slice;
25 }
32 }
26
33
27 QList<QPieSlice*> QPieSeries::ChangeSet::added() const
34 QList<QPieSlice*> QPieSeries::ChangeSet::added() const
28 {
35 {
29 return m_added;
36 return m_added;
30 }
37 }
31
38
32 QList<QPieSlice*> QPieSeries::ChangeSet::changed() const
39 QList<QPieSlice*> QPieSeries::ChangeSet::changed() const
33 {
40 {
34 return m_changed;
41 return m_changed;
35 }
42 }
36
43
37 QList<QPieSlice*> QPieSeries::ChangeSet::removed() const
44 QList<QPieSlice*> QPieSeries::ChangeSet::removed() const
38 {
45 {
39 return m_removed;
46 return m_removed;
40 }
47 }
41
48
42 bool QPieSeries::ChangeSet::isEmpty() const
49 bool QPieSeries::ChangeSet::isEmpty() const
43 {
50 {
44 if (m_added.count() || m_changed.count() || m_removed.count())
51 if (m_added.count() || m_changed.count() || m_removed.count())
45 return false;
52 return false;
46 return true;
53 return true;
47 }
54 }
48
55
49
56
50 QPieSeries::QPieSeries(QObject *parent) :
57 QPieSeries::QPieSeries(QObject *parent) :
51 QChartSeries(parent),
58 QChartSeries(parent),
52 m_sizeFactor(1.0),
59 m_sizeFactor(1.0),
53 m_position(PiePositionMaximized),
60 m_position(PiePositionMaximized),
54 m_pieStartAngle(0),
61 m_pieStartAngle(0),
55 m_pieSpan(360)
62 m_pieSpan(360)
56 {
63 {
57
64
58 }
65 }
59
66
60 QPieSeries::~QPieSeries()
67 QPieSeries::~QPieSeries()
61 {
68 {
62
69
63 }
70 }
64
71
65 bool QPieSeries::setData(QList<qreal> data)
72 bool QPieSeries::setData(QList<qreal> data)
66 {
73 {
67 // TODO: remove this function
74 // TODO: remove this function
68 QList<QPieSlice*> slices;
75 QList<QPieSlice*> slices;
69 foreach (qreal value, data)
76 foreach (qreal value, data)
70 slices << new QPieSlice(value, QString::number(value));
77 slices << new QPieSlice(value, QString::number(value));
71 set(slices);
78 set(slices);
72 return true;
79 return true;
73 }
80 }
74
81
75 void QPieSeries::set(QList<QPieSlice*> slices)
82 void QPieSeries::set(QList<QPieSlice*> slices)
76 {
83 {
77 clear();
84 clear();
78 add(slices);
85 add(slices);
79 }
86 }
80
87
81 void QPieSeries::add(QList<QPieSlice*> slices)
88 void QPieSeries::add(QList<QPieSlice*> slices)
82 {
89 {
83 ChangeSet changeSet;
90 ChangeSet changeSet;
84 foreach (QPieSlice* s, slices) {
91 foreach (QPieSlice* s, slices) {
85 s->setParent(this);
92 s->setParent(this);
86 m_slices << s;
93 m_slices << s;
87 changeSet.appendAdded(s);
94 changeSet.appendAdded(s);
88 }
95 }
89
96
90 updateDerivativeData();
97 updateDerivativeData();
91
98
92 foreach (QPieSlice* s, slices) {
99 foreach (QPieSlice* s, slices) {
93 connect(s, SIGNAL(changed()), this, SLOT(sliceChanged()));
100 connect(s, SIGNAL(changed()), this, SLOT(sliceChanged()));
94 connect(s, SIGNAL(clicked()), this, SLOT(sliceClicked()));
101 connect(s, SIGNAL(clicked()), this, SLOT(sliceClicked()));
95 connect(s, SIGNAL(hoverEnter()), this, SLOT(sliceHoverEnter()));
102 connect(s, SIGNAL(hoverEnter()), this, SLOT(sliceHoverEnter()));
96 connect(s, SIGNAL(hoverLeave()), this, SLOT(sliceHoverLeave()));
103 connect(s, SIGNAL(hoverLeave()), this, SLOT(sliceHoverLeave()));
97 }
104 }
98
105
99 emit changed(changeSet);
106 emit changed(changeSet);
100 }
107 }
101
108
102 void QPieSeries::add(QPieSlice* slice)
109 void QPieSeries::add(QPieSlice* slice)
103 {
110 {
104 add(QList<QPieSlice*>() << slice);
111 add(QList<QPieSlice*>() << slice);
105 }
112 }
106
113
107 QPieSlice* QPieSeries::add(qreal value, QString name)
114 QPieSlice* QPieSeries::add(qreal value, QString name)
108 {
115 {
109 QPieSlice* slice = new QPieSlice(value, name);
116 QPieSlice* slice = new QPieSlice(value, name);
110 add(slice);
117 add(slice);
111 return slice;
118 return slice;
112 }
119 }
113
120
114 void QPieSeries::remove(QPieSlice* slice)
121 void QPieSeries::remove(QPieSlice* slice)
115 {
122 {
116 if (!m_slices.removeOne(slice)) {
123 if (!m_slices.removeOne(slice)) {
117 Q_ASSERT(0); // TODO: remove before release
124 Q_ASSERT(0); // TODO: how should this be reported?
118 return;
125 return;
119 }
126 }
120
127
121 ChangeSet changeSet;
128 ChangeSet changeSet;
122 changeSet.appendRemoved(slice);
129 changeSet.appendRemoved(slice);
123 emit changed(changeSet);
130 emit changed(changeSet);
124
131
125 delete slice;
132 delete slice;
126 slice = NULL;
133 slice = NULL;
127
134
128 updateDerivativeData();
135 updateDerivativeData();
129 }
136 }
130
137
131 void QPieSeries::clear()
138 void QPieSeries::clear()
132 {
139 {
133 if (m_slices.count() == 0)
140 if (m_slices.count() == 0)
134 return;
141 return;
135
142
136 ChangeSet changeSet;
143 ChangeSet changeSet;
137 foreach (QPieSlice* s, m_slices) {
144 foreach (QPieSlice* s, m_slices) {
138 changeSet.appendRemoved(s);
145 changeSet.appendRemoved(s);
139 m_slices.removeOne(s);
146 m_slices.removeOne(s);
140 delete s;
147 delete s;
141 }
148 }
142 emit changed(changeSet);
149 emit changed(changeSet);
143 updateDerivativeData();
150 updateDerivativeData();
144 }
151 }
145
152
146 void QPieSeries::setSizeFactor(qreal factor)
153 void QPieSeries::setSizeFactor(qreal factor)
147 {
154 {
148 if (factor < 0.0)
155 if (factor < 0.0)
149 return;
156 return;
150
157
151 if (m_sizeFactor != factor) {
158 if (m_sizeFactor != factor) {
152 m_sizeFactor = factor;
159 m_sizeFactor = factor;
153 emit sizeFactorChanged();
160 emit sizeFactorChanged();
154 }
161 }
155 }
162 }
156
163
157 void QPieSeries::setPosition(PiePosition position)
164 void QPieSeries::setPosition(PiePosition position)
158 {
165 {
159 if (m_position != position) {
166 if (m_position != position) {
160 m_position = position;
167 m_position = position;
161 emit positionChanged();
168 emit positionChanged();
162 }
169 }
163 }
170 }
164
171
165 void QPieSeries::setSpan(qreal startAngle, qreal span)
172 void QPieSeries::setSpan(qreal startAngle, qreal span)
166 {
173 {
167 if (startAngle >= 0 && startAngle < 360 &&
174 if (startAngle >= 0 && startAngle < 360 &&
168 span > 0 && span <= 360) {
175 span > 0 && span <= 360) {
169 m_pieStartAngle = startAngle;
176 m_pieStartAngle = startAngle;
170 m_pieSpan = span;
177 m_pieSpan = span;
171 updateDerivativeData();
178 updateDerivativeData();
172 }
179 }
173 }
180 }
174
181
175 void QPieSeries::setLabelsVisible(bool visible)
182 void QPieSeries::setLabelsVisible(bool visible)
176 {
183 {
177 foreach (QPieSlice* s, m_slices)
184 foreach (QPieSlice* s, m_slices)
178 s->setLabelVisible(visible);
185 s->setLabelVisible(visible);
179 }
186 }
180
187
181 void QPieSeries::enableClickExplodes(bool enable)
188 void QPieSeries::enableClickExplodes(bool enable)
182 {
189 {
183 if (enable)
190 if (enable)
184 connect(this, SIGNAL(clicked(QPieSlice*)), this, SLOT(toggleExploded(QPieSlice*)));
191 connect(this, SIGNAL(clicked(QPieSlice*)), this, SLOT(toggleExploded(QPieSlice*)));
185 else
192 else
186 disconnect(this, SLOT(toggleExploded(QPieSlice*)));
193 disconnect(this, SLOT(toggleExploded(QPieSlice*)));
187 }
194 }
188
195
189 void QPieSeries::enableHoverHighlight(bool enable)
196 void QPieSeries::enableHoverHighlight(bool enable)
190 {
197 {
191 if (enable) {
198 if (enable) {
192 connect(this, SIGNAL(hoverEnter(QPieSlice*)), this, SLOT(highlightOn(QPieSlice*)));
199 connect(this, SIGNAL(hoverEnter(QPieSlice*)), this, SLOT(highlightOn(QPieSlice*)));
193 connect(this, SIGNAL(hoverLeave(QPieSlice*)), this, SLOT(highlightOff(QPieSlice*)));
200 connect(this, SIGNAL(hoverLeave(QPieSlice*)), this, SLOT(highlightOff(QPieSlice*)));
194 } else {
201 } else {
195 disconnect(this, SLOT(hoverEnter(QPieSlice*)));
202 disconnect(this, SLOT(hoverEnter(QPieSlice*)));
196 disconnect(this, SLOT(hoverLeave(QPieSlice*)));
203 disconnect(this, SLOT(hoverLeave(QPieSlice*)));
197 }
204 }
198 }
205 }
199
206
200 void QPieSeries::sliceChanged()
207 void QPieSeries::sliceChanged()
201 {
208 {
202 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
209 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
203 Q_ASSERT(m_slices.contains(slice));
210 Q_ASSERT(m_slices.contains(slice));
204
211
205 ChangeSet changeSet;
212 ChangeSet changeSet;
206 changeSet.appendChanged(slice);
213 changeSet.appendChanged(slice);
207 emit changed(changeSet);
214 emit changed(changeSet);
208
215
209 updateDerivativeData();
216 updateDerivativeData();
210 }
217 }
211
218
212 void QPieSeries::sliceClicked()
219 void QPieSeries::sliceClicked()
213 {
220 {
214 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
221 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
215 Q_ASSERT(m_slices.contains(slice));
222 Q_ASSERT(m_slices.contains(slice));
216 emit clicked(slice);
223 emit clicked(slice);
217 }
224 }
218
225
219 void QPieSeries::sliceHoverEnter()
226 void QPieSeries::sliceHoverEnter()
220 {
227 {
221 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
228 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
222 Q_ASSERT(m_slices.contains(slice));
229 Q_ASSERT(m_slices.contains(slice));
223 emit hoverEnter(slice);
230 emit hoverEnter(slice);
224 }
231 }
225
232
226 void QPieSeries::sliceHoverLeave()
233 void QPieSeries::sliceHoverLeave()
227 {
234 {
228 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
235 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
229 Q_ASSERT(m_slices.contains(slice));
236 Q_ASSERT(m_slices.contains(slice));
230 emit hoverLeave(slice);
237 emit hoverLeave(slice);
231 }
238 }
232
239
233 void QPieSeries::toggleExploded(QPieSlice* slice)
240 void QPieSeries::toggleExploded(QPieSlice* slice)
234 {
241 {
235 Q_ASSERT(slice);
242 Q_ASSERT(slice);
236 slice->setExploded(!slice->isExploded());
243 slice->setExploded(!slice->isExploded());
237 }
244 }
238
245
239 void QPieSeries::highlightOn(QPieSlice* slice)
246 void QPieSeries::highlightOn(QPieSlice* slice)
240 {
247 {
241 Q_ASSERT(slice);
248 Q_ASSERT(slice);
242 QColor c = slice->brush().color().lighter();
249 QColor c = slice->brush().color().lighter();
243 slice->setBrush(c);
250 slice->setBrush(c);
244 }
251 }
245
252
246 void QPieSeries::highlightOff(QPieSlice* slice)
253 void QPieSeries::highlightOff(QPieSlice* slice)
247 {
254 {
248 Q_ASSERT(slice);
255 Q_ASSERT(slice);
249 QColor c = slice->brush().color().darker(150);
256 QColor c = slice->brush().color().darker(150);
250 slice->setBrush(c);
257 slice->setBrush(c);
251 }
258 }
252
259
253 void QPieSeries::updateDerivativeData()
260 void QPieSeries::updateDerivativeData()
254 {
261 {
255 m_total = 0;
262 m_total = 0;
256
263
257 // nothing to do?
264 // nothing to do?
258 if (m_slices.count() == 0)
265 if (m_slices.count() == 0)
259 return;
266 return;
260
267
261 // calculate total
268 // calculate total
262 foreach (QPieSlice* s, m_slices)
269 foreach (QPieSlice* s, m_slices)
263 m_total += s->value();
270 m_total += s->value();
264
271
265 // we must have some values
272 // we must have some values
266 Q_ASSERT(m_total > 0); // TODO
273 Q_ASSERT(m_total > 0); // TODO: is this the correct way to handle this?
267
274
268 // update slice attributes
275 // update slice attributes
269 qreal sliceAngle = m_pieStartAngle;
276 qreal sliceAngle = m_pieStartAngle;
270 foreach (QPieSlice* s, m_slices) {
277 foreach (QPieSlice* s, m_slices) {
271
278
272 bool changed = false;
279 bool changed = false;
273
280
274 qreal percentage = s->value() / m_total;
281 qreal percentage = s->value() / m_total;
275 if (s->m_percentage != percentage) {
282 if (s->m_percentage != percentage) {
276 s->m_percentage = percentage;
283 s->m_percentage = percentage;
277 changed = true;
284 changed = true;
278 }
285 }
279
286
280 qreal sliceSpan = m_pieSpan * percentage;
287 qreal sliceSpan = m_pieSpan * percentage;
281 if (s->m_span != sliceSpan) {
288 if (s->m_angleSpan != sliceSpan) {
282 s->m_span = sliceSpan;
289 s->m_angleSpan = sliceSpan;
283 changed = true;
290 changed = true;
284 }
291 }
285
292
286 if (s->m_angle != sliceAngle) {
293 if (s->m_angle != sliceAngle) {
287 s->m_angle = sliceAngle;
294 s->m_angle = sliceAngle;
288 changed = true;
295 changed = true;
289 }
296 }
290 sliceAngle += sliceSpan;
297 sliceAngle += sliceSpan;
291
298
292 if (changed)
299 if (changed)
293 emit s->changed();
300 emit s->changed();
294 }
301 }
295 }
302 }
296
303
297 #include "moc_qpieseries.cpp"
304 #include "moc_qpieseries.cpp"
298
305
299 QTCOMMERCIALCHART_END_NAMESPACE
306 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,127 +1,131
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>
8 #include <QPen>
9 #include <QBrush>
9 #include <QBrush>
10 #include <QSignalMapper>
10 #include <QSignalMapper>
11
11
12 class QGraphicsObject;
12 class QGraphicsObject;
13 QTCOMMERCIALCHART_BEGIN_NAMESPACE
13 QTCOMMERCIALCHART_BEGIN_NAMESPACE
14 class PiePresenter;
14 class PiePresenter;
15 class PieSlice;
15 class PieSlice;
16 class QPieSlice;
16 class QPieSlice;
17
17
18 class QTCOMMERCIALCHART_EXPORT QPieSeries : public QChartSeries
18 class QTCOMMERCIALCHART_EXPORT QPieSeries : public QChartSeries
19 {
19 {
20 Q_OBJECT
20 Q_OBJECT
21
21
22 public:
22 public:
23 enum PiePosition {
23 enum PiePosition {
24 PiePositionMaximized = 0,
24 PiePositionMaximized = 0,
25 PiePositionTopLeft,
25 PiePositionTopLeft,
26 PiePositionTopRight,
26 PiePositionTopRight,
27 PiePositionBottomLeft,
27 PiePositionBottomLeft,
28 PiePositionBottomRight
28 PiePositionBottomRight
29 };
29 };
30
30
31 class ChangeSet
31 class ChangeSet
32 {
32 {
33 public:
33 public:
34 void appendAdded(QPieSlice* slice);
34 void appendAdded(QPieSlice* slice);
35 void appendAdded(QList<QPieSlice*> slices);
35 void appendChanged(QPieSlice* slice);
36 void appendChanged(QPieSlice* slice);
36 void appendRemoved(QPieSlice* slice);
37 void appendRemoved(QPieSlice* slice);
37
38
38 QList<QPieSlice*> added() const;
39 QList<QPieSlice*> added() const;
39 QList<QPieSlice*> changed() const;
40 QList<QPieSlice*> changed() const;
40 QList<QPieSlice*> removed() const;
41 QList<QPieSlice*> removed() const;
41
42
42 bool isEmpty() const;
43 bool isEmpty() const;
43
44
44 private:
45 private:
45 QList<QPieSlice*> m_added;
46 QList<QPieSlice*> m_added;
46 QList<QPieSlice*> m_changed;
47 QList<QPieSlice*> m_changed;
47 QList<QPieSlice*> m_removed;
48 QList<QPieSlice*> m_removed;
48 };
49 };
49
50
50 public:
51 public:
51 QPieSeries(QObject *parent = 0);
52 QPieSeries(QObject *parent = 0);
52 virtual ~QPieSeries();
53 virtual ~QPieSeries();
53
54
54 public: // from QChartSeries
55 public: // from QChartSeries
55 QChartSeriesType type() const { return QChartSeries::SeriesTypePie; }
56 QChartSeriesType type() const { return QChartSeries::SeriesTypePie; }
56 virtual bool setData(QList<qreal> data); // TODO: remove this
57 virtual bool setData(QList<qreal> data); // TODO: remove this
57
58
58 public:
59 public:
59 void set(QList<QPieSlice*> slices);
60 void set(QList<QPieSlice*> slices);
60 void add(QList<QPieSlice*> slices);
61 void add(QList<QPieSlice*> slices);
61 void add(QPieSlice* slice);
62 void add(QPieSlice* slice);
62 QPieSlice* add(qreal value, QString name);
63 QPieSlice* add(qreal value, QString name);
63 void remove(QPieSlice* slice);
64 void remove(QPieSlice* slice);
64 void clear();
65 void clear();
65
66
66 int count() const { return m_slices.count(); }
67 int count() const { return m_slices.count(); }
67
68
68 QList<QPieSlice*> slices() const { return m_slices; }
69 QList<QPieSlice*> slices() const { return m_slices; }
69
70
70 // TODO: find slices?
71 // QList<QPieSlice*> findByValue(qreal value);
72 // ...
73
74 // TODO: sorting slices?
75 // void sort(QPieSeries::SortByValue)
76
77 void setSizeFactor(qreal sizeFactor);
71 void setSizeFactor(qreal sizeFactor);
78 qreal sizeFactor() const { return m_sizeFactor; }
72 qreal sizeFactor() const { return m_sizeFactor; }
79
73
80 void setPosition(PiePosition position);
74 void setPosition(PiePosition position);
81 PiePosition position() const { return m_position; }
75 PiePosition position() const { return m_position; }
82
76
83 void setSpan(qreal startAngle, qreal span);
77 void setSpan(qreal startAngle, qreal span);
84
78
85 void setLabelsVisible(bool visible);
79 void setLabelsVisible(bool visible);
86 void enableClickExplodes(bool enable);
80 void enableClickExplodes(bool enable);
87 void enableHoverHighlight(bool enable);
81 void enableHoverHighlight(bool enable);
88
82
83 // TODO: find slices?
84 // QList<QPieSlice*> findByValue(qreal value);
85 // ...
86
87 // TODO: sorting slices?
88 // void sort(QPieSeries::SortByValue|label|??)
89
90 // TODO: general graphics customization
91 // setDrawStyle(2d|3d)
92 // setDropShadows(bool)
93
89 Q_SIGNALS:
94 Q_SIGNALS:
90 void changed(const QPieSeries::ChangeSet& changeSet);
95 void changed(const QPieSeries::ChangeSet& changeSet);
91 void clicked(QPieSlice* slice);
96 void clicked(QPieSlice* slice);
92 void hoverEnter(QPieSlice* slice);
97 void hoverEnter(QPieSlice* slice);
93 void hoverLeave(QPieSlice* slice);
98 void hoverLeave(QPieSlice* slice);
94 void sizeFactorChanged();
99 void sizeFactorChanged();
95 void positionChanged();
100 void positionChanged();
96
101
97 private Q_SLOTS: // should be private and not in the interface
102 private Q_SLOTS: // TODO: should be private and not visible in the interface at all
98 void sliceChanged();
103 void sliceChanged();
99 void sliceClicked();
104 void sliceClicked();
100 void sliceHoverEnter();
105 void sliceHoverEnter();
101 void sliceHoverLeave();
106 void sliceHoverLeave();
102
103 void toggleExploded(QPieSlice* slice);
107 void toggleExploded(QPieSlice* slice);
104 void highlightOn(QPieSlice* slice);
108 void highlightOn(QPieSlice* slice);
105 void highlightOff(QPieSlice* slice);
109 void highlightOff(QPieSlice* slice);
106
110
107 private:
111 private:
108 void updateDerivativeData();
112 void updateDerivativeData();
109
113
110 private:
114 private:
111 Q_DISABLE_COPY(QPieSeries)
115 Q_DISABLE_COPY(QPieSeries)
112
116
113 // TODO: use PIML
117 // TODO: use PIML
114 friend class PiePresenter;
118 friend class PiePresenter;
115 friend class PieSlice;
119 friend class PieSlice;
116
120
117 QList<QPieSlice*> m_slices;
121 QList<QPieSlice*> m_slices;
118 qreal m_sizeFactor;
122 qreal m_sizeFactor;
119 PiePosition m_position;
123 PiePosition m_position;
120 qreal m_total;
124 qreal m_total;
121 qreal m_pieStartAngle;
125 qreal m_pieStartAngle;
122 qreal m_pieSpan;
126 qreal m_pieSpan;
123 };
127 };
124
128
125 QTCOMMERCIALCHART_END_NAMESPACE
129 QTCOMMERCIALCHART_END_NAMESPACE
126
130
127 #endif // PIESERIES_H
131 #endif // PIESERIES_H
@@ -1,181 +1,197
1 #include "qpieslice.h"
1 #include "qpieslice.h"
2
2
3 QTCOMMERCIALCHART_BEGIN_NAMESPACE
3 QTCOMMERCIALCHART_BEGIN_NAMESPACE
4
4
5 #define DEFAULT_PEN_COLOR Qt::black
5 #define DEFAULT_PEN_COLOR Qt::black
6 #define DEFAULT_BRUSH_COLOR Qt::white
6 #define DEFAULT_BRUSH_COLOR Qt::white
7 #define DEFAULT_LABEL_ARM_LENGTH 50
7 #define DEFAULT_LABEL_ARM_LENGTH 50
8 #define DEFAULT_EXPOLODE_DISTANCE 20
8
9
9 QPieSlice::QPieSlice(QObject *parent)
10 QPieSlice::QPieSlice(QObject *parent)
10 :QObject(parent),
11 :QObject(parent),
11 m_value(0),
12 m_value(0),
12 m_isLabelVisible(true),
13 m_isLabelVisible(true),
13 m_isExploded(false),
14 m_isExploded(false),
15 m_explodeDistance(DEFAULT_EXPOLODE_DISTANCE),
14 m_percentage(0),
16 m_percentage(0),
15 m_angle(0),
17 m_angle(0),
16 m_span(0),
18 m_angleSpan(0),
17 m_pen(DEFAULT_PEN_COLOR),
19 m_pen(DEFAULT_PEN_COLOR),
18 m_brush(DEFAULT_BRUSH_COLOR),
20 m_brush(DEFAULT_BRUSH_COLOR),
19 m_labelPen(DEFAULT_PEN_COLOR),
21 m_labelPen(DEFAULT_PEN_COLOR),
20 m_labelArmLength(DEFAULT_LABEL_ARM_LENGTH)
22 m_labelArmLength(DEFAULT_LABEL_ARM_LENGTH)
21 {
23 {
22
24
23 }
25 }
24
26
25 QPieSlice::QPieSlice(qreal value, QString label, bool labelVisible, QObject *parent)
27 QPieSlice::QPieSlice(qreal value, QString label, bool labelVisible, QObject *parent)
26 :QObject(parent),
28 :QObject(parent),
27 m_value(value),
29 m_value(value),
28 m_label(label),
30 m_label(label),
29 m_isLabelVisible(labelVisible),
31 m_isLabelVisible(labelVisible),
30 m_isExploded(false),
32 m_isExploded(false),
33 m_explodeDistance(DEFAULT_EXPOLODE_DISTANCE),
31 m_percentage(0),
34 m_percentage(0),
32 m_angle(0),
35 m_angle(0),
33 m_span(0),
36 m_angleSpan(0),
34 m_pen(DEFAULT_PEN_COLOR),
37 m_pen(DEFAULT_PEN_COLOR),
35 m_brush(DEFAULT_BRUSH_COLOR),
38 m_brush(DEFAULT_BRUSH_COLOR),
36 m_labelPen(DEFAULT_PEN_COLOR),
39 m_labelPen(DEFAULT_PEN_COLOR),
37 m_labelArmLength(DEFAULT_LABEL_ARM_LENGTH)
40 m_labelArmLength(DEFAULT_LABEL_ARM_LENGTH)
38 {
41 {
39
42
40 }
43 }
41
44
42 QPieSlice::~QPieSlice()
45 QPieSlice::~QPieSlice()
43 {
46 {
44
47
45 }
48 }
46
49
47 qreal QPieSlice::value() const
50 qreal QPieSlice::value() const
48 {
51 {
49 return m_value;
52 return m_value;
50 }
53 }
51
54
52 QString QPieSlice::label() const
55 QString QPieSlice::label() const
53 {
56 {
54 return m_label;
57 return m_label;
55 }
58 }
56
59
57 bool QPieSlice::isLabelVisible() const
60 bool QPieSlice::isLabelVisible() const
58 {
61 {
59 return m_isLabelVisible;
62 return m_isLabelVisible;
60 }
63 }
61
64
62 bool QPieSlice::isExploded() const
65 bool QPieSlice::isExploded() const
63 {
66 {
64 return m_isExploded;
67 return m_isExploded;
65 }
68 }
66
69
70 qreal QPieSlice::explodeDistance() const
71 {
72 return m_explodeDistance;
73 }
74
67 qreal QPieSlice::percentage() const
75 qreal QPieSlice::percentage() const
68 {
76 {
69 return m_percentage;
77 return m_percentage;
70 }
78 }
71
79
72 qreal QPieSlice::angle() const
80 qreal QPieSlice::angle() const
73 {
81 {
74 return m_angle;
82 return m_angle;
75 }
83 }
76
84
77 qreal QPieSlice::span() const
85 qreal QPieSlice::angleSpan() const
78 {
86 {
79 return m_span;
87 return m_angleSpan;
80 }
88 }
81
89
82 QPen QPieSlice::pen() const
90 QPen QPieSlice::pen() const
83 {
91 {
84 return m_pen;
92 return m_pen;
85 }
93 }
86
94
87 QBrush QPieSlice::brush() const
95 QBrush QPieSlice::brush() const
88 {
96 {
89 return m_brush;
97 return m_brush;
90 }
98 }
91
99
92 QPen QPieSlice::labelPen() const
100 QPen QPieSlice::labelPen() const
93 {
101 {
94 return m_labelPen;
102 return m_labelPen;
95 }
103 }
96
104
97 QFont QPieSlice::labelFont() const
105 QFont QPieSlice::labelFont() const
98 {
106 {
99 return m_labelFont;
107 return m_labelFont;
100 }
108 }
101
109
102 qreal QPieSlice::labelArmLenght() const
110 qreal QPieSlice::labelArmLength() const
103 {
111 {
104 return m_labelArmLength;
112 return m_labelArmLength;
105 }
113 }
106
114
107 void QPieSlice::setValue(qreal value)
115 void QPieSlice::setValue(qreal value)
108 {
116 {
109 if (m_value != value) {
117 if (m_value != value) {
110 m_value = value;
118 m_value = value;
111 emit changed();
119 emit changed();
112 }
120 }
113 }
121 }
114
122
115 void QPieSlice::setLabel(QString label)
123 void QPieSlice::setLabel(QString label)
116 {
124 {
117 if (m_label != label) {
125 if (m_label != label) {
118 m_label = label;
126 m_label = label;
119 emit changed();
127 emit changed();
120 }
128 }
121 }
129 }
122
130
123 void QPieSlice::setLabelVisible(bool visible)
131 void QPieSlice::setLabelVisible(bool visible)
124 {
132 {
125 if (m_isLabelVisible != visible) {
133 if (m_isLabelVisible != visible) {
126 m_isLabelVisible = visible;
134 m_isLabelVisible = visible;
127 emit changed();
135 emit changed();
128 }
136 }
129 }
137 }
130
138
131 void QPieSlice::setExploded(bool exploded)
139 void QPieSlice::setExploded(bool exploded)
132 {
140 {
133 if (m_isExploded != exploded) {
141 if (m_isExploded != exploded) {
134 m_isExploded = exploded;
142 m_isExploded = exploded;
135 emit changed();
143 emit changed();
136 }
144 }
137 }
145 }
138
146
147 void QPieSlice::setExplodeDistance(qreal distance)
148 {
149 if (m_explodeDistance != distance) {
150 m_explodeDistance = distance;
151 emit changed();
152 }
153 }
154
139 void QPieSlice::setPen(QPen pen)
155 void QPieSlice::setPen(QPen pen)
140 {
156 {
141 if (m_pen != pen) {
157 if (m_pen != pen) {
142 m_pen = pen;
158 m_pen = pen;
143 emit changed();
159 emit changed();
144 }
160 }
145 }
161 }
146
162
147 void QPieSlice::setBrush(QBrush brush)
163 void QPieSlice::setBrush(QBrush brush)
148 {
164 {
149 if (m_brush != brush) {
165 if (m_brush != brush) {
150 m_brush = brush;
166 m_brush = brush;
151 emit changed();
167 emit changed();
152 }
168 }
153 }
169 }
154
170
155 void QPieSlice::setLabelFont(QFont font)
171 void QPieSlice::setLabelFont(QFont font)
156 {
172 {
157 if (m_labelFont != font) {
173 if (m_labelFont != font) {
158 m_labelFont = font;
174 m_labelFont = font;
159 emit changed();
175 emit changed();
160 }
176 }
161 }
177 }
162
178
163 void QPieSlice::setLabelPen(QPen pen)
179 void QPieSlice::setLabelPen(QPen pen)
164 {
180 {
165 if (m_labelPen != pen) {
181 if (m_labelPen != pen) {
166 m_labelPen = pen;
182 m_labelPen = pen;
167 emit changed();
183 emit changed();
168 }
184 }
169 }
185 }
170
186
171 void QPieSlice::setLabelArmLength(qreal len)
187 void QPieSlice::setLabelArmLength(qreal len)
172 {
188 {
173 if (m_labelArmLength != len) {
189 if (m_labelArmLength != len) {
174 m_labelArmLength = len;
190 m_labelArmLength = len;
175 emit changed();
191 emit changed();
176 }
192 }
177 }
193 }
178
194
179 #include "moc_qpieslice.cpp"
195 #include "moc_qpieslice.cpp"
180
196
181 QTCOMMERCIALCHART_END_NAMESPACE
197 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,88 +1,96
1 #ifndef QPIESLICE_H
1 #ifndef QPIESLICE_H
2 #define QPIESLICE_H
2 #define QPIESLICE_H
3
3
4 #include <qchartglobal.h>
4 #include <qchartglobal.h>
5 #include <QObject>
5 #include <QObject>
6 #include <QPen>
6 #include <QPen>
7 #include <QBrush>
7 #include <QBrush>
8 #include <QFont>
8 #include <QFont>
9
9
10 QTCOMMERCIALCHART_BEGIN_NAMESPACE
10 QTCOMMERCIALCHART_BEGIN_NAMESPACE
11
11
12 class QTCOMMERCIALCHART_EXPORT QPieSlice : public QObject
12 class QTCOMMERCIALCHART_EXPORT QPieSlice : public QObject
13 {
13 {
14 Q_OBJECT
14 Q_OBJECT
15 Q_PROPERTY(QString label READ label WRITE setLabel /*NOTIFY dataYChanged*/)
15 Q_PROPERTY(QString label READ label WRITE setLabel /*NOTIFY dataYChanged*/)
16 Q_PROPERTY(qreal value READ value WRITE setValue /*NOTIFY dataXChanged*/)
16 Q_PROPERTY(qreal value READ value WRITE setValue /*NOTIFY dataXChanged*/)
17
17
18 public:
18 public:
19 QPieSlice(QObject *parent = 0);
19 QPieSlice(QObject *parent = 0);
20 QPieSlice(qreal value, QString label, bool labelVisible = true, QObject *parent = 0);
20 QPieSlice(qreal value, QString label, bool labelVisible = true, QObject *parent = 0);
21 virtual ~QPieSlice();
21 virtual ~QPieSlice();
22
22
23 // data
23 // data
24 qreal value() const;
24 qreal value() const;
25 QString label() const;
25 QString label() const;
26 bool isLabelVisible() const;
26 bool isLabelVisible() const;
27 bool isExploded() const;
27 bool isExploded() const;
28 qreal explodeDistance() const;
28
29
29 // generated data
30 // generated data
30 qreal percentage() const;
31 qreal percentage() const;
31 qreal angle() const;
32 qreal angle() const;
32 qreal span() const;
33 qreal angleSpan() const;
33
34
34 // customization
35 // customization
35 QPen pen() const;
36 QPen pen() const;
36 QBrush brush() const;
37 QBrush brush() const;
37 QPen labelPen() const;
38 QPen labelPen() const;
38 QFont labelFont() const;
39 QFont labelFont() const;
39 qreal labelArmLenght() const;
40 qreal labelArmLength() const;
40
41
41 Q_SIGNALS:
42 Q_SIGNALS:
42 void clicked();
43 void clicked();
43 void hoverEnter();
44 void hoverEnter();
44 void hoverLeave();
45 void hoverLeave();
45 void changed();
46 void changed();
46
47
47 public Q_SLOTS:
48 public Q_SLOTS:
48
49
49 // data
50 // data
50 void setLabel(QString label);
51 void setLabel(QString label);
51 void setLabelVisible(bool visible);
52 void setLabelVisible(bool visible);
52 void setValue(qreal value);
53 void setValue(qreal value);
53 void setExploded(bool exploded);
54 void setExploded(bool exploded);
55 void setExplodeDistance(qreal distance);
54
56
55 // customization
57 // customization
56 void setPen(QPen pen);
58 void setPen(QPen pen);
57 void setBrush(QBrush brush);
59 void setBrush(QBrush brush);
58 void setLabelFont(QFont font);
60 void setLabelFont(QFont font);
59 void setLabelPen(QPen pen);
61 void setLabelPen(QPen pen);
60 void setLabelArmLength(qreal len);
62 void setLabelArmLength(qreal len);
61
63
64 // TODO: label position in general
65 // setLabelFlags(inside|outside|labelArmOn|labelArmOff|???)
66 // setLabelOrientation(horizontal|vertical|same as slice center angle|???)
67
62 private:
68 private:
63
69
64 // TODO: use private class
70 // TODO: use private class
65 friend class QPieSeries;
71 friend class QPieSeries;
72 friend class PiePresenter;
66
73
67 // data
74 // data
68 qreal m_value;
75 qreal m_value;
69 QString m_label;
76 QString m_label;
70 bool m_isLabelVisible;
77 bool m_isLabelVisible;
71 bool m_isExploded;
78 bool m_isExploded;
79 qreal m_explodeDistance;
72
80
73 // generated data
81 // generated data
74 qreal m_percentage;
82 qreal m_percentage;
75 qreal m_angle;
83 qreal m_angle;
76 qreal m_span;
84 qreal m_angleSpan;
77
85
78 // customization
86 // customization
79 QPen m_pen;
87 QPen m_pen;
80 QBrush m_brush;
88 QBrush m_brush;
81 QPen m_labelPen;
89 QPen m_labelPen;
82 QFont m_labelFont;
90 QFont m_labelFont;
83 qreal m_labelArmLength;
91 qreal m_labelArmLength;
84 };
92 };
85
93
86 QTCOMMERCIALCHART_END_NAMESPACE
94 QTCOMMERCIALCHART_END_NAMESPACE
87
95
88 #endif // QPIESLICE_H
96 #endif // QPIESLICE_H
General Comments 0
You need to be logged in to leave comments. Login now