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

Applets

compactlayout.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   compactlayout.cpp                                                     *
00003  *                                                                         *
00004  *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@gmail.com>              *
00005  *                                                                         *
00006  *   This program is free software; you can redistribute it and/or modify  *
00007  *   it under the terms of the GNU General Public License as published by  *
00008  *   the Free Software Foundation; either version 2 of the License, or     *
00009  *   (at your option) any later version.                                   *
00010  *                                                                         *
00011  *   This program is distributed in the hope that it will be useful,       *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00014  *   GNU General Public License for more details.                          *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU General Public License     *
00017  *   along with this program; if not, write to the                         *
00018  *   Free Software Foundation, Inc.,                                       *
00019  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .        *
00020  ***************************************************************************/
00021 
00022 #include "compactlayout.h"
00023 
00024 #include <QtCore/QHash>
00025 
00026 #include <QtGui/QGraphicsWidget>
00027 #include <kdebug.h>
00028 
00029 namespace SystemTray
00030 {
00031 
00032 
00033 class CompactLayout::Private
00034 {
00035 public:
00036     Private(CompactLayout *q)
00037         : q(q),
00038           spacing(4.0)
00039     {
00040     }
00041 
00042     QHash<QGraphicsLayoutItem*, QRectF> calculateGeometries(const QRectF &rect,
00043                                                             Qt::SizeHint which,
00044                                                             const QSizeF &constraint) const;
00045     void addPadding(QHash<QGraphicsLayoutItem*, QRectF> &geometries,
00046                     const QSizeF &constraint);
00047     QSizeF hackedConstraint(const QSizeF &constraint) const;
00048     void updateParentWidget(QGraphicsWidget *item);
00049     QRectF boundingRect(const QList<QRectF> &rects) const;
00050 
00051     CompactLayout *q;
00052     qreal spacing;
00053     QList<QGraphicsLayoutItem*> items;
00054 };
00055 
00056 
00057 CompactLayout::CompactLayout(QGraphicsLayoutItem *parent)
00058     : QGraphicsLayout(parent),
00059       d(new Private(this))
00060 {
00061 }
00062 
00063 
00064 CompactLayout::~CompactLayout()
00065 {
00066     foreach (QGraphicsLayoutItem* item, d->items) {
00067           removeItem(item);
00068     }
00069     delete d;
00070 }
00071 
00072 
00073 qreal CompactLayout::spacing() const
00074 {
00075     return d->spacing;
00076 }
00077 
00078 
00079 void CompactLayout::setSpacing(qreal spacing)
00080 {
00081     d->spacing = spacing;
00082 }
00083 
00084 
00085 void CompactLayout::insertItem(int index, QGraphicsLayoutItem *item)
00086 {
00087     index = qBound(0, index, d->items.count());
00088 
00089     item->setParentLayoutItem(this);
00090 
00091     QGraphicsWidget *widget = dynamic_cast<QGraphicsWidget *>(item);
00092     if (widget) {
00093         d->updateParentWidget(widget);
00094     }
00095 
00096     if (index == d->items.count()) {
00097         d->items.append(item);
00098     } else {
00099         d->items.insert(index, item);
00100     }
00101 
00102     updateGeometry();
00103     activate();
00104 }
00105 
00106 void CompactLayout::addItem(QGraphicsLayoutItem *item)
00107 {
00108     insertItem(d->items.count(), item);
00109 }
00110 
00111 void CompactLayout::Private::updateParentWidget(QGraphicsWidget *item)
00112 {
00113     QGraphicsLayoutItem *parentItem = q->parentLayoutItem();
00114     while (parentItem && parentItem->isLayout()) {
00115         parentItem = parentItem->parentLayoutItem();
00116     }
00117 
00118     if (parentItem) {
00119         item->setParentItem(static_cast<QGraphicsWidget*>(parentItem));
00120     }
00121 }
00122 
00123 
00124 void CompactLayout::removeItem(QGraphicsLayoutItem *item)
00125 {
00126     d->items.removeAll(item);
00127     item->setParentLayoutItem(0);
00128     updateGeometry();
00129     activate();
00130 }
00131 
00132 
00133 bool CompactLayout::containsItem(QGraphicsLayoutItem *item) const
00134 {
00135     return d->items.contains(item);
00136 }
00137 
00138 
00139 int CompactLayout::count() const
00140 {
00141     return d->items.count();
00142 }
00143 
00144 
00145 void CompactLayout::setGeometry(const QRectF &rect)
00146 {
00147     //kDebug() << rect;
00148     QHash<QGraphicsLayoutItem*, QRectF> geometries;
00149     geometries = d->calculateGeometries(rect, Qt::PreferredSize, rect.size());
00150     d->addPadding(geometries, rect.size());
00151 
00152     QHashIterator<QGraphicsLayoutItem*, QRectF> i(geometries);
00153     while (i.hasNext()) {
00154         i.next();
00155         QGraphicsLayoutItem *item = i.key();
00156         item->setGeometry(i.value());
00157     }
00158 }
00159 
00160 
00161 void CompactLayout::Private::addPadding(QHash<QGraphicsLayoutItem*, QRectF> &geometries, const QSizeF &constraint)
00162 {
00163     QSizeF size = boundingRect(geometries.values()).size();
00164 
00165     qreal xAdjustment = (constraint.width() - size.width()) / 2.0;
00166     qreal yAdjustment = (constraint.height() - size.height()) / 2.0;
00167 
00168     if (xAdjustment || yAdjustment) {
00169         foreach (QGraphicsLayoutItem *item, items) {
00170             QGraphicsWidget *widget = dynamic_cast<QGraphicsWidget *>(item);
00171             if (widget && !widget->isVisible()) {
00172                 continue;
00173             }
00174 
00175             geometries[item].moveLeft(geometries[item].left() + xAdjustment);
00176             geometries[item].moveTop(geometries[item].top() + yAdjustment);
00177         }
00178     }
00179 }
00180 
00181 
00182 QGraphicsLayoutItem* CompactLayout::itemAt(int index) const
00183 {
00184     return d->items.at(index);
00185 }
00186 
00187 
00188 void CompactLayout::removeAt(int index)
00189 {
00190     QGraphicsLayoutItem* item = itemAt(index);
00191     if (item) {
00192         item->setParentLayoutItem(0);
00193         d->items.removeAt(index);
00194     }
00195 }
00196 
00197 
00198 QSizeF CompactLayout::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
00199 {
00200     if (which != Qt::PreferredSize) {
00201         return QSizeF();
00202     }
00203 
00204     QHash<QGraphicsLayoutItem*, QRectF> geometries =
00205         d->calculateGeometries(geometry(), which, d->hackedConstraint(constraint));
00206 
00207     return d->boundingRect(geometries.values()).size();
00208 }
00209 
00210 
00211 QRectF CompactLayout::Private::boundingRect(const QList<QRectF> &rects) const
00212 {
00213     QRectF boundingRect;
00214 
00215     foreach (const QRectF &rect, rects) {
00216         if (boundingRect.isNull()) {
00217             boundingRect = rect;
00218         } else {
00219             boundingRect = boundingRect.united(rect);
00220         }
00221     }
00222 
00223     return boundingRect;
00224 }
00225 
00226 
00227 QHash<QGraphicsLayoutItem*, QRectF> CompactLayout::Private::calculateGeometries(const QRectF &geom, Qt::SizeHint which, const QSizeF &constraint) const
00228 {
00229     QSizePolicy sizePolicy;
00230     //FIXME: not really pretty: try to fetch it from the grandparent (assumption on how taskarea is done) otherwise from the parent
00231     if (q->parentLayoutItem()->parentLayoutItem()) {
00232         sizePolicy = q->parentLayoutItem()->parentLayoutItem()->sizePolicy();
00233     } else if (q->parentLayoutItem()) {
00234         sizePolicy = q->parentLayoutItem()->sizePolicy();
00235     } else {
00236         sizePolicy = q->sizePolicy();
00237     }
00238 
00239     QHash<QGraphicsLayoutItem*, QRectF> geometries;
00240     QList<qreal> xPositions;
00241     QList<qreal> yPositions;
00242 
00243     xPositions << geom.left();
00244     yPositions << geom.top();
00245 
00246     foreach (QGraphicsLayoutItem *item, items) {
00247         QGraphicsWidget *widget = dynamic_cast<QGraphicsWidget *>(item);
00248         if (widget && !widget->isVisible()) {
00249             continue;
00250         }
00251 
00252         QRectF rect;
00253         rect.setSize(item->effectiveSizeHint(which));
00254 
00255         rect.setWidth(qBound(item->minimumWidth(), rect.width(), constraint.width()));
00256         rect.setHeight(qBound(item->minimumHeight(), rect.height(), constraint.height()));
00257 
00258         // Try to find an empty space for the item within the bounds
00259         // of the already positioned out items
00260         foreach (qreal x, xPositions) {
00261             rect.moveLeft(x);
00262             if (rect.right() >= xPositions.last()) {
00263                 continue;
00264             }
00265 
00266             foreach (qreal y, yPositions) {
00267                 rect.moveTop(y);
00268                 if (rect.bottom() >= yPositions.last()) {
00269                     continue;
00270                 }
00271 
00272                 bool overlapping = false;
00273                 foreach (const QRectF &existingRect, geometries) {
00274                     if (existingRect.intersects(rect)) {
00275                         overlapping = true;
00276                     }
00277                 }
00278 
00279                 if (!overlapping) {
00280                     goto positioning_done;
00281                 }
00282             }
00283         }
00284 
00285         // It didn't fit anywhere, so the current bounds will need to
00286         // be extended.
00287         Qt::Orientation direction;
00288 
00289         {
00290             const int yDelta = yPositions.last() + rect.height() - constraint.height();
00291             const int xDelta = xPositions.last() + rect.width() - constraint.width();
00292             //a layout without elements will have height==0 when vertical width == 0 when horizontal
00293             if (int(constraint.height()) == 0 && constraint.width() > 0) {
00294                 direction = Qt::Vertical;
00295             } else if (int(constraint.width()) == 0 && constraint.height() > 0) {
00296                 direction = Qt::Horizontal;
00297             // Extend based on constraints and prevent expanding if possible
00298             } else if ((sizePolicy.verticalPolicy() != QSizePolicy::Expanding) && xDelta < 0) {
00299                 direction = Qt::Horizontal;
00300             } else if ((sizePolicy.horizontalPolicy() != QSizePolicy::Expanding) && yDelta < 0) {
00301                 direction = Qt::Vertical;
00302             // Then extend based on expanding policy
00303             } else if (sizePolicy.horizontalPolicy() != QSizePolicy::Expanding) {
00304                 direction = Qt::Horizontal;
00305             } else if (sizePolicy.verticalPolicy() != QSizePolicy::Expanding) {
00306                 direction = Qt::Vertical;
00307             // Otherwise try to keep the shape of a square
00308             } else if (yPositions.last() >= xPositions.last()) {
00309                 direction = Qt::Horizontal;
00310             } else {
00311                 direction = Qt::Vertical;
00312             }
00313         }
00314 
00315         if (direction == Qt::Horizontal) {
00316             rect.moveTop(yPositions.first());
00317             rect.moveLeft(xPositions.last());
00318         } else {
00319             rect.moveLeft(xPositions.first());
00320             rect.moveTop(yPositions.last());
00321         }
00322 
00323     positioning_done:
00324         if (!xPositions.contains(rect.right() + spacing)) {
00325             xPositions.append(rect.right() + spacing);
00326             qSort(xPositions);
00327         }
00328 
00329         if (!yPositions.contains(rect.bottom() + spacing)) {
00330             yPositions.append(rect.bottom() + spacing);
00331             qSort(yPositions);
00332         }
00333 
00334         geometries[item] = rect;
00335     }
00336 
00337     return geometries;
00338 }
00339 
00340 
00341 QSizeF CompactLayout::Private::hackedConstraint(const QSizeF &constraint) const
00342 {
00343     // Qt doesn't seem to ever specify constraints to sizeHint()
00344     // but the layout needs to know what the constraints are.
00345     // This function returns a new constraint with the size of
00346     // the containing view when Qt hasn't passed a constraint.
00347 
00348     if (constraint.width() != -1 || constraint.height() != -1) {
00349         return constraint;
00350     }
00351 
00352     const QGraphicsWidget *widget = 0;
00353     const QGraphicsLayoutItem *item = q;
00354 
00355     while (item && !widget) {
00356         item = item->parentLayoutItem();
00357         if (!item->isLayout()) {
00358             widget = static_cast<const QGraphicsWidget*>(item);
00359         }
00360     }
00361 
00362     if (!widget) {
00363         return constraint;
00364     }
00365 
00366     QSizeF parentSize;
00367     qreal xMargins = 0.0, yMargins = 0.0;
00368 
00369     while (widget->parentWidget()) {
00370         widget = widget->parentWidget();
00371         parentSize = widget->size();
00372 
00373         qreal left, top, right, bottom;
00374 
00375         if (widget->layout()) {
00376             widget->layout()->getContentsMargins(&left, &top, &right, &bottom);
00377         } else {
00378             widget->getContentsMargins(&left, &top, &right, &bottom);
00379         }
00380 
00381         xMargins += left + right;
00382         yMargins += top + bottom;
00383     }
00384 
00385     return parentSize - QSizeF(xMargins, yMargins);
00386 }
00387 
00388 
00389 }

Applets

Skip menu "Applets"
  • 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