support applets

This commit is contained in:
lixianjing 2022-07-05 07:57:16 +08:00
parent ed803b8fd2
commit 6e9c7282b4
26 changed files with 419 additions and 24 deletions

70
docs/applet.md Normal file
View File

@ -0,0 +1,70 @@
# 支持可独立安装的小应用程序 (applet)
AWTK 应用程序通常是一个单体的应用程序里面所有的窗口都共享一个资源包目录不能单独卸载和安装。但是在有的设备里AWTK 应用程序又扮演着"系统"的角色,比如在智能手表中,用户可以自己安装喜欢的表盘甚至应用程序,为了方便说明,我们可以独立安装的这类应用程序成为小应用程序 (applet)。
小应用程序 (applet) 的资源必须是独立的才方便安装和卸载。运行时先到自己的资源目录中找资源如果找不到再到系统中去找。AWTK 最近对此做了支持。具体使用方法如下:
## 1. 使用方法
### 1.1 设置小应用程序 (applet) 资源所在的根目录(所有的小应用程序 (applet) 的资源都安装到该目录下)。
```c
/**
* @method assets_managers_set_applet_res_root
* 设置小应用程序 (applet) 的资源根目录。
* @param {const char*} res_root 资源根目录。
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t assets_managers_set_applet_res_root(const char* res_root);
```
如:
```c
assets_managers_set_applet_res_root("applets/");
```
### 1.2 为窗口指定 applet_name 属性
为窗口指定 applet\_name 属性后,窗口优先到对应的 applet 中查找引用的资源,如果找不到就到系统中去查找。
> 在开发小程序应用 (applet),其中所有窗口都必须指定同一个 applet 名称。
```c
/**
* @property {char*} applet_name
* @annotation ["set_prop","get_prop","readable","persitent","design","scriptable"]
* 小应用程序 (applet) 的名称。
*
* > 如果该窗口属于某个独立的小程序应用 (applet),需要指定它的名称,以便到对应的资源目录查找资源。
*/
char* applet_name;
```
示例:
```xml
<window text="foo" anim_hint="htranslate" applet_name="foo">
...
</window>
```
### 1.3 打开小应用程序 (applet) 中的窗口
要进入小应用程序 (applet),就要打开其中的窗口。在调用 window\_open 时就要指定小应用程序 (applet) 的名称。
格式为:小应用程序 (applet) 名 . 窗口名
示例:
```c
window_open("foo.main");
```
## 2. 小应用程序 (applet) 的管理
对小应用程序 (applet) 的管理,比如安装、卸载和查看,需要应用程序自己处理。
## 3. 完整示例
[完整示例](https://github.com/zlgopen/awtk-c-demos/blob/master/demos/applets.c)

View File

@ -1,4 +1,9 @@
# 最新动态
2022/07/05
* 支持独立可以安装的applet让它们具有独立的资源目录。
* 增加文档[支持可独立安装的小应用程序 (applet)](applet.md)
2022/06/30
* 增加函数 fscript\_get\_code\_id
* 支持 image\_animation 修改 interval 属性马上生效(感谢智明提供补丁)

View File

@ -480,6 +480,9 @@ static asset_info_t* assets_manager_load_asset(assets_manager_t* am, asset_type_
if ((info = try_load_assets(am, theme, name, ".bin", type, ASSET_TYPE_UI)) != NULL) {
break;
}
if ((info = try_load_assets(am, theme, name, ".xml", type, ASSET_TYPE_UI)) != NULL) {
break;
}
break;
}
case ASSET_TYPE_XML: {
@ -878,15 +881,20 @@ ret_t assets_manager_set_loader(assets_manager_t* am, asset_loader_t* loader) {
return RET_OK;
}
static darray_t* s_assets_managers = NULL;
static const char* s_module_res_root = NULL;
static const char* s_applet_res_root = NULL;
ret_t assets_managers_set_module_res_root(const char* res_root) {
s_module_res_root = res_root;
ret_t assets_managers_set_applet_res_root(const char* res_root) {
s_applet_res_root = res_root;
return RET_OK;
}
bool_t assets_managers_is_applet_assets_supported(void) {
return s_applet_res_root != NULL;
}
static darray_t* s_assets_managers = NULL;
static int assets_manager_cmp_by_name(assets_manager_t* am, const char* name) {
if (tk_str_eq(am->name, name)) {
return 0;
@ -917,7 +925,7 @@ assets_manager_t* assets_managers_ref(const char* name) {
am = assets_manager_create(5);
return_value_if_fail(am != NULL, NULL);
am->name = tk_strdup(name);
path_build(res_root, MAX_PATH, s_module_res_root, name, NULL);
path_build(res_root, MAX_PATH, s_applet_res_root, name, NULL);
darray_push(s_assets_managers, am);
assets_manager_set_res_root(am, res_root);

View File

@ -427,24 +427,33 @@ bool_t assets_manager_is_save_assets_list(asset_type_t type);
/**
* @class assets_managers_t
* @annotation ["fake"]
*
*
*
* > AWTK是单进程应用程序"applet"
*/
/**
* @method assets_managers_set_module_res_root
* @method assets_managers_set_applet_res_root
* (applet)
* @param {const char*} res_root
*
*
* @return {ret_t} RET_OK表示成功
*/
ret_t assets_managers_set_module_res_root(const char* res_root);
ret_t assets_managers_set_applet_res_root(const char* res_root);
/**
* @method assets_managers_is_applet_assets_supported
* (applet)
*
* @return {bool_t} TRUE表示支持
*/
bool_t assets_managers_is_applet_assets_supported(void);
/**
* @method assets_managers_ref
*
* (applet)
* @annotation ["constructor"]
* @param {const char*} name
* @param {const char*} name (applet)
*
* @return {assets_manager_t*} asset manager对象
*/
@ -452,7 +461,7 @@ assets_manager_t* assets_managers_ref(const char* name);
/**
* @method assets_managers_unref
*
* (applet)
* @annotation ["deconstructor"]
* @param {assets_manager_t*} am
*

View File

@ -62,6 +62,7 @@ font_manager_t* font_manager_init(font_manager_t* fm, font_loader_t* loader) {
fm->loader = loader;
fm->assets_manager = NULL;
fm->refcount = 1;
return fm;
}
@ -223,7 +224,7 @@ ret_t font_manager_unload_all(font_manager_t* fm) {
ret_t font_manager_deinit(font_manager_t* fm) {
return_value_if_fail(fm != NULL, RET_BAD_PARAMS);
TKMEM_FREE(fm->name);
return darray_deinit(&(fm->fonts));
}
@ -259,3 +260,61 @@ ret_t font_manager_set_fallback_get_font(font_manager_t* fm,
return RET_OK;
}
static darray_t* s_font_managers = NULL;
static int font_manager_cmp_by_name(font_manager_t* fm, const char* name) {
if (tk_str_eq(fm->name, name)) {
return 0;
}
return -1;
}
static font_t* font_manager_fallback_get_font_default(font_manager_t* fm, const char* name, font_size_t size) {
return font_manager_get_font(font_manager(), name, size);
}
font_manager_t* font_managers_ref(const char* name) {
font_manager_t* fm = NULL;
return_value_if_fail(name != NULL, NULL);
if (s_font_managers == NULL) {
s_font_managers = darray_create(3, (tk_destroy_t)font_manager_destroy,
(tk_compare_t)font_manager_cmp_by_name);
}
return_value_if_fail(s_font_managers != NULL, NULL);
fm = (font_manager_t*)darray_find(s_font_managers, (void*)name);
if (fm == NULL) {
fm = font_manager_create(s_font_manager->loader);
return_value_if_fail(fm != NULL, NULL);
fm->name = tk_strdup(name);
darray_push(s_font_managers, fm);
font_manager_set_assets_manager(fm, assets_managers_ref(name));
font_manager_set_fallback_get_font(fm, font_manager_fallback_get_font_default, NULL);
} else {
fm->refcount++;
}
return fm;
}
ret_t font_managers_unref(font_manager_t* fm) {
return_value_if_fail(fm != NULL, RET_BAD_PARAMS);
return_value_if_fail(s_font_managers != NULL, RET_BAD_PARAMS);
assert(fm->refcount > 0);
if (fm->refcount == 1) {
assets_managers_unref(fm->assets_manager);
darray_remove(s_font_managers, fm);
if (s_font_managers->size == 0) {
darray_destroy(s_font_managers);
s_font_managers = NULL;
}
} else {
fm->refcount--;
}
return RET_OK;
}

View File

@ -58,6 +58,8 @@ struct _font_manager_t {
assets_manager_t* assets_manager;
/*private*/
char* name;
int32_t refcount;
font_manager_get_font_t fallback_get_font;
void* fallback_get_font_ctx;
};
@ -217,6 +219,33 @@ ret_t font_manager_destroy(font_manager_t* fm);
*/
font_t* font_manager_lookup(font_manager_t* fm, const char* name, font_size_t size);
/**
* @class font_managers_t
* @annotation ["fake"]
*
*
*/
/**
* @method font_managers_ref
* (applet)
* @annotation ["constructor"]
* @param {const char*} name (applet)
*
* @return {font_manager_t*} asset manager对象
*/
font_manager_t* font_managers_ref(const char* name);
/**
* @method font_managers_unref
* (applet)
* @annotation ["deconstructor"]
* @param {font_manager_t*} imm
*
* @return {ret_t} RET_OK表示成功
*/
ret_t font_managers_unref(font_manager_t* imm);
END_C_DECLS
#endif /*TK_FONT_MANAGER_H*/

View File

@ -628,8 +628,6 @@ static ret_t func_theme_set(fscript_t* fscript, fscript_args_t* args, value_t* r
}
static ret_t func_to_name(fscript_t* fscript, fscript_args_t* args, value_t* result) {
const char* name = NULL;
widget_t* widget = WIDGET(tk_object_get_prop_pointer(fscript->obj, STR_PROP_SELF));
FSCRIPT_FUNC_CHECK(args->size == 1, RET_BAD_PARAMS);
value_set_str(result, value_str(args->args));

View File

@ -99,6 +99,7 @@ image_manager_t* image_manager_init(image_manager_t* imm) {
darray_init(&(imm->images), 0, (tk_destroy_t)bitmap_cache_destroy, NULL);
imm->assets_manager = assets_manager();
imm->refcount = 1;
return imm;
}
@ -375,6 +376,7 @@ ret_t image_manager_unload_bitmap(image_manager_t* imm, bitmap_t* image) {
ret_t image_manager_deinit(image_manager_t* imm) {
return_value_if_fail(imm != NULL, RET_BAD_PARAMS);
TKMEM_FREE(imm->name);
darray_deinit(&(imm->images));
return RET_OK;
@ -407,3 +409,62 @@ ret_t image_manager_set_fallback_get_bitmap(image_manager_t* imm,
return RET_OK;
}
static darray_t* s_image_managers = NULL;
static int image_manager_cmp_by_name(image_manager_t* imm, const char* name) {
if (tk_str_eq(imm->name, name)) {
return 0;
}
return -1;
}
static ret_t image_manager_fallback_get_bitmap_default(image_manager_t* imm, const char* name,
bitmap_t* image) {
return image_manager_get_bitmap(image_manager(), name, image);
}
image_manager_t* image_managers_ref(const char* name) {
image_manager_t* imm = NULL;
return_value_if_fail(name != NULL, NULL);
if (s_image_managers == NULL) {
s_image_managers = darray_create(3, (tk_destroy_t)image_manager_destroy,
(tk_compare_t)image_manager_cmp_by_name);
}
return_value_if_fail(s_image_managers != NULL, NULL);
imm = (image_manager_t*)darray_find(s_image_managers, (void*)name);
if (imm == NULL) {
imm = image_manager_create();
return_value_if_fail(imm != NULL, NULL);
imm->name = tk_strdup(name);
darray_push(s_image_managers, imm);
image_manager_set_assets_manager(imm, assets_managers_ref(name));
image_manager_set_fallback_get_bitmap(imm, image_manager_fallback_get_bitmap_default, NULL);
} else {
imm->refcount++;
}
return imm;
}
ret_t image_managers_unref(image_manager_t* imm) {
return_value_if_fail(imm != NULL, RET_BAD_PARAMS);
return_value_if_fail(s_image_managers != NULL, RET_BAD_PARAMS);
assert(imm->refcount > 0);
if (imm->refcount == 1) {
assets_managers_unref(imm->assets_manager);
darray_remove(s_image_managers, imm);
if (s_image_managers->size == 0) {
darray_destroy(s_image_managers);
s_image_managers = NULL;
}
} else {
imm->refcount--;
}
return RET_OK;
}

View File

@ -65,6 +65,8 @@ struct _image_manager_t {
assets_manager_t* assets_manager;
/*private*/
char* name;
int32_t refcount;
uint32_t mem_size_of_cached_images;
uint32_t max_mem_size_of_cached_images;
@ -249,6 +251,33 @@ ret_t image_manager_destroy(image_manager_t* im);
ret_t image_manager_add(image_manager_t* imm, const char* name, const bitmap_t* image);
ret_t image_manager_lookup(image_manager_t* imm, const char* name, bitmap_t* image);
/**
* @class image_managers_t
* @annotation ["fake"]
*
*
*/
/**
* @method image_managers_ref
* (applet)
* @annotation ["constructor"]
* @param {const char*} name (applet)
*
* @return {image_manager_t*} asset manager对象
*/
image_manager_t* image_managers_ref(const char* name);
/**
* @method image_managers_unref
* (applet)
* @annotation ["deconstructor"]
* @param {image_manager_t*} imm
*
* @return {ret_t} RET_OK表示成功
*/
ret_t image_managers_unref(image_manager_t* imm);
END_C_DECLS
#endif /*TK_IMAGE_MANAGER_H*/

View File

@ -38,11 +38,23 @@ widget_t* ui_loader_load_widget(const char* name) {
}
widget_t* ui_loader_load_widget_with_parent(const char* name, widget_t* parent) {
char rname[128];
widget_t* root = NULL;
char rname[128] = {0};
char applet_name[TK_NAME_LEN + 1] = {0};
const asset_info_t* ui = NULL;
ui_builder_t* builder = NULL;
ui_loader_t* loader = default_ui_loader();
const asset_info_t* ui = assets_manager_ref(assets_manager(), ASSET_TYPE_UI, name);
assets_manager_t* am = assets_manager();
if (strncmp(name, STR_SCHEMA_FILE, strlen(STR_SCHEMA_FILE)) != 0 &&
assets_managers_is_applet_assets_supported()) {
const char* p = strchr(name, '.');
if (p != NULL) {
tk_strncpy_s(applet_name, sizeof(applet_name) - 1, name, p - name);
am = assets_managers_ref(applet_name);
name = p + 1;
}
}
ui = assets_manager_ref(am, ASSET_TYPE_UI, name);
return_value_if_fail(ui != NULL, NULL);
if (strncmp(name, STR_SCHEMA_FILE, strlen(STR_SCHEMA_FILE)) == 0 || ui->data[0] == '<') {
@ -57,9 +69,12 @@ widget_t* ui_loader_load_widget_with_parent(const char* name, widget_t* parent)
builder->widget = parent;
ui_loader_load(loader, ui->data, ui->size, builder);
assets_manager_unref(assets_manager(), ui);
assets_manager_unref(am, ui);
root = builder->root;
ui_builder_destroy(builder);
if (applet_name[0]) {
assets_managers_unref(am);
}
return root;
}

View File

@ -419,6 +419,12 @@ BEGIN_C_DECLS
*/
#define WIDGET_PROP_SENSITIVE "sensitive"
/**
* @const WIDGET_PROP_APPLET_NAME
* (applet)
*/
#define WIDGET_PROP_APPLET_NAME "applet_name"
/**
* @const WIDGET_PROP_ANIMATION
*

View File

@ -153,16 +153,28 @@ ret_t window_base_get_prop(widget_t* widget, const char* name, value_t* v) {
value_set_pointer(v, (void*)(theme()));
return RET_OK;
} else if (tk_str_eq(name, WIDGET_PROP_IMAGE_MANAGER)) {
value_set_pointer(v, (void*)(image_manager()));
if(window_base->image_manager != NULL) {
value_set_pointer(v, (void*)(window_base->image_manager));
} else {
value_set_pointer(v, (void*)(image_manager()));
}
return RET_OK;
} else if (tk_str_eq(name, WIDGET_PROP_LOCALE_INFO)) {
value_set_pointer(v, (void*)(locale_info()));
return RET_OK;
} else if (tk_str_eq(name, WIDGET_PROP_FONT_MANAGER)) {
value_set_pointer(v, (void*)(font_manager()));
if(window_base->font_manager != NULL) {
value_set_pointer(v, (void*)(window_base->font_manager));
} else {
value_set_pointer(v, (void*)(font_manager()));
}
return RET_OK;
} else if (tk_str_eq(name, WIDGET_PROP_ASSETS_MANAGER)) {
value_set_pointer(v, (void*)(assets_manager()));
if(window_base->assets_manager != NULL) {
value_set_pointer(v, (void*)(window_base->assets_manager));
} else {
value_set_pointer(v, (void*)(assets_manager()));
}
return RET_OK;
} else if (tk_str_eq(name, WIDGET_PROP_STAGE)) {
value_set_int(v, window_base->stage);
@ -212,11 +224,38 @@ ret_t window_base_get_prop(widget_t* widget, const char* name, value_t* v) {
} else if (tk_str_eq(name, WIDGET_PROP_AUTO_SCALE_CHILDREN_H)) {
value_set_bool(v, window_base->auto_scale_children_h);
return RET_OK;
} else if (tk_str_eq(name, WIDGET_PROP_APPLET_NAME)) {
value_set_str(v, window_base->applet_name);
return RET_OK;
}
return RET_NOT_FOUND;
}
static ret_t window_base_set_applet_name(widget_t* widget, const char* applet_name) {
window_base_t* window_base = WINDOW_BASE(widget);
if(tk_str_eq(window_base->applet_name, applet_name)) {
return RET_OK;
}
if(window_base->applet_name != NULL) {
assets_managers_unref(window_base->assets_manager);
image_managers_unref(window_base->image_manager);
font_managers_unref(window_base->font_manager);
}
if(TK_STR_IS_EMPTY(applet_name)) {
TKMEM_FREE(window_base->applet_name);
} else {
window_base->applet_name = tk_str_copy(window_base->applet_name, applet_name);
window_base->assets_manager = assets_managers_ref(applet_name);
window_base->image_manager = image_managers_ref(applet_name);
window_base->font_manager = font_managers_ref(applet_name);
}
return RET_OK;
}
ret_t window_base_set_prop(widget_t* widget, const char* name, const value_t* v) {
window_base_t* window_base = WINDOW_BASE(widget);
return_value_if_fail(widget != NULL && name != NULL && v != NULL, RET_BAD_PARAMS);
@ -294,6 +333,9 @@ ret_t window_base_set_prop(widget_t* widget, const char* name, const value_t* v)
window_base->closable = (window_closable_t)value_int(v);
}
return RET_OK;
} else if (tk_str_eq(name, WIDGET_PROP_APPLET_NAME)) {
window_base_set_applet_name(widget, value_str(v));
return RET_OK;
}
return RET_NOT_FOUND;

View File

@ -233,6 +233,15 @@ typedef struct _window_base_t {
* [](https://github.com/zlgopen/awtk/blob/master/docs/widget_focus.md)
*/
char* move_focus_right_key;
/**
* @property {char*} applet_name
* @annotation ["set_prop","get_prop","readable","persitent","design","scriptable"]
* (applet)
*
* > (applet)便
*/
char* applet_name;
/**
* @property {bool_t} single_instance
@ -250,13 +259,15 @@ typedef struct _window_base_t {
/*private*/
const asset_info_t* res_theme;
font_manager_t* font_manager;
native_window_t* native_window;
widget_t* save_focus_widget;
uint32_t grab_count_when_to_foreground;
bool_t need_relayout;
bool_t moving_focus_mode;
bool_t pressed;
font_manager_t* font_manager;
assets_manager_t* assets_manager;
image_manager_t* image_manager;
} window_base_t;
/**

View File

@ -205,7 +205,6 @@ const char* tokenizer_next_str(tokenizer_t* tokenizer) {
const char* ret = NULL;
return_value_if_fail(tokenizer_skip_separator(tokenizer) == RET_OK, NULL);
if (tokenizer_has_more(tokenizer)) {
str_t* s = &(tokenizer->token);
char start = tokenizer->str[tokenizer->cursor];
if (start == '"') {

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@ -0,0 +1,9 @@
<button>
<style name="default" border_color="#a0a0a0" text_color="green" font_name="bar" font_size="24">
<normal bg_color="#f0f0f0" />
<pressed bg_color="#c0c0c0" x_offset="1" y_offset="1"/>
<over bg_color="#e0e0e0" />
<focused bg_color="#e0e0e0" />
<disable bg_color="gray" text_color="#d0d0d0" />
</style>
</button>

View File

@ -0,0 +1,4 @@
<window text="bar" anim_hint="htranslate" applet_name="bar">
<image image="bar" self_layout="default(x=c,y=m,w=128,h=128)" draw_type="center"/>
<button style="bar" text="close bar window" self_layout="default(x=c,y=b:20,w=80%,h=36)" on:click="back()"/>
</window>

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -0,0 +1,9 @@
<button>
<style name="default" border_color="#a0a0a0" text_color="red" font_name="foo" font_size="24">
<normal bg_color="#f0f0f0" />
<pressed bg_color="#c0c0c0" x_offset="1" y_offset="1"/>
<over bg_color="#e0e0e0" />
<focused bg_color="#e0e0e0" />
<disable bg_color="gray" text_color="#d0d0d0" />
</style>
</button>

View File

@ -0,0 +1,4 @@
<window text="foo" anim_hint="htranslate" applet_name="foo">
<image image="foo" self_layout="default(x=c,y=m,w=128,h=128)" draw_type="center"/>
<button style="foo" text="close foo window" self_layout="default(x=c,y=b:20,w=80%,h=36)" on:click="back()"/>
</window>

View File

@ -377,7 +377,7 @@ TEST(AssetsManager, custom_load_asset) {
}
TEST(AssetsManager, assets_managers) {
assets_managers_set_module_res_root("./tests/apps");
assets_managers_set_applet_res_root("./tests/applets");
assets_manager_t* foo = assets_managers_ref("foo");
assets_manager_t* bar = assets_managers_ref("bar");
assets_manager_t* bar1 = assets_managers_ref("bar");

View File

@ -49,6 +49,15 @@ TEST(FontManager, loader) {
ASSERT_EQ(font_manager_get_font(&font_manager, "ap", 20) != NULL, true);
font_manager_deinit(&font_manager);
}
TEST(FontManager, font_managers) {
assets_managers_set_applet_res_root("./tests/applets");
font_manager_t* fm = font_managers_ref("foo");
font_t* font = font_manager_get_font(fm, "foo", 18);
ASSERT_EQ(font != NULL, true);
font_managers_unref(fm);
}
TEST(FontManager, unload) {
font_manager_t font_manager;

View File

@ -132,3 +132,22 @@ TEST(ImageManager, limit) {
ASSERT_EQ(image_manager_add(imm, "b3", &b3), RET_OK);
ASSERT_EQ(imm->images.size, 1u);
}
TEST(ImageManager, images_managers1) {
bitmap_t bmp;
assets_managers_set_applet_res_root("./tests/applets");
image_manager_t* imm = image_managers_ref("foo");
ASSERT_EQ(image_manager_get_bitmap(imm, "foo", &bmp), RET_OK);
image_managers_unref(imm);
}
TEST(ImageManager, images_managers2) {
bitmap_t bmp;
assets_managers_set_applet_res_root("./tests/applets");
image_manager_t* imm = image_managers_ref("bar");
ASSERT_EQ(image_manager_get_bitmap(imm, "bar", &bmp), RET_OK);
image_managers_unref(imm);
}