1
0
mirror of https://github.com/esphome/esphome.git synced 2025-03-21 10:08:15 +00:00
2025-01-15 14:29:51 +13:00

149 lines
5.2 KiB
Python

from esphome import config_validation as cv
from esphome.const import CONF_BUTTON, CONF_ID, CONF_ITEMS, CONF_TEXT
from esphome.core import ID
from esphome.cpp_generator import new_Pvariable, static_const_array
from esphome.cpp_types import nullptr
from ..defines import (
CONF_BODY,
CONF_BUTTON_STYLE,
CONF_BUTTONS,
CONF_CLOSE_BUTTON,
CONF_MSGBOXES,
CONF_TITLE,
TYPE_FLEX,
literal,
)
from ..helpers import add_lv_use, lvgl_components_required
from ..lv_validation import lv_bool, lv_pct, lv_text
from ..lvcode import (
EVENT_ARG,
LambdaContext,
LocalVariable,
lv,
lv_add,
lv_assign,
lv_expr,
lv_obj,
lv_Pvariable,
)
from ..schemas import STYLE_SCHEMA, STYLED_TEXT_SCHEMA, container_schema, part_schema
from ..types import LV_EVENT, char_ptr, lv_obj_t
from . import Widget, add_widgets, set_obj_properties
from .button import button_spec
from .buttonmatrix import (
BUTTONMATRIX_BUTTON_SCHEMA,
CONF_BUTTON_TEXT_LIST_ID,
buttonmatrix_spec,
get_button_data,
lv_buttonmatrix_t,
set_btn_data,
)
from .label import CONF_LABEL
from .obj import obj_spec
CONF_MSGBOX = "msgbox"
MSGBOX_SCHEMA = container_schema(
obj_spec,
STYLE_SCHEMA.extend(
{
cv.GenerateID(CONF_ID): cv.declare_id(lv_obj_t),
cv.Required(CONF_TITLE): STYLED_TEXT_SCHEMA,
cv.Optional(CONF_BODY, default=""): STYLED_TEXT_SCHEMA,
cv.Optional(CONF_BUTTONS): cv.ensure_list(BUTTONMATRIX_BUTTON_SCHEMA),
cv.Optional(CONF_BUTTON_STYLE): part_schema(buttonmatrix_spec.parts),
cv.Optional(CONF_CLOSE_BUTTON, default=True): lv_bool,
cv.GenerateID(CONF_BUTTON_TEXT_LIST_ID): cv.declare_id(char_ptr),
}
),
)
async def msgbox_to_code(top_layer, conf):
"""
Construct a message box. This consists of a full-screen translucent background enclosing a centered container
with an optional title, body, close button and a button matrix. And any other widgets the user cares to add
:param conf: The config data
:return: code to add to the init lambda
"""
add_lv_use(
TYPE_FLEX,
CONF_BUTTON,
CONF_LABEL,
CONF_MSGBOX,
*buttonmatrix_spec.get_uses(),
*button_spec.get_uses(),
)
lvgl_components_required.add("BUTTONMATRIX")
messagebox_id = conf[CONF_ID]
outer_id = f"{messagebox_id.id}_outer"
outer = lv_Pvariable(lv_obj_t, messagebox_id.id + "_outer")
buttonmatrix = new_Pvariable(
ID(
f"{messagebox_id.id}_buttonmatrix_",
is_declaration=True,
type=lv_buttonmatrix_t,
)
)
msgbox = lv_Pvariable(lv_obj_t, messagebox_id.id)
outer_widget = Widget.create(outer_id, outer, obj_spec, conf)
outer_widget.move_to_foreground = True
msgbox_widget = Widget.create(messagebox_id, msgbox, obj_spec, conf)
msgbox_widget.outer = outer_widget
buttonmatrix_widget = Widget.create(
str(buttonmatrix), buttonmatrix, buttonmatrix_spec, conf
)
text_list, ctrl_list, width_list, _ = await get_button_data(
(conf,), buttonmatrix_widget
)
text_id = conf[CONF_BUTTON_TEXT_LIST_ID]
text_list = static_const_array(text_id, text_list)
text = await lv_text.process(conf[CONF_BODY].get(CONF_TEXT, ""))
title = await lv_text.process(conf[CONF_TITLE].get(CONF_TEXT, ""))
close_button = conf[CONF_CLOSE_BUTTON]
lv_assign(outer, lv_expr.obj_create(top_layer))
lv_obj.set_width(outer, lv_pct(100))
lv_obj.set_height(outer, lv_pct(100))
lv_obj.set_style_bg_opa(outer, 128, 0)
lv_obj.set_style_bg_color(outer, literal("lv_color_black()"), 0)
lv_obj.set_style_border_width(outer, 0, 0)
lv_obj.set_style_pad_all(outer, 0, 0)
lv_obj.set_style_radius(outer, 0, 0)
outer_widget.add_flag("LV_OBJ_FLAG_HIDDEN")
lv_assign(
msgbox, lv_expr.msgbox_create(outer, title, text, text_list, close_button)
)
lv_obj.set_style_align(msgbox, literal("LV_ALIGN_CENTER"), 0)
lv_add(buttonmatrix.set_obj(lv_expr.msgbox_get_btns(msgbox)))
if button_style := conf.get(CONF_BUTTON_STYLE):
button_style = {CONF_ITEMS: button_style}
await set_obj_properties(buttonmatrix_widget, button_style)
await set_obj_properties(msgbox_widget, conf)
await add_widgets(msgbox_widget, conf)
async with LambdaContext(EVENT_ARG, where=messagebox_id) as close_action:
outer_widget.add_flag("LV_OBJ_FLAG_HIDDEN")
if close_button:
with LocalVariable(
"close_btn_", lv_obj_t, lv_expr.msgbox_get_close_btn(msgbox)
) as close_btn:
lv_obj.remove_event_cb(close_btn, nullptr)
lv_obj.add_event_cb(
close_btn,
await close_action.get_lambda(),
LV_EVENT.CLICKED,
nullptr,
)
else:
lv_obj.add_event_cb(
outer, await close_action.get_lambda(), LV_EVENT.CLICKED, nullptr
)
if len(ctrl_list) != 0 or len(width_list) != 0:
set_btn_data(buttonmatrix.obj, ctrl_list, width_list)
async def msgboxes_to_code(lv_component, config):
top_layer = lv.disp_get_layer_top(lv_component.get_disp())
for conf in config.get(CONF_MSGBOXES, ()):
await msgbox_to_code(top_layer, conf)