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