##// END OF EJS Templates
PieSliceItem bounding rect fix
Jani Honkonen -
r718:7a2556deb83d
parent child
Show More
@@ -1,182 +1,185
1 #include "piesliceitem_p.h"
1 #include "piesliceitem_p.h"
2 #include "piechartitem_p.h"
2 #include "piechartitem_p.h"
3 #include "qpieseries.h"
3 #include "qpieseries.h"
4 #include "qpieslice.h"
4 #include "qpieslice.h"
5 #include "chartpresenter_p.h"
5 #include "chartpresenter_p.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 // TODO: is this defined in some header?
14 #define PI 3.14159265 // TODO: is this defined in some header?
15
15
16 QPointF offset(qreal angle, qreal length)
16 QPointF offset(qreal angle, qreal length)
17 {
17 {
18 qreal dx = qSin(angle*(PI/180)) * length;
18 qreal dx = qSin(angle*(PI/180)) * length;
19 qreal dy = qCos(angle*(PI/180)) * length;
19 qreal dy = qCos(angle*(PI/180)) * length;
20 return QPointF(dx, -dy);
20 return QPointF(dx, -dy);
21 }
21 }
22
22
23 PieSliceItem::PieSliceItem(QGraphicsItem* parent)
23 PieSliceItem::PieSliceItem(QGraphicsItem* parent)
24 :QGraphicsObject(parent)
24 :QGraphicsObject(parent)
25 {
25 {
26 setAcceptHoverEvents(true);
26 setAcceptHoverEvents(true);
27 setAcceptedMouseButtons(Qt::MouseButtonMask);
27 setAcceptedMouseButtons(Qt::MouseButtonMask);
28 setZValue(ChartPresenter::PieSeriesZValue);
28 setZValue(ChartPresenter::PieSeriesZValue);
29 }
29 }
30
30
31 PieSliceItem::~PieSliceItem()
31 PieSliceItem::~PieSliceItem()
32 {
32 {
33
33
34 }
34 }
35
35
36 QRectF PieSliceItem::boundingRect() const
36 QRectF PieSliceItem::boundingRect() const
37 {
37 {
38 return m_boundingRect;
38 return m_boundingRect;
39 }
39 }
40
40
41 QPainterPath PieSliceItem::shape() const
41 QPainterPath PieSliceItem::shape() const
42 {
42 {
43 // Don't include the label and label arm.
43 // Don't include the label and label arm.
44 // This is used to detect a mouse clicks. We do not want clicks from label.
44 // This is used to detect a mouse clicks. We do not want clicks from label.
45 return m_slicePath;
45 return m_slicePath;
46 }
46 }
47
47
48 void PieSliceItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
48 void PieSliceItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
49 {
49 {
50 painter->setClipRect(parentItem()->boundingRect());
50 painter->setClipRect(parentItem()->boundingRect());
51
51
52 painter->save();
52 painter->save();
53 painter->setPen(m_data.m_slicePen);
53 painter->setPen(m_data.m_slicePen);
54 painter->setBrush(m_data.m_sliceBrush);
54 painter->setBrush(m_data.m_sliceBrush);
55 painter->drawPath(m_slicePath);
55 painter->drawPath(m_slicePath);
56 painter->restore();
56 painter->restore();
57
57
58 if (m_data.m_isLabelVisible) {
58 if (m_data.m_isLabelVisible) {
59 painter->setPen(m_data.m_labelPen);
59 painter->setPen(m_data.m_labelPen);
60 painter->drawPath(m_labelArmPath);
60 painter->drawPath(m_labelArmPath);
61 // the pen color will affect the font color as well
61 // the pen color will affect the font color as well
62 painter->setFont(m_data.m_labelFont);
62 painter->setFont(m_data.m_labelFont);
63 painter->drawText(m_labelTextRect.bottomLeft(), m_data.m_labelText);
63 painter->drawText(m_labelTextRect.bottomLeft(), m_data.m_labelText);
64 }
64 }
65 }
65 }
66
66
67 void PieSliceItem::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
67 void PieSliceItem::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
68 {
68 {
69 emit hoverEnter();
69 emit hoverEnter();
70 }
70 }
71
71
72 void PieSliceItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
72 void PieSliceItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
73 {
73 {
74 emit hoverLeave();
74 emit hoverLeave();
75 }
75 }
76
76
77 void PieSliceItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
77 void PieSliceItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
78 {
78 {
79 emit clicked(event->buttons());
79 emit clicked(event->buttons());
80 }
80 }
81
81
82 void PieSliceItem::setSliceData(PieSliceData sliceData)
82 void PieSliceItem::setSliceData(PieSliceData sliceData)
83 {
83 {
84 m_data = sliceData;
84 m_data = sliceData;
85 }
85 }
86
86
87 void PieSliceItem::updateGeometry()
87 void PieSliceItem::updateGeometry()
88 {
88 {
89 if (m_data.m_radius <= 0)
89 if (m_data.m_radius <= 0)
90 return;
90 return;
91
91
92 prepareGeometryChange();
92 prepareGeometryChange();
93
93
94 // update slice path
94 // update slice path
95 qreal centerAngle;
95 qreal centerAngle;
96 QPointF armStart;
96 QPointF armStart;
97 m_slicePath = slicePath(m_data.m_center, m_data.m_radius, m_data.m_startAngle, m_data.m_angleSpan, &centerAngle, &armStart);
97 m_slicePath = slicePath(m_data.m_center, m_data.m_radius, m_data.m_startAngle, m_data.m_angleSpan, &centerAngle, &armStart);
98
98
99 // update text rect
99 // update text rect
100 m_labelTextRect = labelTextRect(m_data.m_labelFont, m_data.m_labelText);
100 m_labelTextRect = labelTextRect(m_data.m_labelFont, m_data.m_labelText);
101
101
102 // update label arm path
102 // update label arm path
103 QPointF labelTextStart;
103 QPointF labelTextStart;
104 m_labelArmPath = labelArmPath(armStart, centerAngle, m_data.m_radius * m_data.m_labelArmLengthFactor, m_labelTextRect.width(), &labelTextStart);
104 m_labelArmPath = labelArmPath(armStart, centerAngle, m_data.m_radius * m_data.m_labelArmLengthFactor, m_labelTextRect.width(), &labelTextStart);
105
105
106 // update text position
106 // update text position
107 m_labelTextRect.moveBottomLeft(labelTextStart);
107 m_labelTextRect.moveBottomLeft(labelTextStart);
108
108
109 // update bounding rect
109 // update bounding rect
110 if (m_data.m_isLabelVisible)
110 m_boundingRect = m_slicePath.boundingRect().united(m_labelArmPath.boundingRect()).united(m_labelTextRect);
111 m_boundingRect = m_slicePath.boundingRect().united(m_labelArmPath.boundingRect()).united(m_labelTextRect);
112 else
113 m_boundingRect = m_slicePath.boundingRect();
111 }
114 }
112
115
113 QPointF PieSliceItem::sliceCenter(QPointF point, qreal radius, QPieSlice *slice)
116 QPointF PieSliceItem::sliceCenter(QPointF point, qreal radius, QPieSlice *slice)
114 {
117 {
115 if (slice->isExploded()) {
118 if (slice->isExploded()) {
116 qreal centerAngle = slice->startAngle() + ((slice->endAngle() - slice->startAngle())/2);
119 qreal centerAngle = slice->startAngle() + ((slice->endAngle() - slice->startAngle())/2);
117 qreal len = radius * slice->explodeDistanceFactor();
120 qreal len = radius * slice->explodeDistanceFactor();
118 qreal dx = qSin(centerAngle*(PI/180)) * len;
121 qreal dx = qSin(centerAngle*(PI/180)) * len;
119 qreal dy = -qCos(centerAngle*(PI/180)) * len;
122 qreal dy = -qCos(centerAngle*(PI/180)) * len;
120 point += QPointF(dx, dy);
123 point += QPointF(dx, dy);
121 }
124 }
122 return point;
125 return point;
123 }
126 }
124
127
125 QPainterPath PieSliceItem::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal* centerAngle, QPointF* armStart)
128 QPainterPath PieSliceItem::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal* centerAngle, QPointF* armStart)
126 {
129 {
127 // calculate center angle
130 // calculate center angle
128 *centerAngle = startAngle + (angleSpan/2);
131 *centerAngle = startAngle + (angleSpan/2);
129
132
130 // calculate slice rectangle
133 // calculate slice rectangle
131 QRectF rect(center.x()-radius, center.y()-radius, radius*2, radius*2);
134 QRectF rect(center.x()-radius, center.y()-radius, radius*2, radius*2);
132
135
133 // slice path
136 // slice path
134 // TODO: draw the shape so that it might have a hole in the center
137 // TODO: draw the shape so that it might have a hole in the center
135 QPainterPath path;
138 QPainterPath path;
136 path.moveTo(rect.center());
139 path.moveTo(rect.center());
137 path.arcTo(rect, -startAngle + 90, -angleSpan);
140 path.arcTo(rect, -startAngle + 90, -angleSpan);
138 path.closeSubpath();
141 path.closeSubpath();
139
142
140 // calculate label arm start point
143 // calculate label arm start point
141 *armStart = center;
144 *armStart = center;
142 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
145 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
143
146
144 return path;
147 return path;
145 }
148 }
146
149
147 QPainterPath PieSliceItem::labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF* textStart)
150 QPainterPath PieSliceItem::labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF* textStart)
148 {
151 {
149 qreal dx = qSin(angle*(PI/180)) * length;
152 qreal dx = qSin(angle*(PI/180)) * length;
150 qreal dy = -qCos(angle*(PI/180)) * length;
153 qreal dy = -qCos(angle*(PI/180)) * length;
151 QPointF parm1 = start + QPointF(dx, dy);
154 QPointF parm1 = start + QPointF(dx, dy);
152
155
153 QPointF parm2 = parm1;
156 QPointF parm2 = parm1;
154 if (angle < 180) { // arm swings the other way on the left side
157 if (angle < 180) { // arm swings the other way on the left side
155 parm2 += QPointF(textWidth, 0);
158 parm2 += QPointF(textWidth, 0);
156 *textStart = parm1;
159 *textStart = parm1;
157 }
160 }
158 else {
161 else {
159 parm2 += QPointF(-textWidth,0);
162 parm2 += QPointF(-textWidth,0);
160 *textStart = parm2;
163 *textStart = parm2;
161 }
164 }
162
165
163 // elevate the text position a bit so that it does not hit the line
166 // elevate the text position a bit so that it does not hit the line
164 *textStart += QPointF(0, -5);
167 *textStart += QPointF(0, -5);
165
168
166 QPainterPath path;
169 QPainterPath path;
167 path.moveTo(start);
170 path.moveTo(start);
168 path.lineTo(parm1);
171 path.lineTo(parm1);
169 path.lineTo(parm2);
172 path.lineTo(parm2);
170
173
171 return path;
174 return path;
172 }
175 }
173
176
174 QRectF PieSliceItem::labelTextRect(QFont font, QString text)
177 QRectF PieSliceItem::labelTextRect(QFont font, QString text)
175 {
178 {
176 QFontMetricsF fm(font);
179 QFontMetricsF fm(font);
177 return fm.boundingRect(text);
180 return fm.boundingRect(text);
178 }
181 }
179
182
180 #include "moc_piesliceitem_p.cpp"
183 #include "moc_piesliceitem_p.cpp"
181
184
182 QTCOMMERCIALCHART_END_NAMESPACE
185 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now