Kirigami2

headerfooterlayout.cpp
1/*
2 * SPDX-FileCopyrightText: 2023 Marco Martin <mart@kde.org>
3 * SPDX-FileCopyrightText: 2023 ivan tkachenko <me@ratijas.tk>
4 *
5 * SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7
8#include "headerfooterlayout.h"
9
10#include <QDebug>
11#include <QTimer>
12
13HeaderFooterLayout::HeaderFooterLayout(QQuickItem *parent)
14 : QQuickItem(parent)
15 , m_isDirty(false)
16 , m_performingLayout(false)
17{
18}
19
20HeaderFooterLayout::~HeaderFooterLayout()
21{
22 disconnectItem(m_header);
23 disconnectItem(m_contentItem);
24 disconnectItem(m_footer);
25};
26
27void HeaderFooterLayout::setHeader(QQuickItem *item)
28{
29 if (m_header == item) {
30 return;
31 }
32
33 if (m_header) {
34 disconnectItem(m_header);
35 m_header->setParentItem(nullptr);
36 }
37
38 m_header = item;
39
40 if (m_header) {
41 m_header->setParentItem(this);
42 if (m_header->z() == 0) {
43 m_header->setZ(1);
44 }
45
46 connect(m_header, &QQuickItem::implicitWidthChanged, this, &HeaderFooterLayout::markAsDirty);
47 connect(m_header, &QQuickItem::implicitHeightChanged, this, &HeaderFooterLayout::markAsDirty);
48 connect(m_header, &QQuickItem::visibleChanged, this, &HeaderFooterLayout::markAsDirty);
49
50 if (m_header->inherits("QQuickTabBar") || m_header->inherits("QQuickToolBar") || m_header->inherits("QQuickDialogButtonBox")) {
51 // Assume 0 is Header for all 3 types
52 m_header->setProperty("position", 0);
53 }
54 }
55
56 markAsDirty();
57
58 Q_EMIT headerChanged();
59}
60
62{
63 return m_header;
64}
65
66void HeaderFooterLayout::setContentItem(QQuickItem *item)
67{
68 if (m_contentItem == item) {
69 return;
70 }
71
72 if (m_contentItem) {
73 disconnectItem(m_contentItem);
74 m_contentItem->setParentItem(nullptr);
75 }
76
77 m_contentItem = item;
78
79 if (m_contentItem) {
80 m_contentItem->setParentItem(this);
81 connect(m_contentItem, &QQuickItem::implicitWidthChanged, this, &HeaderFooterLayout::markAsDirty);
82 connect(m_contentItem, &QQuickItem::implicitHeightChanged, this, &HeaderFooterLayout::markAsDirty);
83 connect(m_contentItem, &QQuickItem::visibleChanged, this, &HeaderFooterLayout::markAsDirty);
84 }
85
86 markAsDirty();
87
88 Q_EMIT contentItemChanged();
89}
90
92{
93 return m_contentItem;
94}
95
96void HeaderFooterLayout::setFooter(QQuickItem *item)
97{
98 if (m_footer == item) {
99 return;
100 }
101
102 if (m_footer) {
103 disconnectItem(m_footer);
104 m_footer->setParentItem(nullptr);
105 }
106
107 m_footer = item;
108
109 if (m_footer) {
110 m_footer->setParentItem(this);
111 if (m_footer->z() == 0) {
112 m_footer->setZ(1);
113 }
114
115 connect(m_footer, &QQuickItem::implicitWidthChanged, this, &HeaderFooterLayout::markAsDirty);
116 connect(m_footer, &QQuickItem::implicitHeightChanged, this, &HeaderFooterLayout::markAsDirty);
117 connect(m_footer, &QQuickItem::visibleChanged, this, &HeaderFooterLayout::markAsDirty);
118
119 if (m_footer->inherits("QQuickTabBar") || m_footer->inherits("QQuickToolBar") || m_footer->inherits("QQuickDialogButtonBox")) {
120 // Assume 1 is Footer for all 3 types
121 m_footer->setProperty("position", 1);
122 }
123 }
124
125 markAsDirty();
126
127 Q_EMIT footerChanged();
128}
129
131{
132 return m_footer;
133}
134
136{
137 updatePolish();
138}
139
140void HeaderFooterLayout::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
141{
142 if (newGeometry != oldGeometry) {
143 markAsDirty();
144 }
145
146 QQuickItem::geometryChange(newGeometry, oldGeometry);
147}
148
149void HeaderFooterLayout::componentComplete()
150{
152 if (m_isDirty) {
153 performLayout();
154 }
155}
156
157void HeaderFooterLayout::updatePolish()
158{
159 if (m_isDirty) {
160 performLayout();
161 }
162}
163
164void HeaderFooterLayout::markAsDirty()
165{
166 if (!m_isDirty) {
167 m_isDirty = true;
168 polish();
169 }
170}
171
172void HeaderFooterLayout::performLayout()
173{
174 if (!isComponentComplete() || m_performingLayout) {
175 return;
176 }
177
178 m_isDirty = false;
179 m_performingLayout = true;
180
181 // Implicit size has to be updated first, as it may propagate to the
182 // actual size which will be used below during layouting.
183 updateImplicitSize();
184
185 const QSizeF newSize = size();
186 qreal headerHeight = 0;
187 qreal footerHeight = 0;
188
189 if (m_header) {
190 m_header->setWidth(newSize.width());
191 if (m_header->isVisible()) {
192 headerHeight = m_header->height();
193 }
194 }
195 if (m_footer) {
196 m_footer->setY(newSize.height() - m_footer->height());
197 m_footer->setWidth(newSize.width());
198 if (m_footer->isVisible()) {
199 footerHeight = m_footer->height();
200 }
201 }
202 if (m_contentItem) {
203 m_contentItem->setY(headerHeight);
204 m_contentItem->setWidth(newSize.width());
205 m_contentItem->setHeight(newSize.height() - headerHeight - footerHeight);
206 }
207
208 m_performingLayout = false;
209}
210
211void HeaderFooterLayout::updateImplicitSize()
212{
213 qreal impWidth = 0;
214 qreal impHeight = 0;
215
216 if (m_header && m_header->isVisible()) {
217 impWidth = std::max(impWidth, m_header->implicitWidth());
218 impHeight += m_header->implicitHeight();
219 }
220 if (m_footer && m_footer->isVisible()) {
221 impWidth = std::max(impWidth, m_footer->implicitWidth());
222 impHeight += m_footer->implicitHeight();
223 }
224 if (m_contentItem && m_contentItem->isVisible()) {
225 impWidth = std::max(impWidth, m_contentItem->implicitWidth());
226 impHeight += m_contentItem->implicitHeight();
227 }
228 setImplicitSize(impWidth, impHeight);
229}
230
231void HeaderFooterLayout::disconnectItem(QQuickItem *item)
232{
233 if (item) {
234 disconnect(item, &QQuickItem::implicitWidthChanged, this, &HeaderFooterLayout::markAsDirty);
235 disconnect(item, &QQuickItem::implicitHeightChanged, this, &HeaderFooterLayout::markAsDirty);
236 disconnect(item, &QQuickItem::visibleChanged, this, &HeaderFooterLayout::markAsDirty);
237 }
238}
239
240#include "moc_headerfooterlayout.cpp"
QQuickItem * footer
This property holds the page footer item.
QML_ELEMENTQQuickItem * header
This property holds the page header item.
Q_INVOKABLE void forceLayout()
HeaderFooterLayout normally positions its header, footer and contentItem once per frame (at polish ev...
QQuickItem * contentItem
This property holds the visual content Item.
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()
bool isComponentComplete() const const
void polish()
QSizeF size() const const
void visibleChanged()
qreal height() const const
qreal width() const const
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.