diff --git a/demos/resource.c b/demos/resource.c index 4150df7fe..35f4b0f70 100644 --- a/demos/resource.c +++ b/demos/resource.c @@ -118,13 +118,13 @@ #include "res/inc/images/unchecked.data" #include "res/inc/images/unmuted.data" #include "res/inc/images/warn.data" -#endif/*WITH_STB_IMAGE*/ +#endif /*WITH_STB_IMAGE*/ #ifdef WITH_STB_FONT #include "res/inc/fonts/default.res" #else #include "res/inc/fonts/default.data" -#endif/*WITH_STB_FONT*/ -#endif/*WITH_FS_RES*/ +#endif /*WITH_STB_FONT*/ +#endif /*WITH_FS_RES*/ ret_t resource_init(void) { resource_manager_t* rm = resource_manager(); diff --git a/src/base/emitter.c b/src/base/emitter.c index dd982fa2a..b5cc51396 100644 --- a/src/base/emitter.c +++ b/src/base/emitter.c @@ -31,80 +31,86 @@ emitter_t* emitter_create() { emitter_t* emitter_init(emitter_t* emitter) { return_value_if_fail(emitter, NULL); + memset(emitter, 0x00, sizeof(emitter_t)); emitter->enable = TRUE; - emitter->curr_id = 1; + emitter->next_id = TK_INVALID_ID + 1; return emitter; } +static ret_t emitter_remove(emitter_t* emitter, emitter_item_t* prev, emitter_item_t* iter) { + return_value_if_fail(emitter != NULL && iter != NULL, RET_BAD_PARAMS); + + if (emitter->curr_iter == iter) { + emitter->remove_curr_iter = TRUE; + return RET_OK; + } + + if (iter == emitter->items) { + emitter->items = iter->next; + } else { + prev->next = iter->next; + } + + TKMEM_FREE(iter); + + return RET_OK; +} + ret_t emitter_dispatch(emitter_t* emitter, event_t* e) { + ret_t ret = RET_OK; return_value_if_fail(emitter != NULL && e != NULL, RET_BAD_PARAMS); if (!(e->time)) { e->time = time_now_ms(); } + if (e->target == NULL) { + e->target = emitter; + } + if (emitter->enable && emitter->items) { - uint32_t i = 0; - uint32_t size = emitter->size; - emitter_item_t* items = emitter->items; + emitter_item_t* iter = emitter->items; + emitter_item_t* prev = emitter->items; + + while (iter != NULL) { + emitter->curr_iter = iter; - emitter->stop = FALSE; - for (i = 0; i < size; i++) { - emitter_item_t* iter = items + i; if (iter->type == e->type) { - iter->handler(iter->ctx, e); + ret = iter->handler(iter->ctx, e); + if (ret == RET_STOP) { + return ret; + } else if (ret == RET_REMOVE || emitter->remove_curr_iter) { + emitter->curr_iter = NULL; + emitter->remove_curr_iter = FALSE; + emitter_remove(emitter, prev, iter); + } } - if (emitter->stop) { - break; - } + prev = iter; + iter = iter->next; } } + emitter->curr_iter = NULL; + emitter->remove_curr_iter = FALSE; return RET_OK; } -static ret_t emitter_extends(emitter_t* emitter, uint32_t nr) { - uint32_t capacity = 0; - emitter_item_t* items = NULL; - if (emitter->items && emitter->size < emitter->capacity) { - return RET_OK; - } - - if (emitter->items == NULL) { - emitter->items = TKMEM_ZALLOC(emitter_item_t); - return_value_if_fail(emitter->items != NULL, RET_FAIL); - - emitter->size = 0; - emitter->capacity = 1; - - return RET_OK; - } - - capacity = emitter->capacity + 5; - items = TKMEM_REALLOC(emitter_item_t, emitter->items, capacity); - return_value_if_fail(items != NULL, RET_FAIL); - - emitter->items = items; - emitter->capacity = capacity; - - return RET_OK; -} - -uint32_t emitter_on(emitter_t* emitter, uint16_t etype, event_func_t handler, void* ctx) { +uint32_t emitter_on(emitter_t* emitter, uint32_t etype, event_func_t handler, void* ctx) { emitter_item_t* iter = NULL; - return_value_if_fail(emitter != NULL && handler != NULL, 0); - return_value_if_fail(emitter_extends(emitter, 1) == RET_OK, 0); + return_value_if_fail(emitter != NULL && handler != NULL, TK_INVALID_ID); + + iter = TKMEM_ZALLOC(emitter_item_t); + return_value_if_fail(iter != NULL, TK_INVALID_ID); - iter = emitter->items + emitter->size; iter->type = etype; iter->ctx = ctx; iter->handler = handler; - iter->id = emitter->curr_id++; - - emitter->size++; + iter->id = emitter->next_id++; + iter->next = emitter->items; + emitter->items = iter; return iter->id; } @@ -113,76 +119,76 @@ emitter_item_t* emitter_find(emitter_t* emitter, uint32_t id) { return_value_if_fail(emitter != NULL, NULL); if (emitter->items) { - uint32_t i = 0; - uint32_t size = emitter->size; - emitter_item_t* items = emitter->items; + emitter_item_t* iter = emitter->items; - for (i = 0; i < size; i++) { - emitter_item_t* iter = items + i; + while (iter != NULL) { if (iter->id == id) { return iter; } + + iter = iter->next; } } return NULL; } +uint32_t emitter_size(emitter_t* emitter) { + uint32_t size = 0; + return_value_if_fail(emitter != NULL, size); + + if (emitter->items) { + emitter_item_t* iter = emitter->items; + + while (iter != NULL) { + size++; + iter = iter->next; + } + } + + return size; +} + ret_t emitter_off(emitter_t* emitter, uint32_t id) { return_value_if_fail(emitter != NULL, RET_BAD_PARAMS); if (emitter->items) { - uint32_t i = 0; - uint32_t size = emitter->size; - emitter_item_t* items = emitter->items; + emitter_item_t* iter = emitter->items; + emitter_item_t* prev = emitter->items; - for (i = 0; i < size; i++) { - emitter_item_t* iter = items + i; + while (iter != NULL) { if (iter->id == id) { - for (; i < (size - 1); i++) { - items[i] = items[i + 1]; - } - emitter->size--; - - return RET_OK; + return emitter_remove(emitter, prev, iter); } + + prev = iter; + iter = iter->next; } } return RET_FAIL; } -ret_t emitter_off_by_func(emitter_t* emitter, uint16_t etype, event_func_t handler, void* ctx) { +ret_t emitter_off_by_func(emitter_t* emitter, uint32_t etype, event_func_t handler, void* ctx) { return_value_if_fail(emitter != NULL && handler != NULL, RET_BAD_PARAMS); if (emitter->items) { - uint32_t i = 0; - uint32_t size = emitter->size; - emitter_item_t* items = emitter->items; + emitter_item_t* iter = emitter->items; + emitter_item_t* prev = emitter->items; - for (i = 0; i < size; i++) { - emitter_item_t* iter = items + i; + while (iter != NULL) { if (iter->type == etype && iter->ctx == ctx && iter->handler == handler) { - for (; i < (size - 1); i++) { - items[i] = items[i + 1]; - } - emitter->size--; - - return RET_OK; + return emitter_remove(emitter, prev, iter); } + + prev = iter; + iter = iter->next; } } return RET_FAIL; } -ret_t emitter_stop(emitter_t* emitter) { - return_value_if_fail(emitter != NULL, RET_BAD_PARAMS); - emitter->stop = TRUE; - - return RET_OK; -} - ret_t emitter_enable(emitter_t* emitter) { return_value_if_fail(emitter != NULL, RET_BAD_PARAMS); emitter->enable = TRUE; @@ -200,7 +206,15 @@ ret_t emitter_disable(emitter_t* emitter) { ret_t emitter_deinit(emitter_t* emitter) { return_value_if_fail(emitter != NULL, RET_BAD_PARAMS); if (emitter->items) { - TKMEM_FREE(emitter->items); + emitter_item_t* iter = emitter->items; + emitter_item_t* next = emitter->items; + + while (iter != NULL) { + next = iter->next; + TKMEM_FREE(iter); + iter = next; + } + emitter->items = NULL; } return RET_OK; diff --git a/src/base/emitter.h b/src/base/emitter.h index 98602a217..d1073cf8d 100644 --- a/src/base/emitter.h +++ b/src/base/emitter.h @@ -26,36 +26,175 @@ BEGIN_C_DECLS -typedef struct _emitter_item_t { - uint32_t id; - uint16_t type; - void* ctx; - event_func_t handler; -} emitter_item_t; +struct _emitter_item_t; +typedef struct _emitter_item_t emitter_item_t; +struct _emitter_item_t { + void* ctx; + uint32_t id; + uint32_t type; + event_func_t handler; + + emitter_item_t* next; +}; + +/** + * @class emitter_t + * @scriptable no + * 事件分发器, 用于实现观察者模式。 + */ typedef struct _emitter_t { - uint8_t size; - uint8_t capacity; - uint8_t stop; - uint8_t enable; + /** + * @property {emitter_item_t*} items + * @private + * 注册的回调函数集合。 + */ emitter_item_t* items; - uint32_t curr_id; + /** + * @property {uint32_t} next_id + * @private + * 下一次emitter_on返回的ID,emitter_on成功后会自动增加next_id。 + */ + uint32_t next_id; + /** + * @property {bool_t} enable + * @readonly + * 禁用标志。禁用时dispatch无效。 + */ + bool_t enable; + /** + * @property {bool_t} remove_curr_iter + * @private + * 如果在回调函数中,emitter_off当前正在dispatch的回调函数,我们只是设置remove_curr_iter为TRUE,在分发完成后才执行。 + * XXX: 如果要注销当前正在dispatch的回调函数,直接返回RET_REMOVE是最好的选择。 + */ + bool_t remove_curr_iter; + /** + * @property {emitter_item_t*} curr_iter + * @private + * 当前正在dispatch的项。 + */ + emitter_item_t* curr_iter; } emitter_t; +/** + * @method emitter_create + * @constructor + * 创建emitter对象。 + * + * @return {emitter_t*} 对象。 + */ emitter_t* emitter_create(void); + +/** + * @method emitter_init + * @constructor + * 初始化emitter对象。 + * @param {emitter_t*} emitter emitter对象。 + * + * @return {emitter_t*} 对象。 + */ emitter_t* emitter_init(emitter_t* emitter); + +/** + * @method emitter_dispatch + * 分发事件。如果当前分发的回调函数返回RET_REMOVE,该回调函数将被移出。 + * 禁用状态下,本函数不做任何事情。 + * @param {emitter_t*} emitter emitter对象。 + * @param {event_t*} e 事件对象。 + + * @return {ret_t} + 如果当前分发的回调函数返回RET_STOP,dispatch中断分发,并返回RET_STOP,否则返回RET_OK。 + */ ret_t emitter_dispatch(emitter_t* emitter, event_t* e); -uint32_t emitter_on(emitter_t* emitter, uint16_t etype, event_func_t handler, void* ctx); -ret_t emitter_off(emitter_t* emitter, uint32_t id); -emitter_item_t* emitter_find(emitter_t* emitter, uint32_t id); -ret_t emitter_off_by_func(emitter_t* emitter, uint16_t etype, event_func_t handler, void* ctx); +/** + * @method emitter_on + * 注册指定事件的处理函数。 + * @param {emitter_t*} emitter emitter对象。 + * @param {event_type_t} type 事件类型。 + * @param {event_func_t} on_event 事件处理函数。 + * @param {void*} ctx 事件处理函数上下文。 + * + * @return {uint32_t} 返回id,用于emitter_off。 + */ +uint32_t emitter_on(emitter_t* emitter, uint32_t etype, event_func_t handler, void* ctx); -ret_t emitter_stop(emitter_t* emitter); +/** + * @method emitter_off + * 注销指定事件的处理函数。 + * @param {emitter_t*} emitter emitter对象。 + * @param {uint32_t} id emitter_on返回的ID。 + * + * @return {ret_t} 返回RET_OK表示成功,否则表示失败。 + */ +ret_t emitter_off(emitter_t* emitter, uint32_t id); + +/** + * @method emitter_off_by_func + * 注销指定事件的处理函数。 + * @param {emitter_t*} emitter emitter对象。 + * @param {event_type_t} type 事件类型。 + * @param {event_func_t} on_event 事件处理函数。 + * @param {void*} ctx 事件处理函数上下文。 + * + * @return {ret_t} 返回RET_OK表示成功,否则表示失败。 + */ +ret_t emitter_off_by_func(emitter_t* emitter, uint32_t etype, event_func_t handler, void* ctx); + +/** + * @method emitter_find + * 通过ID查找emitter_item_t,主要用于辅助测试。 + * @param {emitter_t*} emitter emitter对象。 + * @param {uint32_t} id emitter_on返回的ID。 + * + * @return {ret_t} 返回RET_OK表示成功,否则表示失败。 + */ +emitter_item_t* emitter_find(emitter_t* emitter, uint32_t id); + +/** + * @method emitter_enable + * 启用。 + * @param {emitter_t*} emitter emitter对象。 + * + * @return {ret_t} 返回RET_OK表示成功,否则表示失败。 + */ ret_t emitter_enable(emitter_t* emitter); + +/** + * @method emitter_disable + * 禁用。禁用后emitter_dispatch无效,但可以注册和注销。 + * @param {emitter_t*} emitter emitter对象。 + * + * @return {ret_t} 返回RET_OK表示成功,否则表示失败。 + */ ret_t emitter_disable(emitter_t* emitter); +/** + * @method emitter_size + * 获取注册的回调函数个数,主要用于辅助测试。 + * @param {emitter_t*} emitter emitter对象。 + * + * @return {uint32_t} 回调函数个数。 + */ +uint32_t emitter_size(emitter_t* emitter); + +/** + * @method emitter_deinit + * 析构。 + * @param {emitter_t*} emitter emitter对象。 + * + * @return {ret_t} 返回RET_OK表示成功,否则表示失败。 + */ ret_t emitter_deinit(emitter_t* emitter); + +/** + * @method emitter_destroy + * 销毁。 + * @param {emitter_t*} emitter emitter对象。 + * + * @return {ret_t} 返回RET_OK表示成功,否则表示失败。 + */ ret_t emitter_destroy(emitter_t* emitter); END_C_DECLS diff --git a/src/base/types_def.h b/src/base/types_def.h index a1fa37479..d41225abc 100755 --- a/src/base/types_def.h +++ b/src/base/types_def.h @@ -94,6 +94,11 @@ typedef enum _ret_t { * 操作完成。 */ RET_DONE, + /** + * @const RET_STOP + * 停止后续操作。 + */ + RET_STOP, /** * @const RET_BAD_PARAMS * 无效参数。 @@ -236,5 +241,6 @@ typedef float float_t; #define TK_MAX_FPS 100 #define TK_OPACITY_ALPHA 0xfa #define TK_TRANSPARENT_ALPHA 0x05 +#define TK_INVALID_ID 0 #endif /*TYPES_DEF_H*/ diff --git a/src/window_animators/vtranslate.inc b/src/window_animators/vtranslate.inc old mode 100755 new mode 100644 index 4ad3fa2f9..fa59af454 --- a/src/window_animators/vtranslate.inc +++ b/src/window_animators/vtranslate.inc @@ -44,8 +44,8 @@ static ret_t window_animator_open_vtranslate_draw_curr(window_animator_t* wa) { #ifdef WITH_NANOVG vgcanvas_t* vg = lcd_get_vgcanvas(c->lcd); - vgcanvas_draw_image(vg, &(wa->curr_img), win->x*ratio, win->y*ratio, win->w * ratio, h * ratio, win->x, y, win->w, - h); + vgcanvas_draw_image(vg, &(wa->curr_img), win->x * ratio, win->y * ratio, win->w * ratio, + h * ratio, win->x, y, win->w, h); #else rect_t src; rect_t dst; diff --git a/tests/emitter_test.cc b/tests/emitter_test.cc index 0a6b2019e..648d79bc7 100644 --- a/tests/emitter_test.cc +++ b/tests/emitter_test.cc @@ -15,12 +15,37 @@ static ret_t on_event(void* ctx, event_t* e) { return RET_OK; } +static ret_t on_remove(void* ctx, event_t* e) { + uint32_t* p = (uint32_t*)ctx; + *p = *p + 1; + (void)e; + + return RET_REMOVE; +} + +static ret_t on_remove_id(void* ctx, event_t* e) { + uint32_t id = *((uint32_t*)ctx); + emitter_t* emitter = (emitter_t*)e->target; + + emitter_off(emitter, id); + + return RET_REMOVE; +} + +static ret_t on_stop(void* ctx, event_t* e) { + uint32_t* p = (uint32_t*)ctx; + *p = *p + 1; + (void)e; + + return RET_STOP; +} + TEST(Emitter, basic) { event_t e; uint32_t n = 0; emitter_t emitter; emitter_init(&emitter); - uint16_t type = 12; + uint32_t type = 12; e.type = type; ASSERT_EQ(emitter_on(NULL, type, on_event, NULL), 0); ASSERT_EQ(emitter_on(&emitter, type, NULL, NULL), 0); @@ -50,3 +75,106 @@ TEST(Emitter, basic) { emitter_deinit(&emitter); } + +TEST(Emitter, off) { + event_t e; + uint32_t n = 0; + uint32_t id = 0; + uint32_t type = 12; + emitter_t* emitter = emitter_create(); + + e.type = type; + + id = emitter_on(emitter, type, on_event, &n); + ASSERT_EQ(id > TK_INVALID_ID, true); + ASSERT_EQ(emitter_size(emitter), 1); + ASSERT_EQ(emitter_find(emitter, id) != NULL, true); + + ASSERT_EQ(emitter_off(emitter, id), RET_OK); + ASSERT_EQ(emitter_size(emitter), 0); + ASSERT_EQ(emitter_find(emitter, id) == NULL, true); + + id = emitter_on(emitter, type, on_event, &n); + ASSERT_EQ(id > TK_INVALID_ID, true); + ASSERT_EQ(emitter_size(emitter), 1); + ASSERT_EQ(emitter_find(emitter, id) != NULL, true); + + id = emitter_on(emitter, type, on_event, &n); + ASSERT_EQ(id > TK_INVALID_ID, true); + ASSERT_EQ(emitter_size(emitter), 2); + ASSERT_EQ(emitter_find(emitter, id) != NULL, true); + + ASSERT_EQ(emitter_off(emitter, id), RET_OK); + ASSERT_EQ(emitter_size(emitter), 1); + + emitter_destroy(emitter); +} + +TEST(Emitter, remove) { + event_t e; + uint32_t n = 0; + uint32_t id = 0; + uint32_t type = 12; + emitter_t* emitter = emitter_create(); + + e.type = type; + + id = emitter_on(emitter, type, on_remove, &n); + id = emitter_on(emitter, type, on_remove, &n); + id = emitter_on(emitter, type, on_remove, &n); + id = emitter_on(emitter, type, on_remove, &n); + + n = 0; + ASSERT_EQ(emitter_dispatch(emitter, &e), RET_OK); + ASSERT_EQ(emitter_size(emitter), 0); + ASSERT_EQ(n, 4); + + emitter_destroy(emitter); +} + +TEST(Emitter, stop) { + event_t e; + uint32_t n = 0; + uint32_t id = 0; + uint32_t type = 12; + emitter_t* emitter = emitter_create(); + + e.type = type; + + id = emitter_on(emitter, type, on_stop, &n); + id = emitter_on(emitter, type, on_stop, &n); + id = emitter_on(emitter, type, on_stop, &n); + id = emitter_on(emitter, type, on_stop, &n); + + n = 0; + ASSERT_EQ(emitter_size(emitter), 4); + ASSERT_EQ(emitter_dispatch(emitter, &e), RET_STOP); + ASSERT_EQ(emitter_size(emitter), 4); + ASSERT_EQ(n, 1); + + emitter_destroy(emitter); +} + +TEST(Emitter, remove_in_func) { + event_t e; + uint32_t n = 0; + uint32_t id1 = 0; + uint32_t id2 = 0; + uint32_t type = 12; + emitter_t* emitter = emitter_create(); + + e.type = type; + e.target = emitter; + + id1 = emitter_on(emitter, type, on_event, &n); + id2 = emitter_on(emitter, type, on_remove_id, &id1); + ASSERT_EQ(emitter_dispatch(emitter, &e), RET_OK); + ASSERT_EQ(emitter_size(emitter), 0); + + id1 = emitter_on(emitter, type, on_event, &n); + id2 = emitter_on(emitter, type, on_remove_id, &id2); + ASSERT_EQ(emitter_dispatch(emitter, &e), RET_OK); + ASSERT_EQ(emitter_size(emitter), 1); + + emitter_destroy(emitter); +}