0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-02-13 10:38:13 -05:00

Support rotated UI

This commit is contained in:
alonso.torres 2023-05-26 11:46:38 +02:00
parent b83c35b0dd
commit 03c64303f5
3 changed files with 102 additions and 82 deletions

View file

@ -242,7 +242,6 @@
children (->> (cph/get-immediate-children objects (:id frame))
(remove :hidden)
(map #(vector (gpo/parent-coords-bounds (:points %) (:points frame)) %)))
layout-data (ld/calc-layout-data frame children (:points frame))
position (gmt/transform-point-center position (gco/center-shape frame) (:transform-inverse frame))]
layout-data (ld/calc-layout-data frame children (:points frame))]
(get-position-grid-coord layout-data position)))

View file

@ -160,6 +160,7 @@
(fn [event]
(when (and (nil? selrect)
(or (dom/class? (dom/get-target event) "viewport-controls")
(dom/child? (dom/get-target event) (dom/query ".viewport-controls"))
(dom/class? (dom/get-target event) "viewport-selrect")))
(let [ctrl? (kbd/ctrl? event)
shift? (kbd/shift? event)
@ -233,11 +234,11 @@
(if workspace-read-only?
(dom/prevent-default event)
(when (or (dom/class? (dom/get-target event) "viewport-controls")
(dom/class? (dom/get-target event) "viewport-selrect"))
(dom/prevent-default event)
(dom/child? (dom/get-target event) (dom/query ".viewport-controls"))
(dom/class? (dom/get-target event) "viewport-selrect")
workspace-read-only?)
(let [position (dom/get-client-position event)]
;; Delayed callback because we need to wait to the previous context menu to be closed
;; Delayed callback because we need to wait to the previous context menu to be closed
(timers/schedule
#(st/emit!
(if (some? @hover)

View file

@ -9,7 +9,9 @@
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.geom.matrix :as gmt]
[app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh]
[app.common.geom.shapes.grid-layout :as gsg]
[app.common.geom.shapes.points :as gpo]
[app.common.math :as mth]
@ -170,7 +172,10 @@
direction (unchecked-get props "direction")
layout-data (unchecked-get props "layout-data")
cursor (if (= direction :row) (cur/scale-ns 0) (cur/scale-ew 0))
cursor
(if (= direction :row)
(cur/scale-ns (:rotation shape))
(cur/scale-ew (:rotation shape)))
handle-drag-position
(mf/use-callback
@ -277,6 +282,8 @@
cell-origin (gpo/origin cell-bounds)
cell-width (gpo/width-points cell-bounds)
cell-height (gpo/height-points cell-bounds)
cell-center (gsh/center-points cell-bounds)
cell-origin (gpt/transform cell-origin (gmt/transform-in cell-center (:transform-inverse shape)))
handle-pointer-enter
(mf/use-callback
@ -298,7 +305,8 @@
[:g.cell-editor
[:rect
{:class (dom/classnames (css :grid-cell-outline) true
{:transform (dm/str (gmt/transform-in cell-center (:transform shape)))
:class (dom/classnames (css :grid-cell-outline) true
(css :hover) hover?
(css :selected) selected?)
:x (:x cell-origin)
@ -323,7 +331,7 @@
[:right (+ (:x cell-origin) cell-width (/ -10 zoom)) (:y cell-origin) (/ 20 zoom) cell-height :column]
[:bottom (:x cell-origin) (+ (:y cell-origin) cell-height (/ -10 zoom)) cell-width (/ 20 zoom) :row]
[:left (+ (:x cell-origin) (/ -10 zoom)) (:y cell-origin) (/ 20 zoom) cell-height :column]]]
[:*
[:g {:transform (dm/str (gmt/transform-in cell-center (:transform shape)))}
(for [[handler x y width height dir] handlers]
[:& resize-cell-handler {:key (dm/str "resize-" (d/name handler) "-" (:id cell))
:shape shape
@ -402,6 +410,7 @@
(let [shape (unchecked-get props "shape")
index (unchecked-get props "index")
last? (unchecked-get props "last?")
track-before (unchecked-get props "track-before")
track-after (unchecked-get props "track-after")
snap-pixel? (unchecked-get props "snap-pixel?")
@ -411,35 +420,54 @@
type (unchecked-get props "type")
zoom (unchecked-get props "zoom")
bounds (:points shape)
hv #(gpo/start-hv bounds %)
vv #(gpo/start-vv bounds %)
[layout-gap-row layout-gap-col] (ctl/gaps shape)
{:keys [handle-pointer-down handle-lost-pointer-capture handle-pointer-move]}
(use-resize-track type shape index track-before track-after zoom snap-pixel?)
[x y width height]
[width height]
(if (= type :column)
[(- (:x start-p) layout-gap-col (/ (- (max layout-gap-col (/ 16 zoom)) layout-gap-col) 2))
(:y start-p)
(max layout-gap-col (/ 16 zoom))
[(max layout-gap-col (/ 16 zoom))
(+ row-total-size row-total-gap)]
[(:x start-p)
(- (:y start-p) layout-gap-row (/ (- (max layout-gap-row (/ 16 zoom)) layout-gap-row) 2))
(+ column-total-size column-total-gap)
(max layout-gap-row (/ 16 zoom))])]
[(+ column-total-size column-total-gap)
(max layout-gap-row (/ 16 zoom))])
start-p
(cond-> start-p
(and (= type :column) (= index 0))
(gpt/subtract (hv width))
(and (= type :row) (= index 0))
(gpt/subtract (vv height))
(and (= type :column) (not= index 0) (not last?))
(-> (gpt/subtract (hv (/ layout-gap-col 2)))
(gpt/subtract (hv (/ width 2))))
(and (= type :row) (not= index 0) (not last?))
(-> (gpt/subtract (vv (/ layout-gap-row 2)))
(gpt/subtract (vv (/ height 2)))))]
[:rect.resize-track-handler
{:x x
:y y
:class (if (= type :column)
"resize-ew-0"
"resize-ns-0")
{:x (:x start-p)
:y (:y start-p)
:height height
:width width
:on-pointer-down handle-pointer-down
:on-lost-pointer-capture handle-lost-pointer-capture
:on-pointer-move handle-pointer-move
:style {:fill "transparent"}}]))
:transform (dm/str (gmt/transform-in start-p (:transform shape)))
:style {:fill "transparent"
:opacity 0.5
:stroke-width 0
:cursor (if (= type :column)
(cur/resize-ew (:rotation shape))
(cur/resize-ns (:rotation shape)))}}]))
(mf/defc track-marker
{::mf/wrap-props false}
@ -482,9 +510,11 @@
:on-lost-pointer-capture handle-lost-pointer-capture
:on-pointer-move handle-pointer-move
:class (css :grid-track-marker)
:transform (dm/str (gmt/transform-in center (:transform shape)))
:style {:cursor (if (= type :column)
(cur/resize-ew 0)
(cur/resize-ns 0))}}
(cur/resize-ew (:rotation shape))
(cur/resize-ns (:rotation shape)))}}
[:polygon {:class (css :marker-shape)
:points (->> marker-points
(map #(dm/fmt "%,%" (:x %) (:y %)))
@ -493,7 +523,7 @@
:x text-x
:y text-y
:width (/ 26.26 zoom)
:height (/ 32 zoom)
:height (/ 36 zoom)
:text-anchor "middle"
:dominant-baseline "middle"}
(dm/str value)]]))
@ -512,38 +542,28 @@
track-input-ref (mf/use-ref)
[layout-gap-row layout-gap-col] (ctl/gaps shape)
bounds (:points shape)
origin (gpo/origin bounds)
vv #(gpo/start-vv bounds %)
hv #(gpo/start-hv bounds %)
start-p (:start-p track-data)
relative (gpt/to-vec origin start-p)
hpt (gpo/project-point bounds :h start-p)
vpt (gpo/project-point bounds :v start-p)
marker-p
(if (= type :column)
(-> origin
(gpt/add (hv (:x relative)))
(-> hpt
(gpt/subtract (vv (/ 20 zoom)))
(cond-> (not= index 0)
(gpt/subtract (hv (/ layout-gap-col 2)))))
(-> origin
(gpt/add (vv (:y relative)))
(-> vpt
(gpt/subtract (hv (/ 20 zoom)))
(cond-> (not= index 0)
(gpt/subtract (vv (/ layout-gap-row 2))))))
text-p
(if (= type :column)
(-> origin
(gpt/add (hv (:x relative)))
(gpt/subtract (vv (/ 36 zoom))))
(-> origin
(gpt/add (vv (:y relative)))
(gpt/subtract (hv (/ (:size track-data) 2)))
(gpt/subtract (hv (/ 16 zoom)))
(gpt/add (vv (/ (:size track-data) 2)))
(gpt/subtract (vv (/ 18 zoom)))))
text-p (if (= type :column) hpt vpt)
handle-blur-track-input
(mf/use-callback
@ -585,8 +605,8 @@
track-list-prop (if (= type :column) :column-tracks :row-tracks)
[text-x text-y text-width text-height]
(if (= type :column)
[(:x text-p) (:y text-p) (max 0 (- (:size track-data) 4)) (/ 32 zoom)]
[(:x text-p) (:y text-p) (:size track-data) (/ 36 zoom)])
[(:x text-p) (- (:y text-p) (/ 36 zoom)) (max 0 (:size track-data)) (/ 36 zoom)]
[(- (:x text-p) (max 0 (:size track-data))) (- (:y text-p) (/ 36 zoom)) (max 0 (:size track-data)) (/ 36 zoom)])
track-before (get-in layout-data [track-list-prop (dec index)])]
@ -596,17 +616,9 @@
(dom/set-value! (mf/ref-val track-input-ref) (format-size track-data))))
[:g.track
[:g {:transform (when (= type :row) (dm/fmt "rotate(-90 % %)" (:x marker-p) (:y marker-p)))}
[:& track-marker {:center marker-p
:index index
:shape shape
:snap-pixel? snap-pixel?
:track-after track-data
:track-before track-before
:type type
:value (dm/str (inc index))
:zoom zoom}]]
[:g {:transform (when (= type :row) (dm/fmt "rotate(-90 % %)" (+ (:x text-p) (/ (:size track-data) 2)) (+ (:y text-p) (/ 36 zoom 2))))}
[:g {:transform (if (= type :column)
(dm/str (gmt/transform-in text-p (:transform shape)))
(dm/str (gmt/transform-in text-p (gmt/rotate (:transform shape) -90))))}
[:foreignObject {:x text-x :y text-y :width text-width :height text-height}
[:input
{:ref track-input-ref
@ -617,6 +629,18 @@
:on-key-down handle-keydown-track-input
:on-blur handle-blur-track-input}]]]
[:g {:transform (when (= type :row) (dm/fmt "rotate(-90 % %)" (:x marker-p) (:y marker-p)))}
[:& track-marker
{:center marker-p
:index index
:shape shape
:snap-pixel? snap-pixel?
:track-after track-data
:track-before track-before
:type type
:value (dm/str (inc index))
:zoom zoom}]]
[:& resize-track-handler
{:index index
:layout-data layout-data
@ -668,8 +692,6 @@
height (gpo/height-points bounds)
origin (gpo/origin bounds)
[layout-gap-row layout-gap-col] (ctl/gaps shape)
{:keys [row-tracks column-tracks] :as layout-data}
(mf/use-memo
(mf/deps shape children)
@ -705,16 +727,18 @@
[:& grid-editor-frame {:zoom zoom
:bounds bounds}]
(let [start-p (-> origin (gpt/add (hv width)))]
[:& plus-btn {:start-p start-p
:zoom zoom
:type :column
:on-click handle-add-column}])
[:g {:transform (dm/str (gmt/transform-in start-p (:transform shape)))}
[:& plus-btn {:start-p start-p
:zoom zoom
:type :column
:on-click handle-add-column}]])
(let [start-p (-> origin (gpt/add (vv height)))]
[:& plus-btn {:start-p start-p
:zoom zoom
:type :row
:on-click handle-add-row}])
[:g {:transform (dm/str (gmt/transform-in start-p (:transform shape)))}
[:& plus-btn {:start-p start-p
:zoom zoom
:type :row
:on-click handle-add-row}]])
(for [[idx column-data] (d/enumerate column-tracks)]
[:& track {:key (dm/str "column-track-" idx)
@ -729,12 +753,10 @@
;; Last track resize handler
(when-not (empty? column-tracks)
(let [last-track (last column-tracks)
start-p (:start-p (last column-tracks))
relative (gpt/to-vec origin start-p)
marker-p (-> origin
(gpt/add (hv (:x relative)))
(gpt/subtract (vv (/ 20 zoom)))
(gpt/add (hv (:size last-track))))]
start-p (:start-p last-track)
end-p (gpt/add start-p (hv (:size last-track)))
marker-p (-> (gpo/project-point bounds :h end-p)
(gpt/subtract (vv (/ 20 zoom))))]
[:g.track
[:& track-marker {:center marker-p
:index (count column-tracks)
@ -746,10 +768,11 @@
:zoom zoom}]
[:& resize-track-handler
{:index (count column-tracks)
:last? true
:shape shape
:layout-data layout-data
:snap-pixel? snap-pixel?
:start-p (-> start-p (gpt/add (hv (+ layout-gap-col (:size last-track)))))
:start-p end-p
:type :column
:track-before (last column-tracks)
:zoom zoom}]]))
@ -766,13 +789,10 @@
(when-not (empty? row-tracks)
(let [last-track (last row-tracks)
start-p (:start-p (last row-tracks))
relative (gpt/to-vec origin start-p)
marker-p
(-> origin
(gpt/add (vv (:y relative)))
(gpt/subtract (hv (/ 20 zoom)))
(gpt/add (vv (:size last-track))))]
start-p (:start-p last-track)
end-p (gpt/add start-p (vv (:size last-track)))
marker-p (-> (gpo/project-point bounds :v end-p)
(gpt/subtract (hv (/ 20 zoom))))]
[:g.track
[:g {:transform (dm/fmt "rotate(-90 % %)" (:x marker-p) (:y marker-p))}
[:& track-marker {:center marker-p
@ -785,10 +805,10 @@
:zoom zoom}]]
[:& resize-track-handler
{:index (count row-tracks)
:last? true
:shape shape
:layout-data layout-data
:start-p (-> start-p
(gpt/add (vv (+ layout-gap-row (:size last-track)))))
:start-p end-p
:type :row
:track-before (last row-tracks)
:snap-pixel? snap-pixel?