#pragma once #include #include #include struct SdCardFontFileInfo { std::string path; // v4 on-disk naming: "///_.cpfont" // where is "/.fonts" (preferred, hidden) or "/fonts" (visible). // e.g. "/.fonts/NotoSansCJK/NotoSansCJK_14.cpfont" uint8_t pointSize; // parsed from filename: 14 uint8_t style; // always 0 in v4 (all 4 styles bundled in one file); // kept for potential future formats }; struct SdCardFontFamilyInfo { std::string name; // directory name, e.g. "NotoSansCJK" std::vector files; const SdCardFontFileInfo* findFile(uint8_t size, uint8_t style = 0) const; bool hasSize(uint8_t size) const; std::vector availableSizes() const; // Pick the file whose pointSize is closest to targetPtSize. On ties (equal // distance) prefers the smaller pointSize so behaviour is deterministic // across SD card layouts. Returns nullptr when files is empty. // // Robust against families that don't ship the canonical {12,14,16,18} set: // a family with only [10,14,18] resolves target 12 → 10 (or 14 on tie), // target 16 → 14 or 18, etc., instead of mis-indexing by ordinal slot. const SdCardFontFileInfo* pickClosestSize(uint8_t targetPtSize) const; }; class SdCardFontRegistry { public: static constexpr int MAX_SD_FAMILIES = 128; // Two top-level roots are scanned at discovery time. Hidden is preferred // when creating new installs; both are read from if present. static constexpr const char* FONTS_DIR_HIDDEN = "/.fonts"; static constexpr const char* FONTS_DIR_VISIBLE = "/fonts"; // Returns the existing root for `familyName` (the one that contains // ///), or nullptr if the family is not installed in // either root. Used by writers to keep re-installs in their existing dir. static const char* findFamilyRoot(const char* familyName); // Returns the root path that should be used when creating a brand-new // family on disk (no prior install): the existing root if exactly one of // the two roots exists, otherwise the hidden root. static const char* defaultWriteRoot(); // Scan SD card, populate families_. Returns true if any families found. bool discover(); const std::vector& getFamilies() const { return families_; } const SdCardFontFamilyInfo* findFamily(const std::string& name) const; int getFamilyIndex(const std::string& name) const; int getFamilyCount() const { return static_cast(families_.size()); } private: std::vector families_; // sorted alphabetically static bool parseFilename(const char* filename, uint8_t& size, uint8_t& style); static void scanDirectory(const char* dirPath, SdCardFontFamilyInfo& family); // Scan one root (e.g. "/.fonts"), append families to `out`, dedup by name. static void scanRoot(const char* rootPath, std::vector& out); };