From 2b33d92a0111db4e2c4a6a04fe4ac8282834bca5 Mon Sep 17 00:00:00 2001 From: CaptainFrito Date: Thu, 29 Jan 2026 17:08:33 +0700 Subject: [PATCH] Updated tabs controls --- src/activities/home/MyLibraryActivity.cpp | 2 +- src/activities/settings/SettingsActivity.cpp | 33 ++++++++++------- src/components/UITheme.cpp | 4 +- src/components/UITheme.h | 2 +- src/components/themes/BaseTheme.cpp | 20 ++++++---- src/components/themes/BaseTheme.h | 2 +- src/components/themes/lyra/LyraTheme.cpp | 39 ++++++++++++++------ src/components/themes/lyra/LyraTheme.h | 4 +- 8 files changed, 67 insertions(+), 39 deletions(-) diff --git a/src/activities/home/MyLibraryActivity.cpp b/src/activities/home/MyLibraryActivity.cpp index f211d044..2dcacc22 100644 --- a/src/activities/home/MyLibraryActivity.cpp +++ b/src/activities/home/MyLibraryActivity.cpp @@ -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; diff --git a/src/activities/settings/SettingsActivity.cpp b/src/activities/settings/SettingsActivity.cpp index c3910d9f..206388aa 100644 --- a/src/activities/settings/SettingsActivity.cpp +++ b/src/activities/settings/SettingsActivity.cpp @@ -110,12 +110,19 @@ void SettingsActivity::loop() { subActivity->loop(); return; } - + bool hasChangedCategory = false; + // Handle actions with early return if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { - toggleCurrentSetting(); - updateRequired = true; - return; + 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)) { @@ -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"); diff --git a/src/components/UITheme.cpp b/src/components/UITheme.cpp index 8c790654..dac4de6f 100644 --- a/src/components/UITheme.cpp +++ b/src/components/UITheme.cpp @@ -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& tabs) { +void UITheme::drawTabBar(const GfxRenderer& renderer, const Rect rect, const std::vector& tabs, bool selected) { if (currentTheme != nullptr) { - currentTheme->drawTabBar(renderer, rect, tabs); + currentTheme->drawTabBar(renderer, rect, tabs, selected); } } diff --git a/src/components/UITheme.h b/src/components/UITheme.h index cc43ffb9..1790cb58 100644 --- a/src/components/UITheme.h +++ b/src/components/UITheme.h @@ -81,7 +81,7 @@ class UITheme { const std::function& rowIcon, bool hasValue, const std::function& rowValue); static void drawHeader(const GfxRenderer& renderer, Rect rect, const char* title); - static void drawTabBar(const GfxRenderer& renderer, Rect rect, const std::vector& tabs); + static void drawTabBar(const GfxRenderer& renderer, Rect rect, const std::vector& tabs, bool selected); static void drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std::vector& recentBooks, const int selectorIndex, bool& coverRendered, bool& coverBufferStored, bool& bufferRestored, std::function storeCoverBuffer); diff --git a/src/components/themes/BaseTheme.cpp b/src/components/themes/BaseTheme.cpp index 31ad738e..84b33c65 100644 --- a/src/components/themes/BaseTheme.cpp +++ b/src/components/themes/BaseTheme.cpp @@ -191,7 +191,9 @@ void BaseTheme::drawList(const GfxRenderer& renderer, Rect rect, int itemCount, // Draw selection int contentWidth = rect.width - BaseMetrics::values.sideButtonHintsWidth - 5; - renderer.fillRect(0, rect.y + selectedIndex % pageItems * rowHeight - 2, contentWidth, rowHeight); + 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& tabs) { +void BaseTheme::drawTabBar(const GfxRenderer& renderer, const Rect rect, const std::vector& tabs, bool selected) { constexpr int underlineHeight = 2; // Height of selection underline constexpr int underlineGap = 4; // Gap between text and underline @@ -244,15 +246,19 @@ 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) { - renderer.fillRect(currentX, rect.y + lineHeight + underlineGap, textWidth, underlineHeight); + 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; } } diff --git a/src/components/themes/BaseTheme.h b/src/components/themes/BaseTheme.h index 7ab2a96e..8a739372 100644 --- a/src/components/themes/BaseTheme.h +++ b/src/components/themes/BaseTheme.h @@ -53,7 +53,7 @@ class BaseTheme { const std::function& rowValue); virtual void drawHeader(const GfxRenderer& renderer, Rect rect, const char* title); - virtual void drawTabBar(const GfxRenderer& renderer, Rect rect, const std::vector& tabs); + virtual void drawTabBar(const GfxRenderer& renderer, Rect rect, const std::vector& tabs, bool selected); virtual void drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std::vector& recentBooks, const int selectorIndex, bool& coverRendered, bool& coverBufferStored, bool& bufferRestored, diff --git a/src/components/themes/lyra/LyraTheme.cpp b/src/components/themes/lyra/LyraTheme.cpp index e9a0c078..a726fc6b 100644 --- a/src/components/themes/lyra/LyraTheme.cpp +++ b/src/components/themes/lyra/LyraTheme.cpp @@ -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& tabs) { +void LyraTheme::drawTabBar(const GfxRenderer& renderer, Rect rect, const std::vector& 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); - renderer.fillRoundedRect(LyraMetrics::values.contentSidePadding, rect.y + selectedIndex % pageItems * rowHeight, + 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 + const int x = buttonPositions[i]; + renderer.fillRect(x, pageHeight - buttonY, buttonWidth, buttonHeight, false); if (labels[i] != nullptr && labels[i][0] != '\0') { - const int x = buttonPositions[i]; - renderer.fillRect(x, pageHeight - buttonY, buttonWidth, buttonHeight, false); 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}; diff --git a/src/components/themes/lyra/LyraTheme.h b/src/components/themes/lyra/LyraTheme.h index 22fad551..3fad82e4 100644 --- a/src/components/themes/lyra/LyraTheme.h +++ b/src/components/themes/lyra/LyraTheme.h @@ -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& tabs) override; + void drawTabBar(const GfxRenderer& renderer, Rect rect, const std::vector& tabs, bool selected) override; void drawList(const GfxRenderer& renderer, Rect rect, int itemCount, int selectedIndex, const std::function& rowTitle, bool hasIcon, const std::function& rowIcon, bool hasValue,