diff --git a/common/src/app/common/logic/libraries.cljc b/common/src/app/common/logic/libraries.cljc index 5e4ec03656..d5c8f112f5 100644 --- a/common/src/app/common/logic/libraries.cljc +++ b/common/src/app/common/logic/libraries.cljc @@ -260,6 +260,27 @@ :include-deleted? true))] (recur shape-inst' next-data component'))))))) +(defn- main-in-parent-orientation + "Place a main in the orientation of an ordinary instance parent. Such a + parent can survive detach, while the nested copy stays untouched." + [main-container shape-main container shape-inst] + (let [parent (ctn/get-shape container (:parent-id shape-inst)) + main-parent (get-in main-container [:objects (:parent-id shape-main)]) + relative (gmt/multiply (or (:transform parent) (gmt/matrix)) + (or (:transform-inverse main-parent) (gmt/matrix)))] + (if (or (nil? parent) (:shape-ref parent) (gmt/unit? relative)) + main-container + (let [transform (gmt/transform-in (gsh/shape->center shape-main) relative) + angle (- (or (:rotation parent) 0) (or (:rotation main-parent) 0)) + turn #(-> % + (assoc-in [:modifiers :rotation] angle) + (gsh/apply-transform transform) + (dissoc :modifiers))] + (update main-container :objects + (fn [objects] + (reduce #(update %1 %2 turn) objects + (cfh/get-children-ids-with-self objects (:id shape-main))))))))) + (defn- generate-sync-shape-direct "Generate changes to synchronize one shape that is the root of a component instance, and all its children, from the given component." @@ -275,11 +296,14 @@ (let [shape-main (if reset? ;; the reset is against the ref-shape, not against the original shape of the component (ctf/find-ref-shape file container libraries shape-inst :include-deleted? true) - (ctf/get-content-ref-shape library component shape-inst))] + (ctf/get-content-ref-shape library component shape-inst)) + main-container (find-main-container container shape-inst shape-main + library file libraries component) + main-container (main-in-parent-orientation main-container shape-main container shape-inst) + shape-main (ctn/get-shape main-container (:id shape-main))] (sync-copy-recursive changes {:container container - :main-container (find-main-container container shape-inst shape-main - library file libraries component) + :main-container main-container :component component :library library :root-inst shape-inst diff --git a/common/test/common_tests/logic/comp_expected_geometry_test.cljc b/common/test/common_tests/logic/comp_expected_geometry_test.cljc index 9a6f150a5d..0399ae1719 100644 --- a/common/test/common_tests/logic/comp_expected_geometry_test.cljc +++ b/common/test/common_tests/logic/comp_expected_geometry_test.cljc @@ -21,6 +21,7 @@ [app.common.test-helpers.components :as thc] [app.common.test-helpers.composable.comp.nodes :as n] [app.common.test-helpers.composable.comp.runner :as r] + [app.common.test-helpers.composable.comp.setups :as setup] [app.common.test-helpers.composable.core :as tm] [app.common.test-helpers.compositions :as tho] [app.common.test-helpers.files :as thf] @@ -34,6 +35,20 @@ (t/use-fixtures :each thi/test-fixture) +(t/deftest a-nested-copy-keeps-its-detached-parents-orientation-on-sync + (let [detached (-> (setup/nested-component-with-copy) + (r/step (n/rotate :copy-root 90)) r/settle + (r/step (n/detach :copy-root)) r/settle) + head (tm/role-shape detached :copy-instance) + id (first (:shapes head)) + before (tm/shape-by-id detached id) + synced (-> detached (r/step (n/change-property :main1-child :fills "#ff0000")) r/settle) + after (tm/shape-by-id synced id)] + (t/is (= "#ff0000" (-> after :fills first :fill-color))) + (t/is (gsh/close-attrs? :points (:points before) (:points after) 0.001)) + (t/is (= (:rotation before) (:rotation after))) + (t/is (nil? (:touched after))))) + (defn- component-with-child "A 100x100 main board with a 20x20 rect at (70, 10) of it, constrained `constraints-h`, and a copy of it at (300, 0)."