KQuickCharts

AxisLabels.cpp
1/*
2 * This file is part of KQuickCharts
3 * SPDX-FileCopyrightText: 2019 Arjen Hiemstra <ahiemstra@heimr.nl>
4 *
5 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6 */
7
8#include "AxisLabels.h"
9
10#include <QDebug>
11#include <QQmlContext>
12
13#include "ItemBuilder.h"
14#include "datasource/ChartDataSource.h"
15
16AxisLabelsAttached::AxisLabelsAttached(QObject *parent)
17 : QObject(parent)
18{
19}
20
21int AxisLabelsAttached::index() const
22{
23 return m_index;
24}
25
26void AxisLabelsAttached::setIndex(int newIndex)
27{
28 if (newIndex == m_index) {
29 return;
30 }
31
32 m_index = newIndex;
33 Q_EMIT indexChanged();
34}
35
36QString AxisLabelsAttached::label() const
37{
38 return m_label;
39}
40
41void AxisLabelsAttached::setLabel(const QString &newLabel)
42{
43 if (newLabel == m_label) {
44 return;
45 }
46
47 m_label = newLabel;
48 Q_EMIT labelChanged();
49}
50
51AxisLabels::AxisLabels(QQuickItem *parent)
52 : QQuickItem(parent)
53{
54 m_itemBuilder = std::make_unique<ItemBuilder>();
55 connect(m_itemBuilder.get(), &ItemBuilder::finished, this, &AxisLabels::polish);
56 connect(m_itemBuilder.get(), &ItemBuilder::beginCreate, this, &AxisLabels::onBeginCreate);
57}
58
59AxisLabels::~AxisLabels() = default;
60
61AxisLabels::Direction AxisLabels::direction() const
62{
63 return m_direction;
64}
65
66void AxisLabels::setDirection(AxisLabels::Direction newDirection)
67{
68 if (newDirection == m_direction) {
69 return;
70 }
71
72 m_direction = newDirection;
73 polish();
74 Q_EMIT directionChanged();
75}
76
77QQmlComponent *AxisLabels::delegate() const
78{
79 return m_itemBuilder->component();
80}
81
82void AxisLabels::setDelegate(QQmlComponent *newDelegate)
83{
84 if (newDelegate == m_itemBuilder->component()) {
85 return;
86 }
87
88 m_itemBuilder->setComponent(newDelegate);
89 updateLabels();
90 Q_EMIT delegateChanged();
91}
92
93ChartDataSource *AxisLabels::source() const
94{
95 return m_source;
96}
97
98void AxisLabels::setSource(ChartDataSource *newSource)
99{
100 if (newSource == m_source) {
101 return;
102 }
103
104 if (m_source) {
105 m_source->disconnect(this);
106 }
107
108 m_source = newSource;
109
110 if (m_source) {
111 connect(m_source, &ChartDataSource::dataChanged, this, [this]() {
112 updateLabels();
113 });
114 }
115
116 updateLabels();
117 Q_EMIT sourceChanged();
118}
119
120Qt::Alignment AxisLabels::alignment() const
121{
122 return m_alignment;
123}
124
125void AxisLabels::setAlignment(Qt::Alignment newAlignment)
126{
127 if (newAlignment == m_alignment) {
128 return;
129 }
130
131 m_alignment = newAlignment;
132 polish();
133 Q_EMIT alignmentChanged();
134}
135
136bool AxisLabels::constrainToBounds() const
137{
138 return m_constrainToBounds;
139}
140
141void AxisLabels::setConstrainToBounds(bool newConstrainToBounds)
142{
143 if (newConstrainToBounds == m_constrainToBounds) {
144 return;
145 }
146
147 m_constrainToBounds = newConstrainToBounds;
148 polish();
149 Q_EMIT constrainToBoundsChanged();
150}
151
152void AxisLabels::updatePolish()
153{
154 if (!m_itemBuilder->isFinished()) {
155 return;
156 }
157
158 auto maxWidth = 0.0;
159 auto totalWidth = 0.0;
160 auto maxHeight = 0.0;
161 auto totalHeight = 0.0;
162
163 auto labels = m_itemBuilder->items();
164 for (auto label : labels) {
165 maxWidth = std::max(maxWidth, label->implicitWidth());
166 maxHeight = std::max(maxHeight, label->implicitHeight());
167 totalWidth += label->implicitWidth();
168 totalHeight += label->implicitHeight();
169 }
170
171 auto impWidth = isHorizontal() ? totalWidth : maxWidth;
172 auto impHeight = isHorizontal() ? maxHeight : totalHeight;
173
174 if (qFuzzyCompare(impWidth, width()) && qFuzzyCompare(impHeight, height())) {
175 return;
176 }
177
178 setImplicitSize(impWidth, impHeight);
179
180 auto spacing = (isHorizontal() ? width() : height()) / (labels.size() - 1);
181 auto i = 0;
182 auto layoutWidth = isHorizontal() ? 0.0 : width();
183 auto layoutHeight = isHorizontal() ? height() : 0.0;
184
185 for (auto label : labels) {
186 auto x = 0.0;
187 auto y = 0.0;
188
189 switch (m_direction) {
190 case Direction::HorizontalLeftRight:
191 x = i * spacing;
192 break;
193 case Direction::HorizontalRightLeft:
194 x = width() - i * spacing;
195 break;
196 case Direction::VerticalTopBottom:
197 y = i * spacing;
198 break;
199 case Direction::VerticalBottomTop:
200 y = height() - i * spacing;
201 break;
202 }
203
204 if (m_alignment & Qt::AlignHCenter) {
205 x += (layoutWidth - label->implicitWidth()) / 2;
206 } else if (m_alignment & Qt::AlignRight) {
207 x += layoutWidth - label->implicitWidth();
208 }
209
210 if (m_alignment & Qt::AlignVCenter) {
211 y += (layoutHeight - label->implicitHeight()) / 2;
212 } else if (m_alignment & Qt::AlignBottom) {
213 y += layoutHeight - label->implicitHeight();
214 }
215
216 if (m_constrainToBounds) {
217 x = std::max(x, 0.0);
218 x = x + label->implicitWidth() > width() ? width() - label->implicitWidth() : x;
219 y = std::max(y, 0.0);
220 y = y + label->implicitHeight() > height() ? height() - label->implicitHeight() : y;
221 }
222
223 label->setX(x);
224 label->setY(y);
225
226 i++;
227 }
228}
229
230void AxisLabels::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
231{
232 QQuickItem::geometryChange(newGeometry, oldGeometry);
233
234 if (newGeometry != oldGeometry) {
235 polish();
236 }
237}
238
239bool AxisLabels::isHorizontal()
240{
241 return m_direction == Direction::HorizontalLeftRight || m_direction == Direction::HorizontalRightLeft;
242}
243
244void AxisLabels::updateLabels()
245{
246 m_itemBuilder->clear();
247
248 if (!m_itemBuilder->component() || !m_source) {
249 return;
250 }
251
252 m_itemBuilder->setCount(m_source->itemCount());
253 m_itemBuilder->build(this);
254}
255
256void AxisLabels::onBeginCreate(int index, QQuickItem *item)
257{
260
261 auto attached = static_cast<AxisLabelsAttached *>(qmlAttachedPropertiesObject<AxisLabels>(item, true));
262 attached->setIndex(index);
263 attached->setLabel(m_source->item(index).toString());
264}
265
266#include "moc_AxisLabels.cpp"
Abstract base class for data sources.
QString label(StandardShortcut id)
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
virtual void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
void implicitHeightChanged()
void implicitWidthChanged()
void polish()
QSizeF size() const const
typedef Alignment
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Apr 18 2025 12:13:47 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.