1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QQUICKLAYOUT_P_H
5#define QQUICKLAYOUT_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QPointer>
19#include <QQuickItem>
20#include <QtCore/qflags.h>
21
22#include <QtQuickLayouts/private/qquicklayoutglobal_p.h>
23#include <private/qquickitem_p.h>
24#include <QtQuick/private/qquickitemchangelistener_p.h>
25#include <QtGui/private/qlayoutpolicy_p.h>
26
27QT_BEGIN_NAMESPACE
28
29class QQuickLayoutAttached;
30Q_DECLARE_LOGGING_CATEGORY(lcQuickLayouts)
31
32class QQuickLayoutPrivate;
33class Q_QUICKLAYOUTS_PRIVATE_EXPORT QQuickLayout : public QQuickItem, public QQuickItemChangeListener
34
35{
36 Q_OBJECT
37 QML_NAMED_ELEMENT(Layout)
38 QML_ADDED_IN_VERSION(1, 0)
39 QML_UNCREATABLE("Do not create objects of type Layout.")
40 QML_ATTACHED(QQuickLayoutAttached)
41
42public:
43 enum SizeHint {
44 MinimumSize = 0,
45 PreferredSize,
46 MaximumSize,
47 NSizes
48 };
49
50 enum EnsureLayoutItemsUpdatedOption {
51 Recursive = 0b001,
52 ApplySizeHints = 0b010
53 };
54
55 Q_DECLARE_FLAGS(EnsureLayoutItemsUpdatedOptions, EnsureLayoutItemsUpdatedOption)
56
57 explicit QQuickLayout(QQuickLayoutPrivate &dd, QQuickItem *parent = nullptr);
58 ~QQuickLayout();
59
60 static QQuickLayoutAttached *qmlAttachedProperties(QObject *object);
61
62
63 void componentComplete() override;
64 virtual QSizeF sizeHint(Qt::SizeHint whichSizeHint) const = 0;
65 virtual void setAlignment(QQuickItem *item, Qt::Alignment align) = 0;
66 virtual void setStretchFactor(QQuickItem *item, int stretchFactor, Qt::Orientation orient) = 0;
67
68 virtual void invalidate(QQuickItem * childItem = nullptr);
69 virtual void updateLayoutItems() = 0;
70
71 void ensureLayoutItemsUpdated(EnsureLayoutItemsUpdatedOptions options = {}) const;
72
73 // iterator
74 virtual QQuickItem *itemAt(int index) const = 0;
75 virtual int itemCount() const = 0;
76
77 virtual void rearrange(const QSizeF &);
78
79 static void effectiveSizeHints_helper(QQuickItem *item, QSizeF *cachedSizeHints, QQuickLayoutAttached **info, bool useFallbackToWidthOrHeight);
80 static QLayoutPolicy::Policy effectiveSizePolicy_helper(QQuickItem *item, Qt::Orientation orientation, QQuickLayoutAttached *info);
81 bool shouldIgnoreItem(QQuickItem *child) const;
82 void checkAnchors(QQuickItem *item) const;
83
84 void itemChange(ItemChange change, const ItemChangeData &value) override;
85 void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
86 bool isReady() const;
87 void deactivateRecur();
88
89 bool invalidated() const;
90 bool invalidatedArrangement() const;
91 bool isMirrored() const;
92
93 /* QQuickItemChangeListener */
94 void itemSiblingOrderChanged(QQuickItem *item) override;
95 void itemImplicitWidthChanged(QQuickItem *item) override;
96 void itemImplicitHeightChanged(QQuickItem *item) override;
97 void itemDestroyed(QQuickItem *item) override;
98 void itemVisibilityChanged(QQuickItem *item) override;
99
100 void maybeSubscribeToBaseLineOffsetChanges(QQuickItem *item);
101
102 Q_INVOKABLE void _q_dumpLayoutTree() const;
103 void dumpLayoutTreeRecursive(int level, QString &buf) const;
104
105protected:
106 void updatePolish() override;
107
108 enum Orientation {
109 Vertical = 0,
110 Horizontal,
111 NOrientations
112 };
113
114protected Q_SLOTS:
115 void invalidateSenderItem();
116
117private:
118 unsigned m_inUpdatePolish : 1;
119 unsigned m_polishInsideUpdatePolish : 2;
120
121 Q_DECLARE_PRIVATE(QQuickLayout)
122
123 friend class QQuickLayoutAttached;
124};
125
126Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickLayout::EnsureLayoutItemsUpdatedOptions)
127
128class QQuickLayoutPrivate : public QQuickItemPrivate
129{
130 Q_DECLARE_PUBLIC(QQuickLayout)
131public:
132 QQuickLayoutPrivate() : m_dirty(true)
133 , m_dirtyArrangement(true)
134 , m_isReady(false)
135 , m_disableRearrange(true)
136 , m_hasItemChangeListeners(false) {}
137
138 void applySizeHints() const;
139
140protected:
141 /* m_dirty == true means that something in the layout was changed,
142 but its state has not been synced to the internal grid layout engine. It is usually:
143 1. A child item was added or removed from the layout (or made visible/invisble)
144 2. A child item got one of its size hints changed
145 */
146 mutable unsigned m_dirty : 1;
147 /* m_dirtyArrangement == true means that the layout still needs a rearrange despite that
148 * m_dirty == false. This is only used for the case that a layout has been invalidated,
149 * but its new size is the same as the old size (in that case the child layout won't get
150 * a geometryChanged() notification, which rearrange() usually reacts to)
151 */
152 mutable unsigned m_dirtyArrangement : 1;
153 unsigned m_isReady : 1;
154 unsigned m_disableRearrange : 1;
155 unsigned m_hasItemChangeListeners : 1; // if false, we don't need to remove its item change listeners...
156};
157
158
159class Q_QUICKLAYOUTS_PRIVATE_EXPORT QQuickLayoutAttached : public QObject
160{
161 Q_OBJECT
162 Q_PROPERTY(qreal minimumWidth READ minimumWidth WRITE setMinimumWidth NOTIFY minimumWidthChanged FINAL)
163 Q_PROPERTY(qreal minimumHeight READ minimumHeight WRITE setMinimumHeight NOTIFY minimumHeightChanged FINAL)
164 Q_PROPERTY(qreal preferredWidth READ preferredWidth WRITE setPreferredWidth NOTIFY preferredWidthChanged FINAL)
165 Q_PROPERTY(qreal preferredHeight READ preferredHeight WRITE setPreferredHeight NOTIFY preferredHeightChanged FINAL)
166 Q_PROPERTY(qreal maximumWidth READ maximumWidth WRITE setMaximumWidth NOTIFY maximumWidthChanged FINAL)
167 Q_PROPERTY(qreal maximumHeight READ maximumHeight WRITE setMaximumHeight NOTIFY maximumHeightChanged FINAL)
168 Q_PROPERTY(bool fillHeight READ fillHeight WRITE setFillHeight NOTIFY fillHeightChanged FINAL)
169 Q_PROPERTY(bool fillWidth READ fillWidth WRITE setFillWidth NOTIFY fillWidthChanged FINAL)
170 Q_PROPERTY(int row READ row WRITE setRow NOTIFY rowChanged FINAL)
171 Q_PROPERTY(int column READ column WRITE setColumn NOTIFY columnChanged FINAL)
172 Q_PROPERTY(int rowSpan READ rowSpan WRITE setRowSpan NOTIFY rowSpanChanged FINAL)
173 Q_PROPERTY(int columnSpan READ columnSpan WRITE setColumnSpan NOTIFY columnSpanChanged FINAL)
174 Q_PROPERTY(Qt::Alignment alignment READ alignment WRITE setAlignment NOTIFY alignmentChanged FINAL)
175 Q_PROPERTY(int horizontalStretchFactor READ horizontalStretchFactor WRITE setHorizontalStretchFactor NOTIFY horizontalStretchFactorChanged FINAL)
176 Q_PROPERTY(int verticalStretchFactor READ verticalStretchFactor WRITE setVerticalStretchFactor NOTIFY verticalStretchFactorChanged FINAL)
177
178 Q_PROPERTY(qreal margins READ margins WRITE setMargins NOTIFY marginsChanged FINAL)
179 Q_PROPERTY(qreal leftMargin READ leftMargin WRITE setLeftMargin RESET resetLeftMargin NOTIFY leftMarginChanged FINAL)
180 Q_PROPERTY(qreal topMargin READ topMargin WRITE setTopMargin RESET resetTopMargin NOTIFY topMarginChanged FINAL)
181 Q_PROPERTY(qreal rightMargin READ rightMargin WRITE setRightMargin RESET resetRightMargin NOTIFY rightMarginChanged FINAL)
182 Q_PROPERTY(qreal bottomMargin READ bottomMargin WRITE setBottomMargin RESET resetBottomMargin NOTIFY bottomMarginChanged FINAL)
183
184public:
185 QQuickLayoutAttached(QObject *object);
186
187 qreal minimumWidth() const { return !m_isMinimumWidthSet ? sizeHint(which: Qt::MinimumSize, orientation: Qt::Horizontal) : m_minimumWidth; }
188 void setMinimumWidth(qreal width);
189 bool isMinimumWidthSet() const {return m_isMinimumWidthSet; }
190
191 qreal minimumHeight() const { return !m_isMinimumHeightSet ? sizeHint(which: Qt::MinimumSize, orientation: Qt::Vertical) : m_minimumHeight; }
192 void setMinimumHeight(qreal height);
193 bool isMinimumHeightSet() const {return m_isMinimumHeightSet; }
194
195 qreal preferredWidth() const { return m_preferredWidth; }
196 void setPreferredWidth(qreal width);
197 bool isPreferredWidthSet() const {return m_preferredWidth > -1; }
198
199 qreal preferredHeight() const { return m_preferredHeight; }
200 void setPreferredHeight(qreal width);
201 bool isPreferredHeightSet() const {return m_preferredHeight > -1; }
202
203 qreal maximumWidth() const { return !m_isMaximumWidthSet ? sizeHint(which: Qt::MaximumSize, orientation: Qt::Horizontal) : m_maximumWidth; }
204 void setMaximumWidth(qreal width);
205 bool isMaximumWidthSet() const {return m_isMaximumWidthSet; }
206
207 qreal maximumHeight() const { return !m_isMaximumHeightSet ? sizeHint(which: Qt::MaximumSize, orientation: Qt::Vertical) : m_maximumHeight; }
208 void setMaximumHeight(qreal height);
209 bool isMaximumHeightSet() const {return m_isMaximumHeightSet; }
210
211 void setMinimumImplicitSize(const QSizeF &sz);
212 void setMaximumImplicitSize(const QSizeF &sz);
213
214 bool fillWidth() const { return m_fillWidth; }
215 void setFillWidth(bool fill);
216 bool isFillWidthSet() const { return m_isFillWidthSet; }
217
218 bool fillHeight() const { return m_fillHeight; }
219 void setFillHeight(bool fill);
220 bool isFillHeightSet() const { return m_isFillHeightSet; }
221
222 int row() const { return qMax(a: m_row, b: 0); }
223 void setRow(int row);
224 bool isRowSet() const { return m_row >= 0; }
225 int column() const { return qMax(a: m_column, b: 0); }
226 void setColumn(int column);
227 bool isColumnSet() const { return m_column >= 0; }
228
229 int rowSpan() const { return m_rowSpan; }
230 void setRowSpan(int span);
231 int columnSpan() const { return m_columnSpan; }
232 void setColumnSpan(int span);
233
234 Qt::Alignment alignment() const { return m_alignment; }
235 void setAlignment(Qt::Alignment align);
236 bool isAlignmentSet() const {return m_isAlignmentSet; }
237
238 int horizontalStretchFactor() const { return m_horizontalStretch; }
239 void setHorizontalStretchFactor(int stretchFactor);
240 bool isHorizontalStretchFactorSet() const { return m_horizontalStretch > -1; }
241 int verticalStretchFactor() const { return m_verticalStretch; }
242 void setVerticalStretchFactor(int stretchFactor);
243 bool isVerticalStretchFactorSet() const { return m_verticalStretch > -1; }
244
245 qreal margins() const { return m_defaultMargins; }
246 void setMargins(qreal m);
247 bool isMarginsSet() const { return m_isMarginsSet; }
248
249 qreal leftMargin() const { return m_isLeftMarginSet ? m_margins.left() : m_defaultMargins; }
250 void setLeftMargin(qreal m);
251 void resetLeftMargin();
252 bool isLeftMarginSet() const { return m_isLeftMarginSet; }
253
254 qreal topMargin() const { return m_isTopMarginSet ? m_margins.top() : m_defaultMargins; }
255 void setTopMargin(qreal m);
256 void resetTopMargin();
257 bool isTopMarginSet() const {return m_isTopMarginSet; }
258
259 qreal rightMargin() const { return m_isRightMarginSet ? m_margins.right() : m_defaultMargins; }
260 void setRightMargin(qreal m);
261 void resetRightMargin();
262 bool isRightMarginSet() const { return m_isRightMarginSet; }
263
264 qreal bottomMargin() const { return m_isBottomMarginSet ? m_margins.bottom() : m_defaultMargins; }
265 void setBottomMargin(qreal m);
266 void resetBottomMargin();
267 bool isBottomMarginSet() const { return m_isBottomMarginSet; }
268
269 QMarginsF qMargins() const {
270 return QMarginsF(leftMargin(), topMargin(), rightMargin(), bottomMargin());
271 }
272
273 QMarginsF effectiveQMargins() const {
274 bool mirrored = parentLayout() && parentLayout()->isMirrored();
275 if (mirrored)
276 return QMarginsF(rightMargin(), topMargin(), leftMargin(), bottomMargin());
277 else
278 return qMargins();
279 }
280
281 bool setChangesNotificationEnabled(bool enabled)
282 {
283 const bool old = m_changesNotificationEnabled;
284 m_changesNotificationEnabled = enabled;
285 return old;
286 }
287
288 qreal sizeHint(Qt::SizeHint which, Qt::Orientation orientation) const;
289
290 bool isExtentExplicitlySet(Qt::Orientation o, Qt::SizeHint whichSize) const
291 {
292 switch (whichSize) {
293 case Qt::MinimumSize:
294 return o == Qt::Horizontal ? m_isMinimumWidthSet : m_isMinimumHeightSet;
295 case Qt::MaximumSize:
296 return o == Qt::Horizontal ? m_isMaximumWidthSet : m_isMaximumHeightSet;
297 case Qt::PreferredSize:
298 return true; // Layout.preferredWidth is always explicitly set
299 case Qt::MinimumDescent: // Not supported
300 case Qt::NSizeHints:
301 return false;
302 }
303 return false;
304 }
305
306Q_SIGNALS:
307 void minimumWidthChanged();
308 void minimumHeightChanged();
309 void preferredWidthChanged();
310 void preferredHeightChanged();
311 void maximumWidthChanged();
312 void maximumHeightChanged();
313 void fillWidthChanged();
314 void fillHeightChanged();
315 void leftMarginChanged();
316 void topMarginChanged();
317 void rightMarginChanged();
318 void bottomMarginChanged();
319 void marginsChanged();
320 void rowChanged();
321 void columnChanged();
322 void rowSpanChanged();
323 void columnSpanChanged();
324 void alignmentChanged();
325 void horizontalStretchFactorChanged();
326 void verticalStretchFactorChanged();
327
328private:
329 void invalidateItem();
330 QQuickLayout *parentLayout() const;
331 QQuickItem *item() const;
332private:
333 qreal m_minimumWidth;
334 qreal m_minimumHeight;
335 qreal m_preferredWidth;
336 qreal m_preferredHeight;
337 qreal m_maximumWidth;
338 qreal m_maximumHeight;
339
340 qreal m_defaultMargins;
341 QMarginsF m_margins;
342
343 qreal m_fallbackWidth;
344 qreal m_fallbackHeight;
345
346 // GridLayout specific properties
347 int m_row;
348 int m_column;
349 int m_rowSpan;
350 int m_columnSpan;
351
352 unsigned m_fillWidth : 1;
353 unsigned m_fillHeight : 1;
354 unsigned m_isFillWidthSet : 1;
355 unsigned m_isFillHeightSet : 1;
356 unsigned m_isMinimumWidthSet : 1;
357 unsigned m_isMinimumHeightSet : 1;
358 // preferredWidth and preferredHeight are always explicit, since
359 // their implicit equivalent is implicitWidth and implicitHeight
360 unsigned m_isMaximumWidthSet : 1;
361 unsigned m_isMaximumHeightSet : 1;
362 unsigned m_changesNotificationEnabled : 1;
363 unsigned m_isMarginsSet : 1;
364 unsigned m_isLeftMarginSet : 1;
365 unsigned m_isTopMarginSet : 1;
366 unsigned m_isRightMarginSet : 1;
367 unsigned m_isBottomMarginSet : 1;
368 unsigned m_isAlignmentSet : 1;
369 Qt::Alignment m_alignment;
370 int m_horizontalStretch;
371 int m_verticalStretch;
372 friend class QQuickLayout;
373};
374
375inline QQuickLayoutAttached *attachedLayoutObject(QQuickItem *item, bool create = true)
376{
377 return static_cast<QQuickLayoutAttached *>(qmlAttachedPropertiesObject<QQuickLayout>(obj: item, create));
378}
379
380QT_END_NAMESPACE
381
382QML_DECLARE_TYPE(QQuickLayout)
383
384#endif // QQUICKLAYOUT_P_H
385

source code of qtdeclarative/src/quicklayouts/qquicklayout_p.h