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