mirror of
https://github.com/OpenCut-app/OpenCut.git
synced 2026-07-13 21:52:53 +02:00
fix: model editor time as wasm MediaTime ticks end-to-end
This commit is contained in:
@@ -3,7 +3,12 @@ import type { ComputeDropTargetParams, DropTarget } from "@/timeline";
|
||||
import { resolveTrackPlacement } from "@/timeline/placement";
|
||||
import { TIMELINE_TRACK_GAP_PX } from "./layout";
|
||||
import { getTrackHeight } from "./track-layout";
|
||||
import { TICKS_PER_SECOND } from "@/wasm";
|
||||
import {
|
||||
mediaTime,
|
||||
type MediaTime,
|
||||
roundMediaTime,
|
||||
TICKS_PER_SECOND,
|
||||
} from "@/wasm";
|
||||
|
||||
function findElementAtPosition({
|
||||
mouseX,
|
||||
@@ -20,9 +25,11 @@ function findElementAtPosition({
|
||||
pixelsPerSecond: number;
|
||||
zoomLevel: number;
|
||||
}): { elementId: string; trackId: string } | null {
|
||||
const time = Math.round(
|
||||
(mouseX / (pixelsPerSecond * zoomLevel)) * TICKS_PER_SECOND,
|
||||
);
|
||||
const time = mediaTime({
|
||||
ticks: Math.round(
|
||||
(mouseX / (pixelsPerSecond * zoomLevel)) * TICKS_PER_SECOND,
|
||||
),
|
||||
});
|
||||
const track = tracks[trackIndex];
|
||||
if (!track || !("elements" in track)) return null;
|
||||
|
||||
@@ -82,7 +89,7 @@ const EMPTY_TARGET_ELEMENT = null;
|
||||
function fallbackNewTrackDropTarget({
|
||||
xPosition,
|
||||
}: {
|
||||
xPosition: number;
|
||||
xPosition: MediaTime;
|
||||
}): DropTarget {
|
||||
return {
|
||||
trackIndex: 0,
|
||||
@@ -111,13 +118,16 @@ export function computeDropTarget({
|
||||
const orderedTracks = [...tracks.overlay, tracks.main, ...tracks.audio];
|
||||
const mainTrackIndex = tracks.overlay.length;
|
||||
const xPosition =
|
||||
typeof startTimeOverride === "number"
|
||||
startTimeOverride !== undefined
|
||||
? startTimeOverride
|
||||
: isExternalDrop
|
||||
? playheadTime
|
||||
: Math.round(
|
||||
Math.max(0, mouseX / (pixelsPerSecond * zoomLevel)) * TICKS_PER_SECOND,
|
||||
);
|
||||
: mediaTime({
|
||||
ticks: Math.round(
|
||||
Math.max(0, mouseX / (pixelsPerSecond * zoomLevel)) *
|
||||
TICKS_PER_SECOND,
|
||||
),
|
||||
});
|
||||
|
||||
if (orderedTracks.length === 0) {
|
||||
const placementResult = resolveTrackPlacement({
|
||||
@@ -221,7 +231,10 @@ export function computeDropTarget({
|
||||
}
|
||||
|
||||
if (placementResult.kind === "existingTrack") {
|
||||
const adjustedXPosition = placementResult.adjustedStartTime ?? xPosition;
|
||||
const adjustedXPosition =
|
||||
placementResult.adjustedStartTime !== undefined
|
||||
? roundMediaTime({ time: placementResult.adjustedStartTime })
|
||||
: xPosition;
|
||||
|
||||
return {
|
||||
trackIndex: placementResult.trackIndex,
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
useState,
|
||||
type ReactNode,
|
||||
} from "react";
|
||||
import type { MediaTime } from "@/wasm";
|
||||
import type { ElementDragState, DropTarget } from "@/timeline";
|
||||
import { TimelineTrackContent } from "./timeline-track";
|
||||
import { TimelinePlayhead } from "./timeline-playhead";
|
||||
@@ -132,7 +133,7 @@ export function Timeline() {
|
||||
[scene],
|
||||
);
|
||||
const mainTrackId = scene?.tracks.main.id ?? null;
|
||||
const seek = (time: number) => editor.playback.seek({ time });
|
||||
const seek = (time: MediaTime) => editor.playback.seek({ time });
|
||||
|
||||
const timelineRef = useRef<HTMLDivElement>(null);
|
||||
const timelineHeaderRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
@@ -49,7 +49,7 @@ import {
|
||||
import { buildWaveformGainSamples } from "@/timeline/audio-state";
|
||||
import { getTimelinePixelsPerSecond } from "@/timeline";
|
||||
import { buildWaveformSourceKey } from "@/media/waveform-summary";
|
||||
import { TICKS_PER_SECOND } from "@/wasm/ticks";
|
||||
import { addMediaTime, TICKS_PER_SECOND, ZERO_MEDIA_TIME } from "@/wasm";
|
||||
import {
|
||||
getActionDefinition,
|
||||
type TAction,
|
||||
@@ -257,10 +257,11 @@ export function TimelineElement({
|
||||
isBeingDragged && dragState.isDragging
|
||||
? dragState.currentMouseY - dragState.startMouseY
|
||||
: 0;
|
||||
const dragTimeOffset = dragState.dragTimeOffsets[element.id] ?? 0;
|
||||
const dragTimeOffset =
|
||||
dragState.dragTimeOffsets[element.id] ?? ZERO_MEDIA_TIME;
|
||||
const elementStartTime =
|
||||
isBeingDragged && dragState.isDragging
|
||||
? dragState.currentTime + dragTimeOffset
|
||||
? addMediaTime({ a: dragState.currentTime, b: dragTimeOffset })
|
||||
: renderElement.startTime;
|
||||
const displayedStartTime = elementStartTime;
|
||||
const displayedDuration = renderElement.duration;
|
||||
|
||||
@@ -7,7 +7,14 @@ import {
|
||||
timelineTimeToSnappedPixels,
|
||||
} from "@/timeline";
|
||||
import { useTimelinePlayhead } from "@/timeline/hooks/use-timeline-playhead";
|
||||
import { TICKS_PER_SECOND } from "@/wasm";
|
||||
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";
|
||||
@@ -72,17 +79,24 @@ export function TimelinePlayhead({
|
||||
|
||||
event.preventDefault();
|
||||
const fps = editor.project.getActive().settings.fps;
|
||||
const ticksPerFrame = Math.round(
|
||||
(TICKS_PER_SECOND * fps.denominator) / fps.numerator,
|
||||
);
|
||||
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 = Math.max(
|
||||
0,
|
||||
Math.min(duration, now + direction * ticksPerFrame),
|
||||
);
|
||||
const nextTime =
|
||||
direction > 0
|
||||
? addMediaTime({ a: now, b: ticksPerFrame })
|
||||
: subMediaTime({ a: now, b: ticksPerFrame });
|
||||
|
||||
editor.playback.seek({ time: nextTime });
|
||||
editor.playback.seek({
|
||||
time: maxMediaTime({
|
||||
a: ZERO_MEDIA_TIME,
|
||||
b: duration < nextTime ? duration : nextTime,
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user