~ubuntu-branches/ubuntu/oneiric/kdeplasma-addons/oneiric

« back to all changes in this revision

Viewing changes to libs/lancelot/layouts/NodeLayout.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Thomas
  • Date: 2010-05-25 09:50:14 UTC
  • mto: (0.4.3 experimental)
  • mto: This revision was merged to the branch mainline in revision 68.
  • Revision ID: james.westby@ubuntu.com-20100525095014-e3cebfkdenjrx3xg
Tags: upstream-4.4.80
ImportĀ upstreamĀ versionĀ 4.4.80

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *   Copyright (C) 2007, 2008, 2009, 2010 Ivan Cukic <ivan.cukic(at)kde.org>
 
3
 *
 
4
 *   This program is free software; you can redistribute it and/or modify
 
5
 *   it under the terms of the GNU Lesser/Library General Public License version 2,
 
6
 *   or (at your option) any later version, as published by the Free
 
7
 *   Software Foundation
 
8
 *
 
9
 *   This program is distributed in the hope that it will be useful,
 
10
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 *   GNU Lesser/Library General Public License for more details
 
13
 *
 
14
 *   You should have received a copy of the GNU Lesser/Library General Public
 
15
 *   License along with this program; if not, write to the
 
16
 *   Free Software Foundation, Inc.,
 
17
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
18
 */
 
19
 
 
20
#include "NodeLayout.h"
 
21
#include "Global.h"
 
22
 
 
23
#include <QMap>
 
24
#include <QPair>
 
25
 
 
26
#include <lancelot/lancelot.h>
 
27
 
 
28
#include <limits>
 
29
 
 
30
namespace Lancelot
 
31
{
 
32
 
 
33
NodeLayout::NodeCoordinate::NodeCoordinate(qreal xRelative, qreal yRelative, qreal xAbsolute, qreal yAbsolute)
 
34
    : xr(xRelative), xa(xAbsolute), yr(yRelative), ya(yAbsolute) {}
 
35
 
 
36
NodeLayout::NodeCoordinate NodeLayout::NodeCoordinate::simple(qreal x, qreal y,
 
37
        CoordinateType xType, CoordinateType yType)
 
38
{
 
39
    NodeLayout::NodeCoordinate coo;
 
40
    switch (xType) {
 
41
    case Relative:
 
42
        coo.xr = x;
 
43
        coo.xa = 0;
 
44
        break;
 
45
    case Absolute:
 
46
        coo.xr = 0;
 
47
        coo.xa = x;
 
48
        break;
 
49
    case InnerRelative:
 
50
        coo.xr = x;
 
51
        coo.xa = QREAL_INFINITY;
 
52
        break;
 
53
    }
 
54
 
 
55
    switch (yType) {
 
56
    case Relative:
 
57
        coo.yr = y;
 
58
        coo.ya = 0;
 
59
        break;
 
60
    case Absolute:
 
61
        coo.yr = 0;
 
62
        coo.ya = y;
 
63
        break;
 
64
    case InnerRelative:
 
65
        coo.yr = y;
 
66
        coo.ya = QREAL_INFINITY;
 
67
        break;
 
68
    }
 
69
    return coo;
 
70
}
 
71
 
 
72
class NodeLayout::Private {
 
73
public:
 
74
    QMap <QGraphicsLayoutItem * , QPair < NodeCoordinate, NodeCoordinate > > items;
 
75
    NodeLayout * parent;
 
76
    QMap < Qt::SizeHint, QSizeF > sizeHintCache;
 
77
 
 
78
    Private(NodeLayout * parentLayout) {
 
79
        parent = parentLayout;
 
80
    }
 
81
 
 
82
    void relayout()
 
83
    {
 
84
        foreach (QGraphicsLayoutItem * item, items.keys()) // krazy:exclude=foreach
 
85
        {
 
86
            if (item) {
 
87
                item->setGeometry(calculateRectangle(item));
 
88
            }
 
89
        }
 
90
    }
 
91
 
 
92
    qreal calculateXPosition(const NodeCoordinate & coo, const QRectF & parentGeometry) const
 
93
    {
 
94
        return parentGeometry.left() + (coo.xr * parentGeometry.width())  + coo.xa;
 
95
    }
 
96
 
 
97
    qreal calculateYPosition(const NodeCoordinate & coo, const QRectF & parentGeometry) const
 
98
    {
 
99
        return parentGeometry.top() + (coo.yr * parentGeometry.height())  + coo.ya;
 
100
    }
 
101
 
 
102
    QPointF calculatePosition(const NodeCoordinate & coo, const QRectF & parentGeometry) const
 
103
    {
 
104
        Q_UNUSED( parentGeometry );
 
105
 
 
106
        return QPointF(
 
107
            calculateXPosition(coo, parent->geometry()),
 
108
            calculateYPosition(coo, parent->geometry())
 
109
        );
 
110
    }
 
111
 
 
112
    QRectF calculateRectangle(QGraphicsLayoutItem * item, QRectF geometry = QRectF()) const
 
113
    {
 
114
        if (geometry == QRectF()) {
 
115
            geometry = parent->geometry();
 
116
        }
 
117
 
 
118
        QRectF result;
 
119
        if (!item || !items.contains(item)) {
 
120
            return QRectF();
 
121
        }
 
122
 
 
123
        result.setTopLeft(calculatePosition(items[item].first, geometry));
 
124
 
 
125
        if (items[item].second.xa != QREAL_INFINITY) {
 
126
            result.setRight(calculateXPosition(items[item].second, geometry));
 
127
        } else {
 
128
            result.setWidth(item->preferredSize().width());
 
129
            result.moveLeft(result.left() - items[item].second.xr * result.width());
 
130
        }
 
131
 
 
132
        if (items[item].second.ya != QREAL_INFINITY) {
 
133
            result.setBottom(calculateYPosition(items[item].second, geometry));
 
134
        } else {
 
135
            result.setHeight(item->preferredSize().height());
 
136
            result.moveTop(result.top() - items[item].second.yr * result.height());
 
137
        }
 
138
        return result;
 
139
    }
 
140
 
 
141
    void calculateSizeHint(QGraphicsLayoutItem * item = NULL) {
 
142
        if (item == NULL) {
 
143
            // Recalculate the sizeHint using all items
 
144
            sizeHintCache[Qt::MinimumSize] = QSizeF();
 
145
            sizeHintCache[Qt::MaximumSize] = QSizeF();
 
146
            sizeHintCache[Qt::PreferredSize] = QSizeF();
 
147
            foreach (QGraphicsLayoutItem * item, items.keys()) // krazy:exclude=foreach
 
148
            {
 
149
                if (item) {
 
150
                    calculateSizeHint(item);
 
151
                }
 
152
            }
 
153
        } else {
 
154
            // Calculate size hint for current item
 
155
            const QRectF scaled = calculateRectangle(item, QRectF(0, 0, 1, 1));
 
156
 
 
157
            // qMin(..., 1.0) so that for autosized elements we don't get smaller
 
158
            // size than the item's size itself. The sizeHint for NodeLayout can
 
159
            // not do anything smarter concerning the sizeHint when there are
 
160
            // autosized elements.
 
161
 
 
162
            QSizeF size;
 
163
 
 
164
            foreach (const Qt::SizeHint &which, sizeHintCache.keys()) // krazy:exclude=foreach
 
165
            {
 
166
                size = item->effectiveSizeHint(which);
 
167
                size.scale(
 
168
                    1 / qMin(scaled.width(), qreal(1.0)),
 
169
                    1 / qMin(scaled.height(), qreal(1.0)),
 
170
                    Qt::IgnoreAspectRatio
 
171
                );
 
172
                sizeHintCache[which] = sizeHintCache[which].expandedTo(size);
 
173
            }
 
174
        }
 
175
    }
 
176
 
 
177
};
 
178
 
 
179
NodeLayout::NodeLayout(QGraphicsLayoutItem * parent)
 
180
  : QGraphicsLayout(parent), d(new Private(this))
 
181
{
 
182
}
 
183
 
 
184
NodeLayout::~NodeLayout()
 
185
{
 
186
    delete d;
 
187
}
 
188
 
 
189
QSizeF NodeLayout::sizeHint(Qt::SizeHint which,
 
190
        const QSizeF & constraint) const
 
191
{
 
192
    Q_UNUSED(which);
 
193
    Q_UNUSED(constraint);
 
194
    QSizeF result;
 
195
 
 
196
    switch (which) {
 
197
        case Qt::MaximumSize:
 
198
            result = MAX_WIDGET_SIZE;
 
199
            break;
 
200
        default:
 
201
            result = d->sizeHintCache[which];
 
202
    }
 
203
    if (constraint.isValid()) {
 
204
        result = result.boundedTo(constraint);
 
205
    }
 
206
    return result;
 
207
}
 
208
 
 
209
void NodeLayout::addItem(QGraphicsLayoutItem * item)
 
210
{
 
211
    NodeLayout::addItem(item, NodeCoordinate());
 
212
}
 
213
 
 
214
void NodeLayout::addItem(QGraphicsLayoutItem * item, NodeCoordinate topLeft, NodeCoordinate bottomRight)
 
215
{
 
216
    if (!item) {
 
217
        return;
 
218
    }
 
219
 
 
220
    d->items[item] = QPair<NodeCoordinate, NodeCoordinate>(topLeft, bottomRight);
 
221
    d->calculateSizeHint(item);
 
222
    updateGeometry();
 
223
}
 
224
 
 
225
void NodeLayout::addItem(QGraphicsLayoutItem * item, NodeCoordinate node, qreal xr, qreal yr)
 
226
{
 
227
    if (!item) {
 
228
        return;
 
229
    }
 
230
 
 
231
    d->items[item] = QPair<NodeCoordinate, NodeCoordinate>(node,
 
232
        NodeCoordinate::simple(xr, yr, NodeCoordinate::InnerRelative, NodeCoordinate::InnerRelative));
 
233
    d->calculateSizeHint(item);
 
234
    updateGeometry();
 
235
}
 
236
 
 
237
int NodeLayout::count() const
 
238
{
 
239
    return d->items.count();
 
240
}
 
241
 
 
242
QGraphicsLayoutItem * NodeLayout::itemAt(int i) const
 
243
{
 
244
    if (i >= d->items.count()) {
 
245
        return 0;
 
246
    }
 
247
 
 
248
    return d->items.keys()[i];
 
249
}
 
250
 
 
251
void NodeLayout::removeAt(int i)
 
252
{
 
253
    if (i >= d->items.count()) {
 
254
        return;
 
255
    }
 
256
 
 
257
    d->items.remove(itemAt(i));
 
258
}
 
259
 
 
260
void NodeLayout::setGeometry(const QRectF & rect)
 
261
{
 
262
    QGraphicsLayout::setGeometry(rect);
 
263
    d->relayout();
 
264
}
 
265
 
 
266
} // namespace Lancelot
 
267