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
qgraphicsanchorlayout_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 QGRAPHICSANCHORLAYOUT_P_H
6#define QGRAPHICSANCHORLAYOUT_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 purely as an
13// implementation detail. This header file may change from version to
14// version without notice, or even be removed.
15//
16// We mean it.
17//
18
19#include <QtWidgets/private/qtwidgetsglobal_p.h>
20#include <QGraphicsWidget>
21#include <private/qobject_p.h>
22
25#include "qgraph_p.h"
26#include "qsimplex_p.h"
27
28#include <QtGui/private/qgridlayoutengine_p.h>
29
30#include <array>
31
33
34QT_BEGIN_NAMESPACE
35
36/*
37 The public QGraphicsAnchorLayout interface represents an anchorage point
38 as a pair of a <QGraphicsLayoutItem *> and a <Qt::AnchorPoint>.
39
40 Internally though, it has a graph of anchorage points (vertices) and
41 anchors (edges), represented by the AnchorVertex and AnchorData structs
42 respectively.
43*/
44
46/*!
47 \internal
48
49 Represents a vertex (anchorage point) in the internal graph
50*/
52{
53 AnchorVertex(QGraphicsLayoutItem *item, Qt::AnchorPoint edge)
54 : m_item(item), m_edge(edge) {}
55
57 : m_item(nullptr), m_edge(Qt::AnchorPoint(0)) {}
58
59 virtual ~AnchorVertex() = default;
60
61#ifdef QT_DEBUG
62 virtual inline QString toString() const;
63#endif
64
65 QGraphicsLayoutItem *m_item;
67
68 // Current distance from this vertex to the layout edge (Left or Top)
69 // Value is calculated from the current anchors sizes.
71};
72
73/*!
74 \internal
75
76 Represents an edge (anchor) in the internal graph.
77*/
78struct AnchorData : public QSimplexVariable {
80
86
92
94 : QSimplexVariable(), from(nullptr), to(nullptr),
95 minSize(0), prefSize(0), maxSize(0),
98 sizeAtMaximum(0), item(nullptr), graphicsAnchor(nullptr),
99 type(Normal), isLayoutAnchor(false),
100 isCenterAnchor(false), isVertical(false),
102 virtual ~AnchorData();
103
104 virtual void updateChildrenSizes() {}
105 void refreshSizeHints(const QLayoutStyleInfo *styleInfo = nullptr);
106
107#ifdef QT_DEBUG
108 void dump(int indent = 2);
109 inline QString toString() const;
111#endif
112
113 // Anchor is semantically directed
116
117 // Nominal sizes
118 // These are the intrinsic size restrictions for a given item. They are
119 // used as input for the calculation of the actual sizes.
120 // These values are filled by the refreshSizeHints method, based on the
121 // anchor size policy, the size hints of the item it (possibly) represents
122 // and the layout spacing information.
126
129
130 // Calculated sizes
131 // These attributes define which sizes should that anchor be in when the
132 // layout is at its minimum, preferred or maximum sizes. Values are
133 // calculated by the Simplex solver based on the current layout setup.
137
138 // References to the classes that represent this anchor in the public world
139 // An anchor may represent a LayoutItem, it may also be accessible externally
140 // through a GraphicsAnchor "handler".
141 QGraphicsLayoutItem *item;
143
144 uint type : 2; // either Normal, Sequential or Parallel
145 uint isLayoutAnchor : 1; // if this anchor is an internal layout anchor
148 uint dependency : 2; // either Independent, Master or Slave
149};
150
151#ifdef QT_DEBUG
152inline QString AnchorData::toString() const
153{
154 return QString::fromLatin1("Anchor(%1)").arg(name);
155}
156#endif
157
159{
160 SequentialAnchorData(const QList<AnchorVertex *> &vertices, const QList<AnchorData *> &edges)
162 {
163 type = AnchorData::Sequential;
164 isVertical = m_edges.at(0)->isVertical;
165#ifdef QT_DEBUG
166 name = QString::fromLatin1("%1 -- %2").arg(vertices.first()->toString(), vertices.last()->toString());
167#else
168 Q_UNUSED(vertices);
169#endif
170 }
171
172 virtual void updateChildrenSizes() override;
173 void calculateSizeHints();
174
175 const QList<AnchorData *> m_edges; // keep the list of edges too.
176};
177
179{
181 : AnchorData(), firstEdge(first), secondEdge(second)
182 {
183 type = AnchorData::Parallel;
184 isVertical = first->isVertical;
185
186 // This assert whether the child anchors share their vertices
187 Q_ASSERT(((first->from == second->from) && (first->to == second->to)) ||
188 ((first->from == second->to) && (first->to == second->from)));
189
190 // Our convention will be that the parallel group anchor will have the same
191 // direction as the first anchor.
192 from = first->from;
193 to = first->to;
194#ifdef QT_DEBUG
195 name = QString::fromLatin1("%1 | %2").arg(first->toString(), second->toString());
196#endif
197 }
198
199 virtual void updateChildrenSizes() override;
200 bool calculateSizeHints();
201
202 bool secondForward() const {
203 // We have the convention that the first children will define the direction of the
204 // pararell group. Note that we can't rely on 'this->from' or 'this->to' because they
205 // might be changed by vertex simplification.
207 }
208
211
214};
215
236
237#ifdef QT_DEBUG
238inline QString AnchorVertex::toString() const
239{
240 using namespace Qt::StringLiterals;
241
242 if (!m_item)
243 return QString::fromLatin1("NULL_%1").arg(quintptr(this));
244
246 switch (m_edge) {
247 case Qt::AnchorLeft:
248 edge = "Left"_L1;
249 break;
251 edge = "HorizontalCenter"_L1;
252 break;
253 case Qt::AnchorRight:
254 edge = "Right"_L1;
255 break;
256 case Qt::AnchorTop:
257 edge = "Top"_L1;
258 break;
260 edge = "VerticalCenter"_L1;
261 break;
262 case Qt::AnchorBottom:
263 edge = "Bottom"_L1;
264 break;
265 default:
266 edge = "None"_L1;
267 break;
268 }
270 if (m_item->isLayout()) {
271 itemName = "layout"_L1;
272 } else {
274 itemName = item->data(0).toString();
275 }
276 }
277 edge.insert(0, "%1_"_L1);
278 return edge.arg(itemName);
279}
280#endif
281
282/*!
283 \internal
284
285 Representation of a valid path for a given vertex in the graph.
286 In this struct, "positives" is the set of anchors that have been
287 traversed in the forward direction, while "negatives" is the set
288 with the ones walked backwards.
289
290 This paths are compared against each other to produce LP Constraints,
291 the exact order in which the anchors were traversed is not relevant.
292*/
294{
295public:
297
298 QSimplexConstraint *constraint(const GraphPath &path) const;
299#ifdef QT_DEBUG
300 QString toString() const;
301#endif
304};
305} // namespace QtGraphicsAnchorLayout
306using namespace QtGraphicsAnchorLayout;
307
309
310class QGraphicsAnchorLayoutPrivate;
311/*!
312 \internal
313*/
315{
316 Q_DECLARE_PUBLIC(QGraphicsAnchor)
317
318public:
321
322 void setSpacing(qreal value);
323 void unsetSpacing();
324 qreal spacing() const;
325
326 void setSizePolicy(QSizePolicy::Policy policy);
327
328 static QGraphicsAnchorPrivate *get(QGraphicsAnchor *q)
329 { return q->d_func(); }
330
331 QGraphicsAnchorLayoutPrivate *layoutPrivate;
333
334 // Size information for user controlled anchor
337
338 uint hasSize : 1; // if false, get size from style.
339};
340
341
342
343
344/*!
345 \internal
346
347 QGraphicsAnchorLayout private methods and attributes.
348*/
349class Q_AUTOTEST_EXPORT QGraphicsAnchorLayoutPrivate : public QGraphicsLayoutPrivate
350{
351 Q_DECLARE_PUBLIC(QGraphicsAnchorLayout)
352
353public:
354 // When the layout geometry is different from its Minimum, Preferred
355 // or Maximum values, interpolation is used to calculate the geometries
356 // of the items.
357 //
358 // Interval represents which interpolation interval are we operating in.
359 enum Interval {
360 MinimumToMinPreferred = 0,
361 MinPreferredToPreferred,
362 PreferredToMaxPreferred,
363 MaxPreferredToMaximum
364 };
365
366 typedef Qt::Orientation Orientation [[deprecated]];
367 [[deprecated]] static inline constexpr Qt::Orientation Horizontal = Qt::Horizontal;
368 [[deprecated]] static inline constexpr Qt::Orientation Vertical = Qt::Vertical;
369
370 QGraphicsAnchorLayoutPrivate();
371
372 static QGraphicsAnchorLayoutPrivate *get(QGraphicsAnchorLayout *q)
373 {
374 return q ? q->d_func() : nullptr;
375 }
376
377 static Qt::AnchorPoint oppositeEdge(
378 Qt::AnchorPoint edge);
379
380 static Qt::Orientation edgeOrientation(Qt::AnchorPoint edge) noexcept;
381
382 static Qt::AnchorPoint pickEdge(Qt::AnchorPoint edge, Qt::Orientation orientation)
383 {
384 if (orientation == Qt::Vertical && int(edge) <= 2)
385 return (Qt::AnchorPoint)(edge + 3);
386 else if (orientation == Qt::Horizontal && int(edge) >= 3) {
387 return (Qt::AnchorPoint)(edge - 3);
388 }
389 return edge;
390 }
391
392 // Init methods
393 void createLayoutEdges();
394 void deleteLayoutEdges();
395 void createItemEdges(QGraphicsLayoutItem *item);
396 void createCenterAnchors(QGraphicsLayoutItem *item, Qt::AnchorPoint centerEdge);
397 void removeCenterAnchors(QGraphicsLayoutItem *item, Qt::AnchorPoint centerEdge, bool substitute = true);
398 void removeCenterConstraints(QGraphicsLayoutItem *item, Qt::Orientation orientation);
399
400 QGraphicsAnchor *acquireGraphicsAnchor(AnchorData *data)
401 {
402 Q_Q(QGraphicsAnchorLayout);
403 if (!data->graphicsAnchor) {
404 data->graphicsAnchor = new QGraphicsAnchor(q);
405 data->graphicsAnchor->d_func()->data = data;
406 }
407 return data->graphicsAnchor;
408 }
409
410 // function used by the 4 API functions
411 QGraphicsAnchor *addAnchor(QGraphicsLayoutItem *firstItem,
412 Qt::AnchorPoint firstEdge,
413 QGraphicsLayoutItem *secondItem,
414 Qt::AnchorPoint secondEdge,
415 qreal *spacing = nullptr);
416
417 // Helper for Anchor Manipulation methods
418 void addAnchor_helper(QGraphicsLayoutItem *firstItem,
419 Qt::AnchorPoint firstEdge,
420 QGraphicsLayoutItem *secondItem,
421 Qt::AnchorPoint secondEdge,
422 AnchorData *data);
423
424 QGraphicsAnchor *getAnchor(QGraphicsLayoutItem *firstItem, Qt::AnchorPoint firstEdge,
425 QGraphicsLayoutItem *secondItem, Qt::AnchorPoint secondEdge);
426
427 void removeAnchor(AnchorVertex *firstVertex, AnchorVertex *secondVertex);
428 void removeAnchor_helper(AnchorVertex *v1, AnchorVertex *v2);
429
430 void removeAnchors(QGraphicsLayoutItem *item);
431
432 void removeVertex(QGraphicsLayoutItem *item, Qt::AnchorPoint edge);
433
434 void correctEdgeDirection(QGraphicsLayoutItem *&firstItem,
435 Qt::AnchorPoint &firstEdge,
436 QGraphicsLayoutItem *&secondItem,
437 Qt::AnchorPoint &secondEdge);
438
439 QLayoutStyleInfo &styleInfo() const;
440
441 AnchorData *addAnchorMaybeParallel(AnchorData *newAnchor, bool *feasible);
442
443 // Activation
444 void calculateGraphs();
445 void calculateGraphs(Qt::Orientation orientation);
446
447 // Simplification
448 bool simplifyGraph(Qt::Orientation orientation);
449 bool simplifyVertices(Qt::Orientation orientation);
450 bool simplifyGraphIteration(Qt::Orientation orientation, bool *feasible);
451
452 bool replaceVertex(Qt::Orientation orientation, AnchorVertex *oldV,
453 AnchorVertex *newV, const QList<AnchorData *> &edges);
454
455
456 void restoreSimplifiedGraph(Qt::Orientation orientation);
457 void restoreSimplifiedAnchor(AnchorData *edge);
458 void restoreSimplifiedConstraints(ParallelAnchorData *parallel);
459 void restoreVertices(Qt::Orientation orientation);
460
461 bool calculateTrunk(Qt::Orientation orientation, const GraphPath &trunkPath,
462 const QList<QSimplexConstraint *> &constraints,
463 const QList<AnchorData *> &variables);
464 bool calculateNonTrunk(const QList<QSimplexConstraint *> &constraints,
465 const QList<AnchorData *> &variables);
466
467 // Support functions for calculateGraph()
468 void refreshAllSizeHints(Qt::Orientation orientation);
469 void findPaths(Qt::Orientation orientation);
470 void constraintsFromPaths(Qt::Orientation orientation);
471 void updateAnchorSizes(Qt::Orientation orientation);
472 QList<QSimplexConstraint *> constraintsFromSizeHints(const QList<AnchorData *> &anchors);
473 struct GraphParts {
474 QList<QSimplexConstraint *> trunkConstraints;
475 QList<QSimplexConstraint *> nonTrunkConstraints;
476 };
477 GraphParts getGraphParts(Qt::Orientation orientation);
478 void identifyFloatItems(const QSet<AnchorData *> &visited, Qt::Orientation orientation);
479 void identifyNonFloatItems_helper(const AnchorData *ad, QSet<QGraphicsLayoutItem *> *nonFloatingItemsIdentifiedSoFar);
480
481 inline AnchorVertex *internalVertex(const std::pair<QGraphicsLayoutItem*, Qt::AnchorPoint> &itemEdge) const
482 {
483 return m_vertexList.value(itemEdge).first;
484 }
485
486 inline AnchorVertex *internalVertex(const QGraphicsLayoutItem *item, Qt::AnchorPoint edge) const
487 {
488 return internalVertex(std::pair(const_cast<QGraphicsLayoutItem *>(item), edge));
489 }
490
491 inline void changeLayoutVertex(Qt::Orientation orientation, AnchorVertex *oldV, AnchorVertex *newV)
492 {
493 if (layoutFirstVertex[orientation] == oldV)
494 layoutFirstVertex[orientation] = newV;
495 else if (layoutCentralVertex[orientation] == oldV)
496 layoutCentralVertex[orientation] = newV;
497 else if (layoutLastVertex[orientation] == oldV)
498 layoutLastVertex[orientation] = newV;
499 }
500
501
502 AnchorVertex *addInternalVertex(QGraphicsLayoutItem *item, Qt::AnchorPoint edge);
503 void removeInternalVertex(QGraphicsLayoutItem *item, Qt::AnchorPoint edge);
504
505 // Geometry interpolation methods
506 void setItemsGeometries(const QRectF &geom);
507
508 void calculateVertexPositions(Qt::Orientation orientation);
509 void setupEdgesInterpolation(Qt::Orientation orientation);
510 void interpolateEdge(AnchorVertex *base, AnchorData *edge);
511
512 // Linear Programming solver methods
513 bool solveMinMax(const QList<QSimplexConstraint *> &constraints,
514 const GraphPath &path, qreal *min, qreal *max);
515 bool solvePreferred(const QList<QSimplexConstraint *> &constraints,
516 const QList<AnchorData *> &variables);
517 bool hasConflicts() const;
518
519#ifdef QT_DEBUG
520 void dumpGraph(const QString &name = QString());
521#endif
522
523
524 QHVContainer<qreal> spacings = {-1, -1};
525 // Size hints from simplex engine
526 QHVContainer<std::array<qreal, 3>> sizeHints = {{-1, -1, -1}, {-1, -1, -1}};
527
528 // Items
529 QList<QGraphicsLayoutItem *> items;
530
531 // Mapping between high level anchorage points (Item, Edge) to low level
532 // ones (Graph Vertices)
533
534 QHash<std::pair<QGraphicsLayoutItem*, Qt::AnchorPoint>, std::pair<AnchorVertex *, int> > m_vertexList;
535
536 // Internal graph of anchorage points and anchors, for both orientations
537 QHVContainer<Graph<AnchorVertex, AnchorData>> graph;
538
539 QHVContainer<AnchorVertex *> layoutFirstVertex = {};
540 QHVContainer<AnchorVertex *> layoutCentralVertex = {};
541 QHVContainer<AnchorVertex *> layoutLastVertex = {};
542
543 // Combined anchors in order of creation
544 QHVContainer<QList<AnchorVertexPair *>> simplifiedVertices;
545 QHVContainer<QList<AnchorData *>> anchorsFromSimplifiedVertices;
546
547 // Graph paths and constraints, for both orientations
548 QHVContainer<QMultiHash<AnchorVertex *, GraphPath>> graphPaths;
549 QHVContainer<QList<QSimplexConstraint *>> constraints;
550 QHVContainer<QList<QSimplexConstraint *>> itemCenterConstraints;
551
552 // The interpolation interval and progress based on the current size
553 // as well as the key values (minimum, preferred and maximum)
554 QHVContainer<Interval> interpolationInterval;
555 QHVContainer<qreal> interpolationProgress = {-1, -1};
556
557 QHVContainer<bool> graphHasConflicts = {};
558 QHVContainer<QSet<QGraphicsLayoutItem *>> m_floatItems;
559
560#if defined(QT_DEBUG) || defined(QT_BUILD_INTERNAL)
561 QHVContainer<bool> lastCalculationUsedSimplex;
562#endif
563
564 uint calculateGraphCacheDirty : 1;
565 mutable uint styleInfoDirty : 1;
566 mutable QLayoutStyleInfo cachedStyleInfo;
567
568 friend class QGraphicsAnchorPrivate;
569};
570
571QT_END_NAMESPACE
572
573#endif
void setSizePolicy(QSizePolicy::Policy policy)
static QGraphicsAnchorPrivate * get(QGraphicsAnchor *q)
QGraphicsAnchorLayoutPrivate * layoutPrivate
QSimplexConstraint * constraint(const GraphPath &path) const
QT_REQUIRE_CONFIG(animation)
Q_DECLARE_TYPEINFO(GraphPath, Q_RELOCATABLE_TYPE)
QT_REQUIRE_CONFIG(graphicsview)
void refreshSizeHints(const QLayoutStyleInfo *styleInfo=nullptr)
AnchorVertexPair(AnchorVertex *v1, AnchorVertex *v2, AnchorData *data)
AnchorVertex(QGraphicsLayoutItem *item, Qt::AnchorPoint edge)
ParallelAnchorData(AnchorData *first, AnchorData *second)
SequentialAnchorData(const QList< AnchorVertex * > &vertices, const QList< AnchorData * > &edges)