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 {Two rectangles side by side showing their dimensions}
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 {Three rectangles stacked vertically: red, green, blue}
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 {Text arranged in grid: Three, words, in, a, row}
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} and \l{Layout.column} properties. You can also
177 specify the row span or column span by setting the \l{Layout.rowSpan} or
178 \l{Layout.columnSpan} properties.
179
180
181 Items in a GridLayout support these attached properties:
182 \list
183 \li \l{Layout.row}
184 \li \l{Layout.column}
185 \li \l{Layout.rowSpan}
186 \li \l{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},
632 \l{Layout.preferredWidth} and
633 \l{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}, \l{Layout.preferredHeight} and
663 \l{Layout.maximumHeight} in this mode but might make
664 compromises to fullfill the requirements of all items.
665
666 Default value is \c false.
667
668 \sa GridLayout::uniformCellWidths, RowLayout::uniformCellSizes, ColumnLayout::uniformCellSizes
669*/
670bool QQuickGridLayout::uniformCellHeights() const
671{
672 Q_D(const QQuickGridLayout);
673 return d->engine.uniformCellHeights();
674}
675
676void QQuickGridLayout::setUniformCellHeights(bool uniformCellHeights)
677{
678 Q_D(QQuickGridLayout);
679 if (d->engine.uniformCellHeights() == uniformCellHeights)
680 return;
681 d->engine.setUniformCellHeights(uniformCellHeights);
682 invalidate();
683 emit uniformCellHeightsChanged();
684}
685
686
687void QQuickGridLayout::insertLayoutItems()
688{
689 Q_D(QQuickGridLayout);
690
691 int nextCellPos[2] = {0,0};
692 int &nextColumn = nextCellPos[0];
693 int &nextRow = nextCellPos[1];
694
695 const QSize gridSize(columns(), rows());
696 const int flowOrientation = flow();
697 int &flowColumn = nextCellPos[flowOrientation];
698 int &flowRow = nextCellPos[1 - flowOrientation];
699 int flowBound = (flowOrientation == QQuickGridLayout::LeftToRight) ? columns() : rows();
700
701 if (flowBound < 0)
702 flowBound = std::numeric_limits<int>::max();
703
704 const auto items = childItems();
705 for (QQuickItem *child : items) {
706 checkAnchors(child);
707 // Will skip all items with effective maximum width/height == 0
708 if (shouldIgnoreItem(child))
709 continue;
710 QQuickLayoutAttached *info = attachedLayoutObject(child, false);
711
712 Qt::Alignment alignment;
713 int hStretch = -1;
714 int vStretch = -1;
715 int row = -1;
716 int column = -1;
717 int span[2] = {1,1};
718 int &columnSpan = span[0];
719 int &rowSpan = span[1];
720
721 if (info) {
722 if (info->isRowSet() || info->isColumnSet()) {
723 // If row is specified and column is not specified (or vice versa),
724 // the unspecified component of the cell position should default to 0
725 // The getters do this for us, as they will return 0 for an
726 // unset (or negative) value.
727 // In addition, if \a rows is less than Layout.row, treat Layout.row as if it was not set
728 // This will basically make it find the next available cell (potentially wrapping to
729 // the next line). Likewise for an invalid Layout.column
730
731 if (gridSize.height() >= 0 && row >= gridSize.height()) {
732 qmlWarning(child) << QString::fromLatin1("Layout: row (%1) should be less than the number of rows (%2)").arg(info->row()).arg(rows());
733 } else {
734 row = info->row();
735 }
736
737 if (gridSize.width() >= 0 && info->column() >= gridSize.width()) {
738 qmlWarning(child) << QString::fromLatin1("Layout: column (%1) should be less than the number of columns (%2)").arg(info->column()).arg(columns());
739 } else {
740 column = info->column();
741 }
742 }
743 rowSpan = info->rowSpan();
744 columnSpan = info->columnSpan();
745 if (columnSpan < 1) {
746 qmlWarning(child) << "Layout: invalid column span: " << columnSpan;
747 return;
748
749 } else if (rowSpan < 1) {
750 qmlWarning(child) << "Layout: invalid row span: " << rowSpan;
751 return;
752 }
753 alignment = info->alignment();
754 hStretch = info->horizontalStretchFactor();
755 if (hStretch >= 0 && !info->fillWidth())
756 qmlWarning(child) << "horizontalStretchFactor requires fillWidth to also be set to true";
757 vStretch = info->verticalStretchFactor();
758 if (vStretch >= 0 && !info->fillHeight())
759 qmlWarning(child) << "verticalStretchFactor requires fillHeight to also be set to true";
760 }
761
762 Q_ASSERT(columnSpan >= 1);
763 Q_ASSERT(rowSpan >= 1);
764 const int sp = span[flowOrientation];
765 if (sp > flowBound)
766 return;
767
768 if (row >= 0)
769 nextRow = row;
770 if (column >= 0)
771 nextColumn = column;
772
773 if (row < 0 || column < 0) {
774 /* if row or column is not specified, find next position by
775 advancing in the flow direction until there is a cell that
776 can accept the item.
777
778 The acceptance rules are pretty simple, but complexity arises
779 when an item requires several cells (due to spans):
780 1. Check if the cells that the item will require
781 does not extend beyond columns (for LeftToRight) or
782 rows (for TopToBottom).
783 2. Check if the cells that the item will require is not already
784 taken by another item.
785 */
786 bool cellAcceptsItem;
787 while (true) {
788 // Check if the item does not span beyond the layout bound
789 cellAcceptsItem = (flowColumn + sp) <= flowBound;
790
791 // Check if all the required cells are not taken
792 for (int rs = 0; cellAcceptsItem && rs < rowSpan; ++rs) {
793 for (int cs = 0; cellAcceptsItem && cs < columnSpan; ++cs) {
794 if (d->engine.itemAt(nextRow + rs, nextColumn + cs)) {
795 cellAcceptsItem = false;
796 }
797 }
798 }
799 if (cellAcceptsItem)
800 break;
801 ++flowColumn;
802 if (flowColumn == flowBound) {
803 flowColumn = 0;
804 ++flowRow;
805 }
806 }
807 }
808 column = nextColumn;
809 row = nextRow;
810 QQuickGridLayoutItem *layoutItem = new QQuickGridLayoutItem(child, row, column, rowSpan, columnSpan, alignment);
811 if (hStretch >= 0)
812 layoutItem->setStretchFactor(hStretch, Qt::Horizontal);
813 if (vStretch >= 0)
814 layoutItem->setStretchFactor(vStretch, Qt::Vertical);
815
816 d->engine.insertItem(layoutItem, -1);
817 }
818}
819
820/**********************************
821 **
822 ** QQuickLinearLayout
823 **
824 **/
825QQuickLinearLayout::QQuickLinearLayout(Qt::Orientation orientation,
826 QQuickItem *parent /*= nullptr*/)
827 : QQuickGridLayoutBase(*new QQuickLinearLayoutPrivate, orientation, parent)
828{
829}
830
831/*!
832 \qmlproperty enumeration RowLayout::layoutDirection
833 \since QtQuick.Layouts 1.1
834
835 This property holds the layout direction of the row layout - it controls whether items are laid
836 out from left to right or right to left. If \c Qt.RightToLeft is specified,
837 left-aligned items will be right-aligned and right-aligned items will be left-aligned.
838
839 Possible values:
840
841 \value Qt.LeftToRight (default) Items are laid out from left to right.
842 \value Qt.RightToLeft Items are laid out from right to left
843
844 \sa GridLayout::layoutDirection, ColumnLayout::layoutDirection
845*/
846/*!
847 \qmlproperty enumeration ColumnLayout::layoutDirection
848 \since QtQuick.Layouts 1.1
849
850 This property holds the layout direction of the column layout - it
851 controls the horizontal alignment of items within the column.
852 If \c Qt.RightToLeft is specified,left-aligned items will be
853 right-aligned and right-aligned items will be left-aligned.
854
855 Possible values:
856
857 \value Qt.LeftToRight (default) Items are laid out from left to right.
858 \value Qt.RightToLeft Items are laid out from right to left
859
860 \sa GridLayout::layoutDirection, RowLayout::layoutDirection
861*/
862
863/*!
864 \qmlproperty bool RowLayout::uniformCellSizes
865 \since QtQuick.Layouts 6.6
866
867 If this property is set to \c true, the layout will force all cells to have
868 a uniform size.
869
870 \sa GridLayout::uniformCellWidths, GridLayout::uniformCellHeights, ColumnLayout::uniformCellSizes
871*/
872/*!
873 \qmlproperty bool ColumnLayout::uniformCellSizes
874 \since QtQuick.Layouts 6.6
875
876 If this property is set to \c true, the layout will force all cells to have
877 a uniform size.
878
879 \sa GridLayout::uniformCellWidths, GridLayout::uniformCellHeights, RowLayout::uniformCellSizes
880*/
881bool QQuickLinearLayout::uniformCellSizes() const
882{
883 Q_D(const QQuickLinearLayout);
884 Q_ASSERT(d->engine.uniformCellWidths() == d->engine.uniformCellHeights());
885 return d->engine.uniformCellWidths();
886}
887
888void QQuickLinearLayout::setUniformCellSizes(bool uniformCellSizes)
889{
890 Q_D(QQuickLinearLayout);
891 Q_ASSERT(d->engine.uniformCellWidths() == d->engine.uniformCellHeights());
892 if (d->engine.uniformCellHeights() == uniformCellSizes)
893 return;
894 d->engine.setUniformCellWidths(uniformCellSizes);
895 d->engine.setUniformCellHeights(uniformCellSizes);
896 invalidate();
897 emit uniformCellSizesChanged();
898}
899
900
901/*!
902 \qmlproperty real RowLayout::spacing
903
904 This property holds the spacing between each cell.
905 The default value is \c 5.
906*/
907/*!
908 \qmlproperty real ColumnLayout::spacing
909
910 This property holds the spacing between each cell.
911 The default value is \c 5.
912*/
913
914qreal QQuickLinearLayout::spacing() const
915{
916 Q_D(const QQuickLinearLayout);
917 return d->engine.spacing(d->orientation, d->styleInfo);
918}
919
920void QQuickLinearLayout::setSpacing(qreal space)
921{
922 Q_D(QQuickLinearLayout);
923 if (qt_is_nan(space) || spacing() == space)
924 return;
925
926 d->engine.setSpacing(space, Qt::Horizontal | Qt::Vertical);
927 invalidate();
928 emit spacingChanged();
929}
930
931void QQuickLinearLayout::insertLayoutItems()
932{
933 Q_D(QQuickLinearLayout);
934 const auto items = childItems();
935 for (QQuickItem *child : items) {
936 Q_ASSERT(child);
937 checkAnchors(child);
938
939 // Will skip all items with effective maximum width/height == 0
940 if (shouldIgnoreItem(child))
941 continue;
942 QQuickLayoutAttached *info = attachedLayoutObject(child, false);
943
944 Qt::Alignment alignment;
945 int hStretch = -1;
946 int vStretch = -1;
947 bool fillWidth = false;
948 bool fillHeight = false;
949 if (info) {
950 alignment = info->alignment();
951 hStretch = info->horizontalStretchFactor();
952 vStretch = info->verticalStretchFactor();
953 fillWidth = info->fillWidth();
954 fillHeight = info->fillHeight();
955 }
956
957 const int index = d->engine.rowCount(d->orientation);
958 d->engine.insertRow(index, d->orientation);
959
960 int gridRow = 0;
961 int gridColumn = index;
962 if (d->orientation == Qt::Vertical)
963 qSwap(gridRow, gridColumn);
964 QQuickGridLayoutItem *layoutItem = new QQuickGridLayoutItem(child, gridRow, gridColumn, 1, 1, alignment);
965
966 if (hStretch >= 0) {
967 if (!fillWidth)
968 qmlWarning(child) << "horizontalStretchFactor requires fillWidth to also be set to true";
969 layoutItem->setStretchFactor(hStretch, Qt::Horizontal);
970 }
971 if (vStretch >= 0) {
972 if (!fillHeight)
973 qmlWarning(child) << "verticalStretchFactor requires fillHeight to also be set to true";
974 layoutItem->setStretchFactor(vStretch, Qt::Vertical);
975 }
976 d->engine.insertItem(layoutItem, index);
977 }
978}
979
980QT_END_NAMESPACE
981
982#include "moc_qquicklinearlayout_p.cpp"
Combined button and popup list for selecting options.