0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-02-03 04:49:03 -05:00

Add performance improvements to start-resize

This commit is contained in:
Andrey Antukh 2024-01-08 13:15:23 +01:00
parent 1465ed3607
commit 36b5ca7313

View file

@ -45,17 +45,19 @@
;; For each of the 8 handlers gives the multiplier for resize ;; For each of the 8 handlers gives the multiplier for resize
;; for example, right will only grow in the x coordinate and left ;; for example, right will only grow in the x coordinate and left
;; will grow in the inverse of the x coordinate ;; will grow in the inverse of the x coordinate
(def ^:private handler-multipliers (defn get-handler-multiplier
{:right [1 0] [handler]
:bottom [0 1] (case handler
:left [-1 0] :right (gpt/point 1 0)
:top [0 -1] :bottom (gpt/point 0 1)
:top-right [1 -1] :left (gpt/point -1 0)
:top-left [-1 -1] :top (gpt/point 0 -1)
:bottom-right [1 1] :top-right (gpt/point 1 -1)
:bottom-left [-1 1]}) :top-left (gpt/point -1 -1)
:bottom-right (gpt/point 1 1)
:bottom-left (gpt/point -1 1)))
(defn- handler-resize-origin (defn- get-handler-resize-origin
"Given a handler, return the coordinate origin for resizes. "Given a handler, return the coordinate origin for resizes.
This is the opposite of the handler so for right we want the This is the opposite of the handler so for right we want the
left side as origin of the resize. left side as origin of the resize.
@ -64,39 +66,66 @@
mx, my => middle x/y mx, my => middle x/y
ex, ey => end x/y ex, ey => end x/y
" "
[{sx :x sy :y :keys [width height]} handler] [selrect handler]
(let [mx (+ sx (/ width 2)) (let [sx (dm/get-prop selrect :x)
my (+ sy (/ height 2)) sy (dm/get-prop selrect :y)
ex (+ sx width) width (dm/get-prop selrect :width)
ey (+ sy height) height (dm/get-prop selrect :height)
mx (+ sx (/ width 2))
[x y] (case handler my (+ sy (/ height 2))
:right [sx my] ex (+ sx width)
:bottom [mx sy] ey (+ sy height)]
:left [ex my] (case handler
:top [mx ey] :right (gpt/point sx my)
:top-right [sx ey] :bottom (gpt/point mx sy)
:top-left [ex ey] :left (gpt/point ex my)
:bottom-right [sx sy] :top (gpt/point mx ey)
:bottom-left [ex sy])] :top-right (gpt/point sx ey)
(gpt/point x y))) :top-left (gpt/point ex ey)
:bottom-right (gpt/point sx sy)
:bottom-left (gpt/point ex sy))))
(defn- fix-init-point (defn- fix-init-point
"Fix the initial point so the resizes are accurate" "Fix the initial point so the resizes are accurate"
[initial handler shape] [initial handler shape]
(let [{:keys [x y width height]} (:selrect shape)] (let [selrect (dm/get-prop shape :selrect)
(cond-> initial x (dm/get-prop selrect :x)
(contains? #{:left :top-left :bottom-left} handler) y (dm/get-prop selrect :y)
(assoc :x x) width (dm/get-prop selrect :width)
height (dm/get-prop selrect :height)]
(contains? #{:right :top-right :bottom-right} handler) (case handler
(assoc :x (+ x width)) :left
(assoc initial :x x)
(contains? #{:top :top-right :top-left} handler) :top
(assoc :y y) (assoc initial :y y)
(contains? #{:bottom :bottom-right :bottom-left} handler) :top-left
(assoc :y (+ y height))))) (-> initial
(assoc :x x)
(assoc :y y))
:bottom-left
(-> initial
(assoc :x x)
(assoc :y (+ y height)))
:right
(assoc initial :x (+ x width))
:top-right
(-> initial
(assoc :x (+ x width))
(assoc :y y))
:bottom-right
(-> initial
(assoc :x (+ x width))
(assoc :y (+ y height)))
:bottom
(assoc initial :y (+ y height)))))
(defn finish-transform [] (defn finish-transform []
(ptk/reify ::finish-transform (ptk/reify ::finish-transform
@ -104,16 +133,16 @@
(update [_ state] (update [_ state]
(update state :workspace-local dissoc :transform :duplicate-move-started? false)))) (update state :workspace-local dissoc :transform :duplicate-move-started? false))))
;; -- Resize -------------------------------------------------------- ;; -- Resize --------------------------------------------------------
(defn start-resize (defn start-resize
"Enter mouse resize mode, until mouse button is released." "Enter mouse resize mode, until mouse button is released."
[handler ids shape] [handler ids shape]
(letfn [(resize (letfn [(resize [shape initial layout [point lock? center? point-snap]]
[shape initial layout [point lock? center? point-snap]] (let [selrect (dm/get-prop shape :selrect)
(let [{:keys [width height]} (:selrect shape) width (dm/get-prop selrect :width)
{:keys [rotation]} shape height (dm/get-prop selrect :height)
rotation (dm/get-prop shape :rotation)
shape-center (gsh/shape->center shape) shape-center (gsh/shape->center shape)
shape-transform (:transform shape) shape-transform (:transform shape)
@ -129,78 +158,84 @@
shapev (-> (gpt/point width height)) shapev (-> (gpt/point width height))
scale-text (:scale-text layout) scale-text (contains? layout :scale-text)
;; Force lock if the scale text mode is active ;; Force lock if the scale text mode is active
lock? (or lock? scale-text) lock? (or ^boolean lock?
^boolean scale-text)
;; Vector modifiers depending on the handler ;; Difference between the origin point in the
handler-mult (let [[x y] (handler-multipliers handler)] (gpt/point x y)) ;; coordinate system of the rotation
;; Difference between the origin point in the coordinate system of the rotation
deltav (-> (gpt/to-vec initial point) deltav (-> (gpt/to-vec initial point)
(gpt/multiply handler-mult)) ;; Vector modifiers depending on the handler
(gpt/multiply (get-handler-multiplier handler)))
;; Resize vector ;; Resize vector
scalev (-> (gpt/divide (gpt/add shapev deltav) shapev) scalev (-> (gpt/divide (gpt/add shapev deltav) shapev)
(gpt/no-zeros)) (gpt/no-zeros))
scalev (if lock? scalev (if ^boolean lock?
(let [v (cond (let [v (cond
(#{:right :left} handler) (:x scalev) (or (= handler :right)
(#{:top :bottom} handler) (:y scalev) (= handler :left))
:else (max (:x scalev) (:y scalev)))] (dm/get-prop scalev :x)
(gpt/point v v))
(or (= handler :top)
(= handler :bottom))
(dm/get-prop scalev :y)
:else
(mth/max (dm/get-prop scalev :x)
(dm/get-prop scalev :y)))]
(gpt/point v v))
scalev) scalev)
;; Resize origin point given the selected handler ;; Resize origin point given the selected handler
handler-origin (handler-resize-origin (:selrect shape) handler) selrect (dm/get-prop shape :selrect)
handler-origin (get-handler-resize-origin selrect handler)
;; If we want resize from center, displace the shape ;; If we want resize from center, displace the shape
;; so it is still centered after resize. ;; so it is still centered after resize.
displacement displacement (when ^boolean center?
(when center? (-> shape-center
(-> shape-center (gpt/subtract handler-origin)
(gpt/subtract handler-origin) (gpt/multiply scalev)
(gpt/multiply scalev) (gpt/add handler-origin)
(gpt/add handler-origin) (gpt/subtract shape-center)
(gpt/subtract shape-center) (gpt/multiply (gpt/point -1 -1))
(gpt/multiply (gpt/point -1 -1)) (gpt/transform shape-transform)))
(gpt/transform shape-transform)))
resize-origin resize-origin (gmt/transform-point-center handler-origin shape-center shape-transform)
(cond-> (gmt/transform-point-center handler-origin shape-center shape-transform) resize-origin (if (some? displacement)
(some? displacement) (gpt/add resize-origin displacement)
(gpt/add displacement)) resize-origin)
;; When the horizontal/vertical scale a flex children with auto/fill ;; When the horizontal/vertical scale a flex children with auto/fill
;; we change it too fixed ;; we change it too fixed
set-fix-width? set-fix-width?
(not (mth/close? (:x scalev) 1)) (not (mth/close? (dm/get-prop scalev :x) 1))
set-fix-height? set-fix-height?
(not (mth/close? (:y scalev) 1)) (not (mth/close? (dm/get-prop scalev :y) 1))
modifiers modifiers (cond-> (ctm/empty)
(-> (ctm/empty) (some? displacement)
(ctm/move displacement)
(cond-> displacement :always
(ctm/move displacement)) (ctm/resize scalev resize-origin shape-transform shape-transform-inverse)
(ctm/resize scalev resize-origin shape-transform shape-transform-inverse) ^boolean set-fix-width?
(ctm/change-property :layout-item-h-sizing :fix)
(cond-> set-fix-width? ^boolean set-fix-height?
(ctm/change-property :layout-item-h-sizing :fix)) (ctm/change-property :layout-item-v-sizing :fix)
(cond-> set-fix-height? ^boolean scale-text
(ctm/change-property :layout-item-v-sizing :fix)) (ctm/scale-content (dm/get-prop scalev :x)))
(cond-> scale-text
(ctm/scale-content (:x scalev))))
modif-tree (dwm/create-modif-tree ids modifiers)] modif-tree (dwm/create-modif-tree ids modifiers)]
(rx/of (dwm/set-modifiers modif-tree scale-text)))) (rx/of (dwm/set-modifiers modif-tree scale-text))))
;; Unifies the instantaneous proportion lock modifier ;; Unifies the instantaneous proportion lock modifier
@ -208,7 +243,10 @@
;; lock flag that can be activated on element options. ;; lock flag that can be activated on element options.
(normalize-proportion-lock [[point shift? alt?]] (normalize-proportion-lock [[point shift? alt?]]
(let [proportion-lock? (:proportion-lock shape)] (let [proportion-lock? (:proportion-lock shape)]
[point (or proportion-lock? shift?) alt?]))] [point
(or ^boolean proportion-lock?
^boolean shift?)
alt?]))]
(reify (reify
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
@ -218,15 +256,16 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
(let [initial-position @ms/mouse-position (let [initial-position @ms/mouse-position
stopper (->> stream stopper (->> stream
(rx/filter mse/mouse-event?) (rx/filter mse/mouse-event?)
(rx/filter mse/mouse-up-event?)) (rx/filter mse/mouse-up-event?))
layout (:workspace-layout state) layout (:workspace-layout state)
page-id (:current-page-id state) page-id (:current-page-id state)
focus (:workspace-focus-selected state) focus (:workspace-focus-selected state)
zoom (get-in state [:workspace-local :zoom] 1) zoom (dm/get-in state [:workspace-local :zoom] 1)
objects (wsh/lookup-page-objects state page-id) objects (wsh/lookup-page-objects state page-id)
resizing-shapes (map #(get objects %) ids)] shapes (map (d/getf objects) ids)]
(rx/concat (rx/concat
(->> ms/mouse-position (->> ms/mouse-position
@ -234,7 +273,7 @@
(rx/with-latest-from ms/mouse-position-shift ms/mouse-position-alt) (rx/with-latest-from ms/mouse-position-shift ms/mouse-position-alt)
(rx/map normalize-proportion-lock) (rx/map normalize-proportion-lock)
(rx/switch-map (fn [[point _ _ :as current]] (rx/switch-map (fn [[point _ _ :as current]]
(->> (snap/closest-snap-point page-id resizing-shapes objects layout zoom focus point) (->> (snap/closest-snap-point page-id shapes objects layout zoom focus point)
(rx/map #(conj current %))))) (rx/map #(conj current %)))))
(rx/mapcat (partial resize shape initial-position layout)) (rx/mapcat (partial resize shape initial-position layout))
(rx/take-until stopper)) (rx/take-until stopper))