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

source code of qtgraphs/src/graphs/axis/qvalue3daxis.cpp