make candidates scollable

This commit is contained in:
lixianjing 2019-05-30 16:24:04 +08:00
parent a4f349c414
commit 4a79ec7bd1
5 changed files with 446 additions and 4 deletions

View File

@ -3,6 +3,7 @@
* 增加颜色格式描述文档。
* FAQ增加半透明相关的问答。
* tab button放在scrollview中激活时自动滚动到可见区域。
* 候选字支持左右滚动。
* 2019/05/29
* 增加overlay窗口

327
src/base/hscrollable.c Normal file
View File

@ -0,0 +1,327 @@
/**
* File: hscrollable.c
* Author: AWTK Develop Team
* Brief: hscrollable
*
* Copyright (c) 2018 - 2019 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2019-05-30 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "tkc/mem.h"
#include "tkc/utf8.h"
#include "tkc/utils.h"
#include "base/hscrollable.h"
#include "base/widget_vtable.h"
#include "widget_animators/widget_animator_scroll.h"
static widget_t* hscrollable_get_widget(hscrollable_t* hscrollable) {
return hscrollable != NULL ? hscrollable->widget : NULL;
}
static ret_t hscrollable_invalidate_self(hscrollable_t* hscrollable) {
rect_t r;
widget_t* widget = hscrollable_get_widget(hscrollable);
return_value_if_fail(hscrollable != NULL && widget != NULL, RET_BAD_PARAMS);
widget->dirty = FALSE;
r = rect_init(widget->x, widget->y, widget->w, widget->h);
return widget_invalidate(widget->parent, &r);
}
static ret_t hscrollable_on_pointer_down(hscrollable_t* hscrollable, pointer_event_t* e) {
velocity_t* v = &(hscrollable->velocity);
velocity_reset(v);
hscrollable->down.x = e->x;
hscrollable->down.y = e->y;
hscrollable->xoffset_save = hscrollable->xoffset;
velocity_update(v, e->e.time, e->x, e->y);
return RET_OK;
}
static ret_t hscrollable_on_pointer_move(hscrollable_t* hscrollable, pointer_event_t* e) {
velocity_t* v = &(hscrollable->velocity);
int32_t dx = e->x - hscrollable->down.x;
velocity_update(v, e->e.time, e->x, e->y);
hscrollable->xoffset = hscrollable->xoffset_save - dx;
return RET_OK;
}
static ret_t hscrollable_on_scroll_done(void* ctx, event_t* e) {
hscrollable_t* hscrollable = (hscrollable_t*)(ctx);
return_value_if_fail(hscrollable != NULL, RET_BAD_PARAMS);
hscrollable->wa = NULL;
hscrollable_invalidate_self(hscrollable);
return RET_REMOVE;
}
static ret_t hscrollable_fix_end_offset_default(hscrollable_t* hscrollable) {
int32_t xoffset_end = 0;
widget_t* widget = hscrollable_get_widget(hscrollable);
return_value_if_fail(hscrollable != NULL && widget != NULL, RET_BAD_PARAMS);
xoffset_end = hscrollable->xoffset_end;
xoffset_end = tk_max(xoffset_end, 0);
xoffset_end = tk_min(xoffset_end, (hscrollable->virtual_w - widget->w));
if (hscrollable->virtual_w <= widget->w) {
xoffset_end = 0;
}
hscrollable->xoffset_end = xoffset_end;
return RET_OK;
}
ret_t hscrollable_scroll_to(hscrollable_t* hscrollable, int32_t xoffset_end, int32_t duration) {
int32_t xoffset = 0;
widget_t* widget = hscrollable_get_widget(hscrollable);
return_value_if_fail(hscrollable != NULL && widget != NULL, RET_FAIL);
hscrollable_fix_end_offset_default(hscrollable);
xoffset_end = hscrollable->xoffset_end;
xoffset = hscrollable->xoffset;
if (xoffset == xoffset_end) {
return RET_OK;
}
hscrollable->xoffset_end = xoffset_end;
xoffset_end = hscrollable->xoffset_end;
hscrollable->wa = widget_animator_scroll_create(widget, TK_ANIMATING_TIME, 0, EASING_SIN_INOUT);
return_value_if_fail(hscrollable->wa != NULL, RET_OOM);
widget_animator_scroll_set_params(hscrollable->wa, xoffset, 0, xoffset_end, 0);
widget_animator_on(hscrollable->wa, EVT_ANIM_END, hscrollable_on_scroll_done, hscrollable);
widget_animator_start(hscrollable->wa);
return RET_OK;
}
#define SPEED_SCALE 2
#define MIN_DELTA 10
static ret_t hscrollable_on_pointer_up(hscrollable_t* hscrollable, pointer_event_t* e) {
velocity_t* v = &(hscrollable->velocity);
int32_t move_dx = e->x - hscrollable->down.x;
velocity_update(v, e->e.time, e->x, e->y);
if (move_dx) {
int xv = tk_min(v->xv, 100);
hscrollable->xoffset_end = hscrollable->xoffset - xv;
hscrollable_scroll_to(hscrollable, hscrollable->xoffset_end, 300);
}
return RET_OK;
}
ret_t hscrollable_on_event(hscrollable_t* hscrollable, event_t* e) {
ret_t ret = RET_OK;
uint16_t type = e->type;
widget_t* widget = hscrollable_get_widget(hscrollable);
return_value_if_fail(hscrollable != NULL && widget != NULL && e != NULL, RET_BAD_PARAMS);
if (hscrollable->wa != NULL) {
log_debug("animating ignore event\n");
return RET_STOP;
}
switch (type) {
case EVT_POINTER_DOWN:
hscrollable->dragged = FALSE;
widget_grab(widget->parent, widget);
hscrollable_on_pointer_down(hscrollable, (pointer_event_t*)e);
break;
case EVT_POINTER_UP: {
pointer_event_t* evt = (pointer_event_t*)e;
int32_t dx = evt->x - hscrollable->down.x;
if (dx) {
hscrollable_on_pointer_up(hscrollable, (pointer_event_t*)e);
}
hscrollable->dragged = FALSE;
widget_ungrab(widget->parent, widget);
break;
}
case EVT_POINTER_MOVE: {
pointer_event_t* evt = (pointer_event_t*)e;
if (!evt->pressed) {
break;
}
if (hscrollable->dragged) {
hscrollable_on_pointer_move(hscrollable, evt);
hscrollable_invalidate_self(hscrollable);
} else {
int32_t delta = evt->x - hscrollable->down.x;
if (tk_abs(delta) >= TK_DRAG_THRESHOLD) {
pointer_event_t abort = *evt;
abort.e.type = EVT_POINTER_DOWN_ABORT;
widget_dispatch_event_to_target_recursive(widget, (event_t*)(&abort));
hscrollable->dragged = TRUE;
}
}
ret = hscrollable->dragged ? RET_STOP : RET_OK;
break;
}
default:
break;
}
return ret;
}
ret_t hscrollable_invalidate(hscrollable_t* hscrollable, rect_t* r) {
rect_t r_self;
widget_t* widget = hscrollable_get_widget(hscrollable);
return_value_if_fail(hscrollable != NULL && widget != NULL, RET_BAD_PARAMS);
r_self = rect_init(0, 0, widget->w, widget->h);
r->x += widget->x;
r->x -= hscrollable->xoffset;
*r = rect_intersect(r, &r_self);
if (r->w <= 0 || r->h <= 0) {
return RET_OK;
}
if (widget->parent) {
widget_invalidate(widget->parent, r);
}
return RET_OK;
}
ret_t hscrollable_on_paint_children(hscrollable_t* hscrollable, canvas_t* c) {
rect_t r_save;
widget_t* widget = hscrollable_get_widget(hscrollable);
return_value_if_fail(hscrollable != NULL && c != NULL && widget != NULL, RET_BAD_PARAMS);
rect_t r = rect_init(c->ox, c->oy, widget->w, widget->h);
int32_t xoffset = -hscrollable->xoffset;
canvas_translate(c, xoffset, 0);
canvas_get_clip_rect(c, &r_save);
r = rect_intersect(&r, &r_save);
canvas_set_clip_rect(c, &r);
widget_on_paint_children_default(widget, c);
canvas_set_clip_rect(c, &r_save);
canvas_untranslate(c, xoffset, 0);
return RET_OK;
}
ret_t hscrollable_get_prop(hscrollable_t* hscrollable, const char* name, value_t* v) {
widget_t* widget = hscrollable_get_widget(hscrollable);
return_value_if_fail(widget != NULL && hscrollable != NULL && name != NULL && v != NULL,
RET_BAD_PARAMS);
if (tk_str_eq(name, WIDGET_PROP_VIRTUAL_W) || tk_str_eq(name, WIDGET_PROP_LAYOUT_W)) {
value_set_int(v, tk_max(widget->w, hscrollable->virtual_w));
return RET_OK;
} else if (tk_str_eq(name, WIDGET_PROP_VIRTUAL_H) || tk_str_eq(name, WIDGET_PROP_LAYOUT_H)) {
value_set_int(v, widget->h);
return RET_OK;
} else if (tk_str_eq(name, WIDGET_PROP_XOFFSET)) {
value_set_int(v, hscrollable->xoffset);
return RET_OK;
} else if (tk_str_eq(name, WIDGET_PROP_YOFFSET)) {
value_set_int(v, 0);
return RET_OK;
} else if (tk_str_eq(name, WIDGET_PROP_XSLIDABLE)) {
value_set_bool(v, TRUE);
return RET_OK;
} else if (tk_str_eq(name, WIDGET_PROP_YSLIDABLE)) {
value_set_bool(v, FALSE);
return RET_OK;
}
return RET_NOT_FOUND;
}
ret_t hscrollable_set_prop(hscrollable_t* hscrollable, const char* name, const value_t* v) {
return_value_if_fail(hscrollable != NULL && name != NULL && v != NULL, RET_BAD_PARAMS);
if (tk_str_eq(name, WIDGET_PROP_VIRTUAL_W)) {
hscrollable->virtual_w = value_int(v);
return RET_OK;
} else if (tk_str_eq(name, WIDGET_PROP_XSLIDABLE)) {
return RET_OK;
} else if (tk_str_eq(name, WIDGET_PROP_XOFFSET)) {
hscrollable->xoffset = value_int(v);
hscrollable_invalidate_self(hscrollable);
return RET_OK;
} else if (tk_str_eq(name, WIDGET_PROP_YOFFSET)) {
return RET_OK;
}
return RET_NOT_FOUND;
}
hscrollable_t* hscrollable_create(widget_t* widget) {
hscrollable_t* hscrollable = NULL;
return_value_if_fail(widget != NULL, NULL);
hscrollable = TKMEM_ZALLOC(hscrollable_t);
return_value_if_fail(hscrollable != NULL, NULL);
hscrollable->widget = widget;
return hscrollable;
}
ret_t hscrollable_set_always_scrollable(hscrollable_t* hscrollable, bool_t always_scrollable) {
return_value_if_fail(hscrollable != NULL, RET_BAD_PARAMS);
hscrollable->always_scrollable = always_scrollable;
return RET_OK;
}
ret_t hscrollable_set_xoffset(hscrollable_t* hscrollable, int32_t xoffset) {
return_value_if_fail(hscrollable != NULL, RET_BAD_PARAMS);
hscrollable->xoffset = xoffset;
return RET_OK;
}
ret_t hscrollable_set_virtual_w(hscrollable_t* hscrollable, int32_t virtual_w) {
return_value_if_fail(hscrollable != NULL, RET_BAD_PARAMS);
hscrollable->virtual_w = virtual_w;
return RET_OK;
}
ret_t hscrollable_destroy(hscrollable_t* hscrollable) {
return_value_if_fail(hscrollable != NULL, RET_BAD_PARAMS);
TKMEM_FREE(hscrollable);
return RET_OK;
}

65
src/base/hscrollable.h Normal file
View File

@ -0,0 +1,65 @@
/**
* File: hscrollable.h
* Author: AWTK Develop Team
* Brief: input method text hscrollable
*
* Copyright (c) 2018 - 2019 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2019-05-30 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_HSCROLLABLE_H
#define TK_HSCROLLABLE_H
#include "tkc/str.h"
#include "base/widget.h"
#include "base/velocity.h"
#include "base/widget_animator.h"
BEGIN_C_DECLS
/**
* @class hscrollable_t
*
*/
typedef struct _hscrollable_t {
point_t down;
bool_t dragged;
int32_t xoffset;
int32_t xoffset_end;
int32_t xoffset_save;
int32_t virtual_w;
widget_t* widget;
velocity_t velocity;
widget_animator_t* wa;
bool_t always_scrollable;
} hscrollable_t;
hscrollable_t* hscrollable_create(widget_t* widget);
ret_t hscrollable_set_xoffset(hscrollable_t* hscrollable, int32_t xoffset);
ret_t hscrollable_set_virtual_w(hscrollable_t* hscrollable, int32_t virtual_w);
ret_t hscrollable_set_always_scrollable(hscrollable_t* hscrollable, bool_t always_scrollable);
ret_t hscrollable_invalidate(hscrollable_t* hscrollable, rect_t* r);
ret_t hscrollable_on_event(hscrollable_t* hscrollable, event_t* e);
ret_t hscrollable_get_prop(hscrollable_t* hscrollable, const char* name, value_t* v);
ret_t hscrollable_set_prop(hscrollable_t* hscrollable, const char* name, const value_t* v);
ret_t hscrollable_on_paint_children(hscrollable_t* hscrollable, canvas_t* c);
ret_t hscrollable_destroy(hscrollable_t* hscrollable);
END_C_DECLS
#endif /*TK_HSCROLLABLE_H*/

View File

@ -104,17 +104,19 @@ static ret_t candidates_relayout_children(widget_t* widget) {
for (i = 0; i < nr; i++) {
iter = children[i];
child_w = candidates_calc_child_width(candidates->canvas, iter);
if ((child_x + child_w + margin) < w && iter->text.size > 0) {
if (iter->text.size) {
widget_set_visible(iter, TRUE, FALSE);
widget_move_resize(iter, child_x, child_y, child_w, child_h);
} else {
child_w = 0;
widget_set_visible(iter, FALSE, FALSE);
widget_move_resize(iter, 0, 0, 0, 0);
}
widget_move_resize(iter, child_x, child_y, child_w, child_h);
child_x += child_w + margin;
}
hscrollable_set_xoffset(candidates->hscrollable, 0);
hscrollable_set_virtual_w(candidates->hscrollable, child_x);
return RET_OK;
}
@ -150,6 +152,7 @@ static ret_t candidates_on_destroy_default(widget_t* widget) {
candidates_t* candidates = CANDIDATES(widget);
return_value_if_fail(widget != NULL && candidates != NULL, RET_BAD_PARAMS);
hscrollable_destroy(candidates->hscrollable);
input_method_off(input_method(), candidates->event_id);
return RET_OK;
@ -163,11 +166,52 @@ static ret_t candidates_on_paint_self(widget_t* widget, canvas_t* c) {
return widget_paint_helper(widget, c, NULL, NULL);
}
static ret_t candidates_on_event(widget_t* widget, event_t* e) {
candidates_t* candidates = CANDIDATES(widget);
return_value_if_fail(candidates != NULL, RET_BAD_PARAMS);
return hscrollable_on_event(candidates->hscrollable, e);
}
static ret_t candidates_invalidate(widget_t* widget, rect_t* r) {
candidates_t* candidates = CANDIDATES(widget);
return_value_if_fail(candidates != NULL, RET_BAD_PARAMS);
return hscrollable_invalidate(candidates->hscrollable, r);
}
static ret_t candidates_on_paint_children(widget_t* widget, canvas_t* c) {
candidates_t* candidates = CANDIDATES(widget);
return_value_if_fail(candidates != NULL, RET_BAD_PARAMS);
return hscrollable_on_paint_children(candidates->hscrollable, c);
}
static ret_t candidates_get_prop(widget_t* widget, const char* name, value_t* v) {
candidates_t* candidates = CANDIDATES(widget);
return_value_if_fail(candidates != NULL, RET_BAD_PARAMS);
return hscrollable_get_prop(candidates->hscrollable, name, v);
}
static ret_t candidates_set_prop(widget_t* widget, const char* name, const value_t* v) {
candidates_t* candidates = CANDIDATES(widget);
return_value_if_fail(candidates != NULL, RET_BAD_PARAMS);
return hscrollable_set_prop(candidates->hscrollable, name, v);
}
TK_DECL_VTABLE(candidates) = {.size = sizeof(candidates_t),
.scrollable = TRUE,
.type = WIDGET_TYPE_CANDIDATES,
.parent = TK_PARENT_VTABLE(widget),
.create = candidates_create,
.on_event = candidates_on_event,
.invalidate = candidates_invalidate,
.on_paint_self = candidates_on_paint_self,
.on_paint_children = candidates_on_paint_children,
.get_prop = candidates_get_prop,
.set_prop = candidates_set_prop,
.on_destroy = candidates_on_destroy_default};
static ret_t candidates_on_im_candidates_event(void* ctx, event_t* e) {
@ -182,9 +226,12 @@ widget_t* candidates_create(widget_t* parent, xy_t x, xy_t y, wh_t w, wh_t h) {
candidates_t* candidates = CANDIDATES(widget);
return_value_if_fail(candidates != NULL, NULL);
candidates->hscrollable = hscrollable_create(widget);
candidates->event_id = input_method_on(input_method(), EVT_IM_SHOW_CANDIDATES,
candidates_on_im_candidates_event, candidates);
ENSURE(candidates->hscrollable != NULL);
return widget;
}

View File

@ -24,6 +24,7 @@
#include "tkc/str.h"
#include "base/widget.h"
#include "base/hscrollable.h"
BEGIN_C_DECLS
@ -41,6 +42,7 @@ typedef struct _candidates_t {
wh_t normal_h;
uint32_t event_id;
canvas_t* canvas;
hscrollable_t* hscrollable;
} candidates_t;
/**