slight improvement to the context view layout imo.
[amarok.git] / src / context / layouts / ContextLayout.cpp
blob3f88befa52c05df061390a204e23522a628c90f0
1 /*
2 * Copyright 2007 by Robert Knight <robertknight@gmail.com>
3 * Copyright 2007 by Leo Franchi <lfranchi@gmail.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Library General Public License
7 * as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details
15 * You should have received a copy of the GNU Library General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "ContextLayout.h"
23 #include <limits.h>
24 #include <math.h>
26 #include "kdebug.h"
27 #include <QtCore/QList>
28 #include <QtCore/QRectF>
29 #include <QtCore/QTimeLine>
31 #include <QtDebug>
33 #include "plasma/layouts/layoutanimator.h"
35 using namespace Context;
37 class ContextLayout::Private
39 public:
40 Private() : columnWidth( -1 ) {}
41 QList<LayoutItem*> items;
42 qreal columnWidth;
45 ContextLayout::ContextLayout(LayoutItem* parent)
46 : Layout(parent)
47 , d(new Private)
50 ContextLayout::~ContextLayout()
52 delete d;
55 int ContextLayout::count() const
57 return d->items.count();
60 void ContextLayout::addItem(LayoutItem* item)
62 if (d->items.contains(item)) {
63 return;
66 d->items << item;
68 if (animator()) {
69 animator()->setCurrentState(item,Plasma::LayoutAnimator::InsertedState);
72 item->setManagingLayout(this);
74 void ContextLayout::removeItem(LayoutItem* item)
76 item->unsetManagingLayout(this);
77 d->items.removeAll(item);
79 if (animator()) {
80 animator()->setCurrentState(item,Plasma::LayoutAnimator::RemovedState);
83 int ContextLayout::indexOf(LayoutItem* item) const
85 return d->items.indexOf(item);
88 Plasma::LayoutItem* ContextLayout::itemAt(int i) const
90 return d->items[i];
92 QSizeF ContextLayout::sizeHint() const
94 // TODO A proper algorithm here
95 //
96 // Idea: Return a size hint based on the golden ratio to
97 // make it aesthetically good
98 // eg. Longer side is 1.61x the length of the shorter side
101 // testing
102 return QSizeF(500,500);
105 Plasma::LayoutItem* ContextLayout::takeAt(int i)
107 return d->items.takeAt(i);
110 template <class T>
111 T qSum(const QList<T>& container)
113 T total = 0;
114 foreach( const T& item , container ) {
115 total += item;
117 return total;
120 void ContextLayout::relayout()
122 QRectF rect = geometry().adjusted(margin(LeftMargin), margin(TopMargin), -margin(RightMargin), -margin(BottomMargin));
124 qDebug() << "Context layout geometry set to " << geometry() << " using column width: " << d->columnWidth;
125 const int columnCount = qMax( (int)(rect.width() / d->columnWidth), 1 ); //use at least one column
127 int insertColumn = 0;
128 qreal rowPos = 0;
129 qreal rowHeight = 0;
131 // lay the items out in left-to-right , top-to-bottom order
132 foreach( LayoutItem *item , d->items ) {
134 const QSizeF& itemSize = item->sizeHint();
136 int columnSpan = (int)ceil(itemSize.width() / d->columnWidth);
138 if ( insertColumn + columnSpan > columnCount ) {
139 // start a new row
140 insertColumn = 0;
141 rowPos += rowHeight + spacing();
144 // qDebug() << "Inserting item at column" << insertColumn
145 // << "spanning" << columnSpan << "columns"
146 // << "with offset" << offset;
149 // try to expand the item to fill its allocated number of columns
150 qreal itemWidth = itemSize.width();
151 const qreal idealWidth = columnSpan * d->columnWidth - spacing();
152 if ( itemWidth < idealWidth &&
153 idealWidth < item->maximumSize().width() ) {
154 itemWidth = idealWidth;
157 // calculate offset to horizontally center item
158 //if there is space for only one column,
159 //center the item relative to the whole available rectangle
160 qreal offset;
161 if( columnCount > 1 ) {
162 offset = (columnSpan * d->columnWidth) - itemWidth;
163 } else {
164 offset = rect.width() - itemWidth;
166 if( columnCount > 1 ) { //no need for spacing if there is only one column
167 offset -= spacing() / 4;
169 if( offset < 0 )
171 offset = 0;
173 offset /= 2;
175 // try to restrict the item width to the available geometry's
176 // width
177 if ( itemWidth > rect.width() ) {
178 itemWidth = qMax(rect.width(),item->minimumSize().width());
179 offset = 0;
182 // position the item
183 qreal itemHeight;
184 if( item->hasHeightForWidth() )
185 itemHeight = item->heightForWidth( itemWidth );
186 else
187 itemHeight = itemSize.height(); // this is not good, applets should provide heightForWidth
189 const QRectF newGeometry(rect.left() + insertColumn * d->columnWidth + offset,
190 rect.top() + margin( TopMargin ) + rowPos,
191 itemWidth,
192 itemHeight );
194 rowHeight = qMax(rowHeight,itemHeight);
195 insertColumn += columnSpan;
197 kDebug() << "Setting a child item geometry to:" << newGeometry;
198 if ( animator() )
199 animator()->setGeometry( item , newGeometry );
200 else
201 item->setGeometry( newGeometry );
204 startAnimation();
207 Qt::Orientations ContextLayout::expandingDirections() const
209 return Qt::Vertical | Qt::Horizontal;
212 qreal ContextLayout::columnWidth() const
214 return d->columnWidth;
217 void ContextLayout::setColumnWidth( const qreal width )
219 d->columnWidth = width;