Compare commits

...

2 Commits

Author SHA1 Message Date
CaptainFrito
3ea0878189
Merge 2b33d92a01 into da4d3b5ea5 2026-01-29 17:08:46 +07:00
CaptainFrito
2b33d92a01 Updated tabs controls 2026-01-29 17:08:33 +07:00
8 changed files with 67 additions and 39 deletions

View File

@ -233,7 +233,7 @@ void MyLibraryActivity::render() const {
UITheme::drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, folderName);
UITheme::drawTabBar(renderer, Rect{0, metrics.topPadding + metrics.headerHeight, pageWidth, metrics.tabBarHeight},
{{"Recent", currentTab == Tab::Recent}, {"Files", currentTab == Tab::Files}});
{{"Recent", currentTab == Tab::Recent}, {"Files", currentTab == Tab::Files}}, false);
const int contentTop = metrics.topPadding + metrics.headerHeight + metrics.tabBarHeight + metrics.verticalSpacing;
const int contentHeight = pageHeight - contentTop - metrics.buttonHintsHeight - metrics.verticalSpacing * 2;

View File

@ -110,13 +110,20 @@ void SettingsActivity::loop() {
subActivity->loop();
return;
}
bool hasChangedCategory = false;
// Handle actions with early return
if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) {
if (selectedSettingIndex == 0) {
selectedCategoryIndex = (selectedCategoryIndex < categoryCount - 1) ? (selectedCategoryIndex + 1) : 0;
hasChangedCategory = true;
updateRequired = true;
} else {
toggleCurrentSetting();
updateRequired = true;
return;
}
}
if (mappedInput.wasPressed(MappedInputManager::Button::Back)) {
SETTINGS.saveToFile();
@ -124,14 +131,13 @@ void SettingsActivity::loop() {
return;
}
bool hasChangedCategory = false;
// Handle navigation
if (mappedInput.wasPressed(MappedInputManager::Button::Left)) {
selectedSettingIndex = (selectedSettingIndex > 0) ? (selectedSettingIndex - 1) : (settingsCount - 1);
selectedSettingIndex = (selectedSettingIndex > 0) ? (selectedSettingIndex - 1) : (settingsCount);
updateRequired = true;
} else if (mappedInput.wasPressed(MappedInputManager::Button::Right)) {
selectedSettingIndex = (selectedSettingIndex < settingsCount - 1) ? (selectedSettingIndex + 1) : 0;
selectedSettingIndex = (selectedSettingIndex < settingsCount) ? (selectedSettingIndex + 1) : 0;
updateRequired = true;
} else if (mappedInput.wasPressed(MappedInputManager::Button::Up)) {
hasChangedCategory = true;
@ -144,7 +150,7 @@ void SettingsActivity::loop() {
}
if (hasChangedCategory) {
selectedSettingIndex = 0;
selectedSettingIndex = (selectedSettingIndex == 0) ? 0 : 1;
switch (selectedCategoryIndex) {
case 0: // Display
settingsList = displaySettings;
@ -167,11 +173,12 @@ void SettingsActivity::loop() {
}
void SettingsActivity::toggleCurrentSetting() {
if (selectedSettingIndex < 0 || selectedSettingIndex >= settingsCount) {
int selectedSetting = selectedSettingIndex - 1;
if (selectedSetting < 0 || selectedSetting >= settingsCount) {
return;
}
const auto& setting = settingsList[selectedSettingIndex];
const auto& setting = settingsList[selectedSetting];
if (setting.type == SettingType::TOGGLE && setting.valuePtr != nullptr) {
// Toggle the boolean value using the member pointer
@ -256,14 +263,14 @@ void SettingsActivity::render() const {
tabs.push_back({categoryNames[i], selectedCategoryIndex == i});
}
UITheme::drawTabBar(renderer, Rect{0, metrics.topPadding + metrics.headerHeight, pageWidth, metrics.tabBarHeight},
tabs);
tabs, selectedSettingIndex == 0);
UITheme::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)},
settingsCount, selectedSettingIndex, [this](int index) { return std::string(settingsList[index].name); }, false,
settingsCount, selectedSettingIndex - 1, [this](int index) { return std::string(settingsList[index].name); }, false,
nullptr, true,
[this](int i) {
const auto& setting = settingsList[i];
@ -286,7 +293,7 @@ void SettingsActivity::render() const {
metrics.versionTextY, CROSSPOINT_VERSION);
// Draw help text
const auto labels = mappedInput.mapLabels("« Back", "Select", "Up", "Down");
const auto labels = mappedInput.mapLabels("« Back", selectedSettingIndex == 0 ? "Tab >" : "Toggle", "Up", "Down");
UITheme::drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
UITheme::drawSideButtonHints(renderer, "^", "v");

View File

@ -89,9 +89,9 @@ void UITheme::drawHeader(const GfxRenderer& renderer, Rect rect, const char* tit
}
}
void UITheme::drawTabBar(const GfxRenderer& renderer, const Rect rect, const std::vector<TabInfo>& tabs) {
void UITheme::drawTabBar(const GfxRenderer& renderer, const Rect rect, const std::vector<TabInfo>& tabs, bool selected) {
if (currentTheme != nullptr) {
currentTheme->drawTabBar(renderer, rect, tabs);
currentTheme->drawTabBar(renderer, rect, tabs, selected);
}
}

View File

@ -81,7 +81,7 @@ class UITheme {
const std::function<std::string(int index)>& rowIcon, bool hasValue,
const std::function<std::string(int index)>& rowValue);
static void drawHeader(const GfxRenderer& renderer, Rect rect, const char* title);
static void drawTabBar(const GfxRenderer& renderer, Rect rect, const std::vector<TabInfo>& tabs);
static void drawTabBar(const GfxRenderer& renderer, Rect rect, const std::vector<TabInfo>& tabs, bool selected);
static void drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std::vector<RecentBookWithCover>& recentBooks,
const int selectorIndex, bool& coverRendered, bool& coverBufferStored,
bool& bufferRestored, std::function<bool()> storeCoverBuffer);

View File

@ -191,7 +191,9 @@ void BaseTheme::drawList(const GfxRenderer& renderer, Rect rect, int itemCount,
// Draw selection
int contentWidth = rect.width - BaseMetrics::values.sideButtonHintsWidth - 5;
if (selectedIndex >= 0) {
renderer.fillRect(0, rect.y + selectedIndex % pageItems * rowHeight - 2, contentWidth, rowHeight);
}
// Draw all items
const auto pageStartIndex = selectedIndex / pageItems * pageItems;
for (int i = pageStartIndex; i < itemCount && i < pageStartIndex + pageItems; i++) {
@ -232,7 +234,7 @@ void BaseTheme::drawHeader(const GfxRenderer& renderer, Rect rect, const char* t
}
}
void BaseTheme::drawTabBar(const GfxRenderer& renderer, const Rect rect, const std::vector<TabInfo>& tabs) {
void BaseTheme::drawTabBar(const GfxRenderer& renderer, const Rect rect, const std::vector<TabInfo>& tabs, bool selected) {
constexpr int underlineHeight = 2; // Height of selection underline
constexpr int underlineGap = 4; // Gap between text and underline
@ -244,14 +246,18 @@ void BaseTheme::drawTabBar(const GfxRenderer& renderer, const Rect rect, const s
const int textWidth =
renderer.getTextWidth(UI_12_FONT_ID, tab.label, tab.selected ? EpdFontFamily::BOLD : EpdFontFamily::REGULAR);
// Draw tab label
renderer.drawText(UI_12_FONT_ID, currentX, rect.y, tab.label, true,
tab.selected ? EpdFontFamily::BOLD : EpdFontFamily::REGULAR);
// Draw underline for selected tab
if (tab.selected) {
if (selected) {
renderer.fillRect(currentX - 3, rect.y, textWidth + 6, lineHeight + underlineGap);
} else {
renderer.fillRect(currentX, rect.y + lineHeight + underlineGap, textWidth, underlineHeight);
}
}
// Draw tab label
renderer.drawText(UI_12_FONT_ID, currentX, rect.y, tab.label, !(tab.selected && selected),
tab.selected ? EpdFontFamily::BOLD : EpdFontFamily::REGULAR);
currentX += textWidth + BaseMetrics::values.tabSpacing;
}

View File

@ -53,7 +53,7 @@ class BaseTheme {
const std::function<std::string(int index)>& rowValue);
virtual void drawHeader(const GfxRenderer& renderer, Rect rect, const char* title);
virtual void drawTabBar(const GfxRenderer& renderer, Rect rect, const std::vector<TabInfo>& tabs);
virtual void drawTabBar(const GfxRenderer& renderer, Rect rect, const std::vector<TabInfo>& tabs, bool selected);
virtual void drawRecentBookCover(GfxRenderer& renderer, Rect rect,
const std::vector<RecentBookWithCover>& recentBooks, const int selectorIndex,
bool& coverRendered, bool& coverBufferStored, bool& bufferRestored,

View File

@ -78,21 +78,30 @@ void LyraTheme::drawHeader(const GfxRenderer& renderer, Rect rect, const char* t
}
}
void LyraTheme::drawTabBar(const GfxRenderer& renderer, Rect rect, const std::vector<TabInfo>& tabs) {
void LyraTheme::drawTabBar(const GfxRenderer& renderer, Rect rect, const std::vector<TabInfo>& tabs, bool selected) {
int currentX = rect.x + LyraMetrics::values.contentSidePadding;
if (selected) {
renderer.fillRectDither(rect.x, rect.y, rect.width, rect.height, COLOR_LIGHT_GRAY);
}
for (const auto& tab : tabs) {
const int textWidth = renderer.getTextWidth(UI_10_FONT_ID, tab.label, EpdFontFamily::REGULAR);
// Draw tab label
renderer.drawText(UI_10_FONT_ID, currentX, rect.y + 6, tab.label, true, EpdFontFamily::REGULAR);
// Draw underline for selected tab
if (tab.selected) {
renderer.drawLine(currentX, rect.y + rect.height - 2, currentX + textWidth, rect.y + rect.height - 2, true);
if (selected) {
renderer.fillRoundedRect(currentX, rect.y + 1, textWidth + 2 * hPaddingInSelection, rect.height - 4,
cornerRadius, COLOR_BLACK);
} else {
renderer.fillRectDither(currentX, rect.y, textWidth + 2 * hPaddingInSelection, rect.height - 3, COLOR_LIGHT_GRAY);
renderer.drawLine(currentX, rect.y + rect.height - 3, currentX + textWidth + 2 * hPaddingInSelection, rect.y + rect.height - 3, 2, true);
}
}
currentX += textWidth + LyraMetrics::values.tabSpacing;
renderer.drawText(UI_10_FONT_ID, currentX + hPaddingInSelection, rect.y + 6, tab.label, !(tab.selected && selected), EpdFontFamily::REGULAR);
currentX += textWidth + LyraMetrics::values.tabSpacing + 2 * hPaddingInSelection;
}
renderer.drawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width, rect.y + rect.height - 1, true);
@ -123,9 +132,11 @@ void LyraTheme::drawList(const GfxRenderer& renderer, Rect rect, int itemCount,
int contentWidth =
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_LIGHT_GRAY);
}
// Draw all items
const auto pageStartIndex = selectedIndex / pageItems * pageItems;
@ -169,22 +180,26 @@ void LyraTheme::drawButtonHints(const GfxRenderer& renderer, const char* btn1, c
const int pageHeight = renderer.getScreenHeight();
constexpr int buttonWidth = 80;
constexpr int smallButtonHeight = 15;
constexpr int buttonHeight = LyraMetrics::values.buttonHintsHeight;
constexpr int buttonY = LyraMetrics::values.buttonHintsHeight; // Distance from bottom
constexpr int textYOffset = 7; // Distance from top of button to text baseline
constexpr int buttonPositions[] = {68, 156, 244, 332};
constexpr int buttonPositions[] = {58, 146, 254, 342};
const char* labels[] = {btn1, btn2, btn3, btn4};
for (int i = 0; i < 4; i++) {
// Only draw if the label is non-empty
if (labels[i] != nullptr && labels[i][0] != '\0') {
const int x = buttonPositions[i];
renderer.fillRect(x, pageHeight - buttonY, buttonWidth, buttonHeight, false);
if (labels[i] != nullptr && labels[i][0] != '\0') {
renderer.drawRoundedRect(x, pageHeight - buttonY, buttonWidth, buttonHeight, 1, cornerRadius, true, true, false,
false, true);
const int textWidth = renderer.getTextWidth(SMALL_FONT_ID, labels[i]);
const int textX = x + (buttonWidth - 1 - textWidth) / 2;
renderer.drawText(SMALL_FONT_ID, textX, pageHeight - buttonY + textYOffset, labels[i]);
} else {
renderer.drawRoundedRect(x, pageHeight - smallButtonHeight, buttonWidth, smallButtonHeight, 1, cornerRadius, true, true, false,
false, true);
}
}
@ -194,7 +209,7 @@ void LyraTheme::drawButtonHints(const GfxRenderer& renderer, const char* btn1, c
void LyraTheme::drawSideButtonHints(const GfxRenderer& renderer, const char* topBtn, const char* bottomBtn) {
const int screenWidth = renderer.getScreenWidth();
constexpr int buttonWidth = LyraMetrics::values.sideButtonHintsWidth; // Width on screen (height when rotated)
constexpr int buttonHeight = 80; // Height on screen (width when rotated)
constexpr int buttonHeight = 78; // Height on screen (width when rotated)
// Position for the button group - buttons share a border so they're adjacent
const char* labels[] = {topBtn, bottomBtn};

View File

@ -16,7 +16,7 @@ constexpr ThemeMetrics values = {.batteryWidth = 16,
.listRowHeight = 40,
.menuRowHeight = 64,
.menuSpacing = 8,
.tabSpacing = 20,
.tabSpacing = 8,
.tabBarHeight = 40,
.scrollBarWidth = 4,
.scrollBarRightOffset = 5,
@ -36,7 +36,7 @@ class LyraTheme : public BaseTheme {
// void drawProgressBar(const GfxRenderer& renderer, Rect rect, size_t current, size_t total) override;
void drawBattery(const GfxRenderer& renderer, Rect rect, bool showPercentage = true) override;
void drawHeader(const GfxRenderer& renderer, Rect rect, const char* title) override;
void drawTabBar(const GfxRenderer& renderer, Rect rect, const std::vector<TabInfo>& tabs) override;
void drawTabBar(const GfxRenderer& renderer, Rect rect, const std::vector<TabInfo>& tabs, bool selected) override;
void drawList(const GfxRenderer& renderer, Rect rect, int itemCount, int selectedIndex,
const std::function<std::string(int index)>& rowTitle, bool hasIcon,
const std::function<std::string(int index)>& rowIcon, bool hasValue,