diff --git a/common/src/app/common/pages/helpers.cljc b/common/src/app/common/pages/helpers.cljc index 55b3c571e..e04291bd2 100644 --- a/common/src/app/common/pages/helpers.cljc +++ b/common/src/app/common/pages/helpers.cljc @@ -29,7 +29,7 @@ (defn frame-shape? ([objects id] - (= (get-in objects [id :type]) id)) + (frame-shape? (get objects id))) ([{:keys [type]}] (= type :frame))) @@ -467,7 +467,6 @@ (defn selected-with-children [objects selected] - (into selected (mapcat #(get-children-ids objects %)) selected)) diff --git a/common/src/app/common/types/shape_tree.cljc b/common/src/app/common/types/shape_tree.cljc index 905854d03..d894d77ef 100644 --- a/common/src/app/common/types/shape_tree.cljc +++ b/common/src/app/common/types/shape_tree.cljc @@ -224,16 +224,25 @@ "Search for the top nested frame for positioning shapes when moving or creating. Looks for all the frames in a position and then goes in depth between the top-most and its children to find the target." - [objects position] - (let [frame-ids (all-frames-by-position objects position) - frame-set (set frame-ids)] - (loop [current-id (first frame-ids)] - (let [current-shape (get objects current-id) - child-frame-id (d/seek #(contains? frame-set %) - (-> (:shapes current-shape) reverse))] - (if (nil? child-frame-id) - (or current-id uuid/zero) - (recur child-frame-id)))))) + ([objects position] + (top-nested-frame objects position nil)) + + ([objects position excluded] + (assert (or (nil? excluded) (set? excluded))) + + (let [frame-ids (cond->> (all-frames-by-position objects position) + (some? excluded) + (remove excluded)) + + frame-set (set frame-ids)] + + (loop [current-id (first frame-ids)] + (let [current-shape (get objects current-id) + child-frame-id (d/seek #(contains? frame-set %) + (-> (:shapes current-shape) reverse))] + (if (nil? child-frame-id) + (or current-id uuid/zero) + (recur child-frame-id))))))) (defn top-nested-frame-ids "Search the top nested frame in a list of ids" diff --git a/frontend/src/app/main/data/workspace/modifiers.cljs b/frontend/src/app/main/data/workspace/modifiers.cljs index 4861414e3..1e322c83f 100644 --- a/frontend/src/app/main/data/workspace/modifiers.cljs +++ b/frontend/src/app/main/data/workspace/modifiers.cljs @@ -16,6 +16,7 @@ [app.common.pages.helpers :as cph] [app.common.spec :as us] [app.common.types.modifiers :as ctm] + [app.common.types.shape.layout :as ctl] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.comments :as-alias dwcm] [app.main.data.workspace.guides :as-alias dwg] @@ -144,12 +145,11 @@ (into {} (map #(vector % {:modifiers (get-modifier (get objects %))})) ids)) (defn build-change-frame-modifiers - [modif-tree objects selected target-frame position] + [modif-tree objects selected target-frame drop-index] (let [origin-frame-ids (->> selected (group-by #(get-in objects [% :frame-id]))) - layout? (get-in objects [target-frame :layout]) child-set (set (get-in objects [target-frame :shapes])) - drop-index (when layout? (gsl/get-drop-index target-frame objects position)) + layout? (ctl/layout? objects target-frame) update-frame-modifiers (fn [modif-tree [original-frame shapes]] diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 9ec4c4383..46aa09915 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -353,7 +353,7 @@ (declare start-move) (declare start-move-duplicate) -(declare calculate-frame-for-move) +(declare move-shapes-to-frame) (declare get-displacement) (defn start-move-selected @@ -414,7 +414,6 @@ (rx/take 1) (rx/map #(start-move from-position)))))) - (defn- start-move ([from-position] (start-move from-position nil)) ([from-position ids] @@ -436,13 +435,18 @@ zoom (get-in state [:workspace-local :zoom] 1) focus (:workspace-focus-selected state) - fix-axis (fn [[position shift?]] - (let [delta (gpt/to-vec from-position position)] - (if shift? - (if (> (mth/abs (:x delta)) (mth/abs (:y delta))) - (gpt/point (:x delta) 0) - (gpt/point 0 (:y delta))) - delta))) + exclude-frames (into #{} + (filter (partial cph/frame-shape? objects)) + (cph/selected-with-children objects selected)) + + fix-axis + (fn [[position shift?]] + (let [delta (gpt/to-vec from-position position)] + (if shift? + (if (> (mth/abs (:x delta)) (mth/abs (:y delta))) + (gpt/point (:x delta) 0) + (gpt/point 0 (:y delta))) + delta))) position (->> ms/mouse-position (rx/with-latest-from ms/mouse-position-shift) @@ -456,33 +460,48 @@ (rx/switch-map (fn [pos] (->> (snap/closest-snap-move page-id shapes objects layout zoom focus pos) - (rx/map #(vector pos %)))))))] + (rx/map #(vector pos %))))))) + + drop-frame (atom nil)] (if (empty? shapes) (rx/of (finish-transform)) - (rx/concat - (rx/merge - (->> position - ;; We ask for the snap position but we continue even if the result is not available - (rx/with-latest vector snap-delta) + (let [move-stream + (->> position + ;; We ask for the snap position but we continue even if the result is not available + (rx/with-latest vector snap-delta) - ;; We try to use the previous snap so we don't have to wait for the result of the new - (rx/map snap/correct-snap-point) + ;; We try to use the previous snap so we don't have to wait for the result of the new + (rx/map snap/correct-snap-point) - (rx/map - (fn [move-vector] - (let [position (gpt/add from-position move-vector) - target-frame (ctst/top-nested-frame objects position)] - (-> (dwm/create-modif-tree ids (ctm/move move-vector)) - (dwm/build-change-frame-modifiers objects selected target-frame position) - (dwm/set-modifiers))))) + (rx/map + (fn [move-vector] + (let [position (gpt/add from-position move-vector) + target-frame (ctst/top-nested-frame objects position exclude-frames) + layout? (ctl/layout? objects target-frame) + drop-index (when layout? (gsl/get-drop-index target-frame objects position))] + [move-vector target-frame drop-index]))) - (rx/take-until stopper))) + (rx/take-until stopper))] - (rx/of (dwu/start-undo-transaction) - (calculate-frame-for-move ids) - (dwm/apply-modifiers {:undo-transation? false}) - (finish-transform) - (dwu/commit-undo-transaction))))))))) + (rx/merge + ;; Temporary modifiers stream + (->> move-stream + (rx/map + (fn [[move-vector target-frame drop-index]] + (-> (dwm/create-modif-tree ids (ctm/move move-vector)) + (dwm/build-change-frame-modifiers objects selected target-frame drop-index) + (dwm/set-modifiers))))) + + ;; Last event will write the modifiers creating the changes + (->> move-stream + (rx/last) + (rx/mapcat + (fn [[move-vector target-frame drop-index]] + (rx/of (dwu/start-undo-transaction) + (move-shapes-to-frame ids target-frame drop-index) + (dwm/apply-modifiers {:undo-transation? false}) + (finish-transform) + (dwu/commit-undo-transaction))))))))))))) (s/def ::direction #{:up :down :right :left}) @@ -561,15 +580,13 @@ (rx/of (dwm/set-modifiers modif-tree) (dwm/apply-modifiers)))))) -(defn- calculate-frame-for-move - [ids] - (ptk/reify ::calculate-frame-for-move +(defn- move-shapes-to-frame + [ids frame-id drop-index] + (ptk/reify ::move-shapes-to-frame ptk/WatchEvent (watch [it state _] - (let [position @ms/mouse-position - page-id (:current-page-id state) + (let [page-id (:current-page-id state) objects (wsh/lookup-page-objects state page-id) - frame-id (ctst/top-nested-frame objects position) layout? (get-in objects [frame-id :layout]) lookup (d/getf objects) @@ -584,14 +601,12 @@ (remove #(and (= (:frame-id %) frame-id) (not= (:parent-id %) frame-id)))) - drop-index (when layout? (gsl/get-drop-index frame-id objects position)) - changes (-> (pcb/empty-changes it page-id) (pcb/with-objects objects) (pcb/change-parent frame-id moving-shapes drop-index))] - (when-not (empty? changes) + (when (and (some? frame-id) (not (empty? changes))) (rx/of (dch/commit-changes changes) (dwc/expand-collapse frame-id)))))))