From 629bd46b437e700a7d83fc73a60b0b6776f346c7 Mon Sep 17 00:00:00 2001 From: Milk-Cool Date: Sat, 16 Sep 2023 18:29:44 +0300 Subject: [PATCH] added proper gui --- .vscode/settings.json | 3 +- Makefile | 2 +- README.md | 7 ++-- flipper/furi.h | 1 - flipper/gui/gui.c | 81 +++++++++++++++++++++++++++--------------- flipper/gui/gui.h | 2 ++ helpers/crash.c | 5 ++- images/screenshot.png | Bin 0 -> 4020 bytes index.js | 3 +- 9 files changed, 65 insertions(+), 39 deletions(-) create mode 100644 images/screenshot.png diff --git a/.vscode/settings.json b/.vscode/settings.json index c2989a2..8d2d14e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,7 +9,8 @@ "stdlib.h": "c", "record.h": "c", "crash.h": "c", - "unistd.h": "c" + "unistd.h": "c", + "random": "c" }, "[python]": { "editor.defaultFormatter": "ms-python.autopep8" diff --git a/Makefile b/Makefile index 394bb59..e716d79 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ CC_PREFIX_FINAL = gcc -Wall -Wno-main all: $(OUT_APP) $(OUT_APP):# $(OUT_LIB)# - $(CC_PREFIX_FINAL) -I$(LIBS) -I$(HELPERS) $(SRC_APP) $(SOURCES) -lncurses -o $(OUT_APP) + $(CC_PREFIX_FINAL) -I$(LIBS) -I$(HELPERS) $(SRC_APP) $(SOURCES) -lSDL2 -o $(OUT_APP) #$(OUT_LIB): $(OBJECTS) # ar rcs $(OUT_LIB) $(OBJECTS) diff --git a/README.md b/README.md index e704751..4d5167c 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ An emulator for the Flipper Zero\ Based on [Flipper Zero Firmware](https://github.com/flipperdevices/flipperzero-firmware) +![Screenshot](https://raw.githubusercontent.com/Milk-Cool/flippulator/main/images/screenshot.png) + ## Requirements A linux system\ Packages `make`, `gcc`, `libncurses5` @@ -12,11 +14,10 @@ Packages `make`, `gcc`, `libncurses5` ## Limitations - The main function cannot be called `main` - `furi.h` must be included -- `furi.h` includes `ncurses.h`, which reserves some function names such as `clear` and `refresh` -- Due to ncurses limitations, only the `InputTypePress` input type is supported. +- Right now, only the `InputTypePress` and `InputTypeRelease` input types are supported. ## TODOs -- [ ] Use GTK instead of ncurses +- [x] Use ~~GTK~~ SDL instead of ncurses - [ ] Write support for FuriTypes (FuriString, FuriMutex, etc.) diff --git a/flipper/furi.h b/flipper/furi.h index 543477d..8a6f794 100644 --- a/flipper/furi.h +++ b/flipper/furi.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include "core/base.h" #include "core/message_queue.h" diff --git a/flipper/gui/gui.c b/flipper/gui/gui.c index 03e1a86..ae9ed5e 100644 --- a/flipper/gui/gui.c +++ b/flipper/gui/gui.c @@ -1,12 +1,18 @@ #include "gui_i.h" #include -#include #ifdef _WIN32 #include #else #include #endif +#include + +static SDL_Renderer* renderer; +static SDL_Window* window; +static SDL_Rect rect; +static SDL_Event event; +static bool running = true; #include @@ -16,41 +22,60 @@ Gui* gui_alloc() { return gui; } +void exit_sdl(uint8_t code) { + // FIXME: crashes when exiting + // SDL_DestroyRenderer(renderer); + // SDL_DestroyWindow(window); + // SDL_Quit(); + exit(code); +} + // TODO: long presses and stuff -void* handle_input(void* _view_port) { +static void* handle_input(void* _view_port) { ViewPort* view_port = _view_port; - while(true) { - char c; - c = getch(); - InputEvent* event = malloc(sizeof(InputEvent)); - event->type = InputTypePress; - if(c == 3) event->key = InputKeyUp; - else if(c == 2) event->key = InputKeyDown; - else if(c == 4) event->key = InputKeyLeft; - else if(c == 5) event->key = InputKeyRight; - else if(c == 122) event->key = InputKeyOk; - else if(c == 120) event->key = InputKeyBack; - else if(c == 113) { - endwin(); - exit(0); + while(running) { + while(SDL_PollEvent(&event)) { + if(event.type == SDL_QUIT) exit_sdl(0); + if(event.type == SDL_KEYDOWN || event.type == SDL_KEYUP) { + InputEvent* e = malloc(sizeof(InputEvent)); + e->type = event.type == SDL_KEYDOWN ? InputTypePress : InputTypeRelease; + bool flag = true; + if(event.key.keysym.sym == SDLK_UP) e->key = InputKeyUp; + else if(event.key.keysym.sym == SDLK_DOWN) e->key = InputKeyDown; + else if(event.key.keysym.sym == SDLK_LEFT) e->key = InputKeyLeft; + else if(event.key.keysym.sym == SDLK_RIGHT) e->key = InputKeyRight; + else if(event.key.keysym.sym == SDLK_z) e->key = InputKeyOk; + else if(event.key.keysym.sym == SDLK_x) e->key = InputKeyBack; + else flag = false; + if(view_port->input_callback != NULL && flag) + view_port->input_callback(e, view_port->input_callback_context); + } } - view_port->input_callback(event, view_port->input_callback_context); } return NULL; } -void* handle_gui(void* _view_port) { +static void* handle_gui(void* _view_port) { ViewPort* view_port = _view_port; - while(true) { + while(running) { if(view_port->draw_callback != NULL) view_port->draw_callback(view_port->gui->canvas, view_port->draw_callback_context); - clear(); + + SDL_SetRenderDrawColor(renderer, 0xff, 0x82, 0x00, 0xff); + SDL_RenderClear(renderer); + SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xff); for(uint8_t x = 0; x < view_port->width; x++) for(uint8_t y = 0; y < view_port->height; y++) { - move(y, x); - printw("%c", view_port->gui->canvas->fb[view_port->gui->canvas->offset_x + x][view_port->gui->canvas->offset_y + y] == 1 ? 'X' : ' '); + if(view_port->gui->canvas->fb[view_port->gui->canvas->offset_x + x][view_port->gui->canvas->offset_y + y] != 1) + continue; + rect.x = x * 5; + rect.y = y * 5; + rect.w = 5; + rect.h = 5; + SDL_RenderDrawRect(renderer, &rect); + SDL_RenderFillRect(renderer, &rect); } - refresh(); + SDL_RenderPresent(renderer); // ~60 FPS #ifdef _WIN32 Sleep(16); // 16ms @@ -67,11 +92,11 @@ void gui_add_view_port(Gui* gui, ViewPort* view_port, GuiLayer layer) { gui->view_port = view_port; view_port->gui = gui; - initscr(); - noecho(); - cbreak(); - keypad(stdscr, TRUE); - + SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); + SDL_Init(SDL_INIT_VIDEO); + SDL_CreateWindowAndRenderer(640, 320, 0, &window, &renderer); + SDL_SetWindowTitle(window, "Flippulator"); + pthread_t draw_thread_id; pthread_create(&draw_thread_id, NULL, handle_gui, view_port); pthread_t input_thread_id; diff --git a/flipper/gui/gui.h b/flipper/gui/gui.h index f0979fa..2515975 100644 --- a/flipper/gui/gui.h +++ b/flipper/gui/gui.h @@ -26,6 +26,8 @@ typedef void (*GuiCanvasCommitCallback)( typedef struct Gui Gui; +void exit_sdl(uint8_t code); + void gui_add_view_port(Gui* gui, ViewPort* view_port, GuiLayer layer); void gui_remove_view_port(Gui* gui, ViewPort* view_port); Gui* gui_alloc(); diff --git a/helpers/crash.c b/helpers/crash.c index beac401..1049ff9 100644 --- a/helpers/crash.c +++ b/helpers/crash.c @@ -1,8 +1,7 @@ #include "crash.h" -#include +#include void crash(uint8_t code, const char* msg) { - endwin(); printf("\e[1;91mCRASHED DUE TO: %s\e[0m\r\n", msg); - exit(code); + exit_sdl(code); } \ No newline at end of file diff --git a/images/screenshot.png b/images/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..5db5ec1ee6573f2337b6550385b20be6a2dc25b4 GIT binary patch literal 4020 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 ArvLx| literal 0 HcmV?d00001 diff --git a/index.js b/index.js index 62d3dc3..0035b8b 100644 --- a/index.js +++ b/index.js @@ -36,8 +36,7 @@ const APP_COPY = "flippulator_app_copy"; int main() { furi_init(); ${manifest.entry_point}(NULL); - endwin(); - return 0; + exit_sdl(0); }`); spawn("make", [], { "cwd": process.cwd(),