diff options
| author | raven <citrons@mondecitronne.com> | 2026-04-09 18:50:16 -0500 |
|---|---|---|
| committer | raven <citrons@mondecitronne.com> | 2026-04-09 18:51:00 -0500 |
| commit | 75920242a0efd749bf88fe1eb9a51946bb2a2365 (patch) | |
| tree | 0f5d35717b915b74e59161c69a722ada7b42123a /src/menu.c | |
| parent | 18a86e1038b20cb6f8922beead08dcc24ba2a4d3 (diff) | |
context menu to jump to different mappings
Diffstat (limited to 'src/menu.c')
| -rw-r--r-- | src/menu.c | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/src/menu.c b/src/menu.c new file mode 100644 index 0000000..53eeffb --- /dev/null +++ b/src/menu.c @@ -0,0 +1,121 @@ +#include <stdlib.h> +#include <SDL3/SDL.h> +#include <SDL3_ttf/SDL_ttf.h> +#include "panic.h" +#include "font.h" +#include "main.h" +#include "menu.h" + +#define MENU_PADDING 4 + +static int option_at(menu *m, int x, int y) { + float cur_y = MENU_PADDING; + for (int i = 0; i < m->count; i++) { + float tw, th; + must(SDL_GetTextureSize(m->textures[i], &tw, &th)); + cur_y += th; + if (y < cur_y) return i; + } + return -1; +} + +menu *create_menu(menu_entry *entries, int count, int x, int y) { + menu *m = calloc(1, sizeof(menu)); + if (!m) panic("out of memory"); + + m->window = must(SDL_CreatePopupWindow(window, + x + 2, y - 8, 0, 0, SDL_WINDOW_POPUP_MENU | SDL_WINDOW_BORDERLESS + )); + m->renderer = must(SDL_CreateRenderer(m->window, NULL)); + + m->entries = entries; + m->count = count; + m->textures = calloc(count, sizeof(SDL_Texture *)); + if (!m->textures) panic("out of memory"); + + int w = 0, h = 0; + for (int i = 0; i < count; i++) { + SDL_Color color = {0xff, 0xff, 0xff, 0xff}; + SDL_Surface *text = + must(TTF_RenderText_Blended(font, m->entries[i].name, 0, color)); + m->textures[i] = must(SDL_CreateTextureFromSurface(m->renderer, text)); + float tw, th; + must(SDL_GetTextureSize(m->textures[i], &tw, &th)); + w = SDL_max(w, tw); + h += th; + } + SDL_SetWindowSize(m->window, w + MENU_PADDING * 2, h + MENU_PADDING * 2); + SDL_RaiseWindow(m->window); + SDL_SyncWindow(m->window); + return m; +} + +bool menu_handle_event(menu *m, SDL_Event e) { + switch (e.type) { + case SDL_EVENT_WINDOW_CLOSE_REQUESTED: + if (e.window.windowID == SDL_GetWindowID(m->window)) + return false; + break; + case SDL_EVENT_MOUSE_BUTTON_DOWN: + if (e.button.windowID != SDL_GetWindowID(m->window)) { + return false; + } + case SDL_EVENT_MOUSE_BUTTON_UP: + if (e.button.windowID != SDL_GetWindowID(m->window)) { + break; + } + int option = option_at(m, e.button.x, e.button.y); + if (option != -1) { + m->entries[option].action(m->entries[option].data); + return false; + } + break; + case SDL_EVENT_KEY_DOWN: + if (e.key.key == SDLK_ESCAPE) return false; + break; + case SDL_EVENT_QUIT: + return false; + default: + } + return true; +} + +void menu_render(menu *m) { + int ww, wh; + SDL_GetWindowSize(m->window, &ww, &wh); + float mx, my; + SDL_GetMouseState(&mx, &my); + int hovered = -1; + if (SDL_GetWindowFlags(m->window) & SDL_WINDOW_MOUSE_FOCUS) + hovered = option_at(m, mx, my); + + SDL_RenderClear(m->renderer); + float x = MENU_PADDING, y = MENU_PADDING; + for (int i = 0; i < m->count; i++) { + SDL_FRect dst; + dst.x = x; + dst.y = y; + must(SDL_GetTextureSize(m->textures[i], &dst.w, &dst.h)); + if (i == hovered) { + SDL_FRect highlight_rect = {0, y, ww, dst.h}; + SDL_SetRenderDrawColor(m->renderer, 0x50, 0x50, 0x50, 0xff); + SDL_RenderFillRect(m->renderer, &highlight_rect); + SDL_SetRenderDrawColor(m->renderer, 0x00, 0x00, 0x00, 0xff); + } + SDL_RenderTexture(m->renderer, m->textures[i], NULL, &dst); + y += dst.h; + } + SDL_FRect border_rect = {0, 0, ww, wh}; + SDL_RenderRect(m->renderer, &border_rect); + SDL_RenderPresent(m->renderer); +} + +void close_menu(menu *m) { + for (int i = 0; i < m->count; i++) { + SDL_DestroyTexture(m->textures[i]); + } + free(m->textures); + SDL_DestroyRenderer(m->renderer); + SDL_DestroyWindow(m->window); + free(m); +} |
