应援灯颜色切换从 LVGL 渲染改为直接 DMA 填充 GRAM,彻底消除 LVGL 刷新竞争: lcd.c/lcd.h: - 新增 lcd_fill_color_with_buf() 直接 DMA 分条填充全屏纯色 - 新增 TEON(0x35) 启用 TE 内部同步信号 - 新增 lcd_read_scanline()/lcd_wait_vsync_timeout() VSYNC 读取接口 (实测 QSPI 模式下 TESLRD 始终返回 0xFFFF,软件 VSYNC 不可用) ui_ScreenSet.c: - LVGL flush 回调拦截:进入应援灯时替换为空操作,退出时恢复 解决 LVGL 周期刷新覆盖 DMA 颜色导致红色方块残留的问题 - DMA 缓冲区生命周期管理:进入时分配,退出时释放 - 颜色切换 PWM=0 黑屏遮蔽:DMA 期间完全熄灭背光,撕裂不可见 - 滑块交互优化:拖动期间锁定其他按钮 + PWM 50ms 节流 - 手动滑动检测替代 LVGL 手势(layer_top 上手势不可靠) .gitignore: 排除 docs/*.pdf 文档文件 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
585 lines
24 KiB
C
585 lines
24 KiB
C
// This file was generated by SquareLine Studio
|
||
// SquareLine Studio version: SquareLine Studio 1.6.0
|
||
// LVGL version: 8.3.11
|
||
// Project name: Lcd_Pro
|
||
|
||
#include "../ui.h"
|
||
#include "ui_ScreenImg.h" // 用于调用 ui_ScreenImg_show_delete_container
|
||
#include "../../pages/include/pages.h"
|
||
#include "../../sleep_mgr/include/sleep_mgr.h"
|
||
#include "esp_lvgl_port.h" // LVGL锁机制
|
||
#include "esp_timer.h"
|
||
#include "esp_log.h"
|
||
#include "dzbj_button.h"
|
||
#include "freertos/FreeRTOS.h"
|
||
#include "freertos/task.h"
|
||
|
||
lv_obj_t *ui_ScreenSet = NULL;lv_obj_t *ui_GlobalContainer = NULL;lv_obj_t *ui_ContainerTop = NULL;lv_obj_t *ui_ImgLowPower = NULL;lv_obj_t *ui_ImgFlashlight = NULL;lv_obj_t *ui_ImgDelete = NULL;lv_obj_t *ui_ContainerCentral = NULL;lv_obj_t *ui_SliderBrightness = NULL;lv_obj_t *ui_ImgSun = NULL;lv_obj_t *ui_LabelBrightness = NULL;lv_obj_t *ui_ArcPowerLevel = NULL;lv_obj_t *ui_ImgLightning = NULL;lv_obj_t *ui_LabelPowerLevel = NULL;
|
||
|
||
// 记录从哪个界面进入ScreenSet(用于返回)
|
||
static lv_obj_t **previous_screen = NULL;
|
||
static void (*previous_screen_init)(void) = NULL;
|
||
|
||
// 设置前一个界面(在切换到ScreenSet前调用)
|
||
void ui_ScreenSet_set_previous(lv_obj_t **screen, void (*init_func)(void)) {
|
||
previous_screen = screen;
|
||
previous_screen_init = init_func;
|
||
}
|
||
|
||
// ==================== 应援灯功能 ====================
|
||
// 行为:进入时高亮常亮 → 点击屏幕切换闪烁/常亮 → 下滑切换颜色
|
||
// 颜色切换使用直接 DMA 填充 GRAM(绕过 LVGL),约 27ms 瞬间完成
|
||
|
||
#include "lcd.h"
|
||
#include "esp_heap_caps.h"
|
||
|
||
static lv_obj_t *flashlight_overlay = NULL; // 全屏遮罩层
|
||
static lv_timer_t *flashlight_timer = NULL; // 闪烁定时器
|
||
static uint8_t flashlight_color_index = 0; // 当前颜色索引
|
||
static bool flashlight_bright = true; // 当前亮度状态(true=亮,false=暗)
|
||
static bool flashlight_blinking = false; // 是否处于闪烁状态
|
||
static uint8_t saved_brightness = 50; // 进入前保存的亮度
|
||
|
||
// DMA 缓冲区(应援灯生命周期内常驻,避免反复 malloc/free)
|
||
// 条带越大,条数越少,总传输时间越短,撕裂概率越低
|
||
// 72行 × 5条 = 360行,~15ms 完成(< 1帧 16.67ms),基本消除撕裂
|
||
#define FL_STRIP_H 72 // 每条带高度
|
||
static uint16_t *fl_dma_buf = NULL; // DMA 缓冲区指针
|
||
static size_t fl_dma_buf_size = 0; // 缓冲区像素数
|
||
|
||
// 颜色数组(RGB888,可扩展)
|
||
static const uint32_t flashlight_color_values[] = {
|
||
0xFF0000, // 红色
|
||
0x00FF00, // 绿色
|
||
0x0000FF, // 蓝色
|
||
0xFFFF00, // 黄色
|
||
0xFF00FF, // 品红
|
||
0x00FFFF, // 青色
|
||
0xFFFFFF, // 白色
|
||
};
|
||
#define FLASHLIGHT_COLOR_COUNT (sizeof(flashlight_color_values) / sizeof(flashlight_color_values[0]))
|
||
|
||
// RGB888 转 RGB565(大端字节序,匹配 LCD GRAM 格式)
|
||
static uint16_t rgb888_to_rgb565(uint32_t rgb888) {
|
||
uint8_t r = (rgb888 >> 16) & 0xFF;
|
||
uint8_t g = (rgb888 >> 8) & 0xFF;
|
||
uint8_t b = rgb888 & 0xFF;
|
||
uint16_t rgb565 = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
|
||
// ESP32 SPI LCD 使用大端字节序
|
||
return (rgb565 >> 8) | (rgb565 << 8);
|
||
}
|
||
|
||
// 用指定颜色填充 DMA 缓冲区
|
||
static void fl_fill_buf_color(uint32_t rgb888) {
|
||
if (!fl_dma_buf) return;
|
||
uint16_t color565 = rgb888_to_rgb565(rgb888);
|
||
for (size_t i = 0; i < fl_dma_buf_size; i++) {
|
||
fl_dma_buf[i] = color565;
|
||
}
|
||
}
|
||
|
||
// 分配 DMA 缓冲区(应援灯进入时调用)
|
||
static bool fl_alloc_dma_buf(void) {
|
||
if (fl_dma_buf) return true; // 已分配
|
||
fl_dma_buf_size = LCD_WID * FL_STRIP_H;
|
||
fl_dma_buf = heap_caps_malloc(fl_dma_buf_size * sizeof(uint16_t), MALLOC_CAP_DMA);
|
||
if (!fl_dma_buf) {
|
||
fl_dma_buf_size = 0;
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
// 释放 DMA 缓冲区(应援灯退出时调用)
|
||
static void fl_free_dma_buf(void) {
|
||
if (fl_dma_buf) {
|
||
heap_caps_free(fl_dma_buf);
|
||
fl_dma_buf = NULL;
|
||
fl_dma_buf_size = 0;
|
||
}
|
||
}
|
||
|
||
// ---- LVGL flush 拦截:应援灯模式下阻止 LVGL 向 LCD 写入任何数据 ----
|
||
// 仅暂停 refr timer 不够可靠(其他模块可能恢复它),
|
||
// 替换 flush 回调为空操作是最彻底的方案。
|
||
static void (*fl_original_flush_cb)(struct _lv_disp_drv_t *, const lv_area_t *, lv_color_t *) = NULL;
|
||
|
||
// 空 flush 回调:不写入 LCD,仅通知 LVGL 完成(防止 LVGL 挂起)
|
||
static void fl_dummy_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_p) {
|
||
lv_disp_flush_ready(drv);
|
||
}
|
||
|
||
// 禁用 LVGL LCD 输出(进入应援灯时调用)
|
||
static void fl_disable_lvgl_flush(void) {
|
||
lv_disp_t *disp = lv_disp_get_default();
|
||
if (disp && disp->driver) {
|
||
fl_original_flush_cb = disp->driver->flush_cb;
|
||
disp->driver->flush_cb = fl_dummy_flush_cb;
|
||
}
|
||
}
|
||
|
||
// 恢复 LVGL LCD 输出 + 强制全屏重绘(退出应援灯时调用)
|
||
static void fl_enable_lvgl_flush(void) {
|
||
lv_disp_t *disp = lv_disp_get_default();
|
||
if (disp && disp->driver && fl_original_flush_cb) {
|
||
disp->driver->flush_cb = fl_original_flush_cb;
|
||
fl_original_flush_cb = NULL;
|
||
// GRAM 已被 DMA 覆写,强制 LVGL 全屏重绘恢复正常界面
|
||
lv_obj_invalidate(lv_scr_act());
|
||
}
|
||
}
|
||
|
||
// 直接 DMA 切换颜色(独占 GRAM,LVGL flush 已禁用,无竞争)
|
||
// QSPI 模式下 TESLRD 读取无效(始终返回0xFFFF),无法软件同步 VSYNC
|
||
// 采用 PWM 微降方案:DMA 期间亮度降至极低,人眼不可见撕裂,完成后恢复
|
||
static void fl_switch_color_direct(uint32_t rgb888) {
|
||
fl_fill_buf_color(rgb888);
|
||
|
||
// 持有 LVGL 锁,确保 DMA 期间不会与 indev 等其他 SPI 操作冲突
|
||
if (lvgl_port_lock(100)) {
|
||
uint8_t restore_brightness = flashlight_bright ? 100 : 20;
|
||
|
||
// 完全关闭背光(PWM=0),DMA期间屏幕全黑,撕裂不可见
|
||
pwm_set_brightness(0);
|
||
// 等待1个PWM周期(200μs@5kHz)确保背光完全熄灭
|
||
esp_rom_delay_us(200);
|
||
|
||
lcd_fill_color_with_buf(fl_dma_buf, FL_STRIP_H);
|
||
|
||
// DMA 完成后恢复亮度,显示新颜色
|
||
pwm_set_brightness(restore_brightness);
|
||
|
||
lvgl_port_unlock();
|
||
}
|
||
}
|
||
|
||
// 闪烁定时器回调(每 500ms 切换亮暗)
|
||
static void flashlight_blink_timer_cb(lv_timer_t *timer) {
|
||
if (!flashlight_overlay) return;
|
||
flashlight_bright = !flashlight_bright;
|
||
pwm_set_brightness(flashlight_bright ? 100 : 20);
|
||
}
|
||
|
||
// 手动滑动检测(layer_top 上 LVGL 手势检测不可靠,改用坐标位移判定)
|
||
// 仅影响 overlay 对象,其他界面的 LV_EVENT_GESTURE 不受影响
|
||
static lv_coord_t fl_press_y = 0; // 按下时的 Y 坐标
|
||
static bool fl_press_valid = false; // 是否有有效的按下记录
|
||
#define FL_SWIPE_THRESHOLD 50 // 下滑判定阈值(像素)
|
||
|
||
// 切换颜色(下滑时调用)
|
||
// 无需 PWM=0 黑屏:纯色→纯色直接 DMA 覆写,~15ms 完成
|
||
static void fl_do_switch_color(void) {
|
||
bool was_blinking = flashlight_blinking;
|
||
if (flashlight_timer) {
|
||
lv_timer_pause(flashlight_timer);
|
||
}
|
||
|
||
flashlight_color_index = (flashlight_color_index + 1) % FLASHLIGHT_COLOR_COUNT;
|
||
fl_switch_color_direct(flashlight_color_values[flashlight_color_index]);
|
||
flashlight_bright = true;
|
||
|
||
if (was_blinking && flashlight_timer) {
|
||
lv_timer_resume(flashlight_timer);
|
||
}
|
||
}
|
||
|
||
// 切换闪烁状态(点击时调用)
|
||
static void fl_do_toggle_blink(void) {
|
||
flashlight_blinking = !flashlight_blinking;
|
||
if (flashlight_blinking) {
|
||
flashlight_bright = true;
|
||
pwm_set_brightness(100);
|
||
if (!flashlight_timer) {
|
||
flashlight_timer = lv_timer_create(flashlight_blink_timer_cb, 500, NULL);
|
||
}
|
||
} else {
|
||
if (flashlight_timer) {
|
||
lv_timer_del(flashlight_timer);
|
||
flashlight_timer = NULL;
|
||
}
|
||
flashlight_bright = true;
|
||
pwm_set_brightness(100);
|
||
}
|
||
}
|
||
|
||
// 遮罩层事件处理:按下记录坐标,释放时判定点击 vs 下滑
|
||
static void flashlight_overlay_event_cb(lv_event_t *e) {
|
||
lv_event_code_t code = lv_event_get_code(e);
|
||
|
||
if (code == LV_EVENT_PRESSED) {
|
||
lv_indev_t *indev = lv_indev_get_act();
|
||
lv_point_t point;
|
||
lv_indev_get_point(indev, &point);
|
||
fl_press_y = point.y;
|
||
fl_press_valid = true;
|
||
} else if (code == LV_EVENT_RELEASED) {
|
||
if (!fl_press_valid) return;
|
||
fl_press_valid = false;
|
||
|
||
lv_indev_t *indev = lv_indev_get_act();
|
||
lv_point_t point;
|
||
lv_indev_get_point(indev, &point);
|
||
lv_coord_t dy = point.y - fl_press_y;
|
||
|
||
if (dy > FL_SWIPE_THRESHOLD) {
|
||
// 下滑:切换颜色
|
||
fl_do_switch_color();
|
||
} else if (dy > -FL_SWIPE_THRESHOLD) {
|
||
// 位移小:视为点击,切换闪烁/常亮
|
||
fl_do_toggle_blink();
|
||
}
|
||
// 上滑(dy < -threshold):忽略
|
||
}
|
||
}
|
||
|
||
// 退出应援灯模式(外部调用,不恢复亮度)
|
||
void flashlight_exit(void) {
|
||
pwm_set_brightness(0);
|
||
|
||
if (lvgl_port_lock(100)) {
|
||
if (flashlight_timer) {
|
||
lv_timer_del(flashlight_timer);
|
||
flashlight_timer = NULL;
|
||
}
|
||
if (flashlight_overlay) {
|
||
lv_obj_del(flashlight_overlay);
|
||
flashlight_overlay = NULL;
|
||
}
|
||
lvgl_port_unlock();
|
||
}
|
||
|
||
flashlight_blinking = false;
|
||
fl_free_dma_buf();
|
||
|
||
// 恢复 LVGL 显示刷新(退出应援灯后 LVGL 重新接管屏幕渲染)
|
||
fl_enable_lvgl_flush();
|
||
}
|
||
|
||
// 查询应援灯是否激活
|
||
bool flashlight_is_active(void) {
|
||
return (flashlight_overlay != NULL);
|
||
}
|
||
|
||
// 获取进入应援灯前保存的亮度值
|
||
uint8_t flashlight_get_saved_brightness(void) {
|
||
return saved_brightness;
|
||
}
|
||
|
||
// 进入应援灯模式
|
||
static void show_flashlight(void) {
|
||
if (flashlight_overlay) return;
|
||
|
||
// 分配 DMA 缓冲区
|
||
if (!fl_alloc_dma_buf()) {
|
||
ESP_LOGE("Flashlight", "DMA缓冲区分配失败");
|
||
return;
|
||
}
|
||
|
||
saved_brightness = pwm_get_brightness();
|
||
|
||
// 创建全屏遮罩层
|
||
flashlight_overlay = lv_obj_create(lv_layer_top());
|
||
lv_obj_remove_style_all(flashlight_overlay);
|
||
lv_obj_set_size(flashlight_overlay, LV_HOR_RES, LV_VER_RES);
|
||
lv_obj_set_pos(flashlight_overlay, 0, 0);
|
||
|
||
// 启用滚动手势识别 + 点击
|
||
// 只需 CLICKABLE 接收触摸事件,手动检测滑动不依赖 SCROLLABLE
|
||
lv_obj_add_flag(flashlight_overlay, LV_OBJ_FLAG_CLICKABLE);
|
||
|
||
// 设置初始颜色(红色)
|
||
flashlight_color_index = 0;
|
||
lv_obj_set_style_bg_color(flashlight_overlay, lv_color_hex(flashlight_color_values[0]), 0);
|
||
lv_obj_set_style_bg_opa(flashlight_overlay, LV_OPA_COVER, 0);
|
||
|
||
// 注册事件回调(点击 + 手势)
|
||
lv_obj_add_event_cb(flashlight_overlay, flashlight_overlay_event_cb, LV_EVENT_ALL, NULL);
|
||
|
||
// 暂停 LVGL 显示刷新,应援灯模式由 DMA 独占 GRAM
|
||
// 必须在创建 overlay 后暂停,避免 LVGL 渲染 overlay 与 DMA 竞争
|
||
fl_disable_lvgl_flush();
|
||
|
||
// DMA 填充初始颜色到 GRAM
|
||
fl_switch_color_direct(flashlight_color_values[0]);
|
||
|
||
// 进入时:高亮常亮,不闪烁
|
||
flashlight_blinking = false;
|
||
flashlight_bright = true;
|
||
flashlight_timer = NULL;
|
||
pwm_set_brightness(100);
|
||
}
|
||
|
||
// ImgFlashlight点击事件:显示手电筒
|
||
static void ui_event_ImgFlashlight(lv_event_t *e) {
|
||
lv_event_code_t code = lv_event_get_code(e);
|
||
if (code == LV_EVENT_CLICKED) {
|
||
show_flashlight();
|
||
}
|
||
}
|
||
|
||
// ImgDelete 点击事件:跳转到 ScreenImg 并显示删除容器
|
||
static void ui_event_ImgDelete(lv_event_t *e) {
|
||
lv_event_code_t code = lv_event_get_code(e);
|
||
if (code == LV_EVENT_CLICKED) {
|
||
// 跳转到 ScreenImg 界面
|
||
_ui_screen_change(&ui_ScreenImg, LV_SCR_LOAD_ANIM_NONE, 0, 0, &ui_ScreenImg_screen_init);
|
||
// 显示删除容器
|
||
ui_ScreenImg_show_delete_container();
|
||
}
|
||
}
|
||
|
||
// event funtions
|
||
void ui_event_ScreenSet( lv_event_t * e) {
|
||
lv_event_code_t event_code = lv_event_get_code(e);
|
||
|
||
if ( event_code == LV_EVENT_GESTURE && lv_indev_get_gesture_dir(lv_indev_get_act()) == LV_DIR_TOP ) {
|
||
lv_indev_wait_release(lv_indev_get_act());
|
||
// 返回到之前的界面,如果没有记录则默认返回Home
|
||
if (previous_screen && previous_screen_init) {
|
||
_ui_screen_change(previous_screen, LV_SCR_LOAD_ANIM_NONE, 0, 0, previous_screen_init);
|
||
// 根据返回目标同步按键上下文
|
||
if (previous_screen == &ui_ScreenImg) {
|
||
dzbj_button_set_context(BTN_CTX_IMG);
|
||
} else {
|
||
dzbj_button_set_context(BTN_CTX_HOME);
|
||
}
|
||
} else {
|
||
_ui_screen_change(&ui_ScreenHome, LV_SCR_LOAD_ANIM_NONE, 0, 0, &ui_ScreenHome_screen_init);
|
||
dzbj_button_set_context(BTN_CTX_HOME);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 滑块交互锁定:拖动期间禁用其他按钮,防止坐标跳变导致误触
|
||
static void slider_lock_other_buttons(bool lock)
|
||
{
|
||
if (lock) {
|
||
lv_obj_clear_flag(ui_ImgDelete, LV_OBJ_FLAG_CLICKABLE);
|
||
lv_obj_clear_flag(ui_ImgFlashlight, LV_OBJ_FLAG_CLICKABLE);
|
||
lv_obj_clear_flag(ui_ImgLowPower, LV_OBJ_FLAG_CLICKABLE);
|
||
} else {
|
||
lv_obj_add_flag(ui_ImgDelete, LV_OBJ_FLAG_CLICKABLE | LV_OBJ_FLAG_ADV_HITTEST);
|
||
lv_obj_add_flag(ui_ImgFlashlight, LV_OBJ_FLAG_CLICKABLE | LV_OBJ_FLAG_ADV_HITTEST);
|
||
lv_obj_add_flag(ui_ImgLowPower, LV_OBJ_FLAG_CLICKABLE);
|
||
}
|
||
}
|
||
|
||
// PWM节流:最小更新间隔50ms,避免频繁调用
|
||
static int64_t last_brightness_update_us = 0;
|
||
|
||
void ui_event_SliderBrightness( lv_event_t * e) {
|
||
lv_event_code_t event_code = lv_event_get_code(e);
|
||
|
||
if (event_code == LV_EVENT_PRESSED) {
|
||
slider_lock_other_buttons(true);
|
||
} else if (event_code == LV_EVENT_RELEASED || event_code == LV_EVENT_PRESS_LOST) {
|
||
slider_lock_other_buttons(false);
|
||
// 松手时确保最终值写入
|
||
lv_obj_t *target = lv_event_get_target(e);
|
||
int32_t val = lv_slider_get_value(target);
|
||
if (val < 10) { val = 10; lv_slider_set_value(target, 10, LV_ANIM_OFF); }
|
||
pwm_set_brightness((uint8_t)val);
|
||
_ui_slider_set_text_value(ui_LabelBrightness, target, "", "%");
|
||
last_brightness_update_us = 0;
|
||
} else if (event_code == LV_EVENT_VALUE_CHANGED) {
|
||
lv_obj_t *target = lv_event_get_target(e);
|
||
int32_t val = lv_slider_get_value(target);
|
||
if (val < 10) { val = 10; lv_slider_set_value(target, 10, LV_ANIM_OFF); }
|
||
// 文本始终更新(轻量操作)
|
||
_ui_slider_set_text_value(ui_LabelBrightness, target, "", "%");
|
||
// PWM节流:50ms内不重复调用
|
||
int64_t now = esp_timer_get_time();
|
||
if (now - last_brightness_update_us >= 50000) {
|
||
pwm_set_brightness((uint8_t)val);
|
||
last_brightness_update_us = now;
|
||
}
|
||
}
|
||
}
|
||
|
||
// ImgLowPower点击事件:切换休眠模式
|
||
void ui_event_ImgLowPower( lv_event_t * e) {
|
||
lv_event_code_t event_code = lv_event_get_code(e);
|
||
if ( event_code == LV_EVENT_VALUE_CHANGED) {
|
||
lv_obj_t * target = lv_event_get_target(e);
|
||
// checked=true时显示s12(休眠模式),false时显示s11(正常模式)
|
||
bool checked = lv_obj_has_state(target, LV_STATE_CHECKED);
|
||
sleep_mgr_set_enabled(checked);
|
||
}
|
||
}
|
||
|
||
// build funtions
|
||
|
||
void ui_ScreenSet_screen_init(void)
|
||
{
|
||
ui_ScreenSet = lv_obj_create(NULL);
|
||
lv_obj_clear_flag( ui_ScreenSet, LV_OBJ_FLAG_SCROLLABLE ); /// Flags
|
||
lv_obj_set_style_bg_color(ui_ScreenSet, lv_color_hex(0x000000), LV_PART_MAIN | LV_STATE_DEFAULT );
|
||
lv_obj_set_style_bg_opa(ui_ScreenSet, 255, LV_PART_MAIN| LV_STATE_DEFAULT);
|
||
|
||
ui_GlobalContainer = lv_obj_create(ui_ScreenSet);
|
||
lv_obj_remove_style_all(ui_GlobalContainer);
|
||
lv_obj_set_width( ui_GlobalContainer, 360);
|
||
lv_obj_set_height( ui_GlobalContainer, 360);
|
||
lv_obj_set_align( ui_GlobalContainer, LV_ALIGN_CENTER );
|
||
lv_obj_clear_flag( ui_GlobalContainer, LV_OBJ_FLAG_CLICKABLE | LV_OBJ_FLAG_SCROLLABLE ); /// Flags
|
||
|
||
ui_ContainerTop = lv_obj_create(ui_GlobalContainer);
|
||
lv_obj_remove_style_all(ui_ContainerTop);
|
||
lv_obj_set_width( ui_ContainerTop, 240);
|
||
lv_obj_set_height( ui_ContainerTop, 80);
|
||
lv_obj_set_x( ui_ContainerTop, 0 );
|
||
lv_obj_set_y( ui_ContainerTop, -40 );
|
||
lv_obj_set_align( ui_ContainerTop, LV_ALIGN_CENTER );
|
||
lv_obj_clear_flag( ui_ContainerTop, LV_OBJ_FLAG_CLICKABLE | LV_OBJ_FLAG_SCROLLABLE ); /// Flags
|
||
|
||
ui_ImgLowPower = lv_imgbtn_create(ui_ContainerTop);
|
||
lv_imgbtn_set_src(ui_ImgLowPower, LV_IMGBTN_STATE_RELEASED, NULL, &ui_img_s11_png, NULL);
|
||
lv_imgbtn_set_src(ui_ImgLowPower, LV_IMGBTN_STATE_PRESSED, NULL, &ui_img_s11_png, NULL);
|
||
lv_imgbtn_set_src(ui_ImgLowPower, LV_IMGBTN_STATE_DISABLED, NULL, &ui_img_s12_png, NULL);
|
||
lv_imgbtn_set_src(ui_ImgLowPower, LV_IMGBTN_STATE_CHECKED_PRESSED, NULL, &ui_img_s12_png, NULL);
|
||
lv_imgbtn_set_src(ui_ImgLowPower, LV_IMGBTN_STATE_CHECKED_RELEASED, NULL, &ui_img_s12_png, NULL);
|
||
lv_obj_set_width( ui_ImgLowPower, 64);
|
||
lv_obj_set_height( ui_ImgLowPower, 64);
|
||
lv_obj_set_x( ui_ImgLowPower, -86 );
|
||
lv_obj_set_y( ui_ImgLowPower, -1 );
|
||
lv_obj_set_align( ui_ImgLowPower, LV_ALIGN_CENTER );
|
||
lv_obj_add_flag( ui_ImgLowPower, LV_OBJ_FLAG_CHECKABLE ); /// Flags
|
||
|
||
ui_ImgFlashlight = lv_img_create(ui_ContainerTop);
|
||
lv_img_set_src(ui_ImgFlashlight, &ui_img_s9_png);
|
||
lv_obj_set_width( ui_ImgFlashlight, LV_SIZE_CONTENT); /// 1
|
||
lv_obj_set_height( ui_ImgFlashlight, LV_SIZE_CONTENT); /// 1
|
||
lv_obj_set_x( ui_ImgFlashlight, -2 );
|
||
lv_obj_set_y( ui_ImgFlashlight, -1 );
|
||
lv_obj_set_align( ui_ImgFlashlight, LV_ALIGN_CENTER );
|
||
lv_obj_add_flag( ui_ImgFlashlight, LV_OBJ_FLAG_ADV_HITTEST | LV_OBJ_FLAG_CLICKABLE ); /// Flags
|
||
lv_obj_clear_flag( ui_ImgFlashlight, LV_OBJ_FLAG_SCROLLABLE ); /// Flags
|
||
|
||
ui_ImgDelete = lv_img_create(ui_ContainerTop);
|
||
lv_img_set_src(ui_ImgDelete, &ui_img_s6_png);
|
||
lv_obj_set_width( ui_ImgDelete, LV_SIZE_CONTENT); /// 1
|
||
lv_obj_set_height( ui_ImgDelete, LV_SIZE_CONTENT); /// 1
|
||
lv_obj_set_x( ui_ImgDelete, 82 );
|
||
lv_obj_set_y( ui_ImgDelete, -1 );
|
||
lv_obj_set_align( ui_ImgDelete, LV_ALIGN_CENTER );
|
||
lv_obj_add_flag( ui_ImgDelete, LV_OBJ_FLAG_ADV_HITTEST | LV_OBJ_FLAG_CLICKABLE ); /// Flags
|
||
lv_obj_clear_flag( ui_ImgDelete, LV_OBJ_FLAG_SCROLLABLE ); /// Flags
|
||
|
||
ui_ContainerCentral = lv_obj_create(ui_GlobalContainer);
|
||
lv_obj_remove_style_all(ui_ContainerCentral);
|
||
lv_obj_set_width( ui_ContainerCentral, 230);
|
||
lv_obj_set_height( ui_ContainerCentral, 70);
|
||
lv_obj_set_x( ui_ContainerCentral, 6 );
|
||
lv_obj_set_y( ui_ContainerCentral, 44 );
|
||
lv_obj_set_align( ui_ContainerCentral, LV_ALIGN_CENTER );
|
||
lv_obj_clear_flag( ui_ContainerCentral, LV_OBJ_FLAG_CLICKABLE | LV_OBJ_FLAG_SCROLLABLE ); /// Flags
|
||
|
||
ui_SliderBrightness = lv_slider_create(ui_ContainerCentral);
|
||
lv_slider_set_value( ui_SliderBrightness, 50, LV_ANIM_OFF);
|
||
if (lv_slider_get_mode(ui_SliderBrightness)==LV_SLIDER_MODE_RANGE ) lv_slider_set_left_value( ui_SliderBrightness, 0, LV_ANIM_OFF);
|
||
lv_obj_set_width( ui_SliderBrightness, 220);
|
||
lv_obj_set_height( ui_SliderBrightness, 60);
|
||
lv_obj_set_x( ui_SliderBrightness, -3 );
|
||
lv_obj_set_y( ui_SliderBrightness, 0 );
|
||
lv_obj_set_align( ui_SliderBrightness, LV_ALIGN_CENTER );
|
||
lv_obj_set_style_radius(ui_SliderBrightness, 50, LV_PART_MAIN| LV_STATE_DEFAULT);
|
||
lv_obj_set_style_bg_grad_dir(ui_SliderBrightness, LV_GRAD_DIR_NONE, LV_PART_MAIN| LV_STATE_DEFAULT);
|
||
lv_obj_set_style_blend_mode(ui_SliderBrightness, LV_BLEND_MODE_NORMAL, LV_PART_MAIN| LV_STATE_DEFAULT);
|
||
|
||
lv_obj_set_style_radius(ui_SliderBrightness, 0, LV_PART_INDICATOR| LV_STATE_DEFAULT);
|
||
lv_obj_set_style_bg_color(ui_SliderBrightness, lv_color_hex(0x64A8EB), LV_PART_INDICATOR | LV_STATE_DEFAULT );
|
||
lv_obj_set_style_bg_opa(ui_SliderBrightness, 255, LV_PART_INDICATOR| LV_STATE_DEFAULT);
|
||
|
||
lv_obj_set_style_bg_color(ui_SliderBrightness, lv_color_hex(0xFFFFFF), LV_PART_KNOB | LV_STATE_DEFAULT );
|
||
lv_obj_set_style_bg_opa(ui_SliderBrightness, 0, LV_PART_KNOB| LV_STATE_DEFAULT);
|
||
|
||
ui_ImgSun = lv_img_create(ui_ContainerCentral);
|
||
lv_img_set_src(ui_ImgSun, &ui_img_s10_png);
|
||
lv_obj_set_width( ui_ImgSun, LV_SIZE_CONTENT); /// 1
|
||
lv_obj_set_height( ui_ImgSun, LV_SIZE_CONTENT); /// 1
|
||
lv_obj_set_x( ui_ImgSun, -78 );
|
||
lv_obj_set_y( ui_ImgSun, 0 );
|
||
lv_obj_set_align( ui_ImgSun, LV_ALIGN_CENTER );
|
||
lv_obj_add_flag( ui_ImgSun, LV_OBJ_FLAG_ADV_HITTEST ); /// Flags
|
||
lv_obj_clear_flag( ui_ImgSun, LV_OBJ_FLAG_SCROLLABLE ); /// Flags
|
||
|
||
ui_LabelBrightness = lv_label_create(ui_ContainerCentral);
|
||
lv_obj_set_width( ui_LabelBrightness, LV_SIZE_CONTENT); /// 1
|
||
lv_obj_set_height( ui_LabelBrightness, LV_SIZE_CONTENT); /// 1
|
||
lv_obj_set_x( ui_LabelBrightness, 6 );
|
||
lv_obj_set_y( ui_LabelBrightness, 0 );
|
||
lv_obj_set_align( ui_LabelBrightness, LV_ALIGN_CENTER );
|
||
lv_label_set_text(ui_LabelBrightness,"50%");
|
||
lv_obj_set_style_text_color(ui_LabelBrightness, lv_color_hex(0xFFFFFF), LV_PART_MAIN | LV_STATE_DEFAULT );
|
||
lv_obj_set_style_text_opa(ui_LabelBrightness, 255, LV_PART_MAIN| LV_STATE_DEFAULT);
|
||
lv_obj_set_style_text_font(ui_LabelBrightness, &lv_font_montserrat_18, LV_PART_MAIN| LV_STATE_DEFAULT);
|
||
|
||
ui_ArcPowerLevel = lv_arc_create(ui_GlobalContainer);
|
||
lv_obj_set_width( ui_ArcPowerLevel, 320);
|
||
lv_obj_set_height( ui_ArcPowerLevel, 320);
|
||
lv_obj_set_align( ui_ArcPowerLevel, LV_ALIGN_CENTER );
|
||
lv_obj_clear_flag( ui_ArcPowerLevel, LV_OBJ_FLAG_CLICKABLE ); /// Flags
|
||
lv_arc_set_value(ui_ArcPowerLevel, 50);
|
||
lv_obj_set_style_arc_color(ui_ArcPowerLevel, lv_color_hex(0x39393E), LV_PART_MAIN | LV_STATE_DEFAULT );
|
||
lv_obj_set_style_arc_opa(ui_ArcPowerLevel, 255, LV_PART_MAIN| LV_STATE_DEFAULT);
|
||
lv_obj_set_style_arc_width(ui_ArcPowerLevel, 16, LV_PART_MAIN| LV_STATE_DEFAULT);
|
||
|
||
lv_obj_set_style_arc_color(ui_ArcPowerLevel, lv_color_hex(0x19FA29), LV_PART_INDICATOR | LV_STATE_DEFAULT );
|
||
lv_obj_set_style_arc_opa(ui_ArcPowerLevel, 255, LV_PART_INDICATOR| LV_STATE_DEFAULT);
|
||
lv_obj_set_style_arc_width(ui_ArcPowerLevel, 16, LV_PART_INDICATOR| LV_STATE_DEFAULT);
|
||
|
||
lv_obj_set_style_bg_color(ui_ArcPowerLevel, lv_color_hex(0x19FA29), LV_PART_KNOB | LV_STATE_DEFAULT );
|
||
lv_obj_set_style_bg_opa(ui_ArcPowerLevel, 255, LV_PART_KNOB| LV_STATE_DEFAULT);
|
||
|
||
ui_ImgLightning = lv_img_create(ui_GlobalContainer);
|
||
lv_img_set_src(ui_ImgLightning, &ui_img_s8_png);
|
||
lv_obj_set_width( ui_ImgLightning, LV_SIZE_CONTENT); /// 20
|
||
lv_obj_set_height( ui_ImgLightning, LV_SIZE_CONTENT); /// 20
|
||
lv_obj_set_x( ui_ImgLightning, -23 );
|
||
lv_obj_set_y( ui_ImgLightning, 121 );
|
||
lv_obj_set_align( ui_ImgLightning, LV_ALIGN_CENTER );
|
||
lv_obj_add_flag( ui_ImgLightning, LV_OBJ_FLAG_ADV_HITTEST ); /// Flags
|
||
lv_obj_clear_flag( ui_ImgLightning, LV_OBJ_FLAG_SCROLLABLE ); /// Flags
|
||
|
||
ui_LabelPowerLevel = lv_label_create(ui_GlobalContainer);
|
||
lv_obj_set_width( ui_LabelPowerLevel, LV_SIZE_CONTENT); /// 1
|
||
lv_obj_set_height( ui_LabelPowerLevel, LV_SIZE_CONTENT); /// 1
|
||
lv_obj_set_x( ui_LabelPowerLevel, 26 );
|
||
lv_obj_set_y( ui_LabelPowerLevel, 121 );
|
||
lv_obj_set_align( ui_LabelPowerLevel, LV_ALIGN_CENTER );
|
||
lv_label_set_text(ui_LabelPowerLevel,"70%");
|
||
lv_obj_set_style_text_color(ui_LabelPowerLevel, lv_color_hex(0xFFFFFF), LV_PART_MAIN | LV_STATE_DEFAULT );
|
||
lv_obj_set_style_text_opa(ui_LabelPowerLevel, 255, LV_PART_MAIN| LV_STATE_DEFAULT);
|
||
lv_obj_set_style_text_font(ui_LabelPowerLevel, &lv_font_montserrat_20, LV_PART_MAIN| LV_STATE_DEFAULT);
|
||
|
||
// 按钮只注册需要的事件,减少无效回调调用
|
||
lv_obj_add_event_cb(ui_ImgLowPower, ui_event_ImgLowPower, LV_EVENT_VALUE_CHANGED, NULL);
|
||
lv_obj_add_event_cb(ui_ImgFlashlight, ui_event_ImgFlashlight, LV_EVENT_CLICKED, NULL);
|
||
lv_obj_add_event_cb(ui_ImgDelete, ui_event_ImgDelete, LV_EVENT_CLICKED, NULL);
|
||
// 滑块需要 PRESSED/RELEASED/PRESS_LOST/VALUE_CHANGED,保留 ALL
|
||
lv_obj_add_event_cb(ui_SliderBrightness, ui_event_SliderBrightness, LV_EVENT_ALL, NULL);
|
||
lv_obj_add_event_cb(ui_ScreenSet, ui_event_ScreenSet, LV_EVENT_ALL, NULL);
|
||
|
||
}
|
||
|
||
void ui_ScreenSet_screen_destroy(void)
|
||
{
|
||
if (ui_ScreenSet) lv_obj_del(ui_ScreenSet);
|
||
|
||
// NULL screen variables
|
||
ui_ScreenSet= NULL;
|
||
ui_GlobalContainer= NULL;
|
||
ui_ContainerTop= NULL;
|
||
ui_ImgLowPower= NULL;
|
||
ui_ImgFlashlight= NULL;
|
||
ui_ImgDelete= NULL;
|
||
ui_ContainerCentral= NULL;
|
||
ui_SliderBrightness= NULL;
|
||
ui_ImgSun= NULL;
|
||
ui_LabelBrightness= NULL;
|
||
ui_ArcPowerLevel= NULL;
|
||
ui_ImgLightning= NULL;
|
||
ui_LabelPowerLevel= NULL;
|
||
|
||
}
|