Compare commits

...

10 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

View File

@@ -59,6 +59,21 @@
[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 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?
"Checks if one rect is fully inside the other"
[rect other]
@@ -182,6 +197,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

View File

@@ -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)
@@ -472,7 +473,7 @@
(defmulti components-changed (fn [_ change] (:type change)))
(defmethod components-changed :mod-obj
[file-data {:keys [id page-id _component-id operations]}]
[file-data {:keys [id page-id operations]}]
(when page-id
(let [page (ctpl/get-page file-data page-id)
shape-and-parents (map #(ctn/get-shape page %)

View File

@@ -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))))

View File

@@ -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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View File

@@ -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= (:id shape-main) (:id 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))

View File

@@ -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

View File

@@ -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))

View File

@@ -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?

View File

@@ -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))]

View File

@@ -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))

View File

@@ -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
@@ -721,7 +721,13 @@
(when sync-typographies?
(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
(:redo-changes changes)
@@ -842,10 +848,25 @@
check-changes
(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))
#{}
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?)
(log/info :msg "DETECTED COMPONENTS CHANGED"
:ids (map str components-changed))
@@ -890,6 +911,7 @@
(let [state (dissoc state :files)]
(assoc state :workspace-shared-files files)))))
(defn fetch-shared-files
[{:keys [team-id] :as params}]
(us/assert ::us/uuid team-id)

View File

@@ -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))))

View File

@@ -16,6 +16,8 @@
[app.common.pages.common :as cpc]
[app.common.pages.helpers :as cph]
[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.main.data.workspace.changes :as dch]
[app.main.data.workspace.collapse :as dwc]
@@ -30,6 +32,100 @@
[cljs.spec.alpha :as s]
[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 --------------------------------------------------------
;; For each of the 8 handlers gives the multiplier for resize
@@ -137,10 +233,22 @@
(contains? (:workspace-layout state) :snap-pixel-grid))
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))))))
;; (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).
(defn- set-rotation-modifiers
([angle shapes]
@@ -249,7 +357,7 @@
shape
(nil? root)
(cph/get-root-shape objects shape)
(ctn/get-root-shape objects shape)
:else root)
@@ -259,7 +367,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)

View File

@@ -300,7 +300,6 @@
[ids]
(l/derived #(select-keys % ids) workspace-modifiers))
(def workspace-modifiers-with-objects
(l/derived
(fn [state]

View File

@@ -11,9 +11,15 @@
[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.data.workspace.transforms :as dwt]
[app.main.store :as st]
[app.main.ui.workspace.viewport.utils :as vwu]
[app.util.dom :as dom]
[app.util.timers :as tm]
[rumext.v2 :as mf]))
(defn- transform-no-resize
@@ -252,11 +258,15 @@
(defn use-dynamic-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/deps modifiers)
(fn []
(when (some? modifiers)
(when (seq modifiers)
(d/mapm (fn [id {modifiers :modifiers}]
(let [shape (get objects id)
center (gsh/center-shape shape)
@@ -273,11 +283,7 @@
(mf/deps transforms)
(fn []
(->> (keys transforms)
(mapv (d/getf objects)))))
prev-shapes (mf/use-var nil)
prev-modifiers (mf/use-var nil)
prev-transforms (mf/use-var nil)]
(map (d/getf objects)))))]
(mf/use-layout-effect
(mf/deps transforms)

View File

@@ -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))]

View File

@@ -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))]