[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-panel-devel
Subject:    [Panel-devel] [PATCH] FlowLayout
From:       "Robert Knight" <robertknight () gmail ! com>
Date:       2007-08-31 15:38:41
Message-ID: 13ed09c00708310838x9c022f3xf979e724fe777f6 () mail ! gmail ! com
[Download RAW message or body]

Hi,

This patch implements a layout which organises children in a
left-to-right , top-to-bottom fashion.  It may come in useful for
laying out icons in desktop applets etc.  Items can be of different
sizes and the layout divides icons up into columns with a width equal
to the average item width.

I am not sure whether to commit this to the Plasma libs yet since no
applets directly require it.

Regards,
Robert.

["rk_flow_layout.patch" (text/x-diff)]

Index: widgets/flowlayout.h
===================================================================
--- widgets/flowlayout.h	(revision 0)
+++ widgets/flowlayout.h	(revision 0)
@@ -0,0 +1,64 @@
+/*
+*   Copyright 2007 by Robert Knight <robertknight@gmail.com>
+*
+*   This program is free software; you can redistribute it and/or modify
+*   it under the terms of the GNU Library General Public License version 2,
+*   or (at your option) any later version.
+*
+*   This program is distributed in the hope that it will be useful,
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*   GNU General Public License for more details
+*
+*   You should have received a copy of the GNU Library General Public
+*   License along with this program; if not, write to the
+*   Free Software Foundation, Inc.,
+*   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+#ifndef __FLOWLAYOUT__
+#define __FLOWLAYOUT__
+
+#include <plasma/plasma_export.h>
+
+#include "layout.h"
+
+namespace Plasma
+{
+
+class LayoutItem;
+
+/**
+ * A layout which lays items out left-to-right , top-to-bottom.
+ *
+ * This is similar to the layout of items in a QListView. 
+ */
+class PLASMA_EXPORT FlowLayout : public Layout
+{
+public:
+    /** Construct a new flow layout with the specified parent. */
+    explicit FlowLayout(LayoutItem* parent);
+    virtual ~FlowLayout();
+
+    // reimplemented
+    virtual int count() const;
+    virtual void addItem(LayoutItem* item);
+    virtual void removeItem(LayoutItem* item);
+    virtual int indexOf(LayoutItem* item) const;
+    virtual LayoutItem* itemAt(int i) const;
+    virtual LayoutItem* takeAt(int i);
+
+    virtual QSizeF sizeHint() const;
+    virtual QRectF geometry() const;
+    virtual void setGeometry(const QRectF& geometry);
+    virtual Qt::Orientations expandingDirections() const;
+
+private:
+    class Private;
+    Private *const d;
+};
+
+}
+
+#endif // __FLOWLAYOUT__
+
Index: widgets/flowlayout.cpp
===================================================================
--- widgets/flowlayout.cpp	(revision 0)
+++ widgets/flowlayout.cpp	(revision 0)
@@ -0,0 +1,204 @@
+/*
+*   Copyright 2007 by Robert Knight <robertknight@gmail.com>
+*
+*   This program is free software; you can redistribute it and/or modify
+*   it under the terms of the GNU Library General Public License version 2,
+*   or (at your option) any later version.
+*
+*   This program is distributed in the hope that it will be useful,
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*   GNU General Public License for more details
+*
+*   You should have received a copy of the GNU Library General Public
+*   License along with this program; if not, write to the
+*   Free Software Foundation, Inc.,
+*   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+#include "flowlayout.h"
+
+#include <limits.h>
+#include <math.h>
+
+#include <QtCore/QList>
+#include <QtCore/QRectF>
+#include <QtCore/QTimeLine>
+
+#include <QtDebug>
+
+#include "layoutanimator.h"
+
+using namespace Plasma;
+
+class FlowLayout::Private
+{
+public:
+    QList<LayoutItem*> items; 
+    QRectF geometry; 
+};
+
+FlowLayout::FlowLayout(LayoutItem* parent)
+    : Layout(parent)
+    , d(new Private)
+{
+}
+FlowLayout::~FlowLayout()
+{
+    delete d;
+}
+
+int FlowLayout::count() const
+{
+    return d->items.count();
+}
+void FlowLayout::addItem(LayoutItem* item)
+{
+    d->items << item;
+
+    if ( animator() )
+        animator()->setCurrentState(item,LayoutAnimator::InsertedState);
+
+    item->setManagingLayout(this);
+}
+void FlowLayout::removeItem(LayoutItem* item)
+{
+    d->items.removeAll(item);
+
+    if ( animator() )
+        animator()->setCurrentState(item,LayoutAnimator::RemovedState);
+}
+int FlowLayout::indexOf(LayoutItem* item) const
+{
+    return d->items.indexOf(item);
+}
+LayoutItem* FlowLayout::itemAt(int i) const
+{
+    return d->items[i];
+}
+QSizeF FlowLayout::sizeHint() const
+{
+    // TODO A proper algorithm here
+    // 
+    // Idea:  Return a size hint based on the golden ratio to
+    //        make it aesthetically good
+    //        eg. Longer side is 1.61x the length of the shorter side
+    //
+
+    // testing
+    return QSizeF(500,500);
+}
+LayoutItem* FlowLayout::takeAt(int i)
+{
+    return d->items.takeAt(i);
+}
+
+QRectF FlowLayout::geometry() const
+{
+    return d->geometry;
+}
+
+template <class T>
+T qSum(const QList<T>& container) 
+{
+    T total = 0;
+    foreach( const T& item , container ) {
+        total += item; 
+    }   
+    return total;
+}
+
+void FlowLayout::setGeometry(const QRectF& geo)
+{
+    QRectF geometry(geo);
+    geometry.adjust(margin(),margin(),-margin(),-margin());
+ 
+    qDebug() << "Flow layout geometry set to " << geo;
+
+    // calculate average size of items
+    qreal totalWidth = 0;
+    qreal totalHeight = 0;
+
+    foreach( LayoutItem *item , d->items ) {
+        totalWidth += item->sizeHint().width();
+        totalHeight += item->sizeHint().height();
+    }
+
+    // use the average item width as the column width.
+    // Also include the spacing either side of each item as part of the 
+    // average width, this provides the spacing between the items and
+    // also allows some tolerance for small differences in item widths 
+    const qreal averageWidth = totalWidth / d->items.count() + 2*spacing();
+
+    const int columnCount = (int)(geometry.width() / averageWidth);
+
+    int insertColumn = 0;
+    qreal rowPos = 0;
+    qreal rowHeight = 0;
+
+    // lay the items out in left-to-right , top-to-bottom order
+    foreach( LayoutItem *item , d->items ) {
+    
+        const QSizeF& itemSize = item->sizeHint();
+
+        int columnSpan = (int)ceil(itemSize.width() / averageWidth);
+
+        if ( insertColumn + columnSpan > columnCount ) {
+            // start a new row
+            insertColumn = 0;
+            rowPos += rowHeight + spacing();
+        }
+
+       // qDebug() << "Inserting item at column" << insertColumn 
+       //          << "spanning" << columnSpan << "columns"
+       //          << "with offset" << offset;
+
+
+        // try to expand the item to fill its allocated number of columns
+        qreal itemWidth = itemSize.width(); 
+        const qreal idealWidth = columnSpan * averageWidth - spacing();
+        if ( itemWidth < idealWidth && 
+             idealWidth < item->maximumSize().width() ) {
+             itemWidth = idealWidth; 
+        }
+       
+        // calculate offset to horizontally center item 
+        qreal offset = (columnSpan * averageWidth) - itemWidth;
+        if ( insertColumn == 0 )
+            offset -= spacing();  
+        offset /= 2;
+
+        // try to restrict the item width to the available geometry's
+        // width
+        if ( itemWidth > geometry.width() ) {
+            itemWidth = qMax(geometry.width(),item->minimumSize().width());
+            offset = 0;
+        }        
+
+        // position the item
+        const QRectF newGeometry( geometry.left() + 
+                                    insertColumn * averageWidth + offset, 
+                                  geometry.top() + rowPos , 
+                                  itemWidth , 
+                                  itemSize.height() );
+
+        rowHeight = qMax(rowHeight,itemSize.height());
+        insertColumn += columnSpan;
+
+        if ( animator() )
+            animator()->setGeometry( item , newGeometry );
+        else
+            item->setGeometry( newGeometry );
+    }
+
+    d->geometry = geo;
+
+    if ( animator() && animator()->timeLine() )
+        animator()->timeLine()->start();
+}
+
+Qt::Orientations FlowLayout::expandingDirections() const
+{
+    return Qt::Vertical | Qt::Horizontal;
+}
+


_______________________________________________
Panel-devel mailing list
Panel-devel@kde.org
https://mail.kde.org/mailman/listinfo/panel-devel


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic