0
Fork 0
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:
alonso.torres 2022-07-07 14:53:24 +02:00 committed by Andrey Antukh
parent 6e5a23c190
commit 5e5355230c
2 changed files with 196 additions and 73 deletions

View file

@ -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

View file

@ -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]