// Portal-style end-credits show for the EL512.256-H: timed song text typed into // a console on the left, credits typed top right, ASCII art bottom right. // // Framework-agnostic: draws straight into an EL512Panel with the built-in 5x7 // font, so the PlatformIO demo (src/still_alive) and the ESPHome component use // the same code. The content is in still_alive_data.h, generated by // tools/import_still_alive.py. #pragma once #include #include class EL512Panel; namespace el512sa { enum : uint8_t { STEP_NEWLINE = 1 << 0, // start a new line after the text is typed STEP_CLEAR = 1 << 1, // clear the console before typing }; // One timed piece of console text. Steps are sorted by startMs. struct LyricStep { uint32_t startMs; // from the start of the show uint16_t durMs; // the text is typed out evenly over this time uint8_t flags; int8_t art; // picture to show (index into ARTS), or ART_KEEP const char *text; }; struct Art { const char *const *lines; uint8_t count; }; static constexpr int8_t ART_KEEP = -1; // leave the current picture static constexpr int8_t ART_NONE = 0; // ARTS[0] is always the empty picture // Fixed-size character console in the 5x7 font (6x8 cells), optionally inside a // dashed frame. Text wraps at the right edge and scrolls up past the bottom row. class TextBox { public: static constexpr uint8_t MAX_COLS = 48; static constexpr uint8_t MAX_ROWS = 32; static constexpr int16_t PAD = 4; static constexpr int16_t CHAR_W = 6; static constexpr int16_t CHAR_H = 8; TextBox(int16_t x, int16_t y, int16_t w, int16_t h); uint8_t cols() const { return cols_; } uint8_t rows() const { return rows_; } void clear(); void put(char c); void print(const char *s); void draw(EL512Panel &panel, bool cursor, bool frame = true) const; private: void newLine(); int16_t x_, y_, w_, h_; uint8_t cols_, rows_; uint8_t row_ = 0, col_ = 0; char text_[MAX_ROWS][MAX_COLS + 1]; }; class StillAlivePlayer { public: static constexpr uint32_t START_DELAY_MS = 1000; // after start() static constexpr uint32_t CURSOR_BLINK_MS = 300; static constexpr uint32_t HOLD_MS = 10000; // after the last step, before finished() StillAlivePlayer(); // Restart the show; it begins START_DELAY_MS after nowMs. void start(uint32_t nowMs); // Advance to nowMs; true if the screen changed (text, picture or cursor). bool update(uint32_t nowMs); // Draw the whole show; the caller clears the panel first and shows it after. void draw(EL512Panel &panel) const; // True once the last step has been typed and HOLD_MS has passed. bool finished(uint32_t nowMs) const; // When to start the music, relative to start(). static uint32_t songStartMs(); private: bool updateLyrics(uint32_t t, uint32_t nowMs); bool updateCredits(uint32_t t); void showArt(int8_t id); TextBox lyrics_; TextBox credits_; TextBox art_; uint32_t showStart_ = 0; size_t step_ = 0; size_t charIdx_ = 0; bool stepStarted_ = false; bool done_ = false; uint32_t doneAt_ = 0; size_t creditIdx_ = 0; size_t creditChar_ = 0; bool creditLineOpen_ = false; bool creditsDone_ = false; uint32_t creditLineAt_ = 0; bool cursor_ = false; bool creditsCursor_ = false; }; } // namespace el512sa