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

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