File indexing completed on 2024-04-21 03:55:59
0001 /* 0002 * SPDX-FileCopyrightText: 2023 Marco Martin <mart@kde.org> 0003 * SPDX-FileCopyrightText: 2023 ivan tkachenko <me@ratijas.tk> 0004 * 0005 * SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "headerfooterlayout.h" 0009 0010 #include <QDebug> 0011 #include <QTimer> 0012 0013 HeaderFooterLayout::HeaderFooterLayout(QQuickItem *parent) 0014 : QQuickItem(parent) 0015 , m_isDirty(false) 0016 , m_performingLayout(false) 0017 { 0018 } 0019 0020 HeaderFooterLayout::~HeaderFooterLayout() 0021 { 0022 disconnectItem(m_header); 0023 disconnectItem(m_contentItem); 0024 disconnectItem(m_footer); 0025 }; 0026 0027 void HeaderFooterLayout::setHeader(QQuickItem *item) 0028 { 0029 if (m_header == item) { 0030 return; 0031 } 0032 0033 if (m_header) { 0034 disconnectItem(m_header); 0035 m_header->setParentItem(nullptr); 0036 } 0037 0038 m_header = item; 0039 0040 if (m_header) { 0041 m_header->setParentItem(this); 0042 if (m_header->z() == 0) { 0043 m_header->setZ(1); 0044 } 0045 0046 connect(m_header, &QQuickItem::implicitWidthChanged, this, &HeaderFooterLayout::markAsDirty); 0047 connect(m_header, &QQuickItem::implicitHeightChanged, this, &HeaderFooterLayout::markAsDirty); 0048 connect(m_header, &QQuickItem::visibleChanged, this, &HeaderFooterLayout::markAsDirty); 0049 0050 if (m_header->inherits("QQuickTabBar") || m_header->inherits("QQuickToolBar") || m_header->inherits("QQuickDialogButtonBox")) { 0051 // Assume 0 is Header for all 3 types 0052 m_header->setProperty("position", 0); 0053 } 0054 } 0055 0056 markAsDirty(); 0057 0058 Q_EMIT headerChanged(); 0059 } 0060 0061 QQuickItem *HeaderFooterLayout::header() 0062 { 0063 return m_header; 0064 } 0065 0066 void HeaderFooterLayout::setContentItem(QQuickItem *item) 0067 { 0068 if (m_contentItem == item) { 0069 return; 0070 } 0071 0072 if (m_contentItem) { 0073 disconnectItem(m_contentItem); 0074 m_contentItem->setParentItem(nullptr); 0075 } 0076 0077 m_contentItem = item; 0078 0079 if (m_contentItem) { 0080 m_contentItem->setParentItem(this); 0081 connect(m_contentItem, &QQuickItem::implicitWidthChanged, this, &HeaderFooterLayout::markAsDirty); 0082 connect(m_contentItem, &QQuickItem::implicitHeightChanged, this, &HeaderFooterLayout::markAsDirty); 0083 connect(m_contentItem, &QQuickItem::visibleChanged, this, &HeaderFooterLayout::markAsDirty); 0084 } 0085 0086 markAsDirty(); 0087 0088 Q_EMIT contentItemChanged(); 0089 } 0090 0091 QQuickItem *HeaderFooterLayout::contentItem() 0092 { 0093 return m_contentItem; 0094 } 0095 0096 void HeaderFooterLayout::setFooter(QQuickItem *item) 0097 { 0098 if (m_footer == item) { 0099 return; 0100 } 0101 0102 if (m_footer) { 0103 disconnectItem(m_footer); 0104 m_footer->setParentItem(nullptr); 0105 } 0106 0107 m_footer = item; 0108 0109 if (m_footer) { 0110 m_footer->setParentItem(this); 0111 if (m_footer->z() == 0) { 0112 m_footer->setZ(1); 0113 } 0114 0115 connect(m_footer, &QQuickItem::implicitWidthChanged, this, &HeaderFooterLayout::markAsDirty); 0116 connect(m_footer, &QQuickItem::implicitHeightChanged, this, &HeaderFooterLayout::markAsDirty); 0117 connect(m_footer, &QQuickItem::visibleChanged, this, &HeaderFooterLayout::markAsDirty); 0118 0119 if (m_footer->inherits("QQuickTabBar") || m_footer->inherits("QQuickToolBar") || m_footer->inherits("QQuickDialogButtonBox")) { 0120 // Assume 1 is Footer for all 3 types 0121 m_footer->setProperty("position", 1); 0122 } 0123 } 0124 0125 markAsDirty(); 0126 0127 Q_EMIT footerChanged(); 0128 } 0129 0130 QQuickItem *HeaderFooterLayout::footer() 0131 { 0132 return m_footer; 0133 } 0134 0135 void HeaderFooterLayout::forceLayout() 0136 { 0137 updatePolish(); 0138 } 0139 0140 void HeaderFooterLayout::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) 0141 { 0142 if (newGeometry != oldGeometry) { 0143 markAsDirty(); 0144 } 0145 0146 QQuickItem::geometryChange(newGeometry, oldGeometry); 0147 } 0148 0149 void HeaderFooterLayout::componentComplete() 0150 { 0151 QQuickItem::componentComplete(); 0152 if (m_isDirty) { 0153 performLayout(); 0154 } 0155 } 0156 0157 void HeaderFooterLayout::updatePolish() 0158 { 0159 if (m_isDirty) { 0160 performLayout(); 0161 } 0162 } 0163 0164 void HeaderFooterLayout::markAsDirty() 0165 { 0166 if (!m_isDirty) { 0167 m_isDirty = true; 0168 polish(); 0169 } 0170 } 0171 0172 void HeaderFooterLayout::performLayout() 0173 { 0174 if (!isComponentComplete() || m_performingLayout) { 0175 return; 0176 } 0177 0178 m_isDirty = false; 0179 m_performingLayout = true; 0180 0181 // Implicit size has to be updated first, as it may propagate to the 0182 // actual size which will be used below during layouting. 0183 updateImplicitSize(); 0184 0185 const QSizeF newSize = size(); 0186 qreal headerHeight = 0; 0187 qreal footerHeight = 0; 0188 0189 if (m_header) { 0190 m_header->setWidth(newSize.width()); 0191 if (m_header->isVisible()) { 0192 headerHeight = m_header->height(); 0193 } 0194 } 0195 if (m_footer) { 0196 m_footer->setY(newSize.height() - m_footer->height()); 0197 m_footer->setWidth(newSize.width()); 0198 if (m_footer->isVisible()) { 0199 footerHeight = m_footer->height(); 0200 } 0201 } 0202 if (m_contentItem) { 0203 m_contentItem->setY(headerHeight); 0204 m_contentItem->setWidth(newSize.width()); 0205 m_contentItem->setHeight(newSize.height() - headerHeight - footerHeight); 0206 } 0207 0208 m_performingLayout = false; 0209 } 0210 0211 void HeaderFooterLayout::updateImplicitSize() 0212 { 0213 qreal impWidth = 0; 0214 qreal impHeight = 0; 0215 0216 if (m_header && m_header->isVisible()) { 0217 impWidth = std::max(impWidth, m_header->implicitWidth()); 0218 impHeight += m_header->implicitHeight(); 0219 } 0220 if (m_footer && m_footer->isVisible()) { 0221 impWidth = std::max(impWidth, m_footer->implicitWidth()); 0222 impHeight += m_footer->implicitHeight(); 0223 } 0224 if (m_contentItem && m_contentItem->isVisible()) { 0225 impWidth = std::max(impWidth, m_contentItem->implicitWidth()); 0226 impHeight += m_contentItem->implicitHeight(); 0227 } 0228 setImplicitSize(impWidth, impHeight); 0229 } 0230 0231 void HeaderFooterLayout::disconnectItem(QQuickItem *item) 0232 { 0233 if (item) { 0234 disconnect(item, &QQuickItem::implicitWidthChanged, this, &HeaderFooterLayout::markAsDirty); 0235 disconnect(item, &QQuickItem::implicitHeightChanged, this, &HeaderFooterLayout::markAsDirty); 0236 disconnect(item, &QQuickItem::visibleChanged, this, &HeaderFooterLayout::markAsDirty); 0237 } 0238 } 0239 0240 #include "moc_headerfooterlayout.cpp"