diff --git a/chat-summaries/2026-03-09_05-00-summary.md b/chat-summaries/2026-03-09_05-00-summary.md new file mode 100644 index 00000000..b4ff4688 --- /dev/null +++ b/chat-summaries/2026-03-09_05-00-summary.md @@ -0,0 +1,27 @@ +# BookInfo: Landscape Button Hint Gutter Fix + +**Date**: 2026-03-09 +**Task**: Adjust BookInfo's content area and header placement in landscape orientations to account for button hints appearing on a side instead of the bottom. + +## Problem + +In landscape orientations the physical front buttons end up on a side of the screen (CW = left, CCW = right). BookInfo was reserving `buttonHintsHeight` at the bottom in all orientations, wasting vertical space in landscape and not accounting for the side gutter needed to avoid overlapping the side-drawn button hints. + +## Changes Made + +### `src/activities/home/BookInfoActivity.cpp` + +- **`buildLayout()`**: Added `hintGutterWidth` computation (`metrics.sideButtonHintsWidth` in landscape, 0 in portrait). Text wrapping width (`contentW`) now subtracts `hintGutterWidth`. Bottom padding for `contentHeight` uses only `verticalSpacing` in landscape (no `buttonHintsHeight` since there are no bottom hints). +- **`render()`**: Added `isLandscapeCw`, `hintGutterWidth`, and `contentX` computations following the established codebase pattern. In CW, `contentX = hintGutterWidth` shifts all content right (hints on left). In CCW, `contentX = 0` and content width is reduced (hints on right). Cover X position offset by `contentX`. Field X offset by `contentX`. `contentBottom` no longer subtracts `buttonHintsHeight` in landscape. Header `fillRect` and `drawHeader` Rect both adjusted by `contentX` and `hintGutterWidth`. + +## Pattern Followed + +The established pattern from `LookedUpWordsActivity`, `DictionarySuggestionsActivity`, `EpubReaderMenuActivity`, and others: +```cpp +const int hintGutterWidth = isLandscape ? metrics.sideButtonHintsWidth : 0; +const int contentX = isLandscapeCw ? hintGutterWidth : 0; +``` + +## Follow-up + +Ready for hardware testing in all 4 orientations. diff --git a/src/activities/home/BookInfoActivity.cpp b/src/activities/home/BookInfoActivity.cpp index ec243cc3..01c9eef8 100644 --- a/src/activities/home/BookInfoActivity.cpp +++ b/src/activities/home/BookInfoActivity.cpp @@ -141,6 +141,7 @@ void BookInfoActivity::buildLayout(const BookMetadataCache::BookMetadata& meta, const auto& metrics = UITheme::getInstance().getMetrics(); const int pageW = renderer.getScreenWidth(); const int sidePad = metrics.contentSidePadding; + const int hintGutterWidth = isLandscape ? metrics.sideButtonHintsWidth : 0; if (!coverBmpPath.empty()) { FsFile file; @@ -159,9 +160,10 @@ void BookInfoActivity::buildLayout(const BookMetadataCache::BookMetadata& meta, coverPanelWidth = std::min(coverDisplayWidth + sidePad * 2, pageW * 2 / 5); } - const int contentW = isLandscape && coverPanelWidth > 0 - ? pageW - coverPanelWidth - sidePad - : pageW - sidePad * 2; + const int availW = pageW - hintGutterWidth; + const int contentW = (isLandscape && coverPanelWidth > 0) + ? availW - coverPanelWidth - sidePad + : availW - sidePad * 2; fields.reserve(13); @@ -225,7 +227,7 @@ void BookInfoActivity::buildLayout(const BookMetadataCache::BookMetadata& meta, h += static_cast(field.lines.size()) * lineH12; h += SECTION_GAP; } - h += metrics.buttonHintsHeight + metrics.verticalSpacing; + h += isLandscape ? metrics.verticalSpacing : (metrics.buttonHintsHeight + metrics.verticalSpacing); contentHeight = h; } @@ -270,8 +272,14 @@ void BookInfoActivity::render(RenderLock&&) { const int sidePad = metrics.contentSidePadding; const int lineH10 = renderer.getLineHeight(UI_10_FONT_ID); const int lineH12 = renderer.getLineHeight(UI_12_FONT_ID); + + const bool isLandscapeCw = renderer.getOrientation() == GfxRenderer::Orientation::LandscapeClockwise; + const int hintGutterWidth = isLandscape ? metrics.sideButtonHintsWidth : 0; + const int contentX = (isLandscape && isLandscapeCw) ? hintGutterWidth : 0; + const int contentTop = metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing; - const int contentBottom = pageH - metrics.buttonHintsHeight - metrics.verticalSpacing; + const int contentBottom = isLandscape ? pageH - metrics.verticalSpacing + : pageH - metrics.buttonHintsHeight - metrics.verticalSpacing; if (isLandscape && coverPanelWidth > 0 && !coverBmpPath.empty() && coverDisplayHeight > 0) { FsFile file; @@ -279,14 +287,14 @@ void BookInfoActivity::render(RenderLock&&) { Bitmap bitmap(file); if (bitmap.parseHeaders() == BmpReaderError::Ok) { const int availH = contentBottom - contentTop; - const int coverX = (coverPanelWidth - coverDisplayWidth) / 2; + const int coverX = contentX + (coverPanelWidth - coverDisplayWidth) / 2; renderer.drawBitmap1Bit(bitmap, coverX, contentTop, coverDisplayWidth, availH); } file.close(); } } - const int fieldX = (isLandscape && coverPanelWidth > 0) ? coverPanelWidth : sidePad; + const int fieldX = (isLandscape && coverPanelWidth > 0) ? contentX + coverPanelWidth : contentX + sidePad; int y = contentTop - scrollOffset; if (!isLandscape && !coverBmpPath.empty() && coverDisplayHeight > 0) { @@ -325,8 +333,9 @@ void BookInfoActivity::render(RenderLock&&) { y += SECTION_GAP; } - renderer.fillRect(0, 0, pageW, contentTop, false); - GUI.drawHeader(renderer, Rect(0, metrics.topPadding, pageW, metrics.headerHeight), tr(STR_BOOK_INFO)); + renderer.fillRect(contentX, 0, pageW - hintGutterWidth, contentTop, false); + GUI.drawHeader(renderer, Rect(contentX, metrics.topPadding, pageW - hintGutterWidth, metrics.headerHeight), + tr(STR_BOOK_INFO)); const bool canScrollDown = scrollOffset + pageH < contentHeight; const bool canScrollUp = scrollOffset > 0;