Parcourir la source

Adds undo redo

main
Steve Ruiz il y a 4 ans
Parent
révision
9bca2dd646

+ 0
- 1
components/canvas/canvas.tsx Voir le fichier

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

+ 0
- 1
components/canvas/shape.tsx Voir le fichier

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

+ 7
- 1
hooks/useKeyboardEvents.ts Voir le fichier

@@ -1,12 +1,18 @@
1 1
 import { useEffect } from "react"
2 2
 import state from "state"
3
-import { getKeyboardEventInfo } from "utils/utils"
3
+import { getKeyboardEventInfo, isDarwin } from "utils/utils"
4 4
 
5 5
 export default function useKeyboardEvents() {
6 6
   useEffect(() => {
7 7
     function handleKeyDown(e: KeyboardEvent) {
8 8
       if (e.key === "Escape") {
9 9
         state.send("CANCELLED")
10
+      } else if (e.key === "z" && (isDarwin() ? e.metaKey : e.ctrlKey)) {
11
+        if (e.shiftKey) {
12
+          state.send("REDO")
13
+        } else {
14
+          state.send("UNDO")
15
+        }
10 16
       }
11 17
 
12 18
       state.send("PRESSED_KEY", getKeyboardEventInfo(e))

+ 3
- 3
hooks/useZoomEvents.ts Voir le fichier

@@ -1,6 +1,6 @@
1 1
 import React, { useEffect, useRef } from "react"
2 2
 import state from "state"
3
-import { getPointerEventInfo } from "utils/utils"
3
+import inputs from "state/inputs"
4 4
 import * as vec from "utils/vec"
5 5
 
6 6
 /**
@@ -24,14 +24,14 @@ export default function useZoomEvents(
24 24
       if (e.ctrlKey) {
25 25
         state.send("ZOOMED_CAMERA", {
26 26
           delta: e.deltaY,
27
-          ...getPointerEventInfo(e),
27
+          ...inputs.wheel(e),
28 28
         })
29 29
         return
30 30
       }
31 31
 
32 32
       state.send("PANNED_CAMERA", {
33 33
         delta: [e.deltaX, e.deltaY],
34
-        ...getPointerEventInfo(e),
34
+        ...inputs.wheel(e),
35 35
       })
36 36
     }
37 37
 

+ 1
- 1
state/commands/translate-command.ts Voir le fichier

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

state/commands/history.ts → state/history.ts Voir le fichier

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

+ 34
- 13
state/inputs.tsx Voir le fichier

@@ -1,4 +1,5 @@
1 1
 import { PointerInfo } from "types"
2
+import { isDarwin } from "utils/utils"
2 3
 
3 4
 class Inputs {
4 5
   points: Record<string, PointerInfo> = {}
@@ -6,47 +7,67 @@ class Inputs {
6 7
   pointerDown(e: PointerEvent | React.PointerEvent) {
7 8
     const { shiftKey, ctrlKey, metaKey, altKey } = e
8 9
 
9
-    this.points[e.pointerId] = {
10
+    const info = {
10 11
       pointerId: e.pointerId,
11 12
       origin: [e.clientX, e.clientY],
12 13
       point: [e.clientX, e.clientY],
13 14
       shiftKey,
14 15
       ctrlKey,
15
-      metaKey,
16
+      metaKey: isDarwin() ? metaKey : ctrlKey,
16 17
       altKey,
17 18
     }
18 19
 
19
-    return this.points[e.pointerId]
20
+    this.points[e.pointerId] = info
21
+
22
+    return info
20 23
   }
21 24
 
22 25
   pointerMove(e: PointerEvent | React.PointerEvent) {
23
-    if (this.points[e.pointerId]) {
24
-      this.points[e.pointerId].point = [e.clientX, e.clientY]
25
-      return this.points[e.pointerId]
26
-    }
27
-
28 26
     const { shiftKey, ctrlKey, metaKey, altKey } = e
29 27
 
30
-    return {
28
+    const prev = this.points[e.pointerId]
29
+
30
+    const info = {
31 31
       pointerId: e.pointerId,
32
-      origin: [e.clientX, e.clientY],
32
+      origin: prev?.origin || [e.clientX, e.clientY],
33 33
       point: [e.clientX, e.clientY],
34 34
       shiftKey,
35 35
       ctrlKey,
36
-      metaKey,
36
+      metaKey: isDarwin() ? metaKey : ctrlKey,
37 37
       altKey,
38 38
     }
39
+
40
+    if (this.points[e.pointerId]) {
41
+      this.points[e.pointerId] = info
42
+    }
43
+
44
+    return info
39 45
   }
40 46
 
41 47
   pointerUp(e: PointerEvent | React.PointerEvent) {
42
-    this.points[e.pointerId].point = [e.clientX, e.clientY]
48
+    const { shiftKey, ctrlKey, metaKey, altKey } = e
43 49
 
44
-    const info = this.points[e.pointerId]
50
+    const prev = this.points[e.pointerId]
51
+
52
+    const info = {
53
+      pointerId: e.pointerId,
54
+      origin: prev?.origin || [e.clientX, e.clientY],
55
+      point: [e.clientX, e.clientY],
56
+      shiftKey,
57
+      ctrlKey,
58
+      metaKey: isDarwin() ? metaKey : ctrlKey,
59
+      altKey,
60
+    }
45 61
 
46 62
     delete this.points[e.pointerId]
47 63
 
48 64
     return info
49 65
   }
66
+
67
+  wheel(e: WheelEvent) {
68
+    const { shiftKey, ctrlKey, metaKey, altKey } = e
69
+    return { point: [e.clientX, e.clientY], shiftKey, ctrlKey, metaKey, altKey }
70
+  }
50 71
 }
51 72
 
52 73
 export default new Inputs()

+ 21
- 0
state/state.ts Voir le fichier

@@ -4,6 +4,7 @@ import * as vec from "utils/vec"
4 4
 import { Bounds, Data, PointerInfo, Shape, ShapeType } from "types"
5 5
 import { defaultDocument } from "./data"
6 6
 import Shapes from "lib/shapes"
7
+import history from "state/history"
7 8
 import * as Sessions from "./sessions"
8 9
 
9 10
 const initialData: Data = {
@@ -32,6 +33,10 @@ const state = createState({
32 33
   initial: "selecting",
33 34
   states: {
34 35
     selecting: {
36
+      on: {
37
+        UNDO: { do: "undo" },
38
+        REDO: { do: "redo" },
39
+      },
35 40
       initial: "notPointing",
36 41
       states: {
37 42
         notPointing: {
@@ -118,6 +123,21 @@ const state = createState({
118 123
     },
119 124
   },
120 125
   actions: {
126
+    // History
127
+    enableHistory() {
128
+      history.enable()
129
+    },
130
+    disableHistory() {
131
+      history.disable()
132
+    },
133
+    undo(data) {
134
+      history.undo(data)
135
+    },
136
+    redo(data) {
137
+      history.redo(data)
138
+    },
139
+
140
+    // Sessions
121 141
     cancelSession(data) {
122 142
       session.cancel(data)
123 143
       session = undefined
@@ -126,6 +146,7 @@ const state = createState({
126 146
       session.complete(data)
127 147
       session = undefined
128 148
     },
149
+
129 150
     // Brushing
130 151
     startBrushSession(data, payload: { point: number[] }) {
131 152
       session = new Sessions.BrushSession(

+ 10
- 7
utils/utils.ts Voir le fichier

@@ -877,14 +877,17 @@ export async function postJsonToEndpoint(
877 877
   return await d.json()
878 878
 }
879 879
 
880
-export function getPointerEventInfo(
881
-  e: PointerEvent | React.PointerEvent | WheelEvent
882
-) {
880
+export function getKeyboardEventInfo(e: KeyboardEvent | React.KeyboardEvent) {
883 881
   const { shiftKey, ctrlKey, metaKey, altKey } = e
884
-  return { point: [e.clientX, e.clientY], shiftKey, ctrlKey, metaKey, altKey }
882
+  return {
883
+    key: e.key,
884
+    shiftKey,
885
+    ctrlKey,
886
+    metaKey: isDarwin() ? metaKey : ctrlKey,
887
+    altKey,
888
+  }
885 889
 }
886 890
 
887
-export function getKeyboardEventInfo(e: KeyboardEvent | React.KeyboardEvent) {
888
-  const { shiftKey, ctrlKey, metaKey, altKey } = e
889
-  return { key: e.key, shiftKey, ctrlKey, metaKey, altKey }
891
+export function isDarwin() {
892
+  return /Mac|iPod|iPhone|iPad/.test(window.navigator.platform)
890 893
 }

Chargement…
Annuler
Enregistrer