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