#pragma once #include "application.h" #include "./Geometry.h" #include "./Figment.h" #include "FastLED/FastLED.h" typedef Vector3d MotionVec; struct Variant { enum Type { Null, Integer, String, Color, }; Variant(int v) : type(Integer), m_value{.asInt=v} {} Variant(const char* v) : type(String), m_value{.asString=v} {} Variant(const NSFastLED::CRGB &v) : type(Color), m_value{.asRGB={v.r, v.g, v.b}} {} Variant() : type(Null) {} Type type; const char* asString() const; NSFastLED::CRGB asRGB() const; int asInt() const; private: union { int asInt; const char* asString; uint8_t asRGB[3]; } m_value; }; struct InputEvent: public Variant { enum Intent { // An empty non-event None, // An input from the user, for other tasks to translate into canonical // types. Makes for easy button re-mapping on the fly. UserInput, // // The canonical types // // Hardware inputs ButtonPress, Acceleration, NetworkStatus, NetworkActivity, // Power management PowerToggle, SetPower, SetBrightness, // Animation sequencing PreviousPattern, NextPattern, SetPattern, PreviousScene, NextScene, SetScene, // Timekeeping ScheduleChange, // Task management StartThing, StopThing, // Configuration SetDisplayOffset, SetDisplayLength, SetColor, SaveConfigurationRequest, // Firmware events FirmwareUpdate, }; template InputEvent(Intent s, Value v) : Variant(v), intent(s) {} InputEvent(Intent s) : Variant(), intent(s) {} InputEvent() : Variant(), intent(None) {} Intent intent; }; class InputSource: public Task { public: InputSource() : Task() {} InputSource(const char* name) : Task(name) {} InputSource(Task::State initialState) : Task(initialState) {} InputSource(const char* name, Task::State initialState) : Task(name, initialState) {} void loop() override; virtual InputEvent read() = 0; }; class InputFunc : public InputSource { public: InputFunc(std::function f) : InputSource(), m_func(f) {} InputFunc(std::function f, const char* name) : InputSource(name), m_func(f) {} InputFunc(std::function f, const char* name, Task::State initialState) : InputSource(name, initialState), m_func(f) {} InputEvent read() override { return m_func(); } private: std::function m_func; }; class BufferedInputSource: public InputSource { public: BufferedInputSource() : InputSource() {} BufferedInputSource(const char* name) : InputSource(name) {} InputEvent read() override; protected: void setEvent(InputEvent &&evt); void setEvent(InputEvent::Intent intent, Variant &&v); private: InputEvent m_lastEvent; }; class InputMapper: public BufferedInputSource { public: InputMapper(std::function f) : BufferedInputSource(), m_func(f) {} void handleEvent(const InputEvent& evt) override { setEvent(m_func(evt)); } private: std::function m_func; };