GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/widget.cpp Lines: 180 222 81.1 %
Date: 2021-03-17 Branches: 66 114 57.9 %

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
/*
66
 * For comments regarding functions please see the header file.
67
 */
68
69
#include "gui/widgets/widget.h"
70
71
#include "gui/focushandler.h"
72
73
#include "listeners/actionlistener.h"
74
#include "listeners/widgetdeathlistener.h"
75
#include "listeners/widgetlistener.h"
76
77
#include "utils/foreach.h"
78
79
#include "debug.h"
80
81
Font* Widget::mGlobalFont = nullptr;
82
1
std::list<Widget*> Widget::mAllWidgets;
83
1
std::set<Widget*> Widget::mAllWidgetsSet;
84
85
2512
Widget::Widget(const Widget2 *const widget) :
86
    Widget2(widget),
87
    mVisible(Visible_true),
88
    mMouseListeners(),
89
    mKeyListeners(),
90
    mActionListeners(),
91
    mDeathListeners(),
92
    mFocusListeners(),
93
    mWidgetListeners(),
94
    mForegroundColor(0x000000),
95
    mBackgroundColor(0xffffff),
96
    mBaseColor(0x808090),
97
    mDimension(),
98
    mActionEventId(),
99
    mId(),
100
    mFocusHandler(nullptr),
101
    mInternalFocusHandler(nullptr),
102
    mParent(nullptr),
103
    mCurrentFont(nullptr),
104
    mFrameSize(0),
105
    mFocusable(false),
106
    mTabIn(true),
107
    mTabOut(true),
108
    mEnabled(true),
109
    mAllowLogic(true),
110
    mMouseConsume(true),
111
    mRedraw(true),
112
35168
    mSelectable(true)
113
{
114
5024
    mAllWidgets.push_back(this);
115
5024
    mAllWidgetsSet.insert(this);
116
2512
}
117
118
27632
Widget::~Widget()
119
{
120
7536
    FOR_EACH (WidgetDeathListenerIterator, iter, mDeathListeners)
121
    {
122
4454
        Event event(this);
123
2227
        (*iter)->death(event);
124
    }
125
126
    // +++ call to virtual member
127
2512
    setFocusHandler(nullptr);
128
129
2512
    mAllWidgets.remove(this);
130
5024
    mAllWidgetsSet.erase(this);
131
2512
}
132
133
5097
void Widget::setWidth(const int width)
134
{
135
15291
    Rect newDimension = mDimension;
136
5097
    newDimension.width = width;
137
5097
    setDimension(newDimension);
138
5097
}
139
140
3693
void Widget::setHeight(const int height)
141
{
142
11079
    Rect newDimension = mDimension;
143
3693
    newDimension.height = height;
144
3693
    setDimension(newDimension);
145
3693
}
146
147
void Widget::setX(const int x)
148
{
149
    Rect newDimension = mDimension;
150
    newDimension.x = x;
151
    setDimension(newDimension);
152
}
153
154
206
void Widget::setY(const int y)
155
{
156
618
    Rect newDimension = mDimension;
157
206
    newDimension.y = y;
158
206
    setDimension(newDimension);
159
206
}
160
161
2430
void Widget::setPosition(const int x, const int y)
162
{
163
7290
    Rect newDimension = mDimension;
164
2430
    newDimension.x = x;
165
2430
    newDimension.y = y;
166
2430
    setDimension(newDimension);
167
2430
}
168
169
13254
void Widget::setDimension(const Rect& dimension)
170
{
171
39762
    const Rect oldDimension = mDimension;
172
26508
    mDimension = dimension;
173
174
13254
    if (mDimension.width != oldDimension.width
175
13254
        || mDimension.height != oldDimension.height)
176
    {
177
        distributeResizedEvent();
178
    }
179
180
13254
    if (mDimension.x != oldDimension.x || mDimension.y != oldDimension.y)
181
        distributeMovedEvent();
182
13254
}
183
184
568
bool Widget::isFocused() const
185
{
186
568
    if (mFocusHandler == nullptr)
187
        return false;
188
189
235
    return mFocusHandler->isFocused(this);
190
}
191
192
1357
void Widget::setFocusable(const bool focusable)
193
{
194


1357
    if (!focusable && isFocused() && (mFocusHandler != nullptr))
195
        mFocusHandler->focusNone();
196
1357
    mFocusable = focusable;
197
1357
}
198
199
29
bool Widget::isFocusable() const
200
{
201

58
    return mFocusable && isVisible() && isEnabled();
202
}
203
204
29
void Widget::requestFocus()
205
{
206
29
    if (mFocusHandler == nullptr)
207
        return;
208
209
29
    if (isFocusable())
210
24
        mFocusHandler->requestFocus(this);
211
}
212
213
void Widget::requestMoveToTop()
214
{
215
    if (mParent != nullptr)
216
        mParent->moveToTop(this);
217
}
218
219
void Widget::requestMoveToBottom()
220
{
221
    if (mParent != nullptr)
222
        mParent->moveToBottom(this);
223
}
224
225
559
void Widget::setVisible(Visible visible)
226
{
227


559
    if (visible == Visible_false && isFocused() && (mFocusHandler != nullptr))
228
        mFocusHandler->focusNone();
229
230
559
    if (visible == Visible_true)
231
        distributeShownEvent();
232
    else
233
        distributeHiddenEvent();
234
235
559
    mVisible = visible;
236
559
}
237
238
6550
void Widget::setFocusHandler(FocusHandler *const focusHandler)
239
{
240
6550
    if (mFocusHandler != nullptr)
241
    {
242
1246
        releaseModalFocus();
243
1246
        mFocusHandler->remove(this);
244
    }
245
246
6550
    if (focusHandler != nullptr)
247
1246
        focusHandler->add(this);
248
249
6550
    mFocusHandler = focusHandler;
250
6550
}
251
252
1970
void Widget::addActionListener(ActionListener *const actionListener)
253
{
254
3940
    mActionListeners.push_back(actionListener);
255
1970
}
256
257
6
void Widget::removeActionListener(ActionListener *const actionListener)
258
{
259
6
    mActionListeners.remove(actionListener);
260
6
}
261
262
2302
void Widget::addDeathListener(WidgetDeathListener *const deathListener)
263
{
264
4604
    mDeathListeners.push_back(deathListener);
265
2302
}
266
267
75
void Widget::removeDeathListener(WidgetDeathListener *const deathListener)
268
{
269
75
    mDeathListeners.remove(deathListener);
270
75
}
271
272
1179
void Widget::addKeyListener(KeyListener *const keyListener)
273
{
274
2358
    mKeyListeners.push_back(keyListener);
275
1179
}
276
277
100
void Widget::removeKeyListener(KeyListener *const keyListener)
278
{
279
100
    mKeyListeners.remove(keyListener);
280
100
}
281
282
547
void Widget::addFocusListener(FocusListener *const focusListener)
283
{
284
1094
    mFocusListeners.push_back(focusListener);
285
547
}
286
287
99
void Widget::removeFocusListener(FocusListener *const focusListener)
288
{
289
99
    mFocusListeners.remove(focusListener);
290
99
}
291
292
2277
void Widget::addMouseListener(MouseListener *const mouseListener)
293
{
294
4554
    mMouseListeners.push_back(mouseListener);
295
2277
}
296
297
615
void Widget::removeMouseListener(MouseListener *const mouseListener)
298
{
299
615
    mMouseListeners.remove(mouseListener);
300
615
}
301
302
2206
void Widget::addWidgetListener(WidgetListener *const widgetListener)
303
{
304
4412
    mWidgetListeners.push_back(widgetListener);
305
2206
}
306
307
1480
void Widget::removeWidgetListener(WidgetListener *const widgetListener)
308
{
309
1480
    mWidgetListeners.remove(widgetListener);
310
1480
}
311
312
113
void Widget::getAbsolutePosition(int& x, int& y) const
313
{
314
113
    if (mParent == nullptr)
315
    {
316
74
        x = mDimension.x;
317
74
        y = mDimension.y;
318
74
        return;
319
    }
320
321
    int parentX;
322
    int parentY;
323
324
39
    mParent->getAbsolutePosition(parentX, parentY);
325
326
78
    const Rect &rect = mParent->getChildrenArea();
327
39
    x = parentX + mDimension.x + rect.x;
328
39
    y = parentY + mDimension.y + rect.y;
329
}
330
331
2848
Font* Widget::getFont() const
332
{
333
2848
    if (mCurrentFont == nullptr)
334
2843
        return mGlobalFont;
335
    return mCurrentFont;
336
}
337
338
131
void Widget::setGlobalFont(Font *const font)
339
{
340
131
    mGlobalFont = font;
341
342
655
    FOR_EACH (std::list<Widget*>::const_iterator, iter, mAllWidgets)
343
    {
344
133
        if ((*iter)->mCurrentFont == nullptr)
345
133
            (*iter)->fontChanged();
346
    }
347
131
}
348
349
18
void Widget::setFont(Font *const font)
350
{
351
18
    mCurrentFont = font;
352
18
    fontChanged();
353
18
}
354
355
void Widget::distributeWindowResizeEvent()
356
{
357
    FOR_EACH (std::list<Widget*>::const_iterator, iter, mAllWidgets)
358
        (*iter)->windowResized();
359
}
360
361
127
bool Widget::widgetExists(const Widget *const widget)
362
{
363
254
    return mAllWidgetsSet.find(const_cast<Widget*>(widget))
364
254
        != mAllWidgetsSet.end();
365
}
366
367
957
void Widget::setSize(const int width, const int height)
368
{
369
2871
    Rect newDimension = mDimension;
370
957
    newDimension.width = width;
371
957
    newDimension.height = height;
372
957
    setDimension(newDimension);
373
957
}
374
375
128
bool Widget::isEnabled() const
376
{
377

225
    return mEnabled && isVisible();
378
}
379
380
7
void Widget::requestModalFocus()
381
{
382
7
    if (mFocusHandler == nullptr)
383
        return;
384
7
    mFocusHandler->requestModalFocus(this);
385
}
386
387
void Widget::requestModalMouseInputFocus()
388
{
389
    if (mFocusHandler == nullptr)
390
        return;
391
    mFocusHandler->requestModalMouseInputFocus(this);
392
}
393
394
1246
void Widget::releaseModalFocus()
395
{
396
1246
    if (mFocusHandler == nullptr)
397
        return;
398
1246
    mFocusHandler->releaseModalFocus(this);
399
}
400
401
void Widget::releaseModalMouseInputFocus()
402
{
403
    if (mFocusHandler == nullptr)
404
        return;
405
    mFocusHandler->releaseModalMouseInputFocus(this);
406
}
407
408
3
bool Widget::isModalFocused() const
409
{
410
3
    if (mFocusHandler == nullptr)
411
        return false;
412
413
3
    if (mParent != nullptr)
414
    {
415
2
        return (mFocusHandler->getModalFocused() == this)
416

2
            || mParent->isModalFocused();
417
    }
418
419
1
    return mFocusHandler->getModalFocused() == this;
420
}
421
422
bool Widget::isModalMouseInputFocused() const
423
{
424
    if (mFocusHandler == nullptr)
425
        return false;
426
427
    if (mParent != nullptr)
428
    {
429
        return (mFocusHandler->getModalMouseInputFocused() == this)
430
            || mParent->isModalMouseInputFocused();
431
    }
432
433
    return mFocusHandler->getModalMouseInputFocused() == this;
434
}
435
436
const std::list<MouseListener*> &Widget::getMouseListeners() const
437
{
438
    return mMouseListeners;
439
}
440
441
const std::list<KeyListener*> &Widget::getKeyListeners() const
442
{
443
    return mKeyListeners;
444
}
445
446
25
const std::list<FocusListener*> &Widget::getFocusListeners() const
447
{
448
25
    return mFocusListeners;
449
}
450
451
Rect Widget::getChildrenArea()
452
{
453
    return Rect(0, 0, 0, 0);
454
}
455
456
FocusHandler* Widget::getInternalFocusHandler()
457
{
458
    return mInternalFocusHandler;
459
}
460
461
void Widget::setInternalFocusHandler(FocusHandler *const focusHandler)
462
{
463
    mInternalFocusHandler = focusHandler;
464
}
465
466
9
void Widget::distributeResizedEvent()
467
{
468

18447
    FOR_EACH (WidgetListenerIterator, iter, mWidgetListeners)
469
    {
470
5066
        Event event(this);
471
2533
        (*iter)->widgetResized(event);
472
    }
473
9
}
474
475
void Widget::distributeMovedEvent()
476
{
477

6606
    FOR_EACH (WidgetListenerIterator, iter, mWidgetListeners)
478
    {
479
3766
        Event event(this);
480
1883
        (*iter)->widgetMoved(event);
481
    }
482
}
483
484
void Widget::distributeHiddenEvent()
485
{
486

1140
    FOR_EACH (WidgetListenerIterator, iter, mWidgetListeners)
487
    {
488
620
        Event event(this);
489
310
        (*iter)->widgetHidden(event);
490
    }
491
}
492
493
1
void Widget::distributeActionEvent()
494
{
495
3
    FOR_EACH (ActionListenerIterator, iter, mActionListeners)
496
    {
497
3
        ActionEvent actionEvent(this, mActionEventId);
498
1
        (*iter)->action(actionEvent);
499
    }
500
1
}
501
502
void Widget::distributeShownEvent()
503
{
504

537
    FOR_EACH (WidgetListenerIterator, iter, mWidgetListeners)
505
    {
506
734
        Event event(this);
507
367
        (*iter)->widgetShown(event);
508
    }
509
}
510
511
210
void Widget::showPart(const Rect &rectangle)
512
{
513
210
    if (mParent != nullptr)
514
210
        mParent->showWidgetPart(this, rectangle);
515
210
}
516
517
void Widget::windowResized()
518
{
519
    mRedraw = true;
520
}
521
522
254
Widget *Widget::callPostInit(Widget *const widget)
523
{
524
254
    if (widget != nullptr)
525
254
        widget->postInit();
526
254
    return widget;
527

3
}