🐛 Fix overlay position when it has shadow or blur

This commit is contained in:
Andrés Moya 2023-07-07 17:31:11 +02:00
parent e563611c05
commit 65598aa724
10 changed files with 242 additions and 102 deletions

View file

@ -65,6 +65,7 @@
- Fix shortcuts translations not homogenized [Taiga #5141](https://tree.taiga.io/project/penpot/issue/5141) - 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 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 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 ### :arrow_up: Deps updates

View file

@ -147,6 +147,7 @@
:else :else
(cph/reduce-objects (cph/reduce-objects
objects objects
(fn [shape] (fn [shape]
(and (d/not-empty? (:shapes shape)) (and (d/not-empty? (:shapes shape))
(or (not (cph/frame-shape? shape)) (or (not (cph/frame-shape? shape))

View file

@ -526,37 +526,46 @@
overlay-position overlay-position
{:x (- (:x overlay-position) (:x relative-to-adjusted-to-base-frame)) {:x (- (:x overlay-position) (:x relative-to-adjusted-to-base-frame))
:y (- (:y overlay-position) (:y relative-to-adjusted-to-base-frame))})] :y (- (:y overlay-position) (:y relative-to-adjusted-to-base-frame))})]
(case (:overlay-pos-type interaction) (case (:overlay-pos-type interaction)
:center :center
(gpt/point (+ (:x base-position) (/ (- (:width relative-to-shape-size) (:width 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))) (+ (:y base-position) (/ (- (:height relative-to-shape-size) (:height overlay-size)) 2)))
[:center :center]]
:top-left :top-left
(gpt/point (:x base-position) (:y base-position)) [(gpt/point (:x base-position) (:y base-position))
[:top :left]]
:top-right :top-right
(gpt/point (+ (:x base-position) (- (:width relative-to-shape-size) (:width overlay-size))) [(gpt/point (+ (:x base-position) (- (:width relative-to-shape-size) (:width overlay-size)))
(:y base-position)) (:y base-position))
[:top :right]]
:top-center :top-center
(gpt/point (+ (:x base-position) (/ (- (:width relative-to-shape-size) (:width overlay-size)) 2)) [(gpt/point (+ (:x base-position) (/ (- (:width relative-to-shape-size) (:width overlay-size)) 2))
(:y base-position)) (:y base-position))
[:top :center]]
:bottom-left :bottom-left
(gpt/point (:x base-position) [(gpt/point (:x base-position)
(+ (:y base-position) (- (:height relative-to-shape-size) (:height overlay-size)))) (+ (:y base-position) (- (:height relative-to-shape-size) (:height overlay-size))))
[:bottom :left]]
:bottom-right :bottom-right
(gpt/point (+ (:x base-position) (- (:width relative-to-shape-size) (:width 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)))) (+ (:y base-position) (- (:height relative-to-shape-size) (:height overlay-size))))
[:bottom :right]]
:bottom-center :bottom-center
(gpt/point (+ (:x base-position) (/ (- (:width relative-to-shape-size) (:width 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)))) (+ (:y base-position) (- (:height relative-to-shape-size) (:height overlay-size))))
[:bottom :center]]
:manual :manual
(gpt/point (+ (:x base-position) (:x overlay-position)) [(gpt/point (+ (:x base-position) (:x overlay-position))
(+ (:y base-position) (:y overlay-position)))))))) (+ (:y base-position) (:y overlay-position)))
[:top :left]])))))
(defn has-animation? (defn has-animation?
[interaction] [interaction]

View file

@ -324,209 +324,275 @@
interaction-rect (ctsi/set-position-relative-to interaction (:id rect))] interaction-rect (ctsi/set-position-relative-to interaction (:id rect))]
(t/testing "Overlay top-left relative to auto" (t/testing "Overlay top-left relative to auto"
(let [i2 (ctsi/set-overlay-pos-type interaction-auto :top-left base-frame objects) (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 (= (: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" (t/testing "Overlay top-center relative to auto"
(let [i2 (ctsi/set-overlay-pos-type interaction-auto :top-center base-frame objects) (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 (= (: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" (t/testing "Overlay top-right relative to auto"
(let [i2 (ctsi/set-overlay-pos-type interaction-auto :top-right base-frame objects) (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 (= (: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" (t/testing "Overlay bottom-left relative to auto"
(let [i2 (ctsi/set-overlay-pos-type interaction-auto :bottom-left base-frame objects) (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 (= (: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" (t/testing "Overlay bottom-center relative to auto"
(let [i2 (ctsi/set-overlay-pos-type interaction-auto :bottom-center base-frame objects) (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 (= (: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" (t/testing "Overlay bottom-right relative to auto"
(let [i2 (ctsi/set-overlay-pos-type interaction-auto :bottom-right base-frame objects) (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 (= (: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" (t/testing "Overlay center relative to auto"
(let [i2 (ctsi/set-overlay-pos-type interaction-auto :center base-frame objects) (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 (= (: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" (t/testing "Overlay manual relative to auto"
(let [i2 (ctsi/set-overlay-pos-type interaction-auto :center base-frame objects) (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 (= (: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" (t/testing "Overlay manual relative to auto"
(let [i2 (-> interaction-auto (let [i2 (-> interaction-auto
(ctsi/set-overlay-pos-type :manual base-frame objects) (ctsi/set-overlay-pos-type :manual base-frame objects)
(ctsi/set-overlay-position (gpt/point 12 62))) (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 (= (: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" (t/testing "Overlay top-left relative to base-frame"
(let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :top-left base-frame objects) (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 (= (: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" (t/testing "Overlay top-center relative to base-frame"
(let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :top-center base-frame objects) (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 (= (: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" (t/testing "Overlay top-right relative to base-frame"
(let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :top-right base-frame objects) (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 (= (: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" (t/testing "Overlay bottom-left relative to base-frame"
(let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :bottom-left base-frame objects) (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 (= (: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" (t/testing "Overlay bottom-center relative to base-frame"
(let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :bottom-center base-frame objects) (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 (= (: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" (t/testing "Overlay bottom-right relative to base-frame"
(let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :bottom-right base-frame objects) (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 (= (: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" (t/testing "Overlay center relative to base-frame"
(let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :center base-frame objects) (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 (= (: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" (t/testing "Overlay manual relative to base-frame"
(let [i2 (-> interaction-base-frame (let [i2 (-> interaction-base-frame
(ctsi/set-overlay-pos-type :manual base-frame objects) (ctsi/set-overlay-pos-type :manual base-frame objects)
(ctsi/set-overlay-position (gpt/point 12 62))) (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 (= (: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" (t/testing "Overlay top-left relative to popup"
(let [i2 (ctsi/set-overlay-pos-type interaction-popup :top-left base-frame objects) (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 (= (: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" (t/testing "Overlay top-center relative to popup"
(let [i2 (ctsi/set-overlay-pos-type interaction-popup :top-center base-frame objects) (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 (= (: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" (t/testing "Overlay top-right relative to popup"
(let [i2 (ctsi/set-overlay-pos-type interaction-popup :top-right base-frame objects) (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 (= (: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" (t/testing "Overlay bottom-left relative to popup"
(let [i2 (ctsi/set-overlay-pos-type interaction-popup :bottom-left base-frame objects) (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 (= (: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" (t/testing "Overlay bottom-center relative to popup"
(let [i2 (ctsi/set-overlay-pos-type interaction-popup :bottom-center base-frame objects) (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 (= (: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" (t/testing "Overlay bottom-right relative to popup"
(let [i2 (ctsi/set-overlay-pos-type interaction-popup :bottom-right base-frame objects) (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 (= (: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" (t/testing "Overlay center relative to popup"
(let [i2 (ctsi/set-overlay-pos-type interaction-popup :center base-frame objects) (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 (= (: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" (t/testing "Overlay manual relative to popup"
(let [i2 (-> interaction-popup (let [i2 (-> interaction-popup
(ctsi/set-overlay-pos-type :manual base-frame objects) (ctsi/set-overlay-pos-type :manual base-frame objects)
(ctsi/set-overlay-position (gpt/point 12 62))) (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 (= (: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" (t/testing "Overlay top-left relative to popup"
(let [i2 (ctsi/set-overlay-pos-type interaction-popup :top-left base-frame objects) (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 (= (: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" (t/testing "Overlay top-center relative to rect"
(let [i2 (ctsi/set-overlay-pos-type interaction-rect :top-center base-frame objects) (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 (= (: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" (t/testing "Overlay top-right relative to rect"
(let [i2 (ctsi/set-overlay-pos-type interaction-rect :top-right base-frame objects) (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 (= (: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" (t/testing "Overlay bottom-left relative to rect"
(let [i2 (ctsi/set-overlay-pos-type interaction-rect :bottom-left base-frame objects) (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 (= (: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" (t/testing "Overlay bottom-center relative to rect"
(let [i2 (ctsi/set-overlay-pos-type interaction-rect :bottom-center base-frame objects) (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 (= (: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" (t/testing "Overlay bottom-right relative to rect"
(let [i2 (ctsi/set-overlay-pos-type interaction-rect :bottom-right base-frame objects) (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 (= (: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" (t/testing "Overlay center relative to rect"
(let [i2 (ctsi/set-overlay-pos-type interaction-rect :center base-frame objects) (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 (= (: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" (t/testing "Overlay manual relative to rect"
(let [i2 (-> interaction-rect (let [i2 (-> interaction-rect
(ctsi/set-overlay-pos-type :manual base-frame objects) (ctsi/set-overlay-pos-type :manual base-frame objects)
(ctsi/set-overlay-position (gpt/point 12 62))) (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 (= (: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 (t/deftest animation-checks

View file

@ -542,13 +542,14 @@
;; --- Overlays ;; --- Overlays
(defn- open-overlay* (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 (cond-> state
:always :always
(update :viewer-overlays conj (update :viewer-overlays conj
{:frame frame {:frame frame
:id (:id frame) :id (:id frame)
:position position :position position
:snap-to snap-to
:close-click-outside close-click-outside :close-click-outside close-click-outside
:background-overlay background-overlay :background-overlay background-overlay
:animation animation}) :animation animation})
@ -571,7 +572,7 @@
:animation animation}))) :animation animation})))
(defn open-overlay (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! (uuid? frame-id))
(dm/assert! (gpt/point? position)) (dm/assert! (gpt/point? position))
(dm/assert! (or (nil? close-click-outside) (dm/assert! (or (nil? close-click-outside)
@ -593,6 +594,7 @@
(open-overlay* state (open-overlay* state
frame frame
position position
snap-to
close-click-outside close-click-outside
background-overlay background-overlay
animation) animation)
@ -600,7 +602,7 @@
(defn toggle-overlay (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! (uuid? frame-id))
(dm/assert! (gpt/point? position)) (dm/assert! (gpt/point? position))
(dm/assert! (or (nil? close-click-outside) (dm/assert! (or (nil? close-click-outside)
@ -623,6 +625,7 @@
(open-overlay* state (open-overlay* state
frame frame
position position
snap-to
close-click-outside close-click-outside
background-overlay background-overlay
animation) animation)

View file

@ -142,5 +142,6 @@
[:> frame-container props [:> frame-container props
[:g.frame-children {:opacity (:opacity shape)} [:g.frame-children {:opacity (:opacity shape)}
(for [item childs] (for [item childs]
[:& shape-wrapper {:key (dm/str (:id item)) :shape item}])]]))) (when (:id item)
[:& shape-wrapper {:key (dm/str (:id item)) :shape item}]))]])))

View file

@ -50,6 +50,8 @@
(l/derived :viewer-overlays st/state)) (l/derived :viewer-overlays st/state))
(defn- calculate-size (defn- calculate-size
"Calculate the total size we must reserve for the frame, including possible paddings
added because shadows or blur."
[objects frame zoom] [objects frame zoom]
(let [{:keys [x y width height]} (gsb/get-object-bounds objects frame)] (let [{:keys [x y width height]} (gsb/get-object-bounds objects frame)]
{:base-width width {:base-width width
@ -60,6 +62,23 @@
:height (* height zoom) :height (* height zoom)
:vbox (dm/fmt "% % % %" 0 0 width height)})) :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 (defn- calculate-wrapper
[size1 size2 zoom] [size1 size2 zoom]
(cond (cond
@ -113,6 +132,10 @@
(mf/with-memo [page overlay zoom] (mf/with-memo [page overlay zoom]
(calculate-size (:objects page) (:frame 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 on-click
(mf/use-fn (mf/use-fn
(mf/deps overlay close-click-outside?) (mf/deps overlay close-click-outside?)
@ -145,6 +168,7 @@
:base-frame frame :base-frame frame
:frame-offset overlay-position :frame-offset overlay-position
:size size :size size
:delta delta
:page page :page page
:interactions-mode interactions-mode}]]])) :interactions-mode interactions-mode}]]]))

View file

@ -7,6 +7,7 @@
(ns app.main.ui.viewer.inspect.render (ns app.main.ui.viewer.inspect.render
"The main container for a frame in inspect mode" "The main container for a frame in inspect mode"
(:require (:require
[app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.main.data.viewer :as dv] [app.main.data.viewer :as dv]
@ -186,7 +187,7 @@
(mf/defc render-frame-svg (mf/defc render-frame-svg
[{:keys [page frame local size]}] [{:keys [page frame local size]}]
(let [objects (mf/with-memo [page frame 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 ;; Retrieve frame again with correct modifier
frame (get objects (:id frame)) frame (get objects (:id frame))

View file

@ -28,9 +28,10 @@
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(defn prepare-objects (defn prepare-objects
[frame size objects] [frame size delta objects]
(let [frame-id (:id frame) (let [frame-id (:id frame)
vector (-> (gpt/point (:x size) (:y size)) vector (-> (gpt/point (:x size) (:y size))
(gpt/add delta)
(gpt/negate)) (gpt/negate))
update-fn #(d/update-when %1 %2 gsh/transform-shape (ctm/move-modifiers vector))] update-fn #(d/update-when %1 %2 gsh/transform-shape (ctm/move-modifiers vector))]
(->> (cph/get-children-ids objects frame-id) (->> (cph/get-children-ids objects frame-id)
@ -46,6 +47,7 @@
base (unchecked-get props "base") base (unchecked-get props "base")
offset (unchecked-get props "offset") offset (unchecked-get props "offset")
size (unchecked-get props "size") size (unchecked-get props "size")
delta (or (unchecked-get props "delta") (gpt/point 0 0))
vbox (:vbox size) vbox (:vbox size)
@ -67,7 +69,7 @@
(map (d/getf (:objects page))) (map (d/getf (:objects page)))
(concat [frame]) (concat [frame])
(d/index-by :id) (d/index-by :id)
(prepare-objects frame size))) (prepare-objects frame size delta)))
wrapper-fixed (mf/with-memo [page frame size] wrapper-fixed (mf/with-memo [page frame size]
(shapes/frame-container-factory (calculate-objects fixed-ids))) (shapes/frame-container-factory (calculate-objects fixed-ids)))
@ -121,6 +123,7 @@
mode (h/use-equal-memo (unchecked-get props "interactions-mode")) mode (h/use-equal-memo (unchecked-get props "interactions-mode"))
offset (h/use-equal-memo (unchecked-get props "frame-offset")) offset (h/use-equal-memo (unchecked-get props "frame-offset"))
size (h/use-equal-memo (unchecked-get props "size")) size (h/use-equal-memo (unchecked-get props "size"))
delta (unchecked-get props "delta")
page (unchecked-get props "page") page (unchecked-get props "page")
frame (unchecked-get props "frame") frame (unchecked-get props "frame")
@ -163,7 +166,8 @@
:frame frame :frame frame
:base base :base base
:offset offset :offset offset
:size size}])) :size size
:delta delta}]))
(mf/defc flows-menu (mf/defc flows-menu
{::mf/wrap [mf/memo]} {::mf/wrap [mf/memo]}

View file

@ -61,14 +61,16 @@
(let [dest-frame-id (:destination interaction) (let [dest-frame-id (:destination interaction)
dest-frame (get objects dest-frame-id) dest-frame (get objects dest-frame-id)
relative-to-id (if (= :manual (:overlay-pos-type interaction)) 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)) (:position-relative-to interaction))
relative-to-shape (or (get objects relative-to-id) base-frame) relative-to-shape (or (get objects relative-to-id) base-frame)
close-click-outside (:close-click-outside interaction) close-click-outside (:close-click-outside interaction)
background-overlay (:background-overlay interaction) background-overlay (:background-overlay interaction)
overlays-ids (set (map :id overlays)) overlays-ids (set (map :id overlays))
relative-to-base-frame (find-relative-to-base-frame relative-to-shape objects overlays-ids base-frame) 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 shape
objects objects
relative-to-shape relative-to-shape
@ -78,6 +80,7 @@
(when dest-frame-id (when dest-frame-id
(st/emit! (dv/open-overlay dest-frame-id (st/emit! (dv/open-overlay dest-frame-id
position position
snap-to
close-click-outside close-click-outside
background-overlay background-overlay
(:animation interaction))))) (:animation interaction)))))
@ -86,12 +89,14 @@
(let [dest-frame-id (:destination interaction) (let [dest-frame-id (:destination interaction)
dest-frame (get objects dest-frame-id) dest-frame (get objects dest-frame-id)
relative-to-id (if (= :manual (:overlay-pos-type interaction)) 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)) (:position-relative-to interaction))
relative-to-shape (or (get objects relative-to-id) base-frame) relative-to-shape (or (get objects relative-to-id) base-frame)
overlays-ids (set (map :id overlays)) overlays-ids (set (map :id overlays))
relative-to-base-frame (find-relative-to-base-frame relative-to-shape objects overlays-ids base-frame) 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 shape
objects objects
relative-to-shape relative-to-shape
@ -104,6 +109,7 @@
(when dest-frame-id (when dest-frame-id
(st/emit! (dv/toggle-overlay dest-frame-id (st/emit! (dv/toggle-overlay dest-frame-id
position position
snap-to
close-click-outside close-click-outside
background-overlay background-overlay
(:animation interaction))))) (:animation interaction)))))
@ -136,29 +142,49 @@
(st/emit! (dv/close-overlay frame-id))) (st/emit! (dv/close-overlay frame-id)))
:toggle-overlay :toggle-overlay
(let [frame-id (:destination interaction) (let [dest-frame-id (:destination interaction)
position (:overlay-position 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) close-click-outside (:close-click-outside interaction)
background-overlay (:background-overlay interaction)] background-overlay (:background-overlay interaction)]
(when frame-id (when dest-frame-id
(st/emit! (dv/toggle-overlay frame-id (st/emit! (dv/toggle-overlay dest-frame-id
position position
snap-to
close-click-outside close-click-outside
background-overlay background-overlay
(:animation interaction))))) (:animation interaction)))))
:close-overlay :close-overlay
(let [dest-frame-id (:destination interaction) (let [dest-frame-id (:destination interaction)
dest-frame (get objects dest-frame-id) dest-frame (get objects dest-frame-id)
relative-to-id (if (= :manual (:overlay-pos-type interaction)) 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)) (:position-relative-to interaction))
relative-to-shape (or (get objects relative-to-id) base-frame) relative-to-shape (or (get objects relative-to-id) base-frame)
close-click-outside (:close-click-outside interaction) close-click-outside (:close-click-outside interaction)
background-overlay (:background-overlay interaction) background-overlay (:background-overlay interaction)
overlays-ids (set (map :id overlays)) overlays-ids (set (map :id overlays))
relative-to-base-frame (find-relative-to-base-frame relative-to-shape objects overlays-ids base-frame) 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 shape
objects objects
relative-to-shape relative-to-shape
@ -168,6 +194,7 @@
(when dest-frame-id (when dest-frame-id
(st/emit! (dv/open-overlay dest-frame-id (st/emit! (dv/open-overlay dest-frame-id
position position
snap-to
close-click-outside close-click-outside
background-overlay background-overlay
(:animation interaction))))) (:animation interaction)))))
@ -266,6 +293,9 @@
svg-element? (and (= :svg-raw (:type shape)) svg-element? (and (= :svg-raw (:type shape))
(not= :svg (get-in shape [:content :tag]))) (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 on-pointer-down
(mf/use-fn (mf/deps shape base-frame frame-offset objects) (mf/use-fn (mf/deps shape base-frame frame-offset objects)
#(on-pointer-down % shape base-frame frame-offset objects overlays)) #(on-pointer-down % shape base-frame frame-offset objects overlays))