/** **************************************************************************************************** * @file ui_common.c * @author HiFi Player Project * @version V1.2 * @date 2026-01-01 * @brief 界面共用组件实现 **************************************************************************************************** */ #include "ui_common.h" #include #include /* 底部按键提示条的布局参数 */ #define KEY_BAR_Y 196 #define KEY_BAR_W 74 #define KEY_BAR_H 40 #define KEY_BAR_GAP 4 #define KEY_BAR_X0 6 void ui_style_screen(lv_obj_t *scr) { lv_obj_clear_flag(scr, LV_OBJ_FLAG_SCROLLABLE); lv_obj_set_style_bg_color(scr, lv_color_hex(UI_COL_BG), LV_PART_MAIN); lv_obj_set_style_bg_opa(scr, LV_OPA_COVER, LV_PART_MAIN); lv_obj_set_style_pad_all(scr, 0, LV_PART_MAIN); lv_obj_set_style_text_color(scr, lv_color_hex(UI_COL_TEXT), LV_PART_MAIN); } lv_obj_t *ui_card(lv_obj_t *parent, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h, uint32_t color, lv_coord_t radius) { lv_obj_t *obj = lv_obj_create(parent); lv_obj_set_pos(obj, x, y); lv_obj_set_size(obj, w, h); lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLLABLE); lv_obj_set_style_bg_color(obj, lv_color_hex(color), LV_PART_MAIN); lv_obj_set_style_bg_opa(obj, LV_OPA_COVER, LV_PART_MAIN); lv_obj_set_style_radius(obj, radius, LV_PART_MAIN); lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN); lv_obj_set_style_pad_all(obj, 0, LV_PART_MAIN); return obj; } lv_obj_t *ui_label(lv_obj_t *parent, const char *text, const lv_font_t *font, uint32_t color) { lv_obj_t *label = lv_label_create(parent); lv_label_set_text(label, text); lv_obj_set_style_text_font(label, font, LV_PART_MAIN); lv_obj_set_style_text_color(label, lv_color_hex(color), LV_PART_MAIN); return label; } void ui_label_set_if_changed(lv_obj_t *label, const char *text) { if (strcmp(lv_label_get_text(label), text) != 0) { lv_label_set_text(label, text); } } void ui_format_time(uint32_t seconds, char *buffer, size_t size) { snprintf(buffer, size, "%02u:%02u", (unsigned)((seconds / 60) % 100), (unsigned)(seconds % 60)); } /* ---------------- 按键提示条 ---------------- */ void ui_key_bar_create(lv_obj_t *parent, ui_key_bar_t *bar, const char *const symbols[APP_KEY_NUM], const char *const captions[APP_KEY_NUM], const bool enabled[APP_KEY_NUM]) { memset(bar, 0, sizeof(*bar)); bar->highlight = -1; for (int i = 0; i < APP_KEY_NUM; i++) { bool en = enabled[i]; bar->enabled[i] = en; lv_obj_t *card = ui_card(parent, (lv_coord_t)(KEY_BAR_X0 + i * (KEY_BAR_W + KEY_BAR_GAP)), KEY_BAR_Y, KEY_BAR_W, KEY_BAR_H, UI_COL_CARD, 8); bar->card[i] = card; bar->icon[i] = ui_label(card, (symbols != NULL) ? symbols[i] : "", &lv_font_montserrat_16, en ? UI_COL_ACCENT : UI_COL_DIM); lv_obj_align(bar->icon[i], LV_ALIGN_TOP_MID, 0, 2); bar->caption[i] = ui_label(card, captions[i], &lv_font_montserrat_12, en ? UI_COL_SUB : UI_COL_DIM); lv_obj_align(bar->caption[i], LV_ALIGN_BOTTOM_MID, 0, -3); } } void ui_key_bar_set_highlight(ui_key_bar_t *bar, int index) { if (bar->highlight == index) { return; /* 状态未变化,避免无谓重绘 */ } bar->highlight = index; for (int i = 0; i < APP_KEY_NUM; i++) { bool on = (i == index) && bar->enabled[i]; lv_obj_set_style_bg_color(bar->card[i], lv_color_hex(on ? UI_COL_ACCENT : UI_COL_CARD), LV_PART_MAIN); lv_obj_set_style_text_color(bar->icon[i], lv_color_hex(bar->enabled[i] ? (on ? UI_COL_BG : UI_COL_ACCENT) : UI_COL_DIM), LV_PART_MAIN); } } void ui_key_bar_set_icon(ui_key_bar_t *bar, int key, const char *symbol) { if ((key < 0) || (key >= APP_KEY_NUM) || (symbol == NULL)) { return; } ui_label_set_if_changed(bar->icon[key], symbol); } void ui_key_bar_set_caption(ui_key_bar_t *bar, int key, const char *caption) { if ((key < 0) || (key >= APP_KEY_NUM) || (caption == NULL)) { return; } ui_label_set_if_changed(bar->caption[key], caption); } /* ---------------- 按键高亮 ---------------- */ void ui_flash_trigger(ui_flash_t *flash, int key) { flash->key = key; flash->tick = lv_tick_get(); } int ui_flash_active(const ui_flash_t *flash) { if ((flash->key < 0) || (flash->key >= APP_KEY_NUM)) { return -1; } return (lv_tick_elaps(flash->tick) < UI_KEY_FLASH_MS) ? (int)flash->key : -1; }