🔧 Use changes-builder in many places

This commit is contained in:
Andrés Moya 2022-02-28 13:22:40 +01:00
parent a7b455fb9a
commit e609670a41
17 changed files with 174 additions and 407 deletions

View file

@ -26,6 +26,10 @@
:undo-changes [] :undo-changes []
:origin origin})) :origin origin}))
(defn set-save-undo?
[changes save-undo?]
(assoc changes :save-undo? save-undo?))
(defn with-page [changes page] (defn with-page [changes page]
(vary-meta changes assoc (vary-meta changes assoc
::page page ::page page
@ -266,10 +270,10 @@
(d/preconj (d/preconj
change-set change-set
{:type :add-obj {:type :add-obj
:id id
:page-id page-id :page-id page-id
:parent-id (:frame-id shape) :parent-id (:frame-id shape)
:frame-id (:frame-id shape) :frame-id (:frame-id shape)
:id id
:index (cph/get-position-on-parent objects id) :index (cph/get-position-on-parent objects id)
:obj (cond-> shape :obj (cond-> shape
(contains? shape :shapes) (contains? shape :shapes)

View file

@ -194,15 +194,6 @@
(conj done (:id current)) (conj done (:id current))
(concat (rest pending) (:shapes current)))))) (concat (rest pending) (:shapes current))))))
(defn get-index-in-parent
"Retrieves the index in the parent"
[objects shape-id]
(let [shape (get objects shape-id)
parent (get objects (:parent-id shape))
[parent-idx _] (d/seek (fn [[_idx child-id]] (= child-id shape-id))
(d/enumerate (:shapes parent)))]
parent-idx))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; COMPONENTS HELPERS ;; COMPONENTS HELPERS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View file

@ -14,7 +14,7 @@
"scripts": { "scripts": {
"compile-test": "clojure -M:dev:shadow-cljs compile test --config-merge '{:autorun false}'", "compile-test": "clojure -M:dev:shadow-cljs compile test --config-merge '{:autorun false}'",
"lint-scss": "yarn run prettier -c resources/styles", "lint-scss": "yarn run prettier -c resources/styles",
"run-test": "node target/test.js", "run-test": "node target/tests.js",
"test": "yarn run compile-test && yarn run run-test", "test": "yarn run compile-test && yarn run run-test",
"watch-gulp": "gulp watch", "watch-gulp": "gulp watch",
"watch-main": "shadow-cljs watch main", "watch-main": "shadow-cljs watch main",

View file

@ -8,7 +8,7 @@
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.common.pages.changes-builder :as cb] [app.common.pages.changes-builder :as pcb]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.path.shapes-to-path :as stp] [app.common.path.shapes-to-path :as stp]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
@ -96,10 +96,10 @@
(when-not (empty? shapes) (when-not (empty? shapes)
(let [[boolean-data index] (create-bool-data bool-type name shapes objects) (let [[boolean-data index] (create-bool-data bool-type name shapes objects)
shape-id (:id boolean-data) shape-id (:id boolean-data)
changes (-> (cb/empty-changes it page-id) changes (-> (pcb/empty-changes it page-id)
(cb/with-objects objects) (pcb/with-objects objects)
(cb/add-obj boolean-data {:index index}) (pcb/add-obj boolean-data {:index index})
(cb/change-parent shape-id shapes))] (pcb/change-parent shape-id shapes))]
(rx/of (dch/commit-changes changes) (rx/of (dch/commit-changes changes)
(dwc/select-shapes (d/ordered-set shape-id))))))))) (dwc/select-shapes (d/ordered-set shape-id)))))))))

View file

@ -6,9 +6,9 @@
(ns app.main.data.workspace.changes (ns app.main.data.workspace.changes
(:require (:require
[app.common.data :as d]
[app.common.logging :as log] [app.common.logging :as log]
[app.common.pages :as cp] [app.common.pages :as cp]
[app.common.pages.changes-builder :as pcb]
[app.common.spec :as us] [app.common.spec :as us]
[app.common.spec.change :as spec.change] [app.common.spec.change :as spec.change]
[app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.state-helpers :as wsh]
@ -31,78 +31,38 @@
(def commit-changes? (ptk/type? ::commit-changes)) (def commit-changes? (ptk/type? ::commit-changes))
(defn- generate-operation
"Given an object old and new versions and an attribute will append into changes
the set and undo operations"
[changes attr old new ignore-geometry?]
(let [old-val (get old attr)
new-val (get new attr)]
(if (= old-val new-val)
changes
(-> changes
(update :rops conj {:type :set :attr attr :val new-val :ignore-geometry ignore-geometry?})
(update :uops conj {:type :set :attr attr :val old-val :ignore-touched true})))))
(defn- update-shape-changes
"Calculate the changes and undos to be done when a function is applied to a
single object"
[changes page-id objects update-fn attrs id ignore-geometry?]
(let [old-obj (get objects id)
new-obj (update-fn old-obj)
attrs (or attrs (d/concat-set (keys old-obj) (keys new-obj)))
{rops :rops uops :uops}
(reduce #(generate-operation %1 %2 old-obj new-obj ignore-geometry?)
{:rops [] :uops []}
attrs)
uops (cond-> uops
(seq uops)
(conj {:type :set-touched :touched (:touched old-obj)}))
change {:type :mod-obj :page-id page-id :id id}]
(cond-> changes
(seq rops)
(update :redo-changes conj (assoc change :operations rops))
(seq uops)
(update :undo-changes conj (assoc change :operations uops)))))
(defn update-shapes (defn update-shapes
([ids f] (update-shapes ids f nil nil)) ([ids update-fn] (update-shapes ids update-fn nil nil))
([ids f keys] (update-shapes ids f nil keys)) ([ids update-fn keys] (update-shapes ids update-fn nil keys))
([ids f page-id {:keys [reg-objects? save-undo? attrs ignore-tree] ([ids update-fn page-id {:keys [reg-objects? save-undo? attrs ignore-tree]
:or {reg-objects? false save-undo? true attrs nil}}] :or {reg-objects? false save-undo? true attrs nil}}]
(us/assert ::coll-of-uuid ids) (us/assert ::coll-of-uuid ids)
(us/assert fn? f) (us/assert fn? update-fn)
(ptk/reify ::update-shapes (ptk/reify ::update-shapes
ptk/WatchEvent ptk/WatchEvent
(watch [it state _] (watch [it state _]
(let [page-id (or page-id (:current-page-id state)) (let [page-id (or page-id (:current-page-id state))
objects (wsh/lookup-page-objects state page-id) objects (wsh/lookup-page-objects state)
changes {:redo-changes []
:undo-changes []
:origin it
:save-undo? save-undo?}
ids (into [] (filter some?) ids) ids (into [] (filter some?) ids)
changes (reduce changes (reduce
#(update-shape-changes %1 page-id objects f attrs %2 (get ignore-tree %2)) (fn [changes id]
changes ids)] (pcb/update-shapes changes
[id]
update-fn
{:attrs attrs
:ignore-geometry? (get ignore-tree id)}))
(-> (pcb/empty-changes it page-id)
(pcb/set-save-undo? save-undo?)
(pcb/with-objects objects))
ids)]
(when-not (empty? (:redo-changes changes)) (when (seq (:redo-changes changes))
(let [reg-objs {:type :reg-objects (let [changes (cond-> changes
:page-id page-id
:shapes ids}
changes (cond-> changes
reg-objects? reg-objects?
(-> (update :redo-changes conj reg-objs) (pcb/resize-parents ids))]
(update :undo-changes conj reg-objs)))]
(rx/of (commit-changes changes))))))))) (rx/of (commit-changes changes)))))))))
(defn update-indices (defn update-indices
@ -125,6 +85,7 @@
(ptk/reify ::commit-changes (ptk/reify ::commit-changes
cljs.core/IDeref cljs.core/IDeref
(-deref [_] (-deref [_]
{:file-id file-id {:file-id file-id
:hint-events @st/last-events :hint-events @st/last-events
:hint-origin (ptk/type origin) :hint-origin (ptk/type origin)

View file

@ -8,8 +8,10 @@
(:require (:require
[app.common.colors :as clr] [app.common.colors :as clr]
[app.common.data :as d] [app.common.data :as d]
[app.common.pages.changes-builder :as pcb]
[app.common.spec :as us] [app.common.spec :as us]
[app.main.data.workspace.changes :as dch] [app.main.data.workspace.changes :as dch]
[app.main.data.workspace.state-helpers :as wsh]
[beicon.core :as rx] [beicon.core :as rx]
[potok.core :as ptk])) [potok.core :as ptk]))
@ -72,15 +74,8 @@
(ptk/reify ::set-default-grid (ptk/reify ::set-default-grid
ptk/WatchEvent ptk/WatchEvent
(watch [it state _] (watch [it state _]
(let [pid (:current-page-id state) (let [page (wsh/lookup-page state)]
prev-value (get-in state [:workspace-data :pages-index pid :options :saved-grids type])]
(rx/of (dch/commit-changes (rx/of (dch/commit-changes
{:redo-changes [{:type :set-option (-> (pcb/empty-changes it)
:page-id pid (pcb/with-page page)
:option [:saved-grids type] (pcb/set-page-option [:saved-grids type] params))))))))
:value params}]
:undo-changes [{:type :set-option
:page-id pid
:option [:saved-grids type]
:value prev-value}]
:origin it}))))))

View file

@ -9,9 +9,8 @@
[app.common.data :as d] [app.common.data :as d]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.common.pages :as cp] [app.common.pages :as cp]
[app.common.pages.changes-builder :as cb] [app.common.pages.changes-builder :as pcb]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.spec :as us]
[app.main.data.workspace.changes :as dch] [app.main.data.workspace.changes :as dch]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.state-helpers :as wsh]
@ -65,7 +64,7 @@
result))))))) result)))))))
(defn prepare-create-group (defn prepare-create-group
[objects page-id shapes base-name keep-name?] [it objects page-id shapes base-name keep-name?]
(let [frame-id (:frame-id (first shapes)) (let [frame-id (:frame-id (first shapes))
parent-id (:parent-id (first shapes)) parent-id (:parent-id (first shapes))
gname (if (and keep-name? gname (if (and keep-name?
@ -78,62 +77,22 @@
selrect (gsh/selection-rect shapes) selrect (gsh/selection-rect shapes)
group (-> (cp/make-minimal-group frame-id selrect gname) group (-> (cp/make-minimal-group frame-id selrect gname)
(gsh/setup selrect) (gsh/setup selrect)
(assoc :shapes (mapv :id shapes))) (assoc :shapes (mapv :id shapes)
rchanges [{:type :add-obj
:id (:id group)
:page-id page-id
:frame-id frame-id
:parent-id parent-id :parent-id parent-id
:obj group :frame-id frame-id
:index (::index (first shapes))} :index (::index (first shapes))))
{:type :mov-objects
:page-id page-id
:parent-id (:id group)
:shapes (mapv :id shapes)}]
uchanges (-> (mapv (fn [obj]
{:type :mov-objects
:page-id page-id
:parent-id (:parent-id obj)
:index (::index obj)
:shapes [(:id obj)]})
shapes)
(conj {:type :del-obj
:id (:id group)
:page-id page-id}))
;; Look at the `get-empty-groups-after-group-creation` ;; Look at the `get-empty-groups-after-group-creation`
;; docstring to understand the real purpose of this code ;; docstring to understand the real purpose of this code
ids-to-delete (get-empty-groups-after-group-creation objects parent-id shapes) ids-to-delete (get-empty-groups-after-group-creation objects parent-id shapes)
delete-group changes (-> (pcb/empty-changes it page-id)
(fn [changes id] (pcb/with-objects objects)
(conj changes {:type :del-obj (pcb/add-obj group)
:id id (pcb/change-parent (:id group) shapes)
:page-id page-id})) (pcb/remove-objects ids-to-delete))]
add-deleted-group [group changes]))
(fn [changes id]
(let [obj (-> (get objects id)
(dissoc :shapes))]
(into [{:type :add-obj
:id id
:page-id page-id
:frame-id (:frame-id obj)
:parent-id (:parent-id obj)
:obj obj
:index (::index obj)}]
changes)))
rchanges (->> ids-to-delete
(reduce delete-group rchanges))
uchanges (->> ids-to-delete
(reduce add-deleted-group uchanges))]
[group rchanges uchanges]))
(defn prepare-remove-group (defn prepare-remove-group
[it page-id group objects] [it page-id group objects]
@ -159,36 +118,13 @@
:shape-ref :shape-ref
:touched))] :touched))]
(cond-> (-> (cb/empty-changes it page-id) (cond-> (-> (pcb/empty-changes it page-id)
(cb/with-objects objects) (pcb/with-objects objects)
(cb/change-parent parent-id children index-in-parent) (pcb/change-parent parent-id children index-in-parent)
(cb/remove-objects [(:id group)])) (pcb/remove-objects [(:id group)]))
(some? ids-to-detach) (some? ids-to-detach)
(cb/update-shapes ids-to-detach detach-fn)))) (pcb/update-shapes ids-to-detach detach-fn))))
(defn prepare-remove-mask
[page-id mask]
(let [rchanges [{:type :mod-obj
:page-id page-id
:id (:id mask)
:operations [{:type :set
:attr :masked-group?
:val nil}]}
{:type :reg-objects
:page-id page-id
:shapes [(:id mask)]}]
uchanges [{:type :mod-obj
:page-id page-id
:id (:id mask)
:operations [{:type :set
:attr :masked-group?
:val (:masked-group? mask)}]}
{:type :reg-objects
:page-id page-id
:shapes [(:id mask)]}]]
[rchanges uchanges]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; GROUPS ;; GROUPS
@ -204,11 +140,9 @@
selected (cph/clean-loops objects selected) selected (cph/clean-loops objects selected)
shapes (shapes-for-grouping objects selected)] shapes (shapes-for-grouping objects selected)]
(when-not (empty? shapes) (when-not (empty? shapes)
(let [[group rchanges uchanges] (let [[group changes]
(prepare-create-group objects page-id shapes "Group-1" false)] (prepare-create-group it objects page-id shapes "Group-1" false)]
(rx/of (dch/commit-changes {:redo-changes rchanges (rx/of (dch/commit-changes changes)
:undo-changes uchanges
:origin it})
(dwc/select-shapes (d/ordered-set (:id group)))))))))) (dwc/select-shapes (d/ordered-set (:id group))))))))))
(def ungroup-selected (def ungroup-selected
@ -241,81 +175,35 @@
objects (wsh/lookup-page-objects state page-id) objects (wsh/lookup-page-objects state page-id)
selected (wsh/lookup-selected state) selected (wsh/lookup-selected state)
selected (cph/clean-loops objects selected) selected (cph/clean-loops objects selected)
shapes (shapes-for-grouping objects selected)] shapes (shapes-for-grouping objects selected)
first-shape (first shapes)]
(when-not (empty? shapes) (when-not (empty? shapes)
(let [;; If the selected shape is a group, we can use it. If not, (let [;; If the selected shape is a group, we can use it. If not,
;; create a new group and set it as masked. ;; create a new group and set it as masked.
[group rchanges uchanges] [group changes]
(if (and (= (count shapes) 1) (if (and (= (count shapes) 1)
(= (:type (first shapes)) :group)) (= (:type (first shapes)) :group))
[(first shapes) [] []] [first-shape (-> (pcb/empty-changes it page-id)
(prepare-create-group objects page-id shapes "Group-1" true)) (pcb/with-objects objects))]
(prepare-create-group it objects page-id shapes "Group-1" true))
;; Assertions just for documentation purposes changes (-> changes
_ (us/assert vector? rchanges) (pcb/update-shapes (:shapes group)
_ (us/assert vector? uchanges) (fn [shape]
(assoc shape
:constraints-h :scale
:constraints-v :scale)))
(pcb/update-shapes [(:id group)]
(fn [group]
(assoc group
:masked-group? true
:selrect (:selrect first-shape)
:points (:points first-shape)
:transform (:transform first-shape)
:transform-inverse (:transform-inverse first-shape))))
(pcb/resize-parents [(:id group)]))]
children (map #(get objects %) (:shapes group)) (rx/of (dch/commit-changes changes)
rchanges (d/concat-vec
rchanges
(for [child children]
{:type :mod-obj
:page-id page-id
:id (:id child)
:operations [{:type :set
:attr :constraints-h
:val :scale}
{:type :set
:attr :constraints-v
:val :scale}]})
[{:type :mod-obj
:page-id page-id
:id (:id group)
:operations [{:type :set
:attr :masked-group?
:val true}
{:type :set
:attr :selrect
:val (-> shapes first :selrect)}
{:type :set
:attr :points
:val (-> shapes first :points)}
{:type :set
:attr :transform
:val (-> shapes first :transform)}
{:type :set
:attr :transform-inverse
:val (-> shapes first :transform-inverse)}]}
{:type :reg-objects
:page-id page-id
:shapes [(:id group)]}])
uchanges (d/concat-vec
uchanges
(for [child children]
{:type :mod-obj
:page-id page-id
:id (:id child)
:operations [{:type :set
:attr :constraints-h
:val (:constraints-h child)}
{:type :set
:attr :constraints-v
:val (:constraints-v child)}]})
[{:type :mod-obj
:page-id page-id
:id (:id group)
:operations [{:type :set
:attr :masked-group?
:val nil}]}
{:type :reg-objects
:page-id page-id
:shapes [(:id group)]}])]
(rx/of (dch/commit-changes {:redo-changes rchanges
:undo-changes uchanges
:origin it})
(dwc/select-shapes (d/ordered-set (:id group)))))))))) (dwc/select-shapes (d/ordered-set (:id group))))))))))
(def unmask-group (def unmask-group
@ -325,13 +213,18 @@
(let [page-id (:current-page-id state) (let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id) objects (wsh/lookup-page-objects state page-id)
changes-in-bulk (->> (wsh/lookup-selected state) masked-groups (->> (wsh/lookup-selected state)
(map #(get objects %)) (map #(get objects %))
(filter #(or (= :bool (:type %)) (= :group (:type %)))) (filter #(or (= :bool (:type %)) (= :group (:type %)))))
(map #(prepare-remove-mask page-id %)))
rchanges-in-bulk (into [] (mapcat first) changes-in-bulk)
uchanges-in-bulk (into [] (mapcat second) changes-in-bulk)]
(rx/of (dch/commit-changes {:redo-changes rchanges-in-bulk changes (reduce (fn [changes mask]
:undo-changes uchanges-in-bulk (-> changes
:origin it})))))) (pcb/update-shapes [(:id mask)]
(fn [shape]
(dissoc shape :masked-group?)))
(pcb/resize-parents [(:id mask)])))
(-> (pcb/empty-changes it page-id)
(pcb/with-objects objects))
masked-groups)]
(rx/of (dch/commit-changes changes))))))

View file

@ -8,6 +8,7 @@
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.pages.changes-builder :as pcb]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.spec :as us] [app.common.spec :as us]
[app.common.spec.interactions :as csi] [app.common.spec.interactions :as csi]
@ -27,12 +28,8 @@
(ptk/reify ::add-flow (ptk/reify ::add-flow
ptk/WatchEvent ptk/WatchEvent
(watch [it state _] (watch [it state _]
(let [page-id (:current-page-id state) (let [page (wsh/lookup-page state)
flows (get-in state [:workspace-data flows (get-in page [:options :flows] [])
:pages-index
page-id
:options
:flows] [])
unames (into #{} (map :name flows)) unames (into #{} (map :name flows))
name (dwc/generate-unique-name unames "Flow-1") name (dwc/generate-unique-name unames "Flow-1")
@ -42,15 +39,10 @@
:starting-frame starting-frame}] :starting-frame starting-frame}]
(rx/of (dch/commit-changes (rx/of (dch/commit-changes
{:redo-changes [{:type :set-option (-> (pcb/empty-changes it)
:page-id page-id (pcb/with-page page)
:option :flows (pcb/set-page-option :flows
:value (csp/add-flow flows new-flow)}] (csp/add-flow flows new-flow)))))))))
:undo-changes [{:type :set-option
:page-id page-id
:option :flows
:value flows}]
:origin it}))))))
(defn add-flow-selected-frame (defn add-flow-selected-frame
[] []
@ -66,22 +58,13 @@
(ptk/reify ::remove-flow (ptk/reify ::remove-flow
ptk/WatchEvent ptk/WatchEvent
(watch [it state _] (watch [it state _]
(let [page-id (:current-page-id state) (let [page (wsh/lookup-page state)
flows (get-in state [:workspace-data flows (get-in page [:options :flows] [])]
:pages-index
page-id
:options
:flows] [])]
(rx/of (dch/commit-changes (rx/of (dch/commit-changes
{:redo-changes [{:type :set-option (-> (pcb/empty-changes it)
:page-id page-id (pcb/with-page page)
:option :flows (pcb/set-page-option :flows
:value (csp/remove-flow flows flow-id)}] (csp/remove-flow flows flow-id)))))))))
:undo-changes [{:type :set-option
:page-id page-id
:option :flows
:value flows}]
:origin it}))))))
(defn rename-flow (defn rename-flow
[flow-id name] [flow-id name]
@ -90,24 +73,14 @@
(ptk/reify ::rename-flow (ptk/reify ::rename-flow
ptk/WatchEvent ptk/WatchEvent
(watch [it state _] (watch [it state _]
(let [page-id (:current-page-id state) (let [page (wsh/lookup-page state)
flows (get-in state [:workspace-data flows (get-in page [:options :flows] [])]
:pages-index
page-id
:options
:flows] [])]
(rx/of (dch/commit-changes (rx/of (dch/commit-changes
{:redo-changes [{:type :set-option (-> (pcb/empty-changes it)
:page-id page-id (pcb/with-page page)
:option :flows (pcb/set-page-option :flows
:value (csp/update-flow flows flow-id (csp/update-flow flows flow-id
#(csp/rename-flow % name))}] #(csp/rename-flow % name))))))))))
:undo-changes [{:type :set-option
:page-id page-id
:option :flows
:value flows}]
:origin it}))))))
(defn start-rename-flow (defn start-rename-flow
[id] [id]

View file

@ -288,7 +288,7 @@
shapes (dwg/shapes-for-grouping objects selected)] shapes (dwg/shapes-for-grouping objects selected)]
(when-not (empty? shapes) (when-not (empty? shapes)
(let [[group rchanges uchanges] (let [[group rchanges uchanges]
(dwlh/generate-add-component shapes objects page-id file-id)] (dwlh/generate-add-component it shapes objects page-id file-id)]
(when-not (empty? rchanges) (when-not (empty? rchanges)
(rx/of (dch/commit-changes {:redo-changes rchanges (rx/of (dch/commit-changes {:redo-changes rchanges
:undo-changes uchanges :undo-changes uchanges

View file

@ -131,7 +131,7 @@
"If there is exactly one id, and it's a group, use it as root. Otherwise, "If there is exactly one id, and it's a group, use it as root. Otherwise,
create a group that contains all ids. Then, make a component with it, create a group that contains all ids. Then, make a component with it,
and link all shapes to their corresponding one in the component." and link all shapes to their corresponding one in the component."
[shapes objects page-id file-id] [it shapes objects page-id file-id]
(if (and (= (count shapes) 1) (if (and (= (count shapes) 1)
(:component-id (first shapes))) (:component-id (first shapes)))
empty-changes empty-changes
@ -140,7 +140,8 @@
(if (and (= (count shapes) 1) (if (and (= (count shapes) 1)
(= (:type (first shapes)) :group)) (= (:type (first shapes)) :group))
[(first shapes) [] []] [(first shapes) [] []]
(dwg/prepare-create-group objects page-id shapes name true)) (let [[group changes] (dwg/prepare-create-group it objects page-id shapes name true)]
[group (:redo-changes changes) (:undo-changes changes)]))
;; Asserts for documentation purposes ;; Asserts for documentation purposes
_ (us/assert vector? rchanges) _ (us/assert vector? rchanges)

View file

@ -6,7 +6,7 @@
(ns app.main.data.workspace.path.changes (ns app.main.data.workspace.path.changes
(:require (:require
[app.common.pages.helpers :as cph] [app.common.pages.changes-builder :as pcb]
[app.common.spec :as us] [app.common.spec :as us]
[app.main.data.workspace.changes :as dch] [app.main.data.workspace.changes :as dch]
[app.main.data.workspace.path.helpers :as helpers] [app.main.data.workspace.path.helpers :as helpers]
@ -17,70 +17,37 @@
[potok.core :as ptk])) [potok.core :as ptk]))
(defn generate-path-changes (defn generate-path-changes
"Generates content changes and the undos for the content given" "Generates changes to update the new content of the shape"
[objects page-id shape old-content new-content] [it objects page-id shape old-content new-content]
(us/verify ::spec/content old-content) (us/verify ::spec/content old-content)
(us/verify ::spec/content new-content) (us/verify ::spec/content new-content)
(let [shape-id (:id shape) (let [shape-id (:id shape)
frame-id (:frame-id shape)
parent-id (:parent-id shape)
parent-index (cph/get-position-on-parent objects shape-id)
[old-points old-selrect] (helpers/content->points+selrect shape old-content) [new-points new-selrect]
[new-points new-selrect] (helpers/content->points+selrect shape new-content) (helpers/content->points+selrect shape new-content)
rch (cond changes (-> (pcb/empty-changes it page-id)
(pcb/with-objects objects))]
(cond
;; https://tree.taiga.io/project/penpot/issue/2366 ;; https://tree.taiga.io/project/penpot/issue/2366
(nil? shape-id) (nil? shape-id)
[] changes
(empty? new-content) (empty? new-content)
[{:type :del-obj (-> changes
:id shape-id (pcb/remove-objects [shape-id])
:page-id page-id} (pcb/resize-parents [shape-id]))
{:type :reg-objects
:page-id page-id
:shapes [shape-id]}]
:else :else
[{:type :mod-obj (-> changes
:id shape-id (pcb/update-shapes [shape-id]
:page-id page-id (fn [shape]
:operations [{:type :set :attr :content :val new-content} (assoc shape
{:type :set :attr :selrect :val new-selrect} :content new-content
{:type :set :attr :points :val new-points}]} :selrect new-selrect
{:type :reg-objects :points new-points)))
:page-id page-id (pcb/resize-parents [shape-id])))))
:shapes [shape-id]}])
uch (cond
;; https://tree.taiga.io/project/penpot/issue/2366
(nil? shape-id)
[]
(empty? new-content)
[{:type :add-obj
:id shape-id
:obj shape
:page-id page-id
:frame-id frame-id
:parent-id parent-id
:index parent-index}
{:type :reg-objects
:page-id page-id
:shapes [shape-id]}]
:else
[{:type :mod-obj
:id shape-id
:page-id page-id
:operations [{:type :set :attr :content :val old-content}
{:type :set :attr :selrect :val old-selrect}
{:type :set :attr :points :val old-points}]}
{:type :reg-objects
:page-id page-id
:shapes [shape-id]}])]
[rch uch]))
(defn save-path-content (defn save-path-content
([] ([]
@ -105,10 +72,8 @@
old-content (get-in state [:workspace-local :edit-path id :old-content]) old-content (get-in state [:workspace-local :edit-path id :old-content])
shape (st/get-path state)] shape (st/get-path state)]
(if (and (some? old-content) (some? (:id shape))) (if (and (some? old-content) (some? (:id shape)))
(let [[rch uch] (generate-path-changes objects page-id shape old-content (:content shape))] (let [changes (generate-path-changes it objects page-id shape old-content (:content shape))]
(rx/of (dch/commit-changes {:redo-changes rch (rx/of (dch/commit-changes changes)))
:undo-changes uch
:origin it})))
(rx/empty))))))) (rx/empty)))))))

View file

@ -61,15 +61,11 @@
point-change (->> (map hash-map old-points new-points) (reduce merge))] point-change (->> (map hash-map old-points new-points) (reduce merge))]
(when (and (some? new-content) (some? shape)) (when (and (some? new-content) (some? shape))
(let [[rch uch] (changes/generate-path-changes objects page-id shape (:content shape) new-content)] (let [changes (changes/generate-path-changes it objects page-id shape (:content shape) new-content)]
(if (empty? new-content) (if (empty? new-content)
(rx/of (dch/commit-changes {:redo-changes rch (rx/of (dch/commit-changes changes)
:undo-changes uch
:origin it})
dwc/clear-edition-mode) dwc/clear-edition-mode)
(rx/of (dch/commit-changes {:redo-changes rch (rx/of (dch/commit-changes changes)
:undo-changes uch
:origin it})
(selection/update-selection point-change) (selection/update-selection point-change)
(fn [state] (update-in state [:workspace-local :edit-path id] dissoc :content-modifiers :moving-nodes :moving-handler)))))))))) (fn [state] (update-in state [:workspace-local :edit-path id] dissoc :content-modifiers :moving-nodes :moving-handler))))))))))

View file

@ -6,7 +6,7 @@
(ns app.main.data.workspace.path.shapes-to-path (ns app.main.data.workspace.path.shapes-to-path
(:require (:require
[app.common.pages.changes-builder :as cb] [app.common.pages.changes-builder :as pcb]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.path.shapes-to-path :as upsp] [app.common.path.shapes-to-path :as upsp]
[app.main.data.workspace.changes :as dch] [app.main.data.workspace.changes :as dch]
@ -28,9 +28,9 @@
selected) selected)
changes changes
(-> (cb/empty-changes it page-id) (-> (pcb/empty-changes it page-id)
(cb/with-objects objects) (pcb/with-objects objects)
(cb/remove-objects children-ids) (pcb/remove-objects children-ids)
(cb/update-shapes selected #(upsp/convert-to-path % objects)))] (pcb/update-shapes selected #(upsp/convert-to-path % objects)))]
(rx/of (dch/commit-changes changes)))))) (rx/of (dch/commit-changes changes))))))

View file

@ -34,13 +34,11 @@
(when (and (seq points) (some? shape)) (when (and (seq points) (some? shape))
(let [new-content (-> (tool-fn (:content shape) points) (let [new-content (-> (tool-fn (:content shape) points)
(ups/close-subpaths)) (ups/close-subpaths))
[rch uch] (changes/generate-path-changes objects page-id shape (:content shape) new-content)] changes (changes/generate-path-changes it objects page-id shape (:content shape) new-content)]
(rx/concat (rx/concat
(rx/of (dch/update-shapes [id] upsp/convert-to-path)) (rx/of (dch/update-shapes [id] upsp/convert-to-path))
(rx/of (dch/commit-changes {:redo-changes rch (rx/of (dch/commit-changes changes)
:undo-changes uch
:origin it})
(when (empty? new-content) (when (empty? new-content)
dwc/clear-edition-mode)))))))))) dwc/clear-edition-mode))))))))))

View file

@ -407,7 +407,7 @@
changes (-> changes changes (-> changes
(pcb/with-objects objects) (pcb/with-objects objects)
(pcb/add-obj new-shape) (pcb/add-obj new-shape)
(pcb/change-parent parent-id [new-shape])) (pcb/change-parent parent-id [new-shape] index))
unames (conj unames (:name new-shape)) unames (conj unames (:name new-shape))

View file

@ -12,6 +12,7 @@
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.common.math :as mth] [app.common.math :as mth]
[app.common.pages.changes-builder :as pcb]
[app.common.pages.common :as cpc] [app.common.pages.common :as cpc]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.spec :as us] [app.common.spec :as us]
@ -673,26 +674,13 @@
(remove #(or (nil? %) (remove #(or (nil? %)
(= (:frame-id %) frame-id)))) (= (:frame-id %) frame-id))))
rch [{:type :mov-objects changes (-> (pcb/empty-changes it page-id)
:page-id page-id (pcb/with-objects objects)
:parent-id frame-id (pcb/change-parent frame-id moving-shapes))]
:shapes (mapv :id moving-shapes)}]
(when-not (empty? changes)
uch (->> moving-shapes
(reverse)
(mapv (fn [shape]
{:type :mov-objects
:page-id page-id
:parent-id (:parent-id shape)
:index (cph/get-index-in-parent objects (:id shape))
:shapes [(:id shape)]})))]
(when-not (empty? uch)
(rx/of dwu/pop-undo-into-transaction (rx/of dwu/pop-undo-into-transaction
(dch/commit-changes {:redo-changes rch (dch/commit-changes changes)
:undo-changes uch
:origin it})
(dwu/commit-undo-transaction) (dwu/commit-undo-transaction)
(dwc/expand-collapse frame-id))))))) (dwc/expand-collapse frame-id)))))))

View file

@ -12,6 +12,7 @@
[app.main.data.workspace :as dw] [app.main.data.workspace :as dw]
[app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.groups :as dwg] [app.main.data.workspace.groups :as dwg]
[app.main.data.workspace.layout :as layout]
[app.main.data.workspace.libraries-helpers :as dwlh])) [app.main.data.workspace.libraries-helpers :as dwlh]))
;; ---- Helpers to manage pages and objects ;; ---- Helpers to manage pages and objects
@ -21,8 +22,8 @@
(def initial-state (def initial-state
{:current-file-id current-file-id {:current-file-id current-file-id
:current-page-id nil :current-page-id nil
:workspace-global dw/default-workspace-global :workspace-layout layout/default-layout
:workspace-local dw/default-workspace-local :workspace-global layout/default-global
:workspace-data {:id current-file-id :workspace-data {:id current-file-id
:components {} :components {}
:pages [] :pages []
@ -87,12 +88,12 @@
shapes (dwg/shapes-for-grouping (:objects page) ids)] shapes (dwg/shapes-for-grouping (:objects page) ids)]
(if (empty? shapes) (if (empty? shapes)
state state
(let [[group rchanges uchanges] (let [[group changes]
(dwg/prepare-create-group (:objects page) (:id page) shapes prefix true)] (dwg/prepare-create-group nil (:objects page) (:id page) shapes prefix true)]
(swap! idmap assoc label (:id group)) (swap! idmap assoc label (:id group))
(update state :workspace-data (update state :workspace-data
cp/process-changes rchanges)))))) cp/process-changes (:redo-changes changes)))))))
(defn make-component (defn make-component
[state label ids] [state label ids]
@ -101,7 +102,8 @@
shapes (dwg/shapes-for-grouping objects ids) shapes (dwg/shapes-for-grouping objects ids)
[group rchanges uchanges] [group rchanges uchanges]
(dwlh/generate-add-component shapes (dwlh/generate-add-component nil
shapes
(:objects page) (:objects page)
(:id page) (:id page)
current-file-id)] current-file-id)]