summaryrefslogtreecommitdiff
path: root/src/menu.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/menu.c')
-rw-r--r--src/menu.c121
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);
+}