Merge pull request #220 from jpirnay/feat-txt-font

feat: Add a default font for .txt / .md files
This commit is contained in:
jpirnay
2026-05-15 10:31:45 +02:00
committed by GitHub
43 changed files with 264 additions and 48 deletions
+2 -2
View File
@@ -286,7 +286,7 @@ void ActivityManager::goToBrowser() {
void ActivityManager::goToReader(std::string path) {
RenderLock lock;
ensureSdFontLoaded();
ensureSdFontLoadedForPath(path.c_str());
replaceActivity(std::make_unique<ReaderActivity>(renderer, mappedInput, std::move(path)));
}
@@ -307,7 +307,7 @@ void ActivityManager::replaceWithReader(std::string path, ReturnHint hint) {
returnHint = std::move(hint);
hasReturnHint = true;
RenderLock lock;
ensureSdFontLoaded();
ensureSdFontLoadedForPath(path.c_str());
replaceActivity(std::make_unique<ReaderActivity>(renderer, mappedInput, std::move(path)));
}
+2 -2
View File
@@ -494,7 +494,7 @@ BookOverlayInfo SleepActivity::getBookOverlayInfo(const std::string& bookPath) c
f.close();
}
}
} else if (FsHelpers::checkFileExtension(bookPath, ".txt")) {
} else if (FsHelpers::hasTxtExtension(bookPath) || FsHelpers::hasMarkdownExtension(bookPath)) {
Txt txt(bookPath, "/.crosspoint");
if (txt.load()) {
info.title = txt.getTitle();
@@ -834,7 +834,7 @@ void SleepActivity::renderOverlaySleepScreen() const {
if (FsHelpers::checkFileExtension(path, ".xtc") || FsHelpers::checkFileExtension(path, ".xtch")) {
rendered = XtcReaderActivity::drawCurrentPageToBuffer(path, renderer);
} else if (FsHelpers::checkFileExtension(path, ".txt")) {
} else if (FsHelpers::hasTxtExtension(path) || FsHelpers::hasMarkdownExtension(path)) {
rendered = TxtReaderActivity::drawCurrentPageToBuffer(path, renderer);
} else if (FsHelpers::checkFileExtension(path, ".epub")) {
rendered = EpubReaderActivity::drawCurrentPageToBuffer(path, renderer);
+1 -1
View File
@@ -325,7 +325,7 @@ void MdReaderActivity::initializeReader() {
return;
}
cachedFontId = SETTINGS.getReaderFontId();
cachedFontId = SETTINGS.getTxtReaderFontId();
cachedScreenMargin = SETTINGS.screenMargin;
cachedParagraphAlignment = SETTINGS.paragraphAlignment;
+2 -2
View File
@@ -273,7 +273,7 @@ void TxtReaderActivity::initializeReader() {
}
// Store current settings for cache validation
cachedFontId = SETTINGS.getReaderFontId();
cachedFontId = SETTINGS.getTxtReaderFontId();
cachedScreenMargin = SETTINGS.screenMargin;
cachedParagraphAlignment = SETTINGS.paragraphAlignment;
@@ -710,7 +710,7 @@ bool TxtReaderActivity::drawCurrentPageToBuffer(const std::string& filePath, Gfx
}
// Compute layout values that match what initializeReader() produces
const int fontId = SETTINGS.getReaderFontId();
const int fontId = SETTINGS.getTxtReaderFontId();
const uint8_t screenMargin = SETTINGS.screenMargin;
const uint8_t paragraphAlignment = SETTINGS.paragraphAlignment;
@@ -6,28 +6,12 @@
#include "MappedInputManager.h"
#include "SdCardFontGlobals.h"
#include "components/UITheme.h"
#include "fontIds.h"
namespace {
uint8_t currentFontIndex() {
if (SETTINGS.sdFontFamilyName[0] != '\0') {
const auto& families = sdFontSystem.registry().getFamilies();
for (int i = 0; i < static_cast<int>(families.size()); i++) {
if (families[i].name == SETTINGS.sdFontFamilyName) {
return static_cast<uint8_t>(CrossPointSettings::BUILTIN_FONT_COUNT + i);
}
}
}
return SETTINGS.fontFamily < CrossPointSettings::BUILTIN_FONT_COUNT ? SETTINGS.fontFamily : 0;
}
} // namespace
void FontSelectionActivity::onEnter() {
Activity::onEnter();
fontCount = fontFamilyOptionCount();
selectedIndex = currentFontIndex();
selectedIndex =
static_cast<int>(target == Target::TXT ? txtFontFamilyDynamicGetter(nullptr) : fontFamilyDynamicGetter(nullptr));
if (selectedIndex >= fontCount) selectedIndex = 0;
requestUpdate();
}
@@ -50,7 +34,11 @@ void FontSelectionActivity::loop() {
}
void FontSelectionActivity::handleSelection() {
fontFamilyDynamicSetter(nullptr, static_cast<uint8_t>(selectedIndex));
if (target == Target::TXT) {
txtFontFamilyDynamicSetter(nullptr, static_cast<uint8_t>(selectedIndex));
} else {
fontFamilyDynamicSetter(nullptr, static_cast<uint8_t>(selectedIndex));
}
finish();
}
@@ -60,13 +48,15 @@ void FontSelectionActivity::render(RenderLock&&) {
const auto& metrics = UITheme::getInstance().getMetrics();
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
const StrId headerStr = target == Target::TXT ? StrId::STR_TXT_FONT_FAMILY : StrId::STR_FONT_FAMILY;
GUI.drawHeader(renderer, Rect{contentRect.x, metrics.topPadding, contentRect.width, metrics.headerHeight},
tr(STR_FONT_FAMILY));
I18N.get(headerStr));
const int contentTop = metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing;
const int contentHeight = contentRect.height - contentTop - metrics.verticalSpacing;
const uint8_t activeIndex = currentFontIndex();
const uint8_t activeIndex = static_cast<uint8_t>(target == Target::TXT ? txtFontFamilyDynamicGetter(nullptr)
: fontFamilyDynamicGetter(nullptr));
GUI.drawList(
renderer, Rect{contentRect.x, contentTop, contentRect.width, contentHeight}, fontCount, selectedIndex,
[](int index) { return fontFamilyOptionLabel(static_cast<uint8_t>(index)); }, nullptr, nullptr,
@@ -11,8 +11,10 @@ class MappedInputManager;
/// Replaces in-place enum cycling for the Reader Font Family setting.
class FontSelectionActivity final : public Activity {
public:
explicit FontSelectionActivity(GfxRenderer& renderer, MappedInputManager& mappedInput)
: Activity("FontSelect", renderer, mappedInput) {}
enum class Target { EPUB, TXT };
explicit FontSelectionActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, Target target = Target::EPUB)
: Activity("FontSelect", renderer, mappedInput), target(target) {}
void onEnter() override;
void onExit() override;
@@ -25,4 +27,5 @@ class FontSelectionActivity final : public Activity {
ButtonNavigator buttonNavigator;
int selectedIndex = 0;
uint8_t fontCount = 0;
Target target;
};
+9
View File
@@ -221,9 +221,18 @@ struct SettingInfo {
}
bool isSeparator = false;
bool usesSelectorActivity = false; // Confirm opens a full-screen selector instead of inline cycling
StrId subcategory = StrId::STR_NONE_OPT; // Triggers a separator row on first use and on change
StrId submenu = StrId::STR_NONE_OPT; // Routes item into a submenu; hidden from main list
// Marks this entry as requiring a full-screen selector activity on Confirm
// (instead of inline value cycling). The SettingsActivity / SettingsSubmenuActivity
// intercept entries with this flag before toggleValue() is called.
SettingInfo& withSelectorActivity() {
usesSelectorActivity = true;
return *this;
}
// Inserts a separator row in the parent tab when this item's subcategory first appears or changes.
SettingInfo& withSubcategory(StrId sub) {
subcategory = sub;
+9 -6
View File
@@ -81,10 +81,11 @@ void SettingsActivity::onEnter() {
setting.nameId == StrId::STR_TIMEZONE)) {
continue;
}
// Enrich the font-family entry with SD card families discovered at boot.
// Enrich font-family entries with SD card families discovered at boot.
// The list itself is a namespace-static; we only mutate our local copy here.
SettingInfo enriched = setting;
if (setting.key && std::strcmp(setting.key, "fontFamily") == 0) {
if (setting.key &&
(std::strcmp(setting.key, "fontFamily") == 0 || std::strcmp(setting.key, "txtFontFamily") == 0)) {
const uint8_t n = fontFamilyOptionCount();
enriched.enumLabels.clear();
enriched.enumLabels.reserve(n);
@@ -96,8 +97,8 @@ void SettingsActivity::onEnter() {
continue;
}
const bool isReaderFontEntry =
enriched.category == StrId::STR_CAT_READER && (enriched.subcategory == StrId::STR_MENU_READER_FONT ||
enriched.submenu == StrId::STR_MENU_READER_FONT_SETTINGS);
enriched.category == StrId::STR_CAT_READER &&
(enriched.submenu == StrId::STR_MENU_READER_FONT || enriched.submenu == StrId::STR_MENU_TXT_FONT);
if (!insertedFontDownload && sawReaderFontSection && !isReaderFontEntry) {
insertFontDownloadBelowFontSection();
@@ -277,8 +278,10 @@ void SettingsActivity::toggleCurrentSetting() {
const auto& setting = (*currentSettings)[selectedSetting];
if (setting.isSeparator) return;
if (setting.type == SettingType::ENUM && setting.nameId == StrId::STR_FONT_FAMILY) {
startActivityForResult(std::make_unique<FontSelectionActivity>(renderer, mappedInput),
if (setting.usesSelectorActivity) {
const auto target = (setting.valueGetter == txtFontFamilyDynamicGetter) ? FontSelectionActivity::Target::TXT
: FontSelectionActivity::Target::EPUB;
startActivityForResult(std::make_unique<FontSelectionActivity>(renderer, mappedInput, target),
[this](const ActivityResult&) {
SETTINGS.saveToFile();
needsHalfRefresh = true;
@@ -6,7 +6,9 @@
#include <I18n.h>
#include "CrossPointSettings.h"
#include "FontSelectionActivity.h"
#include "MappedInputManager.h"
#include "SdCardFontGlobals.h"
#include "SettingActionDispatch.h"
#include "components/UITheme.h"
#include "fontIds.h"
@@ -48,6 +50,26 @@ std::string SettingsSubmenuActivity::getItemValueString(int index) const {
return MenuListActivity::getItemValueString(index);
}
void SettingsSubmenuActivity::toggleCurrentItem() {
if (selectedIndex < 0 || selectedIndex >= static_cast<int>(menuItems.size())) return;
const auto& setting = menuItems[selectedIndex];
if (setting.isSeparator) return;
if (setting.usesSelectorActivity) {
const auto target = (setting.valueGetter == txtFontFamilyDynamicGetter) ? FontSelectionActivity::Target::TXT
: FontSelectionActivity::Target::EPUB;
startActivityForResult(std::make_unique<FontSelectionActivity>(renderer, mappedInput, target),
[this](const ActivityResult&) {
SETTINGS.saveToFile();
needsHalfRefresh = true;
requestUpdate();
});
return;
}
MenuListActivity::toggleCurrentItem();
}
void SettingsSubmenuActivity::onSettingToggled(int /*index*/) { SETTINGS.saveToFile(); }
void SettingsSubmenuActivity::render(RenderLock&&) {
@@ -16,6 +16,7 @@ class SettingsSubmenuActivity final : public MenuListActivity {
// MenuListActivity overrides
void onEnter() override;
void toggleCurrentItem() override;
void onActionSelected(int index) override;
void onSettingToggled(int index) override;
std::string getItemValueString(int index) const override;