mirror of
https://github.com/penpot/penpot.git
synced 2025-02-03 12:59:12 -05:00
✨ Improvements to loop removing
This commit is contained in:
parent
2184286a78
commit
1a7b098282
8 changed files with 96 additions and 73 deletions
|
@ -22,6 +22,7 @@
|
||||||
[app.util.path.commands :as upc]
|
[app.util.path.commands :as upc]
|
||||||
[app.util.path.geom :as upg]
|
[app.util.path.geom :as upg]
|
||||||
[app.util.path.tools :as upt]
|
[app.util.path.tools :as upt]
|
||||||
|
[app.util.path.subpaths :as ups]
|
||||||
[beicon.core :as rx]
|
[beicon.core :as rx]
|
||||||
[potok.core :as ptk]))
|
[potok.core :as ptk]))
|
||||||
|
|
||||||
|
@ -35,9 +36,7 @@
|
||||||
modifiers (helpers/move-handler-modifiers content index prefix false match-opposite? dx dy)
|
modifiers (helpers/move-handler-modifiers content index prefix false match-opposite? dx dy)
|
||||||
[cx cy] (if (= prefix :c1) [:c1x :c1y] [:c2x :c2y])
|
[cx cy] (if (= prefix :c1) [:c1x :c1y] [:c2x :c2y])
|
||||||
point (gpt/point (+ (get-in content [index :params cx]) dx)
|
point (gpt/point (+ (get-in content [index :params cx]) dx)
|
||||||
(+ (get-in content [index :params cy]) dy))
|
(+ (get-in content [index :params cy]) dy))]
|
||||||
|
|
||||||
]
|
|
||||||
|
|
||||||
(-> state
|
(-> state
|
||||||
(update-in [:workspace-local :edit-path id :content-modifiers] merge modifiers)
|
(update-in [:workspace-local :edit-path id :content-modifiers] merge modifiers)
|
||||||
|
@ -192,8 +191,8 @@
|
||||||
(ptk/reify ::start-path-edit
|
(ptk/reify ::start-path-edit
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(let [edit-path (get-in state [:workspace-local :edit-path id])]
|
(let [edit-path (get-in state [:workspace-local :edit-path id])
|
||||||
|
state (update-in state (st/get-path state :content) ups/close-subpaths)]
|
||||||
(cond-> state
|
(cond-> state
|
||||||
(or (not edit-path) (= :draw (:edit-mode edit-path)))
|
(or (not edit-path) (= :draw (:edit-mode edit-path)))
|
||||||
(assoc-in [:workspace-local :edit-path id] {:edit-mode :move
|
(assoc-in [:workspace-local :edit-path id] {:edit-mode :move
|
||||||
|
|
|
@ -11,10 +11,11 @@
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[app.common.geom.shapes :as gsh]
|
[app.common.geom.shapes :as gsh]
|
||||||
[app.common.math :as mth]
|
[app.common.math :as mth]
|
||||||
[app.main.data.workspace.path.state :refer [get-path]]
|
|
||||||
[app.main.data.workspace.path.common :as common]
|
[app.main.data.workspace.path.common :as common]
|
||||||
|
[app.main.data.workspace.path.state :refer [get-path]]
|
||||||
[app.main.streams :as ms]
|
[app.main.streams :as ms]
|
||||||
[app.util.path.commands :as upc]
|
[app.util.path.commands :as upc]
|
||||||
|
[app.util.path.subpaths :as ups]
|
||||||
[potok.core :as ptk]))
|
[potok.core :as ptk]))
|
||||||
|
|
||||||
;; CONSTANTS
|
;; CONSTANTS
|
||||||
|
@ -105,6 +106,7 @@
|
||||||
(let [command (next-node shape position prev-point prev-handler)]
|
(let [command (next-node shape position prev-point prev-handler)]
|
||||||
(-> shape
|
(-> shape
|
||||||
(update :content (fnil conj []) command)
|
(update :content (fnil conj []) command)
|
||||||
|
(update :content ups/close-subpaths)
|
||||||
(update-selrect))))
|
(update-selrect))))
|
||||||
|
|
||||||
(defn angle-points [common p1 p2]
|
(defn angle-points [common p1 p2]
|
||||||
|
|
|
@ -40,8 +40,8 @@
|
||||||
:command "p"
|
:command "p"
|
||||||
:fn #(st/emit! (drp/change-edit-mode :draw))}
|
:fn #(st/emit! (drp/change-edit-mode :draw))}
|
||||||
|
|
||||||
:add-node {:tooltip (ds/meta "+")
|
:add-node {:tooltip "+"
|
||||||
:command (ds/c-mod "+")
|
:command "+"
|
||||||
:fn #(st/emit! (drp/add-node))}
|
:fn #(st/emit! (drp/add-node))}
|
||||||
|
|
||||||
:delete-node {:tooltip (ds/supr)
|
:delete-node {:tooltip (ds/supr)
|
||||||
|
@ -52,20 +52,20 @@
|
||||||
:command (ds/c-mod "j")
|
:command (ds/c-mod "j")
|
||||||
:fn #(st/emit! (drp/merge-nodes))}
|
:fn #(st/emit! (drp/merge-nodes))}
|
||||||
|
|
||||||
:join-nodes {:tooltip (ds/meta-shift "J")
|
:join-nodes {:tooltip "J"
|
||||||
:command (ds/c-mod "shift+j")
|
:command "j"
|
||||||
:fn #(st/emit! (drp/join-nodes))}
|
:fn #(st/emit! (drp/join-nodes))}
|
||||||
|
|
||||||
:separate-nodes {:tooltip (ds/meta "K")
|
:separate-nodes {:tooltip "K"
|
||||||
:command (ds/c-mod "k")
|
:command "k"
|
||||||
:fn #(st/emit! (drp/separate-nodes))}
|
:fn #(st/emit! (drp/separate-nodes))}
|
||||||
|
|
||||||
:make-corner {:tooltip (ds/meta "B")
|
:make-corner {:tooltip "B"
|
||||||
:command (ds/c-mod "b")
|
:command "b"
|
||||||
:fn #(st/emit! (drp/make-corner))}
|
:fn #(st/emit! (drp/make-corner))}
|
||||||
|
|
||||||
:make-curve {:tooltip (ds/meta-shift "B")
|
:make-curve {:tooltip (ds/meta "B")
|
||||||
:command (ds/c-mod "shift+b")
|
:command (ds/c-mod "b")
|
||||||
:fn #(st/emit! (drp/make-curve))}
|
:fn #(st/emit! (drp/make-curve))}
|
||||||
|
|
||||||
:snap-nodes {:tooltip (ds/meta "'")
|
:snap-nodes {:tooltip (ds/meta "'")
|
||||||
|
|
|
@ -11,33 +11,46 @@
|
||||||
[app.main.data.workspace.path.common :as common]
|
[app.main.data.workspace.path.common :as common]
|
||||||
[app.main.data.workspace.path.state :as st]
|
[app.main.data.workspace.path.state :as st]
|
||||||
[app.util.path.tools :as upt]
|
[app.util.path.tools :as upt]
|
||||||
|
[app.util.path.subpaths :as ups]
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[beicon.core :as rx]
|
[beicon.core :as rx]
|
||||||
[potok.core :as ptk]))
|
[potok.core :as ptk]))
|
||||||
|
|
||||||
(defn process-path-tool
|
(defn process-path-tool
|
||||||
"Generic function that executes path transformations with the content and selected nodes"
|
"Generic function that executes path transformations with the content and selected nodes"
|
||||||
[tool-fn]
|
([tool-fn]
|
||||||
(ptk/reify ::process-path-tool
|
(process-path-tool nil tool-fn))
|
||||||
ptk/WatchEvent
|
([points tool-fn]
|
||||||
(watch [_ state stream]
|
(ptk/reify ::process-path-tool
|
||||||
(let [id (st/get-path-id state)
|
ptk/WatchEvent
|
||||||
page-id (:current-page-id state)
|
(watch [_ state stream]
|
||||||
shape (get-in state (st/get-path state))
|
(let [id (st/get-path-id state)
|
||||||
selected-points (get-in state [:workspace-local :edit-path id :selected-points] #{})
|
page-id (:current-page-id state)
|
||||||
new-content (tool-fn (:content shape) selected-points)
|
shape (get-in state (st/get-path state))
|
||||||
[rch uch] (changes/generate-path-changes page-id shape (:content shape) new-content)]
|
selected-points (get-in state [:workspace-local :edit-path id :selected-points] #{})
|
||||||
(rx/of (dwc/commit-changes rch uch {:commit-local? true}))))))
|
points (or points selected-points)
|
||||||
|
new-content (-> (tool-fn (:content shape) points)
|
||||||
|
(ups/close-subpaths))
|
||||||
|
[rch uch] (changes/generate-path-changes page-id shape (:content shape) new-content)]
|
||||||
|
(rx/of (dwc/commit-changes rch uch {:commit-local? true})))))))
|
||||||
|
|
||||||
(defn make-corner []
|
(defn make-corner
|
||||||
(process-path-tool
|
([]
|
||||||
(fn [content points]
|
(make-corner nil))
|
||||||
(reduce upt/make-corner-point content points))))
|
([point]
|
||||||
|
(process-path-tool
|
||||||
|
#{point}
|
||||||
|
(fn [content points]
|
||||||
|
(reduce upt/make-corner-point content points)))))
|
||||||
|
|
||||||
(defn make-curve []
|
(defn make-curve
|
||||||
(process-path-tool
|
([]
|
||||||
(fn [content points]
|
(make-curve nil))
|
||||||
(reduce upt/make-curve-point content points))))
|
([point]
|
||||||
|
(process-path-tool
|
||||||
|
#{point}
|
||||||
|
(fn [content points]
|
||||||
|
(reduce upt/make-curve-point content points)))))
|
||||||
|
|
||||||
(defn add-node []
|
(defn add-node []
|
||||||
(process-path-tool (fn [content points] (upt/split-segments content points 0.5))))
|
(process-path-tool (fn [content points] (upt/split-segments content points 0.5))))
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
[rumext.alpha :as mf])
|
[rumext.alpha :as mf])
|
||||||
(:import goog.events.EventType))
|
(:import goog.events.EventType))
|
||||||
|
|
||||||
(mf/defc path-point [{:keys [position zoom edit-mode hover? selected? preview? start-path? last-p? new-point?]}]
|
(mf/defc path-point [{:keys [position zoom edit-mode hover? selected? preview? start-path? last-p? new-point? curve?]}]
|
||||||
(let [{:keys [x y]} position
|
(let [{:keys [x y]} position
|
||||||
|
|
||||||
on-enter
|
on-enter
|
||||||
|
@ -45,8 +45,15 @@
|
||||||
(when (and new-point? (some? (meta position)))
|
(when (and new-point? (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 [shift? (kbd/shift? event)
|
||||||
|
ctrl? (kbd/ctrl? event)]
|
||||||
(cond
|
(cond
|
||||||
|
(and (= edit-mode :move) ctrl? (not curve?))
|
||||||
|
(st/emit! (drp/make-curve position))
|
||||||
|
|
||||||
|
(and (= edit-mode :move) ctrl? curve?)
|
||||||
|
(st/emit! (drp/make-corner position))
|
||||||
|
|
||||||
(= edit-mode :move)
|
(= edit-mode :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 shift?))
|
||||||
|
@ -274,37 +281,42 @@
|
||||||
:zoom zoom}]])
|
:zoom zoom}]])
|
||||||
|
|
||||||
(for [position points]
|
(for [position points]
|
||||||
(let [point-selected? (contains? selected-points (get point->base position))
|
(let [show-handler?
|
||||||
|
(fn [[index prefix]]
|
||||||
|
(let [handler-position (upc/handler->point content index prefix)]
|
||||||
|
(not= position handler-position)))
|
||||||
|
|
||||||
|
pos-handlers (get handlers 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))]
|
last-p? (= last-point (get point->base position))
|
||||||
|
|
||||||
|
pos-handlers (->> pos-handlers (filter show-handler?))
|
||||||
|
curve? (not (empty? pos-handlers))]
|
||||||
|
|
||||||
[:g.path-node
|
[:g.path-node
|
||||||
[:g.point-handlers {:pointer-events (when (= edit-mode :draw) "none")}
|
[:g.point-handlers {:pointer-events (when (= edit-mode :draw) "none")}
|
||||||
(let [pos-handlers (get handlers position)]
|
(for [[index prefix] pos-handlers]
|
||||||
(for [[index prefix] pos-handlers]
|
(let [handler-position (upc/handler->point content index prefix)
|
||||||
(let [command (get content index)
|
handler-hover? (contains? hover-handlers [index prefix])
|
||||||
x (get-in command [:params (d/prefix-keyword prefix :x)])
|
moving-handler? (= handler-position moving-handler)
|
||||||
y (get-in command [:params (d/prefix-keyword prefix :y)])
|
matching-handler? (matching-handler? content position pos-handlers)]
|
||||||
handler-position (gpt/point x y)
|
[:& path-handler {:point position
|
||||||
handler-hover? (contains? hover-handlers [index prefix])
|
:handler handler-position
|
||||||
moving-handler? (= handler-position moving-handler)
|
:index index
|
||||||
matching-handler? (matching-handler? content position pos-handlers)]
|
:prefix prefix
|
||||||
(when (not= position handler-position)
|
:zoom zoom
|
||||||
[:& path-handler {:point position
|
:hover? handler-hover?
|
||||||
:handler handler-position
|
:snap-angle? (and moving-handler? matching-handler?)
|
||||||
:index index
|
:edit-mode edit-mode}]))]
|
||||||
:prefix prefix
|
|
||||||
:zoom zoom
|
|
||||||
:hover? handler-hover?
|
|
||||||
:snap-angle? (and moving-handler? matching-handler?)
|
|
||||||
:edit-mode edit-mode}]))))]
|
|
||||||
[:& path-point {:position position
|
[:& path-point {:position position
|
||||||
:zoom zoom
|
:zoom zoom
|
||||||
:edit-mode edit-mode
|
:edit-mode edit-mode
|
||||||
:selected? point-selected?
|
:selected? point-selected?
|
||||||
:hover? point-hover?
|
:hover? point-hover?
|
||||||
:last-p? last-p?
|
:last-p? last-p?
|
||||||
:start-path? start-p?}]]))
|
:start-path? start-p?
|
||||||
|
:curve? curve?}]]))
|
||||||
|
|
||||||
(when prev-handler
|
(when prev-handler
|
||||||
[:g.prev-handler {:pointer-events "none"}
|
[:g.prev-handler {:pointer-events "none"}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
(defn check-enabled [content selected-points]
|
(defn check-enabled [content selected-points]
|
||||||
(let [segments (upt/get-segments content selected-points)
|
(let [segments (upt/get-segments content selected-points)
|
||||||
|
num-points (count selected-points)
|
||||||
points-selected? (not (empty? selected-points))
|
points-selected? (not (empty? selected-points))
|
||||||
segments-selected? (not (empty? segments))]
|
segments-selected? (not (empty? segments))]
|
||||||
{:make-corner points-selected?
|
{:make-corner points-selected?
|
||||||
|
@ -26,7 +27,7 @@
|
||||||
:add-node segments-selected?
|
:add-node segments-selected?
|
||||||
:remove-node points-selected?
|
:remove-node points-selected?
|
||||||
:merge-nodes segments-selected?
|
:merge-nodes segments-selected?
|
||||||
:join-nodes points-selected?
|
:join-nodes (and points-selected? (>= num-points 2))
|
||||||
:separate-nodes segments-selected?}))
|
:separate-nodes segments-selected?}))
|
||||||
|
|
||||||
(mf/defc path-actions [{:keys [shape]}]
|
(mf/defc path-actions [{:keys [shape]}]
|
||||||
|
|
|
@ -65,22 +65,20 @@
|
||||||
|
|
||||||
|
|
||||||
(defn format-path [content]
|
(defn format-path [content]
|
||||||
(let [content (ups/close-subpaths content)]
|
(with-out-str
|
||||||
(loop [result ""
|
(loop [last-move nil
|
||||||
last-move nil
|
|
||||||
current (first content)
|
current (first content)
|
||||||
content (rest content)]
|
content (rest content)]
|
||||||
|
|
||||||
(if (some? current)
|
(when (some? current)
|
||||||
(let [point (upc/command->point current)
|
(let [point (upc/command->point current)
|
||||||
current-move? (= :move-to (:command current))
|
current-move? (= :move-to (:command current))
|
||||||
result (str result (command->string current))
|
|
||||||
result (if (and (not current-move?) (= last-move point))
|
|
||||||
(str result "Z")
|
|
||||||
result)
|
|
||||||
last-move (if current-move? point last-move)]
|
last-move (if current-move? point last-move)]
|
||||||
(recur result
|
(print (command->string current))
|
||||||
last-move
|
|
||||||
|
(when (and (not current-move?) (= last-move point))
|
||||||
|
(print "Z"))
|
||||||
|
|
||||||
|
(recur last-move
|
||||||
(first content)
|
(first content)
|
||||||
(rest content)))
|
(rest content)))))))
|
||||||
result))))
|
|
||||||
|
|
|
@ -103,9 +103,7 @@
|
||||||
(defn close-subpaths
|
(defn close-subpaths
|
||||||
"Searches a path for posible supaths that can create closed loops and merge them"
|
"Searches a path for posible supaths that can create closed loops and merge them"
|
||||||
[content]
|
[content]
|
||||||
|
|
||||||
(let [subpaths (get-subpaths content)
|
(let [subpaths (get-subpaths content)
|
||||||
|
|
||||||
closed-subpaths
|
closed-subpaths
|
||||||
(loop [result []
|
(loop [result []
|
||||||
current (first subpaths)
|
current (first subpaths)
|
||||||
|
|
Loading…
Add table
Reference in a new issue