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

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

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

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

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

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

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

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

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

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

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

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

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

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



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