improve spin box for easy touch

This commit is contained in:
lixianjing 2022-06-11 18:00:49 +08:00
parent 1a5a000521
commit d3785ba561
13 changed files with 1834 additions and 1427 deletions

View File

@ -52,6 +52,18 @@
<over bg_color="#e0e0e0" icon="arrow_down_o"/>
</style>
<style name="spinbox_bottom" border_color="#a0a0a0">
<normal bg_color="#f0f0f0" icon="arrow_down_n"/>
<pressed bg_color="#c0c0c0" icon="arrow_down_p"/>
<over bg_color="#e0e0e0" icon="arrow_down_o"/>
</style>
<style name="spinbox_top" border_color="#a0a0a0">
<normal bg_color="#f0f0f0" icon="arrow_up_n"/>
<pressed bg_color="#c0c0c0" icon="arrow_up_p"/>
<over bg_color="#e0e0e0" icon="arrow_up_o"/>
</style>
<style name="spinbox_down" border_color="#a0a0a0">
<normal bg_color="#f0f0f0" icon="arrow_down_n"/>
<pressed bg_color="#c0c0c0" icon="arrow_down_p"/>
@ -163,6 +175,14 @@
<empty bg_color="#f0f0f0" text_color="#a0a0a0" />
<empty_focus bg_color="#f0f0f0" text_color="#a0a0a0" border_color="black"/>
</style>
<style name="center" border_color="#a0a0a0" text_color="black" text_align_h="center">
<normal bg_color="#f0f0f0" />
<focused bg_color="#f0f0f0" border_color="black"/>
<disable bg_color="gray" text_color="#d0d0d0" />
<error bg_color="#f0f0f0" text_color="red" />
<empty bg_color="#f0f0f0" text_color="#a0a0a0" />
<empty_focus bg_color="#f0f0f0" text_color="#a0a0a0" border_color="black"/>
</style>
</spin_box>
<digit_clock>

View File

@ -1,5 +1,8 @@
# 最新动态
2022/06/11
* 完善spin box支持不同的形态。具体请参考[spin box的三种形态](spin_box.md)
2022/06/10
* edit/mledit 支持属性获取行高。
* 完善软键盘弹出,平移窗口的距离由编辑器决定。

BIN
docs/images/spin_box.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
docs/images/spin_box_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

BIN
docs/images/spin_box_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

BIN
docs/images/spin_box_3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

129
docs/spin_box.md Normal file
View File

@ -0,0 +1,129 @@
# spin_box 的几种形态
spin_box 是一个特殊的 edit主要用于数值编辑。它自带两个按钮点击它们可以增加/减少数值,增量可以用 step 来设置。
在 AWTK 中spin\_box 有三种形态。
## 1. 传统形态
![](images/spin_box_1.png)
### 1.1 特点
两个按钮均在右侧,按钮比较小,相距很近,只要移动很小距离,即可在两个按钮之间切换,适合鼠标这种比较精确的输入设备。
### 1.2 按钮的 style
* 增加 (inc) 按钮的 style 由 spinbox_up 决定。
* 减小 (dec) 按钮的 style 由 spinbox_down 决定。
### 1.3 示例:
* UI
```xml
<spin_box x="5%" y="10" w="50%" h="30" text="100"/>
```
* style
```xml
<style name="spinbox_down" border_color="#a0a0a0">
<normal bg_color="#f0f0f0" icon="arrow_down_n"/>
<pressed bg_color="#c0c0c0" icon="arrow_down_p"/>
<over bg_color="#e0e0e0" icon="arrow_down_o"/>
</style>
<style name="spinbox_up" border_color="#a0a0a0">
<normal bg_color="#f0f0f0" icon="arrow_up_n"/>
<pressed bg_color="#c0c0c0" icon="arrow_up_p"/>
<over bg_color="#e0e0e0" icon="arrow_up_o"/>
</style>
```
## 2. 按钮在左右两侧
![](images/spin_box_2.png)
### 2.1 特点
按钮在编辑器左右两侧,按钮比较大,不容易发生误操作。适合电容屏这种不太精确的输入设备。
### 2.2 按钮的 style
* 增加 (inc) 按钮的 style 由 spinbox_right 决定。
* 减小 (dec) 按钮的 style 由 spinbox_left 决定。
### 2.3 使用方法
* 需要设置 easy\_touch\_mode="true"
* 控件的 style 中设置文本居中。
### 2.4 示例:
* UI
```xml
<spin_box x="5%" y="100" w="50%" h="30" text="100" easy_touch_mode="true" style="center"/>
```
* style
```xml
<style name="spinbox_left" border_color="#a0a0a0">
<normal bg_color="#f0f0f0" icon="arrow_left_n"/>
<pressed bg_color="#c0c0c0" icon="arrow_left_p"/>
<over bg_color="#e0e0e0" icon="arrow_left_o"/>
</style>
<style name="spinbox_right" border_color="#a0a0a0">
<normal bg_color="#f0f0f0" icon="arrow_right_n"/>
<pressed bg_color="#c0c0c0" icon="arrow_right_p"/>
<over bg_color="#e0e0e0" icon="arrow_right_o"/>
</style>
```
## 3. 按钮在上下两端
![](images/spin_box_3.png)
### 3.1 特点
按钮在编辑器上下两端,按钮比较大,不容易发生误操作。适合电容屏这种不太精确的输入设备。
### 3.2 按钮的 style
* 增加 (inc) 按钮的 style 由 spinbox_top 决定。
* 减小 (dec) 按钮的 style 由 spinbox_bottom 决定。
### 3.3 使用方法:
* 需要设置 easy\_touch\_mode="true"
* 控件的 style 中设置文本居中。
* 并保证控件的高度大于字体大小的 3 倍
### 3.4 示例:
* UI
```xml
<spin_box x="5%" y="200" w="40%" h="90" text="100" easy_touch_mode="true" style="center"/>
```
* style
```xml
<style name="spinbox_bottom" border_color="#a0a0a0">
<normal bg_color="#f0f0f0" icon="arrow_down_n"/>
<pressed bg_color="#c0c0c0" icon="arrow_down_p"/>
<over bg_color="#e0e0e0" icon="arrow_down_o"/>
</style>
<style name="spinbox_top" border_color="#a0a0a0">
<normal bg_color="#f0f0f0" icon="arrow_up_n"/>
<pressed bg_color="#c0c0c0" icon="arrow_up_p"/>
<over bg_color="#e0e0e0" icon="arrow_up_o"/>
</style>
```
> 在 AWTK 中spin\_box 完全可以用 edit + button 来实现,只是直接使用 spin\_box 要简单一些。使用时可以根据自己的实际情况进行选择。

File diff suppressed because it is too large Load Diff

View File

@ -293,6 +293,12 @@ BEGIN_C_DECLS
*/
#define WIDGET_PROP_VALUE "value"
/**
* @const WIDGET_PROP_EASY_TOUCH_MODE
* (spinbox)
*/
#define WIDGET_PROP_EASY_TOUCH_MODE "easy_touch_mode"
/**
* @const WIDGET_PROP_RADIO
* CheckButton是否单选

View File

@ -23,24 +23,92 @@
#include "base/layout.h"
#include "widgets/spin_box.h"
extern const char* s_edit_properties[];
const char* const s_spin_box_properties[] = {TK_EDIT_PROPS, WIDGET_PROP_EASY_TOUCH_MODE, NULL};
widget_t* spin_box_create_self(widget_t* parent, xy_t x, xy_t y, wh_t w, wh_t h);
static ret_t spin_box_on_copy(widget_t* widget, widget_t* other) {
spin_box_t* spin_box = SPIN_BOX(widget);
spin_box_t* spin_box_other = SPIN_BOX(other);
return_value_if_fail(spin_box != NULL && spin_box_other != NULL, RET_BAD_PARAMS);
spin_box->easy_touch_mode = spin_box_other->easy_touch_mode;
return edit_on_copy(widget, other);
}
static ret_t spin_box_set_prop(widget_t* widget, const char* name, const value_t* v) {
if (tk_str_eq(name, WIDGET_PROP_EASY_TOUCH_MODE)) {
spin_box_set_easy_touch_mode(widget, value_bool(v));
return RET_OK;
}
return edit_set_prop(widget, name, v);
}
static ret_t spin_box_get_prop(widget_t* widget, const char* name, value_t* v) {
if (tk_str_eq(name, WIDGET_PROP_EASY_TOUCH_MODE)) {
value_set_bool(v, SPIN_BOX(widget)->easy_touch_mode);
return RET_OK;
}
return edit_get_prop(widget, name, v);
}
static ret_t spin_box_on_layout_children(widget_t* widget) {
edit_t* edit = EDIT(widget);
spin_box_t* spin_box = SPIN_BOX(widget);
widget_t* inc = widget_child(widget, STR_EDIT_INC_NAME);
widget_t* dec = widget_child(widget, STR_EDIT_DEC_NAME);
return_value_if_fail(inc != NULL && dec != NULL, RET_BAD_PARAMS);
if (spin_box->easy_touch_mode) {
int32_t font_size = style_get_int(widget->astyle, STYLE_ID_FONT_SIZE, 18);
if (widget->h > font_size * 3) {
int32_t h = widget->h / 3;
edit->top_margin = h;
edit->bottom_margin = h;
widget_move_resize(inc, 0, 0, widget->w, h);
widget_move_resize(dec, 0, widget->h - h, widget->w, h);
widget_use_style(inc, "spinbox_top");
widget_use_style(dec, "spinbox_bottom");
} else {
int32_t size = widget->h;
edit->left_margin = size;
edit->right_margin = size;
widget_move_resize(dec, 0, 0, size, size);
widget_move_resize(inc, widget->w - size, 0, size, size);
widget_use_style(dec, "spinbox_left");
widget_use_style(inc, "spinbox_right");
}
} else {
int32_t size = widget->h / 2;
int32_t x = widget->w - size;
edit->right_margin = size + 1;
widget_move_resize(inc, x, 0, size, size);
widget_move_resize(dec, x, size, size, size);
widget_use_style(inc, "spinbox_up");
widget_use_style(dec, "spinbox_down");
}
return RET_OK;
}
TK_DECL_VTABLE(spin_box) = {.size = sizeof(spin_box_t),
.type = WIDGET_TYPE_SPIN_BOX,
.inputable = TRUE,
.focusable = TRUE,
.pointer_cursor = WIDGET_CURSOR_EDIT,
.clone_properties = s_edit_properties,
.persistent_properties = s_edit_properties,
.clone_properties = s_spin_box_properties,
.persistent_properties = s_spin_box_properties,
.parent = TK_PARENT_VTABLE(edit),
.create = spin_box_create_self,
.on_paint_self = edit_on_paint_self,
.set_prop = edit_set_prop,
.get_prop = edit_get_prop,
.set_prop = spin_box_set_prop,
.get_prop = spin_box_get_prop,
.on_layout_children = spin_box_on_layout_children,
.on_destroy = edit_on_destroy,
.on_copy = edit_on_copy,
.on_copy = spin_box_on_copy,
.on_event = edit_on_event};
widget_t* spin_box_create_self(widget_t* parent, xy_t x, xy_t y, wh_t w, wh_t h) {
@ -49,7 +117,6 @@ widget_t* spin_box_create_self(widget_t* parent, xy_t x, xy_t y, wh_t w, wh_t h)
return_value_if_fail(spin_box != NULL, NULL);
edit->step = 1;
edit->right_margin = 21;
edit->input_type = INPUT_INT;
return spin_box;
@ -64,20 +131,25 @@ widget_t* spin_box_create(widget_t* parent, xy_t x, xy_t y, wh_t w, wh_t h) {
inc = button_create(spin_box, 0, 0, 0, 0);
inc->auto_created = TRUE;
button_set_repeat(inc, 300);
widget_set_name(inc, "inc");
widget_use_style(inc, "spinbox_up");
widget_set_self_layout_params(inc, "right", "0", "20", "50%");
widget_set_name(inc, STR_EDIT_INC_NAME);
dec = button_create(spin_box, 0, 0, 0, 0);
dec->auto_created = TRUE;
button_set_repeat(dec, 300);
widget_set_name(dec, "dec");
widget_use_style(dec, "spinbox_down");
widget_set_self_layout_params(dec, "right", "bottom", "20", "50%");
widget_set_name(dec, STR_EDIT_DEC_NAME);
return spin_box;
}
ret_t spin_box_set_easy_touch_mode(widget_t* widget, bool_t easy_touch_mode) {
spin_box_t* spin_box = SPIN_BOX(widget);
return_value_if_fail(spin_box != NULL, RET_BAD_PARAMS);
spin_box->easy_touch_mode = easy_touch_mode;
return RET_OK;
}
widget_t* spin_box_cast(widget_t* widget) {
return_value_if_fail(WIDGET_IS_INSTANCE_OF(widget, spin_box), NULL);

View File

@ -80,7 +80,22 @@ BEGIN_C_DECLS
* default](https://github.com/zlgopen/awtk/blob/master/design/default/styles/default.xml#L128)
*
*/
typedef edit_t spin_box_t;
typedef struct _spin_box_t {
edit_t edit;
/**
* @property {bool_t} easy_touch_mode
* @annotation ["set_prop","get_prop","readable","persitent","design","scriptable"]
* ()
* >
* > * 1.font size的3倍时inc按钮在顶部(style名为spinbox_top)dec按钮在底部(style名为spinbox_bottom)
* > * 2.dec按钮在左边(style名为spinbox_left)inc按钮在右边(style名为spinbox_right)
* >
* > inc按钮在右上角(style名为spinbox_up)dec按钮在右下角(style名为spinbox_down)
*/
bool_t easy_touch_mode;
} spin_box_t;
/**
* @method spin_box_create
@ -106,6 +121,17 @@ widget_t* spin_box_create(widget_t* parent, xy_t x, xy_t y, wh_t w, wh_t h);
*/
widget_t* spin_box_cast(widget_t* widget);
/**
* @method spin_box_set_easy_touch_mode
*
* @annotation ["scriptable"]
* @param {widget_t*} widget widget对象
* @param {bool_t} easy_touch_mode
*
* @return {ret_t} RET_OK表示成功
*/
ret_t spin_box_set_easy_touch_mode(widget_t* widget, bool_t easy_touch_mode);
#define SPIN_BOX(widget) ((spin_box_t*)(spin_box_cast(WIDGET(widget))))
/*public for subclass and runtime type check*/

View File

@ -39,8 +39,8 @@ TEST(SpinBox, to_xml) {
"<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>\r\n<spin_box x=\"10\" y=\"20\" "
"w=\"30\" h=\"40\" focusable=\"true\" min=\"0\" max=\"1024\" step=\"1.000000\" "
"input_type=\"1\" readonly=\"false\" cancelable=\"false\" auto_fix=\"false\" "
"left_margin=\"2\" right_margin=\"21\" top_margin=\"2\" bottom_margin=\"2\" "
"action_text=\"done\" password_visible=\"false\">\n</spin_box>\n"));
"left_margin=\"2\" right_margin=\"2\" top_margin=\"2\" bottom_margin=\"2\" "
"action_text=\"done\" password_visible=\"false\" easy_touch_mode=\"false\">\n</spin_box>\n"));
str_reset(&str);
widget_destroy(w1);
@ -65,3 +65,51 @@ TEST(SpinBox, set_value) {
widget_destroy(w);
}
TEST(SpinBox, easy_touch_mode) {
widget_t* w = spin_box_create(NULL, 0, 0, 100, 40);
widget_t* inc = widget_lookup(w, STR_EDIT_INC_NAME, TRUE);
widget_t* dec = widget_lookup(w, STR_EDIT_DEC_NAME, TRUE);
widget_layout(w);
ASSERT_EQ(inc->w, inc->h);
ASSERT_EQ(dec->w, dec->h);
ASSERT_EQ(inc->w, 20);
ASSERT_EQ(dec->h, 20);
ASSERT_EQ(inc->x, w->w - inc->w);
ASSERT_EQ(inc->y, 0);
ASSERT_EQ(dec->x, w->w - inc->w);
ASSERT_EQ(dec->y, inc->h);
ASSERT_EQ(dec->w, dec->h);
spin_box_set_easy_touch_mode(w, TRUE);
widget_layout(w);
ASSERT_EQ(inc->w, w->h);
ASSERT_EQ(inc->h, w->h);
ASSERT_EQ(inc->y, 0);
ASSERT_EQ(inc->x, w->w - inc->w);
ASSERT_EQ(dec->w, w->h);
ASSERT_EQ(dec->h, w->h);
ASSERT_EQ(dec->y, 0);
ASSERT_EQ(dec->x, 0);
widget_resize(w, 80, 90);
widget_layout(w);
ASSERT_EQ(inc->w, w->w);
ASSERT_EQ(inc->h, w->h/3);
ASSERT_EQ(inc->x, 0);
ASSERT_EQ(inc->y, 0);
ASSERT_EQ(dec->w, w->w);
ASSERT_EQ(dec->h, w->h/3);
ASSERT_EQ(dec->x, 0);
ASSERT_EQ(dec->y, 2 * w->h/3);
widget_t* w1 = widget_clone(w, NULL);
ASSERT_EQ(SPIN_BOX(w1)->easy_touch_mode, TRUE);
widget_destroy(w);
widget_destroy(w1);
}