Changeset View
Changeset View
Standalone View
Standalone View
components/containmentlayoutmanager/gridlayoutmanager.cpp
- This file was added.
1 | /* | ||||
---|---|---|---|---|---|
2 | * Copyright 2019 by Marco Martin <mart@kde.org> | ||||
3 | * | ||||
4 | * This program is free software; you can redistribute it and/or modify | ||||
5 | * it under the terms of the GNU Library General Public License as | ||||
6 | * published by the Free Software Foundation; either version 2, or | ||||
7 | * (at your option) any later version. | ||||
8 | * | ||||
9 | * This program is distributed in the hope that it will be useful, | ||||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
12 | * GNU Library General Public License for more details | ||||
13 | * | ||||
14 | * You should have received a copy of the GNU Library General Public | ||||
15 | * License along with this program; if not, write to the | ||||
16 | * Free Software Foundation, Inc., | ||||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
18 | * | ||||
19 | */ | ||||
20 | | ||||
21 | #include "gridlayoutmanager.h" | ||||
22 | #include "appletslayout.h" | ||||
23 | #include <cmath> | ||||
24 | | ||||
25 | GridLayoutManager::GridLayoutManager(AppletsLayout *layout) | ||||
26 | : AbstractLayoutManager(layout) | ||||
27 | { | ||||
28 | } | ||||
29 | | ||||
30 | GridLayoutManager::~GridLayoutManager() | ||||
31 | { | ||||
32 | } | ||||
33 | | ||||
34 | QString GridLayoutManager::serializeLayout() const | ||||
35 | { | ||||
36 | QString result; | ||||
37 | | ||||
38 | for (auto *item : layout()->childItems()) { | ||||
39 | ItemContainer *itemCont = qobject_cast<ItemContainer*>(item); | ||||
40 | if (itemCont && itemCont != layout()->placeHolder()) { | ||||
41 | result += itemCont->key() + QLatin1Char(':') | ||||
42 | + QString::number(itemCont->x()) + QLatin1Char(',') | ||||
43 | + QString::number(itemCont->y()) + QLatin1Char(',') | ||||
44 | + QString::number(itemCont->width()) + QLatin1Char(',') | ||||
45 | + QString::number(itemCont->height()) + QLatin1Char(',') | ||||
46 | + QString::number(itemCont->rotation()) + QLatin1Char(';'); | ||||
47 | } | ||||
48 | } | ||||
49 | | ||||
50 | return result; | ||||
51 | } | ||||
52 | | ||||
53 | void GridLayoutManager::parseLayout(const QString &savedLayout) | ||||
54 | { | ||||
55 | m_parsedConfig.clear(); | ||||
56 | QStringList itemsConfigs = savedLayout.split(QLatin1Char(';')); | ||||
57 | | ||||
58 | for (const auto &itemString : itemsConfigs) { | ||||
59 | QStringList itemConfig = itemString.split(QLatin1Char(':')); | ||||
60 | if (itemConfig.count() != 2) { | ||||
61 | continue; | ||||
62 | } | ||||
63 | | ||||
64 | QString id = itemConfig[0]; | ||||
65 | QStringList itemGeom = itemConfig[1].split(QLatin1Char(',')); | ||||
66 | if (itemGeom.count() != 5) { | ||||
67 | continue; | ||||
68 | } | ||||
69 | | ||||
70 | m_parsedConfig[id] = {itemGeom[0].toInt(), itemGeom[1].toInt(), itemGeom[2].toInt(), itemGeom[3].toInt(), itemGeom[4].toInt()}; | ||||
71 | } | ||||
72 | } | ||||
73 | | ||||
74 | bool GridLayoutManager::itemIsManaged(ItemContainer *item) | ||||
75 | { | ||||
76 | return m_pointsForItem.contains(item); | ||||
77 | } | ||||
78 | | ||||
79 | inline void maintainItemEdgeAlignment(QQuickItem *item, const QRectF &newRect, const QRectF &oldRect) | ||||
80 | { | ||||
81 | const qreal leftDist = item->x() - oldRect.x(); | ||||
82 | const qreal hCenterDist = item->x() + item->width()/2 - oldRect.center().x(); | ||||
83 | const qreal rightDist = oldRect.right() - item->x() - item->width(); | ||||
84 | | ||||
85 | qreal hMin = qMin(qMin(qAbs(leftDist), qAbs(hCenterDist)), qAbs(rightDist)); | ||||
86 | if (qFuzzyCompare(hMin, qAbs(leftDist))) { | ||||
87 | // Right alignment, do nothing | ||||
88 | } else if (qFuzzyCompare(hMin, qAbs(hCenterDist))) { | ||||
89 | item->setX(newRect.center().x() - item->width()/2 + hCenterDist); | ||||
90 | } else if (qFuzzyCompare(hMin, qAbs(rightDist))) { | ||||
91 | item->setX(newRect.right() - item->width() - rightDist ); | ||||
92 | } | ||||
93 | | ||||
94 | const qreal topDist = item->y() - oldRect.y(); | ||||
95 | const qreal vCenterDist = item->y() + item->height()/2 - oldRect.center().y(); | ||||
96 | const qreal bottomDist = oldRect.bottom() - item->y() - item->height(); | ||||
97 | | ||||
98 | qreal vMin = qMin(qMin(qAbs(topDist), qAbs(vCenterDist)), qAbs(bottomDist)); | ||||
99 | | ||||
100 | if (qFuzzyCompare(vMin, qAbs(topDist))) { | ||||
101 | // Top alignment, do nothing | ||||
102 | } else if (qFuzzyCompare(vMin, qAbs(vCenterDist))) { | ||||
103 | item->setY(newRect.center().y() - item->height()/2 + vCenterDist); | ||||
104 | } else if (qFuzzyCompare(vMin, qAbs(bottomDist))) { | ||||
105 | item->setY(newRect.bottom() - item->height() - bottomDist ); | ||||
106 | } | ||||
107 | } | ||||
108 | | ||||
109 | void GridLayoutManager::layoutGeometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) | ||||
110 | { | ||||
111 | for (auto *item : layout()->childItems()) { | ||||
112 | // Stash the old config | ||||
113 | //m_parsedConfig[item->key()] = {item->x(), item->y(), item->width(), item->height(), item->rotation()}; | ||||
114 | // Move the item to maintain the distance with the anchors point | ||||
115 | maintainItemEdgeAlignment(item, newGeometry, oldGeometry); | ||||
116 | } | ||||
117 | } | ||||
118 | | ||||
119 | void GridLayoutManager::resetLayout() | ||||
120 | { | ||||
121 | m_grid.clear(); | ||||
122 | m_pointsForItem.clear(); | ||||
123 | for (auto *item : layout()->childItems()) { | ||||
124 | ItemContainer *itemCont = qobject_cast<ItemContainer*>(item); | ||||
125 | if (itemCont && itemCont != layout()->placeHolder()) { | ||||
126 | // NOTE: do not use positionItemAndAssign here, because we do not want to emit layoutNeedsSaving, to not save after resize | ||||
127 | positionItem(itemCont); | ||||
128 | assignSpaceImpl(itemCont); | ||||
129 | } | ||||
130 | } | ||||
131 | } | ||||
132 | | ||||
133 | void GridLayoutManager::resetLayoutFromConfig() | ||||
134 | { | ||||
135 | m_grid.clear(); | ||||
136 | m_pointsForItem.clear(); | ||||
137 | QList<ItemContainer *> missingItems; | ||||
138 | | ||||
139 | for (auto *item : layout()->childItems()) { | ||||
140 | ItemContainer *itemCont = qobject_cast<ItemContainer*>(item); | ||||
141 | if (itemCont && itemCont != layout()->placeHolder()) { | ||||
142 | if (!restoreItem(itemCont)) { | ||||
143 | missingItems << itemCont; | ||||
144 | } | ||||
145 | } | ||||
146 | } | ||||
147 | | ||||
148 | for (auto *item : missingItems) { | ||||
149 | // NOTE: do not use positionItemAndAssign here, because we do not want to emit layoutNeedsSaving, to not save after resize | ||||
150 | positionItem(item); | ||||
151 | assignSpaceImpl(item); | ||||
152 | } | ||||
153 | } | ||||
154 | | ||||
155 | bool GridLayoutManager::restoreItem(ItemContainer *item) | ||||
156 | { | ||||
157 | auto it = m_parsedConfig.find(item->key()); | ||||
158 | | ||||
159 | if (it != m_parsedConfig.end()) { | ||||
160 | // Actual restore | ||||
161 | item->setPosition(QPointF(it.value().x, it.value().y)); | ||||
162 | item->setSize(QSizeF(it.value().width, it.value().height)); | ||||
163 | item->setRotation(it.value().rotation); | ||||
164 | | ||||
165 | // NOTE: do not use positionItemAndAssign here, because we do not want to emit layoutNeedsSaving, to not save after resize | ||||
166 | // If size is empty the layout is not in a valid state and probably startup is not completed yet | ||||
167 | if (!layout()->size().isEmpty()) { | ||||
168 | releaseSpaceImpl(item); | ||||
169 | positionItem(item); | ||||
170 | assignSpaceImpl(item); | ||||
171 | } | ||||
172 | | ||||
173 | return true; | ||||
174 | } | ||||
175 | | ||||
176 | return false; | ||||
177 | } | ||||
178 | | ||||
179 | bool GridLayoutManager::isRectAvailable(const QRectF &rect) | ||||
180 | { | ||||
181 | //TODO: define directions in which it can grow | ||||
182 | if (rect.x() < 0 || rect.y() < 0 || rect.x() + rect.width() > layout()->width() || rect.y() + rect.height() > layout()->height()) { | ||||
183 | return false; | ||||
184 | } | ||||
185 | | ||||
186 | const QRect cellItemGeom = cellBasedGeometry(rect); | ||||
187 | | ||||
188 | for (int row = cellItemGeom.top(); row <= cellItemGeom.bottom(); ++row) { | ||||
189 | for (int column = cellItemGeom.left(); column <= cellItemGeom.right(); ++column) { | ||||
190 | if (!isCellAvailable(QPair<int, int>(row, column))) { | ||||
191 | return false; | ||||
192 | } | ||||
193 | } | ||||
194 | } | ||||
195 | return true; | ||||
196 | } | ||||
197 | | ||||
198 | bool GridLayoutManager::assignSpaceImpl(ItemContainer *item) | ||||
199 | { | ||||
200 | // Don't emit extra layoutneedssaving signals | ||||
201 | releaseSpaceImpl(item); | ||||
202 | if (!isRectAvailable(itemGeometry(item))) { | ||||
203 | qWarning()<<"Trying to take space not available" << item; | ||||
204 | return false; | ||||
205 | } | ||||
206 | | ||||
207 | const QRect cellItemGeom = cellBasedGeometry(itemGeometry(item)); | ||||
208 | | ||||
209 | for (int row = cellItemGeom.top(); row <= cellItemGeom.bottom(); ++row) { | ||||
210 | for (int column = cellItemGeom.left(); column <= cellItemGeom.right(); ++column) { | ||||
211 | QPair<int, int> cell(row, column); | ||||
212 | m_grid.insert(cell, item); | ||||
213 | m_pointsForItem[item].insert(cell); | ||||
214 | } | ||||
215 | } | ||||
216 | | ||||
217 | // Reorder items tab order | ||||
218 | for (auto *i2 : layout()->childItems()) { | ||||
219 | ItemContainer *item2 = qobject_cast<ItemContainer*>(i2); | ||||
220 | if (item2 && item != item2 && item2 != layout()->placeHolder() | ||||
221 | && item->y() < item2->y() + item2->height() | ||||
222 | && item->x() <= item2->x()) { | ||||
223 | item->stackBefore(item2); | ||||
224 | break; | ||||
225 | } | ||||
226 | } | ||||
227 | | ||||
228 | if (item->layoutAttached()) { | ||||
229 | connect(item, &ItemContainer::sizeHintsChanged, this, [this, item]() { | ||||
230 | adjustToItemSizeHints(item); | ||||
231 | }); | ||||
232 | } | ||||
233 | | ||||
234 | return true; | ||||
235 | } | ||||
236 | | ||||
237 | void GridLayoutManager::releaseSpaceImpl(ItemContainer *item) | ||||
238 | { | ||||
239 | auto it = m_pointsForItem.find(item); | ||||
240 | | ||||
241 | if (it == m_pointsForItem.end()) { | ||||
242 | return; | ||||
243 | } | ||||
244 | | ||||
245 | for (const auto &point : it.value()) { | ||||
246 | m_grid.remove(point); | ||||
247 | } | ||||
248 | | ||||
249 | m_pointsForItem.erase(it); | ||||
250 | | ||||
251 | disconnect(item, &ItemContainer::sizeHintsChanged, this, nullptr); | ||||
252 | } | ||||
253 | | ||||
254 | int GridLayoutManager::rows() const | ||||
255 | { | ||||
256 | return layout()->height() / cellSize().height(); | ||||
257 | } | ||||
258 | | ||||
259 | int GridLayoutManager::columns() const | ||||
260 | { | ||||
261 | return layout()->width() / cellSize().width(); | ||||
262 | } | ||||
263 | | ||||
264 | void GridLayoutManager::adjustToItemSizeHints(ItemContainer *item) | ||||
265 | { | ||||
266 | if (!item->layoutAttached() || item->editMode()) { | ||||
267 | return; | ||||
268 | } | ||||
269 | | ||||
270 | bool changed = false; | ||||
271 | | ||||
272 | // Minimum | ||||
273 | const qreal newMinimumHeight = item->layoutAttached()->property("minimumHeight").toReal(); | ||||
274 | const qreal newMinimumWidth = item->layoutAttached()->property("minimumWidth").toReal(); | ||||
275 | | ||||
276 | if (newMinimumHeight > item->height()) { | ||||
277 | item->setHeight(newMinimumHeight); | ||||
278 | changed = true; | ||||
279 | } | ||||
280 | if (newMinimumWidth > item->width()) { | ||||
281 | item->setWidth(newMinimumWidth); | ||||
282 | changed = true; | ||||
283 | } | ||||
284 | | ||||
285 | // Preferred | ||||
286 | const qreal newPreferredHeight = item->layoutAttached()->property("preferredHeight").toReal(); | ||||
287 | const qreal newPreferredWidth = item->layoutAttached()->property("preferredWidth").toReal(); | ||||
288 | | ||||
289 | if (newPreferredHeight > item->height()) { | ||||
290 | item->setHeight(layout()->cellHeight() * ceil(newPreferredHeight / layout()->cellHeight())); | ||||
291 | changed = true; | ||||
292 | } | ||||
293 | if (newPreferredWidth > item->width()) { | ||||
294 | item->setWidth(layout()->cellWidth() * ceil(newPreferredWidth / layout()->cellWidth())); | ||||
295 | changed = true; | ||||
296 | } | ||||
297 | | ||||
298 | /*// Maximum : IGNORE? | ||||
299 | const qreal newMaximumHeight = item->layoutAttached()->property("preferredHeight").toReal(); | ||||
300 | const qreal newMaximumWidth = item->layoutAttached()->property("preferredWidth").toReal(); | ||||
301 | | ||||
302 | if (newMaximumHeight > 0 && newMaximumHeight < height()) { | ||||
303 | item->setHeight(newMaximumHeight); | ||||
304 | changed = true; | ||||
305 | } | ||||
306 | if (newMaximumHeight > 0 && newMaximumWidth < width()) { | ||||
307 | item->setWidth(newMaximumWidth); | ||||
308 | changed = true; | ||||
309 | }*/ | ||||
310 | | ||||
311 | // Relayout if anything changed | ||||
312 | if (changed && itemIsManaged(item)) { | ||||
313 | releaseSpace(item); | ||||
314 | positionItem(item); | ||||
315 | } | ||||
316 | } | ||||
317 | | ||||
318 | QRect GridLayoutManager::cellBasedGeometry(const QRectF &geom) const | ||||
319 | { | ||||
320 | return QRect( | ||||
321 | round(qBound(0.0, geom.x(), layout()->width() - geom.width()) / cellSize().width()), | ||||
322 | round(qBound(0.0, geom.y(), layout()->height() - geom.height()) / cellSize().height()), | ||||
323 | round((qreal)geom.width() / cellSize().width()), | ||||
324 | round((qreal)geom.height() / cellSize().height()) | ||||
325 | ); | ||||
326 | } | ||||
327 | | ||||
328 | QRect GridLayoutManager::cellBasedBoundingGeometry(const QRectF &geom) const | ||||
329 | { | ||||
330 | return QRect( | ||||
331 | floor(qBound(0.0, geom.x(), layout()->width() - geom.width()) / cellSize().width()), | ||||
332 | floor(qBound(0.0, geom.y(), layout()->height() - geom.height()) / cellSize().height()), | ||||
333 | ceil((qreal)geom.width() / cellSize().width()), | ||||
334 | ceil((qreal)geom.height() / cellSize().height()) | ||||
335 | ); | ||||
336 | } | ||||
337 | | ||||
338 | bool GridLayoutManager::isOutOfBounds(const QPair<int, int> &cell) const | ||||
339 | { | ||||
340 | return cell.first < 0 | ||||
341 | || cell.second < 0 | ||||
342 | || cell.first >= rows() | ||||
343 | || cell.second >= columns(); | ||||
344 | } | ||||
345 | | ||||
346 | bool GridLayoutManager::isCellAvailable(const QPair<int, int> &cell) const | ||||
347 | { | ||||
348 | return !isOutOfBounds(cell) && !m_grid.contains(cell); | ||||
349 | } | ||||
350 | | ||||
351 | QRectF GridLayoutManager::itemGeometry(QQuickItem *item) const | ||||
352 | { | ||||
353 | return QRectF(item->x(), item->y(), item->width(), item->height()); | ||||
354 | } | ||||
355 | | ||||
356 | QPair<int, int> GridLayoutManager::nextCell(const QPair<int, int> &cell, AppletsLayout::PreferredLayoutDirection direction) const | ||||
357 | { | ||||
358 | QPair<int, int> nCell = cell; | ||||
359 | | ||||
360 | switch (direction) { | ||||
361 | case AppletsLayout::AppletsLayout::BottomToTop: | ||||
362 | --nCell.first; | ||||
363 | break; | ||||
364 | case AppletsLayout::AppletsLayout::TopToBottom: | ||||
365 | ++nCell.first; | ||||
366 | break; | ||||
367 | case AppletsLayout::AppletsLayout::RightToLeft: | ||||
368 | --nCell.second; | ||||
369 | break; | ||||
370 | case AppletsLayout::AppletsLayout::LeftToRight: | ||||
371 | default: | ||||
372 | ++nCell.second; | ||||
373 | break; | ||||
374 | } | ||||
375 | | ||||
376 | return nCell; | ||||
377 | } | ||||
378 | | ||||
379 | QPair<int, int> GridLayoutManager::nextAvailableCell(const QPair<int, int> &cell, AppletsLayout::PreferredLayoutDirection direction) const | ||||
380 | { | ||||
381 | QPair<int, int> nCell = cell; | ||||
382 | while (!isOutOfBounds(nCell)) { | ||||
383 | nCell = nextCell(nCell, direction); | ||||
384 | | ||||
385 | if (isOutOfBounds(nCell)) { | ||||
386 | switch (direction) { | ||||
387 | case AppletsLayout::AppletsLayout::BottomToTop: | ||||
388 | nCell.first = rows() - 1; | ||||
389 | --nCell.second; | ||||
390 | break; | ||||
391 | case AppletsLayout::AppletsLayout::TopToBottom: | ||||
392 | nCell.first = 0; | ||||
393 | ++nCell.second; | ||||
394 | break; | ||||
395 | case AppletsLayout::AppletsLayout::RightToLeft: | ||||
396 | --nCell.first; | ||||
397 | nCell.second = columns() - 1; | ||||
398 | break; | ||||
399 | case AppletsLayout::AppletsLayout::LeftToRight: | ||||
400 | default: | ||||
401 | ++nCell.first; | ||||
402 | nCell.second = 0; | ||||
403 | break; | ||||
404 | } | ||||
405 | } | ||||
406 | | ||||
407 | if (isCellAvailable(nCell)) { | ||||
408 | return nCell; | ||||
409 | } | ||||
410 | } | ||||
411 | | ||||
412 | return QPair<int, int>(-1, -1); | ||||
413 | } | ||||
414 | | ||||
415 | int GridLayoutManager::freeSpaceInDirection(const QPair<int, int> &cell, AppletsLayout::PreferredLayoutDirection direction) const | ||||
416 | { | ||||
417 | QPair<int, int> nCell = cell; | ||||
418 | | ||||
419 | int avail = 0; | ||||
420 | | ||||
421 | while (isCellAvailable(nCell)) { | ||||
422 | ++avail; | ||||
423 | nCell = nextCell(nCell, direction); | ||||
424 | } | ||||
425 | | ||||
426 | return avail; | ||||
427 | } | ||||
428 | | ||||
429 | QRectF GridLayoutManager::nextAvailableSpace(ItemContainer *item, const QSizeF &minimumSize, AppletsLayout::PreferredLayoutDirection direction) const | ||||
430 | { | ||||
431 | // The mionimum size in grid units | ||||
432 | const QSize minimumGridSize( | ||||
433 | ceil((qreal)minimumSize.width() / cellSize().width()), | ||||
434 | ceil((qreal)minimumSize.height() / cellSize().height()) | ||||
435 | ); | ||||
436 | | ||||
437 | QRect itemCellGeom = cellBasedGeometry(itemGeometry(item)); | ||||
438 | itemCellGeom.setWidth(qMax(itemCellGeom.width(), minimumGridSize.width())); | ||||
439 | itemCellGeom.setHeight(qMax(itemCellGeom.height(), minimumGridSize.height())); | ||||
440 | | ||||
441 | QSize partialSize; | ||||
442 | | ||||
443 | QPair<int, int> cell(itemCellGeom.y(), itemCellGeom.x()); | ||||
444 | if (direction == AppletsLayout::AppletsLayout::RightToLeft) { | ||||
445 | cell.second += itemCellGeom.width(); | ||||
446 | } else if (direction == AppletsLayout::AppletsLayout::BottomToTop) { | ||||
447 | cell.first += itemCellGeom.height(); | ||||
448 | } | ||||
449 | | ||||
450 | while (!isOutOfBounds(cell)) { | ||||
451 | | ||||
452 | if (!isCellAvailable(cell)) { | ||||
453 | cell = nextAvailableCell(cell, direction); | ||||
454 | } | ||||
455 | | ||||
456 | if (direction == AppletsLayout::LeftToRight || direction == AppletsLayout::RightToLeft) { | ||||
457 | partialSize = QSize(INT_MAX, 0); | ||||
458 | | ||||
459 | int currentRow = cell.first; | ||||
460 | for (; currentRow < cell.first + itemCellGeom.height(); ++currentRow) { | ||||
461 | | ||||
462 | const int freeRow = freeSpaceInDirection(QPair<int, int>(currentRow, cell.second), direction); | ||||
463 | | ||||
464 | partialSize.setWidth(qMin(partialSize.width(), freeRow)); | ||||
465 | | ||||
466 | if (freeRow > 0) { | ||||
467 | partialSize.setHeight(partialSize.height() + 1); | ||||
468 | } else if (partialSize.height() < minimumGridSize.height()) { | ||||
469 | break; | ||||
470 | } | ||||
471 | | ||||
472 | if (partialSize.width() >= itemCellGeom.width() | ||||
473 | && partialSize.height() >= itemCellGeom.height()) { | ||||
474 | break; | ||||
475 | } else if (partialSize.width() < minimumGridSize.width()) { | ||||
476 | break; | ||||
477 | } | ||||
478 | } | ||||
479 | | ||||
480 | if (partialSize.width() >= minimumGridSize.width() | ||||
481 | && partialSize.height() >= minimumGridSize.height()) { | ||||
482 | | ||||
483 | const int width = qMin(itemCellGeom.width(), partialSize.width()) * cellSize().width(); | ||||
484 | const int height = qMin(itemCellGeom.height(), partialSize.height()) * cellSize().height(); | ||||
485 | | ||||
486 | if (direction == AppletsLayout::RightToLeft) { | ||||
487 | return QRectF((cell.second + 1) * cellSize().width() - width, | ||||
488 | cell.first * cellSize().height(), | ||||
489 | width, height); | ||||
490 | // AppletsLayout::LeftToRight | ||||
491 | } else { | ||||
492 | return QRectF(cell.second * cellSize().width(), | ||||
493 | cell.first * cellSize().height(), | ||||
494 | width, height); | ||||
495 | } | ||||
496 | } else { | ||||
497 | cell.first = currentRow + 1; | ||||
498 | } | ||||
499 | | ||||
500 | } else if (direction == AppletsLayout::TopToBottom || direction == AppletsLayout::BottomToTop) { | ||||
501 | partialSize = QSize(0, INT_MAX); | ||||
502 | | ||||
503 | int currentColumn = cell.second; | ||||
504 | for (; currentColumn < cell.second + itemCellGeom.width(); ++currentColumn) { | ||||
505 | | ||||
506 | const int freeColumn = freeSpaceInDirection(QPair<int, int>(cell.first, currentColumn), direction); | ||||
507 | | ||||
508 | partialSize.setHeight(qMin(partialSize.height(), freeColumn)); | ||||
509 | | ||||
510 | if (freeColumn > 0) { | ||||
511 | partialSize.setWidth(partialSize.width() + 1); | ||||
512 | } else if (partialSize.width() < minimumGridSize.width()) { | ||||
513 | break; | ||||
514 | } | ||||
515 | | ||||
516 | if (partialSize.width() >= itemCellGeom.width() | ||||
517 | && partialSize.height() >= itemCellGeom.height()) { | ||||
518 | break; | ||||
519 | } else if (partialSize.height() < minimumGridSize.height()) { | ||||
520 | break; | ||||
521 | } | ||||
522 | } | ||||
523 | | ||||
524 | if (partialSize.width() >= minimumGridSize.width() | ||||
525 | && partialSize.height() >= minimumGridSize.height()) { | ||||
526 | | ||||
527 | const int width = qMin(itemCellGeom.width(), partialSize.width()) * cellSize().width(); | ||||
528 | const int height = qMin(itemCellGeom.height(), partialSize.height()) * cellSize().height(); | ||||
529 | | ||||
530 | if (direction == AppletsLayout::BottomToTop) { | ||||
531 | return QRectF(cell.second * cellSize().width(), | ||||
532 | (cell.first + 1) * cellSize().height() - height, | ||||
533 | width, height); | ||||
534 | // AppletsLayout::TopToBottom: | ||||
535 | } else { | ||||
536 | return QRectF(cell.second * cellSize().width(), | ||||
537 | cell.first * cellSize().height(), | ||||
538 | width, height); | ||||
539 | } | ||||
540 | } else { | ||||
541 | cell.second = currentColumn + 1; | ||||
542 | } | ||||
543 | } | ||||
544 | } | ||||
545 | | ||||
546 | //We didn't manage to find layout space, return invalid geometry | ||||
547 | return QRectF(); | ||||
548 | } | ||||
549 | | ||||
550 | | ||||
551 | #include "moc_gridlayoutmanager.cpp" |