Absolute File Name: | /home/qt/qt5_coco/qt5/qtbase/src/widgets/graphicsview/qgraphicsanchorlayout_p.cpp |
Source code | Switch to Preprocessed file |
Line | Source | Count | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | /**************************************************************************** | - | ||||||||||||||||||
2 | ** | - | ||||||||||||||||||
3 | ** Copyright (C) 2015 The Qt Company Ltd. | - | ||||||||||||||||||
4 | ** Contact: http://www.qt.io/licensing/ | - | ||||||||||||||||||
5 | ** | - | ||||||||||||||||||
6 | ** This file is part of the QtWidgets module of the Qt Toolkit. | - | ||||||||||||||||||
7 | ** | - | ||||||||||||||||||
8 | ** $QT_BEGIN_LICENSE:LGPL21$ | - | ||||||||||||||||||
9 | ** Commercial License Usage | - | ||||||||||||||||||
10 | ** Licensees holding valid commercial Qt licenses may use this file in | - | ||||||||||||||||||
11 | ** accordance with the commercial license agreement provided with the | - | ||||||||||||||||||
12 | ** Software or, alternatively, in accordance with the terms contained in | - | ||||||||||||||||||
13 | ** a written agreement between you and The Qt Company. For licensing terms | - | ||||||||||||||||||
14 | ** and conditions see http://www.qt.io/terms-conditions. For further | - | ||||||||||||||||||
15 | ** information use the contact form at http://www.qt.io/contact-us. | - | ||||||||||||||||||
16 | ** | - | ||||||||||||||||||
17 | ** GNU Lesser General Public License Usage | - | ||||||||||||||||||
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser | - | ||||||||||||||||||
19 | ** General Public License version 2.1 or version 3 as published by the Free | - | ||||||||||||||||||
20 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and | - | ||||||||||||||||||
21 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the | - | ||||||||||||||||||
22 | ** following information to ensure the GNU Lesser General Public License | - | ||||||||||||||||||
23 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and | - | ||||||||||||||||||
24 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. | - | ||||||||||||||||||
25 | ** | - | ||||||||||||||||||
26 | ** As a special exception, The Qt Company gives you certain additional | - | ||||||||||||||||||
27 | ** rights. These rights are described in The Qt Company LGPL Exception | - | ||||||||||||||||||
28 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | - | ||||||||||||||||||
29 | ** | - | ||||||||||||||||||
30 | ** $QT_END_LICENSE$ | - | ||||||||||||||||||
31 | ** | - | ||||||||||||||||||
32 | ****************************************************************************/ | - | ||||||||||||||||||
33 | - | |||||||||||||||||||
34 | #include <QtWidgets/qwidget.h> | - | ||||||||||||||||||
35 | #include <QtWidgets/qapplication.h> | - | ||||||||||||||||||
36 | #include <QtCore/qlinkedlist.h> | - | ||||||||||||||||||
37 | #include <QtCore/qstack.h> | - | ||||||||||||||||||
38 | - | |||||||||||||||||||
39 | #ifdef QT_DEBUG | - | ||||||||||||||||||
40 | #include <QtCore/qfile.h> | - | ||||||||||||||||||
41 | #endif | - | ||||||||||||||||||
42 | - | |||||||||||||||||||
43 | #include "qgraphicsanchorlayout_p.h" | - | ||||||||||||||||||
44 | - | |||||||||||||||||||
45 | #ifndef QT_NO_GRAPHICSVIEW | - | ||||||||||||||||||
46 | QT_BEGIN_NAMESPACE | - | ||||||||||||||||||
47 | - | |||||||||||||||||||
48 | // To ensure that all variables inside the simplex solver are non-negative, | - | ||||||||||||||||||
49 | // we limit the size of anchors in the interval [-limit, limit]. Then before | - | ||||||||||||||||||
50 | // sending them to the simplex solver we add "limit" as an offset, so that | - | ||||||||||||||||||
51 | // they are actually calculated in the interval [0, 2 * limit] | - | ||||||||||||||||||
52 | // To avoid numerical errors in platforms where we use single precision, | - | ||||||||||||||||||
53 | // we use a tighter limit for the variables range. | - | ||||||||||||||||||
54 | const qreal g_offset = (sizeof(qreal) == sizeof(double)) ? QWIDGETSIZE_MAX : QWIDGETSIZE_MAX / 32; | - | ||||||||||||||||||
55 | - | |||||||||||||||||||
56 | QGraphicsAnchorPrivate::QGraphicsAnchorPrivate(int version) | - | ||||||||||||||||||
57 | : QObjectPrivate(version), layoutPrivate(0), data(0), | - | ||||||||||||||||||
58 | sizePolicy(QSizePolicy::Fixed), preferredSize(0), | - | ||||||||||||||||||
59 | hasSize(true) | - | ||||||||||||||||||
60 | { | - | ||||||||||||||||||
61 | } never executed: end of block | 0 | ||||||||||||||||||
62 | - | |||||||||||||||||||
63 | QGraphicsAnchorPrivate::~QGraphicsAnchorPrivate() | - | ||||||||||||||||||
64 | { | - | ||||||||||||||||||
65 | if (data) {
| 0 | ||||||||||||||||||
66 | // The QGraphicsAnchor was already deleted at this moment. We must clean | - | ||||||||||||||||||
67 | // the dangling pointer to avoid double deletion in the AnchorData dtor. | - | ||||||||||||||||||
68 | data->graphicsAnchor = 0; | - | ||||||||||||||||||
69 | - | |||||||||||||||||||
70 | layoutPrivate->removeAnchor(data->from, data->to); | - | ||||||||||||||||||
71 | } never executed: end of block | 0 | ||||||||||||||||||
72 | } never executed: end of block | 0 | ||||||||||||||||||
73 | - | |||||||||||||||||||
74 | void QGraphicsAnchorPrivate::setSizePolicy(QSizePolicy::Policy policy) | - | ||||||||||||||||||
75 | { | - | ||||||||||||||||||
76 | if (sizePolicy != policy) {
| 0 | ||||||||||||||||||
77 | sizePolicy = policy; | - | ||||||||||||||||||
78 | layoutPrivate->q_func()->invalidate(); | - | ||||||||||||||||||
79 | } never executed: end of block | 0 | ||||||||||||||||||
80 | } never executed: end of block | 0 | ||||||||||||||||||
81 | - | |||||||||||||||||||
82 | void QGraphicsAnchorPrivate::setSpacing(qreal value) | - | ||||||||||||||||||
83 | { | - | ||||||||||||||||||
84 | if (!data) {
| 0 | ||||||||||||||||||
85 | qWarning("QGraphicsAnchor::setSpacing: The anchor does not exist."); | - | ||||||||||||||||||
86 | return; never executed: return; | 0 | ||||||||||||||||||
87 | } | - | ||||||||||||||||||
88 | - | |||||||||||||||||||
89 | if (hasSize && (preferredSize == value))
| 0 | ||||||||||||||||||
90 | return; never executed: return; | 0 | ||||||||||||||||||
91 | - | |||||||||||||||||||
92 | // The anchor has an user-defined size | - | ||||||||||||||||||
93 | hasSize = true; | - | ||||||||||||||||||
94 | preferredSize = value; | - | ||||||||||||||||||
95 | - | |||||||||||||||||||
96 | layoutPrivate->q_func()->invalidate(); | - | ||||||||||||||||||
97 | } never executed: end of block | 0 | ||||||||||||||||||
98 | - | |||||||||||||||||||
99 | void QGraphicsAnchorPrivate::unsetSpacing() | - | ||||||||||||||||||
100 | { | - | ||||||||||||||||||
101 | if (!data) {
| 0 | ||||||||||||||||||
102 | qWarning("QGraphicsAnchor::setSpacing: The anchor does not exist."); | - | ||||||||||||||||||
103 | return; never executed: return; | 0 | ||||||||||||||||||
104 | } | - | ||||||||||||||||||
105 | - | |||||||||||||||||||
106 | // Return to standard direction | - | ||||||||||||||||||
107 | hasSize = false; | - | ||||||||||||||||||
108 | - | |||||||||||||||||||
109 | layoutPrivate->q_func()->invalidate(); | - | ||||||||||||||||||
110 | } never executed: end of block | 0 | ||||||||||||||||||
111 | - | |||||||||||||||||||
112 | qreal QGraphicsAnchorPrivate::spacing() const | - | ||||||||||||||||||
113 | { | - | ||||||||||||||||||
114 | if (!data) {
| 0 | ||||||||||||||||||
115 | qWarning("QGraphicsAnchor::setSpacing: The anchor does not exist."); | - | ||||||||||||||||||
116 | return 0; never executed: return 0; | 0 | ||||||||||||||||||
117 | } | - | ||||||||||||||||||
118 | - | |||||||||||||||||||
119 | return preferredSize; never executed: return preferredSize; | 0 | ||||||||||||||||||
120 | } | - | ||||||||||||||||||
121 | - | |||||||||||||||||||
122 | - | |||||||||||||||||||
123 | static void applySizePolicy(QSizePolicy::Policy policy, | - | ||||||||||||||||||
124 | qreal minSizeHint, qreal prefSizeHint, qreal maxSizeHint, | - | ||||||||||||||||||
125 | qreal *minSize, qreal *prefSize, | - | ||||||||||||||||||
126 | qreal *maxSize) | - | ||||||||||||||||||
127 | { | - | ||||||||||||||||||
128 | // minSize, prefSize and maxSize are initialized | - | ||||||||||||||||||
129 | // with item's preferred Size: this is QSizePolicy::Fixed. | - | ||||||||||||||||||
130 | // | - | ||||||||||||||||||
131 | // Then we check each flag to find the resultant QSizePolicy, | - | ||||||||||||||||||
132 | // according to the following table: | - | ||||||||||||||||||
133 | // | - | ||||||||||||||||||
134 | // constant value | - | ||||||||||||||||||
135 | // QSizePolicy::Fixed 0 | - | ||||||||||||||||||
136 | // QSizePolicy::Minimum GrowFlag | - | ||||||||||||||||||
137 | // QSizePolicy::Maximum ShrinkFlag | - | ||||||||||||||||||
138 | // QSizePolicy::Preferred GrowFlag | ShrinkFlag | - | ||||||||||||||||||
139 | // QSizePolicy::Ignored GrowFlag | ShrinkFlag | IgnoreFlag | - | ||||||||||||||||||
140 | - | |||||||||||||||||||
141 | if (policy & QSizePolicy::ShrinkFlag)
| 0 | ||||||||||||||||||
142 | *minSize = minSizeHint; never executed: *minSize = minSizeHint; | 0 | ||||||||||||||||||
143 | else | - | ||||||||||||||||||
144 | *minSize = prefSizeHint; never executed: *minSize = prefSizeHint; | 0 | ||||||||||||||||||
145 | - | |||||||||||||||||||
146 | if (policy & QSizePolicy::GrowFlag)
| 0 | ||||||||||||||||||
147 | *maxSize = maxSizeHint; never executed: *maxSize = maxSizeHint; | 0 | ||||||||||||||||||
148 | else | - | ||||||||||||||||||
149 | *maxSize = prefSizeHint; never executed: *maxSize = prefSizeHint; | 0 | ||||||||||||||||||
150 | - | |||||||||||||||||||
151 | // Note that these two initializations are affected by the previous flags | - | ||||||||||||||||||
152 | if (policy & QSizePolicy::IgnoreFlag)
| 0 | ||||||||||||||||||
153 | *prefSize = *minSize; never executed: *prefSize = *minSize; | 0 | ||||||||||||||||||
154 | else | - | ||||||||||||||||||
155 | *prefSize = prefSizeHint; never executed: *prefSize = prefSizeHint; | 0 | ||||||||||||||||||
156 | } | - | ||||||||||||||||||
157 | - | |||||||||||||||||||
158 | AnchorData::~AnchorData() | - | ||||||||||||||||||
159 | { | - | ||||||||||||||||||
160 | if (graphicsAnchor) {
| 0 | ||||||||||||||||||
161 | // Remove reference to ourself to avoid double removal in | - | ||||||||||||||||||
162 | // QGraphicsAnchorPrivate dtor. | - | ||||||||||||||||||
163 | graphicsAnchor->d_func()->data = 0; | - | ||||||||||||||||||
164 | - | |||||||||||||||||||
165 | delete graphicsAnchor; | - | ||||||||||||||||||
166 | } never executed: end of block | 0 | ||||||||||||||||||
167 | } never executed: end of block | 0 | ||||||||||||||||||
168 | - | |||||||||||||||||||
169 | - | |||||||||||||||||||
170 | void AnchorData::refreshSizeHints(const QLayoutStyleInfo *styleInfo) | - | ||||||||||||||||||
171 | { | - | ||||||||||||||||||
172 | QSizePolicy::Policy policy; | - | ||||||||||||||||||
173 | qreal minSizeHint; | - | ||||||||||||||||||
174 | qreal prefSizeHint; | - | ||||||||||||||||||
175 | qreal maxSizeHint; | - | ||||||||||||||||||
176 | - | |||||||||||||||||||
177 | if (item) {
| 0 | ||||||||||||||||||
178 | // It is an internal anchor, fetch size information from the item | - | ||||||||||||||||||
179 | if (isLayoutAnchor) {
| 0 | ||||||||||||||||||
180 | minSize = 0; | - | ||||||||||||||||||
181 | prefSize = 0; | - | ||||||||||||||||||
182 | maxSize = QWIDGETSIZE_MAX; | - | ||||||||||||||||||
183 | if (isCenterAnchor)
| 0 | ||||||||||||||||||
184 | maxSize /= 2; never executed: maxSize /= 2; | 0 | ||||||||||||||||||
185 | - | |||||||||||||||||||
186 | minPrefSize = prefSize; | - | ||||||||||||||||||
187 | maxPrefSize = maxSize; | - | ||||||||||||||||||
188 | return; never executed: return; | 0 | ||||||||||||||||||
189 | } else { | - | ||||||||||||||||||
190 | if (orientation == QGraphicsAnchorLayoutPrivate::Horizontal) {
| 0 | ||||||||||||||||||
191 | policy = item->sizePolicy().horizontalPolicy(); | - | ||||||||||||||||||
192 | minSizeHint = item->effectiveSizeHint(Qt::MinimumSize).width(); | - | ||||||||||||||||||
193 | prefSizeHint = item->effectiveSizeHint(Qt::PreferredSize).width(); | - | ||||||||||||||||||
194 | maxSizeHint = item->effectiveSizeHint(Qt::MaximumSize).width(); | - | ||||||||||||||||||
195 | } else { never executed: end of block | 0 | ||||||||||||||||||
196 | policy = item->sizePolicy().verticalPolicy(); | - | ||||||||||||||||||
197 | minSizeHint = item->effectiveSizeHint(Qt::MinimumSize).height(); | - | ||||||||||||||||||
198 | prefSizeHint = item->effectiveSizeHint(Qt::PreferredSize).height(); | - | ||||||||||||||||||
199 | maxSizeHint = item->effectiveSizeHint(Qt::MaximumSize).height(); | - | ||||||||||||||||||
200 | } never executed: end of block | 0 | ||||||||||||||||||
201 | - | |||||||||||||||||||
202 | if (isCenterAnchor) {
| 0 | ||||||||||||||||||
203 | minSizeHint /= 2; | - | ||||||||||||||||||
204 | prefSizeHint /= 2; | - | ||||||||||||||||||
205 | maxSizeHint /= 2; | - | ||||||||||||||||||
206 | } never executed: end of block | 0 | ||||||||||||||||||
207 | } never executed: end of block | 0 | ||||||||||||||||||
208 | } else { | - | ||||||||||||||||||
209 | // It is a user-created anchor, fetch size information from the associated QGraphicsAnchor | - | ||||||||||||||||||
210 | Q_ASSERT(graphicsAnchor); | - | ||||||||||||||||||
211 | QGraphicsAnchorPrivate *anchorPrivate = graphicsAnchor->d_func(); | - | ||||||||||||||||||
212 | - | |||||||||||||||||||
213 | // Policy, min and max sizes are straightforward | - | ||||||||||||||||||
214 | policy = anchorPrivate->sizePolicy; | - | ||||||||||||||||||
215 | minSizeHint = 0; | - | ||||||||||||||||||
216 | maxSizeHint = QWIDGETSIZE_MAX; | - | ||||||||||||||||||
217 | - | |||||||||||||||||||
218 | // Preferred Size | - | ||||||||||||||||||
219 | if (anchorPrivate->hasSize) {
| 0 | ||||||||||||||||||
220 | // Anchor has user-defined size | - | ||||||||||||||||||
221 | prefSizeHint = anchorPrivate->preferredSize; | - | ||||||||||||||||||
222 | } else { never executed: end of block | 0 | ||||||||||||||||||
223 | // Fetch size information from style | - | ||||||||||||||||||
224 | const Qt::Orientation orient = Qt::Orientation(QGraphicsAnchorLayoutPrivate::edgeOrientation(from->m_edge) + 1); | - | ||||||||||||||||||
225 | qreal s = styleInfo->defaultSpacing(orient); | - | ||||||||||||||||||
226 | if (s < 0) {
| 0 | ||||||||||||||||||
227 | QSizePolicy::ControlType controlTypeFrom = from->m_item->sizePolicy().controlType(); | - | ||||||||||||||||||
228 | QSizePolicy::ControlType controlTypeTo = to->m_item->sizePolicy().controlType(); | - | ||||||||||||||||||
229 | s = styleInfo->perItemSpacing(controlTypeFrom, controlTypeTo, orient); | - | ||||||||||||||||||
230 | - | |||||||||||||||||||
231 | // ### Currently we do not support negative anchors inside the graph. | - | ||||||||||||||||||
232 | // To avoid those being created by a negative style spacing, we must | - | ||||||||||||||||||
233 | // make this test. | - | ||||||||||||||||||
234 | if (s < 0)
| 0 | ||||||||||||||||||
235 | s = 0; never executed: s = 0; | 0 | ||||||||||||||||||
236 | } never executed: end of block | 0 | ||||||||||||||||||
237 | prefSizeHint = s; | - | ||||||||||||||||||
238 | } never executed: end of block | 0 | ||||||||||||||||||
239 | } | - | ||||||||||||||||||
240 | - | |||||||||||||||||||
241 | // Fill minSize, prefSize and maxSize based on policy and sizeHints | - | ||||||||||||||||||
242 | applySizePolicy(policy, minSizeHint, prefSizeHint, maxSizeHint, | - | ||||||||||||||||||
243 | &minSize, &prefSize, &maxSize); | - | ||||||||||||||||||
244 | - | |||||||||||||||||||
245 | minPrefSize = prefSize; | - | ||||||||||||||||||
246 | maxPrefSize = maxSize; | - | ||||||||||||||||||
247 | - | |||||||||||||||||||
248 | // Set the anchor effective sizes to preferred. | - | ||||||||||||||||||
249 | // | - | ||||||||||||||||||
250 | // Note: The idea here is that all items should remain at their | - | ||||||||||||||||||
251 | // preferred size unless where that's impossible. In cases where | - | ||||||||||||||||||
252 | // the item is subject to restrictions (anchored to the layout | - | ||||||||||||||||||
253 | // edges, for instance), the simplex solver will be run to | - | ||||||||||||||||||
254 | // recalculate and override the values we set here. | - | ||||||||||||||||||
255 | sizeAtMinimum = prefSize; | - | ||||||||||||||||||
256 | sizeAtPreferred = prefSize; | - | ||||||||||||||||||
257 | sizeAtMaximum = prefSize; | - | ||||||||||||||||||
258 | } never executed: end of block | 0 | ||||||||||||||||||
259 | - | |||||||||||||||||||
260 | void ParallelAnchorData::updateChildrenSizes() | - | ||||||||||||||||||
261 | { | - | ||||||||||||||||||
262 | firstEdge->sizeAtMinimum = sizeAtMinimum; | - | ||||||||||||||||||
263 | firstEdge->sizeAtPreferred = sizeAtPreferred; | - | ||||||||||||||||||
264 | firstEdge->sizeAtMaximum = sizeAtMaximum; | - | ||||||||||||||||||
265 | - | |||||||||||||||||||
266 | if (secondForward()) {
| 0 | ||||||||||||||||||
267 | secondEdge->sizeAtMinimum = sizeAtMinimum; | - | ||||||||||||||||||
268 | secondEdge->sizeAtPreferred = sizeAtPreferred; | - | ||||||||||||||||||
269 | secondEdge->sizeAtMaximum = sizeAtMaximum; | - | ||||||||||||||||||
270 | } else { never executed: end of block | 0 | ||||||||||||||||||
271 | secondEdge->sizeAtMinimum = -sizeAtMinimum; | - | ||||||||||||||||||
272 | secondEdge->sizeAtPreferred = -sizeAtPreferred; | - | ||||||||||||||||||
273 | secondEdge->sizeAtMaximum = -sizeAtMaximum; | - | ||||||||||||||||||
274 | } never executed: end of block | 0 | ||||||||||||||||||
275 | - | |||||||||||||||||||
276 | firstEdge->updateChildrenSizes(); | - | ||||||||||||||||||
277 | secondEdge->updateChildrenSizes(); | - | ||||||||||||||||||
278 | } never executed: end of block | 0 | ||||||||||||||||||
279 | - | |||||||||||||||||||
280 | /* | - | ||||||||||||||||||
281 | \internal | - | ||||||||||||||||||
282 | - | |||||||||||||||||||
283 | Initialize the parallel anchor size hints using the sizeHint information from | - | ||||||||||||||||||
284 | its children. | - | ||||||||||||||||||
285 | - | |||||||||||||||||||
286 | Note that parallel groups can lead to unfeasibility, so during calculation, we can | - | ||||||||||||||||||
287 | find out one unfeasibility. Because of that this method return boolean. This can't | - | ||||||||||||||||||
288 | happen in sequential, so there the method is void. | - | ||||||||||||||||||
289 | */ | - | ||||||||||||||||||
290 | bool ParallelAnchorData::calculateSizeHints() | - | ||||||||||||||||||
291 | { | - | ||||||||||||||||||
292 | // Normalize second child sizes. | - | ||||||||||||||||||
293 | // A negative anchor of sizes min, minPref, pref, maxPref and max, is equivalent | - | ||||||||||||||||||
294 | // to a forward anchor of sizes -max, -maxPref, -pref, -minPref, -min | - | ||||||||||||||||||
295 | qreal secondMin; | - | ||||||||||||||||||
296 | qreal secondMinPref; | - | ||||||||||||||||||
297 | qreal secondPref; | - | ||||||||||||||||||
298 | qreal secondMaxPref; | - | ||||||||||||||||||
299 | qreal secondMax; | - | ||||||||||||||||||
300 | - | |||||||||||||||||||
301 | if (secondForward()) {
| 0 | ||||||||||||||||||
302 | secondMin = secondEdge->minSize; | - | ||||||||||||||||||
303 | secondMinPref = secondEdge->minPrefSize; | - | ||||||||||||||||||
304 | secondPref = secondEdge->prefSize; | - | ||||||||||||||||||
305 | secondMaxPref = secondEdge->maxPrefSize; | - | ||||||||||||||||||
306 | secondMax = secondEdge->maxSize; | - | ||||||||||||||||||
307 | } else { never executed: end of block | 0 | ||||||||||||||||||
308 | secondMin = -secondEdge->maxSize; | - | ||||||||||||||||||
309 | secondMinPref = -secondEdge->maxPrefSize; | - | ||||||||||||||||||
310 | secondPref = -secondEdge->prefSize; | - | ||||||||||||||||||
311 | secondMaxPref = -secondEdge->minPrefSize; | - | ||||||||||||||||||
312 | secondMax = -secondEdge->minSize; | - | ||||||||||||||||||
313 | } never executed: end of block | 0 | ||||||||||||||||||
314 | - | |||||||||||||||||||
315 | minSize = qMax(firstEdge->minSize, secondMin); | - | ||||||||||||||||||
316 | maxSize = qMin(firstEdge->maxSize, secondMax); | - | ||||||||||||||||||
317 | - | |||||||||||||||||||
318 | // This condition means that the maximum size of one anchor being simplified is smaller than | - | ||||||||||||||||||
319 | // the minimum size of the other anchor. The consequence is that there won't be a valid size | - | ||||||||||||||||||
320 | // for this parallel setup. | - | ||||||||||||||||||
321 | if (minSize > maxSize) {
| 0 | ||||||||||||||||||
322 | return false; never executed: return false; | 0 | ||||||||||||||||||
323 | } | - | ||||||||||||||||||
324 | - | |||||||||||||||||||
325 | // Preferred size calculation | - | ||||||||||||||||||
326 | // The calculation of preferred size is done as follows: | - | ||||||||||||||||||
327 | // | - | ||||||||||||||||||
328 | // 1) Check whether one of the child anchors is the layout structural anchor | - | ||||||||||||||||||
329 | // If so, we can simply copy the preferred information from the other child, | - | ||||||||||||||||||
330 | // after bounding it to our minimum and maximum sizes. | - | ||||||||||||||||||
331 | // If not, then we proceed with the actual calculations. | - | ||||||||||||||||||
332 | // | - | ||||||||||||||||||
333 | // 2) The whole algorithm for preferred size calculation is based on the fact | - | ||||||||||||||||||
334 | // that, if a given anchor cannot remain at its preferred size, it'd rather | - | ||||||||||||||||||
335 | // grow than shrink. | - | ||||||||||||||||||
336 | // | - | ||||||||||||||||||
337 | // What happens though is that while this affirmative is true for simple | - | ||||||||||||||||||
338 | // anchors, it may not be true for sequential anchors that have one or more | - | ||||||||||||||||||
339 | // reversed anchors inside it. That happens because when a sequential anchor | - | ||||||||||||||||||
340 | // grows, any reversed anchors inside it may be required to shrink, something | - | ||||||||||||||||||
341 | // we try to avoid, as said above. | - | ||||||||||||||||||
342 | // | - | ||||||||||||||||||
343 | // To overcome this, besides their actual preferred size "prefSize", each anchor | - | ||||||||||||||||||
344 | // exports what we call "minPrefSize" and "maxPrefSize". These two values define | - | ||||||||||||||||||
345 | // a surrounding interval where, if required to move, the anchor would rather | - | ||||||||||||||||||
346 | // remain inside. | - | ||||||||||||||||||
347 | // | - | ||||||||||||||||||
348 | // For standard anchors, this area simply represents the region between | - | ||||||||||||||||||
349 | // prefSize and maxSize, which makes sense since our first affirmation. | - | ||||||||||||||||||
350 | // For composed anchors, these values are calculated as to reduce the global | - | ||||||||||||||||||
351 | // "damage", that is, to reduce the total deviation and the total amount of | - | ||||||||||||||||||
352 | // anchors that had to shrink. | - | ||||||||||||||||||
353 | - | |||||||||||||||||||
354 | if (firstEdge->isLayoutAnchor) {
| 0 | ||||||||||||||||||
355 | prefSize = qBound(minSize, secondPref, maxSize); | - | ||||||||||||||||||
356 | minPrefSize = qBound(minSize, secondMinPref, maxSize); | - | ||||||||||||||||||
357 | maxPrefSize = qBound(minSize, secondMaxPref, maxSize); | - | ||||||||||||||||||
358 | } else if (secondEdge->isLayoutAnchor) { never executed: end of block
| 0 | ||||||||||||||||||
359 | prefSize = qBound(minSize, firstEdge->prefSize, maxSize); | - | ||||||||||||||||||
360 | minPrefSize = qBound(minSize, firstEdge->minPrefSize, maxSize); | - | ||||||||||||||||||
361 | maxPrefSize = qBound(minSize, firstEdge->maxPrefSize, maxSize); | - | ||||||||||||||||||
362 | } else { never executed: end of block | 0 | ||||||||||||||||||
363 | // Calculate the intersection between the "preferred" regions of each child | - | ||||||||||||||||||
364 | const qreal lowerBoundary = | - | ||||||||||||||||||
365 | qBound(minSize, qMax(firstEdge->minPrefSize, secondMinPref), maxSize); | - | ||||||||||||||||||
366 | const qreal upperBoundary = | - | ||||||||||||||||||
367 | qBound(minSize, qMin(firstEdge->maxPrefSize, secondMaxPref), maxSize); | - | ||||||||||||||||||
368 | const qreal prefMean = | - | ||||||||||||||||||
369 | qBound(minSize, (firstEdge->prefSize + secondPref) / 2, maxSize); | - | ||||||||||||||||||
370 | - | |||||||||||||||||||
371 | if (lowerBoundary < upperBoundary) {
| 0 | ||||||||||||||||||
372 | // If there is an intersection between the two regions, this intersection | - | ||||||||||||||||||
373 | // will be used as the preferred region of the parallel anchor itself. | - | ||||||||||||||||||
374 | // The preferred size will be the bounded average between the two preferred | - | ||||||||||||||||||
375 | // sizes. | - | ||||||||||||||||||
376 | prefSize = qBound(lowerBoundary, prefMean, upperBoundary); | - | ||||||||||||||||||
377 | minPrefSize = lowerBoundary; | - | ||||||||||||||||||
378 | maxPrefSize = upperBoundary; | - | ||||||||||||||||||
379 | } else { never executed: end of block | 0 | ||||||||||||||||||
380 | // If there is no intersection, we have to attribute "damage" to at least | - | ||||||||||||||||||
381 | // one of the children. The minimum total damage is achieved in points | - | ||||||||||||||||||
382 | // inside the region that extends from (1) the upper boundary of the lower | - | ||||||||||||||||||
383 | // region to (2) the lower boundary of the upper region. | - | ||||||||||||||||||
384 | // Then, we expose this region as _our_ preferred region and once again, | - | ||||||||||||||||||
385 | // use the bounded average as our preferred size. | - | ||||||||||||||||||
386 | prefSize = qBound(upperBoundary, prefMean, lowerBoundary); | - | ||||||||||||||||||
387 | minPrefSize = upperBoundary; | - | ||||||||||||||||||
388 | maxPrefSize = lowerBoundary; | - | ||||||||||||||||||
389 | } never executed: end of block | 0 | ||||||||||||||||||
390 | } | - | ||||||||||||||||||
391 | - | |||||||||||||||||||
392 | // See comment in AnchorData::refreshSizeHints() about sizeAt* values | - | ||||||||||||||||||
393 | sizeAtMinimum = prefSize; | - | ||||||||||||||||||
394 | sizeAtPreferred = prefSize; | - | ||||||||||||||||||
395 | sizeAtMaximum = prefSize; | - | ||||||||||||||||||
396 | - | |||||||||||||||||||
397 | return true; never executed: return true; | 0 | ||||||||||||||||||
398 | } | - | ||||||||||||||||||
399 | - | |||||||||||||||||||
400 | /*! | - | ||||||||||||||||||
401 | \internal | - | ||||||||||||||||||
402 | returns the factor in the interval [-1, 1]. | - | ||||||||||||||||||
403 | -1 is at Minimum | - | ||||||||||||||||||
404 | 0 is at Preferred | - | ||||||||||||||||||
405 | 1 is at Maximum | - | ||||||||||||||||||
406 | */ | - | ||||||||||||||||||
407 | static QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> getFactor(qreal value, qreal min, | - | ||||||||||||||||||
408 | qreal minPref, qreal pref, | - | ||||||||||||||||||
409 | qreal maxPref, qreal max) | - | ||||||||||||||||||
410 | { | - | ||||||||||||||||||
411 | QGraphicsAnchorLayoutPrivate::Interval interval; | - | ||||||||||||||||||
412 | qreal lower; | - | ||||||||||||||||||
413 | qreal upper; | - | ||||||||||||||||||
414 | - | |||||||||||||||||||
415 | if (value < minPref) {
| 0 | ||||||||||||||||||
416 | interval = QGraphicsAnchorLayoutPrivate::MinimumToMinPreferred; | - | ||||||||||||||||||
417 | lower = min; | - | ||||||||||||||||||
418 | upper = minPref; | - | ||||||||||||||||||
419 | } else if (value < pref) { never executed: end of block
| 0 | ||||||||||||||||||
420 | interval = QGraphicsAnchorLayoutPrivate::MinPreferredToPreferred; | - | ||||||||||||||||||
421 | lower = minPref; | - | ||||||||||||||||||
422 | upper = pref; | - | ||||||||||||||||||
423 | } else if (value < maxPref) { never executed: end of block
| 0 | ||||||||||||||||||
424 | interval = QGraphicsAnchorLayoutPrivate::PreferredToMaxPreferred; | - | ||||||||||||||||||
425 | lower = pref; | - | ||||||||||||||||||
426 | upper = maxPref; | - | ||||||||||||||||||
427 | } else { never executed: end of block | 0 | ||||||||||||||||||
428 | interval = QGraphicsAnchorLayoutPrivate::MaxPreferredToMaximum; | - | ||||||||||||||||||
429 | lower = maxPref; | - | ||||||||||||||||||
430 | upper = max; | - | ||||||||||||||||||
431 | } never executed: end of block | 0 | ||||||||||||||||||
432 | - | |||||||||||||||||||
433 | qreal progress; | - | ||||||||||||||||||
434 | if (upper == lower) {
| 0 | ||||||||||||||||||
435 | progress = 0; | - | ||||||||||||||||||
436 | } else { never executed: end of block | 0 | ||||||||||||||||||
437 | progress = (value - lower) / (upper - lower); | - | ||||||||||||||||||
438 | } never executed: end of block | 0 | ||||||||||||||||||
439 | - | |||||||||||||||||||
440 | return qMakePair(interval, progress); never executed: return qMakePair(interval, progress); | 0 | ||||||||||||||||||
441 | } | - | ||||||||||||||||||
442 | - | |||||||||||||||||||
443 | static qreal interpolate(const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> &factor, | - | ||||||||||||||||||
444 | qreal min, qreal minPref, qreal pref, qreal maxPref, qreal max) | - | ||||||||||||||||||
445 | { | - | ||||||||||||||||||
446 | qreal lower = 0; | - | ||||||||||||||||||
447 | qreal upper = 0; | - | ||||||||||||||||||
448 | - | |||||||||||||||||||
449 | switch (factor.first) { | - | ||||||||||||||||||
450 | case QGraphicsAnchorLayoutPrivate::MinimumToMinPreferred: never executed: case QGraphicsAnchorLayoutPrivate::MinimumToMinPreferred: | 0 | ||||||||||||||||||
451 | lower = min; | - | ||||||||||||||||||
452 | upper = minPref; | - | ||||||||||||||||||
453 | break; never executed: break; | 0 | ||||||||||||||||||
454 | case QGraphicsAnchorLayoutPrivate::MinPreferredToPreferred: never executed: case QGraphicsAnchorLayoutPrivate::MinPreferredToPreferred: | 0 | ||||||||||||||||||
455 | lower = minPref; | - | ||||||||||||||||||
456 | upper = pref; | - | ||||||||||||||||||
457 | break; never executed: break; | 0 | ||||||||||||||||||
458 | case QGraphicsAnchorLayoutPrivate::PreferredToMaxPreferred: never executed: case QGraphicsAnchorLayoutPrivate::PreferredToMaxPreferred: | 0 | ||||||||||||||||||
459 | lower = pref; | - | ||||||||||||||||||
460 | upper = maxPref; | - | ||||||||||||||||||
461 | break; never executed: break; | 0 | ||||||||||||||||||
462 | case QGraphicsAnchorLayoutPrivate::MaxPreferredToMaximum: never executed: case QGraphicsAnchorLayoutPrivate::MaxPreferredToMaximum: | 0 | ||||||||||||||||||
463 | lower = maxPref; | - | ||||||||||||||||||
464 | upper = max; | - | ||||||||||||||||||
465 | break; never executed: break; | 0 | ||||||||||||||||||
466 | } | - | ||||||||||||||||||
467 | - | |||||||||||||||||||
468 | return lower + factor.second * (upper - lower); never executed: return lower + factor.second * (upper - lower); | 0 | ||||||||||||||||||
469 | } | - | ||||||||||||||||||
470 | - | |||||||||||||||||||
471 | void SequentialAnchorData::updateChildrenSizes() | - | ||||||||||||||||||
472 | { | - | ||||||||||||||||||
473 | // Band here refers if the value is in the Minimum To Preferred | - | ||||||||||||||||||
474 | // band (the lower band) or the Preferred To Maximum (the upper band). | - | ||||||||||||||||||
475 | - | |||||||||||||||||||
476 | const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> minFactor = | - | ||||||||||||||||||
477 | getFactor(sizeAtMinimum, minSize, minPrefSize, prefSize, maxPrefSize, maxSize); | - | ||||||||||||||||||
478 | const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> prefFactor = | - | ||||||||||||||||||
479 | getFactor(sizeAtPreferred, minSize, minPrefSize, prefSize, maxPrefSize, maxSize); | - | ||||||||||||||||||
480 | const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> maxFactor = | - | ||||||||||||||||||
481 | getFactor(sizeAtMaximum, minSize, minPrefSize, prefSize, maxPrefSize, maxSize); | - | ||||||||||||||||||
482 | - | |||||||||||||||||||
483 | // XXX This is not safe if Vertex simplification takes place after the sequential | - | ||||||||||||||||||
484 | // anchor is created. In that case, "prev" will be a group-vertex, different from | - | ||||||||||||||||||
485 | // "from" or "to", that _contains_ one of them. | - | ||||||||||||||||||
486 | AnchorVertex *prev = from; | - | ||||||||||||||||||
487 | - | |||||||||||||||||||
488 | for (int i = 0; i < m_edges.count(); ++i) {
| 0 | ||||||||||||||||||
489 | AnchorData *e = m_edges.at(i); | - | ||||||||||||||||||
490 | - | |||||||||||||||||||
491 | const bool edgeIsForward = (e->from == prev); | - | ||||||||||||||||||
492 | if (edgeIsForward) {
| 0 | ||||||||||||||||||
493 | e->sizeAtMinimum = interpolate(minFactor, e->minSize, e->minPrefSize, | - | ||||||||||||||||||
494 | e->prefSize, e->maxPrefSize, e->maxSize); | - | ||||||||||||||||||
495 | e->sizeAtPreferred = interpolate(prefFactor, e->minSize, e->minPrefSize, | - | ||||||||||||||||||
496 | e->prefSize, e->maxPrefSize, e->maxSize); | - | ||||||||||||||||||
497 | e->sizeAtMaximum = interpolate(maxFactor, e->minSize, e->minPrefSize, | - | ||||||||||||||||||
498 | e->prefSize, e->maxPrefSize, e->maxSize); | - | ||||||||||||||||||
499 | prev = e->to; | - | ||||||||||||||||||
500 | } else { never executed: end of block | 0 | ||||||||||||||||||
501 | Q_ASSERT(prev == e->to); | - | ||||||||||||||||||
502 | e->sizeAtMinimum = interpolate(minFactor, e->maxSize, e->maxPrefSize, | - | ||||||||||||||||||
503 | e->prefSize, e->minPrefSize, e->minSize); | - | ||||||||||||||||||
504 | e->sizeAtPreferred = interpolate(prefFactor, e->maxSize, e->maxPrefSize, | - | ||||||||||||||||||
505 | e->prefSize, e->minPrefSize, e->minSize); | - | ||||||||||||||||||
506 | e->sizeAtMaximum = interpolate(maxFactor, e->maxSize, e->maxPrefSize, | - | ||||||||||||||||||
507 | e->prefSize, e->minPrefSize, e->minSize); | - | ||||||||||||||||||
508 | prev = e->from; | - | ||||||||||||||||||
509 | } never executed: end of block | 0 | ||||||||||||||||||
510 | - | |||||||||||||||||||
511 | e->updateChildrenSizes(); | - | ||||||||||||||||||
512 | } never executed: end of block | 0 | ||||||||||||||||||
513 | } never executed: end of block | 0 | ||||||||||||||||||
514 | - | |||||||||||||||||||
515 | void SequentialAnchorData::calculateSizeHints() | - | ||||||||||||||||||
516 | { | - | ||||||||||||||||||
517 | minSize = 0; | - | ||||||||||||||||||
518 | prefSize = 0; | - | ||||||||||||||||||
519 | maxSize = 0; | - | ||||||||||||||||||
520 | minPrefSize = 0; | - | ||||||||||||||||||
521 | maxPrefSize = 0; | - | ||||||||||||||||||
522 | - | |||||||||||||||||||
523 | AnchorVertex *prev = from; | - | ||||||||||||||||||
524 | - | |||||||||||||||||||
525 | for (int i = 0; i < m_edges.count(); ++i) {
| 0 | ||||||||||||||||||
526 | AnchorData *edge = m_edges.at(i); | - | ||||||||||||||||||
527 | - | |||||||||||||||||||
528 | const bool edgeIsForward = (edge->from == prev); | - | ||||||||||||||||||
529 | if (edgeIsForward) {
| 0 | ||||||||||||||||||
530 | minSize += edge->minSize; | - | ||||||||||||||||||
531 | prefSize += edge->prefSize; | - | ||||||||||||||||||
532 | maxSize += edge->maxSize; | - | ||||||||||||||||||
533 | minPrefSize += edge->minPrefSize; | - | ||||||||||||||||||
534 | maxPrefSize += edge->maxPrefSize; | - | ||||||||||||||||||
535 | prev = edge->to; | - | ||||||||||||||||||
536 | } else { never executed: end of block | 0 | ||||||||||||||||||
537 | Q_ASSERT(prev == edge->to); | - | ||||||||||||||||||
538 | minSize -= edge->maxSize; | - | ||||||||||||||||||
539 | prefSize -= edge->prefSize; | - | ||||||||||||||||||
540 | maxSize -= edge->minSize; | - | ||||||||||||||||||
541 | minPrefSize -= edge->maxPrefSize; | - | ||||||||||||||||||
542 | maxPrefSize -= edge->minPrefSize; | - | ||||||||||||||||||
543 | prev = edge->from; | - | ||||||||||||||||||
544 | } never executed: end of block | 0 | ||||||||||||||||||
545 | } | - | ||||||||||||||||||
546 | - | |||||||||||||||||||
547 | // See comment in AnchorData::refreshSizeHints() about sizeAt* values | - | ||||||||||||||||||
548 | sizeAtMinimum = prefSize; | - | ||||||||||||||||||
549 | sizeAtPreferred = prefSize; | - | ||||||||||||||||||
550 | sizeAtMaximum = prefSize; | - | ||||||||||||||||||
551 | } never executed: end of block | 0 | ||||||||||||||||||
552 | - | |||||||||||||||||||
553 | #ifdef QT_DEBUG | - | ||||||||||||||||||
554 | void AnchorData::dump(int indent) { | - | ||||||||||||||||||
555 | if (type == Parallel) {
| 0 | ||||||||||||||||||
556 | qDebug("%*s type: parallel:", indent, ""); | - | ||||||||||||||||||
557 | ParallelAnchorData *p = static_cast<ParallelAnchorData *>(this); | - | ||||||||||||||||||
558 | p->firstEdge->dump(indent+2); | - | ||||||||||||||||||
559 | p->secondEdge->dump(indent+2); | - | ||||||||||||||||||
560 | } else if (type == Sequential) { never executed: end of block
| 0 | ||||||||||||||||||
561 | SequentialAnchorData *s = static_cast<SequentialAnchorData *>(this); | - | ||||||||||||||||||
562 | int kids = s->m_edges.count(); | - | ||||||||||||||||||
563 | qDebug("%*s type: sequential(%d):", indent, "", kids); | - | ||||||||||||||||||
564 | for (int i = 0; i < kids; ++i) {
| 0 | ||||||||||||||||||
565 | s->m_edges.at(i)->dump(indent+2); | - | ||||||||||||||||||
566 | } never executed: end of block | 0 | ||||||||||||||||||
567 | } else { never executed: end of block | 0 | ||||||||||||||||||
568 | qDebug("%*s type: Normal:", indent, ""); | - | ||||||||||||||||||
569 | } never executed: end of block | 0 | ||||||||||||||||||
570 | } | - | ||||||||||||||||||
571 | - | |||||||||||||||||||
572 | #endif | - | ||||||||||||||||||
573 | - | |||||||||||||||||||
574 | QSimplexConstraint *GraphPath::constraint(const GraphPath &path) const | - | ||||||||||||||||||
575 | { | - | ||||||||||||||||||
576 | // Calculate | - | ||||||||||||||||||
577 | QSet<AnchorData *> cPositives; | - | ||||||||||||||||||
578 | QSet<AnchorData *> cNegatives; | - | ||||||||||||||||||
579 | QSet<AnchorData *> intersection; | - | ||||||||||||||||||
580 | - | |||||||||||||||||||
581 | cPositives = positives + path.negatives; | - | ||||||||||||||||||
582 | cNegatives = negatives + path.positives; | - | ||||||||||||||||||
583 | - | |||||||||||||||||||
584 | intersection = cPositives & cNegatives; | - | ||||||||||||||||||
585 | - | |||||||||||||||||||
586 | cPositives -= intersection; | - | ||||||||||||||||||
587 | cNegatives -= intersection; | - | ||||||||||||||||||
588 | - | |||||||||||||||||||
589 | // Fill | - | ||||||||||||||||||
590 | QSimplexConstraint *c = new QSimplexConstraint; | - | ||||||||||||||||||
591 | QSet<AnchorData *>::iterator i; | - | ||||||||||||||||||
592 | for (i = cPositives.begin(); i != cPositives.end(); ++i)
| 0 | ||||||||||||||||||
593 | c->variables.insert(*i, 1.0); never executed: c->variables.insert(*i, 1.0); | 0 | ||||||||||||||||||
594 | - | |||||||||||||||||||
595 | for (i = cNegatives.begin(); i != cNegatives.end(); ++i)
| 0 | ||||||||||||||||||
596 | c->variables.insert(*i, -1.0); never executed: c->variables.insert(*i, -1.0); | 0 | ||||||||||||||||||
597 | - | |||||||||||||||||||
598 | return c; never executed: return c; | 0 | ||||||||||||||||||
599 | } | - | ||||||||||||||||||
600 | - | |||||||||||||||||||
601 | #ifdef QT_DEBUG | - | ||||||||||||||||||
602 | QString GraphPath::toString() const | - | ||||||||||||||||||
603 | { | - | ||||||||||||||||||
604 | QString string(QLatin1String("Path: ")); | - | ||||||||||||||||||
605 | foreach(AnchorData *edge, positives) | - | ||||||||||||||||||
606 | string += QString::fromLatin1(" (+++) %1").arg(edge->toString()); never executed: string += QString::fromLatin1(" (+++) %1").arg(edge->toString()); | 0 | ||||||||||||||||||
607 | - | |||||||||||||||||||
608 | foreach(AnchorData *edge, negatives) | - | ||||||||||||||||||
609 | string += QString::fromLatin1(" (---) %1").arg(edge->toString()); never executed: string += QString::fromLatin1(" (---) %1").arg(edge->toString()); | 0 | ||||||||||||||||||
610 | - | |||||||||||||||||||
611 | return string; never executed: return string; | 0 | ||||||||||||||||||
612 | } | - | ||||||||||||||||||
613 | #endif | - | ||||||||||||||||||
614 | - | |||||||||||||||||||
615 | QGraphicsAnchorLayoutPrivate::QGraphicsAnchorLayoutPrivate() | - | ||||||||||||||||||
616 | : calculateGraphCacheDirty(true), styleInfoDirty(true) | - | ||||||||||||||||||
617 | { | - | ||||||||||||||||||
618 | for (int i = 0; i < NOrientations; ++i) {
| 0 | ||||||||||||||||||
619 | for (int j = 0; j < 3; ++j) {
| 0 | ||||||||||||||||||
620 | sizeHints[i][j] = -1; | - | ||||||||||||||||||
621 | } never executed: end of block | 0 | ||||||||||||||||||
622 | interpolationProgress[i] = -1; | - | ||||||||||||||||||
623 | - | |||||||||||||||||||
624 | spacings[i] = -1; | - | ||||||||||||||||||
625 | graphHasConflicts[i] = false; | - | ||||||||||||||||||
626 | - | |||||||||||||||||||
627 | layoutFirstVertex[i] = 0; | - | ||||||||||||||||||
628 | layoutCentralVertex[i] = 0; | - | ||||||||||||||||||
629 | layoutLastVertex[i] = 0; | - | ||||||||||||||||||
630 | } never executed: end of block | 0 | ||||||||||||||||||
631 | } never executed: end of block | 0 | ||||||||||||||||||
632 | - | |||||||||||||||||||
633 | Qt::AnchorPoint QGraphicsAnchorLayoutPrivate::oppositeEdge(Qt::AnchorPoint edge) | - | ||||||||||||||||||
634 | { | - | ||||||||||||||||||
635 | switch (edge) { | - | ||||||||||||||||||
636 | case Qt::AnchorLeft: never executed: case Qt::AnchorLeft: | 0 | ||||||||||||||||||
637 | edge = Qt::AnchorRight; | - | ||||||||||||||||||
638 | break; never executed: break; | 0 | ||||||||||||||||||
639 | case Qt::AnchorRight: never executed: case Qt::AnchorRight: | 0 | ||||||||||||||||||
640 | edge = Qt::AnchorLeft; | - | ||||||||||||||||||
641 | break; never executed: break; | 0 | ||||||||||||||||||
642 | case Qt::AnchorTop: never executed: case Qt::AnchorTop: | 0 | ||||||||||||||||||
643 | edge = Qt::AnchorBottom; | - | ||||||||||||||||||
644 | break; never executed: break; | 0 | ||||||||||||||||||
645 | case Qt::AnchorBottom: never executed: case Qt::AnchorBottom: | 0 | ||||||||||||||||||
646 | edge = Qt::AnchorTop; | - | ||||||||||||||||||
647 | break; never executed: break; | 0 | ||||||||||||||||||
648 | default: never executed: default: | 0 | ||||||||||||||||||
649 | break; never executed: break; | 0 | ||||||||||||||||||
650 | } | - | ||||||||||||||||||
651 | return edge; never executed: return edge; | 0 | ||||||||||||||||||
652 | } | - | ||||||||||||||||||
653 | - | |||||||||||||||||||
654 | - | |||||||||||||||||||
655 | /*! | - | ||||||||||||||||||
656 | \internal | - | ||||||||||||||||||
657 | - | |||||||||||||||||||
658 | Adds \a newAnchor to the graph. | - | ||||||||||||||||||
659 | - | |||||||||||||||||||
660 | Returns the newAnchor itself if it could be added without further changes to the graph. If a | - | ||||||||||||||||||
661 | new parallel anchor had to be created, then returns the new parallel anchor. If a parallel anchor | - | ||||||||||||||||||
662 | had to be created and it results in an unfeasible setup, \a feasible is set to false, otherwise | - | ||||||||||||||||||
663 | true. | - | ||||||||||||||||||
664 | - | |||||||||||||||||||
665 | Note that in the case a new parallel anchor is created, it might also take over some constraints | - | ||||||||||||||||||
666 | from its children anchors. | - | ||||||||||||||||||
667 | */ | - | ||||||||||||||||||
668 | AnchorData *QGraphicsAnchorLayoutPrivate::addAnchorMaybeParallel(AnchorData *newAnchor, bool *feasible) | - | ||||||||||||||||||
669 | { | - | ||||||||||||||||||
670 | Orientation orientation = Orientation(newAnchor->orientation); | - | ||||||||||||||||||
671 | Graph<AnchorVertex, AnchorData> &g = graph[orientation]; | - | ||||||||||||||||||
672 | *feasible = true; | - | ||||||||||||||||||
673 | - | |||||||||||||||||||
674 | // If already exists one anchor where newAnchor is supposed to be, we create a parallel | - | ||||||||||||||||||
675 | // anchor. | - | ||||||||||||||||||
676 | if (AnchorData *oldAnchor = g.takeEdge(newAnchor->from, newAnchor->to)) {
| 0 | ||||||||||||||||||
677 | ParallelAnchorData *parallel = new ParallelAnchorData(oldAnchor, newAnchor); | - | ||||||||||||||||||
678 | - | |||||||||||||||||||
679 | // The parallel anchor will "replace" its children anchors in | - | ||||||||||||||||||
680 | // every center constraint that they appear. | - | ||||||||||||||||||
681 | - | |||||||||||||||||||
682 | // ### If the dependent (center) anchors had reference(s) to their constraints, we | - | ||||||||||||||||||
683 | // could avoid traversing all the itemCenterConstraints. | - | ||||||||||||||||||
684 | QList<QSimplexConstraint *> &constraints = itemCenterConstraints[orientation]; | - | ||||||||||||||||||
685 | - | |||||||||||||||||||
686 | AnchorData *children[2] = { oldAnchor, newAnchor }; | - | ||||||||||||||||||
687 | QList<QSimplexConstraint *> *childrenConstraints[2] = { ¶llel->m_firstConstraints, | - | ||||||||||||||||||
688 | ¶llel->m_secondConstraints }; | - | ||||||||||||||||||
689 | - | |||||||||||||||||||
690 | for (int i = 0; i < 2; ++i) {
| 0 | ||||||||||||||||||
691 | AnchorData *child = children[i]; | - | ||||||||||||||||||
692 | QList<QSimplexConstraint *> *childConstraints = childrenConstraints[i]; | - | ||||||||||||||||||
693 | - | |||||||||||||||||||
694 | // We need to fix the second child constraints if the parallel group will have the | - | ||||||||||||||||||
695 | // opposite direction of the second child anchor. For the point of view of external | - | ||||||||||||||||||
696 | // entities, this anchor was reversed. So if at some point we say that the parallel | - | ||||||||||||||||||
697 | // has a value of 20, this mean that the second child (when reversed) will be | - | ||||||||||||||||||
698 | // assigned -20. | - | ||||||||||||||||||
699 | const bool needsReverse = i == 1 && !parallel->secondForward();
| 0 | ||||||||||||||||||
700 | - | |||||||||||||||||||
701 | if (!child->isCenterAnchor)
| 0 | ||||||||||||||||||
702 | continue; never executed: continue; | 0 | ||||||||||||||||||
703 | - | |||||||||||||||||||
704 | parallel->isCenterAnchor = true; | - | ||||||||||||||||||
705 | - | |||||||||||||||||||
706 | for (int j = 0; j < constraints.count(); ++j) {
| 0 | ||||||||||||||||||
707 | QSimplexConstraint *c = constraints[j]; | - | ||||||||||||||||||
708 | if (c->variables.contains(child)) {
| 0 | ||||||||||||||||||
709 | childConstraints->append(c); | - | ||||||||||||||||||
710 | qreal v = c->variables.take(child); | - | ||||||||||||||||||
711 | if (needsReverse)
| 0 | ||||||||||||||||||
712 | v *= -1; never executed: v *= -1; | 0 | ||||||||||||||||||
713 | c->variables.insert(parallel, v); | - | ||||||||||||||||||
714 | } never executed: end of block | 0 | ||||||||||||||||||
715 | } never executed: end of block | 0 | ||||||||||||||||||
716 | } never executed: end of block | 0 | ||||||||||||||||||
717 | - | |||||||||||||||||||
718 | // At this point we can identify that the parallel anchor is not feasible, e.g. one | - | ||||||||||||||||||
719 | // anchor minimum size is bigger than the other anchor maximum size. | - | ||||||||||||||||||
720 | *feasible = parallel->calculateSizeHints(); | - | ||||||||||||||||||
721 | newAnchor = parallel; | - | ||||||||||||||||||
722 | } never executed: end of block | 0 | ||||||||||||||||||
723 | - | |||||||||||||||||||
724 | g.createEdge(newAnchor->from, newAnchor->to, newAnchor); | - | ||||||||||||||||||
725 | return newAnchor; never executed: return newAnchor; | 0 | ||||||||||||||||||
726 | } | - | ||||||||||||||||||
727 | - | |||||||||||||||||||
728 | /*! | - | ||||||||||||||||||
729 | \internal | - | ||||||||||||||||||
730 | - | |||||||||||||||||||
731 | Takes the sequence of vertices described by (\a before, \a vertices, \a after) and removes | - | ||||||||||||||||||
732 | all anchors connected to the vertices in \a vertices, returning one simplified anchor between | - | ||||||||||||||||||
733 | \a before and \a after. | - | ||||||||||||||||||
734 | - | |||||||||||||||||||
735 | Note that this function doesn't add the created anchor to the graph. This should be done by | - | ||||||||||||||||||
736 | the caller. | - | ||||||||||||||||||
737 | */ | - | ||||||||||||||||||
738 | static AnchorData *createSequence(Graph<AnchorVertex, AnchorData> *graph, | - | ||||||||||||||||||
739 | AnchorVertex *before, | - | ||||||||||||||||||
740 | const QVector<AnchorVertex*> &vertices, | - | ||||||||||||||||||
741 | AnchorVertex *after) | - | ||||||||||||||||||
742 | { | - | ||||||||||||||||||
743 | #if defined(QT_DEBUG) && 0 | - | ||||||||||||||||||
744 | QString strVertices; | - | ||||||||||||||||||
745 | for (int i = 0; i < vertices.count(); ++i) { | - | ||||||||||||||||||
746 | strVertices += QString::fromLatin1("%1 - ").arg(vertices.at(i)->toString()); | - | ||||||||||||||||||
747 | } | - | ||||||||||||||||||
748 | QString strPath = QString::fromLatin1("%1 - %2%3").arg(before->toString(), strVertices, after->toString()); | - | ||||||||||||||||||
749 | qDebug("simplifying [%s] to [%s - %s]", qPrintable(strPath), qPrintable(before->toString()), qPrintable(after->toString())); | - | ||||||||||||||||||
750 | #endif | - | ||||||||||||||||||
751 | - | |||||||||||||||||||
752 | AnchorVertex *prev = before; | - | ||||||||||||||||||
753 | QVector<AnchorData *> edges; | - | ||||||||||||||||||
754 | edges.reserve(vertices.count() + 1); | - | ||||||||||||||||||
755 | - | |||||||||||||||||||
756 | const int numVertices = vertices.count(); | - | ||||||||||||||||||
757 | edges.reserve(numVertices + 1); | - | ||||||||||||||||||
758 | // Take from the graph, the edges that will be simplificated | - | ||||||||||||||||||
759 | for (int i = 0; i < numVertices; ++i) {
| 0 | ||||||||||||||||||
760 | AnchorVertex *next = vertices.at(i); | - | ||||||||||||||||||
761 | AnchorData *ad = graph->takeEdge(prev, next); | - | ||||||||||||||||||
762 | Q_ASSERT(ad); | - | ||||||||||||||||||
763 | edges.append(ad); | - | ||||||||||||||||||
764 | prev = next; | - | ||||||||||||||||||
765 | } never executed: end of block | 0 | ||||||||||||||||||
766 | - | |||||||||||||||||||
767 | // Take the last edge (not covered in the loop above) | - | ||||||||||||||||||
768 | AnchorData *ad = graph->takeEdge(vertices.last(), after); | - | ||||||||||||||||||
769 | Q_ASSERT(ad); | - | ||||||||||||||||||
770 | edges.append(ad); | - | ||||||||||||||||||
771 | - | |||||||||||||||||||
772 | // Create sequence | - | ||||||||||||||||||
773 | SequentialAnchorData *sequence = new SequentialAnchorData(vertices, edges); | - | ||||||||||||||||||
774 | sequence->from = before; | - | ||||||||||||||||||
775 | sequence->to = after; | - | ||||||||||||||||||
776 | - | |||||||||||||||||||
777 | sequence->calculateSizeHints(); | - | ||||||||||||||||||
778 | - | |||||||||||||||||||
779 | return sequence; never executed: return sequence; | 0 | ||||||||||||||||||
780 | } | - | ||||||||||||||||||
781 | - | |||||||||||||||||||
782 | /*! | - | ||||||||||||||||||
783 | \internal | - | ||||||||||||||||||
784 | - | |||||||||||||||||||
785 | The purpose of this function is to simplify the graph. | - | ||||||||||||||||||
786 | Simplification serves two purposes: | - | ||||||||||||||||||
787 | 1. Reduce the number of edges in the graph, (thus the number of variables to the equation | - | ||||||||||||||||||
788 | solver is reduced, and the solver performs better). | - | ||||||||||||||||||
789 | 2. Be able to do distribution of sequences of edges more intelligently (esp. with sequential | - | ||||||||||||||||||
790 | anchors) | - | ||||||||||||||||||
791 | - | |||||||||||||||||||
792 | It is essential that it must be possible to restore simplified anchors back to their "original" | - | ||||||||||||||||||
793 | form. This is done by restoreSimplifiedAnchor(). | - | ||||||||||||||||||
794 | - | |||||||||||||||||||
795 | There are two types of simplification that can be done: | - | ||||||||||||||||||
796 | 1. Sequential simplification | - | ||||||||||||||||||
797 | Sequential simplification means that all sequences of anchors will be merged into one single | - | ||||||||||||||||||
798 | anchor. Only anhcors that points in the same direction will be merged. | - | ||||||||||||||||||
799 | 2. Parallel simplification | - | ||||||||||||||||||
800 | If a simplified sequential anchor is about to be inserted between two vertices in the graph | - | ||||||||||||||||||
801 | and there already exist an anchor between those two vertices, a parallel anchor will be | - | ||||||||||||||||||
802 | created that serves as a placeholder for the sequential anchor and the anchor that was | - | ||||||||||||||||||
803 | already between the two vertices. | - | ||||||||||||||||||
804 | - | |||||||||||||||||||
805 | The process of simplification can be described as: | - | ||||||||||||||||||
806 | - | |||||||||||||||||||
807 | 1. Simplify all sequences of anchors into one anchor. | - | ||||||||||||||||||
808 | If no further simplification was done, go to (3) | - | ||||||||||||||||||
809 | - If there already exist an anchor where the sequential anchor is supposed to be inserted, | - | ||||||||||||||||||
810 | take that anchor out of the graph | - | ||||||||||||||||||
811 | - Then create a parallel anchor that holds the sequential anchor and the anchor just taken | - | ||||||||||||||||||
812 | out of the graph. | - | ||||||||||||||||||
813 | 2. Go to (1) | - | ||||||||||||||||||
814 | 3. Done | - | ||||||||||||||||||
815 | - | |||||||||||||||||||
816 | When creating the parallel anchors, the algorithm might identify unfeasible situations. In this | - | ||||||||||||||||||
817 | case the simplification process stops and returns \c false. Otherwise returns \c true. | - | ||||||||||||||||||
818 | */ | - | ||||||||||||||||||
819 | bool QGraphicsAnchorLayoutPrivate::simplifyGraph(Orientation orientation) | - | ||||||||||||||||||
820 | { | - | ||||||||||||||||||
821 | if (items.isEmpty())
| 0 | ||||||||||||||||||
822 | return true; never executed: return true; | 0 | ||||||||||||||||||
823 | - | |||||||||||||||||||
824 | #if defined(QT_DEBUG) && 0 | - | ||||||||||||||||||
825 | qDebug("Simplifying Graph for %s", | - | ||||||||||||||||||
826 | orientation == Horizontal ? "Horizontal" : "Vertical"); | - | ||||||||||||||||||
827 | - | |||||||||||||||||||
828 | static int count = 0; | - | ||||||||||||||||||
829 | if (orientation == Horizontal) { | - | ||||||||||||||||||
830 | count++; | - | ||||||||||||||||||
831 | dumpGraph(QString::fromLatin1("%1-full").arg(count)); | - | ||||||||||||||||||
832 | } | - | ||||||||||||||||||
833 | #endif | - | ||||||||||||||||||
834 | - | |||||||||||||||||||
835 | // Vertex simplification | - | ||||||||||||||||||
836 | if (!simplifyVertices(orientation)) {
| 0 | ||||||||||||||||||
837 | restoreVertices(orientation); | - | ||||||||||||||||||
838 | return false; never executed: return false; | 0 | ||||||||||||||||||
839 | } | - | ||||||||||||||||||
840 | - | |||||||||||||||||||
841 | // Anchor simplification | - | ||||||||||||||||||
842 | bool dirty; | - | ||||||||||||||||||
843 | bool feasible = true; | - | ||||||||||||||||||
844 | do { | - | ||||||||||||||||||
845 | dirty = simplifyGraphIteration(orientation, &feasible); | - | ||||||||||||||||||
846 | } while (dirty && feasible); never executed: end of block
| 0 | ||||||||||||||||||
847 | - | |||||||||||||||||||
848 | // Note that if we are not feasible, we fallback and make sure that the graph is fully restored | - | ||||||||||||||||||
849 | if (!feasible) {
| 0 | ||||||||||||||||||
850 | restoreSimplifiedGraph(orientation); | - | ||||||||||||||||||
851 | restoreVertices(orientation); | - | ||||||||||||||||||
852 | return false; never executed: return false; | 0 | ||||||||||||||||||
853 | } | - | ||||||||||||||||||
854 | - | |||||||||||||||||||
855 | #if defined(QT_DEBUG) && 0 | - | ||||||||||||||||||
856 | dumpGraph(QString::fromLatin1("%1-simplified-%2").arg(count).arg( | - | ||||||||||||||||||
857 | QString::fromLatin1(orientation == Horizontal ? "Horizontal" : "Vertical"))); | - | ||||||||||||||||||
858 | #endif | - | ||||||||||||||||||
859 | - | |||||||||||||||||||
860 | return true; never executed: return true; | 0 | ||||||||||||||||||
861 | } | - | ||||||||||||||||||
862 | - | |||||||||||||||||||
863 | static AnchorVertex *replaceVertex_helper(AnchorData *data, AnchorVertex *oldV, AnchorVertex *newV) | - | ||||||||||||||||||
864 | { | - | ||||||||||||||||||
865 | AnchorVertex *other; | - | ||||||||||||||||||
866 | if (data->from == oldV) {
| 0 | ||||||||||||||||||
867 | data->from = newV; | - | ||||||||||||||||||
868 | other = data->to; | - | ||||||||||||||||||
869 | } else { never executed: end of block | 0 | ||||||||||||||||||
870 | data->to = newV; | - | ||||||||||||||||||
871 | other = data->from; | - | ||||||||||||||||||
872 | } never executed: end of block | 0 | ||||||||||||||||||
873 | return other; never executed: return other; | 0 | ||||||||||||||||||
874 | } | - | ||||||||||||||||||
875 | - | |||||||||||||||||||
876 | bool QGraphicsAnchorLayoutPrivate::replaceVertex(Orientation orientation, AnchorVertex *oldV, | - | ||||||||||||||||||
877 | AnchorVertex *newV, const QList<AnchorData *> &edges) | - | ||||||||||||||||||
878 | { | - | ||||||||||||||||||
879 | Graph<AnchorVertex, AnchorData> &g = graph[orientation]; | - | ||||||||||||||||||
880 | bool feasible = true; | - | ||||||||||||||||||
881 | - | |||||||||||||||||||
882 | for (int i = 0; i < edges.count(); ++i) {
| 0 | ||||||||||||||||||
883 | AnchorData *ad = edges[i]; | - | ||||||||||||||||||
884 | AnchorVertex *otherV = replaceVertex_helper(ad, oldV, newV); | - | ||||||||||||||||||
885 | - | |||||||||||||||||||
886 | #if defined(QT_DEBUG) | - | ||||||||||||||||||
887 | ad->name = QString::fromLatin1("%1 --to--> %2").arg(ad->from->toString()).arg(ad->to->toString()); | - | ||||||||||||||||||
888 | #endif | - | ||||||||||||||||||
889 | - | |||||||||||||||||||
890 | bool newFeasible; | - | ||||||||||||||||||
891 | AnchorData *newAnchor = addAnchorMaybeParallel(ad, &newFeasible); | - | ||||||||||||||||||
892 | feasible &= newFeasible; | - | ||||||||||||||||||
893 | - | |||||||||||||||||||
894 | if (newAnchor != ad) {
| 0 | ||||||||||||||||||
895 | // A parallel was created, we mark that in the list of anchors created by vertex | - | ||||||||||||||||||
896 | // simplification. This is needed because we want to restore them in a separate step | - | ||||||||||||||||||
897 | // from the restoration of anchor simplification. | - | ||||||||||||||||||
898 | anchorsFromSimplifiedVertices[orientation].append(newAnchor); | - | ||||||||||||||||||
899 | } never executed: end of block | 0 | ||||||||||||||||||
900 | - | |||||||||||||||||||
901 | g.takeEdge(oldV, otherV); | - | ||||||||||||||||||
902 | } never executed: end of block | 0 | ||||||||||||||||||
903 | - | |||||||||||||||||||
904 | return feasible; never executed: return feasible; | 0 | ||||||||||||||||||
905 | } | - | ||||||||||||||||||
906 | - | |||||||||||||||||||
907 | /*! | - | ||||||||||||||||||
908 | \internal | - | ||||||||||||||||||
909 | */ | - | ||||||||||||||||||
910 | bool QGraphicsAnchorLayoutPrivate::simplifyVertices(Orientation orientation) | - | ||||||||||||||||||
911 | { | - | ||||||||||||||||||
912 | Q_Q(QGraphicsAnchorLayout); | - | ||||||||||||||||||
913 | Graph<AnchorVertex, AnchorData> &g = graph[orientation]; | - | ||||||||||||||||||
914 | - | |||||||||||||||||||
915 | // We'll walk through vertices | - | ||||||||||||||||||
916 | QStack<AnchorVertex *> stack; | - | ||||||||||||||||||
917 | stack.push(layoutFirstVertex[orientation]); | - | ||||||||||||||||||
918 | QSet<AnchorVertex *> visited; | - | ||||||||||||||||||
919 | - | |||||||||||||||||||
920 | while (!stack.isEmpty()) {
| 0 | ||||||||||||||||||
921 | AnchorVertex *v = stack.pop(); | - | ||||||||||||||||||
922 | visited.insert(v); | - | ||||||||||||||||||
923 | - | |||||||||||||||||||
924 | // Each adjacent of 'v' is a possible vertex to be merged. So we traverse all of | - | ||||||||||||||||||
925 | // them. Since once a merge is made, we might add new adjacents, and we don't want to | - | ||||||||||||||||||
926 | // pass two times through one adjacent. The 'index' is used to track our position. | - | ||||||||||||||||||
927 | QList<AnchorVertex *> adjacents = g.adjacentVertices(v); | - | ||||||||||||||||||
928 | int index = 0; | - | ||||||||||||||||||
929 | - | |||||||||||||||||||
930 | while (index < adjacents.count()) {
| 0 | ||||||||||||||||||
931 | AnchorVertex *next = adjacents.at(index); | - | ||||||||||||||||||
932 | index++; | - | ||||||||||||||||||
933 | - | |||||||||||||||||||
934 | AnchorData *data = g.edgeData(v, next); | - | ||||||||||||||||||
935 | const bool bothLayoutVertices = v->m_item == q && next->m_item == q;
| 0 | ||||||||||||||||||
936 | const bool zeroSized = !data->minSize && !data->maxSize;
| 0 | ||||||||||||||||||
937 | - | |||||||||||||||||||
938 | if (!bothLayoutVertices && zeroSized) {
| 0 | ||||||||||||||||||
939 | - | |||||||||||||||||||
940 | // Create a new vertex pair, note that we keep a list of those vertices so we can | - | ||||||||||||||||||
941 | // easily process them when restoring the graph. | - | ||||||||||||||||||
942 | AnchorVertexPair *newV = new AnchorVertexPair(v, next, data); | - | ||||||||||||||||||
943 | simplifiedVertices[orientation].append(newV); | - | ||||||||||||||||||
944 | - | |||||||||||||||||||
945 | // Collect the anchors of both vertices, the new vertex pair will take their place | - | ||||||||||||||||||
946 | // in those anchors | - | ||||||||||||||||||
947 | const QList<AnchorVertex *> &vAdjacents = g.adjacentVertices(v); | - | ||||||||||||||||||
948 | const QList<AnchorVertex *> &nextAdjacents = g.adjacentVertices(next); | - | ||||||||||||||||||
949 | - | |||||||||||||||||||
950 | for (int i = 0; i < vAdjacents.count(); ++i) {
| 0 | ||||||||||||||||||
951 | AnchorVertex *adjacent = vAdjacents.at(i); | - | ||||||||||||||||||
952 | if (adjacent != next) {
| 0 | ||||||||||||||||||
953 | AnchorData *ad = g.edgeData(v, adjacent); | - | ||||||||||||||||||
954 | newV->m_firstAnchors.append(ad); | - | ||||||||||||||||||
955 | } never executed: end of block | 0 | ||||||||||||||||||
956 | } never executed: end of block | 0 | ||||||||||||||||||
957 | - | |||||||||||||||||||
958 | for (int i = 0; i < nextAdjacents.count(); ++i) {
| 0 | ||||||||||||||||||
959 | AnchorVertex *adjacent = nextAdjacents.at(i); | - | ||||||||||||||||||
960 | if (adjacent != v) {
| 0 | ||||||||||||||||||
961 | AnchorData *ad = g.edgeData(next, adjacent); | - | ||||||||||||||||||
962 | newV->m_secondAnchors.append(ad); | - | ||||||||||||||||||
963 | - | |||||||||||||||||||
964 | // We'll also add new vertices to the adjacent list of the new 'v', to be | - | ||||||||||||||||||
965 | // created as a vertex pair and replace the current one. | - | ||||||||||||||||||
966 | if (!adjacents.contains(adjacent))
| 0 | ||||||||||||||||||
967 | adjacents.append(adjacent); never executed: adjacents.append(adjacent); | 0 | ||||||||||||||||||
968 | } never executed: end of block | 0 | ||||||||||||||||||
969 | } never executed: end of block | 0 | ||||||||||||||||||
970 | - | |||||||||||||||||||
971 | // ### merge this loop into the ones that calculated m_firstAnchors/m_secondAnchors? | - | ||||||||||||||||||
972 | // Make newV take the place of v and next | - | ||||||||||||||||||
973 | bool feasible = replaceVertex(orientation, v, newV, newV->m_firstAnchors); | - | ||||||||||||||||||
974 | feasible &= replaceVertex(orientation, next, newV, newV->m_secondAnchors); | - | ||||||||||||||||||
975 | - | |||||||||||||||||||
976 | // Update the layout vertex information if one of the vertices is a layout vertex. | - | ||||||||||||||||||
977 | AnchorVertex *layoutVertex = 0; | - | ||||||||||||||||||
978 | if (v->m_item == q)
| 0 | ||||||||||||||||||
979 | layoutVertex = v; never executed: layoutVertex = v; | 0 | ||||||||||||||||||
980 | else if (next->m_item == q)
| 0 | ||||||||||||||||||
981 | layoutVertex = next; never executed: layoutVertex = next; | 0 | ||||||||||||||||||
982 | - | |||||||||||||||||||
983 | if (layoutVertex) {
| 0 | ||||||||||||||||||
984 | // Layout vertices always have m_item == q... | - | ||||||||||||||||||
985 | newV->m_item = q; | - | ||||||||||||||||||
986 | changeLayoutVertex(orientation, layoutVertex, newV); | - | ||||||||||||||||||
987 | } never executed: end of block | 0 | ||||||||||||||||||
988 | - | |||||||||||||||||||
989 | g.takeEdge(v, next); | - | ||||||||||||||||||
990 | - | |||||||||||||||||||
991 | // If a non-feasibility is found, we leave early and cancel the simplification | - | ||||||||||||||||||
992 | if (!feasible)
| 0 | ||||||||||||||||||
993 | return false; never executed: return false; | 0 | ||||||||||||||||||
994 | - | |||||||||||||||||||
995 | v = newV; | - | ||||||||||||||||||
996 | visited.insert(newV); | - | ||||||||||||||||||
997 | - | |||||||||||||||||||
998 | } else if (!visited.contains(next) && !stack.contains(next)) { never executed: end of block
| 0 | ||||||||||||||||||
999 | // If the adjacent is not fit for merge and it wasn't visited by the outermost | - | ||||||||||||||||||
1000 | // loop, we add it to the stack. | - | ||||||||||||||||||
1001 | stack.push(next); | - | ||||||||||||||||||
1002 | } never executed: end of block | 0 | ||||||||||||||||||
1003 | } never executed: end of block | 0 | ||||||||||||||||||
1004 | } never executed: end of block | 0 | ||||||||||||||||||
1005 | - | |||||||||||||||||||
1006 | return true; never executed: return true; | 0 | ||||||||||||||||||
1007 | } | - | ||||||||||||||||||
1008 | - | |||||||||||||||||||
1009 | /*! | - | ||||||||||||||||||
1010 | \internal | - | ||||||||||||||||||
1011 | - | |||||||||||||||||||
1012 | One iteration of the simplification algorithm. Returns \c true if another iteration is needed. | - | ||||||||||||||||||
1013 | - | |||||||||||||||||||
1014 | The algorithm walks the graph in depth-first order, and only collects vertices that has two | - | ||||||||||||||||||
1015 | edges connected to it. If the vertex does not have two edges or if it is a layout edge, it | - | ||||||||||||||||||
1016 | will take all the previously collected vertices and try to create a simplified sequential | - | ||||||||||||||||||
1017 | anchor representing all the previously collected vertices. Once the simplified anchor is | - | ||||||||||||||||||
1018 | inserted, the collected list is cleared in order to find the next sequence to simplify. | - | ||||||||||||||||||
1019 | - | |||||||||||||||||||
1020 | Note that there are some catches to this that are not covered by the above explanation, see | - | ||||||||||||||||||
1021 | the function comments for more details. | - | ||||||||||||||||||
1022 | */ | - | ||||||||||||||||||
1023 | bool QGraphicsAnchorLayoutPrivate::simplifyGraphIteration(QGraphicsAnchorLayoutPrivate::Orientation orientation, | - | ||||||||||||||||||
1024 | bool *feasible) | - | ||||||||||||||||||
1025 | { | - | ||||||||||||||||||
1026 | Q_Q(QGraphicsAnchorLayout); | - | ||||||||||||||||||
1027 | Graph<AnchorVertex, AnchorData> &g = graph[orientation]; | - | ||||||||||||||||||
1028 | - | |||||||||||||||||||
1029 | QSet<AnchorVertex *> visited; | - | ||||||||||||||||||
1030 | QStack<QPair<AnchorVertex *, AnchorVertex *> > stack; | - | ||||||||||||||||||
1031 | stack.push(qMakePair(static_cast<AnchorVertex *>(0), layoutFirstVertex[orientation])); | - | ||||||||||||||||||
1032 | QVector<AnchorVertex*> candidates; | - | ||||||||||||||||||
1033 | - | |||||||||||||||||||
1034 | // Walk depth-first, in the stack we store start of the candidate sequence (beforeSequence) | - | ||||||||||||||||||
1035 | // and the vertex to be visited. | - | ||||||||||||||||||
1036 | while (!stack.isEmpty()) {
| 0 | ||||||||||||||||||
1037 | QPair<AnchorVertex *, AnchorVertex *> pair = stack.pop(); | - | ||||||||||||||||||
1038 | AnchorVertex *beforeSequence = pair.first; | - | ||||||||||||||||||
1039 | AnchorVertex *v = pair.second; | - | ||||||||||||||||||
1040 | - | |||||||||||||||||||
1041 | // The basic idea is to determine whether we found an end of sequence, | - | ||||||||||||||||||
1042 | // if that's the case, we stop adding vertices to the candidate list | - | ||||||||||||||||||
1043 | // and do a simplification step. | - | ||||||||||||||||||
1044 | // | - | ||||||||||||||||||
1045 | // A vertex can trigger an end of sequence if | - | ||||||||||||||||||
1046 | // (a) it is a layout vertex, we don't simplify away the layout vertices; | - | ||||||||||||||||||
1047 | // (b) it does not have exactly 2 adjacents; | - | ||||||||||||||||||
1048 | // (c) its next adjacent is already visited (a cycle in the graph). | - | ||||||||||||||||||
1049 | // (d) the next anchor is a center anchor. | - | ||||||||||||||||||
1050 | - | |||||||||||||||||||
1051 | const QList<AnchorVertex *> &adjacents = g.adjacentVertices(v); | - | ||||||||||||||||||
1052 | const bool isLayoutVertex = v->m_item == q; | - | ||||||||||||||||||
1053 | AnchorVertex *afterSequence = v; | - | ||||||||||||||||||
1054 | bool endOfSequence = false; | - | ||||||||||||||||||
1055 | - | |||||||||||||||||||
1056 | // | - | ||||||||||||||||||
1057 | // Identify the end cases. | - | ||||||||||||||||||
1058 | // | - | ||||||||||||||||||
1059 | - | |||||||||||||||||||
1060 | // Identifies cases (a) and (b) | - | ||||||||||||||||||
1061 | endOfSequence = isLayoutVertex || adjacents.count() != 2;
| 0 | ||||||||||||||||||
1062 | - | |||||||||||||||||||
1063 | if (!endOfSequence) {
| 0 | ||||||||||||||||||
1064 | // This is a tricky part. We peek at the next vertex to find out whether | - | ||||||||||||||||||
1065 | // | - | ||||||||||||||||||
1066 | // - we already visited the next vertex (c); | - | ||||||||||||||||||
1067 | // - the next anchor is a center (d). | - | ||||||||||||||||||
1068 | // | - | ||||||||||||||||||
1069 | // Those are needed to identify the remaining end of sequence cases. Note that unlike | - | ||||||||||||||||||
1070 | // (a) and (b), we preempt the end of sequence by looking into the next vertex. | - | ||||||||||||||||||
1071 | - | |||||||||||||||||||
1072 | // Peek at the next vertex | - | ||||||||||||||||||
1073 | AnchorVertex *after; | - | ||||||||||||||||||
1074 | if (candidates.isEmpty())
| 0 | ||||||||||||||||||
1075 | after = (beforeSequence == adjacents.last() ? adjacents.first() : adjacents.last()); never executed: after = (beforeSequence == adjacents.last() ? adjacents.first() : adjacents.last());
| 0 | ||||||||||||||||||
1076 | else | - | ||||||||||||||||||
1077 | after = (candidates.last() == adjacents.last() ? adjacents.first() : adjacents.last()); never executed: after = (candidates.last() == adjacents.last() ? adjacents.first() : adjacents.last());
| 0 | ||||||||||||||||||
1078 | - | |||||||||||||||||||
1079 | // ### At this point we assumed that candidates will not contain 'after', this may not hold | - | ||||||||||||||||||
1080 | // when simplifying FLOATing anchors. | - | ||||||||||||||||||
1081 | Q_ASSERT(!candidates.contains(after)); | - | ||||||||||||||||||
1082 | - | |||||||||||||||||||
1083 | const AnchorData *data = g.edgeData(v, after); | - | ||||||||||||||||||
1084 | Q_ASSERT(data); | - | ||||||||||||||||||
1085 | const bool cycleFound = visited.contains(after); | - | ||||||||||||||||||
1086 | - | |||||||||||||||||||
1087 | // Now cases (c) and (d)... | - | ||||||||||||||||||
1088 | endOfSequence = cycleFound || data->isCenterAnchor;
| 0 | ||||||||||||||||||
1089 | - | |||||||||||||||||||
1090 | if (!endOfSequence) {
| 0 | ||||||||||||||||||
1091 | // If it's not an end of sequence, then the vertex didn't trigger neither of the | - | ||||||||||||||||||
1092 | // previously three cases, so it can be added to the candidates list. | - | ||||||||||||||||||
1093 | candidates.append(v); | - | ||||||||||||||||||
1094 | } else if (cycleFound && (beforeSequence != after)) { never executed: end of block
| 0 | ||||||||||||||||||
1095 | afterSequence = after; | - | ||||||||||||||||||
1096 | candidates.append(v); | - | ||||||||||||||||||
1097 | } never executed: end of block | 0 | ||||||||||||||||||
1098 | } never executed: end of block | 0 | ||||||||||||||||||
1099 | - | |||||||||||||||||||
1100 | // | - | ||||||||||||||||||
1101 | // Add next non-visited vertices to the stack. | - | ||||||||||||||||||
1102 | // | - | ||||||||||||||||||
1103 | for (int i = 0; i < adjacents.count(); ++i) {
| 0 | ||||||||||||||||||
1104 | AnchorVertex *next = adjacents.at(i); | - | ||||||||||||||||||
1105 | if (visited.contains(next))
| 0 | ||||||||||||||||||
1106 | continue; never executed: continue; | 0 | ||||||||||||||||||
1107 | - | |||||||||||||||||||
1108 | // If current vertex is an end of sequence, and it'll reset the candidates list. So | - | ||||||||||||||||||
1109 | // the next vertices will build candidates lists with the current vertex as 'before' | - | ||||||||||||||||||
1110 | // vertex. If it's not an end of sequence, we keep the original 'before' vertex, | - | ||||||||||||||||||
1111 | // since we are keeping the candidates list. | - | ||||||||||||||||||
1112 | if (endOfSequence)
| 0 | ||||||||||||||||||
1113 | stack.push(qMakePair(v, next)); never executed: stack.push(qMakePair(v, next)); | 0 | ||||||||||||||||||
1114 | else | - | ||||||||||||||||||
1115 | stack.push(qMakePair(beforeSequence, next)); never executed: stack.push(qMakePair(beforeSequence, next)); | 0 | ||||||||||||||||||
1116 | } | - | ||||||||||||||||||
1117 | - | |||||||||||||||||||
1118 | visited.insert(v); | - | ||||||||||||||||||
1119 | - | |||||||||||||||||||
1120 | if (!endOfSequence || candidates.isEmpty())
| 0 | ||||||||||||||||||
1121 | continue; never executed: continue; | 0 | ||||||||||||||||||
1122 | - | |||||||||||||||||||
1123 | // | - | ||||||||||||||||||
1124 | // Create a sequence for (beforeSequence, candidates, afterSequence). | - | ||||||||||||||||||
1125 | // | - | ||||||||||||||||||
1126 | - | |||||||||||||||||||
1127 | // One restriction we have is to not simplify half of an anchor and let the other half | - | ||||||||||||||||||
1128 | // unsimplified. So we remove center edges before and after the sequence. | - | ||||||||||||||||||
1129 | const AnchorData *firstAnchor = g.edgeData(beforeSequence, candidates.first()); | - | ||||||||||||||||||
1130 | if (firstAnchor->isCenterAnchor) {
| 0 | ||||||||||||||||||
1131 | beforeSequence = candidates.first(); | - | ||||||||||||||||||
1132 | candidates.remove(0); | - | ||||||||||||||||||
1133 | - | |||||||||||||||||||
1134 | // If there's not candidates to be simplified, leave. | - | ||||||||||||||||||
1135 | if (candidates.isEmpty())
| 0 | ||||||||||||||||||
1136 | continue; never executed: continue; | 0 | ||||||||||||||||||
1137 | } never executed: end of block | 0 | ||||||||||||||||||
1138 | - | |||||||||||||||||||
1139 | const AnchorData *lastAnchor = g.edgeData(candidates.last(), afterSequence); | - | ||||||||||||||||||
1140 | if (lastAnchor->isCenterAnchor) {
| 0 | ||||||||||||||||||
1141 | afterSequence = candidates.last(); | - | ||||||||||||||||||
1142 | candidates.remove(candidates.count() - 1); | - | ||||||||||||||||||
1143 | - | |||||||||||||||||||
1144 | if (candidates.isEmpty())
| 0 | ||||||||||||||||||
1145 | continue; never executed: continue; | 0 | ||||||||||||||||||
1146 | } never executed: end of block | 0 | ||||||||||||||||||
1147 | - | |||||||||||||||||||
1148 | // | - | ||||||||||||||||||
1149 | // Add the sequence to the graph. | - | ||||||||||||||||||
1150 | // | - | ||||||||||||||||||
1151 | - | |||||||||||||||||||
1152 | AnchorData *sequence = createSequence(&g, beforeSequence, candidates, afterSequence); | - | ||||||||||||||||||
1153 | - | |||||||||||||||||||
1154 | // If 'beforeSequence' and 'afterSequence' already had an anchor between them, we'll | - | ||||||||||||||||||
1155 | // create a parallel anchor between the new sequence and the old anchor. | - | ||||||||||||||||||
1156 | bool newFeasible; | - | ||||||||||||||||||
1157 | AnchorData *newAnchor = addAnchorMaybeParallel(sequence, &newFeasible); | - | ||||||||||||||||||
1158 | - | |||||||||||||||||||
1159 | if (!newFeasible) {
| 0 | ||||||||||||||||||
1160 | *feasible = false; | - | ||||||||||||||||||
1161 | return false; never executed: return false; | 0 | ||||||||||||||||||
1162 | } | - | ||||||||||||||||||
1163 | - | |||||||||||||||||||
1164 | // When a new parallel anchor is create in the graph, we finish the iteration and return | - | ||||||||||||||||||
1165 | // true to indicate a new iteration is needed. This happens because a parallel anchor | - | ||||||||||||||||||
1166 | // changes the number of adjacents one vertex has, possibly opening up oportunities for | - | ||||||||||||||||||
1167 | // building candidate lists (when adjacents == 2). | - | ||||||||||||||||||
1168 | if (newAnchor != sequence)
| 0 | ||||||||||||||||||
1169 | return true; never executed: return true; | 0 | ||||||||||||||||||
1170 | - | |||||||||||||||||||
1171 | // If there was no parallel simplification, we'll keep walking the graph. So we clear the | - | ||||||||||||||||||
1172 | // candidates list to start again. | - | ||||||||||||||||||
1173 | candidates.clear(); | - | ||||||||||||||||||
1174 | } never executed: end of block | 0 | ||||||||||||||||||
1175 | - | |||||||||||||||||||
1176 | return false; never executed: return false; | 0 | ||||||||||||||||||
1177 | } | - | ||||||||||||||||||
1178 | - | |||||||||||||||||||
1179 | void QGraphicsAnchorLayoutPrivate::restoreSimplifiedAnchor(AnchorData *edge) | - | ||||||||||||||||||
1180 | { | - | ||||||||||||||||||
1181 | #if 0 | - | ||||||||||||||||||
1182 | static const char *anchortypes[] = {"Normal", | - | ||||||||||||||||||
1183 | "Sequential", | - | ||||||||||||||||||
1184 | "Parallel"}; | - | ||||||||||||||||||
1185 | qDebug("Restoring %s edge.", anchortypes[int(edge->type)]); | - | ||||||||||||||||||
1186 | #endif | - | ||||||||||||||||||
1187 | - | |||||||||||||||||||
1188 | Graph<AnchorVertex, AnchorData> &g = graph[edge->orientation]; | - | ||||||||||||||||||
1189 | - | |||||||||||||||||||
1190 | if (edge->type == AnchorData::Normal) {
| 0 | ||||||||||||||||||
1191 | g.createEdge(edge->from, edge->to, edge); | - | ||||||||||||||||||
1192 | - | |||||||||||||||||||
1193 | } else if (edge->type == AnchorData::Sequential) { never executed: end of block
| 0 | ||||||||||||||||||
1194 | SequentialAnchorData *sequence = static_cast<SequentialAnchorData *>(edge); | - | ||||||||||||||||||
1195 | - | |||||||||||||||||||
1196 | for (int i = 0; i < sequence->m_edges.count(); ++i) {
| 0 | ||||||||||||||||||
1197 | AnchorData *data = sequence->m_edges.at(i); | - | ||||||||||||||||||
1198 | restoreSimplifiedAnchor(data); | - | ||||||||||||||||||
1199 | } never executed: end of block | 0 | ||||||||||||||||||
1200 | - | |||||||||||||||||||
1201 | delete sequence; | - | ||||||||||||||||||
1202 | - | |||||||||||||||||||
1203 | } else if (edge->type == AnchorData::Parallel) { never executed: end of block
| 0 | ||||||||||||||||||
1204 | - | |||||||||||||||||||
1205 | // Skip parallel anchors that were created by vertex simplification, they will be processed | - | ||||||||||||||||||
1206 | // later, when restoring vertex simplification. | - | ||||||||||||||||||
1207 | // ### we could improve this check bit having a bit inside 'edge' | - | ||||||||||||||||||
1208 | if (anchorsFromSimplifiedVertices[edge->orientation].contains(edge))
| 0 | ||||||||||||||||||
1209 | return; never executed: return; | 0 | ||||||||||||||||||
1210 | - | |||||||||||||||||||
1211 | ParallelAnchorData* parallel = static_cast<ParallelAnchorData*>(edge); | - | ||||||||||||||||||
1212 | restoreSimplifiedConstraints(parallel); | - | ||||||||||||||||||
1213 | - | |||||||||||||||||||
1214 | // ### Because of the way parallel anchors are created in the anchor simplification | - | ||||||||||||||||||
1215 | // algorithm, we know that one of these will be a sequence, so it'll be safe if the other | - | ||||||||||||||||||
1216 | // anchor create an edge between the same vertices as the parallel. | - | ||||||||||||||||||
1217 | Q_ASSERT(parallel->firstEdge->type == AnchorData::Sequential | - | ||||||||||||||||||
1218 | || parallel->secondEdge->type == AnchorData::Sequential); | - | ||||||||||||||||||
1219 | restoreSimplifiedAnchor(parallel->firstEdge); | - | ||||||||||||||||||
1220 | restoreSimplifiedAnchor(parallel->secondEdge); | - | ||||||||||||||||||
1221 | - | |||||||||||||||||||
1222 | delete parallel; | - | ||||||||||||||||||
1223 | } never executed: end of block | 0 | ||||||||||||||||||
1224 | } never executed: end of block | 0 | ||||||||||||||||||
1225 | - | |||||||||||||||||||
1226 | void QGraphicsAnchorLayoutPrivate::restoreSimplifiedConstraints(ParallelAnchorData *parallel) | - | ||||||||||||||||||
1227 | { | - | ||||||||||||||||||
1228 | if (!parallel->isCenterAnchor)
| 0 | ||||||||||||||||||
1229 | return; never executed: return; | 0 | ||||||||||||||||||
1230 | - | |||||||||||||||||||
1231 | for (int i = 0; i < parallel->m_firstConstraints.count(); ++i) {
| 0 | ||||||||||||||||||
1232 | QSimplexConstraint *c = parallel->m_firstConstraints.at(i); | - | ||||||||||||||||||
1233 | qreal v = c->variables[parallel]; | - | ||||||||||||||||||
1234 | c->variables.remove(parallel); | - | ||||||||||||||||||
1235 | c->variables.insert(parallel->firstEdge, v); | - | ||||||||||||||||||
1236 | } never executed: end of block | 0 | ||||||||||||||||||
1237 | - | |||||||||||||||||||
1238 | // When restoring, we might have to revert constraints back. See comments on | - | ||||||||||||||||||
1239 | // addAnchorMaybeParallel(). | - | ||||||||||||||||||
1240 | const bool needsReverse = !parallel->secondForward(); | - | ||||||||||||||||||
1241 | - | |||||||||||||||||||
1242 | for (int i = 0; i < parallel->m_secondConstraints.count(); ++i) {
| 0 | ||||||||||||||||||
1243 | QSimplexConstraint *c = parallel->m_secondConstraints.at(i); | - | ||||||||||||||||||
1244 | qreal v = c->variables[parallel]; | - | ||||||||||||||||||
1245 | if (needsReverse)
| 0 | ||||||||||||||||||
1246 | v *= -1; never executed: v *= -1; | 0 | ||||||||||||||||||
1247 | c->variables.remove(parallel); | - | ||||||||||||||||||
1248 | c->variables.insert(parallel->secondEdge, v); | - | ||||||||||||||||||
1249 | } never executed: end of block | 0 | ||||||||||||||||||
1250 | } never executed: end of block | 0 | ||||||||||||||||||
1251 | - | |||||||||||||||||||
1252 | void QGraphicsAnchorLayoutPrivate::restoreSimplifiedGraph(Orientation orientation) | - | ||||||||||||||||||
1253 | { | - | ||||||||||||||||||
1254 | #if 0 | - | ||||||||||||||||||
1255 | qDebug("Restoring Simplified Graph for %s", | - | ||||||||||||||||||
1256 | orientation == Horizontal ? "Horizontal" : "Vertical"); | - | ||||||||||||||||||
1257 | #endif | - | ||||||||||||||||||
1258 | - | |||||||||||||||||||
1259 | // Restore anchor simplification | - | ||||||||||||||||||
1260 | Graph<AnchorVertex, AnchorData> &g = graph[orientation]; | - | ||||||||||||||||||
1261 | QList<QPair<AnchorVertex*, AnchorVertex*> > connections = g.connections(); | - | ||||||||||||||||||
1262 | for (int i = 0; i < connections.count(); ++i) {
| 0 | ||||||||||||||||||
1263 | AnchorVertex *v1 = connections.at(i).first; | - | ||||||||||||||||||
1264 | AnchorVertex *v2 = connections.at(i).second; | - | ||||||||||||||||||
1265 | AnchorData *edge = g.edgeData(v1, v2); | - | ||||||||||||||||||
1266 | - | |||||||||||||||||||
1267 | // We restore only sequential anchors and parallels that were not created by | - | ||||||||||||||||||
1268 | // vertex simplification. | - | ||||||||||||||||||
1269 | if (edge->type == AnchorData::Sequential
| 0 | ||||||||||||||||||
1270 | || (edge->type == AnchorData::Parallel &&
| 0 | ||||||||||||||||||
1271 | !anchorsFromSimplifiedVertices[orientation].contains(edge))) {
| 0 | ||||||||||||||||||
1272 | - | |||||||||||||||||||
1273 | g.takeEdge(v1, v2); | - | ||||||||||||||||||
1274 | restoreSimplifiedAnchor(edge); | - | ||||||||||||||||||
1275 | } never executed: end of block | 0 | ||||||||||||||||||
1276 | } never executed: end of block | 0 | ||||||||||||||||||
1277 | - | |||||||||||||||||||
1278 | restoreVertices(orientation); | - | ||||||||||||||||||
1279 | } never executed: end of block | 0 | ||||||||||||||||||
1280 | - | |||||||||||||||||||
1281 | void QGraphicsAnchorLayoutPrivate::restoreVertices(Orientation orientation) | - | ||||||||||||||||||
1282 | { | - | ||||||||||||||||||
1283 | Q_Q(QGraphicsAnchorLayout); | - | ||||||||||||||||||
1284 | - | |||||||||||||||||||
1285 | Graph<AnchorVertex, AnchorData> &g = graph[orientation]; | - | ||||||||||||||||||
1286 | QList<AnchorVertexPair *> &toRestore = simplifiedVertices[orientation]; | - | ||||||||||||||||||
1287 | - | |||||||||||||||||||
1288 | // Since we keep a list of parallel anchors and vertices that were created during vertex | - | ||||||||||||||||||
1289 | // simplification, we can now iterate on those lists instead of traversing the graph | - | ||||||||||||||||||
1290 | // recursively. | - | ||||||||||||||||||
1291 | - | |||||||||||||||||||
1292 | // First, restore the constraints changed when we created parallel anchors. Note that this | - | ||||||||||||||||||
1293 | // works at this point because the constraints doesn't depend on vertex information and at | - | ||||||||||||||||||
1294 | // this point it's always safe to identify whether the second child is forward or backwards. | - | ||||||||||||||||||
1295 | // In the next step, we'll change the anchors vertices so that would not be possible anymore. | - | ||||||||||||||||||
1296 | QList<AnchorData *> ¶llelAnchors = anchorsFromSimplifiedVertices[orientation]; | - | ||||||||||||||||||
1297 | - | |||||||||||||||||||
1298 | for (int i = parallelAnchors.count() - 1; i >= 0; --i) {
| 0 | ||||||||||||||||||
1299 | ParallelAnchorData *parallel = static_cast<ParallelAnchorData *>(parallelAnchors.at(i)); | - | ||||||||||||||||||
1300 | restoreSimplifiedConstraints(parallel); | - | ||||||||||||||||||
1301 | } never executed: end of block | 0 | ||||||||||||||||||
1302 | - | |||||||||||||||||||
1303 | // Then, we will restore the vertices in the inverse order of creation, this way we ensure that | - | ||||||||||||||||||
1304 | // the vertex being restored was not wrapped by another simplification. | - | ||||||||||||||||||
1305 | for (int i = toRestore.count() - 1; i >= 0; --i) {
| 0 | ||||||||||||||||||
1306 | AnchorVertexPair *pair = toRestore.at(i); | - | ||||||||||||||||||
1307 | QList<AnchorVertex *> adjacents = g.adjacentVertices(pair); | - | ||||||||||||||||||
1308 | - | |||||||||||||||||||
1309 | // Restore the removed edge, this will also restore both vertices 'first' and 'second' to | - | ||||||||||||||||||
1310 | // the graph structure. | - | ||||||||||||||||||
1311 | AnchorVertex *first = pair->m_first; | - | ||||||||||||||||||
1312 | AnchorVertex *second = pair->m_second; | - | ||||||||||||||||||
1313 | g.createEdge(first, second, pair->m_removedAnchor); | - | ||||||||||||||||||
1314 | - | |||||||||||||||||||
1315 | // Restore the anchors for the first child vertex | - | ||||||||||||||||||
1316 | for (int j = 0; j < pair->m_firstAnchors.count(); ++j) {
| 0 | ||||||||||||||||||
1317 | AnchorData *ad = pair->m_firstAnchors.at(j); | - | ||||||||||||||||||
1318 | Q_ASSERT(ad->from == pair || ad->to == pair); | - | ||||||||||||||||||
1319 | - | |||||||||||||||||||
1320 | replaceVertex_helper(ad, pair, first); | - | ||||||||||||||||||
1321 | g.createEdge(ad->from, ad->to, ad); | - | ||||||||||||||||||
1322 | } never executed: end of block | 0 | ||||||||||||||||||
1323 | - | |||||||||||||||||||
1324 | // Restore the anchors for the second child vertex | - | ||||||||||||||||||
1325 | for (int j = 0; j < pair->m_secondAnchors.count(); ++j) {
| 0 | ||||||||||||||||||
1326 | AnchorData *ad = pair->m_secondAnchors.at(j); | - | ||||||||||||||||||
1327 | Q_ASSERT(ad->from == pair || ad->to == pair); | - | ||||||||||||||||||
1328 | - | |||||||||||||||||||
1329 | replaceVertex_helper(ad, pair, second); | - | ||||||||||||||||||
1330 | g.createEdge(ad->from, ad->to, ad); | - | ||||||||||||||||||
1331 | } never executed: end of block | 0 | ||||||||||||||||||
1332 | - | |||||||||||||||||||
1333 | for (int j = 0; j < adjacents.count(); ++j) {
| 0 | ||||||||||||||||||
1334 | g.takeEdge(pair, adjacents.at(j)); | - | ||||||||||||||||||
1335 | } never executed: end of block | 0 | ||||||||||||||||||
1336 | - | |||||||||||||||||||
1337 | // The pair simplified a layout vertex, so place back the correct vertex in the variable | - | ||||||||||||||||||
1338 | // that track layout vertices | - | ||||||||||||||||||
1339 | if (pair->m_item == q) {
| 0 | ||||||||||||||||||
1340 | AnchorVertex *layoutVertex = first->m_item == q ? first : second;
| 0 | ||||||||||||||||||
1341 | Q_ASSERT(layoutVertex->m_item == q); | - | ||||||||||||||||||
1342 | changeLayoutVertex(orientation, pair, layoutVertex); | - | ||||||||||||||||||
1343 | } never executed: end of block | 0 | ||||||||||||||||||
1344 | - | |||||||||||||||||||
1345 | delete pair; | - | ||||||||||||||||||
1346 | } never executed: end of block | 0 | ||||||||||||||||||
1347 | qDeleteAll(parallelAnchors); | - | ||||||||||||||||||
1348 | parallelAnchors.clear(); | - | ||||||||||||||||||
1349 | toRestore.clear(); | - | ||||||||||||||||||
1350 | } never executed: end of block | 0 | ||||||||||||||||||
1351 | - | |||||||||||||||||||
1352 | QGraphicsAnchorLayoutPrivate::Orientation | - | ||||||||||||||||||
1353 | QGraphicsAnchorLayoutPrivate::edgeOrientation(Qt::AnchorPoint edge) | - | ||||||||||||||||||
1354 | { | - | ||||||||||||||||||
1355 | return edge > Qt::AnchorRight ? Vertical : Horizontal; never executed: return edge > Qt::AnchorRight ? Vertical : Horizontal;
| 0 | ||||||||||||||||||
1356 | } | - | ||||||||||||||||||
1357 | - | |||||||||||||||||||
1358 | /*! | - | ||||||||||||||||||
1359 | \internal | - | ||||||||||||||||||
1360 | - | |||||||||||||||||||
1361 | Create internal anchors to connect the layout edges (Left to Right and | - | ||||||||||||||||||
1362 | Top to Bottom). | - | ||||||||||||||||||
1363 | - | |||||||||||||||||||
1364 | These anchors doesn't have size restrictions, that will be enforced by | - | ||||||||||||||||||
1365 | other anchors and items in the layout. | - | ||||||||||||||||||
1366 | */ | - | ||||||||||||||||||
1367 | void QGraphicsAnchorLayoutPrivate::createLayoutEdges() | - | ||||||||||||||||||
1368 | { | - | ||||||||||||||||||
1369 | Q_Q(QGraphicsAnchorLayout); | - | ||||||||||||||||||
1370 | QGraphicsLayoutItem *layout = q; | - | ||||||||||||||||||
1371 | - | |||||||||||||||||||
1372 | // Horizontal | - | ||||||||||||||||||
1373 | AnchorData *data = new AnchorData; | - | ||||||||||||||||||
1374 | addAnchor_helper(layout, Qt::AnchorLeft, layout, | - | ||||||||||||||||||
1375 | Qt::AnchorRight, data); | - | ||||||||||||||||||
1376 | data->maxSize = QWIDGETSIZE_MAX; | - | ||||||||||||||||||
1377 | - | |||||||||||||||||||
1378 | // Save a reference to layout vertices | - | ||||||||||||||||||
1379 | layoutFirstVertex[Horizontal] = internalVertex(layout, Qt::AnchorLeft); | - | ||||||||||||||||||
1380 | layoutCentralVertex[Horizontal] = 0; | - | ||||||||||||||||||
1381 | layoutLastVertex[Horizontal] = internalVertex(layout, Qt::AnchorRight); | - | ||||||||||||||||||
1382 | - | |||||||||||||||||||
1383 | // Vertical | - | ||||||||||||||||||
1384 | data = new AnchorData; | - | ||||||||||||||||||
1385 | addAnchor_helper(layout, Qt::AnchorTop, layout, | - | ||||||||||||||||||
1386 | Qt::AnchorBottom, data); | - | ||||||||||||||||||
1387 | data->maxSize = QWIDGETSIZE_MAX; | - | ||||||||||||||||||
1388 | - | |||||||||||||||||||
1389 | // Save a reference to layout vertices | - | ||||||||||||||||||
1390 | layoutFirstVertex[Vertical] = internalVertex(layout, Qt::AnchorTop); | - | ||||||||||||||||||
1391 | layoutCentralVertex[Vertical] = 0; | - | ||||||||||||||||||
1392 | layoutLastVertex[Vertical] = internalVertex(layout, Qt::AnchorBottom); | - | ||||||||||||||||||
1393 | } never executed: end of block | 0 | ||||||||||||||||||
1394 | - | |||||||||||||||||||
1395 | void QGraphicsAnchorLayoutPrivate::deleteLayoutEdges() | - | ||||||||||||||||||
1396 | { | - | ||||||||||||||||||
1397 | Q_Q(QGraphicsAnchorLayout); | - | ||||||||||||||||||
1398 | - | |||||||||||||||||||
1399 | Q_ASSERT(!internalVertex(q, Qt::AnchorHorizontalCenter)); | - | ||||||||||||||||||
1400 | Q_ASSERT(!internalVertex(q, Qt::AnchorVerticalCenter)); | - | ||||||||||||||||||
1401 | - | |||||||||||||||||||
1402 | removeAnchor_helper(internalVertex(q, Qt::AnchorLeft), | - | ||||||||||||||||||
1403 | internalVertex(q, Qt::AnchorRight)); | - | ||||||||||||||||||
1404 | removeAnchor_helper(internalVertex(q, Qt::AnchorTop), | - | ||||||||||||||||||
1405 | internalVertex(q, Qt::AnchorBottom)); | - | ||||||||||||||||||
1406 | } never executed: end of block | 0 | ||||||||||||||||||
1407 | - | |||||||||||||||||||
1408 | void QGraphicsAnchorLayoutPrivate::createItemEdges(QGraphicsLayoutItem *item) | - | ||||||||||||||||||
1409 | { | - | ||||||||||||||||||
1410 | items.append(item); | - | ||||||||||||||||||
1411 | - | |||||||||||||||||||
1412 | // Create horizontal and vertical internal anchors for the item and | - | ||||||||||||||||||
1413 | // refresh its size hint / policy values. | - | ||||||||||||||||||
1414 | AnchorData *data = new AnchorData; | - | ||||||||||||||||||
1415 | addAnchor_helper(item, Qt::AnchorLeft, item, Qt::AnchorRight, data); | - | ||||||||||||||||||
1416 | data->refreshSizeHints(); | - | ||||||||||||||||||
1417 | - | |||||||||||||||||||
1418 | data = new AnchorData; | - | ||||||||||||||||||
1419 | addAnchor_helper(item, Qt::AnchorTop, item, Qt::AnchorBottom, data); | - | ||||||||||||||||||
1420 | data->refreshSizeHints(); | - | ||||||||||||||||||
1421 | } never executed: end of block | 0 | ||||||||||||||||||
1422 | - | |||||||||||||||||||
1423 | /*! | - | ||||||||||||||||||
1424 | \internal | - | ||||||||||||||||||
1425 | - | |||||||||||||||||||
1426 | By default, each item in the layout is represented internally as | - | ||||||||||||||||||
1427 | a single anchor in each direction. For instance, from Left to Right. | - | ||||||||||||||||||
1428 | - | |||||||||||||||||||
1429 | However, to support anchorage of items to the center of items, we | - | ||||||||||||||||||
1430 | must split this internal anchor into two half-anchors. From Left | - | ||||||||||||||||||
1431 | to Center and then from Center to Right, with the restriction that | - | ||||||||||||||||||
1432 | these anchors must have the same time at all times. | - | ||||||||||||||||||
1433 | */ | - | ||||||||||||||||||
1434 | void QGraphicsAnchorLayoutPrivate::createCenterAnchors( | - | ||||||||||||||||||
1435 | QGraphicsLayoutItem *item, Qt::AnchorPoint centerEdge) | - | ||||||||||||||||||
1436 | { | - | ||||||||||||||||||
1437 | Q_Q(QGraphicsAnchorLayout); | - | ||||||||||||||||||
1438 | - | |||||||||||||||||||
1439 | Orientation orientation; | - | ||||||||||||||||||
1440 | switch (centerEdge) { | - | ||||||||||||||||||
1441 | case Qt::AnchorHorizontalCenter: never executed: case Qt::AnchorHorizontalCenter: | 0 | ||||||||||||||||||
1442 | orientation = Horizontal; | - | ||||||||||||||||||
1443 | break; never executed: break; | 0 | ||||||||||||||||||
1444 | case Qt::AnchorVerticalCenter: never executed: case Qt::AnchorVerticalCenter: | 0 | ||||||||||||||||||
1445 | orientation = Vertical; | - | ||||||||||||||||||
1446 | break; never executed: break; | 0 | ||||||||||||||||||
1447 | default: never executed: default: | 0 | ||||||||||||||||||
1448 | // Don't create center edges unless needed | - | ||||||||||||||||||
1449 | return; never executed: return; | 0 | ||||||||||||||||||
1450 | } | - | ||||||||||||||||||
1451 | - | |||||||||||||||||||
1452 | // Check if vertex already exists | - | ||||||||||||||||||
1453 | if (internalVertex(item, centerEdge))
| 0 | ||||||||||||||||||
1454 | return; never executed: return; | 0 | ||||||||||||||||||
1455 | - | |||||||||||||||||||
1456 | // Orientation code | - | ||||||||||||||||||
1457 | Qt::AnchorPoint firstEdge; | - | ||||||||||||||||||
1458 | Qt::AnchorPoint lastEdge; | - | ||||||||||||||||||
1459 | - | |||||||||||||||||||
1460 | if (orientation == Horizontal) {
| 0 | ||||||||||||||||||
1461 | firstEdge = Qt::AnchorLeft; | - | ||||||||||||||||||
1462 | lastEdge = Qt::AnchorRight; | - | ||||||||||||||||||
1463 | } else { never executed: end of block | 0 | ||||||||||||||||||
1464 | firstEdge = Qt::AnchorTop; | - | ||||||||||||||||||
1465 | lastEdge = Qt::AnchorBottom; | - | ||||||||||||||||||
1466 | } never executed: end of block | 0 | ||||||||||||||||||
1467 | - | |||||||||||||||||||
1468 | AnchorVertex *first = internalVertex(item, firstEdge); | - | ||||||||||||||||||
1469 | AnchorVertex *last = internalVertex(item, lastEdge); | - | ||||||||||||||||||
1470 | Q_ASSERT(first && last); | - | ||||||||||||||||||
1471 | - | |||||||||||||||||||
1472 | // Create new anchors | - | ||||||||||||||||||
1473 | QSimplexConstraint *c = new QSimplexConstraint; | - | ||||||||||||||||||
1474 | - | |||||||||||||||||||
1475 | AnchorData *data = new AnchorData; | - | ||||||||||||||||||
1476 | c->variables.insert(data, 1.0); | - | ||||||||||||||||||
1477 | addAnchor_helper(item, firstEdge, item, centerEdge, data); | - | ||||||||||||||||||
1478 | data->isCenterAnchor = true; | - | ||||||||||||||||||
1479 | data->dependency = AnchorData::Master; | - | ||||||||||||||||||
1480 | data->refreshSizeHints(); | - | ||||||||||||||||||
1481 | - | |||||||||||||||||||
1482 | data = new AnchorData; | - | ||||||||||||||||||
1483 | c->variables.insert(data, -1.0); | - | ||||||||||||||||||
1484 | addAnchor_helper(item, centerEdge, item, lastEdge, data); | - | ||||||||||||||||||
1485 | data->isCenterAnchor = true; | - | ||||||||||||||||||
1486 | data->dependency = AnchorData::Slave; | - | ||||||||||||||||||
1487 | data->refreshSizeHints(); | - | ||||||||||||||||||
1488 | - | |||||||||||||||||||
1489 | itemCenterConstraints[orientation].append(c); | - | ||||||||||||||||||
1490 | - | |||||||||||||||||||
1491 | // Remove old one | - | ||||||||||||||||||
1492 | removeAnchor_helper(first, last); | - | ||||||||||||||||||
1493 | - | |||||||||||||||||||
1494 | if (item == q) {
| 0 | ||||||||||||||||||
1495 | layoutCentralVertex[orientation] = internalVertex(q, centerEdge); | - | ||||||||||||||||||
1496 | } never executed: end of block | 0 | ||||||||||||||||||
1497 | } never executed: end of block | 0 | ||||||||||||||||||
1498 | - | |||||||||||||||||||
1499 | void QGraphicsAnchorLayoutPrivate::removeCenterAnchors( | - | ||||||||||||||||||
1500 | QGraphicsLayoutItem *item, Qt::AnchorPoint centerEdge, | - | ||||||||||||||||||
1501 | bool substitute) | - | ||||||||||||||||||
1502 | { | - | ||||||||||||||||||
1503 | Q_Q(QGraphicsAnchorLayout); | - | ||||||||||||||||||
1504 | - | |||||||||||||||||||
1505 | Orientation orientation; | - | ||||||||||||||||||
1506 | switch (centerEdge) { | - | ||||||||||||||||||
1507 | case Qt::AnchorHorizontalCenter: never executed: case Qt::AnchorHorizontalCenter: | 0 | ||||||||||||||||||
1508 | orientation = Horizontal; | - | ||||||||||||||||||
1509 | break; never executed: break; | 0 | ||||||||||||||||||
1510 | case Qt::AnchorVerticalCenter: never executed: case Qt::AnchorVerticalCenter: | 0 | ||||||||||||||||||
1511 | orientation = Vertical; | - | ||||||||||||||||||
1512 | break; never executed: break; | 0 | ||||||||||||||||||
1513 | default: never executed: default: | 0 | ||||||||||||||||||
1514 | // Don't remove edges that not the center ones | - | ||||||||||||||||||
1515 | return; never executed: return; | 0 | ||||||||||||||||||
1516 | } | - | ||||||||||||||||||
1517 | - | |||||||||||||||||||
1518 | // Orientation code | - | ||||||||||||||||||
1519 | Qt::AnchorPoint firstEdge; | - | ||||||||||||||||||
1520 | Qt::AnchorPoint lastEdge; | - | ||||||||||||||||||
1521 | - | |||||||||||||||||||
1522 | if (orientation == Horizontal) {
| 0 | ||||||||||||||||||
1523 | firstEdge = Qt::AnchorLeft; | - | ||||||||||||||||||
1524 | lastEdge = Qt::AnchorRight; | - | ||||||||||||||||||
1525 | } else { never executed: end of block | 0 | ||||||||||||||||||
1526 | firstEdge = Qt::AnchorTop; | - | ||||||||||||||||||
1527 | lastEdge = Qt::AnchorBottom; | - | ||||||||||||||||||
1528 | } never executed: end of block | 0 | ||||||||||||||||||
1529 | - | |||||||||||||||||||
1530 | AnchorVertex *center = internalVertex(item, centerEdge); | - | ||||||||||||||||||
1531 | if (!center)
| 0 | ||||||||||||||||||
1532 | return; never executed: return; | 0 | ||||||||||||||||||
1533 | AnchorVertex *first = internalVertex(item, firstEdge); | - | ||||||||||||||||||
1534 | - | |||||||||||||||||||
1535 | Q_ASSERT(first); | - | ||||||||||||||||||
1536 | Q_ASSERT(center); | - | ||||||||||||||||||
1537 | - | |||||||||||||||||||
1538 | Graph<AnchorVertex, AnchorData> &g = graph[orientation]; | - | ||||||||||||||||||
1539 | - | |||||||||||||||||||
1540 | - | |||||||||||||||||||
1541 | AnchorData *oldData = g.edgeData(first, center); | - | ||||||||||||||||||
1542 | // Remove center constraint | - | ||||||||||||||||||
1543 | for (int i = itemCenterConstraints[orientation].count() - 1; i >= 0; --i) {
| 0 | ||||||||||||||||||
1544 | if (itemCenterConstraints[orientation].at(i)->variables.contains(oldData)) {
| 0 | ||||||||||||||||||
1545 | delete itemCenterConstraints[orientation].takeAt(i); | - | ||||||||||||||||||
1546 | break; never executed: break; | 0 | ||||||||||||||||||
1547 | } | - | ||||||||||||||||||
1548 | } never executed: end of block | 0 | ||||||||||||||||||
1549 | - | |||||||||||||||||||
1550 | if (substitute) {
| 0 | ||||||||||||||||||
1551 | // Create the new anchor that should substitute the left-center-right anchors. | - | ||||||||||||||||||
1552 | AnchorData *data = new AnchorData; | - | ||||||||||||||||||
1553 | addAnchor_helper(item, firstEdge, item, lastEdge, data); | - | ||||||||||||||||||
1554 | data->refreshSizeHints(); | - | ||||||||||||||||||
1555 | - | |||||||||||||||||||
1556 | // Remove old anchors | - | ||||||||||||||||||
1557 | removeAnchor_helper(first, center); | - | ||||||||||||||||||
1558 | removeAnchor_helper(center, internalVertex(item, lastEdge)); | - | ||||||||||||||||||
1559 | - | |||||||||||||||||||
1560 | } else { never executed: end of block | 0 | ||||||||||||||||||
1561 | // this is only called from removeAnchors() | - | ||||||||||||||||||
1562 | // first, remove all non-internal anchors | - | ||||||||||||||||||
1563 | QList<AnchorVertex*> adjacents = g.adjacentVertices(center); | - | ||||||||||||||||||
1564 | for (int i = 0; i < adjacents.count(); ++i) {
| 0 | ||||||||||||||||||
1565 | AnchorVertex *v = adjacents.at(i); | - | ||||||||||||||||||
1566 | if (v->m_item != item) {
| 0 | ||||||||||||||||||
1567 | removeAnchor_helper(center, internalVertex(v->m_item, v->m_edge)); | - | ||||||||||||||||||
1568 | } never executed: end of block | 0 | ||||||||||||||||||
1569 | } never executed: end of block | 0 | ||||||||||||||||||
1570 | // when all non-internal anchors is removed it will automatically merge the | - | ||||||||||||||||||
1571 | // center anchor into a left-right (or top-bottom) anchor. We must also delete that. | - | ||||||||||||||||||
1572 | // by this time, the center vertex is deleted and merged into a non-centered internal anchor | - | ||||||||||||||||||
1573 | removeAnchor_helper(first, internalVertex(item, lastEdge)); | - | ||||||||||||||||||
1574 | } never executed: end of block | 0 | ||||||||||||||||||
1575 | - | |||||||||||||||||||
1576 | if (item == q) {
| 0 | ||||||||||||||||||
1577 | layoutCentralVertex[orientation] = 0; | - | ||||||||||||||||||
1578 | } never executed: end of block | 0 | ||||||||||||||||||
1579 | } never executed: end of block | 0 | ||||||||||||||||||
1580 | - | |||||||||||||||||||
1581 | - | |||||||||||||||||||
1582 | void QGraphicsAnchorLayoutPrivate::removeCenterConstraints(QGraphicsLayoutItem *item, | - | ||||||||||||||||||
1583 | Orientation orientation) | - | ||||||||||||||||||
1584 | { | - | ||||||||||||||||||
1585 | // Remove the item center constraints associated to this item | - | ||||||||||||||||||
1586 | // ### This is a temporary solution. We should probably use a better | - | ||||||||||||||||||
1587 | // data structure to hold items and/or their associated constraints | - | ||||||||||||||||||
1588 | // so that we can remove those easily | - | ||||||||||||||||||
1589 | - | |||||||||||||||||||
1590 | AnchorVertex *first = internalVertex(item, orientation == Horizontal ? | - | ||||||||||||||||||
1591 | Qt::AnchorLeft : | - | ||||||||||||||||||
1592 | Qt::AnchorTop); | - | ||||||||||||||||||
1593 | AnchorVertex *center = internalVertex(item, orientation == Horizontal ? | - | ||||||||||||||||||
1594 | Qt::AnchorHorizontalCenter : | - | ||||||||||||||||||
1595 | Qt::AnchorVerticalCenter); | - | ||||||||||||||||||
1596 | - | |||||||||||||||||||
1597 | // Skip if no center constraints exist | - | ||||||||||||||||||
1598 | if (!center)
| 0 | ||||||||||||||||||
1599 | return; never executed: return; | 0 | ||||||||||||||||||
1600 | - | |||||||||||||||||||
1601 | Q_ASSERT(first); | - | ||||||||||||||||||
1602 | AnchorData *internalAnchor = graph[orientation].edgeData(first, center); | - | ||||||||||||||||||
1603 | - | |||||||||||||||||||
1604 | // Look for our anchor in all item center constraints, then remove it | - | ||||||||||||||||||
1605 | for (int i = 0; i < itemCenterConstraints[orientation].size(); ++i) {
| 0 | ||||||||||||||||||
1606 | if (itemCenterConstraints[orientation].at(i)->variables.contains(internalAnchor)) {
| 0 | ||||||||||||||||||
1607 | delete itemCenterConstraints[orientation].takeAt(i); | - | ||||||||||||||||||
1608 | break; never executed: break; | 0 | ||||||||||||||||||
1609 | } | - | ||||||||||||||||||
1610 | } never executed: end of block | 0 | ||||||||||||||||||
1611 | } never executed: end of block | 0 | ||||||||||||||||||
1612 | - | |||||||||||||||||||
1613 | /*! | - | ||||||||||||||||||
1614 | * \internal | - | ||||||||||||||||||
1615 | * Implements the high level "addAnchor" feature. Called by the public API | - | ||||||||||||||||||
1616 | * addAnchor method. | - | ||||||||||||||||||
1617 | * | - | ||||||||||||||||||
1618 | * The optional \a spacing argument defines the size of the anchor. If not provided, | - | ||||||||||||||||||
1619 | * the anchor size is either 0 or not-set, depending on type of anchor created (see | - | ||||||||||||||||||
1620 | * matrix below). | - | ||||||||||||||||||
1621 | * | - | ||||||||||||||||||
1622 | * All anchors that remain with size not-set will assume the standard spacing, | - | ||||||||||||||||||
1623 | * set either by the layout style or through the "setSpacing" layout API. | - | ||||||||||||||||||
1624 | */ | - | ||||||||||||||||||
1625 | QGraphicsAnchor *QGraphicsAnchorLayoutPrivate::addAnchor(QGraphicsLayoutItem *firstItem, | - | ||||||||||||||||||
1626 | Qt::AnchorPoint firstEdge, | - | ||||||||||||||||||
1627 | QGraphicsLayoutItem *secondItem, | - | ||||||||||||||||||
1628 | Qt::AnchorPoint secondEdge, | - | ||||||||||||||||||
1629 | qreal *spacing) | - | ||||||||||||||||||
1630 | { | - | ||||||||||||||||||
1631 | Q_Q(QGraphicsAnchorLayout); | - | ||||||||||||||||||
1632 | if ((firstItem == 0) || (secondItem == 0)) {
| 0 | ||||||||||||||||||
1633 | qWarning("QGraphicsAnchorLayout::addAnchor(): " | - | ||||||||||||||||||
1634 | "Cannot anchor NULL items"); | - | ||||||||||||||||||
1635 | return 0; never executed: return 0; | 0 | ||||||||||||||||||
1636 | } | - | ||||||||||||||||||
1637 | - | |||||||||||||||||||
1638 | if (firstItem == secondItem) {
| 0 | ||||||||||||||||||
1639 | qWarning("QGraphicsAnchorLayout::addAnchor(): " | - | ||||||||||||||||||
1640 | "Cannot anchor the item to itself"); | - | ||||||||||||||||||
1641 | return 0; never executed: return 0; | 0 | ||||||||||||||||||
1642 | } | - | ||||||||||||||||||
1643 | - | |||||||||||||||||||
1644 | if (edgeOrientation(secondEdge) != edgeOrientation(firstEdge)) {
| 0 | ||||||||||||||||||
1645 | qWarning("QGraphicsAnchorLayout::addAnchor(): " | - | ||||||||||||||||||
1646 | "Cannot anchor edges of different orientations"); | - | ||||||||||||||||||
1647 | return 0; never executed: return 0; | 0 | ||||||||||||||||||
1648 | } | - | ||||||||||||||||||
1649 | - | |||||||||||||||||||
1650 | const QGraphicsLayoutItem *parentWidget = q->parentLayoutItem(); | - | ||||||||||||||||||
1651 | if (firstItem == parentWidget || secondItem == parentWidget) {
| 0 | ||||||||||||||||||
1652 | qWarning("QGraphicsAnchorLayout::addAnchor(): " | - | ||||||||||||||||||
1653 | "You cannot add the parent of the layout to the layout."); | - | ||||||||||||||||||
1654 | return 0; never executed: return 0; | 0 | ||||||||||||||||||
1655 | } | - | ||||||||||||||||||
1656 | - | |||||||||||||||||||
1657 | // In QGraphicsAnchorLayout, items are represented in its internal | - | ||||||||||||||||||
1658 | // graph as four anchors that connect: | - | ||||||||||||||||||
1659 | // - Left -> HCenter | - | ||||||||||||||||||
1660 | // - HCenter-> Right | - | ||||||||||||||||||
1661 | // - Top -> VCenter | - | ||||||||||||||||||
1662 | // - VCenter -> Bottom | - | ||||||||||||||||||
1663 | - | |||||||||||||||||||
1664 | // Ensure that the internal anchors have been created for both items. | - | ||||||||||||||||||
1665 | if (firstItem != q && !items.contains(firstItem)) {
| 0 | ||||||||||||||||||
1666 | createItemEdges(firstItem); | - | ||||||||||||||||||
1667 | addChildLayoutItem(firstItem); | - | ||||||||||||||||||
1668 | } never executed: end of block | 0 | ||||||||||||||||||
1669 | if (secondItem != q && !items.contains(secondItem)) {
| 0 | ||||||||||||||||||
1670 | createItemEdges(secondItem); | - | ||||||||||||||||||
1671 | addChildLayoutItem(secondItem); | - | ||||||||||||||||||
1672 | } never executed: end of block | 0 | ||||||||||||||||||
1673 | - | |||||||||||||||||||
1674 | // Create center edges if needed | - | ||||||||||||||||||
1675 | createCenterAnchors(firstItem, firstEdge); | - | ||||||||||||||||||
1676 | createCenterAnchors(secondItem, secondEdge); | - | ||||||||||||||||||
1677 | - | |||||||||||||||||||
1678 | // Use heuristics to find out what the user meant with this anchor. | - | ||||||||||||||||||
1679 | correctEdgeDirection(firstItem, firstEdge, secondItem, secondEdge); | - | ||||||||||||||||||
1680 | - | |||||||||||||||||||
1681 | AnchorData *data = new AnchorData; | - | ||||||||||||||||||
1682 | QGraphicsAnchor *graphicsAnchor = acquireGraphicsAnchor(data); | - | ||||||||||||||||||
1683 | - | |||||||||||||||||||
1684 | addAnchor_helper(firstItem, firstEdge, secondItem, secondEdge, data); | - | ||||||||||||||||||
1685 | - | |||||||||||||||||||
1686 | if (spacing) {
| 0 | ||||||||||||||||||
1687 | graphicsAnchor->setSpacing(*spacing); | - | ||||||||||||||||||
1688 | } else { never executed: end of block | 0 | ||||||||||||||||||
1689 | // If firstItem or secondItem is the layout itself, the spacing will default to 0. | - | ||||||||||||||||||
1690 | // Otherwise, the following matrix is used (questionmark means that the spacing | - | ||||||||||||||||||
1691 | // is queried from the style): | - | ||||||||||||||||||
1692 | // from | - | ||||||||||||||||||
1693 | // to Left HCenter Right | - | ||||||||||||||||||
1694 | // Left 0 0 ? | - | ||||||||||||||||||
1695 | // HCenter 0 0 0 | - | ||||||||||||||||||
1696 | // Right ? 0 0 | - | ||||||||||||||||||
1697 | if (firstItem == q
| 0 | ||||||||||||||||||
1698 | || secondItem == q
| 0 | ||||||||||||||||||
1699 | || pickEdge(firstEdge, Horizontal) == Qt::AnchorHorizontalCenter
| 0 | ||||||||||||||||||
1700 | || oppositeEdge(firstEdge) != secondEdge) {
| 0 | ||||||||||||||||||
1701 | graphicsAnchor->setSpacing(0); | - | ||||||||||||||||||
1702 | } else { never executed: end of block | 0 | ||||||||||||||||||
1703 | graphicsAnchor->unsetSpacing(); | - | ||||||||||||||||||
1704 | } never executed: end of block | 0 | ||||||||||||||||||
1705 | } | - | ||||||||||||||||||
1706 | - | |||||||||||||||||||
1707 | return graphicsAnchor; never executed: return graphicsAnchor; | 0 | ||||||||||||||||||
1708 | } | - | ||||||||||||||||||
1709 | - | |||||||||||||||||||
1710 | /* | - | ||||||||||||||||||
1711 | \internal | - | ||||||||||||||||||
1712 | - | |||||||||||||||||||
1713 | This method adds an AnchorData to the internal graph. It is responsible for doing | - | ||||||||||||||||||
1714 | the boilerplate part of such task. | - | ||||||||||||||||||
1715 | - | |||||||||||||||||||
1716 | If another AnchorData exists between the mentioned vertices, it is deleted and | - | ||||||||||||||||||
1717 | the new one is inserted. | - | ||||||||||||||||||
1718 | */ | - | ||||||||||||||||||
1719 | void QGraphicsAnchorLayoutPrivate::addAnchor_helper(QGraphicsLayoutItem *firstItem, | - | ||||||||||||||||||
1720 | Qt::AnchorPoint firstEdge, | - | ||||||||||||||||||
1721 | QGraphicsLayoutItem *secondItem, | - | ||||||||||||||||||
1722 | Qt::AnchorPoint secondEdge, | - | ||||||||||||||||||
1723 | AnchorData *data) | - | ||||||||||||||||||
1724 | { | - | ||||||||||||||||||
1725 | Q_Q(QGraphicsAnchorLayout); | - | ||||||||||||||||||
1726 | - | |||||||||||||||||||
1727 | const Orientation orientation = edgeOrientation(firstEdge); | - | ||||||||||||||||||
1728 | - | |||||||||||||||||||
1729 | // Create or increase the reference count for the related vertices. | - | ||||||||||||||||||
1730 | AnchorVertex *v1 = addInternalVertex(firstItem, firstEdge); | - | ||||||||||||||||||
1731 | AnchorVertex *v2 = addInternalVertex(secondItem, secondEdge); | - | ||||||||||||||||||
1732 | - | |||||||||||||||||||
1733 | // Remove previous anchor | - | ||||||||||||||||||
1734 | if (graph[orientation].edgeData(v1, v2)) {
| 0 | ||||||||||||||||||
1735 | removeAnchor_helper(v1, v2); | - | ||||||||||||||||||
1736 | } never executed: end of block | 0 | ||||||||||||||||||
1737 | - | |||||||||||||||||||
1738 | // If its an internal anchor, set the associated item | - | ||||||||||||||||||
1739 | if (firstItem == secondItem)
| 0 | ||||||||||||||||||
1740 | data->item = firstItem; never executed: data->item = firstItem; | 0 | ||||||||||||||||||
1741 | - | |||||||||||||||||||
1742 | data->orientation = orientation; | - | ||||||||||||||||||
1743 | - | |||||||||||||||||||
1744 | // Create a bi-directional edge in the sense it can be transversed both | - | ||||||||||||||||||
1745 | // from v1 or v2. "data" however is shared between the two references | - | ||||||||||||||||||
1746 | // so we still know that the anchor direction is from 1 to 2. | - | ||||||||||||||||||
1747 | data->from = v1; | - | ||||||||||||||||||
1748 | data->to = v2; | - | ||||||||||||||||||
1749 | #ifdef QT_DEBUG | - | ||||||||||||||||||
1750 | data->name = QString::fromLatin1("%1 --to--> %2").arg(v1->toString()).arg(v2->toString()); | - | ||||||||||||||||||
1751 | #endif | - | ||||||||||||||||||
1752 | // ### bit to track internal anchors, since inside AnchorData methods | - | ||||||||||||||||||
1753 | // we don't have access to the 'q' pointer. | - | ||||||||||||||||||
1754 | data->isLayoutAnchor = (data->item == q); | - | ||||||||||||||||||
1755 | - | |||||||||||||||||||
1756 | graph[orientation].createEdge(v1, v2, data); | - | ||||||||||||||||||
1757 | } never executed: end of block | 0 | ||||||||||||||||||
1758 | - | |||||||||||||||||||
1759 | QGraphicsAnchor *QGraphicsAnchorLayoutPrivate::getAnchor(QGraphicsLayoutItem *firstItem, | - | ||||||||||||||||||
1760 | Qt::AnchorPoint firstEdge, | - | ||||||||||||||||||
1761 | QGraphicsLayoutItem *secondItem, | - | ||||||||||||||||||
1762 | Qt::AnchorPoint secondEdge) | - | ||||||||||||||||||
1763 | { | - | ||||||||||||||||||
1764 | // Do not expose internal anchors | - | ||||||||||||||||||
1765 | if (firstItem == secondItem)
| 0 | ||||||||||||||||||
1766 | return 0; never executed: return 0; | 0 | ||||||||||||||||||
1767 | - | |||||||||||||||||||
1768 | const Orientation orientation = edgeOrientation(firstEdge); | - | ||||||||||||||||||
1769 | AnchorVertex *v1 = internalVertex(firstItem, firstEdge); | - | ||||||||||||||||||
1770 | AnchorVertex *v2 = internalVertex(secondItem, secondEdge); | - | ||||||||||||||||||
1771 | - | |||||||||||||||||||
1772 | QGraphicsAnchor *graphicsAnchor = 0; | - | ||||||||||||||||||
1773 | - | |||||||||||||||||||
1774 | AnchorData *data = graph[orientation].edgeData(v1, v2); | - | ||||||||||||||||||
1775 | if (data) {
| 0 | ||||||||||||||||||
1776 | // We could use "acquireGraphicsAnchor" here, but to avoid a regression where | - | ||||||||||||||||||
1777 | // an internal anchor was wrongly exposed, I want to ensure no new | - | ||||||||||||||||||
1778 | // QGraphicsAnchor instances are created by this call. | - | ||||||||||||||||||
1779 | // This assumption must hold because anchors are either user-created (and already | - | ||||||||||||||||||
1780 | // have their public object created), or they are internal (and must not reach | - | ||||||||||||||||||
1781 | // this point). | - | ||||||||||||||||||
1782 | Q_ASSERT(data->graphicsAnchor); | - | ||||||||||||||||||
1783 | graphicsAnchor = data->graphicsAnchor; | - | ||||||||||||||||||
1784 | } never executed: end of block | 0 | ||||||||||||||||||
1785 | return graphicsAnchor; never executed: return graphicsAnchor; | 0 | ||||||||||||||||||
1786 | } | - | ||||||||||||||||||
1787 | - | |||||||||||||||||||
1788 | /*! | - | ||||||||||||||||||
1789 | * \internal | - | ||||||||||||||||||
1790 | * | - | ||||||||||||||||||
1791 | * Implements the high level "removeAnchor" feature. Called by | - | ||||||||||||||||||
1792 | * the QAnchorData destructor. | - | ||||||||||||||||||
1793 | */ | - | ||||||||||||||||||
1794 | void QGraphicsAnchorLayoutPrivate::removeAnchor(AnchorVertex *firstVertex, | - | ||||||||||||||||||
1795 | AnchorVertex *secondVertex) | - | ||||||||||||||||||
1796 | { | - | ||||||||||||||||||
1797 | Q_Q(QGraphicsAnchorLayout); | - | ||||||||||||||||||
1798 | - | |||||||||||||||||||
1799 | // Save references to items while it's safe to assume the vertices exist | - | ||||||||||||||||||
1800 | QGraphicsLayoutItem *firstItem = firstVertex->m_item; | - | ||||||||||||||||||
1801 | QGraphicsLayoutItem *secondItem = secondVertex->m_item; | - | ||||||||||||||||||
1802 | - | |||||||||||||||||||
1803 | // Delete the anchor (may trigger deletion of center vertices) | - | ||||||||||||||||||
1804 | removeAnchor_helper(firstVertex, secondVertex); | - | ||||||||||||||||||
1805 | - | |||||||||||||||||||
1806 | // Ensure no dangling pointer is left behind | - | ||||||||||||||||||
1807 | firstVertex = secondVertex = 0; | - | ||||||||||||||||||
1808 | - | |||||||||||||||||||
1809 | // Checking if the item stays in the layout or not | - | ||||||||||||||||||
1810 | bool keepFirstItem = false; | - | ||||||||||||||||||
1811 | bool keepSecondItem = false; | - | ||||||||||||||||||
1812 | - | |||||||||||||||||||
1813 | QPair<AnchorVertex *, int> v; | - | ||||||||||||||||||
1814 | int refcount = -1; | - | ||||||||||||||||||
1815 | - | |||||||||||||||||||
1816 | if (firstItem != q) {
| 0 | ||||||||||||||||||
1817 | for (int i = Qt::AnchorLeft; i <= Qt::AnchorBottom; ++i) {
| 0 | ||||||||||||||||||
1818 | v = m_vertexList.value(qMakePair(firstItem, static_cast<Qt::AnchorPoint>(i))); | - | ||||||||||||||||||
1819 | if (v.first) {
| 0 | ||||||||||||||||||
1820 | if (i == Qt::AnchorHorizontalCenter || i == Qt::AnchorVerticalCenter)
| 0 | ||||||||||||||||||
1821 | refcount = 2; never executed: refcount = 2; | 0 | ||||||||||||||||||
1822 | else | - | ||||||||||||||||||
1823 | refcount = 1; never executed: refcount = 1; | 0 | ||||||||||||||||||
1824 | - | |||||||||||||||||||
1825 | if (v.second > refcount) {
| 0 | ||||||||||||||||||
1826 | keepFirstItem = true; | - | ||||||||||||||||||
1827 | break; never executed: break; | 0 | ||||||||||||||||||
1828 | } | - | ||||||||||||||||||
1829 | } never executed: end of block | 0 | ||||||||||||||||||
1830 | } never executed: end of block | 0 | ||||||||||||||||||
1831 | } else never executed: end of block | 0 | ||||||||||||||||||
1832 | keepFirstItem = true; never executed: keepFirstItem = true; | 0 | ||||||||||||||||||
1833 | - | |||||||||||||||||||
1834 | if (secondItem != q) {
| 0 | ||||||||||||||||||
1835 | for (int i = Qt::AnchorLeft; i <= Qt::AnchorBottom; ++i) {
| 0 | ||||||||||||||||||
1836 | v = m_vertexList.value(qMakePair(secondItem, static_cast<Qt::AnchorPoint>(i))); | - | ||||||||||||||||||
1837 | if (v.first) {
| 0 | ||||||||||||||||||
1838 | if (i == Qt::AnchorHorizontalCenter || i == Qt::AnchorVerticalCenter)
| 0 | ||||||||||||||||||
1839 | refcount = 2; never executed: refcount = 2; | 0 | ||||||||||||||||||
1840 | else | - | ||||||||||||||||||
1841 | refcount = 1; never executed: refcount = 1; | 0 | ||||||||||||||||||
1842 | - | |||||||||||||||||||
1843 | if (v.second > refcount) {
| 0 | ||||||||||||||||||
1844 | keepSecondItem = true; | - | ||||||||||||||||||
1845 | break; never executed: break; | 0 | ||||||||||||||||||
1846 | } | - | ||||||||||||||||||
1847 | } never executed: end of block | 0 | ||||||||||||||||||
1848 | } never executed: end of block | 0 | ||||||||||||||||||
1849 | } else never executed: end of block | 0 | ||||||||||||||||||
1850 | keepSecondItem = true; never executed: keepSecondItem = true; | 0 | ||||||||||||||||||
1851 | - | |||||||||||||||||||
1852 | if (!keepFirstItem)
| 0 | ||||||||||||||||||
1853 | q->removeAt(items.indexOf(firstItem)); never executed: q->removeAt(items.indexOf(firstItem)); | 0 | ||||||||||||||||||
1854 | - | |||||||||||||||||||
1855 | if (!keepSecondItem)
| 0 | ||||||||||||||||||
1856 | q->removeAt(items.indexOf(secondItem)); never executed: q->removeAt(items.indexOf(secondItem)); | 0 | ||||||||||||||||||
1857 | - | |||||||||||||||||||
1858 | // Removing anchors invalidates the layout | - | ||||||||||||||||||
1859 | q->invalidate(); | - | ||||||||||||||||||
1860 | } never executed: end of block | 0 | ||||||||||||||||||
1861 | - | |||||||||||||||||||
1862 | /* | - | ||||||||||||||||||
1863 | \internal | - | ||||||||||||||||||
1864 | - | |||||||||||||||||||
1865 | Implements the low level "removeAnchor" feature. Called by | - | ||||||||||||||||||
1866 | private methods. | - | ||||||||||||||||||
1867 | */ | - | ||||||||||||||||||
1868 | void QGraphicsAnchorLayoutPrivate::removeAnchor_helper(AnchorVertex *v1, AnchorVertex *v2) | - | ||||||||||||||||||
1869 | { | - | ||||||||||||||||||
1870 | Q_ASSERT(v1 && v2); | - | ||||||||||||||||||
1871 | - | |||||||||||||||||||
1872 | // Remove edge from graph | - | ||||||||||||||||||
1873 | const Orientation o = edgeOrientation(v1->m_edge); | - | ||||||||||||||||||
1874 | graph[o].removeEdge(v1, v2); | - | ||||||||||||||||||
1875 | - | |||||||||||||||||||
1876 | // Decrease vertices reference count (may trigger a deletion) | - | ||||||||||||||||||
1877 | removeInternalVertex(v1->m_item, v1->m_edge); | - | ||||||||||||||||||
1878 | removeInternalVertex(v2->m_item, v2->m_edge); | - | ||||||||||||||||||
1879 | } never executed: end of block | 0 | ||||||||||||||||||
1880 | - | |||||||||||||||||||
1881 | AnchorVertex *QGraphicsAnchorLayoutPrivate::addInternalVertex(QGraphicsLayoutItem *item, | - | ||||||||||||||||||
1882 | Qt::AnchorPoint edge) | - | ||||||||||||||||||
1883 | { | - | ||||||||||||||||||
1884 | QPair<QGraphicsLayoutItem *, Qt::AnchorPoint> pair(item, edge); | - | ||||||||||||||||||
1885 | QPair<AnchorVertex *, int> v = m_vertexList.value(pair); | - | ||||||||||||||||||
1886 | - | |||||||||||||||||||
1887 | if (!v.first) {
| 0 | ||||||||||||||||||
1888 | Q_ASSERT(v.second == 0); | - | ||||||||||||||||||
1889 | v.first = new AnchorVertex(item, edge); | - | ||||||||||||||||||
1890 | } never executed: end of block | 0 | ||||||||||||||||||
1891 | v.second++; | - | ||||||||||||||||||
1892 | m_vertexList.insert(pair, v); | - | ||||||||||||||||||
1893 | return v.first; never executed: return v.first; | 0 | ||||||||||||||||||
1894 | } | - | ||||||||||||||||||
1895 | - | |||||||||||||||||||
1896 | /** | - | ||||||||||||||||||
1897 | * \internal | - | ||||||||||||||||||
1898 | * | - | ||||||||||||||||||
1899 | * returns the AnchorVertex that was dereferenced, also when it was removed. | - | ||||||||||||||||||
1900 | * returns 0 if it did not exist. | - | ||||||||||||||||||
1901 | */ | - | ||||||||||||||||||
1902 | void QGraphicsAnchorLayoutPrivate::removeInternalVertex(QGraphicsLayoutItem *item, | - | ||||||||||||||||||
1903 | Qt::AnchorPoint edge) | - | ||||||||||||||||||
1904 | { | - | ||||||||||||||||||
1905 | QPair<QGraphicsLayoutItem *, Qt::AnchorPoint> pair(item, edge); | - | ||||||||||||||||||
1906 | QPair<AnchorVertex *, int> v = m_vertexList.value(pair); | - | ||||||||||||||||||
1907 | - | |||||||||||||||||||
1908 | if (!v.first) {
| 0 | ||||||||||||||||||
1909 | qWarning("This item with this edge is not in the graph"); | - | ||||||||||||||||||
1910 | return; never executed: return; | 0 | ||||||||||||||||||
1911 | } | - | ||||||||||||||||||
1912 | - | |||||||||||||||||||
1913 | v.second--; | - | ||||||||||||||||||
1914 | if (v.second == 0) {
| 0 | ||||||||||||||||||
1915 | // Remove reference and delete vertex | - | ||||||||||||||||||
1916 | m_vertexList.remove(pair); | - | ||||||||||||||||||
1917 | delete v.first; | - | ||||||||||||||||||
1918 | } else { never executed: end of block | 0 | ||||||||||||||||||
1919 | // Update reference count | - | ||||||||||||||||||
1920 | m_vertexList.insert(pair, v); | - | ||||||||||||||||||
1921 | - | |||||||||||||||||||
1922 | if ((v.second == 2) &&
| 0 | ||||||||||||||||||
1923 | ((edge == Qt::AnchorHorizontalCenter) ||
| 0 | ||||||||||||||||||
1924 | (edge == Qt::AnchorVerticalCenter))) {
| 0 | ||||||||||||||||||
1925 | removeCenterAnchors(item, edge, true); | - | ||||||||||||||||||
1926 | } never executed: end of block | 0 | ||||||||||||||||||
1927 | } never executed: end of block | 0 | ||||||||||||||||||
1928 | } | - | ||||||||||||||||||
1929 | - | |||||||||||||||||||
1930 | void QGraphicsAnchorLayoutPrivate::removeVertex(QGraphicsLayoutItem *item, Qt::AnchorPoint edge) | - | ||||||||||||||||||
1931 | { | - | ||||||||||||||||||
1932 | if (AnchorVertex *v = internalVertex(item, edge)) {
| 0 | ||||||||||||||||||
1933 | Graph<AnchorVertex, AnchorData> &g = graph[edgeOrientation(edge)]; | - | ||||||||||||||||||
1934 | const QList<AnchorVertex *> allVertices = graph[edgeOrientation(edge)].adjacentVertices(v); | - | ||||||||||||||||||
1935 | AnchorVertex *v2; | - | ||||||||||||||||||
1936 | foreach (v2, allVertices) { | - | ||||||||||||||||||
1937 | g.removeEdge(v, v2); | - | ||||||||||||||||||
1938 | removeInternalVertex(item, edge); | - | ||||||||||||||||||
1939 | removeInternalVertex(v2->m_item, v2->m_edge); | - | ||||||||||||||||||
1940 | } never executed: end of block | 0 | ||||||||||||||||||
1941 | } never executed: end of block | 0 | ||||||||||||||||||
1942 | } never executed: end of block | 0 | ||||||||||||||||||
1943 | - | |||||||||||||||||||
1944 | void QGraphicsAnchorLayoutPrivate::removeAnchors(QGraphicsLayoutItem *item) | - | ||||||||||||||||||
1945 | { | - | ||||||||||||||||||
1946 | // remove the center anchor first!! | - | ||||||||||||||||||
1947 | removeCenterAnchors(item, Qt::AnchorHorizontalCenter, false); | - | ||||||||||||||||||
1948 | removeVertex(item, Qt::AnchorLeft); | - | ||||||||||||||||||
1949 | removeVertex(item, Qt::AnchorRight); | - | ||||||||||||||||||
1950 | - | |||||||||||||||||||
1951 | removeCenterAnchors(item, Qt::AnchorVerticalCenter, false); | - | ||||||||||||||||||
1952 | removeVertex(item, Qt::AnchorTop); | - | ||||||||||||||||||
1953 | removeVertex(item, Qt::AnchorBottom); | - | ||||||||||||||||||
1954 | } never executed: end of block | 0 | ||||||||||||||||||
1955 | - | |||||||||||||||||||
1956 | /*! | - | ||||||||||||||||||
1957 | \internal | - | ||||||||||||||||||
1958 | - | |||||||||||||||||||
1959 | Use heuristics to determine the correct orientation of a given anchor. | - | ||||||||||||||||||
1960 | - | |||||||||||||||||||
1961 | After API discussions, we decided we would like expressions like | - | ||||||||||||||||||
1962 | anchor(A, Left, B, Right) to mean the same as anchor(B, Right, A, Left). | - | ||||||||||||||||||
1963 | The problem with this is that anchors could become ambiguous, for | - | ||||||||||||||||||
1964 | instance, what does the anchor A, B of size X mean? | - | ||||||||||||||||||
1965 | - | |||||||||||||||||||
1966 | "pos(B) = pos(A) + X" or "pos(A) = pos(B) + X" ? | - | ||||||||||||||||||
1967 | - | |||||||||||||||||||
1968 | To keep the API user friendly and at the same time, keep our algorithm | - | ||||||||||||||||||
1969 | deterministic, we use an heuristic to determine a direction for each | - | ||||||||||||||||||
1970 | added anchor and then keep it. The heuristic is based on the fact | - | ||||||||||||||||||
1971 | that people usually avoid overlapping items, therefore: | - | ||||||||||||||||||
1972 | - | |||||||||||||||||||
1973 | "A, RIGHT to B, LEFT" means that B is to the LEFT of A. | - | ||||||||||||||||||
1974 | "B, LEFT to A, RIGHT" is corrected to the above anchor. | - | ||||||||||||||||||
1975 | - | |||||||||||||||||||
1976 | Special correction is also applied when one of the items is the | - | ||||||||||||||||||
1977 | layout. We handle Layout Left as if it was another items's Right | - | ||||||||||||||||||
1978 | and Layout Right as another item's Left. | - | ||||||||||||||||||
1979 | */ | - | ||||||||||||||||||
1980 | void QGraphicsAnchorLayoutPrivate::correctEdgeDirection(QGraphicsLayoutItem *&firstItem, | - | ||||||||||||||||||
1981 | Qt::AnchorPoint &firstEdge, | - | ||||||||||||||||||
1982 | QGraphicsLayoutItem *&secondItem, | - | ||||||||||||||||||
1983 | Qt::AnchorPoint &secondEdge) | - | ||||||||||||||||||
1984 | { | - | ||||||||||||||||||
1985 | Q_Q(QGraphicsAnchorLayout); | - | ||||||||||||||||||
1986 | - | |||||||||||||||||||
1987 | if ((firstItem != q) && (secondItem != q)) {
| 0 | ||||||||||||||||||
1988 | // If connection is between widgets (not the layout itself) | - | ||||||||||||||||||
1989 | // Ensure that "right-edges" sit to the left of "left-edges". | - | ||||||||||||||||||
1990 | if (firstEdge < secondEdge) {
| 0 | ||||||||||||||||||
1991 | qSwap(firstItem, secondItem); | - | ||||||||||||||||||
1992 | qSwap(firstEdge, secondEdge); | - | ||||||||||||||||||
1993 | } never executed: end of block | 0 | ||||||||||||||||||
1994 | } else if (firstItem == q) { never executed: end of block
| 0 | ||||||||||||||||||
1995 | // If connection involves the right or bottom of a layout, ensure | - | ||||||||||||||||||
1996 | // the layout is the second item. | - | ||||||||||||||||||
1997 | if ((firstEdge == Qt::AnchorRight) || (firstEdge == Qt::AnchorBottom)) {
| 0 | ||||||||||||||||||
1998 | qSwap(firstItem, secondItem); | - | ||||||||||||||||||
1999 | qSwap(firstEdge, secondEdge); | - | ||||||||||||||||||
2000 | } never executed: end of block | 0 | ||||||||||||||||||
2001 | } else if ((secondEdge != Qt::AnchorRight) && (secondEdge != Qt::AnchorBottom)) { never executed: end of block
| 0 | ||||||||||||||||||
2002 | // If connection involves the left, center or top of layout, ensure | - | ||||||||||||||||||
2003 | // the layout is the first item. | - | ||||||||||||||||||
2004 | qSwap(firstItem, secondItem); | - | ||||||||||||||||||
2005 | qSwap(firstEdge, secondEdge); | - | ||||||||||||||||||
2006 | } never executed: end of block | 0 | ||||||||||||||||||
2007 | } never executed: end of block | 0 | ||||||||||||||||||
2008 | - | |||||||||||||||||||
2009 | QLayoutStyleInfo &QGraphicsAnchorLayoutPrivate::styleInfo() const | - | ||||||||||||||||||
2010 | { | - | ||||||||||||||||||
2011 | if (styleInfoDirty) {
| 0 | ||||||||||||||||||
2012 | Q_Q(const QGraphicsAnchorLayout); | - | ||||||||||||||||||
2013 | //### Fix this if QGV ever gets support for Metal style or different Aqua sizes. | - | ||||||||||||||||||
2014 | QWidget *wid = 0; | - | ||||||||||||||||||
2015 | - | |||||||||||||||||||
2016 | QGraphicsLayoutItem *parent = q->parentLayoutItem(); | - | ||||||||||||||||||
2017 | while (parent && parent->isLayout()) {
| 0 | ||||||||||||||||||
2018 | parent = parent->parentLayoutItem(); | - | ||||||||||||||||||
2019 | } never executed: end of block | 0 | ||||||||||||||||||
2020 | QGraphicsWidget *w = 0; | - | ||||||||||||||||||
2021 | if (parent) {
| 0 | ||||||||||||||||||
2022 | QGraphicsItem *parentItem = parent->graphicsItem(); | - | ||||||||||||||||||
2023 | if (parentItem && parentItem->isWidget())
| 0 | ||||||||||||||||||
2024 | w = static_cast<QGraphicsWidget*>(parentItem); never executed: w = static_cast<QGraphicsWidget*>(parentItem); | 0 | ||||||||||||||||||
2025 | } never executed: end of block | 0 | ||||||||||||||||||
2026 | - | |||||||||||||||||||
2027 | QStyle *style = w ? w->style() : QApplication::style();
| 0 | ||||||||||||||||||
2028 | cachedStyleInfo = QLayoutStyleInfo(style, wid); | - | ||||||||||||||||||
2029 | cachedStyleInfo.setDefaultSpacing(Qt::Horizontal, spacings[0]); | - | ||||||||||||||||||
2030 | cachedStyleInfo.setDefaultSpacing(Qt::Vertical, spacings[1]); | - | ||||||||||||||||||
2031 | - | |||||||||||||||||||
2032 | styleInfoDirty = false; | - | ||||||||||||||||||
2033 | } never executed: end of block | 0 | ||||||||||||||||||
2034 | return cachedStyleInfo; never executed: return cachedStyleInfo; | 0 | ||||||||||||||||||
2035 | } | - | ||||||||||||||||||
2036 | - | |||||||||||||||||||
2037 | /*! | - | ||||||||||||||||||
2038 | \internal | - | ||||||||||||||||||
2039 | - | |||||||||||||||||||
2040 | Called on activation. Uses Linear Programming to define minimum, preferred | - | ||||||||||||||||||
2041 | and maximum sizes for the layout. Also calculates the sizes that each item | - | ||||||||||||||||||
2042 | should assume when the layout is in one of such situations. | - | ||||||||||||||||||
2043 | */ | - | ||||||||||||||||||
2044 | void QGraphicsAnchorLayoutPrivate::calculateGraphs() | - | ||||||||||||||||||
2045 | { | - | ||||||||||||||||||
2046 | if (!calculateGraphCacheDirty)
| 0 | ||||||||||||||||||
2047 | return; never executed: return; | 0 | ||||||||||||||||||
2048 | calculateGraphs(Horizontal); | - | ||||||||||||||||||
2049 | calculateGraphs(Vertical); | - | ||||||||||||||||||
2050 | calculateGraphCacheDirty = false; | - | ||||||||||||||||||
2051 | } never executed: end of block | 0 | ||||||||||||||||||
2052 | - | |||||||||||||||||||
2053 | // ### Maybe getGraphParts could return the variables when traversing, at least | - | ||||||||||||||||||
2054 | // for trunk... | - | ||||||||||||||||||
2055 | QList<AnchorData *> getVariables(const QList<QSimplexConstraint *> &constraints) | - | ||||||||||||||||||
2056 | { | - | ||||||||||||||||||
2057 | QSet<AnchorData *> variableSet; | - | ||||||||||||||||||
2058 | for (int i = 0; i < constraints.count(); ++i) {
| 0 | ||||||||||||||||||
2059 | const QSimplexConstraint *c = constraints.at(i); | - | ||||||||||||||||||
2060 | foreach (QSimplexVariable *var, c->variables.keys()) { | - | ||||||||||||||||||
2061 | variableSet += static_cast<AnchorData *>(var); | - | ||||||||||||||||||
2062 | } never executed: end of block | 0 | ||||||||||||||||||
2063 | } never executed: end of block | 0 | ||||||||||||||||||
2064 | return variableSet.toList(); never executed: return variableSet.toList(); | 0 | ||||||||||||||||||
2065 | } | - | ||||||||||||||||||
2066 | - | |||||||||||||||||||
2067 | /*! | - | ||||||||||||||||||
2068 | \internal | - | ||||||||||||||||||
2069 | - | |||||||||||||||||||
2070 | Calculate graphs is the method that puts together all the helper routines | - | ||||||||||||||||||
2071 | so that the AnchorLayout can calculate the sizes of each item. | - | ||||||||||||||||||
2072 | - | |||||||||||||||||||
2073 | In a nutshell it should do: | - | ||||||||||||||||||
2074 | - | |||||||||||||||||||
2075 | 1) Refresh anchor nominal sizes, that is, the size that each anchor would | - | ||||||||||||||||||
2076 | have if no other restrictions applied. This is done by quering the | - | ||||||||||||||||||
2077 | layout style and the sizeHints of the items belonging to the layout. | - | ||||||||||||||||||
2078 | - | |||||||||||||||||||
2079 | 2) Simplify the graph by grouping together parallel and sequential anchors | - | ||||||||||||||||||
2080 | into "group anchors". These have equivalent minimum, preferred and maximum | - | ||||||||||||||||||
2081 | sizeHints as the anchors they replace. | - | ||||||||||||||||||
2082 | - | |||||||||||||||||||
2083 | 3) Check if we got to a trivial case. In some cases, the whole graph can be | - | ||||||||||||||||||
2084 | simplified into a single anchor. If so, use this information. If not, | - | ||||||||||||||||||
2085 | then call the Simplex solver to calculate the anchors sizes. | - | ||||||||||||||||||
2086 | - | |||||||||||||||||||
2087 | 4) Once the root anchors had its sizes calculated, propagate that to the | - | ||||||||||||||||||
2088 | anchors they represent. | - | ||||||||||||||||||
2089 | */ | - | ||||||||||||||||||
2090 | void QGraphicsAnchorLayoutPrivate::calculateGraphs( | - | ||||||||||||||||||
2091 | QGraphicsAnchorLayoutPrivate::Orientation orientation) | - | ||||||||||||||||||
2092 | { | - | ||||||||||||||||||
2093 | #if defined(QT_DEBUG) || defined(QT_BUILD_INTERNAL) | - | ||||||||||||||||||
2094 | lastCalculationUsedSimplex[orientation] = false; | - | ||||||||||||||||||
2095 | #endif | - | ||||||||||||||||||
2096 | - | |||||||||||||||||||
2097 | static bool simplificationEnabled = qEnvironmentVariableIsEmpty("QT_ANCHORLAYOUT_NO_SIMPLIFICATION"); | - | ||||||||||||||||||
2098 | - | |||||||||||||||||||
2099 | // Reset the nominal sizes of each anchor based on the current item sizes | - | ||||||||||||||||||
2100 | refreshAllSizeHints(orientation); | - | ||||||||||||||||||
2101 | - | |||||||||||||||||||
2102 | // Simplify the graph | - | ||||||||||||||||||
2103 | if (simplificationEnabled && !simplifyGraph(orientation)) {
| 0 | ||||||||||||||||||
2104 | qWarning("QGraphicsAnchorLayout: anchor setup is not feasible."); | - | ||||||||||||||||||
2105 | graphHasConflicts[orientation] = true; | - | ||||||||||||||||||
2106 | return; never executed: return; | 0 | ||||||||||||||||||
2107 | } | - | ||||||||||||||||||
2108 | - | |||||||||||||||||||
2109 | // Traverse all graph edges and store the possible paths to each vertex | - | ||||||||||||||||||
2110 | findPaths(orientation); | - | ||||||||||||||||||
2111 | - | |||||||||||||||||||
2112 | // From the paths calculated above, extract the constraints that the current | - | ||||||||||||||||||
2113 | // anchor setup impose, to our Linear Programming problem. | - | ||||||||||||||||||
2114 | constraintsFromPaths(orientation); | - | ||||||||||||||||||
2115 | - | |||||||||||||||||||
2116 | // Split the constraints and anchors into groups that should be fed to the | - | ||||||||||||||||||
2117 | // simplex solver independently. Currently we find two groups: | - | ||||||||||||||||||
2118 | // | - | ||||||||||||||||||
2119 | // 1) The "trunk", that is, the set of anchors (items) that are connected | - | ||||||||||||||||||
2120 | // to the two opposite sides of our layout, and thus need to stretch in | - | ||||||||||||||||||
2121 | // order to fit in the current layout size. | - | ||||||||||||||||||
2122 | // | - | ||||||||||||||||||
2123 | // 2) The floating or semi-floating anchors (items) that are those which | - | ||||||||||||||||||
2124 | // are connected to only one (or none) of the layout sides, thus are not | - | ||||||||||||||||||
2125 | // influenced by the layout size. | - | ||||||||||||||||||
2126 | QList<QList<QSimplexConstraint *> > parts = getGraphParts(orientation); | - | ||||||||||||||||||
2127 | - | |||||||||||||||||||
2128 | // Now run the simplex solver to calculate Minimum, Preferred and Maximum sizes | - | ||||||||||||||||||
2129 | // of the "trunk" set of constraints and variables. | - | ||||||||||||||||||
2130 | // ### does trunk always exist? empty = trunk is the layout left->center->right | - | ||||||||||||||||||
2131 | QList<QSimplexConstraint *> trunkConstraints = parts.at(0); | - | ||||||||||||||||||
2132 | QList<AnchorData *> trunkVariables = getVariables(trunkConstraints); | - | ||||||||||||||||||
2133 | - | |||||||||||||||||||
2134 | // For minimum and maximum, use the path between the two layout sides as the | - | ||||||||||||||||||
2135 | // objective function. | - | ||||||||||||||||||
2136 | AnchorVertex *v = layoutLastVertex[orientation]; | - | ||||||||||||||||||
2137 | GraphPath trunkPath = graphPaths[orientation].value(v); | - | ||||||||||||||||||
2138 | - | |||||||||||||||||||
2139 | bool feasible = calculateTrunk(orientation, trunkPath, trunkConstraints, trunkVariables); | - | ||||||||||||||||||
2140 | - | |||||||||||||||||||
2141 | // For the other parts that not the trunk, solve only for the preferred size | - | ||||||||||||||||||
2142 | // that is the size they will remain at, since they are not stretched by the | - | ||||||||||||||||||
2143 | // layout. | - | ||||||||||||||||||
2144 | - | |||||||||||||||||||
2145 | // Skipping the first (trunk) | - | ||||||||||||||||||
2146 | for (int i = 1; i < parts.count(); ++i) {
| 0 | ||||||||||||||||||
2147 | if (!feasible)
| 0 | ||||||||||||||||||
2148 | break; never executed: break; | 0 | ||||||||||||||||||
2149 | - | |||||||||||||||||||
2150 | QList<QSimplexConstraint *> partConstraints = parts.at(i); | - | ||||||||||||||||||
2151 | QList<AnchorData *> partVariables = getVariables(partConstraints); | - | ||||||||||||||||||
2152 | Q_ASSERT(!partVariables.isEmpty()); | - | ||||||||||||||||||
2153 | feasible &= calculateNonTrunk(partConstraints, partVariables); | - | ||||||||||||||||||
2154 | } never executed: end of block | 0 | ||||||||||||||||||
2155 | - | |||||||||||||||||||
2156 | // Propagate the new sizes down the simplified graph, ie. tell the | - | ||||||||||||||||||
2157 | // group anchors to set their children anchors sizes. | - | ||||||||||||||||||
2158 | updateAnchorSizes(orientation); | - | ||||||||||||||||||
2159 | - | |||||||||||||||||||
2160 | graphHasConflicts[orientation] = !feasible; | - | ||||||||||||||||||
2161 | - | |||||||||||||||||||
2162 | // Clean up our data structures. They are not needed anymore since | - | ||||||||||||||||||
2163 | // distribution uses just interpolation. | - | ||||||||||||||||||
2164 | qDeleteAll(constraints[orientation]); | - | ||||||||||||||||||
2165 | constraints[orientation].clear(); | - | ||||||||||||||||||
2166 | graphPaths[orientation].clear(); // ### | - | ||||||||||||||||||
2167 | - | |||||||||||||||||||
2168 | if (simplificationEnabled)
| 0 | ||||||||||||||||||
2169 | restoreSimplifiedGraph(orientation); never executed: restoreSimplifiedGraph(orientation); | 0 | ||||||||||||||||||
2170 | } never executed: end of block | 0 | ||||||||||||||||||
2171 | - | |||||||||||||||||||
2172 | /*! | - | ||||||||||||||||||
2173 | \internal | - | ||||||||||||||||||
2174 | - | |||||||||||||||||||
2175 | Shift all the constraints by a certain amount. This allows us to deal with negative values in | - | ||||||||||||||||||
2176 | the linear program if they are bounded by a certain limit. Functions should be careful to | - | ||||||||||||||||||
2177 | call it again with a negative amount, to shift the constraints back. | - | ||||||||||||||||||
2178 | */ | - | ||||||||||||||||||
2179 | static void shiftConstraints(const QList<QSimplexConstraint *> &constraints, qreal amount) | - | ||||||||||||||||||
2180 | { | - | ||||||||||||||||||
2181 | for (int i = 0; i < constraints.count(); ++i) {
| 0 | ||||||||||||||||||
2182 | QSimplexConstraint *c = constraints.at(i); | - | ||||||||||||||||||
2183 | qreal multiplier = 0; | - | ||||||||||||||||||
2184 | foreach (qreal v, c->variables) { | - | ||||||||||||||||||
2185 | multiplier += v; | - | ||||||||||||||||||
2186 | } never executed: end of block | 0 | ||||||||||||||||||
2187 | c->constant += multiplier * amount; | - | ||||||||||||||||||
2188 | } never executed: end of block | 0 | ||||||||||||||||||
2189 | } never executed: end of block | 0 | ||||||||||||||||||
2190 | - | |||||||||||||||||||
2191 | /*! | - | ||||||||||||||||||
2192 | \internal | - | ||||||||||||||||||
2193 | - | |||||||||||||||||||
2194 | Calculate the sizes for all anchors which are part of the trunk. This works | - | ||||||||||||||||||
2195 | on top of a (possibly) simplified graph. | - | ||||||||||||||||||
2196 | */ | - | ||||||||||||||||||
2197 | bool QGraphicsAnchorLayoutPrivate::calculateTrunk(Orientation orientation, const GraphPath &path, | - | ||||||||||||||||||
2198 | const QList<QSimplexConstraint *> &constraints, | - | ||||||||||||||||||
2199 | const QList<AnchorData *> &variables) | - | ||||||||||||||||||
2200 | { | - | ||||||||||||||||||
2201 | bool feasible = true; | - | ||||||||||||||||||
2202 | bool needsSimplex = !constraints.isEmpty(); | - | ||||||||||||||||||
2203 | - | |||||||||||||||||||
2204 | #if 0 | - | ||||||||||||||||||
2205 | qDebug("Simplex %s for trunk of %s", needsSimplex ? "used" : "NOT used", | - | ||||||||||||||||||
2206 | orientation == Horizontal ? "Horizontal" : "Vertical"); | - | ||||||||||||||||||
2207 | #endif | - | ||||||||||||||||||
2208 | - | |||||||||||||||||||
2209 | if (needsSimplex) {
| 0 | ||||||||||||||||||
2210 | - | |||||||||||||||||||
2211 | QList<QSimplexConstraint *> sizeHintConstraints = constraintsFromSizeHints(variables); | - | ||||||||||||||||||
2212 | QList<QSimplexConstraint *> allConstraints = constraints + sizeHintConstraints; | - | ||||||||||||||||||
2213 | - | |||||||||||||||||||
2214 | shiftConstraints(allConstraints, g_offset); | - | ||||||||||||||||||
2215 | - | |||||||||||||||||||
2216 | // Solve min and max size hints | - | ||||||||||||||||||
2217 | qreal min, max; | - | ||||||||||||||||||
2218 | feasible = solveMinMax(allConstraints, path, &min, &max); | - | ||||||||||||||||||
2219 | - | |||||||||||||||||||
2220 | if (feasible) {
| 0 | ||||||||||||||||||
2221 | solvePreferred(constraints, variables); | - | ||||||||||||||||||
2222 | - | |||||||||||||||||||
2223 | // Calculate and set the preferred size for the layout, | - | ||||||||||||||||||
2224 | // from the edge sizes that were calculated above. | - | ||||||||||||||||||
2225 | qreal pref(0.0); | - | ||||||||||||||||||
2226 | foreach (const AnchorData *ad, path.positives) { | - | ||||||||||||||||||
2227 | pref += ad->sizeAtPreferred; | - | ||||||||||||||||||
2228 | } never executed: end of block | 0 | ||||||||||||||||||
2229 | foreach (const AnchorData *ad, path.negatives) { | - | ||||||||||||||||||
2230 | pref -= ad->sizeAtPreferred; | - | ||||||||||||||||||
2231 | } never executed: end of block | 0 | ||||||||||||||||||
2232 | - | |||||||||||||||||||
2233 | sizeHints[orientation][Qt::MinimumSize] = min; | - | ||||||||||||||||||
2234 | sizeHints[orientation][Qt::PreferredSize] = pref; | - | ||||||||||||||||||
2235 | sizeHints[orientation][Qt::MaximumSize] = max; | - | ||||||||||||||||||
2236 | } never executed: end of block | 0 | ||||||||||||||||||
2237 | - | |||||||||||||||||||
2238 | qDeleteAll(sizeHintConstraints); | - | ||||||||||||||||||
2239 | shiftConstraints(constraints, -g_offset); | - | ||||||||||||||||||
2240 | - | |||||||||||||||||||
2241 | } else { never executed: end of block | 0 | ||||||||||||||||||
2242 | // No Simplex is necessary because the path was simplified all the way to a single | - | ||||||||||||||||||
2243 | // anchor. | - | ||||||||||||||||||
2244 | Q_ASSERT(path.positives.count() == 1); | - | ||||||||||||||||||
2245 | Q_ASSERT(path.negatives.count() == 0); | - | ||||||||||||||||||
2246 | - | |||||||||||||||||||
2247 | AnchorData *ad = path.positives.toList()[0]; | - | ||||||||||||||||||
2248 | ad->sizeAtMinimum = ad->minSize; | - | ||||||||||||||||||
2249 | ad->sizeAtPreferred = ad->prefSize; | - | ||||||||||||||||||
2250 | ad->sizeAtMaximum = ad->maxSize; | - | ||||||||||||||||||
2251 | - | |||||||||||||||||||
2252 | sizeHints[orientation][Qt::MinimumSize] = ad->sizeAtMinimum; | - | ||||||||||||||||||
2253 | sizeHints[orientation][Qt::PreferredSize] = ad->sizeAtPreferred; | - | ||||||||||||||||||
2254 | sizeHints[orientation][Qt::MaximumSize] = ad->sizeAtMaximum; | - | ||||||||||||||||||
2255 | } never executed: end of block | 0 | ||||||||||||||||||
2256 | - | |||||||||||||||||||
2257 | #if defined(QT_DEBUG) || defined(QT_BUILD_INTERNAL) | - | ||||||||||||||||||
2258 | lastCalculationUsedSimplex[orientation] = needsSimplex; | - | ||||||||||||||||||
2259 | #endif | - | ||||||||||||||||||
2260 | - | |||||||||||||||||||
2261 | return feasible; never executed: return feasible; | 0 | ||||||||||||||||||
2262 | } | - | ||||||||||||||||||
2263 | - | |||||||||||||||||||
2264 | /*! | - | ||||||||||||||||||
2265 | \internal | - | ||||||||||||||||||
2266 | */ | - | ||||||||||||||||||
2267 | bool QGraphicsAnchorLayoutPrivate::calculateNonTrunk(const QList<QSimplexConstraint *> &constraints, | - | ||||||||||||||||||
2268 | const QList<AnchorData *> &variables) | - | ||||||||||||||||||
2269 | { | - | ||||||||||||||||||
2270 | shiftConstraints(constraints, g_offset); | - | ||||||||||||||||||
2271 | bool feasible = solvePreferred(constraints, variables); | - | ||||||||||||||||||
2272 | - | |||||||||||||||||||
2273 | if (feasible) {
| 0 | ||||||||||||||||||
2274 | // Propagate size at preferred to other sizes. Semi-floats always will be | - | ||||||||||||||||||
2275 | // in their sizeAtPreferred. | - | ||||||||||||||||||
2276 | for (int j = 0; j < variables.count(); ++j) {
| 0 | ||||||||||||||||||
2277 | AnchorData *ad = variables.at(j); | - | ||||||||||||||||||
2278 | Q_ASSERT(ad); | - | ||||||||||||||||||
2279 | ad->sizeAtMinimum = ad->sizeAtPreferred; | - | ||||||||||||||||||
2280 | ad->sizeAtMaximum = ad->sizeAtPreferred; | - | ||||||||||||||||||
2281 | } never executed: end of block | 0 | ||||||||||||||||||
2282 | } never executed: end of block | 0 | ||||||||||||||||||
2283 | - | |||||||||||||||||||
2284 | shiftConstraints(constraints, -g_offset); | - | ||||||||||||||||||
2285 | return feasible; never executed: return feasible; | 0 | ||||||||||||||||||
2286 | } | - | ||||||||||||||||||
2287 | - | |||||||||||||||||||
2288 | /*! | - | ||||||||||||||||||
2289 | \internal | - | ||||||||||||||||||
2290 | - | |||||||||||||||||||
2291 | Traverse the graph refreshing the size hints. Edges will query their associated | - | ||||||||||||||||||
2292 | item or graphicsAnchor for their size hints. | - | ||||||||||||||||||
2293 | */ | - | ||||||||||||||||||
2294 | void QGraphicsAnchorLayoutPrivate::refreshAllSizeHints(Orientation orientation) | - | ||||||||||||||||||
2295 | { | - | ||||||||||||||||||
2296 | Graph<AnchorVertex, AnchorData> &g = graph[orientation]; | - | ||||||||||||||||||
2297 | QList<QPair<AnchorVertex *, AnchorVertex *> > vertices = g.connections(); | - | ||||||||||||||||||
2298 | - | |||||||||||||||||||
2299 | QLayoutStyleInfo styleInf = styleInfo(); | - | ||||||||||||||||||
2300 | for (int i = 0; i < vertices.count(); ++i) {
| 0 | ||||||||||||||||||
2301 | AnchorData *data = g.edgeData(vertices.at(i).first, vertices.at(i).second); | - | ||||||||||||||||||
2302 | data->refreshSizeHints(&styleInf); | - | ||||||||||||||||||
2303 | } never executed: end of block | 0 | ||||||||||||||||||
2304 | } never executed: end of block | 0 | ||||||||||||||||||
2305 | - | |||||||||||||||||||
2306 | /*! | - | ||||||||||||||||||
2307 | \internal | - | ||||||||||||||||||
2308 | - | |||||||||||||||||||
2309 | This method walks the graph using a breadth-first search to find paths | - | ||||||||||||||||||
2310 | between the root vertex and each vertex on the graph. The edges | - | ||||||||||||||||||
2311 | directions in each path are considered and they are stored as a | - | ||||||||||||||||||
2312 | positive edge (left-to-right) or negative edge (right-to-left). | - | ||||||||||||||||||
2313 | - | |||||||||||||||||||
2314 | The list of paths is used later to generate a list of constraints. | - | ||||||||||||||||||
2315 | */ | - | ||||||||||||||||||
2316 | void QGraphicsAnchorLayoutPrivate::findPaths(Orientation orientation) | - | ||||||||||||||||||
2317 | { | - | ||||||||||||||||||
2318 | QQueue<QPair<AnchorVertex *, AnchorVertex *> > queue; | - | ||||||||||||||||||
2319 | - | |||||||||||||||||||
2320 | QSet<AnchorData *> visited; | - | ||||||||||||||||||
2321 | - | |||||||||||||||||||
2322 | AnchorVertex *root = layoutFirstVertex[orientation]; | - | ||||||||||||||||||
2323 | - | |||||||||||||||||||
2324 | graphPaths[orientation].insert(root, GraphPath()); | - | ||||||||||||||||||
2325 | - | |||||||||||||||||||
2326 | foreach (AnchorVertex *v, graph[orientation].adjacentVertices(root)) { | - | ||||||||||||||||||
2327 | queue.enqueue(qMakePair(root, v)); | - | ||||||||||||||||||
2328 | } never executed: end of block | 0 | ||||||||||||||||||
2329 | - | |||||||||||||||||||
2330 | while(!queue.isEmpty()) {
| 0 | ||||||||||||||||||
2331 | QPair<AnchorVertex *, AnchorVertex *> pair = queue.dequeue(); | - | ||||||||||||||||||
2332 | AnchorData *edge = graph[orientation].edgeData(pair.first, pair.second); | - | ||||||||||||||||||
2333 | - | |||||||||||||||||||
2334 | if (visited.contains(edge))
| 0 | ||||||||||||||||||
2335 | continue; never executed: continue; | 0 | ||||||||||||||||||
2336 | - | |||||||||||||||||||
2337 | visited.insert(edge); | - | ||||||||||||||||||
2338 | GraphPath current = graphPaths[orientation].value(pair.first); | - | ||||||||||||||||||
2339 | - | |||||||||||||||||||
2340 | if (edge->from == pair.first)
| 0 | ||||||||||||||||||
2341 | current.positives.insert(edge); never executed: current.positives.insert(edge); | 0 | ||||||||||||||||||
2342 | else | - | ||||||||||||||||||
2343 | current.negatives.insert(edge); never executed: current.negatives.insert(edge); | 0 | ||||||||||||||||||
2344 | - | |||||||||||||||||||
2345 | graphPaths[orientation].insert(pair.second, current); | - | ||||||||||||||||||
2346 | - | |||||||||||||||||||
2347 | foreach (AnchorVertex *v, | - | ||||||||||||||||||
2348 | graph[orientation].adjacentVertices(pair.second)) { | - | ||||||||||||||||||
2349 | queue.enqueue(qMakePair(pair.second, v)); | - | ||||||||||||||||||
2350 | } never executed: end of block | 0 | ||||||||||||||||||
2351 | } never executed: end of block | 0 | ||||||||||||||||||
2352 | - | |||||||||||||||||||
2353 | // We will walk through every reachable items (non-float) store them in a temporary set. | - | ||||||||||||||||||
2354 | // We them create a set of all items and subtract the non-floating items from the set in | - | ||||||||||||||||||
2355 | // order to get the floating items. The floating items is then stored in m_floatItems | - | ||||||||||||||||||
2356 | identifyFloatItems(visited, orientation); | - | ||||||||||||||||||
2357 | } never executed: end of block | 0 | ||||||||||||||||||
2358 | - | |||||||||||||||||||
2359 | /*! | - | ||||||||||||||||||
2360 | \internal | - | ||||||||||||||||||
2361 | - | |||||||||||||||||||
2362 | Each vertex on the graph that has more than one path to it | - | ||||||||||||||||||
2363 | represents a contra int to the sizes of the items in these paths. | - | ||||||||||||||||||
2364 | - | |||||||||||||||||||
2365 | This method walks the list of paths to each vertex, generate | - | ||||||||||||||||||
2366 | the constraints and store them in a list so they can be used later | - | ||||||||||||||||||
2367 | by the Simplex solver. | - | ||||||||||||||||||
2368 | */ | - | ||||||||||||||||||
2369 | void QGraphicsAnchorLayoutPrivate::constraintsFromPaths(Orientation orientation) | - | ||||||||||||||||||
2370 | { | - | ||||||||||||||||||
2371 | foreach (AnchorVertex *vertex, graphPaths[orientation].uniqueKeys()) | - | ||||||||||||||||||
2372 | { | - | ||||||||||||||||||
2373 | int valueCount = graphPaths[orientation].count(vertex); | - | ||||||||||||||||||
2374 | if (valueCount == 1)
| 0 | ||||||||||||||||||
2375 | continue; never executed: continue; | 0 | ||||||||||||||||||
2376 | - | |||||||||||||||||||
2377 | QList<GraphPath> pathsToVertex = graphPaths[orientation].values(vertex); | - | ||||||||||||||||||
2378 | for (int i = 1; i < valueCount; ++i) {
| 0 | ||||||||||||||||||
2379 | constraints[orientation] += \ | - | ||||||||||||||||||
2380 | pathsToVertex[0].constraint(pathsToVertex.at(i)); | - | ||||||||||||||||||
2381 | } never executed: end of block | 0 | ||||||||||||||||||
2382 | } never executed: end of block | 0 | ||||||||||||||||||
2383 | } never executed: end of block | 0 | ||||||||||||||||||
2384 | - | |||||||||||||||||||
2385 | /*! | - | ||||||||||||||||||
2386 | \internal | - | ||||||||||||||||||
2387 | */ | - | ||||||||||||||||||
2388 | void QGraphicsAnchorLayoutPrivate::updateAnchorSizes(Orientation orientation) | - | ||||||||||||||||||
2389 | { | - | ||||||||||||||||||
2390 | Graph<AnchorVertex, AnchorData> &g = graph[orientation]; | - | ||||||||||||||||||
2391 | const QList<QPair<AnchorVertex *, AnchorVertex *> > &vertices = g.connections(); | - | ||||||||||||||||||
2392 | - | |||||||||||||||||||
2393 | for (int i = 0; i < vertices.count(); ++i) {
| 0 | ||||||||||||||||||
2394 | AnchorData *ad = g.edgeData(vertices.at(i).first, vertices.at(i).second); | - | ||||||||||||||||||
2395 | ad->updateChildrenSizes(); | - | ||||||||||||||||||
2396 | } never executed: end of block | 0 | ||||||||||||||||||
2397 | } never executed: end of block | 0 | ||||||||||||||||||
2398 | - | |||||||||||||||||||
2399 | /*! | - | ||||||||||||||||||
2400 | \internal | - | ||||||||||||||||||
2401 | - | |||||||||||||||||||
2402 | Create LP constraints for each anchor based on its minimum and maximum | - | ||||||||||||||||||
2403 | sizes, as specified in its size hints | - | ||||||||||||||||||
2404 | */ | - | ||||||||||||||||||
2405 | QList<QSimplexConstraint *> QGraphicsAnchorLayoutPrivate::constraintsFromSizeHints( | - | ||||||||||||||||||
2406 | const QList<AnchorData *> &anchors) | - | ||||||||||||||||||
2407 | { | - | ||||||||||||||||||
2408 | if (anchors.isEmpty())
| 0 | ||||||||||||||||||
2409 | return QList<QSimplexConstraint *>(); never executed: return QList<QSimplexConstraint *>(); | 0 | ||||||||||||||||||
2410 | - | |||||||||||||||||||
2411 | // Look for the layout edge. That can be either the first half in case the | - | ||||||||||||||||||
2412 | // layout is split in two, or the whole layout anchor. | - | ||||||||||||||||||
2413 | Orientation orient = Orientation(anchors.first()->orientation); | - | ||||||||||||||||||
2414 | AnchorData *layoutEdge = 0; | - | ||||||||||||||||||
2415 | if (layoutCentralVertex[orient]) {
| 0 | ||||||||||||||||||
2416 | layoutEdge = graph[orient].edgeData(layoutFirstVertex[orient], layoutCentralVertex[orient]); | - | ||||||||||||||||||
2417 | } else { never executed: end of block | 0 | ||||||||||||||||||
2418 | layoutEdge = graph[orient].edgeData(layoutFirstVertex[orient], layoutLastVertex[orient]); | - | ||||||||||||||||||
2419 | } never executed: end of block | 0 | ||||||||||||||||||
2420 | - | |||||||||||||||||||
2421 | // If maxSize is less then "infinite", that means there are other anchors | - | ||||||||||||||||||
2422 | // grouped together with this one. We can't ignore its maximum value so we | - | ||||||||||||||||||
2423 | // set back the variable to NULL to prevent the continue condition from being | - | ||||||||||||||||||
2424 | // satisfied in the loop below. | - | ||||||||||||||||||
2425 | const qreal expectedMax = layoutCentralVertex[orient] ? QWIDGETSIZE_MAX / 2 : QWIDGETSIZE_MAX;
| 0 | ||||||||||||||||||
2426 | qreal actualMax; | - | ||||||||||||||||||
2427 | if (layoutEdge->from == layoutFirstVertex[orient]) {
| 0 | ||||||||||||||||||
2428 | actualMax = layoutEdge->maxSize; | - | ||||||||||||||||||
2429 | } else { never executed: end of block | 0 | ||||||||||||||||||
2430 | actualMax = -layoutEdge->minSize; | - | ||||||||||||||||||
2431 | } never executed: end of block | 0 | ||||||||||||||||||
2432 | if (actualMax != expectedMax) {
| 0 | ||||||||||||||||||
2433 | layoutEdge = 0; | - | ||||||||||||||||||
2434 | } never executed: end of block | 0 | ||||||||||||||||||
2435 | - | |||||||||||||||||||
2436 | // For each variable, create constraints based on size hints | - | ||||||||||||||||||
2437 | QList<QSimplexConstraint *> anchorConstraints; | - | ||||||||||||||||||
2438 | bool unboundedProblem = true; | - | ||||||||||||||||||
2439 | for (int i = 0; i < anchors.size(); ++i) {
| 0 | ||||||||||||||||||
2440 | AnchorData *ad = anchors.at(i); | - | ||||||||||||||||||
2441 | - | |||||||||||||||||||
2442 | // Anchors that have their size directly linked to another one don't need constraints | - | ||||||||||||||||||
2443 | // For exammple, the second half of an item has exactly the same size as the first half | - | ||||||||||||||||||
2444 | // thus constraining the latter is enough. | - | ||||||||||||||||||
2445 | if (ad->dependency == AnchorData::Slave)
| 0 | ||||||||||||||||||
2446 | continue; never executed: continue; | 0 | ||||||||||||||||||
2447 | - | |||||||||||||||||||
2448 | // To use negative variables inside simplex, we shift them so the minimum negative value is | - | ||||||||||||||||||
2449 | // mapped to zero before solving. To make sure that it works, we need to guarantee that the | - | ||||||||||||||||||
2450 | // variables are all inside a certain boundary. | - | ||||||||||||||||||
2451 | qreal boundedMin = qBound(-g_offset, ad->minSize, g_offset); | - | ||||||||||||||||||
2452 | qreal boundedMax = qBound(-g_offset, ad->maxSize, g_offset); | - | ||||||||||||||||||
2453 | - | |||||||||||||||||||
2454 | if ((boundedMin == boundedMax) || qFuzzyCompare(boundedMin, boundedMax)) {
| 0 | ||||||||||||||||||
2455 | QSimplexConstraint *c = new QSimplexConstraint; | - | ||||||||||||||||||
2456 | c->variables.insert(ad, 1.0); | - | ||||||||||||||||||
2457 | c->constant = boundedMin; | - | ||||||||||||||||||
2458 | c->ratio = QSimplexConstraint::Equal; | - | ||||||||||||||||||
2459 | anchorConstraints += c; | - | ||||||||||||||||||
2460 | unboundedProblem = false; | - | ||||||||||||||||||
2461 | } else { never executed: end of block | 0 | ||||||||||||||||||
2462 | QSimplexConstraint *c = new QSimplexConstraint; | - | ||||||||||||||||||
2463 | c->variables.insert(ad, 1.0); | - | ||||||||||||||||||
2464 | c->constant = boundedMin; | - | ||||||||||||||||||
2465 | c->ratio = QSimplexConstraint::MoreOrEqual; | - | ||||||||||||||||||
2466 | anchorConstraints += c; | - | ||||||||||||||||||
2467 | - | |||||||||||||||||||
2468 | // We avoid adding restrictions to the layout internal anchors. That's | - | ||||||||||||||||||
2469 | // to prevent unnecessary fair distribution from happening due to this | - | ||||||||||||||||||
2470 | // artificial restriction. | - | ||||||||||||||||||
2471 | if (ad == layoutEdge)
| 0 | ||||||||||||||||||
2472 | continue; never executed: continue; | 0 | ||||||||||||||||||
2473 | - | |||||||||||||||||||
2474 | c = new QSimplexConstraint; | - | ||||||||||||||||||
2475 | c->variables.insert(ad, 1.0); | - | ||||||||||||||||||
2476 | c->constant = boundedMax; | - | ||||||||||||||||||
2477 | c->ratio = QSimplexConstraint::LessOrEqual; | - | ||||||||||||||||||
2478 | anchorConstraints += c; | - | ||||||||||||||||||
2479 | unboundedProblem = false; | - | ||||||||||||||||||
2480 | } never executed: end of block | 0 | ||||||||||||||||||
2481 | } | - | ||||||||||||||||||
2482 | - | |||||||||||||||||||
2483 | // If no upper boundary restriction was added, add one to avoid unbounded problem | - | ||||||||||||||||||
2484 | if (unboundedProblem) {
| 0 | ||||||||||||||||||
2485 | QSimplexConstraint *c = new QSimplexConstraint; | - | ||||||||||||||||||
2486 | c->variables.insert(layoutEdge, 1.0); | - | ||||||||||||||||||
2487 | // The maximum size that the layout can take | - | ||||||||||||||||||
2488 | c->constant = g_offset; | - | ||||||||||||||||||
2489 | c->ratio = QSimplexConstraint::LessOrEqual; | - | ||||||||||||||||||
2490 | anchorConstraints += c; | - | ||||||||||||||||||
2491 | } never executed: end of block | 0 | ||||||||||||||||||
2492 | - | |||||||||||||||||||
2493 | return anchorConstraints; never executed: return anchorConstraints; | 0 | ||||||||||||||||||
2494 | } | - | ||||||||||||||||||
2495 | - | |||||||||||||||||||
2496 | /*! | - | ||||||||||||||||||
2497 | \internal | - | ||||||||||||||||||
2498 | */ | - | ||||||||||||||||||
2499 | QList< QList<QSimplexConstraint *> > | - | ||||||||||||||||||
2500 | QGraphicsAnchorLayoutPrivate::getGraphParts(Orientation orientation) | - | ||||||||||||||||||
2501 | { | - | ||||||||||||||||||
2502 | Q_ASSERT(layoutFirstVertex[orientation] && layoutLastVertex[orientation]); | - | ||||||||||||||||||
2503 | - | |||||||||||||||||||
2504 | AnchorData *edgeL1 = 0; | - | ||||||||||||||||||
2505 | AnchorData *edgeL2 = 0; | - | ||||||||||||||||||
2506 | - | |||||||||||||||||||
2507 | // The layout may have a single anchor between Left and Right or two half anchors | - | ||||||||||||||||||
2508 | // passing through the center | - | ||||||||||||||||||
2509 | if (layoutCentralVertex[orientation]) {
| 0 | ||||||||||||||||||
2510 | edgeL1 = graph[orientation].edgeData(layoutFirstVertex[orientation], layoutCentralVertex[orientation]); | - | ||||||||||||||||||
2511 | edgeL2 = graph[orientation].edgeData(layoutCentralVertex[orientation], layoutLastVertex[orientation]); | - | ||||||||||||||||||
2512 | } else { never executed: end of block | 0 | ||||||||||||||||||
2513 | edgeL1 = graph[orientation].edgeData(layoutFirstVertex[orientation], layoutLastVertex[orientation]); | - | ||||||||||||||||||
2514 | } never executed: end of block | 0 | ||||||||||||||||||
2515 | - | |||||||||||||||||||
2516 | QLinkedList<QSimplexConstraint *> remainingConstraints; | - | ||||||||||||||||||
2517 | for (int i = 0; i < constraints[orientation].count(); ++i) {
| 0 | ||||||||||||||||||
2518 | remainingConstraints += constraints[orientation].at(i); | - | ||||||||||||||||||
2519 | } never executed: end of block | 0 | ||||||||||||||||||
2520 | for (int i = 0; i < itemCenterConstraints[orientation].count(); ++i) {
| 0 | ||||||||||||||||||
2521 | remainingConstraints += itemCenterConstraints[orientation].at(i); | - | ||||||||||||||||||
2522 | } never executed: end of block | 0 | ||||||||||||||||||
2523 | - | |||||||||||||||||||
2524 | QList<QSimplexConstraint *> trunkConstraints; | - | ||||||||||||||||||
2525 | QSet<QSimplexVariable *> trunkVariables; | - | ||||||||||||||||||
2526 | - | |||||||||||||||||||
2527 | trunkVariables += edgeL1; | - | ||||||||||||||||||
2528 | if (edgeL2)
| 0 | ||||||||||||||||||
2529 | trunkVariables += edgeL2; never executed: trunkVariables += edgeL2; | 0 | ||||||||||||||||||
2530 | - | |||||||||||||||||||
2531 | bool dirty; | - | ||||||||||||||||||
2532 | do { | - | ||||||||||||||||||
2533 | dirty = false; | - | ||||||||||||||||||
2534 | - | |||||||||||||||||||
2535 | QLinkedList<QSimplexConstraint *>::iterator it = remainingConstraints.begin(); | - | ||||||||||||||||||
2536 | while (it != remainingConstraints.end()) {
| 0 | ||||||||||||||||||
2537 | QSimplexConstraint *c = *it; | - | ||||||||||||||||||
2538 | bool match = false; | - | ||||||||||||||||||
2539 | - | |||||||||||||||||||
2540 | // Check if this constraint have some overlap with current | - | ||||||||||||||||||
2541 | // trunk variables... | - | ||||||||||||||||||
2542 | foreach (QSimplexVariable *ad, trunkVariables) { | - | ||||||||||||||||||
2543 | if (c->variables.contains(ad)) {
| 0 | ||||||||||||||||||
2544 | match = true; | - | ||||||||||||||||||
2545 | break; never executed: break; | 0 | ||||||||||||||||||
2546 | } | - | ||||||||||||||||||
2547 | } never executed: end of block | 0 | ||||||||||||||||||
2548 | - | |||||||||||||||||||
2549 | // If so, we add it to trunk, and erase it from the | - | ||||||||||||||||||
2550 | // remaining constraints. | - | ||||||||||||||||||
2551 | if (match) {
| 0 | ||||||||||||||||||
2552 | trunkConstraints += c; | - | ||||||||||||||||||
2553 | trunkVariables += QSet<QSimplexVariable *>::fromList(c->variables.keys()); | - | ||||||||||||||||||
2554 | it = remainingConstraints.erase(it); | - | ||||||||||||||||||
2555 | dirty = true; | - | ||||||||||||||||||
2556 | } else { never executed: end of block | 0 | ||||||||||||||||||
2557 | // Note that we don't erase the constraint if it's not | - | ||||||||||||||||||
2558 | // a match, since in a next iteration of a do-while we | - | ||||||||||||||||||
2559 | // can pass on it again and it will be a match. | - | ||||||||||||||||||
2560 | // | - | ||||||||||||||||||
2561 | // For example: if trunk share a variable with | - | ||||||||||||||||||
2562 | // remainingConstraints[1] and it shares with | - | ||||||||||||||||||
2563 | // remainingConstraints[0], we need a second iteration | - | ||||||||||||||||||
2564 | // of the do-while loop to match both. | - | ||||||||||||||||||
2565 | ++it; | - | ||||||||||||||||||
2566 | } never executed: end of block | 0 | ||||||||||||||||||
2567 | } | - | ||||||||||||||||||
2568 | } while (dirty); never executed: end of block
| 0 | ||||||||||||||||||
2569 | - | |||||||||||||||||||
2570 | QList< QList<QSimplexConstraint *> > result; | - | ||||||||||||||||||
2571 | result += trunkConstraints; | - | ||||||||||||||||||
2572 | - | |||||||||||||||||||
2573 | if (!remainingConstraints.isEmpty()) {
| 0 | ||||||||||||||||||
2574 | QList<QSimplexConstraint *> nonTrunkConstraints; | - | ||||||||||||||||||
2575 | nonTrunkConstraints.reserve(remainingConstraints.size()); | - | ||||||||||||||||||
2576 | QLinkedList<QSimplexConstraint *>::iterator it = remainingConstraints.begin(); | - | ||||||||||||||||||
2577 | while (it != remainingConstraints.end()) {
| 0 | ||||||||||||||||||
2578 | nonTrunkConstraints += *it; | - | ||||||||||||||||||
2579 | ++it; | - | ||||||||||||||||||
2580 | } never executed: end of block | 0 | ||||||||||||||||||
2581 | result += nonTrunkConstraints; | - | ||||||||||||||||||
2582 | } never executed: end of block | 0 | ||||||||||||||||||
2583 | - | |||||||||||||||||||
2584 | return result; never executed: return result; | 0 | ||||||||||||||||||
2585 | } | - | ||||||||||||||||||
2586 | - | |||||||||||||||||||
2587 | /*! | - | ||||||||||||||||||
2588 | \internal | - | ||||||||||||||||||
2589 | - | |||||||||||||||||||
2590 | Use all visited Anchors on findPaths() so we can identify non-float Items. | - | ||||||||||||||||||
2591 | */ | - | ||||||||||||||||||
2592 | void QGraphicsAnchorLayoutPrivate::identifyFloatItems(const QSet<AnchorData *> &visited, Orientation orientation) | - | ||||||||||||||||||
2593 | { | - | ||||||||||||||||||
2594 | QSet<QGraphicsLayoutItem *> nonFloating; | - | ||||||||||||||||||
2595 | - | |||||||||||||||||||
2596 | foreach (const AnchorData *ad, visited) | - | ||||||||||||||||||
2597 | identifyNonFloatItems_helper(ad, &nonFloating); never executed: identifyNonFloatItems_helper(ad, &nonFloating); | 0 | ||||||||||||||||||
2598 | - | |||||||||||||||||||
2599 | QSet<QGraphicsLayoutItem *> allItems; | - | ||||||||||||||||||
2600 | foreach (QGraphicsLayoutItem *item, items) | - | ||||||||||||||||||
2601 | allItems.insert(item); never executed: allItems.insert(item); | 0 | ||||||||||||||||||
2602 | m_floatItems[orientation] = allItems - nonFloating; | - | ||||||||||||||||||
2603 | } never executed: end of block | 0 | ||||||||||||||||||
2604 | - | |||||||||||||||||||
2605 | - | |||||||||||||||||||
2606 | /*! | - | ||||||||||||||||||
2607 | \internal | - | ||||||||||||||||||
2608 | - | |||||||||||||||||||
2609 | Given an anchor, if it is an internal anchor and Normal we must mark it's item as non-float. | - | ||||||||||||||||||
2610 | If the anchor is Sequential or Parallel, we must iterate on its children recursively until we reach | - | ||||||||||||||||||
2611 | internal anchors (items). | - | ||||||||||||||||||
2612 | */ | - | ||||||||||||||||||
2613 | void QGraphicsAnchorLayoutPrivate::identifyNonFloatItems_helper(const AnchorData *ad, QSet<QGraphicsLayoutItem *> *nonFloatingItemsIdentifiedSoFar) | - | ||||||||||||||||||
2614 | { | - | ||||||||||||||||||
2615 | Q_Q(QGraphicsAnchorLayout); | - | ||||||||||||||||||
2616 | - | |||||||||||||||||||
2617 | switch(ad->type) { | - | ||||||||||||||||||
2618 | case AnchorData::Normal: never executed: case AnchorData::Normal: | 0 | ||||||||||||||||||
2619 | if (ad->item && ad->item != q)
| 0 | ||||||||||||||||||
2620 | nonFloatingItemsIdentifiedSoFar->insert(ad->item); never executed: nonFloatingItemsIdentifiedSoFar->insert(ad->item); | 0 | ||||||||||||||||||
2621 | break; never executed: break; | 0 | ||||||||||||||||||
2622 | case AnchorData::Sequential: never executed: case AnchorData::Sequential: | 0 | ||||||||||||||||||
2623 | foreach (const AnchorData *d, static_cast<const SequentialAnchorData *>(ad)->m_edges) | - | ||||||||||||||||||
2624 | identifyNonFloatItems_helper(d, nonFloatingItemsIdentifiedSoFar); never executed: identifyNonFloatItems_helper(d, nonFloatingItemsIdentifiedSoFar); | 0 | ||||||||||||||||||
2625 | break; never executed: break; | 0 | ||||||||||||||||||
2626 | case AnchorData::Parallel: never executed: case AnchorData::Parallel: | 0 | ||||||||||||||||||
2627 | identifyNonFloatItems_helper(static_cast<const ParallelAnchorData *>(ad)->firstEdge, nonFloatingItemsIdentifiedSoFar); | - | ||||||||||||||||||
2628 | identifyNonFloatItems_helper(static_cast<const ParallelAnchorData *>(ad)->secondEdge, nonFloatingItemsIdentifiedSoFar); | - | ||||||||||||||||||
2629 | break; never executed: break; | 0 | ||||||||||||||||||
2630 | } | - | ||||||||||||||||||
2631 | } never executed: end of block | 0 | ||||||||||||||||||
2632 | - | |||||||||||||||||||
2633 | /*! | - | ||||||||||||||||||
2634 | \internal | - | ||||||||||||||||||
2635 | - | |||||||||||||||||||
2636 | Use the current vertices distance to calculate and set the geometry of | - | ||||||||||||||||||
2637 | each item. | - | ||||||||||||||||||
2638 | */ | - | ||||||||||||||||||
2639 | void QGraphicsAnchorLayoutPrivate::setItemsGeometries(const QRectF &geom) | - | ||||||||||||||||||
2640 | { | - | ||||||||||||||||||
2641 | Q_Q(QGraphicsAnchorLayout); | - | ||||||||||||||||||
2642 | AnchorVertex *firstH, *secondH, *firstV, *secondV; | - | ||||||||||||||||||
2643 | - | |||||||||||||||||||
2644 | qreal top; | - | ||||||||||||||||||
2645 | qreal left; | - | ||||||||||||||||||
2646 | qreal right; | - | ||||||||||||||||||
2647 | - | |||||||||||||||||||
2648 | q->getContentsMargins(&left, &top, &right, 0); | - | ||||||||||||||||||
2649 | const Qt::LayoutDirection visualDir = visualDirection(); | - | ||||||||||||||||||
2650 | if (visualDir == Qt::RightToLeft)
| 0 | ||||||||||||||||||
2651 | qSwap(left, right); never executed: qSwap(left, right); | 0 | ||||||||||||||||||
2652 | - | |||||||||||||||||||
2653 | left += geom.left(); | - | ||||||||||||||||||
2654 | top += geom.top(); | - | ||||||||||||||||||
2655 | right = geom.right() - right; | - | ||||||||||||||||||
2656 | - | |||||||||||||||||||
2657 | foreach (QGraphicsLayoutItem *item, items) { | - | ||||||||||||||||||
2658 | QRectF newGeom; | - | ||||||||||||||||||
2659 | QSizeF itemPreferredSize = item->effectiveSizeHint(Qt::PreferredSize); | - | ||||||||||||||||||
2660 | if (m_floatItems[Horizontal].contains(item)) {
| 0 | ||||||||||||||||||
2661 | newGeom.setLeft(0); | - | ||||||||||||||||||
2662 | newGeom.setRight(itemPreferredSize.width()); | - | ||||||||||||||||||
2663 | } else { never executed: end of block | 0 | ||||||||||||||||||
2664 | firstH = internalVertex(item, Qt::AnchorLeft); | - | ||||||||||||||||||
2665 | secondH = internalVertex(item, Qt::AnchorRight); | - | ||||||||||||||||||
2666 | - | |||||||||||||||||||
2667 | if (visualDir == Qt::LeftToRight) {
| 0 | ||||||||||||||||||
2668 | newGeom.setLeft(left + firstH->distance); | - | ||||||||||||||||||
2669 | newGeom.setRight(left + secondH->distance); | - | ||||||||||||||||||
2670 | } else { never executed: end of block | 0 | ||||||||||||||||||
2671 | newGeom.setLeft(right - secondH->distance); | - | ||||||||||||||||||
2672 | newGeom.setRight(right - firstH->distance); | - | ||||||||||||||||||
2673 | } never executed: end of block | 0 | ||||||||||||||||||
2674 | } | - | ||||||||||||||||||
2675 | - | |||||||||||||||||||
2676 | if (m_floatItems[Vertical].contains(item)) {
| 0 | ||||||||||||||||||
2677 | newGeom.setTop(0); | - | ||||||||||||||||||
2678 | newGeom.setBottom(itemPreferredSize.height()); | - | ||||||||||||||||||
2679 | } else { never executed: end of block | 0 | ||||||||||||||||||
2680 | firstV = internalVertex(item, Qt::AnchorTop); | - | ||||||||||||||||||
2681 | secondV = internalVertex(item, Qt::AnchorBottom); | - | ||||||||||||||||||
2682 | - | |||||||||||||||||||
2683 | newGeom.setTop(top + firstV->distance); | - | ||||||||||||||||||
2684 | newGeom.setBottom(top + secondV->distance); | - | ||||||||||||||||||
2685 | } never executed: end of block | 0 | ||||||||||||||||||
2686 | - | |||||||||||||||||||
2687 | item->setGeometry(newGeom); | - | ||||||||||||||||||
2688 | } never executed: end of block | 0 | ||||||||||||||||||
2689 | } never executed: end of block | 0 | ||||||||||||||||||
2690 | - | |||||||||||||||||||
2691 | /*! | - | ||||||||||||||||||
2692 | \internal | - | ||||||||||||||||||
2693 | - | |||||||||||||||||||
2694 | Calculate the position of each vertex based on the paths to each of | - | ||||||||||||||||||
2695 | them as well as the current edges sizes. | - | ||||||||||||||||||
2696 | */ | - | ||||||||||||||||||
2697 | void QGraphicsAnchorLayoutPrivate::calculateVertexPositions( | - | ||||||||||||||||||
2698 | QGraphicsAnchorLayoutPrivate::Orientation orientation) | - | ||||||||||||||||||
2699 | { | - | ||||||||||||||||||
2700 | QQueue<QPair<AnchorVertex *, AnchorVertex *> > queue; | - | ||||||||||||||||||
2701 | QSet<AnchorVertex *> visited; | - | ||||||||||||||||||
2702 | - | |||||||||||||||||||
2703 | // Get root vertex | - | ||||||||||||||||||
2704 | AnchorVertex *root = layoutFirstVertex[orientation]; | - | ||||||||||||||||||
2705 | - | |||||||||||||||||||
2706 | root->distance = 0; | - | ||||||||||||||||||
2707 | visited.insert(root); | - | ||||||||||||||||||
2708 | - | |||||||||||||||||||
2709 | // Add initial edges to the queue | - | ||||||||||||||||||
2710 | foreach (AnchorVertex *v, graph[orientation].adjacentVertices(root)) { | - | ||||||||||||||||||
2711 | queue.enqueue(qMakePair(root, v)); | - | ||||||||||||||||||
2712 | } never executed: end of block | 0 | ||||||||||||||||||
2713 | - | |||||||||||||||||||
2714 | // Do initial calculation required by "interpolateEdge()" | - | ||||||||||||||||||
2715 | setupEdgesInterpolation(orientation); | - | ||||||||||||||||||
2716 | - | |||||||||||||||||||
2717 | // Traverse the graph and calculate vertex positions | - | ||||||||||||||||||
2718 | while (!queue.isEmpty()) {
| 0 | ||||||||||||||||||
2719 | QPair<AnchorVertex *, AnchorVertex *> pair = queue.dequeue(); | - | ||||||||||||||||||
2720 | AnchorData *edge = graph[orientation].edgeData(pair.first, pair.second); | - | ||||||||||||||||||
2721 | - | |||||||||||||||||||
2722 | if (visited.contains(pair.second))
| 0 | ||||||||||||||||||
2723 | continue; never executed: continue; | 0 | ||||||||||||||||||
2724 | - | |||||||||||||||||||
2725 | visited.insert(pair.second); | - | ||||||||||||||||||
2726 | interpolateEdge(pair.first, edge); | - | ||||||||||||||||||
2727 | - | |||||||||||||||||||
2728 | QList<AnchorVertex *> adjacents = graph[orientation].adjacentVertices(pair.second); | - | ||||||||||||||||||
2729 | for (int i = 0; i < adjacents.count(); ++i) {
| 0 | ||||||||||||||||||
2730 | if (!visited.contains(adjacents.at(i)))
| 0 | ||||||||||||||||||
2731 | queue.enqueue(qMakePair(pair.second, adjacents.at(i))); never executed: queue.enqueue(qMakePair(pair.second, adjacents.at(i))); | 0 | ||||||||||||||||||
2732 | } never executed: end of block | 0 | ||||||||||||||||||
2733 | } never executed: end of block | 0 | ||||||||||||||||||
2734 | } never executed: end of block | 0 | ||||||||||||||||||
2735 | - | |||||||||||||||||||
2736 | /*! | - | ||||||||||||||||||
2737 | \internal | - | ||||||||||||||||||
2738 | - | |||||||||||||||||||
2739 | Calculate interpolation parameters based on current Layout Size. | - | ||||||||||||||||||
2740 | Must be called once before calling "interpolateEdgeSize()" for | - | ||||||||||||||||||
2741 | the edges. | - | ||||||||||||||||||
2742 | */ | - | ||||||||||||||||||
2743 | void QGraphicsAnchorLayoutPrivate::setupEdgesInterpolation( | - | ||||||||||||||||||
2744 | Orientation orientation) | - | ||||||||||||||||||
2745 | { | - | ||||||||||||||||||
2746 | Q_Q(QGraphicsAnchorLayout); | - | ||||||||||||||||||
2747 | - | |||||||||||||||||||
2748 | qreal current; | - | ||||||||||||||||||
2749 | current = (orientation == Horizontal) ? q->contentsRect().width() : q->contentsRect().height();
| 0 | ||||||||||||||||||
2750 | - | |||||||||||||||||||
2751 | QPair<Interval, qreal> result; | - | ||||||||||||||||||
2752 | result = getFactor(current, | - | ||||||||||||||||||
2753 | sizeHints[orientation][Qt::MinimumSize], | - | ||||||||||||||||||
2754 | sizeHints[orientation][Qt::PreferredSize], | - | ||||||||||||||||||
2755 | sizeHints[orientation][Qt::PreferredSize], | - | ||||||||||||||||||
2756 | sizeHints[orientation][Qt::PreferredSize], | - | ||||||||||||||||||
2757 | sizeHints[orientation][Qt::MaximumSize]); | - | ||||||||||||||||||
2758 | - | |||||||||||||||||||
2759 | interpolationInterval[orientation] = result.first; | - | ||||||||||||||||||
2760 | interpolationProgress[orientation] = result.second; | - | ||||||||||||||||||
2761 | } never executed: end of block | 0 | ||||||||||||||||||
2762 | - | |||||||||||||||||||
2763 | /*! | - | ||||||||||||||||||
2764 | \internal | - | ||||||||||||||||||
2765 | - | |||||||||||||||||||
2766 | Calculate the current Edge size based on the current Layout size and the | - | ||||||||||||||||||
2767 | size the edge is supposed to have when the layout is at its: | - | ||||||||||||||||||
2768 | - | |||||||||||||||||||
2769 | - minimum size, | - | ||||||||||||||||||
2770 | - preferred size, | - | ||||||||||||||||||
2771 | - maximum size. | - | ||||||||||||||||||
2772 | - | |||||||||||||||||||
2773 | These three key values are calculated in advance using linear | - | ||||||||||||||||||
2774 | programming (more expensive) or the simplification algorithm, then | - | ||||||||||||||||||
2775 | subsequential resizes of the parent layout require a simple | - | ||||||||||||||||||
2776 | interpolation. | - | ||||||||||||||||||
2777 | */ | - | ||||||||||||||||||
2778 | void QGraphicsAnchorLayoutPrivate::interpolateEdge(AnchorVertex *base, AnchorData *edge) | - | ||||||||||||||||||
2779 | { | - | ||||||||||||||||||
2780 | const Orientation orientation = Orientation(edge->orientation); | - | ||||||||||||||||||
2781 | const QPair<Interval, qreal> factor(interpolationInterval[orientation], | - | ||||||||||||||||||
2782 | interpolationProgress[orientation]); | - | ||||||||||||||||||
2783 | - | |||||||||||||||||||
2784 | qreal edgeDistance = interpolate(factor, edge->sizeAtMinimum, edge->sizeAtPreferred, | - | ||||||||||||||||||
2785 | edge->sizeAtPreferred, edge->sizeAtPreferred, | - | ||||||||||||||||||
2786 | edge->sizeAtMaximum); | - | ||||||||||||||||||
2787 | - | |||||||||||||||||||
2788 | Q_ASSERT(edge->from == base || edge->to == base); | - | ||||||||||||||||||
2789 | - | |||||||||||||||||||
2790 | // Calculate the distance for the vertex opposite to the base | - | ||||||||||||||||||
2791 | if (edge->from == base) {
| 0 | ||||||||||||||||||
2792 | edge->to->distance = base->distance + edgeDistance; | - | ||||||||||||||||||
2793 | } else { never executed: end of block | 0 | ||||||||||||||||||
2794 | edge->from->distance = base->distance - edgeDistance; | - | ||||||||||||||||||
2795 | } never executed: end of block | 0 | ||||||||||||||||||
2796 | } | - | ||||||||||||||||||
2797 | - | |||||||||||||||||||
2798 | bool QGraphicsAnchorLayoutPrivate::solveMinMax(const QList<QSimplexConstraint *> &constraints, | - | ||||||||||||||||||
2799 | GraphPath path, qreal *min, qreal *max) | - | ||||||||||||||||||
2800 | { | - | ||||||||||||||||||
2801 | QSimplex simplex; | - | ||||||||||||||||||
2802 | bool feasible = simplex.setConstraints(constraints); | - | ||||||||||||||||||
2803 | if (feasible) {
| 0 | ||||||||||||||||||
2804 | // Obtain the objective constraint | - | ||||||||||||||||||
2805 | QSimplexConstraint objective; | - | ||||||||||||||||||
2806 | QSet<AnchorData *>::const_iterator iter; | - | ||||||||||||||||||
2807 | for (iter = path.positives.constBegin(); iter != path.positives.constEnd(); ++iter)
| 0 | ||||||||||||||||||
2808 | objective.variables.insert(*iter, 1.0); never executed: objective.variables.insert(*iter, 1.0); | 0 | ||||||||||||||||||
2809 | - | |||||||||||||||||||
2810 | for (iter = path.negatives.constBegin(); iter != path.negatives.constEnd(); ++iter)
| 0 | ||||||||||||||||||
2811 | objective.variables.insert(*iter, -1.0); never executed: objective.variables.insert(*iter, -1.0); | 0 | ||||||||||||||||||
2812 | - | |||||||||||||||||||
2813 | const qreal objectiveOffset = (path.positives.count() - path.negatives.count()) * g_offset; | - | ||||||||||||||||||
2814 | simplex.setObjective(&objective); | - | ||||||||||||||||||
2815 | - | |||||||||||||||||||
2816 | // Calculate minimum values | - | ||||||||||||||||||
2817 | *min = simplex.solveMin() - objectiveOffset; | - | ||||||||||||||||||
2818 | - | |||||||||||||||||||
2819 | // Save sizeAtMinimum results | - | ||||||||||||||||||
2820 | QList<AnchorData *> variables = getVariables(constraints); | - | ||||||||||||||||||
2821 | for (int i = 0; i < variables.size(); ++i) {
| 0 | ||||||||||||||||||
2822 | AnchorData *ad = static_cast<AnchorData *>(variables.at(i)); | - | ||||||||||||||||||
2823 | ad->sizeAtMinimum = ad->result - g_offset; | - | ||||||||||||||||||
2824 | } never executed: end of block | 0 | ||||||||||||||||||
2825 | - | |||||||||||||||||||
2826 | // Calculate maximum values | - | ||||||||||||||||||
2827 | *max = simplex.solveMax() - objectiveOffset; | - | ||||||||||||||||||
2828 | - | |||||||||||||||||||
2829 | // Save sizeAtMaximum results | - | ||||||||||||||||||
2830 | for (int i = 0; i < variables.size(); ++i) {
| 0 | ||||||||||||||||||
2831 | AnchorData *ad = static_cast<AnchorData *>(variables.at(i)); | - | ||||||||||||||||||
2832 | ad->sizeAtMaximum = ad->result - g_offset; | - | ||||||||||||||||||
2833 | } never executed: end of block | 0 | ||||||||||||||||||
2834 | } never executed: end of block | 0 | ||||||||||||||||||
2835 | return feasible; never executed: return feasible; | 0 | ||||||||||||||||||
2836 | } | - | ||||||||||||||||||
2837 | - | |||||||||||||||||||
2838 | enum slackType { Grower = -1, Shrinker = 1 }; | - | ||||||||||||||||||
2839 | static QPair<QSimplexVariable *, QSimplexConstraint *> createSlack(QSimplexConstraint *sizeConstraint, | - | ||||||||||||||||||
2840 | qreal interval, slackType type) | - | ||||||||||||||||||
2841 | { | - | ||||||||||||||||||
2842 | QSimplexVariable *slack = new QSimplexVariable; | - | ||||||||||||||||||
2843 | sizeConstraint->variables.insert(slack, type); | - | ||||||||||||||||||
2844 | - | |||||||||||||||||||
2845 | QSimplexConstraint *limit = new QSimplexConstraint; | - | ||||||||||||||||||
2846 | limit->variables.insert(slack, 1.0); | - | ||||||||||||||||||
2847 | limit->ratio = QSimplexConstraint::LessOrEqual; | - | ||||||||||||||||||
2848 | limit->constant = interval; | - | ||||||||||||||||||
2849 | - | |||||||||||||||||||
2850 | return qMakePair(slack, limit); never executed: return qMakePair(slack, limit); | 0 | ||||||||||||||||||
2851 | } | - | ||||||||||||||||||
2852 | - | |||||||||||||||||||
2853 | bool QGraphicsAnchorLayoutPrivate::solvePreferred(const QList<QSimplexConstraint *> &constraints, | - | ||||||||||||||||||
2854 | const QList<AnchorData *> &variables) | - | ||||||||||||||||||
2855 | { | - | ||||||||||||||||||
2856 | QList<QSimplexConstraint *> preferredConstraints; | - | ||||||||||||||||||
2857 | QList<QSimplexVariable *> preferredVariables; | - | ||||||||||||||||||
2858 | QSimplexConstraint objective; | - | ||||||||||||||||||
2859 | - | |||||||||||||||||||
2860 | // Fill the objective coefficients for this variable. In the | - | ||||||||||||||||||
2861 | // end the objective function will be | - | ||||||||||||||||||
2862 | // | - | ||||||||||||||||||
2863 | // z = n * (A_shrinker_hard + A_grower_hard + B_shrinker_hard + B_grower_hard + ...) + | - | ||||||||||||||||||
2864 | // (A_shrinker_soft + A_grower_soft + B_shrinker_soft + B_grower_soft + ...) | - | ||||||||||||||||||
2865 | // | - | ||||||||||||||||||
2866 | // where n is the number of variables that have | - | ||||||||||||||||||
2867 | // slacks. Note that here we use the number of variables | - | ||||||||||||||||||
2868 | // as coefficient, this is to mark the "shrinker slack | - | ||||||||||||||||||
2869 | // variable" less likely to get value than the "grower | - | ||||||||||||||||||
2870 | // slack variable". | - | ||||||||||||||||||
2871 | - | |||||||||||||||||||
2872 | // This will fill the values for the structural constraints | - | ||||||||||||||||||
2873 | // and we now fill the values for the slack constraints (one per variable), | - | ||||||||||||||||||
2874 | // which have this form (the constant A_pref was set when creating the slacks): | - | ||||||||||||||||||
2875 | // | - | ||||||||||||||||||
2876 | // A + A_shrinker_hard + A_shrinker_soft - A_grower_hard - A_grower_soft = A_pref | - | ||||||||||||||||||
2877 | // | - | ||||||||||||||||||
2878 | for (int i = 0; i < variables.size(); ++i) {
| 0 | ||||||||||||||||||
2879 | AnchorData *ad = variables.at(i); | - | ||||||||||||||||||
2880 | - | |||||||||||||||||||
2881 | // The layout original structure anchors are not relevant in preferred size calculation | - | ||||||||||||||||||
2882 | if (ad->isLayoutAnchor)
| 0 | ||||||||||||||||||
2883 | continue; never executed: continue; | 0 | ||||||||||||||||||
2884 | - | |||||||||||||||||||
2885 | // By default, all variables are equal to their preferred size. If they have room to | - | ||||||||||||||||||
2886 | // grow or shrink, such flexibility will be added by the additional variables below. | - | ||||||||||||||||||
2887 | QSimplexConstraint *sizeConstraint = new QSimplexConstraint; | - | ||||||||||||||||||
2888 | preferredConstraints += sizeConstraint; | - | ||||||||||||||||||
2889 | sizeConstraint->variables.insert(ad, 1.0); | - | ||||||||||||||||||
2890 | sizeConstraint->constant = ad->prefSize + g_offset; | - | ||||||||||||||||||
2891 | - | |||||||||||||||||||
2892 | // Can easily shrink | - | ||||||||||||||||||
2893 | QPair<QSimplexVariable *, QSimplexConstraint *> slack; | - | ||||||||||||||||||
2894 | const qreal softShrinkInterval = ad->prefSize - ad->minPrefSize; | - | ||||||||||||||||||
2895 | if (softShrinkInterval) {
| 0 | ||||||||||||||||||
2896 | slack = createSlack(sizeConstraint, softShrinkInterval, Shrinker); | - | ||||||||||||||||||
2897 | preferredVariables += slack.first; | - | ||||||||||||||||||
2898 | preferredConstraints += slack.second; | - | ||||||||||||||||||
2899 | - | |||||||||||||||||||
2900 | // Add to objective with ratio == 1 (soft) | - | ||||||||||||||||||
2901 | objective.variables.insert(slack.first, 1.0); | - | ||||||||||||||||||
2902 | } never executed: end of block | 0 | ||||||||||||||||||
2903 | - | |||||||||||||||||||
2904 | // Can easily grow | - | ||||||||||||||||||
2905 | const qreal softGrowInterval = ad->maxPrefSize - ad->prefSize; | - | ||||||||||||||||||
2906 | if (softGrowInterval) {
| 0 | ||||||||||||||||||
2907 | slack = createSlack(sizeConstraint, softGrowInterval, Grower); | - | ||||||||||||||||||
2908 | preferredVariables += slack.first; | - | ||||||||||||||||||
2909 | preferredConstraints += slack.second; | - | ||||||||||||||||||
2910 | - | |||||||||||||||||||
2911 | // Add to objective with ratio == 1 (soft) | - | ||||||||||||||||||
2912 | objective.variables.insert(slack.first, 1.0); | - | ||||||||||||||||||
2913 | } never executed: end of block | 0 | ||||||||||||||||||
2914 | - | |||||||||||||||||||
2915 | // Can shrink if really necessary | - | ||||||||||||||||||
2916 | const qreal hardShrinkInterval = ad->minPrefSize - ad->minSize; | - | ||||||||||||||||||
2917 | if (hardShrinkInterval) {
| 0 | ||||||||||||||||||
2918 | slack = createSlack(sizeConstraint, hardShrinkInterval, Shrinker); | - | ||||||||||||||||||
2919 | preferredVariables += slack.first; | - | ||||||||||||||||||
2920 | preferredConstraints += slack.second; | - | ||||||||||||||||||
2921 | - | |||||||||||||||||||
2922 | // Add to objective with ratio == N (hard) | - | ||||||||||||||||||
2923 | objective.variables.insert(slack.first, variables.size()); | - | ||||||||||||||||||
2924 | } never executed: end of block | 0 | ||||||||||||||||||
2925 | - | |||||||||||||||||||
2926 | // Can grow if really necessary | - | ||||||||||||||||||
2927 | const qreal hardGrowInterval = ad->maxSize - ad->maxPrefSize; | - | ||||||||||||||||||
2928 | if (hardGrowInterval) {
| 0 | ||||||||||||||||||
2929 | slack = createSlack(sizeConstraint, hardGrowInterval, Grower); | - | ||||||||||||||||||
2930 | preferredVariables += slack.first; | - | ||||||||||||||||||
2931 | preferredConstraints += slack.second; | - | ||||||||||||||||||
2932 | - | |||||||||||||||||||
2933 | // Add to objective with ratio == N (hard) | - | ||||||||||||||||||
2934 | objective.variables.insert(slack.first, variables.size()); | - | ||||||||||||||||||
2935 | } never executed: end of block | 0 | ||||||||||||||||||
2936 | } never executed: end of block | 0 | ||||||||||||||||||
2937 | - | |||||||||||||||||||
2938 | QSimplex *simplex = new QSimplex; | - | ||||||||||||||||||
2939 | bool feasible = simplex->setConstraints(constraints + preferredConstraints); | - | ||||||||||||||||||
2940 | if (feasible) {
| 0 | ||||||||||||||||||
2941 | simplex->setObjective(&objective); | - | ||||||||||||||||||
2942 | - | |||||||||||||||||||
2943 | // Calculate minimum values | - | ||||||||||||||||||
2944 | simplex->solveMin(); | - | ||||||||||||||||||
2945 | - | |||||||||||||||||||
2946 | // Save sizeAtPreferred results | - | ||||||||||||||||||
2947 | for (int i = 0; i < variables.size(); ++i) {
| 0 | ||||||||||||||||||
2948 | AnchorData *ad = variables.at(i); | - | ||||||||||||||||||
2949 | ad->sizeAtPreferred = ad->result - g_offset; | - | ||||||||||||||||||
2950 | } never executed: end of block | 0 | ||||||||||||||||||
2951 | } never executed: end of block | 0 | ||||||||||||||||||
2952 | - | |||||||||||||||||||
2953 | // Make sure we delete the simplex solver -before- we delete the | - | ||||||||||||||||||
2954 | // constraints used by it. | - | ||||||||||||||||||
2955 | delete simplex; | - | ||||||||||||||||||
2956 | - | |||||||||||||||||||
2957 | // Delete constraints and variables we created. | - | ||||||||||||||||||
2958 | qDeleteAll(preferredConstraints); | - | ||||||||||||||||||
2959 | qDeleteAll(preferredVariables); | - | ||||||||||||||||||
2960 | - | |||||||||||||||||||
2961 | return feasible; never executed: return feasible; | 0 | ||||||||||||||||||
2962 | } | - | ||||||||||||||||||
2963 | - | |||||||||||||||||||
2964 | /*! | - | ||||||||||||||||||
2965 | \internal | - | ||||||||||||||||||
2966 | Returns \c true if there are no arrangement that satisfies all constraints. | - | ||||||||||||||||||
2967 | Otherwise returns \c false. | - | ||||||||||||||||||
2968 | - | |||||||||||||||||||
2969 | \sa addAnchor() | - | ||||||||||||||||||
2970 | */ | - | ||||||||||||||||||
2971 | bool QGraphicsAnchorLayoutPrivate::hasConflicts() const | - | ||||||||||||||||||
2972 | { | - | ||||||||||||||||||
2973 | QGraphicsAnchorLayoutPrivate *that = const_cast<QGraphicsAnchorLayoutPrivate*>(this); | - | ||||||||||||||||||
2974 | that->calculateGraphs(); | - | ||||||||||||||||||
2975 | - | |||||||||||||||||||
2976 | bool floatConflict = !m_floatItems[0].isEmpty() || !m_floatItems[1].isEmpty();
| 0 | ||||||||||||||||||
2977 | - | |||||||||||||||||||
2978 | return graphHasConflicts[0] || graphHasConflicts[1] || floatConflict; never executed: return graphHasConflicts[0] || graphHasConflicts[1] || floatConflict;
| 0 | ||||||||||||||||||
2979 | } | - | ||||||||||||||||||
2980 | - | |||||||||||||||||||
2981 | #ifdef QT_DEBUG | - | ||||||||||||||||||
2982 | void QGraphicsAnchorLayoutPrivate::dumpGraph(const QString &name) | - | ||||||||||||||||||
2983 | { | - | ||||||||||||||||||
2984 | QFile file(QString::fromLatin1("anchorlayout.%1.dot").arg(name)); | - | ||||||||||||||||||
2985 | if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
| 0 | ||||||||||||||||||
2986 | qWarning("Could not write to %s", file.fileName().toLocal8Bit().constData()); never executed: QMessageLogger(__FILE__, 2986, __PRETTY_FUNCTION__).warning("Could not write to %s", file.fileName().toLocal8Bit().constData()); | 0 | ||||||||||||||||||
2987 | - | |||||||||||||||||||
2988 | QString str = QString::fromLatin1("digraph anchorlayout {\nnode [shape=\"rect\"]\n%1}"); | - | ||||||||||||||||||
2989 | QString dotContents = graph[0].serializeToDot(); | - | ||||||||||||||||||
2990 | dotContents += graph[1].serializeToDot(); | - | ||||||||||||||||||
2991 | file.write(str.arg(dotContents).toLocal8Bit()); | - | ||||||||||||||||||
2992 | - | |||||||||||||||||||
2993 | file.close(); | - | ||||||||||||||||||
2994 | } never executed: end of block | 0 | ||||||||||||||||||
2995 | #endif | - | ||||||||||||||||||
2996 | - | |||||||||||||||||||
2997 | QT_END_NAMESPACE | - | ||||||||||||||||||
2998 | #endif //QT_NO_GRAPHICSVIEW | - | ||||||||||||||||||
Source code | Switch to Preprocessed file |