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:
parent
c01c46041d
commit
8d9ed4f8af
9 changed files with 162 additions and 80 deletions
|
@ -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]))
|
||||
|
||||
|
|
|
@ -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)))
|
||||
|
||||
|
|
|
@ -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))))
|
||||
|
|
|
@ -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))))
|
||||
|
||||
|
|
|
@ -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)) ]
|
||||
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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}]))]))
|
||||
|
|
Loading…
Add table
Reference in a new issue