refactor: group viewport/zoom/pan state into a Viewport sub-struct

The visible-window + pan-anchor state was 10 flat fields (viewStart, viewEnd,
freqView*, pan*) used densely throughout the zoom/pan/scrollbar code. Group
them into a Viewport sub-struct (app.view.*).

Rename anchored strictly to 'app.' so ScopeView's own view->viewStart/viewEnd
(same field names) are untouched. Settled render verified pixel-identical
(AE=0); End/zoom path verified via injected key input.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-25 09:17:26 -07:00
parent 8e4250ae63
commit f91cae77e8
3 changed files with 125 additions and 123 deletions
+17 -17
View File
@@ -283,7 +283,7 @@ void DrawLabels(Rectangle bounds)
// Time labels
for (int i = 0; i <= 10; i++) {
float t = (float)i / 10;
float timeSec = (app.viewStart + t * (app.viewEnd - app.viewStart)) * app.signal.duration;
float timeSec = (app.view.start + t * (app.view.end - app.view.start)) * app.signal.duration;
float x = bounds.x + t * bounds.width;
char label[32];
if (timeSec >= 60) sprintf(label, "%d:%02d", (int)(timeSec / 60), (int)(timeSec) % 60);
@@ -293,8 +293,8 @@ void DrawLabels(Rectangle bounds)
// Frequency labels adapted to current zoom level
float maxFreq = (float)app.signal.sampleRate / 2.0f;
float freqMin = app.freqViewStart * maxFreq;
float freqMax = app.freqViewEnd * maxFreq;
float freqMin = app.view.freqStart * maxFreq;
float freqMax = app.view.freqEnd * maxFreq;
// Choose tick spacing based on zoom range
float freqRange = freqMax - freqMin;
@@ -348,13 +348,13 @@ void DrawSelection(Rectangle bounds)
Color overlayColor = Fade(BLACK, 0.25f); // Lighter overlay
// Convert signal coordinates to viewport coordinates
float viewWidth = app.viewEnd - app.viewStart;
float freqWidth = app.freqViewEnd - app.freqViewStart;
float viewWidth = app.view.end - app.view.start;
float freqWidth = app.view.freqEnd - app.view.freqStart;
float selStartX = bounds.x + ((app.sel.timeStart - app.viewStart) / viewWidth) * bounds.width;
float selEndX = bounds.x + ((app.sel.timeEnd - app.viewStart) / viewWidth) * bounds.width;
float selStartY = bounds.y + bounds.height - ((app.sel.freqEnd - app.freqViewStart) / freqWidth) * bounds.height;
float selEndY = bounds.y + bounds.height - ((app.sel.freqStart - app.freqViewStart) / freqWidth) * bounds.height;
float selStartX = bounds.x + ((app.sel.timeStart - app.view.start) / viewWidth) * bounds.width;
float selEndX = bounds.x + ((app.sel.timeEnd - app.view.start) / viewWidth) * bounds.width;
float selStartY = bounds.y + bounds.height - ((app.sel.freqEnd - app.view.freqStart) / freqWidth) * bounds.height;
float selEndY = bounds.y + bounds.height - ((app.sel.freqStart - app.view.freqStart) / freqWidth) * bounds.height;
// Clamp to viewport bounds
selStartX = fmaxf(bounds.x, fminf(bounds.x + bounds.width, selStartX));
@@ -443,13 +443,13 @@ void DrawSelectionDrag(Rectangle bounds)
(app.sel.isDragging && !IsMouseButtonDown(MOUSE_LEFT_BUTTON))) return;
// Convert signal coordinates to viewport coordinates
float viewWidth = app.viewEnd - app.viewStart;
float freqWidth = app.freqViewEnd - app.freqViewStart;
float viewWidth = app.view.end - app.view.start;
float freqWidth = app.view.freqEnd - app.view.freqStart;
float selStartX = bounds.x + ((app.sel.timeStart - app.viewStart) / viewWidth) * bounds.width;
float selEndX = bounds.x + ((app.sel.timeEnd - app.viewStart) / viewWidth) * bounds.width;
float selStartY = bounds.y + bounds.height - ((app.sel.freqEnd - app.freqViewStart) / freqWidth) * bounds.height;
float selEndY = bounds.y + bounds.height - ((app.sel.freqStart - app.freqViewStart) / freqWidth) * bounds.height;
float selStartX = bounds.x + ((app.sel.timeStart - app.view.start) / viewWidth) * bounds.width;
float selEndX = bounds.x + ((app.sel.timeEnd - app.view.start) / viewWidth) * bounds.width;
float selStartY = bounds.y + bounds.height - ((app.sel.freqEnd - app.view.freqStart) / freqWidth) * bounds.height;
float selEndY = bounds.y + bounds.height - ((app.sel.freqStart - app.view.freqStart) / freqWidth) * bounds.height;
// Clamp to viewport bounds
selStartX = fmaxf(bounds.x, fminf(bounds.x + bounds.width, selStartX));
@@ -539,8 +539,8 @@ void DrawPlayhead(Rectangle bounds)
if (!app.isPlaying || app.playheadT < 0.0f || app.playheadT > 1.0f) return;
float timePos = app.sel.timeStart + app.playheadT * (app.sel.timeEnd - app.sel.timeStart);
float viewWidth = app.viewEnd - app.viewStart;
float t = (timePos - app.viewStart) / viewWidth;
float viewWidth = app.view.end - app.view.start;
float t = (timePos - app.view.start) / viewWidth;
float x = bounds.x + t * bounds.width;
// Clamp to bounds