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