ManaPlus
browserbox.cpp
Go to the documentation of this file.
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/browserbox.h"
26 
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"
37 
38 #include "render/graphics.h"
39 
40 #include "resources/imageset.h"
41 
42 #include "resources/image/image.h"
43 
46 
47 #include "utils/browserboxtools.h"
48 #include "utils/checkutils.h"
49 #include "utils/foreach.h"
50 #include "utils/stringutils.h"
51 #include "utils/timer.h"
53 
54 #include <algorithm>
55 
56 #include "debug.h"
57 
58 ImageSet *BrowserBox::mEmotes = nullptr;
60 
61 BrowserBox::BrowserBox(const Widget2 *const widget,
62  const Opaque opaque,
63  const std::string &skin) :
64  Widget(widget),
65  MouseListener(),
67  mTextRows(),
68  mTextRowLinksCount(),
69  mLineParts(),
70  mLinks(),
71  mLinkHandler(nullptr),
72  mSkin(nullptr),
73  mHighlightMode(0),
74  mSelectedLink(-1),
75  mMaxRows(0),
76  mHeight(0),
77  mWidth(0),
78  mYStart(0),
79  mUpdateTime(-1),
80  mPadding(0),
81  mNewLinePadding(15U),
82  mItemPadding(0),
83  mDataWidth(0),
84  mHighlightColor(getThemeColor(ThemeColorId::HIGHLIGHT, 255U)),
85  mHyperLinkColor(getThemeColor(ThemeColorId::HYPERLINK, 255U)),
86  mOpaque(opaque),
87  mUseLinksAndUserColors(true),
88  mUseEmotes(true),
89  mAlwaysUpdate(true),
90  mProcessVars(false),
91  mEnableImages(false),
92  mEnableKeys(false),
93  mEnableTabs(false)
94 {
95  mAllowLogic = false;
96 
97  setFocusable(true);
98  addMouseListener(this);
99  addWidgetListener(this);
100 
102 
103  if (theme != nullptr)
104  {
105  mSkin = theme->load(skin,
106  "browserbox.xml",
107  true,
109  }
110  if (mInstances == 0)
111  {
113  "graphics/sprites/chatemotes.png", 17, 18);
114  }
115  mInstances ++;
116 
117  if (mSkin != nullptr)
118  {
121  mSkin->getOption("newLinePadding", 15));
122  mItemPadding = mSkin->getOption("itemPadding");
123  if (mSkin->getOption("highlightBackground") != 0)
125  if (mSkin->getOption("highlightUnderline") != 0)
127  }
128 
129  readColor(BLACK);
130  readColor(RED);
131  readColor(GREEN);
132  readColor(BLUE);
133  readColor(ORANGE);
134  readColor(YELLOW);
135  readColor(PINK);
136  readColor(PURPLE);
137  readColor(GRAY);
138  readColor(BROWN);
139 
140  mForegroundColor = getThemeColor(ThemeColorId::BROWSERBOX, 255U);
141  mForegroundColor2 = getThemeColor(ThemeColorId::BROWSERBOX_OUTLINE, 255U);
142 }
143 
145 {
146  if (gui != nullptr)
147  gui->removeDragged(this);
148 
149  if (theme != nullptr)
150  {
151  theme->unload(mSkin);
152  mSkin = nullptr;
153  }
154 
155  mInstances --;
156  if (mInstances == 0)
157  {
158  if (mEmotes != nullptr)
159  {
160  mEmotes->decRef();
161  mEmotes = nullptr;
162  }
163  }
164 }
165 
167 {
168  mLinkHandler = linkHandler;
169 }
170 
171 void BrowserBox::addRow(const std::string &row, const bool atTop)
172 {
173  std::string tmp = row;
174  std::string newRow;
175  const Font *const font = getFont();
176  int linksCount = 0;
177 
178  if (getWidth() < 0)
179  return;
180 
181  if (mProcessVars)
182  {
184  }
185 
186  // Use links and user defined colors
188  {
189  BrowserLink bLink;
190 
191  // Check for links in format "@@link|[email protected]@"
192  const uint32_t sz = CAST_U32(mTextRows.size());
193 
194  if (mEnableKeys)
195  {
197  }
198 
199  size_t idx1 = tmp.find("@@");
200  while (idx1 != std::string::npos)
201  {
202  const size_t idx2 = tmp.find('|', idx1);
203  const size_t idx3 = tmp.find("@@", idx2);
204 
205  if (idx2 == std::string::npos || idx3 == std::string::npos)
206  break;
207  bLink.link = tmp.substr(idx1 + 2, idx2 - (idx1 + 2));
208  bLink.caption = tmp.substr(idx2 + 1, idx3 - (idx2 + 1));
209  bLink.y1 = CAST_S32(sz) * font->getHeight();
210  bLink.y2 = bLink.y1 + font->getHeight();
211  if (bLink.caption.empty())
212  {
214  bLink.link);
215  if (translator != nullptr)
216  bLink.caption = translator->getStr(bLink.caption);
217  }
218 
219  newRow.append(tmp.substr(0, idx1));
220 
221  std::string tmp2 = newRow;
222  idx1 = tmp2.find("##");
223  while (idx1 != std::string::npos)
224  {
225  tmp2.erase(idx1, 3);
226  idx1 = tmp2.find("##");
227  }
228  bLink.x1 = font->getWidth(tmp2) - 1;
229  bLink.x2 = bLink.x1 + font->getWidth(bLink.caption) + 1;
230 
231  if (atTop)
232  mLinks.insert(mLinks.begin(), bLink);
233  else
234  mLinks.push_back(bLink);
235  linksCount ++;
236 
237  newRow.append("##<").append(bLink.caption);
238 
239  tmp.erase(0, idx3 + 2);
240  if (!tmp.empty())
241  newRow.append("##>");
242 
243  idx1 = tmp.find("@@");
244  }
245 
246  newRow.append(tmp);
247  }
248  // Don't use links and user defined colors
249  else
250  {
251  newRow = row;
252  }
253 
254  if (mEnableTabs)
255  {
257  }
258 
259  if (atTop)
260  {
261  mTextRows.push_front(newRow);
262  mTextRowLinksCount.push_front(linksCount);
263  }
264  else
265  {
266  mTextRows.push_back(newRow);
267  mTextRowLinksCount.push_back(linksCount);
268  }
269 
270  // discard older rows when a row limit has been set
271  if (mMaxRows > 0 && !mTextRows.empty())
272  {
273  while (mTextRows.size() > CAST_SIZE(mMaxRows))
274  {
275  mTextRows.pop_front();
276  int cnt = mTextRowLinksCount.front();
277  mTextRowLinksCount.pop_front();
278 
279  while ((cnt != 0) && !mLinks.empty())
280  {
281  mLinks.erase(mLinks.begin());
282  cnt --;
283  }
284  }
285  }
286 
287  const int fontHeight = font->getHeight();
288  unsigned int y = 0;
289  unsigned int nextChar;
290  const char *const hyphen = "~";
291  const unsigned int hyphenWidth = CAST_U32(
292  font->getWidth(hyphen));
293  unsigned int x = 0;
294 
296  {
297  std::string tempRow = *i;
298  for (uint32_t j = 0, sz = CAST_U32(tempRow.size());
299  j < sz;
300  j++)
301  {
302  const std::string character = tempRow.substr(j, 1);
303  x += CAST_U32(font->getWidth(character));
304  nextChar = j + 1;
305 
306  // Wraping between words (at blank spaces)
307  if (nextChar < sz && tempRow.at(nextChar) == ' ')
308  {
309  int nextSpacePos = CAST_U32(
310  tempRow.find(' ', (nextChar + 1)));
311  if (nextSpacePos <= 0)
312  nextSpacePos = CAST_U32(sz) - 1U;
313 
314  const unsigned int nextWordWidth =
315  CAST_U32(font->getWidth(
316  tempRow.substr(nextChar,
317  (CAST_U32(nextSpacePos) - nextChar))));
318 
319  if ((x + nextWordWidth + 10)
320  > CAST_U32(getWidth()))
321  {
322  x = mNewLinePadding; // Ident in new line
323  y += 1;
324  j ++;
325  }
326  }
327  // Wrapping looong lines (brutal force)
328  else if ((x + 2 * hyphenWidth)
329  > CAST_U32(getWidth()))
330  {
331  x = mNewLinePadding; // Ident in new line
332  y += 1;
333  }
334  }
335  }
336 
337  setHeight(fontHeight * (CAST_S32(
338  CAST_U32(mTextRows.size()) + y)));
339  mUpdateTime = 0;
340  updateHeight();
341 }
342 
343 void BrowserBox::addRow(const std::string &cmd, const char *const text)
344 {
345  addRow(strprintf("@@%s|%[email protected]@", encodeLinkText(cmd).c_str(),
346  encodeLinkText(text).c_str()),
347  false);
348 }
349 
350 void BrowserBox::addImage(const std::string &path)
351 {
352  if (!mEnableImages)
353  return;
354 
355  mTextRows.push_back("~~~" + path);
356  mTextRowLinksCount.push_back(0);
357 }
358 
360 {
361  mTextRows.clear();
362  mTextRowLinksCount.clear();
363  mLinks.clear();
364  setWidth(0);
365  setHeight(0);
366  mSelectedLink = -1;
367  mUpdateTime = 0;
368  mDataWidth = 0;
369  updateHeight();
370 }
371 
373 {
374  if (mLinkHandler == nullptr)
375  return;
376 
377  const LinkIterator i = std::find_if(mLinks.begin(), mLinks.end(),
378  MouseOverLink(event.getX(), event.getY()));
379 
380  if (i != mLinks.end())
381  {
382  mLinkHandler->handleLink(i->link, &event);
383  event.consume();
384  }
385 }
386 
388 {
389  const LinkIterator i = std::find_if(mLinks.begin(), mLinks.end(),
390  MouseOverLink(event.getX(), event.getY()));
391 
392  mSelectedLink = (i != mLinks.end())
393  ? CAST_S32(i - mLinks.begin()) : -1;
394 }
395 
397 {
398  mSelectedLink = -1;
399 }
400 
401 void BrowserBox::draw(Graphics *const graphics)
402 {
403  BLOCK_START("BrowserBox::draw")
404  const ClipRect &cr = graphics->getTopClip();
405  mYStart = cr.y - cr.yOffset;
406  const int yEnd = mYStart + cr.height;
407  if (mYStart < 0)
408  mYStart = 0;
409 
410  if (mDimension.width != mWidth)
411  {
413  mHeight = calcHeight();
416  if (mDimension.width != mWidth)
417  reportAlways("browserbox resize in draw")
418  }
419 
420  if (mOpaque == Opaque_true)
421  {
422  graphics->setColor(mBackgroundColor);
423  graphics->fillRectangle(Rect(0, 0,
425  }
426 
427  if (mSelectedLink >= 0 &&
428  mSelectedLink < CAST_S32(mLinks.size()))
429  {
431  {
433  graphics->setColor(mHighlightColor);
434  graphics->fillRectangle(Rect(
435  link.x1,
436  link.y1,
437  link.x2 - link.x1,
438  link.y2 - link.y1));
439  }
440 
442  {
444  graphics->setColor(mHyperLinkColor);
445  graphics->drawLine(
446  link.x1,
447  link.y2,
448  link.x2,
449  link.y2);
450  }
451  }
452 
453  Font *const font = getFont();
454 
456  {
457  const LinePart &part = *i;
458  if (part.mY + 50 < mYStart)
459  continue;
460  if (part.mY > yEnd)
461  break;
462  if (part.mType == 0U)
463  {
464  if (part.mBold)
465  {
466  boldFont->drawString(graphics,
467  part.mColor,
468  part.mColor2,
469  part.mText,
470  part.mX, part.mY);
471  }
472  else
473  {
474  font->drawString(graphics,
475  part.mColor,
476  part.mColor2,
477  part.mText,
478  part.mX, part.mY);
479  }
480  }
481  else if (part.mImage != nullptr)
482  {
483  graphics->drawImage(part.mImage, part.mX, part.mY);
484  }
485  }
486 
487  BLOCK_END("BrowserBox::draw")
488 }
489 
490 void BrowserBox::safeDraw(Graphics *const graphics)
491 {
492  BrowserBox::draw(graphics);
493 }
494 
496 {
497  unsigned int y = CAST_U32(mPadding);
498  int wrappedLines = 0;
499  int moreHeight = 0;
500  int maxWidth = mDimension.width - mPadding;
501  int link = 0;
502  bool bold = false;
503  unsigned int wWidth = CAST_U32(maxWidth);
504 
505  if (maxWidth < 0)
506  return 1;
507 
508  const Font *const font = getFont();
509  const int fontHeight = font->getHeight() + 2 * mItemPadding;
510  const int fontWidthMinus = font->getWidth("-");
511  const char *const hyphen = "~";
512  const int hyphenWidth = font->getWidth(hyphen);
513 
514  Color selColor[2] = {mForegroundColor, mForegroundColor2};
515  const Color textColor[2] = {mForegroundColor, mForegroundColor2};
516  mLineParts.clear();
517 
519  {
520  unsigned int x = CAST_U32(mPadding);
521  const std::string row = *(i);
522  bool wrapped = false;
523  int objects = 0;
524 
525  // Check for separator lines
526  if (row.find("---", 0) == 0)
527  {
528  const int dashWidth = fontWidthMinus;
529  for (x = CAST_U32(mPadding); x < wWidth; x ++)
530  {
531  mLineParts.push_back(LinePart(CAST_S32(x),
533  selColor[0], selColor[1], "-", false));
534  x += CAST_U32(CAST_S32(
535  dashWidth) - 2);
536  }
537 
538  y += CAST_U32(fontHeight);
539  continue;
540  }
541  else if (mEnableImages && row.find("~~~", 0) == 0)
542  {
543  std::string str = row.substr(3);
544  const size_t sz = str.size();
545  if (sz > 2 && str.substr(sz - 1) == "~")
546  str = str.substr(0, sz - 1);
547  Image *const img = Loader::getImage(str);
548  if (img != nullptr)
549  {
550  img->incRef();
551  mLineParts.push_back(LinePart(CAST_S32(x),
553  selColor[0], selColor[1], img));
554  y += CAST_U32(img->getHeight() + 2);
555  moreHeight += img->getHeight();
556  if (img->getWidth() > maxWidth)
557  maxWidth = img->getWidth() + 2;
558  }
559  continue;
560  }
561 
562  Color prevColor[2];
563  prevColor[0] = selColor[0];
564  prevColor[1] = selColor[1];
565  bold = false;
566 
567  const int xPadding = CAST_S32(mNewLinePadding) + mPadding;
568 
569  for (size_t start = 0, end = std::string::npos;
570  start != std::string::npos;
571  start = end, end = std::string::npos)
572  {
573  bool processed(false);
574 
575  // Wrapped line continuation shall be indented
576  if (wrapped)
577  {
578  y += CAST_U32(fontHeight);
579  x = CAST_U32(xPadding);
580  wrapped = false;
581  }
582 
583  size_t idx1 = end;
584  size_t idx2 = end;
585 
586  // "Tokenize" the string at control sequences
588  idx1 = row.find("##", start + 1);
589  if (start == 0 || mUseLinksAndUserColors)
590  {
591  // Check for color change in format "##x", x = [L,P,0..9]
592  if (row.find("##", start) == start && row.size() > start + 2)
593  {
594  const signed char c = row.at(start + 2);
595 
596  bool valid(false);
597  const Color col[2] =
598  {
601  c | 0x80), valid)
602  };
603 
604  if (c == '>')
605  {
606  selColor[0] = prevColor[0];
607  selColor[1] = prevColor[1];
608  }
609  else if (c == '<')
610  {
611  prevColor[0] = selColor[0];
612  prevColor[1] = selColor[1];
613  selColor[0] = col[0];
614  selColor[1] = col[1];
615  }
616  else if (c == 'B')
617  {
618  bold = true;
619  }
620  else if (c == 'b')
621  {
622  bold = false;
623  }
624  else if (valid)
625  {
626  selColor[0] = col[0];
627  selColor[1] = col[1];
628  }
629  else
630  {
631  switch (c)
632  {
633  case '0':
634  selColor[0] = mColors[0][ColorName::BLACK];
635  selColor[1] = mColors[1][ColorName::BLACK];
636  break;
637  case '1':
638  selColor[0] = mColors[0][ColorName::RED];
639  selColor[1] = mColors[1][ColorName::RED];
640  break;
641  case '2':
642  selColor[0] = mColors[0][ColorName::GREEN];
643  selColor[1] = mColors[1][ColorName::GREEN];
644  break;
645  case '3':
646  selColor[0] = mColors[0][ColorName::BLUE];
647  selColor[1] = mColors[1][ColorName::BLUE];
648  break;
649  case '4':
650  selColor[0] = mColors[0][ColorName::ORANGE];
651  selColor[1] = mColors[1][ColorName::ORANGE];
652  break;
653  case '5':
654  selColor[0] = mColors[0][ColorName::YELLOW];
655  selColor[1] = mColors[1][ColorName::YELLOW];
656  break;
657  case '6':
658  selColor[0] = mColors[0][ColorName::PINK];
659  selColor[1] = mColors[1][ColorName::PINK];
660  break;
661  case '7':
662  selColor[0] = mColors[0][ColorName::PURPLE];
663  selColor[1] = mColors[1][ColorName::PURPLE];
664  break;
665  case '8':
666  selColor[0] = mColors[0][ColorName::GRAY];
667  selColor[1] = mColors[1][ColorName::GRAY];
668  break;
669  case '9':
670  selColor[0] = mColors[0][ColorName::BROWN];
671  selColor[1] = mColors[1][ColorName::BROWN];
672  break;
673  default:
674  selColor[0] = textColor[0];
675  selColor[1] = textColor[1];
676  break;
677  }
678  }
679 
680  if (c == '<' && link < CAST_S32(mLinks.size()))
681  {
682  int size;
683  if (bold)
684  {
686  mLinks[CAST_SIZE(link)].caption) + 1;
687  }
688  else
689  {
690  size = font->getWidth(
691  mLinks[CAST_SIZE(link)].caption) + 1;
692  }
693 
694  BrowserLink &linkRef = mLinks[CAST_SIZE(
695  link)];
696  linkRef.x1 = CAST_S32(x);
697  linkRef.y1 = CAST_S32(y);
698  linkRef.x2 = linkRef.x1 + size;
699  linkRef.y2 = CAST_S32(y) + fontHeight - 1;
700  link++;
701  }
702 
703  processed = true;
704  start += 3;
705  if (start == row.size())
706  break;
707  }
708  }
709  if (mUseEmotes)
710  idx2 = row.find("%%", start + 1);
711  if (idx1 < idx2)
712  end = idx1;
713  else
714  end = idx2;
715  if (mUseEmotes)
716  {
717  // check for emote icons
718  if (row.size() > start + 2 && row.substr(start, 2) == "%%")
719  {
720  if (objects < 5)
721  {
722  const int cid = row.at(start + 2) - '0';
723  if (cid >= 0)
724  {
725  if (mEmotes != nullptr)
726  {
727  const size_t sz = mEmotes->size();
728  if (CAST_SIZE(cid) < sz)
729  {
730  Image *const img = mEmotes->get(
731  CAST_SIZE(cid));
732  if (img != nullptr)
733  {
734  mLineParts.push_back(LinePart(
735  CAST_S32(x),
737  selColor[0], selColor[1], img));
738  x += 18;
739  }
740  }
741  }
742  }
743  objects ++;
744  processed = true;
745  }
746 
747  start += 3;
748  if (start == row.size())
749  {
750  if (x > mDataWidth)
751  mDataWidth = x;
752  break;
753  }
754  }
755  }
756  const size_t len = (end == std::string::npos) ? end : end - start;
757 
758  if (start >= row.length())
759  break;
760 
761  std::string part = row.substr(start, len);
762  int width = 0;
763  if (bold)
764  width = boldFont->getWidth(part);
765  else
766  width = font->getWidth(part);
767 
768  // Auto wrap mode
769  if (wWidth > 0 &&
770  width > 0 &&
771  (x + CAST_U32(width) + 10) > wWidth)
772  {
773  bool forced = false;
774 
775  /* FIXME: This code layout makes it easy to crash remote
776  clients by talking garbage. Forged long utf-8 characters
777  will cause either a buffer underflow in substr or an
778  infinite loop in the main loop. */
779  do
780  {
781  if (!forced)
782  end = row.rfind(' ', end);
783 
784  // Check if we have to (stupidly) force-wrap
785  if (end == std::string::npos || end <= start)
786  {
787  forced = true;
788  end = row.size();
789  x += CAST_U32(hyphenWidth);
790  continue;
791  }
792 
793  // Skip to the start of the current character
794  while ((row[end] & 192) == 128)
795  end--;
796  end--; // And then to the last byte of the previous one
797 
798  part = row.substr(start, end - start + 1);
799  if (bold)
800  width = boldFont->getWidth(part);
801  else
802  width = font->getWidth(part);
803  }
804  while (end > start &&
805  width > 0 &&
806  (x + CAST_U32(width) + 10) > wWidth);
807 
808  if (forced)
809  {
810  x -= CAST_U32(hyphenWidth);
811  mLineParts.push_back(LinePart(
812  CAST_S32(wWidth) - hyphenWidth,
814  selColor[0], selColor[1], hyphen, bold));
815  end++; // Skip to the next character
816  }
817  else
818  {
819  end += 2; // Skip to after the space
820  }
821 
822  wrapped = true;
823  wrappedLines++;
824  }
825 
826  mLineParts.push_back(LinePart(CAST_S32(x),
828  selColor[0], selColor[1], part.c_str(), bold));
829 
830  if (bold)
831  width = boldFont->getWidth(part);
832  else
833  width = font->getWidth(part);
834 
835  if (width == 0 && !processed)
836  break;
837 
838  x += CAST_U32(width);
839  if (x > mDataWidth)
840  mDataWidth = x;
841  }
842  y += CAST_U32(fontHeight);
843  }
844  if (CAST_S32(wWidth) != maxWidth)
845  setWidth(maxWidth);
846 
847  return (CAST_S32(mTextRows.size()) + wrappedLines)
848  * fontHeight + moreHeight + 2 * mPadding;
849 }
850 
852 {
854  || mTextRows.size() < 3 || (mUpdateTime == 0))
855  {
857  mHeight = calcHeight();
860  }
861 }
862 
863 void BrowserBox::updateSize(const bool always)
864 {
865  if (always)
866  mUpdateTime = 0;
867  updateHeight();
868 }
869 
870 std::string BrowserBox::getTextAtPos(const int x, const int y) const
871 {
872  int textX = 0;
873  int textY = 0;
874 
875  getAbsolutePosition(textX, textY);
876  if (x < textX || y < textY)
877  return std::string();
878 
879  textY = y - textY;
880  std::string str;
881  int lastY = 0;
882 
884  {
885  const LinePart &part = *i;
886  if (part.mY + 50 < mYStart)
887  continue;
888  if (part.mY > textY)
889  break;
890 
891  if (part.mY > lastY)
892  {
893  str = part.mText;
894  lastY = part.mY;
895  }
896  else
897  {
898  str.append(part.mText);
899  }
900  }
901 
902  return str;
903 }
904 
906  const Color &color2)
907 {
908  mForegroundColor = color1;
909  mForegroundColor2 = color2;
910 }
911 
913 {
914  if (mSelectedLink <= 0)
915  mSelectedLink = CAST_S32(mLinks.size()) - 1;
916  else
917  mSelectedLink --;
918 }
919 
921 {
922  mSelectedLink ++;
923  if (mSelectedLink >= static_cast<signed int>(mLinks.size()))
924  mSelectedLink = 0;
925 }
926 
928 {
929  if ((mLinkHandler == nullptr) ||
930  mSelectedLink < 0 ||
931  mSelectedLink >= static_cast<signed int>(mLinks.size()))
932  {
933  return;
934  }
935 
937  nullptr);
938 }
939 
941 {
942  updateHeight();
943 }
volatile time_t cur_time
Definition: timer.cpp:58
#define CAST_S8
Definition: cast.h:26
#define CAST_S32
Definition: cast.h:30
#define CAST_U32
Definition: cast.h:31
#define CAST_SIZE
Definition: cast.h:34
#define reportAlways(...)
Definition: checkutils.h:253
bool mEnableTabs
Definition: browserbox.h:206
unsigned int mDataWidth
Definition: browserbox.h:193
int mPadding
Definition: browserbox.h:190
TextRows::const_iterator TextRowCIter
Definition: browserbox.h:168
void mousePressed(MouseEvent &event)
Definition: browserbox.cpp:372
BrowserBox(const Widget2 *const widget, const Opaque opaque, const std::string &skin)
Definition: browserbox.cpp:61
void updateHeight()
Definition: browserbox.cpp:851
std::string getTextAtPos(const int x, const int y) const
Definition: browserbox.cpp:870
Color mColors[2][ColorName::COLORS_MAX]
Definition: browserbox.h:197
Links mLinks
Definition: browserbox.h:179
unsigned int mHighlightMode
Definition: browserbox.h:183
int mSelectedLink
Definition: browserbox.h:184
void updateSize(const bool always)
Definition: browserbox.cpp:863
Color mHyperLinkColor
Definition: browserbox.h:196
Skin * mSkin
Definition: browserbox.h:182
static ImageSet * mEmotes
Definition: browserbox.h:208
void setForegroundColorAll(const Color &color1, const Color &color2)
Definition: browserbox.cpp:905
Links::iterator LinkIterator
Definition: browserbox.h:178
void widgetResized(const Event &event)
Definition: browserbox.cpp:940
void addRow(const std::string &row, const bool atTop)
Definition: browserbox.cpp:171
time_t mUpdateTime
Definition: browserbox.h:189
bool mEnableKeys
Definition: browserbox.h:205
void mouseMoved(MouseEvent &event)
Definition: browserbox.cpp:387
void addImage(const std::string &path)
Definition: browserbox.cpp:350
void setLinkHandler(LinkHandler *linkHandler)
Definition: browserbox.cpp:166
LinkHandler * mLinkHandler
Definition: browserbox.h:181
void moveSelectionUp()
Definition: browserbox.cpp:912
std::list< int > mTextRowLinksCount
Definition: browserbox.h:170
bool mAlwaysUpdate
Definition: browserbox.h:202
unsigned int mMaxRows
Definition: browserbox.h:185
void clearRows()
Definition: browserbox.cpp:359
int mItemPadding
Definition: browserbox.h:192
void mouseExited(MouseEvent &event)
Definition: browserbox.cpp:396
Opaque mOpaque
Definition: browserbox.h:199
Color mHighlightColor
Definition: browserbox.h:195
LinePartList mLineParts
Definition: browserbox.h:175
void safeDraw(Graphics *const graphics)
Definition: browserbox.cpp:490
LinePartList::const_iterator LinePartCIter
Definition: browserbox.h:174
bool mProcessVars
Definition: browserbox.h:203
bool mEnableImages
Definition: browserbox.h:204
bool mUseLinksAndUserColors
Definition: browserbox.h:200
void draw(Graphics *const graphics)
Definition: browserbox.cpp:401
TextRows mTextRows
Definition: browserbox.h:169
int calcHeight()
Definition: browserbox.cpp:495
void selectSelection()
Definition: browserbox.cpp:927
bool mUseEmotes
Definition: browserbox.h:201
unsigned int mNewLinePadding
Definition: browserbox.h:191
void moveSelectionDown()
Definition: browserbox.cpp:920
static int mInstances
Definition: browserbox.h:209
int yOffset
Definition: cliprect.h:127
Definition: color.h:76
Definition: event.h:79
Definition: font.h:90
int getHeight() const
Definition: font.cpp:362
int getWidth(const std::string &text) const
Definition: font.cpp:334
void drawString(Graphics *const graphics, Color col, const Color &col2, const std::string &text, const int x, const int y)
Definition: font.cpp:254
virtual void drawImage(const Image *const image, int dstX, int dstY)=0
virtual void fillRectangle(const Rect &rectangle)=0
virtual void setColor(const Color &color)
Definition: graphics.h:320
virtual void drawLine(int x1, int y1, int x2, int y2)=0
ClipRect & getTopClip() const
Definition: graphics.h:281
void removeDragged(const Widget *const widget)
Definition: gui.cpp:1162
Image * get(const size_type i) const
Definition: imageset.cpp:67
size_type size() const
Definition: imageset.h:73
int mX
Definition: linepart.h:93
unsigned char mType
Definition: linepart.h:98
int mY
Definition: linepart.h:94
bool mBold
Definition: linepart.h:100
Color mColor
Definition: linepart.h:95
Image * mImage
Definition: linepart.h:99
Color mColor2
Definition: linepart.h:96
std::string mText
Definition: linepart.h:97
virtual void handleLink(const std::string &link, MouseEvent *event)=0
int getX() const
Definition: mouseevent.h:127
int getY() const
Definition: mouseevent.h:138
const std::string getStr(const std::string &str)
Definition: podict.cpp:45
Definition: rect.h:74
int y
Definition: rect.h:214
int width
Definition: rect.h:219
int height
Definition: rect.h:224
virtual void decRef()
Definition: resource.cpp:50
int getOption(const std::string &name) const
Definition: skin.h:106
int getPadding() const
Definition: skin.h:100
void unload(Skin *const skin)
Definition: theme.cpp:250
static std::string getThemePath()
Definition: theme.h:67
Skin * load(const std::string &filename, const std::string &filename2, const bool full, const std::string &defaultPath)
Definition: theme.cpp:179
const Color & getThemeCharColor(const signed char c, bool &valid) const A_INLINE
Definition: widget2.h:52
Color mForegroundColor2
Definition: widget2.h:113
const Color & getThemeColor(const ThemeColorIdT type, const unsigned int alpha) const A_INLINE
Definition: widget2.h:45
Definition: widget.h:99
Color mForegroundColor
Definition: widget.h:1086
void setFocusable(const bool focusable)
Definition: widget.cpp:192
void setWidth(const int width)
Definition: widget.cpp:133
virtual void getAbsolutePosition(int &x, int &y) const
Definition: widget.cpp:312
Rect mDimension
Definition: widget.h:1101
Color mBackgroundColor
Definition: widget.h:1091
bool mAllowLogic
Definition: widget.h:1160
void addMouseListener(MouseListener *const mouseListener)
Definition: widget.cpp:292
void addWidgetListener(WidgetListener *const widgetListener)
Definition: widget.cpp:302
void setHeight(const int height)
Definition: widget.cpp:140
Font * getFont() const
Definition: widget.cpp:331
int getWidth() const
Definition: widget.h:221
#define FOR_EACH(type, iter, array)
Definition: foreach.h:25
Gui * gui
Definition: gui.cpp:111
Font * boldFont
Definition: gui.cpp:112
#define nullptr
Definition: localconsts.h:45
#define A_UNUSED
Definition: localconsts.h:160
void replaceKeys(std::string &data)
void replaceVars(std::string &data)
std::string replaceLinkCommands(const std::string &link)
void replaceTabs(std::string &data)
int size()
Definition: emotedb.cpp:306
Image * getImage(const std::string &idPath)
Definition: imageloader.cpp:86
ImageSet * getImageSet(const std::string &imagePath, const int w, const int h)
const bool Opaque_true
Definition: opaque.h:30
bool Opaque
Definition: opaque.h:30
#define BLOCK_END(name)
Definition: perfomance.h:80
#define BLOCK_START(name)
Definition: perfomance.h:79
PoDict * translator
Definition: podict.cpp:28
std::string strprintf(const char *const format,...)
std::string encodeLinkText(std::string data)
Theme * theme
Definition: theme.cpp:62
static Color readColor(const std::string &description)
Definition: theme.cpp:697