Merge pull request #1670 from penpot/more-changes-builder

More changes builder
This commit is contained in:
Andrey Antukh 2022-03-10 16:50:55 +01:00 committed by GitHub
commit 11a0e01f08
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 431 additions and 683 deletions

View file

@ -160,6 +160,7 @@
(dm/export gtr/transform-rect)
(dm/export gtr/calculate-adjust-matrix)
(dm/export gtr/update-group-selrect)
(dm/export gtr/update-mask-selrect)
(dm/export gtr/resize-modifiers)
(dm/export gtr/rotation-modifiers)
(dm/export gtr/merge-modifiers)

View file

@ -318,7 +318,8 @@
(update :width + (:width deltas))
(update :height + (:height deltas)))))))
(defn update-group-selrect [group children]
(defn update-group-selrect
[group children]
(let [shape-center (gco/center-shape group)
;; Points for every shape inside the group
points (->> children (mapcat :points))
@ -346,6 +347,18 @@
(assoc :flip-y false)
(apply-transform (gmt/matrix) true))))
(defn update-mask-selrect
[masked-group children]
(let [mask (first children)]
(-> masked-group
(assoc :selrect (-> mask :selrect))
(assoc :points (-> mask :points))
(assoc :x (-> mask :selrect :x))
(assoc :y (-> mask :selrect :y))
(assoc :width (-> mask :selrect :width))
(assoc :height (-> mask :selrect :height))
(assoc :flip-x (-> mask :flip-x))
(assoc :flip-y (-> mask :flip-y)))))
;; --- Modifiers
@ -600,3 +613,4 @@
(->> shapes
(map (comp gpr/points->selrect :points transform-shape))
(gpr/join-selrects)))

View file

@ -7,7 +7,11 @@
(ns app.common.pages.changes-builder
(:require
[app.common.data :as d]
[app.common.pages.helpers :as cph]))
[app.common.geom.shapes :as gsh]
[app.common.geom.shapes.bool :as gshb]
[app.common.pages :as cp]
[app.common.pages.helpers :as cph]
[app.common.uuid :as uuid]))
;; Auxiliary functions to help create a set of changes (undo + redo)
@ -22,6 +26,10 @@
:undo-changes []
:origin origin}))
(defn set-save-undo?
[changes save-undo?]
(assoc changes :save-undo? save-undo?))
(defn with-page [changes page]
(vary-meta changes assoc
::page page
@ -29,7 +37,10 @@
::objects (:objects page)))
(defn with-objects [changes objects]
(vary-meta changes assoc ::objects objects))
(let [file-data (-> (cp/make-file-data (uuid/next) uuid/zero)
(assoc-in [:pages-index uuid/zero :objects] objects))]
(vary-meta changes assoc ::file-data file-data
::applied-changes-count 0)))
(defn amend-last-change
"Modify the last redo-changes added with an update function."
@ -52,7 +63,21 @@
(defn- assert-objects
[changes]
(assert (contains? (meta changes) ::objects) "Call (with-objects) before using this function"))
(assert (contains? (meta changes) ::file-data) "Call (with-objects) before using this function"))
(defn- apply-changes-local
[changes]
(if-let [file-data (::file-data (meta changes))]
(let [index (::applied-changes-count (meta changes))
redo-changes (:redo-changes changes)
new-changes (if (< index (count redo-changes))
(->> (subvec (:redo-changes changes) index)
(map #(assoc % :page-id uuid/zero)))
[])
new-file-data (cp/process-changes file-data new-changes)]
(vary-meta changes assoc ::file-data new-file-data
::applied-changes-count (count redo-changes)))
changes))
;; Page changes
@ -60,31 +85,36 @@
[changes id name]
(-> changes
(update :redo-changes conj {:type :add-page :id id :name name})
(update :undo-changes conj {:type :del-page :id id})))
(update :undo-changes conj {:type :del-page :id id})
(apply-changes-local)))
(defn add-page
[changes id page]
(-> changes
(update :redo-changes conj {:type :add-page :id id :page page})
(update :undo-changes conj {:type :del-page :id id})))
(update :undo-changes conj {:type :del-page :id id})
(apply-changes-local)))
(defn mod-page
[changes page new-name]
(-> changes
(update :redo-changes conj {:type :mod-page :id (:id page) :name new-name})
(update :undo-changes conj {:type :mod-page :id (:id page) :name (:name page)})))
(update :undo-changes conj {:type :mod-page :id (:id page) :name (:name page)})
(apply-changes-local)))
(defn del-page
[changes page]
(-> changes
(update :redo-changes conj {:type :del-page :id (:id page)})
(update :undo-changes conj {:type :add-page :id (:id page) :page page})))
(update :undo-changes conj {:type :add-page :id (:id page) :page page})
(apply-changes-local)))
(defn move-page
[changes page-id index prev-index]
(-> changes
(update :redo-changes conj {:type :mov-page :id page-id :index index})
(update :undo-changes conj {:type :mov-page :id page-id :index prev-index})))
(update :undo-changes conj {:type :mov-page :id page-id :index prev-index})
(apply-changes-local)))
(defn set-page-option
[changes option-key option-val]
@ -101,7 +131,27 @@
(update :undo-changes conj {:type :set-option
:page-id page-id
:option option-key
:value old-val}))))
:value old-val})
(apply-changes-local))))
(defn update-page-option
[changes option-key update-fn & args]
(assert-page changes)
(let [page-id (::page-id (meta changes))
page (::page (meta changes))
old-val (get-in page [:options option-key])
new-val (apply update-fn old-val args)]
(-> changes
(update :redo-changes conj {:type :set-option
:page-id page-id
:option option-key
:value new-val})
(update :undo-changes conj {:type :set-option
:page-id page-id
:option option-key
:value old-val})
(apply-changes-local))))
;; Shape tree changes
@ -132,7 +182,8 @@
(-> changes
(update :redo-changes conj add-change)
(update :undo-changes d/preconj del-change)))))
(update :undo-changes d/preconj del-change)
(apply-changes-local)))))
(defn change-parent
([changes parent-id shapes]
@ -141,7 +192,8 @@
([changes parent-id shapes index]
(assert-page-id changes)
(assert-objects changes)
(let [objects (::objects (meta changes))
(let [objects (get-in (meta changes) [::file-data :pages-index uuid/zero :objects])
set-parent-change
(cond-> {:type :mov-objects
:parent-id parent-id
@ -163,7 +215,8 @@
(-> changes
(update :redo-changes conj set-parent-change)
(update :undo-changes #(reduce mk-undo-change % shapes))))))
(update :undo-changes #(reduce mk-undo-change % shapes))
(apply-changes-local)))))
(defn update-shapes
"Calculate the changes and undos to be done when a function is applied to a
@ -174,15 +227,15 @@
([changes ids update-fn {:keys [attrs ignore-geometry?] :or {attrs nil ignore-geometry? false}}]
(assert-page-id changes)
(assert-objects changes)
(let [objects (::objects (meta changes))
(let [objects (get-in (meta changes) [::file-data :pages-index uuid/zero :objects])
generate-operation
(fn [changes attr old new ignore-geometry?]
(fn [operations attr old new ignore-geometry?]
(let [old-val (get old attr)
new-val (get new attr)]
(if (= old-val new-val)
changes
(-> changes
operations
(-> operations
(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})))))
@ -213,14 +266,15 @@
(seq uops)
(update :undo-changes d/preconj (assoc change :operations uops)))))]
(reduce update-shape changes ids))))
(-> (reduce update-shape changes ids)
(apply-changes-local)))))
(defn remove-objects
[changes ids]
(assert-page-id changes)
(assert-objects changes)
(let [page-id (::page-id (meta changes))
objects (::objects (meta changes))
objects (get-in (meta changes) [::file-data :pages-index uuid/zero :objects])
add-redo-change
(fn [change-set id]
@ -235,11 +289,11 @@
(d/preconj
change-set
{:type :add-obj
:id id
:page-id page-id
:parent-id (:frame-id shape)
:frame-id (:frame-id shape)
:id id
:index (cph/get-position-on-parent objects (:id shape))
:index (cph/get-position-on-parent objects id)
:obj (cond-> shape
(contains? shape :shapes)
(assoc :shapes []))})))
@ -260,14 +314,63 @@
(update :redo-changes #(reduce add-redo-change % ids))
(update :undo-changes #(as-> % $
(reduce add-undo-change-parent $ ids)
(reduce add-undo-change-shape $ ids))))))
(reduce add-undo-change-shape $ ids)))
(apply-changes-local))))
(defn resize-parents
[changes ids]
(assert-page-id changes)
(assert-objects changes)
(let [page-id (::page-id (meta changes))
shapes (vec ids)]
(-> changes
(update :redo-changes conj {:type :reg-objects :page-id page-id :shapes shapes})
(update :undo-changes conj {:type :reg-objects :page-id page-id :shapes shapes}))))
objects (get-in (meta changes) [::file-data :pages-index uuid/zero :objects])
xform (comp
(mapcat #(cons % (cph/get-parent-ids objects %)))
(map (d/getf objects))
(filter #(contains? #{:group :bool} (:type %)))
(distinct))
all-parents (sequence xform ids)
generate-operation
(fn [operations attr old new]
(let [old-val (get old attr)
new-val (get new attr)]
(if (= old-val new-val)
operations
(-> operations
(update :rops conj {:type :set :attr attr :val new-val :ignore-touched true})
(update :uops conj {:type :set :attr attr :val old-val :ignore-touched true})))))
resize-parent
(fn [changes parent]
(let [children (->> parent :shapes (map (d/getf objects)))
resized-parent (cond
(empty? children)
changes
(= (:type parent) :bool)
(gshb/update-bool-selrect parent children objects)
(= (:type parent) :group)
(if (:masked-group? parent)
(gsh/update-mask-selrect parent children)
(gsh/update-group-selrect parent children)))
{rops :rops uops :uops}
(reduce #(generate-operation %1 %2 parent resized-parent)
{:rops [] :uops []}
(keys parent))
change {:type :mod-obj
:page-id page-id
:id (:id parent)}]
(if (seq rops)
(-> changes
(update :redo-changes conj (assoc change :operations rops))
(update :undo-changes conj (assoc change :operations uops)))
changes)))]
(-> (reduce resize-parent changes all-parents)
(apply-changes-local))))

View file

@ -194,15 +194,6 @@
(conj done (:id 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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View file

@ -14,7 +14,7 @@
"scripts": {
"compile-test": "clojure -M:dev:shadow-cljs compile test --config-merge '{:autorun false}'",
"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",
"watch-gulp": "gulp watch",
"watch-main": "shadow-cljs watch main",

View file

@ -1526,9 +1526,8 @@
(pcb/amend-changes (partial process-rchange media-idx))
(pcb/amend-changes (partial change-add-obj-index paste-objects selected index)))
;; Adds a reg-objects operation so the groups are updated. We add all the new objects
;; Adds a resize-parents operation so the groups are updated. We add all the new objects
new-objects-ids (->> changes :redo-changes (filter #(= (:type %) :add-obj)) (mapv :id))
changes (pcb/resize-parents changes new-objects-ids)
selected (->> changes

View file

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

View file

@ -6,9 +6,9 @@
(ns app.main.data.workspace.changes
(:require
[app.common.data :as d]
[app.common.logging :as log]
[app.common.pages :as cp]
[app.common.pages.changes-builder :as pcb]
[app.common.spec :as us]
[app.common.spec.change :as spec.change]
[app.main.data.workspace.state-helpers :as wsh]
@ -31,78 +31,38 @@
(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
([ids f] (update-shapes ids f nil nil))
([ids f keys] (update-shapes ids f nil keys))
([ids f page-id {:keys [reg-objects? save-undo? attrs ignore-tree]
:or {reg-objects? false save-undo? true attrs nil}}]
([ids update-fn] (update-shapes ids update-fn nil nil))
([ids update-fn keys] (update-shapes ids update-fn nil keys))
([ids update-fn page-id {:keys [reg-objects? save-undo? attrs ignore-tree]
:or {reg-objects? false save-undo? true attrs nil}}]
(us/assert ::coll-of-uuid ids)
(us/assert fn? f)
(us/assert fn? update-fn)
(ptk/reify ::update-shapes
ptk/WatchEvent
(watch [it state _]
(let [page-id (or page-id (:current-page-id state))
objects (wsh/lookup-page-objects state page-id)
changes {:redo-changes []
:undo-changes []
:origin it
:save-undo? save-undo?}
objects (wsh/lookup-page-objects state)
ids (into [] (filter some?) ids)
changes (reduce
#(update-shape-changes %1 page-id objects f attrs %2 (get ignore-tree %2))
changes ids)]
(fn [changes id]
(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))
(let [reg-objs {:type :reg-objects
:page-id page-id
:shapes ids}
changes (cond-> changes
(when (seq (:redo-changes changes))
(let [changes (cond-> changes
reg-objects?
(-> (update :redo-changes conj reg-objs)
(update :undo-changes conj reg-objs)))]
(pcb/resize-parents ids))]
(rx/of (commit-changes changes)))))))))
(defn update-indices
@ -125,6 +85,7 @@
(ptk/reify ::commit-changes
cljs.core/IDeref
(-deref [_]
{:file-id file-id
:hint-events @st/last-events
:hint-origin (ptk/type origin)

View file

@ -11,6 +11,7 @@
[app.common.geom.shapes :as gsh]
[app.common.logging :as log]
[app.common.pages :as cp]
[app.common.pages.changes-builder :as pcb]
[app.common.pages.helpers :as cph]
[app.common.spec :as us]
[app.common.spec.interactions :as csi]
@ -280,40 +281,25 @@
{:keys [frame-id parent-id]} shape]
[frame-id parent-id (inc index)])))))
(defn add-shape-changes
([page-id objects selected attrs]
(add-shape-changes page-id objects selected attrs true))
([page-id objects selected attrs reg-object?]
(let [id (:id attrs)
shape (gpr/setup-proportions attrs)
(defn make-new-shape
[attrs objects selected]
(let [default-attrs (if (= :frame (:type attrs))
cp/default-frame-attrs
cp/default-shape-attrs)
default-attrs (if (= :frame (:type shape))
cp/default-frame-attrs
cp/default-shape-attrs)
selected-non-frames
(into #{} (comp (map (d/getf objects))
(remove cph/frame-shape?))
selected)
shape (merge default-attrs shape)
[frame-id parent-id index]
(get-shape-layer-position objects selected-non-frames attrs)]
not-frame? #(not (= :frame (get-in objects [% :type])))
selected (into #{} (filter not-frame?) selected)
[frame-id parent-id index] (get-shape-layer-position objects selected attrs)
redo-changes (cond-> [{:type :add-obj
:id id
:page-id page-id
:frame-id frame-id
:parent-id parent-id
:index index
:obj shape}]
reg-object?
(conj {:type :reg-objects
:page-id page-id
:shapes [id]}))
undo-changes [{:type :del-obj
:page-id page-id
:id id}]]
[redo-changes undo-changes])))
(-> (merge default-attrs attrs)
(gpr/setup-proportions)
(assoc :frame-id frame-id
:parent-id parent-id
:index index))))
(defn add-shape
([attrs]
@ -326,26 +312,23 @@
(watch [it state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
id (or (:id attrs) (uuid/next))
name (-> objects
(retrieve-used-names)
(generate-unique-name (:name attrs)))
selected (wsh/lookup-selected state)
[rchanges uchanges] (add-shape-changes
page-id
objects
selected
(-> attrs
(assoc :id id )
(assoc :name name)))]
id (or (:id attrs) (uuid/next))
name (-> objects
(retrieve-used-names)
(generate-unique-name (:name attrs)))
shape (make-new-shape
(assoc attrs :id id :name name)
objects
selected)
changes (-> (pcb/empty-changes it page-id)
(pcb/add-obj shape))]
(rx/concat
(rx/of (dch/commit-changes {:redo-changes rchanges
:undo-changes uchanges
:origin it})
(rx/of (dch/commit-changes changes)
(when-not no-select?
(select-shapes (d/ordered-set id))))
(when (= :text (:type attrs))
@ -361,28 +344,15 @@
to-move-shapes (->> (cph/get-immediate-children objects)
(remove cph/frame-shape?)
(mapv :id)
(d/enumerate)
(filterv (comp shapes second)))
(filterv (comp shapes :id second))
(mapv second))
rchanges [{:type :mov-objects
:parent-id frame-id
:frame-id frame-id
:page-id page-id
:index 0
:shapes (mapv second to-move-shapes)}]
changes (-> (pcb/empty-changes it page-id)
(pcb/with-objects objects)
(pcb/change-parent frame-id to-move-shapes 0))]
uchanges (->> to-move-shapes
(mapv (fn [[index shape-id]]
{:type :mov-objects
:parent-id uuid/zero
:frame-id uuid/zero
:page-id page-id
:index index
:shapes [shape-id]})))]
(rx/of (dch/commit-changes {:redo-changes rchanges
:undo-changes uchanges
:origin it}))))))
(rx/of (dch/commit-changes changes))))))
(s/def ::set-of-uuid
(s/every ::us/uuid :kind set?))
@ -395,10 +365,9 @@
(watch [it state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
options (wsh/lookup-page-options state page-id)
page (wsh/lookup-page state page-id)
ids (cph/clean-loops objects ids)
flows (:flows options)
groups-to-unmask
(reduce (fn [group-ids id]
@ -416,6 +385,8 @@
interacting-shapes
(filter (fn [shape]
;; If any of the deleted shapes is the destination of
;; some interaction, this must be deleted, too.
(let [interactions (:interactions shape)]
(some #(and (csi/has-destination %)
(contains? ids (:destination %)))
@ -423,7 +394,26 @@
(vals objects))
starting-flows
(filter #(contains? ids (:starting-frame %)) flows)
(filter (fn [flow]
;; If any of the deleted is a frame that starts a flow,
;; this must be deleted, too.
(contains? ids (:starting-frame flow)))
(-> page :options :flows))
all-parents
(reduce (fn [res id]
;; All parents of any deleted shape must be resized.
(into res (cph/get-parent-ids objects id)))
(d/ordered-set)
ids)
all-children
(->> ids ;; Children of deleted shapes must be also deleted.
(reduce (fn [res id]
(into res (cph/get-children-ids objects id)))
[])
(reverse)
(into (d/ordered-set)))
empty-parents-xform
(comp
@ -435,142 +425,36 @@
(take-while some?)
(map :id))
all-parents
(reduce (fn [res id]
(into res (cph/get-parent-ids objects id)))
(d/ordered-set)
ids)
all-children
(->> ids
(reduce (fn [res id]
(into res (cph/get-children-ids objects id)))
[])
(reverse)
(into (d/ordered-set)))
empty-parents
;; Any parent whose children are all deleted, must be deleted too.
(into (d/ordered-set) empty-parents-xform all-parents)
mk-del-obj-xf
(comp (filter (partial contains? objects))
(map (fn [id]
{:type :del-obj
:page-id page-id
:id id})))
changes (-> (pcb/empty-changes it page-id)
(pcb/with-page page)
(pcb/with-objects objects)
(pcb/remove-objects all-children)
(pcb/remove-objects ids)
(pcb/remove-objects empty-parents)
(pcb/resize-parents all-parents)
(pcb/update-shapes groups-to-unmask
(fn [shape]
(assoc shape :masked-group? false)))
(pcb/update-shapes (map :id interacting-shapes)
(fn [shape]
(update shape :interactions
(fn [interactions]
(when interactions
(d/removev #(and (csi/has-destination %)
(contains? ids (:destination %)))
interactions))))))
(cond->
(seq starting-flows)
(pcb/update-page-option :flows (fn [flows]
(reduce #(csp/remove-flow %1 (:id %2))
flows
starting-flows)))))]
mk-add-obj-xf
(comp (filter (partial contains? objects))
(map (fn [id]
(let [item (get objects id)]
{:type :add-obj
:id (:id item)
:page-id page-id
:index (cph/get-position-on-parent objects id)
:frame-id (:frame-id item)
:parent-id (:parent-id item)
:obj item}))))
mk-mod-touched-xf
(comp (filter (partial contains? objects))
(map (fn [id]
(let [parent (get objects id)]
{:type :mod-obj
:page-id page-id
:id (:id parent)
:operations [{:type :set-touched
:touched (:touched parent)}]}))))
mk-mod-int-del-xf
(comp (filter some?)
(map (fn [obj]
{:type :mod-obj
:page-id page-id
:id (:id obj)
:operations [{:type :set
:attr :interactions
:val (vec (remove (fn [interaction]
(and (csi/has-destination interaction)
(contains? ids (:destination interaction))))
(:interactions obj)))}]})))
mk-mod-int-add-xf
(comp (filter some?)
(map (fn [obj]
{:type :mod-obj
:page-id page-id
:id (:id obj)
:operations [{:type :set
:attr :interactions
:val (:interactions obj)}]})))
mk-mod-del-flow-xf
(comp (filter some?)
(map (fn [flow]
{:type :set-option
:page-id page-id
:option :flows
:value (csp/remove-flow flows (:id flow))})))
mk-mod-add-flow-xf
(comp (filter some?)
(map (fn [_]
{:type :set-option
:page-id page-id
:option :flows
:value flows})))
mk-mod-unmask-xf
(comp (filter (partial contains? objects))
(map (fn [id]
{:type :mod-obj
:page-id page-id
:id id
:operations [{:type :set
:attr :masked-group?
:val false}]})))
mk-mod-mask-xf
(comp (filter (partial contains? objects))
(map (fn [id]
{:type :mod-obj
:page-id page-id
:id id
:operations [{:type :set
:attr :masked-group?
:val true}]})))
rchanges
(-> []
(into mk-del-obj-xf all-children)
(into mk-del-obj-xf ids)
(into mk-del-obj-xf empty-parents)
(conj {:type :reg-objects
:page-id page-id
:shapes (vec all-parents)})
(into mk-mod-unmask-xf groups-to-unmask)
(into mk-mod-int-del-xf interacting-shapes)
(into mk-mod-del-flow-xf starting-flows))
uchanges
(-> []
(into mk-add-obj-xf (reverse empty-parents))
(into mk-add-obj-xf (reverse ids))
(into mk-add-obj-xf (reverse all-children))
(conj {:type :reg-objects
:page-id page-id
:shapes (vec all-parents)})
(into mk-mod-touched-xf (reverse all-parents))
(into mk-mod-mask-xf groups-to-unmask)
(into mk-mod-int-add-xf interacting-shapes)
(into mk-mod-add-flow-xf starting-flows))]
;; (println "================ rchanges")
;; (cljs.pprint/pprint rchanges)
;; (println "================ uchanges")
;; (cljs.pprint/pprint uchanges)
(rx/of (dch/commit-changes {:redo-changes rchanges
:undo-changes uchanges
:origin it}))))))
(rx/of (dch/commit-changes changes))))))
;; --- Add shape to Workspace

View file

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

View file

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

@ -28,14 +28,11 @@
(ptk/reify ::update-guides
ptk/WatchEvent
(watch [it state _]
(let [page (wsh/lookup-page state)
guides (get-in page [:options :guides] {})
new-guides (assoc guides (:id guide) guide)
(let [page (wsh/lookup-page state)
changes
(-> (pcb/empty-changes it)
(pcb/with-page page)
(pcb/set-page-option :guides new-guides))]
(pcb/update-page-option :guides assoc (:id guide) guide))]
(rx/of (dwc/commit-changes changes))))))
(defn remove-guide [guide]
@ -49,14 +46,11 @@
ptk/WatchEvent
(watch [it state _]
(let [page (wsh/lookup-page state)
guides (get-in page [:options :guides] {})
new-guides (dissoc guides (:id guide))
(let [page (wsh/lookup-page state)
changes
(-> (pcb/empty-changes it)
(pcb/with-page page)
(pcb/set-page-option :guides new-guides))]
(pcb/update-page-option :guides dissoc (:id guide)))]
(rx/of (dwc/commit-changes changes))))))
(defn remove-guides

View file

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

View file

@ -288,7 +288,7 @@
shapes (dwg/shapes-for-grouping objects selected)]
(when-not (empty? shapes)
(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)
(rx/of (dch/commit-changes {:redo-changes rchanges
: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,
create a group that contains all ids. Then, make a component with it,
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)
(:component-id (first shapes)))
empty-changes
@ -140,7 +140,8 @@
(if (and (= (count shapes) 1)
(= (:type (first shapes)) :group))
[(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
_ (us/assert vector? rchanges)

View file

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

View file

@ -61,15 +61,11 @@
point-change (->> (map hash-map old-points new-points) (reduce merge))]
(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)
(rx/of (dch/commit-changes {:redo-changes rch
:undo-changes uch
:origin it})
(rx/of (dch/commit-changes changes)
dwc/clear-edition-mode)
(rx/of (dch/commit-changes {:redo-changes rch
:undo-changes uch
:origin it})
(rx/of (dch/commit-changes changes)
(selection/update-selection point-change)
(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
(:require
[app.common.pages.changes-builder :as cb]
[app.common.pages.changes-builder :as pcb]
[app.common.pages.helpers :as cph]
[app.common.path.shapes-to-path :as upsp]
[app.main.data.workspace.changes :as dch]
@ -28,9 +28,9 @@
selected)
changes
(-> (cb/empty-changes it page-id)
(cb/with-objects objects)
(cb/remove-objects children-ids)
(cb/update-shapes selected #(upsp/convert-to-path % objects)))]
(-> (pcb/empty-changes it page-id)
(pcb/with-objects objects)
(pcb/remove-objects children-ids)
(pcb/update-shapes selected #(upsp/convert-to-path % objects)))]
(rx/of (dch/commit-changes changes))))))

View file

@ -34,13 +34,11 @@
(when (and (seq points) (some? shape))
(let [new-content (-> (tool-fn (:content shape) points)
(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/of (dch/update-shapes [id] upsp/convert-to-path))
(rx/of (dch/commit-changes {:redo-changes rch
:undo-changes uch
:origin it})
(rx/of (dch/commit-changes changes)
(when (empty? new-content)
dwc/clear-edition-mode))))))))))

View file

@ -376,17 +376,18 @@
(filter #(= (:type %) :frame))
(filter #(some? (ctp/get-frame-flow flows (:id %)))))]
(if-not (empty? frames-with-flow)
(let [new-flows (reduce
(fn [flows frame]
(let [name (dwc/generate-unique-name @unames "Flow-1")
_ (vswap! unames conj name)
new-flow {:id (uuid/next)
:name name
:starting-frame (get ids-map (:id frame))}]
(ctp/add-flow flows new-flow)))
flows
frames-with-flow)]
(pcb/set-page-option changes :flows new-flows))
(let [update-flows (fn [flows]
(reduce
(fn [flows frame]
(let [name (dwc/generate-unique-name @unames "Flow-1")
_ (vswap! unames conj name)
new-flow {:id (uuid/next)
:name name
:starting-frame (get ids-map (:id frame))}]
(ctp/add-flow flows new-flow)))
flows
frames-with-flow))]
(pcb/update-page-option changes :flows update-flows))
changes)))
(defn duplicate-changes-update-indices

View file

@ -12,6 +12,7 @@
[app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh]
[app.common.math :as mth]
[app.common.pages.changes-builder :as pcb]
[app.common.pages.helpers :as cph]
[app.common.spec :refer [max-safe-int min-safe-int]]
[app.common.uuid :as uuid]
@ -397,32 +398,23 @@
(mapv #(usvg/inherit-attributes attrs %)))]
[shape children]))))
(defn add-svg-child-changes [page-id objects selected frame-id parent-id svg-data [unames [rchs uchs]] [index data]]
(defn add-svg-child-changes [page-id objects selected frame-id parent-id svg-data [unames changes] [index data]]
(let [[shape children] (parse-svg-element frame-id svg-data data unames)]
(if (some? shape)
(let [shape-id (:id shape)
[rch1 uch1] (dwc/add-shape-changes page-id objects selected shape false)
new-shape (dwc/make-new-shape shape objects selected)
changes (-> changes
(pcb/with-objects objects)
(pcb/add-obj new-shape)
(pcb/change-parent parent-id [new-shape] index))
;; Mov-objects won't have undo because we "delete" the object in the undo of the
;; previous operation
rch2 [{:type :mov-objects
:parent-id parent-id
:frame-id frame-id
:page-id page-id
:index index
:shapes [shape-id]}]
;; Careful! the undo changes are concatenated reversed (we undo in reverse order
changes [(d/concat-vec rchs rch1 rch2)
(d/concat-vec uch1 uchs)]
unames (conj unames (:name shape))
unames (conj unames (:name new-shape))
reducer-fn (partial add-svg-child-changes page-id objects selected frame-id shape-id svg-data)]
(reduce reducer-fn [unames changes] (d/enumerate children)))
;; Cannot create the data from current tags
[unames [rchs uchs]])))
[unames changes])))
(declare create-svg-shapes)
@ -493,27 +485,29 @@
root-id (:id root-shape)
;; Creates the root shape
changes (dwc/add-shape-changes page-id objects selected root-shape false)
new-shape (dwc/make-new-shape root-shape objects selected)
changes (-> (pcb/empty-changes it page-id)
(pcb/add-obj new-shape))
root-attrs (-> (:attrs svg-data)
(usvg/format-styles))
;; Reduces the children to create the changes to add the children shapes
[_ [rchanges uchanges]]
;; Reduce the children to create the changes to add the children shapes
[_ changes]
(reduce (partial add-svg-child-changes page-id objects selected frame-id root-id svg-data)
[unames changes]
(d/enumerate (->> (:content svg-data)
(mapv #(usvg/inherit-attributes root-attrs %)))))
reg-objects-action {:type :reg-objects
:page-id page-id
:shapes (->> rchanges (filter #(= :add-obj (:type %))) (map :id) reverse vec)}
changes (pcb/resize-parents changes
(->> changes
:redo-changes
(filter #(= :add-obj (:type %)))
(map :id)
reverse
vec))]
rchanges (conj rchanges reg-objects-action)]
(rx/of (dch/commit-changes {:redo-changes rchanges
:undo-changes uchanges
:origin it})
(rx/of (dch/commit-changes changes)
(dwc/select-shapes (d/ordered-set root-id))))
(catch :default e

View file

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

View file

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