Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion electron/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ function showHudOverlayFromTray() {
if (process.platform === "win32" && isHudOverlayMousePassthroughSupported()) {
hud.showInactive();
hud.moveTop();
reassertHudOverlayMouseState();
reassertHudOverlayMouseState({ interactiveGraceMs: 1200 });
return true;
}

Expand Down
8 changes: 6 additions & 2 deletions electron/windows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,11 @@ export function getHudOverlayWindow(): BrowserWindow | null {
* hover detection on the HUD is immediately restored without requiring the
* user to move their mouse over the bar.
*/
export function reassertHudOverlayMousePassthrough(): void {
export function reassertHudOverlayMousePassthrough({
interactiveGraceMs = 50,
}: {
interactiveGraceMs?: number;
} = {}): void {
if (process.platform !== "win32" || !isHudOverlayMousePassthroughSupported()) {
return;
}
Expand All @@ -639,7 +643,7 @@ export function reassertHudOverlayMousePassthrough(): void {
if (!hud.isDestroyed()) {
setHudOverlayMousePassthrough(hudOverlayIgnoringMouse);
}
}, 50);
}, interactiveGraceMs);
}

export function setHudOverlayRecordingActive(recording: boolean): void {
Expand Down
49 changes: 35 additions & 14 deletions src/components/launch/hooks/useLaunchHudInteractionState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,23 @@ export function useLaunchHudInteractionState({
}) {
const isMouseOverHudRef = useRef(false);
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
const lastInteractiveReassertAtRef = useRef(0);

const setHudMouseInteractive = useCallback((force = false) => {
const now = performance.now();
if (
!force &&
isMouseOverHudRef.current &&
now - lastInteractiveReassertAtRef.current < 250
) {
return;
}

isMouseOverHudRef.current = true;
lastInteractiveReassertAtRef.current = now;
if (timeoutRef.current) clearTimeout(timeoutRef.current);
window.electronAPI?.hudOverlaySetIgnoreMouse?.(false);
}, []);

useEffect(() => {
if (openId !== null) {
Expand All @@ -28,17 +45,15 @@ export function useLaunchHudInteractionState({
}, [openId]);

useEffect(() => {
const handleMouseOver = (e: globalThis.MouseEvent) => {
const handleMouseTracking = (e: globalThis.MouseEvent) => {
const target = e.target as HTMLElement | null;
if (!target) return;
const isInteractive = !!target.closest(
".pointer-events-auto, [data-hud-interactive], [data-radix-popper-content-wrapper]",
);

if (isInteractive) {
isMouseOverHudRef.current = true;
if (timeoutRef.current) clearTimeout(timeoutRef.current);
window.electronAPI?.hudOverlaySetIgnoreMouse?.(false);
setHudMouseInteractive();
} else {
isMouseOverHudRef.current = false;
if (timeoutRef.current) clearTimeout(timeoutRef.current);
Expand All @@ -55,20 +70,26 @@ export function useLaunchHudInteractionState({
}
};

window.addEventListener("mouseover", handleMouseOver);
return () => window.removeEventListener("mouseover", handleMouseOver);
}, [isHudDraggingRef, isWebcamPreviewDraggingRef, webcamPreviewDragStartRef]);
window.addEventListener("mouseover", handleMouseTracking);
window.addEventListener("mousemove", handleMouseTracking);
return () => {
window.removeEventListener("mouseover", handleMouseTracking);
window.removeEventListener("mousemove", handleMouseTracking);
};
}, [
isHudDraggingRef,
isWebcamPreviewDraggingRef,
setHudMouseInteractive,
webcamPreviewDragStartRef,
]);

const beginInteractiveHudAction = useCallback(() => {
isMouseOverHudRef.current = true;
window.electronAPI?.hudOverlaySetIgnoreMouse?.(false);
}, []);
setHudMouseInteractive(true);
}, [setHudMouseInteractive]);

const handleHudMouseEnter = useCallback(() => {
isMouseOverHudRef.current = true;
if (timeoutRef.current) clearTimeout(timeoutRef.current);
window.electronAPI?.hudOverlaySetIgnoreMouse?.(false);
}, []);
setHudMouseInteractive(true);
}, [setHudMouseInteractive]);

const handleHudMouseLeave = useCallback(
(event: MouseEvent<HTMLDivElement>) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,30 @@ export default function TimelineWrapper({
[formatTooltipMs],
);

const resolveDragPreviewSpan = useCallback(
(event: DragMoveEvent, span: Span): Span | null => {
const proposedRowId = event.over?.id as string | undefined;
if (!proposedRowId) return span;

const activeItemId = event.active.id as string;
const resolved = resolveDragEnd(
activeItemId,
span,
proposedRowId,
{
allRegionSpans,
totalMs,
minItemDurationMs,
hasOverlap,
},
resolveTargetRowId,
);

return resolved?.span ?? null;
},
[allRegionSpans, hasOverlap, minItemDurationMs, resolveTargetRowId, totalMs],
Comment thread
coderabbitai[bot] marked this conversation as resolved.
);

const onDragStart = useCallback(
(event: DragStartEvent) => {
const span = event.active.data.current.getSpanFromDragEvent?.(event);
Expand All @@ -137,17 +161,22 @@ export default function TimelineWrapper({
const onDragMove = useCallback(
(event: DragMoveEvent) => {
const span = event.active.data.current.getSpanFromDragEvent?.(event);
const previewSpan = span ? resolveDragPreviewSpan(event, span) : null;
const screenX =
event.activatorEvent && "clientX" in event.activatorEvent
? (event.activatorEvent as PointerEvent).clientX + (event.delta?.x ?? 0)
: undefined;
if (span) showTooltip(span, screenX);
if (previewSpan) {
showTooltip(previewSpan, screenX);
} else {
showTooltip(null);
}
const moved = Math.hypot(event.delta?.x ?? 0, event.delta?.y ?? 0) > 0.01;
if (moved) {
onLiveSpanPreviewChange?.(event.active.id as string, span ?? null);
onLiveSpanPreviewChange?.(event.active.id as string, previewSpan);
}
},
[onLiveSpanPreviewChange, showTooltip],
[onLiveSpanPreviewChange, resolveDragPreviewSpan, showTooltip],
);

const onResizeMove = useCallback(
Expand Down Expand Up @@ -210,7 +239,13 @@ export default function TimelineWrapper({
onDragStart={onDragStart}
onDragMove={onDragMove}
onDragEnd={onDragEndWithTooltip}
autoScroll={{ enabled: false }}
autoScroll={{
enabled: true,
threshold: { x: 0.08, y: 0.08 },
acceleration: 3,
interval: 16,
layoutShiftCompensation: { x: false, y: false },
}}
resizeHandleWidth={28}
>
<div className="relative h-full min-h-0">
Expand Down
Loading