knxdisplay/main/Fonts.cpp
2026-01-25 15:20:12 +01:00

178 lines
5.7 KiB
C++

#include "Fonts.hpp"
#include "esp_log.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <cstddef>
#if CONFIG_ESP_LVGL_ADAPTER_ENABLE_FREETYPE
#include "esp_lv_adapter.h"
#include <sys/stat.h>
#endif
namespace {
static const char* TAG = "Fonts";
static constexpr const char* kFontPath = "/sdcard/fonts/Montserrat-Medium.ttf";
static constexpr const char* kIconFontPath = "/sdcard/fonts/MaterialSymbolsOutlined.ttf";
static constexpr uint16_t kFontSizes[] = {14, 18, 22, 28, 36, 48};
static constexpr size_t kFontCount = sizeof(kFontSizes) / sizeof(kFontSizes[0]);
static const lv_font_t* s_fonts[kFontCount] = {nullptr};
static const lv_font_t* s_iconFonts[kFontCount] = {nullptr};
static bool s_initialized = false;
static bool s_iconFontAvailable = false;
const lv_font_t* fallbackFont(uint8_t sizeIndex) {
switch (sizeIndex) {
case 0: return &lv_font_montserrat_14;
#if LV_FONT_MONTSERRAT_18
case 1: return &lv_font_montserrat_18;
#endif
#if LV_FONT_MONTSERRAT_22
case 2: return &lv_font_montserrat_22;
#endif
#if LV_FONT_MONTSERRAT_28
case 3: return &lv_font_montserrat_28;
#endif
#if LV_FONT_MONTSERRAT_36
case 4: return &lv_font_montserrat_36;
#endif
#if LV_FONT_MONTSERRAT_48
case 5: return &lv_font_montserrat_48;
#endif
default: return &lv_font_montserrat_14;
}
}
#if CONFIG_ESP_LVGL_ADAPTER_ENABLE_FREETYPE
bool fontFileExists(const char* path) {
struct stat st;
return stat(path, &st) == 0;
}
#endif
} // namespace
void Fonts::init() {
#if CONFIG_ESP_LVGL_ADAPTER_ENABLE_FREETYPE
ESP_LOGI(TAG, "FreeType enabled");
if (s_initialized) {
ESP_LOGI(TAG, "Already initialized");
return;
}
s_initialized = true;
if (!fontFileExists(kFontPath)) {
ESP_LOGW(TAG, "Font file not found: %s", kFontPath);
return;
}
ESP_LOGI(TAG, "Font file exists: %s", kFontPath);
// Give LVGL task time to start and release mutex
ESP_LOGI(TAG, "Waiting for LVGL task...");
vTaskDelay(pdMS_TO_TICKS(500));
// Test if LVGL lock is available
ESP_LOGI(TAG, "Testing LVGL lock...");
if (esp_lv_adapter_lock(1000) == ESP_OK) { // 1 second timeout
ESP_LOGI(TAG, "Lock acquired OK, releasing...");
esp_lv_adapter_unlock();
} else {
ESP_LOGE(TAG, "Could not acquire LVGL lock - something is holding it!");
return; // Don't try to init fonts if lock is stuck
}
for (size_t i = 0; i < kFontCount; ++i) {
ESP_LOGI(TAG, "Loading font size %u...", kFontSizes[i]);
esp_lv_adapter_ft_font_config_t cfg = {};
cfg.name = kFontPath;
cfg.size = kFontSizes[i];
cfg.style = ESP_LV_ADAPTER_FT_FONT_STYLE_NORMAL;
cfg.mem = nullptr;
cfg.mem_size = 0;
esp_lv_adapter_ft_font_handle_t handle = nullptr;
ESP_LOGI(TAG, "Calling esp_lv_adapter_ft_font_init (free heap: %lu)...",
(unsigned long)esp_get_free_heap_size());
esp_err_t ret = esp_lv_adapter_ft_font_init(&cfg, &handle);
ESP_LOGI(TAG, "esp_lv_adapter_ft_font_init returned %d", ret);
if (ret != ESP_OK || handle == nullptr) {
ESP_LOGW(TAG, "Failed to load FreeType font size %u (err=%d)", cfg.size, ret);
continue;
}
s_fonts[i] = esp_lv_adapter_ft_font_get(handle);
if (!s_fonts[i]) {
ESP_LOGW(TAG, "FreeType font handle returned null for size %u", cfg.size);
}
ESP_LOGI(TAG, "Font size %u loaded successfully", kFontSizes[i]);
}
ESP_LOGI(TAG, "Text font initialization complete");
// Load icon font if available
if (fontFileExists(kIconFontPath)) {
ESP_LOGI(TAG, "Icon font file exists: %s", kIconFontPath);
for (size_t i = 0; i < kFontCount; ++i) {
ESP_LOGI(TAG, "Loading icon font size %u...", kFontSizes[i]);
esp_lv_adapter_ft_font_config_t cfg = {};
cfg.name = kIconFontPath;
cfg.size = kFontSizes[i];
cfg.style = ESP_LV_ADAPTER_FT_FONT_STYLE_NORMAL;
cfg.mem = nullptr;
cfg.mem_size = 0;
esp_lv_adapter_ft_font_handle_t handle = nullptr;
esp_err_t ret = esp_lv_adapter_ft_font_init(&cfg, &handle);
if (ret != ESP_OK || handle == nullptr) {
ESP_LOGW(TAG, "Failed to load icon font size %u (err=%d)", cfg.size, ret);
continue;
}
s_iconFonts[i] = esp_lv_adapter_ft_font_get(handle);
if (s_iconFonts[i]) {
s_iconFontAvailable = true;
ESP_LOGI(TAG, "Icon font size %u loaded successfully", kFontSizes[i]);
}
}
ESP_LOGI(TAG, "Icon font initialization complete");
} else {
ESP_LOGW(TAG, "Icon font file not found: %s", kIconFontPath);
}
#else
ESP_LOGI(TAG, "FreeType disabled, using built-in fonts");
#endif
}
const lv_font_t* Fonts::bySizeIndex(uint8_t sizeIndex) {
#if CONFIG_ESP_LVGL_ADAPTER_ENABLE_FREETYPE
if (sizeIndex < kFontCount && s_fonts[sizeIndex]) {
return s_fonts[sizeIndex];
}
#endif
return fallbackFont(sizeIndex);
}
const lv_font_t* Fonts::iconFont(uint8_t sizeIndex) {
#if CONFIG_ESP_LVGL_ADAPTER_ENABLE_FREETYPE
if (sizeIndex < kFontCount && s_iconFonts[sizeIndex]) {
return s_iconFonts[sizeIndex];
}
// Try to return any available icon font size as fallback
if (s_iconFontAvailable) {
for (size_t i = 0; i < kFontCount; ++i) {
if (s_iconFonts[i]) return s_iconFonts[i];
}
}
#endif
// No icon font available - return text font as last resort
return fallbackFont(sizeIndex);
}
bool Fonts::hasIconFont() {
#if CONFIG_ESP_LVGL_ADAPTER_ENABLE_FREETYPE
return s_iconFontAvailable;
#else
return false;
#endif
}