Adjust menu design to still fit on screen
This commit is contained in:
@@ -19,6 +19,85 @@
|
|||||||
#include "components/UITheme.h"
|
#include "components/UITheme.h"
|
||||||
#include "fontIds.h"
|
#include "fontIds.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr int CLASSIC_MIN_RECENT_TILE_HEIGHT = 280;
|
||||||
|
constexpr int LYRA_MIN_RECENT_TILE_HEIGHT = 170;
|
||||||
|
constexpr int LYRA_3_COVERS_MIN_RECENT_TILE_HEIGHT = 200;
|
||||||
|
constexpr int CLASSIC_MIN_RECENT_TO_MENU_GAP = 2;
|
||||||
|
constexpr int LYRA_MIN_RECENT_TO_MENU_GAP = 4;
|
||||||
|
|
||||||
|
struct HomeScreenLayout {
|
||||||
|
int recentTileHeight;
|
||||||
|
int recentToMenuGap;
|
||||||
|
int menuHeight;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool isLyraFamilyTheme() {
|
||||||
|
const auto theme = static_cast<CrossPointSettings::UI_THEME>(SETTINGS.uiTheme);
|
||||||
|
return theme == CrossPointSettings::UI_THEME::LYRA || theme == CrossPointSettings::UI_THEME::LYRA_3_COVERS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isLyraExtendedTheme() {
|
||||||
|
return static_cast<CrossPointSettings::UI_THEME>(SETTINGS.uiTheme) == CrossPointSettings::UI_THEME::LYRA_3_COVERS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getMinRecentTileHeight() {
|
||||||
|
if (isLyraExtendedTheme()) {
|
||||||
|
return LYRA_3_COVERS_MIN_RECENT_TILE_HEIGHT;
|
||||||
|
}
|
||||||
|
if (isLyraFamilyTheme()) {
|
||||||
|
return LYRA_MIN_RECENT_TILE_HEIGHT;
|
||||||
|
}
|
||||||
|
return CLASSIC_MIN_RECENT_TILE_HEIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getMinRecentToMenuGap() {
|
||||||
|
return isLyraFamilyTheme() ? LYRA_MIN_RECENT_TO_MENU_GAP : CLASSIC_MIN_RECENT_TO_MENU_GAP;
|
||||||
|
}
|
||||||
|
|
||||||
|
HomeScreenLayout computeHomeScreenLayout(const ThemeMetrics& metrics, int contentHeight, int menuItemCount) {
|
||||||
|
HomeScreenLayout layout{metrics.homeCoverTileHeight, metrics.verticalSpacing, 0};
|
||||||
|
|
||||||
|
const int menuRequiredHeight =
|
||||||
|
menuItemCount * metrics.menuRowHeight + std::max(0, menuItemCount - 1) * metrics.menuSpacing;
|
||||||
|
|
||||||
|
auto computeMenuHeight = [&]() {
|
||||||
|
return contentHeight - (metrics.homeTopPadding + layout.recentTileHeight + layout.recentToMenuGap);
|
||||||
|
};
|
||||||
|
|
||||||
|
layout.menuHeight = computeMenuHeight();
|
||||||
|
if (layout.menuHeight >= menuRequiredHeight) {
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int gapReduction =
|
||||||
|
std::min(layout.recentToMenuGap - getMinRecentToMenuGap(), menuRequiredHeight - layout.menuHeight);
|
||||||
|
if (gapReduction > 0) {
|
||||||
|
layout.recentToMenuGap -= gapReduction;
|
||||||
|
layout.menuHeight = computeMenuHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layout.menuHeight >= menuRequiredHeight) {
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int tileReduction =
|
||||||
|
std::min(layout.recentTileHeight - getMinRecentTileHeight(), menuRequiredHeight - layout.menuHeight);
|
||||||
|
if (tileReduction > 0) {
|
||||||
|
layout.recentTileHeight -= tileReduction;
|
||||||
|
layout.menuHeight = computeMenuHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
layout.menuHeight = std::max(0, layout.menuHeight);
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getHomeCoverRenderHeight(const HomeScreenLayout& layout) {
|
||||||
|
return isLyraExtendedTheme() ? std::max(120, layout.recentTileHeight - 58)
|
||||||
|
: std::max(120, layout.recentTileHeight - (isLyraFamilyTheme() ? 16 : 0));
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
int HomeActivity::getMenuItemCount() const {
|
int HomeActivity::getMenuItemCount() const {
|
||||||
int count = 5; // File Browser, Recents, File transfer, Weather, Settings
|
int count = 5; // File Browser, Recents, File transfer, Weather, Settings
|
||||||
if (!recentBooks.empty()) {
|
if (!recentBooks.empty()) {
|
||||||
@@ -222,11 +301,6 @@ void HomeActivity::render(RenderLock&&) {
|
|||||||
|
|
||||||
GUI.drawHeader(renderer, Rect{contentRect.x, metrics.topPadding, contentRect.width, metrics.homeTopPadding}, nullptr);
|
GUI.drawHeader(renderer, Rect{contentRect.x, metrics.topPadding, contentRect.width, metrics.homeTopPadding}, nullptr);
|
||||||
|
|
||||||
GUI.drawRecentBookCover(renderer,
|
|
||||||
Rect{contentRect.x, metrics.homeTopPadding, contentRect.width, metrics.homeCoverTileHeight},
|
|
||||||
recentBooks, selectorIndex, coverRendered, coverBufferStored, bufferRestored,
|
|
||||||
std::bind(&HomeActivity::storeCoverBuffer, this));
|
|
||||||
|
|
||||||
// Build menu items dynamically
|
// Build menu items dynamically
|
||||||
std::vector<const char*> menuItems = {tr(STR_BROWSE_FILES), tr(STR_MENU_RECENT_BOOKS), tr(STR_FILE_TRANSFER),
|
std::vector<const char*> menuItems = {tr(STR_BROWSE_FILES), tr(STR_MENU_RECENT_BOOKS), tr(STR_FILE_TRANSFER),
|
||||||
tr(STR_WEATHER), tr(STR_SETTINGS_TITLE)};
|
tr(STR_WEATHER), tr(STR_SETTINGS_TITLE)};
|
||||||
@@ -238,11 +312,18 @@ void HomeActivity::render(RenderLock&&) {
|
|||||||
menuIcons.insert(menuIcons.begin() + 2, Library);
|
menuIcons.insert(menuIcons.begin() + 2, Library);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const HomeScreenLayout layout =
|
||||||
|
computeHomeScreenLayout(metrics, contentRect.height, static_cast<int>(menuItems.size()));
|
||||||
|
|
||||||
|
GUI.drawRecentBookCover(renderer,
|
||||||
|
Rect{contentRect.x, metrics.homeTopPadding, contentRect.width, layout.recentTileHeight},
|
||||||
|
recentBooks, selectorIndex, coverRendered, coverBufferStored, bufferRestored,
|
||||||
|
std::bind(&HomeActivity::storeCoverBuffer, this));
|
||||||
|
|
||||||
GUI.drawButtonMenu(
|
GUI.drawButtonMenu(
|
||||||
renderer,
|
renderer,
|
||||||
Rect{contentRect.x, metrics.homeTopPadding + metrics.homeCoverTileHeight + metrics.verticalSpacing,
|
Rect{contentRect.x, metrics.homeTopPadding + layout.recentTileHeight + layout.recentToMenuGap, contentRect.width,
|
||||||
contentRect.width,
|
layout.menuHeight},
|
||||||
contentRect.height - (metrics.headerHeight + metrics.homeTopPadding + metrics.verticalSpacing * 2)},
|
|
||||||
static_cast<int>(menuItems.size()), selectorIndex - recentBooks.size(),
|
static_cast<int>(menuItems.size()), selectorIndex - recentBooks.size(),
|
||||||
[&menuItems](int index) { return std::string(menuItems[index]); },
|
[&menuItems](int index) { return std::string(menuItems[index]); },
|
||||||
[&menuIcons](int index) { return menuIcons[index]; });
|
[&menuIcons](int index) { return menuIcons[index]; });
|
||||||
@@ -257,7 +338,7 @@ void HomeActivity::render(RenderLock&&) {
|
|||||||
requestUpdate();
|
requestUpdate();
|
||||||
} else if (!recentsLoaded && !recentsLoading) {
|
} else if (!recentsLoaded && !recentsLoading) {
|
||||||
recentsLoading = true;
|
recentsLoading = true;
|
||||||
loadRecentCovers(metrics.homeCoverHeight);
|
loadRecentCovers(getHomeCoverRenderHeight(layout));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -652,18 +652,33 @@ void BaseTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
|
|||||||
void BaseTheme::drawButtonMenu(GfxRenderer& renderer, Rect rect, int buttonCount, int selectedIndex,
|
void BaseTheme::drawButtonMenu(GfxRenderer& renderer, Rect rect, int buttonCount, int selectedIndex,
|
||||||
const std::function<std::string(int index)>& buttonLabel,
|
const std::function<std::string(int index)>& buttonLabel,
|
||||||
const std::function<UIIcon(int index)>& rowIcon) const {
|
const std::function<UIIcon(int index)>& rowIcon) const {
|
||||||
|
int rowHeight = BaseMetrics::values.menuRowHeight;
|
||||||
|
int rowSpacing = BaseMetrics::values.menuSpacing;
|
||||||
|
if (buttonCount > 0 && rect.height > 0) {
|
||||||
|
const int defaultHeight = buttonCount * rowHeight + std::max(0, buttonCount - 1) * rowSpacing;
|
||||||
|
if (defaultHeight > rect.height) {
|
||||||
|
rowSpacing = std::max(0, (rect.height - buttonCount * rowHeight) / std::max(1, buttonCount - 1));
|
||||||
|
if (buttonCount * rowHeight + std::max(0, buttonCount - 1) * rowSpacing > rect.height) {
|
||||||
|
rowHeight = std::max(30, (rect.height - std::max(0, buttonCount - 1) * rowSpacing) / buttonCount);
|
||||||
|
}
|
||||||
|
if (buttonCount * rowHeight + std::max(0, buttonCount - 1) * rowSpacing > rect.height) {
|
||||||
|
rowHeight = std::max(1, rect.height / buttonCount);
|
||||||
|
rowSpacing = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < buttonCount; ++i) {
|
for (int i = 0; i < buttonCount; ++i) {
|
||||||
const int tileY = BaseMetrics::values.verticalSpacing + rect.y +
|
const int tileY = rect.y + static_cast<int>(i) * (rowHeight + rowSpacing);
|
||||||
static_cast<int>(i) * (BaseMetrics::values.menuRowHeight + BaseMetrics::values.menuSpacing);
|
|
||||||
|
|
||||||
const bool selected = selectedIndex == i;
|
const bool selected = selectedIndex == i;
|
||||||
|
|
||||||
if (selected) {
|
if (selected) {
|
||||||
renderer.fillRect(rect.x + BaseMetrics::values.contentSidePadding, tileY,
|
renderer.fillRect(rect.x + BaseMetrics::values.contentSidePadding, tileY,
|
||||||
rect.width - BaseMetrics::values.contentSidePadding * 2, BaseMetrics::values.menuRowHeight);
|
rect.width - BaseMetrics::values.contentSidePadding * 2, rowHeight);
|
||||||
} else {
|
} else {
|
||||||
renderer.drawRect(rect.x + BaseMetrics::values.contentSidePadding, tileY,
|
renderer.drawRect(rect.x + BaseMetrics::values.contentSidePadding, tileY,
|
||||||
rect.width - BaseMetrics::values.contentSidePadding * 2, BaseMetrics::values.menuRowHeight);
|
rect.width - BaseMetrics::values.contentSidePadding * 2, rowHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string labelStr = buttonLabel(i);
|
std::string labelStr = buttonLabel(i);
|
||||||
@@ -671,8 +686,7 @@ void BaseTheme::drawButtonMenu(GfxRenderer& renderer, Rect rect, int buttonCount
|
|||||||
const int textWidth = renderer.getTextWidth(UI_10_FONT_ID, label);
|
const int textWidth = renderer.getTextWidth(UI_10_FONT_ID, label);
|
||||||
const int textX = rect.x + (rect.width - textWidth) / 2;
|
const int textX = rect.x + (rect.width - textWidth) / 2;
|
||||||
const int lineHeight = renderer.getLineHeight(UI_10_FONT_ID);
|
const int lineHeight = renderer.getLineHeight(UI_10_FONT_ID);
|
||||||
const int textY =
|
const int textY = tileY + (rowHeight - lineHeight) / 2; // vertically centered assuming y is top of text
|
||||||
tileY + (BaseMetrics::values.menuRowHeight - lineHeight) / 2; // vertically centered assuming y is top of text
|
|
||||||
// Invert text when the tile is selected, to contrast with the filled background
|
// Invert text when the tile is selected, to contrast with the filled background
|
||||||
renderer.drawText(UI_10_FONT_ID, textX, textY, label, selectedIndex != i);
|
renderer.drawText(UI_10_FONT_ID, textX, textY, label, selectedIndex != i);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ void Lyra3CoversTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, con
|
|||||||
bool& bufferRestored, std::function<bool()> storeCoverBuffer) const {
|
bool& bufferRestored, std::function<bool()> storeCoverBuffer) const {
|
||||||
const int tileWidth = (rect.width - 2 * Lyra3CoversMetrics::values.contentSidePadding) / 3;
|
const int tileWidth = (rect.width - 2 * Lyra3CoversMetrics::values.contentSidePadding) / 3;
|
||||||
const int tileY = rect.y;
|
const int tileY = rect.y;
|
||||||
|
const int titleAreaHeight = renderer.getLineHeight(SMALL_FONT_ID) * 3 + hPaddingInSelection + 5;
|
||||||
|
const int coverHeight = std::max(120, rect.height - titleAreaHeight);
|
||||||
const bool hasContinueReading = !recentBooks.empty();
|
const bool hasContinueReading = !recentBooks.empty();
|
||||||
|
|
||||||
// Draw book card regardless, fill with message based on `hasContinueReading`
|
// Draw book card regardless, fill with message based on `hasContinueReading`
|
||||||
@@ -38,40 +40,38 @@ void Lyra3CoversTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, con
|
|||||||
if (coverPath.empty()) {
|
if (coverPath.empty()) {
|
||||||
hasCover = false;
|
hasCover = false;
|
||||||
} else {
|
} else {
|
||||||
const std::string coverBmpPath =
|
const std::string coverBmpPath = UITheme::getCoverThumbPath(coverPath, coverHeight);
|
||||||
UITheme::getCoverThumbPath(coverPath, Lyra3CoversMetrics::values.homeCoverHeight);
|
|
||||||
|
|
||||||
// First time: load cover from SD and render
|
// First time: load cover from SD and render
|
||||||
FsFile file;
|
FsFile file;
|
||||||
if (Storage.openFileForRead("HOME", coverBmpPath, file)) {
|
if (Storage.openFileForRead("HOME", coverBmpPath, file)) {
|
||||||
Bitmap bitmap(file);
|
Bitmap bitmap(file);
|
||||||
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
||||||
float coverHeight = static_cast<float>(bitmap.getHeight());
|
const float bitmapHeight = static_cast<float>(bitmap.getHeight());
|
||||||
float coverWidth = static_cast<float>(bitmap.getWidth());
|
const float bitmapWidth = static_cast<float>(bitmap.getWidth());
|
||||||
float ratio = coverWidth / coverHeight;
|
const float ratio = bitmapWidth / bitmapHeight;
|
||||||
const float tileRatio = static_cast<float>(tileWidth - 2 * hPaddingInSelection) /
|
const float tileRatio =
|
||||||
static_cast<float>(Lyra3CoversMetrics::values.homeCoverHeight);
|
static_cast<float>(tileWidth - 2 * hPaddingInSelection) / static_cast<float>(coverHeight);
|
||||||
float cropX = 1.0f - (tileRatio / ratio);
|
const float cropX = 1.0f - (tileRatio / ratio);
|
||||||
|
|
||||||
renderer.drawBitmap(bitmap, tileX + hPaddingInSelection, tileY + hPaddingInSelection,
|
renderer.drawBitmap(bitmap, tileX + hPaddingInSelection, tileY + hPaddingInSelection,
|
||||||
tileWidth - 2 * hPaddingInSelection, Lyra3CoversMetrics::values.homeCoverHeight,
|
tileWidth - 2 * hPaddingInSelection, coverHeight, cropX);
|
||||||
cropX);
|
|
||||||
} else {
|
} else {
|
||||||
hasCover = false;
|
hasCover = false;
|
||||||
}
|
}
|
||||||
file.close();
|
file.close();
|
||||||
|
} else {
|
||||||
|
hasCover = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Draw either way
|
// Draw either way
|
||||||
renderer.drawRect(tileX + hPaddingInSelection, tileY + hPaddingInSelection, tileWidth - 2 * hPaddingInSelection,
|
renderer.drawRect(tileX + hPaddingInSelection, tileY + hPaddingInSelection, tileWidth - 2 * hPaddingInSelection,
|
||||||
Lyra3CoversMetrics::values.homeCoverHeight, true);
|
coverHeight, true);
|
||||||
|
|
||||||
if (!hasCover) {
|
if (!hasCover) {
|
||||||
// Render empty cover
|
// Render empty cover
|
||||||
renderer.fillRect(tileX + hPaddingInSelection,
|
renderer.fillRect(tileX + hPaddingInSelection, tileY + hPaddingInSelection + (coverHeight / 3),
|
||||||
tileY + hPaddingInSelection + (Lyra3CoversMetrics::values.homeCoverHeight / 3),
|
tileWidth - 2 * hPaddingInSelection, 2 * coverHeight / 3, true);
|
||||||
tileWidth - 2 * hPaddingInSelection, 2 * Lyra3CoversMetrics::values.homeCoverHeight / 3,
|
|
||||||
true);
|
|
||||||
renderer.drawIcon(CoverIcon, tileX + hPaddingInSelection + 24, tileY + hPaddingInSelection + 24, 32, 32);
|
renderer.drawIcon(CoverIcon, tileX + hPaddingInSelection + 24, tileY + hPaddingInSelection + 24, 32, 32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,16 +99,14 @@ void Lyra3CoversTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, con
|
|||||||
// Draw selection box
|
// Draw selection box
|
||||||
renderer.fillRoundedRect(tileX, tileY, tileWidth, hPaddingInSelection, cornerRadius, true, true, false, false,
|
renderer.fillRoundedRect(tileX, tileY, tileWidth, hPaddingInSelection, cornerRadius, true, true, false, false,
|
||||||
Color::LightGray);
|
Color::LightGray);
|
||||||
renderer.fillRectDither(tileX, tileY + hPaddingInSelection, hPaddingInSelection,
|
renderer.fillRectDither(tileX, tileY + hPaddingInSelection, hPaddingInSelection, coverHeight, Color::LightGray);
|
||||||
Lyra3CoversMetrics::values.homeCoverHeight, Color::LightGray);
|
|
||||||
renderer.fillRectDither(tileX + tileWidth - hPaddingInSelection, tileY + hPaddingInSelection,
|
renderer.fillRectDither(tileX + tileWidth - hPaddingInSelection, tileY + hPaddingInSelection,
|
||||||
hPaddingInSelection, Lyra3CoversMetrics::values.homeCoverHeight, Color::LightGray);
|
hPaddingInSelection, coverHeight, Color::LightGray);
|
||||||
renderer.fillRoundedRect(tileX, tileY + Lyra3CoversMetrics::values.homeCoverHeight + hPaddingInSelection,
|
renderer.fillRoundedRect(tileX, tileY + coverHeight + hPaddingInSelection, tileWidth, dynamicTitleBoxHeight,
|
||||||
tileWidth, dynamicTitleBoxHeight, cornerRadius, false, false, true, true,
|
cornerRadius, false, false, true, true, Color::LightGray);
|
||||||
Color::LightGray);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int currentY = tileY + Lyra3CoversMetrics::values.homeCoverHeight + hPaddingInSelection + 5;
|
int currentY = tileY + coverHeight + hPaddingInSelection + 5;
|
||||||
for (const auto& line : titleLines) {
|
for (const auto& line : titleLines) {
|
||||||
renderer.drawText(SMALL_FONT_ID, tileX + hPaddingInSelection, currentY, line.c_str(), true);
|
renderer.drawText(SMALL_FONT_ID, tileX + hPaddingInSelection, currentY, line.c_str(), true);
|
||||||
currentY += titleLineHeight;
|
currentY += titleLineHeight;
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ constexpr int maxListValueWidth = 200;
|
|||||||
constexpr int mainMenuIconSize = 32;
|
constexpr int mainMenuIconSize = 32;
|
||||||
constexpr int listIconSize = 24;
|
constexpr int listIconSize = 24;
|
||||||
constexpr int mainMenuColumns = 2;
|
constexpr int mainMenuColumns = 2;
|
||||||
|
constexpr int minAdaptiveMenuRowHeight = 40;
|
||||||
int coverWidth = 0;
|
int coverWidth = 0;
|
||||||
|
|
||||||
void drawLyraBatteryIcon(const GfxRenderer& renderer, int x, int y, int battWidth, int rectHeight,
|
void drawLyraBatteryIcon(const GfxRenderer& renderer, int x, int y, int battWidth, int rectHeight,
|
||||||
@@ -430,9 +431,10 @@ void LyraTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
|
|||||||
const int tileWidth = rect.width - 2 * LyraMetrics::values.contentSidePadding;
|
const int tileWidth = rect.width - 2 * LyraMetrics::values.contentSidePadding;
|
||||||
const int tileHeight = rect.height;
|
const int tileHeight = rect.height;
|
||||||
const int tileY = rect.y;
|
const int tileY = rect.y;
|
||||||
|
const int coverHeight = std::max(120, tileHeight - 2 * hPaddingInSelection);
|
||||||
const bool hasContinueReading = !recentBooks.empty();
|
const bool hasContinueReading = !recentBooks.empty();
|
||||||
if (coverWidth == 0) {
|
if (coverWidth == 0) {
|
||||||
coverWidth = LyraMetrics::values.homeCoverHeight * 0.6;
|
coverWidth = static_cast<int>(coverHeight * 0.6f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw book card regardless, fill with message based on `hasContinueReading`
|
// Draw book card regardless, fill with message based on `hasContinueReading`
|
||||||
@@ -447,7 +449,7 @@ void LyraTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
|
|||||||
if (coverPath.empty()) {
|
if (coverPath.empty()) {
|
||||||
hasCover = false;
|
hasCover = false;
|
||||||
} else {
|
} else {
|
||||||
const std::string coverBmpPath = UITheme::getCoverThumbPath(coverPath, LyraMetrics::values.homeCoverHeight);
|
const std::string coverBmpPath = UITheme::getCoverThumbPath(coverPath, coverHeight);
|
||||||
|
|
||||||
// First time: load cover from SD and render
|
// First time: load cover from SD and render
|
||||||
FsFile file;
|
FsFile file;
|
||||||
@@ -456,7 +458,7 @@ void LyraTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
|
|||||||
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
||||||
coverWidth = bitmap.getWidth();
|
coverWidth = bitmap.getWidth();
|
||||||
renderer.drawBitmap(bitmap, tileX + hPaddingInSelection, tileY + hPaddingInSelection, coverWidth,
|
renderer.drawBitmap(bitmap, tileX + hPaddingInSelection, tileY + hPaddingInSelection, coverWidth,
|
||||||
LyraMetrics::values.homeCoverHeight);
|
coverHeight);
|
||||||
} else {
|
} else {
|
||||||
hasCover = false;
|
hasCover = false;
|
||||||
}
|
}
|
||||||
@@ -465,14 +467,12 @@ void LyraTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Draw either way
|
// Draw either way
|
||||||
renderer.drawRect(tileX + hPaddingInSelection, tileY + hPaddingInSelection, coverWidth,
|
renderer.drawRect(tileX + hPaddingInSelection, tileY + hPaddingInSelection, coverWidth, coverHeight, true);
|
||||||
LyraMetrics::values.homeCoverHeight, true);
|
|
||||||
|
|
||||||
if (!hasCover) {
|
if (!hasCover) {
|
||||||
// Render empty cover
|
// Render empty cover
|
||||||
renderer.fillRect(tileX + hPaddingInSelection,
|
renderer.fillRect(tileX + hPaddingInSelection, tileY + hPaddingInSelection + (coverHeight / 3), coverWidth,
|
||||||
tileY + hPaddingInSelection + (LyraMetrics::values.homeCoverHeight / 3), coverWidth,
|
2 * coverHeight / 3, true);
|
||||||
2 * LyraMetrics::values.homeCoverHeight / 3, true);
|
|
||||||
renderer.drawIcon(CoverIcon, tileX + hPaddingInSelection + 24, tileY + hPaddingInSelection + 24, 32, 32);
|
renderer.drawIcon(CoverIcon, tileX + hPaddingInSelection + 24, tileY + hPaddingInSelection + 24, 32, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,13 +489,11 @@ void LyraTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
|
|||||||
// Draw selection box
|
// Draw selection box
|
||||||
renderer.fillRoundedRect(tileX, tileY, tileWidth, hPaddingInSelection, cornerRadius, true, true, false, false,
|
renderer.fillRoundedRect(tileX, tileY, tileWidth, hPaddingInSelection, cornerRadius, true, true, false, false,
|
||||||
Color::LightGray);
|
Color::LightGray);
|
||||||
renderer.fillRectDither(tileX, tileY + hPaddingInSelection, hPaddingInSelection,
|
renderer.fillRectDither(tileX, tileY + hPaddingInSelection, hPaddingInSelection, coverHeight, Color::LightGray);
|
||||||
LyraMetrics::values.homeCoverHeight, Color::LightGray);
|
|
||||||
renderer.fillRectDither(tileX + hPaddingInSelection + coverWidth, tileY + hPaddingInSelection,
|
renderer.fillRectDither(tileX + hPaddingInSelection + coverWidth, tileY + hPaddingInSelection,
|
||||||
tileWidth - hPaddingInSelection - coverWidth, LyraMetrics::values.homeCoverHeight,
|
tileWidth - hPaddingInSelection - coverWidth, coverHeight, Color::LightGray);
|
||||||
Color::LightGray);
|
renderer.fillRoundedRect(tileX, tileY + coverHeight + hPaddingInSelection, tileWidth, hPaddingInSelection,
|
||||||
renderer.fillRoundedRect(tileX, tileY + LyraMetrics::values.homeCoverHeight + hPaddingInSelection, tileWidth,
|
cornerRadius, false, false, true, true, Color::LightGray);
|
||||||
hPaddingInSelection, cornerRadius, false, false, true, true, Color::LightGray);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto titleLines = renderer.wrappedText(UI_12_FONT_ID, book.title.c_str(), textWidth, 3, EpdFontFamily::BOLD);
|
auto titleLines = renderer.wrappedText(UI_12_FONT_ID, book.title.c_str(), textWidth, 3, EpdFontFamily::BOLD);
|
||||||
@@ -537,11 +535,28 @@ void LyraTheme::drawEmptyRecents(const GfxRenderer& renderer, const Rect rect) c
|
|||||||
void LyraTheme::drawButtonMenu(GfxRenderer& renderer, Rect rect, int buttonCount, int selectedIndex,
|
void LyraTheme::drawButtonMenu(GfxRenderer& renderer, Rect rect, int buttonCount, int selectedIndex,
|
||||||
const std::function<std::string(int index)>& buttonLabel,
|
const std::function<std::string(int index)>& buttonLabel,
|
||||||
const std::function<UIIcon(int index)>& rowIcon) const {
|
const std::function<UIIcon(int index)>& rowIcon) const {
|
||||||
|
int rowHeight = LyraMetrics::values.menuRowHeight;
|
||||||
|
int rowSpacing = LyraMetrics::values.menuSpacing;
|
||||||
|
if (buttonCount > 0 && rect.height > 0) {
|
||||||
|
const int defaultHeight = buttonCount * rowHeight + std::max(0, buttonCount - 1) * rowSpacing;
|
||||||
|
if (defaultHeight > rect.height) {
|
||||||
|
const int spacingSlots = std::max(1, buttonCount - 1);
|
||||||
|
rowSpacing = std::max(0, (rect.height - buttonCount * rowHeight) / spacingSlots);
|
||||||
|
if (buttonCount * rowHeight + std::max(0, buttonCount - 1) * rowSpacing > rect.height) {
|
||||||
|
rowHeight =
|
||||||
|
std::max(minAdaptiveMenuRowHeight, (rect.height - std::max(0, buttonCount - 1) * rowSpacing) / buttonCount);
|
||||||
|
}
|
||||||
|
if (buttonCount * rowHeight + std::max(0, buttonCount - 1) * rowSpacing > rect.height) {
|
||||||
|
rowHeight = std::max(1, rect.height / buttonCount);
|
||||||
|
rowSpacing = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < buttonCount; ++i) {
|
for (int i = 0; i < buttonCount; ++i) {
|
||||||
int tileWidth = rect.width - LyraMetrics::values.contentSidePadding * 2;
|
int tileWidth = rect.width - LyraMetrics::values.contentSidePadding * 2;
|
||||||
Rect tileRect = Rect{rect.x + LyraMetrics::values.contentSidePadding,
|
Rect tileRect = Rect{rect.x + LyraMetrics::values.contentSidePadding, rect.y + i * (rowHeight + rowSpacing),
|
||||||
rect.y + i * (LyraMetrics::values.menuRowHeight + LyraMetrics::values.menuSpacing), tileWidth,
|
tileWidth, rowHeight};
|
||||||
LyraMetrics::values.menuRowHeight};
|
|
||||||
|
|
||||||
const bool selected = selectedIndex == i;
|
const bool selected = selectedIndex == i;
|
||||||
|
|
||||||
@@ -553,7 +568,7 @@ void LyraTheme::drawButtonMenu(GfxRenderer& renderer, Rect rect, int buttonCount
|
|||||||
const char* label = labelStr.c_str();
|
const char* label = labelStr.c_str();
|
||||||
int textX = tileRect.x + 16;
|
int textX = tileRect.x + 16;
|
||||||
const int lineHeight = renderer.getLineHeight(UI_12_FONT_ID);
|
const int lineHeight = renderer.getLineHeight(UI_12_FONT_ID);
|
||||||
const int textY = tileRect.y + (LyraMetrics::values.menuRowHeight - lineHeight) / 2;
|
const int textY = tileRect.y + (rowHeight - lineHeight) / 2;
|
||||||
|
|
||||||
if (rowIcon != nullptr) {
|
if (rowIcon != nullptr) {
|
||||||
UIIcon icon = rowIcon(i);
|
UIIcon icon = rowIcon(i);
|
||||||
|
|||||||
Reference in New Issue
Block a user