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/*!
431 \reimp
432*/
433int QGraphicsLinearLayout::count() const
434{
435 Q_D(const QGraphicsLinearLayout);
436 return d->engine.itemCount();
437}
438
439/*!
440 \reimp
441 When iterating from 0 and up, it will return the items in the visual arranged order.
442*/
443QGraphicsLayoutItem *QGraphicsLinearLayout::itemAt(int index) const
444{
445 Q_D(const QGraphicsLinearLayout);
446 if (index < 0 || index >= d->engine.itemCount()) {
447 qWarning("QGraphicsLinearLayout::itemAt: invalid index %d", index);
448 return nullptr;
449 }
450 QGraphicsLayoutItem *item = nullptr;
451 if (QGraphicsGridLayoutEngineItem *gridItem = static_cast<QGraphicsGridLayoutEngineItem *>(d->engine.itemAt(index)))
452 item = gridItem->layoutItem();
453 return item;
454}
455
456/*!
457 \reimp
458*/
459void QGraphicsLinearLayout::setGeometry(const QRectF &rect)
460{
461 Q_D(QGraphicsLinearLayout);
462 QGraphicsLayout::setGeometry(rect);
463 QRectF effectiveRect = geometry();
464 qreal left, top, right, bottom;
465 getContentsMargins(&left, &top, &right, &bottom);
466 Qt::LayoutDirection visualDir = d->visualDirection();
467 d->engine.setVisualDirection(visualDir);
468 if (visualDir == Qt::RightToLeft)
469 qSwap(left, right);
470 effectiveRect.adjust(+left, +top, -right, -bottom);
471#ifdef QGRIDLAYOUTENGINE_DEBUG
472 if (qt_graphicsLayoutDebug()) {
473 static int counter = 0;
474 qDebug() << counter++ << "QGraphicsLinearLayout::setGeometry - " << rect;
475 dump(1);
476 }
477#endif
478 d->engine.setGeometries(effectiveRect, d->styleInfo());
479#ifdef QGRIDLAYOUTENGINE_DEBUG
480 if (qt_graphicsLayoutDebug()) {
481 qDebug("post dump");
482 dump(1);
483 }
484#endif
485}
486
487/*!
488 \reimp
489*/
490QSizeF QGraphicsLinearLayout::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
491{
492 Q_D(const QGraphicsLinearLayout);
493 qreal left, top, right, bottom;
494 getContentsMargins(&left, &top, &right, &bottom);
495 const QSizeF extraMargins(left + right, top + bottom);
496 return d->engine.sizeHint(which , constraint - extraMargins, d->styleInfo()) + extraMargins;
497}
498
499/*!
500 \reimp
501*/
502void QGraphicsLinearLayout::invalidate()
503{
504 Q_D(QGraphicsLinearLayout);
505 d->engine.invalidate();
506 if (d->m_styleInfo)
507 d->m_styleInfo->invalidate();
508 QGraphicsLayout::invalidate();
509}
510
511/*!
512 \internal
513*/
514void QGraphicsLinearLayout::dump(int indent) const
515{
516#ifdef QGRIDLAYOUTENGINE_DEBUG
517 if (qt_graphicsLayoutDebug()) {
518 Q_D(const QGraphicsLinearLayout);
519 qDebug("%*s%s layout", indent, "",
520 d->orientation == Qt::Horizontal ? "Horizontal" : "Vertical");
521 d->engine.dump(indent + 1);
522 }
523#else
524 Q_UNUSED(indent);
525#endif
526}
527
528QT_END_NAMESPACE
QGraphicsLinearLayoutPrivate(Qt::Orientation orientation)
void removeGridItem(QGridLayoutItem *gridItem)
QGraphicsLayoutStyleInfo * styleInfo() const
QScopedPointer< QGraphicsLayoutStyleInfo > m_styleInfo
Combined button and popup list for selecting options.