mirror of
https://github.com/penpot/penpot.git
synced 2025-01-25 07:58:49 -05:00
🎉 Add support for wrap layout
This commit is contained in:
parent
6e5a23c190
commit
5e5355230c
2 changed files with 196 additions and 73 deletions
|
@ -8,8 +8,7 @@
|
|||
(:require
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes.rect :as gre]
|
||||
[app.common.geom.shapes.transforms :as gtr]))
|
||||
[app.common.geom.shapes.rect :as gre]))
|
||||
|
||||
;; :layout ;; true if active, false if not
|
||||
;; :layout-dir ;; :right, :left, :top, :bottom
|
||||
|
@ -66,20 +65,157 @@
|
|||
(update :x + p3)
|
||||
(update :height - p1 p4))))
|
||||
|
||||
(defn calc-layout-data
|
||||
"Digest the layout data to pass it to the constrains"
|
||||
[{:keys [layout-type layout-gap] :as shape} children modif-tree transformed-rect]
|
||||
(defn calc-layout-lines
|
||||
[{:keys [layout-gap layout-wrap-type] :as shape} children {:keys [width height] :as layout-bounds}]
|
||||
|
||||
(let [{:keys [x y width height]} (-> transformed-rect (add-padding shape))
|
||||
num-children (count children)
|
||||
(let [wrap? (= layout-wrap-type :wrap)
|
||||
|
||||
[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]))
|
||||
reduce-fn
|
||||
(fn [[{:keys [line-width line-height num-children] :as line-data} result] child]
|
||||
(let [child-bounds (-> child :points gre/points->rect)
|
||||
next-width (-> child-bounds :width)
|
||||
next-height (-> child-bounds :height)]
|
||||
|
||||
layout-gap
|
||||
(if (and (some? line-data)
|
||||
(or (not wrap?)
|
||||
(and (col? shape) (<= (+ line-width next-width (* layout-gap num-children)) width))
|
||||
(and (row? shape) (<= (+ line-height next-height (* layout-gap num-children)) height))))
|
||||
|
||||
[{:line-width (if (col? shape) (+ line-width next-width) (max line-width next-width))
|
||||
:line-height (if (row? shape) (+ line-height next-height) (max line-height next-height))
|
||||
:num-children (inc num-children)}
|
||||
result]
|
||||
|
||||
[{:line-width next-width
|
||||
:line-height next-height
|
||||
:num-children 1}
|
||||
(cond-> result (some? line-data) (conj line-data))])))
|
||||
|
||||
[line-data layout-lines] (reduce reduce-fn [nil []] children)]
|
||||
|
||||
(cond-> layout-lines (some? line-data) (conj line-data))))
|
||||
|
||||
(defn calc-layout-lines-position
|
||||
[{:keys [layout-gap layout-type] :as shape} {:keys [x y width height]} layout-lines]
|
||||
|
||||
(letfn [(get-base-line
|
||||
[total-width total-height]
|
||||
|
||||
(let [base-x
|
||||
(cond
|
||||
(and (row? shape) (h-center? shape))
|
||||
(+ x (/ (- width total-width) 2))
|
||||
|
||||
(and (row? shape) (h-end? shape))
|
||||
(+ x width (- total-width))
|
||||
|
||||
:else x)
|
||||
|
||||
base-y
|
||||
(cond
|
||||
(and (col? shape) (v-center? shape))
|
||||
(+ y (/ (- height total-height) 2))
|
||||
|
||||
(and (col? shape) (v-end? shape))
|
||||
(+ y height (- total-height))
|
||||
|
||||
:else y)]
|
||||
|
||||
[base-x base-y]))
|
||||
|
||||
(get-start-line
|
||||
[{:keys [line-width line-height num-children]} base-x base-y]
|
||||
|
||||
(let [children-gap (* layout-gap (dec num-children))
|
||||
|
||||
start-x
|
||||
(cond
|
||||
(or (and (col? shape) (= :space-between layout-type))
|
||||
(and (col? shape) (= :space-around layout-type)))
|
||||
x
|
||||
|
||||
(and (col? shape) (h-center? shape))
|
||||
(- (+ x (/ width 2)) (/ (+ line-width children-gap) 2))
|
||||
|
||||
(and (col? shape) (h-end? shape))
|
||||
(- (+ x width) (+ line-width children-gap))
|
||||
|
||||
(and (row? shape) (h-center? shape))
|
||||
(+ base-x (/ line-width 2))
|
||||
|
||||
(and (row? shape) (h-end? shape))
|
||||
(+ base-x line-width)
|
||||
|
||||
(row? shape)
|
||||
base-x
|
||||
|
||||
:else
|
||||
x)
|
||||
|
||||
start-y
|
||||
(cond
|
||||
(or (and (row? shape) (= :space-between layout-type))
|
||||
(and (row? shape) (= :space-around layout-type)))
|
||||
y
|
||||
|
||||
(and (row? shape) (v-center? shape))
|
||||
(- (+ y (/ height 2)) (/ (+ line-height children-gap) 2))
|
||||
|
||||
(and (row? shape) (v-end? shape))
|
||||
(- (+ y height) (+ line-height children-gap))
|
||||
|
||||
(and (col? shape) (v-center? shape))
|
||||
(+ base-y (/ line-height 2))
|
||||
|
||||
(and (col? shape) (v-end? shape))
|
||||
(+ base-y line-height)
|
||||
|
||||
(col? shape)
|
||||
base-y
|
||||
|
||||
:else
|
||||
y)]
|
||||
[start-x start-y]))
|
||||
|
||||
(get-next-line
|
||||
[{:keys [line-width line-height]} base-x base-y]
|
||||
(let [next-x (if (col? shape) base-x (+ base-x line-width layout-gap))
|
||||
next-y (if (row? shape) base-y (+ base-y line-height layout-gap))]
|
||||
[next-x next-y]))
|
||||
|
||||
(add-lines [[total-width total-height] {:keys [line-width line-height]}]
|
||||
[(+ total-width line-width)
|
||||
(+ total-height line-height)])
|
||||
|
||||
(add-starts [[result base-x base-y] layout-line]
|
||||
(let [[start-x start-y] (get-start-line layout-line base-x base-y)
|
||||
[next-x next-y] (get-next-line layout-line base-x base-y)]
|
||||
[(conj result
|
||||
(assoc layout-line
|
||||
:start-x start-x
|
||||
:start-y start-y))
|
||||
next-x
|
||||
next-y]))]
|
||||
|
||||
(let [[total-width total-height]
|
||||
(->> layout-lines (reduce add-lines [0 0]))
|
||||
|
||||
total-width (+ total-width (* layout-gap (dec (count layout-lines))))
|
||||
total-height (+ total-height (* layout-gap (dec (count layout-lines))))
|
||||
|
||||
[base-x base-y]
|
||||
(get-base-line total-width total-height)
|
||||
|
||||
[layout-lines _ _ _ _]
|
||||
(reduce add-starts [[] base-x base-y] layout-lines)]
|
||||
layout-lines)))
|
||||
|
||||
(defn calc-layout-line-data
|
||||
[{:keys [layout-type layout-gap] :as shape}
|
||||
{:keys [width height] :as layout-bounds}
|
||||
{:keys [num-children line-width line-height] :as line-data}]
|
||||
|
||||
(let [layout-gap
|
||||
(cond
|
||||
(= :packed layout-type)
|
||||
layout-gap
|
||||
|
@ -88,73 +224,47 @@
|
|||
0
|
||||
|
||||
(and (col? shape) (= :space-between layout-type))
|
||||
(/ (- width children-width) (dec num-children))
|
||||
(/ (- width line-width) (dec num-children))
|
||||
|
||||
(and (row? shape) (= :space-between layout-type))
|
||||
(/ (- height children-height) (dec num-children)))
|
||||
(/ (- height line-height) (dec num-children)))
|
||||
|
||||
margin-x (if (and (col? shape) (= :space-around layout-type))
|
||||
(/ (- width children-width) (dec num-children) 2)
|
||||
0)
|
||||
margin-x
|
||||
(if (and (col? shape) (= :space-around layout-type))
|
||||
(/ (- width line-width) (inc num-children) )
|
||||
0)
|
||||
|
||||
margin-y (if (and (row? shape) (= :space-around layout-type))
|
||||
(/ (- height children-height) (inc num-children))
|
||||
0)
|
||||
margin-y
|
||||
(if (and (row? shape) (= :space-around layout-type))
|
||||
(/ (- height line-height) (inc num-children))
|
||||
0)]
|
||||
|
||||
children-gap (* layout-gap (dec num-children))
|
||||
(assoc line-data
|
||||
:layout-gap layout-gap
|
||||
:margin-x margin-x
|
||||
:margin-y margin-y)))
|
||||
|
||||
start-x
|
||||
(cond
|
||||
(or (and (col? shape) (= :space-between layout-type))
|
||||
(and (col? shape) (= :space-around layout-type)))
|
||||
x
|
||||
|
||||
(and (row? shape) (h-center? shape))
|
||||
(+ x (/ width 2))
|
||||
(defn calc-layout-data
|
||||
"Digest the layout data to pass it to the constrains"
|
||||
[{:keys [layout-dir] :as shape} children layout-bounds]
|
||||
|
||||
(and (row? shape) (h-end? shape))
|
||||
(+ x width)
|
||||
(let [reverse? (or (= :left layout-dir) (= :bottom layout-dir))
|
||||
layout-bounds (-> layout-bounds (add-padding shape))
|
||||
children (cond->> children reverse? reverse)
|
||||
layout-lines
|
||||
(->> (calc-layout-lines shape children layout-bounds)
|
||||
(calc-layout-lines-position shape layout-bounds)
|
||||
(map (partial calc-layout-line-data shape layout-bounds)))]
|
||||
|
||||
(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)
|
||||
|
||||
start-y
|
||||
(cond
|
||||
(or (and (row? shape) (= :space-between layout-type))
|
||||
(and (row? shape) (= :space-around layout-type)))
|
||||
y
|
||||
|
||||
(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)]
|
||||
|
||||
{:start-x start-x
|
||||
:start-y start-y
|
||||
:layout-gap layout-gap
|
||||
:margin-x margin-x
|
||||
:margin-y margin-y
|
||||
:reverse? (or (= :left (:layout-dir shape)) (= :bottom (:layout-dir shape)))}))
|
||||
{:layout-lines layout-lines
|
||||
:reverse? reverse?}))
|
||||
|
||||
(defn next-p
|
||||
"Calculates the position for the current shape given the layout-data context"
|
||||
[shape {:keys [width height]} {:keys [start-x start-y layout-gap margin-x margin-y] :as layout-data}]
|
||||
[shape
|
||||
{:keys [width height]}
|
||||
{:keys [start-x start-y layout-gap margin-x margin-y] :as layout-data}]
|
||||
|
||||
(let [pos-x
|
||||
(cond
|
||||
|
|
|
@ -165,13 +165,26 @@
|
|||
modifiers (get-in modif-tree [id :modifiers])
|
||||
|
||||
transformed-rect (gtr/transform-selrect (:selrect shape) modifiers)
|
||||
layout-data (gcl/calc-layout-data shape children modif-tree transformed-rect)
|
||||
children (cond-> children (:reverse? layout-data) reverse)
|
||||
layout-data (gcl/calc-layout-data shape children transformed-rect)
|
||||
children (into [] (cond-> children (:reverse? layout-data) reverse))
|
||||
|
||||
[_ modif-tree]
|
||||
(reduce (partial set-layout-modifiers shape) [layout-data modif-tree] children)]
|
||||
max-idx (dec (count children))
|
||||
layout-lines (:layout-lines layout-data)]
|
||||
|
||||
modif-tree)))
|
||||
(loop [modif-tree modif-tree
|
||||
layout-line (first layout-lines)
|
||||
pending (rest layout-lines)
|
||||
from-idx 0]
|
||||
(if (and (some? layout-line) (<= from-idx max-idx))
|
||||
(let [to-idx (+ from-idx (:num-children layout-line))
|
||||
children (subvec children from-idx to-idx)
|
||||
|
||||
[_ modif-tree]
|
||||
(reduce (partial set-layout-modifiers shape) [layout-line modif-tree] children)]
|
||||
|
||||
(recur modif-tree (first pending) (rest pending) to-idx))
|
||||
|
||||
modif-tree)))))
|
||||
|
||||
(defn get-first-layout
|
||||
[id objects]
|
||||
|
|
Loading…
Add table
Reference in a new issue