diff --git a/electron/hudOverlayBounds.test.ts b/electron/hudOverlayBounds.test.ts index cc00daac..dac1058c 100644 --- a/electron/hudOverlayBounds.test.ts +++ b/electron/hudOverlayBounds.test.ts @@ -1,6 +1,9 @@ import { describe, expect, it } from "vitest"; -import { getHudOverlayWindowBounds } from "./hudOverlayBounds"; +import { + getHudOverlayWindowBounds, + resizeHudOverlayFallbackBounds, +} from "./hudOverlayBounds"; describe("getHudOverlayWindowBounds", () => { const workArea = { @@ -71,3 +74,72 @@ describe("getHudOverlayWindowBounds", () => { }); }); }); + +describe("resizeHudOverlayFallbackBounds", () => { + const workArea = { + x: 0, + y: 0, + width: 1920, + height: 1080, + }; + + it("preserves the dragged bottom edge when expanding", () => { + expect( + resizeHudOverlayFallbackBounds( + workArea, + { + x: 420, + y: 700, + width: 860, + height: 160, + }, + true, + ), + ).toEqual({ + x: 420, + y: 320, + width: 860, + height: 540, + }); + }); + + it("preserves the dragged bottom edge when compacting", () => { + expect( + resizeHudOverlayFallbackBounds( + workArea, + { + x: 420, + y: 320, + width: 860, + height: 540, + }, + false, + ), + ).toEqual({ + x: 420, + y: 700, + width: 860, + height: 160, + }); + }); + + it("keeps resized fallback bounds inside the display work area", () => { + expect( + resizeHudOverlayFallbackBounds( + workArea, + { + x: 1500, + y: 900, + width: 860, + height: 160, + }, + true, + ), + ).toEqual({ + x: 1060, + y: 520, + width: 860, + height: 540, + }); + }); +}); diff --git a/electron/hudOverlayBounds.ts b/electron/hudOverlayBounds.ts index 9168281f..b8800e30 100644 --- a/electron/hudOverlayBounds.ts +++ b/electron/hudOverlayBounds.ts @@ -9,6 +9,10 @@ const NON_PASSTHROUGH_HUD_WIDTH_DIP = 860; const NON_PASSTHROUGH_HUD_COMPACT_HEIGHT_DIP = 160; const NON_PASSTHROUGH_HUD_EXPANDED_HEIGHT_DIP = 540; +function clamp(value: number, min: number, max: number): number { + return Math.min(Math.max(value, min), max); +} + export function getHudOverlayWindowBounds( workArea: HudOverlayWorkArea, mousePassthroughSupported: boolean, @@ -33,3 +37,19 @@ export function getHudOverlayWindowBounds( height, }; } + +export function resizeHudOverlayFallbackBounds( + workArea: HudOverlayWorkArea, + currentBounds: HudOverlayWorkArea, + fallbackExpanded: boolean, +): HudOverlayWorkArea { + const nextBounds = getHudOverlayWindowBounds(workArea, false, fallbackExpanded); + const maxX = workArea.x + workArea.width - nextBounds.width; + const maxY = workArea.y + workArea.height - nextBounds.height; + + return { + ...nextBounds, + x: clamp(currentBounds.x, workArea.x, maxX), + y: clamp(currentBounds.y + currentBounds.height - nextBounds.height, workArea.y, maxY), + }; +} diff --git a/electron/windows.ts b/electron/windows.ts index a1a30358..dbdb4692 100644 --- a/electron/windows.ts +++ b/electron/windows.ts @@ -5,7 +5,10 @@ import path from "node:path"; import { fileURLToPath } from "node:url"; import { app, BrowserWindow, ipcMain } from "electron"; import { USER_DATA_PATH } from "./appPaths"; -import { getHudOverlayWindowBounds } from "./hudOverlayBounds"; +import { + getHudOverlayWindowBounds, + resizeHudOverlayFallbackBounds, +} from "./hudOverlayBounds"; import { getPackagedRendererBaseUrl } from "./rendererServer"; const electronWindowsDir = path.dirname(fileURLToPath(import.meta.url)); @@ -253,7 +256,13 @@ function setHudOverlayFallbackExpanded(expanded: boolean) { return; } - hudOverlayWindow.setBounds(getHudOverlayBounds(), false); + const { workArea } = getHudOverlayDisplay(); + const nextBounds = resizeHudOverlayFallbackBounds( + workArea, + hudOverlayWindow.getBounds(), + expanded, + ); + hudOverlayWindow.setBounds(nextBounds, false); positionUpdateToastWindow(); if (hudOverlayWindow.isVisible()) { hudOverlayWindow.moveTop(); diff --git a/src/components/launch/LaunchWindow.tsx b/src/components/launch/LaunchWindow.tsx index 2158d7a2..b3c92476 100644 --- a/src/components/launch/LaunchWindow.tsx +++ b/src/components/launch/LaunchWindow.tsx @@ -427,8 +427,7 @@ function LaunchWindowContent() { const hudMode = finalizing ? "finalizing" : recording ? "recording" : "idle"; const useNativeHudBarDrag = - (platform === "linux" || hudOverlayMousePassthroughSupported === false) && - !showRecordingWebcamPreview; + platform === "linux" || hudOverlayMousePassthroughSupported === false; return (