source: trunk/src/gui/graphicsview/qgraphicslinearlayout.cpp@ 1006

Last change on this file since 1006 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 17.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
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 qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42/*!
43 \class QGraphicsLinearLayout
44 \brief The QGraphicsLinearLayout class provides a horizontal or vertical
45 layout for managing widgets in Graphics View.
46 \since 4.4
47 \ingroup graphicsview-api
48
49 The default orientation for a linear layout is Qt::Horizontal. You can
50 choose a vertical orientation either by calling setOrientation(), or by
51 passing Qt::Vertical to QGraphicsLinearLayout's constructor.
52
53 The most common way to use QGraphicsLinearLayout is to construct an object
54 on the heap with no parent, add widgets and layouts by calling addItem(),
55 and finally assign the layout to a widget by calling
56 QGraphicsWidget::setLayout().
57
58 \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicslinearlayout.cpp 0
59
60 You can add widgets, layouts, stretches (addStretch(), insertStretch() or
61 setStretchFactor()), and spacings (setItemSpacing()) to a linear
62 layout. The layout takes ownership of the items. In some cases when the layout
63 item also inherits from QGraphicsItem (such as QGraphicsWidget) there will be a
64 ambiguity in ownership because the layout item belongs to two ownership hierarchies.
65 See the documentation of QGraphicsLayoutItem::setOwnedByLayout() how to handle
66 this.
67 You can access each item in the layout by calling count() and itemAt(). Calling
68 removeAt() or removeItem() will remove an item from the layout, without
69 destroying it.
70
71 \section1 Size Hints and Size Policies in QGraphicsLinearLayout
72
73 QGraphicsLinearLayout respects each item's size hints and size policies,
74 and when the layout contains more space than the items can fill, each item
75 is arranged according to the layout's alignment for that item. You can set
76 an alignment for each item by calling setAlignment(), and check the
77 alignment for any item by calling alignment(). By default, items are
78 aligned to the top left.
79
80 \section1 Spacing within QGraphicsLinearLayout
81
82 Between the items, the layout distributes some space. The actual amount of
83 space depends on the managed widget's current style, but the common
84 spacing is 4. You can also set your own spacing by calling setSpacing(),
85 and get the current spacing value by calling spacing(). If you want to
86 configure individual spacing for your items, you can call setItemSpacing().
87
88 \section1 Stretch Factor in QGraphicsLinearLayout
89
90 You can assign a stretch factor to each item to control how much space it
91 will get compared to the other items. By default, two identical widgets
92 arranged in a linear layout will have the same size, but if the first
93 widget has a stretch factor of 1 and the second widget has a stretch
94 factor of 2, the first widget will get 1/3 of the available space, and the
95 second will get 2/3.
96
97 QGraphicsLinearLayout calculates the distribution of sizes by adding up
98 the stretch factors of all items, and then dividing the available space
99 accordingly. The default stretch factor is 0 for all items; a factor of 0
100 means the item does not have any defined stretch factor; effectively this
101 is the same as setting the stretch factor to 1. The stretch factor only
102 applies to the available space in the lengthwise direction of the layout
103 (following its orientation). If you want to control both the item's
104 horizontal and vertical stretch, you can use QGraphicsGridLayout instead.
105
106 \section1 QGraphicsLinearLayout Compared to Other Layouts
107
108 QGraphicsLinearLayout is very similar to QVBoxLayout and QHBoxLayout, but
109 in contrast to these classes, it is used to manage QGraphicsWidget and
110 QGraphicsLayout instead of QWidget and QLayout.
111
112 \sa QGraphicsGridLayout, QGraphicsWidget
113*/
114
115#include "qapplication.h"
116
117#ifndef QT_NO_GRAPHICSVIEW
118
119#include "qwidget.h"
120#include "qgraphicslayout_p.h"
121#include "qgraphicslayoutitem.h"
122#include "qgraphicslinearlayout.h"
123#include "qgraphicswidget.h"
124#include "qgridlayoutengine_p.h"
125#ifdef QT_DEBUG
126#include <QtCore/qdebug.h>
127#endif
128
129QT_BEGIN_NAMESPACE
130
131class QGraphicsLinearLayoutPrivate : public QGraphicsLayoutPrivate
132{
133public:
134 QGraphicsLinearLayoutPrivate(Qt::Orientation orientation) : orientation(orientation) { }
135
136 void removeGridItem(QGridLayoutItem *gridItem);
137 QLayoutStyleInfo styleInfo() const;
138 void fixIndex(int *index) const;
139 int gridRow(int index) const;
140 int gridColumn(int index) const;
141
142 Qt::Orientation orientation;
143 QGridLayoutEngine engine;
144};
145
146void QGraphicsLinearLayoutPrivate::removeGridItem(QGridLayoutItem *gridItem)
147{
148 int index = gridItem->firstRow(orientation);
149 engine.removeItem(gridItem);
150 engine.removeRows(index, 1, orientation);
151}
152
153void QGraphicsLinearLayoutPrivate::fixIndex(int *index) const
154{
155 int count = engine.rowCount(orientation);
156 if (uint(*index) > uint(count))
157 *index = count;
158}
159
160int QGraphicsLinearLayoutPrivate::gridRow(int index) const
161{
162 if (orientation == Qt::Horizontal)
163 return 0;
164 return int(qMin(uint(index), uint(engine.rowCount())));
165}
166
167int QGraphicsLinearLayoutPrivate::gridColumn(int index) const
168{
169 if (orientation == Qt::Vertical)
170 return 0;
171 return int(qMin(uint(index), uint(engine.columnCount())));
172}
173
174Q_GLOBAL_STATIC(QWidget, globalStyleInfoWidget)
175
176QLayoutStyleInfo QGraphicsLinearLayoutPrivate::styleInfo() const
177{
178 QGraphicsItem *item = parentItem();
179 QStyle *style = (item && item->isWidget()) ? static_cast<QGraphicsWidget*>(item)->style() : QApplication::style();
180 return QLayoutStyleInfo(style, globalStyleInfoWidget());
181}
182
183/*!
184 Constructs a QGraphicsLinearLayout instance. You can pass the
185 \a orientation for the layout, either horizontal or vertical, and
186 \a parent is passed to QGraphicsLayout's constructor.
187*/
188QGraphicsLinearLayout::QGraphicsLinearLayout(Qt::Orientation orientation, QGraphicsLayoutItem *parent)
189 : QGraphicsLayout(*new QGraphicsLinearLayoutPrivate(orientation), parent)
190{
191}
192
193/*!
194 Constructs a QGraphicsLinearLayout instance using Qt::Horizontal
195 orientation. \a parent is passed to QGraphicsLayout's constructor.
196*/
197QGraphicsLinearLayout::QGraphicsLinearLayout(QGraphicsLayoutItem *parent)
198 : QGraphicsLayout(*new QGraphicsLinearLayoutPrivate(Qt::Horizontal), parent)
199{
200}
201
202/*!
203 Destroys the QGraphicsLinearLayout object.
204*/
205QGraphicsLinearLayout::~QGraphicsLinearLayout()
206{
207 for (int i = count() - 1; i >= 0; --i) {
208 QGraphicsLayoutItem *item = itemAt(i);
209 // The following lines can be removed, but this removes the item
210 // from the layout more efficiently than the implementation of
211 // ~QGraphicsLayoutItem.
212 removeAt(i);
213 if (item) {
214 item->setParentLayoutItem(0);
215 if (item->ownedByLayout())
216 delete item;
217 }
218 }
219}
220
221/*!
222 Change the layout orientation to \a orientation. Changing the layout
223 orientation will automatically invalidate the layout.
224
225 \sa orientation()
226*/
227void QGraphicsLinearLayout::setOrientation(Qt::Orientation orientation)
228{
229 Q_D(QGraphicsLinearLayout);
230 if (orientation != d->orientation) {
231 d->engine.transpose();
232 d->orientation = orientation;
233 invalidate();
234 }
235}
236
237/*!
238 Returns the layout orientation.
239 \sa setOrientation()
240 */
241Qt::Orientation QGraphicsLinearLayout::orientation() const
242{
243 Q_D(const QGraphicsLinearLayout);
244 return d->orientation;
245}
246
247/*!
248 \fn void QGraphicsLinearLayout::addItem(QGraphicsLayoutItem *item)
249
250 This convenience function is equivalent to calling
251 insertItem(-1, \a item).
252*/
253
254/*!
255 \fn void QGraphicsLinearLayout::addStretch(int stretch)
256
257 This convenience function is equivalent to calling
258 insertStretch(-1, \a stretch).
259*/
260
261/*!
262 Inserts \a item into the layout at \a index, or before any item that is
263 currently at \a index.
264
265 \sa addItem(), itemAt(), insertStretch(), setItemSpacing()
266*/
267void QGraphicsLinearLayout::insertItem(int index, QGraphicsLayoutItem *item)
268{
269 Q_D(QGraphicsLinearLayout);
270 if (!item) {
271 qWarning("QGraphicsLinearLayout::insertItem: cannot insert null item");
272 return;
273 }
274 if (item == this) {
275 qWarning("QGraphicsLinearLayout::insertItem: cannot insert itself");
276 return;
277 }
278 Q_ASSERT(item);
279
280 //the order of the following instructions is very important because
281 //invalidating the layout before adding the child item will make the layout happen
282 //before we try to paint the item
283 invalidate();
284 d->addChildLayoutItem(item);
285
286 d->fixIndex(&index);
287 d->engine.insertRow(index, d->orientation);
288 new QGridLayoutItem(&d->engine, item, d->gridRow(index), d->gridColumn(index), 1, 1, 0, index);
289}
290
291/*!
292 Inserts a stretch of \a stretch at \a index, or before any item that is
293 currently at \a index.
294
295 \sa addStretch(), setStretchFactor(), setItemSpacing(), insertItem()
296*/
297void QGraphicsLinearLayout::insertStretch(int index, int stretch)
298{
299 Q_D(QGraphicsLinearLayout);
300 d->fixIndex(&index);
301 d->engine.insertRow(index, d->orientation);
302 d->engine.setRowStretchFactor(index, stretch, d->orientation);
303 invalidate();
304}
305
306/*!
307 Removes \a item from the layout without destroying it. Ownership of
308 \a item is transferred to the caller.
309
310 \sa removeAt(), insertItem()
311*/
312void QGraphicsLinearLayout::removeItem(QGraphicsLayoutItem *item)
313{
314 Q_D(QGraphicsLinearLayout);
315 if (QGridLayoutItem *gridItem = d->engine.findLayoutItem(item)) {
316 item->setParentLayoutItem(0);
317 d->removeGridItem(gridItem);
318 delete gridItem;
319 invalidate();
320 }
321}
322
323/*!
324 Removes the item at \a index without destroying it. Ownership of the item
325 is transferred to the caller.
326
327 \sa removeItem(), insertItem()
328*/
329void QGraphicsLinearLayout::removeAt(int index)
330{
331 Q_D(QGraphicsLinearLayout);
332 if (index < 0 || index >= d->engine.itemCount()) {
333 qWarning("QGraphicsLinearLayout::removeAt: invalid index %d", index);
334 return;
335 }
336 if (QGridLayoutItem *gridItem = d->engine.itemAt(index)) {
337 if (QGraphicsLayoutItem *layoutItem = gridItem->layoutItem())
338 layoutItem->setParentLayoutItem(0);
339 d->removeGridItem(gridItem);
340 delete gridItem;
341 invalidate();
342 }
343}
344
345/*!
346 Sets the layout's spacing to \a spacing. Spacing refers to the
347 vertical and horizontal distances between items.
348
349 \sa setItemSpacing(), setStretchFactor(), QGraphicsGridLayout::setSpacing()
350*/
351void QGraphicsLinearLayout::setSpacing(qreal spacing)
352{
353 Q_D(QGraphicsLinearLayout);
354 if (spacing < 0) {
355 qWarning("QGraphicsLinearLayout::setSpacing: invalid spacing %g", spacing);
356 return;
357 }
358 d->engine.setSpacing(spacing, Qt::Horizontal | Qt::Vertical);
359 invalidate();
360}
361
362/*!
363 Returns the layout's spacing. Spacing refers to the
364 vertical and horizontal distances between items.
365
366 \sa setSpacing()
367 */
368qreal QGraphicsLinearLayout::spacing() const
369{
370 Q_D(const QGraphicsLinearLayout);
371 return d->engine.spacing(d->styleInfo(), d->orientation);
372}
373
374/*!
375 Sets the spacing after item at \a index to \a spacing.
376*/
377void QGraphicsLinearLayout::setItemSpacing(int index, qreal spacing)
378{
379 Q_D(QGraphicsLinearLayout);
380 d->engine.setRowSpacing(index, spacing, d->orientation);
381 invalidate();
382}
383/*!
384 Returns the spacing after item at \a index.
385*/
386qreal QGraphicsLinearLayout::itemSpacing(int index) const
387{
388 Q_D(const QGraphicsLinearLayout);
389 return d->engine.rowSpacing(index, d->orientation);
390}
391
392/*!
393 Sets the stretch factor for \a item to \a stretch. If an item's stretch
394 factor changes, this function will invalidate the layout.
395
396 Setting \a stretch to 0 removes the stretch factor from the item, and is
397 effectively equivalent to setting \a stretch to 1.
398
399 \sa stretchFactor()
400*/
401void QGraphicsLinearLayout::setStretchFactor(QGraphicsLayoutItem *item, int stretch)
402{
403 Q_D(QGraphicsLinearLayout);
404 if (!item) {
405 qWarning("QGraphicsLinearLayout::setStretchFactor: cannot assign"
406 " a stretch factor to a null item");
407 return;
408 }
409 if (stretchFactor(item) == stretch)
410 return;
411 d->engine.setStretchFactor(item, stretch, d->orientation);
412 invalidate();
413}
414
415/*!
416 Returns the stretch factor for \a item. The default stretch factor is 0,
417 meaning that the item has no assigned stretch factor.
418
419 \sa setStretchFactor()
420*/
421int QGraphicsLinearLayout::stretchFactor(QGraphicsLayoutItem *item) const
422{
423 Q_D(const QGraphicsLinearLayout);
424 if (!item) {
425 qWarning("QGraphicsLinearLayout::setStretchFactor: cannot return"
426 " a stretch factor for a null item");
427 return 0;
428 }
429 return d->engine.stretchFactor(item, d->orientation);
430}
431
432/*!
433 Sets the alignment of \a item to \a alignment. If \a item's alignment
434 changes, the layout is automatically invalidated.
435
436 \sa alignment(), invalidate()
437*/
438void QGraphicsLinearLayout::setAlignment(QGraphicsLayoutItem *item, Qt::Alignment alignment)
439{
440 Q_D(QGraphicsLinearLayout);
441 if (this->alignment(item) == alignment)
442 return;
443 d->engine.setAlignment(item, alignment);
444 invalidate();
445}
446
447/*!
448 Returns the alignment for \a item. The default alignment is
449 Qt::AlignTop | Qt::AlignLeft.
450
451 The alignment decides how the item is positioned within its assigned space
452 in the case where there's more space available in the layout than the
453 widgets can occupy.
454
455 \sa setAlignment()
456*/
457Qt::Alignment QGraphicsLinearLayout::alignment(QGraphicsLayoutItem *item) const
458{
459 Q_D(const QGraphicsLinearLayout);
460 return d->engine.alignment(item);
461}
462
463#if 0 // ###
464QSizePolicy::ControlTypes QGraphicsLinearLayout::controlTypes(LayoutSide side) const
465{
466 return d->engine.controlTypes(side);
467}
468#endif
469
470/*!
471 \reimp
472*/
473int QGraphicsLinearLayout::count() const
474{
475 Q_D(const QGraphicsLinearLayout);
476 return d->engine.itemCount();
477}
478
479/*!
480 \reimp
481 When iterating from 0 and up, it will return the items in the visual arranged order.
482*/
483QGraphicsLayoutItem *QGraphicsLinearLayout::itemAt(int index) const
484{
485 Q_D(const QGraphicsLinearLayout);
486 if (index < 0 || index >= d->engine.itemCount()) {
487 qWarning("QGraphicsLinearLayout::itemAt: invalid index %d", index);
488 return 0;
489 }
490 QGraphicsLayoutItem *item = 0;
491 if (QGridLayoutItem *gridItem = d->engine.itemAt(index))
492 item = gridItem->layoutItem();
493 return item;
494}
495
496/*!
497 \reimp
498*/
499void QGraphicsLinearLayout::setGeometry(const QRectF &rect)
500{
501 Q_D(QGraphicsLinearLayout);
502 QGraphicsLayout::setGeometry(rect);
503 QRectF effectiveRect = geometry();
504 qreal left, top, right, bottom;
505 getContentsMargins(&left, &top, &right, &bottom);
506 Qt::LayoutDirection visualDir = d->visualDirection();
507 d->engine.setVisualDirection(visualDir);
508 if (visualDir == Qt::RightToLeft)
509 qSwap(left, right);
510 effectiveRect.adjust(+left, +top, -right, -bottom);
511#ifdef QT_DEBUG
512 if (qt_graphicsLayoutDebug()) {
513 static int counter = 0;
514 qDebug() << counter++ << "QGraphicsLinearLayout::setGeometry - " << rect;
515 dump(1);
516 }
517#endif
518 d->engine.setGeometries(d->styleInfo(), effectiveRect);
519#ifdef QT_DEBUG
520 if (qt_graphicsLayoutDebug()) {
521 qDebug() << "post dump";
522 dump(1);
523 }
524#endif
525}
526
527/*!
528 \reimp
529*/
530QSizeF QGraphicsLinearLayout::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
531{
532 Q_D(const QGraphicsLinearLayout);
533 qreal left, top, right, bottom;
534 getContentsMargins(&left, &top, &right, &bottom);
535 const QSizeF extraMargins(left + right, top + bottom);
536 return d->engine.sizeHint(d->styleInfo(), which , constraint - extraMargins) + extraMargins;
537}
538
539/*!
540 \reimp
541*/
542void QGraphicsLinearLayout::invalidate()
543{
544 Q_D(QGraphicsLinearLayout);
545 d->engine.invalidate();
546 QGraphicsLayout::invalidate();
547}
548
549/*!
550 \internal
551*/
552void QGraphicsLinearLayout::dump(int indent) const
553{
554#ifdef QT_DEBUG
555 if (qt_graphicsLayoutDebug()) {
556 Q_D(const QGraphicsLinearLayout);
557 qDebug("%*s%s layout", indent, "",
558 d->orientation == Qt::Horizontal ? "Horizontal" : "Vertical");
559 d->engine.dump(indent + 1);
560 }
561#else
562 Q_UNUSED(indent);
563#endif
564}
565
566QT_END_NAMESPACE
567
568#endif //QT_NO_GRAPHICSVIEW
Note: See TracBrowser for help on using the repository browser.