Refactor ui content rect

This commit is contained in:
jpirnay
2026-03-10 19:11:30 +01:00
parent 0a4a369d25
commit 2008060a81
30 changed files with 304 additions and 303 deletions
@@ -139,13 +139,13 @@ void OpdsBookBrowserActivity::loop() {
void OpdsBookBrowserActivity::render(RenderLock&&) {
renderer.clearScreen();
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
const int midY = contentRect.y + contentRect.height / 2;
renderer.drawCenteredText(UI_12_FONT_ID, 15, tr(STR_OPDS_BROWSER), true, EpdFontFamily::BOLD);
if (state == BrowserState::CHECK_WIFI) {
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2, statusMessage.c_str());
renderer.drawCenteredText(UI_10_FONT_ID, midY, statusMessage.c_str());
const auto labels = mappedInput.mapLabels(tr(STR_BACK), "", "", "");
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
renderer.displayBuffer();
@@ -153,7 +153,7 @@ void OpdsBookBrowserActivity::render(RenderLock&&) {
}
if (state == BrowserState::LOADING) {
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2, statusMessage.c_str());
renderer.drawCenteredText(UI_10_FONT_ID, midY, statusMessage.c_str());
const auto labels = mappedInput.mapLabels(tr(STR_BACK), "", "", "");
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
renderer.displayBuffer();
@@ -161,8 +161,8 @@ void OpdsBookBrowserActivity::render(RenderLock&&) {
}
if (state == BrowserState::ERROR) {
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 - 20, tr(STR_ERROR_MSG));
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 + 10, errorMessage.c_str());
renderer.drawCenteredText(UI_10_FONT_ID, midY - 20, tr(STR_ERROR_MSG));
renderer.drawCenteredText(UI_10_FONT_ID, midY + 10, errorMessage.c_str());
const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_RETRY), "", "");
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
renderer.displayBuffer();
@@ -170,16 +170,15 @@ void OpdsBookBrowserActivity::render(RenderLock&&) {
}
if (state == BrowserState::DOWNLOADING) {
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 - 40, tr(STR_DOWNLOADING));
const auto maxWidth = pageWidth - 40;
// Trim long titles to keep them within the screen bounds.
auto title = renderer.truncatedText(UI_10_FONT_ID, statusMessage.c_str(), maxWidth);
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 - 10, title.c_str());
renderer.drawCenteredText(UI_10_FONT_ID, midY - 40, tr(STR_DOWNLOADING));
// Trim long titles to keep them within the content bounds.
auto title = renderer.truncatedText(UI_10_FONT_ID, statusMessage.c_str(), contentRect.width - 40);
renderer.drawCenteredText(UI_10_FONT_ID, midY - 10, title.c_str());
if (downloadTotal > 0) {
const int barWidth = pageWidth - 100;
const int barWidth = contentRect.width - 100;
constexpr int barHeight = 20;
constexpr int barX = 50;
const int barY = pageHeight / 2 + 20;
const int barX = contentRect.x + 50;
const int barY = midY + 20;
GUI.drawProgressBar(renderer, Rect{barX, barY, barWidth, barHeight}, downloadProgress, downloadTotal);
}
renderer.displayBuffer();
@@ -196,13 +195,13 @@ void OpdsBookBrowserActivity::render(RenderLock&&) {
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
if (entries.empty()) {
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2, tr(STR_NO_ENTRIES));
renderer.drawCenteredText(UI_10_FONT_ID, midY, tr(STR_NO_ENTRIES));
renderer.displayBuffer();
return;
}
const auto pageStartIndex = selectorIndex / PAGE_ITEMS * PAGE_ITEMS;
renderer.fillRect(0, 60 + (selectorIndex % PAGE_ITEMS) * 30 - 2, pageWidth - 1, 30);
renderer.fillRect(contentRect.x, 60 + (selectorIndex % PAGE_ITEMS) * 30 - 2, contentRect.width - 1, 30);
for (size_t i = pageStartIndex; i < entries.size() && i < static_cast<size_t>(pageStartIndex + PAGE_ITEMS); i++) {
const auto& entry = entries[i];
@@ -219,8 +218,8 @@ void OpdsBookBrowserActivity::render(RenderLock&&) {
}
}
auto item = renderer.truncatedText(UI_10_FONT_ID, displayText.c_str(), renderer.getScreenWidth() - 40);
renderer.drawText(UI_10_FONT_ID, 20, 60 + (i % PAGE_ITEMS) * 30, item.c_str(),
auto item = renderer.truncatedText(UI_10_FONT_ID, displayText.c_str(), contentRect.width - 40);
renderer.drawText(UI_10_FONT_ID, contentRect.x + 20, 60 + (i % PAGE_ITEMS) * 30, item.c_str(),
i != static_cast<size_t>(selectorIndex));
}
+11 -10
View File
@@ -27,13 +27,14 @@ std::string BookInfoActivity::formatFileSize(const size_t bytes) {
void BookInfoActivity::renderLoading() {
renderer.clearScreen();
const auto pageWidth = renderer.getScreenWidth();
const auto& metrics = UITheme::getInstance().getMetrics();
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, tr(STR_INFO));
GUI.drawHeader(renderer, Rect{contentRect.x, metrics.topPadding, contentRect.width, metrics.headerHeight},
tr(STR_INFO));
const int contentTop = metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing;
renderer.drawText(UI_12_FONT_ID, metrics.contentSidePadding, contentTop, tr(STR_LOADING));
renderer.drawText(UI_12_FONT_ID, contentRect.x + metrics.contentSidePadding, contentTop, tr(STR_LOADING));
renderer.displayBuffer();
}
@@ -111,17 +112,17 @@ void BookInfoActivity::loop() {
void BookInfoActivity::render(RenderLock&&) {
renderer.clearScreen();
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
const auto& metrics = UITheme::getInstance().getMetrics();
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
// Header
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, tr(STR_INFO));
GUI.drawHeader(renderer, Rect{contentRect.x, metrics.topPadding, contentRect.width, metrics.headerHeight},
tr(STR_INFO));
const int contentTop = metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing;
const int contentBottom = pageHeight - metrics.buttonHintsHeight - metrics.verticalSpacing;
const int textX = metrics.contentSidePadding;
const int textWidth = pageWidth - metrics.contentSidePadding * 2;
const int contentBottom = contentRect.y + contentRect.height - metrics.verticalSpacing;
const int textX = contentRect.x + metrics.contentSidePadding;
const int textWidth = contentRect.width - metrics.contentSidePadding * 2;
const int lineHeightSmall = renderer.getLineHeight(UI_10_FONT_ID);
const int lineHeightLarge = renderer.getLineHeight(UI_12_FONT_ID);
@@ -240,7 +241,7 @@ void BookInfoActivity::render(RenderLock&&) {
if (!description.empty()) {
int y = topSectionBottom + metrics.verticalSpacing;
if (y + lineHeightSmall + 4 < contentBottom) {
renderer.drawLine(textX, y, pageWidth - metrics.contentSidePadding, y);
renderer.drawLine(textX, y, contentRect.x + contentRect.width - metrics.contentSidePadding, y);
y += 4;
const int descMaxLines = (contentBottom - y) / lineHeightSmall;
+7 -6
View File
@@ -269,20 +269,21 @@ std::string getFileName(std::string filename) {
void FileBrowserActivity::render(RenderLock&&) {
renderer.clearScreen();
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
const auto& metrics = UITheme::getInstance().getMetrics();
const Rect contentRect = UITheme::getContentRect(renderer, true, true);
std::string folderName = (basepath == "/") ? tr(STR_SD_CARD) : basepath.substr(basepath.rfind('/') + 1);
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, folderName.c_str());
GUI.drawHeader(renderer, Rect{contentRect.x, metrics.topPadding, contentRect.width, metrics.headerHeight},
folderName.c_str());
const int contentTop = metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing;
const int contentHeight = pageHeight - contentTop - metrics.buttonHintsHeight - metrics.verticalSpacing;
const int contentHeight = contentRect.height - contentTop - metrics.verticalSpacing;
if (files.empty()) {
renderer.drawText(UI_10_FONT_ID, metrics.contentSidePadding, contentTop + 20, tr(STR_NO_FILES_FOUND));
renderer.drawText(UI_10_FONT_ID, contentRect.x + metrics.contentSidePadding, contentTop + 20,
tr(STR_NO_FILES_FOUND));
} else {
GUI.drawList(
renderer, Rect{0, contentTop, pageWidth, contentHeight}, files.size(), selectorIndex,
renderer, Rect{contentRect.x, contentTop, contentRect.width, contentHeight}, files.size(), selectorIndex,
[this](int index) { return getFileName(files[index]); }, nullptr,
[this](int index) { return UITheme::getFileIcon(files[index]); });
}
+7 -7
View File
@@ -212,15 +212,15 @@ void HomeActivity::loop() {
void HomeActivity::render(RenderLock&&) {
const auto& metrics = UITheme::getInstance().getMetrics();
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
renderer.clearScreen();
bool bufferRestored = coverBufferStored && restoreCoverBuffer();
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.homeTopPadding}, nullptr);
GUI.drawHeader(renderer, Rect{contentRect.x, metrics.topPadding, contentRect.width, metrics.homeTopPadding}, nullptr);
GUI.drawRecentBookCover(renderer, Rect{0, metrics.homeTopPadding, pageWidth, metrics.homeCoverTileHeight},
GUI.drawRecentBookCover(renderer,
Rect{contentRect.x, metrics.homeTopPadding, contentRect.width, metrics.homeCoverTileHeight},
recentBooks, selectorIndex, coverRendered, coverBufferStored, bufferRestored,
std::bind(&HomeActivity::storeCoverBuffer, this));
@@ -237,9 +237,9 @@ void HomeActivity::render(RenderLock&&) {
GUI.drawButtonMenu(
renderer,
Rect{0, metrics.homeTopPadding + metrics.homeCoverTileHeight + metrics.verticalSpacing, pageWidth,
pageHeight - (metrics.headerHeight + metrics.homeTopPadding + metrics.verticalSpacing * 2 +
metrics.buttonHintsHeight)},
Rect{contentRect.x, metrics.homeTopPadding + metrics.homeCoverTileHeight + metrics.verticalSpacing,
contentRect.width,
contentRect.height - (metrics.headerHeight + metrics.homeTopPadding + metrics.verticalSpacing * 2)},
static_cast<int>(menuItems.size()), selectorIndex - recentBooks.size(),
[&menuItems](int index) { return std::string(menuItems[index]); },
[&menuIcons](int index) { return menuIcons[index]; });
+7 -6
View File
@@ -98,21 +98,22 @@ void RecentBooksActivity::loop() {
void RecentBooksActivity::render(RenderLock&&) {
renderer.clearScreen();
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
const auto& metrics = UITheme::getInstance().getMetrics();
const Rect contentRect = UITheme::getContentRect(renderer, true, true);
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, tr(STR_MENU_RECENT_BOOKS));
GUI.drawHeader(renderer, Rect{contentRect.x, metrics.topPadding, contentRect.width, metrics.headerHeight},
tr(STR_MENU_RECENT_BOOKS));
const int contentTop = metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing;
const int contentHeight = pageHeight - contentTop - metrics.buttonHintsHeight - metrics.verticalSpacing;
const int contentHeight = contentRect.height - contentTop - metrics.verticalSpacing;
// Recent tab
if (recentBooks.empty()) {
renderer.drawText(UI_10_FONT_ID, metrics.contentSidePadding, contentTop + 20, tr(STR_NO_RECENT_BOOKS));
renderer.drawText(UI_10_FONT_ID, contentRect.x + metrics.contentSidePadding, contentTop + 20,
tr(STR_NO_RECENT_BOOKS));
} else {
GUI.drawList(
renderer, Rect{0, contentTop, pageWidth, contentHeight}, recentBooks.size(), selectorIndex,
renderer, Rect{contentRect.x, contentTop, contentRect.width, contentHeight}, recentBooks.size(), selectorIndex,
[this](int index) { return recentBooks[index].title; },
[this](int index) {
const auto& book = recentBooks[index];
@@ -169,57 +169,59 @@ void CalibreConnectActivity::loop() {
void CalibreConnectActivity::render(RenderLock&&) {
const auto& metrics = UITheme::getInstance().getMetrics();
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
renderer.clearScreen();
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, tr(STR_CALIBRE_WIRELESS));
GUI.drawHeader(renderer, Rect{contentRect.x, metrics.topPadding, contentRect.width, metrics.headerHeight},
tr(STR_CALIBRE_WIRELESS));
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
const auto top = (pageHeight - height) / 2;
const auto top = contentRect.y + (contentRect.height - height) / 2;
if (state == CalibreConnectState::SERVER_STARTING) {
renderer.drawCenteredText(UI_12_FONT_ID, top, tr(STR_CALIBRE_STARTING));
} else if (state == CalibreConnectState::ERROR) {
renderer.drawCenteredText(UI_12_FONT_ID, top, tr(STR_CONNECTION_FAILED), true, EpdFontFamily::BOLD);
} else if (state == CalibreConnectState::SERVER_RUNNING) {
GUI.drawSubHeader(renderer, Rect{0, metrics.topPadding + metrics.headerHeight, pageWidth, metrics.tabBarHeight},
connectedSSID.c_str(), (std::string(tr(STR_IP_ADDRESS_PREFIX)) + connectedIP).c_str());
GUI.drawSubHeader(
renderer,
Rect{contentRect.x, metrics.topPadding + metrics.headerHeight, contentRect.width, metrics.tabBarHeight},
connectedSSID.c_str(), (std::string(tr(STR_IP_ADDRESS_PREFIX)) + connectedIP).c_str());
const int textX = contentRect.x + metrics.contentSidePadding;
const int textWidth = contentRect.width - metrics.contentSidePadding * 2;
int y = metrics.topPadding + metrics.headerHeight + metrics.tabBarHeight + metrics.verticalSpacing * 4;
const auto heightText12 = renderer.getTextHeight(UI_12_FONT_ID);
renderer.drawText(UI_12_FONT_ID, metrics.contentSidePadding, y, tr(STR_CALIBRE_SETUP), true, EpdFontFamily::BOLD);
renderer.drawText(UI_12_FONT_ID, textX, y, tr(STR_CALIBRE_SETUP), true, EpdFontFamily::BOLD);
y += heightText12 + metrics.verticalSpacing * 2;
renderer.drawText(SMALL_FONT_ID, metrics.contentSidePadding, y, tr(STR_CALIBRE_INSTRUCTION_1));
renderer.drawText(SMALL_FONT_ID, metrics.contentSidePadding, y + height, tr(STR_CALIBRE_INSTRUCTION_2));
renderer.drawText(SMALL_FONT_ID, metrics.contentSidePadding, y + height * 2, tr(STR_CALIBRE_INSTRUCTION_3));
renderer.drawText(SMALL_FONT_ID, metrics.contentSidePadding, y + height * 3, tr(STR_CALIBRE_INSTRUCTION_4));
renderer.drawText(SMALL_FONT_ID, textX, y, tr(STR_CALIBRE_INSTRUCTION_1));
renderer.drawText(SMALL_FONT_ID, textX, y + height, tr(STR_CALIBRE_INSTRUCTION_2));
renderer.drawText(SMALL_FONT_ID, textX, y + height * 2, tr(STR_CALIBRE_INSTRUCTION_3));
renderer.drawText(SMALL_FONT_ID, textX, y + height * 3, tr(STR_CALIBRE_INSTRUCTION_4));
y += height * 3 + metrics.verticalSpacing * 4;
renderer.drawText(UI_12_FONT_ID, metrics.contentSidePadding, y, tr(STR_CALIBRE_STATUS), true, EpdFontFamily::BOLD);
renderer.drawText(UI_12_FONT_ID, textX, y, tr(STR_CALIBRE_STATUS), true, EpdFontFamily::BOLD);
y += heightText12 + metrics.verticalSpacing * 2;
if (lastProgressTotal > 0 && lastProgressReceived <= lastProgressTotal) {
std::string label = tr(STR_CALIBRE_RECEIVING);
if (!currentUploadName.empty()) {
label += ": " + currentUploadName;
label = renderer.truncatedText(SMALL_FONT_ID, label.c_str(), pageWidth - metrics.contentSidePadding * 2,
EpdFontFamily::REGULAR);
label = renderer.truncatedText(SMALL_FONT_ID, label.c_str(), textWidth, EpdFontFamily::REGULAR);
}
renderer.drawText(SMALL_FONT_ID, metrics.contentSidePadding, y, label.c_str());
renderer.drawText(SMALL_FONT_ID, textX, y, label.c_str());
GUI.drawProgressBar(renderer,
Rect{metrics.contentSidePadding, y + height + metrics.verticalSpacing,
pageWidth - metrics.contentSidePadding * 2, metrics.progressBarHeight},
Rect{contentRect.x + metrics.contentSidePadding, y + height + metrics.verticalSpacing,
textWidth, metrics.progressBarHeight},
lastProgressReceived, lastProgressTotal);
y += height + metrics.verticalSpacing * 2 + metrics.progressBarHeight;
}
if (lastCompleteAt > 0 && (millis() - lastCompleteAt) < 6000) {
std::string msg = std::string(tr(STR_CALIBRE_RECEIVED)) + lastCompleteName;
msg = renderer.truncatedText(SMALL_FONT_ID, msg.c_str(), pageWidth - metrics.contentSidePadding * 2,
EpdFontFamily::REGULAR);
renderer.drawText(SMALL_FONT_ID, metrics.contentSidePadding, y, msg.c_str());
msg = renderer.truncatedText(SMALL_FONT_ID, msg.c_str(), textWidth, EpdFontFamily::REGULAR);
renderer.drawText(SMALL_FONT_ID, textX, y, msg.c_str());
}
const auto labels = mappedInput.mapLabels(tr(STR_EXIT), "", "", "");
@@ -348,19 +348,20 @@ void CrossPointWebServerActivity::render(RenderLock&&) {
if (state == WebServerActivityState::SERVER_RUNNING || state == WebServerActivityState::AP_STARTING) {
renderer.clearScreen();
const auto& metrics = UITheme::getInstance().getMetrics();
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight},
GUI.drawHeader(renderer, Rect{contentRect.x, metrics.topPadding, contentRect.width, metrics.headerHeight},
isApMode ? tr(STR_HOTSPOT_MODE) : tr(STR_FILE_TRANSFER), nullptr);
if (state == WebServerActivityState::SERVER_RUNNING) {
GUI.drawSubHeader(renderer, Rect{0, metrics.topPadding + metrics.headerHeight, pageWidth, metrics.tabBarHeight},
connectedSSID.c_str());
GUI.drawSubHeader(
renderer,
Rect{contentRect.x, metrics.topPadding + metrics.headerHeight, contentRect.width, metrics.tabBarHeight},
connectedSSID.c_str());
renderServerRunning();
} else {
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
const auto top = (pageHeight - height) / 2;
const auto top = contentRect.y + (contentRect.height - height) / 2;
renderer.drawCenteredText(UI_10_FONT_ID, top, tr(STR_STARTING_HOTSPOT));
}
renderer.displayBuffer();
@@ -369,12 +370,13 @@ void CrossPointWebServerActivity::render(RenderLock&&) {
void CrossPointWebServerActivity::renderServerRunning() const {
const auto& metrics = UITheme::getInstance().getMetrics();
const auto pageWidth = renderer.getScreenWidth();
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight},
GUI.drawHeader(renderer, Rect{contentRect.x, metrics.topPadding, contentRect.width, metrics.headerHeight},
isApMode ? tr(STR_HOTSPOT_MODE) : tr(STR_FILE_TRANSFER), nullptr);
GUI.drawSubHeader(renderer, Rect{0, metrics.topPadding + metrics.headerHeight, pageWidth, metrics.tabBarHeight},
connectedSSID.c_str());
GUI.drawSubHeader(
renderer, Rect{contentRect.x, metrics.topPadding + metrics.headerHeight, contentRect.width, metrics.tabBarHeight},
connectedSSID.c_str());
int startY = metrics.topPadding + metrics.headerHeight + metrics.tabBarHeight + metrics.verticalSpacing * 2;
int height10 = renderer.getLineHeight(UI_10_FONT_ID);
@@ -424,7 +426,7 @@ void CrossPointWebServerActivity::renderServerRunning() const {
// Show QR code for URL
std::string webInfo = "http://" + connectedIP + "/";
const Rect qrBounds((pageWidth - QR_CODE_WIDTH) / 2, startY, QR_CODE_WIDTH, QR_CODE_HEIGHT);
const Rect qrBounds(contentRect.x + (contentRect.width - QR_CODE_WIDTH) / 2, startY, QR_CODE_WIDTH, QR_CODE_HEIGHT);
QrUtils::drawQrCode(renderer, qrBounds, webInfo);
startY += QR_CODE_HEIGHT + metrics.verticalSpacing * 2;
@@ -58,13 +58,13 @@ void NetworkModeSelectionActivity::render(RenderLock&&) {
renderer.clearScreen();
const auto& metrics = UITheme::getInstance().getMetrics();
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, tr(STR_FILE_TRANSFER));
GUI.drawHeader(renderer, Rect{contentRect.x, metrics.topPadding, contentRect.width, metrics.headerHeight},
tr(STR_FILE_TRANSFER));
const int contentTop = metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing;
const int contentHeight = pageHeight - contentTop - metrics.buttonHintsHeight - metrics.verticalSpacing * 2;
const int contentHeight = contentRect.height - contentTop - metrics.verticalSpacing * 2;
// Menu items and descriptions
static constexpr StrId menuItems[MENU_ITEM_COUNT] = {StrId::STR_JOIN_NETWORK, StrId::STR_CALIBRE_WIRELESS,
StrId::STR_CREATE_HOTSPOT};
@@ -73,8 +73,8 @@ void NetworkModeSelectionActivity::render(RenderLock&&) {
static constexpr UIIcon menuIcons[MENU_ITEM_COUNT] = {UIIcon::Wifi, UIIcon::Library, UIIcon::Hotspot};
GUI.drawList(
renderer, Rect{0, contentTop, pageWidth, contentHeight}, static_cast<int>(MENU_ITEM_COUNT), selectedIndex,
[](int index) { return std::string(I18N.get(menuItems[index])); },
renderer, Rect{contentRect.x, contentTop, contentRect.width, contentHeight}, static_cast<int>(MENU_ITEM_COUNT),
selectedIndex, [](int index) { return std::string(I18N.get(menuItems[index])); },
[](int index) { return std::string(I18N.get(menuDescs[index])); }, [](int index) { return menuIcons[index]; });
// Draw help text at bottom
@@ -472,16 +472,16 @@ void WifiSelectionActivity::render(RenderLock&&) {
renderer.clearScreen();
const auto& metrics = UITheme::getInstance().getMetrics();
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
// Draw header
char countStr[32];
snprintf(countStr, sizeof(countStr), tr(STR_NETWORKS_FOUND), networks.size());
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, tr(STR_WIFI_NETWORKS),
countStr);
GUI.drawSubHeader(renderer, Rect{0, metrics.topPadding + metrics.headerHeight, pageWidth, metrics.tabBarHeight},
cachedMacAddress.c_str());
GUI.drawHeader(renderer, Rect{contentRect.x, metrics.topPadding, contentRect.width, metrics.headerHeight},
tr(STR_WIFI_NETWORKS), countStr);
GUI.drawSubHeader(
renderer, Rect{contentRect.x, metrics.topPadding + metrics.headerHeight, contentRect.width, metrics.tabBarHeight},
cachedMacAddress.c_str());
switch (state) {
case WifiSelectionState::AUTO_CONNECTING:
@@ -515,20 +515,19 @@ void WifiSelectionActivity::render(RenderLock&&) {
void WifiSelectionActivity::renderNetworkList() const {
const auto& metrics = UITheme::getInstance().getMetrics();
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
if (networks.empty()) {
// No networks found or scan failed
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
const auto top = (pageHeight - height) / 2;
const auto top = (contentRect.y + contentRect.height - height) / 2;
renderer.drawCenteredText(UI_10_FONT_ID, top, tr(STR_NO_NETWORKS));
renderer.drawCenteredText(SMALL_FONT_ID, top + height + 10, tr(STR_PRESS_OK_SCAN));
} else {
int contentTop = metrics.topPadding + metrics.headerHeight + metrics.tabBarHeight + metrics.verticalSpacing;
int contentHeight = pageHeight - contentTop - metrics.buttonHintsHeight - metrics.verticalSpacing * 2;
int contentHeight = contentRect.height - contentTop - metrics.verticalSpacing * 2;
GUI.drawList(
renderer, Rect{0, contentTop, pageWidth, contentHeight}, static_cast<int>(networks.size()),
renderer, Rect{contentRect.x, contentTop, contentRect.width, contentHeight}, static_cast<int>(networks.size()),
selectedNetworkIndex, [this](int index) { return networks[index].ssid; }, nullptr, nullptr,
[this](int index) {
auto network = networks[index];
@@ -537,9 +536,10 @@ void WifiSelectionActivity::renderNetworkList() const {
});
}
GUI.drawHelpText(renderer,
Rect{0, pageHeight - metrics.buttonHintsHeight - metrics.contentSidePadding - 15, pageWidth, 20},
tr(STR_NETWORK_LEGEND));
GUI.drawHelpText(
renderer,
Rect{contentRect.x, contentRect.y + contentRect.height - metrics.contentSidePadding - 15, contentRect.width, 20},
tr(STR_NETWORK_LEGEND));
const bool hasSavedPassword = !networks.empty() && networks[selectedNetworkIndex].hasSavedPassword;
const char* forgetLabel = hasSavedPassword ? tr(STR_FORGET_BUTTON) : "";
@@ -10,17 +10,10 @@
int EpubReaderChapterSelectionActivity::getTotalItems() const { return epub->getTocItemsCount(); }
int EpubReaderChapterSelectionActivity::getPageItems() const {
// Layout constants used in renderScreen
constexpr int lineHeight = 30;
const int screenHeight = renderer.getScreenHeight();
const auto orientation = renderer.getOrientation();
// In inverted portrait, the button hints are drawn near the logical top.
// Reserve vertical space so list items do not collide with the hints.
const bool isPortraitInverted = orientation == GfxRenderer::Orientation::PortraitInverted;
const int hintGutterHeight = isPortraitInverted ? 50 : 0;
const int startY = 60 + hintGutterHeight;
const int availableHeight = screenHeight - startY - lineHeight;
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
const int startY = 60 + contentRect.y;
const int availableHeight = contentRect.y + contentRect.height - startY - lineHeight;
// Clamp to at least one item to avoid division by zero and empty paging.
return std::max(1, availableHeight / lineHeight);
}
@@ -89,43 +82,33 @@ void EpubReaderChapterSelectionActivity::loop() {
void EpubReaderChapterSelectionActivity::render(RenderLock&&) {
renderer.clearScreen();
const auto pageWidth = renderer.getScreenWidth();
const auto orientation = renderer.getOrientation();
// Landscape orientation: reserve a horizontal gutter for button hints.
const bool isLandscapeCw = orientation == GfxRenderer::Orientation::LandscapeClockwise;
const bool isLandscapeCcw = orientation == GfxRenderer::Orientation::LandscapeCounterClockwise;
// Inverted portrait: reserve vertical space for hints at the top.
const bool isPortraitInverted = orientation == GfxRenderer::Orientation::PortraitInverted;
const int hintGutterWidth = (isLandscapeCw || isLandscapeCcw) ? 30 : 0;
// Landscape CW places hints on the left edge; CCW keeps them on the right.
const int contentX = isLandscapeCw ? hintGutterWidth : 0;
const int contentWidth = pageWidth - hintGutterWidth;
const int hintGutterHeight = isPortraitInverted ? 50 : 0;
const int contentY = hintGutterHeight;
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
const int pageItems = getPageItems();
const int totalItems = getTotalItems();
// Manual centering to honor content gutters.
const int titleX =
contentX + (contentWidth - renderer.getTextWidth(UI_12_FONT_ID, tr(STR_SELECT_CHAPTER), EpdFontFamily::BOLD)) / 2;
renderer.drawText(UI_12_FONT_ID, titleX, 15 + contentY, tr(STR_SELECT_CHAPTER), true, EpdFontFamily::BOLD);
contentRect.x +
(contentRect.width - renderer.getTextWidth(UI_12_FONT_ID, tr(STR_SELECT_CHAPTER), EpdFontFamily::BOLD)) / 2;
renderer.drawText(UI_12_FONT_ID, titleX, 15 + contentRect.y, tr(STR_SELECT_CHAPTER), true, EpdFontFamily::BOLD);
const auto pageStartIndex = selectorIndex / pageItems * pageItems;
// Highlight only the content area, not the hint gutters.
renderer.fillRect(contentX, 60 + contentY + (selectorIndex % pageItems) * 30 - 2, contentWidth - 1, 30);
renderer.fillRect(contentRect.x, 60 + contentRect.y + (selectorIndex % pageItems) * 30 - 2, contentRect.width - 1,
30);
for (int i = 0; i < pageItems; i++) {
int itemIndex = pageStartIndex + i;
if (itemIndex >= totalItems) break;
const int displayY = 60 + contentY + i * 30;
const int displayY = 60 + contentRect.y + i * 30;
const bool isSelected = (itemIndex == selectorIndex);
auto item = epub->getTocItem(itemIndex);
// Indent per TOC level while keeping content within the gutter-safe region.
const int indentSize = contentX + 20 + (item.level - 1) * 15;
const int indentSize = contentRect.x + 20 + (item.level - 1) * 15;
const std::string chapterName =
renderer.truncatedText(UI_10_FONT_ID, item.title.c_str(), contentWidth - 40 - indentSize);
renderer.truncatedText(UI_10_FONT_ID, item.title.c_str(), contentRect.width - 40 - indentSize);
renderer.drawText(UI_10_FONT_ID, indentSize, displayY, chapterName.c_str(), !isSelected);
}
@@ -64,19 +64,19 @@ void EpubReaderFootnotesActivity::render(RenderLock&&) {
constexpr int startY = 50;
constexpr int lineHeight = 36;
const int screenWidth = renderer.getScreenWidth();
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
constexpr int marginLeft = 20;
const int visibleCount = std::max(1, (renderer.getScreenHeight() - startY) / lineHeight);
const int visibleCount = std::max(1, (contentRect.height - startY) / lineHeight);
if (selectedIndex < scrollOffset) scrollOffset = selectedIndex;
if (selectedIndex >= scrollOffset + visibleCount) scrollOffset = selectedIndex - visibleCount + 1;
for (int i = scrollOffset; i < static_cast<int>(footnotes.size()) && i < scrollOffset + visibleCount; i++) {
const int y = startY + (i - scrollOffset) * lineHeight;
const int y = contentRect.y + startY + (i - scrollOffset) * lineHeight;
const bool isSelected = (i == selectedIndex);
if (isSelected) {
renderer.fillRect(0, y, screenWidth, lineHeight, true);
renderer.fillRect(contentRect.x, y, contentRect.width, lineHeight, true);
}
// Show footnote number and abbreviated href
@@ -84,7 +84,7 @@ void EpubReaderFootnotesActivity::render(RenderLock&&) {
if (label.empty()) {
label = tr(STR_LINK);
}
renderer.drawText(UI_10_FONT_ID, marginLeft, y + 4, label.c_str(), !isSelected);
renderer.drawText(UI_10_FONT_ID, contentRect.x + marginLeft, y + 4, label.c_str(), !isSelected);
}
const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), "", "");
@@ -86,29 +86,16 @@ void EpubReaderMenuActivity::loop() {
void EpubReaderMenuActivity::render(RenderLock&&) {
renderer.clearScreen();
const auto pageWidth = renderer.getScreenWidth();
const auto orientation = renderer.getOrientation();
// Landscape orientation: button hints are drawn along a vertical edge, so we
// reserve a horizontal gutter to prevent overlap with menu content.
const bool isLandscapeCw = orientation == GfxRenderer::Orientation::LandscapeClockwise;
const bool isLandscapeCcw = orientation == GfxRenderer::Orientation::LandscapeCounterClockwise;
// Inverted portrait: button hints appear near the logical top, so we reserve
// vertical space to keep the header and list clear.
const bool isPortraitInverted = orientation == GfxRenderer::Orientation::PortraitInverted;
const int hintGutterWidth = (isLandscapeCw || isLandscapeCcw) ? 30 : 0;
// Landscape CW places hints on the left edge; CCW keeps them on the right.
const int contentX = isLandscapeCw ? hintGutterWidth : 0;
const int contentWidth = pageWidth - hintGutterWidth;
const int hintGutterHeight = isPortraitInverted ? 50 : 0;
const int contentY = hintGutterHeight;
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
// Title
const std::string truncTitle =
renderer.truncatedText(UI_12_FONT_ID, title.c_str(), contentWidth - 40, EpdFontFamily::BOLD);
renderer.truncatedText(UI_12_FONT_ID, title.c_str(), contentRect.width - 40, EpdFontFamily::BOLD);
// Manual centering so we can respect the content gutter.
const int titleX =
contentX + (contentWidth - renderer.getTextWidth(UI_12_FONT_ID, truncTitle.c_str(), EpdFontFamily::BOLD)) / 2;
renderer.drawText(UI_12_FONT_ID, titleX, 15 + contentY, truncTitle.c_str(), true, EpdFontFamily::BOLD);
contentRect.x +
(contentRect.width - renderer.getTextWidth(UI_12_FONT_ID, truncTitle.c_str(), EpdFontFamily::BOLD)) / 2;
renderer.drawText(UI_12_FONT_ID, titleX, 15 + contentRect.y, truncTitle.c_str(), true, EpdFontFamily::BOLD);
// Progress summary
std::string progressLine;
@@ -120,7 +107,7 @@ void EpubReaderMenuActivity::render(RenderLock&&) {
renderer.drawCenteredText(UI_10_FONT_ID, 45, progressLine.c_str());
// Menu Items
const int startY = 75 + contentY;
const int startY = 75 + contentRect.y;
constexpr int lineHeight = 30;
for (size_t i = 0; i < menuItems.size(); ++i) {
@@ -129,23 +116,23 @@ void EpubReaderMenuActivity::render(RenderLock&&) {
if (isSelected) {
// Highlight only the content area so we don't paint over hint gutters.
renderer.fillRect(contentX, displayY, contentWidth - 1, lineHeight, true);
renderer.fillRect(contentRect.x, displayY, contentRect.width - 1, lineHeight, true);
}
renderer.drawText(UI_10_FONT_ID, contentX + 20, displayY, I18N.get(menuItems[i].labelId), !isSelected);
renderer.drawText(UI_10_FONT_ID, contentRect.x + 20, displayY, I18N.get(menuItems[i].labelId), !isSelected);
if (menuItems[i].action == MenuAction::ROTATE_SCREEN) {
// Render current orientation value on the right edge of the content area.
const char* value = I18N.get(orientationLabels[pendingOrientation]);
const auto width = renderer.getTextWidth(UI_10_FONT_ID, value);
renderer.drawText(UI_10_FONT_ID, contentX + contentWidth - 20 - width, displayY, value, !isSelected);
renderer.drawText(UI_10_FONT_ID, contentRect.x + contentRect.width - 20 - width, displayY, value, !isSelected);
}
if (menuItems[i].action == MenuAction::AUTO_PAGE_TURN) {
// Render current page turn value on the right edge of the content area.
const auto value = pageTurnLabels[selectedPageTurnOption];
const auto width = renderer.getTextWidth(UI_10_FONT_ID, value);
renderer.drawText(UI_10_FONT_ID, contentX + contentWidth - 20 - width, displayY, value, !isSelected);
renderer.drawText(UI_10_FONT_ID, contentRect.x + contentRect.width - 20 - width, displayY, value, !isSelected);
}
}
@@ -65,10 +65,10 @@ void EpubReaderPercentSelectionActivity::render(RenderLock&&) {
renderer.drawCenteredText(UI_12_FONT_ID, 90, percentText.c_str(), true, EpdFontFamily::BOLD);
// Draw slider track.
const int screenWidth = renderer.getScreenWidth();
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
constexpr int barWidth = 360;
constexpr int barHeight = 16;
const int barX = (screenWidth - barWidth) / 2;
const int barX = contentRect.x + (contentRect.width - barWidth) / 2;
const int barY = 140;
renderer.drawRect(barX, barY, barWidth, barHeight);
+14 -13
View File
@@ -221,10 +221,10 @@ void KOReaderSyncActivity::onExit() {
}
void KOReaderSyncActivity::render(RenderLock&&) {
const auto pageWidth = renderer.getScreenWidth();
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
renderer.clearScreen();
renderer.drawCenteredText(UI_12_FONT_ID, 15, tr(STR_KOREADER_SYNC), true, EpdFontFamily::BOLD);
renderer.drawCenteredText(UI_12_FONT_ID, 15 + contentRect.y, tr(STR_KOREADER_SYNC), true, EpdFontFamily::BOLD);
if (state == NO_CREDENTIALS) {
renderer.drawCenteredText(UI_10_FONT_ID, 280, tr(STR_NO_CREDENTIALS_MSG), true, EpdFontFamily::BOLD);
@@ -257,45 +257,46 @@ void KOReaderSyncActivity::render(RenderLock&&) {
: (std::string(tr(STR_SECTION_PREFIX)) + std::to_string(currentSpineIndex + 1));
// Remote progress - chapter and page
renderer.drawText(UI_10_FONT_ID, 20, 160, tr(STR_REMOTE_LABEL), true);
renderer.drawText(UI_10_FONT_ID, contentRect.x + 20, 160, tr(STR_REMOTE_LABEL), true);
char remoteChapterStr[128];
snprintf(remoteChapterStr, sizeof(remoteChapterStr), " %s", remoteChapter.c_str());
renderer.drawText(UI_10_FONT_ID, 20, 185, remoteChapterStr);
renderer.drawText(UI_10_FONT_ID, contentRect.x + 20, 185, remoteChapterStr);
char remotePageStr[64];
snprintf(remotePageStr, sizeof(remotePageStr), tr(STR_PAGE_OVERALL_FORMAT), remotePosition.pageNumber + 1,
remoteProgress.percentage * 100);
renderer.drawText(UI_10_FONT_ID, 20, 210, remotePageStr);
renderer.drawText(UI_10_FONT_ID, contentRect.x + 20, 210, remotePageStr);
if (!remoteProgress.device.empty()) {
char deviceStr[64];
snprintf(deviceStr, sizeof(deviceStr), tr(STR_DEVICE_FROM_FORMAT), remoteProgress.device.c_str());
renderer.drawText(UI_10_FONT_ID, 20, 235, deviceStr);
renderer.drawText(UI_10_FONT_ID, contentRect.x + 20, 235, deviceStr);
}
// Local progress - chapter and page
renderer.drawText(UI_10_FONT_ID, 20, 270, tr(STR_LOCAL_LABEL), true);
renderer.drawText(UI_10_FONT_ID, contentRect.x + 20, 270, tr(STR_LOCAL_LABEL), true);
char localChapterStr[128];
snprintf(localChapterStr, sizeof(localChapterStr), " %s", localChapter.c_str());
renderer.drawText(UI_10_FONT_ID, 20, 295, localChapterStr);
renderer.drawText(UI_10_FONT_ID, contentRect.x + 20, 295, localChapterStr);
char localPageStr[64];
snprintf(localPageStr, sizeof(localPageStr), tr(STR_PAGE_TOTAL_OVERALL_FORMAT), currentPage + 1, totalPagesInSpine,
localProgress.percentage * 100);
renderer.drawText(UI_10_FONT_ID, 20, 320, localPageStr);
renderer.drawText(UI_10_FONT_ID, contentRect.x + 20, 320, localPageStr);
const int optionY = 350;
const int optionHeight = 30;
// Apply option
if (selectedOption == 0) {
renderer.fillRect(0, optionY - 2, pageWidth - 1, optionHeight);
renderer.fillRect(contentRect.x, optionY - 2, contentRect.width - 1, optionHeight);
}
renderer.drawText(UI_10_FONT_ID, 20, optionY, tr(STR_APPLY_REMOTE), selectedOption != 0);
renderer.drawText(UI_10_FONT_ID, contentRect.x + 20, optionY, tr(STR_APPLY_REMOTE), selectedOption != 0);
// Upload option
if (selectedOption == 1) {
renderer.fillRect(0, optionY + optionHeight - 2, pageWidth - 1, optionHeight);
renderer.fillRect(contentRect.x, optionY + optionHeight - 2, contentRect.width - 1, optionHeight);
}
renderer.drawText(UI_10_FONT_ID, 20, optionY + optionHeight, tr(STR_UPLOAD_LOCAL), selectedOption != 1);
renderer.drawText(UI_10_FONT_ID, contentRect.x + 20, optionY + optionHeight, tr(STR_UPLOAD_LOCAL),
selectedOption != 1);
// Bottom button hints
const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), tr(STR_DIR_UP), tr(STR_DIR_DOWN));
+7 -7
View File
@@ -25,17 +25,17 @@ void QrDisplayActivity::loop() {
void QrDisplayActivity::render(RenderLock&&) {
renderer.clearScreen();
auto metrics = UITheme::getInstance().getMetrics();
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
const auto& metrics = UITheme::getInstance().getMetrics();
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, tr(STR_DISPLAY_QR), nullptr);
GUI.drawHeader(renderer, Rect{contentRect.x, metrics.topPadding, contentRect.width, metrics.headerHeight},
tr(STR_DISPLAY_QR), nullptr);
const int availableWidth = pageWidth - 40;
const int availableHeight = pageHeight - metrics.topPadding - metrics.headerHeight - metrics.verticalSpacing * 2 - 40;
const int startY = metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing;
const int availableHeight = contentRect.height - startY - metrics.verticalSpacing;
const Rect qrBounds(20, startY, availableWidth, availableHeight);
const Rect qrBounds(contentRect.x + metrics.contentSidePadding, startY,
contentRect.width - metrics.contentSidePadding * 2, availableHeight);
QrUtils::drawQrCode(renderer, qrBounds, textPayload);
const auto labels = mappedInput.mapLabels(tr(STR_BACK), "", "", "");
@@ -11,15 +11,9 @@
int XtcReaderChapterSelectionActivity::getPageItems() const {
constexpr int lineHeight = 30;
const int screenHeight = renderer.getScreenHeight();
const auto orientation = renderer.getOrientation();
// In inverted portrait, the hint row is drawn near the logical top.
// Reserve vertical space so the list starts below the hints.
const bool isPortraitInverted = orientation == GfxRenderer::Orientation::PortraitInverted;
const int hintGutterHeight = isPortraitInverted ? 50 : 0;
const int startY = 60 + hintGutterHeight;
const int availableHeight = screenHeight - startY - lineHeight;
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
constexpr int startY = 60;
const int availableHeight = contentRect.height - startY - lineHeight;
// Clamp to at least one item to prevent empty page math.
return std::max(1, availableHeight / lineHeight);
}
@@ -93,48 +87,35 @@ void XtcReaderChapterSelectionActivity::loop() {
void XtcReaderChapterSelectionActivity::render(RenderLock&&) {
renderer.clearScreen();
const auto pageWidth = renderer.getScreenWidth();
const auto orientation = renderer.getOrientation();
// Landscape orientation: reserve a horizontal gutter for button hints.
const bool isLandscapeCw = orientation == GfxRenderer::Orientation::LandscapeClockwise;
const bool isLandscapeCcw = orientation == GfxRenderer::Orientation::LandscapeCounterClockwise;
// Inverted portrait: reserve vertical space for hints at the top.
const bool isPortraitInverted = orientation == GfxRenderer::Orientation::PortraitInverted;
const int hintGutterWidth = (isLandscapeCw || isLandscapeCcw) ? 30 : 0;
// Landscape CW places hints on the left edge; CCW keeps them on the right.
const int contentX = isLandscapeCw ? hintGutterWidth : 0;
const int contentWidth = pageWidth - hintGutterWidth;
const int hintGutterHeight = isPortraitInverted ? 50 : 0;
const int contentY = hintGutterHeight;
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
const int pageItems = getPageItems();
// Manual centering to honor content gutters.
const int titleX =
contentX + (contentWidth - renderer.getTextWidth(UI_12_FONT_ID, tr(STR_SELECT_CHAPTER), EpdFontFamily::BOLD)) / 2;
renderer.drawText(UI_12_FONT_ID, titleX, 15 + contentY, tr(STR_SELECT_CHAPTER), true, EpdFontFamily::BOLD);
contentRect.x +
(contentRect.width - renderer.getTextWidth(UI_12_FONT_ID, tr(STR_SELECT_CHAPTER), EpdFontFamily::BOLD)) / 2;
renderer.drawText(UI_12_FONT_ID, titleX, contentRect.y + 15, tr(STR_SELECT_CHAPTER), true, EpdFontFamily::BOLD);
const auto& chapters = xtc->getChapters();
if (chapters.empty()) {
// Center the empty state within the gutter-safe content region.
const int emptyX = contentX + (contentWidth - renderer.getTextWidth(UI_10_FONT_ID, tr(STR_NO_CHAPTERS))) / 2;
renderer.drawText(UI_10_FONT_ID, emptyX, 120 + contentY, tr(STR_NO_CHAPTERS));
const int emptyX =
contentRect.x + (contentRect.width - renderer.getTextWidth(UI_10_FONT_ID, tr(STR_NO_CHAPTERS))) / 2;
renderer.drawText(UI_10_FONT_ID, emptyX, contentRect.y + 120, tr(STR_NO_CHAPTERS));
renderer.displayBuffer();
return;
}
const auto pageStartIndex = selectorIndex / pageItems * pageItems;
// Highlight only the content area, not the hint gutters.
renderer.fillRect(contentX, 60 + contentY + (selectorIndex % pageItems) * 30 - 2, contentWidth - 1, 30);
renderer.fillRect(contentRect.x, contentRect.y + 60 + (selectorIndex % pageItems) * 30 - 2, contentRect.width - 1,
30);
for (int i = pageStartIndex; i < static_cast<int>(chapters.size()) && i < pageStartIndex + pageItems; i++) {
const auto& chapter = chapters[i];
const char* title = chapter.name.empty() ? tr(STR_UNNAMED) : chapter.name.c_str();
renderer.drawText(UI_10_FONT_ID, contentX + 20, 60 + contentY + (i % pageItems) * 30, title, i != selectorIndex);
renderer.drawText(UI_10_FONT_ID, contentRect.x + 20, contentRect.y + 60 + (i % pageItems) * 30, title,
i != selectorIndex);
}
// Skip button hints in landscape CW mode (they overlap content)
if (renderer.getOrientation() != GfxRenderer::LandscapeClockwise) {
const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), tr(STR_DIR_UP), tr(STR_DIR_DOWN));
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
}
const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), tr(STR_DIR_UP), tr(STR_DIR_DOWN));
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
renderer.displayBuffer();
}
+16 -12
View File
@@ -105,19 +105,20 @@ void ButtonRemapActivity::render(RenderLock&&) {
};
const auto& metrics = UITheme::getInstance().getMetrics();
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
renderer.clearScreen();
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, tr(STR_REMAP_FRONT_BUTTONS));
GUI.drawSubHeader(renderer, Rect{0, metrics.topPadding + metrics.headerHeight, pageWidth, metrics.tabBarHeight},
tr(STR_REMAP_PROMPT));
GUI.drawHeader(renderer, Rect{contentRect.x, metrics.topPadding, contentRect.width, metrics.headerHeight},
tr(STR_REMAP_FRONT_BUTTONS));
GUI.drawSubHeader(
renderer, Rect{contentRect.x, metrics.topPadding + metrics.headerHeight, contentRect.width, metrics.tabBarHeight},
tr(STR_REMAP_PROMPT));
int topOffset = metrics.topPadding + metrics.headerHeight + metrics.tabBarHeight + metrics.verticalSpacing;
int contentHeight = pageHeight - topOffset - metrics.buttonHintsHeight - metrics.verticalSpacing;
int contentHeight = contentRect.height - topOffset - metrics.verticalSpacing;
GUI.drawList(
renderer, Rect{0, topOffset, pageWidth, contentHeight}, kRoleCount, currentStep,
renderer, Rect{contentRect.x, topOffset, contentRect.width, contentHeight}, kRoleCount, currentStep,
[&](int index) { return getRoleName(static_cast<uint8_t>(index)); }, nullptr, nullptr,
[&](int index) {
uint8_t assignedButton = tempMapping[static_cast<uint8_t>(index)];
@@ -128,16 +129,19 @@ void ButtonRemapActivity::render(RenderLock&&) {
// Temporary warning banner for duplicates.
if (!errorMessage.empty()) {
GUI.drawHelpText(renderer,
Rect{0, pageHeight - metrics.buttonHintsHeight - metrics.contentSidePadding - 15, pageWidth, 20},
Rect{contentRect.x, contentRect.y + contentRect.height - metrics.contentSidePadding - 15,
contentRect.width, 20},
errorMessage.c_str());
}
// Provide side button actions at the bottom of the screen (split across two lines).
GUI.drawHelpText(
renderer,
Rect{contentRect.x, topOffset + 4 * metrics.listRowHeight + 4 * metrics.verticalSpacing, contentRect.width, 20},
tr(STR_REMAP_RESET_HINT));
GUI.drawHelpText(renderer,
Rect{0, topOffset + 4 * metrics.listRowHeight + 4 * metrics.verticalSpacing, pageWidth, 20},
tr(STR_REMAP_RESET_HINT));
GUI.drawHelpText(renderer,
Rect{0, topOffset + 4 * metrics.listRowHeight + 5 * metrics.verticalSpacing + 20, pageWidth, 20},
Rect{contentRect.x, topOffset + 4 * metrics.listRowHeight + 5 * metrics.verticalSpacing + 20,
contentRect.width, 20},
tr(STR_REMAP_CANCEL_HINT));
// Live preview of logical labels under front buttons.
@@ -92,16 +92,17 @@ void CalibreSettingsActivity::render(RenderLock&&) {
renderer.clearScreen();
const auto& metrics = UITheme::getInstance().getMetrics();
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, tr(STR_OPDS_BROWSER));
GUI.drawSubHeader(renderer, Rect{0, metrics.topPadding + metrics.headerHeight, pageWidth, metrics.tabBarHeight},
tr(STR_CALIBRE_URL_HINT));
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
GUI.drawHeader(renderer, Rect{contentRect.x, metrics.topPadding, contentRect.width, metrics.headerHeight},
tr(STR_OPDS_BROWSER));
GUI.drawSubHeader(
renderer, Rect{contentRect.x, metrics.topPadding + metrics.headerHeight, contentRect.width, metrics.tabBarHeight},
tr(STR_CALIBRE_URL_HINT));
const int contentTop = metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing + metrics.tabBarHeight;
const int contentHeight = pageHeight - contentTop - metrics.buttonHintsHeight - metrics.verticalSpacing * 2;
const int contentHeight = contentRect.height - contentTop - metrics.verticalSpacing * 2;
GUI.drawList(
renderer, Rect{0, contentTop, pageWidth, contentHeight}, static_cast<int>(MENU_ITEMS),
renderer, Rect{contentRect.x, contentTop, contentRect.width, contentHeight}, static_cast<int>(MENU_ITEMS),
static_cast<int>(selectedIndex), [](int index) { return std::string(I18N.get(menuNames[index])); }, nullptr,
nullptr,
[this](int index) {
+13 -14
View File
@@ -20,19 +20,19 @@ void ClearCacheActivity::onExit() { Activity::onExit(); }
void ClearCacheActivity::render(RenderLock&&) {
const auto& metrics = UITheme::getInstance().getMetrics();
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
renderer.clearScreen();
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, tr(STR_CLEAR_READING_CACHE));
GUI.drawHeader(renderer, Rect{contentRect.x, metrics.topPadding, contentRect.width, metrics.headerHeight},
tr(STR_CLEAR_READING_CACHE));
const int midY = contentRect.y + contentRect.height / 2;
if (state == WARNING) {
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 - 60, tr(STR_CLEAR_CACHE_WARNING_1), true);
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 - 30, tr(STR_CLEAR_CACHE_WARNING_2), true,
EpdFontFamily::BOLD);
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 + 10, tr(STR_CLEAR_CACHE_WARNING_3), true);
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 + 30, tr(STR_CLEAR_CACHE_WARNING_4), true);
renderer.drawCenteredText(UI_10_FONT_ID, midY - 60, tr(STR_CLEAR_CACHE_WARNING_1), true);
renderer.drawCenteredText(UI_10_FONT_ID, midY - 30, tr(STR_CLEAR_CACHE_WARNING_2), true, EpdFontFamily::BOLD);
renderer.drawCenteredText(UI_10_FONT_ID, midY + 10, tr(STR_CLEAR_CACHE_WARNING_3), true);
renderer.drawCenteredText(UI_10_FONT_ID, midY + 30, tr(STR_CLEAR_CACHE_WARNING_4), true);
const auto labels = mappedInput.mapLabels(tr(STR_CANCEL), tr(STR_CLEAR_BUTTON), "", "");
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
@@ -41,18 +41,18 @@ void ClearCacheActivity::render(RenderLock&&) {
}
if (state == CLEARING) {
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2, tr(STR_CLEARING_CACHE));
renderer.drawCenteredText(UI_10_FONT_ID, midY, tr(STR_CLEARING_CACHE));
renderer.displayBuffer();
return;
}
if (state == SUCCESS) {
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 - 20, tr(STR_CACHE_CLEARED), true, EpdFontFamily::BOLD);
renderer.drawCenteredText(UI_10_FONT_ID, midY - 20, tr(STR_CACHE_CLEARED), true, EpdFontFamily::BOLD);
std::string resultText = std::to_string(clearedCount) + " " + std::string(tr(STR_ITEMS_REMOVED));
if (failedCount > 0) {
resultText += ", " + std::to_string(failedCount) + " " + std::string(tr(STR_FAILED_LOWER));
}
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 + 10, resultText.c_str());
renderer.drawCenteredText(UI_10_FONT_ID, midY + 10, resultText.c_str());
const auto labels = mappedInput.mapLabels(tr(STR_BACK), "", "", "");
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
@@ -61,9 +61,8 @@ void ClearCacheActivity::render(RenderLock&&) {
}
if (state == FAILED) {
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 - 20, tr(STR_CLEAR_CACHE_FAILED), true,
EpdFontFamily::BOLD);
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 + 10, tr(STR_CHECK_SERIAL_OUTPUT));
renderer.drawCenteredText(UI_10_FONT_ID, midY - 20, tr(STR_CLEAR_CACHE_FAILED), true, EpdFontFamily::BOLD);
renderer.drawCenteredText(UI_10_FONT_ID, midY + 10, tr(STR_CHECK_SERIAL_OUTPUT));
const auto labels = mappedInput.mapLabels(tr(STR_BACK), "", "", "");
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
@@ -76,12 +76,12 @@ void KOReaderAuthActivity::render(RenderLock&&) {
renderer.clearScreen();
const auto& metrics = UITheme::getInstance().getMetrics();
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, tr(STR_KOREADER_AUTH));
GUI.drawHeader(renderer, Rect{contentRect.x, metrics.topPadding, contentRect.width, metrics.headerHeight},
tr(STR_KOREADER_AUTH));
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
const auto top = (pageHeight - height) / 2;
const auto top = contentRect.y + (contentRect.height - height) / 2;
if (state == AUTHENTICATING) {
renderer.drawCenteredText(UI_10_FONT_ID, top, statusMessage.c_str());
@@ -115,15 +115,15 @@ void KOReaderSettingsActivity::render(RenderLock&&) {
renderer.clearScreen();
const auto& metrics = UITheme::getInstance().getMetrics();
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, tr(STR_KOREADER_SYNC));
GUI.drawHeader(renderer, Rect{contentRect.x, metrics.topPadding, contentRect.width, metrics.headerHeight},
tr(STR_KOREADER_SYNC));
const int contentTop = metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing;
const int contentHeight = pageHeight - contentTop - metrics.buttonHintsHeight - metrics.verticalSpacing * 2;
const int contentHeight = contentRect.height - contentTop - metrics.verticalSpacing * 2;
GUI.drawList(
renderer, Rect{0, contentTop, pageWidth, contentHeight}, static_cast<int>(MENU_ITEMS),
renderer, Rect{contentRect.x, contentTop, contentRect.width, contentHeight}, static_cast<int>(MENU_ITEMS),
static_cast<int>(selectedIndex), [](int index) { return std::string(I18N.get(menuNames[index])); }, nullptr,
nullptr,
[this](int index) {
@@ -61,18 +61,18 @@ void LanguageSelectActivity::handleSelection() {
void LanguageSelectActivity::render(RenderLock&&) {
renderer.clearScreen();
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
auto metrics = UITheme::getInstance().getMetrics();
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, tr(STR_LANGUAGE));
GUI.drawHeader(renderer, Rect{contentRect.x, metrics.topPadding, contentRect.width, metrics.headerHeight},
tr(STR_LANGUAGE));
// Current language marker
const int contentTop = metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing;
const int contentHeight = pageHeight - contentTop - metrics.buttonHintsHeight - metrics.verticalSpacing;
const int contentHeight = contentRect.height - contentTop - metrics.verticalSpacing;
const auto currentLang = static_cast<uint8_t>(I18N.getLanguage());
GUI.drawList(
renderer, Rect{0, contentTop, pageWidth, contentHeight}, totalItems, selectedIndex,
renderer, Rect{contentRect.x, contentTop, contentRect.width, contentHeight}, totalItems, selectedIndex,
[this](int index) { return I18N.getLanguageName(static_cast<Language>(SORTED_LANGUAGE_INDICES[index])); },
nullptr, nullptr,
[this, currentLang](int index) { return SORTED_LANGUAGE_INDICES[index] == currentLang ? tr(STR_SELECTED) : ""; },
+11 -10
View File
@@ -75,14 +75,14 @@ void OtaUpdateActivity::onExit() {
void OtaUpdateActivity::render(RenderLock&&) {
const auto& metrics = UITheme::getInstance().getMetrics();
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
renderer.clearScreen();
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, tr(STR_UPDATE));
GUI.drawHeader(renderer, Rect{contentRect.x, metrics.topPadding, contentRect.width, metrics.headerHeight},
tr(STR_UPDATE));
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
const auto top = (pageHeight - height) / 2;
const auto top = contentRect.y + (contentRect.height - height) / 2;
float updaterProgress = 0;
if (state == UPDATE_IN_PROGRESS) {
@@ -99,9 +99,10 @@ void OtaUpdateActivity::render(RenderLock&&) {
renderer.drawCenteredText(UI_10_FONT_ID, top, tr(STR_CHECKING_UPDATE));
} else if (state == WAITING_CONFIRMATION) {
renderer.drawCenteredText(UI_10_FONT_ID, top, tr(STR_NEW_UPDATE), true, EpdFontFamily::BOLD);
renderer.drawText(UI_10_FONT_ID, metrics.contentSidePadding, top + height + metrics.verticalSpacing,
renderer.drawText(UI_10_FONT_ID, contentRect.x + metrics.contentSidePadding, top + height + metrics.verticalSpacing,
(std::string(tr(STR_CURRENT_VERSION)) + CROSSPOINT_VERSION).c_str());
renderer.drawText(UI_10_FONT_ID, metrics.contentSidePadding, top + height * 2 + metrics.verticalSpacing * 2,
renderer.drawText(UI_10_FONT_ID, contentRect.x + metrics.contentSidePadding,
top + height * 2 + metrics.verticalSpacing * 2,
(std::string(tr(STR_NEW_VERSION)) + updater.getLatestVersion()).c_str());
const auto labels = mappedInput.mapLabels(tr(STR_CANCEL), tr(STR_UPDATE), "", "");
@@ -110,10 +111,10 @@ void OtaUpdateActivity::render(RenderLock&&) {
renderer.drawCenteredText(UI_10_FONT_ID, top, tr(STR_UPDATING));
int y = top + height + metrics.verticalSpacing;
GUI.drawProgressBar(
renderer,
Rect{metrics.contentSidePadding, y, pageWidth - metrics.contentSidePadding * 2, metrics.progressBarHeight},
static_cast<int>(updaterProgress * 100), 100);
GUI.drawProgressBar(renderer,
Rect{contentRect.x + metrics.contentSidePadding, y,
contentRect.width - metrics.contentSidePadding * 2, metrics.progressBarHeight},
static_cast<int>(updaterProgress * 100), 100);
y += metrics.progressBarHeight + metrics.verticalSpacing;
renderer.drawCenteredText(UI_10_FONT_ID, y,
+10 -10
View File
@@ -202,28 +202,28 @@ void SettingsActivity::toggleCurrentSetting() {
void SettingsActivity::render(RenderLock&&) {
renderer.clearScreen();
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
const auto& metrics = UITheme::getInstance().getMetrics();
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, tr(STR_SETTINGS_TITLE),
CROSSPOINT_VERSION);
GUI.drawHeader(renderer, Rect{contentRect.x, metrics.topPadding, contentRect.width, metrics.headerHeight},
tr(STR_SETTINGS_TITLE), CROSSPOINT_VERSION);
std::vector<TabInfo> tabs;
tabs.reserve(categoryCount);
for (int i = 0; i < categoryCount; i++) {
tabs.push_back({I18N.get(categoryNames[i]), selectedCategoryIndex == i});
}
GUI.drawTabBar(renderer, Rect{0, metrics.topPadding + metrics.headerHeight, pageWidth, metrics.tabBarHeight}, tabs,
selectedSettingIndex == 0);
GUI.drawTabBar(
renderer, Rect{contentRect.x, metrics.topPadding + metrics.headerHeight, contentRect.width, metrics.tabBarHeight},
tabs, selectedSettingIndex == 0);
const int contentTop = metrics.topPadding + metrics.headerHeight + metrics.tabBarHeight + metrics.verticalSpacing;
const auto& settings = *currentSettings;
GUI.drawList(
renderer,
Rect{0, metrics.topPadding + metrics.headerHeight + metrics.tabBarHeight + metrics.verticalSpacing, pageWidth,
pageHeight - (metrics.topPadding + metrics.headerHeight + metrics.tabBarHeight + metrics.buttonHintsHeight +
metrics.verticalSpacing * 2)},
Rect{contentRect.x, contentTop, contentRect.width,
contentRect.height -
(metrics.topPadding + metrics.headerHeight + metrics.tabBarHeight + metrics.verticalSpacing * 2)},
settingsCount, selectedSettingIndex - 1,
[&settings](int index) { return std::string(I18N.get(settings[index].nameId)); }, nullptr, nullptr,
[&settings](int i) {
@@ -118,15 +118,15 @@ void StatusBarSettingsActivity::render(RenderLock&&) {
renderer.clearScreen();
auto metrics = UITheme::getInstance().getMetrics();
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, tr(STR_CUSTOMISE_STATUS_BAR));
GUI.drawHeader(renderer, Rect{contentRect.x, metrics.topPadding, contentRect.width, metrics.headerHeight},
tr(STR_CUSTOMISE_STATUS_BAR));
const int contentTop = metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing;
const int contentHeight = pageHeight - contentTop - metrics.buttonHintsHeight - metrics.verticalSpacing * 2;
const int contentHeight = contentRect.height - contentTop - metrics.verticalSpacing * 2;
GUI.drawList(
renderer, Rect{0, contentTop, pageWidth, contentHeight}, static_cast<int>(MENU_ITEMS),
renderer, Rect{contentRect.x, contentTop, contentRect.width, contentHeight}, static_cast<int>(MENU_ITEMS),
static_cast<int>(selectedIndex), [](int index) { return std::string(I18N.get(menuNames[index])); }, nullptr,
nullptr,
[this](int index) {
+3 -2
View File
@@ -14,7 +14,8 @@ void ConfirmationActivity::onEnter() {
inputArmed = false;
lineHeight = renderer.getLineHeight(fontId);
const int maxWidth = renderer.getScreenWidth() - (margin * 2);
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
const int maxWidth = contentRect.width - (margin * 2);
if (!heading.empty()) {
safeHeading = renderer.truncatedText(fontId, heading.c_str(), maxWidth, EpdFontFamily::BOLD);
@@ -28,7 +29,7 @@ void ConfirmationActivity::onEnter() {
if (!safeBody.empty()) totalHeight += lineHeight;
if (!safeHeading.empty() && !safeBody.empty()) totalHeight += spacing;
startY = (renderer.getScreenHeight() - totalHeight) / 2;
startY = contentRect.y + (contentRect.height - totalHeight) / 2;
requestUpdate(true);
}
+12 -10
View File
@@ -192,11 +192,11 @@ void KeyboardEntryActivity::loop() {
void KeyboardEntryActivity::render(RenderLock&&) {
renderer.clearScreen();
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
const auto& metrics = UITheme::getInstance().getMetrics();
const Rect contentRect = UITheme::getContentRect(renderer, true, true);
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, title.c_str());
GUI.drawHeader(renderer, Rect{contentRect.x, metrics.topPadding, contentRect.width, metrics.headerHeight},
title.c_str());
// Draw input field
const int lineHeight = renderer.getLineHeight(UI_12_FONT_ID);
@@ -221,11 +221,13 @@ void KeyboardEntryActivity::render(RenderLock&&) {
while (true) {
std::string lineText = displayText.substr(lineStartIdx, lineEndIdx - lineStartIdx);
textWidth = renderer.getTextWidth(UI_12_FONT_ID, lineText.c_str());
if (textWidth <= pageWidth - 2 * metrics.contentSidePadding) {
if (textWidth <= contentRect.width - 2 * metrics.contentSidePadding) {
if (metrics.keyboardCenteredText) {
renderer.drawCenteredText(UI_12_FONT_ID, inputStartY + inputHeight, lineText.c_str());
const int centeredX = contentRect.x + (contentRect.width - textWidth) / 2;
renderer.drawText(UI_12_FONT_ID, centeredX, inputStartY + inputHeight, lineText.c_str());
} else {
renderer.drawText(UI_12_FONT_ID, metrics.contentSidePadding, inputStartY + inputHeight, lineText.c_str());
renderer.drawText(UI_12_FONT_ID, contentRect.x + metrics.contentSidePadding, inputStartY + inputHeight,
lineText.c_str());
}
if (lineEndIdx == displayText.length()) {
break;
@@ -239,11 +241,11 @@ void KeyboardEntryActivity::render(RenderLock&&) {
}
}
GUI.drawTextField(renderer, Rect{0, inputStartY, pageWidth, inputHeight}, textWidth);
GUI.drawTextField(renderer, Rect{contentRect.x, inputStartY, contentRect.width, inputHeight}, textWidth);
// Draw keyboard - use compact spacing to fit 5 rows on screen
const int keyboardStartY = metrics.keyboardBottomAligned
? pageHeight - metrics.buttonHintsHeight - metrics.verticalSpacing -
? contentRect.y + contentRect.height - metrics.verticalSpacing -
(metrics.keyboardKeyHeight + metrics.keyboardKeySpacing) * NUM_ROWS
: inputStartY + inputHeight + metrics.verticalSpacing * 4;
const int keyWidth = metrics.keyboardKeyWidth;
@@ -252,9 +254,9 @@ void KeyboardEntryActivity::render(RenderLock&&) {
const char* const* layout = shiftState ? keyboardShift : keyboard;
// Calculate left margin to center the longest row (13 keys)
// Calculate left margin to center the longest row (13 keys) within the content area
const int maxRowWidth = KEYS_PER_ROW * (keyWidth + keySpacing);
const int leftMargin = (pageWidth - maxRowWidth) / 2;
const int leftMargin = contentRect.x + (contentRect.width - maxRowWidth) / 2;
for (int row = 0; row < NUM_ROWS; row++) {
const int rowY = keyboardStartY + row * (keyHeight + keySpacing);
+33 -2
View File
@@ -51,6 +51,7 @@ void UITheme::setTheme(CrossPointSettings::UI_THEME type) {
int UITheme::getNumberOfItemsPerPage(const GfxRenderer& renderer, bool hasHeader, bool hasTabBar, bool hasButtonHints,
bool hasSubtitle) {
const ThemeMetrics& metrics = UITheme::getInstance().getMetrics();
const Rect contentRect = getContentRect(renderer, hasButtonHints, /*hasSideHints=*/false);
int reservedHeight = metrics.topPadding;
if (hasHeader) {
reservedHeight += metrics.headerHeight + metrics.verticalSpacing;
@@ -59,13 +60,43 @@ int UITheme::getNumberOfItemsPerPage(const GfxRenderer& renderer, bool hasHeader
reservedHeight += metrics.tabBarHeight;
}
if (hasButtonHints) {
reservedHeight += metrics.verticalSpacing + metrics.buttonHintsHeight;
reservedHeight += metrics.verticalSpacing;
}
const int availableHeight = renderer.getScreenHeight() - reservedHeight;
const int availableHeight = contentRect.height - reservedHeight;
int rowHeight = hasSubtitle ? metrics.listWithSubtitleRowHeight : metrics.listRowHeight;
return availableHeight / rowHeight;
}
Rect UITheme::getContentRect(const GfxRenderer& renderer, bool hasBottomHints, bool hasSideHints) {
const ThemeMetrics& metrics = UITheme::getInstance().getMetrics();
const int bh = hasBottomHints ? metrics.buttonHintsHeight : 0;
const int sw = hasSideHints ? metrics.sideButtonHintsWidth : 0;
int top = 0, right = 0, bottom = 0, left = 0;
switch (renderer.getOrientation()) {
case GfxRenderer::Portrait:
bottom = bh;
right = sw;
break;
case GfxRenderer::PortraitInverted:
top = bh;
left = sw;
break;
case GfxRenderer::LandscapeClockwise:
left = bh;
bottom = sw;
break;
case GfxRenderer::LandscapeCounterClockwise:
right = bh;
top = sw;
break;
}
const int w = renderer.getScreenWidth();
const int h = renderer.getScreenHeight();
return Rect{left, top, w - left - right, h - top - bottom};
}
std::string UITheme::getCoverThumbPath(std::string coverBmpPath, int coverHeight) {
size_t pos = coverBmpPath.find("[HEIGHT]", 0);
if (pos != std::string::npos) {
+4
View File
@@ -20,6 +20,10 @@ class UITheme {
void setTheme(CrossPointSettings::UI_THEME type);
static int getNumberOfItemsPerPage(const GfxRenderer& renderer, bool hasHeader, bool hasTabBar, bool hasButtonHints,
bool hasSubtitle);
// Returns the drawable content Rect accounting for screen orientation and visible button hints.
// Bottom hints occupy the physical bottom edge; side hints occupy the physical right edge.
// The mapping to logical edges is orientation-dependent.
static Rect getContentRect(const GfxRenderer& renderer, bool hasBottomHints, bool hasSideHints);
static std::string getCoverThumbPath(std::string coverBmpPath, int coverHeight);
static UIIcon getFileIcon(const std::string& filename);
static int getStatusBarHeight();
+4 -4
View File
@@ -273,9 +273,9 @@ void LyraTheme::drawList(const GfxRenderer& renderer, Rect rect, int itemCount,
rect.width -
(totalPages > 1 ? (LyraMetrics::values.scrollBarWidth + LyraMetrics::values.scrollBarRightOffset) : 1);
if (selectedIndex >= 0) {
renderer.fillRoundedRect(LyraMetrics::values.contentSidePadding, rect.y + selectedIndex % pageItems * rowHeight,
contentWidth - LyraMetrics::values.contentSidePadding * 2, rowHeight, cornerRadius,
Color::LightGray);
renderer.fillRoundedRect(
rect.x + LyraMetrics::values.contentSidePadding, rect.y + selectedIndex % pageItems * rowHeight,
contentWidth - LyraMetrics::values.contentSidePadding * 2, rowHeight, cornerRadius, Color::LightGray);
}
int textX = rect.x + LyraMetrics::values.contentSidePadding + hPaddingInSelection;
@@ -336,7 +336,7 @@ void LyraTheme::drawList(const GfxRenderer& renderer, Rect rect, int itemCount,
if (!valueText.empty()) {
if (i == selectedIndex && highlightValue) {
renderer.fillRoundedRect(
contentWidth - LyraMetrics::values.contentSidePadding - hPaddingInSelection - valueWidth, itemY,
rect.x + contentWidth - LyraMetrics::values.contentSidePadding - hPaddingInSelection - valueWidth, itemY,
valueWidth + hPaddingInSelection, rowHeight, cornerRadius, Color::Black);
}