GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/scrollarea.cpp Lines: 299 685 43.6 %
Date: 2020-06-04 Branches: 183 683 26.8 %

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-2019  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/widgets/scrollarea.h"
67
68
#include "settings.h"
69
70
#include "gui/gui.h"
71
#include "gui/skin.h"
72
73
#include "utils/delete2.h"
74
#include "utils/stringutils.h"
75
76
#include "render/graphics.h"
77
78
#include "render/vertexes/imagecollection.h"
79
80
#include "resources/imagerect.h"
81
82
#include "resources/image/image.h"
83
84
#include "debug.h"
85
86
int ScrollArea::instances = 0;
87
float ScrollArea::mAlpha = 1.0;
88
bool ScrollArea::mShowButtons = true;
89
int ScrollArea::mMarkerSize = 0;
90
int ScrollArea::mScrollbarSize = 12;
91
1
ImageRect ScrollArea::background;
92
1
ImageRect ScrollArea::vMarker;
93
1
ImageRect ScrollArea::vMarkerHi;
94
1
ImageRect ScrollArea::vBackground;
95
1
ImageRect ScrollArea::hBackground;
96
Image *ScrollArea::buttons[4][2];
97
98
3
static std::string const buttonFiles[2] =
99
{
100
    "scrollbuttons.xml",
101
    "scrollbuttons_pressed.xml"
102

5
};
103
104
164
ScrollArea::ScrollArea(Widget2 *const widget2,
105
                       Widget *const widget,
106
                       const Opaque opaque,
107
164
                       const std::string &skin) :
108
    BasicContainer(widget2),
109
    MouseListener(),
110
    WidgetListener(),
111

164
    mVertexes(new ImageCollection),
112

164
    mVertexes2(new ImageCollection),
113
    mHPolicy(SHOW_AUTO),
114
    mVPolicy(SHOW_AUTO),
115
    mVScroll(0),
116
    mHScroll(0),
117
    mScrollbarWidth(12),
118
    mUpButtonScrollAmount(10),
119
    mDownButtonScrollAmount(10),
120
    mLeftButtonScrollAmount(10),
121
    mRightButtonScrollAmount(10),
122
    mHorizontalMarkerDragOffset(0),
123
    mVerticalMarkerDragOffset(0),
124
    mX(0),
125
    mY(0),
126
    mClickX(0),
127
    mClickY(0),
128
    mXOffset(0),
129
    mYOffset(0),
130
    mDrawWidth(0),
131
    mDrawHeight(0),
132
    mVBarVisible(false),
133
    mHBarVisible(false),
134
    mUpButtonPressed(false),
135
    mDownButtonPressed(false),
136
    mLeftButtonPressed(false),
137
    mRightButtonPressed(false),
138
    mIsVerticalMarkerDragged(false),
139
    mIsHorizontalMarkerDragged(false),
140
    mOpaque(Opaque_true),
141
984
    mHasMouse(false)
142
{
143
164
    setContent(widget);
144
164
    addMouseListener(this);
145
164
    mOpaque = opaque;
146
328
    init(skin);
147
164
}
148
149
820
ScrollArea::~ScrollArea()
150
{
151
164
    if (gui != nullptr)
152
164
        gui->removeDragged(this);
153
154
    // Garbage collection
155
164
    delete getContent();
156
157
164
    instances--;
158
164
    if (instances == 0)
159
    {
160
35
        Theme::unloadRect(background, 0, 8);
161
35
        Theme::unloadRect(vMarker, 0, 8);
162
35
        Theme::unloadRect(vMarkerHi, 0, 8);
163
35
        Theme::unloadRect(vBackground, 0, 8);
164
35
        Theme::unloadRect(hBackground, 0, 8);
165
105
        for (int i = 0; i < 2; i ++)
166
        {
167
630
            for (int f = UP; f < BUTTONS_DIR; f ++)
168
            {
169
280
                if (buttons[f][i] != nullptr)
170
280
                    buttons[f][i]->decRef();
171
            }
172
        }
173
    }
174
175
164
    delete2(mVertexes)
176
164
    delete2(mVertexes2)
177
178
164
    setContent(nullptr);
179
328
}
180
181
164
void ScrollArea::init(std::string skinName)
182
{
183
328
    setOpaque(mOpaque);
184
185
328
    setUpButtonScrollAmount(2);
186
328
    setDownButtonScrollAmount(2);
187
328
    setLeftButtonScrollAmount(2);
188
328
    setRightButtonScrollAmount(2);
189
190
164
    if (instances == 0)
191
    {
192
665
        for (int f = 0; f < 9; f ++)
193
        {
194
315
            background.grid[f] = nullptr;
195
315
            vMarker.grid[f] = nullptr;
196
315
            vMarkerHi.grid[f] = nullptr;
197
315
            vBackground.grid[f] = nullptr;
198
315
            hBackground.grid[f] = nullptr;
199
        }
200
201
        // +++ here probably need move background from static
202
35
        if (skinName.empty())
203
            skinName = "scroll_background.xml";
204
35
        if (theme != nullptr)
205
        {
206
140
            theme->loadRect(background,
207
                skinName,
208
                "scroll_background.xml",
209
                0,
210
35
                8);
211
245
            theme->loadRect(vMarker,
212
                "scroll.xml",
213
                "",
214
                0,
215
35
                8);
216
245
            theme->loadRect(vMarkerHi,
217
                "scroll_highlighted.xml",
218
                "scroll.xml",
219
                0,
220
35
                8);
221
245
            theme->loadRect(vBackground,
222
                "scroll_vbackground.xml",
223
                "",
224
                0,
225
35
                8);
226
245
            theme->loadRect(hBackground,
227
                "scroll_hbackground.xml",
228
                "",
229
                0,
230
35
                8);
231
        }
232
233
175
        for (int i = 0; i < 2; i ++)
234
        {
235
70
            Skin *skin = nullptr;
236
70
            if (theme != nullptr)
237
            {
238
280
                skin = theme->load(buttonFiles[i],
239
                    "scrollbuttons.xml",
240
                    true,
241
140
                    Theme::getThemePath());
242
            }
243
70
            if (skin != nullptr)
244
            {
245
70
                const ImageRect &rect = skin->getBorder();
246
350
                for (int f = UP; f < BUTTONS_DIR; f ++)
247
                {
248
280
                    if (rect.grid[f] != nullptr)
249
280
                        rect.grid[f]->incRef();
250
280
                    buttons[f][i] = rect.grid[f];
251
                }
252
70
                if (i == 0)
253
                {
254
140
                    mShowButtons = (skin->getOption("showbuttons", 1) == 1);
255
140
                    mMarkerSize = skin->getOption("markersize", 0);
256
140
                    mScrollbarSize = skin->getOption("scrollbarsize", 12);
257
                }
258
            }
259
            else
260
            {
261
                for (int f = UP; f < BUTTONS_DIR; f ++)
262
                    buttons[f][i] = nullptr;
263
            }
264
70
            if (theme != nullptr)
265
70
                theme->unload(skin);
266
        }
267
    }
268
164
    mScrollbarWidth = mScrollbarSize;
269
164
    instances++;
270
164
}
271
272
1
void ScrollArea::logic()
273
{
274
    BLOCK_START("ScrollArea::logic")
275
2
    if (!isVisible())
276
    {
277
        BLOCK_END("ScrollArea::logic")
278
        return;
279
    }
280
281
1
    checkPolicies();
282
283
2
    setVerticalScrollAmount(mVScroll);
284
2
    setHorizontalScrollAmount(mHScroll);
285
286
1
    Widget *const content = getContent();
287
1
    if (content != nullptr)
288
    {
289
1
        unsigned int frameSize = content->getFrameSize();
290
1
        content->setPosition(-mHScroll + frameSize, -mVScroll + frameSize);
291
1
        content->logic();
292
293
        // When no scrollbar in a certain direction,
294
        // adapt content size to match the content dimension exactly.
295
1
        frameSize = 2 * content->getFrameSize();
296
1
        if (mHPolicy == ScrollArea::SHOW_NEVER)
297
        {
298
3
            content->setWidth((mVBarVisible ? (mDimension.width
299
3
                - mScrollbarWidth) : mDimension.width) - frameSize);
300
        }
301
1
        if (mVPolicy == ScrollArea::SHOW_NEVER)
302
        {
303
            content->setHeight((mHBarVisible ? (mDimension.height
304
                - mScrollbarWidth) : mDimension.height) - frameSize);
305
        }
306
    }
307
308
1
    if (mUpButtonPressed)
309
        setVerticalScrollAmount(mVScroll - mUpButtonScrollAmount);
310
1
    else if (mDownButtonPressed)
311
        setVerticalScrollAmount(mVScroll + mDownButtonScrollAmount);
312
1
    else if (mLeftButtonPressed)
313
        setHorizontalScrollAmount(mHScroll - mLeftButtonScrollAmount);
314
1
    else if (mRightButtonPressed)
315
        setHorizontalScrollAmount(mHScroll + mRightButtonScrollAmount);
316
    BLOCK_END("ScrollArea::logic")
317
}
318
319
17
void ScrollArea::updateAlpha()
320
{
321
    const float alpha = std::max(settings.guiAlpha,
322
51
        theme->getMinimumOpacity());
323
324
17
    if (alpha != mAlpha)
325
    {
326
        mAlpha = alpha;
327
        for (int a = 0; a < 9; a++)
328
        {
329
            if (background.grid[a] != nullptr)
330
                background.grid[a]->setAlpha(mAlpha);
331
            if (hBackground.grid[a] != nullptr)
332
                hBackground.grid[a]->setAlpha(mAlpha);
333
            if (vBackground.grid[a] != nullptr)
334
                vBackground.grid[a]->setAlpha(mAlpha);
335
            if (vMarker.grid[a] != nullptr)
336
                vMarker.grid[a]->setAlpha(mAlpha);
337
            if (vMarkerHi.grid[a] != nullptr)
338
                vMarkerHi.grid[a]->setAlpha(mAlpha);
339
        }
340
    }
341
17
}
342
343
17
void ScrollArea::draw(Graphics *const graphics)
344
{
345
    BLOCK_START("ScrollArea::draw")
346

17
    if (mVBarVisible || mHBarVisible)
347
    {
348
11
        if (mOpaque == Opaque_false)
349
            updateCalcFlag(graphics);
350
        // need add caching or remove calc calls.
351
//        if (mRedraw)
352
        {
353
11
            mVertexes->clear();
354
11
            if (mVBarVisible)
355
            {
356
11
                if (mShowButtons)
357
                {
358
                    calcButton(graphics, UP);
359
                    calcButton(graphics, DOWN);
360
                }
361
11
                calcVBar(graphics);
362
11
                calcVMarker(graphics);
363
            }
364
365
11
            if (mHBarVisible)
366
            {
367
                if (mShowButtons)
368
                {
369
                    calcButton(graphics, LEFT);
370
                    calcButton(graphics, RIGHT);
371
                }
372
                calcHBar(graphics);
373
                calcHMarker(graphics);
374
            }
375
11
            graphics->finalize(mVertexes);
376
        }
377
11
        graphics->drawTileCollection(mVertexes);
378
    }
379
380
17
    updateAlpha();
381
382
17
    if (mRedraw)
383
    {
384
17
        const bool redraw = graphics->getRedraw();
385
17
        graphics->setRedraw(true);
386
17
        drawChildren(graphics);
387
17
        graphics->setRedraw(redraw);
388
    }
389
    else
390
    {
391
        drawChildren(graphics);
392
    }
393
17
    mRedraw = false;
394
    BLOCK_END("ScrollArea::draw")
395
17
}
396
397
void ScrollArea::safeDraw(Graphics *const graphics)
398
{
399
    BLOCK_START("ScrollArea::draw")
400
    if (mVBarVisible)
401
    {
402
        if (mShowButtons)
403
        {
404
            drawButton(graphics, UP);
405
            drawButton(graphics, DOWN);
406
        }
407
        drawVBar(graphics);
408
        drawVMarker(graphics);
409
    }
410
411
    if (mHBarVisible)
412
    {
413
        if (mShowButtons)
414
        {
415
            drawButton(graphics, LEFT);
416
            drawButton(graphics, RIGHT);
417
        }
418
        drawHBar(graphics);
419
        drawHMarker(graphics);
420
    }
421
422
    updateAlpha();
423
424
    safeDrawChildren(graphics);
425
    mRedraw = false;
426
    BLOCK_END("ScrollArea::draw")
427
}
428
429
16
void ScrollArea::updateCalcFlag(const Graphics *const graphics)
430
{
431
16
    if (!mRedraw)
432
    {
433
        // because we don't know where parent windows was moved,
434
        // need recalc vertexes
435
        const ClipRect &rect = graphics->getTopClip();
436
        if (rect.xOffset != mXOffset || rect.yOffset != mYOffset)
437
        {
438
            mRedraw = true;
439
            mXOffset = rect.xOffset;
440
            mYOffset = rect.yOffset;
441
        }
442
        else if (rect.width != mDrawWidth || rect.height != mDrawHeight)
443
        {
444
            mRedraw = true;
445
            mDrawWidth = rect.width;
446
            mDrawHeight = rect.height;
447
        }
448
        else if (graphics->getRedraw())
449
        {
450
            mRedraw = true;
451
        }
452
    }
453
16
}
454
455
16
void ScrollArea::drawFrame(Graphics *const graphics)
456
{
457
    BLOCK_START("ScrollArea::drawFrame")
458
16
    if (mOpaque == Opaque_true)
459
    {
460
16
        updateCalcFlag(graphics);
461
462
16
        if (mRedraw)
463
        {
464
16
            const int bs = mFrameSize * 2;
465
16
            const int w = mDimension.width + bs;
466
16
            const int h = mDimension.height + bs;
467
16
            mVertexes2->clear();
468
16
            graphics->calcWindow(mVertexes2,
469
                0, 0,
470
                w, h,
471
32
                background);
472
16
            graphics->finalize(mVertexes2);
473
        }
474
16
        graphics->drawTileCollection(mVertexes2);
475
    }
476
    BLOCK_END("ScrollArea::drawFrame")
477
16
}
478
479
void ScrollArea::safeDrawFrame(Graphics *const graphics)
480
{
481
    BLOCK_START("ScrollArea::drawFrame")
482
    if (mOpaque == Opaque_true)
483
    {
484
        const int bs = mFrameSize * 2;
485
        const int w = mDimension.width + bs;
486
        const int h = mDimension.height + bs;
487
488
        updateCalcFlag(graphics);
489
        graphics->drawImageRect(0, 0,
490
            w, h,
491
            background);
492
    }
493
    BLOCK_END("ScrollArea::drawFrame")
494
}
495
496
void ScrollArea::setOpaque(Opaque opaque)
497
{
498
    mOpaque = opaque;
499

328
    setFrameSize(mOpaque == Opaque_true ? 2 : 0);
500
}
501
502
Image *ScrollArea::getImageByState(Rect &dim, const BUTTON_DIR dir)
503
{
504
    int state = 0;
505
506
    switch (dir)
507
    {
508
        case UP:
509
            state = mUpButtonPressed ? 1 : 0;
510
            dim = getUpButtonDimension();
511
            break;
512
        case DOWN:
513
            state = mDownButtonPressed ? 1 : 0;
514
            dim = getDownButtonDimension();
515
            break;
516
        case LEFT:
517
            state = mLeftButtonPressed ? 1 : 0;
518
            dim = getLeftButtonDimension();
519
            break;
520
        case RIGHT:
521
            state = mRightButtonPressed ? 1 : 0;
522
            dim = getRightButtonDimension();
523
            break;
524
        case BUTTONS_DIR:
525
        default:
526
            logger->log("ScrollArea::drawButton unknown dir: "
527
                        + toString(CAST_U32(dir)));
528
            return nullptr;
529
    }
530
    return buttons[CAST_SIZE(dir)][state];
531
}
532
533
void ScrollArea::drawButton(Graphics *const graphics,
534
                            const BUTTON_DIR dir)
535
{
536
    Rect dim;
537
    const Image *const image = getImageByState(dim, dir);
538
539
    if (image != nullptr)
540
        graphics->drawImage(image, dim.x, dim.y);
541
}
542
543
void ScrollArea::calcButton(Graphics *const graphics,
544
                            const BUTTON_DIR dir)
545
{
546
    Rect dim;
547
    const Image *const image = getImageByState(dim, dir);
548
549
    if (image != nullptr)
550
    {
551
        static_cast<Graphics*>(graphics)->calcTileCollection(
552
            mVertexes, image, dim.x, dim.y);
553
    }
554
}
555
556
void ScrollArea::drawVBar(Graphics *const graphics) const
557
{
558
    const Rect &dim = getVerticalBarDimension();
559
560
    if (vBackground.grid[4] != nullptr)
561
    {
562
        graphics->drawPattern(vBackground.grid[4],
563
            dim.x, dim.y, dim.width, dim.height);
564
    }
565
    if (vBackground.grid[1] != nullptr)
566
    {
567
        graphics->drawPattern(vBackground.grid[1],
568
            dim.x, dim.y,
569
            dim.width, vBackground.grid[1]->getHeight());
570
    }
571
    if (vBackground.grid[7] != nullptr)
572
    {
573
        graphics->drawPattern(vBackground.grid[7],
574
            dim.x, dim.height - vBackground.grid[7]->getHeight() + dim.y,
575
            dim.width, vBackground.grid[7]->getHeight());
576
    }
577
}
578
579
11
void ScrollArea::calcVBar(const Graphics *const graphics)
580
{
581
22
    const Rect &dim = getVerticalBarDimension();
582
583
11
    if (vBackground.grid[4] != nullptr)
584
    {
585
11
        graphics->calcPattern(mVertexes,
586
            vBackground.grid[4],
587
11
            dim.x, dim.y,
588
22
            dim.width, dim.height);
589
    }
590
11
    if (vBackground.grid[1] != nullptr)
591
    {
592
22
        graphics->calcPattern(mVertexes,
593
            vBackground.grid[1],
594
11
            dim.x, dim.y,
595
33
            dim.width, vBackground.grid[1]->getHeight());
596
    }
597
11
    if (vBackground.grid[7] != nullptr)
598
    {
599
33
        graphics->calcPattern(mVertexes,
600
            vBackground.grid[7],
601
22
            dim.x, dim.height - vBackground.grid[7]->getHeight() + dim.y,
602
33
            dim.width, vBackground.grid[7]->getHeight());
603
    }
604
11
}
605
606
void ScrollArea::drawHBar(Graphics *const graphics) const
607
{
608
    const Rect &dim = getHorizontalBarDimension();
609
610
    if (hBackground.grid[4] != nullptr)
611
    {
612
        graphics->drawPattern(hBackground.grid[4],
613
            dim.x, dim.y,
614
            dim.width, dim.height);
615
    }
616
617
    if (hBackground.grid[3] != nullptr)
618
    {
619
        graphics->drawPattern(hBackground.grid[3],
620
            dim.x, dim.y,
621
            hBackground.grid[3]->getWidth(), dim.height);
622
    }
623
624
    if (hBackground.grid[5] != nullptr)
625
    {
626
        graphics->drawPattern(hBackground.grid[5],
627
            dim.x + dim.width - hBackground.grid[5]->getWidth(),
628
            dim.y,
629
            hBackground.grid[5]->getWidth(),
630
            dim.height);
631
    }
632
}
633
634
void ScrollArea::calcHBar(const Graphics *const graphics)
635
{
636
    const Rect &dim = getHorizontalBarDimension();
637
638
    if (hBackground.grid[4] != nullptr)
639
    {
640
        graphics->calcPattern(mVertexes,
641
            hBackground.grid[4],
642
            dim.x, dim.y,
643
            dim.width, dim.height);
644
    }
645
646
    if (hBackground.grid[3] != nullptr)
647
    {
648
        graphics->calcPattern(mVertexes,
649
            hBackground.grid[3],
650
            dim.x, dim.y,
651
            hBackground.grid[3]->getWidth(), dim.height);
652
    }
653
654
    if (hBackground.grid[5] != nullptr)
655
    {
656
        graphics->calcPattern(mVertexes,
657
            hBackground.grid[5],
658
            dim.x + dim.width - hBackground.grid[5]->getWidth(),
659
            dim.y,
660
            hBackground.grid[5]->getWidth(),
661
            dim.height);
662
    }
663
}
664
665
void ScrollArea::drawVMarker(Graphics *const graphics)
666
{
667
    const Rect &dim = getVerticalMarkerDimension();
668
669
    if ((mHasMouse) && (mX > (mDimension.width - mScrollbarWidth)))
670
    {
671
        graphics->drawImageRect(dim.x, dim.y,
672
            dim.width, dim.height,
673
            vMarkerHi);
674
    }
675
    else
676
    {
677
        graphics->drawImageRect(dim.x, dim.y,
678
            dim.width, dim.height,
679
            vMarker);
680
    }
681
}
682
683
11
void ScrollArea::calcVMarker(Graphics *const graphics)
684
{
685
22
    const Rect &dim = getVerticalMarkerDimension();
686
687

11
    if ((mHasMouse) && (mX > (mDimension.width - mScrollbarWidth)))
688
    {
689
        graphics->calcWindow(mVertexes,
690
            dim.x, dim.y,
691
            dim.width, dim.height,
692
            vMarkerHi);
693
    }
694
    else
695
    {
696
11
        graphics->calcWindow(mVertexes,
697
11
            dim.x, dim.y,
698
11
            dim.width, dim.height,
699
22
            vMarker);
700
    }
701
11
}
702
703
void ScrollArea::drawHMarker(Graphics *const graphics)
704
{
705
    const Rect dim = getHorizontalMarkerDimension();
706
707
    if ((mHasMouse) && (mY > (mDimension.height - mScrollbarWidth)))
708
    {
709
        graphics->drawImageRect(dim.x, dim.y,
710
            dim.width, dim.height,
711
            vMarkerHi);
712
    }
713
    else
714
    {
715
        graphics->drawImageRect(
716
            dim.x, dim.y,
717
            dim.width, dim.height,
718
            vMarker);
719
    }
720
}
721
722
void ScrollArea::calcHMarker(Graphics *const graphics)
723
{
724
    const Rect dim = getHorizontalMarkerDimension();
725
726
    if ((mHasMouse) && (mY > (mDimension.height - mScrollbarWidth)))
727
    {
728
        graphics->calcWindow(mVertexes,
729
            dim.x, dim.y,
730
            dim.width, dim.height,
731
            vMarkerHi);
732
    }
733
    else
734
    {
735
        graphics->calcWindow(mVertexes,
736
            dim.x, dim.y,
737
            dim.width, dim.height,
738
            vMarker);
739
    }
740
}
741
742
void ScrollArea::mouseMoved(MouseEvent& event)
743
{
744
    mX = event.getX();
745
    mY = event.getY();
746
}
747
748
void ScrollArea::mouseEntered(MouseEvent& event A_UNUSED)
749
{
750
    mHasMouse = true;
751
}
752
753
void ScrollArea::mouseExited(MouseEvent& event A_UNUSED)
754
{
755
    mHasMouse = false;
756
}
757
758
void ScrollArea::widgetResized(const Event &event A_UNUSED)
759
{
760
    mRedraw = true;
761
    Widget *const content = getContent();
762
    if (content != nullptr)
763
    {
764
        const unsigned int frameSize = 2 * mFrameSize;
765
        content->setSize(mDimension.width - frameSize,
766
            mDimension.height - frameSize);
767
    }
768
}
769
770
void ScrollArea::widgetMoved(const Event& event A_UNUSED)
771
{
772
    mRedraw = true;
773
}
774
775
void ScrollArea::mousePressed(MouseEvent& event)
776
{
777
    const int x = event.getX();
778
    const int y = event.getY();
779
780
    if (getUpButtonDimension().isPointInRect(x, y))
781
    {
782
        setVerticalScrollAmount(mVScroll
783
                                - mUpButtonScrollAmount);
784
        mUpButtonPressed = true;
785
        event.consume();
786
    }
787
    else if (getDownButtonDimension().isPointInRect(x, y))
788
    {
789
        setVerticalScrollAmount(mVScroll
790
                                + mDownButtonScrollAmount);
791
        mDownButtonPressed = true;
792
        event.consume();
793
    }
794
    else if (getLeftButtonDimension().isPointInRect(x, y))
795
    {
796
        setHorizontalScrollAmount(mHScroll
797
                                  - mLeftButtonScrollAmount);
798
        mLeftButtonPressed = true;
799
        event.consume();
800
    }
801
    else if (getRightButtonDimension().isPointInRect(x, y))
802
    {
803
        setHorizontalScrollAmount(mHScroll
804
                                  + mRightButtonScrollAmount);
805
        mRightButtonPressed = true;
806
        event.consume();
807
    }
808
    else if (getVerticalMarkerDimension().isPointInRect(x, y))
809
    {
810
        mIsHorizontalMarkerDragged = false;
811
        mIsVerticalMarkerDragged = true;
812
813
        mVerticalMarkerDragOffset = y - getVerticalMarkerDimension().y;
814
        event.consume();
815
    }
816
    else if (getVerticalBarDimension().isPointInRect(x, y))
817
    {
818
        if (y < getVerticalMarkerDimension().y)
819
        {
820
            setVerticalScrollAmount(mVScroll
821
                - CAST_S32(getChildrenArea().height * 0.1));
822
        }
823
        else
824
        {
825
            setVerticalScrollAmount(mVScroll
826
                + CAST_S32(getChildrenArea().height * 0.1));
827
        }
828
        event.consume();
829
    }
830
    else if (getHorizontalMarkerDimension().isPointInRect(x, y))
831
    {
832
        mIsHorizontalMarkerDragged = true;
833
        mIsVerticalMarkerDragged = false;
834
        mHorizontalMarkerDragOffset = x - getHorizontalMarkerDimension().x;
835
        event.consume();
836
    }
837
    else if (getHorizontalBarDimension().isPointInRect(x, y))
838
    {
839
        if (x < getHorizontalMarkerDimension().x)
840
        {
841
            setHorizontalScrollAmount(mHScroll
842
                - CAST_S32(getChildrenArea().width * 0.1));
843
        }
844
        else
845
        {
846
            setHorizontalScrollAmount(mHScroll
847
                + CAST_S32(getChildrenArea().width * 0.1));
848
        }
849
        event.consume();
850
    }
851
852
    if (event.getButton() == MouseButton::LEFT &&
853
        !event.isConsumed())
854
    {
855
        mClickX = event.getX();
856
        mClickY = event.getY();
857
    }
858
}
859
860
void ScrollArea::mouseReleased(MouseEvent& event)
861
{
862
    if (event.getButton() == MouseButton::LEFT &&
863
        mClickX != 0 &&
864
        mClickY != 0)
865
    {
866
        if (!event.isConsumed())
867
        {
868
#ifdef ANDROID
869
            int dx = mClickX - event.getX();
870
            int dy = mClickY - event.getY();
871
#else  // ANDROID
872
873
            int dx = event.getX() - mClickX;
874
            int dy = event.getY() - mClickY;
875
#endif  // ANDROID
876
877
            if ((dx < 20 && dx > 0) || (dx > -20 && dx < 0))
878
                dx = 0;
879
880
            if ((dy < 20 && dy > 0) || (dy > -20 && dy < 0))
881
                dy = 0;
882
883
            if (abs(dx) > abs(dy))
884
            {
885
                int s = mHScroll + dx;
886
                if (s < 0)
887
                {
888
                    s = 0;
889
                }
890
                else
891
                {
892
                    const int maxH = getHorizontalMaxScroll();
893
                    if (s > maxH)
894
                        s = maxH;
895
                }
896
897
                setHorizontalScrollAmount(s);
898
            }
899
            else if (dy != 0)
900
            {
901
                int s = mVScroll + dy;
902
                if (s < 0)
903
                {
904
                    s = 0;
905
                }
906
                else
907
                {
908
                    const int maxV = getVerticalMaxScroll();
909
                    if (s > maxV)
910
                        s = maxV;
911
                }
912
913
                setVerticalScrollAmount(s);
914
            }
915
            mClickX = 0;
916
            mClickY = 0;
917
            if (mMouseConsume && ((dx != 0) || (dy != 0)))
918
                event.consume();
919
        }
920
    }
921
    mUpButtonPressed = false;
922
    mDownButtonPressed = false;
923
    mLeftButtonPressed = false;
924
    mRightButtonPressed = false;
925
    mIsHorizontalMarkerDragged = false;
926
    mIsVerticalMarkerDragged = false;
927
    if (mMouseConsume)
928
        event.consume();
929
    mRedraw = true;
930
}
931
932
void ScrollArea::mouseDragged(MouseEvent &event)
933
{
934
    if (mIsVerticalMarkerDragged)
935
    {
936
        const Rect barDim = getVerticalBarDimension();
937
        const int length = getVerticalMarkerDimension().height;
938
939
        if ((barDim.height - length) > 0)
940
        {
941
            const int pos = event.getY() - barDim.y
942
                - mVerticalMarkerDragOffset;
943
            setVerticalScrollAmount((getVerticalMaxScroll() * pos)
944
                                      / (barDim.height - length));
945
        }
946
        else
947
        {
948
            setVerticalScrollAmount(0);
949
        }
950
    }
951
952
    if (mIsHorizontalMarkerDragged)
953
    {
954
        const Rect barDim = getHorizontalBarDimension();
955
        const int length = getHorizontalMarkerDimension().width;
956
957
        if ((barDim.width - length) > 0)
958
        {
959
            const int pos = event.getX() - barDim.x
960
                - mHorizontalMarkerDragOffset;
961
            setHorizontalScrollAmount((getHorizontalMaxScroll() * pos)
962
                                      / (barDim.width - length));
963
        }
964
        else
965
        {
966
            setHorizontalScrollAmount(0);
967
        }
968
    }
969
970
    event.consume();
971
    mRedraw = true;
972
}
973
974
11
Rect ScrollArea::getVerticalBarDimension() const
975
{
976
11
    if (!mVBarVisible)
977
        return Rect(0, 0, 0, 0);
978
979
11
    const int height = mShowButtons ? mScrollbarWidth : 0;
980
11
    if (mHBarVisible)
981
    {
982
        return Rect(mDimension.width - mScrollbarWidth,
983
            height,
984
            mScrollbarWidth,
985
            mDimension.height - 2 * height - mScrollbarWidth);
986
    }
987
988
11
    return Rect(mDimension.width - mScrollbarWidth,
989
        height,
990
11
        mScrollbarWidth,
991
22
        mDimension.height - 2 * height);
992
}
993
994
Rect ScrollArea::getHorizontalBarDimension() const
995
{
996
    if (!mHBarVisible)
997
        return Rect(0, 0, 0, 0);
998
999
    const int width = mShowButtons ? mScrollbarWidth : 0;
1000
    if (mVBarVisible)
1001
    {
1002
        return Rect(width,
1003
            mDimension.height - mScrollbarWidth,
1004
            mDimension.width - 2 * width - mScrollbarWidth,
1005
            mScrollbarWidth);
1006
    }
1007
1008
    return Rect(width,
1009
                      mDimension.height - mScrollbarWidth,
1010
                      mDimension.width - 2 * width,
1011
                      mScrollbarWidth);
1012
}
1013
1014
11
Rect ScrollArea::getVerticalMarkerDimension()
1015
{
1016
11
    if (!mVBarVisible)
1017
        return Rect(0, 0, 0, 0);
1018
1019
    int length;
1020
    int pos;
1021
    int height;
1022
    const int h2 = mShowButtons
1023
11
        ? mScrollbarWidth : mMarkerSize / 2;
1024
    const Widget *content;
1025
22
    if (!mWidgets.empty())
1026
22
        content = *mWidgets.begin();
1027
    else
1028
        content = nullptr;
1029
1030
11
    if (mHBarVisible)
1031
        height = mDimension.height - 2 * h2 - mScrollbarWidth;
1032
    else
1033
11
        height = mDimension.height - 2 * h2;
1034
1035
11
    const int maxV = getVerticalMaxScroll();
1036

11
    if ((mMarkerSize != 0) && (maxV != 0))
1037
    {
1038
        pos = (mVScroll * height / maxV - mMarkerSize / 2);
1039
        length = mMarkerSize;
1040
    }
1041
    else
1042
    {
1043
11
        if (content != nullptr)
1044
        {
1045
11
            const int h3 = content->getHeight();
1046
11
            if (h3 != 0)
1047
10
                length = (height * getChildrenArea().height) / h3;
1048
            else
1049
                length = height;
1050
        }
1051
        else
1052
        {
1053
            length = height;
1054
        }
1055
1056
11
        if (length < mScrollbarWidth)
1057
            length = mScrollbarWidth;
1058
1059
11
        if (length > height)
1060
10
            length = height;
1061
1062
11
        if (maxV != 0)
1063
            pos = ((height - length) * mVScroll) / maxV;
1064
        else
1065
            pos = 0;
1066
    }
1067
1068
11
    return Rect(mDimension.width - mScrollbarWidth, h2 + pos,
1069
22
        mScrollbarWidth, length);
1070
}
1071
1072
Rect ScrollArea::getHorizontalMarkerDimension()
1073
{
1074
    if (!mHBarVisible)
1075
        return Rect(0, 0, 0, 0);
1076
1077
    int length;
1078
    int pos;
1079
    int width;
1080
    const int w2 = mShowButtons
1081
        ? mScrollbarWidth : mMarkerSize / 2;
1082
    const Widget *content;
1083
    if (!mWidgets.empty())
1084
        content = *mWidgets.begin();
1085
    else
1086
        content = nullptr;
1087
1088
    if (mVBarVisible)
1089
        width = mDimension.width - 2 * w2 - mScrollbarWidth;
1090
    else
1091
        width = mDimension.width - w2 - mScrollbarWidth;
1092
1093
    const int maxH = getHorizontalMaxScroll();
1094
    if (mMarkerSize != 0 && maxH != 0)
1095
    {
1096
        pos = (mHScroll * width / maxH - mMarkerSize / 2);
1097
        length = mMarkerSize;
1098
    }
1099
    else
1100
    {
1101
        if (content != nullptr)
1102
        {
1103
            const int w3 = content->getWidth();
1104
            if (w3 != 0)
1105
                length = (width * getChildrenArea().width) / w3;
1106
            else
1107
                length = width;
1108
        }
1109
        else
1110
        {
1111
            length = width;
1112
        }
1113
1114
        if (length < mScrollbarWidth)
1115
            length = mScrollbarWidth;
1116
1117
        if (length > width)
1118
            length = width;
1119
1120
        if (maxH != 0)
1121
        {
1122
            pos = ((width - length) * mHScroll) / maxH;
1123
        }
1124
        else
1125
        {
1126
            pos = 0;
1127
        }
1128
    }
1129
1130
    return Rect(w2 + pos, mDimension.height - mScrollbarWidth,
1131
        length, mScrollbarWidth);
1132
}
1133
1134
Rect ScrollArea::getUpButtonDimension() const
1135
{
1136
    if (!mVBarVisible || !mShowButtons)
1137
        return Rect(0, 0, 0, 0);
1138
1139
    return Rect(mDimension.width - mScrollbarWidth, 0,
1140
        mScrollbarWidth, mScrollbarWidth);
1141
}
1142
1143
Rect ScrollArea::getDownButtonDimension() const
1144
{
1145
    if (!mVBarVisible || !mShowButtons)
1146
        return Rect(0, 0, 0, 0);
1147
1148
    if (mHBarVisible)
1149
    {
1150
        return Rect(mDimension.width - mScrollbarWidth,
1151
            mDimension.height - mScrollbarWidth * 2,
1152
            mScrollbarWidth,
1153
            mScrollbarWidth);
1154
    }
1155
1156
    return Rect(mDimension.width - mScrollbarWidth,
1157
        mDimension.height - mScrollbarWidth,
1158
        mScrollbarWidth,
1159
        mScrollbarWidth);
1160
}
1161
1162
Rect ScrollArea::getLeftButtonDimension() const
1163
{
1164
    if (!mHBarVisible || !mShowButtons)
1165
        return Rect(0, 0, 0, 0);
1166
1167
    return Rect(0, mDimension.height - mScrollbarWidth,
1168
        mScrollbarWidth, mScrollbarWidth);
1169
}
1170
1171
Rect ScrollArea::getRightButtonDimension() const
1172
{
1173
    if (!mHBarVisible || !mShowButtons)
1174
        return Rect(0, 0, 0, 0);
1175
1176
    if (mVBarVisible)
1177
    {
1178
        return Rect(mDimension.width - mScrollbarWidth*2,
1179
            mDimension.height - mScrollbarWidth,
1180
            mScrollbarWidth,
1181
            mScrollbarWidth);
1182
    }
1183
1184
    return Rect(mDimension.width - mScrollbarWidth,
1185
        mDimension.height - mScrollbarWidth,
1186
        mScrollbarWidth,
1187
        mScrollbarWidth);
1188
}
1189
1190
165
void ScrollArea::setContent(Widget* widget)
1191
{
1192
165
    if (widget != nullptr)
1193
    {
1194
165
        clear();
1195
165
        add(widget);
1196
165
        widget->setPosition(0, 0);
1197
    }
1198
    else
1199
    {
1200
164
        clear();
1201
    }
1202
1203
329
    checkPolicies();
1204
165
}
1205
1206
2
Widget* ScrollArea::getContent()
1207
{
1208




4528
    if (!mWidgets.empty())
1209
4136
        return *mWidgets.begin();
1210
1211
    return nullptr;
1212
}
1213
1214
56
void ScrollArea::setHorizontalScrollPolicy(const ScrollPolicy hPolicy)
1215
{
1216
56
    mHPolicy = hPolicy;
1217
56
    checkPolicies();
1218
56
}
1219
1220
26
void ScrollArea::setVerticalScrollPolicy(const ScrollPolicy vPolicy)
1221
{
1222
26
    mVPolicy = vPolicy;
1223
26
    checkPolicies();
1224
26
}
1225
1226
4
void ScrollArea::setScrollPolicy(const ScrollPolicy hPolicy,
1227
                                 const ScrollPolicy vPolicy)
1228
{
1229
4
    mHPolicy = hPolicy;
1230
4
    mVPolicy = vPolicy;
1231
4
    checkPolicies();
1232
4
}
1233
1234
3
void ScrollArea::setVerticalScrollAmount(const int vScroll)
1235
{
1236
207
    const int max = getVerticalMaxScroll();
1237
1238
207
    mVScroll = vScroll;
1239
1240







207
    if (vScroll > max)
1241
5
        mVScroll = max;
1242
1243







207
    if (vScroll < 0)
1244
        mVScroll = 0;
1245
3
}
1246
1247
void ScrollArea::setHorizontalScrollAmount(int hScroll)
1248
{
1249
204
    const int max = getHorizontalMaxScroll();
1250
1251
204
    mHScroll = hScroll;
1252
1253






204
    if (hScroll > max)
1254
        mHScroll = max;
1255






204
    else if (hScroll < 0)
1256
        mHScroll = 0;
1257
}
1258
1259
1
void ScrollArea::setScrollAmount(const int hScroll, const int vScroll)
1260
{
1261
1
    setHorizontalScrollAmount(hScroll);
1262
1
    setVerticalScrollAmount(vScroll);
1263
1
}
1264
1265
204
int ScrollArea::getHorizontalMaxScroll()
1266
{
1267
204
    checkPolicies();
1268
1269
204
    const Widget *const content = getContent();
1270
204
    if (content == nullptr)
1271
        return 0;
1272
1273
816
    const int value = content->getWidth() - getChildrenArea().width +
1274
408
        2 * content->getFrameSize();
1275
1276
204
    if (value < 0)
1277
        return 0;
1278
1279
1
    return value;
1280
}
1281
1282
219
int ScrollArea::getVerticalMaxScroll()
1283
{
1284
219
    checkPolicies();
1285
1286
219
    const Widget *const content = getContent();
1287
219
    if (content == nullptr)
1288
        return 0;
1289
1290
    int value;
1291
1292
657
    value = content->getHeight() - getChildrenArea().height +
1293
219
        2 * content->getFrameSize();
1294
1295
219
    if (value < 0)
1296
        return 0;
1297
1298
201
    return value;
1299
}
1300
1301
void ScrollArea::setScrollbarWidth(const int width)
1302
{
1303
    if (width > 0)
1304
        mScrollbarWidth = width;
1305
}
1306
1307
202
void ScrollArea::showWidgetPart(Widget *const widget, const Rect &area)
1308
{
1309
202
    const Widget *const content = getContent();
1310
202
    if (widget != content || (content == nullptr))
1311
        return;
1312
1313
202
    BasicContainer::showWidgetPart(widget, area);
1314
1315
404
    setHorizontalScrollAmount(content->getFrameSize()
1316
404
        - content->getX());
1317
404
    setVerticalScrollAmount(content->getFrameSize()
1318
202
        - content->getY());
1319
}
1320
1321
219
Rect ScrollArea::getChildrenArea()
1322
{
1323
    const Rect area = Rect(0, 0,
1324
1793
        mVBarVisible ? (getWidth() - mScrollbarWidth) : getWidth(),
1325












3912
        mHBarVisible ? (getHeight() - mScrollbarWidth) : getHeight());
1326
1327












652
    if (area.width < 0 || area.height < 0)
1328
        return Rect();
1329
1330
    return area;
1331
}
1332
1333
Widget *ScrollArea::getWidgetAt(int x, int y)
1334
{
1335
    if (getChildrenArea().isPointInRect(x, y))
1336
        return getContent();
1337
1338
    return nullptr;
1339
}
1340
1341
315
void ScrollArea::setWidth(int width)
1342
{
1343
315
    Widget::setWidth(width);
1344
315
    checkPolicies();
1345
315
}
1346
1347
317
void ScrollArea::setHeight(int height)
1348
{
1349
317
    Widget::setHeight(height);
1350
317
    checkPolicies();
1351
317
}
1352
1353
1
void ScrollArea::setDimension(const Rect& dimension)
1354
{
1355
1
    Widget::setDimension(dimension);
1356
1
    checkPolicies();
1357
1
}
1358
1359
void ScrollArea::mouseWheelMovedUp(MouseEvent& event)
1360
{
1361
    if (event.isConsumed())
1362
        return;
1363
1364
    setVerticalScrollAmount(mVScroll
1365
        - getChildrenArea().height / 8);
1366
1367
    event.consume();
1368
}
1369
1370
void ScrollArea::mouseWheelMovedDown(MouseEvent& event)
1371
{
1372
    if (event.isConsumed())
1373
        return;
1374
1375
    setVerticalScrollAmount(mVScroll
1376
        + getChildrenArea().height / 8);
1377
1378
    event.consume();
1379
}
1380
1381
1472
void ScrollArea::checkPolicies()
1382
{
1383
2944
    const int w = getWidth();
1384
2944
    const int h = getHeight();
1385
1386
1472
    mHBarVisible = false;
1387
1472
    mVBarVisible = false;
1388
1389
1472
    const Widget *const content = getContent();
1390
1472
    if (content == nullptr)
1391
    {
1392
164
        mHBarVisible = (mHPolicy == SHOW_ALWAYS);
1393
164
        mVBarVisible = (mVPolicy == SHOW_ALWAYS);
1394
164
        return;
1395
    }
1396
1397
1308
    if (mHPolicy == SHOW_AUTO &&
1398
        mVPolicy == SHOW_AUTO)
1399
    {
1400
1140
        if (content->getWidth() <= w
1401
            && content->getHeight() <= h)
1402
        {
1403
            mHBarVisible = false;
1404
            mVBarVisible = false;
1405
        }
1406
1407
1140
        if (content->getWidth() > w)
1408
        {
1409
322
            mHBarVisible = true;
1410
        }
1411
1412
2280
        if ((content->getHeight() > h)
1413

1142
            || (mHBarVisible && content->getHeight()
1414
2
            > h - mScrollbarWidth))
1415
        {
1416
964
            mVBarVisible = true;
1417
        }
1418
1419

1140
        if (mVBarVisible && content->getWidth() > w - mScrollbarWidth)
1420
962
            mHBarVisible = true;
1421
1422
        return;
1423
    }
1424
1425
168
    switch (mHPolicy)
1426
    {
1427
        case SHOW_NEVER:
1428
            mHBarVisible = false;
1429
            break;
1430
1431
        case SHOW_ALWAYS:
1432
            mHBarVisible = true;
1433
            break;
1434
1435
        case SHOW_AUTO:
1436
8
            if (mVPolicy == SHOW_NEVER)
1437
            {
1438
2
                mHBarVisible = (content->getWidth() > w);
1439
            }
1440
            else  // (mVPolicy == SHOW_ALWAYS)
1441
            {
1442
12
                mHBarVisible = (content->getWidth()
1443
6
                    > w - mScrollbarWidth);
1444
            }
1445
            break;
1446
1447
        default:
1448
            break;
1449
    }
1450
1451
168
    switch (mVPolicy)
1452
    {
1453
        case SHOW_NEVER:
1454
            mVBarVisible = false;
1455
            break;
1456
1457
        case SHOW_ALWAYS:
1458
17
            mVBarVisible = true;
1459
17
            break;
1460
1461
        case SHOW_AUTO:
1462
144
            if (mHPolicy == SHOW_NEVER)
1463
            {
1464
144
                mVBarVisible = (content->getHeight() > h);
1465
            }
1466
            else  // (mHPolicy == SHOW_ALWAYS)
1467
            {
1468
                mVBarVisible = (content->getHeight()
1469
                    > h - mScrollbarWidth);
1470
            }
1471
            break;
1472
        default:
1473
            break;
1474
    }
1475
}
1476
1477
bool ScrollArea::isSelectable() const noexcept2
1478
{
1479
    if (mVBarVisible || mHBarVisible)
1480
        return true;
1481
    return Widget::isSelectable();
1482

3
}