Files
crosspoint-reader-mod/chat-summaries/2026-02-12_17-34-summary.md
cottongin dfbc931c14 mod: Phase 1 - bring forward mod-exclusive files with ActivityManager migration
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
2026-03-07 15:10:00 -05:00

4.1 KiB
Raw Permalink Blame History

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+0250U+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