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
62QT_BEGIN_NAMESPACE
63
64static 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*/
118QLayout::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*/
132QLayout::QLayout()
133 : QObject(*new QLayoutPrivate, 0)
134{
135}
136
137
138/*! \internal
139 */
140QLayout::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(0);
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 = 0;
160 QT_RETHROW;
161 }
162 }
163 }
164}
165
166QLayoutPrivate::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(0)
170{
171}
172
173void 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, 0, pw);
185 } else {
186 *result = 0;
187 }
188}
189
190// Static item factory functions that allow for hooking things in Designer
191
192QLayoutPrivate::QWidgetItemFactoryMethod QLayoutPrivate::widgetItemFactoryMethod = 0;
193QLayoutPrivate::QSpacerItemFactoryMethod QLayoutPrivate::spacerItemFactoryMethod = 0;
194
195QWidgetItem *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
203QSpacerItem *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*/
233void 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*/
246bool 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*/
269bool 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*/
299int 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*/
313void 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
336int 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
357void 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*/
389void 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*/
414void 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*/
435void 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*/
454QMargins 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*/
469QRect 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*/
487QWidget *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*/
510bool 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*/
526QSizePolicy::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*/
539void QLayout::setGeometry(const QRect &r)
540{
541 Q_D(QLayout);
542 d->rect = r;
543}
544
545/*!
546 \reimp
547*/
548QRect QLayout::geometry() const
549{
550 Q_D(const QLayout);
551 return d->rect;
552}
553
554/*!
555 \reimp
556*/
557void QLayout::invalidate()
558{
559 Q_D(QLayout);
560 d->rect = QRect();
561 update();
562}
563
564static 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
586void QLayoutPrivate::doResize(const QSize &r)
587{
588 Q_Q(QLayout);
589 int mbh = menuBarHeightForWidth(menubar, r.width());
590 QWidget *mw = q->parentWidget();
591 QRect rect = mw->testAttribute(Qt::WA_LayoutOnEntireRect) ? mw->rect() : mw->contentsRect();
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, r.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*/
608void 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 QResizeEvent *r = (QResizeEvent *)e;
618 d->doResize(r->size());
619 } else {
620 activate();
621 }
622 break;
623 case QEvent::ChildRemoved:
624 {
625 QChildEvent *c = (QChildEvent *)e;
626 if (c->child()->isWidgetType()) {
627#if QT_CONFIG(menubar)
628 if (c->child() == d->menubar)
629 d->menubar = 0;
630#endif
631 removeWidgetRecursively(this, c->child());
632 }
633 }
634 break;
635 case QEvent::LayoutRequest:
636 if (static_cast<QWidget *>(parent())->isVisible())
637 activate();
638 break;
639 default:
640 break;
641 }
642}
643
644/*!
645 \reimp
646*/
647void QLayout::childEvent(QChildEvent *e)
648{
649 Q_D(QLayout);
650 if (!d->enabled)
651 return;
652
653 if (e->type() != QEvent::ChildRemoved)
654 return;
655
656 if (QLayout *childLayout = qobject_cast<QLayout *>(e->child()))
657 removeItem(childLayout);
658}
659
660/*!
661 \internal
662 Also takes contentsMargins and menu bar into account.
663*/
664int QLayout::totalHeightForWidth(int w) const
665{
666 Q_D(const QLayout);
667 int side=0, top=0;
668 if (d->topLevel) {
669 QWidget *parent = parentWidget();
670 parent->ensurePolished();
671 QWidgetPrivate *wd = parent->d_func();
672 side += wd->leftmargin + wd->rightmargin;
673 top += wd->topmargin + wd->bottommargin;
674 }
675 int h = heightForWidth(w - side) + top;
676#if QT_CONFIG(menubar)
677 h += menuBarHeightForWidth(d->menubar, w);
678#endif
679 return h;
680}
681
682/*!
683 \internal
684 Also takes contentsMargins and menu bar into account.
685*/
686QSize QLayout::totalMinimumSize() const
687{
688 Q_D(const QLayout);
689 int side=0, top=0;
690 if (d->topLevel) {
691 QWidget *pw = parentWidget();
692 pw->ensurePolished();
693 QWidgetPrivate *wd = pw->d_func();
694 side += wd->leftmargin + wd->rightmargin;
695 top += wd->topmargin + wd->bottommargin;
696 }
697
698 QSize s = minimumSize();
699#if QT_CONFIG(menubar)
700 top += menuBarHeightForWidth(d->menubar, s.width() + side);
701#endif
702 return s + QSize(side, top);
703}
704
705/*!
706 \internal
707 Also takes contentsMargins and menu bar into account.
708*/
709QSize QLayout::totalSizeHint() const
710{
711 Q_D(const QLayout);
712 int side=0, top=0;
713 if (d->topLevel) {
714 QWidget *pw = parentWidget();
715 pw->ensurePolished();
716 QWidgetPrivate *wd = pw->d_func();
717 side += wd->leftmargin + wd->rightmargin;
718 top += wd->topmargin + wd->bottommargin;
719 }
720
721 QSize s = sizeHint();
722 if (hasHeightForWidth())
723 s.setHeight(heightForWidth(s.width() + side));
724#if QT_CONFIG(menubar)
725 top += menuBarHeightForWidth(d->menubar, s.width());
726#endif
727 return s + QSize(side, top);
728}
729
730/*!
731 \internal
732 Also takes contentsMargins and menu bar into account.
733*/
734QSize QLayout::totalMaximumSize() const
735{
736 Q_D(const QLayout);
737 int side=0, top=0;
738 if (d->topLevel) {
739 QWidget *pw = parentWidget();
740 pw->ensurePolished();
741 QWidgetPrivate *wd = pw->d_func();
742 side += wd->leftmargin + wd->rightmargin;
743 top += wd->topmargin + wd->bottommargin;
744 }
745
746 QSize s = maximumSize();
747#if QT_CONFIG(menubar)
748 top += menuBarHeightForWidth(d->menubar, s.width());
749#endif
750
751 if (d->topLevel)
752 s = QSize(qMin(s.width() + side, QLAYOUTSIZE_MAX),
753 qMin(s.height() + top, QLAYOUTSIZE_MAX));
754 return s;
755}
756
757/*!
758 \internal
759 Destroys the layout, deleting all child layouts.
760 Geometry management stops when a top-level layout is deleted.
761
762 The layout classes will probably be fatally confused if you delete
763 a sublayout.
764*/
765QLayout::~QLayout()
766{
767 Q_D(QLayout);
768 if (d->topLevel && parent() && parent()->isWidgetType() && parentWidget()->layout() == this)
769 parentWidget()->d_func()->layout = 0;
770 else if (QLayout *parentLayout = qobject_cast<QLayout *>(parent()))
771 parentLayout->removeItem(this);
772}
773
774
775/*!
776 This function is called from \c addLayout() or \c insertLayout() functions in
777 subclasses to add layout \a l as a sub-layout.
778
779 The only scenario in which you need to call it directly is if you
780 implement a custom layout that supports nested layouts.
781
782 \sa QBoxLayout::addLayout(), QBoxLayout::insertLayout(), QGridLayout::addLayout()
783*/
784void QLayout::addChildLayout(QLayout *l)
785{
786 if (Q_UNLIKELY(l->parent())) {
787 qWarning("QLayout::addChildLayout: layout \"%ls\" already has a parent",
788 qUtf16Printable(l->objectName()));
789 return;
790 }
791 l->setParent(this);
792
793 if (QWidget *mw = parentWidget()) {
794 l->d_func()->reparentChildWidgets(mw);
795 }
796
797}
798
799/*!
800 \internal
801 */
802bool QLayout::adoptLayout(QLayout *layout)
803{
804 const bool ok = !layout->parent();
805 addChildLayout(layout);
806 return ok;
807}
808
809#ifdef QT_DEBUG
810static bool layoutDebug()
811{
812 static int checked_env = -1;
813 if(checked_env == -1)
814 checked_env = !!qEnvironmentVariableIntValue("QT_LAYOUT_DEBUG");
815
816 return checked_env;
817}
818#endif
819
820void QLayoutPrivate::reparentChildWidgets(QWidget *mw)
821{
822 Q_Q(QLayout);
823 int n = q->count();
824
825#if QT_CONFIG(menubar)
826 if (menubar && menubar->parentWidget() != mw) {
827 menubar->setParent(mw);
828 }
829#endif
830 bool mwVisible = mw && mw->isVisible();
831 for (int i = 0; i < n; ++i) {
832 QLayoutItem *item = q->itemAt(i);
833 if (QWidget *w = item->widget()) {
834 QWidget *pw = w->parentWidget();
835#ifdef QT_DEBUG
836 if (Q_UNLIKELY(pw && pw != mw && layoutDebug())) {
837 qWarning("QLayout::addChildLayout: widget %s \"%ls\" in wrong parent; moved to correct parent",
838 w->metaObject()->className(), qUtf16Printable(w->objectName()));
839 }
840#endif
841 bool needShow = mwVisible && !(w->isHidden() && w->testAttribute(Qt::WA_WState_ExplicitShowHide));
842 if (pw != mw)
843 w->setParent(mw);
844 if (needShow)
845 QMetaObject::invokeMethod(w, "_q_showIfNotHidden", Qt::QueuedConnection); //show later
846 } else if (QLayout *l = item->layout()) {
847 l->d_func()->reparentChildWidgets(mw);
848 }
849 }
850}
851
852/*!
853 Returns \c true if the \a widget can be added to the \a layout;
854 otherwise returns \c false.
855*/
856bool QLayoutPrivate::checkWidget(QWidget *widget) const
857{
858 Q_Q(const QLayout);
859 if (Q_UNLIKELY(!widget)) {
860 qWarning("QLayout: Cannot add a null widget to %s/%ls", q->metaObject()->className(),
861 qUtf16Printable(q->objectName()));
862 return false;
863 }
864 if (Q_UNLIKELY(widget == q->parentWidget())) {
865 qWarning("QLayout: Cannot add parent widget %s/%ls to its child layout %s/%ls",
866 widget->metaObject()->className(), qUtf16Printable(widget->objectName()),
867 q->metaObject()->className(), qUtf16Printable(q->objectName()));
868 return false;
869 }
870 return true;
871}
872
873/*!
874 Returns \c true if the \a otherLayout can be added to the \a layout;
875 otherwise returns \c false.
876*/
877bool QLayoutPrivate::checkLayout(QLayout *otherLayout) const
878{
879 Q_Q(const QLayout);
880 if (Q_UNLIKELY(!otherLayout)) {
881 qWarning("QLayout: Cannot add a null layout to %s/%ls",
882 q->metaObject()->className(), qUtf16Printable(q->objectName()));
883 return false;
884 }
885 if (Q_UNLIKELY(otherLayout == q)) {
886 qWarning("QLayout: Cannot add layout %s/%ls to itself",
887 q->metaObject()->className(), qUtf16Printable(q->objectName()));
888 return false;
889 }
890 return true;
891}
892
893/*!
894 This function is called from \c addWidget() functions in
895 subclasses to add \a w as a managed widget of a layout.
896
897 If \a w is already managed by a layout, this function will give a warning
898 and remove \a w from that layout. This function must therefore be
899 called before adding \a w to the layout's data structure.
900*/
901void QLayout::addChildWidget(QWidget *w)
902{
903 QWidget *mw = parentWidget();
904 QWidget *pw = w->parentWidget();
905
906 //Qt::WA_LaidOut is never reset. It only means that the widget at some point has
907 //been in a layout.
908 if (pw && w->testAttribute(Qt::WA_LaidOut)) {
909 QLayout *l = pw->layout();
910 if (l && removeWidgetRecursively(l, w)) {
911#ifdef QT_DEBUG
912 if (Q_UNLIKELY(layoutDebug()))
913 qWarning("QLayout::addChildWidget: %s \"%ls\" is already in a layout; moved to new layout",
914 w->metaObject()->className(), qUtf16Printable(w->objectName()));
915#endif
916 }
917 }
918 if (pw && mw && pw != mw) {
919#ifdef QT_DEBUG
920 if (Q_UNLIKELY(layoutDebug()))
921 qWarning("QLayout::addChildWidget: %s \"%ls\" in wrong parent; moved to correct parent",
922 w->metaObject()->className(), qUtf16Printable(w->objectName()));
923#endif
924 pw = 0;
925 }
926 bool needShow = mw && mw->isVisible() && !(w->isHidden() && w->testAttribute(Qt::WA_WState_ExplicitShowHide));
927 if (!pw && mw)
928 w->setParent(mw);
929 w->setAttribute(Qt::WA_LaidOut);
930 if (needShow)
931 QMetaObject::invokeMethod(w, "_q_showIfNotHidden", Qt::QueuedConnection); //show later
932}
933
934
935
936
937
938
939
940
941/*!
942 Tells the geometry manager to place the menu bar \a widget at the
943 top of parentWidget(), outside QWidget::contentsMargins(). All
944 child widgets are placed below the bottom edge of the menu bar.
945*/
946void QLayout::setMenuBar(QWidget *widget)
947{
948 Q_D(QLayout);
949 if (widget)
950 addChildWidget(widget);
951 d->menubar = widget;
952}
953
954/*!
955 Returns the menu bar set for this layout, or \nullptr if no
956 menu bar is set.
957*/
958
959QWidget *QLayout::menuBar() const
960{
961 Q_D(const QLayout);
962 return d->menubar;
963}
964
965
966/*!
967 Returns the minimum size of this layout. This is the smallest
968 size that the layout can have while still respecting the
969 specifications.
970
971 The returned value doesn't include the space required by
972 QWidget::setContentsMargins() or menuBar().
973
974 The default implementation allows unlimited resizing.
975*/
976QSize QLayout::minimumSize() const
977{
978 return QSize(0, 0);
979}
980
981/*!
982 Returns the maximum size of this layout. This is the largest size
983 that the layout can have while still respecting the
984 specifications.
985
986 The returned value doesn't include the space required by
987 QWidget::setContentsMargins() or menuBar().
988
989 The default implementation allows unlimited resizing.
990*/
991QSize QLayout::maximumSize() const
992{
993 return QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX);
994}
995
996/*!
997 Returns whether this layout can make use of more space than
998 sizeHint(). A value of Qt::Vertical or Qt::Horizontal means that
999 it wants to grow in only one dimension, whereas Qt::Vertical |
1000 Qt::Horizontal means that it wants to grow in both dimensions.
1001
1002 The default implementation returns Qt::Horizontal | Qt::Vertical.
1003 Subclasses reimplement it to return a meaningful value based on
1004 their child widgets's \l{QSizePolicy}{size policies}.
1005
1006 \sa sizeHint()
1007*/
1008Qt::Orientations QLayout::expandingDirections() const
1009{
1010 return Qt::Horizontal | Qt::Vertical;
1011}
1012
1013void QLayout::activateRecursiveHelper(QLayoutItem *item)
1014{
1015 item->invalidate();
1016 QLayout *layout = item->layout();
1017 if (layout) {
1018 QLayoutItem *child;
1019 int i=0;
1020 while ((child = layout->itemAt(i++)))
1021 activateRecursiveHelper(child);
1022 layout->d_func()->activated = true;
1023 }
1024}
1025
1026/*!
1027 Updates the layout for parentWidget().
1028
1029 You should generally not need to call this because it is
1030 automatically called at the most appropriate times.
1031
1032 \sa activate(), invalidate()
1033*/
1034
1035void QLayout::update()
1036{
1037 QLayout *layout = this;
1038 while (layout && layout->d_func()->activated) {
1039 layout->d_func()->activated = false;
1040 if (layout->d_func()->topLevel) {
1041 Q_ASSERT(layout->parent()->isWidgetType());
1042 QWidget *mw = static_cast<QWidget*>(layout->parent());
1043 QCoreApplication::postEvent(mw, new QEvent(QEvent::LayoutRequest));
1044 break;
1045 }
1046 layout = static_cast<QLayout*>(layout->parent());
1047 }
1048}
1049
1050/*!
1051 Redoes the layout for parentWidget() if necessary.
1052
1053 You should generally not need to call this because it is
1054 automatically called at the most appropriate times. It returns
1055 true if the layout was redone.
1056
1057 \sa update(), QWidget::updateGeometry()
1058*/
1059bool QLayout::activate()
1060{
1061 Q_D(QLayout);
1062 if (!d->enabled || !parent())
1063 return false;
1064 if (!d->topLevel)
1065 return static_cast<QLayout*>(parent())->activate();
1066 if (d->activated)
1067 return false;
1068 QWidget *mw = static_cast<QWidget*>(parent());
1069 if (Q_UNLIKELY(!mw)) {
1070 qWarning("QLayout::activate: %s \"%ls\" does not have a main widget",
1071 metaObject()->className(), qUtf16Printable(objectName()));
1072 return false;
1073 }
1074 activateRecursiveHelper(this);
1075
1076 QWidgetPrivate *md = mw->d_func();
1077 uint explMin = md->extra ? md->extra->explicitMinSize : 0;
1078 uint explMax = md->extra ? md->extra->explicitMaxSize : 0;
1079
1080 switch (d->constraint) {
1081 case SetFixedSize:
1082 // will trigger resize
1083 mw->setFixedSize(totalSizeHint());
1084 break;
1085 case SetMinimumSize:
1086 mw->setMinimumSize(totalMinimumSize());
1087 break;
1088 case SetMaximumSize:
1089 mw->setMaximumSize(totalMaximumSize());
1090 break;
1091 case SetMinAndMaxSize:
1092 mw->setMinimumSize(totalMinimumSize());
1093 mw->setMaximumSize(totalMaximumSize());
1094 break;
1095 case SetDefaultConstraint: {
1096 bool widthSet = explMin & Qt::Horizontal;
1097 bool heightSet = explMin & Qt::Vertical;
1098 if (mw->isWindow()) {
1099 QSize ms = totalMinimumSize();
1100 if (widthSet)
1101 ms.setWidth(mw->minimumSize().width());
1102 if (heightSet)
1103 ms.setHeight(mw->minimumSize().height());
1104 mw->setMinimumSize(ms);
1105 } else if (!widthSet || !heightSet) {
1106 QSize ms = mw->minimumSize();
1107 if (!widthSet)
1108 ms.setWidth(0);
1109 if (!heightSet)
1110 ms.setHeight(0);
1111 mw->setMinimumSize(ms);
1112 }
1113 break;
1114 }
1115 case SetNoConstraint:
1116 break;
1117 }
1118
1119 d->doResize(mw->size());
1120
1121 if (md->extra) {
1122 md->extra->explicitMinSize = explMin;
1123 md->extra->explicitMaxSize = explMax;
1124 }
1125 // ideally only if sizeHint() or sizePolicy() has changed
1126 mw->updateGeometry();
1127 return true;
1128}
1129
1130/*!
1131 \since 5.2
1132
1133 Searches for widget \a from and replaces it with widget \a to if found.
1134 Returns the layout item that contains the widget \a from on success.
1135 Otherwise \nullptr is returned.
1136 If \a options contains \c Qt::FindChildrenRecursively (the default),
1137 sub-layouts are searched for doing the replacement.
1138 Any other flag in \a options is ignored.
1139
1140 Notice that the returned item therefore might not belong to this layout,
1141 but to a sub-layout.
1142
1143 The returned layout item is no longer owned by the layout and should be
1144 either deleted or inserted to another layout. The widget \a from is no
1145 longer managed by the layout and may need to be deleted or hidden. The
1146 parent of widget \a from is left unchanged.
1147
1148 This function works for the built-in Qt layouts, but might not work for
1149 custom layouts.
1150
1151 \sa indexOf()
1152*/
1153
1154QLayoutItem *QLayout::replaceWidget(QWidget *from, QWidget *to, Qt::FindChildOptions options)
1155{
1156 Q_D(QLayout);
1157 if (!from || !to)
1158 return 0;
1159 if (from == to) // Do not return a QLayoutItem for \a from, since ownership still
1160 return nullptr; // belongs to the layout (since nothing was changed)
1161
1162 int index = -1;
1163 QLayoutItem *item = 0;
1164 for (int u = 0; u < count(); ++u) {
1165 item = itemAt(u);
1166 if (!item)
1167 continue;
1168
1169 if (item->widget() == from) {
1170 index = u;
1171 break;
1172 }
1173
1174 if (item->layout() && (options & Qt::FindChildrenRecursively)) {
1175 QLayoutItem *r = item->layout()->replaceWidget(from, to, options);
1176 if (r)
1177 return r;
1178 }
1179 }
1180 if (index == -1)
1181 return 0;
1182
1183 addChildWidget(to);
1184 QLayoutItem *newitem = new QWidgetItem(to);
1185 newitem->setAlignment(item->alignment());
1186 QLayoutItem *r = d->replaceAt(index, newitem);
1187 if (!r)
1188 delete newitem;
1189 return r;
1190}
1191
1192/*!
1193 \fn QLayoutItem *QLayout::itemAt(int index) const
1194
1195 Must be implemented in subclasses to return the layout item at \a
1196 index. If there is no such item, the function must return 0.
1197 Items are numbered consecutively from 0. If an item is deleted, other items will be renumbered.
1198
1199 This function can be used to iterate over a layout. The following
1200 code will draw a rectangle for each layout item in the layout structure of the widget.
1201
1202 \snippet code/src_gui_kernel_qlayout.cpp 0
1203
1204 \sa count(), takeAt()
1205*/
1206
1207/*!
1208 \fn QLayoutItem *QLayout::takeAt(int index)
1209
1210 Must be implemented in subclasses to remove the layout item at \a
1211 index from the layout, and return the item. If there is no such
1212 item, the function must do nothing and return 0. Items are numbered
1213 consecutively from 0. If an item is removed, other items will be
1214 renumbered.
1215
1216 The following code fragment shows a safe way to remove all items
1217 from a layout:
1218
1219 \snippet code/src_gui_kernel_qlayout.cpp 1
1220
1221 \sa itemAt(), count()
1222*/
1223
1224/*!
1225 \fn int *QLayout::count() const
1226
1227 Must be implemented in subclasses to return the number of items
1228 in the layout.
1229
1230 \sa itemAt()
1231*/
1232
1233/*!
1234 Searches for widget \a widget in this layout (not including child
1235 layouts).
1236
1237 Returns the index of \a widget, or -1 if \a widget is not found.
1238
1239 The default implementation iterates over all items using itemAt()
1240*/
1241int QLayout::indexOf(QWidget *widget) const
1242{
1243 int i = 0;
1244 QLayoutItem *item = itemAt(i);
1245 while (item) {
1246 if (item->widget() == widget)
1247 return i;
1248 ++i;
1249 item = itemAt(i);
1250 }
1251 return -1;
1252}
1253
1254/*!
1255 \since 5.12
1256 Searches for layout item \a layoutItem in this layout (not including child
1257 layouts).
1258
1259 Returns the index of \a layoutItem, or -1 if \a layoutItem is not found.
1260*/
1261int QLayout::indexOf(QLayoutItem *layoutItem) const
1262{
1263 int i = 0;
1264 QLayoutItem *item = itemAt(i);
1265 while (item) {
1266 if (item == layoutItem)
1267 return i;
1268 ++i;
1269 item = itemAt(i);
1270 }
1271 return -1;
1272}
1273
1274/*!
1275 \enum QLayout::SizeConstraint
1276
1277 The possible values are:
1278
1279 \value SetDefaultConstraint The main widget's minimum size is set
1280 to minimumSize(), unless the widget already has
1281 a minimum size.
1282
1283 \value SetFixedSize The main widget's size is set to sizeHint(); it
1284 cannot be resized at all.
1285 \value SetMinimumSize The main widget's minimum size is set to
1286 minimumSize(); it cannot be smaller.
1287
1288 \value SetMaximumSize The main widget's maximum size is set to
1289 maximumSize(); it cannot be larger.
1290
1291 \value SetMinAndMaxSize The main widget's minimum size is set to
1292 minimumSize() and its maximum size is set to
1293 maximumSize().
1294
1295 \value SetNoConstraint The widget is not constrained.
1296
1297 \sa setSizeConstraint()
1298*/
1299
1300/*!
1301 \property QLayout::sizeConstraint
1302 \brief the resize mode of the layout
1303
1304 The default mode is \l {QLayout::SetDefaultConstraint}
1305 {SetDefaultConstraint}.
1306*/
1307void QLayout::setSizeConstraint(SizeConstraint constraint)
1308{
1309 Q_D(QLayout);
1310 if (constraint == d->constraint)
1311 return;
1312
1313 d->constraint = constraint;
1314 invalidate();
1315}
1316
1317QLayout::SizeConstraint QLayout::sizeConstraint() const
1318{
1319 Q_D(const QLayout);
1320 return d->constraint;
1321}
1322
1323/*!
1324 Returns the rectangle that should be covered when the geometry of
1325 this layout is set to \a r, provided that this layout supports
1326 setAlignment().
1327
1328 The result is derived from sizeHint() and expanding(). It is never
1329 larger than \a r.
1330*/
1331QRect QLayout::alignmentRect(const QRect &r) const
1332{
1333 QSize s = sizeHint();
1334 Qt::Alignment a = alignment();
1335
1336 /*
1337 This is a hack to obtain the real maximum size, not
1338 QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX), the value consistently
1339 returned by QLayoutItems that have an alignment.
1340 */
1341 QLayout *that = const_cast<QLayout *>(this);
1342 that->setAlignment(0);
1343 QSize ms = that->maximumSize();
1344 that->setAlignment(a);
1345
1346 if ((expandingDirections() & Qt::Horizontal) ||
1347 !(a & Qt::AlignHorizontal_Mask)) {
1348 s.setWidth(qMin(r.width(), ms.width()));
1349 }
1350 if ((expandingDirections() & Qt::Vertical) ||
1351 !(a & Qt::AlignVertical_Mask)) {
1352 s.setHeight(qMin(r.height(), ms.height()));
1353 } else if (hasHeightForWidth()) {
1354 int hfw = heightForWidth(s.width());
1355 if (hfw < s.height())
1356 s.setHeight(qMin(hfw, ms.height()));
1357 }
1358
1359 s = s.boundedTo(r.size());
1360 int x = r.x();
1361 int y = r.y();
1362
1363 if (a & Qt::AlignBottom)
1364 y += (r.height() - s.height());
1365 else if (!(a & Qt::AlignTop))
1366 y += (r.height() - s.height()) / 2;
1367
1368 QWidget *parent = parentWidget();
1369 a = QStyle::visualAlignment(parent ? parent->layoutDirection() : QGuiApplication::layoutDirection(), a);
1370 if (a & Qt::AlignRight)
1371 x += (r.width() - s.width());
1372 else if (!(a & Qt::AlignLeft))
1373 x += (r.width() - s.width()) / 2;
1374
1375 return QRect(x, y, s.width(), s.height());
1376}
1377
1378/*!
1379 Removes the widget \a widget from the layout. After this call, it
1380 is the caller's responsibility to give the widget a reasonable
1381 geometry or to put the widget back into a layout or to explicitly
1382 hide it if necessary.
1383
1384 \b{Note:} The ownership of \a widget remains the same as
1385 when it was added.
1386
1387 \sa removeItem(), QWidget::setGeometry(), addWidget()
1388*/
1389void QLayout::removeWidget(QWidget *widget)
1390{
1391 int i = 0;
1392 QLayoutItem *child;
1393 while ((child = itemAt(i))) {
1394 if (child->widget() == widget) {
1395 delete takeAt(i);
1396 invalidate();
1397 } else {
1398 ++i;
1399 }
1400 }
1401}
1402
1403/*!
1404 Removes the layout item \a item from the layout. It is the
1405 caller's responsibility to delete the item.
1406
1407 Notice that \a item can be a layout (since QLayout inherits
1408 QLayoutItem).
1409
1410 \sa removeWidget(), addItem()
1411*/
1412void QLayout::removeItem(QLayoutItem *item)
1413{
1414 int i = 0;
1415 QLayoutItem *child;
1416 while ((child = itemAt(i))) {
1417 if (child == item) {
1418 takeAt(i);
1419 invalidate();
1420 } else {
1421 ++i;
1422 }
1423 }
1424}
1425
1426/*!
1427 Enables this layout if \a enable is true, otherwise disables it.
1428
1429 An enabled layout adjusts dynamically to changes; a disabled
1430 layout acts as if it did not exist.
1431
1432 By default all layouts are enabled.
1433
1434 \sa isEnabled()
1435*/
1436void QLayout::setEnabled(bool enable)
1437{
1438 Q_D(QLayout);
1439 d->enabled = enable;
1440}
1441
1442/*!
1443 Returns \c true if the layout is enabled; otherwise returns \c false.
1444
1445 \sa setEnabled()
1446*/
1447bool QLayout::isEnabled() const
1448{
1449 Q_D(const QLayout);
1450 return d->enabled;
1451}
1452
1453/*!
1454 Returns a size that satisfies all size constraints on \a widget,
1455 including heightForWidth() and that is as close as possible to \a
1456 size.
1457*/
1458
1459QSize QLayout::closestAcceptableSize(const QWidget *widget, const QSize &size)
1460{
1461 QSize result = size.boundedTo(qSmartMaxSize(widget));
1462 result = result.expandedTo(qSmartMinSize(widget));
1463 QLayout *l = widget->layout();
1464 if (l && l->hasHeightForWidth() && result.height() < l->minimumHeightForWidth(result.width()) ) {
1465 QSize current = widget->size();
1466 int currentHfw = l->minimumHeightForWidth(current.width());
1467 int newHfw = l->minimumHeightForWidth(result.width());
1468 if (current.height() < currentHfw || currentHfw == newHfw) {
1469 //handle the constant hfw case and the vertical-only case, as well as the
1470 // current-size-is-not-correct case
1471 result.setHeight(newHfw);
1472 } else {
1473 // binary search; assume hfw is decreasing ###
1474
1475 int maxw = qMax(widget->width(),result.width());
1476 int maxh = qMax(widget->height(), result.height());
1477 int minw = qMin(widget->width(),result.width());
1478 int minh = qMin(widget->height(), result.height());
1479
1480 int minhfw = l->minimumHeightForWidth(minw);
1481 int maxhfw = l->minimumHeightForWidth(maxw);
1482 while (minw < maxw) {
1483 if (minhfw > maxh) { //assume decreasing
1484 minw = maxw - (maxw-minw)/2;
1485 minhfw = l->minimumHeightForWidth(minw);
1486 } else if (maxhfw < minh ) { //assume decreasing
1487 maxw = minw + (maxw-minw)/2;
1488 maxhfw = l->minimumHeightForWidth(maxw);
1489 } else {
1490 break;
1491 }
1492 }
1493 result = result.expandedTo(QSize(minw, minhfw));
1494 }
1495 }
1496 return result;
1497}
1498
1499QT_END_NAMESPACE
1500
1501#include "moc_qlayout.cpp"
1502