From 0e518d5117b73fd54081decf1c0eb9f9d3173ff6 Mon Sep 17 00:00:00 2001 From: Uros Majstorovic Date: Wed, 29 Jul 2020 09:21:45 +0200 Subject: unicode support --- code/fe310/eos/eve/Makefile | 2 +- code/fe310/eos/eve/eve.h | 1 - code/fe310/eos/eve/screen/font.c | 38 +++++-- code/fe310/eos/eve/screen/font.h | 5 +- code/fe310/eos/eve/screen/form.c | 1 + code/fe310/eos/eve/screen/page.c | 1 + code/fe310/eos/eve/unicode.c | 103 +++++++++++++++++++ code/fe310/eos/eve/unicode.h | 10 ++ code/fe310/eos/eve/widget/clipb.c | 6 +- code/fe310/eos/eve/widget/clipb.h | 4 +- code/fe310/eos/eve/widget/label.c | 1 + code/fe310/eos/eve/widget/pagew.c | 1 + code/fe310/eos/eve/widget/strw.c | 181 ++++++++++++++++------------------ code/fe310/eos/eve/widget/strw.h | 4 +- code/fe310/eos/eve/widget/textw.c | 197 +++++++++++++++++++------------------ code/fe310/eos/eve/widget/textw.h | 6 +- code/fe310/eos/eve/widget/widget.c | 1 + 17 files changed, 344 insertions(+), 218 deletions(-) create mode 100644 code/fe310/eos/eve/unicode.c create mode 100644 code/fe310/eos/eve/unicode.h (limited to 'code/fe310/eos') diff --git a/code/fe310/eos/eve/Makefile b/code/fe310/eos/eve/Makefile index 0a737cc..3355dd5 100644 --- a/code/fe310/eos/eve/Makefile +++ b/code/fe310/eos/eve/Makefile @@ -2,7 +2,7 @@ include ../../common.mk CFLAGS += -I.. -I../../include -obj = eve.o eve_touch.o eve_track.o eve_kbd.o eve_text.o eve_platform.o +obj = eve.o eve_touch.o eve_track.o eve_kbd.o eve_text.o eve_platform.o unicode.o %.o: %.c %.h diff --git a/code/fe310/eos/eve/eve.h b/code/fe310/eos/eve/eve.h index 0fd5ede..eb59959 100644 --- a/code/fe310/eos/eve/eve.h +++ b/code/fe310/eos/eve/eve.h @@ -7,7 +7,6 @@ #define EVE_OK 0 #define EVE_ERR -1 -#define EVE_ERR_TEXT -100 #define EVE_PSTATE_ACTIVE 0 #define EVE_PSTATE_STANDBY 1 diff --git a/code/fe310/eos/eve/screen/font.c b/code/fe310/eos/eve/screen/font.c index 6fc7d39..da02983 100644 --- a/code/fe310/eos/eve/screen/font.c +++ b/code/fe310/eos/eve/screen/font.c @@ -1,6 +1,8 @@ #include #include "eve.h" +#include "unicode.h" + #include "font.h" void eve_font_init(EVEFont *font, uint8_t font_id) { @@ -14,23 +16,41 @@ void eve_font_init(EVEFont *font, uint8_t font_id) { eve_readb(p, font->w_ch, 128); } -uint16_t eve_font_str_w(EVEFont *font, char *s) { +uint8_t eve_font_ch_w(EVEFont *font, utf32_t ch) { + if (ch < 128) return font->w_ch[ch]; + return 0; +} + +uint16_t eve_font_str_w(EVEFont *font, utf8_t *str) { uint16_t r = 0; + utf32_t ch; + uint8_t ch_w; + uint8_t ch_l; - while (*s) { - r += font->w_ch[*s]; - s++; + if (str == NULL) return 0; + + while (*str) { + ch_l = utf8_dec(str, &ch); + ch_w = eve_font_ch_w(font, ch); + r += ch_w; + str += ch_l; } return r; } -uint16_t eve_font_buf_w(EVEFont *font, char *buf, uint16_t buf_len) { - int i; +uint16_t eve_font_buf_w(EVEFont *font, utf8_t *buf, uint16_t buf_len) { + int i = 0; uint16_t r = 0; - - for (i=0; iw_ch[*(buf + i)]; + utf32_t ch; + uint8_t ch_w; + uint8_t ch_l; + + while (i < buf_len) { + ch_l = utf8_dec(buf + i, &ch); + ch_w = eve_font_ch_w(font, ch); + r += ch_w; + i += ch_l; } return r; diff --git a/code/fe310/eos/eve/screen/font.h b/code/fe310/eos/eve/screen/font.h index 525e669..aff038c 100644 --- a/code/fe310/eos/eve/screen/font.h +++ b/code/fe310/eos/eve/screen/font.h @@ -8,6 +8,7 @@ typedef struct EVEFont { } EVEFont; void eve_font_init(EVEFont *font, uint8_t font_id); -uint16_t eve_font_str_w(EVEFont *font, char *s); -uint16_t eve_font_buf_w(EVEFont *font, char *buf, uint16_t buf_len); +uint8_t eve_font_ch_w(EVEFont *font, utf32_t ch); +uint16_t eve_font_str_w(EVEFont *font, utf8_t *str); +uint16_t eve_font_buf_w(EVEFont *font, utf8_t *buf, uint16_t buf_len); uint8_t eve_font_h(EVEFont *font); diff --git a/code/fe310/eos/eve/screen/form.c b/code/fe310/eos/eve/screen/form.c index 096cfa3..f7d37ee 100644 --- a/code/fe310/eos/eve/screen/form.c +++ b/code/fe310/eos/eve/screen/form.c @@ -3,6 +3,7 @@ #include "eve.h" #include "eve_kbd.h" +#include "unicode.h" #include "screen.h" #include "window.h" diff --git a/code/fe310/eos/eve/screen/page.c b/code/fe310/eos/eve/screen/page.c index 7631c95..f54056c 100644 --- a/code/fe310/eos/eve/screen/page.c +++ b/code/fe310/eos/eve/screen/page.c @@ -3,6 +3,7 @@ #include "eve.h" #include "eve_kbd.h" +#include "unicode.h" #include "screen.h" #include "window.h" diff --git a/code/fe310/eos/eve/unicode.c b/code/fe310/eos/eve/unicode.c new file mode 100644 index 0000000..62b1714 --- /dev/null +++ b/code/fe310/eos/eve/unicode.c @@ -0,0 +1,103 @@ +#include "unicode.h" + +uint8_t utf8_enc(utf32_t ch, utf8_t *str) { + if (ch <= 0x7f) { + str[0] = ch; + return 1; + } else if (ch <= 0x7ff) { + str[0] = 0xc0 | (ch >> 6); + str[1] = 0x80 | (ch & 0x3f); + return 2; + } else if (ch <= 0xffff) { + if ((ch >= 0xd800) && (ch <= 0xdfff)) return 0; + str[0] = 0xe0 | (ch >> 12); + str[1] = 0x80 | ((ch >> 6) & 0x3f); + str[2] = 0x80 | (ch & 0x3f); + return 3; + } else if (ch <= 0x10ffff) { + str[0] = 0xf0 | (ch >> 18); + str[1] = 0x80 | ((ch >> 12) & 0x3f); + str[2] = 0x80 | ((ch >> 6) & 0x3f); + str[3] = 0x80 | (ch & 0x3f); + return 4; + } else { + return 0; + } +} + +uint8_t utf8_dec(utf8_t *str, utf32_t *ch) { + if ((str[0] & 0x80) == 0x00) { + *ch = str[0]; + return 1; + } else if ((str[0] & 0xe0) == 0xc0) { + if ((str[1] & 0xc0) != 0x80) return 0; + *ch = (utf32_t)(str[0] & 0x1f) << 6; + *ch |= (utf32_t)(str[1] & 0x3f); + if (*ch < 0x80) return 0; + return 2; + } else if ((str[0] & 0xf0) == 0xe0) { + if (((str[1] & 0xc0) != 0x80) || ((str[2] & 0xc0) != 0x80)) return 0; + *ch = (utf32_t)(str[0] & 0x0f) << 12; + *ch |= (utf32_t)(str[1] & 0x3f) << 6; + *ch |= (utf32_t)(str[2] & 0x3f); + if ((*ch >= 0xd800) && (*ch <= 0xdfff)) return 0; + if (*ch < 0x800) return 0; + return 3; + } else if ((str[0] & 0xf8) == 0xf0) { + if (((str[1] & 0xc0) != 0x80) || ((str[2] & 0xc0) != 0x80) || ((str[3] & 0xc0) != 0x80)) return 0; + *ch = (utf32_t)(str[0] & 0x07) << 18; + *ch |= (utf32_t)(str[1] & 0x0f) << 12; + *ch |= (utf32_t)(str[2] & 0x3f) << 6; + *ch |= (utf32_t)(str[3] & 0x3f); + if (*ch < 0x010000) return 0; + if (*ch > 0x10ffff) return 0; + return 4; + } else { + return 0; + } +} + +int utf8_seek(utf8_t *str, int off, utf32_t *ch) { + int i; + int len = 0; + + if (off < 0) { + off = -off; + for (i=0; i + +typedef uint8_t utf8_t; +typedef uint16_t utf16_t; +typedef uint32_t utf32_t; + +uint8_t utf8_enc(utf32_t ch, utf8_t *str); +uint8_t utf8_dec(utf8_t *str, utf32_t *ch); +int utf8_seek(utf8_t *str, int off, utf32_t *ch); +int utf8_verify(utf8_t *str, int sz); \ No newline at end of file diff --git a/code/fe310/eos/eve/widget/clipb.c b/code/fe310/eos/eve/widget/clipb.c index f480d83..04c9a46 100644 --- a/code/fe310/eos/eve/widget/clipb.c +++ b/code/fe310/eos/eve/widget/clipb.c @@ -3,9 +3,9 @@ #include "eve.h" #include "clipb.h" -static char _clipb[EVE_CLIPB_SIZE_BUF]; +static uint8_t _clipb[EVE_CLIPB_SIZE_BUF]; -int eve_clipb_push(char *str, uint16_t len) { +int eve_clipb_push(uint8_t *str, uint16_t len) { if (len >= EVE_CLIPB_SIZE_BUF) return EVE_ERR; memcpy(_clipb, str, len); @@ -14,6 +14,6 @@ int eve_clipb_push(char *str, uint16_t len) { return EVE_OK; } -char *eve_clipb_get(void) { +uint8_t *eve_clipb_get(void) { return _clipb; } \ No newline at end of file diff --git a/code/fe310/eos/eve/widget/clipb.h b/code/fe310/eos/eve/widget/clipb.h index 8b3e980..2d6fae6 100644 --- a/code/fe310/eos/eve/widget/clipb.h +++ b/code/fe310/eos/eve/widget/clipb.h @@ -2,5 +2,5 @@ #define EVE_CLIPB_SIZE_BUF 256 -int eve_clipb_push(char *str, uint16_t len); -char *eve_clipb_get(void); \ No newline at end of file +int eve_clipb_push(uint8_t *str, uint16_t len); +uint8_t *eve_clipb_get(void); \ No newline at end of file diff --git a/code/fe310/eos/eve/widget/label.c b/code/fe310/eos/eve/widget/label.c index 44b63b0..ebea823 100644 --- a/code/fe310/eos/eve/widget/label.c +++ b/code/fe310/eos/eve/widget/label.c @@ -3,6 +3,7 @@ #include "eve.h" #include "eve_kbd.h" +#include "unicode.h" #include "screen/screen.h" #include "screen/window.h" diff --git a/code/fe310/eos/eve/widget/pagew.c b/code/fe310/eos/eve/widget/pagew.c index 8c3b515..c64c477 100644 --- a/code/fe310/eos/eve/widget/pagew.c +++ b/code/fe310/eos/eve/widget/pagew.c @@ -3,6 +3,7 @@ #include "eve.h" #include "eve_kbd.h" +#include "unicode.h" #include "screen/screen.h" #include "screen/window.h" diff --git a/code/fe310/eos/eve/widget/strw.c b/code/fe310/eos/eve/widget/strw.c index 519f171..da57bab 100644 --- a/code/fe310/eos/eve/widget/strw.c +++ b/code/fe310/eos/eve/widget/strw.c @@ -1,9 +1,9 @@ #include #include -#include #include "eve.h" #include "eve_kbd.h" +#include "unicode.h" #include "screen/screen.h" #include "screen/window.h" @@ -29,7 +29,7 @@ #define CHAR_VALID_INPUT(c) ((c >= 0x20) && (c < 0x7f)) -void eve_strw_init(EVEStrWidget *widget, EVERect *g, EVEFont *font, char *str, uint16_t str_size) { +void eve_strw_init(EVEStrWidget *widget, EVERect *g, EVEFont *font, utf8_t *str, uint16_t str_size) { EVEWidget *_widget = &widget->w; memset(widget, 0, sizeof(EVEStrWidget)); @@ -37,7 +37,7 @@ void eve_strw_init(EVEStrWidget *widget, EVERect *g, EVEFont *font, char *str, u widget->font = font; widget->str = str; widget->str_size = str_size; - widget->str_len = strlen(str); + widget->str_len = utf8_verify(str, str_size); widget->str_g.w = eve_font_str_w(font, str); if (_widget->g.h == 0) _widget->g.h = eve_font_h(font); } @@ -243,13 +243,13 @@ uint8_t eve_strw_draw(EVEWidget *_widget, EVEPage *page, uint8_t tag0) { l1 = c1->ch; l2 = c2->ch - c1->ch; - l3 = strlen(widget->str) - c2->ch; + l3 = widget->str_len - c2->ch; _draw_str(widget, page->v.window, 0, l1, 0, c1->x, 0); _draw_str(widget, page->v.window, c1->ch, l2, c1->x, c2->x, 1); _draw_str(widget, page->v.window, c2->ch, l3, c2->x, widget->str_g.x + _widget->g.w, 0); } else { if (widget->cursor1.on) _draw_cursor(widget, &widget->cursor1); - _draw_str(widget, page->v.window, 0, strlen(widget->str), 0, widget->str_g.x + _widget->g.w, 0); + _draw_str(widget, page->v.window, 0, widget->str_len, 0, widget->str_g.x + _widget->g.w, 0); } if (cut) { @@ -264,10 +264,13 @@ void eve_strw_putc(void *_page, int c) { EVEStrWidget *widget = (EVEStrWidget *)eve_page_get_focus(page); EVEStrCursor *cursor1 = &widget->cursor1; EVEStrCursor *cursor2 = &widget->cursor2; - char *str; - char *clipb = NULL; + utf8_t *str; + utf8_t *clipb = NULL; int w0 = widget->font->w; int w1 = widget->w.g.w - widget->font->w; + int ins_c = 0, del_c = 0; + int ins_w = 0, del_w = 0; + if (c == CH_EOF) { if (cursor1->on) eve_strw_cursor_clear(widget, cursor1); @@ -277,107 +280,85 @@ void eve_strw_putc(void *_page, int c) { if (!cursor1->on) return; - if (cursor2->on) { - EVEStrCursor *c1; - EVEStrCursor *c2; - int ins_c = 0, del_c = 0; - int ins_ch_w = 0, del_ch_w = 0; + if (!cursor2->on && ((c == CH_BS) || (c == CH_DEL))) { + utf32_t uc; - if (cursor1->ch <= cursor2->ch) { - c1 = cursor1; - c2 = cursor2; - } else { - c1 = cursor2; - c2 = cursor1; + str = widget->str + cursor1->ch; + switch (c) { + case CH_BS: + if (cursor1->ch > 0) { + del_c = utf8_seek(str, -1, &uc); + del_w = eve_font_ch_w(widget->font, uc); + memmove(str - del_c, str, widget->str_len - cursor1->ch + 1); + widget->str_len -= del_c; + widget->str_g.w -= del_w; + cursor1->ch -= del_c; + cursor1->x -= del_w; + } + break; + + case CH_DEL: + if (cursor1->ch < widget->str_len) { + del_c = utf8_dec(str, &uc); + del_w = eve_font_ch_w(widget->font, uc); + memmove(str, str + del_c, widget->str_len - cursor1->ch - del_c + 1); + widget->str_len -= del_c; + widget->str_g.w -= del_w; + } + break; + } + if (widget->str_g.w - widget->str_g.x < w1) { + widget->str_g.x -= del_w; + if (widget->str_g.x < 0) widget->str_g.x = 0; } + } else { + EVEStrCursor *c1 = cursor1; + EVEStrCursor *c2 = cursor1; + utf8_t utf8_buf[4]; - str = widget->str + c1->ch; - del_c = c2->ch - c1->ch; - del_ch_w = eve_font_buf_w(widget->font, str, del_c); - if ((c == CH_CTRLX) || (c == CH_CTRLC)) { - eve_clipb_push(str, del_c); - if (c == CH_CTRLC) return; + if (cursor2->on) { + if (cursor1->ch <= cursor2->ch) { + c2 = cursor2; + } else { + c1 = cursor2; + } + del_c = c2->ch - c1->ch; + del_w = eve_font_buf_w(widget->font, str, del_c); + if ((c == CH_CTRLX) || (c == CH_CTRLC)) { + eve_clipb_push(str, del_c); + if (c == CH_CTRLC) return; + } } - if (CHAR_VALID_INPUT(c) && (widget->str_len < widget->str_size + del_c - 1)) { - ins_c = 1; - ins_ch_w = widget->font->w_ch[c]; + + str = widget->str + c1->ch; + if (CHAR_VALID_INPUT(c)) { + ins_c = utf8_enc(c, utf8_buf); + ins_w = eve_font_ch_w(widget->font, c); } else if (c == CH_CTRLV) { clipb = eve_clipb_get(); - ins_c = clipb ? strlen(clipb) : 0; - if (widget->str_len >= widget->str_size - (ins_c - del_c)) ins_c = widget->str_size - widget->str_len + del_c - 1; - ins_ch_w = eve_font_buf_w(widget->font, clipb, ins_c); + ins_c = clipb ? utf8_verify(clipb, EVE_CLIPB_SIZE_BUF) : 0; + ins_w = eve_font_str_w(widget->font, clipb); + } + if (widget->str_len + ins_c >= widget->str_size + del_c) { + ins_c = 0; + ins_w = 0; } if (ins_c != del_c) memmove(str + ins_c, str + del_c, widget->str_len - c2->ch + 1); if (ins_c) { if (c == CH_CTRLV) { memcpy(str, clipb, ins_c); + } else if (ins_c > 1) { + memcpy(str, utf8_buf, ins_c); } else { - *str = c; + *str = utf8_buf[0]; } c1->ch += ins_c; - c1->x += ins_ch_w; + c1->x += ins_w; } widget->str_len += ins_c - del_c; - widget->str_g.w += ins_ch_w - del_ch_w; + widget->str_g.w += ins_w - del_w; if (c1 == cursor2) widget->cursor1 = widget->cursor2; - eve_strw_cursor_clear(widget, cursor2); - } else { - int ch_w = 0; - int c_len; - - str = widget->str + cursor1->ch; - switch (c) { - case CH_BS: - if (cursor1->ch > 0) { - ch_w = widget->font->w_ch[*(str - 1)]; - memmove(str - 1, str, widget->str_len - cursor1->ch + 1); - widget->str_len--; - widget->str_g.w -= ch_w; - cursor1->ch--; - cursor1->x -= ch_w; - } - break; - - case CH_DEL: - if (cursor1->ch < widget->str_len) { - ch_w = widget->font->w_ch[*str]; - memmove(str, str + 1, widget->str_len - cursor1->ch); - widget->str_len--; - widget->str_g.w -= ch_w; - } - break; - - case CH_CTRLV: - clipb = eve_clipb_get(); - c_len = clipb ? strlen(clipb) : 0; - if (widget->str_len >= widget->str_size - c_len) c_len = widget->str_size - widget->str_len - 1; - ch_w = eve_font_buf_w(widget->font, clipb, c_len); - if (c_len) { - memmove(str + c_len, str, widget->str_len - cursor1->ch + 1); - memcpy(str, clipb, c_len); - widget->str_len += c_len; - widget->str_g.w += ch_w; - cursor1->ch += c_len; - cursor1->x += ch_w; - } - break; - - default: - if (CHAR_VALID_INPUT(c) && (widget->str_len < widget->str_size - 1)) { - ch_w = widget->font->w_ch[c]; - memmove(str + 1, str, widget->str_len - cursor1->ch + 1); - *str = c; - widget->str_len++; - widget->str_g.w += ch_w; - cursor1->ch++; - cursor1->x += ch_w; - } - break; - } - if (((c == CH_BS) || (c == CH_DEL)) && (widget->str_g.w - widget->str_g.x < w1)) { - widget->str_g.x -= ch_w; - if (widget->str_g.x < 0) widget->str_g.x = 0; - } + if (cursor2->on) eve_strw_cursor_clear(widget, cursor2); } if (cursor1->x - widget->str_g.x < w0) widget->str_g.x = cursor1->x > w0 ? cursor1->x - w0 : 0; @@ -387,19 +368,25 @@ void eve_strw_putc(void *_page, int c) { void eve_strw_cursor_set(EVEStrWidget *widget, EVEStrCursor *cursor, int16_t x) { int i; int16_t _x, _d; + utf32_t ch; + uint8_t ch_w; + uint8_t ch_l; EVEWidget *_widget = &widget->w; x = x - _widget->g.x + widget->str_g.x; _x = 0; _d = x; - for (i=0; istr_len; i++) { - _x += widget->font->w_ch[widget->str[i]]; + i = 0; + while (i < widget->str_len) { + ch_l = utf8_dec(widget->str + i, &ch); + ch_w = eve_font_ch_w(widget->font, ch); + _x += ch_w; + i += ch_l; if (_x >= x) { - if (_x - x < _d) { - i++; - } else { - _x -= widget->font->w_ch[widget->str[i]]; + if (_x - x > _d) { + _x -= ch_w; + i -= ch_l; } break; } else { diff --git a/code/fe310/eos/eve/widget/strw.h b/code/fe310/eos/eve/widget/strw.h index 1277c20..72fc6aa 100644 --- a/code/fe310/eos/eve/widget/strw.h +++ b/code/fe310/eos/eve/widget/strw.h @@ -9,7 +9,7 @@ typedef struct EVEStrCursor { typedef struct EVEStrWidget { EVEWidget w; EVEFont *font; - char *str; + utf8_t *str; uint16_t str_size; uint16_t str_len; struct { @@ -27,7 +27,7 @@ typedef struct EVEStrWidget { } track; } EVEStrWidget; -void eve_strw_init(EVEStrWidget *widget, EVERect *g, EVEFont *font, char *str, uint16_t str_size); +void eve_strw_init(EVEStrWidget *widget, EVERect *g, EVEFont *font, utf8_t *str, uint16_t str_size); int eve_strw_touch(EVEWidget *_widget, EVEPage *page, uint8_t tag0, int touch_idx); uint8_t eve_strw_draw(EVEWidget *_widget, EVEPage *page, uint8_t tag0); void eve_strw_putc(void *_page, int c); diff --git a/code/fe310/eos/eve/widget/textw.c b/code/fe310/eos/eve/widget/textw.c index e72bb8c..f14e4f6 100644 --- a/code/fe310/eos/eve/widget/textw.c +++ b/code/fe310/eos/eve/widget/textw.c @@ -1,9 +1,9 @@ #include #include -#include #include "eve.h" #include "eve_kbd.h" +#include "unicode.h" #include "screen/screen.h" #include "screen/window.h" @@ -33,7 +33,9 @@ #define CHAR_VALID_INPUT(c) (((c >= 0x20) && (c < 0x7f)) || (c == '\n')) -void eve_textw_init(EVETextWidget *widget, EVERect *g, EVEFont *font, char *text, uint16_t text_size, uint16_t *line, uint16_t line_size) { +#define DIVC(x,y) ((x) / (y) + ((x) % (y) != 0)) + +void eve_textw_init(EVETextWidget *widget, EVERect *g, EVEFont *font, utf8_t *text, uint16_t text_size, uint16_t *line, uint16_t line_size) { EVEWidget *_widget = &widget->w; memset(widget, 0, sizeof(EVETextWidget)); @@ -41,9 +43,11 @@ void eve_textw_init(EVETextWidget *widget, EVERect *g, EVEFont *font, char *text widget->font = font; widget->text = text; widget->text_size = text_size; + widget->text_len = utf8_verify(text, text_size); widget->line = line; widget->line_size = line_size; - if (text_size && line_size) eve_textw_update(widget, NULL, 0); + memset(widget->line, 0xff, line_size * sizeof(uint16_t)); + eve_textw_update(widget, NULL, 0); } static void set_focus(EVETextWidget *widget, EVETextCursor *cursor, EVEPage *page) { @@ -186,7 +190,7 @@ uint8_t eve_textw_draw(EVEWidget *_widget, EVEPage *page, uint8_t tag0) { char lineNvisible; _line0 = line0 = ((int)page->win_y - _widget->g.y) / widget->font->h; - _lineN = lineN = ceil((double)((int)page->win_y - _widget->g.y + page->v.window->g.h) / widget->font->h); + _lineN = lineN = DIVC(((int)page->win_y - _widget->g.y + page->v.window->g.h), widget->font->h); if (line0 < 0) line0 = 0; if (lineN < 0) lineN = 0; if (line0 > widget->line_len) line0 = widget->line_len; @@ -278,8 +282,8 @@ void eve_textw_putc(void *_page, int c) { EVETextWidget *widget = (EVETextWidget *)eve_page_get_focus(page); EVETextCursor *cursor1 = &widget->cursor1; EVETextCursor *cursor2 = &widget->cursor2; - char *text; - char *clipb = NULL; + utf8_t *text; + utf8_t *clipb = NULL; int i, r; int ins_c = 0, del_c = 0; int ch_w = 0; @@ -292,86 +296,72 @@ void eve_textw_putc(void *_page, int c) { if (!cursor1->on) return; - if (cursor2->on) { - EVETextCursor *c1; - EVETextCursor *c2; + if (!cursor2->on && ((c == CH_BS) || (c == CH_DEL))) { + utf32_t uc; - if (cursor1->ch <= cursor2->ch) { - c1 = cursor1; - c2 = cursor2; - } else { - c1 = cursor2; - c2 = cursor1; + text = widget->text + cursor1->ch; + switch (c) { + case CH_BS: + if (cursor1->ch > 0) { + del_c = utf8_seek(text, -1, &uc); + ch_w = eve_font_ch_w(widget->font, uc); + memmove(text - del_c, text, widget->text_len - cursor1->ch + 1); + cursor1->ch -= del_c; + } + break; + + case CH_DEL: + if (cursor1->ch < widget->text_len) { + del_c = utf8_dec(text, &uc); + ch_w = eve_font_ch_w(widget->font, uc); + memmove(text, text + del_c, widget->text_len - cursor1->ch - del_c + 1); + } + break; + } + } else { + EVETextCursor *c1 = cursor1; + EVETextCursor *c2 = cursor1; + utf8_t utf8_buf[4]; + + if (cursor2->on) { + if (cursor1->ch <= cursor2->ch) { + c2 = cursor2; + } else { + c1 = cursor2; + } + del_c = c2->ch - c1->ch; + if ((c == CH_CTRLX) || (c == CH_CTRLC)) { + eve_clipb_push(text, del_c); + if (c == CH_CTRLC) return; + } } text = widget->text + c1->ch; - del_c = c2->ch - c1->ch; - if ((c == CH_CTRLX) || (c == CH_CTRLC)) { - eve_clipb_push(text, del_c); - if (c == CH_CTRLC) return; - } - if (CHAR_VALID_INPUT(c) && (widget->text_len < widget->text_size + del_c - 1)) { - ins_c = 1; - ch_w = widget->font->w_ch[c]; + if (CHAR_VALID_INPUT(c)) { + ins_c = utf8_enc(c, utf8_buf); + ch_w = eve_font_ch_w(widget->font, c); } else if (c == CH_CTRLV) { clipb = eve_clipb_get(); - ins_c = clipb ? strlen(clipb) : 0; - if (widget->text_len >= widget->text_size - (ins_c - del_c)) ins_c = widget->text_size - widget->text_len + del_c - 1; - ch_w = eve_font_buf_w(widget->font, clipb, ins_c); + ins_c = clipb ? utf8_verify(clipb, EVE_CLIPB_SIZE_BUF) : 0; + ch_w = eve_font_str_w(widget->font, clipb); + } + if (widget->text_len + ins_c >= widget->text_size + del_c) { + ins_c = 0; + ch_w = 0; } if (ins_c != del_c) memmove(text + ins_c, text + del_c, widget->text_len - c2->ch + 1); if (ins_c) { if (c == CH_CTRLV) { memcpy(text, clipb, ins_c); + } else if (ins_c > 1) { + memcpy(text, utf8_buf, ins_c); } else { - *text = c; + *text = utf8_buf[0]; } c1->ch += ins_c; } if (c1 == cursor2) widget->cursor1 = widget->cursor2; - eve_textw_cursor_clear(widget, cursor2); - } else { - text = widget->text + cursor1->ch; - - switch (c) { - case CH_BS: - if (cursor1->ch > 0) { - ch_w = -widget->font->w_ch[*(text - 1)]; - memmove(text - 1, text, widget->text_len - cursor1->ch + 1); - cursor1->ch--; - del_c = 1; - } - break; - - case CH_DEL: - if (cursor1->ch < widget->text_len) { - memmove(text, text + 1, widget->text_len - cursor1->ch); - del_c = 1; - } - break; - - case CH_CTRLV: - clipb = eve_clipb_get(); - ins_c = clipb ? strlen(clipb) : 0; - if (widget->text_len >= widget->text_size - ins_c) ins_c = widget->text_size - widget->text_len - 1; - ch_w = eve_font_buf_w(widget->font, clipb, ins_c); - if (ins_c) { - memmove(text + ins_c, text, widget->text_len - cursor1->ch + 1); - memcpy(text, clipb, ins_c); - cursor1->ch += ins_c; - } - break; - - default: - if (CHAR_VALID_INPUT(c) && (widget->text_len < widget->text_size - 1)) { - ch_w = widget->font->w_ch[c]; - memmove(text + 1, text, widget->text_len - cursor1->ch + 1); - *text = c; - cursor1->ch++; - ins_c = 1; - } - break; - } + if (cursor2->on) eve_textw_cursor_clear(widget, cursor2); } if ((ins_c == 0) && (del_c == 0)) return; @@ -384,7 +374,6 @@ void eve_textw_putc(void *_page, int c) { r = cursor1->line; if (cursor1->line) r = eve_textw_update(widget, page, cursor1->line - 1); if ((cursor1->line == 0) || (r == cursor1->line - 1)) r = eve_textw_update(widget, page, cursor1->line); - if (r < 0) return; if (cursor1->line && (cursor1->ch < LINE_START(widget, cursor1->line))) { cursor1->line--; @@ -399,10 +388,11 @@ void eve_textw_putc(void *_page, int c) { } } -int eve_textw_update(EVETextWidget *widget, EVEPage *page, uint16_t line) { +uint16_t eve_textw_update(EVETextWidget *widget, EVEPage *page, uint16_t line) { int i; - char ch; + utf32_t ch; uint8_t ch_w; + uint8_t ch_l; uint16_t word_w, line_w, line_b; uint16_t new_h; EVEWidget *_widget = &widget->w; @@ -410,9 +400,18 @@ int eve_textw_update(EVETextWidget *widget, EVEPage *page, uint16_t line) { word_w = 0; line_w = 0; line_b = LINE_EMPTY; - for (i=LINE_START(widget, line); itext_size; i++) { - ch = widget->text[i]; - if (ch < 128) ch_w = widget->font->w_ch[ch]; + + i = LINE_START(widget, line); + while (i < widget->text_size) { + ch_l = utf8_dec(widget->text + i, &ch); + if (!CHAR_VALID_INPUT(ch) && ch) { + ch = 0; + widget->text[i] = '\0'; + widget->text_len = i; + widget->line[line] = LINE_EMPTY; + } + + ch_w = eve_font_ch_w(widget->font, ch); if (ch <= 0x20) { if ((ch == '\n') || (ch == '\0')) { if (widget->line[line] == i) return line; @@ -426,14 +425,10 @@ int eve_textw_update(EVETextWidget *widget, EVEPage *page, uint16_t line) { word_w = 0; line_w += ch_w; line_b = i; - } else { - return EVE_ERR_TEXT; } - } else if (ch < 0x7f) { + } else { word_w += ch_w; line_w += ch_w; - } else { - return EVE_ERR_TEXT; } if ((line_w > _widget->g.w) && (line_b != LINE_EMPTY)) { if (widget->line[line] == line_b) return line; @@ -446,12 +441,9 @@ int eve_textw_update(EVETextWidget *widget, EVEPage *page, uint16_t line) { line_w = word_w; line_b = LINE_EMPTY; } + i += ch_l; } - if (i == widget->text_size) i--; - widget->text[i] = '\0'; - widget->text_len = i; - widget->line_len = line; new_h = (line + 1) * widget->font->h; for (i=line; iline_size; i++) { @@ -467,13 +459,15 @@ int eve_textw_update(EVETextWidget *widget, EVEPage *page, uint16_t line) { } void eve_textw_cursor_update(EVETextWidget *widget, EVETextCursor *cursor) { - int i; - uint16_t x; - - x = 0; - for (i=LINE_START(widget, cursor->line); iline); i++) { - if (cursor->ch == i) break; - x += widget->font->w_ch[widget->text[i]]; + int i = LINE_START(widget, cursor->line); + uint16_t x = 0; + utf32_t ch; + uint8_t ch_l; + + while ((i < cursor->ch) && (i < LINE_END(widget, cursor->line))) { + ch_l = utf8_dec(widget->text + i, &ch); + x += eve_font_ch_w(widget->font, ch); + i += ch_l; } cursor->x = x; } @@ -482,6 +476,9 @@ void eve_textw_cursor_set(EVETextWidget *widget, EVETextCursor *cursor, uint8_t int i; int16_t _x, _d; uint16_t c_line = LINE_EMPTY; + utf32_t ch; + uint8_t ch_w; + uint8_t ch_l; EVEWidget *_widget = &widget->w; if ((tag >= widget->tag0) && ((widget->tagN == EVE_TAG_NOTAG) || (tag < widget->tagN))) c_line = tag - widget->tag0 + widget->line0; @@ -494,15 +491,19 @@ void eve_textw_cursor_set(EVETextWidget *widget, EVETextCursor *cursor, uint8_t } x -= _widget->g.x; + _x = 0; _d = x; - for (i=LINE_START(widget, cursor->line); iline); i++) { - _x += widget->font->w_ch[widget->text[i]]; + i = LINE_START(widget, cursor->line); + while (i < LINE_END(widget, cursor->line)) { + ch_l = utf8_dec(widget->text + i, &ch); + ch_w = eve_font_ch_w(widget->font, ch); + _x += ch_w; + i += ch_l; if (_x >= x) { - if (_x - x < _d) { - i++; - } else { - _x -= widget->font->w_ch[widget->text[i]]; + if (_x - x > _d) { + _x -= ch_w; + i -= ch_l; } break; } else { diff --git a/code/fe310/eos/eve/widget/textw.h b/code/fe310/eos/eve/widget/textw.h index ee3eefb..cd46ea3 100644 --- a/code/fe310/eos/eve/widget/textw.h +++ b/code/fe310/eos/eve/widget/textw.h @@ -10,7 +10,7 @@ typedef struct EVETextCursor { typedef struct EVETextWidget { EVEWidget w; EVEFont *font; - char *text; + utf8_t *text; uint16_t text_size; uint16_t text_len; uint16_t *line; @@ -29,11 +29,11 @@ typedef struct EVETextWidget { } track; } EVETextWidget; -void eve_textw_init(EVETextWidget *widget, EVERect *g, EVEFont *font, char *text, uint16_t text_size, uint16_t *line, uint16_t line_size); +void eve_textw_init(EVETextWidget *widget, EVERect *g, EVEFont *font, utf8_t *text, uint16_t text_size, uint16_t *line, uint16_t line_size); int eve_textw_touch(EVEWidget *_widget, EVEPage *page, uint8_t tag0, int touch_idx); uint8_t eve_textw_draw(EVEWidget *_widget, EVEPage *page, uint8_t tag0); void eve_textw_putc(void *_w, int c); -int eve_textw_update(EVETextWidget *widget, EVEPage *page, uint16_t line); +uint16_t eve_textw_update(EVETextWidget *widget, EVEPage *page, uint16_t line); void eve_textw_cursor_update(EVETextWidget *widget, EVETextCursor *cursor); void eve_textw_cursor_set(EVETextWidget *widget, EVETextCursor *cursor, uint8_t tag, int16_t x); void eve_textw_cursor_clear(EVETextWidget *widget, EVETextCursor *cursor); diff --git a/code/fe310/eos/eve/widget/widget.c b/code/fe310/eos/eve/widget/widget.c index e33a7d6..ab121d8 100644 --- a/code/fe310/eos/eve/widget/widget.c +++ b/code/fe310/eos/eve/widget/widget.c @@ -3,6 +3,7 @@ #include "eve.h" #include "eve_kbd.h" +#include "unicode.h" #include "screen/screen.h" #include "screen/window.h" -- cgit v1.2.3