Implemented tabview

This commit is contained in:
clydebarrow 2024-05-13 21:18:11 +10:00
parent 891c7833b5
commit 74630d4c17
4 changed files with 162 additions and 63 deletions

View File

@ -62,6 +62,8 @@ from esphome.const import (
CONF_TYPE,
CONF_NAME,
CONF_POSITION,
CONF_SIZE,
CONF_INDEX,
)
from esphome.cpp_generator import LambdaExpression
@ -864,7 +866,7 @@ def container_schema(widget_type, extras=None):
def validator(value):
result = schema
ltype = df.TYPE_NONE
if layout := value.get(df.CONF_LAYOUT):
if value and (layout := value.get(df.CONF_LAYOUT)):
if not isinstance(layout, dict):
raise cv.Invalid("Layout value must be a dict")
ltype = layout.get(CONF_TYPE)
@ -887,14 +889,15 @@ def any_widget_schema(extras=None):
return cv.Any(dict(map(lambda wt: widget_schema(wt, extras), WIDGET_TYPES)))
TILE_SCHEMA = any_widget_schema(
{
cv.Required(CONF_ROW): lv_int,
cv.Required(df.CONF_COLUMN): lv_int,
cv.GenerateID(df.CONF_TILE_ID): cv.declare_id(ty.lv_tile_t),
cv.Optional(df.CONF_DIR, default="ALL"): df.TILE_DIRECTIONS.several_of,
}
)
WIDGET_SCHEMA = any_widget_schema()
TILE_SCHEMA = {
cv.Required(CONF_ROW): lv_int,
cv.Required(df.CONF_COLUMN): lv_int,
cv.GenerateID(): cv.declare_id(ty.lv_tile_t),
cv.Optional(df.CONF_DIR, default="ALL"): df.TILE_DIRECTIONS.several_of,
cv.Required(df.CONF_WIDGETS): cv.ensure_list(WIDGET_SCHEMA),
}
TILEVIEW_SCHEMA = {
cv.Required(df.CONF_TILES): cv.ensure_list(TILE_SCHEMA),
@ -907,15 +910,16 @@ TILEVIEW_SCHEMA = {
),
}
TAB_SCHEMA = any_widget_schema(
{
cv.Required(CONF_NAME): cv.string,
cv.GenerateID(df.CONF_TILE_ID): cv.declare_id(ty.lv_tab_t),
cv.Optional(CONF_POSITION, default="ALL"): df.DIRECTIONS.one_of,
}
)
TAB_SCHEMA = {
cv.Required(CONF_NAME): cv.string,
cv.GenerateID(): cv.declare_id(ty.lv_tab_t),
cv.Required(df.CONF_WIDGETS): cv.ensure_list(WIDGET_SCHEMA),
}
TABVIEW_SCHEMA = {
cv.Required(df.CONF_TABS): cv.ensure_list(TAB_SCHEMA),
cv.Optional(CONF_POSITION, default="top"): df.DIRECTIONS.one_of,
cv.Optional(CONF_SIZE, default="10%"): lv.size,
cv.Optional(CONF_ON_VALUE): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
@ -925,7 +929,6 @@ TABVIEW_SCHEMA = {
),
}
WIDGET_SCHEMA = any_widget_schema()
MSGBOX_SCHEMA = STYLE_SCHEMA.extend(
{
@ -1086,6 +1089,16 @@ def collect_parts(config):
return parts
async def add_widgets(parent: Widget, config: dict):
init = []
if widgets := config.get(df.CONF_WIDGETS):
for widg in widgets:
w_type, w_cnfig = next(iter(widg.items()))
ext_init = await widget_to_code(w_cnfig, w_type, parent)
init.extend(ext_init)
return init
async def set_obj_properties(widg: Widget, config):
"""Return a list of C++ statements to apply properties to an ty.lv_obj_t"""
init = []
@ -1234,22 +1247,38 @@ async def obj_to_code(_, __):
return []
def tabview_obj_creator(parent: Widget, config: dict):
return (
f"lv_tabview_create({parent.obj}, {config[CONF_POSITION]}, {config[CONF_SIZE]})"
)
async def tabview_to_code(tv: Widget, config: dict):
init = []
for widg in config[df.CONF_TABS]:
w_id = widg[CONF_ID]
tab_obj = cg.Pvariable(w_id, cg.nullptr, type_=ty.lv_tab_t)
tab = Widget(tab_obj, ty.lv_tab_t)
widget_map[w_id] = tab
init.append(f'{tab_obj} = lv_tabview_add_tab({tv.obj}, "{widg[CONF_NAME]}")')
init.extend(await add_widgets(tab, widg))
return init
async def tileview_to_code(var: Widget, config: dict):
init = []
for widg in config[df.CONF_TILES]:
w_type, wc = next(iter(widg.items()))
w_id = wc[df.CONF_TILE_ID]
w_id = widg[CONF_ID]
tile_obj = cg.Pvariable(w_id, cg.nullptr, type_=ty.lv_obj_t)
tile = Widget(tile_obj, ty.lv_tile_t)
widget_map[w_id] = tile
dirs = wc[df.CONF_DIR]
dirs = widg[df.CONF_DIR]
if isinstance(dirs, list):
dirs = "|".join(dirs)
init.append(
f"{tile.obj} = lv_tileview_add_tile({var.obj}, {wc[df.CONF_COLUMN]}, {wc[CONF_ROW]}, {dirs})"
f"{tile.obj} = lv_tileview_add_tile({var.obj}, {widg[df.CONF_COLUMN]}, {widg[CONF_ROW]}, {dirs})"
)
ext_init = await widget_to_code(wc, w_type, tile)
init.extend(ext_init)
init.extend(await add_widgets(tile, widg))
return init
@ -1266,11 +1295,7 @@ async def page_to_code(config, pconf, index):
# Set outer config first
init.extend(await set_obj_properties(page, config))
init.extend(await set_obj_properties(page, pconf))
if df.CONF_WIDGETS in pconf:
for widg in pconf[df.CONF_WIDGETS]:
w_type, w_cnfig = next(iter(widg.items()))
ext_init = await widget_to_code(w_cnfig, w_type, page)
init.extend(ext_init)
init.extend(await add_widgets(page, pconf))
return var, init
@ -1332,11 +1357,38 @@ async def tileview_select(config, action_id, template_arg, args):
init = [f"lv_obj_set_tile({widget.obj}, {tile}, {config[df.CONF_ANIMATED]})"]
else:
init = [
f"lv_obj_set_tile_id({widget.obj}, {config[df.CONF_COLUMN]}, {config[CONF_ROW]}, {config[df.CONF_ANIMATED]})"
f"lv_obj_set_tile_id({widget.obj}, {config[df.CONF_COLUMN]}, {config[CONF_ROW]}, {config[df.CONF_ANIMATED]})",
f" lv_event_send({widget.obj}, LV_EVENT_VALUE_CHANGED, nullptr);",
]
return await action_to_code(init, action_id, widget, template_arg, args)
@automation.register_action(
"lvgl.tabview.select",
ty.ObjUpdateAction,
cv.Schema(
{
cv.Required(CONF_ID): cv.use_id(ty.lv_tabview_t),
cv.Optional(df.CONF_ANIMATED, default=False): lv.animated,
cv.Exclusive(CONF_INDEX, CONF_INDEX): lv_int,
cv.Exclusive(df.CONF_TAB_ID, CONF_INDEX): cv.use_id(ty.lv_tab_t),
},
).add_extra(cv.has_at_least_one_key(CONF_INDEX, df.CONF_TAB_ID)),
)
async def tabview_select(config, action_id, template_arg, args):
widget = await get_widget(config[CONF_ID])
if tab := config.get(df.CONF_TAB_ID):
tab = await cg.get_variable(tab)
index = f"lv_obj_get_index(lv_tabview_get_content({tab}))"
else:
index = config[CONF_INDEX]
init = [
f"lv_tabview_set_act({widget.obj}, {index}, {config[df.CONF_ANIMATED]})",
f" lv_event_send({widget.obj}, LV_EVENT_VALUE_CHANGED, nullptr);",
]
return await action_to_code(init, action_id, widget, template_arg, args)
@automation.register_action(
"lvgl.spinbox.increment",
ty.ObjUpdateAction,
@ -2121,9 +2173,7 @@ async def update_to_code(config, action_id, widget: Widget, init, template_arg,
and widget.type.value_property in config
):
init.append(
f"""
lv_event_send({widget.obj}, LV_EVENT_VALUE_CHANGED, nullptr);
"""
f" lv_event_send({widget.obj}, LV_EVENT_VALUE_CHANGED, nullptr);"
)
return await action_to_code(init, action_id, widget, template_arg, args)
@ -2229,6 +2279,10 @@ def spinner_obj_creator(parent: Widget, config: dict):
return f"lv_spinner_create({parent.obj}, {config[df.CONF_SPIN_TIME].total_milliseconds}, {config[df.CONF_ARC_LENGTH] // 10})"
def tab_obj_creator(parent: Widget, config: dict):
return f"lv_tabview_add_tab({parent.obj}, {config[CONF_NAME]})"
async def widget_to_code(w_cnfig, w_type, parent: Widget):
init = []
@ -2256,8 +2310,7 @@ async def widget_to_code(w_cnfig, w_type, parent: Widget):
if widgets := w_cnfig.get(df.CONF_WIDGETS):
for widg in widgets:
sub_type, sub_config = next(iter(widg.items()))
ext_init = await widget_to_code(sub_config, sub_type, widget)
init.extend(ext_init)
init.extend(await widget_to_code(sub_config, sub_type, widget))
fun = f"{w_type}_to_code"
if fun := globals().get(fun):
init.extend(await fun(widget, w_cnfig))

View File

@ -407,6 +407,7 @@ CONF_STYLE_DEFINITIONS = "style_definitions"
CONF_STYLE_ID = "style_id"
CONF_SKIP = "skip"
CONF_SYMBOL = "symbol"
CONF_TAB_ID = "tab_id"
CONF_TABS = "tabs"
CONF_TEXT = "text"
CONF_TILE = "tile"

View File

@ -106,7 +106,7 @@ lv_line_t = LvType("lv_line_t")
lv_img_t = LvType("lv_img_t")
lv_animimg_t = LvType("lv_animimg_t")
lv_tile_t = LvType("lv_tileview_tile_t")
lv_tab_t = LvType("lv_tabview_tab_t")
lv_tab_t = LvType("lv_obj_t")
lv_spinbox_t = LvNumber("lv_spinbox_t")
lv_arc_t = LvNumber("lv_arc_t")
lv_bar_t = LvNumber("lv_bar_t")
@ -145,6 +145,11 @@ lv_tileview_t = LvType(
largs=[(lv_obj_t_ptr, "tile")],
lvalue=lambda w: f"lv_tileview_get_tile_act({w.obj})",
)
lv_tabview_t = LvType(
"lv_tabview_t",
largs=[(lv_obj_t_ptr, "tab")],
lvalue=lambda w: f"lv_obj_get_child(lv_tabview_get_content({w.obj}), lv_tabview_get_tab_act({w.obj}))",
)
lv_spinner_t = lv_obj_t
lv_ticks_t = lv_obj_t
lv_tick_style_t = lv_obj_t

View File

@ -56,7 +56,7 @@ select:
animated: true
image:
- id: cat_image
- id: cat_img
file: $component_dir/cat.png
- id: dog_img
file: $component_dir/dog.png
@ -82,7 +82,7 @@ lvgl:
default_font: montserrat_14
bg_color: my_light_red
disp_bg_color: my_light_red
disp_bg_image: cat_image
disp_bg_image: cat_img
style_definitions:
- id: style_test
bg_color: 0x2F8CD8
@ -361,7 +361,7 @@ lvgl:
r_mod: -4
- img:
id: needle_img
src: cat_image
src: cat_img
value: 4
pivot_x: 31
pivot_y: 9
@ -422,7 +422,7 @@ lvgl:
flex_align_cross: center
flex_align_track: start
align: CENTER
src: cat_image
src: cat_img
id: img_id
radius: 11
clip_corner: true
@ -434,7 +434,7 @@ lvgl:
- animimg:
align: CENTER
id: anim_id
src: [cat_image, dog_img]
src: [cat_img, dog_img]
duration: 600ms
on_click:
then:
@ -493,31 +493,71 @@ lvgl:
then:
- logger.log: "Cat tile is now showing"
tiles:
- img:
tile_id: cat_tile
dir: [LEFT, top]
row: 0
column: 0
align: center
src: cat_image
on_click:
then:
- lvgl.tileview.select:
id: tv_id
row: 1
column: 0
animated: false
- id: cat_tile
dir: [LEFT, top]
row: 0
column: 0
widgets:
- img:
align: center
src: cat_img
on_click:
then:
- lvgl.tileview.select:
id: tv_id
row: 1
column: 0
animated: false
- img:
row: 1
column: 0
src: dog_img
on_click:
- id: dog_tile
row: 1
column: 0
widgets:
- img:
src: dog_img
on_click:
then:
- lvgl.tileview.select:
id: tv_id
tile_id: cat_tile
animated: true
- id: tabview_page
widgets:
- tabview:
id: tabview_id
width: 100%
height: 100%
position: top
on_value:
then:
- if:
condition:
lambda: return tab == id(tabview_tab_1);
then:
- lvgl.tileview.select:
id: tv_id
tile_id: cat_tile
animated: true
- logger.log: "Dog tab is now showing"
tabs:
- name: Tab1
id: tabview_tab_1
widgets:
- img:
src: dog_img
on_click:
then:
- lvgl.tabview.select:
id: tabview_id
tab_id: tabview_tab_2
animated: true
- name: Tab1
id: tabview_tab_2
widgets:
- img:
src: cat_img
on_click:
then:
- lvgl.tabview.select:
id: tabview_id
tab_id: tabview_tab_1
animated: true
- id: keyboard_page
widgets:
- label: