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

libplasma

flowlayout.cpp

Go to the documentation of this file.
00001 /*
00002 *   Copyright 2007 by Robert Knight <robertknight@gmail.com>
00003 *
00004 *   This program is free software; you can redistribute it and/or modify
00005 *   it under the terms of the GNU Library General Public License
00006 *   as published by the Free Software Foundation; either
00007 *   version 2 of the License, or (at your option) any later version.
00008 *
00009 *   This program is distributed in the hope that it will be useful,
00010 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 *   GNU General Public License for more details
00013 *
00014 *   You should have received a copy of the GNU Library General Public
00015 *   License along with this program; if not, write to the
00016 *   Free Software Foundation, Inc.,
00017 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00018 */
00019 
00020 #include "flowlayout.h"
00021 
00022 #include <limits.h>
00023 #include <math.h>
00024 
00025 #include <QtCore/QList>
00026 #include <QtCore/QRectF>
00027 #include <QtCore/QTimeLine>
00028 
00029 #include <QtDebug>
00030 
00031 #include "layoutanimator.h"
00032 
00033 using namespace Plasma;
00034 
00035 class FlowLayout::Private
00036 {
00037 public:
00038     Private() : columnWidth( -1 ) {}
00039     QList<LayoutItem*> items; 
00040     qreal columnWidth;
00041 };
00042 
00043 FlowLayout::FlowLayout(LayoutItem* parent)
00044     : Layout(parent)
00045     , d(new Private)
00046 {
00047 }
00048 FlowLayout::~FlowLayout()
00049 {
00050     delete d;
00051 }
00052 
00053 int FlowLayout::count() const
00054 {
00055     return d->items.count();
00056 }
00057 
00058 void FlowLayout::addItem(LayoutItem* item)
00059 {
00060     if (!item || d->items.contains(item)) {
00061         return;
00062     }
00063 
00064     item->setManagingLayout(this);
00065     d->items << item;
00066 
00067     if (animator()) {
00068         animator()->setCurrentState(item,LayoutAnimator::InsertedState);
00069     }
00070 
00071     updateGeometry();
00072 }
00073 void FlowLayout::removeItem(LayoutItem* item)
00074 {
00075     if (!item) {
00076         return;
00077     }
00078 
00079     item->unsetManagingLayout(this);
00080     d->items.removeAll(item);
00081 
00082     if (animator()) {
00083         animator()->setCurrentState(item,LayoutAnimator::RemovedState);
00084     }
00085 
00086     updateGeometry();
00087 }
00088 int FlowLayout::indexOf(LayoutItem* item) const
00089 {
00090     if (!item) {
00091         return -1;
00092     }
00093 
00094     return d->items.indexOf(item);
00095 }
00096 LayoutItem* FlowLayout::itemAt(int i) const
00097 {
00098     if (i >= d->items.count()) {
00099         return 0;
00100     }
00101 
00102     return d->items[i];
00103 }
00104 
00105 QSizeF FlowLayout::sizeHint() const
00106 {
00107     // TODO A proper algorithm here
00108     // 
00109     // Idea:  Return a size hint based on the golden ratio to
00110     //        make it aesthetically good
00111     //        eg. Longer side is 1.61x the length of the shorter side
00112     //
00113 
00114     // testing
00115     return QSizeF(500,500);
00116 }
00117 
00118 LayoutItem* FlowLayout::takeAt(int i)
00119 {
00120     if (i >= d->items.count()) {
00121         return 0;
00122     }
00123 
00124     return d->items.takeAt(i);
00125     // FIXME: Should updateGeometry() be called?
00126 }
00127 
00128 template <class T>
00129 T qSum(const QList<T>& container) 
00130 {
00131     T total = 0;
00132     foreach( const T& item , container ) {
00133         total += item; 
00134     }   
00135     return total;
00136 }
00137 
00138 void FlowLayout::relayout()
00139 {
00140     QRectF rect = geometry().adjusted(margin(LeftMargin), margin(TopMargin), -margin(RightMargin), -margin(BottomMargin));
00141 
00142     qDebug() << "Flow layout geometry set to " << geometry();
00143 
00144     // calculate average size of items
00145     qreal totalWidth = 0;
00146     qreal totalHeight = 0;
00147 
00148     foreach(LayoutItem *item , d->items) {
00149         totalWidth += item->sizeHint().width();
00150         totalHeight += item->sizeHint().height();
00151     }
00152 
00153     // use the average item width as the column width.
00154     // Also include the spacing either side of each item as part of the 
00155     // average width, this provides the spacing between the items and
00156     // also allows some tolerance for small differences in item widths 
00157     qreal averageWidth;
00158     if (d->columnWidth == -1) {
00159         averageWidth = totalWidth / d->items.count() + 2*spacing();
00160     } else {
00161         averageWidth = d->columnWidth;
00162     }
00163 
00164     const int columnCount = (int)(rect.width() / averageWidth);
00165 
00166     int insertColumn = 0;
00167     qreal rowPos = 0;
00168     qreal rowHeight = 0;
00169 
00170     // lay the items out in left-to-right , top-to-bottom order
00171     foreach(LayoutItem *item , d->items) {
00172         const QSizeF& itemSize = item->sizeHint();
00173 
00174         int columnSpan = (int)ceil(itemSize.width() / averageWidth);
00175 
00176         if ( insertColumn + columnSpan > columnCount ) {
00177             // start a new row
00178             insertColumn = 0;
00179             rowPos += rowHeight + spacing();
00180         }
00181 
00182        // qDebug() << "Inserting item at column" << insertColumn 
00183        //          << "spanning" << columnSpan << "columns"
00184        //          << "with offset" << offset;
00185 
00186 
00187         // try to expand the item to fill its allocated number of columns
00188         qreal itemWidth = itemSize.width(); 
00189         const qreal idealWidth = columnSpan * averageWidth - spacing();
00190         if ( itemWidth < idealWidth && 
00191              idealWidth < item->maximumSize().width() ) {
00192              itemWidth = idealWidth; 
00193         }
00194        
00195         // calculate offset to horizontally center item 
00196         qreal offset = (columnSpan * averageWidth) - itemWidth;
00197         if ( insertColumn == 0 )
00198             offset -= spacing();  
00199         offset /= 2;
00200 
00201         // try to restrict the item width to the available geometry's
00202         // width
00203         if ( itemWidth > rect.width() ) {
00204             itemWidth = qMax(rect.width(),item->minimumSize().width());
00205             offset = 0;
00206         }        
00207 
00208         // position the item
00209         const QRectF newGeometry(rect.left() + insertColumn * averageWidth + offset,
00210                                  rect.top() + rowPos,
00211                                  itemWidth,
00212                                  itemSize.height());
00213 
00214         rowHeight = qMax(rowHeight,itemSize.height());
00215         insertColumn += columnSpan;
00216 
00217         if ( animator() )
00218             animator()->setGeometry( item , newGeometry );
00219         else
00220             item->setGeometry( newGeometry );
00221     }
00222 
00223     startAnimation();
00224 }
00225 
00226 Qt::Orientations FlowLayout::expandingDirections() const
00227 {
00228     return Qt::Vertical | Qt::Horizontal;
00229 }
00230 
00231 qreal FlowLayout::columnWidth() const
00232 {
00233     return d->columnWidth;
00234 }
00235 
00236 void FlowLayout::setColumnWidth( const qreal width )
00237 {
00238     d->columnWidth = width;
00239 }

libplasma

Skip menu "libplasma"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libplasma
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.4
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