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 a \c 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/*!
286 \property QLayout::margin
287 \brief the width of the outside border of the layout
288 \obsolete
289
290 Use setContentsMargins() and getContentsMargins() instead.
291
292 \sa contentsRect(), spacing
293*/
294
295/*!
296 \obsolete
297*/
298int QLayout::margin() const
299{
300 int left, top, right, bottom;
301 getContentsMargins(&left, &top, &right, &bottom);
302 if (left == top && top == right && right == bottom) {
303 return left;
304 } else {
305 return -1;
306 }
307}
308
309/*!
310 \property QLayout::spacing
311 \brief the spacing between widgets inside the layout
312
313 If no value is explicitly set, the layout's spacing is inherited
314 from the parent layout, or from the style settings for the parent
315 widget.
316
317 For QGridLayout and QFormLayout, it is possible to set different horizontal and
318 vertical spacings using \l{QGridLayout::}{setHorizontalSpacing()}
319 and \l{QGridLayout::}{setVerticalSpacing()}. In that case,
320 spacing() returns -1.
321
322 \sa contentsRect(), getContentsMargins(), QStyle::layoutSpacing(),
323 QStyle::pixelMetric()
324*/
325
326int QLayout::spacing() const
327{
328 if (const QBoxLayout* boxlayout = qobject_cast<const QBoxLayout*>(this)) {
329 return boxlayout->spacing();
330 } else if (const QGridLayout* gridlayout = qobject_cast<const QGridLayout*>(this)) {
331 return gridlayout->spacing();
332#if QT_CONFIG(formlayout)
333 } else if (const QFormLayout* formlayout = qobject_cast<const QFormLayout*>(this)) {
334 return formlayout->spacing();
335#endif
336 } else {
337 Q_D(const QLayout);
338 if (d->insideSpacing >=0) {
339 return d->insideSpacing;
340 } else {
341 // arbitrarily prefer horizontal spacing to vertical spacing
342 return qSmartSpacing(this, QStyle::PM_LayoutHorizontalSpacing);
343 }
344 }
345}
346
347/*!
348 \obsolete
349*/
350void QLayout::setMargin(int margin)
351{
352 setContentsMargins(margin, margin, margin, margin);
353}
354
355void QLayout::setSpacing(int spacing)
356{
357 if (QBoxLayout* boxlayout = qobject_cast<QBoxLayout*>(this)) {
358 boxlayout->setSpacing(spacing);
359 } else if (QGridLayout* gridlayout = qobject_cast<QGridLayout*>(this)) {
360 gridlayout->setSpacing(spacing);
361#if QT_CONFIG(formlayout)
362 } else if (QFormLayout* formlayout = qobject_cast<QFormLayout*>(this)) {
363 formlayout->setSpacing(spacing);
364#endif
365 } else {
366 Q_D(QLayout);
367 d->insideSpacing = spacing;
368 invalidate();
369 }
370}
371
372/*!
373 \since 4.3
374
375 Sets the \a left, \a top, \a right, and \a bottom margins to use
376 around the layout.
377
378 By default, QLayout uses the values provided by the style. On
379 most platforms, the margin is 11 pixels in all directions.
380
381 \sa getContentsMargins(), QStyle::pixelMetric(),
382 {QStyle::}{PM_LayoutLeftMargin},
383 {QStyle::}{PM_LayoutTopMargin},
384 {QStyle::}{PM_LayoutRightMargin},
385 {QStyle::}{PM_LayoutBottomMargin}
386*/
387void QLayout::setContentsMargins(int left, int top, int right, int bottom)
388{
389 Q_D(QLayout);
390
391 if (d->userLeftMargin == left && d->userTopMargin == top &&
392 d->userRightMargin == right && d->userBottomMargin == bottom)
393 return;
394
395 d->userLeftMargin = left;
396 d->userTopMargin = top;
397 d->userRightMargin = right;
398 d->userBottomMargin = bottom;
399 invalidate();
400}
401
402/*!
403 \since 4.6
404
405 Sets the \a margins to use around the layout.
406
407 By default, QLayout uses the values provided by the style. On
408 most platforms, the margin is 11 pixels in all directions.
409
410 \sa contentsMargins()
411*/
412void QLayout::setContentsMargins(const QMargins &margins)
413{
414 setContentsMargins(margins.left(), margins.top(), margins.right(), margins.bottom());
415}
416
417/*!
418 \since 4.3
419
420 Extracts the left, top, right, and bottom margins used around the
421 layout, and assigns them to *\a left, *\a top, *\a right, and *\a
422 bottom (unless they are null pointers).
423
424 By default, QLayout uses the values provided by the style. On
425 most platforms, the margin is 11 pixels in all directions.
426
427 \sa setContentsMargins(), QStyle::pixelMetric(),
428 {QStyle::}{PM_LayoutLeftMargin},
429 {QStyle::}{PM_LayoutTopMargin},
430 {QStyle::}{PM_LayoutRightMargin},
431 {QStyle::}{PM_LayoutBottomMargin}
432*/
433void QLayout::getContentsMargins(int *left, int *top, int *right, int *bottom) const
434{
435 Q_D(const QLayout);
436 d->getMargin(left, d->userLeftMargin, QStyle::PM_LayoutLeftMargin);
437 d->getMargin(top, d->userTopMargin, QStyle::PM_LayoutTopMargin);
438 d->getMargin(right, d->userRightMargin, QStyle::PM_LayoutRightMargin);
439 d->getMargin(bottom, d->userBottomMargin, QStyle::PM_LayoutBottomMargin);
440}
441
442/*!
443 \since 4.6
444
445 Returns the margins used around the layout.
446
447 By default, QLayout uses the values provided by the style. On
448 most platforms, the margin is 11 pixels in all directions.
449
450 \sa setContentsMargins()
451*/
452QMargins QLayout::contentsMargins() const
453{
454 int left, top, right, bottom;
455 getContentsMargins(&left, &top, &right, &bottom);
456 return QMargins(left, top, right, bottom);
457}
458
459/*!
460 \since 4.3
461
462 Returns the layout's geometry() rectangle, but taking into account the
463 contents margins.
464
465 \sa setContentsMargins(), getContentsMargins()
466*/
467QRect QLayout::contentsRect() const
468{
469 Q_D(const QLayout);
470 int left, top, right, bottom;
471 getContentsMargins(&left, &top, &right, &bottom);
472 return d->rect.adjusted(+left, +top, -right, -bottom);
473}
474
475
476/*!
477 Returns the parent widget of this layout, or \nullptr if this
478 layout is not installed on any widget.
479
480 If the layout is a sub-layout, this function returns the parent
481 widget of the parent layout.
482
483 \sa parent()
484*/
485QWidget *QLayout::parentWidget() const
486{
487 Q_D(const QLayout);
488 if (!d->topLevel) {
489 if (parent()) {
490 QLayout *parentLayout = qobject_cast<QLayout*>(parent());
491 if (Q_UNLIKELY(!parentLayout)) {
492 qWarning("QLayout::parentWidget: A layout can only have another layout as a parent.");
493 return nullptr;
494 }
495 return parentLayout->parentWidget();
496 } else {
497 return nullptr;
498 }
499 } else {
500 Q_ASSERT(parent() && parent()->isWidgetType());
501 return static_cast<QWidget *>(parent());
502 }
503}
504
505/*!
506 \reimp
507*/
508bool QLayout::isEmpty() const
509{
510 int i = 0;
511 QLayoutItem *item = itemAt(i);
512 while (item) {
513 if (!item->isEmpty())
514 return false;
515 ++i;
516 item = itemAt(i);
517 }
518 return true;
519}
520
521/*!
522 \reimp
523*/
524QSizePolicy::ControlTypes QLayout::controlTypes() const
525{
526 if (count() == 0)
527 return QSizePolicy::DefaultType;
528 QSizePolicy::ControlTypes types;
529 for (int i = count() - 1; i >= 0; --i)
530 types |= itemAt(i)->controlTypes();
531 return types;
532}
533
534/*!
535 \reimp
536*/
537void QLayout::setGeometry(const QRect &r)
538{
539 Q_D(QLayout);
540 d->rect = r;
541}
542
543/*!
544 \reimp
545*/
546QRect QLayout::geometry() const
547{
548 Q_D(const QLayout);
549 return d->rect;
550}
551
552/*!
553 \reimp
554*/
555void QLayout::invalidate()
556{
557 Q_D(QLayout);
558 d->rect = QRect();
559 update();
560}
561
562static bool removeWidgetRecursively(QLayoutItem *li, QObject *w)
563{
564 QLayout *lay = li->layout();
565 if (!lay)
566 return false;
567 int i = 0;
568 QLayoutItem *child;
569 while ((child = lay->itemAt(i))) {
570 if (child->widget() == w) {
571 delete lay->takeAt(i);
572 lay->invalidate();
573 return true;
574 } else if (removeWidgetRecursively(child, w)) {
575 return true;
576 } else {
577 ++i;
578 }
579 }
580 return false;
581}
582
583
584void QLayoutPrivate::doResize(const QSize &r)
585{
586 Q_Q(QLayout);
587 int mbh = menuBarHeightForWidth(menubar, r.width());
588 QWidget *mw = q->parentWidget();
589 QRect rect = mw->testAttribute(Qt::WA_LayoutOnEntireRect) ? mw->rect() : mw->contentsRect();
590 const int mbTop = rect.top();
591 rect.setTop(mbTop + mbh);
592 q->setGeometry(rect);
593#if QT_CONFIG(menubar)
594 if (menubar)
595 menubar->setGeometry(rect.left(), mbTop, r.width(), mbh);
596#endif
597}
598
599
600/*!
601 \internal
602 Performs child widget layout when the parent widget is
603 resized. Also handles removal of widgets. \a e is the
604 event
605*/
606void QLayout::widgetEvent(QEvent *e)
607{
608 Q_D(QLayout);
609 if (!d->enabled)
610 return;
611
612 switch (e->type()) {
613 case QEvent::Resize:
614 if (d->activated) {
615 QResizeEvent *r = (QResizeEvent *)e;
616 d->doResize(r->size());
617 } else {
618 activate();
619 }
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 = 0;
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*/
645void 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*/
662int 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*/
684QSize 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*/
707QSize 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*/
732QSize 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*/
763QLayout::~QLayout()
764{
765 Q_D(QLayout);
766 if (d->topLevel && parent() && parent()->isWidgetType() && parentWidget()->layout() == this)
767 parentWidget()->d_func()->layout = 0;
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*/
782void 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 */
800bool QLayout::adoptLayout(QLayout *layout)
801{
802 const bool ok = !layout->parent();
803 addChildLayout(layout);
804 return ok;
805}
806
807#ifdef QT_DEBUG
808static 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
818void 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*/
854bool 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*/
875bool 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*/
899void 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 = 0;
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*/
944void 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
957QWidget *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*/
974QSize 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*/
989QSize 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*/
1006Qt::Orientations QLayout::expandingDirections() const
1007{
1008 return Qt::Horizontal | Qt::Vertical;
1009}
1010
1011void 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
1033void 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 QApplication::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*/
1057bool 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(mw->size());
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
1152QLayoutItem *QLayout::replaceWidget(QWidget *from, QWidget *to, Qt::FindChildOptions options)
1153{
1154 Q_D(QLayout);
1155 if (!from || !to)
1156 return 0;
1157
1158 int index = -1;
1159 QLayoutItem *item = 0;
1160 for (int u = 0; u < count(); ++u) {
1161 item = itemAt(u);
1162 if (!item)
1163 continue;
1164
1165 if (item->widget() == from) {
1166 index = u;
1167 break;
1168 }
1169
1170 if (item->layout() && (options & Qt::FindChildrenRecursively)) {
1171 QLayoutItem *r = item->layout()->replaceWidget(from, to, options);
1172 if (r)
1173 return r;
1174 }
1175 }
1176 if (index == -1)
1177 return 0;
1178
1179 addChildWidget(to);
1180 QLayoutItem *newitem = new QWidgetItem(to);
1181 newitem->setAlignment(item->alignment());
1182 QLayoutItem *r = d->replaceAt(index, newitem);
1183 if (!r)
1184 delete newitem;
1185 return r;
1186}
1187
1188/*!
1189 \fn QLayoutItem *QLayout::itemAt(int index) const
1190
1191 Must be implemented in subclasses to return the layout item at \a
1192 index. If there is no such item, the function must return 0.
1193 Items are numbered consecutively from 0. If an item is deleted, other items will be renumbered.
1194
1195 This function can be used to iterate over a layout. The following
1196 code will draw a rectangle for each layout item in the layout structure of the widget.
1197
1198 \snippet code/src_gui_kernel_qlayout.cpp 0
1199
1200 \sa count(), takeAt()
1201*/
1202
1203/*!
1204 \fn QLayoutItem *QLayout::takeAt(int index)
1205
1206 Must be implemented in subclasses to remove the layout item at \a
1207 index from the layout, and return the item. If there is no such
1208 item, the function must do nothing and return 0. Items are numbered
1209 consecutively from 0. If an item is removed, other items will be
1210 renumbered.
1211
1212 The following code fragment shows a safe way to remove all items
1213 from a layout:
1214
1215 \snippet code/src_gui_kernel_qlayout.cpp 1
1216
1217 \sa itemAt(), count()
1218*/
1219
1220/*!
1221 \fn int *QLayout::count() const
1222
1223 Must be implemented in subclasses to return the number of items
1224 in the layout.
1225
1226 \sa itemAt()
1227*/
1228
1229/*!
1230 Searches for widget \a widget in this layout (not including child
1231 layouts).
1232
1233 Returns the index of \a widget, or -1 if \a widget is not found.
1234
1235 The default implementation iterates over all items using itemAt()
1236*/
1237int QLayout::indexOf(QWidget *widget) const
1238{
1239 int i = 0;
1240 QLayoutItem *item = itemAt(i);
1241 while (item) {
1242 if (item->widget() == widget)
1243 return i;
1244 ++i;
1245 item = itemAt(i);
1246 }
1247 return -1;
1248}
1249
1250/*!
1251 \since 5.12
1252 Searches for layout item \a layoutItem in this layout (not including child
1253 layouts).
1254
1255 Returns the index of \a layoutItem, or -1 if \a layoutItem is not found.
1256*/
1257int QLayout::indexOf(QLayoutItem *layoutItem) const
1258{
1259 int i = 0;
1260 QLayoutItem *item = itemAt(i);
1261 while (item) {
1262 if (item == layoutItem)
1263 return i;
1264 ++i;
1265 item = itemAt(i);
1266 }
1267 return -1;
1268}
1269
1270/*!
1271 \enum QLayout::SizeConstraint
1272
1273 The possible values are:
1274
1275 \value SetDefaultConstraint The main widget's minimum size is set
1276 to minimumSize(), unless the widget already has
1277 a minimum size.
1278
1279 \value SetFixedSize The main widget's size is set to sizeHint(); it
1280 cannot be resized at all.
1281 \value SetMinimumSize The main widget's minimum size is set to
1282 minimumSize(); it cannot be smaller.
1283
1284 \value SetMaximumSize The main widget's maximum size is set to
1285 maximumSize(); it cannot be larger.
1286
1287 \value SetMinAndMaxSize The main widget's minimum size is set to
1288 minimumSize() and its maximum size is set to
1289 maximumSize().
1290
1291 \value SetNoConstraint The widget is not constrained.
1292
1293 \sa setSizeConstraint()
1294*/
1295
1296/*!
1297 \property QLayout::sizeConstraint
1298 \brief the resize mode of the layout
1299
1300 The default mode is \l {QLayout::SetDefaultConstraint}
1301 {SetDefaultConstraint}.
1302*/
1303void QLayout::setSizeConstraint(SizeConstraint constraint)
1304{
1305 Q_D(QLayout);
1306 if (constraint == d->constraint)
1307 return;
1308
1309 d->constraint = constraint;
1310 invalidate();
1311}
1312
1313QLayout::SizeConstraint QLayout::sizeConstraint() const
1314{
1315 Q_D(const QLayout);
1316 return d->constraint;
1317}
1318
1319/*!
1320 Returns the rectangle that should be covered when the geometry of
1321 this layout is set to \a r, provided that this layout supports
1322 setAlignment().
1323
1324 The result is derived from sizeHint() and expanding(). It is never
1325 larger than \a r.
1326*/
1327QRect QLayout::alignmentRect(const QRect &r) const
1328{
1329 QSize s = sizeHint();
1330 Qt::Alignment a = alignment();
1331
1332 /*
1333 This is a hack to obtain the real maximum size, not
1334 QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX), the value consistently
1335 returned by QLayoutItems that have an alignment.
1336 */
1337 QLayout *that = const_cast<QLayout *>(this);
1338 that->setAlignment(0);
1339 QSize ms = that->maximumSize();
1340 that->setAlignment(a);
1341
1342 if ((expandingDirections() & Qt::Horizontal) ||
1343 !(a & Qt::AlignHorizontal_Mask)) {
1344 s.setWidth(qMin(r.width(), ms.width()));
1345 }
1346 if ((expandingDirections() & Qt::Vertical) ||
1347 !(a & Qt::AlignVertical_Mask)) {
1348 s.setHeight(qMin(r.height(), ms.height()));
1349 } else if (hasHeightForWidth()) {
1350 int hfw = heightForWidth(s.width());
1351 if (hfw < s.height())
1352 s.setHeight(qMin(hfw, ms.height()));
1353 }
1354
1355 s = s.boundedTo(r.size());
1356 int x = r.x();
1357 int y = r.y();
1358
1359 if (a & Qt::AlignBottom)
1360 y += (r.height() - s.height());
1361 else if (!(a & Qt::AlignTop))
1362 y += (r.height() - s.height()) / 2;
1363
1364 QWidget *parent = parentWidget();
1365 a = QStyle::visualAlignment(parent ? parent->layoutDirection() : QApplication::layoutDirection(), a);
1366 if (a & Qt::AlignRight)
1367 x += (r.width() - s.width());
1368 else if (!(a & Qt::AlignLeft))
1369 x += (r.width() - s.width()) / 2;
1370
1371 return QRect(x, y, s.width(), s.height());
1372}
1373
1374/*!
1375 Removes the widget \a widget from the layout. After this call, it
1376 is the caller's responsibility to give the widget a reasonable
1377 geometry or to put the widget back into a layout or to explicitly
1378 hide it if necessary.
1379
1380 \b{Note:} The ownership of \a widget remains the same as
1381 when it was added.
1382
1383 \sa removeItem(), QWidget::setGeometry(), addWidget()
1384*/
1385void QLayout::removeWidget(QWidget *widget)
1386{
1387 int i = 0;
1388 QLayoutItem *child;
1389 while ((child = itemAt(i))) {
1390 if (child->widget() == widget) {
1391 delete takeAt(i);
1392 invalidate();
1393 } else {
1394 ++i;
1395 }
1396 }
1397}
1398
1399/*!
1400 Removes the layout item \a item from the layout. It is the
1401 caller's responsibility to delete the item.
1402
1403 Notice that \a item can be a layout (since QLayout inherits
1404 QLayoutItem).
1405
1406 \sa removeWidget(), addItem()
1407*/
1408void QLayout::removeItem(QLayoutItem *item)
1409{
1410 int i = 0;
1411 QLayoutItem *child;
1412 while ((child = itemAt(i))) {
1413 if (child == item) {
1414 takeAt(i);
1415 invalidate();
1416 } else {
1417 ++i;
1418 }
1419 }
1420}
1421
1422/*!
1423 Enables this layout if \a enable is true, otherwise disables it.
1424
1425 An enabled layout adjusts dynamically to changes; a disabled
1426 layout acts as if it did not exist.
1427
1428 By default all layouts are enabled.
1429
1430 \sa isEnabled()
1431*/
1432void QLayout::setEnabled(bool enable)
1433{
1434 Q_D(QLayout);
1435 d->enabled = enable;
1436}
1437
1438/*!
1439 Returns \c true if the layout is enabled; otherwise returns \c false.
1440
1441 \sa setEnabled()
1442*/
1443bool QLayout::isEnabled() const
1444{
1445 Q_D(const QLayout);
1446 return d->enabled;
1447}
1448
1449/*!
1450 Returns a size that satisfies all size constraints on \a widget,
1451 including heightForWidth() and that is as close as possible to \a
1452 size.
1453*/
1454
1455QSize QLayout::closestAcceptableSize(const QWidget *widget, const QSize &size)
1456{
1457 QSize result = size.boundedTo(qSmartMaxSize(widget));
1458 result = result.expandedTo(qSmartMinSize(widget));
1459 QLayout *l = widget->layout();
1460 if (l && l->hasHeightForWidth() && result.height() < l->minimumHeightForWidth(result.width()) ) {
1461 QSize current = widget->size();
1462 int currentHfw = l->minimumHeightForWidth(current.width());
1463 int newHfw = l->minimumHeightForWidth(result.width());
1464 if (current.height() < currentHfw || currentHfw == newHfw) {
1465 //handle the constant hfw case and the vertical-only case, as well as the
1466 // current-size-is-not-correct case
1467 result.setHeight(newHfw);
1468 } else {
1469 // binary search; assume hfw is decreasing ###
1470
1471 int maxw = qMax(widget->width(),result.width());
1472 int maxh = qMax(widget->height(), result.height());
1473 int minw = qMin(widget->width(),result.width());
1474 int minh = qMin(widget->height(), result.height());
1475
1476 int minhfw = l->minimumHeightForWidth(minw);
1477 int maxhfw = l->minimumHeightForWidth(maxw);
1478 while (minw < maxw) {
1479 if (minhfw > maxh) { //assume decreasing
1480 minw = maxw - (maxw-minw)/2;
1481 minhfw = l->minimumHeightForWidth(minw);
1482 } else if (maxhfw < minh ) { //assume decreasing
1483 maxw = minw + (maxw-minw)/2;
1484 maxhfw = l->minimumHeightForWidth(maxw);
1485 } else {
1486 break;
1487 }
1488 }
1489 result = result.expandedTo(QSize(minw, minhfw));
1490 }
1491 }
1492 return result;
1493}
1494
1495QT_END_NAMESPACE
1496
1497#include "moc_qlayout.cpp"
1498