summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorraven <citrons@mondecitronne.com>2026-04-10 15:57:46 -0500
committerraven <citrons@mondecitronne.com>2026-04-10 15:57:46 -0500
commiteea6a7df4a4110db7daa572d304caed7a8d476e0 (patch)
tree3adadc866ea0a467fc5810d5e341e29a67411d08
parentc8a89507bc62ea54c5789274c163409fd0147c97 (diff)
make context menu scrollable
-rw-r--r--src/menu.c43
-rw-r--r--src/menu.h2
2 files changed, 39 insertions, 6 deletions
diff --git a/src/menu.c b/src/menu.c
index be7595a..73b1dbd 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -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;
diff --git a/src/menu.h b/src/menu.h
index 1c6cbd1..ddc8e42 100644
--- a/src/menu.h
+++ b/src/menu.h
@@ -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);