-
Notifications
You must be signed in to change notification settings - Fork 22
Description
Introduce the problem
It appears to me that some LVGL constants are bound to the Lua interface as integers, and others are bound as strings.
From the example provided in the main page of the repository:
-- flex layout and align
root:set {
flex = {
flex_direction = "row",
flex_wrap = "wrap",
justify_content = "center",
align_items = "center",
align_content = "center",
},
w = 300,
h = 75,
align = lvgl.ALIGN.CENTER
}
Notice that all the "flex" properties are set as strings.
Meanwhile, the "align" (next to last line) is set as a named constant.
I can perhaps see where use of strings could have an advantage in cases where multiple LVGL constants can be "stacked together" as flags for a specific outcome. However, when the constants are part of a sequential enum (i.e. not "binary stackable flags"), use of strings seems rather odd.
Another potential usecase could stem from trying to differentiate between multiple different constants with the same name, e.g. "center"--although there should be ways around that, e.g. "lvgl.FLEX_ALIGN.CENTER". Possibly harder would be getting the linter to suggest from "FLEX_ALIGN" on those properties over just "ALIGN"...?
In source, here is where the "align" constants are defined:
Lines 125 to 150 in d25acfb
| static const rotable_Reg align_const_table[] = { | |
| {.name = "DEFAULT", .integer = LV_ALIGN_DEFAULT }, | |
| {.name = "TOP_LEFT", .integer = LV_ALIGN_TOP_LEFT }, | |
| {.name = "TOP_MID", .integer = LV_ALIGN_TOP_MID }, | |
| {.name = "TOP_RIGHT", .integer = LV_ALIGN_TOP_RIGHT }, | |
| {.name = "BOTTOM_LEFT", .integer = LV_ALIGN_BOTTOM_LEFT }, | |
| {.name = "BOTTOM_MID", .integer = LV_ALIGN_BOTTOM_MID }, | |
| {.name = "BOTTOM_RIGHT", .integer = LV_ALIGN_BOTTOM_RIGHT }, | |
| {.name = "LEFT_MID", .integer = LV_ALIGN_LEFT_MID }, | |
| {.name = "RIGHT_MID", .integer = LV_ALIGN_RIGHT_MID }, | |
| {.name = "CENTER", .integer = LV_ALIGN_CENTER }, | |
| {.name = "OUT_TOP_LEFT", .integer = LV_ALIGN_OUT_TOP_LEFT }, | |
| {.name = "OUT_TOP_MID", .integer = LV_ALIGN_OUT_TOP_MID }, | |
| {.name = "OUT_TOP_RIGHT", .integer = LV_ALIGN_OUT_TOP_RIGHT }, | |
| {.name = "OUT_BOTTOM_LEFT", .integer = LV_ALIGN_OUT_BOTTOM_LEFT }, | |
| {.name = "OUT_BOTTOM_MID", .integer = LV_ALIGN_OUT_BOTTOM_MID }, | |
| {.name = "OUT_BOTTOM_RIGHT", .integer = LV_ALIGN_OUT_BOTTOM_RIGHT}, | |
| {.name = "OUT_LEFT_TOP", .integer = LV_ALIGN_OUT_LEFT_TOP }, | |
| {.name = "OUT_LEFT_MID", .integer = LV_ALIGN_OUT_LEFT_MID }, | |
| {.name = "OUT_LEFT_BOTTOM", .integer = LV_ALIGN_OUT_LEFT_BOTTOM }, | |
| {.name = "OUT_RIGHT_TOP", .integer = LV_ALIGN_OUT_RIGHT_TOP }, | |
| {.name = "OUT_RIGHT_MID", .integer = LV_ALIGN_OUT_RIGHT_MID }, | |
| {.name = "OUT_RIGHT_BOTTOM", .integer = LV_ALIGN_OUT_RIGHT_BOTTOM}, | |
| {0, 0 }, | |
| }; |
It's a nice and straightforward dictionary of integers, linked to Lua here:
Lines 612 to 619 in d25acfb
| static void luavgl_constants_init(lua_State *L) | |
| { | |
| rotable_setfiled(L, -2, "EVENT", event_const_table); | |
| rotable_setfiled(L, -2, "FLAG", obj_flag_const_table); | |
| rotable_setfiled(L, -2, "STATE", state_const_table); | |
| rotable_setfiled(L, -2, "PART", part_const_table); | |
| rotable_setfiled(L, -2, "ALIGN", align_const_table); |
callback assigned here:
Lines 872 to 878 in d25acfb
| static const luavgl_property_ops_t obj_property_ops[] = { | |
| {.name = "align", .ops = obj_property_align }, | |
| {.name = "id", .ops = obj_property_id }, | |
| {.name = "h", .ops = obj_property_h }, | |
| {.name = "w", .ops = obj_property_w }, | |
| {.name = "user_data", .ops = obj_property_user_data}, | |
| }; |
and easily handled on the receiving end here:
Lines 803 to 811 in d25acfb
| static int obj_property_align(lua_State *L, lv_obj_t *obj, bool set) | |
| { | |
| if (set) { | |
| if (lua_isinteger(L, -1)) { | |
| lv_obj_align(obj, lua_tointeger(L, -1), 0, 0); | |
| return 0; | |
| } | |
| if (!lua_istable(L, -1)) { |
(code goes on further to allow other entries as well for more specific aligning if a Lua table is provided)
Conversely, in "luavgl_to_flex_align" (among several others), it's just a list of sequential strcmps with the goal of getting the corresponding integer constant:
Lines 196 to 221 in d25acfb
| static lv_flex_align_t luavgl_to_flex_align(lua_State *L, int idx) | |
| { | |
| if (lua_type(L, idx) != LUA_TSTRING) | |
| return LV_FLEX_ALIGN_START; | |
| const char *str = lua_tostring(L, idx); | |
| if (lv_strcmp("flex-start", str) == 0) | |
| return LV_FLEX_ALIGN_START; | |
| if (lv_strcmp("flex-end", str) == 0) | |
| return LV_FLEX_ALIGN_END; | |
| if (lv_strcmp("center", str) == 0) | |
| return LV_FLEX_ALIGN_CENTER; | |
| if (lv_strcmp("space-evenly", str) == 0) | |
| return LV_FLEX_ALIGN_SPACE_EVENLY; | |
| if (lv_strcmp("space-around", str) == 0) | |
| return LV_FLEX_ALIGN_SPACE_AROUND; | |
| if (lv_strcmp("space-between", str) == 0) | |
| return LV_FLEX_ALIGN_SPACE_BETWEEN; | |
| return LV_FLEX_ALIGN_START; | |
| } |
Note that with "flex_direction", strstr is used to allow "-reverse" as a flag keyword; however, as there are only 4 options, I still think this would better be handled with an integer constant. Besides, Lua allows adding together defined values:
Lines 256 to 274 in d25acfb
| /** | |
| * flex-direction: | |
| * row | row-reverse | column | column-reverse | |
| */ | |
| lua_getfield(L, -1, "flex_direction"); | |
| if (lua_type(L, -1) == LUA_TSTRING) { | |
| str = lua_tostring(L, -1); | |
| /* starts with */ | |
| if (lv_strcmp("row", str) == 0) { | |
| flow = LV_FLEX_FLOW_ROW; | |
| } else if (lv_strcmp("column", str) == 0) { | |
| flow = LV_FLEX_FLOW_COLUMN; | |
| } | |
| /* if reverse presents */ | |
| if (luavgl_strstr(str, "-reverse")) { | |
| flow |= LV_FLEX_REVERSE; | |
| } | |
| } |
All that to say...I am not well versed in Lua, so I could be missing something obvious.
But: Is there a specific reason for the use of strings when binding LVGL constants to Lua?
Proposal
Port all "strcmp" sequential argument parsing to named constants?