1. 花了几天时间基于lvgl8.3封装了lvgl_cpp,写了一些基本需要的控件,支持链式调用
还存在一点点bug,不难fix 2. 增加了中文字库,支持中文显示 3. 修复和优化了一些地方
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
#include "PetBaseClass.h"
|
||||
#include "PetDao.h"
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
|
||||
void testPetSystem() {
|
||||
std::cout << "Test point1" << std::endl;
|
||||
@@ -431,10 +432,273 @@ void createWebSocket() {
|
||||
std::thread websocket_thread = ThreadManager::createThread(websocket_config, websocket_task);
|
||||
websocket_thread.detach();
|
||||
}
|
||||
#include "LVGLRender.h"
|
||||
#include <lvgl.h>
|
||||
#define TAG "BIN_TEST"
|
||||
|
||||
/* 从 SD 卡读任意 .bin 到堆 → 直接显示 */
|
||||
void test_show_bin(const char* fileName)
|
||||
{
|
||||
ESP_LOGI(TAG, "=== fast bin test: %s ===", fileName);
|
||||
|
||||
/* 1. 读文件 */
|
||||
std::string path = "/sdcard/" + std::string(fileName);
|
||||
std::string data = SDFileManager::getInstance()->readFileSync(path.c_str());
|
||||
if (data.empty()) {
|
||||
ESP_LOGE(TAG, "read fail");
|
||||
return;
|
||||
}
|
||||
size_t sz = data.size();
|
||||
ESP_LOGI(TAG, "file size = %zu", sz);
|
||||
ESP_LOG_BUFFER_HEX(TAG, data.data(), 16); // 头 16 字节
|
||||
|
||||
/* 2. 拷到堆(LVGL 长期持有)*/
|
||||
void* buf = heap_caps_malloc(sz, MALLOC_CAP_8BIT);
|
||||
memcpy(buf, data.data(), sz);
|
||||
|
||||
/* 3. 离线量好的尺寸(先填 320×240 测试,不对再改)*/
|
||||
uint32_t w = 720;
|
||||
uint32_t h = 720;
|
||||
if (sz != w * h * 2) { // RGB565 每像素 2 字节
|
||||
ESP_LOGW(TAG, "size mismatch, expect %ld, got %zu", w * h * 2, sz);
|
||||
}
|
||||
|
||||
/* 4. 一次性描述符 */
|
||||
static lv_img_dsc_t dsc;
|
||||
dsc.data = static_cast<const uint8_t *>(buf);
|
||||
dsc.header.cf = LV_IMG_CF_TRUE_COLOR;
|
||||
dsc.header.w = w;
|
||||
dsc.header.h = h;
|
||||
dsc.data_size = sz;
|
||||
|
||||
/* 5. 直接显示(不经过 PNG 解码器)*/
|
||||
lv_obj_t* img = lv_img_create(lv_scr_act());
|
||||
lv_img_set_src(img, &dsc);
|
||||
lv_obj_center(img);
|
||||
|
||||
ESP_LOGI(TAG, "bin displayed, w=%ld h=%ld", w, h);
|
||||
}
|
||||
|
||||
#include "lvpp.h"
|
||||
LV_FONT_DECLARE(SiYuanHeiTiGoogleBan);
|
||||
// 使用全局智能指针管理主要对象
|
||||
static std::shared_ptr<lvgl_cpp::Screen> g_screen;
|
||||
using namespace lvgl_cpp;
|
||||
struct AppCalc : BaseApp {
|
||||
using BaseApp::BaseApp;
|
||||
void onShow() override {
|
||||
Label(*this).text("Calculator").center();
|
||||
}
|
||||
};
|
||||
struct AppMusic : BaseApp {
|
||||
using BaseApp::BaseApp;
|
||||
void onShow() override {
|
||||
btn_.emplace(*this);
|
||||
gif.emplace(*this);
|
||||
btn_->size(180, 60)
|
||||
.align(LV_ALIGN_CENTER, nullptr, 0, 80)
|
||||
.on(LV_EVENT_CLICKED, [&](lv_event_t*) {
|
||||
/* 居中 GIF,背景黑 */
|
||||
lv_obj_set_style_bg_color(this->raw(), lv_color_black(), 0);
|
||||
lv_obj_set_style_bg_opa(this->raw(), LV_OPA_COVER, 0);
|
||||
gif->src("small_-min.gif")
|
||||
.center();
|
||||
});
|
||||
|
||||
/* 按钮文字 */
|
||||
lv_obj_t* label = lv_label_create(btn_->raw());
|
||||
lv_obj_set_style_text_font(label, &SiYuanHeiTiGoogleBan, LV_PART_MAIN);
|
||||
lv_label_set_text(label, "Gif测试");
|
||||
lv_obj_center(label);
|
||||
}
|
||||
private:
|
||||
std::optional<lvgl_cpp::Button> btn_; // c++17 轻量 RAII
|
||||
std::optional<lvgl_cpp::Gif> gif;
|
||||
};
|
||||
|
||||
class ButtonApp : public BaseApp {
|
||||
public:
|
||||
using BaseApp::BaseApp; // 继承 exit 按钮机制
|
||||
|
||||
void onShow() override {
|
||||
/* 居中按钮:180×60 px,圆角,现代蓝 */
|
||||
btn_.emplace(*this);
|
||||
btn_->size(180, 60)
|
||||
.align(LV_ALIGN_CENTER, nullptr, 0, 80)
|
||||
.on(LV_EVENT_CLICKED, [](lv_event_t*) {
|
||||
lvgl_cpp::Toast::show("咕咕嘎嘎!",
|
||||
lvgl_cpp::Toast::Type::INFO,
|
||||
1000);
|
||||
});
|
||||
LV_FONT_DECLARE(SiYuanHeiTiGoogleBan);
|
||||
/* 按钮文字 */
|
||||
lv_obj_t* label = lv_label_create(btn_->raw());
|
||||
lv_obj_set_style_text_font(label, &SiYuanHeiTiGoogleBan, LV_PART_MAIN);
|
||||
lv_label_set_text(label, "按我");
|
||||
lv_obj_center(label);
|
||||
}
|
||||
|
||||
private:
|
||||
std::optional<lvgl_cpp::Button> btn_; // c++17 轻量 RAII
|
||||
};
|
||||
static std::shared_ptr<HomePage> g_home;
|
||||
static std::shared_ptr<AppMenu> g_menu;
|
||||
void Cpp_Hand() {
|
||||
// testMIC();
|
||||
// testPetSystem();
|
||||
SDFileManager::getInstance()->tryInitSDCard();
|
||||
LVGLRender::getInstance()->tryToInitRenderGif(); // 初始化lvgl驱动(包括任务循环)
|
||||
LVGLRender::setFps(60); // 设置lvgl刷新频率
|
||||
|
||||
/* LVGL 已经初始化,屏幕驱动已注册 */
|
||||
// auto scr = lvgl_cpp::Screen{}; // RAII,离开作用域自动 del
|
||||
// lv_scr_load(scr.raw()); // 让 LVGL 把它当活动屏幕
|
||||
|
||||
// lvgl_cpp::Image img(scr);
|
||||
// img.bin("pic_no_alp_swap.bin", 720, 720)
|
||||
// .center();
|
||||
//
|
||||
// /* 1. 创建按钮 */
|
||||
// /* 1. 黑色文字样式 */
|
||||
// static lvgl_cpp::Style txt_style;
|
||||
// txt_style.text_color(lv_color_black());
|
||||
//
|
||||
// /* 2. 按钮 */
|
||||
// lvgl_cpp::Button btn{scr};
|
||||
// btn.size(150, 60).pos(40, 40);
|
||||
// /* 3. 先创建 Label 对象并保存,再链式调 */
|
||||
// lvgl_cpp::Label lbl{btn}; // 一定要存实例
|
||||
// lbl.text("Click Me")
|
||||
// .add_style(&txt_style.s, LV_PART_MAIN); // 样式作用到文字本身
|
||||
// /* 3. 注册点击事件 */
|
||||
// btn.on(LV_EVENT_CLICKED, [](lv_event_t*){
|
||||
// lvgl_cpp::Toast::show("Saved successfully !");
|
||||
// /* 2. 警告,3 s,顶部 */
|
||||
// lvgl_cpp::Toast::show("SD card missing", lvgl_cpp::Toast::Type::WARN, 3000, LV_ALIGN_TOP_MID, 20);
|
||||
//
|
||||
// /* 3. 错误,1.5 s,底部右侧 */
|
||||
// lvgl_cpp::Toast::show("Network error", lvgl_cpp::Toast::Type::ERROR, 1500, LV_ALIGN_BOTTOM_RIGHT, -30);
|
||||
// ESP_LOGI("BTN", "pressed");
|
||||
// });
|
||||
//
|
||||
// /* 1. 消息框 */
|
||||
// // const char* btns[] = {"Yes", "No", ""};
|
||||
// // auto mbox = lvgl_cpp::MsgBox::create("Hint", "Delete file ?", btns);
|
||||
//
|
||||
// /* 3. 进度条(双向 + 动画) */
|
||||
// lvgl_cpp::Bar bar(scr);
|
||||
// bar.range(0, 100)
|
||||
// .start_value(20) // 左端
|
||||
// .value(80, LV_ANIM_ON) // 右端带动画
|
||||
// .anim_time(500)
|
||||
// .size(200, 15)
|
||||
// .align(LV_ALIGN_CENTER, nullptr, 0, 40);
|
||||
//
|
||||
// /* 4. 折线:画一个 △ */
|
||||
// std::vector<lv_point_t> triangle = {{0,0}, {40,0}, {20,40}, {0,0}};
|
||||
// lvgl_cpp::Line line(scr);
|
||||
// line.points(triangle)
|
||||
// .y_invert(false)
|
||||
// .align(LV_ALIGN_CENTER, nullptr, 0, 100);
|
||||
//
|
||||
// lvgl_cpp::Battery bat(scr);
|
||||
// bat.size(60, 30) // 手机经典尺寸
|
||||
// .percent(true) // 显示 50%
|
||||
// .onRead([]() -> uint8_t { // 替换成你的 ADC/INA219 回调
|
||||
// static uint8_t v = 100;
|
||||
// if (v) --v;
|
||||
// return v;
|
||||
// })
|
||||
// .align(LV_ALIGN_TOP_RIGHT, -10, 10); // 九宫格对齐
|
||||
//
|
||||
// /* 3. 日期时间 */
|
||||
// lvgl_cpp::DateTime dt(scr);
|
||||
// dt.format("%m/%d %a %H:%M")
|
||||
// .onRead([](char* buf, size_t len){
|
||||
// /* 这里用 SNTP / RTC 填充,示例直接给假时间 */
|
||||
// snprintf(buf, len, "06/25 Tue 14:30");
|
||||
// })
|
||||
// .align(LV_ALIGN_BOTTOM_MID, nullptr, 0, -10);
|
||||
|
||||
|
||||
// lvgl_cpp::ColorPicker cp(scr);
|
||||
// cp.size(120, 120)
|
||||
// .align(LV_ALIGN_BOTTOM_MID, nullptr, 0, -20)
|
||||
// .on(LV_EVENT_VALUE_CHANGED, [&](lv_event_t*){
|
||||
// lv_color_t c = cp.color();
|
||||
// ESP_LOGI("CP", "rgb=%d,%d,%d", c.ch.red, c.ch.green_h, c.ch.blue);
|
||||
// });
|
||||
|
||||
// 1. 创建屏幕
|
||||
g_screen = std::make_shared<lvgl_cpp::Screen>();
|
||||
lv_scr_load(g_screen->raw());
|
||||
|
||||
// 2. 延迟创建界面组件
|
||||
auto init_timer = std::make_unique<lvgl_cpp::Timer>([&]() {
|
||||
ESP_LOGI("MAIN", "Initializing UI components...");
|
||||
|
||||
// 创建主页
|
||||
g_home = std::make_shared<HomePage>(*g_screen);
|
||||
g_home->bg("pic360.bin", 360, 360)
|
||||
.onBattery([]() -> uint8_t {
|
||||
static uint8_t v = 100;
|
||||
if (v) --v;
|
||||
return 88;
|
||||
})
|
||||
.onDateTime([](char* buf, size_t len) {
|
||||
snprintf(buf, len, "06/25 Tue 14:30");
|
||||
});
|
||||
|
||||
// 创建菜单
|
||||
g_menu = std::make_shared<AppMenu>(*g_screen);
|
||||
g_menu->addItem("Calcu", 100, 50)
|
||||
.addItem("Gif测试", 100, 50)
|
||||
.addItem("Button", 100, 50)
|
||||
.onClick([](const char* name) {
|
||||
ESP_LOGI("APP", "Launching: %s", name);
|
||||
|
||||
/* 1. 让工厂创建子应用 */
|
||||
auto app = AppFactory::create(name, *g_screen);
|
||||
if (!app) return;
|
||||
|
||||
/* 2. 隐藏菜单,显示应用 */
|
||||
lv_obj_add_flag(g_menu->raw(), LV_OBJ_FLAG_HIDDEN);
|
||||
app->onShow();
|
||||
|
||||
/* 3. 应用退出时回到菜单 */
|
||||
app->onExit([app_ptr = app.release()]() { // 转移所有权到 lambda
|
||||
lv_obj_clear_flag(g_menu->raw(), LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_del(app_ptr->raw()); // 自毁
|
||||
});
|
||||
});
|
||||
|
||||
lv_obj_add_flag(g_menu->raw(), LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
// 安全的事件连接
|
||||
g_home->onOpenMenu([]() {
|
||||
if (g_home && g_menu) {
|
||||
lv_obj_add_flag(g_home->raw(), LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(g_menu->raw(), LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
});
|
||||
|
||||
ESP_LOGI("MAIN", "UI initialization complete");
|
||||
}, 1000, true); // 1秒后执行一次
|
||||
|
||||
// 注册应用
|
||||
AppFactory::registerApp("Calcu", [](Obj& p) {
|
||||
return std::make_unique<AppCalc>(p);
|
||||
});
|
||||
AppFactory::registerApp("Gif测试", [](Obj& p) {
|
||||
return std::make_unique<AppMusic>(p);
|
||||
});
|
||||
AppFactory::registerApp("Button", [](lvgl_cpp::Obj& p) {
|
||||
return std::make_unique<ButtonApp>(p);
|
||||
});
|
||||
|
||||
// test_show_bin("pic_no_alp_swap.bin");
|
||||
|
||||
// LVGLRender::getInstance()->RenderGif("sequence02mmm.gif");
|
||||
|
||||
ESP_LOGI("CppHandle::Cpp_Hand", "当前固件版本 %s:", ToolsClass::getDeviceVersion().c_str());
|
||||
|
||||
@@ -442,18 +706,19 @@ void Cpp_Hand() {
|
||||
ESP_LOGI("CppHandle::Cpp_Hand", "当前设备固件序列号 %s:", ToolsClass::getChipSerialNumber().c_str());
|
||||
|
||||
// 连接wifi
|
||||
WifiConnectors::getInstance()->connectWifi("Misaki-2.4G", "88888888", 5);
|
||||
// WifiConnectors::getInstance()->connectWifi("Misaki-2.4G", "88888888", 5);
|
||||
|
||||
// 创建WebSocket
|
||||
createWebSocket();
|
||||
// createWebSocket();
|
||||
|
||||
// 设置OTA回调
|
||||
setupOtaCallbacks();
|
||||
// setupOtaCallbacks();
|
||||
|
||||
while (true) { // 主线程线程循环
|
||||
// ThreadManager::print_sys_memory(); // 打印系统内存使用情况
|
||||
// ThreadManager::stats_task(); // 打印任务统计信息
|
||||
|
||||
ESP_LOGI("APP_TASK", "Battery is:%ld", ToolsClass::getInstance()->getBatteryPer());
|
||||
ESP_LOGI("APP_TASK", "Battery is:%f", ToolsClass::getInstance()->getBatteryVolts());
|
||||
std::this_thread::sleep_for(sleep_time); // 休眠5秒
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user