From 83a02ad6e6dee44ad6965072823d68e8c8734a81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Mon, 30 Mar 2020 11:20:09 +0200 Subject: [PATCH 1/5] :tada: Copy and paste to cursor position --- frontend/src/uxbox/main/data/workspace.cljs | 38 +++++++++++++-------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/frontend/src/uxbox/main/data/workspace.cljs b/frontend/src/uxbox/main/data/workspace.cljs index 6ee707b358..8b1daf4d86 100644 --- a/frontend/src/uxbox/main/data/workspace.cljs +++ b/frontend/src/uxbox/main/data/workspace.cljs @@ -2051,43 +2051,51 @@ (defn- paste-impl [{:keys [selected objects] :as data}] - (letfn [(prepare-change [id] + (letfn [(prepare-change [delta id] (let [obj (get objects id)] - ;; (prn "prepare-change" id obj) (if (= :frame (:type obj)) - (prepare-frame-change obj) - (prepare-shape-change obj uuid/zero)))) + (prepare-frame-change obj delta) + (prepare-shape-change obj delta uuid/zero)))) - (prepare-shape-change [obj frame-id] - (let [id (uuid/next)] + (prepare-shape-change [obj delta frame-id] + (let [id (uuid/next) + renamed-obj (assoc obj :id id :frame-id frame-id) + moved-obj (geom/move renamed-obj delta)] {:type :add-obj :id id :frame-id frame-id - :obj (assoc obj :id id :frame-id frame-id)})) + :obj moved-obj})) - (prepare-frame-change [obj] + (prepare-frame-change [obj delta] (let [frame-id (uuid/next) sch (->> (map #(get objects %) (:shapes obj)) - (map #(prepare-shape-change % frame-id))) + (map #(prepare-shape-change % delta frame-id))) + renamed-frame (-> obj + (assoc :id frame-id) + (assoc :frame-id uuid/zero) + (assoc :shapes (mapv :id sch))) + moved-frame (geom/move renamed-frame delta) fch {:type :add-obj :id frame-id :frame-id uuid/zero - :obj (-> obj - (assoc :id frame-id) - (assoc :frame-id uuid/zero) - (assoc :shapes (mapv :id sch)))}] + :obj moved-frame}] (d/concat [fch] sch)))] (ptk/reify ::paste-impl ptk/WatchEvent (watch [_ state stream] - (let [rchanges (->> (map prepare-change selected) + (let [selected-objs (map #(get objects %) selected) + orig-pos (geom/selection-rect selected-objs) + mouse-pos @ms/mouse-position + delta {:x (- (:x mouse-pos) (:x orig-pos)) + :y (- (:y mouse-pos) (:y orig-pos))} + + rchanges (->> (map (partial prepare-change delta) selected) (flatten)) uchanges (map (fn [ch] {:type :del-obj :id (:id ch)}) rchanges)] - (cljs.pprint/pprint rchanges) (rx/of (commit-changes (vec rchanges) (vec (reverse uchanges)) {:commit-local? true}))))))) From 82c264b75fd9bc9c83e7cd851b29c41b228faf70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Mon, 30 Mar 2020 16:15:09 +0200 Subject: [PATCH 2/5] :tada: Give unique names to objects when pasting --- frontend/src/uxbox/main/data/workspace.cljs | 70 ++++++++++++++------- 1 file changed, 49 insertions(+), 21 deletions(-) diff --git a/frontend/src/uxbox/main/data/workspace.cljs b/frontend/src/uxbox/main/data/workspace.cljs index 8b1daf4d86..584b30c1a4 100644 --- a/frontend/src/uxbox/main/data/workspace.cljs +++ b/frontend/src/uxbox/main/data/workspace.cljs @@ -930,26 +930,34 @@ ;; --- Add shape to Workspace (defn impl-retrieve-used-names - "Returns a set of already used names by shapes - in the current workspace page." - [state] - (let [page-id (::page-id state) - objects (get-in state [:workspace-data page-id :objects])] - (into #{} (map :name) (vals objects)))) + [objects] + (into #{} (map :name) (vals objects))) + +(defn extract-numeric-suffix + [basename] + (let [result (re-find #"(.*)-([0-9]+)$" basename)] + (if result + [(get result 1) (+ 1 (js/parseInt (get result 2)))] + [basename 1]))) (defn impl-generate-unique-name - "A unique name generator based on the current workspace page." - [state basename] - (let [used (impl-retrieve-used-names state)] - (loop [counter 1] - (let [candidate (str basename "-" counter)] + "A unique name generator" + [objects basename] + (let [used (impl-retrieve-used-names objects) + [prefix initial] (extract-numeric-suffix basename)] + (loop [counter initial] + (let [candidate (str prefix "-" counter)] (if (contains? used candidate) (recur (inc counter)) candidate))))) (defn impl-assoc-shape + "Add a shape to the current workspace page, inside a given frame. + Give it a name that is unique in the page" [state {:keys [id frame-id] :as data}] - (let [name (impl-generate-unique-name state (:name data)) + (let [page-id (::page-id state) + objects (get-in state [:workspace-data page-id :objects]) + name (impl-generate-unique-name objects (:name data)) shape (assoc data :name name) page-id (::page-id state)] (-> state @@ -2051,27 +2059,48 @@ (defn- paste-impl [{:keys [selected objects] :as data}] - (letfn [(prepare-change [delta id] + (letfn [(prepare-changes [state delta] + "Prepare objects to paste: generate new id, give them unique names, + and move to the position of mouse pointer" + (let [page-id (::page-id state)] + (loop [existing-objs (get-in state [:workspace-data page-id :objects]) + chgs [] + id (first selected) + ids (rest selected)] + (if (nil? id) + chgs + (let [result (prepare-change id existing-objs delta) + result (if (vector? result) result [result])] + (recur + (reduce conj existing-objs (map (fn [item] {(:id item) (:obj item)}) result)) + (into chgs result) + (first ids) + (rest ids))))))) + + (prepare-change [id existing-objs delta] (let [obj (get objects id)] (if (= :frame (:type obj)) - (prepare-frame-change obj delta) - (prepare-shape-change obj delta uuid/zero)))) + (prepare-frame-change existing-objs obj delta) + (prepare-shape-change existing-objs obj delta uuid/zero)))) - (prepare-shape-change [obj delta frame-id] + (prepare-shape-change [objects obj delta frame-id] (let [id (uuid/next) - renamed-obj (assoc obj :id id :frame-id frame-id) + name (impl-generate-unique-name objects (:name obj)) + renamed-obj (assoc obj :id id :frame-id frame-id :name name) moved-obj (geom/move renamed-obj delta)] {:type :add-obj :id id :frame-id frame-id :obj moved-obj})) - (prepare-frame-change [obj delta] + (prepare-frame-change [objects obj delta] (let [frame-id (uuid/next) + frame-name (impl-generate-unique-name objects (:name obj)) sch (->> (map #(get objects %) (:shapes obj)) - (map #(prepare-shape-change % delta frame-id))) + (map #(prepare-shape-change objects % delta frame-id))) renamed-frame (-> obj (assoc :id frame-id) + (assoc :name frame-name) (assoc :frame-id uuid/zero) (assoc :shapes (mapv :id sch))) moved-frame (geom/move renamed-frame delta) @@ -2090,8 +2119,7 @@ delta {:x (- (:x mouse-pos) (:x orig-pos)) :y (- (:y mouse-pos) (:y orig-pos))} - rchanges (->> (map (partial prepare-change delta) selected) - (flatten)) + rchanges (prepare-changes state delta) uchanges (map (fn [ch] {:type :del-obj :id (:id ch)}) From a4d8675a15cd690279499bdfb0d3c793b08e07ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Tue, 31 Mar 2020 13:22:31 +0200 Subject: [PATCH 3/5] :tada: Calculate in which frame the pasted objects fit --- frontend/src/uxbox/main/data/workspace.cljs | 31 +++++++++++---------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/frontend/src/uxbox/main/data/workspace.cljs b/frontend/src/uxbox/main/data/workspace.cljs index 584b30c1a4..7a41243308 100644 --- a/frontend/src/uxbox/main/data/workspace.cljs +++ b/frontend/src/uxbox/main/data/workspace.cljs @@ -973,9 +973,8 @@ :fill-opacity 1}) (defn- calculate-frame-overlap - [data shape] - (let [objects (:objects data) - rshp (geom/shape->rect-shape shape) + [objects shape] + (let [rshp (geom/shape->rect-shape shape) xfmt (comp (filter #(= :frame (:type %))) @@ -997,10 +996,10 @@ ptk/UpdateEvent (update [_ state] (let [page-id (::page-id state) - data (get-in state [:workspace-data page-id]) + objects (get-in state [:workspace-data page-id :objects]) shape (-> (geom/setup-proportions attrs) (assoc :id id)) - frame-id (calculate-frame-overlap data shape) + frame-id (calculate-frame-overlap objects shape) shape (merge shape-default-attrs shape {:frame-id frame-id})] (impl-assoc-shape state shape))) @@ -1524,9 +1523,9 @@ (if (nil? id) [rch uch] (let [pid (::page-id state) - dta (get-in state [:workspace-data pid]) - obj (get-in dta [:objects id]) - fid (calculate-frame-overlap dta obj)] + objects (get-in state [:workspace-data pid :objects]) + obj (get objects id) + fid (calculate-frame-overlap objects obj)] (if (not= fid (:frame-id obj)) (recur (first ids) (rest ids) @@ -2060,8 +2059,8 @@ (defn- paste-impl [{:keys [selected objects] :as data}] (letfn [(prepare-changes [state delta] - "Prepare objects to paste: generate new id, give them unique names, - and move to the position of mouse pointer" + "Prepare objects to paste: generate new id, give them unique names, move + to the position of mouse pointer, and find in what frame they fit." (let [page-id (::page-id state)] (loop [existing-objs (get-in state [:workspace-data page-id :objects]) chgs [] @@ -2081,17 +2080,21 @@ (let [obj (get objects id)] (if (= :frame (:type obj)) (prepare-frame-change existing-objs obj delta) - (prepare-shape-change existing-objs obj delta uuid/zero)))) + (prepare-shape-change existing-objs obj delta nil)))) (prepare-shape-change [objects obj delta frame-id] (let [id (uuid/next) name (impl-generate-unique-name objects (:name obj)) - renamed-obj (assoc obj :id id :frame-id frame-id :name name) - moved-obj (geom/move renamed-obj delta)] + renamed-obj (assoc obj :id id :name name) + moved-obj (geom/move renamed-obj delta) + frame-id (if frame-id + frame-id + (calculate-frame-overlap objects moved-obj)) + reframed-obj (assoc moved-obj :frame-id frame-id)] {:type :add-obj :id id :frame-id frame-id - :obj moved-obj})) + :obj reframed-obj})) (prepare-frame-change [objects obj delta] (let [frame-id (uuid/next) From 637f0934f97419b17424d5fe5a11b0a018371624 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Tue, 31 Mar 2020 15:25:29 +0200 Subject: [PATCH 4/5] :tada: Auto select pasted objects --- frontend/src/uxbox/main/data/workspace.cljs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/frontend/src/uxbox/main/data/workspace.cljs b/frontend/src/uxbox/main/data/workspace.cljs index 7a41243308..9d0289cbaf 100644 --- a/frontend/src/uxbox/main/data/workspace.cljs +++ b/frontend/src/uxbox/main/data/workspace.cljs @@ -2056,6 +2056,8 @@ (rx/ignore))))))) +(declare select-pasted-objs) + (defn- paste-impl [{:keys [selected objects] :as data}] (letfn [(prepare-changes [state delta] @@ -2129,7 +2131,8 @@ rchanges)] (rx/of (commit-changes (vec rchanges) (vec (reverse uchanges)) - {:commit-local? true}))))))) + {:commit-local? true}) + (select-pasted-objs rchanges))))))) (def paste (ptk/reify ::paste @@ -2144,6 +2147,13 @@ (js/console.error "Clipboard blocked:" err) (rx/empty))))))) +(defn select-pasted-objs + [rchanges] + (ptk/reify ::select-pasted-objs + ptk/UpdateEvent + (update [_ state] + (assoc-in state [:workspace-local :selected] + (map #(get-in % [:obj :id]) rchanges))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Page Changes Reactions From ec3be7678234dea8b945f3c208c2fdc46d166718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Wed, 1 Apr 2020 08:47:19 +0200 Subject: [PATCH 5/5] :recycle: Enhance some fragments of code --- frontend/src/uxbox/main/data/workspace.cljs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/frontend/src/uxbox/main/data/workspace.cljs b/frontend/src/uxbox/main/data/workspace.cljs index 9d0289cbaf..aae9035b71 100644 --- a/frontend/src/uxbox/main/data/workspace.cljs +++ b/frontend/src/uxbox/main/data/workspace.cljs @@ -935,10 +935,9 @@ (defn extract-numeric-suffix [basename] - (let [result (re-find #"(.*)-([0-9]+)$" basename)] - (if result - [(get result 1) (+ 1 (js/parseInt (get result 2)))] - [basename 1]))) + (if-let [[match p1 p2] (re-find #"(.*)-([0-9]+)$" basename)] + [p1 (+ 1 (d/parse-integer p2))] + [basename 1])) (defn impl-generate-unique-name "A unique name generator" @@ -2073,7 +2072,7 @@ (let [result (prepare-change id existing-objs delta) result (if (vector? result) result [result])] (recur - (reduce conj existing-objs (map (fn [item] {(:id item) (:obj item)}) result)) + (reduce #(assoc %1 (:id %2) (:obj %2)) existing-objs result) (into chgs result) (first ids) (rest ids))))))) @@ -2119,10 +2118,10 @@ ptk/WatchEvent (watch [_ state stream] (let [selected-objs (map #(get objects %) selected) - orig-pos (geom/selection-rect selected-objs) + wrapper (geom/selection-rect selected-objs) + orig-pos (gpt/point (:x1 wrapper) (:y1 wrapper)) mouse-pos @ms/mouse-position - delta {:x (- (:x mouse-pos) (:x orig-pos)) - :y (- (:y mouse-pos) (:y orig-pos))} + delta (gpt/subtract mouse-pos orig-pos) rchanges (prepare-changes state delta) uchanges (map (fn [ch] @@ -2153,7 +2152,7 @@ ptk/UpdateEvent (update [_ state] (assoc-in state [:workspace-local :selected] - (map #(get-in % [:obj :id]) rchanges))))) + (into #{} (map #(get-in % [:obj :id])) rchanges))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Page Changes Reactions