diff --git a/src/spectrogram.c b/src/spectrogram.c index 0bd7250..76387b8 100644 --- a/src/spectrogram.c +++ b/src/spectrogram.c @@ -53,6 +53,15 @@ static bool IsUserInteracting(void) return false; } +// Fraction of the view area used by the spectrogram. When the scope is hidden +// the spectrogram fills the whole area (divider at the bottom); otherwise the +// scope takes the remainder below dividerY. +#define SCOPE_COLLAPSE_DIVIDER 0.88f // drag the handle past this to hide the scope +static float ScopeDivider(void) +{ + return app.showScope ? app.dividerY : 1.0f; +} + // Reset all per-signal state after a new signal has been loaded into app.signal. // Drops the cached STFT/FFT-size cache and the on-screen textures so the main // loop recomputes from scratch (loadingPhase 0 handles the STFT (re)alloc). @@ -260,7 +269,7 @@ int main(int argc, char* argv[]) float topMargin = 50 * viewScale; float bottomMargin = 10 * viewScale; - float spectroHeight = (GetScreenHeight() - topMargin - bottomMargin - labelHeight - scrollbarHeight - 10 * viewScale) * app.dividerY; + float spectroHeight = (GetScreenHeight() - topMargin - bottomMargin - labelHeight - scrollbarHeight - 10 * viewScale) * ScopeDivider(); Rectangle viewBounds = { sidebarWidth + freqLabelWidth, topMargin, @@ -478,7 +487,7 @@ int main(int argc, char* argv[]) float selTopMargin = 50 * selScale; float selBottomMargin = 10 * selScale; - float selSpectroHeight = (GetScreenHeight() - selTopMargin - selBottomMargin - selLabelHeight - selScrollbarHeight - 10.0f * selScale) * app.dividerY; + float selSpectroHeight = (GetScreenHeight() - selTopMargin - selBottomMargin - selLabelHeight - selScrollbarHeight - 10.0f * selScale) * ScopeDivider(); Rectangle selBounds = { selSidebarWidth + selFreqLabelWidth, selTopMargin, @@ -628,28 +637,28 @@ int main(int argc, char* argv[]) } } - // Handle divider drag - if (app.loaded && app.showScope && !app.showFileBrowser && !app.showAbout) { - // Calculate divider position (using same calculation as selBounds) - float viewScale = GetUIScale(); - float topMargin = 50 * viewScale; - float bottomMargin = 10 * viewScale; - float labelHeight = 15 * viewScale; - float scrollbarHeight = 18 * viewScale; - float totalHeight = GetScreenHeight() - topMargin - bottomMargin - labelHeight - scrollbarHeight; - - // Check if mouse is near divider + // Handle divider drag. Works whether or not the scope is currently shown + // (when hidden, the handle sits at the bottom and can be dragged back up). + if (app.loaded && !app.showFileBrowser && !app.showAbout) { + // Grab the handle. The starting position is the *effective* divider, + // which is the bottom of the view (1.0) while the scope is hidden. if (mouseNearDivider && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { app.isDividing = true; app.dividerStartPos = mousePos; - app.dividerStartY = app.dividerY; + app.dividerStartY = ScopeDivider(); } if (app.isDividing && IsMouseButtonDown(MOUSE_LEFT_BUTTON)) { - float dy = (mousePos.y - app.dividerStartPos.y) / GetScreenHeight(); - app.dividerY = app.dividerStartY + dy; - // Clamp to reasonable range: 0.3 to 0.8 (30% to 80% for spectrogram) - if (app.dividerY < 0.3f) app.dividerY = 0.3f; - if (app.dividerY > 0.8f) app.dividerY = 0.8f; + float d = app.dividerStartY + (mousePos.y - app.dividerStartPos.y) / GetScreenHeight(); + if (d >= SCOPE_COLLAPSE_DIVIDER) { + // Dragged (almost) to the bottom — hide the scope. + app.showScope = false; + } else { + // Otherwise the scope is shown; clamp the split to 30%..80%. + if (d < 0.3f) d = 0.3f; + if (d > 0.8f) d = 0.8f; + app.showScope = true; + app.dividerY = d; + } } if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) { app.isDividing = false; @@ -767,7 +776,7 @@ int main(int argc, char* argv[]) float bottomMargin = 10 * renderScale; // Spectrogram area (excludes labels and scrollbars) - float spectroHeight = (GetScreenHeight() - topMargin - bottomMargin - labelHeight - scrollbarHeight - 10 * renderScale) * app.dividerY; + float spectroHeight = (GetScreenHeight() - topMargin - bottomMargin - labelHeight - scrollbarHeight - 10 * renderScale) * ScopeDivider(); Rectangle viewBounds = { sidebarWidth + freqLabelWidth, topMargin, @@ -933,8 +942,9 @@ int main(int argc, char* argv[]) DrawTextScaled("Waveform (Time/Amplitude)", viewBounds.x, app.scopeView.y - 20, 14, LIGHTGRAY); } - // Draw divider line between spectrogram and scope - if (app.showScope && app.loaded) { + // Draw divider line + handle. Always shown (even when the scope is + // hidden) so the handle can be grabbed at the bottom to bring it back. + if (app.loaded) { float dividerY = viewBounds.y + viewBounds.height; Color dividerColor = app.isDividing ? CYAN : Fade((Color){ 180, 180, 200, 255 }, 0.7f); @@ -963,6 +973,12 @@ int main(int argc, char* argv[]) // Draw line extending from handle to edges DrawLine(viewBounds.x, (int)dividerY, handleX, (int)dividerY, dividerColor); DrawLine(handleX + handleW, (int)dividerY, viewBounds.x + viewBounds.width, (int)dividerY, dividerColor); + + // Hint that the hidden scope can be dragged back up. + if (!app.showScope && !app.isDividing) { + DrawTextScaled("drag up for scope", handleX + handleW + 8, (int)dividerY - 7, 11, + Fade(LIGHTGRAY, 0.6f)); + } } } else if (!app.showFileBrowser) { const char* msg1 = "Press 'O' or click 'Open File Browser' to load a WAV";