1 | // Copyright (C) 2017 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include "qvalue3daxis_p.h" |
5 | #include "qvalue3daxisformatter_p.h" |
6 | #include "abstract3dcontroller_p.h" |
7 | |
8 | QT_BEGIN_NAMESPACE |
9 | |
10 | /*! |
11 | * \class QValue3DAxis |
12 | * \inmodule QtDataVisualization |
13 | * \brief The QValue3DAxis class manipulates an axis of a graph. |
14 | * \since QtDataVisualization 1.0 |
15 | * |
16 | * A value axis can be given a range of values and segment and subsegment |
17 | * counts to divide the range into. |
18 | * |
19 | * Labels are drawn between each segment. Grid lines are drawn between each segment and each |
20 | * subsegment. \note If visible, there will always be at least two grid lines and labels indicating |
21 | * the minimum and the maximum values of the range, as there is always at least one segment. |
22 | */ |
23 | |
24 | /*! |
25 | * \qmltype ValueAxis3D |
26 | * \inqmlmodule QtDataVisualization |
27 | * \since QtDataVisualization 1.0 |
28 | * \ingroup datavisualization_qml |
29 | * \instantiates QValue3DAxis |
30 | * \inherits AbstractAxis3D |
31 | * \brief Manipulates an axis of a graph. |
32 | * |
33 | * This type provides an axis that can be given a range of values and segment and subsegment |
34 | * counts to divide the range into. |
35 | */ |
36 | |
37 | |
38 | /*! |
39 | * \qmlproperty int ValueAxis3D::segmentCount |
40 | * |
41 | * The number of segments on the axis. This indicates how many labels are drawn. The number |
42 | * of grid lines to be drawn is calculated with the following formula: |
43 | * \c {segments * subsegments + 1}. |
44 | * The preset default is \c 5. The value cannot be below \c 1. |
45 | */ |
46 | |
47 | /*! |
48 | * \qmlproperty int ValueAxis3D::subSegmentCount |
49 | * |
50 | * The number of subsegments inside each segment on the axis. Grid lines are drawn between |
51 | * each subsegment, in addition to each segment. |
52 | * The preset default is \c 1. The value cannot be below \c 1. |
53 | */ |
54 | |
55 | /*! |
56 | * \qmlproperty string ValueAxis3D::labelFormat |
57 | * |
58 | * The label format to be used for the labels on this axis. |
59 | * |
60 | * The format string supports the following conversion specifiers, length |
61 | * modifiers, and flags provided by \c printf() in the standard C++ library: |
62 | * d, i, o, x, X, f, F, e, E, g, G, c. |
63 | * |
64 | * If AbstractGraph3D::locale is anything else than \c{"C"}, the supported |
65 | * specifiers are limited to: d, e, E, f, g, G, and i. Also, only the precision |
66 | * modifier is supported. The rest of the formatting comes from the default |
67 | * \l Locale of the application. |
68 | * |
69 | * \sa AbstractGraph3D::locale |
70 | */ |
71 | |
72 | /*! |
73 | * \qmlproperty ValueAxis3DFormatter ValueAxis3D::formatter |
74 | * \since QtDataVisualization 1.1 |
75 | * |
76 | * The axis formatter to be used. Any existing formatter is deleted when a new formatter |
77 | * is set. |
78 | * |
79 | */ |
80 | |
81 | /*! |
82 | * \qmlproperty bool ValueAxis3D::reversed |
83 | * \since QtDataVisualization 1.1 |
84 | * |
85 | * If \c{true}, the axis will be rendered in reverse. That is, the positions of |
86 | * the minimum and maximum values are swapped when the graph is rendered. This |
87 | * property does not affect the actual minimum and maximum values of the axis. |
88 | */ |
89 | |
90 | /*! |
91 | * Constructs QValue3DAxis with the given \a parent. |
92 | */ |
93 | QValue3DAxis::QValue3DAxis(QObject *parent) : |
94 | QAbstract3DAxis(new QValue3DAxisPrivate(this), parent) |
95 | { |
96 | setFormatter(new QValue3DAxisFormatter); |
97 | } |
98 | |
99 | /*! |
100 | * Destroys QValue3DAxis. |
101 | */ |
102 | QValue3DAxis::~QValue3DAxis() |
103 | { |
104 | } |
105 | |
106 | /*! |
107 | * \property QValue3DAxis::segmentCount |
108 | * |
109 | * \brief The number of segments on the axis. |
110 | * |
111 | * This indicates how many labels are drawn. The number |
112 | * of grid lines to be drawn is calculated with formula: \c {segments * subsegments + 1}. |
113 | * The preset default is \c 5. The value cannot be below \c 1. |
114 | * |
115 | * \sa setSubSegmentCount() |
116 | */ |
117 | void QValue3DAxis::setSegmentCount(int count) |
118 | { |
119 | if (count <= 0) { |
120 | qWarning() << "Warning: Illegal segment count automatically adjusted to a legal one:" |
121 | << count << "-> 1" ; |
122 | count = 1; |
123 | } |
124 | if (dptr()->m_segmentCount != count) { |
125 | dptr()->m_segmentCount = count; |
126 | dptr()->emitLabelsChanged(); |
127 | emit segmentCountChanged(count); |
128 | } |
129 | } |
130 | |
131 | int QValue3DAxis::segmentCount() const |
132 | { |
133 | return dptrc()->m_segmentCount; |
134 | } |
135 | |
136 | /*! |
137 | * \property QValue3DAxis::subSegmentCount |
138 | * |
139 | * \brief The number of subsegments inside each segment on the axis. |
140 | * |
141 | * Grid lines are drawn between |
142 | * each subsegment, in addition to each segment. |
143 | * The preset default is \c 1. The value cannot be below \c 1. |
144 | * |
145 | * \sa setSegmentCount() |
146 | */ |
147 | void QValue3DAxis::setSubSegmentCount(int count) |
148 | { |
149 | if (count <= 0) { |
150 | qWarning() << "Warning: Illegal subsegment count automatically adjusted to a legal one:" |
151 | << count << "-> 1" ; |
152 | count = 1; |
153 | } |
154 | if (dptr()->m_subSegmentCount != count) { |
155 | dptr()->m_subSegmentCount = count; |
156 | emit subSegmentCountChanged(count); |
157 | } |
158 | } |
159 | |
160 | int QValue3DAxis::subSegmentCount() const |
161 | { |
162 | return dptrc()->m_subSegmentCount; |
163 | } |
164 | |
165 | /*! |
166 | * \property QValue3DAxis::labelFormat |
167 | * |
168 | * \brief The label format to be used for the labels on this axis. |
169 | * |
170 | * The format string supports the following conversion specifiers, length |
171 | * modifiers, and flags provided by \c printf() in the standard C++ library: |
172 | * d, i, o, x, X, f, F, e, E, g, G, c. |
173 | * |
174 | * If QAbstract3DGraph::locale is anything else than \c{"C"}, the supported |
175 | * specifiers are limited to: d, e, E, f, g, G, and i. Also, only the precision |
176 | * modifier is supported. The rest of the formatting comes from the default |
177 | * QLocale of the application. |
178 | * |
179 | * Usage example: |
180 | * |
181 | * \c {axis->setLabelFormat("%.2f mm");} |
182 | * |
183 | * \sa formatter, QAbstract3DGraph::locale |
184 | */ |
185 | void QValue3DAxis::setLabelFormat(const QString &format) |
186 | { |
187 | if (dptr()->m_labelFormat != format) { |
188 | dptr()->m_labelFormat = format; |
189 | dptr()->emitLabelsChanged(); |
190 | emit labelFormatChanged(format); |
191 | } |
192 | } |
193 | |
194 | QString QValue3DAxis::labelFormat() const |
195 | { |
196 | return dptrc()->m_labelFormat; |
197 | } |
198 | |
199 | /*! |
200 | * \property QValue3DAxis::formatter |
201 | * \since QtDataVisualization 1.1 |
202 | * |
203 | * \brief The axis formatter to be used. |
204 | * |
205 | * Any existing formatter is deleted when a new formatter |
206 | * is set. |
207 | */ |
208 | void QValue3DAxis::setFormatter(QValue3DAxisFormatter *formatter) |
209 | { |
210 | Q_ASSERT(formatter); |
211 | |
212 | if (formatter != dptr()->m_formatter) { |
213 | delete dptr()->m_formatter; |
214 | dptr()->m_formatter = formatter; |
215 | formatter->setParent(this); |
216 | formatter->d_ptr->setAxis(this); |
217 | Abstract3DController *controller = qobject_cast<Abstract3DController *>(object: parent()); |
218 | if (controller) |
219 | formatter->setLocale(controller->locale()); |
220 | emit formatterChanged(formatter); |
221 | emit dptr()->formatterDirty(); |
222 | } |
223 | } |
224 | |
225 | QValue3DAxisFormatter *QValue3DAxis::formatter() const |
226 | { |
227 | return dptrc()->m_formatter; |
228 | } |
229 | |
230 | /*! |
231 | * \property QValue3DAxis::reversed |
232 | * \since QtDataVisualization 1.1 |
233 | * |
234 | * \brief Whether the axis is rendered in reverse. |
235 | * |
236 | * If \c{true}, the axis will be rendered in reverse, i.e. the positions of minimum and maximum |
237 | * values are swapped when the graph is rendered. This property doesn't affect the actual |
238 | * minimum and maximum values of the axis. |
239 | */ |
240 | void QValue3DAxis::setReversed(bool enable) |
241 | { |
242 | if (dptr()->m_reversed != enable) { |
243 | dptr()->m_reversed = enable; |
244 | emit reversedChanged(enable); |
245 | } |
246 | } |
247 | |
248 | bool QValue3DAxis::reversed() const |
249 | { |
250 | return dptrc()->m_reversed; |
251 | } |
252 | |
253 | /*! |
254 | * \internal |
255 | */ |
256 | QValue3DAxisPrivate *QValue3DAxis::dptr() |
257 | { |
258 | return static_cast<QValue3DAxisPrivate *>(d_ptr.data()); |
259 | } |
260 | |
261 | /*! |
262 | * \internal |
263 | */ |
264 | const QValue3DAxisPrivate *QValue3DAxis::dptrc() const |
265 | { |
266 | return static_cast<const QValue3DAxisPrivate *>(d_ptr.data()); |
267 | } |
268 | |
269 | QValue3DAxisPrivate::QValue3DAxisPrivate(QValue3DAxis *q) |
270 | : QAbstract3DAxisPrivate(q, QAbstract3DAxis::AxisTypeValue), |
271 | m_segmentCount(5), |
272 | m_subSegmentCount(1), |
273 | m_labelFormat(Utils::defaultLabelFormat()), |
274 | m_labelsDirty(true), |
275 | m_formatter(0), |
276 | m_reversed(false) |
277 | { |
278 | } |
279 | |
280 | QValue3DAxisPrivate::~QValue3DAxisPrivate() |
281 | { |
282 | } |
283 | |
284 | void QValue3DAxisPrivate::setRange(float min, float max, bool suppressWarnings) |
285 | { |
286 | bool dirty = (min != m_min || max != m_max); |
287 | |
288 | QAbstract3DAxisPrivate::setRange(min, max, suppressWarnings); |
289 | |
290 | if (dirty) |
291 | emitLabelsChanged(); |
292 | } |
293 | |
294 | void QValue3DAxisPrivate::setMin(float min) |
295 | { |
296 | bool dirty = (min != m_min); |
297 | |
298 | QAbstract3DAxisPrivate::setMin(min); |
299 | |
300 | if (dirty) |
301 | emitLabelsChanged(); |
302 | } |
303 | |
304 | void QValue3DAxisPrivate::setMax(float max) |
305 | { |
306 | bool dirty = (max != m_max); |
307 | |
308 | QAbstract3DAxisPrivate::setMax(max); |
309 | |
310 | if (dirty) |
311 | emitLabelsChanged(); |
312 | } |
313 | |
314 | void QValue3DAxisPrivate::emitLabelsChanged() |
315 | { |
316 | m_labelsDirty = true; |
317 | emit q_ptr->labelsChanged(); |
318 | } |
319 | |
320 | void QValue3DAxisPrivate::updateLabels() |
321 | { |
322 | if (!m_labelsDirty) |
323 | return; |
324 | |
325 | m_labelsDirty = false; |
326 | |
327 | m_formatter->d_ptr->recalculate(); |
328 | |
329 | m_labels = m_formatter->labelStrings(); |
330 | } |
331 | |
332 | bool QValue3DAxisPrivate::allowZero() |
333 | { |
334 | return m_formatter->allowZero(); |
335 | } |
336 | |
337 | bool QValue3DAxisPrivate::allowNegatives() |
338 | { |
339 | return m_formatter->allowNegatives(); |
340 | } |
341 | |
342 | bool QValue3DAxisPrivate::allowMinMaxSame() |
343 | { |
344 | return false; |
345 | } |
346 | |
347 | QValue3DAxis *QValue3DAxisPrivate::qptr() |
348 | { |
349 | return static_cast<QValue3DAxis *>(q_ptr); |
350 | } |
351 | |
352 | QT_END_NAMESPACE |
353 | |