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