143 lines
3.6 KiB
TypeScript
143 lines
3.6 KiB
TypeScript
import { createOpaqueId } from "../core/ids";
|
|
import { cloneEditorSelection, type EditorSelection } from "../core/selection";
|
|
import type { ToolMode } from "../core/tool-mode";
|
|
import {
|
|
cloneScenePath,
|
|
getScenePathPointIndex
|
|
} from "../document/paths";
|
|
import type { Vec3 } from "../core/vector";
|
|
|
|
import type { EditorCommand } from "./command";
|
|
|
|
interface SetPathPointPositionCommandOptions {
|
|
pathId: string;
|
|
pointId: string;
|
|
position: Vec3;
|
|
label?: string;
|
|
}
|
|
|
|
function cloneVec3(vector: Vec3): Vec3 {
|
|
return {
|
|
x: vector.x,
|
|
y: vector.y,
|
|
z: vector.z
|
|
};
|
|
}
|
|
|
|
function setSelectedPathPointSelection(
|
|
pathId: string,
|
|
pointId: string
|
|
): EditorSelection {
|
|
return {
|
|
kind: "pathPoint",
|
|
pathId,
|
|
pointId
|
|
};
|
|
}
|
|
|
|
export function createSetPathPointPositionCommand(
|
|
options: SetPathPointPositionCommandOptions
|
|
): EditorCommand {
|
|
const nextPosition = cloneVec3(options.position);
|
|
let previousPosition: Vec3 | null = null;
|
|
let previousSelection: EditorSelection | null = null;
|
|
let previousToolMode: ToolMode | null = null;
|
|
|
|
return {
|
|
id: createOpaqueId("command"),
|
|
label: options.label ?? "Move path point",
|
|
execute(context) {
|
|
const currentDocument = context.getDocument();
|
|
const path = currentDocument.paths[options.pathId];
|
|
|
|
if (path === undefined) {
|
|
throw new Error(`Path ${options.pathId} does not exist.`);
|
|
}
|
|
|
|
const pointIndex = getScenePathPointIndex(path, options.pointId);
|
|
|
|
if (pointIndex === -1) {
|
|
throw new Error(`Path point ${options.pointId} does not exist on path ${options.pathId}.`);
|
|
}
|
|
|
|
if (previousPosition === null) {
|
|
previousPosition = cloneVec3(path.points[pointIndex].position);
|
|
}
|
|
|
|
if (previousSelection === null) {
|
|
previousSelection = cloneEditorSelection(context.getSelection());
|
|
}
|
|
|
|
if (previousToolMode === null) {
|
|
previousToolMode = context.getToolMode();
|
|
}
|
|
|
|
context.setDocument({
|
|
...currentDocument,
|
|
paths: {
|
|
...currentDocument.paths,
|
|
[path.id]: cloneScenePath({
|
|
...path,
|
|
points: path.points.map((point, index) =>
|
|
index === pointIndex
|
|
? {
|
|
...point,
|
|
position: cloneVec3(nextPosition)
|
|
}
|
|
: point
|
|
)
|
|
})
|
|
}
|
|
});
|
|
context.setSelection(
|
|
setSelectedPathPointSelection(options.pathId, options.pointId)
|
|
);
|
|
context.setToolMode("select");
|
|
},
|
|
undo(context) {
|
|
if (previousPosition === null) {
|
|
return;
|
|
}
|
|
|
|
const currentDocument = context.getDocument();
|
|
const path = currentDocument.paths[options.pathId];
|
|
|
|
if (path === undefined) {
|
|
throw new Error(`Path ${options.pathId} does not exist.`);
|
|
}
|
|
|
|
const pointIndex = getScenePathPointIndex(path, options.pointId);
|
|
|
|
if (pointIndex === -1) {
|
|
throw new Error(`Path point ${options.pointId} does not exist on path ${options.pathId}.`);
|
|
}
|
|
|
|
context.setDocument({
|
|
...currentDocument,
|
|
paths: {
|
|
...currentDocument.paths,
|
|
[path.id]: cloneScenePath({
|
|
...path,
|
|
points: path.points.map((point, index) =>
|
|
index === pointIndex
|
|
? {
|
|
...point,
|
|
position: cloneVec3(previousPosition)
|
|
}
|
|
: point
|
|
)
|
|
})
|
|
}
|
|
});
|
|
|
|
if (previousSelection !== null) {
|
|
context.setSelection(previousSelection);
|
|
}
|
|
|
|
if (previousToolMode !== null) {
|
|
context.setToolMode(previousToolMode);
|
|
}
|
|
}
|
|
};
|
|
}
|