diff --git a/common/src/app/common/geom/shapes/flex_layout/params.cljc b/common/src/app/common/geom/shapes/flex_layout/params.cljc index 57a1fab63d..0d7d67ba1b 100644 --- a/common/src/app/common/geom/shapes/flex_layout/params.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/params.cljc @@ -88,8 +88,8 @@ parent-selrect (:selrect parent) padding (when (and (not (nil? parent)) (> (count shapes) 0)) - {:p1 (- min-y (:y1 parent-selrect)) - :p2 (- min-x (:x1 parent-selrect))})] + {:p1 (max 0 (- min-y (:y1 parent-selrect))) + :p2 (max 0 (- min-x (:x1 parent-selrect)))})] (cond-> {:layout-flex-dir direction :layout-gap layout-gap} (not (nil? padding)) diff --git a/common/src/app/common/geom/shapes/grid_layout/params.cljc b/common/src/app/common/geom/shapes/grid_layout/params.cljc index ee3a779942..e310dfadd1 100644 --- a/common/src/app/common/geom/shapes/grid_layout/params.cljc +++ b/common/src/app/common/geom/shapes/grid_layout/params.cljc @@ -154,8 +154,8 @@ layout-grid-columns (mapv (constantly ctl/default-track-value) cols) parent-childs-vector (gpt/to-vec (gpo/origin (:points parent)) (gpt/point all-shapes-rect)) - p-left (:x parent-childs-vector) - p-top (:y parent-childs-vector)] + p-left (max 0 (:x parent-childs-vector)) + p-top (max 0 (:y parent-childs-vector))] (-> {:layout-grid-columns layout-grid-columns :layout-grid-rows layout-grid-rows diff --git a/common/test/common_tests/geom_flex_layout_test.cljc b/common/test/common_tests/geom_flex_layout_test.cljc index c016daeea7..4e6f6a149c 100644 --- a/common/test/common_tests/geom_flex_layout_test.cljc +++ b/common/test/common_tests/geom_flex_layout_test.cljc @@ -7,6 +7,7 @@ (ns common-tests.geom-flex-layout-test (:require [app.common.geom.rect :as grc] + [app.common.geom.shapes.flex-layout.params :as flparams] [app.common.geom.shapes.flex-layout.positions :as flp] [app.common.math :as mth] [app.common.types.shape :as cts] @@ -104,3 +105,33 @@ :layout-justify-content :end :x 0 :y 0 :width 100 :height 100})] (t/is (not (ctl/v-end? frame)))))) + +;; ---- calculate-params paddings ---- +;; +;; Adding a flex layout derives the paddings from the distance between the +;; board and its children. A child that overflows the board, or floating +;; point noise after "Resize board to fit content", gave negative paddings +;; that the shape schema rejects, which broke autosave (#12107). + +(defn- params-for-child + [child-attrs] + (let [parent (cts/setup-shape {:type :frame :x 0 :y 0 :width 100 :height 100}) + child (cts/setup-shape (merge {:type :rect :parent-id (:id parent)} child-attrs)) + parent (assoc parent :shapes [(:id child)]) + objects {(:id parent) parent (:id child) child}] + (flparams/calculate-params objects [child] parent))) + +(t/deftest calculate-params-keeps-positive-padding + (t/is (= {:p1 20 :p2 10 :p3 20 :p4 10} + (:layout-padding (params-for-child {:x 10 :y 20 :width 50 :height 50}))))) + +(t/deftest calculate-params-clamps-overflowing-child-padding + (t/is (= {:p1 0 :p2 0 :p3 0 :p4 0} + (:layout-padding (params-for-child {:x -10 :y -5 :width 150 :height 150}))))) + +(t/deftest calculate-params-clamps-float-noise-padding + (let [padding (:layout-padding + (params-for-child {:x -1.1728368917829357E-5 + :y -2.1457672119140625E-6 + :width 100 :height 100}))] + (t/is (every? #(not (neg? %)) (vals padding))))) diff --git a/common/test/common_tests/geom_grid_layout_test.cljc b/common/test/common_tests/geom_grid_layout_test.cljc index 1769ab634a..ac642b2d43 100644 --- a/common/test/common_tests/geom_grid_layout_test.cljc +++ b/common/test/common_tests/geom_grid_layout_test.cljc @@ -11,6 +11,7 @@ [app.common.geom.modifiers] [app.common.geom.rect :as grc] [app.common.geom.shapes.grid-layout.layout-data :as gld] + [app.common.geom.shapes.grid-layout.params :as glparams] [app.common.math :as mth] [app.common.types.shape :as cts] [clojure.test :as t])) @@ -408,3 +409,27 @@ result (gld/set-auto-multi-span (auto-col-parent) tracks cmap cells frame-bounds {} :column)] (t/is (mth/close? 100.0 (:size (nth result 0)) 0.001)) (t/is (mth/close? 100.0 (:size (nth result 1)) 0.001))))) + +;; --------------------------------------------------------------------------- +;; calculate-params: derived paddings are never negative +;; --------------------------------------------------------------------------- +;; +;; Adding a grid layout derives the paddings from the children. A child that +;; overflows the board gave negative paddings that the shape schema rejects, +;; which broke autosave (#12107). + +(defn- grid-params-for-children + [& children-attrs] + (let [parent (cts/setup-shape {:type :frame :x 0 :y 0 :width 100 :height 100}) + children (mapv #(cts/setup-shape (merge {:type :rect :parent-id (:id parent)} %)) + children-attrs)] + (glparams/calculate-params nil children parent))) + +(t/deftest grid-calculate-params-keeps-positive-padding + (let [params (grid-params-for-children {:x 10 :y 20 :width 30 :height 30})] + (t/is (mth/close? 20 (get-in params [:layout-padding :p1]))) + (t/is (mth/close? 10 (get-in params [:layout-padding :p2]))))) + +(t/deftest grid-calculate-params-clamps-overflowing-child-padding + (let [params (grid-params-for-children {:x -10 :y -5 :width 150 :height 150})] + (t/is (= {:p1 0 :p2 0 :p3 0 :p4 0} (:layout-padding params)))))