mirror of
https://github.com/usatiuk/cardboy.git
synced 2025-10-28 23:27:49 +01:00
faster timeout for games
This commit is contained in:
@@ -145,11 +145,14 @@ public:
|
||||
|
||||
~EventBus() override { vQueueDelete(_queueHandle); }
|
||||
void post(const sdk::AppEvent& event) override { xQueueSendToBack(_queueHandle, &event, portMAX_DELAY); }
|
||||
sdk::AppEvent pop() override {
|
||||
std::optional<sdk::AppEvent> pop(std::optional<std::uint32_t> timeout_ms = std::nullopt) override {
|
||||
sdk::AppEvent out;
|
||||
xQueueReceive(_queueHandle, &out, portMAX_DELAY);
|
||||
TickType_t ticks = timeout_ms ? pdMS_TO_TICKS(*timeout_ms) : portMAX_DELAY;
|
||||
if (xQueueReceive(_queueHandle, &out, ticks) == pdTRUE) {
|
||||
return out;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr std::uint32_t _kMaxQueueSize = 32;
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace apps {
|
||||
namespace {
|
||||
|
||||
using cardboy::sdk::AppButtonEvent;
|
||||
using cardboy::sdk::AppTimeoutEvent;
|
||||
using cardboy::sdk::AppContext;
|
||||
using cardboy::sdk::AppTimerEvent;
|
||||
|
||||
@@ -55,13 +56,14 @@ public:
|
||||
|
||||
void onStop() override { cancelRefreshTimer(); }
|
||||
|
||||
void handleEvent(const cardboy::sdk::AppEvent& event) override {
|
||||
event.visit(cardboy::sdk::overload(
|
||||
[this](const AppButtonEvent& button) { handleButtonEvent(button); },
|
||||
std::optional<std::uint32_t> handleEvent(const cardboy::sdk::AppEvent& event) override {
|
||||
event.visit(cardboy::sdk::overload([this](const AppButtonEvent& button) { handleButtonEvent(button); },
|
||||
[this](const AppTimerEvent& timer) {
|
||||
if (timer.handle == refreshTimer)
|
||||
updateDisplay();
|
||||
}));
|
||||
},
|
||||
[](const AppTimeoutEvent&) { /* ignore */ }));
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -154,6 +154,7 @@ class GameboyApp;
|
||||
using cardboy::sdk::AppButtonEvent;
|
||||
using cardboy::sdk::AppContext;
|
||||
using cardboy::sdk::AppEvent;
|
||||
using cardboy::sdk::AppTimeoutEvent;
|
||||
using cardboy::sdk::AppTimerEvent;
|
||||
using cardboy::sdk::AppTimerHandle;
|
||||
using cardboy::sdk::InputState;
|
||||
@@ -224,7 +225,6 @@ public:
|
||||
::gAudioWriteThunk = &GameboyApp::audioWriteThunk;
|
||||
apu.attach(this);
|
||||
apu.reset();
|
||||
cancelTick();
|
||||
frameDelayCarryUs = 0;
|
||||
GB_PERF_ONLY(perf.resetAll();)
|
||||
prevInput = context.input.readState();
|
||||
@@ -235,11 +235,10 @@ public:
|
||||
refreshRomList();
|
||||
mode = Mode::Browse;
|
||||
browserDirty = true;
|
||||
scheduleNextTick(0);
|
||||
nextTimeoutMs = 0;
|
||||
}
|
||||
|
||||
void onStop() override {
|
||||
cancelTick();
|
||||
frameDelayCarryUs = 0;
|
||||
GB_PERF_ONLY(perf.maybePrintAggregate(true);)
|
||||
unloadRom();
|
||||
@@ -252,14 +251,9 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void handleEvent(const AppEvent& event) override {
|
||||
bool handled = false;
|
||||
std::optional<std::uint32_t> handleEvent(const AppEvent& event) override {
|
||||
event.visit(cardboy::sdk::overload(
|
||||
[this, &handled](const AppTimerEvent& timer) {
|
||||
if (timer.handle != tickTimer)
|
||||
return;
|
||||
handled = true;
|
||||
tickTimer = kInvalidAppTimer;
|
||||
[this](const AppTimeoutEvent&) {
|
||||
const uint64_t frameStartUs = nowMicros();
|
||||
performStep();
|
||||
const uint64_t frameEndUs = nowMicros();
|
||||
@@ -269,10 +263,10 @@ public:
|
||||
},
|
||||
[this](const AppButtonEvent&) {
|
||||
frameDelayCarryUs = 0;
|
||||
scheduleNextTick(0);
|
||||
}));
|
||||
if (handled)
|
||||
return;
|
||||
nextTimeoutMs = 0;
|
||||
},
|
||||
[](const AppTimerEvent&) { /* ignore */ }));
|
||||
return nextTimeoutMs;
|
||||
}
|
||||
|
||||
void performStep() {
|
||||
@@ -1119,8 +1113,8 @@ public:
|
||||
cardboy::sdk::IFilesystem* filesystem = nullptr;
|
||||
cardboy::sdk::IHighResClock* highResClock = nullptr;
|
||||
PerfTracker perf{};
|
||||
AppTimerHandle tickTimer = kInvalidAppTimer;
|
||||
int64_t frameDelayCarryUs = 0;
|
||||
std::optional<std::uint32_t> nextTimeoutMs;
|
||||
static constexpr uint32_t kTargetFrameUs = 1000000 / 60; // ~16.6 ms
|
||||
|
||||
Mode mode = Mode::Browse;
|
||||
@@ -1155,20 +1149,6 @@ public:
|
||||
uint8_t lastLoud = 0;
|
||||
uint32_t stableFrames = 0;
|
||||
|
||||
void cancelTick() {
|
||||
if (tickTimer == kInvalidAppTimer)
|
||||
return;
|
||||
if (auto* timer = context.timer())
|
||||
timer->cancelTimer(tickTimer);
|
||||
tickTimer = kInvalidAppTimer;
|
||||
}
|
||||
|
||||
void scheduleNextTick(uint32_t delayMs) {
|
||||
cancelTick();
|
||||
if (auto* timer = context.timer())
|
||||
tickTimer = timer->scheduleTimer(delayMs, false);
|
||||
}
|
||||
|
||||
uint32_t idleDelayMs() const { return browserDirty ? 50 : 140; }
|
||||
|
||||
void scheduleAfterFrame(uint64_t elapsedUs) {
|
||||
@@ -1177,17 +1157,17 @@ public:
|
||||
desiredUs += frameDelayCarryUs;
|
||||
if (desiredUs <= 0) {
|
||||
frameDelayCarryUs = desiredUs;
|
||||
scheduleNextTick(0);
|
||||
nextTimeoutMs = 0;
|
||||
return;
|
||||
}
|
||||
frameDelayCarryUs = desiredUs % 1000;
|
||||
desiredUs -= frameDelayCarryUs;
|
||||
uint32_t delayMs = static_cast<uint32_t>(desiredUs / 1000);
|
||||
scheduleNextTick(delayMs);
|
||||
nextTimeoutMs = delayMs;
|
||||
return;
|
||||
}
|
||||
frameDelayCarryUs = 0;
|
||||
scheduleNextTick(idleDelayMs());
|
||||
nextTimeoutMs = idleDelayMs();
|
||||
}
|
||||
|
||||
bool ensureFilesystemReady() {
|
||||
@@ -1838,7 +1818,7 @@ public:
|
||||
promptDirty = true;
|
||||
mode = Mode::Prompt;
|
||||
gb.direct.joypad = 0xFF;
|
||||
scheduleNextTick(0);
|
||||
// scheduleNextTick(0);
|
||||
}
|
||||
|
||||
void exitPrompt(Mode nextMode) {
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
#include "cardboy/sdk/app_framework.hpp"
|
||||
#include "cardboy/sdk/app_system.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
@@ -18,6 +18,7 @@ namespace apps {
|
||||
namespace {
|
||||
|
||||
using cardboy::sdk::AppButtonEvent;
|
||||
using cardboy::sdk::AppTimeoutEvent;
|
||||
using cardboy::sdk::AppContext;
|
||||
using cardboy::sdk::AppTimerEvent;
|
||||
|
||||
@@ -27,19 +28,13 @@ constexpr std::uint32_t kUnlockHoldMs = 1500;
|
||||
using Framebuffer = typename AppContext::Framebuffer;
|
||||
using Clock = typename AppContext::Clock;
|
||||
|
||||
constexpr std::array<std::uint8_t, font16x8::kGlyphHeight> kArrowUpGlyph{0b00011000, 0b00111100, 0b01111110,
|
||||
0b11111111, 0b00011000, 0b00011000,
|
||||
0b00011000, 0b00011000, 0b00011000,
|
||||
0b00011000, 0b00011000, 0b00011000,
|
||||
0b00011000, 0b00011000, 0b00000000,
|
||||
0b00000000};
|
||||
constexpr std::array<std::uint8_t, font16x8::kGlyphHeight> kArrowUpGlyph{
|
||||
0b00011000, 0b00111100, 0b01111110, 0b11111111, 0b00011000, 0b00011000, 0b00011000, 0b00011000,
|
||||
0b00011000, 0b00011000, 0b00011000, 0b00011000, 0b00011000, 0b00011000, 0b00000000, 0b00000000};
|
||||
|
||||
constexpr std::array<std::uint8_t, font16x8::kGlyphHeight> kArrowDownGlyph{0b00000000, 0b00000000, 0b00011000,
|
||||
0b00011000, 0b00011000, 0b00011000,
|
||||
0b00011000, 0b00011000, 0b00011000,
|
||||
0b00011000, 0b00011000, 0b11111111,
|
||||
0b01111110, 0b00111100, 0b00011000,
|
||||
0b00000000};
|
||||
constexpr std::array<std::uint8_t, font16x8::kGlyphHeight> kArrowDownGlyph{
|
||||
0b00000000, 0b00000000, 0b00011000, 0b00011000, 0b00011000, 0b00011000, 0b00011000, 0b00011000,
|
||||
0b00011000, 0b00011000, 0b00011000, 0b11111111, 0b01111110, 0b00111100, 0b00011000, 0b00000000};
|
||||
|
||||
struct TimeSnapshot {
|
||||
bool hasWallTime = false;
|
||||
@@ -75,15 +70,16 @@ public:
|
||||
|
||||
void onStop() override { cancelRefreshTimer(); }
|
||||
|
||||
void handleEvent(const cardboy::sdk::AppEvent& event) override {
|
||||
event.visit(cardboy::sdk::overload(
|
||||
[this](const AppButtonEvent& button) { handleButtonEvent(button); },
|
||||
std::optional<std::uint32_t> handleEvent(const cardboy::sdk::AppEvent& event) override {
|
||||
event.visit(cardboy::sdk::overload([this](const AppButtonEvent& button) { handleButtonEvent(button); },
|
||||
[this](const AppTimerEvent& timer) {
|
||||
if (timer.handle == refreshTimer) {
|
||||
advanceHoldProgress();
|
||||
updateDisplay();
|
||||
}
|
||||
}));
|
||||
},
|
||||
[](const AppTimeoutEvent&) { /* ignore */ }));
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -213,8 +209,7 @@ private:
|
||||
|
||||
void advanceHoldProgress() {
|
||||
if (holdActive) {
|
||||
const std::uint32_t next =
|
||||
std::min<std::uint32_t>(holdProgressMs + kRefreshIntervalMs, kUnlockHoldMs);
|
||||
const std::uint32_t next = std::min<std::uint32_t>(holdProgressMs + kRefreshIntervalMs, kUnlockHoldMs);
|
||||
if (next != holdProgressMs) {
|
||||
holdProgressMs = next;
|
||||
dirty = true;
|
||||
@@ -239,8 +234,8 @@ private:
|
||||
}
|
||||
|
||||
static bool sameSnapshot(const TimeSnapshot& a, const TimeSnapshot& b) {
|
||||
return a.hasWallTime == b.hasWallTime && a.hour24 == b.hour24 && a.minute == b.minute &&
|
||||
a.second == b.second && a.day == b.day && a.month == b.month && a.year == b.year;
|
||||
return a.hasWallTime == b.hasWallTime && a.hour24 == b.hour24 && a.minute == b.minute && a.second == b.second &&
|
||||
a.day == b.day && a.month == b.month && a.year == b.year;
|
||||
}
|
||||
|
||||
TimeSnapshot captureTime() const {
|
||||
@@ -369,8 +364,7 @@ private:
|
||||
|
||||
if (!word.empty()) {
|
||||
std::string candidate = current.empty() ? word : current + " " + word;
|
||||
if (!current.empty() &&
|
||||
font16x8::measureText(candidate, scale, letterSpacing) > maxWidth) {
|
||||
if (!current.empty() && font16x8::measureText(candidate, scale, letterSpacing) > maxWidth) {
|
||||
flushCurrent();
|
||||
if (lines.size() >= static_cast<std::size_t>(maxLines)) {
|
||||
truncated = true;
|
||||
@@ -481,7 +475,8 @@ private:
|
||||
std::snprintf(counter, sizeof(counter), "%zu/%zu", selectedNotification + 1, notifications.size());
|
||||
const int counterWidth = font16x8::measureText(counter, scaleSmall, 1);
|
||||
const int counterX = cardMarginSide + cardWidth - cardPadding - counterWidth;
|
||||
font16x8::drawText(framebuffer, counterX, cardMarginTop + cardPadding, counter, scaleSmall, true, 1);
|
||||
font16x8::drawText(framebuffer, counterX, cardMarginTop + cardPadding, counter, scaleSmall, true,
|
||||
1);
|
||||
const int arrowWidth = font16x8::kGlyphWidth * scaleSmall;
|
||||
const int arrowSpacing = std::max(1, scaleSmall);
|
||||
const int arrowsTotalWide = arrowWidth * 2 + arrowSpacing;
|
||||
@@ -531,8 +526,7 @@ private:
|
||||
if (cardHeight > 0)
|
||||
timeY = cardMarginTop + cardHeight + 16;
|
||||
const int minTimeY = (cardHeight > 0) ? (cardMarginTop + cardHeight + 12) : 16;
|
||||
const int maxTimeY =
|
||||
std::max(minTimeY, framebuffer.height() - font16x8::kGlyphHeight * scaleTime - 48);
|
||||
const int maxTimeY = std::max(minTimeY, framebuffer.height() - font16x8::kGlyphHeight * scaleTime - 48);
|
||||
timeY = std::clamp(timeY, minTimeY, maxTimeY);
|
||||
|
||||
char hoursMinutes[6];
|
||||
@@ -570,8 +564,7 @@ private:
|
||||
if (holdActive || holdProgressMs > 0) {
|
||||
const int innerWidth = barWidth - 2;
|
||||
const int innerHeight = barHeight - 2;
|
||||
const float ratio =
|
||||
std::clamp(holdProgressMs / static_cast<float>(kUnlockHoldMs), 0.0f, 1.0f);
|
||||
const float ratio = std::clamp(holdProgressMs / static_cast<float>(kUnlockHoldMs), 0.0f, 1.0f);
|
||||
const int fillWidth = static_cast<int>(ratio * innerWidth + 0.5f);
|
||||
if (fillWidth > 0)
|
||||
fillRect(framebuffer, barX + 1, barY + 1, fillWidth, innerHeight);
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace apps {
|
||||
namespace {
|
||||
|
||||
using cardboy::sdk::AppButtonEvent;
|
||||
using cardboy::sdk::AppTimeoutEvent;
|
||||
using cardboy::sdk::AppContext;
|
||||
using cardboy::sdk::AppEvent;
|
||||
using cardboy::sdk::AppTimerEvent;
|
||||
@@ -44,15 +45,16 @@ public:
|
||||
|
||||
void onStop() override { cancelInactivityTimer(); }
|
||||
|
||||
void handleEvent(const cardboy::sdk::AppEvent& event) override {
|
||||
event.visit(cardboy::sdk::overload(
|
||||
[this](const AppButtonEvent& button) { handleButtonEvent(button); },
|
||||
std::optional<std::uint32_t> handleEvent(const cardboy::sdk::AppEvent& event) override {
|
||||
event.visit(cardboy::sdk::overload([this](const AppButtonEvent& button) { handleButtonEvent(button); },
|
||||
[this](const AppTimerEvent& timer) {
|
||||
if (timer.handle == inactivityTimer) {
|
||||
cancelInactivityTimer();
|
||||
context.requestAppSwitchByName(kLockscreenAppName);
|
||||
}
|
||||
}));
|
||||
},
|
||||
[](const AppTimeoutEvent&) { /* ignore */ }));
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -38,13 +38,11 @@ public:
|
||||
renderIfNeeded();
|
||||
}
|
||||
|
||||
void handleEvent(const cardboy::sdk::AppEvent& event) override {
|
||||
const auto* buttonEvent = event.button();
|
||||
if (!buttonEvent)
|
||||
return;
|
||||
|
||||
const auto& current = buttonEvent->current;
|
||||
const auto& previous = buttonEvent->previous;
|
||||
std::optional<std::uint32_t> handleEvent(const cardboy::sdk::AppEvent& event) override {
|
||||
event.visit(cardboy::sdk::overload(
|
||||
[this](const cardboy::sdk::AppButtonEvent& button) {
|
||||
const auto& current = button.current;
|
||||
const auto& previous = button.previous;
|
||||
|
||||
const bool previousAvailable = buzzerAvailable;
|
||||
syncBuzzerState();
|
||||
@@ -74,6 +72,10 @@ public:
|
||||
dirty = true;
|
||||
|
||||
renderIfNeeded();
|
||||
},
|
||||
[](const cardboy::sdk::AppTimerEvent&) { /* ignore */ },
|
||||
[](const cardboy::sdk::AppTimeoutEvent&) { /* ignore */ }));
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace apps {
|
||||
namespace {
|
||||
|
||||
using cardboy::sdk::AppButtonEvent;
|
||||
using cardboy::sdk::AppTimeoutEvent;
|
||||
using cardboy::sdk::AppContext;
|
||||
using cardboy::sdk::AppEvent;
|
||||
using cardboy::sdk::AppTimerEvent;
|
||||
@@ -69,11 +70,12 @@ public:
|
||||
|
||||
void onStop() { cancelMoveTimer(); }
|
||||
|
||||
void handleEvent(const AppEvent& event) {
|
||||
event.visit(cardboy::sdk::overload(
|
||||
[this](const AppButtonEvent& button) { handleButtons(button); },
|
||||
[this](const AppTimerEvent& timer) { handleTimer(timer.handle); }));
|
||||
std::optional<std::uint32_t> handleEvent(const AppEvent& event) {
|
||||
event.visit(cardboy::sdk::overload([this](const AppButtonEvent& button) { handleButtons(button); },
|
||||
[this](const AppTimerEvent& timer) { handleTimer(timer.handle); },
|
||||
[](const AppTimeoutEvent&) { /* ignore */ }));
|
||||
renderIfNeeded();
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -299,9 +301,7 @@ private:
|
||||
framebuffer.sendFrame();
|
||||
}
|
||||
|
||||
[[nodiscard]] int boardOriginX() const {
|
||||
return (cardboy::sdk::kDisplayWidth - kBoardWidth * kCellSize) / 2;
|
||||
}
|
||||
[[nodiscard]] int boardOriginX() const { return (cardboy::sdk::kDisplayWidth - kBoardWidth * kCellSize) / 2; }
|
||||
|
||||
[[nodiscard]] int boardOriginY() const {
|
||||
const int centered = (cardboy::sdk::kDisplayHeight - kBoardHeight * kCellSize) / 2;
|
||||
@@ -408,7 +408,7 @@ public:
|
||||
|
||||
void onStart() override { game.onStart(); }
|
||||
void onStop() override { game.onStop(); }
|
||||
void handleEvent(const AppEvent& event) override { game.handleEvent(event); }
|
||||
std::optional<std::uint32_t> handleEvent(const AppEvent& event) override { return game.handleEvent(event); }
|
||||
|
||||
private:
|
||||
SnakeGame game;
|
||||
|
||||
@@ -148,11 +148,12 @@ public:
|
||||
|
||||
void onStop() { cancelTimers(); }
|
||||
|
||||
void handleEvent(const AppEvent& event) {
|
||||
event.visit(cardboy::sdk::overload(
|
||||
[this](const AppButtonEvent& button) { handleButtons(button); },
|
||||
[this](const AppTimerEvent& timer) { handleTimer(timer.handle); }));
|
||||
std::optional<std::uint32_t> handleEvent(const AppEvent& event) {
|
||||
event.visit(cardboy::sdk::overload([this](const AppButtonEvent& button) { handleButtons(button); },
|
||||
[this](const AppTimerEvent& timer) { handleTimer(timer.handle); },
|
||||
[](const cardboy::sdk::AppTimeoutEvent&) { /* ignore */ }));
|
||||
renderIfNeeded();
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -636,7 +637,7 @@ public:
|
||||
|
||||
void onStart() override { game.onStart(); }
|
||||
void onStop() override { game.onStop(); }
|
||||
void handleEvent(const AppEvent& event) override { game.handleEvent(event); }
|
||||
std::optional<std::uint32_t> handleEvent(const AppEvent& event) override { return game.handleEvent(event); }
|
||||
|
||||
private:
|
||||
TetrisGame game;
|
||||
|
||||
@@ -21,14 +21,17 @@ struct AppTimerEvent {
|
||||
AppTimerHandle handle = kInvalidAppTimer;
|
||||
};
|
||||
|
||||
struct AppTimeoutEvent {};
|
||||
|
||||
struct AppEvent {
|
||||
using Data = std::variant<AppButtonEvent, AppTimerEvent>;
|
||||
using Data = std::variant<AppButtonEvent, AppTimerEvent, AppTimeoutEvent>;
|
||||
|
||||
std::uint32_t timestamp_ms = 0;
|
||||
Data data{AppButtonEvent{}};
|
||||
|
||||
[[nodiscard]] bool isButton() const { return std::holds_alternative<AppButtonEvent>(data); }
|
||||
[[nodiscard]] bool isTimer() const { return std::holds_alternative<AppTimerEvent>(data); }
|
||||
[[nodiscard]] bool isTimeout() const { return std::holds_alternative<AppTimeoutEvent>(data); }
|
||||
|
||||
[[nodiscard]] const AppButtonEvent* button() const { return std::get_if<AppButtonEvent>(&data); }
|
||||
[[nodiscard]] AppButtonEvent* button() { return std::get_if<AppButtonEvent>(&data); }
|
||||
@@ -36,6 +39,9 @@ struct AppEvent {
|
||||
[[nodiscard]] const AppTimerEvent* timer() const { return std::get_if<AppTimerEvent>(&data); }
|
||||
[[nodiscard]] AppTimerEvent* timer() { return std::get_if<AppTimerEvent>(&data); }
|
||||
|
||||
[[nodiscard]] const AppTimeoutEvent* timeout() const { return std::get_if<AppTimeoutEvent>(&data); }
|
||||
[[nodiscard]] AppTimeoutEvent* timeout() { return std::get_if<AppTimeoutEvent>(&data); }
|
||||
|
||||
template<typename Visitor>
|
||||
decltype(auto) visit(Visitor&& visitor) {
|
||||
return std::visit(std::forward<Visitor>(visitor), data);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
@@ -98,7 +99,7 @@ public:
|
||||
virtual ~IEventBus() = default;
|
||||
|
||||
virtual void post(const AppEvent& event) = 0;
|
||||
virtual AppEvent pop() = 0;
|
||||
virtual std::optional<AppEvent> pop(std::optional<std::uint32_t> timeout_ms = std::nullopt) = 0;
|
||||
};
|
||||
|
||||
struct AppScopedServices {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
@@ -78,7 +79,7 @@ public:
|
||||
virtual ~IApp() = default;
|
||||
virtual void onStart() {}
|
||||
virtual void onStop() {}
|
||||
virtual void handleEvent(const AppEvent& event) = 0;
|
||||
virtual std::optional<std::uint32_t> handleEvent(const AppEvent& event) = 0;
|
||||
};
|
||||
|
||||
class IAppFactory {
|
||||
|
||||
@@ -39,6 +39,7 @@ private:
|
||||
std::size_t _activeIndex = static_cast<std::size_t>(-1);
|
||||
std::unique_ptr<AppScopedServices> _scopedServices;
|
||||
std::uint64_t _nextScopedGeneration = 1;
|
||||
std::optional<std::uint32_t> _currentTimeout;
|
||||
};
|
||||
|
||||
} // namespace cardboy::sdk
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "cardboy/sdk/status_bar.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
namespace cardboy::sdk {
|
||||
@@ -66,6 +67,7 @@ void AppSystem::startAppByIndex(std::size_t index) {
|
||||
_context._pendingSwitchByName = false;
|
||||
_context._pendingAppName.clear();
|
||||
_current = std::move(app);
|
||||
_currentTimeout = std::nullopt;
|
||||
StatusBar::instance().setServices(_context.services);
|
||||
StatusBar::instance().setCurrentAppName(_activeFactory ? _activeFactory->name() : "");
|
||||
_current->onStart();
|
||||
@@ -81,14 +83,21 @@ void AppSystem::run() {
|
||||
if (auto* hooks = _context.loopHooks())
|
||||
hooks->onLoopIteration();
|
||||
|
||||
auto event = _context.eventBus()->pop();
|
||||
AppEvent event;
|
||||
auto event_opt = _context.eventBus()->pop(_currentTimeout);
|
||||
if (!event_opt) {
|
||||
event = AppEvent{_context.clock.millis(), AppTimeoutEvent{}};
|
||||
} else {
|
||||
event = *event_opt;
|
||||
}
|
||||
|
||||
if (const auto* btn = event.button()) {
|
||||
const bool consumedByStatusToggle = StatusBar::instance().handleToggleInput(btn->current, btn->previous);
|
||||
if (consumedByStatusToggle) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
_current->handleEvent(event);
|
||||
_currentTimeout = _current->handleEvent(event);
|
||||
if (_context._pendingSwitch) {
|
||||
handlePendingSwitchRequest();
|
||||
continue;
|
||||
|
||||
Reference in New Issue
Block a user