NodeLayout:
* initial implementation of sizeHint() * support for automatic sizing (on one or two dimensions) * simplified node definition svn path=/trunk/KDE/kdebase/workspace/libs/plasma/; revision=724794
This commit is contained in:
parent
108c3e323f
commit
04f5730e1e
@ -42,6 +42,7 @@ set(plasma_LIB_SRCS
|
||||
widgets/borderlayout.cpp
|
||||
widgets/checkbox.cpp
|
||||
widgets/freelayout.cpp
|
||||
widgets/nodelayout.cpp
|
||||
widgets/flowlayout.cpp
|
||||
widgets/flash.cpp
|
||||
widgets/icon.cpp
|
||||
@ -122,6 +123,7 @@ install(FILES
|
||||
install(FILES
|
||||
widgets/boxlayout.h
|
||||
widgets/borderlayout.h
|
||||
widgets/nodelayout.h
|
||||
widgets/hboxlayout.h
|
||||
widgets/vboxlayout.h
|
||||
widgets/freelayout.h
|
||||
|
236
widgets/nodelayout.cpp
Normal file
236
widgets/nodelayout.cpp
Normal file
@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Library/Lesser General Public License
|
||||
* version 2, or (at your option) any later version, 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/Lesser 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 "nodelayout.h"
|
||||
|
||||
#include <QPair>
|
||||
#include <QMap>
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
NodeLayout::NodeCoordinate::NodeCoordinate(qreal xRelative, qreal yRelative, qreal xAbsolute, qreal yAbsolute)
|
||||
: xr(xRelative), xa(xAbsolute), yr(yRelative), ya(yAbsolute) {};
|
||||
|
||||
NodeLayout::NodeCoordinate NodeLayout::NodeCoordinate::simple(qreal x, qreal y,
|
||||
CoordinateType xType, CoordinateType yType)
|
||||
{
|
||||
NodeLayout::NodeCoordinate coo;
|
||||
switch (xType) {
|
||||
case Relative:
|
||||
coo.xr = x;
|
||||
coo.xa = 0;
|
||||
break;
|
||||
case Absolute:
|
||||
coo.xr = 0;
|
||||
coo.xa = x;
|
||||
break;
|
||||
case InnerRelative:
|
||||
coo.xr = x;
|
||||
coo.xa = INFINITY;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (yType) {
|
||||
case Relative:
|
||||
coo.yr = y;
|
||||
coo.ya = 0;
|
||||
break;
|
||||
case Absolute:
|
||||
coo.yr = 0;
|
||||
coo.ya = y;
|
||||
break;
|
||||
case InnerRelative:
|
||||
coo.yr = y;
|
||||
coo.ya = INFINITY;
|
||||
break;
|
||||
}
|
||||
return coo;
|
||||
}
|
||||
|
||||
class NodeLayout::Private {
|
||||
public:
|
||||
QMap <LayoutItem * , QPair < NodeCoordinate, NodeCoordinate > > items;
|
||||
QRectF geometry;
|
||||
QSizeF sizeHint;
|
||||
|
||||
qreal calculateXPosition(const NodeCoordinate & coo, const QRectF & parentGeometry) const
|
||||
{
|
||||
return parentGeometry.left() + (coo.xr * parentGeometry.width()) + coo.xa;
|
||||
}
|
||||
|
||||
qreal calculateYPosition(const NodeCoordinate & coo, const QRectF & parentGeometry) const
|
||||
{
|
||||
return parentGeometry.top() + (coo.yr * parentGeometry.height()) + coo.ya;
|
||||
}
|
||||
|
||||
QPointF calculatePosition(const NodeCoordinate & coo, const QRectF & parentGeometry) const
|
||||
{
|
||||
return QPointF(
|
||||
calculateXPosition(coo, geometry),
|
||||
calculateYPosition(coo, geometry)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
QRectF calculateRectangle(LayoutItem * item, QRectF geometry = QRectF()) const
|
||||
{
|
||||
if (geometry == QRectF()) geometry = this->geometry;
|
||||
|
||||
QRectF result;
|
||||
if (!item || !items.contains(item)) return QRectF();
|
||||
|
||||
result.setTopLeft(calculatePosition(items[item].first, geometry));
|
||||
|
||||
if (items[item].second.xa != INFINITY) {
|
||||
result.setRight(calculateXPosition(items[item].second, geometry));
|
||||
} else {
|
||||
result.setWidth(item->sizeHint().width());
|
||||
result.moveLeft(result.left() - items[item].second.xr * result.width());
|
||||
}
|
||||
|
||||
if (items[item].second.ya != INFINITY) {
|
||||
result.setBottom(calculateYPosition(items[item].second, geometry));
|
||||
} else {
|
||||
result.setHeight(item->sizeHint().height());
|
||||
result.moveTop(result.top() - items[item].second.yr * result.height());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void invalidate()
|
||||
{
|
||||
foreach (LayoutItem * item, items.keys()) {
|
||||
if (item) {
|
||||
item->setGeometry(calculateRectangle(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void calculateSizeHint(LayoutItem * item = NULL) {
|
||||
if (item == NULL) {
|
||||
// Recalculate the sizeHint using all items
|
||||
sizeHint = QSizeF();
|
||||
foreach (LayoutItem * item, items.keys()) {
|
||||
if (item) {
|
||||
calculateSizeHint(item);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Calculate size hint for current item
|
||||
QRectF scaled = calculateRectangle(item, QRectF(0, 0, 1, 1));
|
||||
|
||||
// qMin(..., 1.0) so that for autosized elements we don't get smaller
|
||||
// size than the item's size itself. The sizeHint for NodeLayout can
|
||||
// not do anything smarter concerning the sizeHint when there are
|
||||
// autosized elements.
|
||||
|
||||
qreal width = item->sizeHint().width() / qMin(scaled.width(), 1.0);
|
||||
qreal height = item->sizeHint().height() / qMin(scaled.height(), 1.0);
|
||||
|
||||
if (width > sizeHint.width()) sizeHint.setWidth(width);
|
||||
if (height > sizeHint.height()) sizeHint.setHeight(height);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
NodeLayout::NodeLayout(LayoutItem * parent)
|
||||
: Layout(parent), d(new Private())
|
||||
{
|
||||
}
|
||||
|
||||
NodeLayout::~NodeLayout()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
Qt::Orientations NodeLayout::expandingDirections() const
|
||||
{
|
||||
return Qt::Horizontal | Qt::Vertical;
|
||||
}
|
||||
|
||||
QRectF NodeLayout::geometry() const
|
||||
{
|
||||
return d->geometry;
|
||||
}
|
||||
|
||||
void NodeLayout::setGeometry(const QRectF& geometry)
|
||||
{
|
||||
if (!geometry.isValid() || geometry.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
d->geometry = geometry;
|
||||
d->invalidate();
|
||||
}
|
||||
|
||||
QSizeF NodeLayout::sizeHint() const
|
||||
{
|
||||
return d->sizeHint;
|
||||
}
|
||||
|
||||
void NodeLayout::addItem (LayoutItem * item)
|
||||
{
|
||||
NodeLayout::addItem (item, NodeCoordinate());
|
||||
}
|
||||
|
||||
void NodeLayout::addItem (LayoutItem * item, NodeCoordinate topLeft, NodeCoordinate bottomRight)
|
||||
{
|
||||
d->items[item] = QPair<NodeCoordinate, NodeCoordinate>(topLeft, bottomRight);
|
||||
d->calculateSizeHint(item);
|
||||
}
|
||||
|
||||
void NodeLayout::addItem (LayoutItem * item, NodeCoordinate node, qreal xr, qreal yr)
|
||||
{
|
||||
d->items[item] = QPair<NodeCoordinate, NodeCoordinate>(node,
|
||||
NodeCoordinate::simple(xr, yr, NodeCoordinate::InnerRelative, NodeCoordinate::InnerRelative));
|
||||
d->calculateSizeHint(item);
|
||||
}
|
||||
|
||||
void NodeLayout::removeItem (LayoutItem * item)
|
||||
{
|
||||
d->items.remove(item);
|
||||
d->calculateSizeHint();
|
||||
}
|
||||
|
||||
int NodeLayout::count() const
|
||||
{
|
||||
return d->items.count();
|
||||
}
|
||||
|
||||
int NodeLayout::indexOf(LayoutItem * item) const
|
||||
{
|
||||
return d->items.keys().indexOf(item);
|
||||
}
|
||||
|
||||
LayoutItem * NodeLayout::itemAt(int i) const
|
||||
{
|
||||
return d->items.keys()[i];
|
||||
}
|
||||
|
||||
LayoutItem * NodeLayout::takeAt(int i)
|
||||
{
|
||||
LayoutItem * item = itemAt(i);
|
||||
removeItem(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
}
|
119
widgets/nodelayout.h
Normal file
119
widgets/nodelayout.h
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Library/Lesser General Public License
|
||||
* version 2, or (at your option) any later version, 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/Lesser 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 PLASMA_NODE_LAYOUT
|
||||
#define PLASMA_NODE_LAYOUT
|
||||
|
||||
#include <QtCore/QMap>
|
||||
#include <cmath>
|
||||
|
||||
#include <plasma/plasma_export.h>
|
||||
#include <plasma/plasma.h>
|
||||
#include <plasma/widgets/layout.h>
|
||||
|
||||
namespace Plasma {
|
||||
|
||||
/**
|
||||
* Node layout has an advanced layouting mechanism. Every item's position
|
||||
* is defined by two nodes - one for top-left corner, and the other one for
|
||||
* bottom-right corner.
|
||||
*
|
||||
* Each node is defined by a pair of relative (xr, yr) and a pair of
|
||||
* absolute (xa, ya) coordinates. The calculated node coordinates depend
|
||||
* on the size and position of the NodeLayout object in the following
|
||||
* manner:
|
||||
* x = layoutLeft + (xr * layoutWidth) + xa
|
||||
* y = layoutTop + (yr * layoutHeight) + ya
|
||||
*
|
||||
* Alternatively, the item's position can be defined by using one node and
|
||||
* one pair of relative coordinates (xr, yr). In that case, the item is sized
|
||||
* following the sizeHint(). The relative coordinates (this time they are
|
||||
* relative to the item's geometry, not the layout's) specify what point of
|
||||
* the item will be bound to the defined node.
|
||||
*/
|
||||
|
||||
class PLASMA_EXPORT NodeLayout : public Layout {
|
||||
public:
|
||||
class PLASMA_EXPORT NodeCoordinate {
|
||||
public:
|
||||
/**
|
||||
* Position is calculated:
|
||||
* x = parentLeft + (xRelative * parentWidth) + xAbsolute
|
||||
* y = parentTop + (yRelative * parentHeight) + yAbsolute
|
||||
*/
|
||||
NodeCoordinate(qreal xRelative = 0, qreal yRelative = 0, qreal xAbsolute = 0, qreal yAbsolute = 0);
|
||||
|
||||
enum CoordinateType {
|
||||
Relative = 0,
|
||||
Absolute = 1,
|
||||
InnerRelative = 2 };
|
||||
|
||||
static NodeCoordinate simple(qreal x, qreal y, CoordinateType xType = Relative, CoordinateType yType = Relative);
|
||||
|
||||
float xr, xa;
|
||||
float yr, ya;
|
||||
};
|
||||
|
||||
// reimplemented
|
||||
virtual Qt::Orientations expandingDirections() const;
|
||||
|
||||
explicit NodeLayout(LayoutItem * parent = 0);
|
||||
virtual ~NodeLayout();
|
||||
|
||||
virtual QRectF geometry() const;
|
||||
void setGeometry(const QRectF& geometry);
|
||||
|
||||
QSizeF sizeHint() const;
|
||||
|
||||
/**
|
||||
* Adds item at top-left corner, with automatic sizing
|
||||
* (using sizeHint of the item)
|
||||
*/
|
||||
void addItem (LayoutItem * item);
|
||||
|
||||
/**
|
||||
* Adds item with specified top-left and bottom right corners.
|
||||
*/
|
||||
void addItem (LayoutItem * item,
|
||||
NodeCoordinate topLeft, NodeCoordinate bottomRight);
|
||||
|
||||
/**
|
||||
* Adds item with automatic sizing turned on. xr and yr specify
|
||||
* which point of the item is bound to node coordinate. Those
|
||||
* are relative coordinates so (0, 0) represent top left corner,
|
||||
* (0.5, 0.5) represent the center of the item etc.
|
||||
*/
|
||||
void addItem (LayoutItem * item,
|
||||
NodeCoordinate node, qreal xr = 0, qreal yr = 0);
|
||||
|
||||
void removeItem (LayoutItem * item);
|
||||
|
||||
virtual int count() const;
|
||||
virtual int indexOf(LayoutItem * item) const;
|
||||
virtual LayoutItem * itemAt(int i) const;
|
||||
virtual LayoutItem * takeAt(int i);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* PLASMA_NODE_LAYOUT */
|
Loading…
Reference in New Issue
Block a user