##// END OF EJS Templates
Fix label clipping issues using QOpenGLWidget as ChartView viewport...
Miikka Heikkinen -
r2828:7557d1ea51b5
parent child
Show More
@@ -1,374 +1,377
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd
3 ** Copyright (C) 2015 The Qt Company Ltd
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to The Qt Company, please use contact form at http://qt.io
5 ** For any questions to The Qt Company, please use contact form at http://qt.io
6 **
6 **
7 ** This file is part of the Qt Charts module.
7 ** This file is part of the Qt Charts module.
8 **
8 **
9 ** Licensees holding valid commercial license for Qt may use this file in
9 ** Licensees holding valid commercial license for Qt may use this file in
10 ** accordance with the Qt License Agreement provided with the Software
10 ** accordance with the Qt License Agreement provided with the Software
11 ** or, alternatively, in accordance with the terms contained in a written
11 ** or, alternatively, in accordance with the terms contained in a written
12 ** agreement between you and The Qt Company.
12 ** agreement between you and The Qt Company.
13 **
13 **
14 ** If you have questions regarding the use of this file, please use
14 ** If you have questions regarding the use of this file, please use
15 ** contact form at http://qt.io
15 ** contact form at http://qt.io
16 **
16 **
17 ****************************************************************************/
17 ****************************************************************************/
18
18
19 #include <private/horizontalaxis_p.h>
19 #include <private/horizontalaxis_p.h>
20 #include <private/qabstractaxis_p.h>
20 #include <private/qabstractaxis_p.h>
21 #include <private/chartpresenter_p.h>
21 #include <private/chartpresenter_p.h>
22 #include <QtCharts/QCategoryAxis>
22 #include <QtCharts/QCategoryAxis>
23 #include <QtCore/QtMath>
23 #include <QtCore/QtMath>
24 #include <QtCore/QDebug>
24 #include <QtCore/QDebug>
25
25
26 QT_CHARTS_BEGIN_NAMESPACE
26 QT_CHARTS_BEGIN_NAMESPACE
27
27
28 HorizontalAxis::HorizontalAxis(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
28 HorizontalAxis::HorizontalAxis(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
29 : CartesianChartAxis(axis, item, intervalAxis)
29 : CartesianChartAxis(axis, item, intervalAxis)
30 {
30 {
31 }
31 }
32
32
33 HorizontalAxis::~HorizontalAxis()
33 HorizontalAxis::~HorizontalAxis()
34 {
34 {
35 }
35 }
36
36
37 void HorizontalAxis::updateGeometry()
37 void HorizontalAxis::updateGeometry()
38 {
38 {
39 const QVector<qreal> &layout = ChartAxisElement::layout();
39 const QVector<qreal> &layout = ChartAxisElement::layout();
40
40
41 if (layout.isEmpty() && axis()->type() != QAbstractAxis::AxisTypeLogValue)
41 if (layout.isEmpty() && axis()->type() != QAbstractAxis::AxisTypeLogValue)
42 return;
42 return;
43
43
44 QStringList labelList = labels();
44 QStringList labelList = labels();
45
45
46 QList<QGraphicsItem *> labels = labelItems();
46 QList<QGraphicsItem *> labels = labelItems();
47 QList<QGraphicsItem *> arrow = arrowItems();
47 QList<QGraphicsItem *> arrow = arrowItems();
48 QGraphicsTextItem *title = titleItem();
48 QGraphicsTextItem *title = titleItem();
49
49
50 Q_ASSERT(labels.size() == labelList.size());
50 Q_ASSERT(labels.size() == labelList.size());
51 Q_ASSERT(layout.size() == labelList.size());
51 Q_ASSERT(layout.size() == labelList.size());
52
52
53 const QRectF &axisRect = axisGeometry();
53 const QRectF &axisRect = axisGeometry();
54 const QRectF &gridRect = gridGeometry();
54 const QRectF &gridRect = gridGeometry();
55
55
56 //arrow
56 //arrow
57 QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem *>(arrow.at(0));
57 QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem *>(arrow.at(0));
58
58
59 if (axis()->alignment() == Qt::AlignTop)
59 if (axis()->alignment() == Qt::AlignTop)
60 arrowItem->setLine(gridRect.left(), axisRect.bottom(), gridRect.right(), axisRect.bottom());
60 arrowItem->setLine(gridRect.left(), axisRect.bottom(), gridRect.right(), axisRect.bottom());
61 else if (axis()->alignment() == Qt::AlignBottom)
61 else if (axis()->alignment() == Qt::AlignBottom)
62 arrowItem->setLine(gridRect.left(), axisRect.top(), gridRect.right(), axisRect.top());
62 arrowItem->setLine(gridRect.left(), axisRect.top(), gridRect.right(), axisRect.top());
63
63
64 qreal width = 0;
64 qreal width = 0;
65 const QLatin1String ellipsis("...");
65 const QLatin1String ellipsis("...");
66
66
67 //title
67 //title
68 QRectF titleBoundingRect;
68 QRectF titleBoundingRect;
69 QString titleText = axis()->titleText();
69 QString titleText = axis()->titleText();
70 qreal availableSpace = axisRect.height() - labelPadding();
70 qreal availableSpace = axisRect.height() - labelPadding();
71 if (!titleText.isEmpty() && titleItem()->isVisible()) {
71 if (!titleText.isEmpty() && titleItem()->isVisible()) {
72 availableSpace -= titlePadding() * 2.0;
72 availableSpace -= titlePadding() * 2.0;
73 qreal minimumLabelHeight = ChartPresenter::textBoundingRect(axis()->labelsFont(),
73 qreal minimumLabelHeight = ChartPresenter::textBoundingRect(axis()->labelsFont(),
74 QStringLiteral("...")).height();
74 QStringLiteral("...")).height();
75 qreal titleSpace = availableSpace - minimumLabelHeight;
75 qreal titleSpace = availableSpace - minimumLabelHeight;
76 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0),
76 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0),
77 gridRect.width(), titleSpace,
77 gridRect.width(), titleSpace,
78 titleBoundingRect));
78 titleBoundingRect));
79 title->setTextWidth(titleBoundingRect.width());
79 title->setTextWidth(titleBoundingRect.width());
80
80
81 titleBoundingRect = title->boundingRect();
81 titleBoundingRect = title->boundingRect();
82
82
83 QPointF center = gridRect.center() - titleBoundingRect.center();
83 QPointF center = gridRect.center() - titleBoundingRect.center();
84 if (axis()->alignment() == Qt::AlignTop)
84 if (axis()->alignment() == Qt::AlignTop)
85 title->setPos(center.x(), axisRect.top() + titlePadding());
85 title->setPos(center.x(), axisRect.top() + titlePadding());
86 else if (axis()->alignment() == Qt::AlignBottom)
86 else if (axis()->alignment() == Qt::AlignBottom)
87 title->setPos(center.x(), axisRect.bottom() - titleBoundingRect.height() - titlePadding());
87 title->setPos(center.x(), axisRect.bottom() - titleBoundingRect.height() - titlePadding());
88
88
89 availableSpace -= titleBoundingRect.height();
89 availableSpace -= titleBoundingRect.height();
90 }
90 }
91
91
92 if (layout.isEmpty() && axis()->type() == QAbstractAxis::AxisTypeLogValue)
92 if (layout.isEmpty() && axis()->type() == QAbstractAxis::AxisTypeLogValue)
93 return;
93 return;
94
94
95 QList<QGraphicsItem *> lines = gridItems();
95 QList<QGraphicsItem *> lines = gridItems();
96 QList<QGraphicsItem *> shades = shadeItems();
96 QList<QGraphicsItem *> shades = shadeItems();
97 QList<QGraphicsItem *> minorLines = minorGridItems();
97 QList<QGraphicsItem *> minorLines = minorGridItems();
98 QList<QGraphicsItem *> minorArrows = minorArrowItems();
98 QList<QGraphicsItem *> minorArrows = minorArrowItems();
99
99
100 for (int i = 0; i < layout.size(); ++i) {
100 for (int i = 0; i < layout.size(); ++i) {
101 //items
101 //items
102 QGraphicsLineItem *gridItem = static_cast<QGraphicsLineItem*>(lines.at(i));
102 QGraphicsLineItem *gridItem = static_cast<QGraphicsLineItem*>(lines.at(i));
103 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem*>(arrow.at(i + 1));
103 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem*>(arrow.at(i + 1));
104 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labels.at(i));
104 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labels.at(i));
105
105
106 //grid line
106 //grid line
107 if (axis()->isReverse()) {
107 if (axis()->isReverse()) {
108 gridItem->setLine(gridRect.right() - layout[i] + gridRect.left(), gridRect.top(),
108 gridItem->setLine(gridRect.right() - layout[i] + gridRect.left(), gridRect.top(),
109 gridRect.right() - layout[i] + gridRect.left(), gridRect.bottom());
109 gridRect.right() - layout[i] + gridRect.left(), gridRect.bottom());
110 } else {
110 } else {
111 gridItem->setLine(layout[i], gridRect.top(), layout[i], gridRect.bottom());
111 gridItem->setLine(layout[i], gridRect.top(), layout[i], gridRect.bottom());
112 }
112 }
113
113
114 //label text wrapping
114 //label text wrapping
115 QString text;
115 QString text;
116 if (axis()->isReverse() && axis()->type() != QAbstractAxis::AxisTypeCategory)
116 if (axis()->isReverse() && axis()->type() != QAbstractAxis::AxisTypeCategory)
117 text = labelList.at(labelList.count() - i - 1);
117 text = labelList.at(labelList.count() - i - 1);
118 else
118 else
119 text = labelList.at(i);
119 text = labelList.at(i);
120
120
121 QRectF boundingRect;
121 QRectF boundingRect;
122 // don't truncate empty labels
122 // don't truncate empty labels
123 if (text.isEmpty()) {
123 if (text.isEmpty()) {
124 labelItem->setHtml(text);
124 labelItem->setHtml(text);
125 } else {
125 } else {
126 qreal labelWidth = axisRect.width() / layout.count() - (2 * labelPadding());
126 qreal labelWidth = axisRect.width() / layout.count() - (2 * labelPadding());
127 QString truncatedText = ChartPresenter::truncatedText(axis()->labelsFont(), text,
127 QString truncatedText = ChartPresenter::truncatedText(axis()->labelsFont(), text,
128 axis()->labelsAngle(),
128 axis()->labelsAngle(),
129 labelWidth,
129 labelWidth,
130 availableSpace, boundingRect);
130 availableSpace, boundingRect);
131 labelItem->setTextWidth(ChartPresenter::textBoundingRect(axis()->labelsFont(),
131 labelItem->setTextWidth(ChartPresenter::textBoundingRect(axis()->labelsFont(),
132 truncatedText).width());
132 truncatedText).width());
133 labelItem->setHtml(truncatedText);
133 labelItem->setHtml(truncatedText);
134 }
134 }
135
135
136 //label transformation origin point
136 //label transformation origin point
137 const QRectF& rect = labelItem->boundingRect();
137 const QRectF& rect = labelItem->boundingRect();
138 QPointF center = rect.center();
138 QPointF center = rect.center();
139 labelItem->setTransformOriginPoint(center.x(), center.y());
139 labelItem->setTransformOriginPoint(center.x(), center.y());
140 qreal heightDiff = rect.height() - boundingRect.height();
140 qreal heightDiff = rect.height() - boundingRect.height();
141 qreal widthDiff = rect.width() - boundingRect.width();
141 qreal widthDiff = rect.width() - boundingRect.width();
142
142
143 //ticks and label position
143 //ticks and label position
144 QPointF labelPos;
144 if (axis()->alignment() == Qt::AlignTop) {
145 if (axis()->alignment() == Qt::AlignTop) {
145 if (axis()->isReverse()) {
146 if (axis()->isReverse()) {
146 labelItem->setPos(gridRect.right() - layout[layout.size() - i - 1]
147 labelPos = QPointF(gridRect.right() - layout[layout.size() - i - 1]
147 + gridRect.left() - center.x(),
148 + gridRect.left() - center.x(),
148 axisRect.bottom() - rect.height()
149 axisRect.bottom() - rect.height()
149 + (heightDiff / 2.0) - labelPadding());
150 + (heightDiff / 2.0) - labelPadding());
150 tickItem->setLine(gridRect.right() + gridRect.left() - layout[i],
151 tickItem->setLine(gridRect.right() + gridRect.left() - layout[i],
151 axisRect.bottom(),
152 axisRect.bottom(),
152 gridRect.right() + gridRect.left() - layout[i],
153 gridRect.right() + gridRect.left() - layout[i],
153 axisRect.bottom() - labelPadding());
154 axisRect.bottom() - labelPadding());
154 } else {
155 } else {
155 labelItem->setPos(layout[i] - center.x(), axisRect.bottom() - rect.height()
156 labelPos = QPointF(layout[i] - center.x(), axisRect.bottom() - rect.height()
156 + (heightDiff / 2.0) - labelPadding());
157 + (heightDiff / 2.0) - labelPadding());
157 tickItem->setLine(layout[i], axisRect.bottom(),
158 tickItem->setLine(layout[i], axisRect.bottom(),
158 layout[i], axisRect.bottom() - labelPadding());
159 layout[i], axisRect.bottom() - labelPadding());
159 }
160 }
160 } else if (axis()->alignment() == Qt::AlignBottom) {
161 } else if (axis()->alignment() == Qt::AlignBottom) {
161 if (axis()->isReverse()) {
162 if (axis()->isReverse()) {
162 labelItem->setPos(gridRect.right() - layout[layout.size() - i - 1]
163 labelPos = QPointF(gridRect.right() - layout[layout.size() - i - 1]
163 + gridRect.left() - center.x(),
164 + gridRect.left() - center.x(),
164 axisRect.top() - (heightDiff / 2.0) + labelPadding());
165 axisRect.top() - (heightDiff / 2.0) + labelPadding());
165 tickItem->setLine(gridRect.right() + gridRect.left() - layout[i], axisRect.top(),
166 tickItem->setLine(gridRect.right() + gridRect.left() - layout[i], axisRect.top(),
166 gridRect.right() + gridRect.left() - layout[i],
167 gridRect.right() + gridRect.left() - layout[i],
167 axisRect.top() + labelPadding());
168 axisRect.top() + labelPadding());
168 } else {
169 } else {
169 labelItem->setPos(layout[i] - center.x(), axisRect.top() - (heightDiff / 2.0)
170 labelPos = QPointF(layout[i] - center.x(), axisRect.top() - (heightDiff / 2.0)
170 + labelPadding());
171 + labelPadding());
171 tickItem->setLine(layout[i], axisRect.top(),
172 tickItem->setLine(layout[i], axisRect.top(),
172 layout[i], axisRect.top() + labelPadding());
173 layout[i], axisRect.top() + labelPadding());
173 }
174 }
174 }
175 }
175
176
176 //label in between
177 //label in between
177 bool forceHide = false;
178 bool forceHide = false;
178 if (intervalAxis() && (i + 1) != layout.size()) {
179 if (intervalAxis() && (i + 1) != layout.size()) {
179 qreal leftBound;
180 qreal leftBound;
180 qreal rightBound;
181 qreal rightBound;
181 if (axis()->isReverse()) {
182 if (axis()->isReverse()) {
182 leftBound = qMax(gridRect.right() + gridRect.left() - layout[i + 1],
183 leftBound = qMax(gridRect.right() + gridRect.left() - layout[i + 1],
183 gridRect.left());
184 gridRect.left());
184 rightBound = qMin(gridRect.right() + gridRect.left() - layout[i], gridRect.right());
185 rightBound = qMin(gridRect.right() + gridRect.left() - layout[i], gridRect.right());
185 } else {
186 } else {
186 leftBound = qMax(layout[i], gridRect.left());
187 leftBound = qMax(layout[i], gridRect.left());
187 rightBound = qMin(layout[i + 1], gridRect.right());
188 rightBound = qMin(layout[i + 1], gridRect.right());
188 }
189 }
189 const qreal delta = rightBound - leftBound;
190 const qreal delta = rightBound - leftBound;
190 if (axis()->type() != QAbstractAxis::AxisTypeCategory) {
191 if (axis()->type() != QAbstractAxis::AxisTypeCategory) {
191 // Hide label in case visible part of the category at the grid edge is too narrow
192 // Hide label in case visible part of the category at the grid edge is too narrow
192 if (delta < boundingRect.width()
193 if (delta < boundingRect.width()
193 && (leftBound == gridRect.left() || rightBound == gridRect.right())) {
194 && (leftBound == gridRect.left() || rightBound == gridRect.right())) {
194 forceHide = true;
195 forceHide = true;
195 } else {
196 } else {
196 labelItem->setPos(leftBound + (delta / 2.0) - center.x(), labelItem->pos().y());
197 labelPos.setX(leftBound + (delta / 2.0) - center.x());
197 }
198 }
198 } else {
199 } else {
199 QCategoryAxis *categoryAxis = static_cast<QCategoryAxis *>(axis());
200 QCategoryAxis *categoryAxis = static_cast<QCategoryAxis *>(axis());
200 if (categoryAxis->labelsPosition() == QCategoryAxis::AxisLabelsPositionCenter) {
201 if (categoryAxis->labelsPosition() == QCategoryAxis::AxisLabelsPositionCenter) {
201 if (delta < boundingRect.width()
202 if (delta < boundingRect.width()
202 && (leftBound == gridRect.left() || rightBound == gridRect.right())) {
203 && (leftBound == gridRect.left() || rightBound == gridRect.right())) {
203 forceHide = true;
204 forceHide = true;
204 } else {
205 } else {
205 labelItem->setPos(leftBound + (delta / 2.0) - center.x(),
206 labelPos.setX(leftBound + (delta / 2.0) - center.x());
206 labelItem->pos().y());
207 }
207 }
208 } else if (categoryAxis->labelsPosition()
208 } else if (categoryAxis->labelsPosition()
209 == QCategoryAxis::AxisLabelsPositionOnValue) {
209 == QCategoryAxis::AxisLabelsPositionOnValue) {
210 if (axis()->isReverse())
210 if (axis()->isReverse())
211 labelItem->setPos(leftBound - center.x(), labelItem->pos().y());
211 labelPos.setX(leftBound - center.x());
212 else
212 else
213 labelItem->setPos(rightBound - center.x(), labelItem->pos().y());
213 labelPos.setX(rightBound - center.x());
214 }
214 }
215 }
215 }
216 }
216 }
217
217
218 // Round to full pixel via QPoint to avoid one pixel clipping on the edge in some cases
219 labelItem->setPos(labelPos.toPoint());
220
218 //label overlap detection - compensate one pixel for rounding errors
221 //label overlap detection - compensate one pixel for rounding errors
219 if ((labelItem->pos().x() < width && labelItem->toPlainText() == ellipsis) || forceHide ||
222 if ((labelItem->pos().x() < width && labelItem->toPlainText() == ellipsis) || forceHide ||
220 (labelItem->pos().x() + (widthDiff / 2.0)) < (axisRect.left() - 1.0) ||
223 (labelItem->pos().x() + (widthDiff / 2.0)) < (axisRect.left() - 1.0) ||
221 (labelItem->pos().x() + (widthDiff / 2.0) - 1.0) > axisRect.right()) {
224 (labelItem->pos().x() + (widthDiff / 2.0) - 1.0) > axisRect.right()) {
222 labelItem->setVisible(false);
225 labelItem->setVisible(false);
223 } else {
226 } else {
224 labelItem->setVisible(true);
227 labelItem->setVisible(true);
225 width = boundingRect.width() + labelItem->pos().x();
228 width = boundingRect.width() + labelItem->pos().x();
226 }
229 }
227
230
228 //shades
231 //shades
229 QGraphicsRectItem *shadeItem = 0;
232 QGraphicsRectItem *shadeItem = 0;
230 if (i == 0)
233 if (i == 0)
231 shadeItem = static_cast<QGraphicsRectItem *>(shades.at(0));
234 shadeItem = static_cast<QGraphicsRectItem *>(shades.at(0));
232 else if (i % 2)
235 else if (i % 2)
233 shadeItem = static_cast<QGraphicsRectItem *>(shades.at((i / 2) + 1));
236 shadeItem = static_cast<QGraphicsRectItem *>(shades.at((i / 2) + 1));
234 if (shadeItem) {
237 if (shadeItem) {
235 qreal leftBound;
238 qreal leftBound;
236 qreal rightBound;
239 qreal rightBound;
237 if (i == 0) {
240 if (i == 0) {
238 if (axis()->isReverse()) {
241 if (axis()->isReverse()) {
239 leftBound = gridRect.right() + gridRect.left() - layout[i];
242 leftBound = gridRect.right() + gridRect.left() - layout[i];
240 rightBound = gridRect.right();
243 rightBound = gridRect.right();
241 } else {
244 } else {
242 leftBound = gridRect.left();
245 leftBound = gridRect.left();
243 rightBound = layout[0];
246 rightBound = layout[0];
244 }
247 }
245 } else {
248 } else {
246 if (axis()->isReverse()) {
249 if (axis()->isReverse()) {
247 rightBound = gridRect.right() + gridRect.left() - layout[i];
250 rightBound = gridRect.right() + gridRect.left() - layout[i];
248 if (i == layout.size() - 1) {
251 if (i == layout.size() - 1) {
249 leftBound = gridRect.left();
252 leftBound = gridRect.left();
250 } else {
253 } else {
251 leftBound = qMax(gridRect.right() + gridRect.left() - layout[i + 1],
254 leftBound = qMax(gridRect.right() + gridRect.left() - layout[i + 1],
252 gridRect.left());
255 gridRect.left());
253 }
256 }
254 } else {
257 } else {
255 leftBound = layout[i];
258 leftBound = layout[i];
256 if (i == layout.size() - 1)
259 if (i == layout.size() - 1)
257 rightBound = gridRect.right();
260 rightBound = gridRect.right();
258 else
261 else
259 rightBound = qMin(layout[i + 1], gridRect.right());
262 rightBound = qMin(layout[i + 1], gridRect.right());
260 }
263 }
261 }
264 }
262 if (leftBound < gridRect.left())
265 if (leftBound < gridRect.left())
263 leftBound = gridRect.left();
266 leftBound = gridRect.left();
264 if (rightBound > gridRect.right())
267 if (rightBound > gridRect.right())
265 rightBound = gridRect.right();
268 rightBound = gridRect.right();
266 shadeItem->setRect(leftBound, gridRect.top(), rightBound - leftBound,
269 shadeItem->setRect(leftBound, gridRect.top(), rightBound - leftBound,
267 gridRect.height());
270 gridRect.height());
268 if (shadeItem->rect().width() <= 0.0)
271 if (shadeItem->rect().width() <= 0.0)
269 shadeItem->setVisible(false);
272 shadeItem->setVisible(false);
270 else
273 else
271 shadeItem->setVisible(true);
274 shadeItem->setVisible(true);
272 }
275 }
273
276
274 // check if the grid line and the axis tick should be shown
277 // check if the grid line and the axis tick should be shown
275 qreal x = gridItem->line().p1().x();
278 qreal x = gridItem->line().p1().x();
276 if (x < gridRect.left() || x > gridRect.right()) {
279 if (x < gridRect.left() || x > gridRect.right()) {
277 gridItem->setVisible(false);
280 gridItem->setVisible(false);
278 tickItem->setVisible(false);
281 tickItem->setVisible(false);
279 } else {
282 } else {
280 gridItem->setVisible(true);
283 gridItem->setVisible(true);
281 tickItem->setVisible(true);
284 tickItem->setVisible(true);
282 }
285 }
283
286
284 // add minor ticks
287 // add minor ticks
285 QValueAxis *valueAxis = qobject_cast<QValueAxis *>(axis());
288 QValueAxis *valueAxis = qobject_cast<QValueAxis *>(axis());
286 if ((i + 1) != layout.size() && valueAxis) {
289 if ((i + 1) != layout.size() && valueAxis) {
287 int minorTickCount = valueAxis->minorTickCount();
290 int minorTickCount = valueAxis->minorTickCount();
288 if (minorTickCount != 0) {
291 if (minorTickCount != 0) {
289 qreal minorTickDistance = (layout[i] - layout[i + 1]) / qreal(minorTickCount + 1);
292 qreal minorTickDistance = (layout[i] - layout[i + 1]) / qreal(minorTickCount + 1);
290 for (int j = 0; j < minorTickCount; j++) {
293 for (int j = 0; j < minorTickCount; j++) {
291 QGraphicsLineItem *minorGridItem =
294 QGraphicsLineItem *minorGridItem =
292 static_cast<QGraphicsLineItem *>(minorLines.at(i * minorTickCount + j));
295 static_cast<QGraphicsLineItem *>(minorLines.at(i * minorTickCount + j));
293 QGraphicsLineItem *minorArrowItem =
296 QGraphicsLineItem *minorArrowItem =
294 static_cast<QGraphicsLineItem *>(minorArrows.at(i * minorTickCount + j));
297 static_cast<QGraphicsLineItem *>(minorArrows.at(i * minorTickCount + j));
295 if (i == 0) {
298 if (i == 0) {
296 minorGridItem->setLine(gridRect.left() - minorTickDistance * qreal(j + 1),
299 minorGridItem->setLine(gridRect.left() - minorTickDistance * qreal(j + 1),
297 gridRect.top(),
300 gridRect.top(),
298 gridRect.left() - minorTickDistance * qreal(j + 1),
301 gridRect.left() - minorTickDistance * qreal(j + 1),
299 gridRect.bottom());
302 gridRect.bottom());
300 } else {
303 } else {
301 minorGridItem->setLine(gridItem->line().p1().x()
304 minorGridItem->setLine(gridItem->line().p1().x()
302 - minorTickDistance * qreal(j + 1),
305 - minorTickDistance * qreal(j + 1),
303 gridRect.top(),
306 gridRect.top(),
304 gridItem->line().p1().x()
307 gridItem->line().p1().x()
305 - minorTickDistance * qreal(j + 1),
308 - minorTickDistance * qreal(j + 1),
306 gridRect.bottom());
309 gridRect.bottom());
307 }
310 }
308 if (axis()->alignment() == Qt::AlignTop) {
311 if (axis()->alignment() == Qt::AlignTop) {
309 minorArrowItem->setLine(minorGridItem->line().p1().x(),
312 minorArrowItem->setLine(minorGridItem->line().p1().x(),
310 axisRect.bottom(),
313 axisRect.bottom(),
311 minorGridItem->line().p1().x(),
314 minorGridItem->line().p1().x(),
312 axisRect.bottom() - labelPadding() / 2);
315 axisRect.bottom() - labelPadding() / 2);
313 } else if (axis()->alignment() == Qt::AlignBottom){
316 } else if (axis()->alignment() == Qt::AlignBottom){
314 minorArrowItem->setLine(minorGridItem->line().p1().x(),
317 minorArrowItem->setLine(minorGridItem->line().p1().x(),
315 axisRect.top(),
318 axisRect.top(),
316 minorGridItem->line().p1().x(),
319 minorGridItem->line().p1().x(),
317 axisRect.top() + labelPadding() / 2);
320 axisRect.top() + labelPadding() / 2);
318 }
321 }
319
322
320 // check if the minor grid line and the axis tick should be shown
323 // check if the minor grid line and the axis tick should be shown
321 qreal minorXPos = minorGridItem->line().p1().x();
324 qreal minorXPos = minorGridItem->line().p1().x();
322 if (minorXPos < gridRect.left() || minorXPos > gridRect.right()) {
325 if (minorXPos < gridRect.left() || minorXPos > gridRect.right()) {
323 minorGridItem->setVisible(false);
326 minorGridItem->setVisible(false);
324 minorArrowItem->setVisible(false);
327 minorArrowItem->setVisible(false);
325 } else {
328 } else {
326 minorGridItem->setVisible(true);
329 minorGridItem->setVisible(true);
327 minorArrowItem->setVisible(true);
330 minorArrowItem->setVisible(true);
328 }
331 }
329 }
332 }
330 }
333 }
331 }
334 }
332 }
335 }
333
336
334 //begin/end grid line in case labels between
337 //begin/end grid line in case labels between
335 if (intervalAxis()) {
338 if (intervalAxis()) {
336 QGraphicsLineItem *gridLine;
339 QGraphicsLineItem *gridLine;
337 gridLine = static_cast<QGraphicsLineItem *>(lines.at(layout.size()));
340 gridLine = static_cast<QGraphicsLineItem *>(lines.at(layout.size()));
338 gridLine->setLine(gridRect.right(), gridRect.top(), gridRect.right(), gridRect.bottom());
341 gridLine->setLine(gridRect.right(), gridRect.top(), gridRect.right(), gridRect.bottom());
339 gridLine->setVisible(true);
342 gridLine->setVisible(true);
340 gridLine = static_cast<QGraphicsLineItem*>(lines.at(layout.size()+1));
343 gridLine = static_cast<QGraphicsLineItem*>(lines.at(layout.size()+1));
341 gridLine->setLine(gridRect.left(), gridRect.top(), gridRect.left(), gridRect.bottom());
344 gridLine->setLine(gridRect.left(), gridRect.top(), gridRect.left(), gridRect.bottom());
342 gridLine->setVisible(true);
345 gridLine->setVisible(true);
343 }
346 }
344 }
347 }
345
348
346 QSizeF HorizontalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
349 QSizeF HorizontalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
347 {
350 {
348 Q_UNUSED(constraint);
351 Q_UNUSED(constraint);
349 QSizeF sh(0,0);
352 QSizeF sh(0,0);
350
353
351 if (axis()->titleText().isEmpty() || !titleItem()->isVisible())
354 if (axis()->titleText().isEmpty() || !titleItem()->isVisible())
352 return sh;
355 return sh;
353
356
354 switch (which) {
357 switch (which) {
355 case Qt::MinimumSize: {
358 case Qt::MinimumSize: {
356 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(),
359 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(),
357 QStringLiteral("..."));
360 QStringLiteral("..."));
358 sh = QSizeF(titleRect.width(), titleRect.height() + (titlePadding() * 2.0));
361 sh = QSizeF(titleRect.width(), titleRect.height() + (titlePadding() * 2.0));
359 break;
362 break;
360 }
363 }
361 case Qt::MaximumSize:
364 case Qt::MaximumSize:
362 case Qt::PreferredSize: {
365 case Qt::PreferredSize: {
363 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText());
366 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText());
364 sh = QSizeF(titleRect.width(), titleRect.height() + (titlePadding() * 2.0));
367 sh = QSizeF(titleRect.width(), titleRect.height() + (titlePadding() * 2.0));
365 break;
368 break;
366 }
369 }
367 default:
370 default:
368 break;
371 break;
369 }
372 }
370
373
371 return sh;
374 return sh;
372 }
375 }
373
376
374 QT_CHARTS_END_NAMESPACE
377 QT_CHARTS_END_NAMESPACE
@@ -1,390 +1,392
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd
3 ** Copyright (C) 2015 The Qt Company Ltd
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to The Qt Company, please use contact form at http://qt.io
5 ** For any questions to The Qt Company, please use contact form at http://qt.io
6 **
6 **
7 ** This file is part of the Qt Charts module.
7 ** This file is part of the Qt Charts module.
8 **
8 **
9 ** Licensees holding valid commercial license for Qt may use this file in
9 ** Licensees holding valid commercial license for Qt may use this file in
10 ** accordance with the Qt License Agreement provided with the Software
10 ** accordance with the Qt License Agreement provided with the Software
11 ** or, alternatively, in accordance with the terms contained in a written
11 ** or, alternatively, in accordance with the terms contained in a written
12 ** agreement between you and The Qt Company.
12 ** agreement between you and The Qt Company.
13 **
13 **
14 ** If you have questions regarding the use of this file, please use
14 ** If you have questions regarding the use of this file, please use
15 ** contact form at http://qt.io
15 ** contact form at http://qt.io
16 **
16 **
17 ****************************************************************************/
17 ****************************************************************************/
18
18
19 #include <private/verticalaxis_p.h>
19 #include <private/verticalaxis_p.h>
20 #include <QtCharts/QAbstractAxis>
20 #include <QtCharts/QAbstractAxis>
21 #include <private/chartpresenter_p.h>
21 #include <private/chartpresenter_p.h>
22 #include <QtCharts/QCategoryAxis>
22 #include <QtCharts/QCategoryAxis>
23 #include <QtCore/QDebug>
23 #include <QtCore/QDebug>
24
24
25 QT_CHARTS_BEGIN_NAMESPACE
25 QT_CHARTS_BEGIN_NAMESPACE
26
26
27 VerticalAxis::VerticalAxis(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
27 VerticalAxis::VerticalAxis(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
28 : CartesianChartAxis(axis, item, intervalAxis)
28 : CartesianChartAxis(axis, item, intervalAxis)
29 {
29 {
30 }
30 }
31
31
32 VerticalAxis::~VerticalAxis()
32 VerticalAxis::~VerticalAxis()
33 {
33 {
34 }
34 }
35
35
36 void VerticalAxis::updateGeometry()
36 void VerticalAxis::updateGeometry()
37 {
37 {
38 const QVector<qreal> &layout = ChartAxisElement::layout();
38 const QVector<qreal> &layout = ChartAxisElement::layout();
39
39
40 if (layout.isEmpty() && axis()->type() != QAbstractAxis::AxisTypeLogValue)
40 if (layout.isEmpty() && axis()->type() != QAbstractAxis::AxisTypeLogValue)
41 return;
41 return;
42
42
43 QStringList labelList = labels();
43 QStringList labelList = labels();
44
44
45 QList<QGraphicsItem *> labels = labelItems();
45 QList<QGraphicsItem *> labels = labelItems();
46 QList<QGraphicsItem *> arrow = arrowItems();
46 QList<QGraphicsItem *> arrow = arrowItems();
47 QGraphicsTextItem *title = titleItem();
47 QGraphicsTextItem *title = titleItem();
48
48
49 Q_ASSERT(labels.size() == labelList.size());
49 Q_ASSERT(labels.size() == labelList.size());
50 Q_ASSERT(layout.size() == labelList.size());
50 Q_ASSERT(layout.size() == labelList.size());
51
51
52 const QRectF &axisRect = axisGeometry();
52 const QRectF &axisRect = axisGeometry();
53 const QRectF &gridRect = gridGeometry();
53 const QRectF &gridRect = gridGeometry();
54
54
55 qreal height = axisRect.bottom();
55 qreal height = axisRect.bottom();
56
56
57 //arrow
57 //arrow
58 QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem*>(arrow.at(0));
58 QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem*>(arrow.at(0));
59
59
60 //arrow position
60 //arrow position
61 if (axis()->alignment() == Qt::AlignLeft)
61 if (axis()->alignment() == Qt::AlignLeft)
62 arrowItem->setLine(axisRect.right(), gridRect.top(), axisRect.right(), gridRect.bottom());
62 arrowItem->setLine(axisRect.right(), gridRect.top(), axisRect.right(), gridRect.bottom());
63 else if (axis()->alignment() == Qt::AlignRight)
63 else if (axis()->alignment() == Qt::AlignRight)
64 arrowItem->setLine(axisRect.left(), gridRect.top(), axisRect.left(), gridRect.bottom());
64 arrowItem->setLine(axisRect.left(), gridRect.top(), axisRect.left(), gridRect.bottom());
65
65
66 //title
66 //title
67 QRectF titleBoundingRect;
67 QRectF titleBoundingRect;
68 QString titleText = axis()->titleText();
68 QString titleText = axis()->titleText();
69 qreal availableSpace = axisRect.width() - labelPadding();
69 qreal availableSpace = axisRect.width() - labelPadding();
70 if (!titleText.isEmpty() && titleItem()->isVisible()) {
70 if (!titleText.isEmpty() && titleItem()->isVisible()) {
71 availableSpace -= titlePadding() * 2.0;
71 availableSpace -= titlePadding() * 2.0;
72 qreal minimumLabelWidth = ChartPresenter::textBoundingRect(axis()->labelsFont(),
72 qreal minimumLabelWidth = ChartPresenter::textBoundingRect(axis()->labelsFont(),
73 QStringLiteral("...")).width();
73 QStringLiteral("...")).width();
74 qreal titleSpace = availableSpace - minimumLabelWidth;
74 qreal titleSpace = availableSpace - minimumLabelWidth;
75 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(90.0),
75 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(90.0),
76 titleSpace, gridRect.height(),
76 titleSpace, gridRect.height(),
77 titleBoundingRect));
77 titleBoundingRect));
78 title->setTextWidth(titleBoundingRect.height());
78 title->setTextWidth(titleBoundingRect.height());
79
79
80 titleBoundingRect = title->boundingRect();
80 titleBoundingRect = title->boundingRect();
81
81
82 QPointF center = gridRect.center() - titleBoundingRect.center();
82 QPointF center = gridRect.center() - titleBoundingRect.center();
83 if (axis()->alignment() == Qt::AlignLeft)
83 if (axis()->alignment() == Qt::AlignLeft)
84 title->setPos(axisRect.left() - titleBoundingRect.width() / 2.0 + titleBoundingRect.height() / 2.0 + titlePadding(), center.y());
84 title->setPos(axisRect.left() - titleBoundingRect.width() / 2.0 + titleBoundingRect.height() / 2.0 + titlePadding(), center.y());
85 else if (axis()->alignment() == Qt::AlignRight)
85 else if (axis()->alignment() == Qt::AlignRight)
86 title->setPos(axisRect.right() - titleBoundingRect.width() / 2.0 - titleBoundingRect.height() / 2.0 - titlePadding(), center.y());
86 title->setPos(axisRect.right() - titleBoundingRect.width() / 2.0 - titleBoundingRect.height() / 2.0 - titlePadding(), center.y());
87
87
88 title->setTransformOriginPoint(titleBoundingRect.center());
88 title->setTransformOriginPoint(titleBoundingRect.center());
89 title->setRotation(270);
89 title->setRotation(270);
90
90
91 availableSpace -= titleBoundingRect.height();
91 availableSpace -= titleBoundingRect.height();
92 }
92 }
93
93
94 if (layout.isEmpty() && axis()->type() == QAbstractAxis::AxisTypeLogValue)
94 if (layout.isEmpty() && axis()->type() == QAbstractAxis::AxisTypeLogValue)
95 return;
95 return;
96
96
97 QList<QGraphicsItem *> lines = gridItems();
97 QList<QGraphicsItem *> lines = gridItems();
98 QList<QGraphicsItem *> shades = shadeItems();
98 QList<QGraphicsItem *> shades = shadeItems();
99 QList<QGraphicsItem *> minorLines = minorGridItems();
99 QList<QGraphicsItem *> minorLines = minorGridItems();
100 QList<QGraphicsItem *> minorArrows = minorArrowItems();
100 QList<QGraphicsItem *> minorArrows = minorArrowItems();
101
101
102 for (int i = 0; i < layout.size(); ++i) {
102 for (int i = 0; i < layout.size(); ++i) {
103 //items
103 //items
104 QGraphicsLineItem *gridItem = static_cast<QGraphicsLineItem *>(lines.at(i));
104 QGraphicsLineItem *gridItem = static_cast<QGraphicsLineItem *>(lines.at(i));
105 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrow.at(i + 1));
105 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrow.at(i + 1));
106 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labels.at(i));
106 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labels.at(i));
107
107
108 //grid line
108 //grid line
109 if (axis()->isReverse()) {
109 if (axis()->isReverse()) {
110 gridItem->setLine(gridRect.left(), gridRect.top() + gridRect.bottom() - layout[i],
110 gridItem->setLine(gridRect.left(), gridRect.top() + gridRect.bottom() - layout[i],
111 gridRect.right(), gridRect.top() + gridRect.bottom() - layout[i]);
111 gridRect.right(), gridRect.top() + gridRect.bottom() - layout[i]);
112 } else {
112 } else {
113 gridItem->setLine(gridRect.left(), layout[i], gridRect.right(), layout[i]);
113 gridItem->setLine(gridRect.left(), layout[i], gridRect.right(), layout[i]);
114 }
114 }
115
115
116 //label text wrapping
116 //label text wrapping
117 QString text;
117 QString text;
118 if (axis()->isReverse() && axis()->type() != QAbstractAxis::AxisTypeCategory)
118 if (axis()->isReverse() && axis()->type() != QAbstractAxis::AxisTypeCategory)
119 text = labelList.at(labelList.count() - i - 1);
119 text = labelList.at(labelList.count() - i - 1);
120 else
120 else
121 text = labelList.at(i);
121 text = labelList.at(i);
122
122
123 QRectF boundingRect;
123 QRectF boundingRect;
124 // don't truncate empty labels
124 // don't truncate empty labels
125 if (text.isEmpty()) {
125 if (text.isEmpty()) {
126 labelItem->setHtml(text);
126 labelItem->setHtml(text);
127 } else {
127 } else {
128 qreal labelHeight = (axisRect.height() / layout.count()) - (2 * labelPadding());
128 qreal labelHeight = (axisRect.height() / layout.count()) - (2 * labelPadding());
129 QString truncatedText = ChartPresenter::truncatedText(axis()->labelsFont(), text,
129 QString truncatedText = ChartPresenter::truncatedText(axis()->labelsFont(), text,
130 axis()->labelsAngle(),
130 axis()->labelsAngle(),
131 availableSpace,
131 availableSpace,
132 labelHeight, boundingRect);
132 labelHeight, boundingRect);
133 labelItem->setTextWidth(ChartPresenter::textBoundingRect(axis()->labelsFont(),
133 labelItem->setTextWidth(ChartPresenter::textBoundingRect(axis()->labelsFont(),
134 truncatedText).width());
134 truncatedText).width());
135 labelItem->setHtml(truncatedText);
135 labelItem->setHtml(truncatedText);
136 }
136 }
137
137
138 //label transformation origin point
138 //label transformation origin point
139 const QRectF &rect = labelItem->boundingRect();
139 const QRectF &rect = labelItem->boundingRect();
140 QPointF center = rect.center();
140 QPointF center = rect.center();
141 labelItem->setTransformOriginPoint(center.x(), center.y());
141 labelItem->setTransformOriginPoint(center.x(), center.y());
142 qreal widthDiff = rect.width() - boundingRect.width();
142 qreal widthDiff = rect.width() - boundingRect.width();
143 qreal heightDiff = rect.height() - boundingRect.height();
143 qreal heightDiff = rect.height() - boundingRect.height();
144
144
145 //ticks and label position
145 //ticks and label position
146 QPointF labelPos;
146 if (axis()->alignment() == Qt::AlignLeft) {
147 if (axis()->alignment() == Qt::AlignLeft) {
147 if (axis()->isReverse()) {
148 if (axis()->isReverse()) {
148 labelItem->setPos(axisRect.right() - rect.width() + (widthDiff / 2.0)
149 labelPos = QPointF(axisRect.right() - rect.width() + (widthDiff / 2.0)
149 - labelPadding(),
150 - labelPadding(),
150 gridRect.top() + gridRect.bottom()
151 gridRect.top() + gridRect.bottom()
151 - layout[layout.size() - i - 1] - center.y());
152 - layout[layout.size() - i - 1] - center.y());
152 tickItem->setLine(axisRect.right() - labelPadding(),
153 tickItem->setLine(axisRect.right() - labelPadding(),
153 gridRect.top() + gridRect.bottom() - layout[i],
154 gridRect.top() + gridRect.bottom() - layout[i],
154 axisRect.right(),
155 axisRect.right(),
155 gridRect.top() + gridRect.bottom() - layout[i]);
156 gridRect.top() + gridRect.bottom() - layout[i]);
156 } else {
157 } else {
157 labelItem->setPos(axisRect.right() - rect.width() + (widthDiff / 2.0)
158 labelPos = QPointF(axisRect.right() - rect.width() + (widthDiff / 2.0)
158 - labelPadding(),
159 - labelPadding(),
159 layout[i] - center.y());
160 layout[i] - center.y());
160 tickItem->setLine(axisRect.right() - labelPadding(), layout[i],
161 tickItem->setLine(axisRect.right() - labelPadding(), layout[i],
161 axisRect.right(), layout[i]);
162 axisRect.right(), layout[i]);
162 }
163 }
163 } else if (axis()->alignment() == Qt::AlignRight) {
164 } else if (axis()->alignment() == Qt::AlignRight) {
164 if (axis()->isReverse()) {
165 if (axis()->isReverse()) {
165 tickItem->setLine(axisRect.left(),
166 tickItem->setLine(axisRect.left(),
166 gridRect.top() + gridRect.bottom() - layout[i],
167 gridRect.top() + gridRect.bottom() - layout[i],
167 axisRect.left() + labelPadding(),
168 axisRect.left() + labelPadding(),
168 gridRect.top() + gridRect.bottom() - layout[i]);
169 gridRect.top() + gridRect.bottom() - layout[i]);
169 labelItem->setPos(axisRect.left() + labelPadding() - (widthDiff / 2.0),
170 labelPos = QPointF(axisRect.left() + labelPadding() - (widthDiff / 2.0),
170 gridRect.top() + gridRect.bottom()
171 gridRect.top() + gridRect.bottom()
171 - layout[layout.size() - i - 1] - center.y());
172 - layout[layout.size() - i - 1] - center.y());
172 } else {
173 } else {
173 labelItem->setPos(axisRect.left() + labelPadding() - (widthDiff / 2.0),
174 labelPos = QPointF(axisRect.left() + labelPadding() - (widthDiff / 2.0),
174 layout[i] - center.y());
175 layout[i] - center.y());
175 tickItem->setLine(axisRect.left(), layout[i],
176 tickItem->setLine(axisRect.left(), layout[i],
176 axisRect.left() + labelPadding(), layout[i]);
177 axisRect.left() + labelPadding(), layout[i]);
177 }
178 }
178 }
179 }
179
180
180 //label in between
181 //label in between
181 bool forceHide = false;
182 bool forceHide = false;
182 bool labelOnValue = false;
183 bool labelOnValue = false;
183 if (intervalAxis() && (i + 1) != layout.size()) {
184 if (intervalAxis() && (i + 1) != layout.size()) {
184 qreal lowerBound;
185 qreal lowerBound;
185 qreal upperBound;
186 qreal upperBound;
186 if (axis()->isReverse()) {
187 if (axis()->isReverse()) {
187 lowerBound = qMax(gridRect.top() + gridRect.bottom() - layout[i + 1],
188 lowerBound = qMax(gridRect.top() + gridRect.bottom() - layout[i + 1],
188 gridRect.top());
189 gridRect.top());
189 upperBound = qMin(gridRect.top() + gridRect.bottom() - layout[i],
190 upperBound = qMin(gridRect.top() + gridRect.bottom() - layout[i],
190 gridRect.bottom());
191 gridRect.bottom());
191 } else {
192 } else {
192 lowerBound = qMin(layout[i], gridRect.bottom());
193 lowerBound = qMin(layout[i], gridRect.bottom());
193 upperBound = qMax(layout[i + 1], gridRect.top());
194 upperBound = qMax(layout[i + 1], gridRect.top());
194 }
195 }
195 const qreal delta = lowerBound - upperBound;
196 const qreal delta = lowerBound - upperBound;
196 if (axis()->type() != QAbstractAxis::AxisTypeCategory) {
197 if (axis()->type() != QAbstractAxis::AxisTypeCategory) {
197 // Hide label in case visible part of the category at the grid edge is too narrow
198 // Hide label in case visible part of the category at the grid edge is too narrow
198 if (delta < boundingRect.height()
199 if (delta < boundingRect.height()
199 && (lowerBound == gridRect.bottom() || upperBound == gridRect.top())) {
200 && (lowerBound == gridRect.bottom() || upperBound == gridRect.top())) {
200 forceHide = true;
201 forceHide = true;
201 } else {
202 } else {
202 labelItem->setPos(labelItem->pos().x(),
203 labelPos.setY(lowerBound - (delta / 2.0) - center.y());
203 lowerBound - (delta / 2.0) - center.y());
204 }
204 }
205 } else {
205 } else {
206 QCategoryAxis *categoryAxis = static_cast<QCategoryAxis *>(axis());
206 QCategoryAxis *categoryAxis = static_cast<QCategoryAxis *>(axis());
207 if (categoryAxis->labelsPosition() == QCategoryAxis::AxisLabelsPositionCenter) {
207 if (categoryAxis->labelsPosition() == QCategoryAxis::AxisLabelsPositionCenter) {
208 if (delta < boundingRect.height()
208 if (delta < boundingRect.height()
209 && (lowerBound == gridRect.bottom() || upperBound == gridRect.top())) {
209 && (lowerBound == gridRect.bottom() || upperBound == gridRect.top())) {
210 forceHide = true;
210 forceHide = true;
211 } else {
211 } else {
212 labelItem->setPos(labelItem->pos().x(),
212 labelPos.setY(lowerBound - (delta / 2.0) - center.y());
213 lowerBound - (delta / 2.0) - center.y());
214 }
213 }
215 } else if (categoryAxis->labelsPosition()
214 } else if (categoryAxis->labelsPosition()
216 == QCategoryAxis::AxisLabelsPositionOnValue) {
215 == QCategoryAxis::AxisLabelsPositionOnValue) {
217 labelOnValue = true;
216 labelOnValue = true;
218 if (axis()->isReverse()) {
217 if (axis()->isReverse()) {
219 labelItem->setPos(labelItem->pos().x(), gridRect.top() + gridRect.bottom()
218 labelPos.setY(gridRect.top() + gridRect.bottom()
220 - layout[i + 1] - center.y());
219 - layout[i + 1] - center.y());
221 } else {
220 } else {
222 labelItem->setPos(labelItem->pos().x(), upperBound - center.y());
221 labelPos.setY(upperBound - center.y());
223 }
222 }
224 }
223 }
225 }
224 }
226 }
225 }
227
226
227 // Round to full pixel via QPoint to avoid one pixel clipping on the edge in some cases
228 labelItem->setPos(labelPos.toPoint());
229
228 //label overlap detection - compensate one pixel for rounding errors
230 //label overlap detection - compensate one pixel for rounding errors
229 if (axis()->isReverse()) {
231 if (axis()->isReverse()) {
230 if (forceHide)
232 if (forceHide)
231 labelItem->setVisible(false);
233 labelItem->setVisible(false);
232 } else if (labelItem->pos().y() + boundingRect.height() > height || forceHide ||
234 } else if (labelItem->pos().y() + boundingRect.height() > height || forceHide ||
233 ((labelItem->pos().y() + (heightDiff / 2.0) - 1.0) > axisRect.bottom()
235 ((labelItem->pos().y() + (heightDiff / 2.0) - 1.0) > axisRect.bottom()
234 && !labelOnValue) ||
236 && !labelOnValue) ||
235 (labelItem->pos().y() + (heightDiff / 2.0) < (axisRect.top() - 1.0) && !labelOnValue)) {
237 (labelItem->pos().y() + (heightDiff / 2.0) < (axisRect.top() - 1.0) && !labelOnValue)) {
236 labelItem->setVisible(false);
238 labelItem->setVisible(false);
237 }
239 }
238 else {
240 else {
239 labelItem->setVisible(true);
241 labelItem->setVisible(true);
240 height=labelItem->pos().y();
242 height=labelItem->pos().y();
241 }
243 }
242
244
243 //shades
245 //shades
244 QGraphicsRectItem *shadeItem = 0;
246 QGraphicsRectItem *shadeItem = 0;
245 if (i == 0)
247 if (i == 0)
246 shadeItem = static_cast<QGraphicsRectItem *>(shades.at(0));
248 shadeItem = static_cast<QGraphicsRectItem *>(shades.at(0));
247 else if (i % 2)
249 else if (i % 2)
248 shadeItem = static_cast<QGraphicsRectItem *>(shades.at((i / 2) + 1));
250 shadeItem = static_cast<QGraphicsRectItem *>(shades.at((i / 2) + 1));
249 if (shadeItem) {
251 if (shadeItem) {
250 qreal lowerBound;
252 qreal lowerBound;
251 qreal upperBound;
253 qreal upperBound;
252 if (i == 0) {
254 if (i == 0) {
253 if (axis()->isReverse()) {
255 if (axis()->isReverse()) {
254 upperBound = gridRect.top();
256 upperBound = gridRect.top();
255 lowerBound = gridRect.top() + gridRect.bottom() - layout[i];
257 lowerBound = gridRect.top() + gridRect.bottom() - layout[i];
256 } else {
258 } else {
257 lowerBound = gridRect.bottom();
259 lowerBound = gridRect.bottom();
258 upperBound = layout[0];
260 upperBound = layout[0];
259 }
261 }
260 } else {
262 } else {
261 if (axis()->isReverse()) {
263 if (axis()->isReverse()) {
262 upperBound = gridRect.top() + gridRect.bottom() - layout[i];
264 upperBound = gridRect.top() + gridRect.bottom() - layout[i];
263 if (i == layout.size() - 1) {
265 if (i == layout.size() - 1) {
264 lowerBound = gridRect.bottom();
266 lowerBound = gridRect.bottom();
265 } else {
267 } else {
266 lowerBound = qMax(gridRect.top() + gridRect.bottom() - layout[i + 1],
268 lowerBound = qMax(gridRect.top() + gridRect.bottom() - layout[i + 1],
267 gridRect.top());
269 gridRect.top());
268 }
270 }
269 } else {
271 } else {
270 lowerBound = layout[i];
272 lowerBound = layout[i];
271 if (i == layout.size() - 1)
273 if (i == layout.size() - 1)
272 upperBound = gridRect.top();
274 upperBound = gridRect.top();
273 else
275 else
274 upperBound = qMax(layout[i + 1], gridRect.top());
276 upperBound = qMax(layout[i + 1], gridRect.top());
275 }
277 }
276
278
277 }
279 }
278 if (lowerBound > gridRect.bottom())
280 if (lowerBound > gridRect.bottom())
279 lowerBound = gridRect.bottom();
281 lowerBound = gridRect.bottom();
280 if (upperBound < gridRect.top())
282 if (upperBound < gridRect.top())
281 upperBound = gridRect.top();
283 upperBound = gridRect.top();
282 shadeItem->setRect(gridRect.left(), upperBound, gridRect.width(),
284 shadeItem->setRect(gridRect.left(), upperBound, gridRect.width(),
283 lowerBound - upperBound);
285 lowerBound - upperBound);
284 if (shadeItem->rect().height() <= 0.0)
286 if (shadeItem->rect().height() <= 0.0)
285 shadeItem->setVisible(false);
287 shadeItem->setVisible(false);
286 else
288 else
287 shadeItem->setVisible(true);
289 shadeItem->setVisible(true);
288 }
290 }
289
291
290 // check if the grid line and the axis tick should be shown
292 // check if the grid line and the axis tick should be shown
291 qreal y = gridItem->line().p1().y();
293 qreal y = gridItem->line().p1().y();
292 if ((y < gridRect.top() || y > gridRect.bottom()))
294 if ((y < gridRect.top() || y > gridRect.bottom()))
293 {
295 {
294 gridItem->setVisible(false);
296 gridItem->setVisible(false);
295 tickItem->setVisible(false);
297 tickItem->setVisible(false);
296 }else{
298 }else{
297 gridItem->setVisible(true);
299 gridItem->setVisible(true);
298 tickItem->setVisible(true);
300 tickItem->setVisible(true);
299 }
301 }
300
302
301 // add minor ticks
303 // add minor ticks
302 QValueAxis *valueAxis = qobject_cast<QValueAxis *>(axis());
304 QValueAxis *valueAxis = qobject_cast<QValueAxis *>(axis());
303 if ((i + 1) != layout.size() && valueAxis) {
305 if ((i + 1) != layout.size() && valueAxis) {
304 int minorTickCount = valueAxis->minorTickCount();
306 int minorTickCount = valueAxis->minorTickCount();
305 if (minorTickCount != 0) {
307 if (minorTickCount != 0) {
306 qreal minorTickDistance = (layout[i] - layout[i + 1]) / qreal(minorTickCount + 1);
308 qreal minorTickDistance = (layout[i] - layout[i + 1]) / qreal(minorTickCount + 1);
307 for (int j = 0; j < minorTickCount; j++) {
309 for (int j = 0; j < minorTickCount; j++) {
308 QGraphicsLineItem *minorGridItem =
310 QGraphicsLineItem *minorGridItem =
309 static_cast<QGraphicsLineItem *>(minorLines.at(i * minorTickCount + j));
311 static_cast<QGraphicsLineItem *>(minorLines.at(i * minorTickCount + j));
310 QGraphicsLineItem *minorArrowItem =
312 QGraphicsLineItem *minorArrowItem =
311 static_cast<QGraphicsLineItem *>(minorArrows.at(i * minorTickCount + j));
313 static_cast<QGraphicsLineItem *>(minorArrows.at(i * minorTickCount + j));
312 if (i == 0) {
314 if (i == 0) {
313 minorGridItem->setLine(gridRect.left(),
315 minorGridItem->setLine(gridRect.left(),
314 gridRect.bottom() - minorTickDistance * qreal(j + 1),
316 gridRect.bottom() - minorTickDistance * qreal(j + 1),
315 gridRect.right(),
317 gridRect.right(),
316 gridRect.bottom() - minorTickDistance * qreal(j + 1));
318 gridRect.bottom() - minorTickDistance * qreal(j + 1));
317 } else {
319 } else {
318 minorGridItem->setLine(gridRect.left(),
320 minorGridItem->setLine(gridRect.left(),
319 gridItem->line().p1().y()
321 gridItem->line().p1().y()
320 - minorTickDistance * qreal(j + 1),
322 - minorTickDistance * qreal(j + 1),
321 gridRect.right(),
323 gridRect.right(),
322 gridItem->line().p1().y()
324 gridItem->line().p1().y()
323 - minorTickDistance * qreal(j + 1));
325 - minorTickDistance * qreal(j + 1));
324 }
326 }
325 if (axis()->alignment() == Qt::AlignLeft) {
327 if (axis()->alignment() == Qt::AlignLeft) {
326 minorArrowItem->setLine(gridRect.left() - labelPadding() / 2,
328 minorArrowItem->setLine(gridRect.left() - labelPadding() / 2,
327 minorGridItem->line().p1().y(),
329 minorGridItem->line().p1().y(),
328 gridRect.left(),
330 gridRect.left(),
329 minorGridItem->line().p1().y());
331 minorGridItem->line().p1().y());
330 } else if (axis()->alignment() == Qt::AlignRight){
332 } else if (axis()->alignment() == Qt::AlignRight){
331 minorArrowItem->setLine(gridRect.right(),
333 minorArrowItem->setLine(gridRect.right(),
332 minorGridItem->line().p1().y(),
334 minorGridItem->line().p1().y(),
333 gridRect.right() + labelPadding() / 2,
335 gridRect.right() + labelPadding() / 2,
334 minorGridItem->line().p1().y());
336 minorGridItem->line().p1().y());
335 }
337 }
336
338
337 // check if the minor grid line and the axis tick should be shown
339 // check if the minor grid line and the axis tick should be shown
338 qreal minorYPos = minorGridItem->line().p1().y();
340 qreal minorYPos = minorGridItem->line().p1().y();
339 if (minorYPos < gridRect.top() || minorYPos > gridRect.bottom()) {
341 if (minorYPos < gridRect.top() || minorYPos > gridRect.bottom()) {
340 minorGridItem->setVisible(false);
342 minorGridItem->setVisible(false);
341 minorArrowItem->setVisible(false);
343 minorArrowItem->setVisible(false);
342 } else {
344 } else {
343 minorGridItem->setVisible(true);
345 minorGridItem->setVisible(true);
344 minorArrowItem->setVisible(true);
346 minorArrowItem->setVisible(true);
345 }
347 }
346 }
348 }
347 }
349 }
348 }
350 }
349 }
351 }
350 //begin/end grid line in case labels between
352 //begin/end grid line in case labels between
351 if (intervalAxis()) {
353 if (intervalAxis()) {
352 QGraphicsLineItem *gridLine;
354 QGraphicsLineItem *gridLine;
353 gridLine = static_cast<QGraphicsLineItem *>(lines.at(layout.size()));
355 gridLine = static_cast<QGraphicsLineItem *>(lines.at(layout.size()));
354 gridLine->setLine(gridRect.left(), gridRect.top(), gridRect.right(), gridRect.top());
356 gridLine->setLine(gridRect.left(), gridRect.top(), gridRect.right(), gridRect.top());
355 gridLine->setVisible(true);
357 gridLine->setVisible(true);
356 gridLine = static_cast<QGraphicsLineItem*>(lines.at(layout.size() + 1));
358 gridLine = static_cast<QGraphicsLineItem*>(lines.at(layout.size() + 1));
357 gridLine->setLine(gridRect.left(), gridRect.bottom(), gridRect.right(), gridRect.bottom());
359 gridLine->setLine(gridRect.left(), gridRect.bottom(), gridRect.right(), gridRect.bottom());
358 gridLine->setVisible(true);
360 gridLine->setVisible(true);
359 }
361 }
360 }
362 }
361
363
362 QSizeF VerticalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
364 QSizeF VerticalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
363 {
365 {
364 Q_UNUSED(constraint);
366 Q_UNUSED(constraint);
365 QSizeF sh(0, 0);
367 QSizeF sh(0, 0);
366
368
367 if (axis()->titleText().isEmpty() || !titleItem()->isVisible())
369 if (axis()->titleText().isEmpty() || !titleItem()->isVisible())
368 return sh;
370 return sh;
369
371
370 switch (which) {
372 switch (which) {
371 case Qt::MinimumSize: {
373 case Qt::MinimumSize: {
372 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(),
374 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(),
373 QStringLiteral("..."));
375 QStringLiteral("..."));
374 sh = QSizeF(titleRect.height() + (titlePadding() * 2.0), titleRect.width());
376 sh = QSizeF(titleRect.height() + (titlePadding() * 2.0), titleRect.width());
375 break;
377 break;
376 }
378 }
377 case Qt::MaximumSize:
379 case Qt::MaximumSize:
378 case Qt::PreferredSize: {
380 case Qt::PreferredSize: {
379 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText());
381 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText());
380 sh = QSizeF(titleRect.height() + (titlePadding() * 2.0), titleRect.width());
382 sh = QSizeF(titleRect.height() + (titlePadding() * 2.0), titleRect.width());
381 break;
383 break;
382 }
384 }
383 default:
385 default:
384 break;
386 break;
385 }
387 }
386
388
387 return sh;
389 return sh;
388 }
390 }
389
391
390 QT_CHARTS_END_NAMESPACE
392 QT_CHARTS_END_NAMESPACE
@@ -1,201 +1,203
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd
3 ** Copyright (C) 2015 The Qt Company Ltd
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to The Qt Company, please use contact form at http://qt.io
5 ** For any questions to The Qt Company, please use contact form at http://qt.io
6 **
6 **
7 ** This file is part of the Qt Charts module.
7 ** This file is part of the Qt Charts module.
8 **
8 **
9 ** Licensees holding valid commercial license for Qt may use this file in
9 ** Licensees holding valid commercial license for Qt may use this file in
10 ** accordance with the Qt License Agreement provided with the Software
10 ** accordance with the Qt License Agreement provided with the Software
11 ** or, alternatively, in accordance with the terms contained in a written
11 ** or, alternatively, in accordance with the terms contained in a written
12 ** agreement between you and The Qt Company.
12 ** agreement between you and The Qt Company.
13 **
13 **
14 ** If you have questions regarding the use of this file, please use
14 ** If you have questions regarding the use of this file, please use
15 ** contact form at http://qt.io
15 ** contact form at http://qt.io
16 **
16 **
17 ****************************************************************************/
17 ****************************************************************************/
18
18
19 #include <private/abstractchartlayout_p.h>
19 #include <private/abstractchartlayout_p.h>
20 #include <private/chartpresenter_p.h>
20 #include <private/chartpresenter_p.h>
21 #include <private/qlegend_p.h>
21 #include <private/qlegend_p.h>
22 #include <private/chartaxiselement_p.h>
22 #include <private/chartaxiselement_p.h>
23 #include <private/charttitle_p.h>
23 #include <private/charttitle_p.h>
24 #include <private/chartbackground_p.h>
24 #include <private/chartbackground_p.h>
25 #include <QtCore/QDebug>
25 #include <QtCore/QDebug>
26
26
27 QT_CHARTS_BEGIN_NAMESPACE
27 QT_CHARTS_BEGIN_NAMESPACE
28
28
29 static const qreal golden_ratio = 0.4;
29 static const qreal golden_ratio = 0.4;
30
30
31 AbstractChartLayout::AbstractChartLayout(ChartPresenter *presenter)
31 AbstractChartLayout::AbstractChartLayout(ChartPresenter *presenter)
32 : m_presenter(presenter),
32 : m_presenter(presenter),
33 m_margins(20, 20, 20, 20),
33 m_margins(20, 20, 20, 20),
34 m_minChartRect(0, 0, 200, 200)
34 m_minChartRect(0, 0, 200, 200)
35 {
35 {
36 }
36 }
37
37
38 AbstractChartLayout::~AbstractChartLayout()
38 AbstractChartLayout::~AbstractChartLayout()
39 {
39 {
40 }
40 }
41
41
42 void AbstractChartLayout::setGeometry(const QRectF &rect)
42 void AbstractChartLayout::setGeometry(const QRectF &rect)
43 {
43 {
44 if (!rect.isValid())
44 if (!rect.isValid())
45 return;
45 return;
46
46
47 if (m_presenter->chart()->isVisible()) {
47 if (m_presenter->chart()->isVisible()) {
48 QList<ChartAxisElement *> axes = m_presenter->axisItems();
48 QList<ChartAxisElement *> axes = m_presenter->axisItems();
49 ChartTitle *title = m_presenter->titleElement();
49 ChartTitle *title = m_presenter->titleElement();
50 QLegend *legend = m_presenter->legend();
50 QLegend *legend = m_presenter->legend();
51 ChartBackground *background = m_presenter->backgroundElement();
51 ChartBackground *background = m_presenter->backgroundElement();
52
52
53 QRectF contentGeometry = calculateBackgroundGeometry(rect, background);
53 QRectF contentGeometry = calculateBackgroundGeometry(rect, background);
54
54
55 contentGeometry = calculateContentGeometry(contentGeometry);
55 contentGeometry = calculateContentGeometry(contentGeometry);
56
56
57 if (title && title->isVisible() && !title->text().isEmpty())
57 if (title && title->isVisible() && !title->text().isEmpty())
58 contentGeometry = calculateTitleGeometry(contentGeometry, title);
58 contentGeometry = calculateTitleGeometry(contentGeometry, title);
59
59
60 if (legend->isAttachedToChart() && legend->isVisible())
60 if (legend->isAttachedToChart() && legend->isVisible())
61 contentGeometry = calculateLegendGeometry(contentGeometry, legend);
61 contentGeometry = calculateLegendGeometry(contentGeometry, legend);
62
62
63 contentGeometry = calculateAxisGeometry(contentGeometry, axes);
63 contentGeometry = calculateAxisGeometry(contentGeometry, axes);
64
64
65 m_presenter->setGeometry(contentGeometry);
65 m_presenter->setGeometry(contentGeometry);
66 if (m_presenter->chart()->chartType() == QChart::ChartTypeCartesian)
66 if (m_presenter->chart()->chartType() == QChart::ChartTypeCartesian)
67 static_cast<QGraphicsRectItem *>(m_presenter->plotAreaElement())->setRect(contentGeometry);
67 static_cast<QGraphicsRectItem *>(m_presenter->plotAreaElement())->setRect(contentGeometry);
68 else
68 else
69 static_cast<QGraphicsEllipseItem *>(m_presenter->plotAreaElement())->setRect(contentGeometry);
69 static_cast<QGraphicsEllipseItem *>(m_presenter->plotAreaElement())->setRect(contentGeometry);
70 }
70 }
71
71
72 QGraphicsLayout::setGeometry(rect);
72 QGraphicsLayout::setGeometry(rect);
73 }
73 }
74
74
75 QRectF AbstractChartLayout::calculateContentGeometry(const QRectF &geometry) const
75 QRectF AbstractChartLayout::calculateContentGeometry(const QRectF &geometry) const
76 {
76 {
77 return geometry.adjusted(m_margins.left(), m_margins.top(), -m_margins.right(), -m_margins.bottom());
77 return geometry.adjusted(m_margins.left(), m_margins.top(), -m_margins.right(), -m_margins.bottom());
78 }
78 }
79
79
80 QRectF AbstractChartLayout::calculateContentMinimum(const QRectF &minimum) const
80 QRectF AbstractChartLayout::calculateContentMinimum(const QRectF &minimum) const
81 {
81 {
82 return minimum.adjusted(0, 0, m_margins.left() + m_margins.right(), m_margins.top() + m_margins.bottom());
82 return minimum.adjusted(0, 0, m_margins.left() + m_margins.right(), m_margins.top() + m_margins.bottom());
83 }
83 }
84
84
85
85
86 QRectF AbstractChartLayout::calculateBackgroundGeometry(const QRectF &geometry, ChartBackground *background) const
86 QRectF AbstractChartLayout::calculateBackgroundGeometry(const QRectF &geometry, ChartBackground *background) const
87 {
87 {
88 qreal left;
88 qreal left;
89 qreal top;
89 qreal top;
90 qreal right;
90 qreal right;
91 qreal bottom;
91 qreal bottom;
92 getContentsMargins(&left, &top, &right, &bottom);
92 getContentsMargins(&left, &top, &right, &bottom);
93 QRectF backgroundGeometry = geometry.adjusted(left, top, -right, -bottom);
93 QRectF backgroundGeometry = geometry.adjusted(left, top, -right, -bottom);
94 if (background)
94 if (background)
95 background->setRect(backgroundGeometry);
95 background->setRect(backgroundGeometry);
96 return backgroundGeometry;
96 return backgroundGeometry;
97 }
97 }
98
98
99 QRectF AbstractChartLayout::calculateBackgroundMinimum(const QRectF &minimum) const
99 QRectF AbstractChartLayout::calculateBackgroundMinimum(const QRectF &minimum) const
100 {
100 {
101 qreal left;
101 qreal left;
102 qreal top;
102 qreal top;
103 qreal right;
103 qreal right;
104 qreal bottom;
104 qreal bottom;
105 getContentsMargins(&left, &top, &right, &bottom);
105 getContentsMargins(&left, &top, &right, &bottom);
106 return minimum.adjusted(0, 0, left + right, top + bottom);
106 return minimum.adjusted(0, 0, left + right, top + bottom);
107 }
107 }
108
108
109 QRectF AbstractChartLayout::calculateLegendGeometry(const QRectF &geometry, QLegend *legend) const
109 QRectF AbstractChartLayout::calculateLegendGeometry(const QRectF &geometry, QLegend *legend) const
110 {
110 {
111 QSizeF size = legend->effectiveSizeHint(Qt::PreferredSize, QSizeF(-1, -1));
111 QSizeF size = legend->effectiveSizeHint(Qt::PreferredSize, QSizeF(-1, -1));
112 QRectF legendRect;
112 QRectF legendRect;
113 QRectF result;
113 QRectF result;
114
114
115 switch (legend->alignment()) {
115 switch (legend->alignment()) {
116 case Qt::AlignTop: {
116 case Qt::AlignTop: {
117 legendRect = QRectF(geometry.topLeft(), QSizeF(geometry.width(), size.height()));
117 legendRect = QRectF(geometry.topLeft(), QSizeF(geometry.width(), size.height()));
118 result = geometry.adjusted(0, legendRect.height(), 0, 0);
118 result = geometry.adjusted(0, legendRect.height(), 0, 0);
119 break;
119 break;
120 }
120 }
121 case Qt::AlignBottom: {
121 case Qt::AlignBottom: {
122 legendRect = QRectF(QPointF(geometry.left(), geometry.bottom() - size.height()), QSizeF(geometry.width(), size.height()));
122 legendRect = QRectF(QPointF(geometry.left(), geometry.bottom() - size.height()), QSizeF(geometry.width(), size.height()));
123 result = geometry.adjusted(0, 0, 0, -legendRect.height());
123 result = geometry.adjusted(0, 0, 0, -legendRect.height());
124 break;
124 break;
125 }
125 }
126 case Qt::AlignLeft: {
126 case Qt::AlignLeft: {
127 qreal width = qMin(size.width(), geometry.width() * golden_ratio);
127 qreal width = qMin(size.width(), geometry.width() * golden_ratio);
128 legendRect = QRectF(geometry.topLeft(), QSizeF(width, geometry.height()));
128 legendRect = QRectF(geometry.topLeft(), QSizeF(width, geometry.height()));
129 result = geometry.adjusted(width, 0, 0, 0);
129 result = geometry.adjusted(width, 0, 0, 0);
130 break;
130 break;
131 }
131 }
132 case Qt::AlignRight: {
132 case Qt::AlignRight: {
133 qreal width = qMin(size.width(), geometry.width() * golden_ratio);
133 qreal width = qMin(size.width(), geometry.width() * golden_ratio);
134 legendRect = QRectF(QPointF(geometry.right() - width, geometry.top()), QSizeF(width, geometry.height()));
134 legendRect = QRectF(QPointF(geometry.right() - width, geometry.top()), QSizeF(width, geometry.height()));
135 result = geometry.adjusted(0, 0, -width, 0);
135 result = geometry.adjusted(0, 0, -width, 0);
136 break;
136 break;
137 }
137 }
138 default: {
138 default: {
139 legendRect = QRectF(0, 0, 0, 0);
139 legendRect = QRectF(0, 0, 0, 0);
140 result = geometry;
140 result = geometry;
141 break;
141 break;
142 }
142 }
143 }
143 }
144
144
145 legend->setGeometry(legendRect);
145 legend->setGeometry(legendRect);
146
146
147 return result;
147 return result;
148 }
148 }
149
149
150 QRectF AbstractChartLayout::calculateLegendMinimum(const QRectF &geometry, QLegend *legend) const
150 QRectF AbstractChartLayout::calculateLegendMinimum(const QRectF &geometry, QLegend *legend) const
151 {
151 {
152 QSizeF minSize = legend->effectiveSizeHint(Qt::MinimumSize, QSizeF(-1, -1));
152 QSizeF minSize = legend->effectiveSizeHint(Qt::MinimumSize, QSizeF(-1, -1));
153 return geometry.adjusted(0, 0, minSize.width(), minSize.height());
153 return geometry.adjusted(0, 0, minSize.width(), minSize.height());
154 }
154 }
155
155
156 QRectF AbstractChartLayout::calculateTitleGeometry(const QRectF &geometry, ChartTitle *title) const
156 QRectF AbstractChartLayout::calculateTitleGeometry(const QRectF &geometry, ChartTitle *title) const
157 {
157 {
158 title->setGeometry(geometry);
158 title->setGeometry(geometry);
159 QPointF center = geometry.center() - title->boundingRect().center();
159 // Round to full pixel via QPoint to avoid one pixel clipping on the edge in some cases
160 QPointF center((geometry.center() - title->boundingRect().center()).toPoint());
161
160 title->setPos(center.x(), title->pos().y());
162 title->setPos(center.x(), title->pos().y());
161 return geometry.adjusted(0, title->boundingRect().height()+1, 0, 0);
163 return geometry.adjusted(0, title->boundingRect().height()+1, 0, 0);
162 }
164 }
163
165
164 QRectF AbstractChartLayout::calculateTitleMinimum(const QRectF &minimum, ChartTitle *title) const
166 QRectF AbstractChartLayout::calculateTitleMinimum(const QRectF &minimum, ChartTitle *title) const
165 {
167 {
166 QSizeF min = title->sizeHint(Qt::MinimumSize);
168 QSizeF min = title->sizeHint(Qt::MinimumSize);
167 return minimum.adjusted(0, 0, min.width(), min.height());
169 return minimum.adjusted(0, 0, min.width(), min.height());
168 }
170 }
169
171
170 QSizeF AbstractChartLayout::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
172 QSizeF AbstractChartLayout::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
171 {
173 {
172 Q_UNUSED(constraint);
174 Q_UNUSED(constraint);
173 if (which == Qt::MinimumSize) {
175 if (which == Qt::MinimumSize) {
174 QList<ChartAxisElement *> axes = m_presenter->axisItems();
176 QList<ChartAxisElement *> axes = m_presenter->axisItems();
175 ChartTitle *title = m_presenter->titleElement();
177 ChartTitle *title = m_presenter->titleElement();
176 QLegend *legend = m_presenter->legend();
178 QLegend *legend = m_presenter->legend();
177 QRectF minimumRect(0, 0, 0, 0);
179 QRectF minimumRect(0, 0, 0, 0);
178 minimumRect = calculateBackgroundMinimum(minimumRect);
180 minimumRect = calculateBackgroundMinimum(minimumRect);
179 minimumRect = calculateContentMinimum(minimumRect);
181 minimumRect = calculateContentMinimum(minimumRect);
180 minimumRect = calculateTitleMinimum(minimumRect, title);
182 minimumRect = calculateTitleMinimum(minimumRect, title);
181 minimumRect = calculateLegendMinimum(minimumRect, legend);
183 minimumRect = calculateLegendMinimum(minimumRect, legend);
182 minimumRect = calculateAxisMinimum(minimumRect, axes);
184 minimumRect = calculateAxisMinimum(minimumRect, axes);
183 return minimumRect.united(m_minChartRect).size().toSize();
185 return minimumRect.united(m_minChartRect).size().toSize();
184 }
186 }
185 return QSize(-1, -1);
187 return QSize(-1, -1);
186 }
188 }
187
189
188 void AbstractChartLayout::setMargins(const QMargins &margins)
190 void AbstractChartLayout::setMargins(const QMargins &margins)
189 {
191 {
190 if (m_margins != margins) {
192 if (m_margins != margins) {
191 m_margins = margins;
193 m_margins = margins;
192 updateGeometry();
194 updateGeometry();
193 }
195 }
194 }
196 }
195
197
196 QMargins AbstractChartLayout::margins() const
198 QMargins AbstractChartLayout::margins() const
197 {
199 {
198 return m_margins;
200 return m_margins;
199 }
201 }
200
202
201 QT_CHARTS_END_NAMESPACE
203 QT_CHARTS_END_NAMESPACE
@@ -1,504 +1,510
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd
3 ** Copyright (C) 2015 The Qt Company Ltd
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to The Qt Company, please use contact form at http://qt.io
5 ** For any questions to The Qt Company, please use contact form at http://qt.io
6 **
6 **
7 ** This file is part of the Qt Charts module.
7 ** This file is part of the Qt Charts module.
8 **
8 **
9 ** Licensees holding valid commercial license for Qt may use this file in
9 ** Licensees holding valid commercial license for Qt may use this file in
10 ** accordance with the Qt License Agreement provided with the Software
10 ** accordance with the Qt License Agreement provided with the Software
11 ** or, alternatively, in accordance with the terms contained in a written
11 ** or, alternatively, in accordance with the terms contained in a written
12 ** agreement between you and The Qt Company.
12 ** agreement between you and The Qt Company.
13 **
13 **
14 ** If you have questions regarding the use of this file, please use
14 ** If you have questions regarding the use of this file, please use
15 ** contact form at http://qt.io
15 ** contact form at http://qt.io
16 **
16 **
17 ****************************************************************************/
17 ****************************************************************************/
18
18
19 #include <private/legendlayout_p.h>
19 #include <private/legendlayout_p.h>
20 #include <private/chartpresenter_p.h>
20 #include <private/chartpresenter_p.h>
21 #include <private/qlegend_p.h>
21 #include <private/qlegend_p.h>
22 #include <private/abstractchartlayout_p.h>
22 #include <private/abstractchartlayout_p.h>
23
23
24 #include <private/qlegendmarker_p.h>
24 #include <private/qlegendmarker_p.h>
25 #include <private/legendmarkeritem_p.h>
25 #include <private/legendmarkeritem_p.h>
26 #include <QtCharts/QLegendMarker>
26 #include <QtCharts/QLegendMarker>
27
27
28 QT_CHARTS_BEGIN_NAMESPACE
28 QT_CHARTS_BEGIN_NAMESPACE
29
29
30 LegendLayout::LegendLayout(QLegend *legend)
30 LegendLayout::LegendLayout(QLegend *legend)
31 : m_legend(legend),
31 : m_legend(legend),
32 m_offsetX(0),
32 m_offsetX(0),
33 m_offsetY(0)
33 m_offsetY(0)
34 {
34 {
35
35
36 }
36 }
37
37
38 LegendLayout::~LegendLayout()
38 LegendLayout::~LegendLayout()
39 {
39 {
40
40
41 }
41 }
42
42
43 void LegendLayout::setOffset(qreal x, qreal y)
43 void LegendLayout::setOffset(qreal x, qreal y)
44 {
44 {
45 bool scrollHorizontal = true;
45 bool scrollHorizontal = true;
46 switch (m_legend->alignment()) {
46 switch (m_legend->alignment()) {
47 case Qt::AlignTop:
47 case Qt::AlignTop:
48 case Qt::AlignBottom:
48 case Qt::AlignBottom:
49 scrollHorizontal = true;
49 scrollHorizontal = true;
50 break;
50 break;
51 case Qt::AlignLeft:
51 case Qt::AlignLeft:
52 case Qt::AlignRight:
52 case Qt::AlignRight:
53 scrollHorizontal = false;
53 scrollHorizontal = false;
54 break;
54 break;
55 }
55 }
56
56
57 // If detached, the scrolling direction is vertical instead of horizontal and vice versa.
57 // If detached, the scrolling direction is vertical instead of horizontal and vice versa.
58 if (!m_legend->isAttachedToChart())
58 if (!m_legend->isAttachedToChart())
59 scrollHorizontal = !scrollHorizontal;
59 scrollHorizontal = !scrollHorizontal;
60
60
61 QRectF boundingRect = geometry();
61 QRectF boundingRect = geometry();
62 qreal left, top, right, bottom;
62 qreal left, top, right, bottom;
63 getContentsMargins(&left, &top, &right, &bottom);
63 getContentsMargins(&left, &top, &right, &bottom);
64 boundingRect.adjust(left, top, -right, -bottom);
64 boundingRect.adjust(left, top, -right, -bottom);
65
65
66 // Limit offset between m_minOffset and m_maxOffset
66 // Limit offset between m_minOffset and m_maxOffset
67 if (scrollHorizontal) {
67 if (scrollHorizontal) {
68 if (m_width <= boundingRect.width())
68 if (m_width <= boundingRect.width())
69 return;
69 return;
70
70
71 if (x != m_offsetX) {
71 if (x != m_offsetX) {
72 m_offsetX = qBound(m_minOffsetX, x, m_maxOffsetX);
72 m_offsetX = qBound(m_minOffsetX, x, m_maxOffsetX);
73 m_legend->d_ptr->items()->setPos(-m_offsetX, boundingRect.top());
73 m_legend->d_ptr->items()->setPos(-m_offsetX, boundingRect.top());
74 }
74 }
75 } else {
75 } else {
76 if (m_height <= boundingRect.height())
76 if (m_height <= boundingRect.height())
77 return;
77 return;
78
78
79 if (y != m_offsetY) {
79 if (y != m_offsetY) {
80 m_offsetY = qBound(m_minOffsetY, y, m_maxOffsetY);
80 m_offsetY = qBound(m_minOffsetY, y, m_maxOffsetY);
81 m_legend->d_ptr->items()->setPos(boundingRect.left(), -m_offsetY);
81 m_legend->d_ptr->items()->setPos(boundingRect.left(), -m_offsetY);
82 }
82 }
83 }
83 }
84 }
84 }
85
85
86 QPointF LegendLayout::offset() const
86 QPointF LegendLayout::offset() const
87 {
87 {
88 return QPointF(m_offsetX, m_offsetY);
88 return QPointF(m_offsetX, m_offsetY);
89 }
89 }
90
90
91 void LegendLayout::invalidate()
91 void LegendLayout::invalidate()
92 {
92 {
93 QGraphicsLayout::invalidate();
93 QGraphicsLayout::invalidate();
94 if (m_legend->isAttachedToChart())
94 if (m_legend->isAttachedToChart())
95 m_legend->d_ptr->m_presenter->layout()->invalidate();
95 m_legend->d_ptr->m_presenter->layout()->invalidate();
96 }
96 }
97
97
98 void LegendLayout::setGeometry(const QRectF &rect)
98 void LegendLayout::setGeometry(const QRectF &rect)
99 {
99 {
100 m_legend->d_ptr->items()->setVisible(m_legend->isVisible());
100 m_legend->d_ptr->items()->setVisible(m_legend->isVisible());
101
101
102 QGraphicsLayout::setGeometry(rect);
102 QGraphicsLayout::setGeometry(rect);
103
103
104 if (m_legend->isAttachedToChart())
104 if (m_legend->isAttachedToChart())
105 setAttachedGeometry(rect);
105 setAttachedGeometry(rect);
106 else
106 else
107 setDettachedGeometry(rect);
107 setDettachedGeometry(rect);
108 }
108 }
109
109
110 void LegendLayout::setAttachedGeometry(const QRectF &rect)
110 void LegendLayout::setAttachedGeometry(const QRectF &rect)
111 {
111 {
112 if (!rect.isValid())
112 if (!rect.isValid())
113 return;
113 return;
114
114
115 qreal oldOffsetX = m_offsetX;
115 qreal oldOffsetX = m_offsetX;
116 qreal oldOffsetY = m_offsetY;
116 qreal oldOffsetY = m_offsetY;
117 m_offsetX = 0;
117 m_offsetX = 0;
118 m_offsetY = 0;
118 m_offsetY = 0;
119
119
120 QSizeF size(0, 0);
120 QSizeF size(0, 0);
121
121
122 if (m_legend->d_ptr->markers().isEmpty()) {
122 if (m_legend->d_ptr->markers().isEmpty()) {
123 return;
123 return;
124 }
124 }
125
125
126 m_width = 0;
126 m_width = 0;
127 m_height = 0;
127 m_height = 0;
128
128
129 qreal left, top, right, bottom;
129 qreal left, top, right, bottom;
130 getContentsMargins(&left, &top, &right, &bottom);
130 getContentsMargins(&left, &top, &right, &bottom);
131
131
132 QRectF geometry = rect.adjusted(left, top, -right, -bottom);
132 QRectF geometry = rect.adjusted(left, top, -right, -bottom);
133
133
134 switch(m_legend->alignment()) {
134 switch(m_legend->alignment()) {
135 case Qt::AlignTop:
135 case Qt::AlignTop:
136 case Qt::AlignBottom: {
136 case Qt::AlignBottom: {
137 // Calculate the space required for items and add them to a sorted list.
137 // Calculate the space required for items and add them to a sorted list.
138 qreal markerItemsWidth = 0;
138 qreal markerItemsWidth = 0;
139 qreal itemMargins = 0;
139 qreal itemMargins = 0;
140 QList<LegendWidthStruct *> legendWidthList;
140 QList<LegendWidthStruct *> legendWidthList;
141 foreach (QLegendMarker *marker, m_legend->d_ptr->markers()) {
141 foreach (QLegendMarker *marker, m_legend->d_ptr->markers()) {
142 LegendMarkerItem *item = marker->d_ptr->item();
142 LegendMarkerItem *item = marker->d_ptr->item();
143 if (item->isVisible()) {
143 if (item->isVisible()) {
144 QSizeF dummySize;
144 QSizeF dummySize;
145 qreal itemWidth = item->sizeHint(Qt::PreferredSize, dummySize).width();
145 qreal itemWidth = item->sizeHint(Qt::PreferredSize, dummySize).width();
146 LegendWidthStruct *structItem = new LegendWidthStruct;
146 LegendWidthStruct *structItem = new LegendWidthStruct;
147 structItem->item = item;
147 structItem->item = item;
148 structItem->width = itemWidth;
148 structItem->width = itemWidth;
149 legendWidthList.append(structItem);
149 legendWidthList.append(structItem);
150 markerItemsWidth += itemWidth;
150 markerItemsWidth += itemWidth;
151 itemMargins += marker->d_ptr->item()->m_margin;
151 itemMargins += marker->d_ptr->item()->m_margin;
152 }
152 }
153 }
153 }
154 std::sort(legendWidthList.begin(), legendWidthList.end(), widthLongerThan);
154 std::sort(legendWidthList.begin(), legendWidthList.end(), widthLongerThan);
155
155
156 // If the items would occupy more space than is available, start truncating them
156 // If the items would occupy more space than is available, start truncating them
157 // from the longest one.
157 // from the longest one.
158 qreal availableGeometry = geometry.width() - right - left * 2 - itemMargins;
158 qreal availableGeometry = geometry.width() - right - left * 2 - itemMargins;
159 if (markerItemsWidth >= availableGeometry && legendWidthList.count() > 0) {
159 if (markerItemsWidth >= availableGeometry && legendWidthList.count() > 0) {
160 bool truncated(false);
160 bool truncated(false);
161 int count = legendWidthList.count();
161 int count = legendWidthList.count();
162 for (int i = 1; i < count; i++) {
162 for (int i = 1; i < count; i++) {
163 int truncateIndex = i - 1;
163 int truncateIndex = i - 1;
164
164
165 while (legendWidthList.at(truncateIndex)->width >= legendWidthList.at(i)->width
165 while (legendWidthList.at(truncateIndex)->width >= legendWidthList.at(i)->width
166 && !truncated) {
166 && !truncated) {
167 legendWidthList.at(truncateIndex)->width--;
167 legendWidthList.at(truncateIndex)->width--;
168 markerItemsWidth--;
168 markerItemsWidth--;
169 if (i > 1) {
169 if (i > 1) {
170 // Truncate the items that are before the truncated one in the list.
170 // Truncate the items that are before the truncated one in the list.
171 for (int j = truncateIndex - 1; j >= 0; j--) {
171 for (int j = truncateIndex - 1; j >= 0; j--) {
172 if (legendWidthList.at(truncateIndex)->width
172 if (legendWidthList.at(truncateIndex)->width
173 < legendWidthList.at(j)->width) {
173 < legendWidthList.at(j)->width) {
174 legendWidthList.at(j)->width--;
174 legendWidthList.at(j)->width--;
175 markerItemsWidth--;
175 markerItemsWidth--;
176 }
176 }
177 }
177 }
178 }
178 }
179 if (markerItemsWidth < availableGeometry)
179 if (markerItemsWidth < availableGeometry)
180 truncated = true;
180 truncated = true;
181 }
181 }
182 // Truncate the last item if needed.
182 // Truncate the last item if needed.
183 if (i == count - 1) {
183 if (i == count - 1) {
184 if (legendWidthList.at(count - 1)->width
184 if (legendWidthList.at(count - 1)->width
185 > legendWidthList.at(truncateIndex)->width) {
185 > legendWidthList.at(truncateIndex)->width) {
186 legendWidthList.at(count - 1)->width--;
186 legendWidthList.at(count - 1)->width--;
187 markerItemsWidth--;
187 markerItemsWidth--;
188 }
188 }
189 }
189 }
190
190
191 if (truncated)
191 if (truncated)
192 break;
192 break;
193 }
193 }
194 // Items are of same width and all of them need to be truncated
194 // Items are of same width and all of them need to be truncated
195 // or there is just one item that is truncated.
195 // or there is just one item that is truncated.
196 while (markerItemsWidth >= availableGeometry) {
196 while (markerItemsWidth >= availableGeometry) {
197 for (int i = 0; i < count; i++) {
197 for (int i = 0; i < count; i++) {
198 legendWidthList.at(i)->width--;
198 legendWidthList.at(i)->width--;
199 markerItemsWidth--;
199 markerItemsWidth--;
200 }
200 }
201 }
201 }
202 }
202 }
203
203
204 QPointF point(0,0);
204 QPointF point(0,0);
205
205
206 int markerCount = m_legend->d_ptr->markers().count();
206 int markerCount = m_legend->d_ptr->markers().count();
207 for (int i = 0; i < markerCount; i++) {
207 for (int i = 0; i < markerCount; i++) {
208 QLegendMarker *marker;
208 QLegendMarker *marker;
209 if (m_legend->d_ptr->m_reverseMarkers)
209 if (m_legend->d_ptr->m_reverseMarkers)
210 marker = m_legend->d_ptr->markers().at(markerCount - 1 - i);
210 marker = m_legend->d_ptr->markers().at(markerCount - 1 - i);
211 else
211 else
212 marker = m_legend->d_ptr->markers().at(i);
212 marker = m_legend->d_ptr->markers().at(i);
213 LegendMarkerItem *item = marker->d_ptr->item();
213 LegendMarkerItem *item = marker->d_ptr->item();
214 if (item->isVisible()) {
214 if (item->isVisible()) {
215 QRectF itemRect = geometry;
215 QRectF itemRect = geometry;
216 qreal availableWidth = 0;
216 qreal availableWidth = 0;
217 for (int i = 0; i < legendWidthList.size(); ++i) {
217 for (int i = 0; i < legendWidthList.size(); ++i) {
218 if (legendWidthList.at(i)->item == item) {
218 if (legendWidthList.at(i)->item == item) {
219 availableWidth = legendWidthList.at(i)->width;
219 availableWidth = legendWidthList.at(i)->width;
220 break;
220 break;
221 }
221 }
222 }
222 }
223 itemRect.setWidth(availableWidth);
223 itemRect.setWidth(availableWidth);
224 item->setGeometry(itemRect);
224 item->setGeometry(itemRect);
225 item->setPos(point.x(),geometry.height()/2 - item->boundingRect().height()/2);
225 item->setPos(point.x(),geometry.height()/2 - item->boundingRect().height()/2);
226 const QRectF &rect = item->boundingRect();
226 const QRectF &rect = item->boundingRect();
227 size = size.expandedTo(rect.size());
227 size = size.expandedTo(rect.size());
228 qreal w = rect.width();
228 qreal w = rect.width();
229 m_width = m_width + w - item->m_margin;
229 m_width = m_width + w - item->m_margin;
230 point.setX(point.x() + w);
230 point.setX(point.x() + w);
231 }
231 }
232 }
232 }
233 // Delete structs from the container
233 // Delete structs from the container
234 qDeleteAll(legendWidthList);
234 qDeleteAll(legendWidthList);
235
235
236 if (m_width < geometry.width())
236 // Round to full pixel via QPoint to avoid one pixel clipping on the edge in some cases
237 m_legend->d_ptr->items()->setPos(geometry.width() / 2 - m_width / 2, geometry.top());
237 if (m_width < geometry.width()) {
238 else
238 m_legend->d_ptr->items()->setPos(QPoint(geometry.width() / 2 - m_width / 2,
239 m_legend->d_ptr->items()->setPos(geometry.topLeft());
239 geometry.top()));
240 } else {
241 m_legend->d_ptr->items()->setPos(geometry.topLeft().toPoint());
242 }
240 m_height = size.height();
243 m_height = size.height();
241 }
244 }
242 break;
245 break;
243 case Qt::AlignLeft:
246 case Qt::AlignLeft:
244 case Qt::AlignRight: {
247 case Qt::AlignRight: {
245 QPointF point(0,0);
248 QPointF point(0,0);
246 int markerCount = m_legend->d_ptr->markers().count();
249 int markerCount = m_legend->d_ptr->markers().count();
247 for (int i = 0; i < markerCount; i++) {
250 for (int i = 0; i < markerCount; i++) {
248 QLegendMarker *marker;
251 QLegendMarker *marker;
249 if (m_legend->d_ptr->m_reverseMarkers)
252 if (m_legend->d_ptr->m_reverseMarkers)
250 marker = m_legend->d_ptr->markers().at(markerCount - 1 - i);
253 marker = m_legend->d_ptr->markers().at(markerCount - 1 - i);
251 else
254 else
252 marker = m_legend->d_ptr->markers().at(i);
255 marker = m_legend->d_ptr->markers().at(i);
253 LegendMarkerItem *item = marker->d_ptr->item();
256 LegendMarkerItem *item = marker->d_ptr->item();
254 if (item->isVisible()) {
257 if (item->isVisible()) {
255 item->setGeometry(geometry);
258 item->setGeometry(geometry);
256 item->setPos(point);
259 item->setPos(point);
257 const QRectF &rect = item->boundingRect();
260 const QRectF &rect = item->boundingRect();
258 qreal h = rect.height();
261 qreal h = rect.height();
259 size = size.expandedTo(rect.size());
262 size = size.expandedTo(rect.size());
260 m_height+=h;
263 m_height+=h;
261 point.setY(point.y() + h);
264 point.setY(point.y() + h);
262 }
265 }
263 }
266 }
264
267
265 if (m_height < geometry.height())
268 // Round to full pixel via QPoint to avoid one pixel clipping on the edge in some cases
266 m_legend->d_ptr->items()->setPos(geometry.left(), geometry.height() / 2 - m_height / 2);
269 if (m_height < geometry.height()) {
267 else
270 m_legend->d_ptr->items()->setPos(QPoint(geometry.left(),
268 m_legend->d_ptr->items()->setPos(geometry.topLeft());
271 geometry.height() / 2 - m_height / 2));
272 } else {
273 m_legend->d_ptr->items()->setPos(geometry.topLeft().toPoint());
274 }
269 m_width = size.width();
275 m_width = size.width();
270 break;
276 break;
271 }
277 }
272 }
278 }
273
279
274 m_minOffsetX = -left;
280 m_minOffsetX = -left;
275 m_minOffsetY = - top;
281 m_minOffsetY = - top;
276 m_maxOffsetX = m_width - geometry.width() - right;
282 m_maxOffsetX = m_width - geometry.width() - right;
277 m_maxOffsetY = m_height - geometry.height() - bottom;
283 m_maxOffsetY = m_height - geometry.height() - bottom;
278
284
279 setOffset(oldOffsetX, oldOffsetY);
285 setOffset(oldOffsetX, oldOffsetY);
280 }
286 }
281
287
282 void LegendLayout::setDettachedGeometry(const QRectF &rect)
288 void LegendLayout::setDettachedGeometry(const QRectF &rect)
283 {
289 {
284 if (!rect.isValid())
290 if (!rect.isValid())
285 return;
291 return;
286
292
287 // Detached layout is different.
293 // Detached layout is different.
288 // In detached mode legend may have multiple rows and columns, so layout calculations
294 // In detached mode legend may have multiple rows and columns, so layout calculations
289 // differ a log from attached mode.
295 // differ a log from attached mode.
290 // Also the scrolling logic is bit different.
296 // Also the scrolling logic is bit different.
291
297
292 qreal oldOffsetX = m_offsetX;
298 qreal oldOffsetX = m_offsetX;
293 qreal oldOffsetY = m_offsetY;
299 qreal oldOffsetY = m_offsetY;
294 m_offsetX = 0;
300 m_offsetX = 0;
295 m_offsetY = 0;
301 m_offsetY = 0;
296
302
297 qreal left, top, right, bottom;
303 qreal left, top, right, bottom;
298 getContentsMargins(&left, &top, &right, &bottom);
304 getContentsMargins(&left, &top, &right, &bottom);
299 QRectF geometry = rect.adjusted(left, top, -right, -bottom);
305 QRectF geometry = rect.adjusted(left, top, -right, -bottom);
300
306
301 QSizeF size(0, 0);
307 QSizeF size(0, 0);
302
308
303 QList<QLegendMarker *> markers = m_legend->d_ptr->markers();
309 QList<QLegendMarker *> markers = m_legend->d_ptr->markers();
304
310
305 if (markers.isEmpty())
311 if (markers.isEmpty())
306 return;
312 return;
307
313
308 switch (m_legend->alignment()) {
314 switch (m_legend->alignment()) {
309 case Qt::AlignTop: {
315 case Qt::AlignTop: {
310 QPointF point(0, 0);
316 QPointF point(0, 0);
311 m_width = 0;
317 m_width = 0;
312 m_height = 0;
318 m_height = 0;
313 for (int i = 0; i < markers.count(); i++) {
319 for (int i = 0; i < markers.count(); i++) {
314 LegendMarkerItem *item = markers.at(i)->d_ptr->item();
320 LegendMarkerItem *item = markers.at(i)->d_ptr->item();
315 if (item->isVisible()) {
321 if (item->isVisible()) {
316 item->setGeometry(geometry);
322 item->setGeometry(geometry);
317 item->setPos(point.x(),point.y());
323 item->setPos(point.x(),point.y());
318 const QRectF &boundingRect = item->boundingRect();
324 const QRectF &boundingRect = item->boundingRect();
319 qreal w = boundingRect.width();
325 qreal w = boundingRect.width();
320 qreal h = boundingRect.height();
326 qreal h = boundingRect.height();
321 m_width = qMax(m_width,w);
327 m_width = qMax(m_width,w);
322 m_height = qMax(m_height,h);
328 m_height = qMax(m_height,h);
323 point.setX(point.x() + w);
329 point.setX(point.x() + w);
324 if (point.x() + w > geometry.left() + geometry.width() - right) {
330 if (point.x() + w > geometry.left() + geometry.width() - right) {
325 // Next item would go off rect.
331 // Next item would go off rect.
326 point.setX(0);
332 point.setX(0);
327 point.setY(point.y() + h);
333 point.setY(point.y() + h);
328 if (i+1 < markers.count()) {
334 if (i+1 < markers.count()) {
329 m_height += h;
335 m_height += h;
330 }
336 }
331 }
337 }
332 }
338 }
333 }
339 }
334 m_legend->d_ptr->items()->setPos(geometry.topLeft());
340 m_legend->d_ptr->items()->setPos(geometry.topLeft());
335
341
336 m_minOffsetX = -left;
342 m_minOffsetX = -left;
337 m_minOffsetY = -top;
343 m_minOffsetY = -top;
338 m_maxOffsetX = m_width - geometry.width() - right;
344 m_maxOffsetX = m_width - geometry.width() - right;
339 m_maxOffsetY = m_height - geometry.height() - bottom;
345 m_maxOffsetY = m_height - geometry.height() - bottom;
340 }
346 }
341 break;
347 break;
342 case Qt::AlignBottom: {
348 case Qt::AlignBottom: {
343 QPointF point(0, geometry.height());
349 QPointF point(0, geometry.height());
344 m_width = 0;
350 m_width = 0;
345 m_height = 0;
351 m_height = 0;
346 for (int i = 0; i < markers.count(); i++) {
352 for (int i = 0; i < markers.count(); i++) {
347 LegendMarkerItem *item = markers.at(i)->d_ptr->item();
353 LegendMarkerItem *item = markers.at(i)->d_ptr->item();
348 if (item->isVisible()) {
354 if (item->isVisible()) {
349 item->setGeometry(geometry);
355 item->setGeometry(geometry);
350 const QRectF &boundingRect = item->boundingRect();
356 const QRectF &boundingRect = item->boundingRect();
351 qreal w = boundingRect.width();
357 qreal w = boundingRect.width();
352 qreal h = boundingRect.height();
358 qreal h = boundingRect.height();
353 m_width = qMax(m_width,w);
359 m_width = qMax(m_width,w);
354 m_height = qMax(m_height,h);
360 m_height = qMax(m_height,h);
355 item->setPos(point.x(),point.y() - h);
361 item->setPos(point.x(),point.y() - h);
356 point.setX(point.x() + w);
362 point.setX(point.x() + w);
357 if (point.x() + w > geometry.left() + geometry.width() - right) {
363 if (point.x() + w > geometry.left() + geometry.width() - right) {
358 // Next item would go off rect.
364 // Next item would go off rect.
359 point.setX(0);
365 point.setX(0);
360 point.setY(point.y() - h);
366 point.setY(point.y() - h);
361 if (i+1 < markers.count()) {
367 if (i+1 < markers.count()) {
362 m_height += h;
368 m_height += h;
363 }
369 }
364 }
370 }
365 }
371 }
366 }
372 }
367 m_legend->d_ptr->items()->setPos(geometry.topLeft());
373 m_legend->d_ptr->items()->setPos(geometry.topLeft());
368
374
369 m_minOffsetX = -left;
375 m_minOffsetX = -left;
370 m_minOffsetY = -m_height + geometry.height() - top;
376 m_minOffsetY = -m_height + geometry.height() - top;
371 m_maxOffsetX = m_width - geometry.width() - right;
377 m_maxOffsetX = m_width - geometry.width() - right;
372 m_maxOffsetY = -bottom;
378 m_maxOffsetY = -bottom;
373 }
379 }
374 break;
380 break;
375 case Qt::AlignLeft: {
381 case Qt::AlignLeft: {
376 QPointF point(0, 0);
382 QPointF point(0, 0);
377 m_width = 0;
383 m_width = 0;
378 m_height = 0;
384 m_height = 0;
379 qreal maxWidth = 0;
385 qreal maxWidth = 0;
380 for (int i = 0; i < markers.count(); i++) {
386 for (int i = 0; i < markers.count(); i++) {
381 LegendMarkerItem *item = markers.at(i)->d_ptr->item();
387 LegendMarkerItem *item = markers.at(i)->d_ptr->item();
382 if (item->isVisible()) {
388 if (item->isVisible()) {
383 item->setGeometry(geometry);
389 item->setGeometry(geometry);
384 const QRectF &boundingRect = item->boundingRect();
390 const QRectF &boundingRect = item->boundingRect();
385 qreal w = boundingRect.width();
391 qreal w = boundingRect.width();
386 qreal h = boundingRect.height();
392 qreal h = boundingRect.height();
387 m_height = qMax(m_height,h);
393 m_height = qMax(m_height,h);
388 maxWidth = qMax(maxWidth,w);
394 maxWidth = qMax(maxWidth,w);
389 item->setPos(point.x(),point.y());
395 item->setPos(point.x(),point.y());
390 point.setY(point.y() + h);
396 point.setY(point.y() + h);
391 if (point.y() + h > geometry.bottom() - bottom) {
397 if (point.y() + h > geometry.bottom() - bottom) {
392 // Next item would go off rect.
398 // Next item would go off rect.
393 point.setX(point.x() + maxWidth);
399 point.setX(point.x() + maxWidth);
394 point.setY(0);
400 point.setY(0);
395 if (i+1 < markers.count()) {
401 if (i+1 < markers.count()) {
396 m_width += maxWidth;
402 m_width += maxWidth;
397 maxWidth = 0;
403 maxWidth = 0;
398 }
404 }
399 }
405 }
400 }
406 }
401 }
407 }
402 m_width += maxWidth;
408 m_width += maxWidth;
403 m_legend->d_ptr->items()->setPos(geometry.topLeft());
409 m_legend->d_ptr->items()->setPos(geometry.topLeft());
404
410
405 m_minOffsetX = -left;
411 m_minOffsetX = -left;
406 m_minOffsetY = -top;
412 m_minOffsetY = -top;
407 m_maxOffsetX = m_width - geometry.width() - right;
413 m_maxOffsetX = m_width - geometry.width() - right;
408 m_maxOffsetY = m_height - geometry.height() - bottom;
414 m_maxOffsetY = m_height - geometry.height() - bottom;
409 }
415 }
410 break;
416 break;
411 case Qt::AlignRight: {
417 case Qt::AlignRight: {
412 QPointF point(geometry.width(), 0);
418 QPointF point(geometry.width(), 0);
413 m_width = 0;
419 m_width = 0;
414 m_height = 0;
420 m_height = 0;
415 qreal maxWidth = 0;
421 qreal maxWidth = 0;
416 for (int i = 0; i < markers.count(); i++) {
422 for (int i = 0; i < markers.count(); i++) {
417 LegendMarkerItem *item = markers.at(i)->d_ptr->item();
423 LegendMarkerItem *item = markers.at(i)->d_ptr->item();
418 if (item->isVisible()) {
424 if (item->isVisible()) {
419 item->setGeometry(geometry);
425 item->setGeometry(geometry);
420 const QRectF &boundingRect = item->boundingRect();
426 const QRectF &boundingRect = item->boundingRect();
421 qreal w = boundingRect.width();
427 qreal w = boundingRect.width();
422 qreal h = boundingRect.height();
428 qreal h = boundingRect.height();
423 m_height = qMax(m_height,h);
429 m_height = qMax(m_height,h);
424 maxWidth = qMax(maxWidth,w);
430 maxWidth = qMax(maxWidth,w);
425 item->setPos(point.x() - w,point.y());
431 item->setPos(point.x() - w,point.y());
426 point.setY(point.y() + h);
432 point.setY(point.y() + h);
427 if (point.y() + h > geometry.bottom()-bottom) {
433 if (point.y() + h > geometry.bottom()-bottom) {
428 // Next item would go off rect.
434 // Next item would go off rect.
429 point.setX(point.x() - maxWidth);
435 point.setX(point.x() - maxWidth);
430 point.setY(0);
436 point.setY(0);
431 if (i+1 < markers.count()) {
437 if (i+1 < markers.count()) {
432 m_width += maxWidth;
438 m_width += maxWidth;
433 maxWidth = 0;
439 maxWidth = 0;
434 }
440 }
435 }
441 }
436 }
442 }
437 }
443 }
438 m_width += maxWidth;
444 m_width += maxWidth;
439 m_legend->d_ptr->items()->setPos(geometry.topLeft());
445 m_legend->d_ptr->items()->setPos(geometry.topLeft());
440
446
441 m_minOffsetX = - m_width + geometry.width() - left;
447 m_minOffsetX = - m_width + geometry.width() - left;
442 m_minOffsetY = -top;
448 m_minOffsetY = -top;
443 m_maxOffsetX = - right;
449 m_maxOffsetX = - right;
444 m_maxOffsetY = m_height - geometry.height() - bottom;
450 m_maxOffsetY = m_height - geometry.height() - bottom;
445 }
451 }
446 break;
452 break;
447 default:
453 default:
448 break;
454 break;
449 }
455 }
450
456
451 setOffset(oldOffsetX, oldOffsetY);
457 setOffset(oldOffsetX, oldOffsetY);
452 }
458 }
453
459
454 QSizeF LegendLayout::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
460 QSizeF LegendLayout::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
455 {
461 {
456 QSizeF size(0, 0);
462 QSizeF size(0, 0);
457 qreal left, top, right, bottom;
463 qreal left, top, right, bottom;
458 getContentsMargins(&left, &top, &right, &bottom);
464 getContentsMargins(&left, &top, &right, &bottom);
459
465
460 if(constraint.isValid()) {
466 if(constraint.isValid()) {
461 foreach(QLegendMarker *marker, m_legend->d_ptr->markers()) {
467 foreach(QLegendMarker *marker, m_legend->d_ptr->markers()) {
462 LegendMarkerItem *item = marker->d_ptr->item();
468 LegendMarkerItem *item = marker->d_ptr->item();
463 size = size.expandedTo(item->effectiveSizeHint(which));
469 size = size.expandedTo(item->effectiveSizeHint(which));
464 }
470 }
465 size = size.boundedTo(constraint);
471 size = size.boundedTo(constraint);
466 }
472 }
467 else if (constraint.width() >= 0) {
473 else if (constraint.width() >= 0) {
468 qreal width = 0;
474 qreal width = 0;
469 qreal height = 0;
475 qreal height = 0;
470 foreach(QLegendMarker *marker, m_legend->d_ptr->markers()) {
476 foreach(QLegendMarker *marker, m_legend->d_ptr->markers()) {
471 LegendMarkerItem *item = marker->d_ptr->item();
477 LegendMarkerItem *item = marker->d_ptr->item();
472 width+=item->effectiveSizeHint(which).width();
478 width+=item->effectiveSizeHint(which).width();
473 height=qMax(height,item->effectiveSizeHint(which).height());
479 height=qMax(height,item->effectiveSizeHint(which).height());
474 }
480 }
475
481
476 size = QSizeF(qMin(constraint.width(),width), height);
482 size = QSizeF(qMin(constraint.width(),width), height);
477 }
483 }
478 else if (constraint.height() >= 0) {
484 else if (constraint.height() >= 0) {
479 qreal width = 0;
485 qreal width = 0;
480 qreal height = 0;
486 qreal height = 0;
481 foreach(QLegendMarker *marker, m_legend->d_ptr->markers()) {
487 foreach(QLegendMarker *marker, m_legend->d_ptr->markers()) {
482 LegendMarkerItem *item = marker->d_ptr->item();
488 LegendMarkerItem *item = marker->d_ptr->item();
483 width=qMax(width,item->effectiveSizeHint(which).width());
489 width=qMax(width,item->effectiveSizeHint(which).width());
484 height+=height,item->effectiveSizeHint(which).height();
490 height+=height,item->effectiveSizeHint(which).height();
485 }
491 }
486 size = QSizeF(width,qMin(constraint.height(),height));
492 size = QSizeF(width,qMin(constraint.height(),height));
487 }
493 }
488 else {
494 else {
489 foreach(QLegendMarker *marker, m_legend->d_ptr->markers()) {
495 foreach(QLegendMarker *marker, m_legend->d_ptr->markers()) {
490 LegendMarkerItem *item = marker->d_ptr->item();
496 LegendMarkerItem *item = marker->d_ptr->item();
491 size = size.expandedTo(item->effectiveSizeHint(which));
497 size = size.expandedTo(item->effectiveSizeHint(which));
492 }
498 }
493 }
499 }
494 size += QSize(left + right, top + bottom);
500 size += QSize(left + right, top + bottom);
495 return size;
501 return size;
496 }
502 }
497
503
498 bool LegendLayout::widthLongerThan(const LegendWidthStruct *item1,
504 bool LegendLayout::widthLongerThan(const LegendWidthStruct *item1,
499 const LegendWidthStruct *item2)
505 const LegendWidthStruct *item2)
500 {
506 {
501 return item1->width > item2->width;
507 return item1->width > item2->width;
502 }
508 }
503
509
504 QT_CHARTS_END_NAMESPACE
510 QT_CHARTS_END_NAMESPACE
@@ -1,10 +1,9
1 !include( ../../tests.pri ) {
1 !include( ../../tests.pri ) {
2 error( "Couldn't find the test.pri file!" )
2 error( "Couldn't find the test.pri file!" )
3 }
3 }
4 include(charts/charts.pri)
4 include(charts/charts.pri)
5 TARGET = chartviewer
5 TARGET = chartviewer
6 QT += opengl
7 INCLUDEPATH += .
6 INCLUDEPATH += .
8 SOURCES += main.cpp window.cpp view.cpp grid.cpp
7 SOURCES += main.cpp window.cpp view.cpp grid.cpp
9 HEADERS += window.h view.h charts.h model.h grid.h
8 HEADERS += window.h view.h charts.h model.h grid.h
10
9
@@ -1,585 +1,585
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd
3 ** Copyright (C) 2015 The Qt Company Ltd
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to The Qt Company, please use contact form at http://qt.io
5 ** For any questions to The Qt Company, please use contact form at http://qt.io
6 **
6 **
7 ** This file is part of the Qt Charts module.
7 ** This file is part of the Qt Charts module.
8 **
8 **
9 ** Licensees holding valid commercial license for Qt may use this file in
9 ** Licensees holding valid commercial license for Qt may use this file in
10 ** accordance with the Qt License Agreement provided with the Software
10 ** accordance with the Qt License Agreement provided with the Software
11 ** or, alternatively, in accordance with the terms contained in a written
11 ** or, alternatively, in accordance with the terms contained in a written
12 ** agreement between you and The Qt Company.
12 ** agreement between you and The Qt Company.
13 **
13 **
14 ** If you have questions regarding the use of this file, please use
14 ** If you have questions regarding the use of this file, please use
15 ** contact form at http://qt.io
15 ** contact form at http://qt.io
16 **
16 **
17 ****************************************************************************/
17 ****************************************************************************/
18
18
19 #include "window.h"
19 #include "window.h"
20 #include "view.h"
20 #include "view.h"
21 #include "grid.h"
21 #include "grid.h"
22 #include "charts.h"
22 #include "charts.h"
23 #include <QtCharts/QChartView>
23 #include <QtCharts/QChartView>
24 #include <QtCharts/QAreaSeries>
24 #include <QtCharts/QAreaSeries>
25 #include <QtCharts/QLegend>
25 #include <QtCharts/QLegend>
26 #include <QtCharts/QValueAxis>
26 #include <QtCharts/QValueAxis>
27 #include <QtWidgets/QGridLayout>
27 #include <QtWidgets/QGridLayout>
28 #include <QtWidgets/QFormLayout>
28 #include <QtWidgets/QFormLayout>
29 #include <QtWidgets/QComboBox>
29 #include <QtWidgets/QComboBox>
30 #include <QtWidgets/QSpinBox>
30 #include <QtWidgets/QSpinBox>
31 #include <QtWidgets/QCheckBox>
31 #include <QtWidgets/QCheckBox>
32 #include <QtWidgets/QGroupBox>
32 #include <QtWidgets/QGroupBox>
33 #include <QtWidgets/QLabel>
33 #include <QtWidgets/QLabel>
34 #include <QtWidgets/QGraphicsScene>
34 #include <QtWidgets/QGraphicsScene>
35 #include <QtWidgets/QGraphicsLinearLayout>
35 #include <QtWidgets/QGraphicsLinearLayout>
36 #include <QtWidgets/QGraphicsProxyWidget>
36 #include <QtWidgets/QGraphicsProxyWidget>
37 #include <QtOpenGL/QGLWidget>
37 #include <QtWidgets/QOpenGLWidget>
38 #include <QtWidgets/QApplication>
38 #include <QtWidgets/QApplication>
39 #include <QtCore/QDebug>
39 #include <QtCore/QDebug>
40 #include <QtWidgets/QMenu>
40 #include <QtWidgets/QMenu>
41 #include <QtWidgets/QPushButton>
41 #include <QtWidgets/QPushButton>
42
42
43 Window::Window(const QVariantHash &parameters, QWidget *parent)
43 Window::Window(const QVariantHash &parameters, QWidget *parent)
44 : QMainWindow(parent),
44 : QMainWindow(parent),
45 m_scene(new QGraphicsScene(this)),
45 m_scene(new QGraphicsScene(this)),
46 m_view(0),
46 m_view(0),
47 m_form(0),
47 m_form(0),
48 m_themeComboBox(0),
48 m_themeComboBox(0),
49 m_antialiasCheckBox(0),
49 m_antialiasCheckBox(0),
50 m_animatedComboBox(0),
50 m_animatedComboBox(0),
51 m_legendComboBox(0),
51 m_legendComboBox(0),
52 m_templateComboBox(0),
52 m_templateComboBox(0),
53 m_viewComboBox(0),
53 m_viewComboBox(0),
54 m_xTickSpinBox(0),
54 m_xTickSpinBox(0),
55 m_yTickSpinBox(0),
55 m_yTickSpinBox(0),
56 m_minorXTickSpinBox(0),
56 m_minorXTickSpinBox(0),
57 m_minorYTickSpinBox(0),
57 m_minorYTickSpinBox(0),
58 m_openGLCheckBox(0),
58 m_openGLCheckBox(0),
59 m_zoomCheckBox(0),
59 m_zoomCheckBox(0),
60 m_scrollCheckBox(0),
60 m_scrollCheckBox(0),
61 m_baseLayout(new QGraphicsLinearLayout()),
61 m_baseLayout(new QGraphicsLinearLayout()),
62 m_menu(createMenu()),
62 m_menu(createMenu()),
63 m_template(0),
63 m_template(0),
64 m_grid(new Grid(-1))
64 m_grid(new Grid(-1))
65 {
65 {
66 createProxyWidgets();
66 createProxyWidgets();
67 // create layout
67 // create layout
68 QGraphicsLinearLayout *settingsLayout = new QGraphicsLinearLayout();
68 QGraphicsLinearLayout *settingsLayout = new QGraphicsLinearLayout();
69
69
70 settingsLayout->setOrientation(Qt::Vertical);
70 settingsLayout->setOrientation(Qt::Vertical);
71 settingsLayout->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
71 settingsLayout->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
72 settingsLayout->addItem(m_widgetHash["openGLCheckBox"]);
72 settingsLayout->addItem(m_widgetHash["openGLCheckBox"]);
73 settingsLayout->addItem(m_widgetHash["antialiasCheckBox"]);
73 settingsLayout->addItem(m_widgetHash["antialiasCheckBox"]);
74 settingsLayout->addItem(m_widgetHash["viewLabel"]);
74 settingsLayout->addItem(m_widgetHash["viewLabel"]);
75 settingsLayout->addItem(m_widgetHash["viewComboBox"]);
75 settingsLayout->addItem(m_widgetHash["viewComboBox"]);
76 settingsLayout->addItem(m_widgetHash["themeLabel"]);
76 settingsLayout->addItem(m_widgetHash["themeLabel"]);
77 settingsLayout->addItem(m_widgetHash["themeComboBox"]);
77 settingsLayout->addItem(m_widgetHash["themeComboBox"]);
78 settingsLayout->addItem(m_widgetHash["animationsLabel"]);
78 settingsLayout->addItem(m_widgetHash["animationsLabel"]);
79 settingsLayout->addItem(m_widgetHash["animatedComboBox"]);
79 settingsLayout->addItem(m_widgetHash["animatedComboBox"]);
80 settingsLayout->addItem(m_widgetHash["legendLabel"]);
80 settingsLayout->addItem(m_widgetHash["legendLabel"]);
81 settingsLayout->addItem(m_widgetHash["legendComboBox"]);
81 settingsLayout->addItem(m_widgetHash["legendComboBox"]);
82 settingsLayout->addItem(m_widgetHash["templateLabel"]);
82 settingsLayout->addItem(m_widgetHash["templateLabel"]);
83 settingsLayout->addItem(m_widgetHash["templateComboBox"]);
83 settingsLayout->addItem(m_widgetHash["templateComboBox"]);
84 settingsLayout->addItem(m_widgetHash["scrollCheckBox"]);
84 settingsLayout->addItem(m_widgetHash["scrollCheckBox"]);
85 settingsLayout->addItem(m_widgetHash["zoomCheckBox"]);
85 settingsLayout->addItem(m_widgetHash["zoomCheckBox"]);
86 settingsLayout->addItem(m_widgetHash["xTickLabel"]);
86 settingsLayout->addItem(m_widgetHash["xTickLabel"]);
87 settingsLayout->addItem(m_widgetHash["xTickSpinBox"]);
87 settingsLayout->addItem(m_widgetHash["xTickSpinBox"]);
88 settingsLayout->addItem(m_widgetHash["yTickLabel"]);
88 settingsLayout->addItem(m_widgetHash["yTickLabel"]);
89 settingsLayout->addItem(m_widgetHash["yTickSpinBox"]);
89 settingsLayout->addItem(m_widgetHash["yTickSpinBox"]);
90 settingsLayout->addItem(m_widgetHash["minorXTickLabel"]);
90 settingsLayout->addItem(m_widgetHash["minorXTickLabel"]);
91 settingsLayout->addItem(m_widgetHash["minorXTickSpinBox"]);
91 settingsLayout->addItem(m_widgetHash["minorXTickSpinBox"]);
92 settingsLayout->addItem(m_widgetHash["minorYTickLabel"]);
92 settingsLayout->addItem(m_widgetHash["minorYTickLabel"]);
93 settingsLayout->addItem(m_widgetHash["minorYTickSpinBox"]);
93 settingsLayout->addItem(m_widgetHash["minorYTickSpinBox"]);
94 settingsLayout->addStretch();
94 settingsLayout->addStretch();
95
95
96 m_baseLayout->setOrientation(Qt::Horizontal);
96 m_baseLayout->setOrientation(Qt::Horizontal);
97 m_baseLayout->addItem(m_grid);
97 m_baseLayout->addItem(m_grid);
98 m_baseLayout->addItem(settingsLayout);
98 m_baseLayout->addItem(settingsLayout);
99
99
100 m_form = new QGraphicsWidget();
100 m_form = new QGraphicsWidget();
101 m_form->setLayout(m_baseLayout);
101 m_form->setLayout(m_baseLayout);
102 m_scene->addItem(m_form);
102 m_scene->addItem(m_form);
103
103
104 m_view = new View(m_scene, m_form);
104 m_view = new View(m_scene, m_form);
105 m_view->setMinimumSize(m_form->minimumSize().toSize());
105 m_view->setMinimumSize(m_form->minimumSize().toSize());
106
106
107 // Set defaults
107 // Set defaults
108 m_antialiasCheckBox->setChecked(true);
108 m_antialiasCheckBox->setChecked(true);
109 initializeFromParamaters(parameters);
109 initializeFromParamaters(parameters);
110 updateUI();
110 updateUI();
111 if(!m_category.isEmpty() && !m_subcategory.isEmpty() && !m_name.isEmpty())
111 if(!m_category.isEmpty() && !m_subcategory.isEmpty() && !m_name.isEmpty())
112 m_grid->createCharts(m_category,m_subcategory,m_name);
112 m_grid->createCharts(m_category,m_subcategory,m_name);
113
113
114
114
115 handleGeometryChanged();
115 handleGeometryChanged();
116 setCentralWidget(m_view);
116 setCentralWidget(m_view);
117
117
118 connectSignals();
118 connectSignals();
119 }
119 }
120
120
121 Window::~Window()
121 Window::~Window()
122 {
122 {
123 }
123 }
124
124
125 void Window::connectSignals()
125 void Window::connectSignals()
126 {
126 {
127 QObject::connect(m_form, SIGNAL(geometryChanged()), this , SLOT(handleGeometryChanged()));
127 QObject::connect(m_form, SIGNAL(geometryChanged()), this , SLOT(handleGeometryChanged()));
128 QObject::connect(m_viewComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateUI()));
128 QObject::connect(m_viewComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateUI()));
129 QObject::connect(m_themeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateUI()));
129 QObject::connect(m_themeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateUI()));
130 QObject::connect(m_xTickSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateUI()));
130 QObject::connect(m_xTickSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateUI()));
131 QObject::connect(m_yTickSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateUI()));
131 QObject::connect(m_yTickSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateUI()));
132 QObject::connect(m_minorXTickSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateUI()));
132 QObject::connect(m_minorXTickSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateUI()));
133 QObject::connect(m_minorYTickSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateUI()));
133 QObject::connect(m_minorYTickSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateUI()));
134 QObject::connect(m_antialiasCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateUI()));
134 QObject::connect(m_antialiasCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateUI()));
135 QObject::connect(m_openGLCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateUI()));
135 QObject::connect(m_openGLCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateUI()));
136 QObject::connect(m_zoomCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateUI()));
136 QObject::connect(m_zoomCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateUI()));
137 QObject::connect(m_scrollCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateUI()));
137 QObject::connect(m_scrollCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateUI()));
138 QObject::connect(m_animatedComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateUI()));
138 QObject::connect(m_animatedComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateUI()));
139 QObject::connect(m_legendComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateUI()));
139 QObject::connect(m_legendComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateUI()));
140 QObject::connect(m_templateComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateUI()));
140 QObject::connect(m_templateComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateUI()));
141 QObject::connect(m_grid, SIGNAL(chartSelected(QChart*)), this, SLOT(handleChartSelected(QChart*)));
141 QObject::connect(m_grid, SIGNAL(chartSelected(QChart*)), this, SLOT(handleChartSelected(QChart*)));
142 }
142 }
143
143
144 void Window::createProxyWidgets()
144 void Window::createProxyWidgets()
145 {
145 {
146 m_themeComboBox = createThemeBox();
146 m_themeComboBox = createThemeBox();
147 m_viewComboBox = createViewBox();
147 m_viewComboBox = createViewBox();
148 m_xTickSpinBox = new QSpinBox();
148 m_xTickSpinBox = new QSpinBox();
149 m_xTickSpinBox->setMinimum(2);
149 m_xTickSpinBox->setMinimum(2);
150 m_xTickSpinBox->setValue(5);
150 m_xTickSpinBox->setValue(5);
151 m_yTickSpinBox = new QSpinBox();
151 m_yTickSpinBox = new QSpinBox();
152 m_yTickSpinBox->setMinimum(2);
152 m_yTickSpinBox->setMinimum(2);
153 m_yTickSpinBox->setValue(5);
153 m_yTickSpinBox->setValue(5);
154 m_minorXTickSpinBox = new QSpinBox();
154 m_minorXTickSpinBox = new QSpinBox();
155 m_minorYTickSpinBox = new QSpinBox();
155 m_minorYTickSpinBox = new QSpinBox();
156 m_antialiasCheckBox = new QCheckBox(tr("Anti-aliasing"));
156 m_antialiasCheckBox = new QCheckBox(tr("Anti-aliasing"));
157 m_animatedComboBox = createAnimationBox();
157 m_animatedComboBox = createAnimationBox();
158 m_legendComboBox = createLegendBox();
158 m_legendComboBox = createLegendBox();
159 m_openGLCheckBox = new QCheckBox(tr("OpenGL"));
159 m_openGLCheckBox = new QCheckBox(tr("OpenGL"));
160 m_zoomCheckBox = new QCheckBox(tr("Zoom"));
160 m_zoomCheckBox = new QCheckBox(tr("Zoom"));
161 m_scrollCheckBox = new QCheckBox(tr("Scroll"));
161 m_scrollCheckBox = new QCheckBox(tr("Scroll"));
162 m_templateComboBox = createTempleteBox();
162 m_templateComboBox = createTempleteBox();
163 m_widgetHash["viewLabel"] = m_scene->addWidget(new QLabel("View"));
163 m_widgetHash["viewLabel"] = m_scene->addWidget(new QLabel("View"));
164 m_widgetHash["viewComboBox"] = m_scene->addWidget(m_viewComboBox);
164 m_widgetHash["viewComboBox"] = m_scene->addWidget(m_viewComboBox);
165 m_widgetHash["themeComboBox"] = m_scene->addWidget(m_themeComboBox);
165 m_widgetHash["themeComboBox"] = m_scene->addWidget(m_themeComboBox);
166 m_widgetHash["antialiasCheckBox"] = m_scene->addWidget(m_antialiasCheckBox);
166 m_widgetHash["antialiasCheckBox"] = m_scene->addWidget(m_antialiasCheckBox);
167 m_widgetHash["animatedComboBox"] = m_scene->addWidget(m_animatedComboBox);
167 m_widgetHash["animatedComboBox"] = m_scene->addWidget(m_animatedComboBox);
168 m_widgetHash["legendComboBox"] = m_scene->addWidget(m_legendComboBox);
168 m_widgetHash["legendComboBox"] = m_scene->addWidget(m_legendComboBox);
169 m_widgetHash["xTickLabel"] = m_scene->addWidget(new QLabel("X Tick"));
169 m_widgetHash["xTickLabel"] = m_scene->addWidget(new QLabel("X Tick"));
170 m_widgetHash["xTickSpinBox"] = m_scene->addWidget(m_xTickSpinBox);
170 m_widgetHash["xTickSpinBox"] = m_scene->addWidget(m_xTickSpinBox);
171 m_widgetHash["yTickLabel"] = m_scene->addWidget(new QLabel("Y Tick"));
171 m_widgetHash["yTickLabel"] = m_scene->addWidget(new QLabel("Y Tick"));
172 m_widgetHash["yTickSpinBox"] = m_scene->addWidget(m_yTickSpinBox);
172 m_widgetHash["yTickSpinBox"] = m_scene->addWidget(m_yTickSpinBox);
173 m_widgetHash["minorXTickLabel"] = m_scene->addWidget(new QLabel("Minor X Tick"));
173 m_widgetHash["minorXTickLabel"] = m_scene->addWidget(new QLabel("Minor X Tick"));
174 m_widgetHash["minorXTickSpinBox"] = m_scene->addWidget(m_minorXTickSpinBox);
174 m_widgetHash["minorXTickSpinBox"] = m_scene->addWidget(m_minorXTickSpinBox);
175 m_widgetHash["minorYTickLabel"] = m_scene->addWidget(new QLabel("Minor Y Tick"));
175 m_widgetHash["minorYTickLabel"] = m_scene->addWidget(new QLabel("Minor Y Tick"));
176 m_widgetHash["minorYTickSpinBox"] = m_scene->addWidget(m_minorYTickSpinBox);
176 m_widgetHash["minorYTickSpinBox"] = m_scene->addWidget(m_minorYTickSpinBox);
177 m_widgetHash["openGLCheckBox"] = m_scene->addWidget(m_openGLCheckBox);
177 m_widgetHash["openGLCheckBox"] = m_scene->addWidget(m_openGLCheckBox);
178 m_widgetHash["themeLabel"] = m_scene->addWidget(new QLabel("Theme"));
178 m_widgetHash["themeLabel"] = m_scene->addWidget(new QLabel("Theme"));
179 m_widgetHash["animationsLabel"] = m_scene->addWidget(new QLabel("Animations"));
179 m_widgetHash["animationsLabel"] = m_scene->addWidget(new QLabel("Animations"));
180 m_widgetHash["legendLabel"] = m_scene->addWidget(new QLabel("Legend"));
180 m_widgetHash["legendLabel"] = m_scene->addWidget(new QLabel("Legend"));
181 m_widgetHash["templateLabel"] = m_scene->addWidget(new QLabel("Chart template"));
181 m_widgetHash["templateLabel"] = m_scene->addWidget(new QLabel("Chart template"));
182 m_widgetHash["templateComboBox"] = m_scene->addWidget(m_templateComboBox);
182 m_widgetHash["templateComboBox"] = m_scene->addWidget(m_templateComboBox);
183 m_widgetHash["zoomCheckBox"] = m_scene->addWidget(m_zoomCheckBox);
183 m_widgetHash["zoomCheckBox"] = m_scene->addWidget(m_zoomCheckBox);
184 m_widgetHash["scrollCheckBox"] = m_scene->addWidget(m_scrollCheckBox);
184 m_widgetHash["scrollCheckBox"] = m_scene->addWidget(m_scrollCheckBox);
185 }
185 }
186
186
187 QComboBox *Window::createThemeBox()
187 QComboBox *Window::createThemeBox()
188 {
188 {
189 QComboBox *themeComboBox = new ComboBox(this);
189 QComboBox *themeComboBox = new ComboBox(this);
190 themeComboBox->addItem("Light", QChart::ChartThemeLight);
190 themeComboBox->addItem("Light", QChart::ChartThemeLight);
191 themeComboBox->addItem("Blue Cerulean", QChart::ChartThemeBlueCerulean);
191 themeComboBox->addItem("Blue Cerulean", QChart::ChartThemeBlueCerulean);
192 themeComboBox->addItem("Dark", QChart::ChartThemeDark);
192 themeComboBox->addItem("Dark", QChart::ChartThemeDark);
193 themeComboBox->addItem("Brown Sand", QChart::ChartThemeBrownSand);
193 themeComboBox->addItem("Brown Sand", QChart::ChartThemeBrownSand);
194 themeComboBox->addItem("Blue NCS", QChart::ChartThemeBlueNcs);
194 themeComboBox->addItem("Blue NCS", QChart::ChartThemeBlueNcs);
195 themeComboBox->addItem("High Contrast", QChart::ChartThemeHighContrast);
195 themeComboBox->addItem("High Contrast", QChart::ChartThemeHighContrast);
196 themeComboBox->addItem("Blue Icy", QChart::ChartThemeBlueIcy);
196 themeComboBox->addItem("Blue Icy", QChart::ChartThemeBlueIcy);
197 themeComboBox->addItem("Qt", QChart::ChartThemeQt);
197 themeComboBox->addItem("Qt", QChart::ChartThemeQt);
198 return themeComboBox;
198 return themeComboBox;
199 }
199 }
200
200
201 QComboBox *Window::createViewBox()
201 QComboBox *Window::createViewBox()
202 {
202 {
203 QComboBox *viewComboBox = new ComboBox(this);
203 QComboBox *viewComboBox = new ComboBox(this);
204 viewComboBox->addItem("1 chart", 1);
204 viewComboBox->addItem("1 chart", 1);
205 viewComboBox->addItem("4 charts", 2);
205 viewComboBox->addItem("4 charts", 2);
206 viewComboBox->addItem("9 charts", 3);
206 viewComboBox->addItem("9 charts", 3);
207 viewComboBox->addItem("16 charts", 4);
207 viewComboBox->addItem("16 charts", 4);
208 return viewComboBox;
208 return viewComboBox;
209 }
209 }
210
210
211 QComboBox *Window::createAnimationBox()
211 QComboBox *Window::createAnimationBox()
212 {
212 {
213 QComboBox *animationComboBox = new ComboBox(this);
213 QComboBox *animationComboBox = new ComboBox(this);
214 animationComboBox->addItem("No Animations", QChart::NoAnimation);
214 animationComboBox->addItem("No Animations", QChart::NoAnimation);
215 animationComboBox->addItem("GridAxis Animations", QChart::GridAxisAnimations);
215 animationComboBox->addItem("GridAxis Animations", QChart::GridAxisAnimations);
216 animationComboBox->addItem("Series Animations", QChart::SeriesAnimations);
216 animationComboBox->addItem("Series Animations", QChart::SeriesAnimations);
217 animationComboBox->addItem("All Animations", QChart::AllAnimations);
217 animationComboBox->addItem("All Animations", QChart::AllAnimations);
218 return animationComboBox;
218 return animationComboBox;
219 }
219 }
220
220
221 QComboBox *Window::createLegendBox()
221 QComboBox *Window::createLegendBox()
222 {
222 {
223 QComboBox *legendComboBox = new ComboBox(this);
223 QComboBox *legendComboBox = new ComboBox(this);
224 legendComboBox->addItem("No Legend ", 0);
224 legendComboBox->addItem("No Legend ", 0);
225 legendComboBox->addItem("Legend Top", Qt::AlignTop);
225 legendComboBox->addItem("Legend Top", Qt::AlignTop);
226 legendComboBox->addItem("Legend Bottom", Qt::AlignBottom);
226 legendComboBox->addItem("Legend Bottom", Qt::AlignBottom);
227 legendComboBox->addItem("Legend Left", Qt::AlignLeft);
227 legendComboBox->addItem("Legend Left", Qt::AlignLeft);
228 legendComboBox->addItem("Legend Right", Qt::AlignRight);
228 legendComboBox->addItem("Legend Right", Qt::AlignRight);
229 return legendComboBox;
229 return legendComboBox;
230 }
230 }
231
231
232 QComboBox *Window::createTempleteBox()
232 QComboBox *Window::createTempleteBox()
233 {
233 {
234 QComboBox *templateComboBox = new ComboBox(this);
234 QComboBox *templateComboBox = new ComboBox(this);
235 templateComboBox->addItem("No Template", 0);
235 templateComboBox->addItem("No Template", 0);
236
236
237 Charts::ChartList list = Charts::chartList();
237 Charts::ChartList list = Charts::chartList();
238 QMultiMap<QString, Chart *> categoryMap;
238 QMultiMap<QString, Chart *> categoryMap;
239
239
240 foreach (Chart *chart, list)
240 foreach (Chart *chart, list)
241 categoryMap.insertMulti(chart->category(), chart);
241 categoryMap.insertMulti(chart->category(), chart);
242
242
243 foreach (const QString &category, categoryMap.uniqueKeys())
243 foreach (const QString &category, categoryMap.uniqueKeys())
244 templateComboBox->addItem(category, category);
244 templateComboBox->addItem(category, category);
245
245
246 return templateComboBox;
246 return templateComboBox;
247 }
247 }
248
248
249 void Window::initializeFromParamaters(const QVariantHash &parameters)
249 void Window::initializeFromParamaters(const QVariantHash &parameters)
250 {
250 {
251 if (parameters.contains("view")) {
251 if (parameters.contains("view")) {
252 int t = parameters["view"].toInt();
252 int t = parameters["view"].toInt();
253 for (int i = 0; i < m_viewComboBox->count(); ++i) {
253 for (int i = 0; i < m_viewComboBox->count(); ++i) {
254 if (m_viewComboBox->itemData(i).toInt() == t) {
254 if (m_viewComboBox->itemData(i).toInt() == t) {
255 m_viewComboBox->setCurrentIndex(i);
255 m_viewComboBox->setCurrentIndex(i);
256 break;
256 break;
257 }
257 }
258 }
258 }
259 }
259 }
260
260
261 if (parameters.contains("chart")) {
261 if (parameters.contains("chart")) {
262 QString t = parameters["chart"].toString();
262 QString t = parameters["chart"].toString();
263
263
264 QRegExp rx("([a-zA-Z0-9_]*)::([a-zA-Z0-9_]*)::([a-zA-Z0-9_]*)");
264 QRegExp rx("([a-zA-Z0-9_]*)::([a-zA-Z0-9_]*)::([a-zA-Z0-9_]*)");
265 int pos = rx.indexIn(t);
265 int pos = rx.indexIn(t);
266
266
267 if (pos > -1) {
267 if (pos > -1) {
268 m_category = rx.cap(1);
268 m_category = rx.cap(1);
269 m_subcategory = rx.cap(2);
269 m_subcategory = rx.cap(2);
270 m_name = rx.cap(3);
270 m_name = rx.cap(3);
271 m_templateComboBox->setCurrentIndex(0);
271 m_templateComboBox->setCurrentIndex(0);
272 }
272 }
273 else {
273 else {
274 for (int i = 0; i < m_templateComboBox->count(); ++i) {
274 for (int i = 0; i < m_templateComboBox->count(); ++i) {
275 if (m_templateComboBox->itemText(i) == t) {
275 if (m_templateComboBox->itemText(i) == t) {
276 m_templateComboBox->setCurrentIndex(i);
276 m_templateComboBox->setCurrentIndex(i);
277 break;
277 break;
278 }
278 }
279 }
279 }
280 }
280 }
281 }
281 }
282 if (parameters.contains("opengl")) {
282 if (parameters.contains("opengl")) {
283 bool checked = parameters["opengl"].toBool();
283 bool checked = parameters["opengl"].toBool();
284 m_openGLCheckBox->setChecked(checked);
284 m_openGLCheckBox->setChecked(checked);
285 }
285 }
286 if (parameters.contains("theme")) {
286 if (parameters.contains("theme")) {
287 QString t = parameters["theme"].toString();
287 QString t = parameters["theme"].toString();
288 for (int i = 0; i < m_themeComboBox->count(); ++i) {
288 for (int i = 0; i < m_themeComboBox->count(); ++i) {
289 if (m_themeComboBox->itemText(i) == t) {
289 if (m_themeComboBox->itemText(i) == t) {
290 m_themeComboBox->setCurrentIndex(i);
290 m_themeComboBox->setCurrentIndex(i);
291 break;
291 break;
292 }
292 }
293 }
293 }
294 }
294 }
295 if (parameters.contains("animation")) {
295 if (parameters.contains("animation")) {
296 QString t = parameters["animation"].toString();
296 QString t = parameters["animation"].toString();
297 for (int i = 0; i < m_animatedComboBox->count(); ++i) {
297 for (int i = 0; i < m_animatedComboBox->count(); ++i) {
298 if (m_animatedComboBox->itemText(i) == t) {
298 if (m_animatedComboBox->itemText(i) == t) {
299 m_animatedComboBox->setCurrentIndex(i);
299 m_animatedComboBox->setCurrentIndex(i);
300 break;
300 break;
301 }
301 }
302 }
302 }
303 }
303 }
304 if (parameters.contains("legend")) {
304 if (parameters.contains("legend")) {
305 QString t = parameters["legend"].toString();
305 QString t = parameters["legend"].toString();
306 for (int i = 0; i < m_legendComboBox->count(); ++i) {
306 for (int i = 0; i < m_legendComboBox->count(); ++i) {
307 if (m_legendComboBox->itemText(i) == t) {
307 if (m_legendComboBox->itemText(i) == t) {
308 m_legendComboBox->setCurrentIndex(i);
308 m_legendComboBox->setCurrentIndex(i);
309 break;
309 break;
310 }
310 }
311 }
311 }
312 }
312 }
313 }
313 }
314
314
315 void Window::updateUI()
315 void Window::updateUI()
316 {
316 {
317 checkView();
317 checkView();
318 checkTemplate();
318 checkTemplate();
319 checkOpenGL();
319 checkOpenGL();
320 checkTheme();
320 checkTheme();
321 checkAnimationOptions();
321 checkAnimationOptions();
322 checkLegend();
322 checkLegend();
323 checkState();
323 checkState();
324 checkXTick();
324 checkXTick();
325 checkYTick();
325 checkYTick();
326 checkMinorXTick();
326 checkMinorXTick();
327 checkMinorYTick();
327 checkMinorYTick();
328 }
328 }
329
329
330 void Window::checkView()
330 void Window::checkView()
331 {
331 {
332 int count(m_viewComboBox->itemData(m_viewComboBox->currentIndex()).toInt());
332 int count(m_viewComboBox->itemData(m_viewComboBox->currentIndex()).toInt());
333 if(m_grid->size()!=count){
333 if(m_grid->size()!=count){
334 m_grid->setSize(count);
334 m_grid->setSize(count);
335 m_template = 0;
335 m_template = 0;
336 }
336 }
337 }
337 }
338
338
339 void Window::checkXTick()
339 void Window::checkXTick()
340 {
340 {
341 foreach (QChart *chart, m_grid->charts()) {
341 foreach (QChart *chart, m_grid->charts()) {
342 if (qobject_cast<QValueAxis *>(chart->axisX())) {
342 if (qobject_cast<QValueAxis *>(chart->axisX())) {
343 QValueAxis *valueAxis = qobject_cast<QValueAxis *>(chart->axisX());
343 QValueAxis *valueAxis = qobject_cast<QValueAxis *>(chart->axisX());
344 valueAxis->setGridLineVisible();
344 valueAxis->setGridLineVisible();
345 valueAxis->setTickCount(m_xTickSpinBox->value());
345 valueAxis->setTickCount(m_xTickSpinBox->value());
346 }
346 }
347 }
347 }
348 }
348 }
349
349
350 void Window::checkYTick()
350 void Window::checkYTick()
351 {
351 {
352 foreach (QChart *chart, m_grid->charts()) {
352 foreach (QChart *chart, m_grid->charts()) {
353 if (qobject_cast<QValueAxis *>(chart->axisY())) {
353 if (qobject_cast<QValueAxis *>(chart->axisY())) {
354 QValueAxis *valueAxis = qobject_cast<QValueAxis *>(chart->axisY());
354 QValueAxis *valueAxis = qobject_cast<QValueAxis *>(chart->axisY());
355 valueAxis->setGridLineVisible();
355 valueAxis->setGridLineVisible();
356 valueAxis->setTickCount(m_yTickSpinBox->value());
356 valueAxis->setTickCount(m_yTickSpinBox->value());
357 }
357 }
358 }
358 }
359 }
359 }
360
360
361 void Window::checkMinorXTick()
361 void Window::checkMinorXTick()
362 {
362 {
363 foreach (QChart *chart, m_grid->charts()) {
363 foreach (QChart *chart, m_grid->charts()) {
364 if (qobject_cast<QValueAxis *>(chart->axisX())) {
364 if (qobject_cast<QValueAxis *>(chart->axisX())) {
365 QValueAxis *valueAxis = qobject_cast<QValueAxis *>(chart->axisX());
365 QValueAxis *valueAxis = qobject_cast<QValueAxis *>(chart->axisX());
366 valueAxis->setMinorGridLineVisible();
366 valueAxis->setMinorGridLineVisible();
367 valueAxis->setMinorTickCount(m_minorXTickSpinBox->value());
367 valueAxis->setMinorTickCount(m_minorXTickSpinBox->value());
368 }
368 }
369 }
369 }
370 }
370 }
371
371
372 void Window::checkMinorYTick()
372 void Window::checkMinorYTick()
373 {
373 {
374 foreach (QChart *chart, m_grid->charts()) {
374 foreach (QChart *chart, m_grid->charts()) {
375 if (qobject_cast<QValueAxis *>(chart->axisY())) {
375 if (qobject_cast<QValueAxis *>(chart->axisY())) {
376 QValueAxis *valueAxis = qobject_cast<QValueAxis *>(chart->axisY());
376 QValueAxis *valueAxis = qobject_cast<QValueAxis *>(chart->axisY());
377 valueAxis->setMinorGridLineVisible();
377 valueAxis->setMinorGridLineVisible();
378 valueAxis->setMinorTickCount(m_minorYTickSpinBox->value());
378 valueAxis->setMinorTickCount(m_minorYTickSpinBox->value());
379 }
379 }
380 }
380 }
381 }
381 }
382
382
383 void Window::checkLegend()
383 void Window::checkLegend()
384 {
384 {
385 Qt::Alignment alignment(m_legendComboBox->itemData(m_legendComboBox->currentIndex()).toInt());
385 Qt::Alignment alignment(m_legendComboBox->itemData(m_legendComboBox->currentIndex()).toInt());
386
386
387 if (!alignment) {
387 if (!alignment) {
388 foreach (QChart *chart, m_grid->charts())
388 foreach (QChart *chart, m_grid->charts())
389 chart->legend()->hide();
389 chart->legend()->hide();
390 } else {
390 } else {
391 foreach (QChart *chart, m_grid->charts()) {
391 foreach (QChart *chart, m_grid->charts()) {
392 chart->legend()->setAlignment(alignment);
392 chart->legend()->setAlignment(alignment);
393 chart->legend()->show();
393 chart->legend()->show();
394 }
394 }
395 }
395 }
396 }
396 }
397
397
398 void Window::checkOpenGL()
398 void Window::checkOpenGL()
399 {
399 {
400 bool opengl = m_openGLCheckBox->isChecked();
400 bool opengl = m_openGLCheckBox->isChecked();
401 bool isOpengl = qobject_cast<QGLWidget *>(m_view->viewport());
401 bool isOpengl = qobject_cast<QOpenGLWidget *>(m_view->viewport());
402 if ((isOpengl && !opengl) || (!isOpengl && opengl)) {
402 if ((isOpengl && !opengl) || (!isOpengl && opengl)) {
403 m_view->deleteLater();
403 m_view->deleteLater();
404 m_view = new View(m_scene, m_form);
404 m_view = new View(m_scene, m_form);
405 m_view->setViewport(!opengl ? new QWidget() : new QGLWidget());
405 m_view->setViewport(!opengl ? new QWidget() : new QOpenGLWidget());
406 setCentralWidget(m_view);
406 setCentralWidget(m_view);
407 }
407 }
408
408
409 bool antialias = m_antialiasCheckBox->isChecked();
409 bool antialias = m_antialiasCheckBox->isChecked();
410
410
411 if (opengl)
411 if (opengl)
412 m_view->setRenderHint(QPainter::HighQualityAntialiasing, antialias);
412 m_view->setRenderHint(QPainter::HighQualityAntialiasing, antialias);
413 else
413 else
414 m_view->setRenderHint(QPainter::Antialiasing, antialias);
414 m_view->setRenderHint(QPainter::Antialiasing, antialias);
415 }
415 }
416
416
417 void Window::checkAnimationOptions()
417 void Window::checkAnimationOptions()
418 {
418 {
419 QChart::AnimationOptions options(
419 QChart::AnimationOptions options(
420 m_animatedComboBox->itemData(m_animatedComboBox->currentIndex()).toInt());
420 m_animatedComboBox->itemData(m_animatedComboBox->currentIndex()).toInt());
421
421
422 QList<QChart *> charts = m_grid->charts();
422 QList<QChart *> charts = m_grid->charts();
423
423
424 if (!charts.isEmpty() && charts.at(0)->animationOptions() != options) {
424 if (!charts.isEmpty() && charts.at(0)->animationOptions() != options) {
425 foreach (QChart *chart, charts)
425 foreach (QChart *chart, charts)
426 chart->setAnimationOptions(options);
426 chart->setAnimationOptions(options);
427 }
427 }
428 }
428 }
429
429
430 void Window::checkState()
430 void Window::checkState()
431 {
431 {
432 bool scroll = m_scrollCheckBox->isChecked();
432 bool scroll = m_scrollCheckBox->isChecked();
433
433
434
434
435 if (m_grid->state() != Grid::ScrollState && scroll) {
435 if (m_grid->state() != Grid::ScrollState && scroll) {
436 m_grid->setState(Grid::ScrollState);
436 m_grid->setState(Grid::ScrollState);
437 m_zoomCheckBox->setChecked(false);
437 m_zoomCheckBox->setChecked(false);
438 } else if (!scroll && m_grid->state() == Grid::ScrollState) {
438 } else if (!scroll && m_grid->state() == Grid::ScrollState) {
439 m_grid->setState(Grid::NoState);
439 m_grid->setState(Grid::NoState);
440 }
440 }
441
441
442 bool zoom = m_zoomCheckBox->isChecked();
442 bool zoom = m_zoomCheckBox->isChecked();
443
443
444 if (m_grid->state() != Grid::ZoomState && zoom) {
444 if (m_grid->state() != Grid::ZoomState && zoom) {
445 m_grid->setState(Grid::ZoomState);
445 m_grid->setState(Grid::ZoomState);
446 m_scrollCheckBox->setChecked(false);
446 m_scrollCheckBox->setChecked(false);
447 } else if (!zoom && m_grid->state() == Grid::ZoomState) {
447 } else if (!zoom && m_grid->state() == Grid::ZoomState) {
448 m_grid->setState(Grid::NoState);
448 m_grid->setState(Grid::NoState);
449 }
449 }
450 }
450 }
451
451
452 void Window::checkTemplate()
452 void Window::checkTemplate()
453 {
453 {
454 int index = m_templateComboBox->currentIndex();
454 int index = m_templateComboBox->currentIndex();
455 if (m_template == index || index == 0)
455 if (m_template == index || index == 0)
456 return;
456 return;
457
457
458 m_template = index;
458 m_template = index;
459 QString category = m_templateComboBox->itemData(index).toString();
459 QString category = m_templateComboBox->itemData(index).toString();
460 m_grid->createCharts(category);
460 m_grid->createCharts(category);
461 }
461 }
462
462
463 void Window::checkTheme()
463 void Window::checkTheme()
464 {
464 {
465 QChart::ChartTheme theme = (QChart::ChartTheme) m_themeComboBox->itemData(
465 QChart::ChartTheme theme = (QChart::ChartTheme) m_themeComboBox->itemData(
466 m_themeComboBox->currentIndex()).toInt();
466 m_themeComboBox->currentIndex()).toInt();
467
467
468 foreach (QChart *chart, m_grid->charts())
468 foreach (QChart *chart, m_grid->charts())
469 chart->setTheme(theme);
469 chart->setTheme(theme);
470
470
471 QPalette pal = window()->palette();
471 QPalette pal = window()->palette();
472 if (theme == QChart::ChartThemeLight) {
472 if (theme == QChart::ChartThemeLight) {
473 pal.setColor(QPalette::Window, QRgb(0xf0f0f0));
473 pal.setColor(QPalette::Window, QRgb(0xf0f0f0));
474 pal.setColor(QPalette::WindowText, QRgb(0x404044));
474 pal.setColor(QPalette::WindowText, QRgb(0x404044));
475 } else if (theme == QChart::ChartThemeDark) {
475 } else if (theme == QChart::ChartThemeDark) {
476 pal.setColor(QPalette::Window, QRgb(0x121218));
476 pal.setColor(QPalette::Window, QRgb(0x121218));
477 pal.setColor(QPalette::WindowText, QRgb(0xd6d6d6));
477 pal.setColor(QPalette::WindowText, QRgb(0xd6d6d6));
478 } else if (theme == QChart::ChartThemeBlueCerulean) {
478 } else if (theme == QChart::ChartThemeBlueCerulean) {
479 pal.setColor(QPalette::Window, QRgb(0x40434a));
479 pal.setColor(QPalette::Window, QRgb(0x40434a));
480 pal.setColor(QPalette::WindowText, QRgb(0xd6d6d6));
480 pal.setColor(QPalette::WindowText, QRgb(0xd6d6d6));
481 } else if (theme == QChart::ChartThemeBrownSand) {
481 } else if (theme == QChart::ChartThemeBrownSand) {
482 pal.setColor(QPalette::Window, QRgb(0x9e8965));
482 pal.setColor(QPalette::Window, QRgb(0x9e8965));
483 pal.setColor(QPalette::WindowText, QRgb(0x404044));
483 pal.setColor(QPalette::WindowText, QRgb(0x404044));
484 } else if (theme == QChart::ChartThemeBlueNcs) {
484 } else if (theme == QChart::ChartThemeBlueNcs) {
485 pal.setColor(QPalette::Window, QRgb(0x018bba));
485 pal.setColor(QPalette::Window, QRgb(0x018bba));
486 pal.setColor(QPalette::WindowText, QRgb(0x404044));
486 pal.setColor(QPalette::WindowText, QRgb(0x404044));
487 } else if (theme == QChart::ChartThemeHighContrast) {
487 } else if (theme == QChart::ChartThemeHighContrast) {
488 pal.setColor(QPalette::Window, QRgb(0xffab03));
488 pal.setColor(QPalette::Window, QRgb(0xffab03));
489 pal.setColor(QPalette::WindowText, QRgb(0x181818));
489 pal.setColor(QPalette::WindowText, QRgb(0x181818));
490 } else if (theme == QChart::ChartThemeBlueIcy) {
490 } else if (theme == QChart::ChartThemeBlueIcy) {
491 pal.setColor(QPalette::Window, QRgb(0xcee7f0));
491 pal.setColor(QPalette::Window, QRgb(0xcee7f0));
492 pal.setColor(QPalette::WindowText, QRgb(0x404044));
492 pal.setColor(QPalette::WindowText, QRgb(0x404044));
493 } else if (theme == QChart::ChartThemeQt) {
493 } else if (theme == QChart::ChartThemeQt) {
494 pal.setColor(QPalette::Window, QRgb(0xf0f0f0));
494 pal.setColor(QPalette::Window, QRgb(0xf0f0f0));
495 pal.setColor(QPalette::WindowText, QRgb(0x404044));
495 pal.setColor(QPalette::WindowText, QRgb(0x404044));
496 } else {
496 } else {
497 pal.setColor(QPalette::Window, QRgb(0xf0f0f0));
497 pal.setColor(QPalette::Window, QRgb(0xf0f0f0));
498 pal.setColor(QPalette::WindowText, QRgb(0x404044));
498 pal.setColor(QPalette::WindowText, QRgb(0x404044));
499 }
499 }
500 foreach (QGraphicsProxyWidget *widget, m_widgetHash)
500 foreach (QGraphicsProxyWidget *widget, m_widgetHash)
501 widget->setPalette(pal);
501 widget->setPalette(pal);
502 m_view->setBackgroundBrush(pal.color((QPalette::Window)));
502 m_view->setBackgroundBrush(pal.color((QPalette::Window)));
503 m_grid->setRubberPen(pal.color((QPalette::WindowText)));
503 m_grid->setRubberPen(pal.color((QPalette::WindowText)));
504 }
504 }
505
505
506 void Window::comboBoxFocused(QComboBox *combobox)
506 void Window::comboBoxFocused(QComboBox *combobox)
507 {
507 {
508 foreach (QGraphicsProxyWidget *widget , m_widgetHash) {
508 foreach (QGraphicsProxyWidget *widget , m_widgetHash) {
509 if (widget->widget() == combobox)
509 if (widget->widget() == combobox)
510 widget->setZValue(2.0);
510 widget->setZValue(2.0);
511 else
511 else
512 widget->setZValue(0.0);
512 widget->setZValue(0.0);
513 }
513 }
514 }
514 }
515
515
516 void Window::handleChartSelected(QChart *qchart)
516 void Window::handleChartSelected(QChart *qchart)
517 {
517 {
518 if (m_templateComboBox->currentIndex() != 0)
518 if (m_templateComboBox->currentIndex() != 0)
519 return;
519 return;
520
520
521 QAction *chosen = m_menu->exec(QCursor::pos());
521 QAction *chosen = m_menu->exec(QCursor::pos());
522
522
523 if (chosen) {
523 if (chosen) {
524 Chart *chart = (Chart *) chosen->data().value<void *>();
524 Chart *chart = (Chart *) chosen->data().value<void *>();
525 m_grid->replaceChart(qchart, chart);
525 m_grid->replaceChart(qchart, chart);
526 updateUI();
526 updateUI();
527 }
527 }
528 }
528 }
529
529
530 QMenu *Window::createMenu()
530 QMenu *Window::createMenu()
531 {
531 {
532 Charts::ChartList list = Charts::chartList();
532 Charts::ChartList list = Charts::chartList();
533 QMultiMap<QString, Chart *> categoryMap;
533 QMultiMap<QString, Chart *> categoryMap;
534
534
535 QMenu *result = new QMenu(this);
535 QMenu *result = new QMenu(this);
536
536
537 foreach (Chart *chart, list)
537 foreach (Chart *chart, list)
538 categoryMap.insertMulti(chart->category(), chart);
538 categoryMap.insertMulti(chart->category(), chart);
539
539
540 foreach (const QString &category, categoryMap.uniqueKeys()) {
540 foreach (const QString &category, categoryMap.uniqueKeys()) {
541 QMenu *menu(0);
541 QMenu *menu(0);
542 QMultiMap<QString, Chart *> subCategoryMap;
542 QMultiMap<QString, Chart *> subCategoryMap;
543 if (category.isEmpty()) {
543 if (category.isEmpty()) {
544 menu = result;
544 menu = result;
545 } else {
545 } else {
546 menu = new QMenu(category, this);
546 menu = new QMenu(category, this);
547 result->addMenu(menu);
547 result->addMenu(menu);
548 }
548 }
549
549
550 foreach (Chart *chart, categoryMap.values(category))
550 foreach (Chart *chart, categoryMap.values(category))
551 subCategoryMap.insert(chart->subCategory(), chart);
551 subCategoryMap.insert(chart->subCategory(), chart);
552
552
553 foreach (const QString &subCategory, subCategoryMap.uniqueKeys()) {
553 foreach (const QString &subCategory, subCategoryMap.uniqueKeys()) {
554 QMenu *subMenu(0);
554 QMenu *subMenu(0);
555 if (subCategory.isEmpty()) {
555 if (subCategory.isEmpty()) {
556 subMenu = menu;
556 subMenu = menu;
557 } else {
557 } else {
558 subMenu = new QMenu(subCategory, this);
558 subMenu = new QMenu(subCategory, this);
559 menu->addMenu(subMenu);
559 menu->addMenu(subMenu);
560 }
560 }
561
561
562 foreach (Chart *chart, subCategoryMap.values(subCategory)) {
562 foreach (Chart *chart, subCategoryMap.values(subCategory)) {
563 createMenuAction(subMenu, QIcon(), chart->name(),
563 createMenuAction(subMenu, QIcon(), chart->name(),
564 qVariantFromValue((void *) chart));
564 qVariantFromValue((void *) chart));
565 }
565 }
566 }
566 }
567 }
567 }
568 return result;
568 return result;
569 }
569 }
570
570
571 QAction *Window::createMenuAction(QMenu *menu, const QIcon &icon, const QString &text,
571 QAction *Window::createMenuAction(QMenu *menu, const QIcon &icon, const QString &text,
572 const QVariant &data)
572 const QVariant &data)
573 {
573 {
574 QAction *action = menu->addAction(icon, text);
574 QAction *action = menu->addAction(icon, text);
575 action->setCheckable(false);
575 action->setCheckable(false);
576 action->setData(data);
576 action->setData(data);
577 return action;
577 return action;
578 }
578 }
579
579
580 void Window::handleGeometryChanged()
580 void Window::handleGeometryChanged()
581 {
581 {
582 QSizeF size = m_baseLayout->sizeHint(Qt::MinimumSize);
582 QSizeF size = m_baseLayout->sizeHint(Qt::MinimumSize);
583 m_view->scene()->setSceneRect(0, 0, this->width(), this->height());
583 m_view->scene()->setSceneRect(0, 0, this->width(), this->height());
584 m_view->setMinimumSize(size.toSize());
584 m_view->setMinimumSize(size.toSize());
585 }
585 }
@@ -1,15 +1,15
1 !include( ../../tests.pri ) {
1 !include( ../../tests.pri ) {
2 error( "Couldn't find the test.pri file!" )
2 error( "Couldn't find the test.pri file!" )
3 }
3 }
4
4
5 TEMPLATE = app
5 TEMPLATE = app
6
6
7 QT += core gui opengl widgets
7 QT += core gui widgets
8
8
9 SOURCES += main.cpp \
9 SOURCES += main.cpp \
10 mainwidget.cpp \
10 mainwidget.cpp \
11 dataseriedialog.cpp
11 dataseriedialog.cpp
12
12
13 HEADERS += \
13 HEADERS += \
14 mainwidget.h \
14 mainwidget.h \
15 dataseriedialog.h
15 dataseriedialog.h
@@ -1,378 +1,377
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd
3 ** Copyright (C) 2015 The Qt Company Ltd
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to The Qt Company, please use contact form at http://qt.io
5 ** For any questions to The Qt Company, please use contact form at http://qt.io
6 **
6 **
7 ** This file is part of the Qt Charts module.
7 ** This file is part of the Qt Charts module.
8 **
8 **
9 ** Licensees holding valid commercial license for Qt may use this file in
9 ** Licensees holding valid commercial license for Qt may use this file in
10 ** accordance with the Qt License Agreement provided with the Software
10 ** accordance with the Qt License Agreement provided with the Software
11 ** or, alternatively, in accordance with the terms contained in a written
11 ** or, alternatively, in accordance with the terms contained in a written
12 ** agreement between you and The Qt Company.
12 ** agreement between you and The Qt Company.
13 **
13 **
14 ** If you have questions regarding the use of this file, please use
14 ** If you have questions regarding the use of this file, please use
15 ** contact form at http://qt.io
15 ** contact form at http://qt.io
16 **
16 **
17 ****************************************************************************/
17 ****************************************************************************/
18
18
19 #include "mainwidget.h"
19 #include "mainwidget.h"
20 #include "dataseriedialog.h"
20 #include "dataseriedialog.h"
21 #include <QtCharts/QChartView>
21 #include <QtCharts/QChartView>
22 #include <QtCharts/QPieSeries>
22 #include <QtCharts/QPieSeries>
23 #include <QtCharts/QScatterSeries>
23 #include <QtCharts/QScatterSeries>
24 #include <QtCharts/QLineSeries>
24 #include <QtCharts/QLineSeries>
25 #include <QtCharts/QAreaSeries>
25 #include <QtCharts/QAreaSeries>
26 #include <QtCharts/QSplineSeries>
26 #include <QtCharts/QSplineSeries>
27 #include <QtCharts/QBarSet>
27 #include <QtCharts/QBarSet>
28 #include <QtCharts/QBarSeries>
28 #include <QtCharts/QBarSeries>
29 #include <QtCharts/QStackedBarSeries>
29 #include <QtCharts/QStackedBarSeries>
30 #include <QtCharts/QPercentBarSeries>
30 #include <QtCharts/QPercentBarSeries>
31 #include <QtWidgets/QPushButton>
31 #include <QtWidgets/QPushButton>
32 #include <QtWidgets/QComboBox>
32 #include <QtWidgets/QComboBox>
33 #include <QtWidgets/QSpinBox>
33 #include <QtWidgets/QSpinBox>
34 #include <QtWidgets/QCheckBox>
34 #include <QtWidgets/QCheckBox>
35 #include <QtWidgets/QGridLayout>
35 #include <QtWidgets/QGridLayout>
36 #include <QtWidgets/QHBoxLayout>
36 #include <QtWidgets/QHBoxLayout>
37 #include <QtWidgets/QLabel>
37 #include <QtWidgets/QLabel>
38 #include <QtWidgets/QSpacerItem>
38 #include <QtWidgets/QSpacerItem>
39 #include <QtWidgets/QMessageBox>
39 #include <QtWidgets/QMessageBox>
40 #include <cmath>
40 #include <cmath>
41 #include <QtCore/QDebug>
41 #include <QtCore/QDebug>
42 #include <QtGui/QStandardItemModel>
42 #include <QtGui/QStandardItemModel>
43 #include <QtCharts/QBarCategoryAxis>
43 #include <QtCharts/QBarCategoryAxis>
44 #include <QtOpenGL/QGLWidget>
44 #include <QtWidgets/QOpenGLWidget>
45
45
46 QT_CHARTS_USE_NAMESPACE
46 QT_CHARTS_USE_NAMESPACE
47
47
48 MainWidget::MainWidget(QWidget *parent) :
48 MainWidget::MainWidget(QWidget *parent) :
49 QWidget(parent),
49 QWidget(parent),
50 m_addSerieDialog(0),
50 m_addSerieDialog(0),
51 m_chart(0)
51 m_chart(0)
52 {
52 {
53 m_chart = new QChart();
53 m_chart = new QChart();
54
54
55 // Grid layout for the controls for configuring the chart widget
55 // Grid layout for the controls for configuring the chart widget
56 QGridLayout *grid = new QGridLayout();
56 QGridLayout *grid = new QGridLayout();
57 QPushButton *addSeriesButton = new QPushButton("Add series");
57 QPushButton *addSeriesButton = new QPushButton("Add series");
58 connect(addSeriesButton, SIGNAL(clicked()), this, SLOT(addSeries()));
58 connect(addSeriesButton, SIGNAL(clicked()), this, SLOT(addSeries()));
59 grid->addWidget(addSeriesButton, 0, 1);
59 grid->addWidget(addSeriesButton, 0, 1);
60 initBackroundCombo(grid);
60 initBackroundCombo(grid);
61 initScaleControls(grid);
61 initScaleControls(grid);
62 initThemeCombo(grid);
62 initThemeCombo(grid);
63 initCheckboxes(grid);
63 initCheckboxes(grid);
64
64
65 // add row with empty label to make all the other rows static
65 // add row with empty label to make all the other rows static
66 grid->addWidget(new QLabel(""), grid->rowCount(), 0);
66 grid->addWidget(new QLabel(""), grid->rowCount(), 0);
67 grid->setRowStretch(grid->rowCount() - 1, 1);
67 grid->setRowStretch(grid->rowCount() - 1, 1);
68
68
69 // Create chart view with the chart
69 // Create chart view with the chart
70 m_chartView = new QChartView(m_chart, this);
70 m_chartView = new QChartView(m_chart, this);
71 m_chartView->setRubberBand(QChartView::HorizontalRubberBand);
71 m_chartView->setRubberBand(QChartView::HorizontalRubberBand);
72
72
73 // Another grid layout as a main layout
73 // Another grid layout as a main layout
74 QGridLayout *mainLayout = new QGridLayout();
74 QGridLayout *mainLayout = new QGridLayout();
75 mainLayout->addLayout(grid, 0, 0);
75 mainLayout->addLayout(grid, 0, 0);
76 mainLayout->addWidget(m_chartView, 0, 1, 3, 1);
76 mainLayout->addWidget(m_chartView, 0, 1, 3, 1);
77 setLayout(mainLayout);
77 setLayout(mainLayout);
78 }
78 }
79
79
80 // Combo box for selecting the chart's background
80 // Combo box for selecting the chart's background
81 void MainWidget::initBackroundCombo(QGridLayout *grid)
81 void MainWidget::initBackroundCombo(QGridLayout *grid)
82 {
82 {
83 QComboBox *backgroundCombo = new QComboBox(this);
83 QComboBox *backgroundCombo = new QComboBox(this);
84 backgroundCombo->addItem("Color");
84 backgroundCombo->addItem("Color");
85 backgroundCombo->addItem("Gradient");
85 backgroundCombo->addItem("Gradient");
86 backgroundCombo->addItem("Image");
86 backgroundCombo->addItem("Image");
87 connect(backgroundCombo, SIGNAL(currentIndexChanged(int)),
87 connect(backgroundCombo, SIGNAL(currentIndexChanged(int)),
88 this, SLOT(backgroundChanged(int)));
88 this, SLOT(backgroundChanged(int)));
89
89
90 grid->addWidget(new QLabel("Background:"), grid->rowCount(), 0);
90 grid->addWidget(new QLabel("Background:"), grid->rowCount(), 0);
91 grid->addWidget(backgroundCombo, grid->rowCount() - 1, 1);
91 grid->addWidget(backgroundCombo, grid->rowCount() - 1, 1);
92 }
92 }
93
93
94 // Scale related controls (auto-scale vs. manual min-max values)
94 // Scale related controls (auto-scale vs. manual min-max values)
95 void MainWidget::initScaleControls(QGridLayout *grid)
95 void MainWidget::initScaleControls(QGridLayout *grid)
96 {
96 {
97 m_autoScaleCheck = new QCheckBox("Automatic scaling");
97 m_autoScaleCheck = new QCheckBox("Automatic scaling");
98 connect(m_autoScaleCheck, SIGNAL(stateChanged(int)), this, SLOT(autoScaleChanged(int)));
98 connect(m_autoScaleCheck, SIGNAL(stateChanged(int)), this, SLOT(autoScaleChanged(int)));
99 // Allow setting also non-sense values (like -2147483648 and 2147483647)
99 // Allow setting also non-sense values (like -2147483648 and 2147483647)
100 m_xMinSpin = new QSpinBox();
100 m_xMinSpin = new QSpinBox();
101 m_xMinSpin->setMinimum(INT_MIN);
101 m_xMinSpin->setMinimum(INT_MIN);
102 m_xMinSpin->setMaximum(INT_MAX);
102 m_xMinSpin->setMaximum(INT_MAX);
103 m_xMinSpin->setValue(0);
103 m_xMinSpin->setValue(0);
104 connect(m_xMinSpin, SIGNAL(valueChanged(int)), this, SLOT(xMinChanged(int)));
104 connect(m_xMinSpin, SIGNAL(valueChanged(int)), this, SLOT(xMinChanged(int)));
105 m_xMaxSpin = new QSpinBox();
105 m_xMaxSpin = new QSpinBox();
106 m_xMaxSpin->setMinimum(INT_MIN);
106 m_xMaxSpin->setMinimum(INT_MIN);
107 m_xMaxSpin->setMaximum(INT_MAX);
107 m_xMaxSpin->setMaximum(INT_MAX);
108 m_xMaxSpin->setValue(10);
108 m_xMaxSpin->setValue(10);
109 connect(m_xMaxSpin, SIGNAL(valueChanged(int)), this, SLOT(xMaxChanged(int)));
109 connect(m_xMaxSpin, SIGNAL(valueChanged(int)), this, SLOT(xMaxChanged(int)));
110 m_yMinSpin = new QSpinBox();
110 m_yMinSpin = new QSpinBox();
111 m_yMinSpin->setMinimum(INT_MIN);
111 m_yMinSpin->setMinimum(INT_MIN);
112 m_yMinSpin->setMaximum(INT_MAX);
112 m_yMinSpin->setMaximum(INT_MAX);
113 m_yMinSpin->setValue(0);
113 m_yMinSpin->setValue(0);
114 connect(m_yMinSpin, SIGNAL(valueChanged(int)), this, SLOT(yMinChanged(int)));
114 connect(m_yMinSpin, SIGNAL(valueChanged(int)), this, SLOT(yMinChanged(int)));
115 m_yMaxSpin = new QSpinBox();
115 m_yMaxSpin = new QSpinBox();
116 m_yMaxSpin->setMinimum(INT_MIN);
116 m_yMaxSpin->setMinimum(INT_MIN);
117 m_yMaxSpin->setMaximum(INT_MAX);
117 m_yMaxSpin->setMaximum(INT_MAX);
118 m_yMaxSpin->setValue(10);
118 m_yMaxSpin->setValue(10);
119 connect(m_yMaxSpin, SIGNAL(valueChanged(int)), this, SLOT(yMaxChanged(int)));
119 connect(m_yMaxSpin, SIGNAL(valueChanged(int)), this, SLOT(yMaxChanged(int)));
120
120
121 grid->addWidget(m_autoScaleCheck, grid->rowCount(), 0);
121 grid->addWidget(m_autoScaleCheck, grid->rowCount(), 0);
122 grid->addWidget(new QLabel("x min:"), grid->rowCount(), 0);
122 grid->addWidget(new QLabel("x min:"), grid->rowCount(), 0);
123 grid->addWidget(m_xMinSpin, grid->rowCount() - 1, 1);
123 grid->addWidget(m_xMinSpin, grid->rowCount() - 1, 1);
124 grid->addWidget(new QLabel("x max:"), grid->rowCount(), 0);
124 grid->addWidget(new QLabel("x max:"), grid->rowCount(), 0);
125 grid->addWidget(m_xMaxSpin, grid->rowCount() - 1, 1);
125 grid->addWidget(m_xMaxSpin, grid->rowCount() - 1, 1);
126 grid->addWidget(new QLabel("y min:"), grid->rowCount(), 0);
126 grid->addWidget(new QLabel("y min:"), grid->rowCount(), 0);
127 grid->addWidget(m_yMinSpin, grid->rowCount() - 1, 1);
127 grid->addWidget(m_yMinSpin, grid->rowCount() - 1, 1);
128 grid->addWidget(new QLabel("y max:"), grid->rowCount(), 0);
128 grid->addWidget(new QLabel("y max:"), grid->rowCount(), 0);
129 grid->addWidget(m_yMaxSpin, grid->rowCount() - 1, 1);
129 grid->addWidget(m_yMaxSpin, grid->rowCount() - 1, 1);
130
130
131 m_autoScaleCheck->setChecked(true);
131 m_autoScaleCheck->setChecked(true);
132 }
132 }
133
133
134 // Combo box for selecting theme
134 // Combo box for selecting theme
135 void MainWidget::initThemeCombo(QGridLayout *grid)
135 void MainWidget::initThemeCombo(QGridLayout *grid)
136 {
136 {
137 QComboBox *chartTheme = new QComboBox();
137 QComboBox *chartTheme = new QComboBox();
138 chartTheme->addItem("Default");
138 chartTheme->addItem("Default");
139 chartTheme->addItem("Light");
139 chartTheme->addItem("Light");
140 chartTheme->addItem("Blue Cerulean");
140 chartTheme->addItem("Blue Cerulean");
141 chartTheme->addItem("Dark");
141 chartTheme->addItem("Dark");
142 chartTheme->addItem("Brown Sand");
142 chartTheme->addItem("Brown Sand");
143 chartTheme->addItem("Blue NCS");
143 chartTheme->addItem("Blue NCS");
144 chartTheme->addItem("High Contrast");
144 chartTheme->addItem("High Contrast");
145 chartTheme->addItem("Blue Icy");
145 chartTheme->addItem("Blue Icy");
146 chartTheme->addItem("Qt");
146 chartTheme->addItem("Qt");
147 connect(chartTheme, SIGNAL(currentIndexChanged(int)),
147 connect(chartTheme, SIGNAL(currentIndexChanged(int)),
148 this, SLOT(changeChartTheme(int)));
148 this, SLOT(changeChartTheme(int)));
149 grid->addWidget(new QLabel("Chart theme:"), 8, 0);
149 grid->addWidget(new QLabel("Chart theme:"), 8, 0);
150 grid->addWidget(chartTheme, 8, 1);
150 grid->addWidget(chartTheme, 8, 1);
151 }
151 }
152
152
153 // Different check boxes for customizing chart
153 // Different check boxes for customizing chart
154 void MainWidget::initCheckboxes(QGridLayout *grid)
154 void MainWidget::initCheckboxes(QGridLayout *grid)
155 {
155 {
156 // TODO: setZoomEnabled slot has been removed from QChartView -> Re-implement zoom on/off
156 // TODO: setZoomEnabled slot has been removed from QChartView -> Re-implement zoom on/off
157 QCheckBox *zoomCheckBox = new QCheckBox("Drag'n drop Zoom");
157 QCheckBox *zoomCheckBox = new QCheckBox("Drag'n drop Zoom");
158 // connect(zoomCheckBox, SIGNAL(toggled(bool)), m_chartView, SLOT(setZoomEnabled(bool)));
158 // connect(zoomCheckBox, SIGNAL(toggled(bool)), m_chartView, SLOT(setZoomEnabled(bool)));
159 zoomCheckBox->setChecked(true);
159 zoomCheckBox->setChecked(true);
160 grid->addWidget(zoomCheckBox, grid->rowCount(), 0);
160 grid->addWidget(zoomCheckBox, grid->rowCount(), 0);
161
161
162 QCheckBox *aliasCheckBox = new QCheckBox("Anti-alias");
162 QCheckBox *aliasCheckBox = new QCheckBox("Anti-alias");
163 connect(aliasCheckBox, SIGNAL(toggled(bool)), this, SLOT(antiAliasToggled(bool)));
163 connect(aliasCheckBox, SIGNAL(toggled(bool)), this, SLOT(antiAliasToggled(bool)));
164 aliasCheckBox->setChecked(false);
164 aliasCheckBox->setChecked(false);
165 grid->addWidget(aliasCheckBox, grid->rowCount(), 0);
165 grid->addWidget(aliasCheckBox, grid->rowCount(), 0);
166
166
167 QCheckBox *openGLCheckBox = new QCheckBox("Use QGLWidget");
167 QCheckBox *openGLCheckBox = new QCheckBox("Use QOpenGLWidget");
168 connect(openGLCheckBox, SIGNAL(toggled(bool)), this, SLOT(openGLToggled(bool)));
168 connect(openGLCheckBox, SIGNAL(toggled(bool)), this, SLOT(openGLToggled(bool)));
169 openGLCheckBox->setChecked(false);
169 openGLCheckBox->setChecked(false);
170 grid->addWidget(openGLCheckBox, grid->rowCount(), 0);
170 grid->addWidget(openGLCheckBox, grid->rowCount(), 0);
171 }
171 }
172
172
173 void MainWidget::antiAliasToggled(bool enabled)
173 void MainWidget::antiAliasToggled(bool enabled)
174 {
174 {
175 m_chartView->setRenderHint(QPainter::Antialiasing, enabled);
175 m_chartView->setRenderHint(QPainter::Antialiasing, enabled);
176 }
176 }
177
177
178 void MainWidget::openGLToggled(bool enabled)
178 void MainWidget::openGLToggled(bool enabled)
179 {
179 {
180 if (enabled) {
180 if (enabled) {
181 QGLFormat f = QGLFormat::defaultFormat();
181 QSurfaceFormat f = QSurfaceFormat::defaultFormat();
182 f.setSampleBuffers(true);
183 f.setSamples(4);
182 f.setSamples(4);
184 QGLFormat::setDefaultFormat(f);
183 QSurfaceFormat::setDefaultFormat(f);
185 QGLWidget *g = new QGLWidget();
184 QOpenGLWidget *g = new QOpenGLWidget();
186 m_chartView->setViewport(g);
185 m_chartView->setViewport(g);
187 } else {
186 } else {
188 m_chartView->setViewport(0);
187 m_chartView->setViewport(0);
189 }
188 }
190 }
189 }
191
190
192 void MainWidget::addSeries()
191 void MainWidget::addSeries()
193 {
192 {
194 if (!m_addSerieDialog) {
193 if (!m_addSerieDialog) {
195 m_addSerieDialog = new DataSerieDialog(this);
194 m_addSerieDialog = new DataSerieDialog(this);
196 connect(m_addSerieDialog, SIGNAL(accepted(QString,int,int,QString,bool)),
195 connect(m_addSerieDialog, SIGNAL(accepted(QString,int,int,QString,bool)),
197 this, SLOT(addSeries(QString,int,int,QString,bool)));
196 this, SLOT(addSeries(QString,int,int,QString,bool)));
198 }
197 }
199 m_addSerieDialog->exec();
198 m_addSerieDialog->exec();
200 }
199 }
201
200
202 QList<RealList> MainWidget::generateTestData(int columnCount, int rowCount, QString dataCharacteristics)
201 QList<RealList> MainWidget::generateTestData(int columnCount, int rowCount, QString dataCharacteristics)
203 {
202 {
204 QList<RealList> testData;
203 QList<RealList> testData;
205 for (int j(0); j < columnCount; j++) {
204 for (int j(0); j < columnCount; j++) {
206 QList <qreal> newColumn;
205 QList <qreal> newColumn;
207 for (int i(0); i < rowCount; i++) {
206 for (int i(0); i < rowCount; i++) {
208 if (dataCharacteristics == "Sin") {
207 if (dataCharacteristics == "Sin") {
209 newColumn.append(abs(sin(3.14159265358979 / 50 * i) * 100));
208 newColumn.append(abs(sin(3.14159265358979 / 50 * i) * 100));
210 } else if (dataCharacteristics == "Sin + random") {
209 } else if (dataCharacteristics == "Sin + random") {
211 newColumn.append(abs(sin(3.14159265358979 / 50 * i) * 100) + (rand() % 5));
210 newColumn.append(abs(sin(3.14159265358979 / 50 * i) * 100) + (rand() % 5));
212 } else if (dataCharacteristics == "Random") {
211 } else if (dataCharacteristics == "Random") {
213 newColumn.append(rand() % 10 + (qreal) rand() / (qreal) RAND_MAX);
212 newColumn.append(rand() % 10 + (qreal) rand() / (qreal) RAND_MAX);
214 } else if (dataCharacteristics == "Linear") {
213 } else if (dataCharacteristics == "Linear") {
215 //newColumn.append(i * (j + 1.0));
214 //newColumn.append(i * (j + 1.0));
216 // TODO: temporary hack to make pie work; prevent zero values:
215 // TODO: temporary hack to make pie work; prevent zero values:
217 newColumn.append(i * (j + 1.0) + 0.1);
216 newColumn.append(i * (j + 1.0) + 0.1);
218 } else { // "constant"
217 } else { // "constant"
219 newColumn.append((j + 1.0));
218 newColumn.append((j + 1.0));
220 }
219 }
221 }
220 }
222 testData.append(newColumn);
221 testData.append(newColumn);
223 }
222 }
224 return testData;
223 return testData;
225 }
224 }
226
225
227 QStringList MainWidget::generateLabels(int count)
226 QStringList MainWidget::generateLabels(int count)
228 {
227 {
229 QStringList result;
228 QStringList result;
230 for (int i(0); i < count; i++)
229 for (int i(0); i < count; i++)
231 result.append("label" + QString::number(i));
230 result.append("label" + QString::number(i));
232 return result;
231 return result;
233 }
232 }
234
233
235 void MainWidget::addSeries(QString seriesName, int columnCount, int rowCount, QString dataCharacteristics, bool labelsEnabled)
234 void MainWidget::addSeries(QString seriesName, int columnCount, int rowCount, QString dataCharacteristics, bool labelsEnabled)
236 {
235 {
237 qDebug() << "addSeries: " << seriesName
236 qDebug() << "addSeries: " << seriesName
238 << " columnCount: " << columnCount
237 << " columnCount: " << columnCount
239 << " rowCount: " << rowCount
238 << " rowCount: " << rowCount
240 << " dataCharacteristics: " << dataCharacteristics
239 << " dataCharacteristics: " << dataCharacteristics
241 << " labels enabled: " << labelsEnabled;
240 << " labels enabled: " << labelsEnabled;
242 m_defaultSeriesName = seriesName;
241 m_defaultSeriesName = seriesName;
243
242
244 QList<RealList> data = generateTestData(columnCount, rowCount, dataCharacteristics);
243 QList<RealList> data = generateTestData(columnCount, rowCount, dataCharacteristics);
245
244
246 // Line series and scatter series use similar data
245 // Line series and scatter series use similar data
247 if (seriesName == "Line") {
246 if (seriesName == "Line") {
248 for (int j(0); j < data.count(); j ++) {
247 for (int j(0); j < data.count(); j ++) {
249 QList<qreal> column = data.at(j);
248 QList<qreal> column = data.at(j);
250 QLineSeries *series = new QLineSeries();
249 QLineSeries *series = new QLineSeries();
251 series->setName("line" + QString::number(j));
250 series->setName("line" + QString::number(j));
252 for (int i(0); i < column.count(); i++)
251 for (int i(0); i < column.count(); i++)
253 series->append(i, column.at(i));
252 series->append(i, column.at(i));
254 m_chart->addSeries(series);
253 m_chart->addSeries(series);
255 }
254 }
256 } else if (seriesName == "Area") {
255 } else if (seriesName == "Area") {
257 // TODO: lower series for the area?
256 // TODO: lower series for the area?
258 for (int j(0); j < data.count(); j ++) {
257 for (int j(0); j < data.count(); j ++) {
259 QList<qreal> column = data.at(j);
258 QList<qreal> column = data.at(j);
260 QLineSeries *lineSeries = new QLineSeries();
259 QLineSeries *lineSeries = new QLineSeries();
261 for (int i(0); i < column.count(); i++)
260 for (int i(0); i < column.count(); i++)
262 lineSeries->append(i, column.at(i));
261 lineSeries->append(i, column.at(i));
263 QAreaSeries *areaSeries = new QAreaSeries(lineSeries);
262 QAreaSeries *areaSeries = new QAreaSeries(lineSeries);
264 areaSeries->setName("area" + QString::number(j));
263 areaSeries->setName("area" + QString::number(j));
265 m_chart->addSeries(areaSeries);
264 m_chart->addSeries(areaSeries);
266 }
265 }
267 } else if (seriesName == "Scatter") {
266 } else if (seriesName == "Scatter") {
268 for (int j(0); j < data.count(); j++) {
267 for (int j(0); j < data.count(); j++) {
269 QList<qreal> column = data.at(j);
268 QList<qreal> column = data.at(j);
270 QScatterSeries *series = new QScatterSeries();
269 QScatterSeries *series = new QScatterSeries();
271 series->setName("scatter" + QString::number(j));
270 series->setName("scatter" + QString::number(j));
272 for (int i(0); i < column.count(); i++)
271 for (int i(0); i < column.count(); i++)
273 series->append(i, column.at(i));
272 series->append(i, column.at(i));
274 m_chart->addSeries(series);
273 m_chart->addSeries(series);
275 }
274 }
276 } else if (seriesName == "Pie") {
275 } else if (seriesName == "Pie") {
277 QStringList labels = generateLabels(rowCount);
276 QStringList labels = generateLabels(rowCount);
278 for (int j(0); j < data.count(); j++) {
277 for (int j(0); j < data.count(); j++) {
279 QPieSeries *series = new QPieSeries();
278 QPieSeries *series = new QPieSeries();
280 QList<qreal> column = data.at(j);
279 QList<qreal> column = data.at(j);
281 for (int i(0); i < column.count(); i++)
280 for (int i(0); i < column.count(); i++)
282 series->append(labels.at(i), column.at(i));
281 series->append(labels.at(i), column.at(i));
283 m_chart->addSeries(series);
282 m_chart->addSeries(series);
284 }
283 }
285 } else if (seriesName == "Bar"
284 } else if (seriesName == "Bar"
286 || seriesName == "Stacked bar"
285 || seriesName == "Stacked bar"
287 || seriesName == "Percent bar") {
286 || seriesName == "Percent bar") {
288 QStringList category;
287 QStringList category;
289 QStringList labels = generateLabels(rowCount);
288 QStringList labels = generateLabels(rowCount);
290 foreach (QString label, labels)
289 foreach (QString label, labels)
291 category << label;
290 category << label;
292 QAbstractBarSeries* series = 0;
291 QAbstractBarSeries* series = 0;
293 if (seriesName == "Bar") {
292 if (seriesName == "Bar") {
294 series = new QBarSeries(this);
293 series = new QBarSeries(this);
295 QBarCategoryAxis* axis = new QBarCategoryAxis();
294 QBarCategoryAxis* axis = new QBarCategoryAxis();
296 axis->append(category);
295 axis->append(category);
297 m_chart->setAxisX(axis,series);
296 m_chart->setAxisX(axis,series);
298 } else if (seriesName == "Stacked bar") {
297 } else if (seriesName == "Stacked bar") {
299 series = new QStackedBarSeries(this);
298 series = new QStackedBarSeries(this);
300 QBarCategoryAxis* axis = new QBarCategoryAxis();
299 QBarCategoryAxis* axis = new QBarCategoryAxis();
301 axis->append(category);
300 axis->append(category);
302 m_chart->setAxisX(axis,series);
301 m_chart->setAxisX(axis,series);
303 } else {
302 } else {
304 series = new QPercentBarSeries(this);
303 series = new QPercentBarSeries(this);
305 QBarCategoryAxis* axis = new QBarCategoryAxis();
304 QBarCategoryAxis* axis = new QBarCategoryAxis();
306 axis->append(category);
305 axis->append(category);
307 m_chart->setAxisX(axis,series);
306 m_chart->setAxisX(axis,series);
308 }
307 }
309
308
310 for (int j(0); j < data.count(); j++) {
309 for (int j(0); j < data.count(); j++) {
311 QList<qreal> column = data.at(j);
310 QList<qreal> column = data.at(j);
312 QBarSet *set = new QBarSet("set" + QString::number(j));
311 QBarSet *set = new QBarSet("set" + QString::number(j));
313 for (int i(0); i < column.count(); i++)
312 for (int i(0); i < column.count(); i++)
314 *set << column.at(i);
313 *set << column.at(i);
315 series->append(set);
314 series->append(set);
316 }
315 }
317
316
318 m_chart->addSeries(series);
317 m_chart->addSeries(series);
319 } else if (seriesName == "Spline") {
318 } else if (seriesName == "Spline") {
320 for (int j(0); j < data.count(); j ++) {
319 for (int j(0); j < data.count(); j ++) {
321 QList<qreal> column = data.at(j);
320 QList<qreal> column = data.at(j);
322 QSplineSeries *series = new QSplineSeries();
321 QSplineSeries *series = new QSplineSeries();
323 series->setName("spline" + QString::number(j));
322 series->setName("spline" + QString::number(j));
324 for (int i(0); i < column.count(); i++)
323 for (int i(0); i < column.count(); i++)
325 series->append(i, column.at(i));
324 series->append(i, column.at(i));
326 m_chart->addSeries(series);
325 m_chart->addSeries(series);
327 }
326 }
328 }
327 }
329 m_chart->createDefaultAxes();
328 m_chart->createDefaultAxes();
330 }
329 }
331
330
332 void MainWidget::backgroundChanged(int itemIndex)
331 void MainWidget::backgroundChanged(int itemIndex)
333 {
332 {
334 qDebug() << "backgroundChanged: " << itemIndex;
333 qDebug() << "backgroundChanged: " << itemIndex;
335 }
334 }
336
335
337 void MainWidget::autoScaleChanged(int value)
336 void MainWidget::autoScaleChanged(int value)
338 {
337 {
339 if (value) {
338 if (value) {
340 // TODO: enable auto scaling
339 // TODO: enable auto scaling
341 } else {
340 } else {
342 // TODO: set scaling manually (and disable auto scaling)
341 // TODO: set scaling manually (and disable auto scaling)
343 }
342 }
344
343
345 m_xMinSpin->setEnabled(!value);
344 m_xMinSpin->setEnabled(!value);
346 m_xMaxSpin->setEnabled(!value);
345 m_xMaxSpin->setEnabled(!value);
347 m_yMinSpin->setEnabled(!value);
346 m_yMinSpin->setEnabled(!value);
348 m_yMaxSpin->setEnabled(!value);
347 m_yMaxSpin->setEnabled(!value);
349 }
348 }
350
349
351 void MainWidget::xMinChanged(int value)
350 void MainWidget::xMinChanged(int value)
352 {
351 {
353 qDebug() << "xMinChanged: " << value;
352 qDebug() << "xMinChanged: " << value;
354 }
353 }
355
354
356 void MainWidget::xMaxChanged(int value)
355 void MainWidget::xMaxChanged(int value)
357 {
356 {
358 qDebug() << "xMaxChanged: " << value;
357 qDebug() << "xMaxChanged: " << value;
359 }
358 }
360
359
361 void MainWidget::yMinChanged(int value)
360 void MainWidget::yMinChanged(int value)
362 {
361 {
363 qDebug() << "yMinChanged: " << value;
362 qDebug() << "yMinChanged: " << value;
364 }
363 }
365
364
366 void MainWidget::yMaxChanged(int value)
365 void MainWidget::yMaxChanged(int value)
367 {
366 {
368 qDebug() << "yMaxChanged: " << value;
367 qDebug() << "yMaxChanged: " << value;
369 }
368 }
370
369
371 void MainWidget::changeChartTheme(int themeIndex)
370 void MainWidget::changeChartTheme(int themeIndex)
372 {
371 {
373 qDebug() << "changeChartTheme: " << themeIndex;
372 qDebug() << "changeChartTheme: " << themeIndex;
374 if (themeIndex == 0)
373 if (themeIndex == 0)
375 m_chart->setTheme(QChart::ChartThemeLight);
374 m_chart->setTheme(QChart::ChartThemeLight);
376 else
375 else
377 m_chart->setTheme((QChart::ChartTheme) (themeIndex - 1));
376 m_chart->setTheme((QChart::ChartTheme) (themeIndex - 1));
378 }
377 }
@@ -1,42 +1,42
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd
3 ** Copyright (C) 2015 The Qt Company Ltd
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to The Qt Company, please use contact form at http://qt.io
5 ** For any questions to The Qt Company, please use contact form at http://qt.io
6 **
6 **
7 ** This file is part of the Qt Charts module.
7 ** This file is part of the Qt Charts module.
8 **
8 **
9 ** Licensees holding valid commercial license for Qt may use this file in
9 ** Licensees holding valid commercial license for Qt may use this file in
10 ** accordance with the Qt License Agreement provided with the Software
10 ** accordance with the Qt License Agreement provided with the Software
11 ** or, alternatively, in accordance with the terms contained in a written
11 ** or, alternatively, in accordance with the terms contained in a written
12 ** agreement between you and The Qt Company.
12 ** agreement between you and The Qt Company.
13 **
13 **
14 ** If you have questions regarding the use of this file, please use
14 ** If you have questions regarding the use of this file, please use
15 ** contact form at http://qt.io
15 ** contact form at http://qt.io
16 **
16 **
17 ****************************************************************************/
17 ****************************************************************************/
18
18
19 #include "wavechart.h"
19 #include "wavechart.h"
20 #include <QtWidgets/QApplication>
20 #include <QtWidgets/QApplication>
21 #include <QtWidgets/QMainWindow>
21 #include <QtWidgets/QMainWindow>
22 #include <QtOpenGL/QGLWidget>
22 #include <QtWidgets/QOpenGLWidget>
23
23
24 int main(int argc, char *argv[])
24 int main(int argc, char *argv[])
25 {
25 {
26 QApplication a(argc, argv);
26 QApplication a(argc, argv);
27
27
28 QMainWindow window;
28 QMainWindow window;
29 QChart *chart = new QChart();
29 QChart *chart = new QChart();
30 WaveChart *waveChart = new WaveChart(chart,&window);
30 WaveChart *waveChart = new WaveChart(chart,&window);
31
31
32 waveChart->setViewport( new QGLWidget() );
32 waveChart->setViewport( new QOpenGLWidget() );
33 waveChart->setRenderHint(QPainter::Antialiasing);
33 waveChart->setRenderHint(QPainter::Antialiasing);
34 chart->setAnimationOptions(QChart::AllAnimations);
34 chart->setAnimationOptions(QChart::AllAnimations);
35 chart->setTitle("This is wave generator.");
35 chart->setTitle("This is wave generator.");
36
36
37 window.setCentralWidget(waveChart);
37 window.setCentralWidget(waveChart);
38 window.resize(400, 300);
38 window.resize(400, 300);
39 window.show();
39 window.show();
40
40
41 return a.exec();
41 return a.exec();
42 }
42 }
@@ -1,8 +1,7
1 !include( ../../tests.pri ) {
1 !include( ../../tests.pri ) {
2 error( "Couldn't find the test.pri file!" )
2 error( "Couldn't find the test.pri file!" )
3 }
3 }
4
4
5 QT+=opengl
6 TARGET = wavechart
5 TARGET = wavechart
7 SOURCES += main.cpp wavechart.cpp
6 SOURCES += main.cpp wavechart.cpp
8 HEADERS += wavechart.h
7 HEADERS += wavechart.h
General Comments 0
You need to be logged in to leave comments. Login now