Add home screen (#42)
## Summary * Add home screen * Sits as new root screen, allows for navigation to settings or file list
This commit is contained in:
@@ -98,7 +98,7 @@ void EpubReaderScreen::handleInput() {
|
||||
}
|
||||
|
||||
if (inputManager.wasPressed(InputManager::BTN_BACK)) {
|
||||
onGoHome();
|
||||
onGoBack();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ class EpubReaderScreen final : public Screen {
|
||||
int nextPageNumber = 0;
|
||||
int pagesUntilFullRefresh = 0;
|
||||
bool updateRequired = false;
|
||||
const std::function<void()> onGoHome;
|
||||
const std::function<void()> onGoBack;
|
||||
|
||||
static void taskTrampoline(void* param);
|
||||
[[noreturn]] void displayTaskLoop();
|
||||
@@ -27,8 +27,8 @@ class EpubReaderScreen final : public Screen {
|
||||
|
||||
public:
|
||||
explicit EpubReaderScreen(GfxRenderer& renderer, InputManager& inputManager, std::unique_ptr<Epub> epub,
|
||||
const std::function<void()>& onGoHome)
|
||||
: Screen(renderer, inputManager), epub(std::move(epub)), onGoHome(onGoHome) {}
|
||||
const std::function<void()>& onGoBack)
|
||||
: Screen(renderer, inputManager), epub(std::move(epub)), onGoBack(onGoBack) {}
|
||||
void onEnter() override;
|
||||
void onExit() override;
|
||||
void handleInput() override;
|
||||
|
||||
@@ -98,8 +98,8 @@ void FileSelectionScreen::handleInput() {
|
||||
loadFiles();
|
||||
updateRequired = true;
|
||||
} else {
|
||||
// At root level, go to settings
|
||||
onSettingsOpen();
|
||||
// At root level, go back home
|
||||
onGoHome();
|
||||
}
|
||||
} else if (prevPressed) {
|
||||
selectorIndex = (selectorIndex + files.size() - 1) % files.size();
|
||||
@@ -129,7 +129,7 @@ void FileSelectionScreen::render() const {
|
||||
renderer.drawCenteredText(READER_FONT_ID, 10, "CrossPoint Reader", true, BOLD);
|
||||
|
||||
// Help text
|
||||
renderer.drawText(SMALL_FONT_ID, 20, GfxRenderer::getScreenHeight() - 30, "Press BACK for Settings");
|
||||
renderer.drawText(SMALL_FONT_ID, 20, GfxRenderer::getScreenHeight() - 30, "Press BACK for Home");
|
||||
|
||||
if (files.empty()) {
|
||||
renderer.drawText(UI_FONT_ID, 20, 60, "No EPUBs found");
|
||||
|
||||
@@ -17,7 +17,7 @@ class FileSelectionScreen final : public Screen {
|
||||
int selectorIndex = 0;
|
||||
bool updateRequired = false;
|
||||
const std::function<void(const std::string&)> onSelect;
|
||||
const std::function<void()> onSettingsOpen;
|
||||
const std::function<void()> onGoHome;
|
||||
|
||||
static void taskTrampoline(void* param);
|
||||
[[noreturn]] void displayTaskLoop();
|
||||
@@ -27,8 +27,8 @@ class FileSelectionScreen final : public Screen {
|
||||
public:
|
||||
explicit FileSelectionScreen(GfxRenderer& renderer, InputManager& inputManager,
|
||||
const std::function<void(const std::string&)>& onSelect,
|
||||
const std::function<void()>& onSettingsOpen)
|
||||
: Screen(renderer, inputManager), onSelect(onSelect), onSettingsOpen(onSettingsOpen) {}
|
||||
const std::function<void()>& onGoHome)
|
||||
: Screen(renderer, inputManager), onSelect(onSelect), onGoHome(onGoHome) {}
|
||||
void onEnter() override;
|
||||
void onExit() override;
|
||||
void handleInput() override;
|
||||
|
||||
99
src/screens/HomeScreen.cpp
Normal file
99
src/screens/HomeScreen.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
#include "HomeScreen.h"
|
||||
|
||||
#include <GfxRenderer.h>
|
||||
#include <SD.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
void HomeScreen::taskTrampoline(void* param) {
|
||||
auto* self = static_cast<HomeScreen*>(param);
|
||||
self->displayTaskLoop();
|
||||
}
|
||||
|
||||
void HomeScreen::onEnter() {
|
||||
renderingMutex = xSemaphoreCreateMutex();
|
||||
|
||||
selectorIndex = 0;
|
||||
|
||||
// Trigger first update
|
||||
updateRequired = true;
|
||||
|
||||
xTaskCreate(&HomeScreen::taskTrampoline, "HomeScreenTask",
|
||||
2048, // Stack size
|
||||
this, // Parameters
|
||||
1, // Priority
|
||||
&displayTaskHandle // Task handle
|
||||
);
|
||||
}
|
||||
|
||||
void HomeScreen::onExit() {
|
||||
// Wait until not rendering to delete task to avoid killing mid-instruction to EPD
|
||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||
if (displayTaskHandle) {
|
||||
vTaskDelete(displayTaskHandle);
|
||||
displayTaskHandle = nullptr;
|
||||
}
|
||||
vSemaphoreDelete(renderingMutex);
|
||||
renderingMutex = nullptr;
|
||||
}
|
||||
|
||||
void HomeScreen::handleInput() {
|
||||
const bool prevPressed =
|
||||
inputManager.wasPressed(InputManager::BTN_UP) || inputManager.wasPressed(InputManager::BTN_LEFT);
|
||||
const bool nextPressed =
|
||||
inputManager.wasPressed(InputManager::BTN_DOWN) || inputManager.wasPressed(InputManager::BTN_RIGHT);
|
||||
|
||||
if (inputManager.wasPressed(InputManager::BTN_CONFIRM)) {
|
||||
if (selectorIndex == 0) {
|
||||
onFileSelectionOpen();
|
||||
} else if (selectorIndex == 1) {
|
||||
onSettingsOpen();
|
||||
}
|
||||
} else if (prevPressed) {
|
||||
selectorIndex = (selectorIndex + menuItemCount - 1) % menuItemCount;
|
||||
updateRequired = true;
|
||||
} else if (nextPressed) {
|
||||
selectorIndex = (selectorIndex + 1) % menuItemCount;
|
||||
updateRequired = true;
|
||||
}
|
||||
}
|
||||
|
||||
void HomeScreen::displayTaskLoop() {
|
||||
while (true) {
|
||||
if (updateRequired) {
|
||||
updateRequired = false;
|
||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||
render();
|
||||
xSemaphoreGive(renderingMutex);
|
||||
}
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
void HomeScreen::render() const {
|
||||
renderer.clearScreen();
|
||||
|
||||
const auto pageWidth = GfxRenderer::getScreenWidth();
|
||||
const auto pageHeight = GfxRenderer::getScreenHeight();
|
||||
renderer.drawCenteredText(READER_FONT_ID, 10, "CrossPoint Reader", true, BOLD);
|
||||
|
||||
// Draw selection
|
||||
renderer.fillRect(0, 60 + selectorIndex * 30 + 2, pageWidth - 1, 30);
|
||||
renderer.drawText(UI_FONT_ID, 20, 60, "Read", selectorIndex != 0);
|
||||
renderer.drawText(UI_FONT_ID, 20, 90, "Settings", selectorIndex != 1);
|
||||
|
||||
renderer.drawRect(25, pageHeight - 40, 106, 40);
|
||||
renderer.drawText(UI_FONT_ID, 25 + (105 - renderer.getTextWidth(UI_FONT_ID, "Back")) / 2, pageHeight - 35, "Back");
|
||||
|
||||
renderer.drawRect(130, pageHeight - 40, 106, 40);
|
||||
renderer.drawText(UI_FONT_ID, 130 + (105 - renderer.getTextWidth(UI_FONT_ID, "Confirm")) / 2, pageHeight - 35,
|
||||
"Confirm");
|
||||
|
||||
renderer.drawRect(245, pageHeight - 40, 106, 40);
|
||||
renderer.drawText(UI_FONT_ID, 245 + (105 - renderer.getTextWidth(UI_FONT_ID, "Left")) / 2, pageHeight - 35, "Left");
|
||||
|
||||
renderer.drawRect(350, pageHeight - 40, 106, 40);
|
||||
renderer.drawText(UI_FONT_ID, 350 + (105 - renderer.getTextWidth(UI_FONT_ID, "Right")) / 2, pageHeight - 35, "Right");
|
||||
|
||||
renderer.displayBuffer();
|
||||
}
|
||||
31
src/screens/HomeScreen.h
Normal file
31
src/screens/HomeScreen.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include <freertos/task.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "Screen.h"
|
||||
|
||||
class HomeScreen final : public Screen {
|
||||
TaskHandle_t displayTaskHandle = nullptr;
|
||||
SemaphoreHandle_t renderingMutex = nullptr;
|
||||
int selectorIndex = 0;
|
||||
bool updateRequired = false;
|
||||
const std::function<void()> onFileSelectionOpen;
|
||||
const std::function<void()> onSettingsOpen;
|
||||
|
||||
static constexpr int menuItemCount = 2;
|
||||
|
||||
static void taskTrampoline(void* param);
|
||||
[[noreturn]] void displayTaskLoop();
|
||||
void render() const;
|
||||
|
||||
public:
|
||||
explicit HomeScreen(GfxRenderer& renderer, InputManager& inputManager,
|
||||
const std::function<void()>& onFileSelectionOpen, const std::function<void()>& onSettingsOpen)
|
||||
: Screen(renderer, inputManager), onFileSelectionOpen(onFileSelectionOpen), onSettingsOpen(onSettingsOpen) {}
|
||||
void onEnter() override;
|
||||
void onExit() override;
|
||||
void handleInput() override;
|
||||
};
|
||||
Reference in New Issue
Block a user