Adds undo redo

This commit is contained in:
Steve Ruiz 2021-05-13 09:34:56 +01:00
parent 8c81823b20
commit 9bca2dd646
9 changed files with 78 additions and 29 deletions

View file

@ -1,5 +1,4 @@
import styled from "styles"
import { getPointerEventInfo } from "utils/utils"
import React, { useCallback, useRef } from "react"
import useZoomEvents from "hooks/useZoomEvents"
import useCamera from "hooks/useCamera"

View file

@ -1,6 +1,5 @@
import React, { useCallback, useRef, memo } from "react"
import state, { useSelector } from "state"
import { getPointerEventInfo } from "utils/utils"
import inputs from "state/inputs"
import shapes from "lib/shapes"
import styled from "styles"

View file

@ -1,12 +1,18 @@
import { useEffect } from "react"
import state from "state"
import { getKeyboardEventInfo } from "utils/utils"
import { getKeyboardEventInfo, isDarwin } from "utils/utils"
export default function useKeyboardEvents() {
useEffect(() => {
function handleKeyDown(e: KeyboardEvent) {
if (e.key === "Escape") {
state.send("CANCELLED")
} else if (e.key === "z" && (isDarwin() ? e.metaKey : e.ctrlKey)) {
if (e.shiftKey) {
state.send("REDO")
} else {
state.send("UNDO")
}
}
state.send("PRESSED_KEY", getKeyboardEventInfo(e))

View file

@ -1,6 +1,6 @@
import React, { useEffect, useRef } from "react"
import state from "state"
import { getPointerEventInfo } from "utils/utils"
import inputs from "state/inputs"
import * as vec from "utils/vec"
/**
@ -24,14 +24,14 @@ export default function useZoomEvents(
if (e.ctrlKey) {
state.send("ZOOMED_CAMERA", {
delta: e.deltaY,
...getPointerEventInfo(e),
...inputs.wheel(e),
})
return
}
state.send("PANNED_CAMERA", {
delta: [e.deltaX, e.deltaY],
...getPointerEventInfo(e),
...inputs.wheel(e),
})
}

View file

@ -1,5 +1,5 @@
import Command from "./command"
import history from "./history"
import history from "../history"
import { TranslateSnapshot } from "state/sessions/translate-session"
import { Data } from "types"

View file

@ -1,5 +1,5 @@
import { Data } from "types"
import { BaseCommand } from "./command"
import { BaseCommand } from "./commands/command"
// A singleton to manage history changes.

View file

@ -1,4 +1,5 @@
import { PointerInfo } from "types"
import { isDarwin } from "utils/utils"
class Inputs {
points: Record<string, PointerInfo> = {}
@ -6,47 +7,67 @@ class Inputs {
pointerDown(e: PointerEvent | React.PointerEvent) {
const { shiftKey, ctrlKey, metaKey, altKey } = e
this.points[e.pointerId] = {
const info = {
pointerId: e.pointerId,
origin: [e.clientX, e.clientY],
point: [e.clientX, e.clientY],
shiftKey,
ctrlKey,
metaKey,
metaKey: isDarwin() ? metaKey : ctrlKey,
altKey,
}
return this.points[e.pointerId]
this.points[e.pointerId] = info
return info
}
pointerMove(e: PointerEvent | React.PointerEvent) {
if (this.points[e.pointerId]) {
this.points[e.pointerId].point = [e.clientX, e.clientY]
return this.points[e.pointerId]
}
const { shiftKey, ctrlKey, metaKey, altKey } = e
return {
const prev = this.points[e.pointerId]
const info = {
pointerId: e.pointerId,
origin: [e.clientX, e.clientY],
origin: prev?.origin || [e.clientX, e.clientY],
point: [e.clientX, e.clientY],
shiftKey,
ctrlKey,
metaKey,
metaKey: isDarwin() ? metaKey : ctrlKey,
altKey,
}
if (this.points[e.pointerId]) {
this.points[e.pointerId] = info
}
return info
}
pointerUp(e: PointerEvent | React.PointerEvent) {
this.points[e.pointerId].point = [e.clientX, e.clientY]
const { shiftKey, ctrlKey, metaKey, altKey } = e
const info = this.points[e.pointerId]
const prev = this.points[e.pointerId]
const info = {
pointerId: e.pointerId,
origin: prev?.origin || [e.clientX, e.clientY],
point: [e.clientX, e.clientY],
shiftKey,
ctrlKey,
metaKey: isDarwin() ? metaKey : ctrlKey,
altKey,
}
delete this.points[e.pointerId]
return info
}
wheel(e: WheelEvent) {
const { shiftKey, ctrlKey, metaKey, altKey } = e
return { point: [e.clientX, e.clientY], shiftKey, ctrlKey, metaKey, altKey }
}
}
export default new Inputs()

View file

@ -4,6 +4,7 @@ import * as vec from "utils/vec"
import { Bounds, Data, PointerInfo, Shape, ShapeType } from "types"
import { defaultDocument } from "./data"
import Shapes from "lib/shapes"
import history from "state/history"
import * as Sessions from "./sessions"
const initialData: Data = {
@ -32,6 +33,10 @@ const state = createState({
initial: "selecting",
states: {
selecting: {
on: {
UNDO: { do: "undo" },
REDO: { do: "redo" },
},
initial: "notPointing",
states: {
notPointing: {
@ -118,6 +123,21 @@ const state = createState({
},
},
actions: {
// History
enableHistory() {
history.enable()
},
disableHistory() {
history.disable()
},
undo(data) {
history.undo(data)
},
redo(data) {
history.redo(data)
},
// Sessions
cancelSession(data) {
session.cancel(data)
session = undefined
@ -126,6 +146,7 @@ const state = createState({
session.complete(data)
session = undefined
},
// Brushing
startBrushSession(data, payload: { point: number[] }) {
session = new Sessions.BrushSession(

View file

@ -877,14 +877,17 @@ export async function postJsonToEndpoint(
return await d.json()
}
export function getPointerEventInfo(
e: PointerEvent | React.PointerEvent | WheelEvent
) {
const { shiftKey, ctrlKey, metaKey, altKey } = e
return { point: [e.clientX, e.clientY], shiftKey, ctrlKey, metaKey, altKey }
}
export function getKeyboardEventInfo(e: KeyboardEvent | React.KeyboardEvent) {
const { shiftKey, ctrlKey, metaKey, altKey } = e
return { key: e.key, shiftKey, ctrlKey, metaKey, altKey }
return {
key: e.key,
shiftKey,
ctrlKey,
metaKey: isDarwin() ? metaKey : ctrlKey,
altKey,
}
}
export function isDarwin() {
return /Mac|iPod|iPhone|iPad/.test(window.navigator.platform)
}