undo support for trash
This commit is contained in:
parent
0b4a442f5e
commit
2d00568ce9
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user