Re implement display
This commit is contained in:
@@ -1,151 +0,0 @@
|
||||
#include "apps/demo_app.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#define TAG "DemoApp"
|
||||
|
||||
esp_err_t DemoApp::init(lv_obj_t* container) {
|
||||
if (!container) {
|
||||
ESP_LOGE(TAG, "Container is null");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
_container = container;
|
||||
ESP_LOGI(TAG, "Initializing demo app...");
|
||||
|
||||
// Header label
|
||||
_label_header = lv_label_create(_container);
|
||||
lv_label_set_text(_label_header, "Counter & Brightness Demo");
|
||||
lv_obj_set_style_text_color(_label_header, lv_color_black(), 0);
|
||||
lv_obj_align(_label_header, LV_ALIGN_TOP_MID, 0, 20);
|
||||
|
||||
// Counter label
|
||||
_label_counter = lv_label_create(_container);
|
||||
lv_label_set_text(_label_counter, "Count: 0");
|
||||
lv_obj_set_style_text_color(_label_counter, lv_color_black(), 0);
|
||||
lv_obj_align(_label_counter, LV_ALIGN_CENTER, 0, -80);
|
||||
|
||||
// Increment button
|
||||
_btn_increment = lv_btn_create(_container);
|
||||
lv_obj_set_size(_btn_increment, 150, 60);
|
||||
lv_obj_align(_btn_increment, LV_ALIGN_CENTER, -100, -20);
|
||||
lv_obj_add_event_cb(_btn_increment, btn_increment_event_cb, LV_EVENT_CLICKED, this);
|
||||
|
||||
lv_obj_t* label_inc = lv_label_create(_btn_increment);
|
||||
lv_label_set_text(label_inc, "+");
|
||||
lv_obj_set_style_text_color(label_inc, lv_color_black(), 0);
|
||||
lv_obj_center(label_inc);
|
||||
|
||||
// Decrement button
|
||||
_btn_decrement = lv_btn_create(_container);
|
||||
lv_obj_set_size(_btn_decrement, 150, 60);
|
||||
lv_obj_align(_btn_decrement, LV_ALIGN_CENTER, 100, -20);
|
||||
lv_obj_add_event_cb(_btn_decrement, btn_decrement_event_cb, LV_EVENT_CLICKED, this);
|
||||
|
||||
lv_obj_t* label_dec = lv_label_create(_btn_decrement);
|
||||
lv_label_set_text(label_dec, "-");
|
||||
lv_obj_set_style_text_color(label_dec, lv_color_black(), 0);
|
||||
lv_obj_center(label_dec);
|
||||
|
||||
// Slider
|
||||
_slider_brightness = lv_slider_create(_container);
|
||||
lv_obj_set_width(_slider_brightness, 400);
|
||||
lv_obj_align(_slider_brightness, LV_ALIGN_CENTER, 0, 80);
|
||||
lv_slider_set_range(_slider_brightness, 0, 100);
|
||||
lv_slider_set_value(_slider_brightness, 50, LV_ANIM_OFF);
|
||||
lv_obj_add_event_cb(_slider_brightness, slider_event_cb, LV_EVENT_VALUE_CHANGED, this);
|
||||
|
||||
// Slider value label
|
||||
_label_slider_value = lv_label_create(_container);
|
||||
lv_label_set_text(_label_slider_value, "Brightness: 50%");
|
||||
lv_obj_set_style_text_color(_label_slider_value, lv_color_black(), 0);
|
||||
lv_obj_align(_label_slider_value, LV_ALIGN_CENTER, 0, 130);
|
||||
|
||||
// Info text at bottom
|
||||
lv_obj_t* label_info = lv_label_create(_container);
|
||||
lv_label_set_text(label_info, "Touch buttons and slider to test");
|
||||
lv_obj_set_style_text_color(label_info, lv_color_black(), 0);
|
||||
lv_obj_align(label_info, LV_ALIGN_BOTTOM_MID, 0, -20);
|
||||
|
||||
ESP_LOGI(TAG, "Demo app initialized successfully");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t DemoApp::deinit(void) {
|
||||
ESP_LOGI(TAG, "Deinitializing demo app");
|
||||
|
||||
// All widgets will be automatically deleted when container is cleaned
|
||||
_label_header = nullptr;
|
||||
_label_counter = nullptr;
|
||||
_btn_increment = nullptr;
|
||||
_btn_decrement = nullptr;
|
||||
_slider_brightness = nullptr;
|
||||
_label_slider_value = nullptr;
|
||||
_counter = 0;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
std::string DemoApp::get_name(void) const {
|
||||
return "Demo";
|
||||
}
|
||||
|
||||
void DemoApp::btn_increment_event_cb(lv_event_t* e) {
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
if (code == LV_EVENT_CLICKED) {
|
||||
DemoApp* app = (DemoApp*)lv_event_get_user_data(e);
|
||||
if (app) {
|
||||
app->_counter++;
|
||||
lv_label_set_text_fmt(app->_label_counter, "Count: %d", app->_counter);
|
||||
ESP_LOGI(TAG, "Increment button clicked, count: %d", app->_counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DemoApp::btn_decrement_event_cb(lv_event_t* e) {
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
if (code == LV_EVENT_CLICKED) {
|
||||
DemoApp* app = (DemoApp*)lv_event_get_user_data(e);
|
||||
if (app) {
|
||||
app->_counter--;
|
||||
lv_label_set_text_fmt(app->_label_counter, "Count: %d", app->_counter);
|
||||
ESP_LOGI(TAG, "Decrement button clicked, count: %d", app->_counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DemoApp::slider_event_cb(lv_event_t* e) {
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
if (code == LV_EVENT_VALUE_CHANGED) {
|
||||
DemoApp* app = (DemoApp*)lv_event_get_user_data(e);
|
||||
if (app) {
|
||||
lv_obj_t* slider = (lv_obj_t*)lv_event_get_target(e);
|
||||
int32_t value = lv_slider_get_value(slider);
|
||||
lv_label_set_text_fmt(app->_label_slider_value, "Brightness: %d%%", (int)value);
|
||||
ESP_LOGI(TAG, "Slider value changed: %d", (int)value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DemoAppDescriptor implementation
|
||||
DemoApp* DemoAppDescriptor::_app_instance = nullptr;
|
||||
|
||||
DemoAppDescriptor::DemoAppDescriptor()
|
||||
: AppDescriptor("Demo", nullptr) {
|
||||
// Create singleton app instance
|
||||
if (!_app_instance) {
|
||||
_app_instance = new DemoApp();
|
||||
}
|
||||
|
||||
// Register with AppRegistry
|
||||
AppRegistry::instance().register_app(this);
|
||||
ESP_LOGI(TAG, "DemoApp registered with AppRegistry");
|
||||
}
|
||||
|
||||
void DemoAppDescriptor::draw_icon(lv_obj_t* parent) {
|
||||
// Create a simple icon with text and a symbol
|
||||
lv_obj_t* icon_label = lv_label_create(parent);
|
||||
lv_label_set_text(icon_label, LV_SYMBOL_SETTINGS "\nDemo");
|
||||
lv_obj_set_style_text_color(icon_label, lv_color_white(), 0);
|
||||
lv_obj_set_style_text_align(icon_label, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_obj_center(icon_label);
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "ui/ui_app.h"
|
||||
#include "ui/app_registry.h"
|
||||
|
||||
/**
|
||||
* @brief Demo application - counter and brightness slider
|
||||
*
|
||||
* Demonstrates interactive UI components with touch input:
|
||||
* - Counter display with increment/decrement buttons
|
||||
* - Brightness slider
|
||||
*/
|
||||
class DemoApp : public UIApp {
|
||||
public:
|
||||
DemoApp() = default;
|
||||
virtual ~DemoApp() = default;
|
||||
|
||||
esp_err_t init(lv_obj_t* container) override;
|
||||
esp_err_t deinit(void) override;
|
||||
std::string get_name(void) const override;
|
||||
|
||||
private:
|
||||
// UI components
|
||||
lv_obj_t* _label_header= nullptr;
|
||||
lv_obj_t* _label_counter= nullptr;
|
||||
lv_obj_t* _btn_increment= nullptr;
|
||||
lv_obj_t* _btn_decrement= nullptr;
|
||||
lv_obj_t* _slider_brightness= nullptr;
|
||||
lv_obj_t* _label_slider_value= nullptr;
|
||||
|
||||
// State
|
||||
int _counter= 0;
|
||||
|
||||
// Event callbacks
|
||||
static void btn_increment_event_cb(lv_event_t* e);
|
||||
static void btn_decrement_event_cb(lv_event_t* e);
|
||||
static void slider_event_cb(lv_event_t* e);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief AppDescriptor for DemoApp
|
||||
*
|
||||
* Registers the demo app with the AppRegistry and provides
|
||||
* icon rendering functionality.
|
||||
*/
|
||||
class DemoAppDescriptor : public AppDescriptor {
|
||||
public:
|
||||
DemoAppDescriptor();
|
||||
void draw_icon(lv_obj_t* parent) override;
|
||||
|
||||
private:
|
||||
static DemoApp* _app_instance;
|
||||
};
|
||||
@@ -126,62 +126,86 @@ bool DiscordApp::on_back_button_pressed() {
|
||||
// ============================================================================
|
||||
|
||||
void DiscordApp::build_main_page(lv_obj_t* page) {
|
||||
// Status icon (large, centered)
|
||||
status_icon_label_ = lv_label_create(page);
|
||||
lv_label_set_text(status_icon_label_, LV_SYMBOL_MUTE);
|
||||
// Using default font (only montserrat_14 is enabled)
|
||||
lv_obj_align(status_icon_label_, LV_ALIGN_CENTER, 0, -80);
|
||||
// Set up main page with flex column layout
|
||||
lv_obj_set_flex_flow(page, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_flex_align(page, LV_FLEX_ALIGN_SPACE_BETWEEN, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||
lv_obj_set_style_pad_all(page, 10, 0);
|
||||
|
||||
// Status text
|
||||
status_text_label_ = lv_label_create(page);
|
||||
lv_label_set_text(status_text_label_, "Unknown Status");
|
||||
// Using default font
|
||||
lv_obj_align(status_text_label_, LV_ALIGN_CENTER, 0, -20);
|
||||
|
||||
// Mute button
|
||||
mute_button_ = lv_btn_create(page);
|
||||
lv_obj_set_size(mute_button_, 200, 60);
|
||||
lv_obj_align(mute_button_, LV_ALIGN_CENTER, 0, 50);
|
||||
lv_obj_add_event_cb(mute_button_, on_mute_button_clicked, LV_EVENT_CLICKED, this);
|
||||
|
||||
lv_obj_t* mute_label = lv_label_create(mute_button_);
|
||||
lv_label_set_text(mute_label, "MUTE");
|
||||
// Using default font
|
||||
lv_obj_center(mute_label);
|
||||
|
||||
// Settings button (gear icon in corner)
|
||||
lv_obj_t* settings_btn = lv_btn_create(page);
|
||||
lv_obj_set_size(settings_btn, 60, 60);
|
||||
lv_obj_align(settings_btn, LV_ALIGN_BOTTOM_RIGHT, -10, -10);
|
||||
lv_obj_add_event_cb(settings_btn, on_settings_button_clicked, LV_EVENT_CLICKED, this);
|
||||
|
||||
lv_obj_t* settings_icon = lv_label_create(settings_btn);
|
||||
lv_label_set_text(settings_icon, LV_SYMBOL_SETTINGS);
|
||||
// Using default font
|
||||
lv_obj_center(settings_icon);
|
||||
|
||||
// Error notification (hidden by default)
|
||||
// === Top Section: Error Notification ===
|
||||
error_notification_ = lv_obj_create(page);
|
||||
lv_obj_set_size(error_notification_, 250, 50);
|
||||
lv_obj_align(error_notification_, LV_ALIGN_TOP_MID, 0, 10);
|
||||
lv_obj_set_width(error_notification_, LV_PCT(90));
|
||||
lv_obj_set_height(error_notification_, LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_bg_color(error_notification_, lv_color_hex(0xFF0000), 0);
|
||||
lv_obj_set_style_bg_opa(error_notification_, LV_OPA_70, 0);
|
||||
lv_obj_set_style_pad_all(error_notification_, 10, 0);
|
||||
lv_obj_set_style_radius(error_notification_, 8, 0);
|
||||
lv_obj_add_flag(error_notification_, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_set_flex_flow(error_notification_, LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_flex_align(error_notification_, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||
|
||||
lv_obj_t* error_label = lv_label_create(error_notification_);
|
||||
lv_label_set_text(error_label, LV_SYMBOL_WARNING " Connection Lost");
|
||||
lv_obj_set_style_text_color(error_label, lv_color_white(), 0);
|
||||
lv_obj_center(error_label);
|
||||
|
||||
// Show config prompt if not configured
|
||||
// === Center Section: Main Content ===
|
||||
lv_obj_t* center_container = lv_obj_create(page);
|
||||
lv_obj_set_size(center_container, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_bg_opa(center_container, LV_OPA_TRANSP, 0);
|
||||
lv_obj_set_style_border_width(center_container, 0, 0);
|
||||
lv_obj_set_style_pad_all(center_container, 0, 0);
|
||||
lv_obj_set_flex_flow(center_container, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_flex_align(center_container, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||
lv_obj_set_style_pad_row(center_container, 15, 0);
|
||||
lv_obj_set_flex_grow(center_container, 1);
|
||||
|
||||
// Status icon (large, centered)
|
||||
status_icon_label_ = lv_label_create(center_container);
|
||||
lv_label_set_text(status_icon_label_, LV_SYMBOL_MUTE);
|
||||
|
||||
// Status text
|
||||
status_text_label_ = lv_label_create(center_container);
|
||||
lv_label_set_text(status_text_label_, "Unknown Status");
|
||||
|
||||
// Mute button
|
||||
mute_button_ = lv_btn_create(center_container);
|
||||
lv_obj_set_size(mute_button_, 200, 60);
|
||||
lv_obj_add_event_cb(mute_button_, on_mute_button_clicked, LV_EVENT_CLICKED, this);
|
||||
|
||||
lv_obj_t* mute_label = lv_label_create(mute_button_);
|
||||
lv_label_set_text(mute_label, "MUTE");
|
||||
lv_obj_center(mute_label);
|
||||
|
||||
// === Bottom Section: Settings and Config Prompt ===
|
||||
lv_obj_t* bottom_container = lv_obj_create(page);
|
||||
lv_obj_set_size(bottom_container, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_bg_opa(bottom_container, LV_OPA_TRANSP, 0);
|
||||
lv_obj_set_style_border_width(bottom_container, 0, 0);
|
||||
lv_obj_set_style_pad_all(bottom_container, 0, 0);
|
||||
lv_obj_set_flex_flow(bottom_container, LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_flex_align(bottom_container, LV_FLEX_ALIGN_SPACE_BETWEEN, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||
|
||||
// Config prompt (left side)
|
||||
if (!settings_configured_) {
|
||||
lv_obj_t* config_prompt = lv_label_create(page);
|
||||
lv_obj_t* config_prompt = lv_label_create(bottom_container);
|
||||
lv_label_set_text(config_prompt, "Tap " LV_SYMBOL_SETTINGS " to configure");
|
||||
// Using default font
|
||||
lv_obj_set_style_text_color(config_prompt, lv_color_hex(0x888888), 0);
|
||||
lv_obj_align(config_prompt, LV_ALIGN_BOTTOM_LEFT, 10, -10);
|
||||
} else {
|
||||
// Empty spacer if configured
|
||||
lv_obj_t* spacer = lv_obj_create(bottom_container);
|
||||
lv_obj_set_size(spacer, 0, 0);
|
||||
lv_obj_set_style_bg_opa(spacer, LV_OPA_TRANSP, 0);
|
||||
lv_obj_set_style_border_width(spacer, 0, 0);
|
||||
}
|
||||
|
||||
// Settings button (right side)
|
||||
lv_obj_t* settings_btn = lv_btn_create(bottom_container);
|
||||
lv_obj_set_size(settings_btn, 60, 60);
|
||||
lv_obj_add_event_cb(settings_btn, on_settings_button_clicked, LV_EVENT_CLICKED, this);
|
||||
|
||||
lv_obj_t* settings_icon = lv_label_create(settings_btn);
|
||||
lv_label_set_text(settings_icon, LV_SYMBOL_SETTINGS);
|
||||
lv_obj_center(settings_icon);
|
||||
|
||||
// Update display with current state
|
||||
update_status_display();
|
||||
}
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
#define NAV_BAR_HEIGHT 50
|
||||
#define APP_CONTAINER_HEIGHT (DISPLAY_HEIGHT - HEADER_HEIGHT - NAV_BAR_HEIGHT)
|
||||
|
||||
// forward-declare local event callback
|
||||
static void on_home_button_clicked(lv_event_t* event);
|
||||
|
||||
RootLayout::RootLayout(UIHandler* ui_handler)
|
||||
: _ui_handler(ui_handler) { }
|
||||
|
||||
@@ -48,35 +51,76 @@ esp_err_t RootLayout::deinit(void) {
|
||||
}
|
||||
|
||||
esp_err_t RootLayout::create_layout(lv_obj_t* parent) {
|
||||
// Create header (top)
|
||||
// Configure parent as flexbox column layout
|
||||
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_flex_align(parent, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START);
|
||||
lv_obj_set_style_pad_all(parent, 0, 0);
|
||||
lv_obj_set_style_pad_gap(parent, 0, 0);
|
||||
|
||||
// Create header (top, fixed height)
|
||||
_header = lv_obj_create(parent);
|
||||
lv_obj_set_size(_header, DISPLAY_WIDTH, HEADER_HEIGHT);
|
||||
lv_obj_set_pos(_header, 0, 0);
|
||||
lv_obj_set_style_bg_color(_header, lv_color_hex(0x333333), 0);
|
||||
lv_obj_set_width(_header, lv_pct(100));
|
||||
lv_obj_set_height(_header, HEADER_HEIGHT);
|
||||
lv_obj_set_style_bg_color(_header, lv_color_hex(0xFFFFFF), 0);
|
||||
lv_obj_set_style_border_width(_header, 0, 0);
|
||||
lv_obj_set_style_border_color(_header, lv_color_hex(0x000000), 0);
|
||||
lv_obj_set_style_border_width(_header, 1, LV_BORDER_SIDE_BOTTOM);
|
||||
lv_obj_set_style_pad_all(_header, 0, 0);
|
||||
lv_obj_set_style_radius(_header, 0, 0);
|
||||
|
||||
_header_label = lv_label_create(_header);
|
||||
lv_label_set_text(_header_label, "App");
|
||||
lv_obj_set_style_text_color(_header_label, lv_color_white(), 0);
|
||||
lv_obj_set_style_text_color(_header_label, lv_color_black(), 0);
|
||||
lv_obj_align(_header_label, LV_ALIGN_LEFT_MID, 10, 0);
|
||||
|
||||
// Create app container (middle)
|
||||
// Create app container (middle, flexible - grows to fill available space)
|
||||
_app_container = lv_obj_create(parent);
|
||||
lv_obj_set_size(_app_container, DISPLAY_WIDTH, APP_CONTAINER_HEIGHT);
|
||||
lv_obj_set_pos(_app_container, 0, HEADER_HEIGHT);
|
||||
lv_obj_set_width(_app_container, lv_pct(100));
|
||||
lv_obj_set_flex_grow(_app_container, 1);
|
||||
lv_obj_set_style_bg_color(_app_container, lv_color_white(), 0);
|
||||
lv_obj_set_style_border_width(_app_container, 0, 0);
|
||||
lv_obj_set_style_pad_all(_app_container, 0, 0);
|
||||
lv_obj_set_style_radius(_app_container, 0, 0);
|
||||
|
||||
// Create navigation bar (bottom)
|
||||
// Create navigation bar (bottom, fixed height)
|
||||
_nav_bar = lv_obj_create(parent);
|
||||
lv_obj_set_size(_nav_bar, DISPLAY_WIDTH, NAV_BAR_HEIGHT);
|
||||
lv_obj_set_pos(_nav_bar, 0, HEADER_HEIGHT + APP_CONTAINER_HEIGHT);
|
||||
lv_obj_set_style_bg_color(_nav_bar, lv_color_hex(0x333333), 0);
|
||||
lv_obj_set_style_border_width(_nav_bar, 0, 0);
|
||||
lv_obj_set_width(_nav_bar, lv_pct(100));
|
||||
lv_obj_set_height(_nav_bar, NAV_BAR_HEIGHT);
|
||||
lv_obj_set_style_bg_color(_nav_bar, lv_color_hex(0xFFFFFF), 0);
|
||||
lv_obj_set_style_border_color(_nav_bar, lv_color_hex(0x000000), 0);
|
||||
lv_obj_set_style_border_width(_nav_bar, 1, LV_BORDER_SIDE_TOP);
|
||||
lv_obj_set_style_pad_all(_nav_bar, 5, 0);
|
||||
lv_obj_set_style_radius(_nav_bar, 0, 0);
|
||||
|
||||
ESP_LOGI(TAG, "Layout created: Header=%d, AppContainer=%d, NavBar=%d",
|
||||
HEADER_HEIGHT, APP_CONTAINER_HEIGHT, NAV_BAR_HEIGHT);
|
||||
// Configure nav bar as flexbox row layout with space-between
|
||||
lv_obj_set_flex_flow(_nav_bar, LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_flex_align(_nav_bar, LV_FLEX_ALIGN_SPACE_BETWEEN, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||
|
||||
// Create back button (aligned to start by flex layout)
|
||||
_back_button = lv_btn_create(_nav_bar);
|
||||
lv_obj_set_size(_back_button, 60, NAV_BAR_HEIGHT - 10);
|
||||
lv_obj_set_style_bg_color(_back_button, lv_color_hex(0x555555), 0);
|
||||
lv_obj_add_event_cb(_back_button, on_back_button_clicked, LV_EVENT_CLICKED, _ui_handler);
|
||||
lv_obj_add_flag(_back_button, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
// Add back arrow label
|
||||
lv_obj_t* back_label = lv_label_create(_back_button);
|
||||
lv_label_set_text(back_label, LV_SYMBOL_LEFT);
|
||||
lv_obj_set_style_text_color(back_label, lv_color_black(), 0);
|
||||
lv_obj_align(back_label, LV_ALIGN_CENTER, 0, 0);
|
||||
|
||||
// Create home button (aligned to end by flex layout)
|
||||
lv_obj_t* home_button = lv_btn_create(_nav_bar);
|
||||
lv_obj_set_size(home_button, 60, NAV_BAR_HEIGHT - 10);
|
||||
lv_obj_set_style_bg_color(home_button, lv_color_hex(0x555555), 0);
|
||||
lv_obj_t* home_label = lv_label_create(home_button);
|
||||
lv_label_set_text(home_label, LV_SYMBOL_HOME);
|
||||
lv_obj_set_style_text_color(home_label, lv_color_white(), 0);
|
||||
lv_obj_align(home_label, LV_ALIGN_CENTER, 0, 0);
|
||||
lv_obj_add_event_cb(home_button, on_home_button_clicked, LV_EVENT_CLICKED, _ui_handler);
|
||||
|
||||
ESP_LOGI(TAG, "Layout created with flexible design: Header=%d, NavBar=%d",
|
||||
HEADER_HEIGHT, NAV_BAR_HEIGHT);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -99,8 +143,12 @@ esp_err_t RootLayout::render_app_icons(void) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// Clear existing nav bar content
|
||||
lv_obj_clean(_nav_bar);
|
||||
// Clear existing app container content (icons are rendered in the app area)
|
||||
if (!_app_container) {
|
||||
ESP_LOGE(TAG, "App container not initialized");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
lv_obj_clean(_app_container);
|
||||
|
||||
// Get all registered apps from registry
|
||||
const auto& app_descriptors = AppRegistry::instance().get_app_descriptors();
|
||||
@@ -114,56 +162,39 @@ esp_err_t RootLayout::render_app_icons(void) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Rendering %d app icons", app_descriptors.size());
|
||||
ESP_LOGI(TAG, "Rendering %d app icons", (int)app_descriptors.size());
|
||||
|
||||
// Calculate icon spacing
|
||||
// Calculate icon spacing inside the app container
|
||||
int icon_count = app_descriptors.size();
|
||||
int icon_width = 96;
|
||||
int icon_height = 96;
|
||||
int icon_spacing = DISPLAY_WIDTH / (icon_count + 1);
|
||||
int x_offset = icon_spacing;
|
||||
int y_offset = (APP_CONTAINER_HEIGHT - icon_height) / 2;
|
||||
|
||||
// Render each app icon
|
||||
// Render each app icon into the app container
|
||||
for (size_t i = 0; i < app_descriptors.size(); i++) {
|
||||
AppDescriptor* descriptor = app_descriptors[i];
|
||||
|
||||
// Create a container for this app icon
|
||||
lv_obj_t* icon_container = lv_obj_create(_nav_bar);
|
||||
lv_obj_set_size(icon_container, icon_spacing - 10, NAV_BAR_HEIGHT - 10);
|
||||
lv_obj_set_pos(icon_container, x_offset - (icon_spacing - 10) / 2, 5);
|
||||
lv_obj_t* icon_container = lv_obj_create(_app_container);
|
||||
lv_obj_set_size(icon_container, icon_width, icon_height);
|
||||
lv_obj_set_pos(icon_container, x_offset - icon_width / 2, y_offset);
|
||||
lv_obj_set_style_bg_opa(icon_container, LV_OPA_TRANSP, 0);
|
||||
lv_obj_set_style_border_width(icon_container, 0, 0);
|
||||
lv_obj_set_style_pad_all(icon_container, 0, 0);
|
||||
// add a border for debugging
|
||||
lv_obj_set_style_border_color(icon_container, lv_color_hex(0x000000), 0);
|
||||
lv_obj_set_style_border_width(icon_container, 1, 0);
|
||||
|
||||
// Store both the descriptor and ui_handler as user data
|
||||
lv_obj_set_user_data(icon_container, descriptor);
|
||||
|
||||
// Let the descriptor draw its icon
|
||||
descriptor->draw_icon(icon_container);
|
||||
|
||||
// Add click event handler
|
||||
lv_obj_add_flag(icon_container, LV_OBJ_FLAG_CLICKABLE);
|
||||
lv_obj_add_event_cb(icon_container, on_app_icon_clicked, LV_EVENT_CLICKED, _ui_handler);
|
||||
|
||||
x_offset += icon_spacing;
|
||||
}
|
||||
|
||||
// Create back button on the left side of the nav bar
|
||||
_back_button = lv_btn_create(_nav_bar);
|
||||
lv_obj_set_size(_back_button, 60, NAV_BAR_HEIGHT - 10);
|
||||
lv_obj_set_pos(_back_button, 5, 5);
|
||||
lv_obj_set_style_bg_color(_back_button, lv_color_hex(0x555555), 0);
|
||||
|
||||
// Add back arrow label
|
||||
lv_obj_t* back_label = lv_label_create(_back_button);
|
||||
lv_label_set_text(back_label, LV_SYMBOL_LEFT);
|
||||
lv_obj_set_style_text_color(back_label, lv_color_white(), 0);
|
||||
lv_obj_align(back_label, LV_ALIGN_CENTER, 0, 0);
|
||||
|
||||
// Add click event handler
|
||||
lv_obj_add_event_cb(_back_button, on_back_button_clicked, LV_EVENT_CLICKED, _ui_handler);
|
||||
|
||||
// Initially hide back button (shown when app is active)
|
||||
lv_obj_add_flag(_back_button, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -180,7 +211,9 @@ void RootLayout::hide_back_button(void) {
|
||||
}
|
||||
|
||||
void RootLayout::on_app_icon_clicked(lv_event_t* event) {
|
||||
lv_obj_t* icon_container = static_cast<lv_obj_t*>(lv_event_get_target(event));
|
||||
// Use the current target (the object the callback was attached to)
|
||||
// instead of the event target, which may be a child (like a label).
|
||||
lv_obj_t* icon_container = static_cast<lv_obj_t*>(lv_event_get_current_target(event));
|
||||
UIHandler* handler = static_cast<UIHandler*>(lv_event_get_user_data(event));
|
||||
AppDescriptor* descriptor = static_cast<AppDescriptor*>(lv_obj_get_user_data(icon_container));
|
||||
|
||||
@@ -218,3 +251,14 @@ void RootLayout::on_back_button_clicked(lv_event_t* event) {
|
||||
handler->return_to_main_screen();
|
||||
}
|
||||
}
|
||||
|
||||
static void on_home_button_clicked(lv_event_t* event) {
|
||||
UIHandler* handler = static_cast<UIHandler*>(lv_event_get_user_data(event));
|
||||
|
||||
if (!handler) {
|
||||
ESP_LOGE(TAG, "Invalid handler in home button click");
|
||||
return;
|
||||
}
|
||||
|
||||
handler->return_to_main_screen();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user