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 QtWidgets 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 "qgridlayout.h"
41#include "qapplication.h"
42#include "qwidget.h"
43#include "qlist.h"
44#include "qsizepolicy.h"
45#include "qvector.h"
46#include "qvarlengtharray.h"
47#include "qlayoutengine_p.h"
48#include "qlayout_p.h"
49
50QT_BEGIN_NAMESPACE
51
52struct QGridLayoutSizeTriple
53{
54 QSize minS;
55 QSize hint;
56 QSize maxS;
57};
58
59/*
60 Three internal classes related to QGridLayout: (1) QGridBox is a
61 QLayoutItem with (row, column) information and (torow, tocolumn) information; (3) QGridLayoutData is
62 the internal representation of a QGridLayout.
63*/
64
65class QGridBox
66{
67public:
68 QGridBox(QLayoutItem *lit) { item_ = lit; }
69
70 QGridBox(const QLayout *l, QWidget *wid) { item_ = QLayoutPrivate::createWidgetItem(layout: l, widget: wid); }
71 ~QGridBox() { delete item_; }
72
73 QSize sizeHint() const { return item_->sizeHint(); }
74 QSize minimumSize() const { return item_->minimumSize(); }
75 QSize maximumSize() const { return item_->maximumSize(); }
76 Qt::Orientations expandingDirections() const { return item_->expandingDirections(); }
77 bool isEmpty() const { return item_->isEmpty(); }
78
79 bool hasHeightForWidth() const { return item_->hasHeightForWidth(); }
80 int heightForWidth(int w) const { return item_->heightForWidth(w); }
81
82 void setAlignment(Qt::Alignment a) { item_->setAlignment(a); }
83 void setGeometry(const QRect &r) { item_->setGeometry(r); }
84 Qt::Alignment alignment() const { return item_->alignment(); }
85 QLayoutItem *item() { return item_; }
86 void setItem(QLayoutItem *newitem) { item_ = newitem; }
87 QLayoutItem *takeItem() { QLayoutItem *i = item_; item_ = nullptr; return i; }
88
89 int hStretch() { return item_->widget() ?
90 item_->widget()->sizePolicy().horizontalStretch() : 0; }
91 int vStretch() { return item_->widget() ?
92 item_->widget()->sizePolicy().verticalStretch() : 0; }
93
94private:
95 friend class QGridLayoutPrivate;
96 friend class QGridLayout;
97
98 inline int toRow(int rr) const { return torow >= 0 ? torow : rr - 1; }
99 inline int toCol(int cc) const { return tocol >= 0 ? tocol : cc - 1; }
100
101 QLayoutItem *item_;
102 int row, col;
103 int torow, tocol;
104};
105
106class QGridLayoutPrivate : public QLayoutPrivate
107{
108 Q_DECLARE_PUBLIC(QGridLayout)
109public:
110 QGridLayoutPrivate();
111
112 void add(QGridBox*, int row, int col);
113 void add(QGridBox*, int row1, int row2, int col1, int col2);
114 QSize sizeHint(int hSpacing, int vSpacing) const;
115 QSize minimumSize(int hSpacing, int vSpacing) const;
116 QSize maximumSize(int hSpacing, int vSpacing) const;
117
118 Qt::Orientations expandingDirections(int hSpacing, int vSpacing) const;
119
120 void distribute(QRect rect, int hSpacing, int vSpacing);
121 inline int numRows() const { return rr; }
122 inline int numCols() const { return cc; }
123 inline void expand(int rows, int cols)
124 { setSize(rows: qMax(a: rows, b: rr), cols: qMax(a: cols, b: cc)); }
125 inline void setRowStretch(int r, int s)
126 { expand(rows: r + 1, cols: 0); rStretch[r] = s; setDirty(); }
127 inline void setColStretch(int c, int s)
128 { expand(rows: 0, cols: c + 1); cStretch[c] = s; setDirty(); }
129 inline int rowStretch(int r) const { return rStretch.at(i: r); }
130 inline int colStretch(int c) const { return cStretch.at(i: c); }
131 inline void setRowMinimumHeight(int r, int s)
132 { expand(rows: r + 1, cols: 0); rMinHeights[r] = s; setDirty(); }
133 inline void setColumnMinimumWidth(int c, int s)
134 { expand(rows: 0, cols: c + 1); cMinWidths[c] = s; setDirty(); }
135 inline int rowSpacing(int r) const { return rMinHeights.at(i: r); }
136 inline int colSpacing(int c) const { return cMinWidths.at(i: c); }
137
138 inline void setReversed(bool r, bool c) { hReversed = c; vReversed = r; }
139 inline bool horReversed() const { return hReversed; }
140 inline bool verReversed() const { return vReversed; }
141 inline void setDirty() { needRecalc = true; hfw_width = -1; }
142 inline bool isDirty() const { return needRecalc; }
143 bool hasHeightForWidth(int hSpacing, int vSpacing);
144 int heightForWidth(int width, int hSpacing, int vSpacing);
145 int minimumHeightForWidth(int width, int hSpacing, int vSpacing);
146
147 inline void getNextPos(int &row, int &col) { row = nextR; col = nextC; }
148 inline int count() const { return things.count(); }
149 QRect cellRect(int row, int col) const;
150
151 inline QLayoutItem *itemAt(int index) const {
152 if (index >= 0 && index < things.count())
153 return things.at(i: index)->item();
154 else
155 return nullptr;
156 }
157 inline QLayoutItem *takeAt(int index) {
158 Q_Q(QGridLayout);
159 if (index >= 0 && index < things.count()) {
160 if (QGridBox *b = things.takeAt(i: index)) {
161 QLayoutItem *item = b->takeItem();
162 if (QLayout *l = item->layout()) {
163 // sanity check in case the user passed something weird to QObject::setParent()
164 if (l->parent() == q)
165 l->setParent(nullptr);
166 }
167 delete b;
168 return item;
169 }
170 }
171 return nullptr;
172 }
173 QLayoutItem* replaceAt(int index, QLayoutItem *newitem) override
174 {
175 if (!newitem)
176 return nullptr;
177 QLayoutItem *item = nullptr;
178 QGridBox *b = things.value(i: index);
179 if (b) {
180 item = b->takeItem();
181 b->setItem(newitem);
182 }
183 return item;
184 }
185
186 void getItemPosition(int index, int *row, int *column, int *rowSpan, int *columnSpan) const {
187 if (index >= 0 && index < things.count()) {
188 const QGridBox *b = things.at(i: index);
189 int toRow = b->toRow(rr);
190 int toCol = b->toCol(cc);
191 *row = b->row;
192 *column = b->col;
193 *rowSpan = toRow - *row + 1;
194 *columnSpan = toCol - *column +1;
195 }
196 }
197 void deleteAll();
198
199private:
200 void setNextPosAfter(int r, int c);
201 void recalcHFW(int w);
202 void addHfwData(QGridBox *box, int width);
203 void init();
204 QSize findSize(int QLayoutStruct::*, int hSpacing, int vSpacing) const;
205 void addData(QGridBox *b, const QGridLayoutSizeTriple &sizes, bool r, bool c);
206 void setSize(int rows, int cols);
207 void setupSpacings(QVector<QLayoutStruct> &chain, QGridBox *grid[], int fixedSpacing,
208 Qt::Orientation orientation);
209 void setupLayoutData(int hSpacing, int vSpacing);
210 void setupHfwLayoutData();
211 void effectiveMargins(int *left, int *top, int *right, int *bottom) const;
212
213 int rr;
214 int cc;
215 QVector<QLayoutStruct> rowData;
216 QVector<QLayoutStruct> colData;
217 QVector<QLayoutStruct> *hfwData;
218 QVector<int> rStretch;
219 QVector<int> cStretch;
220 QVector<int> rMinHeights;
221 QVector<int> cMinWidths;
222 QList<QGridBox *> things;
223
224 int hfw_width;
225 int hfw_height;
226 int hfw_minheight;
227 int nextR;
228 int nextC;
229
230 int horizontalSpacing;
231 int verticalSpacing;
232 int leftMargin;
233 int topMargin;
234 int rightMargin;
235 int bottomMargin;
236
237 uint hReversed : 1;
238 uint vReversed : 1;
239 uint needRecalc : 1;
240 uint has_hfw : 1;
241 uint addVertical : 1;
242};
243
244void QGridLayoutPrivate::effectiveMargins(int *left, int *top, int *right, int *bottom) const
245{
246 int l = leftMargin;
247 int t = topMargin;
248 int r = rightMargin;
249 int b = bottomMargin;
250#ifdef Q_OS_MAC
251 int leftMost = INT_MAX;
252 int topMost = INT_MAX;
253 int rightMost = 0;
254 int bottomMost = 0;
255
256 QWidget *w = 0;
257 const int n = things.count();
258 for (int i = 0; i < n; ++i) {
259 QGridBox *box = things.at(i);
260 QLayoutItem *itm = box->item();
261 w = itm->widget();
262 if (w) {
263 bool visualHReversed = hReversed != (w->layoutDirection() == Qt::RightToLeft);
264 QRect lir = itm->geometry();
265 QRect wr = w->geometry();
266 if (box->col <= leftMost) {
267 if (box->col < leftMost) {
268 // we found an item even closer to the margin, discard.
269 leftMost = box->col;
270 if (visualHReversed)
271 r = rightMargin;
272 else
273 l = leftMargin;
274 }
275 if (visualHReversed) {
276 r = qMax(r, wr.right() - lir.right());
277 } else {
278 l = qMax(l, lir.left() - wr.left());
279 }
280 }
281 if (box->row <= topMost) {
282 if (box->row < topMost) {
283 // we found an item even closer to the margin, discard.
284 topMost = box->row;
285 if (vReversed)
286 b = bottomMargin;
287 else
288 t = topMargin;
289 }
290 if (vReversed)
291 b = qMax(b, wr.bottom() - lir.bottom());
292 else
293 t = qMax(t, lir.top() - wr.top());
294 }
295 if (box->toCol(cc) >= rightMost) {
296 if (box->toCol(cc) > rightMost) {
297 // we found an item even closer to the margin, discard.
298 rightMost = box->toCol(cc);
299 if (visualHReversed)
300 l = leftMargin;
301 else
302 r = rightMargin;
303 }
304 if (visualHReversed) {
305 l = qMax(l, lir.left() - wr.left());
306 } else {
307 r = qMax(r, wr.right() - lir.right());
308 }
309
310 }
311 if (box->toRow(rr) >= bottomMost) {
312 if (box->toRow(rr) > bottomMost) {
313 // we found an item even closer to the margin, discard.
314 bottomMost = box->toRow(rr);
315 if (vReversed)
316 t = topMargin;
317 else
318 b = bottomMargin;
319 }
320 if (vReversed)
321 t = qMax(t, lir.top() - wr.top());
322 else
323 b = qMax(b, wr.bottom() - lir.bottom());
324 }
325 }
326 }
327
328#endif
329 if (left)
330 *left = l;
331 if (top)
332 *top = t;
333 if (right)
334 *right = r;
335 if (bottom)
336 *bottom = b;
337}
338
339QGridLayoutPrivate::QGridLayoutPrivate()
340{
341 addVertical = false;
342 setDirty();
343 rr = cc = 0;
344 nextR = nextC = 0;
345 hfwData = nullptr;
346 hReversed = false;
347 vReversed = false;
348 horizontalSpacing = -1;
349 verticalSpacing = -1;
350}
351
352#if 0
353QGridLayoutPrivate::QGridLayoutPrivate(int nRows, int nCols)
354 : rowData(0), colData(0)
355{
356 init();
357 if (nRows < 0) {
358 nRows = 1;
359 addVertical = false;
360 }
361 if (nCols < 0) {
362 nCols = 1;
363 addVertical = true;
364 }
365 setSize(nRows, nCols);
366}
367#endif
368
369void QGridLayoutPrivate::deleteAll()
370{
371 while (!things.isEmpty())
372 delete things.takeFirst();
373 delete hfwData;
374}
375
376bool QGridLayoutPrivate::hasHeightForWidth(int hSpacing, int vSpacing)
377{
378 setupLayoutData(hSpacing, vSpacing);
379 return has_hfw;
380}
381
382/*
383 Assumes that setupLayoutData() has been called, and that
384 qGeomCalc() has filled in colData with appropriate values.
385*/
386void QGridLayoutPrivate::recalcHFW(int w)
387{
388 /*
389 Go through all children, using colData and heightForWidth()
390 and put the results in hfwData.
391 */
392 if (!hfwData)
393 hfwData = new QVector<QLayoutStruct>(rr);
394 setupHfwLayoutData();
395 QVector<QLayoutStruct> &rData = *hfwData;
396
397 int h = 0;
398 int mh = 0;
399 for (int r = 0; r < rr; r++) {
400 int spacing = rData.at(i: r).spacing;
401 h += rData.at(i: r).sizeHint + spacing;
402 mh += rData.at(i: r).minimumSize + spacing;
403 }
404
405 hfw_width = w;
406 hfw_height = qMin(a: QLAYOUTSIZE_MAX, b: h);
407 hfw_minheight = qMin(a: QLAYOUTSIZE_MAX, b: mh);
408}
409
410int QGridLayoutPrivate::heightForWidth(int w, int hSpacing, int vSpacing)
411{
412 setupLayoutData(hSpacing, vSpacing);
413 if (!has_hfw)
414 return -1;
415 int left, top, right, bottom;
416 effectiveMargins(left: &left, top: &top, right: &right, bottom: &bottom);
417
418 int hMargins = left + right;
419 if (w - hMargins != hfw_width) {
420 qGeomCalc(chain&: colData, start: 0, count: cc, pos: 0, space: w - hMargins);
421 recalcHFW(w: w - hMargins);
422 }
423 return hfw_height + top + bottom;
424}
425
426int QGridLayoutPrivate::minimumHeightForWidth(int w, int hSpacing, int vSpacing)
427{
428 (void)heightForWidth(w, hSpacing, vSpacing);
429 if (!has_hfw)
430 return -1;
431 int top, bottom;
432 effectiveMargins(left: nullptr, top: &top, right: nullptr, bottom: &bottom);
433 return hfw_minheight + top + bottom;
434}
435
436QSize QGridLayoutPrivate::findSize(int QLayoutStruct::*size, int hSpacing, int vSpacing) const
437{
438 QGridLayoutPrivate *that = const_cast<QGridLayoutPrivate*>(this);
439 that->setupLayoutData(hSpacing, vSpacing);
440
441 int w = 0;
442 int h = 0;
443
444 for (int r = 0; r < rr; r++)
445 h += rowData.at(i: r).*size + rowData.at(i: r).spacing;
446 for (int c = 0; c < cc; c++)
447 w += colData.at(i: c).*size + colData.at(i: c).spacing;
448
449 w = qMin(a: QLAYOUTSIZE_MAX, b: w);
450 h = qMin(a: QLAYOUTSIZE_MAX, b: h);
451
452 return QSize(w, h);
453}
454
455Qt::Orientations QGridLayoutPrivate::expandingDirections(int hSpacing, int vSpacing) const
456{
457 QGridLayoutPrivate *that = const_cast<QGridLayoutPrivate*>(this);
458 that->setupLayoutData(hSpacing, vSpacing);
459 Qt::Orientations ret;
460
461 for (int r = 0; r < rr; r++) {
462 if (rowData.at(i: r).expansive) {
463 ret |= Qt::Vertical;
464 break;
465 }
466 }
467 for (int c = 0; c < cc; c++) {
468 if (colData.at(i: c).expansive) {
469 ret |= Qt::Horizontal;
470 break;
471 }
472 }
473 return ret;
474}
475
476QSize QGridLayoutPrivate::sizeHint(int hSpacing, int vSpacing) const
477{
478 return findSize(size: &QLayoutStruct::sizeHint, hSpacing, vSpacing);
479}
480
481QSize QGridLayoutPrivate::maximumSize(int hSpacing, int vSpacing) const
482{
483 return findSize(size: &QLayoutStruct::maximumSize, hSpacing, vSpacing);
484}
485
486QSize QGridLayoutPrivate::minimumSize(int hSpacing, int vSpacing) const
487{
488 return findSize(size: &QLayoutStruct::minimumSize, hSpacing, vSpacing);
489}
490
491void QGridLayoutPrivate::setSize(int r, int c)
492{
493 if ((int)rowData.size() < r) {
494 int newR = qMax(a: r, b: rr * 2);
495 rowData.resize(size: newR);
496 rStretch.resize(size: newR);
497 rMinHeights.resize(size: newR);
498 for (int i = rr; i < newR; i++) {
499 rowData[i].init();
500 rowData[i].maximumSize = 0;
501 rowData[i].pos = 0;
502 rowData[i].size = 0;
503 rStretch[i] = 0;
504 rMinHeights[i] = 0;
505 }
506 }
507 if ((int)colData.size() < c) {
508 int newC = qMax(a: c, b: cc * 2);
509 colData.resize(size: newC);
510 cStretch.resize(size: newC);
511 cMinWidths.resize(size: newC);
512 for (int i = cc; i < newC; i++) {
513 colData[i].init();
514 colData[i].maximumSize = 0;
515 colData[i].pos = 0;
516 colData[i].size = 0;
517 cStretch[i] = 0;
518 cMinWidths[i] = 0;
519 }
520 }
521
522 if (hfwData && (int)hfwData->size() < r) {
523 delete hfwData;
524 hfwData = nullptr;
525 hfw_width = -1;
526 }
527 rr = r;
528 cc = c;
529}
530
531void QGridLayoutPrivate::setNextPosAfter(int row, int col)
532{
533 if (addVertical) {
534 if (col > nextC || (col == nextC && row >= nextR)) {
535 nextR = row + 1;
536 nextC = col;
537 if (nextR >= rr) {
538 nextR = 0;
539 nextC++;
540 }
541 }
542 } else {
543 if (row > nextR || (row == nextR && col >= nextC)) {
544 nextR = row;
545 nextC = col + 1;
546 if (nextC >= cc) {
547 nextC = 0;
548 nextR++;
549 }
550 }
551 }
552}
553
554void QGridLayoutPrivate::add(QGridBox *box, int row, int col)
555{
556 expand(rows: row + 1, cols: col + 1);
557 box->row = box->torow = row;
558 box->col = box->tocol = col;
559 things.append(t: box);
560 setDirty();
561 setNextPosAfter(row, col);
562}
563
564void QGridLayoutPrivate::add(QGridBox *box, int row1, int row2, int col1, int col2)
565{
566 if (Q_UNLIKELY(row2 >= 0 && row2 < row1))
567 qWarning(msg: "QGridLayout: Multi-cell fromRow greater than toRow");
568 if (Q_UNLIKELY(col2 >= 0 && col2 < col1))
569 qWarning(msg: "QGridLayout: Multi-cell fromCol greater than toCol");
570 if (row1 == row2 && col1 == col2) {
571 add(box, row: row1, col: col1);
572 return;
573 }
574 expand(rows: qMax(a: row1, b: row2) + 1, cols: qMax(a: col1, b: col2) + 1);
575 box->row = row1;
576 box->col = col1;
577
578 box->torow = row2;
579 box->tocol = col2;
580
581 things.append(t: box);
582 setDirty();
583 if (col2 < 0)
584 col2 = cc - 1;
585
586 setNextPosAfter(row: row2, col: col2);
587}
588
589void QGridLayoutPrivate::addData(QGridBox *box, const QGridLayoutSizeTriple &sizes, bool r, bool c)
590{
591 const QWidget *widget = box->item()->widget();
592
593 if (box->isEmpty() && widget)
594 return;
595
596 if (c) {
597 QLayoutStruct *data = &colData[box->col];
598 if (!cStretch.at(i: box->col))
599 data->stretch = qMax(a: data->stretch, b: box->hStretch());
600 data->sizeHint = qMax(a: sizes.hint.width(), b: data->sizeHint);
601 data->minimumSize = qMax(a: sizes.minS.width(), b: data->minimumSize);
602
603 qMaxExpCalc(max&: data->maximumSize, exp&: data->expansive, empty&: data->empty, boxmax: sizes.maxS.width(),
604 boxexp: box->expandingDirections() & Qt::Horizontal, boxempty: box->isEmpty());
605 }
606 if (r) {
607 QLayoutStruct *data = &rowData[box->row];
608 if (!rStretch.at(i: box->row))
609 data->stretch = qMax(a: data->stretch, b: box->vStretch());
610 data->sizeHint = qMax(a: sizes.hint.height(), b: data->sizeHint);
611 data->minimumSize = qMax(a: sizes.minS.height(), b: data->minimumSize);
612
613 qMaxExpCalc(max&: data->maximumSize, exp&: data->expansive, empty&: data->empty, boxmax: sizes.maxS.height(),
614 boxexp: box->expandingDirections() & Qt::Vertical, boxempty: box->isEmpty());
615 }
616}
617
618static void initEmptyMultiBox(QVector<QLayoutStruct> &chain, int start, int end)
619{
620 for (int i = start; i <= end; i++) {
621 QLayoutStruct *data = &chain[i];
622 if (data->empty && data->maximumSize == 0) // truly empty box
623 data->maximumSize = QWIDGETSIZE_MAX;
624 data->empty = false;
625 }
626}
627
628static void distributeMultiBox(QVector<QLayoutStruct> &chain, int start, int end, int minSize,
629 int sizeHint, QVector<int> &stretchArray, int stretch)
630{
631 int i;
632 int w = 0;
633 int wh = 0;
634 int max = 0;
635
636 for (i = start; i <= end; i++) {
637 QLayoutStruct *data = &chain[i];
638 w += data->minimumSize;
639 wh += data->sizeHint;
640 max += data->maximumSize;
641 if (stretchArray.at(i) == 0)
642 data->stretch = qMax(a: data->stretch, b: stretch);
643
644 if (i != end) {
645 int spacing = data->spacing;
646 w += spacing;
647 wh += spacing;
648 max += spacing;
649 }
650 }
651
652 if (max < minSize) { // implies w < minSize
653 /*
654 We must increase the maximum size of at least one of the
655 items. qGeomCalc() will put the extra space in between the
656 items. We must recover that extra space and put it
657 somewhere. It does not really matter where, since the user
658 can always specify stretch factors and avoid this code.
659 */
660 qGeomCalc(chain, start, count: end - start + 1, pos: 0, space: minSize);
661 int pos = 0;
662 for (i = start; i <= end; i++) {
663 QLayoutStruct *data = &chain[i];
664 int nextPos = (i == end) ? minSize : chain.at(i: i + 1).pos;
665 int realSize = nextPos - pos;
666 if (i != end)
667 realSize -= data->spacing;
668 if (data->minimumSize < realSize)
669 data->minimumSize = realSize;
670 if (data->maximumSize < data->minimumSize)
671 data->maximumSize = data->minimumSize;
672 pos = nextPos;
673 }
674 } else if (w < minSize) {
675 qGeomCalc(chain, start, count: end - start + 1, pos: 0, space: minSize);
676 for (i = start; i <= end; i++) {
677 QLayoutStruct *data = &chain[i];
678 if (data->minimumSize < data->size)
679 data->minimumSize = data->size;
680 }
681 }
682
683 if (wh < sizeHint) {
684 qGeomCalc(chain, start, count: end - start + 1, pos: 0, space: sizeHint);
685 for (i = start; i <= end; i++) {
686 QLayoutStruct *data = &chain[i];
687 if (data->sizeHint < data->size)
688 data->sizeHint = data->size;
689 }
690 }
691}
692
693static QGridBox *&gridAt(QGridBox *grid[], int r, int c, int cc,
694 Qt::Orientation orientation = Qt::Vertical)
695{
696 if (orientation == Qt::Horizontal)
697 qSwap(value1&: r, value2&: c);
698 return grid[(r * cc) + c];
699}
700
701void QGridLayoutPrivate::setupSpacings(QVector<QLayoutStruct> &chain,
702 QGridBox *grid[], int fixedSpacing,
703 Qt::Orientation orientation)
704{
705 Q_Q(QGridLayout);
706 int numRows = rr; // or columns if orientation is horizontal
707 int numColumns = cc; // or rows if orientation is horizontal
708
709 if (orientation == Qt::Horizontal) {
710 qSwap(value1&: numRows, value2&: numColumns);
711 }
712
713 QStyle *style = nullptr;
714 if (fixedSpacing < 0) {
715 if (QWidget *parentWidget = q->parentWidget())
716 style = parentWidget->style();
717 }
718
719 for (int c = 0; c < numColumns; ++c) {
720 QGridBox *previousBox = nullptr;
721 int previousRow = -1; // previous *non-empty* row
722
723 for (int r = 0; r < numRows; ++r) {
724 if (chain.at(i: r).empty)
725 continue;
726
727 QGridBox *box = gridAt(grid, r, c, cc, orientation);
728 if (previousRow != -1 && (!box || previousBox != box)) {
729 int spacing = fixedSpacing;
730 if (spacing < 0) {
731 QSizePolicy::ControlTypes controlTypes1 = QSizePolicy::DefaultType;
732 QSizePolicy::ControlTypes controlTypes2 = QSizePolicy::DefaultType;
733 if (previousBox)
734 controlTypes1 = previousBox->item()->controlTypes();
735 if (box)
736 controlTypes2 = box->item()->controlTypes();
737
738 if ((orientation == Qt::Horizontal && hReversed)
739 || (orientation == Qt::Vertical && vReversed))
740 qSwap(value1&: controlTypes1, value2&: controlTypes2);
741
742 if (style)
743 spacing = style->combinedLayoutSpacing(controls1: controlTypes1, controls2: controlTypes2,
744 orientation, option: nullptr, widget: q->parentWidget());
745 } else {
746 if (orientation == Qt::Vertical) {
747 QGridBox *sibling = vReversed ? previousBox : box;
748 if (sibling) {
749 if (sibling->item()->isEmpty()) {
750 spacing = 0;
751 } else {
752 QWidget *wid = sibling->item()->widget();
753 if (wid)
754 spacing = qMax(a: spacing, b: sibling->item()->geometry().top() - wid->geometry().top());
755 }
756 }
757 }
758 }
759
760 if (spacing > chain.at(i: previousRow).spacing)
761 chain[previousRow].spacing = spacing;
762 }
763
764 previousBox = box;
765 previousRow = r;
766 }
767 }
768}
769
770//#define QT_LAYOUT_DISABLE_CACHING
771
772void QGridLayoutPrivate::setupLayoutData(int hSpacing, int vSpacing)
773{
774 Q_Q(QGridLayout);
775
776#ifndef QT_LAYOUT_DISABLE_CACHING
777 if (!needRecalc)
778 return;
779#endif
780 has_hfw = false;
781 int i;
782
783 for (i = 0; i < rr; i++) {
784 rowData[i].init(stretchFactor: rStretch.at(i), minSize: rMinHeights.at(i));
785 rowData[i].maximumSize = rStretch.at(i) ? QLAYOUTSIZE_MAX : rMinHeights.at(i);
786 }
787 for (i = 0; i < cc; i++) {
788 colData[i].init(stretchFactor: cStretch.at(i), minSize: cMinWidths.at(i));
789 colData[i].maximumSize = cStretch.at(i) ? QLAYOUTSIZE_MAX : cMinWidths.at(i);
790 }
791
792 int n = things.size();
793 QVarLengthArray<QGridLayoutSizeTriple> sizes(n);
794
795 bool has_multi = false;
796
797 /*
798 Grid of items. We use it to determine which items are
799 adjacent to which and compute the spacings correctly.
800 */
801 QVarLengthArray<QGridBox *> grid(rr * cc);
802 memset(s: grid.data(), c: 0, n: rr * cc * sizeof(QGridBox *));
803
804 /*
805 Initialize 'sizes' and 'grid' data structures, and insert
806 non-spanning items to our row and column data structures.
807 */
808 for (i = 0; i < n; ++i) {
809 QGridBox * const box = things.at(i);
810 sizes[i].minS = box->minimumSize();
811 sizes[i].hint = box->sizeHint();
812 sizes[i].maxS = box->maximumSize();
813
814 if (box->hasHeightForWidth())
815 has_hfw = true;
816
817 if (box->row == box->toRow(rr)) {
818 addData(box, sizes: sizes[i], r: true, c: false);
819 } else {
820 initEmptyMultiBox(chain&: rowData, start: box->row, end: box->toRow(rr));
821 has_multi = true;
822 }
823
824 if (box->col == box->toCol(cc)) {
825 addData(box, sizes: sizes[i], r: false, c: true);
826 } else {
827 initEmptyMultiBox(chain&: colData, start: box->col, end: box->toCol(cc));
828 has_multi = true;
829 }
830
831 for (int r = box->row; r <= box->toRow(rr); ++r) {
832 for (int c = box->col; c <= box->toCol(cc); ++c) {
833 gridAt(grid: grid.data(), r, c, cc) = box;
834 }
835 }
836 }
837
838 setupSpacings(chain&: colData, grid: grid.data(), fixedSpacing: hSpacing, orientation: Qt::Horizontal);
839 setupSpacings(chain&: rowData, grid: grid.data(), fixedSpacing: vSpacing, orientation: Qt::Vertical);
840
841 /*
842 Insert multicell items to our row and column data structures.
843 This must be done after the non-spanning items to obtain a
844 better distribution in distributeMultiBox().
845 */
846 if (has_multi) {
847 for (i = 0; i < n; ++i) {
848 QGridBox * const box = things.at(i);
849
850 if (box->row != box->toRow(rr))
851 distributeMultiBox(chain&: rowData, start: box->row, end: box->toRow(rr), minSize: sizes[i].minS.height(),
852 sizeHint: sizes[i].hint.height(), stretchArray&: rStretch, stretch: box->vStretch());
853 if (box->col != box->toCol(cc))
854 distributeMultiBox(chain&: colData, start: box->col, end: box->toCol(cc), minSize: sizes[i].minS.width(),
855 sizeHint: sizes[i].hint.width(), stretchArray&: cStretch, stretch: box->hStretch());
856 }
857 }
858
859 for (i = 0; i < rr; i++)
860 rowData[i].expansive = rowData.at(i).expansive || rowData.at(i).stretch > 0;
861 for (i = 0; i < cc; i++)
862 colData[i].expansive = colData.at(i).expansive || colData.at(i).stretch > 0;
863
864 q->getContentsMargins(left: &leftMargin, top: &topMargin, right: &rightMargin, bottom: &bottomMargin);
865
866 needRecalc = false;
867}
868
869void QGridLayoutPrivate::addHfwData(QGridBox *box, int width)
870{
871 QVector<QLayoutStruct> &rData = *hfwData;
872 if (box->hasHeightForWidth()) {
873 int hint = box->heightForWidth(w: width);
874 rData[box->row].sizeHint = qMax(a: hint, b: rData.at(i: box->row).sizeHint);
875 rData[box->row].minimumSize = qMax(a: hint, b: rData.at(i: box->row).minimumSize);
876 } else {
877 QSize hint = box->sizeHint();
878 QSize minS = box->minimumSize();
879 rData[box->row].sizeHint = qMax(a: hint.height(), b: rData.at(i: box->row).sizeHint);
880 rData[box->row].minimumSize = qMax(a: minS.height(), b: rData.at(i: box->row).minimumSize);
881 }
882}
883
884/*
885 Similar to setupLayoutData(), but uses heightForWidth(colData)
886 instead of sizeHint(). Assumes that setupLayoutData() and
887 qGeomCalc(colData) has been called.
888*/
889void QGridLayoutPrivate::setupHfwLayoutData()
890{
891 QVector<QLayoutStruct> &rData = *hfwData;
892 for (int i = 0; i < rr; i++) {
893 rData[i] = rowData.at(i);
894 rData[i].minimumSize = rData[i].sizeHint = rMinHeights.at(i);
895 }
896
897 for (int pass = 0; pass < 2; ++pass) {
898 for (int i = 0; i < things.size(); ++i) {
899 QGridBox *box = things.at(i);
900 int r1 = box->row;
901 int c1 = box->col;
902 int r2 = box->toRow(rr);
903 int c2 = box->toCol(cc);
904 int w = colData.at(i: c2).pos + colData.at(i: c2).size - colData.at(i: c1).pos;
905
906 if (r1 == r2) {
907 if (pass == 0)
908 addHfwData(box, width: w);
909 } else {
910 if (pass == 0) {
911 initEmptyMultiBox(chain&: rData, start: r1, end: r2);
912 } else {
913 QSize hint = box->sizeHint();
914 QSize min = box->minimumSize();
915 if (box->hasHeightForWidth()) {
916 int hfwh = box->heightForWidth(w);
917 if (hfwh > hint.height())
918 hint.setHeight(hfwh);
919 if (hfwh > min.height())
920 min.setHeight(hfwh);
921 }
922 distributeMultiBox(chain&: rData, start: r1, end: r2, minSize: min.height(), sizeHint: hint.height(),
923 stretchArray&: rStretch, stretch: box->vStretch());
924 }
925 }
926 }
927 }
928 for (int i = 0; i < rr; i++)
929 rData[i].expansive = rData.at(i).expansive || rData.at(i).stretch > 0;
930}
931
932void QGridLayoutPrivate::distribute(QRect r, int hSpacing, int vSpacing)
933{
934 Q_Q(QGridLayout);
935 bool visualHReversed = hReversed;
936 QWidget *parent = q->parentWidget();
937 if (parent && parent->isRightToLeft())
938 visualHReversed = !visualHReversed;
939
940 setupLayoutData(hSpacing, vSpacing);
941
942 int left, top, right, bottom;
943 effectiveMargins(left: &left, top: &top, right: &right, bottom: &bottom);
944 r.adjust(dx1: +left, dy1: +top, dx2: -right, dy2: -bottom);
945
946 qGeomCalc(chain&: colData, start: 0, count: cc, pos: r.x(), space: r.width());
947 QVector<QLayoutStruct> *rDataPtr;
948 if (has_hfw) {
949 recalcHFW(w: r.width());
950 qGeomCalc(chain&: *hfwData, start: 0, count: rr, pos: r.y(), space: r.height());
951 rDataPtr = hfwData;
952 } else {
953 qGeomCalc(chain&: rowData, start: 0, count: rr, pos: r.y(), space: r.height());
954 rDataPtr = &rowData;
955 }
956 QVector<QLayoutStruct> &rData = *rDataPtr;
957 int i;
958
959 bool reverse = ((r.bottom() > rect.bottom()) || (r.bottom() == rect.bottom()
960 && ((r.right() > rect.right()) != visualHReversed)));
961 int n = things.size();
962 for (i = 0; i < n; ++i) {
963 QGridBox *box = things.at(i: reverse ? n-i-1 : i);
964 int r2 = box->toRow(rr);
965 int c2 = box->toCol(cc);
966
967 int x = colData.at(i: box->col).pos;
968 int y = rData.at(i: box->row).pos;
969 int x2p = colData.at(i: c2).pos + colData.at(i: c2).size; // x2+1
970 int y2p = rData.at(i: r2).pos + rData.at(i: r2).size; // y2+1
971 int w = x2p - x;
972 int h = y2p - y;
973
974 if (visualHReversed)
975 x = r.left() + r.right() - x - w + 1;
976 if (vReversed)
977 y = r.top() + r.bottom() - y - h + 1;
978
979 box->setGeometry(QRect(x, y, w, h));
980 }
981}
982
983QRect QGridLayoutPrivate::cellRect(int row, int col) const
984{
985 if (row < 0 || row >= rr || col < 0 || col >= cc)
986 return QRect();
987
988 const QVector<QLayoutStruct> *rDataPtr;
989 if (has_hfw && hfwData)
990 rDataPtr = hfwData;
991 else
992 rDataPtr = &rowData;
993 return QRect(colData.at(i: col).pos, rDataPtr->at(i: row).pos,
994 colData.at(i: col).size, rDataPtr->at(i: row).size);
995}
996
997/*!
998 \class QGridLayout
999
1000 \brief The QGridLayout class lays out widgets in a grid.
1001
1002 \ingroup geomanagement
1003 \inmodule QtWidgets
1004
1005 QGridLayout takes the space made available to it (by its parent
1006 layout or by the parentWidget()), divides it up into rows and
1007 columns, and puts each widget it manages into the correct cell.
1008
1009 Columns and rows behave identically; we will discuss columns, but
1010 there are equivalent functions for rows.
1011
1012 Each column has a minimum width and a stretch factor. The minimum
1013 width is the greatest of that set using setColumnMinimumWidth() and the
1014 minimum width of each widget in that column. The stretch factor is
1015 set using setColumnStretch() and determines how much of the available
1016 space the column will get over and above its necessary minimum.
1017
1018 Normally, each managed widget or layout is put into a cell of its
1019 own using addWidget(). It is also possible for a widget to occupy
1020 multiple cells using the row and column spanning overloads of
1021 addItem() and addWidget(). If you do this, QGridLayout will guess
1022 how to distribute the size over the columns/rows (based on the
1023 stretch factors).
1024
1025 To remove a widget from a layout, call removeWidget(). Calling
1026 QWidget::hide() on a widget also effectively removes the widget
1027 from the layout until QWidget::show() is called.
1028
1029 This illustration shows a fragment of a dialog with a five-column,
1030 three-row grid (the grid is shown overlaid in magenta):
1031
1032 \image qgridlayout.png A grid layout
1033
1034 Columns 0, 2 and 4 in this dialog fragment are made up of a
1035 QLabel, a QLineEdit, and a QListBox. Columns 1 and 3 are
1036 placeholders made with setColumnMinimumWidth(). Row 0 consists of three
1037 QLabel objects, row 1 of three QLineEdit objects and row 2 of
1038 three QListBox objects. We used placeholder columns (1 and 3) to
1039 get the right amount of space between the columns.
1040
1041 Note that the columns and rows are not equally wide or tall. If
1042 you want two columns to have the same width, you must set their
1043 minimum widths and stretch factors to be the same yourself. You do
1044 this using setColumnMinimumWidth() and setColumnStretch().
1045
1046 If the QGridLayout is not the top-level layout (i.e. does not
1047 manage all of the widget's area and children), you must add it to
1048 its parent layout when you create it, but before you do anything
1049 with it. The normal way to add a layout is by calling
1050 addLayout() on the parent layout.
1051
1052 Once you have added your layout you can start putting widgets and
1053 other layouts into the cells of your grid layout using
1054 addWidget(), addItem(), and addLayout().
1055
1056 QGridLayout also includes two margin widths:
1057 the \l{getContentsMargins()}{contents margin} and the spacing().
1058 The contents margin is the width of the reserved space along each
1059 of the QGridLayout's four sides. The spacing() is the width of the
1060 automatically allocated spacing between neighboring boxes.
1061
1062 The default contents margin values are provided by the
1063 \l{QStyle::pixelMetric()}{style}. The default value Qt styles specify
1064 is 9 for child widgets and 11 for windows. The spacing defaults to the same as
1065 the margin width for a top-level layout, or to the same as the
1066 parent layout.
1067
1068 \sa QBoxLayout, QStackedLayout, {Layout Management}, {Basic Layouts Example}
1069*/
1070
1071
1072/*!
1073 Constructs a new QGridLayout with parent widget, \a parent. The
1074 layout has one row and one column initially, and will expand when
1075 new items are inserted.
1076
1077 The layout is set directly as the top-level layout for \a parent.
1078 There can be only one top-level layout for a widget. It is returned
1079 by QWidget::layout().
1080
1081 \sa QWidget::setLayout()
1082*/
1083QGridLayout::QGridLayout(QWidget *parent)
1084 : QLayout(*new QGridLayoutPrivate, nullptr, parent)
1085{
1086 Q_D(QGridLayout);
1087 d->expand(rows: 1, cols: 1);
1088}
1089
1090/*!
1091 Constructs a new grid layout.
1092
1093 You must insert this grid into another layout. You can insert
1094 widgets and layouts into this layout at any time, but laying out
1095 will not be performed before this is inserted into another layout.
1096*/
1097QGridLayout::QGridLayout()
1098 : QLayout(*new QGridLayoutPrivate, nullptr, nullptr)
1099{
1100 Q_D(QGridLayout);
1101 d->expand(rows: 1, cols: 1);
1102}
1103
1104
1105
1106
1107/*!
1108\internal (mostly)
1109
1110Sets the positioning mode used by addItem(). If \a orient is
1111Qt::Horizontal, this layout is expanded to \a n columns, and items
1112will be added columns-first. Otherwise it is expanded to \a n rows and
1113items will be added rows-first.
1114*/
1115
1116void QGridLayout::setDefaultPositioning(int n, Qt::Orientation orient)
1117{
1118 Q_D(QGridLayout);
1119 if (orient == Qt::Horizontal) {
1120 d->expand(rows: 1, cols: n);
1121 d->addVertical = false;
1122 } else {
1123 d->expand(rows: n,cols: 1);
1124 d->addVertical = true;
1125 }
1126}
1127
1128
1129/*!
1130 Destroys the grid layout. Geometry management is terminated if
1131 this is a top-level grid.
1132
1133 The layout's widgets aren't destroyed.
1134*/
1135QGridLayout::~QGridLayout()
1136{
1137 Q_D(QGridLayout);
1138 d->deleteAll();
1139}
1140
1141/*!
1142 \property QGridLayout::horizontalSpacing
1143 \brief the spacing between widgets that are laid out side by side
1144 \since 4.3
1145
1146 If no value is explicitly set, the layout's horizontal spacing is
1147 inherited from the parent layout, or from the style settings for
1148 the parent widget.
1149
1150 \sa verticalSpacing, QStyle::pixelMetric(), {QStyle::}{PM_LayoutHorizontalSpacing}
1151*/
1152void QGridLayout::setHorizontalSpacing(int spacing)
1153{
1154 Q_D(QGridLayout);
1155 d->horizontalSpacing = spacing;
1156 invalidate();
1157}
1158
1159int QGridLayout::horizontalSpacing() const
1160{
1161 Q_D(const QGridLayout);
1162 if (d->horizontalSpacing >= 0) {
1163 return d->horizontalSpacing;
1164 } else {
1165 return qSmartSpacing(layout: this, pm: QStyle::PM_LayoutHorizontalSpacing);
1166 }
1167}
1168
1169/*!
1170 \property QGridLayout::verticalSpacing
1171 \brief the spacing between widgets that are laid out on top of each other
1172 \since 4.3
1173
1174 If no value is explicitly set, the layout's vertical spacing is
1175 inherited from the parent layout, or from the style settings for
1176 the parent widget.
1177
1178 \sa horizontalSpacing, QStyle::pixelMetric(), {QStyle::}{PM_LayoutHorizontalSpacing}
1179*/
1180void QGridLayout::setVerticalSpacing(int spacing)
1181{
1182 Q_D(QGridLayout);
1183 d->verticalSpacing = spacing;
1184 invalidate();
1185}
1186
1187int QGridLayout::verticalSpacing() const
1188{
1189 Q_D(const QGridLayout);
1190 if (d->verticalSpacing >= 0) {
1191 return d->verticalSpacing;
1192 } else {
1193 return qSmartSpacing(layout: this, pm: QStyle::PM_LayoutVerticalSpacing);
1194 }
1195}
1196
1197/*!
1198 This function sets both the vertical and horizontal spacing to
1199 \a spacing.
1200
1201 \sa setVerticalSpacing(), setHorizontalSpacing()
1202*/
1203void QGridLayout::setSpacing(int spacing)
1204{
1205 Q_D(QGridLayout);
1206 d->horizontalSpacing = d->verticalSpacing = spacing;
1207 invalidate();
1208}
1209
1210/*!
1211 If the vertical spacing is equal to the horizontal spacing,
1212 this function returns that value; otherwise it return -1.
1213
1214 \sa setSpacing(), verticalSpacing(), horizontalSpacing()
1215*/
1216int QGridLayout::spacing() const
1217{
1218 int hSpacing = horizontalSpacing();
1219 if (hSpacing == verticalSpacing()) {
1220 return hSpacing;
1221 } else {
1222 return -1;
1223 }
1224}
1225
1226/*!
1227 Returns the number of rows in this grid.
1228*/
1229int QGridLayout::rowCount() const
1230{
1231 Q_D(const QGridLayout);
1232 return d->numRows();
1233}
1234
1235/*!
1236 Returns the number of columns in this grid.
1237*/
1238int QGridLayout::columnCount() const
1239{
1240 Q_D(const QGridLayout);
1241 return d->numCols();
1242}
1243
1244/*!
1245 \reimp
1246*/
1247QSize QGridLayout::sizeHint() const
1248{
1249 Q_D(const QGridLayout);
1250 QSize result(d->sizeHint(hSpacing: horizontalSpacing(), vSpacing: verticalSpacing()));
1251 int left, top, right, bottom;
1252 d->effectiveMargins(left: &left, top: &top, right: &right, bottom: &bottom);
1253 result += QSize(left + right, top + bottom);
1254 return result;
1255}
1256
1257/*!
1258 \reimp
1259*/
1260QSize QGridLayout::minimumSize() const
1261{
1262 Q_D(const QGridLayout);
1263 QSize result(d->minimumSize(hSpacing: horizontalSpacing(), vSpacing: verticalSpacing()));
1264 int left, top, right, bottom;
1265 d->effectiveMargins(left: &left, top: &top, right: &right, bottom: &bottom);
1266 result += QSize(left + right, top + bottom);
1267 return result;
1268}
1269
1270/*!
1271 \reimp
1272*/
1273QSize QGridLayout::maximumSize() const
1274{
1275 Q_D(const QGridLayout);
1276
1277 QSize s = d->maximumSize(hSpacing: horizontalSpacing(), vSpacing: verticalSpacing());
1278 int left, top, right, bottom;
1279 d->effectiveMargins(left: &left, top: &top, right: &right, bottom: &bottom);
1280 s += QSize(left + right, top + bottom);
1281 s = s.boundedTo(otherSize: QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX));
1282 if (alignment() & Qt::AlignHorizontal_Mask)
1283 s.setWidth(QLAYOUTSIZE_MAX);
1284 if (alignment() & Qt::AlignVertical_Mask)
1285 s.setHeight(QLAYOUTSIZE_MAX);
1286 return s;
1287}
1288
1289/*!
1290 \reimp
1291*/
1292bool QGridLayout::hasHeightForWidth() const
1293{
1294 return const_cast<QGridLayout*>(this)->d_func()->hasHeightForWidth(hSpacing: horizontalSpacing(), vSpacing: verticalSpacing());
1295}
1296
1297/*!
1298 \reimp
1299*/
1300int QGridLayout::heightForWidth(int w) const
1301{
1302 Q_D(const QGridLayout);
1303 QGridLayoutPrivate *dat = const_cast<QGridLayoutPrivate *>(d);
1304 return dat->heightForWidth(w, hSpacing: horizontalSpacing(), vSpacing: verticalSpacing());
1305}
1306
1307/*!
1308 \reimp
1309*/
1310int QGridLayout::minimumHeightForWidth(int w) const
1311{
1312 Q_D(const QGridLayout);
1313 QGridLayoutPrivate *dat = const_cast<QGridLayoutPrivate *>(d);
1314 return dat->minimumHeightForWidth(w, hSpacing: horizontalSpacing(), vSpacing: verticalSpacing());
1315}
1316
1317/*!
1318 \reimp
1319*/
1320int QGridLayout::count() const
1321{
1322 Q_D(const QGridLayout);
1323 return d->count();
1324}
1325
1326
1327/*!
1328 \reimp
1329*/
1330QLayoutItem *QGridLayout::itemAt(int index) const
1331{
1332 Q_D(const QGridLayout);
1333 return d->itemAt(index);
1334}
1335
1336/*!
1337 \since 4.4
1338
1339 Returns the layout item that occupies cell (\a row, \a column), or
1340 \nullptr if the cell is empty.
1341
1342 \sa getItemPosition(), indexOf()
1343*/
1344QLayoutItem *QGridLayout::itemAtPosition(int row, int column) const
1345{
1346 Q_D(const QGridLayout);
1347 int n = d->things.count();
1348 for (int i = 0; i < n; ++i) {
1349 QGridBox *box = d->things.at(i);
1350 if (row >= box->row && row <= box->toRow(rr: d->rr)
1351 && column >= box->col && column <= box->toCol(cc: d->cc)) {
1352 return box->item();
1353 }
1354 }
1355 return nullptr;
1356}
1357
1358/*!
1359 \reimp
1360*/
1361QLayoutItem *QGridLayout::takeAt(int index)
1362{
1363 Q_D(QGridLayout);
1364 return d->takeAt(index);
1365}
1366
1367/*!
1368 Returns the position information of the item with the given \a index.
1369
1370 The variables passed as \a row and \a column are updated with the position of the
1371 item in the layout, and the \a rowSpan and \a columnSpan variables are updated
1372 with the vertical and horizontal spans of the item.
1373
1374 \sa itemAtPosition(), itemAt()
1375*/
1376void QGridLayout::getItemPosition(int index, int *row, int *column, int *rowSpan, int *columnSpan) const
1377{
1378 Q_D(const QGridLayout);
1379 d->getItemPosition(index, row, column, rowSpan, columnSpan);
1380}
1381
1382
1383/*!
1384 \reimp
1385*/
1386void QGridLayout::setGeometry(const QRect &rect)
1387{
1388 Q_D(QGridLayout);
1389 if (d->isDirty() || rect != geometry()) {
1390 QRect cr = alignment() ? alignmentRect(rect) : rect;
1391 d->distribute(r: cr, hSpacing: horizontalSpacing(), vSpacing: verticalSpacing());
1392 QLayout::setGeometry(rect);
1393 }
1394}
1395
1396/*!
1397 Returns the geometry of the cell with row \a row and column \a column
1398 in the grid. Returns an invalid rectangle if \a row or \a column is
1399 outside the grid.
1400
1401 \warning in the current version of Qt this function does not
1402 return valid results until setGeometry() has been called, i.e.
1403 after the parentWidget() is visible.
1404*/
1405QRect QGridLayout::cellRect(int row, int column) const
1406{
1407 Q_D(const QGridLayout);
1408 return d->cellRect(row, col: column);
1409}
1410
1411/*!
1412 \reimp
1413*/
1414void QGridLayout::addItem(QLayoutItem *item)
1415{
1416 Q_D(QGridLayout);
1417 int r, c;
1418 d->getNextPos(row&: r, col&: c);
1419 addItem(item, row: r, column: c);
1420}
1421
1422/*!
1423 Adds \a item at position \a row, \a column, spanning \a rowSpan
1424 rows and \a columnSpan columns, and aligns it according to \a
1425 alignment. If \a rowSpan and/or \a columnSpan is -1, then the item
1426 will extend to the bottom and/or right edge, respectively. The
1427 layout takes ownership of the \a item.
1428
1429 \warning Do not use this function to add child layouts or child
1430 widget items. Use addLayout() or addWidget() instead.
1431*/
1432void QGridLayout::addItem(QLayoutItem *item, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment)
1433{
1434 Q_D(QGridLayout);
1435 QGridBox *b = new QGridBox(item);
1436 b->setAlignment(alignment);
1437 d->add(box: b, row1: row, row2: (rowSpan < 0) ? -1 : row + rowSpan - 1, col1: column, col2: (columnSpan < 0) ? -1 : column + columnSpan - 1);
1438 invalidate();
1439}
1440
1441/*!
1442 Adds the given \a widget to the cell grid at \a row, \a column. The
1443 top-left position is (0, 0) by default.
1444
1445 The alignment is specified by \a alignment. The default
1446 alignment is 0, which means that the widget fills the entire cell.
1447
1448*/
1449void QGridLayout::addWidget(QWidget *widget, int row, int column, Qt::Alignment alignment)
1450{
1451 Q_D(QGridLayout);
1452 if (!d->checkWidget(widget))
1453 return;
1454 if (Q_UNLIKELY(row < 0 || column < 0)) {
1455 qWarning(msg: "QGridLayout: Cannot add %s/%s to %s/%s at row %d column %d",
1456 widget->metaObject()->className(), widget->objectName().toLocal8Bit().data(),
1457 metaObject()->className(), objectName().toLocal8Bit().data(), row, column);
1458 return;
1459 }
1460 addChildWidget(w: widget);
1461 QWidgetItem *b = QLayoutPrivate::createWidgetItem(layout: this, widget);
1462 addItem(item: b, row, column, rowSpan: 1, columnSpan: 1, alignment);
1463}
1464
1465/*!
1466 \overload
1467
1468 This version adds the given \a widget to the cell grid, spanning
1469 multiple rows/columns. The cell will start at \a fromRow, \a
1470 fromColumn spanning \a rowSpan rows and \a columnSpan columns. The
1471 \a widget will have the given \a alignment.
1472
1473 If \a rowSpan and/or \a columnSpan is -1, then the widget will
1474 extend to the bottom and/or right edge, respectively.
1475
1476*/
1477void QGridLayout::addWidget(QWidget *widget, int fromRow, int fromColumn,
1478 int rowSpan, int columnSpan, Qt::Alignment alignment)
1479{
1480 Q_D(QGridLayout);
1481 if (!d->checkWidget(widget))
1482 return;
1483 int toRow = (rowSpan < 0) ? -1 : fromRow + rowSpan - 1;
1484 int toColumn = (columnSpan < 0) ? -1 : fromColumn + columnSpan - 1;
1485 addChildWidget(w: widget);
1486 QGridBox *b = new QGridBox(this, widget);
1487 b->setAlignment(alignment);
1488 d->add(box: b, row1: fromRow, row2: toRow, col1: fromColumn, col2: toColumn);
1489 invalidate();
1490}
1491
1492/*!
1493 \fn void QGridLayout::addWidget(QWidget *widget)
1494
1495 \overload
1496 \internal
1497*/
1498
1499/*!
1500 Places the \a layout at position (\a row, \a column) in the grid. The
1501 top-left position is (0, 0).
1502
1503 The alignment is specified by \a alignment. The default
1504 alignment is 0, which means that the widget fills the entire cell.
1505
1506 A non-zero alignment indicates that the layout should not grow to
1507 fill the available space but should be sized according to
1508 sizeHint().
1509
1510
1511 \a layout becomes a child of the grid layout.
1512*/
1513void QGridLayout::addLayout(QLayout *layout, int row, int column, Qt::Alignment alignment)
1514{
1515 Q_D(QGridLayout);
1516 if (!d->checkLayout(otherLayout: layout))
1517 return;
1518 if (!adoptLayout(layout))
1519 return;
1520 QGridBox *b = new QGridBox(layout);
1521 b->setAlignment(alignment);
1522 d->add(box: b, row, col: column);
1523}
1524
1525/*!
1526 \overload
1527 This version adds the layout \a layout to the cell grid, spanning multiple
1528 rows/columns. The cell will start at \a row, \a column spanning \a
1529 rowSpan rows and \a columnSpan columns.
1530
1531 If \a rowSpan and/or \a columnSpan is -1, then the layout will extend to the bottom
1532 and/or right edge, respectively.
1533*/
1534void QGridLayout::addLayout(QLayout *layout, int row, int column,
1535 int rowSpan, int columnSpan, Qt::Alignment alignment)
1536{
1537 Q_D(QGridLayout);
1538 if (!d->checkLayout(otherLayout: layout))
1539 return;
1540 if (!adoptLayout(layout))
1541 return;
1542 QGridBox *b = new QGridBox(layout);
1543 b->setAlignment(alignment);
1544 d->add(box: b, row1: row, row2: (rowSpan < 0) ? -1 : row + rowSpan - 1, col1: column, col2: (columnSpan < 0) ? -1 : column + columnSpan - 1);
1545}
1546
1547/*!
1548 Sets the stretch factor of row \a row to \a stretch. The first row
1549 is number 0.
1550
1551 The stretch factor is relative to the other rows in this grid.
1552 Rows with a higher stretch factor take more of the available
1553 space.
1554
1555 The default stretch factor is 0. If the stretch factor is 0 and no
1556 other row in this table can grow at all, the row may still grow.
1557
1558 \sa rowStretch(), setRowMinimumHeight(), setColumnStretch()
1559*/
1560void QGridLayout::setRowStretch(int row, int stretch)
1561{
1562 Q_D(QGridLayout);
1563 d->setRowStretch(r: row, s: stretch);
1564 invalidate();
1565}
1566
1567/*!
1568 Returns the stretch factor for row \a row.
1569
1570 \sa setRowStretch()
1571*/
1572int QGridLayout::rowStretch(int row) const
1573{
1574 Q_D(const QGridLayout);
1575 return d->rowStretch(r: row);
1576}
1577
1578/*!
1579 Returns the stretch factor for column \a column.
1580
1581 \sa setColumnStretch()
1582*/
1583int QGridLayout::columnStretch(int column) const
1584{
1585 Q_D(const QGridLayout);
1586 return d->colStretch(c: column);
1587}
1588
1589/*!
1590 Sets the stretch factor of column \a column to \a stretch. The first
1591 column is number 0.
1592
1593 The stretch factor is relative to the other columns in this grid.
1594 Columns with a higher stretch factor take more of the available
1595 space.
1596
1597 The default stretch factor is 0. If the stretch factor is 0 and no
1598 other column in this table can grow at all, the column may still
1599 grow.
1600
1601 An alternative approach is to add spacing using addItem() with a
1602 QSpacerItem.
1603
1604 \sa columnStretch(), setRowStretch()
1605*/
1606void QGridLayout::setColumnStretch(int column, int stretch)
1607{
1608 Q_D(QGridLayout);
1609 d->setColStretch(c: column, s: stretch);
1610 invalidate();
1611}
1612
1613
1614
1615/*!
1616 Sets the minimum height of row \a row to \a minSize pixels.
1617
1618 \sa rowMinimumHeight(), setColumnMinimumWidth()
1619*/
1620void QGridLayout::setRowMinimumHeight(int row, int minSize)
1621{
1622 Q_D(QGridLayout);
1623 d->setRowMinimumHeight(r: row, s: minSize);
1624 invalidate();
1625}
1626
1627/*!
1628 Returns the minimum width set for row \a row.
1629
1630 \sa setRowMinimumHeight()
1631*/
1632int QGridLayout::rowMinimumHeight(int row) const
1633{
1634 Q_D(const QGridLayout);
1635 return d->rowSpacing(r: row);
1636}
1637
1638/*!
1639 Sets the minimum width of column \a column to \a minSize pixels.
1640
1641 \sa columnMinimumWidth(), setRowMinimumHeight()
1642*/
1643void QGridLayout::setColumnMinimumWidth(int column, int minSize)
1644{
1645 Q_D(QGridLayout);
1646 d->setColumnMinimumWidth(c: column, s: minSize);
1647 invalidate();
1648}
1649
1650/*!
1651 Returns the column spacing for column \a column.
1652
1653 \sa setColumnMinimumWidth()
1654*/
1655int QGridLayout::columnMinimumWidth(int column) const
1656{
1657 Q_D(const QGridLayout);
1658 return d->colSpacing(c: column);
1659}
1660
1661/*!
1662 \reimp
1663*/
1664Qt::Orientations QGridLayout::expandingDirections() const
1665{
1666 Q_D(const QGridLayout);
1667 return d->expandingDirections(hSpacing: horizontalSpacing(), vSpacing: verticalSpacing());
1668}
1669
1670/*!
1671 Sets the grid's origin corner, i.e. position (0, 0), to \a corner.
1672*/
1673void QGridLayout::setOriginCorner(Qt::Corner corner)
1674{
1675 Q_D(QGridLayout);
1676 d->setReversed(r: corner == Qt::BottomLeftCorner || corner == Qt::BottomRightCorner,
1677 c: corner == Qt::TopRightCorner || corner == Qt::BottomRightCorner);
1678}
1679
1680/*!
1681 Returns the corner that's used for the grid's origin, i.e. for
1682 position (0, 0).
1683*/
1684Qt::Corner QGridLayout::originCorner() const
1685{
1686 Q_D(const QGridLayout);
1687 if (d->horReversed()) {
1688 return d->verReversed() ? Qt::BottomRightCorner : Qt::TopRightCorner;
1689 } else {
1690 return d->verReversed() ? Qt::BottomLeftCorner : Qt::TopLeftCorner;
1691 }
1692}
1693
1694/*!
1695 \reimp
1696*/
1697void QGridLayout::invalidate()
1698{
1699 Q_D(QGridLayout);
1700 d->setDirty();
1701 QLayout::invalidate();
1702}
1703
1704QT_END_NAMESPACE
1705
1706#include "moc_qgridlayout.cpp"
1707

source code of qtbase/src/widgets/kernel/qgridlayout.cpp