GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/layoutarray.cpp Lines: 159 165 96.4 %
Date: 2021-03-17 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-2019  The ManaPlus Developers
6
 *  Copyright (C) 2019-2021  Andrei Karas
7
 *
8
 *  This file is part of The ManaPlus Client.
9
 *
10
 *  This program is free software; you can redistribute it and/or modify
11
 *  it under the terms of the GNU General Public License as published by
12
 *  the Free Software Foundation; either version 2 of the License, or
13
 *  any later version.
14
 *
15
 *  This program is distributed in the hope that it will be useful,
16
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 *  GNU General Public License for more details.
19
 *
20
 *  You should have received a copy of the GNU General Public License
21
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
 */
23
24
#include "gui/widgets/layoutarray.h"
25
26
#include "enums/gui/layouttype.h"
27
28
#include "gui/widgets/layoutcell.h"
29
#include "gui/widgets/widget.h"
30
31
#include <cassert>
32
33
#include "debug.h"
34
35
161
LayoutArray::LayoutArray() :
36
    mCells(),
37
644
    mSpacing(4)
38
{
39
161
}
40
41

483
LayoutArray::~LayoutArray()
42
{
43
    STD_VECTOR <STD_VECTOR <LayoutCell *> >::iterator
44
322
        i = mCells.begin();
45
    const STD_VECTOR <STD_VECTOR <LayoutCell *> >::iterator
46
322
        i_end = mCells.end();
47
1641
    while (i != i_end)
48
    {
49
1480
        STD_VECTOR< LayoutCell * >::iterator j = i->begin();
50
1480
        const STD_VECTOR< LayoutCell * >::iterator j_end = i->end();
51
5180
        while (j != j_end)
52
        {
53
4440
            delete *j;
54
            ++j;
55
        }
56
740
        ++i;
57
    }
58
161
}
59
60
701
LayoutCell &LayoutArray::at(const int x, const int y,
61
                            const int w, const int h)
62
{
63
701
    resizeGrid(x + w, y + h);
64
2103
    LayoutCell *&cell = mCells[CAST_SIZE(y)][static_cast<size_t>(x)];
65
701
    if (cell == nullptr)
66
1400
        cell = new LayoutCell;
67
701
    return *cell;
68
}
69
70
740
void LayoutArray::resizeGrid(int w, const int h)
71
{
72

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

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

623
    if (cs == LayoutType::DEF && w == 1)
155
157
        cs = 0;
156

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

1798
    if ((sizeCount != 0) && cell.mExtent[dim] > sizeCount)
171
1
        cnt = sizeCount;
172
173
3835
    for (int i = 1; i < cnt; ++i)
174
2037
        size_max += sizes[i] + mSpacing;
175
3596
    size = std::min<int>(cell.mSize[dim], size_max);
176
177

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

19900
            if ((cell == nullptr) || cell->mType == LayoutCell::NONE)
213
                continue;
214
215
3241
            if (cell->mExtent[dim] == 1)
216
            {
217
2184
                const int n = (dim == 0 ? gridX : gridY);
218
2184
                const int s = cell->mSize[dim] + cell->mVPadding * 2;
219
4368
                if (s > sizes[CAST_SIZE(n)])
220
1656
                    sizes[CAST_SIZE(n)] = s;
221
            }
222
        }
223
    }
224
225
751
    if (upp == LayoutType::DEF)
226
        return sizes;
227
228
    // Compute the FILL sizes.
229
856
    const int nb = CAST_S32(sizes.size());
230
428
    int nbFill = 0;
231
2204
    for (int i = 0; i < nb; ++i)
232
    {
233
5328
        if (mSizes[CAST_SIZE(dim)][static_cast<size_t>(i)]
234
1776
            <= LayoutType::DEF)
235
        {
236
1158
            ++nbFill;
237
2316
            if (mSizes[CAST_SIZE(dim)][static_cast<size_t>(i)] ==
238

2283
                LayoutType::SET ||
239
2250
                sizes[CAST_SIZE(i)] <= LayoutType::DEF)
240
            {
241
1988
                sizes[CAST_SIZE(i)] = 0;
242
            }
243
        }
244
3552
        upp -= sizes[CAST_SIZE(i)] + mSpacing;
245
    }
246
428
    upp = upp + mSpacing;
247
248
428
    if (nbFill == 0)
249
        return sizes;
250
251
3425
    for (int i = 0; i < nb; ++i)
252
    {
253
3042
        if (mSizes[CAST_SIZE(dim)][static_cast<size_t>(i)] >
254
            LayoutType::DEF)
255
        {
256
            continue;
257
        }
258
259
1158
        const int s = upp / nbFill;
260
2316
        sizes[CAST_SIZE(i)] += s;
261
1158
        upp -= s;
262
1158
        --nbFill;
263
    }
264
265
    return sizes;
266
}
267
268
316
int LayoutArray::getSize(const int dim) const
269
{
270
632
    STD_VECTOR<int> sizes = getSizes(dim, LayoutType::DEF);
271
316
    int size = 0;
272
632
    const int nb = CAST_S32(sizes.size());
273
1672
    for (int i = 0; i < nb; ++i)
274
    {
275
2712
        if (sizes[CAST_SIZE(i)] > LayoutType::DEF)
276
622
            size += sizes[CAST_SIZE(i)];
277
1356
        size += mSpacing;
278
    }
279
632
    return size - mSpacing;
280
}
281
282
214
void LayoutArray::reflow(const int nx, const int ny,
283
                         const int nw, const int nh)
284
{
285
428
    const int gridW = CAST_S32(mSizes[0].size());
286
428
    const int gridH = CAST_S32(mSizes[1].size());
287
288
428
    STD_VECTOR<int> widths  = getSizes(0, nw);
289
428
    STD_VECTOR<int> heights = getSizes(1, nh);
290
291
428
    const int szW = CAST_S32(widths.size());
292
428
    const int szH = CAST_S32(heights.size());
293
214
    int y = ny;
294
1186
    for (int gridY = 0; gridY < gridH; ++gridY)
295
    {
296
        int x = nx;
297
11928
        for (int gridX = 0; gridX < gridW; ++gridX)
298
        {
299
10956
            LayoutCell *const cell = mCells[CAST_SIZE(gridY)]
300
16434
                [CAST_SIZE(gridX)];
301

5478
            if ((cell != nullptr) && cell->mType != LayoutCell::NONE)
302
            {
303
899
                int dx = x;
304
899
                int dy = y;
305
899
                int dw = 0;
306
899
                int dh = 0;
307
899
                align(dx, dw, 0, *cell,
308
1798
                    &widths[CAST_SIZE(gridX)], szW - gridX);
309
899
                align(dy, dh, 1, *cell,
310
1798
                    &heights[CAST_SIZE(gridY)], szH - gridY);
311
899
                cell->reflow(dx, dy, dw, dh);
312
            }
313
10956
            x += widths[CAST_SIZE(gridX)] + mSpacing;
314
        }
315
1944
        y += heights[CAST_SIZE(gridY)] + mSpacing;
316
    }
317
214
}