diff --git a/common/src/app/common/geom/shapes.cljc b/common/src/app/common/geom/shapes.cljc index a08fe8a21..e8774a8ae 100644 --- a/common/src/app/common/geom/shapes.cljc +++ b/common/src/app/common/geom/shapes.cljc @@ -59,6 +59,11 @@ [shape] (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 fully-contained? "Checks if one rect is fully inside the other" [rect other] @@ -182,6 +187,7 @@ (dm/export gtr/modifiers->transform) (dm/export gtr/empty-modifiers?) (dm/export gtr/move-position-data) +(dm/export gtr/apply-modifiers) (dm/export gtr/apply-transform) ;; Constratins diff --git a/common/src/app/common/pages/changes.cljc b/common/src/app/common/pages/changes.cljc index feedf70bd..8a36b4ff8 100644 --- a/common/src/app/common/pages/changes.cljc +++ b/common/src/app/common/pages/changes.cljc @@ -16,6 +16,7 @@ [app.common.pages.helpers :as cph] [app.common.spec :as us] [app.common.pages.changes-spec :as pcs] + [app.common.types.component :as ctk] [app.common.types.components-list :as ctkl] [app.common.types.container :as ctn] [app.common.types.colors-list :as ctcl] @@ -103,7 +104,7 @@ (cond-> parent (and (:shape-ref parent) (not ignore-touched)) - (-> (update :touched cph/set-touched-group :shapes-group) + (-> (update :touched ctk/set-touched-group :shapes-group) (dissoc :remote-synced?))))) (delete-from-objects [objects] @@ -208,7 +209,7 @@ (update :shapes d/vec-without-nils))] (cond-> parent (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?))))) (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] d/vec-without-nils) (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?))))))))) (update-parent-id [objects id] @@ -429,7 +430,7 @@ (not root-name?) (not (and ignore-geometry is-geometry?))) (-> - (update :touched cph/set-touched-group group) + (update :touched ctk/set-touched-group group) (dissoc :remote-synced?)) (nil? val) diff --git a/common/src/app/common/pages/changes_builder.cljc b/common/src/app/common/pages/changes_builder.cljc index b1d1b9166..506236dbe 100644 --- a/common/src/app/common/pages/changes_builder.cljc +++ b/common/src/app/common/pages/changes_builder.cljc @@ -16,6 +16,7 @@ [app.common.math :as mth] [app.common.pages :as cp] [app.common.pages.helpers :as cph] + [app.common.types.container :as ctn] [app.common.types.file :as ctf] [app.common.uuid :as uuid])) @@ -44,7 +45,7 @@ (defn with-container [changes container] - (if (cph/page? container) + (if (ctn/page? container) (vary-meta changes assoc ::page-id (:id container)) (vary-meta changes assoc ::component-id (:id container)))) diff --git a/common/src/app/common/pages/helpers.cljc b/common/src/app/common/pages/helpers.cljc index 02e21f8c2..e77faae46 100644 --- a/common/src/app/common/pages/helpers.cljc +++ b/common/src/app/common/pages/helpers.cljc @@ -168,71 +168,6 @@ :else (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 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/common/src/app/common/types/component.cljc b/common/src/app/common/types/component.cljc index 2614626a8..64e193858 100644 --- a/common/src/app/common/types/component.cljc +++ b/common/src/app/common/types/component.cljc @@ -7,10 +7,23 @@ (ns app.common.types.component) (defn instance-root? + "Check if the shape is the root of an instance or a subinstance." [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? + "Check if the shape is the root of a near instance of the component." [shape file-id component-id] (and (some? (:component-id shape)) (some? (:component-file shape)) @@ -18,23 +31,38 @@ (= (:component-file shape) file-id))) (defn is-main-of? + "Check if the first shape is the near main of the second one." [shape-main shape-inst] - (and (:shape-ref shape-inst) + (and (not= shape-main shape-inst) + (:shape-ref shape-inst) (or (= (:shape-ref shape-inst) (:id shape-main)) (= (:shape-ref shape-inst) (:shape-ref shape-main))))) (defn is-main-instance? + "Check if the shape is the root of the main instance of the component." [shape-id page-id component] (and (= shape-id (:main-instance-id component)) (= page-id (:main-instance-page component)))) (defn get-component-root + "Get the root shape of the component." [component] (get-in component [:objects (:id component)])) (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] (and (some? (:component-id shape)) (= (: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)) + diff --git a/common/src/app/common/types/container.cljc b/common/src/app/common/types/container.cljc index 104fd0f34..4de7512e7 100644 --- a/common/src/app/common/types/container.cljc +++ b/common/src/app/common/types/container.cljc @@ -9,6 +9,7 @@ [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] [app.common.spec :as us] + [app.common.types.component :as ctk] [app.common.types.shape-tree :as ctst] [clojure.spec.alpha :as s])) @@ -34,17 +35,6 @@ [container] (= (: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 [container shape-id] (us/assert ::container container) @@ -61,6 +51,40 @@ [container 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 "Clone the shape and all children. Generate new ids and detach from parent and frame. Update the original shapes to have links diff --git a/common/src/app/common/types/file.cljc b/common/src/app/common/types/file.cljc index 74f11a20b..99cb9ca78 100644 --- a/common/src/app/common/types/file.cljc +++ b/common/src/app/common/types/file.cljc @@ -6,6 +6,7 @@ (ns app.common.types.file (:require + [app.common.pprint :refer [pprint]] [app.common.data :as d] [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] @@ -111,6 +112,17 @@ (concat (map #(ctn/make-container % :page) (ctpl/pages-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 "Update a container inside the file, it can be a page or a component" [file-data container f] @@ -512,7 +524,7 @@ (show-component [shape objects] (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-file-id (when root-shape (:component-file root-shape)) component-file (when component-file-id (get libraries component-file-id nil)) diff --git a/common/src/app/common/types/shape_tree.cljc b/common/src/app/common/types/shape_tree.cljc index 633e757a4..c0c3fd505 100644 --- a/common/src/app/common/types/shape_tree.cljc +++ b/common/src/app/common/types/shape_tree.cljc @@ -13,6 +13,7 @@ [app.common.math :as mth] [app.common.pages.helpers :as cph] [app.common.spec :as us] + [app.common.types.component :as ctk] [app.common.types.shape :as cts] [app.common.uuid :as uuid] [clojure.spec.alpha :as s])) @@ -45,7 +46,7 @@ (cond-> (and (:shape-ref parent) (not= (:id parent) frame-id) (not ignore-touched)) - (-> (update :touched cph/set-touched-group :shapes-group) + (-> (update :touched ctk/set-touched-group :shapes-group) (dissoc :remote-synced?))))) ;; TODO: this looks wrong, why we allow nil values? diff --git a/common/test/app/common/test_helpers/components.cljc b/common/test/app/common/test_helpers/components.cljc index 843b74a4e..358f08d3b 100644 --- a/common/test/app/common/test_helpers/components.cljc +++ b/common/test/app/common/test_helpers/components.cljc @@ -3,7 +3,8 @@ [clojure.test :as t] [app.common.pages.helpers :as cph] [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 @@ -75,7 +76,7 @@ [page root-inst-id libraries] (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-main (cph/get-children-with-self (:objects component) (:shape-ref root-inst)) @@ -84,10 +85,10 @@ main-exists? (fn [shape] (let [component-shape - (cph/get-component-shape (:objects page) shape) + (ctn/get-component-shape (:objects page) shape) component - (cph/get-component libraries (:component-id component-shape)) + (ctf/get-component libraries (:component-id component-shape)) main-shape (ctn/get-shape component (:shape-ref shape))] @@ -111,7 +112,7 @@ [page root-inst-id libraries] (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-main (cph/get-children-with-self (:objects component) (:shape-ref root-inst)) @@ -120,10 +121,10 @@ main-exists? (fn [shape] (let [component-shape - (cph/get-component-shape (:objects page) shape) + (ctn/get-component-shape (:objects page) shape) component - (cph/get-component libraries (:component-id component-shape)) + (ctf/get-component libraries (:component-id component-shape)) main-shape (ctn/get-shape component (:shape-ref shape))] @@ -138,7 +139,7 @@ (defn resolve-component "Get the component with the given id and all its shapes." [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) shapes-main (cph/get-children-with-self (:objects component) (:id root-main))] diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index fe64a5d41..acc8179e8 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -18,6 +18,7 @@ [app.common.spec :as us] [app.common.text :as txt] [app.common.transit :as t] + [app.common.types.container :as ctn] [app.common.types.shape :as cts] [app.common.types.shape-tree :as ctst] [app.common.uuid :as uuid] @@ -641,8 +642,8 @@ (not (:component-root? shape))) parent (get objects parent-id) - component-shape (cph/get-component-shape objects shape) - component-shape-parent (cph/get-component-shape objects parent) + component-shape (ctn/get-component-shape objects shape) + component-shape-parent (ctn/get-component-shape objects parent) detach? (and instance-part? (not= (:id component-shape) (:id component-shape-parent))) @@ -1406,7 +1407,7 @@ ;; Check if the shape is an instance whose master is defined in a ;; library that is not linked to the current file (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)] (and (some? root) (not= root-file-id (:current-file-id state)) diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 5a8dadce2..c290269b1 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -367,7 +367,7 @@ ptk/WatchEvent (watch [it 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) unames (into #{} (map :name) all-components) new-name (ctst/generate-unique-name unames (:name component)) @@ -484,7 +484,7 @@ (watch [it state _] (let [file (wsh/get-local-file state) 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) (pcb/with-container container) @@ -500,7 +500,7 @@ (let [page-id (:current-page-id state) objects (wsh/lookup-page-objects state page-id) file (wsh/get-local-file state) - container (cph/get-container file :page page-id) + container (ctf/get-container file :page page-id) selected (->> state (wsh/lookup-selected) (cph/clean-loops objects)) @@ -557,7 +557,7 @@ libraries (wsh/get-libraries 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 (features/active-feature? state :components-v2) @@ -593,7 +593,7 @@ local-file (wsh/get-local-file 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) changes diff --git a/frontend/src/app/main/data/workspace/libraries_helpers.cljs b/frontend/src/app/main/data/workspace/libraries_helpers.cljs index 565cd1b93..ae225fa59 100644 --- a/frontend/src/app/main/data/workspace/libraries_helpers.cljs +++ b/frontend/src/app/main/data/workspace/libraries_helpers.cljs @@ -18,6 +18,7 @@ [app.common.types.color :as ctc] [app.common.types.component :as ctk] [app.common.types.container :as ctn] + [app.common.types.file :as ctf] [app.common.types.shape-tree :as ctst] [app.common.types.typography :as cty] [app.main.data.workspace.groups :as dwg] @@ -126,7 +127,7 @@ (defn generate-instantiate-component "Generate changes to create a new instance from a component." [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] (ctn/make-component-instance page component file-id position) @@ -190,7 +191,7 @@ asset-id library-id state - (cph/make-container page :page) + (ctn/make-container page :page) components-v2))) changes)))) @@ -226,7 +227,7 @@ asset-id library-id state - (cph/make-container local-component :component) + (ctn/make-container local-component :component) components-v2))) changes)))) @@ -235,7 +236,7 @@ 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] - (if (cph/page? container) + (if (ctn/page? 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))) @@ -450,7 +451,7 @@ [changes libraries container shape-id reset? components-v2] (log/debug :msg "Sync shape direct" :shape (str shape-id) :reset? reset?) (let [shape-inst (ctn/get-shape container shape-id) - component (cph/get-component libraries + component (ctf/get-component libraries (:component-file shape-inst) (:component-id shape-inst)) shape-main (when component @@ -582,7 +583,7 @@ [changes libraries container shape-id] (log/debug :msg "Sync shape inverse" :shape (str 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-id shape-inst)) shape-main (ctn/get-shape component (:shape-ref shape-inst)) @@ -612,7 +613,7 @@ (if (nil? shape-main) ;; This should not occur, but protect against it in any case changes - (let [component-container (cph/make-container component :component) + (let [component-container (ctn/make-container component :component) omit-touched? false set-remote-synced? (not initial-root?) @@ -819,7 +820,7 @@ :shapes all-parents})) 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'))) @@ -902,7 +903,7 @@ (defn- remove-shape [changes shape container omit-touched?] (log/info :msg (str "REMOVE-SHAPE " - (if (cph/page? container) "[P] " "[C] ") + (if (ctn/page? container) "[P] " "[C] ") (:name shape))) (let [objects (get container :objects) parents (cph/get-parent-ids objects (:id shape)) @@ -940,14 +941,14 @@ changes' (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'))) (defn- move-shape [changes shape index-before index-after container omit-touched?] (log/info :msg (str "MOVE " - (if (cph/page? container) "[P] " "[C] ") + (if (ctn/page? container) "[P] " "[C] ") (:name shape) " " index-before @@ -971,7 +972,7 @@ :index index-before :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'))) @@ -983,7 +984,7 @@ changes (do (log/info :msg (str "CHANGE-TOUCHED " - (if (cph/page? container) "[P] " "[C] ") + (if (ctn/page? container) "[P] " "[C] ") (:name dest-shape)) :options options) (let [new-touched (cond @@ -1018,7 +1019,7 @@ changes (do (log/info :msg (str "CHANGE-REMOTE-SYNCED? " - (if (cph/page? container) "[P] " "[C] ") + (if (ctn/page? container) "[P] " "[C] ") (:name shape)) :remote-synced? remote-synced?) (-> changes @@ -1048,7 +1049,7 @@ (log/info :msg (str "SYNC " (:name origin-shape) " -> " - (if (cph/page? container) "[P] " "[C] ") + (if (ctn/page? container) "[P] " "[C] ") (:name dest-shape))) (let [; To synchronize geometry attributes we need to make a prior @@ -1127,7 +1128,7 @@ (defn- make-change [container change] - (if (cph/page? container) + (if (ctn/page? container) (assoc change :page-id (:id container)) (assoc change :component-id (:id container)))) diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 84ba8d689..054eb33c6 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -16,6 +16,7 @@ [app.common.pages.common :as cpc] [app.common.pages.helpers :as cph] [app.common.spec :as us] + [app.common.types.container :as ctn] [app.common.types.shape-tree :as ctst] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.collapse :as dwc] @@ -249,7 +250,7 @@ shape (nil? root) - (cph/get-root-shape objects shape) + (ctn/get-root-shape objects shape) :else root) @@ -259,7 +260,7 @@ transformed-shape (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 $))))) :else transformed-root) diff --git a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs index 2f4207e14..4e796747e 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs @@ -11,6 +11,10 @@ [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] [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.store :as st] [app.main.ui.workspace.viewport.utils :as vwu] [app.util.dom :as dom] @@ -249,6 +253,21 @@ (dom/remove-attribute! node "data-old-transform") (dom/remove-attribute! node "transform"))))))))) +(defn get-copy-shapes + "If one or more of the shapes belongs to a component's main instance, find all copies of + the component in the same page. Ignore copies with the geometry values touched." + [shapes objects] + (letfn [(get-copy-shapes-one [shape] + (let [root-shape (ctn/get-root-shape objects shape)] + (when (:main-instance? root-shape) + (->> (ctn/get-instances objects shape) + (filter #(not (ctk/touched-group? % :geometry-group))))))) + + (pack-main-copies [shape] + (map #(vector shape %) (get-copy-shapes-one shape)))] + + (mapcat pack-main-copies shapes))) + (defn use-dynamic-modifiers [objects node modifiers] @@ -277,7 +296,187 @@ prev-shapes (mf/use-var nil) prev-modifiers (mf/use-var nil) - prev-transforms (mf/use-var nil)] + prev-transforms (mf/use-var nil) + + copy-shapes + (mf/use-memo + (mf/deps (and (d/not-empty? @prev-modifiers) (d/not-empty? modifiers))) + (fn [] + (get-copy-shapes shapes objects))) + + transforms + (mf/use-memo + (mf/deps objects modifiers transforms copy-shapes) + (fn [] + (let [add-copy-transforms + (fn [transforms main-shape copy-shape] + (let [main-bounds (gsh/bounding-box main-shape) + copy-bounds (gsh/bounding-box copy-shape) + delta (gpt/subtract (gpt/point (:x copy-bounds) (:y copy-bounds)) + (gpt/point (:x main-bounds) (:y main-bounds))) + + ;; Move the modifier origin points to the position of the copy. + main-modifiers (get-in modifiers [(:id main-shape) :modifiers]) + copy-modifiers (let [origin (:resize-origin main-modifiers) + origin-2 (:resize-origin-2 main-modifiers)] + (cond-> main-modifiers + (some? origin) + (assoc :resize-origin (gpt/add origin delta)) + + (some? origin-2) + (assoc :resize-origin-2 (gpt/add origin-2 delta)))) + + center (gsh/center-shape copy-shape)] + + (update transforms (:id copy-shape) + #(let [transform (or % (gmt/matrix))] + (gmt/multiply transform + (gsh/modifiers->transform center copy-modifiers)))))) + + apply-delta + (fn [transforms shape-id delta] + (let [shape-ids (-> (cph/get-children-ids objects shape-id) + (conj shape-id)) + + add-delta (fn [transform] + (let [transform (or transform (gmt/matrix))] + (gmt/multiply transform (gmt/translate-matrix delta))))] + + (reduce #(update %1 %2 add-delta) + transforms + shape-ids))) + + manage-root + (fn [transforms main-shape copy-shape] + (let [main-modifiers (get-in modifiers [(:id main-shape) :modifiers]) + modified-main (gsh/apply-modifiers main-shape main-modifiers) + + delta (gpt/subtract (gsh/orig-pos main-shape) + (gsh/orig-pos modified-main))] + + (cond-> transforms + (not (gpt/almost-zero? delta)) + (apply-delta (:id copy-shape) delta)))) + + manage-nonroot + (fn [transforms main-shape copy-shape] + ; TODO: comparar el orig-pos de la main-shape modificada con el del su propio + ; root también modificado (antes de rotación). Si es menor que cero en alguno + ; de los dos ejes, añadir un desplazamiento al root y todos sus hijos + (let [main-root (ctn/get-root-shape objects main-shape) + main-root-modifiers (get-in modifiers [(:id main-root) :modifiers]) + modified-main-root (gsh/apply-modifiers main-root main-root-modifiers) + + main-shape-modifiers (get-in modifiers [(:id main-shape) :modifiers]) + modified-main-shape (gsh/apply-modifiers main-shape main-shape-modifiers) + + delta (gpt/subtract (gsh/orig-pos modified-main-shape) + (gsh/orig-pos modified-main-root)) + + delta-x (- (min 0 (:x delta))) + delta-y (- (min 0 (:y delta)))] + + (if (or (pos? delta-x) (pos? delta-y)) + (let [copy-root (ctn/get-root-shape objects copy-shape)] + (apply-delta transforms (:id copy-root) (gpt/point delta-x delta-y))) + transforms))) + + add-all-transforms + (fn [transforms [main-shape copy-shape]] + (js/console.log "----------------------") + (js/console.log "main-shape" (clj->js main-shape)) + (js/console.log "copy-shape" (clj->js copy-shape)) + (as-> transforms $ + (add-copy-transforms $ main-shape copy-shape) + (if (ctk/instance-root? main-shape) + (manage-root $ main-shape copy-shape) + (manage-nonroot $ main-shape copy-shape))))] + + (js/console.log "==================") + (reduce add-all-transforms + transforms + copy-shapes)))) + + ;; (let [translate1 + ;; (fn [shape modifiers] + ;; (let [root-shape (ctn/get-root-shape objects shape) + ;; root-pos (gsh/orig-pos root-shape) + ;; + ;; modified-shape (gsh/apply-modifiers shape modifiers) + ;; modified-pos (gsh/orig-pos modified-shape)] + ;; ;; (js/console.log "root-pos" (clj->js root-pos)) + ;; ;; (js/console.log "modified-pos" (clj->js modified-pos)) + ;; (if (or (< (:x modified-pos) (:x root-pos)) + ;; (< (:y modified-pos) (:y root-pos))) + ;; (let [displacement (get modifiers :displacement (gmt/matrix)) + ;; delta (gpt/point (max 0 (- (:x root-pos) (:x modified-pos))) + ;; (max 0 (- (:y root-pos) (:y modified-pos))))] + ;; [(assoc modifiers :displacement + ;; (gmt/add-translate displacement + ;; (gmt/translate-matrix delta))) + ;; delta]) + ;; [modifiers (gpt/point 0 0)]))) + ;; + ;; get-copy-transform + ;; (fn [[main-shape copy-shape]] + ;; (js/console.log "----------------------") + ;; (js/console.log "main-shape" (clj->js main-shape)) + ;; (js/console.log "copy-shape" (clj->js copy-shape)) + ;; (let [[main-modifiers deltaa] (->> (get-in modifiers [(:id main-shape) :modifiers]) + ;; (translate1 main-shape)) + ;; + ;; main-bounds (gsh/bounding-box main-shape) + ;; copy-bounds (gpt/add (gpt/point + ;; (:x (gsh/bounding-box copy-shape)) + ;; (:y (gsh/bounding-box copy-shape))) + ;; deltaa) + ;; delta (gpt/subtract (gpt/point (:x copy-bounds) (:y copy-bounds)) + ;; (gpt/point (:x main-bounds) (:y main-bounds))) + ;; + ;; root-shape (ctn/get-root-shape objects main-shape) + ;; root-modifiers (get-in modifiers [(:id root-shape) :modifiers]) + ;; _ (js/console.log "main-modifiers" (clj->js main-modifiers)) + ;; _ (js/console.log "root-modifiers" (clj->js root-modifiers)) + ;; + ;; ;; root-shape (ctn/get-root-shape objects copy-shape) + ;; ;; root-pos (gsh/orig-pos root-shape) + ;; ;; copy-pos (gsh/orig-pos copy-shape) + ;; + ;; ;; Move the modifier origin points to the position of the copy. + ;; copy-modifiers (let [origin (:resize-origin main-modifiers) + ;; origin-2 (:resize-origin-2 main-modifiers)] + ;; (cond-> main-modifiers + ;; (some? origin) + ;; (assoc :resize-origin (gpt/add origin delta)) + ;; + ;; (some? origin-2) + ;; (assoc :resize-origin-2 (gpt/add origin-2 delta)) + ;; + ;; ;; (gpt/close? root-pos copy-pos) + ;; ;; (dissoc :displacement) + ;; )) + ;; + ;; center (gsh/center-shape copy-shape)] + ;; + ;; ;; (js/console.log "delta" (clj->js delta)) + ;; ;; (js/console.log "main-modifiers" (clj->js main-modifiers)) + ;; ;; (js/console.log "main-transform" (str (gsh/modifiers->transform + ;; ;; (gsh/center-shape main-shape) + ;; ;; main-modifiers))) + ;; ;; (js/console.log "copy-modifiers" (clj->js copy-modifiers)) + ;; ;; (js/console.log "copy-transform" (str (gsh/modifiers->transform + ;; ;; center copy-modifiers))) + ;; (gsh/modifiers->transform center copy-modifiers)))] + ;; + ;; (reduce #(assoc %1 (:id (second %2)) (get-copy-transform %2)) + ;; transforms + ;; copy-shapes)))) + + shapes + (mf/use-memo + (mf/deps transforms) + (fn [] + (map #(get objects %) (keys transforms))))] (mf/use-layout-effect (mf/deps transforms) diff --git a/frontend/test/app/components_basic_test.cljs b/frontend/test/app/components_basic_test.cljs index f419b9646..5846414e2 100644 --- a/frontend/test/app/components_basic_test.cljs +++ b/frontend/test/app/components_basic_test.cljs @@ -302,7 +302,7 @@ ; Renamed component ; Rect-1 (let [libs (wsh/get-libraries new-state) - component (cph/get-component libs + component (ctf/get-component libs (:component-file instance1) (:component-id instance1))] (t/is (= (:name component) @@ -400,7 +400,7 @@ (:id instance1)) libs (wsh/get-libraries new-state) - component (cph/get-component libs + component (ctf/get-component libs (:component-file instance1) (:component-id instance1))] diff --git a/frontend/test/app/test_helpers/libraries.cljs b/frontend/test/app/test_helpers/libraries.cljs index 8a2a2b8fe..717d77b3e 100644 --- a/frontend/test/app/test_helpers/libraries.cljs +++ b/frontend/test/app/test_helpers/libraries.cljs @@ -5,6 +5,7 @@ [app.common.pages.helpers :as cph] [app.common.types.component :as ctk] [app.common.types.container :as ctn] + [app.common.types.file :as ctf] [app.main.data.workspace.state-helpers :as wsh] [app.test-helpers.pages :as thp])) @@ -85,7 +86,7 @@ root-inst (ctn/get-shape page root-inst-id) 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-main (cph/get-children-with-self (:objects component) (:shape-ref root-inst)) @@ -94,10 +95,10 @@ main-exists? (fn [shape] (let [component-shape - (cph/get-component-shape (:objects page) shape) + (ctn/get-component-shape (:objects page) shape) component - (cph/get-component libs (:component-id component-shape)) + (ctf/get-component libs (:component-id component-shape)) main-shape (ctn/get-shape component (:shape-ref shape))] @@ -125,7 +126,7 @@ root-inst (ctn/get-shape page root-inst-id) 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-main (cph/get-children-with-self (:objects component) (:shape-ref root-inst)) @@ -134,10 +135,10 @@ main-exists? (fn [shape] (let [component-shape - (cph/get-component-shape (:objects page) shape) + (ctn/get-component-shape (:objects page) shape) component - (cph/get-component libs (:component-id component-shape)) + (ctf/get-component libs (:component-id component-shape)) main-shape (ctn/get-shape component (:shape-ref shape))] @@ -154,7 +155,7 @@ [state component-id] (let [page (thp/current-page 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) shapes-main (cph/get-children-with-self (:objects component) (:id root-main))]