mirror of
https://github.com/OpenCut-app/OpenCut.git
synced 2026-07-13 21:52:53 +02:00
196 lines
4.9 KiB
TypeScript
196 lines
4.9 KiB
TypeScript
import type { EditorCore } from "@/core";
|
|
import type { SelectedKeyframeRef } from "@/animation/types";
|
|
import type {
|
|
EditorSelectionKind,
|
|
EditorSelectionPatch,
|
|
EditorSelectionSnapshot,
|
|
SelectedMaskPointSelection,
|
|
} from "@/selection/editor-selection";
|
|
import type { ElementRef } from "@/timeline/types";
|
|
|
|
export class SelectionManager {
|
|
private selectedElements: ElementRef[] = [];
|
|
private selectedKeyframes: SelectedKeyframeRef[] = [];
|
|
private keyframeSelectionAnchor: SelectedKeyframeRef | null = null;
|
|
private selectedMaskPoints: SelectedMaskPointSelection | null = null;
|
|
private listeners = new Set<() => void>();
|
|
|
|
constructor(editor: EditorCore) {
|
|
void editor;
|
|
}
|
|
|
|
getSelectedElements(): ElementRef[] {
|
|
return this.selectedElements;
|
|
}
|
|
|
|
getSelectedKeyframes(): SelectedKeyframeRef[] {
|
|
return this.selectedKeyframes;
|
|
}
|
|
|
|
getKeyframeSelectionAnchor(): SelectedKeyframeRef | null {
|
|
return this.keyframeSelectionAnchor;
|
|
}
|
|
|
|
getSelectedMaskPointSelection(): SelectedMaskPointSelection | null {
|
|
return this.selectedMaskPoints;
|
|
}
|
|
|
|
getActiveSelectionKind(): EditorSelectionKind | null {
|
|
if ((this.selectedMaskPoints?.pointIds.length ?? 0) > 0) {
|
|
return "mask-points";
|
|
}
|
|
if (this.selectedKeyframes.length > 0) {
|
|
return "keyframes";
|
|
}
|
|
if (this.selectedElements.length > 0) {
|
|
return "elements";
|
|
}
|
|
return null;
|
|
}
|
|
|
|
getSnapshot(): EditorSelectionSnapshot {
|
|
return {
|
|
selectedElements: [...this.selectedElements],
|
|
selectedKeyframes: [...this.selectedKeyframes],
|
|
keyframeSelectionAnchor: this.keyframeSelectionAnchor,
|
|
selectedMaskPoints: this.selectedMaskPoints
|
|
? {
|
|
...this.selectedMaskPoints,
|
|
pointIds: [...this.selectedMaskPoints.pointIds],
|
|
}
|
|
: null,
|
|
};
|
|
}
|
|
|
|
setSelectedElements({ elements }: { elements: ElementRef[] }): void {
|
|
this.selectedElements = elements;
|
|
this.selectedKeyframes = [];
|
|
this.keyframeSelectionAnchor = null;
|
|
this.selectedMaskPoints = null;
|
|
this.notify();
|
|
}
|
|
|
|
setSelectedKeyframes({
|
|
keyframes,
|
|
anchorKeyframe,
|
|
}: {
|
|
keyframes: SelectedKeyframeRef[];
|
|
anchorKeyframe?: SelectedKeyframeRef | null;
|
|
}): void {
|
|
this.selectedKeyframes = keyframes;
|
|
if (anchorKeyframe !== undefined) {
|
|
this.keyframeSelectionAnchor = anchorKeyframe;
|
|
} else if (keyframes.length === 0) {
|
|
this.keyframeSelectionAnchor = null;
|
|
}
|
|
this.selectedMaskPoints = null;
|
|
this.notify();
|
|
}
|
|
|
|
setSelectedMaskPoints({
|
|
selection,
|
|
}: {
|
|
selection: SelectedMaskPointSelection | null;
|
|
}): void {
|
|
this.selectedMaskPoints =
|
|
selection && selection.pointIds.length > 0
|
|
? {
|
|
...selection,
|
|
pointIds: [...selection.pointIds],
|
|
}
|
|
: null;
|
|
this.selectedKeyframes = [];
|
|
this.keyframeSelectionAnchor = null;
|
|
this.notify();
|
|
}
|
|
|
|
clearSelection(): void {
|
|
this.selectedElements = [];
|
|
this.selectedKeyframes = [];
|
|
this.keyframeSelectionAnchor = null;
|
|
this.selectedMaskPoints = null;
|
|
this.notify();
|
|
}
|
|
|
|
clearKeyframeSelection(): void {
|
|
this.selectedKeyframes = [];
|
|
this.keyframeSelectionAnchor = null;
|
|
this.notify();
|
|
}
|
|
|
|
clearMaskPointSelection(): void {
|
|
if (!this.selectedMaskPoints) {
|
|
return;
|
|
}
|
|
this.selectedMaskPoints = null;
|
|
this.notify();
|
|
}
|
|
|
|
clearMostSpecificSelection(): boolean {
|
|
const activeSelectionKind = this.getActiveSelectionKind();
|
|
if (activeSelectionKind === "mask-points") {
|
|
this.clearMaskPointSelection();
|
|
return true;
|
|
}
|
|
if (activeSelectionKind === "keyframes") {
|
|
this.clearKeyframeSelection();
|
|
return true;
|
|
}
|
|
if (activeSelectionKind === "elements") {
|
|
this.setSelectedElements({ elements: [] });
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
applySelectionPatch({
|
|
patch,
|
|
}: {
|
|
patch: EditorSelectionPatch;
|
|
}): EditorSelectionSnapshot {
|
|
if (patch.selectedElements !== undefined) {
|
|
this.selectedElements = [...patch.selectedElements];
|
|
}
|
|
if (patch.selectedKeyframes !== undefined) {
|
|
this.selectedKeyframes = [...patch.selectedKeyframes];
|
|
}
|
|
if (patch.keyframeSelectionAnchor !== undefined) {
|
|
this.keyframeSelectionAnchor = patch.keyframeSelectionAnchor;
|
|
}
|
|
if (patch.selectedMaskPoints !== undefined) {
|
|
this.selectedMaskPoints = patch.selectedMaskPoints
|
|
? {
|
|
...patch.selectedMaskPoints,
|
|
pointIds: [...patch.selectedMaskPoints.pointIds],
|
|
}
|
|
: null;
|
|
}
|
|
this.notify();
|
|
return this.getSnapshot();
|
|
}
|
|
|
|
restoreSnapshot({ snapshot }: { snapshot: EditorSelectionSnapshot }): void {
|
|
this.selectedElements = [...snapshot.selectedElements];
|
|
this.selectedKeyframes = [...snapshot.selectedKeyframes];
|
|
this.keyframeSelectionAnchor = snapshot.keyframeSelectionAnchor;
|
|
this.selectedMaskPoints = snapshot.selectedMaskPoints
|
|
? {
|
|
...snapshot.selectedMaskPoints,
|
|
pointIds: [...snapshot.selectedMaskPoints.pointIds],
|
|
}
|
|
: null;
|
|
this.notify();
|
|
}
|
|
|
|
subscribe(listener: () => void): () => void {
|
|
this.listeners.add(listener);
|
|
return () => this.listeners.delete(listener);
|
|
}
|
|
|
|
private notify(): void {
|
|
this.listeners.forEach((fn) => {
|
|
fn();
|
|
});
|
|
}
|
|
}
|