summaryrefslogtreecommitdiff
path: root/fw/fe310/eos/eve/widget/strw.c
diff options
context:
space:
mode:
Diffstat (limited to 'fw/fe310/eos/eve/widget/strw.c')
-rw-r--r--fw/fe310/eos/eve/widget/strw.c446
1 files changed, 446 insertions, 0 deletions
diff --git a/fw/fe310/eos/eve/widget/strw.c b/fw/fe310/eos/eve/widget/strw.c
new file mode 100644
index 0000000..e78cf46
--- /dev/null
+++ b/fw/fe310/eos/eve/widget/strw.c
@@ -0,0 +1,446 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "clipb.h"
+
+#include "eve.h"
+#include "eve_kbd.h"
+#include "eve_font.h"
+
+#include "screen/window.h"
+#include "screen/page.h"
+
+#include "label.h"
+#include "widget.h"
+#include "strw.h"
+
+#define STRW_TOUCH_OPT EVE_TOUCH_OPT_TRACK | EVE_TOUCH_OPT_TRACK_X | EVE_TOUCH_OPT_TRACK_EXT_X | EVE_TOUCH_OPT_LPRESS
+
+#define STRW_TMODE_NONE 0
+#define STRW_TMODE_CRSR 1
+#define STRW_TMODE_TXT 2
+
+#define CH_BS 0x08
+#define CH_DEL 0x7f
+
+#define CH_CTRLX 0x18
+#define CH_CTRLC 0x03
+#define CH_CTRLV 0x16
+
+#define CHAR_VALID_INPUT(c) ((c >= 0x20) && (c < 0x7f))
+
+int eve_strw_create(EVEStrWidget *widget, EVERect *g, EVEPage *page, EVEStrSpec *spec) {
+ EVEFont *font = spec->font ? spec->font : eve_window_font(page->v.window);
+ utf8_t *str;
+ uint16_t *line;
+
+ str = eve_malloc(spec->str_size);
+ if (str == NULL) return EVE_ERR_NOMEM;
+ str[0] = '\0';
+
+ eve_strw_init(widget, g, page, font, str, spec->str_size);
+
+ return EVE_OK;
+}
+
+void eve_strw_init(EVEStrWidget *widget, EVERect *g, EVEPage *page, EVEFont *font, utf8_t *str, uint16_t str_size) {
+ EVEWidget *_widget = &widget->w;
+ int rv, str_len;
+
+ memset(widget, 0, sizeof(EVEStrWidget));
+ eve_widget_init(_widget, EVE_WIDGET_TYPE_STR, g, page, eve_strw_draw, eve_strw_touch, eve_strw_putc);
+ widget->font = font;
+ rv = utf8_verify(str, str_size, &str_len);
+ if (rv != UTF_OK) {
+ if (str_len >= str_size) str_len = 0;
+ str[str_len] = '\0';
+ }
+ widget->str = str;
+ widget->str_size = str_size;
+ widget->str_len = str_len;
+ widget->str_g.w = eve_font_str_w(widget->font, str);
+ if (_widget->g.h == 0) _widget->g.h = eve_font_h(widget->font);
+}
+
+int eve_strw_update(EVEStrWidget *widget) {
+ int rv, str_len;
+
+ rv = utf8_verify(widget->str, widget->str_size, &str_len);
+ if (rv != UTF_OK) {
+ if (str_len >= widget->str_size) str_len = 0;
+ widget->str[str_len] = '\0';
+ }
+ widget->str_len = str_len;
+ return (rv == UTF_OK) ? EVE_OK : EVE_ERR;
+}
+
+void eve_strw_destroy(EVEStrWidget *widget) {
+ eve_free(widget->str);
+}
+
+static void set_focus(EVEStrWidget *widget) {
+ EVEWidget *_widget = &widget->w;
+ EVERect focus;
+
+ focus.x = _widget->g.x;
+ focus.y = _widget->g.y;
+ focus.w = _widget->g.w;
+ focus.h = 2 * widget->font->h;
+ eve_widget_focus(_widget, &focus);
+}
+
+static EVEStrCursor *cursor_prox(EVEStrWidget *widget, EVEStrCursor *cursor, EVETouch *touch, short *dx) {
+ EVEWidget *_widget = &widget->w;
+ EVEPage *page = _widget->page;
+ int x = eve_page_x(page, touch->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;
+}
+
+static void draw_string(EVEStrWidget *widget, uint16_t ch, uint16_t len, uint16_t x1, uint16_t x2, char s) {
+ int16_t x;
+ EVEWidget *_widget = &widget->w;
+ EVEPage *page = _widget->page;
+
+ 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(BEGIN(EVE_LINES));
+ eve_cmd_dl(VERTEX2F(x + x1, _widget->g.y + widget->font->h));
+ eve_cmd_dl(VERTEX2F(x + x2, _widget->g.y + widget->font->h));
+ }
+ eve_cmd_dl(END());
+ if (len) {
+ if (s) eve_cmd_dl(COLOR_RGBC(page->v.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(page->v.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, uint8_t tag0) {
+ EVEStrWidget *widget = (EVEStrWidget *)_widget;
+ char cut = widget->str_g.x || (widget->str_g.w > _widget->g.w);
+
+ _widget->tag0 = tag0;
+ if (tag0 != EVE_NOTAG) {
+ eve_cmd_dl(TAG(tag0));
+ eve_touch_set_opt(tag0, STRW_TOUCH_OPT);
+ tag0++;
+ }
+ _widget->tagN = tag0;
+
+ if (cut) {
+ EVEPage *page = _widget->page;
+ EVEWindow *window = page->v.window;
+ 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 > window->root->w.g.w) win_x2 = window->root->w.g.w;
+ if (win_y2 > window->root->w.g.h) win_y2 = window->root->w.g.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_string(widget, 0, l1, 0, c1->x, 0);
+ draw_string(widget, c1->ch, l2, c1->x, c2->x, 1);
+ draw_string(widget, c2->ch, l3, c2->x, widget->str_g.x + _widget->g.w, 0);
+ } else {
+ if (widget->cursor1.on) draw_cursor(widget, &widget->cursor1);
+ draw_string(widget, 0, widget->str_len, 0, widget->str_g.x + _widget->g.w, 0);
+ }
+
+ if (cut) {
+ eve_cmd_dl(RESTORE_CONTEXT());
+ }
+
+ return _widget->tagN;
+}
+
+int eve_strw_touch(EVEWidget *_widget, EVETouch *touch, uint16_t evt) {
+ EVEPage *page = _widget->page;
+ EVEStrWidget *widget = (EVEStrWidget *)_widget;
+ EVEStrCursor *t_cursor = NULL;
+ short dx;
+ int ret = 0;
+
+ if (evt & (EVE_TOUCH_ETYPE_LPRESS | EVE_TOUCH_ETYPE_TRACK_START)) {
+ if (widget->cursor2.on) {
+ t_cursor = cursor_prox(widget, &widget->cursor2, touch, &dx);
+ }
+ if ((t_cursor == NULL) && widget->cursor1.on) {
+ t_cursor = cursor_prox(widget, &widget->cursor1, touch, &dx);
+ }
+ if (evt & EVE_TOUCH_ETYPE_TRACK_START) {
+ if (t_cursor) {
+ widget->track.mode = STRW_TMODE_CRSR;
+ widget->track.cursor = t_cursor;
+ widget->track.dx = dx;
+ } else if (touch->eevt & EVE_TOUCH_EETYPE_TRACK_X) {
+ widget->track.mode = STRW_TMODE_TXT;
+ }
+ }
+ }
+
+ if (widget->track.mode) {
+ int x, w1;
+
+ if (evt & EVE_TOUCH_ETYPE_TRACK) {
+ switch (widget->track.mode) {
+ case STRW_TMODE_TXT:
+ if (evt & EVE_TOUCH_ETYPE_TRACK_START) {
+ widget->str_g.x0 = widget->str_g.x;
+ }
+ x = widget->str_g.x0 + touch->x0 - touch->x;
+ w1 = _widget->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_CRSR:
+ eve_strw_cursor_set(widget, widget->track.cursor, eve_page_x(page, touch->x) + widget->track.dx);
+ break;
+ }
+ }
+ ret = 1;
+ } else {
+ 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, touch->x));
+ }
+ } else {
+ // select
+ }
+ ret = 1;
+ }
+ if ((evt & EVE_TOUCH_ETYPE_POINT_UP) && !(touch->eevt & (EVE_TOUCH_EETYPE_TRACK_XY | EVE_TOUCH_EETYPE_ABORT | EVE_TOUCH_EETYPE_LPRESS))) {
+ eve_strw_cursor_set(widget, &widget->cursor1, eve_page_x(page, touch->x0));
+ if (widget->cursor2.on) eve_strw_cursor_clear(widget, &widget->cursor2);
+ set_focus(widget);
+ ret = 1;
+ }
+ }
+
+ if (evt & EVE_TOUCH_ETYPE_TRACK_STOP) {
+ widget->track.mode = STRW_TMODE_NONE;
+ widget->track.cursor = NULL;
+ widget->track.dx = 0;
+ }
+
+ return ret;
+}
+
+void eve_strw_putc(void *w, int c) {
+ EVEStrWidget *widget = (EVEStrWidget *)w;
+ EVEWidget *_widget = &widget->w;
+ EVEStrCursor *cursor1 = &widget->cursor1;
+ EVEStrCursor *cursor2 = &widget->cursor2;
+ utf8_t *str;
+ utf8_t *clipb = NULL;
+ int w0 = widget->font->w;
+ int w1 = _widget->g.w - widget->font->w;
+ int ins_c = 0, del_c = 0;
+ int ins_w = 0, del_w = 0;
+
+
+ if (c == EVE_PAGE_KBDCH_CLOSE) {
+ 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;
+}