File indexing completed on 2024-04-21 03:56:01
0001 /* 0002 * SPDX-FileCopyrightText: 2023 Marco Martin <mart@kde.org> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "padding.h" 0008 0009 #include <QMarginsF> 0010 #include <qnumeric.h> 0011 #include <qtypes.h> 0012 0013 class PaddingPrivate 0014 { 0015 Padding *const q; 0016 0017 public: 0018 enum Paddings { 0019 Left = 1 << 0, 0020 Top = 1 << 1, 0021 Right = 1 << 2, 0022 Bottom = 1 << 3, 0023 Horizontal = Left | Right, 0024 Vertical = Top | Bottom, 0025 All = Horizontal | Vertical 0026 }; 0027 0028 PaddingPrivate(Padding *qq) 0029 : q(qq) 0030 { 0031 } 0032 0033 void calculateImplicitSize(); 0034 void signalPaddings(const QMarginsF &oldPaddings, Paddings paddings); 0035 QMarginsF paddings() const; 0036 void disconnect(); 0037 0038 QPointer<QQuickItem> m_contentItem; 0039 0040 qreal m_padding = 0; 0041 0042 std::optional<qreal> m_horizontalPadding; 0043 std::optional<qreal> m_verticalPadding; 0044 0045 std::optional<qreal> m_leftPadding; 0046 std::optional<qreal> m_topPadding; 0047 std::optional<qreal> m_rightPadding; 0048 std::optional<qreal> m_bottomPadding; 0049 }; 0050 0051 void PaddingPrivate::calculateImplicitSize() 0052 { 0053 qreal impWidth = 0; 0054 qreal impHeight = 0; 0055 0056 if (m_contentItem) { 0057 impWidth += m_contentItem->implicitWidth(); 0058 impHeight += m_contentItem->implicitHeight(); 0059 } 0060 0061 impWidth += q->leftPadding() + q->rightPadding(); 0062 impHeight += q->topPadding() + q->bottomPadding(); 0063 0064 q->setImplicitSize(impWidth, impHeight); 0065 } 0066 0067 QMarginsF PaddingPrivate::paddings() const 0068 { 0069 return {q->leftPadding(), q->topPadding(), q->rightPadding(), q->bottomPadding()}; 0070 } 0071 0072 void PaddingPrivate::signalPaddings(const QMarginsF &oldPaddings, Paddings which) 0073 { 0074 if ((which & Left) && !qFuzzyCompare(q->leftPadding(), oldPaddings.left())) { 0075 Q_EMIT q->leftPaddingChanged(); 0076 } 0077 if ((which & Top) && !qFuzzyCompare(q->topPadding(), oldPaddings.top())) { 0078 Q_EMIT q->topPaddingChanged(); 0079 } 0080 if ((which & Right) && !qFuzzyCompare(q->rightPadding(), oldPaddings.right())) { 0081 Q_EMIT q->rightPaddingChanged(); 0082 } 0083 if ((which & Bottom) && !qFuzzyCompare(q->bottomPadding(), oldPaddings.bottom())) { 0084 Q_EMIT q->bottomPaddingChanged(); 0085 } 0086 if ((which == Horizontal || which == All) 0087 && (!qFuzzyCompare(q->leftPadding(), oldPaddings.left()) || !qFuzzyCompare(q->rightPadding(), oldPaddings.right()))) { 0088 Q_EMIT q->horizontalPaddingChanged(); 0089 } 0090 if ((which == Vertical || which == All) 0091 && (!qFuzzyCompare(q->topPadding(), oldPaddings.top()) || !qFuzzyCompare(q->bottomPadding(), oldPaddings.bottom()))) { 0092 Q_EMIT q->verticalPaddingChanged(); 0093 } 0094 if (!qFuzzyCompare(q->leftPadding() + q->rightPadding(), oldPaddings.left() + oldPaddings.right())) { 0095 Q_EMIT q->availableWidthChanged(); 0096 } 0097 if (!qFuzzyCompare(q->topPadding() + q->bottomPadding(), oldPaddings.top() + oldPaddings.bottom())) { 0098 Q_EMIT q->availableHeightChanged(); 0099 } 0100 } 0101 0102 void PaddingPrivate::disconnect() 0103 { 0104 if (m_contentItem) { 0105 QObject::disconnect(m_contentItem, &QQuickItem::implicitWidthChanged, q, &Padding::polish); 0106 QObject::disconnect(m_contentItem, &QQuickItem::implicitHeightChanged, q, &Padding::polish); 0107 QObject::disconnect(m_contentItem, &QQuickItem::visibleChanged, q, &Padding::polish); 0108 QObject::disconnect(m_contentItem, &QQuickItem::implicitWidthChanged, q, &Padding::implicitContentWidthChanged); 0109 QObject::disconnect(m_contentItem, &QQuickItem::implicitHeightChanged, q, &Padding::implicitContentHeightChanged); 0110 } 0111 } 0112 0113 Padding::Padding(QQuickItem *parent) 0114 : QQuickItem(parent) 0115 , d(std::make_unique<PaddingPrivate>(this)) 0116 { 0117 } 0118 0119 Padding::~Padding() 0120 { 0121 d->disconnect(); 0122 } 0123 0124 void Padding::setContentItem(QQuickItem *item) 0125 { 0126 if (d->m_contentItem == item) { 0127 return; 0128 } 0129 0130 // Not unsetting old contentItem's parent unlike Control 0131 d->disconnect(); 0132 0133 d->m_contentItem = item; 0134 0135 if (d->m_contentItem) { 0136 d->m_contentItem->setParentItem(this); 0137 connect(d->m_contentItem, &QQuickItem::implicitWidthChanged, this, &Padding::polish); 0138 connect(d->m_contentItem, &QQuickItem::implicitHeightChanged, this, &Padding::polish); 0139 connect(d->m_contentItem, &QQuickItem::visibleChanged, this, &Padding::polish); 0140 connect(d->m_contentItem, &QQuickItem::implicitWidthChanged, this, &Padding::implicitContentWidthChanged); 0141 connect(d->m_contentItem, &QQuickItem::implicitHeightChanged, this, &Padding::implicitContentHeightChanged); 0142 } 0143 0144 polish(); 0145 0146 Q_EMIT contentItemChanged(); 0147 Q_EMIT implicitContentWidthChanged(); 0148 Q_EMIT implicitContentWidthChanged(); 0149 } 0150 0151 QQuickItem *Padding::contentItem() 0152 { 0153 return d->m_contentItem; 0154 } 0155 0156 void Padding::setPadding(qreal padding) 0157 { 0158 if (qFuzzyCompare(padding, d->m_padding)) { 0159 return; 0160 } 0161 0162 const QMarginsF oldPadding = d->paddings(); 0163 d->m_padding = padding; 0164 0165 Q_EMIT paddingChanged(); 0166 0167 d->signalPaddings(oldPadding, PaddingPrivate::All); 0168 0169 polish(); 0170 } 0171 0172 void Padding::resetPadding() 0173 { 0174 if (qFuzzyCompare(d->m_padding, 0)) { 0175 return; 0176 } 0177 0178 const QMarginsF oldPadding = d->paddings(); 0179 d->m_padding = 0; 0180 0181 Q_EMIT paddingChanged(); 0182 0183 d->signalPaddings(oldPadding, PaddingPrivate::All); 0184 0185 polish(); 0186 } 0187 0188 qreal Padding::padding() const 0189 { 0190 return d->m_padding; 0191 } 0192 0193 void Padding::setHorizontalPadding(qreal padding) 0194 { 0195 if (qFuzzyCompare(padding, horizontalPadding()) && d->m_horizontalPadding.has_value()) { 0196 return; 0197 } 0198 0199 const QMarginsF oldPadding = d->paddings(); 0200 d->m_horizontalPadding = padding; 0201 0202 d->signalPaddings(oldPadding, PaddingPrivate::Horizontal); 0203 0204 polish(); 0205 } 0206 0207 void Padding::resetHorizontalPadding() 0208 { 0209 if (!d->m_horizontalPadding.has_value()) { 0210 return; 0211 } 0212 0213 const QMarginsF oldPadding = d->paddings(); 0214 d->m_horizontalPadding.reset(); 0215 0216 d->signalPaddings(oldPadding, PaddingPrivate::Horizontal); 0217 0218 polish(); 0219 } 0220 0221 qreal Padding::horizontalPadding() const 0222 { 0223 return d->m_horizontalPadding.value_or(d->m_padding); 0224 } 0225 0226 void Padding::setVerticalPadding(qreal padding) 0227 { 0228 if (qFuzzyCompare(padding, verticalPadding()) && d->m_verticalPadding.has_value()) { 0229 return; 0230 } 0231 0232 const QMarginsF oldPadding = d->paddings(); 0233 d->m_verticalPadding = padding; 0234 0235 d->signalPaddings(oldPadding, PaddingPrivate::Vertical); 0236 0237 polish(); 0238 } 0239 0240 void Padding::resetVerticalPadding() 0241 { 0242 if (!d->m_verticalPadding.has_value()) { 0243 return; 0244 } 0245 0246 const QMarginsF oldPadding = d->paddings(); 0247 d->m_verticalPadding.reset(); 0248 0249 d->signalPaddings(oldPadding, PaddingPrivate::Vertical); 0250 0251 polish(); 0252 } 0253 0254 qreal Padding::verticalPadding() const 0255 { 0256 return d->m_verticalPadding.value_or(d->m_padding); 0257 } 0258 0259 void Padding::setLeftPadding(qreal padding) 0260 { 0261 const QMarginsF oldPadding = d->paddings(); 0262 if (qFuzzyCompare(padding, oldPadding.left()) && d->m_leftPadding.has_value()) { 0263 return; 0264 } 0265 0266 d->m_leftPadding = padding; 0267 0268 d->signalPaddings(oldPadding, PaddingPrivate::Left); 0269 0270 polish(); 0271 } 0272 0273 void Padding::resetLeftPadding() 0274 { 0275 if (!d->m_leftPadding.has_value()) { 0276 return; 0277 } 0278 0279 const QMarginsF oldPadding = d->paddings(); 0280 d->m_leftPadding.reset(); 0281 0282 d->signalPaddings(oldPadding, PaddingPrivate::Left); 0283 0284 polish(); 0285 } 0286 0287 qreal Padding::leftPadding() const 0288 { 0289 if (d->m_leftPadding.has_value()) { 0290 return d->m_leftPadding.value(); 0291 } else { 0292 return horizontalPadding(); 0293 } 0294 } 0295 0296 void Padding::setTopPadding(qreal padding) 0297 { 0298 const QMarginsF oldPadding = d->paddings(); 0299 if (qFuzzyCompare(padding, oldPadding.top()) && d->m_topPadding.has_value()) { 0300 return; 0301 } 0302 0303 d->m_topPadding = padding; 0304 0305 d->signalPaddings(oldPadding, PaddingPrivate::Top); 0306 0307 polish(); 0308 } 0309 0310 void Padding::resetTopPadding() 0311 { 0312 if (!d->m_topPadding.has_value()) { 0313 return; 0314 } 0315 0316 const QMarginsF oldPadding = d->paddings(); 0317 d->m_topPadding.reset(); 0318 0319 d->signalPaddings(oldPadding, PaddingPrivate::Top); 0320 0321 polish(); 0322 } 0323 0324 qreal Padding::topPadding() const 0325 { 0326 if (d->m_topPadding.has_value()) { 0327 return d->m_topPadding.value(); 0328 } else { 0329 return verticalPadding(); 0330 } 0331 } 0332 0333 void Padding::setRightPadding(qreal padding) 0334 { 0335 const QMarginsF oldPadding = d->paddings(); 0336 if (qFuzzyCompare(padding, oldPadding.right()) && d->m_rightPadding.has_value()) { 0337 return; 0338 } 0339 0340 d->m_rightPadding = padding; 0341 0342 d->signalPaddings(oldPadding, PaddingPrivate::Right); 0343 0344 polish(); 0345 } 0346 0347 void Padding::resetRightPadding() 0348 { 0349 if (!d->m_rightPadding.has_value()) { 0350 return; 0351 } 0352 0353 const QMarginsF oldPadding = d->paddings(); 0354 d->m_rightPadding.reset(); 0355 0356 d->signalPaddings(oldPadding, PaddingPrivate::Right); 0357 0358 polish(); 0359 } 0360 0361 qreal Padding::rightPadding() const 0362 { 0363 if (d->m_rightPadding.has_value()) { 0364 return d->m_rightPadding.value(); 0365 } else { 0366 return horizontalPadding(); 0367 } 0368 } 0369 0370 void Padding::setBottomPadding(qreal padding) 0371 { 0372 const QMarginsF oldPadding = d->paddings(); 0373 if (qFuzzyCompare(padding, oldPadding.bottom()) && d->m_bottomPadding.has_value()) { 0374 return; 0375 } 0376 0377 d->m_bottomPadding = padding; 0378 0379 d->signalPaddings(oldPadding, PaddingPrivate::Bottom); 0380 0381 polish(); 0382 } 0383 0384 void Padding::resetBottomPadding() 0385 { 0386 if (!d->m_bottomPadding.has_value()) { 0387 return; 0388 } 0389 0390 const QMarginsF oldPadding = d->paddings(); 0391 d->m_bottomPadding.reset(); 0392 0393 d->signalPaddings(oldPadding, PaddingPrivate::Bottom); 0394 0395 polish(); 0396 } 0397 0398 qreal Padding::bottomPadding() const 0399 { 0400 if (d->m_bottomPadding.has_value()) { 0401 return d->m_bottomPadding.value(); 0402 } else { 0403 return verticalPadding(); 0404 } 0405 } 0406 0407 qreal Padding::availableWidth() const 0408 { 0409 return width() - leftPadding() - rightPadding(); 0410 } 0411 0412 qreal Padding::availableHeight() const 0413 { 0414 return height() - topPadding() - bottomPadding(); 0415 } 0416 0417 qreal Padding::implicitContentWidth() const 0418 { 0419 if (d->m_contentItem) { 0420 return d->m_contentItem->implicitWidth(); 0421 } else { 0422 return 0.0; 0423 } 0424 } 0425 0426 qreal Padding::implicitContentHeight() const 0427 { 0428 if (d->m_contentItem) { 0429 return d->m_contentItem->implicitHeight(); 0430 } else { 0431 return 0.0; 0432 } 0433 } 0434 0435 void Padding::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) 0436 { 0437 if (newGeometry != oldGeometry) { 0438 Q_EMIT availableWidthChanged(); 0439 Q_EMIT availableHeightChanged(); 0440 polish(); 0441 } 0442 0443 QQuickItem::geometryChange(newGeometry, oldGeometry); 0444 } 0445 0446 void Padding::updatePolish() 0447 { 0448 d->calculateImplicitSize(); 0449 if (!d->m_contentItem) { 0450 return; 0451 } 0452 0453 d->m_contentItem->setPosition(QPointF(leftPadding(), topPadding())); 0454 d->m_contentItem->setSize(QSizeF(availableWidth(), availableHeight())); 0455 } 0456 0457 #include "moc_padding.cpp"