summaryrefslogtreecommitdiff
path: root/apps/web/src/timeline/controllers/resize-controller.ts
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/src/timeline/controllers/resize-controller.ts')
-rw-r--r--apps/web/src/timeline/controllers/resize-controller.ts80
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,
});