Brings ~55 mod-exclusive files to the upstream-based mod/master-resync branch: Activities (migrated to new ActivityManager pattern): - Clock/Time: SetTimeActivity, SetTimezoneOffsetActivity, NtpSyncActivity - Dictionary: DictionaryDefinitionActivity, DictionarySuggestionsActivity, DictionaryWordSelectActivity, LookedUpWordsActivity - Bookmark: EpubReaderBookmarkSelectionActivity - Book management: BookManageMenuActivity, EndOfBookMenuActivity - OPDS: OpdsServerListActivity, OpdsSettingsActivity - Utility: DirectoryPickerActivity, NumericStepperActivity Utilities (unchanged): - BookManager, BookSettings, BookmarkStore, BootNtpSync - Dictionary, LookupHistory, TimeSync, OpdsServerStore Libraries: PlaceholderCover, TableData, ChapterXPathIndexer Scripts: inject_mod_version, generate_book_icon, preview_placeholder_cover Docs: KOReader sync XPath mapping Migration changes: - ActivityWithSubactivity -> Activity base class - Callback constructors -> finish()/setResult() pattern - enterNewActivity() -> startActivityForResult() - Activity::RenderLock&& -> RenderLock&& These files won't compile yet - they reference mod settings and I18n strings that will be added in subsequent phases. Made-with: Cursor
54 lines
4.1 KiB
Markdown
54 lines
4.1 KiB
Markdown
# Dictionary Feature Bug Fixes (Round 2)
|
||
|
||
**Date:** 2026-02-12
|
||
**Branch:** mod/add-dictionary
|
||
|
||
## Task
|
||
|
||
Fix three remaining bugs with the dictionary word lookup feature after initial implementation and first round of fixes.
|
||
|
||
## Changes Made
|
||
|
||
### 1. Fix: Lookup only works for first word searched (Dictionary.cpp)
|
||
|
||
**Root cause:** The binary search used C++ `operator<=` (case-sensitive, pure `strcmp` order) for comparing index entries, but StarDict `.idx` files are sorted using `stardict_strcmp` — a two-level comparison that sorts case-*insensitively* first, then uses case-sensitive `strcmp` as a tiebreaker. This means entries like "Simple" and "simple" are adjacent, and uppercase/lowercase entries for the same letter are interleaved (e.g., "Silver", "silver", "Simple", "simple", "Simpson", "simpson").
|
||
|
||
With the wrong sort order, the binary search overshoots for many words: uppercase entries like "Simpson" are case-sensitively < "simple" (because 'S' < 's'), so `lo` moves past the segment actually containing "simple". The linear scan then starts too late and doesn't find the word. By coincidence, some words (like "professor") happen to land in correct segments while others (like "simple") don't.
|
||
|
||
**Fix:**
|
||
- Added `stardictCmp()` (case-insensitive first, then case-sensitive tiebreaker) and `asciiCaseCmp()` helper functions
|
||
- Binary search now uses `stardictCmp(key, word) <= 0` instead of `key <= word`
|
||
- Linear scan early termination now uses `stardictCmp(key, word) > 0` instead of `key > word`
|
||
- Exact match now uses `asciiCaseCmp(key, word) == 0` (case-insensitive) since `cleanWord` lowercases the search term but the dictionary may store entries in any case
|
||
- Removed the two-pass search approach (no longer needed — single pass handles all casing)
|
||
|
||
**Files:** `src/util/Dictionary.cpp`
|
||
|
||
### 2. Fix: Unrendered glyphs in pronunciation guide (DictionaryDefinitionActivity.cpp)
|
||
|
||
**Root cause:** The dictionary stores IPA pronunciation as raw text between entries, e.g., `/əmˈsɛlvz/` appearing between `</html>` and the next `<p>` tag. These IPA Extension Unicode characters (U+0250–U+02FF) are not in the e-ink display's bitmap font, rendering as empty boxes.
|
||
|
||
**Fix:** Added IPA detection in `parseHtml()`: when encountering `/` or `[` delimiters, the parser looks ahead for a matching close delimiter within 80 characters. If the enclosed content contains any non-ASCII byte (> 0x7F), the entire section (including delimiters) is skipped. This removes IPA transcriptions like `/ˈsɪmpəl/` and `[hɜː(ɹ)b]` while preserving legitimate ASCII bracket content like "[citation needed]" or "and/or".
|
||
|
||
**Files:** `src/activities/reader/DictionaryDefinitionActivity.cpp`
|
||
|
||
### 3. Fix: Thinner button hints with overlap detection (DictionaryWordSelectActivity)
|
||
|
||
**Root cause:** Button hints used `GUI.drawButtonHints()` which draws 40px-tall buttons, taking excessive space over the book page content. No overlap detection meant hints could obscure the selected word at the bottom of the screen.
|
||
|
||
**Fix:**
|
||
- Replaced `GUI.drawButtonHints()` with a custom `drawHints()` method
|
||
- Draws thinner hints (22px instead of 40px) using `drawRect` + small text
|
||
- Converts the selected word's bounding box from the current orientation to portrait coordinates (handles portrait, inverted, landscape CW/CCW)
|
||
- Checks vertical and horizontal overlap between each of the 4 button hint areas and the selected word (including hyphenation continuations)
|
||
- Individual hints that overlap the cursor are hidden (white area cleared, no button drawn)
|
||
- Uses the theme's button positions `[58, 146, 254, 342]` to match the physical button layout
|
||
|
||
**Files:** `src/activities/reader/DictionaryWordSelectActivity.h`, `src/activities/reader/DictionaryWordSelectActivity.cpp`
|
||
|
||
## Follow-up Items
|
||
|
||
- The landscape coordinate conversions for overlap detection are best-guess transforms; if they're wrong for the specific device rotation mapping, they may need tuning after testing
|
||
- The IPA skip heuristic is conservative (only skips content with non-ASCII in `/`/`[` delimiters); some edge-case IPA content outside these delimiters would still show
|
||
- `SMALL_FONT_ID` is now included via `fontIds.h` in the word select activity
|