#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, EVEViewStack *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); page->stack = stack; page->opt = opt; page->destructor = destructor; eve_page_set_widget(page, widget, widget_size); } 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; } void eve_page_open(EVEPage *parent, eve_view_constructor_t constructor) { EVEWindow *window = parent->v.window; EVEViewStack *stack = parent->stack; eve_page_destructor_t destructor = parent->destructor; eve_page_set_focus(parent, NULL); if (destructor) destructor(parent); eve_stack_create_view(stack, window, constructor); } void eve_page_close(EVEPage *page) { EVEWindow *window = page->v.window; EVEViewStack *stack = page->stack; eve_page_destructor_t destructor = page->destructor; if (stack->level <= 1) return; eve_page_set_focus(page, NULL); if (eve_timer_running()) { eve_timer_stop(); } if (eve_window_scroll(window->root, NULL) == window) { eve_window_scroll_stop(window); } eve_window_kbd_detach(window); if (destructor) destructor(page); eve_stack_back(stack, window); } /* 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 *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_show_rect(EVEPage *page, EVERect *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); } } /* returns true if x or y are out of page bounds for window */ int eve_page_oob(EVEPage *page, int *_max_x, int *_max_y) { int max_x, max_y; EVERect vg; eve_window_visible_g(page->v.window, &vg); max_x = page->g.w > vg.w ? page->g.w - vg.w : 0; max_y = page->g.h > vg.h ? page->g.h - vg.h : 0; if (_max_x) *_max_x = max_x; if (_max_y) *_max_y = max_y; return ((page->g.x < 0) || (page->g.x > max_x) || (page->g.y < 0) || (page->g.y > max_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_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); if (!(widget_f && widget_f->putc)) eve_window_kbd_attach(window); } if (page->widget_f) eve_view_uievt_push(&page->v, EVE_UIEVT_WIDGET_FOCUS_OUT, page->widget_f); page->widget_f = widget; if (page->widget_f) eve_view_uievt_push(&page->v, EVE_UIEVT_WIDGET_FOCUS_IN, page->widget_f); } } static int page_touch(EVEPage *page, EVETouch *touch, uint16_t evt, uint8_t tag0) { EVEView *view = &page->v; EVEWindow *window = view->window; int scroll_x = 0, scroll_y = 0, scroll; int ret = 0; if (touch) { 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 ((evt & EVE_TOUCH_ETYPE_POINT_UP) && !(touch->eevt & (EVE_TOUCH_EETYPE_TRACK_XY | EVE_TOUCH_EETYPE_ABORT))) { int _ret = 0; eve_page_set_focus(page, NULL); _ret = eve_view_uievt_push_gest(view, EVE_UIEVT_GEST_TOUCH, touch, evt, tag0); if (_ret) return _ret; ret = 1; } /* Scroll / track 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_push_gest(view, EVE_UIEVT_GEST_SCROLL_START, touch, evt, tag0); } else { page->track_mode = PAGE_TMODE_TRACK; _ret = eve_view_uievt_push_gest(view, EVE_UIEVT_GEST_TRACK_START, touch, evt, tag0); } if (_ret) return _ret; ret = 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_ABORT) && !(touch->eevt & EVE_TOUCH_EETYPE_TRACK_XY))) { if ((page->track_mode == PAGE_TMODE_SCROLL) && (page->opt & EVE_PAGE_OPT_SCROLL_BACK)) { int max_x, max_y; int oob; oob = eve_page_oob(page, &max_x, &max_y); if (oob) { int lho_x, lho_y; uint8_t _tag; EVEPhyLHO *lho = &page->lho; lho_x = page->g.x < 0 ? 0 : max_x; lho_y = page->g.y < 0 ? 0 : max_y; eve_window_scroll(window->root, &_tag); page->lho_t0 = eve_get_tick(); eve_phy_lho_init(lho, lho_x, lho_y, 100, 0.5, 0); eve_phy_lho_start(lho, page->g.x, page->g.y); eve_timer_start(_tag, 20); } } if (!eve_timer_running()) { int _ret = 0; switch (page->track_mode) { case PAGE_TMODE_SCROLL: { page->track_mode = PAGE_TMODE_NONE; eve_window_scroll_stop(window); _ret = eve_view_uievt_push_gest(view, EVE_UIEVT_GEST_SCROLL_STOP, touch, evt, tag0); break; } case PAGE_TMODE_TRACK: { page->track_mode = PAGE_TMODE_NONE; _ret = eve_view_uievt_push_gest(view, EVE_UIEVT_GEST_TRACK_STOP, touch, evt, tag0); break; } } 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 (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 ((evt & EVE_TOUCH_ETYPE_TIMER) && (page->opt & EVE_PAGE_OPT_SCROLL_BACK)) { EVEPhyLHO *lho = &page->lho; int scroll_x = page->opt & EVE_PAGE_OPT_SCROLL_X; int scroll_y = page->opt & EVE_PAGE_OPT_SCROLL_Y; int x, y, more; more = eve_phy_lho_tick(lho, eve_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->track_mode = PAGE_TMODE_NONE; eve_timer_stop(); eve_window_scroll_stop(window); _ret = eve_view_uievt_push_gest(view, EVE_UIEVT_GEST_SCROLL_STOP, touch, evt, tag0); if (_ret) return _ret; } ret = 1; } } return ret; } uint8_t eve_page_draw(EVEPage *page, uint8_t tag0) { EVEView *view = &page->v; EVEWidget *widget = page->widget; int i; uint8_t tagN = tag0; uint8_t tag_opt; 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; 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; EVEViewStack *stack = page->stack; 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 (stack->dirty) { stack->dirty = 0; return 1; } if (ret) 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, tag0, widget->tag0, widget->tagN - widget->tag0); if (_evt) { if (page->track_mode == PAGE_TMODE_NONE) { ret = widget->touch(widget, touch, _evt); if (stack->dirty) { stack->dirty = 0; return 1; } if (ret) { eve_widget_set_focus(widget); return 1; } } ret = page_touch(page, touch, _evt, tag0); if (stack->dirty) { stack->dirty = 0; return 1; } if (ret) return 1; } touch_nextw: widget = eve_widget_next(widget); } return 0; }