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 | |
13 | HeaderFooterLayout::(QQuickItem *parent) |
14 | : QQuickItem(parent) |
15 | , m_isDirty(false) |
16 | , m_performingLayout(false) |
17 | { |
18 | } |
19 | |
20 | HeaderFooterLayout::() |
21 | { |
22 | disconnectItem(item: m_header); |
23 | disconnectItem(item: m_contentItem); |
24 | disconnectItem(item: m_footer); |
25 | }; |
26 | |
27 | void HeaderFooterLayout::(QQuickItem *item) |
28 | { |
29 | if (m_header == item) { |
30 | return; |
31 | } |
32 | |
33 | if (m_header) { |
34 | disconnectItem(item: 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(sender: m_header, signal: &QQuickItem::implicitWidthChanged, context: this, slot: &HeaderFooterLayout::markAsDirty); |
47 | connect(sender: m_header, signal: &QQuickItem::implicitHeightChanged, context: this, slot: &HeaderFooterLayout::markAsDirty); |
48 | connect(sender: m_header, signal: &QQuickItem::visibleChanged, context: this, slot: &HeaderFooterLayout::markAsDirty); |
49 | |
50 | if (m_header->inherits(classname: "QQuickTabBar" ) || m_header->inherits(classname: "QQuickToolBar" ) || m_header->inherits(classname: "QQuickDialogButtonBox" )) { |
51 | // Assume 0 is Header for all 3 types |
52 | m_header->setProperty(name: "position" , value: 0); |
53 | } |
54 | } |
55 | |
56 | markAsDirty(); |
57 | |
58 | Q_EMIT headerChanged(); |
59 | } |
60 | |
61 | QQuickItem *HeaderFooterLayout::() |
62 | { |
63 | return m_header; |
64 | } |
65 | |
66 | void HeaderFooterLayout::(QQuickItem *item) |
67 | { |
68 | if (m_contentItem == item) { |
69 | return; |
70 | } |
71 | |
72 | if (m_contentItem) { |
73 | disconnectItem(item: 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(sender: m_contentItem, signal: &QQuickItem::implicitWidthChanged, context: this, slot: &HeaderFooterLayout::markAsDirty); |
82 | connect(sender: m_contentItem, signal: &QQuickItem::implicitHeightChanged, context: this, slot: &HeaderFooterLayout::markAsDirty); |
83 | connect(sender: m_contentItem, signal: &QQuickItem::visibleChanged, context: this, slot: &HeaderFooterLayout::markAsDirty); |
84 | } |
85 | |
86 | markAsDirty(); |
87 | |
88 | Q_EMIT contentItemChanged(); |
89 | } |
90 | |
91 | QQuickItem *HeaderFooterLayout::() |
92 | { |
93 | return m_contentItem; |
94 | } |
95 | |
96 | void HeaderFooterLayout::(QQuickItem *item) |
97 | { |
98 | if (m_footer == item) { |
99 | return; |
100 | } |
101 | |
102 | if (m_footer) { |
103 | disconnectItem(item: 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(sender: m_footer, signal: &QQuickItem::implicitWidthChanged, context: this, slot: &HeaderFooterLayout::markAsDirty); |
116 | connect(sender: m_footer, signal: &QQuickItem::implicitHeightChanged, context: this, slot: &HeaderFooterLayout::markAsDirty); |
117 | connect(sender: m_footer, signal: &QQuickItem::visibleChanged, context: this, slot: &HeaderFooterLayout::markAsDirty); |
118 | |
119 | if (m_footer->inherits(classname: "QQuickTabBar" ) || m_footer->inherits(classname: "QQuickToolBar" ) || m_footer->inherits(classname: "QQuickDialogButtonBox" )) { |
120 | // Assume 1 is Footer for all 3 types |
121 | m_footer->setProperty(name: "position" , value: 1); |
122 | } |
123 | } |
124 | |
125 | markAsDirty(); |
126 | |
127 | Q_EMIT footerChanged(); |
128 | } |
129 | |
130 | QQuickItem *HeaderFooterLayout::() |
131 | { |
132 | return m_footer; |
133 | } |
134 | |
135 | void HeaderFooterLayout::(qreal spacing) |
136 | { |
137 | if (spacing == m_spacing) { |
138 | return; |
139 | } |
140 | |
141 | m_spacing = spacing; |
142 | |
143 | markAsDirty(); |
144 | |
145 | Q_EMIT spacingChanged(); |
146 | } |
147 | |
148 | qreal HeaderFooterLayout::() const |
149 | { |
150 | return m_spacing; |
151 | } |
152 | |
153 | void HeaderFooterLayout::() |
154 | { |
155 | updatePolish(); |
156 | } |
157 | |
158 | void HeaderFooterLayout::(const QRectF &newGeometry, const QRectF &oldGeometry) |
159 | { |
160 | if (newGeometry != oldGeometry) { |
161 | markAsDirty(); |
162 | } |
163 | |
164 | QQuickItem::geometryChange(newGeometry, oldGeometry); |
165 | } |
166 | |
167 | void HeaderFooterLayout::() |
168 | { |
169 | QQuickItem::componentComplete(); |
170 | if (m_isDirty) { |
171 | performLayout(); |
172 | } |
173 | } |
174 | |
175 | void HeaderFooterLayout::() |
176 | { |
177 | if (m_isDirty) { |
178 | performLayout(); |
179 | } |
180 | } |
181 | |
182 | void HeaderFooterLayout::() |
183 | { |
184 | if (!m_isDirty) { |
185 | m_isDirty = true; |
186 | polish(); |
187 | } |
188 | } |
189 | |
190 | void HeaderFooterLayout::() |
191 | { |
192 | if (!isComponentComplete() || m_performingLayout) { |
193 | return; |
194 | } |
195 | |
196 | m_isDirty = false; |
197 | m_performingLayout = true; |
198 | |
199 | // Implicit size has to be updated first, as it may propagate to the |
200 | // actual size which will be used below during layouting. |
201 | updateImplicitSize(); |
202 | |
203 | const QSizeF newSize = size(); |
204 | qreal = 0; |
205 | qreal = 0; |
206 | |
207 | if (m_header) { |
208 | m_header->setWidth(newSize.width()); |
209 | if (m_header->isVisible()) { |
210 | headerHeight = m_header->height() + m_spacing; |
211 | } |
212 | } |
213 | if (m_footer) { |
214 | m_footer->setY(newSize.height() - m_footer->height()); |
215 | m_footer->setWidth(newSize.width()); |
216 | if (m_footer->isVisible()) { |
217 | footerHeight = m_footer->height() + m_spacing; |
218 | } |
219 | } |
220 | if (m_contentItem) { |
221 | m_contentItem->setY(headerHeight); |
222 | m_contentItem->setWidth(newSize.width()); |
223 | m_contentItem->setHeight(newSize.height() - headerHeight - footerHeight); |
224 | } |
225 | |
226 | m_performingLayout = false; |
227 | } |
228 | |
229 | void HeaderFooterLayout::() |
230 | { |
231 | qreal impWidth = 0; |
232 | qreal impHeight = 0; |
233 | |
234 | if (m_header && m_header->isVisible()) { |
235 | impWidth = std::max(a: impWidth, b: m_header->implicitWidth()); |
236 | impHeight += m_header->implicitHeight() + m_spacing; |
237 | } |
238 | if (m_footer && m_footer->isVisible()) { |
239 | impWidth = std::max(a: impWidth, b: m_footer->implicitWidth()); |
240 | impHeight += m_footer->implicitHeight() + m_spacing; |
241 | } |
242 | if (m_contentItem && m_contentItem->isVisible()) { |
243 | impWidth = std::max(a: impWidth, b: m_contentItem->implicitWidth()); |
244 | impHeight += m_contentItem->implicitHeight(); |
245 | } |
246 | setImplicitSize(impWidth, impHeight); |
247 | } |
248 | |
249 | void HeaderFooterLayout::(QQuickItem *item) |
250 | { |
251 | if (item) { |
252 | disconnect(sender: item, signal: &QQuickItem::implicitWidthChanged, receiver: this, slot: &HeaderFooterLayout::markAsDirty); |
253 | disconnect(sender: item, signal: &QQuickItem::implicitHeightChanged, receiver: this, slot: &HeaderFooterLayout::markAsDirty); |
254 | disconnect(sender: item, signal: &QQuickItem::visibleChanged, receiver: this, slot: &HeaderFooterLayout::markAsDirty); |
255 | } |
256 | } |
257 | |
258 | #include "moc_headerfooterlayout.cpp" |
259 | |