#pragma once #include #include #include #include #include class AppSystem; struct InputState { bool up = false; bool left = false; bool right = false; bool down = false; bool a = false; bool b = false; bool select = false; bool start = false; }; class IFramebuffer { public: virtual ~IFramebuffer() = default; virtual void drawPixel(int x, int y, bool on) = 0; // on=true => black virtual void clear(bool on) = 0; // fill full screen to on/off virtual int width() const = 0; virtual int height() const = 0; }; class IInput { public: virtual ~IInput() = default; virtual InputState readState() = 0; }; class IClock { public: virtual ~IClock() = default; virtual uint32_t millis() = 0; virtual void sleep_ms(uint32_t ms) = 0; }; struct AppContext { AppContext() = delete; AppContext(IFramebuffer& fb, IInput& in, IClock& clk) : framebuffer(fb), input(in), clock(clk) {} IFramebuffer& framebuffer; IInput& input; IClock& 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; } private: friend class AppSystem; bool pendingSwitch = false; bool pendingSwitchByName = false; std::size_t pendingAppIndex = 0; std::string pendingAppName; }; struct AppSleepPlan { uint32_t slow_ms = 0; // long sleep allowing battery/UI periodic refresh uint32_t normal_ms = 0; // short sleep for responsiveness on input wake }; class IApp { public: virtual ~IApp() = default; virtual void onStart() {} virtual void onStop() {} virtual void step() = 0; virtual AppSleepPlan sleepPlan(uint32_t now) const { return {}; } }; class IAppFactory { public: virtual ~IAppFactory() = default; virtual const char* name() const = 0; virtual std::unique_ptr create(AppContext& context) = 0; };