Merge staging: ef-1.0.1 and ef-1.0.2
ef-1.0.2 - Quick Menu Enhancements - Screen rotation toggle (Portrait/Landscape CCW) - Customizable menu order with pick-and-place reordering - Navigation button hints on quick menu ef-1.0.1 - Dictionary Stability & UX - Fixed dictionary crashes from heap fragmentation - Refactored TextBlock/ParsedText to std::vector (~12x fewer allocations) - Uncompressed .dict support, chunked HTML parsing - Orientation-aware button hints on dictionary screens
This commit is contained in:
commit
d5e42b9e40
105
ef-CHANGELOG.md
Normal file
105
ef-CHANGELOG.md
Normal file
@ -0,0 +1,105 @@
|
||||
# crosspoint-ef Changelog
|
||||
|
||||
All notable changes to the crosspoint-ef fork are documented here.
|
||||
|
||||
Base: CrossPoint Reader 0.15.0
|
||||
|
||||
---
|
||||
|
||||
## ef-1.0.2
|
||||
|
||||
**Quick Menu Enhancements**
|
||||
|
||||
### New Features
|
||||
|
||||
- **Screen Rotation Toggle**: Quick toggle between Portrait and Landscape CCW directly from the quick menu
|
||||
- Automatically reindexes content for new screen dimensions
|
||||
- Preserves reading position via content offset restoration
|
||||
- **Customizable Menu Order**: Reorder quick menu items to your preference
|
||||
- New "Edit List Order" option at bottom of menu
|
||||
- Pick-and-place reordering: select item, navigate to destination, place
|
||||
- Order persists across sessions
|
||||
|
||||
### UI Improvements
|
||||
|
||||
- Added navigation button hints to quick menu (prev/next on front buttons, up/down on side buttons)
|
||||
- Fixed orientation-aware margins for button hint areas in landscape modes
|
||||
- New default menu order: Bookmark, Dictionary, Rotate Screen, Settings, Clear Cache
|
||||
|
||||
---
|
||||
|
||||
## ef-1.0.1
|
||||
|
||||
**Dictionary Stability & UX Improvements**
|
||||
|
||||
### Bug Fixes - Stability
|
||||
|
||||
- Fixed dictionary crashes caused by heap fragmentation from repeated page navigation
|
||||
- Refactored TextBlock/ParsedText from `std::list` to `std::vector`, reducing heap allocations by ~12x per TextBlock
|
||||
- Affects EPUB reader page rendering, dictionary definition display, and word selection
|
||||
- Contiguous memory improves cache locality during text layout and reduces heap fragmentation on the memory-constrained ESP32
|
||||
- Added uncompressed dictionary (`.dict`) support to avoid decompression memory issues with large dictzip chunks (58KB chunks -> direct read)
|
||||
- Implemented chunked on-demand HTML parsing for large definitions, parsing pages as user navigates rather than all at once
|
||||
- Limited cached pages to 4 with re-parse capability for backward navigation beyond cache window
|
||||
- Fixed double-button press bug when loading new dictionary chunks
|
||||
|
||||
### Bug Fixes - UI/Layout
|
||||
|
||||
- Restored proper orientation-aware button hint spacing (front: 45px, side: 50px)
|
||||
- Added side button hints to definition screen with "<" / ">" labels for page navigation
|
||||
- Added side button hints to word selection screen ("UP"/"DOWN" labels, borderless, small font)
|
||||
- Added side button hints to dictionary menu ("< Prev", "Next >")
|
||||
- Moved page indicator up to avoid bezel cutoff in landscape orientations
|
||||
|
||||
---
|
||||
|
||||
## ef-1.0.0
|
||||
|
||||
**First Official Release** (previously ef-0.15.99)
|
||||
|
||||
First milestone release of the crosspoint-ef fork, building on CrossPoint Reader 0.15.0 with 14+ major new features and enhancements.
|
||||
|
||||
### New Features
|
||||
|
||||
- **Dictionary Support**: Offline StarDict dictionary with word selection from reader, fast prefix-indexed search, rich HTML formatting, and multi-page pagination
|
||||
- **Bookmark System**: Per-book bookmarks with visual folded-corner indicators, dedicated management interface, and auto-generated bookmark names
|
||||
- **Quick Menu**: In-reader quick access menu for common actions (Dictionary, Bookmark, Clear Cache, Settings) via short power button press
|
||||
- **Library Search**: Search across all books by title, author, or filename with dynamic character picker and weighted relevance scoring
|
||||
- **CSS Support**: Parse and apply CSS styles from EPUB stylesheets (text-align, font-style, font-weight, text-decoration, margins, padding)
|
||||
- **Inline Image Support**: PNG and Baseline JPEG rendering within EPUB content with 2-bit grayscale dithering and caching
|
||||
- **Custom Fonts**: Atkinson Hyperlegible Next (low-vision readers) and Fern Micro (small screens)
|
||||
- **Enhanced Web Server**: File management (upload, download, delete, rename, copy, move, mkdir), companion app API, WebSocket uploads, mDNS discovery at `crosspoint.local`
|
||||
- **Reading Lists**: Create, manage, and pin custom book lists with web API support (CSV format)
|
||||
- **Enhanced Tab Bar**: Unified tab bar with horizontal scrolling and overflow indicators (Recent, Lists, Bookmarks, Search, Files)
|
||||
- **Progress Bar Status**: Additional status bar option showing visual reading progress
|
||||
- **OPDS Browser Enhancements**: Navigation history, page skipping (hold Up/Down), error retry, HTTP Basic Auth support
|
||||
|
||||
### Display Enhancements
|
||||
|
||||
- **High Contrast Mode**: System-wide contrast adjustment
|
||||
- **Bezel Compensation**: Configurable margin (0-10px) for physical screen edge defects
|
||||
- **Sleep Screen Improvements**: Edge-aware color filling for seamless letterbox appearance
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fixed device hanging when booted without USB connected (Serial.available()/Serial.read() called without Serial.begin())
|
||||
- Fixed grayscale state corruption causing ghosting artifacts when anti-aliasing enabled under memory pressure
|
||||
- Memory optimization with graceful degradation when memory is low
|
||||
|
||||
### Development Tools
|
||||
|
||||
- `pre_flash.py`: Displays "Flashing firmware..." screen during upload
|
||||
- `debugging_monitor.py`: Enhanced serial monitor with memory graphs
|
||||
- `pio_helper.py`: Interactive PlatformIO workflow helper
|
||||
|
||||
---
|
||||
|
||||
## Differences from Upstream 0.16.0
|
||||
|
||||
This fork is based on upstream 0.15.0. The following 0.16.0 features are not included:
|
||||
|
||||
- KOReader sync support
|
||||
- Non-English hyphenation patterns (Spanish, German, French, Russian)
|
||||
- XTC/XTCH file format support
|
||||
|
||||
See [crosspoint-ef-features.md](docs/crosspoint-ef-features.md) for complete feature documentation.
|
||||
@ -2,7 +2,8 @@
|
||||
default_envs = default
|
||||
|
||||
[crosspoint]
|
||||
version = ef-0.15.99
|
||||
# 0.15.0 CrossPoint base, ef-1.0.0 is the first release of the ef branch
|
||||
version = 0.15.ef-1.0.2
|
||||
|
||||
[base]
|
||||
platform = espressif32 @ 6.12.0
|
||||
|
||||
@ -155,6 +155,11 @@ class CrossPointSettings {
|
||||
// Pinned list name (empty = none pinned)
|
||||
char pinnedListName[64] = "";
|
||||
|
||||
// Quick menu item order (indices 0-4 representing the 5 menu items)
|
||||
// Maps to QuickMenuAction enum: 0=Dictionary, 1=Bookmark, 2=ClearCache, 3=Orientation, 4=Settings
|
||||
// Default order: Bookmark(1), Dictionary(0), Orientation(3), Settings(4), ClearCache(2)
|
||||
uint8_t quickMenuOrder[5] = {1, 0, 3, 4, 2};
|
||||
|
||||
~CrossPointSettings() = default;
|
||||
|
||||
// Get singleton instance
|
||||
|
||||
@ -496,6 +496,28 @@ void EpubReaderActivity::loop() {
|
||||
self->onGoToClearCache();
|
||||
return;
|
||||
}
|
||||
self->updateRequired = true;
|
||||
} else if (action == QuickMenuAction::TOGGLE_ORIENTATION) {
|
||||
// Toggle between Portrait and Landscape CCW
|
||||
if (SETTINGS.orientation == CrossPointSettings::ORIENTATION::PORTRAIT) {
|
||||
SETTINGS.orientation = CrossPointSettings::ORIENTATION::LANDSCAPE_CCW;
|
||||
} else {
|
||||
SETTINGS.orientation = CrossPointSettings::ORIENTATION::PORTRAIT;
|
||||
}
|
||||
SETTINGS.saveToFile();
|
||||
|
||||
// Apply new orientation to renderer
|
||||
if (SETTINGS.orientation == CrossPointSettings::ORIENTATION::PORTRAIT) {
|
||||
self->renderer.setOrientation(GfxRenderer::Orientation::Portrait);
|
||||
} else {
|
||||
self->renderer.setOrientation(GfxRenderer::Orientation::LandscapeCounterClockwise);
|
||||
}
|
||||
|
||||
// Force section reload with new orientation's viewport dimensions
|
||||
xSemaphoreTake(cachedMutex, portMAX_DELAY);
|
||||
self->section.reset();
|
||||
xSemaphoreGive(cachedMutex);
|
||||
|
||||
self->updateRequired = true;
|
||||
} else if (action == QuickMenuAction::GO_TO_SETTINGS) {
|
||||
// Navigate to Settings activity
|
||||
|
||||
@ -2,16 +2,25 @@
|
||||
|
||||
#include <GfxRenderer.h>
|
||||
|
||||
#include "CrossPointSettings.h"
|
||||
#include "MappedInputManager.h"
|
||||
#include "fontIds.h"
|
||||
|
||||
namespace {
|
||||
constexpr int MENU_ITEM_COUNT = 4;
|
||||
const char* MENU_ITEMS[MENU_ITEM_COUNT] = {"Dictionary", "Bookmark", "Clear Cache", "Settings"};
|
||||
const char* MENU_DESCRIPTIONS_ADD[MENU_ITEM_COUNT] = {"Look up a word", "Add bookmark to this page",
|
||||
"Free up storage space", "Open settings menu"};
|
||||
const char* MENU_DESCRIPTIONS_REMOVE[MENU_ITEM_COUNT] = {"Look up a word", "Remove bookmark from this page",
|
||||
"Free up storage space", "Open settings menu"};
|
||||
// Base menu item count (reorderable items)
|
||||
constexpr int BASE_MENU_ITEM_COUNT = 5;
|
||||
// Total display count including "Edit List Order"
|
||||
constexpr int DISPLAY_ITEM_COUNT = 6;
|
||||
|
||||
// Menu items indexed by QuickMenuAction enum value
|
||||
// 0=Dictionary, 1=Bookmark, 2=ClearCache, 3=Orientation, 4=Settings
|
||||
const char* MENU_ITEMS[BASE_MENU_ITEM_COUNT] = {"Dictionary", "Bookmark", "Clear Cache", "Rotate Screen", "Settings"};
|
||||
const char* MENU_DESCRIPTIONS_ADD[BASE_MENU_ITEM_COUNT] = {"Look up a word", "Add bookmark to this page",
|
||||
"Free up storage space", "Toggle screen orientation",
|
||||
"Open settings menu"};
|
||||
const char* MENU_DESCRIPTIONS_REMOVE[BASE_MENU_ITEM_COUNT] = {"Look up a word", "Remove bookmark from this page",
|
||||
"Free up storage space", "Toggle screen orientation",
|
||||
"Open settings menu"};
|
||||
} // namespace
|
||||
|
||||
void QuickMenuActivity::taskTrampoline(void* param) {
|
||||
@ -53,6 +62,16 @@ void QuickMenuActivity::onExit() {
|
||||
}
|
||||
|
||||
void QuickMenuActivity::loop() {
|
||||
if (editMode) {
|
||||
// Edit mode logic
|
||||
handleEditMode();
|
||||
} else {
|
||||
// Normal mode logic
|
||||
handleNormalMode();
|
||||
}
|
||||
}
|
||||
|
||||
void QuickMenuActivity::handleNormalMode() {
|
||||
// Handle back button - cancel
|
||||
if (mappedInput.wasReleased(MappedInputManager::Button::Back)) {
|
||||
onCancel();
|
||||
@ -61,8 +80,22 @@ void QuickMenuActivity::loop() {
|
||||
|
||||
// Handle confirm button - select current option
|
||||
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
||||
// Last item is "Edit List Order"
|
||||
if (selectedIndex == DISPLAY_ITEM_COUNT - 1) {
|
||||
// Enter edit mode - copy current order to local buffer
|
||||
for (int i = 0; i < BASE_MENU_ITEM_COUNT; i++) {
|
||||
localOrder[i] = SETTINGS.quickMenuOrder[i];
|
||||
}
|
||||
editMode = true;
|
||||
selectedIndex = 0; // Start at first item in edit mode
|
||||
updateRequired = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the action from the order array
|
||||
const int actionIndex = SETTINGS.quickMenuOrder[selectedIndex];
|
||||
QuickMenuAction action;
|
||||
switch (selectedIndex) {
|
||||
switch (actionIndex) {
|
||||
case 0:
|
||||
action = QuickMenuAction::DICTIONARY;
|
||||
break;
|
||||
@ -73,6 +106,9 @@ void QuickMenuActivity::loop() {
|
||||
action = QuickMenuAction::CLEAR_CACHE;
|
||||
break;
|
||||
case 3:
|
||||
action = QuickMenuAction::TOGGLE_ORIENTATION;
|
||||
break;
|
||||
case 4:
|
||||
default:
|
||||
action = QuickMenuAction::GO_TO_SETTINGS;
|
||||
break;
|
||||
@ -88,10 +124,69 @@ void QuickMenuActivity::loop() {
|
||||
mappedInput.wasPressed(MappedInputManager::Button::Right);
|
||||
|
||||
if (prevPressed) {
|
||||
selectedIndex = (selectedIndex + MENU_ITEM_COUNT - 1) % MENU_ITEM_COUNT;
|
||||
selectedIndex = (selectedIndex + DISPLAY_ITEM_COUNT - 1) % DISPLAY_ITEM_COUNT;
|
||||
updateRequired = true;
|
||||
} else if (nextPressed) {
|
||||
selectedIndex = (selectedIndex + 1) % MENU_ITEM_COUNT;
|
||||
selectedIndex = (selectedIndex + 1) % DISPLAY_ITEM_COUNT;
|
||||
updateRequired = true;
|
||||
}
|
||||
}
|
||||
|
||||
void QuickMenuActivity::handleEditMode() {
|
||||
// Handle back button - save and exit edit mode
|
||||
if (mappedInput.wasReleased(MappedInputManager::Button::Back)) {
|
||||
// Save the local order to settings
|
||||
for (int i = 0; i < BASE_MENU_ITEM_COUNT; i++) {
|
||||
SETTINGS.quickMenuOrder[i] = localOrder[i];
|
||||
}
|
||||
SETTINGS.saveToFile();
|
||||
editMode = false;
|
||||
movingIndex = -1;
|
||||
selectedIndex = DISPLAY_ITEM_COUNT - 1; // Select "Edit List Order" when exiting
|
||||
updateRequired = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle confirm button - pick or place item
|
||||
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
||||
if (movingIndex < 0) {
|
||||
// No item selected yet - pick up the current item
|
||||
movingIndex = selectedIndex;
|
||||
} else {
|
||||
// Item is being moved - place it at the current position
|
||||
if (movingIndex != selectedIndex) {
|
||||
// Remove item from old position and insert at new position
|
||||
const uint8_t movingItem = localOrder[movingIndex];
|
||||
if (movingIndex < selectedIndex) {
|
||||
// Moving down - shift items up
|
||||
for (int i = movingIndex; i < selectedIndex; i++) {
|
||||
localOrder[i] = localOrder[i + 1];
|
||||
}
|
||||
} else {
|
||||
// Moving up - shift items down
|
||||
for (int i = movingIndex; i > selectedIndex; i--) {
|
||||
localOrder[i] = localOrder[i - 1];
|
||||
}
|
||||
}
|
||||
localOrder[selectedIndex] = movingItem;
|
||||
}
|
||||
movingIndex = -1; // Deselect
|
||||
}
|
||||
updateRequired = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle navigation - just move cursor
|
||||
const bool prevPressed = mappedInput.wasPressed(MappedInputManager::Button::Up) ||
|
||||
mappedInput.wasPressed(MappedInputManager::Button::Left);
|
||||
const bool nextPressed = mappedInput.wasPressed(MappedInputManager::Button::Down) ||
|
||||
mappedInput.wasPressed(MappedInputManager::Button::Right);
|
||||
|
||||
if (prevPressed && selectedIndex > 0) {
|
||||
selectedIndex--;
|
||||
updateRequired = true;
|
||||
} else if (nextPressed && selectedIndex < BASE_MENU_ITEM_COUNT - 1) {
|
||||
selectedIndex++;
|
||||
updateRequired = true;
|
||||
}
|
||||
}
|
||||
@ -120,46 +215,110 @@ void QuickMenuActivity::render() const {
|
||||
const int bezelRight = renderer.getBezelOffsetRight();
|
||||
const int bezelBottom = renderer.getBezelOffsetBottom();
|
||||
|
||||
// Calculate usable content area
|
||||
const int marginLeft = 20 + bezelLeft;
|
||||
const int marginRight = 20 + bezelRight;
|
||||
const int marginTop = 15 + bezelTop;
|
||||
const int contentWidth = pageWidth - marginLeft - marginRight;
|
||||
const int contentHeight = pageHeight - marginTop - 60 - bezelBottom; // 60 for button hints
|
||||
// Button hint space constants
|
||||
constexpr int FRONT_BUTTON_SPACE = 45; // 40px button height + 5px padding
|
||||
constexpr int SIDE_BUTTON_SPACE = 50; // 45px button area + 5px padding
|
||||
|
||||
// Draw header
|
||||
renderer.drawCenteredText(UI_12_FONT_ID, marginTop, "Quick Menu", true, EpdFontFamily::BOLD);
|
||||
// Calculate button hint margins based on orientation
|
||||
// Physical button locations (fixed on device):
|
||||
// - Front buttons: physical bottom in portrait
|
||||
// - Side buttons: physical right in portrait
|
||||
// These map to different logical edges depending on orientation
|
||||
int frontBtnMarginTop = 0, frontBtnMarginBottom = 0, frontBtnMarginLeft = 0, frontBtnMarginRight = 0;
|
||||
int sideBtnMarginTop = 0, sideBtnMarginBottom = 0, sideBtnMarginLeft = 0, sideBtnMarginRight = 0;
|
||||
|
||||
switch (renderer.getOrientation()) {
|
||||
case GfxRenderer::Portrait:
|
||||
// Front buttons at logical BOTTOM, Side buttons at logical RIGHT
|
||||
frontBtnMarginBottom = FRONT_BUTTON_SPACE;
|
||||
sideBtnMarginRight = SIDE_BUTTON_SPACE;
|
||||
break;
|
||||
case GfxRenderer::LandscapeClockwise:
|
||||
// Front buttons at logical LEFT, Side buttons at logical BOTTOM
|
||||
frontBtnMarginLeft = FRONT_BUTTON_SPACE;
|
||||
sideBtnMarginBottom = SIDE_BUTTON_SPACE;
|
||||
break;
|
||||
case GfxRenderer::PortraitInverted:
|
||||
// Front buttons at logical TOP, Side buttons at logical LEFT
|
||||
frontBtnMarginTop = FRONT_BUTTON_SPACE;
|
||||
sideBtnMarginLeft = SIDE_BUTTON_SPACE;
|
||||
break;
|
||||
case GfxRenderer::LandscapeCounterClockwise:
|
||||
// Front buttons at logical RIGHT, Side buttons at logical TOP
|
||||
frontBtnMarginRight = FRONT_BUTTON_SPACE;
|
||||
sideBtnMarginTop = SIDE_BUTTON_SPACE;
|
||||
break;
|
||||
}
|
||||
|
||||
// Calculate usable content area with bezel and button hint margins
|
||||
const int marginLeft = 20 + bezelLeft + frontBtnMarginLeft + sideBtnMarginLeft;
|
||||
const int marginRight = 20 + bezelRight + frontBtnMarginRight + sideBtnMarginRight;
|
||||
const int marginTop = 15 + bezelTop + frontBtnMarginTop + sideBtnMarginTop;
|
||||
const int marginBottom = 15 + bezelBottom + frontBtnMarginBottom + sideBtnMarginBottom;
|
||||
const int contentWidth = pageWidth - marginLeft - marginRight;
|
||||
const int contentHeight = pageHeight - marginTop - marginBottom;
|
||||
|
||||
// Draw header - different text in edit mode
|
||||
const char* headerText = editMode ? "Edit Menu Order" : "Quick Menu";
|
||||
renderer.drawCenteredText(UI_12_FONT_ID, marginTop, headerText, true, EpdFontFamily::BOLD);
|
||||
|
||||
// Select descriptions based on bookmark state
|
||||
const char* const* descriptions = isPageBookmarked ? MENU_DESCRIPTIONS_REMOVE : MENU_DESCRIPTIONS_ADD;
|
||||
|
||||
// Get the order array to use (local copy in edit mode, settings otherwise)
|
||||
const uint8_t* order = editMode ? localOrder : SETTINGS.quickMenuOrder;
|
||||
|
||||
// Draw menu items centered in content area
|
||||
constexpr int itemHeight = 50; // Height for each menu item (including description)
|
||||
const int startY = marginTop + (contentHeight - (MENU_ITEM_COUNT * itemHeight)) / 2;
|
||||
const int startY = marginTop + (contentHeight - (DISPLAY_ITEM_COUNT * itemHeight)) / 2;
|
||||
|
||||
for (int i = 0; i < MENU_ITEM_COUNT; i++) {
|
||||
for (int i = 0; i < DISPLAY_ITEM_COUNT; i++) {
|
||||
const int itemY = startY + i * itemHeight;
|
||||
const bool isSelected = (i == selectedIndex);
|
||||
const bool isBeingMoved = (editMode && i == movingIndex);
|
||||
|
||||
// Draw selection highlight (black fill) for selected item
|
||||
if (isSelected) {
|
||||
renderer.fillRect(marginLeft + 10, itemY - 2, contentWidth - 20, itemHeight - 6);
|
||||
}
|
||||
|
||||
// Draw menu item text
|
||||
const char* itemText = MENU_ITEMS[i];
|
||||
// For bookmark item, show different text based on state
|
||||
if (i == 1) {
|
||||
itemText = isPageBookmarked ? "Remove Bookmark" : "Add Bookmark";
|
||||
// Draw outline for item being moved (when cursor is elsewhere)
|
||||
if (isBeingMoved && !isSelected) {
|
||||
renderer.drawRect(marginLeft + 10, itemY - 2, contentWidth - 20, itemHeight - 6);
|
||||
}
|
||||
|
||||
renderer.drawText(UI_10_FONT_ID, marginLeft + 20, itemY, itemText, !isSelected);
|
||||
renderer.drawText(SMALL_FONT_ID, marginLeft + 20, itemY + 22, descriptions[i], !isSelected);
|
||||
// Last item is always "Edit List Order" (fixed, not in the order array)
|
||||
if (i == DISPLAY_ITEM_COUNT - 1) {
|
||||
renderer.drawText(UI_10_FONT_ID, marginLeft + 20, itemY, "- Edit List Order -", !isSelected);
|
||||
renderer.drawText(SMALL_FONT_ID, marginLeft + 20, itemY + 22, "Customize menu order", !isSelected);
|
||||
} else {
|
||||
// Get the action index from the order array
|
||||
const int actionIndex = order[i];
|
||||
|
||||
// Draw menu item text - add indicator for item being moved
|
||||
const char* itemText = MENU_ITEMS[actionIndex];
|
||||
// For bookmark item (action index 1), show different text based on state
|
||||
if (actionIndex == 1) {
|
||||
itemText = isPageBookmarked ? "Remove Bookmark" : "Add Bookmark";
|
||||
}
|
||||
|
||||
renderer.drawText(UI_10_FONT_ID, marginLeft + 20, itemY, itemText, !isSelected);
|
||||
renderer.drawText(SMALL_FONT_ID, marginLeft + 20, itemY + 22, descriptions[actionIndex], !isSelected);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw help text at bottom
|
||||
const auto labels = mappedInput.mapLabels("\xc2\xab Back", "Select", "", "");
|
||||
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||
// Draw help text at bottom - different hints for edit mode
|
||||
if (editMode) {
|
||||
const char* confirmLabel = (movingIndex < 0) ? "Pick" : "Place";
|
||||
const auto labels = mappedInput.mapLabels("\xc2\xab Done", confirmLabel, "", "");
|
||||
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||
// Side button hints for navigation
|
||||
renderer.drawSideButtonHints(UI_10_FONT_ID, "<", ">");
|
||||
} else {
|
||||
const auto labels = mappedInput.mapLabels("\xc2\xab Back", "Select", "< Prev", "Next >");
|
||||
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||
// Side button hints for up/down navigation
|
||||
renderer.drawSideButtonHints(UI_10_FONT_ID, "<", ">");
|
||||
}
|
||||
|
||||
renderer.displayBuffer();
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
#include "../Activity.h"
|
||||
|
||||
// Enum for quick menu selection
|
||||
enum class QuickMenuAction { DICTIONARY, ADD_BOOKMARK, CLEAR_CACHE, GO_TO_SETTINGS };
|
||||
enum class QuickMenuAction { DICTIONARY, ADD_BOOKMARK, CLEAR_CACHE, TOGGLE_ORIENTATION, GO_TO_SETTINGS };
|
||||
|
||||
/**
|
||||
* QuickMenuActivity presents a quick access menu triggered by short power button press.
|
||||
@ -28,9 +28,16 @@ class QuickMenuActivity final : public Activity {
|
||||
const std::function<void()> onCancel;
|
||||
const bool isPageBookmarked; // True if current page already has a bookmark
|
||||
|
||||
// Edit mode state
|
||||
bool editMode = false; // True when in edit mode
|
||||
int movingIndex = -1; // Index of item being moved (-1 if none)
|
||||
uint8_t localOrder[5] = {0}; // Local copy of order for editing
|
||||
|
||||
static void taskTrampoline(void* param);
|
||||
[[noreturn]] void displayTaskLoop();
|
||||
void render() const;
|
||||
void handleNormalMode();
|
||||
void handleEditMode();
|
||||
|
||||
public:
|
||||
explicit QuickMenuActivity(GfxRenderer& renderer, MappedInputManager& mappedInput,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user