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