1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt Charts module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 or (at your option) any later version |
20 | ** approved by the KDE Free Qt Foundation. The licenses are as published by |
21 | ** the Free Software Foundation and appearing in the file LICENSE.GPL3 |
22 | ** included in the packaging of this file. Please review the following |
23 | ** information to ensure the GNU General Public License requirements will |
24 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
25 | ** |
26 | ** $QT_END_LICENSE$ |
27 | ** |
28 | ****************************************************************************/ |
29 | |
30 | #include <private/cartesianchartlayout_p.h> |
31 | #include <private/chartpresenter_p.h> |
32 | #include <private/chartaxiselement_p.h> |
33 | #include <QtCore/QDebug> |
34 | |
35 | QT_CHARTS_BEGIN_NAMESPACE |
36 | |
37 | static const qreal maxAxisPortion = 0.4; |
38 | |
39 | CartesianChartLayout::CartesianChartLayout(ChartPresenter *presenter) |
40 | : AbstractChartLayout(presenter) |
41 | { |
42 | } |
43 | |
44 | CartesianChartLayout::~CartesianChartLayout() |
45 | { |
46 | } |
47 | |
48 | QRectF CartesianChartLayout::calculateAxisGeometry(const QRectF &geometry, |
49 | const QList<ChartAxisElement *> &axes, |
50 | bool update) const |
51 | { |
52 | Q_UNUSED(update) |
53 | QSizeF left(0,0); |
54 | QSizeF minLeft(0,0); |
55 | QSizeF right(0,0); |
56 | QSizeF minRight(0,0); |
57 | QSizeF bottom(0,0); |
58 | QSizeF minBottom(0,0); |
59 | QSizeF top(0,0); |
60 | QSizeF minTop(0,0); |
61 | QSizeF labelExtents(0,0); |
62 | int leftCount = 0; |
63 | int rightCount = 0; |
64 | int topCount = 0; |
65 | int bottomCount = 0; |
66 | |
67 | foreach (ChartAxisElement *axis , axes) { |
68 | |
69 | if (!axis->isVisible()) |
70 | continue; |
71 | |
72 | |
73 | QSizeF size = axis->effectiveSizeHint(which: Qt::PreferredSize); |
74 | //this is used to get single thick font size |
75 | QSizeF minSize = axis->effectiveSizeHint(which: Qt::MinimumSize); |
76 | |
77 | switch (axis->axis()->alignment()) { |
78 | case Qt::AlignLeft: |
79 | left.setWidth(left.width()+size.width()); |
80 | left.setHeight(qMax(a: left.height(),b: size.height())); |
81 | minLeft.setWidth(minLeft.width()+minSize.width()); |
82 | minLeft.setHeight(qMax(a: minLeft.height(),b: minSize.height())); |
83 | labelExtents.setHeight(qMax(a: size.height(), b: labelExtents.height())); |
84 | leftCount++; |
85 | break; |
86 | case Qt::AlignRight: |
87 | right.setWidth(right.width()+size.width()); |
88 | right.setHeight(qMax(a: right.height(),b: size.height())); |
89 | minRight.setWidth(minRight.width()+minSize.width()); |
90 | minRight.setHeight(qMax(a: minRight.height(),b: minSize.height())); |
91 | labelExtents.setHeight(qMax(a: size.height(), b: labelExtents.height())); |
92 | rightCount++; |
93 | break; |
94 | case Qt::AlignTop: |
95 | top.setWidth(qMax(a: top.width(),b: size.width())); |
96 | top.setHeight(top.height()+size.height()); |
97 | minTop.setWidth(qMax(a: minTop.width(),b: minSize.width())); |
98 | minTop.setHeight(minTop.height()+minSize.height()); |
99 | labelExtents.setWidth(qMax(a: size.width(), b: labelExtents.width())); |
100 | topCount++; |
101 | break; |
102 | case Qt::AlignBottom: |
103 | bottom.setWidth(qMax(a: bottom.width(), b: size.width())); |
104 | bottom.setHeight(bottom.height() + size.height()); |
105 | minBottom.setWidth(qMax(a: minBottom.width(),b: minSize.width())); |
106 | minBottom.setHeight(minBottom.height() + minSize.height()); |
107 | labelExtents.setWidth(qMax(a: size.width(), b: labelExtents.width())); |
108 | bottomCount++; |
109 | break; |
110 | default: |
111 | qWarning()<<"Axis is without alignment !" ; |
112 | break; |
113 | } |
114 | } |
115 | |
116 | qreal totalVerticalAxes = leftCount + rightCount; |
117 | qreal leftSqueezeRatio = 1.0; |
118 | qreal rightSqueezeRatio = 1.0; |
119 | qreal vratio = 0; |
120 | |
121 | if (totalVerticalAxes > 0) |
122 | vratio = (maxAxisPortion * geometry.width()) / totalVerticalAxes; |
123 | |
124 | if (leftCount > 0) { |
125 | int maxWidth = vratio * leftCount; |
126 | if (left.width() > maxWidth) { |
127 | leftSqueezeRatio = maxWidth / left.width(); |
128 | left.setWidth(maxWidth); |
129 | } |
130 | } |
131 | if (rightCount > 0) { |
132 | int maxWidth = vratio * rightCount; |
133 | if (right.width() > maxWidth) { |
134 | rightSqueezeRatio = maxWidth / right.width(); |
135 | right.setWidth(maxWidth); |
136 | } |
137 | } |
138 | |
139 | qreal totalHorizontalAxes = topCount + bottomCount; |
140 | qreal topSqueezeRatio = 1.0; |
141 | qreal bottomSqueezeRatio = 1.0; |
142 | qreal hratio = 0; |
143 | |
144 | if (totalHorizontalAxes > 0) |
145 | hratio = (maxAxisPortion * geometry.height()) / totalHorizontalAxes; |
146 | |
147 | if (topCount > 0) { |
148 | int maxHeight = hratio * topCount; |
149 | if (top.height() > maxHeight) { |
150 | topSqueezeRatio = maxHeight / top.height(); |
151 | top.setHeight(maxHeight); |
152 | } |
153 | } |
154 | if (bottomCount > 0) { |
155 | int maxHeight = hratio * bottomCount; |
156 | if (bottom.height() > maxHeight) { |
157 | bottomSqueezeRatio = maxHeight / bottom.height(); |
158 | bottom.setHeight(maxHeight); |
159 | } |
160 | } |
161 | |
162 | qreal minHeight = qMax(a: minLeft.height(),b: minRight.height()) + 1; |
163 | qreal minWidth = qMax(a: minTop.width(),b: minBottom.width()) + 1; |
164 | |
165 | // Ensure that there is enough space for first and last tick labels. |
166 | left.setWidth(qMax(a: labelExtents.width(), b: left.width())); |
167 | right.setWidth(qMax(a: labelExtents.width(), b: right.width())); |
168 | top.setHeight(qMax(a: labelExtents.height(), b: top.height())); |
169 | bottom.setHeight(qMax(a: labelExtents.height(), b: bottom.height())); |
170 | |
171 | QRectF chartRect = geometry.adjusted(xp1: qMax(a: left.width(),b: minWidth/2), yp1: qMax(a: top.height(), b: minHeight/2),xp2: -qMax(a: right.width(),b: minWidth/2),yp2: -qMax(a: bottom.height(),b: minHeight/2)); |
172 | |
173 | qreal leftOffset = 0; |
174 | qreal rightOffset = 0; |
175 | qreal topOffset = 0; |
176 | qreal bottomOffset = 0; |
177 | |
178 | // The axes are positioned here for the first time, so we need to catch any possible resizing |
179 | // of the chart when in fixed geometry to prevent them being moved out of place. |
180 | if (m_presenter->isFixedGeometry()) |
181 | chartRect = m_presenter->geometry(); |
182 | |
183 | foreach (ChartAxisElement *axis , axes) { |
184 | |
185 | if (!axis->isVisible()) |
186 | continue; |
187 | |
188 | QSizeF size = axis->effectiveSizeHint(which: Qt::PreferredSize); |
189 | |
190 | switch (axis->axis()->alignment()){ |
191 | case Qt::AlignLeft:{ |
192 | qreal width = size.width(); |
193 | if (leftSqueezeRatio < 1.0) |
194 | width *= leftSqueezeRatio; |
195 | leftOffset+=width; |
196 | axis->setGeometry(axis: QRect(chartRect.left()-leftOffset, geometry.top(),width, geometry.bottom()),grid: chartRect); |
197 | break; |
198 | } |
199 | case Qt::AlignRight:{ |
200 | qreal width = size.width(); |
201 | if (rightSqueezeRatio < 1.0) |
202 | width *= rightSqueezeRatio; |
203 | axis->setGeometry(axis: QRect(chartRect.right()+rightOffset,geometry.top(),width,geometry.bottom()),grid: chartRect); |
204 | rightOffset+=width; |
205 | break; |
206 | } |
207 | case Qt::AlignTop: { |
208 | qreal height = size.height(); |
209 | if (topSqueezeRatio < 1.0) |
210 | height *= topSqueezeRatio; |
211 | axis->setGeometry(axis: QRect(geometry.left(), chartRect.top() - topOffset - height, geometry.width(), height), grid: chartRect); |
212 | topOffset += height; |
213 | break; |
214 | } |
215 | case Qt::AlignBottom: |
216 | qreal height = size.height(); |
217 | if (bottomSqueezeRatio < 1.0) |
218 | height *= bottomSqueezeRatio; |
219 | axis->setGeometry(axis: QRect(geometry.left(), chartRect.bottom() + bottomOffset, geometry.width(), height), grid: chartRect); |
220 | bottomOffset += height; |
221 | break; |
222 | } |
223 | } |
224 | |
225 | return chartRect; |
226 | } |
227 | |
228 | QRectF CartesianChartLayout::calculateAxisMinimum(const QRectF &minimum, const QList<ChartAxisElement *> &axes) const |
229 | { |
230 | QSizeF left; |
231 | QSizeF right; |
232 | QSizeF bottom; |
233 | QSizeF top; |
234 | |
235 | foreach (ChartAxisElement *axis, axes) { |
236 | QSizeF size = axis->effectiveSizeHint(which: Qt::MinimumSize); |
237 | |
238 | if (!axis->isVisible()) |
239 | continue; |
240 | |
241 | switch (axis->axis()->alignment()) { |
242 | case Qt::AlignLeft: |
243 | left.setWidth(left.width() + size.width()); |
244 | left.setHeight(qMax(a: left.height(), b: size.height())); |
245 | break; |
246 | case Qt::AlignRight: |
247 | right.setWidth(right.width() + size.width()); |
248 | right.setHeight(qMax(a: right.height(), b: size.height())); |
249 | break; |
250 | case Qt::AlignTop: |
251 | top.setWidth(qMax(a: top.width(), b: size.width())); |
252 | top.setHeight(top.height() + size.height()); |
253 | break; |
254 | case Qt::AlignBottom: |
255 | bottom.setWidth(qMax(a: bottom.width(), b: size.width())); |
256 | bottom.setHeight(bottom.height() + size.height()); |
257 | break; |
258 | } |
259 | } |
260 | return minimum.adjusted(xp1: 0, yp1: 0, xp2: left.width() + right.width() + qMax(a: top.width(), b: bottom.width()), yp2: top.height() + bottom.height() + qMax(a: left.height(), b: right.height())); |
261 | } |
262 | |
263 | QT_CHARTS_END_NAMESPACE |
264 | |