Fixed text ellipsis ...

... (triple dot being added after too long text) not being UTF-8-aware.

Added font::make_text_ellipsis function, that works like
word_wrap_text, but instead adds ellipsis on too long text Made
word_wrap_text UTF-8-aware.
This commit is contained in:
Philippe Plantier 2004-05-26 20:18:28 +00:00
parent c79e038759
commit 695bc5346c
4 changed files with 171 additions and 113 deletions

View file

@ -336,11 +336,13 @@ SDL_Rect draw_text_line(SDL_Surface *gui_surface, const SDL_Rect& area, int size
return res;
}
const std::string etext = make_text_ellipsis(text, size, area.w);
if(gui_surface == NULL) {
return text_size(font,text,colour,style);
return text_size(font,etext,colour,style);
}
scoped_sdl_surface surface(render_text(font,text,colour,style));
scoped_sdl_surface surface(render_text(font,etext,colour,style));
if(surface == NULL) {
SDL_Rect res = {0,0,0,0};
return res;
@ -358,20 +360,12 @@ SDL_Rect draw_text_line(SDL_Surface *gui_surface, const SDL_Rect& area, int size
dest.w = surface->w;
dest.h = surface->h;
if(line_width(text, size) > area.w) {
tooltips::add_tooltip(dest,text);
}
if(dest.x + dest.w > area.x + area.w) {
if(text.size() > 3) {
std::string txt = text;
if(std::count(txt.end()-3,txt.end(),'.') == 3) {
txt.erase(txt.end()-4);
} else {
tooltips::add_tooltip(dest,text);
std::fill(txt.end()-3,txt.end(),'.');
}
return draw_text_line(gui_surface,area,size,colour,txt,x,y,bg,false,style);
}
std::cerr << "Error: text with ellipsis does not fit !\n";
dest.w = area.x + area.w - dest.x;
}
@ -495,96 +489,123 @@ std::string remove_first_space(const std::string& text)
namespace font {
int line_width(const std::string line, int font_size)
{
int line_width(const std::string line, int font_size)
{
TTF_Font* const font = get_font(font_size);
if(font == NULL) {
std::cerr << "Could not get font\n";
return 0;
}
int w = 0;
int h = 0;
TTF_Font* const font = get_font(font_size);
if(font == NULL) {
std::cerr << "Could not get font\n";
return 0;
}
int w = 0;
int h = 0;
TTF_SizeUTF8(font, line.c_str(), &w, &h);
TTF_SizeUTF8(font, line.c_str(), &w, &h);
return w;
}
std::string word_wrap_text(const std::string& unwrapped_text, int font_size, int max_width)
{
std::string wrapped_text; // the final result
size_t word_start_pos = 0;
std::string cur_word; // including start-whitespace
std::string cur_line; // the whole line so far
for(int c = 0; c < unwrapped_text.length(); c++) {
// Find the next word
bool forced_line_break = false;
if (c == unwrapped_text.length() - 1) {
cur_word = unwrapped_text.substr(word_start_pos, c + 1 - word_start_pos);
word_start_pos = c + 1;
} else if (unwrapped_text[c] == '\n') {
cur_word = unwrapped_text.substr(word_start_pos, c + 1 - word_start_pos);
word_start_pos = c + 1;
forced_line_break = true;
} else if (unwrapped_text[c] == ' ') {
cur_word = unwrapped_text.substr(word_start_pos, c - word_start_pos);
word_start_pos = c;
} else {
continue;
}
// Test if the line should be wrapped or not
if (line_width(cur_line + cur_word, font_size) > max_width) {
if (line_width(cur_word, font_size) > (max_width /*/ 2*/)) {
// The last word is too big to fit in a nice way, split it on a char basis
for (std::string::iterator i = cur_word.begin(); i != cur_word.end(); ++i) {
if (line_width(cur_line + *i, font_size) > max_width) {
wrapped_text += cur_line + '\n';
cur_line = *i;
} else {
cur_line += *i;
}
}
} else {
// Split the line on a word basis
wrapped_text += cur_line + '\n';
cur_line = remove_first_space(cur_word);
return w;
}
} else {
cur_line += cur_word;
}
if (forced_line_break) {
wrapped_text += cur_line;
cur_line = "";
forced_line_break = false;
}
}
std::string word_wrap_text(const std::string& unwrapped_text, int font_size, int max_width)
{
std::cerr << "Wrapping word " << unwrapped_text << "\n";
std::string wrapped_text; // the final result
size_t word_start_pos = 0;
std::string cur_word; // including start-whitespace
std::string cur_line; // the whole line so far
for(int c = 0; c < unwrapped_text.length(); c++) {
// Find the next word
bool forced_line_break = false;
if (c == unwrapped_text.length() - 1) {
cur_word = unwrapped_text.substr(word_start_pos, c + 1 - word_start_pos);
word_start_pos = c + 1;
} else if (unwrapped_text[c] == '\n') {
cur_word = unwrapped_text.substr(word_start_pos, c + 1 - word_start_pos);
word_start_pos = c + 1;
forced_line_break = true;
} else if (unwrapped_text[c] == ' ') {
cur_word = unwrapped_text.substr(word_start_pos, c - word_start_pos);
word_start_pos = c;
} else {
continue;
}
// Test if the line should be wrapped or not
if (line_width(cur_line + cur_word, font_size) > max_width) {
if (line_width(cur_word, font_size) > (max_width /*/ 2*/)) {
// The last word is too big to fit in a nice way, split it on a char basis
std::vector<std::string> split_word = split_utf8_string(cur_word);
for (std::vector<std::string>::iterator i = split_word.begin(); i != split_word.end(); ++i) {
if (line_width(cur_line + *i, font_size) > max_width) {
wrapped_text += cur_line + '\n';
cur_line = *i;
} else {
cur_line += *i;
}
}
} else {
// Split the line on a word basis
wrapped_text += cur_line + '\n';
cur_line = remove_first_space(cur_word);
}
} else {
cur_line += cur_word;
}
if (forced_line_break) {
wrapped_text += cur_line;
cur_line = "";
forced_line_break = false;
}
}
// Don't forget to add the text left in cur_line
if (cur_line != "") {
wrapped_text += cur_line + '\n';
}
// Don't forget to add the text left in cur_line
if (cur_line != "") {
wrapped_text += cur_line + '\n';
}
return wrapped_text;
}
return wrapped_text;
}
std::string make_text_ellipsis(const std::string &text, int font_size, int max_width)
{
static const std::string ellipsis = "...";
if(line_width(text, font_size) <= max_width)
return text;
if(line_width(ellipsis, font_size) > max_width)
return "";
std::vector<std::string> characters = split_utf8_string(text);
std::string current_substring = "";
SDL_Rect draw_wrapped_text(display* gui, const SDL_Rect& area, int font_size,
for(std::vector<std::string>::const_iterator itor = characters.begin(); itor != characters.end(); ++itor) {
if (line_width(current_substring + *itor + ellipsis, font_size ) > max_width) {
return current_substring + ellipsis;
}
current_substring += *itor;
}
return text; // Should not happen
}
SDL_Rect draw_wrapped_text(display* gui, const SDL_Rect& area, int font_size,
const SDL_Color& colour, const std::string& text,
int x, int y, int max_width, SDL_Surface* bg)
{
std::string wrapped_text = word_wrap_text(text, font_size, max_width);
return font::draw_text(gui, area, font_size, colour, wrapped_text, x, y, bg, false, NO_MARKUP);
}
{
std::string wrapped_text = word_wrap_text(text, font_size, max_width);
return font::draw_text(gui, area, font_size, colour, wrapped_text, x, y, bg, false, NO_MARKUP);
}
}

View file

@ -92,6 +92,12 @@ int line_width(const std::string line, int font_size);
///
std::string word_wrap_text(const std::string& unwrapped_text, int font_size, int max_width);
///
/// If the text excedes the specified max width, end it with an ellipsis (...)
///
std::string make_text_ellipsis(const std::string& text, int font_size, int max_width);
///
/// Draw text on the screen. This method makes sure that the text
/// fits within a given maximum width. If a line exceedes this width it

View file

@ -227,32 +227,39 @@ std::string wstring_to_utf8(const wide_string &src)
}
}
int byte_size_from_utf8_first(unsigned char ch)
{
int count;
if ((ch & 0x80) == 0)
count = 1;
else if ((ch & 0xE0) == 0xC0)
count = 2;
else if ((ch & 0xF0) == 0xE0)
count = 3;
else if ((ch & 0xF8) == 0xF0)
count = 4;
else if ((ch & 0xFC) == 0xF8)
count = 5;
else if ((ch & 0xFE) == 0xFC)
count = 6;
else
throw invalid_utf8_exception(); /* stop on invalid characters */
return count;
}
wide_string utf8_to_wstring(const std::string &src)
{
wide_string ret;
wchar_t ch;
wchar_t ch;
std::string::const_iterator i;
try {
for(i = src.begin(); i != src.end(); ++i ) {
ch = (unsigned char)*i;
int count;
if ((ch & 0x80) == 0)
count = 1;
else if ((ch & 0xE0) == 0xC0)
count = 2;
else if ((ch & 0xF0) == 0xE0)
count = 3;
else if ((ch & 0xF8) == 0xF0)
count = 4;
else if ((ch & 0xFC) == 0xF8)
count = 5;
else if ((ch & 0xFE) == 0xFC)
count = 6;
else
throw invalid_utf8_exception(); /* stop on invalid characters */
const int count = byte_size_from_utf8_first(ch);
if(i + count - 1 == src.end())
throw invalid_utf8_exception();
@ -283,9 +290,32 @@ wide_string utf8_to_wstring(const std::string &src)
}
std::vector<std::string> split_utf8_string(const std::string &src)
{
std::vector<std::string> ret;
try {
for(size_t i = 0; i < src.size(); /* nop */) {
const int size = byte_size_from_utf8_first(src[i]);
if(i + size > src.size())
throw invalid_utf8_exception();
ret.push_back(src.substr(i, size));
i += size;
}
}
catch(invalid_utf8_exception e) {
std::cerr << "Invalid UTF-8 string: \"" << src << "\"\n";
return ret;
}
return ret;
}
std::string wstring_to_string(const wide_string &src)
{
return wstring_to_utf8(src);
return wstring_to_utf8(src);
}
wide_string string_to_wstring(const std::string &src)

View file

@ -61,6 +61,7 @@ std::string get_locale();
//functions for converting Unicode wide-char strings to UTF-8 encoded
//strings, back and forth
std::vector<std::string> split_utf8_string(const std::string &src);
std::string wstring_to_string(const wide_string &);
wide_string string_to_wstring(const std::string &);