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

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