awtk/tools/preview_ui/preview_ui.c
2023-12-31 10:14:21 +08:00

419 lines
14 KiB
C

/**
* File: preview_ui.c
* Author: AWTK Develop Team
* Brief: preview_ui
*
* Copyright (c) 2018 - 2020 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-02-16 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifdef WITH_VLD
#include "vld.h"
#endif
#include "awtk.h"
#include "tkc/dl.h"
#include "tkc/log.h"
#include "base/timer.h"
#include "ui_loader/ui_loader_xml.h"
#include "ui_loader/ui_loader_default.h"
#include "ui_loader/ui_builder_default.h"
#define DEFAULT_UI "./demos/assets/raw/ui/main.xml"
#define MAX_ARGV 12
#ifndef APP_RES_ROOT_DEFAULT_VALUE
#define APP_RES_ROOT_DEFAULT_VALUE NULL
#endif /*APP_RES_ROOT_DEFAULT_VALUE*/
static const char* s_ui = DEFAULT_UI;
static const char* s_system_bar = NULL;
static const char* s_system_bar_bottom = NULL;
static const char* s_res_root = APP_RES_ROOT_DEFAULT_VALUE;
static const char* s_plugins_path = NULL;
static const char* s_render_mode = "OpenGL";
static const char* s_language = NULL;
static const char* s_theme = NULL;
static const char* s_log_level = NULL;
static const char* s_fps = NULL;
#undef APP_RES_ROOT // 以便可以通过命令行参数指定res目录
#if defined(WIN32) && !defined(NDEBUG)
#define SET_ENABLE_CONSOLE() \
if (tk_str_icmp(key, "enable_console") == 0) { \
enable_console = tk_atob(val + 1); \
} else { \
log_debug(usage, argv[0]); \
}
#else
#define SET_ENABLE_CONSOLE() \
{ log_debug(usage, argv[0]); }
#endif /*WIN32 && !NDEBUG*/
#define ON_CMD_LINE(argc, argv) \
{ \
const char* usage = \
"Usage: %s ui=xxx [lcd_w=800] [lcd_h=480] [res_root=xxx] " \
"[language=xxx] [theme=xxx] [system_bar=xxx] [bottom_system_bar=xxx] " \
"[plugins_path=xxx] [render_mode=xxx] [enable_console=xxx]\n"; \
if (argc >= 2) { \
char key[TK_NAME_LEN + 1]; \
int i = 1; \
\
for (i = 1; i < argc; i++) { \
const char* p = argv[i]; \
const char* val = strstr(p, "="); \
uint32_t len = (uint32_t)(val - p); \
\
if (*(argv[i]) == '\0') { \
continue; \
} \
\
if (val == NULL || val == p || *(val + 1) == '\0' || len > TK_NAME_LEN) { \
log_debug(usage, argv[0]); \
exit(0); \
} \
\
tk_strncpy(key, p, len); \
key[len] = '\0'; \
\
if (tk_str_icmp(key, "res_root") == 0) { \
s_res_root = val + 1; \
} else if (tk_str_icmp(key, "ui") == 0) { \
s_ui = val + 1; \
} else if (tk_str_icmp(key, "system_bar") == 0) { \
s_system_bar = val + 1; \
} else if (tk_str_icmp(key, "bottom_system_bar") == 0) { \
s_system_bar_bottom = val + 1; \
} else if (tk_str_icmp(key, "lcd_w") == 0) { \
lcd_w = tk_atoi(val + 1); \
} else if (tk_str_icmp(key, "lcd_h") == 0) { \
lcd_h = tk_atoi(val + 1); \
} else if (tk_str_icmp(key, "plugins_path") == 0) { \
s_plugins_path = val + 1; \
} else if (tk_str_icmp(key, "render_mode") == 0) { \
s_render_mode = val + 1; \
} else if (tk_str_icmp(key, "language") == 0) { \
s_language = val + 1; \
} else if (tk_str_icmp(key, "theme") == 0) { \
s_theme = val + 1; \
} else if (tk_str_icmp(key, "log_level") == 0) { \
s_log_level = val + 1; \
} else if (tk_str_icmp(key, "fps") == 0) { \
s_fps = val + 1; \
} else { \
SET_ENABLE_CONSOLE() \
} \
} \
\
} else { \
log_debug(usage, argv[0]); \
exit(0); \
} \
}
static ret_t get_default_res_root(char path[MAX_PATH + 1]) {
#ifdef APP_RES_DEFAULT_ROOT
tk_strncpy(path, APP_RES_DEFAULT_ROOT, strlen(APP_RES_DEFAULT_ROOT));
return RET_OK;
#else
char app_root[MAX_PATH + 1];
if (path_app_root(app_root) == RET_OK) {
return path_build(path, MAX_PATH, app_root, "res", NULL);
}
return RET_FAIL;
#endif
}
typedef ret_t (*plugin_register_t)(void);
typedef const char* (*plugin_supported_render_mode_t)(void);
static ret_t plugins_dll_register(const char* dirname, const char* render_mode) {
str_t funcname;
fs_item_t item;
char path[MAX_PATH + 1] = {0};
fs_dir_t* dir = fs_open_dir(os_fs(), dirname);
return_value_if_fail(dir != NULL, RET_FAIL);
str_init(&funcname, 0);
while (fs_dir_read(dir, &item) != RET_FAIL) {
if (item.is_dir) {
if (!tk_str_eq(item.name, ".") && !tk_str_eq(item.name, "..")) {
path_build(path, MAX_PATH, dirname, item.name, NULL);
plugins_dll_register(path, render_mode);
}
} else {
bool_t should_try_register = TRUE;
tk_dl_t* dl = NULL;
plugin_register_t register_func;
plugin_supported_render_mode_t render_mode_func;
#ifdef WIN32
if (item.is_reg_file && tk_str_end_with(item.name, ".dll")) {
str_set(&funcname, item.name);
str_replace(&funcname, ".dll", "");
} else {
continue;
}
#elif defined LINUX
if (item.is_reg_file && tk_str_end_with(item.name, ".so") &&
tk_str_start_with(item.name, "lib")) {
str_set(&funcname, item.name);
str_replace(&funcname, "lib", "");
str_replace(&funcname, ".so", "");
} else {
continue;
}
#elif defined MACOS
if (item.is_reg_file && tk_str_end_with(item.name, ".dylib") &&
tk_str_start_with(item.name, "lib")) {
str_set(&funcname, item.name);
str_replace(&funcname, "lib", "");
str_replace(&funcname, ".dylib", "");
} else {
continue;
}
#else
log_debug("Not supported platform.\n");
return RET_FAIL;
#endif
path_build(path, MAX_PATH, dirname, item.name, NULL);
dl = tk_dl_open(path);
if (dl == NULL) {
#ifdef WIN32
log_debug("Open dynamic library faild: %s, error code: %d!\n", path, GetLastError());
#else
log_debug("Open dynamic library faild: %s!\n", path);
#endif
continue;
}
str_append(&funcname, "_supported_render_mode");
render_mode_func = (plugin_supported_render_mode_t)(tk_dl_sym(dl, funcname.str));
if (render_mode_func != NULL) {
const char* modes = render_mode_func();
should_try_register = strstr(modes, render_mode) != NULL;
if (!should_try_register) {
log_debug("Not supported render mode: %s %s!\n", path, render_mode);
}
}
str_replace(&funcname, "_supported_render_mode", "");
if (should_try_register) {
str_append(&funcname, "_register");
register_func = (plugin_register_t)tk_dl_sym(dl, funcname.str);
if (register_func != NULL) {
register_func();
} else {
log_debug("Not found function: %s %s!\n", path, funcname.str);
}
}
}
}
str_reset(&funcname);
return RET_OK;
}
static ret_t plugins_register(void) {
const char* path = s_plugins_path;
if (path != NULL && *path != '\0') {
return_value_if_fail(dir_exist(path), RET_BAD_PARAMS);
return plugins_dll_register(path, s_render_mode);
}
return RET_OK;
}
static ret_t refresh_in_timer(const timer_info_t* info) {
widget_t* widget = WIDGET(info->ctx);
widget_invalidate(widget, NULL);
return RET_REPEAT;
}
static ret_t application_on_launch(void) {
// 当程序初始化完成时调用,全局只触发一次。
if (s_language != NULL && *s_language != '\0') {
const char* p = strstr(s_language, "_");
if (p != NULL) {
char language[TK_NAME_LEN + 1] = {0};
tk_strncpy(language, s_language, tk_min((size_t)(p - s_language), sizeof(language)));
locale_info_change(locale_info(), language, p + 1);
} else {
locale_info_change(locale_info(), s_language, "");
}
}
widget_set_style_str(window_manager(), "bg_color", "white");
return RET_OK;
}
static ret_t application_on_exit(void) {
// 当程序退出时调用,全局只触发一次。
return RET_OK;
}
static widget_t* preview_ui(const char* filename) {
str_t s;
uint32_t size = 0;
widget_t* root = NULL;
char name[TK_NAME_LEN + 1];
ui_builder_t* builder = NULL;
uint8_t* content = NULL;
bool_t is_bin = strstr(filename, ".bin") != NULL;
ui_loader_t* loader = is_bin ? default_ui_loader() : xml_ui_loader();
str_init(&s, 0);
if (is_bin) {
content = (uint8_t*)file_read(filename, &size);
} else {
xml_file_expand_read(filename, &s);
content = (uint8_t*)s.str;
size = s.size;
}
filename_to_name(filename, name, TK_NAME_LEN);
builder = ui_builder_default_create(name);
printf("preview %s\n", filename);
return_value_if_fail(content != NULL, NULL);
ui_loader_load(loader, content, size, builder);
if (builder->root == NULL) {
builder->root = label_create(NULL, 10, 10, 100, 30);
widget_set_text_utf8(builder->root, "not found ui file!");
}
if (builder->root != NULL && !(builder->root->vt->is_window)) {
widget_t* win = window_create(NULL, 0, 0, 0, 0);
widget_add_child(win, builder->root);
widget_layout(win);
timer_add(refresh_in_timer, builder->root, 1000);
}
if (is_bin) {
TKMEM_FREE(content);
} else {
str_reset(&s);
}
root = builder->root;
ui_builder_destroy(builder);
return root;
}
static ret_t application_init(void) {
plugins_register();
application_on_launch();
if (s_system_bar != NULL && *s_system_bar != '\0') {
window_open(s_system_bar);
}
if (s_system_bar_bottom != NULL && *s_system_bar_bottom != '\0') {
window_open(s_system_bar_bottom);
}
preview_ui(s_ui);
return RET_OK;
}
static ret_t application_exit() {
application_on_exit();
log_debug("application_exit\n");
return RET_OK;
}
static ret_t build_asset_dir_custom(void* ctx, char* path, uint32_t size, const char* theme,
const char* ratio, const char* subpath) {
return_value_if_fail(path_build(path, size, s_res_root, theme, subpath, ratio, NULL) == RET_OK,
RET_FAIL);
if (path != NULL && *path != '\0') {
return RET_OK;
} else {
return RET_FAIL;
}
}
ret_t assets_init(void) {
#ifdef WITH_FS_RES
assets_manager_t* am = assets_manager();
const char* res_root = NULL;
bool_t run_default = FALSE;
if (s_theme != NULL) {
assets_manager_set_theme(am, s_theme);
}
TKMEM_FREE(am->res_root);
am->res_root = NULL;
assets_manager_set_custom_build_asset_dir(am, build_asset_dir_custom, NULL);
char path[MAX_PATH + 1];
if (s_res_root != NULL && *s_res_root != '\0') {
assets_manager_set_res_root(am, s_res_root);
}
res_root = assets_manager_get_res_root(am);
tk_snprintf(path, sizeof(path), "%s/assets/default/raw/ui", res_root);
if (!dir_exist(path)) {
run_default = TRUE;
}
if (run_default) {
char path[MAX_PATH + 1];
if (get_default_res_root(path) == RET_OK) {
assets_manager_set_res_root(am, path);
}
}
assets_manager_preload(am, ASSET_TYPE_FONT, "default");
assets_manager_preload(am, ASSET_TYPE_STYLE, "default");
#endif
tk_init_assets();
return RET_OK;
}
static ret_t global_init(void) {
tk_log_level_t log_level =
s_log_level != NULL && *s_log_level != '\0' ? tk_atoi(s_log_level) : LOG_LEVEL_DEBUG;
log_set_log_level(log_level);
return RET_OK;
}
static ret_t global_exit(void) {
return RET_OK;
}
#define GLOBAL_INIT() global_init()
#define GLOBAL_EXIT() global_exit()
#define APP_NAME "awtk_preview"
#include "awtk_main.inc"