improved the font system even futher. utf8 is now used everywhere. it uses less memory as well

This commit is contained in:
Magnus Auvinen 2009-06-13 08:22:37 +00:00
parent 9254ca61f1
commit 69511102de
11 changed files with 333 additions and 174 deletions

View file

@ -1188,6 +1188,139 @@ void gui_messagebox(const char *title, const char *message)
int str_isspace(char c) { return c == ' ' || c == '\n' || c == '\t'; } int str_isspace(char c) { return c == ' ' || c == '\n' || c == '\t'; }
static int str_utf8_isstart(char c)
{
if((c&0xC0) == 0x80) /* 10xxxxxx */
return 0;
return 1;
}
int str_utf8_rewind(const char *str, int cursor)
{
while(cursor)
{
cursor--;
if(str_utf8_isstart(*(str + cursor)))
break;
}
return cursor;
}
int str_utf8_forward(const char *str, int cursor)
{
const char *buf = str + cursor;
if(!buf[0])
return cursor;
if((*buf&0x80) == 0x0) /* 0xxxxxxx */
return cursor+1;
else if((*buf&0xE0) == 0xC0) /* 110xxxxx */
{
if(!buf[1]) return cursor+1;
return cursor+2;
}
else if((*buf & 0xF0) == 0xE0) /* 1110xxxx */
{
if(!buf[1]) return cursor+1;
if(!buf[2]) return cursor+2;
return cursor+2;
}
else if((*buf & 0xF8) == 0xF0) /* 11110xxx */
{
if(!buf[1]) return cursor+1;
if(!buf[2]) return cursor+2;
if(!buf[3]) return cursor+3;
return cursor+3;
}
/* invalid */
return cursor+1;
}
int str_utf8_encode(char *ptr, int chr)
{
/* encode */
if(chr <= 0x7F)
{
ptr[0] = (char)chr;
return 1;
}
else if(chr <= 0x7FF)
{
ptr[0] = 0xC0|((chr>>6)&0x1F);
ptr[1] = 0x80|(chr&0x3F);
return 2;
}
else if(chr <= 0xFFFF)
{
ptr[0] = 0xE0|((chr>>12)&0x0F);
ptr[1] = 0xC0|((chr>>6)&0x3F);
ptr[2] = 0xC0|(chr&0x3F);
return 3;
}
else if(chr <= 0x10FFFF)
{
ptr[0] = 0xF0|((chr>>18)&0x07);
ptr[1] = 0xC0|((chr>>12)&0x3F);
ptr[2] = 0xC0|((chr>>6)&0x3F);
ptr[3] = 0xC0|(chr&0x3F);
return 4;
}
return 0;
}
int str_utf8_decode(const char **ptr)
{
const char *buf = *ptr;
int ch = 0;
do
{
if((*buf&0x80) == 0x0) /* 0xxxxxxx */
{
ch = *buf;
buf++;
}
else if((*buf&0xE0) == 0xC0) /* 110xxxxx */
{
ch = (*buf++ & 0x3F) << 6; if(!(*buf)) break;
ch += (*buf++ & 0x3F);
if(ch == 0) ch = -1;
}
else if((*buf & 0xF0) == 0xE0) /* 1110xxxx */
{
ch = (*buf++ & 0x1F) << 12; if(!(*buf)) break;
ch += (*buf++ & 0x3F) << 6; if(!(*buf)) break;
ch += (*buf++ & 0x3F);
if(ch == 0) ch = -1;
}
else if((*buf & 0xF8) == 0xF0) /* 11110xxx */
{
ch = (*buf++ & 0x0F) << 18; if(!(*buf)) break;
ch += (*buf++ & 0x3F) << 12; if(!(*buf)) break;
ch += (*buf++ & 0x3F) << 6; if(!(*buf)) break;
ch += (*buf++ & 0x3F);
if(ch == 0) ch = -1;
}
else
{
/* invalid */
buf++;
break;
}
*ptr = buf;
return ch;
} while(0);
/* out of bounds */
*ptr = buf;
return -1;
}
#if defined(__cplusplus) #if defined(__cplusplus)
} }
#endif #endif

View file

@ -947,6 +947,69 @@ int str_isspace(char c);
*/ */
void gui_messagebox(const char *title, const char *message); void gui_messagebox(const char *title, const char *message);
/*
Function: str_utf8_rewind
Moves a cursor backwards in an utf8 string
Parameters:
str - utf8 string
cursor - position in the string
Returns:
New cursor position.
Remarks:
- Won't move the cursor less then 0
*/
int str_utf8_rewind(const char *str, int cursor);
/*
Function: str_utf8_forward
Moves a cursor forwards in an utf8 string
Parameters:
str - utf8 string
cursor - position in the string
Returns:
New cursor position.
Remarks:
- Won't move the cursor beyond the zero termination marker
*/
int str_utf8_forward(const char *str, int cursor);
/*
Function: str_utf8_decode
Decodes an utf8 character
Parameters:
ptr - pointer to an utf8 string. this pointer will be moved forward
Returns:
Unicode value for the character. -1 for invalid characters and 0 for end of string.
Remarks:
- This function will also move the pointer forward.
*/
int str_utf8_decode(const char **ptr);
/*
Function: str_utf8_encode
Encode an utf8 character
Parameters:
ptr - Pointer to a buffer that should recive the data. Should be able to hold at least 4 bytes.
Returns:
Number of bytes put into the buffer.
Remarks:
- Does not do zero termination of the string.
*/
int str_utf8_encode(char *ptr, int chr);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -121,6 +121,9 @@ typedef struct FONTSIZEDATA
int num_x_chars; int num_x_chars;
int num_y_chars; int num_y_chars;
int char_max_width;
int char_max_height;
FONTCHAR characters[MAX_CHARACTERS*MAX_CHARACTERS]; FONTCHAR characters[MAX_CHARACTERS*MAX_CHARACTERS];
int current_character; int current_character;
@ -201,35 +204,87 @@ static void grow(unsigned char *in, unsigned char *out, int w, int h)
} }
} }
static void font_init_texture(FONTSIZEDATA *font, int width, int height) static void font_init_texture(FONTSIZEDATA *sizedata, int charwidth, int charheight, int xchars, int ychars)
{ {
static int font_memory_usage = 0;
int i; int i;
int width = charwidth*xchars;
int height = charheight*ychars;
void *mem = mem_alloc(width*height, 1); void *mem = mem_alloc(width*height, 1);
mem_zero(mem, width*height); mem_zero(mem, width*height);
font->texture_width = width; if(sizedata->textures[0] == 0)
font->texture_height = height; glGenTextures(2, sizedata->textures);
font->num_x_chars = 32; else
font->num_y_chars = 32; font_memory_usage -= sizedata->texture_width*sizedata->texture_height*2;
font->current_character = 0;
glGenTextures(2, font->textures); sizedata->num_x_chars = xchars;
sizedata->num_y_chars = ychars;
sizedata->texture_width = width;
sizedata->texture_height = height;
sizedata->current_character = 0;
for(i = 0; i < 2; i++) for(i = 0; i < 2; i++)
{ {
glBindTexture(GL_TEXTURE_2D, font->textures[i]); glBindTexture(GL_TEXTURE_2D, sizedata->textures[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, font_texture_format, width, height, 0, font_texture_format, GL_UNSIGNED_BYTE, mem); glTexImage2D(GL_TEXTURE_2D, 0, font_texture_format, width, height, 0, font_texture_format, GL_UNSIGNED_BYTE, mem);
font_memory_usage += width*height;
} }
dbg_msg("", "font memory usage: %d", font_memory_usage);
mem_free(mem); mem_free(mem);
} }
static void font_increase_texture_size(FONTSIZEDATA *sizedata)
{
if(sizedata->texture_width < sizedata->texture_height)
sizedata->num_x_chars <<= 1;
else
sizedata->num_y_chars <<= 1;
font_init_texture(sizedata, sizedata->char_max_width, sizedata->char_max_height, sizedata->num_x_chars, sizedata->num_y_chars);
}
static void font_init_index(FONT *font, int index) static void font_init_index(FONT *font, int index)
{ {
font->sizes[index].font_size = font_sizes[index]; int outline_thickness = 1;
FONTSIZEDATA *sizedata = &font->sizes[index];
sizedata->font_size = font_sizes[index];
FT_Set_Pixel_Sizes(font->ft_face, 0, sizedata->font_size);
if(sizedata->font_size >= 18)
outline_thickness = 2;
{
unsigned glyph_index;
int charcode;
int max_h = 0;
int max_w = 0;
charcode = FT_Get_First_Char(font->ft_face, &glyph_index);
while(glyph_index != 0)
{
/* do stuff */
FT_Load_Glyph(font->ft_face, glyph_index, FT_LOAD_DEFAULT);
if(font->ft_face->glyph->metrics.width > max_w) max_w = font->ft_face->glyph->metrics.width;
if(font->ft_face->glyph->metrics.height > max_h) max_h = font->ft_face->glyph->metrics.height;
charcode = FT_Get_Next_Char(font->ft_face, charcode, &glyph_index);
}
max_w = (max_w>>6)+2+outline_thickness*2;
max_h = (max_h>>6)+2+outline_thickness*2;
for(sizedata->char_max_width = 1; sizedata->char_max_width < max_w; sizedata->char_max_width <<= 1);
for(sizedata->char_max_height = 1; sizedata->char_max_height < max_h; sizedata->char_max_height <<= 1);
}
//dbg_msg("font", "init size %d, texture size %d %d", font->sizes[index].font_size, w, h);
//FT_New_Face(ft_library, "data/fonts/vera.ttf", 0, &font->ft_face); //FT_New_Face(ft_library, "data/fonts/vera.ttf", 0, &font->ft_face);
font_init_texture(&font->sizes[index], 1024*2, 1024*2); font_init_texture(sizedata, sizedata->char_max_width, sizedata->char_max_height, 8, 8);
} }
static FONTSIZEDATA *font_get_size(FONT *font, int pixelsize) static FONTSIZEDATA *font_get_size(FONT *font, int pixelsize)
@ -279,6 +334,13 @@ static int font_get_slot(FONTSIZEDATA *sizedata)
if(sizedata->characters[i].touch_time < sizedata->characters[oldest].touch_time) if(sizedata->characters[i].touch_time < sizedata->characters[oldest].touch_time)
oldest = i; oldest = i;
} }
if(time_get()-sizedata->characters[oldest].touch_time < time_freq())
{
font_increase_texture_size(sizedata);
return font_get_slot(sizedata);
}
return oldest; return oldest;
} }
} }
@ -286,7 +348,7 @@ static int font_get_slot(FONTSIZEDATA *sizedata)
static int font_render_glyph(FONT *font, FONTSIZEDATA *sizedata, int chr) static int font_render_glyph(FONT *font, FONTSIZEDATA *sizedata, int chr)
{ {
FT_Bitmap *bitmap; FT_Bitmap *bitmap;
int slot_id = sizedata->current_character; int slot_id = 0;
int slot_w = sizedata->texture_width / sizedata->num_x_chars; int slot_w = sizedata->texture_width / sizedata->num_x_chars;
int slot_h = sizedata->texture_height / sizedata->num_y_chars; int slot_h = sizedata->texture_height / sizedata->num_y_chars;
int slot_size = slot_w*slot_h; int slot_size = slot_w*slot_h;
@ -297,7 +359,7 @@ static int font_render_glyph(FONT *font, FONTSIZEDATA *sizedata, int chr)
FT_Set_Pixel_Sizes(font->ft_face, 0, sizedata->font_size); FT_Set_Pixel_Sizes(font->ft_face, 0, sizedata->font_size);
if(FT_Load_Char(font->ft_face, chr, FT_LOAD_RENDER)) if(FT_Load_Char(font->ft_face, chr, FT_LOAD_RENDER|FT_LOAD_NO_BITMAP))
{ {
dbg_msg("font", "error loading glyph %d", chr); dbg_msg("font", "error loading glyph %d", chr);
return -1; return -1;
@ -412,7 +474,7 @@ static FONTCHAR *font_get_char(FONT *font, FONTSIZEDATA *sizedata, int chr)
} }
/* must only be called from the rendering function as the font must be set to the correct size */ /* must only be called from the rendering function as the font must be set to the correct size */
static void font_setsize(FONT *font, int size) static void font_render_setup(FONT *font, int size)
{ {
FT_Set_Pixel_Sizes(font->ft_face, 0, size); FT_Set_Pixel_Sizes(font->ft_face, 0, size);
} }
@ -424,53 +486,6 @@ static float font_kerning(FONT *font, int left, int right)
return (kerning.x>>6); return (kerning.x>>6);
} }
static int utf8_decode(const unsigned char **ptr)
{
const unsigned char *buf = *ptr;
int ch = 0;
do
{
if((*buf&0x80) == 0x0) /* 0xxxxxxx */
{
ch = *buf;
buf++;
}
else if((*buf&0xE0) == 0xC0) /* 110xxxxx */
{
ch = (*buf++ & 0x3F) << 6; if(!(*buf)) break;
ch += (*buf++ & 0x3F);
if(ch == 0) ch = -1;
}
else if((*buf & 0xF0) == 0xE0) /* 1110xxxx */
{
ch = (*buf++ & 0x1F) << 12; if(!(*buf)) break;
ch += (*buf++ & 0x3F) << 6; if(!(*buf)) break;
ch += (*buf++ & 0x3F);
if(ch == 0) ch = -1;
}
else if((*buf & 0xF8) == 0xF0) /* 11110xxx */
{
ch = (*buf++ & 0x0F) << 18; if(!(*buf)) break;
ch += (*buf++ & 0x3F) << 12; if(!(*buf)) break;
ch += (*buf++ & 0x3F) << 6; if(!(*buf)) break;
ch += (*buf++ & 0x3F);
if(ch == 0) ch = -1;
}
else
break;
/* valid */
*ptr = buf;
return ch;
} while(0);
/* invalid */
*ptr = buf;
return -1;
}
void gfx_text_ex(TEXT_CURSOR *cursor, const char *text, int length) void gfx_text_ex(TEXT_CURSOR *cursor, const char *text, int length)
{ {
FONT *font = cursor->font; FONT *font = cursor->font;
@ -512,7 +527,7 @@ void gfx_text_ex(TEXT_CURSOR *cursor, const char *text, int length)
return; return;
sizedata = font_get_size(font, actual_size); sizedata = font_get_size(font, actual_size);
font_setsize(font, actual_size); font_render_setup(font, actual_size);
/* set length */ /* set length */
if(length < 0) if(length < 0)
@ -527,8 +542,8 @@ void gfx_text_ex(TEXT_CURSOR *cursor, const char *text, int length)
for(;i < 2; i++) for(;i < 2; i++)
{ {
const unsigned char *current = (unsigned char *)text; const char *current = (char *)text;
const unsigned char *end = current+length; const char *end = current+length;
//int to_render = length; //int to_render = length;
draw_x = cursor_x; draw_x = cursor_x;
draw_y = cursor_y; draw_y = cursor_y;
@ -553,7 +568,7 @@ void gfx_text_ex(TEXT_CURSOR *cursor, const char *text, int length)
{ {
int new_line = 0; int new_line = 0;
//int this_batch = (int)(end-current); //int this_batch = (int)(end-current);
const unsigned char *batch_end = end; const char *batch_end = end;
if(cursor->line_width > 0 && !(cursor->flags&TEXTFLAG_STOP_AT_END)) if(cursor->line_width > 0 && !(cursor->flags&TEXTFLAG_STOP_AT_END))
{ {
int wlen = word_length((char *)current); int wlen = word_length((char *)current);
@ -599,19 +614,23 @@ void gfx_text_ex(TEXT_CURSOR *cursor, const char *text, int length)
while(current < batch_end) while(current < batch_end)
{ {
const char *tmp;
float advance = 0; float advance = 0;
int character = 0; int character = 0;
int nextcharacter = 0;
FONTCHAR *chr; FONTCHAR *chr;
// TODO: UTF-8 decode // TODO: UTF-8 decode
character = utf8_decode(&current); character = str_utf8_decode(&current);
tmp = current;
nextcharacter = str_utf8_decode(&tmp);
if(character == '\n') if(character == '\n')
{ {
draw_x = cursor->start_x; draw_x = cursor->start_x;
draw_y += size; draw_y += size;
draw_x = (int)(draw_x * fake_to_screen_x) / fake_to_screen_x; /* realign */ draw_x = (int)(draw_x * fake_to_screen_x) / fake_to_screen_x; /* realign */
draw_y = (int)(draw_y * fake_to_screen_y) / fake_to_screen_y; draw_y = (int)(draw_y * fake_to_screen_y) / fake_to_screen_y;
/* current++; */
continue; continue;
} }
@ -625,7 +644,7 @@ void gfx_text_ex(TEXT_CURSOR *cursor, const char *text, int length)
gfx_quads_drawTL(draw_x+chr->offset_x*size, draw_y+chr->offset_y*size, chr->width*size, chr->height*size); gfx_quads_drawTL(draw_x+chr->offset_x*size, draw_y+chr->offset_y*size, chr->width*size, chr->height*size);
} }
advance = chr->advance_x; /* + font_kerning(font, character, *(current+1));*/ advance = chr->advance_x + font_kerning(font, character, nextcharacter)/size;
} }
if(cursor->flags&TEXTFLAG_STOP_AT_END && draw_x+advance*size-cursor->start_x > cursor->line_width) if(cursor->flags&TEXTFLAG_STOP_AT_END && draw_x+advance*size-cursor->start_x > cursor->line_width)

View file

@ -49,11 +49,11 @@ enum
static INPUT_EVENT input_events[INPUT_BUFFER_SIZE]; static INPUT_EVENT input_events[INPUT_BUFFER_SIZE];
static int num_events = 0; static int num_events = 0;
static void add_event(char c, int key, int flags) static void add_event(int unicode, int key, int flags)
{ {
if(num_events != INPUT_BUFFER_SIZE) if(num_events != INPUT_BUFFER_SIZE)
{ {
input_events[num_events].ch = c; input_events[num_events].unicode = unicode;
input_events[num_events].key = key; input_events[num_events].key = key;
input_events[num_events].flags = flags; input_events[num_events].flags = flags;
num_events++; num_events++;
@ -178,7 +178,7 @@ void inp_update()
{ {
/* handle keys */ /* handle keys */
case SDL_KEYDOWN: case SDL_KEYDOWN:
if(event.key.keysym.unicode < 255) /*if(event.key.keysym.unicode < 255) */
add_event(event.key.keysym.unicode, 0, 0); add_event(event.key.keysym.unicode, 0, 0);
key = event.key.keysym.sym; key = event.key.keysym.sym;
break; break;

View file

@ -671,5 +671,4 @@ void gfx_text_ex(TEXT_CURSOR *cursor, const char *text, int length);
struct FONT *gfx_font_load(const char *filename); struct FONT *gfx_font_load(const char *filename);
void gfx_font_destroy(struct FONT *font); void gfx_font_destroy(struct FONT *font);
#endif #endif

View file

@ -20,7 +20,7 @@ enum
typedef struct typedef struct
{ {
int flags; int flags;
unsigned char ch; int unicode;
int key; int key;
} INPUT_EVENT; } INPUT_EVENT;

View file

@ -18,6 +18,7 @@
#include <game/generated/gc_data.hpp> #include <game/generated/gc_data.hpp>
#include <game/client/gameclient.hpp> #include <game/client/gameclient.hpp>
#include <game/client/lineinput.hpp>
#include <mastersrv/mastersrv.h> #include <mastersrv/mastersrv.h>
vec4 MENUS::gui_color; vec4 MENUS::gui_color;
@ -199,7 +200,7 @@ void MENUS::ui_draw_checkbox_number(const void *id, const char *text, int checke
ui_draw_checkbox_common(id, text, buf, r); ui_draw_checkbox_common(id, text, buf, r);
} }
int MENUS::ui_do_edit_box(void *id, const RECT *rect, char *str, int str_size, float font_size, bool hidden) int MENUS::ui_do_edit_box(void *id, const RECT *rect, char *str, unsigned str_size, float font_size, bool hidden)
{ {
int inside = ui_mouse_inside(rect); int inside = ui_mouse_inside(rect);
int r = 0; int r = 0;
@ -229,48 +230,7 @@ int MENUS::ui_do_edit_box(void *id, const RECT *rect, char *str, int str_size, f
for(int i = 0; i < num_inputevents; i++) for(int i = 0; i < num_inputevents; i++)
{ {
len = strlen(str); len = strlen(str);
INPUT_EVENT e = inputevents[i]; LINEINPUT::manipulate(inputevents[i], str, str_size, &len, &at_index);
char c = e.ch;
int k = e.key;
if (at_index > len)
at_index = len;
if (!(c >= 0 && c < 32) && c != 127)
{
if (len < str_size - 1 && at_index < str_size - 1)
{
memmove(str + at_index + 1, str + at_index, len - at_index + 1);
str[at_index] = c;
at_index++;
r = 1;
}
}
if(e.flags&INPFLAG_PRESS)
{
if (k == KEY_BACKSPACE && at_index > 0)
{
memmove(str + at_index - 1, str + at_index, len - at_index + 1);
at_index--;
r = 1;
}
else if (k == KEY_DELETE && at_index < len)
{
memmove(str + at_index, str + at_index + 1, len - at_index);
r = 1;
}
else if (k == KEY_RETURN)
ui_clear_last_active_item();
else if (k == KEY_LEFT && at_index > 0)
at_index--;
else if (k == KEY_RIGHT && at_index < len)
at_index++;
else if (k == KEY_HOME)
at_index = 0;
else if (k == KEY_END)
at_index = len;
}
} }
} }

View file

@ -40,7 +40,7 @@ class MENUS : public COMPONENT
static void ui_draw_checkbox_common(const void *id, const char *text, const char *boxtext, const RECT *r); static void ui_draw_checkbox_common(const void *id, const char *text, const char *boxtext, const RECT *r);
static void ui_draw_checkbox(const void *id, const char *text, int checked, const RECT *r, const void *extra); static void ui_draw_checkbox(const void *id, const char *text, int checked, const RECT *r, const void *extra);
static void ui_draw_checkbox_number(const void *id, const char *text, int checked, const RECT *r, const void *extra); static void ui_draw_checkbox_number(const void *id, const char *text, int checked, const RECT *r, const void *extra);
static int ui_do_edit_box(void *id, const RECT *rect, char *str, int str_size, float font_size, bool hidden=false); static int ui_do_edit_box(void *id, const RECT *rect, char *str, unsigned str_size, float font_size, bool hidden=false);
static float ui_do_scrollbar_v(const void *id, const RECT *rect, float current); static float ui_do_scrollbar_v(const void *id, const RECT *rect, float current);
static float ui_do_scrollbar_h(const void *id, const RECT *rect, float current); static float ui_do_scrollbar_h(const void *id, const RECT *rect, float current);

View file

@ -21,23 +21,30 @@ void LINEINPUT::set(const char *string)
cursor_pos = len; cursor_pos = len;
} }
void LINEINPUT::process_input(INPUT_EVENT e) void LINEINPUT::manipulate(INPUT_EVENT e, char *str, int str_max_size, int *str_len_ptr, int *cursor_pos_ptr)
{ {
int cursor_pos = *cursor_pos_ptr;
int len = *str_len_ptr;
if(cursor_pos > len) if(cursor_pos > len)
cursor_pos = len; cursor_pos = len;
char c = e.ch; int code = e.unicode;
int k = e.key; int k = e.key;
// 127 is produced on Mac OS X and corresponds to the delete key // 127 is produced on Mac OS X and corresponds to the delete key
if (!(c >= 0 && c < 32) && c != 127) if (!(code >= 0 && code < 32) && code != 127)
{ {
if (len < sizeof(str) - 1 && cursor_pos < sizeof(str) - 1) char tmp[8];
int charsize = str_utf8_encode(tmp, code);
if (len < str_max_size - charsize && cursor_pos < str_max_size - charsize)
{ {
memmove(str + cursor_pos + 1, str + cursor_pos, len - cursor_pos + 1); memmove(str + cursor_pos + charsize, str + cursor_pos, len - cursor_pos + charsize);
str[cursor_pos] = c; for(int i = 0; i < charsize; i++)
cursor_pos++; str[cursor_pos+i] = tmp[i];
len++; cursor_pos += charsize;
len += charsize;
} }
} }
@ -45,22 +52,34 @@ void LINEINPUT::process_input(INPUT_EVENT e)
{ {
if (k == KEY_BACKSPACE && cursor_pos > 0) if (k == KEY_BACKSPACE && cursor_pos > 0)
{ {
memmove(str + cursor_pos - 1, str + cursor_pos, len - cursor_pos + 1); int new_cursor_pos = str_utf8_rewind(str, cursor_pos);
cursor_pos--; int charsize = cursor_pos-new_cursor_pos;
len--; memmove(str+new_cursor_pos, str+cursor_pos, len - charsize + 1); // +1 == null term
cursor_pos = new_cursor_pos;
len -= charsize;
} }
else if (k == KEY_DELETE && cursor_pos < len) else if (k == KEY_DELETE && cursor_pos < len)
{ {
memmove(str + cursor_pos, str + cursor_pos + 1, len - cursor_pos); int p = str_utf8_forward(str, cursor_pos);
len--; int charsize = p-cursor_pos;
memmove(str + cursor_pos, str + cursor_pos + charsize, len - cursor_pos - charsize + 1); // +1 == null term
len -= charsize;
} }
else if (k == KEY_LEFT && cursor_pos > 0) else if (k == KEY_LEFT && cursor_pos > 0)
cursor_pos--; cursor_pos = str_utf8_rewind(str, cursor_pos);
else if (k == KEY_RIGHT && cursor_pos < len) else if (k == KEY_RIGHT && cursor_pos < len)
cursor_pos++; cursor_pos = str_utf8_forward(str, cursor_pos);
else if (k == KEY_HOME) else if (k == KEY_HOME)
cursor_pos = 0; cursor_pos = 0;
else if (k == KEY_END) else if (k == KEY_END)
cursor_pos = len; cursor_pos = len;
} }
*cursor_pos_ptr = cursor_pos;
*str_len_ptr = len;
}
void LINEINPUT::process_input(INPUT_EVENT e)
{
manipulate(e, str, sizeof(str), &len, &cursor_pos);
} }

View file

@ -5,9 +5,11 @@
class LINEINPUT class LINEINPUT
{ {
char str[256]; char str[256];
unsigned len; int len;
unsigned cursor_pos; int cursor_pos;
public: public:
static void manipulate(INPUT_EVENT e, char *str, int str_max_size, int *str_len, int *cursor_pos);
class CALLBACK class CALLBACK
{ {
public: public:

View file

@ -18,6 +18,7 @@ extern "C" {
#include <game/client/render.hpp> #include <game/client/render.hpp>
#include "ed_editor.hpp" #include "ed_editor.hpp"
#include <game/client/lineinput.hpp>
static int checker_texture = 0; static int checker_texture = 0;
static int background_texture = 0; static int background_texture = 0;
@ -209,44 +210,7 @@ int ui_do_edit_box(void *id, const RECT *rect, char *str, int str_size, float fo
for(int i = 0; i < inp_num_events(); i++) for(int i = 0; i < inp_num_events(); i++)
{ {
len = strlen(str); len = strlen(str);
LINEINPUT::manipulate(inp_get_event(i), str, str_size, &len, &at_index);
INPUT_EVENT e = inp_get_event(i);
char c = e.ch;
int k = e.key;
if (at_index > len)
at_index = len;
if (!(c >= 0 && c < 32) && c != 127)
{
if (len < str_size - 1 && at_index < str_size - 1)
{
memmove(str + at_index + 1, str + at_index, len - at_index + 1);
str[at_index] = c;
at_index++;
}
}
if(e.flags&INPFLAG_PRESS)
{
if (k == KEY_BACKSPACE && at_index > 0)
{
memmove(str + at_index - 1, str + at_index, len - at_index + 1);
at_index--;
}
else if (k == KEY_DELETE && at_index < len)
memmove(str + at_index, str + at_index + 1, len - at_index);
else if (k == KEY_RETURN)
ui_clear_last_active_item();
else if (k == KEY_LEFT && at_index > 0)
at_index--;
else if (k == KEY_RIGHT && at_index < len)
at_index++;
else if (k == KEY_HOME)
at_index = 0;
else if (k == KEY_END)
at_index = len;
}
} }
r = 1; r = 1;