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
qgridlayoutengine_p.h
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#ifndef QGRIDLAYOUTENGINE_P_H
6#define QGRIDLAYOUTENGINE_P_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists for the convenience
13// of the graphics view layout classes. This header
14// file may change from version to version without notice, or even be removed.
15//
16// We mean it.
17//
18
19#include <QtGui/private/qtguiglobal_p.h>
20
21#include <QtCore/qalgorithms.h>
22#include <QtCore/qbitarray.h>
23#include <QtCore/qlist.h>
24#include <QtCore/qmap.h>
25#include <QtCore/qsize.h>
26#include <QtCore/qrect.h>
27#include <QtCore/qdebug.h>
28
29#include <float.h>
32
33// #define QGRIDLAYOUTENGINE_DEBUG
34
36
37class QStyle;
38class QWidget;
39
40// ### deal with Descent in a similar way
41enum {
42 MinimumSize = Qt::MinimumSize,
43 PreferredSize = Qt::PreferredSize,
44 MaximumSize = Qt::MaximumSize,
46};
47
48// do not reorder
55
56enum {
58 HorizontalConstraint, // Width depends on the height
59 VerticalConstraint, // Height depends on the width
60 UnknownConstraint, // need to update cache
61 UnfeasibleConstraint // not feasible, it be has some items with Vertical and others with Horizontal constraints
62};
63
64/*
65 Minimal container to store Qt::Orientation-discriminated values.
66
67 The salient feature is the indexing operator, which takes
68 Qt::Orientation (and assumes it's passed only Qt::Horizontal or Qt::Vertical).
69*/
70template <typename T>
72 T m_data[2];
73
74 static_assert(Qt::Horizontal == 0x1);
75 static_assert(Qt::Vertical == 0x2);
76 static constexpr int map(Qt::Orientation o)
77 {
78 Q_ASSERT(o == Qt::Horizontal || o == Qt::Vertical); // Q_PRE
79 return int(o) - 1;
80 }
81 static constexpr int mapOther(Qt::Orientation o)
82 {
83 Q_ASSERT(o == Qt::Horizontal || o == Qt::Vertical); // Q_PRE
84 return 2 - int(o);
85 }
86public:
87 constexpr QHVContainer(const T &h, const T &v)
89 : m_data{h, v} {}
90 QHVContainer() = default;
91
92 constexpr T &operator[](Qt::Orientation o) { return m_data[map(o)]; }
93 constexpr const T &operator[](Qt::Orientation o) const { return m_data[map(o)]; }
94
95 constexpr T &other(Qt::Orientation o) { return m_data[mapOther(o)]; }
96 constexpr const T &other(Qt::Orientation o) const { return m_data[mapOther(o)]; }
97
98 constexpr void transpose() noexcept { qSwap(m_data[0], m_data[1]); }
99 constexpr QHVContainer transposed() const
101 { return {m_data[1], m_data[0]}; }
102};
103
104template <typename T>
106{
107public:
109
110 inline QLayoutParameter() : q_value(T()), q_state(Default) {}
111 inline QLayoutParameter(T value, State state = Default) : q_value(value), q_state(state) {}
112
113 inline void setUserValue(T value) {
114 q_value = value;
115 q_state = User;
116 }
117 inline void setCachedValue(T value) const {
118 if (q_state != User) {
119 q_value = value;
120 q_state = Cached;
121 }
122 }
123 inline T value() const { return q_value; }
124 inline T value(T defaultValue) const { return isUser() ? q_value : defaultValue; }
125 inline bool isDefault() const { return q_state == Default; }
126 inline bool isUser() const { return q_state == User; }
127 inline bool isCached() const { return q_state == Cached; }
128
129private:
130 mutable T q_value;
131 mutable State q_state;
132};
133
135{
136public:
138
139};
140
141class Q_GUI_EXPORT QGridLayoutBox
142{
143public:
144 inline QGridLayoutBox()
145 : q_minimumSize(0), q_preferredSize(0), q_maximumSize(FLT_MAX),
146 q_minimumDescent(-1), q_minimumAscent(-1) {}
147
148 void add(const QGridLayoutBox &other, int stretch, qreal spacing);
149 void combine(const QGridLayoutBox &other);
150 void normalize();
151
152#ifdef QGRIDLAYOUTENGINE_DEBUG
153 void dump(int indent = 0) const;
154#endif
155 // This code could use the union-struct-array trick, but a compiler
156 // bug prevents this from working.
157 qreal q_minimumSize;
158 qreal q_preferredSize;
159 qreal q_maximumSize;
160 qreal q_minimumDescent;
161 qreal q_minimumAscent;
162 inline qreal &q_sizes(int which)
163 {
164 return const_cast<qreal&>(static_cast<const QGridLayoutBox*>(this)->q_sizes(which));
165 }
166 inline const qreal &q_sizes(int which) const
167 {
168 switch (which) {
169 case Qt::MinimumSize:
170 return q_minimumSize;
171 case Qt::PreferredSize:
172 return q_preferredSize;
173 case Qt::MaximumSize:
174 return q_maximumSize;
175 case Qt::MinimumDescent:
176 return q_minimumDescent;
177 case (Qt::MinimumDescent + 1):
178 return q_minimumAscent;
179 default:
180 Q_UNREACHABLE();
181 }
182 }
183};
184Q_DECLARE_TYPEINFO(QGridLayoutBox, Q_RELOCATABLE_TYPE); // cannot be Q_PRIMITIVE_TYPE, as q_maximumSize, say, is != 0
185
186bool operator==(const QGridLayoutBox &box1, const QGridLayoutBox &box2);
187inline bool operator!=(const QGridLayoutBox &box1, const QGridLayoutBox &box2)
188 { return !operator==(box1, box2); }
189
198
200
202
204{
205public:
206 void reset(int count);
207 void distributeMultiCells(const QGridLayoutRowInfo &rowInfo, bool snapToPixelGrid);
208 void calculateGeometries(int start, int end, qreal targetSize, qreal *positions, qreal *sizes,
209 qreal *descents, const QGridLayoutBox &totalBox,
210 const QGridLayoutRowInfo &rowInfo, bool snapToPixelGrid);
211 QGridLayoutBox totalBox(int start, int end) const;
212 void stealBox(int start, int end, int which, qreal *positions, qreal *sizes);
213
214#ifdef QGRIDLAYOUTENGINE_DEBUG
215 void dump(int indent = 0) const;
216#endif
217
218 QBitArray ignore; // ### rename q_
224};
225
227{
228public:
229 inline QGridLayoutRowInfo() : count(0) {}
230
231 void insertOrRemoveRows(int row, int delta);
232
233#ifdef QGRIDLAYOUTENGINE_DEBUG
234 void dump(int indent = 0) const;
235#endif
236
237 int count;
242};
243
244
245class Q_GUI_EXPORT QGridLayoutItem
246{
247public:
248 QGridLayoutItem(int row, int column, int rowSpan = 1, int columnSpan = 1,
249 Qt::Alignment alignment = { });
250 virtual ~QGridLayoutItem() {}
251
252 inline int firstRow() const { return q_firstRows[Qt::Vertical]; }
253 inline int firstColumn() const { return q_firstRows[Qt::Horizontal]; }
254 inline int rowSpan() const { return q_rowSpans[Qt::Vertical]; }
255 inline int columnSpan() const { return q_rowSpans[Qt::Horizontal]; }
256 inline int lastRow() const { return firstRow() + rowSpan() - 1; }
257 inline int lastColumn() const { return firstColumn() + columnSpan() - 1; }
258
259 int firstRow(Qt::Orientation orientation) const;
260 int firstColumn(Qt::Orientation orientation) const;
261 int lastRow(Qt::Orientation orientation) const;
262 int lastColumn(Qt::Orientation orientation) const;
263 int rowSpan(Qt::Orientation orientation) const;
264 int columnSpan(Qt::Orientation orientation) const;
265 void setFirstRow(int row, Qt::Orientation orientation = Qt::Vertical);
266 void setRowSpan(int rowSpan, Qt::Orientation orientation = Qt::Vertical);
267
268 int stretchFactor(Qt::Orientation orientation) const;
269 void setStretchFactor(int stretch, Qt::Orientation orientation);
270
271 inline Qt::Alignment alignment() const { return q_alignment; }
272 inline void setAlignment(Qt::Alignment alignment) { q_alignment = alignment; }
273
274 virtual QLayoutPolicy::Policy sizePolicy(Qt::Orientation orientation) const = 0;
275 virtual QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const = 0;
276 virtual bool isEmpty() const { return false; }
277
278 virtual void setGeometry(const QRectF &rect) = 0;
279 /*
280 returns true if the size policy returns true for either hasHeightForWidth()
281 or hasWidthForHeight()
282 */
283 virtual bool hasDynamicConstraint() const { return false; }
284 virtual Qt::Orientation dynamicConstraintOrientation() const { return Qt::Horizontal; }
285
286
287 virtual QLayoutPolicy::ControlTypes controlTypes(LayoutSide side) const;
288
289 inline virtual QString toString() const { return QDebug::toString(this); }
290
291 QRectF geometryWithin(qreal x, qreal y, qreal width, qreal height, qreal rowDescent, Qt::Alignment align, bool snapToPixelGrid) const;
292 QGridLayoutBox box(Qt::Orientation orientation, bool snapToPixelGrid, qreal constraint = -1.0) const;
293
294
295 void transpose();
296 void insertOrRemoveRows(int row, int delta, Qt::Orientation orientation = Qt::Vertical);
297 QSizeF effectiveMaxSize(const QSizeF &constraint) const;
298
299#ifdef QGRIDLAYOUTENGINE_DEBUG
300 void dump(int indent = 0) const;
301#endif
302
303private:
304 QHVContainer<int> q_firstRows;
305 QHVContainer<int> q_rowSpans;
306 QHVContainer<int> q_stretches;
307 Qt::Alignment q_alignment;
308
309};
310
311class Q_GUI_EXPORT QGridLayoutEngine
312{
313public:
314 QGridLayoutEngine(Qt::Alignment defaultAlignment = { }, bool snapToPixelGrid = false);
315 inline ~QGridLayoutEngine() { qDeleteAll(q_items); }
316
317 int rowCount(Qt::Orientation orientation) const;
318 int columnCount(Qt::Orientation orientation) const;
319 inline int rowCount() const { return q_infos[Qt::Vertical].count; }
320 inline int columnCount() const { return q_infos[Qt::Horizontal].count; }
321 // returns the number of items inserted, which may be less than (rowCount * columnCount)
322 int itemCount() const;
323 QGridLayoutItem *itemAt(int index) const;
324
325 int effectiveFirstRow(Qt::Orientation orientation = Qt::Vertical) const;
326 int effectiveLastRow(Qt::Orientation orientation = Qt::Vertical) const;
327
328 void setSpacing(qreal spacing, Qt::Orientations orientations);
329 qreal spacing(Qt::Orientation orientation, const QAbstractLayoutStyleInfo *styleInfo) const;
330 // ### setSpacingAfterRow(), spacingAfterRow()
331 void setRowSpacing(int row, qreal spacing, Qt::Orientation orientation = Qt::Vertical);
332 qreal rowSpacing(int row, Qt::Orientation orientation = Qt::Vertical) const;
333
334 void setRowStretchFactor(int row, int stretch, Qt::Orientation orientation = Qt::Vertical);
335 int rowStretchFactor(int row, Qt::Orientation orientation = Qt::Vertical) const;
336
337 void setRowSizeHint(Qt::SizeHint which, int row, qreal size,
338 Qt::Orientation orientation = Qt::Vertical);
339 qreal rowSizeHint(Qt::SizeHint which, int row,
340 Qt::Orientation orientation = Qt::Vertical) const;
341
342 bool uniformCellWidths() const;
343 void setUniformCellWidths(bool uniformCellWidths);
344
345 bool uniformCellHeights() const;
346 void setUniformCellHeights(bool uniformCellHeights);
347
348 void setRowAlignment(int row, Qt::Alignment alignment, Qt::Orientation orientation);
349 Qt::Alignment rowAlignment(int row, Qt::Orientation orientation) const;
350
351 Qt::Alignment effectiveAlignment(const QGridLayoutItem *layoutItem) const;
352
353
354 void insertItem(QGridLayoutItem *item, int index);
355 void addItem(QGridLayoutItem *item);
356 void removeItem(QGridLayoutItem *item);
357 void deleteItems()
358 {
359 const QList<QGridLayoutItem *> oldItems = q_items;
360 q_items.clear(); // q_items are used as input when the grid is regenerated in removeRows
361 // The following calls to removeRows are suboptimal
362 int rows = rowCount(Qt::Vertical);
363 removeRows(0, rows, Qt::Vertical);
364 rows = rowCount(Qt::Horizontal);
365 removeRows(0, rows, Qt::Horizontal);
366 qDeleteAll(oldItems);
367 }
368
369 QGridLayoutItem *itemAt(int row, int column, Qt::Orientation orientation = Qt::Vertical) const;
370 inline void insertRow(int row, Qt::Orientation orientation = Qt::Vertical)
371 { insertOrRemoveRows(row, +1, orientation); }
372 inline void removeRows(int row, int count, Qt::Orientation orientation)
373 { insertOrRemoveRows(row, -count, orientation); }
374
375 void invalidate();
376 void setGeometries(const QRectF &contentsGeometry, const QAbstractLayoutStyleInfo *styleInfo);
377 QRectF cellRect(const QRectF &contentsGeometry, int row, int column, int rowSpan, int columnSpan,
378 const QAbstractLayoutStyleInfo *styleInfo) const;
379 QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint,
380 const QAbstractLayoutStyleInfo *styleInfo) const;
381
382 // heightForWidth / widthForHeight support
383 QSizeF dynamicallyConstrainedSizeHint(Qt::SizeHint which, const QSizeF &constraint) const;
384 bool ensureDynamicConstraint() const;
385 bool hasDynamicConstraint() const;
386 Qt::Orientation constraintOrientation() const;
387
388
389 QLayoutPolicy::ControlTypes controlTypes(LayoutSide side) const;
390 void transpose();
391 void setVisualDirection(Qt::LayoutDirection direction);
392 Qt::LayoutDirection visualDirection() const;
393#ifdef QGRIDLAYOUTENGINE_DEBUG
394 void dump(int indent = 0) const;
395#endif
396
397private:
398 static int grossRoundUp(int n) { return ((n + 2) | 0x3) - 2; }
399
400 void maybeExpandGrid(int row, int column, Qt::Orientation orientation = Qt::Vertical);
401 void regenerateGrid();
402 inline int internalGridRowCount() const { return grossRoundUp(rowCount()); }
403 inline int internalGridColumnCount() const { return grossRoundUp(columnCount()); }
404 void setItemAt(int row, int column, QGridLayoutItem *item);
405 void insertOrRemoveRows(int row, int delta, Qt::Orientation orientation = Qt::Vertical);
406 void fillRowData(QGridLayoutRowData *rowData,
407 const qreal *colPositions, const qreal *colSizes,
408 Qt::Orientation orientation,
409 const QAbstractLayoutStyleInfo *styleInfo) const;
410 void ensureEffectiveFirstAndLastRows() const;
411 void ensureColumnAndRowData(QGridLayoutRowData *rowData, QGridLayoutBox *totalBox,
412 const qreal *colPositions, const qreal *colSizes,
413 Qt::Orientation orientation,
414 const QAbstractLayoutStyleInfo *styleInfo) const;
415
416 void ensureGeometries(const QSizeF &size, const QAbstractLayoutStyleInfo *styleInfo) const;
417protected:
418 QList<QGridLayoutItem *> q_items;
419private:
420 // User input
421 QList<QGridLayoutItem *> q_grid;
422 QHVContainer<QLayoutParameter<qreal>> q_defaultSpacings;
423 QHVContainer<QGridLayoutRowInfo> q_infos;
424 Qt::LayoutDirection m_visualDirection;
425
426 // Configuration
427 Qt::Alignment m_defaultAlignment;
428 unsigned m_snapToPixelGrid : 1;
429 unsigned m_uniformCellWidths : 1;
430 unsigned m_uniformCellHeights : 1;
431
432 // Lazily computed from the above user input
433 mutable QHVContainer<int> q_cachedEffectiveFirstRows;
434 mutable QHVContainer<int> q_cachedEffectiveLastRows;
435 mutable quint8 q_cachedConstraintOrientation : 3;
436
437 // this is useful to cache
438 mutable QHVContainer<QGridLayoutBox> q_totalBoxes;
439 enum {
440 NotCached = -2, // Cache is empty. Happens when the engine is invalidated.
441 CachedWithNoConstraint = -1 // cache has a totalBox without any HFW/WFH constraints.
442 // >= 0 // cache has a totalBox with this specific constraint.
443 };
444 mutable QHVContainer<qreal> q_totalBoxCachedConstraints; // holds the constraint used for the cached totalBox
445
446 // Layout item input
447 mutable QGridLayoutRowData q_columnData;
448 mutable QGridLayoutRowData q_rowData;
449
450 // Output
451 mutable QSizeF q_cachedSize;
452 mutable QList<qreal> q_xx;
453 mutable QList<qreal> q_yy;
454 mutable QList<qreal> q_widths;
455 mutable QList<qreal> q_heights;
456 mutable QList<qreal> q_descents;
457
458 friend class QGridLayoutItem;
459};
460
461QT_END_NAMESPACE
462
463#endif
friend bool operator==(const QByteArray::FromBase64Result &lhs, const QByteArray::FromBase64Result &rhs) noexcept
Returns true if lhs and rhs are equal, otherwise returns false.
Definition qbytearray.h:801
friend bool operator!=(const QByteArray::FromBase64Result &lhs, const QByteArray::FromBase64Result &rhs) noexcept
Returns true if lhs and rhs are different, otherwise returns false.
Definition qbytearray.h:812
QList< QGridLayoutBox > boxes
QGridLayoutBox totalBox(int start, int end) const
void stealBox(int start, int end, int which, qreal *positions, qreal *sizes)
void calculateGeometries(int start, int end, qreal targetSize, qreal *positions, qreal *sizes, qreal *descents, const QGridLayoutBox &totalBox, const QGridLayoutRowInfo &rowInfo, bool snapToPixelGrid)
void distributeMultiCells(const QGridLayoutRowInfo &rowInfo, bool snapToPixelGrid)
QList< QLayoutParameter< qreal > > spacings
QList< QGridLayoutBox > boxes
QList< Qt::Alignment > alignments
QList< QStretchParameter > stretches
void insertOrRemoveRows(int row, int delta)
constexpr T & operator[](Qt::Orientation o)
constexpr T & other(Qt::Orientation o)
constexpr const T & other(Qt::Orientation o) const
constexpr const T & operator[](Qt::Orientation o) const
constexpr void transpose() noexcept
constexpr QHVContainer transposed() const noexcept(std::is_nothrow_copy_constructible_v< T >)
QHVContainer()=default
constexpr QHVContainer(const T &h, const T &v) noexcept(std::is_nothrow_copy_constructible_v< T >)
QLayoutParameter(T value, State state=Default)
void setUserValue(T value)
T value(T defaultValue) const
void setCachedValue(T value) const
friend class QWidget
Definition qpainter.h:431
Q_DECLARE_TYPEINFO(QByteArrayView, Q_PRIMITIVE_TYPE)
static void insertOrRemoveItems(QList< T > &items, int index, int delta)
static qreal growthFactorBelowPreferredSize(qreal desired, qreal sumAvailable, qreal sumDesired)
static void visualRect(QRectF *geom, Qt::LayoutDirection dir, const QRectF &contentsRect)
static qreal fixedDescent(qreal descent, qreal ascent, qreal targetSize)
#define LAYOUTITEMSIZE_MAX
static qreal compare(const QGridLayoutBox &box1, const QGridLayoutBox &box2, int which)
@ UnfeasibleConstraint
@ VerticalConstraint
@ HorizontalConstraint
@ UnknownConstraint
@ NoConstraint
QMap< std::pair< int, int >, QGridLayoutMultiCellData > MultiCellMap
@ MinimumSize
@ PreferredSize
@ MaximumSize