Kirigami2

padding.cpp
1/*
2 * SPDX-FileCopyrightText: 2023 Marco Martin <mart@kde.org>
3 * SPDX-FileCopyrightText: 2024 Harald Sitter <sitter@kde.org>
4 *
5 * SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7
8#include "padding.h"
9
10#include <QMarginsF>
11#include <qnumeric.h>
12#include <qtypes.h>
13
14class PaddingPrivate
15{
16 Padding *const q;
17
18public:
19 enum Paddings {
20 Left = 1 << 0,
21 Top = 1 << 1,
22 Right = 1 << 2,
23 Bottom = 1 << 3,
24 Horizontal = Left | Right,
25 Vertical = Top | Bottom,
26 All = Horizontal | Vertical
27 };
28
29 PaddingPrivate(Padding *qq)
30 : q(qq)
31 {
32 }
33
34 void calculateImplicitSize();
35 void signalPaddings(const QMarginsF &oldPaddings, Paddings paddings);
36 QMarginsF paddings() const;
37 void disconnect();
38
39 QPointer<QQuickItem> m_contentItem;
40
41 qreal m_padding = 0;
42
43 std::optional<qreal> m_horizontalPadding;
44 std::optional<qreal> m_verticalPadding;
45
46 std::optional<qreal> m_leftPadding;
47 std::optional<qreal> m_topPadding;
48 std::optional<qreal> m_rightPadding;
49 std::optional<qreal> m_bottomPadding;
50};
51
52void PaddingPrivate::calculateImplicitSize()
53{
54 qreal impWidth = 0;
55 qreal impHeight = 0;
56
57 if (m_contentItem) {
58 impWidth += m_contentItem->implicitWidth();
59 impHeight += m_contentItem->implicitHeight();
60 }
61
62 impWidth += q->leftPadding() + q->rightPadding();
63 impHeight += q->topPadding() + q->bottomPadding();
64
65 q->setImplicitSize(impWidth, impHeight);
66}
67
68QMarginsF PaddingPrivate::paddings() const
69{
70 return {q->leftPadding(), q->topPadding(), q->rightPadding(), q->bottomPadding()};
71}
72
73void PaddingPrivate::signalPaddings(const QMarginsF &oldPaddings, Paddings which)
74{
75 if ((which & Left) && !qFuzzyCompare(q->leftPadding(), oldPaddings.left())) {
76 Q_EMIT q->leftPaddingChanged();
77 }
78 if ((which & Top) && !qFuzzyCompare(q->topPadding(), oldPaddings.top())) {
79 Q_EMIT q->topPaddingChanged();
80 }
81 if ((which & Right) && !qFuzzyCompare(q->rightPadding(), oldPaddings.right())) {
82 Q_EMIT q->rightPaddingChanged();
83 }
84 if ((which & Bottom) && !qFuzzyCompare(q->bottomPadding(), oldPaddings.bottom())) {
85 Q_EMIT q->bottomPaddingChanged();
86 }
87 if ((which == Horizontal || which == All)
88 && (!qFuzzyCompare(q->leftPadding(), oldPaddings.left()) || !qFuzzyCompare(q->rightPadding(), oldPaddings.right()))) {
89 Q_EMIT q->horizontalPaddingChanged();
90 }
91 if ((which == Vertical || which == All)
92 && (!qFuzzyCompare(q->topPadding(), oldPaddings.top()) || !qFuzzyCompare(q->bottomPadding(), oldPaddings.bottom()))) {
93 Q_EMIT q->verticalPaddingChanged();
94 }
95 if (!qFuzzyCompare(q->leftPadding() + q->rightPadding(), oldPaddings.left() + oldPaddings.right())) {
96 Q_EMIT q->availableWidthChanged();
97 }
98 if (!qFuzzyCompare(q->topPadding() + q->bottomPadding(), oldPaddings.top() + oldPaddings.bottom())) {
99 Q_EMIT q->availableHeightChanged();
100 }
101}
102
103void PaddingPrivate::disconnect()
104{
105 if (m_contentItem) {
109 QObject::disconnect(m_contentItem, &QQuickItem::implicitWidthChanged, q, &Padding::implicitContentWidthChanged);
110 QObject::disconnect(m_contentItem, &QQuickItem::implicitHeightChanged, q, &Padding::implicitContentHeightChanged);
111 }
112}
113
114Padding::Padding(QQuickItem *parent)
115 : QQuickItem(parent)
116 , d(std::make_unique<PaddingPrivate>(this))
117{
118}
119
120Padding::~Padding()
121{
122 d->disconnect();
123}
124
125void Padding::setContentItem(QQuickItem *item)
126{
127 if (d->m_contentItem == item) {
128 return;
129 }
130
131 // Not unsetting old contentItem's parent unlike Control
132 d->disconnect();
133
134 d->m_contentItem = item;
135
136 if (d->m_contentItem) {
137 d->m_contentItem->setParentItem(this);
138 connect(d->m_contentItem, &QQuickItem::implicitWidthChanged, this, &Padding::polish);
140 connect(d->m_contentItem, &QQuickItem::visibleChanged, this, &Padding::polish);
141 connect(d->m_contentItem, &QQuickItem::implicitWidthChanged, this, &Padding::implicitContentWidthChanged);
142 connect(d->m_contentItem, &QQuickItem::implicitHeightChanged, this, &Padding::implicitContentHeightChanged);
143 }
144
145 polish();
146
147 Q_EMIT contentItemChanged();
148 Q_EMIT implicitContentWidthChanged();
149 Q_EMIT implicitContentWidthChanged();
150}
151
153{
154 return d->m_contentItem;
155}
156
157void Padding::setPadding(qreal padding)
158{
159 if (qFuzzyCompare(padding, d->m_padding)) {
160 return;
161 }
162
163 const QMarginsF oldPadding = d->paddings();
164 d->m_padding = padding;
165
166 Q_EMIT paddingChanged();
167
168 d->signalPaddings(oldPadding, PaddingPrivate::All);
169
170 polish();
171}
172
173void Padding::resetPadding()
174{
175 if (qFuzzyCompare(d->m_padding, 0)) {
176 return;
177 }
178
179 const QMarginsF oldPadding = d->paddings();
180 d->m_padding = 0;
181
182 Q_EMIT paddingChanged();
183
184 d->signalPaddings(oldPadding, PaddingPrivate::All);
185
186 polish();
187}
188
189qreal Padding::padding() const
190{
191 return d->m_padding;
192}
193
194void Padding::setHorizontalPadding(qreal padding)
195{
196 if (qFuzzyCompare(padding, horizontalPadding()) && d->m_horizontalPadding.has_value()) {
197 return;
198 }
199
200 const QMarginsF oldPadding = d->paddings();
201 d->m_horizontalPadding = padding;
202
203 d->signalPaddings(oldPadding, PaddingPrivate::Horizontal);
204
205 polish();
206}
207
208void Padding::resetHorizontalPadding()
209{
210 if (!d->m_horizontalPadding.has_value()) {
211 return;
212 }
213
214 const QMarginsF oldPadding = d->paddings();
215 d->m_horizontalPadding.reset();
216
217 d->signalPaddings(oldPadding, PaddingPrivate::Horizontal);
218
219 polish();
220}
221
222qreal Padding::horizontalPadding() const
223{
224 return d->m_horizontalPadding.value_or(d->m_padding);
225}
226
227void Padding::setVerticalPadding(qreal padding)
228{
229 if (qFuzzyCompare(padding, verticalPadding()) && d->m_verticalPadding.has_value()) {
230 return;
231 }
232
233 const QMarginsF oldPadding = d->paddings();
234 d->m_verticalPadding = padding;
235
236 d->signalPaddings(oldPadding, PaddingPrivate::Vertical);
237
238 polish();
239}
240
241void Padding::resetVerticalPadding()
242{
243 if (!d->m_verticalPadding.has_value()) {
244 return;
245 }
246
247 const QMarginsF oldPadding = d->paddings();
248 d->m_verticalPadding.reset();
249
250 d->signalPaddings(oldPadding, PaddingPrivate::Vertical);
251
252 polish();
253}
254
255qreal Padding::verticalPadding() const
256{
257 return d->m_verticalPadding.value_or(d->m_padding);
258}
259
260void Padding::setLeftPadding(qreal padding)
261{
262 const QMarginsF oldPadding = d->paddings();
263 if (qFuzzyCompare(padding, oldPadding.left()) && d->m_leftPadding.has_value()) {
264 return;
265 }
266
267 d->m_leftPadding = padding;
268
269 d->signalPaddings(oldPadding, PaddingPrivate::Left);
270
271 polish();
272}
273
274void Padding::resetLeftPadding()
275{
276 if (!d->m_leftPadding.has_value()) {
277 return;
278 }
279
280 const QMarginsF oldPadding = d->paddings();
281 d->m_leftPadding.reset();
282
283 d->signalPaddings(oldPadding, PaddingPrivate::Left);
284
285 polish();
286}
287
288qreal Padding::leftPadding() const
289{
290 if (d->m_leftPadding.has_value()) {
291 return d->m_leftPadding.value();
292 } else {
293 return horizontalPadding();
294 }
295}
296
297void Padding::setTopPadding(qreal padding)
298{
299 const QMarginsF oldPadding = d->paddings();
300 if (qFuzzyCompare(padding, oldPadding.top()) && d->m_topPadding.has_value()) {
301 return;
302 }
303
304 d->m_topPadding = padding;
305
306 d->signalPaddings(oldPadding, PaddingPrivate::Top);
307
308 polish();
309}
310
311void Padding::resetTopPadding()
312{
313 if (!d->m_topPadding.has_value()) {
314 return;
315 }
316
317 const QMarginsF oldPadding = d->paddings();
318 d->m_topPadding.reset();
319
320 d->signalPaddings(oldPadding, PaddingPrivate::Top);
321
322 polish();
323}
324
325qreal Padding::topPadding() const
326{
327 if (d->m_topPadding.has_value()) {
328 return d->m_topPadding.value();
329 } else {
330 return verticalPadding();
331 }
332}
333
334void Padding::setRightPadding(qreal padding)
335{
336 const QMarginsF oldPadding = d->paddings();
337 if (qFuzzyCompare(padding, oldPadding.right()) && d->m_rightPadding.has_value()) {
338 return;
339 }
340
341 d->m_rightPadding = padding;
342
343 d->signalPaddings(oldPadding, PaddingPrivate::Right);
344
345 polish();
346}
347
348void Padding::resetRightPadding()
349{
350 if (!d->m_rightPadding.has_value()) {
351 return;
352 }
353
354 const QMarginsF oldPadding = d->paddings();
355 d->m_rightPadding.reset();
356
357 d->signalPaddings(oldPadding, PaddingPrivate::Right);
358
359 polish();
360}
361
362qreal Padding::rightPadding() const
363{
364 if (d->m_rightPadding.has_value()) {
365 return d->m_rightPadding.value();
366 } else {
367 return horizontalPadding();
368 }
369}
370
371void Padding::setBottomPadding(qreal padding)
372{
373 const QMarginsF oldPadding = d->paddings();
374 if (qFuzzyCompare(padding, oldPadding.bottom()) && d->m_bottomPadding.has_value()) {
375 return;
376 }
377
378 d->m_bottomPadding = padding;
379
380 d->signalPaddings(oldPadding, PaddingPrivate::Bottom);
381
382 polish();
383}
384
385void Padding::resetBottomPadding()
386{
387 if (!d->m_bottomPadding.has_value()) {
388 return;
389 }
390
391 const QMarginsF oldPadding = d->paddings();
392 d->m_bottomPadding.reset();
393
394 d->signalPaddings(oldPadding, PaddingPrivate::Bottom);
395
396 polish();
397}
398
399qreal Padding::bottomPadding() const
400{
401 if (d->m_bottomPadding.has_value()) {
402 return d->m_bottomPadding.value();
403 } else {
404 return verticalPadding();
405 }
406}
407
408qreal Padding::availableWidth() const
409{
410 return width() - leftPadding() - rightPadding();
411}
412
413qreal Padding::availableHeight() const
414{
415 return height() - topPadding() - bottomPadding();
416}
417
419{
420 if (d->m_contentItem) {
421 return d->m_contentItem->implicitWidth();
422 } else {
423 return 0.0;
424 }
425}
426
428{
429 if (d->m_contentItem) {
430 return d->m_contentItem->implicitHeight();
431 } else {
432 return 0.0;
433 }
434}
435
436void Padding::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
437{
438 if (newGeometry != oldGeometry) {
439 Q_EMIT availableWidthChanged();
440 Q_EMIT availableHeightChanged();
441 polish();
442 }
443
444 QQuickItem::geometryChange(newGeometry, oldGeometry);
445}
446
447void Padding::updatePolish()
448{
449 d->calculateImplicitSize();
450 if (!d->m_contentItem) {
451 return;
452 }
453
454 d->m_contentItem->setPosition(QPointF(leftPadding(), topPadding()));
455 d->m_contentItem->setSize(QSizeF(availableWidth(), availableHeight()));
456}
457
458void Padding::componentComplete()
459{
461 // This is important! We must have a geometry so our parents can lay out.
462 updatePolish();
463}
464
465#include "moc_padding.cpp"
This item simply adds an external padding to contentItem's size.
Definition padding.h:61
qreal rightPadding
This property holds the padding on the right side.
Definition padding.h:119
qreal bottomPadding
This property holds the padding on the bottom side.
Definition padding.h:126
qreal implicitContentWidth
The implicitWidth of its contentItem, or 0 if not present.
Definition padding.h:141
qreal verticalPadding
This property holds the vertical padding.
Definition padding.h:96
qreal leftPadding
This property holds the padding on the left side.
Definition padding.h:104
qreal availableHeight
The height available to the contentItem after deducting vertical padding from the width of the Paddin...
Definition padding.h:136
qreal padding
This property holds the default padding.
Definition padding.h:82
qreal topPadding
the padding on the top side.
Definition padding.h:111
qreal horizontalPadding
This property holds the horizontal padding.
Definition padding.h:89
QML_ELEMENTQQuickItem * contentItem
This property holds the visual content Item.
Definition padding.h:70
qreal implicitContentHeight
The implicitHeight of its contentItem, or 0 if not present.
Definition padding.h:146
qreal availableWidth
The width available to the contentItem after deducting horizontal padding from the width of the Paddi...
Definition padding.h:131
qreal bottom() const const
qreal left() const const
qreal right() const const
qreal top() const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
virtual void componentComplete() override
virtual void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
void implicitHeightChanged()
void implicitWidthChanged()
void polish()
void visibleChanged()
Vertical
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:18:46 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.