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