~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to plasma/desktop/containments/desktop/itemspace.h

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  Copyright (c) 2008 Ambroz Bizjak <ambro@b4ever.net>
 
3
 
 
4
  This program is free software; you can redistribute it and/or modify
 
5
  it under the terms of the GNU General Public License as published by
 
6
  the Free Software Foundation; either version 2 of the License, or
 
7
  (at your option) any later version.
 
8
*/
 
9
 
 
10
#ifndef _ITEMSPACE_H
 
11
#define _ITEMSPACE_H
 
12
 
 
13
#include <QRectF>
 
14
#include <QList>
 
15
#include <QVariant>
 
16
 
 
17
/**
 
18
 * ItemSpace class
 
19
 * Implements "push and pull" dynamics of rectangular items in 2D space.
 
20
 *
 
21
 * All isolated motion folows these rules:
 
22
 *  - overlapping items stay at the same positions relative to each other
 
23
 *  - non-overlapping items stay such and do not jump one over another
 
24
 *
 
25
 * There are two types of motion:
 
26
 *  - forced motion: an item moves all items on its way, even if any of them
 
27
 *    would intersect the border of the working area
 
28
 *  - non-forced motion: an item moves items on its way only as much as the border
 
29
 *    of the working area
 
30
 *
 
31
 * Items are pushed to fit inside the working area:
 
32
 * if an item is in the way of one of the borders of alignment, the move is forced;
 
33
 * if an item is in the way of one of the opposite borders, the move is non-forced.
 
34
 *
 
35
 * An item can have a "preferred position". Such item is moved non-forced in the
 
36
 * direction towards the preferred position.
 
37
 **/
 
38
class ItemSpace
 
39
{
 
40
  public:
 
41
    ItemSpace();
 
42
 
 
43
    void setWorkingArea(const QSizeF& area);
 
44
 
 
45
    /**
 
46
     * Returns the visibility of an item at a given position.
 
47
     * This is the part of the item inside the working area.
 
48
     **/
 
49
    qreal positionVisibility(const QRectF& geom);
 
50
 
 
51
    class ItemSpaceItem
 
52
    {
 
53
      public:
 
54
        QPointF preferredPosition;
 
55
        QRectF lastGeometry;
 
56
        bool pushBack : 1;
 
57
        bool animateMovement : 1;
 
58
        QVariant user;
 
59
    };
 
60
 
 
61
    enum DirectionFlag {
 
62
        DirLeft = 1,
 
63
        DirRight = 2,
 
64
        DirUp = 4,
 
65
        DirDown = 8
 
66
    };
 
67
    Q_DECLARE_FLAGS(Direction, DirectionFlag)
 
68
 
 
69
    enum PushPowerFlag {
 
70
        NoPower = 0,
 
71
        PushAwayFromPreferred = 1,
 
72
        PushOverBorder = 2
 
73
    };
 
74
    Q_DECLARE_FLAGS(PushPower, PushPowerFlag)
 
75
 
 
76
    /**
 
77
     * Push an item group. Requires no initialization.
 
78
     *
 
79
     * @param groupId the index of the group
 
80
     * @param direction in which direction pushing will be done
 
81
     * @param amount how much to push
 
82
     * @param power how 'powerful' the push is; what types of obstacles
 
83
     *              can be pushed or ignored
 
84
     *
 
85
     * @return how much the item group was really pushed
 
86
     **/
 
87
    qreal performPush(int groupId, Direction direction, qreal amount, PushPower power);
 
88
 
 
89
    /**
 
90
     * Add a new item.
 
91
     * Groups will be updated to reflect the change.
 
92
     *
 
93
     * @param newItem the item to add; must be initialized
 
94
     **/
 
95
    void addItem(ItemSpaceItem newItem);
 
96
 
 
97
    /**
 
98
     * Removes an item by its location.
 
99
     *
 
100
     * @param groupIndex the index of the item's group
 
101
     * @param itemInGroup the index of the item in its group
 
102
     **/
 
103
    void removeItem(int groupIndex, int itemInGroup);
 
104
 
 
105
    /**
 
106
     * Move the item to a new position.
 
107
     *
 
108
     * @param groupIndex the index of the item's group
 
109
     * @param itemInGroup the index of the item in its group
 
110
     * @param newGeom the new geometry of the item
 
111
     **/
 
112
    void moveItem(int groupIndex, int itemInGroup, const QRectF& newGeom);
 
113
 
 
114
    /**
 
115
     * Resize an item. The item's alignment corner will be the center of resizing.
 
116
     *
 
117
     * @param groupId the index of the group
 
118
     * @param direction in which direction pushing will be done
 
119
     * @param newSize the item's new size
 
120
     **/
 
121
    void resizeItem(int groupId, int itemInGroup, const QSizeF& newSize);
 
122
 
 
123
    /**
 
124
     * Offset the positions of all items.
 
125
     **/
 
126
    void offsetPositions(const QPointF &offset);
 
127
 
 
128
    /**
 
129
     * Find an item by its number as if we iterated over
 
130
     * all groups and over all items in each group.
 
131
     **/
 
132
    bool locateItemByPosition(int pos, int *groupIndex, int *itemInGroup) const;
 
133
 
 
134
    /**
 
135
     * Find an item by its 'user' parameter.
 
136
     **/
 
137
    bool locateItemByUser(QVariant user, int *groupIndex, int *itemInGroup) const;
 
138
 
 
139
    /**
 
140
     * Finds an empty place for an item.
 
141
     * Tries to stack the item vertically, starting in the corner
 
142
     * of alignment, and advances horizontally once no more positions
 
143
     * are valid.
 
144
     *
 
145
     * @param itemSize the size of the item; placementSpacing is already
 
146
     *                 considered
 
147
     * @param align the corner of the screen where position testing will
 
148
     *              begin (and in what directions it will advance)
 
149
     *              must be an OR of Qt::AlignLeft or Qt::AlignRight
 
150
     *              and Qt::AlignTop or Qt::AlignBottom
 
151
     * @param limitedSpace if true, positions outside the working area
 
152
     *                     will not be considered; otherwise, positions
 
153
     *                     will only be limited by the borders at the
 
154
     *                     alignment corner.
 
155
     * @param findAll if false, searching will stop after the first valid
 
156
     *                position
 
157
     *
 
158
     * @return all positions found
 
159
     **/
 
160
    QList<QPointF> positionVertically(
 
161
        const QSizeF &itemSize,
 
162
        Qt::Alignment align,
 
163
        bool limitedSpace,
 
164
        bool findAll
 
165
    ) const;
 
166
 
 
167
    bool positionedProperly(const QRectF& itemGeom);
 
168
 
 
169
    /**
 
170
     * Represents a group of overlapping items.
 
171
     **/
 
172
    class ItemGroup
 
173
    {
 
174
      public:
 
175
 
 
176
        class Request
 
177
        {
 
178
          public:
 
179
            /**
 
180
             * Create a push request. No calculations will be performed.
 
181
             *
 
182
             * @param sourceGroup the group that posted the request, or
 
183
             *                    -1 if it was posted manually.
 
184
             * @param sourceGroupPushRequested how much the posting group wanted
 
185
             *                                 to move itself when the request was
 
186
             *                                 posted (if sourceGroup is -1)
 
187
             * @param pushRequested how much the group concerned is asked to move
 
188
             **/
 
189
            Request(
 
190
                int sourceGroup,
 
191
                qreal sourceGroupPushRequested,
 
192
                qreal pushRequested
 
193
            );
 
194
 
 
195
            /**
 
196
             * Perform obstacle searching and post push request to obstacle groups.
 
197
             * This is the main method involved in recursive push calculation.
 
198
             *
 
199
             * If an item is found to be in the way of any of the group's items,
 
200
             * its ItemGroup will be created if it doesn't have one already,
 
201
             * and a new push request will bo posted to it.
 
202
             *
 
203
             * If the offending group can not move as much as we need it to,
 
204
             * we limit the amount our group wants to move, and future obstacles
 
205
             * will be asked to move less than they would have been had there
 
206
             * been no obstacle.
 
207
             *
 
208
             * @param group the ItemGroup this push request belongs to
 
209
             **/
 
210
            void activate(ItemSpace *itemSpace, ItemGroup *group);
 
211
 
 
212
            // saved from constructor
 
213
            int m_sourceGroup;
 
214
            qreal m_sourceGroupPushRequested;
 
215
            qreal m_pushRequested;
 
216
 
 
217
            // true if the request has already been reached by applyResults
 
218
            // and compensated for the reduction of the requester's move
 
219
            bool m_compensated;
 
220
        };
 
221
 
 
222
        void resetPush(int id);
 
223
 
 
224
        /**
 
225
         * Post a move request.
 
226
         * This adds the request to the group and calls activate on it.
 
227
         **/
 
228
        void addRequest(ItemSpace *itemSpace, const class Request &request);
 
229
 
 
230
        /**
 
231
         * Apply the results of initial push calculation, moving the items.
 
232
         *
 
233
         * For each push request belonging to the calling/requesting group,
 
234
         * the requesting group is checked for how much it still wants to
 
235
         * move itself, and the value is compared to how much it wanted to
 
236
         * when the request was posted. The amount of the request is reduced
 
237
         * by the difference.
 
238
         *
 
239
         * If all requests have been compensated, it updates the amount it
 
240
         * would like to move (the maximum of all move requests) and
 
241
         * physically moves its items. In that case it also calls applyResults
 
242
         * on the item groups it has requested to move, which will see the new
 
243
         * push amount.
 
244
         * (Otherwise, another requesting group will reach it later on.)
 
245
         **/
 
246
        void applyResults(ItemSpace *itemSpace, int cameFrom);
 
247
 
 
248
        // items belonging to this group
 
249
        QList<ItemSpaceItem> m_groupItems;
 
250
 
 
251
        // the list index of this group in the calculation process
 
252
        int m_id;
 
253
        // the maximum of all push requests
 
254
        qreal m_largestPushRequested;
 
255
        // the available space calculated so-far
 
256
        qreal m_pushAvailable;
 
257
 
 
258
      private:
 
259
        // return true if the group is above this one (its requests lead here)
 
260
        bool groupIsAbove(ItemSpace *itemSpace, QList<int> &visited, int groupId);
 
261
 
 
262
        // move requests posted to this group
 
263
        QList<Request> m_requests;
 
264
        // groups we asked to move
 
265
        QList<int> m_obstacles;
 
266
    };
 
267
 
 
268
    /**
 
269
     * All item groups.
 
270
     **/
 
271
    QList<ItemGroup> m_groups;
 
272
 
 
273
    Qt::Alignment spaceAlignment;
 
274
    QSizeF workingGeom;
 
275
 
 
276
    qreal placementSpacing;
 
277
    qreal screenSpacing;
 
278
    qreal shiftingSpacing;
 
279
 
 
280
  private:
 
281
 
 
282
    void linkItem(ItemSpaceItem newItem);
 
283
    void unlinkItem(int removeGroup, int removeItemInGroup);
 
284
 
 
285
    /**
 
286
     * Prepare for pushing.
 
287
     * After that, move requests can be posted to item groups
 
288
     * with ItemGroup::addRequest and the move can be performed
 
289
     * with ItemGroup::applyResults.
 
290
     *
 
291
     * @param direction in which direction pushing will be done
 
292
     * @param power how 'powerful' the push is; what types of obstacles
 
293
     *              can be pushed or ignored
 
294
     **/
 
295
    void preparePush(Direction direction, PushPower power);
 
296
 
 
297
    /**
 
298
     * Look for items overlapping with working area borders and move them inside as much as possible.
 
299
     **/
 
300
    void checkBorders();
 
301
 
 
302
    /**
 
303
     * Look for items not in their preferred positions and move them back as much as possible.
 
304
     **/
 
305
    void checkPreferredPositions();
 
306
 
 
307
    QRectF itemInRegionStartingFirstVert(const QRectF &region) const;
 
308
    QRectF itemInRegionEndingLastVert(const QRectF &region) const;
 
309
    QRectF itemInRegionEndingFirstHoriz(const QRectF &region) const;
 
310
    QRectF itemInRegionStartingLastHoriz(const QRectF &region) const;
 
311
 
 
312
    Direction m_direction;
 
313
    PushPower m_power;
 
314
};
 
315
 
 
316
#endif