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
4#include "qlayout.h"
5
6#include "qlayoutengine_p.h"
7#include "qguiapplication.h"
8#include "qevent.h"
9#include "qstyle.h"
10#include "qwidget_p.h"
11#include "qlayout_p.h"
12
13QT_BEGIN_NAMESPACE
14
15static int menuBarHeightForWidth(QWidget *menubar, int w)
16{
17 if (menubar && !menubar->isHidden() && !menubar->isWindow()) {
18 int result = menubar->heightForWidth(qMax(a: w, b: menubar->minimumWidth()));
19 if (result == -1)
20 result = menubar->sizeHint().height();
21 const int min = qSmartMinSize(w: menubar).height();
22 result = qBound(min, val: result, max: menubar->maximumSize().height());
23 if (result != -1)
24 return result;
25 }
26 return 0;
27}
28
29/*!
30 \class QLayout
31 \brief The QLayout class is the base class of geometry managers.
32
33 \ingroup geomanagement
34 \inmodule QtWidgets
35
36 This is an abstract base class inherited by the concrete classes
37 QBoxLayout, QGridLayout, QFormLayout, and QStackedLayout.
38
39 For users of QLayout subclasses or of QMainWindow there is seldom
40 any need to use the basic functions provided by QLayout, such as
41 setSizeConstraint() or setMenuBar(). See \l{Layout Management}
42 for more information.
43
44 To make your own layout manager, implement the functions
45 addItem(), sizeHint(), setGeometry(), itemAt() and takeAt(). You
46 should also implement minimumSize() to ensure your layout isn't
47 resized to zero size if there is too little space. To support
48 children whose heights depend on their widths, implement
49 hasHeightForWidth() and heightForWidth(). See the
50 \l{layouts/flowlayout}{Flow Layout} example for
51 more information about implementing custom layout managers.
52
53 Geometry management stops when the layout manager is deleted.
54
55 \sa QLayoutItem, {Layout Management}, {Basic Layouts Example},
56 {Flow Layout Example}
57*/
58
59
60/*!
61 Constructs a new top-level QLayout, with parent \a parent.
62
63 The layout is set directly as the top-level layout for
64 \a parent. There can be only one top-level layout for a
65 widget. It is returned by QWidget::layout().
66
67 If \a parent is \nullptr, then you must insert this layout
68 into another layout, or set it as a widget's layout using
69 QWidget::setLayout().
70
71 \sa QWidget::setLayout()
72*/
73QLayout::QLayout(QWidget *parent)
74 : QObject(*new QLayoutPrivate, parent)
75{
76 if (!parent)
77 return;
78 parent->setLayout(this);
79}
80
81/*! \internal
82 */
83QLayout::QLayout(QLayoutPrivate &dd, QLayout *lay, QWidget *w)
84 : QObject(dd, lay ? static_cast<QObject*>(lay) : static_cast<QObject*>(w))
85{
86 Q_D(QLayout);
87 if (lay) {
88 lay->addItem(this);
89 } else if (w) {
90 if (Q_UNLIKELY(w->layout())) {
91 qWarning(msg: "QLayout: Attempting to add QLayout \"%ls\" to %s \"%ls\", which"
92 " already has a layout",
93 qUtf16Printable(QObject::objectName()), w->metaObject()->className(),
94 qUtf16Printable(w->objectName()));
95 setParent(nullptr);
96 } else {
97 d->topLevel = true;
98 w->d_func()->layout = this;
99 QT_TRY {
100 invalidate();
101 } QT_CATCH(...) {
102 w->d_func()->layout = nullptr;
103 QT_RETHROW;
104 }
105 }
106 }
107}
108
109QLayoutPrivate::QLayoutPrivate()
110 : QObjectPrivate(), insideSpacing(-1), userLeftMargin(-1), userTopMargin(-1), userRightMargin(-1),
111 userBottomMargin(-1), topLevel(false), enabled(true), activated(true), autoNewChild(false),
112 horizontalConstraint(QLayout::SetDefaultConstraint), verticalConstraint(QLayout::SetDefaultConstraint), menubar(nullptr)
113{
114}
115
116void QLayoutPrivate::getMargin(int *result, int userMargin, QStyle::PixelMetric pm) const
117{
118 if (!result)
119 return;
120
121 Q_Q(const QLayout);
122 if (userMargin >= 0) {
123 *result = userMargin;
124 } else if (!topLevel) {
125 *result = 0;
126 } else if (QWidget *pw = q->parentWidget()) {
127 *result = pw->style()->pixelMetric(metric: pm, option: nullptr, widget: pw);
128 } else {
129 *result = 0;
130 }
131}
132
133// Static item factory functions that allow for hooking things in Designer
134
135QLayoutPrivate::QWidgetItemFactoryMethod QLayoutPrivate::widgetItemFactoryMethod = nullptr;
136QLayoutPrivate::QSpacerItemFactoryMethod QLayoutPrivate::spacerItemFactoryMethod = nullptr;
137
138QWidgetItem *QLayoutPrivate::createWidgetItem(const QLayout *layout, QWidget *widget)
139{
140 if (widgetItemFactoryMethod)
141 if (QWidgetItem *wi = (*widgetItemFactoryMethod)(layout, widget))
142 return wi;
143 return new QWidgetItemV2(widget);
144}
145
146QSpacerItem *QLayoutPrivate::createSpacerItem(const QLayout *layout, int w, int h, QSizePolicy::Policy hPolicy, QSizePolicy::Policy vPolicy)
147{
148 if (spacerItemFactoryMethod)
149 if (QSpacerItem *si = (*spacerItemFactoryMethod)(layout, w, h, hPolicy, vPolicy))
150 return si;
151 return new QSpacerItem(w, h, hPolicy, vPolicy);
152}
153
154
155
156/*!
157 \fn void QLayout::addItem(QLayoutItem *item)
158
159 Implemented in subclasses to add an \a item. How it is added is
160 specific to each subclass.
161
162 This function is not usually called in application code. To add a widget
163 to a layout, use the addWidget() function; to add a child layout, use the
164 addLayout() function provided by the relevant QLayout subclass.
165
166 \b{Note:} The ownership of \a item is transferred to the layout, and it's
167 the layout's responsibility to delete it.
168
169 \sa addWidget(), QBoxLayout::addLayout(), QGridLayout::addLayout()
170*/
171
172/*!
173 Adds widget \a w to this layout in a manner specific to the
174 layout. This function uses addItem().
175*/
176void QLayout::addWidget(QWidget *w)
177{
178 addChildWidget(w);
179 addItem(QLayoutPrivate::createWidgetItem(layout: this, widget: w));
180}
181
182
183
184/*!
185 Sets the alignment for widget \a w to \a alignment and returns
186 true if \a w is found in this layout (not including child
187 layouts); otherwise returns \c false.
188*/
189bool QLayout::setAlignment(QWidget *w, Qt::Alignment alignment)
190{
191 int i = 0;
192 QLayoutItem *item = itemAt(index: i);
193 while (item) {
194 if (item->widget() == w) {
195 item->setAlignment(alignment);
196 invalidate();
197 return true;
198 }
199 ++i;
200 item = itemAt(index: i);
201 }
202 return false;
203}
204
205/*!
206 \overload
207
208 Sets the alignment for the layout \a l to \a alignment and
209 returns \c true if \a l is found in this layout (not including child
210 layouts); otherwise returns \c false.
211*/
212bool QLayout::setAlignment(QLayout *l, Qt::Alignment alignment)
213{
214 int i = 0;
215 QLayoutItem *item = itemAt(index: i);
216 while (item) {
217 if (item->layout() == l) {
218 item->setAlignment(alignment);
219 invalidate();
220 return true;
221 }
222 ++i;
223 item = itemAt(index: i);
224 }
225 return false;
226}
227
228/*!
229 \property QLayout::spacing
230 \brief the spacing between widgets inside the layout
231
232 If no value is explicitly set, the layout's spacing is inherited
233 from the parent layout, or from the style settings for the parent
234 widget.
235
236 For QGridLayout and QFormLayout, it is possible to set different horizontal and
237 vertical spacings using \l{QGridLayout::}{setHorizontalSpacing()}
238 and \l{QGridLayout::}{setVerticalSpacing()}. In that case,
239 spacing() returns -1.
240
241 \sa contentsRect(), getContentsMargins(), QStyle::layoutSpacing(),
242 QStyle::pixelMetric()
243*/
244
245int QLayout::spacing() const
246{
247 Q_D(const QLayout);
248 if (d->insideSpacing >=0) {
249 return d->insideSpacing;
250 } else {
251 // arbitrarily prefer horizontal spacing to vertical spacing
252 return qSmartSpacing(layout: this, pm: QStyle::PM_LayoutHorizontalSpacing);
253 }
254}
255
256void QLayout::setSpacing(int spacing)
257{
258 Q_D(QLayout);
259 d->insideSpacing = spacing;
260 invalidate();
261}
262
263/*!
264 \since 4.3
265
266 Sets the \a left, \a top, \a right, and \a bottom margins to use
267 around the layout.
268
269 By default, QLayout uses the values provided by the style. On
270 most platforms, the margin is 11 pixels in all directions.
271
272 \sa getContentsMargins(), QStyle::pixelMetric(),
273 {QStyle::}{PM_LayoutLeftMargin},
274 {QStyle::}{PM_LayoutTopMargin},
275 {QStyle::}{PM_LayoutRightMargin},
276 {QStyle::}{PM_LayoutBottomMargin}
277*/
278void QLayout::setContentsMargins(int left, int top, int right, int bottom)
279{
280 Q_D(QLayout);
281
282 if (d->userLeftMargin == left && d->userTopMargin == top &&
283 d->userRightMargin == right && d->userBottomMargin == bottom)
284 return;
285
286 d->userLeftMargin = left;
287 d->userTopMargin = top;
288 d->userRightMargin = right;
289 d->userBottomMargin = bottom;
290 invalidate();
291}
292
293/*!
294 \since 4.6
295
296 Sets the \a margins to use around the layout.
297
298 By default, QLayout uses the values provided by the style. On
299 most platforms, the margin is 11 pixels in all directions.
300
301 \sa contentsMargins()
302*/
303void QLayout::setContentsMargins(const QMargins &margins)
304{
305 setContentsMargins(left: margins.left(), top: margins.top(), right: margins.right(), bottom: margins.bottom());
306}
307
308/*!
309 \since 6.1
310
311 Unsets any user-defined margins around the layout. The layout will
312 use the default values provided by the style.
313
314 \sa setContentsMargins()
315*/
316void QLayout::unsetContentsMargins()
317{
318 setContentsMargins(left: -1, top: -1, right: -1, bottom: -1);
319}
320
321/*!
322 \since 4.3
323
324 For each of \a left, \a top, \a right and \a bottom that is not
325 \nullptr, stores the size of the margin named in the location the
326 pointer refers to.
327
328 By default, QLayout uses the values provided by the style. On
329 most platforms, the margin is 11 pixels in all directions.
330
331 \sa setContentsMargins(), QStyle::pixelMetric(),
332 {QStyle::}{PM_LayoutLeftMargin},
333 {QStyle::}{PM_LayoutTopMargin},
334 {QStyle::}{PM_LayoutRightMargin},
335 {QStyle::}{PM_LayoutBottomMargin}
336*/
337void QLayout::getContentsMargins(int *left, int *top, int *right, int *bottom) const
338{
339 Q_D(const QLayout);
340 d->getMargin(result: left, userMargin: d->userLeftMargin, pm: QStyle::PM_LayoutLeftMargin);
341 d->getMargin(result: top, userMargin: d->userTopMargin, pm: QStyle::PM_LayoutTopMargin);
342 d->getMargin(result: right, userMargin: d->userRightMargin, pm: QStyle::PM_LayoutRightMargin);
343 d->getMargin(result: bottom, userMargin: d->userBottomMargin, pm: QStyle::PM_LayoutBottomMargin);
344}
345
346/*!
347 \since 4.6
348
349 Returns the margins used around the layout.
350
351 By default, QLayout uses the values provided by the style. On
352 most platforms, the margin is 11 pixels in all directions.
353
354 \sa setContentsMargins()
355*/
356QMargins QLayout::contentsMargins() const
357{
358 int left, top, right, bottom;
359 getContentsMargins(left: &left, top: &top, right: &right, bottom: &bottom);
360 return QMargins(left, top, right, bottom);
361}
362
363/*!
364 \since 4.3
365
366 Returns the layout's geometry() rectangle, but taking into account the
367 contents margins.
368
369 \sa setContentsMargins(), getContentsMargins()
370*/
371QRect QLayout::contentsRect() const
372{
373 Q_D(const QLayout);
374 int left, top, right, bottom;
375 getContentsMargins(left: &left, top: &top, right: &right, bottom: &bottom);
376 return d->rect.adjusted(xp1: +left, yp1: +top, xp2: -right, yp2: -bottom);
377}
378
379
380/*!
381 Returns the parent widget of this layout, or \nullptr if this
382 layout is not installed on any widget.
383
384 If the layout is a sub-layout, this function returns the parent
385 widget of the parent layout.
386
387 \sa parent()
388*/
389QWidget *QLayout::parentWidget() const
390{
391 Q_D(const QLayout);
392 if (!d->topLevel) {
393 if (parent()) {
394 QLayout *parentLayout = qobject_cast<QLayout*>(object: parent());
395 if (Q_UNLIKELY(!parentLayout)) {
396 qWarning(msg: "QLayout::parentWidget: A layout can only have another layout as a parent.");
397 return nullptr;
398 }
399 return parentLayout->parentWidget();
400 } else {
401 return nullptr;
402 }
403 } else {
404 Q_ASSERT(parent() && parent()->isWidgetType());
405 return static_cast<QWidget *>(parent());
406 }
407}
408
409/*!
410 \reimp
411*/
412bool QLayout::isEmpty() const
413{
414 int i = 0;
415 QLayoutItem *item = itemAt(index: i);
416 while (item) {
417 if (!item->isEmpty())
418 return false;
419 ++i;
420 item = itemAt(index: i);
421 }
422 return true;
423}
424
425/*!
426 \reimp
427*/
428QSizePolicy::ControlTypes QLayout::controlTypes() const
429{
430 if (count() == 0)
431 return QSizePolicy::DefaultType;
432 QSizePolicy::ControlTypes types;
433 for (int i = count() - 1; i >= 0; --i)
434 types |= itemAt(index: i)->controlTypes();
435 return types;
436}
437
438/*!
439 \reimp
440*/
441void QLayout::setGeometry(const QRect &r)
442{
443 Q_D(QLayout);
444 d->rect = r;
445}
446
447/*!
448 \reimp
449*/
450QRect QLayout::geometry() const
451{
452 Q_D(const QLayout);
453 return d->rect;
454}
455
456/*!
457 \reimp
458*/
459void QLayout::invalidate()
460{
461 Q_D(QLayout);
462 d->rect = QRect();
463 update();
464}
465
466static bool removeWidgetRecursively(QLayoutItem *li, QObject *w)
467{
468 QLayout *lay = li->layout();
469 if (!lay)
470 return false;
471 int i = 0;
472 QLayoutItem *child;
473 while ((child = lay->itemAt(index: i))) {
474 if (child->widget() == w) {
475 delete lay->takeAt(index: i);
476 lay->invalidate();
477 return true;
478 } else if (removeWidgetRecursively(li: child, w)) {
479 return true;
480 } else {
481 ++i;
482 }
483 }
484 return false;
485}
486
487
488void QLayoutPrivate::doResize()
489{
490 Q_Q(QLayout);
491 QWidget *mw = q->parentWidget();
492 QRect rect = mw->testAttribute(attribute: Qt::WA_LayoutOnEntireRect) ? mw->rect() : mw->contentsRect();
493 const int mbh = menuBarHeightForWidth(menubar, w: rect.width());
494 const int mbTop = rect.top();
495 rect.setTop(mbTop + mbh);
496 q->setGeometry(rect);
497 if (menubar)
498 menubar->setGeometry(ax: rect.left(), ay: mbTop, aw: rect.width(), ah: mbh);
499}
500
501
502/*!
503 \internal
504 Performs child widget layout when the parent widget is
505 resized. Also handles removal of widgets. \a e is the
506 event
507*/
508void QLayout::widgetEvent(QEvent *e)
509{
510 Q_D(QLayout);
511 const QEvent::Type type = e->type();
512 if (!d->enabled && type != QEvent::ChildRemoved)
513 return;
514
515 switch (type) {
516 case QEvent::Resize:
517 if (d->activated)
518 d->doResize();
519 else
520 activate();
521 break;
522 case QEvent::ChildRemoved:
523 {
524 QChildEvent *c = (QChildEvent *)e;
525 QObject *child = c->child();
526 QObjectPrivate *op = QObjectPrivate::get(o: child);
527 if (op->wasWidget) {
528 if (child == d->menubar)
529 d->menubar = nullptr;
530 removeWidgetRecursively(li: this, w: child);
531 }
532 }
533 break;
534 case QEvent::LayoutRequest:
535 if (static_cast<QWidget *>(parent())->isVisible())
536 activate();
537 break;
538 default:
539 break;
540 }
541}
542
543/*!
544 \reimp
545*/
546void QLayout::childEvent(QChildEvent *e)
547{
548 Q_D(QLayout);
549 if (!d->enabled)
550 return;
551
552 if (e->type() != QEvent::ChildRemoved)
553 return;
554
555 if (QLayout *childLayout = qobject_cast<QLayout *>(object: e->child()))
556 removeItem(childLayout);
557}
558
559/*!
560 \internal
561 Also takes contentsMargins and menu bar into account.
562*/
563int QLayout::totalMinimumHeightForWidth(int w) const
564{
565 Q_D(const QLayout);
566 int side=0, top=0;
567 if (d->topLevel) {
568 QWidget *parent = parentWidget();
569 parent->ensurePolished();
570 QWidgetPrivate *wd = parent->d_func();
571 side += wd->leftmargin + wd->rightmargin;
572 top += wd->topmargin + wd->bottommargin;
573 }
574 int h = minimumHeightForWidth(w - side) + top +
575 menuBarHeightForWidth(menubar: d->menubar, w);
576 return h;
577}
578
579/*!
580 \internal
581 Also takes contentsMargins and menu bar into account.
582*/
583int QLayout::totalHeightForWidth(int w) const
584{
585 Q_D(const QLayout);
586 int side=0, top=0;
587 if (d->topLevel) {
588 QWidget *parent = parentWidget();
589 parent->ensurePolished();
590 QWidgetPrivate *wd = parent->d_func();
591 side += wd->leftmargin + wd->rightmargin;
592 top += wd->topmargin + wd->bottommargin;
593 }
594 int h = heightForWidth(w - side) + top +
595 menuBarHeightForWidth(menubar: d->menubar, w);
596 return h;
597}
598
599/*!
600 \internal
601 Also takes contentsMargins and menu bar into account.
602*/
603QSize QLayout::totalMinimumSize() const
604{
605 Q_D(const QLayout);
606 int side=0, top=0;
607 if (d->topLevel) {
608 QWidget *pw = parentWidget();
609 pw->ensurePolished();
610 QWidgetPrivate *wd = pw->d_func();
611 side += wd->leftmargin + wd->rightmargin;
612 top += wd->topmargin + wd->bottommargin;
613 }
614
615 QSize s = minimumSize();
616 top += menuBarHeightForWidth(menubar: d->menubar, w: s.width() + side);
617 return s + QSize(side, top);
618}
619
620/*!
621 \internal
622 Also takes contentsMargins and menu bar into account.
623*/
624QSize QLayout::totalSizeHint() const
625{
626 Q_D(const QLayout);
627 int side=0, top=0;
628 if (d->topLevel) {
629 QWidget *pw = parentWidget();
630 pw->ensurePolished();
631 QWidgetPrivate *wd = pw->d_func();
632 side += wd->leftmargin + wd->rightmargin;
633 top += wd->topmargin + wd->bottommargin;
634 }
635
636 QSize s = sizeHint();
637 if (hasHeightForWidth())
638 s.setHeight(heightForWidth(s.width() + side));
639 top += menuBarHeightForWidth(menubar: d->menubar, w: s.width());
640 return s + QSize(side, top);
641}
642
643/*!
644 \internal
645 Also takes contentsMargins and menu bar into account.
646*/
647QSize QLayout::totalMaximumSize() const
648{
649 Q_D(const QLayout);
650 int side=0, top=0;
651 if (d->topLevel) {
652 QWidget *pw = parentWidget();
653 pw->ensurePolished();
654 QWidgetPrivate *wd = pw->d_func();
655 side += wd->leftmargin + wd->rightmargin;
656 top += wd->topmargin + wd->bottommargin;
657 }
658
659 QSize s = maximumSize();
660 top += menuBarHeightForWidth(menubar: d->menubar, w: s.width());
661
662 if (d->topLevel)
663 s = QSize(qMin(a: s.width() + side, b: QLAYOUTSIZE_MAX),
664 qMin(a: s.height() + top, b: QLAYOUTSIZE_MAX));
665 return s;
666}
667
668/*!
669 \internal
670 Destroys the layout, deleting all child layouts.
671 Geometry management stops when a top-level layout is deleted.
672
673 The layout classes will probably be fatally confused if you delete
674 a sublayout.
675*/
676QLayout::~QLayout()
677{
678 Q_D(QLayout);
679 if (d->topLevel && parent() && parent()->isWidgetType() && parentWidget()->layout() == this)
680 parentWidget()->d_func()->layout = nullptr;
681 else if (QLayout *parentLayout = qobject_cast<QLayout *>(object: parent()))
682 parentLayout->removeItem(this);
683}
684
685
686/*!
687 This function is called from \c addLayout() or \c insertLayout() functions in
688 subclasses to add layout \a childLayout as a sub-layout.
689
690 The only scenario in which you need to call it directly is if you
691 implement a custom layout that supports nested layouts.
692
693 \sa QBoxLayout::addLayout(), QBoxLayout::insertLayout(), QGridLayout::addLayout()
694*/
695void QLayout::addChildLayout(QLayout *childLayout)
696{
697 if (Q_UNLIKELY(childLayout->parent())) {
698 qWarning(msg: "QLayout::addChildLayout: layout %s \"%ls\" already has a parent",
699 childLayout->metaObject()->className(), qUtf16Printable(childLayout->objectName()));
700 return;
701 }
702 childLayout->setParent(this);
703
704 if (QWidget *mw = parentWidget()) {
705 childLayout->d_func()->reparentChildWidgets(mw);
706 }
707
708}
709
710/*!
711 \internal
712 */
713bool QLayout::adoptLayout(QLayout *layout)
714{
715 const bool ok = !layout->parent();
716 addChildLayout(childLayout: layout);
717 return ok;
718}
719
720#ifdef QT_DEBUG
721static bool layoutDebug()
722{
723 static int checked_env = -1;
724 if (checked_env == -1)
725 checked_env = !!qEnvironmentVariableIntValue(varName: "QT_LAYOUT_DEBUG");
726
727 return checked_env;
728}
729#endif
730
731void QLayoutPrivate::reparentChildWidgets(QWidget *mw)
732{
733 Q_Q(QLayout);
734 int n = q->count();
735
736 if (menubar && menubar->parentWidget() != mw)
737 menubar->setParent(mw);
738
739 bool mwVisible = mw && mw->isVisible();
740 for (int i = 0; i < n; ++i) {
741 QLayoutItem *item = q->itemAt(index: i);
742 if (QWidget *w = item->widget()) {
743 QWidget *pw = w->parentWidget();
744#ifdef QT_DEBUG
745 if (Q_UNLIKELY(pw && pw != mw && layoutDebug())) {
746 qWarning(msg: "QLayout::addChildLayout: widget %s \"%ls\" in wrong parent; moved to correct parent",
747 w->metaObject()->className(), qUtf16Printable(w->objectName()));
748 }
749#endif
750 bool needShow = mwVisible && !QWidgetPrivate::get(w)->isExplicitlyHidden();
751 if (pw != mw)
752 w->setParent(mw);
753 if (needShow)
754 QMetaObject::invokeMethod(obj: w, member: "_q_showIfNotHidden", c: Qt::QueuedConnection); //show later
755 } else if (QLayout *l = item->layout()) {
756 l->d_func()->reparentChildWidgets(mw);
757 }
758 }
759}
760
761/*!
762 Returns \c true if the \a widget can be added to the \a layout;
763 otherwise returns \c false.
764*/
765bool QLayoutPrivate::checkWidget(QWidget *widget) const
766{
767 Q_Q(const QLayout);
768 if (Q_UNLIKELY(!widget)) {
769 qWarning(msg: "QLayout: Cannot add a null widget to %s/%ls", q->metaObject()->className(),
770 qUtf16Printable(q->objectName()));
771 return false;
772 }
773 if (Q_UNLIKELY(widget == q->parentWidget())) {
774 qWarning(msg: "QLayout: Cannot add parent widget %s/%ls to its child layout %s/%ls",
775 widget->metaObject()->className(), qUtf16Printable(widget->objectName()),
776 q->metaObject()->className(), qUtf16Printable(q->objectName()));
777 return false;
778 }
779 return true;
780}
781
782/*!
783 Returns \c true if the \a otherLayout can be added to the \a layout;
784 otherwise returns \c false.
785*/
786bool QLayoutPrivate::checkLayout(QLayout *otherLayout) const
787{
788 Q_Q(const QLayout);
789 if (Q_UNLIKELY(!otherLayout)) {
790 qWarning(msg: "QLayout: Cannot add a null layout to %s/%ls",
791 q->metaObject()->className(), qUtf16Printable(q->objectName()));
792 return false;
793 }
794 if (Q_UNLIKELY(otherLayout == q)) {
795 qWarning(msg: "QLayout: Cannot add layout %s/%ls to itself",
796 q->metaObject()->className(), qUtf16Printable(q->objectName()));
797 return false;
798 }
799 return true;
800}
801
802/*!
803 This function is called from \c addWidget() functions in
804 subclasses to add \a w as a managed widget of a layout.
805
806 If \a w is already managed by a layout, this function will produce
807 a warning, and remove \a w from that layout. This function must
808 therefore be called before adding \a w to the layout's data
809 structure.
810*/
811void QLayout::addChildWidget(QWidget *w)
812{
813 QWidget *mw = parentWidget();
814 QWidget *pw = w->parentWidget();
815
816 //Qt::WA_LaidOut is never reset. It only means that the widget at some point has
817 //been in a layout.
818 if (pw && w->testAttribute(attribute: Qt::WA_LaidOut)) {
819 QLayout *l = pw->layout();
820 if (l && removeWidgetRecursively(li: l, w)) {
821#ifdef QT_DEBUG
822 if (Q_UNLIKELY(layoutDebug()))
823 qWarning(msg: "QLayout::addChildWidget: %s \"%ls\" is already in a layout; moved to new layout",
824 w->metaObject()->className(), qUtf16Printable(w->objectName()));
825#endif
826 }
827 }
828 if (pw && mw && pw != mw) {
829#ifdef QT_DEBUG
830 if (Q_UNLIKELY(layoutDebug()))
831 qWarning(msg: "QLayout::addChildWidget: %s \"%ls\" in wrong parent; moved to correct parent",
832 w->metaObject()->className(), qUtf16Printable(w->objectName()));
833#endif
834 pw = nullptr;
835 }
836 bool needShow = mw && mw->isVisible() && !QWidgetPrivate::get(w)->isExplicitlyHidden();
837 if (!pw && mw)
838 w->setParent(mw);
839 w->setAttribute(Qt::WA_LaidOut);
840 if (needShow)
841 QMetaObject::invokeMethod(obj: w, member: "_q_showIfNotHidden", c: Qt::QueuedConnection); //show later
842}
843
844/*!
845 Tells the geometry manager to place the menu bar \a widget at the
846 top of parentWidget(), outside QWidget::contentsMargins(). All
847 child widgets are placed below the bottom edge of the menu bar.
848*/
849void QLayout::setMenuBar(QWidget *widget)
850{
851 Q_D(QLayout);
852 if (widget)
853 addChildWidget(w: widget);
854 d->menubar = widget;
855}
856
857/*!
858 Returns the menu bar set for this layout, or \nullptr if no
859 menu bar is set.
860*/
861
862QWidget *QLayout::menuBar() const
863{
864 Q_D(const QLayout);
865 return d->menubar;
866}
867
868
869/*!
870 Returns the minimum size of this layout. This is the smallest
871 size that the layout can have while still respecting the
872 specifications.
873
874 The returned value doesn't include the space required by
875 QWidget::setContentsMargins() or menuBar().
876
877 The default implementation allows unlimited resizing.
878*/
879QSize QLayout::minimumSize() const
880{
881 return QSize(0, 0);
882}
883
884/*!
885 Returns the maximum size of this layout. This is the largest size
886 that the layout can have while still respecting the
887 specifications.
888
889 The returned value doesn't include the space required by
890 QWidget::setContentsMargins() or menuBar().
891
892 The default implementation allows unlimited resizing.
893*/
894QSize QLayout::maximumSize() const
895{
896 return QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX);
897}
898
899/*!
900 Returns whether this layout can make use of more space than
901 sizeHint(). A value of Qt::Vertical or Qt::Horizontal means that
902 it wants to grow in only one dimension, whereas Qt::Vertical |
903 Qt::Horizontal means that it wants to grow in both dimensions.
904
905 The default implementation returns Qt::Horizontal | Qt::Vertical.
906 Subclasses reimplement it to return a meaningful value based on
907 their child widgets's \l{QSizePolicy}{size policies}.
908
909 \sa sizeHint()
910*/
911Qt::Orientations QLayout::expandingDirections() const
912{
913 return Qt::Horizontal | Qt::Vertical;
914}
915
916void QLayout::activateRecursiveHelper(QLayoutItem *item)
917{
918 item->invalidate();
919 QLayout *layout = item->layout();
920 if (layout) {
921 QLayoutItem *child;
922 int i=0;
923 while ((child = layout->itemAt(index: i++)))
924 activateRecursiveHelper(item: child);
925 layout->d_func()->activated = true;
926 }
927}
928
929/*!
930 Updates the layout for parentWidget().
931
932 You should generally not need to call this because it is
933 automatically called at the most appropriate times.
934
935 \sa activate(), invalidate()
936*/
937
938void QLayout::update()
939{
940 QLayout *layout = this;
941 while (layout && layout->d_func()->activated) {
942 layout->d_func()->activated = false;
943 if (layout->d_func()->topLevel) {
944 Q_ASSERT(layout->parent()->isWidgetType());
945 QWidget *mw = static_cast<QWidget*>(layout->parent());
946 QCoreApplication::postEvent(receiver: mw, event: new QEvent(QEvent::LayoutRequest));
947 break;
948 }
949 layout = static_cast<QLayout*>(layout->parent());
950 }
951}
952
953/*!
954 Redoes the layout for parentWidget() if necessary.
955
956 You should generally not need to call this because it is
957 automatically called at the most appropriate times. It returns
958 true if the layout was redone.
959
960 \sa update(), QWidget::updateGeometry()
961*/
962bool QLayout::activate()
963{
964 Q_D(QLayout);
965 if (!d->enabled || !parent())
966 return false;
967 if (!d->topLevel)
968 return static_cast<QLayout*>(parent())->activate();
969 if (d->activated)
970 return false;
971 QWidget *mw = static_cast<QWidget*>(parent());
972 if (Q_UNLIKELY(!mw)) {
973 qWarning(msg: "QLayout::activate: %s \"%ls\" does not have a main widget",
974 metaObject()->className(), qUtf16Printable(objectName()));
975 return false;
976 }
977 activateRecursiveHelper(item: this);
978
979 QWidgetPrivate *md = mw->d_func();
980 uint explMin = md->extra ? md->extra->explicitMinSize : 0;
981 uint explMax = md->extra ? md->extra->explicitMaxSize : 0;
982
983 // Do actual calculation
984 // Result values (needs to be zero or greater to be considered valid/set)
985 // We make some illegal values different from each other due a later compare.
986 // ### In the future we may want minSize(0, 0) and maxSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)
987 // ### Also see comment below.
988 QSize minSize(-1, -1);
989 QSize maxSize(-2, -2);
990
991 // Potentially cached values to avoid calling the same function more times.
992 constexpr QSize empty(0, 0);
993 QSize totalSzH = empty;
994 QSize totalMinSz = empty;
995 QSize totalMaxSz = empty;
996
997 switch (d->verticalConstraint) {
998 case SetFixedSize:
999 totalSzH = totalSizeHint();
1000 minSize.setHeight(totalSzH.height());
1001 maxSize.setHeight(totalSzH.height());
1002 break;
1003 case SetMinimumSize:
1004 totalMinSz = totalMinimumSize();
1005 minSize.setHeight(totalMinSz.height());
1006 break;
1007 case SetMaximumSize:
1008 totalMaxSz = totalMaximumSize();
1009 maxSize.setHeight(totalMaxSz.height());
1010 break;
1011 case SetMinAndMaxSize:
1012 totalMinSz = totalMinimumSize();
1013 totalMaxSz = totalMaximumSize();
1014 minSize.setHeight(totalMinSz.height());
1015 maxSize.setHeight(totalMaxSz.height());
1016 break;
1017 case SetDefaultConstraint: {
1018 bool heightSet = explMin & Qt::Vertical;
1019 if (mw->isWindow()) {
1020 if (!heightSet) {
1021 totalMinSz = totalMinimumSize();
1022 minSize.setHeight(totalMinSz.height());
1023 } else {
1024 minSize.setHeight(mw->minimumHeight());
1025 }
1026 } else {
1027 minSize.setHeight(heightSet ? mw->minimumHeight() : 0);
1028 }
1029 break;
1030 }
1031 case SetNoConstraint:
1032 break;
1033 }
1034 switch (d->horizontalConstraint) {
1035 case SetFixedSize:
1036 if (totalSzH == empty)
1037 totalSzH = totalSizeHint();
1038 minSize.setWidth(totalSzH.width());
1039 maxSize.setWidth(totalSzH.width());
1040 break;
1041 case SetMinimumSize:
1042 if (totalMinSz == empty)
1043 totalMinSz = totalMinimumSize();
1044 minSize.setWidth(totalMinSz.width());
1045 break;
1046 case SetMaximumSize:
1047 if (totalMaxSz == empty)
1048 totalMaxSz = totalMaximumSize();
1049 maxSize.setWidth(totalMaxSz.width());
1050 break;
1051 case SetMinAndMaxSize:
1052 if (totalMinSz == empty)
1053 totalMinSz = totalMinimumSize();
1054 if (totalMaxSz == empty)
1055 totalMaxSz = totalMaximumSize();
1056
1057 minSize.setWidth(totalMinSz.width());
1058 maxSize.setWidth(totalMaxSz.width());
1059 break;
1060 case SetDefaultConstraint: {
1061 const bool widthSet = explMin & Qt::Horizontal;
1062 if (mw->isWindow()) {
1063 if (!widthSet) {
1064 if (totalMinSz == empty)
1065 totalMinSz = totalMinimumSize();
1066 minSize.setWidth(totalMinSz.width());
1067 } else {
1068 minSize.setWidth(mw->minimumWidth());
1069 }
1070 } else {
1071 minSize.setWidth(widthSet ? mw->minimumWidth() : 0);
1072 }
1073 break;
1074 }
1075 case SetNoConstraint:
1076 break;
1077 }
1078 if (minSize == maxSize) {
1079 mw->setFixedSize(minSize);
1080 }
1081 else {
1082 // ### To preserve backward compatibility with behavior prior to introducing separate
1083 // ### horizontal and vertical constraints, we only update the specific size properties
1084 // ### dictated by the constraints. For example, if only minimum width is specified
1085 // ### by the constraint, we leave the minimum height untouched.
1086 // ### Like before we leave unconstrained values unchanged though it can
1087 // ### (unintentionally?) retain stale values.
1088
1089 // handle min-size
1090 if (minSize.isValid())
1091 mw->setMinimumSize(minSize);
1092 else if (minSize.width() >= 0)
1093 mw->setMinimumWidth(minSize.width());
1094 else if (minSize.height() >= 0)
1095 mw->setMinimumHeight(minSize.height());
1096
1097 // handle max-size
1098 if (maxSize.isValid())
1099 mw->setMaximumSize(maxSize);
1100 else if (maxSize.width() >= 0)
1101 mw->setMaximumWidth(maxSize.width());
1102 else if (maxSize.height() >= 0)
1103 mw->setMaximumHeight(maxSize.height());
1104 }
1105
1106 d->doResize();
1107
1108 if (md->extra) {
1109 md->extra->explicitMinSize = explMin;
1110 md->extra->explicitMaxSize = explMax;
1111 }
1112 // ideally only if sizeHint() or sizePolicy() has changed
1113 mw->updateGeometry();
1114 return true;
1115}
1116
1117/*!
1118 \since 5.2
1119
1120 Searches for widget \a from and replaces it with widget \a to if found.
1121 Returns the layout item that contains the widget \a from on success.
1122 Otherwise \nullptr is returned.
1123 If \a options contains \c Qt::FindChildrenRecursively (the default),
1124 sub-layouts are searched for doing the replacement.
1125 Any other flag in \a options is ignored.
1126
1127 Notice that the returned item therefore might not belong to this layout,
1128 but to a sub-layout.
1129
1130 The returned layout item is no longer owned by the layout and should be
1131 either deleted or inserted to another layout. The widget \a from is no
1132 longer managed by the layout and may need to be deleted or hidden. The
1133 parent of widget \a from is left unchanged.
1134
1135 This function works for the built-in Qt layouts, but might not work for
1136 custom layouts.
1137
1138 \sa indexOf()
1139*/
1140
1141QLayoutItem *QLayout::replaceWidget(QWidget *from, QWidget *to, Qt::FindChildOptions options)
1142{
1143 Q_D(QLayout);
1144 if (!from || !to)
1145 return nullptr;
1146 if (from == to) // Do not return a QLayoutItem for \a from, since ownership still
1147 return nullptr; // belongs to the layout (since nothing was changed)
1148
1149 int index = -1;
1150 QLayoutItem *item = nullptr;
1151 for (int u = 0; u < count(); ++u) {
1152 item = itemAt(index: u);
1153 if (!item)
1154 continue;
1155
1156 if (item->widget() == from) {
1157 index = u;
1158 break;
1159 }
1160
1161 if (item->layout() && (options & Qt::FindChildrenRecursively)) {
1162 QLayoutItem *r = item->layout()->replaceWidget(from, to, options);
1163 if (r)
1164 return r;
1165 }
1166 }
1167 if (index == -1)
1168 return nullptr;
1169
1170 addChildWidget(w: to);
1171 QLayoutItem *newitem = new QWidgetItem(to);
1172 newitem->setAlignment(item->alignment());
1173 QLayoutItem *r = d->replaceAt(index, newitem);
1174 if (!r)
1175 delete newitem;
1176 return r;
1177}
1178
1179/*!
1180 \fn QLayoutItem *QLayout::itemAt(int index) const
1181
1182 Must be implemented in subclasses to return the layout item at \a
1183 index. If there is no such item, the function must return \nullptr.
1184 Items are numbered consecutively from 0. If an item is deleted, other items will be renumbered.
1185
1186 This function can be used to iterate over a layout. The following
1187 code will draw a rectangle for each layout item in the layout structure of the widget.
1188
1189 \snippet code/src_gui_kernel_qlayout.cpp 0
1190
1191 \sa count(), takeAt()
1192*/
1193
1194/*!
1195 \fn QLayoutItem *QLayout::takeAt(int index)
1196
1197 Must be implemented in subclasses to remove the layout item at \a
1198 index from the layout, and return the item. If there is no such
1199 item, the function must do nothing and return 0. Items are numbered
1200 consecutively from 0. If an item is removed, other items will be
1201 renumbered.
1202
1203 The following code fragment shows a safe way to remove all items
1204 from a layout:
1205
1206 \snippet code/src_gui_kernel_qlayout.cpp 1
1207
1208 \sa itemAt(), count()
1209*/
1210
1211/*!
1212 \fn int *QLayout::count() const
1213
1214 Must be implemented in subclasses to return the number of items
1215 in the layout.
1216
1217 \sa itemAt()
1218*/
1219
1220/*!
1221 Searches for widget \a widget in this layout (not including child
1222 layouts).
1223
1224 Returns the index of \a widget, or -1 if \a widget is not found.
1225
1226 The default implementation iterates over all items using itemAt().
1227*/
1228int QLayout::indexOf(const QWidget *widget) const
1229{
1230 const int c = count();
1231
1232 for (int i = 0; i < c; ++i) {
1233 if (itemAt(index: i)->widget() == widget)
1234 return i;
1235 }
1236
1237 return -1;
1238}
1239
1240/*!
1241 \since 5.12
1242 Searches for layout item \a layoutItem in this layout (not including child
1243 layouts).
1244
1245 Returns the index of \a layoutItem, or -1 if \a layoutItem is not found.
1246*/
1247int QLayout::indexOf(const QLayoutItem *layoutItem) const
1248{
1249 const int c = count();
1250
1251 for (int i = 0; i < c; ++i) {
1252 if (itemAt(index: i) == layoutItem)
1253 return i;
1254 }
1255
1256 return -1;
1257}
1258
1259/*!
1260 \enum QLayout::SizeConstraint
1261 Describes how the layout constrains the size of the widget.
1262
1263 A vertical constraint affects the widget's height, while a horizontal constraint affects its width.
1264
1265 The possible values are:
1266
1267 \value SetDefaultConstraint
1268 In the constrained orientation(s), the widget’s minimum extent
1269 is set to \l minimumSize(), unless a minimum size has already been set.
1270
1271 \value SetFixedSize
1272 In the constrained orientation(s), the widget’s extent is set to
1273 \l sizeHint(), and it cannot be resized in that direction.
1274
1275 \value SetMinimumSize
1276 In the constrained orientation(s), the widget’s minimum extent
1277 is set to \l minimumSize().
1278
1279 \value SetMaximumSize
1280 In the constrained orientation(s), the widget’s maximum extent
1281 is set to \l maximumSize().
1282
1283 \value SetMinAndMaxSize
1284 In the constrained orientation(s), the widget’s minimum extent
1285 is set to \l minimumSize(), and the maximum extent is set to \l maximumSize().
1286
1287 \value SetNoConstraint
1288 No size constraints are applied to the widget.
1289
1290 \sa setSizeConstraint(), setSizeConstraints(), horizontalSizeConstraint(), setHorizontalSizeConstraint(), setVerticalSizeConstraint()
1291*/
1292
1293/*!
1294 \property QLayout::sizeConstraint
1295 \brief the resize mode of the layout.
1296 Setting the size constraint for the dialog.
1297 Setting a vertical or horizontal size constraint will override this.
1298
1299 The default mode is \l {QLayout::SetDefaultConstraint}
1300 {SetDefaultConstraint}.
1301
1302 \sa horizontalSizeConstraint(), verticalSizeConstraint()
1303*/
1304
1305void QLayout::setSizeConstraint(SizeConstraint constraint)
1306{
1307 setSizeConstraints(horizontal: constraint, vertical: constraint);
1308}
1309
1310/*!
1311 \since 6.10
1312
1313 Sets both the \a horizontal and \a vertical size constraints.
1314
1315 \sa sizeConstraint(), horizontalSizeConstraint(), verticalSizeConstraint()
1316 */
1317void QLayout::setSizeConstraints(SizeConstraint horizontal, SizeConstraint vertical)
1318{
1319 Q_D(QLayout);
1320 if (horizontal == d->horizontalConstraint && vertical == d->verticalConstraint)
1321 return;
1322 d->horizontalConstraint = horizontal;
1323 d->verticalConstraint = vertical;
1324 invalidate();
1325}
1326
1327QLayout::SizeConstraint QLayout::sizeConstraint() const
1328{
1329 Q_D(const QLayout);
1330 return d->horizontalConstraint;
1331}
1332
1333/*!
1334 \property QLayout::horizontalSizeConstraint
1335 \since 6.10
1336 \brief The horizontal size constraint.
1337
1338 The default mode is \l {QLayout::SetDefaultConstraint}
1339
1340 \sa verticalSizeConstraint(), sizeConstraint()
1341*/
1342
1343void QLayout::setHorizontalSizeConstraint(SizeConstraint constraint)
1344{
1345 Q_D(QLayout);
1346 if (constraint == d->horizontalConstraint)
1347 return;
1348 d->horizontalConstraint = constraint;
1349 invalidate();
1350}
1351
1352
1353QLayout::SizeConstraint QLayout::horizontalSizeConstraint() const
1354{
1355 Q_D(const QLayout);
1356 return d->horizontalConstraint;
1357}
1358
1359/*!
1360 \property QLayout::verticalSizeConstraint
1361 \since 6.10
1362 \brief The vertical size constraint.
1363
1364 The default mode is \l {QLayout::SetDefaultConstraint}
1365
1366 \sa horizontalSizeConstraint(), sizeConstraint()
1367*/
1368
1369void QLayout::setVerticalSizeConstraint(SizeConstraint constraint)
1370{
1371 Q_D(QLayout);
1372 if (constraint == d->verticalConstraint)
1373 return;
1374 d->verticalConstraint = constraint;
1375 invalidate();
1376}
1377
1378QLayout::SizeConstraint QLayout::verticalSizeConstraint() const
1379{
1380 Q_D(const QLayout);
1381 return d->verticalConstraint;
1382}
1383
1384/*!
1385 Returns the rectangle that should be covered when the geometry of
1386 this layout is set to \a r, provided that this layout supports
1387 setAlignment().
1388
1389 The result is derived from sizeHint() and expandingDirections(). It is never
1390 larger than \a r.
1391*/
1392QRect QLayout::alignmentRect(const QRect &r) const
1393{
1394 QSize s = sizeHint();
1395 Qt::Alignment a = alignment();
1396
1397 /*
1398 This is a hack to obtain the real maximum size, not
1399 QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX), the value consistently
1400 returned by QLayoutItems that have an alignment.
1401 */
1402 QLayout *that = const_cast<QLayout *>(this);
1403 that->setAlignment({ });
1404 QSize ms = that->maximumSize();
1405 that->setAlignment(a);
1406
1407 if ((expandingDirections() & Qt::Horizontal) ||
1408 !(a & Qt::AlignHorizontal_Mask)) {
1409 s.setWidth(qMin(a: r.width(), b: ms.width()));
1410 }
1411 if ((expandingDirections() & Qt::Vertical) ||
1412 !(a & Qt::AlignVertical_Mask)) {
1413 s.setHeight(qMin(a: r.height(), b: ms.height()));
1414 } else if (hasHeightForWidth()) {
1415 int hfw = heightForWidth(s.width());
1416 if (hfw < s.height())
1417 s.setHeight(qMin(a: hfw, b: ms.height()));
1418 }
1419
1420 s = s.boundedTo(otherSize: r.size());
1421 int x = r.x();
1422 int y = r.y();
1423
1424 if (a & Qt::AlignBottom)
1425 y += (r.height() - s.height());
1426 else if (!(a & Qt::AlignTop))
1427 y += (r.height() - s.height()) / 2;
1428
1429 QWidget *parent = parentWidget();
1430 a = QStyle::visualAlignment(direction: parent ? parent->layoutDirection() : QGuiApplication::layoutDirection(), alignment: a);
1431 if (a & Qt::AlignRight)
1432 x += (r.width() - s.width());
1433 else if (!(a & Qt::AlignLeft))
1434 x += (r.width() - s.width()) / 2;
1435
1436 return QRect(x, y, s.width(), s.height());
1437}
1438
1439/*!
1440 Removes the widget \a widget from the layout. After this call, it
1441 is the caller's responsibility to give the widget a reasonable
1442 geometry or to put the widget back into a layout or to explicitly
1443 hide it if necessary.
1444
1445 \b{Note:} The ownership of \a widget remains the same as
1446 when it was added.
1447
1448 \sa removeItem(), QWidget::setGeometry(), addWidget()
1449*/
1450void QLayout::removeWidget(QWidget *widget)
1451{
1452 if (Q_UNLIKELY(!widget)) {
1453 qWarning(msg: "QLayout::removeWidget: Cannot remove a null widget.");
1454 return;
1455 }
1456
1457 int i = 0;
1458 QLayoutItem *child;
1459 while ((child = itemAt(index: i))) {
1460 if (child->widget() == widget) {
1461 delete takeAt(index: i);
1462 invalidate();
1463 } else {
1464 ++i;
1465 }
1466 }
1467}
1468
1469/*!
1470 Removes the layout item \a item from the layout. It is the
1471 caller's responsibility to delete the item.
1472
1473 Notice that \a item can be a layout (since QLayout inherits
1474 QLayoutItem).
1475
1476 \sa removeWidget(), addItem()
1477*/
1478void QLayout::removeItem(QLayoutItem *item)
1479{
1480 int i = 0;
1481 QLayoutItem *child;
1482 while ((child = itemAt(index: i))) {
1483 if (child == item) {
1484 takeAt(index: i);
1485 invalidate();
1486 } else {
1487 ++i;
1488 }
1489 }
1490}
1491
1492/*!
1493 Enables this layout if \a enable is true, otherwise disables it.
1494
1495 An enabled layout adjusts dynamically to changes; a disabled
1496 layout acts as if it did not exist.
1497
1498 By default all layouts are enabled.
1499
1500 \sa isEnabled()
1501*/
1502void QLayout::setEnabled(bool enable)
1503{
1504 Q_D(QLayout);
1505 d->enabled = enable;
1506}
1507
1508/*!
1509 Returns \c true if the layout is enabled; otherwise returns \c false.
1510
1511 \sa setEnabled()
1512*/
1513bool QLayout::isEnabled() const
1514{
1515 Q_D(const QLayout);
1516 return d->enabled;
1517}
1518
1519/*!
1520 Returns a size that satisfies all size constraints on \a widget,
1521 including heightForWidth() and that is as close as possible to \a
1522 size.
1523*/
1524
1525QSize QLayout::closestAcceptableSize(const QWidget *widget, const QSize &size)
1526{
1527 QSize result = size.boundedTo(otherSize: qSmartMaxSize(w: widget));
1528 result = result.expandedTo(otherSize: qSmartMinSize(w: widget));
1529 QLayout *l = widget->layout();
1530 if (l && l->hasHeightForWidth() && result.height() < l->minimumHeightForWidth(result.width()) ) {
1531 QSize current = widget->size();
1532 int currentHfw = l->minimumHeightForWidth(current.width());
1533 int newHfw = l->minimumHeightForWidth(result.width());
1534 if (current.height() < currentHfw || currentHfw == newHfw) {
1535 //handle the constant hfw case and the vertical-only case, as well as the
1536 // current-size-is-not-correct case
1537 result.setHeight(newHfw);
1538 } else {
1539 // binary search; assume hfw is decreasing ###
1540
1541 int maxw = qMax(a: widget->width(),b: result.width());
1542 int maxh = qMax(a: widget->height(), b: result.height());
1543 int minw = qMin(a: widget->width(),b: result.width());
1544 int minh = qMin(a: widget->height(), b: result.height());
1545
1546 int minhfw = l->minimumHeightForWidth(minw);
1547 int maxhfw = l->minimumHeightForWidth(maxw);
1548 while (minw < maxw) {
1549 if (minhfw > maxh) { //assume decreasing
1550 minw = maxw - (maxw-minw)/2;
1551 minhfw = l->minimumHeightForWidth(minw);
1552 } else if (maxhfw < minh ) { //assume decreasing
1553 maxw = minw + (maxw-minw)/2;
1554 maxhfw = l->minimumHeightForWidth(maxw);
1555 } else {
1556 break;
1557 }
1558 }
1559 result = result.expandedTo(otherSize: QSize(minw, minhfw));
1560 }
1561 }
1562 return result;
1563}
1564
1565QT_END_NAMESPACE
1566
1567#include "moc_qlayout.cpp"
1568

source code of qtbase/src/widgets/kernel/qlayout.cpp