##// END OF EJS Templates
Fix multiline alignment...
Titta Heikkala -
r2607:dfd05e587e31
parent child
Show More
@@ -1,219 +1,224
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2013 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Enterprise Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 11 ** accordance with the Qt Enterprise License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "horizontalaxis_p.h"
22 22 #include "qabstractaxis_p.h"
23 23 #include "chartpresenter_p.h"
24 24 #include <qmath.h>
25 25 #include <QDebug>
26 26
27 27 QTCOMMERCIALCHART_BEGIN_NAMESPACE
28 28
29 29 HorizontalAxis::HorizontalAxis(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
30 30 : CartesianChartAxis(axis, item, intervalAxis)
31 31 {
32 32 }
33 33
34 34 HorizontalAxis::~HorizontalAxis()
35 35 {
36 36 }
37 37
38 38 void HorizontalAxis::updateGeometry()
39 39 {
40 40 const QVector<qreal> &layout = ChartAxisElement::layout();
41 41
42 42 if (layout.isEmpty())
43 43 return;
44 44
45 45 QStringList labelList = labels();
46 46
47 47 QList<QGraphicsItem *> lines = gridItems();
48 48 QList<QGraphicsItem *> labels = labelItems();
49 49 QList<QGraphicsItem *> shades = shadeItems();
50 50 QList<QGraphicsItem *> arrow = arrowItems();
51 51 QGraphicsTextItem *title = titleItem();
52 52
53 53 Q_ASSERT(labels.size() == labelList.size());
54 54 Q_ASSERT(layout.size() == labelList.size());
55 55
56 56 const QRectF &axisRect = axisGeometry();
57 57 const QRectF &gridRect = gridGeometry();
58 58
59 59 //arrow
60 60 QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem *>(arrow.at(0));
61 61
62 62 if (axis()->alignment() == Qt::AlignTop)
63 63 arrowItem->setLine(gridRect.left(), axisRect.bottom(), gridRect.right(), axisRect.bottom());
64 64 else if (axis()->alignment() == Qt::AlignBottom)
65 65 arrowItem->setLine(gridRect.left(), axisRect.top(), gridRect.right(), axisRect.top());
66 66
67 67 qreal width = 0;
68 68
69 69 //title
70 70 QRectF titleBoundingRect;
71 71 QString titleText = axis()->titleText();
72 72 qreal availableSpace = axisRect.height() - labelPadding();
73 73 if (!titleText.isEmpty() && titleItem()->isVisible()) {
74 74 availableSpace -= titlePadding() * 2.0;
75 75 qreal minimumLabelHeight = ChartPresenter::textBoundingRect(axis()->labelsFont(), "...").height();
76 76 qreal titleSpace = availableSpace - minimumLabelHeight;
77 77 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0),
78 78 gridRect.width(), titleSpace,
79 79 titleBoundingRect));
80 title->setTextWidth(titleBoundingRect.width());
80 81
81 82 titleBoundingRect = title->boundingRect();
82 83
83 84 QPointF center = gridRect.center() - titleBoundingRect.center();
84 85 if (axis()->alignment() == Qt::AlignTop)
85 86 title->setPos(center.x(), axisRect.top() + titlePadding());
86 87 else if (axis()->alignment() == Qt::AlignBottom)
87 88 title->setPos(center.x(), axisRect.bottom() - titleBoundingRect.height() - titlePadding());
88 89
89 90 availableSpace -= titleBoundingRect.height();
90 91 }
91 92
92 93 for (int i = 0; i < layout.size(); ++i) {
93 94 //items
94 95 QGraphicsLineItem *gridItem = static_cast<QGraphicsLineItem*>(lines.at(i));
95 96 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem*>(arrow.at(i + 1));
96 97 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labels.at(i));
97 98
98 99 //grid line
99 100 gridItem->setLine(layout[i], gridRect.top(), layout[i], gridRect.bottom());
100 101
101 102 //label text wrapping
102 103 QString text = labelList.at(i);
103 104 QRectF boundingRect;
104 105 // don't truncate empty labels
105 106 if (text.isEmpty()) {
106 107 labelItem->setHtml(text);
107 108 } else {
108 109 qreal labelWidth = axisRect.width() / layout.count() - (2 * labelPadding());
109 labelItem->setHtml(ChartPresenter::truncatedText(axis()->labelsFont(), text,
110 axis()->labelsAngle(), labelWidth,
111 availableSpace, boundingRect));
110 QString truncatedText = ChartPresenter::truncatedText(axis()->labelsFont(), text,
111 axis()->labelsAngle(),
112 labelWidth,
113 availableSpace, boundingRect);
114 labelItem->setTextWidth(ChartPresenter::textBoundingRect(axis()->labelsFont(),
115 truncatedText).width());
116 labelItem->setHtml(truncatedText);
112 117 }
113 118
114 119 //label transformation origin point
115 120 const QRectF& rect = labelItem->boundingRect();
116 121 QPointF center = rect.center();
117 122 labelItem->setTransformOriginPoint(center.x(), center.y());
118 123 qreal heightDiff = rect.height() - boundingRect.height();
119 124 qreal widthDiff = rect.width() - boundingRect.width();
120 125
121 126 //ticks and label position
122 127 if (axis()->alignment() == Qt::AlignTop) {
123 128 labelItem->setPos(layout[i] - center.x(), axisRect.bottom() - rect.height() + (heightDiff / 2.0) - labelPadding());
124 129 tickItem->setLine(layout[i], axisRect.bottom(), layout[i], axisRect.bottom() - labelPadding());
125 130 } else if (axis()->alignment() == Qt::AlignBottom) {
126 131 labelItem->setPos(layout[i] - center.x(), axisRect.top() - (heightDiff / 2.0) + labelPadding());
127 132 tickItem->setLine(layout[i], axisRect.top(), layout[i], axisRect.top() + labelPadding());
128 133 }
129 134
130 135 //label in between
131 136 bool forceHide = false;
132 137 if (intervalAxis() && (i + 1) != layout.size()) {
133 138 qreal leftBound = qMax(layout[i], gridRect.left());
134 139 qreal rightBound = qMin(layout[i + 1], gridRect.right());
135 140 const qreal delta = rightBound - leftBound;
136 141 // Hide label in case visible part of the category at the grid edge is too narrow
137 142 if (delta < boundingRect.width()
138 143 && (leftBound == gridRect.left() || rightBound == gridRect.right())
139 144 && !intervalAxis()) {
140 145 forceHide = true;
141 146 } else {
142 147 labelItem->setPos(leftBound + (delta / 2.0) - center.x(), labelItem->pos().y());
143 148 }
144 149 }
145 150 //label overlap detection - compensate one pixel for rounding errors
146 151 if ((labelItem->pos().x() < width || forceHide ||
147 152 (labelItem->pos().x() + (widthDiff / 2.0)) < (axisRect.left() - 1.0) ||
148 153 (labelItem->pos().x() + (widthDiff / 2.0) - 1.0) > axisRect.right())
149 154 && !intervalAxis()) {
150 155 labelItem->setVisible(false);
151 156 } else {
152 157 labelItem->setVisible(true);
153 158 width = boundingRect.width() + labelItem->pos().x();
154 159 }
155 160
156 161 //shades
157 162 if ((i + 1) % 2 && i > 1) {
158 163 QGraphicsRectItem *rectItem = static_cast<QGraphicsRectItem *>(shades.at(i / 2 - 1));
159 164 qreal leftBound = qMax(layout[i - 1], gridRect.left());
160 165 qreal rightBound = qMin(layout[i], gridRect.right());
161 166 rectItem->setRect(leftBound, gridRect.top(), rightBound - leftBound, gridRect.height());
162 167 if (rectItem->rect().width() <= 0.0)
163 168 rectItem->setVisible(false);
164 169 else
165 170 rectItem->setVisible(true);
166 171 }
167 172
168 173 // check if the grid line and the axis tick should be shown
169 174 qreal x = gridItem->line().p1().x();
170 175 if (x < gridRect.left() || x > gridRect.right()) {
171 176 gridItem->setVisible(false);
172 177 tickItem->setVisible(false);
173 178 } else {
174 179 gridItem->setVisible(true);
175 180 tickItem->setVisible(true);
176 181 }
177 182
178 183 }
179 184
180 185 //begin/end grid line in case labels between
181 186 if (intervalAxis()) {
182 187 QGraphicsLineItem *gridLine;
183 188 gridLine = static_cast<QGraphicsLineItem *>(lines.at(layout.size()));
184 189 gridLine->setLine(gridRect.right(), gridRect.top(), gridRect.right(), gridRect.bottom());
185 190 gridLine->setVisible(true);
186 191 gridLine = static_cast<QGraphicsLineItem*>(lines.at(layout.size()+1));
187 192 gridLine->setLine(gridRect.left(), gridRect.top(), gridRect.left(), gridRect.bottom());
188 193 gridLine->setVisible(true);
189 194 }
190 195 }
191 196
192 197 QSizeF HorizontalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
193 198 {
194 199 Q_UNUSED(constraint);
195 200 QSizeF sh(0,0);
196 201
197 202 if (axis()->titleText().isEmpty() || !titleItem()->isVisible())
198 203 return sh;
199 204
200 205 switch (which) {
201 206 case Qt::MinimumSize: {
202 207 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), "...");
203 208 sh = QSizeF(titleRect.width(), titleRect.height() + (titlePadding() * 2.0));
204 209 break;
205 210 }
206 211 case Qt::MaximumSize:
207 212 case Qt::PreferredSize: {
208 213 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText());
209 214 sh = QSizeF(titleRect.width(), titleRect.height() + (titlePadding() * 2.0));
210 215 break;
211 216 }
212 217 default:
213 218 break;
214 219 }
215 220
216 221 return sh;
217 222 }
218 223
219 224 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,427 +1,431
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2013 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Enterprise Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 11 ** accordance with the Qt Enterprise License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "polarchartaxisangular_p.h"
22 22 #include "chartpresenter_p.h"
23 23 #include "abstractchartlayout_p.h"
24 24 #include "qabstractaxis.h"
25 25 #include "qabstractaxis_p.h"
26 26 #include <QDebug>
27 27 #include <qmath.h>
28 28 #include <QTextDocument>
29 29
30 30 QTCOMMERCIALCHART_BEGIN_NAMESPACE
31 31
32 32 PolarChartAxisAngular::PolarChartAxisAngular(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
33 33 : PolarChartAxis(axis, item, intervalAxis)
34 34 {
35 35 }
36 36
37 37 PolarChartAxisAngular::~PolarChartAxisAngular()
38 38 {
39 39 }
40 40
41 41 void PolarChartAxisAngular::updateGeometry()
42 42 {
43 43 QGraphicsLayoutItem::updateGeometry();
44 44
45 45 const QVector<qreal> &layout = this->layout();
46 46 if (layout.isEmpty())
47 47 return;
48 48
49 49 createAxisLabels(layout);
50 50 QStringList labelList = labels();
51 51 QPointF center = axisGeometry().center();
52 52 QList<QGraphicsItem *> arrowItemList = arrowItems();
53 53 QList<QGraphicsItem *> gridItemList = gridItems();
54 54 QList<QGraphicsItem *> labelItemList = labelItems();
55 55 QList<QGraphicsItem *> shadeItemList = shadeItems();
56 56 QGraphicsTextItem *title = titleItem();
57 57
58 58 QGraphicsEllipseItem *axisLine = static_cast<QGraphicsEllipseItem *>(arrowItemList.at(0));
59 59 axisLine->setRect(axisGeometry());
60 60
61 61 qreal radius = axisGeometry().height() / 2.0;
62 62
63 63 QRectF previousLabelRect;
64 64 QRectF firstLabelRect;
65 65
66 66 qreal labelHeight = 0;
67 67
68 68 bool firstShade = true;
69 69 bool nextTickVisible = false;
70 70 if (layout.size())
71 71 nextTickVisible = !(layout.at(0) < 0.0 || layout.at(0) > 360.0);
72 72
73 73 for (int i = 0; i < layout.size(); ++i) {
74 74 qreal angularCoordinate = layout.at(i);
75 75
76 76 QGraphicsLineItem *gridLineItem = static_cast<QGraphicsLineItem *>(gridItemList.at(i));
77 77 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrowItemList.at(i + 1));
78 78 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labelItemList.at(i));
79 79 QGraphicsPathItem *shadeItem = 0;
80 80 if (i == 0)
81 81 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
82 82 else if (i % 2)
83 83 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at((i / 2) + 1));
84 84
85 85 // Ignore ticks outside valid range
86 86 bool currentTickVisible = nextTickVisible;
87 87 if ((i == layout.size() - 1)
88 88 || layout.at(i + 1) < 0.0
89 89 || layout.at(i + 1) > 360.0) {
90 90 nextTickVisible = false;
91 91 } else {
92 92 nextTickVisible = true;
93 93 }
94 94
95 95 qreal labelCoordinate = angularCoordinate;
96 96 qreal labelVisible = currentTickVisible;
97 97 if (intervalAxis()) {
98 98 qreal farEdge;
99 99 if (i == (layout.size() - 1))
100 100 farEdge = 360.0;
101 101 else
102 102 farEdge = qMin(qreal(360.0), layout.at(i + 1));
103 103
104 104 // Adjust the labelCoordinate to show it if next tick is visible
105 105 if (nextTickVisible)
106 106 labelCoordinate = qMax(qreal(0.0), labelCoordinate);
107 107
108 108 labelCoordinate = (labelCoordinate + farEdge) / 2.0;
109 109 // Don't display label once the category gets too small near the axis
110 110 if (labelCoordinate < 5.0 || labelCoordinate > 355.0)
111 111 labelVisible = false;
112 112 else
113 113 labelVisible = true;
114 114 }
115 115
116 116 // Need this also in label calculations, so determine it first
117 117 QLineF tickLine(QLineF::fromPolar(radius - tickWidth(), 90.0 - angularCoordinate).p2(),
118 118 QLineF::fromPolar(radius + tickWidth(), 90.0 - angularCoordinate).p2());
119 119 tickLine.translate(center);
120 120
121 121 // Angular axis label
122 122 if (axis()->labelsVisible() && labelVisible) {
123 QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(),
124 labelList.at(i),
125 axis()->labelsAngle());
126 labelItem->setTextWidth(boundingRect.width());
123 127 labelItem->setHtml(labelList.at(i));
124 128 const QRectF &rect = labelItem->boundingRect();
125 129 QPointF labelCenter = rect.center();
126 130 labelItem->setTransformOriginPoint(labelCenter.x(), labelCenter.y());
127 QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), labelList.at(i), axis()->labelsAngle());
128 131 boundingRect.moveCenter(labelCenter);
129 132 QPointF positionDiff(rect.topLeft() - boundingRect.topLeft());
130 133
131 134 QPointF labelPoint;
132 135 if (intervalAxis()) {
133 136 QLineF labelLine = QLineF::fromPolar(radius + tickWidth(), 90.0 - labelCoordinate);
134 137 labelLine.translate(center);
135 138 labelPoint = labelLine.p2();
136 139 } else {
137 140 labelPoint = tickLine.p2();
138 141 }
139 142
140 143 QRectF labelRect = moveLabelToPosition(labelCoordinate, labelPoint, boundingRect);
141 144 labelItem->setPos(labelRect.topLeft() + positionDiff);
142 145
143 146 // Store height for title calculations
144 147 qreal labelClearance = axisGeometry().top() - labelRect.top();
145 148 labelHeight = qMax(labelHeight, labelClearance);
146 149
147 150 // Label overlap detection
148 151 if (i && (previousLabelRect.intersects(labelRect) || firstLabelRect.intersects(labelRect))) {
149 152 labelVisible = false;
150 153 } else {
151 154 // Store labelRect for future comparison. Some area is deducted to make things look
152 155 // little nicer, as usually intersection happens at label corner with angular labels.
153 156 labelRect.adjust(-2.0, -4.0, -2.0, -4.0);
154 157 if (firstLabelRect.isEmpty())
155 158 firstLabelRect = labelRect;
156 159
157 160 previousLabelRect = labelRect;
158 161 labelVisible = true;
159 162 }
160 163 }
161 164
162 165 labelItem->setVisible(labelVisible);
163 166 if (!currentTickVisible) {
164 167 gridLineItem->setVisible(false);
165 168 tickItem->setVisible(false);
166 169 if (shadeItem)
167 170 shadeItem->setVisible(false);
168 171 continue;
169 172 }
170 173
171 174 // Angular grid line
172 175 QLineF gridLine = QLineF::fromPolar(radius, 90.0 - angularCoordinate);
173 176 gridLine.translate(center);
174 177 gridLineItem->setLine(gridLine);
175 178 gridLineItem->setVisible(true);
176 179
177 180 // Tick
178 181 tickItem->setLine(tickLine);
179 182 tickItem->setVisible(true);
180 183
181 184 // Shades
182 185 if (i % 2 || (i == 0 && !nextTickVisible)) {
183 186 QPainterPath path;
184 187 path.moveTo(center);
185 188 if (i == 0) {
186 189 // If first tick is also the last, we need to custom fill the first partial arc
187 190 // or it won't get filled.
188 191 path.arcTo(axisGeometry(), 90.0 - layout.at(0), layout.at(0));
189 192 path.closeSubpath();
190 193 } else {
191 194 qreal nextCoordinate;
192 195 if (!nextTickVisible) // Last visible tick
193 196 nextCoordinate = 360.0;
194 197 else
195 198 nextCoordinate = layout.at(i + 1);
196 199 qreal arcSpan = angularCoordinate - nextCoordinate;
197 200 path.arcTo(axisGeometry(), 90.0 - angularCoordinate, arcSpan);
198 201 path.closeSubpath();
199 202
200 203 // Add additional arc for first shade item if there is a partial arc to be filled
201 204 if (firstShade) {
202 205 QGraphicsPathItem *specialShadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
203 206 if (layout.at(i - 1) > 0.0) {
204 207 QPainterPath specialPath;
205 208 specialPath.moveTo(center);
206 209 specialPath.arcTo(axisGeometry(), 90.0 - layout.at(i - 1), layout.at(i - 1));
207 210 specialPath.closeSubpath();
208 211 specialShadeItem->setPath(specialPath);
209 212 specialShadeItem->setVisible(true);
210 213 } else {
211 214 specialShadeItem->setVisible(false);
212 215 }
213 216 }
214 217 }
215 218 shadeItem->setPath(path);
216 219 shadeItem->setVisible(true);
217 220 firstShade = false;
218 221 }
219 222 }
220 223
221 224 // Title, centered above the chart
222 225 QString titleText = axis()->titleText();
223 226 if (!titleText.isEmpty() && axis()->isTitleVisible()) {
224 QRectF dummyRect;
227 QRectF truncatedRect;
225 228 qreal availableTitleHeight = axisGeometry().height() - labelPadding() - titlePadding() * 2.0;
226 229 qreal minimumLabelHeight = ChartPresenter::textBoundingRect(axis()->labelsFont(), "...").height();
227 230 availableTitleHeight -= minimumLabelHeight;
228 231 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0),
229 232 axisGeometry().width(), availableTitleHeight,
230 dummyRect));
233 truncatedRect));
234 title->setTextWidth(truncatedRect.width());
231 235
232 236 QRectF titleBoundingRect = title->boundingRect();
233 237 QPointF titleCenter = center - titleBoundingRect.center();
234 238 title->setPos(titleCenter.x(), axisGeometry().top() - titlePadding() * 2.0 - titleBoundingRect.height() - labelHeight);
235 239 }
236 240 }
237 241
238 242 Qt::Orientation PolarChartAxisAngular::orientation() const
239 243 {
240 244 return Qt::Horizontal;
241 245 }
242 246
243 247 void PolarChartAxisAngular::createItems(int count)
244 248 {
245 249 if (arrowItems().count() == 0) {
246 250 // angular axis line
247 251 QGraphicsEllipseItem *arrow = new QGraphicsEllipseItem(presenter()->rootItem());
248 252 arrow->setPen(axis()->linePen());
249 253 arrowGroup()->addToGroup(arrow);
250 254 }
251 255
252 256 for (int i = 0; i < count; ++i) {
253 257 QGraphicsLineItem *arrow = new QGraphicsLineItem(presenter()->rootItem());
254 258 QGraphicsLineItem *grid = new QGraphicsLineItem(presenter()->rootItem());
255 259 QGraphicsTextItem *label = new QGraphicsTextItem(presenter()->rootItem());
256 260 label->document()->setDocumentMargin(ChartPresenter::textMargin());
257 261 QGraphicsTextItem *title = titleItem();
258 262 arrow->setPen(axis()->linePen());
259 263 grid->setPen(axis()->gridLinePen());
260 264 label->setFont(axis()->labelsFont());
261 265 label->setDefaultTextColor(axis()->labelsBrush().color());
262 266 label->setRotation(axis()->labelsAngle());
263 267 title->setFont(axis()->titleFont());
264 268 title->setDefaultTextColor(axis()->titleBrush().color());
265 269 title->setHtml(axis()->titleText());
266 270 arrowGroup()->addToGroup(arrow);
267 271 gridGroup()->addToGroup(grid);
268 272 labelGroup()->addToGroup(label);
269 273 if (gridItems().size() == 1 || (((gridItems().size() + 1) % 2) && gridItems().size() > 0)) {
270 274 QGraphicsPathItem *shade = new QGraphicsPathItem(presenter()->rootItem());
271 275 shade->setPen(axis()->shadesPen());
272 276 shade->setBrush(axis()->shadesBrush());
273 277 shadeGroup()->addToGroup(shade);
274 278 }
275 279 }
276 280 }
277 281
278 282 void PolarChartAxisAngular::handleArrowPenChanged(const QPen &pen)
279 283 {
280 284 bool first = true;
281 285 foreach (QGraphicsItem *item, arrowItems()) {
282 286 if (first) {
283 287 first = false;
284 288 // First arrow item is the outer circle of axis
285 289 static_cast<QGraphicsEllipseItem *>(item)->setPen(pen);
286 290 } else {
287 291 static_cast<QGraphicsLineItem *>(item)->setPen(pen);
288 292 }
289 293 }
290 294 }
291 295
292 296 void PolarChartAxisAngular::handleGridPenChanged(const QPen &pen)
293 297 {
294 298 foreach (QGraphicsItem *item, gridItems())
295 299 static_cast<QGraphicsLineItem *>(item)->setPen(pen);
296 300 }
297 301
298 302 QSizeF PolarChartAxisAngular::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
299 303 {
300 304 Q_UNUSED(which);
301 305 Q_UNUSED(constraint);
302 306 return QSizeF(-1, -1);
303 307 }
304 308
305 309 qreal PolarChartAxisAngular::preferredAxisRadius(const QSizeF &maxSize)
306 310 {
307 311 qreal radius = maxSize.height() / 2.0;
308 312 if (maxSize.width() < maxSize.height())
309 313 radius = maxSize.width() / 2.0;
310 314
311 315 if (axis()->labelsVisible()) {
312 316 QVector<qreal> layout = calculateLayout();
313 317 if (layout.isEmpty())
314 318 return radius;
315 319
316 320 createAxisLabels(layout);
317 321 QStringList labelList = labels();
318 322 QFont font = axis()->labelsFont();
319 323
320 324 QRectF maxRect;
321 325 maxRect.setSize(maxSize);
322 326 maxRect.moveCenter(QPointF(0.0, 0.0));
323 327
324 328 // This is a horrible way to find out the maximum radius for angular axis and its labels.
325 329 // It just increments the radius down until everyhing fits the constraint size.
326 330 // Proper way would be to actually calculate it but this seems to work reasonably fast as it is.
327 331 bool nextTickVisible = false;
328 332 for (int i = 0; i < layout.size(); ) {
329 333 if ((i == layout.size() - 1)
330 334 || layout.at(i + 1) < 0.0
331 335 || layout.at(i + 1) > 360.0) {
332 336 nextTickVisible = false;
333 337 } else {
334 338 nextTickVisible = true;
335 339 }
336 340
337 341 qreal labelCoordinate = layout.at(i);
338 342 qreal labelVisible;
339 343
340 344 if (intervalAxis()) {
341 345 qreal farEdge;
342 346 if (i == (layout.size() - 1))
343 347 farEdge = 360.0;
344 348 else
345 349 farEdge = qMin(qreal(360.0), layout.at(i + 1));
346 350
347 351 // Adjust the labelCoordinate to show it if next tick is visible
348 352 if (nextTickVisible)
349 353 labelCoordinate = qMax(qreal(0.0), labelCoordinate);
350 354
351 355 labelCoordinate = (labelCoordinate + farEdge) / 2.0;
352 356 }
353 357
354 358 if (labelCoordinate < 0.0 || labelCoordinate > 360.0)
355 359 labelVisible = false;
356 360 else
357 361 labelVisible = true;
358 362
359 363 if (!labelVisible) {
360 364 i++;
361 365 continue;
362 366 }
363 367
364 368 QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), labelList.at(i), axis()->labelsAngle());
365 369 QPointF labelPoint = QLineF::fromPolar(radius + tickWidth(), 90.0 - labelCoordinate).p2();
366 370
367 371 boundingRect = moveLabelToPosition(labelCoordinate, labelPoint, boundingRect);
368 372 QRectF intersectRect = maxRect.intersected(boundingRect);
369 373 if (boundingRect.isEmpty() || intersectRect == boundingRect) {
370 374 i++;
371 375 } else {
372 376 qreal reduction(0.0);
373 377 // If there is no intersection, reduce by smallest dimension of label rect to be on the safe side
374 378 if (intersectRect.isEmpty()) {
375 379 reduction = qMin(boundingRect.height(), boundingRect.width());
376 380 } else {
377 381 // Approximate needed radius reduction is the amount label rect exceeds max rect in either dimension.
378 382 // Could be further optimized by figuring out the proper math how to calculate exact needed reduction.
379 383 reduction = qMax(boundingRect.height() - intersectRect.height(),
380 384 boundingRect.width() - intersectRect.width());
381 385 }
382 386 // Typically the approximated reduction is little low, so add one
383 387 radius -= (reduction + 1.0);
384 388
385 389 if (radius < 1.0) // safeguard
386 390 return 1.0;
387 391 }
388 392 }
389 393 }
390 394
391 395 if (!axis()->titleText().isEmpty() && axis()->isTitleVisible()) {
392 396 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText());
393 397
394 398 radius -= titlePadding() + (titleRect.height() / 2.0);
395 399 if (radius < 1.0) // safeguard
396 400 return 1.0;
397 401 }
398 402
399 403 return radius;
400 404 }
401 405
402 406 QRectF PolarChartAxisAngular::moveLabelToPosition(qreal angularCoordinate, QPointF labelPoint, QRectF labelRect) const
403 407 {
404 408 if (angularCoordinate == 0.0)
405 409 labelRect.moveCenter(labelPoint + QPointF(0, -labelRect.height() / 2.0));
406 410 else if (angularCoordinate < 90.0)
407 411 labelRect.moveBottomLeft(labelPoint);
408 412 else if (angularCoordinate == 90.0)
409 413 labelRect.moveCenter(labelPoint + QPointF(labelRect.width() / 2.0 + 2.0, 0)); // +2 so that it does not hit the radial axis
410 414 else if (angularCoordinate < 180.0)
411 415 labelRect.moveTopLeft(labelPoint);
412 416 else if (angularCoordinate == 180.0)
413 417 labelRect.moveCenter(labelPoint + QPointF(0, labelRect.height() / 2.0));
414 418 else if (angularCoordinate < 270.0)
415 419 labelRect.moveTopRight(labelPoint);
416 420 else if (angularCoordinate == 270.0)
417 421 labelRect.moveCenter(labelPoint + QPointF(-labelRect.width() / 2.0 - 2.0, 0)); // -2 so that it does not hit the radial axis
418 422 else if (angularCoordinate < 360.0)
419 423 labelRect.moveBottomRight(labelPoint);
420 424 else
421 425 labelRect.moveCenter(labelPoint + QPointF(0, -labelRect.height() / 2.0));
422 426 return labelRect;
423 427 }
424 428
425 429 #include "moc_polarchartaxisangular_p.cpp"
426 430
427 431 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,292 +1,296
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2013 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Enterprise Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 11 ** accordance with the Qt Enterprise License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "polarchartaxisradial_p.h"
22 22 #include "chartpresenter_p.h"
23 23 #include "abstractchartlayout_p.h"
24 24 #include "qabstractaxis_p.h"
25 25 #include "linearrowitem_p.h"
26 26 #include <QTextDocument>
27 27
28 28 QTCOMMERCIALCHART_BEGIN_NAMESPACE
29 29
30 30 PolarChartAxisRadial::PolarChartAxisRadial(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
31 31 : PolarChartAxis(axis, item, intervalAxis)
32 32 {
33 33 }
34 34
35 35 PolarChartAxisRadial::~PolarChartAxisRadial()
36 36 {
37 37 }
38 38
39 39 void PolarChartAxisRadial::updateGeometry()
40 40 {
41 41 const QVector<qreal> &layout = this->layout();
42 42 if (layout.isEmpty())
43 43 return;
44 44
45 45 createAxisLabels(layout);
46 46 QStringList labelList = labels();
47 47 QPointF center = axisGeometry().center();
48 48 QList<QGraphicsItem *> arrowItemList = arrowItems();
49 49 QList<QGraphicsItem *> gridItemList = gridItems();
50 50 QList<QGraphicsItem *> labelItemList = labelItems();
51 51 QList<QGraphicsItem *> shadeItemList = shadeItems();
52 52 QGraphicsTextItem* title = titleItem();
53 53 qreal radius = axisGeometry().height() / 2.0;
54 54
55 55 QLineF line(center, center + QPointF(0, -radius));
56 56 QGraphicsLineItem *axisLine = static_cast<QGraphicsLineItem *>(arrowItemList.at(0));
57 57 axisLine->setLine(line);
58 58
59 59 QRectF previousLabelRect;
60 60 bool firstShade = true;
61 61 bool nextTickVisible = false;
62 62 if (layout.size())
63 63 nextTickVisible = !(layout.at(0) < 0.0 || layout.at(0) > radius);
64 64
65 65 for (int i = 0; i < layout.size(); ++i) {
66 66 qreal radialCoordinate = layout.at(i);
67 67
68 68 QGraphicsEllipseItem *gridItem = static_cast<QGraphicsEllipseItem *>(gridItemList.at(i));
69 69 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrowItemList.at(i + 1));
70 70 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labelItemList.at(i));
71 71 QGraphicsPathItem *shadeItem = 0;
72 72 if (i == 0)
73 73 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
74 74 else if (i % 2)
75 75 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at((i / 2) + 1));
76 76
77 77 // Ignore ticks outside valid range
78 78 bool currentTickVisible = nextTickVisible;
79 79 if ((i == layout.size() - 1)
80 80 || layout.at(i + 1) < 0.0
81 81 || layout.at(i + 1) > radius) {
82 82 nextTickVisible = false;
83 83 } else {
84 84 nextTickVisible = true;
85 85 }
86 86
87 87 qreal labelCoordinate = radialCoordinate;
88 88 qreal labelVisible = currentTickVisible;
89 89 qreal labelPad = labelPadding() / 2.0;
90 90 if (intervalAxis()) {
91 91 qreal farEdge;
92 92 if (i == (layout.size() - 1))
93 93 farEdge = radius;
94 94 else
95 95 farEdge = qMin(radius, layout.at(i + 1));
96 96
97 97 // Adjust the labelCoordinate to show it if next tick is visible
98 98 if (nextTickVisible)
99 99 labelCoordinate = qMax(qreal(0.0), labelCoordinate);
100 100
101 101 labelCoordinate = (labelCoordinate + farEdge) / 2.0;
102 102 if (labelCoordinate > 0.0 && labelCoordinate < radius)
103 103 labelVisible = true;
104 104 else
105 105 labelVisible = false;
106 106 }
107 107
108 108 // Radial axis label
109 109 if (axis()->labelsVisible() && labelVisible) {
110 QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(),
111 labelList.at(i),
112 axis()->labelsAngle());
113 labelItem->setTextWidth(boundingRect.width());
110 114 labelItem->setHtml(labelList.at(i));
111 115 QRectF labelRect = labelItem->boundingRect();
112 116 QPointF labelCenter = labelRect.center();
113 117 labelItem->setTransformOriginPoint(labelCenter.x(), labelCenter.y());
114 QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), labelList.at(i), axis()->labelsAngle());
115 118 boundingRect.moveCenter(labelCenter);
116 119 QPointF positionDiff(labelRect.topLeft() - boundingRect.topLeft());
117 120 QPointF labelPoint = center;
118 121 if (intervalAxis())
119 122 labelPoint += QPointF(labelPad, -labelCoordinate - (boundingRect.height() / 2.0));
120 123 else
121 124 labelPoint += QPointF(labelPad, labelPad - labelCoordinate);
122 125 labelRect.moveTopLeft(labelPoint);
123 126 labelItem->setPos(labelRect.topLeft() + positionDiff);
124 127
125 128 // Label overlap detection
126 129 labelRect.setSize(boundingRect.size());
127 130 if ((i && previousLabelRect.intersects(labelRect))
128 131 || !axisGeometry().contains(labelRect)) {
129 132 labelVisible = false;
130 133 } else {
131 134 previousLabelRect = labelRect;
132 135 labelVisible = true;
133 136 }
134 137 }
135 138
136 139 labelItem->setVisible(labelVisible);
137 140 if (!currentTickVisible) {
138 141 gridItem->setVisible(false);
139 142 tickItem->setVisible(false);
140 143 if (shadeItem)
141 144 shadeItem->setVisible(false);
142 145 continue;
143 146 }
144 147
145 148 // Radial grid line
146 149 QRectF gridRect;
147 150 gridRect.setWidth(radialCoordinate * 2.0);
148 151 gridRect.setHeight(radialCoordinate * 2.0);
149 152 gridRect.moveCenter(center);
150 153
151 154 gridItem->setRect(gridRect);
152 155 gridItem->setVisible(true);
153 156
154 157 // Tick
155 158 QLineF tickLine(-tickWidth(), 0.0, tickWidth(), 0.0);
156 159 tickLine.translate(center.rx(), gridRect.top());
157 160 tickItem->setLine(tickLine);
158 161 tickItem->setVisible(true);
159 162
160 163 // Shades
161 164 if (i % 2 || (i == 0 && !nextTickVisible)) {
162 165 QPainterPath path;
163 166 if (i == 0) {
164 167 // If first tick is also the last, we need to custom fill the inner circle
165 168 // or it won't get filled.
166 169 QRectF innerCircle(0.0, 0.0, layout.at(0) * 2.0, layout.at(0) * 2.0);
167 170 innerCircle.moveCenter(center);
168 171 path.addEllipse(innerCircle);
169 172 } else {
170 173 QRectF otherGridRect;
171 174 if (!nextTickVisible) { // Last visible tick
172 175 otherGridRect = axisGeometry();
173 176 } else {
174 177 qreal otherGridRectDimension = layout.at(i + 1) * 2.0;
175 178 otherGridRect.setWidth(otherGridRectDimension);
176 179 otherGridRect.setHeight(otherGridRectDimension);
177 180 otherGridRect.moveCenter(center);
178 181 }
179 182 path.addEllipse(gridRect);
180 183 path.addEllipse(otherGridRect);
181 184
182 185 // Add additional shading in first visible shade item if there is a partial tick
183 186 // to be filled at the center (log & category axes)
184 187 if (firstShade) {
185 188 QGraphicsPathItem *specialShadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
186 189 if (layout.at(i - 1) > 0.0) {
187 190 QRectF innerCircle(0.0, 0.0, layout.at(i - 1) * 2.0, layout.at(i - 1) * 2.0);
188 191 innerCircle.moveCenter(center);
189 192 QPainterPath specialPath;
190 193 specialPath.addEllipse(innerCircle);
191 194 specialShadeItem->setPath(specialPath);
192 195 specialShadeItem->setVisible(true);
193 196 } else {
194 197 specialShadeItem->setVisible(false);
195 198 }
196 199 }
197 200 }
198 201 shadeItem->setPath(path);
199 202 shadeItem->setVisible(true);
200 203 firstShade = false;
201 204 }
202 205 }
203 206
204 207 // Title, along the 0 axis
205 208 QString titleText = axis()->titleText();
206 209 if (!titleText.isEmpty() && axis()->isTitleVisible()) {
207 QRectF dummyRect;
210 QRectF truncatedRect;
208 211 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0),
209 radius, radius, dummyRect));
212 radius, radius, truncatedRect));
213 title->setTextWidth(truncatedRect.width());
210 214
211 215 QRectF titleBoundingRect = title->boundingRect();
212 216 QPointF titleCenter = titleBoundingRect.center();
213 217 QPointF arrowCenter = axisLine->boundingRect().center();
214 218 QPointF titleCenterDiff = arrowCenter - titleCenter;
215 219 title->setPos(titleCenterDiff.x() - titlePadding() - (titleBoundingRect.height() / 2.0), titleCenterDiff.y());
216 220 title->setTransformOriginPoint(titleCenter);
217 221 title->setRotation(270.0);
218 222 }
219 223
220 224 QGraphicsLayoutItem::updateGeometry();
221 225 }
222 226
223 227 Qt::Orientation PolarChartAxisRadial::orientation() const
224 228 {
225 229 return Qt::Vertical;
226 230 }
227 231
228 232 void PolarChartAxisRadial::createItems(int count)
229 233 {
230 234 if (arrowItems().count() == 0) {
231 235 // radial axis center line
232 236 QGraphicsLineItem *arrow = new LineArrowItem(this, presenter()->rootItem());
233 237 arrow->setPen(axis()->linePen());
234 238 arrowGroup()->addToGroup(arrow);
235 239 }
236 240
237 241 for (int i = 0; i < count; ++i) {
238 242 QGraphicsLineItem *arrow = new QGraphicsLineItem(presenter()->rootItem());
239 243 QGraphicsEllipseItem *grid = new QGraphicsEllipseItem(presenter()->rootItem());
240 244 QGraphicsTextItem *label = new QGraphicsTextItem(presenter()->rootItem());
241 245 label->document()->setDocumentMargin(ChartPresenter::textMargin());
242 246 QGraphicsTextItem *title = titleItem();
243 247 arrow->setPen(axis()->linePen());
244 248 grid->setPen(axis()->gridLinePen());
245 249 label->setFont(axis()->labelsFont());
246 250 label->setDefaultTextColor(axis()->labelsBrush().color());
247 251 label->setRotation(axis()->labelsAngle());
248 252 title->setFont(axis()->titleFont());
249 253 title->setDefaultTextColor(axis()->titleBrush().color());
250 254 title->setHtml(axis()->titleText());
251 255 arrowGroup()->addToGroup(arrow);
252 256 gridGroup()->addToGroup(grid);
253 257 labelGroup()->addToGroup(label);
254 258 if (gridItems().size() == 1 || (((gridItems().size() + 1) % 2) && gridItems().size() > 0)) {
255 259 QGraphicsPathItem *shade = new QGraphicsPathItem(presenter()->rootItem());
256 260 shade->setPen(axis()->shadesPen());
257 261 shade->setBrush(axis()->shadesBrush());
258 262 shadeGroup()->addToGroup(shade);
259 263 }
260 264 }
261 265 }
262 266
263 267 void PolarChartAxisRadial::handleArrowPenChanged(const QPen &pen)
264 268 {
265 269 foreach (QGraphicsItem *item, arrowItems())
266 270 static_cast<QGraphicsLineItem *>(item)->setPen(pen);
267 271 }
268 272
269 273 void PolarChartAxisRadial::handleGridPenChanged(const QPen &pen)
270 274 {
271 275 foreach (QGraphicsItem *item, gridItems())
272 276 static_cast<QGraphicsEllipseItem *>(item)->setPen(pen);
273 277 }
274 278
275 279 QSizeF PolarChartAxisRadial::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
276 280 {
277 281 Q_UNUSED(which);
278 282 Q_UNUSED(constraint);
279 283 return QSizeF(-1.0, -1.0);
280 284 }
281 285
282 286 qreal PolarChartAxisRadial::preferredAxisRadius(const QSizeF &maxSize)
283 287 {
284 288 qreal radius = maxSize.height() / 2.0;
285 289 if (maxSize.width() < maxSize.height())
286 290 radius = maxSize.width() / 2.0;
287 291 return radius;
288 292 }
289 293
290 294 #include "moc_polarchartaxisradial_p.cpp"
291 295
292 296 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,225 +1,230
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2013 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Enterprise Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 11 ** accordance with the Qt Enterprise License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "verticalaxis_p.h"
22 22 #include "qabstractaxis.h"
23 23 #include "chartpresenter_p.h"
24 24 #include <QDebug>
25 25
26 26 QTCOMMERCIALCHART_BEGIN_NAMESPACE
27 27
28 28 VerticalAxis::VerticalAxis(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
29 29 : CartesianChartAxis(axis, item, intervalAxis)
30 30 {
31 31 }
32 32
33 33 VerticalAxis::~VerticalAxis()
34 34 {
35 35 }
36 36
37 37 void VerticalAxis::updateGeometry()
38 38 {
39 39 const QVector<qreal> &layout = ChartAxisElement::layout();
40 40
41 41 if (layout.isEmpty())
42 42 return;
43 43
44 44 QStringList labelList = labels();
45 45
46 46 QList<QGraphicsItem *> lines = gridItems();
47 47 QList<QGraphicsItem *> labels = labelItems();
48 48 QList<QGraphicsItem *> shades = shadeItems();
49 49 QList<QGraphicsItem *> arrow = arrowItems();
50 50 QGraphicsTextItem *title = titleItem();
51 51
52 52 Q_ASSERT(labels.size() == labelList.size());
53 53 Q_ASSERT(layout.size() == labelList.size());
54 54
55 55 const QRectF &axisRect = axisGeometry();
56 56 const QRectF &gridRect = gridGeometry();
57 57
58 58 qreal height = axisRect.bottom();
59 59
60 60
61 61 //arrow
62 62 QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem*>(arrow.at(0));
63 63
64 64 //arrow position
65 65 if (axis()->alignment() == Qt::AlignLeft)
66 66 arrowItem->setLine(axisRect.right(), gridRect.top(), axisRect.right(), gridRect.bottom());
67 67 else if (axis()->alignment() == Qt::AlignRight)
68 68 arrowItem->setLine(axisRect.left(), gridRect.top(), axisRect.left(), gridRect.bottom());
69 69
70 70 //title
71 71 QRectF titleBoundingRect;
72 72 QString titleText = axis()->titleText();
73 73 qreal availableSpace = axisRect.width() - labelPadding();
74 74 if (!titleText.isEmpty() && titleItem()->isVisible()) {
75 75 availableSpace -= titlePadding() * 2.0;
76 76 qreal minimumLabelWidth = ChartPresenter::textBoundingRect(axis()->labelsFont(), "...").width();
77 77 qreal titleSpace = availableSpace - minimumLabelWidth;
78 78 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(90.0),
79 79 titleSpace, gridRect.height(),
80 80 titleBoundingRect));
81 title->setTextWidth(titleBoundingRect.height());
81 82
82 83 titleBoundingRect = title->boundingRect();
83 84
84 85 QPointF center = gridRect.center() - titleBoundingRect.center();
85 86 if (axis()->alignment() == Qt::AlignLeft)
86 87 title->setPos(axisRect.left() - titleBoundingRect.width() / 2.0 + titleBoundingRect.height() / 2.0 + titlePadding(), center.y());
87 88 else if (axis()->alignment() == Qt::AlignRight)
88 89 title->setPos(axisRect.right() - titleBoundingRect.width() / 2.0 - titleBoundingRect.height() / 2.0 - titlePadding(), center.y());
89 90
90 91 title->setTransformOriginPoint(titleBoundingRect.center());
91 92 title->setRotation(270);
92 93
93 94 availableSpace -= titleBoundingRect.height();
94 95 }
95 96
96 97 for (int i = 0; i < layout.size(); ++i) {
97 98 //items
98 99 QGraphicsLineItem *gridItem = static_cast<QGraphicsLineItem *>(lines.at(i));
99 100 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrow.at(i + 1));
100 101 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labels.at(i));
101 102
102 103 //grid line
103 104 gridItem->setLine(gridRect.left(), layout[i], gridRect.right(), layout[i]);
104 105
105 106 //label text wrapping
106 107 QString text = labelList.at(i);
107 108 QRectF boundingRect;
108 109 // don't truncate empty labels
109 110 if (text.isEmpty()) {
110 111 labelItem->setHtml(text);
111 112 } else {
112 113 qreal labelHeight = (axisRect.height() / layout.count()) - (2 * labelPadding());
113 labelItem->setHtml(ChartPresenter::truncatedText(axis()->labelsFont(), text,
114 axis()->labelsAngle(), availableSpace,
115 labelHeight, boundingRect));
114 QString truncatedText = ChartPresenter::truncatedText(axis()->labelsFont(), text,
115 axis()->labelsAngle(),
116 availableSpace,
117 labelHeight, boundingRect);
118 labelItem->setTextWidth(ChartPresenter::textBoundingRect(axis()->labelsFont(),
119 truncatedText).width());
120 labelItem->setHtml(truncatedText);
116 121 }
117 122
118 123 //label transformation origin point
119 124 const QRectF &rect = labelItem->boundingRect();
120 125 QPointF center = rect.center();
121 126 labelItem->setTransformOriginPoint(center.x(), center.y());
122 127 qreal widthDiff = rect.width() - boundingRect.width();
123 128 qreal heightDiff = rect.height() - boundingRect.height();
124 129
125 130 //ticks and label position
126 131 if (axis()->alignment() == Qt::AlignLeft) {
127 132 labelItem->setPos(axisRect.right() - rect.width() + (widthDiff / 2.0) - labelPadding(), layout[i] - center.y());
128 133 tickItem->setLine(axisRect.right() - labelPadding(), layout[i], axisRect.right(), layout[i]);
129 134 } else if (axis()->alignment() == Qt::AlignRight) {
130 135 labelItem->setPos(axisRect.left() + labelPadding() - (widthDiff / 2.0), layout[i] - center.y());
131 136 tickItem->setLine(axisRect.left(), layout[i], axisRect.left() + labelPadding(), layout[i]);
132 137 }
133 138
134 139 //label in between
135 140 bool forceHide = false;
136 141 if (intervalAxis() && (i + 1) != layout.size()) {
137 142 qreal lowerBound = qMin(layout[i], gridRect.bottom());
138 143 qreal upperBound = qMax(layout[i + 1], gridRect.top());
139 144 const qreal delta = lowerBound - upperBound;
140 145 // Hide label in case visible part of the category at the grid edge is too narrow
141 146 if (delta < boundingRect.height()
142 147 && (lowerBound == gridRect.bottom() || upperBound == gridRect.top())
143 148 && !intervalAxis()) {
144 149 forceHide = true;
145 150 } else {
146 151 labelItem->setPos(labelItem->pos().x() , lowerBound - (delta / 2.0) - center.y());
147 152 }
148 153 }
149 154
150 155 //label overlap detection - compensate one pixel for rounding errors
151 156 if ((labelItem->pos().y() + boundingRect.height() > height || forceHide ||
152 157 (labelItem->pos().y() + (heightDiff / 2.0) - 1.0) > axisRect.bottom() ||
153 158 labelItem->pos().y() + (heightDiff / 2.0) < (axisRect.top() - 1.0))
154 159 && !intervalAxis()) {
155 160 labelItem->setVisible(false);
156 161 }
157 162 else {
158 163 labelItem->setVisible(true);
159 164 height=labelItem->pos().y();
160 165 }
161 166
162 167 //shades
163 168 if ((i + 1) % 2 && i > 1) {
164 169 QGraphicsRectItem *rectItem = static_cast<QGraphicsRectItem *>(shades.at(i / 2 - 1));
165 170 qreal lowerBound = qMin(layout[i - 1], gridRect.bottom());
166 171 qreal upperBound = qMax(layout[i], gridRect.top());
167 172 rectItem->setRect(gridRect.left(), upperBound, gridRect.width(), lowerBound - upperBound);
168 173 if (rectItem->rect().height() <= 0.0)
169 174 rectItem->setVisible(false);
170 175 else
171 176 rectItem->setVisible(true);
172 177 }
173 178
174 179 // check if the grid line and the axis tick should be shown
175 180 qreal y = gridItem->line().p1().y();
176 181 if ((y < gridRect.top() || y > gridRect.bottom()))
177 182 {
178 183 gridItem->setVisible(false);
179 184 tickItem->setVisible(false);
180 185 }else{
181 186 gridItem->setVisible(true);
182 187 tickItem->setVisible(true);
183 188 }
184 189
185 190 }
186 191 //begin/end grid line in case labels between
187 192 if (intervalAxis()) {
188 193 QGraphicsLineItem *gridLine;
189 194 gridLine = static_cast<QGraphicsLineItem *>(lines.at(layout.size()));
190 195 gridLine->setLine(gridRect.left(), gridRect.top(), gridRect.right(), gridRect.top());
191 196 gridLine->setVisible(true);
192 197 gridLine = static_cast<QGraphicsLineItem*>(lines.at(layout.size() + 1));
193 198 gridLine->setLine(gridRect.left(), gridRect.bottom(), gridRect.right(), gridRect.bottom());
194 199 gridLine->setVisible(true);
195 200 }
196 201 }
197 202
198 203 QSizeF VerticalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
199 204 {
200 205 Q_UNUSED(constraint);
201 206 QSizeF sh(0, 0);
202 207
203 208 if (axis()->titleText().isEmpty() || !titleItem()->isVisible())
204 209 return sh;
205 210
206 211 switch (which) {
207 212 case Qt::MinimumSize: {
208 213 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), "...");
209 214 sh = QSizeF(titleRect.height() + (titlePadding() * 2.0), titleRect.width());
210 215 break;
211 216 }
212 217 case Qt::MaximumSize:
213 218 case Qt::PreferredSize: {
214 219 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText());
215 220 sh = QSizeF(titleRect.height() + (titlePadding() * 2.0), titleRect.width());
216 221 break;
217 222 }
218 223 default:
219 224 break;
220 225 }
221 226
222 227 return sh;
223 228 }
224 229
225 230 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,90 +1,91
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2013 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Enterprise Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 11 ** accordance with the Qt Enterprise License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "charttitle_p.h"
22 22 #include "chartpresenter_p.h"
23 23 #include <QFont>
24 24 #include <QFontMetrics>
25 25 #include <QDebug>
26 26 #include <QTextDocument>
27 27
28 28 QTCOMMERCIALCHART_BEGIN_NAMESPACE
29 29
30 30 ChartTitle::ChartTitle(QGraphicsItem *parent)
31 31 : QGraphicsTextItem(parent)
32 32 {
33 33 document()->setDocumentMargin(ChartPresenter::textMargin());
34 34 }
35 35
36 36 ChartTitle::~ChartTitle()
37 37 {
38 38
39 39 }
40 40
41 41 void ChartTitle::setText(const QString &text)
42 42 {
43 43 m_text = text;
44 44 }
45 45
46 46 QString ChartTitle::text() const
47 47 {
48 48 return m_text;
49 49 }
50 50
51 51 void ChartTitle::setGeometry(const QRectF &rect)
52 52 {
53 QRectF dummyRect;
53 QRectF truncatedRect;
54 54 QGraphicsTextItem::setHtml(ChartPresenter::truncatedText(font(), m_text, qreal(0.0),
55 55 rect.width(), rect.height(),
56 dummyRect));
56 truncatedRect));
57 QGraphicsTextItem::setTextWidth(truncatedRect.width());
57 58 setPos(rect.topLeft());
58 59 }
59 60
60 61
61 62 QSizeF ChartTitle::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
62 63 {
63 64 Q_UNUSED(constraint);
64 65 QSizeF sh;
65 66
66 67 switch (which) {
67 68 case Qt::MinimumSize: {
68 69 QRectF titleRect = ChartPresenter::textBoundingRect(font(), "...");
69 70 sh = QSizeF(titleRect.width(), titleRect.height());
70 71 break;
71 72 }
72 73 case Qt::PreferredSize:
73 74 case Qt::MaximumSize: {
74 75 QRectF titleRect = ChartPresenter::textBoundingRect(font(), m_text);
75 76 sh = QSizeF(titleRect.width(), titleRect.height());
76 77 break;
77 78 }
78 79 case Qt::MinimumDescent: {
79 80 QFontMetrics fn(font());
80 81 sh = QSizeF(0, fn.descent());
81 82 break;
82 83 }
83 84 default:
84 85 break;
85 86 }
86 87
87 88 return sh;
88 89 }
89 90
90 91 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,190 +1,191
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2013 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Enterprise Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 11 ** accordance with the Qt Enterprise License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include <QPainter>
22 22 #include <QGraphicsSceneEvent>
23 23 #include <QGraphicsTextItem>
24 24 #include <QTextDocument>
25 25
26 26 #include "qlegend.h"
27 27 #include "qlegend_p.h"
28 28 #include "qlegendmarker.h"
29 29 #include "qlegendmarker_p.h"
30 30 #include "legendmarkeritem_p.h"
31 31 #include "chartpresenter_p.h"
32 32
33 33 QTCOMMERCIALCHART_BEGIN_NAMESPACE
34 34
35 35 LegendMarkerItem::LegendMarkerItem(QLegendMarkerPrivate *marker, QGraphicsObject *parent) :
36 36 QGraphicsObject(parent),
37 37 m_marker(marker),
38 38 m_markerRect(0,0,10.0,10.0),
39 39 m_boundingRect(0,0,0,0),
40 40 m_textItem(new QGraphicsTextItem(this)),
41 41 m_rectItem(new QGraphicsRectItem(this)),
42 42 m_margin(3),
43 43 m_space(4),
44 44 m_hovering(false),
45 45 m_pressPos(0, 0)
46 46 {
47 47 m_rectItem->setRect(m_markerRect);
48 48 m_textItem->document()->setDocumentMargin(ChartPresenter::textMargin());
49 49 setAcceptHoverEvents(true);
50 50 }
51 51
52 52 LegendMarkerItem::~LegendMarkerItem()
53 53 {
54 54 if (m_hovering) {
55 55 emit m_marker->q_ptr->hovered(false);
56 56 }
57 57 }
58 58
59 59 void LegendMarkerItem::setPen(const QPen &pen)
60 60 {
61 61 m_rectItem->setPen(pen);
62 62 }
63 63
64 64 QPen LegendMarkerItem::pen() const
65 65 {
66 66 return m_rectItem->pen();
67 67 }
68 68
69 69 void LegendMarkerItem::setBrush(const QBrush &brush)
70 70 {
71 71 m_rectItem->setBrush(brush);
72 72 }
73 73
74 74 QBrush LegendMarkerItem::brush() const
75 75 {
76 76 return m_rectItem->brush();
77 77 }
78 78
79 79 void LegendMarkerItem::setFont(const QFont &font)
80 80 {
81 81 m_textItem->setFont(font);
82 82 QFontMetrics fn(font);
83 83 m_markerRect = QRectF(0,0,fn.height()/2,fn.height()/2);
84 84 updateGeometry();
85 85 }
86 86
87 87 QFont LegendMarkerItem::font() const
88 88 {
89 89 return m_textItem->font();
90 90 }
91 91
92 92 void LegendMarkerItem::setLabel(const QString label)
93 93 {
94 94 m_label = label;
95 95 updateGeometry();
96 96 }
97 97
98 98 QString LegendMarkerItem::label() const
99 99 {
100 100 return m_label;
101 101 }
102 102
103 103 void LegendMarkerItem::setLabelBrush(const QBrush &brush)
104 104 {
105 105 m_textItem->setDefaultTextColor(brush.color());
106 106 }
107 107
108 108 QBrush LegendMarkerItem::labelBrush() const
109 109 {
110 110 return QBrush(m_textItem->defaultTextColor());
111 111 }
112 112
113 113 void LegendMarkerItem::setGeometry(const QRectF &rect)
114 114 {
115 115 qreal width = rect.width();
116 116 qreal x = m_margin + m_markerRect.width() + m_space + m_margin;
117 117 QRectF truncatedRect;
118 118
119 119 m_textItem->setHtml(ChartPresenter::truncatedText(m_textItem->font(), m_label, qreal(0.0),
120 120 width - x, rect.height(), truncatedRect));
121 m_textItem->setTextWidth(truncatedRect.width());
121 122
122 123 qreal y = qMax(m_markerRect.height() + 2 * m_margin, truncatedRect.height() + 2 * m_margin);
123 124
124 125 const QRectF &textRect = m_textItem->boundingRect();
125 126
126 127 m_textItem->setPos(x - m_margin, y / 2 - textRect.height() / 2);
127 128 m_rectItem->setRect(m_markerRect);
128 129 // The textMargin adjustments to position are done to make default case rects less blurry with anti-aliasing
129 130 m_rectItem->setPos(m_margin - ChartPresenter::textMargin(), y / 2.0 - m_markerRect.height() / 2.0 + ChartPresenter::textMargin());
130 131
131 132 prepareGeometryChange();
132 133 m_boundingRect = QRectF(0, 0, x + textRect.width() + m_margin, y);
133 134 }
134 135
135 136 QRectF LegendMarkerItem::boundingRect() const
136 137 {
137 138 return m_boundingRect;
138 139 }
139 140
140 141 void LegendMarkerItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
141 142 {
142 143 Q_UNUSED(option)
143 144 Q_UNUSED(widget)
144 145 Q_UNUSED(painter)
145 146 }
146 147
147 148 QSizeF LegendMarkerItem::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const
148 149 {
149 150 Q_UNUSED(constraint)
150 151
151 152 QSizeF sh;
152 153
153 154 switch (which) {
154 155 case Qt::MinimumSize: {
155 156 QRectF labelRect = ChartPresenter::textBoundingRect(m_textItem->font(), "...");
156 157 sh = QSizeF(labelRect.width() + (2.0 * m_margin) + m_space + m_markerRect.width(),
157 158 qMax(m_markerRect.height(), labelRect.height()) + (2.0 * m_margin));
158 159 break;
159 160 }
160 161 case Qt::PreferredSize: {
161 162 QRectF labelRect = ChartPresenter::textBoundingRect(m_textItem->font(), m_label);
162 163 sh = QSizeF(labelRect.width() + (2.0 * m_margin) + m_space + m_markerRect.width(),
163 164 qMax(m_markerRect.height(), labelRect.height()) + (2.0 * m_margin));
164 165 break;
165 166 }
166 167 default:
167 168 break;
168 169 }
169 170
170 171 return sh;
171 172 }
172 173
173 174 void LegendMarkerItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
174 175 {
175 176 Q_UNUSED(event)
176 177 m_hovering = true;
177 178 emit m_marker->q_ptr->hovered(true);
178 179 }
179 180
180 181 void LegendMarkerItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
181 182 {
182 183 Q_UNUSED(event)
183 184 m_hovering = false;
184 185 emit m_marker->q_ptr->hovered(false);
185 186 }
186 187
187 188
188 189 #include "moc_legendmarkeritem_p.cpp"
189 190
190 191 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now