mirror of
https://github.com/daveallie/crosspoint-reader.git
synced 2026-02-04 14:47:37 +03:00
feat: Add percent selection feature for jumping within the book
This commit is contained in:
parent
e5c0ddc9fa
commit
606b20d9d0
@ -5,12 +5,14 @@
|
|||||||
#include <GfxRenderer.h>
|
#include <GfxRenderer.h>
|
||||||
#include <SDCardManager.h>
|
#include <SDCardManager.h>
|
||||||
|
|
||||||
|
|
||||||
#include "CrossPointSettings.h"
|
#include "CrossPointSettings.h"
|
||||||
#include "CrossPointState.h"
|
#include "CrossPointState.h"
|
||||||
#include "EpubReaderChapterSelectionActivity.h"
|
#include "EpubReaderChapterSelectionActivity.h"
|
||||||
#include "MappedInputManager.h"
|
#include "MappedInputManager.h"
|
||||||
#include "RecentBooksStore.h"
|
#include "RecentBooksStore.h"
|
||||||
#include "ScreenComponents.h"
|
#include "ScreenComponents.h"
|
||||||
|
#include "activities/reader/EpubReaderPercentSelectionActivity.h"
|
||||||
#include "fontIds.h"
|
#include "fontIds.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -22,6 +24,17 @@ constexpr int progressBarMarginTop = 1;
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
// Clamp any percent-like value into the valid 0-100 range.
|
||||||
|
static int clampPercent(const int value) {
|
||||||
|
if (value < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (value > 100) {
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
void EpubReaderActivity::taskTrampoline(void* param) {
|
void EpubReaderActivity::taskTrampoline(void* param) {
|
||||||
auto* self = static_cast<EpubReaderActivity*>(param);
|
auto* self = static_cast<EpubReaderActivity*>(param);
|
||||||
self->displayTaskLoop();
|
self->displayTaskLoop();
|
||||||
@ -123,7 +136,19 @@ void EpubReaderActivity::loop() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enter chapter selection activity
|
// Enter reader menu activity (suppressed after slider confirm/cancel).
|
||||||
|
if (suppressMenuOpenOnce) {
|
||||||
|
// If we're seeing the confirm release that closed the slider, consume it and return.
|
||||||
|
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
||||||
|
suppressMenuOpenOnce = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// If confirm is no longer pressed and no release is pending, clear suppression.
|
||||||
|
if (!mappedInput.isPressed(MappedInputManager::Button::Confirm)) {
|
||||||
|
suppressMenuOpenOnce = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
||||||
// Don't start activity transition while rendering
|
// Don't start activity transition while rendering
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
@ -225,6 +250,85 @@ void EpubReaderActivity::onReaderMenuBack() {
|
|||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Translate an absolute percent into a spine index plus a normalized position
|
||||||
|
// within that spine so we can jump after the section is loaded.
|
||||||
|
void EpubReaderActivity::jumpToPercent(int percent) {
|
||||||
|
if (!epub) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t bookSize = epub->getBookSize();
|
||||||
|
if (bookSize == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize input to 0-100 to avoid invalid jumps.
|
||||||
|
percent = clampPercent(percent);
|
||||||
|
|
||||||
|
// Convert percent into a byte-like absolute position across the spine sizes.
|
||||||
|
size_t targetSize = (bookSize * static_cast<size_t>(percent)) / 100;
|
||||||
|
if (percent >= 100 && bookSize > 0) {
|
||||||
|
// Ensure the final percent lands inside the last spine item.
|
||||||
|
targetSize = bookSize - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int spineCount = epub->getSpineItemsCount();
|
||||||
|
if (spineCount == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int targetSpineIndex = spineCount - 1;
|
||||||
|
size_t prevCumulative = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < spineCount; i++) {
|
||||||
|
const size_t cumulative = epub->getCumulativeSpineItemSize(i);
|
||||||
|
if (targetSize <= cumulative) {
|
||||||
|
// Found the spine item containing the absolute position.
|
||||||
|
targetSpineIndex = i;
|
||||||
|
prevCumulative = (i > 0) ? epub->getCumulativeSpineItemSize(i - 1) : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t cumulative = epub->getCumulativeSpineItemSize(targetSpineIndex);
|
||||||
|
const size_t spineSize = (cumulative > prevCumulative) ? (cumulative - prevCumulative) : 0;
|
||||||
|
// Store a normalized position within the spine so it can be applied once loaded.
|
||||||
|
pendingSpineProgress = (spineSize == 0) ? 0.0f
|
||||||
|
: static_cast<float>(targetSize - prevCumulative) /
|
||||||
|
static_cast<float>(spineSize);
|
||||||
|
if (pendingSpineProgress < 0.0f) {
|
||||||
|
pendingSpineProgress = 0.0f;
|
||||||
|
} else if (pendingSpineProgress > 1.0f) {
|
||||||
|
pendingSpineProgress = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset state so renderScreen() reloads and repositions on the target spine.
|
||||||
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
|
currentSpineIndex = targetSpineIndex;
|
||||||
|
nextPageNumber = 0;
|
||||||
|
pendingPercentJump = true;
|
||||||
|
section.reset();
|
||||||
|
xSemaphoreGive(renderingMutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the overall reading position as a percent of the book.
|
||||||
|
int EpubReaderActivity::getCurrentPercent() const {
|
||||||
|
if (!epub || epub->getBookSize() == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Estimate within-spine progress based on the current page.
|
||||||
|
float chapterProgress = 0.0f;
|
||||||
|
if (section && section->pageCount > 0) {
|
||||||
|
chapterProgress = static_cast<float>(section->currentPage) / static_cast<float>(section->pageCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to overall progress using cumulative spine sizes.
|
||||||
|
const float progress = epub->calculateProgress(currentSpineIndex, chapterProgress);
|
||||||
|
const int percent = static_cast<int>(progress * 100.0f + 0.5f);
|
||||||
|
return clampPercent(percent);
|
||||||
|
}
|
||||||
|
|
||||||
void EpubReaderActivity::onReaderMenuConfirm(EpubReaderMenuActivity::MenuAction action) {
|
void EpubReaderActivity::onReaderMenuConfirm(EpubReaderMenuActivity::MenuAction action) {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case EpubReaderMenuActivity::MenuAction::SELECT_CHAPTER: {
|
case EpubReaderMenuActivity::MenuAction::SELECT_CHAPTER: {
|
||||||
@ -268,6 +372,29 @@ void EpubReaderActivity::onReaderMenuConfirm(EpubReaderMenuActivity::MenuAction
|
|||||||
xSemaphoreGive(renderingMutex);
|
xSemaphoreGive(renderingMutex);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case EpubReaderMenuActivity::MenuAction::GO_TO_PERCENT: {
|
||||||
|
// Launch the slider-based percent selector and return here on confirm/cancel.
|
||||||
|
const int initialPercent = getCurrentPercent();
|
||||||
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
|
exitActivity();
|
||||||
|
enterNewActivity(new EpubReaderPercentSelectionActivity(
|
||||||
|
renderer, mappedInput, initialPercent,
|
||||||
|
[this](const int percent) {
|
||||||
|
// Apply the new position and exit back to the reader.
|
||||||
|
jumpToPercent(percent);
|
||||||
|
suppressMenuOpenOnce = true;
|
||||||
|
exitActivity();
|
||||||
|
updateRequired = true;
|
||||||
|
},
|
||||||
|
[this]() {
|
||||||
|
// Cancel selection and return to the reader.
|
||||||
|
suppressMenuOpenOnce = true;
|
||||||
|
exitActivity();
|
||||||
|
updateRequired = true;
|
||||||
|
}));
|
||||||
|
xSemaphoreGive(renderingMutex);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case EpubReaderMenuActivity::MenuAction::GO_HOME: {
|
case EpubReaderMenuActivity::MenuAction::GO_HOME: {
|
||||||
// 2. Trigger the reader's "Go Home" callback
|
// 2. Trigger the reader's "Go Home" callback
|
||||||
if (onGoHome) {
|
if (onGoHome) {
|
||||||
@ -398,6 +525,18 @@ void EpubReaderActivity::renderScreen() {
|
|||||||
}
|
}
|
||||||
cachedChapterTotalPageCount = 0; // resets to 0 to prevent reading cached progress again
|
cachedChapterTotalPageCount = 0; // resets to 0 to prevent reading cached progress again
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pendingPercentJump && section->pageCount > 0) {
|
||||||
|
// Apply the pending percent jump now that we know the new section's page count.
|
||||||
|
int newPage = static_cast<int>(pendingSpineProgress * static_cast<float>(section->pageCount));
|
||||||
|
if (newPage < 0) {
|
||||||
|
newPage = 0;
|
||||||
|
} else if (newPage >= section->pageCount) {
|
||||||
|
newPage = section->pageCount - 1;
|
||||||
|
}
|
||||||
|
section->currentPage = newPage;
|
||||||
|
pendingPercentJump = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer.clearScreen();
|
renderer.clearScreen();
|
||||||
|
|||||||
@ -18,6 +18,13 @@ class EpubReaderActivity final : public ActivityWithSubactivity {
|
|||||||
int pagesUntilFullRefresh = 0;
|
int pagesUntilFullRefresh = 0;
|
||||||
int cachedSpineIndex = 0;
|
int cachedSpineIndex = 0;
|
||||||
int cachedChapterTotalPageCount = 0;
|
int cachedChapterTotalPageCount = 0;
|
||||||
|
// Signals that the next render should reposition within the newly loaded section
|
||||||
|
// based on a cross-book percentage jump.
|
||||||
|
bool pendingPercentJump = false;
|
||||||
|
// Normalized 0.0-1.0 progress within the target spine item, computed from book percentage.
|
||||||
|
float pendingSpineProgress = 0.0f;
|
||||||
|
// Prevents the reader menu from reopening due to the confirm button used to exit the slider.
|
||||||
|
bool suppressMenuOpenOnce = false;
|
||||||
bool updateRequired = false;
|
bool updateRequired = false;
|
||||||
const std::function<void()> onGoBack;
|
const std::function<void()> onGoBack;
|
||||||
const std::function<void()> onGoHome;
|
const std::function<void()> onGoHome;
|
||||||
@ -29,6 +36,10 @@ class EpubReaderActivity final : public ActivityWithSubactivity {
|
|||||||
int orientedMarginBottom, int orientedMarginLeft);
|
int orientedMarginBottom, int orientedMarginLeft);
|
||||||
void renderStatusBar(int orientedMarginRight, int orientedMarginBottom, int orientedMarginLeft) const;
|
void renderStatusBar(int orientedMarginRight, int orientedMarginBottom, int orientedMarginLeft) const;
|
||||||
void saveProgress(int spineIndex, int currentPage, int pageCount);
|
void saveProgress(int spineIndex, int currentPage, int pageCount);
|
||||||
|
// Jump to a percentage of the book (0-100), mapping it to spine and page.
|
||||||
|
void jumpToPercent(int percent);
|
||||||
|
// Compute the current reading position as an integer percent (0-100).
|
||||||
|
int getCurrentPercent() const;
|
||||||
void onReaderMenuBack();
|
void onReaderMenuBack();
|
||||||
void onReaderMenuConfirm(EpubReaderMenuActivity::MenuAction action);
|
void onReaderMenuConfirm(EpubReaderMenuActivity::MenuAction action);
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,8 @@
|
|||||||
|
|
||||||
class EpubReaderMenuActivity final : public ActivityWithSubactivity {
|
class EpubReaderMenuActivity final : public ActivityWithSubactivity {
|
||||||
public:
|
public:
|
||||||
enum class MenuAction { SELECT_CHAPTER, GO_HOME, DELETE_CACHE };
|
// Menu actions available from the reader menu.
|
||||||
|
enum class MenuAction { SELECT_CHAPTER, GO_TO_PERCENT, GO_HOME, DELETE_CACHE };
|
||||||
|
|
||||||
explicit EpubReaderMenuActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, const std::string& title,
|
explicit EpubReaderMenuActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, const std::string& title,
|
||||||
const std::function<void()>& onBack, const std::function<void(MenuAction)>& onAction)
|
const std::function<void()>& onBack, const std::function<void(MenuAction)>& onAction)
|
||||||
@ -32,7 +33,9 @@ class EpubReaderMenuActivity final : public ActivityWithSubactivity {
|
|||||||
std::string label;
|
std::string label;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Fixed menu layout (order matters for up/down navigation).
|
||||||
const std::vector<MenuItem> menuItems = {{MenuAction::SELECT_CHAPTER, "Go to Chapter"},
|
const std::vector<MenuItem> menuItems = {{MenuAction::SELECT_CHAPTER, "Go to Chapter"},
|
||||||
|
{MenuAction::GO_TO_PERCENT, "Go to %"},
|
||||||
{MenuAction::GO_HOME, "Go Home"},
|
{MenuAction::GO_HOME, "Go Home"},
|
||||||
{MenuAction::DELETE_CACHE, "Delete Book Cache"}};
|
{MenuAction::DELETE_CACHE, "Delete Book Cache"}};
|
||||||
|
|
||||||
|
|||||||
138
src/activities/reader/EpubReaderPercentSelectionActivity.cpp
Normal file
138
src/activities/reader/EpubReaderPercentSelectionActivity.cpp
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
#include "EpubReaderPercentSelectionActivity.h"
|
||||||
|
|
||||||
|
#include <GfxRenderer.h>
|
||||||
|
|
||||||
|
#include "MappedInputManager.h"
|
||||||
|
#include "fontIds.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// Fine/coarse slider step sizes for percent adjustments.
|
||||||
|
constexpr int kSmallStep = 1;
|
||||||
|
constexpr int kLargeStep = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EpubReaderPercentSelectionActivity::onEnter() {
|
||||||
|
ActivityWithSubactivity::onEnter();
|
||||||
|
// Set up rendering task and mark first frame dirty.
|
||||||
|
renderingMutex = xSemaphoreCreateMutex();
|
||||||
|
updateRequired = true;
|
||||||
|
xTaskCreate(&EpubReaderPercentSelectionActivity::taskTrampoline, "EpubPercentSlider", 4096, this, 1,
|
||||||
|
&displayTaskHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EpubReaderPercentSelectionActivity::onExit() {
|
||||||
|
ActivityWithSubactivity::onExit();
|
||||||
|
// Ensure the render task is stopped before freeing the mutex.
|
||||||
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
|
if (displayTaskHandle) {
|
||||||
|
vTaskDelete(displayTaskHandle);
|
||||||
|
displayTaskHandle = nullptr;
|
||||||
|
}
|
||||||
|
vSemaphoreDelete(renderingMutex);
|
||||||
|
renderingMutex = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EpubReaderPercentSelectionActivity::taskTrampoline(void* param) {
|
||||||
|
auto* self = static_cast<EpubReaderPercentSelectionActivity*>(param);
|
||||||
|
self->displayTaskLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EpubReaderPercentSelectionActivity::displayTaskLoop() {
|
||||||
|
while (true) {
|
||||||
|
// Render only when the view is dirty and no subactivity is running.
|
||||||
|
if (updateRequired && !subActivity) {
|
||||||
|
updateRequired = false;
|
||||||
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
|
renderScreen();
|
||||||
|
xSemaphoreGive(renderingMutex);
|
||||||
|
}
|
||||||
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EpubReaderPercentSelectionActivity::adjustPercent(const int delta) {
|
||||||
|
// Apply delta and clamp within 0-100.
|
||||||
|
percent += delta;
|
||||||
|
if (percent < 0) {
|
||||||
|
percent = 0;
|
||||||
|
} else if (percent > 100) {
|
||||||
|
percent = 100;
|
||||||
|
}
|
||||||
|
updateRequired = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EpubReaderPercentSelectionActivity::loop() {
|
||||||
|
if (subActivity) {
|
||||||
|
subActivity->loop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Back cancels, confirm selects, arrows adjust the percent.
|
||||||
|
if (mappedInput.wasReleased(MappedInputManager::Button::Back)) {
|
||||||
|
onCancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
||||||
|
onSelect(percent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mappedInput.wasReleased(MappedInputManager::Button::Left)) {
|
||||||
|
adjustPercent(-kSmallStep);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mappedInput.wasReleased(MappedInputManager::Button::Right)) {
|
||||||
|
adjustPercent(kSmallStep);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mappedInput.wasReleased(MappedInputManager::Button::Up)) {
|
||||||
|
adjustPercent(kLargeStep);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mappedInput.wasReleased(MappedInputManager::Button::Down)) {
|
||||||
|
adjustPercent(-kLargeStep);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EpubReaderPercentSelectionActivity::renderScreen() {
|
||||||
|
renderer.clearScreen();
|
||||||
|
|
||||||
|
// Title and numeric percent value.
|
||||||
|
renderer.drawCenteredText(UI_12_FONT_ID, 15, "Go to Position", true, EpdFontFamily::BOLD);
|
||||||
|
|
||||||
|
const std::string percentText = std::to_string(percent) + "%";
|
||||||
|
renderer.drawCenteredText(UI_12_FONT_ID, 70, percentText.c_str(), true, EpdFontFamily::BOLD);
|
||||||
|
|
||||||
|
// Draw slider track.
|
||||||
|
const int screenWidth = renderer.getScreenWidth();
|
||||||
|
constexpr int barWidth = 360;
|
||||||
|
constexpr int barHeight = 16;
|
||||||
|
const int barX = (screenWidth - barWidth) / 2;
|
||||||
|
const int barY = 120;
|
||||||
|
|
||||||
|
renderer.drawRect(barX, barY, barWidth, barHeight);
|
||||||
|
|
||||||
|
// Fill slider based on percent.
|
||||||
|
const int fillWidth = (barWidth - 4) * percent / 100;
|
||||||
|
if (fillWidth > 0) {
|
||||||
|
renderer.fillRect(barX + 2, barY + 2, fillWidth, barHeight - 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw a simple knob centered at the current percent.
|
||||||
|
const int knobX = barX + 2 + fillWidth - 2;
|
||||||
|
renderer.fillRect(knobX, barY - 4, 4, barHeight + 8, true);
|
||||||
|
|
||||||
|
// Hint text for step sizes.
|
||||||
|
renderer.drawCenteredText(SMALL_FONT_ID, barY + 30, "Left/Right: 1% Up/Down: 10%", true);
|
||||||
|
|
||||||
|
// Button hints follow the current front button layout.
|
||||||
|
const auto labels = mappedInput.mapLabels("« Back", "Select", "-", "+");
|
||||||
|
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||||
|
|
||||||
|
renderer.displayBuffer();
|
||||||
|
}
|
||||||
46
src/activities/reader/EpubReaderPercentSelectionActivity.h
Normal file
46
src/activities/reader/EpubReaderPercentSelectionActivity.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <freertos/FreeRTOS.h>
|
||||||
|
#include <freertos/semphr.h>
|
||||||
|
#include <freertos/task.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include "activities/ActivityWithSubactivity.h"
|
||||||
|
#include "MappedInputManager.h"
|
||||||
|
|
||||||
|
class EpubReaderPercentSelectionActivity final : public ActivityWithSubactivity {
|
||||||
|
public:
|
||||||
|
// Slider-style percent selector for jumping within a book.
|
||||||
|
explicit EpubReaderPercentSelectionActivity(GfxRenderer& renderer, MappedInputManager& mappedInput,
|
||||||
|
const int initialPercent, const std::function<void(int)>& onSelect,
|
||||||
|
const std::function<void()>& onCancel)
|
||||||
|
: ActivityWithSubactivity("EpubReaderPercentSelection", renderer, mappedInput),
|
||||||
|
percent(initialPercent),
|
||||||
|
onSelect(onSelect),
|
||||||
|
onCancel(onCancel) {}
|
||||||
|
|
||||||
|
void onEnter() override;
|
||||||
|
void onExit() override;
|
||||||
|
void loop() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Current percent value (0-100) shown on the slider.
|
||||||
|
int percent = 0;
|
||||||
|
// Render dirty flag for the task loop.
|
||||||
|
bool updateRequired = false;
|
||||||
|
// FreeRTOS task and mutex for rendering.
|
||||||
|
TaskHandle_t displayTaskHandle = nullptr;
|
||||||
|
SemaphoreHandle_t renderingMutex = nullptr;
|
||||||
|
|
||||||
|
// Callback invoked when the user confirms a percent.
|
||||||
|
const std::function<void(int)> onSelect;
|
||||||
|
// Callback invoked when the user cancels the slider.
|
||||||
|
const std::function<void()> onCancel;
|
||||||
|
|
||||||
|
static void taskTrampoline(void* param);
|
||||||
|
[[noreturn]] void displayTaskLoop();
|
||||||
|
// Render the slider UI.
|
||||||
|
void renderScreen();
|
||||||
|
// Change the current percent by a delta and clamp within bounds.
|
||||||
|
void adjustPercent(int delta);
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue
Block a user