From a42b8f06691d177248816344833aad792d75f304 Mon Sep 17 00:00:00 2001 From: xianjimli Date: Sun, 1 Jul 2018 11:56:06 +0800 Subject: [PATCH] add dragger --- demos/res/raw/ui/dragger.xml | 11 +++ demos/resource.c | 12 +-- src/base/dragger.c | 173 +++++++++++++++++++++++++++++++++++ src/base/dragger.h | 80 ++++++++++++++++ src/base/enums.c | 1 + src/base/events.h | 16 ++++ src/base/widget_consts.h | 16 +++- src/base/widget_factory.c | 2 + tests/dragger_test.cc | 117 +++++++++++++++++++++++ 9 files changed, 419 insertions(+), 9 deletions(-) create mode 100644 demos/res/raw/ui/dragger.xml create mode 100644 src/base/dragger.c create mode 100644 src/base/dragger.h create mode 100644 tests/dragger_test.cc diff --git a/demos/res/raw/ui/dragger.xml b/demos/res/raw/ui/dragger.xml new file mode 100644 index 000000000..8c62db1d0 --- /dev/null +++ b/demos/res/raw/ui/dragger.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/demos/resource.c b/demos/resource.c index e4d2c7ca9..840ed3b2b 100644 --- a/demos/resource.c +++ b/demos/resource.c @@ -161,17 +161,17 @@ #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 #ifdef WITH_MINI_FONT #include "res/inc/fonts/default.mini.res" -#else/*WITH_MINI_FONT*/ +#else /*WITH_MINI_FONT*/ #include "res/inc/fonts/default.res" -#endif/*WITH_MINI_FONT*/ -#else/*WITH_STB_FONT*/ +#endif /*WITH_MINI_FONT*/ +#else /*WITH_STB_FONT*/ #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/dragger.c b/src/base/dragger.c new file mode 100644 index 000000000..a0decce50 --- /dev/null +++ b/src/base/dragger.c @@ -0,0 +1,173 @@ +/** + * File: dragger.h + * Author: AWTK Develop Team + * Brief: dragger + * + * Copyright (c) 2018 - 2018 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: + * ================================================================ + * 2018-01-28 Li XianJing created + * + */ + +#include "base/mem.h" +#include "base/utils.h" +#include "base/dragger.h" + +static ret_t dragger_on_paint_self(widget_t* widget, canvas_t* c) { + return widget_paint_helper(widget, c, NULL, NULL); +} + +static ret_t dragger_move(widget_t* widget, xy_t dx, xy_t dy) { + dragger_t* dragger = DRAGGER(widget); + xy_t x = dragger->save_x + dx; + xy_t y = dragger->save_y + dy; + + x = tk_max(x, dragger->x_min); + y = tk_max(y, dragger->y_min); + x = tk_min(x, dragger->x_max); + y = tk_min(y, dragger->y_max); + + if (x != widget->x || y != widget->y) { + event_t evt = event_init(EVT_DRAG, widget); + widget_move(widget, x, y); + widget_dispatch(widget, (event_t*)&evt); + } + + return RET_OK; +} + +static ret_t dragger_on_event(widget_t* widget, event_t* e) { + uint16_t type = e->type; + dragger_t* dragger = DRAGGER(widget); + + switch (type) { + case EVT_POINTER_DOWN: { + pointer_event_t* pointer_event = (pointer_event_t*)e; + event_t evt = event_init(EVT_DRAG_START, widget); + widget_set_state(widget, WIDGET_STATE_PRESSED); + widget_dispatch(widget, (event_t*)&evt); + widget_grab(widget->parent, widget); + + dragger->down_x = pointer_event->x; + dragger->down_y = pointer_event->y; + dragger->save_x = widget->x; + dragger->save_y = widget->y; + dragger_move(widget, 0, 0); + dragger->dragging = TRUE; + break; + } + case EVT_POINTER_UP: { + pointer_event_t* pointer_event = (pointer_event_t*)e; + event_t evt = event_init(EVT_DRAG_END, widget); + dragger_move(widget, pointer_event->x - dragger->down_x, pointer_event->y - dragger->down_y); + widget_set_state(widget, WIDGET_STATE_NORMAL); + widget_dispatch(widget, (event_t*)&evt); + widget_ungrab(widget->parent, widget); + dragger->dragging = FALSE; + break; + } + case EVT_POINTER_MOVE: { + if (dragger->dragging) { + pointer_event_t* pointer_event = (pointer_event_t*)e; + dragger_move(widget, pointer_event->x - dragger->down_x, + pointer_event->y - dragger->down_y); + } + break; + } + case EVT_POINTER_LEAVE: + widget_set_state(widget, WIDGET_STATE_NORMAL); + break; + case EVT_POINTER_ENTER: + widget_set_state(widget, WIDGET_STATE_OVER); + break; + default: + break; + } + + return RET_OK; +} + +ret_t dragger_set_range(widget_t* widget, xy_t x_min, xy_t y_min, xy_t x_max, xy_t y_max) { + dragger_t* dragger = DRAGGER(widget); + return_value_if_fail(widget != NULL && x_min <= x_max && y_min <= y_max, RET_BAD_PARAMS); + + dragger->x_min = x_min; + dragger->x_max = x_max; + dragger->y_min = y_min; + dragger->y_max = y_max; + + return RET_OK; +} + +static ret_t dragger_get_prop(widget_t* widget, const char* name, value_t* v) { + dragger_t* dragger = DRAGGER(widget); + return_value_if_fail(widget != NULL && name != NULL && v != NULL, RET_BAD_PARAMS); + + if (tk_str_eq(name, WIDGET_PROP_X_MIN)) { + value_set_int(v, dragger->x_min); + return RET_OK; + } else if (tk_str_eq(name, WIDGET_PROP_X_MAX)) { + value_set_int(v, dragger->x_max); + return RET_OK; + } else if (tk_str_eq(name, WIDGET_PROP_Y_MIN)) { + value_set_int(v, dragger->y_min); + return RET_OK; + } else if (tk_str_eq(name, WIDGET_PROP_Y_MAX)) { + value_set_int(v, dragger->y_max); + return RET_OK; + } + + return RET_NOT_FOUND; +} + +static ret_t dragger_set_prop(widget_t* widget, const char* name, const value_t* v) { + dragger_t* dragger = DRAGGER(widget); + return_value_if_fail(widget != NULL && name != NULL && v != NULL, RET_BAD_PARAMS); + + if (tk_str_eq(name, WIDGET_PROP_X_MIN)) { + dragger->x_min = value_int(v); + return RET_OK; + } else if (tk_str_eq(name, WIDGET_PROP_X_MAX)) { + dragger->x_max = value_int(v); + return RET_OK; + } else if (tk_str_eq(name, WIDGET_PROP_Y_MIN)) { + dragger->y_min = value_int(v); + return RET_OK; + } else if (tk_str_eq(name, WIDGET_PROP_Y_MAX)) { + dragger->y_max = value_int(v); + return RET_OK; + } + + return RET_NOT_FOUND; +} + +static const widget_vtable_t s_dragger_vtable = {.type_name = WIDGET_TYPE_DRAGGER, + .set_prop = dragger_set_prop, + .get_prop = dragger_get_prop, + .on_event = dragger_on_event, + .on_paint_self = dragger_on_paint_self}; + +widget_t* dragger_create(widget_t* parent, xy_t x, xy_t y, wh_t w, wh_t h) { + widget_t* widget = NULL; + dragger_t* dragger = TKMEM_ZALLOC(dragger_t); + return_value_if_fail(dragger != NULL, NULL); + + widget = WIDGET(dragger); + widget->vt = &s_dragger_vtable; + widget_init(widget, parent, WIDGET_DRAGGER); + widget_move_resize(widget, x, y, w, h); + + widget_set_state(widget, WIDGET_STATE_NORMAL); + + return widget; +} diff --git a/src/base/dragger.h b/src/base/dragger.h new file mode 100644 index 000000000..0abfaa5a4 --- /dev/null +++ b/src/base/dragger.h @@ -0,0 +1,80 @@ +/** + * File: dragger.h + * Author: AWTK Develop Team + * Brief: dragger + * + * Copyright (c) 2018 - 2018 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: + * ================================================================ + * 2018-07-01 Li XianJing created + * + */ + +#ifndef TK_DRAGGER_H +#define TK_DRAGGER_H + +#include "base/widget.h" + +BEGIN_C_DECLS + +/** + * @class dragger_t + * @parent widget_t + * @scriptable + * dragger控件。 + */ +typedef struct _dragger_t { + widget_t widget; + xy_t x_min; + xy_t y_min; + xy_t x_max; + xy_t y_max; + + xy_t save_x; + xy_t save_y; + xy_t down_x; + xy_t down_y; + bool_t dragging; +} dragger_t; + +/** + * @method dragger_create + * @constructor + * 创建dragger对象 + * @param {widget_t*} parent 父控件 + * @param {xy_t} x x坐标 + * @param {xy_t} y y坐标 + * @param {wh_t} w 宽度 + * @param {wh_t} h 高度 + * + * @return {widget_t*} 对象。 + */ +widget_t* dragger_create(widget_t* parent, xy_t x, xy_t y, wh_t w, wh_t h); + +/** + * @method dragger_set_range + * 创建dragger对象 + * @param {widget_t*} widget dragger控件。 + * @param {xy_t} x_min x坐标最小值。 + * @param {xy_t} y_min y坐标最小值。 + * @param {xy_t} x_max x坐标最大值。 + * @param {xy_t} y_max y坐标最大值。 + * + * @return {widget_t*} 对象。 + */ +ret_t dragger_set_range(widget_t* widget, xy_t x_min, xy_t y_min, xy_t x_max, xy_t y_max); + +#define DRAGGER(widget) ((dragger_t*)(widget)) + +END_C_DECLS + +#endif /*TK_DRAGGER_H*/ diff --git a/src/base/enums.c b/src/base/enums.c index 58dbe08d0..0b3bcfa2d 100644 --- a/src/base/enums.c +++ b/src/base/enums.c @@ -34,6 +34,7 @@ static const key_type_value_t widget_type_value[] = { {WIDGET_TYPE_POPUP, 0, WIDGET_POPUP}, {WIDGET_TYPE_SPRITE, 0, WIDGET_SPRITE}, {WIDGET_TYPE_KEYBOARD, 0, WIDGET_KEYBOARD}, + {WIDGET_TYPE_DND, 0, WIDGET_DND}, {WIDGET_TYPE_DRAGGER, 0, WIDGET_DRAGGER}, {WIDGET_TYPE_LABEL, 0, WIDGET_LABEL}, {WIDGET_TYPE_BUTTON, 0, WIDGET_BUTTON}, diff --git a/src/base/events.h b/src/base/events.h index 99ed7c55e..a88d0fadd 100644 --- a/src/base/events.h +++ b/src/base/events.h @@ -201,6 +201,22 @@ typedef enum _event_type_t { * 请求更新软键盘上的Action按钮的信息。 */ EVT_IM_ACTION_INFO, + /** + * @const EVT_DRAG_START + * 开始拖动。 + */ + EVT_DRAG_START, + /** + * @const EVT_DRAG + * 拖动。 + */ + EVT_DRAG, + /** + * @const EVT_DRAG_END + * 结束拖动。 + */ + EVT_DRAG_END, + /** * @const EVT_REQ_START * event queue其它请求编号起始值。 diff --git a/src/base/widget_consts.h b/src/base/widget_consts.h index c7c12542a..391d91579 100644 --- a/src/base/widget_consts.h +++ b/src/base/widget_consts.h @@ -59,6 +59,10 @@ BEGIN_C_DECLS #define WIDGET_PROP_YOFFSET "yoffset" #define WIDGET_PROP_AUTO_PLAY "auto_play" #define WIDGET_PROP_AUTO_FIX "auto_fix" +#define WIDGET_PROP_X_MIN "x_min" +#define WIDGET_PROP_X_MAX "x_max" +#define WIDGET_PROP_Y_MIN "y_min" +#define WIDGET_PROP_Y_MAX "y_max" /*widget type name*/ #define WIDGET_TYPE_NONE "widget" @@ -69,7 +73,7 @@ BEGIN_C_DECLS #define WIDGET_TYPE_POPUP "popup" #define WIDGET_TYPE_SPRITE "sprite" #define WIDGET_TYPE_KEYBOARD "keyboard" -#define WIDGET_TYPE_DRAGGER "dragger" +#define WIDGET_TYPE_DND "dnd" #define WIDGET_TYPE_LABEL "label" #define WIDGET_TYPE_BUTTON "button" #define WIDGET_TYPE_IMAGE "image" @@ -86,6 +90,7 @@ BEGIN_C_DECLS #define WIDGET_TYPE_PAGES "pages" #define WIDGET_TYPE_CANDIDATES "candidates" #define WIDGET_TYPE_SPIN_BOX "spin_box" +#define WIDGET_TYPE_DRAGGER "dragger" /** * @enum widget_type_t @@ -134,10 +139,10 @@ typedef enum _widget_type_t { */ WIDGET_KEYBOARD, /** - * @const WIDGET_DRAGGER + * @const WIDGET_DND * drag & drop icon。 */ - WIDGET_DRAGGER, + WIDGET_DND, /** * @const WIDGET_LABEL * 简单文本。 @@ -218,6 +223,11 @@ typedef enum _widget_type_t { * Spin Box。 */ WIDGET_SPIN_BOX, + /** + * @const WIDGET_DRAGGER + * DRAGGER。 + */ + WIDGET_DRAGGER, WIDGET_NR, WIDGET_USER_START = 100 diff --git a/src/base/widget_factory.c b/src/base/widget_factory.c index 6c46bb809..8614d4d1c 100644 --- a/src/base/widget_factory.c +++ b/src/base/widget_factory.c @@ -31,6 +31,7 @@ #include "base/edit.h" #include "base/pages.h" #include "base/view.h" +#include "base/dragger.h" #include "base/keyboard.h" #include "base/candidates.h" #include "base/spin_box.h" @@ -62,6 +63,7 @@ static const creator_item_t s_builtin_creators[] = { {WIDGET_TYPE_RADIO_BUTTON, check_button_create_radio}, {WIDGET_TYPE_PAGES, pages_create}, {WIDGET_TYPE_SPIN_BOX, spin_box_create}, + {WIDGET_TYPE_DRAGGER, dragger_create}, #ifndef WITH_LOW_RES {WIDGET_TYPE_SLIDE_VIEW, slide_view_create}, diff --git a/tests/dragger_test.cc b/tests/dragger_test.cc new file mode 100644 index 000000000..66fcc1227 --- /dev/null +++ b/tests/dragger_test.cc @@ -0,0 +1,117 @@ +#include "base/dragger.h" +#include "base/canvas.h" +#include "base/widget.h" +#include "font_dummy.h" +#include "lcd_log.h" +#include "gtest/gtest.h" +#include + +TEST(Dragger, basic) { + value_t v1; + value_t v2; + widget_t* b = dragger_create(NULL, 0, 0, 30, 30); + dragger_t* dragger = DRAGGER(b); + + ASSERT_EQ(dragger_set_range(b, 0, 100, 100, 200), RET_OK); + ASSERT_EQ(widget_get_prop(b, WIDGET_PROP_X_MIN, &v2), RET_OK); + ASSERT_EQ(0, value_int(&v2)); + ASSERT_EQ(widget_get_prop(b, WIDGET_PROP_Y_MIN, &v2), RET_OK); + ASSERT_EQ(100, value_int(&v2)); + + ASSERT_EQ(widget_get_prop(b, WIDGET_PROP_X_MAX, &v2), RET_OK); + ASSERT_EQ(100, value_int(&v2)); + ASSERT_EQ(widget_get_prop(b, WIDGET_PROP_Y_MAX, &v2), RET_OK); + ASSERT_EQ(200, value_int(&v2)); + + value_set_int(&v1, 1); + ASSERT_EQ(widget_set_prop(b, WIDGET_PROP_X_MIN, &v1), RET_OK); + ASSERT_EQ(dragger->x_min, 1); + + value_set_int(&v1, 2); + ASSERT_EQ(widget_set_prop(b, WIDGET_PROP_X_MAX, &v1), RET_OK); + ASSERT_EQ(dragger->x_max, 2); + + value_set_int(&v1, 3); + ASSERT_EQ(widget_set_prop(b, WIDGET_PROP_Y_MIN, &v1), RET_OK); + ASSERT_EQ(dragger->y_min, 3); + + value_set_int(&v1, 4); + ASSERT_EQ(widget_set_prop(b, WIDGET_PROP_Y_MAX, &v1), RET_OK); + ASSERT_EQ(dragger->y_max, 4); + + widget_destroy(b); +} + +TEST(Dragger, dragger_h) { + pointer_event_t e; + widget_t* b = dragger_create(NULL, 0, 0, 30, 30); + + ASSERT_EQ(dragger_set_range(b, 0, 0, 100, 0), RET_OK); + + e.x = 0; + e.y = 0; + e.e = event_init(EVT_POINTER_DOWN, b); + widget_dispatch(b, &(e.e)); + ASSERT_EQ(b->x, 0); + ASSERT_EQ(b->y, 0); + + e.x = 90; + e.y = 90; + e.e = event_init(EVT_POINTER_MOVE, b); + widget_dispatch(b, &(e.e)); + ASSERT_EQ(b->x, 90); + ASSERT_EQ(b->y, 0); + + e.x = 140; + e.y = 90; + e.e = event_init(EVT_POINTER_MOVE, b); + widget_dispatch(b, &(e.e)); + ASSERT_EQ(b->x, 100); + ASSERT_EQ(b->y, 0); + + e.x = 90; + e.y = 90; + e.e = event_init(EVT_POINTER_UP, b); + widget_dispatch(b, &(e.e)); + ASSERT_EQ(b->x, 90); + ASSERT_EQ(b->y, 0); + + widget_destroy(b); +} + +TEST(Dragger, dragger_v) { + pointer_event_t e; + widget_t* b = dragger_create(NULL, 0, 0, 30, 30); + + ASSERT_EQ(dragger_set_range(b, 0, 0, 0, 100), RET_OK); + + e.x = 0; + e.y = 0; + e.e = event_init(EVT_POINTER_DOWN, b); + widget_dispatch(b, &(e.e)); + ASSERT_EQ(b->x, 0); + ASSERT_EQ(b->y, 0); + + e.x = 90; + e.y = 90; + e.e = event_init(EVT_POINTER_MOVE, b); + widget_dispatch(b, &(e.e)); + ASSERT_EQ(b->x, 0); + ASSERT_EQ(b->y, 90); + + e.x = 90; + e.y = 160; + e.e = event_init(EVT_POINTER_MOVE, b); + widget_dispatch(b, &(e.e)); + ASSERT_EQ(b->x, 0); + ASSERT_EQ(b->y, 100); + + e.x = 90; + e.y = 90; + e.e = event_init(EVT_POINTER_UP, b); + widget_dispatch(b, &(e.e)); + ASSERT_EQ(b->x, 0); + ASSERT_EQ(b->y, 90); + + widget_destroy(b); +}