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 "qapplication.h"
41#include "qgridlayout.h"
42#include "qlist.h"
43#include "qsizepolicy.h"
44#include "qvarlengtharray.h"
45#include "qwidget.h"
46
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(l, 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(qMax(rows, rr), qMax(cols, cc)); }
125 inline void setRowStretch(int r, int s)
126 { expand(r + 1, 0); rStretch[r] = s; setDirty(); }
127 inline void setColStretch(int c, int s)
128 { expand(0, c + 1); cStretch[c] = s; setDirty(); }
129 inline int rowStretch(int r) const { return rStretch.at(r); }
130 inline int colStretch(int c) const { return cStretch.at(c); }
131 inline void setRowMinimumHeight(int r, int s)
132 { expand(r + 1, 0); rMinHeights[r] = s; setDirty(); }
133 inline void setColumnMinimumWidth(int c, int s)
134 { expand(0, c + 1); cMinWidths[c] = s; setDirty(); }
135 inline int rowSpacing(int r) const { return rMinHeights.at(r); }
136 inline int colSpacing(int c) const { return cMinWidths.at(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 < things.count())
153 return things.at(index)->item();
154 else
155 return nullptr;
156 }
157 inline QLayoutItem *takeAt(int index) {
158 Q_Q(QGridLayout);
159 if (index < things.count()) {
160 if (QGridBox *b = things.takeAt(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(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 < things.count()) {
188 const QGridBox *b = things.at(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(QList<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 QList<QLayoutStruct> rowData;
216 QList<QLayoutStruct> colData;
217 QList<QLayoutStruct> *hfwData;
218 QList<int> rStretch;
219 QList<int> cStretch;
220 QList<int> rMinHeights;
221 QList<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 = nullptr;
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 QList<QLayoutStruct>(rr);
394 setupHfwLayoutData();
395 QList<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(r).spacing;
401 h += rData.at(r).sizeHint + spacing;
402 mh += rData.at(r).minimumSize + spacing;
403 }
404
405 hfw_width = w;
406 hfw_height = qMin(QLAYOUTSIZE_MAX, h);
407 hfw_minheight = qMin(QLAYOUTSIZE_MAX, 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, &top, &right, &bottom);
417
418 int hMargins = left + right;
419 if (w - hMargins != hfw_width) {
420 qGeomCalc(colData, 0, cc, 0, w - hMargins);
421 recalcHFW(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(nullptr, &top, nullptr, &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(r).*size + rowData.at(r).spacing;
446 for (int c = 0; c < cc; c++)
447 w += colData.at(c).*size + colData.at(c).spacing;
448
449 w = qMin(QLAYOUTSIZE_MAX, w);
450 h = qMin(QLAYOUTSIZE_MAX, 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(r).expansive) {
463 ret |= Qt::Vertical;
464 break;
465 }
466 }
467 for (int c = 0; c < cc; c++) {
468 if (colData.at(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(&QLayoutStruct::sizeHint, hSpacing, vSpacing);
479}
480
481QSize QGridLayoutPrivate::maximumSize(int hSpacing, int vSpacing) const
482{
483 return findSize(&QLayoutStruct::maximumSize, hSpacing, vSpacing);
484}
485
486QSize QGridLayoutPrivate::minimumSize(int hSpacing, int vSpacing) const
487{
488 return findSize(&QLayoutStruct::minimumSize, hSpacing, vSpacing);
489}
490
491void QGridLayoutPrivate::setSize(int r, int c)
492{
493 if ((int)rowData.size() < r) {
494 int newR = qMax(r, rr * 2);
495 rowData.resize(newR);
496 rStretch.resize(newR);
497 rMinHeights.resize(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(c, cc * 2);
509 colData.resize(newC);
510 cStretch.resize(newC);
511 cMinWidths.resize(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(row + 1, col + 1);
557 box->row = box->torow = row;
558 box->col = box->tocol = col;
559 things.append(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("QGridLayout: Multi-cell fromRow greater than toRow");
568 if (Q_UNLIKELY(col2 >= 0 && col2 < col1))
569 qWarning("QGridLayout: Multi-cell fromCol greater than toCol");
570 if (row1 == row2 && col1 == col2) {
571 add(box, row1, col1);
572 return;
573 }
574 expand(qMax(row1, row2) + 1, qMax(col1, col2) + 1);
575 box->row = row1;
576 box->col = col1;
577
578 box->torow = row2;
579 box->tocol = col2;
580
581 things.append(box);
582 setDirty();
583 if (col2 < 0)
584 col2 = cc - 1;
585
586 setNextPosAfter(row2, 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(box->col))
599 data->stretch = qMax(data->stretch, box->hStretch());
600 data->sizeHint = qMax(sizes.hint.width(), data->sizeHint);
601 data->minimumSize = qMax(sizes.minS.width(), data->minimumSize);
602
603 qMaxExpCalc(data->maximumSize, data->expansive, data->empty, sizes.maxS.width(),
604 box->expandingDirections() & Qt::Horizontal, box->isEmpty());
605 }
606 if (r) {
607 QLayoutStruct *data = &rowData[box->row];
608 if (!rStretch.at(box->row))
609 data->stretch = qMax(data->stretch, box->vStretch());
610 data->sizeHint = qMax(sizes.hint.height(), data->sizeHint);
611 data->minimumSize = qMax(sizes.minS.height(), data->minimumSize);
612
613 qMaxExpCalc(data->maximumSize, data->expansive, data->empty, sizes.maxS.height(),
614 box->expandingDirections() & Qt::Vertical, box->isEmpty());
615 }
616}
617
618static void initEmptyMultiBox(QList<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(QList<QLayoutStruct> &chain, int start, int end, int minSize,
629 int sizeHint, QList<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(data->stretch, 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, end - start + 1, 0, 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 + 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, end - start + 1, 0, 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, end - start + 1, 0, 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(r, c);
698 return grid[(r * cc) + c];
699}
700
701void QGridLayoutPrivate::setupSpacings(QList<QLayoutStruct> &chain, QGridBox *grid[],
702 int fixedSpacing, Qt::Orientation orientation)
703{
704 Q_Q(QGridLayout);
705 int numRows = rr; // or columns if orientation is horizontal
706 int numColumns = cc; // or rows if orientation is horizontal
707
708 if (orientation == Qt::Horizontal) {
709 qSwap(numRows, numColumns);
710 }
711
712 QStyle *style = nullptr;
713 if (fixedSpacing < 0) {
714 if (QWidget *parentWidget = q->parentWidget())
715 style = parentWidget->style();
716 }
717
718 for (int c = 0; c < numColumns; ++c) {
719 QGridBox *previousBox = nullptr;
720 int previousRow = -1; // previous *non-empty* row
721
722 for (int r = 0; r < numRows; ++r) {
723 if (chain.at(r).empty)
724 continue;
725
726 QGridBox *box = gridAt(grid, r, c, cc, orientation);
727 if (previousRow != -1 && (!box || previousBox != box)) {
728 int spacing = fixedSpacing;
729 if (spacing < 0) {
730 QSizePolicy::ControlTypes controlTypes1 = QSizePolicy::DefaultType;
731 QSizePolicy::ControlTypes controlTypes2 = QSizePolicy::DefaultType;
732 if (previousBox)
733 controlTypes1 = previousBox->item()->controlTypes();
734 if (box)
735 controlTypes2 = box->item()->controlTypes();
736
737 if ((orientation == Qt::Horizontal && hReversed)
738 || (orientation == Qt::Vertical && vReversed))
739 qSwap(controlTypes1, controlTypes2);
740
741 if (style)
742 spacing = style->combinedLayoutSpacing(controlTypes1, controlTypes2,
743 orientation, nullptr, q->parentWidget());
744 } else {
745 if (orientation == Qt::Vertical) {
746 QGridBox *sibling = vReversed ? previousBox : box;
747 if (sibling) {
748 if (sibling->item()->isEmpty()) {
749 spacing = 0;
750 } else {
751 QWidget *wid = sibling->item()->widget();
752 if (wid)
753 spacing = qMax(spacing, sibling->item()->geometry().top() - wid->geometry().top());
754 }
755 }
756 }
757 }
758
759 if (spacing > chain.at(previousRow).spacing)
760 chain[previousRow].spacing = spacing;
761 }
762
763 previousBox = box;
764 previousRow = r;
765 }
766 }
767}
768
769//#define QT_LAYOUT_DISABLE_CACHING
770
771void QGridLayoutPrivate::setupLayoutData(int hSpacing, int vSpacing)
772{
773 Q_Q(QGridLayout);
774
775#ifndef QT_LAYOUT_DISABLE_CACHING
776 if (!needRecalc)
777 return;
778#endif
779 has_hfw = false;
780 int i;
781
782 for (i = 0; i < rr; i++) {
783 rowData[i].init(rStretch.at(i), rMinHeights.at(i));
784 rowData[i].maximumSize = rStretch.at(i) ? QLAYOUTSIZE_MAX : rMinHeights.at(i);
785 }
786 for (i = 0; i < cc; i++) {
787 colData[i].init(cStretch.at(i), cMinWidths.at(i));
788 colData[i].maximumSize = cStretch.at(i) ? QLAYOUTSIZE_MAX : cMinWidths.at(i);
789 }
790
791 int n = things.size();
792 QVarLengthArray<QGridLayoutSizeTriple> sizes(n);
793
794 bool has_multi = false;
795
796 /*
797 Grid of items. We use it to determine which items are
798 adjacent to which and compute the spacings correctly.
799 */
800 QVarLengthArray<QGridBox *> grid(rr * cc);
801 memset(grid.data(), 0, rr * cc * sizeof(QGridBox *));
802
803 /*
804 Initialize 'sizes' and 'grid' data structures, and insert
805 non-spanning items to our row and column data structures.
806 */
807 for (i = 0; i < n; ++i) {
808 QGridBox * const box = things.at(i);
809 sizes[i].minS = box->minimumSize();
810 sizes[i].hint = box->sizeHint();
811 sizes[i].maxS = box->maximumSize();
812
813 if (box->hasHeightForWidth())
814 has_hfw = true;
815
816 if (box->row == box->toRow(rr)) {
817 addData(box, sizes[i], true, false);
818 } else {
819 initEmptyMultiBox(rowData, box->row, box->toRow(rr));
820 has_multi = true;
821 }
822
823 if (box->col == box->toCol(cc)) {
824 addData(box, sizes[i], false, true);
825 } else {
826 initEmptyMultiBox(colData, box->col, box->toCol(cc));
827 has_multi = true;
828 }
829
830 for (int r = box->row; r <= box->toRow(rr); ++r) {
831 for (int c = box->col; c <= box->toCol(cc); ++c) {
832 gridAt(grid.data(), r, c, cc) = box;
833 }
834 }
835 }
836
837 setupSpacings(colData, grid.data(), hSpacing, Qt::Horizontal);
838 setupSpacings(rowData, grid.data(), vSpacing, Qt::Vertical);
839
840 /*
841 Insert multicell items to our row and column data structures.
842 This must be done after the non-spanning items to obtain a
843 better distribution in distributeMultiBox().
844 */
845 if (has_multi) {
846 for (i = 0; i < n; ++i) {
847 QGridBox * const box = things.at(i);
848
849 if (box->row != box->toRow(rr))
850 distributeMultiBox(rowData, box->row, box->toRow(rr), sizes[i].minS.height(),
851 sizes[i].hint.height(), rStretch, box->vStretch());
852 if (box->col != box->toCol(cc))
853 distributeMultiBox(colData, box->col, box->toCol(cc), sizes[i].minS.width(),
854 sizes[i].hint.width(), cStretch, box->hStretch());
855 }
856 }
857
858 for (i = 0; i < rr; i++)
859 rowData[i].expansive = rowData.at(i).expansive || rowData.at(i).stretch > 0;
860 for (i = 0; i < cc; i++)
861 colData[i].expansive = colData.at(i).expansive || colData.at(i).stretch > 0;
862
863 q->getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
864
865 needRecalc = false;
866}
867
868void QGridLayoutPrivate::addHfwData(QGridBox *box, int width)
869{
870 QList<QLayoutStruct> &rData = *hfwData;
871 if (box->hasHeightForWidth()) {
872 int hint = box->heightForWidth(width);
873 rData[box->row].sizeHint = qMax(hint, rData.at(box->row).sizeHint);
874 rData[box->row].minimumSize = qMax(hint, rData.at(box->row).minimumSize);
875 } else {
876 QSize hint = box->sizeHint();
877 QSize minS = box->minimumSize();
878 rData[box->row].sizeHint = qMax(hint.height(), rData.at(box->row).sizeHint);
879 rData[box->row].minimumSize = qMax(minS.height(), rData.at(box->row).minimumSize);
880 }
881}
882
883/*
884 Similar to setupLayoutData(), but uses heightForWidth(colData)
885 instead of sizeHint(). Assumes that setupLayoutData() and
886 qGeomCalc(colData) has been called.
887*/
888void QGridLayoutPrivate::setupHfwLayoutData()
889{
890 QList<QLayoutStruct> &rData = *hfwData;
891 for (int i = 0; i < rr; i++) {
892 rData[i] = rowData.at(i);
893 rData[i].minimumSize = rData[i].sizeHint = rMinHeights.at(i);
894 }
895
896 for (int pass = 0; pass < 2; ++pass) {
897 for (int i = 0; i < things.size(); ++i) {
898 QGridBox *box = things.at(i);
899 int r1 = box->row;
900 int c1 = box->col;
901 int r2 = box->toRow(rr);
902 int c2 = box->toCol(cc);
903 int w = colData.at(c2).pos + colData.at(c2).size - colData.at(c1).pos;
904
905 if (r1 == r2) {
906 if (pass == 0)
907 addHfwData(box, w);
908 } else {
909 if (pass == 0) {
910 initEmptyMultiBox(rData, r1, r2);
911 } else {
912 QSize hint = box->sizeHint();
913 QSize min = box->minimumSize();
914 if (box->hasHeightForWidth()) {
915 int hfwh = box->heightForWidth(w);
916 if (hfwh > hint.height())
917 hint.setHeight(hfwh);
918 if (hfwh > min.height())
919 min.setHeight(hfwh);
920 }
921 distributeMultiBox(rData, r1, r2, min.height(), hint.height(),
922 rStretch, box->vStretch());
923 }
924 }
925 }
926 }
927 for (int i = 0; i < rr; i++)
928 rData[i].expansive = rData.at(i).expansive || rData.at(i).stretch > 0;
929}
930
931void QGridLayoutPrivate::distribute(QRect r, int hSpacing, int vSpacing)
932{
933 Q_Q(QGridLayout);
934 bool visualHReversed = hReversed;
935 QWidget *parent = q->parentWidget();
936 if (parent && parent->isRightToLeft())
937 visualHReversed = !visualHReversed;
938
939 setupLayoutData(hSpacing, vSpacing);
940
941 int left, top, right, bottom;
942 effectiveMargins(&left, &top, &right, &bottom);
943 r.adjust(+left, +top, -right, -bottom);
944
945 qGeomCalc(colData, 0, cc, r.x(), r.width());
946 QList<QLayoutStruct> *rDataPtr;
947 if (has_hfw) {
948 recalcHFW(r.width());
949 qGeomCalc(*hfwData, 0, rr, r.y(), r.height());
950 rDataPtr = hfwData;
951 } else {
952 qGeomCalc(rowData, 0, rr, r.y(), r.height());
953 rDataPtr = &rowData;
954 }
955 QList<QLayoutStruct> &rData = *rDataPtr;
956 int i;
957
958 bool reverse = ((r.bottom() > rect.bottom()) || (r.bottom() == rect.bottom()
959 && ((r.right() > rect.right()) != visualHReversed)));
960 int n = things.size();
961 for (i = 0; i < n; ++i) {
962 QGridBox *box = things.at(reverse ? n-i-1 : i);
963 int r2 = box->toRow(rr);
964 int c2 = box->toCol(cc);
965
966 int x = colData.at(box->col).pos;
967 int y = rData.at(box->row).pos;
968 int x2p = colData.at(c2).pos + colData.at(c2).size; // x2+1
969 int y2p = rData.at(r2).pos + rData.at(r2).size; // y2+1
970 int w = x2p - x;
971 int h = y2p - y;
972
973 if (visualHReversed)
974 x = r.left() + r.right() - x - w + 1;
975 if (vReversed)
976 y = r.top() + r.bottom() - y - h + 1;
977
978 box->setGeometry(QRect(x, y, w, h));
979 }
980}
981
982QRect QGridLayoutPrivate::cellRect(int row, int col) const
983{
984 if (row < 0 || row >= rr || col < 0 || col >= cc)
985 return QRect();
986
987 const QList<QLayoutStruct> *rDataPtr;
988 if (has_hfw && hfwData)
989 rDataPtr = hfwData;
990 else
991 rDataPtr = &rowData;
992 return QRect(colData.at(col).pos, rDataPtr->at(row).pos,
993 colData.at(col).size, rDataPtr->at(row).size);
994}
995
996/*!
997 \class QGridLayout
998
999 \brief The QGridLayout class lays out widgets in a grid.
1000
1001 \ingroup geomanagement
1002 \inmodule QtWidgets
1003
1004 QGridLayout takes the space made available to it (by its parent
1005 layout or by the parentWidget()), divides it up into rows and
1006 columns, and puts each widget it manages into the correct cell.
1007
1008 Columns and rows behave identically; we will discuss columns, but
1009 there are equivalent functions for rows.
1010
1011 Each column has a minimum width and a stretch factor. The minimum
1012 width is the greatest of that set using setColumnMinimumWidth() and the
1013 minimum width of each widget in that column. The stretch factor is
1014 set using setColumnStretch() and determines how much of the available
1015 space the column will get over and above its necessary minimum.
1016
1017 Normally, each managed widget or layout is put into a cell of its
1018 own using addWidget(). It is also possible for a widget to occupy
1019 multiple cells using the row and column spanning overloads of
1020 addItem() and addWidget(). If you do this, QGridLayout will guess
1021 how to distribute the size over the columns/rows (based on the
1022 stretch factors).
1023
1024 To remove a widget from a layout, call removeWidget(). Calling
1025 QWidget::hide() on a widget also effectively removes the widget
1026 from the layout until QWidget::show() is called.
1027
1028 This illustration shows a fragment of a dialog with a five-column,
1029 three-row grid (the grid is shown overlaid in magenta):
1030
1031 \image qgridlayout.png A grid layout
1032
1033 Columns 0, 2 and 4 in this dialog fragment are made up of a
1034 QLabel, a QLineEdit, and a QListBox. Columns 1 and 3 are
1035 placeholders made with setColumnMinimumWidth(). Row 0 consists of three
1036 QLabel objects, row 1 of three QLineEdit objects and row 2 of
1037 three QListBox objects. We used placeholder columns (1 and 3) to
1038 get the right amount of space between the columns.
1039
1040 Note that the columns and rows are not equally wide or tall. If
1041 you want two columns to have the same width, you must set their
1042 minimum widths and stretch factors to be the same yourself. You do
1043 this using setColumnMinimumWidth() and setColumnStretch().
1044
1045 If the QGridLayout is not the top-level layout (i.e. does not
1046 manage all of the widget's area and children), you must add it to
1047 its parent layout when you create it, but before you do anything
1048 with it. The normal way to add a layout is by calling
1049 addLayout() on the parent layout.
1050
1051 Once you have added your layout you can start putting widgets and
1052 other layouts into the cells of your grid layout using
1053 addWidget(), addItem(), and addLayout().
1054
1055 QGridLayout also includes two margin widths:
1056 the \l{getContentsMargins()}{contents margin} and the spacing().
1057 The contents margin is the width of the reserved space along each
1058 of the QGridLayout's four sides. The spacing() is the width of the
1059 automatically allocated spacing between neighboring boxes.
1060
1061 The default contents margin values are provided by the
1062 \l{QStyle::pixelMetric()}{style}. The default value Qt styles specify
1063 is 9 for child widgets and 11 for windows. The spacing defaults to the same as
1064 the margin width for a top-level layout, or to the same as the
1065 parent layout.
1066
1067 \sa QBoxLayout, QStackedLayout, {Layout Management}, {Basic Layouts Example}
1068*/
1069
1070
1071/*!
1072 Constructs a new QGridLayout with parent widget, \a parent. The
1073 layout has one row and one column initially, and will expand when
1074 new items are inserted.
1075*/
1076QGridLayout::QGridLayout(QWidget *parent)
1077 : QLayout(*new QGridLayoutPrivate, nullptr, parent)
1078{
1079 Q_D(QGridLayout);
1080 d->expand(1, 1);
1081}
1082
1083/*!
1084 Constructs a new grid layout.
1085
1086 You must insert this grid into another layout. You can insert
1087 widgets and layouts into this layout at any time, but laying out
1088 will not be performed before this is inserted into another layout.
1089*/
1090QGridLayout::QGridLayout()
1091 : QLayout(*new QGridLayoutPrivate, nullptr, nullptr)
1092{
1093 Q_D(QGridLayout);
1094 d->expand(1, 1);
1095}
1096
1097
1098
1099
1100/*!
1101\internal (mostly)
1102
1103Sets the positioning mode used by addItem(). If \a orient is
1104Qt::Horizontal, this layout is expanded to \a n columns, and items
1105will be added columns-first. Otherwise it is expanded to \a n rows and
1106items will be added rows-first.
1107*/
1108
1109void QGridLayout::setDefaultPositioning(int n, Qt::Orientation orient)
1110{
1111 Q_D(QGridLayout);
1112 if (orient == Qt::Horizontal) {
1113 d->expand(1, n);
1114 d->addVertical = false;
1115 } else {
1116 d->expand(n,1);
1117 d->addVertical = true;
1118 }
1119}
1120
1121
1122/*!
1123 Destroys the grid layout. Geometry management is terminated if
1124 this is a top-level grid.
1125
1126 The layout's widgets aren't destroyed.
1127*/
1128QGridLayout::~QGridLayout()
1129{
1130 Q_D(QGridLayout);
1131 d->deleteAll();
1132}
1133
1134/*!
1135 \property QGridLayout::horizontalSpacing
1136 \brief the spacing between widgets that are laid out side by side
1137 \since 4.3
1138
1139 If no value is explicitly set, the layout's horizontal spacing is
1140 inherited from the parent layout, or from the style settings for
1141 the parent widget.
1142
1143 \sa verticalSpacing, QStyle::pixelMetric(), {QStyle::}{PM_LayoutHorizontalSpacing}
1144*/
1145void QGridLayout::setHorizontalSpacing(int spacing)
1146{
1147 Q_D(QGridLayout);
1148 d->horizontalSpacing = spacing;
1149 invalidate();
1150}
1151
1152int QGridLayout::horizontalSpacing() const
1153{
1154 Q_D(const QGridLayout);
1155 if (d->horizontalSpacing >= 0) {
1156 return d->horizontalSpacing;
1157 } else {
1158 return qSmartSpacing(this, QStyle::PM_LayoutHorizontalSpacing);
1159 }
1160}
1161
1162/*!
1163 \property QGridLayout::verticalSpacing
1164 \brief the spacing between widgets that are laid out on top of each other
1165 \since 4.3
1166
1167 If no value is explicitly set, the layout's vertical spacing is
1168 inherited from the parent layout, or from the style settings for
1169 the parent widget.
1170
1171 \sa horizontalSpacing, QStyle::pixelMetric(), {QStyle::}{PM_LayoutHorizontalSpacing}
1172*/
1173void QGridLayout::setVerticalSpacing(int spacing)
1174{
1175 Q_D(QGridLayout);
1176 d->verticalSpacing = spacing;
1177 invalidate();
1178}
1179
1180int QGridLayout::verticalSpacing() const
1181{
1182 Q_D(const QGridLayout);
1183 if (d->verticalSpacing >= 0) {
1184 return d->verticalSpacing;
1185 } else {
1186 return qSmartSpacing(this, QStyle::PM_LayoutVerticalSpacing);
1187 }
1188}
1189
1190/*!
1191 This function sets both the vertical and horizontal spacing to
1192 \a spacing.
1193
1194 \sa setVerticalSpacing(), setHorizontalSpacing()
1195*/
1196void QGridLayout::setSpacing(int spacing)
1197{
1198 Q_D(QGridLayout);
1199 d->horizontalSpacing = d->verticalSpacing = spacing;
1200 invalidate();
1201}
1202
1203/*!
1204 If the vertical spacing is equal to the horizontal spacing,
1205 this function returns that value; otherwise it return -1.
1206
1207 \sa setSpacing(), verticalSpacing(), horizontalSpacing()
1208*/
1209int QGridLayout::spacing() const
1210{
1211 int hSpacing = horizontalSpacing();
1212 if (hSpacing == verticalSpacing()) {
1213 return hSpacing;
1214 } else {
1215 return -1;
1216 }
1217}
1218
1219/*!
1220 Returns the number of rows in this grid.
1221*/
1222int QGridLayout::rowCount() const
1223{
1224 Q_D(const QGridLayout);
1225 return d->numRows();
1226}
1227
1228/*!
1229 Returns the number of columns in this grid.
1230*/
1231int QGridLayout::columnCount() const
1232{
1233 Q_D(const QGridLayout);
1234 return d->numCols();
1235}
1236
1237/*!
1238 \reimp
1239*/
1240QSize QGridLayout::sizeHint() const
1241{
1242 Q_D(const QGridLayout);
1243 QSize result(d->sizeHint(horizontalSpacing(), verticalSpacing()));
1244 int left, top, right, bottom;
1245 d->effectiveMargins(&left, &top, &right, &bottom);
1246 result += QSize(left + right, top + bottom);
1247 return result;
1248}
1249
1250/*!
1251 \reimp
1252*/
1253QSize QGridLayout::minimumSize() const
1254{
1255 Q_D(const QGridLayout);
1256 QSize result(d->minimumSize(horizontalSpacing(), verticalSpacing()));
1257 int left, top, right, bottom;
1258 d->effectiveMargins(&left, &top, &right, &bottom);
1259 result += QSize(left + right, top + bottom);
1260 return result;
1261}
1262
1263/*!
1264 \reimp
1265*/
1266QSize QGridLayout::maximumSize() const
1267{
1268 Q_D(const QGridLayout);
1269
1270 QSize s = d->maximumSize(horizontalSpacing(), verticalSpacing());
1271 int left, top, right, bottom;
1272 d->effectiveMargins(&left, &top, &right, &bottom);
1273 s += QSize(left + right, top + bottom);
1274 s = s.boundedTo(QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX));
1275 if (alignment() & Qt::AlignHorizontal_Mask)
1276 s.setWidth(QLAYOUTSIZE_MAX);
1277 if (alignment() & Qt::AlignVertical_Mask)
1278 s.setHeight(QLAYOUTSIZE_MAX);
1279 return s;
1280}
1281
1282/*!
1283 \reimp
1284*/
1285bool QGridLayout::hasHeightForWidth() const
1286{
1287 return const_cast<QGridLayout*>(this)->d_func()->hasHeightForWidth(horizontalSpacing(), verticalSpacing());
1288}
1289
1290/*!
1291 \reimp
1292*/
1293int QGridLayout::heightForWidth(int w) const
1294{
1295 Q_D(const QGridLayout);
1296 QGridLayoutPrivate *dat = const_cast<QGridLayoutPrivate *>(d);
1297 return dat->heightForWidth(w, horizontalSpacing(), verticalSpacing());
1298}
1299
1300/*!
1301 \reimp
1302*/
1303int QGridLayout::minimumHeightForWidth(int w) const
1304{
1305 Q_D(const QGridLayout);
1306 QGridLayoutPrivate *dat = const_cast<QGridLayoutPrivate *>(d);
1307 return dat->minimumHeightForWidth(w, horizontalSpacing(), verticalSpacing());
1308}
1309
1310/*!
1311 \reimp
1312*/
1313int QGridLayout::count() const
1314{
1315 Q_D(const QGridLayout);
1316 return d->count();
1317}
1318
1319
1320/*!
1321 \reimp
1322*/
1323QLayoutItem *QGridLayout::itemAt(int index) const
1324{
1325 Q_D(const QGridLayout);
1326 return d->itemAt(index);
1327}
1328
1329/*!
1330 \since 4.4
1331
1332 Returns the layout item that occupies cell (\a row, \a column), or
1333 \nullptr if the cell is empty.
1334
1335 \sa getItemPosition(), indexOf()
1336*/
1337QLayoutItem *QGridLayout::itemAtPosition(int row, int column) const
1338{
1339 Q_D(const QGridLayout);
1340 int n = d->things.count();
1341 for (int i = 0; i < n; ++i) {
1342 QGridBox *box = d->things.at(i);
1343 if (row >= box->row && row <= box->toRow(d->rr)
1344 && column >= box->col && column <= box->toCol(d->cc)) {
1345 return box->item();
1346 }
1347 }
1348 return nullptr;
1349}
1350
1351/*!
1352 \reimp
1353*/
1354QLayoutItem *QGridLayout::takeAt(int index)
1355{
1356 Q_D(QGridLayout);
1357 return d->takeAt(index);
1358}
1359
1360/*!
1361 Returns the position information of the item with the given \a index.
1362
1363 The variables passed as \a row and \a column are updated with the position of the
1364 item in the layout, and the \a rowSpan and \a columnSpan variables are updated
1365 with the vertical and horizontal spans of the item.
1366
1367 \sa itemAtPosition(), itemAt()
1368*/
1369void QGridLayout::getItemPosition(int index, int *row, int *column, int *rowSpan, int *columnSpan) const
1370{
1371 Q_D(const QGridLayout);
1372 d->getItemPosition(index, row, column, rowSpan, columnSpan);
1373}
1374
1375
1376/*!
1377 \reimp
1378*/
1379void QGridLayout::setGeometry(const QRect &rect)
1380{
1381 Q_D(QGridLayout);
1382 if (d->isDirty() || rect != geometry()) {
1383 QRect cr = alignment() ? alignmentRect(rect) : rect;
1384 d->distribute(cr, horizontalSpacing(), verticalSpacing());
1385 QLayout::setGeometry(rect);
1386 }
1387}
1388
1389/*!
1390 Returns the geometry of the cell with row \a row and column \a column
1391 in the grid. Returns an invalid rectangle if \a row or \a column is
1392 outside the grid.
1393
1394 \warning in the current version of Qt this function does not
1395 return valid results until setGeometry() has been called, i.e.
1396 after the parentWidget() is visible.
1397*/
1398QRect QGridLayout::cellRect(int row, int column) const
1399{
1400 Q_D(const QGridLayout);
1401 return d->cellRect(row, column);
1402}
1403
1404/*!
1405 \reimp
1406*/
1407void QGridLayout::addItem(QLayoutItem *item)
1408{
1409 Q_D(QGridLayout);
1410 int r, c;
1411 d->getNextPos(r, c);
1412 addItem(item, r, c);
1413}
1414
1415/*!
1416 Adds \a item at position \a row, \a column, spanning \a rowSpan
1417 rows and \a columnSpan columns, and aligns it according to \a
1418 alignment. If \a rowSpan and/or \a columnSpan is -1, then the item
1419 will extend to the bottom and/or right edge, respectively. The
1420 layout takes ownership of the \a item.
1421
1422 \warning Do not use this function to add child layouts or child
1423 widget items. Use addLayout() or addWidget() instead.
1424*/
1425void QGridLayout::addItem(QLayoutItem *item, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment)
1426{
1427 Q_D(QGridLayout);
1428 QGridBox *b = new QGridBox(item);
1429 b->setAlignment(alignment);
1430 d->add(b, row, (rowSpan < 0) ? -1 : row + rowSpan - 1, column, (columnSpan < 0) ? -1 : column + columnSpan - 1);
1431 invalidate();
1432}
1433
1434/*!
1435 Adds the given \a widget to the cell grid at \a row, \a column. The
1436 top-left position is (0, 0) by default.
1437
1438 The alignment is specified by \a alignment. The default
1439 alignment is 0, which means that the widget fills the entire cell.
1440
1441*/
1442void QGridLayout::addWidget(QWidget *widget, int row, int column, Qt::Alignment alignment)
1443{
1444 Q_D(QGridLayout);
1445 if (!d->checkWidget(widget))
1446 return;
1447 if (Q_UNLIKELY(row < 0 || column < 0)) {
1448 qWarning("QGridLayout: Cannot add %s/%s to %s/%s at row %d column %d",
1449 widget->metaObject()->className(), widget->objectName().toLocal8Bit().data(),
1450 metaObject()->className(), objectName().toLocal8Bit().data(), row, column);
1451 return;
1452 }
1453 addChildWidget(widget);
1454 QWidgetItem *b = QLayoutPrivate::createWidgetItem(this, widget);
1455 addItem(b, row, column, 1, 1, alignment);
1456}
1457
1458/*!
1459 \overload
1460
1461 This version adds the given \a widget to the cell grid, spanning
1462 multiple rows/columns. The cell will start at \a fromRow, \a
1463 fromColumn spanning \a rowSpan rows and \a columnSpan columns. The
1464 \a widget will have the given \a alignment.
1465
1466 If \a rowSpan and/or \a columnSpan is -1, then the widget will
1467 extend to the bottom and/or right edge, respectively.
1468
1469*/
1470void QGridLayout::addWidget(QWidget *widget, int fromRow, int fromColumn,
1471 int rowSpan, int columnSpan, Qt::Alignment alignment)
1472{
1473 Q_D(QGridLayout);
1474 if (!d->checkWidget(widget))
1475 return;
1476 int toRow = (rowSpan < 0) ? -1 : fromRow + rowSpan - 1;
1477 int toColumn = (columnSpan < 0) ? -1 : fromColumn + columnSpan - 1;
1478 addChildWidget(widget);
1479 QGridBox *b = new QGridBox(this, widget);
1480 b->setAlignment(alignment);
1481 d->add(b, fromRow, toRow, fromColumn, toColumn);
1482 invalidate();
1483}
1484
1485/*!
1486 \fn void QGridLayout::addWidget(QWidget *widget)
1487
1488 \overload
1489 \internal
1490*/
1491
1492/*!
1493 Places the \a layout at position (\a row, \a column) in the grid. The
1494 top-left position is (0, 0).
1495
1496 The alignment is specified by \a alignment. The default
1497 alignment is 0, which means that the widget fills the entire cell.
1498
1499 A non-zero alignment indicates that the layout should not grow to
1500 fill the available space but should be sized according to
1501 sizeHint().
1502
1503
1504 \a layout becomes a child of the grid layout.
1505*/
1506void QGridLayout::addLayout(QLayout *layout, int row, int column, Qt::Alignment alignment)
1507{
1508 Q_D(QGridLayout);
1509 if (!d->checkLayout(layout))
1510 return;
1511 if (!adoptLayout(layout))
1512 return;
1513 QGridBox *b = new QGridBox(layout);
1514 b->setAlignment(alignment);
1515 d->add(b, row, column);
1516}
1517
1518/*!
1519 \overload
1520 This version adds the layout \a layout to the cell grid, spanning multiple
1521 rows/columns. The cell will start at \a row, \a column spanning \a
1522 rowSpan rows and \a columnSpan columns.
1523
1524 If \a rowSpan and/or \a columnSpan is -1, then the layout will extend to the bottom
1525 and/or right edge, respectively.
1526*/
1527void QGridLayout::addLayout(QLayout *layout, int row, int column,
1528 int rowSpan, int columnSpan, Qt::Alignment alignment)
1529{
1530 Q_D(QGridLayout);
1531 if (!d->checkLayout(layout))
1532 return;
1533 if (!adoptLayout(layout))
1534 return;
1535 QGridBox *b = new QGridBox(layout);
1536 b->setAlignment(alignment);
1537 d->add(b, row, (rowSpan < 0) ? -1 : row + rowSpan - 1, column, (columnSpan < 0) ? -1 : column + columnSpan - 1);
1538}
1539
1540/*!
1541 Sets the stretch factor of row \a row to \a stretch. The first row
1542 is number 0.
1543
1544 The stretch factor is relative to the other rows in this grid.
1545 Rows with a higher stretch factor take more of the available
1546 space.
1547
1548 The default stretch factor is 0. If the stretch factor is 0 and no
1549 other row in this table can grow at all, the row may still grow.
1550
1551 \sa rowStretch(), setRowMinimumHeight(), setColumnStretch()
1552*/
1553void QGridLayout::setRowStretch(int row, int stretch)
1554{
1555 Q_D(QGridLayout);
1556 d->setRowStretch(row, stretch);
1557 invalidate();
1558}
1559
1560/*!
1561 Returns the stretch factor for row \a row.
1562
1563 \sa setRowStretch()
1564*/
1565int QGridLayout::rowStretch(int row) const
1566{
1567 Q_D(const QGridLayout);
1568 return d->rowStretch(row);
1569}
1570
1571/*!
1572 Returns the stretch factor for column \a column.
1573
1574 \sa setColumnStretch()
1575*/
1576int QGridLayout::columnStretch(int column) const
1577{
1578 Q_D(const QGridLayout);
1579 return d->colStretch(column);
1580}
1581
1582/*!
1583 Sets the stretch factor of column \a column to \a stretch. The first
1584 column is number 0.
1585
1586 The stretch factor is relative to the other columns in this grid.
1587 Columns with a higher stretch factor take more of the available
1588 space.
1589
1590 The default stretch factor is 0. If the stretch factor is 0 and no
1591 other column in this table can grow at all, the column may still
1592 grow.
1593
1594 An alternative approach is to add spacing using addItem() with a
1595 QSpacerItem.
1596
1597 \sa columnStretch(), setRowStretch()
1598*/
1599void QGridLayout::setColumnStretch(int column, int stretch)
1600{
1601 Q_D(QGridLayout);
1602 d->setColStretch(column, stretch);
1603 invalidate();
1604}
1605
1606
1607
1608/*!
1609 Sets the minimum height of row \a row to \a minSize pixels.
1610
1611 \sa rowMinimumHeight(), setColumnMinimumWidth()
1612*/
1613void QGridLayout::setRowMinimumHeight(int row, int minSize)
1614{
1615 Q_D(QGridLayout);
1616 d->setRowMinimumHeight(row, minSize);
1617 invalidate();
1618}
1619
1620/*!
1621 Returns the minimum width set for row \a row.
1622
1623 \sa setRowMinimumHeight()
1624*/
1625int QGridLayout::rowMinimumHeight(int row) const
1626{
1627 Q_D(const QGridLayout);
1628 return d->rowSpacing(row);
1629}
1630
1631/*!
1632 Sets the minimum width of column \a column to \a minSize pixels.
1633
1634 \sa columnMinimumWidth(), setRowMinimumHeight()
1635*/
1636void QGridLayout::setColumnMinimumWidth(int column, int minSize)
1637{
1638 Q_D(QGridLayout);
1639 d->setColumnMinimumWidth(column, minSize);
1640 invalidate();
1641}
1642
1643/*!
1644 Returns the column spacing for column \a column.
1645
1646 \sa setColumnMinimumWidth()
1647*/
1648int QGridLayout::columnMinimumWidth(int column) const
1649{
1650 Q_D(const QGridLayout);
1651 return d->colSpacing(column);
1652}
1653
1654/*!
1655 \reimp
1656*/
1657Qt::Orientations QGridLayout::expandingDirections() const
1658{
1659 Q_D(const QGridLayout);
1660 return d->expandingDirections(horizontalSpacing(), verticalSpacing());
1661}
1662
1663/*!
1664 Sets the grid's origin corner, i.e. position (0, 0), to \a corner.
1665*/
1666void QGridLayout::setOriginCorner(Qt::Corner corner)
1667{
1668 Q_D(QGridLayout);
1669 d->setReversed(corner == Qt::BottomLeftCorner || corner == Qt::BottomRightCorner,
1670 corner == Qt::TopRightCorner || corner == Qt::BottomRightCorner);
1671}
1672
1673/*!
1674 Returns the corner that's used for the grid's origin, i.e. for
1675 position (0, 0).
1676*/
1677Qt::Corner QGridLayout::originCorner() const
1678{
1679 Q_D(const QGridLayout);
1680 if (d->horReversed()) {
1681 return d->verReversed() ? Qt::BottomRightCorner : Qt::TopRightCorner;
1682 } else {
1683 return d->verReversed() ? Qt::BottomLeftCorner : Qt::TopLeftCorner;
1684 }
1685}
1686
1687/*!
1688 \reimp
1689*/
1690void QGridLayout::invalidate()
1691{
1692 Q_D(QGridLayout);
1693 d->setDirty();
1694 QLayout::invalidate();
1695}
1696
1697QT_END_NAMESPACE
1698
1699#include "moc_qgridlayout.cpp"
1700