From d1437997d22a5a836acf138873b12f4832bb3748 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Tue, 27 Oct 2020 16:47:08 +0100 Subject: [PATCH] :bug: Fixes problem with inside-frame calculations --- common/app/common/geom/shapes.cljc | 10 +++- common/app/common/pages_helpers.cljc | 11 +++- frontend/src/app/main/data/workspace.cljs | 52 ++++++++++++++----- .../src/app/main/data/workspace/common.cljs | 49 ----------------- .../app/main/data/workspace/libraries.cljs | 5 +- .../app/main/data/workspace/selection.cljs | 4 -- .../app/main/data/workspace/transforms.cljs | 37 +++++++++++-- .../app/main/ui/workspace/left_toolbar.cljs | 2 +- .../app/main/ui/workspace/shapes/frame.cljs | 16 +++++- .../main/ui/workspace/sidebar/history.cljs | 4 ++ .../src/app/main/ui/workspace/viewport.cljs | 2 +- 11 files changed, 113 insertions(+), 79 deletions(-) diff --git a/common/app/common/geom/shapes.cljc b/common/app/common/geom/shapes.cljc index 1f77a7d15..ed053344f 100644 --- a/common/app/common/geom/shapes.cljc +++ b/common/app/common/geom/shapes.cljc @@ -11,7 +11,6 @@ (:require [clojure.spec.alpha :as s] [app.common.spec :as us] - [app.common.pages-helpers :as cph] [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] [app.common.math :as mth] @@ -58,10 +57,17 @@ (update :points #(mapv inc-point %)) (update :segments #(mapv inc-point %))))) +;; Duplicated from pages-helpers to remove cyclic dependencies +(defn get-children [id objects] + (let [shapes (vec (get-in objects [id :shapes]))] + (if shapes + (d/concat shapes (mapcat #(get-children % objects) shapes)) + []))) + (defn recursive-move "Move the shape and all its recursive children." [shape dpoint objects] - (let [children-ids (cph/get-children (:id shape) objects) + (let [children-ids (get-children (:id shape) objects) children (map #(get objects %) children-ids)] (map #(move % dpoint) (cons shape children)))) diff --git a/common/app/common/pages_helpers.cljc b/common/app/common/pages_helpers.cljc index cb4ea47eb..28f5a3b40 100644 --- a/common/app/common/pages_helpers.cljc +++ b/common/app/common/pages_helpers.cljc @@ -10,7 +10,8 @@ (ns app.common.pages-helpers (:require [app.common.data :as d] - [app.common.uuid :as uuid])) + [app.common.uuid :as uuid] + [app.common.geom.shapes :as gsh])) (defn walk-pages "Go through all pages of a file and apply a function to each one" @@ -247,3 +248,11 @@ (filter (fn [[idx _]] (and (>= idx from) (<= idx to)))) (map second) (into #{})))) + +(defn frame-id-by-position [objects position] + (let [frames (select-frames objects)] + (or + (->> frames + (d/seek #(gsh/has-point? % position)) + :id) + uuid/zero))) diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 64eba8d41..413ec40e9 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -549,11 +549,8 @@ unames (dwc/retrieve-used-names objects) name (dwc/generate-unique-name unames (:name shape)) - frames (cph/select-frames objects) - - frame-id (if (= :frame (:type shape)) - uuid/zero - (dwc/calculate-frame-overlap frames shape)) + frame-id (or (:frame-id attrs) + (cph/frame-id-by-position objects attrs)) shape (merge (if (= :frame (:type shape)) @@ -561,8 +558,7 @@ cp/default-shape-attrs) (assoc shape :id id - :name name - :frame-id frame-id)) + :name name)) rchange {:type :add-obj :id id @@ -586,19 +582,25 @@ [(+ x (/ width 2)) (+ y (/ height 2))])) (defn create-and-add-shape - [type data] + [type frame-x frame-y data] (ptk/reify ::create-and-add-shape ptk/WatchEvent (watch [_ state stream] (let [{:keys [width height]} data + [vbc-x vbc-y] (viewport-center state) x (:x data (- vbc-x (/ width 2))) y (:y data (- vbc-y (/ height 2))) + page-id (:current-page-id state) + frame-id (-> (dwc/lookup-page-objects state page-id) + (cph/frame-id-by-position {:x frame-x :y frame-y})) + shape (-> (cp/make-minimal-shape type) (merge data) (merge {:x x :y y}) + (assoc :frame-id frame-id) (geom/setup-selrect))] (rx/of (add-shape shape)))))) @@ -1243,16 +1245,26 @@ (def copy-selected (letfn [(prepare-selected [objects selected] - (let [data (reduce #(prepare %1 objects %2) {} selected)] + (let [data (reduce #(prepare %1 objects selected %2) {} selected)] {:type :copied-shapes :selected selected :objects data})) - (prepare [result objects id] - (let [obj (get objects id)] + (maybe-translate [shape objects selected] + (if (and (not= (:type shape) :frame) + (not (contains? selected (:frame-id shape)))) + ;; When the parent frame is not selected we change to relative + ;; coordinates + (let [frame (get objects (:frame-id shape))] + (geom/translate-to-frame shape frame)) + shape)) + + (prepare [result objects selected id] + (let [obj (-> (get objects id) + (maybe-translate objects selected))] (as-> result $$ (assoc $$ id obj) - (reduce #(prepare %1 objects %2) $$ (:shapes obj))))) + (reduce #(prepare %1 objects selected %2) $$ (:shapes obj))))) (on-copy-error [error] (js/console.error "Clipboard blocked:" error) @@ -1279,6 +1291,15 @@ wrapper (geom/selection-rect selected-objs) orig-pos (gpt/point (:x1 wrapper) (:y1 wrapper)) mouse-pos @ms/mouse-position + + page-id (:current-page-id state) + frame-id (-> (dwc/lookup-page-objects state page-id) + (cph/frame-id-by-position mouse-pos)) + + objects (d/mapm (fn [_ v] (assoc v + :frame-id frame-id + :parent-id frame-id)) objects) + delta (gpt/subtract mouse-pos orig-pos) page-id (:current-page-id state) @@ -1309,7 +1330,7 @@ :height height :id (:id image) :path (:path image)}}] - (st/emit! (create-and-add-shape :image shape)))) + (st/emit! (create-and-add-shape :image x y shape)))) (defn- paste-image-impl [image] @@ -1378,12 +1399,16 @@ {:keys [x y]} @ms/mouse-position width (min (* 7 (count text)) 700) height 16 + page-id (:current-page-id state) + frame-id (-> (dwc/lookup-page-objects state page-id) + (cph/frame-id-by-position @ms/mouse-position)) shape (geom/setup-selrect {:id id :type :text :name "Text" :x x :y y + :frame-id frame-id :width width :height height :grow-type (if (> (count text) 100) :auto-height :auto-width) @@ -1391,7 +1416,6 @@ (rx/of dwc/start-undo-transaction (dws/deselect-all) (add-shape shape) - (dwc/rehash-shape-frame-relationship [id]) dwc/commit-undo-transaction))))) (defn update-shape-flags diff --git a/frontend/src/app/main/data/workspace/common.cljs b/frontend/src/app/main/data/workspace/common.cljs index 06a77f648..282efc500 100644 --- a/frontend/src/app/main/data/workspace/common.cljs +++ b/frontend/src/app/main/data/workspace/common.cljs @@ -155,55 +155,6 @@ ;; --- Common Helpers & Events -(defn- calculate-frame-overlap - [frames shape] - (let [xf (comp - (filter #(geom/overlaps? % (:selrect shape))) - (take 1)) - frame (first (into [] xf frames))] - (or (:id frame) uuid/zero))) - -(defn- calculate-shape-to-frame-relationship-changes - [page-id frames shapes] - (loop [shape (first shapes) - shapes (rest shapes) - rch [] - uch []] - (if (nil? shape) - [rch uch] - (let [fid (calculate-frame-overlap frames shape)] - (if (not= fid (:frame-id shape)) - (recur (first shapes) - (rest shapes) - (conj rch {:type :mov-objects - :page-id page-id - :parent-id fid - :shapes [(:id shape)]}) - (conj uch {:type :mov-objects - :page-id page-id - :parent-id (:frame-id shape) - :shapes [(:id shape)]})) - (recur (first shapes) - (rest shapes) - rch - uch)))))) - -(defn rehash-shape-frame-relationship - [ids] - (ptk/reify ::rehash-shape-frame-relationship - ptk/WatchEvent - (watch [_ state stream] - (let [page-id (:current-page-id state) - objects (lookup-page-objects state page-id) - - shapes (cph/select-toplevel-shapes objects) - frames (cph/select-frames objects) - - [rch uch] (calculate-shape-to-frame-relationship-changes page-id frames shapes)] - (when-not (empty? rch) - (rx/of (commit-changes rch uch {:commit-local? true}))))))) - - (defn get-frame-at-point [objects point] (let [frames (cph/select-frames objects)] diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 94badbbd6..44aa7881f 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -241,7 +241,7 @@ objects (dwc/lookup-page-objects state page-id) unames (atom (dwc/retrieve-used-names objects)) - all-frames (cph/select-frames objects) + frame-id (cph/frame-id-by-position objects (gpt/add orig-pos delta)) update-new-shape (fn [new-shape original-shape] @@ -255,8 +255,7 @@ (as-> $ (assoc $ :name new-name) (geom/move $ delta) - (assoc $ :frame-id - (dwc/calculate-frame-overlap all-frames $)) + (assoc $ :frame-id frame-id) (assoc $ :parent-id (or (:parent-id $) (:frame-id $))) (assoc $ :shape-ref (:id original-shape)) diff --git a/frontend/src/app/main/data/workspace/selection.cljs b/frontend/src/app/main/data/workspace/selection.cljs index eeee08501..0ade6bbc5 100644 --- a/frontend/src/app/main/data/workspace/selection.cljs +++ b/frontend/src/app/main/data/workspace/selection.cljs @@ -304,10 +304,6 @@ renamed-obj (assoc obj :id id :name name) moved-obj (geom/move renamed-obj delta) frames (cph/select-frames objects) - frame-id (if frame-id - frame-id - (dwc/calculate-frame-overlap frames moved-obj)) - parent-id (or parent-id frame-id) children-changes diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 5f9025dcc..56985d95c 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -233,6 +233,38 @@ (rx/first) (rx/map #(start-move from-position)))))) +(defn calculate-frame-for-move [ids] + (ptk/reify ::calculate-frame-for-move + ptk/WatchEvent + (watch [_ state stream] + (let [position @ms/mouse-position + page-id (:current-page-id state) + objects (dwc/lookup-page-objects state page-id) + frame-id (cph/frame-id-by-position objects position) + + moving-shapes (->> ids + (map #(get objects %)) + (remove #(= (:frame-id %) frame-id))) + + rch [{:type :mov-objects + :page-id page-id + :parent-id frame-id + :shapes (mapv :id moving-shapes)}] + + moving-shapes-by-frame-id (group-by :frame-id moving-shapes) + + uch (->> moving-shapes-by-frame-id + (mapv (fn [[frame-id shapes]] + {:type :mov-objects + :page-id page-id + :parent-id frame-id + :shapes (mapv :id shapes)})))] + + (when-not (empty? rch) + (rx/of dwc/pop-undo-into-transaction + (dwc/commit-changes rch uch {:commit-local? true}) + dwc/commit-undo-transaction)))))) + (defn start-move ([from-position] (start-move from-position nil)) ([from-position ids] @@ -261,6 +293,7 @@ (rx/of (set-modifiers ids) (apply-modifiers ids) + (calculate-frame-for-move ids) (fn [state] (update state :workspace-local dissoc :modifiers)) finish-transform))))))) @@ -433,10 +466,8 @@ ;; we have 3 different objects references). rchanges (conj (dwc/generate-changes page-id objects1 objects2) regchg) - uchanges (conj (dwc/generate-changes page-id objects2 objects0) regchg) - ] + uchanges (conj (dwc/generate-changes page-id objects2 objects0) regchg)] (rx/of dwc/start-undo-transaction (dwc/commit-changes rchanges uchanges {:commit-local? true}) - (dwc/rehash-shape-frame-relationship ids) dwc/commit-undo-transaction))))) diff --git a/frontend/src/app/main/ui/workspace/left_toolbar.cljs b/frontend/src/app/main/ui/workspace/left_toolbar.cljs index 482f3b97d..8a1cd65c4 100644 --- a/frontend/src/app/main/ui/workspace/left_toolbar.cljs +++ b/frontend/src/app/main/ui/workspace/left_toolbar.cljs @@ -42,7 +42,7 @@ :id (:id image) :path (:path image)}} aspect-ratio (/ (:width image) (:height image))] - (st/emit! (dw/create-and-add-shape :image shape)))) + (st/emit! (dw/create-and-add-shape :image 0 0 shape)))) on-files-selected (fn [js-files] diff --git a/frontend/src/app/main/ui/workspace/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/shapes/frame.cljs index d72bc71ca..433b22f3f 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame.cljs @@ -70,6 +70,13 @@ :on-mouse-out on-mouse-out} (:name frame)])) +(defn make-is-moving-ref + [id] + (let [check-moving (fn [local] + (and (= :move (:transform local)) + (contains? (:selected local) id)))] + (l/derived check-moving refs/workspace-local))) + (defn frame-wrapper-factory [shape-wrapper] (let [frame-shape (frame/frame-shape shape-wrapper)] @@ -80,6 +87,11 @@ [props] (let [shape (unchecked-get props "shape") objects (unchecked-get props "objects") + ghost? (unchecked-get props "ghost?") + + moving-iref (mf/use-memo (mf/deps (:id shape)) + #(make-is-moving-ref (:id shape))) + moving? (mf/deref moving-iref) selected-iref (mf/use-memo (mf/deps (:id shape)) #(refs/make-selected-ref (:id shape))) @@ -114,7 +126,9 @@ (fn [] (st/emit! (dws/change-hover-state (:id shape) false))))] - (when-not (:hidden shape) + (when (and shape + (or ghost? (not moving?)) + (not (:hidden shape))) [:g {:class (when selected? "selected") :on-context-menu on-context-menu :on-double-click on-double-click diff --git a/frontend/src/app/main/ui/workspace/sidebar/history.cljs b/frontend/src/app/main/ui/workspace/sidebar/history.cljs index 6f14f6933..aebc62bb5 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/history.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/history.cljs @@ -187,6 +187,10 @@ (single? (filter #(= :group (first %)) (:delete operations))) (-> entries (get (first (filter #(= :group (first %)) (:delete operations)))) (last)) + ;; If there is a move of shapes will have priority + (single? (:move operations)) + (-> entries (get (first (:move operations))) (last)) + ;; Otherwise we could have the same operation between several ;; types (i.e: delete various shapes). If that happens we return ;; the operation with `:multiple` id diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index 88290eafb..57f1b462d 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -408,7 +408,7 @@ :id (:id image) :path (:path image)}} aspect-ratio (/ (:width image) (:height image))] - (st/emit! (dw/create-and-add-shape :image shape)))) + (st/emit! (dw/create-and-add-shape :image x y shape)))) on-drop (fn [event]