Skip to content

Commit 14ef2b4

Browse files
committedMay 31, 2016
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.
1 parent 1d40385 commit 14ef2b4

28 files changed

+690
-319
lines changed
 

‎builtin/game/chatcommands.lua

+1-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ core.register_chatcommand("help", {
102102
description = "Get help for commands or list privileges",
103103
func = function(name, param)
104104
local function format_help_line(cmd, def)
105-
local msg = core.colorize("00ffff", "/"..cmd)
105+
local msg = core.colorize("#00ffff", "/"..cmd)
106106
if def.params and def.params ~= "" then
107107
msg = msg .. " " .. def.params
108108
end

‎builtin/game/misc.lua

+29-14
Original file line numberDiff line numberDiff line change
@@ -198,19 +198,34 @@ function core.http_add_fetch(httpenv)
198198
return httpenv
199199
end
200200

201-
function core.get_color_escape_sequence(color)
202-
--if string.len(color) == 3 then
203-
-- local r = string.sub(color, 1, 1)
204-
-- local g = string.sub(color, 2, 2)
205-
-- local b = string.sub(color, 3, 3)
206-
-- color = r .. r .. g .. g .. b .. b
207-
--end
208-
209-
--assert(#color == 6, "Color must be six characters in length.")
210-
--return "\v" .. color
211-
return "\v(color;" .. color .. ")"
212-
end
201+
if minetest.setting_getbool("disable_escape_sequences") then
202+
203+
function core.get_color_escape_sequence(color)
204+
return ""
205+
end
206+
207+
function core.get_background_escape_sequence(color)
208+
return ""
209+
end
210+
211+
function core.colorize(color, message)
212+
return message
213+
end
214+
215+
else
216+
217+
local ESCAPE_CHAR = string.char(0x1b)
218+
function core.get_color_escape_sequence(color)
219+
return ESCAPE_CHAR .. "(c@" .. color .. ")"
220+
end
221+
222+
function core.get_background_escape_sequence(color)
223+
return ESCAPE_CHAR .. "(b@" .. color .. ")"
224+
end
225+
226+
function core.colorize(color, message)
227+
return core.get_color_escape_sequence(color) .. message .. core.get_color_escape_sequence("#ffffff")
228+
end
213229

214-
function core.colorize(color, message)
215-
return core.get_color_escape_sequence(color) .. message .. core.get_color_escape_sequence("ffffff")
216230
end
231+

‎builtin/settingtypes.txt

+5
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,11 @@ server_announce (Announce server) bool false
615615
# If you want to announce your ipv6 address, use serverlist_url = v6.servers.minetest.net.
616616
serverlist_url (Serverlist URL) string servers.minetest.net
617617

618+
# Disable escape sequences, e.g. chat coloring.
619+
# Use this if you want to run a server with pre-0.4.14 clients and you want to disable
620+
# the escape sequences generated by mods.
621+
disable_escape_sequences (Disable escape sequences) bool false
622+
618623
[*Network]
619624

620625
# Network port to listen (UDP).

‎doc/lua_api.txt

+18
Original file line numberDiff line numberDiff line change
@@ -1701,6 +1701,24 @@ numerical form, the raw integer value of an ARGB8 quad:
17011701
or string form, a ColorString (defined above):
17021702
`colorspec = "green"`
17031703

1704+
Escape sequences
1705+
----------------
1706+
Most text can contain escape sequences, that can for example color the text.
1707+
There are a few exceptions: tab headers, dropdowns and vertical labels can't.
1708+
The following functions provide escape sequences:
1709+
* `core.get_color_escape_sequence(color)`:
1710+
* `color` is a ColorString
1711+
* The escape sequence sets the text color to `color`
1712+
* `core.colorize(color, message)`:
1713+
* Equivalent to:
1714+
`core.get_color_escape_sequence(color) ..
1715+
message ..
1716+
core.get_color_escape_sequence("#ffffff")`
1717+
* `color.get_background_escape_sequence(color)`
1718+
* `color` is a ColorString
1719+
* The escape sequence sets the background of the whole text element to
1720+
`color`. Only defined for item descriptions and tooltips.
1721+
17041722
Spatial Vectors
17051723
---------------
17061724
* `vector.new(a[, b, c])`: returns a vector:

‎src/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ add_subdirectory(network)
376376
add_subdirectory(script)
377377
add_subdirectory(unittest)
378378
add_subdirectory(util)
379+
add_subdirectory(irrlicht_changes)
379380

380381
set(common_SRCS
381382
ban.cpp
@@ -493,6 +494,7 @@ set(client_SRCS
493494
${common_SRCS}
494495
${sound_SRCS}
495496
${client_network_SRCS}
497+
${client_irrlicht_changes_SRCS}
496498
camera.cpp
497499
client.cpp
498500
clientmap.cpp

‎src/cguittfont/CGUITTFont.cpp

+25-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*
22
CGUITTFont FreeType class for Irrlicht
33
Copyright (c) 2009-2010 John Norman
4+
Copyright (c) 2016 Nathanaël Courant
45
56
This software is provided 'as-is', without any express or implied
67
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
545546

546547
void CGUITTFont::draw(const core::stringw& text, const core::rect<s32>& position, video::SColor color, bool hcenter, bool vcenter, const core::rect<s32>* clip)
547548
{
549+
draw(EnrichedString(std::wstring(text.c_str()), color), position, color, hcenter, vcenter, clip);
550+
}
551+
552+
void CGUITTFont::draw(const EnrichedString &text, const core::rect<s32>& position, video::SColor color, bool hcenter, bool vcenter, const core::rect<s32>* clip)
553+
{
554+
std::vector<video::SColor> colors = text.getColors();
555+
548556
if (!Driver)
549557
return;
550558

@@ -572,7 +580,7 @@ void CGUITTFont::draw(const core::stringw& text, const core::rect<s32>& position
572580
}
573581

574582
// Convert to a unicode string.
575-
core::ustring utext(text);
583+
core::ustring utext = text.getString();
576584

577585
// Set up our render map.
578586
core::map<u32, CGUITTGlyphPage*> Render_Map;
@@ -581,6 +589,7 @@ void CGUITTFont::draw(const core::stringw& text, const core::rect<s32>& position
581589
u32 n;
582590
uchar32_t previousChar = 0;
583591
core::ustring::const_iterator iter(utext);
592+
std::vector<video::SColor> applied_colors;
584593
while (!iter.atEnd())
585594
{
586595
uchar32_t currentChar = *iter;
@@ -590,7 +599,7 @@ void CGUITTFont::draw(const core::stringw& text, const core::rect<s32>& position
590599
if (currentChar == L'\r') // Mac or Windows breaks
591600
{
592601
lineBreak = true;
593-
if (*(iter + 1) == (uchar32_t)'\n') // Windows line breaks.
602+
if (*(iter + 1) == (uchar32_t)'\n') // Windows line breaks.
594603
currentChar = *(++iter);
595604
}
596605
else if (currentChar == (uchar32_t)'\n') // Unix breaks
@@ -627,6 +636,9 @@ void CGUITTFont::draw(const core::stringw& text, const core::rect<s32>& position
627636
page->render_positions.push_back(core::position2di(offset.X + offx, offset.Y + offy));
628637
page->render_source_rects.push_back(glyph.source_rect);
629638
Render_Map.set(glyph.glyph_page, page);
639+
u32 current_color = iter.getPos();
640+
if (current_color < colors.size())
641+
applied_colors.push_back(colors[current_color]);
630642
}
631643
offset.X += getWidthFromCharacter(currentChar);
632644

@@ -645,16 +657,24 @@ void CGUITTFont::draw(const core::stringw& text, const core::rect<s32>& position
645657

646658
CGUITTGlyphPage* page = n->getValue();
647659

648-
if (!use_transparency) color.color |= 0xff000000;
649-
650660
if (shadow_offset) {
651661
for (size_t i = 0; i < page->render_positions.size(); ++i)
652662
page->render_positions[i] += core::vector2di(shadow_offset, shadow_offset);
653663
Driver->draw2DImageBatch(page->texture, page->render_positions, page->render_source_rects, clip, video::SColor(shadow_alpha,0,0,0), true);
654664
for (size_t i = 0; i < page->render_positions.size(); ++i)
655665
page->render_positions[i] -= core::vector2di(shadow_offset, shadow_offset);
656666
}
657-
Driver->draw2DImageBatch(page->texture, page->render_positions, page->render_source_rects, clip, color, true);
667+
for (size_t i = 0; i < page->render_positions.size(); ++i) {
668+
irr::video::SColor col;
669+
if (!applied_colors.empty()) {
670+
col = applied_colors[i < applied_colors.size() ? i : 0];
671+
} else {
672+
col = irr::video::SColor(255, 255, 255, 255);
673+
}
674+
if (!use_transparency)
675+
col.color |= 0xff000000;
676+
Driver->draw2DImage(page->texture, page->render_positions[i], page->render_source_rects[i], clip, col, true);
677+
}
658678
}
659679
}
660680

‎src/cguittfont/CGUITTFont.h

+7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*
22
CGUITTFont FreeType class for Irrlicht
33
Copyright (c) 2009-2010 John Norman
4+
Copyright (c) 2016 Nathanaël Courant
45
56
This software is provided 'as-is', without any express or implied
67
warranty. In no event will the authors be held liable for any
@@ -33,6 +34,8 @@
3334

3435
#include <irrlicht.h>
3536
#include <ft2build.h>
37+
#include <vector>
38+
#include "util/enriched_string.h"
3639
#include FT_FREETYPE_H
3740

3841
namespace irr
@@ -258,6 +261,10 @@ namespace gui
258261
virtual void draw(const core::stringw& text, const core::rect<s32>& position,
259262
video::SColor color, bool hcenter=false, bool vcenter=false,
260263
const core::rect<s32>* clip=0);
264+
265+
virtual void draw(const EnrichedString& text, const core::rect<s32>& position,
266+
video::SColor color, bool hcenter=false, bool vcenter=false,
267+
const core::rect<s32>* clip=0);
261268

262269
//! Returns the dimension of a character produced by this font.
263270
virtual core::dimension2d<u32> getCharDimension(const wchar_t ch) const;

‎src/chat.cpp

+19-18
Original file line numberDiff line numberDiff line change
@@ -267,28 +267,26 @@ u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols,
267267
next_frags.push_back(temp_frag);
268268
}
269269

270-
std::wstring name_sanitized = removeEscapes(line.name);
270+
std::wstring name_sanitized = line.name.c_str();
271271

272272
// Choose an indentation level
273273
if (line.name.empty()) {
274274
// Server messages
275275
hanging_indentation = 0;
276-
}
277-
else if (name_sanitized.size() + 3 <= cols/2) {
276+
} else if (name_sanitized.size() + 3 <= cols/2) {
278277
// Names shorter than about half the console width
279278
hanging_indentation = line.name.size() + 3;
280-
}
281-
else {
279+
} else {
282280
// Very long names
283281
hanging_indentation = 2;
284282
}
285-
ColoredString line_text(line.text);
283+
//EnrichedString line_text(line.text);
286284

287285
next_line.first = true;
288286
bool text_processing = false;
289287

290288
// Produce fragments and layout them into lines
291-
while (!next_frags.empty() || in_pos < line_text.size())
289+
while (!next_frags.empty() || in_pos < line.text.size())
292290
{
293291
// Layout fragments into lines
294292
while (!next_frags.empty())
@@ -326,9 +324,9 @@ u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols,
326324
}
327325

328326
// Produce fragment
329-
if (in_pos < line_text.size())
327+
if (in_pos < line.text.size())
330328
{
331-
u32 remaining_in_input = line_text.size() - in_pos;
329+
u32 remaining_in_input = line.text.size() - in_pos;
332330
u32 remaining_in_output = cols - out_column;
333331

334332
// Determine a fragment length <= the minimum of
@@ -338,14 +336,14 @@ u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols,
338336
while (frag_length < remaining_in_input &&
339337
frag_length < remaining_in_output)
340338
{
341-
if (isspace(line_text[in_pos + frag_length]))
339+
if (isspace(line.text.getString()[in_pos + frag_length]))
342340
space_pos = frag_length;
343341
++frag_length;
344342
}
345343
if (space_pos != 0 && frag_length < remaining_in_input)
346344
frag_length = space_pos + 1;
347345

348-
temp_frag.text = line_text.substr(in_pos, frag_length);
346+
temp_frag.text = line.text.substr(in_pos, frag_length);
349347
temp_frag.column = 0;
350348
//temp_frag.bold = 0;
351349
next_frags.push_back(temp_frag);
@@ -729,19 +727,22 @@ ChatBuffer& ChatBackend::getRecentBuffer()
729727
return m_recent_buffer;
730728
}
731729

732-
std::wstring ChatBackend::getRecentChat()
730+
EnrichedString ChatBackend::getRecentChat()
733731
{
734-
std::wostringstream stream;
732+
EnrichedString result;
735733
for (u32 i = 0; i < m_recent_buffer.getLineCount(); ++i)
736734
{
737735
const ChatLine& line = m_recent_buffer.getLine(i);
738736
if (i != 0)
739-
stream << L"\n";
740-
if (!line.name.empty())
741-
stream << L"<" << line.name << L"> ";
742-
stream << line.text;
737+
result += L"\n";
738+
if (!line.name.empty()) {
739+
result += L"<";
740+
result += line.name;
741+
result += L"> ";
742+
}
743+
result += line.text;
743744
}
744-
return stream.str();
745+
return result;
745746
}
746747

747748
ChatPrompt& ChatBackend::getPrompt()

‎src/chat.h

+12-5
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
2525
#include <list>
2626

2727
#include "irrlichttypes.h"
28-
#include "util/coloredstring.h"
28+
#include "util/enriched_string.h"
2929

3030
// Chat console related classes
3131

@@ -34,22 +34,29 @@ struct ChatLine
3434
// age in seconds
3535
f32 age;
3636
// name of sending player, or empty if sent by server
37-
std::wstring name;
37+
EnrichedString name;
3838
// message text
39-
ColoredString text;
39+
EnrichedString text;
4040

4141
ChatLine(std::wstring a_name, std::wstring a_text):
4242
age(0.0),
4343
name(a_name),
4444
text(a_text)
4545
{
4646
}
47+
48+
ChatLine(EnrichedString a_name, EnrichedString a_text):
49+
age(0.0),
50+
name(a_name),
51+
text(a_text)
52+
{
53+
}
4754
};
4855

4956
struct ChatFormattedFragment
5057
{
5158
// text string
52-
std::wstring text;
59+
EnrichedString text;
5360
// starting column
5461
u32 column;
5562
// formatting
@@ -262,7 +269,7 @@ class ChatBackend
262269
// Get the recent messages buffer
263270
ChatBuffer& getRecentBuffer();
264271
// Concatenate all recent messages
265-
std::wstring getRecentChat();
272+
EnrichedString getRecentChat();
266273
// Get the console prompt
267274
ChatPrompt& getPrompt();
268275

‎src/client/CMakeLists.txt

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
set(client_SRCS
22
${CMAKE_CURRENT_SOURCE_DIR}/clientlauncher.cpp
3-
${CMAKE_CURRENT_SOURCE_DIR}/guiChatConsole.cpp
43
${CMAKE_CURRENT_SOURCE_DIR}/tile.cpp
54
PARENT_SCOPE
65
)

‎src/defaultsettings.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ void set_default_settings(Settings *settings)
202202
settings->setDefault("server_name", "");
203203
settings->setDefault("server_description", "");
204204

205+
settings->setDefault("disable_escape_sequences", "false");
206+
205207
#if USE_FREETYPE
206208
settings->setDefault("freetype", "true");
207209
settings->setDefault("font_path", porting::getDataPath("fonts" DIR_DELIM "liberationsans.ttf"));

0 commit comments

Comments
 (0)
Please sign in to comment.