void
Console::init_graphics()
{
- font.reset(new Font("images/engine/fonts/white-small.png",
+ font.reset(new Font(Font::FIXED,
+ "images/engine/fonts/white-small.png",
"images/engine/fonts/shadow-small.png", 8, 9, 1));
fontheight = font->get_height();
background.reset(new Surface("images/engine/console.png"));
if (focused) {
lineNo++;
float py = height-4-1*9;
- context.draw_text(font.get(), "> "+inputBuffer.str()+"_", Vector(4, py), LEFT_ALLIGN, layer);
+ context.draw_text(font.get(), "> "+inputBuffer.str()+"_", Vector(4, py), ALIGN_LEFT, layer);
}
int skipLines = -offset;
lineNo++;
float py = height-4-lineNo*9;
if (py < -9) break;
- context.draw_text(font.get(), *i, Vector(4, py), LEFT_ALLIGN, layer);
+ context.draw_text(font.get(), *i, Vector(4, py), ALIGN_LEFT, layer);
}
context.pop_transform();
}
}
// context.draw_text(gold_text, level->get_name(), Vector(SCREEN_WIDTH/2, 160),
-// CENTER_ALLIGN, LAYER_FOREGROUND1);
+// ALIGN_CENTER, LAYER_FOREGROUND1);
context.draw_center_text(gold_text, level->get_name(), Vector(0, 160),
LAYER_FOREGROUND1);
std::stringstream ss_coins;
ss_coins << _("Coins") << ": " << player_status->coins;
context.draw_text(white_text, ss_coins.str(), Vector(SCREEN_WIDTH/2, 210),
- CENTER_ALLIGN, LAYER_FOREGROUND1);
+ ALIGN_CENTER, LAYER_FOREGROUND1);
if((level->get_author().size()) && (level->get_author() != "SuperTux Team"))
context.draw_text(white_small_text,
std::string(_("contributed by ")) + level->get_author(),
- Vector(SCREEN_WIDTH/2, 350), CENTER_ALLIGN, LAYER_FOREGROUND1);
+ Vector(SCREEN_WIDTH/2, 350), ALIGN_CENTER, LAYER_FOREGROUND1);
if(best_level_statistics != NULL)
best_level_statistics->draw_message_info(context, _("Best Level Statistics"));
offset = Vector(size.x, 0);
else
offset = Vector(-30, -size.y/2);
- context.draw_text(info_font, info, pos + offset, LEFT_ALLIGN, LAYER_GUI+2);
+ context.draw_text(info_font, info, pos + offset, ALIGN_LEFT, LAYER_GUI+2);
if(binding != 0)
context.draw_text(info_font, "(" + std::string(SDL_GetKeyName(binding)) +
")", pos + offset + Vector(0,12),
- LEFT_ALLIGN, LAYER_GUI+2);
+ ALIGN_LEFT, LAYER_GUI+2);
}
context.draw_surface_part(image, Vector(0,0), size, pos, LAYER_GUI+1);
{
context.draw_text(deactive_font, pitem.text,
Vector(SCREEN_WIDTH/2, y_pos - int(deactive_font->get_height()/2)),
- CENTER_ALLIGN, LAYER_GUI);
+ ALIGN_CENTER, LAYER_GUI);
break;
}
{
context.draw_text(label_font, pitem.text,
Vector(SCREEN_WIDTH/2, y_pos - int(label_font->get_height()/2)),
- CENTER_ALLIGN, LAYER_GUI);
+ ALIGN_CENTER, LAYER_GUI);
break;
}
case MN_TEXTFIELD:
context.draw_text(field_font,
pitem.get_input_with_symbol(true),
Vector(input_pos, y_pos - int(field_font->get_height()/2)),
- LEFT_ALLIGN, LAYER_GUI);
+ ALIGN_LEFT, LAYER_GUI);
else
context.draw_text(field_font,
pitem.get_input_with_symbol(false),
Vector(input_pos, y_pos - int(field_font->get_height()/2)),
- LEFT_ALLIGN, LAYER_GUI);
+ ALIGN_LEFT, LAYER_GUI);
}
else
context.draw_text(field_font, pitem.input,
Vector(input_pos, y_pos - int(field_font->get_height()/2)),
- LEFT_ALLIGN, LAYER_GUI);
+ ALIGN_LEFT, LAYER_GUI);
context.draw_text(text_font, pitem.text,
Vector(text_pos, y_pos - int(text_font->get_height()/2)),
- LEFT_ALLIGN, LAYER_GUI);
+ ALIGN_LEFT, LAYER_GUI);
break;
}
case MN_STRINGSELECT:
context.draw_text(text_font, pitem.list[pitem.selected],
Vector(SCREEN_WIDTH/2 + text_pos, y_pos - int(text_font->get_height()/2)),
- CENTER_ALLIGN, LAYER_GUI);
+ ALIGN_CENTER, LAYER_GUI);
context.draw_text(text_font, pitem.text,
Vector(SCREEN_WIDTH/2 + list_pos_2/2, y_pos - int(text_font->get_height()/2)),
- CENTER_ALLIGN, LAYER_GUI);
+ ALIGN_CENTER, LAYER_GUI);
break;
}
case MN_BACK:
{
context.draw_text(text_font, pitem.text,
Vector(SCREEN_WIDTH/2, y_pos - int(text_font->get_height()/2)),
- CENTER_ALLIGN, LAYER_GUI);
+ ALIGN_CENTER, LAYER_GUI);
context.draw_surface(back.get(),
Vector(x_pos + text_width/2 + 16, y_pos - 8),
LAYER_GUI);
{
context.draw_text(text_font, pitem.text,
Vector(SCREEN_WIDTH/2, y_pos - (text_font->get_height()/2)),
- CENTER_ALLIGN, LAYER_GUI);
+ ALIGN_CENTER, LAYER_GUI);
if(pitem.toggled)
context.draw_surface(checkbox_checked.get(),
case MN_ACTION:
context.draw_text(text_font, pitem.text,
Vector(SCREEN_WIDTH/2, y_pos - int(text_font->get_height()/2)),
- CENTER_ALLIGN, LAYER_GUI);
+ ALIGN_CENTER, LAYER_GUI);
break;
case MN_GOTO:
context.draw_text(text_font, pitem.text,
Vector(SCREEN_WIDTH/2, y_pos - int(text_font->get_height()/2)),
- CENTER_ALLIGN, LAYER_GUI);
+ ALIGN_CENTER, LAYER_GUI);
break;
}
}
char str[60];
snprintf(str, sizeof(str), "%3.1f", fps_fps);
const char* fpstext = "FPS";
- context.draw_text(white_text, fpstext, Vector(SCREEN_WIDTH - white_text->get_text_width(fpstext) - gold_text->get_text_width(" 99999") - BORDER_X, BORDER_Y + 20), LEFT_ALLIGN, LAYER_HUD);
- context.draw_text(gold_text, str, Vector(SCREEN_WIDTH - BORDER_X, BORDER_Y + 20), RIGHT_ALLIGN, LAYER_HUD);
+ context.draw_text(white_text, fpstext, Vector(SCREEN_WIDTH - white_text->get_text_width(fpstext) - gold_text->get_text_width(" 99999") - BORDER_X, BORDER_Y + 20), ALIGN_LEFT, LAYER_HUD);
+ context.draw_text(gold_text, str, Vector(SCREEN_WIDTH - BORDER_X, BORDER_Y + 20), ALIGN_RIGHT, LAYER_HUD);
}
void
context.push_transform();
context.set_alpha(alpha);
- context.draw_text(gold_text, text, position, LEFT_ALLIGN, LAYER_OBJECTS+1);
+ context.draw_text(gold_text, text, position, ALIGN_LEFT, LAYER_OBJECTS+1);
context.pop_transform();
}
if (time_surf) {
float all_width = time_surf->get_width() + white_text->get_text_width(time_text);
context.draw_surface(time_surf, Vector((SCREEN_WIDTH - all_width)/2, BORDER_Y + 1), LAYER_FOREGROUND1);
- context.draw_text(gold_text, time_text, Vector((SCREEN_WIDTH - all_width)/2 + time_surf->get_width(), BORDER_Y), LEFT_ALLIGN, LAYER_FOREGROUND1);
+ context.draw_text(gold_text, time_text, Vector((SCREEN_WIDTH - all_width)/2 + time_surf->get_width(), BORDER_Y), ALIGN_LEFT, LAYER_FOREGROUND1);
}
}
Color(0.6f, 0.7f, 0.8f, 0.5f), LAYER_GUI-50);
if (centered) {
context.draw_center_text(font, text, Vector(0, 50+35), LAYER_GUI-40);
+ } else {
+ context.draw_text(font, text, Vector(125+35, 50+35), ALIGN_LEFT, LAYER_GUI-40);
}
- else context.draw_text(font, text, Vector(125+35, 50+35), LEFT_ALLIGN, LAYER_GUI-40);
context.pop_transform();
}
if (coin_surf) {
context.draw_surface(coin_surf, Vector(SCREEN_WIDTH - BORDER_X - coin_surf->get_width() - gold_text->get_text_width(coins_text), BORDER_Y + 1), LAYER_HUD);
}
- context.draw_text(gold_text, coins_text, Vector(SCREEN_WIDTH - BORDER_X, BORDER_Y), RIGHT_ALLIGN, LAYER_HUD);
+ context.draw_text(gold_text, coins_text, Vector(SCREEN_WIDTH - BORDER_X, BORDER_Y), ALIGN_RIGHT, LAYER_HUD);
context.pop_transform();
}
MouseCursor::set_current(mouse_cursor);
/* Load global images: */
- gold_text = new Font("images/engine/fonts/gold.png",
+ gold_text = new Font(Font::FIXED,
+ "images/engine/fonts/gold.png",
"images/engine/fonts/shadow.png", 16, 18);
- blue_text = new Font("images/engine/fonts/blue.png",
+ blue_text = new Font(Font::FIXED,
+ "images/engine/fonts/blue.png",
"images/engine/fonts/shadow.png", 16, 18, 3);
// white_text = new Font("images/engine/fonts/white.png",
// "images/engine/fonts/shadow.png", 16, 18);
- white_text = new Font("images/engine/fonts/white.png", 16, 18);
- gray_text = new Font("images/engine/fonts/gray.png",
+ white_text = new Font(Font::VARIABLE,
+ "images/engine/fonts/white.png", 16, 18);
+ gray_text = new Font(Font::FIXED,
+ "images/engine/fonts/gray.png",
"images/engine/fonts/shadow.png", 16, 18);
- white_small_text = new Font("images/engine/fonts/white-small.png",
- "images/engine/fonts/shadow-small.png", 8, 9, 1);
- white_big_text = new Font("images/engine/fonts/white-big.png",
+ white_small_text = new Font(Font::VARIABLE,
+ "images/engine/fonts/white-small.png",
+ 8, 9);
+ // "images/engine/fonts/shadow-small.png", 8, 9, 1);
+ white_big_text = new Font(Font::FIXED,
+ "images/engine/fonts/white-big.png",
"images/engine/fonts/shadow-big.png", 20, 22, 3);
Menu::default_font = white_text;
// skip draw if stats were declared invalid
if (!valid) return;
- context.draw_text(white_small_text, std::string("- ") + _("Best Level Statistics") + " -", Vector((WMAP_INFO_LEFT_X + WMAP_INFO_RIGHT_X) / 2, WMAP_INFO_TOP_Y1), CENTER_ALLIGN, LAYER_GUI);
+ context.draw_text(white_small_text, std::string("- ") + _("Best Level Statistics") + " -", Vector((WMAP_INFO_LEFT_X + WMAP_INFO_RIGHT_X) / 2, WMAP_INFO_TOP_Y1), ALIGN_CENTER, LAYER_GUI);
float alpha;
if(timer.get_timegone() < FADING_TIME)
if (display_stat > 3) display_stat = 0;
}
- context.draw_text(white_small_text, caption_buf, Vector(WMAP_INFO_LEFT_X, WMAP_INFO_TOP_Y2), LEFT_ALLIGN, LAYER_GUI);
- context.draw_text(white_small_text, stat_buf, Vector(WMAP_INFO_RIGHT_X, WMAP_INFO_TOP_Y2), RIGHT_ALLIGN, LAYER_GUI);
+ context.draw_text(white_small_text, caption_buf, Vector(WMAP_INFO_LEFT_X, WMAP_INFO_TOP_Y2), ALIGN_LEFT, LAYER_GUI);
+ context.draw_text(white_small_text, stat_buf, Vector(WMAP_INFO_RIGHT_X, WMAP_INFO_TOP_Y2), ALIGN_RIGHT, LAYER_GUI);
context.pop_transform();
}
const float left = (SCREEN_WIDTH - width) / 2;
const float right = (SCREEN_WIDTH + width) / 2;
- context.draw_text(gold_text, title, Vector(SCREEN_WIDTH/2, 410), CENTER_ALLIGN, LAYER_GUI);
+ context.draw_text(gold_text, title, Vector(SCREEN_WIDTH/2, 410), ALIGN_CENTER, LAYER_GUI);
char stat_buf[128];
int py = 450 + 18;
snprintf(stat_buf, sizeof(stat_buf), "%d/%d", coins, total_coins);
- context.draw_text(white_small_text, _("Max coins collected:"), Vector(left, py), LEFT_ALLIGN, LAYER_GUI);
- context.draw_text(white_small_text, "%d / %d", Vector(right, py), RIGHT_ALLIGN, LAYER_GUI);
+ context.draw_text(white_small_text, _("Max coins collected:"), Vector(left, py), ALIGN_LEFT, LAYER_GUI);
+ context.draw_text(white_small_text, "%d / %d", Vector(right, py), ALIGN_RIGHT, LAYER_GUI);
py+=18;
snprintf(stat_buf, sizeof(stat_buf), "%d/%d", badguys, total_badguys);
- context.draw_text(white_small_text, _("Max fragging:"), Vector(left, py), LEFT_ALLIGN, LAYER_GUI);
- context.draw_text(white_small_text, "%d / %d", Vector(right, py), RIGHT_ALLIGN, LAYER_GUI);
+ context.draw_text(white_small_text, _("Max fragging:"), Vector(left, py), ALIGN_LEFT, LAYER_GUI);
+ context.draw_text(white_small_text, "%d / %d", Vector(right, py), ALIGN_RIGHT, LAYER_GUI);
py+=18;
int csecs = (int)(time * 100);
int mins = (int)(csecs / 6000);
int secs = (csecs % 6000) / 100;
snprintf(stat_buf, sizeof(stat_buf), "%02d:%02d", mins,secs);
- context.draw_text(white_small_text, _("Min time needed:"), Vector(left, py), LEFT_ALLIGN, LAYER_GUI);
- context.draw_text(white_small_text, "%02d:%02d", Vector(right, py), RIGHT_ALLIGN, LAYER_GUI);
+ context.draw_text(white_small_text, _("Min time needed:"), Vector(left, py), ALIGN_LEFT, LAYER_GUI);
+ context.draw_text(white_small_text, "%02d:%02d", Vector(right, py), ALIGN_RIGHT, LAYER_GUI);
py+=18;
snprintf(stat_buf, sizeof(stat_buf), "%d/%d", secrets, total_secrets);
- context.draw_text(white_small_text, _("Max secrets found:"), Vector(left, py), LEFT_ALLIGN, LAYER_GUI);
- context.draw_text(white_small_text, "%d / %d", Vector(right, py), RIGHT_ALLIGN, LAYER_GUI);
+ context.draw_text(white_small_text, _("Max secrets found:"), Vector(left, py), ALIGN_LEFT, LAYER_GUI);
+ context.draw_text(white_small_text, "%d / %d", Vector(right, py), ALIGN_RIGHT, LAYER_GUI);
py+=18;
}
context.pop_transform();
char buf[129];
- context.draw_text(white_text, _("You"), Vector(col2_x, row1_y), LEFT_ALLIGN, LAYER_GUI);
- context.draw_text(white_text, _("Best"), Vector(col3_x, row1_y), LEFT_ALLIGN, LAYER_GUI);
+ context.draw_text(white_text, _("You"), Vector(col2_x, row1_y), ALIGN_LEFT, LAYER_GUI);
+ context.draw_text(white_text, _("Best"), Vector(col3_x, row1_y), ALIGN_LEFT, LAYER_GUI);
- context.draw_text(white_text, _("Coins"), Vector(col2_x-16, row2_y), RIGHT_ALLIGN, LAYER_GUI);
+ context.draw_text(white_text, _("Coins"), Vector(col2_x-16, row2_y), ALIGN_RIGHT, LAYER_GUI);
snprintf(buf, sizeof(buf), "%d/%d", std::min(coins, 999), std::min(total_coins, 999));
- context.draw_text(gold_text, buf, Vector(col2_x, row2_y), LEFT_ALLIGN, LAYER_GUI);
+ context.draw_text(gold_text, buf, Vector(col2_x, row2_y), ALIGN_LEFT, LAYER_GUI);
if (best_stats && (best_stats->coins > coins)) {
snprintf(buf, sizeof(buf), "%d/%d", std::min(best_stats->coins, 999), std::min(best_stats->total_coins, 999));
}
- context.draw_text(gold_text, buf, Vector(col3_x, row2_y), LEFT_ALLIGN, LAYER_GUI);
+ context.draw_text(gold_text, buf, Vector(col3_x, row2_y), ALIGN_LEFT, LAYER_GUI);
- context.draw_text(white_text, _("Secrets"), Vector(col2_x-16, row4_y), RIGHT_ALLIGN, LAYER_GUI);
+ context.draw_text(white_text, _("Secrets"), Vector(col2_x-16, row4_y), ALIGN_RIGHT, LAYER_GUI);
snprintf(buf, sizeof(buf), "%d/%d", secrets, total_secrets);
- context.draw_text(gold_text, buf, Vector(col2_x, row4_y), LEFT_ALLIGN, LAYER_GUI);
+ context.draw_text(gold_text, buf, Vector(col2_x, row4_y), ALIGN_LEFT, LAYER_GUI);
if (best_stats && (best_stats->secrets > secrets)) {
snprintf(buf, sizeof(buf), "%d/%d", best_stats->secrets, best_stats->total_secrets);
}
- context.draw_text(gold_text, buf, Vector(col3_x, row4_y), LEFT_ALLIGN, LAYER_GUI);
+ context.draw_text(gold_text, buf, Vector(col3_x, row4_y), ALIGN_LEFT, LAYER_GUI);
- context.draw_text(white_text, _("Time"), Vector(col2_x-16, row3_y), RIGHT_ALLIGN, LAYER_GUI);
+ context.draw_text(white_text, _("Time"), Vector(col2_x-16, row3_y), ALIGN_RIGHT, LAYER_GUI);
int csecs = (int)(time * 100);
int mins = (int)(csecs / 6000);
int secs = (csecs % 6000) / 100;
snprintf(buf, sizeof(buf), "%02d:%02d", mins,secs);
- context.draw_text(gold_text, buf, Vector(col2_x, row3_y), LEFT_ALLIGN, LAYER_GUI);
+ context.draw_text(gold_text, buf, Vector(col2_x, row3_y), ALIGN_LEFT, LAYER_GUI);
if (best_stats && (best_stats->time < time)) {
int csecs = (int)(best_stats->time * 100);
int mins = (int)(csecs / 6000);
int secs = (csecs % 6000) / 100;
snprintf(buf, sizeof(buf), "%02d:%02d", mins,secs);
}
- context.draw_text(gold_text, buf, Vector(col3_x, row3_y), LEFT_ALLIGN, LAYER_GUI);
+ context.draw_text(gold_text, buf, Vector(col3_x, row3_y), ALIGN_LEFT, LAYER_GUI);
}
void
context.draw_surface(image, Vector( (SCREEN_WIDTH - image->get_width()) / 2, position.y), layer);
break;
case NORMAL_LEFT:
- context.draw_text(font, text, Vector(position.x, position.y), LEFT_ALLIGN, layer);
+ context.draw_text(font, text, Vector(position.x, position.y), ALIGN_LEFT, layer);
break;
default:
- context.draw_text(font, text, Vector(SCREEN_WIDTH/2, position.y), CENTER_ALLIGN, layer);
+ context.draw_text(font, text, Vector(SCREEN_WIDTH/2, position.y), ALIGN_CENTER, layer);
break;
}
}
Sector* sector = titlesession->get_current_sector();
sector->draw(context);
- context.draw_text(white_small_text, " SuperTux " PACKAGE_VERSION "\n",
- Vector(0, SCREEN_HEIGHT - 50), LEFT_ALLIGN, LAYER_FOREGROUND1);
+ context.draw_text(white_small_text, "SuperTux " PACKAGE_VERSION "\n",
+ Vector(5, SCREEN_HEIGHT - 50), ALIGN_LEFT, LAYER_FOREGROUND1);
context.draw_text(white_small_text,
_(
"Copyright (c) 2006 SuperTux Devel Team\n"
"This game comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to\n"
"redistribute it under certain conditions; see the file COPYING for details.\n"
),
- Vector(0, SCREEN_HEIGHT - 50 + white_small_text->get_height() + 5),
- LEFT_ALLIGN, LAYER_FOREGROUND1);
+ Vector(5, SCREEN_HEIGHT - 50 + white_small_text->get_height() + 5),
+ ALIGN_LEFT, LAYER_FOREGROUND1);
}
void
const Vector& position, int layer)
{
draw_text(font, text, Vector(position.x + SCREEN_WIDTH/2, position.y),
- CENTER_ALLIGN, layer);
+ ALIGN_CENTER, layer);
}
void
//
// SuperTux
// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+// Ingo Ruhnke <grumbel@gmx.de>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
bool has_multibyte_mark(unsigned char c);
uint32_t decode_utf8(const std::string& text, size_t& p);
+struct UTF8Iterator
+{
+ const std::string& text;
+ std::string::size_type pos;
+ uint32_t chr;
+
+ UTF8Iterator(const std::string& text_)
+ : text(text_),
+ pos(0)
+ {
+ chr = decode_utf8(text, pos);
+ }
+
+ bool done() const
+ {
+ return pos > text.size();
+ }
+
+ UTF8Iterator& operator++() {
+ try {
+ chr = decode_utf8(text, pos);
+ } catch (std::runtime_error) {
+ log_debug << "Malformed utf-8 sequence beginning with " << *((uint32_t*)(text.c_str() + pos)) << " found " << std::endl;
+ chr = 0;
+ ++pos;
+ }
+
+ return *this;
+ }
+
+ uint32_t operator*() const {
+ return chr;
+ }
+};
+
bool vline_empty(SDL_Surface* surface, int x, int start_y, int end_y, Uint8 threshold)
{
Uint8* pixels = (Uint8*)surface->pixels;
}
} // namespace
-Font::Font(const std::string& file, const std::string& shadowfile,
- int w, int h, int shadowsize)
- : glyph_surface(0), shadow_chars(0),
- char_width(w), char_height(h),
+Font::Font(GlyphWidth glyph_width_,
+ const std::string& file, const std::string& shadowfile,
+ int char_width, int char_height_, int shadowsize)
+ : glyph_width(glyph_width_),
+ glyph_surface(0), shadow_chars(0),
+ char_height(char_height_),
shadowsize(shadowsize)
{
glyph_surface = new Surface(file);
}
}
-Font::Font(const std::string& filename, int char_width_, int char_height_)
- : glyph_surface(0), shadow_chars(0),
- char_width(char_width_), char_height(char_height_),
+Font::Font(GlyphWidth glyph_width_, const std::string& filename, int char_width, int char_height_)
+ : glyph_width(glyph_width_),
+ glyph_surface(0), shadow_chars(0),
+ char_height(char_height_),
shadowsize(0)
{
glyph_surface = new Surface(filename);
float curr_width = 0;
float last_width = 0;
- // FIXME: add UTF8 decode here
- for(std::string::size_type i = 0; i < text.size(); ++i)
+ for(UTF8Iterator it(text); !it.done(); ++it)
{
- uint32_t chr = text[i];
- if (chr == '\n')
+ if (*it == '\n')
{
last_width = std::max(last_width, curr_width);
curr_width = 0;
}
else
{
- curr_width += glyphs[static_cast<unsigned char>(text[i])].get_width() + 1;
+ int idx = chr2glyph(*it);
+ curr_width += glyphs[idx].get_width();
}
}
{
std::string::size_type text_height = char_height;
- for(std::string::size_type i = 0; i < text.size(); ++i)
- {
- if (i == '\n')
+ for(std::string::const_iterator it = text.begin(); it != text.end(); ++it)
+ { // since UTF8 multibyte characters are decoded with values
+ // outside the ASCII range there is no risk of overlapping and
+ // thus we don't need to decode the utf-8 string
+ if (*it == '\n')
text_height += char_height + 2;
}
Font::draw(const std::string& text, const Vector& pos_, FontAlignment alignment,
DrawingEffect drawing_effect, float alpha) const
{
- /* Cut lines changes into seperate strings, needed to support center/right text
- alignments with break lines.
- Feel free to replace this hack with a more elegant solution
- */
- char temp[1024];
- std::string::size_type l, i, y;
- bool done = false;
- i = y = 0;
-
- while(!done) {
- l = text.find("\n", i);
- if(l == std::string::npos) {
- l = text.size();
- done = true;
- }
-
- if(l > sizeof(temp)-1)
- l = sizeof(temp)-1;
-
- temp[text.copy(temp, l - i, i)] = '\0';
-
- // calculate X positions based on the alignment type
- Vector pos = Vector(pos_);
- if(alignment == CENTER_ALLIGN)
- pos.x -= get_text_width(temp) / 2;
- else if(alignment == RIGHT_ALLIGN)
- pos.x -= get_text_width(temp);
-
- draw_text(temp, pos + Vector(0,y), drawing_effect, alpha);
+ float x = pos_.x;
+ float y = pos_.y;
- i = l+1;
- y += char_height + 2;
- }
+ std::string::size_type last = 0;
+ for(std::string::size_type i = 0;; ++i)
+ {
+ if (text[i] == '\n' || i == text.size())
+ {
+ std::string temp = text.substr(last, i - last);
+
+ // calculate X positions based on the alignment type
+ Vector pos = Vector(x, y);
+
+ if(alignment == ALIGN_CENTER)
+ pos.x -= get_text_width(temp) / 2;
+ else if(alignment == ALIGN_RIGHT)
+ pos.x -= get_text_width(temp);
+
+ draw_text(temp, pos, drawing_effect, alpha);
+
+ if (i == text.size())
+ break;
+
+ y += char_height + 2;
+ last = i + 1;
+ }
+ }
}
void
draw_chars(glyph_surface, text, pos, drawing_effect, alpha);
}
+int
+Font::chr2glyph(uint32_t chr) const
+{
+ int glyph_index = chr - first_char;
+
+ // we don't have the control chars 0x80-0xa0 in the font
+ if (chr >= 0x80) { // non-ascii character
+ glyph_index -= 32;
+ if(chr <= 0xa0) {
+ log_debug << "Unsupported utf-8 character '" << chr << "' found" << std::endl;
+ glyph_index = 0;
+ }
+ }
+
+ if(glyph_index < 0 || glyph_index >= (int) char_count) {
+ log_debug << "Unsupported utf-8 character found" << std::endl;
+ glyph_index = 0;
+ }
+
+ return glyph_index;
+}
+
void
Font::draw_chars(Surface* pchars, const std::string& text, const Vector& pos,
DrawingEffect drawing_effect, float alpha) const
{
Vector p = pos;
- size_t i = 0;
- while(i < text.size()) {
- uint32_t c;
- try {
- c = decode_utf8(text, i); // FIXME: this seems wrong, since when incrementing i by
- }
- catch (std::runtime_error) {
- log_debug << "Malformed utf-8 sequence beginning with " << *((uint32_t*)(text.c_str() + i)) << " found " << std::endl;
- c = 0;
- i++;
- }
-
- int font_index = c - first_char;
-
- // a non-printable character?
- if(c == '\n') {
- p.x = pos.x;
- p.y += char_height + 2;
- continue;
- }
- if(c == ' ') {
- p.x += glyphs[font_index].get_width();
- continue;
- }
-
- // we don't have the control chars 0x80-0xa0 in the font
- if (c >= 0x80) {
- font_index -= 32;
- if(c <= 0xa0) {
- log_debug << "Unsupported utf-8 character '" << c << "' found" << std::endl;
- font_index = 0;
- }
- }
+ for(UTF8Iterator it(text); !it.done(); ++it)
+ {
+ int font_index = chr2glyph(*it);
- if(font_index < 0 || font_index >= (int) char_count) {
- log_debug << "Unsupported utf-8 character found" << std::endl;
- font_index = 0;
+ if(*it == '\n')
+ {
+ p.x = pos.x;
+ p.y += char_height + 2;
+ }
+ else if(*it == ' ')
+ {
+ p.x += glyphs[font_index].get_width();
+ }
+ else
+ {
+ const Rect& glyph = glyphs[font_index];
+ pchars->draw_part(glyph.get_left(), glyph.get_top(),
+ p.x, p.y,
+ glyph.get_width(), glyph.get_height(),
+ alpha, drawing_effect);
+ p.x += glyphs[font_index].get_width();
+ }
}
-
- const Rect& glyph = glyphs[font_index];
- pchars->draw_part(glyph.get_left(), glyph.get_top(),
- p.x, p.y,
- glyph.get_width(), glyph.get_height(),
- alpha, drawing_effect);
- p.x += glyphs[font_index].get_width();
- }
}
}
/**
- * gets unicode character at byte position @a p of UTF-8 encoded @a text, then advances @a p to the next character.
+ * gets unicode character at byte position @a p of UTF-8 encoded @a
+ * text, then advances @a p to the next character.
+ *
* @throws std::runtime_error if decoding fails.
* See unicode standard section 3.10 table 3-5 and 3-6 for details.
*/
// $Id$
//
// SuperTux
-// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+// Copyright (C) 2006 Matthias Braun <matze@braunis.de>,
+// Ingo Ruhnke <grumbel@gmx.de>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
#include "math/rect.hpp"
enum FontAlignment {
- LEFT_ALLIGN,
- CENTER_ALLIGN,
- RIGHT_ALLIGN
+ ALIGN_LEFT,
+ ALIGN_CENTER,
+ ALIGN_RIGHT
};
class Font
{
public:
+ enum GlyphWidth {
+ FIXED,
+ VARIABLE
+ };
+
/** Construct a fixed-width font
*
* @param file image file containing the characters
* @param w width of a character
* @param h height of a character
*/
- Font(const std::string& file, const std::string& shadowfile,
+ Font(GlyphWidth glyph_width, const std::string& file, const std::string& shadowfile,
int w, int h, int shadowsize = 2);
/** Construct a variable-width font
*
* @param file image file containing the characters
*/
- Font(const std::string& file, int char_width, int char_height);
+ Font(GlyphWidth glyph_width, const std::string& filename,
+ int char_width, int char_height);
~Font();
/** Draws the given text to the screen. Also needs the position.
* Type of alignment, drawing effect and alpha are optional. */
void draw(const std::string& text, const Vector& pos,
- FontAlignment allignment = LEFT_ALLIGN,
+ FontAlignment allignment = ALIGN_LEFT,
DrawingEffect drawing_effect = NO_EFFECT,
float alpha = 1.0f) const;
const Vector& position, DrawingEffect drawing_effect,
float alpha) const;
- Surface* glyph_surface;
- Surface* shadow_chars;
- int char_width;
+ /** Convert a Unicode character code to the index of its glyph */
+ int chr2glyph(uint32_t chr) const;
+
+ GlyphWidth glyph_width;
+ Surface* glyph_surface;
+ Surface* shadow_chars;
int char_height;
int shadowsize;
get_level_title(*level);
context.draw_text(white_text, level->title,
- Vector(SCREEN_WIDTH/2,
- SCREEN_HEIGHT - white_text->get_height() - 30),
- CENTER_ALLIGN, LAYER_FOREGROUND1);
+ Vector(SCREEN_WIDTH/2,
+ SCREEN_HEIGHT - white_text->get_height() - 30),
+ ALIGN_CENTER, LAYER_FOREGROUND1);
// if level is solved, draw level picture behind stats
/*
context.draw_text(gold_text, special_tile->map_message,
Vector(SCREEN_WIDTH/2,
SCREEN_HEIGHT - white_text->get_height() - 60),
- CENTER_ALLIGN, LAYER_FOREGROUND1);
+ ALIGN_CENTER, LAYER_FOREGROUND1);
break;
}
}
Teleporter* teleporter = at_teleporter(tux->get_tile_pos());
if (teleporter && (teleporter->message != "")) {
Vector pos = Vector(SCREEN_WIDTH/2, SCREEN_HEIGHT - white_text->get_height() - 30);
- context.draw_text(white_text, teleporter->message, pos, CENTER_ALLIGN, LAYER_FOREGROUND1);
+ context.draw_text(white_text, teleporter->message, pos, ALIGN_CENTER, LAYER_FOREGROUND1);
}
}
if(passive_message_timer.started())
context.draw_text(gold_text, passive_message,
Vector(SCREEN_WIDTH/2, SCREEN_HEIGHT - white_text->get_height() - 60),
- CENTER_ALLIGN, LAYER_FOREGROUND1);
+ ALIGN_CENTER, LAYER_FOREGROUND1);
context.pop_transform();
}