This breaks the existing Plasma applet API, see the contentSize()
comments below. * New Flow Layout. This provides simple icon view-esque layout of items. Useful for icons for documents , applications or other tasks on the desktop for example. Supports non-equally sized items. Works well when used with the LayoutAnimator class to animate insertions and removals. * Re-wrote BoxLayout and removed old HBoxLayout,VBoxLayout classes which had a lot of code duplication. BoxLayout class now takes a direction argument in the constructor, ala. QBoxLayout. New BoxLayout class actually takes minimumSize() , maximumSize() of items into account. The Qt layout code for box and grid layouts is surprisingly sophisticated, so the results from BoxLayout probably will not be as good in certain situations but it should do for the panel. New BoxLayout also has support for LayoutAnimator * Fix Plasma::HBoxLayout and Plasma::VBoxLayout to use margin() rather than spacing() for the distance from the top and left margins respectively. * Fix Plasma::Applet::contentSize() to return the actual content size rather than a size hint. Added a new method contentSizeHint() which applets use to provide a hint about suitable content size. Existing implementations of contentSize() in applets need to be renamed to contentSizeHint(). The arguments and return type are the same as before. * Install the LayoutAnimator header so that applets can use it svn path=/trunk/KDE/kdebase/workspace/libs/plasma/; revision=707275
This commit is contained in:
parent
04375c4b09
commit
a29ae57a7d
@ -33,8 +33,7 @@ set(plasma_LIB_SRCS
|
|||||||
karambamanager.cpp
|
karambamanager.cpp
|
||||||
widgets/boxlayout.cpp
|
widgets/boxlayout.cpp
|
||||||
widgets/checkbox.cpp
|
widgets/checkbox.cpp
|
||||||
widgets/hboxlayout.cpp
|
widgets/flowlayout.cpp
|
||||||
# widgets/flowlayout.cpp
|
|
||||||
widgets/flash.cpp
|
widgets/flash.cpp
|
||||||
widgets/icon.cpp
|
widgets/icon.cpp
|
||||||
widgets/label.cpp
|
widgets/label.cpp
|
||||||
@ -46,7 +45,6 @@ set(plasma_LIB_SRCS
|
|||||||
widgets/radiobutton.cpp
|
widgets/radiobutton.cpp
|
||||||
# widgets/rectangle.cpp
|
# widgets/rectangle.cpp
|
||||||
widgets/widget.cpp
|
widgets/widget.cpp
|
||||||
widgets/vboxlayout.cpp
|
|
||||||
widgets/signalplotter.cpp
|
widgets/signalplotter.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -105,17 +103,18 @@ install(FILES
|
|||||||
install(FILES
|
install(FILES
|
||||||
widgets/boxlayout.h
|
widgets/boxlayout.h
|
||||||
widgets/hboxlayout.h
|
widgets/hboxlayout.h
|
||||||
|
widgets/vboxlayout.h
|
||||||
widgets/flash.h
|
widgets/flash.h
|
||||||
widgets/icon.h
|
widgets/icon.h
|
||||||
widgets/label.h
|
widgets/label.h
|
||||||
widgets/layout.h
|
widgets/layout.h
|
||||||
|
widgets/layoutanimator.h
|
||||||
widgets/layoutitem.h
|
widgets/layoutitem.h
|
||||||
widgets/lineedit.h
|
widgets/lineedit.h
|
||||||
widgets/pushbutton.h
|
widgets/pushbutton.h
|
||||||
widgets/checkbox.h
|
widgets/checkbox.h
|
||||||
widgets/radiobutton.h
|
widgets/radiobutton.h
|
||||||
# widgets/rectangle.h
|
# widgets/rectangle.h
|
||||||
widgets/vboxlayout.h
|
|
||||||
widgets/widget.h
|
widgets/widget.h
|
||||||
widgets/signalplotter.h
|
widgets/signalplotter.h
|
||||||
DESTINATION ${INCLUDE_INSTALL_DIR}/plasma/widgets)
|
DESTINATION ${INCLUDE_INSTALL_DIR}/plasma/widgets)
|
||||||
|
26
applet.cpp
26
applet.cpp
@ -54,7 +54,7 @@
|
|||||||
#include "plasma/widgets/widget.h"
|
#include "plasma/widgets/widget.h"
|
||||||
#include "plasma/widgets/lineedit.h"
|
#include "plasma/widgets/lineedit.h"
|
||||||
#include "plasma/widgets/pushbutton.h"
|
#include "plasma/widgets/pushbutton.h"
|
||||||
#include "plasma/widgets/vboxlayout.h"
|
#include "plasma/widgets/boxlayout.h"
|
||||||
|
|
||||||
//#define DYNAMIC_SHADOWS
|
//#define DYNAMIC_SHADOWS
|
||||||
namespace Plasma
|
namespace Plasma
|
||||||
@ -300,7 +300,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (!background) {
|
if (!background) {
|
||||||
top = left = right = bottom = 0;
|
top = left = right = bottom = 0;
|
||||||
} else {
|
} else {
|
||||||
top = background->elementSize("top").height();
|
top = background->elementSize("top").height();
|
||||||
left = background->elementSize("left").width();
|
left = background->elementSize("left").width();
|
||||||
right = background->elementSize("right").width();
|
right = background->elementSize("right").width();
|
||||||
@ -568,7 +568,7 @@ void Applet::setFailedToLaunch(bool failed, const QString& reason)
|
|||||||
|
|
||||||
if (failed) {
|
if (failed) {
|
||||||
setDrawStandardBackground(true);
|
setDrawStandardBackground(true);
|
||||||
Layout* failureLayout = new VBoxLayout(this);
|
Layout* failureLayout = new BoxLayout(BoxLayout::TopToBottom,this);
|
||||||
d->failureText = new LineEdit(this, scene());
|
d->failureText = new LineEdit(this, scene());
|
||||||
d->failureText->setFlags(0);
|
d->failureText->setFlags(0);
|
||||||
d->failureText->setHtml(visibleFailureText(reason));
|
d->failureText->setHtml(visibleFailureText(reason));
|
||||||
@ -598,7 +598,7 @@ void Applet::setNeedsConfiguring(bool needsConfig)
|
|||||||
|
|
||||||
if (needsConfig) {
|
if (needsConfig) {
|
||||||
setDrawStandardBackground(true);
|
setDrawStandardBackground(true);
|
||||||
Layout* layout = new VBoxLayout(this);
|
Layout* layout = new BoxLayout(BoxLayout::TopToBottom,this);
|
||||||
PushButton* button = new PushButton(this);
|
PushButton* button = new PushButton(this);
|
||||||
button->setText(i18n("Configure..."));
|
button->setText(i18n("Configure..."));
|
||||||
connect(button, SIGNAL(clicked()), this, SLOT(performSetupConfig()));
|
connect(button, SIGNAL(clicked()), this, SLOT(performSetupConfig()));
|
||||||
@ -628,6 +628,9 @@ QRectF Applet::boundingRect() const
|
|||||||
int bottom;
|
int bottom;
|
||||||
|
|
||||||
d->getBorderSize(left,top,right,bottom);
|
d->getBorderSize(left,top,right,bottom);
|
||||||
|
|
||||||
|
|
||||||
|
//qDebug() << "Background , Border size" << d->background << left << top << right << bottom;
|
||||||
|
|
||||||
return rect.adjusted(-left,-top,right,bottom);
|
return rect.adjusted(-left,-top,right,bottom);
|
||||||
}
|
}
|
||||||
@ -641,7 +644,9 @@ QSizeF Applet::sizeHint() const
|
|||||||
|
|
||||||
d->getBorderSize(left,top,right,bottom);
|
d->getBorderSize(left,top,right,bottom);
|
||||||
|
|
||||||
return contentSize() + QSizeF(left+right,top+bottom);
|
//qDebug() << "Applet content size hint: " << contentSizeHint();
|
||||||
|
|
||||||
|
return contentSizeHint() + QSizeF(left+right,top+bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QAction*> Applet::contextActions()
|
QList<QAction*> Applet::contextActions()
|
||||||
@ -746,6 +751,17 @@ Location Applet::location() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
QSizeF Applet::contentSize() const
|
QSizeF Applet::contentSize() const
|
||||||
|
{
|
||||||
|
int top , left , right , bottom;
|
||||||
|
d->getBorderSize(left,top,right,bottom);
|
||||||
|
|
||||||
|
// qDebug() << "Geometry size: " << geometry().size();
|
||||||
|
// qDebug() << "Borders: " << left << top << right << bottom;
|
||||||
|
|
||||||
|
return geometry().size() - QSizeF(left+right,top+bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
QSizeF Applet::contentSizeHint() const
|
||||||
{
|
{
|
||||||
if (layout()) {
|
if (layout()) {
|
||||||
return layout()->sizeHint();
|
return layout()->sizeHint();
|
||||||
|
53
applet.h
53
applet.h
@ -197,39 +197,23 @@ class PLASMA_EXPORT Applet : public Widget
|
|||||||
Location location() const;
|
Location location() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a maximum size hint based on the Corona's space availability.
|
* Returns the area within which contents can be painted. If there is no
|
||||||
*
|
* background, then this is equivalent to boundingRect().size()
|
||||||
* An applet may choose to violate this size hint, but should try and
|
**/
|
||||||
* respect it as much as possible.
|
QSizeF contentSize() const;
|
||||||
*/
|
|
||||||
// QRectF maxSizeHint() const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the area within which contents can be painted. If there is no
|
* Returns an ideal size for the applet's content.
|
||||||
* background, then this is equivalent to boundingRect().
|
* Applets can re-implement this to provide a suitable size based
|
||||||
|
* on their contents.
|
||||||
*
|
*
|
||||||
* Applets should implement contentSize() to tell Plasma::Applet how
|
* Unlike sizeHint() , contentSizeHint() does not include the
|
||||||
* much space they need.
|
* size of any borders surrounding the content area.
|
||||||
*
|
*
|
||||||
* When drawing to the applet in the paintInterface() method, you can
|
* The default implementation returns the sizeHint() of the applet's
|
||||||
* use the QRect passed to that function. Outside paintInterface(), for
|
* layout if it has one, or a null size otherwise.
|
||||||
* example when positioning a Plasma::Widget, you can assume your drawing
|
*/
|
||||||
* area has (0,0) at the top left and is the size of contentSize().
|
virtual QSizeF contentSizeHint() const;
|
||||||
*
|
|
||||||
* If drawStandardBackground() == true, enough space will reserved
|
|
||||||
* within the borders for the content, and boundingRect() will the
|
|
||||||
* total size of the applet, including borders.
|
|
||||||
*
|
|
||||||
* If the applet has not asked Plasma::Applet to draw the default
|
|
||||||
* background, boundingRect().size() == contentSize(), and
|
|
||||||
* boundingRect().topLeft() == QPointF(0,0). Also, such applets will
|
|
||||||
* not break if they implement boundingRect() instead.
|
|
||||||
*
|
|
||||||
* Note that if the value returned by contentSize() (and hence
|
|
||||||
* boundingRect()) changes for any reason, you should call
|
|
||||||
* prepareGeometryChange() to notify the Corona.
|
|
||||||
**/
|
|
||||||
virtual QSizeF contentSize() const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of all known applets in a hash keyed by a unique
|
* Returns a list of all known applets in a hash keyed by a unique
|
||||||
@ -470,6 +454,11 @@ class PLASMA_EXPORT Applet : public Widget
|
|||||||
*/
|
*/
|
||||||
bool isShadowShown() const;
|
bool isShadowShown() const;
|
||||||
|
|
||||||
|
// reimplemented from LayoutItem
|
||||||
|
// value is the same as contentSizeHint() if drawStandardBackground() is false
|
||||||
|
// or contentSizeHint() plus the size of the border otherwise.
|
||||||
|
virtual QSizeF sizeHint() const;
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
/**
|
/**
|
||||||
* Emitted when the applet needs to take (or lose) keyboard focus.
|
* Emitted when the applet needs to take (or lose) keyboard focus.
|
||||||
@ -550,11 +539,7 @@ class PLASMA_EXPORT Applet : public Widget
|
|||||||
*/
|
*/
|
||||||
QVariant itemChange(GraphicsItemChange change, const QVariant &value);
|
QVariant itemChange(GraphicsItemChange change, const QVariant &value);
|
||||||
|
|
||||||
// reimplemented from LayoutItem
|
|
||||||
// value is the same as contentSize() if drawStandardBackground() is false
|
|
||||||
// or contentSize() plus the size of the border otherwise.
|
|
||||||
virtual QSizeF sizeHint() const;
|
|
||||||
|
|
||||||
protected Q_SLOTS:
|
protected Q_SLOTS:
|
||||||
/**
|
/**
|
||||||
* @internal used to show the configuration of an applet on first show
|
* @internal used to show the configuration of an applet on first show
|
||||||
|
23
corona.cpp
23
corona.cpp
@ -37,8 +37,7 @@
|
|||||||
#include "dataengine.h"
|
#include "dataengine.h"
|
||||||
#include "karambamanager.h"
|
#include "karambamanager.h"
|
||||||
#include "phase.h"
|
#include "phase.h"
|
||||||
#include "widgets/hboxlayout.h"
|
#include "widgets/boxlayout.h"
|
||||||
#include "widgets/vboxlayout.h"
|
|
||||||
#include "widgets/icon.h"
|
#include "widgets/icon.h"
|
||||||
|
|
||||||
using namespace Plasma;
|
using namespace Plasma;
|
||||||
@ -136,10 +135,10 @@ void Corona::setFormFactor(FormFactor formFactor)
|
|||||||
case Planar:
|
case Planar:
|
||||||
break;
|
break;
|
||||||
case Horizontal:
|
case Horizontal:
|
||||||
d->layout = new HBoxLayout;
|
d->layout = new BoxLayout(BoxLayout::LeftToRight);
|
||||||
break;
|
break;
|
||||||
case Vertical:
|
case Vertical:
|
||||||
d->layout = new VBoxLayout;
|
d->layout = new BoxLayout(BoxLayout::TopToBottom);
|
||||||
break;
|
break;
|
||||||
case MediaCenter:
|
case MediaCenter:
|
||||||
break;
|
break;
|
||||||
@ -224,17 +223,31 @@ Applet* Corona::addApplet(const QString& name, const QVariantList& args, uint id
|
|||||||
|
|
||||||
qreal appWidth = applet->boundingRect().width();
|
qreal appWidth = applet->boundingRect().width();
|
||||||
qreal appHeight = applet->boundingRect().height();
|
qreal appHeight = applet->boundingRect().height();
|
||||||
|
|
||||||
|
if (geometry.isValid()) {
|
||||||
|
applet->setGeometry(geometry);
|
||||||
|
} else {
|
||||||
|
applet->setGeometry( QRectF(geometry.topLeft(),applet->sizeHint()) );
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (!geometry.size().isValid()) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (geometry.isValid()) {
|
if (geometry.isValid()) {
|
||||||
applet->setGeometry(geometry);
|
applet->setGeometry(geometry);
|
||||||
} else if (geometry.x() != -1 && geometry.y() != -1) {
|
} else if (geometry.x() != -1 && geometry.y() != -1) {
|
||||||
// yes, this means we can't have items start -1, -1
|
// yes, this means we can't have items start -1, -1
|
||||||
applet->setPos(geometry.topLeft() - QPoint(applet->boundingRect().width()/2,
|
applet->setPos(geometry.topLeft() - QPointF(applet->boundingRect().width()/2,
|
||||||
applet->boundingRect().height()/2));
|
applet->boundingRect().height()/2));
|
||||||
} else {
|
} else {
|
||||||
//TODO: Make sure new applets don't overlap with existing ones
|
//TODO: Make sure new applets don't overlap with existing ones
|
||||||
// Center exactly:
|
// Center exactly:
|
||||||
applet->setPos((width() / 2) - (appWidth / 2), (height() / 2) - (appHeight / 2));
|
applet->setPos((width() / 2) - (appWidth / 2), (height() / 2) - (appHeight / 2));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
addItem(applet);
|
addItem(applet);
|
||||||
applet->updateConstraints();
|
applet->updateConstraints();
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2007 by Matias Valdenegro T. <mvaldenegro@informatica.utem.cl>
|
* Copyright 2007 by Matias Valdenegro T. <mvaldenegro@informatica.utem.cl>
|
||||||
|
* Copyright 2007 by Robert Knight <robertknight@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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 as
|
* it under the terms of the GNU Library General Public License version 2 as
|
||||||
@ -19,34 +20,253 @@
|
|||||||
#include "boxlayout.h"
|
#include "boxlayout.h"
|
||||||
|
|
||||||
#include <QtCore/QList>
|
#include <QtCore/QList>
|
||||||
|
#include <QtCore/QTimeLine>
|
||||||
|
|
||||||
#include <KDebug>
|
#include <KDebug>
|
||||||
|
|
||||||
|
#include "layoutanimator.h"
|
||||||
|
|
||||||
namespace Plasma
|
namespace Plasma
|
||||||
{
|
{
|
||||||
|
|
||||||
class BoxLayout::Private
|
class BoxLayout::Private
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QRectF geometry;
|
BoxLayout *const q;
|
||||||
QList<LayoutItem *> childList;
|
Direction direction;
|
||||||
Qt::Orientations orientation;
|
QRectF geometry;
|
||||||
|
QList<LayoutItem*> children;
|
||||||
|
|
||||||
|
Private(BoxLayout *parent)
|
||||||
|
: q(parent)
|
||||||
|
, direction(LeftToRight)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the component of 'size' in the expanding direction
|
||||||
|
// of this layout
|
||||||
|
qreal size(const QSizeF& size) const
|
||||||
|
{
|
||||||
|
switch (direction) {
|
||||||
|
case LeftToRight:
|
||||||
|
case RightToLeft:
|
||||||
|
return size.width();
|
||||||
|
case TopToBottom:
|
||||||
|
case BottomToTop:
|
||||||
|
return size.height();
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the direction in which this layout expands
|
||||||
|
// or shrinks
|
||||||
|
Qt::Orientation expandingDirection() const
|
||||||
|
{
|
||||||
|
switch ( direction ) {
|
||||||
|
case LeftToRight:
|
||||||
|
case RightToLeft:
|
||||||
|
return Qt::Horizontal;
|
||||||
|
case TopToBottom:
|
||||||
|
case BottomToTop:
|
||||||
|
return Qt::Vertical;
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
return Qt::Horizontal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the position from which layouting should
|
||||||
|
// begin depending on the direction of this layout
|
||||||
|
qreal startPos(const QRectF& geometry) const
|
||||||
|
{
|
||||||
|
switch ( direction ) {
|
||||||
|
case LeftToRight:
|
||||||
|
case TopToBottom:
|
||||||
|
return 0;
|
||||||
|
case RightToLeft:
|
||||||
|
return geometry.width();
|
||||||
|
case BottomToTop:
|
||||||
|
return geometry.height();
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lays out an item
|
||||||
|
//
|
||||||
|
// 'geometry' the geometry of the layout
|
||||||
|
// 'item' the item whoose geometry should be altered
|
||||||
|
// 'pos' the position of the item (in the expanding direction of the layout)
|
||||||
|
// 'size' the size of the item (in the expanding direction of the layout)
|
||||||
|
//
|
||||||
|
// returns the position for the next item in the layout
|
||||||
|
//
|
||||||
|
qreal layoutItem(const QRectF& geometry , LayoutItem *item , const qreal pos , qreal size)
|
||||||
|
{
|
||||||
|
//qDebug() << "layoutItem: " << direction << "item size" << size;
|
||||||
|
|
||||||
|
QRectF newGeometry;
|
||||||
|
qreal newPos = 0;
|
||||||
|
|
||||||
|
qreal top = 0;
|
||||||
|
qreal height = 0;
|
||||||
|
|
||||||
|
QSizeF minSize = item->minimumSize();
|
||||||
|
QSizeF maxSize = item->maximumSize();
|
||||||
|
switch ( direction ) {
|
||||||
|
case LeftToRight:
|
||||||
|
case RightToLeft:
|
||||||
|
height = qBound(minSize.height(),geometry.height(),maxSize.height());
|
||||||
|
top = geometry.top();
|
||||||
|
break;
|
||||||
|
case TopToBottom:
|
||||||
|
case BottomToTop:
|
||||||
|
height = qBound(minSize.width(),geometry.width(),maxSize.width());
|
||||||
|
top = geometry.left();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ( direction ) {
|
||||||
|
case LeftToRight:
|
||||||
|
newGeometry = QRectF(pos,top,size,height);
|
||||||
|
newPos = pos+size+q->spacing();
|
||||||
|
break;
|
||||||
|
case RightToLeft:
|
||||||
|
newGeometry = QRectF(geometry.width()-pos-size,top,
|
||||||
|
size,height);
|
||||||
|
newPos = pos-size-q->spacing();
|
||||||
|
break;
|
||||||
|
case TopToBottom:
|
||||||
|
newGeometry = QRectF(top,pos,height,size);
|
||||||
|
newPos = pos+size+q->spacing();
|
||||||
|
break;
|
||||||
|
case BottomToTop:
|
||||||
|
newGeometry = QRectF(top,geometry.height()-pos-size,
|
||||||
|
height,size);
|
||||||
|
newPos = pos-size-q->spacing();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// qDebug() << "Item geometry: " << newGeometry;
|
||||||
|
|
||||||
|
if ( q->animator() )
|
||||||
|
q->animator()->setGeometry(item,newGeometry);
|
||||||
|
else
|
||||||
|
item->setGeometry(newGeometry);
|
||||||
|
|
||||||
|
return newPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SizeType
|
||||||
|
{
|
||||||
|
MinSize,
|
||||||
|
MaxSize,
|
||||||
|
HintSize
|
||||||
|
};
|
||||||
|
|
||||||
|
// this provides a + function which can be passed as the 'op'
|
||||||
|
// argument to calculateSize
|
||||||
|
static qreal sum(const qreal a , const qreal b)
|
||||||
|
{
|
||||||
|
return a+b;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calcualtes a size hint or value for this layout
|
||||||
|
// 'sizeType' - The item size ( minimum , maximum , hint ) to use
|
||||||
|
// 'dir' - The direction component of the item size to use
|
||||||
|
// 'op' - A function to apply to the size of each item in the layout
|
||||||
|
// , usually qMax,qMin or sum
|
||||||
|
template <class T>
|
||||||
|
qreal calculateSize(SizeType sizeType , Qt::Orientation dir , T (*op)(T,T)) const
|
||||||
|
{
|
||||||
|
qreal value = 0;
|
||||||
|
for ( int i = 0 ; i < children.count() ; i++ ) {
|
||||||
|
|
||||||
|
QSizeF itemSize;
|
||||||
|
switch ( sizeType ) {
|
||||||
|
case MinSize:
|
||||||
|
itemSize = children[i]->minimumSize();
|
||||||
|
break;
|
||||||
|
case MaxSize:
|
||||||
|
itemSize = children[i]->maximumSize();
|
||||||
|
break;
|
||||||
|
case HintSize:
|
||||||
|
itemSize = children[i]->sizeHint();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( dir == Qt::Horizontal ) {
|
||||||
|
value = op(value,itemSize.width());
|
||||||
|
} else {
|
||||||
|
value = op(value,itemSize.height());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculates a size hint or value for this layout
|
||||||
|
// 'calculateSizeType' specifies the value to be calculated
|
||||||
|
QSizeF calculateSize(SizeType calculateSizeType) const
|
||||||
|
{
|
||||||
|
QSizeF result;
|
||||||
|
|
||||||
|
const qreal totalMargin = q->margin() * 2;
|
||||||
|
const qreal totalSpacing = q->spacing() * (children.count()-1);
|
||||||
|
|
||||||
|
switch ( direction ) {
|
||||||
|
case LeftToRight:
|
||||||
|
case RightToLeft:
|
||||||
|
result = QSizeF(calculateSize(calculateSizeType,Qt::Horizontal,sum),
|
||||||
|
calculateSize(calculateSizeType,Qt::Vertical,qMax<qreal>));
|
||||||
|
|
||||||
|
result.rwidth() += totalMargin + totalSpacing;
|
||||||
|
result.rheight() += totalMargin;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case TopToBottom:
|
||||||
|
case BottomToTop:
|
||||||
|
result = QSizeF(calculateSize(calculateSizeType,Qt::Horizontal,qMax<qreal>),
|
||||||
|
calculateSize(calculateSizeType,Qt::Vertical,sum));
|
||||||
|
|
||||||
|
result.rheight() += totalMargin + totalSpacing;
|
||||||
|
result.rwidth() += totalMargin;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
BoxLayout::BoxLayout(Qt::Orientations orientation, LayoutItem *parent)
|
BoxLayout::BoxLayout(Direction direction , LayoutItem *parent)
|
||||||
: Layout(parent),
|
: Layout(parent),
|
||||||
d(new Private)
|
d(new Private(this))
|
||||||
{
|
{
|
||||||
if (parent) {
|
if (parent) {
|
||||||
parent->setLayout(this);
|
parent->setLayout(this);
|
||||||
}
|
}
|
||||||
d->orientation = orientation;
|
|
||||||
|
d->direction = direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoxLayout::setDirection(Direction direction)
|
||||||
|
{
|
||||||
|
d->direction = direction;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
BoxLayout::Direction BoxLayout::direction() const
|
||||||
|
{
|
||||||
|
return d->direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
BoxLayout::~BoxLayout()
|
BoxLayout::~BoxLayout()
|
||||||
{
|
{
|
||||||
foreach (LayoutItem* item, children()) {
|
foreach (LayoutItem* item, d->children) {
|
||||||
item->unsetManagingLayout(this);
|
item->unsetManagingLayout(this);
|
||||||
}
|
}
|
||||||
delete d;
|
delete d;
|
||||||
@ -54,17 +274,17 @@ BoxLayout::~BoxLayout()
|
|||||||
|
|
||||||
Qt::Orientations BoxLayout::expandingDirections() const
|
Qt::Orientations BoxLayout::expandingDirections() const
|
||||||
{
|
{
|
||||||
return d->orientation;
|
switch ( d->direction ) {
|
||||||
}
|
case LeftToRight:
|
||||||
|
case RightToLeft:
|
||||||
QSizeF BoxLayout::minimumSize() const
|
return Qt::Horizontal;
|
||||||
{
|
case TopToBottom:
|
||||||
return QSizeF();
|
case BottomToTop:
|
||||||
}
|
return Qt::Vertical;
|
||||||
|
default:
|
||||||
QSizeF BoxLayout::maximumSize() const
|
Q_ASSERT(false);
|
||||||
{
|
return 0;
|
||||||
return QSizeF();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QRectF BoxLayout::geometry() const
|
QRectF BoxLayout::geometry() const
|
||||||
@ -72,162 +292,180 @@ QRectF BoxLayout::geometry() const
|
|||||||
return d->geometry;
|
return d->geometry;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BoxLayout::setGeometry(const QRectF& geometry)
|
|
||||||
{
|
|
||||||
if (!geometry.isValid() || geometry.isEmpty()) {
|
|
||||||
kDebug() << "Invalid Geometry " << geometry;
|
|
||||||
d->geometry = geometry;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
kDebug() << this << " Geometry process " << geometry << " for " << children().count() << " children";
|
|
||||||
|
|
||||||
QList<LayoutItem *> fixedChildren;
|
|
||||||
QList<LayoutItem *> expandingChildren;
|
|
||||||
QList<QSizeF> sizes;
|
|
||||||
QSizeF available = geometry.size() - QSizeF(2 * margin(), 2 * margin());
|
|
||||||
|
|
||||||
foreach (LayoutItem *l, children()) {
|
|
||||||
if (l->expandingDirections() & d->orientation) {
|
|
||||||
expandingChildren.append(l);
|
|
||||||
} else {
|
|
||||||
fixedChildren.append(l);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (LayoutItem *l, fixedChildren) {
|
|
||||||
QSizeF hint = l->sizeHint();
|
|
||||||
if ( d->orientation == Qt::Vertical ) {
|
|
||||||
sizes.insert(indexOf(l), QSizeF(available.width(), hint.height()));
|
|
||||||
available -= QSizeF(0.0, hint.height() + spacing());
|
|
||||||
} else {
|
|
||||||
sizes.insert(indexOf(l), QSizeF(hint.width(), available.height()));
|
|
||||||
available -= QSizeF(hint.width() + spacing(), 0.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expandingChildren.count() > 0) {
|
|
||||||
if ( d->orientation == Qt::Vertical ) {
|
|
||||||
qreal expandHeight = (available.height() - ((expandingChildren.count() - 1) * spacing())) / expandingChildren.count();
|
|
||||||
foreach (LayoutItem *l, expandingChildren) {
|
|
||||||
sizes.insert(indexOf(l),QSizeF(available.width(), expandHeight));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
qreal expandWidth = (available.width() - ((expandingChildren.count() - 1) * spacing())) / expandingChildren.count();
|
|
||||||
foreach (LayoutItem *l, expandingChildren) {
|
|
||||||
sizes.insert(indexOf(l), QSizeF(expandWidth, available.height()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QPointF start = geometry.topLeft();
|
|
||||||
start += QPointF(margin(), spacing());
|
|
||||||
|
|
||||||
for (int i = 0; i < sizes.size(); i++) {
|
|
||||||
LayoutItem *l = itemAt(i);
|
|
||||||
kDebug() << "Setting Geometry for child " << l << " to " << QRectF(start, sizes[i]);
|
|
||||||
l->setGeometry(QRectF(start, sizes[i]));
|
|
||||||
if ( d->orientation == Qt::Vertical ) {
|
|
||||||
start += QPointF(0.0, sizes[i].height() + spacing());
|
|
||||||
} else {
|
|
||||||
start += QPointF(sizes[i].width() + spacing(), 0.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
d->geometry = geometry;
|
|
||||||
}
|
|
||||||
|
|
||||||
QSizeF BoxLayout::sizeHint() const
|
|
||||||
{
|
|
||||||
qreal hintHeight = 0.0;
|
|
||||||
qreal hintWidth = 0.0;
|
|
||||||
|
|
||||||
foreach(LayoutItem *l, children()) {
|
|
||||||
|
|
||||||
QSizeF hint = l->sizeHint();
|
|
||||||
|
|
||||||
if ( d->orientation == Qt::Vertical ) {
|
|
||||||
hintWidth = qMax(hint.width(), hintWidth);
|
|
||||||
hintHeight += hint.height() + spacing();
|
|
||||||
} else {
|
|
||||||
hintHeight = qMax(hint.height(), hintHeight);
|
|
||||||
hintWidth += hint.width() + spacing();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hintWidth += 2 * margin();
|
|
||||||
hintHeight += 2 * margin();
|
|
||||||
|
|
||||||
return QSizeF(hintWidth, hintHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
int BoxLayout::count() const
|
int BoxLayout::count() const
|
||||||
{
|
{
|
||||||
return d->childList.count();
|
return d->children.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BoxLayout::isEmpty() const
|
void BoxLayout::insertItem(int index, LayoutItem *item)
|
||||||
{
|
{
|
||||||
return count() == 0;
|
if (!item) {
|
||||||
}
|
|
||||||
|
|
||||||
void BoxLayout::insertItem(int index, LayoutItem *l)
|
|
||||||
{
|
|
||||||
if (!l) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//l->setLayout(this);
|
item->setManagingLayout(this);
|
||||||
d->childList.insert(index, l);
|
|
||||||
setGeometry(geometry());
|
if ( index == -1 )
|
||||||
|
index = d->children.size();
|
||||||
|
|
||||||
|
d->children.insert(index, item);
|
||||||
|
|
||||||
|
if ( animator() )
|
||||||
|
animator()->setCurrentState(item,LayoutAnimator::InsertedState);
|
||||||
|
|
||||||
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BoxLayout::addItem(LayoutItem *l)
|
void BoxLayout::addItem(LayoutItem *item)
|
||||||
{
|
{
|
||||||
if (!l) {
|
insertItem(-1,item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoxLayout::removeItem(LayoutItem *item)
|
||||||
|
{
|
||||||
|
if (!item) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
l->setManagingLayout(this);
|
item->unsetManagingLayout(this);
|
||||||
d->childList.append(l);
|
d->children.removeAll(item);
|
||||||
setGeometry(geometry());
|
|
||||||
}
|
|
||||||
|
|
||||||
void BoxLayout::removeItem(LayoutItem *l)
|
if ( animator() )
|
||||||
{
|
animator()->setCurrentState(item,LayoutAnimator::RemovedState);
|
||||||
if (!l) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
l->unsetManagingLayout(this);
|
update();
|
||||||
d->childList.removeAll(l);
|
|
||||||
setGeometry(geometry());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int BoxLayout::indexOf(LayoutItem *l) const
|
int BoxLayout::indexOf(LayoutItem *l) const
|
||||||
{
|
{
|
||||||
return d->childList.indexOf(l);
|
return d->children.indexOf(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
LayoutItem *BoxLayout::itemAt(int i) const
|
LayoutItem *BoxLayout::itemAt(int i) const
|
||||||
{
|
{
|
||||||
return d->childList[i];
|
return d->children[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
LayoutItem *BoxLayout::takeAt(int i)
|
LayoutItem *BoxLayout::takeAt(int i)
|
||||||
{
|
{
|
||||||
return d->childList.takeAt(i);
|
return d->children.takeAt(i);
|
||||||
|
|
||||||
setGeometry(geometry());
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
QSizeF BoxLayout::size() const
|
void BoxLayout::setGeometry(const QRectF& geo)
|
||||||
{
|
{
|
||||||
return d->geometry.size();
|
QRectF geometry = geo.adjusted(margin(),margin(),-margin(),-margin());
|
||||||
|
|
||||||
|
//qDebug() << "geo before " << geo << "after" << geometry << "margin" << margin();
|
||||||
|
//qDebug() << "Box layout beginning with geo" << geometry;
|
||||||
|
//qDebug() << "This box max size" << maximumSize();
|
||||||
|
|
||||||
|
QVector<qreal> sizes(count());
|
||||||
|
QVector<qreal> expansionSpace(count());
|
||||||
|
|
||||||
|
qreal available = d->size(geometry.size()) - spacing()*(d->children.count()-1);
|
||||||
|
qreal perItemSize = available / count();
|
||||||
|
|
||||||
|
// initial distribution of space to items
|
||||||
|
for ( int i = 0 ; i < sizes.count() ; i++ ) {
|
||||||
|
const LayoutItem *item = d->children[i];
|
||||||
|
|
||||||
|
const bool isExpanding = item->expandingDirections() & d->expandingDirection();
|
||||||
|
|
||||||
|
if ( isExpanding )
|
||||||
|
sizes[i] = perItemSize;
|
||||||
|
else
|
||||||
|
sizes[i] = d->size(item->sizeHint());
|
||||||
|
|
||||||
|
const qreal minItemSize = d->size(item->minimumSize());
|
||||||
|
const qreal maxItemSize = d->size(item->maximumSize());
|
||||||
|
|
||||||
|
// qDebug() << "Layout max item " << i << "size: " << maxItemSize;
|
||||||
|
|
||||||
|
sizes[i] = qMin( sizes[i] , maxItemSize );
|
||||||
|
sizes[i] = qMax( sizes[i] , minItemSize );
|
||||||
|
|
||||||
|
// qDebug() << "Available: " << available << "per item:" << perItemSize <<
|
||||||
|
// "Initial size: " << sizes[i];
|
||||||
|
|
||||||
|
if ( isExpanding )
|
||||||
|
expansionSpace[i] = maxItemSize-sizes[i];
|
||||||
|
else
|
||||||
|
expansionSpace[i] = 0;
|
||||||
|
|
||||||
|
// adjust the per-item size if the space was over or under used
|
||||||
|
if ( sizes[i] != perItemSize && i != sizes.count()-1 ) {
|
||||||
|
perItemSize = available / (sizes.count()-i-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
available -= sizes[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// distribute out any remaining space to items which can still expand
|
||||||
|
//
|
||||||
|
// space is distributed equally amongst remaining items until we run
|
||||||
|
// out of space or items to expand
|
||||||
|
int expandable = sizes.count();
|
||||||
|
const qreal threshold = 1.0;
|
||||||
|
while ( available > threshold && expandable > 0 ) {
|
||||||
|
|
||||||
|
qreal extraSpace = available / expandable;
|
||||||
|
for ( int i = 0 ; i < sizes.count() ; i++ ) {
|
||||||
|
if ( expansionSpace[i] > threshold ) {
|
||||||
|
qreal oldSize = sizes[i];
|
||||||
|
|
||||||
|
sizes[i] += qMin(extraSpace,expansionSpace[i]);
|
||||||
|
|
||||||
|
expansionSpace[i] -= sizes[i]-oldSize;
|
||||||
|
available -= sizes[i]-oldSize;
|
||||||
|
} else {
|
||||||
|
expandable--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set items' geometry according to new sizes
|
||||||
|
qreal pos = d->startPos(geometry);
|
||||||
|
for ( int i = 0 ; i < sizes.count() ; i++ ) {
|
||||||
|
|
||||||
|
//QObject *obj = dynamic_cast<QObject*>(d->children[i]);
|
||||||
|
//if ( obj )
|
||||||
|
//qDebug() << "Item " << i << obj->metaObject()->className() << "size:" << sizes[i];
|
||||||
|
|
||||||
|
pos = d->layoutItem( geometry , d->children[i] , pos , sizes[i] );
|
||||||
|
}
|
||||||
|
|
||||||
|
d->geometry = geometry;
|
||||||
|
|
||||||
|
if ( animator() && animator()->timeLine() )
|
||||||
|
animator()->timeLine()->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<LayoutItem *> BoxLayout::children() const
|
|
||||||
|
QSizeF BoxLayout::maximumSize() const
|
||||||
{
|
{
|
||||||
return d->childList;
|
return Layout::maximumSize();
|
||||||
}
|
}
|
||||||
|
QSizeF BoxLayout::minimumSize() const
|
||||||
|
{
|
||||||
|
return d->calculateSize(Private::MinSize);
|
||||||
|
}
|
||||||
|
QSizeF BoxLayout::sizeHint() const
|
||||||
|
{
|
||||||
|
return d->calculateSize(Private::HintSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
HBoxLayout::HBoxLayout(LayoutItem *parent)
|
||||||
|
: BoxLayout(LeftToRight,parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VBoxLayout::VBoxLayout(LayoutItem *parent)
|
||||||
|
: BoxLayout(TopToBottom,parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // Plasma namespace
|
} // Plasma namespace
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2007 by Matias Valdenegro T. <mvaldenegro@informatica.utem.cl>
|
* Copyright 2007 by Matias Valdenegro T. <mvaldenegro@informatica.utem.cl>
|
||||||
|
* Copyright 2007 by Robert Knight <robertknight@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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 as
|
* it under the terms of the GNU Library General Public License version 2 as
|
||||||
@ -27,61 +28,89 @@
|
|||||||
namespace Plasma
|
namespace Plasma
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vertical Box Layout
|
* The BoxLayout class lays out items in a horizontal or vertical line.
|
||||||
*
|
|
||||||
* @author Matias Valdenegro T. <mvaldenegro@informatica.utem.cl>
|
|
||||||
*
|
|
||||||
* This class implements a generic box Layout used as a common API for VBox and HBox implementations.
|
|
||||||
*/
|
*/
|
||||||
class PLASMA_EXPORT BoxLayout : public Layout
|
class PLASMA_EXPORT BoxLayout : public Layout
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* This enum describes the directions in which items can be laid
|
||||||
|
* out.
|
||||||
|
*/
|
||||||
|
enum Direction
|
||||||
|
{
|
||||||
|
/** Lay items out horizontally, from left to right. */
|
||||||
|
LeftToRight,
|
||||||
|
/** Lay items out horizontally, from right to left. */
|
||||||
|
RightToLeft,
|
||||||
|
/** Lay items out vertically, from top to bottom. */
|
||||||
|
TopToBottom,
|
||||||
|
/** Lay items out vertically, from bottom to top. */
|
||||||
|
BottomToTop
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Creates a new box layout which lays items out in the specified
|
||||||
*/
|
* @p direction
|
||||||
explicit BoxLayout(Qt::Orientations orientation, LayoutItem *parent = 0);
|
*/
|
||||||
|
explicit BoxLayout(Direction direction , LayoutItem *parent = 0);
|
||||||
/**
|
|
||||||
* Destructor.
|
|
||||||
*/
|
|
||||||
~BoxLayout();
|
~BoxLayout();
|
||||||
|
|
||||||
Qt::Orientations expandingDirections() const;
|
/** Sets the direction in which items are laid out. */
|
||||||
|
void setDirection(Direction direction);
|
||||||
QSizeF minimumSize() const;
|
/** Returns the direction in which items are laid out. */
|
||||||
QSizeF maximumSize() const;
|
Direction direction() const;
|
||||||
|
|
||||||
QRectF geometry() const;
|
|
||||||
void setGeometry(const QRectF& geometry);
|
|
||||||
|
|
||||||
QSizeF sizeHint() const;
|
|
||||||
|
|
||||||
int count() const;
|
|
||||||
|
|
||||||
bool isEmpty() const;
|
|
||||||
|
|
||||||
|
/** Inserts a new item into the layout at the specified index. */
|
||||||
void insertItem(int index, LayoutItem *l);
|
void insertItem(int index, LayoutItem *l);
|
||||||
void addItem(LayoutItem *l);
|
|
||||||
|
// reimplemented from Layout
|
||||||
|
virtual void addItem(LayoutItem *l);
|
||||||
|
virtual void removeItem(LayoutItem *l);
|
||||||
|
virtual int indexOf(LayoutItem *l) const;
|
||||||
|
virtual LayoutItem *itemAt(int i) const;
|
||||||
|
virtual LayoutItem *takeAt(int i);
|
||||||
|
virtual Qt::Orientations expandingDirections() const;
|
||||||
|
virtual QRectF geometry() const;
|
||||||
|
virtual void setGeometry(const QRectF& geometry);
|
||||||
|
virtual int count() const;
|
||||||
|
|
||||||
void removeItem(LayoutItem *l);
|
virtual QSizeF minimumSize() const;
|
||||||
|
virtual QSizeF maximumSize() const;
|
||||||
int indexOf(LayoutItem *l) const;
|
virtual QSizeF sizeHint() const;
|
||||||
LayoutItem *itemAt(int i) const;
|
|
||||||
LayoutItem *takeAt(int i);
|
|
||||||
|
|
||||||
QSizeF size() const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
QList<LayoutItem *> children() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Private;
|
class Private;
|
||||||
Private *const d;
|
Private *const d;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A BoxLayout which defaults to laying items out
|
||||||
|
* horizontally in a left-to-right order.
|
||||||
|
*
|
||||||
|
* Equivalent to creating a BoxLayout and passing LeftToRight
|
||||||
|
* in the constructor.
|
||||||
|
*/
|
||||||
|
class PLASMA_EXPORT HBoxLayout : public BoxLayout
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit HBoxLayout(LayoutItem *parent = 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A BoxLayout which defaults to laying items out
|
||||||
|
* vertically in a top-to-bottom order.
|
||||||
|
*
|
||||||
|
* Equivalent to creating a BoxLayout and passing TopToBottom
|
||||||
|
* in the constructor.
|
||||||
|
*/
|
||||||
|
class PLASMA_EXPORT VBoxLayout : public BoxLayout
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit VBoxLayout(LayoutItem *parent = 0);
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _H_BOX_LAYOUT__ */
|
#endif /* PLASMA_BOX_LAYOUT */
|
||||||
|
204
widgets/flowlayout.cpp
Normal file
204
widgets/flowlayout.cpp
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
|
64
widgets/flowlayout.h
Normal file
64
widgets/flowlayout.h
Normal file
@ -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__
|
||||||
|
|
@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2007 by Matias Valdenegro T. <mvaldenegro@informatica.utem.cl>
|
|
||||||
*
|
|
||||||
* 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 as
|
|
||||||
* published by the Free Software Foundation
|
|
||||||
*
|
|
||||||
* 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 "hboxlayout.h"
|
|
||||||
|
|
||||||
namespace Plasma
|
|
||||||
{
|
|
||||||
|
|
||||||
HBoxLayout::HBoxLayout(LayoutItem *parent)
|
|
||||||
: BoxLayout(Qt::Horizontal, parent),
|
|
||||||
d(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
HBoxLayout::~HBoxLayout()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HBoxLayout::hasWidthForHeight() const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
qreal HBoxLayout::widthForHeight(qreal w) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(w);
|
|
||||||
return qreal();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2007 by Matias Valdenegro T. <mvaldenegro@informatica.utem.cl>
|
* Copyright 2007 by Robert Knight <robertknight@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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 as
|
* it under the terms of the GNU Library General Public License version 2 as
|
||||||
@ -16,48 +16,9 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __H_BOX_LAYOUT__
|
#ifndef PLASMA_HBOXLAYOUT
|
||||||
#define __H_BOX_LAYOUT__
|
#define PLASMA_HBOXLAYOUT
|
||||||
|
|
||||||
#include <QtCore/QRectF>
|
|
||||||
#include <QtCore/QSizeF>
|
|
||||||
|
|
||||||
#include <plasma/plasma_export.h>
|
|
||||||
#include <plasma/widgets/boxlayout.h>
|
#include <plasma/widgets/boxlayout.h>
|
||||||
|
|
||||||
namespace Plasma
|
#endif /* PLASMA_HBOXLAYOUT */
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Horizontal Box Layout
|
|
||||||
*
|
|
||||||
* @author Matias Valdenegro T. <mvaldenegro@informatica.utem.cl>
|
|
||||||
*
|
|
||||||
* This class implements a Horizontal Box Layout, it just lays items horizontally, from left to right.
|
|
||||||
*/
|
|
||||||
class PLASMA_EXPORT HBoxLayout : public BoxLayout
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor.
|
|
||||||
*/
|
|
||||||
HBoxLayout(LayoutItem *parent = 0);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Virtual Destructor.
|
|
||||||
*/
|
|
||||||
virtual ~HBoxLayout();
|
|
||||||
|
|
||||||
bool hasWidthForHeight() const;
|
|
||||||
qreal widthForHeight(qreal w) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
class Private;
|
|
||||||
Private *const d;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* __H_BOX_LAYOUT__ */
|
|
||||||
|
@ -10,8 +10,7 @@
|
|||||||
|
|
||||||
#include "../pushbutton.h"
|
#include "../pushbutton.h"
|
||||||
#include "../lineedit.h"
|
#include "../lineedit.h"
|
||||||
#include "../vboxlayout.h"
|
#include "../boxlayout.h"
|
||||||
#include "../hboxlayout.h"
|
|
||||||
#include "../widget.h"
|
#include "../widget.h"
|
||||||
#include "../label.h"
|
#include "../label.h"
|
||||||
|
|
||||||
@ -54,14 +53,16 @@ int main(int argc, char **argv)
|
|||||||
h2->addItem(pushTwo);
|
h2->addItem(pushTwo);
|
||||||
scene.addItem(pushTwo);
|
scene.addItem(pushTwo);
|
||||||
|
|
||||||
Plasma::LineEdit *editTwo = new Plasma::LineEdit;
|
Plasma::LineEdit *editTwo = new Plasma::LineEdit;
|
||||||
h2->addItem(editTwo);
|
h2->addItem(editTwo);
|
||||||
scene.addItem(editTwo);
|
scene.addItem(editTwo);
|
||||||
|
|
||||||
Plasma::Label *labelTwo = new Plasma::Label( 0 );
|
Plasma::Label *labelTwo = new Plasma::Label( 0 );
|
||||||
labelTwo->setText( "hello world 2" );
|
labelTwo->setText( "hello world 2" );
|
||||||
h2->addItem(labelTwo);
|
h2->addItem(labelTwo);
|
||||||
scene.addItem(labelTwo);
|
scene.addItem(labelTwo);
|
||||||
|
|
||||||
|
widgetLayout->update();
|
||||||
|
|
||||||
view.show();
|
view.show();
|
||||||
return app.exec();
|
return app.exec();
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2007 by Matias Valdenegro T. <mvaldenegro@informatica.utem.cl>
|
|
||||||
*
|
|
||||||
* 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 as
|
|
||||||
* published by the Free Software Foundation
|
|
||||||
*
|
|
||||||
* 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 "vboxlayout.h"
|
|
||||||
|
|
||||||
namespace Plasma
|
|
||||||
{
|
|
||||||
|
|
||||||
VBoxLayout::VBoxLayout(LayoutItem *parent)
|
|
||||||
: BoxLayout(Qt::Vertical, parent),
|
|
||||||
d(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
VBoxLayout::~VBoxLayout()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VBoxLayout::hasHeightForWidth() const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
qreal VBoxLayout::heightForWidth(qreal w) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(w);
|
|
||||||
return qreal();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2007 by Matias Valdenegro T. <mvaldenegro@informatica.utem.cl>
|
* Copyright 2007 by Robert Knight <robertknight@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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 as
|
* it under the terms of the GNU Library General Public License version 2 as
|
||||||
@ -19,42 +19,6 @@
|
|||||||
#ifndef PLASMA_VBOXLAYOUT
|
#ifndef PLASMA_VBOXLAYOUT
|
||||||
#define PLASMA_VBOXLAYOUT
|
#define PLASMA_VBOXLAYOUT
|
||||||
|
|
||||||
#include <plasma/plasma_export.h>
|
|
||||||
#include <plasma/widgets/boxlayout.h>
|
#include <plasma/widgets/boxlayout.h>
|
||||||
|
|
||||||
namespace Plasma
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Vertical Box Layout
|
|
||||||
*
|
|
||||||
* @author Matias Valdenegro T. <mvaldenegro@informatica.utem.cl>
|
|
||||||
*
|
|
||||||
* This class implements a Vertical Box Layout, it just lays items in vertical, from up to down.
|
|
||||||
*/
|
|
||||||
class PLASMA_EXPORT VBoxLayout : public BoxLayout
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor.
|
|
||||||
*/
|
|
||||||
explicit VBoxLayout(LayoutItem *parent = 0);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Virtual Destructor.
|
|
||||||
*/
|
|
||||||
~VBoxLayout();
|
|
||||||
|
|
||||||
bool hasHeightForWidth() const;
|
|
||||||
qreal heightForWidth(qreal w) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
class Private;
|
|
||||||
Private *const d;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* PLASMA_VBOXLAYOUT */
|
#endif /* PLASMA_VBOXLAYOUT */
|
||||||
|
Loading…
Reference in New Issue
Block a user