mirror of
https://github.com/moparisthebest/minetest
synced 2024-11-15 05:45:13 -05:00
Add colored text (not only colored chat).
Add documentation, move files to a proper place and avoid memory leaks. Make it work with most kind of texts, and allow backgrounds too.
This commit is contained in:
parent
1d40385d4a
commit
14ef2b445a
@ -102,7 +102,7 @@ core.register_chatcommand("help", {
|
||||
description = "Get help for commands or list privileges",
|
||||
func = function(name, param)
|
||||
local function format_help_line(cmd, def)
|
||||
local msg = core.colorize("00ffff", "/"..cmd)
|
||||
local msg = core.colorize("#00ffff", "/"..cmd)
|
||||
if def.params and def.params ~= "" then
|
||||
msg = msg .. " " .. def.params
|
||||
end
|
||||
|
@ -198,19 +198,34 @@ function core.http_add_fetch(httpenv)
|
||||
return httpenv
|
||||
end
|
||||
|
||||
function core.get_color_escape_sequence(color)
|
||||
--if string.len(color) == 3 then
|
||||
-- local r = string.sub(color, 1, 1)
|
||||
-- local g = string.sub(color, 2, 2)
|
||||
-- local b = string.sub(color, 3, 3)
|
||||
-- color = r .. r .. g .. g .. b .. b
|
||||
--end
|
||||
if minetest.setting_getbool("disable_escape_sequences") then
|
||||
|
||||
function core.get_color_escape_sequence(color)
|
||||
return ""
|
||||
end
|
||||
|
||||
function core.get_background_escape_sequence(color)
|
||||
return ""
|
||||
end
|
||||
|
||||
function core.colorize(color, message)
|
||||
return message
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
local ESCAPE_CHAR = string.char(0x1b)
|
||||
function core.get_color_escape_sequence(color)
|
||||
return ESCAPE_CHAR .. "(c@" .. color .. ")"
|
||||
end
|
||||
|
||||
function core.get_background_escape_sequence(color)
|
||||
return ESCAPE_CHAR .. "(b@" .. color .. ")"
|
||||
end
|
||||
|
||||
function core.colorize(color, message)
|
||||
return core.get_color_escape_sequence(color) .. message .. core.get_color_escape_sequence("#ffffff")
|
||||
end
|
||||
|
||||
--assert(#color == 6, "Color must be six characters in length.")
|
||||
--return "\v" .. color
|
||||
return "\v(color;" .. color .. ")"
|
||||
end
|
||||
|
||||
function core.colorize(color, message)
|
||||
return core.get_color_escape_sequence(color) .. message .. core.get_color_escape_sequence("ffffff")
|
||||
end
|
||||
|
@ -615,6 +615,11 @@ server_announce (Announce server) bool false
|
||||
# If you want to announce your ipv6 address, use serverlist_url = v6.servers.minetest.net.
|
||||
serverlist_url (Serverlist URL) string servers.minetest.net
|
||||
|
||||
# Disable escape sequences, e.g. chat coloring.
|
||||
# Use this if you want to run a server with pre-0.4.14 clients and you want to disable
|
||||
# the escape sequences generated by mods.
|
||||
disable_escape_sequences (Disable escape sequences) bool false
|
||||
|
||||
[*Network]
|
||||
|
||||
# Network port to listen (UDP).
|
||||
|
@ -1701,6 +1701,24 @@ numerical form, the raw integer value of an ARGB8 quad:
|
||||
or string form, a ColorString (defined above):
|
||||
`colorspec = "green"`
|
||||
|
||||
Escape sequences
|
||||
----------------
|
||||
Most text can contain escape sequences, that can for example color the text.
|
||||
There are a few exceptions: tab headers, dropdowns and vertical labels can't.
|
||||
The following functions provide escape sequences:
|
||||
* `core.get_color_escape_sequence(color)`:
|
||||
* `color` is a ColorString
|
||||
* The escape sequence sets the text color to `color`
|
||||
* `core.colorize(color, message)`:
|
||||
* Equivalent to:
|
||||
`core.get_color_escape_sequence(color) ..
|
||||
message ..
|
||||
core.get_color_escape_sequence("#ffffff")`
|
||||
* `color.get_background_escape_sequence(color)`
|
||||
* `color` is a ColorString
|
||||
* The escape sequence sets the background of the whole text element to
|
||||
`color`. Only defined for item descriptions and tooltips.
|
||||
|
||||
Spatial Vectors
|
||||
---------------
|
||||
* `vector.new(a[, b, c])`: returns a vector:
|
||||
|
@ -376,6 +376,7 @@ add_subdirectory(network)
|
||||
add_subdirectory(script)
|
||||
add_subdirectory(unittest)
|
||||
add_subdirectory(util)
|
||||
add_subdirectory(irrlicht_changes)
|
||||
|
||||
set(common_SRCS
|
||||
ban.cpp
|
||||
@ -493,6 +494,7 @@ set(client_SRCS
|
||||
${common_SRCS}
|
||||
${sound_SRCS}
|
||||
${client_network_SRCS}
|
||||
${client_irrlicht_changes_SRCS}
|
||||
camera.cpp
|
||||
client.cpp
|
||||
clientmap.cpp
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
CGUITTFont FreeType class for Irrlicht
|
||||
Copyright (c) 2009-2010 John Norman
|
||||
Copyright (c) 2016 Nathanaël Courant
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -545,6 +546,13 @@ void CGUITTFont::setFontHinting(const bool enable, const bool enable_auto_hintin
|
||||
|
||||
void CGUITTFont::draw(const core::stringw& text, const core::rect<s32>& position, video::SColor color, bool hcenter, bool vcenter, const core::rect<s32>* clip)
|
||||
{
|
||||
draw(EnrichedString(std::wstring(text.c_str()), color), position, color, hcenter, vcenter, clip);
|
||||
}
|
||||
|
||||
void CGUITTFont::draw(const EnrichedString &text, const core::rect<s32>& position, video::SColor color, bool hcenter, bool vcenter, const core::rect<s32>* clip)
|
||||
{
|
||||
std::vector<video::SColor> colors = text.getColors();
|
||||
|
||||
if (!Driver)
|
||||
return;
|
||||
|
||||
@ -572,7 +580,7 @@ void CGUITTFont::draw(const core::stringw& text, const core::rect<s32>& position
|
||||
}
|
||||
|
||||
// Convert to a unicode string.
|
||||
core::ustring utext(text);
|
||||
core::ustring utext = text.getString();
|
||||
|
||||
// Set up our render map.
|
||||
core::map<u32, CGUITTGlyphPage*> Render_Map;
|
||||
@ -581,6 +589,7 @@ void CGUITTFont::draw(const core::stringw& text, const core::rect<s32>& position
|
||||
u32 n;
|
||||
uchar32_t previousChar = 0;
|
||||
core::ustring::const_iterator iter(utext);
|
||||
std::vector<video::SColor> applied_colors;
|
||||
while (!iter.atEnd())
|
||||
{
|
||||
uchar32_t currentChar = *iter;
|
||||
@ -590,7 +599,7 @@ void CGUITTFont::draw(const core::stringw& text, const core::rect<s32>& position
|
||||
if (currentChar == L'\r') // Mac or Windows breaks
|
||||
{
|
||||
lineBreak = true;
|
||||
if (*(iter + 1) == (uchar32_t)'\n') // Windows line breaks.
|
||||
if (*(iter + 1) == (uchar32_t)'\n') // Windows line breaks.
|
||||
currentChar = *(++iter);
|
||||
}
|
||||
else if (currentChar == (uchar32_t)'\n') // Unix breaks
|
||||
@ -627,6 +636,9 @@ void CGUITTFont::draw(const core::stringw& text, const core::rect<s32>& position
|
||||
page->render_positions.push_back(core::position2di(offset.X + offx, offset.Y + offy));
|
||||
page->render_source_rects.push_back(glyph.source_rect);
|
||||
Render_Map.set(glyph.glyph_page, page);
|
||||
u32 current_color = iter.getPos();
|
||||
if (current_color < colors.size())
|
||||
applied_colors.push_back(colors[current_color]);
|
||||
}
|
||||
offset.X += getWidthFromCharacter(currentChar);
|
||||
|
||||
@ -645,8 +657,6 @@ void CGUITTFont::draw(const core::stringw& text, const core::rect<s32>& position
|
||||
|
||||
CGUITTGlyphPage* page = n->getValue();
|
||||
|
||||
if (!use_transparency) color.color |= 0xff000000;
|
||||
|
||||
if (shadow_offset) {
|
||||
for (size_t i = 0; i < page->render_positions.size(); ++i)
|
||||
page->render_positions[i] += core::vector2di(shadow_offset, shadow_offset);
|
||||
@ -654,7 +664,17 @@ void CGUITTFont::draw(const core::stringw& text, const core::rect<s32>& position
|
||||
for (size_t i = 0; i < page->render_positions.size(); ++i)
|
||||
page->render_positions[i] -= core::vector2di(shadow_offset, shadow_offset);
|
||||
}
|
||||
Driver->draw2DImageBatch(page->texture, page->render_positions, page->render_source_rects, clip, color, true);
|
||||
for (size_t i = 0; i < page->render_positions.size(); ++i) {
|
||||
irr::video::SColor col;
|
||||
if (!applied_colors.empty()) {
|
||||
col = applied_colors[i < applied_colors.size() ? i : 0];
|
||||
} else {
|
||||
col = irr::video::SColor(255, 255, 255, 255);
|
||||
}
|
||||
if (!use_transparency)
|
||||
col.color |= 0xff000000;
|
||||
Driver->draw2DImage(page->texture, page->render_positions[i], page->render_source_rects[i], clip, col, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
CGUITTFont FreeType class for Irrlicht
|
||||
Copyright (c) 2009-2010 John Norman
|
||||
Copyright (c) 2016 Nathanaël Courant
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -33,6 +34,8 @@
|
||||
|
||||
#include <irrlicht.h>
|
||||
#include <ft2build.h>
|
||||
#include <vector>
|
||||
#include "util/enriched_string.h"
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
namespace irr
|
||||
@ -259,6 +262,10 @@ namespace gui
|
||||
video::SColor color, bool hcenter=false, bool vcenter=false,
|
||||
const core::rect<s32>* clip=0);
|
||||
|
||||
virtual void draw(const EnrichedString& text, const core::rect<s32>& position,
|
||||
video::SColor color, bool hcenter=false, bool vcenter=false,
|
||||
const core::rect<s32>* clip=0);
|
||||
|
||||
//! Returns the dimension of a character produced by this font.
|
||||
virtual core::dimension2d<u32> getCharDimension(const wchar_t ch) const;
|
||||
|
||||
|
37
src/chat.cpp
37
src/chat.cpp
@ -267,28 +267,26 @@ u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols,
|
||||
next_frags.push_back(temp_frag);
|
||||
}
|
||||
|
||||
std::wstring name_sanitized = removeEscapes(line.name);
|
||||
std::wstring name_sanitized = line.name.c_str();
|
||||
|
||||
// Choose an indentation level
|
||||
if (line.name.empty()) {
|
||||
// Server messages
|
||||
hanging_indentation = 0;
|
||||
}
|
||||
else if (name_sanitized.size() + 3 <= cols/2) {
|
||||
} else if (name_sanitized.size() + 3 <= cols/2) {
|
||||
// Names shorter than about half the console width
|
||||
hanging_indentation = line.name.size() + 3;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Very long names
|
||||
hanging_indentation = 2;
|
||||
}
|
||||
ColoredString line_text(line.text);
|
||||
//EnrichedString line_text(line.text);
|
||||
|
||||
next_line.first = true;
|
||||
bool text_processing = false;
|
||||
|
||||
// Produce fragments and layout them into lines
|
||||
while (!next_frags.empty() || in_pos < line_text.size())
|
||||
while (!next_frags.empty() || in_pos < line.text.size())
|
||||
{
|
||||
// Layout fragments into lines
|
||||
while (!next_frags.empty())
|
||||
@ -326,9 +324,9 @@ u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols,
|
||||
}
|
||||
|
||||
// Produce fragment
|
||||
if (in_pos < line_text.size())
|
||||
if (in_pos < line.text.size())
|
||||
{
|
||||
u32 remaining_in_input = line_text.size() - in_pos;
|
||||
u32 remaining_in_input = line.text.size() - in_pos;
|
||||
u32 remaining_in_output = cols - out_column;
|
||||
|
||||
// Determine a fragment length <= the minimum of
|
||||
@ -338,14 +336,14 @@ u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols,
|
||||
while (frag_length < remaining_in_input &&
|
||||
frag_length < remaining_in_output)
|
||||
{
|
||||
if (isspace(line_text[in_pos + frag_length]))
|
||||
if (isspace(line.text.getString()[in_pos + frag_length]))
|
||||
space_pos = frag_length;
|
||||
++frag_length;
|
||||
}
|
||||
if (space_pos != 0 && frag_length < remaining_in_input)
|
||||
frag_length = space_pos + 1;
|
||||
|
||||
temp_frag.text = line_text.substr(in_pos, frag_length);
|
||||
temp_frag.text = line.text.substr(in_pos, frag_length);
|
||||
temp_frag.column = 0;
|
||||
//temp_frag.bold = 0;
|
||||
next_frags.push_back(temp_frag);
|
||||
@ -729,19 +727,22 @@ ChatBuffer& ChatBackend::getRecentBuffer()
|
||||
return m_recent_buffer;
|
||||
}
|
||||
|
||||
std::wstring ChatBackend::getRecentChat()
|
||||
EnrichedString ChatBackend::getRecentChat()
|
||||
{
|
||||
std::wostringstream stream;
|
||||
EnrichedString result;
|
||||
for (u32 i = 0; i < m_recent_buffer.getLineCount(); ++i)
|
||||
{
|
||||
const ChatLine& line = m_recent_buffer.getLine(i);
|
||||
if (i != 0)
|
||||
stream << L"\n";
|
||||
if (!line.name.empty())
|
||||
stream << L"<" << line.name << L"> ";
|
||||
stream << line.text;
|
||||
result += L"\n";
|
||||
if (!line.name.empty()) {
|
||||
result += L"<";
|
||||
result += line.name;
|
||||
result += L"> ";
|
||||
}
|
||||
result += line.text;
|
||||
}
|
||||
return stream.str();
|
||||
return result;
|
||||
}
|
||||
|
||||
ChatPrompt& ChatBackend::getPrompt()
|
||||
|
17
src/chat.h
17
src/chat.h
@ -25,7 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include <list>
|
||||
|
||||
#include "irrlichttypes.h"
|
||||
#include "util/coloredstring.h"
|
||||
#include "util/enriched_string.h"
|
||||
|
||||
// Chat console related classes
|
||||
|
||||
@ -34,9 +34,9 @@ struct ChatLine
|
||||
// age in seconds
|
||||
f32 age;
|
||||
// name of sending player, or empty if sent by server
|
||||
std::wstring name;
|
||||
EnrichedString name;
|
||||
// message text
|
||||
ColoredString text;
|
||||
EnrichedString text;
|
||||
|
||||
ChatLine(std::wstring a_name, std::wstring a_text):
|
||||
age(0.0),
|
||||
@ -44,12 +44,19 @@ struct ChatLine
|
||||
text(a_text)
|
||||
{
|
||||
}
|
||||
|
||||
ChatLine(EnrichedString a_name, EnrichedString a_text):
|
||||
age(0.0),
|
||||
name(a_name),
|
||||
text(a_text)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct ChatFormattedFragment
|
||||
{
|
||||
// text string
|
||||
std::wstring text;
|
||||
EnrichedString text;
|
||||
// starting column
|
||||
u32 column;
|
||||
// formatting
|
||||
@ -262,7 +269,7 @@ public:
|
||||
// Get the recent messages buffer
|
||||
ChatBuffer& getRecentBuffer();
|
||||
// Concatenate all recent messages
|
||||
std::wstring getRecentChat();
|
||||
EnrichedString getRecentChat();
|
||||
// Get the console prompt
|
||||
ChatPrompt& getPrompt();
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
set(client_SRCS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/clientlauncher.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/guiChatConsole.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tile.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
@ -202,6 +202,8 @@ void set_default_settings(Settings *settings)
|
||||
settings->setDefault("server_name", "");
|
||||
settings->setDefault("server_description", "");
|
||||
|
||||
settings->setDefault("disable_escape_sequences", "false");
|
||||
|
||||
#if USE_FREETYPE
|
||||
settings->setDefault("freetype", "true");
|
||||
settings->setDefault("font_path", porting::getDataPath("fonts" DIR_DELIM "liberationsans.ttf"));
|
||||
|
53
src/game.cpp
53
src/game.cpp
@ -34,7 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "log.h"
|
||||
#include "filesys.h"
|
||||
#include "gettext.h"
|
||||
#include "client/guiChatConsole.h"
|
||||
#include "guiChatConsole.h"
|
||||
#include "guiFormSpecMenu.h"
|
||||
#include "guiKeyChangeMenu.h"
|
||||
#include "guiPasswordChange.h"
|
||||
@ -55,14 +55,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "tool.h"
|
||||
#include "util/directiontables.h"
|
||||
#include "util/pointedthing.h"
|
||||
#include "irrlicht_changes/static_text.h"
|
||||
#include "version.h"
|
||||
#include "minimap.h"
|
||||
#include "mapblock_mesh.h"
|
||||
|
||||
#if USE_FREETYPE
|
||||
#include "util/statictext.h"
|
||||
#endif
|
||||
|
||||
#include "sound.h"
|
||||
|
||||
#if USE_SOUND
|
||||
@ -541,7 +538,7 @@ void update_profiler_gui(gui::IGUIStaticText *guitext_profiler, FontEngine *fe,
|
||||
std::ostringstream os(std::ios_base::binary);
|
||||
g_profiler->printPage(os, show_profiler, show_profiler_max);
|
||||
std::wstring text = utf8_to_wide(os.str());
|
||||
guitext_profiler->setText(text.c_str());
|
||||
setStaticText(guitext_profiler, text.c_str());
|
||||
guitext_profiler->setVisible(true);
|
||||
|
||||
s32 w = fe->getTextWidth(text.c_str());
|
||||
@ -1244,7 +1241,11 @@ static void updateChat(Client &client, f32 dtime, bool show_debug,
|
||||
|
||||
// Get new messages from error log buffer
|
||||
while (!chat_log_error_buf.empty()) {
|
||||
chat_backend.addMessage(L"", utf8_to_wide(chat_log_error_buf.get()));
|
||||
std::wstring error_message = utf8_to_wide(chat_log_error_buf.get());
|
||||
if (!g_settings->getBool("disable_escape_sequences")) {
|
||||
error_message = L"\x1b(c@red)" + error_message + L"\x1b(c@white)";
|
||||
}
|
||||
chat_backend.addMessage(L"", error_message);
|
||||
}
|
||||
|
||||
// Get new messages from client
|
||||
@ -1259,10 +1260,10 @@ static void updateChat(Client &client, f32 dtime, bool show_debug,
|
||||
|
||||
// Display all messages in a static text element
|
||||
unsigned int recent_chat_count = chat_backend.getRecentBuffer().getLineCount();
|
||||
std::wstring recent_chat = chat_backend.getRecentChat();
|
||||
EnrichedString recent_chat = chat_backend.getRecentChat();
|
||||
unsigned int line_height = g_fontengine->getLineHeight();
|
||||
|
||||
guitext_chat->setText(recent_chat.c_str());
|
||||
setStaticText(guitext_chat, recent_chat);
|
||||
|
||||
// Update gui element size and position
|
||||
s32 chat_y = 5 + line_height;
|
||||
@ -1271,7 +1272,7 @@ static void updateChat(Client &client, f32 dtime, bool show_debug,
|
||||
chat_y += line_height;
|
||||
|
||||
// first pass to calculate height of text to be set
|
||||
s32 width = std::min(g_fontengine->getTextWidth(recent_chat) + 10,
|
||||
s32 width = std::min(g_fontengine->getTextWidth(recent_chat.c_str()) + 10,
|
||||
porting::getWindowSize().X - 20);
|
||||
core::rect<s32> rect(10, chat_y, width, chat_y + porting::getWindowSize().Y);
|
||||
guitext_chat->setRelativePosition(rect);
|
||||
@ -2218,45 +2219,39 @@ bool Game::createClient(const std::string &playername,
|
||||
bool Game::initGui()
|
||||
{
|
||||
// First line of debug text
|
||||
guitext = guienv->addStaticText(
|
||||
guitext = addStaticText(guienv,
|
||||
utf8_to_wide(PROJECT_NAME_C).c_str(),
|
||||
core::rect<s32>(0, 0, 0, 0),
|
||||
false, false, guiroot);
|
||||
|
||||
// Second line of debug text
|
||||
guitext2 = guienv->addStaticText(
|
||||
guitext2 = addStaticText(guienv,
|
||||
L"",
|
||||
core::rect<s32>(0, 0, 0, 0),
|
||||
false, false, guiroot);
|
||||
|
||||
// At the middle of the screen
|
||||
// Object infos are shown in this
|
||||
guitext_info = guienv->addStaticText(
|
||||
guitext_info = addStaticText(guienv,
|
||||
L"",
|
||||
core::rect<s32>(0, 0, 400, g_fontengine->getTextHeight() * 5 + 5) + v2s32(100, 200),
|
||||
false, true, guiroot);
|
||||
|
||||
// Status text (displays info when showing and hiding GUI stuff, etc.)
|
||||
guitext_status = guienv->addStaticText(
|
||||
guitext_status = addStaticText(guienv,
|
||||
L"<Status>",
|
||||
core::rect<s32>(0, 0, 0, 0),
|
||||
false, false, guiroot);
|
||||
guitext_status->setVisible(false);
|
||||
|
||||
#if USE_FREETYPE
|
||||
// Colored chat support when using FreeType
|
||||
guitext_chat = new gui::StaticText(L"", false, guienv, guiroot, -1, core::rect<s32>(0, 0, 0, 0), false);
|
||||
guitext_chat->setWordWrap(true);
|
||||
guitext_chat->drop();
|
||||
#else
|
||||
// Standard chat when FreeType is disabled
|
||||
// Chat text
|
||||
guitext_chat = guienv->addStaticText(
|
||||
guitext_chat = addStaticText(
|
||||
guienv,
|
||||
L"",
|
||||
core::rect<s32>(0, 0, 0, 0),
|
||||
//false, false); // Disable word wrap as of now
|
||||
false, true, guiroot);
|
||||
#endif
|
||||
|
||||
// Remove stale "recent" chat messages from previous connections
|
||||
chat_backend->clearRecentChat();
|
||||
|
||||
@ -2270,7 +2265,7 @@ bool Game::initGui()
|
||||
}
|
||||
|
||||
// Profiler text (size is updated when text is updated)
|
||||
guitext_profiler = guienv->addStaticText(
|
||||
guitext_profiler = addStaticText(guienv,
|
||||
L"<Profiler>",
|
||||
core::rect<s32>(0, 0, 0, 0),
|
||||
false, false, guiroot);
|
||||
@ -4308,12 +4303,12 @@ void Game::updateGui(float *statustext_time, const RunStats &stats,
|
||||
<< ", v_range = " << draw_control->wanted_range
|
||||
<< std::setprecision(3)
|
||||
<< ", RTT = " << client->getRTT();
|
||||
guitext->setText(utf8_to_wide(os.str()).c_str());
|
||||
setStaticText(guitext, utf8_to_wide(os.str()).c_str());
|
||||
guitext->setVisible(true);
|
||||
} else if (flags.show_hud || flags.show_chat) {
|
||||
std::ostringstream os(std::ios_base::binary);
|
||||
os << PROJECT_NAME_C " " << g_version_hash;
|
||||
guitext->setText(utf8_to_wide(os.str()).c_str());
|
||||
setStaticText(guitext, utf8_to_wide(os.str()).c_str());
|
||||
guitext->setVisible(true);
|
||||
} else {
|
||||
guitext->setVisible(false);
|
||||
@ -4350,7 +4345,7 @@ void Game::updateGui(float *statustext_time, const RunStats &stats,
|
||||
}
|
||||
}
|
||||
|
||||
guitext2->setText(utf8_to_wide(os.str()).c_str());
|
||||
setStaticText(guitext2, utf8_to_wide(os.str()).c_str());
|
||||
guitext2->setVisible(true);
|
||||
|
||||
core::rect<s32> rect(
|
||||
@ -4362,7 +4357,7 @@ void Game::updateGui(float *statustext_time, const RunStats &stats,
|
||||
guitext2->setVisible(false);
|
||||
}
|
||||
|
||||
guitext_info->setText(infotext.c_str());
|
||||
setStaticText(guitext_info, infotext.c_str());
|
||||
guitext_info->setVisible(flags.show_hud && g_menumgr.menuCount() == 0);
|
||||
|
||||
float statustext_time_max = 1.5;
|
||||
@ -4376,7 +4371,7 @@ void Game::updateGui(float *statustext_time, const RunStats &stats,
|
||||
}
|
||||
}
|
||||
|
||||
guitext_status->setText(statustext.c_str());
|
||||
setStaticText(guitext_status, statustext.c_str());
|
||||
guitext_status->setVisible(!statustext.empty());
|
||||
|
||||
if (!statustext.empty()) {
|
||||
|
@ -346,9 +346,9 @@ void GUIChatConsole::drawText()
|
||||
// Draw colored text if FreeType is enabled
|
||||
irr::gui::CGUITTFont *tmp = static_cast<irr::gui::CGUITTFont*>(m_font);
|
||||
tmp->draw(
|
||||
fragment.text.c_str(),
|
||||
fragment.text,
|
||||
destrect,
|
||||
fragment.text.getColors(),
|
||||
video::SColor(255, 255, 255, 255),
|
||||
false,
|
||||
false,
|
||||
&AbsoluteClippingRect);
|
@ -37,6 +37,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "log.h"
|
||||
#include "fontengine.h"
|
||||
#include "guiscalingfilter.h"
|
||||
#include "irrlicht_changes/static_text.h"
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include "client/tile.h"
|
||||
@ -172,15 +173,16 @@ GUIEngine::GUIEngine( irr::IrrlichtDevice* dev,
|
||||
m_sound_manager = &dummySoundManager;
|
||||
|
||||
//create topleft header
|
||||
std::wstring t = utf8_to_wide(std::string(PROJECT_NAME_C " ") +
|
||||
m_toplefttext = utf8_to_wide(std::string(PROJECT_NAME_C " ") +
|
||||
g_version_hash);
|
||||
|
||||
core::rect<s32> rect(0, 0, g_fontengine->getTextWidth(t), g_fontengine->getTextHeight());
|
||||
core::rect<s32> rect(0, 0, g_fontengine->getTextWidth(m_toplefttext.c_str()),
|
||||
g_fontengine->getTextHeight());
|
||||
rect += v2s32(4, 0);
|
||||
|
||||
m_irr_toplefttext =
|
||||
m_device->getGUIEnvironment()->addStaticText(t.c_str(),
|
||||
rect,false,true,0,-1);
|
||||
addStaticText(m_device->getGUIEnvironment(), m_toplefttext,
|
||||
rect, false, true, 0, -1);
|
||||
|
||||
//create formspecsource
|
||||
m_formspecgui = new FormspecFormSource("");
|
||||
@ -578,7 +580,7 @@ void GUIEngine::setTopleftText(std::string append)
|
||||
toset += utf8_to_wide(append);
|
||||
}
|
||||
|
||||
m_irr_toplefttext->setText(toset.c_str());
|
||||
m_toplefttext = toset;
|
||||
|
||||
updateTopLeftTextSize();
|
||||
}
|
||||
@ -586,15 +588,14 @@ void GUIEngine::setTopleftText(std::string append)
|
||||
/******************************************************************************/
|
||||
void GUIEngine::updateTopLeftTextSize()
|
||||
{
|
||||
std::wstring text = m_irr_toplefttext->getText();
|
||||
|
||||
core::rect<s32> rect(0, 0, g_fontengine->getTextWidth(text), g_fontengine->getTextHeight());
|
||||
rect += v2s32(4, 0);
|
||||
core::rect<s32> rect(0, 0, g_fontengine->getTextWidth(m_toplefttext.c_str()),
|
||||
g_fontengine->getTextHeight());
|
||||
rect += v2s32(4, 0);
|
||||
|
||||
m_irr_toplefttext->remove();
|
||||
m_irr_toplefttext =
|
||||
m_device->getGUIEnvironment()->addStaticText(text.c_str(),
|
||||
rect,false,true,0,-1);
|
||||
addStaticText(m_device->getGUIEnvironment(), m_toplefttext,
|
||||
rect, false, true, 0, -1);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "guiFormSpecMenu.h"
|
||||
#include "sound.h"
|
||||
#include "client/tile.h"
|
||||
#include "util/enriched_string.h"
|
||||
|
||||
/******************************************************************************/
|
||||
/* Typedefs and macros */
|
||||
@ -275,6 +276,8 @@ private:
|
||||
|
||||
/** pointer to gui element shown at topleft corner */
|
||||
irr::gui::IGUIStaticText* m_irr_toplefttext;
|
||||
/** and text that is in it */
|
||||
EnrichedString m_toplefttext;
|
||||
|
||||
/** initialize cloud subsystem */
|
||||
void cloudInit();
|
||||
|
@ -50,6 +50,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "util/hex.h"
|
||||
#include "util/numeric.h"
|
||||
#include "util/string.h" // for parseColorString()
|
||||
#include "irrlicht_changes/static_text.h"
|
||||
#include "guiscalingfilter.h"
|
||||
|
||||
#if USE_FREETYPE && IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 9
|
||||
@ -249,37 +250,6 @@ std::vector<std::string>* GUIFormSpecMenu::getDropDownValues(const std::string &
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static std::vector<std::string> split(const std::string &s, char delim)
|
||||
{
|
||||
std::vector<std::string> tokens;
|
||||
|
||||
std::string current = "";
|
||||
bool last_was_escape = false;
|
||||
for (unsigned int i = 0; i < s.size(); i++) {
|
||||
char si = s.c_str()[i];
|
||||
if (last_was_escape) {
|
||||
current += '\\';
|
||||
current += si;
|
||||
last_was_escape = false;
|
||||
} else {
|
||||
if (si == delim) {
|
||||
tokens.push_back(current);
|
||||
current = "";
|
||||
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;
|
||||
}
|
||||
|
||||
void GUIFormSpecMenu::parseSize(parserData* data,std::string element)
|
||||
{
|
||||
std::vector<std::string> parts = split(element,',');
|
||||
@ -966,7 +936,7 @@ void GUIFormSpecMenu::parsePwdField(parserData* data,std::string element)
|
||||
int font_height = g_fontengine->getTextHeight();
|
||||
rect.UpperLeftCorner.Y -= font_height;
|
||||
rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + font_height;
|
||||
Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, 0);
|
||||
addStaticText(Environment, spec.flabel.c_str(), rect, false, true, this, 0);
|
||||
}
|
||||
|
||||
e->setPasswordBox(true,L'*');
|
||||
@ -1021,7 +991,7 @@ void GUIFormSpecMenu::parseSimpleField(parserData* data,
|
||||
if (name == "")
|
||||
{
|
||||
// spec field id to 0, this stops submit searching for a value that isn't there
|
||||
Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, spec.fid);
|
||||
addStaticText(Environment, spec.flabel.c_str(), rect, false, true, this, spec.fid);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1056,7 +1026,7 @@ void GUIFormSpecMenu::parseSimpleField(parserData* data,
|
||||
int font_height = g_fontengine->getTextHeight();
|
||||
rect.UpperLeftCorner.Y -= font_height;
|
||||
rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + font_height;
|
||||
Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, 0);
|
||||
addStaticText(Environment, spec.flabel.c_str(), rect, false, true, this, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1117,7 +1087,7 @@ void GUIFormSpecMenu::parseTextArea(parserData* data,
|
||||
if (name == "")
|
||||
{
|
||||
// spec field id to 0, this stops submit searching for a value that isn't there
|
||||
Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, spec.fid);
|
||||
addStaticText(Environment, spec.flabel.c_str(), rect, false, true, this, spec.fid);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1161,7 +1131,7 @@ void GUIFormSpecMenu::parseTextArea(parserData* data,
|
||||
int font_height = g_fontengine->getTextHeight();
|
||||
rect.UpperLeftCorner.Y -= font_height;
|
||||
rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + font_height;
|
||||
Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, 0);
|
||||
addStaticText(Environment, spec.flabel.c_str(), rect, false, true, this, 0);
|
||||
}
|
||||
}
|
||||
m_fields.push_back(spec);
|
||||
@ -1230,7 +1200,7 @@ void GUIFormSpecMenu::parseLabel(parserData* data,std::string element)
|
||||
258+m_fields.size()
|
||||
);
|
||||
gui::IGUIStaticText *e =
|
||||
Environment->addStaticText(spec.flabel.c_str(),
|
||||
addStaticText(Environment, spec.flabel.c_str(),
|
||||
rect, false, false, this, spec.fid);
|
||||
e->setTextAlignment(gui::EGUIA_UPPERLEFT,
|
||||
gui::EGUIA_CENTER);
|
||||
@ -1284,7 +1254,7 @@ void GUIFormSpecMenu::parseVertLabel(parserData* data,std::string element)
|
||||
258+m_fields.size()
|
||||
);
|
||||
gui::IGUIStaticText *t =
|
||||
Environment->addStaticText(spec.flabel.c_str(), rect, false, false, this, spec.fid);
|
||||
addStaticText(Environment, spec.flabel.c_str(), rect, false, false, this, spec.fid);
|
||||
t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
|
||||
m_fields.push_back(spec);
|
||||
return;
|
||||
@ -1910,7 +1880,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
||||
{
|
||||
assert(m_tooltip_element == NULL);
|
||||
// Note: parent != this so that the tooltip isn't clipped by the menu rectangle
|
||||
m_tooltip_element = Environment->addStaticText(L"",core::rect<s32>(0,0,110,18));
|
||||
m_tooltip_element = addStaticText(Environment, L"",core::rect<s32>(0,0,110,18));
|
||||
m_tooltip_element->enableOverrideColor(true);
|
||||
m_tooltip_element->setBackgroundColor(m_default_tooltip_bgcolor);
|
||||
m_tooltip_element->setDrawBackground(true);
|
||||
@ -2255,7 +2225,6 @@ void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase,
|
||||
std::wstring tooltip_text = L"";
|
||||
if (hovering && !m_selected_item) {
|
||||
tooltip_text = utf8_to_wide(item.getDefinition(m_gamedef->idef()).description);
|
||||
tooltip_text = unescape_enriched(tooltip_text);
|
||||
}
|
||||
if (tooltip_text != L"") {
|
||||
std::vector<std::wstring> tt_rows = str_split(tooltip_text, L'\n');
|
||||
@ -2263,7 +2232,7 @@ void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase,
|
||||
m_tooltip_element->setOverrideColor(m_default_tooltip_color);
|
||||
m_tooltip_element->setVisible(true);
|
||||
this->bringToFront(m_tooltip_element);
|
||||
m_tooltip_element->setText(tooltip_text.c_str());
|
||||
setStaticText(m_tooltip_element, tooltip_text.c_str());
|
||||
s32 tooltip_width = m_tooltip_element->getTextWidth() + m_btn_height;
|
||||
#if IRRLICHT_VERSION_MAJOR <= 1 && IRRLICHT_VERSION_MINOR <= 8 && IRRLICHT_VERSION_REVISION < 2
|
||||
s32 tooltip_height = m_tooltip_element->getTextHeight() * tt_rows.size() + 5;
|
||||
@ -2535,8 +2504,10 @@ void GUIFormSpecMenu::drawMenu()
|
||||
iter != m_fields.end(); ++iter) {
|
||||
if (iter->fid == id && m_tooltips[iter->fname].tooltip != L"") {
|
||||
if (m_old_tooltip != m_tooltips[iter->fname].tooltip) {
|
||||
m_tooltip_element->setBackgroundColor(m_tooltips[iter->fname].bgcolor);
|
||||
m_tooltip_element->setOverrideColor(m_tooltips[iter->fname].color);
|
||||
m_old_tooltip = m_tooltips[iter->fname].tooltip;
|
||||
m_tooltip_element->setText(m_tooltips[iter->fname].tooltip.c_str());
|
||||
setStaticText(m_tooltip_element, m_tooltips[iter->fname].tooltip.c_str());
|
||||
std::vector<std::wstring> tt_rows = str_split(m_tooltips[iter->fname].tooltip, L'\n');
|
||||
s32 tooltip_width = m_tooltip_element->getTextWidth() + m_btn_height;
|
||||
s32 tooltip_height = m_tooltip_element->getTextHeight() * tt_rows.size() + 5;
|
||||
@ -2558,8 +2529,6 @@ void GUIFormSpecMenu::drawMenu()
|
||||
core::position2d<s32>(tooltip_x, tooltip_y),
|
||||
core::dimension2d<s32>(tooltip_width, tooltip_height)));
|
||||
}
|
||||
m_tooltip_element->setBackgroundColor(m_tooltips[iter->fname].bgcolor);
|
||||
m_tooltip_element->setOverrideColor(m_tooltips[iter->fname].color);
|
||||
m_tooltip_element->setVisible(true);
|
||||
this->bringToFront(m_tooltip_element);
|
||||
break;
|
||||
@ -2568,6 +2537,8 @@ void GUIFormSpecMenu::drawMenu()
|
||||
}
|
||||
}
|
||||
|
||||
m_tooltip_element->draw();
|
||||
|
||||
/*
|
||||
Draw dragged item stack
|
||||
*/
|
||||
|
@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "guiTable.h"
|
||||
#include "network/networkprotocol.h"
|
||||
#include "util/string.h"
|
||||
#include "util/enriched_string.h"
|
||||
|
||||
class IGameDef;
|
||||
class InventoryManager;
|
||||
@ -202,7 +203,8 @@ class GUIFormSpecMenu : public GUIModalMenu
|
||||
fname(name),
|
||||
fid(id)
|
||||
{
|
||||
flabel = unescape_enriched(label);
|
||||
//flabel = unescape_enriched(label);
|
||||
flabel = label;
|
||||
fdefault = unescape_enriched(default_text);
|
||||
send = false;
|
||||
ftype = f_Unknown;
|
||||
@ -239,7 +241,8 @@ class GUIFormSpecMenu : public GUIModalMenu
|
||||
bgcolor(a_bgcolor),
|
||||
color(a_color)
|
||||
{
|
||||
tooltip = unescape_enriched(utf8_to_wide(a_tooltip));
|
||||
//tooltip = unescape_enriched(utf8_to_wide(a_tooltip));
|
||||
tooltip = utf8_to_wide(a_tooltip);
|
||||
}
|
||||
std::wstring tooltip;
|
||||
irr::video::SColor bgcolor;
|
||||
@ -256,7 +259,8 @@ class GUIFormSpecMenu : public GUIModalMenu
|
||||
rect(a_rect),
|
||||
parent_button(NULL)
|
||||
{
|
||||
text = unescape_enriched(a_text);
|
||||
//text = unescape_enriched(a_text);
|
||||
text = a_text;
|
||||
}
|
||||
StaticTextSpec(const std::wstring &a_text,
|
||||
const core::rect<s32> &a_rect,
|
||||
@ -264,7 +268,8 @@ class GUIFormSpecMenu : public GUIModalMenu
|
||||
rect(a_rect),
|
||||
parent_button(a_parent_button)
|
||||
{
|
||||
text = unescape_enriched(a_text);
|
||||
//text = unescape_enriched(a_text);
|
||||
text = a_text;
|
||||
}
|
||||
std::wstring text;
|
||||
core::rect<s32> rect;
|
||||
|
7
src/irrlicht_changes/CMakeLists.txt
Normal file
7
src/irrlicht_changes/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
if (BUILD_CLIENT)
|
||||
set(client_irrlicht_changes_SRCS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/static_text.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
endif()
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
@ -345,9 +345,11 @@ void TerminalChatConsole::step(int ch)
|
||||
if (p.first > m_log_level)
|
||||
continue;
|
||||
|
||||
m_chat_backend.addMessage(
|
||||
utf8_to_wide(Logger::getLevelLabel(p.first)),
|
||||
utf8_to_wide(p.second));
|
||||
std::wstring error_message = utf8_to_wide(Logger::getLevelLabel(p.first));
|
||||
if (!g_settings->getBool("disable_escape_sequences")) {
|
||||
error_message = L"\x1b(c@red)" + error_message + L"\x1b(c@white)";
|
||||
}
|
||||
m_chat_backend.addMessage(error_message, utf8_to_wide(p.second));
|
||||
}
|
||||
|
||||
// handle input
|
||||
@ -438,7 +440,7 @@ void TerminalChatConsole::draw_text()
|
||||
continue;
|
||||
for (u32 i = 0; i < line.fragments.size(); ++i) {
|
||||
const ChatFormattedFragment& fragment = line.fragments[i];
|
||||
addstr(wide_to_utf8(fragment.text).c_str());
|
||||
addstr(wide_to_utf8(fragment.text.getString()).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
166
src/util/enriched_string.cpp
Normal file
166
src/util/enriched_string.cpp
Normal file
@ -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;
|
||||
}
|
91
src/util/enriched_string.h
Normal file
91
src/util/enriched_string.h
Normal file
@ -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
|
@ -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.
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user