aboutsummaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/irrlicht_changes/static_text.cpp (renamed from src/util/statictext.cpp)139
-rw-r--r--src/irrlicht_changes/static_text.h (renamed from src/util/statictext.h)122
-rw-r--r--src/util/CMakeLists.txt11
-rw-r--r--src/util/coloredstring.cpp68
-rw-r--r--src/util/coloredstring.h44
-rw-r--r--src/util/enriched_string.cpp166
-rw-r--r--src/util/enriched_string.h91
-rw-r--r--src/util/string.h32
8 files changed, 492 insertions, 181 deletions
diff --git a/src/util/statictext.cpp b/src/irrlicht_changes/static_text.cpp
index b534b560e..703287eb3 100644
--- a/src/util/statictext.cpp
+++ b/src/irrlicht_changes/static_text.cpp
@@ -1,12 +1,12 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
+// Copyright (C) 2016 Nathanaël Courant:
+// Modified the functions to use EnrichedText instead of string.
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
-#include "statictext.h"
+#include "static_text.h"
#ifdef _IRR_COMPILE_WITH_GUI_
-//Only compile this if freetype is enabled.
-
#include <vector>
#include <string>
#include <iostream>
@@ -17,15 +17,21 @@
#include <rect.h>
#include <SColor.h>
-#include "cguittfont/xCGUITTFont.h"
+#if USE_FREETYPE
+ #include "cguittfont/xCGUITTFont.h"
+#endif
+
#include "util/string.h"
namespace irr
{
+
+#if USE_FREETYPE
+
namespace gui
{
//! constructor
-StaticText::StaticText(const wchar_t* text, bool border,
+StaticText::StaticText(const EnrichedString &text, bool border,
IGUIEnvironment* environment, IGUIElement* parent,
s32 id, const core::rect<s32>& rectangle,
bool background)
@@ -40,7 +46,8 @@ StaticText::StaticText(const wchar_t* text, bool border,
setDebugName("StaticText");
#endif
- Text = text;
+ Text = text.c_str();
+ cText = text;
if (environment && environment->getSkin())
{
BGColor = environment->getSkin()->getColor(gui::EGDC_3D_FACE);
@@ -55,7 +62,6 @@ StaticText::~StaticText()
OverrideFont->drop();
}
-
//! draws the element and its children
void StaticText::draw()
{
@@ -88,7 +94,7 @@ void StaticText::draw()
}
// draw the text
- if (Text.size())
+ if (cText.size())
{
IGUIFont* font = getActiveFont();
@@ -105,10 +111,11 @@ void StaticText::draw()
if (HAlign == EGUIA_LOWERRIGHT)
{
frameRect.UpperLeftCorner.X = frameRect.LowerRightCorner.X -
- font->getDimension(Text.c_str()).Width;
+ font->getDimension(cText.c_str()).Width;
}
- font->draw(Text.c_str(), frameRect,
+ irr::gui::CGUITTFont *tmp = static_cast<irr::gui::CGUITTFont*>(font);
+ tmp->draw(cText, frameRect,
OverrideColorEnabled ? OverrideColor : skin->getColor(isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT),
HAlign == EGUIA_CENTER, VAlign == EGUIA_CENTER, (RestrainTextInside ? &AbsoluteClippingRect : NULL));
}
@@ -138,16 +145,17 @@ void StaticText::draw()
font->getDimension(BrokenText[i].c_str()).Width;
}
- std::vector<irr::video::SColor> colors;
- std::wstring str;
+ //std::vector<irr::video::SColor> colors;
+ //std::wstring str;
+ EnrichedString str = BrokenText[i];
- str = colorizeText(BrokenText[i].c_str(), colors, previous_color);
- if (!colors.empty())
- previous_color = colors[colors.size() - 1];
+ //str = colorizeText(BrokenText[i].c_str(), colors, previous_color);
+ //if (!colors.empty())
+ // previous_color = colors[colors.size() - 1];
irr::gui::CGUITTFont *tmp = static_cast<irr::gui::CGUITTFont*>(font);
- tmp->draw(str.c_str(), r,
- colors,
+ tmp->draw(str, r,
+ previous_color, // FIXME
HAlign == EGUIA_CENTER, false, (RestrainTextInside ? &AbsoluteClippingRect : NULL));
r.LowerRightCorner.Y += height;
@@ -340,17 +348,17 @@ void StaticText::breakText()
LastBreakFont = font;
- core::stringw line;
- core::stringw word;
- core::stringw whitespace;
- s32 size = Text.size();
+ EnrichedString line;
+ EnrichedString word;
+ EnrichedString whitespace;
+ s32 size = cText.size();
s32 length = 0;
s32 elWidth = RelativeRect.getWidth();
if (Border)
elWidth -= 2*skin->getSize(EGDS_TEXT_DISTANCE_X);
wchar_t c;
- std::vector<irr::video::SColor> colors;
+ //std::vector<irr::video::SColor> colors;
// We have to deal with right-to-left and left-to-right differently
// However, most parts of the following code is the same, it's just
@@ -360,17 +368,17 @@ void StaticText::breakText()
// regular (left-to-right)
for (s32 i=0; i<size; ++i)
{
- c = Text[i];
+ c = cText.getString()[i];
bool lineBreak = false;
if (c == L'\r') // Mac or Windows breaks
{
lineBreak = true;
- if (Text[i+1] == L'\n') // Windows breaks
- {
- Text.erase(i+1);
- --size;
- }
+ //if (Text[i+1] == L'\n') // Windows breaks
+ //{
+ // Text.erase(i+1);
+ // --size;
+ //}
c = '\0';
}
else if (c == L'\n') // Unix breaks
@@ -383,7 +391,8 @@ void StaticText::breakText()
if ( !isWhitespace )
{
// part of a word
- word += c;
+ //word += c;
+ word.addChar(cText, i);
}
if ( isWhitespace || i == (size-1))
@@ -393,20 +402,21 @@ void StaticText::breakText()
// here comes the next whitespace, look if
// we must break the last word to the next line.
const s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
- const std::wstring sanitized = removeEscapes(word.c_str());
- const s32 wordlgth = font->getDimension(sanitized.c_str()).Width;
+ //const std::wstring sanitized = removeEscapes(word.c_str());
+ const s32 wordlgth = font->getDimension(word.c_str()).Width;
if (wordlgth > elWidth)
{
// This word is too long to fit in the available space, look for
// the Unicode Soft HYphen (SHY / 00AD) character for a place to
// break the word at
- int where = word.findFirst( wchar_t(0x00AD) );
+ int where = core::stringw(word.c_str()).findFirst( wchar_t(0x00AD) );
if (where != -1)
{
- core::stringw first = word.subString(0, where);
- core::stringw second = word.subString(where, word.size() - where);
- BrokenText.push_back(line + first + L"-");
+ EnrichedString first = word.substr(0, where);
+ EnrichedString second = word.substr(where, word.size() - where);
+ first.addCharNoColor(L'-');
+ BrokenText.push_back(line + first);
const s32 secondLength = font->getDimension(second.c_str()).Width;
length = secondLength;
@@ -437,13 +447,13 @@ void StaticText::breakText()
length += whitelgth + wordlgth;
}
- word = L"";
- whitespace = L"";
+ word.clear();
+ whitespace.clear();
}
- if ( isWhitespace )
+ if ( isWhitespace && c != 0)
{
- whitespace += c;
+ whitespace.addChar(cText, i);
}
// compute line break
@@ -452,9 +462,9 @@ void StaticText::breakText()
line += whitespace;
line += word;
BrokenText.push_back(line);
- line = L"";
- word = L"";
- whitespace = L"";
+ line.clear();
+ word.clear();
+ whitespace.clear();
length = 0;
}
}
@@ -469,17 +479,17 @@ void StaticText::breakText()
// right-to-left
for (s32 i=size; i>=0; --i)
{
- c = Text[i];
+ c = cText.getString()[i];
bool lineBreak = false;
if (c == L'\r') // Mac or Windows breaks
{
lineBreak = true;
- if ((i>0) && Text[i-1] == L'\n') // Windows breaks
- {
- Text.erase(i-1);
- --size;
- }
+ //if ((i>0) && Text[i-1] == L'\n') // Windows breaks
+ //{
+ // Text.erase(i-1);
+ // --size;
+ //}
c = '\0';
}
else if (c == L'\n') // Unix breaks
@@ -512,12 +522,13 @@ void StaticText::breakText()
length += whitelgth + wordlgth;
}
- word = L"";
- whitespace = L"";
+ word.clear();
+ whitespace.clear();
}
if (c != 0)
- whitespace = core::stringw(&c, 1) + whitespace;
+ // whitespace = core::stringw(&c, 1) + whitespace;
+ whitespace = cText.substr(i, 1) + whitespace;
// compute line break
if (lineBreak)
@@ -525,16 +536,17 @@ void StaticText::breakText()
line = whitespace + line;
line = word + line;
BrokenText.push_back(line);
- line = L"";
- word = L"";
- whitespace = L"";
+ line.clear();
+ word.clear();
+ whitespace.clear();
length = 0;
}
}
else
{
// yippee this is a word..
- word = core::stringw(&c, 1) + word;
+ //word = core::stringw(&c, 1) + word;
+ word = cText.substr(i, 1) + word;
}
}
@@ -548,7 +560,17 @@ void StaticText::breakText()
//! Sets the new caption of this element.
void StaticText::setText(const wchar_t* text)
{
- IGUIElement::setText(text);
+ setText(EnrichedString(text));
+}
+
+//! Sets the new caption of this element.
+void StaticText::setText(const EnrichedString &text)
+{
+ IGUIElement::setText(text.c_str());
+ cText = text;
+ if (text.hasBackground()) {
+ setBackgroundColor(text.getBackground());
+ }
breakText();
}
@@ -598,7 +620,7 @@ s32 StaticText::getTextWidth() const
}
else
{
- return font->getDimension(Text.c_str()).Width;
+ return font->getDimension(cText.c_str()).Width;
}
}
@@ -648,6 +670,9 @@ void StaticText::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWr
}
} // end namespace gui
+
+#endif // USE_FREETYPE
+
} // end namespace irr
diff --git a/src/util/statictext.h b/src/irrlicht_changes/static_text.h
index 8d2f879e7..408a12784 100644
--- a/src/util/statictext.h
+++ b/src/irrlicht_changes/static_text.h
@@ -1,4 +1,6 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
+// Copyright (C) 2016 Nathanaël Courant
+// Modified this class to work with EnrichedStrings too
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
@@ -11,18 +13,30 @@
#include "IGUIStaticText.h"
#include "irrArray.h"
+#include "log.h"
+
#include <vector>
+#include "util/enriched_string.h"
+#include "config.h"
+#include <IGUIEnvironment.h>
+
+#if USE_FREETYPE
+
namespace irr
{
+
namespace gui
{
+
+ const EGUI_ELEMENT_TYPE EGUIET_ENRICHED_STATIC_TEXT = (EGUI_ELEMENT_TYPE)(0x1000);
+
class StaticText : public IGUIStaticText
{
public:
//! constructor
- StaticText(const wchar_t* text, bool border, IGUIEnvironment* environment,
+ StaticText(const EnrichedString &text, bool border, IGUIEnvironment* environment,
IGUIElement* parent, s32 id, const core::rect<s32>& rectangle,
bool background = false);
@@ -121,6 +135,16 @@ namespace gui
//! Reads attributes of the element
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);
+ virtual bool hasType(EGUI_ELEMENT_TYPE t) const {
+ return (t == EGUIET_ENRICHED_STATIC_TEXT) || (t == EGUIET_STATIC_TEXT);
+ };
+
+ virtual bool hasType(EGUI_ELEMENT_TYPE t) {
+ return (t == EGUIET_ENRICHED_STATIC_TEXT) || (t == EGUIET_STATIC_TEXT);
+ };
+
+ void setText(const EnrichedString &text);
+
private:
//! Breaks the single text line.
@@ -139,12 +163,106 @@ namespace gui
gui::IGUIFont* OverrideFont;
gui::IGUIFont* LastBreakFont; // stored because: if skin changes, line break must be recalculated.
- core::array< core::stringw > BrokenText;
+ EnrichedString cText;
+ core::array< EnrichedString > BrokenText;
};
+
} // end namespace gui
+
} // end namespace irr
+inline irr::gui::IGUIStaticText *addStaticText(
+ irr::gui::IGUIEnvironment *guienv,
+ const EnrichedString &text,
+ const core::rect< s32 > &rectangle,
+ bool border = false,
+ bool wordWrap = true,
+ irr::gui::IGUIElement *parent = NULL,
+ s32 id = -1,
+ bool fillBackground = false)
+{
+ if (parent == NULL) {
+ // parent is NULL, so we must find one, or we need not to drop
+ // result, but then there will be a memory leak.
+ //
+ // What Irrlicht does is to use guienv as a parent, but the problem
+ // is that guienv is here only an IGUIEnvironment, while it is a
+ // CGUIEnvironment in Irrlicht, which inherits from both IGUIElement
+ // and IGUIEnvironment.
+ //
+ // A solution would be to dynamic_cast guienv to a
+ // IGUIElement*, but Irrlicht is shipped without rtti support
+ // in some distributions, causing the dymanic_cast to segfault.
+ //
+ // Thus, to find the parent, we create a dummy StaticText and ask
+ // for its parent, and then remove it.
+ irr::gui::IGUIStaticText *dummy_text =
+ guienv->addStaticText(L"", rectangle, border, wordWrap,
+ parent, id, fillBackground);
+ parent = dummy_text->getParent();
+ dummy_text->remove();
+ }
+ irr::gui::IGUIStaticText *result = new irr::gui::StaticText(
+ text, border, guienv, parent,
+ id, rectangle, fillBackground);
+
+ result->setWordWrap(wordWrap);
+ result->drop();
+ return result;
+}
+
+inline void setStaticText(irr::gui::IGUIStaticText *static_text, const EnrichedString &text)
+{
+ // dynamic_cast not possible due to some distributions shipped
+ // without rtti support in irrlicht
+ if (static_text->hasType(irr::gui::EGUIET_ENRICHED_STATIC_TEXT)) {
+ irr::gui::StaticText* stext = static_cast<irr::gui::StaticText*>(static_text);
+ stext->setText(text);
+ } else {
+ static_text->setText(text.c_str());
+ }
+}
+
+#else // USE_FREETYPE
+
+inline irr::gui::IGUIStaticText *addStaticText(
+ irr::gui::IGUIEnvironment *guienv,
+ const EnrichedString &text,
+ const core::rect< s32 > &rectangle,
+ bool border = false,
+ bool wordWrap = true,
+ irr::gui::IGUIElement *parent = NULL,
+ s32 id = -1,
+ bool fillBackground = false)
+{
+ return guienv->addStaticText(text.c_str(), rectangle, border, wordWrap, parent, id, fillBackground);
+}
+
+inline void setStaticText(irr::gui::IGUIStaticText *static_text, const EnrichedString &text)
+{
+ static_text->setText(text.c_str());
+}
+
+#endif
+
+inline irr::gui::IGUIStaticText *addStaticText(
+ irr::gui::IGUIEnvironment *guienv,
+ const wchar_t *text,
+ const core::rect< s32 > &rectangle,
+ bool border = false,
+ bool wordWrap = true,
+ irr::gui::IGUIElement *parent = NULL,
+ s32 id = -1,
+ bool fillBackground = false) {
+ return addStaticText(guienv, EnrichedString(text), rectangle, border, wordWrap, parent, id, fillBackground);
+}
+
+inline void setStaticText(irr::gui::IGUIStaticText *static_text, const wchar_t *text)
+{
+ setStaticText(static_text, EnrichedString(text));
+}
+
#endif // _IRR_COMPILE_WITH_GUI_
#endif // C_GUI_STATIC_TEXT_H_INCLUDED
diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt
index e028a0435..f571ab22c 100644
--- a/src/util/CMakeLists.txt
+++ b/src/util/CMakeLists.txt
@@ -1,17 +1,9 @@
-if(USE_FREETYPE)
- set(UTIL_FREETYPEDEP_SRCS
- ${CMAKE_CURRENT_SOURCE_DIR}/statictext.cpp
- )
-else()
- set(UTIL_FREETYPEDEP_SRCS )
-endif(USE_FREETYPE)
-
set(UTIL_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/areastore.cpp
${CMAKE_CURRENT_SOURCE_DIR}/auth.cpp
${CMAKE_CURRENT_SOURCE_DIR}/base64.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/coloredstring.cpp
${CMAKE_CURRENT_SOURCE_DIR}/directiontables.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/enriched_string.cpp
${CMAKE_CURRENT_SOURCE_DIR}/numeric.cpp
${CMAKE_CURRENT_SOURCE_DIR}/pointedthing.cpp
${CMAKE_CURRENT_SOURCE_DIR}/serialize.cpp
@@ -20,6 +12,5 @@ set(UTIL_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/string.cpp
${CMAKE_CURRENT_SOURCE_DIR}/srp.cpp
${CMAKE_CURRENT_SOURCE_DIR}/timetaker.cpp
- ${UTIL_FREETYPEDEP_SRCS}
PARENT_SCOPE)
diff --git a/src/util/coloredstring.cpp b/src/util/coloredstring.cpp
deleted file mode 100644
index 7db586550..000000000
--- a/src/util/coloredstring.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
-Copyright (C) 2013 xyz, Ilya Zhuravlev <whatever@xyz.is>
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2.1 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public License along
-with this program; if not, write to the Free Software Foundation, Inc.,
-51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-
-#include "coloredstring.h"
-#include "util/string.h"
-
-ColoredString::ColoredString()
-{}
-
-ColoredString::ColoredString(const std::wstring &string, const std::vector<SColor> &colors):
- m_string(string),
- m_colors(colors)
-{}
-
-ColoredString::ColoredString(const std::wstring &s) {
- m_string = colorizeText(s, m_colors, SColor(255, 255, 255, 255));
-}
-
-void ColoredString::operator=(const wchar_t *str) {
- m_string = colorizeText(str, m_colors, SColor(255, 255, 255, 255));
-}
-
-size_t ColoredString::size() const {
- return m_string.size();
-}
-
-ColoredString ColoredString::substr(size_t pos, size_t len) const {
- if (pos == m_string.length())
- return ColoredString();
- if (len == std::string::npos || pos + len > m_string.length()) {
- return ColoredString(
- m_string.substr(pos, std::string::npos),
- std::vector<SColor>(m_colors.begin() + pos, m_colors.end())
- );
- } else {
- return ColoredString(
- m_string.substr(pos, len),
- std::vector<SColor>(m_colors.begin() + pos, m_colors.begin() + pos + len)
- );
- }
-}
-
-const wchar_t *ColoredString::c_str() const {
- return m_string.c_str();
-}
-
-const std::vector<SColor> &ColoredString::getColors() const {
- return m_colors;
-}
-
-const std::wstring &ColoredString::getString() const {
- return m_string;
-}
diff --git a/src/util/coloredstring.h b/src/util/coloredstring.h
deleted file mode 100644
index a6d98db30..000000000
--- a/src/util/coloredstring.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
-Copyright (C) 2013 xyz, Ilya Zhuravlev <whatever@xyz.is>
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2.1 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public License along
-with this program; if not, write to the Free Software Foundation, Inc.,
-51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-
-#ifndef COLOREDSTRING_HEADER
-#define COLOREDSTRING_HEADER
-
-#include <string>
-#include <vector>
-#include <SColor.h>
-
-using namespace irr::video;
-
-class ColoredString {
-public:
- ColoredString();
- ColoredString(const std::wstring &s);
- ColoredString(const std::wstring &string, const std::vector<SColor> &colors);
- void operator=(const wchar_t *str);
- size_t size() const;
- ColoredString substr(size_t pos = 0, size_t len = std::string::npos) const;
- const wchar_t *c_str() const;
- const std::vector<SColor> &getColors() const;
- const std::wstring &getString() const;
-private:
- std::wstring m_string;
- std::vector<SColor> m_colors;
-};
-
-#endif
diff --git a/src/util/enriched_string.cpp b/src/util/enriched_string.cpp
new file mode 100644
index 000000000..a7fc3a828
--- /dev/null
+++ b/src/util/enriched_string.cpp
@@ -0,0 +1,166 @@
+/*
+Copyright (C) 2013 xyz, Ilya Zhuravlev <whatever@xyz.is>
+Copyright (C) 2016 Nore, Nathanaël Courant <nore@mesecons.net>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "enriched_string.h"
+#include "util/string.h"
+#include "log.h"
+using namespace irr::video;
+
+EnrichedString::EnrichedString()
+{
+ clear();
+}
+
+EnrichedString::EnrichedString(const std::wstring &string,
+ const std::vector<SColor> &colors):
+ m_string(string),
+ m_colors(colors),
+ m_has_background(false)
+{}
+
+EnrichedString::EnrichedString(const std::wstring &s, const SColor &color)
+{
+ clear();
+ addAtEnd(s, color);
+}
+
+EnrichedString::EnrichedString(const wchar_t *str, const SColor &color)
+{
+ clear();
+ addAtEnd(std::wstring(str), color);
+}
+
+void EnrichedString::operator=(const wchar_t *str)
+{
+ clear();
+ addAtEnd(std::wstring(str), SColor(255, 255, 255, 255));
+}
+
+void EnrichedString::addAtEnd(const std::wstring &s, const SColor &initial_color)
+{
+ SColor color(initial_color);
+ size_t i = 0;
+ while (i < s.length()) {
+ if (s[i] != L'\x1b') {
+ m_string += s[i];
+ m_colors.push_back(color);
+ ++i;
+ continue;
+ }
+ ++i;
+ size_t start_index = i;
+ size_t length;
+ if (i == s.length()) {
+ break;
+ }
+ if (s[i] == L'(') {
+ ++i;
+ ++start_index;
+ while (i < s.length() && s[i] != L')') {
+ if (s[i] == L'\\') {
+ ++i;
+ }
+ ++i;
+ }
+ length = i - start_index;
+ ++i;
+ } else {
+ ++i;
+ length = 1;
+ }
+ std::wstring escape_sequence(s, start_index, length);
+ std::vector<std::wstring> parts = split(escape_sequence, L'@');
+ if (parts[0] == L"c") {
+ if (parts.size() < 2) {
+ continue;
+ }
+ parseColorString(wide_to_utf8(parts[1]), color, true);
+ } else if (parts[0] == L"b") {
+ if (parts.size() < 2) {
+ continue;
+ }
+ parseColorString(wide_to_utf8(parts[1]), m_background, true);
+ m_has_background = true;
+ }
+ continue;
+ }
+}
+
+void EnrichedString::addChar(const EnrichedString &source, size_t i)
+{
+ m_string += source.m_string[i];
+ m_colors.push_back(source.m_colors[i]);
+}
+
+void EnrichedString::addCharNoColor(wchar_t c)
+{
+ m_string += c;
+ if (m_colors.empty()) {
+ m_colors.push_back(SColor(255, 255, 255, 255));
+ } else {
+ m_colors.push_back(m_colors[m_colors.size() - 1]);
+ }
+}
+
+EnrichedString EnrichedString::operator+(const EnrichedString &other) const
+{
+ std::vector<SColor> result;
+ result.insert(result.end(), m_colors.begin(), m_colors.end());
+ result.insert(result.end(), other.m_colors.begin(), other.m_colors.end());
+ return EnrichedString(m_string + other.m_string, result);
+}
+
+void EnrichedString::operator+=(const EnrichedString &other)
+{
+ m_string += other.m_string;
+ m_colors.insert(m_colors.end(), other.m_colors.begin(), other.m_colors.end());
+}
+
+EnrichedString EnrichedString::substr(size_t pos, size_t len) const
+{
+ if (pos == m_string.length()) {
+ return EnrichedString();
+ }
+ if (len == std::string::npos || pos + len > m_string.length()) {
+ return EnrichedString(
+ m_string.substr(pos, std::string::npos),
+ std::vector<SColor>(m_colors.begin() + pos, m_colors.end())
+ );
+ } else {
+ return EnrichedString(
+ m_string.substr(pos, len),
+ std::vector<SColor>(m_colors.begin() + pos, m_colors.begin() + pos + len)
+ );
+ }
+}
+
+const wchar_t *EnrichedString::c_str() const
+{
+ return m_string.c_str();
+}
+
+const std::vector<SColor> &EnrichedString::getColors() const
+{
+ return m_colors;
+}
+
+const std::wstring &EnrichedString::getString() const
+{
+ return m_string;
+}
diff --git a/src/util/enriched_string.h b/src/util/enriched_string.h
new file mode 100644
index 000000000..1aca8948a
--- /dev/null
+++ b/src/util/enriched_string.h
@@ -0,0 +1,91 @@
+/*
+Copyright (C) 2013 xyz, Ilya Zhuravlev <whatever@xyz.is>
+Copyright (C) 2016 Nore, Nathanaël Courant <nore@mesecons.net>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef ENRICHEDSTRING_HEADER
+#define ENRICHEDSTRING_HEADER
+
+#include <string>
+#include <vector>
+#include <SColor.h>
+
+class EnrichedString {
+public:
+ EnrichedString();
+ EnrichedString(const std::wstring &s,
+ const irr::video::SColor &color = irr::video::SColor(255, 255, 255, 255));
+ EnrichedString(const wchar_t *str,
+ const irr::video::SColor &color = irr::video::SColor(255, 255, 255, 255));
+ EnrichedString(const std::wstring &string,
+ const std::vector<irr::video::SColor> &colors);
+ void operator=(const wchar_t *str);
+ void addAtEnd(const std::wstring &s, const irr::video::SColor &color);
+
+ // Adds the character source[i] at the end.
+ // An EnrichedString should always be able to be copied
+ // to the end of an existing EnrichedString that way.
+ void addChar(const EnrichedString &source, size_t i);
+
+ // Adds a single character at the end, without specifying its
+ // color. The color used will be the one from the last character.
+ void addCharNoColor(wchar_t c);
+
+ EnrichedString substr(size_t pos = 0, size_t len = std::string::npos) const;
+ EnrichedString operator+(const EnrichedString &other) const;
+ void operator+=(const EnrichedString &other);
+ const wchar_t *c_str() const;
+ const std::vector<irr::video::SColor> &getColors() const;
+ const std::wstring &getString() const;
+ inline bool operator==(const EnrichedString &other) const
+ {
+ return (m_string == other.m_string && m_colors == other.m_colors);
+ }
+ inline bool operator!=(const EnrichedString &other) const
+ {
+ return !(*this == other);
+ }
+ inline void clear()
+ {
+ m_string.clear();
+ m_colors.clear();
+ m_has_background = false;
+ }
+ inline bool empty() const
+ {
+ return m_string.empty();
+ }
+ inline size_t size() const
+ {
+ return m_string.size();
+ }
+ inline bool hasBackground() const
+ {
+ return m_has_background;
+ }
+ inline irr::video::SColor getBackground() const
+ {
+ return m_background;
+ }
+private:
+ std::wstring m_string;
+ std::vector<irr::video::SColor> m_colors;
+ bool m_has_background;
+ irr::video::SColor m_background;
+};
+
+#endif
diff --git a/src/util/string.h b/src/util/string.h
index 40ef3e4d3..c77c5a6f9 100644
--- a/src/util/string.h
+++ b/src/util/string.h
@@ -519,6 +519,38 @@ std::basic_string<T> unescape_enriched(const std::basic_string<T> &s)
return output;
}
+template <typename T>
+std::vector<std::basic_string<T> > split(const std::basic_string<T> &s, T delim)
+{
+ std::vector<std::basic_string<T> > tokens;
+
+ std::basic_string<T> current;
+ bool last_was_escape = false;
+ for (size_t i = 0; i < s.length(); i++) {
+ T si = s[i];
+ if (last_was_escape) {
+ current += '\\';
+ current += si;
+ last_was_escape = false;
+ } else {
+ if (si == delim) {
+ tokens.push_back(current);
+ current = std::basic_string<T>();
+ last_was_escape = false;
+ } else if (si == '\\') {
+ last_was_escape = true;
+ } else {
+ current += si;
+ last_was_escape = false;
+ }
+ }
+ }
+ //push last element
+ tokens.push_back(current);
+
+ return tokens;
+}
+
/**
* Checks that all characters in \p to_check are a decimal digits.
*