"use client"; import { useRef } from "react"; import { getCenteredLineLeft, TIMELINE_INDICATOR_LINE_WIDTH_PX, timelineTimeToSnappedPixels, } from "@/timeline"; import { useTimelinePlayhead } from "@/timeline/hooks/use-timeline-playhead"; import { addMediaTime, maxMediaTime, mediaTime, subMediaTime, TICKS_PER_SECOND, ZERO_MEDIA_TIME, } from "@/wasm"; import { useEditor } from "@/editor/use-editor"; import { TIMELINE_SCROLLBAR_SIZE_PX } from "./layout"; import { TIMELINE_LAYERS } from "./layers"; interface TimelinePlayheadProps { zoomLevel: number; hasHorizontalScrollbar: boolean; rulerRef: React.RefObject; rulerScrollRef: React.RefObject; tracksScrollRef: React.RefObject; timelineRef: React.RefObject; playheadRef?: React.RefObject; isSnappingToPlayhead?: boolean; } export function TimelinePlayhead({ zoomLevel, hasHorizontalScrollbar, rulerRef, rulerScrollRef, tracksScrollRef, timelineRef, playheadRef: externalPlayheadRef, isSnappingToPlayhead = false, }: TimelinePlayheadProps) { const editor = useEditor(); const duration = editor.timeline.getTotalDuration(); const internalPlayheadRef = useRef(null); const playheadRef = externalPlayheadRef || internalPlayheadRef; const { handlePlayheadMouseDown } = useTimelinePlayhead({ zoomLevel, rulerRef, rulerScrollRef, tracksScrollRef, playheadRef, }); const timelineContainerHeight = timelineRef.current?.clientHeight ?? tracksScrollRef.current?.clientHeight ?? 400; const totalHeight = Math.max( 0, timelineContainerHeight - (hasHorizontalScrollbar ? TIMELINE_SCROLLBAR_SIZE_PX - 5 : 0), ); const currentTime = editor.playback.getCurrentTime(); const centerPosition = timelineTimeToSnappedPixels({ time: currentTime, zoomLevel, }); const scrollLeft = tracksScrollRef.current?.scrollLeft ?? 0; const leftPosition = getCenteredLineLeft({ centerPixel: centerPosition }) - scrollLeft; const handlePlayheadKeyDown = ( event: React.KeyboardEvent, ) => { if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return; event.preventDefault(); const fps = editor.project.getActive().settings.fps; const ticksPerFrame = mediaTime({ ticks: Math.round( (TICKS_PER_SECOND * fps.denominator) / fps.numerator, ), }); const direction = event.key === "ArrowRight" ? 1 : -1; const now = editor.playback.getCurrentTime(); const nextTime = direction > 0 ? addMediaTime({ a: now, b: ticksPerFrame }) : subMediaTime({ a: now, b: ticksPerFrame }); editor.playback.seek({ time: maxMediaTime({ a: ZERO_MEDIA_TIME, b: duration < nextTime ? duration : nextTime, }), }); }; return (
); }