#include #include #include "eve.h" #include "eve_kbd.h" #include "eve_font.h" #include "window.h" #include "page.h" #include "widget/widget.h" #define PAGE_TMODE_NONE 0 #define PAGE_TMODE_TRACK 1 #define PAGE_TMODE_SCROLL 2 void eve_page_init(EVEPage *page, EVEWindow *window, EVEVStack *stack, EVEWidget *widget, uint16_t widget_size, uint8_t opt, eve_page_draw_t draw, eve_page_touch_t touch, eve_page_uievt_t uievt, eve_page_destructor_t destructor) { memset(page, 0, sizeof(EVEPage)); eve_view_init(&page->v, window, (eve_view_draw_t)draw, (eve_view_touch_t)touch, (eve_view_uievt_t)uievt, NULL); eve_phy_lho_init(&page->lho, 100, 0.5, 0); page->stack = stack; page->opt = opt; page->destructor = destructor; eve_page_set_widget(page, widget, widget_size); } void eve_page_attach(EVEPage *page, EVEWindow *window, void *page_id) { eve_view_attach(&page->v, window, page_id); } void eve_page_detach(EVEPage *page) { eve_view_detach(&page->v); } void eve_page_set_param(EVEPage *page, void *param) { eve_view_set_param(&page->v, param); } EVEView *eve_page_view(EVEPage *page) { return &page->v; } EVEPage *eve_page_from_view(EVEView *view) { return (EVEPage *)view; } EVEWidget *eve_page_widget(EVEPage *page, uint16_t _idx) { EVEWidget *w = page->widget; int i, idx; if (_idx >= page->widget_size) return NULL; idx = 0; for (i=0; iwidget_size; i++) { if (!(w->flags & EVE_WIDGET_FLAG_SKIP)) { if (idx == _idx) { return w; } idx++; } w = eve_widget_next(w); } return NULL; } EVEWidget *eve_page_widget_search(EVEPage *page, char *label) { EVEWidget *w = page->widget; int i; for (i=0; iwidget_size; i++) { if (!(w->flags & EVE_WIDGET_FLAG_SKIP)) { if (w->label && (strcmp(w->label->title, label) == 0)) { return w; } } w = eve_widget_next(w); } return NULL; } void eve_page_set_widget(EVEPage *page, EVEWidget *widget, uint16_t widget_size) { page->widget = widget; page->widget_size = widget_size; } static void page_destroy(EVEPage *page) { EVEWindow *window = page->v.window; eve_page_destructor_t destructor = page->destructor; eve_page_set_focus(page, NULL); if (eve_window_scroll(window, NULL) == window) { eve_window_scroll_stop(window); } eve_window_kbd_detach(window); eve_page_detach(page); if (destructor) destructor(page); } void eve_page_open(EVEPage *parent, eve_view_constructor_t constructor) { EVEWindow *window = parent->v.window; EVEVStack *stack = parent->stack; int rv; if (eve_vstack_full(stack)) return; page_destroy(parent); rv = eve_vstack_create_view(stack, window, constructor); if (rv) { EVEView *view = NULL; do { constructor = eve_vstack_get(stack); if (constructor) view = constructor(window, stack); if (view == NULL) eve_vstack_pull(stack); } while ((view == NULL) && constructor); if (view) eve_view_attach(view, window, constructor); } } void eve_page_close(EVEPage *page) { EVEWindow *window = page->v.window; EVEVStack *stack = page->stack; int rv; if (eve_vstack_level(stack) == 1) return; page_destroy(page); rv = eve_vstack_back(stack, window); if (rv) { eve_view_constructor_t constructor; EVEView *view = NULL; do { eve_vstack_pull(stack); constructor = eve_vstack_get(stack); if (constructor) view = constructor(window, stack); } while ((view == NULL) && constructor); if (view) eve_view_attach(view, window, constructor); } } /* Screen to page coordinates */ int16_t eve_page_x(EVEPage *page, int16_t x) { return x - page->g.x - page->v.window->g.x; } int16_t eve_page_y(EVEPage *page, int16_t 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 eve_page_win_x(page, x) + page->v.window->g.x; } int16_t eve_page_scr_y(EVEPage *page, int16_t y) { return eve_page_win_y(page, y) + page->v.window->g.y; } int eve_page_rect_visible(EVEPage *page, EVERect *rect) { EVERect win_g; eve_window_visible_g(page->v.window, &win_g); win_g.x -= page->v.window->g.x; win_g.y -= page->v.window->g.y; if ((page->g.x + rect->x + rect->w < win_g.x) || (page->g.y + rect->y + rect->h < win_g.y) || (page->g.x + rect->x > win_g.x + win_g.w) || (page->g.y + rect->y > win_g.y + win_g.h)) return 0; return 1; } void eve_page_show_rect(EVEPage *page, EVERect *rect) { EVERect win_g; eve_window_visible_g(page->v.window, &win_g); win_g.x -= page->v.window->g.x; win_g.y -= page->v.window->g.y; if (page->g.x + rect->x < win_g.x) { page->g.x = win_g.x - rect->x; } if (page->g.y + rect->y < win_g.y) { page->g.y = win_g.y - rect->y; } if (page->g.x + rect->x + rect->w > win_g.x + win_g.w) { page->g.x = win_g.x + win_g.w - (rect->x + rect->w); } if (page->g.y + rect->y + rect->h > win_g.y + win_g.h) { page->g.y = win_g.y + win_g.h - (rect->y + rect->h); } } /* returns true if x or y are out of page bounds for window */ int eve_page_oob(EVEPage *page, int *min_x, int *min_y) { int _min_x, _min_y; EVERect win_g; eve_window_visible_g(page->v.window, &win_g); _min_x = -(page->g.w > win_g.w ? page->g.w - win_g.w : 0); _min_y = -(page->g.h > win_g.h ? page->g.h - win_g.h : 0); if (min_x) *min_x = _min_x; if (min_y) *min_y = _min_y; return ((page->g.x > 0) || (page->g.x < _min_x) || (page->g.y > 0) || (page->g.y < _min_y)); } EVEWidget *eve_page_focus(EVEPage *page) { return page->widget_f; } void eve_page_set_focus(EVEPage *page, EVEWidget *widget) { if (page->widget_f != widget) { EVEWindow *window = page->v.window; EVEWidget *widget_f = page->widget_f; if ((widget_f && widget_f->putc) && !(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); if (!(widget_f && widget_f->putc)) { eve_window_kbd_attach(window); eve_page_show_rect(page, &widget->g); } } if (widget_f) { eve_view_uievt_push(&page->v, EVE_UIEVT_WIDGET_FOCUS_OUT, widget_f); widget_f->touch(widget_f, NULL, EVE_TOUCH_ETYPE_EXT | EVE_UIEVT_WIDGET_FOCUS_OUT); } page->widget_f = widget; if (widget) { eve_view_uievt_push(&page->v, EVE_UIEVT_WIDGET_FOCUS_IN, widget); widget->touch(widget, NULL, EVE_TOUCH_ETYPE_EXT | EVE_UIEVT_WIDGET_FOCUS_IN); } } } static int page_touch(EVEPage *page, EVETouch *touch, uint16_t evt) { EVEView *view = &page->v; EVEWindow *window = view->window; int scroll_x = 0, scroll_y = 0, scroll; int rv = 0; if ((page->opt & EVE_PAGE_OPT_SCROLL_XY) == EVE_PAGE_OPT_SCROLL_XY) { scroll_x = scroll_y = (touch->eevt & EVE_TOUCH_EETYPE_TRACK_XY); } else if (page->opt & EVE_PAGE_OPT_SCROLL_X) { scroll_x = (touch->eevt & EVE_TOUCH_EETYPE_TRACK_X); } else if (page->opt & EVE_PAGE_OPT_SCROLL_Y) { scroll_y = (touch->eevt & EVE_TOUCH_EETYPE_TRACK_Y); } scroll = scroll_x || scroll_y; if ((touch->tag0 == page->v.tag) && (evt & EVE_TOUCH_ETYPE_POINT_UP) && !(touch->eevt & (EVE_TOUCH_EETYPE_TRACK_XY | EVE_TOUCH_EETYPE_TRACK_ABORT))) { eve_page_set_focus(page, NULL); eve_view_uievt_push_gest(view, EVE_UIEVT_GEST_TOUCH, touch, evt); if (eve_window_dirty(window)) return 1; rv = 1; } /* Scroll / track start */ if (evt & EVE_TOUCH_ETYPE_TRACK_START) { if (page->track_mode == PAGE_TMODE_NONE) { if (scroll) { page->track_mode = PAGE_TMODE_SCROLL; eve_window_scroll_start(window, touch->tag0); eve_view_uievt_push_gest(view, EVE_UIEVT_GEST_SCROLL_START, touch, evt); } else { page->track_mode = PAGE_TMODE_TRACK; eve_view_uievt_push_gest(view, EVE_UIEVT_GEST_TRACK_START, touch, evt); } if (eve_window_dirty(window)) return 1; } if (scroll_x) { page->x0 = touch->x0 - page->g.x; } if (scroll_y) { page->y0 = touch->y0 - page->g.y; } rv = 1; } if ((evt & EVE_TOUCH_ETYPE_TRACK) && (page->track_mode == PAGE_TMODE_SCROLL)) { if (scroll_x) { page->g.x = touch->x - page->x0; } if (scroll_y) { page->g.y = touch->y - page->y0; } rv = 1; } /* Scroll / track 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_TRACK_ABORT) && !(touch->eevt & EVE_TOUCH_EETYPE_TRACK_XY))) { int start = 0; if ((page->track_mode == PAGE_TMODE_SCROLL) && (page->opt & EVE_PAGE_OPT_SCROLL_BACK)) { int min_gx, min_gy; int oob; oob = eve_page_oob(page, &min_gx, &min_gy); if (oob) { int pivot_x, pivot_y, x0, y0; int scroll_x, scroll_y; EVEPhyLHO *lho = &page->lho; uint8_t scroll_tag; pivot_x = touch->x0 - page->g.x + (page->g.x < min_gx ? min_gx : 0); pivot_y = touch->y0 - page->g.y + (page->g.y < min_gy ? min_gy : 0); x0 = touch->x0; y0 = touch->y0; scroll_x = page->opt & EVE_PAGE_OPT_SCROLL_X; scroll_y = page->opt & EVE_PAGE_OPT_SCROLL_Y; if (!scroll_x) pivot_x = x0; if (!scroll_y) pivot_y = y0; eve_window_scroll(window, &scroll_tag); start = eve_phy_lho_start(lho, pivot_x, pivot_y, x0, y0, eve_get_tick()); if (start) { eve_vtrack_start(lho, eve_phy_lho_tick, EVE_TOUCH_TIMEOUT_TRACK, touch, scroll_tag); } } } if (!start) { switch (page->track_mode) { case PAGE_TMODE_SCROLL: { page->track_mode = PAGE_TMODE_NONE; eve_window_scroll_stop(window); eve_view_uievt_push_gest(view, EVE_UIEVT_GEST_SCROLL_STOP, touch, evt); break; } case PAGE_TMODE_TRACK: { page->track_mode = PAGE_TMODE_NONE; eve_view_uievt_push_gest(view, EVE_UIEVT_GEST_TRACK_STOP, touch, evt); break; } } if (eve_window_dirty(window)) return 1; } rv = 1; } return rv; } uint8_t eve_page_draw(EVEPage *page, uint8_t tag0) { EVEView *view = &page->v; EVEWidget *widget = page->widget; int i; uint8_t tagN; uint8_t tag_opt; tag_opt = 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; iwidget_size; i++) { if (widget->flags & EVE_WIDGET_FLAG_HIDDEN) goto draw_nextw; 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); } draw_nextw: widget = eve_widget_next(widget); } eve_cmd_dl(RESTORE_CONTEXT()); for (i=tag0; iwidget; EVEWindow *window = page->v.window; int8_t touch_idx = eve_touch_get_idx(touch); uint16_t _evt; int i, rv; if (touch_idx > 0) return 0; _evt = eve_touch_evt(touch, evt, page->v.tag, 1); if (_evt) { rv = page_touch(page, touch, _evt); if (rv || eve_window_dirty(window)) return 1; } for (i=0; iwidget_size; i++) { if (!eve_page_rect_visible(page, &widget->g) || (widget->flags & (EVE_WIDGET_FLAG_SKIP | EVE_WIDGET_FLAG_RO | EVE_WIDGET_FLAG_HIDDEN))) goto touch_nextw; _evt = eve_touch_evt(touch, evt, widget->tag0, widget->tagN - widget->tag0); if (_evt) { if (page->track_mode == PAGE_TMODE_NONE) { rv = widget->touch(widget, touch, _evt); if (eve_window_dirty(window)) return 1; if (rv) { eve_page_set_focus(page, widget); return 1; } } rv = page_touch(page, touch, _evt); if (rv || eve_window_dirty(window)) return 1; } touch_nextw: widget = eve_widget_next(widget); } return 0; }