refactor: group selection state into a Selection sub-struct + ClearSelection()

The box-selection state was 11 fields spread across three comment blocks
(time sel, freq sel, drag state). Consolidate them into one Selection
sub-struct (app.sel.*) and extract the 4-line 'clear to full range' block —
duplicated in 5 places — into a ClearSelection() helper.

Pure mechanical rename (anchored to app./spa-> so the ScopeView fields of the
same name are untouched) + behavior-identical dedup. Fully-settled render
verified pixel-identical (AE=0).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-25 09:15:50 -07:00
parent ab7a6bc71c
commit 8e4250ae63
5 changed files with 103 additions and 107 deletions
+52 -62
View File
@@ -120,8 +120,7 @@ void ResetForNewSignal(void)
// Reset view + selection to full range.
app.viewStart = 0.0f; app.viewEnd = 1.0f;
app.timeSelectionStart = 0.0f; app.timeSelectionEnd = 1.0f;
app.freqSelectionStart = 0.0f; app.freqSelectionEnd = 1.0f;
ClearSelection();
// Invalidate the cached visible texture.
if (app.visibleTexture.id != 0) UnloadTexture(app.visibleTexture);
@@ -223,8 +222,8 @@ int main(int argc, char* argv[])
TraceLog(LOG_WARNING, "Failed to load TTF font, using default bitmap font");
}
app.timeSelectionStart = 0.0f; app.timeSelectionEnd = 1.0f;
app.freqSelectionStart = 0.0f; app.freqSelectionEnd = 1.0f;
app.sel.timeStart = 0.0f; app.sel.timeEnd = 1.0f;
app.sel.freqStart = 0.0f; app.sel.freqEnd = 1.0f;
app.viewStart = 0.0f; app.viewEnd = 1.0f;
app.freqViewStart = 0.0f; app.freqViewEnd = 1.0f;
app.showGrid = true;
@@ -326,7 +325,7 @@ int main(int argc, char* argv[])
}
// Track playhead position manually
app.playheadElapsed += GetFrameTime();
float selectionDuration = (app.timeSelectionEnd - app.timeSelectionStart) * app.signal.duration;
float selectionDuration = (app.sel.timeEnd - app.sel.timeStart) * app.signal.duration;
if (selectionDuration > 0) {
app.playheadT = app.playheadElapsed / selectionDuration;
}
@@ -528,10 +527,7 @@ int main(int argc, char* argv[])
app.showFileBrowser = false;
} else {
// Clear selections instead of exiting
app.timeSelectionStart = 0.0f;
app.timeSelectionEnd = 1.0f;
app.freqSelectionStart = 0.0f;
app.freqSelectionEnd = 1.0f;
ClearSelection();
}
}
@@ -556,15 +552,12 @@ int main(int argc, char* argv[])
// Right-click clears selection
if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT) && CheckCollisionPointRec(mousePos, selBounds)) {
app.timeSelectionStart = 0.0f;
app.timeSelectionEnd = 1.0f;
app.freqSelectionStart = 0.0f;
app.freqSelectionEnd = 1.0f;
ClearSelection();
}
// Check if click is inside existing selection (for dragging)
bool hasSelection = (app.timeSelectionStart > 0.001f || app.timeSelectionEnd < 0.999f ||
app.freqSelectionStart > 0.001f || app.freqSelectionEnd < 0.999f);
bool hasSelection = (app.sel.timeStart > 0.001f || app.sel.timeEnd < 0.999f ||
app.sel.freqStart > 0.001f || app.sel.freqEnd < 0.999f);
bool clickInsideSelection = false;
bool hoverInsideSelection = false;
if (hasSelection && CheckCollisionPointRec(mousePos, selBounds)) {
@@ -574,8 +567,8 @@ int main(int argc, char* argv[])
float mouseTime = app.viewStart + ((mousePos.x - selBounds.x) / selBounds.width) * viewWidth;
float mouseFreq = app.freqViewStart + (1.0f - (mousePos.y - selBounds.y) / selBounds.height) * freqWidth;
if (mouseTime >= app.timeSelectionStart && mouseTime <= app.timeSelectionEnd &&
mouseFreq >= app.freqSelectionStart && mouseFreq <= app.freqSelectionEnd) {
if (mouseTime >= app.sel.timeStart && mouseTime <= app.sel.timeEnd &&
mouseFreq >= app.sel.freqStart && mouseFreq <= app.sel.freqEnd) {
hoverInsideSelection = true;
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) {
clickInsideSelection = true;
@@ -584,7 +577,7 @@ int main(int argc, char* argv[])
}
// Set cursor based on context
if (app.isDraggingSelection) {
if (app.sel.isDragging) {
SetMouseCursor(MOUSE_CURSOR_RESIZE_ALL); // 4-way arrow while dragging
} else if (hoverInsideSelection) {
SetMouseCursor(MOUSE_CURSOR_POINTING_HAND); // Pointing hand on hover
@@ -597,7 +590,7 @@ int main(int argc, char* argv[])
// Set cursor to resize all when near divider
if (mouseNearDivider && !app.isDividing) {
SetMouseCursor(MOUSE_CURSOR_RESIZE_ALL);
} else if (app.isDraggingSelection) {
} else if (app.sel.isDragging) {
SetMouseCursor(MOUSE_CURSOR_RESIZE_ALL); // 4-way arrow while dragging
} else if (hoverInsideSelection) {
SetMouseCursor(MOUSE_CURSOR_POINTING_HAND); // Pointing hand on hover
@@ -607,85 +600,82 @@ int main(int argc, char* argv[])
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) {
if (clickInsideSelection) {
// Start dragging existing selection
app.isDraggingSelection = true;
app.dragSelectionStartPos = mousePos;
app.dragSelectionTimeStart = app.timeSelectionStart;
app.dragSelectionFreqStart = app.freqSelectionStart;
app.sel.isDragging = true;
app.sel.dragStartPos = mousePos;
app.sel.dragTimeStart = app.sel.timeStart;
app.sel.dragFreqStart = app.sel.freqStart;
} else {
// Start new box selection
app.isTimeSelecting = true;
app.isFreqSelecting = true;
app.selectStartPos = mousePos;
app.sel.isTimeSelecting = true;
app.sel.isFreqSelecting = true;
app.sel.selectStartPos = mousePos;
// Convert screen position to signal coordinates (accounting for zoom)
float viewportT = (mousePos.x - selBounds.x) / selBounds.width;
float viewportF = 1.0f - (mousePos.y - selBounds.y) / selBounds.height;
app.timeSelectionStart = Clamp(app.viewStart + viewportT * (app.viewEnd - app.viewStart), 0.0f, 1.0f);
app.timeSelectionEnd = app.timeSelectionStart;
app.freqSelectionStart = Clamp(app.freqViewStart + viewportF * (app.freqViewEnd - app.freqViewStart), 0.0f, 1.0f);
app.freqSelectionEnd = app.freqSelectionStart;
app.sel.timeStart = Clamp(app.viewStart + viewportT * (app.viewEnd - app.viewStart), 0.0f, 1.0f);
app.sel.timeEnd = app.sel.timeStart;
app.sel.freqStart = Clamp(app.freqViewStart + viewportF * (app.freqViewEnd - app.freqViewStart), 0.0f, 1.0f);
app.sel.freqEnd = app.sel.freqStart;
}
}
// Dragging existing selection
if (app.isDraggingSelection && IsMouseButtonDown(MOUSE_LEFT_BUTTON)) {
if (app.sel.isDragging && IsMouseButtonDown(MOUSE_LEFT_BUTTON)) {
float viewWidth = app.viewEnd - app.viewStart;
float freqWidth = app.freqViewEnd - app.freqViewStart;
float dx = (mousePos.x - app.dragSelectionStartPos.x) / selBounds.width;
float dy = (mousePos.y - app.dragSelectionStartPos.y) / selBounds.height;
float dx = (mousePos.x - app.sel.dragStartPos.x) / selBounds.width;
float dy = (mousePos.y - app.sel.dragStartPos.y) / selBounds.height;
float timeShift = dx * viewWidth;
float freqShift = -dy * freqWidth; // Y is inverted
float timeWidth = app.timeSelectionEnd - app.timeSelectionStart;
float freqHeight = app.freqSelectionEnd - app.freqSelectionStart;
float timeWidth = app.sel.timeEnd - app.sel.timeStart;
float freqHeight = app.sel.freqEnd - app.sel.freqStart;
app.timeSelectionStart = Clamp(app.dragSelectionTimeStart + timeShift, 0.0f, 1.0f - timeWidth);
app.timeSelectionEnd = app.timeSelectionStart + timeWidth;
app.freqSelectionStart = Clamp(app.dragSelectionFreqStart + freqShift, 0.0f, 1.0f - freqHeight);
app.freqSelectionEnd = app.freqSelectionStart + freqHeight;
app.sel.timeStart = Clamp(app.sel.dragTimeStart + timeShift, 0.0f, 1.0f - timeWidth);
app.sel.timeEnd = app.sel.timeStart + timeWidth;
app.sel.freqStart = Clamp(app.sel.dragFreqStart + freqShift, 0.0f, 1.0f - freqHeight);
app.sel.freqEnd = app.sel.freqStart + freqHeight;
}
// Creating new box selection
if ((app.isTimeSelecting || app.isFreqSelecting) && IsMouseButtonDown(MOUSE_LEFT_BUTTON)) {
if ((app.sel.isTimeSelecting || app.sel.isFreqSelecting) && IsMouseButtonDown(MOUSE_LEFT_BUTTON)) {
float viewportT = (mousePos.x - selBounds.x) / selBounds.width;
float viewportF = 1.0f - (mousePos.y - selBounds.y) / selBounds.height;
app.timeSelectionEnd = Clamp(app.viewStart + viewportT * (app.viewEnd - app.viewStart), 0.0f, 1.0f);
app.freqSelectionEnd = Clamp(app.freqViewStart + viewportF * (app.freqViewEnd - app.freqViewStart), 0.0f, 1.0f);
app.sel.timeEnd = Clamp(app.viewStart + viewportT * (app.viewEnd - app.viewStart), 0.0f, 1.0f);
app.sel.freqEnd = Clamp(app.freqViewStart + viewportF * (app.freqViewEnd - app.freqViewStart), 0.0f, 1.0f);
}
if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) {
if (app.isDraggingSelection) {
app.isDraggingSelection = false;
} else if (app.isTimeSelecting || app.isFreqSelecting) {
if (app.sel.isDragging) {
app.sel.isDragging = false;
} else if (app.sel.isTimeSelecting || app.sel.isFreqSelecting) {
// Check if drag was large enough (minimum 5 pixels)
float dx = mousePos.x - app.selectStartPos.x;
float dy = mousePos.y - app.selectStartPos.y;
float dx = mousePos.x - app.sel.selectStartPos.x;
float dy = mousePos.y - app.sel.selectStartPos.y;
float dragDist = sqrtf(dx * dx + dy * dy);
if (dragDist > 5.0f) {
// Normalize so start < end
if (app.timeSelectionEnd < app.timeSelectionStart) {
float tmp = app.timeSelectionStart;
app.timeSelectionStart = app.timeSelectionEnd;
app.timeSelectionEnd = tmp;
if (app.sel.timeEnd < app.sel.timeStart) {
float tmp = app.sel.timeStart;
app.sel.timeStart = app.sel.timeEnd;
app.sel.timeEnd = tmp;
}
if (app.freqSelectionEnd < app.freqSelectionStart) {
float tmp = app.freqSelectionStart;
app.freqSelectionStart = app.freqSelectionEnd;
app.freqSelectionEnd = tmp;
if (app.sel.freqEnd < app.sel.freqStart) {
float tmp = app.sel.freqStart;
app.sel.freqStart = app.sel.freqEnd;
app.sel.freqEnd = tmp;
}
} else {
// Drag too small - revert to full range
app.timeSelectionStart = 0.0f;
app.timeSelectionEnd = 1.0f;
app.freqSelectionStart = 0.0f;
app.freqSelectionEnd = 1.0f;
ClearSelection();
}
app.isTimeSelecting = false;
app.isFreqSelecting = false;
app.sel.isTimeSelecting = false;
app.sel.isFreqSelecting = false;
}
}
}
@@ -982,7 +972,7 @@ int main(int argc, char* argv[])
app.scopeView.data.sampleRate = app.signal.sampleRate;
// Show playhead if playing
if (app.isPlaying) {
DrawScopeView(&app.scopeView, app.timeSelectionStart + app.playheadT * (app.timeSelectionEnd - app.timeSelectionStart));
DrawScopeView(&app.scopeView, app.sel.timeStart + app.playheadT * (app.sel.timeEnd - app.sel.timeStart));
} else {
DrawScopeView(&app.scopeView, -1.0f);
}