summaryrefslogtreecommitdiff
path: root/fw/fe310/eos/eve/widget
diff options
context:
space:
mode:
authorUros Majstorovic <majstor@majstor.org>2020-08-05 03:39:22 +0200
committerUros Majstorovic <majstor@majstor.org>2020-08-05 03:39:22 +0200
commitcf7c06297d04bade9cd04c056f9ed510e64dd7bd (patch)
treea3b8cc23574b98e10874b51d33c9fe1bfc012663 /fw/fe310/eos/eve/widget
parent5cd610a07468137066ea4daa5176c3e7045113b0 (diff)
code -> fw
Diffstat (limited to 'fw/fe310/eos/eve/widget')
-rw-r--r--fw/fe310/eos/eve/widget/Makefile17
-rw-r--r--fw/fe310/eos/eve/widget/clipb.c19
-rw-r--r--fw/fe310/eos/eve/widget/clipb.h6
-rw-r--r--fw/fe310/eos/eve/widget/label.c26
-rw-r--r--fw/fe310/eos/eve/widget/label.h10
-rw-r--r--fw/fe310/eos/eve/widget/pagew.c60
-rw-r--r--fw/fe310/eos/eve/widget/pagew.h13
-rw-r--r--fw/fe310/eos/eve/widget/strw.c418
-rw-r--r--fw/fe310/eos/eve/widget/strw.h35
-rw-r--r--fw/fe310/eos/eve/widget/textw.c535
-rw-r--r--fw/fe310/eos/eve/widget/textw.h39
-rw-r--r--fw/fe310/eos/eve/widget/widget.c41
-rw-r--r--fw/fe310/eos/eve/widget/widget.h23
13 files changed, 1242 insertions, 0 deletions
diff --git a/fw/fe310/eos/eve/widget/Makefile b/fw/fe310/eos/eve/widget/Makefile
new file mode 100644
index 0000000..160db72
--- /dev/null
+++ b/fw/fe310/eos/eve/widget/Makefile
@@ -0,0 +1,17 @@
+include ../../../common.mk
+
+CFLAGS += -I.. -I../..
+
+obj = clipb.o label.o widget.o pagew.o strw.o textw.o
+
+
+%.o: %.c %.h
+ $(CC) $(CFLAGS) -c $<
+
+%.o: %.S
+ $(CC) $(CFLAGS) -c $<
+
+all: $(obj)
+
+clean:
+ rm -f *.o \ No newline at end of file
diff --git a/fw/fe310/eos/eve/widget/clipb.c b/fw/fe310/eos/eve/widget/clipb.c
new file mode 100644
index 0000000..04c9a46
--- /dev/null
+++ b/fw/fe310/eos/eve/widget/clipb.c
@@ -0,0 +1,19 @@
+#include <string.h>
+
+#include "eve.h"
+#include "clipb.h"
+
+static uint8_t _clipb[EVE_CLIPB_SIZE_BUF];
+
+int eve_clipb_push(uint8_t *str, uint16_t len) {
+ if (len >= EVE_CLIPB_SIZE_BUF) return EVE_ERR;
+
+ memcpy(_clipb, str, len);
+ _clipb[len] = '\0';
+
+ return EVE_OK;
+}
+
+uint8_t *eve_clipb_get(void) {
+ return _clipb;
+} \ No newline at end of file
diff --git a/fw/fe310/eos/eve/widget/clipb.h b/fw/fe310/eos/eve/widget/clipb.h
new file mode 100644
index 0000000..2d6fae6
--- /dev/null
+++ b/fw/fe310/eos/eve/widget/clipb.h
@@ -0,0 +1,6 @@
+#include <stdint.h>
+
+#define EVE_CLIPB_SIZE_BUF 256
+
+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/fw/fe310/eos/eve/widget/label.c b/fw/fe310/eos/eve/widget/label.c
new file mode 100644
index 0000000..ebea823
--- /dev/null
+++ b/fw/fe310/eos/eve/widget/label.c
@@ -0,0 +1,26 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "eve.h"
+#include "eve_kbd.h"
+#include "unicode.h"
+
+#include "screen/screen.h"
+#include "screen/window.h"
+#include "screen/page.h"
+#include "screen/font.h"
+
+#include "label.h"
+
+void eve_label_init(EVELabel *label, EVERect *g, EVEFont *font, char *title) {
+ memset(label, 0, sizeof(EVELabel));
+ if (g) label->g = *g;
+ label->title = title;
+ label->font = font;
+ if (label->g.w == 0) label->g.w = eve_font_str_w(font, label->title);
+ if (label->g.h == 0) label->g.h = eve_font_h(font);
+}
+
+void eve_label_draw(EVELabel *label) {
+ eve_cmd(CMD_TEXT, "hhhhs", label->g.x, label->g.y, label->font->id, 0, label->title);
+} \ No newline at end of file
diff --git a/fw/fe310/eos/eve/widget/label.h b/fw/fe310/eos/eve/widget/label.h
new file mode 100644
index 0000000..ec96844
--- /dev/null
+++ b/fw/fe310/eos/eve/widget/label.h
@@ -0,0 +1,10 @@
+#include <stdint.h>
+
+typedef struct EVELabel {
+ EVERect g;
+ char *title;
+ EVEFont *font;
+} EVELabel;
+
+void eve_label_init(EVELabel *label, EVERect *g, EVEFont *font, char *title);
+void eve_label_draw(EVELabel *label); \ No newline at end of file
diff --git a/fw/fe310/eos/eve/widget/pagew.c b/fw/fe310/eos/eve/widget/pagew.c
new file mode 100644
index 0000000..c64c477
--- /dev/null
+++ b/fw/fe310/eos/eve/widget/pagew.c
@@ -0,0 +1,60 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "eve.h"
+#include "eve_kbd.h"
+#include "unicode.h"
+
+#include "screen/screen.h"
+#include "screen/window.h"
+#include "screen/page.h"
+#include "screen/font.h"
+
+#include "label.h"
+#include "widget.h"
+#include "pagew.h"
+
+void eve_pagew_init(EVEPageWidget *widget, EVERect *g, char *title, EVEFont *font, EVEPage *page) {
+ EVEWidget *_widget = &widget->w;
+
+ memset(widget, 0, sizeof(EVEPageWidget));
+ eve_widget_init(_widget, EVE_WIDGET_TYPE_PAGE, g, eve_pagew_touch, eve_pagew_draw, NULL);
+ widget->title = title;
+ widget->font = font;
+ widget->page = page;
+ if (_widget->g.w == 0) _widget->g.w = eve_font_str_w(font, widget->title);
+ if (_widget->g.h == 0) _widget->g.h = eve_font_h(font);
+}
+
+int eve_pagew_touch(EVEWidget *_widget, EVEPage *page, uint8_t tag0, int touch_idx) {
+ EVEPageWidget *widget = (EVEPageWidget *)_widget;
+ EVETouch *t;
+ uint16_t evt;
+ int ret = 0;
+
+ if (touch_idx > 0) return 0;
+
+ t = eve_touch_evt(tag0, touch_idx, widget->tag, 1, &evt);
+ if (t && evt) {
+ if (evt & EVE_TOUCH_ETYPE_TRACK_MASK) {
+ if (page && page->handle_evt) page->handle_evt(page, _widget, t, evt, tag0, touch_idx);
+ } else if (evt & EVE_TOUCH_ETYPE_TAG_UP) {
+ widget->page->open(widget->page, page);
+ }
+ ret = 1;
+ }
+ return ret;
+}
+
+uint8_t eve_pagew_draw(EVEWidget *_widget, EVEPage *page, uint8_t tag0) {
+ EVEPageWidget *widget = (EVEPageWidget *)_widget;
+
+ widget->tag = tag0;
+ if (tag0 != EVE_TAG_NOTAG) {
+ eve_cmd_dl(TAG(tag0));
+ tag0++;
+ }
+ eve_cmd(CMD_TEXT, "hhhhs", _widget->g.x, _widget->g.y, widget->font->id, 0, widget->title);
+
+ return tag0;
+}
diff --git a/fw/fe310/eos/eve/widget/pagew.h b/fw/fe310/eos/eve/widget/pagew.h
new file mode 100644
index 0000000..1f9ae18
--- /dev/null
+++ b/fw/fe310/eos/eve/widget/pagew.h
@@ -0,0 +1,13 @@
+#include <stdint.h>
+
+typedef struct EVEPageWidget {
+ EVEWidget w;
+ char *title;
+ EVEFont *font;
+ EVEPage *page;
+ uint8_t tag;
+} EVEPageWidget;
+
+void eve_pagew_init(EVEPageWidget *widget, EVERect *g, char *title, EVEFont *font, EVEPage *page);
+int eve_pagew_touch(EVEWidget *_widget, EVEPage *page, uint8_t tag0, int touch_idx);
+uint8_t eve_pagew_draw(EVEWidget *_widget, EVEPage *page, uint8_t tag0);
diff --git a/fw/fe310/eos/eve/widget/strw.c b/fw/fe310/eos/eve/widget/strw.c
new file mode 100644
index 0000000..2a80a28
--- /dev/null
+++ b/fw/fe310/eos/eve/widget/strw.c
@@ -0,0 +1,418 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "eve.h"
+#include "eve_kbd.h"
+#include "unicode.h"
+
+#include "screen/screen.h"
+#include "screen/window.h"
+#include "screen/page.h"
+#include "screen/font.h"
+
+#include "clipb.h"
+#include "label.h"
+#include "widget.h"
+#include "strw.h"
+
+#define CH_BS 0x08
+#define CH_DEL 0x7f
+#define CH_EOF 0x1a
+
+#define CH_CTRLX 0x18
+#define CH_CTRLC 0x03
+#define CH_CTRLV 0x16
+
+#define STRW_TMODE_CURSOR 1
+#define STRW_TMODE_SCROLL_X 2
+#define STRW_TMODE_SCROLL_Y 3
+
+#define CHAR_VALID_INPUT(c) ((c >= 0x20) && (c < 0x7f))
+
+void eve_strw_init(EVEStrWidget *widget, EVERect *g, EVEFont *font, utf8_t *str, uint16_t str_size) {
+ int rv, str_len;
+ EVEWidget *_widget = &widget->w;
+
+ memset(widget, 0, sizeof(EVEStrWidget));
+ eve_widget_init(_widget, EVE_WIDGET_TYPE_STR, g, eve_strw_touch, eve_strw_draw, eve_strw_putc);
+ widget->font = font;
+ widget->str = str;
+ widget->str_size = str_size;
+ rv = utf8_verify(str, str_size, &str_len);
+ if (rv != UTF_OK) {
+ if (str_len >= str_size) str_len = 0;
+ widget->str[str_len] = '\0';
+ }
+ widget->str_len = str_len;
+ widget->str_g.w = eve_font_str_w(font, str);
+ if (_widget->g.h == 0) _widget->g.h = eve_font_h(font);
+}
+
+static void set_focus(EVEStrWidget *widget, EVEPage *page) {
+ EVERect focus;
+ EVEWidget *_widget = &widget->w;
+
+ focus.x = _widget->g.x;
+ focus.y = _widget->g.y;
+ focus.w = _widget->g.w;
+ focus.h = 2 * widget->font->h;
+ eve_page_set_focus(page, _widget, &focus);
+}
+
+static EVEStrCursor *cursor_prox(EVEStrWidget *widget, EVEStrCursor *cursor, EVEPage *page, EVETouch *t, short *dx) {
+ EVEWidget *_widget = &widget->w;
+ int x = eve_page_x(page, t->x0) - _widget->g.x + widget->str_g.x;
+ int _dx;
+
+ *dx = cursor->x - x;
+ _dx = *dx < 0 ? -(*dx) : *dx;
+
+ if (_dx <= widget->font->w) return cursor;
+ return NULL;
+}
+
+int eve_strw_touch(EVEWidget *_widget, EVEPage *page, uint8_t tag0, int touch_idx) {
+ EVEStrWidget *widget = (EVEStrWidget *)_widget;
+ EVETouch *t;
+ uint16_t evt;
+
+ if (touch_idx > 0) return 0;
+
+ t = eve_touch_evt(tag0, touch_idx, widget->tag, 1, &evt);
+ if (t && evt) {
+ EVEStrCursor *t_cursor = NULL;
+ short dx;
+
+ if (evt & (EVE_TOUCH_ETYPE_LPRESS | EVE_TOUCH_ETYPE_TRACK_START)) {
+ if (widget->cursor2.on) {
+ t_cursor = cursor_prox(widget, &widget->cursor2, page, t, &dx);
+ }
+ if ((t_cursor == NULL) && widget->cursor1.on) {
+ t_cursor = cursor_prox(widget, &widget->cursor1, page, t, &dx);
+ }
+ if (evt & EVE_TOUCH_ETYPE_TRACK_START) {
+ widget->track.cursor = t_cursor;
+ if (t_cursor) {
+ widget->track.mode = STRW_TMODE_CURSOR;
+ widget->track.dx = dx;
+ } else if (t->eevt & EVE_TOUCH_EETYPE_TRACK_X) {
+ widget->track.mode = STRW_TMODE_SCROLL_X;
+ } else if (t->eevt & EVE_TOUCH_EETYPE_TRACK_Y) {
+ widget->track.mode = STRW_TMODE_SCROLL_Y;
+ }
+ }
+ }
+
+ switch (widget->track.mode) {
+ case STRW_TMODE_SCROLL_Y:
+ if (page->handle_evt) page->handle_evt(page, _widget, t, evt, tag0, touch_idx);
+ break;
+
+ case STRW_TMODE_SCROLL_X:
+ if (evt & EVE_TOUCH_ETYPE_TRACK_START) {
+ widget->str_g.x0 = widget->str_g.x;
+ }
+ if (evt & EVE_TOUCH_ETYPE_TRACK) {
+ int x = widget->str_g.x0 + t->x0 - t->x;
+ int w1 = widget->w.g.w - widget->font->w;
+
+ if (x > widget->str_g.w - w1) x = widget->str_g.w - w1;
+ if (x < 0) x = 0;
+ widget->str_g.x = x;
+ }
+ break;
+
+ case STRW_TMODE_CURSOR:
+ if (evt & EVE_TOUCH_ETYPE_TRACK) eve_strw_cursor_set(widget, widget->track.cursor, eve_page_x(page, t->x) + widget->track.dx);
+ break;
+
+ default:
+ if (evt & EVE_TOUCH_ETYPE_LPRESS) {
+ if (widget->cursor2.on) {
+ // copy
+ } else if (widget->cursor1.on) {
+ if (t_cursor) {
+ // paste
+ } else {
+ eve_strw_cursor_set(widget, &widget->cursor2, eve_page_x(page, t->x));
+ }
+ } else {
+ // select
+ }
+ }
+ if ((evt & EVE_TOUCH_ETYPE_POINT_UP) && !(t->eevt & EVE_TOUCH_EETYPE_LPRESS)) {
+ eve_strw_cursor_set(widget, &widget->cursor1, eve_page_x(page, t->x0));
+ if (widget->cursor2.on) eve_strw_cursor_clear(widget, &widget->cursor2);
+ set_focus(widget, page);
+ }
+ break;
+ }
+
+ if (evt & EVE_TOUCH_ETYPE_TRACK_STOP) {
+ widget->track.mode = 0;
+ widget->track.cursor = NULL;
+ widget->track.dx = 0;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static void _draw_str(EVEStrWidget *widget, EVEWindow *window, uint16_t ch, uint16_t len, uint16_t x1, uint16_t x2, char s) {
+ int16_t x;
+ EVEWidget *_widget = &widget->w;
+
+ x = _widget->g.x - widget->str_g.x;
+ if (x1 != x2) {
+ eve_cmd_dl(BEGIN(EVE_RECTS));
+ if (!s) eve_cmd_dl(COLOR_MASK(0 ,0 ,0 ,0));
+ eve_cmd_dl(VERTEX2F(x + x1, _widget->g.y));
+ eve_cmd_dl(VERTEX2F(x + x2, _widget->g.y + widget->font->h));
+ if (!s) eve_cmd_dl(COLOR_MASK(1 ,1 ,1 ,1));
+ eve_cmd_dl(END());
+ if (len) {
+ if (s) eve_cmd_dl(COLOR_RGBC(window->color_bg));
+ eve_cmd(CMD_TEXT, "hhhhpb", x + x1, _widget->g.y, widget->font->id, 0, widget->str + ch, len, 0);
+ if (s) eve_cmd_dl(COLOR_RGBC(window->color_fg));
+ }
+ }
+}
+
+static void _draw_cursor(EVEStrWidget *widget, EVEStrCursor *cursor) {
+ uint16_t x, y;
+ EVEWidget *_widget = &widget->w;
+
+ x = _widget->g.x - widget->str_g.x + cursor->x;
+ y = _widget->g.y;
+ eve_cmd_dl(BEGIN(EVE_LINES));
+ eve_cmd_dl(VERTEX2F(x, y));
+ eve_cmd_dl(VERTEX2F(x, y + widget->font->h));
+ eve_cmd_dl(END());
+}
+
+uint8_t eve_strw_draw(EVEWidget *_widget, EVEPage *page, uint8_t tag0) {
+ EVEStrWidget *widget = (EVEStrWidget *)_widget;
+ char cut = widget->str_g.x || (widget->str_g.w > _widget->g.w);
+
+ widget->tag = tag0;
+ if (tag0 != EVE_TAG_NOTAG) {
+ eve_cmd_dl(TAG(tag0));
+ eve_touch_set_opt(tag0, EVE_TOUCH_OPT_LPRESS);
+ tag0++;
+ }
+
+ if (cut) {
+ EVEWindow *window = page->v.window;
+ EVEScreen *screen = window->screen;
+ int16_t x = eve_page_scr_x(page, _widget->g.x);
+ int16_t y = eve_page_scr_y(page, _widget->g.y);
+ uint16_t w = _widget->g.w;
+ uint16_t h = _widget->g.h;
+ int16_t win_x1 = window->g.x;
+ int16_t win_y1 = window->g.y;
+ int16_t win_x2 = win_x1 + window->g.w;
+ int16_t win_y2 = win_y1 + window->g.h;
+
+ if (win_x1 < 0) win_x1 = 0;
+ if (win_y1 < 0) win_y1 = 0;
+ if (win_x2 > screen->w) win_x2 = screen->w;
+ if (win_y2 > screen->h) win_y2 = screen->h;
+ if (x < win_x1) {
+ w += x - win_x1;
+ x = win_x1;
+ }
+ if (y < win_y1) {
+ h += y - win_y1;
+ y = win_y1;
+ }
+ if (x + w > win_x2) w = win_x2 - x;
+ if (y + h > win_y2) h = win_y2 - y;
+
+ eve_cmd_dl(SAVE_CONTEXT());
+ eve_cmd_dl(SCISSOR_XY(x, y));
+ eve_cmd_dl(SCISSOR_SIZE(w, h));
+ }
+
+ if (widget->cursor2.on) {
+ EVEStrCursor *c1, *c2;
+ int l1, l2, l3;
+
+ if (widget->cursor1.ch <= widget->cursor2.ch) {
+ c1 = &widget->cursor1;
+ c2 = &widget->cursor2;
+ } else {
+ c1 = &widget->cursor2;
+ c2 = &widget->cursor1;
+ }
+
+ l1 = c1->ch;
+ l2 = c2->ch - c1->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, widget->str_len, 0, widget->str_g.x + _widget->g.w, 0);
+ }
+
+ if (cut) {
+ eve_cmd_dl(RESTORE_CONTEXT());
+ }
+
+ return tag0;
+}
+
+void eve_strw_putc(void *_page, int c) {
+ EVEPage *page = _page;
+ EVEStrWidget *widget = (EVEStrWidget *)eve_page_get_focus(page);
+ EVEStrCursor *cursor1 = &widget->cursor1;
+ EVEStrCursor *cursor2 = &widget->cursor2;
+ 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);
+ if (cursor2->on) eve_strw_cursor_clear(widget, cursor2);
+ return;
+ }
+
+ if (!cursor1->on) return;
+
+ if (!cursor2->on && ((c == CH_BS) || (c == CH_DEL))) {
+ utf32_t uc;
+
+ 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];
+
+ 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;
+ }
+ }
+
+ 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) {
+ int rv, clipb_len = 0;
+
+ clipb = eve_clipb_get();
+ if (clipb) {
+ rv = utf8_verify(clipb, EVE_CLIPB_SIZE_BUF, &clipb_len);
+ if (rv != UTF_OK) {
+ clipb = NULL;
+ clipb_len = 0;
+ }
+ }
+ ins_c = clipb_len;
+ 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 = utf8_buf[0];
+ }
+ c1->ch += ins_c;
+ c1->x += ins_w;
+ }
+ widget->str_len += ins_c - del_c;
+ widget->str_g.w += ins_w - del_w;
+ if (c1 == cursor2) widget->cursor1 = widget->cursor2;
+ 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;
+ if (cursor1->x - widget->str_g.x > w1) widget->str_g.x = cursor1->x - w1;
+}
+
+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;
+ 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) {
+ _x -= ch_w;
+ i -= ch_l;
+ }
+ break;
+ } else {
+ _d = x - _x;
+ }
+ }
+ cursor->x = _x;
+ cursor->ch = i;
+ cursor->on = 1;
+}
+
+void eve_strw_cursor_clear(EVEStrWidget *widget, EVEStrCursor *cursor) {
+ cursor->on = 0;
+}
diff --git a/fw/fe310/eos/eve/widget/strw.h b/fw/fe310/eos/eve/widget/strw.h
new file mode 100644
index 0000000..72fc6aa
--- /dev/null
+++ b/fw/fe310/eos/eve/widget/strw.h
@@ -0,0 +1,35 @@
+#include <stdint.h>
+
+typedef struct EVEStrCursor {
+ char on;
+ uint16_t x;
+ uint16_t ch;
+} EVEStrCursor;
+
+typedef struct EVEStrWidget {
+ EVEWidget w;
+ EVEFont *font;
+ utf8_t *str;
+ uint16_t str_size;
+ uint16_t str_len;
+ struct {
+ int16_t x;
+ int16_t x0;
+ uint16_t w;
+ } str_g;
+ EVEStrCursor cursor1;
+ EVEStrCursor cursor2;
+ uint8_t tag;
+ struct {
+ EVEStrCursor *cursor;
+ short dx;
+ char mode;
+ } track;
+} EVEStrWidget;
+
+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);
+void eve_strw_cursor_set(EVEStrWidget *widget, EVEStrCursor *cursor, int16_t x);
+void eve_strw_cursor_clear(EVEStrWidget *widget, EVEStrCursor *cursor); \ No newline at end of file
diff --git a/fw/fe310/eos/eve/widget/textw.c b/fw/fe310/eos/eve/widget/textw.c
new file mode 100644
index 0000000..bf075cf
--- /dev/null
+++ b/fw/fe310/eos/eve/widget/textw.c
@@ -0,0 +1,535 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "eve.h"
+#include "eve_kbd.h"
+#include "unicode.h"
+
+#include "screen/screen.h"
+#include "screen/window.h"
+#include "screen/page.h"
+#include "screen/font.h"
+
+#include "clipb.h"
+#include "label.h"
+#include "widget.h"
+#include "textw.h"
+
+#define CH_BS 0x08
+#define CH_DEL 0x7f
+#define CH_EOF 0x1a
+
+#define CH_CTRLX 0x18
+#define CH_CTRLC 0x03
+#define CH_CTRLV 0x16
+
+#define TEXTW_TMODE_CURSOR 1
+#define TEXTW_TMODE_SCROLL 2
+
+#define LINE_LEN(w,l) ((l) ? (w->line[l] ? w->line[l] - w->line[(l) - 1] - 1 : 0) : w->line[l])
+#define LINE_START(w,l) ((l) ? w->line[(l) - 1] + 1 : 0)
+#define LINE_END(w,l) (w->line[l])
+#define LINE_EMPTY 0xffff
+
+#define CHAR_VALID_INPUT(c) (((c >= 0x20) && (c < 0x7f)) || (c == '\n'))
+
+#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) {
+ int rv, text_len;
+ EVEWidget *_widget = &widget->w;
+
+ memset(widget, 0, sizeof(EVETextWidget));
+ eve_widget_init(_widget, EVE_WIDGET_TYPE_TEXT, g, eve_textw_touch, eve_textw_draw, eve_textw_putc);
+ widget->font = font;
+ widget->text = text;
+ widget->text_size = text_size;
+ rv = utf8_verify(text, text_size, &text_len);
+ if (rv != UTF_OK) {
+ if (text_len >= text_size) text_len = 0;
+ widget->text[text_len] = '\0';
+ }
+ widget->text_len = text_len;
+ widget->line = line;
+ widget->line_size = line_size;
+ 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) {
+ EVERect focus;
+ EVEWidget *_widget = &widget->w;
+
+ focus.x = _widget->g.x;
+ focus.y = _widget->g.y + cursor->line * widget->font->h;
+ focus.w = _widget->g.w;
+ focus.h = 2 * widget->font->h;
+ eve_page_set_focus(page, _widget, &focus);
+}
+
+static EVETextCursor *cursor_prox(EVETextWidget *widget, EVETextCursor *cursor, EVEPage *page, EVETouch *t, short *dx, short *dl) {
+ EVEWidget *_widget = &widget->w;
+ int x = eve_page_x(page, t->x0) - _widget->g.x;
+ int l = (int)t->tag0 - widget->tag0 + widget->line0;
+ int _dx, _dl;
+
+ *dx = cursor->x - x;
+ *dl = cursor->line - l;
+
+ _dx = *dx < 0 ? -(*dx) : *dx;
+ _dl = *dl < 0 ? -(*dl) : *dl;
+
+ if ((_dx <= widget->font->h) && (_dl <= 1)) return cursor;
+ return NULL;
+}
+
+int eve_textw_touch(EVEWidget *_widget, EVEPage *page, uint8_t tag0, int touch_idx) {
+ EVETextWidget *widget = (EVETextWidget *)_widget;
+ EVETouch *t;
+ uint16_t evt;
+ int ret = 0;
+
+ if (touch_idx > 0) return 0;
+
+ t = eve_touch_evt(tag0, touch_idx, widget->tag0, widget->tagN - widget->tag0, &evt);
+ if (t && evt) {
+ EVETextCursor *t_cursor = NULL;
+ short dx, dl;
+
+ if (evt & (EVE_TOUCH_ETYPE_LPRESS | EVE_TOUCH_ETYPE_TRACK_START)) {
+ if (widget->cursor2.on) {
+ t_cursor = cursor_prox(widget, &widget->cursor2, page, t, &dx, &dl);
+ }
+ if ((t_cursor == NULL) && widget->cursor1.on) {
+ t_cursor = cursor_prox(widget, &widget->cursor1, page, t, &dx, &dl);
+ }
+ if (evt & EVE_TOUCH_ETYPE_TRACK_START) {
+ widget->track.cursor = t_cursor;
+ if (t_cursor) {
+ widget->track.mode = TEXTW_TMODE_CURSOR;
+ widget->track.dx = dx;
+ widget->track.dl = dl;
+ } else {
+ widget->track.mode = TEXTW_TMODE_SCROLL;
+ }
+ }
+ }
+
+ switch (widget->track.mode) {
+ case TEXTW_TMODE_SCROLL:
+ if (page->handle_evt) page->handle_evt(page, _widget, t, evt, tag0, touch_idx);
+ break;
+
+ case TEXTW_TMODE_CURSOR:
+ if (evt & EVE_TOUCH_ETYPE_TRACK) eve_textw_cursor_set(widget, widget->track.cursor, t->tag + widget->track.dl, eve_page_x(page, t->x) + widget->track.dx);
+ break;
+
+ default:
+ if (evt & EVE_TOUCH_ETYPE_LPRESS) {
+ if (widget->cursor2.on) {
+ // copy
+ } else if (widget->cursor1.on) {
+ if (t_cursor && (dl == 0)) {
+ // paste
+ } else {
+ eve_textw_cursor_set(widget, &widget->cursor2, t->tag, eve_page_x(page, t->x));
+ }
+ } else {
+ // select
+ }
+ }
+ if ((evt & EVE_TOUCH_ETYPE_POINT_UP) && !(t->eevt & EVE_TOUCH_EETYPE_LPRESS)) {
+ eve_textw_cursor_set(widget, &widget->cursor1, t->tag_up, eve_page_x(page, t->x0));
+ if (widget->cursor2.on) eve_textw_cursor_clear(widget, &widget->cursor2);
+ set_focus(widget, &widget->cursor1, page);
+ }
+ break;
+ }
+
+ if (evt & EVE_TOUCH_ETYPE_TRACK_STOP) {
+ widget->track.mode = 0;
+ widget->track.cursor = NULL;
+ widget->track.dx = 0;
+ widget->track.dl = 0;
+ }
+
+ ret = 1;
+ }
+
+ return ret;
+}
+
+static void _draw_line(EVETextWidget *widget, EVEWindow *window, uint16_t l, uint16_t ch, uint16_t len, uint16_t x1, uint16_t x2, char s) {
+ EVEWidget *_widget = &widget->w;
+
+ if (x1 != x2) {
+ eve_cmd_dl(BEGIN(EVE_RECTS));
+ if (!s) eve_cmd_dl(COLOR_MASK(0 ,0 ,0 ,0));
+ eve_cmd_dl(VERTEX2F(_widget->g.x + x1, _widget->g.y + l * widget->font->h));
+ eve_cmd_dl(VERTEX2F(_widget->g.x + x2, _widget->g.y + (l + 1) * widget->font->h));
+ if (!s) eve_cmd_dl(COLOR_MASK(1 ,1 ,1 ,1));
+ eve_cmd_dl(END());
+ if (len) {
+ if (s) eve_cmd_dl(COLOR_RGBC(window->color_bg));
+ eve_cmd(CMD_TEXT, "hhhhpb", _widget->g.x + x1, _widget->g.y + l * widget->font->h, widget->font->id, 0, widget->text + ch, len, 0);
+ if (s) eve_cmd_dl(COLOR_RGBC(window->color_fg));
+ }
+ }
+}
+
+static void _draw_cursor(EVETextWidget *widget, EVETextCursor *cursor) {
+ uint16_t x, y;
+ EVEWidget *_widget = &widget->w;
+
+ x = _widget->g.x + cursor->x;
+ y = _widget->g.y + cursor->line * widget->font->h;
+ eve_cmd_dl(BEGIN(EVE_LINES));
+ eve_cmd_dl(VERTEX2F(x, y));
+ eve_cmd_dl(VERTEX2F(x, y + widget->font->h));
+ eve_cmd_dl(END());
+}
+
+uint8_t eve_textw_draw(EVEWidget *_widget, EVEPage *page, uint8_t tag0) {
+ EVETextWidget *widget = (EVETextWidget *)_widget;
+ int line0, lineN;
+ int _line0, _lineN;
+ char lineNvisible;
+
+ _line0 = line0 = ((int)page->win_y - _widget->g.y) / 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;
+ if (lineN > widget->line_len) lineN = widget->line_len;
+ lineNvisible = (lineN >= _line0) && (lineN < _lineN);
+
+ if (lineNvisible || (line0 < lineN)) {
+ int i;
+ char s = 0;
+ EVETextCursor *c1, *c2;
+
+ widget->line0 = line0;
+ widget->tag0 = tag0;
+ widget->tagN = tag0;
+
+ if (widget->cursor2.on) {
+ if (widget->cursor1.ch <= widget->cursor2.ch) {
+ c1 = &widget->cursor1;
+ c2 = &widget->cursor2;
+ } else {
+ c1 = &widget->cursor2;
+ c2 = &widget->cursor1;
+ }
+ } else {
+ c1 = NULL;
+ c2 = NULL;
+ }
+
+ for (i=line0; i<lineN; i++) {
+ if (widget->tagN != EVE_TAG_NOTAG) {
+ eve_cmd_dl(TAG(widget->tagN));
+ eve_touch_set_opt(widget->tagN, EVE_TOUCH_OPT_LPRESS);
+ widget->tagN++;
+ }
+ if (!s && c1 && (c1->line == i)) {
+ int l1, l2, l3;
+
+ l1 = c1->ch - LINE_START(widget, i);
+ if (c2->line == i) {
+ l2 = c2->ch - c1->ch;
+ l3 = LINE_START(widget, i) + LINE_LEN(widget, i) - c2->ch;
+ } else {
+ l2 = LINE_START(widget, i) + LINE_LEN(widget, i) - c1->ch;
+ l3 = 0;
+ s = 1;
+ }
+ _draw_line(widget, page->v.window, i, LINE_START(widget, i), l1, 0, c1->x, 0);
+ _draw_line(widget, page->v.window, i, c1->ch, l2, c1->x, s ? _widget->g.w : c2->x, 1);
+ if (!s) {
+ _draw_line(widget, page->v.window, i, c2->ch, l3, c2->x, _widget->g.w, 0);
+ c1 = NULL;
+ c2 = NULL;
+ }
+ } else if (s && (c2->line == i)) {
+ int l1 = c2->ch - LINE_START(widget, i);
+ int l2 = LINE_START(widget, i) + LINE_LEN(widget, i) - c2->ch;
+
+ _draw_line(widget, page->v.window, i, LINE_START(widget, i), l1, 0, c2->x, 1);
+ _draw_line(widget, page->v.window, i, c2->ch, l2, c2->x, _widget->g.w, 0);
+ c1 = NULL;
+ c2 = NULL;
+ s = 0;
+ } else {
+ if (widget->cursor1.on && (widget->cursor1.line == i)) _draw_cursor(widget, &widget->cursor1);
+ _draw_line(widget, page->v.window, i, LINE_START(widget, i), LINE_LEN(widget, i), 0, _widget->g.w, s);
+ }
+ }
+ if (lineNvisible) {
+ if (widget->tagN != EVE_TAG_NOTAG) {
+ eve_cmd_dl(TAG(widget->tagN));
+ eve_touch_set_opt(widget->tagN, EVE_TOUCH_OPT_LPRESS);
+ widget->tagN++;
+ }
+ _draw_line(widget, page->v.window, lineN, 0, 0, 0, _widget->g.w, 0);
+ }
+
+ return widget->tagN;
+ } else {
+ widget->line0 = 0;
+ widget->tag0 = EVE_TAG_NOTAG;
+ widget->tagN = EVE_TAG_NOTAG;
+
+ return tag0;
+ }
+}
+
+void eve_textw_putc(void *_page, int c) {
+ EVEPage *page = _page;
+ EVETextWidget *widget = (EVETextWidget *)eve_page_get_focus(page);
+ EVETextCursor *cursor1 = &widget->cursor1;
+ EVETextCursor *cursor2 = &widget->cursor2;
+ utf8_t *text;
+ utf8_t *clipb = NULL;
+ int i, r;
+ int ins_c = 0, del_c = 0;
+ int ch_w = 0;
+
+ if (c == CH_EOF) {
+ if (cursor1->on) eve_textw_cursor_clear(widget, cursor1);
+ if (cursor2->on) eve_textw_cursor_clear(widget, cursor2);
+ return;
+ }
+
+ if (!cursor1->on) return;
+
+ if (!cursor2->on && ((c == CH_BS) || (c == CH_DEL))) {
+ utf32_t uc;
+
+ 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;
+ 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) {
+ int rv, clipb_len = 0;
+
+ clipb = eve_clipb_get();
+ if (clipb) {
+ rv = utf8_verify(clipb, EVE_CLIPB_SIZE_BUF, &clipb_len);
+ if (rv != UTF_OK) {
+ clipb = NULL;
+ clipb_len = 0;
+ }
+ }
+ ins_c = clipb_len;
+ 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 = utf8_buf[0];
+ }
+ c1->ch += ins_c;
+ }
+ if (c1 == cursor2) widget->cursor1 = widget->cursor2;
+ if (cursor2->on) eve_textw_cursor_clear(widget, cursor2);
+ }
+
+ if ((ins_c == 0) && (del_c == 0)) return;
+
+ widget->text_len += ins_c - del_c;
+ for (i=cursor1->line; i<widget->line_len; i++) {
+ widget->line[i] += ins_c - del_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 (cursor1->line && (cursor1->ch < LINE_START(widget, cursor1->line))) {
+ cursor1->line--;
+ eve_textw_cursor_update(widget, cursor1);
+ set_focus(widget, cursor1, page);
+ } else if (cursor1->ch > LINE_END(widget, cursor1->line)) {
+ while (cursor1->ch > LINE_END(widget, cursor1->line)) cursor1->line++;
+ eve_textw_cursor_update(widget, cursor1);
+ set_focus(widget, cursor1, page);
+ } else {
+ cursor1->x += ch_w;
+ }
+}
+
+uint16_t eve_textw_update(EVETextWidget *widget, EVEPage *page, uint16_t line) {
+ int i;
+ 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;
+
+ word_w = 0;
+ line_w = 0;
+ line_b = LINE_EMPTY;
+
+ 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;
+ widget->line[line] = i;
+ line++;
+ if ((ch == '\0') || (line == widget->line_size)) break;
+ word_w = 0;
+ line_w = 0;
+ line_b = LINE_EMPTY;
+ } else if (ch == ' ') {
+ word_w = 0;
+ line_w += ch_w;
+ line_b = i;
+ }
+ } else {
+ word_w += ch_w;
+ line_w += ch_w;
+ }
+ if ((line_w > _widget->g.w) && (line_b != LINE_EMPTY)) {
+ if (widget->line[line] == line_b) return line;
+ widget->line[line] = line_b;
+ line++;
+ if (line == widget->line_size) {
+ i = line_b;
+ break;
+ }
+ line_w = word_w;
+ line_b = LINE_EMPTY;
+ }
+ i += ch_l;
+ }
+
+ widget->line_len = line;
+ new_h = (line + 1) * widget->font->h;
+ for (i=line; i<widget->line_size; i++) {
+ widget->line[i] = LINE_EMPTY;
+ }
+
+ if (_widget->g.h != new_h) {
+ _widget->g.h = new_h;
+ if (page && page->update_g) page->update_g(page, _widget);
+ }
+
+ return line;
+}
+
+void eve_textw_cursor_update(EVETextWidget *widget, EVETextCursor *cursor) {
+ 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;
+}
+
+void eve_textw_cursor_set(EVETextWidget *widget, EVETextCursor *cursor, uint8_t tag, int16_t x) {
+ 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;
+ if (c_line < widget->line_len) {
+ cursor->line = c_line;
+ } else if (c_line == widget->line_len) {
+ cursor->line = c_line - 1;
+ } else if (!cursor->on) {
+ return;
+ }
+
+ x -= _widget->g.x;
+
+ _x = 0;
+ _d = x;
+ 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) {
+ _x -= ch_w;
+ i -= ch_l;
+ }
+ break;
+ } else {
+ _d = x - _x;
+ }
+ }
+ cursor->x = _x;
+ cursor->ch = i;
+ cursor->on = 1;
+}
+
+void eve_textw_cursor_clear(EVETextWidget *widget, EVETextCursor *cursor) {
+ cursor->on = 0;
+}
diff --git a/fw/fe310/eos/eve/widget/textw.h b/fw/fe310/eos/eve/widget/textw.h
new file mode 100644
index 0000000..cd46ea3
--- /dev/null
+++ b/fw/fe310/eos/eve/widget/textw.h
@@ -0,0 +1,39 @@
+#include <stdint.h>
+
+typedef struct EVETextCursor {
+ char on;
+ uint16_t x;
+ uint16_t line;
+ uint16_t ch;
+} EVETextCursor;
+
+typedef struct EVETextWidget {
+ EVEWidget w;
+ EVEFont *font;
+ utf8_t *text;
+ uint16_t text_size;
+ uint16_t text_len;
+ uint16_t *line;
+ uint16_t line_size;
+ uint16_t line_len;
+ EVETextCursor cursor1;
+ EVETextCursor cursor2;
+ uint16_t line0;
+ uint8_t tag0;
+ uint8_t tagN;
+ struct {
+ EVETextCursor *cursor;
+ short dx;
+ short dl;
+ char mode;
+ } track;
+} EVETextWidget;
+
+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);
+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/fw/fe310/eos/eve/widget/widget.c b/fw/fe310/eos/eve/widget/widget.c
new file mode 100644
index 0000000..ab121d8
--- /dev/null
+++ b/fw/fe310/eos/eve/widget/widget.c
@@ -0,0 +1,41 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "eve.h"
+#include "eve_kbd.h"
+#include "unicode.h"
+
+#include "screen/screen.h"
+#include "screen/window.h"
+#include "screen/page.h"
+#include "screen/font.h"
+
+#include "label.h"
+#include "widget.h"
+#include "pagew.h"
+#include "strw.h"
+#include "textw.h"
+
+static const size_t _eve_wsize[] = {
+ 0,
+ sizeof(EVEPageWidget),
+ sizeof(EVEStrWidget),
+ sizeof(EVETextWidget)
+};
+
+void eve_widget_init(EVEWidget *widget, uint8_t type, EVERect *g, eve_widget_touch_t touch, eve_widget_draw_t draw, eve_kbd_input_handler_t putc) {
+ if (g) widget->g = *g;
+ widget->touch = touch;
+ widget->draw = draw;
+ widget->putc = putc;
+ widget->type = type;
+}
+
+void eve_widget_set_label(EVEWidget *widget, EVELabel *label) {
+ widget->label = label;
+}
+
+EVEWidget *eve_widget_next(EVEWidget *widget) {
+ char *_w = (char *)widget;
+ return (EVEWidget *)(_w + _eve_wsize[widget->type]);
+}
diff --git a/fw/fe310/eos/eve/widget/widget.h b/fw/fe310/eos/eve/widget/widget.h
new file mode 100644
index 0000000..1aa2cd7
--- /dev/null
+++ b/fw/fe310/eos/eve/widget/widget.h
@@ -0,0 +1,23 @@
+#include <stdint.h>
+
+#define EVE_WIDGET_TYPE_PAGE 1
+#define EVE_WIDGET_TYPE_STR 2
+#define EVE_WIDGET_TYPE_TEXT 3
+
+struct EVEWidget;
+
+typedef int (*eve_widget_touch_t) (struct EVEWidget *, EVEPage *, uint8_t, int);
+typedef uint8_t (*eve_widget_draw_t) (struct EVEWidget *, EVEPage *, uint8_t);
+
+typedef struct EVEWidget {
+ EVERect g;
+ eve_widget_touch_t touch;
+ eve_widget_draw_t draw;
+ eve_kbd_input_handler_t putc;
+ EVELabel *label;
+ uint8_t type;
+} EVEWidget;
+
+void eve_widget_init(EVEWidget *widget, uint8_t type, EVERect *g, eve_widget_touch_t touch, eve_widget_draw_t draw, eve_kbd_input_handler_t putc);
+void eve_widget_set_label(EVEWidget *widget, EVELabel *label);
+EVEWidget *eve_widget_next(EVEWidget *widget);