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 \since 4.6
349
350 Returns 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()
356*/
357QMargins QLayout::contentsMargins() const
358{
359 int left, top, right, bottom;
360 getContentsMargins(&left, &top, &right, &bottom);
361 return QMargins(left, top, right, bottom);
362}
363
364/*!
365 \since 4.3
366
367 Returns the layout's geometry() rectangle, but taking into account the
368 contents margins.
369
370 \sa setContentsMargins(), getContentsMargins()
371*/
372QRect QLayout::contentsRect() const
373{
374 Q_D(const QLayout);
375 int left, top, right, bottom;
376 getContentsMargins(&left, &top, &right, &bottom);
377 return d->rect.adjusted(+left, +top, -right, -bottom);
378}
379
380
381/*!
382 Returns the parent widget of this layout, or \nullptr if this
383 layout is not installed on any widget.
384
385 If the layout is a sub-layout, this function returns the parent
386 widget of the parent layout.
387
388 \sa parent()
389*/
390QWidget *QLayout::parentWidget() const
391{
392 Q_D(const QLayout);
393 if (!d->topLevel) {
394 if (parent()) {
395 QLayout *parentLayout = qobject_cast<QLayout*>(parent());
396 if (Q_UNLIKELY(!parentLayout)) {
397 qWarning("QLayout::parentWidget: A layout can only have another layout as a parent.");
398 return nullptr;
399 }
400 return parentLayout->parentWidget();
401 } else {
402 return nullptr;
403 }
404 } else {
405 Q_ASSERT(parent() && parent()->isWidgetType());
406 return static_cast<QWidget *>(parent());
407 }
408}
409
410/*!
411 \reimp
412*/
413bool QLayout::isEmpty() const
414{
415 int i = 0;
416 QLayoutItem *item = itemAt(i);
417 while (item) {
418 if (!item->isEmpty())
419 return false;
420 ++i;
421 item = itemAt(i);
422 }
423 return true;
424}
425
426/*!
427 \reimp
428*/
429QSizePolicy::ControlTypes QLayout::controlTypes() const
430{
431 if (count() == 0)
432 return QSizePolicy::DefaultType;
433 QSizePolicy::ControlTypes types;
434 for (int i = count() - 1; i >= 0; --i)
435 types |= itemAt(i)->controlTypes();
436 return types;
437}
438
439/*!
440 \reimp
441*/
442void QLayout::setGeometry(const QRect &r)
443{
444 Q_D(QLayout);
445 d->rect = r;
446}
447
448/*!
449 \reimp
450*/
451QRect QLayout::geometry() const
452{
453 Q_D(const QLayout);
454 return d->rect;
455}
456
457/*!
458 \reimp
459*/
460void QLayout::invalidate()
461{
462 Q_D(QLayout);
463 d->rect = QRect();
464 update();
465}
466
467static bool removeWidgetRecursively(QLayoutItem *li, QObject *w)
468{
469 QLayout *lay = li->layout();
470 if (!lay)
471 return false;
472 int i = 0;
473 QLayoutItem *child;
474 while ((child = lay->itemAt(i))) {
475 if (child->widget() == w) {
476 delete lay->takeAt(i);
477 lay->invalidate();
478 return true;
479 } else if (removeWidgetRecursively(child, w)) {
480 return true;
481 } else {
482 ++i;
483 }
484 }
485 return false;
486}
487
488
489void QLayoutPrivate::doResize()
490{
491 Q_Q(QLayout);
492 QWidget *mw = q->parentWidget();
493 QRect rect = mw->testAttribute(Qt::WA_LayoutOnEntireRect) ? mw->rect() : mw->contentsRect();
494 const int mbh = menuBarHeightForWidth(menubar, rect.width());
495 const int mbTop = rect.top();
496 rect.setTop(mbTop + mbh);
497 q->setGeometry(rect);
498 if (menubar)
499 menubar->setGeometry(rect.left(), mbTop, rect.width(), mbh);
500}
501
502
503/*!
504 \internal
505 Performs child widget layout when the parent widget is
506 resized. Also handles removal of widgets. \a e is the
507 event
508*/
509void QLayout::widgetEvent(QEvent *e)
510{
511 Q_D(QLayout);
512 const QEvent::Type type = e->type();
513 if (!d->enabled && type != QEvent::ChildRemoved)
514 return;
515
516 switch (type) {
517 case QEvent::Resize:
518 if (d->activated)
519 d->doResize();
520 else
521 activate();
522 break;
523 case QEvent::ChildRemoved:
524 {
525 QChildEvent *c = (QChildEvent *)e;
526 QObject *child = c->child();
527 QObjectPrivate *op = QObjectPrivate::get(child);
528 if (op->wasWidget) {
529 if (child == d->menubar)
530 d->menubar = nullptr;
531 removeWidgetRecursively(this, child);
532 }
533 }
534 break;
535 case QEvent::LayoutRequest:
536 if (static_cast<QWidget *>(parent())->isVisible())
537 activate();
538 break;
539 default:
540 break;
541 }
542}
543
544/*!
545 \reimp
546*/
547void QLayout::childEvent(QChildEvent *e)
548{
549 Q_D(QLayout);
550 if (!d->enabled)
551 return;
552
553 if (e->type() != QEvent::ChildRemoved)
554 return;
555
556 if (QLayout *childLayout = qobject_cast<QLayout *>(e->child()))
557 removeItem(childLayout);
558}
559
560/*!
561 \internal
562 Also takes contentsMargins and menu bar into account.
563*/
564int QLayout::totalMinimumHeightForWidth(int w) const
565{
566 Q_D(const QLayout);
567 int side=0, top=0;
568 if (d->topLevel) {
569 QWidget *parent = parentWidget();
570 parent->ensurePolished();
571 QWidgetPrivate *wd = parent->d_func();
572 side += wd->leftmargin + wd->rightmargin;
573 top += wd->topmargin + wd->bottommargin;
574 }
575 int h = minimumHeightForWidth(w - side) + top +
576 menuBarHeightForWidth(d->menubar, w);
577 return h;
578}
579
580/*!
581 \internal
582 Also takes contentsMargins and menu bar into account.
583*/
584int QLayout::totalHeightForWidth(int w) const
585{
586 Q_D(const QLayout);
587 int side=0, top=0;
588 if (d->topLevel) {
589 QWidget *parent = parentWidget();
590 parent->ensurePolished();
591 QWidgetPrivate *wd = parent->d_func();
592 side += wd->leftmargin + wd->rightmargin;
593 top += wd->topmargin + wd->bottommargin;
594 }
595 int h = heightForWidth(w - side) + top +
596 menuBarHeightForWidth(d->menubar, w);
597 return h;
598}
599
600/*!
601 \internal
602 Also takes contentsMargins and menu bar into account.
603*/
604QSize QLayout::totalMinimumSize() const
605{
606 Q_D(const QLayout);
607 int side=0, top=0;
608 if (d->topLevel) {
609 QWidget *pw = parentWidget();
610 pw->ensurePolished();
611 QWidgetPrivate *wd = pw->d_func();
612 side += wd->leftmargin + wd->rightmargin;
613 top += wd->topmargin + wd->bottommargin;
614 }
615
616 QSize s = minimumSize();
617 top += menuBarHeightForWidth(d->menubar, s.width() + side);
618 return s + QSize(side, top);
619}
620
621/*!
622 \internal
623 Also takes contentsMargins and menu bar into account.
624*/
625QSize QLayout::totalSizeHint() const
626{
627 Q_D(const QLayout);
628 int side=0, top=0;
629 if (d->topLevel) {
630 QWidget *pw = parentWidget();
631 pw->ensurePolished();
632 QWidgetPrivate *wd = pw->d_func();
633 side += wd->leftmargin + wd->rightmargin;
634 top += wd->topmargin + wd->bottommargin;
635 }
636
637 QSize s = sizeHint();
638 if (hasHeightForWidth())
639 s.setHeight(heightForWidth(s.width() + side));
640 top += menuBarHeightForWidth(d->menubar, s.width());
641 return s + QSize(side, top);
642}
643
644/*!
645 \internal
646 Also takes contentsMargins and menu bar into account.
647*/
648QSize QLayout::totalMaximumSize() const
649{
650 Q_D(const QLayout);
651 int side=0, top=0;
652 if (d->topLevel) {
653 QWidget *pw = parentWidget();
654 pw->ensurePolished();
655 QWidgetPrivate *wd = pw->d_func();
656 side += wd->leftmargin + wd->rightmargin;
657 top += wd->topmargin + wd->bottommargin;
658 }
659
660 QSize s = maximumSize();
661 top += menuBarHeightForWidth(d->menubar, s.width());
662
663 if (d->topLevel)
664 s = QSize(qMin(s.width() + side, QLAYOUTSIZE_MAX),
665 qMin(s.height() + top, QLAYOUTSIZE_MAX));
666 return s;
667}
668
669/*!
670 \internal
671 Destroys the layout, deleting all child layouts.
672 Geometry management stops when a top-level layout is deleted.
673
674 The layout classes will probably be fatally confused if you delete
675 a sublayout.
676*/
677QLayout::~QLayout()
678{
679 Q_D(QLayout);
680 if (d->topLevel && parent() && parent()->isWidgetType() && parentWidget()->layout() == this)
681 parentWidget()->d_func()->layout = nullptr;
682 else if (QLayout *parentLayout = qobject_cast<QLayout *>(parent()))
683 parentLayout->removeItem(this);
684}
685
686
687/*!
688 This function is called from \c addLayout() or \c insertLayout() functions in
689 subclasses to add layout \a childLayout as a sub-layout.
690
691 The only scenario in which you need to call it directly is if you
692 implement a custom layout that supports nested layouts.
693
694 \sa QBoxLayout::addLayout(), QBoxLayout::insertLayout(), QGridLayout::addLayout()
695*/
696void QLayout::addChildLayout(QLayout *childLayout)
697{
698 if (Q_UNLIKELY(childLayout->parent())) {
699 qWarning("QLayout::addChildLayout: layout %s \"%ls\" already has a parent",
700 childLayout->metaObject()->className(), qUtf16Printable(childLayout->objectName()));
701 return;
702 }
703 childLayout->setParent(this);
704
705 if (QWidget *mw = parentWidget()) {
706 childLayout->d_func()->reparentChildWidgets(mw);
707 }
708
709}
710
711/*!
712 \internal
713 */
714bool QLayout::adoptLayout(QLayout *layout)
715{
716 const bool ok = !layout->parent();
717 addChildLayout(layout);
718 return ok;
719}
720
721#ifdef QT_DEBUG
722static bool layoutDebug()
723{
724 static int checked_env = -1;
725 if (checked_env == -1)
726 checked_env = !!qEnvironmentVariableIntValue("QT_LAYOUT_DEBUG");
727
728 return checked_env;
729}
730#endif
731
732void QLayoutPrivate::reparentChildWidgets(QWidget *mw)
733{
734 Q_Q(QLayout);
735 int n = q->count();
736
737 if (menubar && menubar->parentWidget() != mw)
738 menubar->setParent(mw);
739
740 bool mwVisible = mw && mw->isVisible();
741 for (int i = 0; i < n; ++i) {
742 QLayoutItem *item = q->itemAt(i);
743 if (QWidget *w = item->widget()) {
744 QWidget *pw = w->parentWidget();
745#ifdef QT_DEBUG
746 if (Q_UNLIKELY(pw && pw != mw && layoutDebug())) {
747 qWarning("QLayout::addChildLayout: widget %s \"%ls\" in wrong parent; moved to correct parent",
748 w->metaObject()->className(), qUtf16Printable(w->objectName()));
749 }
750#endif
751 bool needShow = mwVisible && !QWidgetPrivate::get(w)->isExplicitlyHidden();
752 if (pw != mw)
753 w->setParent(mw);
754 if (needShow)
755 QMetaObject::invokeMethod(w, "_q_showIfNotHidden", Qt::QueuedConnection); //show later
756 } else if (QLayout *l = item->layout()) {
757 l->d_func()->reparentChildWidgets(mw);
758 }
759 }
760}
761
762/*!
763 Returns \c true if the \a widget can be added to the \a layout;
764 otherwise returns \c false.
765*/
766bool QLayoutPrivate::checkWidget(QWidget *widget) const
767{
768 Q_Q(const QLayout);
769 if (Q_UNLIKELY(!widget)) {
770 qWarning("QLayout: Cannot add a null widget to %s/%ls", q->metaObject()->className(),
771 qUtf16Printable(q->objectName()));
772 return false;
773 }
774 if (Q_UNLIKELY(widget == q->parentWidget())) {
775 qWarning("QLayout: Cannot add parent widget %s/%ls to its child layout %s/%ls",
776 widget->metaObject()->className(), qUtf16Printable(widget->objectName()),
777 q->metaObject()->className(), qUtf16Printable(q->objectName()));
778 return false;
779 }
780 return true;
781}
782
783/*!
784 Returns \c true if the \a otherLayout can be added to the \a layout;
785 otherwise returns \c false.
786*/
787bool QLayoutPrivate::checkLayout(QLayout *otherLayout) const
788{
789 Q_Q(const QLayout);
790 if (Q_UNLIKELY(!otherLayout)) {
791 qWarning("QLayout: Cannot add a null layout to %s/%ls",
792 q->metaObject()->className(), qUtf16Printable(q->objectName()));
793 return false;
794 }
795 if (Q_UNLIKELY(otherLayout == q)) {
796 qWarning("QLayout: Cannot add layout %s/%ls to itself",
797 q->metaObject()->className(), qUtf16Printable(q->objectName()));
798 return false;
799 }
800 return true;
801}
802
803/*!
804 This function is called from \c addWidget() functions in
805 subclasses to add \a w as a managed widget of a layout.
806
807 If \a w is already managed by a layout, this function will produce
808 a warning, and remove \a w from that layout. This function must
809 therefore be called before adding \a w to the layout's data
810 structure.
811*/
812void QLayout::addChildWidget(QWidget *w)
813{
814 QWidget *mw = parentWidget();
815 QWidget *pw = w->parentWidget();
816
817 //Qt::WA_LaidOut is never reset. It only means that the widget at some point has
818 //been in a layout.
819 if (pw && w->testAttribute(Qt::WA_LaidOut)) {
820 QLayout *l = pw->layout();
821 if (l && removeWidgetRecursively(l, w)) {
822#ifdef QT_DEBUG
823 if (Q_UNLIKELY(layoutDebug()))
824 qWarning("QLayout::addChildWidget: %s \"%ls\" is already in a layout; moved to new layout",
825 w->metaObject()->className(), qUtf16Printable(w->objectName()));
826#endif
827 }
828 }
829 if (pw && mw && pw != mw) {
830#ifdef QT_DEBUG
831 if (Q_UNLIKELY(layoutDebug()))
832 qWarning("QLayout::addChildWidget: %s \"%ls\" in wrong parent; moved to correct parent",
833 w->metaObject()->className(), qUtf16Printable(w->objectName()));
834#endif
835 pw = nullptr;
836 }
837 bool needShow = mw && mw->isVisible() && !QWidgetPrivate::get(w)->isExplicitlyHidden();
838 if (!pw && mw)
839 w->setParent(mw);
840 w->setAttribute(Qt::WA_LaidOut);
841 if (needShow)
842 QMetaObject::invokeMethod(w, "_q_showIfNotHidden", Qt::QueuedConnection); //show later
843}
844
845/*!
846 Tells the geometry manager to place the menu bar \a widget at the
847 top of parentWidget(), outside QWidget::contentsMargins(). All
848 child widgets are placed below the bottom edge of the menu bar.
849*/
850void QLayout::setMenuBar(QWidget *widget)
851{
852 Q_D(QLayout);
853 if (widget)
854 addChildWidget(widget);
855 d->menubar = widget;
856}
857
858/*!
859 Returns the menu bar set for this layout, or \nullptr if no
860 menu bar is set.
861*/
862
863QWidget *QLayout::menuBar() const
864{
865 Q_D(const QLayout);
866 return d->menubar;
867}
868
869
870/*!
871 Returns the minimum size of this layout. This is the smallest
872 size that the layout can have while still respecting the
873 specifications.
874
875 The returned value doesn't include the space required by
876 QWidget::setContentsMargins() or menuBar().
877
878 The default implementation allows unlimited resizing.
879*/
880QSize QLayout::minimumSize() const
881{
882 return QSize(0, 0);
883}
884
885/*!
886 Returns the maximum size of this layout. This is the largest size
887 that the layout can have while still respecting the
888 specifications.
889
890 The returned value doesn't include the space required by
891 QWidget::setContentsMargins() or menuBar().
892
893 The default implementation allows unlimited resizing.
894*/
895QSize QLayout::maximumSize() const
896{
897 return QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX);
898}
899
900/*!
901 Returns whether this layout can make use of more space than
902 sizeHint(). A value of Qt::Vertical or Qt::Horizontal means that
903 it wants to grow in only one dimension, whereas Qt::Vertical |
904 Qt::Horizontal means that it wants to grow in both dimensions.
905
906 The default implementation returns Qt::Horizontal | Qt::Vertical.
907 Subclasses reimplement it to return a meaningful value based on
908 their child widgets's \l{QSizePolicy}{size policies}.
909
910 \sa sizeHint()
911*/
912Qt::Orientations QLayout::expandingDirections() const
913{
914 return Qt::Horizontal | Qt::Vertical;
915}
916
917void QLayout::activateRecursiveHelper(QLayoutItem *item)
918{
919 item->invalidate();
920 QLayout *layout = item->layout();
921 if (layout) {
922 QLayoutItem *child;
923 int i=0;
924 while ((child = layout->itemAt(i++)))
925 activateRecursiveHelper(child);
926 layout->d_func()->activated = true;
927 }
928}
929
930/*!
931 Updates the layout for parentWidget().
932
933 You should generally not need to call this because it is
934 automatically called at the most appropriate times.
935
936 \sa activate(), invalidate()
937*/
938
939void QLayout::update()
940{
941 QLayout *layout = this;
942 while (layout && layout->d_func()->activated) {
943 layout->d_func()->activated = false;
944 if (layout->d_func()->topLevel) {
945 Q_ASSERT(layout->parent()->isWidgetType());
946 QWidget *mw = static_cast<QWidget*>(layout->parent());
947 QCoreApplication::postEvent(mw, new QEvent(QEvent::LayoutRequest));
948 break;
949 }
950 layout = static_cast<QLayout*>(layout->parent());
951 }
952}
953
954/*!
955 Redoes the layout for parentWidget() if necessary.
956
957 You should generally not need to call this because it is
958 automatically called at the most appropriate times. It returns
959 true if the layout was redone.
960
961 \sa update(), QWidget::updateGeometry()
962*/
963bool QLayout::activate()
964{
965 Q_D(QLayout);
966 if (!d->enabled || !parent())
967 return false;
968 if (!d->topLevel)
969 return static_cast<QLayout*>(parent())->activate();
970 if (d->activated)
971 return false;
972 QWidget *mw = static_cast<QWidget*>(parent());
973 if (Q_UNLIKELY(!mw)) {
974 qWarning("QLayout::activate: %s \"%ls\" does not have a main widget",
975 metaObject()->className(), qUtf16Printable(objectName()));
976 return false;
977 }
978 activateRecursiveHelper(this);
979
980 QWidgetPrivate *md = mw->d_func();
981 uint explMin = md->extra ? md->extra->explicitMinSize : 0;
982 uint explMax = md->extra ? md->extra->explicitMaxSize : 0;
983
984 // Do actual calculation
985 // Result values (needs to be zero or greater to be considered valid/set)
986 // We make some illegal values different from each other due a later compare.
987 // ### In the future we may want minSize(0, 0) and maxSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)
988 // ### Also see comment below.
989 QSize minSize(-1, -1);
990 QSize maxSize(-2, -2);
991
992 // Potentially cached values to avoid calling the same function more times.
993 constexpr QSize empty(0, 0);
994 QSize totalSzH = empty;
995 QSize totalMinSz = empty;
996 QSize totalMaxSz = empty;
997
998 switch (d->verticalConstraint) {
999 case SetFixedSize:
1000 totalSzH = totalSizeHint();
1001 minSize.setHeight(totalSzH.height());
1002 maxSize.setHeight(totalSzH.height());
1003 break;
1004 case SetMinimumSize:
1005 totalMinSz = totalMinimumSize();
1006 minSize.setHeight(totalMinSz.height());
1007 break;
1008 case SetMaximumSize:
1009 totalMaxSz = totalMaximumSize();
1010 maxSize.setHeight(totalMaxSz.height());
1011 break;
1012 case SetMinAndMaxSize:
1013 totalMinSz = totalMinimumSize();
1014 totalMaxSz = totalMaximumSize();
1015 minSize.setHeight(totalMinSz.height());
1016 maxSize.setHeight(totalMaxSz.height());
1017 break;
1018 case SetDefaultConstraint: {
1019 bool heightSet = explMin & Qt::Vertical;
1020 if (mw->isWindow()) {
1021 if (!heightSet) {
1022 totalMinSz = totalMinimumSize();
1023 minSize.setHeight(totalMinSz.height());
1024 } else {
1025 minSize.setHeight(mw->minimumHeight());
1026 }
1027 } else {
1028 minSize.setHeight(heightSet ? mw->minimumHeight() : 0);
1029 }
1030 break;
1031 }
1032 case SetNoConstraint:
1033 break;
1034 }
1035 switch (d->horizontalConstraint) {
1036 case SetFixedSize:
1037 if (totalSzH == empty)
1038 totalSzH = totalSizeHint();
1039 minSize.setWidth(totalSzH.width());
1040 maxSize.setWidth(totalSzH.width());
1041 break;
1042 case SetMinimumSize:
1043 if (totalMinSz == empty)
1044 totalMinSz = totalMinimumSize();
1045 minSize.setWidth(totalMinSz.width());
1046 break;
1047 case SetMaximumSize:
1048 if (totalMaxSz == empty)
1049 totalMaxSz = totalMaximumSize();
1050 maxSize.setWidth(totalMaxSz.width());
1051 break;
1052 case SetMinAndMaxSize:
1053 if (totalMinSz == empty)
1054 totalMinSz = totalMinimumSize();
1055 if (totalMaxSz == empty)
1056 totalMaxSz = totalMaximumSize();
1057
1058 minSize.setWidth(totalMinSz.width());
1059 maxSize.setWidth(totalMaxSz.width());
1060 break;
1061 case SetDefaultConstraint: {
1062 const bool widthSet = explMin & Qt::Horizontal;
1063 if (mw->isWindow()) {
1064 if (!widthSet) {
1065 if (totalMinSz == empty)
1066 totalMinSz = totalMinimumSize();
1067 minSize.setWidth(totalMinSz.width());
1068 } else {
1069 minSize.setWidth(mw->minimumWidth());
1070 }
1071 } else {
1072 minSize.setWidth(widthSet ? mw->minimumWidth() : 0);
1073 }
1074 break;
1075 }
1076 case SetNoConstraint:
1077 break;
1078 }
1079 if (minSize == maxSize) {
1080 mw->setFixedSize(minSize);
1081 }
1082 else {
1083 // ### To preserve backward compatibility with behavior prior to introducing separate
1084 // ### horizontal and vertical constraints, we only update the specific size properties
1085 // ### dictated by the constraints. For example, if only minimum width is specified
1086 // ### by the constraint, we leave the minimum height untouched.
1087 // ### Like before we leave unconstrained values unchanged though it can
1088 // ### (unintentionally?) retain stale values.
1089
1090 // handle min-size
1091 if (minSize.isValid())
1092 mw->setMinimumSize(minSize);
1093 else if (minSize.width() >= 0)
1094 mw->setMinimumWidth(minSize.width());
1095 else if (minSize.height() >= 0)
1096 mw->setMinimumHeight(minSize.height());
1097
1098 // handle max-size
1099 if (maxSize.isValid())
1100 mw->setMaximumSize(maxSize);
1101 else if (maxSize.width() >= 0)
1102 mw->setMaximumWidth(maxSize.width());
1103 else if (maxSize.height() >= 0)
1104 mw->setMaximumHeight(maxSize.height());
1105 }
1106
1107 d->doResize();
1108
1109 if (md->extra) {
1110 md->extra->explicitMinSize = explMin;
1111 md->extra->explicitMaxSize = explMax;
1112 }
1113 // ideally only if sizeHint() or sizePolicy() has changed
1114 mw->updateGeometry();
1115 return true;
1116}
1117
1118/*!
1119 \since 5.2
1120
1121 Searches for widget \a from and replaces it with widget \a to if found.
1122 Returns the layout item that contains the widget \a from on success.
1123 Otherwise \nullptr is returned.
1124 If \a options contains \c Qt::FindChildrenRecursively (the default),
1125 sub-layouts are searched for doing the replacement.
1126 Any other flag in \a options is ignored.
1127
1128 Notice that the returned item therefore might not belong to this layout,
1129 but to a sub-layout.
1130
1131 The returned layout item is no longer owned by the layout and should be
1132 either deleted or inserted to another layout. The widget \a from is no
1133 longer managed by the layout and may need to be deleted or hidden. The
1134 parent of widget \a from is left unchanged.
1135
1136 This function works for the built-in Qt layouts, but might not work for
1137 custom layouts.
1138
1139 \sa indexOf()
1140*/
1141
1142QLayoutItem *QLayout::replaceWidget(QWidget *from, QWidget *to, Qt::FindChildOptions options)
1143{
1144 Q_D(QLayout);
1145 if (!from || !to)
1146 return nullptr;
1147 if (from == to) // Do not return a QLayoutItem for \a from, since ownership still
1148 return nullptr; // belongs to the layout (since nothing was changed)
1149
1150 int index = -1;
1151 QLayoutItem *item = nullptr;
1152 for (int u = 0; u < count(); ++u) {
1153 item = itemAt(u);
1154 if (!item)
1155 continue;
1156
1157 if (item->widget() == from) {
1158 index = u;
1159 break;
1160 }
1161
1162 if (item->layout() && (options & Qt::FindChildrenRecursively)) {
1163 QLayoutItem *r = item->layout()->replaceWidget(from, to, options);
1164 if (r)
1165 return r;
1166 }
1167 }
1168 if (index == -1)
1169 return nullptr;
1170
1171 addChildWidget(to);
1172 QLayoutItem *newitem = new QWidgetItem(to);
1173 newitem->setAlignment(item->alignment());
1174 QLayoutItem *r = d->replaceAt(index, newitem);
1175 if (!r)
1176 delete newitem;
1177 return r;
1178}
1179
1180/*!
1181 \fn QLayoutItem *QLayout::itemAt(int index) const
1182
1183 Must be implemented in subclasses to return the layout item at \a
1184 index. If there is no such item, the function must return \nullptr.
1185 Items are numbered consecutively from 0. If an item is deleted, other items will be renumbered.
1186
1187 This function can be used to iterate over a layout. The following
1188 code will draw a rectangle for each layout item in the layout structure of the widget.
1189
1190 \snippet code/src_gui_kernel_qlayout.cpp 0
1191
1192 \sa count(), takeAt()
1193*/
1194
1195/*!
1196 \fn QLayoutItem *QLayout::takeAt(int index)
1197
1198 Must be implemented in subclasses to remove the layout item at \a
1199 index from the layout, and return the item. If there is no such
1200 item, the function must do nothing and return 0. Items are numbered
1201 consecutively from 0. If an item is removed, other items will be
1202 renumbered.
1203
1204 The following code fragment shows a safe way to remove all items
1205 from a layout:
1206
1207 \snippet code/src_gui_kernel_qlayout.cpp 1
1208
1209 \sa itemAt(), count()
1210*/
1211
1212/*!
1213 \fn int *QLayout::count() const
1214
1215 Must be implemented in subclasses to return the number of items
1216 in the layout.
1217
1218 \sa itemAt()
1219*/
1220
1221/*!
1222 Searches for widget \a widget in this layout (not including child
1223 layouts).
1224
1225 Returns the index of \a widget, or -1 if \a widget is not found.
1226
1227 The default implementation iterates over all items using itemAt().
1228*/
1229int QLayout::indexOf(const QWidget *widget) const
1230{
1231 const int c = count();
1232
1233 for (int i = 0; i < c; ++i) {
1234 if (itemAt(i)->widget() == widget)
1235 return i;
1236 }
1237
1238 return -1;
1239}
1240
1241/*!
1242 \since 5.12
1243 Searches for layout item \a layoutItem in this layout (not including child
1244 layouts).
1245
1246 Returns the index of \a layoutItem, or -1 if \a layoutItem is not found.
1247*/
1248int QLayout::indexOf(const QLayoutItem *layoutItem) const
1249{
1250 const int c = count();
1251
1252 for (int i = 0; i < c; ++i) {
1253 if (itemAt(i) == layoutItem)
1254 return i;
1255 }
1256
1257 return -1;
1258}
1259
1260/*!
1261 \enum QLayout::SizeConstraint
1262 Describes how the layout constrains the size of the widget.
1263
1264 A vertical constraint affects the widget's height, while a horizontal constraint affects its width.
1265
1266 The possible values are:
1267
1268 \value SetDefaultConstraint
1269 In the constrained orientation(s), the widget’s minimum extent
1270 is set to \l minimumSize(), unless a minimum size has already been set.
1271
1272 \value SetFixedSize
1273 In the constrained orientation(s), the widget’s extent is set to
1274 \l sizeHint(), and it cannot be resized in that direction.
1275
1276 \value SetMinimumSize
1277 In the constrained orientation(s), the widget’s minimum extent
1278 is set to \l minimumSize().
1279
1280 \value SetMaximumSize
1281 In the constrained orientation(s), the widget’s maximum extent
1282 is set to \l maximumSize().
1283
1284 \value SetMinAndMaxSize
1285 In the constrained orientation(s), the widget’s minimum extent
1286 is set to \l minimumSize(), and the maximum extent is set to \l maximumSize().
1287
1288 \value SetNoConstraint
1289 No size constraints are applied to the widget.
1290
1291 \sa setSizeConstraint(), setSizeConstraints(), horizontalSizeConstraint(), setHorizontalSizeConstraint(), setVerticalSizeConstraint()
1292*/
1293
1294/*!
1295 \property QLayout::sizeConstraint
1296 \brief the resize mode of the layout.
1297 Setting the size constraint for the dialog.
1298 Setting a vertical or horizontal size constraint will override this.
1299
1300 The default mode is \l {QLayout::SetDefaultConstraint}
1301 {SetDefaultConstraint}.
1302
1303 \sa horizontalSizeConstraint(), verticalSizeConstraint()
1304*/
1305
1306void QLayout::setSizeConstraint(SizeConstraint constraint)
1307{
1308 setSizeConstraints(constraint, constraint);
1309}
1310
1311/*!
1312 \since 6.10
1313
1314 Sets both the \a horizontal and \a vertical size constraints.
1315
1316 \sa sizeConstraint(), horizontalSizeConstraint(), verticalSizeConstraint()
1317 */
1318void QLayout::setSizeConstraints(SizeConstraint horizontal, SizeConstraint vertical)
1319{
1320 Q_D(QLayout);
1321 if (horizontal == d->horizontalConstraint && vertical == d->verticalConstraint)
1322 return;
1323 d->horizontalConstraint = horizontal;
1324 d->verticalConstraint = vertical;
1325 invalidate();
1326}
1327
1328QLayout::SizeConstraint QLayout::sizeConstraint() const
1329{
1330 Q_D(const QLayout);
1331 return d->horizontalConstraint;
1332}
1333
1334/*!
1335 \property QLayout::horizontalSizeConstraint
1336 \since 6.10
1337 \brief The horizontal size constraint.
1338
1339 The default mode is \l {QLayout::SetDefaultConstraint}
1340
1341 \sa verticalSizeConstraint(), sizeConstraint()
1342*/
1343
1344void QLayout::setHorizontalSizeConstraint(SizeConstraint constraint)
1345{
1346 Q_D(QLayout);
1347 if (constraint == d->horizontalConstraint)
1348 return;
1349 d->horizontalConstraint = constraint;
1350 invalidate();
1351}
1352
1353
1354QLayout::SizeConstraint QLayout::horizontalSizeConstraint() const
1355{
1356 Q_D(const QLayout);
1357 return d->horizontalConstraint;
1358}
1359
1360/*!
1361 \property QLayout::verticalSizeConstraint
1362 \since 6.10
1363 \brief The vertical size constraint.
1364
1365 The default mode is \l {QLayout::SetDefaultConstraint}
1366
1367 \sa horizontalSizeConstraint(), sizeConstraint()
1368*/
1369
1370void QLayout::setVerticalSizeConstraint(SizeConstraint constraint)
1371{
1372 Q_D(QLayout);
1373 if (constraint == d->verticalConstraint)
1374 return;
1375 d->verticalConstraint = constraint;
1376 invalidate();
1377}
1378
1379QLayout::SizeConstraint QLayout::verticalSizeConstraint() const
1380{
1381 Q_D(const QLayout);
1382 return d->verticalConstraint;
1383}
1384
1385/*!
1386 Returns the rectangle that should be covered when the geometry of
1387 this layout is set to \a r, provided that this layout supports
1388 setAlignment().
1389
1390 The result is derived from sizeHint() and expandingDirections(). It is never
1391 larger than \a r.
1392*/
1393QRect QLayout::alignmentRect(const QRect &r) const
1394{
1395 QSize s = sizeHint();
1396 Qt::Alignment a = alignment();
1397
1398 /*
1399 This is a hack to obtain the real maximum size, not
1400 QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX), the value consistently
1401 returned by QLayoutItems that have an alignment.
1402 */
1403 QLayout *that = const_cast<QLayout *>(this);
1404 that->setAlignment({ });
1405 QSize ms = that->maximumSize();
1406 that->setAlignment(a);
1407
1408 if ((expandingDirections() & Qt::Horizontal) ||
1409 !(a & Qt::AlignHorizontal_Mask)) {
1410 s.setWidth(qMin(r.width(), ms.width()));
1411 }
1412 if ((expandingDirections() & Qt::Vertical) ||
1413 !(a & Qt::AlignVertical_Mask)) {
1414 s.setHeight(qMin(r.height(), ms.height()));
1415 } else if (hasHeightForWidth()) {
1416 int hfw = heightForWidth(s.width());
1417 if (hfw < s.height())
1418 s.setHeight(qMin(hfw, ms.height()));
1419 }
1420
1421 s = s.boundedTo(r.size());
1422 int x = r.x();
1423 int y = r.y();
1424
1425 if (a & Qt::AlignBottom)
1426 y += (r.height() - s.height());
1427 else if (!(a & Qt::AlignTop))
1428 y += (r.height() - s.height()) / 2;
1429
1430 QWidget *parent = parentWidget();
1431 a = QStyle::visualAlignment(parent ? parent->layoutDirection() : QGuiApplication::layoutDirection(), a);
1432 if (a & Qt::AlignRight)
1433 x += (r.width() - s.width());
1434 else if (!(a & Qt::AlignLeft))
1435 x += (r.width() - s.width()) / 2;
1436
1437 return QRect(x, y, s.width(), s.height());
1438}
1439
1440/*!
1441 Removes the widget \a widget from the layout. After this call, it
1442 is the caller's responsibility to give the widget a reasonable
1443 geometry or to put the widget back into a layout or to explicitly
1444 hide it if necessary.
1445
1446 \b{Note:} The ownership of \a widget remains the same as
1447 when it was added.
1448
1449 \sa removeItem(), QWidget::setGeometry(), addWidget()
1450*/
1451void QLayout::removeWidget(QWidget *widget)
1452{
1453 if (Q_UNLIKELY(!widget)) {
1454 qWarning("QLayout::removeWidget: Cannot remove a null widget.");
1455 return;
1456 }
1457
1458 int i = 0;
1459 QLayoutItem *child;
1460 while ((child = itemAt(i))) {
1461 if (child->widget() == widget) {
1462 delete takeAt(i);
1463 invalidate();
1464 } else {
1465 ++i;
1466 }
1467 }
1468}
1469
1470/*!
1471 Removes the layout item \a item from the layout. It is the
1472 caller's responsibility to delete the item.
1473
1474 Notice that \a item can be a layout (since QLayout inherits
1475 QLayoutItem).
1476
1477 \sa removeWidget(), addItem()
1478*/
1479void QLayout::removeItem(QLayoutItem *item)
1480{
1481 int i = 0;
1482 QLayoutItem *child;
1483 while ((child = itemAt(i))) {
1484 if (child == item) {
1485 takeAt(i);
1486 invalidate();
1487 } else {
1488 ++i;
1489 }
1490 }
1491}
1492
1493/*!
1494 Enables this layout if \a enable is true, otherwise disables it.
1495
1496 An enabled layout adjusts dynamically to changes; a disabled
1497 layout acts as if it did not exist.
1498
1499 By default all layouts are enabled.
1500
1501 \sa isEnabled()
1502*/
1503void QLayout::setEnabled(bool enable)
1504{
1505 Q_D(QLayout);
1506 d->enabled = enable;
1507}
1508
1509/*!
1510 Returns \c true if the layout is enabled; otherwise returns \c false.
1511
1512 \sa setEnabled()
1513*/
1514bool QLayout::isEnabled() const
1515{
1516 Q_D(const QLayout);
1517 return d->enabled;
1518}
1519
1520/*!
1521 Returns a size that satisfies all size constraints on \a widget,
1522 including heightForWidth() and that is as close as possible to \a
1523 size.
1524*/
1525
1526QSize QLayout::closestAcceptableSize(const QWidget *widget, const QSize &size)
1527{
1528 QSize result = size.boundedTo(qSmartMaxSize(widget));
1529 result = result.expandedTo(qSmartMinSize(widget));
1530 QLayout *l = widget->layout();
1531 if (l && l->hasHeightForWidth() && result.height() < l->minimumHeightForWidth(result.width()) ) {
1532 QSize current = widget->size();
1533 int currentHfw = l->minimumHeightForWidth(current.width());
1534 int newHfw = l->minimumHeightForWidth(result.width());
1535 if (current.height() < currentHfw || currentHfw == newHfw) {
1536 //handle the constant hfw case and the vertical-only case, as well as the
1537 // current-size-is-not-correct case
1538 result.setHeight(newHfw);
1539 } else {
1540 // binary search; assume hfw is decreasing ###
1541
1542 int maxw = qMax(widget->width(),result.width());
1543 int maxh = qMax(widget->height(), result.height());
1544 int minw = qMin(widget->width(),result.width());
1545 int minh = qMin(widget->height(), result.height());
1546
1547 int minhfw = l->minimumHeightForWidth(minw);
1548 int maxhfw = l->minimumHeightForWidth(maxw);
1549 while (minw < maxw) {
1550 if (minhfw > maxh) { //assume decreasing
1551 minw = maxw - (maxw-minw)/2;
1552 minhfw = l->minimumHeightForWidth(minw);
1553 } else if (maxhfw < minh ) { //assume decreasing
1554 maxw = minw + (maxw-minw)/2;
1555 maxhfw = l->minimumHeightForWidth(maxw);
1556 } else {
1557 break;
1558 }
1559 }
1560 result = result.expandedTo(QSize(minw, minhfw));
1561 }
1562 }
1563 return result;
1564}
1565
1566QT_END_NAMESPACE
1567
1568#include "moc_qlayout.cpp"
static QT_BEGIN_NAMESPACE int menuBarHeightForWidth(QWidget *menubar, int w)
Definition qlayout.cpp:16
static bool removeWidgetRecursively(QLayoutItem *li, QObject *w)
Definition qlayout.cpp:467