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