Compare commits

...
Author SHA1 Message Date
Andrés Moya 8f4fcfe5eb wip cleanup 2022-11-29 15:49:24 +01:00
Andrés Moya 7ba15b9a3a wip estotienemejorpinta 2022-10-11 09:37:17 +02:00
Andrés Moya 1cba7346fd wip tampocosirve 2022-10-11 09:37:17 +02:00
Andrés Moya f1bee5edf5 Revert "wip roto 2"
This reverts commit 1cb7391b35fefaa8898abb6dc482310291db3d68.
2022-10-11 09:37:17 +02:00
Andrés Moya 835ed342f8 wip roto 2 2022-10-11 09:37:17 +02:00
Andrés Moya de4c7762ad wip roto 2022-10-11 09:37:17 +02:00
Andrés Moya 3112d04a99 wip 2022-10-11 09:37:17 +02:00
Andrés Moya 3b26d05fed 🎉 Show transient changes in component copies 2022-10-11 09:37:17 +02:00
Andrés Moya 0e88398dc2 🎉 Show transient changes in component copies (old algorithm) 2022-10-11 09:37:17 +02:00
Andrés Moya 5d3eadc6db 🐛 Avoid loops in main instance sync 2022-10-11 09:37:15 +02:00
17 changed files with 298 additions and 141 deletions

No files matched your search

+16
View File
@@ -59,6 +59,21 @@
[shape] [shape]
(or (:y shape) (:y (:selrect shape)))) ; Paths don't have :y attribute (or (:y shape) (:y (:selrect shape)))) ; Paths don't have :y attribute
(defn orig-pos
"Return the top left point of the shape wrapper BEFORE applying transformations."
[shape]
(gpt/point (left-bound shape) (top-bound shape)))
(defn width
"Return the width of the shape BEFORE transformations."
[shape]
(-> shape :selrect :width))
(defn height
"Return the height of the shape BEFORE transformations."
[shape]
(-> shape :selrect :height))
(defn fully-contained? (defn fully-contained?
"Checks if one rect is fully inside the other" "Checks if one rect is fully inside the other"
[rect other] [rect other]
@@ -182,6 +197,7 @@
(dm/export gtr/modifiers->transform) (dm/export gtr/modifiers->transform)
(dm/export gtr/empty-modifiers?) (dm/export gtr/empty-modifiers?)
(dm/export gtr/move-position-data) (dm/export gtr/move-position-data)
(dm/export gtr/apply-modifiers)
(dm/export gtr/apply-transform) (dm/export gtr/apply-transform)
;; Constratins ;; Constratins
+6 -5
View File
@@ -16,6 +16,7 @@
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.spec :as us] [app.common.spec :as us]
[app.common.pages.changes-spec :as pcs] [app.common.pages.changes-spec :as pcs]
[app.common.types.component :as ctk]
[app.common.types.components-list :as ctkl] [app.common.types.components-list :as ctkl]
[app.common.types.container :as ctn] [app.common.types.container :as ctn]
[app.common.types.colors-list :as ctcl] [app.common.types.colors-list :as ctcl]
@@ -103,7 +104,7 @@
(cond-> parent (cond-> parent
(and (:shape-ref parent) (and (:shape-ref parent)
(not ignore-touched)) (not ignore-touched))
(-> (update :touched cph/set-touched-group :shapes-group) (-> (update :touched ctk/set-touched-group :shapes-group)
(dissoc :remote-synced?))))) (dissoc :remote-synced?)))))
(delete-from-objects [objects] (delete-from-objects [objects]
@@ -208,7 +209,7 @@
(update :shapes d/vec-without-nils))] (update :shapes d/vec-without-nils))]
(cond-> parent (cond-> parent
(and (:shape-ref parent) (= (:type parent) :group) (not ignore-touched)) (and (:shape-ref parent) (= (:type parent) :group) (not ignore-touched))
(-> (update :touched cph/set-touched-group :shapes-group) (-> (update :touched ctk/set-touched-group :shapes-group)
(dissoc :remote-synced?))))) (dissoc :remote-synced?)))))
(remove-from-old-parent [cpindex objects shape-id] (remove-from-old-parent [cpindex objects shape-id]
@@ -228,7 +229,7 @@
(d/update-in-when [pid :shapes] without-obj sid) (d/update-in-when [pid :shapes] without-obj sid)
(d/update-in-when [pid :shapes] d/vec-without-nils) (d/update-in-when [pid :shapes] d/vec-without-nils)
(cond-> component? (d/update-when pid #(-> % (cond-> component? (d/update-when pid #(-> %
(update :touched cph/set-touched-group :shapes-group) (update :touched ctk/set-touched-group :shapes-group)
(dissoc :remote-synced?))))))))) (dissoc :remote-synced?)))))))))
(update-parent-id [objects id] (update-parent-id [objects id]
@@ -429,7 +430,7 @@
(not root-name?) (not root-name?)
(not (and ignore-geometry is-geometry?))) (not (and ignore-geometry is-geometry?)))
(-> (->
(update :touched cph/set-touched-group group) (update :touched ctk/set-touched-group group)
(dissoc :remote-synced?)) (dissoc :remote-synced?))
(nil? val) (nil? val)
@@ -472,7 +473,7 @@
(defmulti components-changed (fn [_ change] (:type change))) (defmulti components-changed (fn [_ change] (:type change)))
(defmethod components-changed :mod-obj (defmethod components-changed :mod-obj
[file-data {:keys [id page-id _component-id operations]}] [file-data {:keys [id page-id operations]}]
(when page-id (when page-id
(let [page (ctpl/get-page file-data page-id) (let [page (ctpl/get-page file-data page-id)
shape-and-parents (map #(ctn/get-shape page %) shape-and-parents (map #(ctn/get-shape page %)
@@ -16,6 +16,7 @@
[app.common.math :as mth] [app.common.math :as mth]
[app.common.pages :as cp] [app.common.pages :as cp]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.types.container :as ctn]
[app.common.types.file :as ctf] [app.common.types.file :as ctf]
[app.common.uuid :as uuid])) [app.common.uuid :as uuid]))
@@ -44,7 +45,7 @@
(defn with-container (defn with-container
[changes container] [changes container]
(if (cph/page? container) (if (ctn/page? container)
(vary-meta changes assoc ::page-id (:id container)) (vary-meta changes assoc ::page-id (:id container))
(vary-meta changes assoc ::component-id (:id container)))) (vary-meta changes assoc ::component-id (:id container))))
-65
View File
@@ -168,71 +168,6 @@
:else :else
(recur (get-in objects [current-id :parent-id]))))) (recur (get-in objects [current-id :parent-id])))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; COMPONENTS HELPERS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn set-touched-group
[touched group]
(conj (or touched #{}) group))
(defn touched-group?
[shape group]
((or (:touched shape) #{}) group))
(defn get-component
"Retrieve a component from libraries, if no library-id is provided, we
iterate over all libraries and find the component on it."
([libraries component-id]
(some #(-> % :data :components (get component-id)) (vals libraries)))
([libraries library-id component-id]
(get-in libraries [library-id :data :components component-id])))
(defn get-component-shape
"Get the parent shape linked to a component for this shape, if any"
[objects shape]
(if-not (:shape-ref shape)
nil
(if (:component-id shape)
shape
(if-let [parent-id (:parent-id shape)]
(get-component-shape objects (get objects parent-id))
nil))))
(defn get-root-shape
"Get the root shape linked to a component for this shape, if any."
[objects shape]
(cond
(some? (:component-root? shape))
shape
(some? (:shape-ref shape))
(recur objects (get objects (:parent-id shape)))))
(defn make-container
[page-or-component type]
(assoc page-or-component :type type))
(defn page?
[container]
(= (:type container) :page))
(defn component?
[container]
(= (:type container) :component))
(defn get-container
[file type id]
(us/assert map? file)
(us/assert keyword? type)
(us/assert uuid? id)
(-> (if (= type :page)
(get-in file [:pages-index id])
(get-in file [:components id]))
(assoc :type type)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ALGORITHMS & TRANSFORMATIONS FOR SHAPES ;; ALGORITHMS & TRANSFORMATIONS FOR SHAPES
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+30 -2
View File
@@ -7,10 +7,23 @@
(ns app.common.types.component) (ns app.common.types.component)
(defn instance-root? (defn instance-root?
"Check if the shape is the root of an instance or a subinstance."
[shape] [shape]
(some? (:component-id shape))) (some? (:component-id shape)))
(defn instance-tree-root?
"Check if the shape is the root of an instance that is no
subinstance of a higher one."
[shape]
(:component-root? shape))
(defn instance-shape?
"Check if the shape is part of any instance."
[shape]
(some? (:shape-ref shape)))
(defn instance-of? (defn instance-of?
"Check if the shape is the root of a near instance of the component."
[shape file-id component-id] [shape file-id component-id]
(and (some? (:component-id shape)) (and (some? (:component-id shape))
(some? (:component-file shape)) (some? (:component-file shape))
@@ -18,23 +31,38 @@
(= (:component-file shape) file-id))) (= (:component-file shape) file-id)))
(defn is-main-of? (defn is-main-of?
"Check if the first shape is the near main of the second one."
[shape-main shape-inst] [shape-main shape-inst]
(and (:shape-ref shape-inst) (and (not= (:id shape-main) (:id shape-inst))
(:shape-ref shape-inst)
(or (= (:shape-ref shape-inst) (:id shape-main)) (or (= (:shape-ref shape-inst) (:id shape-main))
(= (:shape-ref shape-inst) (:shape-ref shape-main))))) (= (:shape-ref shape-inst) (:shape-ref shape-main)))))
(defn is-main-instance? (defn is-main-instance?
"Check if the shape is the root of the main instance of the component."
[shape-id page-id component] [shape-id page-id component]
(and (= shape-id (:main-instance-id component)) (and (= shape-id (:main-instance-id component))
(= page-id (:main-instance-page component)))) (= page-id (:main-instance-page component))))
(defn get-component-root (defn get-component-root
"Get the root shape of the component."
[component] [component]
(get-in component [:objects (:id component)])) (get-in component [:objects (:id component)]))
(defn uses-library-components? (defn uses-library-components?
"Check if the shape uses any component in the given library." "Check if the shape is the root of an instance of any component in
the given library."
[shape library-id] [shape library-id]
(and (some? (:component-id shape)) (and (some? (:component-id shape))
(= (:component-file shape) library-id))) (= (:component-file shape) library-id)))
(defn set-touched-group
"Add a group to the touched flags."
[touched group]
(conj (or touched #{}) group))
(defn touched-group?
"Check if the touched flags contain the given group."
[shape group]
((or (:touched shape) #{}) group))
+35 -11
View File
@@ -9,6 +9,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.spec :as us] [app.common.spec :as us]
[app.common.types.component :as ctk]
[app.common.types.shape-tree :as ctst] [app.common.types.shape-tree :as ctst]
[clojure.spec.alpha :as s])) [clojure.spec.alpha :as s]))
@@ -34,17 +35,6 @@
[container] [container]
(= (:type container) :component)) (= (:type container) :component))
(defn get-container
[file type id]
(us/assert map? file)
(us/assert ::type type)
(us/assert uuid? id)
(-> (if (= type :page)
(get-in file [:pages-index id])
(get-in file [:components id]))
(assoc :type type)))
(defn get-shape (defn get-shape
[container shape-id] [container shape-id]
(us/assert ::container container) (us/assert ::container container)
@@ -61,6 +51,40 @@
[container shape-id f] [container shape-id f]
(update-in container [:objects shape-id] f)) (update-in container [:objects shape-id] f))
(defn get-component-shape
"Get the root shape of an instance, the one that is linked to the component.
If this is a subinstance, get the most direct root."
[objects shape]
(if-not (:shape-ref shape)
nil
(if (:component-id shape)
shape
(if-let [parent-id (:parent-id shape)]
(get-component-shape objects (get objects parent-id))
nil))))
(defn get-root-shape
"Get the topmost root shape of an instance, the one that is linked to the
component and without any container instance upwards."
[objects shape]
(cond
(some? (:component-root? shape))
shape
(some? (:shape-ref shape))
(recur objects (get objects (:parent-id shape)))))
(defn get-instances
"Get all shapes in the objects list that are near instances of the given one
---------------------------------------------------------------------------
TODO: Warning!!! this is a slow operation, since it needs to walk the whole
objects list. Perhaps there is a way of indexing this someway.
---------------------------------------------------------------------------"
[objects main-shape]
(filter #(ctk/is-main-of? main-shape %)
(vals objects)))
(defn make-component-shape (defn make-component-shape
"Clone the shape and all children. Generate new ids and detach "Clone the shape and all children. Generate new ids and detach
from parent and frame. Update the original shapes to have links from parent and frame. Update the original shapes to have links
+13 -1
View File
@@ -6,6 +6,7 @@
(ns app.common.types.file (ns app.common.types.file
(:require (:require
[app.common.pprint :refer [pprint]]
[app.common.data :as d] [app.common.data :as d]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
@@ -111,6 +112,17 @@
(concat (map #(ctn/make-container % :page) (ctpl/pages-seq file-data)) (concat (map #(ctn/make-container % :page) (ctpl/pages-seq file-data))
(map #(ctn/make-container % :component) (ctkl/components-seq file-data)))) (map #(ctn/make-container % :component) (ctkl/components-seq file-data))))
(defn get-container
[file type id]
(us/assert map? file)
(us/assert :app.common.types.container/type type)
(us/assert uuid? id)
(-> (if (= type :page)
(get-in file [:pages-index id])
(get-in file [:components id]))
(assoc :type type)))
(defn update-container (defn update-container
"Update a container inside the file, it can be a page or a component" "Update a container inside the file, it can be a page or a component"
[file-data container f] [file-data container f]
@@ -512,7 +524,7 @@
(show-component [shape objects] (show-component [shape objects]
(if (nil? (:shape-ref shape)) (if (nil? (:shape-ref shape))
"" ""
(let [root-shape (cph/get-component-shape objects shape) (let [root-shape (ctn/get-component-shape objects shape)
component-id (when root-shape (:component-id root-shape)) component-id (when root-shape (:component-id root-shape))
component-file-id (when root-shape (:component-file root-shape)) component-file-id (when root-shape (:component-file root-shape))
component-file (when component-file-id (get libraries component-file-id nil)) component-file (when component-file-id (get libraries component-file-id nil))
+2 -1
View File
@@ -13,6 +13,7 @@
[app.common.math :as mth] [app.common.math :as mth]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.spec :as us] [app.common.spec :as us]
[app.common.types.component :as ctk]
[app.common.types.shape :as cts] [app.common.types.shape :as cts]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[clojure.spec.alpha :as s])) [clojure.spec.alpha :as s]))
@@ -45,7 +46,7 @@
(cond-> (and (:shape-ref parent) (cond-> (and (:shape-ref parent)
(not= (:id parent) frame-id) (not= (:id parent) frame-id)
(not ignore-touched)) (not ignore-touched))
(-> (update :touched cph/set-touched-group :shapes-group) (-> (update :touched ctk/set-touched-group :shapes-group)
(dissoc :remote-synced?))))) (dissoc :remote-synced?)))))
;; TODO: this looks wrong, why we allow nil values? ;; TODO: this looks wrong, why we allow nil values?
@@ -3,7 +3,8 @@
[clojure.test :as t] [clojure.test :as t]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.types.component :as ctk] [app.common.types.component :as ctk]
[app.common.types.container :as ctn])) [app.common.types.container :as ctn]
[app.common.types.file :as ctf]))
;; ---- Helpers to manage libraries and synchronization ;; ---- Helpers to manage libraries and synchronization
@@ -75,7 +76,7 @@
[page root-inst-id libraries] [page root-inst-id libraries]
(let [root-inst (ctn/get-shape page root-inst-id) (let [root-inst (ctn/get-shape page root-inst-id)
component (cph/get-component libraries (:component-id root-inst)) component (ctf/get-component libraries (:component-id root-inst))
shapes-inst (cph/get-children-with-self (:objects page) root-inst-id) shapes-inst (cph/get-children-with-self (:objects page) root-inst-id)
shapes-main (cph/get-children-with-self (:objects component) (:shape-ref root-inst)) shapes-main (cph/get-children-with-self (:objects component) (:shape-ref root-inst))
@@ -84,10 +85,10 @@
main-exists? (fn [shape] main-exists? (fn [shape]
(let [component-shape (let [component-shape
(cph/get-component-shape (:objects page) shape) (ctn/get-component-shape (:objects page) shape)
component component
(cph/get-component libraries (:component-id component-shape)) (ctf/get-component libraries (:component-id component-shape))
main-shape main-shape
(ctn/get-shape component (:shape-ref shape))] (ctn/get-shape component (:shape-ref shape))]
@@ -111,7 +112,7 @@
[page root-inst-id libraries] [page root-inst-id libraries]
(let [root-inst (ctn/get-shape page root-inst-id) (let [root-inst (ctn/get-shape page root-inst-id)
component (cph/get-component libraries (:component-id root-inst)) component (ctf/get-component libraries (:component-id root-inst))
shapes-inst (cph/get-children-with-self (:objects page) root-inst-id) shapes-inst (cph/get-children-with-self (:objects page) root-inst-id)
shapes-main (cph/get-children-with-self (:objects component) (:shape-ref root-inst)) shapes-main (cph/get-children-with-self (:objects component) (:shape-ref root-inst))
@@ -120,10 +121,10 @@
main-exists? (fn [shape] main-exists? (fn [shape]
(let [component-shape (let [component-shape
(cph/get-component-shape (:objects page) shape) (ctn/get-component-shape (:objects page) shape)
component component
(cph/get-component libraries (:component-id component-shape)) (ctf/get-component libraries (:component-id component-shape))
main-shape main-shape
(ctn/get-shape component (:shape-ref shape))] (ctn/get-shape component (:shape-ref shape))]
@@ -138,7 +139,7 @@
(defn resolve-component (defn resolve-component
"Get the component with the given id and all its shapes." "Get the component with the given id and all its shapes."
[page component-id libraries] [page component-id libraries]
(let [component (cph/get-component libraries component-id) (let [component (ctf/get-component libraries component-id)
root-main (ctk/get-component-root component) root-main (ctk/get-component-root component)
shapes-main (cph/get-children-with-self (:objects component) (:id root-main))] shapes-main (cph/get-children-with-self (:objects component) (:id root-main))]
+4 -3
View File
@@ -18,6 +18,7 @@
[app.common.spec :as us] [app.common.spec :as us]
[app.common.text :as txt] [app.common.text :as txt]
[app.common.transit :as t] [app.common.transit :as t]
[app.common.types.container :as ctn]
[app.common.types.shape :as cts] [app.common.types.shape :as cts]
[app.common.types.shape-tree :as ctst] [app.common.types.shape-tree :as ctst]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
@@ -641,8 +642,8 @@
(not (:component-root? shape))) (not (:component-root? shape)))
parent (get objects parent-id) parent (get objects parent-id)
component-shape (cph/get-component-shape objects shape) component-shape (ctn/get-component-shape objects shape)
component-shape-parent (cph/get-component-shape objects parent) component-shape-parent (ctn/get-component-shape objects parent)
detach? (and instance-part? (not= (:id component-shape) detach? (and instance-part? (not= (:id component-shape)
(:id component-shape-parent))) (:id component-shape-parent)))
@@ -1406,7 +1407,7 @@
;; Check if the shape is an instance whose master is defined in a ;; Check if the shape is an instance whose master is defined in a
;; library that is not linked to the current file ;; library that is not linked to the current file
(foreign-instance? [shape paste-objects state] (foreign-instance? [shape paste-objects state]
(let [root (cph/get-root-shape paste-objects shape) (let [root (ctn/get-root-shape paste-objects shape)
root-file-id (:component-file root)] root-file-id (:component-file root)]
(and (some? root) (and (some? root)
(not= root-file-id (:current-file-id state)) (not= root-file-id (:current-file-id state))
@@ -367,7 +367,7 @@
ptk/WatchEvent ptk/WatchEvent
(watch [it state _] (watch [it state _]
(let [libraries (wsh/get-libraries state) (let [libraries (wsh/get-libraries state)
component (cph/get-component libraries id) component (ctf/get-component libraries id)
all-components (-> state :workspace-data :components vals) all-components (-> state :workspace-data :components vals)
unames (into #{} (map :name) all-components) unames (into #{} (map :name) all-components)
new-name (ctst/generate-unique-name unames (:name component)) new-name (ctst/generate-unique-name unames (:name component))
@@ -484,7 +484,7 @@
(watch [it state _] (watch [it state _]
(let [file (wsh/get-local-file state) (let [file (wsh/get-local-file state)
page-id (get state :current-page-id) page-id (get state :current-page-id)
container (cph/get-container file :page page-id) container (ctf/get-container file :page page-id)
changes (-> (pcb/empty-changes it) changes (-> (pcb/empty-changes it)
(pcb/with-container container) (pcb/with-container container)
@@ -500,7 +500,7 @@
(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)
file (wsh/get-local-file state) file (wsh/get-local-file state)
container (cph/get-container file :page page-id) container (ctf/get-container file :page page-id)
selected (->> state selected (->> state
(wsh/lookup-selected) (wsh/lookup-selected)
(cph/clean-loops objects)) (cph/clean-loops objects))
@@ -557,7 +557,7 @@
libraries (wsh/get-libraries state) libraries (wsh/get-libraries state)
page-id (:current-page-id state) page-id (:current-page-id state)
container (cph/get-container file :page page-id) container (ctf/get-container file :page page-id)
components-v2 components-v2
(features/active-feature? state :components-v2) (features/active-feature? state :components-v2)
@@ -593,7 +593,7 @@
local-file (wsh/get-local-file state) local-file (wsh/get-local-file state)
libraries (wsh/get-libraries state) libraries (wsh/get-libraries state)
container (cph/get-container local-file :page page-id) container (ctf/get-container local-file :page page-id)
shape (ctn/get-shape container id) shape (ctn/get-shape container id)
changes changes
@@ -721,7 +721,13 @@
(when sync-typographies? (when sync-typographies?
(dwlh/generate-sync-file it file-id :typographies asset-id library-id state))]) (dwlh/generate-sync-file it file-id :typographies asset-id library-id state))])
changes (pcb/concat-changes library-changes file-changes)] changes (pcb/concat-changes library-changes file-changes)
changes (cond-> changes
; Store the origin component to avoid sync loops
(= asset-type :components)
(update :redo-changes
#(vary-meta % assoc :origin-component-id asset-id)))]
(log/debug :msg "SYNC-FILE finished" :js/rchanges (log-changes (log/debug :msg "SYNC-FILE finished" :js/rchanges (log-changes
(:redo-changes changes) (:redo-changes changes)
@@ -842,10 +848,25 @@
check-changes check-changes
(fn [[event data]] (fn [[event data]]
(let [{:keys [changes save-undo?]} (deref event) (let [page (wsh/lookup-page state)
{:keys [changes save-undo?]} (deref event)
components-changed (reduce #(into %1 (ch/components-changed data %2)) components-changed (reduce #(into %1 (ch/components-changed data %2))
#{} #{}
changes)] changes)
orig-component-id (get (meta changes) :origin-component-id)
is-orig (fn [shape-id]
(let [shape (ctn/get-shape page shape-id)]
(= (:component-id shape) orig-component-id)))
;; If the changes are derived of the synchronization of a main component,
;; ignore them to avoid entering loops.
components-changed (if orig-component-id
(set (remove is-orig components-changed))
components-changed)]
(when (and (d/not-empty? components-changed) save-undo?) (when (and (d/not-empty? components-changed) save-undo?)
(log/info :msg "DETECTED COMPONENTS CHANGED" (log/info :msg "DETECTED COMPONENTS CHANGED"
:ids (map str components-changed)) :ids (map str components-changed))
@@ -890,6 +911,7 @@
(let [state (dissoc state :files)] (let [state (dissoc state :files)]
(assoc state :workspace-shared-files files))))) (assoc state :workspace-shared-files files)))))
(defn fetch-shared-files (defn fetch-shared-files
[{:keys [team-id] :as params}] [{:keys [team-id] :as params}]
(us/assert ::us/uuid team-id) (us/assert ::us/uuid team-id)
@@ -18,6 +18,7 @@
[app.common.types.color :as ctc] [app.common.types.color :as ctc]
[app.common.types.component :as ctk] [app.common.types.component :as ctk]
[app.common.types.container :as ctn] [app.common.types.container :as ctn]
[app.common.types.file :as ctf]
[app.common.types.shape-tree :as ctst] [app.common.types.shape-tree :as ctst]
[app.common.types.typography :as cty] [app.common.types.typography :as cty]
[app.main.data.workspace.groups :as dwg] [app.main.data.workspace.groups :as dwg]
@@ -126,7 +127,7 @@
(defn generate-instantiate-component (defn generate-instantiate-component
"Generate changes to create a new instance from a component." "Generate changes to create a new instance from a component."
[it file-id component-id position page libraries] [it file-id component-id position page libraries]
(let [component (cph/get-component libraries file-id component-id) (let [component (ctf/get-component libraries file-id component-id)
[new-shape new-shapes] [new-shape new-shapes]
(ctn/make-component-instance page component file-id position) (ctn/make-component-instance page component file-id position)
@@ -190,7 +191,7 @@
asset-id asset-id
library-id library-id
state state
(cph/make-container page :page) (ctn/make-container page :page)
components-v2))) components-v2)))
changes)))) changes))))
@@ -226,7 +227,7 @@
asset-id asset-id
library-id library-id
state state
(cph/make-container local-component :component) (ctn/make-container local-component :component)
components-v2))) components-v2)))
changes)))) changes))))
@@ -235,7 +236,7 @@
or a component) that use assets of the given type in the given library." or a component) that use assets of the given type in the given library."
[it asset-type asset-id library-id state container components-v2] [it asset-type asset-id library-id state container components-v2]
(if (cph/page? container) (if (ctn/page? container)
(log/debug :msg "Sync page in local file" :page-id (:id container)) (log/debug :msg "Sync page in local file" :page-id (:id container))
(log/debug :msg "Sync component in local library" :component-id (:id container))) (log/debug :msg "Sync component in local library" :component-id (:id container)))
@@ -450,7 +451,7 @@
[changes libraries container shape-id reset? components-v2] [changes libraries container shape-id reset? components-v2]
(log/debug :msg "Sync shape direct" :shape (str shape-id) :reset? reset?) (log/debug :msg "Sync shape direct" :shape (str shape-id) :reset? reset?)
(let [shape-inst (ctn/get-shape container shape-id) (let [shape-inst (ctn/get-shape container shape-id)
component (cph/get-component libraries component (ctf/get-component libraries
(:component-file shape-inst) (:component-file shape-inst)
(:component-id shape-inst)) (:component-id shape-inst))
shape-main (when component shape-main (when component
@@ -582,7 +583,7 @@
[changes libraries container shape-id] [changes libraries container shape-id]
(log/debug :msg "Sync shape inverse" :shape (str shape-id)) (log/debug :msg "Sync shape inverse" :shape (str shape-id))
(let [shape-inst (ctn/get-shape container shape-id) (let [shape-inst (ctn/get-shape container shape-id)
component (cph/get-component libraries component (ctf/get-component libraries
(:component-file shape-inst) (:component-file shape-inst)
(:component-id shape-inst)) (:component-id shape-inst))
shape-main (ctn/get-shape component (:shape-ref shape-inst)) shape-main (ctn/get-shape component (:shape-ref shape-inst))
@@ -612,7 +613,7 @@
(if (nil? shape-main) (if (nil? shape-main)
;; This should not occur, but protect against it in any case ;; This should not occur, but protect against it in any case
changes changes
(let [component-container (cph/make-container component :component) (let [component-container (ctn/make-container component :component)
omit-touched? false omit-touched? false
set-remote-synced? (not initial-root?) set-remote-synced? (not initial-root?)
@@ -819,7 +820,7 @@
:shapes all-parents})) :shapes all-parents}))
changes' (reduce del-obj-change changes' new-shapes)] changes' (reduce del-obj-change changes' new-shapes)]
(if (and (cph/touched-group? parent-shape :shapes-group) omit-touched?) (if (and (ctk/touched-group? parent-shape :shapes-group) omit-touched?)
changes changes
changes'))) changes')))
@@ -902,7 +903,7 @@
(defn- remove-shape (defn- remove-shape
[changes shape container omit-touched?] [changes shape container omit-touched?]
(log/info :msg (str "REMOVE-SHAPE " (log/info :msg (str "REMOVE-SHAPE "
(if (cph/page? container) "[P] " "[C] ") (if (ctn/page? container) "[P] " "[C] ")
(:name shape))) (:name shape)))
(let [objects (get container :objects) (let [objects (get container :objects)
parents (cph/get-parent-ids objects (:id shape)) parents (cph/get-parent-ids objects (:id shape))
@@ -940,14 +941,14 @@
changes' changes'
(map :id children))] (map :id children))]
(if (and (cph/touched-group? parent :shapes-group) omit-touched?) (if (and (ctk/touched-group? parent :shapes-group) omit-touched?)
changes changes
changes'))) changes')))
(defn- move-shape (defn- move-shape
[changes shape index-before index-after container omit-touched?] [changes shape index-before index-after container omit-touched?]
(log/info :msg (str "MOVE " (log/info :msg (str "MOVE "
(if (cph/page? container) "[P] " "[C] ") (if (ctn/page? container) "[P] " "[C] ")
(:name shape) (:name shape)
" " " "
index-before index-before
@@ -971,7 +972,7 @@
:index index-before :index index-before
:ignore-touched true})))] :ignore-touched true})))]
(if (and (cph/touched-group? parent :shapes-group) omit-touched?) (if (and (ctk/touched-group? parent :shapes-group) omit-touched?)
changes changes
changes'))) changes')))
@@ -983,7 +984,7 @@
changes changes
(do (do
(log/info :msg (str "CHANGE-TOUCHED " (log/info :msg (str "CHANGE-TOUCHED "
(if (cph/page? container) "[P] " "[C] ") (if (ctn/page? container) "[P] " "[C] ")
(:name dest-shape)) (:name dest-shape))
:options options) :options options)
(let [new-touched (cond (let [new-touched (cond
@@ -1018,7 +1019,7 @@
changes changes
(do (do
(log/info :msg (str "CHANGE-REMOTE-SYNCED? " (log/info :msg (str "CHANGE-REMOTE-SYNCED? "
(if (cph/page? container) "[P] " "[C] ") (if (ctn/page? container) "[P] " "[C] ")
(:name shape)) (:name shape))
:remote-synced? remote-synced?) :remote-synced? remote-synced?)
(-> changes (-> changes
@@ -1048,7 +1049,7 @@
(log/info :msg (str "SYNC " (log/info :msg (str "SYNC "
(:name origin-shape) (:name origin-shape)
" -> " " -> "
(if (cph/page? container) "[P] " "[C] ") (if (ctn/page? container) "[P] " "[C] ")
(:name dest-shape))) (:name dest-shape)))
(let [; To synchronize geometry attributes we need to make a prior (let [; To synchronize geometry attributes we need to make a prior
@@ -1127,7 +1128,7 @@
(defn- make-change (defn- make-change
[container change] [container change]
(if (cph/page? container) (if (ctn/page? container)
(assoc change :page-id (:id container)) (assoc change :page-id (:id container))
(assoc change :component-id (:id container)))) (assoc change :component-id (:id container))))
@@ -16,6 +16,8 @@
[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]
[app.common.types.component :as ctk]
[app.common.types.container :as ctn]
[app.common.types.shape-tree :as ctst] [app.common.types.shape-tree :as ctst]
[app.main.data.workspace.changes :as dch] [app.main.data.workspace.changes :as dch]
[app.main.data.workspace.collapse :as dwc] [app.main.data.workspace.collapse :as dwc]
@@ -30,6 +32,100 @@
[cljs.spec.alpha :as s] [cljs.spec.alpha :as s]
[potok.core :as ptk])) [potok.core :as ptk]))
;; --- copies ---------------------------
(defn- get-copies
"If one or more of the shapes belongs to a component's main instance, find all copies of
the component in the same page.
Return a map {<main-root-id> [<main-root> [<copy-root> <copy-root>...]] ...}"
[shapes objects modifiers]
(letfn [(get-copies-one [shape]
(let [root-shape (ctn/get-root-shape objects shape)]
(when (:main-instance? root-shape)
(let [children (->> root-shape
:shapes
(map #(get objects %))
(map #(gsh/apply-modifiers % (get-in modifiers [(:id %) :modifiers]))))
root-shape (gsh/update-group-selrect root-shape children)]
[(:id root-shape) [root-shape (ctn/get-instances objects root-shape)]]))))]
(into {} (map get-copies-one shapes))))
(defn- reposition-shape
[shape origin-root dest-root]
(let [shape-pos (fn [shape]
(gpt/point (get-in shape [:selrect :x])
(get-in shape [:selrect :y])))
origin-root-pos (shape-pos origin-root)
dest-root-pos (shape-pos dest-root)
delta (gpt/subtract dest-root-pos origin-root-pos)]
(gsh/move shape delta)))
(defn- sync-shape
[main-shape copy-shape copy-root main-root]
(if (ctk/touched-group? copy-shape :geometry-group)
{}
(let [main-shape (reposition-shape main-shape main-root copy-root)
translation (gpt/subtract (gsh/orig-pos main-shape)
(gsh/orig-pos copy-shape))
center (gsh/orig-pos copy-shape)
mult-w (/ (gsh/width main-shape) (gsh/width copy-shape))
mult-h (/ (gsh/height main-shape) (gsh/height copy-shape))
resize (gpt/point mult-w mult-h)]
(cond-> {}
(not (gpt/almost-zero? translation))
(assoc :displacement (gmt/translate-matrix translation))
(not (gpt/close? resize (gpt/point 1 1)))
(assoc :resize-vector resize
:resize-origin center)))))
(defn- process-text-modifiers
"For texts we only use the displacement because resize
needs to recalculate the text layout"
[shape modifiers]
modifiers)
(defn- add-copies-modifiers
"Add modifiers to all necessary shapes inside the copies"
[copies objects modifiers]
(letfn [(add-copy-modifiers-one [modifiers copy-shape copy-root main-root main-shapes main-shapes-modif]
(let [main-shape-modif (d/seek #(ctk/is-main-of? % copy-shape) main-shapes-modif)
modifier (cond-> (sync-shape main-shape-modif copy-shape copy-root main-root)
(some? (:rotation (get-in modifiers [(:id main-shape-modif) :modifiers])))
(assoc :rotation (:rotation (get-in modifiers [(:id main-shape-modif) :modifiers])))
)]
(if (seq modifier)
(assoc-in modifiers [(:id copy-shape) :modifiers] modifier)
modifiers)))
(add-copy-modifiers [modifiers copy-root main-root main-shapes main-shapes-modif]
(let [copy-shapes (into [copy-root] (cph/get-children objects (:id copy-root)))]
(reduce #(add-copy-modifiers-one %1 %2 copy-root main-root main-shapes main-shapes-modif)
modifiers
copy-shapes)))
(add-copies-modifiers-one [modifiers [main-root copy-roots]]
(let [main-shapes (into [main-root] (cph/get-children objects (:id main-root)))
main-shapes-modif (map (fn [shape]
(->> (get-in modifiers [(:id shape) :modifiers])
(process-text-modifiers shape)
(gsh/apply-modifiers shape)))
main-shapes)]
(reduce #(add-copy-modifiers %1 %2 main-root main-shapes main-shapes-modif)
modifiers
copy-roots)))]
(reduce add-copies-modifiers-one
modifiers
(vals copies))))
;; -- Helpers -------------------------------------------------------- ;; -- Helpers --------------------------------------------------------
;; For each of the 8 handlers gives the multiplier for resize ;; For each of the 8 handlers gives the multiplier for resize
@@ -137,10 +233,22 @@
(contains? (:workspace-layout state) :snap-pixel-grid)) (contains? (:workspace-layout state) :snap-pixel-grid))
modif-tree modif-tree
(gsh/set-objects-modifiers ids objects (constantly modifiers) ignore-constraints snap-pixel?)] (gsh/set-objects-modifiers ids objects (constantly modifiers) ignore-constraints snap-pixel?)
copies (get-copies (mapv (d/getf objects) ids) objects modif-tree)
;; TODO: mark new modifiers to be ignored in apply-modifiers
modif-tree (add-copies-modifiers copies objects modif-tree)]
(update state :workspace-modifiers merge modif-tree)))))) (update state :workspace-modifiers merge modif-tree))))))
;; (defn set-modifiers-raw
;; [modifiers]
;; (ptk/reify ::set-modifiers-raw
;; ptk/UpdateEvent
;; (update [_ state]
;; (update state :workspace-modifiers merge modifiers))))
;; Rotation use different algorithm to calculate children modifiers (and do not use child constraints). ;; Rotation use different algorithm to calculate children modifiers (and do not use child constraints).
(defn- set-rotation-modifiers (defn- set-rotation-modifiers
([angle shapes] ([angle shapes]
@@ -249,7 +357,7 @@
shape shape
(nil? root) (nil? root)
(cph/get-root-shape objects shape) (ctn/get-root-shape objects shape)
:else root) :else root)
@@ -259,7 +367,7 @@
transformed-shape transformed-shape
(nil? transformed-root) (nil? transformed-root)
(as-> (cph/get-root-shape objects transformed-shape) $ (as-> (ctn/get-root-shape objects transformed-shape) $
(gsh/transform-shape (merge $ (get modif-tree (:id $))))) (gsh/transform-shape (merge $ (get modif-tree (:id $)))))
:else transformed-root) :else transformed-root)
-1
View File
@@ -300,7 +300,6 @@
[ids] [ids]
(l/derived #(select-keys % ids) workspace-modifiers)) (l/derived #(select-keys % ids) workspace-modifiers))
(def workspace-modifiers-with-objects (def workspace-modifiers-with-objects
(l/derived (l/derived
(fn [state] (fn [state]
@@ -11,9 +11,15 @@
[app.common.geom.matrix :as gmt] [app.common.geom.matrix :as gmt]
[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.pages.helpers :as cph] ; TODO: move this to ctst
[app.common.types.component :as ctk]
[app.common.types.container :as ctn]
[app.main.data.workspace.transforms :as dwt]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.workspace.viewport.utils :as vwu] [app.main.ui.workspace.viewport.utils :as vwu]
[app.util.dom :as dom] [app.util.dom :as dom]
[app.util.timers :as tm]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(defn- transform-no-resize (defn- transform-no-resize
@@ -252,11 +258,15 @@
(defn use-dynamic-modifiers (defn use-dynamic-modifiers
[objects node modifiers] [objects node modifiers]
(let [transforms (let [prev-shapes (mf/use-var nil)
prev-modifiers (mf/use-var nil)
prev-transforms (mf/use-var nil)
transforms
(mf/use-memo (mf/use-memo
(mf/deps modifiers) (mf/deps modifiers)
(fn [] (fn []
(when (some? modifiers) (when (seq modifiers)
(d/mapm (fn [id {modifiers :modifiers}] (d/mapm (fn [id {modifiers :modifiers}]
(let [shape (get objects id) (let [shape (get objects id)
center (gsh/center-shape shape) center (gsh/center-shape shape)
@@ -273,11 +283,7 @@
(mf/deps transforms) (mf/deps transforms)
(fn [] (fn []
(->> (keys transforms) (->> (keys transforms)
(mapv (d/getf objects))))) (map (d/getf objects)))))]
prev-shapes (mf/use-var nil)
prev-modifiers (mf/use-var nil)
prev-transforms (mf/use-var nil)]
(mf/use-layout-effect (mf/use-layout-effect
(mf/deps transforms) (mf/deps transforms)
+2 -2
View File
@@ -302,7 +302,7 @@
; Renamed component ; Renamed component
; Rect-1 ; Rect-1
(let [libs (wsh/get-libraries new-state) (let [libs (wsh/get-libraries new-state)
component (cph/get-component libs component (ctf/get-component libs
(:component-file instance1) (:component-file instance1)
(:component-id instance1))] (:component-id instance1))]
(t/is (= (:name component) (t/is (= (:name component)
@@ -400,7 +400,7 @@
(:id instance1)) (:id instance1))
libs (wsh/get-libraries new-state) libs (wsh/get-libraries new-state)
component (cph/get-component libs component (ctf/get-component libs
(:component-file instance1) (:component-file instance1)
(:component-id instance1))] (:component-id instance1))]
@@ -5,6 +5,7 @@
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.types.component :as ctk] [app.common.types.component :as ctk]
[app.common.types.container :as ctn] [app.common.types.container :as ctn]
[app.common.types.file :as ctf]
[app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.state-helpers :as wsh]
[app.test-helpers.pages :as thp])) [app.test-helpers.pages :as thp]))
@@ -85,7 +86,7 @@
root-inst (ctn/get-shape page root-inst-id) root-inst (ctn/get-shape page root-inst-id)
libs (wsh/get-libraries state) libs (wsh/get-libraries state)
component (cph/get-component libs (:component-id root-inst)) component (ctf/get-component libs (:component-id root-inst))
shapes-inst (cph/get-children-with-self (:objects page) root-inst-id) shapes-inst (cph/get-children-with-self (:objects page) root-inst-id)
shapes-main (cph/get-children-with-self (:objects component) (:shape-ref root-inst)) shapes-main (cph/get-children-with-self (:objects component) (:shape-ref root-inst))
@@ -94,10 +95,10 @@
main-exists? (fn [shape] main-exists? (fn [shape]
(let [component-shape (let [component-shape
(cph/get-component-shape (:objects page) shape) (ctn/get-component-shape (:objects page) shape)
component component
(cph/get-component libs (:component-id component-shape)) (ctf/get-component libs (:component-id component-shape))
main-shape main-shape
(ctn/get-shape component (:shape-ref shape))] (ctn/get-shape component (:shape-ref shape))]
@@ -125,7 +126,7 @@
root-inst (ctn/get-shape page root-inst-id) root-inst (ctn/get-shape page root-inst-id)
libs (wsh/get-libraries state) libs (wsh/get-libraries state)
component (cph/get-component libs (:component-id root-inst)) component (ctf/get-component libs (:component-id root-inst))
shapes-inst (cph/get-children-with-self (:objects page) root-inst-id) shapes-inst (cph/get-children-with-self (:objects page) root-inst-id)
shapes-main (cph/get-children-with-self (:objects component) (:shape-ref root-inst)) shapes-main (cph/get-children-with-self (:objects component) (:shape-ref root-inst))
@@ -134,10 +135,10 @@
main-exists? (fn [shape] main-exists? (fn [shape]
(let [component-shape (let [component-shape
(cph/get-component-shape (:objects page) shape) (ctn/get-component-shape (:objects page) shape)
component component
(cph/get-component libs (:component-id component-shape)) (ctf/get-component libs (:component-id component-shape))
main-shape main-shape
(ctn/get-shape component (:shape-ref shape))] (ctn/get-shape component (:shape-ref shape))]
@@ -154,7 +155,7 @@
[state component-id] [state component-id]
(let [page (thp/current-page state) (let [page (thp/current-page state)
libs (wsh/get-libraries state) libs (wsh/get-libraries state)
component (cph/get-component libs component-id) component (ctf/get-component libs component-id)
root-main (ctk/get-component-root component) root-main (ctk/get-component-root component)
shapes-main (cph/get-children-with-self (:objects component) (:id root-main))] shapes-main (cph/get-children-with-self (:objects component) (:id root-main))]