fix: adjust BookInfo landscape layout for side button hint gutters

In landscape CW/CCW the physical buttons are on the left/right side,
not the bottom. Reserve a horizontal gutter (sideButtonHintsWidth)
on the appropriate side and remove the bottom buttonHintsHeight
padding, following the established pattern from other activities.

Made-with: Cursor
This commit is contained in:
cottongin
2026-03-09 04:28:26 -04:00
parent 630fb56a11
commit 4851016c47
2 changed files with 45 additions and 9 deletions

View File

@@ -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.

View File

@@ -141,6 +141,7 @@ void BookInfoActivity::buildLayout(const BookMetadataCache::BookMetadata& meta,
const auto& metrics = UITheme::getInstance().getMetrics(); const auto& metrics = UITheme::getInstance().getMetrics();
const int pageW = renderer.getScreenWidth(); const int pageW = renderer.getScreenWidth();
const int sidePad = metrics.contentSidePadding; const int sidePad = metrics.contentSidePadding;
const int hintGutterWidth = isLandscape ? metrics.sideButtonHintsWidth : 0;
if (!coverBmpPath.empty()) { if (!coverBmpPath.empty()) {
FsFile file; FsFile file;
@@ -159,9 +160,10 @@ void BookInfoActivity::buildLayout(const BookMetadataCache::BookMetadata& meta,
coverPanelWidth = std::min(coverDisplayWidth + sidePad * 2, pageW * 2 / 5); coverPanelWidth = std::min(coverDisplayWidth + sidePad * 2, pageW * 2 / 5);
} }
const int contentW = isLandscape && coverPanelWidth > 0 const int availW = pageW - hintGutterWidth;
? pageW - coverPanelWidth - sidePad const int contentW = (isLandscape && coverPanelWidth > 0)
: pageW - sidePad * 2; ? availW - coverPanelWidth - sidePad
: availW - sidePad * 2;
fields.reserve(13); fields.reserve(13);
@@ -225,7 +227,7 @@ void BookInfoActivity::buildLayout(const BookMetadataCache::BookMetadata& meta,
h += static_cast<int>(field.lines.size()) * lineH12; h += static_cast<int>(field.lines.size()) * lineH12;
h += SECTION_GAP; h += SECTION_GAP;
} }
h += metrics.buttonHintsHeight + metrics.verticalSpacing; h += isLandscape ? metrics.verticalSpacing : (metrics.buttonHintsHeight + metrics.verticalSpacing);
contentHeight = h; contentHeight = h;
} }
@@ -270,8 +272,14 @@ void BookInfoActivity::render(RenderLock&&) {
const int sidePad = metrics.contentSidePadding; const int sidePad = metrics.contentSidePadding;
const int lineH10 = renderer.getLineHeight(UI_10_FONT_ID); const int lineH10 = renderer.getLineHeight(UI_10_FONT_ID);
const int lineH12 = renderer.getLineHeight(UI_12_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 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) { if (isLandscape && coverPanelWidth > 0 && !coverBmpPath.empty() && coverDisplayHeight > 0) {
FsFile file; FsFile file;
@@ -279,14 +287,14 @@ void BookInfoActivity::render(RenderLock&&) {
Bitmap bitmap(file); Bitmap bitmap(file);
if (bitmap.parseHeaders() == BmpReaderError::Ok) { if (bitmap.parseHeaders() == BmpReaderError::Ok) {
const int availH = contentBottom - contentTop; 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); renderer.drawBitmap1Bit(bitmap, coverX, contentTop, coverDisplayWidth, availH);
} }
file.close(); file.close();
} }
} }
const int fieldX = (isLandscape && coverPanelWidth > 0) ? coverPanelWidth : sidePad; const int fieldX = (isLandscape && coverPanelWidth > 0) ? contentX + coverPanelWidth : contentX + sidePad;
int y = contentTop - scrollOffset; int y = contentTop - scrollOffset;
if (!isLandscape && !coverBmpPath.empty() && coverDisplayHeight > 0) { if (!isLandscape && !coverBmpPath.empty() && coverDisplayHeight > 0) {
@@ -325,8 +333,9 @@ void BookInfoActivity::render(RenderLock&&) {
y += SECTION_GAP; y += SECTION_GAP;
} }
renderer.fillRect(0, 0, pageW, contentTop, false); renderer.fillRect(contentX, 0, pageW - hintGutterWidth, contentTop, false);
GUI.drawHeader(renderer, Rect(0, metrics.topPadding, pageW, metrics.headerHeight), tr(STR_BOOK_INFO)); GUI.drawHeader(renderer, Rect(contentX, metrics.topPadding, pageW - hintGutterWidth, metrics.headerHeight),
tr(STR_BOOK_INFO));
const bool canScrollDown = scrollOffset + pageH < contentHeight; const bool canScrollDown = scrollOffset + pageH < contentHeight;
const bool canScrollUp = scrollOffset > 0; const bool canScrollUp = scrollOffset > 0;