|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 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 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
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 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
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 |
|
129 QT_BEGIN_NAMESPACE |
|
130 |
|
131 class QGraphicsLinearLayoutPrivate : public QGraphicsLayoutPrivate |
|
132 { |
|
133 public: |
|
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 |
|
146 void QGraphicsLinearLayoutPrivate::removeGridItem(QGridLayoutItem *gridItem) |
|
147 { |
|
148 int index = gridItem->firstRow(orientation); |
|
149 engine.removeItem(gridItem); |
|
150 engine.removeRow(index, orientation); |
|
151 } |
|
152 |
|
153 void QGraphicsLinearLayoutPrivate::fixIndex(int *index) const |
|
154 { |
|
155 int count = engine.rowCount(orientation); |
|
156 if (uint(*index) > uint(count)) |
|
157 *index = count; |
|
158 } |
|
159 |
|
160 int 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 |
|
167 int 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 |
|
174 QLayoutStyleInfo 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 */ |
|
189 QGraphicsLinearLayout::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 */ |
|
198 QGraphicsLinearLayout::QGraphicsLinearLayout(QGraphicsLayoutItem *parent) |
|
199 : QGraphicsLayout(*new QGraphicsLinearLayoutPrivate(Qt::Horizontal), parent) |
|
200 { |
|
201 } |
|
202 |
|
203 /*! |
|
204 Destroys the QGraphicsLinearLayout object. |
|
205 */ |
|
206 QGraphicsLinearLayout::~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 */ |
|
228 void 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 */ |
|
242 Qt::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 */ |
|
268 void 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 */ |
|
294 void 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 */ |
|
309 void 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 */ |
|
326 void 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 */ |
|
348 void 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 */ |
|
365 qreal 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 */ |
|
374 void 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 */ |
|
383 qreal 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 */ |
|
398 void 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 */ |
|
418 int 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 */ |
|
435 void 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 */ |
|
454 Qt::Alignment QGraphicsLinearLayout::alignment(QGraphicsLayoutItem *item) const |
|
455 { |
|
456 Q_D(const QGraphicsLinearLayout); |
|
457 return d->engine.alignment(item); |
|
458 } |
|
459 |
|
460 #if 0 // ### |
|
461 QSizePolicy::ControlTypes QGraphicsLinearLayout::controlTypes(LayoutSide side) const |
|
462 { |
|
463 return d->engine.controlTypes(side); |
|
464 } |
|
465 #endif |
|
466 |
|
467 /*! |
|
468 \reimp |
|
469 */ |
|
470 int 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 */ |
|
480 QGraphicsLayoutItem *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 */ |
|
496 void 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 */ |
|
527 QSizeF 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 */ |
|
538 void QGraphicsLinearLayout::invalidate() |
|
539 { |
|
540 Q_D(QGraphicsLinearLayout); |
|
541 d->engine.invalidate(); |
|
542 QGraphicsLayout::invalidate(); |
|
543 } |
|
544 |
|
545 #ifdef QT_DEBUG |
|
546 void QGraphicsLinearLayout::dump(int indent) const |
|
547 { |
|
548 if (qt_graphicsLayoutDebug()) { |
|
549 Q_D(const QGraphicsLinearLayout); |
|
550 qDebug("%*s%s layout", indent, "", |
|
551 d->orientation == Qt::Horizontal ? "Horizontal" : "Vertical"); |
|
552 d->engine.dump(indent + 1); |
|
553 } |
|
554 } |
|
555 #endif |
|
556 |
|
557 QT_END_NAMESPACE |
|
558 |
|
559 #endif //QT_NO_GRAPHICSVIEW |