GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/layoutarray.cpp Lines: 160 168 95.2 %
Date: 2017-11-29 Branches: 100 111 90.1 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2007-2009  The Mana World Development Team
4
 *  Copyright (C) 2009-2010  The Mana Developers
5
 *  Copyright (C) 2011-2017  The ManaPlus Developers
6
 *
7
 *  This file is part of The ManaPlus Client.
8
 *
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or
12
 *  any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU General Public License
20
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
#include "gui/widgets/layoutarray.h"
24
25
#include "enums/gui/layouttype.h"
26
27
#include "gui/widgets/layoutcell.h"
28
#include "gui/widgets/widget.h"
29
30
#include <cassert>
31
32
#include "debug.h"
33
34
310
LayoutArray::LayoutArray() :
35
    mCells(),
36
1240
    mSpacing(4)
37
{
38
310
}
39
40
930
LayoutArray::~LayoutArray()
41
{
42
    STD_VECTOR <STD_VECTOR <LayoutCell *> >::iterator
43
620
        i = mCells.begin();
44
    const STD_VECTOR <STD_VECTOR <LayoutCell *> >::iterator
45
620
        i_end = mCells.end();
46
3134
    while (i != i_end)
47
    {
48
2824
        STD_VECTOR< LayoutCell * >::iterator j = i->begin();
49
2824
        const STD_VECTOR< LayoutCell * >::iterator j_end = i->end();
50
10050
        while (j != j_end)
51
        {
52
8638
            delete *j;
53
            ++j;
54
        }
55
1412
        ++i;
56
    }
57
310
}
58
59
1280
LayoutCell &LayoutArray::at(const int x, const int y,
60
                            const int w, const int h)
61
{
62
1280
    resizeGrid(x + w, y + h);
63
3840
    LayoutCell *&cell = mCells[CAST_SIZE(y)][static_cast<size_t>(x)];
64
1280
    if (cell == nullptr)
65
2556
        cell = new LayoutCell;
66
1280
    return *cell;
67
}
68
69
1356
void LayoutArray::resizeGrid(int w, const int h)
70
{
71

2654
    const bool extW = (w != 0) && w > CAST_S32(mSizes[0].size());
72

2694
    const bool extH = (h != 0) && h > CAST_S32(mSizes[1].size());
73
74
1356
    if (!extW && !extH)
75
        return;
76
77
898
    if (extH)
78
    {
79
812
        mSizes[1].resize(CAST_SIZE(h), LayoutType::DEF);
80
812
        mCells.resize(CAST_SIZE(h));
81
812
        if (!extW)
82
1000
            w = CAST_S32(mSizes[0].size());
83
    }
84
85
898
    if (extW)
86
398
        mSizes[0].resize(CAST_SIZE(w), LayoutType::DEF);
87
88
    STD_VECTOR <STD_VECTOR <LayoutCell *> >::iterator
89
1796
        i = mCells.begin();
90
    const STD_VECTOR <STD_VECTOR <LayoutCell *> >::iterator
91
1796
        i_end = mCells.end();
92
5114
    while (i != i_end)
93
    {
94
4216
        i->resize(CAST_SIZE(w), nullptr);
95
        ++i;
96
    }
97
}
98
99
6
void LayoutArray::setColWidth(const int n, const int w)
100
{
101
6
    resizeGrid(n + 1, 0);
102
12
    mSizes[0U][CAST_SIZE(n)] = w;
103
6
}
104
105
58
void LayoutArray::setRowHeight(const int n, const int h)
106
{
107
58
    resizeGrid(0, n + 1);
108
116
    mSizes[1][CAST_SIZE(n)] = h;
109
58
}
110
111
12
void LayoutArray::matchColWidth(const int n1, const int n2)
112
{
113
12
    resizeGrid(std::max(n1, n2) + 1, 0);
114
24
    const STD_VECTOR<int> widths = getSizes(0, LayoutType::DEF);
115
24
    const int s = std::max(widths[CAST_SIZE(n1)],
116
36
        widths[CAST_SIZE(n2)]);
117
24
    mSizes[0][CAST_SIZE(n1)] = s;
118
24
    mSizes[0][CAST_SIZE(n2)] = s;
119
12
}
120
121
2
void LayoutArray::extend(const int x, const int y, const int w, const int h)
122
{
123
2
    LayoutCell &cell = at(x, y, w, h);
124
2
    cell.mExtent[0] = w;
125
2
    cell.mExtent[1] = h;
126
2
}
127
128
1130
LayoutCell &LayoutArray::place(Widget *const widget, const int x,
129
                               const int y, const int w, const int h)
130
{
131
1130
    LayoutCell &cell = at(x, y, w, h);
132
1130
    assert(cell.mType == LayoutCell::NONE);
133
1130
    cell.mType = LayoutCell::WIDGET;
134
1130
    cell.mWidget = widget;
135
1130
    if (widget != nullptr)
136
    {
137
1588
        cell.mSize[0] = w == 1 ? widget->getWidth() : 0;
138
2138
        cell.mSize[1] = h == 1 ? widget->getHeight() : 0;
139
    }
140
    else
141
    {
142
        cell.mSize[0] = 1;
143
        cell.mSize[1] = 1;
144
    }
145
1130
    cell.mExtent[0] = w;
146
1130
    cell.mExtent[1] = h;
147
1130
    cell.mHPadding = 0;
148
1130
    cell.mVPadding = 0;
149
1130
    cell.mAlign[0] = LayoutCell::FILL;
150
1130
    cell.mAlign[1] = LayoutCell::FILL;
151
2260
    int &cs = mSizes[0][CAST_SIZE(x)];
152
2260
    int &rs = mSizes[1][CAST_SIZE(y)];
153

1130
    if (cs == LayoutType::DEF && w == 1)
154
302
        cs = 0;
155

1130
    if (rs == LayoutType::DEF && h == 1)
156
590
        rs = 0;
157
1130
    return cell;
158
}
159
160
3352
void LayoutArray::align(int &restrict pos, int &restrict size, const int dim,
161
                        LayoutCell const &restrict cell,
162
                        const int *restrict const sizes,
163
                        const int sizeCount) const
164
{
165
3352
    if (dim < 0 || dim >= 2)
166
        return;
167
3352
    int size_max = sizes[0];
168
3352
    int cnt = cell.mExtent[dim];
169

3352
    if ((sizeCount != 0) && cell.mExtent[dim] > sizeCount)
170
2
        cnt = sizeCount;
171
172
7320
    for (int i = 1; i < cnt; ++i)
173
3968
        size_max += sizes[i] + mSpacing;
174
6704
    size = std::min<int>(cell.mSize[dim], size_max);
175
176

3352
    switch (cell.mAlign[dim])
177
    {
178
        case LayoutCell::LEFT:
179
            return;
180
        case LayoutCell::RIGHT:
181
            pos += size_max - size;
182
            return;
183
2
        case LayoutCell::CENTER:
184
2
            pos += (size_max - size) / 2;
185
2
            return;
186
3342
        case LayoutCell::FILL:
187
3342
            size = size_max;
188
3342
            return;
189
        default:
190
            logger->log1("LayoutArray::align unknown layout");
191
            return;
192
    }
193
}
194
195
1452
STD_VECTOR<int> LayoutArray::getSizes(const int dim, int upp) const
196
{
197
1452
    if (dim < 0 || dim >= 2)
198
        return mSizes[1];
199
200
2904
    const int gridW = CAST_S32(mSizes[0].size());
201
2904
    const int gridH = CAST_S32(mSizes[1].size());
202
1452
    STD_VECTOR<int> sizes = mSizes[dim];
203
204
    // Compute minimum sizes.
205
14780
    for (int gridY = 0; gridY < gridH; ++gridY)
206
    {
207
84304
        for (int gridX = 0; gridX < gridW; ++gridX)
208
        {
209
77640
            const LayoutCell *const cell = mCells[CAST_SIZE(gridY)]
210
77640
                [CAST_SIZE(gridX)];
211

38820
            if ((cell == nullptr) || cell->mType == LayoutCell::NONE)
212
32832
                continue;
213
214
5988
            if (cell->mExtent[dim] == 1)
215
            {
216
3996
                const int n = (dim == 0 ? gridX : gridY);
217
3996
                const int s = cell->mSize[dim] + cell->mVPadding * 2;
218
7992
                if (s > sizes[CAST_SIZE(n)])
219
3144
                    sizes[CAST_SIZE(n)] = s;
220
            }
221
        }
222
    }
223
224
1452
    if (upp == LayoutType::DEF)
225
        return sizes;
226
227
    // Compute the FILL sizes.
228
1664
    const int nb = CAST_S32(sizes.size());
229
832
    int nbFill = 0;
230
4290
    for (int i = 0; i < nb; ++i)
231
    {
232
10374
        if (mSizes[CAST_SIZE(dim)][static_cast<size_t>(i)]
233
3458
            <= LayoutType::DEF)
234
        {
235
2296
            ++nbFill;
236
2296
            if (mSizes[CAST_SIZE(dim)][static_cast<size_t>(i)] ==
237

4526
                LayoutType::SET ||
238
4460
                sizes[CAST_SIZE(i)] <= LayoutType::DEF)
239
            {
240
3960
                sizes[CAST_SIZE(i)] = 0;
241
            }
242
        }
243
6916
        upp -= sizes[CAST_SIZE(i)] + mSpacing;
244
    }
245
832
    upp = upp + mSpacing;
246
247
832
    if (nbFill == 0)
248
        return sizes;
249
250
6768
    for (int i = 0; i < nb; ++i)
251
    {
252
6020
        if (mSizes[CAST_SIZE(dim)][static_cast<size_t>(i)] >
253
            LayoutType::DEF)
254
        {
255
714
            continue;
256
        }
257
258
2296
        const int s = upp / nbFill;
259
4592
        sizes[CAST_SIZE(i)] += s;
260
2296
        upp -= s;
261
2296
        --nbFill;
262
    }
263
264
    return sizes;
265
}
266
267
608
int LayoutArray::getSize(const int dim) const
268
{
269
1216
    STD_VECTOR<int> sizes = getSizes(dim, LayoutType::DEF);
270
608
    int size = 0;
271
1216
    const int nb = CAST_S32(sizes.size());
272
3226
    for (int i = 0; i < nb; ++i)
273
    {
274
5236
        if (sizes[CAST_SIZE(i)] > LayoutType::DEF)
275
1158
            size += sizes[CAST_SIZE(i)];
276
2618
        size += mSpacing;
277
    }
278
1216
    return size - mSpacing;
279
}
280
281
416
void LayoutArray::reflow(const int nx, const int ny,
282
                         const int nw, const int nh)
283
{
284
832
    const int gridW = CAST_S32(mSizes[0].size());
285
832
    const int gridH = CAST_S32(mSizes[1].size());
286
287
832
    STD_VECTOR<int> widths  = getSizes(0, nw);
288
832
    STD_VECTOR<int> heights = getSizes(1, nh);
289
290
832
    const int szW = CAST_S32(widths.size());
291
832
    const int szH = CAST_S32(heights.size());
292
416
    int y = ny;
293
2292
    for (int gridY = 0; gridY < gridH; ++gridY)
294
    {
295
        int x = nx;
296
23304
        for (int gridX = 0; gridX < gridW; ++gridX)
297
        {
298
21428
            LayoutCell *const cell = mCells[CAST_SIZE(gridY)]
299
21428
                [CAST_SIZE(gridX)];
300

10714
            if ((cell != nullptr) && cell->mType != LayoutCell::NONE)
301
            {
302
1676
                int dx = x, dy = y, dw = 0, dh = 0;
303
3352
                align(dx, dw, 0, *cell,
304
3352
                    &widths[CAST_SIZE(gridX)], szW - gridX);
305
3352
                align(dy, dh, 1, *cell,
306
3352
                    &heights[CAST_SIZE(gridY)], szH - gridY);
307
1676
                cell->reflow(dx, dy, dw, dh);
308
            }
309
21428
            x += widths[CAST_SIZE(gridX)] + mSpacing;
310
        }
311
3752
        y += heights[CAST_SIZE(gridY)] + mSpacing;
312
    }
313
416
}