• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

Plasma

desktoplayout.cpp

Go to the documentation of this file.
00001 /*
00002   Copyright (c) 2008 Ambroz Bizjak <ambro@b4ever.net>
00003 
00004   This program is free software; you can redistribute it and/or modify
00005   it under the terms of the GNU General Public License as published by
00006   the Free Software Foundation; either version 2 of the License, or
00007   (at your option) any later version.
00008 */
00009 
00010 #include <limits>
00011 
00012 #include <QCoreApplication>
00013 #include <QGraphicsWidget>
00014 #include <QGraphicsProxyWidget>
00015 #include <QWaitCondition>
00016 
00017 #include <KDebug>
00018 
00019 #include <Plasma/Animator>
00020 
00021 #include "desktoplayout.h"
00022 
00023 DesktopLayout::DesktopLayout(QGraphicsLayoutItem *parent)
00024       : QObject(0),
00025         QGraphicsLayout(parent),
00026         autoWorkingArea(true),
00027         temporaryPlacement(false),
00028         visibilityTolerance(0),
00029         m_activated(false)
00030 {
00031     connect(Plasma::Animator::self(), SIGNAL(movementFinished(QGraphicsItem*)),
00032             this, SLOT(movementFinished(QGraphicsItem*)));
00033 }
00034 
00035 void DesktopLayout::addItem(QGraphicsLayoutItem *item, bool pushBack, const QRectF &preferredGeom, const QRectF &lastGeom)
00036 {
00037     int key = newItemKey();
00038 
00039     ItemSpace::ItemSpaceItem spaceItem;
00040     spaceItem.pushBack = pushBack;
00041     spaceItem.animateMovement = false;
00042     spaceItem.preferredGeometry = preferredGeom;
00043     spaceItem.lastGeometry = (lastGeom.isValid() ? lastGeom : preferredGeom);
00044     spaceItem.user = QVariant(key);
00045 
00046     DesktopLayoutItem desktopItem;
00047     desktopItem.item = item;
00048     desktopItem.temporaryGeometry = QRectF(0, 0, -1, -1);
00049 
00050     itemSpace.addItem(spaceItem);
00051     items.insert(key, desktopItem);
00052 
00053     invalidate();
00054 }
00055 
00056 void DesktopLayout::addItem(QGraphicsLayoutItem *item, bool pushBack, const QSizeF &size)
00057 {
00058     QSizeF itemSize = ( size.isValid() ? size : item->effectiveSizeHint(Qt::PreferredSize) );
00059 
00060     // get possible positions
00061     QList<QPointF> possiblePositions = itemSpace.positionVertically(itemSize, itemSpace.spaceAlignment, false, true);
00062     //kDebug() << "possiblePositions" << possiblePositions;
00063 
00064     // prefer free positions
00065     QRectF bestGeometry = QRectF();
00066     foreach (const QPointF &position, possiblePositions) {
00067         QRectF geom = QRectF(position, itemSize);
00068         if (itemSpace.positionedProperly(geom)) {
00069             bestGeometry = geom;
00070             break;
00071         }
00072     }
00073 
00074     if (!bestGeometry.isValid()) {
00075         // choose the position that with the best resulting visibility
00076         QPointF bestPosition = QPointF();
00077         qreal bestVisibility = 0;
00078         foreach (const QPointF &position, possiblePositions) {
00079             // see how much the item can be pushed into the working area:
00080             // copy our ItemSpace, add the item to the copy, activate it
00081             // and check the resulting position's visibility
00082 
00083             ItemSpace tempItemSpace(itemSpace);
00084 
00085             ItemSpace::ItemSpaceItem spaceItem;
00086             spaceItem.pushBack = pushBack;
00087             spaceItem.animateMovement = false;
00088             spaceItem.preferredGeometry = QRectF(position, itemSize);
00089             spaceItem.lastGeometry = QRectF(position, itemSize);
00090             spaceItem.user = QVariant(-1);
00091 
00092             tempItemSpace.addItem(spaceItem);
00093             tempItemSpace.activate();
00094             int tempGroup, tempItem;
00095             tempItemSpace.locateItemByUser(QVariant(-1), &tempGroup, &tempItem);
00096 
00097             QRectF resultingGeom = tempItemSpace.m_groups[tempGroup].m_groupItems[tempItem].lastGeometry;
00098             qreal visibility = tempItemSpace.positionVisibility(resultingGeom);
00099 
00100             //kDebug() << "Trying " << position << " visibility " << visibility;
00101 
00102             if (visibility > bestVisibility) {
00103                 bestPosition = position;
00104                 bestVisibility = visibility;
00105                 if (visibility >= 1) {
00106                     break;
00107                 }
00108             }
00109         }
00110 
00111         if (bestVisibility < (1.0-visibilityTolerance)) {
00112             bestPosition = QPointF(itemSpace.screenSpacing, itemSpace.screenSpacing);
00113         }
00114 
00115         bestGeometry = QRectF(bestPosition, itemSize);
00116     }
00117 
00118     addItem(item, pushBack, bestGeometry);
00119     kDebug() << "Positioned item to" << bestGeometry;
00120 }
00121 
00122 bool DesktopLayout::getPushBack(int index)
00123 {
00124     int group;
00125     int item;
00126     itemSpace.locateItemByPosition(index, &group, &item);
00127 
00128     return itemSpace.m_groups[group].m_groupItems[item].pushBack;
00129 }
00130 
00131 QRectF DesktopLayout::getPreferredGeometry(int index)
00132 {
00133     int group;
00134     int item;
00135     itemSpace.locateItemByPosition(index, &group, &item);
00136 
00137     return itemSpace.m_groups[group].m_groupItems[item].preferredGeometry;
00138 }
00139 
00140 QRectF DesktopLayout::getLastGeometry(int index)
00141 {
00142     int group;
00143     int item;
00144     itemSpace.locateItemByPosition(index, &group, &item);
00145 
00146     return itemSpace.m_groups[group].m_groupItems[item].lastGeometry;
00147 }
00148 
00149 void DesktopLayout::setPlacementSpacing(qreal spacing)
00150 {
00151     itemSpace.placementSpacing = spacing;
00152 }
00153 
00154 void DesktopLayout::setScreenSpacing(qreal spacing)
00155 {
00156     itemSpace.screenSpacing = spacing;
00157     invalidate();
00158 }
00159 
00160 void DesktopLayout::setShiftingSpacing(qreal spacing)
00161 {
00162     itemSpace.shiftingSpacing = spacing;
00163     // NOTE: not wise to call that during operation yet
00164 }
00165 
00166 void DesktopLayout::setVisibilityTolerance(qreal part)
00167 {
00168     visibilityTolerance = part;
00169     invalidate();
00170 }
00171 
00172 void DesktopLayout::setWorkingArea(QRectF area)
00173 {
00174     // itemSpace positions are relative to working area start,
00175     // adjust them to correspond to the same on-screen positions
00176     itemSpace.offsetPositions(workingStart - area.topLeft());
00177     itemSpace.setWorkingArea(area.size());
00178     workingStart = area.topLeft();
00179     invalidate();
00180 }
00181 
00182 void DesktopLayout::setAlignment(Qt::Alignment alignment)
00183 {
00184     itemSpace.spaceAlignment = alignment;
00185     invalidate();
00186 }
00187 
00188 void DesktopLayout::setTemporaryPlacement(bool enabled)
00189 {
00190     temporaryPlacement = enabled;
00191     invalidate();
00192 }
00193 
00194 void DesktopLayout::setAutoWorkingArea (bool value)
00195 {
00196     autoWorkingArea = value;
00197 }
00198 
00199 int DesktopLayout::count () const
00200 {
00201     return items.size();
00202 }
00203 
00204 QGraphicsLayoutItem *DesktopLayout::itemAt (int i) const
00205 {
00206     int group = -2, item = -2;
00207     itemSpace.locateItemByPosition(i, &group, &item);
00208     int itemKey = itemSpace.m_groups[group].m_groupItems[item].user.toInt();
00209 
00210     return items[itemKey].item;
00211 }
00212 
00213 void DesktopLayout::removeAt (int i)
00214 {
00215     int group, item;
00216     itemSpace.locateItemByPosition(i, &group, &item);
00217     int itemKey = itemSpace.m_groups[group].m_groupItems[item].user.toInt();
00218 
00219     // remove from ItemSpace
00220     itemSpace.removeItem(group, item);
00221     // remove from local list
00222     items.remove(itemKey);
00223 
00224     invalidate();
00225 }
00226 
00227 void DesktopLayout::performTemporaryPlacement(int group, int itemInGroup)
00228 {
00229     ItemSpace::ItemSpaceItem &spaceItem = itemSpace.m_groups[group].m_groupItems[itemInGroup];
00230     DesktopLayoutItem &item = items[spaceItem.user.toInt()];
00231 
00232     QRectF origGeom = spaceItem.lastGeometry;
00233     spaceItem.lastGeometry = QRectF();
00234 
00235     QPointF newPos = QPointF(0, 0);
00236     QList<QPointF> possiblePositions = itemSpace.positionVertically(origGeom.size(), itemSpace.spaceAlignment, true, false);
00237     if (possiblePositions.count() > 0) {
00238         newPos = possiblePositions[0];
00239     }
00240 
00241     spaceItem.lastGeometry = origGeom;
00242     item.temporaryGeometry = QRectF(newPos, origGeom.size());
00243     item.item->setGeometry(item.temporaryGeometry.translated(workingStart));
00244 }
00245 
00246 void DesktopLayout::revertTemporaryPlacement(int group, int itemInGroup)
00247 {
00248     ItemSpace::ItemSpaceItem &spaceItem = itemSpace.m_groups[group].m_groupItems[itemInGroup];
00249     DesktopLayoutItem &item = items[spaceItem.user.toInt()];
00250 
00251     item.temporaryGeometry = QRectF();
00252     item.item->setGeometry(spaceItem.lastGeometry.translated(workingStart));
00253 }
00254 
00255 // update anything that needs updating
00256 void DesktopLayout::setGeometry(const QRectF &rect)
00257 {
00258     m_activated = true;
00259     QGraphicsLayout::setGeometry(rect);
00260 
00261     if (autoWorkingArea || !itemSpace.workingGeom.isValid()) {
00262         setWorkingArea(rect);
00263     }
00264 
00265     // activate the ItemSpace to perform motion as needed
00266     itemSpace.activate();
00267 
00268     for (int groupId = 0; groupId < itemSpace.m_groups.size(); groupId++) {
00269         ItemSpace::ItemGroup &group = itemSpace.m_groups[groupId];
00270 
00271         for (int itemId = 0; itemId < group.m_groupItems.size(); itemId++) {
00272             ItemSpace::ItemSpaceItem &spaceItem = group.m_groupItems[itemId];
00273             DesktopLayoutItem &desktopItem = items[spaceItem.user.toInt()];
00274 
00275             //  Temporarily place the item if it could not be pushed inside the working area.
00276             //  Put it back if it fits again.
00277             if (itemSpace.positionVisibility(spaceItem.lastGeometry) < visibilityTolerance) {
00278                 performTemporaryPlacement(groupId, itemId);
00279             } else if (desktopItem.temporaryGeometry.isValid()) {
00280                 revertTemporaryPlacement(groupId, itemId);
00281             }
00282 
00283             // Reset the absolute position if needed
00284             QRectF visibleGeom = (desktopItem.temporaryGeometry.isValid() ? desktopItem.temporaryGeometry : spaceItem.lastGeometry);
00285             QRectF absoluteGeom = visibleGeom.translated(workingStart);
00286             if (desktopItem.item->geometry() != absoluteGeom) {
00287                 QGraphicsWidget *w = dynamic_cast<QGraphicsWidget*>(desktopItem.item);
00288                 if (w && spaceItem.animateMovement)  {
00289                     Plasma::Animator *anim = Plasma::Animator::self();
00290                     bool animating = m_animatingItems.contains(w);
00291                     if (animating) {
00292                         anim->stopItemMovement(m_animatingItems.value(w));
00293                     }
00294                     int id = Plasma::Animator::self()->moveItem(w, Plasma::Animator::FastSlideInMovement,
00295                                                                 absoluteGeom.topLeft().toPoint());
00296                     if (id > 0) {
00297                         m_animatingItems.insert(w, id);
00298                     } else if (animating) {
00299                         m_animatingItems.remove(w);
00300                     }
00301 
00302                     spaceItem.animateMovement = false;
00303                 } else {
00304                     desktopItem.item->setGeometry(absoluteGeom);
00305                 }
00306             }
00307         }
00308     }
00309     m_activated = false;
00310 }
00311 
00312 // This should be called when the geometry of an item has been changed.
00313 // If the change was made by the user, the new position is used as the preferred position.
00314 void DesktopLayout::itemGeometryChanged(QGraphicsLayoutItem *layoutItem)
00315 {
00316     if (m_activated || m_animatingItems.contains(dynamic_cast<QGraphicsWidget*>(layoutItem))) {
00317         return;
00318     }
00319 
00320     // get local item key
00321     int itemKey = -1;
00322     QMapIterator<int, DesktopLayoutItem> i(items);
00323     while (i.hasNext()) {
00324         i.next();
00325         if (i.value().item == layoutItem) {
00326             itemKey = i.key();
00327             break;
00328         }
00329     }
00330     if (itemKey == -1) {
00331         return;
00332     }
00333 
00334     // locate item
00335     int group, item;
00336     itemSpace.locateItemByUser(itemKey, &group, &item);
00337     ItemSpace::ItemSpaceItem &spaceItem = itemSpace.m_groups[group].m_groupItems[item];
00338 
00339     QRectF currentRelative = layoutItem->geometry().translated(-workingStart);
00340     if (spaceItem.lastGeometry != currentRelative) {
00341         spaceItem.lastGeometry = currentRelative;
00342         spaceItem.preferredGeometry = currentRelative;
00343 
00344         itemSpace.updateItem(group, item);
00345         invalidate();
00346     }
00347 }
00348 
00349 QSizeF DesktopLayout::sizeHint (Qt::SizeHint which, const QSizeF &constraint) const
00350 {
00351     Q_UNUSED(which)
00352     Q_UNUSED(constraint)
00353     return QSizeF();
00354 }
00355 
00356 void DesktopLayout::movementFinished(QGraphicsItem* item)
00357 {
00358     if (m_animatingItems.contains(item)) {
00359         m_animatingItems.remove(item);
00360     }
00361 }
00362 
00363 int DesktopLayout::newItemKey()
00364 {
00365     int from = -1;
00366     QList<int> usedKeys = items.keys();
00367     foreach (int key, usedKeys) {
00368         if (key - from > 1) {
00369             break;
00370         }
00371         from = key;
00372     }
00373     return from+1;
00374 }
00375 
00376 #include <desktoplayout.moc>

Plasma

Skip menu "Plasma"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal