feat: implement PageStack class for multi-page navigation in LVGL apps

This commit is contained in:
GW_MC
2026-01-24 13:13:28 +08:00
parent dfd8959f58
commit dd1702e3e9
2 changed files with 201 additions and 0 deletions

115
main/ui/page_stack.cpp Normal file
View File

@@ -0,0 +1,115 @@
#include "page_stack.h"
#include "esp_log.h"
static const char* TAG = "PageStack";
PageStack::PageStack(lv_obj_t* parent_container)
: parent_container_(parent_container) {
if (!parent_container_) {
ESP_LOGE(TAG, "Parent container is null");
}
}
PageStack::~PageStack() {
clear();
}
lv_obj_t* PageStack::create_page_container() {
lv_obj_t* page = lv_obj_create(parent_container_);
// Fill parent container
lv_obj_set_size(page, LV_PCT(100), LV_PCT(100));
lv_obj_set_pos(page, 0, 0);
// Remove padding and scrollbars
lv_obj_set_style_pad_all(page, 0, 0);
lv_obj_set_scrollbar_mode(page, LV_SCROLLBAR_MODE_OFF);
// White background
lv_obj_set_style_bg_color(page, lv_color_white(), 0);
lv_obj_set_style_bg_opa(page, LV_OPA_COVER, 0);
// Remove border
lv_obj_set_style_border_width(page, 0, 0);
return page;
}
lv_obj_t* PageStack::push(PageBuilder builder, PageCleanup cleanup) {
if (!parent_container_) {
ESP_LOGE(TAG, "Cannot push page: parent container is null");
return nullptr;
}
if (!builder) {
ESP_LOGE(TAG, "Cannot push page: builder is null");
return nullptr;
}
// Hide current page if any
if (!pages_.empty()) {
lv_obj_add_flag(pages_.back().container, LV_OBJ_FLAG_HIDDEN);
}
// Create new page container
lv_obj_t* page = create_page_container();
// Build page content
builder(page);
// Add to stack
pages_.push_back({page, cleanup});
ESP_LOGD(TAG, "Pushed page (depth: %d)", pages_.size());
return page;
}
bool PageStack::pop() {
if (pages_.empty()) {
ESP_LOGW(TAG, "Cannot pop: stack is empty");
return false;
}
// Get and remove current page
Page current = pages_.back();
pages_.pop_back();
// Call cleanup callback if provided
if (current.cleanup) {
current.cleanup(current.container);
}
// Delete page container
lv_obj_del(current.container);
// Show previous page if any
if (!pages_.empty()) {
lv_obj_clear_flag(pages_.back().container, LV_OBJ_FLAG_HIDDEN);
}
ESP_LOGD(TAG, "Popped page (depth: %d)", pages_.size());
return true;
}
void PageStack::clear() {
ESP_LOGD(TAG, "Clearing all pages (depth: %d)", pages_.size());
// Pop all pages (calls cleanup callbacks)
while (!pages_.empty()) {
Page current = pages_.back();
pages_.pop_back();
if (current.cleanup) {
current.cleanup(current.container);
}
lv_obj_del(current.container);
}
}
lv_obj_t* PageStack::current_page() const {
if (pages_.empty()) {
return nullptr;
}
return pages_.back().container;
}