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/chartaxiselement_p.h>
31#include <private/qabstractaxis_p.h>
32#include <private/chartpresenter_p.h>
33#include <private/abstractchartlayout_p.h>
34#include <QtCharts/QCategoryAxis>
35#include <QtCore/QtMath>
36#include <QtCore/QDateTime>
37#include <QtCore/QRegularExpression>
38#include <QtGui/QTextDocument>
39#include <cmath>
40
41QT_CHARTS_BEGIN_NAMESPACE
42
43static const char *labelFormatMatchString = "%[\\-\\+#\\s\\d\\.\\'lhjztL]*([dicuoxfegXFEG])";
44static const char *labelFormatMatchLocalizedString = "^([^%]*)%\\.(\\d+)([defgiEG])(.*)$";
45static QRegularExpression *labelFormatMatcher = 0;
46static QRegularExpression *labelFormatMatcherLocalized = 0;
47class StaticLabelFormatMatcherDeleter
48{
49public:
50 StaticLabelFormatMatcherDeleter() {}
51 ~StaticLabelFormatMatcherDeleter() {
52 delete labelFormatMatcher;
53 delete labelFormatMatcherLocalized;
54 }
55};
56static StaticLabelFormatMatcherDeleter staticLabelFormatMatcherDeleter;
57
58ChartAxisElement::ChartAxisElement(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
59 : ChartElement(item),
60 m_axis(axis),
61 m_animation(0),
62 m_grid(new QGraphicsItemGroup(item)),
63 m_arrow(new QGraphicsItemGroup(item)),
64 m_minorGrid(new QGraphicsItemGroup(item)),
65 m_minorArrow(new QGraphicsItemGroup(item)),
66 m_shades(new QGraphicsItemGroup(item)),
67 m_labels(new QGraphicsItemGroup(item)),
68 m_title(new QGraphicsTextItem(item)),
69 m_intervalAxis(intervalAxis)
70
71{
72 //initial initialization
73 m_arrow->setHandlesChildEvents(false);
74 m_arrow->setZValue(ChartPresenter::AxisZValue);
75 m_minorArrow->setHandlesChildEvents(false);
76 m_minorArrow->setZValue(ChartPresenter::AxisZValue);
77 m_labels->setZValue(ChartPresenter::AxisZValue);
78 m_shades->setZValue(ChartPresenter::ShadesZValue);
79 m_grid->setZValue(ChartPresenter::GridZValue);
80 m_minorGrid->setZValue(ChartPresenter::GridZValue);
81 m_title->setZValue(ChartPresenter::GridZValue);
82 m_title->document()->setDocumentMargin(ChartPresenter::textMargin());
83 handleVisibleChanged(visible: axis->isVisible());
84 connectSlots();
85
86 setFlag(flag: QGraphicsItem::ItemHasNoContents, enabled: true);
87}
88
89ChartAxisElement::~ChartAxisElement()
90{
91}
92
93void ChartAxisElement::connectSlots()
94{
95 QObject::connect(sender: axis(), SIGNAL(visibleChanged(bool)), receiver: this, SLOT(handleVisibleChanged(bool)));
96 QObject::connect(sender: axis(), SIGNAL(lineVisibleChanged(bool)), receiver: this, SLOT(handleArrowVisibleChanged(bool)));
97 QObject::connect(sender: axis(), SIGNAL(gridVisibleChanged(bool)), receiver: this, SLOT(handleGridVisibleChanged(bool)));
98 QObject::connect(sender: axis(), SIGNAL(labelsVisibleChanged(bool)), receiver: this, SLOT(handleLabelsVisibleChanged(bool)));
99 QObject::connect(sender: axis(), SIGNAL(shadesVisibleChanged(bool)), receiver: this, SLOT(handleShadesVisibleChanged(bool)));
100 QObject::connect(sender: axis(), SIGNAL(labelsAngleChanged(int)), receiver: this, SLOT(handleLabelsAngleChanged(int)));
101 QObject::connect(sender: axis(), SIGNAL(linePenChanged(const QPen&)), receiver: this, SLOT(handleArrowPenChanged(const QPen&)));
102 QObject::connect(sender: axis(), SIGNAL(labelsBrushChanged(const QBrush&)), receiver: this, SLOT(handleLabelsBrushChanged(const QBrush&)));
103 QObject::connect(sender: axis(), SIGNAL(labelsFontChanged(const QFont&)), receiver: this, SLOT(handleLabelsFontChanged(const QFont&)));
104 QObject::connect(sender: axis(), SIGNAL(gridLinePenChanged(const QPen&)), receiver: this, SLOT(handleGridPenChanged(const QPen&)));
105 QObject::connect(sender: axis(), SIGNAL(shadesPenChanged(const QPen&)), receiver: this, SLOT(handleShadesPenChanged(const QPen&)));
106 QObject::connect(sender: axis(), SIGNAL(shadesBrushChanged(const QBrush&)), receiver: this, SLOT(handleShadesBrushChanged(const QBrush&)));
107 QObject::connect(sender: axis(), SIGNAL(titleTextChanged(const QString&)), receiver: this, SLOT(handleTitleTextChanged(const QString&)));
108 QObject::connect(sender: axis(), SIGNAL(titleFontChanged(const QFont&)), receiver: this, SLOT(handleTitleFontChanged(const QFont&)));
109 QObject::connect(sender: axis(), SIGNAL(titleBrushChanged(const QBrush&)), receiver: this, SLOT(handleTitleBrushChanged(const QBrush&)));
110 QObject::connect(sender: axis(), SIGNAL(titleVisibleChanged(bool)), receiver: this, SLOT(handleTitleVisibleChanged(bool)));
111 QObject::connect(sender: axis()->d_ptr.data(), SIGNAL(rangeChanged(qreal, qreal)), receiver: this, SLOT(handleRangeChanged(qreal, qreal)));
112 QObject::connect(sender: axis(), SIGNAL(reverseChanged(bool)), receiver: this, SLOT(handleReverseChanged(bool)));
113 QObject::connect(sender: axis(), SIGNAL(lineVisibleChanged(bool)),
114 receiver: this, SLOT(handleMinorArrowVisibleChanged(bool)));
115 QObject::connect(sender: axis(), SIGNAL(linePenChanged(const QPen&)), receiver: this,
116 SLOT(handleMinorArrowPenChanged(const QPen&)));
117 QObject::connect(sender: axis(), SIGNAL(minorGridVisibleChanged(bool)),
118 receiver: this, SLOT(handleMinorGridVisibleChanged(bool)));
119 QObject::connect(sender: axis(), SIGNAL(minorGridLinePenChanged(const QPen&)),
120 receiver: this, SLOT(handleMinorGridPenChanged(const QPen&)));
121 QObject::connect(sender: axis(), SIGNAL(gridLineColorChanged(const QColor&)),
122 receiver: this, SLOT(handleGridLineColorChanged(const QColor&)));
123 QObject::connect(sender: axis(), SIGNAL(minorGridLineColorChanged(const QColor&)),
124 receiver: this, SLOT(handleMinorGridLineColorChanged(const QColor&)));
125
126 if (axis()->type() == QAbstractAxis::AxisTypeCategory) {
127 QCategoryAxis *categoryAxis = static_cast<QCategoryAxis *>(axis());
128 QObject::connect(sender: categoryAxis,
129 SIGNAL(labelsPositionChanged(QCategoryAxis::AxisLabelsPosition)),
130 receiver: this, SLOT(handleLabelsPositionChanged()));
131 }
132}
133
134void ChartAxisElement::handleArrowVisibleChanged(bool visible)
135{
136 m_arrow->setVisible(visible);
137}
138
139void ChartAxisElement::handleMinorArrowVisibleChanged(bool visible)
140{
141 m_minorArrow->setVisible(visible);
142}
143
144void ChartAxisElement::handleGridVisibleChanged(bool visible)
145{
146 m_grid->setVisible(visible);
147}
148
149void ChartAxisElement::handleMinorGridVisibleChanged(bool visible)
150{
151 m_minorGrid->setVisible(visible);
152}
153
154void ChartAxisElement::handleLabelsPositionChanged()
155{
156 QGraphicsLayoutItem::updateGeometry();
157 presenter()->layout()->invalidate();
158}
159
160void ChartAxisElement::valueLabelEdited(qreal oldValue, qreal newValue)
161{
162 qreal range = max() - min();
163 qreal center = ((max() - min()) / 2.0) + min();
164 qreal newRange = 0.0;
165 auto label = static_cast<ValueAxisLabel *>(this->sender());
166 if ((oldValue >= center && newValue >= min())
167 || (oldValue < center && newValue >= max() && oldValue != min())) {
168 newRange = range * ((newValue - min()) / (oldValue - min()));
169 if (newRange > 0) {
170 m_axis->setRange(min: min(), max: min() + newRange);
171 return;
172 }
173 } else if ((oldValue >= center && newValue <= min() && max() != oldValue)
174 || (oldValue < center && newValue < max())) {
175 newRange = range * ((max() - newValue) / (max() - oldValue));
176 if (newRange > 0) {
177 m_axis->setRange(min: max() - newRange, max: max());
178 return;
179 }
180 }
181 label->reloadBeforeEditContent();
182}
183
184void ChartAxisElement::dateTimeLabelEdited(const QDateTime &oldTime, const QDateTime &newTime)
185{
186 qreal range = max() - min();
187 qreal center = ((max() - min()) / 2.0) + min();
188 qreal newRange = 0.0;
189 qint64 oldValue = oldTime.toMSecsSinceEpoch();
190 qint64 newValue = newTime.toMSecsSinceEpoch();
191 if ((oldValue >= center && newValue >= min())
192 || (oldValue < center && newValue >= max() && oldValue != min())) {
193 newRange = range * ((newValue - min()) / (oldValue - min()));
194 if (newRange > 0) {
195 m_axis->setRange(
196 min: QDateTime::fromMSecsSinceEpoch(msecs: min()),
197 max: QDateTime::fromMSecsSinceEpoch(msecs: min() + newRange));
198 return;
199 }
200 } else if ((oldValue >= center && newValue <= min() && max() != oldValue)
201 || (oldValue < center && newValue < max())) {
202 newRange = range * ((max() - newValue) / (max() - oldValue));
203 if (newRange > 0) {
204 m_axis->setRange(min: max() - newRange, max: max());
205 m_axis->setRange(
206 min: QDateTime::fromMSecsSinceEpoch(msecs: max() - newRange),
207 max: QDateTime::fromMSecsSinceEpoch(msecs: max()));
208 return;
209 }
210 }
211 static_cast<DateTimeAxisLabel *>(this->sender())->reloadBeforeEditContent();
212}
213
214void ChartAxisElement::handleLabelsVisibleChanged(bool visible)
215{
216 QGraphicsLayoutItem::updateGeometry();
217 presenter()->layout()->invalidate();
218 m_labels->setVisible(visible);
219}
220
221void ChartAxisElement::handleShadesVisibleChanged(bool visible)
222{
223 m_shades->setVisible(visible);
224}
225
226void ChartAxisElement::handleTitleVisibleChanged(bool visible)
227{
228 QGraphicsLayoutItem::updateGeometry();
229 presenter()->layout()->invalidate();
230 m_title->setVisible(visible);
231}
232
233void ChartAxisElement::handleLabelsAngleChanged(int angle)
234{
235 foreach (QGraphicsItem *item, m_labels->childItems())
236 item->setRotation(angle);
237
238 QGraphicsLayoutItem::updateGeometry();
239 presenter()->layout()->invalidate();
240}
241
242void ChartAxisElement::handleLabelsBrushChanged(const QBrush &brush)
243{
244 foreach (QGraphicsItem *item, m_labels->childItems())
245 static_cast<QGraphicsTextItem *>(item)->setDefaultTextColor(brush.color());
246}
247
248void ChartAxisElement::handleLabelsFontChanged(const QFont &font)
249{
250 foreach (QGraphicsItem *item, m_labels->childItems())
251 static_cast<QGraphicsTextItem *>(item)->setFont(font);
252 QGraphicsLayoutItem::updateGeometry();
253 presenter()->layout()->invalidate();
254}
255
256void ChartAxisElement::handleTitleTextChanged(const QString &title)
257{
258 QGraphicsLayoutItem::updateGeometry();
259 presenter()->layout()->invalidate();
260 if (title.isEmpty() || !m_title->isVisible())
261 m_title->setHtml(title);
262}
263
264void ChartAxisElement::handleTitleBrushChanged(const QBrush &brush)
265{
266 m_title->setDefaultTextColor(brush.color());
267}
268
269void ChartAxisElement::handleTitleFontChanged(const QFont &font)
270{
271 if (m_title->font() != font) {
272 m_title->setFont(font);
273 QGraphicsLayoutItem::updateGeometry();
274 presenter()->layout()->invalidate();
275 }
276}
277
278void ChartAxisElement::handleVisibleChanged(bool visible)
279{
280 setVisible(visible);
281 if (!visible) {
282 m_grid->setVisible(visible);
283 m_arrow->setVisible(visible);
284 m_minorGrid->setVisible(visible);
285 m_minorArrow->setVisible(visible);
286 m_shades->setVisible(visible);
287 m_labels->setVisible(visible);
288 m_title->setVisible(visible);
289 } else {
290 m_grid->setVisible(axis()->isGridLineVisible());
291 m_arrow->setVisible(axis()->isLineVisible());
292 m_minorGrid->setVisible(axis()->isMinorGridLineVisible());
293 m_minorArrow->setVisible(axis()->isLineVisible());
294 m_shades->setVisible(axis()->shadesVisible());
295 m_labels->setVisible(axis()->labelsVisible());
296 m_title->setVisible(axis()->isTitleVisible());
297 }
298 if (presenter()) {
299 if (visible) {
300 QSizeF before = effectiveSizeHint(which: Qt::PreferredSize);
301 QSizeF after = sizeHint(which: Qt::PreferredSize);
302 if (before != after)
303 QGraphicsLayoutItem::updateGeometry();
304 }
305 presenter()->layout()->invalidate();
306 }
307}
308
309void ChartAxisElement::handleRangeChanged(qreal min, qreal max)
310{
311 Q_UNUSED(min);
312 Q_UNUSED(max);
313
314 if (!isEmpty()) {
315 QVector<qreal> layout = calculateLayout();
316 updateLayout(layout);
317 QSizeF before = effectiveSizeHint(which: Qt::PreferredSize);
318 QSizeF after = sizeHint(which: Qt::PreferredSize);
319
320 if (before != after) {
321 QGraphicsLayoutItem::updateGeometry();
322 // We don't want to call invalidate on layout, since it will change minimum size of
323 // component, which we would like to avoid since it causes nasty flips when scrolling
324 // or zooming, instead recalculate layout and use plotArea for extra space.
325 presenter()->layout()->setGeometry(presenter()->layout()->geometry());
326 }
327 }
328}
329
330void ChartAxisElement::handleReverseChanged(bool reverse)
331{
332 Q_UNUSED(reverse);
333
334 QGraphicsLayoutItem::updateGeometry();
335 presenter()->layout()->invalidate();
336}
337
338bool ChartAxisElement::isEmpty()
339{
340 return axisGeometry().isEmpty()
341 || gridGeometry().isEmpty()
342 || qFuzzyCompare(p1: min(), p2: max());
343}
344
345qreal ChartAxisElement::min() const
346{
347 return m_axis->d_ptr->min();
348}
349
350qreal ChartAxisElement::max() const
351{
352 return m_axis->d_ptr->max();
353}
354
355qreal ChartAxisElement::tickInterval() const
356{
357 QValueAxis *valueAxis = qobject_cast<QValueAxis *>(object: m_axis);
358 if (valueAxis)
359 return valueAxis->tickInterval();
360 else
361 return 0.0;
362}
363
364qreal ChartAxisElement::tickAnchor() const
365{
366 QValueAxis *valueAxis = qobject_cast<QValueAxis *>(object: m_axis);
367 if (valueAxis)
368 return valueAxis->tickAnchor();
369 else
370 return 0.0;
371}
372
373QString ChartAxisElement::formatLabel(const QString &formatSpec, const QByteArray &array,
374 qreal value, int precision, const QString &preStr,
375 const QString &postStr) const
376{
377 QString retVal;
378 if (!formatSpec.isEmpty()) {
379 if (formatSpec.at(i: 0) == QLatin1Char('d')
380 || formatSpec.at(i: 0) == QLatin1Char('i')
381 || formatSpec.at(i: 0) == QLatin1Char('c')) {
382 if (presenter()->localizeNumbers())
383 retVal = preStr + presenter()->locale().toString(i: qint64(value)) + postStr;
384 else
385 retVal = QString::asprintf(format: array.constData(), qint64(value));
386 } else if (formatSpec.at(i: 0) == QLatin1Char('u')
387 || formatSpec.at(i: 0) == QLatin1Char('o')
388 || formatSpec.at(i: 0) == QLatin1Char('x')
389 || formatSpec.at(i: 0) == QLatin1Char('X')) {
390 // These formats are not supported by localized numbers
391 retVal = QString::asprintf(format: array.constData(), quint64(value));
392 } else if (formatSpec.at(i: 0) == QLatin1Char('f')
393 || formatSpec.at(i: 0) == QLatin1Char('F')
394 || formatSpec.at(i: 0) == QLatin1Char('e')
395 || formatSpec.at(i: 0) == QLatin1Char('E')
396 || formatSpec.at(i: 0) == QLatin1Char('g')
397 || formatSpec.at(i: 0) == QLatin1Char('G')) {
398 if (presenter()->localizeNumbers()) {
399 retVal = preStr
400 + presenter()->locale().toString(i: value, f: formatSpec.at(i: 0).toLatin1(),
401 prec: precision)
402 + postStr;
403 } else {
404 retVal = QString::asprintf(format: array.constData(), value);
405 }
406 }
407 }
408 return retVal;
409}
410
411QStringList ChartAxisElement::createValueLabels(qreal min, qreal max, int ticks,
412 qreal tickInterval, qreal tickAnchor,
413 QValueAxis::TickType tickType,
414 const QString &format) const
415{
416 QStringList labels;
417
418 if (max <= min || ticks < 1)
419 return labels;
420
421 if (format.isEmpty()) {
422 // Calculate how many decimal digits are needed to show difference between ticks,
423 // for example tick marks 1.002 and 1.003 have a difference of 0.001 and need 3 decimals.
424 // For differences >= 1 (positive log10) use always 1 decimal.
425 double l10 = std::log10(x: (max - min) / (ticks - 1));
426 int n = qMax(a: int(-qFloor(v: l10)), b: 0) + 1;
427 if (tickType == QValueAxis::TicksFixed) {
428 for (int i = 0; i < ticks; i++) {
429 qreal value = min + (i * (max - min) / (ticks - 1));
430 labels << presenter()->numberToString(value, f: 'f', prec: n);
431 }
432 } else {
433 qreal value = tickAnchor;
434 if (value > min)
435 value = value - int((value - min) / tickInterval) * tickInterval;
436 else
437 value = value + qCeil(v: (min - value) / tickInterval) * tickInterval;
438
439 while (value <= max || qFuzzyCompare(p1: value, p2: max)) {
440 labels << presenter()->numberToString(value, f: 'f', prec: n);
441 value += tickInterval;
442 }
443 }
444 } else {
445 QByteArray array = format.toLatin1();
446 QString formatSpec;
447 QString preStr;
448 QString postStr;
449 int precision = 6; // Six is the default precision in Qt API
450 if (presenter()->localizeNumbers()) {
451 if (!labelFormatMatcherLocalized)
452 labelFormatMatcherLocalized
453 = new QRegularExpression(QString::fromLatin1(str: labelFormatMatchLocalizedString));
454 QRegularExpressionMatch rmatch;
455 if (format.indexOf(re: *labelFormatMatcherLocalized, from: 0, rmatch: &rmatch) != -1) {
456 preStr = rmatch.captured(nth: 1);
457 if (!rmatch.captured(nth: 2).isEmpty())
458 precision = rmatch.captured(nth: 2).toInt();
459 formatSpec = rmatch.captured(nth: 3);
460 postStr = rmatch.captured(nth: 4);
461 }
462 } else {
463 if (!labelFormatMatcher)
464 labelFormatMatcher = new QRegularExpression(QString::fromLatin1(str: labelFormatMatchString));
465 QRegularExpressionMatch rmatch;
466 if (format.indexOf(re: *labelFormatMatcher, from: 0, rmatch: &rmatch) != -1)
467 formatSpec = rmatch.captured(nth: 1);
468 }
469 if (tickType == QValueAxis::TicksFixed) {
470 for (int i = 0; i < ticks; i++) {
471 qreal value = min + (i * (max - min) / (ticks - 1));
472 labels << formatLabel(formatSpec, array, value, precision, preStr, postStr);
473 }
474 } else {
475 qreal value = tickAnchor;
476 if (value > min)
477 value = value - int((value - min) / tickInterval) * tickInterval;
478 else
479 value = value + qCeil(v: (min - value) / tickInterval) * tickInterval;
480
481 while (value <= max || qFuzzyCompare(p1: value, p2: max)) {
482 labels << formatLabel(formatSpec, array, value, precision, preStr, postStr);
483 value += tickInterval;
484 }
485 }
486 }
487
488 return labels;
489}
490
491QStringList ChartAxisElement::createLogValueLabels(qreal min, qreal max, qreal base, int ticks,
492 const QString &format) const
493{
494 QStringList labels;
495
496 if (max <= min || ticks < 1)
497 return labels;
498
499 int firstTick;
500 if (base > 1)
501 firstTick = qCeil(v: std::log10(x: min) / std::log10(x: base));
502 else
503 firstTick = qCeil(v: std::log10(x: max) / std::log10(x: base));
504
505 if (format.isEmpty()) {
506 int n = 0;
507 if (ticks > 1)
508 n = qMax(a: int(-qFloor(v: std::log10(x: (max - min) / (ticks - 1)))), b: 0);
509 n++;
510 for (int i = firstTick; i < ticks + firstTick; i++) {
511 qreal value = qPow(x: base, y: i);
512 labels << presenter()->numberToString(value, f: 'f', prec: n);
513 }
514 } else {
515 QByteArray array = format.toLatin1();
516 QString formatSpec;
517 QString preStr;
518 QString postStr;
519 int precision = 6; // Six is the default precision in Qt API
520 if (presenter()->localizeNumbers()) {
521 if (!labelFormatMatcherLocalized)
522 labelFormatMatcherLocalized =
523 new QRegularExpression(QString::fromLatin1(str: labelFormatMatchLocalizedString));
524 QRegularExpressionMatch rmatch;
525 if (format.indexOf(re: *labelFormatMatcherLocalized, from: 0, rmatch: &rmatch) != -1) {
526 preStr = rmatch.captured(nth: 1);
527 if (!rmatch.captured(nth: 2).isEmpty())
528 precision = rmatch.captured(nth: 2).toInt();
529 formatSpec = rmatch.captured(nth: 3);
530 postStr = rmatch.captured(nth: 4);
531 }
532 } else {
533 if (!labelFormatMatcher)
534 labelFormatMatcher = new QRegularExpression(QString::fromLatin1(str: labelFormatMatchString));
535 QRegularExpressionMatch rmatch;
536 if (format.indexOf(re: *labelFormatMatcher, from: 0, rmatch: &rmatch) != -1)
537 formatSpec = rmatch.captured(nth: 1);
538 }
539 for (int i = firstTick; i < ticks + firstTick; i++) {
540 qreal value = qPow(x: base, y: i);
541 labels << formatLabel(formatSpec, array, value, precision, preStr, postStr);
542 }
543 }
544
545 return labels;
546}
547
548QStringList ChartAxisElement::createDateTimeLabels(qreal min, qreal max,int ticks,
549 const QString &format) const
550{
551 QStringList labels;
552
553 if (max <= min || ticks < 1)
554 return labels;
555
556 for (int i = 0; i < ticks; i++) {
557 qreal value = min + (i * (max - min) / (ticks - 1));
558 labels << presenter()->locale().toString(dateTime: QDateTime::fromMSecsSinceEpoch(msecs: value), format);
559 }
560 return labels;
561}
562
563
564bool ChartAxisElement::labelsEditable() const
565{
566 return m_labelsEditable;
567}
568
569void ChartAxisElement::setLabelsEditable(bool labelsEditable)
570{
571 if (axis()->type() == QAbstractAxis::AxisTypeValue
572 || axis()->type() == QAbstractAxis::AxisTypeDateTime) {
573 labelGroup()->setHandlesChildEvents(!labelsEditable);
574 const QList<QGraphicsItem *> childItems = labelGroup()->childItems();
575 for (auto item : childItems) {
576 switch (axis()->type()) {
577 case QtCharts::QAbstractAxis::AxisTypeValue:
578 static_cast<ValueAxisLabel *>(item)->setEditable(labelsEditable);
579 break;
580 case QtCharts::QAbstractAxis::AxisTypeDateTime:
581 static_cast<DateTimeAxisLabel *>(item)->setEditable(labelsEditable);
582 break;
583 default:
584 break;
585 }
586 }
587 m_labelsEditable = labelsEditable;
588 }
589}
590
591void ChartAxisElement::axisSelected()
592{
593 emit clicked();
594}
595
596QT_CHARTS_END_NAMESPACE
597
598#include "moc_chartaxiselement_p.cpp"
599

source code of qtcharts/src/charts/axis/chartaxiselement.cpp