source: trunk/src/gui/graphicsview/qgraphicslayoutitem.cpp@ 135

Last change on this file since 135 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 26.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
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
52#include <QtDebug>
53
54QT_BEGIN_NAMESPACE
55
56/*
57 COMBINE_SIZE() is identical to combineSize(), except that it
58 doesn't evaluate 'size' unless necessary.
59*/
60#define COMBINE_SIZE(result, size) \
61 do { \
62 if ((result).width() < 0 || (result).height() < 0) \
63 combineSize((result), (size)); \
64 } while (false)
65
66static void combineSize(QSizeF &result, const QSizeF &size)
67{
68 if (result.width() < 0)
69 result.setWidth(size.width());
70 if (result.height() < 0)
71 result.setHeight(size.height());
72}
73
74static void boundSize(QSizeF &result, const QSizeF &size)
75{
76 if (size.width() >= 0 && size.width() < result.width())
77 result.setWidth(size.width());
78 if (size.height() >= 0 && size.height() < result.height())
79 result.setHeight(size.height());
80}
81
82static void expandSize(QSizeF &result, const QSizeF &size)
83{
84 if (size.width() >= 0 && size.width() > result.width())
85 result.setWidth(size.width());
86 if (size.height() >= 0 && size.height() > result.height())
87 result.setHeight(size.height());
88}
89
90static void normalizeHints(qreal &minimum, qreal &preferred, qreal &maximum, qreal &descent)
91{
92 if (minimum >= 0 && maximum >= 0 && minimum > maximum)
93 minimum = maximum;
94
95 if (preferred >= 0) {
96 if (minimum >= 0 && preferred < minimum) {
97 preferred = minimum;
98 } else if (maximum >= 0 && preferred > maximum) {
99 preferred = maximum;
100 }
101 }
102
103 if (minimum >= 0 && descent > minimum)
104 descent = minimum;
105}
106
107/*!
108 \internal
109*/
110QGraphicsLayoutItemPrivate::QGraphicsLayoutItemPrivate(QGraphicsLayoutItem *par, bool layout)
111 : parent(par), isLayout(layout), ownedByLayout(false), graphicsItem(0)
112{
113}
114
115/*!
116 \internal
117*/
118void QGraphicsLayoutItemPrivate::init()
119{
120 sizeHintCacheDirty = true;
121 sizePolicy = QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
122}
123
124/*!
125 \internal
126*/
127QSizeF *QGraphicsLayoutItemPrivate::effectiveSizeHints(const QSizeF &constraint) const
128{
129 Q_Q(const QGraphicsLayoutItem);
130 if (!sizeHintCacheDirty && cachedConstraint == constraint)
131 return cachedSizeHints;
132
133 for (int i = 0; i < Qt::NSizeHints; ++i) {
134 cachedSizeHints[i] = constraint;
135 combineSize(cachedSizeHints[i], userSizeHints[i]);
136 }
137
138 QSizeF &minS = cachedSizeHints[Qt::MinimumSize];
139 QSizeF &prefS = cachedSizeHints[Qt::PreferredSize];
140 QSizeF &maxS = cachedSizeHints[Qt::MaximumSize];
141 QSizeF &descentS = cachedSizeHints[Qt::MinimumDescent];
142
143 normalizeHints(minS.rwidth(), prefS.rwidth(), maxS.rwidth(), descentS.rwidth());
144 normalizeHints(minS.rheight(), prefS.rheight(), maxS.rheight(), descentS.rheight());
145
146 // if the minimum, preferred and maximum sizes contradict each other
147 // (e.g. the minimum is larger than the maximum) we give priority to
148 // the maximum size, then the minimum size and finally the preferred size
149 COMBINE_SIZE(maxS, q->sizeHint(Qt::MaximumSize, maxS));
150 combineSize(maxS, QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
151 expandSize(maxS, prefS);
152 expandSize(maxS, minS);
153 boundSize(maxS, QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
154
155 COMBINE_SIZE(minS, q->sizeHint(Qt::MinimumSize, minS));
156 expandSize(minS, QSizeF(0, 0));
157 boundSize(minS, prefS);
158 boundSize(minS, maxS);
159
160 COMBINE_SIZE(prefS, q->sizeHint(Qt::PreferredSize, prefS));
161 expandSize(prefS, minS);
162 boundSize(prefS, maxS);
163
164 // Not supported yet
165 // COMBINE_SIZE(descentS, q->sizeHint(Qt::MinimumDescent, constraint));
166
167 cachedConstraint = constraint;
168 sizeHintCacheDirty = false;
169 return cachedSizeHints;
170}
171
172
173/*!
174 \internal
175
176 Returns the parent item of this layout, or 0 if this layout is
177 not installed on any widget.
178
179 If this is the item that the layout is installed on, it will return "itself".
180
181 If the layout is a sub-layout, this function returns the parent
182 widget of the parent layout.
183
184 Note that it will traverse up the layout item hierarchy instead of just calling
185 QGraphicsItem::parentItem(). This is on purpose.
186
187 \sa parent()
188*/
189QGraphicsItem *QGraphicsLayoutItemPrivate::parentItem() const
190{
191 Q_Q(const QGraphicsLayoutItem);
192
193 const QGraphicsLayoutItem *parent = q;
194 while (parent && parent->isLayout()) {
195 parent = parent->parentLayoutItem();
196 }
197 return parent ? parent->graphicsItem() : 0;
198}
199
200/*!
201 \class QGraphicsLayoutItem
202 \brief The QGraphicsLayoutItem class can be inherited to allow your custom
203 items to be managed by layouts.
204 \since 4.4
205 \ingroup multimedia
206 \ingroup graphicsview-api
207
208 QGraphicsLayoutItem is an abstract class that defines a set of virtual
209 functions describing sizes, size policies, and size hints for any object
210 arranged by QGraphicsLayout. The API contains functions relevant
211 for both the item itself and for the user of the item as most of
212 QGraphicsLayoutItem's functions are also part of the subclass' public API.
213
214 In most cases, existing layout-aware classes such as QGraphicsWidget and
215 QGraphicsLayout already provide the functionality you require. However,
216 subclassing these classes will enable you to create both graphical
217 elements that work well with layouts (QGraphicsWidget) or custom layouts
218 (QGraphicsLayout).
219
220 \section1 Subclassing QGraphicsLayoutItem
221
222 If you create a subclass of QGraphicsLayoutItem and reimplement its
223 virtual functions, you will enable the layout to resize and position your
224 item along with other QGraphicsLayoutItems including QGraphicsWidget
225 and QGraphicsLayout.
226
227 You can start by reimplementing important functions: the protected
228 sizeHint() function, as well as the public setGeometry()
229 function. If you want your items to be aware of immediate geometry
230 changes, you can also reimplement updateGeometry().
231
232 The geometry, size hint, and size policy affect the item's size and
233 position. Calling setGeometry() will always resize and reposition the item
234 immediately. Normally, this function is called by QGraphicsLayout after
235 the layout has been activated, but it can also be called by the item's user
236 at any time.
237
238 The sizeHint() function returns the item' minimum, preferred and maximum
239 size hints. You can override these properties by calling setMinimumSize(),
240 setPreferredSize() or setMaximumSize(). You can also use functions such as
241 setMinimumWidth() or setMaximumHeight() to set only the width or height
242 component if desired.
243
244 The effectiveSizeHint() function, on the other hand, returns a size hint
245 for any given Qt::SizeHint, and guarantees that the returned size is bound
246 to the minimum and maximum sizes and size hints. You can set the item's
247 vertical and horizontal size policy by calling setSizePolicy(). The
248 sizePolicy property is used by the layout system to describe how this item
249 prefers to grow or shrink.
250
251 \section1 Nesting QGraphicsLayoutItems
252
253 QGraphicsLayoutItems can be nested within other QGraphicsLayoutItems,
254 similar to layouts that can contain sublayouts. This is done either by
255 passing a QGraphicsLayoutItem pointer to QGraphicsLayoutItem's
256 protected constructor, or by calling setParentLayoutItem(). The
257 parentLayoutItem() function returns a pointer to the item's layoutItem
258 parent. If the item's parent is 0 or if the the parent does not inherit
259 from QGraphicsItem, the parentLayoutItem() function then returns 0.
260 isLayout() returns true if the QGraphicsLayoutItem subclass is itself a
261 layout, or false otherwise.
262
263 Qt uses QGraphicsLayoutItem to provide layout functionality in the
264 \l{The Graphics View Framework}, but in the future its use may spread
265 throughout Qt itself.
266
267 \sa QGraphicsWidget, QGraphicsLayout, QGraphicsLinearLayout,
268 QGraphicsGridLayout
269*/
270
271/*!
272 Constructs the QGraphicsLayoutItem object. \a parent becomes the object's
273 parent. If \a isLayout is true the item is a layout, otherwise
274 \a isLayout is false.
275*/
276QGraphicsLayoutItem::QGraphicsLayoutItem(QGraphicsLayoutItem *parent, bool isLayout)
277 : d_ptr(new QGraphicsLayoutItemPrivate(parent, isLayout))
278{
279 Q_D(QGraphicsLayoutItem);
280 d->init();
281 d->q_ptr = this;
282}
283
284/*!
285 \internal
286*/
287QGraphicsLayoutItem::QGraphicsLayoutItem(QGraphicsLayoutItemPrivate &dd)
288 : d_ptr(&dd)
289{
290 Q_D(QGraphicsLayoutItem);
291 d->q_ptr = this;
292}
293
294/*!
295 Destroys the QGraphicsLayoutItem object.
296*/
297QGraphicsLayoutItem::~QGraphicsLayoutItem()
298{
299 QGraphicsLayoutItem *parentLI = parentLayoutItem();
300 if (parentLI && parentLI->isLayout()) {
301 QGraphicsLayout *lay = static_cast<QGraphicsLayout*>(parentLI);
302 // this is not optimal
303 for (int i = lay->count() - 1; i >= 0; --i) {
304 if (lay->itemAt(i) == this) {
305 lay->removeAt(i);
306 break;
307 }
308 }
309 }
310 delete d_ptr;
311}
312
313/*!
314 \fn virtual QSizeF QGraphicsLayoutItem::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const = 0;
315
316 This pure virtual function returns the size hint for \a which of the
317 QGraphicsLayoutItem, using the width or height of \a constraint to
318 constrain the output.
319
320 Reimplement this function in a subclass of QGraphicsLayoutItem to
321 provide the necessary size hints for your items.
322
323 \sa effectiveSizeHint()
324*/
325
326/*!
327 Sets the size policy to \a policy. The size policy describes how the item
328 should grow horizontally and vertically when arranged in a layout.
329
330 QGraphicsLayoutItem's default size policy is (QSizePolicy::Fixed,
331 QSizePolicy::Fixed, QSizePolicy::DefaultType), but it is common for
332 subclasses to change the default. For example, QGraphicsWidget defaults
333 to (QSizePolicy::Preferred, QSizePolicy::Preferred,
334 QSizePolicy::DefaultType).
335
336 \sa sizePolicy(), QWidget::sizePolicy()
337*/
338void QGraphicsLayoutItem::setSizePolicy(const QSizePolicy &policy)
339{
340 Q_D(QGraphicsLayoutItem);
341 if (d->sizePolicy == policy)
342 return;
343 d->sizePolicy = policy;
344 updateGeometry();
345}
346
347/*!
348 \overload
349
350 This function is equivalent to calling
351 setSizePolicy(QSizePolicy(\a hPolicy, \a vPolicy, \a controlType)).
352
353 \sa sizePolicy(), QWidget::sizePolicy()
354*/
355void QGraphicsLayoutItem::setSizePolicy(QSizePolicy::Policy hPolicy,
356 QSizePolicy::Policy vPolicy,
357 QSizePolicy::ControlType controlType)
358{
359 setSizePolicy(QSizePolicy(hPolicy, vPolicy, controlType));
360}
361
362/*!
363 Returns the current size policy.
364
365 \sa setSizePolicy(), QWidget::sizePolicy()
366*/
367QSizePolicy QGraphicsLayoutItem::sizePolicy() const
368{
369 Q_D(const QGraphicsLayoutItem);
370 return d->sizePolicy;
371}
372
373/*!
374 Sets the minimum size to \a size. This property overrides sizeHint() for
375 Qt::MinimumSize and ensures that effectiveSizeHint() will never return
376 a size smaller than \a size. In order to unset the minimum size, use an
377 invalid size.
378
379 \sa minimumSize(), maximumSize(), preferredSize(), Qt::MinimumSize,
380 sizeHint(), setMinimumWidth(), setMinimumHeight()
381*/
382void QGraphicsLayoutItem::setMinimumSize(const QSizeF &size)
383{
384 Q_D(QGraphicsLayoutItem);
385 if (size == d->userSizeHints[Qt::MinimumSize])
386 return;
387
388 d->userSizeHints[Qt::MinimumSize] = size;
389 updateGeometry();
390}
391
392/*!
393 \fn QGraphicsLayoutItem::setMinimumSize(qreal w, qreal h)
394
395 This convenience function is equivalent to calling
396 setMinimumSize(QSizeF(\a w, \a h)).
397
398 \sa minimumSize(), setMaximumSize(), setPreferredSize(), sizeHint()
399*/
400
401/*!
402 Returns the minimum size.
403
404 \sa setMinimumSize(), preferredSize(), maximumSize(), Qt::MinimumSize,
405 sizeHint()
406*/
407QSizeF QGraphicsLayoutItem::minimumSize() const
408{
409 return effectiveSizeHint(Qt::MinimumSize);
410}
411
412/*!
413 Sets the minimum width to \a width.
414
415 \sa minimumWidth(), setMinimumSize(), minimumSize()
416*/
417void QGraphicsLayoutItem::setMinimumWidth(qreal width)
418{
419 Q_D(QGraphicsLayoutItem);
420 qreal &userSizeHint = d->userSizeHints[Qt::MinimumSize].rwidth();
421 if (width == userSizeHint)
422 return;
423 userSizeHint = width;
424 updateGeometry();
425}
426
427/*!
428 Sets the minimum height to \a height.
429
430 \sa minimumHeight(), setMinimumSize(), minimumSize()
431*/
432void QGraphicsLayoutItem::setMinimumHeight(qreal height)
433{
434 Q_D(QGraphicsLayoutItem);
435 qreal &userSizeHint = d->userSizeHints[Qt::MinimumSize].rheight();
436 if (height == userSizeHint)
437 return;
438 userSizeHint = height;
439 updateGeometry();
440}
441
442
443/*!
444 Sets the preferred size to \a size. This property overrides sizeHint() for
445 Qt::PreferredSize and provides the default value for effectiveSizeHint().
446 In order to unset the preferred size, use an invalid size.
447
448 \sa preferredSize(), minimumSize(), maximumSize(), Qt::PreferredSize,
449 sizeHint()
450*/
451void QGraphicsLayoutItem::setPreferredSize(const QSizeF &size)
452{
453 Q_D(QGraphicsLayoutItem);
454 if (size == d->userSizeHints[Qt::PreferredSize])
455 return;
456
457 d->userSizeHints[Qt::PreferredSize] = size;
458 updateGeometry();
459}
460
461/*!
462 \fn QGraphicsLayoutItem::setPreferredSize(qreal w, qreal h)
463
464 This convenience function is equivalent to calling
465 setPreferredSize(QSizeF(\a w, \a h)).
466
467 \sa preferredSize(), setMaximumSize(), setMinimumSize(), sizeHint()
468*/
469
470/*!
471 Returns the preferred size.
472
473 \sa setPreferredSize(), minimumSize(), maximumSize(), Qt::PreferredSize,
474 sizeHint()
475*/
476QSizeF QGraphicsLayoutItem::preferredSize() const
477{
478 return effectiveSizeHint(Qt::PreferredSize);
479}
480
481/*!
482 Sets the preferred height to \a height.
483
484 \sa preferredWidth(), setPreferredSize(), preferredSize()
485*/
486void QGraphicsLayoutItem::setPreferredHeight(qreal height)
487{
488 Q_D(QGraphicsLayoutItem);
489 qreal &userSizeHint = d->userSizeHints[Qt::PreferredSize].rheight();
490 if (height == userSizeHint)
491 return;
492 userSizeHint = height;
493 updateGeometry();
494}
495
496/*!
497 Sets the preferred width to \a width.
498
499 \sa preferredHeight(), setPreferredSize(), preferredSize()
500*/
501void QGraphicsLayoutItem::setPreferredWidth(qreal width)
502{
503 Q_D(QGraphicsLayoutItem);
504 qreal &userSizeHint = d->userSizeHints[Qt::PreferredSize].rwidth();
505 if (width == userSizeHint)
506 return;
507 userSizeHint = width;
508 updateGeometry();
509}
510
511/*!
512 Sets the maximum size to \a size. This property overrides sizeHint() for
513 Qt::MaximumSize and ensures that effectiveSizeHint() will never return a
514 size larger than \a size. In order to unset the maximum size, use an
515 invalid size.
516
517 \sa maximumSize(), minimumSize(), preferredSize(), Qt::MaximumSize,
518 sizeHint()
519*/
520void QGraphicsLayoutItem::setMaximumSize(const QSizeF &size)
521{
522 Q_D(QGraphicsLayoutItem);
523 if (size == d->userSizeHints[Qt::MaximumSize])
524 return;
525
526 d->userSizeHints[Qt::MaximumSize] = size;
527 updateGeometry();
528}
529
530/*!
531 \fn QGraphicsLayoutItem::setMaximumSize(qreal w, qreal h)
532
533 This convenience function is equivalent to calling
534 setMaximumSize(QSizeF(\a w, \a h)).
535
536 \sa maximumSize(), setMinimumSize(), setPreferredSize(), sizeHint()
537*/
538
539/*!
540 Returns the maximum size.
541
542 \sa setMaximumSize(), minimumSize(), preferredSize(), Qt::MaximumSize,
543 sizeHint()
544*/
545QSizeF QGraphicsLayoutItem::maximumSize() const
546{
547 return effectiveSizeHint(Qt::MaximumSize);
548}