mirror of
https://github.com/penpot/penpot.git
synced 2025-04-14 07:51:35 -05:00
🎉 Add packed basic layout positions
This commit is contained in:
parent
aeb8fa1896
commit
1c8aef6fa8
4 changed files with 212 additions and 68 deletions
|
@ -11,31 +11,169 @@
|
|||
[app.common.geom.shapes.rect :as gre]
|
||||
[app.common.geom.shapes.transforms :as gtr]))
|
||||
|
||||
;; :layout ;; true if active, false if not
|
||||
;; :layout-dir ;; :right, :left, :top, :bottom
|
||||
;; :layout-gap ;; number could be negative
|
||||
;; :layout-type ;; :packed, :space-between, :space-around
|
||||
;; :layout-wrap-type ;; :wrap, :no-wrap
|
||||
;; :layout-padding-type ;; :simple, :multiple
|
||||
;; :layout-padding ;; {:p1 num :p2 num :p3 num :p4 num} number could be negative
|
||||
;; :layout-h-orientation ;; :top, :center, :bottom
|
||||
;; :layout-v-orientation ;; :left, :center, :right
|
||||
|
||||
(defn col?
|
||||
[{:keys [layout-dir]}]
|
||||
(or (= :right layout-dir) (= :left layout-dir)))
|
||||
|
||||
(defn row?
|
||||
[{:keys [layout-dir]}]
|
||||
(or (= :top layout-dir) (= :bottom layout-dir)))
|
||||
|
||||
(defn h-start?
|
||||
[{:keys [layout-v-orientation]}]
|
||||
(= layout-v-orientation :left))
|
||||
|
||||
(defn h-center?
|
||||
[{:keys [layout-v-orientation]}]
|
||||
(= layout-v-orientation :center))
|
||||
|
||||
(defn h-end?
|
||||
[{:keys [layout-v-orientation]}]
|
||||
(= layout-v-orientation :right))
|
||||
|
||||
(defn v-start?
|
||||
[{:keys [layout-h-orientation]}]
|
||||
(= layout-h-orientation :top))
|
||||
|
||||
(defn v-center?
|
||||
[{:keys [layout-h-orientation]}]
|
||||
(= layout-h-orientation :center))
|
||||
|
||||
(defn v-end?
|
||||
[{:keys [layout-h-orientation]}]
|
||||
(= layout-h-orientation :bottom))
|
||||
|
||||
(defn add-padding [transformed-rect {:keys [layout-padding-type layout-padding]}]
|
||||
(let [{:keys [p1 p2 p3 p4]} layout-padding
|
||||
[p1 p2 p3 p4]
|
||||
(if (= layout-padding-type :multiple)
|
||||
[p1 p2 p3 p4]
|
||||
[p1 p1 p1 p1])]
|
||||
|
||||
(-> transformed-rect
|
||||
(update :y + p1)
|
||||
(update :width - p2 p3)
|
||||
(update :x + p3)
|
||||
(update :height - p1 p4))))
|
||||
|
||||
(defn calc-layout-data
|
||||
"Digest the layout data to pass it to the constrains"
|
||||
[_parent children transformed-rect]
|
||||
[{:keys [layout-gap] :as shape} children modif-tree transformed-rect]
|
||||
|
||||
(let [[children-width children-height]
|
||||
(->> children (reduce (fn [[acc-width acc-height] shape]
|
||||
[(+ acc-width (-> shape :points gre/points->rect :width))
|
||||
(+ acc-height (-> shape :points gre/points->rect :height))]) [0 0]))]
|
||||
{:start-x (:x transformed-rect)
|
||||
:start-y (:y transformed-rect)
|
||||
:children-width children-width
|
||||
:children-height children-height})
|
||||
(let [transformed-rect (-> transformed-rect (add-padding shape))
|
||||
num-children (count children)
|
||||
children-gap (* layout-gap (dec num-children) )
|
||||
[children-width children-height]
|
||||
(->> children
|
||||
(map #(-> (merge % (get modif-tree (:id %))) gtr/transform-shape))
|
||||
(reduce (fn [[acc-width acc-height] shape]
|
||||
[(+ acc-width (-> shape :points gre/points->rect :width))
|
||||
(+ acc-height (-> shape :points gre/points->rect :height))]) [0 0]))
|
||||
|
||||
{:keys [x y width height]} transformed-rect
|
||||
|
||||
start-x
|
||||
(cond
|
||||
(and (row? shape) (h-center? shape))
|
||||
(+ x (/ width 2))
|
||||
|
||||
(and (row? shape) (h-end? shape))
|
||||
(+ x width)
|
||||
|
||||
(and (col? shape) (h-center? shape))
|
||||
(- (+ x (/ width 2)) (/ (+ children-width children-gap) 2))
|
||||
|
||||
(and (col? shape) (h-end? shape))
|
||||
(- (+ x width) (+ children-width children-gap))
|
||||
|
||||
:else
|
||||
(:x transformed-rect))
|
||||
|
||||
start-y
|
||||
(cond
|
||||
(and (col? shape) (v-center? shape))
|
||||
(+ y (/ height 2))
|
||||
|
||||
(and (col? shape) (v-end? shape))
|
||||
(+ y height)
|
||||
|
||||
(and (row? shape) (v-center? shape))
|
||||
(- (+ y (/ height 2)) (/ (+ children-height children-gap) 2))
|
||||
|
||||
(and (row? shape) (v-end? shape))
|
||||
(- (+ y height) (+ children-height children-gap))
|
||||
|
||||
:else
|
||||
(:y transformed-rect) )]
|
||||
|
||||
{:start-x start-x
|
||||
:start-y start-y
|
||||
:reverse? (or (= :left (:layout-dir shape)) (= :bottom (:layout-dir shape)))}))
|
||||
|
||||
(defn next-p
|
||||
"Calculates the position for the current shape given the layout-data context"
|
||||
[{:keys [layout-gap] :as shape} {:keys [width height]} {:keys [start-x start-y] :as layout-data}]
|
||||
|
||||
(let [pos-x
|
||||
(cond
|
||||
(and (row? shape) (h-center? shape))
|
||||
(- start-x (/ width 2))
|
||||
|
||||
(and (row? shape) (h-end? shape))
|
||||
(- start-x width)
|
||||
|
||||
:else
|
||||
start-x)
|
||||
|
||||
pos-y
|
||||
(cond
|
||||
(and (col? shape) (v-center? shape))
|
||||
(- start-y (/ height 2))
|
||||
|
||||
(and (col? shape) (v-end? shape))
|
||||
(- start-y height)
|
||||
|
||||
:else
|
||||
start-y)
|
||||
|
||||
corner-p (gpt/point pos-x pos-y)
|
||||
|
||||
next-x
|
||||
(if (col? shape)
|
||||
(+ start-x width layout-gap)
|
||||
start-x)
|
||||
|
||||
next-y
|
||||
(if (row? shape)
|
||||
(+ start-y height layout-gap)
|
||||
start-y)
|
||||
|
||||
layout-data
|
||||
(assoc layout-data :start-x next-x :start-y next-y)]
|
||||
[corner-p layout-data])
|
||||
)
|
||||
|
||||
(defn calc-layout-modifiers
|
||||
[_parent child current-modifier _modifiers _transformed-rect {:keys [start-x start-y] :as layout-data}]
|
||||
"Calculates the modifiers for the layout"
|
||||
[parent child current-modifier _modifiers _transformed-rect layout-data]
|
||||
|
||||
(let [current-modifier (dissoc current-modifier :displacement-after)
|
||||
child' (-> child (assoc :modifiers current-modifier) gtr/transform-shape)
|
||||
bounds' (-> child' :points gre/points->selrect)
|
||||
corner-p (gpt/point start-x start-y)
|
||||
displacement (gmt/translate-matrix (gpt/subtract corner-p (gpt/point bounds')))
|
||||
modifiers (-> current-modifier
|
||||
(assoc :displacement-after displacement))
|
||||
(let [current-modifier (-> current-modifier (dissoc :displacement-after))
|
||||
child (-> child (assoc :modifiers current-modifier) gtr/transform-shape)
|
||||
bounds (-> child :points gre/points->selrect)
|
||||
|
||||
next-x (+ start-x (:width bounds'))]
|
||||
[corner-p layout-data] (next-p parent bounds layout-data)
|
||||
|
||||
[modifiers (assoc layout-data :start-x next-x )]))
|
||||
delta-p (-> corner-p (gpt/subtract (gpt/point bounds)))
|
||||
modifiers (-> current-modifier (assoc :displacement-after (gmt/translate-matrix delta-p)))]
|
||||
|
||||
[modifiers layout-data]))
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
[app.main.data.workspace.changes :as dch]
|
||||
[app.main.data.workspace.edition :as dwe]
|
||||
[app.main.data.workspace.selection :as dws]
|
||||
[app.main.data.workspace.shape-layout :as dwsl]
|
||||
[app.main.data.workspace.state-helpers :as wsh]
|
||||
[app.main.streams :as ms]
|
||||
[app.util.names :as un]
|
||||
|
@ -98,6 +99,7 @@
|
|||
|
||||
(rx/concat
|
||||
(rx/of (dch/commit-changes changes)
|
||||
(dwsl/update-layout-positions [(:parent-id shape)])
|
||||
(when-not no-select?
|
||||
(dws/select-shapes (d/ordered-set id))))
|
||||
(when (= :text (:type attrs))
|
||||
|
@ -239,7 +241,8 @@
|
|||
flows
|
||||
starting-flows)))))]
|
||||
|
||||
(rx/of (dch/commit-changes changes))))))
|
||||
(rx/of (dch/commit-changes changes)
|
||||
(dwsl/update-layout-positions all-parents))))))
|
||||
|
||||
(defn- viewport-center
|
||||
[state]
|
||||
|
|
|
@ -415,12 +415,12 @@
|
|||
|
||||
(cond
|
||||
(:layout shape)
|
||||
(let [result
|
||||
(->> children
|
||||
(reduce (partial set-layout-child (and snap-pixel? resize-modif?))
|
||||
(merge {:modif-tree modif-tree}
|
||||
(gsh/calc-layout-data shape children transformed-rect))))]
|
||||
(:modif-tree result))
|
||||
(let [layout-data (gsh/calc-layout-data shape children modif-tree transformed-rect)
|
||||
children (cond-> children (:reverse? layout-data) reverse)]
|
||||
(->> children
|
||||
(reduce (partial set-layout-child (and snap-pixel? resize-modif?))
|
||||
(merge {:modif-tree modif-tree} layout-data))
|
||||
:modif-tree))
|
||||
|
||||
:else
|
||||
modif-tree)))]
|
||||
|
|
|
@ -88,9 +88,11 @@
|
|||
type (:layout-type values)
|
||||
is-col? (or (= dir :top)
|
||||
(= dir :bottom))
|
||||
saved-pos [(:layout-h-orientation values) (:layout-v-orientation values)]]
|
||||
saved-pos [(:layout-h-orientation values)
|
||||
(:layout-v-orientation values)]]
|
||||
|
||||
(if (= type :packed)
|
||||
(cond
|
||||
(= type :packed)
|
||||
[:div.orientation-grid
|
||||
[:div.button-wrapper
|
||||
(for [[pv ph] grid-pos]
|
||||
|
@ -110,47 +112,48 @@
|
|||
:rotated is-col?)}
|
||||
(get-layout-icon dir type pv ph)]])]]
|
||||
|
||||
(if is-col?
|
||||
[:div.orientation-grid.col
|
||||
[:div.button-wrapper
|
||||
(for [[idx col] (d/enumerate grid-cols)]
|
||||
[:button.orientation
|
||||
{:key (dm/str idx col)
|
||||
:on-click (partial on-change-orientation :top col type)
|
||||
:class (dom/classnames
|
||||
:active (= col (second saved-pos))
|
||||
:top (= :left col)
|
||||
:centered (= :center col)
|
||||
:bottom (= :right col))}
|
||||
[:span.icon
|
||||
{:class (dom/classnames :rotated is-col?)}
|
||||
(get-layout-icon dir type nil col)]
|
||||
[:span.icon
|
||||
{:class (dom/classnames :rotated is-col?)}
|
||||
(get-layout-icon dir type nil col)]
|
||||
[:span.icon
|
||||
{:class (dom/classnames :rotated is-col?)}
|
||||
(get-layout-icon dir type nil col)]])]]
|
||||
is-col?
|
||||
[:div.orientation-grid.col
|
||||
[:div.button-wrapper
|
||||
(for [[idx col] (d/enumerate grid-cols)]
|
||||
[:button.orientation
|
||||
{:key (dm/str idx col)
|
||||
:on-click (partial on-change-orientation :top col type)
|
||||
:class (dom/classnames
|
||||
:active (= col (second saved-pos))
|
||||
:top (= :left col)
|
||||
:centered (= :center col)
|
||||
:bottom (= :right col))}
|
||||
[:span.icon
|
||||
{:class (dom/classnames :rotated is-col?)}
|
||||
(get-layout-icon dir type nil col)]
|
||||
[:span.icon
|
||||
{:class (dom/classnames :rotated is-col?)}
|
||||
(get-layout-icon dir type nil col)]
|
||||
[:span.icon
|
||||
{:class (dom/classnames :rotated is-col?)}
|
||||
(get-layout-icon dir type nil col)]])]]
|
||||
|
||||
[:div.orientation-grid.row
|
||||
[:div.button-wrapper
|
||||
(for [row grid-rows]
|
||||
[:button.orientation
|
||||
{:on-click (partial on-change-orientation row :left type)
|
||||
:class (dom/classnames
|
||||
:active (= row (first saved-pos))
|
||||
:top (= :top row)
|
||||
:centered (= :center row)
|
||||
:bottom (= :bottom row))}
|
||||
[:span.icon
|
||||
{:class (dom/classnames :rotated is-col?)}
|
||||
(get-layout-icon dir type row nil)]
|
||||
[:span.icon
|
||||
{:class (dom/classnames :rotated is-col?)}
|
||||
(get-layout-icon dir type row nil)]
|
||||
[:span.icon
|
||||
{:class (dom/classnames :rotated is-col?)}
|
||||
(get-layout-icon dir type row nil)]])]]))))
|
||||
:else
|
||||
[:div.orientation-grid.row
|
||||
[:div.button-wrapper
|
||||
(for [row grid-rows]
|
||||
[:button.orientation
|
||||
{:on-click (partial on-change-orientation row :left type)
|
||||
:class (dom/classnames
|
||||
:active (= row (first saved-pos))
|
||||
:top (= :top row)
|
||||
:centered (= :center row)
|
||||
:bottom (= :bottom row))}
|
||||
[:span.icon
|
||||
{:class (dom/classnames :rotated is-col?)}
|
||||
(get-layout-icon dir type row nil)]
|
||||
[:span.icon
|
||||
{:class (dom/classnames :rotated is-col?)}
|
||||
(get-layout-icon dir type row nil)]
|
||||
[:span.icon
|
||||
{:class (dom/classnames :rotated is-col?)}
|
||||
(get-layout-icon dir type row nil)]])]])))
|
||||
|
||||
(mf/defc padding-section
|
||||
[{:keys [values on-change-style on-change] :as props}]
|
||||
|
|
Loading…
Add table
Reference in a new issue