Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquicklinearlayout.cpp
Go to the documentation of this file.
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// Qt-Security score:significant reason:default
4
8#include <QtCore/private/qnumeric_p.h>
9#include <QtQml/qqmlinfo.h>
10#include "qdebug.h"
11#include <limits>
12
13/*!
14 \qmltype RowLayout
15 //! \nativetype QQuickRowLayout
16 \inherits Item
17 \inqmlmodule QtQuick.Layouts
18 \ingroup layouts
19 \brief Identical to \l GridLayout, but having only one row.
20
21 To be able to use this type more efficiently, it is recommended that you
22 understand the general mechanism of the Qt Quick Layouts module. Refer to
23 \l{Qt Quick Layouts Overview} for more information.
24
25 It is available as a convenience for developers, as it offers a cleaner API.
26
27 Items in a RowLayout support these attached properties:
28 \list
29 \input layout.qdocinc attached-properties
30 \endlist
31
32 \image rowlayout.png
33
34 \code
35 RowLayout {
36 id: layout
37 anchors.fill: parent
38 spacing: 6
39 Rectangle {
40 color: 'teal'
41 Layout.fillWidth: true
42 Layout.minimumWidth: 50
43 Layout.preferredWidth: 100
44 Layout.maximumWidth: 300
45 Layout.minimumHeight: 150
46 Text {
47 anchors.centerIn: parent
48 text: parent.width + 'x' + parent.height
49 }
50 }
51 Rectangle {
52 color: 'plum'
53 Layout.fillWidth: true
54 Layout.minimumWidth: 100
55 Layout.preferredWidth: 200
56 Layout.preferredHeight: 100
57 Text {
58 anchors.centerIn: parent
59 text: parent.width + 'x' + parent.height
60 }
61 }
62 }
63 \endcode
64
65 Read more about attached properties \l{QML Object Attributes}{here}.
66 \sa ColumnLayout
67 \sa GridLayout
68 \sa StackLayout
69 \sa Row
70 \sa {Qt Quick Layouts Overview}
71*/
72
73/*!
74 \qmltype ColumnLayout
75 //! \nativetype QQuickColumnLayout
76 \inherits Item
77 \inqmlmodule QtQuick.Layouts
78 \ingroup layouts
79 \brief Identical to \l GridLayout, but having only one column.
80
81 To be able to use this type more efficiently, it is recommended that you
82 understand the general mechanism of the Qt Quick Layouts module. Refer to
83 \l{Qt Quick Layouts Overview} for more information.
84
85 It is available as a convenience for developers, as it offers a cleaner API.
86
87 Items in a ColumnLayout support these attached properties:
88 \list
89 \input layout.qdocinc attached-properties
90 \endlist
91
92 \image columnlayout.png
93
94 \code
95 ColumnLayout{
96 spacing: 2
97
98 Rectangle {
99 Layout.alignment: Qt.AlignCenter
100 color: "red"
101 Layout.preferredWidth: 40
102 Layout.preferredHeight: 40
103 }
104
105 Rectangle {
106 Layout.alignment: Qt.AlignRight
107 color: "green"
108 Layout.preferredWidth: 40
109 Layout.preferredHeight: 70
110 }
111
112 Rectangle {
113 Layout.alignment: Qt.AlignBottom
114 Layout.fillHeight: true
115 color: "blue"
116 Layout.preferredWidth: 70
117 Layout.preferredHeight: 40
118 }
119 }
120 \endcode
121
122 Read more about attached properties \l{QML Object Attributes}{here}.
123
124 \sa RowLayout
125 \sa GridLayout
126 \sa StackLayout
127 \sa Column
128 \sa {Qt Quick Layouts Overview}
129*/
130
131
132/*!
133 \qmltype GridLayout
134 //! \nativetype QQuickGridLayout
135 \inherits Item
136 \inqmlmodule QtQuick.Layouts
137 \ingroup layouts
138 \brief Provides a way of dynamically arranging items in a grid.
139
140 To be able to use this type more efficiently, it is recommended that you
141 understand the general mechanism of the Qt Quick Layouts module. Refer to
142 \l{Qt Quick Layouts Overview} for more information.
143
144 If the GridLayout is resized, all items in the layout will be rearranged. It is similar
145 to the widget-based QGridLayout. All visible children of the GridLayout element will belong to
146 the layout. If you want a layout with just one row or one column, you can use the
147 \l RowLayout or \l ColumnLayout. These offer a bit more convenient API, and improve
148 readability.
149
150 By default items will be arranged according to the \l flow property. The default value of
151 the \l flow property is \c GridLayout.LeftToRight.
152
153 If the \l columns property is specified, it will be treated as a maximum limit of how many
154 columns the layout can have, before the auto-positioning wraps back to the beginning of the
155 next row. The \l columns property is only used when \l flow is \c GridLayout.LeftToRight.
156
157 \image gridlayout.png
158
159 \code
160 GridLayout {
161 id: grid
162 columns: 3
163
164 Text { text: "Three"; font.bold: true; }
165 Text { text: "words"; color: "red" }
166 Text { text: "in"; font.underline: true }
167 Text { text: "a"; font.pixelSize: 20 }
168 Text { text: "row"; font.strikeout: true }
169 }
170 \endcode
171
172 The \l rows property works in a similar way, but items are auto-positioned vertically. The \l
173 rows property is only used when \l flow is \c GridLayout.TopToBottom.
174
175 You can specify which cell you want an item to occupy by setting the
176 \l{Layout::row}{Layout.row} and \l{Layout::column}{Layout.column} properties. You can also
177 specify the row span or column span by setting the \l{Layout::rowSpan}{Layout.rowSpan} or
178 \l{Layout::columnSpan}{Layout.columnSpan} properties.
179
180
181 Items in a GridLayout support these attached properties:
182 \list
183 \li \l{Layout::row}{Layout.row}
184 \li \l{Layout::column}{Layout.column}
185 \li \l{Layout::rowSpan}{Layout.rowSpan}
186 \li \l{Layout::columnSpan}{Layout.columnSpan}
187 \input layout.qdocinc attached-properties
188 \endlist
189
190 Read more about attached properties \l{QML Object Attributes}{here}.
191
192 \sa RowLayout
193 \sa ColumnLayout
194 \sa StackLayout
195 \sa Grid
196 \sa {Qt Quick Layouts Overview}
197*/
198
199
200
202
203QQuickGridLayoutBase::QQuickGridLayoutBase()
204 : QQuickLayout(*new QQuickGridLayoutBasePrivate)
205{
206
207}
208
209QQuickGridLayoutBase::QQuickGridLayoutBase(QQuickGridLayoutBasePrivate &dd,
210 Qt::Orientation orientation,
211 QQuickItem *parent /*= nullptr */)
212 : QQuickLayout(dd, parent)
213{
214 Q_D(QQuickGridLayoutBase);
215 d->orientation = orientation;
216 d->styleInfo = new QQuickLayoutStyleInfo;
217}
218
219Qt::Orientation QQuickGridLayoutBase::orientation() const
220{
221 Q_D(const QQuickGridLayoutBase);
222 return d->orientation;
223}
224
225void QQuickGridLayoutBase::setOrientation(Qt::Orientation orientation)
226{
227 Q_D(QQuickGridLayoutBase);
228 if (d->orientation == orientation)
229 return;
230
231 d->orientation = orientation;
232 invalidate();
233}
234
235QSizeF QQuickGridLayoutBase::sizeHint(Qt::SizeHint whichSizeHint) const
236{
237 Q_D(const QQuickGridLayoutBase);
238 return d->engine.sizeHint(whichSizeHint, QSizeF(), d->styleInfo);
239}
240
241/*!
242 \qmlproperty enumeration GridLayout::layoutDirection
243 \since QtQuick.Layouts 1.1
244
245 This property holds the layout direction of the grid layout - it controls whether items are
246 laid out from left to right or right to left. If \c Qt.RightToLeft is specified,
247 left-aligned items will be right-aligned and right-aligned items will be left-aligned.
248
249 Possible values:
250
251 \value Qt.LeftToRight (default) Items are laid out from left to right.
252 \value Qt.RightToLeft Items are laid out from right to left.
253
254 \sa RowLayout::layoutDirection, ColumnLayout::layoutDirection
255*/
256Qt::LayoutDirection QQuickGridLayoutBase::layoutDirection() const
257{
258 Q_D(const QQuickGridLayoutBase);
259 return d->m_layoutDirection;
260}
261
262void QQuickGridLayoutBase::setLayoutDirection(Qt::LayoutDirection dir)
263{
264 Q_D(QQuickGridLayoutBase);
265 if (d->m_layoutDirection == dir)
266 return;
267 d->m_layoutDirection = dir;
268 invalidate();
269 emit layoutDirectionChanged();
270}
271
272Qt::LayoutDirection QQuickGridLayoutBase::effectiveLayoutDirection() const
273{
274 Q_D(const QQuickGridLayoutBase);
275 return !d->effectiveLayoutMirror == (layoutDirection() == Qt::LeftToRight)
276 ? Qt::LeftToRight : Qt::RightToLeft;
277}
278
279void QQuickGridLayoutBase::setAlignment(QQuickItem *item, Qt::Alignment alignment)
280{
281 Q_D(QQuickGridLayoutBase);
282 d->engine.setAlignment(item, alignment);
283 maybeSubscribeToBaseLineOffsetChanges(item);
284}
285
286void QQuickGridLayoutBase::setStretchFactor(QQuickItem *item, int stretchFactor, Qt::Orientation orient)
287{
288 Q_D(QQuickGridLayoutBase);
289 d->engine.setStretchFactor(item, stretchFactor, orient);
290}
291
292QQuickGridLayoutBase::~QQuickGridLayoutBase()
293{
294 Q_D(QQuickGridLayoutBase);
295
296 // Remove item listeners so we do not act on signalling unnecessarily
297 // (there is no point, as the layout will be torn down anyway).
298 deactivateRecur();
299 delete d->styleInfo;
300}
301
302void QQuickGridLayoutBase::componentComplete()
303{
304 qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::componentComplete()" << this << parent();
305 QQuickLayout::componentComplete();
306
307 /* The layout is invalid when it is constructed, but during construction of the layout and
308 its children (in the "static/from QML" case which this is trying to cover) things
309 change and as a consequence invalidate() and ensureLayoutItemsUpdated() might be called.
310 As soon as ensureLayoutItemsUpdated() is called it will set d->dirty = false.
311 However, a subsequent invalidate() will return early if the component is not completed
312 because it knows that componentComplete() will take care of doing the proper layouting
313 (so it won't set d->dirty = true). When we then call ensureLayoutItemsUpdated() again here
314 it sees that its not dirty and assumes everything up-to-date. For those cases we therefore
315 need to call invalidate() in advance
316 */
317 invalidate();
318 ensureLayoutItemsUpdated(QQuickLayout::ApplySizeHints);
319
320 QQuickItem *par = parentItem();
321 if (qobject_cast<QQuickLayout*>(par))
322 return;
323 rearrange(QSizeF(width(), height()));
324 qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::componentComplete(). COMPLETED" << this << parent();
325}
326
327/*
328 Invalidation happens like this as a reaction to that a size hint changes on an item "a":
329
330 Suppose we have the following Qml document:
331 RowLayout {
332 id: l1
333 RowLayout {
334 id: l2
335 Item {
336 id: a
337 }
338 Item {
339 id: b
340 }
341 }
342 }
343
344 1. l2->invalidate(a) is called on l2, where item refers to "a".
345 (this will dirty the cached size hints of item "a")
346 2. The layout engine will invalidate:
347 i) invalidate the layout engine
348 ii) dirty the cached size hints of item "l2" (by calling parentLayout()->invalidate(l2)
349 The recursion continues to the topmost layout
350 */
351/*!
352 \internal
353
354 Invalidates \a childItem and this layout.
355 After a call to invalidate, the next call to retrieve e.g. sizeHint will be up-to date.
356 This function will also call QQuickLayout::invalidate(0), to ensure that the parent layout
357 is invalidated.
358 */
359void QQuickGridLayoutBase::invalidate(QQuickItem *childItem)
360{
361 Q_D(QQuickGridLayoutBase);
362 if (!isReady())
363 return;
364 qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::invalidate()" << this << ", invalidated:" << invalidated();
365 if (childItem) {
366 if (d->m_rearranging) {
367 if (!d->m_invalidateAfterRearrange.contains(childItem))
368 d->m_invalidateAfterRearrange << childItem;
369 return;
370 }
371 if (QQuickGridLayoutItem *layoutItem = d->engine.findLayoutItem(childItem)) {
372 layoutItem->invalidate();
373 }
374 }
375
376 // invalidate engine
377 d->engine.invalidate();
378
379 qCDebug(lcQuickLayouts) << "calling QQuickLayout::invalidate();";
380 QQuickLayout::invalidate();
381
382 if (auto *parentLayout = qobject_cast<QQuickLayout *>(parentItem()))
383 parentLayout->invalidate(this);
384 qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::invalidate() LEAVING" << this;
385}
386
387void QQuickGridLayoutBase::updateLayoutItems()
388{
389 Q_D(QQuickGridLayoutBase);
390 if (!isReady())
391 return;
392
393 qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::updateLayoutItems ENTERING" << this;
394 d->engine.deleteItems();
395 insertLayoutItems();
396 qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::updateLayoutItems() LEAVING" << this;
397}
398
399QQuickItem *QQuickGridLayoutBase::itemAt(int index) const
400{
401 Q_D(const QQuickGridLayoutBase);
402 return static_cast<QQuickGridLayoutItem*>(d->engine.itemAt(index))->layoutItem();
403}
404
405int QQuickGridLayoutBase::itemCount() const
406{
407 Q_D(const QQuickGridLayoutBase);
408 return d->engine.itemCount();
409}
410
411void QQuickGridLayoutBase::removeGridItem(QGridLayoutItem *gridItem)
412{
413 Q_D(QQuickGridLayoutBase);
414 const int index = gridItem->firstRow(d->orientation);
415 d->engine.removeItem(gridItem);
416 d->engine.removeRows(index, 1, d->orientation);
417}
418
419void QQuickGridLayoutBase::itemDestroyed(QQuickItem *item)
420{
421 if (!isReady())
422 return;
423 Q_D(QQuickGridLayoutBase);
424 qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::itemDestroyed";
425 if (QQuickGridLayoutItem *gridItem = d->engine.findLayoutItem(item)) {
426 removeGridItem(gridItem);
427 delete gridItem;
428 invalidate();
429 }
430}
431
432void QQuickGridLayoutBase::itemVisibilityChanged(QQuickItem *item)
433{
434 Q_UNUSED(item);
435
436 if (!isReady())
437 return;
438 qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::itemVisibilityChanged()";
439 invalidate(item);
440}
441
442void QQuickGridLayoutBase::rearrange(const QSizeF &size)
443{
444 Q_D(QQuickGridLayoutBase);
445 if (!isReady() || !size.isValid())
446 return;
447
448 qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::rearrange" << d->m_recurRearrangeCounter << this;
449 const auto refCounter = qScopeGuard([&d] {
450 --(d->m_recurRearrangeCounter);
451 });
452 if (d->m_recurRearrangeCounter++ == 2) {
453 // allow a recursive depth of two in order to respond to height-for-width
454 // (e.g QQuickText changes implicitHeight when its width gets changed)
455 qmlWarning(this)
456 << "Qt Quick Layouts: Detected recursive rearrange. Aborting after two iterations.";
457 return;
458 }
459
460 // Should normally not be needed, but there might be an incoming window resize event that we
461 // will process before we process updatePolish()
462 ensureLayoutItemsUpdated(QQuickLayout::ApplySizeHints | QQuickLayout::Recursive);
463
464 d->m_rearranging = true;
465 qCDebug(lcQuickLayouts) << objectName() << "QQuickGridLayoutBase::rearrange()" << size;
466 Qt::LayoutDirection visualDir = effectiveLayoutDirection();
467 d->engine.setVisualDirection(visualDir);
468
469 /*
470 qreal left, top, right, bottom;
471 left = top = right = bottom = 0; // ### support for margins?
472 if (visualDir == Qt::RightToLeft)
473 qSwap(left, right);
474 */
475
476 // Set m_dirty to false in case size hint changes during arrangement.
477 // This could happen if there is a binding like implicitWidth: height
478 QQuickLayout::rearrange(size);
479 d->engine.setGeometries(QRectF(QPointF(0,0), size), d->styleInfo);
480 d->m_rearranging = false;
481
482 for (auto childItem : std::as_const(d->m_invalidateAfterRearrange))
483 invalidate(childItem);
484 d->m_invalidateAfterRearrange.clear();
485}
486
487/**********************************
488 **
489 ** QQuickGridLayout
490 **
491 **/
492QQuickGridLayout::QQuickGridLayout(QQuickItem *parent /* = nullptr*/)
493 : QQuickGridLayoutBase(*new QQuickGridLayoutPrivate, Qt::Horizontal, parent)
494{
495}
496
497/*!
498 \qmlproperty real GridLayout::columnSpacing
499
500 This property holds the spacing between each column.
501 The default value is \c 5.
502*/
503qreal QQuickGridLayout::columnSpacing() const
504{
505 Q_D(const QQuickGridLayout);
506 return d->engine.spacing(Qt::Horizontal, d->styleInfo);
507}
508
509void QQuickGridLayout::setColumnSpacing(qreal spacing)
510{
511 Q_D(QQuickGridLayout);
512 if (qt_is_nan(spacing) || columnSpacing() == spacing)
513 return;
514
515 d->engine.setSpacing(spacing, Qt::Horizontal);
516 invalidate();
517 emit columnSpacingChanged();
518}
519
520/*!
521 \qmlproperty real GridLayout::rowSpacing
522
523 This property holds the spacing between each row.
524 The default value is \c 5.
525*/
526qreal QQuickGridLayout::rowSpacing() const
527{
528 Q_D(const QQuickGridLayout);
529 return d->engine.spacing(Qt::Vertical, d->styleInfo);
530}
531
532void QQuickGridLayout::setRowSpacing(qreal spacing)
533{
534 Q_D(QQuickGridLayout);
535 if (qt_is_nan(spacing) || rowSpacing() == spacing)
536 return;
537
538 d->engine.setSpacing(spacing, Qt::Vertical);
539 invalidate();
540 emit rowSpacingChanged();
541}
542
543/*!
544 \qmlproperty int GridLayout::columns
545
546 This property holds the column limit for items positioned if \l flow is
547 \c GridLayout.LeftToRight.
548 The default value is that there is no limit.
549*/
550int QQuickGridLayout::columns() const
551{
552 Q_D(const QQuickGridLayout);
553 return d->columns;
554}
555
556void QQuickGridLayout::setColumns(int columns)
557{
558 Q_D(QQuickGridLayout);
559 if (d->columns == columns)
560 return;
561 d->columns = columns;
562 invalidate();
563 emit columnsChanged();
564}
565
566
567/*!
568 \qmlproperty int GridLayout::rows
569
570 This property holds the row limit for items positioned if \l flow is \c GridLayout.TopToBottom.
571 The default value is that there is no limit.
572*/
573int QQuickGridLayout::rows() const
574{
575 Q_D(const QQuickGridLayout);
576 return d->rows;
577}
578
579void QQuickGridLayout::setRows(int rows)
580{
581 Q_D(QQuickGridLayout);
582 if (d->rows == rows)
583 return;
584 d->rows = rows;
585 invalidate();
586 emit rowsChanged();
587}
588
589
590/*!
591 \qmlproperty enumeration GridLayout::flow
592
593 This property holds the flow direction of items that does not have an explicit cell
594 position set.
595 It is used together with the \l columns or \l rows property, where
596 they specify when flow is reset to the next row or column respectively.
597
598 Possible values are:
599
600 \value GridLayout.LeftToRight
601 (default) Items are positioned next to each other, then wrapped to the next line.
602 \value GridLayout.TopToBottom
603 Items are positioned next to each other from top to bottom, then wrapped to the next column.
604
605 \sa rows
606 \sa columns
607*/
608QQuickGridLayout::Flow QQuickGridLayout::flow() const
609{
610 Q_D(const QQuickGridLayout);
611 return d->flow;
612}
613
614void QQuickGridLayout::setFlow(QQuickGridLayout::Flow flow)
615{
616 Q_D(QQuickGridLayout);
617 if (d->flow == flow)
618 return;
619 d->flow = flow;
620 // If flow is changed, the layout needs to be repopulated
621 invalidate();
622 emit flowChanged();
623}
624
625/*!
626 \qmlproperty bool GridLayout::uniformCellWidths
627 \since QtQuick.Layouts 6.6
628
629 If this property is set to \c true, the layout will force all cells to have
630 a uniform width. The layout aims to respect
631 \l{Layout::minimumWidth}{Layout.minimumWidth},
632 \l{Layout::preferredWidth}{Layout.preferredWidth} and
633 \l{Layout::maximumWidth}{Layout.maximumWidth} in this mode but might make
634 compromisses to fullfill the requirements of all items.
635
636 Default value is \c false.
637
638 \sa GridLayout::uniformCellHeights, RowLayout::uniformCellSizes, ColumnLayout::uniformCellSizes
639*/
640bool QQuickGridLayout::uniformCellWidths() const
641{
642 Q_D(const QQuickGridLayout);
643 return d->engine.uniformCellWidths();
644}
645
646void QQuickGridLayout::setUniformCellWidths(bool uniformCellWidths)
647{
648 Q_D(QQuickGridLayout);
649 if (d->engine.uniformCellWidths() == uniformCellWidths)
650 return;
651 d->engine.setUniformCellWidths(uniformCellWidths);
652 invalidate();
653 emit uniformCellWidthsChanged();
654}
655
656/*!
657 \qmlproperty bool GridLayout::uniformCellHeights
658 \since QtQuick.Layouts 6.6
659
660 If this property is set to \c true, the layout will force all cells to have an
661 uniform Height. The layout aims to respect
662 \l{Layout::minimumHeight}{Layout.minimumHeight},
663 \l{Layout::preferredHeight}{Layout.preferredHeight} and
664 \l{Layout::maximumHeight}{Layout.maximumHeight} in this mode but might make
665 compromisses to fullfill the requirements of all items.
666
667 Default value is \c false.
668
669 \sa GridLayout::uniformCellWidths, RowLayout::uniformCellSizes, ColumnLayout::uniformCellSizes
670*/
671bool QQuickGridLayout::uniformCellHeights() const
672{
673 Q_D(const QQuickGridLayout);
674 return d->engine.uniformCellHeights();
675}
676
677void QQuickGridLayout::setUniformCellHeights(bool uniformCellHeights)
678{
679 Q_D(QQuickGridLayout);
680 if (d->engine.uniformCellHeights() == uniformCellHeights)
681 return;
682 d->engine.setUniformCellHeights(uniformCellHeights);
683 invalidate();
684 emit uniformCellHeightsChanged();
685}
686
687
688void QQuickGridLayout::insertLayoutItems()
689{
690 Q_D(QQuickGridLayout);
691
692 int nextCellPos[2] = {0,0};
693 int &nextColumn = nextCellPos[0];
694 int &nextRow = nextCellPos[1];
695
696 const QSize gridSize(columns(), rows());
697 const int flowOrientation = flow();
698 int &flowColumn = nextCellPos[flowOrientation];
699 int &flowRow = nextCellPos[1 - flowOrientation];
700 int flowBound = (flowOrientation == QQuickGridLayout::LeftToRight) ? columns() : rows();
701
702 if (flowBound < 0)
703 flowBound = std::numeric_limits<int>::max();
704
705 const auto items = childItems();
706 for (QQuickItem *child : items) {
707 checkAnchors(child);
708 // Will skip all items with effective maximum width/height == 0
709 if (shouldIgnoreItem(child))
710 continue;
711 QQuickLayoutAttached *info = attachedLayoutObject(child, false);
712
713 Qt::Alignment alignment;
714 int hStretch = -1;
715 int vStretch = -1;
716 int row = -1;
717 int column = -1;
718 int span[2] = {1,1};
719 int &columnSpan = span[0];
720 int &rowSpan = span[1];
721
722 if (info) {
723 if (info->isRowSet() || info->isColumnSet()) {
724 // If row is specified and column is not specified (or vice versa),
725 // the unspecified component of the cell position should default to 0
726 // The getters do this for us, as they will return 0 for an
727 // unset (or negative) value.
728 // In addition, if \a rows is less than Layout.row, treat Layout.row as if it was not set
729 // This will basically make it find the next available cell (potentially wrapping to
730 // the next line). Likewise for an invalid Layout.column
731
732 if (gridSize.height() >= 0 && row >= gridSize.height()) {
733 qmlWarning(child) << QString::fromLatin1("Layout: row (%1) should be less than the number of rows (%2)").arg(info->row()).arg(rows());
734 } else {
735 row = info->row();
736 }
737
738 if (gridSize.width() >= 0 && info->column() >= gridSize.width()) {
739 qmlWarning(child) << QString::fromLatin1("Layout: column (%1) should be less than the number of columns (%2)").arg(info->column()).arg(columns());
740 } else {
741 column = info->column();
742 }
743 }
744 rowSpan = info->rowSpan();
745 columnSpan = info->columnSpan();
746 if (columnSpan < 1) {
747 qmlWarning(child) << "Layout: invalid column span: " << columnSpan;
748 return;
749
750 } else if (rowSpan < 1) {
751 qmlWarning(child) << "Layout: invalid row span: " << rowSpan;
752 return;
753 }
754 alignment = info->alignment();
755 hStretch = info->horizontalStretchFactor();
756 if (hStretch >= 0 && !info->fillWidth())
757 qmlWarning(child) << "horizontalStretchFactor requires fillWidth to also be set to true";
758 vStretch = info->verticalStretchFactor();
759 if (vStretch >= 0 && !info->fillHeight())
760 qmlWarning(child) << "verticalStretchFactor requires fillHeight to also be set to true";
761 }
762
763 Q_ASSERT(columnSpan >= 1);
764 Q_ASSERT(rowSpan >= 1);
765 const int sp = span[flowOrientation];
766 if (sp > flowBound)
767 return;
768
769 if (row >= 0)
770 nextRow = row;
771 if (column >= 0)
772 nextColumn = column;
773
774 if (row < 0 || column < 0) {
775 /* if row or column is not specified, find next position by
776 advancing in the flow direction until there is a cell that
777 can accept the item.
778
779 The acceptance rules are pretty simple, but complexity arises
780 when an item requires several cells (due to spans):
781 1. Check if the cells that the item will require
782 does not extend beyond columns (for LeftToRight) or
783 rows (for TopToBottom).
784 2. Check if the cells that the item will require is not already
785 taken by another item.
786 */
787 bool cellAcceptsItem;
788 while (true) {
789 // Check if the item does not span beyond the layout bound
790 cellAcceptsItem = (flowColumn + sp) <= flowBound;
791
792 // Check if all the required cells are not taken
793 for (int rs = 0; cellAcceptsItem && rs < rowSpan; ++rs) {
794 for (int cs = 0; cellAcceptsItem && cs < columnSpan; ++cs) {
795 if (d->engine.itemAt(nextRow + rs, nextColumn + cs)) {
796 cellAcceptsItem = false;
797 }
798 }
799 }
800 if (cellAcceptsItem)
801 break;
802 ++flowColumn;
803 if (flowColumn == flowBound) {
804 flowColumn = 0;
805 ++flowRow;
806 }
807 }
808 }
809 column = nextColumn;
810 row = nextRow;
811 QQuickGridLayoutItem *layoutItem = new QQuickGridLayoutItem(child, row, column, rowSpan, columnSpan, alignment);
812 if (hStretch >= 0)
813 layoutItem->setStretchFactor(hStretch, Qt::Horizontal);
814 if (vStretch >= 0)
815 layoutItem->setStretchFactor(vStretch, Qt::Vertical);
816
817 d->engine.insertItem(layoutItem, -1);
818 }
819}
820
821/**********************************
822 **
823 ** QQuickLinearLayout
824 **
825 **/
826QQuickLinearLayout::QQuickLinearLayout(Qt::Orientation orientation,
827 QQuickItem *parent /*= nullptr*/)
828 : QQuickGridLayoutBase(*new QQuickLinearLayoutPrivate, orientation, parent)
829{
830}
831
832/*!
833 \qmlproperty enumeration RowLayout::layoutDirection
834 \since QtQuick.Layouts 1.1
835
836 This property holds the layout direction of the row layout - it controls whether items are laid
837 out from left to right or right to left. If \c Qt.RightToLeft is specified,
838 left-aligned items will be right-aligned and right-aligned items will be left-aligned.
839
840 Possible values:
841
842 \value Qt.LeftToRight (default) Items are laid out from left to right.
843 \value Qt.RightToLeft Items are laid out from right to left
844
845 \sa GridLayout::layoutDirection, ColumnLayout::layoutDirection
846*/
847/*!
848 \qmlproperty enumeration ColumnLayout::layoutDirection
849 \since QtQuick.Layouts 1.1
850
851 This property holds the layout direction of the column layout - it
852 controls the horizontal alignment of items within the column.
853 If \c Qt.RightToLeft is specified,left-aligned items will be
854 right-aligned and right-aligned items will be left-aligned.
855
856 Possible values:
857
858 \value Qt.LeftToRight (default) Items are laid out from left to right.
859 \value Qt.RightToLeft Items are laid out from right to left
860
861 \sa GridLayout::layoutDirection, RowLayout::layoutDirection
862*/
863
864/*!
865 \qmlproperty bool RowLayout::uniformCellSizes
866 \since QtQuick.Layouts 6.6
867
868 If this property is set to \c true, the layout will force all cells to have
869 a uniform size.
870
871 \sa GridLayout::uniformCellWidths, GridLayout::uniformCellHeights, ColumnLayout::uniformCellSizes
872*/
873/*!
874 \qmlproperty bool ColumnLayout::uniformCellSizes
875 \since QtQuick.Layouts 6.6
876
877 If this property is set to \c true, the layout will force all cells to have
878 a uniform size.
879
880 \sa GridLayout::uniformCellWidths, GridLayout::uniformCellHeights, RowLayout::uniformCellSizes
881*/
882bool QQuickLinearLayout::uniformCellSizes() const
883{
884 Q_D(const QQuickLinearLayout);
885 Q_ASSERT(d->engine.uniformCellWidths() == d->engine.uniformCellHeights());
886 return d->engine.uniformCellWidths();
887}
888
889void QQuickLinearLayout::setUniformCellSizes(bool uniformCellSizes)
890{
891 Q_D(QQuickLinearLayout);
892 Q_ASSERT(d->engine.uniformCellWidths() == d->engine.uniformCellHeights());
893 if (d->engine.uniformCellHeights() == uniformCellSizes)
894 return;
895 d->engine.setUniformCellWidths(uniformCellSizes);
896 d->engine.setUniformCellHeights(uniformCellSizes);
897 invalidate();
898 emit uniformCellSizesChanged();
899}
900
901
902/*!
903 \qmlproperty real RowLayout::spacing
904
905 This property holds the spacing between each cell.
906 The default value is \c 5.
907*/
908/*!
909 \qmlproperty real ColumnLayout::spacing
910
911 This property holds the spacing between each cell.
912 The default value is \c 5.
913*/
914
915qreal QQuickLinearLayout::spacing() const
916{
917 Q_D(const QQuickLinearLayout);
918 return d->engine.spacing(d->orientation, d->styleInfo);
919}
920
921void QQuickLinearLayout::setSpacing(qreal space)
922{
923 Q_D(QQuickLinearLayout);
924 if (qt_is_nan(space) || spacing() == space)
925 return;
926
927 d->engine.setSpacing(space, Qt::Horizontal | Qt::Vertical);
928 invalidate();
929 emit spacingChanged();
930}
931
932void QQuickLinearLayout::insertLayoutItems()
933{
934 Q_D(QQuickLinearLayout);
935 const auto items = childItems();
936 for (QQuickItem *child : items) {
937 Q_ASSERT(child);
938 checkAnchors(child);
939
940 // Will skip all items with effective maximum width/height == 0
941 if (shouldIgnoreItem(child))
942 continue;
943 QQuickLayoutAttached *info = attachedLayoutObject(child, false);
944
945 Qt::Alignment alignment;
946 int hStretch = -1;
947 int vStretch = -1;
948 bool fillWidth = false;
949 bool fillHeight = false;
950 if (info) {
951 alignment = info->alignment();
952 hStretch = info->horizontalStretchFactor();
953 vStretch = info->verticalStretchFactor();
954 fillWidth = info->fillWidth();
955 fillHeight = info->fillHeight();
956 }
957
958 const int index = d->engine.rowCount(d->orientation);
959 d->engine.insertRow(index, d->orientation);
960
961 int gridRow = 0;
962 int gridColumn = index;
963 if (d->orientation == Qt::Vertical)
964 qSwap(gridRow, gridColumn);
965 QQuickGridLayoutItem *layoutItem = new QQuickGridLayoutItem(child, gridRow, gridColumn, 1, 1, alignment);
966
967 if (hStretch >= 0) {
968 if (!fillWidth)
969 qmlWarning(child) << "horizontalStretchFactor requires fillWidth to also be set to true";
970 layoutItem->setStretchFactor(hStretch, Qt::Horizontal);
971 }
972 if (vStretch >= 0) {
973 if (!fillHeight)
974 qmlWarning(child) << "verticalStretchFactor requires fillHeight to also be set to true";
975 layoutItem->setStretchFactor(vStretch, Qt::Vertical);
976 }
977 d->engine.insertItem(layoutItem, index);
978 }
979}
980
981QT_END_NAMESPACE
982
983#include "moc_qquicklinearlayout_p.cpp"