Add documentation, move files to a proper place and avoid memory leaks.
Make it work with most kind of texts, and allow backgrounds too.
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
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
-
- --assert(#color == 6, "Color must be six characters in length.")
- --return "\v" .. color
- return "\v(color;" .. color .. ")"
-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
-function core.colorize(color, message)
- return core.get_color_escape_sequence(color) .. message .. core.get_color_escape_sequence("ffffff")
end
+
# 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).
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:
add_subdirectory(script)
add_subdirectory(unittest)
add_subdirectory(util)
+add_subdirectory(irrlicht_changes)
set(common_SRCS
ban.cpp
${common_SRCS}
${sound_SRCS}
${client_network_SRCS}
+ ${client_irrlicht_changes_SRCS}
camera.cpp
client.cpp
clientmap.cpp
/*
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
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;
}
// 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;
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;
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
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);
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);
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);
+ }
}
}
/*
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
#include <irrlicht.h>
#include <ft2build.h>
+#include <vector>
+#include "util/enriched_string.h"
#include FT_FREETYPE_H
namespace irr
virtual void draw(const core::stringw& text, const core::rect<s32>& position,
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;
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())
}
// 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
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);
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()
#include <list>
#include "irrlichttypes.h"
-#include "util/coloredstring.h"
+#include "util/enriched_string.h"
// Chat console related classes
// 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),
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
// Get the recent messages buffer
ChatBuffer& getRecentBuffer();
// Concatenate all recent messages
- std::wstring getRecentChat();
+ EnrichedString getRecentChat();
// Get the console prompt
ChatPrompt& getPrompt();
set(client_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/clientlauncher.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/guiChatConsole.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tile.cpp
PARENT_SCOPE
)
+++ /dev/null
-/*
-Minetest
-Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
-
-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 "guiChatConsole.h"
-#include "chat.h"
-#include "client.h"
-#include "debug.h"
-#include "gettime.h"
-#include "keycode.h"
-#include "settings.h"
-#include "porting.h"
-#include "client/tile.h"
-#include "fontengine.h"
-#include "log.h"
-#include "gettext.h"
-#include <string>
-
-#if USE_FREETYPE
- #include "xCGUITTFont.h"
-#endif
-
-inline u32 clamp_u8(s32 value)
-{
- return (u32) MYMIN(MYMAX(value, 0), 255);
-}
-
-
-GUIChatConsole::GUIChatConsole(
- gui::IGUIEnvironment* env,
- gui::IGUIElement* parent,
- s32 id,
- ChatBackend* backend,
- Client* client,
- IMenuManager* menumgr
-):
- IGUIElement(gui::EGUIET_ELEMENT, env, parent, id,
- core::rect<s32>(0,0,100,100)),
- m_chat_backend(backend),
- m_client(client),
- m_menumgr(menumgr),
- m_screensize(v2u32(0,0)),
- m_animate_time_old(0),
- m_open(false),
- m_close_on_enter(false),
- m_height(0),
- m_desired_height(0),
- m_desired_height_fraction(0.0),
- m_height_speed(5.0),
- m_open_inhibited(0),
- m_cursor_blink(0.0),
- m_cursor_blink_speed(0.0),
- m_cursor_height(0.0),
- m_background(NULL),
- m_background_color(255, 0, 0, 0),
- m_font(NULL),
- m_fontsize(0, 0)
-{
- m_animate_time_old = getTimeMs();
-
- // load background settings
- s32 console_alpha = g_settings->getS32("console_alpha");
- m_background_color.setAlpha(clamp_u8(console_alpha));
-
- // load the background texture depending on settings
- ITextureSource *tsrc = client->getTextureSource();
- if (tsrc->isKnownSourceImage("background_chat.jpg")) {
- m_background = tsrc->getTexture("background_chat.jpg");
- m_background_color.setRed(255);
- m_background_color.setGreen(255);
- m_background_color.setBlue(255);
- } else {
- v3f console_color = g_settings->getV3F("console_color");
- m_background_color.setRed(clamp_u8(myround(console_color.X)));
- m_background_color.setGreen(clamp_u8(myround(console_color.Y)));
- m_background_color.setBlue(clamp_u8(myround(console_color.Z)));
- }
-
- m_font = g_fontengine->getFont(FONT_SIZE_UNSPECIFIED, FM_Mono);
-
- if (m_font == NULL)
- {
- errorstream << "GUIChatConsole: Unable to load mono font ";
- }
- else
- {
- core::dimension2d<u32> dim = m_font->getDimension(L"M");
- m_fontsize = v2u32(dim.Width, dim.Height);
- m_font->grab();
- }
- m_fontsize.X = MYMAX(m_fontsize.X, 1);
- m_fontsize.Y = MYMAX(m_fontsize.Y, 1);
-
- // set default cursor options
- setCursor(true, true, 2.0, 0.1);
-}
-
-GUIChatConsole::~GUIChatConsole()
-{
- if (m_font)
- m_font->drop();
-}
-
-void GUIChatConsole::openConsole(f32 height)
-{
- m_open = true;
- m_desired_height_fraction = height;
- m_desired_height = height * m_screensize.Y;
- reformatConsole();
- m_animate_time_old = getTimeMs();
- IGUIElement::setVisible(true);
- Environment->setFocus(this);
- m_menumgr->createdMenu(this);
-}
-
-bool GUIChatConsole::isOpen() const
-{
- return m_open;
-}
-
-bool GUIChatConsole::isOpenInhibited() const
-{
- return m_open_inhibited > 0;
-}
-
-void GUIChatConsole::closeConsole()
-{
- m_open = false;
- Environment->removeFocus(this);
- m_menumgr->deletingMenu(this);
-}
-
-void GUIChatConsole::closeConsoleAtOnce()
-{
- closeConsole();
- m_height = 0;
- recalculateConsolePosition();
-}
-
-f32 GUIChatConsole::getDesiredHeight() const
-{
- return m_desired_height_fraction;
-}
-
-void GUIChatConsole::replaceAndAddToHistory(std::wstring line)
-{
- ChatPrompt& prompt = m_chat_backend->getPrompt();
- prompt.addToHistory(prompt.getLine());
- prompt.replace(line);
-}
-
-
-void GUIChatConsole::setCursor(
- bool visible, bool blinking, f32 blink_speed, f32 relative_height)
-{
- if (visible)
- {
- if (blinking)
- {
- // leave m_cursor_blink unchanged
- m_cursor_blink_speed = blink_speed;
- }
- else
- {
- m_cursor_blink = 0x8000; // on
- m_cursor_blink_speed = 0.0;
- }
- }
- else
- {
- m_cursor_blink = 0; // off
- m_cursor_blink_speed = 0.0;
- }
- m_cursor_height = relative_height;
-}
-
-void GUIChatConsole::draw()
-{
- if(!IsVisible)
- return;
-
- video::IVideoDriver* driver = Environment->getVideoDriver();
-
- // Check screen size
- v2u32 screensize = driver->getScreenSize();
- if (screensize != m_screensize)
- {
- // screen size has changed
- // scale current console height to new window size
- if (m_screensize.Y != 0)
- m_height = m_height * screensize.Y / m_screensize.Y;
- m_desired_height = m_desired_height_fraction * m_screensize.Y;
- m_screensize = screensize;
- reformatConsole();
- }
-
- // Animation
- u32 now = getTimeMs();
- animate(now - m_animate_time_old);
- m_animate_time_old = now;
-
- // Draw console elements if visible
- if (m_height > 0)
- {
- drawBackground();
- drawText();
- drawPrompt();
- }
-
- gui::IGUIElement::draw();
-}
-
-void GUIChatConsole::reformatConsole()
-{
- s32 cols = m_screensize.X / m_fontsize.X - 2; // make room for a margin (looks better)
- s32 rows = m_desired_height / m_fontsize.Y - 1; // make room for the input prompt
- if (cols <= 0 || rows <= 0)
- cols = rows = 0;
- m_chat_backend->reformat(cols, rows);
-}
-
-void GUIChatConsole::recalculateConsolePosition()
-{
- core::rect<s32> rect(0, 0, m_screensize.X, m_height);
- DesiredRect = rect;
- recalculateAbsolutePosition(false);
-}
-
-void GUIChatConsole::animate(u32 msec)
-{
- // animate the console height
- s32 goal = m_open ? m_desired_height : 0;
-
- // Set invisible if close animation finished (reset by openConsole)
- // This function (animate()) is never called once its visibility becomes false so do not
- // actually set visible to false before the inhibited period is over
- if (!m_open && m_height == 0 && m_open_inhibited == 0)
- IGUIElement::setVisible(false);
-
- if (m_height != goal)
- {
- s32 max_change = msec * m_screensize.Y * (m_height_speed / 1000.0);
- if (max_change == 0)
- max_change = 1;
-
- if (m_height < goal)
- {
- // increase height
- if (m_height + max_change < goal)
- m_height += max_change;
- else
- m_height = goal;
- }
- else
- {
- // decrease height
- if (m_height > goal + max_change)
- m_height -= max_change;
- else
- m_height = goal;
- }
-
- recalculateConsolePosition();
- }
-
- // blink the cursor
- if (m_cursor_blink_speed != 0.0)
- {
- u32 blink_increase = 0x10000 * msec * (m_cursor_blink_speed / 1000.0);
- if (blink_increase == 0)
- blink_increase = 1;
- m_cursor_blink = ((m_cursor_blink + blink_increase) & 0xffff);
- }
-
- // decrease open inhibit counter
- if (m_open_inhibited > msec)
- m_open_inhibited -= msec;
- else
- m_open_inhibited = 0;
-}
-
-void GUIChatConsole::drawBackground()
-{
- video::IVideoDriver* driver = Environment->getVideoDriver();
- if (m_background != NULL)
- {
- core::rect<s32> sourcerect(0, -m_height, m_screensize.X, 0);
- driver->draw2DImage(
- m_background,
- v2s32(0, 0),
- sourcerect,
- &AbsoluteClippingRect,
- m_background_color,
- false);
- }
- else
- {
- driver->draw2DRectangle(
- m_background_color,
- core::rect<s32>(0, 0, m_screensize.X, m_height),
- &AbsoluteClippingRect);
- }
-}
-
-void GUIChatConsole::drawText()
-{
- if (m_font == NULL)
- return;
-
- ChatBuffer& buf = m_chat_backend->getConsoleBuffer();
- for (u32 row = 0; row < buf.getRows(); ++row)
- {
- const ChatFormattedLine& line = buf.getFormattedLine(row);
- if (line.fragments.empty())
- continue;
-
- s32 line_height = m_fontsize.Y;
- s32 y = row * line_height + m_height - m_desired_height;
- if (y + line_height < 0)
- continue;
-
- for (u32 i = 0; i < line.fragments.size(); ++i)
- {
- const ChatFormattedFragment& fragment = line.fragments[i];
- s32 x = (fragment.column + 1) * m_fontsize.X;
- core::rect<s32> destrect(
- x, y, x + m_fontsize.X * fragment.text.size(), y + m_fontsize.Y);
-
-
- #if USE_FREETYPE
- // Draw colored text if FreeType is enabled
- irr::gui::CGUITTFont *tmp = static_cast<irr::gui::CGUITTFont*>(m_font);
- tmp->draw(
- fragment.text.c_str(),
- destrect,
- fragment.text.getColors(),
- false,
- false,
- &AbsoluteClippingRect);
- #else
- // Otherwise use standard text
- m_font->draw(
- fragment.text.c_str(),
- destrect,
- video::SColor(255, 255, 255, 255),
- false,
- false,
- &AbsoluteClippingRect);
- #endif
- }
- }
-}
-
-void GUIChatConsole::drawPrompt()
-{
- if (m_font == NULL)
- return;
-
- u32 row = m_chat_backend->getConsoleBuffer().getRows();
- s32 line_height = m_fontsize.Y;
- s32 y = row * line_height + m_height - m_desired_height;
-
- ChatPrompt& prompt = m_chat_backend->getPrompt();
- std::wstring prompt_text = prompt.getVisiblePortion();
-
- // FIXME Draw string at once, not character by character
- // That will only work with the cursor once we have a monospace font
- for (u32 i = 0; i < prompt_text.size(); ++i)
- {
- wchar_t ws[2] = {prompt_text[i], 0};
- s32 x = (1 + i) * m_fontsize.X;
- core::rect<s32> destrect(
- x, y, x + m_fontsize.X, y + m_fontsize.Y);
- m_font->draw(
- ws,
- destrect,
- video::SColor(255, 255, 255, 255),
- false,
- false,
- &AbsoluteClippingRect);
- }
-
- // Draw the cursor during on periods
- if ((m_cursor_blink & 0x8000) != 0)
- {
- s32 cursor_pos = prompt.getVisibleCursorPosition();
- if (cursor_pos >= 0)
- {
- s32 cursor_len = prompt.getCursorLength();
- video::IVideoDriver* driver = Environment->getVideoDriver();
- s32 x = (1 + cursor_pos) * m_fontsize.X;
- core::rect<s32> destrect(
- x,
- y + m_fontsize.Y * (1.0 - m_cursor_height),
- x + m_fontsize.X * MYMAX(cursor_len, 1),
- y + m_fontsize.Y * (cursor_len ? m_cursor_height+1 : 1)
- );
- video::SColor cursor_color(255,255,255,255);
- driver->draw2DRectangle(
- cursor_color,
- destrect,
- &AbsoluteClippingRect);
- }
- }
-
-}
-
-bool GUIChatConsole::OnEvent(const SEvent& event)
-{
-
- ChatPrompt &prompt = m_chat_backend->getPrompt();
-
- if(event.EventType == EET_KEY_INPUT_EVENT && event.KeyInput.PressedDown)
- {
- // Key input
- if(KeyPress(event.KeyInput) == getKeySetting("keymap_console"))
- {
- closeConsole();
-
- // inhibit open so the_game doesn't reopen immediately
- m_open_inhibited = 50;
- m_close_on_enter = false;
- return true;
- }
- else if(event.KeyInput.Key == KEY_ESCAPE)
- {
- closeConsoleAtOnce();
- m_close_on_enter = false;
- // inhibit open so the_game doesn't reopen immediately
- m_open_inhibited = 1; // so the ESCAPE button doesn't open the "pause menu"
- return true;
- }
- else if(event.KeyInput.Key == KEY_PRIOR)
- {
- m_chat_backend->scrollPageUp();
- return true;
- }
- else if(event.KeyInput.Key == KEY_NEXT)
- {
- m_chat_backend->scrollPageDown();
- return true;
- }
- else if(event.KeyInput.Key == KEY_RETURN)
- {
- prompt.addToHistory(prompt.getLine());
- std::wstring text = prompt.replace(L"");
- m_client->typeChatMessage(text);
- if (m_close_on_enter) {
- closeConsoleAtOnce();
- m_close_on_enter = false;
- }
- return true;
- }
- else if(event.KeyInput.Key == KEY_UP)
- {
- // Up pressed
- // Move back in history
- prompt.historyPrev();
- return true;
- }
- else if(event.KeyInput.Key == KEY_DOWN)
- {
- // Down pressed
- // Move forward in history
- prompt.historyNext();
- return true;
- }
- else if(event.KeyInput.Key == KEY_LEFT || event.KeyInput.Key == KEY_RIGHT)
- {
- // Left/right pressed
- // Move/select character/word to the left depending on control and shift keys
- ChatPrompt::CursorOp op = event.KeyInput.Shift ?
- ChatPrompt::CURSOROP_SELECT :
- ChatPrompt::CURSOROP_MOVE;
- ChatPrompt::CursorOpDir dir = event.KeyInput.Key == KEY_LEFT ?
- ChatPrompt::CURSOROP_DIR_LEFT :
- ChatPrompt::CURSOROP_DIR_RIGHT;
- ChatPrompt::CursorOpScope scope = event.KeyInput.Control ?
- ChatPrompt::CURSOROP_SCOPE_WORD :
- ChatPrompt::CURSOROP_SCOPE_CHARACTER;
- prompt.cursorOperation(op, dir, scope);
- return true;
- }
- else if(event.KeyInput.Key == KEY_HOME)
- {
- // Home pressed
- // move to beginning of line
- prompt.cursorOperation(
- ChatPrompt::CURSOROP_MOVE,
- ChatPrompt::CURSOROP_DIR_LEFT,
- ChatPrompt::CURSOROP_SCOPE_LINE);
- return true;
- }
- else if(event.KeyInput.Key == KEY_END)
- {
- // End pressed
- // move to end of line
- prompt.cursorOperation(
- ChatPrompt::CURSOROP_MOVE,
- ChatPrompt::CURSOROP_DIR_RIGHT,
- ChatPrompt::CURSOROP_SCOPE_LINE);
- return true;
- }
- else if(event.KeyInput.Key == KEY_BACK)
- {
- // Backspace or Ctrl-Backspace pressed
- // delete character / word to the left
- ChatPrompt::CursorOpScope scope =
- event.KeyInput.Control ?
- ChatPrompt::CURSOROP_SCOPE_WORD :
- ChatPrompt::CURSOROP_SCOPE_CHARACTER;
- prompt.cursorOperation(
- ChatPrompt::CURSOROP_DELETE,
- ChatPrompt::CURSOROP_DIR_LEFT,
- scope);
- return true;
- }
- else if(event.KeyInput.Key == KEY_DELETE)
- {
- // Delete or Ctrl-Delete pressed
- // delete character / word to the right
- ChatPrompt::CursorOpScope scope =
- event.KeyInput.Control ?
- ChatPrompt::CURSOROP_SCOPE_WORD :
- ChatPrompt::CURSOROP_SCOPE_CHARACTER;
- prompt.cursorOperation(
- ChatPrompt::CURSOROP_DELETE,
- ChatPrompt::CURSOROP_DIR_RIGHT,
- scope);
- return true;
- }
- else if(event.KeyInput.Key == KEY_KEY_A && event.KeyInput.Control)
- {
- // Ctrl-A pressed
- // Select all text
- prompt.cursorOperation(
- ChatPrompt::CURSOROP_SELECT,
- ChatPrompt::CURSOROP_DIR_LEFT, // Ignored
- ChatPrompt::CURSOROP_SCOPE_LINE);
- return true;
- }
- else if(event.KeyInput.Key == KEY_KEY_C && event.KeyInput.Control)
- {
- // Ctrl-C pressed
- // Copy text to clipboard
- if (prompt.getCursorLength() <= 0)
- return true;
- std::wstring wselected = prompt.getSelection();
- std::string selected(wselected.begin(), wselected.end());
- Environment->getOSOperator()->copyToClipboard(selected.c_str());
- return true;
- }
- else if(event.KeyInput.Key == KEY_KEY_V && event.KeyInput.Control)
- {
- // Ctrl-V pressed
- // paste text from clipboard
- if (prompt.getCursorLength() > 0) {
- // Delete selected section of text
- prompt.cursorOperation(
- ChatPrompt::CURSOROP_DELETE,
- ChatPrompt::CURSOROP_DIR_LEFT, // Ignored
- ChatPrompt::CURSOROP_SCOPE_SELECTION);
- }
- IOSOperator *os_operator = Environment->getOSOperator();
- const c8 *text = os_operator->getTextFromClipboard();
- if (!text)
- return true;
- std::basic_string<unsigned char> str((const unsigned char*)text);
- prompt.input(std::wstring(str.begin(), str.end()));
- return true;
- }
- else if(event.KeyInput.Key == KEY_KEY_X && event.KeyInput.Control)
- {
- // Ctrl-X pressed
- // Cut text to clipboard
- if (prompt.getCursorLength() <= 0)
- return true;
- std::wstring wselected = prompt.getSelection();
- std::string selected(wselected.begin(), wselected.end());
- Environment->getOSOperator()->copyToClipboard(selected.c_str());
- prompt.cursorOperation(
- ChatPrompt::CURSOROP_DELETE,
- ChatPrompt::CURSOROP_DIR_LEFT, // Ignored
- ChatPrompt::CURSOROP_SCOPE_SELECTION);
- return true;
- }
- else if(event.KeyInput.Key == KEY_KEY_U && event.KeyInput.Control)
- {
- // Ctrl-U pressed
- // kill line to left end
- prompt.cursorOperation(
- ChatPrompt::CURSOROP_DELETE,
- ChatPrompt::CURSOROP_DIR_LEFT,
- ChatPrompt::CURSOROP_SCOPE_LINE);
- return true;
- }
- else if(event.KeyInput.Key == KEY_KEY_K && event.KeyInput.Control)
- {
- // Ctrl-K pressed
- // kill line to right end
- prompt.cursorOperation(
- ChatPrompt::CURSOROP_DELETE,
- ChatPrompt::CURSOROP_DIR_RIGHT,
- ChatPrompt::CURSOROP_SCOPE_LINE);
- return true;
- }
- else if(event.KeyInput.Key == KEY_TAB)
- {
- // Tab or Shift-Tab pressed
- // Nick completion
- std::list<std::string> names = m_client->getConnectedPlayerNames();
- bool backwards = event.KeyInput.Shift;
- prompt.nickCompletion(names, backwards);
- return true;
- }
- else if(event.KeyInput.Char != 0 && !event.KeyInput.Control)
- {
- #if (defined(linux) || defined(__linux))
- wchar_t wc = L'_';
- mbtowc( &wc, (char *) &event.KeyInput.Char, sizeof(event.KeyInput.Char) );
- prompt.input(wc);
- #else
- prompt.input(event.KeyInput.Char);
- #endif
- return true;
- }
- }
- else if(event.EventType == EET_MOUSE_INPUT_EVENT)
- {
- if(event.MouseInput.Event == EMIE_MOUSE_WHEEL)
- {
- s32 rows = myround(-3.0 * event.MouseInput.Wheel);
- m_chat_backend->scroll(rows);
- }
- }
-
- return Parent ? Parent->OnEvent(event) : false;
-}
-
-void GUIChatConsole::setVisible(bool visible)
-{
- m_open = visible;
- IGUIElement::setVisible(visible);
- if (!visible) {
- m_height = 0;
- recalculateConsolePosition();
- }
-}
-
+++ /dev/null
-/*
-Minetest
-Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
-
-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 GUICHATCONSOLE_HEADER
-#define GUICHATCONSOLE_HEADER
-
-#include "irrlichttypes_extrabloated.h"
-#include "modalMenu.h"
-#include "chat.h"
-#include "config.h"
-
-class Client;
-
-class GUIChatConsole : public gui::IGUIElement
-{
-public:
- GUIChatConsole(gui::IGUIEnvironment* env,
- gui::IGUIElement* parent,
- s32 id,
- ChatBackend* backend,
- Client* client,
- IMenuManager* menumgr);
- virtual ~GUIChatConsole();
-
- // Open the console (height = desired fraction of screen size)
- // This doesn't open immediately but initiates an animation.
- // You should call isOpenInhibited() before this.
- void openConsole(f32 height);
-
- bool isOpen() const;
-
- // Check if the console should not be opened at the moment
- // This is to avoid reopening the console immediately after closing
- bool isOpenInhibited() const;
- // Close the console, equivalent to openConsole(0).
- // This doesn't close immediately but initiates an animation.
- void closeConsole();
- // Close the console immediately, without animation.
- void closeConsoleAtOnce();
- // Set whether to close the console after the user presses enter.
- void setCloseOnEnter(bool close) { m_close_on_enter = close; }
-
- // Return the desired height (fraction of screen size)
- // Zero if the console is closed or getting closed
- f32 getDesiredHeight() const;
-
- // Replace actual line when adding the actual to the history (if there is any)
- void replaceAndAddToHistory(std::wstring line);
-
- // Change how the cursor looks
- void setCursor(
- bool visible,
- bool blinking = false,
- f32 blink_speed = 1.0,
- f32 relative_height = 1.0);
-
- // Irrlicht draw method
- virtual void draw();
-
- bool canTakeFocus(gui::IGUIElement* element) { return false; }
-
- virtual bool OnEvent(const SEvent& event);
-
- virtual void setVisible(bool visible);
-
-private:
- void reformatConsole();
- void recalculateConsolePosition();
-
- // These methods are called by draw
- void animate(u32 msec);
- void drawBackground();
- void drawText();
- void drawPrompt();
-
-private:
- ChatBackend* m_chat_backend;
- Client* m_client;
- IMenuManager* m_menumgr;
-
- // current screen size
- v2u32 m_screensize;
-
- // used to compute how much time passed since last animate()
- u32 m_animate_time_old;
-
- // should the console be opened or closed?
- bool m_open;
- // should it close after you press enter?
- bool m_close_on_enter;
- // current console height [pixels]
- s32 m_height;
- // desired height [pixels]
- f32 m_desired_height;
- // desired height [screen height fraction]
- f32 m_desired_height_fraction;
- // console open/close animation speed [screen height fraction / second]
- f32 m_height_speed;
- // if nonzero, opening the console is inhibited [milliseconds]
- u32 m_open_inhibited;
-
- // cursor blink frame (16-bit value)
- // cursor is off during [0,32767] and on during [32768,65535]
- u32 m_cursor_blink;
- // cursor blink speed [on/off toggles / second]
- f32 m_cursor_blink_speed;
- // cursor height [line height]
- f32 m_cursor_height;
-
- // background texture
- video::ITexture* m_background;
- // background color (including alpha)
- video::SColor m_background_color;
-
- // font
- gui::IGUIFont* m_font;
- v2u32 m_fontsize;
-};
-
-
-#endif
-
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"));
#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"
#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
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());
// 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
// 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;
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);
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();
}
// 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);
<< ", 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);
}
}
- 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(
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;
}
}
- guitext_status->setText(statustext.c_str());
+ setStaticText(guitext_status, statustext.c_str());
guitext_status->setVisible(!statustext.empty());
if (!statustext.empty()) {
--- /dev/null
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+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 "guiChatConsole.h"
+#include "chat.h"
+#include "client.h"
+#include "debug.h"
+#include "gettime.h"
+#include "keycode.h"
+#include "settings.h"
+#include "porting.h"
+#include "client/tile.h"
+#include "fontengine.h"
+#include "log.h"
+#include "gettext.h"
+#include <string>
+
+#if USE_FREETYPE
+ #include "xCGUITTFont.h"
+#endif
+
+inline u32 clamp_u8(s32 value)
+{
+ return (u32) MYMIN(MYMAX(value, 0), 255);
+}
+
+
+GUIChatConsole::GUIChatConsole(
+ gui::IGUIEnvironment* env,
+ gui::IGUIElement* parent,
+ s32 id,
+ ChatBackend* backend,
+ Client* client,
+ IMenuManager* menumgr
+):
+ IGUIElement(gui::EGUIET_ELEMENT, env, parent, id,
+ core::rect<s32>(0,0,100,100)),
+ m_chat_backend(backend),
+ m_client(client),
+ m_menumgr(menumgr),
+ m_screensize(v2u32(0,0)),
+ m_animate_time_old(0),
+ m_open(false),
+ m_close_on_enter(false),
+ m_height(0),
+ m_desired_height(0),
+ m_desired_height_fraction(0.0),
+ m_height_speed(5.0),
+ m_open_inhibited(0),
+ m_cursor_blink(0.0),
+ m_cursor_blink_speed(0.0),
+ m_cursor_height(0.0),
+ m_background(NULL),
+ m_background_color(255, 0, 0, 0),
+ m_font(NULL),
+ m_fontsize(0, 0)
+{
+ m_animate_time_old = getTimeMs();
+
+ // load background settings
+ s32 console_alpha = g_settings->getS32("console_alpha");
+ m_background_color.setAlpha(clamp_u8(console_alpha));
+
+ // load the background texture depending on settings
+ ITextureSource *tsrc = client->getTextureSource();
+ if (tsrc->isKnownSourceImage("background_chat.jpg")) {
+ m_background = tsrc->getTexture("background_chat.jpg");
+ m_background_color.setRed(255);
+ m_background_color.setGreen(255);
+ m_background_color.setBlue(255);
+ } else {
+ v3f console_color = g_settings->getV3F("console_color");
+ m_background_color.setRed(clamp_u8(myround(console_color.X)));
+ m_background_color.setGreen(clamp_u8(myround(console_color.Y)));
+ m_background_color.setBlue(clamp_u8(myround(console_color.Z)));
+ }
+
+ m_font = g_fontengine->getFont(FONT_SIZE_UNSPECIFIED, FM_Mono);
+
+ if (m_font == NULL)
+ {
+ errorstream << "GUIChatConsole: Unable to load mono font ";
+ }
+ else
+ {
+ core::dimension2d<u32> dim = m_font->getDimension(L"M");
+ m_fontsize = v2u32(dim.Width, dim.Height);
+ m_font->grab();
+ }
+ m_fontsize.X = MYMAX(m_fontsize.X, 1);
+ m_fontsize.Y = MYMAX(m_fontsize.Y, 1);
+
+ // set default cursor options
+ setCursor(true, true, 2.0, 0.1);
+}
+
+GUIChatConsole::~GUIChatConsole()
+{
+ if (m_font)
+ m_font->drop();
+}
+
+void GUIChatConsole::openConsole(f32 height)
+{
+ m_open = true;
+ m_desired_height_fraction = height;
+ m_desired_height = height * m_screensize.Y;
+ reformatConsole();
+ m_animate_time_old = getTimeMs();
+ IGUIElement::setVisible(true);
+ Environment->setFocus(this);
+ m_menumgr->createdMenu(this);
+}
+
+bool GUIChatConsole::isOpen() const
+{
+ return m_open;
+}
+
+bool GUIChatConsole::isOpenInhibited() const
+{
+ return m_open_inhibited > 0;
+}
+
+void GUIChatConsole::closeConsole()
+{
+ m_open = false;
+ Environment->removeFocus(this);
+ m_menumgr->deletingMenu(this);
+}
+
+void GUIChatConsole::closeConsoleAtOnce()
+{
+ closeConsole();
+ m_height = 0;
+ recalculateConsolePosition();
+}
+
+f32 GUIChatConsole::getDesiredHeight() const
+{
+ return m_desired_height_fraction;
+}
+
+void GUIChatConsole::replaceAndAddToHistory(std::wstring line)
+{
+ ChatPrompt& prompt = m_chat_backend->getPrompt();
+ prompt.addToHistory(prompt.getLine());
+ prompt.replace(line);
+}
+
+
+void GUIChatConsole::setCursor(
+ bool visible, bool blinking, f32 blink_speed, f32 relative_height)
+{
+ if (visible)
+ {
+ if (blinking)
+ {
+ // leave m_cursor_blink unchanged
+ m_cursor_blink_speed = blink_speed;
+ }
+ else
+ {
+ m_cursor_blink = 0x8000; // on
+ m_cursor_blink_speed = 0.0;
+ }
+ }
+ else
+ {
+ m_cursor_blink = 0; // off
+ m_cursor_blink_speed = 0.0;
+ }
+ m_cursor_height = relative_height;
+}
+
+void GUIChatConsole::draw()
+{
+ if(!IsVisible)
+ return;
+
+ video::IVideoDriver* driver = Environment->getVideoDriver();
+
+ // Check screen size
+ v2u32 screensize = driver->getScreenSize();
+ if (screensize != m_screensize)
+ {
+ // screen size has changed
+ // scale current console height to new window size
+ if (m_screensize.Y != 0)
+ m_height = m_height * screensize.Y / m_screensize.Y;
+ m_desired_height = m_desired_height_fraction * m_screensize.Y;
+ m_screensize = screensize;
+ reformatConsole();
+ }
+
+ // Animation
+ u32 now = getTimeMs();
+ animate(now - m_animate_time_old);
+ m_animate_time_old = now;
+
+ // Draw console elements if visible
+ if (m_height > 0)
+ {
+ drawBackground();
+ drawText();
+ drawPrompt();
+ }
+
+ gui::IGUIElement::draw();
+}
+
+void GUIChatConsole::reformatConsole()
+{
+ s32 cols = m_screensize.X / m_fontsize.X - 2; // make room for a margin (looks better)
+ s32 rows = m_desired_height / m_fontsize.Y - 1; // make room for the input prompt
+ if (cols <= 0 || rows <= 0)
+ cols = rows = 0;
+ m_chat_backend->reformat(cols, rows);
+}
+
+void GUIChatConsole::recalculateConsolePosition()
+{
+ core::rect<s32> rect(0, 0, m_screensize.X, m_height);
+ DesiredRect = rect;
+ recalculateAbsolutePosition(false);
+}
+
+void GUIChatConsole::animate(u32 msec)
+{
+ // animate the console height
+ s32 goal = m_open ? m_desired_height : 0;
+
+ // Set invisible if close animation finished (reset by openConsole)
+ // This function (animate()) is never called once its visibility becomes false so do not
+ // actually set visible to false before the inhibited period is over
+ if (!m_open && m_height == 0 && m_open_inhibited == 0)
+ IGUIElement::setVisible(false);
+
+ if (m_height != goal)
+ {
+ s32 max_change = msec * m_screensize.Y * (m_height_speed / 1000.0);
+ if (max_change == 0)
+ max_change = 1;
+
+ if (m_height < goal)
+ {
+ // increase height
+ if (m_height + max_change < goal)
+ m_height += max_change;
+ else
+ m_height = goal;
+ }
+ else
+ {
+ // decrease height
+ if (m_height > goal + max_change)
+ m_height -= max_change;
+ else
+ m_height = goal;
+ }
+
+ recalculateConsolePosition();
+ }
+
+ // blink the cursor
+ if (m_cursor_blink_speed != 0.0)
+ {
+ u32 blink_increase = 0x10000 * msec * (m_cursor_blink_speed / 1000.0);
+ if (blink_increase == 0)
+ blink_increase = 1;
+ m_cursor_blink = ((m_cursor_blink + blink_increase) & 0xffff);
+ }
+
+ // decrease open inhibit counter
+ if (m_open_inhibited > msec)
+ m_open_inhibited -= msec;
+ else
+ m_open_inhibited = 0;
+}
+
+void GUIChatConsole::drawBackground()
+{
+ video::IVideoDriver* driver = Environment->getVideoDriver();
+ if (m_background != NULL)
+ {
+ core::rect<s32> sourcerect(0, -m_height, m_screensize.X, 0);
+ driver->draw2DImage(
+ m_background,
+ v2s32(0, 0),
+ sourcerect,
+ &AbsoluteClippingRect,
+ m_background_color,
+ false);
+ }
+ else
+ {
+ driver->draw2DRectangle(
+ m_background_color,
+ core::rect<s32>(0, 0, m_screensize.X, m_height),
+ &AbsoluteClippingRect);
+ }
+}
+
+void GUIChatConsole::drawText()
+{
+ if (m_font == NULL)
+ return;
+
+ ChatBuffer& buf = m_chat_backend->getConsoleBuffer();
+ for (u32 row = 0; row < buf.getRows(); ++row)
+ {
+ const ChatFormattedLine& line = buf.getFormattedLine(row);
+ if (line.fragments.empty())
+ continue;
+
+ s32 line_height = m_fontsize.Y;
+ s32 y = row * line_height + m_height - m_desired_height;
+ if (y + line_height < 0)
+ continue;
+
+ for (u32 i = 0; i < line.fragments.size(); ++i)
+ {
+ const ChatFormattedFragment& fragment = line.fragments[i];
+ s32 x = (fragment.column + 1) * m_fontsize.X;
+ core::rect<s32> destrect(
+ x, y, x + m_fontsize.X * fragment.text.size(), y + m_fontsize.Y);
+
+
+ #if USE_FREETYPE
+ // Draw colored text if FreeType is enabled
+ irr::gui::CGUITTFont *tmp = static_cast<irr::gui::CGUITTFont*>(m_font);
+ tmp->draw(
+ fragment.text,
+ destrect,
+ video::SColor(255, 255, 255, 255),
+ false,
+ false,
+ &AbsoluteClippingRect);
+ #else
+ // Otherwise use standard text
+ m_font->draw(
+ fragment.text.c_str(),
+ destrect,
+ video::SColor(255, 255, 255, 255),
+ false,
+ false,
+ &AbsoluteClippingRect);
+ #endif
+ }
+ }
+}
+
+void GUIChatConsole::drawPrompt()
+{
+ if (m_font == NULL)
+ return;
+
+ u32 row = m_chat_backend->getConsoleBuffer().getRows();
+ s32 line_height = m_fontsize.Y;
+ s32 y = row * line_height + m_height - m_desired_height;
+
+ ChatPrompt& prompt = m_chat_backend->getPrompt();
+ std::wstring prompt_text = prompt.getVisiblePortion();
+
+ // FIXME Draw string at once, not character by character
+ // That will only work with the cursor once we have a monospace font
+ for (u32 i = 0; i < prompt_text.size(); ++i)
+ {
+ wchar_t ws[2] = {prompt_text[i], 0};
+ s32 x = (1 + i) * m_fontsize.X;
+ core::rect<s32> destrect(
+ x, y, x + m_fontsize.X, y + m_fontsize.Y);
+ m_font->draw(
+ ws,
+ destrect,
+ video::SColor(255, 255, 255, 255),
+ false,
+ false,
+ &AbsoluteClippingRect);
+ }
+
+ // Draw the cursor during on periods
+ if ((m_cursor_blink & 0x8000) != 0)
+ {
+ s32 cursor_pos = prompt.getVisibleCursorPosition();
+ if (cursor_pos >= 0)
+ {
+ s32 cursor_len = prompt.getCursorLength();
+ video::IVideoDriver* driver = Environment->getVideoDriver();
+ s32 x = (1 + cursor_pos) * m_fontsize.X;
+ core::rect<s32> destrect(
+ x,
+ y + m_fontsize.Y * (1.0 - m_cursor_height),
+ x + m_fontsize.X * MYMAX(cursor_len, 1),
+ y + m_fontsize.Y * (cursor_len ? m_cursor_height+1 : 1)
+ );
+ video::SColor cursor_color(255,255,255,255);
+ driver->draw2DRectangle(
+ cursor_color,
+ destrect,
+ &AbsoluteClippingRect);
+ }
+ }
+
+}
+
+bool GUIChatConsole::OnEvent(const SEvent& event)
+{
+
+ ChatPrompt &prompt = m_chat_backend->getPrompt();
+
+ if(event.EventType == EET_KEY_INPUT_EVENT && event.KeyInput.PressedDown)
+ {
+ // Key input
+ if(KeyPress(event.KeyInput) == getKeySetting("keymap_console"))
+ {
+ closeConsole();
+
+ // inhibit open so the_game doesn't reopen immediately
+ m_open_inhibited = 50;
+ m_close_on_enter = false;
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_ESCAPE)
+ {
+ closeConsoleAtOnce();
+ m_close_on_enter = false;
+ // inhibit open so the_game doesn't reopen immediately
+ m_open_inhibited = 1; // so the ESCAPE button doesn't open the "pause menu"
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_PRIOR)
+ {
+ m_chat_backend->scrollPageUp();
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_NEXT)
+ {
+ m_chat_backend->scrollPageDown();
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_RETURN)
+ {
+ prompt.addToHistory(prompt.getLine());
+ std::wstring text = prompt.replace(L"");
+ m_client->typeChatMessage(text);
+ if (m_close_on_enter) {
+ closeConsoleAtOnce();
+ m_close_on_enter = false;
+ }
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_UP)
+ {
+ // Up pressed
+ // Move back in history
+ prompt.historyPrev();
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_DOWN)
+ {
+ // Down pressed
+ // Move forward in history
+ prompt.historyNext();
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_LEFT || event.KeyInput.Key == KEY_RIGHT)
+ {
+ // Left/right pressed
+ // Move/select character/word to the left depending on control and shift keys
+ ChatPrompt::CursorOp op = event.KeyInput.Shift ?
+ ChatPrompt::CURSOROP_SELECT :
+ ChatPrompt::CURSOROP_MOVE;
+ ChatPrompt::CursorOpDir dir = event.KeyInput.Key == KEY_LEFT ?
+ ChatPrompt::CURSOROP_DIR_LEFT :
+ ChatPrompt::CURSOROP_DIR_RIGHT;
+ ChatPrompt::CursorOpScope scope = event.KeyInput.Control ?
+ ChatPrompt::CURSOROP_SCOPE_WORD :
+ ChatPrompt::CURSOROP_SCOPE_CHARACTER;
+ prompt.cursorOperation(op, dir, scope);
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_HOME)
+ {
+ // Home pressed
+ // move to beginning of line
+ prompt.cursorOperation(
+ ChatPrompt::CURSOROP_MOVE,
+ ChatPrompt::CURSOROP_DIR_LEFT,
+ ChatPrompt::CURSOROP_SCOPE_LINE);
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_END)
+ {
+ // End pressed
+ // move to end of line
+ prompt.cursorOperation(
+ ChatPrompt::CURSOROP_MOVE,
+ ChatPrompt::CURSOROP_DIR_RIGHT,
+ ChatPrompt::CURSOROP_SCOPE_LINE);
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_BACK)
+ {
+ // Backspace or Ctrl-Backspace pressed
+ // delete character / word to the left
+ ChatPrompt::CursorOpScope scope =
+ event.KeyInput.Control ?
+ ChatPrompt::CURSOROP_SCOPE_WORD :
+ ChatPrompt::CURSOROP_SCOPE_CHARACTER;
+ prompt.cursorOperation(
+ ChatPrompt::CURSOROP_DELETE,
+ ChatPrompt::CURSOROP_DIR_LEFT,
+ scope);
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_DELETE)
+ {
+ // Delete or Ctrl-Delete pressed
+ // delete character / word to the right
+ ChatPrompt::CursorOpScope scope =
+ event.KeyInput.Control ?
+ ChatPrompt::CURSOROP_SCOPE_WORD :
+ ChatPrompt::CURSOROP_SCOPE_CHARACTER;
+ prompt.cursorOperation(
+ ChatPrompt::CURSOROP_DELETE,
+ ChatPrompt::CURSOROP_DIR_RIGHT,
+ scope);
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_KEY_A && event.KeyInput.Control)
+ {
+ // Ctrl-A pressed
+ // Select all text
+ prompt.cursorOperation(
+ ChatPrompt::CURSOROP_SELECT,
+ ChatPrompt::CURSOROP_DIR_LEFT, // Ignored
+ ChatPrompt::CURSOROP_SCOPE_LINE);
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_KEY_C && event.KeyInput.Control)
+ {
+ // Ctrl-C pressed
+ // Copy text to clipboard
+ if (prompt.getCursorLength() <= 0)
+ return true;
+ std::wstring wselected = prompt.getSelection();
+ std::string selected(wselected.begin(), wselected.end());
+ Environment->getOSOperator()->copyToClipboard(selected.c_str());
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_KEY_V && event.KeyInput.Control)
+ {
+ // Ctrl-V pressed
+ // paste text from clipboard
+ if (prompt.getCursorLength() > 0) {
+ // Delete selected section of text
+ prompt.cursorOperation(
+ ChatPrompt::CURSOROP_DELETE,
+ ChatPrompt::CURSOROP_DIR_LEFT, // Ignored
+ ChatPrompt::CURSOROP_SCOPE_SELECTION);
+ }
+ IOSOperator *os_operator = Environment->getOSOperator();
+ const c8 *text = os_operator->getTextFromClipboard();
+ if (!text)
+ return true;
+ std::basic_string<unsigned char> str((const unsigned char*)text);
+ prompt.input(std::wstring(str.begin(), str.end()));
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_KEY_X && event.KeyInput.Control)
+ {
+ // Ctrl-X pressed
+ // Cut text to clipboard
+ if (prompt.getCursorLength() <= 0)
+ return true;
+ std::wstring wselected = prompt.getSelection();
+ std::string selected(wselected.begin(), wselected.end());
+ Environment->getOSOperator()->copyToClipboard(selected.c_str());
+ prompt.cursorOperation(
+ ChatPrompt::CURSOROP_DELETE,
+ ChatPrompt::CURSOROP_DIR_LEFT, // Ignored
+ ChatPrompt::CURSOROP_SCOPE_SELECTION);
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_KEY_U && event.KeyInput.Control)
+ {
+ // Ctrl-U pressed
+ // kill line to left end
+ prompt.cursorOperation(
+ ChatPrompt::CURSOROP_DELETE,
+ ChatPrompt::CURSOROP_DIR_LEFT,
+ ChatPrompt::CURSOROP_SCOPE_LINE);
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_KEY_K && event.KeyInput.Control)
+ {
+ // Ctrl-K pressed
+ // kill line to right end
+ prompt.cursorOperation(
+ ChatPrompt::CURSOROP_DELETE,
+ ChatPrompt::CURSOROP_DIR_RIGHT,
+ ChatPrompt::CURSOROP_SCOPE_LINE);
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_TAB)
+ {
+ // Tab or Shift-Tab pressed
+ // Nick completion
+ std::list<std::string> names = m_client->getConnectedPlayerNames();
+ bool backwards = event.KeyInput.Shift;
+ prompt.nickCompletion(names, backwards);
+ return true;
+ }
+ else if(event.KeyInput.Char != 0 && !event.KeyInput.Control)
+ {
+ #if (defined(linux) || defined(__linux))
+ wchar_t wc = L'_';
+ mbtowc( &wc, (char *) &event.KeyInput.Char, sizeof(event.KeyInput.Char) );
+ prompt.input(wc);
+ #else
+ prompt.input(event.KeyInput.Char);
+ #endif
+ return true;
+ }
+ }
+ else if(event.EventType == EET_MOUSE_INPUT_EVENT)
+ {
+ if(event.MouseInput.Event == EMIE_MOUSE_WHEEL)
+ {
+ s32 rows = myround(-3.0 * event.MouseInput.Wheel);
+ m_chat_backend->scroll(rows);
+ }
+ }
+
+ return Parent ? Parent->OnEvent(event) : false;
+}
+
+void GUIChatConsole::setVisible(bool visible)
+{
+ m_open = visible;
+ IGUIElement::setVisible(visible);
+ if (!visible) {
+ m_height = 0;
+ recalculateConsolePosition();
+ }
+}
+
--- /dev/null
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+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 GUICHATCONSOLE_HEADER
+#define GUICHATCONSOLE_HEADER
+
+#include "irrlichttypes_extrabloated.h"
+#include "modalMenu.h"
+#include "chat.h"
+#include "config.h"
+
+class Client;
+
+class GUIChatConsole : public gui::IGUIElement
+{
+public:
+ GUIChatConsole(gui::IGUIEnvironment* env,
+ gui::IGUIElement* parent,
+ s32 id,
+ ChatBackend* backend,
+ Client* client,
+ IMenuManager* menumgr);
+ virtual ~GUIChatConsole();
+
+ // Open the console (height = desired fraction of screen size)
+ // This doesn't open immediately but initiates an animation.
+ // You should call isOpenInhibited() before this.
+ void openConsole(f32 height);
+
+ bool isOpen() const;
+
+ // Check if the console should not be opened at the moment
+ // This is to avoid reopening the console immediately after closing
+ bool isOpenInhibited() const;
+ // Close the console, equivalent to openConsole(0).
+ // This doesn't close immediately but initiates an animation.
+ void closeConsole();
+ // Close the console immediately, without animation.
+ void closeConsoleAtOnce();
+ // Set whether to close the console after the user presses enter.
+ void setCloseOnEnter(bool close) { m_close_on_enter = close; }
+
+ // Return the desired height (fraction of screen size)
+ // Zero if the console is closed or getting closed
+ f32 getDesiredHeight() const;
+
+ // Replace actual line when adding the actual to the history (if there is any)
+ void replaceAndAddToHistory(std::wstring line);
+
+ // Change how the cursor looks
+ void setCursor(
+ bool visible,
+ bool blinking = false,
+ f32 blink_speed = 1.0,
+ f32 relative_height = 1.0);
+
+ // Irrlicht draw method
+ virtual void draw();
+
+ bool canTakeFocus(gui::IGUIElement* element) { return false; }
+
+ virtual bool OnEvent(const SEvent& event);
+
+ virtual void setVisible(bool visible);
+
+private:
+ void reformatConsole();
+ void recalculateConsolePosition();
+
+ // These methods are called by draw
+ void animate(u32 msec);
+ void drawBackground();
+ void drawText();
+ void drawPrompt();
+
+private:
+ ChatBackend* m_chat_backend;
+ Client* m_client;
+ IMenuManager* m_menumgr;
+
+ // current screen size
+ v2u32 m_screensize;
+
+ // used to compute how much time passed since last animate()
+ u32 m_animate_time_old;
+
+ // should the console be opened or closed?
+ bool m_open;
+ // should it close after you press enter?
+ bool m_close_on_enter;
+ // current console height [pixels]
+ s32 m_height;
+ // desired height [pixels]
+ f32 m_desired_height;
+ // desired height [screen height fraction]
+ f32 m_desired_height_fraction;
+ // console open/close animation speed [screen height fraction / second]
+ f32 m_height_speed;
+ // if nonzero, opening the console is inhibited [milliseconds]
+ u32 m_open_inhibited;
+
+ // cursor blink frame (16-bit value)
+ // cursor is off during [0,32767] and on during [32768,65535]
+ u32 m_cursor_blink;
+ // cursor blink speed [on/off toggles / second]
+ f32 m_cursor_blink_speed;
+ // cursor height [line height]
+ f32 m_cursor_height;
+
+ // background texture
+ video::ITexture* m_background;
+ // background color (including alpha)
+ video::SColor m_background_color;
+
+ // font
+ gui::IGUIFont* m_font;
+ v2u32 m_fontsize;
+};
+
+
+#endif
+
#include "log.h"
#include "fontengine.h"
#include "guiscalingfilter.h"
+#include "irrlicht_changes/static_text.h"
#ifdef __ANDROID__
#include "client/tile.h"
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("");
toset += utf8_to_wide(append);
}
- m_irr_toplefttext->setText(toset.c_str());
+ m_toplefttext = toset;
updateTopLeftTextSize();
}
/******************************************************************************/
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);
}
/******************************************************************************/
#include "guiFormSpecMenu.h"
#include "sound.h"
#include "client/tile.h"
+#include "util/enriched_string.h"
/******************************************************************************/
/* Typedefs and macros */
/** 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();
#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
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,',');
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'*');
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
{
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);
}
}
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
{
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);
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);
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;
{
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);
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');
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;
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;
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;
}
}
+ m_tooltip_element->draw();
+
/*
Draw dragged item stack
*/
#include "guiTable.h"
#include "network/networkprotocol.h"
#include "util/string.h"
+#include "util/enriched_string.h"
class IGameDef;
class InventoryManager;
fname(name),
fid(id)
{
- flabel = unescape_enriched(label);
+ //flabel = unescape_enriched(label);
+ flabel = label;
fdefault = unescape_enriched(default_text);
send = false;
ftype = f_Unknown;
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;
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,
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;
--- /dev/null
+if (BUILD_CLIENT)
+ set(client_irrlicht_changes_SRCS
+ ${CMAKE_CURRENT_SOURCE_DIR}/static_text.cpp
+ PARENT_SCOPE
+ )
+endif()
+
--- /dev/null
+// 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 "static_text.h"
+#ifdef _IRR_COMPILE_WITH_GUI_
+
+#include <vector>
+#include <string>
+#include <iostream>
+#include <IGUISkin.h>
+#include <IGUIEnvironment.h>
+#include <IGUIFont.h>
+#include <IVideoDriver.h>
+#include <rect.h>
+#include <SColor.h>
+
+#if USE_FREETYPE
+ #include "cguittfont/xCGUITTFont.h"
+#endif
+
+#include "util/string.h"
+
+namespace irr
+{
+
+#if USE_FREETYPE
+
+namespace gui
+{
+//! constructor
+StaticText::StaticText(const EnrichedString &text, bool border,
+ IGUIEnvironment* environment, IGUIElement* parent,
+ s32 id, const core::rect<s32>& rectangle,
+ bool background)
+: IGUIStaticText(environment, parent, id, rectangle),
+ HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_UPPERLEFT),
+ Border(border), OverrideColorEnabled(false), OverrideBGColorEnabled(false), WordWrap(false), Background(background),
+ RestrainTextInside(true), RightToLeft(false),
+ OverrideColor(video::SColor(101,255,255,255)), BGColor(video::SColor(101,210,210,210)),
+ OverrideFont(0), LastBreakFont(0)
+{
+ #ifdef _DEBUG
+ setDebugName("StaticText");
+ #endif
+
+ Text = text.c_str();
+ cText = text;
+ if (environment && environment->getSkin())
+ {
+ BGColor = environment->getSkin()->getColor(gui::EGDC_3D_FACE);
+ }
+}
+
+
+//! destructor
+StaticText::~StaticText()
+{
+ if (OverrideFont)
+ OverrideFont->drop();
+}
+
+//! draws the element and its children
+void StaticText::draw()
+{
+ if (!IsVisible)
+ return;
+
+ IGUISkin* skin = Environment->getSkin();
+ if (!skin)
+ return;
+ video::IVideoDriver* driver = Environment->getVideoDriver();
+
+ core::rect<s32> frameRect(AbsoluteRect);
+
+ // draw background
+
+ if (Background)
+ {
+ if ( !OverrideBGColorEnabled ) // skin-colors can change
+ BGColor = skin->getColor(gui::EGDC_3D_FACE);
+
+ driver->draw2DRectangle(BGColor, frameRect, &AbsoluteClippingRect);
+ }
+
+ // draw the border
+
+ if (Border)
+ {
+ skin->draw3DSunkenPane(this, 0, true, false, frameRect, &AbsoluteClippingRect);
+ frameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X);
+ }
+
+ // draw the text
+ if (cText.size())
+ {
+ IGUIFont* font = getActiveFont();
+
+ 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;
+ }
+
+ 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));
+ }
+ else
+ {
+ if (font != LastBreakFont)
+ breakText();
+
+ core::rect<s32> r = frameRect;
+ s32 height = font->getDimension(L"A").Height + font->getKerningHeight();
+ s32 totalHeight = height * BrokenText.size();
+ if (VAlign == EGUIA_CENTER)
+ {
+ r.UpperLeftCorner.Y = r.getCenter().Y - (totalHeight / 2);
+ }
+ else if (VAlign == EGUIA_LOWERRIGHT)
+ {
+ r.UpperLeftCorner.Y = r.LowerRightCorner.Y - totalHeight;
+ }
+
+ irr::video::SColor previous_color(255, 255, 255, 255);
+ for (u32 i=0; i<BrokenText.size(); ++i)
+ {
+ if (HAlign == EGUIA_LOWERRIGHT)
+ {
+ r.UpperLeftCorner.X = frameRect.LowerRightCorner.X -
+ font->getDimension(BrokenText[i].c_str()).Width;
+ }
+
+ //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];
+
+ irr::gui::CGUITTFont *tmp = static_cast<irr::gui::CGUITTFont*>(font);
+ tmp->draw(str, r,
+ previous_color, // FIXME
+ HAlign == EGUIA_CENTER, false, (RestrainTextInside ? &AbsoluteClippingRect : NULL));
+
+ r.LowerRightCorner.Y += height;
+ r.UpperLeftCorner.Y += height;
+ }
+ }
+ }
+ }
+
+ IGUIElement::draw();
+}
+
+
+//! Sets another skin independent font.
+void StaticText::setOverrideFont(IGUIFont* font)
+{
+ if (OverrideFont == font)
+ return;
+
+ if (OverrideFont)
+ OverrideFont->drop();
+
+ OverrideFont = font;
+
+ if (OverrideFont)
+ OverrideFont->grab();
+
+ breakText();
+}
+
+//! Gets the override font (if any)
+IGUIFont * StaticText::getOverrideFont() const
+{
+ return OverrideFont;
+}
+
+//! Get the font which is used right now for drawing
+IGUIFont* StaticText::getActiveFont() const
+{
+ if ( OverrideFont )
+ return OverrideFont;
+ IGUISkin* skin = Environment->getSkin();
+ if (skin)
+ return skin->getFont();
+ return 0;
+}
+
+//! Sets another color for the text.
+void StaticText::setOverrideColor(video::SColor color)
+{
+ OverrideColor = color;
+ OverrideColorEnabled = true;
+}
+
+
+//! Sets another color for the text.
+void StaticText::setBackgroundColor(video::SColor color)
+{
+ BGColor = color;
+ OverrideBGColorEnabled = true;
+ Background = true;
+}
+
+
+//! Sets whether to draw the background
+void StaticText::setDrawBackground(bool draw)
+{
+ Background = draw;
+}
+
+
+//! Gets the background color
+video::SColor StaticText::getBackgroundColor() const
+{
+ return BGColor;
+}
+
+
+//! Checks if background drawing is enabled
+bool StaticText::isDrawBackgroundEnabled() const
+{
+ _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
+ return Background;
+}
+
+
+//! Sets whether to draw the border
+void StaticText::setDrawBorder(bool draw)
+{
+ Border = draw;
+}
+
+
+//! Checks if border drawing is enabled
+bool StaticText::isDrawBorderEnabled() const
+{
+ _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
+ return Border;
+}
+
+
+void StaticText::setTextRestrainedInside(bool restrainTextInside)
+{
+ RestrainTextInside = restrainTextInside;
+}
+
+
+bool StaticText::isTextRestrainedInside() const
+{
+ return RestrainTextInside;
+}
+
+
+void StaticText::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical)
+{
+ HAlign = horizontal;
+ VAlign = vertical;
+}
+
+
+#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 7
+const video::SColor& StaticText::getOverrideColor() const
+#else
+video::SColor StaticText::getOverrideColor() const
+#endif
+{
+ return OverrideColor;
+}
+
+
+//! Sets if the static text should use the overide color or the
+//! color in the gui skin.
+void StaticText::enableOverrideColor(bool enable)
+{
+ OverrideColorEnabled = enable;
+}
+
+
+bool StaticText::isOverrideColorEnabled() const
+{
+ _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
+ return OverrideColorEnabled;
+}
+
+
+//! Enables or disables word wrap for using the static text as
+//! multiline text control.
+void StaticText::setWordWrap(bool enable)
+{
+ WordWrap = enable;
+ breakText();
+}
+
+
+bool StaticText::isWordWrapEnabled() const
+{
+ _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
+ return WordWrap;
+}
+
+
+void StaticText::setRightToLeft(bool rtl)
+{
+ if (RightToLeft != rtl)
+ {
+ RightToLeft = rtl;
+ breakText();
+ }
+}
+
+
+bool StaticText::isRightToLeft() const
+{
+ return RightToLeft;
+}
+
+
+//! Breaks the single text line.
+void StaticText::breakText()
+{
+ if (!WordWrap)
+ return;
+
+ BrokenText.clear();
+
+ IGUISkin* skin = Environment->getSkin();
+ IGUIFont* font = getActiveFont();
+ if (!font)
+ return;
+
+ LastBreakFont = font;
+
+ 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;
+
+ // 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
+ // some order and boundaries which change.
+ if (!RightToLeft)
+ {
+ // regular (left-to-right)
+ for (s32 i=0; i<size; ++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;
+ //}
+ c = '\0';
+ }
+ else if (c == L'\n') // Unix breaks
+ {
+ lineBreak = true;
+ c = '\0';
+ }
+
+ bool isWhitespace = (c == L' ' || c == 0);
+ if ( !isWhitespace )
+ {
+ // part of a word
+ //word += c;
+ word.addChar(cText, i);
+ }
+
+ if ( isWhitespace || i == (size-1))
+ {
+ if (word.size())
+ {
+ // 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(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 = core::stringw(word.c_str()).findFirst( wchar_t(0x00AD) );
+ if (where != -1)
+ {
+ 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;
+ line = second;
+ }
+ else
+ {
+ // No soft hyphen found, so there's nothing more we can do
+ // break to next line
+ if (length)
+ BrokenText.push_back(line);
+ length = wordlgth;
+ line = word;
+ }
+ }
+ else if (length && (length + wordlgth + whitelgth > elWidth))
+ {
+ // break to next line
+ BrokenText.push_back(line);
+ length = wordlgth;
+ line = word;
+ }
+ else
+ {
+ // add word to line
+ line += whitespace;
+ line += word;
+ length += whitelgth + wordlgth;
+ }
+
+ word.clear();
+ whitespace.clear();
+ }
+
+ if ( isWhitespace && c != 0)
+ {
+ whitespace.addChar(cText, i);
+ }
+
+ // compute line break
+ if (lineBreak)
+ {
+ line += whitespace;
+ line += word;
+ BrokenText.push_back(line);
+ line.clear();
+ word.clear();
+ whitespace.clear();
+ length = 0;
+ }
+ }
+ }
+
+ line += whitespace;
+ line += word;
+ BrokenText.push_back(line);
+ }
+ else
+ {
+ // right-to-left
+ for (s32 i=size; i>=0; --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;
+ //}
+ c = '\0';
+ }
+ else if (c == L'\n') // Unix breaks
+ {
+ lineBreak = true;
+ c = '\0';
+ }
+
+ if (c==L' ' || c==0 || i==0)
+ {
+ if (word.size())
+ {
+ // 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 s32 wordlgth = font->getDimension(word.c_str()).Width;
+
+ if (length && (length + wordlgth + whitelgth > elWidth))
+ {
+ // break to next line
+ BrokenText.push_back(line);
+ length = wordlgth;
+ line = word;
+ }
+ else
+ {
+ // add word to line
+ line = whitespace + line;
+ line = word + line;
+ length += whitelgth + wordlgth;
+ }
+
+ word.clear();
+ whitespace.clear();
+ }
+
+ if (c != 0)
+ // whitespace = core::stringw(&c, 1) + whitespace;
+ whitespace = cText.substr(i, 1) + whitespace;
+
+ // compute line break
+ if (lineBreak)
+ {
+ line = whitespace + line;
+ line = word + line;
+ BrokenText.push_back(line);
+ line.clear();
+ word.clear();
+ whitespace.clear();
+ length = 0;
+ }
+ }
+ else
+ {
+ // yippee this is a word..
+ //word = core::stringw(&c, 1) + word;
+ word = cText.substr(i, 1) + word;
+ }
+ }
+
+ line = whitespace + line;
+ line = word + line;
+ BrokenText.push_back(line);
+ }
+}
+
+
+//! Sets the new caption of this element.
+void StaticText::setText(const wchar_t* 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();
+}
+
+
+void StaticText::updateAbsolutePosition()
+{
+ IGUIElement::updateAbsolutePosition();
+ breakText();
+}
+
+
+//! Returns the height of the text in pixels when it is drawn.
+s32 StaticText::getTextHeight() const
+{
+ IGUIFont* font = getActiveFont();
+ if (!font)
+ return 0;
+
+ s32 height = font->getDimension(L"A").Height + font->getKerningHeight();
+
+ if (WordWrap)
+ height *= BrokenText.size();
+
+ return height;
+}
+
+
+s32 StaticText::getTextWidth() const
+{
+ IGUIFont * font = getActiveFont();
+ if(!font)
+ return 0;
+
+ if(WordWrap)
+ {
+ s32 widest = 0;
+
+ for(u32 line = 0; line < BrokenText.size(); ++line)
+ {
+ s32 width = font->getDimension(BrokenText[line].c_str()).Width;
+
+ if(width > widest)
+ widest = width;
+ }
+
+ return widest;
+ }
+ else
+ {
+ return font->getDimension(cText.c_str()).Width;
+ }
+}
+
+
+//! Writes attributes of the element.
+//! Implement this to expose the attributes of your element for
+//! scripting languages, editors, debuggers or xml serialization purposes.
+void StaticText::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
+{
+ IGUIStaticText::serializeAttributes(out,options);
+
+ out->addBool ("Border", Border);
+ out->addBool ("OverrideColorEnabled",OverrideColorEnabled);
+ out->addBool ("OverrideBGColorEnabled",OverrideBGColorEnabled);
+ out->addBool ("WordWrap", WordWrap);
+ out->addBool ("Background", Background);
+ out->addBool ("RightToLeft", RightToLeft);
+ out->addBool ("RestrainTextInside", RestrainTextInside);
+ out->addColor ("OverrideColor", OverrideColor);
+ out->addColor ("BGColor", BGColor);
+ out->addEnum ("HTextAlign", HAlign, GUIAlignmentNames);
+ out->addEnum ("VTextAlign", VAlign, GUIAlignmentNames);
+
+ // out->addFont ("OverrideFont", OverrideFont);
+}
+
+
+//! Reads attributes of the element
+void StaticText::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
+{
+ IGUIStaticText::deserializeAttributes(in,options);
+
+ Border = in->getAttributeAsBool("Border");
+ enableOverrideColor(in->getAttributeAsBool("OverrideColorEnabled"));
+ OverrideBGColorEnabled = in->getAttributeAsBool("OverrideBGColorEnabled");
+ setWordWrap(in->getAttributeAsBool("WordWrap"));
+ Background = in->getAttributeAsBool("Background");
+ RightToLeft = in->getAttributeAsBool("RightToLeft");
+ RestrainTextInside = in->getAttributeAsBool("RestrainTextInside");
+ OverrideColor = in->getAttributeAsColor("OverrideColor");
+ BGColor = in->getAttributeAsColor("BGColor");
+
+ setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames),
+ (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames));
+
+ // OverrideFont = in->getAttributeAsFont("OverrideFont");
+}
+
+} // end namespace gui
+
+#endif // USE_FREETYPE
+
+} // end namespace irr
+
+
+#endif // _IRR_COMPILE_WITH_GUI_
--- /dev/null
+// 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
+
+#ifndef __C_GUI_STATIC_TEXT_H_INCLUDED__
+#define __C_GUI_STATIC_TEXT_H_INCLUDED__
+
+#include "IrrCompileConfig.h"
+#ifdef _IRR_COMPILE_WITH_GUI_
+
+#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 EnrichedString &text, bool border, IGUIEnvironment* environment,
+ IGUIElement* parent, s32 id, const core::rect<s32>& rectangle,
+ bool background = false);
+
+ //! destructor
+ virtual ~StaticText();
+
+ //! draws the element and its children
+ virtual void draw();
+
+ //! Sets another skin independent font.
+ virtual void setOverrideFont(IGUIFont* font=0);
+
+ //! Gets the override font (if any)
+ virtual IGUIFont* getOverrideFont() const;
+
+ //! Get the font which is used right now for drawing
+ virtual IGUIFont* getActiveFont() const;
+
+ //! Sets another color for the text.
+ virtual void setOverrideColor(video::SColor color);
+
+ //! Sets another color for the background.
+ virtual void setBackgroundColor(video::SColor color);
+
+ //! Sets whether to draw the background
+ virtual void setDrawBackground(bool draw);
+
+ //! Gets the background color
+ virtual video::SColor getBackgroundColor() const;
+
+ //! Checks if background drawing is enabled
+ virtual bool isDrawBackgroundEnabled() const;
+
+ //! Sets whether to draw the border
+ virtual void setDrawBorder(bool draw);
+
+ //! Checks if border drawing is enabled
+ virtual bool isDrawBorderEnabled() const;
+
+ //! Sets alignment mode for text
+ virtual void setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical);
+
+ //! Gets the override color
+ #if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 7
+ virtual const video::SColor& getOverrideColor() const;
+ #else
+ virtual video::SColor getOverrideColor() const;
+ #endif
+
+ //! Sets if the static text should use the overide color or the
+ //! color in the gui skin.
+ virtual void enableOverrideColor(bool enable);
+
+ //! Checks if an override color is enabled
+ virtual bool isOverrideColorEnabled() const;
+
+ //! Set whether the text in this label should be clipped if it goes outside bounds
+ virtual void setTextRestrainedInside(bool restrainedInside);
+
+ //! Checks if the text in this label should be clipped if it goes outside bounds
+ virtual bool isTextRestrainedInside() const;
+
+ //! Enables or disables word wrap for using the static text as
+ //! multiline text control.
+ virtual void setWordWrap(bool enable);
+
+ //! Checks if word wrap is enabled
+ virtual bool isWordWrapEnabled() const;
+
+ //! Sets the new caption of this element.
+ virtual void setText(const wchar_t* text);
+
+ //! Returns the height of the text in pixels when it is drawn.
+ virtual s32 getTextHeight() const;
+
+ //! Returns the width of the current text, in the current font
+ virtual s32 getTextWidth() const;
+
+ //! Updates the absolute position, splits text if word wrap is enabled
+ virtual void updateAbsolutePosition();
+
+ //! Set whether the string should be interpreted as right-to-left (RTL) text
+ /** \note This component does not implement the Unicode bidi standard, the
+ text of the component should be already RTL if you call this. The
+ main difference when RTL is enabled is that the linebreaks for multiline
+ elements are performed starting from the end.
+ */
+ virtual void setRightToLeft(bool rtl);
+
+ //! Checks if the text should be interpreted as right-to-left text
+ virtual bool isRightToLeft() const;
+
+ //! Writes attributes of the element.
+ virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;
+
+ //! 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.
+ void breakText();
+
+ EGUI_ALIGNMENT HAlign, VAlign;
+ bool Border;
+ bool OverrideColorEnabled;
+ bool OverrideBGColorEnabled;
+ bool WordWrap;
+ bool Background;
+ bool RestrainTextInside;
+ bool RightToLeft;
+
+ video::SColor OverrideColor, BGColor;
+ gui::IGUIFont* OverrideFont;
+ gui::IGUIFont* LastBreakFont; // stored because: if skin changes, line break must be recalculated.
+
+ 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
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
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());
}
}
}
-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
${CMAKE_CURRENT_SOURCE_DIR}/string.cpp
${CMAKE_CURRENT_SOURCE_DIR}/srp.cpp
${CMAKE_CURRENT_SOURCE_DIR}/timetaker.cpp
- ${UTIL_FREETYPEDEP_SRCS}
PARENT_SCOPE)
+++ /dev/null
-/*
-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;
-}
+++ /dev/null
-/*
-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
--- /dev/null
+/*
+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;
+}
--- /dev/null
+/*
+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
+++ /dev/null
-// Copyright (C) 2002-2012 Nikolaus Gebhardt
-// This file is part of the "Irrlicht Engine".
-// For conditions of distribution and use, see copyright notice in irrlicht.h
-
-#include "statictext.h"
-#ifdef _IRR_COMPILE_WITH_GUI_
-
-//Only compile this if freetype is enabled.
-
-#include <vector>
-#include <string>
-#include <iostream>
-#include <IGUISkin.h>
-#include <IGUIEnvironment.h>
-#include <IGUIFont.h>
-#include <IVideoDriver.h>
-#include <rect.h>
-#include <SColor.h>
-
-#include "cguittfont/xCGUITTFont.h"
-#include "util/string.h"
-
-namespace irr
-{
-namespace gui
-{
-//! constructor
-StaticText::StaticText(const wchar_t* text, bool border,
- IGUIEnvironment* environment, IGUIElement* parent,
- s32 id, const core::rect<s32>& rectangle,
- bool background)
-: IGUIStaticText(environment, parent, id, rectangle),
- HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_UPPERLEFT),
- Border(border), OverrideColorEnabled(false), OverrideBGColorEnabled(false), WordWrap(false), Background(background),
- RestrainTextInside(true), RightToLeft(false),
- OverrideColor(video::SColor(101,255,255,255)), BGColor(video::SColor(101,210,210,210)),
- OverrideFont(0), LastBreakFont(0)
-{
- #ifdef _DEBUG
- setDebugName("StaticText");
- #endif
-
- Text = text;
- if (environment && environment->getSkin())
- {
- BGColor = environment->getSkin()->getColor(gui::EGDC_3D_FACE);
- }
-}
-
-
-//! destructor
-StaticText::~StaticText()
-{
- if (OverrideFont)
- OverrideFont->drop();
-}
-
-
-//! draws the element and its children
-void StaticText::draw()
-{
- if (!IsVisible)
- return;
-
- IGUISkin* skin = Environment->getSkin();
- if (!skin)
- return;
- video::IVideoDriver* driver = Environment->getVideoDriver();
-
- core::rect<s32> frameRect(AbsoluteRect);
-
- // draw background
-
- if (Background)
- {
- if ( !OverrideBGColorEnabled ) // skin-colors can change
- BGColor = skin->getColor(gui::EGDC_3D_FACE);
-
- driver->draw2DRectangle(BGColor, frameRect, &AbsoluteClippingRect);
- }
-
- // draw the border
-
- if (Border)
- {
- skin->draw3DSunkenPane(this, 0, true, false, frameRect, &AbsoluteClippingRect);
- frameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X);
- }
-
- // draw the text
- if (Text.size())
- {
- IGUIFont* font = getActiveFont();
-
- 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(Text.c_str()).Width;
- }
-
- font->draw(Text.c_str(), frameRect,
- OverrideColorEnabled ? OverrideColor : skin->getColor(isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT),
- HAlign == EGUIA_CENTER, VAlign == EGUIA_CENTER, (RestrainTextInside ? &AbsoluteClippingRect : NULL));
- }
- else
- {
- if (font != LastBreakFont)
- breakText();
-
- core::rect<s32> r = frameRect;
- s32 height = font->getDimension(L"A").Height + font->getKerningHeight();
- s32 totalHeight = height * BrokenText.size();
- if (VAlign == EGUIA_CENTER)
- {
- r.UpperLeftCorner.Y = r.getCenter().Y - (totalHeight / 2);
- }
- else if (VAlign == EGUIA_LOWERRIGHT)
- {
- r.UpperLeftCorner.Y = r.LowerRightCorner.Y - totalHeight;
- }
-
- irr::video::SColor previous_color(255, 255, 255, 255);
- for (u32 i=0; i<BrokenText.size(); ++i)
- {
- if (HAlign == EGUIA_LOWERRIGHT)
- {
- r.UpperLeftCorner.X = frameRect.LowerRightCorner.X -
- font->getDimension(BrokenText[i].c_str()).Width;
- }
-
- std::vector<irr::video::SColor> colors;
- std::wstring str;
-
- 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,
- HAlign == EGUIA_CENTER, false, (RestrainTextInside ? &AbsoluteClippingRect : NULL));
-
- r.LowerRightCorner.Y += height;
- r.UpperLeftCorner.Y += height;
- }
- }
- }
- }
-
- IGUIElement::draw();
-}
-
-
-//! Sets another skin independent font.
-void StaticText::setOverrideFont(IGUIFont* font)
-{
- if (OverrideFont == font)
- return;
-
- if (OverrideFont)
- OverrideFont->drop();
-
- OverrideFont = font;
-
- if (OverrideFont)
- OverrideFont->grab();
-
- breakText();
-}
-
-//! Gets the override font (if any)
-IGUIFont * StaticText::getOverrideFont() const
-{
- return OverrideFont;
-}
-
-//! Get the font which is used right now for drawing
-IGUIFont* StaticText::getActiveFont() const
-{
- if ( OverrideFont )
- return OverrideFont;
- IGUISkin* skin = Environment->getSkin();
- if (skin)
- return skin->getFont();
- return 0;
-}
-
-//! Sets another color for the text.
-void StaticText::setOverrideColor(video::SColor color)
-{
- OverrideColor = color;
- OverrideColorEnabled = true;
-}
-
-
-//! Sets another color for the text.
-void StaticText::setBackgroundColor(video::SColor color)
-{
- BGColor = color;
- OverrideBGColorEnabled = true;
- Background = true;
-}
-
-
-//! Sets whether to draw the background
-void StaticText::setDrawBackground(bool draw)
-{
- Background = draw;
-}
-
-
-//! Gets the background color
-video::SColor StaticText::getBackgroundColor() const
-{
- return BGColor;
-}
-
-
-//! Checks if background drawing is enabled
-bool StaticText::isDrawBackgroundEnabled() const
-{
- _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
- return Background;
-}
-
-
-//! Sets whether to draw the border
-void StaticText::setDrawBorder(bool draw)
-{
- Border = draw;
-}
-
-
-//! Checks if border drawing is enabled
-bool StaticText::isDrawBorderEnabled() const
-{
- _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
- return Border;
-}
-
-
-void StaticText::setTextRestrainedInside(bool restrainTextInside)
-{
- RestrainTextInside = restrainTextInside;
-}
-
-
-bool StaticText::isTextRestrainedInside() const
-{
- return RestrainTextInside;
-}
-
-
-void StaticText::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical)
-{
- HAlign = horizontal;
- VAlign = vertical;
-}
-
-
-#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 7
-const video::SColor& StaticText::getOverrideColor() const
-#else
-video::SColor StaticText::getOverrideColor() const
-#endif
-{
- return OverrideColor;
-}
-
-
-//! Sets if the static text should use the overide color or the
-//! color in the gui skin.
-void StaticText::enableOverrideColor(bool enable)
-{
- OverrideColorEnabled = enable;
-}
-
-
-bool StaticText::isOverrideColorEnabled() const
-{
- _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
- return OverrideColorEnabled;
-}
-
-
-//! Enables or disables word wrap for using the static text as
-//! multiline text control.
-void StaticText::setWordWrap(bool enable)
-{
- WordWrap = enable;
- breakText();
-}
-
-
-bool StaticText::isWordWrapEnabled() const
-{
- _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
- return WordWrap;
-}
-
-
-void StaticText::setRightToLeft(bool rtl)
-{
- if (RightToLeft != rtl)
- {
- RightToLeft = rtl;
- breakText();
- }
-}
-
-
-bool StaticText::isRightToLeft() const
-{
- return RightToLeft;
-}
-
-
-//! Breaks the single text line.
-void StaticText::breakText()
-{
- if (!WordWrap)
- return;
-
- BrokenText.clear();
-
- IGUISkin* skin = Environment->getSkin();
- IGUIFont* font = getActiveFont();
- if (!font)
- return;
-
- LastBreakFont = font;
-
- core::stringw line;
- core::stringw word;
- core::stringw whitespace;
- s32 size = Text.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;
-
- // 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
- // some order and boundaries which change.
- if (!RightToLeft)
- {
- // regular (left-to-right)
- for (s32 i=0; i<size; ++i)
- {
- c = Text[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;
- }
- c = '\0';
- }
- else if (c == L'\n') // Unix breaks
- {
- lineBreak = true;
- c = '\0';
- }
-
- bool isWhitespace = (c == L' ' || c == 0);
- if ( !isWhitespace )
- {
- // part of a word
- word += c;
- }
-
- if ( isWhitespace || i == (size-1))
- {
- if (word.size())
- {
- // 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;
-
- 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) );
- 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"-");
- const s32 secondLength = font->getDimension(second.c_str()).Width;
-
- length = secondLength;
- line = second;
- }
- else
- {
- // No soft hyphen found, so there's nothing more we can do
- // break to next line
- if (length)
- BrokenText.push_back(line);
- length = wordlgth;
- line = word;
- }
- }
- else if (length && (length + wordlgth + whitelgth > elWidth))
- {
- // break to next line
- BrokenText.push_back(line);
- length = wordlgth;
- line = word;
- }
- else
- {
- // add word to line
- line += whitespace;
- line += word;
- length += whitelgth + wordlgth;
- }
-
- word = L"";
- whitespace = L"";
- }
-
- if ( isWhitespace )
- {
- whitespace += c;
- }
-
- // compute line break
- if (lineBreak)
- {
- line += whitespace;
- line += word;
- BrokenText.push_back(line);
- line = L"";
- word = L"";
- whitespace = L"";
- length = 0;
- }
- }
- }
-
- line += whitespace;
- line += word;
- BrokenText.push_back(line);
- }
- else
- {
- // right-to-left
- for (s32 i=size; i>=0; --i)
- {
- c = Text[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;
- }
- c = '\0';
- }
- else if (c == L'\n') // Unix breaks
- {
- lineBreak = true;
- c = '\0';
- }
-
- if (c==L' ' || c==0 || i==0)
- {
- if (word.size())
- {
- // 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 s32 wordlgth = font->getDimension(word.c_str()).Width;
-
- if (length && (length + wordlgth + whitelgth > elWidth))
- {
- // break to next line
- BrokenText.push_back(line);
- length = wordlgth;
- line = word;
- }
- else
- {
- // add word to line
- line = whitespace + line;
- line = word + line;
- length += whitelgth + wordlgth;
- }
-
- word = L"";
- whitespace = L"";
- }
-
- if (c != 0)
- whitespace = core::stringw(&c, 1) + whitespace;
-
- // compute line break
- if (lineBreak)
- {
- line = whitespace + line;
- line = word + line;
- BrokenText.push_back(line);
- line = L"";
- word = L"";
- whitespace = L"";
- length = 0;
- }
- }
- else
- {
- // yippee this is a word..
- word = core::stringw(&c, 1) + word;
- }
- }
-
- line = whitespace + line;
- line = word + line;
- BrokenText.push_back(line);
- }
-}
-
-
-//! Sets the new caption of this element.
-void StaticText::setText(const wchar_t* text)
-{
- IGUIElement::setText(text);
- breakText();
-}
-
-
-void StaticText::updateAbsolutePosition()
-{
- IGUIElement::updateAbsolutePosition();
- breakText();
-}
-
-
-//! Returns the height of the text in pixels when it is drawn.
-s32 StaticText::getTextHeight() const
-{
- IGUIFont* font = getActiveFont();
- if (!font)
- return 0;
-
- s32 height = font->getDimension(L"A").Height + font->getKerningHeight();
-
- if (WordWrap)
- height *= BrokenText.size();
-
- return height;
-}
-
-
-s32 StaticText::getTextWidth() const
-{
- IGUIFont * font = getActiveFont();
- if(!font)
- return 0;
-
- if(WordWrap)
- {
- s32 widest = 0;
-
- for(u32 line = 0; line < BrokenText.size(); ++line)
- {
- s32 width = font->getDimension(BrokenText[line].c_str()).Width;
-
- if(width > widest)
- widest = width;
- }
-
- return widest;
- }
- else
- {
- return font->getDimension(Text.c_str()).Width;
- }
-}
-
-
-//! Writes attributes of the element.
-//! Implement this to expose the attributes of your element for
-//! scripting languages, editors, debuggers or xml serialization purposes.
-void StaticText::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
-{
- IGUIStaticText::serializeAttributes(out,options);
-
- out->addBool ("Border", Border);
- out->addBool ("OverrideColorEnabled",OverrideColorEnabled);
- out->addBool ("OverrideBGColorEnabled",OverrideBGColorEnabled);
- out->addBool ("WordWrap", WordWrap);
- out->addBool ("Background", Background);
- out->addBool ("RightToLeft", RightToLeft);
- out->addBool ("RestrainTextInside", RestrainTextInside);
- out->addColor ("OverrideColor", OverrideColor);
- out->addColor ("BGColor", BGColor);
- out->addEnum ("HTextAlign", HAlign, GUIAlignmentNames);
- out->addEnum ("VTextAlign", VAlign, GUIAlignmentNames);
-
- // out->addFont ("OverrideFont", OverrideFont);
-}
-
-
-//! Reads attributes of the element
-void StaticText::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
-{
- IGUIStaticText::deserializeAttributes(in,options);
-
- Border = in->getAttributeAsBool("Border");
- enableOverrideColor(in->getAttributeAsBool("OverrideColorEnabled"));
- OverrideBGColorEnabled = in->getAttributeAsBool("OverrideBGColorEnabled");
- setWordWrap(in->getAttributeAsBool("WordWrap"));
- Background = in->getAttributeAsBool("Background");
- RightToLeft = in->getAttributeAsBool("RightToLeft");
- RestrainTextInside = in->getAttributeAsBool("RestrainTextInside");
- OverrideColor = in->getAttributeAsColor("OverrideColor");
- BGColor = in->getAttributeAsColor("BGColor");
-
- setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames),
- (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames));
-
- // OverrideFont = in->getAttributeAsFont("OverrideFont");
-}
-
-} // end namespace gui
-} // end namespace irr
-
-
-#endif // _IRR_COMPILE_WITH_GUI_
+++ /dev/null
-// Copyright (C) 2002-2012 Nikolaus Gebhardt
-// This file is part of the "Irrlicht Engine".
-// For conditions of distribution and use, see copyright notice in irrlicht.h
-
-#ifndef __C_GUI_STATIC_TEXT_H_INCLUDED__
-#define __C_GUI_STATIC_TEXT_H_INCLUDED__
-
-#include "IrrCompileConfig.h"
-#ifdef _IRR_COMPILE_WITH_GUI_
-
-#include "IGUIStaticText.h"
-#include "irrArray.h"
-
-#include <vector>
-
-namespace irr
-{
-namespace gui
-{
- class StaticText : public IGUIStaticText
- {
- public:
-
- //! constructor
- StaticText(const wchar_t* text, bool border, IGUIEnvironment* environment,
- IGUIElement* parent, s32 id, const core::rect<s32>& rectangle,
- bool background = false);
-
- //! destructor
- virtual ~StaticText();
-
- //! draws the element and its children
- virtual void draw();
-
- //! Sets another skin independent font.
- virtual void setOverrideFont(IGUIFont* font=0);
-
- //! Gets the override font (if any)
- virtual IGUIFont* getOverrideFont() const;
-
- //! Get the font which is used right now for drawing
- virtual IGUIFont* getActiveFont() const;
-
- //! Sets another color for the text.
- virtual void setOverrideColor(video::SColor color);
-
- //! Sets another color for the background.
- virtual void setBackgroundColor(video::SColor color);
-
- //! Sets whether to draw the background
- virtual void setDrawBackground(bool draw);
-
- //! Gets the background color
- virtual video::SColor getBackgroundColor() const;
-
- //! Checks if background drawing is enabled
- virtual bool isDrawBackgroundEnabled() const;
-
- //! Sets whether to draw the border
- virtual void setDrawBorder(bool draw);
-
- //! Checks if border drawing is enabled
- virtual bool isDrawBorderEnabled() const;
-
- //! Sets alignment mode for text
- virtual void setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical);
-
- //! Gets the override color
- #if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 7
- virtual const video::SColor& getOverrideColor() const;
- #else
- virtual video::SColor getOverrideColor() const;
- #endif
-
- //! Sets if the static text should use the overide color or the
- //! color in the gui skin.
- virtual void enableOverrideColor(bool enable);
-
- //! Checks if an override color is enabled
- virtual bool isOverrideColorEnabled() const;
-
- //! Set whether the text in this label should be clipped if it goes outside bounds
- virtual void setTextRestrainedInside(bool restrainedInside);
-
- //! Checks if the text in this label should be clipped if it goes outside bounds
- virtual bool isTextRestrainedInside() const;
-
- //! Enables or disables word wrap for using the static text as
- //! multiline text control.
- virtual void setWordWrap(bool enable);
-
- //! Checks if word wrap is enabled
- virtual bool isWordWrapEnabled() const;
-
- //! Sets the new caption of this element.
- virtual void setText(const wchar_t* text);
-
- //! Returns the height of the text in pixels when it is drawn.
- virtual s32 getTextHeight() const;
-
- //! Returns the width of the current text, in the current font
- virtual s32 getTextWidth() const;
-
- //! Updates the absolute position, splits text if word wrap is enabled
- virtual void updateAbsolutePosition();
-
- //! Set whether the string should be interpreted as right-to-left (RTL) text
- /** \note This component does not implement the Unicode bidi standard, the
- text of the component should be already RTL if you call this. The
- main difference when RTL is enabled is that the linebreaks for multiline
- elements are performed starting from the end.
- */
- virtual void setRightToLeft(bool rtl);
-
- //! Checks if the text should be interpreted as right-to-left text
- virtual bool isRightToLeft() const;
-
- //! Writes attributes of the element.
- virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;
-
- //! Reads attributes of the element
- virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);
-
- private:
-
- //! Breaks the single text line.
- void breakText();
-
- EGUI_ALIGNMENT HAlign, VAlign;
- bool Border;
- bool OverrideColorEnabled;
- bool OverrideBGColorEnabled;
- bool WordWrap;
- bool Background;
- bool RestrainTextInside;
- bool RightToLeft;
-
- video::SColor OverrideColor, BGColor;
- gui::IGUIFont* OverrideFont;
- gui::IGUIFont* LastBreakFont; // stored because: if skin changes, line break must be recalculated.
-
- core::array< core::stringw > BrokenText;
- };
-
-} // end namespace gui
-} // end namespace irr
-
-#endif // _IRR_COMPILE_WITH_GUI_
-
-#endif // C_GUI_STATIC_TEXT_H_INCLUDED
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.
*