From daa87d92b3df433578e53284a8c88083e24f8623 Mon Sep 17 00:00:00 2001
From: Uros Majstorovic <majstor@majstor.org>
Date: Sat, 27 Mar 2021 22:08:31 +0100
Subject: form/app cleanup; scroll infrastructure

---
 fw/fe310/eos/app/Makefile         |   2 +-
 fw/fe310/eos/app/app_form.c       |  85 -----------
 fw/fe310/eos/app/app_form.h       |   6 -
 fw/fe310/eos/app/app_root.c       |   6 +-
 fw/fe310/eos/app/app_root.h       |   2 +-
 fw/fe310/eos/app/app_status.c     |   2 +-
 fw/fe310/eos/eve/eve.h            |   2 -
 fw/fe310/eos/eve/eve_text.c       |   4 +-
 fw/fe310/eos/eve/eve_touch.c      |   2 +-
 fw/fe310/eos/eve/eve_touch.h      |   1 +
 fw/fe310/eos/eve/screen/form.c    | 233 ++++++++++++-----------------
 fw/fe310/eos/eve/screen/form.h    |  23 +--
 fw/fe310/eos/eve/screen/page.c    | 305 +++++++++++++++++++++++++++++++++-----
 fw/fe310/eos/eve/screen/page.h    |  42 ++++--
 fw/fe310/eos/eve/screen/uievt.h   |  10 +-
 fw/fe310/eos/eve/screen/view.c    |  41 ++++-
 fw/fe310/eos/eve/screen/view.h    |   7 +-
 fw/fe310/eos/eve/screen/window.c  |  85 +++++++----
 fw/fe310/eos/eve/screen/window.h  |  18 ++-
 fw/fe310/eos/eve/widget/freew.c   |  12 +-
 fw/fe310/eos/eve/widget/freew.h   |   1 -
 fw/fe310/eos/eve/widget/pagew.c   |  14 +-
 fw/fe310/eos/eve/widget/pagew.h   |   1 -
 fw/fe310/eos/eve/widget/selectw.c | 132 +++++++++--------
 fw/fe310/eos/eve/widget/selectw.h |   7 +-
 fw/fe310/eos/eve/widget/strw.c    |  53 +++----
 fw/fe310/eos/eve/widget/strw.h    |   1 -
 fw/fe310/eos/eve/widget/textw.c   |  64 ++++----
 fw/fe310/eos/eve/widget/textw.h   |   3 +-
 fw/fe310/eos/eve/widget/widget.c  |   9 +-
 fw/fe310/eos/eve/widget/widget.h  |   3 +-
 fw/fe310/test/cell_pdp.c          |  11 +-
 fw/fe310/test/main.c              |   3 +-
 fw/fe310/test/modem.c             |  11 +-
 fw/fe310/test/phone.c             |   5 +-
 fw/fe310/test/status.c            |   9 +-
 fw/fe310/test/wifi.c              |  14 +-
 37 files changed, 686 insertions(+), 543 deletions(-)
 delete mode 100644 fw/fe310/eos/app/app_form.c
 delete mode 100644 fw/fe310/eos/app/app_form.h

diff --git a/fw/fe310/eos/app/Makefile b/fw/fe310/eos/app/Makefile
index 9560fd7..e0eee28 100644
--- a/fw/fe310/eos/app/Makefile
+++ b/fw/fe310/eos/app/Makefile
@@ -2,7 +2,7 @@ include ../../common.mk
 
 CFLAGS += -I..
 
-obj = app_root.o app_status.o app_form.o
+obj = app_root.o app_status.o
 
 
 %.o: %.c %.h
diff --git a/fw/fe310/eos/app/app_form.c b/fw/fe310/eos/app/app_form.c
deleted file mode 100644
index 8daf09e..0000000
--- a/fw/fe310/eos/app/app_form.c
+++ /dev/null
@@ -1,85 +0,0 @@
-#include <stdlib.h>
-
-#include "eve/eve.h"
-#include "eve/eve_kbd.h"
-#include "eve/eve_font.h"
-
-#include "eve/screen/window.h"
-#include "eve/screen/page.h"
-#include "eve/screen/form.h"
-
-#include "eve/widget/widgets.h"
-
-#include "app_form.h"
-
-static void widgets_destroy(EVEWidget *widget, uint16_t widget_size) {
-    int i;
-
-    for (i=0; i<widget_size; i++) {
-        if (widget->label) eve_free(widget->label);
-        eve_widget_destroy(widget);
-        widget = eve_widget_next(widget);
-    }
-}
-
-EVEForm *app_form_create(EVEWindow *window, EVEViewStack *stack, EVEWidgetSpec spec[], uint16_t spec_size, eve_form_action_t action, eve_form_destructor_t destructor) {
-    EVEWidget *widgets;
-    EVEWidget *widget;
-    EVELabel *label;
-    EVEForm *form;
-    int w_size = 0;
-    int i, r;
-
-    for (i=0; i<spec_size; i++) {
-        w_size += eve_widget_size(spec[i].widget.type);
-    }
-    form = eve_malloc(sizeof(EVEForm));
-    if (form == NULL) {
-        return NULL;
-    }
-    if (destructor == NULL) destructor = app_form_destroy;
-    eve_form_init(form, window, stack, NULL, 0, action, destructor);
-
-    widgets = eve_malloc(w_size);
-    if (widgets == NULL) {
-        eve_free(form);
-        return NULL;
-    }
-
-    widget = widgets;
-    for (i=0; i<spec_size; i++) {
-        r = eve_widget_create(widget, spec[i].widget.type, &spec[i].widget.g, (EVEPage *)form, &spec[i].widget.spec);
-        if (r) {
-            widgets_destroy(widgets, i);
-            eve_free(widgets);
-            eve_free(form);
-            return NULL;
-        }
-        if (spec[i].label.title) {
-            EVEFont *font = spec[i].label.font ? spec[i].label.font : eve_window_font(window);
-            label = eve_malloc(sizeof(EVELabel));
-            if (label == NULL) {
-                eve_widget_destroy(widget);
-                widgets_destroy(widgets, i);
-                eve_free(widgets);
-                eve_free(form);
-                return NULL;
-            }
-            eve_label_init(label, &spec[i].label.g, font, spec[i].label.title);
-            eve_widget_set_label(widget, label);
-            if (label->g.w == 0) label->g.w = eve_font_str_w(font, label->title);
-        }
-        if (widget->label && (widget->label->g.w == 0)) eve_font_str_w(label->font, label->title) + APP_LABEL_MARGIN;
-        if (widget->g.w == 0) widget->g.w = window->g.w - (widget->label ? widget->label->g.w : 0);
-        widget = eve_widget_next(widget);
-    }
-    eve_form_update(form, widgets, spec_size, NULL);
-
-    return form;
-}
-
-void app_form_destroy(EVEForm *form) {
-    widgets_destroy(form->widget, form->widget_size);
-    eve_free(form->widget);
-    eve_free(form);
-}
diff --git a/fw/fe310/eos/app/app_form.h b/fw/fe310/eos/app/app_form.h
deleted file mode 100644
index ec0993c..0000000
--- a/fw/fe310/eos/app/app_form.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#include <stdint.h>
-
-#define APP_LABEL_MARGIN    10
-
-EVEForm *app_form_create(EVEWindow *window, EVEViewStack *stack, EVEWidgetSpec spec[], uint16_t spec_size, eve_form_action_t action, eve_form_destructor_t destructor);
-void app_form_destroy(EVEForm *form);
diff --git a/fw/fe310/eos/app/app_root.c b/fw/fe310/eos/app/app_root.c
index 7a6f5c3..1b46ea8 100644
--- a/fw/fe310/eos/app/app_root.c
+++ b/fw/fe310/eos/app/app_root.c
@@ -29,8 +29,8 @@ static EVEWindow win_main;
 static EVEView view_status;
 static EVEViewStack view_stack;
 
-EVEWindow *app_root(void) {
-    return (EVEWindow *)&win_root;
+EVEWindowRoot *app_root(void) {
+    return &win_root;
 }
 
 void app_root_refresh(void) {
@@ -80,7 +80,7 @@ void app_root_init(eve_view_constructor_t home_page) {
     eve_window_append(&win_status);
     eve_window_append(&win_main);
 
-    eve_window_root_draw((EVEWindow *)&win_root);
+    eve_window_root_draw(&win_root);
 
     eve_spi_stop();
 
diff --git a/fw/fe310/eos/app/app_root.h b/fw/fe310/eos/app/app_root.h
index a7907df..7a44565 100644
--- a/fw/fe310/eos/app/app_root.h
+++ b/fw/fe310/eos/app/app_root.h
@@ -6,7 +6,7 @@
 
 #define APP_FONT_HANDLE     31
 
-EVEWindow *app_root(void);
+EVEWindowRoot *app_root(void);
 void app_root_refresh(void);
 
 void app_root_init(eve_view_constructor_t home_page);
diff --git a/fw/fe310/eos/app/app_status.c b/fw/fe310/eos/app/app_status.c
index 1d95728..4ab0a97 100644
--- a/fw/fe310/eos/app/app_status.c
+++ b/fw/fe310/eos/app/app_status.c
@@ -9,7 +9,7 @@
 #include "app_status.h"
 
 uint8_t app_status_draw(EVEView *view, uint8_t tag0) {
-    return eve_view_clear(view, tag0);
+    return eve_view_clear(view, tag0, 0);
 }
 
 int app_status_touch(EVEView *view, EVETouch *touch, uint16_t evt, uint8_t tag0) {
diff --git a/fw/fe310/eos/eve/eve.h b/fw/fe310/eos/eve/eve.h
index d813dce..e85ed76 100644
--- a/fw/fe310/eos/eve/eve.h
+++ b/fw/fe310/eos/eve/eve.h
@@ -18,8 +18,6 @@
 #define EVE_PSTATE_STANDBY  1
 #define EVE_PSTATE_SLEEP    3
 
-#define EVE_TAG_NOTAG       0
-
 #define COLOR_RGBC(c)       ((4UL<<24)|((c)&16777215UL))
 #define CLEAR_COLOR_RGBC(c) ((2UL<<24)|((c)&16777215UL))
 
diff --git a/fw/fe310/eos/eve/eve_text.c b/fw/fe310/eos/eve/eve_text.c
index eecfa0a..b52678d 100644
--- a/fw/fe310/eos/eve/eve_text.c
+++ b/fw/fe310/eos/eve/eve_text.c
@@ -36,7 +36,7 @@ void eve_text_init(EVEText *box, EVERect *g, uint16_t w, uint16_t h, uint16_t li
     box->g = *g;
     box->w = w;
     box->h = h;
-    box->tag = EVE_TAG_NOTAG;
+    box->tag = EVE_NOTAG;
     box->transform_a = 256 / scale_x;
     box->transform_e = 256 / scale_y;
     box->ch_w = scale_x * 8;
@@ -146,7 +146,7 @@ int eve_text_touch(EVEText *box, EVETouch *touch, uint16_t evt, uint8_t tag0) {
 uint8_t eve_text_draw(EVEText *box, uint8_t tag) {
     eve_cmd_dl(SAVE_CONTEXT());
     box->tag = tag;
-    if (tag != EVE_TAG_NOTAG) {
+    if (tag != EVE_NOTAG) {
         eve_cmd_dl(TAG(tag));
         eve_touch_set_opt(tag, EVE_TOUCH_OPT_TRACK | EVE_TOUCH_OPT_TRACK_EXT_Y);
         tag++;
diff --git a/fw/fe310/eos/eve/eve_touch.c b/fw/fe310/eos/eve/eve_touch.c
index b5ca7fd..5b3cd39 100644
--- a/fw/fe310/eos/eve/eve_touch.c
+++ b/fw/fe310/eos/eve/eve_touch.c
@@ -334,7 +334,7 @@ uint16_t eve_touch_evt(EVETouch *touch, uint16_t evt, uint8_t tag0, uint8_t tag_
     uint8_t _tag;
     uint16_t _evt;
 
-    if (tag_min == EVE_TAG_NOTAG) return 0;
+    if (tag_min == EVE_NOTAG) return 0;
 
     tag_max = tag_min + tag_n;
     if ((tag0 < tag_min) || (tag0 >= tag_max)) return 0;
diff --git a/fw/fe310/eos/eve/eve_touch.h b/fw/fe310/eos/eve/eve_touch.h
index d4de196..263379f 100644
--- a/fw/fe310/eos/eve/eve_touch.h
+++ b/fw/fe310/eos/eve/eve_touch.h
@@ -7,6 +7,7 @@
 #define EVE_TOUCH_THRESHOLD_Y           5
 #define EVE_TOUCH_TRAVG                 3
 
+#define EVE_NOTAG                       0
 #define EVE_NOTOUCH                     0x80008000
 #define EVE_MAX_TOUCH                   5
 
diff --git a/fw/fe310/eos/eve/screen/form.c b/fw/fe310/eos/eve/screen/form.c
index 8ea53c8..81c1b86 100644
--- a/fw/fe310/eos/eve/screen/form.c
+++ b/fw/fe310/eos/eve/screen/form.c
@@ -9,20 +9,20 @@
 #include "page.h"
 #include "form.h"
 
-#include "widget/label.h"
-#include "widget/widget.h"
+#include "widget/widgets.h"
 
 #define MIN(X, Y)               (((X) < (Y)) ? (X) : (Y))
 #define MAX(X, Y)               (((X) > (Y)) ? (X) : (Y))
 
 static void form_update_g(EVEForm *form, EVEWidget *_widget) {
-    EVEWidget *widget = form->widget;
+    EVEPage *page = &form->p;
+    EVEWidget *widget = page->widget;
     int i;
     uint16_t w = 0;
     uint16_t h = 0;
     uint16_t l_h = 0;
 
-    for (i=0; i<form->widget_size; i++) {
+    for (i=0; i<page->widget_size; i++) {
         if (widget->label) {
             h += l_h;
             w = widget->label->g.w;
@@ -43,173 +43,124 @@ static void form_update_g(EVEForm *form, EVEWidget *_widget) {
 
         widget = eve_widget_next(widget);
     }
-    form->w = form->p.v.window->g.w;
-    form->h = h + l_h;
+    page->g.w = page->v.window->g.w;
+    page->g.h = h + l_h;
 }
 
-static int form_handle_evt(EVEForm *form, EVEWidget *widget, EVETouch *touch, uint16_t evt, uint8_t tag0) {
-    int ret = 0;
-    EVEPage *page = &form->p;
+static void widgets_destroy(EVEWidget *widget, uint16_t widget_size) {
+    int i;
 
-    if ((evt & EVE_TOUCH_ETYPE_POINT_UP) && !(touch->eevt & (EVE_TOUCH_EETYPE_TRACK_XY | EVE_TOUCH_EETYPE_ABORT))) {
-        if (page->widget_f) eve_page_set_focus(page, NULL, NULL);
-        ret = 1;
+    for (i=0; i<widget_size; i++) {
+        if (widget->label) eve_free(widget->label);
+        eve_widget_destroy(widget);
+        widget = eve_widget_next(widget);
     }
+}
 
-    /* Scroll start */
-    if ((evt & EVE_TOUCH_ETYPE_TRACK_START) && !(touch->eevt & EVE_TOUCH_EETYPE_ABORT)) {
-        form->evt_lock = 1;
-    }
+EVEForm *eve_form_create(EVEWindow *window, EVEViewStack *stack, EVEWidgetSpec spec[], uint16_t spec_size, eve_form_action_t action, eve_form_destructor_t destructor) {
+    EVEWidget *widgets;
+    EVEWidget *widget;
+    EVELabel *label;
+    EVEForm *form;
+    int w_size = 0;
+    int i, r;
 
-    /* Scroll stop */
-    if (((evt & EVE_TOUCH_ETYPE_TRACK_STOP) && !(evt & EVE_TOUCH_ETYPE_TRACK_ABORT)) ||
-        ((evt & EVE_TOUCH_ETYPE_POINT_UP) && (touch->eevt & EVE_TOUCH_EETYPE_ABORT) && !(touch->eevt & EVE_TOUCH_EETYPE_TRACK_XY))) {
-        int wmax_x, wmax_y;
-        int lho_x, lho_y;
-        EVERect vg;
-
-        eve_window_visible_g(page->v.window, &vg);
-        wmax_x = form->w > vg.w ? form->w - vg.w : 0;
-        wmax_y = form->h > vg.h ? form->h - vg.h : 0;
-        lho_x = page->win_x < 0 ? 0 : wmax_x;
-        lho_y = page->win_y < 0 ? 0 : wmax_y;
-        if ((page->win_x < 0) || (page->win_x > wmax_x) ||
-            (page->win_y < 0) || (page->win_y > wmax_y)) {
-            EVEPhyLHO *lho = &form->lho;
-            eve_phy_lho_init(lho, lho_x, lho_y, 1000, 0.5, 0);
-            eve_phy_lho_start(lho, page->win_x, page->win_y);
-            form->lho_t0 = eve_time_get_tick();
-            eve_touch_timer_start(tag0, 20);
-        } else {
-            form->evt_lock = 0;
-            if (evt & EVE_TOUCH_ETYPE_TRACK_STOP) {
-                if (touch->eevt & EVE_TOUCH_EETYPE_TRACK_RIGHT) {
-                    eve_page_close((EVEPage *)form);
-                    return 1;
-                }
-                if (touch->eevt & EVE_TOUCH_EETYPE_TRACK_LEFT) {
-                    if (form->action) form->action(form);
-                    return 1;
-                }
-            }
-        }
+    for (i=0; i<spec_size; i++) {
+        w_size += eve_widget_size(spec[i].widget.type);
     }
-
-    if (evt & EVE_TOUCH_ETYPE_TRACK_START) {
-        if (touch->eevt & EVE_TOUCH_EETYPE_TRACK_Y) {
-            form->win_y0 = page->win_y;
-        }
+    form = eve_malloc(sizeof(EVEForm));
+    if (form == NULL) {
+        return NULL;
     }
-    if (evt & EVE_TOUCH_ETYPE_TRACK) {
-        if (touch->eevt & EVE_TOUCH_EETYPE_TRACK_Y) {
-            page->win_y = form->win_y0 + touch->y0 - touch->y;
-        }
-        ret = 1;
+    if (destructor == NULL) destructor = eve_form_destroy;
+    eve_form_init(form, window, stack, NULL, 0, action, destructor);
+
+    widgets = eve_malloc(w_size);
+    if (widgets == NULL) {
+        eve_free(form);
+        return NULL;
     }
-    if (evt & EVE_TOUCH_ETYPE_TIMER) {
-        EVEPhyLHO *lho = &form->lho;
-        int more = eve_phy_lho_tick(lho, eve_time_get_tick() - form->lho_t0, NULL, &page->win_y);
 
-        if (!more) {
-            form->evt_lock = 0;
-            eve_touch_timer_stop();
+    widget = widgets;
+    for (i=0; i<spec_size; i++) {
+        r = eve_widget_create(widget, spec[i].widget.type, &spec[i].widget.g, (EVEPage *)form, &spec[i].widget.spec);
+        if (r) {
+            widgets_destroy(widgets, i);
+            eve_free(widgets);
+            eve_free(form);
+            return NULL;
         }
-        ret = 1;
+        if (spec[i].label.title) {
+            EVEFont *font = spec[i].label.font ? spec[i].label.font : eve_window_font(window);
+            label = eve_malloc(sizeof(EVELabel));
+            if (label == NULL) {
+                eve_widget_destroy(widget);
+                widgets_destroy(widgets, i);
+                eve_free(widgets);
+                eve_free(form);
+                return NULL;
+            }
+            eve_label_init(label, &spec[i].label.g, font, spec[i].label.title);
+            eve_widget_set_label(widget, label);
+            if (label->g.w == 0) label->g.w = eve_font_str_w(font, label->title);
+        }
+        if (widget->label && (widget->label->g.w == 0)) eve_font_str_w(label->font, label->title) + EVE_FORM_LABEL_MARGIN;
+        if (widget->g.w == 0) widget->g.w = window->g.w - (widget->label ? widget->label->g.w : 0);
+        widget = eve_widget_next(widget);
     }
+    eve_form_update(form, widgets, spec_size);
 
-    return ret;
+    return form;
 }
 
 void eve_form_init(EVEForm *form, EVEWindow *window, EVEViewStack *stack, EVEWidget *widget, uint16_t widget_size, eve_form_action_t action, eve_form_destructor_t destructor) {
     memset(form, 0, sizeof(EVEForm));
-    eve_page_init(&form->p, window, stack, eve_form_draw, eve_form_touch, NULL, (eve_page_destructor_t)destructor);
-    eve_form_update(form, widget, widget_size, action);
+    eve_page_init(&form->p, window, stack, NULL, 0, EVE_PAGE_OPT_SCROLL_Y | EVE_PAGE_OPT_SCROLL_BACK | EVE_PAGE_OPT_TRACK_EXT_Y, eve_page_draw, eve_page_touch, eve_form_uievt, (eve_page_destructor_t)destructor);
+    form->action = action;
+    eve_form_update(form, widget, widget_size);
 }
 
-void eve_form_update(EVEForm *form, EVEWidget *widget, uint16_t widget_size, eve_form_action_t action) {
-    if (widget) {
-        form->widget = widget;
-        form->widget_size = widget_size;
-    }
-    if (action) form->action = action;
+void eve_form_update(EVEForm *form, EVEWidget *widget, uint16_t widget_size) {
+    eve_page_update((EVEPage *)form, widget, widget_size);
     form_update_g(form, NULL);
 }
 
-uint8_t eve_form_draw(EVEView *view, uint8_t tag0) {
-    EVEForm *form = (EVEForm *)view;
-    EVEWidget *widget = form->widget;
-    int i;
-    uint8_t tagN = tag0;
-    uint8_t tag_opt = EVE_TOUCH_OPT_TRACK | EVE_TOUCH_OPT_TRACK_XY | EVE_TOUCH_OPT_TRACK_EXT_Y;
-
-    tagN = eve_view_clear(view, tagN);
-
-    eve_cmd_dl(SAVE_CONTEXT());
-    eve_cmd_dl(VERTEX_FORMAT(0));
-    eve_cmd_dl(VERTEX_TRANSLATE_X(eve_page_scr_x(&form->p, 0) * 16));
-    eve_cmd_dl(VERTEX_TRANSLATE_Y(eve_page_scr_y(&form->p, 0) * 16));
-    for (i=0; i<form->widget_size; i++) {
-        if (widget->label && eve_page_rect_visible(&form->p, &widget->label->g)) {
-            eve_cmd_dl(TAG_MASK(0));
-            eve_label_draw(widget->label);
-            eve_cmd_dl(TAG_MASK(1));
-        }
-        if (eve_page_rect_visible(&form->p, &widget->g)) {
-            uint16_t h = widget->g.h;
-            tagN = widget->draw(widget, tagN);
-            if (h != widget->g.h) form_update_g(form, widget);
-        }
-        widget = eve_widget_next(widget);
-    }
+void eve_form_destroy(EVEForm *form) {
+    widgets_destroy(form->p.widget, form->p.widget_size);
+    eve_free(form->p.widget);
+    eve_free(form);
+}
 
-    eve_cmd_dl(RESTORE_CONTEXT());
+int eve_form_uievt(EVEView *view, uint16_t evt, void *param) {
+    EVEForm *form = (EVEForm *)view;
 
-    for (i=tag0; i<tagN; i++) {
-        eve_touch_set_opt(i, eve_touch_get_opt(i) | tag_opt);
-    }
-    if (view->tag != EVE_TAG_NOTAG) eve_touch_set_opt(view->tag, eve_touch_get_opt(view->tag) | tag_opt);
+    switch (evt) {
+        case EVE_UIEVT_WIDGET_UPDATE_G:
+            form_update_g(form, (EVEWidget *)param);
+            break;
 
-    return tagN;
-}
+        case EVE_UIEVT_PAGE_SCROLL_START:
+            break;
 
-int eve_form_touch(EVEView *view, EVETouch *touch, uint16_t evt, uint8_t tag0) {
-    EVEForm *form = (EVEForm *)view;
-    EVEWidget *widget = form->widget;
-    int8_t touch_idx = eve_touch_get_idx(touch);
-    uint16_t _evt;
-    int i, ret;
+        case EVE_UIEVT_PAGE_SCROLL_STOP:
+            break;
 
-    if (touch_idx > 0) return 0;
+        case EVE_UIEVT_PAGE_TRACK_START:
+            break;
 
-    _evt = eve_touch_evt(touch, evt, tag0, form->p.v.tag, 1);
-    if (_evt) {
-        ret = form_handle_evt(form, NULL, touch, _evt, tag0);
-        if (ret) return 1;
-    }
-    for (i=0; i<form->widget_size; i++) {
-        _evt = eve_touch_evt(touch, evt, tag0, widget->tag0, widget->tagN - widget->tag0);
-        if (_evt) {
-            if (!form->evt_lock) {
-                ret = widget->touch(widget, touch, _evt);
-                if (ret) return 1;
+        case EVE_UIEVT_PAGE_TRACK_STOP: {
+            EVEUIEvtTouch *touch_p = (EVEUIEvtTouch *)param;
+            if (touch_p->evt & EVE_TOUCH_ETYPE_TRACK_STOP) {
+                if (touch_p->touch->eevt & EVE_TOUCH_EETYPE_TRACK_RIGHT) {
+                    eve_page_close((EVEPage *)form);
+                    return 1;
+                }
+                if (touch_p->touch->eevt & EVE_TOUCH_EETYPE_TRACK_LEFT) {
+                    if (form->action) form->action(form);
+                }
             }
-            ret = form_handle_evt(form, widget, touch, _evt, tag0);
-            if (ret) return 1;
+            break;
         }
-        widget = eve_widget_next(widget);
     }
-
     return 0;
 }
-
-EVEWidget *eve_form_widget(EVEForm *form, uint16_t idx) {
-    EVEWidget *w = form->widget;
-    int i;
-
-    if (idx >= form->widget_size) return NULL;
-
-    for (i=0; i<idx; i++) {
-        w = eve_widget_next(w);
-    }
-    return w;
-}
diff --git a/fw/fe310/eos/eve/screen/form.h b/fw/fe310/eos/eve/screen/form.h
index eb817e5..87da85c 100644
--- a/fw/fe310/eos/eve/screen/form.h
+++ b/fw/fe310/eos/eve/screen/form.h
@@ -1,6 +1,9 @@
 #include <stdint.h>
 
+#define EVE_FORM_LABEL_MARGIN   10
+
 struct EVEWidget;
+struct EVEWidgetSpec;
 struct EVEForm;
 
 typedef void (*eve_form_action_t) (struct EVEForm *);
@@ -8,24 +11,12 @@ typedef void (*eve_form_destructor_t) (struct EVEForm *);
 
 typedef struct EVEForm {
     EVEPage p;
-    struct EVEWidget *widget;
-    uint16_t widget_size;
     eve_form_action_t action;
-    int win_x0;
-    int win_y0;
-    uint16_t w;
-    uint16_t h;
-    uint8_t evt_lock;
-    EVEPhyLHO lho;
-    uint64_t lho_t0;
 } EVEForm;
 
+EVEForm *eve_form_create(EVEWindow *window, EVEViewStack *stack, struct EVEWidgetSpec *spec, uint16_t spec_size, eve_form_action_t action, eve_form_destructor_t destructor);
 void eve_form_init(EVEForm *form, EVEWindow *window, EVEViewStack *stack, struct EVEWidget *widget, uint16_t widget_size, eve_form_action_t action, eve_form_destructor_t destructor);
-void eve_form_update(EVEForm *form, struct EVEWidget *widget, uint16_t widget_size, eve_form_action_t action);
-
-uint8_t eve_form_draw(EVEView *view, uint8_t tag0);
-int eve_form_touch(EVEView *view, EVETouch *touch, uint16_t evt, uint8_t tag0);
+void eve_form_update(EVEForm *form, struct EVEWidget *widget, uint16_t widget_size);
+void eve_form_destroy(EVEForm *form);
 
-void eve_form_update_g(EVEForm *form, struct EVEWidget *widget);
-int eve_form_handle_evt(EVEForm *form, struct EVEWidget *widget, EVETouch *touch, uint16_t evt);
-struct EVEWidget *eve_form_widget(EVEForm *form, uint16_t idx);
+int eve_form_uievt(EVEView *view, uint16_t evt, void *param);
diff --git a/fw/fe310/eos/eve/screen/page.c b/fw/fe310/eos/eve/screen/page.c
index 4b8799c..032d746 100644
--- a/fw/fe310/eos/eve/screen/page.c
+++ b/fw/fe310/eos/eve/screen/page.c
@@ -11,12 +11,24 @@
 #include "widget/label.h"
 #include "widget/widget.h"
 
-void eve_page_init(EVEPage *page, EVEWindow *window, EVEViewStack *stack, eve_view_draw_t draw, eve_view_touch_t touch, eve_view_uievt_t uievt, eve_page_destructor_t destructor) {
+#define PAGE_TMODE_NONE     0
+#define PAGE_TMODE_TRACK    1
+#define PAGE_TMODE_SCROLL   2
+
+void eve_page_init(EVEPage *page, EVEWindow *window, EVEViewStack *stack, EVEWidget *widget, uint16_t widget_size, uint8_t opt, eve_view_draw_t draw, eve_view_touch_t touch, eve_view_uievt_t uievt, eve_page_destructor_t destructor) {
     memset(page, 0, sizeof(EVEPage));
     eve_view_init(&page->v, window, draw, touch, uievt, NULL);
-    page->destructor = destructor;
     page->stack = stack;
-    page->widget_f = NULL;
+    page->opt = opt;
+    page->destructor = destructor;
+    eve_page_update(page, widget, widget_size);
+}
+
+void eve_page_update(EVEPage *page, EVEWidget *widget, uint16_t widget_size) {
+    if (widget) {
+        page->widget = widget;
+        page->widget_size = widget_size;
+    }
 }
 
 void eve_page_open(EVEPage *parent, eve_view_constructor_t constructor) {
@@ -33,6 +45,13 @@ void eve_page_close(EVEPage *page) {
     EVEViewStack *stack = page->stack;
     eve_page_destructor_t destructor = page->destructor;
 
+    if (page->lho_t0) {
+        page->lho_t0 = 0;
+        eve_touch_timer_stop();
+    }
+    if (eve_window_scroll(window->root, NULL) == window) {
+        eve_window_scroll_stop(window);
+    }
     if (stack->level > 1) {
         if (destructor) destructor(page);
         eve_window_kbd_detach(window);
@@ -40,77 +59,289 @@ void eve_page_close(EVEPage *page) {
     }
 }
 
+/* Screen to page coordinates */
 int16_t eve_page_x(EVEPage *page, int16_t x) {
-    return x + page->win_x - page->v.window->g.x;
+    return x + page->g.x - page->v.window->g.x;
 }
 
 int16_t eve_page_y(EVEPage *page, int16_t y) {
-    return y + page->win_y - page->v.window->g.y;
+    return y + page->g.y - page->v.window->g.y;
+}
+
+/* Page to window coordinates */
+int16_t eve_page_win_x(EVEPage *page, int16_t x) {
+    return x - page->g.x;
+}
+
+int16_t eve_page_win_y(EVEPage *page, int16_t y) {
+    return y - page->g.y;
 }
 
+/* Page to screen coordinates */
 int16_t eve_page_scr_x(EVEPage *page, int16_t x) {
-    return x - page->win_x + page->v.window->g.x;
+    return eve_page_win_x(page, x) + page->v.window->g.x;
 }
 
 int16_t eve_page_scr_y(EVEPage *page, int16_t y) {
-    return y - page->win_y + page->v.window->g.y;
+    return eve_page_win_y(page, y) + page->v.window->g.y;
+}
+
+int eve_page_rect_visible(EVEPage *page, EVERect *g) {
+    uint16_t w = page->v.window->g.w;
+    uint16_t h = page->v.window->g.h;
+
+    if (((g->x + g->w) >= page->g.x) && ((g->y + g->h) >= page->g.y) && (g->x <= (page->g.x + w)) && (g->y <= (page->g.y + h))) return 1;
+    return 0;
+}
+
+void eve_page_focus(EVEPage *page, EVERect *rect) {
+    if (rect) {
+        EVERect g;
+
+        eve_window_visible_g(page->v.window, &g);
+        g.x -= page->v.window->g.x;
+        g.y -= page->v.window->g.y;
+
+        if (rect->x < page->g.x + g.x) {
+            page->g.x = rect->x - g.x;
+        }
+        if (rect->y < page->g.y + g.y) {
+            page->g.y = rect->y - g.y;
+        }
+        if ((rect->x + rect->w) > (page->g.x + g.x + g.w)) {
+            page->g.x = (rect->x + rect->w) - (g.x + g.w);
+        }
+        if ((rect->y + rect->h) > (page->g.y + g.y + g.h)) {
+            page->g.y = (rect->y + rect->h) - (g.y + g.h);
+        }
+    }
 }
 
-void eve_page_set_focus(EVEPage *page, EVEWidget *widget, EVERect *f) {
+void eve_page_focus_widget(EVEPage *page, EVEWidget *widget, EVERect *rect) {
     if (page->widget_f != widget) {
         EVEWindow *window = page->v.window;
         EVEWidget *widget_f = page->widget_f;
 
         if (widget_f && widget_f->putc) {
-            eve_window_kbd_detach(window);
             widget_f->putc(widget_f, EVE_PAGE_KBDCH_CLOSE);
+            if (!(widget && widget->putc)) eve_window_kbd_detach(window);
         }
         if (widget && widget->putc) {
             EVEKbd *kbd = eve_window_kbd(window);
 
-            if (kbd) {
-                eve_kbd_set_handler(kbd, widget->putc, widget);
-                eve_window_kbd_attach(window);
-            }
+            if (kbd) eve_kbd_set_handler(kbd, widget->putc, widget);
+            if (!(widget_f && widget_f->putc)) eve_window_kbd_attach(window);
         }
         page->widget_f = widget;
     }
+    if (rect) eve_page_focus(page, rect);
+}
 
-    if (f) {
-        EVERect g;
+EVEWidget *eve_page_focus_widget_get(EVEPage *page) {
+    return page->widget_f;
+}
 
-        eve_window_visible_g(page->v.window, &g);
-        g.x -= page->v.window->g.x;
-        g.y -= page->v.window->g.y;
+EVEWidget *eve_page_widget(EVEPage *page, uint16_t idx) {
+    EVEWidget *w = page->widget;
+    int i;
+
+    if (idx >= page->widget_size) return NULL;
+
+    for (i=0; i<idx; i++) {
+        w = eve_widget_next(w);
+    }
+    return w;
+}
+
+static int page_touch(EVEPage *page, EVETouch *touch, uint16_t evt, uint8_t tag0) {
+    EVEView *view = &page->v;
+    EVEWindow *window = view->window;
+    int scroll, scroll_x, scroll_y;
+    int ret = 0;
+
+    scroll_x = page->opt & (EVE_PAGE_OPT_SCROLL_X | EVE_PAGE_OPT_SCROLL_XY);
+    if (scroll_x && touch) scroll_x = touch->eevt & ((page->opt & EVE_PAGE_OPT_SCROLL_XY) ? EVE_TOUCH_EETYPE_TRACK_XY : EVE_TOUCH_EETYPE_TRACK_X);
+
+    scroll_y = page->opt & (EVE_PAGE_OPT_SCROLL_Y | EVE_PAGE_OPT_SCROLL_XY);
+    if (scroll_y && touch) scroll_y = touch->eevt & ((page->opt & EVE_PAGE_OPT_SCROLL_XY) ? EVE_TOUCH_EETYPE_TRACK_XY : EVE_TOUCH_EETYPE_TRACK_Y);
 
-        if (f->x < page->win_x + g.x) {
-            page->win_x = f->x - g.x;
+    scroll = scroll_x || scroll_y;
+
+    if ((evt & EVE_TOUCH_ETYPE_POINT_UP) && !(touch->eevt & (EVE_TOUCH_EETYPE_TRACK_XY | EVE_TOUCH_EETYPE_ABORT))) {
+        if (page->widget_f) eve_page_focus_widget(page, NULL, NULL);
+        ret = 1;
+    }
+
+    /* Scroll start */
+    if ((evt & EVE_TOUCH_ETYPE_TRACK_START) && !(touch->eevt & EVE_TOUCH_EETYPE_ABORT)) {
+        int _ret = 0;
+
+        if (scroll) {
+            page->track_mode = PAGE_TMODE_SCROLL;
+            eve_window_scroll_start(window, touch->tracker.tag);
+            _ret = eve_view_uievt_tpush(view, EVE_UIEVT_PAGE_SCROLL_START, touch, evt, tag0);
+        } else {
+            page->track_mode = PAGE_TMODE_TRACK;
+            _ret = eve_view_uievt_tpush(view, EVE_UIEVT_PAGE_TRACK_START, touch, evt, tag0);
+        }
+        if (_ret) return _ret;
+        ret = 1;
+    }
+
+    /* Scroll stop */
+    if (((evt & EVE_TOUCH_ETYPE_TRACK_STOP) && !(evt & EVE_TOUCH_ETYPE_TRACK_ABORT)) ||
+        ((evt & EVE_TOUCH_ETYPE_POINT_UP) && (touch->eevt & EVE_TOUCH_EETYPE_ABORT) && !(touch->eevt & EVE_TOUCH_EETYPE_TRACK_XY))) {
+        if ((page->track_mode == PAGE_TMODE_SCROLL) && (page->opt & EVE_PAGE_OPT_SCROLL_BACK)) {
+            int wmax_x, wmax_y;
+            int lho_x, lho_y;
+            EVERect vg;
+
+            eve_window_visible_g(page->v.window, &vg);
+            wmax_x = page->g.w > vg.w ? page->g.w - vg.w : 0;
+            wmax_y = page->g.h > vg.h ? page->g.h - vg.h : 0;
+            lho_x = page->g.x < 0 ? 0 : wmax_x;
+            lho_y = page->g.y < 0 ? 0 : wmax_y;
+            if ((page->g.x < 0) || (page->g.x > wmax_x) ||
+                (page->g.y < 0) || (page->g.y > wmax_y)) {
+                EVEPhyLHO *lho = &page->lho;
+                uint8_t _tag;
+
+                eve_window_scroll(window->root, &_tag);
+
+                eve_phy_lho_init(lho, lho_x, lho_y, 1000, 0.5, 0);
+                eve_phy_lho_start(lho, page->g.x, page->g.y);
+                page->lho_t0 = eve_time_get_tick();
+                eve_touch_timer_start(_tag, 20);
+            }
+        }
+
+        if (!page->lho_t0) {
+            int _ret = 0;
+
+            if (page->track_mode == PAGE_TMODE_SCROLL) {
+                page->track_mode = PAGE_TMODE_NONE;
+                eve_window_scroll_stop(window);
+                _ret = eve_view_uievt_tpush(view, EVE_UIEVT_PAGE_SCROLL_STOP, touch, evt, tag0);
+            } else if (!(touch->eevt & EVE_TOUCH_EETYPE_ABORT)) {
+                page->track_mode = PAGE_TMODE_NONE;
+                _ret = eve_view_uievt_tpush(view, EVE_UIEVT_PAGE_TRACK_STOP, touch, evt, tag0);
+            }
+            if (_ret) return _ret;
+            ret = 1;
+        }
+    }
+
+    if (page->track_mode == PAGE_TMODE_SCROLL) {
+        if (evt & EVE_TOUCH_ETYPE_TRACK_START) {
+            if (scroll_x) {
+                page->x0 = page->g.x;
+            }
+            if (scroll_y) {
+                page->y0 = page->g.y;
+            }
         }
-        if (f->y < page->win_y + g.y) {
-            page->win_y = f->y - g.y;
+        if (evt & EVE_TOUCH_ETYPE_TRACK) {
+            if (scroll_x) {
+                page->g.x = page->x0 + touch->x0 - touch->x;
+            }
+            if (scroll_y) {
+                page->g.y = page->y0 + touch->y0 - touch->y;
+            }
+            ret = 1;
         }
-        if ((f->x + f->w) > (page->win_x + g.x + g.w)) {
-            page->win_x = (f->x + f->w) - (g.x + g.w);
+        if ((evt & EVE_TOUCH_ETYPE_TIMER) && (page->opt & EVE_PAGE_OPT_SCROLL_BACK)) {
+            EVEPhyLHO *lho = &page->lho;
+            int x, y, more;
+
+            more = eve_phy_lho_tick(lho, eve_time_get_tick() - page->lho_t0, scroll_x ? &x : NULL, scroll_y ? &y : NULL);
+            if (scroll_x) page->g.x = x;
+            if (scroll_y) page->g.y = y;
+            if (!more) {
+                int _ret = 0;
+
+                page->lho_t0 = 0;
+                eve_touch_timer_stop();
+                page->track_mode = PAGE_TMODE_NONE;
+                eve_window_scroll_stop(window);
+                _ret = eve_view_uievt_tpush(view, EVE_UIEVT_PAGE_SCROLL_STOP, touch, evt, tag0);
+                if (_ret) return _ret;
+            }
+            ret = 1;
         }
-        if ((f->y + f->h) > (page->win_y + g.y + g.h)) {
-            page->win_y = (f->y + f->h) - (g.y + g.h);
+        if (evt & EVE_TOUCH_EETYPE_TIMER_ABORT) {
+            page->lho_t0 = 0;
         }
     }
-}
 
-EVEWidget *eve_page_get_focus(EVEPage *page) {
-    return page->widget_f;
+    return ret;
 }
 
-int eve_page_rect_visible(EVEPage *page, EVERect *g) {
-    uint16_t w = page->v.window->g.w;
-    uint16_t h = page->v.window->g.h;
+uint8_t eve_page_draw(EVEView *view, uint8_t tag0) {
+    EVEPage *page = (EVEPage *)view;
+    EVEWidget *widget = page->widget;
+    int i;
+    uint8_t tagN = tag0;
+    uint8_t tag_opt;
 
-    if (((g->x + g->w) >= page->win_x) && ((g->y + g->h) >= page->win_y) && (g->x <= (page->win_x + w)) && (g->y <= (page->win_y + h))) return 1;
-    return 0;
+    tag_opt = EVE_TOUCH_OPT_TRACK | EVE_TOUCH_OPT_TRACK_XY;
+    if (page->opt & EVE_PAGE_OPT_TRACK_EXT_X) tag_opt |= EVE_TOUCH_OPT_TRACK_EXT_X;
+    if (page->opt & EVE_PAGE_OPT_TRACK_EXT_Y) tag_opt |= EVE_TOUCH_OPT_TRACK_EXT_Y;
+
+    tag0 = eve_view_clear(view, tag0, tag_opt);
+    tagN = tag0;
+    eve_cmd_dl(SAVE_CONTEXT());
+    eve_cmd_dl(VERTEX_FORMAT(0));
+    eve_cmd_dl(VERTEX_TRANSLATE_X(eve_page_scr_x(page, 0) * 16));
+    eve_cmd_dl(VERTEX_TRANSLATE_Y(eve_page_scr_y(page, 0) * 16));
+    for (i=0; i<page->widget_size; i++) {
+        if (widget->label && eve_page_rect_visible(page, &widget->label->g)) {
+            eve_cmd_dl(TAG_MASK(0));
+            eve_label_draw(widget->label);
+            eve_cmd_dl(TAG_MASK(1));
+        }
+        if (eve_page_rect_visible(page, &widget->g)) {
+            tagN = widget->draw(widget, tagN);
+        }
+        widget = eve_widget_next(widget);
+    }
+
+    eve_cmd_dl(RESTORE_CONTEXT());
+
+    for (i=tag0; i<tagN; i++) {
+        if (i != EVE_NOTAG) eve_touch_set_opt(i, eve_touch_get_opt(i) | tag_opt);
+    }
+
+    return tagN;
 }
 
-void eve_page_uievt_push(EVEPage *page, uint16_t evt, void *param) {
-    EVEView *view = &page->v;
-    eve_view_uievt_push(view, evt, param ? param : page);
+int eve_page_touch(EVEView *view, EVETouch *touch, uint16_t evt, uint8_t tag0) {
+    EVEPage *page = (EVEPage *)view;
+    EVEWidget *widget = page->widget;
+    int8_t touch_idx = eve_touch_get_idx(touch);
+    uint16_t _evt;
+    int i, ret;
+
+    if (touch_idx > 0) return 0;
+
+    _evt = eve_touch_evt(touch, evt, tag0, page->v.tag, 1);
+    if (_evt) {
+        ret = page_touch(page, touch, _evt, tag0);
+        if (ret) return 1;
+    }
+    for (i=0; i<page->widget_size; i++) {
+        if (eve_page_rect_visible(page, &widget->g)) {
+            _evt = eve_touch_evt(touch, evt, tag0, widget->tag0, widget->tagN - widget->tag0);
+            if (_evt) {
+                if (page->track_mode == PAGE_TMODE_NONE) {
+                    ret = widget->touch(widget, touch, _evt);
+                    if (ret) return 1;
+                }
+                ret = page_touch(page, touch, _evt, tag0);
+                if (ret) return 1;
+            }
+        }
+        widget = eve_widget_next(widget);
+    }
+
+    return 0;
 }
diff --git a/fw/fe310/eos/eve/screen/page.h b/fw/fe310/eos/eve/screen/page.h
index ded7185..26c33c5 100644
--- a/fw/fe310/eos/eve/screen/page.h
+++ b/fw/fe310/eos/eve/screen/page.h
@@ -1,6 +1,14 @@
 #include <stdint.h>
 
-#define EVE_PAGE_KBDCH_CLOSE    0x1a
+#define EVE_PAGE_KBDCH_CLOSE        0x1a
+
+#define EVE_PAGE_OPT_SCROLL_X       0x01
+#define EVE_PAGE_OPT_SCROLL_Y       0x02
+#define EVE_PAGE_OPT_SCROLL_BACK    0x04
+#define EVE_PAGE_OPT_SCROLL_XY      0x08
+#define EVE_PAGE_OPT_TRACK_EXT_X    0x10
+#define EVE_PAGE_OPT_TRACK_EXT_Y    0x20
+#define EVE_PAGE_OPT_TRACK_EXT_XY  (EVE_PAGE_OPT_TRACK_EXT_X | EVE_PAGE_OPT_TRACK_EXT_Y)
 
 struct EVEWidget;
 struct EVEPage;
@@ -9,24 +17,40 @@ typedef void (*eve_page_destructor_t) (struct EVEPage *);
 
 typedef struct EVEPage {
     EVEView v;
-    int win_x;
-    int win_y;
-    eve_page_destructor_t destructor;
+    EVERect g;
+    int16_t x0;
+    int16_t y0;
     EVEViewStack *stack;
+    eve_page_destructor_t destructor;
+    struct EVEWidget *widget;
+    uint16_t widget_size;
     struct EVEWidget *widget_f;
+    EVEPhyLHO lho;
+    uint64_t lho_t0;
+    uint8_t track_mode;
+    uint8_t opt;
 } EVEPage;
 
-void eve_page_init(EVEPage *page, EVEWindow *window, EVEViewStack *stack, eve_view_draw_t draw, eve_view_touch_t touch, eve_view_uievt_t uievt, eve_page_destructor_t destructor);
+void eve_page_init(EVEPage *page, EVEWindow *window, EVEViewStack *stack, struct EVEWidget *widget, uint16_t widget_size, uint8_t opt,eve_view_draw_t draw, eve_view_touch_t touch, eve_view_uievt_t uievt, eve_page_destructor_t destructor);
+void eve_page_update(EVEPage *page, struct EVEWidget *widget, uint16_t widget_size);
 void eve_page_open(EVEPage *parent, eve_view_constructor_t constructor);
 void eve_page_close(EVEPage *page);
 
+/* Screen to page coordinates */
 int16_t eve_page_x(EVEPage *page, int16_t x);
 int16_t eve_page_y(EVEPage *page, int16_t y);
+/* Page to window coordinates */
+int16_t eve_page_win_x(EVEPage *page, int16_t x);
+int16_t eve_page_win_y(EVEPage *page, int16_t y);
+/* Page to screen coordinates */
 int16_t eve_page_scr_x(EVEPage *page, int16_t x);
 int16_t eve_page_scr_y(EVEPage *page, int16_t y);
-
-void eve_page_set_focus(EVEPage *page, struct EVEWidget *widget, EVERect *focus);
-struct EVEWidget *eve_page_get_focus(EVEPage *page);
 int eve_page_rect_visible(EVEPage *page, EVERect *g);
 
-void eve_page_uievt_push(EVEPage *page, uint16_t evt, void *param);
\ No newline at end of file
+void eve_page_focus(EVEPage *page, EVERect *rect);
+void eve_page_focus_widget(EVEPage *page, struct EVEWidget *widget, EVERect *rect);
+struct EVEWidget *eve_page_focus_widget_get(EVEPage *page);
+struct EVEWidget *eve_page_widget(EVEPage *page, uint16_t idx);
+
+uint8_t eve_page_draw(EVEView *view, uint8_t tag0);
+int eve_page_touch(EVEView *view, EVETouch *touch, uint16_t evt, uint8_t tag0);
diff --git a/fw/fe310/eos/eve/screen/uievt.h b/fw/fe310/eos/eve/screen/uievt.h
index a2657d7..0a751ae 100644
--- a/fw/fe310/eos/eve/screen/uievt.h
+++ b/fw/fe310/eos/eve/screen/uievt.h
@@ -2,4 +2,12 @@
 #define EVE_UIEVT_PAGE_UPDATE_G         2
 #define EVE_UIEVT_PAGE_SCROLL_START     3
 #define EVE_UIEVT_PAGE_SCROLL_STOP      4
-#define EVE_UIEVT_WIDGET_UPDATE_G       5
+#define EVE_UIEVT_PAGE_TRACK_START      5
+#define EVE_UIEVT_PAGE_TRACK_STOP       6
+#define EVE_UIEVT_WIDGET_UPDATE_G       7
+
+typedef struct EVEUIEvtTouch {
+    EVETouch *touch;
+    uint16_t evt;
+    uint8_t tag0;
+} EVEUIEvtTouch;
diff --git a/fw/fe310/eos/eve/screen/view.c b/fw/fe310/eos/eve/screen/view.c
index 3f93c2f..10a3ac1 100644
--- a/fw/fe310/eos/eve/screen/view.c
+++ b/fw/fe310/eos/eve/screen/view.c
@@ -26,13 +26,30 @@ void eve_view_set_color_fg(EVEView *view, uint8_t r, uint8_t g, uint8_t b) {
     view->color_fg = (r << 16) | (g << 8) | b;
 }
 
-uint8_t eve_view_clear(EVEView *view, uint8_t tag0) {
+uint8_t eve_view_clear(EVEView *view, uint8_t tag0, uint8_t tag_opt) {
+    EVEWindow *win_scroll = NULL;
+    EVEWindow *window = view->window;
+    uint8_t _tag;
+
+    win_scroll = eve_window_scroll(window->root, &_tag);
     eve_cmd_dl(CLEAR_COLOR_RGBC(view->color_bg));
     eve_cmd_dl(COLOR_RGBC(view->color_fg));
-    view->tag = tag0;
-    if (tag0 != EVE_TAG_NOTAG) {
-        eve_cmd_dl(CLEAR_TAG(tag0));
-        tag0++;
+    if (win_scroll == window) {
+        view->tag = _tag;
+        eve_touch_set_opt(view->tag, tag_opt);
+        eve_cmd_dl(TAG(view->tag));
+        eve_cmd_dl(CLEAR_TAG(view->tag));
+    } else if (win_scroll) {
+        view->tag = EVE_NOTAG;
+        eve_cmd_dl(TAG(view->tag));
+        eve_cmd_dl(CLEAR_TAG(view->tag));
+    } else {
+        view->tag = tag0;
+        if (tag0 != EVE_NOTAG) {
+            eve_touch_set_opt(tag0, tag_opt);
+            eve_cmd_dl(CLEAR_TAG(tag0));
+            tag0++;
+        }
     }
     eve_cmd_dl(CLEAR(1,1,1));
     return tag0;
@@ -62,4 +79,16 @@ void eve_view_destroy(EVEWindow *window, EVEViewStack *stack) {
 
 void eve_view_uievt_push(EVEView *view, uint16_t evt, void *param) {
     if (view->uievt) view->uievt(view, evt, param);
-}
\ No newline at end of file
+}
+
+int eve_view_uievt_tpush(EVEView *view, uint16_t evt, EVETouch *touch, uint16_t t_evt, uint8_t tag0) {
+    if (view->uievt) {
+        EVEUIEvtTouch param;
+
+        param.touch = touch;
+        param.evt = t_evt;
+        param.tag0 = tag0;
+        view->uievt(view, evt, &param);
+    }
+    return 0;
+}
diff --git a/fw/fe310/eos/eve/screen/view.h b/fw/fe310/eos/eve/screen/view.h
index 527282b..4f93627 100644
--- a/fw/fe310/eos/eve/screen/view.h
+++ b/fw/fe310/eos/eve/screen/view.h
@@ -10,7 +10,7 @@ struct EVEWindow;
 
 typedef uint8_t (*eve_view_draw_t) (struct EVEView *, uint8_t);
 typedef int (*eve_view_touch_t) (struct EVEView *, EVETouch *, uint16_t, uint8_t);
-typedef void (*eve_view_uievt_t) (struct EVEView *, uint16_t, void *);
+typedef int (*eve_view_uievt_t) (struct EVEView *, uint16_t, void *);
 typedef void (*eve_view_constructor_t) (struct EVEWindow *window, struct EVEViewStack *);
 
 typedef struct EVEView {
@@ -32,10 +32,11 @@ typedef struct EVEViewStack {
 void eve_view_init(EVEView *view, struct EVEWindow *window, eve_view_draw_t draw, eve_view_touch_t touch, eve_view_uievt_t uievt, void *param);
 void eve_view_set_color_bg(EVEView *view, uint8_t r, uint8_t g, uint8_t b);
 void eve_view_set_color_fg(EVEView *view, uint8_t r, uint8_t g, uint8_t b);
-uint8_t eve_view_clear(EVEView *view, uint8_t tag0);
+uint8_t eve_view_clear(EVEView *view, uint8_t tag0, uint8_t tag_opt);
 
 void eve_view_stack_init(EVEViewStack *stack);
 void eve_view_create(struct EVEWindow *window, EVEViewStack *stack, eve_view_constructor_t constructor);
 void eve_view_destroy(struct EVEWindow *window, EVEViewStack *stack);
 
-void eve_view_uievt_push(EVEView *view, uint16_t evt, void *param);
\ No newline at end of file
+void eve_view_uievt_push(EVEView *view, uint16_t evt, void *param);
+int eve_view_uievt_tpush(EVEView *view, uint16_t evt, EVETouch *touch, uint16_t t_evt, uint8_t tag0);
diff --git a/fw/fe310/eos/eve/screen/window.c b/fw/fe310/eos/eve/screen/window.c
index 2971ab5..4f059c4 100644
--- a/fw/fe310/eos/eve/screen/window.c
+++ b/fw/fe310/eos/eve/screen/window.c
@@ -18,21 +18,22 @@ void eve_window_init(EVEWindow *window, EVERect *g, EVEWindow *parent, char *nam
     window->name = name;
 }
 
-void eve_window_init_root(EVEWindowRoot *window, EVERect *g, char *name, EVEFont *font) {
-    EVEWindow *_window = &window->w;
+void eve_window_init_root(EVEWindowRoot *root, EVERect *g, char *name, EVEFont *font) {
+    EVEWindow *_window = &root->w;
 
     eve_window_init(_window, g, NULL, name);
-    _window->root = _window;
-    window->mem_next = EVE_RAM_G;
-    window->font = font;
-    window->win_kbd = NULL;
-    eve_touch_set_handler(eve_window_root_touch, window);
+    _window->root = root;
+    root->mem_next = EVE_RAM_G;
+    root->font = font;
+    root->win_kbd = NULL;
+    root->tag0 = EVE_NOTAG;
+    eve_touch_set_handler(eve_window_root_touch, root);
 }
 
 static uint8_t kbd_draw(EVEView *view, uint8_t tag0) {
     EVEKbd *kbd = view->param;
 
-    tag0 = eve_view_clear(view, tag0);
+    tag0 = eve_view_clear(view, tag0, 0);
 
     eve_kbd_draw(kbd);
     return tag0;
@@ -44,14 +45,14 @@ static int kbd_touch(EVEView *view, EVETouch *touch, uint16_t evt, uint8_t tag0)
     return eve_kbd_touch(kbd, touch, evt, tag0);
 }
 
-void eve_window_init_kbd(EVEWindowKbd *window, EVERect *g, EVEWindowRoot *root, char *name, EVEKbd *kbd) {
-    EVEWindow *_window = &window->w;
+void eve_window_init_kbd(EVEWindowKbd *win_kbd, EVERect *g, EVEWindowRoot *root, char *name, EVEKbd *kbd) {
+    EVEWindow *_window = &win_kbd->w;
 
     eve_window_init(_window, g, NULL, name);
-    _window->root = (EVEWindow *)root;
-    window->kbd = kbd;
-    root->win_kbd = window;
-    eve_view_init(&window->v, _window, kbd_draw, kbd_touch, NULL, kbd);
+    _window->root = root;
+    win_kbd->kbd = kbd;
+    root->win_kbd = win_kbd;
+    eve_view_init(&win_kbd->v, _window, kbd_draw, kbd_touch, NULL, kbd);
 }
 
 void eve_window_set_parent(EVEWindow *window, EVEWindow *parent) {
@@ -60,8 +61,8 @@ void eve_window_set_parent(EVEWindow *window, EVEWindow *parent) {
 }
 
 int eve_window_visible(EVEWindow *window) {
-    if (window->g.x >= window->root->g.w) return 0;
-    if (window->g.y >= window->root->g.h) return 0;
+    if (window->g.x >= window->root->w.g.w) return 0;
+    if (window->g.y >= window->root->w.g.h) return 0;
     if ((window->g.x + window->g.w) <= 0) return 0;
     if ((window->g.y + window->g.h) <= 0) return 0;
     return 1;
@@ -182,8 +183,8 @@ uint8_t eve_window_draw(EVEWindow *window, uint8_t tag0) {
                 s_h += s_y;
                 s_y = 0;
             }
-            if (s_x + s_w > window->root->g.w) s_w = window->root->g.w - s_x;
-            if (s_y + s_h > window->root->g.h) s_h = window->root->g.h - s_y;
+            if (s_x + s_w > window->root->w.g.w) s_w = window->root->w.g.w - s_x;
+            if (s_y + s_h > window->root->w.g.h) s_h = window->root->w.g.h - s_y;
             eve_cmd_dl(SCISSOR_XY(s_x, s_y));
             eve_cmd_dl(SCISSOR_SIZE(s_w, s_h));
             tag0 = window->view->draw(window->view, tag0);
@@ -213,13 +214,14 @@ int eve_window_touch(EVEWindow *window, EVETouch *touch, uint16_t evt, uint8_t t
     return 0;
 }
 
-void eve_window_root_draw(EVEWindow *window) {
+void eve_window_root_draw(EVEWindowRoot *root) {
     uint8_t tag0 = 0x80;
 
     eve_cmd_burst_start();
 	eve_cmd_dl(CMD_DLSTART);
 
-    eve_window_draw(window, tag0);
+    if (root->tag0 != EVE_NOTAG) tag0 = EVE_NOTAG;
+    eve_window_draw(&root->w, tag0);
 
     eve_cmd_dl(DISPLAY());
 	eve_cmd_dl(CMD_SWAP);
@@ -228,26 +230,28 @@ void eve_window_root_draw(EVEWindow *window) {
 }
 
 void eve_window_root_touch(EVETouch *touch, uint16_t evt, uint8_t tag0, void *win) {
-    EVEWindow *window = (EVEWindow *)win;
-    int ret = eve_window_touch(window, touch, evt, tag0);
+    EVEWindowRoot *root = (EVEWindowRoot *)win;
+    int ret;
 
+    if (root->tag0 != EVE_NOTAG) tag0 = root->tag0;
+    ret = eve_window_touch(&root->w, touch, evt, tag0);
     if (ret) {
         eve_touch_clear_opt();
-        eve_window_root_draw(window);
+        eve_window_root_draw(root);
     }
 }
 
 EVEKbd *eve_window_kbd(EVEWindow *window) {
-    EVEWindowRoot *win_root = (EVEWindowRoot *)window->root;
-    EVEWindowKbd *win_kbd = win_root->win_kbd;
+    EVEWindowRoot *root = window->root;
+    EVEWindowKbd *win_kbd = root->win_kbd;
 
     if (win_kbd) return win_kbd->kbd;
     return NULL;
 }
 
 void eve_window_kbd_attach(EVEWindow *window) {
-    EVEWindowRoot *win_root = (EVEWindowRoot *)window->root;
-    EVEWindowKbd *win_kbd = win_root->win_kbd;
+    EVEWindowRoot *root = window->root;
+    EVEWindowKbd *win_kbd = root->win_kbd;
     EVEKbd *kbd = win_kbd ? win_kbd->kbd : NULL;
 
     if (kbd) {
@@ -257,8 +261,8 @@ void eve_window_kbd_attach(EVEWindow *window) {
 }
 
 void eve_window_kbd_detach(EVEWindow *window) {
-    EVEWindowRoot *win_root = (EVEWindowRoot *)window->root;
-    EVEWindowKbd *win_kbd = win_root->win_kbd;
+    EVEWindowRoot *root = window->root;
+    EVEWindowKbd *win_kbd = root->win_kbd;
     EVEKbd *kbd = win_kbd ? win_kbd->kbd : NULL;
 
     if (kbd && win_kbd->w.parent) {
@@ -268,7 +272,26 @@ void eve_window_kbd_detach(EVEWindow *window) {
 }
 
 EVEFont *eve_window_font(EVEWindow *window) {
-    EVEWindowRoot *win_root = (EVEWindowRoot *)window->root;
+    EVEWindowRoot *root = window->root;
 
-    return win_root->font;
+    return root->font;
+}
+
+EVEWindow *eve_window_scroll(EVEWindowRoot *root, uint8_t *tag) {
+    if (tag) *tag = root->tag0;
+    return root->win_scroll;
+}
+
+void eve_window_scroll_start(EVEWindow *window, uint8_t tag) {
+    EVEWindowRoot *root = window->root;
+
+    root->win_scroll = window;
+    root->tag0 = tag;
+}
+
+void eve_window_scroll_stop(EVEWindow *window) {
+    EVEWindowRoot *root = window->root;
+
+    root->win_scroll = NULL;
+    root->tag0 = EVE_NOTAG;
 }
diff --git a/fw/fe310/eos/eve/screen/window.h b/fw/fe310/eos/eve/screen/window.h
index 76ccee9..27465c4 100644
--- a/fw/fe310/eos/eve/screen/window.h
+++ b/fw/fe310/eos/eve/screen/window.h
@@ -2,11 +2,13 @@
 
 #include "view.h"
 
+struct EVEWindowRoot;
+
 typedef struct EVEWindow {
     EVERect g;
     char *name;
     EVEView *view;
-    struct EVEWindow *root;
+    struct EVEWindowRoot *root;
     struct EVEWindow *parent;
     struct EVEWindow *next;
     struct EVEWindow *prev;
@@ -25,11 +27,13 @@ typedef struct EVEWindowRoot {
     uint32_t mem_next;
     EVEFont *font;
     EVEWindowKbd *win_kbd;
+    EVEWindow *win_scroll;
+    uint8_t tag0;
 } EVEWindowRoot;
 
 void eve_window_init(EVEWindow *window, EVERect *g, EVEWindow *parent, char *name);
-void eve_window_init_root(EVEWindowRoot *window, EVERect *g, char *name, EVEFont *font);
-void eve_window_init_kbd(EVEWindowKbd *window, EVERect *g, EVEWindowRoot *root, char *name, EVEKbd *kbd);
+void eve_window_init_root(EVEWindowRoot *root, EVERect *g, char *name, EVEFont *font);
+void eve_window_init_kbd(EVEWindowKbd *win_kbd, EVERect *g, EVEWindowRoot *root, char *name, EVEKbd *kbd);
 void eve_window_set_parent(EVEWindow *window, EVEWindow *parent);
 
 int eve_window_visible(EVEWindow *window);
@@ -43,10 +47,14 @@ EVEWindow *eve_window_search(EVEWindow *window, char *name);
 
 uint8_t eve_window_draw(EVEWindow *window, uint8_t tag0);
 int eve_window_touch(EVEWindow *window, EVETouch *touch, uint16_t evt, uint8_t tag0);
-void eve_window_root_draw(EVEWindow *window);
+void eve_window_root_draw(EVEWindowRoot *root);
 void eve_window_root_touch(EVETouch *touch, uint16_t evt, uint8_t tag0, void *win);
 
 EVEKbd *eve_window_kbd(EVEWindow *window);
 void eve_window_kbd_attach(EVEWindow *window);
 void eve_window_kbd_detach(EVEWindow *window);
-EVEFont *eve_window_font(EVEWindow *window);
\ No newline at end of file
+EVEFont *eve_window_font(EVEWindow *window);
+
+EVEWindow *eve_window_scroll(EVEWindowRoot *root, uint8_t *tag);
+void eve_window_scroll_start(EVEWindow *window, uint8_t tag);
+void eve_window_scroll_stop(EVEWindow *window);
diff --git a/fw/fe310/eos/eve/widget/freew.c b/fw/fe310/eos/eve/widget/freew.c
index 1a55ea9..86c2686 100644
--- a/fw/fe310/eos/eve/widget/freew.c
+++ b/fw/fe310/eos/eve/widget/freew.c
@@ -23,19 +23,15 @@ void eve_freew_init(EVEFreeWidget *widget, EVERect *g, EVEPage *page, eve_freew_
 
     memset(widget, 0, sizeof(EVEFreeWidget));
     eve_widget_init(_widget, EVE_WIDGET_TYPE_FREE, g, page, eve_freew_draw, eve_freew_touch, putc);
-    eve_freew_update(widget, draw, touch, NULL);
-}
-
-void eve_freew_update(EVEFreeWidget *widget, eve_freew_draw_t draw, eve_freew_touch_t touch, eve_kbd_input_handler_t putc) {
-    if (draw) widget->_draw = draw;
-    if (touch) widget->_touch = touch;
-    if (putc) widget->w.putc = putc;
+    widget->_draw = draw;
+    widget->_touch = touch;
+    widget->w.putc = putc;
 }
 
 void eve_freew_tag(EVEFreeWidget *widget) {
     EVEWidget *_widget = &widget->w;
 
-    if (_widget->tagN != EVE_TAG_NOTAG) {
+    if (_widget->tagN != EVE_NOTAG) {
         eve_cmd_dl(TAG(_widget->tagN));
         _widget->tagN++;
     }
diff --git a/fw/fe310/eos/eve/widget/freew.h b/fw/fe310/eos/eve/widget/freew.h
index d6d2bf7..7eda8c1 100644
--- a/fw/fe310/eos/eve/widget/freew.h
+++ b/fw/fe310/eos/eve/widget/freew.h
@@ -19,7 +19,6 @@ typedef struct EVEFreeSpec {
 
 int eve_freew_create(EVEFreeWidget *widget, EVERect *g, EVEPage *page, EVEFreeSpec *spec);
 void eve_freew_init(EVEFreeWidget *widget, EVERect *g, EVEPage *page, eve_freew_draw_t draw, eve_freew_touch_t touch, eve_kbd_input_handler_t putc);
-void eve_freew_update(EVEFreeWidget *widget, eve_freew_draw_t draw, eve_freew_touch_t touch, eve_kbd_input_handler_t putc);
 
 void eve_freew_tag(EVEFreeWidget *widget);
 uint8_t eve_freew_draw(EVEWidget *_widget, uint8_t tag0);
diff --git a/fw/fe310/eos/eve/widget/pagew.c b/fw/fe310/eos/eve/widget/pagew.c
index 4f59d2e..bd7819f 100644
--- a/fw/fe310/eos/eve/widget/pagew.c
+++ b/fw/fe310/eos/eve/widget/pagew.c
@@ -25,15 +25,9 @@ void eve_pagew_init(EVEPageWidget *widget, EVERect *g, EVEPage *page, EVEFont *f
 
     memset(widget, 0, sizeof(EVEPageWidget));
     eve_widget_init(_widget, EVE_WIDGET_TYPE_PAGE, g, page, eve_pagew_draw, eve_pagew_touch, NULL);
-    eve_pagew_update(widget, font, title, constructor);
-}
-
-void eve_pagew_update(EVEPageWidget *widget, EVEFont *font, char *title, eve_view_constructor_t constructor) {
-    EVEWidget *_widget = &widget->w;
-
-    if (font) widget->font = font;
-    if (title) widget->title = title;
-    if (constructor) widget->constructor = constructor;
+    widget->font = font;
+    widget->title = title;
+    widget->constructor = constructor;
     if (_widget->g.h == 0) _widget->g.h = eve_font_h(widget->font);
 }
 
@@ -41,7 +35,7 @@ uint8_t eve_pagew_draw(EVEWidget *_widget, uint8_t tag0) {
     EVEPageWidget *widget = (EVEPageWidget *)_widget;
 
     _widget->tag0 = tag0;
-    if (tag0 != EVE_TAG_NOTAG) {
+    if (tag0 != EVE_NOTAG) {
         eve_cmd_dl(TAG(tag0));
         tag0++;
     }
diff --git a/fw/fe310/eos/eve/widget/pagew.h b/fw/fe310/eos/eve/widget/pagew.h
index ef34f48..76ac0d2 100644
--- a/fw/fe310/eos/eve/widget/pagew.h
+++ b/fw/fe310/eos/eve/widget/pagew.h
@@ -15,7 +15,6 @@ typedef struct EVEPageSpec {
 
 int eve_pagew_create(EVEPageWidget *widget, EVERect *g, EVEPage *page, EVEPageSpec *spec);
 void eve_pagew_init(EVEPageWidget *widget, EVERect *g, EVEPage *page, EVEFont *font, char *title, eve_view_constructor_t constructor);
-void eve_pagew_update(EVEPageWidget *widget, EVEFont *font, char *title, eve_view_constructor_t constructor);
 
 uint8_t eve_pagew_draw(EVEWidget *_widget, uint8_t tag0);
 int eve_pagew_touch(EVEWidget *_widget, EVETouch *touch, uint16_t evt);
diff --git a/fw/fe310/eos/eve/widget/selectw.c b/fw/fe310/eos/eve/widget/selectw.c
index d1d1959..7873e95 100644
--- a/fw/fe310/eos/eve/widget/selectw.c
+++ b/fw/fe310/eos/eve/widget/selectw.c
@@ -12,16 +12,18 @@
 #include "widget.h"
 #include "selectw.h"
 
-#define SELECTW_NOSELECT    0xffffffff
+#define SELECTW_NOSELECT        0xffffffff
 
-static int _selectw_verify(utf8_t *opt, uint16_t size) {
+#define DIVC(x,y)               ((x) / (y) + ((x) % (y) != 0))
+
+static int _selectw_verify(utf8_t *option, uint16_t option_size) {
     int o_len;
     uint16_t o_curr;
     int rv;
 
     o_curr = 0;
-    while (o_curr < size) {
-        rv = utf8_verify(opt + o_curr, size - o_curr, &o_len);
+    while (o_curr < option_size) {
+        rv = utf8_verify(option + o_curr, option_size - o_curr, &o_len);
         if (rv) return EVE_ERR;
         if (o_len == 0) return EVE_OK;
         o_curr += o_len + 1;
@@ -49,12 +51,12 @@ static int _selectw_count(EVESelectWidget *widget) {
     return i;
 }
 
-static void _selectw_update_sz(EVESelectWidget *widget, int i) {
+static void _selectw_update_sz(EVESelectWidget *widget, int uievt) {
     EVEWidget *_widget = &widget->w;
     EVEPage *page = _widget->page;
 
-    _widget->g.h = i * widget->font->h;
-    eve_widget_uievt_push(_widget, EVE_UIEVT_WIDGET_UPDATE_G, NULL);
+    _widget->g.h = widget->option_count * widget->font->h;
+    if (uievt) eve_view_uievt_push(&page->v, EVE_UIEVT_WIDGET_UPDATE_G, _widget);
 }
 
 int eve_selectw_create(EVESelectWidget *widget, EVERect *g, EVEPage *page, EVESelectSpec *spec) {
@@ -74,30 +76,20 @@ int eve_selectw_create(EVESelectWidget *widget, EVERect *g, EVEPage *page, EVESe
 
 void eve_selectw_init(EVESelectWidget *widget, EVERect *g, EVEPage *page, EVEFont *font, utf8_t *option, uint16_t option_size, uint8_t multi) {
     EVEWidget *_widget = &widget->w;
+    int rv;
 
     memset(widget, 0, sizeof(EVESelectWidget));
     eve_widget_init(_widget, EVE_WIDGET_TYPE_SELECT, g, page, eve_selectw_draw, eve_selectw_touch, NULL);
-    eve_selectw_update(widget, font, option, option_size);
-    widget->multi = multi;
-}
-
-void eve_selectw_update(EVESelectWidget *widget, EVEFont *font, utf8_t *option, uint16_t option_size) {
-    int rv, text_len;
-
-    if (font) widget->font = font;
-    if (option) {
-        int rv = _selectw_verify(option, option_size);
-        if (rv == EVE_OK) {
-            int i;
-
-            widget->option = option;
-            widget->option_size = option_size;
-            widget->select = widget->multi ? 0 : SELECTW_NOSELECT;
-
-            i = _selectw_count(widget);
-            _selectw_update_sz(widget, i);
-        }
+    widget->font = font;
+    rv = _selectw_verify(option, option_size);
+    if (rv == EVE_OK) {
+        widget->option = option;
+        widget->option_size = option_size;
+        widget->option_count = _selectw_count(widget);
+        _selectw_update_sz(widget, 0);
     }
+    widget->multi = multi;
+    widget->select = widget->multi ? 0 : SELECTW_NOSELECT;
 }
 
 void eve_selectw_destroy(EVESelectWidget *widget) {
@@ -109,40 +101,53 @@ uint8_t eve_selectw_draw(EVEWidget *_widget, uint8_t tag0) {
     EVESelectWidget *widget = (EVESelectWidget *)_widget;
     int o_len;
     int o_curr;
-    int i = 0, s;
+    int i, s;
     int16_t x1, x2, y1, y2;
     uint16_t new_h;
 
+    int line0, lineN;
+
+    line0 = -((int)eve_page_win_y(page, _widget->g.y)) / widget->font->h;
+    lineN = DIVC((-((int)eve_page_win_y(page, _widget->g.y)) + page->v.window->g.h), widget->font->h);
+    if (line0 < 0) line0 = 0;
+    if (lineN < 0) lineN = 0;
+    if (line0 > widget->option_count) line0 = widget->option_count;
+    if (lineN > widget->option_count) lineN = widget->option_count;
+
     _widget->tag0 = tag0;
     _widget->tagN = tag0;
+    widget->line0 = line0;
+
     o_curr = 0;
+    i = 0;
     do {
         o_len = strnlen(widget->option + o_curr, widget->option_size - o_curr);
         if (!o_len || (o_len == widget->option_size - o_curr)) break;
-
-        if (_widget->tagN != EVE_TAG_NOTAG) {
-            eve_cmd_dl(TAG(_widget->tagN));
-            _widget->tagN++;
-        }
-        s = widget->multi ? widget->select & (0x1 << i) : widget->select == i;
-        x1 = _widget->g.x;
-        x2 = x1 + _widget->g.w;
-        y1 = _widget->g.y + i * widget->font->h;
-        y2 = y1 + widget->font->h;
-        eve_cmd_dl(BEGIN(EVE_RECTS));
-        if (!s) eve_cmd_dl(COLOR_MASK(0 ,0 ,0 ,0));
-        eve_cmd_dl(VERTEX2F(x1, y1));
-        eve_cmd_dl(VERTEX2F(x2, y2));
-        if (!s) {
-            eve_cmd_dl(COLOR_MASK(1 ,1 ,1 ,1));
-            eve_cmd_dl(BEGIN(EVE_LINES));
-            eve_cmd_dl(VERTEX2F(x1, y2));
+        if ((i >= line0) && (i < lineN)) {
+            if (_widget->tagN != EVE_NOTAG) {
+                eve_cmd_dl(TAG(_widget->tagN));
+                _widget->tagN++;
+            }
+            s = widget->multi ? widget->select & (0x1 << i) : widget->select == i;
+            x1 = _widget->g.x;
+            x2 = x1 + _widget->g.w;
+            y1 = _widget->g.y + i * widget->font->h;
+            y2 = y1 + widget->font->h;
+            eve_cmd_dl(BEGIN(EVE_RECTS));
+            if (!s) eve_cmd_dl(COLOR_MASK(0 ,0 ,0 ,0));
+            eve_cmd_dl(VERTEX2F(x1, y1));
             eve_cmd_dl(VERTEX2F(x2, y2));
+            if (!s) {
+                eve_cmd_dl(COLOR_MASK(1 ,1 ,1 ,1));
+                eve_cmd_dl(BEGIN(EVE_LINES));
+                eve_cmd_dl(VERTEX2F(x1, y2));
+                eve_cmd_dl(VERTEX2F(x2, y2));
+            }
+            eve_cmd_dl(END());
+            if (s) eve_cmd_dl(COLOR_RGBC(page->v.color_bg));
+            eve_cmd(CMD_TEXT, "hhhhs", x1, y1, widget->font->id, 0, widget->option + o_curr);
+            if (s) eve_cmd_dl(COLOR_RGBC(page->v.color_fg));
         }
-        eve_cmd_dl(END());
-        if (s) eve_cmd_dl(COLOR_RGBC(page->v.color_bg));
-        eve_cmd(CMD_TEXT, "hhhhs", x1, y1, widget->font->id, 0, widget->option + o_curr);
-        if (s) eve_cmd_dl(COLOR_RGBC(page->v.color_fg));
 
         o_curr += o_len + 1;
         i++;
@@ -155,7 +160,7 @@ int eve_selectw_touch(EVEWidget *_widget, EVETouch *touch, uint16_t evt) {
     EVESelectWidget *widget = (EVESelectWidget *)_widget;
 
     if (evt & EVE_TOUCH_ETYPE_TAG_UP) {
-        int i = touch->tag0 - _widget->tag0;
+        int i = touch->tag0 - _widget->tag0 + widget->line0;
         if (widget->multi) {
             uint32_t f = (0x1 << i);
 
@@ -198,12 +203,12 @@ utf8_t *eve_selectw_option_get_select(EVESelectWidget *widget) {
     return eve_selectw_option_get(widget, widget->select);
 }
 
-int eve_selectw_option_add(EVESelectWidget *widget, utf8_t *opt) {
+int eve_selectw_option_add(EVESelectWidget *widget, utf8_t *option) {
     int o_len;
     int o_curr;
     int rv, i;
 
-    rv = utf8_verify(opt, strlen(opt) + 1, NULL);
+    rv = utf8_verify(option, strlen(option) + 1, NULL);
     if (rv) return EVE_ERR;
 
     o_curr = 0;
@@ -217,26 +222,27 @@ int eve_selectw_option_add(EVESelectWidget *widget, utf8_t *opt) {
         }
     } while (o_len);
 
-    if (o_curr + strlen(opt) + 1 > widget->option_size) return EVE_ERR_FULL;
-    strcpy(widget->option + o_curr, opt);
+    if (o_curr + strlen(option) + 1 > widget->option_size) return EVE_ERR_FULL;
+    strcpy(widget->option + o_curr, option);
 
-    _selectw_update_sz(widget, i + 1);
+    widget->option_count = i + 1;
+    _selectw_update_sz(widget, 1);
 
     return EVE_OK;
 }
 
-int eve_selectw_option_set(EVESelectWidget *widget, utf8_t *opt, uint16_t size) {
+int eve_selectw_option_set(EVESelectWidget *widget, utf8_t *option, uint16_t option_size) {
     int rv, i;
 
-    rv = _selectw_verify(opt, size);
+    rv = _selectw_verify(option, option_size);
     if (rv) return rv;
-    if (size > widget->option_size) return EVE_ERR_FULL;
+    if (option_size > widget->option_size) return EVE_ERR_FULL;
 
-    memcpy(widget->option, opt, size);
-    memset(widget->option + size, 0, widget->option_size - size);
+    memcpy(widget->option, option, option_size);
+    memset(widget->option + option_size, 0, widget->option_size - option_size);
 
-    i = _selectw_count(widget);
-    _selectw_update_sz(widget, i);
+    widget->option_count = _selectw_count(widget);
+    _selectw_update_sz(widget, 1);
 
     return EVE_OK;
 }
diff --git a/fw/fe310/eos/eve/widget/selectw.h b/fw/fe310/eos/eve/widget/selectw.h
index 00623c1..939e362 100644
--- a/fw/fe310/eos/eve/widget/selectw.h
+++ b/fw/fe310/eos/eve/widget/selectw.h
@@ -5,7 +5,9 @@ typedef struct EVESelectWidget {
     EVEFont *font;
     utf8_t *option;
     uint16_t option_size;
+    uint16_t option_count;
     uint32_t select;
+    uint16_t line0;
     uint8_t multi;
 } EVESelectWidget;
 
@@ -17,7 +19,6 @@ typedef struct EVESelectSpec {
 
 int eve_selectw_create(EVESelectWidget *widget, EVERect *g, EVEPage *page, EVESelectSpec *spec);
 void eve_selectw_init(EVESelectWidget *widget, EVERect *g, EVEPage *page, EVEFont *font, utf8_t *option, uint16_t option_size, uint8_t multi);
-void eve_selectw_update(EVESelectWidget *widget, EVEFont *font, utf8_t *option, uint16_t option_size);
 void eve_selectw_destroy(EVESelectWidget *widget);
 
 uint8_t eve_selectw_draw(EVEWidget *_widget, uint8_t tag0);
@@ -25,5 +26,5 @@ int eve_selectw_touch(EVEWidget *_widget, EVETouch *touch, uint16_t evt);
 
 utf8_t *eve_selectw_option_get(EVESelectWidget *widget, int idx);
 utf8_t *eve_selectw_option_get_select(EVESelectWidget *widget);
-int eve_selectw_option_add(EVESelectWidget *widget, utf8_t *opt);
-int eve_selectw_option_set(EVESelectWidget *widget, utf8_t *opt, uint16_t size);
+int eve_selectw_option_add(EVESelectWidget *widget, utf8_t *option);
+int eve_selectw_option_set(EVESelectWidget *widget, utf8_t *option, uint16_t option_size);
diff --git a/fw/fe310/eos/eve/widget/strw.c b/fw/fe310/eos/eve/widget/strw.c
index e65dd97..4e1e2c0 100644
--- a/fw/fe310/eos/eve/widget/strw.c
+++ b/fw/fe310/eos/eve/widget/strw.c
@@ -16,9 +16,9 @@
 
 #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_TRACK_NONE         0
-#define STRW_TRACK_CRSR         1
-#define STRW_TRACK_TXT          2
+#define STRW_TMODE_NONE         0
+#define STRW_TMODE_CRSR         1
+#define STRW_TMODE_TXT          2
 
 #define CH_BS                   0x08
 #define CH_DEL                  0x7f
@@ -45,28 +45,20 @@ int eve_strw_create(EVEStrWidget *widget, EVERect *g, EVEPage *page, EVEStrSpec
 
 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);
-    eve_strw_update(widget, font, str, str_size);
-}
-
-void eve_strw_update(EVEStrWidget *widget, EVEFont *font, utf8_t *str, uint16_t str_size) {
-    int rv, str_len;
-    EVEWidget *_widget = &widget->w;
-
-    if (font) widget->font = font;
-    if (str) {
-        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(widget->font, str);
+    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);
 }
 
@@ -76,14 +68,13 @@ void eve_strw_destroy(EVEStrWidget *widget) {
 
 static void set_focus(EVEStrWidget *widget) {
     EVEWidget *_widget = &widget->w;
-    EVEPage *page = _widget->page;
     EVERect focus;
 
     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);
+    eve_widget_focus(_widget, &focus);
 }
 
 static EVEStrCursor *cursor_prox(EVEStrWidget *widget, EVEStrCursor *cursor, EVETouch *touch, short *dx) {
@@ -142,7 +133,7 @@ uint8_t eve_strw_draw(EVEWidget *_widget, uint8_t tag0) {
     char cut = widget->str_g.x || (widget->str_g.w > _widget->g.w);
 
     _widget->tag0 = tag0;
-    if (tag0 != EVE_TAG_NOTAG) {
+    if (tag0 != EVE_NOTAG) {
         eve_cmd_dl(TAG(tag0));
         eve_touch_set_opt(tag0, STRW_TOUCH_OPT);
         tag0++;
@@ -163,8 +154,8 @@ uint8_t eve_strw_draw(EVEWidget *_widget, uint8_t tag0) {
 
         if (win_x1 < 0) win_x1 = 0;
         if (win_y1 < 0) win_y1 = 0;
-        if (win_x2 > window->root->g.w) win_x2 = window->root->g.w;
-        if (win_y2 > window->root->g.h) win_y2 = window->root->g.h;
+        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;
@@ -227,11 +218,11 @@ int eve_strw_touch(EVEWidget *_widget, EVETouch *touch, uint16_t evt) {
         }
         if (evt & EVE_TOUCH_ETYPE_TRACK_START) {
             if (t_cursor) {
-                widget->track.mode = STRW_TRACK_CRSR;
+                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_TRACK_TXT;
+                widget->track.mode = STRW_TMODE_TXT;
             }
         }
     }
@@ -240,7 +231,7 @@ int eve_strw_touch(EVEWidget *_widget, EVETouch *touch, uint16_t evt) {
         int x, w1;
 
         switch (widget->track.mode) {
-            case STRW_TRACK_TXT:
+            case STRW_TMODE_TXT:
                 if (evt & EVE_TOUCH_ETYPE_TRACK_START) {
                     widget->str_g.x0 = widget->str_g.x;
                 }
@@ -251,7 +242,7 @@ int eve_strw_touch(EVEWidget *_widget, EVETouch *touch, uint16_t evt) {
                 widget->str_g.x = x;
                 break;
 
-            case STRW_TRACK_CRSR:
+            case STRW_TMODE_CRSR:
                 eve_strw_cursor_set(widget, widget->track.cursor, eve_page_x(page, touch->x) + widget->track.dx);
                 break;
         }
@@ -277,7 +268,7 @@ int eve_strw_touch(EVEWidget *_widget, EVETouch *touch, uint16_t evt) {
     }
 
     if (evt & EVE_TOUCH_ETYPE_TRACK_STOP) {
-        widget->track.mode = STRW_TRACK_NONE;
+        widget->track.mode = STRW_TMODE_NONE;
         widget->track.cursor = NULL;
         widget->track.dx = 0;
     }
diff --git a/fw/fe310/eos/eve/widget/strw.h b/fw/fe310/eos/eve/widget/strw.h
index ae54700..aaa83fe 100644
--- a/fw/fe310/eos/eve/widget/strw.h
+++ b/fw/fe310/eos/eve/widget/strw.h
@@ -33,7 +33,6 @@ typedef struct EVEStrSpec {
 
 int eve_strw_create(EVEStrWidget *widget, EVERect *g, EVEPage *page, EVEStrSpec *spec);
 void eve_strw_init(EVEStrWidget *widget, EVERect *g, EVEPage *page, EVEFont *font, utf8_t *str, uint16_t str_size);
-void eve_strw_update(EVEStrWidget *widget, EVEFont *font, utf8_t *str, uint16_t str_size);
 void eve_strw_destroy(EVEStrWidget *widget);
 
 uint8_t eve_strw_draw(EVEWidget *_widget, uint8_t tag0);
diff --git a/fw/fe310/eos/eve/widget/textw.c b/fw/fe310/eos/eve/widget/textw.c
index 4224f44..e17351c 100644
--- a/fw/fe310/eos/eve/widget/textw.c
+++ b/fw/fe310/eos/eve/widget/textw.c
@@ -55,32 +55,23 @@ int eve_textw_create(EVETextWidget *widget, EVERect *g, EVEPage *page, EVETextSp
 
 void eve_textw_init(EVETextWidget *widget, EVERect *g, EVEPage *page, EVEFont *font, utf8_t *text, uint16_t text_size, uint16_t *line, uint16_t line_size) {
     EVEWidget *_widget = &widget->w;
+    int rv, text_len;
 
     memset(widget, 0, sizeof(EVETextWidget));
     eve_widget_init(_widget, EVE_WIDGET_TYPE_TEXT, g, page, eve_textw_draw, eve_textw_touch, eve_textw_putc);
-    eve_textw_update(widget, font, text, text_size, line, line_size);
-}
-
-void eve_textw_update(EVETextWidget *widget, EVEFont *font, utf8_t *text, uint16_t text_size, uint16_t *line, uint16_t line_size) {
-    int rv, text_len;
-
-    if (font) widget->font = font;
-    if (text) {
-        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;
-    }
-    if (line) {
-        widget->line = line;
-        widget->line_size = line_size;
+    widget->font = font;
+    rv = utf8_verify(text, text_size, &text_len);
+    if (rv != UTF_OK) {
+        if (text_len >= text_size) text_len = 0;
+        text[text_len] = '\0';
     }
+    widget->text = text;
+    widget->text_size = text_size;
+    widget->text_len = text_len;
+    widget->line = line;
+    widget->line_size = line_size;
     memset(widget->line, 0xff, line_size * sizeof(uint16_t));
-    eve_textw_text_update(widget, 0);
+    eve_textw_text_update(widget, 0, 0);
 }
 
 void eve_textw_destroy(EVETextWidget *widget) {
@@ -90,14 +81,13 @@ void eve_textw_destroy(EVETextWidget *widget) {
 
 static void set_focus(EVETextWidget *widget, EVETextCursor *cursor) {
     EVEWidget *_widget = &widget->w;
-    EVEPage *page = _widget->page;
     EVERect focus;
 
     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);
+    eve_widget_focus(_widget, &focus);
 }
 
 static EVETextCursor *cursor_prox(EVETextWidget *widget, EVETextCursor *cursor, EVETouch *touch, short *dx, short *dl) {
@@ -160,8 +150,8 @@ uint8_t eve_textw_draw(EVEWidget *_widget, uint8_t tag0) {
     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);
+    _line0 = line0 = -((int)eve_page_win_y(page, _widget->g.y)) / widget->font->h;
+    _lineN = lineN = DIVC((-((int)eve_page_win_y(page, _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;
@@ -191,7 +181,7 @@ uint8_t eve_textw_draw(EVEWidget *_widget, uint8_t tag0) {
         }
 
         for (i=line0; i<lineN; i++) {
-            if (_widget->tagN != EVE_TAG_NOTAG) {
+            if (_widget->tagN != EVE_NOTAG) {
                 eve_cmd_dl(TAG(_widget->tagN));
                 eve_touch_set_opt(_widget->tagN, TEXTW_TOUCH_OPT);
                 _widget->tagN++;
@@ -230,7 +220,7 @@ uint8_t eve_textw_draw(EVEWidget *_widget, uint8_t tag0) {
             }
         }
         if (lineNvisible) {
-            if (_widget->tagN != EVE_TAG_NOTAG) {
+            if (_widget->tagN != EVE_NOTAG) {
                 eve_cmd_dl(TAG(_widget->tagN));
                 eve_touch_set_opt(_widget->tagN, TEXTW_TOUCH_OPT);
                 _widget->tagN++;
@@ -239,8 +229,8 @@ uint8_t eve_textw_draw(EVEWidget *_widget, uint8_t tag0) {
         }
     } else {
         widget->line0 = 0;
-        _widget->tag0 = EVE_TAG_NOTAG;
-        _widget->tagN = EVE_TAG_NOTAG;
+        _widget->tag0 = EVE_NOTAG;
+        _widget->tagN = EVE_NOTAG;
     }
 
     return _widget->tagN;
@@ -403,8 +393,8 @@ void eve_textw_putc(void *w, int c) {
     }
 
     r = cursor1->line;
-    if (cursor1->line) r = eve_textw_text_update(widget, cursor1->line - 1);
-    if ((cursor1->line == 0) || (r == cursor1->line - 1)) r = eve_textw_text_update(widget, cursor1->line);
+    if (cursor1->line) r = eve_textw_text_update(widget, cursor1->line - 1, 1);
+    if ((cursor1->line == 0) || (r == cursor1->line - 1)) r = eve_textw_text_update(widget, cursor1->line, 1);
 
     if (cursor1->line && (cursor1->ch < LINE_START(widget, cursor1->line))) {
         cursor1->line--;
@@ -419,7 +409,7 @@ void eve_textw_putc(void *w, int c) {
     }
 }
 
-uint16_t eve_textw_text_update(EVETextWidget *widget, uint16_t line) {
+uint16_t eve_textw_text_update(EVETextWidget *widget, uint16_t line, int uievt) {
     int i;
     utf32_t ch;
     uint8_t ch_w;
@@ -480,11 +470,11 @@ uint16_t eve_textw_text_update(EVETextWidget *widget, uint16_t line) {
         widget->line[i] = LINE_EMPTY;
     }
 
-    if (widget->line_len != line) {
-        widget->line_len = line;
-        _widget->g.h = (widget->line_len + 1) * widget->font->h;
-        eve_widget_uievt_push(_widget, EVE_UIEVT_WIDGET_UPDATE_G, NULL);
+    if (uievt && (widget->line_len != line)) {
+        eve_view_uievt_push(&page->v, EVE_UIEVT_WIDGET_UPDATE_G, _widget);
     }
+    widget->line_len = line;
+    _widget->g.h = (widget->line_len + 1) * widget->font->h;
 
     return line;
 }
@@ -513,7 +503,7 @@ void eve_textw_cursor_set(EVETextWidget *widget, EVETextCursor *cursor, uint8_t
     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 ((tag >= _widget->tag0) && ((_widget->tagN == EVE_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) {
diff --git a/fw/fe310/eos/eve/widget/textw.h b/fw/fe310/eos/eve/widget/textw.h
index 59e6f8c..570bba8 100644
--- a/fw/fe310/eos/eve/widget/textw.h
+++ b/fw/fe310/eos/eve/widget/textw.h
@@ -34,14 +34,13 @@ typedef struct EVETextSpec {
 
 int eve_textw_create(EVETextWidget *widget, EVERect *g, EVEPage *page, EVETextSpec *spec);
 void eve_textw_init(EVETextWidget *widget, EVERect *g, EVEPage *page, EVEFont *font, utf8_t *text, uint16_t text_size, uint16_t *line, uint16_t line_size);
-void eve_textw_update(EVETextWidget *widget, EVEFont *font, utf8_t *text, uint16_t text_size, uint16_t *line, uint16_t line_size);
 void eve_textw_destroy(EVETextWidget *widget);
 
 uint8_t eve_textw_draw(EVEWidget *_widget, uint8_t tag0);
 int eve_textw_touch(EVEWidget *_widget, EVETouch *touch, uint16_t evt);
 void eve_textw_putc(void *_w, int c);
 
-uint16_t eve_textw_text_update(EVETextWidget *widget, uint16_t line);
+uint16_t eve_textw_text_update(EVETextWidget *widget, uint16_t line, int uievt);
 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
index 6f6a3ff..96d2ddf 100644
--- a/fw/fe310/eos/eve/widget/widget.c
+++ b/fw/fe310/eos/eve/widget/widget.c
@@ -70,7 +70,8 @@ void eve_widget_destroy(EVEWidget *widget) {
     if (_widget_destroy[widget->type]) _widget_destroy[widget->type](widget);
 }
 
-void eve_widget_uievt_push(EVEWidget *widget, uint16_t evt, void *param) {
-    EVEView *view = &widget->page->v;
-    eve_view_uievt_push(view, evt, param ? param : widget);
-}
\ No newline at end of file
+void eve_widget_focus(EVEWidget *widget, EVERect *rect) {
+    EVEPage *page = widget->page;
+
+    eve_page_focus_widget(page, widget, rect);
+}
diff --git a/fw/fe310/eos/eve/widget/widget.h b/fw/fe310/eos/eve/widget/widget.h
index 0f76799..f081b4c 100644
--- a/fw/fe310/eos/eve/widget/widget.h
+++ b/fw/fe310/eos/eve/widget/widget.h
@@ -28,5 +28,4 @@ void eve_widget_init(EVEWidget *widget, uint8_t type, EVERect *g, EVEPage *page,
 size_t eve_widget_size(uint8_t type);
 void eve_widget_set_label(EVEWidget *widget, EVELabel *label);
 EVEWidget *eve_widget_next(EVEWidget *widget);
-
-void eve_widget_uievt_push(EVEWidget *widget, uint16_t evt, void *param);
\ No newline at end of file
+void eve_widget_focus(EVEWidget *widget, EVERect *rect);
\ No newline at end of file
diff --git a/fw/fe310/test/cell_pdp.c b/fw/fe310/test/cell_pdp.c
index a45adc4..8bc8c41 100644
--- a/fw/fe310/test/cell_pdp.c
+++ b/fw/fe310/test/cell_pdp.c
@@ -21,7 +21,6 @@
 #include <eve/widget/widgets.h>
 
 #include <app/app_root.h>
-#include <app/app_form.h>
 
 #include "status.h"
 #include "cell_pdp.h"
@@ -92,19 +91,19 @@ void app_cell_pdp(EVEWindow *window, EVEViewStack *stack) {
         },
     };
 
-    EVEForm *form = app_form_create(window, stack, spec, 3, app_cell_pdp_action, app_cell_pdp_close);
+    EVEForm *form = eve_form_create(window, stack, spec, 3, app_cell_pdp_action, app_cell_pdp_close);
 }
 
 void app_cell_pdp_action(EVEForm *form) {
-    EVEStrWidget *apn = (EVEStrWidget *)eve_form_widget(form, 0);
-    EVEStrWidget *user = (EVEStrWidget *)eve_form_widget(form, 1);
-    EVEStrWidget *pass = (EVEStrWidget *)eve_form_widget(form, 2);
+    EVEStrWidget *apn = (EVEStrWidget *)eve_page_widget(&form->p, 0);
+    EVEStrWidget *user = (EVEStrWidget *)eve_page_widget(&form->p, 1);
+    EVEStrWidget *pass = (EVEStrWidget *)eve_page_widget(&form->p, 2);
 
     cell_pdp_connect(apn->str, user->str, pass->str);
 }
 
 void app_cell_pdp_close(EVEForm *form) {
-    app_form_destroy(form);
+    eve_form_destroy(form);
 }
 
 void app_cell_pdp_init(void) {
diff --git a/fw/fe310/test/main.c b/fw/fe310/test/main.c
index a3af24b..7f0fc43 100644
--- a/fw/fe310/test/main.c
+++ b/fw/fe310/test/main.c
@@ -21,7 +21,6 @@
 #include <eve/widget/widgets.h>
 
 #include <app/app_root.h>
-#include <app/app_form.h>
 
 #include "status.h"
 #include "cell_dev.h"
@@ -58,7 +57,7 @@ void app_home_page(EVEWindow *window, EVEViewStack *stack) {
         },
     };
 
-    EVEForm *form = app_form_create(window, stack, spec, 4, NULL, NULL);
+    EVEForm *form = eve_form_create(window, stack, spec, 4, NULL, NULL);
 }
 
 int main() {
diff --git a/fw/fe310/test/modem.c b/fw/fe310/test/modem.c
index ec74482..b78a3b4 100644
--- a/fw/fe310/test/modem.c
+++ b/fw/fe310/test/modem.c
@@ -22,7 +22,6 @@
 #include <eve/widget/widgets.h>
 
 #include <app/app_root.h>
-#include <app/app_form.h>
 
 #include "modem.h"
 
@@ -79,8 +78,8 @@ static void handle_uart(unsigned char type) {
 }
 
 static void handle_cell_msg(unsigned char type, unsigned char *buffer, uint16_t len) {
-    EVEWindow *root = app_root();
-    EVEWindow *window = eve_window_search(root, "main");
+    EVEWindowRoot *root = app_root();
+    EVEWindow *window = eve_window_search(&root->w, "main");
     VParam *param = window->view->param;
 
     if (type == EOS_CELL_MTYPE_UART_DATA) {
@@ -106,7 +105,7 @@ static uint8_t modem_draw(EVEView *view, uint8_t tag0) {
     VParam *param = view->param;
     EVEText *text = &param->text;
 
-    tag0 = eve_view_clear(view, tag0);
+    tag0 = eve_view_clear(view, tag0, 0);
     return eve_text_draw(text, tag0);
 }
 
@@ -119,7 +118,7 @@ static int modem_touch(EVEView *view, EVETouch *touch, uint16_t evt, uint8_t tag
 
 void app_modem(EVEWindow *window, EVEViewStack *stack) {
     unsigned char *buf;
-    EVEWindowRoot *root = (EVEWindowRoot *)window->root;
+    EVEWindowRoot *root = window->root;
     EVEKbd *kbd = eve_window_kbd(window);
     EVERect g = {0, 60, 480, 512};
     EVEView *view;
@@ -150,7 +149,7 @@ void app_modem_close(EVEView *view) {
     unsigned char *buf = eos_net_alloc();
     VParam *param = view->param;
     EVEWindow *window = view->window;
-    EVEWindowRoot *root = (EVEWindowRoot *)window->root;
+    EVEWindowRoot *root = window->root;
     EVEKbd *kbd = eve_window_kbd(window);
     EVEViewStack *stack = param->stack;
 
diff --git a/fw/fe310/test/phone.c b/fw/fe310/test/phone.c
index de5ed1e..0bf1c04 100644
--- a/fw/fe310/test/phone.c
+++ b/fw/fe310/test/phone.c
@@ -21,7 +21,6 @@
 #include <eve/widget/widgets.h>
 
 #include <app/app_root.h>
-#include <app/app_form.h>
 
 #include "status.h"
 #include "phone.h"
@@ -93,12 +92,12 @@ void app_phone(EVEWindow *window, EVEViewStack *stack) {
         },
     };
 
-    EVEForm *form = app_form_create(window, stack, spec, 1, app_phone_action, NULL);
+    EVEForm *form = eve_form_create(window, stack, spec, 1, app_phone_action, NULL);
 }
 
 void app_phone_action(EVEForm *form) {
     char msg[128];
-    EVEStrWidget *w = (EVEStrWidget *)eve_form_widget(form, 0);
+    EVEStrWidget *w = (EVEStrWidget *)eve_page_widget(&form->p, 0);
     unsigned char *buf = eos_net_alloc();
 
     buf[0] = EOS_CELL_MTYPE_VOICE | EOS_CELL_MTYPE_VOICE_DIAL;
diff --git a/fw/fe310/test/status.c b/fw/fe310/test/status.c
index 4413767..b7307b2 100644
--- a/fw/fe310/test/status.c
+++ b/fw/fe310/test/status.c
@@ -21,7 +21,6 @@
 #include <eve/widget/widgets.h>
 
 #include <app/app_root.h>
-#include <app/app_form.h>
 
 #include "phone.h"
 #include "status.h"
@@ -58,10 +57,9 @@ static int status_touch(EVEView *view, EVETouch *touch, uint16_t evt, uint8_t ta
 static uint8_t status_draw(EVEView *view, uint8_t tag0) {
     uint8_t tag_opt = EVE_TOUCH_OPT_TRACK | EVE_TOUCH_OPT_TRACK_XY;
 
-    tag0 = eve_view_clear(view, tag0);
-    if (view->tag != EVE_TAG_NOTAG) eve_touch_set_opt(view->tag, eve_touch_get_opt(view->tag) | tag_opt);
+    tag0 = eve_view_clear(view, tag0, tag_opt);
 
-    if (tag0 != EVE_TAG_NOTAG) {
+    if (tag0 != EVE_NOTAG) {
         eve_touch_set_opt(tag0, eve_touch_get_opt(tag0) | tag_opt);
         eve_cmd_dl(TAG(tag0));
         tag0++;
@@ -79,7 +77,8 @@ void app_status_msg_set(char *msg, int refresh) {
 }
 
 void app_status_init(void) {
-    EVEWindow *status = eve_window_search(app_root(), "status");
+    EVEWindowRoot *root = app_root();
+    EVEWindow *status = eve_window_search(&root->w, "status");
     status->view->touch = status_touch;
     status->view->draw = status_draw;
 }
diff --git a/fw/fe310/test/wifi.c b/fw/fe310/test/wifi.c
index d3c61e4..76e811d 100644
--- a/fw/fe310/test/wifi.c
+++ b/fw/fe310/test/wifi.c
@@ -21,7 +21,6 @@
 #include <eve/widget/widgets.h>
 
 #include <app/app_root.h>
-#include <app/app_form.h>
 
 #include "status.h"
 #include "wifi.h"
@@ -56,9 +55,10 @@ static void wifi_disconnect(void) {
 }
 
 void wifi_scan_handler(unsigned char type, unsigned char *buffer, uint16_t size) {
-    EVEWindow *window = eve_window_search(app_root(), "main");
+    EVEWindowRoot *root = app_root();
+    EVEWindow *window = eve_window_search(&root->w, "main");
     EVEForm *form = (EVEForm *)window->view;
-    EVESelectWidget *select = (EVESelectWidget *)eve_form_widget(form, 0);
+    EVESelectWidget *select = (EVESelectWidget *)eve_page_widget(&form->p, 0);
 
     eve_selectw_option_set(select, buffer + 1, size - 1);
     eos_net_free(buffer, 0);
@@ -99,20 +99,20 @@ void app_wifi(EVEWindow *window, EVEViewStack *stack) {
         },
     };
 
-    EVEForm *form = app_form_create(window, stack, spec, 3, app_wifi_action, app_wifi_close);
+    EVEForm *form = eve_form_create(window, stack, spec, 3, app_wifi_action, app_wifi_close);
     wifi_scan();
 }
 
 void app_wifi_action(EVEForm *form) {
-    EVESelectWidget *sel = (EVESelectWidget *)eve_form_widget(form, 0);
-    EVEStrWidget *str = (EVEStrWidget *)eve_form_widget(form, 2);
+    EVESelectWidget *sel = (EVESelectWidget *)eve_page_widget(&form->p, 0);
+    EVEStrWidget *str = (EVEStrWidget *)eve_page_widget(&form->p, 2);
     char *ssid = eve_selectw_option_get_select(sel);
 
     if (ssid) wifi_connect(ssid, str->str);
 }
 
 void app_wifi_close(EVEForm *form) {
-    app_form_destroy(form);
+    eve_form_destroy(form);
 }
 
 void app_wifi_init(void) {
-- 
cgit v1.2.3