diff --git a/firmware/application/external/snake/Arial12x12.h b/firmware/application/external/snake/Arial12x12.h deleted file mode 100644 index 4dc451eeb..000000000 --- a/firmware/application/external/snake/Arial12x12.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2024 Mark Thompson - * - * This file is part of PortaPack. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -// dummy include file to avoid changing original source - -#ifndef __UI_Arial12x12_H__ -#define __UI_Arial12x12_H__ - -#define Arial12x12 (0) - -#endif /*__UI_Arial12x12_H__*/ diff --git a/firmware/application/external/snake/SPI_TFT_ILI9341.h b/firmware/application/external/snake/SPI_TFT_ILI9341.h deleted file mode 100644 index 0f7db6feb..000000000 --- a/firmware/application/external/snake/SPI_TFT_ILI9341.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * ------------------------------------------------------------ - * | Made by RocketGod | - * | Find me at https://betaskynet.com | - * | Argh matey! | - * ------------------------------------------------------------ - */ - -#ifndef __UI_SPI_TFT_ILI9341_H__ -#define __UI_SPI_TFT_ILI9341_H__ - -ui::Painter painter; - -static int bg_color; - -enum { - White, - Blue, - Yellow, - Purple, - Green, - Red, - Maroon, - Orange, - Black, -}; - -static const Color pp_colors[] = { - Color::white(), - Color::blue(), - Color::yellow(), - Color::purple(), - Color::green(), - Color::red(), - Color::magenta(), - Color::orange(), - Color::black(), -}; - -static void claim(__FILE* x) { - (void)x; -}; - -static void cls() { - painter.fill_rectangle({0, 0, portapack::display.width(), portapack::display.height()}, Color::black()); -}; - -static void background(int color) { - bg_color = color; -}; - -static void set_orientation(int x) { - (void)x; -}; - -static void set_font(unsigned char* x) { - (void)x; -}; - -static void fillrect(int x1, int y1, int x2, int y2, int color) { - painter.fill_rectangle({x1, y1, x2 - x1, y2 - y1}, pp_colors[color]); -}; - -static void rect(int x1, int y1, int x2, int y2, int color) { - painter.draw_rectangle({x1, y1, x2 - x1, y2 - y1}, pp_colors[color]); -}; - -#endif /*__UI_SPI_TFT_ILI9341_H__*/ \ No newline at end of file diff --git a/firmware/application/external/snake/main.cpp b/firmware/application/external/snake/main.cpp index f6574cd44..3c93935aa 100644 --- a/firmware/application/external/snake/main.cpp +++ b/firmware/application/external/snake/main.cpp @@ -65,4 +65,4 @@ __attribute__((section(".external_app.app_snake.application_information"), used) {0, 0, 0, 0}, 0x00000000, }; -} \ No newline at end of file +} // namespace ui::external_app::snake \ No newline at end of file diff --git a/firmware/application/external/snake/mbed.h b/firmware/application/external/snake/mbed.h deleted file mode 100644 index 4d75f8c33..000000000 --- a/firmware/application/external/snake/mbed.h +++ /dev/null @@ -1,98 +0,0 @@ -#ifndef __UI_mbed_H__ -#define __UI_mbed_H__ - -using Callback = void (*)(void); - -#define wait_us(x) (void)0 -#define wait(x) chThdSleepMilliseconds(x * 1000) -#define PullUp 1 - -#include "ui_navigation.hpp" - -enum { - dp0, - dp1, - dp2, - dp3, - dp4, - dp5, - dp6, - dp7, - dp8, - dp9, - dp10, - dp11, - dp12, - dp13, - dp14, - dp15, - dp16, - dp17, - dp18, - dp19, - dp20, - dp21, - dp22, - dp23, - dp24, - dp25, -}; - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-variable" -static bool but_RIGHT; -static bool but_LEFT; -#pragma GCC diagnostic pop -static bool but_SELECT; - -class Timer { - public: - Timer() { (void)0; }; - void reset() { (void)0; }; - void start() { (void)0; } - uint32_t read_ms() { return 1000; }; - - private: -}; - -static Callback game_update_callback; -static uint32_t game_update_timeout; -static uint32_t game_update_counter; - -static void check_game_timer() { - if (game_update_callback) { - if (++game_update_counter >= game_update_timeout) { - game_update_counter = 0; - game_update_callback(); - } - } -} - -class Ticker { - public: - Ticker() { (void)0; }; - void attach(Callback func, double delay_sec) { - game_update_callback = func; - game_update_timeout = delay_sec * 60; - } - void detach() { - game_update_callback = nullptr; - } - - private: -}; - -static Callback button_callback; - -class InterruptIn { - public: - InterruptIn(int reg) { - (void)reg; - }; - void fall(Callback func) { button_callback = func; }; - void mode(int v) { (void)v; }; - - private: -}; - -#endif /*__UI_mbed_H__*/ \ No newline at end of file diff --git a/firmware/application/external/snake/snake.cpp b/firmware/application/external/snake/snake.cpp deleted file mode 100644 index d1f134969..000000000 --- a/firmware/application/external/snake/snake.cpp +++ /dev/null @@ -1,234 +0,0 @@ -/* - * ------------------------------------------------------------ - * | Made by RocketGod | - * | Find me at https://betaskynet.com | - * | Argh matey! | - * ------------------------------------------------------------ - */ - -#include "mbed.h" -#include "SPI_TFT_ILI9341.h" -#include "Arial12x12.h" -#include "ui.hpp" -#include "random.hpp" - -extern int game_state; - -#define SCREEN_WIDTH 240 -#define SCREEN_HEIGHT 320 -#define SNAKE_SIZE 10 -#define INFO_BAR_HEIGHT 25 -#define GAME_AREA_TOP (INFO_BAR_HEIGHT + 1) -#define GAME_AREA_HEIGHT (SCREEN_HEIGHT - INFO_BAR_HEIGHT - 2) -#define GRID_WIDTH ((SCREEN_WIDTH - 2) / SNAKE_SIZE) -#define GRID_HEIGHT (GAME_AREA_HEIGHT / SNAKE_SIZE) -#define STATE_MENU 0 -#define STATE_PLAYING 1 -#define STATE_GAME_OVER 2 - -#define COLOR_BACKGROUND Black -#define COLOR_SNAKE Green -#define COLOR_FOOD Red -#define COLOR_BORDER White - -Ticker game_timer; - -int snake_x[GRID_WIDTH * GRID_HEIGHT]; -int snake_y[GRID_WIDTH * GRID_HEIGHT]; -int snake_length = 1; -int snake_dx = 1, snake_dy = 0; -int food_x, food_y; -int score = 0; -int game_state = STATE_MENU; -bool initialized = false; - -extern ui::Painter painter; - -void init_game(); -void update_game(); -void draw_screen(); -void draw_snake(); -void draw_full_snake(); -void erase_tail(int x, int y); -void draw_food(); -void erase_food(); -void draw_score(); -void draw_borders(); -void spawn_food(); -bool check_collision(); -void show_menu(); -void show_game_over(); - -void game_timer_check() { - if (game_state == STATE_PLAYING) { - update_game(); - } -} - -void init_game() { - claim(stdout); - set_orientation(2); - set_font((unsigned char*)Arial12x12); - snake_x[0] = GRID_WIDTH / 2; - snake_y[0] = GRID_HEIGHT / 2; - snake_length = 1; - snake_dx = 1; - snake_dy = 0; - score = 0; - spawn_food(); - if (game_state == STATE_MENU) { - show_menu(); - } else if (game_state == STATE_PLAYING) { - draw_screen(); - } -} - -void spawn_food() { - bool valid; - do { - food_x = rand() % GRID_WIDTH; - food_y = rand() % GRID_HEIGHT; - valid = true; - for (int i = 0; i < snake_length; i++) { - if (snake_x[i] == food_x && snake_y[i] == food_y) { - valid = false; - break; - } - } - } while (!valid); -} - -void update_game() { - int new_x = snake_x[0] + snake_dx; - int new_y = snake_y[0] + snake_dy; - bool ate_food = (new_x == food_x && new_y == food_y); - - int tail_x = snake_x[snake_length - 1]; - int tail_y = snake_y[snake_length - 1]; - - for (int i = snake_length - 1; i > 0; i--) { - snake_x[i] = snake_x[i - 1]; - snake_y[i] = snake_y[i - 1]; - } - - snake_x[0] = new_x; - snake_y[0] = new_y; - - if (ate_food) { - snake_x[snake_length] = tail_x; - snake_y[snake_length] = tail_y; - snake_length++; - score += 10; - spawn_food(); - draw_food(); - } else { - erase_tail(tail_x, tail_y); - } - - draw_snake(); - draw_score(); - - if (check_collision()) { - draw_borders(); - game_state = STATE_GAME_OVER; - show_game_over(); - return; - } -} - -bool check_collision() { - if (snake_x[0] < 0 || snake_x[0] >= GRID_WIDTH || snake_y[0] < 0 || snake_y[0] >= GRID_HEIGHT) { - return true; - } - for (int i = 1; i < snake_length; i++) { - if (snake_x[0] == snake_x[i] && snake_y[0] == snake_y[i]) { - return true; - } - } - return false; -} - -void draw_screen() { - cls(); - background(COLOR_BACKGROUND); - draw_borders(); - draw_full_snake(); - draw_food(); - draw_score(); -} - -void draw_snake() { - fillrect(1 + snake_x[0] * SNAKE_SIZE, GAME_AREA_TOP + snake_y[0] * SNAKE_SIZE, - 1 + snake_x[0] * SNAKE_SIZE + SNAKE_SIZE, GAME_AREA_TOP + snake_y[0] * SNAKE_SIZE + SNAKE_SIZE, COLOR_SNAKE); -} - -void draw_full_snake() { - for (int i = 0; i < snake_length; i++) { - fillrect(1 + snake_x[i] * SNAKE_SIZE, GAME_AREA_TOP + snake_y[i] * SNAKE_SIZE, - 1 + snake_x[i] * SNAKE_SIZE + SNAKE_SIZE, GAME_AREA_TOP + snake_y[i] * SNAKE_SIZE + SNAKE_SIZE, COLOR_SNAKE); - } -} - -void erase_tail(int x, int y) { - fillrect(1 + x * SNAKE_SIZE, GAME_AREA_TOP + y * SNAKE_SIZE, - 1 + x * SNAKE_SIZE + SNAKE_SIZE, GAME_AREA_TOP + y * SNAKE_SIZE + SNAKE_SIZE, COLOR_BACKGROUND); -} - -void draw_food() { - fillrect(1 + food_x * SNAKE_SIZE, GAME_AREA_TOP + food_y * SNAKE_SIZE, - 1 + food_x * SNAKE_SIZE + SNAKE_SIZE, GAME_AREA_TOP + food_y * SNAKE_SIZE + SNAKE_SIZE, COLOR_FOOD); -} - -void erase_food() { - fillrect(1 + food_x * SNAKE_SIZE, GAME_AREA_TOP + food_y * SNAKE_SIZE, - 1 + food_x * SNAKE_SIZE + SNAKE_SIZE, GAME_AREA_TOP + food_y * SNAKE_SIZE + SNAKE_SIZE, COLOR_BACKGROUND); -} - -void draw_score() { - auto style = *ui::Theme::getInstance()->fg_blue; - painter.draw_string({5, 5}, style, "Score: " + std::to_string(score)); -} - -void draw_borders() { - rect(0, GAME_AREA_TOP - 1, SCREEN_WIDTH, GAME_AREA_TOP, COLOR_BORDER); - rect(0, GAME_AREA_TOP, SCREEN_WIDTH, SCREEN_HEIGHT, COLOR_BORDER); -} - -void show_menu() { - cls(); - background(COLOR_BACKGROUND); - auto style_yellow = *ui::Theme::getInstance()->fg_yellow; - auto style_green = *ui::Theme::getInstance()->fg_green; - auto style_blue = *ui::Theme::getInstance()->fg_blue; - painter.draw_string({50, 40}, style_yellow, "* * * SNAKE * * *"); - painter.draw_string({0, 120}, style_blue, "USE THE D-PAD TO MOVE"); - painter.draw_string({0, 150}, style_blue, "EAT THE RED SQUARES TO GROW"); - painter.draw_string({0, 180}, style_blue, "DON'T HIT THE WALLS OR SELF"); - painter.draw_string({15, 240}, style_green, "** PRESS SELECT TO START **"); -} - -void show_game_over() { - cls(); - background(COLOR_BACKGROUND); - auto style_red = *ui::Theme::getInstance()->fg_red; - auto style_yellow = *ui::Theme::getInstance()->fg_yellow; - auto style_green = *ui::Theme::getInstance()->fg_green; - painter.draw_string({75, 90}, style_red, "GAME OVER"); - painter.draw_string({74, 150}, style_yellow, "SCORE: " + std::to_string(score)); - painter.draw_string({20, 220}, style_green, "PRESS SELECT TO RESTART"); - wait(1); -} - -int main() { - if (!initialized) { - initialized = true; - game_timer.attach(&game_timer_check, 1.0 / 5.0); - init_game(); - } - while (1) { - if (but_SELECT && (game_state == STATE_MENU || game_state == STATE_GAME_OVER)) { - game_state = STATE_PLAYING; - init_game(); - } - } -} \ No newline at end of file diff --git a/firmware/application/external/snake/ui_snake.cpp b/firmware/application/external/snake/ui_snake.cpp index d445240c9..3912c5658 100644 --- a/firmware/application/external/snake/ui_snake.cpp +++ b/firmware/application/external/snake/ui_snake.cpp @@ -10,7 +10,230 @@ namespace ui::external_app::snake { -#include "snake.cpp" +Ticker game_timer; + +int snake_x[GRID_WIDTH * GRID_HEIGHT]; +int snake_y[GRID_WIDTH * GRID_HEIGHT]; +int snake_length = 1; +int snake_dx = 1; +int snake_dy = 0; +int food_x, food_y; +int score = 0; +int game_state = STATE_MENU; +bool initialized = false; + +const Color pp_colors[] = { + Color::white(), + Color::blue(), + Color::yellow(), + Color::purple(), + Color::green(), + Color::red(), + Color::magenta(), + Color::orange(), + Color::black(), +}; + +Painter painter; + +bool but_RIGHT = false; +bool but_LEFT = false; +bool but_SELECT = false; + +static Callback game_update_callback = nullptr; +static uint32_t game_update_timeout = 0; +static uint32_t game_update_counter = 0; + +void cls() { + painter.fill_rectangle({0, 0, portapack::display.width(), portapack::display.height()}, Color::black()); +} + +void background(int color) { + (void)color; +} + +void fillrect(int x1, int y1, int x2, int y2, int color) { + painter.fill_rectangle({x1, y1, x2 - x1, y2 - y1}, pp_colors[color]); +} + +void rect(int x1, int y1, int x2, int y2, int color) { + painter.draw_rectangle({x1, y1, x2 - x1, y2 - y1}, pp_colors[color]); +} + +void check_game_timer() { + if (game_update_callback) { + if (++game_update_counter >= game_update_timeout) { + game_update_counter = 0; + game_update_callback(); + } + } +} + +void Ticker::attach(Callback func, double delay_sec) { + game_update_callback = func; + game_update_timeout = delay_sec * 60; +} + +void Ticker::detach() { + game_update_callback = nullptr; +} + +void game_timer_check() { + if (game_state == STATE_PLAYING) { + update_game(); + } +} + +void init_game() { + snake_x[0] = GRID_WIDTH / 2; + snake_y[0] = GRID_HEIGHT / 2; + snake_length = 1; + snake_dx = 1; + snake_dy = 0; + score = 0; + spawn_food(); + if (game_state == STATE_MENU) { + show_menu(); + } else if (game_state == STATE_PLAYING) { + draw_screen(); + } +} + +void spawn_food() { + bool valid; + do { + food_x = rand() % GRID_WIDTH; + food_y = rand() % GRID_HEIGHT; + valid = true; + for (int i = 0; i < snake_length; i++) { + if (snake_x[i] == food_x && snake_y[i] == food_y) { + valid = false; + break; + } + } + } while (!valid); +} + +void update_game() { + int new_x = snake_x[0] + snake_dx; + int new_y = snake_y[0] + snake_dy; + bool ate_food = (new_x == food_x && new_y == food_y); + + int tail_x = snake_x[snake_length - 1]; + int tail_y = snake_y[snake_length - 1]; + + for (int i = snake_length - 1; i > 0; i--) { + snake_x[i] = snake_x[i - 1]; + snake_y[i] = snake_y[i - 1]; + } + + snake_x[0] = new_x; + snake_y[0] = new_y; + + if (ate_food) { + snake_x[snake_length] = tail_x; + snake_y[snake_length] = tail_y; + snake_length++; + score += 10; + spawn_food(); + draw_food(); + } else { + erase_tail(tail_x, tail_y); + } + + draw_snake(); + draw_score(); + + if (check_collision()) { + draw_borders(); + game_state = STATE_GAME_OVER; + show_game_over(); + return; + } +} + +bool check_collision() { + if (snake_x[0] < 0 || snake_x[0] >= GRID_WIDTH || snake_y[0] < 0 || snake_y[0] >= GRID_HEIGHT) { + return true; + } + for (int i = 1; i < snake_length; i++) { + if (snake_x[0] == snake_x[i] && snake_y[0] == snake_y[i]) { + return true; + } + } + return false; +} + +void draw_screen() { + cls(); + background(COLOR_BACKGROUND); + draw_borders(); + draw_full_snake(); + draw_food(); + draw_score(); +} + +void draw_snake() { + fillrect(1 + snake_x[0] * SNAKE_SIZE, GAME_AREA_TOP + snake_y[0] * SNAKE_SIZE, + 1 + snake_x[0] * SNAKE_SIZE + SNAKE_SIZE, GAME_AREA_TOP + snake_y[0] * SNAKE_SIZE + SNAKE_SIZE, COLOR_SNAKE); +} + +void draw_full_snake() { + for (int i = 0; i < snake_length; i++) { + fillrect(1 + snake_x[i] * SNAKE_SIZE, GAME_AREA_TOP + snake_y[i] * SNAKE_SIZE, + 1 + snake_x[i] * SNAKE_SIZE + SNAKE_SIZE, GAME_AREA_TOP + snake_y[i] * SNAKE_SIZE + SNAKE_SIZE, COLOR_SNAKE); + } +} + +void erase_tail(int x, int y) { + fillrect(1 + x * SNAKE_SIZE, GAME_AREA_TOP + y * SNAKE_SIZE, + 1 + x * SNAKE_SIZE + SNAKE_SIZE, GAME_AREA_TOP + y * SNAKE_SIZE + SNAKE_SIZE, COLOR_BACKGROUND); +} + +void draw_food() { + fillrect(1 + food_x * SNAKE_SIZE, GAME_AREA_TOP + food_y * SNAKE_SIZE, + 1 + food_x * SNAKE_SIZE + SNAKE_SIZE, GAME_AREA_TOP + food_y * SNAKE_SIZE + SNAKE_SIZE, COLOR_FOOD); +} + +void erase_food() { + fillrect(1 + food_x * SNAKE_SIZE, GAME_AREA_TOP + food_y * SNAKE_SIZE, + 1 + food_x * SNAKE_SIZE + SNAKE_SIZE, GAME_AREA_TOP + food_y * SNAKE_SIZE + SNAKE_SIZE, COLOR_BACKGROUND); +} + +void draw_score() { + auto style = *ui::Theme::getInstance()->fg_blue; + painter.draw_string({5, 5}, style, "Score: " + std::to_string(score)); +} + +void draw_borders() { + rect(0, GAME_AREA_TOP - 1, SCREEN_WIDTH, GAME_AREA_TOP, COLOR_BORDER); + rect(0, GAME_AREA_TOP, SCREEN_WIDTH, SCREEN_HEIGHT, COLOR_BORDER); +} + +void show_menu() { + cls(); + background(COLOR_BACKGROUND); + auto style_yellow = *ui::Theme::getInstance()->fg_yellow; + auto style_green = *ui::Theme::getInstance()->fg_green; + auto style_blue = *ui::Theme::getInstance()->fg_blue; + painter.draw_string({50, 40}, style_yellow, "* * * SNAKE * * *"); + painter.draw_string({0, 120}, style_blue, "USE THE D-PAD TO MOVE"); + painter.draw_string({0, 150}, style_blue, "EAT THE RED SQUARES TO GROW"); + painter.draw_string({0, 180}, style_blue, "DON'T HIT THE WALLS OR SELF"); + painter.draw_string({15, 240}, style_green, "** PRESS SELECT TO START **"); +} + +void show_game_over() { + cls(); + background(COLOR_BACKGROUND); + auto style_red = *ui::Theme::getInstance()->fg_red; + auto style_yellow = *ui::Theme::getInstance()->fg_yellow; + auto style_green = *ui::Theme::getInstance()->fg_green; + painter.draw_string({75, 90}, style_red, "GAME OVER"); + painter.draw_string({74, 150}, style_yellow, "SCORE: " + std::to_string(score)); + painter.draw_string({20, 220}, style_green, "PRESS SELECT TO RESTART"); + wait(1); +} SnakeView::SnakeView(NavigationView& nav) : nav_{nav} { diff --git a/firmware/application/external/snake/ui_snake.hpp b/firmware/application/external/snake/ui_snake.hpp index 22fef7466..70be2af90 100644 --- a/firmware/application/external/snake/ui_snake.hpp +++ b/firmware/application/external/snake/ui_snake.hpp @@ -9,23 +9,105 @@ #ifndef __UI_SNAKE_H__ #define __UI_SNAKE_H__ +#include "ui.hpp" #include "ui_navigation.hpp" #include "event_m0.hpp" #include "message.hpp" #include "irq_controls.hpp" #include "random.hpp" #include "lpc43xx_cpp.hpp" -#include "limits.h" #include "ui_widget.hpp" namespace ui::external_app::snake { +enum { + White, + Blue, + Yellow, + Purple, + Green, + Red, + Maroon, + Orange, + Black, +}; + +extern const Color pp_colors[]; +extern Painter painter; +extern bool but_RIGHT; +extern bool but_LEFT; +extern bool but_SELECT; + +void cls(); +void background(int color); +void fillrect(int x1, int y1, int x2, int y2, int color); +void rect(int x1, int y1, int x2, int y2, int color); + +#define wait(x) chThdSleepMilliseconds(x * 1000) + +using Callback = void (*)(void); + +class Ticker { + public: + Ticker() = default; + void attach(Callback func, double delay_sec); + void detach(); +}; + +#define SCREEN_WIDTH 240 +#define SCREEN_HEIGHT 320 +#define SNAKE_SIZE 10 +#define INFO_BAR_HEIGHT 25 +#define GAME_AREA_TOP (INFO_BAR_HEIGHT + 1) +#define GAME_AREA_HEIGHT (SCREEN_HEIGHT - INFO_BAR_HEIGHT - 2) +#define GRID_WIDTH ((SCREEN_WIDTH - 2) / SNAKE_SIZE) +#define GRID_HEIGHT (GAME_AREA_HEIGHT / SNAKE_SIZE) +#define STATE_MENU 0 +#define STATE_PLAYING 1 +#define STATE_GAME_OVER 2 + +#define COLOR_BACKGROUND Black +#define COLOR_SNAKE Green +#define COLOR_FOOD Red +#define COLOR_BORDER White + +extern Ticker game_timer; + +extern int snake_x[GRID_WIDTH * GRID_HEIGHT]; +extern int snake_y[GRID_WIDTH * GRID_HEIGHT]; +extern int snake_length; +extern int snake_dx; +extern int snake_dy; +extern int food_x; +extern int food_y; +extern int score; +extern int game_state; +extern bool initialized; + +void game_timer_check(); +void init_game(); +void update_game(); +void draw_screen(); +void draw_snake(); +void draw_full_snake(); +void erase_tail(int x, int y); +void draw_food(); +void erase_food(); +void draw_score(); +void draw_borders(); +void spawn_food(); +bool check_collision(); +void show_menu(); +void show_game_over(); + class SnakeView : public View { public: SnakeView(NavigationView& nav); void on_show() override; - std::string title() const override { return "Snake"; }; - void focus() override { dummy.focus(); }; + + std::string title() const override { return "Snake"; } + + void focus() override { dummy.focus(); } void paint(Painter& painter) override; void frame_sync(); bool on_key(KeyEvent key) override; @@ -33,9 +115,11 @@ class SnakeView : public View { private: bool initialized = false; NavigationView& nav_; + Button dummy{ {240, 0, 0, 0}, ""}; + MessageHandlerRegistration message_handler_frame_sync{ Message::ID::DisplayFrameSync, [this](const Message* const) { @@ -45,4 +129,4 @@ class SnakeView : public View { } // namespace ui::external_app::snake -#endif /*__UI_SNAKE_H__*/ \ No newline at end of file +#endif /* __UI_SNAKE_H__ */ \ No newline at end of file