#include "QuickOverridesActivity.h" #include #include #include #include "MappedInputManager.h" #include "activities/ActivityResult.h" #include "components/UITheme.h" #include "fontIds.h" QuickOverridesActivity::QuickOverridesActivity( GfxRenderer& renderer, MappedInputManager& mappedInput, const int8_t initialEmbeddedStyleOverride, const int8_t initialImageRenderingOverride, const int8_t initialFontFamilyOverride, const std::string& initialSdFontFamilyOverride, const int8_t initialFontSizeOverride, const int8_t initialBionicReadingOverride, const int8_t initialParagraphAlignmentOverride, const int8_t initialTextAntiAliasingOverride, const int8_t initialHyphenationOverride) : MenuListActivity("QuickOverrides", renderer, mappedInput), pendingEmbeddedStyleOverride(initialEmbeddedStyleOverride), pendingImageRenderingOverride(initialImageRenderingOverride), pendingFontFamilyOverride(initialFontFamilyOverride), pendingSdFontFamilyOverride(initialSdFontFamilyOverride), pendingFontSizeOverride(initialFontSizeOverride), pendingBionicReadingOverride(initialBionicReadingOverride), pendingParagraphAlignmentOverride(initialParagraphAlignmentOverride), pendingTextAntiAliasingOverride(initialTextAntiAliasingOverride), pendingHyphenationOverride(initialHyphenationOverride) { buildMenuItems(); } namespace { // Three-state cycle helper for overrides represented as int8_t with -1 = default. // slot 0 -> -1 (default) // slot 1 -> 1 (on) // slot 2 -> 0 (off) uint8_t threeStateSlotFromOverride(int8_t value) { if (value < 0) return 0; if (value > 0) return 1; return 2; } int8_t threeStateOverrideFromSlot(uint8_t slot) { if (slot == 0) return -1; if (slot == 1) return 1; return 0; } } // namespace void QuickOverridesActivity::buildMenuItems() { menuItems.reserve(8); auto* self = this; // Embedded style: default / on / off menuItems.push_back(SettingInfo::DynamicEnumCtx( StrId::STR_EMBEDDED_STYLE, {StrId::STR_DEFAULT_VALUE, StrId::STR_STATE_ON, StrId::STR_STATE_OFF}, self, [](const void* ctx) -> uint8_t { return threeStateSlotFromOverride( static_cast(ctx)->pendingEmbeddedStyleOverride); }, [](void* ctx, uint8_t v) { static_cast(ctx)->pendingEmbeddedStyleOverride = threeStateOverrideFromSlot(v); })); // Image rendering: default(-1) / display(0) / placeholder(1) / suppress(2) menuItems.push_back(SettingInfo::DynamicEnumCtx( StrId::STR_IMAGES, {StrId::STR_DEFAULT_VALUE, StrId::STR_IMAGES_DISPLAY, StrId::STR_IMAGES_PLACEHOLDER, StrId::STR_IMAGES_SUPPRESS}, self, [](const void* ctx) -> uint8_t { const auto* s = static_cast(ctx); return (s->pendingImageRenderingOverride < 0) ? 0 : (s->pendingImageRenderingOverride + 1); }, [](void* ctx, uint8_t v) { auto* s = static_cast(ctx); s->pendingImageRenderingOverride = (v == 0) ? -1 : static_cast(v - 1); })); // Font family: built-in only — preserves any SD-family override unless the user // explicitly picks a built-in (which clears it, matching the storage semantics). menuItems.push_back(SettingInfo::DynamicEnumCtx( StrId::STR_FONT_FAMILY, {StrId::STR_DEFAULT_VALUE, StrId::STR_BOOKERLY, StrId::STR_NOTO_SANS}, self, [](const void* ctx) -> uint8_t { const auto* s = static_cast(ctx); return (s->pendingFontFamilyOverride < 0) ? 0 : static_cast(s->pendingFontFamilyOverride + 1); }, [](void* ctx, uint8_t v) { auto* s = static_cast(ctx); if (v == 0) { s->pendingFontFamilyOverride = -1; } else { s->pendingFontFamilyOverride = static_cast(v - 1); s->pendingSdFontFamilyOverride.clear(); } })); // Font size: default(-1) -> Small(0) -> Medium(1) -> Large(2) -> X Large(3) -> Tiny(4) menuItems.push_back(SettingInfo::DynamicEnumCtx( StrId::STR_FONT_SIZE, {StrId::STR_DEFAULT_VALUE, StrId::STR_SMALL, StrId::STR_MEDIUM, StrId::STR_LARGE, StrId::STR_X_LARGE, StrId::STR_TINY}, self, [](const void* ctx) -> uint8_t { const auto* s = static_cast(ctx); return (s->pendingFontSizeOverride < 0) ? 0 : static_cast(s->pendingFontSizeOverride + 1); }, [](void* ctx, uint8_t v) { auto* s = static_cast(ctx); s->pendingFontSizeOverride = (v == 0) ? -1 : static_cast(v - 1); })); // Bionic: default / on / off menuItems.push_back(SettingInfo::DynamicEnumCtx( StrId::STR_BIONIC_READING, {StrId::STR_DEFAULT_VALUE, StrId::STR_STATE_ON, StrId::STR_STATE_OFF}, self, [](const void* ctx) -> uint8_t { return threeStateSlotFromOverride( static_cast(ctx)->pendingBionicReadingOverride); }, [](void* ctx, uint8_t v) { static_cast(ctx)->pendingBionicReadingOverride = threeStateOverrideFromSlot(v); })); // Paragraph alignment: default(-1) + the 5 global options menuItems.push_back(SettingInfo::DynamicEnumCtx( StrId::STR_PARA_ALIGNMENT, {StrId::STR_DEFAULT_VALUE, StrId::STR_JUSTIFY, StrId::STR_ALIGN_LEFT, StrId::STR_CENTER, StrId::STR_ALIGN_RIGHT, StrId::STR_BOOK_S_STYLE}, self, [](const void* ctx) -> uint8_t { const auto* s = static_cast(ctx); return (s->pendingParagraphAlignmentOverride < 0) ? 0 : static_cast(s->pendingParagraphAlignmentOverride + 1); }, [](void* ctx, uint8_t v) { auto* s = static_cast(ctx); s->pendingParagraphAlignmentOverride = (v == 0) ? -1 : static_cast(v - 1); })); // Text anti-aliasing: default / on / off menuItems.push_back(SettingInfo::DynamicEnumCtx( StrId::STR_TEXT_AA, {StrId::STR_DEFAULT_VALUE, StrId::STR_STATE_ON, StrId::STR_STATE_OFF}, self, [](const void* ctx) -> uint8_t { return threeStateSlotFromOverride( static_cast(ctx)->pendingTextAntiAliasingOverride); }, [](void* ctx, uint8_t v) { static_cast(ctx)->pendingTextAntiAliasingOverride = threeStateOverrideFromSlot(v); })); // Hyphenation: default / on / off menuItems.push_back(SettingInfo::DynamicEnumCtx( StrId::STR_HYPHENATION, {StrId::STR_DEFAULT_VALUE, StrId::STR_STATE_ON, StrId::STR_STATE_OFF}, self, [](const void* ctx) -> uint8_t { return threeStateSlotFromOverride(static_cast(ctx)->pendingHyphenationOverride); }, [](void* ctx, uint8_t v) { static_cast(ctx)->pendingHyphenationOverride = threeStateOverrideFromSlot(v); })); } void QuickOverridesActivity::onEnter() { MenuListActivity::onEnter(); // Fast refresh keeps the menu feeling responsive when cycling options. The // parent reader is responsible for its own full refresh on resume if any // override actually changed (applyBookReaderOverrides short-circuits if not). renderer.setNextDisplayRefreshMode(HalDisplay::FAST_REFRESH); } void QuickOverridesActivity::onSettingToggled(int /*index*/) { // No persistence on each toggle — overrides are committed on exit through // the result handler in the parent reader activity. renderer.setNextDisplayRefreshMode(HalDisplay::FAST_REFRESH); } void QuickOverridesActivity::onBackPressed() { finishWithResult(/*cancelled=*/false); } void QuickOverridesActivity::finishWithResult(bool cancelled) { ActivityResult result; result.isCancelled = cancelled; MenuResult payload; payload.action = -1; payload.nameId = -1; payload.embeddedStyleOverride = pendingEmbeddedStyleOverride; payload.imageRenderingOverride = pendingImageRenderingOverride; payload.fontFamilyOverride = pendingFontFamilyOverride; payload.sdFontFamilyOverride = pendingSdFontFamilyOverride; payload.fontSizeOverride = pendingFontSizeOverride; payload.bionicReadingOverride = (pendingBionicReadingOverride > 0) ? 1 : 0; payload.paragraphAlignmentOverride = pendingParagraphAlignmentOverride; payload.textAntiAliasingOverride = pendingTextAntiAliasingOverride; payload.hyphenationOverride = pendingHyphenationOverride; result.data = std::move(payload); setResult(std::move(result)); finish(); } void QuickOverridesActivity::render(RenderLock&&) { renderer.clearScreen(); const Rect contentRect = UITheme::getContentRect(renderer, true, false); const std::string title = tr(STR_QUICK_OVERRIDES); const int titleX = contentRect.x + (contentRect.width - renderer.getTextWidth(UI_12_FONT_ID, title.c_str(), EpdFontFamily::BOLD)) / 2; renderer.drawText(UI_12_FONT_ID, titleX, 15 + contentRect.y, title.c_str(), true, EpdFontFamily::BOLD); const int startY = 50 + contentRect.y; const int listHeight = contentRect.height - (startY - contentRect.y); drawMenuList(Rect{contentRect.x, startY, contentRect.width, listHeight}); const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), tr(STR_DIR_UP), tr(STR_DIR_DOWN)); GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); renderer.displayBuffer(HalDisplay::FAST_REFRESH); }