add more spacing
[personal-kdebase.git] / workspace / plasma / containments / desktop / desktoplayout.cpp
blobbd54056a9853a257c800db3eb70f8e6dc3fe3b3b
1 /*
2 Copyright (c) 2008 Ambroz Bizjak <ambro@b4ever.net>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 */
10 #include <limits>
12 #include <QCoreApplication>
13 #include <QGraphicsWidget>
14 #include <QGraphicsProxyWidget>
15 #include <QWaitCondition>
17 #include <KDebug>
19 #include <Plasma/Animator>
21 #include "desktoplayout.h"
23 DesktopLayout::DesktopLayout(QGraphicsLayoutItem *parent)
24 : QObject(0),
25 QGraphicsLayout(parent),
26 autoWorkingArea(true),
27 temporaryPlacement(false),
28 visibilityTolerance(0),
29 m_activated(false)
31 connect(Plasma::Animator::self(), SIGNAL(movementFinished(QGraphicsItem*)),
32 this, SLOT(movementFinished(QGraphicsItem*)));
35 void DesktopLayout::addItem(QGraphicsLayoutItem *item, bool pushBack, const QRectF &preferredGeom, const QRectF &lastGeom)
37 int key = newItemKey();
39 ItemSpace::ItemSpaceItem spaceItem;
40 spaceItem.pushBack = pushBack;
41 spaceItem.animateMovement = false;
42 spaceItem.preferredGeometry = preferredGeom;
43 spaceItem.lastGeometry = (lastGeom.isValid() ? lastGeom : preferredGeom);
44 spaceItem.user = QVariant(key);
46 DesktopLayoutItem desktopItem;
47 desktopItem.item = item;
48 desktopItem.temporaryGeometry = QRectF(0, 0, -1, -1);
50 itemSpace.addItem(spaceItem);
51 items.insert(key, desktopItem);
53 invalidate();
56 void DesktopLayout::addItem(QGraphicsLayoutItem *item, bool pushBack, const QSizeF &size)
58 QSizeF itemSize = ( size.isValid() ? size : item->effectiveSizeHint(Qt::PreferredSize) );
60 // get possible positions
61 QList<QPointF> possiblePositions = itemSpace.positionVertically(itemSize, itemSpace.spaceAlignment, false, true);
62 //kDebug() << "possiblePositions" << possiblePositions;
64 // prefer free positions
65 QRectF bestGeometry = QRectF();
66 foreach (const QPointF &position, possiblePositions) {
67 QRectF geom = QRectF(position, itemSize);
68 if (itemSpace.positionedProperly(geom)) {
69 bestGeometry = geom;
70 break;
74 if (!bestGeometry.isValid()) {
75 // choose the position that with the best resulting visibility
76 QPointF bestPosition = QPointF();
77 qreal bestVisibility = 0;
78 foreach (const QPointF &position, possiblePositions) {
79 // see how much the item can be pushed into the working area:
80 // copy our ItemSpace, add the item to the copy, activate it
81 // and check the resulting position's visibility
83 ItemSpace tempItemSpace(itemSpace);
85 ItemSpace::ItemSpaceItem spaceItem;
86 spaceItem.pushBack = pushBack;
87 spaceItem.animateMovement = false;
88 spaceItem.preferredGeometry = QRectF(position, itemSize);
89 spaceItem.lastGeometry = QRectF(position, itemSize);
90 spaceItem.user = QVariant(-1);
92 tempItemSpace.addItem(spaceItem);
93 tempItemSpace.activate();
94 int tempGroup, tempItem;
95 tempItemSpace.locateItemByUser(QVariant(-1), &tempGroup, &tempItem);
97 QRectF resultingGeom = tempItemSpace.m_groups[tempGroup].m_groupItems[tempItem].lastGeometry;
98 qreal visibility = tempItemSpace.positionVisibility(resultingGeom);
100 //kDebug() << "Trying " << position << " visibility " << visibility;
102 if (visibility > bestVisibility) {
103 bestPosition = position;
104 bestVisibility = visibility;
105 if (visibility >= 1) {
106 break;
111 if (bestVisibility < (1.0-visibilityTolerance)) {
112 bestPosition = QPointF(itemSpace.screenSpacing, itemSpace.screenSpacing);
115 bestGeometry = QRectF(bestPosition, itemSize);
118 addItem(item, pushBack, bestGeometry);
119 kDebug() << "Positioned item to" << bestGeometry;
122 bool DesktopLayout::getPushBack(int index)
124 int group;
125 int item;
126 itemSpace.locateItemByPosition(index, &group, &item);
128 return itemSpace.m_groups[group].m_groupItems[item].pushBack;
131 QRectF DesktopLayout::getPreferredGeometry(int index)
133 int group;
134 int item;
135 itemSpace.locateItemByPosition(index, &group, &item);
137 return itemSpace.m_groups[group].m_groupItems[item].preferredGeometry;
140 QRectF DesktopLayout::getLastGeometry(int index)
142 int group;
143 int item;
144 itemSpace.locateItemByPosition(index, &group, &item);
146 return itemSpace.m_groups[group].m_groupItems[item].lastGeometry;
149 void DesktopLayout::setPlacementSpacing(qreal spacing)
151 itemSpace.placementSpacing = spacing;
154 void DesktopLayout::setScreenSpacing(qreal spacing)
156 itemSpace.screenSpacing = spacing;
157 invalidate();
160 void DesktopLayout::setShiftingSpacing(qreal spacing)
162 itemSpace.shiftingSpacing = spacing;
163 // NOTE: not wise to call that during operation yet
166 void DesktopLayout::setVisibilityTolerance(qreal part)
168 visibilityTolerance = part;
169 invalidate();
172 void DesktopLayout::setWorkingArea(QRectF area)
174 // itemSpace positions are relative to working area start,
175 // adjust them to correspond to the same on-screen positions
176 itemSpace.offsetPositions(workingStart - area.topLeft());
177 itemSpace.setWorkingArea(area.size());
178 workingStart = area.topLeft();
179 invalidate();
182 void DesktopLayout::setAlignment(Qt::Alignment alignment)
184 itemSpace.spaceAlignment = alignment;
185 invalidate();
188 void DesktopLayout::setTemporaryPlacement(bool enabled)
190 temporaryPlacement = enabled;
191 invalidate();
194 void DesktopLayout::setAutoWorkingArea (bool value)
196 autoWorkingArea = value;
199 int DesktopLayout::count () const
201 return items.size();
204 QGraphicsLayoutItem *DesktopLayout::itemAt (int i) const
206 int group = -2, item = -2;
207 itemSpace.locateItemByPosition(i, &group, &item);
208 int itemKey = itemSpace.m_groups[group].m_groupItems[item].user.toInt();
210 return items[itemKey].item;
213 void DesktopLayout::removeAt (int i)
215 int group, item;
216 itemSpace.locateItemByPosition(i, &group, &item);
217 int itemKey = itemSpace.m_groups[group].m_groupItems[item].user.toInt();
219 // remove from ItemSpace
220 itemSpace.removeItem(group, item);
221 // remove from local list
222 items.remove(itemKey);
224 invalidate();
227 void DesktopLayout::performTemporaryPlacement(int group, int itemInGroup)
229 ItemSpace::ItemSpaceItem &spaceItem = itemSpace.m_groups[group].m_groupItems[itemInGroup];
230 DesktopLayoutItem &item = items[spaceItem.user.toInt()];
232 QRectF origGeom = spaceItem.lastGeometry;
233 spaceItem.lastGeometry = QRectF();
235 QPointF newPos = QPointF(0, 0);
236 QList<QPointF> possiblePositions = itemSpace.positionVertically(origGeom.size(), itemSpace.spaceAlignment, true, false);
237 if (possiblePositions.count() > 0) {
238 newPos = possiblePositions[0];
241 spaceItem.lastGeometry = origGeom;
242 item.temporaryGeometry = QRectF(newPos, origGeom.size());
243 item.item->setGeometry(item.temporaryGeometry.translated(workingStart));
246 void DesktopLayout::revertTemporaryPlacement(int group, int itemInGroup)
248 ItemSpace::ItemSpaceItem &spaceItem = itemSpace.m_groups[group].m_groupItems[itemInGroup];
249 DesktopLayoutItem &item = items[spaceItem.user.toInt()];
251 item.temporaryGeometry = QRectF();
252 item.item->setGeometry(spaceItem.lastGeometry.translated(workingStart));
255 // update anything that needs updating
256 void DesktopLayout::setGeometry(const QRectF &rect)
258 m_activated = true;
259 QGraphicsLayout::setGeometry(rect);
261 if (autoWorkingArea || !itemSpace.workingGeom.isValid()) {
262 setWorkingArea(rect);
265 // activate the ItemSpace to perform motion as needed
266 itemSpace.activate();
268 for (int groupId = 0; groupId < itemSpace.m_groups.size(); groupId++) {
269 ItemSpace::ItemGroup &group = itemSpace.m_groups[groupId];
271 for (int itemId = 0; itemId < group.m_groupItems.size(); itemId++) {
272 ItemSpace::ItemSpaceItem &spaceItem = group.m_groupItems[itemId];
273 DesktopLayoutItem &desktopItem = items[spaceItem.user.toInt()];
275 // Temporarily place the item if it could not be pushed inside the working area.
276 // Put it back if it fits again.
277 if (itemSpace.positionVisibility(spaceItem.lastGeometry) < visibilityTolerance) {
278 performTemporaryPlacement(groupId, itemId);
279 } else if (desktopItem.temporaryGeometry.isValid()) {
280 revertTemporaryPlacement(groupId, itemId);
283 // Reset the absolute position if needed
284 QRectF visibleGeom = (desktopItem.temporaryGeometry.isValid() ? desktopItem.temporaryGeometry : spaceItem.lastGeometry);
285 QRectF absoluteGeom = visibleGeom.translated(workingStart);
286 if (desktopItem.item->geometry() != absoluteGeom) {
287 QGraphicsWidget *w = dynamic_cast<QGraphicsWidget*>(desktopItem.item);
288 if (w && spaceItem.animateMovement) {
289 Plasma::Animator *anim = Plasma::Animator::self();
290 bool animating = m_animatingItems.contains(w);
291 if (animating) {
292 anim->stopItemMovement(m_animatingItems.value(w));
294 int id = Plasma::Animator::self()->moveItem(w, Plasma::Animator::FastSlideInMovement,
295 absoluteGeom.topLeft().toPoint());
296 if (id > 0) {
297 m_animatingItems.insert(w, id);
298 } else if (animating) {
299 m_animatingItems.remove(w);
302 spaceItem.animateMovement = false;
303 } else {
304 desktopItem.item->setGeometry(absoluteGeom);
309 m_activated = false;
312 // This should be called when the geometry of an item has been changed.
313 // If the change was made by the user, the new position is used as the preferred position.
314 void DesktopLayout::itemGeometryChanged(QGraphicsLayoutItem *layoutItem)
316 if (m_activated || m_animatingItems.contains(dynamic_cast<QGraphicsWidget*>(layoutItem))) {
317 return;
320 // get local item key
321 int itemKey = -1;
322 QMapIterator<int, DesktopLayoutItem> i(items);
323 while (i.hasNext()) {
324 i.next();
325 if (i.value().item == layoutItem) {
326 itemKey = i.key();
327 break;
330 if (itemKey == -1) {
331 return;
334 // locate item
335 int group, item;
336 itemSpace.locateItemByUser(itemKey, &group, &item);
337 ItemSpace::ItemSpaceItem &spaceItem = itemSpace.m_groups[group].m_groupItems[item];
339 QRectF currentRelative = layoutItem->geometry().translated(-workingStart);
340 if (spaceItem.lastGeometry != currentRelative) {
341 spaceItem.lastGeometry = currentRelative;
342 spaceItem.preferredGeometry = currentRelative;
344 itemSpace.updateItem(group, item);
345 invalidate();
349 QSizeF DesktopLayout::sizeHint (Qt::SizeHint which, const QSizeF &constraint) const
351 Q_UNUSED(which)
352 Q_UNUSED(constraint)
353 return QSizeF();
356 void DesktopLayout::movementFinished(QGraphicsItem* item)
358 if (m_animatingItems.contains(item)) {
359 m_animatingItems.remove(item);
363 int DesktopLayout::newItemKey()
365 int from = -1;
366 QList<int> usedKeys = items.keys();
367 foreach (int key, usedKeys) {
368 if (key - from > 1) {
369 break;
371 from = key;
373 return from+1;
376 #include <desktoplayout.moc>