0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-10 08:50:57 -05:00

Improve flex layout data calculation

This commit is contained in:
alonso.torres 2023-10-18 15:50:42 +02:00
parent be68e45f65
commit 9d6e4c9e2f
2 changed files with 108 additions and 104 deletions

View file

@ -7,6 +7,7 @@
(ns app.common.geom.shapes.flex-layout.bounds (ns app.common.geom.shapes.flex-layout.bounds
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.geom.shapes.points :as gpo] [app.common.geom.shapes.points :as gpo]
[app.common.types.shape.layout :as ctl])) [app.common.types.shape.layout :as ctl]))
@ -31,7 +32,6 @@
(child-layout-bound-points parent child parent-bounds child-bounds (gpt/point) bounds objects)) (child-layout-bound-points parent child parent-bounds child-bounds (gpt/point) bounds objects))
([parent child parent-bounds child-bounds correct-v bounds objects] ([parent child parent-bounds child-bounds correct-v bounds objects]
(let [row? (ctl/row? parent) (let [row? (ctl/row? parent)
col? (ctl/col? parent) col? (ctl/col? parent)
@ -56,7 +56,8 @@
;; This is the leftmost (when row) or topmost (when col) point ;; This is the leftmost (when row) or topmost (when col) point
;; Will be added always to the bounds and then calculated the other limits ;; Will be added always to the bounds and then calculated the other limits
;; from there ;; from there
base-p (cond-> base-p base-p
(cond-> base-p
(and row? v-center?) (and row? v-center?)
(gpt/add (vv (/ height 2))) (gpt/add (vv (/ height 2)))
@ -76,10 +77,12 @@
base-p (gpt/add base-p correct-v) base-p (gpt/add base-p correct-v)
result result
(cond-> [base-p [base-p
(gpt/add base-p (hv 0.01)) (gpt/add base-p (hv 0.01))
(gpt/add base-p (vv 0.01))] (gpt/add base-p (vv 0.01))]
result
(cond-> result
col? col?
(conj (gpt/add base-p (vv min-height))) (conj (gpt/add base-p (vv min-height)))
@ -112,18 +115,26 @@
(gpt/subtract (hv (+ width min-width))) (gpt/subtract (hv (+ width min-width)))
(and col? (ctl/fill-height? child)) (and col? (ctl/fill-height? child))
(gpt/subtract (vv (+ height min-height))) (gpt/subtract (vv (+ height min-height))))]
)]
[result correct-v]))) [result correct-v])))
(defn layout-content-points (defn layout-content-points
[bounds parent children objects] [bounds parent children objects]
(let [parent-id (:id parent) (let [parent-id (dm/get-prop parent :id)
parent-bounds @(get bounds parent-id) parent-bounds @(get bounds parent-id)
get-child-bounds reverse? (ctl/reverse? parent)
(fn [[result correct-v] child] children (cond->> children (not reverse?) reverse)]
(let [child-id (:id child)
(loop [children (seq children)
result (transient [])
correct-v (gpt/point 0)]
(if (not children)
(persistent! result)
(let [child (first children)
child-id (dm/get-prop child :id)
child-bounds @(get bounds child-id) child-bounds @(get bounds child-id)
[margin-top margin-right margin-bottom margin-left] (ctl/child-margins child) [margin-top margin-right margin-bottom margin-left] (ctl/child-margins child)
@ -137,16 +148,9 @@
(-> (gpo/parent-coords-bounds child-bounds parent-bounds) (-> (gpo/parent-coords-bounds child-bounds parent-bounds)
(gpo/pad-points (- margin-top) (- margin-right) (- margin-bottom) (- margin-left))))] (gpo/pad-points (- margin-top) (- margin-right) (- margin-bottom) (- margin-left))))]
[(cond-> result (some? child-bounds) (conj child-bounds)) (recur (next children)
correct-v])) (cond-> result (some? child-bounds) (conj! child-bounds))
correct-v))))))
reverse? (ctl/reverse? parent)
children (cond->> children (not reverse?) reverse)]
(->> children
(remove ctl/layout-absolute?)
(reduce get-child-bounds [[] (gpt/point 0)])
(first))))
(defn layout-content-bounds (defn layout-content-bounds
[bounds {:keys [layout-padding] :as parent} children objects] [bounds {:keys [layout-padding] :as parent} children objects]

View file

@ -53,11 +53,11 @@
layout-height (gpo/height-points layout-bounds)] layout-height (gpo/height-points layout-bounds)]
(loop [line-data nil (loop [line-data nil
result [] result (transient [])
children (seq children)] children (seq children)]
(if (empty? children) (if (not children)
(cond-> result (some? line-data) (conj line-data)) (persistent! (cond-> result (some? line-data) (conj! line-data)))
(let [[child-bounds child] (first children) (let [[child-bounds child] (first children)
{:keys [line-min-width line-min-height {:keys [line-min-width line-min-height
@ -91,7 +91,8 @@
next-max-width (+ child-margin-width (:child-max-width child-data)) next-max-width (+ child-margin-width (:child-max-width child-data))
next-max-height (+ child-margin-height (:child-max-height child-data)) next-max-height (+ child-margin-height (:child-max-height child-data))
total-gap-col (cond total-gap-col
(cond
space-evenly? space-evenly?
(* layout-gap-col (+ num-children 2)) (* layout-gap-col (+ num-children 2))
@ -101,7 +102,8 @@
:else :else
(* layout-gap-col num-children)) (* layout-gap-col num-children))
total-gap-row (cond total-gap-row
(cond
space-evenly? space-evenly?
(* layout-gap-row (+ num-children 2)) (* layout-gap-row (+ num-children 2))
@ -128,7 +130,7 @@
:num-children (inc num-children) :num-children (inc num-children)
:children-data (conjv children-data child-data)} :children-data (conjv children-data child-data)}
result result
(rest children)) (next children))
(recur {:line-min-width next-min-width (recur {:line-min-width next-min-width
:line-min-height next-min-height :line-min-height next-min-height
@ -136,29 +138,31 @@
:line-max-height next-max-height :line-max-height next-max-height
:num-children 1 :num-children 1
:children-data [child-data]} :children-data [child-data]}
(cond-> result (some? line-data) (conj line-data)) (cond-> result (some? line-data) (conj! line-data))
(rest children)))))))) (next children))))))))
(defn add-space-to-items (defn add-space-to-items
;; Distributes the remainder space between the lines ;; Distributes the remainder space between the lines
[prop prop-min prop-max to-share items] [prop prop-min prop-max to-share items]
(let [num-items (->> items (remove #(mth/close? (get % prop) (get % prop-max))) count) (let [num-items (->> items (remove #(mth/close? (get % prop) (get % prop-max))) count)
per-line-target (/ to-share num-items)] per-line-target (/ to-share num-items)]
(loop [current (first items)
items (rest items) (loop [items (seq items)
remainder to-share remainder to-share
result []] result (transient [])]
(if (nil? current)
[result remainder] (if (not items)
(let [cur-val (or (get current prop) (get current prop-min) 0) [(persistent! result) remainder]
(let [current (first items)
cur-val (or (get current prop) (get current prop-min) 0)
max-val (get current prop-max) max-val (get current prop-max)
cur-inc (if (> (+ cur-val per-line-target) max-val) cur-inc (if (> (+ cur-val per-line-target) max-val)
(- max-val cur-val) (- max-val cur-val)
per-line-target) per-line-target)
current (assoc current prop (+ cur-val cur-inc)) current (assoc current prop (+ cur-val cur-inc))
remainder (- remainder cur-inc) remainder (- remainder cur-inc)]
result (conj result current)] (recur (next items) remainder (conj! result current)))))))
(recur (first items) (rest items) remainder result))))))
(defn distribute-space (defn distribute-space
[prop prop-min prop-max min-value bound-value items] [prop prop-min prop-max min-value bound-value items]
@ -200,36 +204,24 @@
(add-starts [total-width total-height num-lines [result base-p] layout-line] (add-starts [total-width total-height num-lines [result base-p] layout-line]
(let [start-p (flp/get-start-line parent layout-bounds layout-line base-p total-width total-height num-lines) (let [start-p (flp/get-start-line parent layout-bounds layout-line base-p total-width total-height num-lines)
next-p (flp/get-next-line parent layout-bounds layout-line base-p total-width total-height num-lines)] next-p (flp/get-next-line parent layout-bounds layout-line base-p total-width total-height num-lines)]
[(-> result (conj! (assoc layout-line :start-p start-p)))
next-p]))
[(conj result (assoc layout-line :start-p start-p)) (get-layout-width [{:keys [num-children]}]
next-p]))] (let [num-gap (cond space-evenly? (inc num-children)
space-around? num-children
:else (dec num-children))]
(- layout-width (* layout-gap-col num-gap))))
(get-layout-height [{:keys [num-children]}]
(let [num-gap (cond space-evenly? (inc num-children)
space-around? num-children
:else (dec num-children))]
(- layout-height (* layout-gap-row num-gap))))]
(let [[total-min-width total-min-height total-max-width total-max-height] (let [[total-min-width total-min-height total-max-width total-max-height]
(->> layout-lines (reduce add-ranges [0 0 0 0])) (->> layout-lines (reduce add-ranges [0 0 0 0]))
get-layout-width (fn [{:keys [num-children]}]
(let [num-gap (cond
space-evenly?
(inc num-children)
space-around?
num-children
:else
(dec num-children))]
(- layout-width (* layout-gap-col num-gap))))
get-layout-height (fn [{:keys [num-children]}]
(let [num-gap (cond
space-evenly?
(inc num-children)
space-around?
num-children
:else
(dec num-children))]
(- layout-height (* layout-gap-row num-gap))))
num-lines (count layout-lines) num-lines (count layout-lines)
;; When align-items is stretch we need to adjust the main axis size to grow for the full content ;; When align-items is stretch we need to adjust the main axis size to grow for the full content
@ -247,6 +239,7 @@
rest-layout-width (- layout-width (* (dec num-lines) layout-gap-col)) rest-layout-width (- layout-width (* (dec num-lines) layout-gap-col))
;; Distributes the space between the layout lines based on its max/min constraints ;; Distributes the space between the layout lines based on its max/min constraints
layout-lines layout-lines
(cond->> layout-lines (cond->> layout-lines
row? row?
@ -267,14 +260,16 @@
(and row? (<= total-max-height rest-layout-height) (not auto-height?)) (and row? (<= total-max-height rest-layout-height) (not auto-height?))
(map #(assoc % :line-height (+ (:line-max-height %) stretch-height-fix))) (map #(assoc % :line-height (+ (:line-max-height %) stretch-height-fix)))
(and row? (< total-min-height rest-layout-height total-max-height) (not auto-height?))
(distribute-space :line-height :line-min-height :line-max-height total-min-height rest-layout-height)
(and col? (or (>= total-min-width rest-layout-width) auto-width?)) (and col? (or (>= total-min-width rest-layout-width) auto-width?))
(map #(assoc % :line-width (:line-min-width %))) (map #(assoc % :line-width (:line-min-width %)))
(and col? (<= total-max-width rest-layout-width) (not auto-width?)) (and col? (<= total-max-width rest-layout-width) (not auto-width?))
(map #(assoc % :line-width (+ (:line-max-width %) stretch-width-fix))) (map #(assoc % :line-width (+ (:line-max-width %) stretch-width-fix))))
layout-lines
(cond->> layout-lines
(and row? (< total-min-height rest-layout-height total-max-height) (not auto-height?))
(distribute-space :line-height :line-min-height :line-max-height total-min-height rest-layout-height)
(and col? (< total-min-width rest-layout-width total-max-width) (not auto-width?)) (and col? (< total-min-width rest-layout-width total-max-width) (not auto-width?))
(distribute-space :line-width :line-min-width :line-max-width total-min-width rest-layout-width)) (distribute-space :line-width :line-min-width :line-max-width total-min-width rest-layout-width))
@ -286,19 +281,21 @@
(->> layout-lines (->> layout-lines
(reduce (reduce
(fn [[result rest-layout-height] {:keys [line-height] :as line}] (fn [[result rest-layout-height] {:keys [line-height] :as line}]
[(conj result (assoc line :to-bound-height rest-layout-height)) [(conj! result (assoc line :to-bound-height rest-layout-height))
(- rest-layout-height line-height layout-gap-row)]) (- rest-layout-height line-height layout-gap-row)])
[[] layout-height]) [(transient []) layout-height])
(first)) (first)
(persistent!))
col? col?
(->> layout-lines (->> layout-lines
(reduce (reduce
(fn [[result rest-layout-width] {:keys [line-width] :as line}] (fn [[result rest-layout-width] {:keys [line-width] :as line}]
[(conj result (assoc line :to-bound-width rest-layout-width)) [(conj! result (assoc line :to-bound-width rest-layout-width))
(- rest-layout-width line-width layout-gap-col)]) (- rest-layout-width line-width layout-gap-col)])
[[] layout-width]) [(transient []) layout-width])
(first)) (first)
(persistent!))
:else :else
layout-lines) layout-lines)
@ -307,7 +304,10 @@
base-p (flp/get-base-line parent layout-bounds total-width total-height num-lines)] base-p (flp/get-base-line parent layout-bounds total-width total-height num-lines)]
(first (reduce (partial add-starts total-width total-height num-lines) [[] base-p] layout-lines)))))) (->> layout-lines
(reduce (partial add-starts total-width total-height num-lines) [(transient []) base-p])
(first)
(persistent!))))))
(defn add-line-spacing (defn add-line-spacing
"Calculates the baseline for a flex layout" "Calculates the baseline for a flex layout"