##// END OF EJS Templates
Fix issue with pie label not drawn correctly when first created
Jani Honkonen -
r209:c977a59b6d90
parent child
Show More
@@ -1,156 +1,158
1 1
2 2 #include "piepresenter.h"
3 3 #include "pieslice.h"
4 4 #include "qpieslice.h"
5 5 #include <QDebug>
6 6 #include <QTime>
7 7
8 8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9 9
10 10 PiePresenter::PiePresenter(QGraphicsItem *parent, QPieSeries *series)
11 11 :ChartItem(parent),
12 12 m_series(series)
13 13 {
14 14 Q_ASSERT(series);
15 15 connect(series, SIGNAL(changed(const QPieSeries::ChangeSet&)), this, SLOT(handleSeriesChanged(const QPieSeries::ChangeSet&)));
16 16 connect(series, SIGNAL(sizeFactorChanged()), this, SLOT(updateGeometry()));
17 17 connect(series, SIGNAL(positionChanged()), this, SLOT(updateGeometry()));
18 18 }
19 19
20 20 PiePresenter::~PiePresenter()
21 21 {
22 22 // slices deleted automatically through QGraphicsItem
23 23 }
24 24
25 25 void PiePresenter::paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *)
26 26 {
27 27 // TODO: paint shadows for all components
28 28 // - get paths from items & merge & offset and draw with shadow color?
29 29 }
30 30
31 31 void PiePresenter::handleSeriesChanged(const QPieSeries::ChangeSet& changeSet)
32 32 {
33 33 //qDebug() << "PiePresenter::handleSeriesChanged()";
34 34 //qDebug() << " added : " << changeSet.added();
35 35 //qDebug() << " changed: " << changeSet.changed();
36 36 //qDebug() << " removed: " << changeSet.removed();
37 37
38 38 // ignore changeset when there are no visual slices
39 39 // changeset might not be valid about the added slices
40 40 if (m_slices.count() == 0) {
41 41 foreach (QPieSlice* s, m_series->m_slices)
42 42 addSlice(s);
43 43 return;
44 44 }
45 45
46 46 foreach (QPieSlice* s, changeSet.removed())
47 47 deleteSlice(s);
48 48
49 49 foreach (QPieSlice* s, changeSet.added())
50 50 addSlice(s);
51 51 }
52 52
53 53 void PiePresenter::handleDomainChanged(const Domain& domain)
54 54 {
55 55 // TODO
56 56 }
57 57
58 58 void PiePresenter::handleGeometryChanged(const QRectF& rect)
59 59 {
60 60 m_rect = rect;
61 61 updateGeometry();
62 62 }
63 63
64 64 void PiePresenter::updateGeometry()
65 65 {
66 66 prepareGeometryChange();
67 67
68 68 QRectF pieRect = m_rect;
69 69
70 70 if (pieRect.width() < pieRect.height()) {
71 71 pieRect.setWidth(pieRect.width() * m_series->sizeFactor());
72 72 pieRect.setHeight(pieRect.width());
73 73 pieRect.moveCenter(m_rect.center());
74 74 } else {
75 75 pieRect.setHeight(pieRect.height() * m_series->sizeFactor());
76 76 pieRect.setWidth(pieRect.height());
77 77 pieRect.moveCenter(m_rect.center());
78 78 }
79 79
80 80 switch (m_series->position()) {
81 81 case QPieSeries::PiePositionTopLeft: {
82 82 pieRect.setHeight(pieRect.height() / 2);
83 83 pieRect.setWidth(pieRect.height());
84 84 pieRect.moveCenter(QPointF(m_rect.center().x() / 2, m_rect.center().y() / 2));
85 85 break;
86 86 }
87 87 case QPieSeries::PiePositionTopRight: {
88 88 pieRect.setHeight(pieRect.height() / 2);
89 89 pieRect.setWidth(pieRect.height());
90 90 pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, m_rect.center().y() / 2));
91 91 break;
92 92 }
93 93 case QPieSeries::PiePositionBottomLeft: {
94 94 pieRect.setHeight(pieRect.height() / 2);
95 95 pieRect.setWidth(pieRect.height());
96 96 pieRect.moveCenter(QPointF(m_rect.center().x() / 2, (m_rect.center().y() / 2) * 3));
97 97 break;
98 98 }
99 99 case QPieSeries::PiePositionBottomRight: {
100 100 pieRect.setHeight(pieRect.height() / 2);
101 101 pieRect.setWidth(pieRect.height());
102 102 pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, (m_rect.center().y() / 2) * 3));
103 103 break;
104 104 }
105 105 default:
106 106 break;
107 107 }
108 108
109 109 if (m_pieRect != pieRect) {
110 110 m_pieRect = pieRect;
111 111 //qDebug() << "PiePresenter::updateGeometry()" << m_pieRect;
112 112 foreach (PieSlice* s, m_slices.values()) {
113 113 s->setPieRect(m_pieRect);
114 114 s->updateGeometry();
115 115 }
116 116 }
117 117 }
118 118
119 119 void PiePresenter::addSlice(QPieSlice* sliceData)
120 120 {
121 121 //qDebug() << "PiePresenter::addSlice()" << sliceData;
122 122
123 123 if (m_slices.keys().contains(sliceData)) {
124 124 //qWarning() << "PiePresenter::addSlice(): slice already exists!" << sliceData;
125 125 Q_ASSERT(0);
126 126 return;
127 127 }
128 128
129 129 // create slice
130 130 PieSlice *slice = new PieSlice(this);
131 131 slice->setPieRect(m_pieRect);
132 132 slice->updateData(sliceData);
133 slice->updateGeometry();
134 slice->update();
133 135 m_slices.insert(sliceData, slice);
134 136
135 137 // connect signals
136 138 connect(sliceData, SIGNAL(changed()), slice, SLOT(handleSliceDataChanged()));
137 139 connect(slice, SIGNAL(clicked()), sliceData, SIGNAL(clicked()));
138 140 connect(slice, SIGNAL(hoverEnter()), sliceData, SIGNAL(hoverEnter()));
139 141 connect(slice, SIGNAL(hoverLeave()), sliceData, SIGNAL(hoverLeave()));
140 142 }
141 143
142 144 void PiePresenter::deleteSlice(QPieSlice* sliceData)
143 145 {
144 146 //qDebug() << "PiePresenter::deleteSlice()" << sliceData;
145 147
146 148 if (m_slices.contains(sliceData))
147 149 delete m_slices.take(sliceData);
148 150 else {
149 151 // nothing to remove
150 152 Q_ASSERT(0); // TODO: remove before release
151 153 }
152 154 }
153 155
154 156 #include "moc_piepresenter.cpp"
155 157
156 158 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,143 +1,141
1 1 #include "pieslice.h"
2 2 #include "pieslicelabel.h"
3 3 #include "piepresenter.h"
4 4 #include "qpieseries.h"
5 5 #include "qpieslice.h"
6 6 #include <QPainter>
7 7 #include <QDebug>
8 8 #include <qmath.h>
9 9 #include <QGraphicsSceneEvent>
10 10 #include <QTime>
11 11
12 12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
13 13
14 14 #define PI 3.14159265
15 15 #define EXPLODE_OFFSET 20
16 16
17 17 QPointF offset(qreal angle, qreal length)
18 18 {
19 19 qreal dx = qSin(angle*(PI/180)) * length;
20 20 qreal dy = qCos(angle*(PI/180)) * length;
21 21 return QPointF(dx, -dy);
22 22 }
23 23
24 24 PieSlice::PieSlice(QGraphicsItem* parent)
25 25 :QGraphicsObject(parent),
26 26 m_slicelabel(new PieSliceLabel(this)),
27 27 m_angle(0),
28 28 m_span(0),
29 29 m_isExploded(false)
30 30 {
31 31 setAcceptHoverEvents(true);
32 32 setAcceptedMouseButtons(Qt::LeftButton);
33 33 }
34 34
35 35 PieSlice::~PieSlice()
36 36 {
37 37
38 38 }
39 39
40 40 QRectF PieSlice::boundingRect() const
41 41 {
42 42 return m_path.boundingRect();
43 43 }
44 44
45 45 QPainterPath PieSlice::shape() const
46 46 {
47 47 return m_path;
48 48 }
49 49
50 50 void PieSlice::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
51 51 {
52 52 painter->setRenderHint(QPainter::Antialiasing);
53 53 painter->setPen(m_pen);
54 54 painter->setBrush(m_brush);
55 55 painter->drawPath(m_path);
56 56 }
57 57
58 58 void PieSlice::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
59 59 {
60 60 emit hoverEnter();
61 61 }
62 62
63 63 void PieSlice::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
64 64 {
65 65 emit hoverLeave();
66 66 }
67 67
68 68 void PieSlice::mousePressEvent(QGraphicsSceneMouseEvent* /*event*/)
69 69 {
70 70 emit clicked();
71 71 }
72 72
73 73 void PieSlice::setPieRect(QRectF rect)
74 74 {
75 75 m_pieRect = rect;
76 76 }
77 77
78 78 void PieSlice::updateGeometry()
79 79 {
80 80 prepareGeometryChange();
81 81
82 82 // calculate center angle
83 83 qreal centerAngle = m_angle + (m_span/2);
84 84
85 85 // adjust rect for exploding
86 86 QRectF rect = m_pieRect;
87 87 rect.adjust(EXPLODE_OFFSET, EXPLODE_OFFSET, -EXPLODE_OFFSET ,-EXPLODE_OFFSET);
88 88 if (m_isExploded) {
89 89 QPointF d = offset((centerAngle), EXPLODE_OFFSET);
90 90 rect.translate(d.x(), d.y());
91 91 }
92 92
93 93 // update slice path
94 94 // TODO: draw the shape so that it might have a hole in the center
95 95 QPainterPath path;
96 96 path.moveTo(rect.center());
97 97 path.arcTo(rect, -m_angle + 90, -m_span);
98 98 path.closeSubpath();
99 99 m_path = path;
100 100
101 101 // update label position
102 102 qreal radius = rect.height() / 2;
103 103 QPointF edgeCenter = rect.center() + offset(centerAngle, radius + 5);
104
105 104 m_slicelabel->setArmStartPoint(edgeCenter);
106 105 m_slicelabel->setArmAngle(centerAngle);
107 106 m_slicelabel->updateGeometry();
108 107
109 108 //qDebug() << "PieSlice::updateGeometry" << m_slicelabel->text() << boundingRect() << m_angle << m_span;
110 109 }
111 110
112 111 void PieSlice::handleSliceDataChanged()
113 112 {
114 113 QPieSlice *slice = qobject_cast<QPieSlice*>(sender());
115 114 Q_ASSERT(slice);
116 115 updateData(slice);
117 116 }
118 117
119 118 void PieSlice::updateData(const QPieSlice* sliceData)
120 119 {
121 120 // TODO: compare what has changes to avoid unneccesary geometry updates
122 121
123 122 m_angle = sliceData->angle();
124 123 m_span = sliceData->span();
125 124 m_isExploded = sliceData->isExploded();
126 125 m_pen = sliceData->pen();
127 126 m_brush = sliceData->brush();
128 127
129 updateGeometry();
130 update();
131
132 128 m_slicelabel->setVisible(sliceData->isLabelVisible());
133 129 m_slicelabel->setText(sliceData->label());
134 130 m_slicelabel->setPen(sliceData->labelPen());
135 131 m_slicelabel->setFont(sliceData->labelFont());
136 132 m_slicelabel->setArmLength(sliceData->labelArmLenght());
137 m_slicelabel->updateGeometry(); // text size & font modifies the geometry
133
134 updateGeometry();
135 update();
138 136 m_slicelabel->update();
139 137 }
140 138
141 139 #include "moc_pieslice.cpp"
142 140
143 141 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,64 +1,70
1 1 #include "pieslicelabel.h"
2 2 #include <QPainter>
3 3 #include <qmath.h>
4 4 #include <QGraphicsTextItem>
5 #include <QDebug>
5 6
6 7 QTCOMMERCIALCHART_BEGIN_NAMESPACE
7 8
8 9 #define PI 3.14159265
9 10
10 11 PieSliceLabel::PieSliceLabel(QGraphicsItem* parent)
11 :QGraphicsItem(parent)
12 :QGraphicsItem(parent),
13 m_armAngle(0),
14 m_armLength(0)
12 15 {
13 // set defaults
14 m_pen = QPen(Qt::black);
16
15 17 }
16 18
17 19 void PieSliceLabel::paint(QPainter *painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
18 20 {
19 21 painter->setRenderHint(QPainter::Antialiasing);
20 22
21 23 painter->setPen(m_pen);
22 24 painter->drawPath(m_armPath);
23 25
24 26 // TODO: do we need a pen for text?
25 27 painter->setFont(m_font);
26 28 painter->drawText(m_textRect, m_text);
29
30 //qDebug() << "PieSliceLabel::paint" << m_text << m_textRect;
27 31 }
28 32
29 33 void PieSliceLabel::updateGeometry()
30 34 {
31 35 prepareGeometryChange();
32 36
33 37 // calculate text size
34 38 QFontMetricsF fm(m_font);
35 39 QRectF textRect = fm.boundingRect(m_text);
36 40
37 41 // calculate path for arm and text start point
38 42 qreal dx = qSin(m_armAngle*(PI/180)) * m_armLength;
39 43 qreal dy = -qCos(m_armAngle*(PI/180)) * m_armLength;
40 44 QPointF parm1 = m_armStartPoint + QPointF(dx, dy);
41 45
42 46 // calculate horizontal arm and text position
43 47 QPointF parm2 = parm1;
44 48 textRect.moveBottomLeft(parm1);
45 49 if (m_armAngle < 180) { // arm swings the other way on the left side
46 50 parm2 += QPointF(m_textRect.width(), 0);
47 51 } else {
48 52 parm2 += QPointF(-m_textRect.width(),0);
49 53 textRect.moveBottomLeft(parm2);
50 54 }
51 55
52 56 // update arm path
53 57 QPainterPath path;
54 58 path.moveTo(m_armStartPoint);
55 59 path.lineTo(parm1);
56 60 path.lineTo(parm2);
57 61
58 62 // update paths & rects
59 63 m_armPath = path;
60 64 m_textRect = textRect;
61 65 m_rect = path.boundingRect().united(m_textRect);
66
67 //qDebug() << "PieSliceLabel::updateGeometry" << m_text << m_armStartPoint << m_armLength << m_armAngle << m_textRect;
62 68 }
63 69
64 70 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now