Fix sidebar layout: sidebar on left (320px), spectrogram on right. SPACE toggles play/stop. dB floor triggers immediate redraw.

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