mirror of
https://github.com/penpot/penpot.git
synced 2025-05-26 04:56:14 +02:00
♻️ Refactor path editor components: path-handler and path-point
This commit is contained in:
parent
da2f519805
commit
3d864c4ff1
1 changed files with 138 additions and 105 deletions
|
@ -37,16 +37,25 @@
|
||||||
(def path-preview-dasharray 4)
|
(def path-preview-dasharray 4)
|
||||||
(def path-snap-stroke-width 1)
|
(def path-snap-stroke-width 1)
|
||||||
|
|
||||||
(mf/defc path-point [{:keys [position zoom edit-mode hover? selected? preview? start-path? last-p? new-point? curve?]}]
|
(mf/defc path-point*
|
||||||
|
{::mf/private true}
|
||||||
|
[{:keys [position zoom edit-mode is-hover is-selected is-preview is-start-path is-last is-new is-curve]}]
|
||||||
(let [{:keys [x y]} position
|
(let [{:keys [x y]} position
|
||||||
|
|
||||||
|
is-draw (= edit-mode :draw)
|
||||||
|
is-move (= edit-mode :move)
|
||||||
|
|
||||||
|
is-active
|
||||||
|
(or ^boolean is-selected
|
||||||
|
^boolean is-hover)
|
||||||
|
|
||||||
on-enter
|
on-enter
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(fn [_]
|
(fn [_]
|
||||||
(st/emit! (drp/path-pointer-enter position))))
|
(st/emit! (drp/path-pointer-enter position))))
|
||||||
|
|
||||||
on-leave
|
on-leave
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(fn [_]
|
(fn [_]
|
||||||
(st/emit! (drp/path-pointer-leave position))))
|
(st/emit! (drp/path-pointer-leave position))))
|
||||||
|
|
||||||
|
@ -55,41 +64,44 @@
|
||||||
(dom/stop-propagation event)
|
(dom/stop-propagation event)
|
||||||
(dom/prevent-default event)
|
(dom/prevent-default event)
|
||||||
|
|
||||||
(when (and new-point? (some? (meta position)))
|
;; FIXME: revisit this, using meta here breaks equality checks
|
||||||
|
(when (and is-new (some? (meta position)))
|
||||||
(st/emit! (drp/create-node-at-position (meta position))))
|
(st/emit! (drp/create-node-at-position (meta position))))
|
||||||
|
|
||||||
(let [shift? (kbd/shift? event)
|
(let [is-shift (kbd/shift? event)
|
||||||
mod? (kbd/mod? event)]
|
is-mod (kbd/mod? event)]
|
||||||
(cond
|
(cond
|
||||||
last-p?
|
is-last
|
||||||
(st/emit! (drp/reset-last-handler))
|
(st/emit! (drp/reset-last-handler))
|
||||||
|
|
||||||
(and (= edit-mode :move) mod? (not curve?))
|
(and is-move is-mod (not is-curve))
|
||||||
(st/emit! (drp/make-curve position))
|
(st/emit! (drp/make-curve position))
|
||||||
|
|
||||||
(and (= edit-mode :move) mod? curve?)
|
(and is-move is-mod is-curve)
|
||||||
(st/emit! (drp/make-corner position))
|
(st/emit! (drp/make-corner position))
|
||||||
|
|
||||||
(= edit-mode :move)
|
is-move
|
||||||
;; If we're dragging a selected item we don't change the selection
|
;; If we're dragging a selected item we don't change the selection
|
||||||
(st/emit! (drp/start-move-path-point position shift?))
|
(st/emit! (drp/start-move-path-point position is-shift))
|
||||||
|
|
||||||
(and (= edit-mode :draw) start-path?)
|
(and is-draw is-start-path)
|
||||||
(st/emit! (drp/start-path-from-point position))
|
(st/emit! (drp/start-path-from-point position))
|
||||||
|
|
||||||
(and (= edit-mode :draw) (not start-path?))
|
(and is-draw (not is-start-path))
|
||||||
(st/emit! (drp/close-path-drag-start position)))))]
|
(st/emit! (drp/close-path-drag-start position)))))]
|
||||||
|
|
||||||
[:g.path-point
|
[:g.path-point
|
||||||
[:circle.path-point
|
[:circle.path-point
|
||||||
{:cx x
|
{:cx x
|
||||||
:cy y
|
:cy y
|
||||||
:r (if (or selected? hover?) (/ point-radius zoom) (/ point-radius-selected zoom))
|
:r (if ^boolean is-active
|
||||||
|
(/ point-radius zoom)
|
||||||
|
(/ point-radius-selected zoom))
|
||||||
:style {:stroke-width (/ point-radius-stroke-width zoom)
|
:style {:stroke-width (/ point-radius-stroke-width zoom)
|
||||||
:stroke (cond (or selected? hover?) pc/black-color
|
:stroke (cond ^boolean is-active pc/black-color
|
||||||
preview? pc/secondary-color
|
^boolean is-preview pc/secondary-color
|
||||||
:else pc/accent-color)
|
:else pc/accent-color)
|
||||||
:fill (cond selected? pc/accent-color
|
:fill (cond is-selected pc/accent-color
|
||||||
:else pc/white-color)}}]
|
:else pc/white-color)}}]
|
||||||
[:circle {:cx x
|
[:circle {:cx x
|
||||||
:cy y
|
:cy y
|
||||||
|
@ -97,70 +109,87 @@
|
||||||
:on-pointer-down on-pointer-down
|
:on-pointer-down on-pointer-down
|
||||||
:on-pointer-enter on-enter
|
:on-pointer-enter on-enter
|
||||||
:on-pointer-leave on-leave
|
:on-pointer-leave on-leave
|
||||||
:pointer-events (when-not preview? "visible")
|
:pointer-events (when-not ^boolean is-preview "visible")
|
||||||
:class (cond (= edit-mode :draw) (cur/get-static "pen-node")
|
:class (cond ^boolean is-draw (cur/get-static "pen-node")
|
||||||
(= edit-mode :move) (cur/get-static "pointer-node"))
|
^boolean is-move (cur/get-static "pointer-node"))
|
||||||
:style {:stroke-width 0
|
:style {:stroke-width 0
|
||||||
:fill "none"}}]]))
|
:fill "none"}}]]))
|
||||||
|
|
||||||
(mf/defc path-handler [{:keys [index prefix point handler zoom selected? hover? edit-mode snap-angle?]}]
|
;; FIXME: is-selected prop looks unused
|
||||||
(when (and point handler)
|
|
||||||
(let [{:keys [x y]} handler
|
|
||||||
on-enter
|
|
||||||
(fn [_]
|
|
||||||
(st/emit! (drp/path-handler-enter index prefix)))
|
|
||||||
|
|
||||||
on-leave
|
(mf/defc path-handler*
|
||||||
(fn [_]
|
{::mf/private true}
|
||||||
(st/emit! (drp/path-handler-leave index prefix)))
|
[{:keys [index prefix point handler zoom is-selected is-hover edit-mode snap-angle]}]
|
||||||
|
(let [x (dm/get-prop handler :x)
|
||||||
|
y (dm/get-prop handler :y)
|
||||||
|
is-draw (= edit-mode :draw)
|
||||||
|
is-move (= edit-mode :move)
|
||||||
|
|
||||||
on-pointer-down
|
is-active
|
||||||
(fn [event]
|
(or ^boolean is-selected
|
||||||
(dom/stop-propagation event)
|
^boolean is-hover)
|
||||||
(dom/prevent-default event)
|
|
||||||
|
|
||||||
(cond
|
on-enter
|
||||||
(= edit-mode :move)
|
(mf/use-fn
|
||||||
(st/emit! (drp/start-move-handler index prefix))))]
|
(mf/deps index prefix)
|
||||||
|
(fn [_] (st/emit! (drp/path-handler-enter index prefix))))
|
||||||
|
|
||||||
[:g.handler {:pointer-events (if (= edit-mode :draw) "none" "visible")}
|
on-leave
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps index prefix)
|
||||||
|
(fn [_] (st/emit! (drp/path-handler-leave index prefix))))
|
||||||
|
|
||||||
|
on-pointer-down
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps index prefix is-move)
|
||||||
|
(fn [event]
|
||||||
|
(dom/stop-propagation event)
|
||||||
|
(dom/prevent-default event)
|
||||||
|
|
||||||
|
(when ^boolean is-move
|
||||||
|
(st/emit! (drp/start-move-handler index prefix)))))]
|
||||||
|
|
||||||
|
[:g.handler {:pointer-events (if ^boolean is-draw "none" "visible")}
|
||||||
|
[:line
|
||||||
|
{:x1 (:x point)
|
||||||
|
:y1 (:y point)
|
||||||
|
:x2 x
|
||||||
|
:y2 y
|
||||||
|
:style {:stroke (if ^boolean is-hover
|
||||||
|
pc/black-color
|
||||||
|
pc/gray-color)
|
||||||
|
:stroke-width (/ point-radius-stroke-width zoom)}}]
|
||||||
|
|
||||||
|
(when ^boolean snap-angle
|
||||||
[:line
|
[:line
|
||||||
{:x1 (:x point)
|
{:x1 (:x point)
|
||||||
:y1 (:y point)
|
:y1 (:y point)
|
||||||
:x2 x
|
:x2 x
|
||||||
:y2 y
|
:y2 y
|
||||||
:style {:stroke (if hover? pc/black-color pc/gray-color)
|
:style {:stroke pc/secondary-color
|
||||||
:stroke-width (/ point-radius-stroke-width zoom)}}]
|
:stroke-width (/ point-radius-stroke-width zoom)}}])
|
||||||
|
|
||||||
(when snap-angle?
|
[:rect
|
||||||
[:line
|
{:x (- x (/ handler-side 2 zoom))
|
||||||
{:x1 (:x point)
|
:y (- y (/ handler-side 2 zoom))
|
||||||
:y1 (:y point)
|
:width (/ handler-side zoom)
|
||||||
:x2 x
|
:height (/ handler-side zoom)
|
||||||
:y2 y
|
|
||||||
:style {:stroke pc/secondary-color
|
|
||||||
:stroke-width (/ point-radius-stroke-width zoom)}}])
|
|
||||||
|
|
||||||
[:rect
|
:style {:stroke-width (/ handler-stroke-width zoom)
|
||||||
{:x (- x (/ handler-side 2 zoom))
|
:stroke (cond ^boolean is-active pc/black-color
|
||||||
:y (- y (/ handler-side 2 zoom))
|
:else pc/accent-color)
|
||||||
:width (/ handler-side zoom)
|
:fill (cond ^boolean is-selected pc/accent-color
|
||||||
:height (/ handler-side zoom)
|
:else pc/white-color)}}]
|
||||||
|
[:circle {:cx x
|
||||||
:style {:stroke-width (/ handler-stroke-width zoom)
|
:cy y
|
||||||
:stroke (cond (or selected? hover?) pc/black-color
|
:r (/ point-radius-active-area zoom)
|
||||||
:else pc/accent-color)
|
:on-pointer-down on-pointer-down
|
||||||
:fill (cond selected? pc/accent-color
|
:on-pointer-enter on-enter
|
||||||
:else pc/white-color)}}]
|
:on-pointer-leave on-leave
|
||||||
[:circle {:cx x
|
:class (when ^boolean is-move
|
||||||
:cy y
|
(cur/get-static "pointer-move"))
|
||||||
:r (/ point-radius-active-area zoom)
|
:style {:fill "none"
|
||||||
:on-pointer-down on-pointer-down
|
:stroke-width 0}}]]))
|
||||||
:on-pointer-enter on-enter
|
|
||||||
:on-pointer-leave on-leave
|
|
||||||
:class (when (= edit-mode :move) (cur/get-static "pointer-move"))
|
|
||||||
:style {:fill "none"
|
|
||||||
:stroke-width 0}}]])))
|
|
||||||
|
|
||||||
(mf/defc path-preview [{:keys [zoom command from]}]
|
(mf/defc path-preview [{:keys [zoom command from]}]
|
||||||
[:g.preview {:style {:pointer-events "none"}}
|
[:g.preview {:style {:pointer-events "none"}}
|
||||||
|
@ -173,9 +202,9 @@
|
||||||
:params {:x (:x from)
|
:params {:x (:x from)
|
||||||
:y (:y from)}}
|
:y (:y from)}}
|
||||||
command])}])
|
command])}])
|
||||||
[:& path-point {:position (:params command)
|
[:> path-point* {:position (:params command)
|
||||||
:preview? true
|
:is-preview true
|
||||||
:zoom zoom}]])
|
:zoom zoom}]])
|
||||||
|
|
||||||
(mf/defc path-snap [{:keys [selected points zoom]}]
|
(mf/defc path-snap [{:keys [selected points zoom]}]
|
||||||
(let [ranges (mf/use-memo (mf/deps selected points) #(snap/create-ranges points selected))
|
(let [ranges (mf/use-memo (mf/deps selected points) #(snap/create-ranges points selected))
|
||||||
|
@ -250,7 +279,7 @@
|
||||||
last-p (->> content last path.segment/get-point)
|
last-p (->> content last path.segment/get-point)
|
||||||
handlers (path.segment/content->handlers content)
|
handlers (path.segment/content->handlers content)
|
||||||
|
|
||||||
start-p? (not (some? last-point))
|
is-path-start (not (some? last-point))
|
||||||
|
|
||||||
[snap-selected snap-points]
|
[snap-selected snap-points]
|
||||||
(cond
|
(cond
|
||||||
|
@ -297,20 +326,20 @@
|
||||||
:from last-p
|
:from last-p
|
||||||
:zoom zoom}])
|
:zoom zoom}])
|
||||||
|
|
||||||
(when drag-handler
|
(when (and drag-handler last-p)
|
||||||
[:g.drag-handler {:pointer-events "none"}
|
[:g.drag-handler {:pointer-events "none"}
|
||||||
[:& path-handler {:point last-p
|
[:> path-handler* {:point last-p
|
||||||
:handler drag-handler
|
:handler drag-handler
|
||||||
:edit-mode edit-mode
|
:edit-mode edit-mode
|
||||||
:zoom zoom}]])
|
:zoom zoom}]])
|
||||||
|
|
||||||
(when @hover-point
|
(when @hover-point
|
||||||
[:g.hover-point
|
[:g.hover-point
|
||||||
[:& path-point {:position @hover-point
|
[:> path-point* {:position @hover-point
|
||||||
:edit-mode edit-mode
|
:edit-mode edit-mode
|
||||||
:new-point? true
|
:is-new true
|
||||||
:start-path? start-p?
|
:is-start-path is-path-start
|
||||||
:zoom zoom}]])
|
:zoom zoom}]])
|
||||||
|
|
||||||
(for [[index position] (d/enumerate points)]
|
(for [[index position] (d/enumerate points)]
|
||||||
(let [show-handler?
|
(let [show-handler?
|
||||||
|
@ -321,10 +350,10 @@
|
||||||
pos-handlers (get handlers position)
|
pos-handlers (get handlers position)
|
||||||
point-selected? (contains? selected-points (get point->base position))
|
point-selected? (contains? selected-points (get point->base position))
|
||||||
point-hover? (contains? hover-points (get point->base position))
|
point-hover? (contains? hover-points (get point->base position))
|
||||||
last-p? (= last-point (get point->base position))
|
is-last (= last-point (get point->base position))
|
||||||
|
|
||||||
pos-handlers (->> pos-handlers (filter show-handler?))
|
pos-handlers (->> pos-handlers (filter show-handler?))
|
||||||
curve? (boolean (seq pos-handlers))]
|
is-curve (boolean (seq pos-handlers))]
|
||||||
|
|
||||||
[:g.path-node {:key (dm/str index "-" (:x position) "-" (:y position))}
|
[:g.path-node {:key (dm/str index "-" (:x position) "-" (:y position))}
|
||||||
[:g.point-handlers {:pointer-events (when (= edit-mode :draw) "none")}
|
[:g.point-handlers {:pointer-events (when (= edit-mode :draw) "none")}
|
||||||
|
@ -333,30 +362,34 @@
|
||||||
handler-hover? (contains? hover-handlers [hindex prefix])
|
handler-hover? (contains? hover-handlers [hindex prefix])
|
||||||
moving-handler? (= handler-position moving-handler)
|
moving-handler? (= handler-position moving-handler)
|
||||||
matching-handler? (matching-handler? content position pos-handlers)]
|
matching-handler? (matching-handler? content position pos-handlers)]
|
||||||
[:& path-handler {:key (dm/str (dm/str index "-" (:x position) "-" (:y position)) "-" hindex "-" (d/name prefix))
|
|
||||||
:point position
|
|
||||||
:handler handler-position
|
|
||||||
:index hindex
|
|
||||||
:prefix prefix
|
|
||||||
:zoom zoom
|
|
||||||
:hover? handler-hover?
|
|
||||||
:snap-angle? (and moving-handler? matching-handler?)
|
|
||||||
:edit-mode edit-mode}]))]
|
|
||||||
[:& path-point {:position position
|
|
||||||
:zoom zoom
|
|
||||||
:edit-mode edit-mode
|
|
||||||
:selected? point-selected?
|
|
||||||
:hover? point-hover?
|
|
||||||
:last-p? last-p?
|
|
||||||
:start-path? start-p?
|
|
||||||
:curve? curve?}]]))
|
|
||||||
|
|
||||||
(when prev-handler
|
(when (and position handler-position)
|
||||||
|
[:> path-handler*
|
||||||
|
{:key (dm/str (dm/str index "-" (:x position) "-" (:y position)) "-" hindex "-" (d/name prefix))
|
||||||
|
:point position
|
||||||
|
:handler handler-position
|
||||||
|
:index hindex
|
||||||
|
:prefix prefix
|
||||||
|
:zoom zoom
|
||||||
|
:is-hover handler-hover?
|
||||||
|
:snap-angle (and moving-handler? matching-handler?)
|
||||||
|
:edit-mode edit-mode}])))]
|
||||||
|
[:> path-point* {:position position
|
||||||
|
:zoom zoom
|
||||||
|
:edit-mode edit-mode
|
||||||
|
:is-selected point-selected?
|
||||||
|
:is-hover point-hover?
|
||||||
|
:is-last is-last
|
||||||
|
:is-start-path is-path-start
|
||||||
|
:is-curve is-curve}]]))
|
||||||
|
|
||||||
|
(when (and prev-handler last-p)
|
||||||
[:g.prev-handler {:pointer-events "none"}
|
[:g.prev-handler {:pointer-events "none"}
|
||||||
[:& path-handler {:point last-p
|
[:> path-handler*
|
||||||
:edit-mode edit-mode
|
{:point last-p
|
||||||
:handler prev-handler
|
:edit-mode edit-mode
|
||||||
:zoom zoom}]])
|
:handler prev-handler
|
||||||
|
:zoom zoom}]])
|
||||||
|
|
||||||
(when show-snap?
|
(when show-snap?
|
||||||
[:g.path-snap {:pointer-events "none"}
|
[:g.path-snap {:pointer-events "none"}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue