Add touch gesture support and LilyGo T5 S3 board
Implements bottom-edge swipe-up gesture detection and delayed touch-select with tracking state. Adds isTouchTapCandidate() to distinguish taps from swipes. Includes LilyGo T5 S3 board configuration with USB CDC logging transport for boards where Serial operator bool reports false incorrectly.
This commit is contained in:
@@ -214,8 +214,6 @@ void FileBrowserActivity::loop() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Touch-down moves the selector to the pressed entry (shows selected state); release
|
||||
// opens it below.
|
||||
int downId = -1;
|
||||
if (mappedInput.wasItemTouchedDown(downId) && downId >= 0 && downId < static_cast<int>(files.size())) {
|
||||
selectorIndex = downId;
|
||||
|
||||
@@ -181,7 +181,7 @@ void HomeActivity::loop() {
|
||||
|
||||
// Tap a menu button to select + activate it. The button menu registers
|
||||
// menu-local ids (drawn with selectorIndex offset by recentBooks.size()), so map
|
||||
// back into the global selector space. Touch-down shows it selected; release opens.
|
||||
// back into the global selector space.
|
||||
int downId = -1;
|
||||
if (mappedInput.wasItemTouchedDown(downId)) {
|
||||
selectorIndex = static_cast<int>(recentBooks.size()) + downId;
|
||||
@@ -274,8 +274,7 @@ void HomeActivity::render(RenderLock&&) {
|
||||
const int menuY = metrics.homeTopPadding + metrics.homeCoverTileHeight + metrics.homeMenuTopOffset;
|
||||
const int bottomReserve = (BaseTheme::showButtonHints() ? metrics.buttonHintsHeight : 0) + metrics.verticalSpacing;
|
||||
GUI.drawButtonMenu(
|
||||
renderer, Rect{0, menuY, pageWidth, pageHeight - menuY - bottomReserve},
|
||||
static_cast<int>(menuItems.size()),
|
||||
renderer, Rect{0, menuY, pageWidth, pageHeight - menuY - bottomReserve}, static_cast<int>(menuItems.size()),
|
||||
metrics.homeContinueReadingInMenu ? selectorIndex : selectorIndex - recentBooks.size(),
|
||||
[&menuItems](int index) { return std::string(menuItems[index]); },
|
||||
[&menuIcons](int index) { return menuIcons[index]; });
|
||||
|
||||
@@ -417,7 +417,7 @@ void WifiSelectionActivity::loop() {
|
||||
requestUpdate();
|
||||
return;
|
||||
}
|
||||
// Touch: down-select highlights the pressed network, tap selects it (like Confirm).
|
||||
// Touch: stable press highlights; tap selects it (like Confirm). Drag/scroll contacts do not preselect a row.
|
||||
int downId = -1;
|
||||
if (mappedInput.wasItemTouchedDown(downId) && downId >= 0 && downId < static_cast<int>(networks.size())) {
|
||||
selectedNetworkIndex = downId;
|
||||
|
||||
@@ -3,11 +3,39 @@
|
||||
#include <GfxRenderer.h>
|
||||
#include <I18n.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "MappedInputManager.h"
|
||||
#include "components/UITheme.h"
|
||||
#include "fontIds.h"
|
||||
|
||||
int EpubReaderChapterSelectionActivity::getTotalItems() const { return epub->getTocItemsCount(); }
|
||||
int EpubReaderChapterSelectionActivity::getTotalItems() const { return epub ? epub->getTocItemsCount() : 0; }
|
||||
|
||||
void EpubReaderChapterSelectionActivity::cancelAndFinish() {
|
||||
ActivityResult result;
|
||||
result.isCancelled = true;
|
||||
setResult(std::move(result));
|
||||
finish();
|
||||
}
|
||||
|
||||
void EpubReaderChapterSelectionActivity::activateSelection(int index) {
|
||||
const int totalItems = getTotalItems();
|
||||
if (!epub || totalItems <= 0) {
|
||||
cancelAndFinish();
|
||||
return;
|
||||
}
|
||||
|
||||
index = std::clamp(index, 0, totalItems - 1);
|
||||
const auto tocItem = epub->getTocItem(index);
|
||||
if (tocItem.spineIndex < 0 || tocItem.spineIndex >= epub->getSpineItemsCount()) {
|
||||
cancelAndFinish();
|
||||
return;
|
||||
}
|
||||
|
||||
selectorIndex = index;
|
||||
setResult(ChapterResult{tocItem.spineIndex, tocItem.anchor});
|
||||
finish();
|
||||
}
|
||||
|
||||
void EpubReaderChapterSelectionActivity::onEnter() {
|
||||
Activity::onEnter();
|
||||
@@ -30,6 +58,12 @@ void EpubReaderChapterSelectionActivity::onExit() { Activity::onExit(); }
|
||||
void EpubReaderChapterSelectionActivity::loop() {
|
||||
const int pageItems = UITheme::getInstance().getNumberOfItemsPerPage(renderer, true, false, true, false);
|
||||
const int totalItems = getTotalItems();
|
||||
if (!epub || totalItems <= 0) {
|
||||
if (mappedInput.wasReleased(MappedInputManager::Button::Back)) {
|
||||
cancelAndFinish();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Vertical swipe page-scrolls the list (touch nav without the side buttons).
|
||||
if (mappedInput.wasListScroll(selectorIndex, totalItems, pageItems)) {
|
||||
@@ -45,23 +79,17 @@ void EpubReaderChapterSelectionActivity::loop() {
|
||||
|
||||
int tappedId = -1;
|
||||
const bool tapped = mappedInput.wasItemTapped(tappedId);
|
||||
if (tapped && tappedId >= 0 && tappedId < totalItems) selectorIndex = tappedId;
|
||||
if (tapped || mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
||||
const auto tocItem = epub->getTocItem(selectorIndex);
|
||||
if (tocItem.spineIndex == -1) {
|
||||
ActivityResult result;
|
||||
result.isCancelled = true;
|
||||
setResult(std::move(result));
|
||||
finish();
|
||||
} else {
|
||||
setResult(ChapterResult{tocItem.spineIndex, tocItem.anchor});
|
||||
finish();
|
||||
}
|
||||
const bool validTap = tapped && tappedId >= 0 && tappedId < totalItems;
|
||||
const bool confirm = mappedInput.wasReleased(MappedInputManager::Button::Confirm);
|
||||
if (validTap) {
|
||||
selectorIndex = tappedId;
|
||||
}
|
||||
if (validTap || confirm) {
|
||||
activateSelection(selectorIndex);
|
||||
return;
|
||||
} else if (mappedInput.wasReleased(MappedInputManager::Button::Back)) {
|
||||
ActivityResult result;
|
||||
result.isCancelled = true;
|
||||
setResult(std::move(result));
|
||||
finish();
|
||||
cancelAndFinish();
|
||||
return;
|
||||
}
|
||||
|
||||
buttonNavigator.onNextRelease([this, totalItems] {
|
||||
@@ -98,10 +126,12 @@ void EpubReaderChapterSelectionActivity::render(RenderLock&&) {
|
||||
const int contentHeight = screen.height - contentTop - metrics.verticalSpacing;
|
||||
|
||||
const int totalItems = getTotalItems();
|
||||
GUI.drawList(renderer, Rect{screen.x, contentTop, screen.width, contentHeight}, totalItems, selectorIndex,
|
||||
const int displayIndex = totalItems > 0 ? std::clamp(selectorIndex, 0, totalItems - 1) : 0;
|
||||
GUI.drawList(renderer, Rect{screen.x, contentTop, screen.width, contentHeight}, totalItems, displayIndex,
|
||||
[this](int index) {
|
||||
auto item = epub->getTocItem(index);
|
||||
std::string indent((item.level - 1) * 2, ' ');
|
||||
const int level = item.level > 0 ? item.level - 1 : 0;
|
||||
std::string indent(level * 2, ' ');
|
||||
return indent + item.title;
|
||||
});
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ class EpubReaderChapterSelectionActivity final : public Activity {
|
||||
|
||||
// Total TOC items count
|
||||
int getTotalItems() const;
|
||||
void cancelAndFinish();
|
||||
void activateSelection(int index);
|
||||
|
||||
public:
|
||||
explicit EpubReaderChapterSelectionActivity(GfxRenderer& renderer, MappedInputManager& mappedInput,
|
||||
|
||||
@@ -64,8 +64,6 @@ void EpubReaderMenuActivity::loop() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Touch-down moves the selection to the pressed item (shows selected state), like
|
||||
// moving with Up/Down; release activates it below.
|
||||
int downId = -1;
|
||||
if (mappedInput.wasItemTouchedDown(downId) && downId >= 0 && downId < static_cast<int>(menuItems.size())) {
|
||||
selectedIndex = downId;
|
||||
|
||||
@@ -133,15 +133,14 @@ void SettingsActivity::loop() {
|
||||
} else if (swipe == MappedInputManager::SwipeDir::Up || swipe == MappedInputManager::SwipeDir::Down) {
|
||||
// Vertical swipe page-scrolls the list (touch nav without the side buttons).
|
||||
// count is settingsCount + 1 because row 0 is the category tab bar.
|
||||
const int page = std::max(
|
||||
1, UITheme::getNumberOfItemsPerPage(renderer, true, true, BaseTheme::showButtonHints(), false));
|
||||
const int page =
|
||||
std::max(1, UITheme::getNumberOfItemsPerPage(renderer, true, true, BaseTheme::showButtonHints(), false));
|
||||
mappedInput.wasListScroll(selectedSettingIndex, settingsCount + 1, page);
|
||||
requestUpdate();
|
||||
}
|
||||
|
||||
// Tap a settings row to select + activate it. Row 0 is the tab bar, so the list
|
||||
// is drawn at selectedSettingIndex - 1; map the tapped row back by +1. Touch-down
|
||||
// shows it selected; release toggles/activates below.
|
||||
// is drawn at selectedSettingIndex - 1; map the tapped row back by +1.
|
||||
int downId = -1;
|
||||
if (!swiped && mappedInput.wasItemTouchedDown(downId) && downId >= 0 && downId < settingsCount) {
|
||||
selectedSettingIndex = downId + 1;
|
||||
|
||||
Reference in New Issue
Block a user