1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtWidgets module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #include "qlayout.h" |
41 | |
42 | #include "qapplication.h" |
43 | #include "qlayoutengine_p.h" |
44 | #if QT_CONFIG(menubar) |
45 | #include "qmenubar.h" |
46 | #endif |
47 | #if QT_CONFIG(toolbar) |
48 | #include "qtoolbar.h" |
49 | #endif |
50 | #if QT_CONFIG(sizegrip) |
51 | #include "qsizegrip.h" |
52 | #endif |
53 | #include "qevent.h" |
54 | #include "qstyle.h" |
55 | #include "qvariant.h" |
56 | #include "qwidget_p.h" |
57 | #include "qlayout_p.h" |
58 | #if QT_CONFIG(formlayout) |
59 | #include "qformlayout.h" |
60 | #endif |
61 | |
62 | QT_BEGIN_NAMESPACE |
63 | |
64 | static int (QWidget *, int w) |
65 | { |
66 | if (menubar && !menubar->isHidden() && !menubar->isWindow()) { |
67 | int result = menubar->heightForWidth(qMax(a: w, b: menubar->minimumWidth())); |
68 | if (result == -1) |
69 | result = menubar->sizeHint().height(); |
70 | const int min = qSmartMinSize(w: menubar).height(); |
71 | result = qBound(min, val: result, max: 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 | */ |
118 | QLayout::QLayout(QWidget *parent) |
119 | : QObject(*new QLayoutPrivate, parent) |
120 | { |
121 | if (!parent) |
122 | return; |
123 | parent->setLayout(this); |
124 | } |
125 | |
126 | /*! |
127 | Constructs a new child QLayout. |
128 | |
129 | This layout has to be inserted into another layout before geometry |
130 | management will work. |
131 | */ |
132 | QLayout::QLayout() |
133 | : QObject(*new QLayoutPrivate, nullptr) |
134 | { |
135 | } |
136 | |
137 | |
138 | /*! \internal |
139 | */ |
140 | QLayout::QLayout(QLayoutPrivate &dd, QLayout *lay, QWidget *w) |
141 | : QObject(dd, lay ? static_cast<QObject*>(lay) : static_cast<QObject*>(w)) |
142 | { |
143 | Q_D(QLayout); |
144 | if (lay) { |
145 | lay->addItem(this); |
146 | } else if (w) { |
147 | if (Q_UNLIKELY(w->layout())) { |
148 | qWarning(msg: "QLayout: Attempting to add QLayout \"%ls\" to %s \"%ls\", which" |
149 | " already has a layout" , |
150 | qUtf16Printable(QObject::objectName()), w->metaObject()->className(), |
151 | qUtf16Printable(w->objectName())); |
152 | setParent(nullptr); |
153 | } else { |
154 | d->topLevel = true; |
155 | w->d_func()->layout = this; |
156 | QT_TRY { |
157 | invalidate(); |
158 | } QT_CATCH(...) { |
159 | w->d_func()->layout = nullptr; |
160 | QT_RETHROW; |
161 | } |
162 | } |
163 | } |
164 | } |
165 | |
166 | QLayoutPrivate::QLayoutPrivate() |
167 | : QObjectPrivate(), insideSpacing(-1), userLeftMargin(-1), userTopMargin(-1), userRightMargin(-1), |
168 | userBottomMargin(-1), topLevel(false), enabled(true), activated(true), autoNewChild(false), |
169 | constraint(QLayout::SetDefaultConstraint), menubar(nullptr) |
170 | { |
171 | } |
172 | |
173 | void QLayoutPrivate::getMargin(int *result, int userMargin, QStyle::PixelMetric pm) const |
174 | { |
175 | if (!result) |
176 | return; |
177 | |
178 | Q_Q(const QLayout); |
179 | if (userMargin >= 0) { |
180 | *result = userMargin; |
181 | } else if (!topLevel) { |
182 | *result = 0; |
183 | } else if (QWidget *pw = q->parentWidget()) { |
184 | *result = pw->style()->pixelMetric(metric: pm, option: nullptr, widget: pw); |
185 | } else { |
186 | *result = 0; |
187 | } |
188 | } |
189 | |
190 | // Static item factory functions that allow for hooking things in Designer |
191 | |
192 | QLayoutPrivate::QWidgetItemFactoryMethod QLayoutPrivate::widgetItemFactoryMethod = nullptr; |
193 | QLayoutPrivate::QSpacerItemFactoryMethod QLayoutPrivate::spacerItemFactoryMethod = nullptr; |
194 | |
195 | QWidgetItem *QLayoutPrivate::createWidgetItem(const QLayout *layout, QWidget *widget) |
196 | { |
197 | if (widgetItemFactoryMethod) |
198 | if (QWidgetItem *wi = (*widgetItemFactoryMethod)(layout, widget)) |
199 | return wi; |
200 | return new QWidgetItemV2(widget); |
201 | } |
202 | |
203 | QSpacerItem *QLayoutPrivate::createSpacerItem(const QLayout *layout, int w, int h, QSizePolicy::Policy hPolicy, QSizePolicy::Policy vPolicy) |
204 | { |
205 | if (spacerItemFactoryMethod) |
206 | if (QSpacerItem *si = (*spacerItemFactoryMethod)(layout, w, h, hPolicy, vPolicy)) |
207 | return si; |
208 | return new QSpacerItem(w, h, hPolicy, vPolicy); |
209 | } |
210 | |
211 | |
212 | |
213 | /*! |
214 | \fn void QLayout::addItem(QLayoutItem *item) |
215 | |
216 | Implemented in subclasses to add an \a item. How it is added is |
217 | specific to each subclass. |
218 | |
219 | This function is not usually called in application code. To add a widget |
220 | to a layout, use the addWidget() function; to add a child layout, use the |
221 | addLayout() function provided by the relevant QLayout subclass. |
222 | |
223 | \b{Note:} The ownership of \a item is transferred to the layout, and it's |
224 | the layout's responsibility to delete it. |
225 | |
226 | \sa addWidget(), QBoxLayout::addLayout(), QGridLayout::addLayout() |
227 | */ |
228 | |
229 | /*! |
230 | Adds widget \a w to this layout in a manner specific to the |
231 | layout. This function uses addItem(). |
232 | */ |
233 | void QLayout::addWidget(QWidget *w) |
234 | { |
235 | addChildWidget(w); |
236 | addItem(QLayoutPrivate::createWidgetItem(layout: this, widget: 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 | */ |
246 | bool QLayout::setAlignment(QWidget *w, Qt::Alignment alignment) |
247 | { |
248 | int i = 0; |
249 | QLayoutItem *item = itemAt(index: i); |
250 | while (item) { |
251 | if (item->widget() == w) { |
252 | item->setAlignment(alignment); |
253 | invalidate(); |
254 | return true; |
255 | } |
256 | ++i; |
257 | item = itemAt(index: 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 | */ |
269 | bool QLayout::setAlignment(QLayout *l, Qt::Alignment alignment) |
270 | { |
271 | int i = 0; |
272 | QLayoutItem *item = itemAt(index: i); |
273 | while (item) { |
274 | if (item->layout() == l) { |
275 | item->setAlignment(alignment); |
276 | invalidate(); |
277 | return true; |
278 | } |
279 | ++i; |
280 | item = itemAt(index: 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 | */ |
299 | int QLayout::margin() const |
300 | { |
301 | int left, top, right, bottom; |
302 | getContentsMargins(left: &left, top: &top, right: &right, bottom: &bottom); |
303 | if (left == top && top == right && right == bottom) { |
304 | return left; |
305 | } else { |
306 | return -1; |
307 | } |
308 | } |
309 | |
310 | /*! |
311 | \obsolete |
312 | */ |
313 | void QLayout::setMargin(int margin) |
314 | { |
315 | setContentsMargins(left: margin, top: margin, right: margin, bottom: 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 | |
336 | int QLayout::spacing() const |
337 | { |
338 | if (const QBoxLayout* boxlayout = qobject_cast<const QBoxLayout*>(object: this)) { |
339 | return boxlayout->spacing(); |
340 | } else if (const QGridLayout* gridlayout = qobject_cast<const QGridLayout*>(object: this)) { |
341 | return gridlayout->spacing(); |
342 | #if QT_CONFIG(formlayout) |
343 | } else if (const QFormLayout* formlayout = qobject_cast<const QFormLayout*>(object: 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(layout: this, pm: QStyle::PM_LayoutHorizontalSpacing); |
353 | } |
354 | } |
355 | } |
356 | |
357 | void QLayout::setSpacing(int spacing) |
358 | { |
359 | if (QBoxLayout* boxlayout = qobject_cast<QBoxLayout*>(object: this)) { |
360 | boxlayout->setSpacing(spacing); |
361 | } else if (QGridLayout* gridlayout = qobject_cast<QGridLayout*>(object: this)) { |
362 | gridlayout->setSpacing(spacing); |
363 | #if QT_CONFIG(formlayout) |
364 | } else if (QFormLayout* formlayout = qobject_cast<QFormLayout*>(object: 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 | */ |
389 | void QLayout::setContentsMargins(int left, int top, int right, int bottom) |
390 | { |
391 | Q_D(QLayout); |
392 | |
393 | if (d->userLeftMargin == left && d->userTopMargin == top && |
394 | d->userRightMargin == right && d->userBottomMargin == bottom) |
395 | return; |
396 | |
397 | d->userLeftMargin = left; |
398 | d->userTopMargin = top; |
399 | d->userRightMargin = right; |
400 | d->userBottomMargin = bottom; |
401 | invalidate(); |
402 | } |
403 | |
404 | /*! |
405 | \since 4.6 |
406 | |
407 | Sets the \a margins to use around the layout. |
408 | |
409 | By default, QLayout uses the values provided by the style. On |
410 | most platforms, the margin is 11 pixels in all directions. |
411 | |
412 | \sa contentsMargins() |
413 | */ |
414 | void QLayout::setContentsMargins(const QMargins &margins) |
415 | { |
416 | setContentsMargins(left: margins.left(), top: margins.top(), right: margins.right(), bottom: 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 | */ |
435 | void QLayout::getContentsMargins(int *left, int *top, int *right, int *bottom) const |
436 | { |
437 | Q_D(const QLayout); |
438 | d->getMargin(result: left, userMargin: d->userLeftMargin, pm: QStyle::PM_LayoutLeftMargin); |
439 | d->getMargin(result: top, userMargin: d->userTopMargin, pm: QStyle::PM_LayoutTopMargin); |
440 | d->getMargin(result: right, userMargin: d->userRightMargin, pm: QStyle::PM_LayoutRightMargin); |
441 | d->getMargin(result: bottom, userMargin: d->userBottomMargin, pm: 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 | */ |
454 | QMargins QLayout::contentsMargins() const |
455 | { |
456 | int left, top, right, bottom; |
457 | getContentsMargins(left: &left, top: &top, right: &right, bottom: &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 | */ |
469 | QRect QLayout::contentsRect() const |
470 | { |
471 | Q_D(const QLayout); |
472 | int left, top, right, bottom; |
473 | getContentsMargins(left: &left, top: &top, right: &right, bottom: &bottom); |
474 | return d->rect.adjusted(xp1: +left, yp1: +top, xp2: -right, yp2: -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 | */ |
487 | QWidget *QLayout::parentWidget() const |
488 | { |
489 | Q_D(const QLayout); |
490 | if (!d->topLevel) { |
491 | if (parent()) { |
492 | QLayout *parentLayout = qobject_cast<QLayout*>(object: parent()); |
493 | if (Q_UNLIKELY(!parentLayout)) { |
494 | qWarning(msg: "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 | */ |
510 | bool QLayout::isEmpty() const |
511 | { |
512 | int i = 0; |
513 | QLayoutItem *item = itemAt(index: i); |
514 | while (item) { |
515 | if (!item->isEmpty()) |
516 | return false; |
517 | ++i; |
518 | item = itemAt(index: i); |
519 | } |
520 | return true; |
521 | } |
522 | |
523 | /*! |
524 | \reimp |
525 | */ |
526 | QSizePolicy::ControlTypes QLayout::controlTypes() const |
527 | { |
528 | if (count() == 0) |
529 | return QSizePolicy::DefaultType; |
530 | QSizePolicy::ControlTypes types; |
531 | for (int i = count() - 1; i >= 0; --i) |
532 | types |= itemAt(index: i)->controlTypes(); |
533 | return types; |
534 | } |
535 | |
536 | /*! |
537 | \reimp |
538 | */ |
539 | void QLayout::setGeometry(const QRect &r) |
540 | { |
541 | Q_D(QLayout); |
542 | d->rect = r; |
543 | } |
544 | |
545 | /*! |
546 | \reimp |
547 | */ |
548 | QRect QLayout::geometry() const |
549 | { |
550 | Q_D(const QLayout); |
551 | return d->rect; |
552 | } |
553 | |
554 | /*! |
555 | \reimp |
556 | */ |
557 | void QLayout::invalidate() |
558 | { |
559 | Q_D(QLayout); |
560 | d->rect = QRect(); |
561 | update(); |
562 | } |
563 | |
564 | static bool removeWidgetRecursively(QLayoutItem *li, QObject *w) |
565 | { |
566 | QLayout *lay = li->layout(); |
567 | if (!lay) |
568 | return false; |
569 | int i = 0; |
570 | QLayoutItem *child; |
571 | while ((child = lay->itemAt(index: i))) { |
572 | if (child->widget() == w) { |
573 | delete lay->takeAt(index: i); |
574 | lay->invalidate(); |
575 | return true; |
576 | } else if (removeWidgetRecursively(li: child, w)) { |
577 | return true; |
578 | } else { |
579 | ++i; |
580 | } |
581 | } |
582 | return false; |
583 | } |
584 | |
585 | |
586 | void QLayoutPrivate::doResize() |
587 | { |
588 | Q_Q(QLayout); |
589 | QWidget *mw = q->parentWidget(); |
590 | QRect rect = mw->testAttribute(attribute: Qt::WA_LayoutOnEntireRect) ? mw->rect() : mw->contentsRect(); |
591 | const int mbh = menuBarHeightForWidth(menubar, w: rect.width()); |
592 | const int mbTop = rect.top(); |
593 | rect.setTop(mbTop + mbh); |
594 | q->setGeometry(rect); |
595 | #if QT_CONFIG(menubar) |
596 | if (menubar) |
597 | menubar->setGeometry(ax: rect.left(), ay: mbTop, aw: rect.width(), ah: 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 | */ |
608 | void QLayout::widgetEvent(QEvent *e) |
609 | { |
610 | Q_D(QLayout); |
611 | if (!d->enabled) |
612 | return; |
613 | |
614 | switch (e->type()) { |
615 | case QEvent::Resize: |
616 | if (d->activated) |
617 | d->doResize(); |
618 | else |
619 | activate(); |
620 | break; |
621 | case QEvent::ChildRemoved: |
622 | { |
623 | QChildEvent *c = (QChildEvent *)e; |
624 | if (c->child()->isWidgetType()) { |
625 | #if QT_CONFIG(menubar) |
626 | if (c->child() == d->menubar) |
627 | d->menubar = nullptr; |
628 | #endif |
629 | removeWidgetRecursively(li: this, w: 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 | */ |
645 | void QLayout::childEvent(QChildEvent *e) |
646 | { |
647 | Q_D(QLayout); |
648 | if (!d->enabled) |
649 | return; |
650 | |
651 | if (e->type() != QEvent::ChildRemoved) |
652 | return; |
653 | |
654 | if (QLayout *childLayout = qobject_cast<QLayout *>(object: e->child())) |
655 | removeItem(childLayout); |
656 | } |
657 | |
658 | /*! |
659 | \internal |
660 | Also takes contentsMargins and menu bar into account. |
661 | */ |
662 | int QLayout::totalHeightForWidth(int w) const |
663 | { |
664 | Q_D(const QLayout); |
665 | int side=0, top=0; |
666 | if (d->topLevel) { |
667 | QWidget *parent = parentWidget(); |
668 | parent->ensurePolished(); |
669 | QWidgetPrivate *wd = parent->d_func(); |
670 | side += wd->leftmargin + wd->rightmargin; |
671 | top += wd->topmargin + wd->bottommargin; |
672 | } |
673 | int h = heightForWidth(w - side) + top; |
674 | #if QT_CONFIG(menubar) |
675 | h += menuBarHeightForWidth(menubar: d->menubar, w); |
676 | #endif |
677 | return h; |
678 | } |
679 | |
680 | /*! |
681 | \internal |
682 | Also takes contentsMargins and menu bar into account. |
683 | */ |
684 | QSize QLayout::totalMinimumSize() const |
685 | { |
686 | Q_D(const QLayout); |
687 | int side=0, top=0; |
688 | if (d->topLevel) { |
689 | QWidget *pw = parentWidget(); |
690 | pw->ensurePolished(); |
691 | QWidgetPrivate *wd = pw->d_func(); |
692 | side += wd->leftmargin + wd->rightmargin; |
693 | top += wd->topmargin + wd->bottommargin; |
694 | } |
695 | |
696 | QSize s = minimumSize(); |
697 | #if QT_CONFIG(menubar) |
698 | top += menuBarHeightForWidth(menubar: d->menubar, w: 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 | */ |
707 | QSize QLayout::totalSizeHint() const |
708 | { |
709 | Q_D(const QLayout); |
710 | int side=0, top=0; |
711 | if (d->topLevel) { |
712 | QWidget *pw = parentWidget(); |
713 | pw->ensurePolished(); |
714 | QWidgetPrivate *wd = pw->d_func(); |
715 | side += wd->leftmargin + wd->rightmargin; |
716 | top += wd->topmargin + wd->bottommargin; |
717 | } |
718 | |
719 | QSize s = sizeHint(); |
720 | if (hasHeightForWidth()) |
721 | s.setHeight(heightForWidth(s.width() + side)); |
722 | #if QT_CONFIG(menubar) |
723 | top += menuBarHeightForWidth(menubar: d->menubar, w: 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 | */ |
732 | QSize QLayout::totalMaximumSize() const |
733 | { |
734 | Q_D(const QLayout); |
735 | int side=0, top=0; |
736 | if (d->topLevel) { |
737 | QWidget *pw = parentWidget(); |
738 | pw->ensurePolished(); |
739 | QWidgetPrivate *wd = pw->d_func(); |
740 | side += wd->leftmargin + wd->rightmargin; |
741 | top += wd->topmargin + wd->bottommargin; |
742 | } |
743 | |
744 | QSize s = maximumSize(); |
745 | #if QT_CONFIG(menubar) |
746 | top += menuBarHeightForWidth(menubar: d->menubar, w: s.width()); |
747 | #endif |
748 | |
749 | if (d->topLevel) |
750 | s = QSize(qMin(a: s.width() + side, b: QLAYOUTSIZE_MAX), |
751 | qMin(a: s.height() + top, b: 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 | */ |
763 | QLayout::~QLayout() |
764 | { |
765 | Q_D(QLayout); |
766 | if (d->topLevel && parent() && parent()->isWidgetType() && parentWidget()->layout() == this) |
767 | parentWidget()->d_func()->layout = nullptr; |
768 | else if (QLayout *parentLayout = qobject_cast<QLayout *>(object: 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 | */ |
782 | void QLayout::addChildLayout(QLayout *l) |
783 | { |
784 | if (Q_UNLIKELY(l->parent())) { |
785 | qWarning(msg: "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 | */ |
800 | bool QLayout::adoptLayout(QLayout *layout) |
801 | { |
802 | const bool ok = !layout->parent(); |
803 | addChildLayout(l: layout); |
804 | return ok; |
805 | } |
806 | |
807 | #ifdef QT_DEBUG |
808 | static bool layoutDebug() |
809 | { |
810 | static int checked_env = -1; |
811 | if(checked_env == -1) |
812 | checked_env = !!qEnvironmentVariableIntValue(varName: "QT_LAYOUT_DEBUG" ); |
813 | |
814 | return checked_env; |
815 | } |
816 | #endif |
817 | |
818 | void QLayoutPrivate::reparentChildWidgets(QWidget *mw) |
819 | { |
820 | Q_Q(QLayout); |
821 | int n = q->count(); |
822 | |
823 | #if QT_CONFIG(menubar) |
824 | if (menubar && menubar->parentWidget() != mw) { |
825 | menubar->setParent(mw); |
826 | } |
827 | #endif |
828 | bool mwVisible = mw && mw->isVisible(); |
829 | for (int i = 0; i < n; ++i) { |
830 | QLayoutItem *item = q->itemAt(index: 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(msg: "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(attribute: Qt::WA_WState_ExplicitShowHide)); |
840 | if (pw != mw) |
841 | w->setParent(mw); |
842 | if (needShow) |
843 | QMetaObject::invokeMethod(obj: w, member: "_q_showIfNotHidden" , type: 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 | */ |
854 | bool QLayoutPrivate::checkWidget(QWidget *widget) const |
855 | { |
856 | Q_Q(const QLayout); |
857 | if (Q_UNLIKELY(!widget)) { |
858 | qWarning(msg: "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(msg: "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 | */ |
875 | bool QLayoutPrivate::checkLayout(QLayout *otherLayout) const |
876 | { |
877 | Q_Q(const QLayout); |
878 | if (Q_UNLIKELY(!otherLayout)) { |
879 | qWarning(msg: "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(msg: "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 | */ |
899 | void QLayout::addChildWidget(QWidget *w) |
900 | { |
901 | QWidget *mw = parentWidget(); |
902 | QWidget *pw = w->parentWidget(); |
903 | |
904 | //Qt::WA_LaidOut is never reset. It only means that the widget at some point has |
905 | //been in a layout. |
906 | if (pw && w->testAttribute(attribute: Qt::WA_LaidOut)) { |
907 | QLayout *l = pw->layout(); |
908 | if (l && removeWidgetRecursively(li: l, w)) { |
909 | #ifdef QT_DEBUG |
910 | if (Q_UNLIKELY(layoutDebug())) |
911 | qWarning(msg: "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(msg: "QLayout::addChildWidget: %s \"%ls\" in wrong parent; moved to correct parent" , |
920 | w->metaObject()->className(), qUtf16Printable(w->objectName())); |
921 | #endif |
922 | pw = nullptr; |
923 | } |
924 | bool needShow = mw && mw->isVisible() && !(w->isHidden() && w->testAttribute(attribute: Qt::WA_WState_ExplicitShowHide)); |
925 | if (!pw && mw) |
926 | w->setParent(mw); |
927 | w->setAttribute(Qt::WA_LaidOut); |
928 | if (needShow) |
929 | QMetaObject::invokeMethod(obj: w, member: "_q_showIfNotHidden" , type: 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 | */ |
944 | void QLayout::(QWidget *widget) |
945 | { |
946 | Q_D(QLayout); |
947 | if (widget) |
948 | addChildWidget(w: 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 | |
957 | QWidget *QLayout::() 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 | */ |
974 | QSize QLayout::minimumSize() const |
975 | { |
976 | return QSize(0, 0); |
977 | } |
978 | |
979 | /*! |
980 | Returns the maximum size of this layout. This is the largest size |
981 | that the layout can have while still respecting the |
982 | specifications. |
983 | |
984 | The returned value doesn't include the space required by |
985 | QWidget::setContentsMargins() or menuBar(). |
986 | |
987 | The default implementation allows unlimited resizing. |
988 | */ |
989 | QSize QLayout::maximumSize() const |
990 | { |
991 | return QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX); |
992 | } |
993 | |
994 | /*! |
995 | Returns whether this layout can make use of more space than |
996 | sizeHint(). A value of Qt::Vertical or Qt::Horizontal means that |
997 | it wants to grow in only one dimension, whereas Qt::Vertical | |
998 | Qt::Horizontal means that it wants to grow in both dimensions. |
999 | |
1000 | The default implementation returns Qt::Horizontal | Qt::Vertical. |
1001 | Subclasses reimplement it to return a meaningful value based on |
1002 | their child widgets's \l{QSizePolicy}{size policies}. |
1003 | |
1004 | \sa sizeHint() |
1005 | */ |
1006 | Qt::Orientations QLayout::expandingDirections() const |
1007 | { |
1008 | return Qt::Horizontal | Qt::Vertical; |
1009 | } |
1010 | |
1011 | void QLayout::activateRecursiveHelper(QLayoutItem *item) |
1012 | { |
1013 | item->invalidate(); |
1014 | QLayout *layout = item->layout(); |
1015 | if (layout) { |
1016 | QLayoutItem *child; |
1017 | int i=0; |
1018 | while ((child = layout->itemAt(index: i++))) |
1019 | activateRecursiveHelper(item: 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 | |
1033 | void QLayout::update() |
1034 | { |
1035 | QLayout *layout = this; |
1036 | while (layout && layout->d_func()->activated) { |
1037 | layout->d_func()->activated = false; |
1038 | if (layout->d_func()->topLevel) { |
1039 | Q_ASSERT(layout->parent()->isWidgetType()); |
1040 | QWidget *mw = static_cast<QWidget*>(layout->parent()); |
1041 | QCoreApplication::postEvent(receiver: mw, event: 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 | */ |
1057 | bool QLayout::activate() |
1058 | { |
1059 | Q_D(QLayout); |
1060 | if (!d->enabled || !parent()) |
1061 | return false; |
1062 | if (!d->topLevel) |
1063 | return static_cast<QLayout*>(parent())->activate(); |
1064 | if (d->activated) |
1065 | return false; |
1066 | QWidget *mw = static_cast<QWidget*>(parent()); |
1067 | if (Q_UNLIKELY(!mw)) { |
1068 | qWarning(msg: "QLayout::activate: %s \"%ls\" does not have a main widget" , |
1069 | metaObject()->className(), qUtf16Printable(objectName())); |
1070 | return false; |
1071 | } |
1072 | activateRecursiveHelper(item: this); |
1073 | |
1074 | QWidgetPrivate *md = mw->d_func(); |
1075 | uint explMin = md->extra ? md->extra->explicitMinSize : 0; |
1076 | uint explMax = md->extra ? md->extra->explicitMaxSize : 0; |
1077 | |
1078 | switch (d->constraint) { |
1079 | case SetFixedSize: |
1080 | // will trigger resize |
1081 | mw->setFixedSize(totalSizeHint()); |
1082 | break; |
1083 | case SetMinimumSize: |
1084 | mw->setMinimumSize(totalMinimumSize()); |
1085 | break; |
1086 | case SetMaximumSize: |
1087 | mw->setMaximumSize(totalMaximumSize()); |
1088 | break; |
1089 | case SetMinAndMaxSize: |
1090 | mw->setMinimumSize(totalMinimumSize()); |
1091 | mw->setMaximumSize(totalMaximumSize()); |
1092 | break; |
1093 | case SetDefaultConstraint: { |
1094 | bool widthSet = explMin & Qt::Horizontal; |
1095 | bool heightSet = explMin & Qt::Vertical; |
1096 | if (mw->isWindow()) { |
1097 | QSize ms = totalMinimumSize(); |
1098 | if (widthSet) |
1099 | ms.setWidth(mw->minimumSize().width()); |
1100 | if (heightSet) |
1101 | ms.setHeight(mw->minimumSize().height()); |
1102 | mw->setMinimumSize(ms); |
1103 | } else if (!widthSet || !heightSet) { |
1104 | QSize ms = mw->minimumSize(); |
1105 | if (!widthSet) |
1106 | ms.setWidth(0); |
1107 | if (!heightSet) |
1108 | ms.setHeight(0); |
1109 | mw->setMinimumSize(ms); |
1110 | } |
1111 | break; |
1112 | } |
1113 | case SetNoConstraint: |
1114 | break; |
1115 | } |
1116 | |
1117 | d->doResize(); |
1118 | |
1119 | if (md->extra) { |
1120 | md->extra->explicitMinSize = explMin; |
1121 | md->extra->explicitMaxSize = explMax; |
1122 | } |
1123 | // ideally only if sizeHint() or sizePolicy() has changed |
1124 | mw->updateGeometry(); |
1125 | return true; |
1126 | } |
1127 | |
1128 | /*! |
1129 | \since 5.2 |
1130 | |
1131 | Searches for widget \a from and replaces it with widget \a to if found. |
1132 | Returns the layout item that contains the widget \a from on success. |
1133 | Otherwise \nullptr is returned. |
1134 | If \a options contains \c Qt::FindChildrenRecursively (the default), |
1135 | sub-layouts are searched for doing the replacement. |
1136 | Any other flag in \a options is ignored. |
1137 | |
1138 | Notice that the returned item therefore might not belong to this layout, |
1139 | but to a sub-layout. |
1140 | |
1141 | The returned layout item is no longer owned by the layout and should be |
1142 | either deleted or inserted to another layout. The widget \a from is no |
1143 | longer managed by the layout and may need to be deleted or hidden. The |
1144 | parent of widget \a from is left unchanged. |
1145 | |
1146 | This function works for the built-in Qt layouts, but might not work for |
1147 | custom layouts. |
1148 | |
1149 | \sa indexOf() |
1150 | */ |
1151 | |
1152 | QLayoutItem *QLayout::replaceWidget(QWidget *from, QWidget *to, Qt::FindChildOptions options) |
1153 | { |
1154 | Q_D(QLayout); |
1155 | if (!from || !to) |
1156 | return nullptr; |
1157 | if (from == to) // Do not return a QLayoutItem for \a from, since ownership still |
1158 | return nullptr; // belongs to the layout (since nothing was changed) |
1159 | |
1160 | int index = -1; |
1161 | QLayoutItem *item = nullptr; |
1162 | for (int u = 0; u < count(); ++u) { |
1163 | item = itemAt(index: u); |
1164 | if (!item) |
1165 | continue; |
1166 | |
1167 | if (item->widget() == from) { |
1168 | index = u; |
1169 | break; |
1170 | } |
1171 | |
1172 | if (item->layout() && (options & Qt::FindChildrenRecursively)) { |
1173 | QLayoutItem *r = item->layout()->replaceWidget(from, to, options); |
1174 | if (r) |
1175 | return r; |
1176 | } |
1177 | } |
1178 | if (index == -1) |
1179 | return nullptr; |
1180 | |
1181 | addChildWidget(w: to); |
1182 | QLayoutItem *newitem = new QWidgetItem(to); |
1183 | newitem->setAlignment(item->alignment()); |
1184 | QLayoutItem *r = d->replaceAt(index, newitem); |
1185 | if (!r) |
1186 | delete newitem; |
1187 | return r; |
1188 | } |
1189 | |
1190 | /*! |
1191 | \fn QLayoutItem *QLayout::itemAt(int index) const |
1192 | |
1193 | Must be implemented in subclasses to return the layout item at \a |
1194 | index. If there is no such item, the function must return 0. |
1195 | Items are numbered consecutively from 0. If an item is deleted, other items will be renumbered. |
1196 | |
1197 | This function can be used to iterate over a layout. The following |
1198 | code will draw a rectangle for each layout item in the layout structure of the widget. |
1199 | |
1200 | \snippet code/src_gui_kernel_qlayout.cpp 0 |
1201 | |
1202 | \sa count(), takeAt() |
1203 | */ |
1204 | |
1205 | /*! |
1206 | \fn QLayoutItem *QLayout::takeAt(int index) |
1207 | |
1208 | Must be implemented in subclasses to remove the layout item at \a |
1209 | index from the layout, and return the item. If there is no such |
1210 | item, the function must do nothing and return 0. Items are numbered |
1211 | consecutively from 0. If an item is removed, other items will be |
1212 | renumbered. |
1213 | |
1214 | The following code fragment shows a safe way to remove all items |
1215 | from a layout: |
1216 | |
1217 | \snippet code/src_gui_kernel_qlayout.cpp 1 |
1218 | |
1219 | \sa itemAt(), count() |
1220 | */ |
1221 | |
1222 | /*! |
1223 | \fn int *QLayout::count() const |
1224 | |
1225 | Must be implemented in subclasses to return the number of items |
1226 | in the layout. |
1227 | |
1228 | \sa itemAt() |
1229 | */ |
1230 | |
1231 | /*! |
1232 | Searches for widget \a widget in this layout (not including child |
1233 | layouts). |
1234 | |
1235 | Returns the index of \a widget, or -1 if \a widget is not found. |
1236 | |
1237 | The default implementation iterates over all items using itemAt() |
1238 | */ |
1239 | int QLayout::indexOf(QWidget *widget) const |
1240 | { |
1241 | int i = 0; |
1242 | QLayoutItem *item = itemAt(index: i); |
1243 | while (item) { |
1244 | if (item->widget() == widget) |
1245 | return i; |
1246 | ++i; |
1247 | item = itemAt(index: i); |
1248 | } |
1249 | return -1; |
1250 | } |
1251 | |
1252 | /*! |
1253 | \since 5.12 |
1254 | Searches for layout item \a layoutItem in this layout (not including child |
1255 | layouts). |
1256 | |
1257 | Returns the index of \a layoutItem, or -1 if \a layoutItem is not found. |
1258 | */ |
1259 | int QLayout::indexOf(QLayoutItem *layoutItem) const |
1260 | { |
1261 | int i = 0; |
1262 | QLayoutItem *item = itemAt(index: i); |
1263 | while (item) { |
1264 | if (item == layoutItem) |
1265 | return i; |
1266 | ++i; |
1267 | item = itemAt(index: i); |
1268 | } |
1269 | return -1; |
1270 | } |
1271 | |
1272 | /*! |
1273 | \enum QLayout::SizeConstraint |
1274 | |
1275 | The possible values are: |
1276 | |
1277 | \value SetDefaultConstraint The main widget's minimum size is set |
1278 | to minimumSize(), unless the widget already has |
1279 | a minimum size. |
1280 | |
1281 | \value SetFixedSize The main widget's size is set to sizeHint(); it |
1282 | cannot be resized at all. |
1283 | \value SetMinimumSize The main widget's minimum size is set to |
1284 | minimumSize(); it cannot be smaller. |
1285 | |
1286 | \value SetMaximumSize The main widget's maximum size is set to |
1287 | maximumSize(); it cannot be larger. |
1288 | |
1289 | \value SetMinAndMaxSize The main widget's minimum size is set to |
1290 | minimumSize() and its maximum size is set to |
1291 | maximumSize(). |
1292 | |
1293 | \value SetNoConstraint The widget is not constrained. |
1294 | |
1295 | \sa setSizeConstraint() |
1296 | */ |
1297 | |
1298 | /*! |
1299 | \property QLayout::sizeConstraint |
1300 | \brief the resize mode of the layout |
1301 | |
1302 | The default mode is \l {QLayout::SetDefaultConstraint} |
1303 | {SetDefaultConstraint}. |
1304 | */ |
1305 | void QLayout::setSizeConstraint(SizeConstraint constraint) |
1306 | { |
1307 | Q_D(QLayout); |
1308 | if (constraint == d->constraint) |
1309 | return; |
1310 | |
1311 | d->constraint = constraint; |
1312 | invalidate(); |
1313 | } |
1314 | |
1315 | QLayout::SizeConstraint QLayout::sizeConstraint() const |
1316 | { |
1317 | Q_D(const QLayout); |
1318 | return d->constraint; |
1319 | } |
1320 | |
1321 | /*! |
1322 | Returns the rectangle that should be covered when the geometry of |
1323 | this layout is set to \a r, provided that this layout supports |
1324 | setAlignment(). |
1325 | |
1326 | The result is derived from sizeHint() and expanding(). It is never |
1327 | larger than \a r. |
1328 | */ |
1329 | QRect QLayout::alignmentRect(const QRect &r) const |
1330 | { |
1331 | QSize s = sizeHint(); |
1332 | Qt::Alignment a = alignment(); |
1333 | |
1334 | /* |
1335 | This is a hack to obtain the real maximum size, not |
1336 | QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX), the value consistently |
1337 | returned by QLayoutItems that have an alignment. |
1338 | */ |
1339 | QLayout *that = const_cast<QLayout *>(this); |
1340 | that->setAlignment({ }); |
1341 | QSize ms = that->maximumSize(); |
1342 | that->setAlignment(a); |
1343 | |
1344 | if ((expandingDirections() & Qt::Horizontal) || |
1345 | !(a & Qt::AlignHorizontal_Mask)) { |
1346 | s.setWidth(qMin(a: r.width(), b: ms.width())); |
1347 | } |
1348 | if ((expandingDirections() & Qt::Vertical) || |
1349 | !(a & Qt::AlignVertical_Mask)) { |
1350 | s.setHeight(qMin(a: r.height(), b: ms.height())); |
1351 | } else if (hasHeightForWidth()) { |
1352 | int hfw = heightForWidth(s.width()); |
1353 | if (hfw < s.height()) |
1354 | s.setHeight(qMin(a: hfw, b: ms.height())); |
1355 | } |
1356 | |
1357 | s = s.boundedTo(otherSize: r.size()); |
1358 | int x = r.x(); |
1359 | int y = r.y(); |
1360 | |
1361 | if (a & Qt::AlignBottom) |
1362 | y += (r.height() - s.height()); |
1363 | else if (!(a & Qt::AlignTop)) |
1364 | y += (r.height() - s.height()) / 2; |
1365 | |
1366 | QWidget *parent = parentWidget(); |
1367 | a = QStyle::visualAlignment(direction: parent ? parent->layoutDirection() : QGuiApplication::layoutDirection(), alignment: a); |
1368 | if (a & Qt::AlignRight) |
1369 | x += (r.width() - s.width()); |
1370 | else if (!(a & Qt::AlignLeft)) |
1371 | x += (r.width() - s.width()) / 2; |
1372 | |
1373 | return QRect(x, y, s.width(), s.height()); |
1374 | } |
1375 | |
1376 | /*! |
1377 | Removes the widget \a widget from the layout. After this call, it |
1378 | is the caller's responsibility to give the widget a reasonable |
1379 | geometry or to put the widget back into a layout or to explicitly |
1380 | hide it if necessary. |
1381 | |
1382 | \b{Note:} The ownership of \a widget remains the same as |
1383 | when it was added. |
1384 | |
1385 | \sa removeItem(), QWidget::setGeometry(), addWidget() |
1386 | */ |
1387 | void QLayout::removeWidget(QWidget *widget) |
1388 | { |
1389 | if (Q_UNLIKELY(!widget)) { |
1390 | qWarning(msg: "QLayout::removeWidget: Cannot remove a null widget." ); |
1391 | return; |
1392 | } |
1393 | |
1394 | int i = 0; |
1395 | QLayoutItem *child; |
1396 | while ((child = itemAt(index: i))) { |
1397 | if (child->widget() == widget) { |
1398 | delete takeAt(index: i); |
1399 | invalidate(); |
1400 | } else { |
1401 | ++i; |
1402 | } |
1403 | } |
1404 | } |
1405 | |
1406 | /*! |
1407 | Removes the layout item \a item from the layout. It is the |
1408 | caller's responsibility to delete the item. |
1409 | |
1410 | Notice that \a item can be a layout (since QLayout inherits |
1411 | QLayoutItem). |
1412 | |
1413 | \sa removeWidget(), addItem() |
1414 | */ |
1415 | void QLayout::removeItem(QLayoutItem *item) |
1416 | { |
1417 | int i = 0; |
1418 | QLayoutItem *child; |
1419 | while ((child = itemAt(index: i))) { |
1420 | if (child == item) { |
1421 | takeAt(index: i); |
1422 | invalidate(); |
1423 | } else { |
1424 | ++i; |
1425 | } |
1426 | } |
1427 | } |
1428 | |
1429 | /*! |
1430 | Enables this layout if \a enable is true, otherwise disables it. |
1431 | |
1432 | An enabled layout adjusts dynamically to changes; a disabled |
1433 | layout acts as if it did not exist. |
1434 | |
1435 | By default all layouts are enabled. |
1436 | |
1437 | \sa isEnabled() |
1438 | */ |
1439 | void QLayout::setEnabled(bool enable) |
1440 | { |
1441 | Q_D(QLayout); |
1442 | d->enabled = enable; |
1443 | } |
1444 | |
1445 | /*! |
1446 | Returns \c true if the layout is enabled; otherwise returns \c false. |
1447 | |
1448 | \sa setEnabled() |
1449 | */ |
1450 | bool QLayout::isEnabled() const |
1451 | { |
1452 | Q_D(const QLayout); |
1453 | return d->enabled; |
1454 | } |
1455 | |
1456 | /*! |
1457 | Returns a size that satisfies all size constraints on \a widget, |
1458 | including heightForWidth() and that is as close as possible to \a |
1459 | size. |
1460 | */ |
1461 | |
1462 | QSize QLayout::closestAcceptableSize(const QWidget *widget, const QSize &size) |
1463 | { |
1464 | QSize result = size.boundedTo(otherSize: qSmartMaxSize(w: widget)); |
1465 | result = result.expandedTo(otherSize: qSmartMinSize(w: widget)); |
1466 | QLayout *l = widget->layout(); |
1467 | if (l && l->hasHeightForWidth() && result.height() < l->minimumHeightForWidth(result.width()) ) { |
1468 | QSize current = widget->size(); |
1469 | int currentHfw = l->minimumHeightForWidth(current.width()); |
1470 | int newHfw = l->minimumHeightForWidth(result.width()); |
1471 | if (current.height() < currentHfw || currentHfw == newHfw) { |
1472 | //handle the constant hfw case and the vertical-only case, as well as the |
1473 | // current-size-is-not-correct case |
1474 | result.setHeight(newHfw); |
1475 | } else { |
1476 | // binary search; assume hfw is decreasing ### |
1477 | |
1478 | int maxw = qMax(a: widget->width(),b: result.width()); |
1479 | int maxh = qMax(a: widget->height(), b: result.height()); |
1480 | int minw = qMin(a: widget->width(),b: result.width()); |
1481 | int minh = qMin(a: widget->height(), b: result.height()); |
1482 | |
1483 | int minhfw = l->minimumHeightForWidth(minw); |
1484 | int maxhfw = l->minimumHeightForWidth(maxw); |
1485 | while (minw < maxw) { |
1486 | if (minhfw > maxh) { //assume decreasing |
1487 | minw = maxw - (maxw-minw)/2; |
1488 | minhfw = l->minimumHeightForWidth(minw); |
1489 | } else if (maxhfw < minh ) { //assume decreasing |
1490 | maxw = minw + (maxw-minw)/2; |
1491 | maxhfw = l->minimumHeightForWidth(maxw); |
1492 | } else { |
1493 | break; |
1494 | } |
1495 | } |
1496 | result = result.expandedTo(otherSize: QSize(minw, minhfw)); |
1497 | } |
1498 | } |
1499 | return result; |
1500 | } |
1501 | |
1502 | QT_END_NAMESPACE |
1503 | |
1504 | #include "moc_qlayout.cpp" |
1505 | |