mirror of
https://github.com/minetest/minetest.git
synced 2024-12-23 14:42:24 +01:00
StaticText/EnrichedString: Styling support (#9187)
* StaticText/EnrichedString: Styling support * Fix tooltip fg/bgcolor * Fix default color for substr(), add unittests
This commit is contained in:
parent
fab3f5f7c8
commit
1892ff3c0d
@ -1,3 +1,5 @@
|
|||||||
|
local color = minetest.colorize
|
||||||
|
|
||||||
local clip_fs = [[
|
local clip_fs = [[
|
||||||
style_type[label;noclip=%c]
|
style_type[label;noclip=%c]
|
||||||
style_type[button;noclip=%c]
|
style_type[button;noclip=%c]
|
||||||
@ -31,8 +33,8 @@ local style_fs = [[
|
|||||||
bgcolor_pressed=purple]
|
bgcolor_pressed=purple]
|
||||||
button[0,0;2.5,0.8;one_btn1;Button]
|
button[0,0;2.5,0.8;one_btn1;Button]
|
||||||
|
|
||||||
style[one_btn2;border=false;textcolor=cyan]
|
style[one_btn2;border=false;textcolor=cyan] ]]..
|
||||||
button[0,1.05;2.5,0.8;one_btn2;Text Button]
|
"button[0,1.05;2.5,0.8;one_btn2;Text " .. color("#FF0", "Yellow") .. [[]
|
||||||
|
|
||||||
style[one_btn3;bgimg=bubble.png;bgimg_hovered=default_apple.png;
|
style[one_btn3;bgimg=bubble.png;bgimg_hovered=default_apple.png;
|
||||||
bgimg_pressed=heart.png]
|
bgimg_pressed=heart.png]
|
||||||
@ -144,16 +146,18 @@ local pages = {
|
|||||||
list[current_player;main;6,8;3,2;1]
|
list[current_player;main;6,8;3,2;1]
|
||||||
button[9,0;2.5,1;name;]
|
button[9,0;2.5,1;name;]
|
||||||
button[9,1;2.5,1;name;]
|
button[9,1;2.5,1;name;]
|
||||||
button[9,2;2.5,1;name;]
|
button[9,2;2.5,1;name;] ]]..
|
||||||
label[9,0;This is a label.\nLine\nLine\nLine\nEnd]
|
"label[9,0.5;This is a label.\nLine\nLine\nLine\nEnd]"..
|
||||||
button[9,3;1,1;name;]
|
[[button[9,3;1,1;name;]
|
||||||
vertlabel[9,4;VERT]
|
vertlabel[9,4;VERT]
|
||||||
label[10,3;HORIZ]
|
label[10,3;HORIZ]
|
||||||
tabheader[6.5,0;6,0.65;name;Tab 1,Tab 2,Tab 3,Secrets;1;false;false]
|
tabheader[6.5,0;6,0.65;name;Tab 1,Tab 2,Tab 3,Secrets;1;false;false]
|
||||||
]],
|
]],
|
||||||
|
|
||||||
"size[12,12]real_coordinates[true]" ..
|
"size[12,12]real_coordinates[true]" ..
|
||||||
"label[0.375,0.375;Styled]" ..
|
("label[0.375,0.375;Styled - %s %s]"):format(
|
||||||
|
color("#F00", "red text"),
|
||||||
|
color("#77FF00CC", "green text")) ..
|
||||||
"label[6.375,0.375;Unstyled]" ..
|
"label[6.375,0.375;Unstyled]" ..
|
||||||
"box[0,0.75;12,0.1;#999]" ..
|
"box[0,0.75;12,0.1;#999]" ..
|
||||||
"box[6,0.85;0.1,11.15;#999]" ..
|
"box[6,0.85;0.1,11.15;#999]" ..
|
||||||
|
@ -155,7 +155,7 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
|
|||||||
|
|
||||||
m_guitext2->setVisible(m_flags.show_debug);
|
m_guitext2->setVisible(m_flags.show_debug);
|
||||||
|
|
||||||
setStaticText(m_guitext_info, translate_string(m_infotext).c_str());
|
setStaticText(m_guitext_info, m_infotext.c_str());
|
||||||
m_guitext_info->setVisible(m_flags.show_hud && g_menumgr.menuCount() == 0);
|
m_guitext_info->setVisible(m_flags.show_hud && g_menumgr.menuCount() == 0);
|
||||||
|
|
||||||
static const float statustext_time_max = 1.5f;
|
static const float statustext_time_max = 1.5f;
|
||||||
@ -169,7 +169,7 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setStaticText(m_guitext_status, translate_string(m_statustext).c_str());
|
setStaticText(m_guitext_status, m_statustext.c_str());
|
||||||
m_guitext_status->setVisible(!m_statustext.empty());
|
m_guitext_status->setVisible(!m_statustext.empty());
|
||||||
|
|
||||||
if (!m_statustext.empty()) {
|
if (!m_statustext.empty()) {
|
||||||
|
@ -53,7 +53,6 @@ GUIButton::GUIButton(IGUIEnvironment* environment, IGUIElement* parent,
|
|||||||
core::clamp<u32>(Colors[i].getGreen() * COLOR_PRESSED_MOD, 0, 255),
|
core::clamp<u32>(Colors[i].getGreen() * COLOR_PRESSED_MOD, 0, 255),
|
||||||
core::clamp<u32>(Colors[i].getBlue() * COLOR_PRESSED_MOD, 0, 255));
|
core::clamp<u32>(Colors[i].getBlue() * COLOR_PRESSED_MOD, 0, 255));
|
||||||
}
|
}
|
||||||
|
|
||||||
StaticText = gui::StaticText::add(Environment, Text.c_str(), core::rect<s32>(0,0,rectangle.getWidth(),rectangle.getHeight()), false, false, this, id);
|
StaticText = gui::StaticText::add(Environment, Text.c_str(), core::rect<s32>(0,0,rectangle.getWidth(),rectangle.getHeight()), false, false, this, id);
|
||||||
StaticText->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER);
|
StaticText->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER);
|
||||||
// END PATCH
|
// END PATCH
|
||||||
|
@ -3417,19 +3417,16 @@ void GUIFormSpecMenu::drawMenu()
|
|||||||
void GUIFormSpecMenu::showTooltip(const std::wstring &text,
|
void GUIFormSpecMenu::showTooltip(const std::wstring &text,
|
||||||
const irr::video::SColor &color, const irr::video::SColor &bgcolor)
|
const irr::video::SColor &color, const irr::video::SColor &bgcolor)
|
||||||
{
|
{
|
||||||
const std::wstring ntext = translate_string(text);
|
EnrichedString ntext(text);
|
||||||
m_tooltip_element->setOverrideColor(color);
|
ntext.setDefaultColor(color);
|
||||||
m_tooltip_element->setBackgroundColor(bgcolor);
|
ntext.setBackground(bgcolor);
|
||||||
setStaticText(m_tooltip_element, ntext.c_str());
|
|
||||||
|
setStaticText(m_tooltip_element, ntext);
|
||||||
|
|
||||||
// Tooltip size and offset
|
// Tooltip size and offset
|
||||||
s32 tooltip_width = m_tooltip_element->getTextWidth() + m_btn_height;
|
s32 tooltip_width = m_tooltip_element->getTextWidth() + m_btn_height;
|
||||||
#if (IRRLICHT_VERSION_MAJOR <= 1 && IRRLICHT_VERSION_MINOR <= 8 && IRRLICHT_VERSION_REVISION < 2) || USE_FREETYPE == 1
|
|
||||||
std::vector<std::wstring> text_rows = str_split(ntext, L'\n');
|
|
||||||
s32 tooltip_height = m_tooltip_element->getTextHeight() * text_rows.size() + 5;
|
|
||||||
#else
|
|
||||||
s32 tooltip_height = m_tooltip_element->getTextHeight() + 5;
|
s32 tooltip_height = m_tooltip_element->getTextHeight() + 5;
|
||||||
#endif
|
|
||||||
v2u32 screenSize = Environment->getVideoDriver()->getScreenSize();
|
v2u32 screenSize = Environment->getVideoDriver()->getScreenSize();
|
||||||
int tooltip_offset_x = m_btn_height;
|
int tooltip_offset_x = m_btn_height;
|
||||||
int tooltip_offset_y = m_btn_height;
|
int tooltip_offset_y = m_btn_height;
|
||||||
|
@ -32,21 +32,15 @@ StaticText::StaticText(const EnrichedString &text, bool border,
|
|||||||
bool background)
|
bool background)
|
||||||
: IGUIStaticText(environment, parent, id, rectangle),
|
: IGUIStaticText(environment, parent, id, rectangle),
|
||||||
HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_UPPERLEFT),
|
HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_UPPERLEFT),
|
||||||
Border(border), OverrideColorEnabled(false), OverrideBGColorEnabled(false), WordWrap(false), Background(background),
|
Border(border), WordWrap(false), Background(background),
|
||||||
RestrainTextInside(true), RightToLeft(false),
|
RestrainTextInside(true), RightToLeft(false),
|
||||||
OverrideColor(video::SColor(101,255,255,255)), BGColor(video::SColor(101,210,210,210)),
|
|
||||||
OverrideFont(0), LastBreakFont(0)
|
OverrideFont(0), LastBreakFont(0)
|
||||||
{
|
{
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
setDebugName("StaticText");
|
setDebugName("StaticText");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Text = text.c_str();
|
setText(text);
|
||||||
cText = text;
|
|
||||||
if (environment && environment->getSkin())
|
|
||||||
{
|
|
||||||
BGColor = environment->getSkin()->getColor(gui::EGDC_3D_FACE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -73,12 +67,7 @@ void StaticText::draw()
|
|||||||
// draw background
|
// draw background
|
||||||
|
|
||||||
if (Background)
|
if (Background)
|
||||||
{
|
driver->draw2DRectangle(getBackgroundColor(), frameRect, &AbsoluteClippingRect);
|
||||||
if ( !OverrideBGColorEnabled ) // skin-colors can change
|
|
||||||
BGColor = skin->getColor(gui::EGDC_3D_FACE);
|
|
||||||
|
|
||||||
driver->draw2DRectangle(BGColor, frameRect, &AbsoluteClippingRect);
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw the border
|
// draw the border
|
||||||
|
|
||||||
@ -89,71 +78,36 @@ void StaticText::draw()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// draw the text
|
// draw the text
|
||||||
if (cText.size())
|
|
||||||
{
|
|
||||||
IGUIFont *font = getActiveFont();
|
IGUIFont *font = getActiveFont();
|
||||||
|
if (font && BrokenText.size()) {
|
||||||
if (font)
|
|
||||||
{
|
|
||||||
if (!WordWrap)
|
|
||||||
{
|
|
||||||
// TODO: add colors here
|
|
||||||
if (VAlign == EGUIA_LOWERRIGHT)
|
|
||||||
{
|
|
||||||
frameRect.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y -
|
|
||||||
font->getDimension(L"A").Height - font->getKerningHeight();
|
|
||||||
}
|
|
||||||
if (HAlign == EGUIA_LOWERRIGHT)
|
|
||||||
{
|
|
||||||
frameRect.UpperLeftCorner.X = frameRect.LowerRightCorner.X -
|
|
||||||
font->getDimension(cText.c_str()).Width;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if USE_FREETYPE
|
|
||||||
if (font->getType() == irr::gui::EGFT_CUSTOM) {
|
|
||||||
irr::gui::CGUITTFont *tmp = static_cast<irr::gui::CGUITTFont*>(font);
|
|
||||||
tmp->draw(Text, frameRect,
|
|
||||||
OverrideColorEnabled ? OverrideColor :
|
|
||||||
skin->getColor(isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT),
|
|
||||||
HAlign == EGUIA_CENTER, VAlign == EGUIA_CENTER,
|
|
||||||
(RestrainTextInside ? &AbsoluteClippingRect : NULL));
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
font->draw(Text.c_str(), frameRect,
|
|
||||||
skin->getColor(EGDC_BUTTON_TEXT),
|
|
||||||
HAlign == EGUIA_CENTER, VAlign == EGUIA_CENTER,
|
|
||||||
(RestrainTextInside ? &AbsoluteClippingRect : NULL));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (font != LastBreakFont)
|
if (font != LastBreakFont)
|
||||||
breakText();
|
updateText();
|
||||||
|
|
||||||
core::rect<s32> r = frameRect;
|
core::rect<s32> r = frameRect;
|
||||||
s32 height = font->getDimension(L"A").Height + font->getKerningHeight();
|
s32 height_line = font->getDimension(L"A").Height + font->getKerningHeight();
|
||||||
s32 totalHeight = height * BrokenText.size();
|
s32 height_total = height_line * BrokenText.size();
|
||||||
if (VAlign == EGUIA_CENTER)
|
if (VAlign == EGUIA_CENTER && WordWrap)
|
||||||
{
|
{
|
||||||
r.UpperLeftCorner.Y = r.getCenter().Y - (totalHeight / 2);
|
r.UpperLeftCorner.Y = r.getCenter().Y - (height_total / 2);
|
||||||
}
|
}
|
||||||
else if (VAlign == EGUIA_LOWERRIGHT)
|
else if (VAlign == EGUIA_LOWERRIGHT)
|
||||||
{
|
{
|
||||||
r.UpperLeftCorner.Y = r.LowerRightCorner.Y - totalHeight;
|
r.UpperLeftCorner.Y = r.LowerRightCorner.Y - height_total;
|
||||||
|
}
|
||||||
|
if (HAlign == EGUIA_LOWERRIGHT)
|
||||||
|
{
|
||||||
|
r.UpperLeftCorner.X = r.LowerRightCorner.X -
|
||||||
|
getTextWidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
irr::video::SColor previous_color(255, 255, 255, 255);
|
irr::video::SColor previous_color(255, 255, 255, 255);
|
||||||
for (u32 i=0; i<BrokenText.size(); ++i)
|
for (const EnrichedString &str : BrokenText) {
|
||||||
{
|
|
||||||
if (HAlign == EGUIA_LOWERRIGHT)
|
if (HAlign == EGUIA_LOWERRIGHT)
|
||||||
{
|
{
|
||||||
r.UpperLeftCorner.X = frameRect.LowerRightCorner.X -
|
r.UpperLeftCorner.X = frameRect.LowerRightCorner.X -
|
||||||
font->getDimension(BrokenText[i].c_str()).Width;
|
font->getDimension(str.c_str()).Width;
|
||||||
}
|
}
|
||||||
|
|
||||||
EnrichedString str = BrokenText[i];
|
|
||||||
|
|
||||||
//str = colorizeText(BrokenText[i].c_str(), colors, previous_color);
|
//str = colorizeText(BrokenText[i].c_str(), colors, previous_color);
|
||||||
//if (!colors.empty())
|
//if (!colors.empty())
|
||||||
// previous_color = colors[colors.size() - 1];
|
// previous_color = colors[colors.size() - 1];
|
||||||
@ -163,23 +117,21 @@ void StaticText::draw()
|
|||||||
irr::gui::CGUITTFont *tmp = static_cast<irr::gui::CGUITTFont*>(font);
|
irr::gui::CGUITTFont *tmp = static_cast<irr::gui::CGUITTFont*>(font);
|
||||||
tmp->draw(str,
|
tmp->draw(str,
|
||||||
r, previous_color, // FIXME
|
r, previous_color, // FIXME
|
||||||
HAlign == EGUIA_CENTER, false,
|
HAlign == EGUIA_CENTER, VAlign == EGUIA_CENTER,
|
||||||
(RestrainTextInside ? &AbsoluteClippingRect : NULL));
|
(RestrainTextInside ? &AbsoluteClippingRect : NULL));
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
// Draw non-colored text
|
// Draw non-colored text
|
||||||
font->draw(str.c_str(),
|
font->draw(str.c_str(),
|
||||||
r, skin->getColor(EGDC_BUTTON_TEXT),
|
r, str.getDefaultColor(), // TODO: Implement colorization
|
||||||
HAlign == EGUIA_CENTER, false,
|
HAlign == EGUIA_CENTER, VAlign == EGUIA_CENTER,
|
||||||
(RestrainTextInside ? &AbsoluteClippingRect : NULL));
|
(RestrainTextInside ? &AbsoluteClippingRect : NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
r.LowerRightCorner.Y += height;
|
r.LowerRightCorner.Y += height_line;
|
||||||
r.UpperLeftCorner.Y += height;
|
r.UpperLeftCorner.Y += height_line;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,7 +153,7 @@ void StaticText::setOverrideFont(IGUIFont* font)
|
|||||||
if (OverrideFont)
|
if (OverrideFont)
|
||||||
OverrideFont->grab();
|
OverrideFont->grab();
|
||||||
|
|
||||||
breakText();
|
updateText();
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Gets the override font (if any)
|
//! Gets the override font (if any)
|
||||||
@ -224,16 +176,15 @@ IGUIFont* StaticText::getActiveFont() const
|
|||||||
//! Sets another color for the text.
|
//! Sets another color for the text.
|
||||||
void StaticText::setOverrideColor(video::SColor color)
|
void StaticText::setOverrideColor(video::SColor color)
|
||||||
{
|
{
|
||||||
OverrideColor = color;
|
ColoredText.setDefaultColor(color);
|
||||||
OverrideColorEnabled = true;
|
updateText();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//! Sets another color for the text.
|
//! Sets another color for the text.
|
||||||
void StaticText::setBackgroundColor(video::SColor color)
|
void StaticText::setBackgroundColor(video::SColor color)
|
||||||
{
|
{
|
||||||
BGColor = color;
|
ColoredText.setBackground(color);
|
||||||
OverrideBGColorEnabled = true;
|
|
||||||
Background = true;
|
Background = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,7 +199,10 @@ void StaticText::setDrawBackground(bool draw)
|
|||||||
//! Gets the background color
|
//! Gets the background color
|
||||||
video::SColor StaticText::getBackgroundColor() const
|
video::SColor StaticText::getBackgroundColor() const
|
||||||
{
|
{
|
||||||
return BGColor;
|
IGUISkin *skin = Environment->getSkin();
|
||||||
|
|
||||||
|
return (ColoredText.hasBackground() || !skin) ?
|
||||||
|
ColoredText.getBackground() : skin->getColor(gui::EGDC_3D_FACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -298,7 +252,7 @@ const video::SColor& StaticText::getOverrideColor() const
|
|||||||
video::SColor StaticText::getOverrideColor() const
|
video::SColor StaticText::getOverrideColor() const
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
return OverrideColor;
|
return ColoredText.getDefaultColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -306,13 +260,13 @@ video::SColor StaticText::getOverrideColor() const
|
|||||||
//! color in the gui skin.
|
//! color in the gui skin.
|
||||||
void StaticText::enableOverrideColor(bool enable)
|
void StaticText::enableOverrideColor(bool enable)
|
||||||
{
|
{
|
||||||
OverrideColorEnabled = enable;
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool StaticText::isOverrideColorEnabled() const
|
bool StaticText::isOverrideColorEnabled() const
|
||||||
{
|
{
|
||||||
return OverrideColorEnabled;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -321,7 +275,7 @@ bool StaticText::isOverrideColorEnabled() const
|
|||||||
void StaticText::setWordWrap(bool enable)
|
void StaticText::setWordWrap(bool enable)
|
||||||
{
|
{
|
||||||
WordWrap = enable;
|
WordWrap = enable;
|
||||||
breakText();
|
updateText();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -336,7 +290,7 @@ void StaticText::setRightToLeft(bool rtl)
|
|||||||
if (RightToLeft != rtl)
|
if (RightToLeft != rtl)
|
||||||
{
|
{
|
||||||
RightToLeft = rtl;
|
RightToLeft = rtl;
|
||||||
breakText();
|
updateText();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,13 +302,23 @@ bool StaticText::isRightToLeft() const
|
|||||||
|
|
||||||
|
|
||||||
//! Breaks the single text line.
|
//! Breaks the single text line.
|
||||||
void StaticText::breakText()
|
// Updates the font colors
|
||||||
|
void StaticText::updateText()
|
||||||
{
|
{
|
||||||
if (!WordWrap)
|
const EnrichedString &cText = ColoredText;
|
||||||
return;
|
|
||||||
|
|
||||||
BrokenText.clear();
|
BrokenText.clear();
|
||||||
|
|
||||||
|
if (cText.hasBackground()) {
|
||||||
|
setBackgroundColor(cText.getBackground());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!WordWrap) {
|
||||||
|
BrokenText.push_back(cText);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update word wrap
|
||||||
|
|
||||||
IGUISkin* skin = Environment->getSkin();
|
IGUISkin* skin = Environment->getSkin();
|
||||||
IGUIFont* font = getActiveFont();
|
IGUIFont* font = getActiveFont();
|
||||||
if (!font)
|
if (!font)
|
||||||
@ -574,25 +538,20 @@ void StaticText::breakText()
|
|||||||
//! Sets the new caption of this element.
|
//! Sets the new caption of this element.
|
||||||
void StaticText::setText(const wchar_t* text)
|
void StaticText::setText(const wchar_t* text)
|
||||||
{
|
{
|
||||||
setText(EnrichedString(text));
|
setText(EnrichedString(text, getOverrideColor()));
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Sets the new caption of this element.
|
|
||||||
void StaticText::setText(const EnrichedString &text)
|
void StaticText::setText(const EnrichedString &text)
|
||||||
{
|
{
|
||||||
IGUIElement::setText(text.c_str());
|
ColoredText = text;
|
||||||
cText = text;
|
IGUIElement::setText(ColoredText.c_str());
|
||||||
if (text.hasBackground()) {
|
updateText();
|
||||||
setBackgroundColor(text.getBackground());
|
|
||||||
}
|
}
|
||||||
breakText();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void StaticText::updateAbsolutePosition()
|
void StaticText::updateAbsolutePosition()
|
||||||
{
|
{
|
||||||
IGUIElement::updateAbsolutePosition();
|
IGUIElement::updateAbsolutePosition();
|
||||||
breakText();
|
updateText();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -603,12 +562,12 @@ s32 StaticText::getTextHeight() const
|
|||||||
if (!font)
|
if (!font)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (WordWrap) {
|
||||||
s32 height = font->getDimension(L"A").Height + font->getKerningHeight();
|
s32 height = font->getDimension(L"A").Height + font->getKerningHeight();
|
||||||
|
return height * BrokenText.size();
|
||||||
if (WordWrap)
|
}
|
||||||
height *= BrokenText.size();
|
// There may be intentional new lines without WordWrap
|
||||||
|
return font->getDimension(BrokenText[0].c_str()).Height;
|
||||||
return height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -618,13 +577,10 @@ s32 StaticText::getTextWidth() const
|
|||||||
if (!font)
|
if (!font)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if(WordWrap)
|
|
||||||
{
|
|
||||||
s32 widest = 0;
|
s32 widest = 0;
|
||||||
|
|
||||||
for(u32 line = 0; line < BrokenText.size(); ++line)
|
for (const EnrichedString &line : BrokenText) {
|
||||||
{
|
s32 width = font->getDimension(line.c_str()).Width;
|
||||||
s32 width = font->getDimension(BrokenText[line].c_str()).Width;
|
|
||||||
|
|
||||||
if (width > widest)
|
if (width > widest)
|
||||||
widest = width;
|
widest = width;
|
||||||
@ -632,11 +588,6 @@ s32 StaticText::getTextWidth() const
|
|||||||
|
|
||||||
return widest;
|
return widest;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
return font->getDimension(cText.c_str()).Width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//! Writes attributes of the element.
|
//! Writes attributes of the element.
|
||||||
@ -647,14 +598,14 @@ void StaticText::serializeAttributes(io::IAttributes* out, io::SAttributeReadWri
|
|||||||
IGUIStaticText::serializeAttributes(out,options);
|
IGUIStaticText::serializeAttributes(out,options);
|
||||||
|
|
||||||
out->addBool ("Border", Border);
|
out->addBool ("Border", Border);
|
||||||
out->addBool ("OverrideColorEnabled",OverrideColorEnabled);
|
out->addBool ("OverrideColorEnabled",true);
|
||||||
out->addBool ("OverrideBGColorEnabled",OverrideBGColorEnabled);
|
out->addBool ("OverrideBGColorEnabled",ColoredText.hasBackground());
|
||||||
out->addBool ("WordWrap", WordWrap);
|
out->addBool ("WordWrap", WordWrap);
|
||||||
out->addBool ("Background", Background);
|
out->addBool ("Background", Background);
|
||||||
out->addBool ("RightToLeft", RightToLeft);
|
out->addBool ("RightToLeft", RightToLeft);
|
||||||
out->addBool ("RestrainTextInside", RestrainTextInside);
|
out->addBool ("RestrainTextInside", RestrainTextInside);
|
||||||
out->addColor ("OverrideColor", OverrideColor);
|
out->addColor ("OverrideColor", ColoredText.getDefaultColor());
|
||||||
out->addColor ("BGColor", BGColor);
|
out->addColor ("BGColor", ColoredText.getBackground());
|
||||||
out->addEnum ("HTextAlign", HAlign, GUIAlignmentNames);
|
out->addEnum ("HTextAlign", HAlign, GUIAlignmentNames);
|
||||||
out->addEnum ("VTextAlign", VAlign, GUIAlignmentNames);
|
out->addEnum ("VTextAlign", VAlign, GUIAlignmentNames);
|
||||||
|
|
||||||
@ -668,14 +619,14 @@ void StaticText::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWr
|
|||||||
IGUIStaticText::deserializeAttributes(in,options);
|
IGUIStaticText::deserializeAttributes(in,options);
|
||||||
|
|
||||||
Border = in->getAttributeAsBool("Border");
|
Border = in->getAttributeAsBool("Border");
|
||||||
enableOverrideColor(in->getAttributeAsBool("OverrideColorEnabled"));
|
|
||||||
OverrideBGColorEnabled = in->getAttributeAsBool("OverrideBGColorEnabled");
|
|
||||||
setWordWrap(in->getAttributeAsBool("WordWrap"));
|
setWordWrap(in->getAttributeAsBool("WordWrap"));
|
||||||
Background = in->getAttributeAsBool("Background");
|
Background = in->getAttributeAsBool("Background");
|
||||||
RightToLeft = in->getAttributeAsBool("RightToLeft");
|
RightToLeft = in->getAttributeAsBool("RightToLeft");
|
||||||
RestrainTextInside = in->getAttributeAsBool("RestrainTextInside");
|
RestrainTextInside = in->getAttributeAsBool("RestrainTextInside");
|
||||||
OverrideColor = in->getAttributeAsColor("OverrideColor");
|
if (in->getAttributeAsBool("OverrideColorEnabled"))
|
||||||
BGColor = in->getAttributeAsColor("BGColor");
|
ColoredText.setDefaultColor(in->getAttributeAsColor("OverrideColor"));
|
||||||
|
if (in->getAttributeAsBool("OverrideBGColorEnabled"))
|
||||||
|
ColoredText.setBackground(in->getAttributeAsColor("BGColor"));
|
||||||
|
|
||||||
setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames),
|
setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames),
|
||||||
(EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames));
|
(EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames));
|
||||||
|
@ -34,7 +34,8 @@ namespace gui
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
//! constructor
|
// StaticText is translated by EnrichedString.
|
||||||
|
// No need to use translate_string()
|
||||||
StaticText(const EnrichedString &text, bool border, IGUIEnvironment* environment,
|
StaticText(const EnrichedString &text, bool border, IGUIEnvironment* environment,
|
||||||
IGUIElement* parent, s32 id, const core::rect<s32>& rectangle,
|
IGUIElement* parent, s32 id, const core::rect<s32>& rectangle,
|
||||||
bool background = false);
|
bool background = false);
|
||||||
@ -201,23 +202,20 @@ namespace gui
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
//! Breaks the single text line.
|
//! Breaks the single text line.
|
||||||
void breakText();
|
void updateText();
|
||||||
|
|
||||||
EGUI_ALIGNMENT HAlign, VAlign;
|
EGUI_ALIGNMENT HAlign, VAlign;
|
||||||
bool Border;
|
bool Border;
|
||||||
bool OverrideColorEnabled;
|
|
||||||
bool OverrideBGColorEnabled;
|
|
||||||
bool WordWrap;
|
bool WordWrap;
|
||||||
bool Background;
|
bool Background;
|
||||||
bool RestrainTextInside;
|
bool RestrainTextInside;
|
||||||
bool RightToLeft;
|
bool RightToLeft;
|
||||||
|
|
||||||
video::SColor OverrideColor, BGColor;
|
|
||||||
gui::IGUIFont* OverrideFont;
|
gui::IGUIFont* OverrideFont;
|
||||||
gui::IGUIFont* LastBreakFont; // stored because: if skin changes, line break must be recalculated.
|
gui::IGUIFont* LastBreakFont; // stored because: if skin changes, line break must be recalculated.
|
||||||
|
|
||||||
EnrichedString cText;
|
EnrichedString ColoredText;
|
||||||
core::array< EnrichedString > BrokenText;
|
std::vector<EnrichedString> BrokenText;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -274,10 +272,7 @@ inline void setStaticText(irr::gui::IGUIStaticText *static_text, const EnrichedS
|
|||||||
|
|
||||||
inline void setStaticText(irr::gui::IGUIStaticText *static_text, const wchar_t *text)
|
inline void setStaticText(irr::gui::IGUIStaticText *static_text, const wchar_t *text)
|
||||||
{
|
{
|
||||||
auto color = static_text->isOverrideColorEnabled()
|
setStaticText(static_text, EnrichedString(text, static_text->getOverrideColor()));
|
||||||
? static_text->getOverrideColor()
|
|
||||||
: irr::video::SColor(255, 255, 255, 255);
|
|
||||||
setStaticText(static_text, EnrichedString(text, color));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // _IRR_COMPILE_WITH_GUI_
|
#endif // _IRR_COMPILE_WITH_GUI_
|
||||||
|
@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "test.h"
|
#include "test.h"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include "util/enriched_string.h"
|
||||||
#include "util/numeric.h"
|
#include "util/numeric.h"
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
|
|
||||||
@ -49,6 +50,7 @@ public:
|
|||||||
void testUTF8();
|
void testUTF8();
|
||||||
void testRemoveEscapes();
|
void testRemoveEscapes();
|
||||||
void testWrapRows();
|
void testWrapRows();
|
||||||
|
void testEnrichedString();
|
||||||
void testIsNumber();
|
void testIsNumber();
|
||||||
void testIsPowerOfTwo();
|
void testIsPowerOfTwo();
|
||||||
void testMyround();
|
void testMyround();
|
||||||
@ -79,6 +81,7 @@ void TestUtilities::runTests(IGameDef *gamedef)
|
|||||||
TEST(testUTF8);
|
TEST(testUTF8);
|
||||||
TEST(testRemoveEscapes);
|
TEST(testRemoveEscapes);
|
||||||
TEST(testWrapRows);
|
TEST(testWrapRows);
|
||||||
|
TEST(testEnrichedString);
|
||||||
TEST(testIsNumber);
|
TEST(testIsNumber);
|
||||||
TEST(testIsPowerOfTwo);
|
TEST(testIsPowerOfTwo);
|
||||||
TEST(testMyround);
|
TEST(testMyround);
|
||||||
@ -344,6 +347,23 @@ void TestUtilities::testWrapRows()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestUtilities::testEnrichedString()
|
||||||
|
{
|
||||||
|
EnrichedString str(L"Test bar");
|
||||||
|
irr::video::SColor color(0xFF, 0, 0, 0xFF);
|
||||||
|
|
||||||
|
UASSERT(str.substr(1, 3).getString() == L"est");
|
||||||
|
str += L" BUZZ";
|
||||||
|
UASSERT(str.substr(9, std::string::npos).getString() == L"BUZZ");
|
||||||
|
str.setDefaultColor(color); // Blue foreground
|
||||||
|
UASSERT(str.getColors()[5] == color);
|
||||||
|
// Green background, then white and yellow text
|
||||||
|
str = L"\x1b(b@#0F0)Regular \x1b(c@#FF0)yellow";
|
||||||
|
UASSERT(str.getColors()[2] == 0xFFFFFFFF);
|
||||||
|
str.setDefaultColor(color); // Blue foreground
|
||||||
|
UASSERT(str.getColors()[13] == 0xFFFFFF00); // Still yellow text
|
||||||
|
UASSERT(str.getBackground() == 0xFF00FF00); // Green background
|
||||||
|
}
|
||||||
|
|
||||||
void TestUtilities::testIsNumber()
|
void TestUtilities::testIsNumber()
|
||||||
{
|
{
|
||||||
|
@ -45,15 +45,27 @@ EnrichedString::EnrichedString(const wchar_t *str, const SColor &color)
|
|||||||
addAtEnd(translate_string(std::wstring(str)), color);
|
addAtEnd(translate_string(std::wstring(str)), color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EnrichedString::clear()
|
||||||
|
{
|
||||||
|
m_string.clear();
|
||||||
|
m_colors.clear();
|
||||||
|
m_has_background = false;
|
||||||
|
m_default_length = 0;
|
||||||
|
m_default_color = irr::video::SColor(255, 255, 255, 255);
|
||||||
|
}
|
||||||
|
|
||||||
void EnrichedString::operator=(const wchar_t *str)
|
void EnrichedString::operator=(const wchar_t *str)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
addAtEnd(translate_string(std::wstring(str)), SColor(255, 255, 255, 255));
|
addAtEnd(translate_string(std::wstring(str)), m_default_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnrichedString::addAtEnd(const std::wstring &s, const SColor &initial_color)
|
void EnrichedString::addAtEnd(const std::wstring &s, const SColor &initial_color)
|
||||||
{
|
{
|
||||||
SColor color(initial_color);
|
SColor color(initial_color);
|
||||||
|
bool use_default = (m_default_length == m_string.size() &&
|
||||||
|
color == m_default_color);
|
||||||
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
while (i < s.length()) {
|
while (i < s.length()) {
|
||||||
if (s[i] != L'\x1b') {
|
if (s[i] != L'\x1b') {
|
||||||
@ -90,6 +102,12 @@ void EnrichedString::addAtEnd(const std::wstring &s, const SColor &initial_color
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
parseColorString(wide_to_utf8(parts[1]), color, true);
|
parseColorString(wide_to_utf8(parts[1]), color, true);
|
||||||
|
|
||||||
|
// No longer use default color after first escape
|
||||||
|
if (use_default) {
|
||||||
|
m_default_length = m_string.size();
|
||||||
|
use_default = false;
|
||||||
|
}
|
||||||
} else if (parts[0] == L"b") {
|
} else if (parts[0] == L"b") {
|
||||||
if (parts.size() < 2) {
|
if (parts.size() < 2) {
|
||||||
continue;
|
continue;
|
||||||
@ -98,6 +116,10 @@ void EnrichedString::addAtEnd(const std::wstring &s, const SColor &initial_color
|
|||||||
m_has_background = true;
|
m_has_background = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update if no escape character was found
|
||||||
|
if (use_default)
|
||||||
|
m_default_length = m_string.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnrichedString::addChar(const EnrichedString &source, size_t i)
|
void EnrichedString::addChar(const EnrichedString &source, size_t i)
|
||||||
@ -110,7 +132,7 @@ void EnrichedString::addCharNoColor(wchar_t c)
|
|||||||
{
|
{
|
||||||
m_string += c;
|
m_string += c;
|
||||||
if (m_colors.empty()) {
|
if (m_colors.empty()) {
|
||||||
m_colors.emplace_back(255, 255, 255, 255);
|
m_colors.emplace_back(m_default_color);
|
||||||
} else {
|
} else {
|
||||||
m_colors.push_back(m_colors[m_colors.size() - 1]);
|
m_colors.push_back(m_colors[m_colors.size() - 1]);
|
||||||
}
|
}
|
||||||
@ -118,35 +140,40 @@ void EnrichedString::addCharNoColor(wchar_t c)
|
|||||||
|
|
||||||
EnrichedString EnrichedString::operator+(const EnrichedString &other) const
|
EnrichedString EnrichedString::operator+(const EnrichedString &other) const
|
||||||
{
|
{
|
||||||
std::vector<SColor> result;
|
EnrichedString result = *this;
|
||||||
result.insert(result.end(), m_colors.begin(), m_colors.end());
|
result += other;
|
||||||
result.insert(result.end(), other.m_colors.begin(), other.m_colors.end());
|
return result;
|
||||||
return EnrichedString(m_string + other.m_string, result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnrichedString::operator+=(const EnrichedString &other)
|
void EnrichedString::operator+=(const EnrichedString &other)
|
||||||
{
|
{
|
||||||
|
bool update_default_color = m_default_length == m_string.size();
|
||||||
|
|
||||||
m_string += other.m_string;
|
m_string += other.m_string;
|
||||||
m_colors.insert(m_colors.end(), other.m_colors.begin(), other.m_colors.end());
|
m_colors.insert(m_colors.end(), other.m_colors.begin(), other.m_colors.end());
|
||||||
|
|
||||||
|
if (update_default_color) {
|
||||||
|
m_default_length += other.m_default_length;
|
||||||
|
updateDefaultColor();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EnrichedString EnrichedString::substr(size_t pos, size_t len) const
|
EnrichedString EnrichedString::substr(size_t pos, size_t len) const
|
||||||
{
|
{
|
||||||
if (pos == m_string.length()) {
|
if (pos >= m_string.length())
|
||||||
return EnrichedString();
|
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())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return EnrichedString(
|
if (len == std::string::npos || pos + len > m_string.length())
|
||||||
|
len = m_string.length() - pos;
|
||||||
|
|
||||||
|
EnrichedString str(
|
||||||
m_string.substr(pos, len),
|
m_string.substr(pos, len),
|
||||||
std::vector<SColor>(m_colors.begin() + pos, m_colors.begin() + pos + len)
|
std::vector<SColor>(m_colors.begin() + pos, m_colors.begin() + pos + len)
|
||||||
);
|
);
|
||||||
|
if (pos < m_default_length)
|
||||||
|
str.m_default_length = m_default_length - pos;
|
||||||
|
str.setDefaultColor(m_default_color);
|
||||||
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
const wchar_t *EnrichedString::c_str() const
|
const wchar_t *EnrichedString::c_str() const
|
||||||
@ -163,3 +190,15 @@ const std::wstring &EnrichedString::getString() const
|
|||||||
{
|
{
|
||||||
return m_string;
|
return m_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EnrichedString::setDefaultColor(const irr::video::SColor &color)
|
||||||
|
{
|
||||||
|
m_default_color = color;
|
||||||
|
updateDefaultColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnrichedString::updateDefaultColor()
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < m_default_length; ++i)
|
||||||
|
m_colors[i] = m_default_color;
|
||||||
|
}
|
||||||
|
@ -32,6 +32,7 @@ public:
|
|||||||
const irr::video::SColor &color = irr::video::SColor(255, 255, 255, 255));
|
const irr::video::SColor &color = irr::video::SColor(255, 255, 255, 255));
|
||||||
EnrichedString(const std::wstring &string,
|
EnrichedString(const std::wstring &string,
|
||||||
const std::vector<irr::video::SColor> &colors);
|
const std::vector<irr::video::SColor> &colors);
|
||||||
|
void clear();
|
||||||
void operator=(const wchar_t *str);
|
void operator=(const wchar_t *str);
|
||||||
void addAtEnd(const std::wstring &s, const irr::video::SColor &color);
|
void addAtEnd(const std::wstring &s, const irr::video::SColor &color);
|
||||||
|
|
||||||
@ -50,6 +51,14 @@ public:
|
|||||||
const wchar_t *c_str() const;
|
const wchar_t *c_str() const;
|
||||||
const std::vector<irr::video::SColor> &getColors() const;
|
const std::vector<irr::video::SColor> &getColors() const;
|
||||||
const std::wstring &getString() const;
|
const std::wstring &getString() const;
|
||||||
|
|
||||||
|
void setDefaultColor(const irr::video::SColor &color);
|
||||||
|
void updateDefaultColor();
|
||||||
|
inline const irr::video::SColor &getDefaultColor() const
|
||||||
|
{
|
||||||
|
return m_default_color;
|
||||||
|
}
|
||||||
|
|
||||||
inline bool operator==(const EnrichedString &other) const
|
inline bool operator==(const EnrichedString &other) const
|
||||||
{
|
{
|
||||||
return (m_string == other.m_string && m_colors == other.m_colors);
|
return (m_string == other.m_string && m_colors == other.m_colors);
|
||||||
@ -58,12 +67,6 @@ public:
|
|||||||
{
|
{
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
inline void clear()
|
|
||||||
{
|
|
||||||
m_string.clear();
|
|
||||||
m_colors.clear();
|
|
||||||
m_has_background = false;
|
|
||||||
}
|
|
||||||
inline bool empty() const
|
inline bool empty() const
|
||||||
{
|
{
|
||||||
return m_string.empty();
|
return m_string.empty();
|
||||||
@ -72,6 +75,7 @@ public:
|
|||||||
{
|
{
|
||||||
return m_string.size();
|
return m_string.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool hasBackground() const
|
inline bool hasBackground() const
|
||||||
{
|
{
|
||||||
return m_has_background;
|
return m_has_background;
|
||||||
@ -80,9 +84,19 @@ public:
|
|||||||
{
|
{
|
||||||
return m_background;
|
return m_background;
|
||||||
}
|
}
|
||||||
|
inline void setBackground(const irr::video::SColor &color)
|
||||||
|
{
|
||||||
|
m_background = color;
|
||||||
|
m_has_background = true;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::wstring m_string;
|
std::wstring m_string;
|
||||||
std::vector<irr::video::SColor> m_colors;
|
std::vector<irr::video::SColor> m_colors;
|
||||||
bool m_has_background = false;
|
bool m_has_background;
|
||||||
|
irr::video::SColor m_default_color;
|
||||||
irr::video::SColor m_background;
|
irr::video::SColor m_background;
|
||||||
|
// This variable defines the length of the default-colored text.
|
||||||
|
// Change this to a std::vector if an "end coloring" tag is wanted.
|
||||||
|
size_t m_default_length;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user