Files
Crosspoint/src/activities/reader/ReaderUtils.h
T
Justin Mitchell cef0d267b7 Clarify touch gesture and input API comments
Simplify and clarify documentation for touch gesture detection (back gesture, item taps, long-press) and board detection flags. No functional changes, just improved comment readability.
2026-06-15 19:42:09 -04:00

146 lines
5.4 KiB
C++

#pragma once
#include <CrossPointSettings.h>
#include <GfxRenderer.h>
#include <HalGPIO.h>
#include <HalTiltSensor.h>
#include <Logging.h>
#include "MappedInputManager.h"
namespace ReaderUtils {
constexpr unsigned long GO_HOME_MS = 1000;
constexpr unsigned long SKIP_HOLD_MS = 700;
constexpr unsigned long BOOKMARK_HOLD_MS = 400;
constexpr unsigned long BOOKMARK_MESSAGE_DURATION_MS = 2500;
// Press-and-hold in the center touch zone (see detectTouchPageTurn) opens the
// reader menu, the touch analogue of releasing the Confirm button.
constexpr unsigned long TOUCH_MENU_HOLD_MS = 400;
inline void applyOrientation(GfxRenderer& renderer, const uint8_t orientation) {
switch (orientation) {
case CrossPointSettings::ORIENTATION::PORTRAIT:
renderer.setOrientation(GfxRenderer::Orientation::Portrait);
break;
case CrossPointSettings::ORIENTATION::LANDSCAPE_CW:
renderer.setOrientation(GfxRenderer::Orientation::LandscapeClockwise);
break;
case CrossPointSettings::ORIENTATION::INVERTED:
renderer.setOrientation(GfxRenderer::Orientation::PortraitInverted);
break;
case CrossPointSettings::ORIENTATION::LANDSCAPE_CCW:
renderer.setOrientation(GfxRenderer::Orientation::LandscapeCounterClockwise);
break;
default:
break;
}
}
struct PageTurnResult {
bool prev;
bool next;
bool fromTilt;
};
inline PageTurnResult detectPageTurn(const MappedInputManager& input) {
const bool usePress = SETTINGS.longPressButtonBehavior == SETTINGS.OFF;
const bool tiltNext = SETTINGS.tiltPageTurn && halTiltSensor.wasTiltedForward();
const bool tiltPrev = SETTINGS.tiltPageTurn && halTiltSensor.wasTiltedBack();
const bool swapFront =
SETTINGS.frontButtonFollowOrientation && (SETTINGS.orientation == CrossPointSettings::INVERTED ||
SETTINGS.orientation == CrossPointSettings::LANDSCAPE_CCW);
const auto prevButton = swapFront ? MappedInputManager::Button::Right : MappedInputManager::Button::Left;
const auto nextButton = swapFront ? MappedInputManager::Button::Left : MappedInputManager::Button::Right;
const bool prev =
tiltPrev ||
(usePress ? (input.wasPressed(MappedInputManager::Button::PageBack) || input.wasPressed(prevButton))
: (input.wasReleased(MappedInputManager::Button::PageBack) || input.wasReleased(prevButton)));
const bool powerTurn = SETTINGS.shortPwrBtn == CrossPointSettings::SHORT_PWRBTN::PAGE_TURN &&
input.wasReleased(MappedInputManager::Button::Power);
const bool next = tiltNext || (usePress ? (input.wasPressed(MappedInputManager::Button::PageForward) || powerTurn ||
input.wasPressed(nextButton))
: (input.wasReleased(MappedInputManager::Button::PageForward) || powerTurn ||
input.wasReleased(nextButton)));
return {prev, next, tiltPrev || tiltNext};
}
// Touch reader controls: left third = page back, right third = forward, center =
// open menu on press-and-hold (see isTouchMenuGesture). heldMs is the contact
// duration, for the same long-press behavior as the buttons (chapter skip).
// All-false on Xteink (no touch) or when the setting is off.
struct TouchPageTurn {
bool prev;
bool next;
bool center;
unsigned long heldMs;
};
inline TouchPageTurn detectTouchPageTurn(GfxRenderer& renderer) {
TouchPageTurn result{false, false, false, 0};
if (gpio.isXteinkDevice() || !SETTINGS.touchReaderControls) {
return result;
}
float nx = 0.0f, ny = 0.0f;
if (!gpio.wasTouchTap(nx, ny)) {
return result;
}
int lx = 0, ly = 0;
renderer.tapToLogical(nx, ny, lx, ly);
const int third = renderer.getScreenWidth() / 3;
if (lx < third) {
result.prev = true;
} else if (lx >= 2 * third) {
result.next = true;
} else {
result.center = true;
}
result.heldMs = gpio.lastTouchHeldMs();
return result;
}
// True when the center zone was pressed and held long enough to open the reader
// menu (touch analogue of a Confirm release).
inline bool isTouchMenuGesture(const TouchPageTurn& touch) {
return touch.center && touch.heldMs >= TOUCH_MENU_HOLD_MS;
}
inline void displayWithRefreshCycle(const GfxRenderer& renderer, int& pagesUntilFullRefresh) {
if (pagesUntilFullRefresh <= 1) {
renderer.displayBuffer(HalDisplay::HALF_REFRESH);
pagesUntilFullRefresh = SETTINGS.getRefreshFrequency();
} else {
renderer.displayBuffer();
pagesUntilFullRefresh--;
}
}
// Grayscale anti-aliasing pass. Renders content twice (LSB + MSB) to build
// the grayscale buffer. Only the content callback is re-rendered — status bars
// and other overlays should be drawn before calling this.
// Kept as a template to avoid std::function overhead; instantiated once per reader type.
template <typename RenderFn>
void renderAntiAliased(GfxRenderer& renderer, RenderFn&& renderFn) {
if (!renderer.storeBwBuffer()) {
LOG_ERR("READER", "Failed to store BW buffer for anti-aliasing");
return;
}
renderer.clearScreen(0x00);
renderer.setRenderMode(GfxRenderer::GRAYSCALE_LSB);
renderFn();
renderer.copyGrayscaleLsbBuffers();
renderer.clearScreen(0x00);
renderer.setRenderMode(GfxRenderer::GRAYSCALE_MSB);
renderFn();
renderer.copyGrayscaleMsbBuffers();
renderer.displayGrayBuffer();
renderer.setRenderMode(GfxRenderer::BW);
renderer.restoreBwBuffer();
}
} // namespace ReaderUtils