##// END OF EJS Templates
Fix text item margins...
Miikka Heikkinen -
r2592:621c955c10d2
parent child
Show More
@@ -1,195 +1,197
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 "cartesianchartaxis_p.h"
22 22 #include "qabstractaxis.h"
23 23 #include "qabstractaxis_p.h"
24 24 #include "chartpresenter_p.h"
25 25 #include "abstractchartlayout_p.h"
26 26 #include "abstractdomain_p.h"
27 27 #include "linearrowitem_p.h"
28 28 #include <QValueAxis>
29 29 #include <QLogValueAxis>
30 30 #include <QGraphicsLayout>
31 #include <QTextDocument>
31 32
32 33 QTCOMMERCIALCHART_BEGIN_NAMESPACE
33 34
34 35 CartesianChartAxis::CartesianChartAxis(QAbstractAxis *axis, QGraphicsItem *item , bool intervalAxis)
35 36 : ChartAxisElement(axis, item, intervalAxis)
36 37 {
37 38 Q_ASSERT(item);
38 39 }
39 40
40 41
41 42 CartesianChartAxis::~CartesianChartAxis()
42 43 {
43 44 }
44 45
45 46 void CartesianChartAxis::createItems(int count)
46 47 {
47 48 if (arrowItems().size() == 0) {
48 49 QGraphicsLineItem *arrow = new LineArrowItem(this, this);
49 50 arrow->setPen(axis()->linePen());
50 51 arrowGroup()->addToGroup(arrow);
51 52 }
52 53
53 54 if (intervalAxis() && gridItems().size() == 0) {
54 55 for (int i = 0 ; i < 2 ; i ++){
55 56 QGraphicsLineItem *item = new QGraphicsLineItem(this);
56 57 item->setPen(axis()->gridLinePen());
57 58 gridGroup()->addToGroup(item);
58 59 }
59 60 }
60 61
61 62 for (int i = 0; i < count; ++i) {
62 63 QGraphicsLineItem *arrow = new QGraphicsLineItem(this);
63 64 QGraphicsLineItem *grid = new QGraphicsLineItem(this);
64 65 QGraphicsTextItem *label = new QGraphicsTextItem(this);
66 label->document()->setDocumentMargin(ChartPresenter::textMargin());
65 67 QGraphicsTextItem *title = titleItem();
66 68 arrow->setPen(axis()->linePen());
67 69 grid->setPen(axis()->gridLinePen());
68 70 label->setFont(axis()->labelsFont());
69 71 label->setDefaultTextColor(axis()->labelsBrush().color());
70 72 label->setRotation(axis()->labelsAngle());
71 73 title->setFont(axis()->titleFont());
72 74 title->setDefaultTextColor(axis()->titleBrush().color());
73 75 title->setHtml(axis()->titleText());
74 76 arrowGroup()->addToGroup(arrow);
75 77 gridGroup()->addToGroup(grid);
76 78 labelGroup()->addToGroup(label);
77 79
78 80 if ((gridItems().size()) % 2 && gridItems().size() > 2) {
79 81 QGraphicsRectItem* shades = new QGraphicsRectItem(this);
80 82 shades->setPen(axis()->shadesPen());
81 83 shades->setBrush(axis()->shadesBrush());
82 84 shadeGroup()->addToGroup(shades);
83 85 }
84 86 }
85 87
86 88 }
87 89
88 90 void CartesianChartAxis::deleteItems(int count)
89 91 {
90 92 QList<QGraphicsItem *> lines = gridItems();
91 93 QList<QGraphicsItem *> labels = labelItems();
92 94 QList<QGraphicsItem *> shades = shadeItems();
93 95 QList<QGraphicsItem *> axis = arrowItems();
94 96
95 97 for (int i = 0; i < count; ++i) {
96 98 if (lines.size() % 2 && lines.size() > 1)
97 99 delete(shades.takeLast());
98 100 delete(lines.takeLast());
99 101 delete(labels.takeLast());
100 102 delete(axis.takeLast());
101 103 }
102 104 }
103 105
104 106 void CartesianChartAxis::updateLayout(QVector<qreal> &layout)
105 107 {
106 108 int diff = ChartAxisElement::layout().size() - layout.size();
107 109
108 110 if (diff > 0)
109 111 deleteItems(diff);
110 112 else if (diff < 0)
111 113 createItems(-diff);
112 114
113 115 if (animation()) {
114 116 switch (presenter()->state()) {
115 117 case ChartPresenter::ZoomInState:
116 118 animation()->setAnimationType(AxisAnimation::ZoomInAnimation);
117 119 animation()->setAnimationPoint(presenter()->statePoint());
118 120 break;
119 121 case ChartPresenter::ZoomOutState:
120 122 animation()->setAnimationType(AxisAnimation::ZoomOutAnimation);
121 123 animation()->setAnimationPoint(presenter()->statePoint());
122 124 break;
123 125 case ChartPresenter::ScrollUpState:
124 126 case ChartPresenter::ScrollLeftState:
125 127 animation()->setAnimationType(AxisAnimation::MoveBackwordAnimation);
126 128 break;
127 129 case ChartPresenter::ScrollDownState:
128 130 case ChartPresenter::ScrollRightState:
129 131 animation()->setAnimationType(AxisAnimation::MoveForwardAnimation);
130 132 break;
131 133 case ChartPresenter::ShowState:
132 134 animation()->setAnimationType(AxisAnimation::DefaultAnimation);
133 135 break;
134 136 }
135 137 animation()->setValues(ChartAxisElement::layout(), layout);
136 138 presenter()->startAnimation(animation());
137 139 } else {
138 140 setLayout(layout);
139 141 updateGeometry();
140 142 }
141 143 }
142 144
143 145 bool CartesianChartAxis::isEmpty()
144 146 {
145 147 return axisGeometry().isEmpty()
146 148 || gridGeometry().isEmpty()
147 149 || qFuzzyCompare(min(), max());
148 150 }
149 151
150 152 void CartesianChartAxis::setGeometry(const QRectF &axis, const QRectF &grid)
151 153 {
152 154 m_gridRect = grid;
153 155 setAxisGeometry(axis);
154 156
155 157 if (isEmpty())
156 158 return;
157 159
158 160 QVector<qreal> layout = calculateLayout();
159 161 updateLayout(layout);
160 162 }
161 163
162 164 QSizeF CartesianChartAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
163 165 {
164 166 Q_UNUSED(which);
165 167 Q_UNUSED(constraint);
166 168 return QSizeF();
167 169 }
168 170
169 171 void CartesianChartAxis::handleArrowPenChanged(const QPen &pen)
170 172 {
171 173 foreach (QGraphicsItem *item, arrowItems())
172 174 static_cast<QGraphicsLineItem *>(item)->setPen(pen);
173 175 }
174 176
175 177 void CartesianChartAxis::handleGridPenChanged(const QPen &pen)
176 178 {
177 179 foreach (QGraphicsItem *item, gridItems())
178 180 static_cast<QGraphicsLineItem *>(item)->setPen(pen);
179 181 }
180 182
181 183 void CartesianChartAxis::handleShadesBrushChanged(const QBrush &brush)
182 184 {
183 185 foreach (QGraphicsItem *item, shadeItems())
184 186 static_cast<QGraphicsRectItem *>(item)->setBrush(brush);
185 187 }
186 188
187 189 void CartesianChartAxis::handleShadesPenChanged(const QPen &pen)
188 190 {
189 191 foreach (QGraphicsItem *item, shadeItems())
190 192 static_cast<QGraphicsRectItem *>(item)->setPen(pen);
191 193 }
192 194
193 195 #include "moc_cartesianchartaxis_p.cpp"
194 196
195 197 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,352 +1,354
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 "chartaxiselement_p.h"
22 22 #include "qabstractaxis_p.h"
23 23 #include "chartpresenter_p.h"
24 24 #include "abstractchartlayout_p.h"
25 25 #include <qmath.h>
26 26 #include <QDateTime>
27 #include <QTextDocument>
27 28
28 29 QTCOMMERCIALCHART_BEGIN_NAMESPACE
29 30
30 31 static const char *labelFormatMatchString = "%[\\-\\+#\\s\\d\\.lhjztL]*([dicuoxfegXFEG])";
31 32 static QRegExp *labelFormatMatcher = 0;
32 33 class StaticLabelFormatMatcherDeleter
33 34 {
34 35 public:
35 36 StaticLabelFormatMatcherDeleter() {}
36 37 ~StaticLabelFormatMatcherDeleter() { delete labelFormatMatcher; }
37 38 };
38 39 static StaticLabelFormatMatcherDeleter staticLabelFormatMatcherDeleter;
39 40
40 41 ChartAxisElement::ChartAxisElement(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
41 42 : ChartElement(item),
42 43 m_axis(axis),
43 44 m_animation(0),
44 45 m_grid(new QGraphicsItemGroup(item)),
45 46 m_arrow(new QGraphicsItemGroup(item)),
46 47 m_shades(new QGraphicsItemGroup(item)),
47 48 m_labels(new QGraphicsItemGroup(item)),
48 49 m_title(new QGraphicsTextItem(item)),
49 50 m_intervalAxis(intervalAxis)
50 51
51 52 {
52 53 //initial initialization
53 54 m_arrow->setHandlesChildEvents(false);
54 55 m_arrow->setZValue(ChartPresenter::AxisZValue);
55 56 m_labels->setZValue(ChartPresenter::AxisZValue);
56 57 m_shades->setZValue(ChartPresenter::ShadesZValue);
57 58 m_grid->setZValue(ChartPresenter::GridZValue);
58 59 m_title->setZValue(ChartPresenter::GridZValue);
60 m_title->document()->setDocumentMargin(ChartPresenter::textMargin());
59 61 handleVisibleChanged(axis->isVisible());
60 62 connectSlots();
61 63
62 64 setFlag(QGraphicsItem::ItemHasNoContents, true);
63 65 }
64 66
65 67 ChartAxisElement::~ChartAxisElement()
66 68 {
67 69 }
68 70
69 71 void ChartAxisElement::connectSlots()
70 72 {
71 73 QObject::connect(axis(), SIGNAL(visibleChanged(bool)), this, SLOT(handleVisibleChanged(bool)));
72 74 QObject::connect(axis(), SIGNAL(lineVisibleChanged(bool)), this, SLOT(handleArrowVisibleChanged(bool)));
73 75 QObject::connect(axis(), SIGNAL(gridVisibleChanged(bool)), this, SLOT(handleGridVisibleChanged(bool)));
74 76 QObject::connect(axis(), SIGNAL(labelsVisibleChanged(bool)), this, SLOT(handleLabelsVisibleChanged(bool)));
75 77 QObject::connect(axis(), SIGNAL(shadesVisibleChanged(bool)), this, SLOT(handleShadesVisibleChanged(bool)));
76 78 QObject::connect(axis(), SIGNAL(labelsAngleChanged(int)), this, SLOT(handleLabelsAngleChanged(int)));
77 79 QObject::connect(axis(), SIGNAL(linePenChanged(const QPen&)), this, SLOT(handleArrowPenChanged(const QPen&)));
78 80 QObject::connect(axis(), SIGNAL(labelsPenChanged(const QPen&)), this, SLOT(handleLabelsPenChanged(const QPen&)));
79 81 QObject::connect(axis(), SIGNAL(labelsBrushChanged(const QBrush&)), this, SLOT(handleLabelsBrushChanged(const QBrush&)));
80 82 QObject::connect(axis(), SIGNAL(labelsFontChanged(const QFont&)), this, SLOT(handleLabelsFontChanged(const QFont&)));
81 83 QObject::connect(axis(), SIGNAL(gridLinePenChanged(const QPen&)), this, SLOT(handleGridPenChanged(const QPen&)));
82 84 QObject::connect(axis(), SIGNAL(shadesPenChanged(const QPen&)), this, SLOT(handleShadesPenChanged(const QPen&)));
83 85 QObject::connect(axis(), SIGNAL(shadesBrushChanged(const QBrush&)), this, SLOT(handleShadesBrushChanged(const QBrush&)));
84 86 QObject::connect(axis(), SIGNAL(titleTextChanged(const QString&)), this, SLOT(handleTitleTextChanged(const QString&)));
85 87 QObject::connect(axis(), SIGNAL(titleFontChanged(const QFont&)), this, SLOT(handleTitleFontChanged(const QFont&)));
86 88 QObject::connect(axis(), SIGNAL(titlePenChanged(const QPen&)), this, SLOT(handleTitlePenChanged(const QPen&)));
87 89 QObject::connect(axis(), SIGNAL(titleBrushChanged(const QBrush&)), this, SLOT(handleTitleBrushChanged(const QBrush&)));
88 90 QObject::connect(axis(), SIGNAL(titleVisibleChanged(bool)), this, SLOT(handleTitleVisibleChanged(bool)));
89 91 QObject::connect(axis()->d_ptr.data(), SIGNAL(rangeChanged(qreal, qreal)), this, SLOT(handleRangeChanged(qreal, qreal)));
90 92 }
91 93
92 94 void ChartAxisElement::handleArrowVisibleChanged(bool visible)
93 95 {
94 96 m_arrow->setVisible(visible);
95 97 }
96 98
97 99 void ChartAxisElement::handleGridVisibleChanged(bool visible)
98 100 {
99 101 m_grid->setVisible(visible);
100 102 }
101 103
102 104 void ChartAxisElement::handleLabelsVisibleChanged(bool visible)
103 105 {
104 106 QGraphicsLayoutItem::updateGeometry();
105 107 presenter()->layout()->invalidate();
106 108 m_labels->setVisible(visible);
107 109 }
108 110
109 111 void ChartAxisElement::handleShadesVisibleChanged(bool visible)
110 112 {
111 113 m_shades->setVisible(visible);
112 114 }
113 115
114 116 void ChartAxisElement::handleTitleVisibleChanged(bool visible)
115 117 {
116 118 QGraphicsLayoutItem::updateGeometry();
117 119 presenter()->layout()->invalidate();
118 120 m_title->setVisible(visible);
119 121 }
120 122
121 123 void ChartAxisElement::handleLabelsAngleChanged(int angle)
122 124 {
123 125 foreach (QGraphicsItem *item, m_labels->childItems())
124 126 item->setRotation(angle);
125 127
126 128 QGraphicsLayoutItem::updateGeometry();
127 129 presenter()->layout()->invalidate();
128 130 }
129 131
130 132 void ChartAxisElement::handleLabelsPenChanged(const QPen &pen)
131 133 {
132 134 Q_UNUSED(pen)
133 135 }
134 136
135 137 void ChartAxisElement::handleLabelsBrushChanged(const QBrush &brush)
136 138 {
137 139 foreach (QGraphicsItem *item, m_labels->childItems())
138 140 static_cast<QGraphicsTextItem *>(item)->setDefaultTextColor(brush.color());
139 141 }
140 142
141 143 void ChartAxisElement::handleLabelsFontChanged(const QFont &font)
142 144 {
143 145 foreach (QGraphicsItem *item, m_labels->childItems())
144 146 static_cast<QGraphicsTextItem *>(item)->setFont(font);
145 147 QGraphicsLayoutItem::updateGeometry();
146 148 presenter()->layout()->invalidate();
147 149 }
148 150
149 151 void ChartAxisElement::handleTitleTextChanged(const QString &title)
150 152 {
151 153 QGraphicsLayoutItem::updateGeometry();
152 154 presenter()->layout()->invalidate();
153 155 m_title->setHtml(title);
154 156 }
155 157
156 158 void ChartAxisElement::handleTitlePenChanged(const QPen &pen)
157 159 {
158 160 Q_UNUSED(pen)
159 161 }
160 162
161 163 void ChartAxisElement::handleTitleBrushChanged(const QBrush &brush)
162 164 {
163 165 m_title->setDefaultTextColor(brush.color());
164 166 }
165 167
166 168 void ChartAxisElement::handleTitleFontChanged(const QFont &font)
167 169 {
168 170 if (m_title->font() != font) {
169 171 m_title->setFont(font);
170 172 QGraphicsLayoutItem::updateGeometry();
171 173 presenter()->layout()->invalidate();
172 174 }
173 175 }
174 176
175 177 void ChartAxisElement::handleVisibleChanged(bool visible)
176 178 {
177 179 setVisible(visible);
178 180 if (!visible) {
179 181 m_grid->setVisible(visible);
180 182 m_arrow->setVisible(visible);
181 183 m_shades->setVisible(visible);
182 184 m_labels->setVisible(visible);
183 185 m_title->setVisible(visible);
184 186 } else {
185 187 m_grid->setVisible(axis()->isGridLineVisible());
186 188 m_arrow->setVisible(axis()->isLineVisible());
187 189 m_shades->setVisible(axis()->shadesVisible());
188 190 m_labels->setVisible(axis()->labelsVisible());
189 191 m_title->setVisible(axis()->isTitleVisible());
190 192 }
191 193
192 194 if (presenter()) presenter()->layout()->invalidate();
193 195 }
194 196
195 197 void ChartAxisElement::handleRangeChanged(qreal min, qreal max)
196 198 {
197 199 Q_UNUSED(min);
198 200 Q_UNUSED(max);
199 201
200 202 if (!isEmpty()) {
201 203 QVector<qreal> layout = calculateLayout();
202 204 updateLayout(layout);
203 205 QSizeF before = effectiveSizeHint(Qt::PreferredSize);
204 206 QSizeF after = sizeHint(Qt::PreferredSize);
205 207
206 208 if (before != after) {
207 209 QGraphicsLayoutItem::updateGeometry();
208 210 // We don't want to call invalidate on layout, since it will change minimum size of
209 211 // component, which we would like to avoid since it causes nasty flips when scrolling
210 212 // or zooming, instead recalculate layout and use plotArea for extra space.
211 213 presenter()->layout()->setGeometry(presenter()->layout()->geometry());
212 214 }
213 215 }
214 216 }
215 217
216 218 bool ChartAxisElement::isEmpty()
217 219 {
218 220 return axisGeometry().isEmpty()
219 221 || gridGeometry().isEmpty()
220 222 || qFuzzyCompare(min(), max());
221 223 }
222 224
223 225 qreal ChartAxisElement::min() const
224 226 {
225 227 return m_axis->d_ptr->min();
226 228 }
227 229
228 230 qreal ChartAxisElement::max() const
229 231 {
230 232 return m_axis->d_ptr->max();
231 233 }
232 234
233 235 static void appendFormattedLabel(const QString &capStr, const QByteArray &array,
234 236 QStringList &labels, qreal value)
235 237 {
236 238 if (capStr.isEmpty()) {
237 239 labels << QString();
238 240 } else if (capStr.at(0) == QLatin1Char('d')
239 241 || capStr.at(0) == QLatin1Char('i')
240 242 || capStr.at(0) == QLatin1Char('c')) {
241 243 labels << QString().sprintf(array, (qint64)value);
242 244 } else if (capStr.at(0) == QLatin1Char('u')
243 245 || capStr.at(0) == QLatin1Char('o')
244 246 || capStr.at(0) == QLatin1Char('x')
245 247 || capStr.at(0) == QLatin1Char('X')) {
246 248 labels << QString().sprintf(array, (quint64)value);
247 249 } else if (capStr.at(0) == QLatin1Char('f')
248 250 || capStr.at(0) == QLatin1Char('F')
249 251 || capStr.at(0) == QLatin1Char('e')
250 252 || capStr.at(0) == QLatin1Char('E')
251 253 || capStr.at(0) == QLatin1Char('g')
252 254 || capStr.at(0) == QLatin1Char('G')) {
253 255 labels << QString().sprintf(array, value);
254 256 } else {
255 257 labels << QString();
256 258 }
257 259 }
258 260
259 261 QStringList ChartAxisElement::createValueLabels(qreal min, qreal max, int ticks, const QString &format)
260 262 {
261 263 QStringList labels;
262 264
263 265 if (max <= min || ticks < 1)
264 266 return labels;
265 267
266 268 int n = qMax(int(-qFloor(log10((max - min) / (ticks - 1)))), 0);
267 269 n++;
268 270
269 271 if (format.isNull()) {
270 272 for (int i = 0; i < ticks; i++) {
271 273 qreal value = min + (i * (max - min) / (ticks - 1));
272 274 labels << QString::number(value, 'f', n);
273 275 }
274 276 } else {
275 277 QByteArray array = format.toLatin1();
276 278 QString capStr;
277 279 if (!labelFormatMatcher)
278 280 labelFormatMatcher = new QRegExp(labelFormatMatchString);
279 281 if (labelFormatMatcher->indexIn(format, 0) != -1)
280 282 capStr = labelFormatMatcher->cap(1);
281 283 for (int i = 0; i < ticks; i++) {
282 284 qreal value = min + (i * (max - min) / (ticks - 1));
283 285 appendFormattedLabel(capStr, array, labels, value);
284 286 }
285 287 }
286 288
287 289 return labels;
288 290 }
289 291
290 292 QStringList ChartAxisElement::createLogValueLabels(qreal min, qreal max, qreal base, int ticks, const QString &format)
291 293 {
292 294 QStringList labels;
293 295
294 296 if (max <= min || ticks < 1)
295 297 return labels;
296 298
297 299 int n = 0;
298 300 if (ticks > 1)
299 301 n = qMax(int(-qFloor(log10((max - min) / (ticks - 1)))), 0);
300 302 n++;
301 303
302 304 int firstTick;
303 305 if (base > 1)
304 306 firstTick = ceil(log10(min) / log10(base));
305 307 else
306 308 firstTick = ceil(log10(max) / log10(base));
307 309
308 310 if (format.isNull()) {
309 311 for (int i = firstTick; i < ticks + firstTick; i++) {
310 312 qreal value = qPow(base, i);
311 313 labels << QString::number(value, 'f', n);
312 314 }
313 315 } else {
314 316 QByteArray array = format.toLatin1();
315 317 QString capStr;
316 318 if (!labelFormatMatcher)
317 319 labelFormatMatcher = new QRegExp(labelFormatMatchString);
318 320 if (labelFormatMatcher->indexIn(format, 0) != -1)
319 321 capStr = labelFormatMatcher->cap(1);
320 322 for (int i = firstTick; i < ticks + firstTick; i++) {
321 323 qreal value = qPow(base, i);
322 324 appendFormattedLabel(capStr, array, labels, value);
323 325 }
324 326 }
325 327
326 328 return labels;
327 329 }
328 330
329 331 QStringList ChartAxisElement::createDateTimeLabels(qreal min, qreal max,int ticks,const QString &format)
330 332 {
331 333 QStringList labels;
332 334
333 335 if (max <= min || ticks < 1)
334 336 return labels;
335 337
336 338 int n = qMax(int(-floor(log10((max - min) / (ticks - 1)))), 0);
337 339 n++;
338 340 for (int i = 0; i < ticks; i++) {
339 341 qreal value = min + (i * (max - min) / (ticks - 1));
340 342 labels << QDateTime::fromMSecsSinceEpoch(value).toString(format);
341 343 }
342 344 return labels;
343 345 }
344 346
345 347 void ChartAxisElement::axisSelected()
346 348 {
347 349 emit clicked();
348 350 }
349 351
350 352 #include "moc_chartaxiselement_p.cpp"
351 353
352 354 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,151 +1,151
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 // W A R N I N G
22 22 // -------------
23 23 //
24 24 // This file is not part of the Qt Enterprise Chart API. It exists purely as an
25 25 // implementation detail. This header file may change from version to
26 26 // version without notice, or even be removed.
27 27 //
28 28 // We mean it.
29 29
30 30 #ifndef CHARTAXISELEMENT_H
31 31 #define CHARTAXISELEMENT_H
32 32
33 33 #include "qchartglobal.h"
34 34 #include "chartelement_p.h"
35 35 #include "axisanimation_p.h"
36 36 #include <QGraphicsItem>
37 37 #include <QGraphicsLayoutItem>
38 38 #include <QFont>
39 39
40 40 QTCOMMERCIALCHART_BEGIN_NAMESPACE
41 41
42 42 class ChartPresenter;
43 43 class QAbstractAxis;
44 44
45 45 class ChartAxisElement : public ChartElement, public QGraphicsLayoutItem
46 46 {
47 47 Q_OBJECT
48 48
49 49 using QGraphicsLayoutItem::setGeometry;
50 50 public:
51 51 ChartAxisElement(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis = false);
52 52 ~ChartAxisElement();
53 53
54 54 virtual QRectF gridGeometry() const = 0;
55 55 virtual void setGeometry(const QRectF &axis, const QRectF &grid) = 0;
56 56 virtual bool isEmpty() = 0;
57 57
58 58 void setAnimation(AxisAnimation *animation) { m_animation = animation; }
59 59 AxisAnimation *animation() const { return m_animation; }
60 60
61 61 QAbstractAxis *axis() const { return m_axis; }
62 62 void setLayout(QVector<qreal> &layout) { m_layout = layout; }
63 63 QVector<qreal> &layout() { return m_layout; } // Modifiable reference
64 inline qreal labelPadding() const { return qreal(1.0); }
65 inline qreal titlePadding() const { return qreal(1.0); }
64 inline qreal labelPadding() const { return qreal(4.0); }
65 inline qreal titlePadding() const { return qreal(2.0); }
66 66 void setLabels(const QStringList &labels) { m_labelsList = labels; }
67 67 QStringList labels() const { return m_labelsList; }
68 68
69 69 qreal min() const;
70 70 qreal max() const;
71 71
72 72 QRectF axisGeometry() const { return m_axisRect; }
73 73 void setAxisGeometry(const QRectF &axisGeometry) { m_axisRect = axisGeometry; }
74 74
75 75 void axisSelected();
76 76
77 77 //this flag indicates that axis is used to show intervals it means labels are in between ticks
78 78 bool intervalAxis() const { return m_intervalAxis; }
79 79
80 80 static QStringList createValueLabels(qreal max, qreal min, int ticks, const QString &format);
81 81 static QStringList createLogValueLabels(qreal min, qreal max, qreal base, int ticks, const QString &format);
82 82 static QStringList createDateTimeLabels(qreal max, qreal min, int ticks, const QString &format);
83 83
84 84 // from QGraphicsLayoutItem
85 85 QRectF boundingRect() const
86 86 {
87 87 return QRectF();
88 88 }
89 89
90 90 // from QGraphicsLayoutItem
91 91 void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*)
92 92 {
93 93 }
94 94
95 95 protected:
96 96 virtual QVector<qreal> calculateLayout() const = 0;
97 97 virtual void updateLayout(QVector<qreal> &layout) = 0;
98 98
99 99 QList<QGraphicsItem *> gridItems() { return m_grid->childItems(); }
100 100 QList<QGraphicsItem *> labelItems() { return m_labels->childItems(); }
101 101 QList<QGraphicsItem *> shadeItems() { return m_shades->childItems(); }
102 102 QList<QGraphicsItem *> arrowItems() { return m_arrow->childItems(); }
103 103 QGraphicsTextItem *titleItem() const { return m_title.data(); }
104 104 QGraphicsItemGroup *gridGroup() { return m_grid.data(); }
105 105 QGraphicsItemGroup *labelGroup() { return m_labels.data(); }
106 106 QGraphicsItemGroup *shadeGroup() { return m_shades.data(); }
107 107 QGraphicsItemGroup *arrowGroup() { return m_arrow.data(); }
108 108
109 109 public Q_SLOTS:
110 110 void handleVisibleChanged(bool visible);
111 111 void handleArrowVisibleChanged(bool visible);
112 112 void handleGridVisibleChanged(bool visible);
113 113 void handleLabelsVisibleChanged(bool visible);
114 114 void handleShadesVisibleChanged(bool visible);
115 115 void handleLabelsAngleChanged(int angle);
116 116 virtual void handleShadesBrushChanged(const QBrush &brush) = 0;
117 117 virtual void handleShadesPenChanged(const QPen &pen) = 0;
118 118 virtual void handleArrowPenChanged(const QPen &pen) = 0;
119 119 virtual void handleGridPenChanged(const QPen &pen) = 0;
120 120 void handleLabelsPenChanged(const QPen &pen);
121 121 void handleLabelsBrushChanged(const QBrush &brush);
122 122 void handleLabelsFontChanged(const QFont &font);
123 123 void handleTitlePenChanged(const QPen &pen);
124 124 void handleTitleBrushChanged(const QBrush &brush);
125 125 void handleTitleFontChanged(const QFont &font);
126 126 void handleTitleTextChanged(const QString &title);
127 127 void handleTitleVisibleChanged(bool visible);
128 128 void handleRangeChanged(qreal min, qreal max);
129 129
130 130 Q_SIGNALS:
131 131 void clicked();
132 132
133 133 private:
134 134 void connectSlots();
135 135
136 136 QAbstractAxis *m_axis;
137 137 AxisAnimation *m_animation;
138 138 QVector<qreal> m_layout;
139 139 QStringList m_labelsList;
140 140 QRectF m_axisRect;
141 141 QScopedPointer<QGraphicsItemGroup> m_grid;
142 142 QScopedPointer<QGraphicsItemGroup> m_arrow;
143 143 QScopedPointer<QGraphicsItemGroup> m_shades;
144 144 QScopedPointer<QGraphicsItemGroup> m_labels;
145 145 QScopedPointer<QGraphicsTextItem> m_title;
146 146 bool m_intervalAxis;
147 147 };
148 148
149 149 QTCOMMERCIALCHART_END_NAMESPACE
150 150
151 151 #endif /* CHARTAXISELEMENT_H */
@@ -1,420 +1,422
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 #include <QTextDocument>
28 29
29 30 QTCOMMERCIALCHART_BEGIN_NAMESPACE
30 31
31 32 PolarChartAxisAngular::PolarChartAxisAngular(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
32 33 : PolarChartAxis(axis, item, intervalAxis)
33 34 {
34 35 }
35 36
36 37 PolarChartAxisAngular::~PolarChartAxisAngular()
37 38 {
38 39 }
39 40
40 41 void PolarChartAxisAngular::updateGeometry()
41 42 {
42 43 QGraphicsLayoutItem::updateGeometry();
43 44
44 45 const QVector<qreal> &layout = this->layout();
45 46 if (layout.isEmpty())
46 47 return;
47 48
48 49 createAxisLabels(layout);
49 50 QStringList labelList = labels();
50 51 QPointF center = axisGeometry().center();
51 52 QList<QGraphicsItem *> arrowItemList = arrowItems();
52 53 QList<QGraphicsItem *> gridItemList = gridItems();
53 54 QList<QGraphicsItem *> labelItemList = labelItems();
54 55 QList<QGraphicsItem *> shadeItemList = shadeItems();
55 56 QGraphicsTextItem *title = titleItem();
56 57
57 58 QGraphicsEllipseItem *axisLine = static_cast<QGraphicsEllipseItem *>(arrowItemList.at(0));
58 59 axisLine->setRect(axisGeometry());
59 60
60 61 qreal radius = axisGeometry().height() / 2.0;
61 62
62 63 QRectF previousLabelRect;
63 64 QRectF firstLabelRect;
64 65
65 66 qreal labelHeight = 0;
66 67
67 68 bool firstShade = true;
68 69 bool nextTickVisible = false;
69 70 if (layout.size())
70 71 nextTickVisible = !(layout.at(0) < 0.0 || layout.at(0) > 360.0);
71 72
72 73 for (int i = 0; i < layout.size(); ++i) {
73 74 qreal angularCoordinate = layout.at(i);
74 75
75 76 QGraphicsLineItem *gridLineItem = static_cast<QGraphicsLineItem *>(gridItemList.at(i));
76 77 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrowItemList.at(i + 1));
77 78 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labelItemList.at(i));
78 79 QGraphicsPathItem *shadeItem = 0;
79 80 if (i == 0)
80 81 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
81 82 else if (i % 2)
82 83 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at((i / 2) + 1));
83 84
84 85 // Ignore ticks outside valid range
85 86 bool currentTickVisible = nextTickVisible;
86 87 if ((i == layout.size() - 1)
87 88 || layout.at(i + 1) < 0.0
88 89 || layout.at(i + 1) > 360.0) {
89 90 nextTickVisible = false;
90 91 } else {
91 92 nextTickVisible = true;
92 93 }
93 94
94 95 qreal labelCoordinate = angularCoordinate;
95 96 qreal labelVisible = currentTickVisible;
96 97 if (intervalAxis()) {
97 98 qreal farEdge;
98 99 if (i == (layout.size() - 1))
99 100 farEdge = 360.0;
100 101 else
101 102 farEdge = qMin(qreal(360.0), layout.at(i + 1));
102 103
103 104 // Adjust the labelCoordinate to show it if next tick is visible
104 105 if (nextTickVisible)
105 106 labelCoordinate = qMax(qreal(0.0), labelCoordinate);
106 107
107 108 labelCoordinate = (labelCoordinate + farEdge) / 2.0;
108 109 // Don't display label once the category gets too small near the axis
109 110 if (labelCoordinate < 5.0 || labelCoordinate > 355.0)
110 111 labelVisible = false;
111 112 else
112 113 labelVisible = true;
113 114 }
114 115
115 116 // Need this also in label calculations, so determine it first
116 117 QLineF tickLine(QLineF::fromPolar(radius - tickWidth(), 90.0 - angularCoordinate).p2(),
117 118 QLineF::fromPolar(radius + tickWidth(), 90.0 - angularCoordinate).p2());
118 119 tickLine.translate(center);
119 120
120 121 // Angular axis label
121 122 if (axis()->labelsVisible() && labelVisible) {
122 123 labelItem->setHtml(labelList.at(i));
123 124 const QRectF &rect = labelItem->boundingRect();
124 125 QPointF labelCenter = rect.center();
125 126 labelItem->setTransformOriginPoint(labelCenter.x(), labelCenter.y());
126 127 QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), labelList.at(i), axis()->labelsAngle());
127 128 boundingRect.moveCenter(labelCenter);
128 129 QPointF positionDiff(rect.topLeft() - boundingRect.topLeft());
129 130
130 131 QPointF labelPoint;
131 132 if (intervalAxis()) {
132 133 QLineF labelLine = QLineF::fromPolar(radius + tickWidth(), 90.0 - labelCoordinate);
133 134 labelLine.translate(center);
134 135 labelPoint = labelLine.p2();
135 136 } else {
136 137 labelPoint = tickLine.p2();
137 138 }
138 139
139 140 QRectF labelRect = moveLabelToPosition(labelCoordinate, labelPoint, boundingRect);
140 141 labelItem->setPos(labelRect.topLeft() + positionDiff);
141 142
142 143 // Store height for title calculations
143 144 qreal labelClearance = axisGeometry().top() - labelRect.top();
144 145 labelHeight = qMax(labelHeight, labelClearance);
145 146
146 147 // Label overlap detection
147 148 if (i && (previousLabelRect.intersects(labelRect) || firstLabelRect.intersects(labelRect))) {
148 149 labelVisible = false;
149 150 } else {
150 151 // Store labelRect for future comparison. Some area is deducted to make things look
151 152 // little nicer, as usually intersection happens at label corner with angular labels.
152 153 labelRect.adjust(-2.0, -4.0, -2.0, -4.0);
153 154 if (firstLabelRect.isEmpty())
154 155 firstLabelRect = labelRect;
155 156
156 157 previousLabelRect = labelRect;
157 158 labelVisible = true;
158 159 }
159 160 }
160 161
161 162 labelItem->setVisible(labelVisible);
162 163 if (!currentTickVisible) {
163 164 gridLineItem->setVisible(false);
164 165 tickItem->setVisible(false);
165 166 if (shadeItem)
166 167 shadeItem->setVisible(false);
167 168 continue;
168 169 }
169 170
170 171 // Angular grid line
171 172 QLineF gridLine = QLineF::fromPolar(radius, 90.0 - angularCoordinate);
172 173 gridLine.translate(center);
173 174 gridLineItem->setLine(gridLine);
174 175 gridLineItem->setVisible(true);
175 176
176 177 // Tick
177 178 tickItem->setLine(tickLine);
178 179 tickItem->setVisible(true);
179 180
180 181 // Shades
181 182 if (i % 2 || (i == 0 && !nextTickVisible)) {
182 183 QPainterPath path;
183 184 path.moveTo(center);
184 185 if (i == 0) {
185 186 // If first tick is also the last, we need to custom fill the first partial arc
186 187 // or it won't get filled.
187 188 path.arcTo(axisGeometry(), 90.0 - layout.at(0), layout.at(0));
188 189 path.closeSubpath();
189 190 } else {
190 191 qreal nextCoordinate;
191 192 if (!nextTickVisible) // Last visible tick
192 193 nextCoordinate = 360.0;
193 194 else
194 195 nextCoordinate = layout.at(i + 1);
195 196 qreal arcSpan = angularCoordinate - nextCoordinate;
196 197 path.arcTo(axisGeometry(), 90.0 - angularCoordinate, arcSpan);
197 198 path.closeSubpath();
198 199
199 200 // Add additional arc for first shade item if there is a partial arc to be filled
200 201 if (firstShade) {
201 202 QGraphicsPathItem *specialShadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
202 203 if (layout.at(i - 1) > 0.0) {
203 204 QPainterPath specialPath;
204 205 specialPath.moveTo(center);
205 206 specialPath.arcTo(axisGeometry(), 90.0 - layout.at(i - 1), layout.at(i - 1));
206 207 specialPath.closeSubpath();
207 208 specialShadeItem->setPath(specialPath);
208 209 specialShadeItem->setVisible(true);
209 210 } else {
210 211 specialShadeItem->setVisible(false);
211 212 }
212 213 }
213 214 }
214 215 shadeItem->setPath(path);
215 216 shadeItem->setVisible(true);
216 217 firstShade = false;
217 218 }
218 219 }
219 220
220 221 // Title, centered above the chart
221 222 QString titleText = axis()->titleText();
222 223 if (!titleText.isEmpty() && axis()->isTitleVisible()) {
223 224 QRectF dummyRect;
224 225 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0), axisGeometry().width(), Qt::Horizontal, dummyRect));
225 226
226 227 QRectF titleBoundingRect = title->boundingRect();
227 228 QPointF titleCenter = center - titleBoundingRect.center();
228 229 title->setPos(titleCenter.x(), axisGeometry().top() - titlePadding() * 2.0 - titleBoundingRect.height() - labelHeight);
229 230 }
230 231 }
231 232
232 233 Qt::Orientation PolarChartAxisAngular::orientation() const
233 234 {
234 235 return Qt::Horizontal;
235 236 }
236 237
237 238 void PolarChartAxisAngular::createItems(int count)
238 239 {
239 240 if (arrowItems().count() == 0) {
240 241 // angular axis line
241 242 QGraphicsEllipseItem *arrow = new QGraphicsEllipseItem(presenter()->rootItem());
242 243 arrow->setPen(axis()->linePen());
243 244 arrowGroup()->addToGroup(arrow);
244 245 }
245 246
246 247 for (int i = 0; i < count; ++i) {
247 248 QGraphicsLineItem *arrow = new QGraphicsLineItem(presenter()->rootItem());
248 249 QGraphicsLineItem *grid = new QGraphicsLineItem(presenter()->rootItem());
249 250 QGraphicsTextItem *label = new QGraphicsTextItem(presenter()->rootItem());
251 label->document()->setDocumentMargin(ChartPresenter::textMargin());
250 252 QGraphicsTextItem *title = titleItem();
251 253 arrow->setPen(axis()->linePen());
252 254 grid->setPen(axis()->gridLinePen());
253 255 label->setFont(axis()->labelsFont());
254 256 label->setDefaultTextColor(axis()->labelsBrush().color());
255 257 label->setRotation(axis()->labelsAngle());
256 258 title->setFont(axis()->titleFont());
257 259 title->setDefaultTextColor(axis()->titleBrush().color());
258 260 title->setHtml(axis()->titleText());
259 261 arrowGroup()->addToGroup(arrow);
260 262 gridGroup()->addToGroup(grid);
261 263 labelGroup()->addToGroup(label);
262 264 if (gridItems().size() == 1 || (((gridItems().size() + 1) % 2) && gridItems().size() > 0)) {
263 265 QGraphicsPathItem *shade = new QGraphicsPathItem(presenter()->rootItem());
264 266 shade->setPen(axis()->shadesPen());
265 267 shade->setBrush(axis()->shadesBrush());
266 268 shadeGroup()->addToGroup(shade);
267 269 }
268 270 }
269 271 }
270 272
271 273 void PolarChartAxisAngular::handleArrowPenChanged(const QPen &pen)
272 274 {
273 275 bool first = true;
274 276 foreach (QGraphicsItem *item, arrowItems()) {
275 277 if (first) {
276 278 first = false;
277 279 // First arrow item is the outer circle of axis
278 280 static_cast<QGraphicsEllipseItem *>(item)->setPen(pen);
279 281 } else {
280 282 static_cast<QGraphicsLineItem *>(item)->setPen(pen);
281 283 }
282 284 }
283 285 }
284 286
285 287 void PolarChartAxisAngular::handleGridPenChanged(const QPen &pen)
286 288 {
287 289 foreach (QGraphicsItem *item, gridItems())
288 290 static_cast<QGraphicsLineItem *>(item)->setPen(pen);
289 291 }
290 292
291 293 QSizeF PolarChartAxisAngular::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
292 294 {
293 295 Q_UNUSED(which);
294 296 Q_UNUSED(constraint);
295 297 return QSizeF(-1, -1);
296 298 }
297 299
298 300 qreal PolarChartAxisAngular::preferredAxisRadius(const QSizeF &maxSize)
299 301 {
300 302 qreal radius = maxSize.height() / 2.0;
301 303 if (maxSize.width() < maxSize.height())
302 304 radius = maxSize.width() / 2.0;
303 305
304 306 if (axis()->labelsVisible()) {
305 307 QVector<qreal> layout = calculateLayout();
306 308 if (layout.isEmpty())
307 309 return radius;
308 310
309 311 createAxisLabels(layout);
310 312 QStringList labelList = labels();
311 313 QFont font = axis()->labelsFont();
312 314
313 315 QRectF maxRect;
314 316 maxRect.setSize(maxSize);
315 317 maxRect.moveCenter(QPointF(0.0, 0.0));
316 318
317 319 // This is a horrible way to find out the maximum radius for angular axis and its labels.
318 320 // It just increments the radius down until everyhing fits the constraint size.
319 321 // Proper way would be to actually calculate it but this seems to work reasonably fast as it is.
320 322 bool nextTickVisible = false;
321 323 for (int i = 0; i < layout.size(); ) {
322 324 if ((i == layout.size() - 1)
323 325 || layout.at(i + 1) < 0.0
324 326 || layout.at(i + 1) > 360.0) {
325 327 nextTickVisible = false;
326 328 } else {
327 329 nextTickVisible = true;
328 330 }
329 331
330 332 qreal labelCoordinate = layout.at(i);
331 333 qreal labelVisible;
332 334
333 335 if (intervalAxis()) {
334 336 qreal farEdge;
335 337 if (i == (layout.size() - 1))
336 338 farEdge = 360.0;
337 339 else
338 340 farEdge = qMin(qreal(360.0), layout.at(i + 1));
339 341
340 342 // Adjust the labelCoordinate to show it if next tick is visible
341 343 if (nextTickVisible)
342 344 labelCoordinate = qMax(qreal(0.0), labelCoordinate);
343 345
344 346 labelCoordinate = (labelCoordinate + farEdge) / 2.0;
345 347 }
346 348
347 349 if (labelCoordinate < 0.0 || labelCoordinate > 360.0)
348 350 labelVisible = false;
349 351 else
350 352 labelVisible = true;
351 353
352 354 if (!labelVisible) {
353 355 i++;
354 356 continue;
355 357 }
356 358
357 359 QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), labelList.at(i), axis()->labelsAngle());
358 360 QPointF labelPoint = QLineF::fromPolar(radius + tickWidth(), 90.0 - labelCoordinate).p2();
359 361
360 362 boundingRect = moveLabelToPosition(labelCoordinate, labelPoint, boundingRect);
361 363 QRectF intersectRect = maxRect.intersected(boundingRect);
362 364 if (boundingRect.isEmpty() || intersectRect == boundingRect) {
363 365 i++;
364 366 } else {
365 367 qreal reduction(0.0);
366 368 // If there is no intersection, reduce by smallest dimension of label rect to be on the safe side
367 369 if (intersectRect.isEmpty()) {
368 370 reduction = qMin(boundingRect.height(), boundingRect.width());
369 371 } else {
370 372 // Approximate needed radius reduction is the amount label rect exceeds max rect in either dimension.
371 373 // Could be further optimized by figuring out the proper math how to calculate exact needed reduction.
372 374 reduction = qMax(boundingRect.height() - intersectRect.height(),
373 375 boundingRect.width() - intersectRect.width());
374 376 }
375 377 // Typically the approximated reduction is little low, so add one
376 378 radius -= (reduction + 1.0);
377 379
378 380 if (radius < 1.0) // safeguard
379 381 return 1.0;
380 382 }
381 383 }
382 384 }
383 385
384 386 if (!axis()->titleText().isEmpty() && axis()->isTitleVisible()) {
385 387 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText());
386 388
387 389 radius -= titlePadding() + (titleRect.height() / 2.0);
388 390 if (radius < 1.0) // safeguard
389 391 return 1.0;
390 392 }
391 393
392 394 return radius;
393 395 }
394 396
395 397 QRectF PolarChartAxisAngular::moveLabelToPosition(qreal angularCoordinate, QPointF labelPoint, QRectF labelRect) const
396 398 {
397 399 if (angularCoordinate == 0.0)
398 400 labelRect.moveCenter(labelPoint + QPointF(0, -labelRect.height() / 2.0));
399 401 else if (angularCoordinate < 90.0)
400 402 labelRect.moveBottomLeft(labelPoint);
401 403 else if (angularCoordinate == 90.0)
402 404 labelRect.moveCenter(labelPoint + QPointF(labelRect.width() / 2.0 + 2.0, 0)); // +2 so that it does not hit the radial axis
403 405 else if (angularCoordinate < 180.0)
404 406 labelRect.moveTopLeft(labelPoint);
405 407 else if (angularCoordinate == 180.0)
406 408 labelRect.moveCenter(labelPoint + QPointF(0, labelRect.height() / 2.0));
407 409 else if (angularCoordinate < 270.0)
408 410 labelRect.moveTopRight(labelPoint);
409 411 else if (angularCoordinate == 270.0)
410 412 labelRect.moveCenter(labelPoint + QPointF(-labelRect.width() / 2.0 - 2.0, 0)); // -2 so that it does not hit the radial axis
411 413 else if (angularCoordinate < 360.0)
412 414 labelRect.moveBottomRight(labelPoint);
413 415 else
414 416 labelRect.moveCenter(labelPoint + QPointF(0, -labelRect.height() / 2.0));
415 417 return labelRect;
416 418 }
417 419
418 420 #include "moc_polarchartaxisangular_p.cpp"
419 421
420 422 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,289 +1,291
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 #include <QTextDocument>
26 27
27 28 QTCOMMERCIALCHART_BEGIN_NAMESPACE
28 29
29 30 PolarChartAxisRadial::PolarChartAxisRadial(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
30 31 : PolarChartAxis(axis, item, intervalAxis)
31 32 {
32 33 }
33 34
34 35 PolarChartAxisRadial::~PolarChartAxisRadial()
35 36 {
36 37 }
37 38
38 39 void PolarChartAxisRadial::updateGeometry()
39 40 {
40 41 const QVector<qreal> &layout = this->layout();
41 42 if (layout.isEmpty())
42 43 return;
43 44
44 45 createAxisLabels(layout);
45 46 QStringList labelList = labels();
46 47 QPointF center = axisGeometry().center();
47 48 QList<QGraphicsItem *> arrowItemList = arrowItems();
48 49 QList<QGraphicsItem *> gridItemList = gridItems();
49 50 QList<QGraphicsItem *> labelItemList = labelItems();
50 51 QList<QGraphicsItem *> shadeItemList = shadeItems();
51 52 QGraphicsTextItem* title = titleItem();
52 53 qreal radius = axisGeometry().height() / 2.0;
53 54
54 55 QLineF line(center, center + QPointF(0, -radius));
55 56 QGraphicsLineItem *axisLine = static_cast<QGraphicsLineItem *>(arrowItemList.at(0));
56 57 axisLine->setLine(line);
57 58
58 59 QRectF previousLabelRect;
59 60 bool firstShade = true;
60 61 bool nextTickVisible = false;
61 62 if (layout.size())
62 63 nextTickVisible = !(layout.at(0) < 0.0 || layout.at(0) > radius);
63 64
64 65 for (int i = 0; i < layout.size(); ++i) {
65 66 qreal radialCoordinate = layout.at(i);
66 67
67 68 QGraphicsEllipseItem *gridItem = static_cast<QGraphicsEllipseItem *>(gridItemList.at(i));
68 69 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrowItemList.at(i + 1));
69 70 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labelItemList.at(i));
70 71 QGraphicsPathItem *shadeItem = 0;
71 72 if (i == 0)
72 73 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
73 74 else if (i % 2)
74 75 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at((i / 2) + 1));
75 76
76 77 // Ignore ticks outside valid range
77 78 bool currentTickVisible = nextTickVisible;
78 79 if ((i == layout.size() - 1)
79 80 || layout.at(i + 1) < 0.0
80 81 || layout.at(i + 1) > radius) {
81 82 nextTickVisible = false;
82 83 } else {
83 84 nextTickVisible = true;
84 85 }
85 86
86 87 qreal labelCoordinate = radialCoordinate;
87 88 qreal labelVisible = currentTickVisible;
88 89 qreal labelPad = labelPadding() / 2.0;
89 90 if (intervalAxis()) {
90 91 qreal farEdge;
91 92 if (i == (layout.size() - 1))
92 93 farEdge = radius;
93 94 else
94 95 farEdge = qMin(radius, layout.at(i + 1));
95 96
96 97 // Adjust the labelCoordinate to show it if next tick is visible
97 98 if (nextTickVisible)
98 99 labelCoordinate = qMax(qreal(0.0), labelCoordinate);
99 100
100 101 labelCoordinate = (labelCoordinate + farEdge) / 2.0;
101 102 if (labelCoordinate > 0.0 && labelCoordinate < radius)
102 103 labelVisible = true;
103 104 else
104 105 labelVisible = false;
105 106 }
106 107
107 108 // Radial axis label
108 109 if (axis()->labelsVisible() && labelVisible) {
109 110 labelItem->setHtml(labelList.at(i));
110 111 QRectF labelRect = labelItem->boundingRect();
111 112 QPointF labelCenter = labelRect.center();
112 113 labelItem->setTransformOriginPoint(labelCenter.x(), labelCenter.y());
113 114 QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), labelList.at(i), axis()->labelsAngle());
114 115 boundingRect.moveCenter(labelCenter);
115 116 QPointF positionDiff(labelRect.topLeft() - boundingRect.topLeft());
116 117 QPointF labelPoint = center;
117 118 if (intervalAxis())
118 119 labelPoint += QPointF(labelPad, -labelCoordinate - (boundingRect.height() / 2.0));
119 120 else
120 121 labelPoint += QPointF(labelPad, labelPad - labelCoordinate);
121 122 labelRect.moveTopLeft(labelPoint);
122 123 labelItem->setPos(labelRect.topLeft() + positionDiff);
123 124
124 125 // Label overlap detection
125 126 labelRect.setSize(boundingRect.size());
126 127 if ((i && previousLabelRect.intersects(labelRect))
127 128 || !axisGeometry().contains(labelRect)) {
128 129 labelVisible = false;
129 130 } else {
130 131 previousLabelRect = labelRect;
131 132 labelVisible = true;
132 133 }
133 134 }
134 135
135 136 labelItem->setVisible(labelVisible);
136 137 if (!currentTickVisible) {
137 138 gridItem->setVisible(false);
138 139 tickItem->setVisible(false);
139 140 if (shadeItem)
140 141 shadeItem->setVisible(false);
141 142 continue;
142 143 }
143 144
144 145 // Radial grid line
145 146 QRectF gridRect;
146 147 gridRect.setWidth(radialCoordinate * 2.0);
147 148 gridRect.setHeight(radialCoordinate * 2.0);
148 149 gridRect.moveCenter(center);
149 150
150 151 gridItem->setRect(gridRect);
151 152 gridItem->setVisible(true);
152 153
153 154 // Tick
154 155 QLineF tickLine(-tickWidth(), 0.0, tickWidth(), 0.0);
155 156 tickLine.translate(center.rx(), gridRect.top());
156 157 tickItem->setLine(tickLine);
157 158 tickItem->setVisible(true);
158 159
159 160 // Shades
160 161 if (i % 2 || (i == 0 && !nextTickVisible)) {
161 162 QPainterPath path;
162 163 if (i == 0) {
163 164 // If first tick is also the last, we need to custom fill the inner circle
164 165 // or it won't get filled.
165 166 QRectF innerCircle(0.0, 0.0, layout.at(0) * 2.0, layout.at(0) * 2.0);
166 167 innerCircle.moveCenter(center);
167 168 path.addEllipse(innerCircle);
168 169 } else {
169 170 QRectF otherGridRect;
170 171 if (!nextTickVisible) { // Last visible tick
171 172 otherGridRect = axisGeometry();
172 173 } else {
173 174 qreal otherGridRectDimension = layout.at(i + 1) * 2.0;
174 175 otherGridRect.setWidth(otherGridRectDimension);
175 176 otherGridRect.setHeight(otherGridRectDimension);
176 177 otherGridRect.moveCenter(center);
177 178 }
178 179 path.addEllipse(gridRect);
179 180 path.addEllipse(otherGridRect);
180 181
181 182 // Add additional shading in first visible shade item if there is a partial tick
182 183 // to be filled at the center (log & category axes)
183 184 if (firstShade) {
184 185 QGraphicsPathItem *specialShadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
185 186 if (layout.at(i - 1) > 0.0) {
186 187 QRectF innerCircle(0.0, 0.0, layout.at(i - 1) * 2.0, layout.at(i - 1) * 2.0);
187 188 innerCircle.moveCenter(center);
188 189 QPainterPath specialPath;
189 190 specialPath.addEllipse(innerCircle);
190 191 specialShadeItem->setPath(specialPath);
191 192 specialShadeItem->setVisible(true);
192 193 } else {
193 194 specialShadeItem->setVisible(false);
194 195 }
195 196 }
196 197 }
197 198 shadeItem->setPath(path);
198 199 shadeItem->setVisible(true);
199 200 firstShade = false;
200 201 }
201 202 }
202 203
203 204 // Title, along the 0 axis
204 205 QString titleText = axis()->titleText();
205 206 if (!titleText.isEmpty() && axis()->isTitleVisible()) {
206 207 QRectF dummyRect;
207 208 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0), radius, Qt::Horizontal, dummyRect));
208 209
209 210 QRectF titleBoundingRect = title->boundingRect();
210 211 QPointF titleCenter = titleBoundingRect.center();
211 212 QPointF arrowCenter = axisLine->boundingRect().center();
212 213 QPointF titleCenterDiff = arrowCenter - titleCenter;
213 214 title->setPos(titleCenterDiff.x() - titlePadding() - (titleBoundingRect.height() / 2.0), titleCenterDiff.y());
214 215 title->setTransformOriginPoint(titleCenter);
215 216 title->setRotation(270.0);
216 217 }
217 218
218 219 QGraphicsLayoutItem::updateGeometry();
219 220 }
220 221
221 222 Qt::Orientation PolarChartAxisRadial::orientation() const
222 223 {
223 224 return Qt::Vertical;
224 225 }
225 226
226 227 void PolarChartAxisRadial::createItems(int count)
227 228 {
228 229 if (arrowItems().count() == 0) {
229 230 // radial axis center line
230 231 QGraphicsLineItem *arrow = new LineArrowItem(this, presenter()->rootItem());
231 232 arrow->setPen(axis()->linePen());
232 233 arrowGroup()->addToGroup(arrow);
233 234 }
234 235
235 236 for (int i = 0; i < count; ++i) {
236 237 QGraphicsLineItem *arrow = new QGraphicsLineItem(presenter()->rootItem());
237 238 QGraphicsEllipseItem *grid = new QGraphicsEllipseItem(presenter()->rootItem());
238 239 QGraphicsTextItem *label = new QGraphicsTextItem(presenter()->rootItem());
240 label->document()->setDocumentMargin(ChartPresenter::textMargin());
239 241 QGraphicsTextItem *title = titleItem();
240 242 arrow->setPen(axis()->linePen());
241 243 grid->setPen(axis()->gridLinePen());
242 244 label->setFont(axis()->labelsFont());
243 245 label->setDefaultTextColor(axis()->labelsBrush().color());
244 246 label->setRotation(axis()->labelsAngle());
245 247 title->setFont(axis()->titleFont());
246 248 title->setDefaultTextColor(axis()->titleBrush().color());
247 249 title->setHtml(axis()->titleText());
248 250 arrowGroup()->addToGroup(arrow);
249 251 gridGroup()->addToGroup(grid);
250 252 labelGroup()->addToGroup(label);
251 253 if (gridItems().size() == 1 || (((gridItems().size() + 1) % 2) && gridItems().size() > 0)) {
252 254 QGraphicsPathItem *shade = new QGraphicsPathItem(presenter()->rootItem());
253 255 shade->setPen(axis()->shadesPen());
254 256 shade->setBrush(axis()->shadesBrush());
255 257 shadeGroup()->addToGroup(shade);
256 258 }
257 259 }
258 260 }
259 261
260 262 void PolarChartAxisRadial::handleArrowPenChanged(const QPen &pen)
261 263 {
262 264 foreach (QGraphicsItem *item, arrowItems())
263 265 static_cast<QGraphicsLineItem *>(item)->setPen(pen);
264 266 }
265 267
266 268 void PolarChartAxisRadial::handleGridPenChanged(const QPen &pen)
267 269 {
268 270 foreach (QGraphicsItem *item, gridItems())
269 271 static_cast<QGraphicsEllipseItem *>(item)->setPen(pen);
270 272 }
271 273
272 274 QSizeF PolarChartAxisRadial::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
273 275 {
274 276 Q_UNUSED(which);
275 277 Q_UNUSED(constraint);
276 278 return QSizeF(-1.0, -1.0);
277 279 }
278 280
279 281 qreal PolarChartAxisRadial::preferredAxisRadius(const QSizeF &maxSize)
280 282 {
281 283 qreal radius = maxSize.height() / 2.0;
282 284 if (maxSize.width() < maxSize.height())
283 285 radius = maxSize.width() / 2.0;
284 286 return radius;
285 287 }
286 288
287 289 #include "moc_polarchartaxisradial_p.cpp"
288 290
289 291 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,229 +1,229
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 QString truncatedTitle = ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0),
78 78 gridRect.height(), Qt::Horizontal, titleBoundingRect);
79 79 qreal titleSpace = availableSpace - minimumLabelWidth;
80 if (titleSpace < titleBoundingRect.width()) {
80 if (titleSpace < titleBoundingRect.height()) {
81 81 // Need to also truncate title vertically (multiline title)
82 82 bool skip = false;
83 83 if (truncatedTitle.endsWith("...")) {
84 84 if (truncatedTitle.size() == 3)
85 85 skip = true; // Already truncated to minimum
86 86 else
87 87 truncatedTitle.chop(3);
88 88 }
89 89 if (!skip)
90 90 truncatedTitle = ChartPresenter::truncatedText(axis()->titleFont(), truncatedTitle, qreal(0.0),
91 91 titleSpace, Qt::Vertical, titleBoundingRect);
92 92 }
93 93 title->setHtml(truncatedTitle);
94 94
95 95 titleBoundingRect = title->boundingRect();
96 96
97 97 QPointF center = gridRect.center() - titleBoundingRect.center();
98 98 if (axis()->alignment() == Qt::AlignLeft)
99 99 title->setPos(axisRect.left() - titleBoundingRect.width() / 2.0 + titleBoundingRect.height() / 2.0 + titlePadding(), center.y());
100 100 else if (axis()->alignment() == Qt::AlignRight)
101 101 title->setPos(axisRect.right() - titleBoundingRect.width() / 2.0 - titleBoundingRect.height() / 2.0 - titlePadding(), center.y());
102 102
103 103 title->setTransformOriginPoint(titleBoundingRect.center());
104 104 title->setRotation(270);
105 105
106 106 availableSpace -= titleBoundingRect.height();
107 107 }
108 108
109 109 for (int i = 0; i < layout.size(); ++i) {
110 110 //items
111 111 QGraphicsLineItem *gridItem = static_cast<QGraphicsLineItem *>(lines.at(i));
112 112 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrow.at(i + 1));
113 113 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labels.at(i));
114 114
115 115 //grid line
116 116 gridItem->setLine(gridRect.left(), layout[i], gridRect.right(), layout[i]);
117 117
118 118 //label text wrapping
119 119 QString text = labelList.at(i);
120 120 QRectF boundingRect;
121 121 labelItem->setHtml(ChartPresenter::truncatedText(axis()->labelsFont(), text, axis()->labelsAngle(),
122 122 availableSpace, Qt::Horizontal, boundingRect));
123 123
124 124 //label transformation origin point
125 125 const QRectF &rect = labelItem->boundingRect();
126 126 QPointF center = rect.center();
127 127 labelItem->setTransformOriginPoint(center.x(), center.y());
128 128 qreal widthDiff = rect.width() - boundingRect.width();
129 129 qreal heightDiff = rect.height() - boundingRect.height();
130 130
131 131 //ticks and label position
132 132 if (axis()->alignment() == Qt::AlignLeft) {
133 133 labelItem->setPos(axisRect.right() - rect.width() + (widthDiff / 2.0) - labelPadding(), layout[i] - center.y());
134 134 tickItem->setLine(axisRect.right() - labelPadding(), layout[i], axisRect.right(), layout[i]);
135 135 } else if (axis()->alignment() == Qt::AlignRight) {
136 136 labelItem->setPos(axisRect.left() + labelPadding() - (widthDiff / 2.0), layout[i] - center.y());
137 137 tickItem->setLine(axisRect.left(), layout[i], axisRect.left() + labelPadding(), layout[i]);
138 138 }
139 139
140 140 //label in between
141 141 bool forceHide = false;
142 142 if (intervalAxis() && (i + 1) != layout.size()) {
143 143 qreal lowerBound = qMin(layout[i], gridRect.bottom());
144 144 qreal upperBound = qMax(layout[i + 1], gridRect.top());
145 145 const qreal delta = lowerBound - upperBound;
146 146 // Hide label in case visible part of the category at the grid edge is too narrow
147 147 if (delta < boundingRect.height()
148 148 && (lowerBound == gridRect.bottom() || upperBound == gridRect.top())) {
149 149 forceHide = true;
150 150 } else {
151 151 labelItem->setPos(labelItem->pos().x() , lowerBound - (delta / 2.0) - center.y());
152 152 }
153 153 }
154 154
155 155 //label overlap detection - compensate one pixel for rounding errors
156 156 if (labelItem->pos().y() + boundingRect.height() > height || forceHide ||
157 157 (labelItem->pos().y() + (heightDiff / 2.0) - 1.0) > axisRect.bottom() ||
158 158 labelItem->pos().y() + (heightDiff / 2.0) < (axisRect.top() - 1.0)) {
159 159 labelItem->setVisible(false);
160 160 }
161 161 else {
162 162 labelItem->setVisible(true);
163 163 height=labelItem->pos().y();
164 164 }
165 165
166 166 //shades
167 167 if ((i + 1) % 2 && i > 1) {
168 168 QGraphicsRectItem *rectItem = static_cast<QGraphicsRectItem *>(shades.at(i / 2 - 1));
169 169 qreal lowerBound = qMin(layout[i - 1], gridRect.bottom());
170 170 qreal upperBound = qMax(layout[i], gridRect.top());
171 171 rectItem->setRect(gridRect.left(), upperBound, gridRect.width(), lowerBound - upperBound);
172 172 if (rectItem->rect().height() <= 0.0)
173 173 rectItem->setVisible(false);
174 174 else
175 175 rectItem->setVisible(true);
176 176 }
177 177
178 178 // check if the grid line and the axis tick should be shown
179 179 qreal y = gridItem->line().p1().y();
180 180 if ((y < gridRect.top() || y > gridRect.bottom()))
181 181 {
182 182 gridItem->setVisible(false);
183 183 tickItem->setVisible(false);
184 184 }else{
185 185 gridItem->setVisible(true);
186 186 tickItem->setVisible(true);
187 187 }
188 188
189 189 }
190 190 //begin/end grid line in case labels between
191 191 if (intervalAxis()) {
192 192 QGraphicsLineItem *gridLine;
193 193 gridLine = static_cast<QGraphicsLineItem *>(lines.at(layout.size()));
194 194 gridLine->setLine(gridRect.left(), gridRect.top(), gridRect.right(), gridRect.top());
195 195 gridLine->setVisible(true);
196 196 gridLine = static_cast<QGraphicsLineItem*>(lines.at(layout.size() + 1));
197 197 gridLine->setLine(gridRect.left(), gridRect.bottom(), gridRect.right(), gridRect.bottom());
198 198 gridLine->setVisible(true);
199 199 }
200 200 }
201 201
202 202 QSizeF VerticalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
203 203 {
204 204 Q_UNUSED(constraint);
205 205 QSizeF sh(0, 0);
206 206
207 207 if (axis()->titleText().isEmpty() || !titleItem()->isVisible())
208 208 return sh;
209 209
210 210 switch (which) {
211 211 case Qt::MinimumSize: {
212 212 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), "...");
213 213 sh = QSizeF(titleRect.height() + (titlePadding() * 2.0), titleRect.width());
214 214 break;
215 215 }
216 216 case Qt::MaximumSize:
217 217 case Qt::PreferredSize: {
218 218 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText());
219 219 sh = QSizeF(titleRect.height() + (titlePadding() * 2.0), titleRect.width());
220 220 break;
221 221 }
222 222 default:
223 223 break;
224 224 }
225 225
226 226 return sh;
227 227 }
228 228
229 229 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,221 +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 "abstractbarchartitem_p.h"
22 22 #include "bar_p.h"
23 23 #include "qbarset.h"
24 24 #include "qbarset_p.h"
25 25 #include "qabstractbarseries.h"
26 26 #include "qabstractbarseries_p.h"
27 27 #include "qchart.h"
28 28 #include "chartpresenter_p.h"
29 29 #include "charttheme_p.h"
30 30 #include "baranimation_p.h"
31 31 #include "chartdataset_p.h"
32 32 #include <QPainter>
33 #include <QTextDocument>
33 34
34 35 QTCOMMERCIALCHART_BEGIN_NAMESPACE
35 36
36 37 AbstractBarChartItem::AbstractBarChartItem(QAbstractBarSeries *series, QGraphicsItem* item) :
37 38 ChartItem(series->d_func(),item),
38 39 m_animation(0),
39 40 m_series(series)
40 41 {
41 42
42 43 setFlag(ItemClipsChildrenToShape);
43 44 connect(series->d_func(), SIGNAL(updatedLayout()), this, SLOT(handleLayoutChanged()));
44 45 connect(series->d_func(), SIGNAL(updatedBars()), this, SLOT(handleUpdatedBars()));
45 46 connect(series->d_func(), SIGNAL(labelsVisibleChanged(bool)), this, SLOT(handleLabelsVisibleChanged(bool)));
46 47 connect(series->d_func(), SIGNAL(restructuredBars()), this, SLOT(handleDataStructureChanged()));
47 48 connect(series, SIGNAL(visibleChanged()), this, SLOT(handleVisibleChanged()));
48 49 connect(series, SIGNAL(opacityChanged()), this, SLOT(handleOpacityChanged()));
49 50 setZValue(ChartPresenter::BarSeriesZValue);
50 51 handleDataStructureChanged();
51 52 handleVisibleChanged();
52 53 handleUpdatedBars();
53 54 }
54 55
55 56 AbstractBarChartItem::~AbstractBarChartItem()
56 57 {
57 58 }
58 59
59 60 void AbstractBarChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
60 61 {
61 62 Q_UNUSED(painter);
62 63 Q_UNUSED(option);
63 64 Q_UNUSED(widget);
64 65 }
65 66
66 67 QRectF AbstractBarChartItem::boundingRect() const
67 68 {
68 69 return m_rect;
69 70 }
70 71
71 72 void AbstractBarChartItem::applyLayout(const QVector<QRectF> &layout)
72 73 {
73 74 QSizeF size = geometry().size();
74 75 if (geometry().size().isValid()) {
75 76 if (m_animation) {
76 77 if (m_layout.count() == 0 || m_oldSize != size) {
77 78 initializeLayout();
78 79 m_oldSize = size;
79 80 }
80 81 m_animation->setup(m_layout, layout);
81 82 presenter()->startAnimation(m_animation);
82 83 } else {
83 84 setLayout(layout);
84 85 update();
85 86 }
86 87 }
87 88 }
88 89
89 90 void AbstractBarChartItem::setAnimation(BarAnimation *animation)
90 91 {
91 92 m_animation = animation;
92 93 }
93 94
94 95 void AbstractBarChartItem::setLayout(const QVector<QRectF> &layout)
95 96 {
96 97 if (layout.count() != m_bars.count())
97 98 return;
98 99
99 100 m_layout = layout;
100 101
101 102 for (int i = 0; i < m_bars.count(); i++) {
102 103 m_bars.at(i)->setRect(layout.at(i));
103 104 QGraphicsTextItem *label = m_labels.at(i);
104 105 label->setPos(layout.at(i).center() - label->boundingRect().center());
105 106
106 107 }
107 108 }
108 109 //handlers
109 110
110 111 void AbstractBarChartItem::handleDomainUpdated()
111 112 {
112 113 m_domainMinX = domain()->minX();
113 114 m_domainMaxX = domain()->maxX();
114 115 m_domainMinY = domain()->minY();
115 116 m_domainMaxY = domain()->maxY();
116 117
117 118 QRectF rect(QPointF(0,0),domain()->size());
118 119
119 120 if(m_rect != rect){
120 121 prepareGeometryChange();
121 122 m_rect = rect;
122 123 }
123 124
124 125 handleLayoutChanged();
125 126 }
126 127
127 128 void AbstractBarChartItem::handleLayoutChanged()
128 129 {
129 130 if ((m_rect.width() <= 0) || (m_rect.height() <= 0))
130 131 return; // rect size zero.
131 132 QVector<QRectF> layout = calculateLayout();
132 133 applyLayout(layout);
133 134 handleUpdatedBars();
134 135 }
135 136
136 137 void AbstractBarChartItem::handleLabelsVisibleChanged(bool visible)
137 138 {
138 139 foreach (QGraphicsTextItem *label, m_labels)
139 140 label->setVisible(visible);
140 141 update();
141 142 }
142 143
143 144 void AbstractBarChartItem::handleDataStructureChanged()
144 145 {
145 146 foreach (QGraphicsItem *item, childItems())
146 147 delete item;
147 148
148 149 m_bars.clear();
149 150 m_labels.clear();
150 151 m_layout.clear();
151 152
152 153 // Create new graphic items for bars
153 154 for (int c = 0; c < m_series->d_func()->categoryCount(); c++) {
154 155 for (int s = 0; s < m_series->count(); s++) {
155 156 QBarSet *set = m_series->d_func()->barsetAt(s);
156 157
157 158 // Bars
158 159 Bar *bar = new Bar(set, c, this);
159 160 m_bars.append(bar);
160 161 connect(bar, SIGNAL(clicked(int,QBarSet*)), m_series, SIGNAL(clicked(int,QBarSet*)));
161 162 connect(bar, SIGNAL(hovered(bool,QBarSet*)), m_series, SIGNAL(hovered(bool,QBarSet*)));
162 163 connect(bar, SIGNAL(clicked(int,QBarSet*)), set, SIGNAL(clicked(int)));
163 164 connect(bar, SIGNAL(hovered(bool,QBarSet*)), set, SIGNAL(hovered(bool)));
164 165 // m_layout.append(QRectF(0, 0, 1, 1));
165 166
166 167 // Labels
167 m_labels.append(new QGraphicsTextItem(this));
168 QGraphicsTextItem *newLabel = new QGraphicsTextItem(this);
169 newLabel->document()->setDocumentMargin(ChartPresenter::textMargin());
170 m_labels.append(newLabel);
168 171 }
169 172 }
170 173
171 174 if(themeManager()) themeManager()->updateSeries(m_series);
172 175 handleLayoutChanged();
173 176 handleVisibleChanged();
174 177 }
175 178
176 179 void AbstractBarChartItem::handleVisibleChanged()
177 180 {
178 181 bool visible = m_series->isVisible();
179 182 if (visible)
180 183 handleLabelsVisibleChanged(m_series->isLabelsVisible());
181 184 else
182 185 handleLabelsVisibleChanged(visible);
183 186
184 187 foreach (QGraphicsItem *bar, m_bars)
185 188 bar->setVisible(visible);
186 189 }
187 190
188 191 void AbstractBarChartItem::handleOpacityChanged()
189 192 {
190 193 foreach (QGraphicsItem *item, childItems())
191 194 item->setOpacity(m_series->opacity());
192 195 }
193 196
194 197 void AbstractBarChartItem::handleUpdatedBars()
195 198 {
196 199 // Handle changes in pen, brush, labels etc.
197 200 int categoryCount = m_series->d_func()->categoryCount();
198 201 int setCount = m_series->count();
199 202 int itemIndex(0);
200 203
201 204 for (int category = 0; category < categoryCount; category++) {
202 205 for (int set = 0; set < setCount; set++) {
203 206 QBarSetPrivate *barSet = m_series->d_func()->barsetAt(set)->d_ptr.data();
204 207 Bar *bar = m_bars.at(itemIndex);
205 208 bar->setPen(barSet->m_pen);
206 209 bar->setBrush(barSet->m_brush);
207 210 bar->update();
208 211
209 212 QGraphicsTextItem *label = m_labels.at(itemIndex);
210 213 label->setHtml(QString("%1").arg(barSet->value(category)));
211 214 label->setFont(barSet->m_labelFont);
212 215 label->setDefaultTextColor(barSet->m_labelBrush.color());
213 216 label->update();
214 217 itemIndex++;
215 218 }
216 219 }
217 220 }
218 221
219 222 #include "moc_abstractbarchartitem_p.cpp"
220 223
221 224 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,478 +1,484
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 #include "chartpresenter_p.h"
21 21 #include "qchart.h"
22 22 #include "chartitem_p.h"
23 23 #include "qchart_p.h"
24 24 #include "qabstractaxis.h"
25 25 #include "qabstractaxis_p.h"
26 26 #include "chartdataset_p.h"
27 27 #include "chartanimation_p.h"
28 28 #include "qabstractseries_p.h"
29 29 #include "qareaseries.h"
30 30 #include "chartaxiselement_p.h"
31 31 #include "chartbackground_p.h"
32 32 #include "cartesianchartlayout_p.h"
33 33 #include "polarchartlayout_p.h"
34 34 #include "charttitle_p.h"
35 35 #include <QTimer>
36 #include <QTextDocument>
36 37
37 38 QTCOMMERCIALCHART_BEGIN_NAMESPACE
38 39
39 40 ChartPresenter::ChartPresenter(QChart *chart, QChart::ChartType type)
40 41 : QObject(chart),
41 42 m_chart(chart),
42 43 m_options(QChart::NoAnimation),
43 44 m_state(ShowState),
44 45 m_background(0),
45 46 m_plotAreaBackground(0),
46 47 m_title(0)
47 48 {
48 49 if (type == QChart::ChartTypeCartesian)
49 50 m_layout = new CartesianChartLayout(this);
50 51 else if (type == QChart::ChartTypePolar)
51 52 m_layout = new PolarChartLayout(this);
52 53 Q_ASSERT(m_layout);
53 54 }
54 55
55 56 ChartPresenter::~ChartPresenter()
56 57 {
57 58
58 59 }
59 60
60 61 void ChartPresenter::setGeometry(const QRectF rect)
61 62 {
62 63 if (m_rect != rect) {
63 64 m_rect = rect;
64 65 foreach (ChartItem *chart, m_chartItems) {
65 66 chart->domain()->setSize(rect.size());
66 67 chart->setPos(rect.topLeft());
67 68 }
68 69 }
69 70 }
70 71
71 72 QRectF ChartPresenter::geometry() const
72 73 {
73 74 return m_rect;
74 75 }
75 76
76 77 void ChartPresenter::handleAxisAdded(QAbstractAxis *axis)
77 78 {
78 79 axis->d_ptr->initializeGraphics(rootItem());
79 80 axis->d_ptr->initializeAnimations(m_options);
80 81 ChartAxisElement *item = axis->d_ptr->axisItem();
81 82 item->setPresenter(this);
82 83 item->setThemeManager(m_chart->d_ptr->m_themeManager);
83 84 m_axisItems<<item;
84 85 m_axes<<axis;
85 86 m_layout->invalidate();
86 87 }
87 88
88 89 void ChartPresenter::handleAxisRemoved(QAbstractAxis *axis)
89 90 {
90 91 ChartAxisElement *item = axis->d_ptr->m_item.take();
91 92 item->hide();
92 93 item->disconnect();
93 94 item->deleteLater();
94 95 m_axisItems.removeAll(item);
95 96 m_axes.removeAll(axis);
96 97 m_layout->invalidate();
97 98 }
98 99
99 100
100 101 void ChartPresenter::handleSeriesAdded(QAbstractSeries *series)
101 102 {
102 103 series->d_ptr->initializeGraphics(rootItem());
103 104 series->d_ptr->initializeAnimations(m_options);
104 105 ChartItem *chart = series->d_ptr->chartItem();
105 106 chart->setPresenter(this);
106 107 chart->setThemeManager(m_chart->d_ptr->m_themeManager);
107 108 chart->domain()->setSize(m_rect.size());
108 109 chart->setPos(m_rect.topLeft());
109 110 chart->handleDomainUpdated(); //this could be moved to intializeGraphics when animator is refactored
110 111 m_chartItems<<chart;
111 112 m_series<<series;
112 113 m_layout->invalidate();
113 114 }
114 115
115 116 void ChartPresenter::handleSeriesRemoved(QAbstractSeries *series)
116 117 {
117 118 ChartItem *chart = series->d_ptr->m_item.take();
118 119 chart->hide();
119 120 chart->disconnect();
120 121 chart->deleteLater();
121 122 m_chartItems.removeAll(chart);
122 123 m_series.removeAll(series);
123 124 m_layout->invalidate();
124 125 }
125 126
126 127 void ChartPresenter::setAnimationOptions(QChart::AnimationOptions options)
127 128 {
128 129 if (m_options != options) {
129 130 QChart::AnimationOptions oldOptions = m_options;
130 131 m_options = options;
131 132 if (options.testFlag(QChart::SeriesAnimations) != oldOptions.testFlag(QChart::SeriesAnimations)) {
132 133 foreach (QAbstractSeries *series, m_series)
133 134 series->d_ptr->initializeAnimations(m_options);
134 135 }
135 136 if (options.testFlag(QChart::GridAxisAnimations) != oldOptions.testFlag(QChart::GridAxisAnimations)) {
136 137 foreach (QAbstractAxis *axis, m_axes)
137 138 axis->d_ptr->initializeAnimations(m_options);
138 139 }
139 140 m_layout->invalidate(); // So that existing animations don't just stop halfway
140 141 }
141 142 }
142 143
143 144 void ChartPresenter::setState(State state,QPointF point)
144 145 {
145 146 m_state=state;
146 147 m_statePoint=point;
147 148 }
148 149
149 150 QChart::AnimationOptions ChartPresenter::animationOptions() const
150 151 {
151 152 return m_options;
152 153 }
153 154
154 155 void ChartPresenter::createBackgroundItem()
155 156 {
156 157 if (!m_background) {
157 158 m_background = new ChartBackground(rootItem());
158 159 m_background->setPen(Qt::NoPen); // Theme doesn't touch pen so don't use default
159 160 m_background->setBrush(QChartPrivate::defaultBrush());
160 161 m_background->setZValue(ChartPresenter::BackgroundZValue);
161 162 }
162 163 }
163 164
164 165 void ChartPresenter::createPlotAreaBackgroundItem()
165 166 {
166 167 if (!m_plotAreaBackground) {
167 168 if (m_chart->chartType() == QChart::ChartTypeCartesian)
168 169 m_plotAreaBackground = new QGraphicsRectItem(rootItem());
169 170 else
170 171 m_plotAreaBackground = new QGraphicsEllipseItem(rootItem());
171 172 // Use transparent pen instead of Qt::NoPen, as Qt::NoPen causes
172 173 // antialising artifacts with axis lines for some reason.
173 174 m_plotAreaBackground->setPen(QPen(Qt::transparent));
174 175 m_plotAreaBackground->setBrush(Qt::NoBrush);
175 176 m_plotAreaBackground->setZValue(ChartPresenter::PlotAreaZValue);
176 177 m_plotAreaBackground->setVisible(false);
177 178 }
178 179 }
179 180
180 181 void ChartPresenter::createTitleItem()
181 182 {
182 183 if (!m_title) {
183 184 m_title = new ChartTitle(rootItem());
184 185 m_title->setZValue(ChartPresenter::BackgroundZValue);
185 186 }
186 187 }
187 188
188 189 void ChartPresenter::startAnimation(ChartAnimation *animation)
189 190 {
190 191 animation->stop();
191 192 QTimer::singleShot(0, animation, SLOT(startChartAnimation()));
192 193 }
193 194
194 195 void ChartPresenter::setBackgroundBrush(const QBrush &brush)
195 196 {
196 197 createBackgroundItem();
197 198 m_background->setBrush(brush);
198 199 m_layout->invalidate();
199 200 }
200 201
201 202 QBrush ChartPresenter::backgroundBrush() const
202 203 {
203 204 if (!m_background)
204 205 return QBrush();
205 206 return m_background->brush();
206 207 }
207 208
208 209 void ChartPresenter::setBackgroundPen(const QPen &pen)
209 210 {
210 211 createBackgroundItem();
211 212 m_background->setPen(pen);
212 213 m_layout->invalidate();
213 214 }
214 215
215 216 QPen ChartPresenter::backgroundPen() const
216 217 {
217 218 if (!m_background)
218 219 return QPen();
219 220 return m_background->pen();
220 221 }
221 222
222 223 void ChartPresenter::setBackgroundRoundness(qreal diameter)
223 224 {
224 225 createBackgroundItem();
225 226 m_background->setDiameter(diameter);
226 227 m_layout->invalidate();
227 228 }
228 229
229 230 qreal ChartPresenter::backgroundRoundness() const
230 231 {
231 232 if (!m_background)
232 233 return 0;
233 234 return m_background->diameter();
234 235 }
235 236
236 237 void ChartPresenter::setPlotAreaBackgroundBrush(const QBrush &brush)
237 238 {
238 239 createPlotAreaBackgroundItem();
239 240 m_plotAreaBackground->setBrush(brush);
240 241 m_layout->invalidate();
241 242 }
242 243
243 244 QBrush ChartPresenter::plotAreaBackgroundBrush() const
244 245 {
245 246 if (!m_plotAreaBackground)
246 247 return QBrush();
247 248 return m_plotAreaBackground->brush();
248 249 }
249 250
250 251 void ChartPresenter::setPlotAreaBackgroundPen(const QPen &pen)
251 252 {
252 253 createPlotAreaBackgroundItem();
253 254 m_plotAreaBackground->setPen(pen);
254 255 m_layout->invalidate();
255 256 }
256 257
257 258 QPen ChartPresenter::plotAreaBackgroundPen() const
258 259 {
259 260 if (!m_plotAreaBackground)
260 261 return QPen();
261 262 return m_plotAreaBackground->pen();
262 263 }
263 264
264 265 void ChartPresenter::setTitle(const QString &title)
265 266 {
266 267 createTitleItem();
267 268 m_title->setText(title);
268 269 m_layout->invalidate();
269 270 }
270 271
271 272 QString ChartPresenter::title() const
272 273 {
273 274 if (!m_title)
274 275 return QString();
275 276 return m_title->text();
276 277 }
277 278
278 279 void ChartPresenter::setTitleFont(const QFont &font)
279 280 {
280 281 createTitleItem();
281 282 m_title->setFont(font);
282 283 m_layout->invalidate();
283 284 }
284 285
285 286 QFont ChartPresenter::titleFont() const
286 287 {
287 288 if (!m_title)
288 289 return QFont();
289 290 return m_title->font();
290 291 }
291 292
292 293 void ChartPresenter::setTitleBrush(const QBrush &brush)
293 294 {
294 295 createTitleItem();
295 296 m_title->setDefaultTextColor(brush.color());
296 297 m_layout->invalidate();
297 298 }
298 299
299 300 QBrush ChartPresenter::titleBrush() const
300 301 {
301 302 if (!m_title)
302 303 return QBrush();
303 304 return QBrush(m_title->defaultTextColor());
304 305 }
305 306
306 307 void ChartPresenter::setBackgroundVisible(bool visible)
307 308 {
308 309 createBackgroundItem();
309 310 m_background->setVisible(visible);
310 311 }
311 312
312 313
313 314 bool ChartPresenter::isBackgroundVisible() const
314 315 {
315 316 if (!m_background)
316 317 return false;
317 318 return m_background->isVisible();
318 319 }
319 320
320 321 void ChartPresenter::setPlotAreaBackgroundVisible(bool visible)
321 322 {
322 323 createPlotAreaBackgroundItem();
323 324 m_plotAreaBackground->setVisible(visible);
324 325 }
325 326
326 327 bool ChartPresenter::isPlotAreaBackgroundVisible() const
327 328 {
328 329 if (!m_plotAreaBackground)
329 330 return false;
330 331 return m_plotAreaBackground->isVisible();
331 332 }
332 333
333 334 void ChartPresenter::setBackgroundDropShadowEnabled(bool enabled)
334 335 {
335 336 createBackgroundItem();
336 337 m_background->setDropShadowEnabled(enabled);
337 338 }
338 339
339 340 bool ChartPresenter::isBackgroundDropShadowEnabled() const
340 341 {
341 342 if (!m_background)
342 343 return false;
343 344 return m_background->isDropShadowEnabled();
344 345 }
345 346
346 347
347 348 AbstractChartLayout *ChartPresenter::layout()
348 349 {
349 350 return m_layout;
350 351 }
351 352
352 353 QLegend *ChartPresenter::legend()
353 354 {
354 355 return m_chart->legend();
355 356 }
356 357
357 358 void ChartPresenter::setVisible(bool visible)
358 359 {
359 360 m_chart->setVisible(visible);
360 361 }
361 362
362 363 ChartBackground *ChartPresenter::backgroundElement()
363 364 {
364 365 return m_background;
365 366 }
366 367
367 368 QAbstractGraphicsShapeItem *ChartPresenter::plotAreaElement()
368 369 {
369 370 return m_plotAreaBackground;
370 371 }
371 372
372 373 QList<ChartAxisElement *> ChartPresenter::axisItems() const
373 374 {
374 375 return m_axisItems;
375 376 }
376 377
377 378 QList<ChartItem *> ChartPresenter::chartItems() const
378 379 {
379 380 return m_chartItems;
380 381 }
381 382
382 383 ChartTitle *ChartPresenter::titleElement()
383 384 {
384 385 return m_title;
385 386 }
386 387
387 388 QRectF ChartPresenter::textBoundingRect(const QFont &font, const QString &text, qreal angle)
388 389 {
389 390 static QGraphicsTextItem dummyTextItem;
391 static bool initMargin = true;
392 if (initMargin) {
393 dummyTextItem.document()->setDocumentMargin(textMargin());
394 initMargin = false;
395 }
390 396
391 397 dummyTextItem.setFont(font);
392 398 dummyTextItem.setHtml(text);
393 399 QRectF boundingRect = dummyTextItem.boundingRect();
394 400
395 401 // Take rotation into account
396 402 if (angle) {
397 403 QTransform transform;
398 404 transform.rotate(angle);
399 405 boundingRect = transform.mapRect(boundingRect);
400 406 }
401 407
402 408 return boundingRect;
403 409 }
404 410
405 411 // boundingRect parameter returns the rotated bounding rect of the text
406 412 QString ChartPresenter::truncatedText(const QFont &font, const QString &text, qreal angle,
407 413 qreal maxSize, Qt::Orientation constraintOrientation,
408 414 QRectF &boundingRect)
409 415 {
410 416 QString truncatedString(text);
411 417 boundingRect = textBoundingRect(font, truncatedString, angle);
412 418 qreal checkDimension = ((constraintOrientation == Qt::Horizontal)
413 419 ? boundingRect.width() : boundingRect.height());
414 420 if (checkDimension > maxSize) {
415 421 // It can be assumed that almost any amount of string manipulation is faster
416 422 // than calculating one bounding rectangle, so first prepare a list of truncated strings
417 423 // to try.
418 424 static const char *truncateMatchString = "&#?[0-9a-zA-Z]*;$";
419 425 static QRegExp truncateMatcher(truncateMatchString);
420 426
421 427 QVector<QString> testStrings(text.length());
422 428 int count(0);
423 429 static QLatin1Char closeTag('>');
424 430 static QLatin1Char openTag('<');
425 431 static QLatin1Char semiColon(';');
426 432 static QLatin1String ellipsis("...");
427 433 while (truncatedString.length() > 1) {
428 434 int chopIndex(-1);
429 435 int chopCount(1);
430 436 QChar lastChar(truncatedString.at(truncatedString.length() - 1));
431 437
432 438 if (lastChar == closeTag)
433 439 chopIndex = truncatedString.lastIndexOf(openTag);
434 440 else if (lastChar == semiColon)
435 441 chopIndex = truncateMatcher.indexIn(truncatedString, 0);
436 442
437 443 if (chopIndex != -1)
438 444 chopCount = truncatedString.length() - chopIndex;
439 445 truncatedString.chop(chopCount);
440 446 testStrings[count] = truncatedString + ellipsis;
441 447 count++;
442 448 }
443 449
444 450 // Binary search for best fit
445 451 int minIndex(0);
446 452 int maxIndex(count - 1);
447 453 int bestIndex(count);
448 454 QRectF checkRect;
449 455 while (maxIndex >= minIndex) {
450 456 int mid = (maxIndex + minIndex) / 2;
451 457 checkRect = textBoundingRect(font, testStrings.at(mid), angle);
452 458 checkDimension = ((constraintOrientation == Qt::Horizontal)
453 459 ? checkRect.width() : checkRect.height());
454 460 if (checkDimension > maxSize) {
455 461 // Checked index too large, all under this are also too large
456 462 minIndex = mid + 1;
457 463 } else {
458 464 // Checked index fits, all over this also fit
459 465 maxIndex = mid - 1;
460 466 bestIndex = mid;
461 467 boundingRect = checkRect;
462 468 }
463 469 }
464 470 // Default to "..." if nothing fits
465 471 if (bestIndex == count) {
466 472 boundingRect = textBoundingRect(font, ellipsis, angle);
467 473 truncatedString = ellipsis;
468 474 } else {
469 475 truncatedString = testStrings.at(bestIndex);
470 476 }
471 477 }
472 478
473 479 return truncatedString;
474 480 }
475 481
476 482 #include "moc_chartpresenter_p.cpp"
477 483
478 484 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,179 +1,180
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 // W A R N I N G
22 22 // -------------
23 23 //
24 24 // This file is not part of the Qt Enterprise Chart API. It exists purely as an
25 25 // implementation detail. This header file may change from version to
26 26 // version without notice, or even be removed.
27 27 //
28 28 // We mean it.
29 29
30 30 #ifndef CHARTPRESENTER_H
31 31 #define CHARTPRESENTER_H
32 32
33 33 #include "qchartglobal.h"
34 34 #include "qchart.h" //because of QChart::ChartThemeId
35 35 #include <QRectF>
36 36 #include <QMargins>
37 37
38 38 QTCOMMERCIALCHART_BEGIN_NAMESPACE
39 39
40 40 class ChartItem;
41 41 class AxisItem;
42 42 class QAbstractSeries;
43 43 class ChartDataSet;
44 44 class AbstractDomain;
45 45 class ChartAxisElement;
46 46 class ChartAnimator;
47 47 class ChartBackground;
48 48 class ChartTitle;
49 49 class ChartAnimation;
50 50 class AbstractChartLayout;
51 51
52 52 class ChartPresenter: public QObject
53 53 {
54 54 Q_OBJECT
55 55 public:
56 56 enum ZValues {
57 57 BackgroundZValue = -1,
58 58 PlotAreaZValue,
59 59 ShadesZValue,
60 60 GridZValue,
61 61 AxisZValue,
62 62 SeriesZValue,
63 63 LineChartZValue = SeriesZValue,
64 64 SplineChartZValue = SeriesZValue,
65 65 BarSeriesZValue = SeriesZValue,
66 66 ScatterSeriesZValue = SeriesZValue,
67 67 PieSeriesZValue = SeriesZValue,
68 68 BoxPlotSeriesZValue = SeriesZValue,
69 69 LegendZValue,
70 70 TopMostZValue
71 71 };
72 72
73 73 enum State {
74 74 ShowState,
75 75 ScrollUpState,
76 76 ScrollDownState,
77 77 ScrollLeftState,
78 78 ScrollRightState,
79 79 ZoomInState,
80 80 ZoomOutState
81 81 };
82 82
83 83 ChartPresenter(QChart *chart, QChart::ChartType type);
84 84 virtual ~ChartPresenter();
85 85
86 86
87 87 void setGeometry(QRectF rect);
88 88 QRectF geometry() const;
89 89
90 90 QGraphicsItem *rootItem(){ return m_chart; }
91 91 ChartBackground *backgroundElement();
92 92 QAbstractGraphicsShapeItem *plotAreaElement();
93 93 ChartTitle *titleElement();
94 94 QList<ChartAxisElement *> axisItems() const;
95 95 QList<ChartItem *> chartItems() const;
96 96
97 97 QLegend *legend();
98 98
99 99 void setBackgroundBrush(const QBrush &brush);
100 100 QBrush backgroundBrush() const;
101 101
102 102 void setBackgroundPen(const QPen &pen);
103 103 QPen backgroundPen() const;
104 104
105 105 void setBackgroundRoundness(qreal diameter);
106 106 qreal backgroundRoundness() const;
107 107
108 108 void setPlotAreaBackgroundBrush(const QBrush &brush);
109 109 QBrush plotAreaBackgroundBrush() const;
110 110
111 111 void setPlotAreaBackgroundPen(const QPen &pen);
112 112 QPen plotAreaBackgroundPen() const;
113 113
114 114 void setTitle(const QString &title);
115 115 QString title() const;
116 116
117 117 void setTitleFont(const QFont &font);
118 118 QFont titleFont() const;
119 119
120 120 void setTitleBrush(const QBrush &brush);
121 121 QBrush titleBrush() const;
122 122
123 123 void setBackgroundVisible(bool visible);
124 124 bool isBackgroundVisible() const;
125 125
126 126 void setPlotAreaBackgroundVisible(bool visible);
127 127 bool isPlotAreaBackgroundVisible() const;
128 128
129 129 void setBackgroundDropShadowEnabled(bool enabled);
130 130 bool isBackgroundDropShadowEnabled() const;
131 131
132 132 void setVisible(bool visible);
133 133
134 134 void setAnimationOptions(QChart::AnimationOptions options);
135 135 QChart::AnimationOptions animationOptions() const;
136 136
137 137 void startAnimation(ChartAnimation *animation);
138 138
139 139 void setState(State state,QPointF point);
140 140 State state() const { return m_state; }
141 141 QPointF statePoint() const { return m_statePoint; }
142 142 AbstractChartLayout *layout();
143 143
144 144 QChart::ChartType chartType() const { return m_chart->chartType(); }
145 145 QChart *chart() { return m_chart; }
146 146
147 147 static QRectF textBoundingRect(const QFont &font, const QString &text, qreal angle = 0.0);
148 148 static QString truncatedText(const QFont &font, const QString &text, qreal angle, qreal maxSize,
149 149 Qt::Orientation constraintOrientation, QRectF &boundingRect);
150 inline static qreal textMargin() { return qreal(0.5); }
150 151 private:
151 152 void createBackgroundItem();
152 153 void createPlotAreaBackgroundItem();
153 154 void createTitleItem();
154 155
155 156 public Q_SLOTS:
156 157 void handleSeriesAdded(QAbstractSeries *series);
157 158 void handleSeriesRemoved(QAbstractSeries *series);
158 159 void handleAxisAdded(QAbstractAxis *axis);
159 160 void handleAxisRemoved(QAbstractAxis *axis);
160 161
161 162 private:
162 163 QChart *m_chart;
163 164 QList<ChartItem *> m_chartItems;
164 165 QList<ChartAxisElement *> m_axisItems;
165 166 QList<QAbstractSeries *> m_series;
166 167 QList<QAbstractAxis *> m_axes;
167 168 QChart::AnimationOptions m_options;
168 169 State m_state;
169 170 QPointF m_statePoint;
170 171 AbstractChartLayout *m_layout;
171 172 ChartBackground *m_background;
172 173 QAbstractGraphicsShapeItem *m_plotAreaBackground;
173 174 ChartTitle *m_title;
174 175 QRectF m_rect;
175 176 };
176 177
177 178 QTCOMMERCIALCHART_END_NAMESPACE
178 179
179 180 #endif /* CHARTPRESENTER_H */
@@ -1,87 +1,88
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 #include <QTextDocument>
26 27
27 28 QTCOMMERCIALCHART_BEGIN_NAMESPACE
28 29
29 30 ChartTitle::ChartTitle(QGraphicsItem *parent)
30 31 : QGraphicsTextItem(parent)
31 32 {
32
33 document()->setDocumentMargin(ChartPresenter::textMargin());
33 34 }
34 35
35 36 ChartTitle::~ChartTitle()
36 37 {
37 38
38 39 }
39 40
40 41 void ChartTitle::setText(const QString &text)
41 42 {
42 43 m_text = text;
43 44 }
44 45
45 46 QString ChartTitle::text() const
46 47 {
47 48 return m_text;
48 49 }
49 50
50 51 void ChartTitle::setGeometry(const QRectF &rect)
51 52 {
52 53 QRectF dummyRect;
53 54 QGraphicsTextItem::setHtml(ChartPresenter::truncatedText(font(), m_text, qreal(0.0), rect.width(), Qt::Horizontal, dummyRect));
54 55 setPos(rect.topLeft());
55 56 }
56 57
57 58
58 59 QSizeF ChartTitle::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
59 60 {
60 61 Q_UNUSED(constraint);
61 62 QSizeF sh;
62 63
63 64 switch (which) {
64 65 case Qt::MinimumSize: {
65 66 QRectF titleRect = ChartPresenter::textBoundingRect(font(), "...");
66 67 sh = QSizeF(titleRect.width(), titleRect.height());
67 68 break;
68 69 }
69 70 case Qt::PreferredSize:
70 71 case Qt::MaximumSize: {
71 72 QRectF titleRect = ChartPresenter::textBoundingRect(font(), m_text);
72 73 sh = QSizeF(titleRect.width(), titleRect.height());
73 74 break;
74 75 }
75 76 case Qt::MinimumDescent: {
76 77 QFontMetrics fn(font());
77 78 sh = QSizeF(0, fn.descent());
78 79 break;
79 80 }
80 81 default:
81 82 break;
82 83 }
83 84
84 85 return sh;
85 86 }
86 87
87 88 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,186 +1,189
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 #include <QTextDocument>
24 25
25 26 #include "qlegend.h"
26 27 #include "qlegend_p.h"
27 28 #include "qlegendmarker.h"
28 29 #include "qlegendmarker_p.h"
29 30 #include "legendmarkeritem_p.h"
30 31 #include "chartpresenter_p.h"
31 32
32 33 QTCOMMERCIALCHART_BEGIN_NAMESPACE
33 34
34 35 LegendMarkerItem::LegendMarkerItem(QLegendMarkerPrivate *marker, QGraphicsObject *parent) :
35 36 QGraphicsObject(parent),
36 37 m_marker(marker),
37 38 m_markerRect(0,0,10.0,10.0),
38 39 m_boundingRect(0,0,0,0),
39 40 m_textItem(new QGraphicsTextItem(this)),
40 41 m_rectItem(new QGraphicsRectItem(this)),
41 m_margin(1),
42 m_space(2),
42 m_margin(3),
43 m_space(4),
43 44 m_hovering(false),
44 45 m_pressPos(0, 0)
45 46 {
46 47 m_rectItem->setRect(m_markerRect);
48 m_textItem->document()->setDocumentMargin(ChartPresenter::textMargin());
47 49 setAcceptHoverEvents(true);
48 50 }
49 51
50 52 LegendMarkerItem::~LegendMarkerItem()
51 53 {
52 54 if (m_hovering) {
53 55 emit m_marker->q_ptr->hovered(false);
54 56 }
55 57 }
56 58
57 59 void LegendMarkerItem::setPen(const QPen &pen)
58 60 {
59 61 m_rectItem->setPen(pen);
60 62 }
61 63
62 64 QPen LegendMarkerItem::pen() const
63 65 {
64 66 return m_rectItem->pen();
65 67 }
66 68
67 69 void LegendMarkerItem::setBrush(const QBrush &brush)
68 70 {
69 71 m_rectItem->setBrush(brush);
70 72 }
71 73
72 74 QBrush LegendMarkerItem::brush() const
73 75 {
74 76 return m_rectItem->brush();
75 77 }
76 78
77 79 void LegendMarkerItem::setFont(const QFont &font)
78 80 {
79 81 m_textItem->setFont(font);
80 82 QFontMetrics fn(font);
81 83 m_markerRect = QRectF(0,0,fn.height()/2,fn.height()/2);
82 84 updateGeometry();
83 85 }
84 86
85 87 QFont LegendMarkerItem::font() const
86 88 {
87 89 return m_textItem->font();
88 90 }
89 91
90 92 void LegendMarkerItem::setLabel(const QString label)
91 93 {
92 94 m_label = label;
93 95 updateGeometry();
94 96 }
95 97
96 98 QString LegendMarkerItem::label() const
97 99 {
98 100 return m_label;
99 101 }
100 102
101 103 void LegendMarkerItem::setLabelBrush(const QBrush &brush)
102 104 {
103 105 m_textItem->setDefaultTextColor(brush.color());
104 106 }
105 107
106 108 QBrush LegendMarkerItem::labelBrush() const
107 109 {
108 110 return QBrush(m_textItem->defaultTextColor());
109 111 }
110 112
111 113 void LegendMarkerItem::setGeometry(const QRectF &rect)
112 114 {
113 115 qreal width = rect.width();
114 116 qreal x = m_margin + m_markerRect.width() + m_space + m_margin;
115 117 QRectF truncatedRect;
116 118
117 119 m_textItem->setHtml(ChartPresenter::truncatedText(m_textItem->font(), m_label, qreal(0.0), width - x, Qt::Horizontal, truncatedRect));
118 120
119 121 qreal y = qMax(m_markerRect.height() + 2 * m_margin, truncatedRect.height() + 2 * m_margin);
120 122
121 123 const QRectF &textRect = m_textItem->boundingRect();
122 124
123 125 m_textItem->setPos(x - m_margin, y / 2 - textRect.height() / 2);
124 126 m_rectItem->setRect(m_markerRect);
125 m_rectItem->setPos(m_margin, y / 2 - m_markerRect.height() / 2);
127 // 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());
126 129
127 130 prepareGeometryChange();
128 131 m_boundingRect = QRectF(0, 0, x + textRect.width() + m_margin, y);
129 132 }
130 133
131 134 QRectF LegendMarkerItem::boundingRect() const
132 135 {
133 136 return m_boundingRect;
134 137 }
135 138
136 139 void LegendMarkerItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
137 140 {
138 141 Q_UNUSED(option)
139 142 Q_UNUSED(widget)
140 143 Q_UNUSED(painter)
141 144 }
142 145
143 146 QSizeF LegendMarkerItem::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const
144 147 {
145 148 Q_UNUSED(constraint)
146 149
147 150 QSizeF sh;
148 151
149 152 switch (which) {
150 153 case Qt::MinimumSize: {
151 154 QRectF labelRect = ChartPresenter::textBoundingRect(m_textItem->font(), "...");
152 155 sh = QSizeF(labelRect.width() + (2.0 * m_margin) + m_space + m_markerRect.width(),
153 156 qMax(m_markerRect.height(), labelRect.height()) + (2.0 * m_margin));
154 157 break;
155 158 }
156 159 case Qt::PreferredSize: {
157 160 QRectF labelRect = ChartPresenter::textBoundingRect(m_textItem->font(), m_label);
158 161 sh = QSizeF(labelRect.width() + (2.0 * m_margin) + m_space + m_markerRect.width(),
159 162 qMax(m_markerRect.height(), labelRect.height()) + (2.0 * m_margin));
160 163 break;
161 164 }
162 165 default:
163 166 break;
164 167 }
165 168
166 169 return sh;
167 170 }
168 171
169 172 void LegendMarkerItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
170 173 {
171 174 Q_UNUSED(event)
172 175 m_hovering = true;
173 176 emit m_marker->q_ptr->hovered(true);
174 177 }
175 178
176 179 void LegendMarkerItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
177 180 {
178 181 Q_UNUSED(event)
179 182 m_hovering = false;
180 183 emit m_marker->q_ptr->hovered(false);
181 184 }
182 185
183 186
184 187 #include "moc_legendmarkeritem_p.cpp"
185 188
186 189 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now