From 65598aa724df74113013eee5b8eb3e66e1dea7fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Fri, 7 Jul 2023 17:31:11 +0200 Subject: [PATCH] :bug: Fix overlay position when it has shadow or blur --- CHANGES.md | 1 + common/src/app/common/geom/shapes/bounds.cljc | 1 + .../app/common/types/shape/interactions.cljc | 39 ++-- .../types_shape_interactions_test.cljc | 198 ++++++++++++------ frontend/src/app/main/data/viewer.cljs | 9 +- frontend/src/app/main/ui/shapes/frame.cljs | 3 +- frontend/src/app/main/ui/viewer.cljs | 24 +++ .../app/main/ui/viewer/inspect/render.cljs | 3 +- .../src/app/main/ui/viewer/interactions.cljs | 10 +- frontend/src/app/main/ui/viewer/shapes.cljs | 56 +++-- 10 files changed, 242 insertions(+), 102 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 6d7acc4a3..44d750ebd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -65,6 +65,7 @@ - Fix shortcuts translations not homogenized [Taiga #5141](https://tree.taiga.io/project/penpot/issue/5141) - Fix overlay manual position in nested boards [Taiga #5135](https://tree.taiga.io/project/penpot/issue/5135) - Fix close overlay from a nested board [Taiga #5587](https://tree.taiga.io/project/penpot/issue/5587) +- Fix overlay position when it has shadow or blur [Taiga #4752](https://tree.taiga.io/project/penpot/issue/4752) ### :arrow_up: Deps updates diff --git a/common/src/app/common/geom/shapes/bounds.cljc b/common/src/app/common/geom/shapes/bounds.cljc index 9bb6686f6..92139415f 100644 --- a/common/src/app/common/geom/shapes/bounds.cljc +++ b/common/src/app/common/geom/shapes/bounds.cljc @@ -147,6 +147,7 @@ :else (cph/reduce-objects objects + (fn [shape] (and (d/not-empty? (:shapes shape)) (or (not (cph/frame-shape? shape)) diff --git a/common/src/app/common/types/shape/interactions.cljc b/common/src/app/common/types/shape/interactions.cljc index 5bfa90681..61ef1ebea 100644 --- a/common/src/app/common/types/shape/interactions.cljc +++ b/common/src/app/common/types/shape/interactions.cljc @@ -526,37 +526,46 @@ overlay-position {:x (- (:x overlay-position) (:x relative-to-adjusted-to-base-frame)) :y (- (:y overlay-position) (:y relative-to-adjusted-to-base-frame))})] + (case (:overlay-pos-type interaction) :center - (gpt/point (+ (:x base-position) (/ (- (:width relative-to-shape-size) (:width overlay-size)) 2)) - (+ (:y base-position) (/ (- (:height relative-to-shape-size) (:height overlay-size)) 2))) + [(gpt/point (+ (:x base-position) (/ (- (:width relative-to-shape-size) (:width overlay-size)) 2)) + (+ (:y base-position) (/ (- (:height relative-to-shape-size) (:height overlay-size)) 2))) + [:center :center]] :top-left - (gpt/point (:x base-position) (:y base-position)) + [(gpt/point (:x base-position) (:y base-position)) + [:top :left]] :top-right - (gpt/point (+ (:x base-position) (- (:width relative-to-shape-size) (:width overlay-size))) - (:y base-position)) + [(gpt/point (+ (:x base-position) (- (:width relative-to-shape-size) (:width overlay-size))) + (:y base-position)) + [:top :right]] :top-center - (gpt/point (+ (:x base-position) (/ (- (:width relative-to-shape-size) (:width overlay-size)) 2)) - (:y base-position)) + [(gpt/point (+ (:x base-position) (/ (- (:width relative-to-shape-size) (:width overlay-size)) 2)) + (:y base-position)) + [:top :center]] :bottom-left - (gpt/point (:x base-position) - (+ (:y base-position) (- (:height relative-to-shape-size) (:height overlay-size)))) + [(gpt/point (:x base-position) + (+ (:y base-position) (- (:height relative-to-shape-size) (:height overlay-size)))) + [:bottom :left]] :bottom-right - (gpt/point (+ (:x base-position) (- (:width relative-to-shape-size) (:width overlay-size))) - (+ (:y base-position) (- (:height relative-to-shape-size) (:height overlay-size)))) + [(gpt/point (+ (:x base-position) (- (:width relative-to-shape-size) (:width overlay-size))) + (+ (:y base-position) (- (:height relative-to-shape-size) (:height overlay-size)))) + [:bottom :right]] :bottom-center - (gpt/point (+ (:x base-position) (/ (- (:width relative-to-shape-size) (:width overlay-size)) 2)) - (+ (:y base-position) (- (:height relative-to-shape-size) (:height overlay-size)))) + [(gpt/point (+ (:x base-position) (/ (- (:width relative-to-shape-size) (:width overlay-size)) 2)) + (+ (:y base-position) (- (:height relative-to-shape-size) (:height overlay-size)))) + [:bottom :center]] :manual - (gpt/point (+ (:x base-position) (:x overlay-position)) - (+ (:y base-position) (:y overlay-position)))))))) + [(gpt/point (+ (:x base-position) (:x overlay-position)) + (+ (:y base-position) (:y overlay-position))) + [:top :left]]))))) (defn has-animation? [interaction] diff --git a/common/test/common_tests/types_shape_interactions_test.cljc b/common/test/common_tests/types_shape_interactions_test.cljc index 4411d86f1..34fd3d47b 100644 --- a/common/test/common_tests/types_shape_interactions_test.cljc +++ b/common/test/common_tests/types_shape_interactions_test.cljc @@ -324,209 +324,275 @@ interaction-rect (ctsi/set-position-relative-to interaction (:id rect))] (t/testing "Overlay top-left relative to auto" (let [i2 (ctsi/set-overlay-pos-type interaction-auto :top-left base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 0)) - (t/is (= (:y overlay-pos) 0)))) + (t/is (= (:y overlay-pos) 0)) + (t/is (= snap-v :top)) + (t/is (= snap-h :left)))) (t/testing "Overlay top-center relative to auto" (let [i2 (ctsi/set-overlay-pos-type interaction-auto :top-center base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 35)) - (t/is (= (:y overlay-pos) 0)))) + (t/is (= (:y overlay-pos) 0)) + (t/is (= snap-v :top)) + (t/is (= snap-h :center)))) (t/testing "Overlay top-right relative to auto" (let [i2 (ctsi/set-overlay-pos-type interaction-auto :top-right base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 70)) - (t/is (= (:y overlay-pos) 0)))) + (t/is (= (:y overlay-pos) 0)) + (t/is (= snap-v :top)) + (t/is (= snap-h :right)))) (t/testing "Overlay bottom-left relative to auto" (let [i2 (ctsi/set-overlay-pos-type interaction-auto :bottom-left base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 0)) - (t/is (= (:y overlay-pos) 80)))) + (t/is (= (:y overlay-pos) 80)) + (t/is (= snap-v :bottom)) + (t/is (= snap-h :left)))) (t/testing "Overlay bottom-center relative to auto" (let [i2 (ctsi/set-overlay-pos-type interaction-auto :bottom-center base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 35)) - (t/is (= (:y overlay-pos) 80)))) + (t/is (= (:y overlay-pos) 80)) + (t/is (= snap-v :bottom)) + (t/is (= snap-h :center)))) (t/testing "Overlay bottom-right relative to auto" (let [i2 (ctsi/set-overlay-pos-type interaction-auto :bottom-right base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 70)) - (t/is (= (:y overlay-pos) 80)))) + (t/is (= (:y overlay-pos) 80)) + (t/is (= snap-v :bottom)) + (t/is (= snap-h :right)))) (t/testing "Overlay center relative to auto" (let [i2 (ctsi/set-overlay-pos-type interaction-auto :center base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 35)) - (t/is (= (:y overlay-pos) 40)))) + (t/is (= (:y overlay-pos) 40)) + (t/is (= snap-v :center)) + (t/is (= snap-h :center)))) (t/testing "Overlay manual relative to auto" (let [i2 (ctsi/set-overlay-pos-type interaction-auto :center base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 35)) - (t/is (= (:y overlay-pos) 40)))) + (t/is (= (:y overlay-pos) 40)) + (t/is (= snap-v :center)) + (t/is (= snap-h :center)))) (t/testing "Overlay manual relative to auto" (let [i2 (-> interaction-auto (ctsi/set-overlay-pos-type :manual base-frame objects) (ctsi/set-overlay-position (gpt/point 12 62))) - overlay-pos (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 17)) - (t/is (= (:y overlay-pos) 67)))) + (t/is (= (:y overlay-pos) 67)) + (t/is (= snap-v :top)) + (t/is (= snap-h :left)))) (t/testing "Overlay top-left relative to base-frame" (let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :top-left base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 5)) - (t/is (= (:y overlay-pos) 5)))) + (t/is (= (:y overlay-pos) 5)) + (t/is (= snap-v :top)) + (t/is (= snap-h :left)))) (t/testing "Overlay top-center relative to base-frame" (let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :top-center base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 40)) - (t/is (= (:y overlay-pos) 5)))) + (t/is (= (:y overlay-pos) 5)) + (t/is (= snap-v :top)) + (t/is (= snap-h :center)))) (t/testing "Overlay top-right relative to base-frame" (let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :top-right base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 75)) - (t/is (= (:y overlay-pos) 5)))) + (t/is (= (:y overlay-pos) 5)) + (t/is (= snap-v :top)) + (t/is (= snap-h :right)))) (t/testing "Overlay bottom-left relative to base-frame" (let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :bottom-left base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 5)) - (t/is (= (:y overlay-pos) 85)))) + (t/is (= (:y overlay-pos) 85)) + (t/is (= snap-v :bottom)) + (t/is (= snap-h :left)))) (t/testing "Overlay bottom-center relative to base-frame" (let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :bottom-center base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 40)) - (t/is (= (:y overlay-pos) 85)))) + (t/is (= (:y overlay-pos) 85)) + (t/is (= snap-v :bottom)) + (t/is (= snap-h :center)))) (t/testing "Overlay bottom-right relative to base-frame" (let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :bottom-right base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 75)) - (t/is (= (:y overlay-pos) 85)))) + (t/is (= (:y overlay-pos) 85)) + (t/is (= snap-v :bottom)) + (t/is (= snap-h :right)))) (t/testing "Overlay center relative to base-frame" (let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :center base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 40)) - (t/is (= (:y overlay-pos) 45)))) + (t/is (= (:y overlay-pos) 45)) + (t/is (= snap-v :center)) + (t/is (= snap-h :center)))) (t/testing "Overlay manual relative to base-frame" (let [i2 (-> interaction-base-frame (ctsi/set-overlay-pos-type :manual base-frame objects) (ctsi/set-overlay-position (gpt/point 12 62))) - overlay-pos (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 17)) - (t/is (= (:y overlay-pos) 67)))) + (t/is (= (:y overlay-pos) 67)) + (t/is (= snap-v :top)) + (t/is (= snap-h :left)))) (t/testing "Overlay top-left relative to popup" (let [i2 (ctsi/set-overlay-pos-type interaction-popup :top-left base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 15)) - (t/is (= (:y overlay-pos) 15)))) + (t/is (= (:y overlay-pos) 15)) + (t/is (= snap-v :top)) + (t/is (= snap-h :left)))) (t/testing "Overlay top-center relative to popup" (let [i2 (ctsi/set-overlay-pos-type interaction-popup :top-center base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 25)) - (t/is (= (:y overlay-pos) 15)))) + (t/is (= (:y overlay-pos) 15)) + (t/is (= snap-v :top)) + (t/is (= snap-h :center)))) (t/testing "Overlay top-right relative to popup" (let [i2 (ctsi/set-overlay-pos-type interaction-popup :top-right base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 35)) - (t/is (= (:y overlay-pos) 15)))) + (t/is (= (:y overlay-pos) 15)) + (t/is (= snap-v :top)) + (t/is (= snap-h :right)))) (t/testing "Overlay bottom-left relative to popup" (let [i2 (ctsi/set-overlay-pos-type interaction-popup :bottom-left base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 15)) - (t/is (= (:y overlay-pos) 45)))) + (t/is (= (:y overlay-pos) 45)) + (t/is (= snap-v :bottom)) + (t/is (= snap-h :left)))) (t/testing "Overlay bottom-center relative to popup" (let [i2 (ctsi/set-overlay-pos-type interaction-popup :bottom-center base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 25)) - (t/is (= (:y overlay-pos) 45)))) + (t/is (= (:y overlay-pos) 45)) + (t/is (= snap-v :bottom)) + (t/is (= snap-h :center)))) (t/testing "Overlay bottom-right relative to popup" (let [i2 (ctsi/set-overlay-pos-type interaction-popup :bottom-right base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 35)) - (t/is (= (:y overlay-pos) 45)))) + (t/is (= (:y overlay-pos) 45)) + (t/is (= snap-v :bottom)) + (t/is (= snap-h :right)))) (t/testing "Overlay center relative to popup" (let [i2 (ctsi/set-overlay-pos-type interaction-popup :center base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 25)) - (t/is (= (:y overlay-pos) 30)))) + (t/is (= (:y overlay-pos) 30)) + (t/is (= snap-v :center)) + (t/is (= snap-h :center)))) (t/testing "Overlay manual relative to popup" (let [i2 (-> interaction-popup (ctsi/set-overlay-pos-type :manual base-frame objects) (ctsi/set-overlay-position (gpt/point 12 62))) - overlay-pos (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 27)) - (t/is (= (:y overlay-pos) 77)))) + (t/is (= (:y overlay-pos) 77)) + (t/is (= snap-v :top)) + (t/is (= snap-h :left)))) (t/testing "Overlay top-left relative to popup" (let [i2 (ctsi/set-overlay-pos-type interaction-popup :top-left base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 15)) - (t/is (= (:y overlay-pos) 15)))) + (t/is (= (:y overlay-pos) 15)) + (t/is (= snap-v :top)) + (t/is (= snap-h :left)))) (t/testing "Overlay top-center relative to rect" (let [i2 (ctsi/set-overlay-pos-type interaction-rect :top-center base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects rect base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects rect base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 25)) - (t/is (= (:y overlay-pos) 15)))) + (t/is (= (:y overlay-pos) 15)) + (t/is (= snap-v :top)) + (t/is (= snap-h :center)))) (t/testing "Overlay top-right relative to rect" (let [i2 (ctsi/set-overlay-pos-type interaction-rect :top-right base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects rect base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects rect base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 35)) - (t/is (= (:y overlay-pos) 15)))) + (t/is (= (:y overlay-pos) 15)) + (t/is (= snap-v :top)) + (t/is (= snap-h :right)))) (t/testing "Overlay bottom-left relative to rect" (let [i2 (ctsi/set-overlay-pos-type interaction-rect :bottom-left base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects rect base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects rect base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 15)) - (t/is (= (:y overlay-pos) 45)))) + (t/is (= (:y overlay-pos) 45)) + (t/is (= snap-v :bottom)) + (t/is (= snap-h :left)))) (t/testing "Overlay bottom-center relative to rect" (let [i2 (ctsi/set-overlay-pos-type interaction-rect :bottom-center base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects rect base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects rect base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 25)) - (t/is (= (:y overlay-pos) 45)))) + (t/is (= (:y overlay-pos) 45)) + (t/is (= snap-v :bottom)) + (t/is (= snap-h :center)))) (t/testing "Overlay bottom-right relative to rect" (let [i2 (ctsi/set-overlay-pos-type interaction-rect :bottom-right base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects rect base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects rect base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 35)) - (t/is (= (:y overlay-pos) 45)))) + (t/is (= (:y overlay-pos) 45)) + (t/is (= snap-v :bottom)) + (t/is (= snap-h :right)))) (t/testing "Overlay center relative to rect" (let [i2 (ctsi/set-overlay-pos-type interaction-rect :center base-frame objects) - overlay-pos (ctsi/calc-overlay-position i2 rect objects rect base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects rect base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 25)) - (t/is (= (:y overlay-pos) 30)))) + (t/is (= (:y overlay-pos) 30)) + (t/is (= snap-v :center)) + (t/is (= snap-h :center)))) (t/testing "Overlay manual relative to rect" (let [i2 (-> interaction-rect (ctsi/set-overlay-pos-type :manual base-frame objects) (ctsi/set-overlay-position (gpt/point 12 62))) - overlay-pos (ctsi/calc-overlay-position i2 rect objects rect base-frame overlay-frame frame-offset)] + [overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects rect base-frame overlay-frame frame-offset)] (t/is (= (:x overlay-pos) 17)) - (t/is (= (:y overlay-pos) 67)))))) + (t/is (= (:y overlay-pos) 67)) + (t/is (= snap-v :top)) + (t/is (= snap-h :left)))))) (t/deftest animation-checks diff --git a/frontend/src/app/main/data/viewer.cljs b/frontend/src/app/main/data/viewer.cljs index f4675beaa..40df6b66c 100644 --- a/frontend/src/app/main/data/viewer.cljs +++ b/frontend/src/app/main/data/viewer.cljs @@ -542,13 +542,14 @@ ;; --- Overlays (defn- open-overlay* - [state frame position close-click-outside background-overlay animation] + [state frame position snap-to close-click-outside background-overlay animation] (cond-> state :always (update :viewer-overlays conj {:frame frame :id (:id frame) :position position + :snap-to snap-to :close-click-outside close-click-outside :background-overlay background-overlay :animation animation}) @@ -571,7 +572,7 @@ :animation animation}))) (defn open-overlay - [frame-id position close-click-outside background-overlay animation] + [frame-id position snap-to close-click-outside background-overlay animation] (dm/assert! (uuid? frame-id)) (dm/assert! (gpt/point? position)) (dm/assert! (or (nil? close-click-outside) @@ -593,6 +594,7 @@ (open-overlay* state frame position + snap-to close-click-outside background-overlay animation) @@ -600,7 +602,7 @@ (defn toggle-overlay - [frame-id position close-click-outside background-overlay animation] + [frame-id position snap-to close-click-outside background-overlay animation] (dm/assert! (uuid? frame-id)) (dm/assert! (gpt/point? position)) (dm/assert! (or (nil? close-click-outside) @@ -623,6 +625,7 @@ (open-overlay* state frame position + snap-to close-click-outside background-overlay animation) diff --git a/frontend/src/app/main/ui/shapes/frame.cljs b/frontend/src/app/main/ui/shapes/frame.cljs index 8a71a26ac..42eccf32b 100644 --- a/frontend/src/app/main/ui/shapes/frame.cljs +++ b/frontend/src/app/main/ui/shapes/frame.cljs @@ -142,5 +142,6 @@ [:> frame-container props [:g.frame-children {:opacity (:opacity shape)} (for [item childs] - [:& shape-wrapper {:key (dm/str (:id item)) :shape item}])]]))) + (when (:id item) + [:& shape-wrapper {:key (dm/str (:id item)) :shape item}]))]]))) diff --git a/frontend/src/app/main/ui/viewer.cljs b/frontend/src/app/main/ui/viewer.cljs index 8d1e315ba..ad8e0f594 100644 --- a/frontend/src/app/main/ui/viewer.cljs +++ b/frontend/src/app/main/ui/viewer.cljs @@ -50,6 +50,8 @@ (l/derived :viewer-overlays st/state)) (defn- calculate-size + "Calculate the total size we must reserve for the frame, including possible paddings + added because shadows or blur." [objects frame zoom] (let [{:keys [x y width height]} (gsb/get-object-bounds objects frame)] {:base-width width @@ -60,6 +62,23 @@ :height (* height zoom) :vbox (dm/fmt "% % % %" 0 0 width height)})) +(defn calculate-delta + "Calculate the displacement we need to apply so that the original selrect appears in the + same position as if it had no extra paddings, depending on the side the frame will + be snapped to." + [size selrect [snap-v snap-h] zoom] + (let [delta-x (case snap-h + :left (- (:x1 selrect) (:x size)) + :right (- (:x2 selrect) (+ (:x size) (/ (:width size) zoom))) + :center (- (/ (- (:width selrect) (/ (:width size) zoom)) 2) + (- (:x size) (:x1 selrect)))) + delta-y (case snap-v + :top (- (:y1 selrect) (:y size)) + :bottom (- (:y2 selrect) (+ (:y size) (/ (:height size) zoom))) + :center (- (/ (- (:height selrect) (/ (:height size) zoom)) 2) + (- (:y size) (:y1 selrect))))] + (gpt/point (* delta-x zoom) (* delta-y zoom)))) + (defn- calculate-wrapper [size1 size2 zoom] (cond @@ -113,6 +132,10 @@ (mf/with-memo [page overlay zoom] (calculate-size (:objects page) (:frame overlay) zoom)) + delta + (mf/with-memo [size overlay-frame overlay zoom] + (calculate-delta size (:selrect overlay-frame) (:snap-to overlay) zoom)) + on-click (mf/use-fn (mf/deps overlay close-click-outside?) @@ -145,6 +168,7 @@ :base-frame frame :frame-offset overlay-position :size size + :delta delta :page page :interactions-mode interactions-mode}]]])) diff --git a/frontend/src/app/main/ui/viewer/inspect/render.cljs b/frontend/src/app/main/ui/viewer/inspect/render.cljs index da8e79d80..01adf3e35 100644 --- a/frontend/src/app/main/ui/viewer/inspect/render.cljs +++ b/frontend/src/app/main/ui/viewer/inspect/render.cljs @@ -7,6 +7,7 @@ (ns app.main.ui.viewer.inspect.render "The main container for a frame in inspect mode" (:require + [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] [app.common.pages.helpers :as cph] [app.main.data.viewer :as dv] @@ -186,7 +187,7 @@ (mf/defc render-frame-svg [{:keys [page frame local size]}] (let [objects (mf/with-memo [page frame size] - (prepare-objects frame size (:objects page))) + (prepare-objects frame size (gpt/point 0 0) (:objects page))) ;; Retrieve frame again with correct modifier frame (get objects (:id frame)) diff --git a/frontend/src/app/main/ui/viewer/interactions.cljs b/frontend/src/app/main/ui/viewer/interactions.cljs index 6e2e6320e..a3419e419 100644 --- a/frontend/src/app/main/ui/viewer/interactions.cljs +++ b/frontend/src/app/main/ui/viewer/interactions.cljs @@ -28,9 +28,10 @@ [rumext.v2 :as mf])) (defn prepare-objects - [frame size objects] + [frame size delta objects] (let [frame-id (:id frame) vector (-> (gpt/point (:x size) (:y size)) + (gpt/add delta) (gpt/negate)) update-fn #(d/update-when %1 %2 gsh/transform-shape (ctm/move-modifiers vector))] (->> (cph/get-children-ids objects frame-id) @@ -46,6 +47,7 @@ base (unchecked-get props "base") offset (unchecked-get props "offset") size (unchecked-get props "size") + delta (or (unchecked-get props "delta") (gpt/point 0 0)) vbox (:vbox size) @@ -67,7 +69,7 @@ (map (d/getf (:objects page))) (concat [frame]) (d/index-by :id) - (prepare-objects frame size))) + (prepare-objects frame size delta))) wrapper-fixed (mf/with-memo [page frame size] (shapes/frame-container-factory (calculate-objects fixed-ids))) @@ -121,6 +123,7 @@ mode (h/use-equal-memo (unchecked-get props "interactions-mode")) offset (h/use-equal-memo (unchecked-get props "frame-offset")) size (h/use-equal-memo (unchecked-get props "size")) + delta (unchecked-get props "delta") page (unchecked-get props "page") frame (unchecked-get props "frame") @@ -163,7 +166,8 @@ :frame frame :base base :offset offset - :size size}])) + :size size + :delta delta}])) (mf/defc flows-menu {::mf/wrap [mf/memo]} diff --git a/frontend/src/app/main/ui/viewer/shapes.cljs b/frontend/src/app/main/ui/viewer/shapes.cljs index 7131bc88c..ccc6663ce 100644 --- a/frontend/src/app/main/ui/viewer/shapes.cljs +++ b/frontend/src/app/main/ui/viewer/shapes.cljs @@ -61,14 +61,16 @@ (let [dest-frame-id (:destination interaction) dest-frame (get objects dest-frame-id) relative-to-id (if (= :manual (:overlay-pos-type interaction)) - (:id shape) ;; manual interactions are allways from "self" + (if (= (:type shape) :frame) ;; manual interactions are always from "self" + (:frame-id shape) + (:id shape)) (:position-relative-to interaction)) relative-to-shape (or (get objects relative-to-id) base-frame) close-click-outside (:close-click-outside interaction) background-overlay (:background-overlay interaction) overlays-ids (set (map :id overlays)) relative-to-base-frame (find-relative-to-base-frame relative-to-shape objects overlays-ids base-frame) - position (ctsi/calc-overlay-position interaction + [position snap-to] (ctsi/calc-overlay-position interaction shape objects relative-to-shape @@ -78,6 +80,7 @@ (when dest-frame-id (st/emit! (dv/open-overlay dest-frame-id position + snap-to close-click-outside background-overlay (:animation interaction))))) @@ -86,12 +89,14 @@ (let [dest-frame-id (:destination interaction) dest-frame (get objects dest-frame-id) relative-to-id (if (= :manual (:overlay-pos-type interaction)) - (:id shape) ;; manual interactions are allways from "self" - (:position-relative-to interaction)) + (if (= (:type shape) :frame) ;; manual interactions are always from "self" + (:frame-id shape) + (:id shape)) + (:position-relative-to interaction)) relative-to-shape (or (get objects relative-to-id) base-frame) overlays-ids (set (map :id overlays)) relative-to-base-frame (find-relative-to-base-frame relative-to-shape objects overlays-ids base-frame) - position (ctsi/calc-overlay-position interaction + [position snap-to] (ctsi/calc-overlay-position interaction shape objects relative-to-shape @@ -104,6 +109,7 @@ (when dest-frame-id (st/emit! (dv/toggle-overlay dest-frame-id position + snap-to close-click-outside background-overlay (:animation interaction))))) @@ -136,29 +142,49 @@ (st/emit! (dv/close-overlay frame-id))) :toggle-overlay - (let [frame-id (:destination interaction) - position (:overlay-position interaction) - close-click-outside (:close-click-outside interaction) - background-overlay (:background-overlay interaction)] - (when frame-id - (st/emit! (dv/toggle-overlay frame-id + (let [dest-frame-id (:destination interaction) + dest-frame (get objects dest-frame-id) + relative-to-id (if (= :manual (:overlay-pos-type interaction)) + (if (= (:type shape) :frame) ;; manual interactions are always from "self" + (:frame-id shape) + (:id shape)) + (:position-relative-to interaction)) + relative-to-shape (or (get objects relative-to-id) base-frame) + overlays-ids (set (map :id overlays)) + relative-to-base-frame (find-relative-to-base-frame relative-to-shape objects overlays-ids base-frame) + [position snap-to] (ctsi/calc-overlay-position interaction + shape + objects + relative-to-shape + relative-to-base-frame + dest-frame + frame-offset) + + close-click-outside (:close-click-outside interaction) + background-overlay (:background-overlay interaction)] + (when dest-frame-id + (st/emit! (dv/toggle-overlay dest-frame-id position + snap-to close-click-outside background-overlay (:animation interaction))))) + :close-overlay (let [dest-frame-id (:destination interaction) dest-frame (get objects dest-frame-id) relative-to-id (if (= :manual (:overlay-pos-type interaction)) - (:id shape) ;; manual interactions are allways from "self" + (if (= (:type shape) :frame) ;; manual interactions are always from "self" + (:frame-id shape) + (:id shape)) (:position-relative-to interaction)) relative-to-shape (or (get objects relative-to-id) base-frame) close-click-outside (:close-click-outside interaction) background-overlay (:background-overlay interaction) overlays-ids (set (map :id overlays)) relative-to-base-frame (find-relative-to-base-frame relative-to-shape objects overlays-ids base-frame) - position (ctsi/calc-overlay-position interaction + [position snap-to] (ctsi/calc-overlay-position interaction shape objects relative-to-shape @@ -168,6 +194,7 @@ (when dest-frame-id (st/emit! (dv/open-overlay dest-frame-id position + snap-to close-click-outside background-overlay (:animation interaction))))) @@ -266,6 +293,9 @@ svg-element? (and (= :svg-raw (:type shape)) (not= :svg (get-in shape [:content :tag]))) + ;; _ (js/console.log "======" (:name shape)) + ;; _ (js/console.log "shape" (clj->js shape)) + ;; _ (js/console.log "frame-offset" (clj->js frame-offset)) on-pointer-down (mf/use-fn (mf/deps shape base-frame frame-offset objects) #(on-pointer-down % shape base-frame frame-offset objects overlays))