GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/layoutarray.cpp Lines: 156 162 96.3 %
Date: 2018-07-14 Branches: 103 115 89.6 %

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-2018  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
157
LayoutArray::LayoutArray() :
35
    mCells(),
36
628
    mSpacing(4)
37
{
38
157
}
39
40

471
LayoutArray::~LayoutArray()
41
{
42
    STD_VECTOR <STD_VECTOR <LayoutCell *> >::iterator
43
314
        i = mCells.begin();
44
    const STD_VECTOR <STD_VECTOR <LayoutCell *> >::iterator
45
314
        i_end = mCells.end();
46
1581
    while (i != i_end)
47
    {
48
1424
        STD_VECTOR< LayoutCell * >::iterator j = i->begin();
49
1424
        const STD_VECTOR< LayoutCell * >::iterator j_end = i->end();
50
5042
        while (j != j_end)
51
        {
52
4330
            delete *j;
53
            ++j;
54
        }
55
712
        ++i;
56
    }
57
157
}
58
59
647
LayoutCell &LayoutArray::at(const int x, const int y,
60
                            const int w, const int h)
61
{
62
647
    resizeGrid(x + w, y + h);
63
1941
    LayoutCell *&cell = mCells[CAST_SIZE(y)][static_cast<size_t>(x)];
64
647
    if (cell == nullptr)
65
1292
        cell = new LayoutCell;
66
647
    return *cell;
67
}
68
69
686
void LayoutArray::resizeGrid(int w, const int h)
70
{
71

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

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

571
    if (cs == LayoutType::DEF && w == 1)
154
152
        cs = 0;
155

571
    if (rs == LayoutType::DEF && h == 1)
156
300
        rs = 0;
157
571
    return cell;
158
}
159
160
1690
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
1690
    if (dim < 0 || dim >= 2)
166
        return;
167
1690
    int size_max = sizes[0];
168
1690
    int cnt = cell.mExtent[dim];
169

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

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

19464
            if ((cell == nullptr) || cell->mType == LayoutCell::NONE)
212
                continue;
213
214
3027
            if (cell->mExtent[dim] == 1)
215
            {
216
2016
                const int n = (dim == 0 ? gridX : gridY);
217
2016
                const int s = cell->mSize[dim] + cell->mVPadding * 2;
218
4032
                if (s > sizes[CAST_SIZE(n)])
219
1586
                    sizes[CAST_SIZE(n)] = s;
220
            }
221
        }
222
    }
223
224
735
    if (upp == LayoutType::DEF)
225
        return sizes;
226
227
    // Compute the FILL sizes.
228
840
    const int nb = CAST_S32(sizes.size());
229
420
    int nbFill = 0;
230
2158
    for (int i = 0; i < nb; ++i)
231
    {
232
5214
        if (mSizes[CAST_SIZE(dim)][static_cast<size_t>(i)]
233
1738
            <= LayoutType::DEF)
234
        {
235
1151
            ++nbFill;
236
2302
            if (mSizes[CAST_SIZE(dim)][static_cast<size_t>(i)] ==
237

2269
                LayoutType::SET ||
238
2236
                sizes[CAST_SIZE(i)] <= LayoutType::DEF)
239
            {
240
1982
                sizes[CAST_SIZE(i)] = 0;
241
            }
242
        }
243
3476
        upp -= sizes[CAST_SIZE(i)] + mSpacing;
244
    }
245
420
    upp = upp + mSpacing;
246
247
420
    if (nbFill == 0)
248
        return sizes;
249
250
3395
    for (int i = 0; i < nb; ++i)
251
    {
252
3018
        if (mSizes[CAST_SIZE(dim)][static_cast<size_t>(i)] >
253
            LayoutType::DEF)
254
        {
255
            continue;
256
        }
257
258
1151
        const int s = upp / nbFill;
259
2302
        sizes[CAST_SIZE(i)] += s;
260
1151
        upp -= s;
261
1151
        --nbFill;
262
    }
263
264
    return sizes;
265
}
266
267
308
int LayoutArray::getSize(const int dim) const
268
{
269
616
    STD_VECTOR<int> sizes = getSizes(dim, LayoutType::DEF);
270
308
    int size = 0;
271
616
    const int nb = CAST_S32(sizes.size());
272
1626
    for (int i = 0; i < nb; ++i)
273
    {
274
2636
        if (sizes[CAST_SIZE(i)] > LayoutType::DEF)
275
587
            size += sizes[CAST_SIZE(i)];
276
1318
        size += mSpacing;
277
    }
278
616
    return size - mSpacing;
279
}
280
281
210
void LayoutArray::reflow(const int nx, const int ny,
282
                         const int nw, const int nh)
283
{
284
420
    const int gridW = CAST_S32(mSizes[0].size());
285
420
    const int gridH = CAST_S32(mSizes[1].size());
286
287
420
    STD_VECTOR<int> widths  = getSizes(0, nw);
288
420
    STD_VECTOR<int> heights = getSizes(1, nh);
289
290
420
    const int szW = CAST_S32(widths.size());
291
420
    const int szH = CAST_S32(heights.size());
292
210
    int y = ny;
293
1154
    for (int gridY = 0; gridY < gridH; ++gridY)
294
    {
295
        int x = nx;
296
11680
        for (int gridX = 0; gridX < gridW; ++gridX)
297
        {
298
10736
            LayoutCell *const cell = mCells[CAST_SIZE(gridY)]
299
16104
                [CAST_SIZE(gridX)];
300

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