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

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

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

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