luat_lib_easylvgl.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. /*
  2. @module easylvgl
  3. @summary EasyLVGL图像库 (LVGL 9.4) - 重构版本
  4. @version 0.1.0
  5. @date 2025.12.02
  6. @tag LUAT_USE_EASYLVGL
  7. */
  8. #include "luat_base.h"
  9. #include "luat_log.h"
  10. #include "lua.h"
  11. #include "lauxlib.h"
  12. #include "rotable2.h"
  13. #include "luat_malloc.h"
  14. #include "../inc/luat_easylvgl.h"
  15. #include "../inc/luat_easylvgl_component.h"
  16. #include "../inc/luat_easylvgl_binding.h"
  17. #include "../inc/luat_easylvgl_symbol.h"
  18. #include "luat_conf_bsp.h"
  19. #if defined(LUAT_USE_EASYLVGL_BK7258)
  20. #include "../src/platform/bk7258/luat_easylvgl_platform_bk7258.h"
  21. #endif
  22. #include <string.h>
  23. #define LUAT_LOG_TAG "easylvgl"
  24. #include "luat_log.h"
  25. // 全局上下文(单例模式)
  26. static easylvgl_ctx_t *g_ctx = NULL;
  27. // 函数声明
  28. static int l_easylvgl_init(lua_State *L);
  29. static int l_easylvgl_deinit(lua_State *L);
  30. static int l_easylvgl_refresh(lua_State *L);
  31. static int l_easylvgl_indev_bind_touch(lua_State *L);
  32. static int l_easylvgl_keyboard_enable_system(lua_State *L);
  33. static int l_easylvgl_font_load(lua_State *L);
  34. // Button 模块声明
  35. extern void easylvgl_register_button_meta(lua_State *L);
  36. extern int easylvgl_button_create(lua_State *L);
  37. // Label 模块声明
  38. extern void easylvgl_register_label_meta(lua_State *L);
  39. extern int easylvgl_label_create(lua_State *L);
  40. // Image 模块声明
  41. extern void easylvgl_register_image_meta(lua_State *L);
  42. extern int easylvgl_image_create(lua_State *L);
  43. // Container 模块声明
  44. extern void easylvgl_register_container_meta(lua_State *L);
  45. extern int easylvgl_container_create(lua_State *L);
  46. // Table 模块声明
  47. extern void easylvgl_register_table_meta(lua_State *L);
  48. extern int easylvgl_table_create(lua_State *L);
  49. // TabView 模块声明
  50. extern void easylvgl_register_tabview_meta(lua_State *L);
  51. extern int easylvgl_tabview_create(lua_State *L);
  52. // Win 模块声明
  53. extern void easylvgl_register_win_meta(lua_State *L);
  54. extern int easylvgl_win_create(lua_State *L);
  55. // Dropdown 模块声明
  56. extern void easylvgl_register_dropdown_meta(lua_State *L);
  57. extern int easylvgl_dropdown_create(lua_State *L);
  58. // Switch 模块声明
  59. extern void easylvgl_register_switch_meta(lua_State *L);
  60. extern int easylvgl_switch_create(lua_State *L);
  61. // Msgbox 模块声明
  62. extern void easylvgl_register_msgbox_meta(lua_State *L);
  63. extern int easylvgl_msgbox_create(lua_State *L);
  64. // Textarea 模块声明
  65. extern void easylvgl_register_textarea_meta(lua_State *L);
  66. extern int easylvgl_textarea_create(lua_State *L);
  67. // Keyboard 模块声明
  68. extern void easylvgl_register_keyboard_meta(lua_State *L);
  69. extern int easylvgl_keyboard_create(lua_State *L);
  70. // 模块注册表
  71. static const rotable_Reg_t reg_easylvgl[] = {
  72. // 基础设置
  73. {"init", ROREG_FUNC(l_easylvgl_init)},
  74. {"deinit", ROREG_FUNC(l_easylvgl_deinit)},
  75. {"refresh", ROREG_FUNC(l_easylvgl_refresh)},
  76. {"indev_bind_touch", ROREG_FUNC(l_easylvgl_indev_bind_touch)},
  77. {"keyboard_enable_system", ROREG_FUNC(l_easylvgl_keyboard_enable_system)},
  78. {"font_load", ROREG_FUNC(l_easylvgl_font_load)},
  79. // 组件注册
  80. {"button", ROREG_FUNC(easylvgl_button_create)},
  81. {"label", ROREG_FUNC(easylvgl_label_create)},
  82. {"image", ROREG_FUNC(easylvgl_image_create)},
  83. {"container", ROREG_FUNC(easylvgl_container_create)},
  84. {"table", ROREG_FUNC(easylvgl_table_create)},
  85. {"tabview", ROREG_FUNC(easylvgl_tabview_create)},
  86. {"win", ROREG_FUNC(easylvgl_win_create)},
  87. {"dropdown", ROREG_FUNC(easylvgl_dropdown_create)},
  88. {"switch", ROREG_FUNC(easylvgl_switch_create)},
  89. {"msgbox", ROREG_FUNC(easylvgl_msgbox_create)},
  90. {"textarea", ROREG_FUNC(easylvgl_textarea_create)},
  91. {"keyboard", ROREG_FUNC(easylvgl_keyboard_create)},
  92. // 颜色格式常量
  93. {"COLOR_FORMAT_RGB565", ROREG_INT(EASYLVGL_COLOR_FORMAT_RGB565)},
  94. {"COLOR_FORMAT_ARGB8888", ROREG_INT(EASYLVGL_COLOR_FORMAT_ARGB8888)},
  95. // 文本对齐常量
  96. {"EASYLVGL_TEXT_ALIGN_LEFT", ROREG_INT(LV_TEXT_ALIGN_LEFT)},
  97. {"EASYLVGL_TEXT_ALIGN_CENTER", ROREG_INT(LV_TEXT_ALIGN_CENTER)},
  98. {"EASYLVGL_TEXT_ALIGN_RIGHT", ROREG_INT(LV_TEXT_ALIGN_RIGHT)},
  99. // TabView 对齐常量
  100. {"EASYLVGL_TABVIEW_PAD_ALL", ROREG_INT(EASYLVGL_TABVIEW_PAD_ALL)},
  101. {"EASYLVGL_TABVIEW_PAD_HOR", ROREG_INT(EASYLVGL_TABVIEW_PAD_HOR)},
  102. {"EASYLVGL_TABVIEW_PAD_VER", ROREG_INT(EASYLVGL_TABVIEW_PAD_VER)},
  103. {"EASYLVGL_TABVIEW_PAD_TOP", ROREG_INT(EASYLVGL_TABVIEW_PAD_TOP)},
  104. {"EASYLVGL_TABVIEW_PAD_BOTTOM", ROREG_INT(EASYLVGL_TABVIEW_PAD_BOTTOM)},
  105. {"EASYLVGL_TABVIEW_PAD_LEFT", ROREG_INT(EASYLVGL_TABVIEW_PAD_LEFT)},
  106. {"EASYLVGL_TABVIEW_PAD_RIGHT", ROREG_INT(EASYLVGL_TABVIEW_PAD_RIGHT)},
  107. // 图标常量
  108. EASYLVGL_SYMBOL_REG,
  109. {NULL, ROREG_INT(0)}
  110. };
  111. LUAMOD_API int luaopen_easylvgl(lua_State *L) {
  112. // 注册各组件元表
  113. easylvgl_register_button_meta(L);
  114. easylvgl_register_label_meta(L);
  115. easylvgl_register_image_meta(L);
  116. easylvgl_register_container_meta(L);
  117. easylvgl_register_table_meta(L);
  118. easylvgl_register_tabview_meta(L);
  119. easylvgl_register_win_meta(L);
  120. easylvgl_register_dropdown_meta(L);
  121. easylvgl_register_switch_meta(L);
  122. easylvgl_register_msgbox_meta(L);
  123. easylvgl_register_textarea_meta(L);
  124. easylvgl_register_keyboard_meta(L);
  125. // 注册模块函数
  126. luat_newlib2(L, reg_easylvgl);
  127. return 1;
  128. }
  129. /**
  130. * 初始化 EasyLVGL
  131. * @api easylvgl.init(width, height, color_format)
  132. * @int width 屏幕宽度,默认 480
  133. * @int height 屏幕高度,默认 320
  134. * @int color_format 颜色格式,可选,默认 RGB565
  135. * 可用值:easylvgl.COLOR_FORMAT_RGB565(嵌入式,节省内存)
  136. * easylvgl.COLOR_FORMAT_ARGB8888(默认,高质量)
  137. * @return bool 成功返回 true,失败返回 false
  138. */
  139. static int l_easylvgl_init(lua_State *L) {
  140. if (g_ctx != NULL) {
  141. LLOGE("easylvgl already initialized");
  142. lua_pushboolean(L, 0);
  143. return 1;
  144. }
  145. int w = luaL_optinteger(L, 1, 480);
  146. int h = luaL_optinteger(L, 2, 320);
  147. // 获取颜色格式参数,默认为RGB565
  148. lv_color_format_t color_format = (lv_color_format_t)luaL_optinteger(L, 3, EASYLVGL_COLOR_FORMAT_RGB565);
  149. // 验证颜色格式是否有效,需要和lvgl的颜色格式对应(只支持 RGB565 和 ARGB8888)
  150. if (color_format != EASYLVGL_COLOR_FORMAT_RGB565 &&
  151. color_format != EASYLVGL_COLOR_FORMAT_ARGB8888) {
  152. LLOGE("easylvgl.init: invalid color format %d, using RGB565", color_format);
  153. color_format = EASYLVGL_COLOR_FORMAT_RGB565;
  154. }
  155. // 分配上下文
  156. g_ctx = luat_heap_malloc(sizeof(easylvgl_ctx_t));
  157. if (g_ctx == NULL) {
  158. lua_pushboolean(L, 0);
  159. return 1;
  160. }
  161. // 创建上下文(自动选择平台驱动)
  162. int ret = easylvgl_ctx_create(g_ctx, NULL);
  163. if (ret != 0) {
  164. luat_heap_free(g_ctx);
  165. g_ctx = NULL;
  166. lua_pushboolean(L, 0);
  167. return 1;
  168. }
  169. // 存储 Lua 状态
  170. g_ctx->L = L;
  171. // 将上下文存储到注册表
  172. lua_pushlightuserdata(L, g_ctx);
  173. lua_setfield(L, LUA_REGISTRYINDEX, "easylvgl_ctx");
  174. // 初始化 EasyLVGL(使用指定的颜色格式)
  175. ret = easylvgl_init(g_ctx, w, h, color_format);
  176. if (ret != 0) {
  177. easylvgl_ctx_create(g_ctx, NULL); // 清理
  178. luat_heap_free(g_ctx);
  179. g_ctx = NULL;
  180. lua_pushboolean(L, 0);
  181. return 1;
  182. }
  183. lua_pushboolean(L, 1);
  184. return 1;
  185. }
  186. /**
  187. * 反初始化 EasyLVGL
  188. * @api easylvgl.deinit()
  189. * @return nil
  190. */
  191. static int l_easylvgl_deinit(lua_State *L) {
  192. (void)L;
  193. if (g_ctx != NULL) {
  194. easylvgl_deinit(g_ctx);
  195. luat_heap_free(g_ctx);
  196. g_ctx = NULL;
  197. // 清除注册表中的上下文
  198. lua_pushnil(L);
  199. lua_setfield(L, LUA_REGISTRYINDEX, "easylvgl_ctx");
  200. }
  201. return 0;
  202. }
  203. /**
  204. * 刷新 LVGL 显示(执行定时器处理)
  205. * @api easylvgl.refresh()
  206. * @return nil
  207. */
  208. static int l_easylvgl_refresh(lua_State *L) {
  209. (void)L;
  210. if (g_ctx == NULL) {
  211. luaL_error(L, "easylvgl not initialized, call easylvgl.init() first");
  212. return 0;
  213. }
  214. // 执行 LVGL 定时器处理(处理重绘、动画、事件等)
  215. lv_timer_handler();
  216. return 0;
  217. }
  218. /**
  219. * 绑定触摸输入配置到 BK7258 平台
  220. * @api easylvgl.indev_bind_touch(tp_cfg)
  221. * @userdata tp_cfg luat_tp_config_t*(lightuserdata)
  222. * @return bool 绑定是否成功
  223. */
  224. static int l_easylvgl_indev_bind_touch(lua_State *L) {
  225. #if defined(LUAT_USE_EASYLVGL_BK7258)
  226. luat_tp_config_t *tp_cfg = (luat_tp_config_t *)lua_touserdata(L, 1);
  227. if (tp_cfg == NULL) {
  228. LLOGE("indev_bind_touch tp_cfg is NULL");
  229. lua_pushboolean(L, 0);
  230. return 1;
  231. }
  232. /* 保存到平台绑定,供初始化时同步 */
  233. easylvgl_platform_bk7258_bind_tp(tp_cfg);
  234. /* 如果上下文已存在且平台数据已分配,运行时也同步一份 */
  235. if (g_ctx && g_ctx->platform_data) {
  236. bk7258_platform_data_t *data = (bk7258_platform_data_t *)g_ctx->platform_data;
  237. data->tp_config = tp_cfg;
  238. }
  239. LLOGD("indev_bind_touch bind %p", tp_cfg);
  240. lua_pushboolean(L, 1);
  241. return 1;
  242. // SDL2 路径:SDL 输入已经通过事件轮询获取,无需绑定 TP
  243. #elif defined(LUAT_USE_EASYLVGL_SDL2)
  244. (void)L;
  245. LLOGI("indev_bind_touch ignored on SDL2 (mouse/SDL events used)");
  246. lua_pushboolean(L, 1);
  247. return 1;
  248. #else
  249. (void)L;
  250. LLOGE("indev_bind_touch unsupported on this platform");
  251. lua_pushboolean(L, 0);
  252. return 1;
  253. #endif
  254. }
  255. static int l_easylvgl_keyboard_enable_system(lua_State *L) {
  256. bool enable = lua_toboolean(L, 1);
  257. easylvgl_ctx_t *ctx = NULL;
  258. lua_getfield(L, LUA_REGISTRYINDEX, "easylvgl_ctx");
  259. if (lua_type(L, -1) == LUA_TLIGHTUSERDATA) {
  260. ctx = (easylvgl_ctx_t *)lua_touserdata(L, -1);
  261. }
  262. lua_pop(L, 1);
  263. if (ctx == NULL) {
  264. luaL_error(L, "easylvgl not initialized");
  265. return 0;
  266. }
  267. int ret = easylvgl_system_keyboard_enable(ctx, enable);
  268. lua_pushboolean(L, ret == EASYLVGL_OK);
  269. return 1;
  270. }
  271. /**
  272. * 推送组件 userdata(通用辅助函数)
  273. */
  274. void easylvgl_push_component_userdata(lua_State *L, lv_obj_t *obj, const char *mt) {
  275. easylvgl_component_ud_t *ud = (easylvgl_component_ud_t *)lua_newuserdata(L, sizeof(easylvgl_component_ud_t));
  276. ud->obj = obj;
  277. luaL_getmetatable(L, mt);
  278. lua_setmetatable(L, -2);
  279. }
  280. /**
  281. * 检查组件 userdata(通用辅助函数)
  282. */
  283. lv_obj_t *easylvgl_check_component(lua_State *L, int index, const char *mt) {
  284. easylvgl_component_ud_t *ud = (easylvgl_component_ud_t *)luaL_checkudata(L, index, mt);
  285. if (ud == NULL || ud->obj == NULL) {
  286. luaL_error(L, "invalid %s object", mt);
  287. }
  288. return ud->obj;
  289. }
  290. /**
  291. * 加载字体
  292. * @api easylvgl.font_load(config)
  293. * @table config 配置表
  294. * @string config.type 字体类型,"hzfont" 或 "bin"
  295. * @string config.path 字体路径,对于 "hzfont",传 nil 则使用内置字库
  296. * @int config.size 可选,TTF 字体大小,默认 16
  297. * @int config.cache_size 可选,TTF 缓存数量,默认 256
  298. * @int config.antialias 可选,TTF 抗锯齿等级,默认 -1(自动)
  299. * @return userdata 字体指针
  300. */
  301. static int l_easylvgl_font_load(lua_State *L) {
  302. luaL_checktype(L, 1, LUA_TTABLE);
  303. const char *type = easylvgl_marshal_string(L, 1, "type", NULL);
  304. if (type == NULL) {
  305. luaL_error(L, "font_load: config.type is required");
  306. return 0;
  307. }
  308. lv_font_t *font = NULL;
  309. if (strcmp(type, "hzfont") == 0) {
  310. const char *path = easylvgl_marshal_string(L, 1, "path", NULL);
  311. uint16_t size = easylvgl_marshal_integer(L, 1, "size", 16);
  312. uint32_t cache_size = easylvgl_marshal_integer(L, 1, "cache_size", 256);
  313. int antialias = easylvgl_marshal_integer(L, 1, "antialias", -1);
  314. font = easylvgl_font_hzfont_create(path, size, cache_size, antialias);
  315. if (font == NULL) {
  316. LLOGE("font_load: failed to create hzfont");
  317. return 0;
  318. }
  319. } else if (strcmp(type, "bin") == 0) {
  320. const char *path = luaL_checkstring(L, 2);
  321. font = lv_binfont_create(path);
  322. if (font == NULL) {
  323. LLOGE("font_load: failed to create bin font");
  324. return 0;
  325. }
  326. } else {
  327. LLOGE("font_load: unsupported type %s", type);
  328. return 0;
  329. }
  330. if (font) {
  331. // 设置为全局默认字体
  332. lv_obj_set_style_text_font(lv_screen_active(), font, 0);
  333. lua_pushlightuserdata(L, font);
  334. return 1;
  335. }else{
  336. LLOGE("font_load: failed to create font");
  337. return 0;
  338. }
  339. return 0;
  340. }