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
qboxlayout.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 "qboxlayout.h"
7#include "qlist.h"
8#include "qsizepolicy.h"
9#include "qwidget.h"
10
11#include "qlayout_p.h"
13
15
17{
18 QBoxLayoutItem(QLayoutItem *it, int stretch_ = 0)
19 : item(it), stretch(stretch_), magic(false) { }
20 ~QBoxLayoutItem() { delete item; }
21
22 int hfw(int w) {
23 if (item->hasHeightForWidth()) {
24 return item->heightForWidth(w);
25 } else {
26 return item->sizeHint().height();
27 }
28 }
29 int mhfw(int w) {
30 if (item->hasHeightForWidth()) {
31 return item->minimumHeightForWidth(w);
32 } else {
33 return item->minimumSize().height();
34 }
35 }
36 int hStretch() {
37 if (stretch == 0 && item->widget()) {
38 return item->widget()->sizePolicy().horizontalStretch();
39 } else {
40 return stretch;
41 }
42 }
43 int vStretch() {
44 if (stretch == 0 && item->widget()) {
45 return item->widget()->sizePolicy().verticalStretch();
46 } else {
47 return stretch;
48 }
49 }
50
51 QLayoutItem *item;
53 bool magic;
54};
55
57{
58 Q_DECLARE_PUBLIC(QBoxLayout)
59public:
60 QBoxLayoutPrivate() : hfwWidth(-1), dirty(true), spacing(-1) { }
62
63 void setDirty() {
64 geomArray.clear();
65 hfwWidth = -1;
66 hfwHeight = -1;
67 dirty = true;
68 }
69
84
85 inline void deleteAll() { while (!list.isEmpty()) delete list.takeFirst(); }
86
87 void setupGeom();
88 void calcHfw(int);
89
90 void effectiveMargins(int *left, int *top, int *right, int *bottom) const;
91 QLayoutItem* replaceAt(int index, QLayoutItem*) override;
92 int validateIndex(int index) const;
93};
94
95QBoxLayoutPrivate::~QBoxLayoutPrivate()
96{
97}
98
99static inline bool horz(QBoxLayout::Direction dir)
100{
101 return dir == QBoxLayout::RightToLeft || dir == QBoxLayout::LeftToRight;
102}
103
104/**
105 * The purpose of this function is to make sure that widgets are not laid out outside its layout.
106 * E.g. the layoutItemRect margins are only meant to take of the surrounding margins/spacings.
107 * However, if the margin is 0, it can easily cover the area of a widget above it.
108 */
109void QBoxLayoutPrivate::effectiveMargins(int *left, int *top, int *right, int *bottom) const
110{
111 int l = leftMargin;
112 int t = topMargin;
113 int r = rightMargin;
114 int b = bottomMargin;
115 /*
116 * \a firstBox is set to the first (left/topmost) visual item
117 * \a lastBox is set to the last (right/bottommost) visual item
118 *
119 * These two boxes will then be used to determine the extra margins the layout needs to be
120 * surrounded by in case they have a layout item rect (e.g. QGroupBox)
121 */
122 auto firstAndLastNonEmptyBox = [](const QList<QBoxLayoutItem*> list,
123 QBoxLayoutItem* *firstBox,
124 QBoxLayoutItem* *lastBox)
125 {
126 auto isNonEmptyBox = [](QBoxLayoutItem *box) { return box && box->item && !box->item->isEmpty();};
127 // search for the first non-empty box
128 auto topIt = std::find_if(list.begin(), list.end(), isNonEmptyBox);
129 if (topIt != list.end()) {
130 *firstBox = *topIt;
131 // search for the last non-empty box, but do not search past the first item found
132 auto bottomIt = std::find_if(list.rbegin(), std::make_reverse_iterator(--topIt), isNonEmptyBox);
133 *lastBox = *bottomIt;
134 } else {
135 *firstBox = nullptr;
136 *lastBox = nullptr;
137 }
138 };
139
140
141 Q_Q(const QBoxLayout);
142 if (horz(dir)) {
143 QBoxLayoutItem *leftBox = nullptr;
144 QBoxLayoutItem *rightBox = nullptr;
145
146 if (left || right) {
147 firstAndLastNonEmptyBox(list, &leftBox, &rightBox);
148 if (dir == QBoxLayout::RightToLeft)
149 qSwap(leftBox, rightBox);
150
151 int leftDelta = 0;
152 int rightDelta = 0;
153 if (leftBox) {
154 QLayoutItem *itm = leftBox->item;
155 if (QWidget *w = itm->widget())
156 leftDelta = itm->geometry().left() - w->geometry().left();
157 }
158 if (rightBox) {
159 QLayoutItem *itm = rightBox->item;
160 if (QWidget *w = itm->widget())
161 rightDelta = w->geometry().right() - itm->geometry().right();
162 }
163 QWidget *w = q->parentWidget();
164 Qt::LayoutDirection layoutDirection = w ? w->layoutDirection() : QGuiApplication::layoutDirection();
165 if (layoutDirection == Qt::RightToLeft)
166 qSwap(leftDelta, rightDelta);
167
168 l = qMax(l, leftDelta);
169 r = qMax(r, rightDelta);
170 }
171
172 int count = top || bottom ? list.count() : 0;
173 for (int i = 0; i < count; ++i) {
174 QBoxLayoutItem *box = list.at(i);
175 QLayoutItem *itm = box->item;
176 QWidget *w = itm->widget();
177 if (w) {
178 QRect lir = itm->geometry();
179 QRect wr = w->geometry();
180 if (top)
181 t = qMax(t, lir.top() - wr.top());
182 if (bottom)
183 b = qMax(b, wr.bottom() - lir.bottom());
184 }
185 }
186 } else { // vertical layout
187 QBoxLayoutItem *topBox = nullptr;
188 QBoxLayoutItem *bottomBox = nullptr;
189
190 if (top || bottom) {
191 firstAndLastNonEmptyBox(list, &topBox, &bottomBox);
192 if (dir == QBoxLayout::BottomToTop) {
193 qSwap(topBox, bottomBox);
194 }
195
196 if (top && topBox) {
197 QLayoutItem *itm = topBox->item;
198 QWidget *w = itm->widget();
199 if (w)
200 t = qMax(t, itm->geometry().top() - w->geometry().top());
201 }
202
203 if (bottom && bottomBox) {
204 QLayoutItem *itm = bottomBox->item;
205 QWidget *w = itm->widget();
206 if (w)
207 b = qMax(b, w->geometry().bottom() - itm->geometry().bottom());
208 }
209 }
210
211 int count = left || right ? list.count() : 0;
212 for (int i = 0; i < count; ++i) {
213 QBoxLayoutItem *box = list.at(i);
214 QLayoutItem *itm = box->item;
215 QWidget *w = itm->widget();
216 if (w) {
217 QRect lir = itm->geometry();
218 QRect wr = w->geometry();
219 if (left)
220 l = qMax(l, lir.left() - wr.left());
221 if (right)
222 r = qMax(r, wr.right() - lir.right());
223 }
224 }
225 }
226
227 if (left)
228 *left = l;
229 if (top)
230 *top = t;
231 if (right)
232 *right = r;
233 if (bottom)
234 *bottom = b;
235}
236
237
238/*
239 Initializes the data structure needed by qGeomCalc and
240 recalculates max/min and size hint.
241*/
243{
244 if (!dirty)
245 return;
246
247 Q_Q(QBoxLayout);
248 int maxw = horz(dir) ? 0 : QLAYOUTSIZE_MAX;
249 int maxh = horz(dir) ? QLAYOUTSIZE_MAX : 0;
250 int minw = 0;
251 int minh = 0;
252 int hintw = 0;
253 int hinth = 0;
254
255 bool horexp = false;
256 bool verexp = false;
257
258 hasHfw = false;
259
260 int n = list.size();
261 geomArray.clear();
262 QList<QLayoutStruct> a(n);
263
264 QSizePolicy::ControlTypes controlTypes1;
265 QSizePolicy::ControlTypes controlTypes2;
266 int fixedSpacing = q->spacing();
267 int previousNonEmptyIndex = -1;
268
269 QStyle *style = nullptr;
270 if (fixedSpacing < 0) {
271 if (QWidget *parentWidget = q->parentWidget())
272 style = parentWidget->style();
273 }
274
275 for (int i = 0; i < n; i++) {
276 QBoxLayoutItem *box = list.at(i);
277 QSize max = box->item->maximumSize();
278 QSize min = box->item->minimumSize();
279 QSize hint = box->item->sizeHint();
280 Qt::Orientations exp = box->item->expandingDirections();
281 bool empty = box->item->isEmpty();
282 int spacing = 0;
283
284 if (!empty) {
285 if (fixedSpacing >= 0) {
286 spacing = (previousNonEmptyIndex >= 0) ? fixedSpacing : 0;
287#ifdef Q_OS_MACOS
288 if (!horz(dir) && previousNonEmptyIndex >= 0) {
289 QBoxLayoutItem *sibling = (dir == QBoxLayout::TopToBottom ? box : list.at(previousNonEmptyIndex));
290 if (sibling) {
291 QWidget *wid = sibling->item->widget();
292 if (wid)
293 spacing = qMax(spacing, sibling->item->geometry().top() - wid->geometry().top());
294 }
295 }
296#endif
297 } else {
298 controlTypes1 = controlTypes2;
299 controlTypes2 = box->item->controlTypes();
300 if (previousNonEmptyIndex >= 0) {
301 QSizePolicy::ControlTypes actual1 = controlTypes1;
302 QSizePolicy::ControlTypes actual2 = controlTypes2;
303 if (dir == QBoxLayout::RightToLeft || dir == QBoxLayout::BottomToTop)
304 qSwap(actual1, actual2);
305
306 if (style) {
307 spacing = style->combinedLayoutSpacing(actual1, actual2,
308 horz(dir) ? Qt::Horizontal : Qt::Vertical,
309 nullptr, q->parentWidget());
310 if (spacing < 0)
311 spacing = 0;
312 }
313 }
314 }
315
316 if (previousNonEmptyIndex >= 0)
317 a[previousNonEmptyIndex].spacing = spacing;
318 previousNonEmptyIndex = i;
319 }
320
321 bool ignore = empty && box->item->widget(); // ignore hidden widgets
322 bool dummy = true;
323 if (horz(dir)) {
324 bool expand = (exp & Qt::Horizontal || box->stretch > 0);
325 horexp = horexp || expand;
326 maxw += spacing + max.width();
327 minw += spacing + min.width();
328 hintw += spacing + hint.width();
329 if (!ignore)
330 qMaxExpCalc(maxh, verexp, dummy,
331 max.height(), exp & Qt::Vertical, box->item->isEmpty());
332 minh = qMax(minh, min.height());
333 hinth = qMax(hinth, hint.height());
334
335 a[i].sizeHint = hint.width();
336 a[i].maximumSize = max.width();
337 a[i].minimumSize = min.width();
338 a[i].expansive = expand;
339 a[i].stretch = box->stretch ? box->stretch : box->hStretch();
340 } else {
341 bool expand = (exp & Qt::Vertical || box->stretch > 0);
342 verexp = verexp || expand;
343 maxh += spacing + max.height();
344 minh += spacing + min.height();
345 hinth += spacing + hint.height();
346 if (!ignore)
347 qMaxExpCalc(maxw, horexp, dummy,
348 max.width(), exp & Qt::Horizontal, box->item->isEmpty());
349 minw = qMax(minw, min.width());
350 hintw = qMax(hintw, hint.width());
351
352 a[i].sizeHint = hint.height();
353 a[i].maximumSize = max.height();
354 a[i].minimumSize = min.height();
355 a[i].expansive = expand;
356 a[i].stretch = box->stretch ? box->stretch : box->vStretch();
357 }
358
359 a[i].empty = empty;
360 a[i].spacing = 0; // might be initialized with a non-zero value in a later iteration
361 hasHfw = hasHfw || box->item->hasHeightForWidth();
362 }
363
364 geomArray = a;
365
366 expanding = (Qt::Orientations)
367 ((horexp ? Qt::Horizontal : 0)
368 | (verexp ? Qt::Vertical : 0));
369
370 minSize = QSize(minw, minh);
371 maxSize = QSize(maxw, maxh).expandedTo(minSize);
372 sizeHint = QSize(hintw, hinth).expandedTo(minSize).boundedTo(maxSize);
373
374 q->getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
375 int left, top, right, bottom;
376 effectiveMargins(&left, &top, &right, &bottom);
377 QSize extra(left + right, top + bottom);
378
379 minSize += extra;
380 maxSize += extra;
381 sizeHint += extra;
382
383 dirty = false;
384}
385
386/*
387 Calculates and stores the preferred height given the width \a w.
388*/
390{
391 QList<QLayoutStruct> &a = geomArray;
392 int n = a.size();
393 int h = 0;
394 int mh = 0;
395
396 Q_ASSERT(n == list.size());
397
398 if (horz(dir)) {
399 qGeomCalc(a, 0, n, 0, w);
400 for (int i = 0; i < n; i++) {
401 QBoxLayoutItem *box = list.at(i);
402 h = qMax(h, box->hfw(a.at(i).size));
403 mh = qMax(mh, box->mhfw(a.at(i).size));
404 }
405 } else {
406 for (int i = 0; i < n; ++i) {
407 QBoxLayoutItem *box = list.at(i);
408 int spacing = a.at(i).spacing;
409 h += box->hfw(w);
410 mh += box->mhfw(w);
411 h += spacing;
412 mh += spacing;
413 }
414 }
415 hfwWidth = w;
416 hfwHeight = h;
417 hfwMinHeight = mh;
418}
419
420QLayoutItem* QBoxLayoutPrivate::replaceAt(int index, QLayoutItem *item)
421{
422 Q_Q(QBoxLayout);
423 if (!item)
424 return nullptr;
425 QBoxLayoutItem *b = list.value(index);
426 if (!b)
427 return nullptr;
428 QLayoutItem *r = b->item;
429
430 b->item = item;
431 q->invalidate();
432 return r;
433}
434
435int QBoxLayoutPrivate::validateIndex(int index) const
436{
437 if (index < 0)
438 return list.size(); // append
439
440 if (index > list.size())
441 qWarning("QBoxLayout::insert: index %d out of range (max: %d)", index, int(list.size()));
442 return index <= list.size() ? index : list.size();
443}
444
445/*!
446 \class QBoxLayout
447
448 \brief The QBoxLayout class lines up child widgets horizontally or
449 vertically.
450
451 \ingroup geomanagement
452 \inmodule QtWidgets
453
454 QBoxLayout takes the space it gets (from its parent layout or from
455 the parentWidget()), divides it up into a row of boxes, and makes
456 each managed widget fill one box.
457
458 \image qhboxlayout-with-5-children.png {Five buttons in horizontal layout}
459
460 If the QBoxLayout's orientation is Qt::Horizontal the boxes are
461 placed in a row, with suitable sizes. Each widget (or other box)
462 will get at least its minimum size and at most its maximum size.
463 Any excess space is shared according to the stretch factors (more
464 about that below).
465
466 \image qvboxlayout-with-5-children.png {Five buttons in vertical layout}
467
468 If the QBoxLayout's orientation is Qt::Vertical, the boxes are
469 placed in a column, again with suitable sizes.
470
471 The easiest way to create a QBoxLayout is to use one of the
472 convenience classes, e.g. QHBoxLayout (for Qt::Horizontal boxes)
473 or QVBoxLayout (for Qt::Vertical boxes). You can also use the
474 QBoxLayout constructor directly, specifying its direction as
475 LeftToRight, RightToLeft, TopToBottom, or BottomToTop.
476
477 If the QBoxLayout is not the top-level layout (i.e. it is not
478 managing all of the widget's area and children), you must add it
479 to its parent layout before you can do anything with it. The
480 normal way to add a layout is by calling
481 parentLayout->addLayout().
482
483 Once you have done this, you can add boxes to the QBoxLayout using
484 one of four functions:
485
486 \list
487 \li addWidget() to add a widget to the QBoxLayout and set the
488 widget's stretch factor. (The stretch factor is along the row of
489 boxes.)
490
491 \li addSpacing() to create an empty box; this is one of the
492 functions you use to create nice and spacious dialogs. See below
493 for ways to set margins.
494
495 \li addStretch() to create an empty, stretchable box.
496
497 \li addLayout() to add a box containing another QLayout to the row
498 and set that layout's stretch factor.
499 \endlist
500
501 Use insertWidget(), insertSpacing(), insertStretch() or
502 insertLayout() to insert a box at a specified position in the
503 layout.
504
505 QBoxLayout also includes two margin widths:
506
507 \list
508 \li setContentsMargins() sets the width of the outer border on
509 each side of the widget. This is the width of the reserved space
510 along each of the QBoxLayout's four sides.
511 \li setSpacing() sets the width between neighboring boxes. (You
512 can use addSpacing() to get more space at a particular spot.)
513 \endlist
514
515 The margin default is provided by the style. The default margin
516 most Qt styles specify is 9 for child widgets and 11 for windows.
517 The spacing defaults to the same as the margin width for a
518 top-level layout, or to the same as the parent layout.
519
520 To remove a widget from a layout, call removeWidget(). Calling
521 QWidget::hide() on a widget also effectively removes the widget
522 from the layout until QWidget::show() is called.
523
524 You will almost always want to use QVBoxLayout and QHBoxLayout
525 rather than QBoxLayout because of their convenient constructors.
526
527 \sa QGridLayout, QStackedLayout, {Layout Management}
528*/
529
530/*!
531 \enum QBoxLayout::Direction
532
533 This type is used to determine the direction of a box layout.
534
535 \value LeftToRight Horizontal from left to right.
536 \value RightToLeft Horizontal from right to left.
537 \value TopToBottom Vertical from top to bottom.
538 \value BottomToTop Vertical from bottom to top.
539
540 \omitvalue Down
541 \omitvalue Up
542*/
543
544/*!
545 Constructs a new QBoxLayout with direction \a dir and parent widget \a
546 parent.
547
548 The layout is set directly as the top-level layout for \a parent.
549 There can be only one top-level layout for a widget. It is returned
550 by QWidget::layout().
551
552 \sa direction(), QWidget::setLayout()
553*/
554QBoxLayout::QBoxLayout(Direction dir, QWidget *parent)
555 : QLayout(*new QBoxLayoutPrivate, nullptr, parent)
556{
557 Q_D(QBoxLayout);
558 d->dir = dir;
559}
560
561
562
563/*!
564 Destroys this box layout.
565
566 The layout's widgets aren't destroyed.
567*/
568QBoxLayout::~QBoxLayout()
569{
570 Q_D(QBoxLayout);
571 d->deleteAll(); // must do it before QObject deletes children, so can't be in ~QBoxLayoutPrivate
572}
573
574/*!
575 Reimplements QLayout::spacing(). If the spacing property is
576 valid, that value is returned. Otherwise, a value for the spacing
577 property is computed and returned. Since layout spacing in a widget
578 is style dependent, if the parent is a widget, it queries the style
579 for the (horizontal or vertical) spacing of the layout. Otherwise,
580 the parent is a layout, and it queries the parent layout for the
581 spacing().
582
583 \sa QLayout::spacing(), setSpacing()
584 */
585int QBoxLayout::spacing() const
586{
587 Q_D(const QBoxLayout);
588 if (d->spacing >=0) {
589 return d->spacing;
590 } else {
591 return qSmartSpacing(this, d->dir == LeftToRight || d->dir == RightToLeft
592 ? QStyle::PM_LayoutHorizontalSpacing
593 : QStyle::PM_LayoutVerticalSpacing);
594 }
595}
596
597/*!
598 Reimplements QLayout::setSpacing(). Sets the spacing
599 property to \a spacing.
600
601 \sa QLayout::setSpacing(), spacing()
602 */
603void QBoxLayout::setSpacing(int spacing)
604{
605 Q_D(QBoxLayout);
606 d->spacing = spacing;
607 invalidate();
608}
609
610/*!
611 \reimp
612*/
613QSize QBoxLayout::sizeHint() const
614{
615 Q_D(const QBoxLayout);
616 if (d->dirty)
617 const_cast<QBoxLayout*>(this)->d_func()->setupGeom();
618 return d->sizeHint;
619}
620
621/*!
622 \reimp
623*/
624QSize QBoxLayout::minimumSize() const
625{
626 Q_D(const QBoxLayout);
627 if (d->dirty)
628 const_cast<QBoxLayout*>(this)->d_func()->setupGeom();
629 return d->minSize;
630}
631
632/*!
633 \reimp
634*/
635QSize QBoxLayout::maximumSize() const
636{
637 Q_D(const QBoxLayout);
638 if (d->dirty)
639 const_cast<QBoxLayout*>(this)->d_func()->setupGeom();
640
641 QSize s = d->maxSize.boundedTo(QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX));
642
643 if (alignment() & Qt::AlignHorizontal_Mask)
644 s.setWidth(QLAYOUTSIZE_MAX);
645 if (alignment() & Qt::AlignVertical_Mask)
646 s.setHeight(QLAYOUTSIZE_MAX);
647 return s;
648}
649
650/*!
651 \reimp
652*/
653bool QBoxLayout::hasHeightForWidth() const
654{
655 Q_D(const QBoxLayout);
656 if (d->dirty)
657 const_cast<QBoxLayout*>(this)->d_func()->setupGeom();
658 return d->hasHfw;
659}
660
661/*!
662 \reimp
663*/
664int QBoxLayout::heightForWidth(int w) const
665{
666 Q_D(const QBoxLayout);
667 if (!hasHeightForWidth())
668 return -1;
669
670 int left, top, right, bottom;
671 d->effectiveMargins(&left, &top, &right, &bottom);
672
673 w -= left + right;
674 if (w != d->hfwWidth)
675 const_cast<QBoxLayout*>(this)->d_func()->calcHfw(w);
676
677 return d->hfwHeight + top + bottom;
678}
679
680/*!
681 \reimp
682*/
683int QBoxLayout::minimumHeightForWidth(int w) const
684{
685 Q_D(const QBoxLayout);
686 (void) heightForWidth(w);
687 int top, bottom;
688 d->effectiveMargins(nullptr, &top, nullptr, &bottom);
689 return d->hasHfw ? (d->hfwMinHeight + top + bottom) : -1;
690}
691
692/*!
693 Resets cached information.
694*/
695void QBoxLayout::invalidate()
696{
697 Q_D(QBoxLayout);
698 d->setDirty();
699 QLayout::invalidate();
700}
701
702/*!
703 \reimp
704*/
705int QBoxLayout::count() const
706{
707 Q_D(const QBoxLayout);
708 return d->list.size();
709}
710
711/*!
712 \reimp
713*/
714QLayoutItem *QBoxLayout::itemAt(int index) const
715{
716 Q_D(const QBoxLayout);
717 return index >= 0 && index < d->list.size() ? d->list.at(index)->item : nullptr;
718}
719
720/*!
721 \reimp
722*/
723QLayoutItem *QBoxLayout::takeAt(int index)
724{
725 Q_D(QBoxLayout);
726 if (index < 0 || index >= d->list.size())
727 return nullptr;
728 QBoxLayoutItem *b = d->list.takeAt(index);
729 QLayoutItem *item = b->item;
730 b->item = nullptr;
731 delete b;
732
733 if (QLayout *l = item->layout()) {
734 // sanity check in case the user passed something weird to QObject::setParent()
735 if (l->parent() == this)
736 l->setParent(nullptr);
737 }
738
739 invalidate();
740 return item;
741}
742
743
744/*!
745 \reimp
746*/
747Qt::Orientations QBoxLayout::expandingDirections() const
748{
749 Q_D(const QBoxLayout);
750 if (d->dirty)
751 const_cast<QBoxLayout*>(this)->d_func()->setupGeom();
752 return d->expanding;
753}
754
755/*!
756 \reimp
757*/
758void QBoxLayout::setGeometry(const QRect &r)
759{
760 Q_D(QBoxLayout);
761 if (d->dirty || r != geometry()) {
762 QRect oldRect = geometry();
763 QLayout::setGeometry(r);
764 if (d->dirty)
765 d->setupGeom();
766 QRect cr = alignment() ? alignmentRect(r) : r;
767
768 int left, top, right, bottom;
769 d->effectiveMargins(&left, &top, &right, &bottom);
770 QRect s(cr.x() + left, cr.y() + top,
771 cr.width() - (left + right),
772 cr.height() - (top + bottom));
773
774 QList<QLayoutStruct> a = d->geomArray;
775 int pos = horz(d->dir) ? s.x() : s.y();
776 int space = horz(d->dir) ? s.width() : s.height();
777 int n = a.size();
778 if (d->hasHfw && !horz(d->dir)) {
779 for (int i = 0; i < n; i++) {
780 QBoxLayoutItem *box = d->list.at(i);
781 if (box->item->hasHeightForWidth()) {
782 int width = qBound(box->item->minimumSize().width(), s.width(), box->item->maximumSize().width());
783 a[i].sizeHint = a[i].minimumSize =
784 box->item->heightForWidth(width);
785 }
786 }
787 }
788
789 Direction visualDir = d->dir;
790 QWidget *parent = parentWidget();
791 if (parent && parent->isRightToLeft()) {
792 if (d->dir == LeftToRight)
793 visualDir = RightToLeft;
794 else if (d->dir == RightToLeft)
795 visualDir = LeftToRight;
796 }
797
798 qGeomCalc(a, 0, n, pos, space);
799
800 bool reverse = (horz(visualDir)
801 ? ((r.right() > oldRect.right()) != (visualDir == RightToLeft))
802 : r.bottom() > oldRect.bottom());
803 for (int j = 0; j < n; j++) {
804 int i = reverse ? n-j-1 : j;
805 QBoxLayoutItem *box = d->list.at(i);
806
807 switch (visualDir) {
808 case LeftToRight:
809 box->item->setGeometry(QRect(a.at(i).pos, s.y(), a.at(i).size, s.height()));
810 break;
811 case RightToLeft:
812 box->item->setGeometry(QRect(s.left() + s.right() - a.at(i).pos - a.at(i).size + 1,
813 s.y(), a.at(i).size, s.height()));
814 break;
815 case TopToBottom:
816 box->item->setGeometry(QRect(s.x(), a.at(i).pos, s.width(), a.at(i).size));
817 break;
818 case BottomToTop:
819 box->item->setGeometry(QRect(s.x(),
820 s.top() + s.bottom() - a.at(i).pos - a.at(i).size + 1,
821 s.width(), a.at(i).size));
822 }
823 }
824 }
825}
826
827/*!
828 \reimp
829*/
830void QBoxLayout::addItem(QLayoutItem *item)
831{
832 Q_D(QBoxLayout);
833 QBoxLayoutItem *it = new QBoxLayoutItem(item);
834 d->list.append(it);
835 invalidate();
836}
837
838/*!
839 Inserts \a item into this box layout at position \a index.
840 Index must be either negative or within the range 0 to count(),
841 inclusive. If \a index is negative or count(), the item is
842 added at the end.
843
844 The ownership of \a item is passed to this layout.
845
846 \sa addItem(), insertWidget(), insertLayout(), insertStretch(),
847 insertSpacing()
848*/
849void QBoxLayout::insertItem(int index, QLayoutItem *item)
850{
851 Q_D(QBoxLayout);
852 index = d->validateIndex(index);
853 QBoxLayoutItem *it = new QBoxLayoutItem(item);
854 d->list.insert(index, it);
855 invalidate();
856}
857
858/*!
859 Inserts a non-stretchable space (a QSpacerItem) at position \a index, with
860 size \a size. If \a index is negative the space is added at the end.
861
862 The box layout has default margin and spacing. This function adds
863 additional space.
864
865 \sa addSpacing(), insertItem(), QSpacerItem
866*/
867void QBoxLayout::insertSpacing(int index, int size)
868{
869 Q_D(QBoxLayout);
870 index = d->validateIndex(index);
871 QLayoutItem *b;
872 if (horz(d->dir))
873 b = QLayoutPrivate::createSpacerItem(this, size, 0, QSizePolicy::Fixed, QSizePolicy::Minimum);
874 else
875 b = QLayoutPrivate::createSpacerItem(this, 0, size, QSizePolicy::Minimum, QSizePolicy::Fixed);
876
877 QBoxLayoutItem *it = new QBoxLayoutItem(b);
878 it->magic = true;
879 d->list.insert(index, it);
880 invalidate();
881}
882
883/*!
884 Inserts a stretchable space (a QSpacerItem) at position \a
885 index, with zero minimum size and stretch factor \a stretch. If \a
886 index is negative the space is added at the end.
887
888 \sa addStretch(), insertItem(), QSpacerItem
889*/
890void QBoxLayout::insertStretch(int index, int stretch)
891{
892 Q_D(QBoxLayout);
893 index = d->validateIndex(index);
894 QLayoutItem *b;
895 if (horz(d->dir))
896 b = QLayoutPrivate::createSpacerItem(this, 0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum);
897 else
898 b = QLayoutPrivate::createSpacerItem(this, 0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
899
900 QBoxLayoutItem *it = new QBoxLayoutItem(b, stretch);
901 it->magic = true;
902 d->list.insert(index, it);
903 invalidate();
904}
905
906/*!
907 \since 4.4
908
909 Inserts \a spacerItem at position \a index, with zero minimum
910 size and stretch factor. If \a index is negative the
911 space is added at the end.
912
913 The ownership of \a spacerItem is passed to this layout.
914
915 \sa addSpacerItem(), insertStretch(), insertSpacing()
916*/
917void QBoxLayout::insertSpacerItem(int index, QSpacerItem *spacerItem)
918{
919 Q_D(QBoxLayout);
920 index = d->validateIndex(index);
921 QBoxLayoutItem *it = new QBoxLayoutItem(spacerItem);
922 it->magic = true;
923 d->list.insert(index, it);
924 invalidate();
925}
926
927/*!
928 Inserts \a layout at position \a index, with stretch factor \a
929 stretch. If \a index is negative, the layout is added at the end.
930
931 \a layout becomes a child of the box layout.
932
933 \sa addLayout(), insertItem()
934*/
935void QBoxLayout::insertLayout(int index, QLayout *layout, int stretch)
936{
937 Q_D(QBoxLayout);
938 if (!d->checkLayout(layout))
939 return;
940 if (!adoptLayout(layout))
941 return;
942 index = d->validateIndex(index);
943 QBoxLayoutItem *it = new QBoxLayoutItem(layout, stretch);
944 d->list.insert(index, it);
945 invalidate();
946}
947
948/*!
949 Inserts \a widget at position \a index, with stretch factor \a
950 stretch and alignment \a alignment. If \a index is negative, the
951 widget is added at the end.
952
953 The stretch factor applies only in the \l{direction()}{direction}
954 of the QBoxLayout, and is relative to the other boxes and widgets
955 in this QBoxLayout. Widgets and boxes with higher stretch factors
956 grow more.
957
958 If the stretch factor is 0 and nothing else in the QBoxLayout has
959 a stretch factor greater than zero, the space is distributed
960 according to the QWidget::sizePolicy() of each widget that's
961 involved.
962
963 The alignment is specified by \a alignment. The default alignment
964 is 0, which means that the widget fills the entire cell.
965
966 \a widget becomes a child of the QLayout::parentWidget().
967
968 \sa addWidget(), insertItem()
969*/
970void QBoxLayout::insertWidget(int index, QWidget *widget, int stretch,
971 Qt::Alignment alignment)
972{
973 Q_D(QBoxLayout);
974 if (!d->checkWidget(widget))
975 return;
976 addChildWidget(widget);
977 index = d->validateIndex(index);
978 QWidgetItem *b = QLayoutPrivate::createWidgetItem(this, widget);
979 b->setAlignment(alignment);
980
981 QBoxLayoutItem *it = new QBoxLayoutItem(b, stretch);
982 d->list.insert(index, it);
983 invalidate();
984}
985
986/*!
987 Adds a non-stretchable space (a QSpacerItem) with size \a size
988 to the end of this box layout. QBoxLayout provides default margin
989 and spacing. This function adds additional space.
990
991 \sa insertSpacing(), addItem(), QSpacerItem
992*/
993void QBoxLayout::addSpacing(int size)
994{
995 insertSpacing(-1, size);
996}
997
998/*!
999 Adds a stretchable space (a QSpacerItem) with zero minimum
1000 size and stretch factor \a stretch to the end of this box layout.
1001
1002 \sa insertStretch(), addItem(), QSpacerItem
1003*/
1004void QBoxLayout::addStretch(int stretch)
1005{
1006 insertStretch(-1, stretch);
1007}
1008
1009/*!
1010 \since 4.4
1011
1012 Adds \a spacerItem to the end of this box layout.
1013
1014 The ownership of \a spacerItem is passed to this layout.
1015
1016 \sa addSpacing(), addStretch()
1017*/
1018void QBoxLayout::addSpacerItem(QSpacerItem *spacerItem)
1019{
1020 insertSpacerItem(-1, spacerItem);
1021}
1022
1023/*!
1024 Adds \a widget to the end of this box layout, with a stretch
1025 factor of \a stretch and alignment \a alignment.
1026
1027 The stretch factor applies only in the \l{direction()}{direction}
1028 of the QBoxLayout, and is relative to the other boxes and widgets
1029 in this QBoxLayout. Widgets and boxes with higher stretch factors
1030 grow more.
1031
1032 If the stretch factor is 0 and nothing else in the QBoxLayout has
1033 a stretch factor greater than zero, the space is distributed
1034 according to the QWidget::sizePolicy() of each widget that's
1035 involved.
1036
1037 The alignment is specified by \a alignment. The default
1038 alignment is 0, which means that the widget fills the entire cell.
1039
1040 \a widget becomes a child of the QLayout::parentWidget().
1041
1042 \sa insertWidget(), addItem(), addLayout(), addStretch(),
1043 addSpacing(), addStrut()
1044*/
1045void QBoxLayout::addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
1046{
1047 insertWidget(-1, widget, stretch, alignment);
1048}
1049
1050/*!
1051 Adds \a layout to the end of the box, with serial stretch factor
1052 \a stretch.
1053
1054 \a layout becomes a child of the box layout.
1055
1056 \sa insertLayout(), addItem(), addWidget()
1057*/
1058void QBoxLayout::addLayout(QLayout *layout, int stretch)
1059{
1060 insertLayout(-1, layout, stretch);
1061}
1062
1063/*!
1064 Limits the perpendicular dimension of the box (e.g. height if the
1065 box is \l LeftToRight) to a minimum of \a size. Other constraints
1066 may increase the limit.
1067
1068 \sa addItem()
1069*/
1070void QBoxLayout::addStrut(int size)
1071{
1072 Q_D(QBoxLayout);
1073 QLayoutItem *b;
1074 if (horz(d->dir))
1075 b = QLayoutPrivate::createSpacerItem(this, 0, size, QSizePolicy::Fixed, QSizePolicy::Minimum);
1076 else
1077 b = QLayoutPrivate::createSpacerItem(this, size, 0, QSizePolicy::Minimum, QSizePolicy::Fixed);
1078
1079 QBoxLayoutItem *it = new QBoxLayoutItem(b);
1080 it->magic = true;
1081 d->list.append(it);
1082 invalidate();
1083}
1084
1085/*!
1086 Sets the stretch factor for \a widget to \a stretch and returns
1087 true if \a widget is found in this layout (not including child
1088 layouts); otherwise returns \c false.
1089
1090 \sa setAlignment()
1091*/
1092bool QBoxLayout::setStretchFactor(QWidget *widget, int stretch)
1093{
1094 Q_D(QBoxLayout);
1095 if (!widget)
1096 return false;
1097 for (int i = 0; i < d->list.size(); ++i) {
1098 QBoxLayoutItem *box = d->list.at(i);
1099 if (box->item->widget() == widget) {
1100 box->stretch = stretch;
1101 invalidate();
1102 return true;
1103 }
1104 }
1105 return false;
1106}
1107
1108/*!
1109 \overload
1110
1111 Sets the stretch factor for the layout \a layout to \a stretch and
1112 returns \c true if \a layout is found in this layout (not including
1113 child layouts); otherwise returns \c false.
1114*/
1115bool QBoxLayout::setStretchFactor(QLayout *layout, int stretch)
1116{
1117 Q_D(QBoxLayout);
1118 for (int i = 0; i < d->list.size(); ++i) {
1119 QBoxLayoutItem *box = d->list.at(i);
1120 if (box->item->layout() == layout) {
1121 if (box->stretch != stretch) {
1122 box->stretch = stretch;
1123 invalidate();
1124 }
1125 return true;
1126 }
1127 }
1128 return false;
1129}
1130
1131/*!
1132 Sets the stretch factor at position \a index. to \a stretch.
1133
1134 \since 4.5
1135*/
1136
1137void QBoxLayout::setStretch(int index, int stretch)
1138{
1139 Q_D(QBoxLayout);
1140 if (index >= 0 && index < d->list.size()) {
1141 QBoxLayoutItem *box = d->list.at(index);
1142 if (box->stretch != stretch) {
1143 box->stretch = stretch;
1144 invalidate();
1145 }
1146 }
1147}
1148
1149/*!
1150 Returns the stretch factor at position \a index.
1151
1152 \since 4.5
1153*/
1154
1155int QBoxLayout::stretch(int index) const
1156{
1157 Q_D(const QBoxLayout);
1158 if (index >= 0 && index < d->list.size())
1159 return d->list.at(index)->stretch;
1160 return -1;
1161}
1162
1163/*!
1164 Sets the direction of this layout to \a direction.
1165*/
1166void QBoxLayout::setDirection(Direction direction)
1167{
1168 Q_D(QBoxLayout);
1169 if (d->dir == direction)
1170 return;
1171 if (horz(d->dir) != horz(direction)) {
1172 //swap around the spacers (the "magic" bits)
1173 //#### a bit yucky, knows too much.
1174 //#### probably best to add access functions to spacerItem
1175 //#### or even a QSpacerItem::flip()
1176 for (int i = 0; i < d->list.size(); ++i) {
1177 QBoxLayoutItem *box = d->list.at(i);
1178 if (box->magic) {
1179 QSpacerItem *sp = box->item->spacerItem();
1180 if (sp) {
1181 if (sp->expandingDirections() == Qt::Orientations{} /*No Direction*/) {
1182 //spacing or strut
1183 QSize s = sp->sizeHint();
1184 sp->changeSize(s.height(), s.width(),
1185 horz(direction) ? QSizePolicy::Fixed:QSizePolicy::Minimum,
1186 horz(direction) ? QSizePolicy::Minimum:QSizePolicy::Fixed);
1187
1188 } else {
1189 //stretch
1190 if (horz(direction))
1191 sp->changeSize(0, 0, QSizePolicy::Expanding,
1192 QSizePolicy::Minimum);
1193 else
1194 sp->changeSize(0, 0, QSizePolicy::Minimum,
1195 QSizePolicy::Expanding);
1196 }
1197 }
1198 }
1199 }
1200 }
1201 d->dir = direction;
1202 invalidate();
1203}
1204
1205/*!
1206 \fn QBoxLayout::Direction QBoxLayout::direction() const
1207
1208 Returns the direction of the box. addWidget() and addSpacing()
1209 work in this direction; the stretch stretches in this direction.
1210
1211 \sa QBoxLayout::Direction, addWidget(), addSpacing()
1212*/
1213
1214QBoxLayout::Direction QBoxLayout::direction() const
1215{
1216 Q_D(const QBoxLayout);
1217 return d->dir;
1218}
1219
1220/*!
1221 \class QHBoxLayout
1222 \brief The QHBoxLayout class lines up widgets horizontally.
1223
1224 \ingroup geomanagement
1225 \inmodule QtWidgets
1226
1227 This class is used to construct horizontal box layout objects. See
1228 QBoxLayout for details.
1229
1230 The simplest use of the class is like this:
1231
1232 \snippet layouts/layouts.cpp 0
1233 \snippet layouts/layouts.cpp 1
1234 \snippet layouts/layouts.cpp 2
1235 \codeline
1236 \snippet layouts/layouts.cpp 3
1237 \snippet layouts/layouts.cpp 4
1238 \snippet layouts/layouts.cpp 5
1239
1240 First, we create the widgets we want to add to the layout. Then,
1241 we create the QHBoxLayout object, setting \c window as parent by
1242 passing it in the constructor; next we add the widgets to the
1243 layout. \c window will be the parent of the widgets that are
1244 added to the layout.
1245
1246 If you don't pass a parent \c window to the constructor, you can
1247 at a later point use QWidget::setLayout() to install the QHBoxLayout
1248 object onto \c window. At that point, the widgets in the layout are
1249 reparented to have \c window as their parent.
1250
1251 \image qhboxlayout-with-5-children.png
1252 {Five buttons in horizontal layout}
1253
1254 \sa QVBoxLayout, QGridLayout, QStackedLayout, {Layout Management}, {Basic Layouts Example}
1255*/
1256
1257
1258/*!
1259 Constructs a new top-level horizontal box with parent \a parent.
1260
1261 The layout is set directly as the top-level layout for \a parent.
1262 There can be only one top-level layout for a widget. It is returned
1263 by QWidget::layout().
1264
1265 \sa QWidget::setLayout()
1266*/
1267QHBoxLayout::QHBoxLayout(QWidget *parent)
1268 : QBoxLayout(LeftToRight, parent)
1269{
1270}
1271
1272/*!
1273 Constructs a new horizontal box. You must add
1274 it to another layout.
1275*/
1276QHBoxLayout::QHBoxLayout()
1277 : QBoxLayout(LeftToRight)
1278{
1279}
1280
1281
1282
1283
1284
1285/*!
1286 Destroys this box layout.
1287
1288 The layout's widgets aren't destroyed.
1289*/
1290QHBoxLayout::~QHBoxLayout()
1291{
1292}
1293
1294/*!
1295 \class QVBoxLayout
1296 \brief The QVBoxLayout class lines up widgets vertically.
1297
1298 \ingroup geomanagement
1299 \inmodule QtWidgets
1300
1301 This class is used to construct vertical box layout objects. See
1302 QBoxLayout for details.
1303
1304 The simplest use of the class is like this:
1305
1306 \snippet layouts/layouts.cpp 6
1307 \snippet layouts/layouts.cpp 7
1308 \snippet layouts/layouts.cpp 8
1309 \codeline
1310 \snippet layouts/layouts.cpp 9
1311 \snippet layouts/layouts.cpp 10
1312 \snippet layouts/layouts.cpp 11
1313
1314 First, we create the widgets we want to add to the layout. Then,
1315 we create the QVBoxLayout object, setting \c window as parent by
1316 passing it in the constructor; next we add the widgets to the
1317 layout. \c window will be the parent of the widgets that are
1318 added to the layout.
1319
1320 If you don't pass a parent \c window to the constructor, you can
1321 at a later point use QWidget::setLayout() to install the QVBoxLayout
1322 object onto \c window. At that point, the widgets in the layout are
1323 reparented to have \c window as their parent.
1324
1325 \image qvboxlayout-with-5-children.png
1326 {Horizontal box layout with five child widgets}
1327
1328 \sa QHBoxLayout, QGridLayout, QStackedLayout, {Layout Management}, {Basic Layouts Example}
1329*/
1330
1331/*!
1332 Constructs a new top-level vertical box with parent \a parent.
1333
1334 The layout is set directly as the top-level layout for \a parent.
1335 There can be only one top-level layout for a widget. It is returned
1336 by QWidget::layout().
1337
1338 \sa QWidget::setLayout()
1339*/
1340QVBoxLayout::QVBoxLayout(QWidget *parent)
1341 : QBoxLayout(TopToBottom, parent)
1342{
1343}
1344
1345/*!
1346 Constructs a new vertical box. You must add
1347 it to another layout.
1348
1349*/
1350QVBoxLayout::QVBoxLayout()
1351 : QBoxLayout(TopToBottom)
1352{
1353}
1354
1355
1356/*!
1357 Destroys this box layout.
1358
1359 The layout's widgets aren't destroyed.
1360*/
1361QVBoxLayout::~QVBoxLayout()
1362{
1363}
1364
1365QT_END_NAMESPACE
1366
1367#include "moc_qboxlayout.cpp"
QList< QBoxLayoutItem * > list
QLayoutItem * replaceAt(int index, QLayoutItem *) override
void effectiveMargins(int *left, int *top, int *right, int *bottom) const
int validateIndex(int index) const
QList< QLayoutStruct > geomArray
Qt::Orientations expanding
Definition qlist.h:82
\inmodule QtCore
Definition qsize.h:27
Combined button and popup list for selecting options.
static bool horz(QBoxLayout::Direction dir)
int mhfw(int w)
QBoxLayoutItem(QLayoutItem *it, int stretch_=0)
int hfw(int w)
QLayoutItem * item