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); }