luat_lib_easylvgl.c 11 KB

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