Пример #1
0
void CGUITextLayout::ParseText(const CStdStringW &text, uint32_t defaultStyle, color_t defaultColor, vecColors &colors, vecText &parsedText)
{
  // run through the string, searching for:
  // [B] or [/B] -> toggle bold on and off
  // [I] or [/I] -> toggle italics on and off
  // [COLOR ffab007f] or [/COLOR] -> toggle color on and off
  // [CAPS <option>] or [/CAPS] -> toggle capatilization on and off

  uint32_t currentStyle = defaultStyle; // start with the default font's style
  color_t currentColor = 0;

  colors.push_back(defaultColor);
  stack<color_t> colorStack;
  colorStack.push(0);

  // these aren't independent, but that's probably not too much of an issue
  // eg [UPPERCASE]Glah[LOWERCASE]FReD[/LOWERCASE]Georeg[/UPPERCASE] will work (lower case >> upper case)
  // but [LOWERCASE]Glah[UPPERCASE]FReD[/UPPERCASE]Georeg[/LOWERCASE] won't

  int startPos = 0;
  size_t pos = text.find(L'[');
  while (pos != std::string::npos && pos + 1 < text.size())
  {
    uint32_t newStyle = 0;
    color_t newColor = currentColor;
    bool colorTagChange = false;
    bool newLine = false;
    // have a [ - check if it's an ON or OFF switch
    bool on(true);
    size_t endPos = pos++; // finish of string
    if (text[pos] == L'/')
    {
      on = false;
      pos++;
    }
    // check for each type
    if (text.compare(pos, 2, L"B]") == 0)
    { // bold - finish the current text block and assign the bold state
      pos += 2;
      if ((on && text.find(L"[/B]",pos) != std::string::npos) ||          // check for a matching end point
         (!on && (currentStyle & FONT_STYLE_BOLD)))       // or matching start point
        newStyle = FONT_STYLE_BOLD;
    }
    else if (text.compare(pos, 2, L"I]") == 0)
    { // italics
      pos += 2;
      if ((on && text.find(L"[/I]", pos) != std::string::npos) ||          // check for a matching end point
         (!on && (currentStyle & FONT_STYLE_ITALICS)))    // or matching start point
        newStyle = FONT_STYLE_ITALICS;
    }
    else if (text.compare(pos, 10, L"UPPERCASE]") == 0)
    {
      pos += 10;
      if ((on && text.find(L"[/UPPERCASE]", pos) != std::string::npos) ||  // check for a matching end point
         (!on && (currentStyle & FONT_STYLE_UPPERCASE)))  // or matching start point
        newStyle = FONT_STYLE_UPPERCASE;
    }
    else if (text.compare(pos, 10, L"LOWERCASE]") == 0)
    {
      pos += 10;
      if ((on && text.find(L"[/LOWERCASE]", pos) != std::string::npos) ||  // check for a matching end point
         (!on && (currentStyle & FONT_STYLE_LOWERCASE)))  // or matching start point
        newStyle = FONT_STYLE_LOWERCASE;
    }
    else if (text.compare(pos, 3, L"CR]") == 0 && on)
    {
      newLine = true;
      pos += 3;
    }
    else if (text.compare(pos,5, L"COLOR") == 0)
    { // color
      size_t finish = text.find(L']', pos + 5);
      if (on && finish != std::string::npos && text.find(L"[/COLOR]",finish) != std::string::npos)
      {
        color_t color = g_colorManager.GetColor(text.substr(pos + 5, finish - pos - 5));
        vecColors::const_iterator it = std::find(colors.begin(), colors.end(), color);
        if (it == colors.end())
        { // create new color
          if (colors.size() <= 0xFF)
          {
            newColor = colors.size();
            colors.push_back(color);
          }
          else // we have only 8 bits for color index, fallback to first color if reach max.
            newColor = 0;
        }
        else
          // reuse existing color
          newColor = it - colors.begin();
        colorStack.push(newColor);
        colorTagChange = true;
      }
      else if (!on && finish == pos + 5 && colorStack.size() > 1)
      { // revert to previous color
        colorStack.pop();
        newColor = colorStack.top();
        colorTagChange = true;
      }
      if (finish != CStdString::npos)
        pos = finish + 1;
    }

    if (newStyle || colorTagChange || newLine)
    { // we have a new style or a new color, so format up the previous segment
      CStdStringW subText = text.substr(startPos, endPos - startPos);
      if (currentStyle & FONT_STYLE_UPPERCASE)
        StringUtils::ToUpper(subText);
      if (currentStyle & FONT_STYLE_LOWERCASE)
        StringUtils::ToLower(subText);
      AppendToUTF32(subText, ((currentStyle & 3) << 24) | (currentColor << 16), parsedText);
      if (newLine)
        parsedText.push_back(L'\n');

      // and switch to the new style
      startPos = pos;
      currentColor = newColor;
      if (on)
        currentStyle |= newStyle;
      else
        currentStyle &= ~newStyle;
    }
    pos = text.find(L'[', pos);
  }
  // now grab the remainder of the string
  CStdStringW subText = text.substr(startPos);
  if (currentStyle & FONT_STYLE_UPPERCASE)
    StringUtils::ToUpper(subText);
  if (currentStyle & FONT_STYLE_LOWERCASE)
    StringUtils::ToLower(subText);
  AppendToUTF32(subText, ((currentStyle & 3) << 24) | (currentColor << 16), parsedText);
}