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

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

trunk: Merged in qt 4.6.2 sources.

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