feat: scope toggle collapses the divider; drag handle to show/hide
Toggling the scope off (P) now drops the divider to the bottom so the spectrogram fills the whole view, instead of leaving an empty gap. The divider handle is always drawn and grabbable: drag it up from the bottom to bring the scope back, or drag it down past ~88% to hide it. Layout uses an effective-divider helper (1.0 when hidden) so all three layout sites stay in sync. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+38
-22
@@ -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";
|
||||
|
||||
Reference in New Issue
Block a user