0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-18 10:41:29 -05:00

Fill elements in auto-layout

This commit is contained in:
alonso.torres 2022-09-30 15:36:30 +02:00
parent c01c46041d
commit 8d9ed4f8af
9 changed files with 162 additions and 80 deletions

View file

@ -6,6 +6,7 @@
(ns app.common.geom.shapes.layout
(:require
[app.common.data :as d]
[app.common.geom.point :as gpt]
[app.common.geom.shapes.rect :as gre]))
@ -70,18 +71,25 @@
(let [wrap? (= layout-wrap-type :wrap)
reduce-fn
(fn [[{:keys [line-width line-height num-children child-fill? num-child-fill] :as line-data} result] child]
(fn [[{:keys [line-width line-height num-children line-fill? child-fill? num-child-fill] :as line-data} result] child]
(let [child-bounds (-> child :points gre/points->rect)
cur-child-fill?
(or (and (col? shape) (= :fill (:layout-h-behavior child)))
(and (row? shape) (= :fill (:layout-v-behavior child))))
next-width (if cur-child-fill?
cur-line-fill?
(or (and (row? shape) (= :fill (:layout-h-behavior child)))
(and (col? shape) (= :fill (:layout-v-behavior child))))
;; TODO LAYOUT: ADD MINWIDTH/HEIGHT
next-width (if (or (and (col? shape) cur-child-fill?)
(and (row? shape) cur-line-fill?))
0
(-> child-bounds :width))
next-height (if cur-child-fill?
next-height (if (or (and (row? shape) cur-child-fill?)
(and (col? shape) cur-line-fill?))
0
(-> child-bounds :height))]
@ -90,19 +98,21 @@
(and (col? shape) (<= (+ line-width next-width (* layout-gap num-children)) width))
(and (row? shape) (<= (+ line-height next-height (* layout-gap num-children)) height))))
;; Si autofill añadimos el minwidth que por defecto es 0
;; When :fill we add min width (0 by default)
[{: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)
:child-fill? (or cur-child-fill? child-fill?)
:line-fill? (or cur-line-fill? line-fill?)
:num-child-fill (cond-> num-child-fill cur-child-fill? inc)}
result]
[{:line-width next-width
:line-height next-height
:num-children 1
:child-fill? child-fill?
:num-child-fill (if child-fill? 1 0)}
:child-fill? cur-child-fill?
:line-fill? cur-line-fill?
:num-child-fill (if cur-child-fill? 1 0)}
(cond-> result (some? line-data) (conj line-data))])))
[line-data layout-lines] (reduce reduce-fn [nil []] children)]
@ -142,10 +152,16 @@
(let [children-gap (* layout-gap (dec num-children))
line-width (if (and (col? shape) child-fill?) (- width (* layout-gap num-children)) line-width)
line-height (if (and (row? shape) child-fill?) (- height (* layout-gap num-children)) line-height)
start-x
(cond
(or (and (col? shape) child-fill?)
(and (col? shape) (= :space-between layout-type))
;;(and (col? shape) child-fill?)
;;;; TODO LAYOUT: Start has to take into account max-width
;;x
(or (and (col? shape) (= :space-between layout-type))
(and (col? shape) (= :space-around layout-type)))
x
@ -169,8 +185,11 @@
start-y
(cond
(or (and (row? shape) child-fill?)
(and (row? shape) (= :space-between layout-type))
;;(and (row? shape) child-fill?)
;;;; TODO LAYOUT: Start has to take into account max-width
;;y
(or (and (row? shape) (= :space-between layout-type))
(and (row? shape) (= :space-around layout-type)))
y
@ -191,6 +210,7 @@
:else
y)]
[start-x start-y]))
(get-next-line
@ -213,12 +233,27 @@
next-x
next-y]))]
(let [[total-width total-height]
(->> layout-lines (reduce add-lines [0 0]))
(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))))
vertical-fill-space (- height total-height)
horizontal-fill-space (- width total-width)
num-line-fill (count (->> layout-lines (filter :line-fill?)))
layout-lines
(->> layout-lines
(mapv #(cond-> %
(and (col? shape) (:line-fill? %))
(update :line-height + (/ vertical-fill-space num-line-fill))
(and (row? shape) (:line-fill? %))
(update :line-width + (/ horizontal-fill-space num-line-fill)))))
total-height (if (and (col? shape) (> num-line-fill 0)) height total-height)
total-width (if (and (row? shape) (> num-line-fill 0)) width total-width)
[base-x base-y]
(get-base-line total-width total-height)
@ -305,6 +340,7 @@
:else
start-y)
pos-x (cond-> pos-x (some? margin-x) (+ margin-x))
pos-y (cond-> pos-y (some? margin-y) (+ margin-y))
@ -323,47 +359,83 @@
next-x (cond-> next-x (some? margin-x) (+ margin-x))
next-y (cond-> next-y (some? margin-y) (+ margin-y))
layout-data
(assoc layout-data :start-x next-x :start-y next-y)]
[corner-p layout-data]))
(defn calc-fill-width-data
[child-bounds
{:keys [layout-gap] :as parent}
{:keys [layout-h-behavior] :as child}
{:keys [num-children line-width layout-bounds line-fill? child-fill?] :as layout-data}]
(cond
(and (col? parent) (= :fill layout-h-behavior) child-fill?)
(let [fill-space (- (:width layout-bounds) line-width (* layout-gap num-children))
fill-width (/ fill-space (:num-child-fill layout-data))
fill-scale (/ fill-width (:width child-bounds))]
{:bounds {:width fill-width}
:modifiers [{:type :resize
:origin (gpt/point child-bounds)
:vector (gpt/point fill-scale 1)}]})
(and (row? parent) (= :fill layout-h-behavior) line-fill?)
(let [fill-scale (/ line-width (:width child-bounds))]
{:bounds {:width line-width}
:modifiers [{:type :resize
:origin (gpt/point child-bounds)
:vector (gpt/point fill-scale 1)}]})
))
(defn calc-fill-height-data
[child-bounds
{:keys [layout-gap] :as parent}
{:keys [layout-v-behavior] :as child}
{:keys [num-children line-height layout-bounds line-fill? child-fill?] :as layout-data}]
(cond
(and (row? parent) (= :fill layout-v-behavior) child-fill?)
(let [fill-space (- (:height layout-bounds) line-height (* layout-gap num-children))
fill-height (/ fill-space (:num-child-fill layout-data))
fill-scale (/ fill-height (:height child-bounds))]
{:bounds {:height fill-height}
:modifiers [{:type :resize
:origin (gpt/point child-bounds)
:vector (gpt/point 1 fill-scale)}]})
(and (col? parent) (= :fill layout-v-behavior) line-fill?)
(let [fill-scale (/ line-height (:height child-bounds))]
{:bounds {:height line-height}
:modifiers [{:type :resize
:origin (gpt/point child-bounds)
:vector (gpt/point 1 fill-scale)}]})
))
(defn calc-layout-modifiers
"Calculates the modifiers for the layout"
[parent transform child layout-data]
(let [child-bounds (-> child :points gre/points->selrect)
fill-space (- (-> layout-data :layout-bounds :width) (:line-width layout-data))
fill-width (calc-fill-width-data child-bounds parent child layout-data)
fill-height (calc-fill-height-data child-bounds parent child layout-data)
fill-width (- (/ fill-space (:num-child-fill layout-data))
(* 2 (:layout-gap layout-data)))
fill-scale (/ fill-width (:width child-bounds))
child-bounds
(cond-> child-bounds
(and (col? parent) (= :fill (:layout-h-behavior child)))
(assoc :width fill-width))
child-bounds (cond-> child-bounds
fill-width (merge (:bounds fill-width))
fill-height (merge (:bounds fill-height)))
[corner-p layout-data] (next-p parent child-bounds layout-data)
delta-p (-> corner-p
(gpt/subtract (gpt/point child-bounds))
(cond-> (some? transform) (gpt/transform transform)))
modifiers []
delta-p
(-> corner-p
(gpt/subtract (gpt/point child-bounds))
(cond-> (some? transform) (gpt/transform transform)))
modifiers
(cond-> modifiers
(and (col? parent) (= :fill (:layout-h-behavior child)))
(conj {:type :resize
:from :layout
:origin (gpt/point child-bounds)
:vector (gpt/point fill-scale 1)}))
modifiers
(conj modifiers {:type :move
:from :layout
:vector delta-p})]
(-> []
(cond-> fill-width (d/concat-vec (:modifiers fill-width)))
(cond-> fill-height (d/concat-vec (:modifiers fill-height)))
(conj {:type :move :vector delta-p}))]
[modifiers layout-data]))

View file

@ -91,6 +91,7 @@
(defn- calculate-height
"Calculates the height of a parallelogram given by the points"
[[p1 _ _ p4]]
(-> (gpt/to-vec p4 p1)
(gpt/length)))

View file

@ -254,3 +254,8 @@
(gmt/multiply (gmt/rotate-matrix rt-modif))
(gmt/translate (gpt/negate center))))))
))
(defn only-move?
[modifier]
(and (= 1 (-> modifier :v2 count))
(= :move (-> modifier :v2 first :type))))

View file

@ -111,8 +111,7 @@
(dom/query-all shape-defs ".svg-mask-wrapper")))
text?
[shape-node
(dom/query shape-node ".text-container")]
[shape-node]
:else
[shape-node]))))
@ -178,12 +177,10 @@
(defn update-transform!
[base-node shapes transforms modifiers]
(doseq [{:keys [id type] :as shape} shapes]
(doseq [{:keys [id _type] :as shape} shapes]
(when-let [nodes (get-nodes base-node shape)]
(let [transform (get transforms id)
modifiers (get-in modifiers [id :modifiers])
text? (= type :text)
transform-text? (and text? (and (nil? (:resize-vector modifiers)) (nil? (:resize-vector-2 modifiers))))]
modifiers (get-in modifiers [id :modifiers])]
;; TODO LAYOUT: Adapt to new modifiers
(doseq [node nodes]
@ -197,19 +194,10 @@
(dom/class? node "frame-children")
(set-transform-att! node "transform" (gmt/inverse transform))
(dom/class? node "text-container")
(let [modifiers (dissoc modifiers :displacement :rotation)]
(when (not (ctm/empty-modifiers? modifiers))
(let [mtx (-> shape
(assoc :modifiers modifiers)
(gsh/transform-shape)
(gsh/transform-matrix {:no-flip true}))]
(override-transform-att! node "transform" mtx))))
(dom/class? node "frame-title")
(let [shape (-> shape (assoc :modifiers modifiers) gsh/transform-shape)
zoom (get-in @st/state [:workspace-local :zoom] 1)
mtx (vwu/title-transform shape zoom)]
(let [shape (gsh/transform-shape shape modifiers)
zoom (get-in @st/state [:workspace-local :zoom] 1)
mtx (vwu/title-transform shape zoom)]
(override-transform-att! node "transform" mtx))
(or (= (dom/get-tag-name node) "mask")
@ -223,7 +211,7 @@
(= (dom/get-tag-name node) "pattern")
(set-transform-att! node "patternTransform" transform)
(and (some? transform) (some? node) (or (not text?) transform-text?))
(and (some? transform) (some? node))
(set-transform-att! node "transform" transform)))))))
(defn remove-transform!
@ -251,6 +239,20 @@
(dom/remove-attribute! node "data-old-transform")
(dom/remove-attribute! node "transform")))))))))
(defn adapt-text-modifiers
[modifiers shape]
(let [shape' (gsh/transform-shape shape modifiers)
scalev
(gpt/point (/ (:width shape) (:width shape'))
(/ (:height shape) (:height shape')))]
;; Reverse the change in size so we can recalculate the layout
(-> modifiers
(update :v2 conj {:type :resize
:vector scalev
:transform (:transform shape')
:transform-inverse (:transform-inverse shape')
:origin (-> shape' :points first)}))))
(defn use-dynamic-modifiers
[objects node modifiers]
@ -262,14 +264,8 @@
(d/mapm (fn [id {modifiers :modifiers}]
(let [shape (get objects id)
center (gsh/center-shape shape)
;; TODO LAYOUT: Adapt to new modifiers
modifiers (cond-> modifiers
;; For texts we only use the displacement because
;; resize needs to recalculate the text layout
(= :text (:type shape))
(select-keys [:displacement :rotation]))
]
text? (= :text (:type shape))
modifiers (cond-> modifiers text? (adapt-text-modifiers shape))]
(ctm/modifiers->transform center modifiers)))
modifiers))))

View file

@ -8,6 +8,7 @@
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh]
[app.common.geom.shapes.text :as gsht]
[app.common.math :as mth]
@ -34,21 +35,29 @@
(with-meta (meta (:position-data shape))))
(dissoc :position-data :transform :transform-inverse)))
;; TODO LAYOUT: Adapt to new modifiers
(defn strip-modifier
#_(defn strip-modifier
[modifier]
(if (or (some? (dm/get-in modifier [:modifiers :resize-vector]))
(some? (dm/get-in modifier [:modifiers :resize-vector-2])))
modifier
(d/update-when modifier :modifiers dissoc :displacement :rotation)))
(defn fix-position [shape modifier]
(let [shape' (-> shape
(assoc :grow-type :fixed)
(gsh/transform-shape modifier))
deltav (gpt/to-vec (gpt/point (:selrect shape'))
(gpt/point (:selrect shape)))]
(gsh/transform-shape shape' (ctm/move deltav))))
(defn process-shape [modifiers {:keys [id] :as shape}]
(let [modifier (-> (get modifiers id) strip-modifier)
shape (cond-> shape
(not (ctm/empty-modifiers? (:modifiers modifier)))
(-> (assoc :grow-type :fixed)
(gsh/transform-shape modifier)))]
(let [modifier (dm/get-in modifiers [id :modifiers])]
(-> shape
(cond-> (and (some? modifier)
(not (ctm/only-move? modifier)))
(fix-position modifier))
(cond-> (nil? (:position-data shape))
(assoc :migrate true))
strip-position-data)))
@ -138,8 +147,8 @@
(fn [id]
(let [new-shape (get text-shapes id)
old-shape (get prev-text-shapes id)
old-modifiers (-> (get prev-modifiers id) strip-modifier)
new-modifiers (-> (get modifiers id) strip-modifier)
old-modifiers (get prev-modifiers id)
new-modifiers (get modifiers id)
remote? (some? (-> new-shape meta :session-id)) ]

View file

@ -30,7 +30,7 @@
frames (map #(deref (refs/object-by-id (:frame-id %))) old-shapes)
shapes (as-> old-shapes $
(map gsh/transform-shape $)
#_(map gsh/transform-shape $)
(map gsh/translate-to-frame $ frames))
values (let [{:keys [x y]} (-> shapes first :points gsh/points->selrect)]

View file

@ -83,7 +83,7 @@
;; the shape with the mouse, generate a copy of the shapes applying
;; the transient transformations.
shapes (as-> old-shapes $
(map gsh/transform-shape $)
#_(map gsh/transform-shape $)
(map gsh/translate-to-frame $ frames))
;; For rotated or stretched shapes, the origin point we show in the menu

View file

@ -202,7 +202,7 @@
{:key (dm/str "texts-" page-id)
:page-id page-id
:objects objects
;;:modifiers modifiers
:modifiers modifiers
:edition edition}]]]]
(when show-comments?

View file

@ -7,7 +7,6 @@
(ns app.main.ui.workspace.viewport.frame-grid
(:require
[app.common.data :as d]
[app.common.geom.shapes :as gsh]
[app.common.math :as mth]
[app.common.types.shape-tree :as ctst]
[app.common.uuid :as uuid]
@ -138,4 +137,4 @@
(or (empty? focus) (contains? focus (:id frame))))
[:& grid-display-frame {:key (str "grid-" (:id frame))
:zoom zoom
:frame (gsh/transform-shape frame)}]))]))
:frame frame}]))]))