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 "qglobal.h"
41 
42 #include "qgraphicslayout.h"
43 #include "qgraphicsscene.h"
44 #include "qgraphicslayoutitem.h"
45 #include "qgraphicslayoutitem_p.h"
46 #include "qwidget.h"
47 #include "qgraphicswidget.h"
48 
49 #include <QtDebug>
50 
51 QT_BEGIN_NAMESPACE
52 
53 /*
54     COMBINE_SIZE() is identical to combineSize(), except that it
55     doesn't evaluate 'size' unless necessary.
56 */
57 #define COMBINE_SIZE(result, size) \
58     do { \
59         if ((result).width() < 0 || (result).height() < 0) \
60             combineSize((result), (size)); \
61     } while (false)
62 
combineSize(QSizeF & result,const QSizeF & size)63 static void combineSize(QSizeF &result, const QSizeF &size)
64 {
65     if (result.width() < 0)
66         result.setWidth(size.width());
67     if (result.height() < 0)
68         result.setHeight(size.height());
69 }
70 
boundSize(QSizeF & result,const QSizeF & size)71 static void boundSize(QSizeF &result, const QSizeF &size)
72 {
73     if (size.width() >= 0 && size.width() < result.width())
74         result.setWidth(size.width());
75     if (size.height() >= 0 && size.height() < result.height())
76         result.setHeight(size.height());
77 }
78 
expandSize(QSizeF & result,const QSizeF & size)79 static void expandSize(QSizeF &result, const QSizeF &size)
80 {
81     if (size.width() >= 0 && size.width() > result.width())
82         result.setWidth(size.width());
83     if (size.height() >= 0 && size.height() > result.height())
84         result.setHeight(size.height());
85 }
86 
normalizeHints(qreal & minimum,qreal & preferred,qreal & maximum,qreal & descent)87 static void normalizeHints(qreal &minimum, qreal &preferred, qreal &maximum, qreal &descent)
88 {
89     if (minimum >= 0 && maximum >= 0 && minimum > maximum)
90         minimum = maximum;
91 
92     if (preferred >= 0) {
93         if (minimum >= 0 && preferred < minimum) {
94             preferred = minimum;
95         } else if (maximum >= 0 && preferred > maximum) {
96             preferred = maximum;
97         }
98     }
99 
100     if (minimum >= 0 && descent > minimum)
101         descent = minimum;
102 }
103 
104 /*!
105     \internal
106 */
QGraphicsLayoutItemPrivate(QGraphicsLayoutItem * par,bool layout)107 QGraphicsLayoutItemPrivate::QGraphicsLayoutItemPrivate(QGraphicsLayoutItem *par, bool layout)
108     : parent(par), userSizeHints(nullptr), isLayout(layout), ownedByLayout(false), graphicsItem(nullptr)
109 {
110 }
111 
112 /*!
113     \internal
114 */
~QGraphicsLayoutItemPrivate()115 QGraphicsLayoutItemPrivate::~QGraphicsLayoutItemPrivate()
116 {
117     // Remove any lazily allocated data
118     delete[] userSizeHints;
119 }
120 
121 /*!
122     \internal
123 */
init()124 void QGraphicsLayoutItemPrivate::init()
125 {
126     sizeHintCacheDirty = true;
127     sizeHintWithConstraintCacheDirty = true;
128 }
129 
130 /*!
131     \internal
132 */
effectiveSizeHints(const QSizeF & constraint) const133 QSizeF *QGraphicsLayoutItemPrivate::effectiveSizeHints(const QSizeF &constraint) const
134 {
135     Q_Q(const QGraphicsLayoutItem);
136     QSizeF *sizeHintCache;
137     const bool hasConstraint = constraint.width() >= 0 || constraint.height() >= 0;
138     if (hasConstraint) {
139         if (!sizeHintWithConstraintCacheDirty && constraint == cachedConstraint)
140             return cachedSizeHintsWithConstraints;
141         sizeHintCache = cachedSizeHintsWithConstraints;
142     } else {
143         if (!sizeHintCacheDirty)
144             return cachedSizeHints;
145         sizeHintCache = cachedSizeHints;
146     }
147 
148     for (int i = 0; i < Qt::NSizeHints; ++i) {
149         sizeHintCache[i] = constraint;
150         if (userSizeHints)
151             combineSize(sizeHintCache[i], userSizeHints[i]);
152     }
153 
154     QSizeF &minS = sizeHintCache[Qt::MinimumSize];
155     QSizeF &prefS = sizeHintCache[Qt::PreferredSize];
156     QSizeF &maxS = sizeHintCache[Qt::MaximumSize];
157     QSizeF &descentS = sizeHintCache[Qt::MinimumDescent];
158 
159     normalizeHints(minS.rwidth(), prefS.rwidth(), maxS.rwidth(), descentS.rwidth());
160     normalizeHints(minS.rheight(), prefS.rheight(), maxS.rheight(), descentS.rheight());
161 
162     // if the minimum, preferred and maximum sizes contradict each other
163     // (e.g. the minimum is larger than the maximum) we give priority to
164     // the maximum size, then the minimum size and finally the preferred size
165     COMBINE_SIZE(maxS, q->sizeHint(Qt::MaximumSize, maxS));
166     combineSize(maxS, QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
167     expandSize(maxS, prefS);
168     expandSize(maxS, minS);
169     boundSize(maxS, QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
170 
171     COMBINE_SIZE(minS, q->sizeHint(Qt::MinimumSize, minS));
172     expandSize(minS, QSizeF(0, 0));
173     boundSize(minS, prefS);
174     boundSize(minS, maxS);
175 
176     COMBINE_SIZE(prefS, q->sizeHint(Qt::PreferredSize, prefS));
177     expandSize(prefS, minS);
178     boundSize(prefS, maxS);
179 
180     // Not supported yet
181     // COMBINE_SIZE(descentS, q->sizeHint(Qt::MinimumDescent, constraint));
182 
183     if (hasConstraint) {
184         cachedConstraint = constraint;
185         sizeHintWithConstraintCacheDirty = false;
186     } else {
187         sizeHintCacheDirty = false;
188     }
189     return sizeHintCache;
190 }
191 
192 
193 /*!
194     \internal
195 
196     Returns the parent item of this layout, or \nullptr if this layout is
197     not installed on any widget.
198 
199     If this is the item that the layout is installed on, it will return "itself".
200 
201     If the layout is a sub-layout, this function returns the parent
202     widget of the parent layout.
203 
204     Note that it will traverse up the layout item hierarchy instead of just calling
205     QGraphicsItem::parentItem(). This is on purpose.
206 
207     \sa parent()
208 */
parentItem() const209 QGraphicsItem *QGraphicsLayoutItemPrivate::parentItem() const
210 {
211     Q_Q(const QGraphicsLayoutItem);
212 
213     const QGraphicsLayoutItem *parent = q;
214     while (parent && parent->isLayout()) {
215         parent = parent->parentLayoutItem();
216     }
217     return parent ? parent->graphicsItem() : nullptr;
218 }
219 
220 /*!
221     \internal
222 
223      Ensures that userSizeHints is allocated.
224      This function must be called before any dereferencing.
225 */
ensureUserSizeHints()226 void QGraphicsLayoutItemPrivate::ensureUserSizeHints()
227 {
228     if (!userSizeHints)
229         userSizeHints = new QSizeF[Qt::NSizeHints];
230 }
231 
232 /*!
233     \internal
234 
235     Sets the user size hint \a which to \a size. Use an invalid size to unset the size hint.
236  */
setSize(Qt::SizeHint which,const QSizeF & size)237 void QGraphicsLayoutItemPrivate::setSize(Qt::SizeHint which, const QSizeF &size)
238 {
239     Q_Q(QGraphicsLayoutItem);
240 
241     if (userSizeHints) {
242         if (size == userSizeHints[which])
243             return;
244     } else if (size.width() < 0 && size.height() < 0) {
245         return;
246     }
247 
248     ensureUserSizeHints();
249     userSizeHints[which] = size;
250     q->updateGeometry();
251 }
252 
253 /*!
254     \internal
255 
256     Sets the width of the user size hint \a which to \a width.
257  */
setSizeComponent(Qt::SizeHint which,SizeComponent component,qreal value)258 void QGraphicsLayoutItemPrivate::setSizeComponent(
259     Qt::SizeHint which, SizeComponent component, qreal value)
260 {
261     Q_Q(QGraphicsLayoutItem);
262     ensureUserSizeHints();
263     qreal &userValue = (component == Width)
264         ? userSizeHints[which].rwidth()
265         : userSizeHints[which].rheight();
266     if (value == userValue)
267         return;
268     userValue = value;
269     q->updateGeometry();
270 }
271 
272 
hasHeightForWidth() const273 bool QGraphicsLayoutItemPrivate::hasHeightForWidth() const
274 {
275     Q_Q(const QGraphicsLayoutItem);
276     if (isLayout) {
277         const QGraphicsLayout *l = static_cast<const QGraphicsLayout *>(q);
278         for (int i = l->count() - 1; i >= 0; --i) {
279             if (QGraphicsLayoutItemPrivate::get(l->itemAt(i))->hasHeightForWidth())
280                 return true;
281         }
282     } else if (QGraphicsItem *item = q->graphicsItem()) {
283         if (item->isWidget()) {
284             QGraphicsWidget *w = static_cast<QGraphicsWidget *>(item);
285             if (w->layout()) {
286                 return QGraphicsLayoutItemPrivate::get(w->layout())->hasHeightForWidth();
287             }
288         }
289     }
290     return q->sizePolicy().hasHeightForWidth();
291 }
292 
hasWidthForHeight() const293 bool QGraphicsLayoutItemPrivate::hasWidthForHeight() const
294 {
295     Q_Q(const QGraphicsLayoutItem);
296     if (isLayout) {
297         const QGraphicsLayout *l = static_cast<const QGraphicsLayout *>(q);
298         for (int i = l->count() - 1; i >= 0; --i) {
299             if (QGraphicsLayoutItemPrivate::get(l->itemAt(i))->hasWidthForHeight())
300                 return true;
301         }
302     } else if (QGraphicsItem *item = q->graphicsItem()) {
303         if (item->isWidget()) {
304             QGraphicsWidget *w = static_cast<QGraphicsWidget *>(item);
305             if (w->layout()) {
306                 return QGraphicsLayoutItemPrivate::get(w->layout())->hasWidthForHeight();
307             }
308         }
309     }
310     return q->sizePolicy().hasWidthForHeight();
311 }
312 
313 /*!
314     \class QGraphicsLayoutItem
315     \brief The QGraphicsLayoutItem class can be inherited to allow your custom
316     items to be managed by layouts.
317     \since 4.4
318     \ingroup graphicsview-api
319     \inmodule QtWidgets
320 
321     QGraphicsLayoutItem is an abstract class that defines a set of virtual
322     functions describing sizes, size policies, and size hints for any object
323     arranged by QGraphicsLayout. The API contains functions relevant
324     for both the item itself and for the user of the item as most of
325     QGraphicsLayoutItem's functions are also part of the subclass' public API.
326 
327     In most cases, existing layout-aware classes such as QGraphicsWidget and
328     QGraphicsLayout already provide the functionality you require. However,
329     subclassing these classes will enable you to create both graphical
330     elements that work well with layouts (QGraphicsWidget) or custom layouts
331     (QGraphicsLayout).
332 
333     \section1 Subclassing QGraphicsLayoutItem
334 
335     If you create a subclass of QGraphicsLayoutItem and reimplement its
336     virtual functions, you will enable the layout to resize and position your
337     item along with other QGraphicsLayoutItems including QGraphicsWidget
338     and QGraphicsLayout.
339 
340     You can start by reimplementing important functions: the protected
341     sizeHint() function, as well as the public setGeometry()
342     function. If you want your items to be aware of immediate geometry
343     changes, you can also reimplement updateGeometry().
344 
345     The geometry, size hint, and size policy affect the item's size and
346     position. Calling setGeometry() will always resize and reposition the item
347     immediately. Normally, this function is called by QGraphicsLayout after
348     the layout has been activated, but it can also be called by the item's user
349     at any time.
350 
351     The sizeHint() function returns the item' minimum, preferred and maximum
352     size hints. You can override these properties by calling setMinimumSize(),
353     setPreferredSize() or setMaximumSize(). You can also use functions such as
354     setMinimumWidth() or setMaximumHeight() to set only the width or height
355     component if desired.
356 
357     The effectiveSizeHint() function, on the other hand, returns a size hint
358     for any given Qt::SizeHint, and guarantees that the returned size is bound
359     to the minimum and maximum sizes and size hints. You can set the item's
360     vertical and horizontal size policy by calling setSizePolicy(). The
361     sizePolicy property is used by the layout system to describe how this item
362     prefers to grow or shrink.
363 
364     \section1 Nesting QGraphicsLayoutItems
365 
366     QGraphicsLayoutItems can be nested within other QGraphicsLayoutItems,
367     similar to layouts that can contain sublayouts. This is done either by
368     passing a QGraphicsLayoutItem pointer to QGraphicsLayoutItem's
369     protected constructor, or by calling setParentLayoutItem(). The
370     parentLayoutItem() function returns a pointer to the item's layoutItem
371     parent. If the item's parent is \nullptr or if the parent does not inherit
372     from QGraphicsItem, the parentLayoutItem() function then returns \nullptr.
373     isLayout() returns \c true if the QGraphicsLayoutItem subclass is itself a
374     layout, or false otherwise.
375 
376     Qt uses QGraphicsLayoutItem to provide layout functionality in the
377     \l{Graphics View Framework}, but in the future its use may spread
378     throughout Qt itself.
379 
380     \sa QGraphicsWidget, QGraphicsLayout, QGraphicsLinearLayout,
381     QGraphicsGridLayout
382 */
383 
384 /*!
385     Constructs the QGraphicsLayoutItem object. \a parent becomes the object's
386     parent. If \a isLayout is true the item is a layout, otherwise
387     \a isLayout is false.
388 */
QGraphicsLayoutItem(QGraphicsLayoutItem * parent,bool isLayout)389 QGraphicsLayoutItem::QGraphicsLayoutItem(QGraphicsLayoutItem *parent, bool isLayout)
390     : d_ptr(new QGraphicsLayoutItemPrivate(parent, isLayout))
391 {
392     Q_D(QGraphicsLayoutItem);
393     d->init();
394     d->sizePolicy = QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
395     d->q_ptr = this;
396 }
397 
398 /*!
399     \internal
400 */
QGraphicsLayoutItem(QGraphicsLayoutItemPrivate & dd)401 QGraphicsLayoutItem::QGraphicsLayoutItem(QGraphicsLayoutItemPrivate &dd)
402     : d_ptr(&dd)
403 {
404     Q_D(QGraphicsLayoutItem);
405     d->init();
406     d->q_ptr = this;
407 }
408 
409 /*!
410     Destroys the QGraphicsLayoutItem object.
411 */
~QGraphicsLayoutItem()412 QGraphicsLayoutItem::~QGraphicsLayoutItem()
413 {
414     QGraphicsLayoutItem *parentLI = parentLayoutItem();
415     if (parentLI && parentLI->isLayout()) {
416         QGraphicsLayout *lay = static_cast<QGraphicsLayout*>(parentLI);
417         // this is not optimal
418         for (int i = lay->count() - 1; i >= 0; --i) {
419             if (lay->itemAt(i) == this) {
420                 lay->removeAt(i);
421                 break;
422             }
423         }
424     }
425 }
426 
427 /*!
428     \fn virtual QSizeF QGraphicsLayoutItem::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const = 0;
429 
430     This pure virtual function returns the size hint for \a which of the
431     QGraphicsLayoutItem, using the width or height of \a constraint to
432     constrain the output.
433 
434     Reimplement this function in a subclass of QGraphicsLayoutItem to
435     provide the necessary size hints for your items.
436 
437     \sa effectiveSizeHint()
438 */
439 
440 /*!
441     Sets the size policy to \a policy. The size policy describes how the item
442     should grow horizontally and vertically when arranged in a layout.
443 
444     QGraphicsLayoutItem's default size policy is (QSizePolicy::Fixed,
445     QSizePolicy::Fixed, QSizePolicy::DefaultType), but it is common for
446     subclasses to change the default. For example, QGraphicsWidget defaults
447     to (QSizePolicy::Preferred, QSizePolicy::Preferred,
448     QSizePolicy::DefaultType).
449 
450     \sa sizePolicy(), QWidget::sizePolicy()
451 */
setSizePolicy(const QSizePolicy & policy)452 void QGraphicsLayoutItem::setSizePolicy(const QSizePolicy &policy)
453 {
454     Q_D(QGraphicsLayoutItem);
455     if (d->sizePolicy == policy)
456         return;
457     d->sizePolicy = policy;
458     updateGeometry();
459 }
460 
461 /*!
462     \overload
463 
464     This function is equivalent to calling
465     setSizePolicy(QSizePolicy(\a hPolicy, \a vPolicy, \a controlType)).
466 
467     \sa sizePolicy(), QWidget::sizePolicy()
468 */
setSizePolicy(QSizePolicy::Policy hPolicy,QSizePolicy::Policy vPolicy,QSizePolicy::ControlType controlType)469 void QGraphicsLayoutItem::setSizePolicy(QSizePolicy::Policy hPolicy,
470                                         QSizePolicy::Policy vPolicy,
471                                         QSizePolicy::ControlType controlType)
472 {
473     setSizePolicy(QSizePolicy(hPolicy, vPolicy, controlType));
474 }
475 
476 /*!
477     Returns the current size policy.
478 
479     \sa setSizePolicy(), QWidget::sizePolicy()
480 */
sizePolicy() const481 QSizePolicy QGraphicsLayoutItem::sizePolicy() const
482 {
483     Q_D(const QGraphicsLayoutItem);
484     return d->sizePolicy;
485 }
486 
487 /*!
488     Sets the minimum size to \a size. This property overrides sizeHint() for
489     Qt::MinimumSize and ensures that effectiveSizeHint() will never return
490     a size smaller than \a size. In order to unset the minimum size, use an
491     invalid size.
492 
493     \sa minimumSize(), maximumSize(), preferredSize(), Qt::MinimumSize,
494     sizeHint(), setMinimumWidth(), setMinimumHeight()
495 */
setMinimumSize(const QSizeF & size)496 void QGraphicsLayoutItem::setMinimumSize(const QSizeF &size)
497 {
498     d_ptr->setSize(Qt::MinimumSize, size);
499 }
500 
501 /*!
502     \fn QGraphicsLayoutItem::setMinimumSize(qreal w, qreal h)
503 
504     This convenience function is equivalent to calling
505     setMinimumSize(QSizeF(\a w, \a h)).
506 
507     \sa minimumSize(), setMaximumSize(), setPreferredSize(), sizeHint()
508 */
509 
510 /*!
511     Returns the minimum size.
512 
513     \sa setMinimumSize(), preferredSize(), maximumSize(), Qt::MinimumSize,
514     sizeHint()
515 */
minimumSize() const516 QSizeF QGraphicsLayoutItem::minimumSize() const
517 {
518     return effectiveSizeHint(Qt::MinimumSize);
519 }
520 
521 /*!
522     Sets the minimum width to \a width.
523 
524     \sa minimumWidth(), setMinimumSize(), minimumSize()
525 */
setMinimumWidth(qreal width)526 void QGraphicsLayoutItem::setMinimumWidth(qreal width)
527 {
528     d_ptr->setSizeComponent(Qt::MinimumSize, d_ptr->Width, width);
529 }
530 
531 /*!
532     Sets the minimum height to \a height.
533 
534     \sa minimumHeight(), setMinimumSize(), minimumSize()
535 */
setMinimumHeight(qreal height)536 void QGraphicsLayoutItem::setMinimumHeight(qreal height)
537 {
538     d_ptr->setSizeComponent(Qt::MinimumSize, d_ptr->Height, height);
539 }
540 
541 
542 /*!
543     Sets the preferred size to \a size. This property overrides sizeHint() for
544     Qt::PreferredSize and provides the default value for effectiveSizeHint().
545     In order to unset the preferred size, use an invalid size.
546 
547     \sa preferredSize(), minimumSize(), maximumSize(), Qt::PreferredSize,
548     sizeHint()
549 */
setPreferredSize(const QSizeF & size)550 void QGraphicsLayoutItem::setPreferredSize(const QSizeF &size)
551 {
552     d_ptr->setSize(Qt::PreferredSize, size);
553 }
554 
555 /*!
556     \fn QGraphicsLayoutItem::setPreferredSize(qreal w, qreal h)
557 
558     This convenience function is equivalent to calling
559     setPreferredSize(QSizeF(\a w, \a h)).
560 
561     \sa preferredSize(), setMaximumSize(), setMinimumSize(), sizeHint()
562 */
563 
564 /*!
565     Returns the preferred size.
566 
567     \sa setPreferredSize(), minimumSize(), maximumSize(), Qt::PreferredSize,
568     sizeHint()
569 */
preferredSize() const570 QSizeF QGraphicsLayoutItem::preferredSize() const
571 {
572     return effectiveSizeHint(Qt::PreferredSize);
573 }
574 
575 /*!
576     Sets the preferred height to \a height.
577 
578     \sa preferredWidth(), setPreferredSize(), preferredSize()
579 */
setPreferredHeight(qreal height)580 void QGraphicsLayoutItem::setPreferredHeight(qreal height)
581 {
582     d_ptr->setSizeComponent(Qt::PreferredSize, d_ptr->Height, height);
583 }
584 
585 /*!
586     Sets the preferred width to \a width.
587 
588     \sa preferredHeight(), setPreferredSize(), preferredSize()
589 */
setPreferredWidth(qreal width)590 void QGraphicsLayoutItem::setPreferredWidth(qreal width)
591 {
592     d_ptr->setSizeComponent(Qt::PreferredSize, d_ptr->Width, width);
593 }
594 
595 /*!
596     Sets the maximum size to \a size. This property overrides sizeHint() for
597     Qt::MaximumSize and ensures that effectiveSizeHint() will never return a
598     size larger than \a size. In order to unset the maximum size, use an
599     invalid size.
600 
601     \sa maximumSize(), minimumSize(), preferredSize(), Qt::MaximumSize,
602     sizeHint()
603 */
setMaximumSize(const QSizeF & size)604 void QGraphicsLayoutItem::setMaximumSize(const QSizeF &size)
605 {
606     d_ptr->setSize(Qt::MaximumSize, size);
607 }
608 
609 /*!
610     \fn QGraphicsLayoutItem::setMaximumSize(qreal w, qreal h)
611 
612     This convenience function is equivalent to calling
613     setMaximumSize(QSizeF(\a w, \a h)).
614 
615     \sa maximumSize(), setMinimumSize(), setPreferredSize(), sizeHint()
616 */
617 
618 /*!
619     Returns the maximum size.
620 
621     \sa setMaximumSize(), minimumSize(), preferredSize(), Qt::MaximumSize,
622     sizeHint()
623 */
maximumSize() const624 QSizeF QGraphicsLayoutItem::maximumSize() const
625 {
626     return effectiveSizeHint(Qt::MaximumSize);
627 }
628 
629 /*!
630     Sets the maximum width to \a width.
631 
632     \sa maximumWidth(), setMaximumSize(), maximumSize()
633 */
setMaximumWidth(qreal width)634 void QGraphicsLayoutItem::setMaximumWidth(qreal width)
635 {
636     d_ptr->setSizeComponent(Qt::MaximumSize, d_ptr->Width, width);
637 }
638 
639 /*!
640     Sets the maximum height to \a height.
641 
642     \sa maximumHeight(), setMaximumSize(), maximumSize()
643 */
setMaximumHeight(qreal height)644 void QGraphicsLayoutItem::setMaximumHeight(qreal height)
645 {
646     d_ptr->setSizeComponent(Qt::MaximumSize, d_ptr->Height, height);
647 }
648 
649 /*!
650     \fn qreal QGraphicsLayoutItem::minimumWidth() const
651 
652     Returns the minimum width.
653 
654     \sa setMinimumWidth(), setMinimumSize(), minimumSize()
655 */
656 
657 /*!
658     \fn qreal QGraphicsLayoutItem::minimumHeight() const
659 
660     Returns the minimum height.
661 
662     \sa setMinimumHeight(), setMinimumSize(), minimumSize()
663 */
664 
665 /*!
666     \fn qreal QGraphicsLayoutItem::preferredWidth() const
667 
668     Returns the preferred width.
669 
670     \sa setPreferredWidth(), setPreferredSize(), preferredSize()
671 */
672 
673 /*!
674     \fn qreal QGraphicsLayoutItem::preferredHeight() const
675 
676     Returns the preferred height.
677 
678     \sa setPreferredHeight(), setPreferredSize(), preferredSize()
679 */
680 
681 /*!
682     \fn qreal QGraphicsLayoutItem::maximumWidth() const
683 
684     Returns the maximum width.
685 
686     \sa setMaximumWidth(), setMaximumSize(), maximumSize()
687 */
688 
689 /*!
690     \fn qreal QGraphicsLayoutItem::maximumHeight() const
691 
692     Returns the maximum height.
693 
694     \sa setMaximumHeight(), setMaximumSize(), maximumSize()
695 */
696 
697 /*!
698     \fn virtual void QGraphicsLayoutItem::setGeometry(const QRectF &rect)
699 
700     This virtual function sets the geometry of the QGraphicsLayoutItem to
701     \a rect, which is in parent coordinates (e.g., the top-left corner of \a rect
702     is equivalent to the item's position in parent coordinates).
703 
704     You must reimplement this function in a subclass of QGraphicsLayoutItem to
705     receive geometry updates. The layout will call this function when it does a
706     rearrangement.
707 
708     If \a rect is outside of the bounds of minimumSize and maximumSize, it
709     will be adjusted to its closest size so that it is within the legal
710     bounds.
711 
712     \sa geometry()
713 */
setGeometry(const QRectF & rect)714 void QGraphicsLayoutItem::setGeometry(const QRectF &rect)
715 {
716     Q_D(QGraphicsLayoutItem);
717     QSizeF effectiveSize = rect.size().expandedTo(effectiveSizeHint(Qt::MinimumSize))
718                                 .boundedTo(effectiveSizeHint(Qt::MaximumSize));
719     d->geom = QRectF(rect.topLeft(), effectiveSize);
720 }
721 
722 /*!
723     \fn QRectF QGraphicsLayoutItem::geometry() const
724 
725     Returns the item's geometry (e.g., position and size) as a
726     QRectF. This function is equivalent to QRectF(pos(), size()).
727 
728     \sa setGeometry()
729 */
geometry() const730 QRectF QGraphicsLayoutItem::geometry() const
731 {
732     Q_D(const QGraphicsLayoutItem);
733     return d->geom;
734 }
735 
736 /*!
737     This virtual function provides the \a left, \a top, \a right and \a bottom
738     contents margins for this QGraphicsLayoutItem. The default implementation
739     assumes all contents margins are 0. The parameters point to values stored
740     in qreals. If any of the pointers is \nullptr, that value will not be updated.
741 
742     \sa QGraphicsWidget::setContentsMargins()
743 */
getContentsMargins(qreal * left,qreal * top,qreal * right,qreal * bottom) const744 void QGraphicsLayoutItem::getContentsMargins(qreal *left, qreal *top, qreal *right, qreal *bottom) const
745 {
746     if (left)
747         *left = 0;
748     if (top)
749         *top = 0;
750     if (right)
751         *right = 0;
752     if (bottom)
753         *bottom = 0;
754 }
755 
756 /*!
757     Returns the contents rect in local coordinates.
758 
759     The contents rect defines the subrectangle used by an associated layout
760     when arranging subitems. This function is a convenience function that
761     adjusts the item's geometry() by its contents margins. Note that
762     getContentsMargins() is a virtual function that you can reimplement to
763     return the item's contents margins.
764 
765     \sa getContentsMargins(), geometry()
766 */
contentsRect() const767 QRectF QGraphicsLayoutItem::contentsRect() const
768 {
769     qreal left, top, right, bottom;
770     getContentsMargins(&left, &top, &right, &bottom);
771     return QRectF(QPointF(), geometry().size()).adjusted(+left, +top, -right, -bottom);
772 }
773 
774 /*!
775     Returns the effective size hint for this QGraphicsLayoutItem.
776 
777     \a which is the size hint in question.
778     \a constraint is an optional argument that defines a special constrain
779     when calculating the effective size hint. By default, \a constraint is
780     QSizeF(-1, -1), which means there is no constraint to the size hint.
781 
782     If you want to specify the widget's size hint for a given width or height,
783     you can provide the fixed dimension in \a constraint. This is useful for
784     widgets that can grow only either vertically or horizontally, and need to
785     set either their width or their height to a special value.
786 
787     For example, a text paragraph item fit into a column width of 200 may
788     grow vertically. You can pass QSizeF(200, -1) as a constraint to get a
789     suitable minimum, preferred and maximum height).
790 
791     You can adjust the effective size hint by reimplementing sizeHint()
792     in a QGraphicsLayoutItem subclass, or by calling one of the following
793     functions: setMinimumSize(), setPreferredSize, or setMaximumSize()
794     (or a combination of both).
795 
796     This function caches each of the size hints and guarantees that
797     sizeHint() will be called only once for each value of \a which - unless
798     \a constraint is not specified and updateGeometry() has been called.
799 
800     \sa sizeHint()
801 */
effectiveSizeHint(Qt::SizeHint which,const QSizeF & constraint) const802 QSizeF QGraphicsLayoutItem::effectiveSizeHint(Qt::SizeHint which, const QSizeF &constraint) const
803 {
804     Q_D(const QGraphicsLayoutItem);
805 
806     if (!d->userSizeHints && constraint.isValid())
807         return constraint;
808 
809     // ### should respect size policy???
810     return d_ptr->effectiveSizeHints(constraint)[which];
811 }
812 
813 /*!
814     This virtual function discards any cached size hint information. You
815     should always call this function if you change the return value of the
816     sizeHint() function. Subclasses must always call the base implementation
817     when reimplementing this function.
818 
819     \sa effectiveSizeHint()
820 */
updateGeometry()821 void QGraphicsLayoutItem::updateGeometry()
822 {
823     Q_D(QGraphicsLayoutItem);
824     d->sizeHintCacheDirty = true;
825     d->sizeHintWithConstraintCacheDirty = true;
826 }
827 
828 /*!
829     Returns the parent of this QGraphicsLayoutItem, or \nullptr if there is
830     no parent, or if the parent does not inherit from QGraphicsLayoutItem
831     (QGraphicsLayoutItem is often used through multiple inheritance with
832     QObject-derived classes).
833 
834     \sa setParentLayoutItem()
835 */
parentLayoutItem() const836 QGraphicsLayoutItem *QGraphicsLayoutItem::parentLayoutItem() const
837 {
838     return d_func()->parent;
839 }
840 
841 /*!
842     Sets the parent of this QGraphicsLayoutItem to \a parent.
843 
844     \sa parentLayoutItem()
845 */
setParentLayoutItem(QGraphicsLayoutItem * parent)846 void QGraphicsLayoutItem::setParentLayoutItem(QGraphicsLayoutItem *parent)
847 {
848     d_func()->parent = parent;
849 }
850 
851 /*!
852     Returns \c true if this QGraphicsLayoutItem is a layout (e.g., is inherited
853     by an object that arranges other QGraphicsLayoutItem objects); otherwise
854     returns \c false.
855 
856     \sa QGraphicsLayout
857 */
isLayout() const858 bool QGraphicsLayoutItem::isLayout() const
859 {
860     return d_func()->isLayout;
861 }
862 
863 /*!
864     \since 4.6
865 
866     Returns whether a layout should delete this item in its destructor.
867     If its true, then the layout will delete it. If its false, then it is
868     assumed that another object has the ownership of it, and the layout won't
869     delete this item.
870 
871     If the item inherits both QGraphicsItem and QGraphicsLayoutItem (such
872     as QGraphicsWidget does) the item is really part of two ownership
873     hierarchies. This property informs what the layout should do with its
874     child items when it is destructed. In the case of QGraphicsWidget, it
875     is preferred that when the layout is deleted it won't delete its children
876     (since they are also part of the graphics item hierarchy).
877 
878     By default this value is initialized to false in QGraphicsLayoutItem,
879     but it is overridden by QGraphicsLayout to return true. This is because
880     QGraphicsLayout is not normally part of the QGraphicsItem hierarchy, so the
881     parent layout should delete it.
882     Subclasses might override this default behaviour by calling
883     setOwnedByLayout(true).
884 
885     \sa setOwnedByLayout()
886 */
ownedByLayout() const887 bool QGraphicsLayoutItem::ownedByLayout() const
888 {
889     return d_func()->ownedByLayout;
890 }
891 /*!
892     \since 4.6
893 
894     Sets whether a layout should delete this item in its destructor or not.
895     \a ownership must be true to in order for the layout to delete it.
896     \sa ownedByLayout()
897 */
setOwnedByLayout(bool ownership)898 void QGraphicsLayoutItem::setOwnedByLayout(bool ownership)
899 {
900     d_func()->ownedByLayout = ownership;
901 }
902 
903 /*!
904  * Returns the QGraphicsItem that this layout item represents.
905  * For QGraphicsWidget it will return itself. For custom items it can return an
906  * aggregated value.
907  *
908  * \sa setGraphicsItem()
909  */
graphicsItem() const910 QGraphicsItem *QGraphicsLayoutItem::graphicsItem() const
911 {
912     return d_func()->graphicsItem;
913 }
914 
915 /*!
916  * If the QGraphicsLayoutItem represents a QGraphicsItem, and it wants to take
917  * advantage of the automatic reparenting capabilities of QGraphicsLayout it
918  * should set this value.
919  * Note that if you delete \a item and not delete the layout item, you are
920  * responsible of calling setGraphicsItem(\nullptr) in order to avoid having a
921  * dangling pointer.
922  *
923  * \sa graphicsItem()
924  */
setGraphicsItem(QGraphicsItem * item)925 void QGraphicsLayoutItem::setGraphicsItem(QGraphicsItem *item)
926 {
927     d_func()->graphicsItem = item;
928 }
929 
930 QT_END_NAMESPACE
931