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