GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/scrollarea.cpp Lines: 299 685 43.6 %
Date: 2018-09-20 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-2018  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
        const int bs = mFrameSize * 2;
461
16
        const int w = mDimension.width + bs;
462
16
        const int h = mDimension.height + bs;
463
464
16
        updateCalcFlag(graphics);
465
466
16
        if (mRedraw)
467
        {
468
16
            mVertexes2->clear();
469
16
            graphics->calcWindow(mVertexes2,
470
                0, 0,
471
                w, h,
472
32
                background);
473
16
            graphics->finalize(mVertexes2);
474
        }
475
16
        graphics->drawTileCollection(mVertexes2);
476
    }
477
    BLOCK_END("ScrollArea::drawFrame")
478
16
}
479
480
void ScrollArea::safeDrawFrame(Graphics *const graphics)
481
{
482
    BLOCK_START("ScrollArea::drawFrame")
483
    if (mOpaque == Opaque_true)
484
    {
485
        const int bs = mFrameSize * 2;
486
        const int w = mDimension.width + bs;
487
        const int h = mDimension.height + bs;
488
489
        updateCalcFlag(graphics);
490
        graphics->drawImageRect(0, 0,
491
            w, h,
492
            background);
493
    }
494
    BLOCK_END("ScrollArea::drawFrame")
495
}
496
497
void ScrollArea::setOpaque(Opaque opaque)
498
{
499
    mOpaque = opaque;
500

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

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

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




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







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







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






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






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












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












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

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

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

3
}