undo support for trash

This commit is contained in:
Michael Peters 2024-01-27 17:06:40 -08:00
parent 0b4a442f5e
commit 2d00568ce9

View File

@ -35,6 +35,24 @@ interface Line {
stroke: string;
}
interface AddLineAction {
line: Line;
}
interface DeleteLinesAction {
lines: Line[];
}
type Action = AddLineAction | DeleteLinesAction;
function isAddLineAction(action: Action): action is AddLineAction {
return action.hasOwnProperty('line');
}
function isDeleteLinesAction(action: Action): action is DeleteLinesAction {
return action.hasOwnProperty('lines');
}
// https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection
// https://stackoverflow.com/questions/9043805/test-if-two-lines-intersect-javascript-function
function lineSegmentIntersection(l0: Range, l1: Range): boolean {
@ -145,7 +163,10 @@ const Grid: FC = () => {
}, [range, GAP]);
const [userLines, setUserLines] = useState<Line[]>([]);
const [userRedoLines, setUserRedoLines] = useState<Line[]>([]);
const [userActions, setUserActions] = useState<Action[]>([]);
const [userRedoActions, setUserRedoActions] = useState<Action[]>([]);
const [userStartPoint, setUserStartPoint] = useState<Point | null>(null);
const userLineColor = useRecoilValue(lineColorState);
const userDrawMode = useRecoilValue(drawModeState);
@ -161,8 +182,6 @@ const Grid: FC = () => {
const point = snapToGrid(mousePoint, GAP);
setUserRedoLines([]);
if (lodash.isEqual(userStartPoint, point)) {
setUserStartPoint(null);
return;
@ -174,11 +193,13 @@ const Grid: FC = () => {
const line = pointsToRange(userStartPoint, point);
setUserRedoActions([]);
if (userDrawMode == 'line') {
setUserLines([
...userLines,
{ ...line, stroke: userLineColor },
]);
// draw a new line
const userLine = { ...line, stroke: userLineColor };
setUserLines([...userLines, userLine]);
setUserActions([...userActions, { line: userLine }]);
if (event.shiftKey == false) {
setUserStartPoint(null);
@ -186,6 +207,7 @@ const Grid: FC = () => {
setUserStartPoint(point);
}
} else if (userDrawMode == 'trash') {
// trash lines
const userLinesGood: Line[] = [];
const userLinesTrashed: Line[] = [];
@ -201,6 +223,7 @@ const Grid: FC = () => {
// TODO: add undo support for userLinesTrashed
setUserLines(userLinesGood);
setUserActions([...userActions, { lines: userLinesTrashed }]);
setUserStartPoint(null);
} else {
throw Error('invalid user draw mode');
@ -211,6 +234,8 @@ const Grid: FC = () => {
userStartPoint,
setUserStartPoint,
setUserLines,
setUserActions,
setUserRedoActions,
GAP,
mousePoint,
]
@ -225,22 +250,46 @@ const Grid: FC = () => {
// ctrl+z/ctrl+y for undo/redo
const onUndo = useCallback(() => {
console.log('onUndo', userLines);
const line = userLines.at(-1);
if (!line) return;
console.log('onUndo', userActions);
const action = userActions.at(-1);
if (!action) return;
setUserLines(userLines.slice(0, -1));
setUserRedoLines([...userRedoLines, line]);
}, [userLines, setUserLines, userRedoLines, setUserRedoLines]);
if (isAddLineAction(action)) {
setUserLines(
userLines.filter((userLine) => userLine != action.line)
);
} else if (isDeleteLinesAction(action)) {
// NOTE: this does not preserve layering
setUserLines([...userLines, ...action.lines]);
} else {
console.error('invalid action');
}
setUserActions(userActions.slice(0, -1));
setUserRedoActions([...userRedoActions, action]);
}, [userLines, setUserLines, userActions, setUserActions]);
const onRedo = useCallback(() => {
console.log('onRedo', userRedoLines);
const line = userRedoLines.at(-1);
if (!line) return;
console.log('onRedo', userRedoActions);
const action = userRedoActions.at(-1);
if (!action) return;
setUserRedoLines(userRedoLines.slice(0, -1));
setUserLines([...userLines, line]);
}, [userLines, setUserLines, userRedoLines, setUserRedoLines]);
if (isAddLineAction(action)) {
setUserLines([...userLines, action.line]);
} else if (isDeleteLinesAction(action)) {
setUserLines(
userLines.filter(
(userLine) =>
!action.lines.find(
(actionLine) => userLine === actionLine
)
)
);
} else {
throw new Error('invalid action');
}
setUserRedoActions(userRedoActions.slice(0, -1));
setUserActions([...userActions, action]);
}, [userLines, setUserLines, userActions, setUserActions]);
useKeyPress(onUndo, 'z', true);
useKeyPress(onRedo, 'y', true);