diff --git a/frontend/src/app/main/data/workspace/drawing.cljs b/frontend/src/app/main/data/workspace/drawing.cljs index 1b1d96beee..a3b77f82ed 100644 --- a/frontend/src/app/main/data/workspace/drawing.cljs +++ b/frontend/src/app/main/data/workspace/drawing.cljs @@ -96,7 +96,7 @@ (watch [_ _ _] (rx/of (case type - :path (path/handle-new-shape) + :path (path/handle-drawing) :curve (curve/handle-drawing) (box/handle-drawing type)))))) diff --git a/frontend/src/app/main/data/workspace/path.cljs b/frontend/src/app/main/data/workspace/path.cljs index 13009db9c3..0fedbd5b57 100644 --- a/frontend/src/app/main/data/workspace/path.cljs +++ b/frontend/src/app/main/data/workspace/path.cljs @@ -14,7 +14,7 @@ [app.main.data.workspace.path.undo :as undo])) ;; Drawing -(dm/export drawing/handle-new-shape) +(dm/export drawing/handle-drawing) (dm/export drawing/start-path-from-point) (dm/export drawing/close-path-drag-start) (dm/export drawing/change-edit-mode) diff --git a/frontend/src/app/main/data/workspace/path/common.cljs b/frontend/src/app/main/data/workspace/path/common.cljs index 3bb60ed721..b90762790b 100644 --- a/frontend/src/app/main/data/workspace/path/common.cljs +++ b/frontend/src/app/main/data/workspace/path/common.cljs @@ -11,7 +11,7 @@ [potok.v2.core :as ptk])) (defn init-path [] - (ptk/reify ::init-path)) + (ptk/data-event ::init-path {})) (defn clean-edit-state [state] diff --git a/frontend/src/app/main/data/workspace/path/drawing.cljs b/frontend/src/app/main/data/workspace/path/drawing.cljs index 7d9eb3cdb1..b85ac2edd7 100644 --- a/frontend/src/app/main/data/workspace/path/drawing.cljs +++ b/frontend/src/app/main/data/workspace/path/drawing.cljs @@ -6,6 +6,7 @@ (ns app.main.data.workspace.path.drawing (:require + [app.common.data :as d] [app.common.data.macros :as dm] [app.common.geom.point :as gpt] [app.common.geom.shapes.flex-layout :as gsl] @@ -32,19 +33,23 @@ (declare change-edit-mode) -(defn preview-next-point [{:keys [x y shift?]}] +(defn preview-next-point + [{:keys [x y shift?]}] (ptk/reify ::preview-next-point ptk/UpdateEvent (update [_ state] - (let [id (st/get-path-id state) + (let [id (st/get-path-id state) fix-angle? shift? last-point (get-in state [:workspace-local :edit-path id :last-point]) - position (cond-> (gpt/point x y) - fix-angle? (path.helpers/position-fixed-angle last-point)) - shape (st/get-path state) - {:keys [last-point prev-handler]} (get-in state [:workspace-local :edit-path id]) - command (path.segment/next-node shape position last-point prev-handler)] - (assoc-in state [:workspace-local :edit-path id :preview] command))))) + position (cond-> (gpt/point x y) + fix-angle? (path.helpers/position-fixed-angle last-point)) + shape (st/get-path state) + + {:keys [last-point prev-handler]} + (get-in state [:workspace-local :edit-path id]) + + segment (path.segment/next-node shape position last-point prev-handler)] + (assoc-in state [:workspace-local :edit-path id :preview] segment))))) (defn add-node [{:keys [x y shift?]}] @@ -189,18 +194,18 @@ (defn make-drag-stream [state stream down-event] - (dm/assert! - "should be a pointer" - (gpt/point? down-event)) + (assert (gpt/point? down-event) + "should be a point instance") (let [stopper (rx/merge (mse/drag-stopper stream) (->> stream (rx/filter helpers/end-path-event?))) - drag-events (->> (streams/position-stream state) - (rx/map #(drag-handler %)) - (rx/take-until stopper))] + drag-events + (->> (streams/position-stream state) + (rx/map #(drag-handler %)) + (rx/take-until stopper))] (rx/concat (rx/of (add-node down-event)) (streams/drag-stream @@ -208,9 +213,9 @@ drag-events (rx/of (finish-drag))))))) -(defn handle-drawing +(defn- start-edition [_id] - (ptk/reify ::handle-drawing + (ptk/reify ::start-edition ptk/UpdateEvent (update [_ state] (let [id (st/get-path-id state)] @@ -218,36 +223,49 @@ ptk/WatchEvent (watch [_ state stream] - (let [mouse-down (->> stream - (rx/filter mse/mouse-event?) - (rx/filter mse/mouse-down-event?)) - end-path-events (->> stream - (rx/filter helpers/end-path-event?)) + (let [mouse-down + (->> stream + (rx/filter mse/mouse-event?) + (rx/filter mse/mouse-down-event?)) + + end-stream + (->> stream + (rx/filter helpers/end-path-event?) + (rx/share)) + + stoper-stream + (->> stream + (rx/filter (ptk/type? ::start-edition)) + (rx/merge end-stream)) ;; Mouse move preview mousemove-events (->> (streams/position-stream state) - (rx/take-until end-path-events) - (rx/map #(preview-next-point %))) + (rx/map #(preview-next-point %)) + (rx/take-until end-stream)) ;; From mouse down we can have: click, drag and double click mousedown-events (->> mouse-down - (rx/take-until end-path-events) ;; We just ignore the mouse event and stream down the ;; last position event (rx/with-latest-from #(-> %2) (streams/position-stream state)) ;; We change to the stream that emits the first event (rx/switch-map #(rx/race (make-node-events-stream stream) - (make-drag-stream state stream %))))] + (make-drag-stream state stream %))) + (rx/take-until end-stream))] (rx/concat (rx/of (undo/start-path-undo)) (rx/of (common/init-path)) - (rx/merge mousemove-events - mousedown-events) - (rx/of (common/finish-path))))))) + (->> (rx/merge mousemove-events + mousedown-events) + (rx/take-until stoper-stream)) + + ;; This step implicitly finish path + (rx/of (common/finish-path) + (change-edit-mode :draw))))))) (defn setup-frame [] (ptk/reify ::setup-frame @@ -275,9 +293,9 @@ (cond-> (some? drop-index) (with-meta {:index drop-index}))))))))) -(defn handle-new-shape-result +(defn- handle-drawing-end [shape-id] - (ptk/reify ::handle-new-shape-result + (ptk/reify ::handle-drawing-end ptk/UpdateEvent (update [_ state] (let [content (dm/get-in state [:workspace-drawing :object :content])] @@ -299,8 +317,8 @@ (change-edit-mode :draw)) (rx/of (dwdc/handle-finish-drawing))))))) -(defn handle-new-shape - "Creates a new path shape" +(defn handle-drawing + "Hanndle the start of drawing new path shape" [] (ptk/reify ::handle-new-shape ptk/UpdateEvent @@ -312,12 +330,12 @@ (watch [_ state stream] (let [shape-id (dm/get-in state [:workspace-drawing :object :id])] (rx/concat - (rx/of (handle-drawing shape-id)) + (rx/of (start-edition shape-id)) (->> stream (rx/filter (ptk/type? ::common/finish-path)) (rx/take 1) (rx/observe-on :async) - (rx/map #(handle-new-shape-result shape-id)))))))) + (rx/map (partial handle-drawing-end shape-id)))))))) (declare check-changed-content) @@ -339,7 +357,7 @@ (if (= :draw edit-mode) (rx/concat (rx/of (dwsh/update-shapes [id] path/convert-to-path)) - (rx/of (handle-drawing id)) + (rx/of (start-edition id)) (->> stream (rx/filter (ptk/type? ::common/finish-path)) (rx/take 1) @@ -367,17 +385,18 @@ (ptk/reify ::change-edit-mode ptk/UpdateEvent (update [_ state] - (let [id (get-in state [:workspace-local :edition])] - (cond-> state - id (assoc-in [:workspace-local :edit-path id :edit-mode] mode)))) + (if-let [id (dm/get-in state [:workspace-local :edition])] + (d/update-in-when state [:workspace-local :edit-path id] assoc :edit-mode mode) + state)) ptk/WatchEvent (watch [_ state _] - (let [id (st/get-path-id state)] - (cond - (and id (= :move mode)) (rx/of (common/finish-path)) - (and id (= :draw mode)) (rx/of (start-draw-mode)) - :else (rx/empty)))))) + (when-let [id (dm/get-in state [:workspace-local :edition])] + (let [mode (dm/get-in state [:workspace-local :edit-path id :edit-mode])] + (case mode + :move (rx/of (common/finish-path)) + :draw (rx/of (start-draw-mode)) + (rx/empty))))))) (defn reset-last-handler [] @@ -385,6 +404,5 @@ ptk/UpdateEvent (update [_ state] (let [id (st/get-path-id state)] - (-> state - (assoc-in [:workspace-local :edit-path id :prev-handler] nil)))))) + (assoc-in state [:workspace-local :edit-path id :prev-handler] nil))))) diff --git a/frontend/src/app/main/data/workspace/path/state.cljs b/frontend/src/app/main/data/workspace/path/state.cljs index efe34a0044..6a89ed127a 100644 --- a/frontend/src/app/main/data/workspace/path/state.cljs +++ b/frontend/src/app/main/data/workspace/path/state.cljs @@ -7,42 +7,8 @@ (ns app.main.data.workspace.path.state (:require [app.common.data.macros :as dm] - [app.common.files.helpers :as cph] [app.common.types.path.shape-to-path :as stp])) -(defn path-editing? - "Returns true if we're editing a path or creating a new one." - [{local :workspace-local - drawing :workspace-drawing}] - (let [selected (:selected local) - edition (:edition local) - - drawing-obj (:object drawing) - drawing-tool (:tool drawing) - - edit-path? (dm/get-in local [:edit-path edition]) - - shape (or drawing-obj (first selected)) - shape-id (:id shape) - - single? (= (count selected) 1) - editing? (and (some? shape-id) - (some? edition) - (= shape-id edition)) - - ;; we need to check if we're drawing a new object but we're - ;; not using the pencil tool. - draw-path? (and (some? drawing-obj) - (cph/path-shape? drawing-obj) - (not= :curve drawing-tool))] - - (or (and ^boolean single? - ^boolean editing? - (and (not (cph/text-shape? shape)) - (not (cph/frame-shape? shape)))) - draw-path? - edit-path?))) - (defn get-path-id "Retrieves the currently editing path id" [state] diff --git a/frontend/src/app/main/data/workspace/viewport.cljs b/frontend/src/app/main/data/workspace/viewport.cljs index 97e88bc29a..d9f523003a 100644 --- a/frontend/src/app/main/data/workspace/viewport.cljs +++ b/frontend/src/app/main/data/workspace/viewport.cljs @@ -22,9 +22,8 @@ (defn initialize-viewport [{:keys [width height] :as size}] - (dm/assert! - "expected `size` to be a rect instance" - (gpr/rect? size)) + (assert (gpr/rect? size) + "expected `size` to be a rect instance") (letfn [(update* [{:keys [vport] :as local}] (let [wprop (/ (:width vport) width) diff --git a/frontend/src/app/main/ui/workspace/top_toolbar.cljs b/frontend/src/app/main/ui/workspace/top_toolbar.cljs index 3b8b14ea9b..5d8abacdad 100644 --- a/frontend/src/app/main/ui/workspace/top_toolbar.cljs +++ b/frontend/src/app/main/ui/workspace/top_toolbar.cljs @@ -7,14 +7,12 @@ (ns app.main.ui.workspace.top-toolbar (:require-macros [app.main.style :as stl]) (:require - [app.common.data.macros :as dm] [app.common.geom.point :as gpt] [app.main.data.event :as ev] [app.main.data.modal :as modal] [app.main.data.workspace :as dw] [app.main.data.workspace.common :as dwc] [app.main.data.workspace.media :as dwm] - [app.main.data.workspace.path.state :as pst] [app.main.data.workspace.shortcuts :as sc] [app.main.features :as features] [app.main.refs :as refs] @@ -68,25 +66,31 @@ :ref ref :on-selected on-selected}]]])) -(def toolbar-hidden - (l/derived - (fn [state] - (let [visibility (dm/get-in state [:workspace-local :hide-toolbar]) - editing? (pst/path-editing? state) - hidden? (if editing? true visibility)] - hidden?)) - st/state)) +(def ^:private toolbar-hidden-ref + (l/derived (fn [state] + (let [visibility (get state :hide-toolbar) + path-edit-state (get state :edit-path) + + selected (get state :selected) + edition (get state :edition) + single? (= (count selected) 1) + + path-editing? (and single? (some? (get path-edit-state edition)))] + (if path-editing? true visibility))) + refs/workspace-local)) (mf/defc top-toolbar* {::mf/memo true} [{:keys [layout]}] - (let [selected-drawtool (mf/deref refs/selected-drawing-tool) - edition (mf/deref refs/selected-edition) + (let [drawtool (mf/deref refs/selected-drawing-tool) + edition (mf/deref refs/selected-edition) - read-only? (mf/use-ctx ctx/workspace-read-only?) + profile (mf/deref refs/profile) + props (get profile :props) - rulers? (mf/deref refs/rulers?) - hide-toolbar? (mf/deref toolbar-hidden) + read-only? (mf/use-ctx ctx/workspace-read-only?) + rulers? (mf/deref refs/rulers?) + hide-toolbar? (mf/deref toolbar-hidden-ref) interrupt (mf/use-fn #(st/emit! :interrupt (dw/clear-edition-mode))) @@ -120,8 +124,6 @@ (dom/blur! (dom/get-target event)) (st/emit! (dwc/toggle-toolbar-visibility)))) - profile (mf/deref refs/profile) - props (get profile :props) test-tooltip-board-text (if (not (:workspace-visited props)) (tr "workspace.toolbar.frame-first-time" (sc/get-tooltip :draw-frame)) @@ -138,7 +140,7 @@ {:title (tr "workspace.toolbar.move" (sc/get-tooltip :move)) :aria-label (tr "workspace.toolbar.move" (sc/get-tooltip :move)) :class (stl/css-case :main-toolbar-options-button true - :selected (and (nil? selected-drawtool) + :selected (and (nil? drawtool) (not edition))) :on-click interrupt} i/move]] @@ -147,7 +149,7 @@ [:button {:title test-tooltip-board-text :aria-label (tr "workspace.toolbar.frame" (sc/get-tooltip :draw-frame)) - :class (stl/css-case :main-toolbar-options-button true :selected (= selected-drawtool :frame)) + :class (stl/css-case :main-toolbar-options-button true :selected (= drawtool :frame)) :on-click select-drawtool :data-tool "frame" :data-testid "artboard-btn"} @@ -156,7 +158,7 @@ [:button {:title (tr "workspace.toolbar.rect" (sc/get-tooltip :draw-rect)) :aria-label (tr "workspace.toolbar.rect" (sc/get-tooltip :draw-rect)) - :class (stl/css-case :main-toolbar-options-button true :selected (= selected-drawtool :rect)) + :class (stl/css-case :main-toolbar-options-button true :selected (= drawtool :rect)) :on-click select-drawtool :data-tool "rect" :data-testid "rect-btn"} @@ -165,7 +167,7 @@ [:button {:title (tr "workspace.toolbar.ellipse" (sc/get-tooltip :draw-ellipse)) :aria-label (tr "workspace.toolbar.ellipse" (sc/get-tooltip :draw-ellipse)) - :class (stl/css-case :main-toolbar-options-button true :selected (= selected-drawtool :circle)) + :class (stl/css-case :main-toolbar-options-button true :selected (= drawtool :circle)) :on-click select-drawtool :data-tool "circle" :data-testid "ellipse-btn"} @@ -174,7 +176,7 @@ [:button {:title (tr "workspace.toolbar.text" (sc/get-tooltip :draw-text)) :aria-label (tr "workspace.toolbar.text" (sc/get-tooltip :draw-text)) - :class (stl/css-case :main-toolbar-options-button true :selected (= selected-drawtool :text)) + :class (stl/css-case :main-toolbar-options-button true :selected (= drawtool :text)) :on-click select-drawtool :data-tool "text"} i/text]] @@ -185,7 +187,7 @@ [:button {:title (tr "workspace.toolbar.curve" (sc/get-tooltip :draw-curve)) :aria-label (tr "workspace.toolbar.curve" (sc/get-tooltip :draw-curve)) - :class (stl/css-case :main-toolbar-options-button true :selected (= selected-drawtool :curve)) + :class (stl/css-case :main-toolbar-options-button true :selected (= drawtool :curve)) :on-click select-drawtool :data-tool "curve" :data-testid "curve-btn"} @@ -194,7 +196,7 @@ [:button {:title (tr "workspace.toolbar.path" (sc/get-tooltip :draw-path)) :aria-label (tr "workspace.toolbar.path" (sc/get-tooltip :draw-path)) - :class (stl/css-case :main-toolbar-options-button true :selected (= selected-drawtool :path)) + :class (stl/css-case :main-toolbar-options-button true :selected (= drawtool :path)) :on-click select-drawtool :data-tool "path" :data-testid "path-btn"}