diff --git a/common/src/app/common/geom/point.cljc b/common/src/app/common/geom/point.cljc index 6c640173a..d83a46c99 100644 --- a/common/src/app/common/geom/point.cljc +++ b/common/src/app/common/geom/point.cljc @@ -60,7 +60,7 @@ (point v v) (point-like? v) - (map->Point v) + (Point. (:x v) (:y v)) :else (ex/raise :hint "invalid arguments (on pointer constructor)" :value v))) diff --git a/frontend/src/app/main/data/workspace/path/drawing.cljs b/frontend/src/app/main/data/workspace/path/drawing.cljs index 649d84571..307c6e290 100644 --- a/frontend/src/app/main/data/workspace/path/drawing.cljs +++ b/frontend/src/app/main/data/workspace/path/drawing.cljs @@ -8,7 +8,6 @@ (:require [app.common.geom.point :as gpt] [app.common.geom.shapes.flex-layout :as gsl] - [app.common.geom.shapes.path :as upg] [app.common.path.commands :as upc] [app.common.path.shapes-to-path :as upsp] [app.common.spec :as us] @@ -125,14 +124,11 @@ (ptk/reify ::close-path-drag-start ptk/WatchEvent (watch [_ state stream] - (let [id (st/get-path-id state) - stop-stream + (let [stop-stream (->> stream (rx/filter #(or (helpers/end-path-event? %) (ms/mouse-up? %)))) content (st/get-path state :content) - snap-toggled (get-in state [:workspace-local :edit-path id :snap-toggled]) - points (upg/content->points content) handlers (-> (upc/content->handlers content) (get position)) @@ -141,7 +137,7 @@ (first handlers)) drag-events-stream - (->> (streams/position-stream snap-toggled points) + (->> (streams/position-stream) (rx/take-until stop-stream) (rx/map #(drag-handler position idx prefix %)))] @@ -164,16 +160,10 @@ (defn start-path-from-point [position] (ptk/reify ::start-path-from-point ptk/WatchEvent - (watch [_ state stream] + (watch [_ _ stream] (let [mouse-up (->> stream (rx/filter #(or (helpers/end-path-event? %) (ms/mouse-up? %)))) - content (st/get-path state :content) - points (upg/content->points content) - - id (st/get-path-id state) - snap-toggled (get-in state [:workspace-local :edit-path id :snap-toggled]) - - drag-events (->> (streams/position-stream snap-toggled points) + drag-events (->> (streams/position-stream) (rx/take-until mouse-up) (rx/map #(drag-handler %)))] @@ -192,11 +182,11 @@ (rx/merge-map #(rx/empty)))) (defn make-drag-stream - [stream snap-toggled _zoom points down-event] + [stream down-event] (let [mouse-up (->> stream (rx/filter #(or (helpers/end-path-event? %) (ms/mouse-up? %)))) - drag-events (->> (streams/position-stream snap-toggled points) + drag-events (->> (streams/position-stream) (rx/take-until mouse-up) (rx/map #(drag-handler %)))] @@ -217,20 +207,13 @@ (assoc-in [:workspace-local :edit-path id :edit-mode] :draw)))) ptk/WatchEvent - (watch [_ state stream] - (let [zoom (get-in state [:workspace-local :zoom]) - mouse-down (->> stream (rx/filter ms/mouse-down?)) + (watch [_ _ stream] + (let [mouse-down (->> stream (rx/filter ms/mouse-down?)) end-path-events (->> stream (rx/filter helpers/end-path-event?)) - content (st/get-path state :content) - points (upg/content->points content) - - id (st/get-path-id state) - snap-toggled (get-in state [:workspace-local :edit-path id :snap-toggled]) - ;; Mouse move preview mousemove-events - (->> (streams/position-stream snap-toggled points) + (->> (streams/position-stream) (rx/take-until end-path-events) (rx/map #(preview-next-point %))) @@ -238,12 +221,12 @@ mousedown-events (->> mouse-down (rx/take-until end-path-events) - (rx/with-latest merge (streams/position-stream snap-toggled points)) + (rx/with-latest merge (streams/position-stream)) ;; We change to the stream that emits the first event (rx/switch-map #(rx/race (make-node-events-stream stream) - (make-drag-stream stream snap-toggled zoom points %))))] + (make-drag-stream stream %))))] (rx/concat (rx/of (undo/start-path-undo)) diff --git a/frontend/src/app/main/data/workspace/path/edition.cljs b/frontend/src/app/main/data/workspace/path/edition.cljs index 2340da662..318f1dbf3 100644 --- a/frontend/src/app/main/data/workspace/path/edition.cljs +++ b/frontend/src/app/main/data/workspace/path/edition.cljs @@ -7,6 +7,7 @@ (ns app.main.data.workspace.path.edition (:require [app.common.data :as d] + [app.common.data.macros :as dm] [app.common.geom.point :as gpt] [app.common.geom.shapes.path :as upg] [app.common.path.commands :as upc] @@ -35,8 +36,8 @@ (let [content (st/get-path state :content) 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))] + point (gpt/point (+ (dm/get-in content [index :params cx]) dx) + (+ (dm/get-in content [index :params cy]) dy))] (-> state (update-in [:workspace-local :edit-path id :content-modifiers] merge modifiers) @@ -51,7 +52,7 @@ id (st/get-path-id state) page-id (:current-page-id state) shape (st/get-path state) - content-modifiers (get-in state [:workspace-local :edit-path id :content-modifiers]) + content-modifiers (dm/get-in state [:workspace-local :edit-path id :content-modifiers]) content (:content shape) new-content (upc/apply-content-modifiers content content-modifiers) @@ -98,7 +99,7 @@ (let [id (st/get-path-id state) content (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 (dm/get-in state [:workspace-local :edit-path id :content-modifiers] {}) content-modifiers (->> points (reduce modifiers-reducer content-modifiers))] @@ -115,9 +116,9 @@ modifiers-reducer (partial modify-content-point content delta) - points (get-in state [:workspace-local :edit-path id :selected-points] #{}) + points (dm/get-in state [:workspace-local :edit-path id :selected-points] #{}) - modifiers (get-in state [:workspace-local :edit-path id :content-modifiers] {}) + modifiers (dm/get-in state [:workspace-local :edit-path id :content-modifiers] {}) modifiers (->> points (reduce modifiers-reducer modifiers))] @@ -132,8 +133,8 @@ (ptk/reify ::start-move-path-point ptk/WatchEvent (watch [_ state _] - (let [id (get-in state [:workspace-local :edition]) - selected-points (get-in state [:workspace-local :edit-path id :selected-points] #{}) + (let [id (dm/get-in state [:workspace-local :edition]) + selected-points (dm/get-in state [:workspace-local :edit-path id :selected-points] #{}) selected? (contains? selected-points position)] (streams/drag-stream (rx/of @@ -148,10 +149,9 @@ ptk/WatchEvent (watch [_ state stream] (let [stopper (->> stream (rx/filter ms/mouse-up?)) - id (get-in state [:workspace-local :edition]) - snap-toggled (get-in state [:workspace-local :edit-path id :snap-toggled]) + id (dm/get-in state [:workspace-local :edition]) - selected-points (get-in state [:workspace-local :edit-path id :selected-points] #{}) + selected-points (dm/get-in state [:workspace-local :edit-path id :selected-points] #{}) content (st/get-path state :content) points (upg/content->points content)] @@ -159,7 +159,7 @@ (rx/concat ;; This stream checks the consecutive mouse positions to do the dragging (->> points - (streams/move-points-stream snap-toggled start-position selected-points) + (streams/move-points-stream start-position selected-points) (rx/map #(move-selected-path-point start-position %)) (rx/take-until stopper)) (rx/of (apply-content-modifiers))))))) @@ -178,7 +178,7 @@ (ptk/reify ::finish-move-selected ptk/UpdateEvent (update [_ state] - (let [id (get-in state [:workspace-local :edition])] + (let [id (dm/get-in state [:workspace-local :edition])] (-> state (update-in [:workspace-local :edit-path id] dissoc :current-move)))))) @@ -192,8 +192,8 @@ ptk/UpdateEvent (update [_ state] - (let [id (get-in state [:workspace-local :edition]) - current-move (get-in state [:workspace-local :edit-path id :current-move])] + (let [id (dm/get-in state [:workspace-local :edition]) + current-move (dm/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) @@ -202,11 +202,11 @@ 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])] + (let [id (dm/get-in state [:workspace-local :edition]) + current-move (dm/get-in state [:workspace-local :edit-path id :current-move])] ;; id can be null if we just selected the tool but we didn't start drawing (if (and id (= same-event current-move)) - (let [points (get-in state [:workspace-local :edit-path id :selected-points] #{}) + (let [points (dm/get-in state [:workspace-local :edit-path id :selected-points] #{}) move-events (->> stream (rx/filter (ptk/type? ::move-selected)) @@ -238,13 +238,13 @@ (ptk/reify ::start-move-handler ptk/WatchEvent (watch [_ state stream] - (let [id (get-in state [:workspace-local :edition]) + (let [id (dm/get-in state [:workspace-local :edition]) cx (d/prefix-keyword prefix :x) cy (d/prefix-keyword prefix :y) start-point @ms/mouse-position - modifiers (get-in state [:workspace-local :edit-path id :content-modifiers]) - start-delta-x (get-in modifiers [index cx] 0) - start-delta-y (get-in modifiers [index cy] 0) + modifiers (dm/get-in state [:workspace-local :edit-path id :content-modifiers]) + start-delta-x (dm/get-in modifiers [index cx] 0) + start-delta-y (dm/get-in modifiers [index cy] 0) content (st/get-path state :content) points (upg/content->points content) @@ -253,14 +253,12 @@ handler (-> content (get index) (upc/get-handler prefix)) [op-idx op-prefix] (upc/opposite-index content index prefix) - opposite (upc/handler->point content op-idx op-prefix) - - snap-toggled (get-in state [:workspace-local :edit-path id :snap-toggled])] + opposite (upc/handler->point content op-idx op-prefix)] (streams/drag-stream (rx/concat (rx/of (dch/update-shapes [id] upsp/convert-to-path)) - (->> (streams/move-handler-stream snap-toggled start-point point handler opposite points) + (->> (streams/move-handler-stream start-point point handler opposite points) (rx/take-until (->> stream (rx/filter #(or (ms/mouse-up? %) (streams/finish-edition? %))))) (rx/map @@ -283,7 +281,7 @@ (ptk/reify ::start-path-edit ptk/UpdateEvent (update [_ state] - (let [edit-path (get-in state [:workspace-local :edit-path id]) + (let [edit-path (dm/get-in state [:workspace-local :edit-path id]) content (st/get-path state :content) state (st/set-content state (ups/close-subpaths content))] (cond-> state @@ -297,7 +295,7 @@ ptk/WatchEvent (watch [_ state stream] - (let [mode (get-in state [:workspace-local :edit-path id :edit-mode]) + (let [mode (dm/get-in state [:workspace-local :edit-path id :edit-mode]) stopper (->> stream (rx/filter #(or (= (ptk/type %) ::dwe/clear-edition-mode) diff --git a/frontend/src/app/main/data/workspace/path/streams.cljs b/frontend/src/app/main/data/workspace/path/streams.cljs index 147fbd511..071e6ab12 100644 --- a/frontend/src/app/main/data/workspace/path/streams.cljs +++ b/frontend/src/app/main/data/workspace/path/streams.cljs @@ -6,10 +6,11 @@ (ns app.main.data.workspace.path.streams (:require + [app.common.data.macros :as dm] [app.common.geom.point :as gpt] [app.common.geom.shapes.path :as upg] [app.main.constants :refer [zoom-half-pixel-precision]] - [app.main.data.workspace.path.state :as state] + [app.main.data.workspace.path.state :as pst] [app.main.snap :as snap] [app.main.store :as st] [app.main.streams :as ms] @@ -71,15 +72,23 @@ (->> position-stream (rx/merge-map (fn [] to-stream))))))) +(defn snap-toggled-stream + [] + (let [get-snap (fn [state] + (let [id (pst/get-path-id state)] + (dm/get-in state [:workspace-local :edit-path id :snap-toggled])))] + (-> (l/derived get-snap st/state) + (rx/from-atom {:emit-current-value? true})))) + (defn move-points-stream - [snap-toggled start-point selected-points points] + [start-point selected-points points] (let [zoom (get-in @st/state [:workspace-local :zoom] 1) ranges (snap/create-ranges points selected-points) d-pos (/ snap/snap-path-accuracy zoom) check-path-snap - (fn [position] + (fn [[position snap-toggled]] (if snap-toggled (let [delta (gpt/subtract position start-point) moved-points (->> selected-points (mapv #(gpt/add % delta))) @@ -88,6 +97,7 @@ position))] (->> ms/mouse-position (rx/map to-pixel-snap) + (rx/with-latest-from (snap-toggled-stream)) (rx/map check-path-snap)))) (defn get-angle [node handler opposite] @@ -99,7 +109,7 @@ [rot-angle rot-sign]))) (defn move-handler-stream - [snap-toggled start-point node handler opposite points] + [start-point node handler opposite points] (let [zoom (get-in @st/state [:workspace-local :zoom] 1) ranges (snap/create-ranges points) @@ -108,7 +118,7 @@ [initial-angle] (get-angle node handler opposite) check-path-snap - (fn [position] + (fn [[position snap-toggled]] (if snap-toggled (let [delta (gpt/subtract position start-point) handler (gpt/add handler delta) @@ -134,13 +144,14 @@ (rx/map to-pixel-snap) (rx/with-latest merge (->> ms/mouse-position-shift (rx/map #(hash-map :shift? %)))) (rx/with-latest merge (->> ms/mouse-position-alt (rx/map #(hash-map :alt? %)))) + (rx/with-latest-from (snap-toggled-stream)) (rx/map check-path-snap)))) (defn position-stream - [snap-toggled _points] + [] (let [zoom (get-in @st/state [:workspace-local :zoom] 1) d-pos (/ snap/snap-path-accuracy zoom) - get-content #(state/get-path % :content) + get-content #(pst/get-path % :content) content-stream (-> (l/derived get-content st/state) @@ -154,7 +165,8 @@ (->> ms/mouse-position (rx/map to-pixel-snap) (rx/with-latest vector ranges-stream) - (rx/map (fn [[position ranges]] + (rx/with-latest-from (snap-toggled-stream)) + (rx/map (fn [[[position ranges] snap-toggled]] (if snap-toggled (let [snap (snap/get-snap-delta [position] ranges d-pos)] (gpt/add position snap)) diff --git a/frontend/src/app/main/ui/workspace/shapes/path/common.cljs b/frontend/src/app/main/ui/workspace/shapes/path/common.cljs index 8c6215304..0322e6571 100644 --- a/frontend/src/app/main/ui/workspace/shapes/path/common.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/path/common.cljs @@ -6,7 +6,10 @@ (ns app.main.ui.workspace.shapes.path.common (:require + [app.common.data.macros :as dm] + [app.main.data.workspace.path.state :as pst] [app.main.refs :as refs] + [app.main.store :as st] [okulary.core :as l] [rumext.v2 :as mf])) @@ -17,10 +20,11 @@ (def gray-color "var(--color-gray-20)") (def current-edit-path-ref - (let [selfn (fn [local] - (let [id (:edition local)] - (get-in local [:edit-path id])))] - (l/derived selfn refs/workspace-local))) + (l/derived + (fn [state] + (let [id (pst/get-path-id state)] + (dm/get-in state [:workspace-local :edit-path id]))) + st/state)) (defn make-edit-path-ref [id] (mf/use-memo 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 8a991bf3f..9ee12f976 100644 --- a/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs @@ -327,14 +327,15 @@ [:g.path-node {:key (dm/str index "-" (:x position) "-" (:y position))} [:g.point-handlers {:pointer-events (when (= edit-mode :draw) "none")} - (for [[index prefix] pos-handlers] - (let [handler-position (upc/handler->point content index prefix) - handler-hover? (contains? hover-handlers [index prefix]) + (for [[hindex prefix] pos-handlers] + (let [handler-position (upc/handler->point content hindex prefix) + handler-hover? (contains? hover-handlers [hindex prefix]) moving-handler? (= handler-position moving-handler) matching-handler? (matching-handler? content position pos-handlers)] - [:& path-handler {:point position + [:& path-handler {:key (dm/str (dm/str index "-" (:x position) "-" (:y position)) "-" hindex "-" (d/name prefix)) + :point position :handler handler-position - :index index + :index hindex :prefix prefix :zoom zoom :hover? handler-hover? diff --git a/frontend/src/app/main/ui/workspace/viewport/widgets.cljs b/frontend/src/app/main/ui/workspace/viewport/widgets.cljs index 087dfd205..d95835fd5 100644 --- a/frontend/src/app/main/ui/workspace/viewport/widgets.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/widgets.cljs @@ -50,12 +50,13 @@ (mf/defc viewport-actions {::mf/wrap [mf/memo]} [] - (let [edition (mf/deref refs/selected-edition) - selected (mf/deref refs/selected-objects) - shape (-> selected first)] - (when (and (= (count selected) 1) - (= (:id shape) edition) - (not= :text (:type shape))) + (let [edition (mf/deref refs/selected-edition) + selected (mf/deref refs/selected-objects) + drawing (mf/deref refs/workspace-drawing) + drawing-obj (:object drawing) + shape (or drawing-obj (-> selected first))] + (when (or (and (= (count selected) 1) (= (:id shape) edition) (not= :text (:type shape))) + (and (some? drawing-obj) (= :path (:type drawing-obj)))) [:div.viewport-actions [:& path-actions {:shape shape}]])))