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