GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
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|Caption@@" |
||
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|%s@@", 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 |
} |
Generated by: GCOVR (Version 3.3) |