##// END OF EJS Templates
Fix long labels visibility for QBarChart...
Titta Heikkala -
r2604:776457a845dd
parent child
Show More
@@ -1,223 +1,219
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2013 Digia Plc
3 ** Copyright (C) 2013 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 **
6 **
7 ** This file is part of the Qt Enterprise Charts Add-on.
7 ** This file is part of the Qt Enterprise Charts Add-on.
8 **
8 **
9 ** $QT_BEGIN_LICENSE$
9 ** $QT_BEGIN_LICENSE$
10 ** Licensees holding valid Qt Enterprise licenses may use this file in
10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 ** accordance with the Qt Enterprise License Agreement provided with the
11 ** accordance with the Qt Enterprise License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.
13 ** a written agreement between you and Digia.
14 **
14 **
15 ** If you have questions regarding the use of this file, please use
15 ** If you have questions regarding the use of this file, please use
16 ** contact form at http://qt.digia.com
16 ** contact form at http://qt.digia.com
17 ** $QT_END_LICENSE$
17 ** $QT_END_LICENSE$
18 **
18 **
19 ****************************************************************************/
19 ****************************************************************************/
20
20
21 #include "horizontalaxis_p.h"
21 #include "horizontalaxis_p.h"
22 #include "qabstractaxis_p.h"
22 #include "qabstractaxis_p.h"
23 #include "chartpresenter_p.h"
23 #include "chartpresenter_p.h"
24 #include <qmath.h>
24 #include <qmath.h>
25 #include <QDebug>
25 #include <QDebug>
26
26
27 QTCOMMERCIALCHART_BEGIN_NAMESPACE
27 QTCOMMERCIALCHART_BEGIN_NAMESPACE
28
28
29 HorizontalAxis::HorizontalAxis(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
29 HorizontalAxis::HorizontalAxis(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
30 : CartesianChartAxis(axis, item, intervalAxis)
30 : CartesianChartAxis(axis, item, intervalAxis)
31 {
31 {
32 }
32 }
33
33
34 HorizontalAxis::~HorizontalAxis()
34 HorizontalAxis::~HorizontalAxis()
35 {
35 {
36 }
36 }
37
37
38 void HorizontalAxis::updateGeometry()
38 void HorizontalAxis::updateGeometry()
39 {
39 {
40 const QVector<qreal> &layout = ChartAxisElement::layout();
40 const QVector<qreal> &layout = ChartAxisElement::layout();
41
41
42 if (layout.isEmpty())
42 if (layout.isEmpty())
43 return;
43 return;
44
44
45 QStringList labelList = labels();
45 QStringList labelList = labels();
46
46
47 QList<QGraphicsItem *> lines = gridItems();
47 QList<QGraphicsItem *> lines = gridItems();
48 QList<QGraphicsItem *> labels = labelItems();
48 QList<QGraphicsItem *> labels = labelItems();
49 QList<QGraphicsItem *> shades = shadeItems();
49 QList<QGraphicsItem *> shades = shadeItems();
50 QList<QGraphicsItem *> arrow = arrowItems();
50 QList<QGraphicsItem *> arrow = arrowItems();
51 QGraphicsTextItem *title = titleItem();
51 QGraphicsTextItem *title = titleItem();
52
52
53 Q_ASSERT(labels.size() == labelList.size());
53 Q_ASSERT(labels.size() == labelList.size());
54 Q_ASSERT(layout.size() == labelList.size());
54 Q_ASSERT(layout.size() == labelList.size());
55
55
56 const QRectF &axisRect = axisGeometry();
56 const QRectF &axisRect = axisGeometry();
57 const QRectF &gridRect = gridGeometry();
57 const QRectF &gridRect = gridGeometry();
58
58
59 //arrow
59 //arrow
60 QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem *>(arrow.at(0));
60 QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem *>(arrow.at(0));
61
61
62 if (axis()->alignment() == Qt::AlignTop)
62 if (axis()->alignment() == Qt::AlignTop)
63 arrowItem->setLine(gridRect.left(), axisRect.bottom(), gridRect.right(), axisRect.bottom());
63 arrowItem->setLine(gridRect.left(), axisRect.bottom(), gridRect.right(), axisRect.bottom());
64 else if (axis()->alignment() == Qt::AlignBottom)
64 else if (axis()->alignment() == Qt::AlignBottom)
65 arrowItem->setLine(gridRect.left(), axisRect.top(), gridRect.right(), axisRect.top());
65 arrowItem->setLine(gridRect.left(), axisRect.top(), gridRect.right(), axisRect.top());
66
66
67 qreal width = 0;
67 qreal width = 0;
68
68
69 //title
69 //title
70 QRectF titleBoundingRect;
70 QRectF titleBoundingRect;
71 QString titleText = axis()->titleText();
71 QString titleText = axis()->titleText();
72 qreal availableSpace = axisRect.height() - labelPadding();
72 qreal availableSpace = axisRect.height() - labelPadding();
73 if (!titleText.isEmpty() && titleItem()->isVisible()) {
73 if (!titleText.isEmpty() && titleItem()->isVisible()) {
74 availableSpace -= titlePadding() * 2.0;
74 availableSpace -= titlePadding() * 2.0;
75 qreal minimumLabelHeight = ChartPresenter::textBoundingRect(axis()->labelsFont(), "...").height();
75 qreal minimumLabelHeight = ChartPresenter::textBoundingRect(axis()->labelsFont(), "...").height();
76 QString truncatedTitle = ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0),
77 gridRect.width(), Qt::Horizontal, titleBoundingRect);
78 qreal titleSpace = availableSpace - minimumLabelHeight;
76 qreal titleSpace = availableSpace - minimumLabelHeight;
79 if (titleSpace < titleBoundingRect.height()) {
77 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0),
80 // Need to also truncate title vertically (multiline title)
78 gridRect.width(), titleSpace,
81 bool skip = false;
79 titleBoundingRect));
82 if (truncatedTitle.endsWith("...")) {
83 if (truncatedTitle.size() == 3)
84 skip = true; // Already truncated to minimum
85 else
86 truncatedTitle.chop(3);
87 }
88 if (!skip)
89 truncatedTitle = ChartPresenter::truncatedText(axis()->titleFont(), truncatedTitle, qreal(0.0),
90 titleSpace, Qt::Vertical, titleBoundingRect);
91 }
92 title->setHtml(truncatedTitle);
93
80
94 titleBoundingRect = title->boundingRect();
81 titleBoundingRect = title->boundingRect();
95
82
96 QPointF center = gridRect.center() - titleBoundingRect.center();
83 QPointF center = gridRect.center() - titleBoundingRect.center();
97 if (axis()->alignment() == Qt::AlignTop)
84 if (axis()->alignment() == Qt::AlignTop)
98 title->setPos(center.x(), axisRect.top() + titlePadding());
85 title->setPos(center.x(), axisRect.top() + titlePadding());
99 else if (axis()->alignment() == Qt::AlignBottom)
86 else if (axis()->alignment() == Qt::AlignBottom)
100 title->setPos(center.x(), axisRect.bottom() - titleBoundingRect.height() - titlePadding());
87 title->setPos(center.x(), axisRect.bottom() - titleBoundingRect.height() - titlePadding());
101
88
102 availableSpace -= titleBoundingRect.height();
89 availableSpace -= titleBoundingRect.height();
103 }
90 }
104
91
105 for (int i = 0; i < layout.size(); ++i) {
92 for (int i = 0; i < layout.size(); ++i) {
106 //items
93 //items
107 QGraphicsLineItem *gridItem = static_cast<QGraphicsLineItem*>(lines.at(i));
94 QGraphicsLineItem *gridItem = static_cast<QGraphicsLineItem*>(lines.at(i));
108 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem*>(arrow.at(i + 1));
95 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem*>(arrow.at(i + 1));
109 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labels.at(i));
96 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labels.at(i));
110
97
111 //grid line
98 //grid line
112 gridItem->setLine(layout[i], gridRect.top(), layout[i], gridRect.bottom());
99 gridItem->setLine(layout[i], gridRect.top(), layout[i], gridRect.bottom());
113
100
114 //label text wrapping
101 //label text wrapping
115 QString text = labelList.at(i);
102 QString text = labelList.at(i);
116 QRectF boundingRect;
103 QRectF boundingRect;
117 labelItem->setHtml(ChartPresenter::truncatedText(axis()->labelsFont(), text, axis()->labelsAngle(),
104 // don't truncate empty labels
118 availableSpace, Qt::Vertical, boundingRect));
105 if (text.isEmpty()) {
106 labelItem->setHtml(text);
107 } else {
108 qreal labelWidth = axisRect.width() / layout.count() - (2 * labelPadding());
109 labelItem->setHtml(ChartPresenter::truncatedText(axis()->labelsFont(), text,
110 axis()->labelsAngle(), labelWidth,
111 availableSpace, boundingRect));
112 }
119
113
120 //label transformation origin point
114 //label transformation origin point
121 const QRectF& rect = labelItem->boundingRect();
115 const QRectF& rect = labelItem->boundingRect();
122 QPointF center = rect.center();
116 QPointF center = rect.center();
123 labelItem->setTransformOriginPoint(center.x(), center.y());
117 labelItem->setTransformOriginPoint(center.x(), center.y());
124 qreal heightDiff = rect.height() - boundingRect.height();
118 qreal heightDiff = rect.height() - boundingRect.height();
125 qreal widthDiff = rect.width() - boundingRect.width();
119 qreal widthDiff = rect.width() - boundingRect.width();
126
120
127 //ticks and label position
121 //ticks and label position
128 if (axis()->alignment() == Qt::AlignTop) {
122 if (axis()->alignment() == Qt::AlignTop) {
129 labelItem->setPos(layout[i] - center.x(), axisRect.bottom() - rect.height() + (heightDiff / 2.0) - labelPadding());
123 labelItem->setPos(layout[i] - center.x(), axisRect.bottom() - rect.height() + (heightDiff / 2.0) - labelPadding());
130 tickItem->setLine(layout[i], axisRect.bottom(), layout[i], axisRect.bottom() - labelPadding());
124 tickItem->setLine(layout[i], axisRect.bottom(), layout[i], axisRect.bottom() - labelPadding());
131 } else if (axis()->alignment() == Qt::AlignBottom) {
125 } else if (axis()->alignment() == Qt::AlignBottom) {
132 labelItem->setPos(layout[i] - center.x(), axisRect.top() - (heightDiff / 2.0) + labelPadding());
126 labelItem->setPos(layout[i] - center.x(), axisRect.top() - (heightDiff / 2.0) + labelPadding());
133 tickItem->setLine(layout[i], axisRect.top(), layout[i], axisRect.top() + labelPadding());
127 tickItem->setLine(layout[i], axisRect.top(), layout[i], axisRect.top() + labelPadding());
134 }
128 }
135
129
136 //label in between
130 //label in between
137 bool forceHide = false;
131 bool forceHide = false;
138 if (intervalAxis() && (i + 1) != layout.size()) {
132 if (intervalAxis() && (i + 1) != layout.size()) {
139 qreal leftBound = qMax(layout[i], gridRect.left());
133 qreal leftBound = qMax(layout[i], gridRect.left());
140 qreal rightBound = qMin(layout[i + 1], gridRect.right());
134 qreal rightBound = qMin(layout[i + 1], gridRect.right());
141 const qreal delta = rightBound - leftBound;
135 const qreal delta = rightBound - leftBound;
142 // Hide label in case visible part of the category at the grid edge is too narrow
136 // Hide label in case visible part of the category at the grid edge is too narrow
143 if (delta < boundingRect.width()
137 if (delta < boundingRect.width()
144 && (leftBound == gridRect.left() || rightBound == gridRect.right())) {
138 && (leftBound == gridRect.left() || rightBound == gridRect.right())
139 && !intervalAxis()) {
145 forceHide = true;
140 forceHide = true;
146 } else {
141 } else {
147 labelItem->setPos(leftBound + (delta / 2.0) - center.x(), labelItem->pos().y());
142 labelItem->setPos(leftBound + (delta / 2.0) - center.x(), labelItem->pos().y());
148 }
143 }
149 }
144 }
150 //label overlap detection - compensate one pixel for rounding errors
145 //label overlap detection - compensate one pixel for rounding errors
151 if (labelItem->pos().x() < width || forceHide ||
146 if ((labelItem->pos().x() < width || forceHide ||
152 (labelItem->pos().x() + (widthDiff / 2.0)) < (axisRect.left() - 1.0) ||
147 (labelItem->pos().x() + (widthDiff / 2.0)) < (axisRect.left() - 1.0) ||
153 (labelItem->pos().x() + (widthDiff / 2.0) - 1.0) > axisRect.right()){
148 (labelItem->pos().x() + (widthDiff / 2.0) - 1.0) > axisRect.right())
149 && !intervalAxis()) {
154 labelItem->setVisible(false);
150 labelItem->setVisible(false);
155 } else {
151 } else {
156 labelItem->setVisible(true);
152 labelItem->setVisible(true);
157 width = boundingRect.width() + labelItem->pos().x();
153 width = boundingRect.width() + labelItem->pos().x();
158 }
154 }
159
155
160 //shades
156 //shades
161 if ((i + 1) % 2 && i > 1) {
157 if ((i + 1) % 2 && i > 1) {
162 QGraphicsRectItem *rectItem = static_cast<QGraphicsRectItem *>(shades.at(i / 2 - 1));
158 QGraphicsRectItem *rectItem = static_cast<QGraphicsRectItem *>(shades.at(i / 2 - 1));
163 qreal leftBound = qMax(layout[i - 1], gridRect.left());
159 qreal leftBound = qMax(layout[i - 1], gridRect.left());
164 qreal rightBound = qMin(layout[i], gridRect.right());
160 qreal rightBound = qMin(layout[i], gridRect.right());
165 rectItem->setRect(leftBound, gridRect.top(), rightBound - leftBound, gridRect.height());
161 rectItem->setRect(leftBound, gridRect.top(), rightBound - leftBound, gridRect.height());
166 if (rectItem->rect().width() <= 0.0)
162 if (rectItem->rect().width() <= 0.0)
167 rectItem->setVisible(false);
163 rectItem->setVisible(false);
168 else
164 else
169 rectItem->setVisible(true);
165 rectItem->setVisible(true);
170 }
166 }
171
167
172 // check if the grid line and the axis tick should be shown
168 // check if the grid line and the axis tick should be shown
173 qreal x = gridItem->line().p1().x();
169 qreal x = gridItem->line().p1().x();
174 if (x < gridRect.left() || x > gridRect.right()) {
170 if (x < gridRect.left() || x > gridRect.right()) {
175 gridItem->setVisible(false);
171 gridItem->setVisible(false);
176 tickItem->setVisible(false);
172 tickItem->setVisible(false);
177 } else {
173 } else {
178 gridItem->setVisible(true);
174 gridItem->setVisible(true);
179 tickItem->setVisible(true);
175 tickItem->setVisible(true);
180 }
176 }
181
177
182 }
178 }
183
179
184 //begin/end grid line in case labels between
180 //begin/end grid line in case labels between
185 if (intervalAxis()) {
181 if (intervalAxis()) {
186 QGraphicsLineItem *gridLine;
182 QGraphicsLineItem *gridLine;
187 gridLine = static_cast<QGraphicsLineItem *>(lines.at(layout.size()));
183 gridLine = static_cast<QGraphicsLineItem *>(lines.at(layout.size()));
188 gridLine->setLine(gridRect.right(), gridRect.top(), gridRect.right(), gridRect.bottom());
184 gridLine->setLine(gridRect.right(), gridRect.top(), gridRect.right(), gridRect.bottom());
189 gridLine->setVisible(true);
185 gridLine->setVisible(true);
190 gridLine = static_cast<QGraphicsLineItem*>(lines.at(layout.size()+1));
186 gridLine = static_cast<QGraphicsLineItem*>(lines.at(layout.size()+1));
191 gridLine->setLine(gridRect.left(), gridRect.top(), gridRect.left(), gridRect.bottom());
187 gridLine->setLine(gridRect.left(), gridRect.top(), gridRect.left(), gridRect.bottom());
192 gridLine->setVisible(true);
188 gridLine->setVisible(true);
193 }
189 }
194 }
190 }
195
191
196 QSizeF HorizontalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
192 QSizeF HorizontalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
197 {
193 {
198 Q_UNUSED(constraint);
194 Q_UNUSED(constraint);
199 QSizeF sh(0,0);
195 QSizeF sh(0,0);
200
196
201 if (axis()->titleText().isEmpty() || !titleItem()->isVisible())
197 if (axis()->titleText().isEmpty() || !titleItem()->isVisible())
202 return sh;
198 return sh;
203
199
204 switch (which) {
200 switch (which) {
205 case Qt::MinimumSize: {
201 case Qt::MinimumSize: {
206 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), "...");
202 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), "...");
207 sh = QSizeF(titleRect.width(), titleRect.height() + (titlePadding() * 2.0));
203 sh = QSizeF(titleRect.width(), titleRect.height() + (titlePadding() * 2.0));
208 break;
204 break;
209 }
205 }
210 case Qt::MaximumSize:
206 case Qt::MaximumSize:
211 case Qt::PreferredSize: {
207 case Qt::PreferredSize: {
212 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText());
208 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText());
213 sh = QSizeF(titleRect.width(), titleRect.height() + (titlePadding() * 2.0));
209 sh = QSizeF(titleRect.width(), titleRect.height() + (titlePadding() * 2.0));
214 break;
210 break;
215 }
211 }
216 default:
212 default:
217 break;
213 break;
218 }
214 }
219
215
220 return sh;
216 return sh;
221 }
217 }
222
218
223 QTCOMMERCIALCHART_END_NAMESPACE
219 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,422 +1,427
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2013 Digia Plc
3 ** Copyright (C) 2013 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 **
6 **
7 ** This file is part of the Qt Enterprise Charts Add-on.
7 ** This file is part of the Qt Enterprise Charts Add-on.
8 **
8 **
9 ** $QT_BEGIN_LICENSE$
9 ** $QT_BEGIN_LICENSE$
10 ** Licensees holding valid Qt Enterprise licenses may use this file in
10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 ** accordance with the Qt Enterprise License Agreement provided with the
11 ** accordance with the Qt Enterprise License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.
13 ** a written agreement between you and Digia.
14 **
14 **
15 ** If you have questions regarding the use of this file, please use
15 ** If you have questions regarding the use of this file, please use
16 ** contact form at http://qt.digia.com
16 ** contact form at http://qt.digia.com
17 ** $QT_END_LICENSE$
17 ** $QT_END_LICENSE$
18 **
18 **
19 ****************************************************************************/
19 ****************************************************************************/
20
20
21 #include "polarchartaxisangular_p.h"
21 #include "polarchartaxisangular_p.h"
22 #include "chartpresenter_p.h"
22 #include "chartpresenter_p.h"
23 #include "abstractchartlayout_p.h"
23 #include "abstractchartlayout_p.h"
24 #include "qabstractaxis.h"
24 #include "qabstractaxis.h"
25 #include "qabstractaxis_p.h"
25 #include "qabstractaxis_p.h"
26 #include <QDebug>
26 #include <QDebug>
27 #include <qmath.h>
27 #include <qmath.h>
28 #include <QTextDocument>
28 #include <QTextDocument>
29
29
30 QTCOMMERCIALCHART_BEGIN_NAMESPACE
30 QTCOMMERCIALCHART_BEGIN_NAMESPACE
31
31
32 PolarChartAxisAngular::PolarChartAxisAngular(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
32 PolarChartAxisAngular::PolarChartAxisAngular(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
33 : PolarChartAxis(axis, item, intervalAxis)
33 : PolarChartAxis(axis, item, intervalAxis)
34 {
34 {
35 }
35 }
36
36
37 PolarChartAxisAngular::~PolarChartAxisAngular()
37 PolarChartAxisAngular::~PolarChartAxisAngular()
38 {
38 {
39 }
39 }
40
40
41 void PolarChartAxisAngular::updateGeometry()
41 void PolarChartAxisAngular::updateGeometry()
42 {
42 {
43 QGraphicsLayoutItem::updateGeometry();
43 QGraphicsLayoutItem::updateGeometry();
44
44
45 const QVector<qreal> &layout = this->layout();
45 const QVector<qreal> &layout = this->layout();
46 if (layout.isEmpty())
46 if (layout.isEmpty())
47 return;
47 return;
48
48
49 createAxisLabels(layout);
49 createAxisLabels(layout);
50 QStringList labelList = labels();
50 QStringList labelList = labels();
51 QPointF center = axisGeometry().center();
51 QPointF center = axisGeometry().center();
52 QList<QGraphicsItem *> arrowItemList = arrowItems();
52 QList<QGraphicsItem *> arrowItemList = arrowItems();
53 QList<QGraphicsItem *> gridItemList = gridItems();
53 QList<QGraphicsItem *> gridItemList = gridItems();
54 QList<QGraphicsItem *> labelItemList = labelItems();
54 QList<QGraphicsItem *> labelItemList = labelItems();
55 QList<QGraphicsItem *> shadeItemList = shadeItems();
55 QList<QGraphicsItem *> shadeItemList = shadeItems();
56 QGraphicsTextItem *title = titleItem();
56 QGraphicsTextItem *title = titleItem();
57
57
58 QGraphicsEllipseItem *axisLine = static_cast<QGraphicsEllipseItem *>(arrowItemList.at(0));
58 QGraphicsEllipseItem *axisLine = static_cast<QGraphicsEllipseItem *>(arrowItemList.at(0));
59 axisLine->setRect(axisGeometry());
59 axisLine->setRect(axisGeometry());
60
60
61 qreal radius = axisGeometry().height() / 2.0;
61 qreal radius = axisGeometry().height() / 2.0;
62
62
63 QRectF previousLabelRect;
63 QRectF previousLabelRect;
64 QRectF firstLabelRect;
64 QRectF firstLabelRect;
65
65
66 qreal labelHeight = 0;
66 qreal labelHeight = 0;
67
67
68 bool firstShade = true;
68 bool firstShade = true;
69 bool nextTickVisible = false;
69 bool nextTickVisible = false;
70 if (layout.size())
70 if (layout.size())
71 nextTickVisible = !(layout.at(0) < 0.0 || layout.at(0) > 360.0);
71 nextTickVisible = !(layout.at(0) < 0.0 || layout.at(0) > 360.0);
72
72
73 for (int i = 0; i < layout.size(); ++i) {
73 for (int i = 0; i < layout.size(); ++i) {
74 qreal angularCoordinate = layout.at(i);
74 qreal angularCoordinate = layout.at(i);
75
75
76 QGraphicsLineItem *gridLineItem = static_cast<QGraphicsLineItem *>(gridItemList.at(i));
76 QGraphicsLineItem *gridLineItem = static_cast<QGraphicsLineItem *>(gridItemList.at(i));
77 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrowItemList.at(i + 1));
77 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrowItemList.at(i + 1));
78 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labelItemList.at(i));
78 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labelItemList.at(i));
79 QGraphicsPathItem *shadeItem = 0;
79 QGraphicsPathItem *shadeItem = 0;
80 if (i == 0)
80 if (i == 0)
81 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
81 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
82 else if (i % 2)
82 else if (i % 2)
83 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at((i / 2) + 1));
83 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at((i / 2) + 1));
84
84
85 // Ignore ticks outside valid range
85 // Ignore ticks outside valid range
86 bool currentTickVisible = nextTickVisible;
86 bool currentTickVisible = nextTickVisible;
87 if ((i == layout.size() - 1)
87 if ((i == layout.size() - 1)
88 || layout.at(i + 1) < 0.0
88 || layout.at(i + 1) < 0.0
89 || layout.at(i + 1) > 360.0) {
89 || layout.at(i + 1) > 360.0) {
90 nextTickVisible = false;
90 nextTickVisible = false;
91 } else {
91 } else {
92 nextTickVisible = true;
92 nextTickVisible = true;
93 }
93 }
94
94
95 qreal labelCoordinate = angularCoordinate;
95 qreal labelCoordinate = angularCoordinate;
96 qreal labelVisible = currentTickVisible;
96 qreal labelVisible = currentTickVisible;
97 if (intervalAxis()) {
97 if (intervalAxis()) {
98 qreal farEdge;
98 qreal farEdge;
99 if (i == (layout.size() - 1))
99 if (i == (layout.size() - 1))
100 farEdge = 360.0;
100 farEdge = 360.0;
101 else
101 else
102 farEdge = qMin(qreal(360.0), layout.at(i + 1));
102 farEdge = qMin(qreal(360.0), layout.at(i + 1));
103
103
104 // Adjust the labelCoordinate to show it if next tick is visible
104 // Adjust the labelCoordinate to show it if next tick is visible
105 if (nextTickVisible)
105 if (nextTickVisible)
106 labelCoordinate = qMax(qreal(0.0), labelCoordinate);
106 labelCoordinate = qMax(qreal(0.0), labelCoordinate);
107
107
108 labelCoordinate = (labelCoordinate + farEdge) / 2.0;
108 labelCoordinate = (labelCoordinate + farEdge) / 2.0;
109 // Don't display label once the category gets too small near the axis
109 // Don't display label once the category gets too small near the axis
110 if (labelCoordinate < 5.0 || labelCoordinate > 355.0)
110 if (labelCoordinate < 5.0 || labelCoordinate > 355.0)
111 labelVisible = false;
111 labelVisible = false;
112 else
112 else
113 labelVisible = true;
113 labelVisible = true;
114 }
114 }
115
115
116 // Need this also in label calculations, so determine it first
116 // Need this also in label calculations, so determine it first
117 QLineF tickLine(QLineF::fromPolar(radius - tickWidth(), 90.0 - angularCoordinate).p2(),
117 QLineF tickLine(QLineF::fromPolar(radius - tickWidth(), 90.0 - angularCoordinate).p2(),
118 QLineF::fromPolar(radius + tickWidth(), 90.0 - angularCoordinate).p2());
118 QLineF::fromPolar(radius + tickWidth(), 90.0 - angularCoordinate).p2());
119 tickLine.translate(center);
119 tickLine.translate(center);
120
120
121 // Angular axis label
121 // Angular axis label
122 if (axis()->labelsVisible() && labelVisible) {
122 if (axis()->labelsVisible() && labelVisible) {
123 labelItem->setHtml(labelList.at(i));
123 labelItem->setHtml(labelList.at(i));
124 const QRectF &rect = labelItem->boundingRect();
124 const QRectF &rect = labelItem->boundingRect();
125 QPointF labelCenter = rect.center();
125 QPointF labelCenter = rect.center();
126 labelItem->setTransformOriginPoint(labelCenter.x(), labelCenter.y());
126 labelItem->setTransformOriginPoint(labelCenter.x(), labelCenter.y());
127 QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), labelList.at(i), axis()->labelsAngle());
127 QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), labelList.at(i), axis()->labelsAngle());
128 boundingRect.moveCenter(labelCenter);
128 boundingRect.moveCenter(labelCenter);
129 QPointF positionDiff(rect.topLeft() - boundingRect.topLeft());
129 QPointF positionDiff(rect.topLeft() - boundingRect.topLeft());
130
130
131 QPointF labelPoint;
131 QPointF labelPoint;
132 if (intervalAxis()) {
132 if (intervalAxis()) {
133 QLineF labelLine = QLineF::fromPolar(radius + tickWidth(), 90.0 - labelCoordinate);
133 QLineF labelLine = QLineF::fromPolar(radius + tickWidth(), 90.0 - labelCoordinate);
134 labelLine.translate(center);
134 labelLine.translate(center);
135 labelPoint = labelLine.p2();
135 labelPoint = labelLine.p2();
136 } else {
136 } else {
137 labelPoint = tickLine.p2();
137 labelPoint = tickLine.p2();
138 }
138 }
139
139
140 QRectF labelRect = moveLabelToPosition(labelCoordinate, labelPoint, boundingRect);
140 QRectF labelRect = moveLabelToPosition(labelCoordinate, labelPoint, boundingRect);
141 labelItem->setPos(labelRect.topLeft() + positionDiff);
141 labelItem->setPos(labelRect.topLeft() + positionDiff);
142
142
143 // Store height for title calculations
143 // Store height for title calculations
144 qreal labelClearance = axisGeometry().top() - labelRect.top();
144 qreal labelClearance = axisGeometry().top() - labelRect.top();
145 labelHeight = qMax(labelHeight, labelClearance);
145 labelHeight = qMax(labelHeight, labelClearance);
146
146
147 // Label overlap detection
147 // Label overlap detection
148 if (i && (previousLabelRect.intersects(labelRect) || firstLabelRect.intersects(labelRect))) {
148 if (i && (previousLabelRect.intersects(labelRect) || firstLabelRect.intersects(labelRect))) {
149 labelVisible = false;
149 labelVisible = false;
150 } else {
150 } else {
151 // Store labelRect for future comparison. Some area is deducted to make things look
151 // Store labelRect for future comparison. Some area is deducted to make things look
152 // little nicer, as usually intersection happens at label corner with angular labels.
152 // little nicer, as usually intersection happens at label corner with angular labels.
153 labelRect.adjust(-2.0, -4.0, -2.0, -4.0);
153 labelRect.adjust(-2.0, -4.0, -2.0, -4.0);
154 if (firstLabelRect.isEmpty())
154 if (firstLabelRect.isEmpty())
155 firstLabelRect = labelRect;
155 firstLabelRect = labelRect;
156
156
157 previousLabelRect = labelRect;
157 previousLabelRect = labelRect;
158 labelVisible = true;
158 labelVisible = true;
159 }
159 }
160 }
160 }
161
161
162 labelItem->setVisible(labelVisible);
162 labelItem->setVisible(labelVisible);
163 if (!currentTickVisible) {
163 if (!currentTickVisible) {
164 gridLineItem->setVisible(false);
164 gridLineItem->setVisible(false);
165 tickItem->setVisible(false);
165 tickItem->setVisible(false);
166 if (shadeItem)
166 if (shadeItem)
167 shadeItem->setVisible(false);
167 shadeItem->setVisible(false);
168 continue;
168 continue;
169 }
169 }
170
170
171 // Angular grid line
171 // Angular grid line
172 QLineF gridLine = QLineF::fromPolar(radius, 90.0 - angularCoordinate);
172 QLineF gridLine = QLineF::fromPolar(radius, 90.0 - angularCoordinate);
173 gridLine.translate(center);
173 gridLine.translate(center);
174 gridLineItem->setLine(gridLine);
174 gridLineItem->setLine(gridLine);
175 gridLineItem->setVisible(true);
175 gridLineItem->setVisible(true);
176
176
177 // Tick
177 // Tick
178 tickItem->setLine(tickLine);
178 tickItem->setLine(tickLine);
179 tickItem->setVisible(true);
179 tickItem->setVisible(true);
180
180
181 // Shades
181 // Shades
182 if (i % 2 || (i == 0 && !nextTickVisible)) {
182 if (i % 2 || (i == 0 && !nextTickVisible)) {
183 QPainterPath path;
183 QPainterPath path;
184 path.moveTo(center);
184 path.moveTo(center);
185 if (i == 0) {
185 if (i == 0) {
186 // If first tick is also the last, we need to custom fill the first partial arc
186 // If first tick is also the last, we need to custom fill the first partial arc
187 // or it won't get filled.
187 // or it won't get filled.
188 path.arcTo(axisGeometry(), 90.0 - layout.at(0), layout.at(0));
188 path.arcTo(axisGeometry(), 90.0 - layout.at(0), layout.at(0));
189 path.closeSubpath();
189 path.closeSubpath();
190 } else {
190 } else {
191 qreal nextCoordinate;
191 qreal nextCoordinate;
192 if (!nextTickVisible) // Last visible tick
192 if (!nextTickVisible) // Last visible tick
193 nextCoordinate = 360.0;
193 nextCoordinate = 360.0;
194 else
194 else
195 nextCoordinate = layout.at(i + 1);
195 nextCoordinate = layout.at(i + 1);
196 qreal arcSpan = angularCoordinate - nextCoordinate;
196 qreal arcSpan = angularCoordinate - nextCoordinate;
197 path.arcTo(axisGeometry(), 90.0 - angularCoordinate, arcSpan);
197 path.arcTo(axisGeometry(), 90.0 - angularCoordinate, arcSpan);
198 path.closeSubpath();
198 path.closeSubpath();
199
199
200 // Add additional arc for first shade item if there is a partial arc to be filled
200 // Add additional arc for first shade item if there is a partial arc to be filled
201 if (firstShade) {
201 if (firstShade) {
202 QGraphicsPathItem *specialShadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
202 QGraphicsPathItem *specialShadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
203 if (layout.at(i - 1) > 0.0) {
203 if (layout.at(i - 1) > 0.0) {
204 QPainterPath specialPath;
204 QPainterPath specialPath;
205 specialPath.moveTo(center);
205 specialPath.moveTo(center);
206 specialPath.arcTo(axisGeometry(), 90.0 - layout.at(i - 1), layout.at(i - 1));
206 specialPath.arcTo(axisGeometry(), 90.0 - layout.at(i - 1), layout.at(i - 1));
207 specialPath.closeSubpath();
207 specialPath.closeSubpath();
208 specialShadeItem->setPath(specialPath);
208 specialShadeItem->setPath(specialPath);
209 specialShadeItem->setVisible(true);
209 specialShadeItem->setVisible(true);
210 } else {
210 } else {
211 specialShadeItem->setVisible(false);
211 specialShadeItem->setVisible(false);
212 }
212 }
213 }
213 }
214 }
214 }
215 shadeItem->setPath(path);
215 shadeItem->setPath(path);
216 shadeItem->setVisible(true);
216 shadeItem->setVisible(true);
217 firstShade = false;
217 firstShade = false;
218 }
218 }
219 }
219 }
220
220
221 // Title, centered above the chart
221 // Title, centered above the chart
222 QString titleText = axis()->titleText();
222 QString titleText = axis()->titleText();
223 if (!titleText.isEmpty() && axis()->isTitleVisible()) {
223 if (!titleText.isEmpty() && axis()->isTitleVisible()) {
224 QRectF dummyRect;
224 QRectF dummyRect;
225 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0), axisGeometry().width(), Qt::Horizontal, dummyRect));
225 qreal availableTitleHeight = axisGeometry().height() - labelPadding() - titlePadding() * 2.0;
226 qreal minimumLabelHeight = ChartPresenter::textBoundingRect(axis()->labelsFont(), "...").height();
227 availableTitleHeight -= minimumLabelHeight;
228 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0),
229 axisGeometry().width(), availableTitleHeight,
230 dummyRect));
226
231
227 QRectF titleBoundingRect = title->boundingRect();
232 QRectF titleBoundingRect = title->boundingRect();
228 QPointF titleCenter = center - titleBoundingRect.center();
233 QPointF titleCenter = center - titleBoundingRect.center();
229 title->setPos(titleCenter.x(), axisGeometry().top() - titlePadding() * 2.0 - titleBoundingRect.height() - labelHeight);
234 title->setPos(titleCenter.x(), axisGeometry().top() - titlePadding() * 2.0 - titleBoundingRect.height() - labelHeight);
230 }
235 }
231 }
236 }
232
237
233 Qt::Orientation PolarChartAxisAngular::orientation() const
238 Qt::Orientation PolarChartAxisAngular::orientation() const
234 {
239 {
235 return Qt::Horizontal;
240 return Qt::Horizontal;
236 }
241 }
237
242
238 void PolarChartAxisAngular::createItems(int count)
243 void PolarChartAxisAngular::createItems(int count)
239 {
244 {
240 if (arrowItems().count() == 0) {
245 if (arrowItems().count() == 0) {
241 // angular axis line
246 // angular axis line
242 QGraphicsEllipseItem *arrow = new QGraphicsEllipseItem(presenter()->rootItem());
247 QGraphicsEllipseItem *arrow = new QGraphicsEllipseItem(presenter()->rootItem());
243 arrow->setPen(axis()->linePen());
248 arrow->setPen(axis()->linePen());
244 arrowGroup()->addToGroup(arrow);
249 arrowGroup()->addToGroup(arrow);
245 }
250 }
246
251
247 for (int i = 0; i < count; ++i) {
252 for (int i = 0; i < count; ++i) {
248 QGraphicsLineItem *arrow = new QGraphicsLineItem(presenter()->rootItem());
253 QGraphicsLineItem *arrow = new QGraphicsLineItem(presenter()->rootItem());
249 QGraphicsLineItem *grid = new QGraphicsLineItem(presenter()->rootItem());
254 QGraphicsLineItem *grid = new QGraphicsLineItem(presenter()->rootItem());
250 QGraphicsTextItem *label = new QGraphicsTextItem(presenter()->rootItem());
255 QGraphicsTextItem *label = new QGraphicsTextItem(presenter()->rootItem());
251 label->document()->setDocumentMargin(ChartPresenter::textMargin());
256 label->document()->setDocumentMargin(ChartPresenter::textMargin());
252 QGraphicsTextItem *title = titleItem();
257 QGraphicsTextItem *title = titleItem();
253 arrow->setPen(axis()->linePen());
258 arrow->setPen(axis()->linePen());
254 grid->setPen(axis()->gridLinePen());
259 grid->setPen(axis()->gridLinePen());
255 label->setFont(axis()->labelsFont());
260 label->setFont(axis()->labelsFont());
256 label->setDefaultTextColor(axis()->labelsBrush().color());
261 label->setDefaultTextColor(axis()->labelsBrush().color());
257 label->setRotation(axis()->labelsAngle());
262 label->setRotation(axis()->labelsAngle());
258 title->setFont(axis()->titleFont());
263 title->setFont(axis()->titleFont());
259 title->setDefaultTextColor(axis()->titleBrush().color());
264 title->setDefaultTextColor(axis()->titleBrush().color());
260 title->setHtml(axis()->titleText());
265 title->setHtml(axis()->titleText());
261 arrowGroup()->addToGroup(arrow);
266 arrowGroup()->addToGroup(arrow);
262 gridGroup()->addToGroup(grid);
267 gridGroup()->addToGroup(grid);
263 labelGroup()->addToGroup(label);
268 labelGroup()->addToGroup(label);
264 if (gridItems().size() == 1 || (((gridItems().size() + 1) % 2) && gridItems().size() > 0)) {
269 if (gridItems().size() == 1 || (((gridItems().size() + 1) % 2) && gridItems().size() > 0)) {
265 QGraphicsPathItem *shade = new QGraphicsPathItem(presenter()->rootItem());
270 QGraphicsPathItem *shade = new QGraphicsPathItem(presenter()->rootItem());
266 shade->setPen(axis()->shadesPen());
271 shade->setPen(axis()->shadesPen());
267 shade->setBrush(axis()->shadesBrush());
272 shade->setBrush(axis()->shadesBrush());
268 shadeGroup()->addToGroup(shade);
273 shadeGroup()->addToGroup(shade);
269 }
274 }
270 }
275 }
271 }
276 }
272
277
273 void PolarChartAxisAngular::handleArrowPenChanged(const QPen &pen)
278 void PolarChartAxisAngular::handleArrowPenChanged(const QPen &pen)
274 {
279 {
275 bool first = true;
280 bool first = true;
276 foreach (QGraphicsItem *item, arrowItems()) {
281 foreach (QGraphicsItem *item, arrowItems()) {
277 if (first) {
282 if (first) {
278 first = false;
283 first = false;
279 // First arrow item is the outer circle of axis
284 // First arrow item is the outer circle of axis
280 static_cast<QGraphicsEllipseItem *>(item)->setPen(pen);
285 static_cast<QGraphicsEllipseItem *>(item)->setPen(pen);
281 } else {
286 } else {
282 static_cast<QGraphicsLineItem *>(item)->setPen(pen);
287 static_cast<QGraphicsLineItem *>(item)->setPen(pen);
283 }
288 }
284 }
289 }
285 }
290 }
286
291
287 void PolarChartAxisAngular::handleGridPenChanged(const QPen &pen)
292 void PolarChartAxisAngular::handleGridPenChanged(const QPen &pen)
288 {
293 {
289 foreach (QGraphicsItem *item, gridItems())
294 foreach (QGraphicsItem *item, gridItems())
290 static_cast<QGraphicsLineItem *>(item)->setPen(pen);
295 static_cast<QGraphicsLineItem *>(item)->setPen(pen);
291 }
296 }
292
297
293 QSizeF PolarChartAxisAngular::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
298 QSizeF PolarChartAxisAngular::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
294 {
299 {
295 Q_UNUSED(which);
300 Q_UNUSED(which);
296 Q_UNUSED(constraint);
301 Q_UNUSED(constraint);
297 return QSizeF(-1, -1);
302 return QSizeF(-1, -1);
298 }
303 }
299
304
300 qreal PolarChartAxisAngular::preferredAxisRadius(const QSizeF &maxSize)
305 qreal PolarChartAxisAngular::preferredAxisRadius(const QSizeF &maxSize)
301 {
306 {
302 qreal radius = maxSize.height() / 2.0;
307 qreal radius = maxSize.height() / 2.0;
303 if (maxSize.width() < maxSize.height())
308 if (maxSize.width() < maxSize.height())
304 radius = maxSize.width() / 2.0;
309 radius = maxSize.width() / 2.0;
305
310
306 if (axis()->labelsVisible()) {
311 if (axis()->labelsVisible()) {
307 QVector<qreal> layout = calculateLayout();
312 QVector<qreal> layout = calculateLayout();
308 if (layout.isEmpty())
313 if (layout.isEmpty())
309 return radius;
314 return radius;
310
315
311 createAxisLabels(layout);
316 createAxisLabels(layout);
312 QStringList labelList = labels();
317 QStringList labelList = labels();
313 QFont font = axis()->labelsFont();
318 QFont font = axis()->labelsFont();
314
319
315 QRectF maxRect;
320 QRectF maxRect;
316 maxRect.setSize(maxSize);
321 maxRect.setSize(maxSize);
317 maxRect.moveCenter(QPointF(0.0, 0.0));
322 maxRect.moveCenter(QPointF(0.0, 0.0));
318
323
319 // This is a horrible way to find out the maximum radius for angular axis and its labels.
324 // This is a horrible way to find out the maximum radius for angular axis and its labels.
320 // It just increments the radius down until everyhing fits the constraint size.
325 // It just increments the radius down until everyhing fits the constraint size.
321 // Proper way would be to actually calculate it but this seems to work reasonably fast as it is.
326 // Proper way would be to actually calculate it but this seems to work reasonably fast as it is.
322 bool nextTickVisible = false;
327 bool nextTickVisible = false;
323 for (int i = 0; i < layout.size(); ) {
328 for (int i = 0; i < layout.size(); ) {
324 if ((i == layout.size() - 1)
329 if ((i == layout.size() - 1)
325 || layout.at(i + 1) < 0.0
330 || layout.at(i + 1) < 0.0
326 || layout.at(i + 1) > 360.0) {
331 || layout.at(i + 1) > 360.0) {
327 nextTickVisible = false;
332 nextTickVisible = false;
328 } else {
333 } else {
329 nextTickVisible = true;
334 nextTickVisible = true;
330 }
335 }
331
336
332 qreal labelCoordinate = layout.at(i);
337 qreal labelCoordinate = layout.at(i);
333 qreal labelVisible;
338 qreal labelVisible;
334
339
335 if (intervalAxis()) {
340 if (intervalAxis()) {
336 qreal farEdge;
341 qreal farEdge;
337 if (i == (layout.size() - 1))
342 if (i == (layout.size() - 1))
338 farEdge = 360.0;
343 farEdge = 360.0;
339 else
344 else
340 farEdge = qMin(qreal(360.0), layout.at(i + 1));
345 farEdge = qMin(qreal(360.0), layout.at(i + 1));
341
346
342 // Adjust the labelCoordinate to show it if next tick is visible
347 // Adjust the labelCoordinate to show it if next tick is visible
343 if (nextTickVisible)
348 if (nextTickVisible)
344 labelCoordinate = qMax(qreal(0.0), labelCoordinate);
349 labelCoordinate = qMax(qreal(0.0), labelCoordinate);
345
350
346 labelCoordinate = (labelCoordinate + farEdge) / 2.0;
351 labelCoordinate = (labelCoordinate + farEdge) / 2.0;
347 }
352 }
348
353
349 if (labelCoordinate < 0.0 || labelCoordinate > 360.0)
354 if (labelCoordinate < 0.0 || labelCoordinate > 360.0)
350 labelVisible = false;
355 labelVisible = false;
351 else
356 else
352 labelVisible = true;
357 labelVisible = true;
353
358
354 if (!labelVisible) {
359 if (!labelVisible) {
355 i++;
360 i++;
356 continue;
361 continue;
357 }
362 }
358
363
359 QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), labelList.at(i), axis()->labelsAngle());
364 QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), labelList.at(i), axis()->labelsAngle());
360 QPointF labelPoint = QLineF::fromPolar(radius + tickWidth(), 90.0 - labelCoordinate).p2();
365 QPointF labelPoint = QLineF::fromPolar(radius + tickWidth(), 90.0 - labelCoordinate).p2();
361
366
362 boundingRect = moveLabelToPosition(labelCoordinate, labelPoint, boundingRect);
367 boundingRect = moveLabelToPosition(labelCoordinate, labelPoint, boundingRect);
363 QRectF intersectRect = maxRect.intersected(boundingRect);
368 QRectF intersectRect = maxRect.intersected(boundingRect);
364 if (boundingRect.isEmpty() || intersectRect == boundingRect) {
369 if (boundingRect.isEmpty() || intersectRect == boundingRect) {
365 i++;
370 i++;
366 } else {
371 } else {
367 qreal reduction(0.0);
372 qreal reduction(0.0);
368 // If there is no intersection, reduce by smallest dimension of label rect to be on the safe side
373 // If there is no intersection, reduce by smallest dimension of label rect to be on the safe side
369 if (intersectRect.isEmpty()) {
374 if (intersectRect.isEmpty()) {
370 reduction = qMin(boundingRect.height(), boundingRect.width());
375 reduction = qMin(boundingRect.height(), boundingRect.width());
371 } else {
376 } else {
372 // Approximate needed radius reduction is the amount label rect exceeds max rect in either dimension.
377 // Approximate needed radius reduction is the amount label rect exceeds max rect in either dimension.
373 // Could be further optimized by figuring out the proper math how to calculate exact needed reduction.
378 // Could be further optimized by figuring out the proper math how to calculate exact needed reduction.
374 reduction = qMax(boundingRect.height() - intersectRect.height(),
379 reduction = qMax(boundingRect.height() - intersectRect.height(),
375 boundingRect.width() - intersectRect.width());
380 boundingRect.width() - intersectRect.width());
376 }
381 }
377 // Typically the approximated reduction is little low, so add one
382 // Typically the approximated reduction is little low, so add one
378 radius -= (reduction + 1.0);
383 radius -= (reduction + 1.0);
379
384
380 if (radius < 1.0) // safeguard
385 if (radius < 1.0) // safeguard
381 return 1.0;
386 return 1.0;
382 }
387 }
383 }
388 }
384 }
389 }
385
390
386 if (!axis()->titleText().isEmpty() && axis()->isTitleVisible()) {
391 if (!axis()->titleText().isEmpty() && axis()->isTitleVisible()) {
387 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText());
392 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText());
388
393
389 radius -= titlePadding() + (titleRect.height() / 2.0);
394 radius -= titlePadding() + (titleRect.height() / 2.0);
390 if (radius < 1.0) // safeguard
395 if (radius < 1.0) // safeguard
391 return 1.0;
396 return 1.0;
392 }
397 }
393
398
394 return radius;
399 return radius;
395 }
400 }
396
401
397 QRectF PolarChartAxisAngular::moveLabelToPosition(qreal angularCoordinate, QPointF labelPoint, QRectF labelRect) const
402 QRectF PolarChartAxisAngular::moveLabelToPosition(qreal angularCoordinate, QPointF labelPoint, QRectF labelRect) const
398 {
403 {
399 if (angularCoordinate == 0.0)
404 if (angularCoordinate == 0.0)
400 labelRect.moveCenter(labelPoint + QPointF(0, -labelRect.height() / 2.0));
405 labelRect.moveCenter(labelPoint + QPointF(0, -labelRect.height() / 2.0));
401 else if (angularCoordinate < 90.0)
406 else if (angularCoordinate < 90.0)
402 labelRect.moveBottomLeft(labelPoint);
407 labelRect.moveBottomLeft(labelPoint);
403 else if (angularCoordinate == 90.0)
408 else if (angularCoordinate == 90.0)
404 labelRect.moveCenter(labelPoint + QPointF(labelRect.width() / 2.0 + 2.0, 0)); // +2 so that it does not hit the radial axis
409 labelRect.moveCenter(labelPoint + QPointF(labelRect.width() / 2.0 + 2.0, 0)); // +2 so that it does not hit the radial axis
405 else if (angularCoordinate < 180.0)
410 else if (angularCoordinate < 180.0)
406 labelRect.moveTopLeft(labelPoint);
411 labelRect.moveTopLeft(labelPoint);
407 else if (angularCoordinate == 180.0)
412 else if (angularCoordinate == 180.0)
408 labelRect.moveCenter(labelPoint + QPointF(0, labelRect.height() / 2.0));
413 labelRect.moveCenter(labelPoint + QPointF(0, labelRect.height() / 2.0));
409 else if (angularCoordinate < 270.0)
414 else if (angularCoordinate < 270.0)
410 labelRect.moveTopRight(labelPoint);
415 labelRect.moveTopRight(labelPoint);
411 else if (angularCoordinate == 270.0)
416 else if (angularCoordinate == 270.0)
412 labelRect.moveCenter(labelPoint + QPointF(-labelRect.width() / 2.0 - 2.0, 0)); // -2 so that it does not hit the radial axis
417 labelRect.moveCenter(labelPoint + QPointF(-labelRect.width() / 2.0 - 2.0, 0)); // -2 so that it does not hit the radial axis
413 else if (angularCoordinate < 360.0)
418 else if (angularCoordinate < 360.0)
414 labelRect.moveBottomRight(labelPoint);
419 labelRect.moveBottomRight(labelPoint);
415 else
420 else
416 labelRect.moveCenter(labelPoint + QPointF(0, -labelRect.height() / 2.0));
421 labelRect.moveCenter(labelPoint + QPointF(0, -labelRect.height() / 2.0));
417 return labelRect;
422 return labelRect;
418 }
423 }
419
424
420 #include "moc_polarchartaxisangular_p.cpp"
425 #include "moc_polarchartaxisangular_p.cpp"
421
426
422 QTCOMMERCIALCHART_END_NAMESPACE
427 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,291 +1,292
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2013 Digia Plc
3 ** Copyright (C) 2013 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 **
6 **
7 ** This file is part of the Qt Enterprise Charts Add-on.
7 ** This file is part of the Qt Enterprise Charts Add-on.
8 **
8 **
9 ** $QT_BEGIN_LICENSE$
9 ** $QT_BEGIN_LICENSE$
10 ** Licensees holding valid Qt Enterprise licenses may use this file in
10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 ** accordance with the Qt Enterprise License Agreement provided with the
11 ** accordance with the Qt Enterprise License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.
13 ** a written agreement between you and Digia.
14 **
14 **
15 ** If you have questions regarding the use of this file, please use
15 ** If you have questions regarding the use of this file, please use
16 ** contact form at http://qt.digia.com
16 ** contact form at http://qt.digia.com
17 ** $QT_END_LICENSE$
17 ** $QT_END_LICENSE$
18 **
18 **
19 ****************************************************************************/
19 ****************************************************************************/
20
20
21 #include "polarchartaxisradial_p.h"
21 #include "polarchartaxisradial_p.h"
22 #include "chartpresenter_p.h"
22 #include "chartpresenter_p.h"
23 #include "abstractchartlayout_p.h"
23 #include "abstractchartlayout_p.h"
24 #include "qabstractaxis_p.h"
24 #include "qabstractaxis_p.h"
25 #include "linearrowitem_p.h"
25 #include "linearrowitem_p.h"
26 #include <QTextDocument>
26 #include <QTextDocument>
27
27
28 QTCOMMERCIALCHART_BEGIN_NAMESPACE
28 QTCOMMERCIALCHART_BEGIN_NAMESPACE
29
29
30 PolarChartAxisRadial::PolarChartAxisRadial(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
30 PolarChartAxisRadial::PolarChartAxisRadial(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
31 : PolarChartAxis(axis, item, intervalAxis)
31 : PolarChartAxis(axis, item, intervalAxis)
32 {
32 {
33 }
33 }
34
34
35 PolarChartAxisRadial::~PolarChartAxisRadial()
35 PolarChartAxisRadial::~PolarChartAxisRadial()
36 {
36 {
37 }
37 }
38
38
39 void PolarChartAxisRadial::updateGeometry()
39 void PolarChartAxisRadial::updateGeometry()
40 {
40 {
41 const QVector<qreal> &layout = this->layout();
41 const QVector<qreal> &layout = this->layout();
42 if (layout.isEmpty())
42 if (layout.isEmpty())
43 return;
43 return;
44
44
45 createAxisLabels(layout);
45 createAxisLabels(layout);
46 QStringList labelList = labels();
46 QStringList labelList = labels();
47 QPointF center = axisGeometry().center();
47 QPointF center = axisGeometry().center();
48 QList<QGraphicsItem *> arrowItemList = arrowItems();
48 QList<QGraphicsItem *> arrowItemList = arrowItems();
49 QList<QGraphicsItem *> gridItemList = gridItems();
49 QList<QGraphicsItem *> gridItemList = gridItems();
50 QList<QGraphicsItem *> labelItemList = labelItems();
50 QList<QGraphicsItem *> labelItemList = labelItems();
51 QList<QGraphicsItem *> shadeItemList = shadeItems();
51 QList<QGraphicsItem *> shadeItemList = shadeItems();
52 QGraphicsTextItem* title = titleItem();
52 QGraphicsTextItem* title = titleItem();
53 qreal radius = axisGeometry().height() / 2.0;
53 qreal radius = axisGeometry().height() / 2.0;
54
54
55 QLineF line(center, center + QPointF(0, -radius));
55 QLineF line(center, center + QPointF(0, -radius));
56 QGraphicsLineItem *axisLine = static_cast<QGraphicsLineItem *>(arrowItemList.at(0));
56 QGraphicsLineItem *axisLine = static_cast<QGraphicsLineItem *>(arrowItemList.at(0));
57 axisLine->setLine(line);
57 axisLine->setLine(line);
58
58
59 QRectF previousLabelRect;
59 QRectF previousLabelRect;
60 bool firstShade = true;
60 bool firstShade = true;
61 bool nextTickVisible = false;
61 bool nextTickVisible = false;
62 if (layout.size())
62 if (layout.size())
63 nextTickVisible = !(layout.at(0) < 0.0 || layout.at(0) > radius);
63 nextTickVisible = !(layout.at(0) < 0.0 || layout.at(0) > radius);
64
64
65 for (int i = 0; i < layout.size(); ++i) {
65 for (int i = 0; i < layout.size(); ++i) {
66 qreal radialCoordinate = layout.at(i);
66 qreal radialCoordinate = layout.at(i);
67
67
68 QGraphicsEllipseItem *gridItem = static_cast<QGraphicsEllipseItem *>(gridItemList.at(i));
68 QGraphicsEllipseItem *gridItem = static_cast<QGraphicsEllipseItem *>(gridItemList.at(i));
69 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrowItemList.at(i + 1));
69 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrowItemList.at(i + 1));
70 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labelItemList.at(i));
70 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labelItemList.at(i));
71 QGraphicsPathItem *shadeItem = 0;
71 QGraphicsPathItem *shadeItem = 0;
72 if (i == 0)
72 if (i == 0)
73 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
73 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
74 else if (i % 2)
74 else if (i % 2)
75 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at((i / 2) + 1));
75 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at((i / 2) + 1));
76
76
77 // Ignore ticks outside valid range
77 // Ignore ticks outside valid range
78 bool currentTickVisible = nextTickVisible;
78 bool currentTickVisible = nextTickVisible;
79 if ((i == layout.size() - 1)
79 if ((i == layout.size() - 1)
80 || layout.at(i + 1) < 0.0
80 || layout.at(i + 1) < 0.0
81 || layout.at(i + 1) > radius) {
81 || layout.at(i + 1) > radius) {
82 nextTickVisible = false;
82 nextTickVisible = false;
83 } else {
83 } else {
84 nextTickVisible = true;
84 nextTickVisible = true;
85 }
85 }
86
86
87 qreal labelCoordinate = radialCoordinate;
87 qreal labelCoordinate = radialCoordinate;
88 qreal labelVisible = currentTickVisible;
88 qreal labelVisible = currentTickVisible;
89 qreal labelPad = labelPadding() / 2.0;
89 qreal labelPad = labelPadding() / 2.0;
90 if (intervalAxis()) {
90 if (intervalAxis()) {
91 qreal farEdge;
91 qreal farEdge;
92 if (i == (layout.size() - 1))
92 if (i == (layout.size() - 1))
93 farEdge = radius;
93 farEdge = radius;
94 else
94 else
95 farEdge = qMin(radius, layout.at(i + 1));
95 farEdge = qMin(radius, layout.at(i + 1));
96
96
97 // Adjust the labelCoordinate to show it if next tick is visible
97 // Adjust the labelCoordinate to show it if next tick is visible
98 if (nextTickVisible)
98 if (nextTickVisible)
99 labelCoordinate = qMax(qreal(0.0), labelCoordinate);
99 labelCoordinate = qMax(qreal(0.0), labelCoordinate);
100
100
101 labelCoordinate = (labelCoordinate + farEdge) / 2.0;
101 labelCoordinate = (labelCoordinate + farEdge) / 2.0;
102 if (labelCoordinate > 0.0 && labelCoordinate < radius)
102 if (labelCoordinate > 0.0 && labelCoordinate < radius)
103 labelVisible = true;
103 labelVisible = true;
104 else
104 else
105 labelVisible = false;
105 labelVisible = false;
106 }
106 }
107
107
108 // Radial axis label
108 // Radial axis label
109 if (axis()->labelsVisible() && labelVisible) {
109 if (axis()->labelsVisible() && labelVisible) {
110 labelItem->setHtml(labelList.at(i));
110 labelItem->setHtml(labelList.at(i));
111 QRectF labelRect = labelItem->boundingRect();
111 QRectF labelRect = labelItem->boundingRect();
112 QPointF labelCenter = labelRect.center();
112 QPointF labelCenter = labelRect.center();
113 labelItem->setTransformOriginPoint(labelCenter.x(), labelCenter.y());
113 labelItem->setTransformOriginPoint(labelCenter.x(), labelCenter.y());
114 QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), labelList.at(i), axis()->labelsAngle());
114 QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), labelList.at(i), axis()->labelsAngle());
115 boundingRect.moveCenter(labelCenter);
115 boundingRect.moveCenter(labelCenter);
116 QPointF positionDiff(labelRect.topLeft() - boundingRect.topLeft());
116 QPointF positionDiff(labelRect.topLeft() - boundingRect.topLeft());
117 QPointF labelPoint = center;
117 QPointF labelPoint = center;
118 if (intervalAxis())
118 if (intervalAxis())
119 labelPoint += QPointF(labelPad, -labelCoordinate - (boundingRect.height() / 2.0));
119 labelPoint += QPointF(labelPad, -labelCoordinate - (boundingRect.height() / 2.0));
120 else
120 else
121 labelPoint += QPointF(labelPad, labelPad - labelCoordinate);
121 labelPoint += QPointF(labelPad, labelPad - labelCoordinate);
122 labelRect.moveTopLeft(labelPoint);
122 labelRect.moveTopLeft(labelPoint);
123 labelItem->setPos(labelRect.topLeft() + positionDiff);
123 labelItem->setPos(labelRect.topLeft() + positionDiff);
124
124
125 // Label overlap detection
125 // Label overlap detection
126 labelRect.setSize(boundingRect.size());
126 labelRect.setSize(boundingRect.size());
127 if ((i && previousLabelRect.intersects(labelRect))
127 if ((i && previousLabelRect.intersects(labelRect))
128 || !axisGeometry().contains(labelRect)) {
128 || !axisGeometry().contains(labelRect)) {
129 labelVisible = false;
129 labelVisible = false;
130 } else {
130 } else {
131 previousLabelRect = labelRect;
131 previousLabelRect = labelRect;
132 labelVisible = true;
132 labelVisible = true;
133 }
133 }
134 }
134 }
135
135
136 labelItem->setVisible(labelVisible);
136 labelItem->setVisible(labelVisible);
137 if (!currentTickVisible) {
137 if (!currentTickVisible) {
138 gridItem->setVisible(false);
138 gridItem->setVisible(false);
139 tickItem->setVisible(false);
139 tickItem->setVisible(false);
140 if (shadeItem)
140 if (shadeItem)
141 shadeItem->setVisible(false);
141 shadeItem->setVisible(false);
142 continue;
142 continue;
143 }
143 }
144
144
145 // Radial grid line
145 // Radial grid line
146 QRectF gridRect;
146 QRectF gridRect;
147 gridRect.setWidth(radialCoordinate * 2.0);
147 gridRect.setWidth(radialCoordinate * 2.0);
148 gridRect.setHeight(radialCoordinate * 2.0);
148 gridRect.setHeight(radialCoordinate * 2.0);
149 gridRect.moveCenter(center);
149 gridRect.moveCenter(center);
150
150
151 gridItem->setRect(gridRect);
151 gridItem->setRect(gridRect);
152 gridItem->setVisible(true);
152 gridItem->setVisible(true);
153
153
154 // Tick
154 // Tick
155 QLineF tickLine(-tickWidth(), 0.0, tickWidth(), 0.0);
155 QLineF tickLine(-tickWidth(), 0.0, tickWidth(), 0.0);
156 tickLine.translate(center.rx(), gridRect.top());
156 tickLine.translate(center.rx(), gridRect.top());
157 tickItem->setLine(tickLine);
157 tickItem->setLine(tickLine);
158 tickItem->setVisible(true);
158 tickItem->setVisible(true);
159
159
160 // Shades
160 // Shades
161 if (i % 2 || (i == 0 && !nextTickVisible)) {
161 if (i % 2 || (i == 0 && !nextTickVisible)) {
162 QPainterPath path;
162 QPainterPath path;
163 if (i == 0) {
163 if (i == 0) {
164 // If first tick is also the last, we need to custom fill the inner circle
164 // If first tick is also the last, we need to custom fill the inner circle
165 // or it won't get filled.
165 // or it won't get filled.
166 QRectF innerCircle(0.0, 0.0, layout.at(0) * 2.0, layout.at(0) * 2.0);
166 QRectF innerCircle(0.0, 0.0, layout.at(0) * 2.0, layout.at(0) * 2.0);
167 innerCircle.moveCenter(center);
167 innerCircle.moveCenter(center);
168 path.addEllipse(innerCircle);
168 path.addEllipse(innerCircle);
169 } else {
169 } else {
170 QRectF otherGridRect;
170 QRectF otherGridRect;
171 if (!nextTickVisible) { // Last visible tick
171 if (!nextTickVisible) { // Last visible tick
172 otherGridRect = axisGeometry();
172 otherGridRect = axisGeometry();
173 } else {
173 } else {
174 qreal otherGridRectDimension = layout.at(i + 1) * 2.0;
174 qreal otherGridRectDimension = layout.at(i + 1) * 2.0;
175 otherGridRect.setWidth(otherGridRectDimension);
175 otherGridRect.setWidth(otherGridRectDimension);
176 otherGridRect.setHeight(otherGridRectDimension);
176 otherGridRect.setHeight(otherGridRectDimension);
177 otherGridRect.moveCenter(center);
177 otherGridRect.moveCenter(center);
178 }
178 }
179 path.addEllipse(gridRect);
179 path.addEllipse(gridRect);
180 path.addEllipse(otherGridRect);
180 path.addEllipse(otherGridRect);
181
181
182 // Add additional shading in first visible shade item if there is a partial tick
182 // Add additional shading in first visible shade item if there is a partial tick
183 // to be filled at the center (log & category axes)
183 // to be filled at the center (log & category axes)
184 if (firstShade) {
184 if (firstShade) {
185 QGraphicsPathItem *specialShadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
185 QGraphicsPathItem *specialShadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
186 if (layout.at(i - 1) > 0.0) {
186 if (layout.at(i - 1) > 0.0) {
187 QRectF innerCircle(0.0, 0.0, layout.at(i - 1) * 2.0, layout.at(i - 1) * 2.0);
187 QRectF innerCircle(0.0, 0.0, layout.at(i - 1) * 2.0, layout.at(i - 1) * 2.0);
188 innerCircle.moveCenter(center);
188 innerCircle.moveCenter(center);
189 QPainterPath specialPath;
189 QPainterPath specialPath;
190 specialPath.addEllipse(innerCircle);
190 specialPath.addEllipse(innerCircle);
191 specialShadeItem->setPath(specialPath);
191 specialShadeItem->setPath(specialPath);
192 specialShadeItem->setVisible(true);
192 specialShadeItem->setVisible(true);
193 } else {
193 } else {
194 specialShadeItem->setVisible(false);
194 specialShadeItem->setVisible(false);
195 }
195 }
196 }
196 }
197 }
197 }
198 shadeItem->setPath(path);
198 shadeItem->setPath(path);
199 shadeItem->setVisible(true);
199 shadeItem->setVisible(true);
200 firstShade = false;
200 firstShade = false;
201 }
201 }
202 }
202 }
203
203
204 // Title, along the 0 axis
204 // Title, along the 0 axis
205 QString titleText = axis()->titleText();
205 QString titleText = axis()->titleText();
206 if (!titleText.isEmpty() && axis()->isTitleVisible()) {
206 if (!titleText.isEmpty() && axis()->isTitleVisible()) {
207 QRectF dummyRect;
207 QRectF dummyRect;
208 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0), radius, Qt::Horizontal, dummyRect));
208 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0),
209 radius, radius, dummyRect));
209
210
210 QRectF titleBoundingRect = title->boundingRect();
211 QRectF titleBoundingRect = title->boundingRect();
211 QPointF titleCenter = titleBoundingRect.center();
212 QPointF titleCenter = titleBoundingRect.center();
212 QPointF arrowCenter = axisLine->boundingRect().center();
213 QPointF arrowCenter = axisLine->boundingRect().center();
213 QPointF titleCenterDiff = arrowCenter - titleCenter;
214 QPointF titleCenterDiff = arrowCenter - titleCenter;
214 title->setPos(titleCenterDiff.x() - titlePadding() - (titleBoundingRect.height() / 2.0), titleCenterDiff.y());
215 title->setPos(titleCenterDiff.x() - titlePadding() - (titleBoundingRect.height() / 2.0), titleCenterDiff.y());
215 title->setTransformOriginPoint(titleCenter);
216 title->setTransformOriginPoint(titleCenter);
216 title->setRotation(270.0);
217 title->setRotation(270.0);
217 }
218 }
218
219
219 QGraphicsLayoutItem::updateGeometry();
220 QGraphicsLayoutItem::updateGeometry();
220 }
221 }
221
222
222 Qt::Orientation PolarChartAxisRadial::orientation() const
223 Qt::Orientation PolarChartAxisRadial::orientation() const
223 {
224 {
224 return Qt::Vertical;
225 return Qt::Vertical;
225 }
226 }
226
227
227 void PolarChartAxisRadial::createItems(int count)
228 void PolarChartAxisRadial::createItems(int count)
228 {
229 {
229 if (arrowItems().count() == 0) {
230 if (arrowItems().count() == 0) {
230 // radial axis center line
231 // radial axis center line
231 QGraphicsLineItem *arrow = new LineArrowItem(this, presenter()->rootItem());
232 QGraphicsLineItem *arrow = new LineArrowItem(this, presenter()->rootItem());
232 arrow->setPen(axis()->linePen());
233 arrow->setPen(axis()->linePen());
233 arrowGroup()->addToGroup(arrow);
234 arrowGroup()->addToGroup(arrow);
234 }
235 }
235
236
236 for (int i = 0; i < count; ++i) {
237 for (int i = 0; i < count; ++i) {
237 QGraphicsLineItem *arrow = new QGraphicsLineItem(presenter()->rootItem());
238 QGraphicsLineItem *arrow = new QGraphicsLineItem(presenter()->rootItem());
238 QGraphicsEllipseItem *grid = new QGraphicsEllipseItem(presenter()->rootItem());
239 QGraphicsEllipseItem *grid = new QGraphicsEllipseItem(presenter()->rootItem());
239 QGraphicsTextItem *label = new QGraphicsTextItem(presenter()->rootItem());
240 QGraphicsTextItem *label = new QGraphicsTextItem(presenter()->rootItem());
240 label->document()->setDocumentMargin(ChartPresenter::textMargin());
241 label->document()->setDocumentMargin(ChartPresenter::textMargin());
241 QGraphicsTextItem *title = titleItem();
242 QGraphicsTextItem *title = titleItem();
242 arrow->setPen(axis()->linePen());
243 arrow->setPen(axis()->linePen());
243 grid->setPen(axis()->gridLinePen());
244 grid->setPen(axis()->gridLinePen());
244 label->setFont(axis()->labelsFont());
245 label->setFont(axis()->labelsFont());
245 label->setDefaultTextColor(axis()->labelsBrush().color());
246 label->setDefaultTextColor(axis()->labelsBrush().color());
246 label->setRotation(axis()->labelsAngle());
247 label->setRotation(axis()->labelsAngle());
247 title->setFont(axis()->titleFont());
248 title->setFont(axis()->titleFont());
248 title->setDefaultTextColor(axis()->titleBrush().color());
249 title->setDefaultTextColor(axis()->titleBrush().color());
249 title->setHtml(axis()->titleText());
250 title->setHtml(axis()->titleText());
250 arrowGroup()->addToGroup(arrow);
251 arrowGroup()->addToGroup(arrow);
251 gridGroup()->addToGroup(grid);
252 gridGroup()->addToGroup(grid);
252 labelGroup()->addToGroup(label);
253 labelGroup()->addToGroup(label);
253 if (gridItems().size() == 1 || (((gridItems().size() + 1) % 2) && gridItems().size() > 0)) {
254 if (gridItems().size() == 1 || (((gridItems().size() + 1) % 2) && gridItems().size() > 0)) {
254 QGraphicsPathItem *shade = new QGraphicsPathItem(presenter()->rootItem());
255 QGraphicsPathItem *shade = new QGraphicsPathItem(presenter()->rootItem());
255 shade->setPen(axis()->shadesPen());
256 shade->setPen(axis()->shadesPen());
256 shade->setBrush(axis()->shadesBrush());
257 shade->setBrush(axis()->shadesBrush());
257 shadeGroup()->addToGroup(shade);
258 shadeGroup()->addToGroup(shade);
258 }
259 }
259 }
260 }
260 }
261 }
261
262
262 void PolarChartAxisRadial::handleArrowPenChanged(const QPen &pen)
263 void PolarChartAxisRadial::handleArrowPenChanged(const QPen &pen)
263 {
264 {
264 foreach (QGraphicsItem *item, arrowItems())
265 foreach (QGraphicsItem *item, arrowItems())
265 static_cast<QGraphicsLineItem *>(item)->setPen(pen);
266 static_cast<QGraphicsLineItem *>(item)->setPen(pen);
266 }
267 }
267
268
268 void PolarChartAxisRadial::handleGridPenChanged(const QPen &pen)
269 void PolarChartAxisRadial::handleGridPenChanged(const QPen &pen)
269 {
270 {
270 foreach (QGraphicsItem *item, gridItems())
271 foreach (QGraphicsItem *item, gridItems())
271 static_cast<QGraphicsEllipseItem *>(item)->setPen(pen);
272 static_cast<QGraphicsEllipseItem *>(item)->setPen(pen);
272 }
273 }
273
274
274 QSizeF PolarChartAxisRadial::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
275 QSizeF PolarChartAxisRadial::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
275 {
276 {
276 Q_UNUSED(which);
277 Q_UNUSED(which);
277 Q_UNUSED(constraint);
278 Q_UNUSED(constraint);
278 return QSizeF(-1.0, -1.0);
279 return QSizeF(-1.0, -1.0);
279 }
280 }
280
281
281 qreal PolarChartAxisRadial::preferredAxisRadius(const QSizeF &maxSize)
282 qreal PolarChartAxisRadial::preferredAxisRadius(const QSizeF &maxSize)
282 {
283 {
283 qreal radius = maxSize.height() / 2.0;
284 qreal radius = maxSize.height() / 2.0;
284 if (maxSize.width() < maxSize.height())
285 if (maxSize.width() < maxSize.height())
285 radius = maxSize.width() / 2.0;
286 radius = maxSize.width() / 2.0;
286 return radius;
287 return radius;
287 }
288 }
288
289
289 #include "moc_polarchartaxisradial_p.cpp"
290 #include "moc_polarchartaxisradial_p.cpp"
290
291
291 QTCOMMERCIALCHART_END_NAMESPACE
292 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,229 +1,225
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2013 Digia Plc
3 ** Copyright (C) 2013 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 **
6 **
7 ** This file is part of the Qt Enterprise Charts Add-on.
7 ** This file is part of the Qt Enterprise Charts Add-on.
8 **
8 **
9 ** $QT_BEGIN_LICENSE$
9 ** $QT_BEGIN_LICENSE$
10 ** Licensees holding valid Qt Enterprise licenses may use this file in
10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 ** accordance with the Qt Enterprise License Agreement provided with the
11 ** accordance with the Qt Enterprise License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.
13 ** a written agreement between you and Digia.
14 **
14 **
15 ** If you have questions regarding the use of this file, please use
15 ** If you have questions regarding the use of this file, please use
16 ** contact form at http://qt.digia.com
16 ** contact form at http://qt.digia.com
17 ** $QT_END_LICENSE$
17 ** $QT_END_LICENSE$
18 **
18 **
19 ****************************************************************************/
19 ****************************************************************************/
20
20
21 #include "verticalaxis_p.h"
21 #include "verticalaxis_p.h"
22 #include "qabstractaxis.h"
22 #include "qabstractaxis.h"
23 #include "chartpresenter_p.h"
23 #include "chartpresenter_p.h"
24 #include <QDebug>
24 #include <QDebug>
25
25
26 QTCOMMERCIALCHART_BEGIN_NAMESPACE
26 QTCOMMERCIALCHART_BEGIN_NAMESPACE
27
27
28 VerticalAxis::VerticalAxis(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
28 VerticalAxis::VerticalAxis(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
29 : CartesianChartAxis(axis, item, intervalAxis)
29 : CartesianChartAxis(axis, item, intervalAxis)
30 {
30 {
31 }
31 }
32
32
33 VerticalAxis::~VerticalAxis()
33 VerticalAxis::~VerticalAxis()
34 {
34 {
35 }
35 }
36
36
37 void VerticalAxis::updateGeometry()
37 void VerticalAxis::updateGeometry()
38 {
38 {
39 const QVector<qreal> &layout = ChartAxisElement::layout();
39 const QVector<qreal> &layout = ChartAxisElement::layout();
40
40
41 if (layout.isEmpty())
41 if (layout.isEmpty())
42 return;
42 return;
43
43
44 QStringList labelList = labels();
44 QStringList labelList = labels();
45
45
46 QList<QGraphicsItem *> lines = gridItems();
46 QList<QGraphicsItem *> lines = gridItems();
47 QList<QGraphicsItem *> labels = labelItems();
47 QList<QGraphicsItem *> labels = labelItems();
48 QList<QGraphicsItem *> shades = shadeItems();
48 QList<QGraphicsItem *> shades = shadeItems();
49 QList<QGraphicsItem *> arrow = arrowItems();
49 QList<QGraphicsItem *> arrow = arrowItems();
50 QGraphicsTextItem *title = titleItem();
50 QGraphicsTextItem *title = titleItem();
51
51
52 Q_ASSERT(labels.size() == labelList.size());
52 Q_ASSERT(labels.size() == labelList.size());
53 Q_ASSERT(layout.size() == labelList.size());
53 Q_ASSERT(layout.size() == labelList.size());
54
54
55 const QRectF &axisRect = axisGeometry();
55 const QRectF &axisRect = axisGeometry();
56 const QRectF &gridRect = gridGeometry();
56 const QRectF &gridRect = gridGeometry();
57
57
58 qreal height = axisRect.bottom();
58 qreal height = axisRect.bottom();
59
59
60
60
61 //arrow
61 //arrow
62 QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem*>(arrow.at(0));
62 QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem*>(arrow.at(0));
63
63
64 //arrow position
64 //arrow position
65 if (axis()->alignment() == Qt::AlignLeft)
65 if (axis()->alignment() == Qt::AlignLeft)
66 arrowItem->setLine(axisRect.right(), gridRect.top(), axisRect.right(), gridRect.bottom());
66 arrowItem->setLine(axisRect.right(), gridRect.top(), axisRect.right(), gridRect.bottom());
67 else if (axis()->alignment() == Qt::AlignRight)
67 else if (axis()->alignment() == Qt::AlignRight)
68 arrowItem->setLine(axisRect.left(), gridRect.top(), axisRect.left(), gridRect.bottom());
68 arrowItem->setLine(axisRect.left(), gridRect.top(), axisRect.left(), gridRect.bottom());
69
69
70 //title
70 //title
71 QRectF titleBoundingRect;
71 QRectF titleBoundingRect;
72 QString titleText = axis()->titleText();
72 QString titleText = axis()->titleText();
73 qreal availableSpace = axisRect.width() - labelPadding();
73 qreal availableSpace = axisRect.width() - labelPadding();
74 if (!titleText.isEmpty() && titleItem()->isVisible()) {
74 if (!titleText.isEmpty() && titleItem()->isVisible()) {
75 availableSpace -= titlePadding() * 2.0;
75 availableSpace -= titlePadding() * 2.0;
76 qreal minimumLabelWidth = ChartPresenter::textBoundingRect(axis()->labelsFont(), "...").width();
76 qreal minimumLabelWidth = ChartPresenter::textBoundingRect(axis()->labelsFont(), "...").width();
77 QString truncatedTitle = ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0),
78 gridRect.height(), Qt::Horizontal, titleBoundingRect);
79 qreal titleSpace = availableSpace - minimumLabelWidth;
77 qreal titleSpace = availableSpace - minimumLabelWidth;
80 if (titleSpace < titleBoundingRect.height()) {
78 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(90.0),
81 // Need to also truncate title vertically (multiline title)
79 titleSpace, gridRect.height(),
82 bool skip = false;
80 titleBoundingRect));
83 if (truncatedTitle.endsWith("...")) {
84 if (truncatedTitle.size() == 3)
85 skip = true; // Already truncated to minimum
86 else
87 truncatedTitle.chop(3);
88 }
89 if (!skip)
90 truncatedTitle = ChartPresenter::truncatedText(axis()->titleFont(), truncatedTitle, qreal(0.0),
91 titleSpace, Qt::Vertical, titleBoundingRect);
92 }
93 title->setHtml(truncatedTitle);
94
81
95 titleBoundingRect = title->boundingRect();
82 titleBoundingRect = title->boundingRect();
96
83
97 QPointF center = gridRect.center() - titleBoundingRect.center();
84 QPointF center = gridRect.center() - titleBoundingRect.center();
98 if (axis()->alignment() == Qt::AlignLeft)
85 if (axis()->alignment() == Qt::AlignLeft)
99 title->setPos(axisRect.left() - titleBoundingRect.width() / 2.0 + titleBoundingRect.height() / 2.0 + titlePadding(), center.y());
86 title->setPos(axisRect.left() - titleBoundingRect.width() / 2.0 + titleBoundingRect.height() / 2.0 + titlePadding(), center.y());
100 else if (axis()->alignment() == Qt::AlignRight)
87 else if (axis()->alignment() == Qt::AlignRight)
101 title->setPos(axisRect.right() - titleBoundingRect.width() / 2.0 - titleBoundingRect.height() / 2.0 - titlePadding(), center.y());
88 title->setPos(axisRect.right() - titleBoundingRect.width() / 2.0 - titleBoundingRect.height() / 2.0 - titlePadding(), center.y());
102
89
103 title->setTransformOriginPoint(titleBoundingRect.center());
90 title->setTransformOriginPoint(titleBoundingRect.center());
104 title->setRotation(270);
91 title->setRotation(270);
105
92
106 availableSpace -= titleBoundingRect.height();
93 availableSpace -= titleBoundingRect.height();
107 }
94 }
108
95
109 for (int i = 0; i < layout.size(); ++i) {
96 for (int i = 0; i < layout.size(); ++i) {
110 //items
97 //items
111 QGraphicsLineItem *gridItem = static_cast<QGraphicsLineItem *>(lines.at(i));
98 QGraphicsLineItem *gridItem = static_cast<QGraphicsLineItem *>(lines.at(i));
112 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrow.at(i + 1));
99 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrow.at(i + 1));
113 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labels.at(i));
100 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labels.at(i));
114
101
115 //grid line
102 //grid line
116 gridItem->setLine(gridRect.left(), layout[i], gridRect.right(), layout[i]);
103 gridItem->setLine(gridRect.left(), layout[i], gridRect.right(), layout[i]);
117
104
118 //label text wrapping
105 //label text wrapping
119 QString text = labelList.at(i);
106 QString text = labelList.at(i);
120 QRectF boundingRect;
107 QRectF boundingRect;
121 labelItem->setHtml(ChartPresenter::truncatedText(axis()->labelsFont(), text, axis()->labelsAngle(),
108 // don't truncate empty labels
122 availableSpace, Qt::Horizontal, boundingRect));
109 if (text.isEmpty()) {
110 labelItem->setHtml(text);
111 } else {
112 qreal labelHeight = (axisRect.height() / layout.count()) - (2 * labelPadding());
113 labelItem->setHtml(ChartPresenter::truncatedText(axis()->labelsFont(), text,
114 axis()->labelsAngle(), availableSpace,
115 labelHeight, boundingRect));
116 }
123
117
124 //label transformation origin point
118 //label transformation origin point
125 const QRectF &rect = labelItem->boundingRect();
119 const QRectF &rect = labelItem->boundingRect();
126 QPointF center = rect.center();
120 QPointF center = rect.center();
127 labelItem->setTransformOriginPoint(center.x(), center.y());
121 labelItem->setTransformOriginPoint(center.x(), center.y());
128 qreal widthDiff = rect.width() - boundingRect.width();
122 qreal widthDiff = rect.width() - boundingRect.width();
129 qreal heightDiff = rect.height() - boundingRect.height();
123 qreal heightDiff = rect.height() - boundingRect.height();
130
124
131 //ticks and label position
125 //ticks and label position
132 if (axis()->alignment() == Qt::AlignLeft) {
126 if (axis()->alignment() == Qt::AlignLeft) {
133 labelItem->setPos(axisRect.right() - rect.width() + (widthDiff / 2.0) - labelPadding(), layout[i] - center.y());
127 labelItem->setPos(axisRect.right() - rect.width() + (widthDiff / 2.0) - labelPadding(), layout[i] - center.y());
134 tickItem->setLine(axisRect.right() - labelPadding(), layout[i], axisRect.right(), layout[i]);
128 tickItem->setLine(axisRect.right() - labelPadding(), layout[i], axisRect.right(), layout[i]);
135 } else if (axis()->alignment() == Qt::AlignRight) {
129 } else if (axis()->alignment() == Qt::AlignRight) {
136 labelItem->setPos(axisRect.left() + labelPadding() - (widthDiff / 2.0), layout[i] - center.y());
130 labelItem->setPos(axisRect.left() + labelPadding() - (widthDiff / 2.0), layout[i] - center.y());
137 tickItem->setLine(axisRect.left(), layout[i], axisRect.left() + labelPadding(), layout[i]);
131 tickItem->setLine(axisRect.left(), layout[i], axisRect.left() + labelPadding(), layout[i]);
138 }
132 }
139
133
140 //label in between
134 //label in between
141 bool forceHide = false;
135 bool forceHide = false;
142 if (intervalAxis() && (i + 1) != layout.size()) {
136 if (intervalAxis() && (i + 1) != layout.size()) {
143 qreal lowerBound = qMin(layout[i], gridRect.bottom());
137 qreal lowerBound = qMin(layout[i], gridRect.bottom());
144 qreal upperBound = qMax(layout[i + 1], gridRect.top());
138 qreal upperBound = qMax(layout[i + 1], gridRect.top());
145 const qreal delta = lowerBound - upperBound;
139 const qreal delta = lowerBound - upperBound;
146 // Hide label in case visible part of the category at the grid edge is too narrow
140 // Hide label in case visible part of the category at the grid edge is too narrow
147 if (delta < boundingRect.height()
141 if (delta < boundingRect.height()
148 && (lowerBound == gridRect.bottom() || upperBound == gridRect.top())) {
142 && (lowerBound == gridRect.bottom() || upperBound == gridRect.top())
143 && !intervalAxis()) {
149 forceHide = true;
144 forceHide = true;
150 } else {
145 } else {
151 labelItem->setPos(labelItem->pos().x() , lowerBound - (delta / 2.0) - center.y());
146 labelItem->setPos(labelItem->pos().x() , lowerBound - (delta / 2.0) - center.y());
152 }
147 }
153 }
148 }
154
149
155 //label overlap detection - compensate one pixel for rounding errors
150 //label overlap detection - compensate one pixel for rounding errors
156 if (labelItem->pos().y() + boundingRect.height() > height || forceHide ||
151 if ((labelItem->pos().y() + boundingRect.height() > height || forceHide ||
157 (labelItem->pos().y() + (heightDiff / 2.0) - 1.0) > axisRect.bottom() ||
152 (labelItem->pos().y() + (heightDiff / 2.0) - 1.0) > axisRect.bottom() ||
158 labelItem->pos().y() + (heightDiff / 2.0) < (axisRect.top() - 1.0)) {
153 labelItem->pos().y() + (heightDiff / 2.0) < (axisRect.top() - 1.0))
154 && !intervalAxis()) {
159 labelItem->setVisible(false);
155 labelItem->setVisible(false);
160 }
156 }
161 else {
157 else {
162 labelItem->setVisible(true);
158 labelItem->setVisible(true);
163 height=labelItem->pos().y();
159 height=labelItem->pos().y();
164 }
160 }
165
161
166 //shades
162 //shades
167 if ((i + 1) % 2 && i > 1) {
163 if ((i + 1) % 2 && i > 1) {
168 QGraphicsRectItem *rectItem = static_cast<QGraphicsRectItem *>(shades.at(i / 2 - 1));
164 QGraphicsRectItem *rectItem = static_cast<QGraphicsRectItem *>(shades.at(i / 2 - 1));
169 qreal lowerBound = qMin(layout[i - 1], gridRect.bottom());
165 qreal lowerBound = qMin(layout[i - 1], gridRect.bottom());
170 qreal upperBound = qMax(layout[i], gridRect.top());
166 qreal upperBound = qMax(layout[i], gridRect.top());
171 rectItem->setRect(gridRect.left(), upperBound, gridRect.width(), lowerBound - upperBound);
167 rectItem->setRect(gridRect.left(), upperBound, gridRect.width(), lowerBound - upperBound);
172 if (rectItem->rect().height() <= 0.0)
168 if (rectItem->rect().height() <= 0.0)
173 rectItem->setVisible(false);
169 rectItem->setVisible(false);
174 else
170 else
175 rectItem->setVisible(true);
171 rectItem->setVisible(true);
176 }
172 }
177
173
178 // check if the grid line and the axis tick should be shown
174 // check if the grid line and the axis tick should be shown
179 qreal y = gridItem->line().p1().y();
175 qreal y = gridItem->line().p1().y();
180 if ((y < gridRect.top() || y > gridRect.bottom()))
176 if ((y < gridRect.top() || y > gridRect.bottom()))
181 {
177 {
182 gridItem->setVisible(false);
178 gridItem->setVisible(false);
183 tickItem->setVisible(false);
179 tickItem->setVisible(false);
184 }else{
180 }else{
185 gridItem->setVisible(true);
181 gridItem->setVisible(true);
186 tickItem->setVisible(true);
182 tickItem->setVisible(true);
187 }
183 }
188
184
189 }
185 }
190 //begin/end grid line in case labels between
186 //begin/end grid line in case labels between
191 if (intervalAxis()) {
187 if (intervalAxis()) {
192 QGraphicsLineItem *gridLine;
188 QGraphicsLineItem *gridLine;
193 gridLine = static_cast<QGraphicsLineItem *>(lines.at(layout.size()));
189 gridLine = static_cast<QGraphicsLineItem *>(lines.at(layout.size()));
194 gridLine->setLine(gridRect.left(), gridRect.top(), gridRect.right(), gridRect.top());
190 gridLine->setLine(gridRect.left(), gridRect.top(), gridRect.right(), gridRect.top());
195 gridLine->setVisible(true);
191 gridLine->setVisible(true);
196 gridLine = static_cast<QGraphicsLineItem*>(lines.at(layout.size() + 1));
192 gridLine = static_cast<QGraphicsLineItem*>(lines.at(layout.size() + 1));
197 gridLine->setLine(gridRect.left(), gridRect.bottom(), gridRect.right(), gridRect.bottom());
193 gridLine->setLine(gridRect.left(), gridRect.bottom(), gridRect.right(), gridRect.bottom());
198 gridLine->setVisible(true);
194 gridLine->setVisible(true);
199 }
195 }
200 }
196 }
201
197
202 QSizeF VerticalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
198 QSizeF VerticalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
203 {
199 {
204 Q_UNUSED(constraint);
200 Q_UNUSED(constraint);
205 QSizeF sh(0, 0);
201 QSizeF sh(0, 0);
206
202
207 if (axis()->titleText().isEmpty() || !titleItem()->isVisible())
203 if (axis()->titleText().isEmpty() || !titleItem()->isVisible())
208 return sh;
204 return sh;
209
205
210 switch (which) {
206 switch (which) {
211 case Qt::MinimumSize: {
207 case Qt::MinimumSize: {
212 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), "...");
208 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), "...");
213 sh = QSizeF(titleRect.height() + (titlePadding() * 2.0), titleRect.width());
209 sh = QSizeF(titleRect.height() + (titlePadding() * 2.0), titleRect.width());
214 break;
210 break;
215 }
211 }
216 case Qt::MaximumSize:
212 case Qt::MaximumSize:
217 case Qt::PreferredSize: {
213 case Qt::PreferredSize: {
218 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText());
214 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText());
219 sh = QSizeF(titleRect.height() + (titlePadding() * 2.0), titleRect.width());
215 sh = QSizeF(titleRect.height() + (titlePadding() * 2.0), titleRect.width());
220 break;
216 break;
221 }
217 }
222 default:
218 default:
223 break;
219 break;
224 }
220 }
225
221
226 return sh;
222 return sh;
227 }
223 }
228
224
229 QTCOMMERCIALCHART_END_NAMESPACE
225 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,484 +1,480
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2013 Digia Plc
3 ** Copyright (C) 2013 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 **
6 **
7 ** This file is part of the Qt Enterprise Charts Add-on.
7 ** This file is part of the Qt Enterprise Charts Add-on.
8 **
8 **
9 ** $QT_BEGIN_LICENSE$
9 ** $QT_BEGIN_LICENSE$
10 ** Licensees holding valid Qt Enterprise licenses may use this file in
10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 ** accordance with the Qt Enterprise License Agreement provided with the
11 ** accordance with the Qt Enterprise License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.
13 ** a written agreement between you and Digia.
14 **
14 **
15 ** If you have questions regarding the use of this file, please use
15 ** If you have questions regarding the use of this file, please use
16 ** contact form at http://qt.digia.com
16 ** contact form at http://qt.digia.com
17 ** $QT_END_LICENSE$
17 ** $QT_END_LICENSE$
18 **
18 **
19 ****************************************************************************/
19 ****************************************************************************/
20 #include "chartpresenter_p.h"
20 #include "chartpresenter_p.h"
21 #include "qchart.h"
21 #include "qchart.h"
22 #include "chartitem_p.h"
22 #include "chartitem_p.h"
23 #include "qchart_p.h"
23 #include "qchart_p.h"
24 #include "qabstractaxis.h"
24 #include "qabstractaxis.h"
25 #include "qabstractaxis_p.h"
25 #include "qabstractaxis_p.h"
26 #include "chartdataset_p.h"
26 #include "chartdataset_p.h"
27 #include "chartanimation_p.h"
27 #include "chartanimation_p.h"
28 #include "qabstractseries_p.h"
28 #include "qabstractseries_p.h"
29 #include "qareaseries.h"
29 #include "qareaseries.h"
30 #include "chartaxiselement_p.h"
30 #include "chartaxiselement_p.h"
31 #include "chartbackground_p.h"
31 #include "chartbackground_p.h"
32 #include "cartesianchartlayout_p.h"
32 #include "cartesianchartlayout_p.h"
33 #include "polarchartlayout_p.h"
33 #include "polarchartlayout_p.h"
34 #include "charttitle_p.h"
34 #include "charttitle_p.h"
35 #include <QTimer>
35 #include <QTimer>
36 #include <QTextDocument>
36 #include <QTextDocument>
37
37
38 QTCOMMERCIALCHART_BEGIN_NAMESPACE
38 QTCOMMERCIALCHART_BEGIN_NAMESPACE
39
39
40 ChartPresenter::ChartPresenter(QChart *chart, QChart::ChartType type)
40 ChartPresenter::ChartPresenter(QChart *chart, QChart::ChartType type)
41 : QObject(chart),
41 : QObject(chart),
42 m_chart(chart),
42 m_chart(chart),
43 m_options(QChart::NoAnimation),
43 m_options(QChart::NoAnimation),
44 m_state(ShowState),
44 m_state(ShowState),
45 m_background(0),
45 m_background(0),
46 m_plotAreaBackground(0),
46 m_plotAreaBackground(0),
47 m_title(0)
47 m_title(0)
48 {
48 {
49 if (type == QChart::ChartTypeCartesian)
49 if (type == QChart::ChartTypeCartesian)
50 m_layout = new CartesianChartLayout(this);
50 m_layout = new CartesianChartLayout(this);
51 else if (type == QChart::ChartTypePolar)
51 else if (type == QChart::ChartTypePolar)
52 m_layout = new PolarChartLayout(this);
52 m_layout = new PolarChartLayout(this);
53 Q_ASSERT(m_layout);
53 Q_ASSERT(m_layout);
54 }
54 }
55
55
56 ChartPresenter::~ChartPresenter()
56 ChartPresenter::~ChartPresenter()
57 {
57 {
58
58
59 }
59 }
60
60
61 void ChartPresenter::setGeometry(const QRectF rect)
61 void ChartPresenter::setGeometry(const QRectF rect)
62 {
62 {
63 if (m_rect != rect) {
63 if (m_rect != rect) {
64 m_rect = rect;
64 m_rect = rect;
65 foreach (ChartItem *chart, m_chartItems) {
65 foreach (ChartItem *chart, m_chartItems) {
66 chart->domain()->setSize(rect.size());
66 chart->domain()->setSize(rect.size());
67 chart->setPos(rect.topLeft());
67 chart->setPos(rect.topLeft());
68 }
68 }
69 }
69 }
70 }
70 }
71
71
72 QRectF ChartPresenter::geometry() const
72 QRectF ChartPresenter::geometry() const
73 {
73 {
74 return m_rect;
74 return m_rect;
75 }
75 }
76
76
77 void ChartPresenter::handleAxisAdded(QAbstractAxis *axis)
77 void ChartPresenter::handleAxisAdded(QAbstractAxis *axis)
78 {
78 {
79 axis->d_ptr->initializeGraphics(rootItem());
79 axis->d_ptr->initializeGraphics(rootItem());
80 axis->d_ptr->initializeAnimations(m_options);
80 axis->d_ptr->initializeAnimations(m_options);
81 ChartAxisElement *item = axis->d_ptr->axisItem();
81 ChartAxisElement *item = axis->d_ptr->axisItem();
82 item->setPresenter(this);
82 item->setPresenter(this);
83 item->setThemeManager(m_chart->d_ptr->m_themeManager);
83 item->setThemeManager(m_chart->d_ptr->m_themeManager);
84 m_axisItems<<item;
84 m_axisItems<<item;
85 m_axes<<axis;
85 m_axes<<axis;
86 m_layout->invalidate();
86 m_layout->invalidate();
87 }
87 }
88
88
89 void ChartPresenter::handleAxisRemoved(QAbstractAxis *axis)
89 void ChartPresenter::handleAxisRemoved(QAbstractAxis *axis)
90 {
90 {
91 ChartAxisElement *item = axis->d_ptr->m_item.take();
91 ChartAxisElement *item = axis->d_ptr->m_item.take();
92 item->hide();
92 item->hide();
93 item->disconnect();
93 item->disconnect();
94 item->deleteLater();
94 item->deleteLater();
95 m_axisItems.removeAll(item);
95 m_axisItems.removeAll(item);
96 m_axes.removeAll(axis);
96 m_axes.removeAll(axis);
97 m_layout->invalidate();
97 m_layout->invalidate();
98 }
98 }
99
99
100
100
101 void ChartPresenter::handleSeriesAdded(QAbstractSeries *series)
101 void ChartPresenter::handleSeriesAdded(QAbstractSeries *series)
102 {
102 {
103 series->d_ptr->initializeGraphics(rootItem());
103 series->d_ptr->initializeGraphics(rootItem());
104 series->d_ptr->initializeAnimations(m_options);
104 series->d_ptr->initializeAnimations(m_options);
105 ChartItem *chart = series->d_ptr->chartItem();
105 ChartItem *chart = series->d_ptr->chartItem();
106 chart->setPresenter(this);
106 chart->setPresenter(this);
107 chart->setThemeManager(m_chart->d_ptr->m_themeManager);
107 chart->setThemeManager(m_chart->d_ptr->m_themeManager);
108 chart->domain()->setSize(m_rect.size());
108 chart->domain()->setSize(m_rect.size());
109 chart->setPos(m_rect.topLeft());
109 chart->setPos(m_rect.topLeft());
110 chart->handleDomainUpdated(); //this could be moved to intializeGraphics when animator is refactored
110 chart->handleDomainUpdated(); //this could be moved to intializeGraphics when animator is refactored
111 m_chartItems<<chart;
111 m_chartItems<<chart;
112 m_series<<series;
112 m_series<<series;
113 m_layout->invalidate();
113 m_layout->invalidate();
114 }
114 }
115
115
116 void ChartPresenter::handleSeriesRemoved(QAbstractSeries *series)
116 void ChartPresenter::handleSeriesRemoved(QAbstractSeries *series)
117 {
117 {
118 ChartItem *chart = series->d_ptr->m_item.take();
118 ChartItem *chart = series->d_ptr->m_item.take();
119 chart->hide();
119 chart->hide();
120 chart->disconnect();
120 chart->disconnect();
121 chart->deleteLater();
121 chart->deleteLater();
122 m_chartItems.removeAll(chart);
122 m_chartItems.removeAll(chart);
123 m_series.removeAll(series);
123 m_series.removeAll(series);
124 m_layout->invalidate();
124 m_layout->invalidate();
125 }
125 }
126
126
127 void ChartPresenter::setAnimationOptions(QChart::AnimationOptions options)
127 void ChartPresenter::setAnimationOptions(QChart::AnimationOptions options)
128 {
128 {
129 if (m_options != options) {
129 if (m_options != options) {
130 QChart::AnimationOptions oldOptions = m_options;
130 QChart::AnimationOptions oldOptions = m_options;
131 m_options = options;
131 m_options = options;
132 if (options.testFlag(QChart::SeriesAnimations) != oldOptions.testFlag(QChart::SeriesAnimations)) {
132 if (options.testFlag(QChart::SeriesAnimations) != oldOptions.testFlag(QChart::SeriesAnimations)) {
133 foreach (QAbstractSeries *series, m_series)
133 foreach (QAbstractSeries *series, m_series)
134 series->d_ptr->initializeAnimations(m_options);
134 series->d_ptr->initializeAnimations(m_options);
135 }
135 }
136 if (options.testFlag(QChart::GridAxisAnimations) != oldOptions.testFlag(QChart::GridAxisAnimations)) {
136 if (options.testFlag(QChart::GridAxisAnimations) != oldOptions.testFlag(QChart::GridAxisAnimations)) {
137 foreach (QAbstractAxis *axis, m_axes)
137 foreach (QAbstractAxis *axis, m_axes)
138 axis->d_ptr->initializeAnimations(m_options);
138 axis->d_ptr->initializeAnimations(m_options);
139 }
139 }
140 m_layout->invalidate(); // So that existing animations don't just stop halfway
140 m_layout->invalidate(); // So that existing animations don't just stop halfway
141 }
141 }
142 }
142 }
143
143
144 void ChartPresenter::setState(State state,QPointF point)
144 void ChartPresenter::setState(State state,QPointF point)
145 {
145 {
146 m_state=state;
146 m_state=state;
147 m_statePoint=point;
147 m_statePoint=point;
148 }
148 }
149
149
150 QChart::AnimationOptions ChartPresenter::animationOptions() const
150 QChart::AnimationOptions ChartPresenter::animationOptions() const
151 {
151 {
152 return m_options;
152 return m_options;
153 }
153 }
154
154
155 void ChartPresenter::createBackgroundItem()
155 void ChartPresenter::createBackgroundItem()
156 {
156 {
157 if (!m_background) {
157 if (!m_background) {
158 m_background = new ChartBackground(rootItem());
158 m_background = new ChartBackground(rootItem());
159 m_background->setPen(Qt::NoPen); // Theme doesn't touch pen so don't use default
159 m_background->setPen(Qt::NoPen); // Theme doesn't touch pen so don't use default
160 m_background->setBrush(QChartPrivate::defaultBrush());
160 m_background->setBrush(QChartPrivate::defaultBrush());
161 m_background->setZValue(ChartPresenter::BackgroundZValue);
161 m_background->setZValue(ChartPresenter::BackgroundZValue);
162 }
162 }
163 }
163 }
164
164
165 void ChartPresenter::createPlotAreaBackgroundItem()
165 void ChartPresenter::createPlotAreaBackgroundItem()
166 {
166 {
167 if (!m_plotAreaBackground) {
167 if (!m_plotAreaBackground) {
168 if (m_chart->chartType() == QChart::ChartTypeCartesian)
168 if (m_chart->chartType() == QChart::ChartTypeCartesian)
169 m_plotAreaBackground = new QGraphicsRectItem(rootItem());
169 m_plotAreaBackground = new QGraphicsRectItem(rootItem());
170 else
170 else
171 m_plotAreaBackground = new QGraphicsEllipseItem(rootItem());
171 m_plotAreaBackground = new QGraphicsEllipseItem(rootItem());
172 // Use transparent pen instead of Qt::NoPen, as Qt::NoPen causes
172 // Use transparent pen instead of Qt::NoPen, as Qt::NoPen causes
173 // antialising artifacts with axis lines for some reason.
173 // antialising artifacts with axis lines for some reason.
174 m_plotAreaBackground->setPen(QPen(Qt::transparent));
174 m_plotAreaBackground->setPen(QPen(Qt::transparent));
175 m_plotAreaBackground->setBrush(Qt::NoBrush);
175 m_plotAreaBackground->setBrush(Qt::NoBrush);
176 m_plotAreaBackground->setZValue(ChartPresenter::PlotAreaZValue);
176 m_plotAreaBackground->setZValue(ChartPresenter::PlotAreaZValue);
177 m_plotAreaBackground->setVisible(false);
177 m_plotAreaBackground->setVisible(false);
178 }
178 }
179 }
179 }
180
180
181 void ChartPresenter::createTitleItem()
181 void ChartPresenter::createTitleItem()
182 {
182 {
183 if (!m_title) {
183 if (!m_title) {
184 m_title = new ChartTitle(rootItem());
184 m_title = new ChartTitle(rootItem());
185 m_title->setZValue(ChartPresenter::BackgroundZValue);
185 m_title->setZValue(ChartPresenter::BackgroundZValue);
186 }
186 }
187 }
187 }
188
188
189 void ChartPresenter::startAnimation(ChartAnimation *animation)
189 void ChartPresenter::startAnimation(ChartAnimation *animation)
190 {
190 {
191 animation->stop();
191 animation->stop();
192 QTimer::singleShot(0, animation, SLOT(startChartAnimation()));
192 QTimer::singleShot(0, animation, SLOT(startChartAnimation()));
193 }
193 }
194
194
195 void ChartPresenter::setBackgroundBrush(const QBrush &brush)
195 void ChartPresenter::setBackgroundBrush(const QBrush &brush)
196 {
196 {
197 createBackgroundItem();
197 createBackgroundItem();
198 m_background->setBrush(brush);
198 m_background->setBrush(brush);
199 m_layout->invalidate();
199 m_layout->invalidate();
200 }
200 }
201
201
202 QBrush ChartPresenter::backgroundBrush() const
202 QBrush ChartPresenter::backgroundBrush() const
203 {
203 {
204 if (!m_background)
204 if (!m_background)
205 return QBrush();
205 return QBrush();
206 return m_background->brush();
206 return m_background->brush();
207 }
207 }
208
208
209 void ChartPresenter::setBackgroundPen(const QPen &pen)
209 void ChartPresenter::setBackgroundPen(const QPen &pen)
210 {
210 {
211 createBackgroundItem();
211 createBackgroundItem();
212 m_background->setPen(pen);
212 m_background->setPen(pen);
213 m_layout->invalidate();
213 m_layout->invalidate();
214 }
214 }
215
215
216 QPen ChartPresenter::backgroundPen() const
216 QPen ChartPresenter::backgroundPen() const
217 {
217 {
218 if (!m_background)
218 if (!m_background)
219 return QPen();
219 return QPen();
220 return m_background->pen();
220 return m_background->pen();
221 }
221 }
222
222
223 void ChartPresenter::setBackgroundRoundness(qreal diameter)
223 void ChartPresenter::setBackgroundRoundness(qreal diameter)
224 {
224 {
225 createBackgroundItem();
225 createBackgroundItem();
226 m_background->setDiameter(diameter);
226 m_background->setDiameter(diameter);
227 m_layout->invalidate();
227 m_layout->invalidate();
228 }
228 }
229
229
230 qreal ChartPresenter::backgroundRoundness() const
230 qreal ChartPresenter::backgroundRoundness() const
231 {
231 {
232 if (!m_background)
232 if (!m_background)
233 return 0;
233 return 0;
234 return m_background->diameter();
234 return m_background->diameter();
235 }
235 }
236
236
237 void ChartPresenter::setPlotAreaBackgroundBrush(const QBrush &brush)
237 void ChartPresenter::setPlotAreaBackgroundBrush(const QBrush &brush)
238 {
238 {
239 createPlotAreaBackgroundItem();
239 createPlotAreaBackgroundItem();
240 m_plotAreaBackground->setBrush(brush);
240 m_plotAreaBackground->setBrush(brush);
241 m_layout->invalidate();
241 m_layout->invalidate();
242 }
242 }
243
243
244 QBrush ChartPresenter::plotAreaBackgroundBrush() const
244 QBrush ChartPresenter::plotAreaBackgroundBrush() const
245 {
245 {
246 if (!m_plotAreaBackground)
246 if (!m_plotAreaBackground)
247 return QBrush();
247 return QBrush();
248 return m_plotAreaBackground->brush();
248 return m_plotAreaBackground->brush();
249 }
249 }
250
250
251 void ChartPresenter::setPlotAreaBackgroundPen(const QPen &pen)
251 void ChartPresenter::setPlotAreaBackgroundPen(const QPen &pen)
252 {
252 {
253 createPlotAreaBackgroundItem();
253 createPlotAreaBackgroundItem();
254 m_plotAreaBackground->setPen(pen);
254 m_plotAreaBackground->setPen(pen);
255 m_layout->invalidate();
255 m_layout->invalidate();
256 }
256 }
257
257
258 QPen ChartPresenter::plotAreaBackgroundPen() const
258 QPen ChartPresenter::plotAreaBackgroundPen() const
259 {
259 {
260 if (!m_plotAreaBackground)
260 if (!m_plotAreaBackground)
261 return QPen();
261 return QPen();
262 return m_plotAreaBackground->pen();
262 return m_plotAreaBackground->pen();
263 }
263 }
264
264
265 void ChartPresenter::setTitle(const QString &title)
265 void ChartPresenter::setTitle(const QString &title)
266 {
266 {
267 createTitleItem();
267 createTitleItem();
268 m_title->setText(title);
268 m_title->setText(title);
269 m_layout->invalidate();
269 m_layout->invalidate();
270 }
270 }
271
271
272 QString ChartPresenter::title() const
272 QString ChartPresenter::title() const
273 {
273 {
274 if (!m_title)
274 if (!m_title)
275 return QString();
275 return QString();
276 return m_title->text();
276 return m_title->text();
277 }
277 }
278
278
279 void ChartPresenter::setTitleFont(const QFont &font)
279 void ChartPresenter::setTitleFont(const QFont &font)
280 {
280 {
281 createTitleItem();
281 createTitleItem();
282 m_title->setFont(font);
282 m_title->setFont(font);
283 m_layout->invalidate();
283 m_layout->invalidate();
284 }
284 }
285
285
286 QFont ChartPresenter::titleFont() const
286 QFont ChartPresenter::titleFont() const
287 {
287 {
288 if (!m_title)
288 if (!m_title)
289 return QFont();
289 return QFont();
290 return m_title->font();
290 return m_title->font();
291 }
291 }
292
292
293 void ChartPresenter::setTitleBrush(const QBrush &brush)
293 void ChartPresenter::setTitleBrush(const QBrush &brush)
294 {
294 {
295 createTitleItem();
295 createTitleItem();
296 m_title->setDefaultTextColor(brush.color());
296 m_title->setDefaultTextColor(brush.color());
297 m_layout->invalidate();
297 m_layout->invalidate();
298 }
298 }
299
299
300 QBrush ChartPresenter::titleBrush() const
300 QBrush ChartPresenter::titleBrush() const
301 {
301 {
302 if (!m_title)
302 if (!m_title)
303 return QBrush();
303 return QBrush();
304 return QBrush(m_title->defaultTextColor());
304 return QBrush(m_title->defaultTextColor());
305 }
305 }
306
306
307 void ChartPresenter::setBackgroundVisible(bool visible)
307 void ChartPresenter::setBackgroundVisible(bool visible)
308 {
308 {
309 createBackgroundItem();
309 createBackgroundItem();
310 m_background->setVisible(visible);
310 m_background->setVisible(visible);
311 }
311 }
312
312
313
313
314 bool ChartPresenter::isBackgroundVisible() const
314 bool ChartPresenter::isBackgroundVisible() const
315 {
315 {
316 if (!m_background)
316 if (!m_background)
317 return false;
317 return false;
318 return m_background->isVisible();
318 return m_background->isVisible();
319 }
319 }
320
320
321 void ChartPresenter::setPlotAreaBackgroundVisible(bool visible)
321 void ChartPresenter::setPlotAreaBackgroundVisible(bool visible)
322 {
322 {
323 createPlotAreaBackgroundItem();
323 createPlotAreaBackgroundItem();
324 m_plotAreaBackground->setVisible(visible);
324 m_plotAreaBackground->setVisible(visible);
325 }
325 }
326
326
327 bool ChartPresenter::isPlotAreaBackgroundVisible() const
327 bool ChartPresenter::isPlotAreaBackgroundVisible() const
328 {
328 {
329 if (!m_plotAreaBackground)
329 if (!m_plotAreaBackground)
330 return false;
330 return false;
331 return m_plotAreaBackground->isVisible();
331 return m_plotAreaBackground->isVisible();
332 }
332 }
333
333
334 void ChartPresenter::setBackgroundDropShadowEnabled(bool enabled)
334 void ChartPresenter::setBackgroundDropShadowEnabled(bool enabled)
335 {
335 {
336 createBackgroundItem();
336 createBackgroundItem();
337 m_background->setDropShadowEnabled(enabled);
337 m_background->setDropShadowEnabled(enabled);
338 }
338 }
339
339
340 bool ChartPresenter::isBackgroundDropShadowEnabled() const
340 bool ChartPresenter::isBackgroundDropShadowEnabled() const
341 {
341 {
342 if (!m_background)
342 if (!m_background)
343 return false;
343 return false;
344 return m_background->isDropShadowEnabled();
344 return m_background->isDropShadowEnabled();
345 }
345 }
346
346
347
347
348 AbstractChartLayout *ChartPresenter::layout()
348 AbstractChartLayout *ChartPresenter::layout()
349 {
349 {
350 return m_layout;
350 return m_layout;
351 }
351 }
352
352
353 QLegend *ChartPresenter::legend()
353 QLegend *ChartPresenter::legend()
354 {
354 {
355 return m_chart->legend();
355 return m_chart->legend();
356 }
356 }
357
357
358 void ChartPresenter::setVisible(bool visible)
358 void ChartPresenter::setVisible(bool visible)
359 {
359 {
360 m_chart->setVisible(visible);
360 m_chart->setVisible(visible);
361 }
361 }
362
362
363 ChartBackground *ChartPresenter::backgroundElement()
363 ChartBackground *ChartPresenter::backgroundElement()
364 {
364 {
365 return m_background;
365 return m_background;
366 }
366 }
367
367
368 QAbstractGraphicsShapeItem *ChartPresenter::plotAreaElement()
368 QAbstractGraphicsShapeItem *ChartPresenter::plotAreaElement()
369 {
369 {
370 return m_plotAreaBackground;
370 return m_plotAreaBackground;
371 }
371 }
372
372
373 QList<ChartAxisElement *> ChartPresenter::axisItems() const
373 QList<ChartAxisElement *> ChartPresenter::axisItems() const
374 {
374 {
375 return m_axisItems;
375 return m_axisItems;
376 }
376 }
377
377
378 QList<ChartItem *> ChartPresenter::chartItems() const
378 QList<ChartItem *> ChartPresenter::chartItems() const
379 {
379 {
380 return m_chartItems;
380 return m_chartItems;
381 }
381 }
382
382
383 ChartTitle *ChartPresenter::titleElement()
383 ChartTitle *ChartPresenter::titleElement()
384 {
384 {
385 return m_title;
385 return m_title;
386 }
386 }
387
387
388 QRectF ChartPresenter::textBoundingRect(const QFont &font, const QString &text, qreal angle)
388 QRectF ChartPresenter::textBoundingRect(const QFont &font, const QString &text, qreal angle)
389 {
389 {
390 static QGraphicsTextItem dummyTextItem;
390 static QGraphicsTextItem dummyTextItem;
391 static bool initMargin = true;
391 static bool initMargin = true;
392 if (initMargin) {
392 if (initMargin) {
393 dummyTextItem.document()->setDocumentMargin(textMargin());
393 dummyTextItem.document()->setDocumentMargin(textMargin());
394 initMargin = false;
394 initMargin = false;
395 }
395 }
396
396
397 dummyTextItem.setFont(font);
397 dummyTextItem.setFont(font);
398 dummyTextItem.setHtml(text);
398 dummyTextItem.setHtml(text);
399 QRectF boundingRect = dummyTextItem.boundingRect();
399 QRectF boundingRect = dummyTextItem.boundingRect();
400
400
401 // Take rotation into account
401 // Take rotation into account
402 if (angle) {
402 if (angle) {
403 QTransform transform;
403 QTransform transform;
404 transform.rotate(angle);
404 transform.rotate(angle);
405 boundingRect = transform.mapRect(boundingRect);
405 boundingRect = transform.mapRect(boundingRect);
406 }
406 }
407
407
408 return boundingRect;
408 return boundingRect;
409 }
409 }
410
410
411 // boundingRect parameter returns the rotated bounding rect of the text
411 // boundingRect parameter returns the rotated bounding rect of the text
412 QString ChartPresenter::truncatedText(const QFont &font, const QString &text, qreal angle,
412 QString ChartPresenter::truncatedText(const QFont &font, const QString &text, qreal angle,
413 qreal maxSize, Qt::Orientation constraintOrientation,
413 qreal maxWidth, qreal maxHeight, QRectF &boundingRect)
414 QRectF &boundingRect)
415 {
414 {
416 QString truncatedString(text);
415 QString truncatedString(text);
417 boundingRect = textBoundingRect(font, truncatedString, angle);
416 boundingRect = textBoundingRect(font, truncatedString, angle);
418 qreal checkDimension = ((constraintOrientation == Qt::Horizontal)
417 if (boundingRect.width() > maxWidth || boundingRect.height() > maxHeight) {
419 ? boundingRect.width() : boundingRect.height());
420 if (checkDimension > maxSize) {
421 // It can be assumed that almost any amount of string manipulation is faster
418 // It can be assumed that almost any amount of string manipulation is faster
422 // than calculating one bounding rectangle, so first prepare a list of truncated strings
419 // than calculating one bounding rectangle, so first prepare a list of truncated strings
423 // to try.
420 // to try.
424 static const char *truncateMatchString = "&#?[0-9a-zA-Z]*;$";
421 static const char *truncateMatchString = "&#?[0-9a-zA-Z]*;$";
425 static QRegExp truncateMatcher(truncateMatchString);
422 static QRegExp truncateMatcher(truncateMatchString);
426
423
427 QVector<QString> testStrings(text.length());
424 QVector<QString> testStrings(text.length());
428 int count(0);
425 int count(0);
429 static QLatin1Char closeTag('>');
426 static QLatin1Char closeTag('>');
430 static QLatin1Char openTag('<');
427 static QLatin1Char openTag('<');
431 static QLatin1Char semiColon(';');
428 static QLatin1Char semiColon(';');
432 static QLatin1String ellipsis("...");
429 static QLatin1String ellipsis("...");
433 while (truncatedString.length() > 1) {
430 while (truncatedString.length() > 1) {
434 int chopIndex(-1);
431 int chopIndex(-1);
435 int chopCount(1);
432 int chopCount(1);
436 QChar lastChar(truncatedString.at(truncatedString.length() - 1));
433 QChar lastChar(truncatedString.at(truncatedString.length() - 1));
437
434
438 if (lastChar == closeTag)
435 if (lastChar == closeTag)
439 chopIndex = truncatedString.lastIndexOf(openTag);
436 chopIndex = truncatedString.lastIndexOf(openTag);
440 else if (lastChar == semiColon)
437 else if (lastChar == semiColon)
441 chopIndex = truncateMatcher.indexIn(truncatedString, 0);
438 chopIndex = truncateMatcher.indexIn(truncatedString, 0);
442
439
443 if (chopIndex != -1)
440 if (chopIndex != -1)
444 chopCount = truncatedString.length() - chopIndex;
441 chopCount = truncatedString.length() - chopIndex;
445 truncatedString.chop(chopCount);
442 truncatedString.chop(chopCount);
446 testStrings[count] = truncatedString + ellipsis;
443 testStrings[count] = truncatedString + ellipsis;
447 count++;
444 count++;
448 }
445 }
449
446
450 // Binary search for best fit
447 // Binary search for best fit
451 int minIndex(0);
448 int minIndex(0);
452 int maxIndex(count - 1);
449 int maxIndex(count - 1);
453 int bestIndex(count);
450 int bestIndex(count);
454 QRectF checkRect;
451 QRectF checkRect;
452
455 while (maxIndex >= minIndex) {
453 while (maxIndex >= minIndex) {
456 int mid = (maxIndex + minIndex) / 2;
454 int mid = (maxIndex + minIndex) / 2;
457 checkRect = textBoundingRect(font, testStrings.at(mid), angle);
455 checkRect = textBoundingRect(font, testStrings.at(mid), angle);
458 checkDimension = ((constraintOrientation == Qt::Horizontal)
456 if (checkRect.width() > maxWidth || checkRect.height() > maxHeight) {
459 ? checkRect.width() : checkRect.height());
460 if (checkDimension > maxSize) {
461 // Checked index too large, all under this are also too large
457 // Checked index too large, all under this are also too large
462 minIndex = mid + 1;
458 minIndex = mid + 1;
463 } else {
459 } else {
464 // Checked index fits, all over this also fit
460 // Checked index fits, all over this also fit
465 maxIndex = mid - 1;
461 maxIndex = mid - 1;
466 bestIndex = mid;
462 bestIndex = mid;
467 boundingRect = checkRect;
463 boundingRect = checkRect;
468 }
464 }
469 }
465 }
470 // Default to "..." if nothing fits
466 // Default to "..." if nothing fits
471 if (bestIndex == count) {
467 if (bestIndex == count) {
472 boundingRect = textBoundingRect(font, ellipsis, angle);
468 boundingRect = textBoundingRect(font, ellipsis, angle);
473 truncatedString = ellipsis;
469 truncatedString = ellipsis;
474 } else {
470 } else {
475 truncatedString = testStrings.at(bestIndex);
471 truncatedString = testStrings.at(bestIndex);
476 }
472 }
477 }
473 }
478
474
479 return truncatedString;
475 return truncatedString;
480 }
476 }
481
477
482 #include "moc_chartpresenter_p.cpp"
478 #include "moc_chartpresenter_p.cpp"
483
479
484 QTCOMMERCIALCHART_END_NAMESPACE
480 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,180 +1,180
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2013 Digia Plc
3 ** Copyright (C) 2013 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 **
6 **
7 ** This file is part of the Qt Enterprise Charts Add-on.
7 ** This file is part of the Qt Enterprise Charts Add-on.
8 **
8 **
9 ** $QT_BEGIN_LICENSE$
9 ** $QT_BEGIN_LICENSE$
10 ** Licensees holding valid Qt Enterprise licenses may use this file in
10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 ** accordance with the Qt Enterprise License Agreement provided with the
11 ** accordance with the Qt Enterprise License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.
13 ** a written agreement between you and Digia.
14 **
14 **
15 ** If you have questions regarding the use of this file, please use
15 ** If you have questions regarding the use of this file, please use
16 ** contact form at http://qt.digia.com
16 ** contact form at http://qt.digia.com
17 ** $QT_END_LICENSE$
17 ** $QT_END_LICENSE$
18 **
18 **
19 ****************************************************************************/
19 ****************************************************************************/
20
20
21 // W A R N I N G
21 // W A R N I N G
22 // -------------
22 // -------------
23 //
23 //
24 // This file is not part of the Qt Enterprise Chart API. It exists purely as an
24 // This file is not part of the Qt Enterprise Chart API. It exists purely as an
25 // implementation detail. This header file may change from version to
25 // implementation detail. This header file may change from version to
26 // version without notice, or even be removed.
26 // version without notice, or even be removed.
27 //
27 //
28 // We mean it.
28 // We mean it.
29
29
30 #ifndef CHARTPRESENTER_H
30 #ifndef CHARTPRESENTER_H
31 #define CHARTPRESENTER_H
31 #define CHARTPRESENTER_H
32
32
33 #include "qchartglobal.h"
33 #include "qchartglobal.h"
34 #include "qchart.h" //because of QChart::ChartThemeId
34 #include "qchart.h" //because of QChart::ChartThemeId
35 #include <QRectF>
35 #include <QRectF>
36 #include <QMargins>
36 #include <QMargins>
37
37
38 QTCOMMERCIALCHART_BEGIN_NAMESPACE
38 QTCOMMERCIALCHART_BEGIN_NAMESPACE
39
39
40 class ChartItem;
40 class ChartItem;
41 class AxisItem;
41 class AxisItem;
42 class QAbstractSeries;
42 class QAbstractSeries;
43 class ChartDataSet;
43 class ChartDataSet;
44 class AbstractDomain;
44 class AbstractDomain;
45 class ChartAxisElement;
45 class ChartAxisElement;
46 class ChartAnimator;
46 class ChartAnimator;
47 class ChartBackground;
47 class ChartBackground;
48 class ChartTitle;
48 class ChartTitle;
49 class ChartAnimation;
49 class ChartAnimation;
50 class AbstractChartLayout;
50 class AbstractChartLayout;
51
51
52 class ChartPresenter: public QObject
52 class ChartPresenter: public QObject
53 {
53 {
54 Q_OBJECT
54 Q_OBJECT
55 public:
55 public:
56 enum ZValues {
56 enum ZValues {
57 BackgroundZValue = -1,
57 BackgroundZValue = -1,
58 PlotAreaZValue,
58 PlotAreaZValue,
59 ShadesZValue,
59 ShadesZValue,
60 GridZValue,
60 GridZValue,
61 AxisZValue,
61 AxisZValue,
62 SeriesZValue,
62 SeriesZValue,
63 LineChartZValue = SeriesZValue,
63 LineChartZValue = SeriesZValue,
64 SplineChartZValue = SeriesZValue,
64 SplineChartZValue = SeriesZValue,
65 BarSeriesZValue = SeriesZValue,
65 BarSeriesZValue = SeriesZValue,
66 ScatterSeriesZValue = SeriesZValue,
66 ScatterSeriesZValue = SeriesZValue,
67 PieSeriesZValue = SeriesZValue,
67 PieSeriesZValue = SeriesZValue,
68 BoxPlotSeriesZValue = SeriesZValue,
68 BoxPlotSeriesZValue = SeriesZValue,
69 LegendZValue,
69 LegendZValue,
70 TopMostZValue
70 TopMostZValue
71 };
71 };
72
72
73 enum State {
73 enum State {
74 ShowState,
74 ShowState,
75 ScrollUpState,
75 ScrollUpState,
76 ScrollDownState,
76 ScrollDownState,
77 ScrollLeftState,
77 ScrollLeftState,
78 ScrollRightState,
78 ScrollRightState,
79 ZoomInState,
79 ZoomInState,
80 ZoomOutState
80 ZoomOutState
81 };
81 };
82
82
83 ChartPresenter(QChart *chart, QChart::ChartType type);
83 ChartPresenter(QChart *chart, QChart::ChartType type);
84 virtual ~ChartPresenter();
84 virtual ~ChartPresenter();
85
85
86
86
87 void setGeometry(QRectF rect);
87 void setGeometry(QRectF rect);
88 QRectF geometry() const;
88 QRectF geometry() const;
89
89
90 QGraphicsItem *rootItem(){ return m_chart; }
90 QGraphicsItem *rootItem(){ return m_chart; }
91 ChartBackground *backgroundElement();
91 ChartBackground *backgroundElement();
92 QAbstractGraphicsShapeItem *plotAreaElement();
92 QAbstractGraphicsShapeItem *plotAreaElement();
93 ChartTitle *titleElement();
93 ChartTitle *titleElement();
94 QList<ChartAxisElement *> axisItems() const;
94 QList<ChartAxisElement *> axisItems() const;
95 QList<ChartItem *> chartItems() const;
95 QList<ChartItem *> chartItems() const;
96
96
97 QLegend *legend();
97 QLegend *legend();
98
98
99 void setBackgroundBrush(const QBrush &brush);
99 void setBackgroundBrush(const QBrush &brush);
100 QBrush backgroundBrush() const;
100 QBrush backgroundBrush() const;
101
101
102 void setBackgroundPen(const QPen &pen);
102 void setBackgroundPen(const QPen &pen);
103 QPen backgroundPen() const;
103 QPen backgroundPen() const;
104
104
105 void setBackgroundRoundness(qreal diameter);
105 void setBackgroundRoundness(qreal diameter);
106 qreal backgroundRoundness() const;
106 qreal backgroundRoundness() const;
107
107
108 void setPlotAreaBackgroundBrush(const QBrush &brush);
108 void setPlotAreaBackgroundBrush(const QBrush &brush);
109 QBrush plotAreaBackgroundBrush() const;
109 QBrush plotAreaBackgroundBrush() const;
110
110
111 void setPlotAreaBackgroundPen(const QPen &pen);
111 void setPlotAreaBackgroundPen(const QPen &pen);
112 QPen plotAreaBackgroundPen() const;
112 QPen plotAreaBackgroundPen() const;
113
113
114 void setTitle(const QString &title);
114 void setTitle(const QString &title);
115 QString title() const;
115 QString title() const;
116
116
117 void setTitleFont(const QFont &font);
117 void setTitleFont(const QFont &font);
118 QFont titleFont() const;
118 QFont titleFont() const;
119
119
120 void setTitleBrush(const QBrush &brush);
120 void setTitleBrush(const QBrush &brush);
121 QBrush titleBrush() const;
121 QBrush titleBrush() const;
122
122
123 void setBackgroundVisible(bool visible);
123 void setBackgroundVisible(bool visible);
124 bool isBackgroundVisible() const;
124 bool isBackgroundVisible() const;
125
125
126 void setPlotAreaBackgroundVisible(bool visible);
126 void setPlotAreaBackgroundVisible(bool visible);
127 bool isPlotAreaBackgroundVisible() const;
127 bool isPlotAreaBackgroundVisible() const;
128
128
129 void setBackgroundDropShadowEnabled(bool enabled);
129 void setBackgroundDropShadowEnabled(bool enabled);
130 bool isBackgroundDropShadowEnabled() const;
130 bool isBackgroundDropShadowEnabled() const;
131
131
132 void setVisible(bool visible);
132 void setVisible(bool visible);
133
133
134 void setAnimationOptions(QChart::AnimationOptions options);
134 void setAnimationOptions(QChart::AnimationOptions options);
135 QChart::AnimationOptions animationOptions() const;
135 QChart::AnimationOptions animationOptions() const;
136
136
137 void startAnimation(ChartAnimation *animation);
137 void startAnimation(ChartAnimation *animation);
138
138
139 void setState(State state,QPointF point);
139 void setState(State state,QPointF point);
140 State state() const { return m_state; }
140 State state() const { return m_state; }
141 QPointF statePoint() const { return m_statePoint; }
141 QPointF statePoint() const { return m_statePoint; }
142 AbstractChartLayout *layout();
142 AbstractChartLayout *layout();
143
143
144 QChart::ChartType chartType() const { return m_chart->chartType(); }
144 QChart::ChartType chartType() const { return m_chart->chartType(); }
145 QChart *chart() { return m_chart; }
145 QChart *chart() { return m_chart; }
146
146
147 static QRectF textBoundingRect(const QFont &font, const QString &text, qreal angle = 0.0);
147 static QRectF textBoundingRect(const QFont &font, const QString &text, qreal angle = 0.0);
148 static QString truncatedText(const QFont &font, const QString &text, qreal angle, qreal maxSize,
148 static QString truncatedText(const QFont &font, const QString &text, qreal angle,
149 Qt::Orientation constraintOrientation, QRectF &boundingRect);
149 qreal maxWidth, qreal maxHeight, QRectF &boundingRect);
150 inline static qreal textMargin() { return qreal(0.5); }
150 inline static qreal textMargin() { return qreal(0.5); }
151 private:
151 private:
152 void createBackgroundItem();
152 void createBackgroundItem();
153 void createPlotAreaBackgroundItem();
153 void createPlotAreaBackgroundItem();
154 void createTitleItem();
154 void createTitleItem();
155
155
156 public Q_SLOTS:
156 public Q_SLOTS:
157 void handleSeriesAdded(QAbstractSeries *series);
157 void handleSeriesAdded(QAbstractSeries *series);
158 void handleSeriesRemoved(QAbstractSeries *series);
158 void handleSeriesRemoved(QAbstractSeries *series);
159 void handleAxisAdded(QAbstractAxis *axis);
159 void handleAxisAdded(QAbstractAxis *axis);
160 void handleAxisRemoved(QAbstractAxis *axis);
160 void handleAxisRemoved(QAbstractAxis *axis);
161
161
162 private:
162 private:
163 QChart *m_chart;
163 QChart *m_chart;
164 QList<ChartItem *> m_chartItems;
164 QList<ChartItem *> m_chartItems;
165 QList<ChartAxisElement *> m_axisItems;
165 QList<ChartAxisElement *> m_axisItems;
166 QList<QAbstractSeries *> m_series;
166 QList<QAbstractSeries *> m_series;
167 QList<QAbstractAxis *> m_axes;
167 QList<QAbstractAxis *> m_axes;
168 QChart::AnimationOptions m_options;
168 QChart::AnimationOptions m_options;
169 State m_state;
169 State m_state;
170 QPointF m_statePoint;
170 QPointF m_statePoint;
171 AbstractChartLayout *m_layout;
171 AbstractChartLayout *m_layout;
172 ChartBackground *m_background;
172 ChartBackground *m_background;
173 QAbstractGraphicsShapeItem *m_plotAreaBackground;
173 QAbstractGraphicsShapeItem *m_plotAreaBackground;
174 ChartTitle *m_title;
174 ChartTitle *m_title;
175 QRectF m_rect;
175 QRectF m_rect;
176 };
176 };
177
177
178 QTCOMMERCIALCHART_END_NAMESPACE
178 QTCOMMERCIALCHART_END_NAMESPACE
179
179
180 #endif /* CHARTPRESENTER_H */
180 #endif /* CHARTPRESENTER_H */
@@ -1,88 +1,90
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2013 Digia Plc
3 ** Copyright (C) 2013 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 **
6 **
7 ** This file is part of the Qt Enterprise Charts Add-on.
7 ** This file is part of the Qt Enterprise Charts Add-on.
8 **
8 **
9 ** $QT_BEGIN_LICENSE$
9 ** $QT_BEGIN_LICENSE$
10 ** Licensees holding valid Qt Enterprise licenses may use this file in
10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 ** accordance with the Qt Enterprise License Agreement provided with the
11 ** accordance with the Qt Enterprise License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.
13 ** a written agreement between you and Digia.
14 **
14 **
15 ** If you have questions regarding the use of this file, please use
15 ** If you have questions regarding the use of this file, please use
16 ** contact form at http://qt.digia.com
16 ** contact form at http://qt.digia.com
17 ** $QT_END_LICENSE$
17 ** $QT_END_LICENSE$
18 **
18 **
19 ****************************************************************************/
19 ****************************************************************************/
20
20
21 #include "charttitle_p.h"
21 #include "charttitle_p.h"
22 #include "chartpresenter_p.h"
22 #include "chartpresenter_p.h"
23 #include <QFont>
23 #include <QFont>
24 #include <QFontMetrics>
24 #include <QFontMetrics>
25 #include <QDebug>
25 #include <QDebug>
26 #include <QTextDocument>
26 #include <QTextDocument>
27
27
28 QTCOMMERCIALCHART_BEGIN_NAMESPACE
28 QTCOMMERCIALCHART_BEGIN_NAMESPACE
29
29
30 ChartTitle::ChartTitle(QGraphicsItem *parent)
30 ChartTitle::ChartTitle(QGraphicsItem *parent)
31 : QGraphicsTextItem(parent)
31 : QGraphicsTextItem(parent)
32 {
32 {
33 document()->setDocumentMargin(ChartPresenter::textMargin());
33 document()->setDocumentMargin(ChartPresenter::textMargin());
34 }
34 }
35
35
36 ChartTitle::~ChartTitle()
36 ChartTitle::~ChartTitle()
37 {
37 {
38
38
39 }
39 }
40
40
41 void ChartTitle::setText(const QString &text)
41 void ChartTitle::setText(const QString &text)
42 {
42 {
43 m_text = text;
43 m_text = text;
44 }
44 }
45
45
46 QString ChartTitle::text() const
46 QString ChartTitle::text() const
47 {
47 {
48 return m_text;
48 return m_text;
49 }
49 }
50
50
51 void ChartTitle::setGeometry(const QRectF &rect)
51 void ChartTitle::setGeometry(const QRectF &rect)
52 {
52 {
53 QRectF dummyRect;
53 QRectF dummyRect;
54 QGraphicsTextItem::setHtml(ChartPresenter::truncatedText(font(), m_text, qreal(0.0), rect.width(), Qt::Horizontal, dummyRect));
54 QGraphicsTextItem::setHtml(ChartPresenter::truncatedText(font(), m_text, qreal(0.0),
55 rect.width(), rect.height(),
56 dummyRect));
55 setPos(rect.topLeft());
57 setPos(rect.topLeft());
56 }
58 }
57
59
58
60
59 QSizeF ChartTitle::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
61 QSizeF ChartTitle::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
60 {
62 {
61 Q_UNUSED(constraint);
63 Q_UNUSED(constraint);
62 QSizeF sh;
64 QSizeF sh;
63
65
64 switch (which) {
66 switch (which) {
65 case Qt::MinimumSize: {
67 case Qt::MinimumSize: {
66 QRectF titleRect = ChartPresenter::textBoundingRect(font(), "...");
68 QRectF titleRect = ChartPresenter::textBoundingRect(font(), "...");
67 sh = QSizeF(titleRect.width(), titleRect.height());
69 sh = QSizeF(titleRect.width(), titleRect.height());
68 break;
70 break;
69 }
71 }
70 case Qt::PreferredSize:
72 case Qt::PreferredSize:
71 case Qt::MaximumSize: {
73 case Qt::MaximumSize: {
72 QRectF titleRect = ChartPresenter::textBoundingRect(font(), m_text);
74 QRectF titleRect = ChartPresenter::textBoundingRect(font(), m_text);
73 sh = QSizeF(titleRect.width(), titleRect.height());
75 sh = QSizeF(titleRect.width(), titleRect.height());
74 break;
76 break;
75 }
77 }
76 case Qt::MinimumDescent: {
78 case Qt::MinimumDescent: {
77 QFontMetrics fn(font());
79 QFontMetrics fn(font());
78 sh = QSizeF(0, fn.descent());
80 sh = QSizeF(0, fn.descent());
79 break;
81 break;
80 }
82 }
81 default:
83 default:
82 break;
84 break;
83 }
85 }
84
86
85 return sh;
87 return sh;
86 }
88 }
87
89
88 QTCOMMERCIALCHART_END_NAMESPACE
90 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,189 +1,190
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2013 Digia Plc
3 ** Copyright (C) 2013 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 **
6 **
7 ** This file is part of the Qt Enterprise Charts Add-on.
7 ** This file is part of the Qt Enterprise Charts Add-on.
8 **
8 **
9 ** $QT_BEGIN_LICENSE$
9 ** $QT_BEGIN_LICENSE$
10 ** Licensees holding valid Qt Enterprise licenses may use this file in
10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 ** accordance with the Qt Enterprise License Agreement provided with the
11 ** accordance with the Qt Enterprise License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.
13 ** a written agreement between you and Digia.
14 **
14 **
15 ** If you have questions regarding the use of this file, please use
15 ** If you have questions regarding the use of this file, please use
16 ** contact form at http://qt.digia.com
16 ** contact form at http://qt.digia.com
17 ** $QT_END_LICENSE$
17 ** $QT_END_LICENSE$
18 **
18 **
19 ****************************************************************************/
19 ****************************************************************************/
20
20
21 #include <QPainter>
21 #include <QPainter>
22 #include <QGraphicsSceneEvent>
22 #include <QGraphicsSceneEvent>
23 #include <QGraphicsTextItem>
23 #include <QGraphicsTextItem>
24 #include <QTextDocument>
24 #include <QTextDocument>
25
25
26 #include "qlegend.h"
26 #include "qlegend.h"
27 #include "qlegend_p.h"
27 #include "qlegend_p.h"
28 #include "qlegendmarker.h"
28 #include "qlegendmarker.h"
29 #include "qlegendmarker_p.h"
29 #include "qlegendmarker_p.h"
30 #include "legendmarkeritem_p.h"
30 #include "legendmarkeritem_p.h"
31 #include "chartpresenter_p.h"
31 #include "chartpresenter_p.h"
32
32
33 QTCOMMERCIALCHART_BEGIN_NAMESPACE
33 QTCOMMERCIALCHART_BEGIN_NAMESPACE
34
34
35 LegendMarkerItem::LegendMarkerItem(QLegendMarkerPrivate *marker, QGraphicsObject *parent) :
35 LegendMarkerItem::LegendMarkerItem(QLegendMarkerPrivate *marker, QGraphicsObject *parent) :
36 QGraphicsObject(parent),
36 QGraphicsObject(parent),
37 m_marker(marker),
37 m_marker(marker),
38 m_markerRect(0,0,10.0,10.0),
38 m_markerRect(0,0,10.0,10.0),
39 m_boundingRect(0,0,0,0),
39 m_boundingRect(0,0,0,0),
40 m_textItem(new QGraphicsTextItem(this)),
40 m_textItem(new QGraphicsTextItem(this)),
41 m_rectItem(new QGraphicsRectItem(this)),
41 m_rectItem(new QGraphicsRectItem(this)),
42 m_margin(3),
42 m_margin(3),
43 m_space(4),
43 m_space(4),
44 m_hovering(false),
44 m_hovering(false),
45 m_pressPos(0, 0)
45 m_pressPos(0, 0)
46 {
46 {
47 m_rectItem->setRect(m_markerRect);
47 m_rectItem->setRect(m_markerRect);
48 m_textItem->document()->setDocumentMargin(ChartPresenter::textMargin());
48 m_textItem->document()->setDocumentMargin(ChartPresenter::textMargin());
49 setAcceptHoverEvents(true);
49 setAcceptHoverEvents(true);
50 }
50 }
51
51
52 LegendMarkerItem::~LegendMarkerItem()
52 LegendMarkerItem::~LegendMarkerItem()
53 {
53 {
54 if (m_hovering) {
54 if (m_hovering) {
55 emit m_marker->q_ptr->hovered(false);
55 emit m_marker->q_ptr->hovered(false);
56 }
56 }
57 }
57 }
58
58
59 void LegendMarkerItem::setPen(const QPen &pen)
59 void LegendMarkerItem::setPen(const QPen &pen)
60 {
60 {
61 m_rectItem->setPen(pen);
61 m_rectItem->setPen(pen);
62 }
62 }
63
63
64 QPen LegendMarkerItem::pen() const
64 QPen LegendMarkerItem::pen() const
65 {
65 {
66 return m_rectItem->pen();
66 return m_rectItem->pen();
67 }
67 }
68
68
69 void LegendMarkerItem::setBrush(const QBrush &brush)
69 void LegendMarkerItem::setBrush(const QBrush &brush)
70 {
70 {
71 m_rectItem->setBrush(brush);
71 m_rectItem->setBrush(brush);
72 }
72 }
73
73
74 QBrush LegendMarkerItem::brush() const
74 QBrush LegendMarkerItem::brush() const
75 {
75 {
76 return m_rectItem->brush();
76 return m_rectItem->brush();
77 }
77 }
78
78
79 void LegendMarkerItem::setFont(const QFont &font)
79 void LegendMarkerItem::setFont(const QFont &font)
80 {
80 {
81 m_textItem->setFont(font);
81 m_textItem->setFont(font);
82 QFontMetrics fn(font);
82 QFontMetrics fn(font);
83 m_markerRect = QRectF(0,0,fn.height()/2,fn.height()/2);
83 m_markerRect = QRectF(0,0,fn.height()/2,fn.height()/2);
84 updateGeometry();
84 updateGeometry();
85 }
85 }
86
86
87 QFont LegendMarkerItem::font() const
87 QFont LegendMarkerItem::font() const
88 {
88 {
89 return m_textItem->font();
89 return m_textItem->font();
90 }
90 }
91
91
92 void LegendMarkerItem::setLabel(const QString label)
92 void LegendMarkerItem::setLabel(const QString label)
93 {
93 {
94 m_label = label;
94 m_label = label;
95 updateGeometry();
95 updateGeometry();
96 }
96 }
97
97
98 QString LegendMarkerItem::label() const
98 QString LegendMarkerItem::label() const
99 {
99 {
100 return m_label;
100 return m_label;
101 }
101 }
102
102
103 void LegendMarkerItem::setLabelBrush(const QBrush &brush)
103 void LegendMarkerItem::setLabelBrush(const QBrush &brush)
104 {
104 {
105 m_textItem->setDefaultTextColor(brush.color());
105 m_textItem->setDefaultTextColor(brush.color());
106 }
106 }
107
107
108 QBrush LegendMarkerItem::labelBrush() const
108 QBrush LegendMarkerItem::labelBrush() const
109 {
109 {
110 return QBrush(m_textItem->defaultTextColor());
110 return QBrush(m_textItem->defaultTextColor());
111 }
111 }
112
112
113 void LegendMarkerItem::setGeometry(const QRectF &rect)
113 void LegendMarkerItem::setGeometry(const QRectF &rect)
114 {
114 {
115 qreal width = rect.width();
115 qreal width = rect.width();
116 qreal x = m_margin + m_markerRect.width() + m_space + m_margin;
116 qreal x = m_margin + m_markerRect.width() + m_space + m_margin;
117 QRectF truncatedRect;
117 QRectF truncatedRect;
118
118
119 m_textItem->setHtml(ChartPresenter::truncatedText(m_textItem->font(), m_label, qreal(0.0), width - x, Qt::Horizontal, truncatedRect));
119 m_textItem->setHtml(ChartPresenter::truncatedText(m_textItem->font(), m_label, qreal(0.0),
120 width - x, rect.height(), truncatedRect));
120
121
121 qreal y = qMax(m_markerRect.height() + 2 * m_margin, truncatedRect.height() + 2 * m_margin);
122 qreal y = qMax(m_markerRect.height() + 2 * m_margin, truncatedRect.height() + 2 * m_margin);
122
123
123 const QRectF &textRect = m_textItem->boundingRect();
124 const QRectF &textRect = m_textItem->boundingRect();
124
125
125 m_textItem->setPos(x - m_margin, y / 2 - textRect.height() / 2);
126 m_textItem->setPos(x - m_margin, y / 2 - textRect.height() / 2);
126 m_rectItem->setRect(m_markerRect);
127 m_rectItem->setRect(m_markerRect);
127 // The textMargin adjustments to position are done to make default case rects less blurry with anti-aliasing
128 // The textMargin adjustments to position are done to make default case rects less blurry with anti-aliasing
128 m_rectItem->setPos(m_margin - ChartPresenter::textMargin(), y / 2.0 - m_markerRect.height() / 2.0 + ChartPresenter::textMargin());
129 m_rectItem->setPos(m_margin - ChartPresenter::textMargin(), y / 2.0 - m_markerRect.height() / 2.0 + ChartPresenter::textMargin());
129
130
130 prepareGeometryChange();
131 prepareGeometryChange();
131 m_boundingRect = QRectF(0, 0, x + textRect.width() + m_margin, y);
132 m_boundingRect = QRectF(0, 0, x + textRect.width() + m_margin, y);
132 }
133 }
133
134
134 QRectF LegendMarkerItem::boundingRect() const
135 QRectF LegendMarkerItem::boundingRect() const
135 {
136 {
136 return m_boundingRect;
137 return m_boundingRect;
137 }
138 }
138
139
139 void LegendMarkerItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
140 void LegendMarkerItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
140 {
141 {
141 Q_UNUSED(option)
142 Q_UNUSED(option)
142 Q_UNUSED(widget)
143 Q_UNUSED(widget)
143 Q_UNUSED(painter)
144 Q_UNUSED(painter)
144 }
145 }
145
146
146 QSizeF LegendMarkerItem::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const
147 QSizeF LegendMarkerItem::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const
147 {
148 {
148 Q_UNUSED(constraint)
149 Q_UNUSED(constraint)
149
150
150 QSizeF sh;
151 QSizeF sh;
151
152
152 switch (which) {
153 switch (which) {
153 case Qt::MinimumSize: {
154 case Qt::MinimumSize: {
154 QRectF labelRect = ChartPresenter::textBoundingRect(m_textItem->font(), "...");
155 QRectF labelRect = ChartPresenter::textBoundingRect(m_textItem->font(), "...");
155 sh = QSizeF(labelRect.width() + (2.0 * m_margin) + m_space + m_markerRect.width(),
156 sh = QSizeF(labelRect.width() + (2.0 * m_margin) + m_space + m_markerRect.width(),
156 qMax(m_markerRect.height(), labelRect.height()) + (2.0 * m_margin));
157 qMax(m_markerRect.height(), labelRect.height()) + (2.0 * m_margin));
157 break;
158 break;
158 }
159 }
159 case Qt::PreferredSize: {
160 case Qt::PreferredSize: {
160 QRectF labelRect = ChartPresenter::textBoundingRect(m_textItem->font(), m_label);
161 QRectF labelRect = ChartPresenter::textBoundingRect(m_textItem->font(), m_label);
161 sh = QSizeF(labelRect.width() + (2.0 * m_margin) + m_space + m_markerRect.width(),
162 sh = QSizeF(labelRect.width() + (2.0 * m_margin) + m_space + m_markerRect.width(),
162 qMax(m_markerRect.height(), labelRect.height()) + (2.0 * m_margin));
163 qMax(m_markerRect.height(), labelRect.height()) + (2.0 * m_margin));
163 break;
164 break;
164 }
165 }
165 default:
166 default:
166 break;
167 break;
167 }
168 }
168
169
169 return sh;
170 return sh;
170 }
171 }
171
172
172 void LegendMarkerItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
173 void LegendMarkerItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
173 {
174 {
174 Q_UNUSED(event)
175 Q_UNUSED(event)
175 m_hovering = true;
176 m_hovering = true;
176 emit m_marker->q_ptr->hovered(true);
177 emit m_marker->q_ptr->hovered(true);
177 }
178 }
178
179
179 void LegendMarkerItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
180 void LegendMarkerItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
180 {
181 {
181 Q_UNUSED(event)
182 Q_UNUSED(event)
182 m_hovering = false;
183 m_hovering = false;
183 emit m_marker->q_ptr->hovered(false);
184 emit m_marker->q_ptr->hovered(false);
184 }
185 }
185
186
186
187
187 #include "moc_legendmarkeritem_p.cpp"
188 #include "moc_legendmarkeritem_p.cpp"
188
189
189 QTCOMMERCIALCHART_END_NAMESPACE
190 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,298 +1,300
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2013 Digia Plc
3 ** Copyright (C) 2013 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 **
6 **
7 ** This file is part of the Qt Enterprise Charts Add-on.
7 ** This file is part of the Qt Enterprise Charts Add-on.
8 **
8 **
9 ** $QT_BEGIN_LICENSE$
9 ** $QT_BEGIN_LICENSE$
10 ** Licensees holding valid Qt Enterprise licenses may use this file in
10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 ** accordance with the Qt Enterprise License Agreement provided with the
11 ** accordance with the Qt Enterprise License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.
13 ** a written agreement between you and Digia.
14 **
14 **
15 ** If you have questions regarding the use of this file, please use
15 ** If you have questions regarding the use of this file, please use
16 ** contact form at http://qt.digia.com
16 ** contact form at http://qt.digia.com
17 ** $QT_END_LICENSE$
17 ** $QT_END_LICENSE$
18 **
18 **
19 ****************************************************************************/
19 ****************************************************************************/
20
20
21 #include "piesliceitem_p.h"
21 #include "piesliceitem_p.h"
22 #include "piechartitem_p.h"
22 #include "piechartitem_p.h"
23 #include "qpieseries.h"
23 #include "qpieseries.h"
24 #include "qpieslice.h"
24 #include "qpieslice.h"
25 #include "chartpresenter_p.h"
25 #include "chartpresenter_p.h"
26 #include <QPainter>
26 #include <QPainter>
27 #include <qmath.h>
27 #include <qmath.h>
28 #include <QGraphicsSceneEvent>
28 #include <QGraphicsSceneEvent>
29 #include <QTime>
29 #include <QTime>
30 #include <QDebug>
30 #include <QDebug>
31
31
32 QTCOMMERCIALCHART_BEGIN_NAMESPACE
32 QTCOMMERCIALCHART_BEGIN_NAMESPACE
33
33
34 QPointF offset(qreal angle, qreal length)
34 QPointF offset(qreal angle, qreal length)
35 {
35 {
36 qreal dx = qSin(angle * (M_PI / 180)) * length;
36 qreal dx = qSin(angle * (M_PI / 180)) * length;
37 qreal dy = qCos(angle * (M_PI / 180)) * length;
37 qreal dy = qCos(angle * (M_PI / 180)) * length;
38 return QPointF(dx, -dy);
38 return QPointF(dx, -dy);
39 }
39 }
40
40
41 PieSliceItem::PieSliceItem(QGraphicsItem *parent)
41 PieSliceItem::PieSliceItem(QGraphicsItem *parent)
42 : QGraphicsObject(parent),
42 : QGraphicsObject(parent),
43 m_hovered(false)
43 m_hovered(false)
44 {
44 {
45 setAcceptHoverEvents(true);
45 setAcceptHoverEvents(true);
46 setAcceptedMouseButtons(Qt::MouseButtonMask);
46 setAcceptedMouseButtons(Qt::MouseButtonMask);
47 setZValue(ChartPresenter::PieSeriesZValue);
47 setZValue(ChartPresenter::PieSeriesZValue);
48 }
48 }
49
49
50 PieSliceItem::~PieSliceItem()
50 PieSliceItem::~PieSliceItem()
51 {
51 {
52 // If user is hovering over the slice and it gets destroyed we do
52 // If user is hovering over the slice and it gets destroyed we do
53 // not get a hover leave event. So we must emit the signal here.
53 // not get a hover leave event. So we must emit the signal here.
54 if (m_hovered)
54 if (m_hovered)
55 emit hovered(false);
55 emit hovered(false);
56 }
56 }
57
57
58 QRectF PieSliceItem::boundingRect() const
58 QRectF PieSliceItem::boundingRect() const
59 {
59 {
60 return m_boundingRect;
60 return m_boundingRect;
61 }
61 }
62
62
63 QPainterPath PieSliceItem::shape() const
63 QPainterPath PieSliceItem::shape() const
64 {
64 {
65 // Don't include the label and label arm.
65 // Don't include the label and label arm.
66 // This is used to detect a mouse clicks. We do not want clicks from label.
66 // This is used to detect a mouse clicks. We do not want clicks from label.
67 return m_slicePath;
67 return m_slicePath;
68 }
68 }
69
69
70 void PieSliceItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
70 void PieSliceItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
71 {
71 {
72 painter->save();
72 painter->save();
73 painter->setClipRect(parentItem()->boundingRect());
73 painter->setClipRect(parentItem()->boundingRect());
74 painter->setPen(m_data.m_slicePen);
74 painter->setPen(m_data.m_slicePen);
75 painter->setBrush(m_data.m_sliceBrush);
75 painter->setBrush(m_data.m_sliceBrush);
76 painter->drawPath(m_slicePath);
76 painter->drawPath(m_slicePath);
77 painter->restore();
77 painter->restore();
78
78
79 if (m_data.m_isLabelVisible) {
79 if (m_data.m_isLabelVisible) {
80 painter->save();
80 painter->save();
81
81
82 // Pen for label arm not defined in the QPieSeries api, let's use brush's color instead
82 // Pen for label arm not defined in the QPieSeries api, let's use brush's color instead
83 // Also, the drawText actually uses the pen color for the text color (unlike QGraphicsSimpleTextItem)
83 // Also, the drawText actually uses the pen color for the text color (unlike QGraphicsSimpleTextItem)
84 painter->setPen(m_data.m_labelBrush.color());
84 painter->setPen(m_data.m_labelBrush.color());
85 painter->setBrush(m_data.m_labelBrush);
85 painter->setBrush(m_data.m_labelBrush);
86 painter->setFont(m_data.m_labelFont);
86 painter->setFont(m_data.m_labelFont);
87
87
88 QFontMetricsF fm(m_data.m_labelFont);
88 QFontMetricsF fm(m_data.m_labelFont);
89 QString label = m_data.m_labelText;
89 QString label = m_data.m_labelText;
90 QRectF labelBoundingRect;
90 QRectF labelBoundingRect;
91
91
92 switch (m_data.m_labelPosition) {
92 switch (m_data.m_labelPosition) {
93 case QPieSlice::LabelOutside:
93 case QPieSlice::LabelOutside:
94 painter->setClipRect(parentItem()->boundingRect());
94 painter->setClipRect(parentItem()->boundingRect());
95 painter->strokePath(m_labelArmPath, m_data.m_labelBrush.color());
95 painter->strokePath(m_labelArmPath, m_data.m_labelBrush.color());
96 if (fm.width(m_data.m_labelText) > m_labelTextRect.width()) {
96 if (fm.width(m_data.m_labelText) > m_labelTextRect.width()) {
97 // Only one line label text is supported currently.
98 // The height for the label is set one pixel over the font metrics.
97 label = ChartPresenter::truncatedText(m_data.m_labelFont, m_data.m_labelText,
99 label = ChartPresenter::truncatedText(m_data.m_labelFont, m_data.m_labelText,
98 qreal(0.0), m_labelTextRect.width(),
100 qreal(0.0), m_labelTextRect.width(),
99 Qt::Horizontal, labelBoundingRect);
101 fm.height() + 1.0, labelBoundingRect);
100 }
102 }
101 painter->drawText(m_labelTextRect, Qt::AlignCenter, label);
103 painter->drawText(m_labelTextRect, Qt::AlignCenter, label);
102 break;
104 break;
103 case QPieSlice::LabelInsideHorizontal:
105 case QPieSlice::LabelInsideHorizontal:
104 painter->setClipPath(m_slicePath);
106 painter->setClipPath(m_slicePath);
105 painter->drawText(m_labelTextRect, Qt::AlignCenter, m_data.m_labelText);
107 painter->drawText(m_labelTextRect, Qt::AlignCenter, m_data.m_labelText);
106 break;
108 break;
107 case QPieSlice::LabelInsideTangential:
109 case QPieSlice::LabelInsideTangential:
108 painter->setClipPath(m_slicePath);
110 painter->setClipPath(m_slicePath);
109 painter->translate(m_labelTextRect.center());
111 painter->translate(m_labelTextRect.center());
110 painter->rotate(m_data.m_startAngle + m_data.m_angleSpan / 2);
112 painter->rotate(m_data.m_startAngle + m_data.m_angleSpan / 2);
111 painter->drawText(-m_labelTextRect.width() / 2, -m_labelTextRect.height() / 2, m_labelTextRect.width(), m_labelTextRect.height(), Qt::AlignCenter, m_data.m_labelText);
113 painter->drawText(-m_labelTextRect.width() / 2, -m_labelTextRect.height() / 2, m_labelTextRect.width(), m_labelTextRect.height(), Qt::AlignCenter, m_data.m_labelText);
112 break;
114 break;
113 case QPieSlice::LabelInsideNormal:
115 case QPieSlice::LabelInsideNormal:
114 painter->setClipPath(m_slicePath);
116 painter->setClipPath(m_slicePath);
115 painter->translate(m_labelTextRect.center());
117 painter->translate(m_labelTextRect.center());
116 if (m_data.m_startAngle + m_data.m_angleSpan / 2 < 180)
118 if (m_data.m_startAngle + m_data.m_angleSpan / 2 < 180)
117 painter->rotate(m_data.m_startAngle + m_data.m_angleSpan / 2 - 90);
119 painter->rotate(m_data.m_startAngle + m_data.m_angleSpan / 2 - 90);
118 else
120 else
119 painter->rotate(m_data.m_startAngle + m_data.m_angleSpan / 2 + 90);
121 painter->rotate(m_data.m_startAngle + m_data.m_angleSpan / 2 + 90);
120 painter->drawText(-m_labelTextRect.width() / 2, -m_labelTextRect.height() / 2, m_labelTextRect.width(), m_labelTextRect.height(), Qt::AlignCenter, m_data.m_labelText);
122 painter->drawText(-m_labelTextRect.width() / 2, -m_labelTextRect.height() / 2, m_labelTextRect.width(), m_labelTextRect.height(), Qt::AlignCenter, m_data.m_labelText);
121 break;
123 break;
122 }
124 }
123
125
124 painter->restore();
126 painter->restore();
125 }
127 }
126 }
128 }
127
129
128 void PieSliceItem::hoverEnterEvent(QGraphicsSceneHoverEvent * /*event*/)
130 void PieSliceItem::hoverEnterEvent(QGraphicsSceneHoverEvent * /*event*/)
129 {
131 {
130 m_hovered = true;
132 m_hovered = true;
131 emit hovered(true);
133 emit hovered(true);
132 }
134 }
133
135
134 void PieSliceItem::hoverLeaveEvent(QGraphicsSceneHoverEvent * /*event*/)
136 void PieSliceItem::hoverLeaveEvent(QGraphicsSceneHoverEvent * /*event*/)
135 {
137 {
136 m_hovered = false;
138 m_hovered = false;
137 emit hovered(false);
139 emit hovered(false);
138 }
140 }
139
141
140 void PieSliceItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
142 void PieSliceItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
141 {
143 {
142 emit clicked(event->buttons());
144 emit clicked(event->buttons());
143 QGraphicsItem::mousePressEvent(event);
145 QGraphicsItem::mousePressEvent(event);
144 }
146 }
145
147
146 void PieSliceItem::setLayout(const PieSliceData &sliceData)
148 void PieSliceItem::setLayout(const PieSliceData &sliceData)
147 {
149 {
148 m_data = sliceData;
150 m_data = sliceData;
149 updateGeometry();
151 updateGeometry();
150 update();
152 update();
151 }
153 }
152
154
153 void PieSliceItem::updateGeometry()
155 void PieSliceItem::updateGeometry()
154 {
156 {
155 if (m_data.m_radius <= 0)
157 if (m_data.m_radius <= 0)
156 return;
158 return;
157
159
158 prepareGeometryChange();
160 prepareGeometryChange();
159
161
160 // slice path
162 // slice path
161 qreal centerAngle;
163 qreal centerAngle;
162 QPointF armStart;
164 QPointF armStart;
163 m_slicePath = slicePath(m_data.m_center, m_data.m_radius, m_data.m_startAngle, m_data.m_angleSpan, &centerAngle, &armStart);
165 m_slicePath = slicePath(m_data.m_center, m_data.m_radius, m_data.m_startAngle, m_data.m_angleSpan, &centerAngle, &armStart);
164
166
165 // text rect
167 // text rect
166 QFontMetricsF fm(m_data.m_labelFont);
168 QFontMetricsF fm(m_data.m_labelFont);
167 m_labelTextRect = QRectF(0, 0, fm.width(m_data.m_labelText), fm.height());
169 m_labelTextRect = QRectF(0, 0, fm.width(m_data.m_labelText), fm.height());
168
170
169 // label arm path
171 // label arm path
170 QPointF labelTextStart;
172 QPointF labelTextStart;
171 m_labelArmPath = labelArmPath(armStart, centerAngle, m_data.m_radius * m_data.m_labelArmLengthFactor, m_labelTextRect.width(), &labelTextStart);
173 m_labelArmPath = labelArmPath(armStart, centerAngle, m_data.m_radius * m_data.m_labelArmLengthFactor, m_labelTextRect.width(), &labelTextStart);
172
174
173 // text position
175 // text position
174 switch (m_data.m_labelPosition) {
176 switch (m_data.m_labelPosition) {
175 case QPieSlice::LabelOutside:
177 case QPieSlice::LabelOutside:
176 m_labelTextRect.moveBottomLeft(labelTextStart);
178 m_labelTextRect.moveBottomLeft(labelTextStart);
177 if (m_labelTextRect.left() < 0)
179 if (m_labelTextRect.left() < 0)
178 m_labelTextRect.setLeft(0);
180 m_labelTextRect.setLeft(0);
179 if (m_labelTextRect.right() > parentItem()->boundingRect().right())
181 if (m_labelTextRect.right() > parentItem()->boundingRect().right())
180 m_labelTextRect.setRight(parentItem()->boundingRect().right());
182 m_labelTextRect.setRight(parentItem()->boundingRect().right());
181 break;
183 break;
182 case QPieSlice::LabelInsideHorizontal:
184 case QPieSlice::LabelInsideHorizontal:
183 case QPieSlice::LabelInsideTangential: {
185 case QPieSlice::LabelInsideTangential: {
184 QPointF textCenter;
186 QPointF textCenter;
185 if (m_data.m_holeRadius > 0)
187 if (m_data.m_holeRadius > 0)
186 textCenter = m_data.m_center + offset(centerAngle, m_data.m_holeRadius + (m_data.m_radius - m_data.m_holeRadius) / 2);
188 textCenter = m_data.m_center + offset(centerAngle, m_data.m_holeRadius + (m_data.m_radius - m_data.m_holeRadius) / 2);
187 else
189 else
188 textCenter = m_data.m_center + offset(centerAngle, m_data.m_radius / 2);
190 textCenter = m_data.m_center + offset(centerAngle, m_data.m_radius / 2);
189 m_labelTextRect.moveCenter(textCenter);
191 m_labelTextRect.moveCenter(textCenter);
190 break;
192 break;
191 }
193 }
192 case QPieSlice::LabelInsideNormal: {
194 case QPieSlice::LabelInsideNormal: {
193 QPointF textCenter;
195 QPointF textCenter;
194 if (m_data.m_holeRadius > 0)
196 if (m_data.m_holeRadius > 0)
195 textCenter = m_data.m_center + offset(centerAngle, m_data.m_holeRadius + (m_data.m_radius - m_data.m_holeRadius) / 2);
197 textCenter = m_data.m_center + offset(centerAngle, m_data.m_holeRadius + (m_data.m_radius - m_data.m_holeRadius) / 2);
196 else
198 else
197 textCenter = m_data.m_center + offset(centerAngle, m_data.m_radius / 2);
199 textCenter = m_data.m_center + offset(centerAngle, m_data.m_radius / 2);
198 m_labelTextRect.moveCenter(textCenter);
200 m_labelTextRect.moveCenter(textCenter);
199 break;
201 break;
200 }
202 }
201 }
203 }
202
204
203 // bounding rect
205 // bounding rect
204 if (m_data.m_isLabelVisible)
206 if (m_data.m_isLabelVisible)
205 m_boundingRect = m_slicePath.boundingRect().united(m_labelArmPath.boundingRect()).united(m_labelTextRect);
207 m_boundingRect = m_slicePath.boundingRect().united(m_labelArmPath.boundingRect()).united(m_labelTextRect);
206 else
208 else
207 m_boundingRect = m_slicePath.boundingRect();
209 m_boundingRect = m_slicePath.boundingRect();
208
210
209 // Inflate bounding rect by 2/3 pen width to make sure it encompasses whole slice also for thick pens
211 // Inflate bounding rect by 2/3 pen width to make sure it encompasses whole slice also for thick pens
210 // and miter joins.
212 // and miter joins.
211 int penWidth = (m_data.m_slicePen.width() * 2) / 3;
213 int penWidth = (m_data.m_slicePen.width() * 2) / 3;
212 m_boundingRect = m_boundingRect.adjusted(-penWidth, -penWidth, penWidth, penWidth);
214 m_boundingRect = m_boundingRect.adjusted(-penWidth, -penWidth, penWidth, penWidth);
213 }
215 }
214
216
215 QPointF PieSliceItem::sliceCenter(QPointF point, qreal radius, QPieSlice *slice)
217 QPointF PieSliceItem::sliceCenter(QPointF point, qreal radius, QPieSlice *slice)
216 {
218 {
217 if (slice->isExploded()) {
219 if (slice->isExploded()) {
218 qreal centerAngle = slice->startAngle() + (slice->angleSpan() / 2);
220 qreal centerAngle = slice->startAngle() + (slice->angleSpan() / 2);
219 qreal len = radius * slice->explodeDistanceFactor();
221 qreal len = radius * slice->explodeDistanceFactor();
220 point += offset(centerAngle, len);
222 point += offset(centerAngle, len);
221 }
223 }
222 return point;
224 return point;
223 }
225 }
224
226
225 QPainterPath PieSliceItem::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal *centerAngle, QPointF *armStart)
227 QPainterPath PieSliceItem::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal *centerAngle, QPointF *armStart)
226 {
228 {
227 // calculate center angle
229 // calculate center angle
228 *centerAngle = startAngle + (angleSpan / 2);
230 *centerAngle = startAngle + (angleSpan / 2);
229
231
230 // calculate slice rectangle
232 // calculate slice rectangle
231 QRectF rect(center.x() - radius, center.y() - radius, radius * 2, radius * 2);
233 QRectF rect(center.x() - radius, center.y() - radius, radius * 2, radius * 2);
232
234
233 // slice path
235 // slice path
234 QPainterPath path;
236 QPainterPath path;
235 if (m_data.m_holeRadius > 0) {
237 if (m_data.m_holeRadius > 0) {
236 QRectF insideRect(center.x() - m_data.m_holeRadius, center.y() - m_data.m_holeRadius, m_data.m_holeRadius * 2, m_data.m_holeRadius * 2);
238 QRectF insideRect(center.x() - m_data.m_holeRadius, center.y() - m_data.m_holeRadius, m_data.m_holeRadius * 2, m_data.m_holeRadius * 2);
237 path.arcMoveTo(rect, -startAngle + 90);
239 path.arcMoveTo(rect, -startAngle + 90);
238 path.arcTo(rect, -startAngle + 90, -angleSpan);
240 path.arcTo(rect, -startAngle + 90, -angleSpan);
239 path.arcTo(insideRect, -startAngle + 90 - angleSpan, angleSpan);
241 path.arcTo(insideRect, -startAngle + 90 - angleSpan, angleSpan);
240 path.closeSubpath();
242 path.closeSubpath();
241 } else {
243 } else {
242 path.moveTo(rect.center());
244 path.moveTo(rect.center());
243 path.arcTo(rect, -startAngle + 90, -angleSpan);
245 path.arcTo(rect, -startAngle + 90, -angleSpan);
244 path.closeSubpath();
246 path.closeSubpath();
245 }
247 }
246
248
247 // calculate label arm start point
249 // calculate label arm start point
248 *armStart = center;
250 *armStart = center;
249 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
251 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
250
252
251 return path;
253 return path;
252 }
254 }
253
255
254 QPainterPath PieSliceItem::labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF *textStart)
256 QPainterPath PieSliceItem::labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF *textStart)
255 {
257 {
256 // Normalize the angle to 0-360 range
258 // Normalize the angle to 0-360 range
257 // NOTE: We are using int here on purpose. Depenging on platform and hardware
259 // NOTE: We are using int here on purpose. Depenging on platform and hardware
258 // qreal can be a double, float or something the user gives to the Qt configure
260 // qreal can be a double, float or something the user gives to the Qt configure
259 // (QT_COORD_TYPE). Compilers do not seem to support modulo for double or float
261 // (QT_COORD_TYPE). Compilers do not seem to support modulo for double or float
260 // but there are fmod() and fmodf() functions for that. So instead of some #ifdef
262 // but there are fmod() and fmodf() functions for that. So instead of some #ifdef
261 // that might break we just use int. Precision for this is just fine for our needs.
263 // that might break we just use int. Precision for this is just fine for our needs.
262 int normalized = angle * 10.0;
264 int normalized = angle * 10.0;
263 normalized = normalized % 3600;
265 normalized = normalized % 3600;
264 if (normalized < 0)
266 if (normalized < 0)
265 normalized += 3600;
267 normalized += 3600;
266 angle = (qreal) normalized / 10.0;
268 angle = (qreal) normalized / 10.0;
267
269
268 // prevent label arm pointing straight down because it will look bad
270 // prevent label arm pointing straight down because it will look bad
269 if (angle < 180 && angle > 170)
271 if (angle < 180 && angle > 170)
270 angle = 170;
272 angle = 170;
271 if (angle > 180 && angle < 190)
273 if (angle > 180 && angle < 190)
272 angle = 190;
274 angle = 190;
273
275
274 // line from slice to label
276 // line from slice to label
275 QPointF parm1 = start + offset(angle, length);
277 QPointF parm1 = start + offset(angle, length);
276
278
277 // line to underline the label
279 // line to underline the label
278 QPointF parm2 = parm1;
280 QPointF parm2 = parm1;
279 if (angle < 180) { // arm swings the other way on the left side
281 if (angle < 180) { // arm swings the other way on the left side
280 parm2 += QPointF(textWidth, 0);
282 parm2 += QPointF(textWidth, 0);
281 *textStart = parm1;
283 *textStart = parm1;
282 } else {
284 } else {
283 parm2 += QPointF(-textWidth, 0);
285 parm2 += QPointF(-textWidth, 0);
284 *textStart = parm2;
286 *textStart = parm2;
285 }
287 }
286
288
287 QPainterPath path;
289 QPainterPath path;
288 path.moveTo(start);
290 path.moveTo(start);
289 path.lineTo(parm1);
291 path.lineTo(parm1);
290 path.lineTo(parm2);
292 path.lineTo(parm2);
291
293
292 return path;
294 return path;
293 }
295 }
294
296
295 #include "moc_piesliceitem_p.cpp"
297 #include "moc_piesliceitem_p.cpp"
296
298
297 QTCOMMERCIALCHART_END_NAMESPACE
299 QTCOMMERCIALCHART_END_NAMESPACE
298
300
General Comments 0
You need to be logged in to leave comments. Login now