diff options
| author | raven <citrons@mondecitronne.com> | 2026-04-10 15:57:46 -0500 |
|---|---|---|
| committer | raven <citrons@mondecitronne.com> | 2026-04-10 15:57:46 -0500 |
| commit | eea6a7df4a4110db7daa572d304caed7a8d476e0 (patch) | |
| tree | 3adadc866ea0a467fc5810d5e341e29a67411d08 | |
| parent | c8a89507bc62ea54c5789274c163409fd0147c97 (diff) | |
make context menu scrollable
| -rw-r--r-- | src/menu.c | 43 | ||||
| -rw-r--r-- | src/menu.h | 2 |
2 files changed, 39 insertions, 6 deletions
@@ -23,8 +23,9 @@ menu *create_menu(menu_entry *entries, int count, int x, int y) { menu *m = calloc(1, sizeof(menu)); if (!m) panic("out of memory"); + x += 2; y -= 8; m->window = must(SDL_CreatePopupWindow(window, - x + 2, y - 8, 0, 0, SDL_WINDOW_POPUP_MENU | SDL_WINDOW_BORDERLESS + x, y, 0, 0, SDL_WINDOW_POPUP_MENU | SDL_WINDOW_BORDERLESS )); m->renderer = must(SDL_CreateRenderer(m->window, NULL)); @@ -33,7 +34,7 @@ menu *create_menu(menu_entry *entries, int count, int x, int y) { m->textures = calloc(count, sizeof(SDL_Texture *)); if (!m->textures) panic("out of memory"); - int w = 0, h = 0; + int w = MENU_PADDING, h = MENU_PADDING; for (int i = 0; i < count; i++) { SDL_Color color = {0xff, 0xff, 0xff, 0xff}; SDL_Surface *text = @@ -44,7 +45,27 @@ menu *create_menu(menu_entry *entries, int count, int x, int y) { w = SDL_max(w, tw); h += th; } - SDL_SetWindowSize(m->window, w + MENU_PADDING * 2, h + MENU_PADDING * 2); + w += MENU_PADDING; h += MENU_PADDING; + m->height = h; + + int px, py; + must(SDL_GetWindowPosition(window, &px, &py)); + SDL_Rect disp; + must( + SDL_GetDisplayUsableBounds(SDL_GetDisplayForWindow(m->window), &disp) + ); + if (py + y + h > disp.h) { + y = disp.h - h - py; + y = SDL_max(y, disp.y - py); + } + if (px + x + w > disp.w) { + x = disp.w - w - px; + x = SDL_max(x, disp.x - px); + } + h = SDL_min(h, disp.h); + SDL_WarpMouseInWindow(window, x - 2, y + 8); + SDL_SetWindowPosition(m->window, x, y); + SDL_SetWindowSize(m->window, w, h); SDL_RaiseWindow(m->window); SDL_SyncWindow(m->window); return m; @@ -52,6 +73,16 @@ menu *create_menu(menu_entry *entries, int count, int x, int y) { bool menu_handle_event(menu *m, SDL_Event e) { switch (e.type) { + case SDL_EVENT_MOUSE_WHEEL: + if (e.wheel.windowID != SDL_GetWindowID(m->window)) { + break; + } + int w, h; + SDL_GetWindowSize(m->window, &w, &h); + m->scroll += -e.wheel.y * 15; + m->scroll = SDL_max(m->scroll, 0); + m->scroll = SDL_min(m->scroll, m->height - h); + break; case SDL_EVENT_WINDOW_CLOSE_REQUESTED: if (e.window.windowID == SDL_GetWindowID(m->window)) return false; @@ -64,7 +95,7 @@ bool menu_handle_event(menu *m, SDL_Event e) { if (e.button.windowID != SDL_GetWindowID(m->window)) { break; } - int option = option_at(m, e.button.x, e.button.y); + int option = option_at(m, e.button.x, e.button.y + m->scroll); if (option != -1) { m->entries[option].action(m->entries[option].data); return false; @@ -87,11 +118,11 @@ void menu_render(menu *m) { SDL_GetMouseState(&mx, &my); int hovered = -1; if (SDL_GetWindowFlags(m->window) & SDL_WINDOW_MOUSE_FOCUS) - hovered = option_at(m, mx, my); + hovered = option_at(m, mx, my + m->scroll); SDL_SetRenderDrawColor(m->renderer, 0x00, 0x00, 0x00, 0xff); SDL_RenderClear(m->renderer); - float x = MENU_PADDING, y = MENU_PADDING; + float x = MENU_PADDING, y = MENU_PADDING - SDL_floor(m->scroll); for (int i = 0; i < m->count; i++) { SDL_FRect dst; dst.x = x; @@ -16,6 +16,8 @@ typedef struct menu { menu_entry *entries; SDL_Texture **textures; int count; + float height; + float scroll; } menu; menu *create_menu(menu_entry *entries, int count, int x, int y); |
