From 53f7fa6047f296f63573abd1672d5b7d7bf37148 Mon Sep 17 00:00:00 2001 From: Tyler Date: Mon, 25 May 2026 08:59:08 -0700 Subject: [PATCH] refactor: extract Clicked() + DrawPanelBox() sidebar widget helpers Collapse the repeated 'CheckCollisionPointRec + IsMouseButtonPressed' click test and the 'DrawRectangleRec + DrawRectangleLinesEx' panel chrome into two helpers used across the sidebar buttons. Pure readability; render output is pixel-identical (verified AE=0 vs baseline). Co-Authored-By: Claude Opus 4.7 --- src/ui.c | 74 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/src/ui.c b/src/ui.c index 2b31b50..b807fab 100644 --- a/src/ui.c +++ b/src/ui.c @@ -14,6 +14,19 @@ static void DrawSlider(Rectangle bounds, float value); static bool UpdateSlider(Rectangle bounds, float* value); +// True if the rect was left-clicked this frame (hovered + button pressed). +static bool Clicked(Rectangle r) +{ + return CheckCollisionPointRec(GetMousePosition(), r) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON); +} + +// The ubiquitous "filled rectangle + 1px border" panel/button chrome. +static void DrawPanelBox(Rectangle r, Color fill, Color border) +{ + DrawRectangleRec(r, fill); + DrawRectangleLinesEx(r, 1, border); +} + // ===== File browser ===== void FreeBrowserFiles(void) { @@ -335,35 +348,32 @@ void DrawSidebar(void) DrawTextScaled(TextFormat("FFT: %d (%.1f Hz/bin)", app.fftSize, (float)app.signal.sampleRate / app.fftSize), x, y, 14, LIGHTGRAY); y += 20 * scale; Rectangle fftMinus = { x, y, 30 * scale, 25 * scale }; Rectangle fftPlus = { x + sidebarWidth - 40 * scale, y, 30 * scale, 25 * scale }; - if (CheckCollisionPointRec(GetMousePosition(), fftMinus) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { + if (Clicked(fftMinus)) { int newFFT = app.fftSize / 2; if (newFFT >= FFT_SIZE_MIN) { ChangeFFTSize(newFFT); } } - if (CheckCollisionPointRec(GetMousePosition(), fftPlus) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { + if (Clicked(fftPlus)) { int newFFT = app.fftSize * 2; if (newFFT <= FFT_SIZE_MAX) { ChangeFFTSize(newFFT); } } - DrawRectangleRec(fftMinus, (Color){ 50, 50, 60, 255 }); - DrawRectangleLinesEx(fftMinus, 1, GRAY); + DrawPanelBox(fftMinus, (Color){ 50, 50, 60, 255 }, GRAY); DrawTextScaled("-", fftMinus.x + 12 * scale, fftMinus.y + 5 * scale, 18, WHITE); - DrawRectangleRec(fftPlus, (Color){ 50, 50, 60, 255 }); - DrawRectangleLinesEx(fftPlus, 1, GRAY); + DrawPanelBox(fftPlus, (Color){ 50, 50, 60, 255 }, GRAY); DrawTextScaled("+", fftPlus.x + 10 * scale, fftPlus.y + 5 * scale, 18, WHITE); y += 32 * scale; // Amplitude scale mode toggle (Relative dynamic range vs Absolute dBFS) Rectangle scaleBtn = { x, y, sidebarWidth - 10 * scale, 22 * scale }; - if (CheckCollisionPointRec(GetMousePosition(), scaleBtn) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { + if (Clicked(scaleBtn)) { app.amplitudeMode = (app.amplitudeMode == SCALE_RELATIVE) ? SCALE_ABSOLUTE : SCALE_RELATIVE; AutoScaleAmplitude(&app.stft); // re-derive floor/ceiling for the new mode needsRegen = true; } - DrawRectangleRec(scaleBtn, (Color){ 50, 50, 60, 255 }); - DrawRectangleLinesEx(scaleBtn, 1, GRAY); + DrawPanelBox(scaleBtn, (Color){ 50, 50, 60, 255 }, GRAY); DrawTextScaled(app.amplitudeMode == SCALE_ABSOLUTE ? "Scale: Absolute (dBFS)" : "Scale: Relative", scaleBtn.x + 8 * scale, scaleBtn.y + 4 * scale, 13, WHITE); y += 30 * scale; @@ -395,13 +405,12 @@ void DrawSidebar(void) // Colormap dropdown DrawTextScaled("Colormap:", x, y, 14, LIGHTGRAY); y += 20 * scale; Rectangle cmapButton = { x, y, sidebarWidth - 10 * scale, 25 * scale }; - if (CheckCollisionPointRec(GetMousePosition(), cmapButton) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { + if (Clicked(cmapButton)) { app.colormap = (ColormapType)((app.colormap + 1) % COLORMAP_COUNT); GenerateColormapTexture(); needsRegen = true; } - DrawRectangleRec(cmapButton, (Color){ 50, 50, 60, 255 }); - DrawRectangleLinesEx(cmapButton, 1, GRAY); + DrawPanelBox(cmapButton, (Color){ 50, 50, 60, 255 }, GRAY); DrawTextScaled(ColormapName(app.colormap), cmapButton.x + 10 * scale, cmapButton.y + 6 * scale, 14, WHITE); DrawTexturePro(colormapTexture, (Rectangle){ 0, 0, 256, 1 }, (Rectangle){ cmapButton.x + cmapButton.width - 60 * scale, cmapButton.y + 5 * scale, 50 * scale, 15 * scale }, @@ -410,28 +419,26 @@ void DrawSidebar(void) // Grid toggle Rectangle gridCheck = { x, y, 18 * scale, 18 * scale }; - if (CheckCollisionPointRec(GetMousePosition(), gridCheck) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { + if (Clicked(gridCheck)) { app.showGrid = !app.showGrid; } - DrawRectangleRec(gridCheck, app.showGrid ? BLUE : DARKGRAY); - DrawRectangleLinesEx(gridCheck, 1, WHITE); + DrawPanelBox(gridCheck, app.showGrid ? BLUE : DARKGRAY, WHITE); DrawTextScaled("Show Grid", x + 25 * scale, y + 2 * scale, 14, LIGHTGRAY); y += 28 * scale; // File loading DrawTextScaled("File:", x, y, 14, LIGHTGRAY); y += 20 * scale; Rectangle fileButton = { x, y, sidebarWidth - 10 * scale, 25 * scale }; - if (CheckCollisionPointRec(GetMousePosition(), fileButton) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { + if (Clicked(fileButton)) { app.showFileBrowser = true; ScanDirectory(GetWorkingDirectory()); } - DrawRectangleRec(fileButton, (Color){ 50, 50, 60, 255 }); - DrawRectangleLinesEx(fileButton, 1, GRAY); + DrawPanelBox(fileButton, (Color){ 50, 50, 60, 255 }, GRAY); DrawTextScaled("Open File Browser (O)", fileButton.x + 10 * scale, fileButton.y + 6 * scale, 14, WHITE); y += 38 * scale; // Playback Rectangle playButton = { x, y, sidebarWidth - 10 * scale, 35 * scale }; - if (CheckCollisionPointRec(GetMousePosition(), playButton) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { + if (Clicked(playButton)) { if (app.isPlaying && AudioPlaybackSound.frameCount > 0) { StopSound(AudioPlaybackSound); app.isPlaying = false; @@ -443,54 +450,50 @@ void DrawSidebar(void) } } 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); + DrawPanelBox(playButton, app.isPlaying ? (Color){ 120, 40, 40, 255 } : (Color){ 40, 100, 40, 255 }, + app.isPlaying ? RED : GREEN); DrawTextScaled(playText, playButton.x + 10 * scale, playButton.y + 12 * scale, 14, WHITE); y += 48 * scale; // Fullscreen toggle Rectangle fsButton = { x, y, sidebarWidth - 10 * scale, 25 * scale }; bool isFullscreen = IsWindowFullscreen(); - if (CheckCollisionPointRec(GetMousePosition(), fsButton) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { + if (Clicked(fsButton)) { ToggleFullscreen(); } - DrawRectangleRec(fsButton, isFullscreen ? (Color){ 40, 80, 120, 255 } : (Color){ 50, 50, 60, 255 }); - DrawRectangleLinesEx(fsButton, 1, GRAY); + DrawPanelBox(fsButton, isFullscreen ? (Color){ 40, 80, 120, 255 } : (Color){ 50, 50, 60, 255 }, GRAY); DrawTextScaled(isFullscreen ? "Exit Fullscreen (F11)" : "Fullscreen (F11)", fsButton.x + 10 * scale, fsButton.y + 6 * scale, 14, WHITE); y += 38 * scale; // Reset/Clear buttons Rectangle resetButton = { x, y, (sidebarWidth - 15 * scale) / 2, 25 * scale }; - if (CheckCollisionPointRec(GetMousePosition(), resetButton) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { + if (Clicked(resetButton)) { app.timeSelectionStart = app.viewStart; app.timeSelectionEnd = app.viewEnd; app.freqSelectionStart = 0.0f; app.freqSelectionEnd = 1.0f; } - DrawRectangleRec(resetButton, (Color){ 80, 50, 50, 255 }); - DrawRectangleLinesEx(resetButton, 1, RED); + DrawPanelBox(resetButton, (Color){ 80, 50, 50, 255 }, RED); DrawTextScaled("Reset Sel (R)", resetButton.x + 10 * scale, resetButton.y + 6 * scale, 14, WHITE); Rectangle clearButton = { x + resetButton.width + 5 * scale, y, (sidebarWidth - 15 * scale) / 2, 25 * scale }; - if (CheckCollisionPointRec(GetMousePosition(), clearButton) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { + if (Clicked(clearButton)) { app.timeSelectionStart = 0.0f; app.timeSelectionEnd = 1.0f; app.freqSelectionStart = 0.0f; app.freqSelectionEnd = 1.0f; } - DrawRectangleRec(clearButton, (Color){ 80, 50, 50, 255 }); - DrawRectangleLinesEx(clearButton, 1, RED); + DrawPanelBox(clearButton, (Color){ 80, 50, 50, 255 }, RED); DrawTextScaled("Clear (ESC)", clearButton.x + 10 * scale, clearButton.y + 6 * scale, 14, WHITE); y += 38 * scale; // Export PNG { Rectangle exportButton = { x, y, sidebarWidth - 10 * scale, 30 * scale }; - if (CheckCollisionPointRec(GetMousePosition(), exportButton) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { + if (Clicked(exportButton)) { ExportPNG(&app, app.exportDir); } - DrawRectangleRec(exportButton, (Color){ 40, 60, 80, 255 }); - DrawRectangleLinesEx(exportButton, 1, CYAN); + DrawPanelBox(exportButton, (Color){ 40, 60, 80, 255 }, CYAN); DrawTextScaled("Export PNG (E)", exportButton.x + 10 * scale, exportButton.y + 7 * scale, 14, WHITE); y += 35 * scale; @@ -518,11 +521,10 @@ void DrawSidebar(void) // About / Help button Rectangle aboutBtn = { x, y, sidebarWidth - 10 * scale, 24 * scale }; - if (CheckCollisionPointRec(GetMousePosition(), aboutBtn) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { + if (Clicked(aboutBtn)) { app.showAbout = true; } - DrawRectangleRec(aboutBtn, (Color){ 50, 50, 60, 255 }); - DrawRectangleLinesEx(aboutBtn, 1, GRAY); + DrawPanelBox(aboutBtn, (Color){ 50, 50, 60, 255 }, GRAY); DrawTextScaled("About / Help (F1)", aboutBtn.x + 8 * scale, aboutBtn.y + 5 * scale, 13, WHITE); y += 30 * scale;