From 5e7841fa76be1cca2deb15de0a9a385156bb2751 Mon Sep 17 00:00:00 2001 From: Tyler Date: Mon, 30 Mar 2026 21:07:47 -0700 Subject: [PATCH] Fix sidebar layout: sidebar on left (320px), spectrogram on right. SPACE toggles play/stop. dB floor triggers immediate redraw. Co-authored-by: Qwen-Coder --- src/spectrogram.c | 78 +++++++++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 26 deletions(-) diff --git a/src/spectrogram.c b/src/spectrogram.c index c226aa6..03c9bd3 100644 --- a/src/spectrogram.c +++ b/src/spectrogram.c @@ -103,7 +103,7 @@ typedef struct { float panStartViewStart; float panStartViewEnd; Vector2 panStartPos; - + // Cached visible texture Texture2D visibleTexture; int cachedVisibleStart; @@ -115,7 +115,7 @@ typedef struct { float amplitudeCeilingDb; ColormapType colormap; bool showGrid; - int fftSize; // Current FFT size (512-8192) + int fftSize; // Current FFT size (128-2048) // File browser state bool showFileBrowser; @@ -126,6 +126,9 @@ typedef struct { int browserScroll; int browserSelected; bool isBrowsing; + + // Playback state + bool isPlaying; } SpectrogramApp; // ============================================================================ @@ -816,12 +819,16 @@ static void DrawSelection(Rectangle bounds) static void DrawSidebar(void) { - float sidebarWidth = 280; + float sidebarWidth = 300; float x = 10; float y = 10; int fontSize = 12; bool needsRegen = false; + // Dark sidebar background + DrawRectangle(0, 0, sidebarWidth + 20, GetScreenHeight(), (Color){ 35, 35, 40, 255 }); + DrawLine(sidebarWidth + 10, 0, sidebarWidth + 10, GetScreenHeight(), GRAY); + // Title DrawText("Spectrogram Controls", x, y, 14, WHITE); y += 25; @@ -849,7 +856,7 @@ static void DrawSidebar(void) DrawSlider(dbSlider, dbValue); if (UpdateSlider(dbSlider, &dbValue)) { app.amplitudeFloorDb = -100.0f + dbValue * 80.0f; - needsRegen = true; + needsRegen = true; // Trigger immediate redraw } y += 25; @@ -894,11 +901,18 @@ static void DrawSidebar(void) // Playback Rectangle playButton = { x, y, sidebarWidth - 10, 35 }; if (CheckCollisionPointRec(GetMousePosition(), playButton) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { - PlaySelectedRegion(); + if (app.isPlaying && AudioPlaybackSound.frameCount > 0) { + StopSound(AudioPlaybackSound); + app.isPlaying = false; + } else { + PlaySelectedRegion(); + app.isPlaying = true; + } } - DrawRectangleRec(playButton, (Color){ 40, 100, 40, 255 }); - DrawRectangleLinesEx(playButton, 1, GREEN); - DrawText("PLAY Selection (SPACE)", playButton.x + 10, playButton.y + 12, fontSize, WHITE); + const char* playText = app.isPlaying ? "STOP (SPACE)" : "PLAY (SPACE)"; + DrawRectangleRec(playButton, app.isPlaying ? (Color){ 120, 40, 40, 255 } : (Color){ 40, 100, 40, 255 }); + DrawRectangleLinesEx(playButton, 1, app.isPlaying ? RED : GREEN); + DrawText(playText, playButton.x + 10, playButton.y + 12, fontSize, WHITE); y += 45; // Reset/Clear buttons @@ -937,6 +951,7 @@ static void DrawSidebar(void) if (needsRegen && app.stftComputed) { GenerateSpectrogramTexture(&app.stft, &app.spectrogramImage, &app.spectrogramTexture); + app.visibleTextureValid = false; // Force cache invalidation } } @@ -995,6 +1010,7 @@ int main(int argc, char* argv[]) app.cachedVisibleEnd = -1; app.visibleTextureValid = false; app.fftSize = FFT_SIZE_DEFAULT; + app.isPlaying = false; GenerateColormapTexture(); ScanDirectory(GetWorkingDirectory()); @@ -1050,10 +1066,11 @@ int main(int argc, char* argv[]) // View controls if (app.loaded && !app.showFileBrowser) { - Rectangle viewBounds = { 100, 50, GetScreenWidth() - 150, GetScreenHeight() - 150 }; - + // Spectrogram area is to the right of sidebar (320px) + Rectangle viewBounds = { 330, 50, GetScreenWidth() - 380, GetScreenHeight() - 150 }; + // Zoom with mouse wheel (zooms to cursor position) - if (CheckCollisionPointRec(GetMousePosition(), viewBounds)) { + if (GetMousePosition().x > 320 && CheckCollisionPointRec(GetMousePosition(), viewBounds)) { int wheel = GetMouseWheelMove(); if (wheel != 0) { // Calculate mouse position as normalized time (0-1) @@ -1117,8 +1134,16 @@ int main(int argc, char* argv[]) } } - // Keyboard shortcuts (SPACE for play, ESC for clear) - if (IsKeyPressed(KEY_SPACE) && !app.showFileBrowser) PlaySelectedRegion(); + // Keyboard shortcuts (SPACE for play/stop toggle, ESC for clear) + if (IsKeyPressed(KEY_SPACE) && !app.showFileBrowser) { + if (app.isPlaying && AudioPlaybackSound.frameCount > 0) { + StopSound(AudioPlaybackSound); + app.isPlaying = false; + } else { + PlaySelectedRegion(); + app.isPlaying = true; + } + } if (IsKeyPressed(KEY_ESCAPE)) { if (app.showFileBrowser) { @@ -1132,11 +1157,11 @@ int main(int argc, char* argv[]) } } - // Selection - Rectangle selBounds = { 100, 50, GetScreenWidth() - 150, GetScreenHeight() - 150 }; + // Selection (only when mouse is in spectrogram area, not sidebar) + Rectangle selBounds = { 330, 50, GetScreenWidth() - 380, GetScreenHeight() - 150 }; Vector2 mousePos = GetMousePosition(); - if (app.loaded && !app.showFileBrowser && CheckCollisionPointRec(mousePos, selBounds)) { + if (app.loaded && !app.showFileBrowser && mousePos.x > 320 && CheckCollisionPointRec(mousePos, selBounds)) { bool shiftHeld = IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT); if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) && !app.isPanning) { @@ -1194,9 +1219,13 @@ int main(int argc, char* argv[]) BeginDrawing(); ClearBackground((Color){ 30, 30, 30, 255 }); - Rectangle viewBounds = { 100, 50, GetScreenWidth() - 150, GetScreenHeight() - 150 }; + // Spectrogram area is to the right of sidebar (320px) + Rectangle viewBounds = { 330, 50, GetScreenWidth() - 380, GetScreenHeight() - 150 }; - // Draw spectrogram first (background) + // Draw sidebar first (on top left) + DrawSidebar(); + + // Draw spectrogram (background, in its own area) if (app.loaded && app.stftComputed) { // Calculate visible region @@ -1247,21 +1276,18 @@ int main(int argc, char* argv[]) DrawText(TextFormat("Frequency (Hz) - Max: %d", app.signal.sampleRate / 2), viewBounds.x - 50, viewBounds.y + viewBounds.height / 2 - 10, 14, Fade(LIGHTGRAY, 0.7f)); } else if (!app.showFileBrowser) { - const char* msg1 = "Press 'O' for file browser or drag & drop WAV"; - const char* msg2 = "Or use command line: ./rspektrum "; + const char* msg1 = "Press 'O' or click 'Open File Browser' to load a WAV"; + const char* msg2 = "Or drag & drop a file, or use: ./rspektrum "; Vector2 t1 = MeasureTextEx(GetFontDefault(), msg1, 24, 0); Vector2 t2 = MeasureTextEx(GetFontDefault(), msg2, 18, 0); - DrawText(msg1, GetScreenWidth() / 2 - t1.x / 2, GetScreenHeight() / 2 - t1.y / 2 - 15, 24, LIGHTGRAY); - DrawText(msg2, GetScreenWidth() / 2 - t2.x / 2, GetScreenHeight() / 2 - t2.y / 2 + 15, 18, GRAY); + DrawText(msg1, 350 + (GetScreenWidth() - 380 - 350) / 2 - t1.x / 2, GetScreenHeight() / 2 - t1.y / 2 - 15, 24, LIGHTGRAY); + DrawText(msg2, 350 + (GetScreenWidth() - 380 - 350) / 2 - t2.x / 2, GetScreenHeight() / 2 - t2.y / 2 + 15, 18, GRAY); } // Draw file browser on top (if active) if (app.showFileBrowser) DrawFileBrowser(); - // Draw sidebar controls - DrawSidebar(); - - // Draw FPS + // Draw FPS in spectrogram area DrawFPS(GetScreenWidth() - 80, 10); EndDrawing(); }