diff --git a/src/spectrogram.c b/src/spectrogram.c index 527b57e..4d94062 100644 --- a/src/spectrogram.c +++ b/src/spectrogram.c @@ -62,6 +62,43 @@ static float ScopeDivider(void) return app.showScope ? app.dividerY : 1.0f; } +// Screen layout metrics, derived from window size + UI scale. Single source of +// truth: the input, selection, and render passes all unpack from this so the +// layout formulas live in exactly one place. +typedef struct { + float scale; + float sidebarWidth; + float labelHeight; + float scrollbarHeight; + float freqLabelWidth; + float vScrollbarWidth; + float topMargin; + float bottomMargin; + float spectroHeight; // height of the spectrogram (respects the scope divider) + Rectangle viewBounds; // the spectrogram drawing area +} Layout; + +static Layout ComputeLayout(void) +{ + Layout L; + L.scale = GetUIScale(); + L.sidebarWidth = 320 * L.scale; + L.labelHeight = 15 * L.scale; + L.scrollbarHeight = 18 * L.scale; + L.freqLabelWidth = 65 * L.scale; + L.vScrollbarWidth = 18 * L.scale; + L.topMargin = 50 * L.scale; + L.bottomMargin = 10 * L.scale; + L.spectroHeight = (GetScreenHeight() - L.topMargin - L.bottomMargin - L.labelHeight - L.scrollbarHeight - 10 * L.scale) * ScopeDivider(); + L.viewBounds = (Rectangle){ + L.sidebarWidth + L.freqLabelWidth, + L.topMargin, + GetScreenWidth() - L.sidebarWidth - L.freqLabelWidth - L.vScrollbarWidth - 20 * L.scale, + L.spectroHeight + }; + return L; +} + // 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,22 +297,17 @@ int main(int argc, char* argv[]) // View controls if (app.loaded && !UiModalOpen()) { // Spectrogram area fills remaining window space (scaled) - float viewScale = GetUIScale(); - float sidebarWidth = 320 * viewScale; - float labelHeight = 15 * viewScale; - float scrollbarHeight = 18 * viewScale; - float freqLabelWidth = 65 * viewScale; - float vScrollbarWidth = 18 * viewScale; - float topMargin = 50 * viewScale; - float bottomMargin = 10 * viewScale; - - float spectroHeight = (GetScreenHeight() - topMargin - bottomMargin - labelHeight - scrollbarHeight - 10 * viewScale) * ScopeDivider(); - Rectangle viewBounds = { - sidebarWidth + freqLabelWidth, - topMargin, - GetScreenWidth() - sidebarWidth - freqLabelWidth - vScrollbarWidth - 20 * viewScale, - spectroHeight - }; + Layout L = ComputeLayout(); + float viewScale = L.scale; + float sidebarWidth = L.sidebarWidth; + float labelHeight = L.labelHeight; + float scrollbarHeight = L.scrollbarHeight; + float freqLabelWidth = L.freqLabelWidth; + float vScrollbarWidth = L.vScrollbarWidth; + float topMargin = L.topMargin; + float bottomMargin = L.bottomMargin; + float spectroHeight = L.spectroHeight; + Rectangle viewBounds = L.viewBounds; // Zoom with mouse wheel (zooms both time and frequency to maintain aspect ratio) if (GetMousePosition().x > sidebarWidth + 5 && CheckCollisionPointRec(GetMousePosition(), viewBounds)) { @@ -478,22 +510,17 @@ int main(int argc, char* argv[]) } // Selection: box select with LMB drag, right-click to clear - float selScale = GetUIScale(); - float selSidebarWidth = 320 * selScale; - float selLabelHeight = 15 * selScale; - float selScrollbarHeight = 18 * selScale; - float selFreqLabelWidth = 65 * selScale; - float selVScrollbarWidth = 18 * selScale; - float selTopMargin = 50 * selScale; - float selBottomMargin = 10 * selScale; - - float selSpectroHeight = (GetScreenHeight() - selTopMargin - selBottomMargin - selLabelHeight - selScrollbarHeight - 10.0f * selScale) * ScopeDivider(); - Rectangle selBounds = { - selSidebarWidth + selFreqLabelWidth, - selTopMargin, - GetScreenWidth() - selSidebarWidth - selFreqLabelWidth - selVScrollbarWidth - 20.0f * selScale, - selSpectroHeight - }; + Layout selL = ComputeLayout(); + float selScale = selL.scale; + float selSidebarWidth = selL.sidebarWidth; + float selLabelHeight = selL.labelHeight; + float selScrollbarHeight = selL.scrollbarHeight; + float selFreqLabelWidth = selL.freqLabelWidth; + float selVScrollbarWidth = selL.vScrollbarWidth; + float selTopMargin = selL.topMargin; + float selBottomMargin = selL.bottomMargin; + float selSpectroHeight = selL.spectroHeight; + Rectangle selBounds = selL.viewBounds; Vector2 mousePos = GetMousePosition(); // Calculate divider screen position (for hover detection) @@ -766,23 +793,18 @@ int main(int argc, char* argv[]) ClearBackground((Color){ 30, 30, 30, 255 }); // Layout: sidebar on left, spectrogram on right (scaled) - float renderScale = GetUIScale(); - float sidebarWidth = 320 * renderScale; - float labelHeight = 15 * renderScale; - float scrollbarHeight = 18 * renderScale; - float freqLabelWidth = 65 * renderScale; - float vScrollbarWidth = 18 * renderScale; - float topMargin = 50 * renderScale; - float bottomMargin = 10 * renderScale; - // Spectrogram area (excludes labels and scrollbars) - float spectroHeight = (GetScreenHeight() - topMargin - bottomMargin - labelHeight - scrollbarHeight - 10 * renderScale) * ScopeDivider(); - Rectangle viewBounds = { - sidebarWidth + freqLabelWidth, - topMargin, - GetScreenWidth() - sidebarWidth - freqLabelWidth - vScrollbarWidth - 20 * renderScale, - spectroHeight - }; + Layout L = ComputeLayout(); + float renderScale = L.scale; + float sidebarWidth = L.sidebarWidth; + float labelHeight = L.labelHeight; + float scrollbarHeight = L.scrollbarHeight; + float freqLabelWidth = L.freqLabelWidth; + float vScrollbarWidth = L.vScrollbarWidth; + float topMargin = L.topMargin; + float bottomMargin = L.bottomMargin; + float spectroHeight = L.spectroHeight; + Rectangle viewBounds = L.viewBounds; // Time labels sit just below the spectrogram Rectangle timeLabelArea = { viewBounds.x, viewBounds.y + viewBounds.height, viewBounds.width, labelHeight }; // Horizontal scrollbar sits below the time labels