mirror of
https://github.com/penpot/penpot.git
synced 2025-01-24 23:49:45 -05:00
Merge pull request #871 from penpot/feat/path-move-nodes-keyboard
Add move path points with keyboard
This commit is contained in:
commit
4c93ef4bb3
4 changed files with 197 additions and 79 deletions
|
@ -57,7 +57,8 @@ jobs:
|
|||
yarn install
|
||||
npx shadow-cljs compile tests
|
||||
environment:
|
||||
PATH: /usr/local/nodejs/bin/:/usr/local/bin:/bin:/usr/bin
|
||||
JAVA_HOME: /usr/lib/jvm/openjdk16
|
||||
PATH: /usr/local/nodejs/bin/:/usr/local/bin:/bin:/usr/bin:/usr/lib/jvm/openjdk16/bin
|
||||
|
||||
- save_cache:
|
||||
paths:
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
(d/export edition/start-move-path-point)
|
||||
(d/export edition/start-path-edit)
|
||||
(d/export edition/create-node-at-position)
|
||||
(d/export edition/move-selected)
|
||||
|
||||
;; Selection
|
||||
(d/export selection/handle-selection)
|
||||
|
|
|
@ -64,45 +64,61 @@
|
|||
(selection/update-selection point-change)
|
||||
(fn [state] (update-in state [:workspace-local :edit-path id] dissoc :content-modifiers :moving-nodes :moving-handler)))))))
|
||||
|
||||
(defn modify-content-point
|
||||
[content {dx :x dy :y} modifiers point]
|
||||
(let [point-indices (upc/point-indices content point) ;; [indices]
|
||||
handler-indices (upc/handler-indices content point) ;; [[index prefix]]
|
||||
|
||||
modify-point
|
||||
(fn [modifiers index]
|
||||
(-> modifiers
|
||||
(update index assoc :x dx :y dy)))
|
||||
|
||||
modify-handler
|
||||
(fn [modifiers [index prefix]]
|
||||
(let [cx (d/prefix-keyword prefix :x)
|
||||
cy (d/prefix-keyword prefix :y)]
|
||||
(-> modifiers
|
||||
(update index assoc cx dx cy dy))))]
|
||||
|
||||
(as-> modifiers $
|
||||
(reduce modify-point $ point-indices)
|
||||
(reduce modify-handler $ handler-indices))))
|
||||
|
||||
(defn set-move-modifier
|
||||
[points move-modifier]
|
||||
(ptk/reify ::set-modifiers
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [id (st/get-path-id state)
|
||||
content (get-in state (st/get-path state :content))
|
||||
modifiers-reducer (partial modify-content-point content move-modifier)
|
||||
content-modifiers (get-in state [:workspace-local :edit-path id :content-modifiers] {})
|
||||
content-modifiers (->> points
|
||||
(reduce modifiers-reducer content-modifiers))]
|
||||
|
||||
(-> state
|
||||
(assoc-in [:workspace-local :edit-path id :content-modifiers] content-modifiers))))))
|
||||
|
||||
(defn move-selected-path-point [from-point to-point]
|
||||
(letfn [(modify-content-point [content {dx :x dy :y} modifiers point]
|
||||
(let [point-indices (upc/point-indices content point) ;; [indices]
|
||||
handler-indices (upc/handler-indices content point) ;; [[index prefix]]
|
||||
(ptk/reify ::move-point
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [id (st/get-path-id state)
|
||||
content (get-in state (st/get-path state :content))
|
||||
delta (gpt/subtract to-point from-point)
|
||||
|
||||
modify-point
|
||||
(fn [modifiers index]
|
||||
(-> modifiers
|
||||
(update index assoc :x dx :y dy)))
|
||||
modifiers-reducer (partial modify-content-point content delta)
|
||||
|
||||
modify-handler
|
||||
(fn [modifiers [index prefix]]
|
||||
(let [cx (d/prefix-keyword prefix :x)
|
||||
cy (d/prefix-keyword prefix :y)]
|
||||
(-> modifiers
|
||||
(update index assoc cx dx cy dy))))]
|
||||
points (get-in state [:workspace-local :edit-path id :selected-points] #{})
|
||||
|
||||
(as-> modifiers $
|
||||
(reduce modify-point $ point-indices)
|
||||
(reduce modify-handler $ handler-indices))))]
|
||||
modifiers (get-in state [:workspace-local :edit-path id :content-modifiers] {})
|
||||
modifiers (->> points
|
||||
(reduce modifiers-reducer modifiers))]
|
||||
|
||||
(ptk/reify ::move-point
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [id (st/get-path-id state)
|
||||
content (get-in state (st/get-path state :content))
|
||||
delta (gpt/subtract to-point from-point)
|
||||
|
||||
modifiers-reducer (partial modify-content-point content delta)
|
||||
|
||||
points (get-in state [:workspace-local :edit-path id :selected-points] #{})
|
||||
|
||||
modifiers (get-in state [:workspace-local :edit-path id :content-modifiers] {})
|
||||
modifiers (->> points
|
||||
(reduce modifiers-reducer {}))]
|
||||
|
||||
(-> state
|
||||
(assoc-in [:workspace-local :edit-path id :moving-nodes] true)
|
||||
(assoc-in [:workspace-local :edit-path id :content-modifiers] modifiers)))))))
|
||||
(-> state
|
||||
(assoc-in [:workspace-local :edit-path id :moving-nodes] true)
|
||||
(assoc-in [:workspace-local :edit-path id :content-modifiers] modifiers))))))
|
||||
|
||||
(declare drag-selected-points)
|
||||
|
||||
|
@ -126,7 +142,6 @@
|
|||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [stopper (->> stream (rx/filter ms/mouse-up?))
|
||||
zoom (get-in state [:workspace-local :zoom])
|
||||
id (get-in state [:workspace-local :edition])
|
||||
snap-toggled (get-in state [:workspace-local :edit-path id :snap-toggled])
|
||||
|
||||
|
@ -143,6 +158,73 @@
|
|||
(rx/map #(move-selected-path-point start-position %)))
|
||||
(rx/of (apply-content-modifiers)))))))
|
||||
|
||||
(defn- get-displacement
|
||||
"Retrieve the correct displacement delta point for the
|
||||
provided direction speed and distances thresholds."
|
||||
[direction]
|
||||
(case direction
|
||||
:up (gpt/point 0 (- 1))
|
||||
:down (gpt/point 0 1)
|
||||
:left (gpt/point (- 1) 0)
|
||||
:right (gpt/point 1 0)))
|
||||
|
||||
(defn finish-move-selected []
|
||||
(ptk/reify ::move-selected
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [id (get-in state [:workspace-local :edition])]
|
||||
(-> state
|
||||
(update-in [:workspace-local :edit-path id] dissoc :current-move))))))
|
||||
|
||||
(defn move-selected
|
||||
[direction shift?]
|
||||
|
||||
(let [same-event (js/Symbol "same-event")]
|
||||
(ptk/reify ::move-selected
|
||||
IDeref
|
||||
(-deref [_] direction)
|
||||
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [id (get-in state [:workspace-local :edition])
|
||||
current-move (get-in state [:workspace-local :edit-path id :current-move])]
|
||||
(if (nil? current-move)
|
||||
(-> state
|
||||
(assoc-in [:workspace-local :edit-path id :moving-nodes] true)
|
||||
(assoc-in [:workspace-local :edit-path id :current-move] same-event))
|
||||
state)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [id (get-in state [:workspace-local :edition])
|
||||
current-move (get-in state [:workspace-local :edit-path id :current-move])]
|
||||
(if (= same-event current-move)
|
||||
(let [points (get-in state [:workspace-local :edit-path id :selected-points] #{})
|
||||
|
||||
move-events (->> stream
|
||||
(rx/filter (ptk/type? ::move-selected))
|
||||
(rx/filter #(= direction (deref %))))
|
||||
|
||||
stopper (->> move-events (rx/debounce 100) (rx/take 1))
|
||||
|
||||
scale (if shift? (gpt/point 10) (gpt/point 1))
|
||||
|
||||
mov-vec (gpt/multiply (get-displacement direction) scale)]
|
||||
|
||||
(rx/concat
|
||||
(rx/merge
|
||||
(->> move-events
|
||||
(rx/take-until stopper)
|
||||
(rx/scan #(gpt/add %1 mov-vec) (gpt/point 0 0))
|
||||
(rx/map #(set-move-modifier points %)))
|
||||
|
||||
;; First event is not read by the stream so we need to send it again
|
||||
(rx/of (move-selected direction shift?)))
|
||||
|
||||
(rx/of (apply-content-modifiers)
|
||||
(finish-move-selected))))
|
||||
(rx/empty)))))))
|
||||
|
||||
(defn start-move-handler
|
||||
[index prefix]
|
||||
(ptk/reify ::start-move-handler
|
||||
|
|
|
@ -32,61 +32,95 @@
|
|||
(rx/empty))))))
|
||||
|
||||
(def shortcuts
|
||||
{:move-nodes {:tooltip "V"
|
||||
:command "v"
|
||||
:fn #(st/emit! (drp/change-edit-mode :move))}
|
||||
{:move-nodes {:tooltip "V"
|
||||
:command "v"
|
||||
:fn #(st/emit! (drp/change-edit-mode :move))}
|
||||
|
||||
:draw-nodes {:tooltip "P"
|
||||
:command "p"
|
||||
:fn #(st/emit! (drp/change-edit-mode :draw))}
|
||||
:draw-nodes {:tooltip "P"
|
||||
:command "p"
|
||||
:fn #(st/emit! (drp/change-edit-mode :draw))}
|
||||
|
||||
:add-node {:tooltip "+"
|
||||
:command "+"
|
||||
:fn #(st/emit! (drp/add-node))}
|
||||
:add-node {:tooltip "+"
|
||||
:command "+"
|
||||
:fn #(st/emit! (drp/add-node))}
|
||||
|
||||
:delete-node {:tooltip (ds/supr)
|
||||
:command ["del" "backspace"]
|
||||
:fn #(st/emit! (drp/remove-node))}
|
||||
:delete-node {:tooltip (ds/supr)
|
||||
:command ["del" "backspace"]
|
||||
:fn #(st/emit! (drp/remove-node))}
|
||||
|
||||
:merge-nodes {:tooltip (ds/meta "J")
|
||||
:command (ds/c-mod "j")
|
||||
:fn #(st/emit! (drp/merge-nodes))}
|
||||
:merge-nodes {:tooltip (ds/meta "J")
|
||||
:command (ds/c-mod "j")
|
||||
:fn #(st/emit! (drp/merge-nodes))}
|
||||
|
||||
:join-nodes {:tooltip "J"
|
||||
:command "j"
|
||||
:fn #(st/emit! (drp/join-nodes))}
|
||||
:join-nodes {:tooltip "J"
|
||||
:command "j"
|
||||
:fn #(st/emit! (drp/join-nodes))}
|
||||
|
||||
:separate-nodes {:tooltip "K"
|
||||
:command "k"
|
||||
:fn #(st/emit! (drp/separate-nodes))}
|
||||
:separate-nodes {:tooltip "K"
|
||||
:command "k"
|
||||
:fn #(st/emit! (drp/separate-nodes))}
|
||||
|
||||
:make-corner {:tooltip "B"
|
||||
:command "b"
|
||||
:fn #(st/emit! (drp/make-corner))}
|
||||
:make-corner {:tooltip "B"
|
||||
:command "b"
|
||||
:fn #(st/emit! (drp/make-corner))}
|
||||
|
||||
:make-curve {:tooltip (ds/meta "B")
|
||||
:command (ds/c-mod "b")
|
||||
:fn #(st/emit! (drp/make-curve))}
|
||||
:make-curve {:tooltip (ds/meta "B")
|
||||
:command (ds/c-mod "b")
|
||||
:fn #(st/emit! (drp/make-curve))}
|
||||
|
||||
:snap-nodes {:tooltip (ds/meta "'")
|
||||
:command (ds/c-mod "'")
|
||||
:fn #(st/emit! (drp/toggle-snap))}
|
||||
|
||||
:escape {:tooltip (ds/esc)
|
||||
:command "escape"
|
||||
:fn #(st/emit! (esc-pressed))}
|
||||
:snap-nodes {:tooltip (ds/meta "'")
|
||||
:command (ds/c-mod "'")
|
||||
:fn #(st/emit! (drp/toggle-snap))}
|
||||
|
||||
:start-editing {:tooltip (ds/enter)
|
||||
:command "enter"
|
||||
:fn #(st/emit! (dw/start-editing-selected))}
|
||||
:escape {:tooltip (ds/esc)
|
||||
:command "escape"
|
||||
:fn #(st/emit! (esc-pressed))}
|
||||
|
||||
:undo {:tooltip (ds/meta "Z")
|
||||
:command (ds/c-mod "z")
|
||||
:fn #(st/emit! (drp/undo-path))}
|
||||
:start-editing {:tooltip (ds/enter)
|
||||
:command "enter"
|
||||
:fn #(st/emit! (dw/start-editing-selected))}
|
||||
|
||||
:undo {:tooltip (ds/meta "Z")
|
||||
:command (ds/c-mod "z")
|
||||
:fn #(st/emit! (drp/undo-path))}
|
||||
|
||||
:redo {:tooltip (ds/meta "Y")
|
||||
:command [(ds/c-mod "shift+z") (ds/c-mod "y")]
|
||||
:fn #(st/emit! (drp/redo-path))}
|
||||
|
||||
;; Arrow movement
|
||||
:move-fast-up {:tooltip (ds/shift ds/up-arrow)
|
||||
:command "shift+up"
|
||||
:fn #(st/emit! (drp/move-selected :up true))}
|
||||
|
||||
:move-fast-down {:tooltip (ds/shift ds/down-arrow)
|
||||
:command "shift+down"
|
||||
:fn #(st/emit! (drp/move-selected :down true))}
|
||||
|
||||
:move-fast-right {:tooltip (ds/shift ds/right-arrow)
|
||||
:command "shift+right"
|
||||
:fn #(st/emit! (drp/move-selected :right true))}
|
||||
|
||||
:move-fast-left {:tooltip (ds/shift ds/left-arrow)
|
||||
:command "shift+left"
|
||||
:fn #(st/emit! (drp/move-selected :left true))}
|
||||
|
||||
:move-unit-up {:tooltip ds/up-arrow
|
||||
:command "up"
|
||||
:fn #(st/emit! (drp/move-selected :up false))}
|
||||
|
||||
:move-unit-down {:tooltip ds/down-arrow
|
||||
:command "down"
|
||||
:fn #(st/emit! (drp/move-selected :down false))}
|
||||
|
||||
:move-unit-left {:tooltip ds/right-arrow
|
||||
:command "right"
|
||||
:fn #(st/emit! (drp/move-selected :right false))}
|
||||
|
||||
:move-unit-right {:tooltip ds/left-arrow
|
||||
:command "left"
|
||||
:fn #(st/emit! (drp/move-selected :left false))}
|
||||
|
||||
:redo {:tooltip (ds/meta "Y")
|
||||
:command [(ds/c-mod "shift+z") (ds/c-mod "y")]
|
||||
:fn #(st/emit! (drp/redo-path))}
|
||||
})
|
||||
|
||||
(defn get-tooltip [shortcut]
|
||||
|
|
Loading…
Add table
Reference in a new issue