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