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

source code of qtdeclarative/src/imports/layouts/qquicklinearlayout.cpp