GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/focushandler.cpp Lines: 71 226 31.4 %
Date: 2017-11-29 Branches: 36 160 22.5 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2004-2009  The Mana World Development Team
4
 *  Copyright (C) 2009-2010  The Mana Developers
5
 *  Copyright (C) 2011-2017  The ManaPlus Developers
6
 *
7
 *  This file is part of The ManaPlus Client.
8
 *
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or
12
 *  any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU General Public License
20
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
/*      _______   __   __   __   ______   __   __   _______   __   __
24
 *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
25
 *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
26
 *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
27
 *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
28
 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
29
 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
30
 *
31
 * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson
32
 *
33
 *
34
 * Per Larsson a.k.a finalman
35
 * Olof Naessén a.k.a jansem/yakslem
36
 *
37
 * Visit: http://guichan.sourceforge.net
38
 *
39
 * License: (BSD)
40
 * Redistribution and use in source and binary forms, with or without
41
 * modification, are permitted provided that the following conditions
42
 * are met:
43
 * 1. Redistributions of source code must retain the above copyright
44
 *    notice, this list of conditions and the following disclaimer.
45
 * 2. Redistributions in binary form must reproduce the above copyright
46
 *    notice, this list of conditions and the following disclaimer in
47
 *    the documentation and/or other materials provided with the
48
 *    distribution.
49
 * 3. Neither the name of Guichan nor the names of its contributors may
50
 *    be used to endorse or promote products derived from this software
51
 *    without specific prior written permission.
52
 *
53
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
54
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
55
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
56
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
57
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
58
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
59
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
60
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
61
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
62
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
63
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64
 */
65
66
#include "gui/focushandler.h"
67
68
#include "gui/gui.h"
69
70
#include "gui/widgets/window.h"
71
72
#include "listeners/focuslistener.h"
73
74
#include "utils/foreach.h"
75
76
#include "debug.h"
77
78
496
FocusHandler::FocusHandler() :
79
    mWidgets(),
80
    mFocusedWidget(nullptr),
81
    mModalFocusedWidget(nullptr),
82
    mModalMouseInputFocusedWidget(nullptr),
83
    mDraggedWidget(nullptr),
84
    mLastWidgetWithMouse(nullptr),
85
    mLastWidgetWithModalFocus(nullptr),
86
    mLastWidgetWithModalMouseInputFocus(nullptr),
87
    mLastWidgetPressed(nullptr),
88
1488
    mModalStack()
89
{
90
496
}
91
92
14
void FocusHandler::requestModalFocus(Widget *const widget)
93
{
94
    /* If there is another widget with modal focus, remove its modal focus
95
     * and put it on the modal widget stack.
96
     */
97

14
    if ((mModalFocusedWidget != nullptr) && mModalFocusedWidget != widget)
98
    {
99
        mModalStack.push_front(mModalFocusedWidget);
100
        mModalFocusedWidget = nullptr;
101
    }
102
103
14
    mModalFocusedWidget = widget;
104

14
    if ((mFocusedWidget != nullptr) && !mFocusedWidget->isModalFocused())
105
        focusNone();
106
14
}
107
108
4876
void FocusHandler::releaseModalFocus(Widget *const widget)
109
{
110
4876
    mModalStack.remove(widget);
111
112
4876
    if (mModalFocusedWidget == widget)
113
    {
114
10
        mModalFocusedWidget = nullptr;
115
116
        /* Check if there were any previously modal widgets that'd still like
117
         * to regain their modal focus.
118
         */
119
20
        if (!mModalStack.empty())
120
        {
121
            requestModalFocus(mModalStack.front());
122
            mModalStack.pop_front();
123
        }
124
    }
125
4876
}
126
127
2438
void FocusHandler::remove(Widget *const widget)
128
{
129
2438
    releaseModalFocus(widget);
130
131
2438
    if (isFocused(widget))
132
46
        mFocusedWidget = nullptr;
133
134
70650
    FOR_EACH (WidgetIterator, iter, mWidgets)
135
    {
136
63336
        if ((*iter) == widget)
137
        {
138
7314
            mWidgets.erase(iter);
139
2438
            break;
140
        }
141
    }
142
143
2438
    if (mDraggedWidget == widget)
144
    {
145
        mDraggedWidget = nullptr;
146
        return;
147
    }
148
149
2438
    if (mLastWidgetWithMouse == widget)
150
    {
151
        mLastWidgetWithMouse = nullptr;
152
        return;
153
    }
154
155
2438
    if (mLastWidgetWithModalFocus == widget)
156
    {
157
        mLastWidgetWithModalFocus = nullptr;
158
        return;
159
    }
160
161
2438
    if (mLastWidgetWithModalMouseInputFocus == widget)
162
    {
163
        mLastWidgetWithModalMouseInputFocus = nullptr;
164
        return;
165
    }
166
167
2438
    if (mLastWidgetPressed == widget)
168
    {
169
        mLastWidgetPressed = nullptr;
170
        return;
171
    }
172
}
173
174
void FocusHandler::tabNext()
175
{
176
    if (mFocusedWidget != nullptr)
177
    {
178
        if (!mFocusedWidget->isTabOutEnabled())
179
            return;
180
    }
181
182
    if (mWidgets.empty())
183
    {
184
        mFocusedWidget = nullptr;
185
        return;
186
    }
187
188
    int i;
189
    int focusedWidget = -1;
190
    const int sz = CAST_S32(mWidgets.size());
191
    for (i = 0; i < sz; ++ i)
192
    {
193
        if (mWidgets[i] == mFocusedWidget)
194
            focusedWidget = i;
195
    }
196
    const int focused = focusedWidget;
197
    bool done = false;
198
199
    // i is a counter that ensures that the following loop
200
    // won't get stuck in an infinite loop
201
    i = sz;
202
    do
203
    {
204
        ++ focusedWidget;
205
206
        if (i == 0)
207
        {
208
            focusedWidget = -1;
209
            break;
210
        }
211
212
        -- i;
213
214
        if (focusedWidget >= sz)
215
            focusedWidget = 0;
216
217
        if (focusedWidget == focused)
218
            return;
219
220
        const Widget *const widget = mWidgets.at(focusedWidget);
221
        if (widget->isFocusable() && widget->isTabInEnabled() &&
222
            ((mModalFocusedWidget == nullptr) || widget->isModalFocused()))
223
        {
224
            done = true;
225
        }
226
    }
227
    while (!done);
228
229
    if (focusedWidget >= 0)
230
    {
231
        mFocusedWidget = mWidgets.at(focusedWidget);
232
        Event focusEvent(mFocusedWidget);
233
        distributeFocusGainedEvent(focusEvent);
234
    }
235
236
    if (focused >= 0)
237
    {
238
        Event focusEvent(mWidgets.at(focused));
239
        distributeFocusLostEvent(focusEvent);
240
    }
241
242
    checkForWindow();
243
}
244
245
void FocusHandler::tabPrevious()
246
{
247
    if (mFocusedWidget != nullptr)
248
    {
249
        if (!mFocusedWidget->isTabOutEnabled())
250
            return;
251
    }
252
253
    if (mWidgets.empty())
254
    {
255
        mFocusedWidget = nullptr;
256
        return;
257
    }
258
259
    int i;
260
    int focusedWidget = -1;
261
    const int sz = CAST_S32(mWidgets.size());
262
    for (i = 0; i < sz; ++ i)
263
    {
264
        if (mWidgets[i] == mFocusedWidget)
265
            focusedWidget = i;
266
    }
267
    const int focused = focusedWidget;
268
    bool done = false;
269
270
    // i is a counter that ensures that the following loop
271
    // won't get stuck in an infinite loop
272
    i = sz;
273
    do
274
    {
275
        -- focusedWidget;
276
277
        if (i == 0)
278
        {
279
            focusedWidget = -1;
280
            break;
281
        }
282
283
        -- i;
284
285
        if (focusedWidget <= 0)
286
            focusedWidget = sz - 1;
287
288
        if (focusedWidget == focused)
289
            return;
290
291
        const Widget *const widget = mWidgets.at(focusedWidget);
292
        if (widget->isFocusable() && widget->isTabInEnabled() &&
293
            ((mModalFocusedWidget == nullptr) || widget->isModalFocused()))
294
        {
295
            done = true;
296
        }
297
    }
298
    while (!done);
299
300
    if (focusedWidget >= 0)
301
    {
302
        mFocusedWidget = mWidgets.at(focusedWidget);
303
        Event focusEvent(mFocusedWidget);
304
        distributeFocusGainedEvent(focusEvent);
305
    }
306
307
    if (focused >= 0)
308
    {
309
        Event focusEvent(mWidgets.at(focused));
310
        distributeFocusLostEvent(focusEvent);
311
    }
312
313
    checkForWindow();
314
}
315
316
void FocusHandler::checkForWindow() const
317
{
318
    if (mFocusedWidget != nullptr)
319
    {
320
        Widget *widget = mFocusedWidget->getParent();
321
322
        while (widget != nullptr)
323
        {
324
            Window *const window = dynamic_cast<Window*>(widget);
325
326
            if (window != nullptr)
327
            {
328
                window->requestMoveToTop();
329
                break;
330
            }
331
332
            widget = widget->getParent();
333
        }
334
    }
335
}
336
337
48
void FocusHandler::distributeFocusGainedEvent(const Event &focusEvent)
338
{
339
48
    if (gui != nullptr)
340
48
        gui->distributeGlobalFocusGainedEvent(focusEvent);
341
342
48
    const Widget *const sourceWidget = focusEvent.getSource();
343
344
48
    if (sourceWidget == nullptr)
345
        return;
346
    std::list<FocusListener*> focusListeners
347
96
        = sourceWidget->getFocusListeners();
348
349
    // Send the event to all focus listeners of the widget.
350
    for (std::list<FocusListener*>::const_iterator
351
144
          it = focusListeners.begin();
352
74
          it != focusListeners.end();
353
          ++ it)
354
    {
355
26
        (*it)->focusGained(focusEvent);
356
    }
357
}
358
359
48
void FocusHandler::requestFocus(const Widget *const widget)
360
{
361

48
    if ((widget == nullptr) || widget == mFocusedWidget)
362
        return;
363
364
48
    int toBeFocusedIndex = -1;
365
278
    for (unsigned int i = 0, fsz = CAST_U32(
366
96
         mWidgets.size()); i < fsz; ++i)
367
    {
368
556
        if (mWidgets[i] == widget)
369
        {
370
48
            toBeFocusedIndex = i;
371
48
            break;
372
        }
373
    }
374
375
48
    if (toBeFocusedIndex < 0)
376
        return;
377
378
48
    Widget *const oldFocused = mFocusedWidget;
379
380
    if (oldFocused != widget)
381
    {
382
96
        mFocusedWidget = mWidgets.at(toBeFocusedIndex);
383
384
48
        if (oldFocused != nullptr)
385
        {
386
            Event focusEvent(oldFocused);
387
            distributeFocusLostEvent(focusEvent);
388
        }
389
390
192
        Event focusEvent(mWidgets.at(toBeFocusedIndex));
391
48
        distributeFocusGainedEvent(focusEvent);
392
    }
393
}
394
395
void FocusHandler::requestModalMouseInputFocus(Widget *const widget)
396
{
397
    if ((mModalMouseInputFocusedWidget != nullptr)
398
        && mModalMouseInputFocusedWidget != widget)
399
    {
400
        return;
401
    }
402
403
    mModalMouseInputFocusedWidget = widget;
404
}
405
406
void FocusHandler::releaseModalMouseInputFocus(const Widget *const widget)
407
{
408
    if (mModalMouseInputFocusedWidget == widget)
409
        mModalMouseInputFocusedWidget = nullptr;
410
}
411
412
Widget* FocusHandler::getFocused() const
413
{
414
    return mFocusedWidget;
415
}
416
417
6
Widget* FocusHandler::getModalFocused() const
418
{
419
6
    return mModalFocusedWidget;
420
}
421
422
Widget* FocusHandler::getModalMouseInputFocused() const
423
{
424
    return mModalMouseInputFocusedWidget;
425
}
426
427
void FocusHandler::focusNext()
428
{
429
    int i;
430
    int focusedWidget = -1;
431
    const int sz = CAST_S32(mWidgets.size());
432
    for (i = 0; i < sz; ++i)
433
    {
434
        if (mWidgets[i] == mFocusedWidget)
435
            focusedWidget = i;
436
    }
437
    const int focused = focusedWidget;
438
439
    // i is a counter that ensures that the following loop
440
    // won't get stuck in an infinite loop
441
    i = sz;
442
    do
443
    {
444
        ++ focusedWidget;
445
446
        if (i == 0)
447
        {
448
            focusedWidget = -1;
449
            break;
450
        }
451
452
        -- i;
453
454
        if (focusedWidget >= sz)
455
            focusedWidget = 0;
456
457
        if (focusedWidget == focused)
458
            return;
459
    }
460
    while (!mWidgets.at(focusedWidget)->isFocusable());
461
462
    if (focusedWidget >= 0)
463
    {
464
        mFocusedWidget = mWidgets.at(focusedWidget);
465
466
        Event focusEvent(mFocusedWidget);
467
        distributeFocusGainedEvent(focusEvent);
468
    }
469
470
    if (focused >= 0)
471
    {
472
        Event focusEvent(mWidgets.at(focused));
473
        distributeFocusLostEvent(focusEvent);
474
    }
475
}
476
477
void FocusHandler::focusPrevious()
478
{
479
    if (mWidgets.empty())
480
    {
481
        mFocusedWidget = nullptr;
482
        return;
483
    }
484
485
    int i;
486
    int focusedWidget = -1;
487
    const int sz = CAST_S32(mWidgets.size());
488
    for (i = 0; i < sz; ++ i)
489
    {
490
        if (mWidgets[i] == mFocusedWidget)
491
            focusedWidget = i;
492
    }
493
    const int focused = focusedWidget;
494
495
    // i is a counter that ensures that the following loop
496
    // won't get stuck in an infinite loop
497
    i = sz;
498
    do
499
    {
500
        -- focusedWidget;
501
502
        if (i == 0)
503
        {
504
            focusedWidget = -1;
505
            break;
506
        }
507
508
        -- i;
509
510
        if (focusedWidget <= 0)
511
            focusedWidget = sz - 1;
512
513
        if (focusedWidget == focused)
514
            return;
515
    }
516
    while (!mWidgets.at(focusedWidget)->isFocusable());
517
518
    if (focusedWidget >= 0)
519
    {
520
        mFocusedWidget = mWidgets.at(focusedWidget);
521
        Event focusEvent(mFocusedWidget);
522
        distributeFocusGainedEvent(focusEvent);
523
    }
524
525
    if (focused >= 0)
526
    {
527
        Event focusEvent(mWidgets.at(focused));
528
        distributeFocusLostEvent(focusEvent);
529
    }
530
}
531
532
467
bool FocusHandler::isFocused(const Widget *const widget) const
533
{
534
2905
    return mFocusedWidget == widget;
535
}
536
537
2438
void FocusHandler::add(Widget *const widget)
538
{
539
2438
    mWidgets.push_back(widget);
540
2438
}
541
542
void FocusHandler::focusNone()
543
{
544

2
    if (mFocusedWidget != nullptr)
545
    {
546
2
        Widget *const focused = mFocusedWidget;
547
2
        mFocusedWidget = nullptr;
548
549
4
        Event focusEvent(focused);
550
2
        distributeFocusLostEvent(focusEvent);
551
    }
552
}
553
554
2
void FocusHandler::distributeFocusLostEvent(const Event& focusEvent)
555
{
556
2
    const Widget *const sourceWidget = focusEvent.getSource();
557
2
    if (sourceWidget == nullptr)
558
        return;
559
560
    std::list<FocusListener*> focusListeners
561
4
        = sourceWidget->getFocusListeners();
562
563
    // Send the event to all focus listeners of the widget.
564
    for (std::list<FocusListener*>::const_iterator
565
6
          it = focusListeners.begin();
566
4
          it != focusListeners.end();
567
          ++ it)
568
    {
569
2
        (*it)->focusLost(focusEvent);
570
    }
571
}
572
573
4724
Widget* FocusHandler::getDraggedWidget() const
574
{
575
4724
    return mDraggedWidget;
576
}
577
578
void FocusHandler::setDraggedWidget(Widget *const draggedWidget)
579
{
580
    mDraggedWidget = draggedWidget;
581
}
582
583
Widget* FocusHandler::getLastWidgetWithMouse() const
584
{
585
    return mLastWidgetWithMouse;
586
}
587
588
void FocusHandler::setLastWidgetWithMouse(Widget *const lastWidgetWithMouse)
589
{
590
    mLastWidgetWithMouse = lastWidgetWithMouse;
591
}
592
593
Widget* FocusHandler::getLastWidgetWithModalFocus() const
594
{
595
    return mLastWidgetWithModalFocus;
596
}
597
598
void FocusHandler::setLastWidgetWithModalFocus(Widget *const widget)
599
{
600
    mLastWidgetWithModalFocus = widget;
601
}
602
603
Widget* FocusHandler::getLastWidgetWithModalMouseInputFocus() const
604
{
605
    return mLastWidgetWithModalMouseInputFocus;
606
}
607
608
void FocusHandler::setLastWidgetWithModalMouseInputFocus(Widget *const widget)
609
{
610
    mLastWidgetWithModalMouseInputFocus = widget;
611
}
612
613
Widget* FocusHandler::getLastWidgetPressed() const
614
{
615
    return mLastWidgetPressed;
616
}
617
618
void FocusHandler::setLastWidgetPressed(Widget *const lastWidgetPressed)
619
{
620
    mLastWidgetPressed = lastWidgetPressed;
621
}