0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-02-13 18:48:37 -05:00

🔧 Use changes-builder in workspace common operations

This commit is contained in:
Andrés Moya 2022-02-25 14:48:03 +01:00
parent 8ed857b4b9
commit a7b455fb9a
3 changed files with 107 additions and 230 deletions

View file

@ -270,7 +270,7 @@
:parent-id (:frame-id shape) :parent-id (:frame-id shape)
:frame-id (:frame-id shape) :frame-id (:frame-id shape)
:id id :id id
:index (cph/get-position-on-parent objects (:id shape)) :index (cph/get-position-on-parent objects id)
:obj (cond-> shape :obj (cond-> shape
(contains? shape :shapes) (contains? shape :shapes)
(assoc :shapes []))}))) (assoc :shapes []))})))

View file

@ -11,6 +11,7 @@
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[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.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]
@ -280,40 +281,23 @@
{:keys [frame-id parent-id]} shape] {:keys [frame-id parent-id]} shape]
[frame-id parent-id (inc index)]))))) [frame-id parent-id (inc index)])))))
(defn add-shape-changes (defn make-new-shape
([page-id objects selected attrs] [attrs objects selected]
(add-shape-changes page-id objects selected attrs true)) (let [default-attrs (if (= :frame (:type attrs))
([page-id objects selected attrs reg-object?]
(let [id (:id attrs)
shape (gpr/setup-proportions attrs)
default-attrs (if (= :frame (:type shape))
cp/default-frame-attrs cp/default-frame-attrs
cp/default-shape-attrs) cp/default-shape-attrs)
shape (merge default-attrs shape) selected-non-frames
(into #{} (filter #(not= (:type (get objects %)) :frame) selected))
not-frame? #(not (= :frame (get-in objects [% :type]))) [frame-id parent-id index]
selected (into #{} (filter not-frame?) selected) (get-shape-layer-position objects selected-non-frames attrs)]
[frame-id parent-id index] (get-shape-layer-position objects selected attrs) (-> (merge default-attrs attrs)
(gpr/setup-proportions)
redo-changes (cond-> [{:type :add-obj (assoc :frame-id frame-id
:id id
:page-id page-id
:frame-id frame-id
:parent-id parent-id :parent-id parent-id
:index index :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])))
(defn add-shape (defn add-shape
([attrs] ([attrs]
@ -326,26 +310,23 @@
(watch [it state _] (watch [it state _]
(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)
selected (wsh/lookup-selected state)
id (or (:id attrs) (uuid/next)) id (or (:id attrs) (uuid/next))
name (-> objects name (-> objects
(retrieve-used-names) (retrieve-used-names)
(generate-unique-name (:name attrs))) (generate-unique-name (:name attrs)))
selected (wsh/lookup-selected state) shape (make-new-shape
(assoc attrs :id id :name name)
[rchanges uchanges] (add-shape-changes
page-id
objects objects
selected selected)
(-> attrs
(assoc :id id ) changes (-> (pcb/empty-changes it page-id)
(assoc :name name)))] (pcb/add-obj shape))]
(rx/concat (rx/concat
(rx/of (dch/commit-changes {:redo-changes rchanges (rx/of (dch/commit-changes changes)
:undo-changes uchanges
:origin it})
(when-not no-select? (when-not no-select?
(select-shapes (d/ordered-set id)))) (select-shapes (d/ordered-set id))))
(when (= :text (:type attrs)) (when (= :text (:type attrs))
@ -361,28 +342,15 @@
to-move-shapes (->> (cph/get-immediate-children objects) to-move-shapes (->> (cph/get-immediate-children objects)
(remove cph/frame-shape?) (remove cph/frame-shape?)
(mapv :id)
(d/enumerate) (d/enumerate)
(filterv (comp shapes second))) (filterv (comp shapes :id second))
(mapv second))
rchanges [{:type :mov-objects changes (-> (pcb/empty-changes it page-id)
:parent-id frame-id (pcb/with-objects objects)
:frame-id frame-id (pcb/change-parent frame-id to-move-shapes 0))]
:page-id page-id
:index 0
:shapes (mapv second to-move-shapes)}]
uchanges (->> to-move-shapes (rx/of (dch/commit-changes changes))))))
(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}))))))
(s/def ::set-of-uuid (s/def ::set-of-uuid
(s/every ::us/uuid :kind set?)) (s/every ::us/uuid :kind set?))
@ -395,10 +363,10 @@
(watch [it state _] (watch [it state _]
(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)
options (wsh/lookup-page-options state page-id) page (wsh/lookup-page state page-id)
flows (-> page :options :flows)
ids (cph/clean-loops objects ids) ids (cph/clean-loops objects ids)
flows (:flows options)
groups-to-unmask groups-to-unmask
(reduce (fn [group-ids id] (reduce (fn [group-ids id]
@ -416,6 +384,8 @@
interacting-shapes interacting-shapes
(filter (fn [shape] (filter (fn [shape]
;; If any of the deleted shapes is the destination of
;; some interaction, this must be deleted, too.
(let [interactions (:interactions shape)] (let [interactions (:interactions shape)]
(some #(and (csi/has-destination %) (some #(and (csi/has-destination %)
(contains? ids (:destination %))) (contains? ids (:destination %)))
@ -423,7 +393,26 @@
(vals objects)) (vals objects))
starting-flows 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)))
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 empty-parents-xform
(comp (comp
@ -435,142 +424,36 @@
(take-while some?) (take-while some?)
(map :id)) (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 empty-parents
;; Any parent whose children are all deleted, must be deleted too.
(into (d/ordered-set) empty-parents-xform all-parents) (into (d/ordered-set) empty-parents-xform all-parents)
mk-del-obj-xf changes (-> (pcb/empty-changes it page-id)
(comp (filter (partial contains? objects)) (pcb/with-page page)
(map (fn [id] (pcb/with-objects objects)
{:type :del-obj (pcb/remove-objects all-children)
:page-id page-id (pcb/remove-objects ids)
:id id}))) (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/set-page-option :flows
(reduce #(csp/remove-flow %1 (:id %2))
flows
starting-flows))))]
mk-add-obj-xf (rx/of (dch/commit-changes changes))))))
(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}))))))
;; --- Add shape to Workspace ;; --- Add shape to Workspace

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.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.spec :refer [max-safe-int min-safe-int]] [app.common.spec :refer [max-safe-int min-safe-int]]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
@ -397,32 +398,23 @@
(mapv #(usvg/inherit-attributes attrs %)))] (mapv #(usvg/inherit-attributes attrs %)))]
[shape children])))) [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)] (let [[shape children] (parse-svg-element frame-id svg-data data unames)]
(if (some? shape) (if (some? shape)
(let [shape-id (:id 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]))
;; Mov-objects won't have undo because we "delete" the object in the undo of the unames (conj unames (:name new-shape))
;; 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))
reducer-fn (partial add-svg-child-changes page-id objects selected frame-id shape-id svg-data)] 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))) (reduce reducer-fn [unames changes] (d/enumerate children)))
;; Cannot create the data from current tags [unames changes])))
[unames [rchs uchs]])))
(declare create-svg-shapes) (declare create-svg-shapes)
@ -493,27 +485,29 @@
root-id (:id root-shape) root-id (:id root-shape)
;; Creates the 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) root-attrs (-> (:attrs svg-data)
(usvg/format-styles)) (usvg/format-styles))
;; Reduces the children to create the changes to add the children shapes ;; Reduce the children to create the changes to add the children shapes
[_ [rchanges uchanges]] [_ changes]
(reduce (partial add-svg-child-changes page-id objects selected frame-id root-id svg-data) (reduce (partial add-svg-child-changes page-id objects selected frame-id root-id svg-data)
[unames changes] [unames changes]
(d/enumerate (->> (:content svg-data) (d/enumerate (->> (:content svg-data)
(mapv #(usvg/inherit-attributes root-attrs %))))) (mapv #(usvg/inherit-attributes root-attrs %)))))
reg-objects-action {:type :reg-objects changes (pcb/resize-parents changes
:page-id page-id (->> changes
:shapes (->> rchanges (filter #(= :add-obj (:type %))) (map :id) reverse vec)} :redo-changes
(filter #(= :add-obj (:type %)))
(map :id)
reverse
vec))]
rchanges (conj rchanges reg-objects-action)] (rx/of (dch/commit-changes changes)
(rx/of (dch/commit-changes {:redo-changes rchanges
:undo-changes uchanges
:origin it})
(dwc/select-shapes (d/ordered-set root-id)))) (dwc/select-shapes (d/ordered-set root-id))))
(catch :default e (catch :default e