GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/basiccontainer.cpp Lines: 101 182 55.5 %
Date: 2021-03-17 Branches: 45 126 35.7 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2011-2019  The ManaPlus Developers
4
 *  Copyright (C) 2019-2021  Andrei Karas
5
 *
6
 *  This file is part of The ManaPlus Client.
7
 *
8
 *  This program is free software; you can redistribute it and/or modify
9
 *  it under the terms of the GNU General Public License as published by
10
 *  the Free Software Foundation; either version 2 of the License, or
11
 *  any later version.
12
 *
13
 *  This program is distributed in the hope that it will be useful,
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 *  GNU General Public License for more details.
17
 *
18
 *  You should have received a copy of the GNU General Public License
19
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 */
21
22
/*      _______   __   __   __   ______   __   __   _______   __   __
23
 *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
24
 *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
25
 *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
26
 *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
27
 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
28
 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
29
 *
30
 * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson
31
 *
32
 *
33
 * Per Larsson a.k.a finalman
34
 * Olof Naessén a.k.a jansem/yakslem
35
 *
36
 * Visit: http://guichan.sourceforge.net
37
 *
38
 * License: (BSD)
39
 * Redistribution and use in source and binary forms, with or without
40
 * modification, are permitted provided that the following conditions
41
 * are met:
42
 * 1. Redistributions of source code must retain the above copyright
43
 *    notice, this list of conditions and the following disclaimer.
44
 * 2. Redistributions in binary form must reproduce the above copyright
45
 *    notice, this list of conditions and the following disclaimer in
46
 *    the documentation and/or other materials provided with the
47
 *    distribution.
48
 * 3. Neither the name of Guichan nor the names of its contributors may
49
 *    be used to endorse or promote products derived from this software
50
 *    without specific prior written permission.
51
 *
52
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
53
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
54
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
55
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
56
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
57
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
58
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
59
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
60
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
61
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
62
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
63
 */
64
65
#include "gui/widgets/basiccontainer.h"
66
67
#include "utils/checkutils.h"
68
#include "utils/foreach.h"
69
70
#include "render/graphics.h"
71
72
#include <algorithm>
73
74
#include "debug.h"
75
76
4465
BasicContainer::~BasicContainer()
77
{
78
    // +++ virtual method call
79
893
    clear();
80
893
}
81
82
2
void BasicContainer::moveToTop(Widget *const widget) restrict2
83
{
84
2
    if (widget == nullptr)
85
    {
86
        reportAlways("BasicContainer::moveToTop empty widget.")
87
        return;
88
    }
89
90
8
    FOR_EACH (WidgetListIterator, iter, mWidgets)
91
    {
92
2
        if (*iter == widget)
93
        {
94
4
            mWidgets.erase(iter);
95
2
            mWidgets.push_back(widget);
96
            break;
97
        }
98
    }
99
8
    FOR_EACH (WidgetListIterator, iter, mLogicWidgets)
100
    {
101
2
        if (*iter == widget)
102
        {
103
4
            mLogicWidgets.erase(iter);
104
2
            mLogicWidgets.push_back(widget);
105
            return;
106
        }
107
    }
108
}
109
110
void BasicContainer::moveToBottom(Widget *const widget) restrict2
111
{
112
    if (widget == nullptr)
113
    {
114
        reportAlways("BasicContainer::moveToBottom empty widget.")
115
        return;
116
    }
117
    const WidgetListIterator iter = std::find(mWidgets.begin(),
118
        mWidgets.end(), widget);
119
    if (iter != mWidgets.end())
120
    {
121
        mWidgets.erase(iter);
122
        mWidgets.insert(mWidgets.begin(), widget);
123
    }
124
125
    const WidgetListIterator iter2 = std::find(mLogicWidgets.begin(),
126
        mLogicWidgets.end(), widget);
127
    if (iter2 != mLogicWidgets.end())
128
    {
129
        mLogicWidgets.erase(iter2);
130
        mLogicWidgets.insert(mLogicWidgets.begin(), widget);
131
    }
132
}
133
134
2227
void BasicContainer::death(const Event &restrict event) restrict2
135
{
136
    const WidgetListIterator iter = std::find(mWidgets.begin(),
137
6681
        mWidgets.end(), event.getSource());
138
6681
    if (iter != mWidgets.end())
139
4454
        mWidgets.erase(iter);
140
141
    const WidgetListIterator iter2 = std::find(mLogicWidgets.begin(),
142
6681
        mLogicWidgets.end(), event.getSource());
143
6681
    if (iter2 != mLogicWidgets.end())
144
1326
        mLogicWidgets.erase(iter2);
145
2227
}
146
147
178
Rect BasicContainer::getChildrenArea() restrict2
148
{
149
356
    return Rect(0, 0, mDimension.width, mDimension.height);
150
}
151
152
void BasicContainer::focusNext() restrict2
153
{
154
    WidgetListConstIterator it;
155
156
    for (it = mWidgets.begin(); it != mWidgets.end(); ++ it)
157
    {
158
        if ((*it)->isFocused())
159
            break;
160
    }
161
162
    const WidgetListConstIterator end = it;
163
164
    if (it == mWidgets.end())
165
        it = mWidgets.begin();
166
167
    ++ it;
168
169
    for ( ; it != end; ++ it)
170
    {
171
        if (it == mWidgets.end())
172
            it = mWidgets.begin();
173
174
        if ((*it)->isFocusable())
175
        {
176
            (*it)->requestFocus();
177
            return;
178
        }
179
    }
180
}
181
182
void BasicContainer::focusPrevious() restrict2
183
{
184
    WidgetListReverseIterator it;
185
186
    for (it = mWidgets.rbegin(); it != mWidgets.rend(); ++ it)
187
    {
188
        if ((*it)->isFocused())
189
            break;
190
    }
191
192
    const WidgetListReverseIterator end = it;
193
194
    ++ it;
195
196
    if (it == mWidgets.rend())
197
        it = mWidgets.rbegin();
198
199
    for ( ; it != end; ++ it)
200
    {
201
        if (it == mWidgets.rend())
202
            it = mWidgets.rbegin();
203
204
        if ((*it)->isFocusable())
205
        {
206
            (*it)->requestFocus();
207
            return;
208
        }
209
    }
210
}
211
212
Widget *BasicContainer::getWidgetAt(int x, int y) restrict2
213
{
214
    const Rect r = getChildrenArea();
215
216
    if (!r.isPointInRect(x, y))
217
        return nullptr;
218
219
    x -= r.x;
220
    y -= r.y;
221
222
    for (WidgetListReverseIterator it = mWidgets.rbegin();
223
         it != mWidgets.rend(); ++ it)
224
    {
225
        const Widget *restrict const widget = *it;
226
        if (widget->isVisible() &&
227
            widget->getDimension().isPointInRect(x, y))
228
        {
229
            return *it;
230
        }
231
    }
232
233
    return nullptr;
234
}
235
236
4
void BasicContainer::logic() restrict2
237
{
238
    BLOCK_START("BasicContainer::logic")
239
4
    if (mVisible == Visible_false)
240
    {
241
        BLOCK_END("BasicContainer::logic")
242
        return;
243
    }
244
4
    logicChildren();
245
    BLOCK_END("BasicContainer::logic")
246
}
247
248
1468
void BasicContainer::setFocusHandler(FocusHandler *restrict2 const
249
                                     focusHandler) restrict2
250
{
251
1468
    Widget::setFocusHandler(focusHandler);
252
253
1468
    if (mInternalFocusHandler != nullptr)
254
        return;
255
256
10221
    FOR_EACH (WidgetListConstIterator, iter, mWidgets)
257
1413
        (*iter)->setFocusHandler(focusHandler);
258
}
259
260
2302
void BasicContainer::add(Widget *const widget) restrict2
261
{
262
2302
    if (widget == nullptr)
263
        return;
264
2302
    mWidgets.push_back(widget);
265
4604
    if (widget->isAllowLogic())
266
734
        mLogicWidgets.push_back(widget);
267
268
2302
    if (mInternalFocusHandler == nullptr)
269
4604
        widget->setFocusHandler(getFocusHandler());
270
    else
271
        widget->setFocusHandler(mInternalFocusHandler);
272
273
2302
    widget->setParent(this);
274
2302
    widget->addDeathListener(this);
275
}
276
277
39
void BasicContainer::remove(Widget *const restrict widget) restrict2
278
{
279
39
    if (widget == nullptr)
280
        return;
281
162
    FOR_EACH (WidgetListIterator, iter, mWidgets)
282
    {
283
36
        if (*iter == widget)
284
        {
285
60
            mWidgets.erase(iter);
286
30
            widget->setFocusHandler(nullptr);
287
30
            widget->setWindow(nullptr);
288
30
            widget->setParent(nullptr);
289
30
            widget->removeDeathListener(this);
290
            break;
291
        }
292
    }
293
162
    FOR_EACH (WidgetListIterator, iter, mLogicWidgets)
294
    {
295
35
        if (*iter == widget)
296
        {
297
58
            mLogicWidgets.erase(iter);
298
29
            return;
299
        }
300
    }
301
}
302
303
1238
void BasicContainer::clear() restrict2
304
{
305
7473
    FOR_EACH (WidgetListConstIterator, iter, mWidgets)
306
    {
307
45
        Widget *restrict const widget = *iter;
308
45
        widget->setFocusHandler(nullptr);
309
45
        widget->setWindow(nullptr);
310
45
        widget->setParent(nullptr);
311
45
        widget->removeDeathListener(this);
312
    }
313
314
2476
    mWidgets.clear();
315
2476
    mLogicWidgets.clear();
316
1238
}
317
318
128
void BasicContainer::drawChildren(Graphics *const restrict graphics) restrict2
319
{
320
    BLOCK_START("BasicContainer::drawChildren")
321
128
    graphics->pushClipArea(getChildrenArea());
322
323
1182
    FOR_EACH (WidgetListConstIterator, iter, mWidgets)
324
    {
325
414
        Widget *restrict const widget = *iter;
326
414
        if (widget->mVisible == Visible_true)
327
        {
328
            // If the widget has a frame,
329
            // draw it before drawing the widget
330
314
            if (widget->mFrameSize > 0)
331
            {
332
186
                Rect rec = widget->mDimension;
333
62
                const int frame = CAST_S32(widget->mFrameSize);
334
62
                const int frame2 = frame * 2;
335
62
                rec.x -= frame;
336
62
                rec.y -= frame;
337
62
                rec.width += frame2;
338
62
                rec.height += frame2;
339
62
                graphics->pushClipArea(rec);
340
                BLOCK_START("BasicContainer::drawChildren 1")
341
62
                widget->drawFrame(graphics);
342
                BLOCK_END("BasicContainer::drawChildren 1")
343
62
                graphics->popClipArea();
344
            }
345
346
314
            graphics->pushClipArea(widget->mDimension);
347
            BLOCK_START("BasicContainer::drawChildren 2")
348
314
            widget->draw(graphics);
349
            BLOCK_END("BasicContainer::drawChildren 2")
350
314
            graphics->popClipArea();
351
        }
352
    }
353
354
128
    graphics->popClipArea();
355
    BLOCK_END("BasicContainer::drawChildren")
356
128
}
357
358
void BasicContainer::safeDrawChildren(Graphics *const restrict graphics)
359
                                      restrict2
360
{
361
    BLOCK_START("BasicContainer::drawChildren")
362
    graphics->pushClipArea(getChildrenArea());
363
364
    FOR_EACH (WidgetListConstIterator, iter, mWidgets)
365
    {
366
        Widget *restrict const widget = *iter;
367
        if (widget->mVisible == Visible_true)
368
        {
369
            // If the widget has a frame,
370
            // draw it before drawing the widget
371
            if (widget->mFrameSize > 0)
372
            {
373
                Rect rec = widget->mDimension;
374
                const int frame = CAST_S32(widget->mFrameSize);
375
                const int frame2 = frame * 2;
376
                rec.x -= frame;
377
                rec.y -= frame;
378
                rec.width += frame2;
379
                rec.height += frame2;
380
                graphics->pushClipArea(rec);
381
                BLOCK_START("BasicContainer::drawChildren 1")
382
                widget->safeDrawFrame(graphics);
383
                BLOCK_END("BasicContainer::drawChildren 1")
384
                graphics->popClipArea();
385
            }
386
387
            graphics->pushClipArea(widget->mDimension);
388
            BLOCK_START("BasicContainer::drawChildren 2")
389
            widget->safeDraw(graphics);
390
            BLOCK_END("BasicContainer::drawChildren 2")
391
            graphics->popClipArea();
392
        }
393
    }
394
395
    graphics->popClipArea();
396
    BLOCK_END("BasicContainer::drawChildren")
397
}
398
399
5
void BasicContainer::logicChildren() restrict2
400
{
401
    BLOCK_START("BasicContainer::logicChildren")
402
35
    FOR_EACH (WidgetListConstIterator, iter, mLogicWidgets)
403
5
        (*iter)->logic();
404
    BLOCK_END("BasicContainer::logicChildren")
405
5
}
406
407
210
void BasicContainer::showWidgetPart(Widget *restrict const widget,
408
                                    const Rect &restrict area) restrict2
409
{
410
210
    if (widget == nullptr)
411
        return;
412
413
420
    const Rect widgetArea = getChildrenArea();
414
415
210
    const int x = widget->mDimension.x;
416
210
    const int y = widget->mDimension.y;
417
210
    const int ax = area.x + x;
418
210
    const int ay = area.y + y;
419
420
210
    if (ax < 0)
421
        widget->setX(-area.x);
422
210
    else if (ax + area.width > widgetArea.width)
423
        widget->setX(widgetArea.width - area.x - area.width);
424
425
210
    if (ay < 0)
426
37
        widget->setY(-area.y);
427
173
    else if (ay + area.height > widgetArea.height)
428
169
        widget->setY(widgetArea.height - area.y - area.height);
429
}
430
431
void BasicContainer::setInternalFocusHandler(FocusHandler *const restrict
432
                                             focusHandler) restrict2
433
{
434
    Widget::setInternalFocusHandler(focusHandler);
435
436
    FocusHandler *const restrict handler = mInternalFocusHandler != nullptr ?
437
        mInternalFocusHandler : getFocusHandler();
438
    FOR_EACH (WidgetListConstIterator, iter, mWidgets)
439
    {
440
        (*iter)->setFocusHandler(handler);
441
    }
442
}
443
444
Widget *BasicContainer::findFirstWidget(const std::set<Widget*> &restrict list)
445
                                        restrict2
446
{
447
    FOR_EACHR (WidgetListReverseIterator, iter, mWidgets)
448
    {
449
        if (list.find(*iter) != list.end())
450
            return *iter;
451
    }
452
    return nullptr;
453
}