#pragma once #include #include #include #include #include "BasicElements.h" #include "IniParser.h" #include "ThemeContext.h" namespace ThemeEngine { struct ProcessedAsset { std::vector data; int w, h; GfxRenderer::Orientation orientation; }; // Screen render cache - stores full screen state for quick restore struct ScreenCache { uint8_t* buffer = nullptr; size_t bufferSize = 0; std::string screenName; uint32_t contextHash = 0; // Hash of context data to detect changes bool valid = false; ScreenCache() = default; ~ScreenCache() { if (buffer) { free(buffer); buffer = nullptr; } } // Prevent double-free from copy ScreenCache(const ScreenCache&) = delete; ScreenCache& operator=(const ScreenCache&) = delete; // Allow move ScreenCache(ScreenCache&& other) noexcept : buffer(other.buffer), bufferSize(other.bufferSize), screenName(std::move(other.screenName)), contextHash(other.contextHash), valid(other.valid) { other.buffer = nullptr; other.bufferSize = 0; other.valid = false; } ScreenCache& operator=(ScreenCache&& other) noexcept { if (this != &other) { if (buffer) free(buffer); buffer = other.buffer; bufferSize = other.bufferSize; screenName = std::move(other.screenName); contextHash = other.contextHash; valid = other.valid; other.buffer = nullptr; other.bufferSize = 0; other.valid = false; } return *this; } void invalidate() { valid = false; } }; class ThemeManager { private: std::map elements; // All elements by ID std::string currentThemeName; int navBookCount = 1; // Number of navigable book slots (from theme [Global] section) std::map fontMap; // Screen-level caching for fast redraw std::map screenCaches; bool useCaching = true; // Track which elements are data-dependent vs static std::map elementDependsOnData; // Factory and property methods UIElement* createElement(const std::string& id, const std::string& type); void applyProperties(UIElement* elem, const std::map& props); public: static ThemeManager& get() { static ThemeManager instance; return instance; } // Initialize defaults (fonts, etc.) void begin(); // Register a font ID mapping (e.g. "UI_12" -> 0) void registerFont(const std::string& name, int id); // Theme loading void loadTheme(const std::string& themeName); void unloadTheme(); // Get current theme name const std::string& getCurrentTheme() const { return currentThemeName; } // Get number of navigable book slots (from theme config, default 1) int getNavBookCount() const { return navBookCount; } // Render a screen void renderScreen(const std::string& screenName, const GfxRenderer& renderer, const ThemeContext& context); // Render with dirty tracking (only redraws changed regions) void renderScreenOptimized(const std::string& screenName, const GfxRenderer& renderer, const ThemeContext& context, const ThemeContext* prevContext = nullptr); // Invalidate all caches (call when theme changes or screen switches) void invalidateAllCaches(); // Invalidate specific screen cache void invalidateScreenCache(const std::string& screenName); // Enable/disable caching void setCachingEnabled(bool enabled) { useCaching = enabled; } bool isCachingEnabled() const { return useCaching; } // Asset path resolution std::string getAssetPath(const std::string& assetName); // Asset caching const std::vector* getCachedAsset(const std::string& path); void cacheAsset(const std::string& path, std::vector&& data); const ProcessedAsset* getProcessedAsset(const std::string& path, GfxRenderer::Orientation orientation, int targetW = 0, int targetH = 0); void cacheProcessedAsset(const std::string& path, const ProcessedAsset& asset, int targetW = 0, int targetH = 0); // Clear asset caches (for memory management) void clearAssetCaches(); // Get element by ID (useful for direct manipulation) UIElement* getElement(const std::string& id) { auto it = elements.find(id); return it != elements.end() ? it->second : nullptr; } private: std::map> assetCache; std::map processedCache; // Compute a simple hash of context data for cache invalidation uint32_t computeContextHash(const ThemeContext& context, const std::string& screenName); }; } // namespace ThemeEngine