Files
cardboy/Firmware/main/include/app_framework.hpp
2025-10-09 17:12:17 +02:00

119 lines
3.0 KiB
C++

#pragma once
#include "app_platform.hpp"
#include "input_state.hpp"
#include <cstdint>
#include <memory>
#include <string>
#include <string_view>
#include <vector>
class AppSystem;
using AppTimerHandle = std::uint32_t;
constexpr AppTimerHandle kInvalidAppTimer = 0;
enum class AppEventType {
Button,
Timer,
};
struct AppButtonEvent {
InputState current{};
InputState previous{};
};
struct AppTimerEvent {
AppTimerHandle handle = kInvalidAppTimer;
};
struct AppEvent {
AppEventType type;
std::uint32_t timestamp_ms = 0;
AppButtonEvent button{};
AppTimerEvent timer{};
};
template<typename FramebufferT, typename InputT, typename ClockT>
struct BasicAppContext {
using Framebuffer = FramebufferT;
using Input = InputT;
using Clock = ClockT;
BasicAppContext() = delete;
BasicAppContext(FramebufferT& fb, InputT& in, ClockT& clk) : framebuffer(fb), input(in), clock(clk) {}
FramebufferT& framebuffer;
InputT& input;
ClockT& clock;
AppSystem* system = nullptr;
void requestAppSwitchByIndex(std::size_t index) {
pendingAppIndex = index;
pendingAppName.clear();
pendingSwitchByName = false;
pendingSwitch = true;
}
void requestAppSwitchByName(std::string_view name) {
pendingAppName.assign(name.begin(), name.end());
pendingSwitchByName = true;
pendingSwitch = true;
}
bool hasPendingAppSwitch() const { return pendingSwitch; }
AppTimerHandle scheduleTimer(uint32_t delay_ms, bool repeat = false) {
if (!system)
return kInvalidAppTimer;
return scheduleTimerInternal(delay_ms, repeat);
}
AppTimerHandle scheduleRepeatingTimer(uint32_t interval_ms) {
if (!system)
return kInvalidAppTimer;
return scheduleTimerInternal(interval_ms, true);
}
void cancelTimer(AppTimerHandle handle) {
if (!system)
return;
cancelTimerInternal(handle);
}
void cancelAllTimers() {
if (!system)
return;
cancelAllTimersInternal();
}
private:
friend class AppSystem;
bool pendingSwitch = false;
bool pendingSwitchByName = false;
std::size_t pendingAppIndex = 0;
std::string pendingAppName;
AppTimerHandle scheduleTimerInternal(uint32_t delay_ms, bool repeat);
void cancelTimerInternal(AppTimerHandle handle);
void cancelAllTimersInternal();
};
using AppContext = BasicAppContext<PlatformFramebuffer, PlatformInput, PlatformClock>;
class IApp {
public:
virtual ~IApp() = default;
virtual void onStart() {}
virtual void onStop() {}
virtual void handleEvent(const AppEvent& event) = 0;
};
class IAppFactory {
public:
virtual ~IAppFactory() = default;
virtual const char* name() const = 0;
virtual std::unique_ptr<IApp> create(AppContext& context) = 0;
};