From b72e1cef186aea3b31776d04fc958878129a0b72 Mon Sep 17 00:00:00 2001 From: Tyler Date: Fri, 5 Jun 2026 16:09:38 -0700 Subject: [PATCH] feat: scroll the sidebar controls with the mouse wheel when they overflow The left-hand control panel is laid out top-to-bottom with a running y; with annotations expanded or a short window, the bottom buttons (export, signal info, about) ran off the bottom and were unreachable. Offset the content by a sidebarScroll amount, measure the laid-out height, and let the wheel scroll it (clamped) when the cursor is over the sidebar and no modal is open. No visible scrollbar; the spectrogram's wheel-zoom already ignores the sidebar column so the two never both fire. Co-Authored-By: Claude Opus 4.8 --- src/spectrogram_types.h | 3 +++ src/ui.c | 27 +++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/spectrogram_types.h b/src/spectrogram_types.h index 65db34f..9a7e580 100644 --- a/src/spectrogram_types.h +++ b/src/spectrogram_types.h @@ -187,6 +187,9 @@ typedef struct { // Overlays bool showAbout; // About / help dialog + // Sidebar scroll offset (px), for when controls overflow a short window + float sidebarScroll; + // File browser state bool showFileBrowser; char browserPath[512]; diff --git a/src/ui.c b/src/ui.c index b043089..b85f86e 100644 --- a/src/ui.c +++ b/src/ui.c @@ -336,11 +336,15 @@ void DrawSidebar(void) float scale = GetUIScale(); float sidebarWidth = 300 * scale; float x = 10 * scale; - float y = 10 * scale; + float topMargin = 10 * scale; + // Content is laid out top-to-bottom from `y`; shift it up by the scroll + // offset so controls that overflow a short window can be reached. Clicks and + // sliders track automatically since their rects are derived from `y`. + float y = topMargin - app.sidebarScroll; int fontSize = (int)(12 * scale); bool needsRegen = false; - // Dark sidebar background + // Dark sidebar background (fixed; does not scroll) DrawRectangle(0, 0, (int)(sidebarWidth + 20 * scale), GetScreenHeight(), (Color){ 35, 35, 40, 255 }); DrawLine((int)(sidebarWidth + 10 * scale), 0, (int)(sidebarWidth + 10 * scale), GetScreenHeight(), GRAY); @@ -644,6 +648,25 @@ void DrawSidebar(void) ColorizeSpectrogram(&app.spectrogramImage, &app.spectrogramTexture); app.visibleTextureValid = false; // Force cache invalidation } + + // ---- Scroll handling ---- + // `y` now sits at the bottom of the laid-out content (in screen space). + // Its natural position (scroll == 0) is y + sidebarScroll; allow scrolling + // until that bottom, plus a small pad, reaches the window's bottom edge. + float contentBottom = y + app.sidebarScroll; + float maxScroll = contentBottom + topMargin - GetScreenHeight(); + if (maxScroll < 0) maxScroll = 0; + + // Wheel scrolls the sidebar only when the cursor is over it and no modal is + // up. The spectrogram's own wheel-zoom already ignores the sidebar column, + // so the two never both fire. + bool overSidebar = GetMousePosition().x < (sidebarWidth + 20 * scale); + if (overSidebar && !UiModalOpen()) { + float wheel = GetMouseWheelMove(); + if (wheel != 0.0f) app.sidebarScroll -= wheel * 40 * scale; + } + if (app.sidebarScroll > maxScroll) app.sidebarScroll = maxScroll; + if (app.sidebarScroll < 0.0f) app.sidebarScroll = 0.0f; } static void DrawSlider(Rectangle bounds, float value)