#include #include #include #include #include "Common.h" #include "common/Common.h" #include "debug/debug_overlay.h" #include "hal/u8g2_hal_sdl.h" #include "model/AppContext.h" #include "ui/Device.h" #include "ui/UIWidget.h" #include "ui/widgets/Button.h" #include "ui/widgets/D_Pad.h" constexpr unsigned int WINDOW_WIDTH = (U8G2_SCREEN_WIDTH * U8G2_SCREEN_FACTOR + 3 * U8G2_SCREEN_PADDING + 2 * BUTTON_WIDTH + DPAD_WIDTH + 2 * U8G2_SCREEN_PADDING); constexpr unsigned int WINDOW_HEIGHT = (U8G2_SCREEN_HEIGHT * U8G2_SCREEN_FACTOR + 50); std::shared_ptr device; std::vector> widgets; static uint64_t lastFrameTime = 0; SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) { if (SDL_Init(SDL_INIT_VIDEO) == false) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL! -> %s", SDL_GetError()); return SDL_APP_FAILURE; } if (TTF_Init() == false) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize TTF! -> %s", SDL_GetError()); return SDL_APP_FAILURE; } const auto win = CreateWindow("System Control (Simulator)", WINDOW_WIDTH, WINDOW_HEIGHT); if (!win) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window! -> %s", SDL_GetError()); return SDL_APP_FAILURE; } SDL_SetRenderVSync(win->renderer(), SDL_RENDERER_VSYNC_ADAPTIVE); SDL_SetWindowPosition(win->window(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); SDL_ShowWindow(win->window()); const auto context = new AppContext(win); *appstate = context; device = std::make_shared(context); widgets.push_back(device); DebugOverlay::Init(context); return SDL_APP_CONTINUE; } SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) { const auto context = static_cast(appstate); DebugOverlay::Update(context, event); switch (event->type) { case SDL_EVENT_WINDOW_CLOSE_REQUESTED: /// multi window if (SDL_GetWindowID(context->MainWindow()) == event->window.windowID) { return SDL_APP_SUCCESS; } break; case SDL_EVENT_QUIT: /// single window application return SDL_APP_SUCCESS; case SDL_EVENT_KEY_DOWN: switch (event->key.key) { case SDLK_ESCAPE: return SDL_APP_SUCCESS; case SDLK_UP: device->OnButtonClicked(ButtonType::UP); break; case SDLK_DOWN: device->OnButtonClicked(ButtonType::DOWN); break; case SDLK_LEFT: device->OnButtonClicked(ButtonType::LEFT); break; case SDLK_RIGHT: device->OnButtonClicked(ButtonType::RIGHT); break; case SDLK_RETURN: device->OnButtonClicked(ButtonType::SELECT); break; case SDLK_BACKSPACE: device->OnButtonClicked(ButtonType::BACK); break; default: break; } break; case SDL_EVENT_KEY_UP: if (event->key.key == SDLK_LSHIFT) { DebugOverlay::show_debug_window = !DebugOverlay::show_debug_window; } break; case SDL_EVENT_MOUSE_MOTION: break; case SDL_EVENT_MOUSE_BUTTON_DOWN: if (event->button.button == SDL_BUTTON_LEFT) { device->HandleTap(&event->button); } break; case SDL_EVENT_MOUSE_BUTTON_UP: if (event->button.button == SDL_BUTTON_LEFT) { device->ReleaseTap(&event->button); } default: { if (DebugOverlay::show_unhandled_events) { SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Unused event: %d", event->type); } } break; } // return continue to continue return SDL_APP_CONTINUE; } SDL_AppResult SDL_AppIterate(void *appstate) { const auto context = static_cast(appstate); /// render main window SDL_SetRenderDrawColor(context->MainRenderer(), 0, 0, 0, 255); SDL_RenderClear(context->MainRenderer()); const uint64_t currentTime = SDL_GetTicks(); uint64_t dt = 0; if (lastFrameTime > 0) { dt = currentTime - lastFrameTime; } lastFrameTime = currentTime; for (const auto &widget : widgets) { widget->Render(dt); } DebugOverlay::Render(context); SDL_RenderPresent(context->MainRenderer()); /// render led matrix context->Render(); return SDL_APP_CONTINUE; } void SDL_AppQuit(void *appstate, SDL_AppResult result) { DebugOverlay::Cleanup(); free(appstate); // SDL will clean up the window/renderer for us. TTF_Quit(); }