GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/basiccontainer.cpp Lines: 100 177 56.5 %
Date: 2017-11-29 Branches: 45 110 40.9 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2011-2017  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/foreach.h"
67
68
#include "render/graphics.h"
69
70
#include <algorithm>
71
72
#include "debug.h"
73
74
8450
BasicContainer::~BasicContainer()
75
{
76
1690
    clear();
77
1690
}
78
79
4
void BasicContainer::moveToTop(Widget *const widget) restrict2
80
{
81
16
    FOR_EACH (WidgetListIterator, iter, mWidgets)
82
    {
83
4
        if (*iter == widget)
84
        {
85
12
            mWidgets.erase(iter);
86
4
            mWidgets.push_back(widget);
87
            break;
88
        }
89
    }
90
16
    FOR_EACH (WidgetListIterator, iter, mLogicWidgets)
91
    {
92
4
        if (*iter == widget)
93
        {
94
12
            mLogicWidgets.erase(iter);
95
4
            mLogicWidgets.push_back(widget);
96
            return;
97
        }
98
    }
99
}
100
101
void BasicContainer::moveToBottom(Widget *const widget) restrict2
102
{
103
    const WidgetListIterator iter = std::find(mWidgets.begin(),
104
        mWidgets.end(), widget);
105
    if (iter != mWidgets.end())
106
    {
107
        mWidgets.erase(iter);
108
        mWidgets.insert(mWidgets.begin(), widget);
109
    }
110
111
    const WidgetListIterator iter2 = std::find(mLogicWidgets.begin(),
112
        mLogicWidgets.end(), widget);
113
    if (iter2 != mLogicWidgets.end())
114
    {
115
        mLogicWidgets.erase(iter2);
116
        mLogicWidgets.insert(mLogicWidgets.begin(), widget);
117
    }
118
}
119
120
4198
void BasicContainer::death(const Event &restrict event) restrict2
121
{
122
    const WidgetListIterator iter = std::find(mWidgets.begin(),
123
12594
        mWidgets.end(), event.getSource());
124
12594
    if (iter != mWidgets.end())
125
12594
        mWidgets.erase(iter);
126
127
    const WidgetListIterator iter2 = std::find(mLogicWidgets.begin(),
128
12594
        mLogicWidgets.end(), event.getSource());
129
12594
    if (iter2 != mLogicWidgets.end())
130
3810
        mLogicWidgets.erase(iter2);
131
4198
}
132
133
348
Rect BasicContainer::getChildrenArea() restrict2
134
{
135
696
    return Rect(0, 0, mDimension.width, mDimension.height);
136
}
137
138
void BasicContainer::focusNext() restrict2
139
{
140
    WidgetListConstIterator it;
141
142
    for (it = mWidgets.begin(); it != mWidgets.end(); ++ it)
143
    {
144
        if ((*it)->isFocused())
145
            break;
146
    }
147
148
    const WidgetListConstIterator end = it;
149
150
    if (it == mWidgets.end())
151
        it = mWidgets.begin();
152
153
    ++ it;
154
155
    for ( ; it != end; ++ it)
156
    {
157
        if (it == mWidgets.end())
158
            it = mWidgets.begin();
159
160
        if ((*it)->isFocusable())
161
        {
162
            (*it)->requestFocus();
163
            return;
164
        }
165
    }
166
}
167
168
void BasicContainer::focusPrevious() restrict2
169
{
170
    WidgetListReverseIterator it;
171
172
    for (it = mWidgets.rbegin(); it != mWidgets.rend(); ++ it)
173
    {
174
        if ((*it)->isFocused())
175
            break;
176
    }
177
178
    const WidgetListReverseIterator end = it;
179
180
    ++ it;
181
182
    if (it == mWidgets.rend())
183
        it = mWidgets.rbegin();
184
185
    for ( ; it != end; ++ it)
186
    {
187
        if (it == mWidgets.rend())
188
            it = mWidgets.rbegin();
189
190
        if ((*it)->isFocusable())
191
        {
192
            (*it)->requestFocus();
193
            return;
194
        }
195
    }
196
}
197
198
Widget *BasicContainer::getWidgetAt(int x, int y) restrict2
199
{
200
    const Rect r = getChildrenArea();
201
202
    if (!r.isPointInRect(x, y))
203
        return nullptr;
204
205
    x -= r.x;
206
    y -= r.y;
207
208
    for (WidgetListReverseIterator it = mWidgets.rbegin();
209
         it != mWidgets.rend(); ++ it)
210
    {
211
        const Widget *restrict const widget = *it;
212
        if (widget->isVisible() &&
213
            widget->getDimension().isPointInRect(x, y))
214
        {
215
            return *it;
216
        }
217
    }
218
219
    return nullptr;
220
}
221
222
5
void BasicContainer::logic() restrict2
223
{
224
    BLOCK_START("BasicContainer::logic")
225
5
    if (mVisible == Visible_false)
226
    {
227
        BLOCK_END("BasicContainer::logic")
228
        return;
229
    }
230
4
    logicChildren();
231
    BLOCK_END("BasicContainer::logic")
232
}
233
234
2762
void BasicContainer::setFocusHandler(FocusHandler *restrict2 const
235
                                     focusHandler) restrict2
236
{
237
2762
    Widget::setFocusHandler(focusHandler);
238
239
2762
    if (mInternalFocusHandler != nullptr)
240
        return;
241
242
19160
    FOR_EACH (WidgetListConstIterator, iter, mWidgets)
243
2588
        (*iter)->setFocusHandler(focusHandler);
244
}
245
246
4332
void BasicContainer::add(Widget *const widget) restrict2
247
{
248
4332
    if (widget == nullptr)
249
        return;
250
4332
    mWidgets.push_back(widget);
251
8664
    if (widget->isAllowLogic())
252
1396
        mLogicWidgets.push_back(widget);
253
254
4332
    if (mInternalFocusHandler == nullptr)
255
8664
        widget->setFocusHandler(getFocusHandler());
256
    else
257
        widget->setFocusHandler(mInternalFocusHandler);
258
259
4332
    widget->setParent(this);
260
4332
    widget->addDeathListener(this);
261
}
262
263
74
void BasicContainer::remove(Widget *const restrict widget) restrict2
264
{
265
74
    if (widget == nullptr)
266
        return;
267
308
    FOR_EACH (WidgetListIterator, iter, mWidgets)
268
    {
269
68
        if (*iter == widget)
270
        {
271
168
            mWidgets.erase(iter);
272
56
            widget->setFocusHandler(nullptr);
273
56
            widget->setWindow(nullptr);
274
56
            widget->setParent(nullptr);
275
56
            widget->removeDeathListener(this);
276
            break;
277
        }
278
    }
279
308
    FOR_EACH (WidgetListIterator, iter, mLogicWidgets)
280
    {
281
66
        if (*iter == widget)
282
        {
283
162
            mLogicWidgets.erase(iter);
284
54
            return;
285
        }
286
    }
287
}
288
289
2360
void BasicContainer::clear() restrict2
290
{
291
14238
    FOR_EACH (WidgetListConstIterator, iter, mWidgets)
292
    {
293
78
        Widget *restrict const widget = *iter;
294
78
        widget->setFocusHandler(nullptr);
295
78
        widget->setWindow(nullptr);
296
78
        widget->setParent(nullptr);
297
78
        widget->removeDeathListener(this);
298
    }
299
300
4720
    mWidgets.clear();
301
4720
    mLogicWidgets.clear();
302
2360
}
303
304
254
void BasicContainer::drawChildren(Graphics *const restrict graphics) restrict2
305
{
306
    BLOCK_START("BasicContainer::drawChildren")
307
254
    graphics->pushClipArea(getChildrenArea());
308
309
2342
    FOR_EACH (WidgetListConstIterator, iter, mWidgets)
310
    {
311
818
        Widget *restrict const widget = *iter;
312
818
        if (widget->mVisible == Visible_true)
313
        {
314
            // If the widget has a frame,
315
            // draw it before drawing the widget
316
626
            if (widget->mFrameSize > 0)
317
            {
318
366
                Rect rec = widget->mDimension;
319
122
                const int frame = CAST_S32(widget->mFrameSize);
320
122
                const int frame2 = frame * 2;
321
122
                rec.x -= frame;
322
122
                rec.y -= frame;
323
122
                rec.width += frame2;
324
122
                rec.height += frame2;
325
122
                graphics->pushClipArea(rec);
326
                BLOCK_START("BasicContainer::drawChildren 1")
327
122
                widget->drawFrame(graphics);
328
                BLOCK_END("BasicContainer::drawChildren 1")
329
122
                graphics->popClipArea();
330
            }
331
332
626
            graphics->pushClipArea(widget->mDimension);
333
            BLOCK_START("BasicContainer::drawChildren 2")
334
626
            widget->draw(graphics);
335
            BLOCK_END("BasicContainer::drawChildren 2")
336
626
            graphics->popClipArea();
337
        }
338
    }
339
340
254
    graphics->popClipArea();
341
    BLOCK_END("BasicContainer::drawChildren")
342
254
}
343
344
void BasicContainer::safeDrawChildren(Graphics *const restrict graphics)
345
                                      restrict2
346
{
347
    BLOCK_START("BasicContainer::drawChildren")
348
    graphics->pushClipArea(getChildrenArea());
349
350
    FOR_EACH (WidgetListConstIterator, iter, mWidgets)
351
    {
352
        Widget *restrict const widget = *iter;
353
        if (widget->mVisible == Visible_true)
354
        {
355
            // If the widget has a frame,
356
            // draw it before drawing the widget
357
            if (widget->mFrameSize > 0)
358
            {
359
                Rect rec = widget->mDimension;
360
                const int frame = CAST_S32(widget->mFrameSize);
361
                const int frame2 = frame * 2;
362
                rec.x -= frame;
363
                rec.y -= frame;
364
                rec.width += frame2;
365
                rec.height += frame2;
366
                graphics->pushClipArea(rec);
367
                BLOCK_START("BasicContainer::drawChildren 1")
368
                widget->safeDrawFrame(graphics);
369
                BLOCK_END("BasicContainer::drawChildren 1")
370
                graphics->popClipArea();
371
            }
372
373
            graphics->pushClipArea(widget->mDimension);
374
            BLOCK_START("BasicContainer::drawChildren 2")
375
            widget->safeDraw(graphics);
376
            BLOCK_END("BasicContainer::drawChildren 2")
377
            graphics->popClipArea();
378
        }
379
    }
380
381
    graphics->popClipArea();
382
    BLOCK_END("BasicContainer::drawChildren")
383
}
384
385
5
void BasicContainer::logicChildren() restrict2
386
{
387
    BLOCK_START("BasicContainer::logicChildren")
388
35
    FOR_EACH (WidgetListConstIterator, iter, mLogicWidgets)
389
5
        (*iter)->logic();
390
    BLOCK_END("BasicContainer::logicChildren")
391
5
}
392
393
398
void BasicContainer::showWidgetPart(Widget *restrict const widget,
394
                                    const Rect &restrict area) restrict2
395
{
396
398
    if (widget == nullptr)
397
        return;
398
399
796
    const Rect widgetArea = getChildrenArea();
400
401
398
    const int x = widget->mDimension.x;
402
398
    const int y = widget->mDimension.y;
403
398
    const int ax = area.x + x;
404
398
    const int ay = area.y + y;
405
406
398
    if (ax < 0)
407
        widget->setX(-area.x);
408
398
    else if (ax + area.width > widgetArea.width)
409
        widget->setX(widgetArea.width - area.x - area.width);
410
411
398
    if (ay < 0)
412
62
        widget->setY(-area.y);
413
336
    else if (ay + area.height > widgetArea.height)
414
328
        widget->setY(widgetArea.height - area.y - area.height);
415
}
416
417
void BasicContainer::setInternalFocusHandler(FocusHandler *const restrict
418
                                             focusHandler) restrict2
419
{
420
    Widget::setInternalFocusHandler(focusHandler);
421
422
    FocusHandler *const restrict handler = mInternalFocusHandler != nullptr ?
423
        mInternalFocusHandler : getFocusHandler();
424
    FOR_EACH (WidgetListConstIterator, iter, mWidgets)
425
    {
426
        (*iter)->setFocusHandler(handler);
427
    }
428
}
429
430
Widget *BasicContainer::findFirstWidget(const std::set<Widget*> &restrict list)
431
                                        restrict2
432
{
433
    FOR_EACHR (WidgetListReverseIterator, iter, mWidgets)
434
    {
435
        if (list.find(*iter) != list.end())
436
            return *iter;
437
    }
438
    return nullptr;
439
}