##// END OF EJS Templates
Refactoring the pie for animations (no actual animations yet)
Jani Honkonen -
r566:875089213706
parent child
Show More
@@ -14,15 +14,7 PiePresenter::PiePresenter(QGraphicsItem *parent, QPieSeries *series)
14 m_series(series)
14 m_series(series)
15 {
15 {
16 Q_ASSERT(series);
16 Q_ASSERT(series);
17 connect(series, SIGNAL(changed(const QPieSeries::ChangeSet&)), this, SLOT(handleSeriesChanged(const QPieSeries::ChangeSet&)));
17 connect(series, SIGNAL(changed()), this, SLOT(handleSeriesChanged()));
18 connect(series, SIGNAL(piePositionChanged()), this, SLOT(updateGeometry()));
19 connect(series, SIGNAL(pieSizeChanged()), this, SLOT(updateGeometry()));
20
21 if (m_series->count()) {
22 QPieSeries::ChangeSet changeSet;
23 changeSet.appendAdded(m_series->m_slices);
24 handleSeriesChanged(changeSet);
25 }
26
18
27 // Note: the following does not affect as long as the item does not have anything to paint
19 // Note: the following does not affect as long as the item does not have anything to paint
28 setZValue(ChartPresenter::PieSeriesZValue);
20 setZValue(ChartPresenter::PieSeriesZValue);
@@ -41,43 +33,38 void PiePresenter::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QW
41 //painter->drawRect(m_debugRect);
33 //painter->drawRect(m_debugRect);
42 }
34 }
43
35
44 void PiePresenter::handleSeriesChanged(const QPieSeries::ChangeSet& changeSet)
36 void PiePresenter::handleSeriesChanged()
45 {
37 {
46 //qDebug() << "PiePresenter::handleSeriesChanged()";
38 QVector<PieSliceLayout> sliceLayout = calculateLayout();
47 //qDebug() << " added : " << changeSet.added();
39 applyLayout(sliceLayout);
48 //qDebug() << " changed: " << changeSet.changed();
40 update();
49 //qDebug() << " removed: " << changeSet.removed();
41 }
50
51 foreach (QPieSlice* s, changeSet.added())
52 addSlice(s);
53
54 foreach (QPieSlice* s, changeSet.changed())
55 updateSlice(s);
56
57 foreach (QPieSlice* s, changeSet.removed())
58 deleteSlice(s);
59
42
60 // every change possibly changes the actual pie size
43 void PiePresenter::handleSliceChanged()
61 updateGeometry();
44 {
45 // TODO: optimize don't need to handle all slices
46 QVector<PieSliceLayout> sliceLayout = calculateLayout();
47 applyLayout(sliceLayout);
48 update();
62 }
49 }
63
50
64 void PiePresenter::handleDomainChanged(const Domain& domain)
51 void PiePresenter::handleDomainChanged(qreal, qreal, qreal, qreal)
65 {
52 {
66 // TODO
53 // TODO
67 }
54 }
68
55
69 void PiePresenter::handleGeometryChanged(const QRectF& rect)
56 void PiePresenter::handleGeometryChanged(const QRectF& rect)
70 {
57 {
71 m_rect = rect;
72 prepareGeometryChange();
58 prepareGeometryChange();
73 updateGeometry();
59 m_rect = rect;
60 QVector<PieSliceLayout> sliceLayout = calculateLayout();
61 applyLayout(sliceLayout);
62 update();
74 }
63 }
75
64
76 void PiePresenter::updateGeometry()
77 {
78 if (!m_rect.isValid() || m_rect.isEmpty())
79 return;
80
65
66 QVector<PieSliceLayout> PiePresenter::calculateLayout()
67 {
81 // find pie center coordinates
68 // find pie center coordinates
82 QPointF center;
69 QPointF center;
83 center.setX(m_rect.left() + (m_rect.width() * m_series->pieHorizontalPosition()));
70 center.setX(m_rect.left() + (m_rect.width() * m_series->pieHorizontalPosition()));
@@ -91,66 +78,64 void PiePresenter::updateGeometry()
91 // apply size factor
78 // apply size factor
92 radius *= m_series->pieSize();
79 radius *= m_series->pieSize();
93
80
94 // update slices
81 QVector<PieSliceLayout> layout;
95 if (m_pieCenter != center || m_pieRadius != radius) {
82 foreach (QPieSlice* s, m_series->slices()) {
96 m_pieCenter = center;
83 PieSliceLayout sliceLayout;
97 m_pieRadius = radius;
84 sliceLayout.m_data = s;
98 //qDebug() << "PiePresenter::updateGeometry()" << m_rect << m_pieCenter << m_pieRadius;
85 sliceLayout.m_center = PieSlice::sliceCenter(center, radius, s);
99 foreach (PieSlice* s, m_slices.values()) {
86 sliceLayout.m_radius = radius;
100 s->setPieCenterAndRadius(center, radius);
87 sliceLayout.m_startAngle = s->startAngle();
101 s->updateGeometry();
88 sliceLayout.m_angleSpan = s->m_angleSpan;
102 s->update();
89 layout << sliceLayout;
103 }
104 }
90 }
105
91
106 update();
92 return layout;
107 }
93 }
108
94
109 void PiePresenter::addSlice(QPieSlice* sliceData)
95 void PiePresenter::applyLayout(const QVector<PieSliceLayout> &layout)
110 {
96 {
111 //qDebug() << "PiePresenter::addSlice()" << sliceData;
97 //if(m_animator)
112
98 // m_animator->applyLayout(this,points);
113 if (m_slices.keys().contains(sliceData)) {
99 //else
114 Q_ASSERT(0); // TODO: how to handle this nicely?
100 setLayout(layout);
115 return;
116 }
117
118 // create slice
119 PieSlice *slice = new PieSlice(this);
120 slice->setPieCenterAndRadius(m_pieCenter, m_pieRadius);
121 slice->updateData(sliceData);
122 slice->updateGeometry();
123 slice->update();
124 m_slices.insert(sliceData, slice);
125
126 // connect signals
127 connect(slice, SIGNAL(clicked()), sliceData, SIGNAL(clicked()));
128 connect(slice, SIGNAL(hoverEnter()), sliceData, SIGNAL(hoverEnter()));
129 connect(slice, SIGNAL(hoverLeave()), sliceData, SIGNAL(hoverLeave()));
130 }
101 }
131
102
132 void PiePresenter::updateSlice(QPieSlice* sliceData)
103 void PiePresenter::setLayout(const QVector<PieSliceLayout> &layout)
133 {
104 {
134 //qDebug() << "PiePresenter::updateSlice()" << sliceData;
105 foreach (PieSliceLayout l, layout) {
106
107 // find slice
108 PieSlice *slice = m_slices.value(l.m_data);
109 if (!slice) {
110 // add a new slice
111 slice = new PieSlice(this);
112 m_slices.insert(l.m_data, slice);
113
114 // connect signals
115 connect(l.m_data, SIGNAL(changed()), this, SLOT(handleSliceChanged()));
116 connect(slice, SIGNAL(clicked()), l.m_data, SIGNAL(clicked()));
117 connect(slice, SIGNAL(hoverEnter()), l.m_data, SIGNAL(hoverEnter()));
118 connect(slice, SIGNAL(hoverLeave()), l.m_data, SIGNAL(hoverLeave()));
119 }
135
120
136 if (!m_slices.contains(sliceData)) {
121 // update
137 Q_ASSERT(0); // TODO: how to handle this nicely?
122 slice->setLayout(l);
138 return;
123 slice->updateGeometry();
124 slice->update();
139 }
125 }
140
126
141 m_slices[sliceData]->updateData(sliceData);
127 // delete slices
142 }
128 foreach (QPieSlice *s, m_slices.keys()) {
143
129
144 void PiePresenter::deleteSlice(QPieSlice* sliceData)
130 bool found = false;
145 {
131 foreach (PieSliceLayout l, layout) {
146 //qDebug() << "PiePresenter::deleteSlice()" << sliceData;
132 if (l.m_data == s)
133 found = true;
134 }
147
135
148 if (!m_slices.contains(sliceData)) {
136 if (!found)
149 Q_ASSERT(0); // TODO: how to handle this nicely?
137 delete m_slices.take(s);
150 return;
151 }
138 }
152
153 delete m_slices.take(sliceData);
154 }
139 }
155
140
156 #include "moc_piepresenter_p.cpp"
141 #include "moc_piepresenter_p.cpp"
@@ -1,13 +1,13
1 #ifndef PIEPRESENTER_H
1 #ifndef PIEPRESENTER_H
2 #define PIEPRESENTER_H
2 #define PIEPRESENTER_H
3
3
4 #include "chartitem_p.h"
5 #include "qpieseries.h"
4 #include "qpieseries.h"
6 #include <QSignalMapper>
5 #include "chartitem_p.h"
6 #include "pieslice_p.h"
7
7
8 class QGraphicsItem;
8 class QGraphicsItem;
9 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9 QTCOMMERCIALCHART_BEGIN_NAMESPACE
10 class PieSlice;
10 class QPieSlice;
11
11
12 class PiePresenter : public QObject, public ChartItem
12 class PiePresenter : public QObject, public ChartItem
13 {
13 {
@@ -23,15 +23,15 public: // from QGraphicsItem
23 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
23 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
24
24
25 public Q_SLOTS:
25 public Q_SLOTS:
26 void handleSeriesChanged(const QPieSeries::ChangeSet& changeSet);
26 void handleSeriesChanged();
27 void handleDomainChanged(const Domain& domain);
27 void handleSliceChanged();
28 void handleDomainChanged(qreal, qreal, qreal, qreal);
28 void handleGeometryChanged(const QRectF& rect);
29 void handleGeometryChanged(const QRectF& rect);
29 void updateGeometry();
30
30
31 private:
31 private:
32 void addSlice(QPieSlice* sliceData);
32 QVector<PieSliceLayout> calculateLayout();
33 void updateSlice(QPieSlice* sliceData);
33 void applyLayout(const QVector<PieSliceLayout> &layout);
34 void deleteSlice(QPieSlice* sliceData);
34 void setLayout(const QVector<PieSliceLayout> &layout);
35
35
36 private:
36 private:
37 friend class PieSlice;
37 friend class PieSlice;
@@ -22,7 +22,6 QPointF offset(qreal angle, qreal length)
22
22
23 PieSlice::PieSlice(QGraphicsItem* parent)
23 PieSlice::PieSlice(QGraphicsItem* parent)
24 :QGraphicsObject(parent),
24 :QGraphicsObject(parent),
25 m_pieRadius(0),
26 m_startAngle(0),
25 m_startAngle(0),
27 m_angleSpan(0),
26 m_angleSpan(0),
28 m_isExploded(false),
27 m_isExploded(false),
@@ -88,15 +87,15 void PieSlice::mousePressEvent(QGraphicsSceneMouseEvent* /*event*/)
88 emit clicked();
87 emit clicked();
89 }
88 }
90
89
91 void PieSlice::setPieCenterAndRadius(QPointF center, qreal radius)
90 void PieSlice::setLayout(PieSliceLayout layout)
92 {
91 {
93 m_pieCenter = center;
92 m_layout = layout;
94 m_pieRadius = radius;
93 updateData(layout.m_data);
95 }
94 }
96
95
97 void PieSlice::updateGeometry()
96 void PieSlice::updateGeometry()
98 {
97 {
99 if (m_pieRadius <= 0)
98 if (m_layout.m_radius <= 0)
100 return;
99 return;
101
100
102 prepareGeometryChange();
101 prepareGeometryChange();
@@ -104,14 +103,14 void PieSlice::updateGeometry()
104 // update slice path
103 // update slice path
105 qreal centerAngle;
104 qreal centerAngle;
106 QPointF armStart;
105 QPointF armStart;
107 m_slicePath = slicePath(m_pieCenter, m_pieRadius, m_startAngle, m_angleSpan, m_isExploded, m_pieRadius * m_explodeDistanceFactor, &centerAngle, &armStart);
106 m_slicePath = slicePath(m_layout.m_center, m_layout.m_radius, m_startAngle, m_angleSpan, &centerAngle, &armStart);
108
107
109 // update text rect
108 // update text rect
110 m_labelTextRect = labelTextRect(m_labelFont, m_labelText);
109 m_labelTextRect = labelTextRect(m_labelFont, m_labelText);
111
110
112 // update label arm path
111 // update label arm path
113 QPointF labelTextStart;
112 QPointF labelTextStart;
114 m_labelArmPath = labelArmPath(armStart, centerAngle, m_pieRadius * m_labelArmLengthFactor, m_labelTextRect.width(), &labelTextStart);
113 m_labelArmPath = labelArmPath(armStart, centerAngle, m_layout.m_radius * m_labelArmLengthFactor, m_labelTextRect.width(), &labelTextStart);
115
114
116 // update text position
115 // update text position
117 m_labelTextRect.moveBottomLeft(labelTextStart);
116 m_labelTextRect.moveBottomLeft(labelTextStart);
@@ -135,12 +134,21 void PieSlice::updateData(const QPieSlice* sliceData)
135 m_labelFont = sliceData->labelFont();
134 m_labelFont = sliceData->labelFont();
136 m_labelArmLengthFactor = sliceData->labelArmLengthFactor();
135 m_labelArmLengthFactor = sliceData->labelArmLengthFactor();
137 m_labelArmPen = sliceData->labelArmPen();
136 m_labelArmPen = sliceData->labelArmPen();
137 }
138
138
139 updateGeometry();
139 QPointF PieSlice::sliceCenter(QPointF point, qreal radius, QPieSlice *slice)
140 update();
140 {
141 if (slice->isExploded()) {
142 qreal centerAngle = slice->startAngle() + (slice->m_angleSpan/2);
143 qreal len = radius * slice->explodeDistanceFactor();
144 qreal dx = qSin(centerAngle*(PI/180)) * len;
145 qreal dy = -qCos(centerAngle*(PI/180)) * len;
146 point += QPointF(dx, dy);
147 }
148 return point;
141 }
149 }
142
150
143 QPainterPath PieSlice::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, bool exploded, qreal explodeDistance, qreal* centerAngle, QPointF* armStart)
151 QPainterPath PieSlice::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal* centerAngle, QPointF* armStart)
144 {
152 {
145 // calculate center angle
153 // calculate center angle
146 *centerAngle = startAngle + (angleSpan/2);
154 *centerAngle = startAngle + (angleSpan/2);
@@ -148,13 +156,6 QPainterPath PieSlice::slicePath(QPointF center, qreal radius, qreal startAngle,
148 // calculate slice rectangle
156 // calculate slice rectangle
149 QRectF rect(center.x()-radius, center.y()-radius, radius*2, radius*2);
157 QRectF rect(center.x()-radius, center.y()-radius, radius*2, radius*2);
150
158
151 // adjust rect for exploding
152 if (exploded) {
153 qreal dx = qSin(*centerAngle*(PI/180)) * explodeDistance;
154 qreal dy = -qCos(*centerAngle*(PI/180)) * explodeDistance;
155 rect.translate(dx, dy);
156 }
157
158 // slice path
159 // slice path
159 // TODO: draw the shape so that it might have a hole in the center
160 // TODO: draw the shape so that it might have a hole in the center
160 QPainterPath path;
161 QPainterPath path;
@@ -164,10 +165,7 QPainterPath PieSlice::slicePath(QPointF center, qreal radius, qreal startAngle,
164
165
165 // calculate label arm start point
166 // calculate label arm start point
166 *armStart = center;
167 *armStart = center;
167 if (exploded)
168 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
168 *armStart += offset(*centerAngle, explodeDistance + radius + PIESLICE_LABEL_GAP);
169 else
170 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
171
169
172 return path;
170 return path;
173 }
171 }
@@ -16,6 +16,16 class PiePresenter;
16 class PieSliceLabel;
16 class PieSliceLabel;
17 class QPieSlice;
17 class QPieSlice;
18
18
19 class PieSliceLayout
20 {
21 public:
22 QPieSlice* m_data;
23 QPointF m_center;
24 qreal m_radius;
25 qreal m_startAngle;
26 qreal m_angleSpan;
27 };
28
19 class PieSlice : public QGraphicsObject
29 class PieSlice : public QGraphicsObject
20 {
30 {
21 Q_OBJECT
31 Q_OBJECT
@@ -37,19 +47,17 Q_SIGNALS:
37 void hoverEnter();
47 void hoverEnter();
38 void hoverLeave();
48 void hoverLeave();
39
49
40 public Q_SLOTS:
50 public:
41 void setPieCenterAndRadius(QPointF center, qreal radius);
51 void setLayout(PieSliceLayout layout);
42 void updateGeometry();
52 void updateGeometry();
43 void updateData(const QPieSlice *sliceData);
53 void updateData(const QPieSlice *sliceData);
44
54 static QPointF sliceCenter(QPointF point, qreal radius, QPieSlice *slice);
45 public:
55 static QPainterPath slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal* centerAngle, QPointF* armStart);
46 static QPainterPath slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, bool exploded, qreal explodeDistance, qreal* centerAngle, QPointF* armStart);
47 static QPainterPath labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF* textStart);
56 static QPainterPath labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF* textStart);
48 static QRectF labelTextRect(QFont font, QString text);
57 static QRectF labelTextRect(QFont font, QString text);
49
58
50 private:
59 private:
51 QPointF m_pieCenter;
60 PieSliceLayout m_layout;
52 qreal m_pieRadius;
53
61
54 QPainterPath m_slicePath;
62 QPainterPath m_slicePath;
55 qreal m_startAngle;
63 qreal m_startAngle;
@@ -147,11 +147,9 void QPieSeries::replace(QList<QPieSlice*> slices)
147 */
147 */
148 void QPieSeries::add(QList<QPieSlice*> slices)
148 void QPieSeries::add(QList<QPieSlice*> slices)
149 {
149 {
150 ChangeSet changeSet;
151 foreach (QPieSlice* s, slices) {
150 foreach (QPieSlice* s, slices) {
152 s->setParent(this);
151 s->setParent(this);
153 m_slices << s;
152 m_slices << s;
154 changeSet.appendAdded(s);
155 }
153 }
156
154
157 updateDerivativeData();
155 updateDerivativeData();
@@ -163,7 +161,7 void QPieSeries::add(QList<QPieSlice*> slices)
163 connect(s, SIGNAL(hoverLeave()), this, SLOT(sliceHoverLeave()));
161 connect(s, SIGNAL(hoverLeave()), this, SLOT(sliceHoverLeave()));
164 }
162 }
165
163
166 emit changed(changeSet);
164 emit changed();
167 }
165 }
168
166
169 /*!
167 /*!
@@ -208,15 +206,12 void QPieSeries::remove(QPieSlice* slice)
208 Q_ASSERT(0); // TODO: how should this be reported?
206 Q_ASSERT(0); // TODO: how should this be reported?
209 return;
207 return;
210 }
208 }
209 emit changed();
211
210
212 ChangeSet changeSet;
211 updateDerivativeData();
213 changeSet.appendRemoved(slice);
214 emit changed(changeSet);
215
212
216 delete slice;
213 delete slice;
217 slice = NULL;
214 slice = NULL;
218
219 updateDerivativeData();
220 }
215 }
221
216
222 /*!
217 /*!
@@ -227,13 +222,13 void QPieSeries::clear()
227 if (m_slices.count() == 0)
222 if (m_slices.count() == 0)
228 return;
223 return;
229
224
230 ChangeSet changeSet;
231 foreach (QPieSlice* s, m_slices) {
225 foreach (QPieSlice* s, m_slices) {
232 changeSet.appendRemoved(s);
233 m_slices.removeOne(s);
226 m_slices.removeOne(s);
234 delete s;
227 delete s;
235 }
228 }
236 emit changed(changeSet);
229
230 emit changed();
231
237 updateDerivativeData();
232 updateDerivativeData();
238 }
233 }
239
234
@@ -276,7 +271,7 void QPieSeries::setPiePosition(qreal relativeHorizontalPosition, qreal relative
276 if (m_pieRelativeHorPos != relativeHorizontalPosition || m_pieRelativeVerPos != relativeVerticalPosition) {
271 if (m_pieRelativeHorPos != relativeHorizontalPosition || m_pieRelativeVerPos != relativeVerticalPosition) {
277 m_pieRelativeHorPos = relativeHorizontalPosition;
272 m_pieRelativeHorPos = relativeHorizontalPosition;
278 m_pieRelativeVerPos = relativeVerticalPosition;
273 m_pieRelativeVerPos = relativeVerticalPosition;
279 emit piePositionChanged();
274 emit changed();
280 }
275 }
281 }
276 }
282
277
@@ -330,7 +325,7 void QPieSeries::setPieSize(qreal relativeSize)
330
325
331 if (m_pieRelativeSize != relativeSize) {
326 if (m_pieRelativeSize != relativeSize) {
332 m_pieRelativeSize = relativeSize;
327 m_pieRelativeSize = relativeSize;
333 emit pieSizeChanged();
328 emit changed();
334 }
329 }
335 }
330 }
336
331
@@ -429,10 +424,9 qreal QPieSeries::total() const
429 }
424 }
430
425
431 /*!
426 /*!
432 \fn void QPieSeries::changed(const QPieSeries::ChangeSet& changeSet)
427 \fn void QPieSeries::changed()
433
428
434 This signal emitted when something has changed in the series.
429 This signal emitted when something has changed in the series.
435 The \a changeSet contains the details of which slices have been added, changed or removed.
436
430
437 \sa QPieSeries::ChangeSet, QPieSlice::changed()
431 \sa QPieSeries::ChangeSet, QPieSlice::changed()
438 */
432 */
@@ -461,31 +455,10 qreal QPieSeries::total() const
461 \sa QPieSlice::hoverLeave()
455 \sa QPieSlice::hoverLeave()
462 */
456 */
463
457
464 /*!
465 \fn void QPieSeries::pieSizeChanged()
466
467 This signal is emitted when size factor has been changed.
468
469 \sa pieSize(), setPieSize()
470 */
471
472 /*!
473 \fn void QPieSeries::piePositionChanged()
474
475 This signal is emitted when position of the pie has been changed.
476
477 \sa pieHorizontalPosition(), pieVerticalPosition(), setPiePosition()
478 */
479
480 void QPieSeries::sliceChanged()
458 void QPieSeries::sliceChanged()
481 {
459 {
482 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
460 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
483 Q_ASSERT(m_slices.contains(slice));
461 Q_ASSERT(m_slices.contains(slice));
484
485 ChangeSet changeSet;
486 changeSet.appendChanged(slice);
487 emit changed(changeSet);
488
489 updateDerivativeData();
462 updateDerivativeData();
490 }
463 }
491
464
@@ -97,11 +97,7 Q_SIGNALS:
97 void clicked(QPieSlice* slice);
97 void clicked(QPieSlice* slice);
98 void hoverEnter(QPieSlice* slice);
98 void hoverEnter(QPieSlice* slice);
99 void hoverLeave(QPieSlice* slice);
99 void hoverLeave(QPieSlice* slice);
100
100 void changed(); // TODO: hide this in PIMPL
101 void pieSizeChanged();
102 void piePositionChanged();
103
104 void changed(const QPieSeries::ChangeSet& changeSet); // TODO: hide this in PIMPL
105
101
106 private Q_SLOTS: // TODO: should be private and not visible in the interface at all
102 private Q_SLOTS: // TODO: should be private and not visible in the interface at all
107 void sliceChanged();
103 void sliceChanged();
General Comments 0
You need to be logged in to leave comments. Login now