diff --git a/frontend/src/app/main/data/workspace/path/edition.cljs b/frontend/src/app/main/data/workspace/path/edition.cljs index 95c5cddf5..6ccb29a9c 100644 --- a/frontend/src/app/main/data/workspace/path/edition.cljs +++ b/frontend/src/app/main/data/workspace/path/edition.cljs @@ -22,6 +22,7 @@ [app.util.path.commands :as upc] [app.util.path.geom :as upg] [app.util.path.tools :as upt] + [app.util.path.subpaths :as ups] [beicon.core :as rx] [potok.core :as ptk])) @@ -35,9 +36,7 @@ modifiers (helpers/move-handler-modifiers content index prefix false match-opposite? dx dy) [cx cy] (if (= prefix :c1) [:c1x :c1y] [:c2x :c2y]) 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 (update-in [:workspace-local :edit-path id :content-modifiers] merge modifiers) @@ -192,8 +191,8 @@ (ptk/reify ::start-path-edit ptk/UpdateEvent (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 (or (not edit-path) (= :draw (:edit-mode edit-path))) (assoc-in [:workspace-local :edit-path id] {:edit-mode :move diff --git a/frontend/src/app/main/data/workspace/path/helpers.cljs b/frontend/src/app/main/data/workspace/path/helpers.cljs index 17c4edb01..79c120d4a 100644 --- a/frontend/src/app/main/data/workspace/path/helpers.cljs +++ b/frontend/src/app/main/data/workspace/path/helpers.cljs @@ -11,10 +11,11 @@ [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] [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.state :refer [get-path]] [app.main.streams :as ms] [app.util.path.commands :as upc] + [app.util.path.subpaths :as ups] [potok.core :as ptk])) ;; CONSTANTS @@ -105,6 +106,7 @@ (let [command (next-node shape position prev-point prev-handler)] (-> shape (update :content (fnil conj []) command) + (update :content ups/close-subpaths) (update-selrect)))) (defn angle-points [common p1 p2] diff --git a/frontend/src/app/main/data/workspace/path/shortcuts.cljs b/frontend/src/app/main/data/workspace/path/shortcuts.cljs index 25eac7a4d..7c28926f6 100644 --- a/frontend/src/app/main/data/workspace/path/shortcuts.cljs +++ b/frontend/src/app/main/data/workspace/path/shortcuts.cljs @@ -40,8 +40,8 @@ :command "p" :fn #(st/emit! (drp/change-edit-mode :draw))} - :add-node {:tooltip (ds/meta "+") - :command (ds/c-mod "+") + :add-node {:tooltip "+" + :command "+" :fn #(st/emit! (drp/add-node))} :delete-node {:tooltip (ds/supr) @@ -52,20 +52,20 @@ :command (ds/c-mod "j") :fn #(st/emit! (drp/merge-nodes))} - :join-nodes {:tooltip (ds/meta-shift "J") - :command (ds/c-mod "shift+j") + :join-nodes {:tooltip "J" + :command "j" :fn #(st/emit! (drp/join-nodes))} - :separate-nodes {:tooltip (ds/meta "K") - :command (ds/c-mod "k") + :separate-nodes {:tooltip "K" + :command "k" :fn #(st/emit! (drp/separate-nodes))} - :make-corner {:tooltip (ds/meta "B") - :command (ds/c-mod "b") + :make-corner {:tooltip "B" + :command "b" :fn #(st/emit! (drp/make-corner))} - :make-curve {:tooltip (ds/meta-shift "B") - :command (ds/c-mod "shift+b") + :make-curve {:tooltip (ds/meta "B") + :command (ds/c-mod "b") :fn #(st/emit! (drp/make-curve))} :snap-nodes {:tooltip (ds/meta "'") diff --git a/frontend/src/app/main/data/workspace/path/tools.cljs b/frontend/src/app/main/data/workspace/path/tools.cljs index 059636565..303e50428 100644 --- a/frontend/src/app/main/data/workspace/path/tools.cljs +++ b/frontend/src/app/main/data/workspace/path/tools.cljs @@ -11,33 +11,46 @@ [app.main.data.workspace.path.common :as common] [app.main.data.workspace.path.state :as st] [app.util.path.tools :as upt] + [app.util.path.subpaths :as ups] [app.common.geom.point :as gpt] [beicon.core :as rx] [potok.core :as ptk])) (defn process-path-tool "Generic function that executes path transformations with the content and selected nodes" - [tool-fn] - (ptk/reify ::process-path-tool - ptk/WatchEvent - (watch [_ state stream] - (let [id (st/get-path-id state) - page-id (:current-page-id state) - shape (get-in state (st/get-path state)) - selected-points (get-in state [:workspace-local :edit-path id :selected-points] #{}) - new-content (tool-fn (:content shape) selected-points) - [rch uch] (changes/generate-path-changes page-id shape (:content shape) new-content)] - (rx/of (dwc/commit-changes rch uch {:commit-local? true})))))) + ([tool-fn] + (process-path-tool nil tool-fn)) + ([points tool-fn] + (ptk/reify ::process-path-tool + ptk/WatchEvent + (watch [_ state stream] + (let [id (st/get-path-id state) + page-id (:current-page-id state) + shape (get-in state (st/get-path state)) + selected-points (get-in state [:workspace-local :edit-path id :selected-points] #{}) + 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 [] - (process-path-tool - (fn [content points] - (reduce upt/make-corner-point content points)))) +(defn make-corner + ([] + (make-corner nil)) + ([point] + (process-path-tool + #{point} + (fn [content points] + (reduce upt/make-corner-point content points))))) -(defn make-curve [] - (process-path-tool - (fn [content points] - (reduce upt/make-curve-point content points)))) +(defn make-curve + ([] + (make-curve nil)) + ([point] + (process-path-tool + #{point} + (fn [content points] + (reduce upt/make-curve-point content points))))) (defn add-node [] (process-path-tool (fn [content points] (upt/split-segments content points 0.5)))) diff --git a/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs b/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs index 0d2e805cd..16101feca 100644 --- a/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs @@ -26,7 +26,7 @@ [rumext.alpha :as mf]) (: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 on-enter @@ -45,8 +45,15 @@ (when (and new-point? (some? (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 + (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) ;; If we're dragging a selected item we don't change the selection (st/emit! (drp/start-move-path-point position shift?)) @@ -274,37 +281,42 @@ :zoom zoom}]]) (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)) - 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.point-handlers {:pointer-events (when (= edit-mode :draw) "none")} - (let [pos-handlers (get handlers position)] - (for [[index prefix] pos-handlers] - (let [command (get content index) - x (get-in command [:params (d/prefix-keyword prefix :x)]) - y (get-in command [:params (d/prefix-keyword prefix :y)]) - handler-position (gpt/point x y) - handler-hover? (contains? hover-handlers [index prefix]) - moving-handler? (= handler-position moving-handler) - matching-handler? (matching-handler? content position pos-handlers)] - (when (not= position handler-position) - [:& path-handler {:point position - :handler handler-position - :index index - :prefix prefix - :zoom zoom - :hover? handler-hover? - :snap-angle? (and moving-handler? matching-handler?) - :edit-mode edit-mode}]))))] + (for [[index prefix] pos-handlers] + (let [handler-position (upc/handler->point content index prefix) + handler-hover? (contains? hover-handlers [index prefix]) + moving-handler? (= handler-position moving-handler) + matching-handler? (matching-handler? content position pos-handlers)] + [:& path-handler {:point position + :handler handler-position + :index index + :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?}]])) + :start-path? start-p? + :curve? curve?}]])) (when prev-handler [:g.prev-handler {:pointer-events "none"} diff --git a/frontend/src/app/main/ui/workspace/viewport/path_actions.cljs b/frontend/src/app/main/ui/workspace/viewport/path_actions.cljs index b53dcc217..d504faf56 100644 --- a/frontend/src/app/main/ui/workspace/viewport/path_actions.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/path_actions.cljs @@ -19,6 +19,7 @@ (defn check-enabled [content selected-points] (let [segments (upt/get-segments content selected-points) + num-points (count selected-points) points-selected? (not (empty? selected-points)) segments-selected? (not (empty? segments))] {:make-corner points-selected? @@ -26,7 +27,7 @@ :add-node segments-selected? :remove-node points-selected? :merge-nodes segments-selected? - :join-nodes points-selected? + :join-nodes (and points-selected? (>= num-points 2)) :separate-nodes segments-selected?})) (mf/defc path-actions [{:keys [shape]}] diff --git a/frontend/src/app/util/path/format.cljs b/frontend/src/app/util/path/format.cljs index 729c3a5ca..a79a5a7e5 100644 --- a/frontend/src/app/util/path/format.cljs +++ b/frontend/src/app/util/path/format.cljs @@ -65,22 +65,20 @@ (defn format-path [content] - (let [content (ups/close-subpaths content)] - (loop [result "" - last-move nil + (with-out-str + (loop [last-move nil current (first content) content (rest content)] - (if (some? current) + (when (some? current) (let [point (upc/command->point 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)] - (recur result - last-move + (print (command->string current)) + + (when (and (not current-move?) (= last-move point)) + (print "Z")) + + (recur last-move (first content) - (rest content))) - result)))) + (rest content))))))) diff --git a/frontend/src/app/util/path/subpaths.cljs b/frontend/src/app/util/path/subpaths.cljs index 6e938829e..3337b6c88 100644 --- a/frontend/src/app/util/path/subpaths.cljs +++ b/frontend/src/app/util/path/subpaths.cljs @@ -103,9 +103,7 @@ (defn close-subpaths "Searches a path for posible supaths that can create closed loops and merge them" [content] - (let [subpaths (get-subpaths content) - closed-subpaths (loop [result [] current (first subpaths)