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