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 | #include "qevent.h" |
51 | #include "qstyle.h" |
52 | #include "qvariant.h" |
53 | #include "qwidget_p.h" |
54 | |
55 | QT_BEGIN_NAMESPACE |
56 | |
57 | inline static QRect fromLayoutItemRect(QWidgetPrivate *priv, const QRect &rect) |
58 | { |
59 | return rect.adjusted(xp1: priv->leftLayoutItemMargin, yp1: priv->topLayoutItemMargin, |
60 | xp2: -priv->rightLayoutItemMargin, yp2: -priv->bottomLayoutItemMargin); |
61 | } |
62 | |
63 | inline static QSize fromLayoutItemSize(QWidgetPrivate *priv, const QSize &size) |
64 | { |
65 | return fromLayoutItemRect(priv, rect: QRect(QPoint(0, 0), size)).size(); |
66 | } |
67 | |
68 | inline static QRect toLayoutItemRect(QWidgetPrivate *priv, const QRect &rect) |
69 | { |
70 | return rect.adjusted(xp1: -priv->leftLayoutItemMargin, yp1: -priv->topLayoutItemMargin, |
71 | xp2: priv->rightLayoutItemMargin, yp2: priv->bottomLayoutItemMargin); |
72 | } |
73 | |
74 | inline static QSize toLayoutItemSize(QWidgetPrivate *priv, const QSize &size) |
75 | { |
76 | return toLayoutItemRect(priv, rect: QRect(QPoint(0, 0), size)).size(); |
77 | } |
78 | |
79 | /*! |
80 | \class QLayoutItem |
81 | \brief The QLayoutItem class provides an abstract item that a |
82 | QLayout manipulates. |
83 | |
84 | \ingroup geomanagement |
85 | \inmodule QtWidgets |
86 | |
87 | This is used by custom layouts. |
88 | |
89 | Pure virtual functions are provided to return information about |
90 | the layout, including, sizeHint(), minimumSize(), maximumSize() |
91 | and expanding(). |
92 | |
93 | The layout's geometry can be set and retrieved with setGeometry() |
94 | and geometry(), and its alignment with setAlignment() and |
95 | alignment(). |
96 | |
97 | isEmpty() returns whether the layout item is empty. If the |
98 | concrete item is a QWidget, it can be retrieved using widget(). |
99 | Similarly for layout() and spacerItem(). |
100 | |
101 | Some layouts have width and height interdependencies. These can |
102 | be expressed using hasHeightForWidth(), heightForWidth(), and |
103 | minimumHeightForWidth(). For more explanation see the \e{Qt |
104 | Quarterly} article |
105 | \l{http://doc.qt.io/archives/qq/qq04-height-for-width.html}{Trading |
106 | Height for Width}. |
107 | |
108 | \sa QLayout |
109 | */ |
110 | |
111 | /*! |
112 | \class QSpacerItem |
113 | \ingroup geomanagement |
114 | \brief The QSpacerItem class provides blank space in a layout. |
115 | |
116 | \inmodule QtWidgets |
117 | |
118 | Normally, you don't need to use this class directly. Qt's |
119 | built-in layout managers provide the following functions for |
120 | manipulating empty space in layouts: |
121 | |
122 | \table |
123 | \header \li Class |
124 | \li Functions |
125 | \row \li QHBoxLayout |
126 | \li \l{QBoxLayout::addSpacing()}{addSpacing()}, |
127 | \l{QBoxLayout::addStretch()}{addStretch()}, |
128 | \l{QBoxLayout::insertSpacing()}{insertSpacing()}, |
129 | \l{QBoxLayout::insertStretch()}{insertStretch()} |
130 | \row \li QGridLayout |
131 | \li \l{QGridLayout::setRowMinimumHeight()}{setRowMinimumHeight()}, |
132 | \l{QGridLayout::setRowStretch()}{setRowStretch()}, |
133 | \l{QGridLayout::setColumnMinimumWidth()}{setColumnMinimumWidth()}, |
134 | \l{QGridLayout::setColumnStretch()}{setColumnStretch()} |
135 | \endtable |
136 | |
137 | \sa QLayout, QWidgetItem, QLayoutItem::spacerItem() |
138 | */ |
139 | |
140 | /*! |
141 | \class QWidgetItem |
142 | \ingroup geomanagement |
143 | \brief The QWidgetItem class is a layout item that represents a widget. |
144 | |
145 | \inmodule QtWidgets |
146 | |
147 | Normally, you don't need to use this class directly. Qt's |
148 | built-in layout managers provide the following functions for |
149 | manipulating widgets in layouts: |
150 | |
151 | \table |
152 | \header \li Class |
153 | \li Functions |
154 | \row \li QBoxLayout |
155 | \li \l{QBoxLayout::addWidget()}{addWidget()}, |
156 | \l{QBoxLayout::insertWidget()}{insertWidget()}, |
157 | \l{QBoxLayout::setStretchFactor()}{setStretchFactor()} |
158 | \row \li QGridLayout |
159 | \li \l{QGridLayout::addWidget()}{addWidget()} |
160 | \row \li QStackedLayout |
161 | \li \l{QStackedLayout::addWidget()}{addWidget()}, |
162 | \l{QStackedLayout::insertWidget()}{insertWidget()}, |
163 | \l{QStackedLayout::currentWidget()}{currentWidget()}, |
164 | \l{QStackedLayout::setCurrentWidget()}{setCurrentWidget()}, |
165 | \l{QStackedLayout::widget()}{widget()} |
166 | \endtable |
167 | |
168 | \sa QLayout, QSpacerItem, QLayoutItem::widget() |
169 | */ |
170 | |
171 | /*! |
172 | \fn QLayoutItem::QLayoutItem(Qt::Alignment alignment) |
173 | |
174 | Constructs a layout item with an \a alignment. |
175 | Not all subclasses support alignment. |
176 | */ |
177 | |
178 | /*! |
179 | \fn Qt::Alignment QLayoutItem::alignment() const |
180 | |
181 | Returns the alignment of this item. |
182 | */ |
183 | |
184 | /*! |
185 | Sets the alignment of this item to \a alignment. |
186 | |
187 | \b{Note:} Item alignment is only supported by QLayoutItem subclasses |
188 | where it would have a visual effect. Except for QSpacerItem, which provides |
189 | blank space for layouts, all public Qt classes that inherit QLayoutItem |
190 | support item alignment. |
191 | */ |
192 | void QLayoutItem::setAlignment(Qt::Alignment alignment) |
193 | { |
194 | align = alignment; |
195 | } |
196 | |
197 | /*! |
198 | \fn QSize QLayoutItem::maximumSize() const |
199 | |
200 | Implemented in subclasses to return the maximum size of this item. |
201 | */ |
202 | |
203 | /*! |
204 | \fn QSize QLayoutItem::minimumSize() const |
205 | |
206 | Implemented in subclasses to return the minimum size of this item. |
207 | */ |
208 | |
209 | /*! |
210 | \fn QSize QLayoutItem::sizeHint() const |
211 | |
212 | Implemented in subclasses to return the preferred size of this item. |
213 | */ |
214 | |
215 | /*! |
216 | \fn Qt::Orientations QLayoutItem::expandingDirections() const |
217 | |
218 | Returns whether this layout item can make use of more space than |
219 | sizeHint(). A value of Qt::Vertical or Qt::Horizontal means that |
220 | it wants to grow in only one dimension, whereas Qt::Vertical | |
221 | Qt::Horizontal means that it wants to grow in both dimensions. |
222 | */ |
223 | |
224 | /*! |
225 | \fn void QLayoutItem::setGeometry(const QRect &r) |
226 | |
227 | Implemented in subclasses to set this item's geometry to \a r. |
228 | |
229 | \sa geometry() |
230 | */ |
231 | |
232 | /*! |
233 | \fn QRect QLayoutItem::geometry() const |
234 | |
235 | Returns the rectangle covered by this layout item. |
236 | |
237 | \sa setGeometry() |
238 | */ |
239 | |
240 | /*! |
241 | \fn virtual bool QLayoutItem::isEmpty() const |
242 | |
243 | Implemented in subclasses to return whether this item is empty, |
244 | i.e. whether it contains any widgets. |
245 | */ |
246 | |
247 | /*! |
248 | \fn QSpacerItem::QSpacerItem(int w, int h, QSizePolicy::Policy hPolicy, QSizePolicy::Policy vPolicy) |
249 | |
250 | Constructs a spacer item with preferred width \a w, preferred |
251 | height \a h, horizontal size policy \a hPolicy and vertical size |
252 | policy \a vPolicy. |
253 | |
254 | The default values provide a gap that is able to stretch if |
255 | nothing else wants the space. |
256 | */ |
257 | |
258 | /*! |
259 | Destructor. |
260 | */ |
261 | QSpacerItem::~QSpacerItem() {} |
262 | |
263 | /*! |
264 | Changes this spacer item to have preferred width \a w, preferred |
265 | height \a h, horizontal size policy \a hPolicy and vertical size |
266 | policy \a vPolicy. |
267 | |
268 | The default values provide a gap that is able to stretch if |
269 | nothing else wants the space. |
270 | |
271 | Note that if changeSize() is called after the spacer item has been added |
272 | to a layout, it is necessary to invalidate the layout in order for the |
273 | spacer item's new size to take effect. |
274 | |
275 | \sa QSpacerItem::invalidate() |
276 | */ |
277 | void QSpacerItem::changeSize(int w, int h, QSizePolicy::Policy hPolicy, |
278 | QSizePolicy::Policy vPolicy) |
279 | { |
280 | width = w; |
281 | height = h; |
282 | sizeP = QSizePolicy(hPolicy, vPolicy); |
283 | } |
284 | |
285 | /*! |
286 | \fn QWidgetItem::QWidgetItem(QWidget *widget) |
287 | |
288 | Creates an item containing the given \a widget. |
289 | */ |
290 | |
291 | /*! |
292 | Destructor. |
293 | */ |
294 | QWidgetItem::~QWidgetItem() = default; |
295 | |
296 | /*! |
297 | Destroys the QLayoutItem. |
298 | */ |
299 | QLayoutItem::~QLayoutItem() = default; |
300 | |
301 | /*! |
302 | Invalidates any cached information in this layout item. |
303 | */ |
304 | void QLayoutItem::invalidate() |
305 | { |
306 | } |
307 | |
308 | /*! |
309 | If this item is a QLayout, it is returned as a QLayout; otherwise |
310 | \nullptr is returned. This function provides type-safe casting. |
311 | |
312 | \sa spacerItem(), widget() |
313 | */ |
314 | QLayout *QLayoutItem::layout() |
315 | { |
316 | return nullptr; |
317 | } |
318 | |
319 | /*! |
320 | If this item is a QSpacerItem, it is returned as a QSpacerItem; |
321 | otherwise \nullptr is returned. This function provides type-safe casting. |
322 | |
323 | \sa layout(), widget() |
324 | */ |
325 | QSpacerItem *QLayoutItem::spacerItem() |
326 | { |
327 | return nullptr; |
328 | } |
329 | |
330 | /*! |
331 | \reimp |
332 | */ |
333 | QLayout * QLayout::layout() |
334 | { |
335 | return this; |
336 | } |
337 | |
338 | /*! |
339 | Returns a pointer to this object. |
340 | */ |
341 | QSpacerItem * QSpacerItem::spacerItem() |
342 | { |
343 | return this; |
344 | } |
345 | |
346 | /*! |
347 | \fn QSizePolicy QSpacerItem::sizePolicy() const |
348 | \since 5.5 |
349 | |
350 | Returns the size policy of this item. |
351 | */ |
352 | |
353 | /*! |
354 | If this item manages a QWidget, returns that widget. Otherwise, |
355 | \nullptr is returned. |
356 | |
357 | \note While the functions layout() and spacerItem() perform casts, this |
358 | function returns another object: QLayout and QSpacerItem inherit QLayoutItem, |
359 | while QWidget does not. |
360 | |
361 | \sa layout(), spacerItem() |
362 | */ |
363 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) |
364 | QWidget *QLayoutItem::widget() |
365 | #else |
366 | QWidget *QLayoutItem::widget() const |
367 | #endif |
368 | { |
369 | return nullptr; |
370 | } |
371 | |
372 | /*! |
373 | Returns the widget managed by this item. |
374 | */ |
375 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) |
376 | QWidget *QWidgetItem::widget() |
377 | #else |
378 | QWidget *QWidgetItem::widget() const |
379 | #endif |
380 | { |
381 | return wid; |
382 | } |
383 | |
384 | /*! |
385 | Returns \c true if this layout's preferred height depends on its |
386 | width; otherwise returns \c false. The default implementation returns |
387 | false. |
388 | |
389 | Reimplement this function in layout managers that support height |
390 | for width. |
391 | |
392 | \sa heightForWidth(), QWidget::heightForWidth() |
393 | */ |
394 | bool QLayoutItem::hasHeightForWidth() const |
395 | { |
396 | return false; |
397 | } |
398 | |
399 | /*! |
400 | Returns the minimum height this widget needs for the given width, |
401 | \a w. The default implementation simply returns heightForWidth(\a |
402 | w). |
403 | */ |
404 | int QLayoutItem::minimumHeightForWidth(int w) const |
405 | { |
406 | return heightForWidth(w); |
407 | } |
408 | |
409 | |
410 | /*! |
411 | Returns the preferred height for this layout item, given the |
412 | width, which is not used in this default implementation. |
413 | |
414 | The default implementation returns -1, indicating that the |
415 | preferred height is independent of the width of the item. Using |
416 | the function hasHeightForWidth() will typically be much faster |
417 | than calling this function and testing for -1. |
418 | |
419 | Reimplement this function in layout managers that support height |
420 | for width. A typical implementation will look like this: |
421 | \snippet code/src_gui_kernel_qlayoutitem.cpp 0 |
422 | |
423 | Caching is strongly recommended; without it layout will take |
424 | exponential time. |
425 | |
426 | \sa hasHeightForWidth() |
427 | */ |
428 | int QLayoutItem::heightForWidth(int /* w */) const |
429 | { |
430 | return -1; |
431 | } |
432 | |
433 | /*! |
434 | Returns the control type(s) for the layout item. For a |
435 | QWidgetItem, the control type comes from the widget's size |
436 | policy; for a QLayoutItem, the control types is derived from the |
437 | layout's contents. |
438 | |
439 | \sa QSizePolicy::controlType() |
440 | */ |
441 | QSizePolicy::ControlTypes QLayoutItem::controlTypes() const |
442 | { |
443 | return QSizePolicy::DefaultType; |
444 | } |
445 | |
446 | /*! |
447 | \reimp |
448 | */ |
449 | void QSpacerItem::setGeometry(const QRect &r) |
450 | { |
451 | rect = r; |
452 | } |
453 | |
454 | /*! |
455 | \reimp |
456 | */ |
457 | void QWidgetItem::setGeometry(const QRect &rect) |
458 | { |
459 | if (isEmpty()) |
460 | return; |
461 | |
462 | QRect r = !wid->testAttribute(attribute: Qt::WA_LayoutUsesWidgetRect) |
463 | ? fromLayoutItemRect(priv: wid->d_func(), rect) |
464 | : rect; |
465 | const QSize widgetRectSurplus = r.size() - rect.size(); |
466 | |
467 | /* |
468 | For historical reasons, this code is done using widget rect |
469 | coordinates, not layout item rect coordinates. However, |
470 | QWidgetItem's sizeHint(), maximumSize(), and heightForWidth() |
471 | all work in terms of layout item rect coordinates, so we have to |
472 | add or subtract widgetRectSurplus here and there. The code could |
473 | be much simpler if we did everything using layout item rect |
474 | coordinates and did the conversion right before the call to |
475 | QWidget::setGeometry(). |
476 | */ |
477 | |
478 | QSize s = r.size().boundedTo(otherSize: maximumSize() + widgetRectSurplus); |
479 | int x = r.x(); |
480 | int y = r.y(); |
481 | if (align & (Qt::AlignHorizontal_Mask | Qt::AlignVertical_Mask)) { |
482 | QSize pref(sizeHint()); |
483 | QSizePolicy sp = wid->sizePolicy(); |
484 | if (sp.horizontalPolicy() == QSizePolicy::Ignored) |
485 | pref.setWidth(wid->sizeHint().expandedTo(otherSize: wid->minimumSize()).width()); |
486 | if (sp.verticalPolicy() == QSizePolicy::Ignored) |
487 | pref.setHeight(wid->sizeHint().expandedTo(otherSize: wid->minimumSize()).height()); |
488 | pref += widgetRectSurplus; |
489 | if (align & Qt::AlignHorizontal_Mask) |
490 | s.setWidth(qMin(a: s.width(), b: pref.width())); |
491 | if (align & Qt::AlignVertical_Mask) { |
492 | if (hasHeightForWidth()) |
493 | s.setHeight(qMin(a: s.height(), |
494 | b: heightForWidth(s.width() - widgetRectSurplus.width()) |
495 | + widgetRectSurplus.height())); |
496 | else |
497 | s.setHeight(qMin(a: s.height(), b: pref.height())); |
498 | } |
499 | } |
500 | Qt::Alignment alignHoriz = QStyle::visualAlignment(direction: wid->layoutDirection(), alignment: align); |
501 | if (alignHoriz & Qt::AlignRight) |
502 | x = x + (r.width() - s.width()); |
503 | else if (!(alignHoriz & Qt::AlignLeft)) |
504 | x = x + (r.width() - s.width()) / 2; |
505 | |
506 | if (align & Qt::AlignBottom) |
507 | y = y + (r.height() - s.height()); |
508 | else if (!(align & Qt::AlignTop)) |
509 | y = y + (r.height() - s.height()) / 2; |
510 | |
511 | // Make sure we don't move outside of the parent, e.g when styles demand |
512 | // surplus space that exceeds the available margins (f.ex macOS with QGroupBox) |
513 | if (x < 0) { |
514 | s.rwidth() += x; |
515 | x = 0; |
516 | } |
517 | if (y < 0) { |
518 | s.rheight() += y; |
519 | y = 0; |
520 | } |
521 | |
522 | wid->setGeometry(ax: x, ay: y, aw: s.width(), ah: s.height()); |
523 | } |
524 | |
525 | /*! |
526 | \reimp |
527 | */ |
528 | QRect QSpacerItem::geometry() const |
529 | { |
530 | return rect; |
531 | } |
532 | |
533 | /*! |
534 | \reimp |
535 | */ |
536 | QRect QWidgetItem::geometry() const |
537 | { |
538 | return !wid->testAttribute(attribute: Qt::WA_LayoutUsesWidgetRect) |
539 | ? toLayoutItemRect(priv: wid->d_func(), rect: wid->geometry()) |
540 | : wid->geometry(); |
541 | } |
542 | |
543 | |
544 | /*! |
545 | \reimp |
546 | */ |
547 | bool QWidgetItem::hasHeightForWidth() const |
548 | { |
549 | if (isEmpty()) |
550 | return false; |
551 | return wid->hasHeightForWidth(); |
552 | } |
553 | |
554 | /*! |
555 | \reimp |
556 | */ |
557 | int QWidgetItem::heightForWidth(int w) const |
558 | { |
559 | if (isEmpty()) |
560 | return -1; |
561 | |
562 | w = !wid->testAttribute(attribute: Qt::WA_LayoutUsesWidgetRect) |
563 | ? fromLayoutItemSize(priv: wid->d_func(), size: QSize(w, 0)).width() |
564 | : w; |
565 | |
566 | int hfw; |
567 | if (wid->layout()) |
568 | hfw = wid->layout()->totalHeightForWidth(w); |
569 | else |
570 | hfw = wid->heightForWidth(w); |
571 | |
572 | if (hfw > wid->maximumHeight()) |
573 | hfw = wid->maximumHeight(); |
574 | if (hfw < wid->minimumHeight()) |
575 | hfw = wid->minimumHeight(); |
576 | |
577 | hfw = !wid->testAttribute(attribute: Qt::WA_LayoutUsesWidgetRect) |
578 | ? toLayoutItemSize(priv: wid->d_func(), size: QSize(0, hfw)).height() |
579 | : hfw; |
580 | |
581 | if (hfw < 0) |
582 | hfw = 0; |
583 | return hfw; |
584 | } |
585 | |
586 | /*! |
587 | \reimp |
588 | */ |
589 | Qt::Orientations QSpacerItem::expandingDirections() const |
590 | { |
591 | return sizeP.expandingDirections(); |
592 | } |
593 | |
594 | /*! |
595 | \reimp |
596 | */ |
597 | Qt::Orientations QWidgetItem::expandingDirections() const |
598 | { |
599 | if (isEmpty()) |
600 | return {}; |
601 | |
602 | Qt::Orientations e = wid->sizePolicy().expandingDirections(); |
603 | /* |
604 | If the layout is expanding, we make the widget expanding, even if |
605 | its own size policy isn't expanding. |
606 | */ |
607 | if (wid->layout()) { |
608 | if (wid->sizePolicy().horizontalPolicy() & QSizePolicy::GrowFlag |
609 | && (wid->layout()->expandingDirections() & Qt::Horizontal)) |
610 | e |= Qt::Horizontal; |
611 | if (wid->sizePolicy().verticalPolicy() & QSizePolicy::GrowFlag |
612 | && (wid->layout()->expandingDirections() & Qt::Vertical)) |
613 | e |= Qt::Vertical; |
614 | } |
615 | |
616 | if (align & Qt::AlignHorizontal_Mask) |
617 | e &= ~Qt::Horizontal; |
618 | if (align & Qt::AlignVertical_Mask) |
619 | e &= ~Qt::Vertical; |
620 | return e; |
621 | } |
622 | |
623 | /*! |
624 | \reimp |
625 | */ |
626 | QSize QSpacerItem::minimumSize() const |
627 | { |
628 | return QSize(sizeP.horizontalPolicy() & QSizePolicy::ShrinkFlag ? 0 : width, |
629 | sizeP.verticalPolicy() & QSizePolicy::ShrinkFlag ? 0 : height); |
630 | } |
631 | |
632 | /*! |
633 | \reimp |
634 | */ |
635 | QSize QWidgetItem::minimumSize() const |
636 | { |
637 | if (isEmpty()) |
638 | return QSize(0, 0); |
639 | return !wid->testAttribute(attribute: Qt::WA_LayoutUsesWidgetRect) |
640 | ? toLayoutItemSize(priv: wid->d_func(), size: qSmartMinSize(i: this)) |
641 | : qSmartMinSize(i: this); |
642 | } |
643 | |
644 | /*! |
645 | \reimp |
646 | */ |
647 | QSize QSpacerItem::maximumSize() const |
648 | { |
649 | return QSize(sizeP.horizontalPolicy() & QSizePolicy::GrowFlag ? QLAYOUTSIZE_MAX : width, |
650 | sizeP.verticalPolicy() & QSizePolicy::GrowFlag ? QLAYOUTSIZE_MAX : height); |
651 | } |
652 | |
653 | /*! |
654 | \reimp |
655 | */ |
656 | QSize QWidgetItem::maximumSize() const |
657 | { |
658 | if (isEmpty()) { |
659 | return QSize(0, 0); |
660 | } else { |
661 | return !wid->testAttribute(attribute: Qt::WA_LayoutUsesWidgetRect) |
662 | ? toLayoutItemSize(priv: wid->d_func(), size: qSmartMaxSize(i: this, align)) |
663 | : qSmartMaxSize(i: this, align); |
664 | } |
665 | } |
666 | |
667 | /*! |
668 | \reimp |
669 | */ |
670 | QSize QSpacerItem::sizeHint() const |
671 | { |
672 | return QSize(width, height); |
673 | } |
674 | |
675 | /*! |
676 | \reimp |
677 | */ |
678 | QSize QWidgetItem::sizeHint() const |
679 | { |
680 | QSize s(0, 0); |
681 | if (!isEmpty()) { |
682 | s = wid->sizeHint().expandedTo(otherSize: wid->minimumSizeHint()); |
683 | s = s.boundedTo(otherSize: wid->maximumSize()) |
684 | .expandedTo(otherSize: wid->minimumSize()); |
685 | s = !wid->testAttribute(attribute: Qt::WA_LayoutUsesWidgetRect) |
686 | ? toLayoutItemSize(priv: wid->d_func(), size: s) |
687 | : s; |
688 | |
689 | if (wid->sizePolicy().horizontalPolicy() == QSizePolicy::Ignored) |
690 | s.setWidth(0); |
691 | if (wid->sizePolicy().verticalPolicy() == QSizePolicy::Ignored) |
692 | s.setHeight(0); |
693 | } |
694 | return s; |
695 | } |
696 | |
697 | /*! |
698 | Returns \c true. |
699 | */ |
700 | bool QSpacerItem::isEmpty() const |
701 | { |
702 | return true; |
703 | } |
704 | |
705 | /*! |
706 | Returns \c true if the widget is hidden; otherwise returns \c false. |
707 | |
708 | \sa QWidget::isHidden() |
709 | */ |
710 | bool QWidgetItem::isEmpty() const |
711 | { |
712 | return (wid->isHidden() && !wid->sizePolicy().retainSizeWhenHidden()) || wid->isWindow(); |
713 | } |
714 | |
715 | /*! |
716 | Returns the control type associated with the widget for which |
717 | this size policy applies. |
718 | |
719 | \sa QSizePolicy::controlType() |
720 | */ |
721 | QSizePolicy::ControlTypes QWidgetItem::controlTypes() const |
722 | { |
723 | return wid->sizePolicy().controlType(); |
724 | } |
725 | |
726 | /*! |
727 | \class QWidgetItemV2 |
728 | \internal |
729 | */ |
730 | |
731 | inline bool QWidgetItemV2::useSizeCache() const |
732 | { |
733 | return wid->d_func()->widgetItem == this; |
734 | } |
735 | |
736 | void QWidgetItemV2::updateCacheIfNecessary() const |
737 | { |
738 | if (q_cachedMinimumSize.width() != Dirty) |
739 | return; |
740 | |
741 | const QSize sizeHint(wid->sizeHint()); |
742 | const QSize minimumSizeHint(wid->minimumSizeHint()); |
743 | const QSize minimumSize(wid->minimumSize()); |
744 | const QSize maximumSize(wid->maximumSize()); |
745 | const QSizePolicy sizePolicy(wid->sizePolicy()); |
746 | const QSize expandedSizeHint(sizeHint.expandedTo(otherSize: minimumSizeHint)); |
747 | |
748 | const QSize smartMinSize(qSmartMinSize(sizeHint, minSizeHint: minimumSizeHint, minSize: minimumSize, maxSize: maximumSize, sizePolicy)); |
749 | const QSize smartMaxSize(qSmartMaxSize(sizeHint: expandedSizeHint, minSize: minimumSize, maxSize: maximumSize, sizePolicy, align)); |
750 | |
751 | const bool useLayoutItemRect = !wid->testAttribute(attribute: Qt::WA_LayoutUsesWidgetRect); |
752 | |
753 | q_cachedMinimumSize = useLayoutItemRect |
754 | ? toLayoutItemSize(priv: wid->d_func(), size: smartMinSize) |
755 | : smartMinSize; |
756 | |
757 | q_cachedSizeHint = expandedSizeHint; |
758 | q_cachedSizeHint = q_cachedSizeHint.boundedTo(otherSize: maximumSize) |
759 | .expandedTo(otherSize: minimumSize); |
760 | q_cachedSizeHint = useLayoutItemRect |
761 | ? toLayoutItemSize(priv: wid->d_func(), size: q_cachedSizeHint) |
762 | : q_cachedSizeHint; |
763 | |
764 | if (wid->sizePolicy().horizontalPolicy() == QSizePolicy::Ignored) |
765 | q_cachedSizeHint.setWidth(0); |
766 | if (wid->sizePolicy().verticalPolicy() == QSizePolicy::Ignored) |
767 | q_cachedSizeHint.setHeight(0); |
768 | |
769 | q_cachedMaximumSize = useLayoutItemRect |
770 | ? toLayoutItemSize(priv: wid->d_func(), size: smartMaxSize) |
771 | : smartMaxSize; |
772 | } |
773 | |
774 | QWidgetItemV2::QWidgetItemV2(QWidget *widget) |
775 | : QWidgetItem(widget), |
776 | q_cachedMinimumSize(Dirty, Dirty), |
777 | q_cachedSizeHint(Dirty, Dirty), |
778 | q_cachedMaximumSize(Dirty, Dirty), |
779 | q_firstCachedHfw(0), |
780 | q_hfwCacheSize(0), |
781 | d(nullptr) |
782 | { |
783 | QWidgetPrivate *wd = wid->d_func(); |
784 | if (!wd->widgetItem) |
785 | wd->widgetItem = this; |
786 | } |
787 | |
788 | QWidgetItemV2::~QWidgetItemV2() |
789 | { |
790 | if (wid) { |
791 | auto *wd = static_cast<QWidgetPrivate *>(QObjectPrivate::get(o: wid)); |
792 | if (wd->widgetItem == this) |
793 | wd->widgetItem = nullptr; |
794 | } |
795 | } |
796 | |
797 | QSize QWidgetItemV2::sizeHint() const |
798 | { |
799 | if (isEmpty()) |
800 | return QSize(0, 0); |
801 | |
802 | if (useSizeCache()) { |
803 | updateCacheIfNecessary(); |
804 | return q_cachedSizeHint; |
805 | } else { |
806 | return QWidgetItem::sizeHint(); |
807 | } |
808 | } |
809 | |
810 | QSize QWidgetItemV2::minimumSize() const |
811 | { |
812 | if (isEmpty()) |
813 | return QSize(0, 0); |
814 | |
815 | if (useSizeCache()) { |
816 | updateCacheIfNecessary(); |
817 | return q_cachedMinimumSize; |
818 | } else { |
819 | return QWidgetItem::minimumSize(); |
820 | } |
821 | } |
822 | |
823 | QSize QWidgetItemV2::maximumSize() const |
824 | { |
825 | if (isEmpty()) |
826 | return QSize(0, 0); |
827 | |
828 | if (useSizeCache()) { |
829 | updateCacheIfNecessary(); |
830 | return q_cachedMaximumSize; |
831 | } else { |
832 | return QWidgetItem::maximumSize(); |
833 | } |
834 | } |
835 | |
836 | /* |
837 | The height-for-width cache is organized as a circular buffer. The entries |
838 | |
839 | q_hfwCachedHfws[q_firstCachedHfw], |
840 | ..., |
841 | q_hfwCachedHfws[(q_firstCachedHfw + q_hfwCacheSize - 1) % HfwCacheMaxSize] |
842 | |
843 | contain the last cached values. When the cache is full, the first entry to |
844 | be erased is the entry before q_hfwCachedHfws[q_firstCachedHfw]. When |
845 | values are looked up, we try to move q_firstCachedHfw to point to that new |
846 | entry (unless the cache is not full, in which case it would leave the cache |
847 | in a broken state), so that the most recently used entry is also the last |
848 | to be erased. |
849 | */ |
850 | |
851 | int QWidgetItemV2::heightForWidth(int width) const |
852 | { |
853 | if (isEmpty()) |
854 | return -1; |
855 | |
856 | for (int i = 0; i < q_hfwCacheSize; ++i) { |
857 | int offset = q_firstCachedHfw + i; |
858 | const QSize &size = q_cachedHfws[offset % HfwCacheMaxSize]; |
859 | if (size.width() == width) { |
860 | if (q_hfwCacheSize == HfwCacheMaxSize) |
861 | q_firstCachedHfw = offset % HfwCacheMaxSize; |
862 | return size.height(); |
863 | } |
864 | } |
865 | |
866 | if (q_hfwCacheSize < HfwCacheMaxSize) |
867 | ++q_hfwCacheSize; |
868 | q_firstCachedHfw = (q_firstCachedHfw + HfwCacheMaxSize - 1) % HfwCacheMaxSize; |
869 | |
870 | int height = QWidgetItem::heightForWidth(w: width); |
871 | q_cachedHfws[q_firstCachedHfw] = QSize(width, height); |
872 | return height; |
873 | } |
874 | |
875 | QT_END_NAMESPACE |
876 | |