From 8aaf01a3ea4f779cf436f500c57d2ef0b5f7f2e9 Mon Sep 17 00:00:00 2001 From: lixianjing Date: Wed, 3 Feb 2021 18:17:57 +0800 Subject: [PATCH] add design_w/design_h/.. props for window --- docs/changes.md | 3 +- src/base/widget_consts.h | 36 ++++++++++++++++ src/base/window_base.c | 92 ++++++++++++++++++++++++++++++++++++++++ src/base/window_base.h | 37 ++++++++++++++++ tests/popup_test.cc | 92 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 259 insertions(+), 1 deletion(-) diff --git a/docs/changes.md b/docs/changes.md index cc74b5b37..33786217c 100644 --- a/docs/changes.md +++ b/docs/changes.md @@ -1,9 +1,10 @@ # 最新动态 -2021/02/02 +2021/02/03 * 修复缺少 SDL 线程函数的声明的问题(感谢智明提供补丁) * 修复改变 lcd 的大小后 vg 的裁剪区没有修改的问题(感谢智明提供补丁) * 修复 page 控件套 pages 控件的时候释放子 pages 控件导致父 pages 控件的 target 为野指针的问题(感谢智明提供补丁) + * 窗口增加design\_w/design\_h/auto\_scale\_x/auto\_scale\_y/auto\_scale\_w/auto\_scale\_h等参数。 2021/02/02 * 修改注释错误(感谢网友QQ631757707提供补丁) diff --git a/src/base/widget_consts.h b/src/base/widget_consts.h index 9328e7d72..c76469bb2 100644 --- a/src/base/widget_consts.h +++ b/src/base/widget_consts.h @@ -65,6 +65,42 @@ BEGIN_C_DECLS */ #define WIDGET_PROP_H "h" +/** + * @const WIDGET_PROP_DESIGN_W + * 窗口设计时宽度。 + */ +#define WIDGET_PROP_DESIGN_W "design_w" + +/** + * @const WIDGET_PROP_DESIGN_H + * 窗口设计时宽度。 + */ +#define WIDGET_PROP_DESIGN_H "design_h" + +/** + * @const WIDGET_PROP_AUTO_SCALE_X + * 窗口大小与设计时大小不同时,是否自动调整子控件的x坐标。 + */ +#define WIDGET_PROP_AUTO_SCALE_X "auto_scale_x" + +/** + * @const WIDGET_PROP_AUTO_SCALE_Y + * 窗口大小与设计时大小不同时,是否自动调整子控件的y坐标。 + */ +#define WIDGET_PROP_AUTO_SCALE_Y "auto_scale_y" + +/** + * @const WIDGET_PROP_AUTO_SCALE_W + * 窗口大小与设计时大小不同时,是否自动调整子控件的宽度。 + */ +#define WIDGET_PROP_AUTO_SCALE_W "auto_scale_w" + +/** + * @const WIDGET_PROP_AUTO_SCALE_H + * 窗口大小与设计时大小不同时,是否自动调整子控件的高度。 + */ +#define WIDGET_PROP_AUTO_SCALE_H "auto_scale_h" + /** * @const WIDGET_PROP_INPUTING * inputing。 diff --git a/src/base/window_base.c b/src/base/window_base.c index 2374bca2f..d26f2ae38 100644 --- a/src/base/window_base.c +++ b/src/base/window_base.c @@ -178,6 +178,24 @@ ret_t window_base_get_prop(widget_t* widget, const char* name, value_t* v) { } else if (tk_str_eq(name, WIDGET_PROP_SINGLE_INSTANCE)) { value_set_bool(v, window_base->single_instance); return RET_OK; + } else if (tk_str_eq(name, WIDGET_PROP_DESIGN_W)) { + value_set_uint32(v, window_base->design_w); + return RET_OK; + } else if (tk_str_eq(name, WIDGET_PROP_DESIGN_H)) { + value_set_uint32(v, window_base->design_h); + return RET_OK; + } else if (tk_str_eq(name, WIDGET_PROP_AUTO_SCALE_X)) { + value_set_bool(v, window_base->auto_scale_x); + return RET_OK; + } else if (tk_str_eq(name, WIDGET_PROP_AUTO_SCALE_Y)) { + value_set_bool(v, window_base->auto_scale_y); + return RET_OK; + } else if (tk_str_eq(name, WIDGET_PROP_AUTO_SCALE_W)) { + value_set_bool(v, window_base->auto_scale_w); + return RET_OK; + } else if (tk_str_eq(name, WIDGET_PROP_AUTO_SCALE_H)) { + value_set_bool(v, window_base->auto_scale_h); + return RET_OK; } return RET_NOT_FOUND; @@ -228,6 +246,24 @@ ret_t window_base_set_prop(widget_t* widget, const char* name, const value_t* v) } else if (tk_str_eq(name, WIDGET_PROP_SINGLE_INSTANCE)) { window_base->single_instance = value_bool(v); return RET_OK; + } else if (tk_str_eq(name, WIDGET_PROP_DESIGN_W)) { + window_base->design_w = value_uint32(v); + return RET_OK; + } else if (tk_str_eq(name, WIDGET_PROP_DESIGN_H)) { + window_base->design_h = value_uint32(v); + return RET_OK; + } else if (tk_str_eq(name, WIDGET_PROP_AUTO_SCALE_X)) { + window_base->auto_scale_x = value_bool(v); + return RET_OK; + } else if (tk_str_eq(name, WIDGET_PROP_AUTO_SCALE_Y)) { + window_base->auto_scale_y = value_bool(v); + return RET_OK; + } else if (tk_str_eq(name, WIDGET_PROP_AUTO_SCALE_W)) { + window_base->auto_scale_w = value_bool(v); + return RET_OK; + } else if (tk_str_eq(name, WIDGET_PROP_AUTO_SCALE_H)) { + window_base->auto_scale_h = value_bool(v); + return RET_OK; } else if (tk_str_eq(name, WIDGET_PROP_CLOSABLE)) { if (v->type == VALUE_TYPE_STRING) { const key_type_value_t* kv = window_closable_type_find(value_str(v)); @@ -295,6 +331,57 @@ static widget_t* window_base_get_key_target_leaf(widget_t* widget) { return iter; } +typedef struct _auto_resize_info_t { + widget_t* window; + float hscale; + float vscale; + bool_t auto_scale_x; + bool_t auto_scale_y; + bool_t auto_scale_w; + bool_t auto_scale_h; +} auto_resize_info_t; + +static ret_t window_base_auto_scale_child(void* ctx, const void* data) { + auto_resize_info_t* info = (auto_resize_info_t*)ctx; + widget_t* widget = WIDGET(data); + + if (widget != info->window) { + if (widget->parent->children_layout == NULL && widget->self_layout == NULL) { + if (info->auto_scale_x) { + widget->x *= info->hscale; + } + if (info->auto_scale_w) { + widget->w *= info->hscale; + } + if (info->auto_scale_y) { + widget->y *= info->vscale; + } + if (info->auto_scale_h) { + widget->h *= info->vscale; + } + } + } + + return RET_OK; +} + +static ret_t window_base_auto_scale_children(widget_t* widget) { + auto_resize_info_t info; + window_base_t* win = WINDOW_BASE(widget); + + info.window = widget; + info.hscale = (float)(win->widget.w) / (float)(win->design_w); + info.vscale = (float)(win->widget.h) / (float)(win->design_h); + info.auto_scale_x = win->auto_scale_x; + info.auto_scale_y = win->auto_scale_y; + info.auto_scale_w = win->auto_scale_w; + info.auto_scale_h = win->auto_scale_h; + + widget_foreach(widget, window_base_auto_scale_child, &info); + + return RET_OK; +} + ret_t window_base_on_event(widget_t* widget, event_t* e) { window_base_t* win = WINDOW_BASE(widget); return_value_if_fail(widget != NULL && win != NULL, RET_BAD_PARAMS); @@ -310,6 +397,11 @@ ret_t window_base_on_event(widget_t* widget, event_t* e) { widget_set_focused_internal(widget, TRUE); } } else if (e->type == EVT_WINDOW_LOAD) { + if (win->design_w && win->design_h) { + if (win->auto_scale_x || win->auto_scale_y || win->auto_scale_w || win->auto_scale_h) { + window_base_auto_scale_children(widget); + } + } } else if (e->type == EVT_WINDOW_CLOSE) { win->stage = WINDOW_STAGE_CLOSED; } else if (e->type == EVT_THEME_CHANGED) { diff --git a/src/base/window_base.h b/src/base/window_base.h index 064938a85..d7589b050 100644 --- a/src/base/window_base.h +++ b/src/base/window_base.h @@ -60,6 +60,43 @@ typedef struct _window_base_t { */ char* theme; + /** + * @property {uint16_t} design_w + * @annotation ["set_prop","get_prop","readable","persitent","design","scriptable"] + * 设计时宽度。 + */ + uint16_t design_w; + /** + * @property {uint16_t} design_h + * @annotation ["set_prop","get_prop","readable","persitent","design","scriptable"] + * 设计时高度。 + */ + uint16_t design_h; + /** + * @property {bool_t} auto_scale_x + * @annotation ["set_prop","get_prop","readable","persitent","design","scriptable"] + * 窗口大小与设计时大小不同时,是否自动调整子控件的x坐标。 + */ + uint16_t auto_scale_x : 1; + /** + * @property {bool_t} auto_scale_y + * @annotation ["set_prop","get_prop","readable","persitent","design","scriptable"] + * 窗口大小与设计时大小不同时,是否自动调整子控件的y坐标。 + */ + uint16_t auto_scale_y : 1; + /** + * @property {bool_t} auto_scale_w + * @annotation ["set_prop","get_prop","readable","persitent","design","scriptable"] + * 窗口大小与设计时大小不同时,是否自动调整子控件的宽度。 + */ + uint16_t auto_scale_w : 1; + /** + * @property {bool_t} auto_scale_h + * @annotation ["set_prop","get_prop","readable","persitent","design","scriptable"] + * 窗口大小与设计时大小不同时,是否自动调整子控件的高度。 + */ + uint16_t auto_scale_h : 1; + /** * @property {bool_t} disable_anim * @annotation ["set_prop","get_prop","readable","persitent","design","scriptable"] diff --git a/tests/popup_test.cc b/tests/popup_test.cc index 1b91736e0..eab29906b 100644 --- a/tests/popup_test.cc +++ b/tests/popup_test.cc @@ -1,4 +1,5 @@ #include "widgets/popup.h" +#include "widgets/button.h" #include "gtest/gtest.h" TEST(Popup, cast) { @@ -27,3 +28,94 @@ TEST(Popup, basic) { widget_destroy(w); } + +TEST(Popup, auto_scale_x) { + widget_t* w = popup_create(NULL, 0, 0, 400, 600); + widget_t* b = button_create(w, 10, 20, 30, 40); + + ASSERT_EQ(widget_get_prop_int(w, WIDGET_PROP_DESIGN_W, 0), 0); + ASSERT_EQ(widget_set_prop_int(w, WIDGET_PROP_DESIGN_W, 200), RET_OK); + ASSERT_EQ(widget_get_prop_int(w, WIDGET_PROP_DESIGN_W, 0), 200); + + ASSERT_EQ(widget_get_prop_int(w, WIDGET_PROP_DESIGN_H, 0), 0); + ASSERT_EQ(widget_set_prop_int(w, WIDGET_PROP_DESIGN_H, 300), RET_OK); + ASSERT_EQ(widget_get_prop_int(w, WIDGET_PROP_DESIGN_H, 0), 300); + + ASSERT_EQ(widget_get_prop_bool(w, WIDGET_PROP_AUTO_SCALE_X, TRUE), FALSE); + ASSERT_EQ(widget_set_prop_bool(w, WIDGET_PROP_AUTO_SCALE_X, TRUE), RET_OK); + ASSERT_EQ(widget_get_prop_bool(w, WIDGET_PROP_AUTO_SCALE_X, FALSE), TRUE); + + widget_dispatch_simple_event(w, EVT_WINDOW_LOAD); + ASSERT_EQ(b->x, 20); + ASSERT_EQ(b->y, 20); + ASSERT_EQ(b->w, 30); + ASSERT_EQ(b->h, 40); + + widget_destroy(w); +} + +TEST(Popup, auto_scale_xy) { + widget_t* w = popup_create(NULL, 0, 0, 400, 600); + widget_t* b = button_create(w, 10, 20, 30, 40); + + ASSERT_EQ(widget_get_prop_int(w, WIDGET_PROP_DESIGN_W, 0), 0); + ASSERT_EQ(widget_set_prop_int(w, WIDGET_PROP_DESIGN_W, 200), RET_OK); + ASSERT_EQ(widget_get_prop_int(w, WIDGET_PROP_DESIGN_W, 0), 200); + + ASSERT_EQ(widget_get_prop_int(w, WIDGET_PROP_DESIGN_H, 0), 0); + ASSERT_EQ(widget_set_prop_int(w, WIDGET_PROP_DESIGN_H, 300), RET_OK); + ASSERT_EQ(widget_get_prop_int(w, WIDGET_PROP_DESIGN_H, 0), 300); + + ASSERT_EQ(widget_get_prop_bool(w, WIDGET_PROP_AUTO_SCALE_X, TRUE), FALSE); + ASSERT_EQ(widget_set_prop_bool(w, WIDGET_PROP_AUTO_SCALE_X, TRUE), RET_OK); + ASSERT_EQ(widget_get_prop_bool(w, WIDGET_PROP_AUTO_SCALE_X, FALSE), TRUE); + + ASSERT_EQ(widget_get_prop_bool(w, WIDGET_PROP_AUTO_SCALE_Y, TRUE), FALSE); + ASSERT_EQ(widget_set_prop_bool(w, WIDGET_PROP_AUTO_SCALE_Y, TRUE), RET_OK); + ASSERT_EQ(widget_get_prop_bool(w, WIDGET_PROP_AUTO_SCALE_Y, FALSE), TRUE); + + widget_dispatch_simple_event(w, EVT_WINDOW_LOAD); + ASSERT_EQ(b->x, 20); + ASSERT_EQ(b->y, 40); + ASSERT_EQ(b->w, 30); + ASSERT_EQ(b->h, 40); + + widget_destroy(w); +} + +TEST(Popup, auto_scale_xywh) { + widget_t* w = popup_create(NULL, 0, 0, 400, 600); + widget_t* b = button_create(w, 10, 20, 30, 40); + + ASSERT_EQ(widget_get_prop_int(w, WIDGET_PROP_DESIGN_W, 0), 0); + ASSERT_EQ(widget_set_prop_int(w, WIDGET_PROP_DESIGN_W, 200), RET_OK); + ASSERT_EQ(widget_get_prop_int(w, WIDGET_PROP_DESIGN_W, 0), 200); + + ASSERT_EQ(widget_get_prop_int(w, WIDGET_PROP_DESIGN_H, 0), 0); + ASSERT_EQ(widget_set_prop_int(w, WIDGET_PROP_DESIGN_H, 300), RET_OK); + ASSERT_EQ(widget_get_prop_int(w, WIDGET_PROP_DESIGN_H, 0), 300); + + ASSERT_EQ(widget_get_prop_bool(w, WIDGET_PROP_AUTO_SCALE_X, TRUE), FALSE); + ASSERT_EQ(widget_set_prop_bool(w, WIDGET_PROP_AUTO_SCALE_X, TRUE), RET_OK); + ASSERT_EQ(widget_get_prop_bool(w, WIDGET_PROP_AUTO_SCALE_X, FALSE), TRUE); + + ASSERT_EQ(widget_get_prop_bool(w, WIDGET_PROP_AUTO_SCALE_Y, TRUE), FALSE); + ASSERT_EQ(widget_set_prop_bool(w, WIDGET_PROP_AUTO_SCALE_Y, TRUE), RET_OK); + ASSERT_EQ(widget_get_prop_bool(w, WIDGET_PROP_AUTO_SCALE_Y, FALSE), TRUE); + + ASSERT_EQ(widget_get_prop_bool(w, WIDGET_PROP_AUTO_SCALE_W, TRUE), FALSE); + ASSERT_EQ(widget_set_prop_bool(w, WIDGET_PROP_AUTO_SCALE_W, TRUE), RET_OK); + ASSERT_EQ(widget_get_prop_bool(w, WIDGET_PROP_AUTO_SCALE_W, FALSE), TRUE); + + ASSERT_EQ(widget_get_prop_bool(w, WIDGET_PROP_AUTO_SCALE_H, TRUE), FALSE); + ASSERT_EQ(widget_set_prop_bool(w, WIDGET_PROP_AUTO_SCALE_H, TRUE), RET_OK); + ASSERT_EQ(widget_get_prop_bool(w, WIDGET_PROP_AUTO_SCALE_H, FALSE), TRUE); + + widget_dispatch_simple_event(w, EVT_WINDOW_LOAD); + ASSERT_EQ(b->x, 20); + ASSERT_EQ(b->y, 40); + ASSERT_EQ(b->w, 60); + ASSERT_EQ(b->h, 80); + + widget_destroy(w); +}