diff options
Diffstat (limited to 'apps/web/src/timeline/controllers/resize-controller.ts')
| -rw-r--r-- | apps/web/src/timeline/controllers/resize-controller.ts | 80 |
1 files changed, 57 insertions, 23 deletions
diff --git a/apps/web/src/timeline/controllers/resize-controller.ts b/apps/web/src/timeline/controllers/resize-controller.ts index cdf502a1..a1098915 100644 --- a/apps/web/src/timeline/controllers/resize-controller.ts +++ b/apps/web/src/timeline/controllers/resize-controller.ts @@ -1,6 +1,14 @@ import type { MouseEvent as ReactMouseEvent } from "react"; import { BASE_TIMELINE_PIXELS_PER_SECOND } from "@/timeline/scale"; -import { TICKS_PER_SECOND } from "@/wasm"; +import { + addMediaTime, + maxMediaTime, + type MediaTime, + mediaTime, + minMediaTime, + subMediaTime, + TICKS_PER_SECOND, +} from "@/wasm"; import { computeGroupResize, type GroupResizeMember, @@ -46,7 +54,7 @@ export interface ResizeConfig { snappingEnabled: boolean; isShiftHeld: () => boolean; getSceneTracks: () => SceneTracks; - getCurrentPlayheadTime: () => number; + getCurrentPlayheadTime: () => MediaTime; getActiveProjectFps: () => FrameRate | null; selectedElements: ElementRef[]; discardPreview: () => void; @@ -87,14 +95,32 @@ export function buildResizeMembers({ (el) => !selectedElementIds.has(el.id), ); const leftNeighborBound = otherElements - .filter((el) => el.startTime + el.duration <= element.startTime) - .reduce( - (bound, el) => Math.max(bound, el.startTime + el.duration), - -Infinity, - ); + .filter( + (el) => + addMediaTime({ a: el.startTime, b: el.duration }) <= + element.startTime, + ) + .reduce<MediaTime | null>((bound, el) => { + const elementEnd = addMediaTime({ + a: el.startTime, + b: el.duration, + }); + return bound === null + ? elementEnd + : maxMediaTime({ a: bound, b: elementEnd }); + }, null); const rightNeighborBound = otherElements - .filter((el) => el.startTime >= element.startTime + element.duration) - .reduce((bound, el) => Math.min(bound, el.startTime), Infinity); + .filter( + (el) => + el.startTime >= addMediaTime({ a: element.startTime, b: element.duration }), + ) + .reduce<MediaTime | null>( + (bound, el) => + bound === null + ? el.startTime + : minMediaTime({ a: bound, b: el.startTime }), + null, + ); return [ { @@ -237,12 +263,18 @@ export class ResizeController { this.notify(); } - private snappedDelta(session: ResizeSession, rawDeltaTicks: number): number { + private snappedDelta({ + session, + rawDeltaTime, + }: { + session: ResizeSession; + rawDeltaTime: MediaTime; + }): MediaTime { const { snappingEnabled, isShiftHeld, zoomLevel } = this.config; if (!snappingEnabled || isShiftHeld()) { this.config.onSnapPointChange?.(null); - return rawDeltaTicks; + return rawDeltaTime; } const tracks = this.config.getSceneTracks(); @@ -264,15 +296,15 @@ export class ResizeController { let closestSnapPoint: SnapPoint | null = null; let closestSnapDistance = Infinity; - let deltaTicks = rawDeltaTicks; + let deltaTime = rawDeltaTime; for (const member of session.members) { const baseEdgeTime = session.side === "left" ? member.startTime - : member.startTime + member.duration; + : addMediaTime({ a: member.startTime, b: member.duration }); const snapResult = resolveTimelineSnap({ - targetTime: baseEdgeTime + rawDeltaTicks, + targetTime: addMediaTime({ a: baseEdgeTime, b: rawDeltaTime }), snapPoints, maxSnapDistance, }); @@ -282,28 +314,30 @@ export class ResizeController { ) { closestSnapDistance = snapResult.snapDistance; closestSnapPoint = snapResult.snapPoint; - deltaTicks = snapResult.snappedTime - baseEdgeTime; + deltaTime = subMediaTime({ a: snapResult.snappedTime, b: baseEdgeTime }); } } this.config.onSnapPointChange?.(closestSnapPoint); - return deltaTicks; + return deltaTime; } private handleMouseMove({ clientX }: MouseEvent): void { if (this.session.kind !== "active") return; const session = this.session; - const rawDeltaTicks = Math.round( - ((clientX - session.startX) / - (BASE_TIMELINE_PIXELS_PER_SECOND * this.config.zoomLevel)) * - TICKS_PER_SECOND, - ); - const deltaTicks = this.snappedDelta(session, rawDeltaTicks); + const rawDeltaTime = mediaTime({ + ticks: Math.round( + ((clientX - session.startX) / + (BASE_TIMELINE_PIXELS_PER_SECOND * this.config.zoomLevel)) * + TICKS_PER_SECOND, + ), + }); + const deltaTime = this.snappedDelta({ session, rawDeltaTime }); const result = computeGroupResize({ members: session.members, side: session.side, - deltaTicks, + deltaTime, fps: session.fps, }); |
