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