GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/staticbrowserbox.cpp Lines: 210 372 56.5 %
Date: 2021-03-17 Branches: 135 343 39.4 %

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
 *  Copyright (C) 2019-2021  Andrei Karas
7
 *  Copyright (C) 2009  Aethyra Development Team
8
 *
9
 *  This file is part of The ManaPlus Client.
10
 *
11
 *  This program is free software; you can redistribute it and/or modify
12
 *  it under the terms of the GNU General Public License as published by
13
 *  the Free Software Foundation; either version 2 of the License, or
14
 *  any later version.
15
 *
16
 *  This program is distributed in the hope that it will be useful,
17
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 *  GNU General Public License for more details.
20
 *
21
 *  You should have received a copy of the GNU General Public License
22
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
23
 */
24
25
#include "gui/widgets/staticbrowserbox.h"
26
27
#include "enums/gui/linkhighlightmode.h"
28
29
#include "gui/gui.h"
30
#include "gui/mouseoverlink.h"
31
#include "gui/skin.h"
32
33
#include "gui/fonts/font.h"
34
35
#include "gui/widgets/browserbox.inc"
36
#include "gui/widgets/linkhandler.h"
37
38
#include "render/graphics.h"
39
40
#include "resources/imageset.h"
41
42
#include "resources/image/image.h"
43
44
#include "resources/loaders/imageloader.h"
45
#include "resources/loaders/imagesetloader.h"
46
47
#include "utils/browserboxtools.h"
48
#include "utils/checkutils.h"
49
#include "utils/foreach.h"
50
#include "utils/stdmove.h"
51
#include "utils/stringutils.h"
52
#include "utils/translation/podict.h"
53
54
#include <algorithm>
55
56
#include "debug.h"
57
58
ImageSet *StaticBrowserBox::mEmotes = nullptr;
59
int StaticBrowserBox::mInstances = 0;
60
61
12
StaticBrowserBox::StaticBrowserBox(const Widget2 *const widget,
62
                                   const Opaque opaque,
63
12
                                   const std::string &skin) :
64
    Widget(widget),
65
    MouseListener(),
66
    mTextRows(),
67
    mTextRowLinksCount(),
68
    mLineParts(),
69
    mLinks(),
70
    mLinkHandler(nullptr),
71
    mSkin(nullptr),
72
    mHighlightMode(0),
73
    mSelectedLink(-1),
74
    mHeight(0),
75
    mWidth(0),
76
    mYStart(0),
77
    mPadding(0),
78
    mNewLinePadding(15U),
79
    mItemPadding(0),
80
24
    mHighlightColor(getThemeColor(ThemeColorId::HIGHLIGHT, 255U)),
81
24
    mHyperLinkColor(getThemeColor(ThemeColorId::HYPERLINK, 255U)),
82
    mOpaque(opaque),
83
    mUseLinksAndUserColors(true),
84
    mUseEmotes(true),
85
    mProcessVars(false),
86
    mEnableImages(false),
87
    mEnableKeys(false),
88
    mEnableTabs(false),
89
96
    mSeparator(false)
90
{
91
12
    mAllowLogic = false;
92
93
12
    setFocusable(true);
94
12
    addMouseListener(this);
95
96
24
    mBackgroundColor = getThemeColor(ThemeColorId::BACKGROUND, 255U);
97
98
12
    if (theme != nullptr)
99
    {
100

48
        mSkin = theme->load(skin,
101
            "browserbox.xml",
102
            true,
103
12
            Theme::getThemePath());
104
    }
105
12
    if (mInstances == 0)
106
    {
107

40
        mEmotes = Loader::getImageSet(
108
            "graphics/sprites/chatemotes.png", 17, 18);
109
    }
110
12
    mInstances ++;
111
112
12
    if (mSkin != nullptr)
113
    {
114
24
        mPadding = mSkin->getPadding();
115
12
        mNewLinePadding = CAST_U32(
116

48
            mSkin->getOption("newLinePadding", 15));
117

48
        mItemPadding = mSkin->getOption("itemPadding");
118

48
        if (mSkin->getOption("highlightBackground") != 0)
119
12
            mHighlightMode |= LinkHighlightMode::BACKGROUND;
120

48
        if (mSkin->getOption("highlightUnderline") != 0)
121
9
            mHighlightMode |= LinkHighlightMode::UNDERLINE;
122
    }
123
124
36
    readColor(BLACK);
125
36
    readColor(RED);
126
36
    readColor(GREEN);
127
36
    readColor(BLUE);
128
36
    readColor(ORANGE);
129
36
    readColor(YELLOW);
130
36
    readColor(PINK);
131
36
    readColor(PURPLE);
132
36
    readColor(GRAY);
133
36
    readColor(BROWN);
134
135
24
    mForegroundColor = getThemeColor(ThemeColorId::BROWSERBOX, 255U);
136
24
    mForegroundColor2 = getThemeColor(ThemeColorId::BROWSERBOX_OUTLINE, 255U);
137
12
}
138
139
72
StaticBrowserBox::~StaticBrowserBox()
140
{
141
12
    if (gui != nullptr)
142
12
        gui->removeDragged(this);
143
144
12
    if (theme != nullptr)
145
    {
146
12
        theme->unload(mSkin);
147
12
        mSkin = nullptr;
148
    }
149
150
12
    mInstances --;
151
12
    if (mInstances == 0)
152
    {
153
10
        if (mEmotes != nullptr)
154
        {
155
10
            mEmotes->decRef();
156
10
            mEmotes = nullptr;
157
        }
158
    }
159
24
}
160
161
10
void StaticBrowserBox::setLinkHandler(LinkHandler* linkHandler)
162
{
163
10
    mLinkHandler = linkHandler;
164
10
}
165
166
void StaticBrowserBox::addSeparator(const std::string &row)
167
{
168
    if (mSeparator)
169
        return;
170
    addRow(row, false);
171
    mSeparator = true;
172
}
173
174
50
void StaticBrowserBox::addRow(const std::string &row,
175
                              const bool atTop)
176
{
177
100
    std::string tmp = row;
178
100
    std::string newRow;
179
    size_t idx1;
180
50
    const Font *const font = getFont();
181
50
    int linksCount = 0;
182
183
100
    if (getWidth() < 0)
184
        return;
185
186
50
    mSeparator = false;
187
188
50
    if (mProcessVars)
189
    {
190
2
        BrowserBoxTools::replaceVars(tmp);
191
    }
192
193
    // Use links and user defined colors
194
50
    if (mUseLinksAndUserColors)
195
    {
196
100
        BrowserLink bLink;
197
198
        // Check for links in format "@@link|[email protected]@"
199
100
        const uint32_t sz = CAST_U32(mTextRows.size());
200
201
50
        if (mEnableKeys)
202
        {
203
            BrowserBoxTools::replaceKeys(tmp);
204
        }
205
206
        idx1 = tmp.find("@@");
207
92
        while (idx1 != std::string::npos)
208
        {
209
31
            const size_t idx2 = tmp.find('|', idx1);
210
31
            const size_t idx3 = tmp.find("@@", idx2);
211
212
31
            if (idx2 == std::string::npos || idx3 == std::string::npos)
213
                break;
214
42
            bLink.link = tmp.substr(idx1 + 2, idx2 - (idx1 + 2));
215
42
            bLink.caption = tmp.substr(idx2 + 1, idx3 - (idx2 + 1));
216
21
            bLink.y1 = CAST_S32(sz) * font->getHeight();
217
21
            bLink.y2 = bLink.y1 + font->getHeight();
218
21
            if (bLink.caption.empty())
219
            {
220
2
                bLink.caption = BrowserBoxTools::replaceLinkCommands(
221
1
                    bLink.link);
222
1
                if (translator != nullptr)
223
                    bLink.caption = translator->getStr(bLink.caption);
224
            }
225
226
63
            newRow.append(tmp.substr(0, idx1));
227
228
42
            std::string tmp2 = newRow;
229
            idx1 = tmp2.find("##");
230
24
            while (idx1 != std::string::npos)
231
            {
232
3
                tmp2.erase(idx1, 3);
233
                idx1 = tmp2.find("##");
234
            }
235
21
            bLink.x1 = font->getWidth(tmp2) - 1;
236
21
            bLink.x2 = bLink.x1 + font->getWidth(bLink.caption) + 1;
237
238
21
            if (atTop)
239
                mLinks.insert(mLinks.begin(), bLink);
240
            else
241
21
                mLinks.push_back(bLink);
242
21
            linksCount ++;
243
244
42
            newRow.append("##<").append(bLink.caption);
245
246
21
            tmp.erase(0, idx3 + 2);
247
21
            if (!tmp.empty())
248
3
                newRow.append("##>");
249
250
21
            idx1 = tmp.find("@@");
251
        }
252
253
50
        newRow.append(tmp);
254
    }
255
    // Don't use links and user defined colors
256
    else
257
    {
258
        newRow = row;
259
    }
260
261
50
    if (mEnableTabs)
262
    {
263
2
        BrowserBoxTools::replaceTabs(newRow);
264
    }
265
266
50
    if (atTop)
267
    {
268
        mTextRows.push_front(newRow);
269
        mTextRowLinksCount.push_front(linksCount);
270
    }
271
    else
272
    {
273
50
        mTextRows.push_back(newRow);
274
50
        mTextRowLinksCount.push_back(linksCount);
275
    }
276
277
150
    std::string plain = STD_MOVE(newRow);
278
    // workaround if used only one string started from bold
279
    // width for this string can be calculated wrong
280
    // this workaround fix width if string start from bold sign
281
50
    const bool startBold = (plain.find("##B") == 0);
282
    for (idx1 = plain.find("##");
283
105
         idx1 != std::string::npos;
284
         idx1 = plain.find("##"))
285
    {
286
55
        plain.erase(idx1, 3);
287
    }
288
289
    // Adjust the StaticBrowserBox size. This need only for implementing "---"
290

100
    const int w = startBold ?
291
100
        boldFont->getWidth(plain) : font->getWidth(plain) + 2 * mPadding;
292
100
    if (w > getWidth())
293
9
        setWidth(w);
294
}
295
296
1
void StaticBrowserBox::addRow(const std::string &cmd,
297
                              const char *const text)
298
{
299

6
    addRow(strprintf("@@%s|%[email protected]@", encodeLinkText(cmd).c_str(),
300
5
        encodeLinkText(text).c_str()),
301
1
        false);
302
1
}
303
304
void StaticBrowserBox::addImage(const std::string &path)
305
{
306
    if (!mEnableImages)
307
        return;
308
309
    mTextRows.push_back("~~~" + path);
310
    mTextRowLinksCount.push_back(0);
311
}
312
313
1
void StaticBrowserBox::clearRows()
314
{
315
2
    mTextRows.clear();
316
2
    mTextRowLinksCount.clear();
317
2
    mLinks.clear();
318
1
    setWidth(0);
319
1
    setHeight(0);
320
1
    mSelectedLink = -1;
321
1
}
322
323
void StaticBrowserBox::mousePressed(MouseEvent &event)
324
{
325
    if (mLinkHandler == nullptr)
326
        return;
327
328
    const LinkIterator i = std::find_if(mLinks.begin(), mLinks.end(),
329
        MouseOverLink(event.getX(), event.getY()));
330
331
    if (i != mLinks.end())
332
    {
333
        mLinkHandler->handleLink(i->link, &event);
334
        event.consume();
335
    }
336
}
337
338
void StaticBrowserBox::mouseMoved(MouseEvent &event)
339
{
340
    const LinkIterator i = std::find_if(mLinks.begin(), mLinks.end(),
341
        MouseOverLink(event.getX(), event.getY()));
342
343
    mSelectedLink = (i != mLinks.end())
344
        ? CAST_S32(i - mLinks.begin()) : -1;
345
}
346
347
void StaticBrowserBox::mouseExited(MouseEvent &event A_UNUSED)
348
{
349
    mSelectedLink = -1;
350
}
351
352
2
void StaticBrowserBox::draw(Graphics *const graphics)
353
{
354
    BLOCK_START("StaticBrowserBox::draw")
355
2
    const ClipRect &cr = graphics->getTopClip();
356
2
    mYStart = cr.y - cr.yOffset;
357
2
    const int yEnd = mYStart + cr.height;
358
2
    if (mYStart < 0)
359
        mYStart = 0;
360
361
2
    if (mDimension.width != mWidth)
362
    {
363
        updateHeight();
364
        reportAlways("browserbox resize in draw: %d, %d",
365
            mDimension.width,
366
            mWidth)
367
    }
368
369
2
    if (mOpaque == Opaque_true)
370
    {
371
        graphics->setColor(mBackgroundColor);
372
        graphics->fillRectangle(Rect(0, 0,
373
            mDimension.width, mDimension.height));
374
    }
375
376

2
    if (mSelectedLink >= 0 &&
377
        mSelectedLink < CAST_S32(mLinks.size()))
378
    {
379
        if ((mHighlightMode & LinkHighlightMode::BACKGROUND) != 0U)
380
        {
381
            BrowserLink &link = mLinks[CAST_SIZE(mSelectedLink)];
382
            graphics->setColor(mHighlightColor);
383
            graphics->fillRectangle(Rect(
384
                link.x1,
385
                link.y1,
386
                link.x2 - link.x1,
387
                link.y2 - link.y1));
388
        }
389
390
        if ((mHighlightMode & LinkHighlightMode::UNDERLINE) != 0U)
391
        {
392
            BrowserLink &link = mLinks[CAST_SIZE(mSelectedLink)];
393
            graphics->setColor(mHyperLinkColor);
394
            graphics->drawLine(
395
                link.x1,
396
                link.y2,
397
                link.x2,
398
                link.y2);
399
        }
400
    }
401
402
2
    Font *const font = getFont();
403
404
12
    FOR_EACH (LinePartCIter, i, mLineParts)
405
    {
406
1
        const LinePart &part = *i;
407
1
        if (part.mY + 50 < mYStart)
408
            continue;
409
1
        if (part.mY > yEnd)
410
            break;
411
        if (part.mType == 0U)
412
        {
413
            if (part.mBold)
414
            {
415
                boldFont->drawString(graphics,
416
                    part.mColor,
417
                    part.mColor2,
418
                    part.mText,
419
                    part.mX, part.mY);
420
            }
421
            else
422
            {
423
                font->drawString(graphics,
424
                    part.mColor,
425
                    part.mColor2,
426
                    part.mText,
427
                    part.mX, part.mY);
428
            }
429
        }
430
        else if (part.mImage != nullptr)
431
        {
432
            graphics->drawImage(part.mImage, part.mX, part.mY);
433
        }
434
    }
435
436
    BLOCK_END("StaticBrowserBox::draw")
437
2
}
438
439
void StaticBrowserBox::safeDraw(Graphics *const graphics)
440
{
441
    StaticBrowserBox::draw(graphics);
442
}
443
444
2
void StaticBrowserBox::updateHeight()
445
{
446
2
    unsigned int y = CAST_U32(mPadding);
447
2
    int moreHeight = 0;
448
2
    int link = 0;
449
2
    bool bold = false;
450
2
    const unsigned int wWidth = CAST_U32(mDimension.width - mPadding);
451
2
    const Font *const font = getFont();
452
2
    const int fontHeight = font->getHeight() + 2 * mItemPadding;
453
8
    const int fontWidthMinus = font->getWidth("-");
454
455
2
    Color selColor[2] = {mForegroundColor, mForegroundColor2};
456
2
    const Color textColor[2] = {mForegroundColor, mForegroundColor2};
457
4
    mLineParts.clear();
458
2
    uint32_t dataWidth = 0;
459
460
2
    if (mSeparator)
461
    {
462
        mSeparator = false;
463
        mTextRows.pop_back();
464
    }
465
466
10
    FOR_EACH (TextRowCIter, i, mTextRows)
467
    {
468
4
        unsigned int x = CAST_U32(mPadding);
469
12
        const std::string row = *(i);
470
4
        int objects = 0;
471
472
        // Check for separator lines
473
4
        if (row.find("---", 0) == 0)
474
        {
475
            const int dashWidth = fontWidthMinus;
476
            for (x = CAST_U32(mPadding); x < wWidth; x ++)
477
            {
478
                mLineParts.push_back(LinePart(CAST_S32(x),
479
                    CAST_S32(y) + mItemPadding,
480
                    selColor[0], selColor[1], "-", false));
481
                x += CAST_U32(CAST_S32(
482
                    dashWidth) - 2);
483
            }
484
485
            y += CAST_U32(fontHeight);
486
            continue;
487
        }
488

4
        else if (mEnableImages && row.find("~~~", 0) == 0)
489
        {
490
            std::string str = row.substr(3);
491
            const size_t sz = str.size();
492
            if (sz > 2 && str.substr(sz - 1) == "~")
493
                str = str.substr(0, sz - 1);
494
            Image *const img = Loader::getImage(str);
495
            if (img != nullptr)
496
            {
497
                img->incRef();
498
                mLineParts.push_back(LinePart(CAST_S32(x),
499
                    CAST_S32(y) + mItemPadding,
500
                    selColor[0], selColor[1], img));
501
                y += CAST_U32(img->getHeight() + 2);
502
                moreHeight += img->getHeight();
503
                if (img->getWidth() + mPadding + 2 > CAST_S32(dataWidth))
504
                    dataWidth = img->getWidth() + 2 + mPadding;
505
            }
506
            continue;
507
        }
508
509
        Color prevColor[2];
510
        prevColor[0] = selColor[0];
511
        prevColor[1] = selColor[1];
512
        bold = false;
513
514
3
        for (size_t start = 0, end = std::string::npos;
515
7
             start != std::string::npos;
516
3
             start = end, end = std::string::npos)
517
        {
518
4
            size_t idx1 = end;
519
4
            size_t idx2 = end;
520
521
            // "Tokenize" the string at control sequences
522
4
            if (mUseLinksAndUserColors)
523
4
                idx1 = row.find("##", start + 1);
524

4
            if (start == 0 || mUseLinksAndUserColors)
525
            {
526
                // Check for color change in format "##x", x = [L,P,0..9]
527

4
                if (row.find("##", start) == start && row.size() > start + 2)
528
                {
529
4
                    const signed char c = row.at(start + 2);
530
531
2
                    bool valid(false);
532
                    const Color col[2] =
533
                    {
534
4
                        getThemeCharColor(c, valid),
535
                        getThemeCharColor(CAST_S8(
536
4
                            c | 0x80), valid)
537
4
                    };
538
539
2
                    if (c == '>')
540
                    {
541
                        selColor[0] = prevColor[0];
542
                        selColor[1] = prevColor[1];
543
                    }
544
2
                    else if (c == '<')
545
                    {
546
                        prevColor[0] = selColor[0];
547
                        prevColor[1] = selColor[1];
548
                        selColor[0] = col[0];
549
                        selColor[1] = col[1];
550
                    }
551
1
                    else if (c == 'B')
552
                    {
553
                        bold = true;
554
                    }
555
                    else if (c == 'b')
556
                    {
557
                        bold = false;
558
                    }
559
                    else if (valid)
560
                    {
561
                        selColor[0] = col[0];
562
                        selColor[1] = col[1];
563
                    }
564
                    else
565
                    {
566
                        switch (c)
567
                        {
568
                            case '0':
569
                                selColor[0] = mColors[0][ColorName::BLACK];
570
                                selColor[1] = mColors[1][ColorName::BLACK];
571
                                break;
572
                            case '1':
573
                                selColor[0] = mColors[0][ColorName::RED];
574
                                selColor[1] = mColors[1][ColorName::RED];
575
                                break;
576
                            case '2':
577
                                selColor[0] = mColors[0][ColorName::GREEN];
578
                                selColor[1] = mColors[1][ColorName::GREEN];
579
                                break;
580
                            case '3':
581
                                selColor[0] = mColors[0][ColorName::BLUE];
582
                                selColor[1] = mColors[1][ColorName::BLUE];
583
                                break;
584
                            case '4':
585
                                selColor[0] = mColors[0][ColorName::ORANGE];
586
                                selColor[1] = mColors[1][ColorName::ORANGE];
587
                                break;
588
                            case '5':
589
                                selColor[0] = mColors[0][ColorName::YELLOW];
590
                                selColor[1] = mColors[1][ColorName::YELLOW];
591
                                break;
592
                            case '6':
593
                                selColor[0] = mColors[0][ColorName::PINK];
594
                                selColor[1] = mColors[1][ColorName::PINK];
595
                                break;
596
                            case '7':
597
                                selColor[0] = mColors[0][ColorName::PURPLE];
598
                                selColor[1] = mColors[1][ColorName::PURPLE];
599
                                break;
600
                            case '8':
601
                                selColor[0] = mColors[0][ColorName::GRAY];
602
                                selColor[1] = mColors[1][ColorName::GRAY];
603
                                break;
604
                            case '9':
605
                                selColor[0] = mColors[0][ColorName::BROWN];
606
                                selColor[1] = mColors[1][ColorName::BROWN];
607
                                break;
608
                            default:
609
                                selColor[0] = textColor[0];
610
                                selColor[1] = textColor[1];
611
                                break;
612
                        }
613
                    }
614
615

3
                    if (c == '<' && link < CAST_S32(mLinks.size()))
616
                    {
617
                        int size;
618
1
                        if (bold)
619
                        {
620
                            size = boldFont->getWidth(
621
                                mLinks[CAST_SIZE(link)].caption) + 1;
622
                        }
623
                        else
624
                        {
625
1
                            size = font->getWidth(
626
2
                                mLinks[CAST_SIZE(link)].caption) + 1;
627
                        }
628
629
                        BrowserLink &linkRef = mLinks[CAST_SIZE(
630
2
                            link)];
631
1
                        linkRef.x1 = CAST_S32(x);
632
1
                        linkRef.y1 = CAST_S32(y);
633
1
                        linkRef.x2 = linkRef.x1 + size;
634
1
                        linkRef.y2 = CAST_S32(y) + fontHeight - 1;
635
1
                        link++;
636
                    }
637
638
2
                    start += 3;
639
2
                    if (start == row.size())
640
                        break;
641
                }
642
            }
643
4
            if (mUseEmotes)
644
4
                idx2 = row.find("%%", start + 1);
645
4
            if (idx1 < idx2)
646
                end = idx1;
647
            else
648
4
                end = idx2;
649
4
            if (mUseEmotes)
650
            {
651
                // check for emote icons
652



10
                if (row.size() > start + 2 && row.substr(start, 2) == "%%")
653
                {
654
                    if (objects < 5)
655
                    {
656
                        const int cid = row.at(start + 2) - '0';
657
                        if (cid >= 0)
658
                        {
659
                            if (mEmotes != nullptr)
660
                            {
661
                                const size_t sz = mEmotes->size();
662
                                if (CAST_SIZE(cid) < sz)
663
                                {
664
                                    Image *const img = mEmotes->get(
665
                                        CAST_SIZE(cid));
666
                                    if (img != nullptr)
667
                                    {
668
                                        mLineParts.push_back(LinePart(
669
                                            CAST_S32(x),
670
                                            CAST_S32(y) + mItemPadding,
671
                                            selColor[0], selColor[1], img));
672
                                        x += 18;
673
                                    }
674
                                }
675
                            }
676
                        }
677
                        objects ++;
678
                    }
679
680
                    start += 3;
681
                    if (start == row.size())
682
                    {
683
                        if (x > dataWidth)
684
                            dataWidth = x;
685
                        break;
686
                    }
687
                }
688
            }
689
4
            const size_t len = (end == std::string::npos) ? end : end - start;
690
691
4
            if (start >= row.length())
692
                break;
693
694
6
            std::string part = row.substr(start, len);
695
696
24
            mLineParts.push_back(LinePart(CAST_S32(x),
697
3
                CAST_S32(y) + mItemPadding,
698
3
                selColor[0], selColor[1], part.c_str(), bold));
699
700
3
            int width = 0;
701
3
            if (bold)
702
1
                width = boldFont->getWidth(part);
703
            else
704
2
                width = font->getWidth(part);
705
706
3
            x += CAST_U32(width);
707
3
            if (x > dataWidth)
708
2
                dataWidth = x;
709
        }
710
4
        y += CAST_U32(fontHeight);
711
    }
712
2
    mWidth = dataWidth + mPadding;
713
6
    mHeight = CAST_S32(mTextRows.size())
714
2
        * fontHeight + moreHeight + 2 * mPadding;
715
    setSize(mWidth,
716
2
        mHeight);
717
2
}
718
719
std::string StaticBrowserBox::getTextAtPos(const int x,
720
                                           const int y) const
721
{
722
    int textX = 0;
723
    int textY = 0;
724
725
    getAbsolutePosition(textX, textY);
726
    if (x < textX || y < textY)
727
        return std::string();
728
729
    textY = y - textY;
730
    std::string str;
731
    int lastY = 0;
732
733
    FOR_EACH (LinePartCIter, i, mLineParts)
734
    {
735
        const LinePart &part = *i;
736
        if (part.mY + 50 < mYStart)
737
            continue;
738
        if (part.mY > textY)
739
            break;
740
741
        if (part.mY > lastY)
742
        {
743
            str = part.mText;
744
            lastY = part.mY;
745
        }
746
        else
747
        {
748
            str.append(part.mText);
749
        }
750
    }
751
752
    return str;
753
}
754
755
1
void StaticBrowserBox::setForegroundColorAll(const Color &color1,
756
                                             const Color &color2)
757
{
758
1
    mForegroundColor = color1;
759
1
    mForegroundColor2 = color2;
760
1
}
761
762
void StaticBrowserBox::moveSelectionUp()
763
{
764
    if (mSelectedLink <= 0)
765
        mSelectedLink = CAST_S32(mLinks.size()) - 1;
766
    else
767
        mSelectedLink --;
768
}
769
770
void StaticBrowserBox::moveSelectionDown()
771
{
772
    mSelectedLink ++;
773
    if (mSelectedLink >= static_cast<signed int>(mLinks.size()))
774
        mSelectedLink = 0;
775
}
776
777
void StaticBrowserBox::selectSelection()
778
{
779
    if ((mLinkHandler == nullptr) ||
780
        mSelectedLink < 0 ||
781
        mSelectedLink >= static_cast<signed int>(mLinks.size()))
782
    {
783
        return;
784
    }
785
786
    mLinkHandler->handleLink(mLinks[CAST_SIZE(mSelectedLink)].link,
787
        nullptr);
788
}