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

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

trunk: Merged in qt 4.6.2 sources.

File size: 17.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 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 centered both vertically and horizontally.
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.removeRow(index, 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
174QLayoutStyleInfo QGraphicsLinearLayoutPrivate::styleInfo() const
175{
176 static QWidget *wid = 0;
177 if (!wid)
178 wid = new QWidget;
179 QGraphicsItem *item = parentItem();
180 QStyle *style = (item && item->isWidget()) ? static_cast<QGraphicsWidget*>(item)->style() : QApplication::style();
181 return QLayoutStyleInfo(style, wid);
182}
183
184/*!
185 Constructs a QGraphicsLinearLayout instance. You can pass the
186 \a orientation for the layout, either horizontal or vertical, and
187 \a parent is passed to QGraphicsLayout's constructor.
188*/
189QGraphicsLinearLayout::QGraphicsLinearLayout(Qt::Orientation orientation, QGraphicsLayoutItem *parent)
190 : QGraphicsLayout(*new QGraphicsLinearLayoutPrivate(orientation), parent)
191{
192}
193
194/*!
195 Constructs a QGraphicsLinearLayout instance using Qt::Horizontal
196 orientation. \a parent is passed to QGraphicsLayout's constructor.
197*/
198QGraphicsLinearLayout::QGraphicsLinearLayout(QGraphicsLayoutItem *parent)
199 : QGraphicsLayout(*new QGraphicsLinearLayoutPrivate(Qt::Horizontal), parent)
200{
201}
202
203/*!
204 Destroys the QGraphicsLinearLayout object.
205*/
206QGraphicsLinearLayout::~QGraphicsLinearLayout()
207{
208 for (int i = count() - 1; i >= 0; --i) {
209 QGraphicsLayoutItem *item = itemAt(i);
210 // The following lines can be removed, but this removes the item
211 // from the layout more efficiently than the implementation of
212 // ~QGraphicsLayoutItem.
213 removeAt(i);
214 if (item) {
215 item->setParentLayoutItem(0);
216 if (item->ownedByLayout())
217 delete item;
218 }
219 }
220}
221
222/*!
223 Change the layout orientation to \a orientation. Changing the layout
224 orientation will automatically invalidate the layout.
225
226 \sa orientation()
227*/
228void QGraphicsLinearLayout::setOrientation(Qt::Orientation orientation)
229{
230 Q_D(QGraphicsLinearLayout);
231 if (orientation != d->orientation) {
232 d->engine.transpose();
233 d->orientation = orientation;
234 invalidate();
235 }
236}
237
238/*!
239 Returns the layout orientation.
240 \sa setOrientation()
241 */
242Qt::Orientation QGraphicsLinearLayout::orientation() const
243{
244 Q_D(const QGraphicsLinearLayout);
245 return d->orientation;
246}
247
248/*!
249 \fn void QGraphicsLinearLayout::addItem(QGraphicsLayoutItem *item)
250
251 This convenience function is equivalent to calling
252 insertItem(-1, \a item).
253*/
254
255/*!
256 \fn void QGraphicsLinearLayout::addStretch(int stretch)
257
258 This convenience function is equivalent to calling
259 insertStretch(-1, \a stretch).
260*/
261
262/*!
263 Inserts \a item into the layout at \a index, or before any item that is
264 currently at \a index.
265
266 \sa addItem(), itemAt(), insertStretch(), setItemSpacing()
267*/
268void QGraphicsLinearLayout::insertItem(int index, QGraphicsLayoutItem *item)
269{
270 Q_D(QGraphicsLinearLayout);
271 if (!item) {
272 qWarning("QGraphicsLinearLayout::insertItem: cannot insert null item");
273 return;
274 }
275 if (item == this) {
276 qWarning("QGraphicsLinearLayout::insertItem: cannot insert itself");
277 return;
278 }
279 d->addChildLayoutItem(item);
280
281 Q_ASSERT(item);
282 d->fixIndex(&index);
283 d->engine.insertRow(index, d->orientation);
284 new QGridLayoutItem(&d->engine, item, d->gridRow(index), d->gridColumn(index), 1, 1, 0, index);
285 invalidate();
286}
287
288/*!
289 Inserts a stretch of \a stretch at \a index, or before any item that is
290 currently at \a index.
291
292 \sa addStretch(), setStretchFactor(), setItemSpacing(), insertItem()
293*/
294void QGraphicsLinearLayout::insertStretch(int index, int stretch)
295{
296 Q_D(QGraphicsLinearLayout);
297 d->fixIndex(&index);
298 d->engine.insertRow(index, d->orientation);
299 d->engine.setRowStretchFactor(index, stretch, d->orientation);
300 invalidate();
301}
302
303/*!
304 Removes \a item from the layout without destroying it. Ownership of
305 \a item is transferred to the caller.
306
307 \sa removeAt(), insertItem()
308*/
309void QGraphicsLinearLayout::removeItem(QGraphicsLayoutItem *item)
310{
311 Q_D(QGraphicsLinearLayout);
312 if (QGridLayoutItem *gridItem = d->engine.findLayoutItem(item)) {
313 item->setParentLayoutItem(0);
314 d->removeGridItem(gridItem);
315 delete gridItem;
316 invalidate();
317 }
318}
319
320/*!
321 Removes the item at \a index without destroying it. Ownership of the item
322 is transferred to the caller.
323
324 \sa removeItem(), insertItem()
325*/
326void QGraphicsLinearLayout::removeAt(int index)
327{
328 Q_D(QGraphicsLinearLayout);
329 if (index < 0 || index >= d->engine.itemCount()) {
330 qWarning("QGraphicsLinearLayout::removeAt: invalid index %d", index);
331 return;
332 }
333 if (QGridLayoutItem *gridItem = d->engine.itemAt(index)) {
334 if (QGraphicsLayoutItem *layoutItem = gridItem->layoutItem())
335 layoutItem->setParentLayoutItem(0);
336 d->removeGridItem(gridItem);
337 delete gridItem;
338 invalidate();
339 }
340}
341
342/*!
343 Sets the layout's spacing to \a spacing. Spacing refers to the
344 vertical and horizontal distances between items.
345
346 \sa setItemSpacing(), setStretchFactor(), QGraphicsGridLayout::setSpacing()
347*/
348void QGraphicsLinearLayout::setSpacing(qreal spacing)
349{
350 Q_D(QGraphicsLinearLayout);
351 if (spacing < 0) {
352 qWarning("QGraphicsLinearLayout::setSpacing: invalid spacing %g", spacing);
353 return;
354 }
355 d->engine.setSpacing(spacing, Qt::Horizontal | Qt::Vertical);
356 invalidate();
357}
358
359/*!
360 Returns the layout's spacing. Spacing refers to the
361 vertical and horizontal distances between items.
362
363 \sa setSpacing()
364 */
365qreal QGraphicsLinearLayout::spacing() const
366{
367 Q_D(const QGraphicsLinearLayout);
368 return d->engine.spacing(d->styleInfo(), d->orientation);
369}
370
371/*!
372 Sets the spacing after item at \a index to \a spacing.
373*/
374void QGraphicsLinearLayout::setItemSpacing(int index, qreal spacing)
375{
376 Q_D(QGraphicsLinearLayout);
377 d->engine.setRowSpacing(index, spacing, d->orientation);
378 invalidate();
379}
380/*!
381 Returns the spacing after item at \a index.
382*/
383qreal QGraphicsLinearLayout::itemSpacing(int index) const
384{
385 Q_D(const QGraphicsLinearLayout);
386 return d->engine.rowSpacing(index, d->orientation);
387}
388
389/*!
390 Sets the stretch factor for \a item to \a stretch. If an item's stretch
391 factor changes, this function will invalidate the layout.
392
393 Setting \a stretch to 0 removes the stretch factor from the item, and is
394 effectively equivalent to setting \a stretch to 1.
395
396 \sa stretchFactor()
397*/
398void QGraphicsLinearLayout::setStretchFactor(QGraphicsLayoutItem *item, int stretch)
399{
400 Q_D(QGraphicsLinearLayout);
401 if (!item) {
402 qWarning("QGraphicsLinearLayout::setStretchFactor: cannot assign"
403 " a stretch factor to a null item");
404 return;
405 }
406 if (stretchFactor(item) == stretch)
407 return;
408 d->engine.setStretchFactor(item, stretch, d->orientation);
409 invalidate();
410}
411
412/*!
413 Returns the stretch factor for \a item. The default stretch factor is 0,
414 meaning that the item has no assigned stretch factor.
415
416 \sa setStretchFactor()
417*/
418int QGraphicsLinearLayout::stretchFactor(QGraphicsLayoutItem *item) const
419{
420 Q_D(const QGraphicsLinearLayout);
421 if (!item) {
422 qWarning("QGraphicsLinearLayout::setStretchFactor: cannot return"
423 " a stretch factor for a null item");
424 return 0;
425 }
426 return d->engine.stretchFactor(item, d->orientation);
427}
428
429/*!
430 Sets the alignment of \a item to \a alignment. If \a item's alignment
431 changes, the layout is automatically invalidated.
432
433 \sa alignment(), invalidate()
434*/
435void QGraphicsLinearLayout::setAlignment(QGraphicsLayoutItem *item, Qt::Alignment alignment)
436{
437 Q_D(QGraphicsLinearLayout);
438 if (this->alignment(item) == alignment)
439 return;
440 d->engine.setAlignment(item, alignment);
441 invalidate();
442}
443
444/*!
445 Returns the alignment for \a item. The default alignment is
446 Qt::AlignCenter.
447
448 The alignment decides how the item is positioned within its assigned space
449 in the case where there's more space available in the layout than the
450 widgets can occupy.
451
452 \sa setAlignment()
453*/
454Qt::Alignment QGraphicsLinearLayout::alignment(QGraphicsLayoutItem *item) const
455{
456 Q_D(const QGraphicsLinearLayout);
457 return d->engine.alignment(item);
458}
459
460#if 0 // ###
461QSizePolicy::ControlTypes QGraphicsLinearLayout::controlTypes(LayoutSide side) const
462{
463 return d->engine.controlTypes(side);
464}
465#endif
466
467/*!
468 \reimp
469*/
470int QGraphicsLinearLayout::count() const
471{
472 Q_D(const QGraphicsLinearLayout);
473 return d->engine.itemCount();
474}
475
476/*!
477 \reimp
478 When iterating from 0 and up, it will return the items in the visual arranged order.
479*/
480QGraphicsLayoutItem *QGraphicsLinearLayout::itemAt(int index) const
481{
482 Q_D(const QGraphicsLinearLayout);
483 if (index < 0 || index >= d->engine.itemCount()) {
484 qWarning("QGraphicsLinearLayout::itemAt: invalid index %d", index);
485 return 0;
486 }
487 QGraphicsLayoutItem *item = 0;
488 if (QGridLayoutItem *gridItem = d->engine.itemAt(index))
489 item = gridItem->layoutItem();
490 return item;
491}
492
493/*!
494 \reimp
495*/
496void QGraphicsLinearLayout::setGeometry(const QRectF &rect)
497{
498 Q_D(QGraphicsLinearLayout);
499 QGraphicsLayout::setGeometry(rect);
500 QRectF effectiveRect = geometry();
501 qreal left, top, right, bottom;
502 getContentsMargins(&left, &top, &right, &bottom);
503 Qt::LayoutDirection visualDir = d->visualDirection();
504 d->engine.setVisualDirection(visualDir);
505 if (visualDir == Qt::RightToLeft)
506 qSwap(left, right);
507 effectiveRect.adjust(+left, +top, -right, -bottom);
508#ifdef QT_DEBUG
509 if (qt_graphicsLayoutDebug()) {
510 static int counter = 0;
511 qDebug() << counter++ << "QGraphicsLinearLayout::setGeometry - " << rect;
512 dump(1);
513 }
514#endif
515 d->engine.setGeometries(d->styleInfo(), effectiveRect);
516#ifdef QT_DEBUG
517 if (qt_graphicsLayoutDebug()) {
518 qDebug() << "post dump";
519 dump(1);
520 }
521#endif
522}
523
524/*!
525 \reimp
526*/
527QSizeF QGraphicsLinearLayout::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
528{
529 Q_D(const QGraphicsLinearLayout);
530 qreal left, top, right, bottom;
531 getContentsMargins(&left, &top, &right, &bottom);
532 return d->engine.sizeHint(d->styleInfo(), which , constraint) + QSizeF(left + right, top + bottom);
533}
534
535/*!
536 \reimp
537*/
538void QGraphicsLinearLayout::invalidate()
539{
540 Q_D(QGraphicsLinearLayout);
541 d->engine.invalidate();
542 QGraphicsLayout::invalidate();
543}
544
545/*!
546 \internal
547*/
548void QGraphicsLinearLayout::dump(int indent) const
549{
550#ifdef QT_DEBUG
551 if (qt_graphicsLayoutDebug()) {
552 Q_D(const QGraphicsLinearLayout);
553 qDebug("%*s%s layout", indent, "",
554 d->orientation == Qt::Horizontal ? "Horizontal" : "Vertical");
555 d->engine.dump(indent + 1);
556 }
557#endif
558}
559
560QT_END_NAMESPACE
561
562#endif //QT_NO_GRAPHICSVIEW
Note: See TracBrowser for help on using the repository browser.