#include "luavgl.h" #include "private.h" #define FONT_DEFAULT_SIZE 12 #define _ARRAY_LEN(a) (sizeof(a) / sizeof(a[0])) /** * Follow css style, specify the name by name family, name size, * name weight. Font weight can be numeric value or 'bold'. Alls strings * are converted to lower-case before matching with local supported name. * * weight named weight * 100 thin * 200 extra light * 300 light * 400 normal (*default) * 500 medium * 600 semi bold * 700 bold * 800 extra bold * 900 ultra bold * * Only normal weight is supported to builtin name. * * Font returned to lua is a userdata, it's used by object style, or style * directly. If name is no longer ref'ed by any object or style, it's * gc'ed. */ /** * lvgl.Font("montserrat, unscii", 8, bold) * lvgl.Font("montserrat", 8) * lvgl.Font("montserrat") * * return nil if failed */ typedef enum { FONT_WEIGHT_THIN = 100, FONT_WEIGHT_EXTRA_LIGHT = 200, FONT_WEIGHT_LIGHT = 300, FONT_WEIGHT_NORMAL = 400, FONT_WEIGHT_MEDIUM = 500, FONT_WEIGHT_SEMI_BOLD = 600, FONT_WEIGHT_BOLD = 700, FONT_WEIGHT_EXTRA_BOLD = 800, FONT_WEIGHT_ULTRA_BOLD = 900, } font_weight_t; static const struct { char *name; int value; } g_named_weight[] = { {"thin", 100}, {"extra light", 200}, {"light", 300}, {"normal", 400}, {"medium", 500}, {"semi bold", 600}, {"bold", 700}, {"extra bold", 800}, {"ultra bold", 900}, }; static const struct { int size; const lv_font_t *font; } g_builtin_montserrat[] = { #if LV_FONT_MONTSERRAT_8 {8, &lv_font_montserrat_8 }, #endif #if LV_FONT_MONTSERRAT_10 {10, &lv_font_montserrat_10}, #endif #if LV_FONT_MONTSERRAT_12 {12, &lv_font_montserrat_12}, #endif #if LV_FONT_MONTSERRAT_14 {14, &lv_font_montserrat_14}, #endif #if LV_FONT_MONTSERRAT_16 {16, &lv_font_montserrat_16}, #endif #if LV_FONT_MONTSERRAT_18 {18, &lv_font_montserrat_18}, #endif #if LV_FONT_MONTSERRAT_20 {20, &lv_font_montserrat_20}, #endif #if LV_FONT_MONTSERRAT_22 {22, &lv_font_montserrat_22}, #endif #if LV_FONT_MONTSERRAT_24 {24, &lv_font_montserrat_24}, #endif #if LV_FONT_MONTSERRAT_26 {26, &lv_font_montserrat_26}, #endif #if LV_FONT_MONTSERRAT_28 {28, &lv_font_montserrat_28}, #endif #if LV_FONT_MONTSERRAT_30 {30, &lv_font_montserrat_30}, #endif #if LV_FONT_MONTSERRAT_32 {32, &lv_font_montserrat_32}, #endif #if LV_FONT_MONTSERRAT_34 {34, &lv_font_montserrat_34}, #endif #if LV_FONT_MONTSERRAT_36 {36, &lv_font_montserrat_36}, #endif #if LV_FONT_MONTSERRAT_38 {38, &lv_font_montserrat_38}, #endif #if LV_FONT_MONTSERRAT_40 {40, &lv_font_montserrat_40}, #endif #if LV_FONT_MONTSERRAT_42 {42, &lv_font_montserrat_42}, #endif #if LV_FONT_MONTSERRAT_44 {44, &lv_font_montserrat_44}, #endif #if LV_FONT_MONTSERRAT_46 {46, &lv_font_montserrat_46}, #endif #if LV_FONT_MONTSERRAT_48 {48, &lv_font_montserrat_48}, #endif }; static int luavgl_get_named_weight(const char *name) { if (name == NULL) { return FONT_DEFAULT_SIZE; } for (int i = 0; i < _ARRAY_LEN(g_named_weight); i++) { if (strcmp(name, g_named_weight[i].name) == 0) { return g_named_weight[i].value; } } return FONT_DEFAULT_SIZE; } static char *to_lower(char *str) { for (char *s = str; *s; ++s) *s = *s >= 'A' && *s <= 'Z' ? *s | 0x60 : *s; return str; } static const lv_font_t *_luavgl_font_create(lua_State *L, const char *name, int size, int weight) { /* check builtin font firstly. */ if (strcmp(name, "montserrat") == 0) { if (FONT_WEIGHT_NORMAL != weight) return NULL; for (int i = 0; i < _ARRAY_LEN(g_builtin_montserrat); i++) { if (size == g_builtin_montserrat[i].size) { return g_builtin_montserrat[i].font; } } } else if (strcmp(name, "unscii") == 0) { if (FONT_WEIGHT_NORMAL != weight) return NULL; #if LV_FONT_UNSCII_8 if (size == 8) return &lv_font_unscii_8; #endif #if LV_FONT_UNSCII_16 if (size == 16) return &lv_font_unscii_16; #endif } #if LV_FONT_MONTSERRAT_12_SUBPX else if (strcmp(name, "montserrat_subpx") == 0) { if (size == 12) return &lv_font_montserrat_12_subpx; } #endif #if LV_FONT_DEJAVU_16_PERSIAN_HEBREW else if (strcmp(name, "dejavu_persian_hebrew") == 0) { if (size == 16) return &lv_font_dejavu_16_persian_hebrew; } #endif #if LV_FONT_SIMSUN_16_CJK else if (strcmp(name, "dejavu_persian_hebrew") == 0) { if (size == 16) return &lv_font_simsun_16_cjk; } #endif /* not built-in font, check extension */ luavgl_ctx_t *ctx = luavgl_context(L); if (ctx->make_font) { return ctx->make_font(name, size, weight); } return NULL; } /** * Dynamic font family fallback is not supported. * The fallback only happen when font creation fails and continue to try next * one. Fallback logic in lvgl is supposed to be system wide. * * lvgl.Font("MiSansW medium, montserrat", 24, "normal") */ static int luavgl_font_create(lua_State *L) { int weight; int size; const char *name; const lv_font_t *font = NULL; if (!lua_isstring(L, 1)) { return luaL_argerror(L, 1, "expect string"); } /* size is optional, default to FONT_DEFAULT_SIZE */ size = lua_tointeger(L, 2); if (size == 0) { size = FONT_DEFAULT_SIZE; } if (!lua_isnoneornil(L, 3)) { if (lua_isinteger(L, 3)) { weight = lua_tointeger(L, 3); } else { char *luastr = (char *)lua_tostring(L, 3); int len = strlen(luastr); if (len > 128) { /* not likely to happen */ return luaL_argerror(L, 3, "too long"); } char s[len + 1]; strcpy(s, luastr); weight = luavgl_get_named_weight(to_lower(s)); } } else { weight = FONT_WEIGHT_NORMAL; } name = lua_tostring(L, 1); font = _luavgl_font_create(L, name, size, weight); if (font) { lua_pushlightuserdata(L, (void *)font); return 1; } return luaL_error(L, "cannot create font."); }