mirror of
https://github.com/penpot/penpot.git
synced 2025-01-26 08:29:42 -05:00
🎉 Add support for nested layouts
This commit is contained in:
parent
1c8aef6fa8
commit
7176bb6f1a
7 changed files with 308 additions and 205 deletions
|
@ -15,6 +15,7 @@
|
||||||
[app.common.geom.shapes.corners :as gsc]
|
[app.common.geom.shapes.corners :as gsc]
|
||||||
[app.common.geom.shapes.intersect :as gin]
|
[app.common.geom.shapes.intersect :as gin]
|
||||||
[app.common.geom.shapes.layout :as gcl]
|
[app.common.geom.shapes.layout :as gcl]
|
||||||
|
[app.common.geom.shapes.modifiers :as gsm]
|
||||||
[app.common.geom.shapes.path :as gsp]
|
[app.common.geom.shapes.path :as gsp]
|
||||||
[app.common.geom.shapes.rect :as gpr]
|
[app.common.geom.shapes.rect :as gpr]
|
||||||
[app.common.geom.shapes.transforms :as gtr]
|
[app.common.geom.shapes.transforms :as gtr]
|
||||||
|
@ -201,3 +202,6 @@
|
||||||
;; Corners
|
;; Corners
|
||||||
(dm/export gsc/shape-corners-1)
|
(dm/export gsc/shape-corners-1)
|
||||||
(dm/export gsc/shape-corners-4)
|
(dm/export gsc/shape-corners-4)
|
||||||
|
|
||||||
|
;; Modifiers
|
||||||
|
(dm/export gsm/set-objects-modifiers)
|
||||||
|
|
|
@ -197,6 +197,9 @@
|
||||||
;; Build final child modifiers. Apply transform again to the result, to get the
|
;; Build final child modifiers. Apply transform again to the result, to get the
|
||||||
;; real modifiers that need to be applied to the child, including rotation as needed.
|
;; real modifiers that need to be applied to the child, including rotation as needed.
|
||||||
(cond-> {}
|
(cond-> {}
|
||||||
|
(some? (:displacement-after modifiers))
|
||||||
|
(assoc :displacement-after (:displacement-after modifiers))
|
||||||
|
|
||||||
(or (contains? modifiers-h :displacement)
|
(or (contains? modifiers-h :displacement)
|
||||||
(contains? modifiers-v :displacement))
|
(contains? modifiers-v :displacement))
|
||||||
(assoc :displacement (cond-> (gpt/point (get-in modifiers-h [:displacement :x] 0)
|
(assoc :displacement (cond-> (gpt/point (get-in modifiers-h [:displacement :x] 0)
|
||||||
|
|
|
@ -68,11 +68,11 @@
|
||||||
|
|
||||||
(defn calc-layout-data
|
(defn calc-layout-data
|
||||||
"Digest the layout data to pass it to the constrains"
|
"Digest the layout data to pass it to the constrains"
|
||||||
[{:keys [layout-gap] :as shape} children modif-tree transformed-rect]
|
[{:keys [layout-type layout-gap] :as shape} children modif-tree transformed-rect]
|
||||||
|
|
||||||
(let [transformed-rect (-> transformed-rect (add-padding shape))
|
(let [{:keys [x y width height]} (-> transformed-rect (add-padding shape))
|
||||||
num-children (count children)
|
num-children (count children)
|
||||||
children-gap (* layout-gap (dec num-children) )
|
|
||||||
[children-width children-height]
|
[children-width children-height]
|
||||||
(->> children
|
(->> children
|
||||||
(map #(-> (merge % (get modif-tree (:id %))) gtr/transform-shape))
|
(map #(-> (merge % (get modif-tree (:id %))) gtr/transform-shape))
|
||||||
|
@ -80,13 +80,39 @@
|
||||||
[(+ acc-width (-> shape :points gre/points->rect :width))
|
[(+ acc-width (-> shape :points gre/points->rect :width))
|
||||||
(+ acc-height (-> shape :points gre/points->rect :height))]) [0 0]))
|
(+ acc-height (-> shape :points gre/points->rect :height))]) [0 0]))
|
||||||
|
|
||||||
{:keys [x y width height]} transformed-rect
|
layout-gap
|
||||||
|
(cond
|
||||||
|
(= :packed layout-type)
|
||||||
|
layout-gap
|
||||||
|
|
||||||
|
(= :space-around layout-type)
|
||||||
|
0
|
||||||
|
|
||||||
|
(and (col? shape) (= :space-between layout-type))
|
||||||
|
(/ (- width children-width) (dec num-children))
|
||||||
|
|
||||||
|
(and (row? shape) (= :space-between layout-type))
|
||||||
|
(/ (- height children-height) (dec num-children)))
|
||||||
|
|
||||||
|
margin-x (if (and (col? shape) (= :space-around layout-type))
|
||||||
|
(/ (- width children-width) (dec num-children) 2)
|
||||||
|
0)
|
||||||
|
|
||||||
|
margin-y (if (and (row? shape) (= :space-around layout-type))
|
||||||
|
(/ (- height children-height) (dec num-children) 2)
|
||||||
|
0)
|
||||||
|
|
||||||
|
children-gap (* layout-gap (dec num-children))
|
||||||
|
|
||||||
start-x
|
start-x
|
||||||
(cond
|
(cond
|
||||||
|
(or (and (col? shape) (= :space-between layout-type))
|
||||||
|
(and (col? shape) (= :space-around layout-type)))
|
||||||
|
x
|
||||||
|
|
||||||
(and (row? shape) (h-center? shape))
|
(and (row? shape) (h-center? shape))
|
||||||
(+ x (/ width 2))
|
(+ x (/ width 2))
|
||||||
|
|
||||||
(and (row? shape) (h-end? shape))
|
(and (row? shape) (h-end? shape))
|
||||||
(+ x width)
|
(+ x width)
|
||||||
|
|
||||||
|
@ -97,10 +123,14 @@
|
||||||
(- (+ x width) (+ children-width children-gap))
|
(- (+ x width) (+ children-width children-gap))
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(:x transformed-rect))
|
x)
|
||||||
|
|
||||||
start-y
|
start-y
|
||||||
(cond
|
(cond
|
||||||
|
(or (and (row? shape) (= :space-between layout-type))
|
||||||
|
(and (row? shape) (= :space-around layout-type)))
|
||||||
|
y
|
||||||
|
|
||||||
(and (col? shape) (v-center? shape))
|
(and (col? shape) (v-center? shape))
|
||||||
(+ y (/ height 2))
|
(+ y (/ height 2))
|
||||||
|
|
||||||
|
@ -114,15 +144,18 @@
|
||||||
(- (+ y height) (+ children-height children-gap))
|
(- (+ y height) (+ children-height children-gap))
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(:y transformed-rect) )]
|
y)]
|
||||||
|
|
||||||
{:start-x start-x
|
{:start-x start-x
|
||||||
:start-y start-y
|
: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)))}))
|
:reverse? (or (= :left (:layout-dir shape)) (= :bottom (:layout-dir shape)))}))
|
||||||
|
|
||||||
(defn next-p
|
(defn next-p
|
||||||
"Calculates the position for the current shape given the layout-data context"
|
"Calculates the position for the current shape given the layout-data context"
|
||||||
[{:keys [layout-gap] :as shape} {:keys [width height]} {:keys [start-x start-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
|
(let [pos-x
|
||||||
(cond
|
(cond
|
||||||
|
@ -146,8 +179,11 @@
|
||||||
:else
|
:else
|
||||||
start-y)
|
start-y)
|
||||||
|
|
||||||
|
pos-x (cond-> pos-x (some? margin-x) (+ margin-x))
|
||||||
|
pos-y (cond-> pos-y (some? margin-y) (+ margin-y))
|
||||||
|
|
||||||
corner-p (gpt/point pos-x pos-y)
|
corner-p (gpt/point pos-x pos-y)
|
||||||
|
|
||||||
next-x
|
next-x
|
||||||
(if (col? shape)
|
(if (col? shape)
|
||||||
(+ start-x width layout-gap)
|
(+ start-x width layout-gap)
|
||||||
|
@ -158,6 +194,9 @@
|
||||||
(+ start-y height layout-gap)
|
(+ start-y height layout-gap)
|
||||||
start-y)
|
start-y)
|
||||||
|
|
||||||
|
next-x (cond-> next-x (some? margin-x) (+ margin-x))
|
||||||
|
next-y (cond-> next-y (some? margin-y) (+ margin-y))
|
||||||
|
|
||||||
layout-data
|
layout-data
|
||||||
(assoc layout-data :start-x next-x :start-y next-y)]
|
(assoc layout-data :start-x next-x :start-y next-y)]
|
||||||
[corner-p layout-data])
|
[corner-p layout-data])
|
||||||
|
@ -165,15 +204,15 @@
|
||||||
|
|
||||||
(defn calc-layout-modifiers
|
(defn calc-layout-modifiers
|
||||||
"Calculates the modifiers for the layout"
|
"Calculates the modifiers for the layout"
|
||||||
[parent child current-modifier _modifiers _transformed-rect layout-data]
|
[parent child modifiers layout-data]
|
||||||
|
|
||||||
(let [current-modifier (-> current-modifier (dissoc :displacement-after))
|
(let [modifiers (-> modifiers (dissoc :displacement-after))
|
||||||
child (-> child (assoc :modifiers current-modifier) gtr/transform-shape)
|
child (-> child (assoc :modifiers modifiers) gtr/transform-shape)
|
||||||
bounds (-> child :points gre/points->selrect)
|
bounds (-> child :points gre/points->selrect)
|
||||||
|
|
||||||
[corner-p layout-data] (next-p parent bounds layout-data)
|
[corner-p layout-data] (next-p parent bounds layout-data)
|
||||||
|
|
||||||
delta-p (-> corner-p (gpt/subtract (gpt/point bounds)))
|
delta-p (-> corner-p (gpt/subtract (gpt/point bounds)))
|
||||||
modifiers (-> current-modifier (assoc :displacement-after (gmt/translate-matrix delta-p)))]
|
modifiers (-> modifiers (assoc :displacement-after (gmt/translate-matrix delta-p)))]
|
||||||
|
|
||||||
[modifiers layout-data]))
|
[modifiers layout-data]))
|
||||||
|
|
213
common/src/app/common/geom/shapes/modifiers.cljc
Normal file
213
common/src/app/common/geom/shapes/modifiers.cljc
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) UXBOX Labs SL
|
||||||
|
|
||||||
|
(ns app.common.geom.shapes.modifiers
|
||||||
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
|
[app.common.geom.matrix :as gmt]
|
||||||
|
[app.common.geom.point :as gpt]
|
||||||
|
[app.common.geom.shapes.common :as gco]
|
||||||
|
[app.common.geom.shapes.constraints :as gct]
|
||||||
|
[app.common.geom.shapes.layout :as gcl]
|
||||||
|
[app.common.geom.shapes.rect :as gpr]
|
||||||
|
[app.common.geom.shapes.transforms :as gtr]
|
||||||
|
[app.common.math :as mth]
|
||||||
|
[app.common.uuid :as uuid]))
|
||||||
|
|
||||||
|
(defn set-pixel-precision
|
||||||
|
"Adjust modifiers so they adjust to the pixel grid"
|
||||||
|
[modifiers shape]
|
||||||
|
|
||||||
|
(if (some? (:resize-transform modifiers))
|
||||||
|
;; If we're working with a rotation we don't handle pixel precision because
|
||||||
|
;; the transformation won't have the precision anyway
|
||||||
|
modifiers
|
||||||
|
|
||||||
|
(let [center (gco/center-shape shape)
|
||||||
|
base-bounds (-> (:points shape) (gpr/points->rect))
|
||||||
|
|
||||||
|
raw-bounds
|
||||||
|
(-> (gtr/transform-bounds (:points shape) center modifiers)
|
||||||
|
(gpr/points->rect))
|
||||||
|
|
||||||
|
flip-x? (neg? (get-in modifiers [:resize-vector :x]))
|
||||||
|
flip-y? (or (neg? (get-in modifiers [:resize-vector :y]))
|
||||||
|
(neg? (get-in modifiers [:resize-vector-2 :y])))
|
||||||
|
|
||||||
|
path? (= :path (:type shape))
|
||||||
|
vertical-line? (and path? (<= (:width raw-bounds) 0.01))
|
||||||
|
horizontal-line? (and path? (<= (:height raw-bounds) 0.01))
|
||||||
|
|
||||||
|
target-width (if vertical-line?
|
||||||
|
(:width raw-bounds)
|
||||||
|
(max 1 (mth/round (:width raw-bounds))))
|
||||||
|
|
||||||
|
target-height (if horizontal-line?
|
||||||
|
(:height raw-bounds)
|
||||||
|
(max 1 (mth/round (:height raw-bounds))))
|
||||||
|
|
||||||
|
target-p (cond-> (gpt/round (gpt/point raw-bounds))
|
||||||
|
flip-x?
|
||||||
|
(update :x + target-width)
|
||||||
|
|
||||||
|
flip-y?
|
||||||
|
(update :y + target-height))
|
||||||
|
|
||||||
|
ratio-width (/ target-width (:width raw-bounds))
|
||||||
|
ratio-height (/ target-height (:height raw-bounds))
|
||||||
|
|
||||||
|
modifiers
|
||||||
|
(-> modifiers
|
||||||
|
(d/without-nils)
|
||||||
|
(d/update-in-when
|
||||||
|
[:resize-vector :x] #(* % ratio-width))
|
||||||
|
|
||||||
|
;; If the resize-vector-2 modifier arrives means the resize-vector
|
||||||
|
;; will only resize on the x axis
|
||||||
|
(cond-> (nil? (:resize-vector-2 modifiers))
|
||||||
|
(d/update-in-when
|
||||||
|
[:resize-vector :y] #(* % ratio-height)))
|
||||||
|
|
||||||
|
(d/update-in-when
|
||||||
|
[:resize-vector-2 :y] #(* % ratio-height)))
|
||||||
|
|
||||||
|
origin (get modifiers :resize-origin)
|
||||||
|
origin-2 (get modifiers :resize-origin-2)
|
||||||
|
|
||||||
|
resize-v (get modifiers :resize-vector)
|
||||||
|
resize-v-2 (get modifiers :resize-vector-2)
|
||||||
|
displacement (get modifiers :displacement)
|
||||||
|
|
||||||
|
target-p-inv
|
||||||
|
(-> target-p
|
||||||
|
(gpt/transform
|
||||||
|
(cond-> (gmt/matrix)
|
||||||
|
(some? displacement)
|
||||||
|
(gmt/multiply (gmt/inverse displacement))
|
||||||
|
|
||||||
|
(and (some? resize-v) (some? origin))
|
||||||
|
(gmt/scale (gpt/inverse resize-v) origin)
|
||||||
|
|
||||||
|
(and (some? resize-v-2) (some? origin-2))
|
||||||
|
(gmt/scale (gpt/inverse resize-v-2) origin-2))))
|
||||||
|
|
||||||
|
delta-v (gpt/subtract target-p-inv (gpt/point base-bounds))
|
||||||
|
|
||||||
|
modifiers
|
||||||
|
(-> modifiers
|
||||||
|
(d/update-when :displacement #(gmt/multiply (gmt/translate-matrix delta-v) %))
|
||||||
|
(cond-> (nil? (:displacement modifiers))
|
||||||
|
(assoc :displacement (gmt/translate-matrix delta-v))))]
|
||||||
|
modifiers)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn set-children-modifiers
|
||||||
|
[modif-tree shape objects ignore-constraints snap-pixel?]
|
||||||
|
(letfn [(set-child [transformed-rect snap-pixel? modif-tree child]
|
||||||
|
(let [modifiers (get-in modif-tree [(:id shape) :modifiers])
|
||||||
|
child-modifiers (gct/calc-child-modifiers shape child modifiers ignore-constraints transformed-rect)
|
||||||
|
child-modifiers (cond-> child-modifiers snap-pixel? (set-pixel-precision child))
|
||||||
|
]
|
||||||
|
(cond-> modif-tree
|
||||||
|
(not (gtr/empty-modifiers? child-modifiers))
|
||||||
|
(assoc (:id child) {:modifiers child-modifiers}))))]
|
||||||
|
(let [children (map (d/getf objects) (:shapes shape))
|
||||||
|
modifiers (get-in modif-tree [(:id shape) :modifiers])
|
||||||
|
transformed-rect (gtr/transform-selrect (:selrect shape) modifiers)
|
||||||
|
resize-modif? (or (:resize-vector modifiers) (:resize-vector-2 modifiers))]
|
||||||
|
(reduce (partial set-child transformed-rect (and snap-pixel? resize-modif?)) modif-tree children))))
|
||||||
|
|
||||||
|
(defn set-layout-modifiers
|
||||||
|
[modif-tree objects id]
|
||||||
|
|
||||||
|
(letfn [(set-layout-modifiers [parent [layout-data modif-tree] child]
|
||||||
|
(let [modifiers (get-in modif-tree [(:id child) :modifiers])
|
||||||
|
|
||||||
|
[modifiers layout-data]
|
||||||
|
(gcl/calc-layout-modifiers parent child modifiers layout-data)
|
||||||
|
|
||||||
|
modif-tree
|
||||||
|
(cond-> modif-tree
|
||||||
|
(not (gtr/empty-modifiers? modifiers))
|
||||||
|
(assoc-in [(:id child) :modifiers] modifiers))]
|
||||||
|
|
||||||
|
[layout-data modif-tree]))]
|
||||||
|
|
||||||
|
(let [shape (get objects id)
|
||||||
|
children (map (d/getf objects) (:shapes shape))
|
||||||
|
modifiers (get-in modif-tree [id :modifiers])
|
||||||
|
|
||||||
|
;;_ (.log js/console "layout" (:name shape) (clj->js 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)
|
||||||
|
|
||||||
|
[_ modif-tree]
|
||||||
|
(reduce (partial set-layout-modifiers shape) [layout-data modif-tree] children)]
|
||||||
|
|
||||||
|
;;(.log js/console "modif-tree" modif-tree)
|
||||||
|
modif-tree)))
|
||||||
|
|
||||||
|
(defn get-first-layout
|
||||||
|
[id objects]
|
||||||
|
|
||||||
|
(loop [current id
|
||||||
|
result id]
|
||||||
|
(let [shape (get objects current)
|
||||||
|
parent (get objects (:parent-id shape))]
|
||||||
|
(cond
|
||||||
|
(or (not shape) (= uuid/zero current))
|
||||||
|
result
|
||||||
|
|
||||||
|
;; Frame found, but not layout we return the last layout found (or the id)
|
||||||
|
(and (= :frame (:type parent))
|
||||||
|
(not (:layout parent)))
|
||||||
|
result
|
||||||
|
|
||||||
|
;; Layout found. We continue upward but we mark this layout
|
||||||
|
(and (= :frame (:type parent))
|
||||||
|
(:layout parent))
|
||||||
|
(recur (:id parent) (:id parent))
|
||||||
|
|
||||||
|
;; If group or boolean or other type of group we continue with the last result
|
||||||
|
:else
|
||||||
|
(recur (:id parent) result)
|
||||||
|
))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn resolve-layout-ids
|
||||||
|
"Given a list of ids, resolve the parent layouts that will need to update. This will go upwards
|
||||||
|
in the tree while a layout is found"
|
||||||
|
[ids objects]
|
||||||
|
|
||||||
|
(into (d/ordered-set)
|
||||||
|
(map #(get-first-layout % objects))
|
||||||
|
ids))
|
||||||
|
|
||||||
|
(defn set-objects-modifiers
|
||||||
|
[ids objects get-modifier ignore-constraints snap-pixel?]
|
||||||
|
|
||||||
|
(let [modif-tree (reduce (fn [modif-tree id]
|
||||||
|
(assoc modif-tree id {:modifiers (get-modifier (get objects id))})) {} ids)
|
||||||
|
|
||||||
|
ids (resolve-layout-ids ids objects)]
|
||||||
|
|
||||||
|
(loop [current (first ids)
|
||||||
|
pending (rest ids)
|
||||||
|
modif-tree modif-tree]
|
||||||
|
(if (some? current)
|
||||||
|
(let [shape (get objects current)
|
||||||
|
pending (concat pending (:shapes shape))
|
||||||
|
|
||||||
|
modif-tree
|
||||||
|
(-> modif-tree
|
||||||
|
(set-children-modifiers shape objects ignore-constraints snap-pixel?)
|
||||||
|
(cond-> (:layout shape)
|
||||||
|
(set-layout-modifiers objects current)))]
|
||||||
|
|
||||||
|
(recur (first pending) (rest pending) modif-tree #_touched-layouts))
|
||||||
|
|
||||||
|
modif-tree))))
|
|
@ -614,7 +614,7 @@
|
||||||
(dissoc :modifiers))))))
|
(dissoc :modifiers))))))
|
||||||
|
|
||||||
(defn transform-bounds
|
(defn transform-bounds
|
||||||
[points center {:keys [displacement resize-transform-inverse resize-vector resize-origin resize-vector-2 resize-origin-2]}]
|
[points center {:keys [displacement displacement-after resize-transform-inverse resize-vector resize-origin resize-vector-2 resize-origin-2]}]
|
||||||
;; FIXME: Improve Performance
|
;; FIXME: Improve Performance
|
||||||
(let [resize-transform-inverse (or resize-transform-inverse (gmt/matrix))
|
(let [resize-transform-inverse (or resize-transform-inverse (gmt/matrix))
|
||||||
|
|
||||||
|
@ -628,9 +628,10 @@
|
||||||
|
|
||||||
resize-origin-2
|
resize-origin-2
|
||||||
(when (some? resize-origin-2)
|
(when (some? resize-origin-2)
|
||||||
(transform-point-center resize-origin-2 center resize-transform-inverse))]
|
(transform-point-center resize-origin-2 center resize-transform-inverse))
|
||||||
|
]
|
||||||
|
|
||||||
(if (and (nil? displacement) (nil? resize-origin) (nil? resize-origin-2))
|
(if (and (nil? displacement) (nil? resize-origin) (nil? resize-origin-2) (nil? displacement-after))
|
||||||
points
|
points
|
||||||
|
|
||||||
(cond-> points
|
(cond-> points
|
||||||
|
@ -641,7 +642,10 @@
|
||||||
(gco/transform-points resize-origin (gmt/scale-matrix resize-vector))
|
(gco/transform-points resize-origin (gmt/scale-matrix resize-vector))
|
||||||
|
|
||||||
(some? resize-origin-2)
|
(some? resize-origin-2)
|
||||||
(gco/transform-points resize-origin-2 (gmt/scale-matrix resize-vector-2))))))
|
(gco/transform-points resize-origin-2 (gmt/scale-matrix resize-vector-2))
|
||||||
|
|
||||||
|
(some? displacement-after)
|
||||||
|
(gco/transform-points displacement-after)))))
|
||||||
|
|
||||||
(defn transform-selrect
|
(defn transform-selrect
|
||||||
[selrect modifiers]
|
[selrect modifiers]
|
||||||
|
|
|
@ -218,7 +218,7 @@
|
||||||
(->> (get-root-shapes objects)
|
(->> (get-root-shapes objects)
|
||||||
(mapv :id)))
|
(mapv :id)))
|
||||||
|
|
||||||
(defn- get-base
|
(defn get-base
|
||||||
[objects id-a id-b]
|
[objects id-a id-b]
|
||||||
|
|
||||||
(let [parents-a (reverse (get-parents-seq objects id-a))
|
(let [parents-a (reverse (get-parents-seq objects id-a))
|
||||||
|
|
|
@ -110,7 +110,7 @@
|
||||||
;; geometric attributes of the shapes.
|
;; geometric attributes of the shapes.
|
||||||
|
|
||||||
(declare clear-local-transform)
|
(declare clear-local-transform)
|
||||||
(declare set-objects-modifiers)
|
|
||||||
(declare get-ignore-tree)
|
(declare get-ignore-tree)
|
||||||
|
|
||||||
(defn set-modifiers
|
(defn set-modifiers
|
||||||
|
@ -128,20 +128,17 @@
|
||||||
(ptk/reify ::set-modifiers
|
(ptk/reify ::set-modifiers
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(let [modifiers (or modifiers (get-in state [:workspace-local :modifiers] {}))
|
|
||||||
page-id (:current-page-id state)
|
(let [objects (wsh/lookup-page-objects state)
|
||||||
objects (wsh/lookup-page-objects state page-id)
|
|
||||||
ids (into #{} (remove #(get-in objects [% :blocked] false)) ids)
|
ids (into #{} (remove #(get-in objects [% :blocked] false)) ids)
|
||||||
layout (get state :workspace-layout)
|
|
||||||
snap-pixel? (and (not ignore-snap-pixel) (contains? layout :snap-pixel-grid))
|
|
||||||
|
|
||||||
setup-modifiers
|
snap-pixel? (and (not ignore-snap-pixel)
|
||||||
(fn [state id]
|
(contains? (:workspace-layout state) :snap-pixel-grid))
|
||||||
(let [shape (get objects id)]
|
|
||||||
(update state :workspace-modifiers
|
|
||||||
#(set-objects-modifiers % objects shape modifiers ignore-constraints snap-pixel?))))]
|
|
||||||
|
|
||||||
(reduce setup-modifiers state ids))))))
|
modif-tree
|
||||||
|
(gsh/set-objects-modifiers ids objects (constantly modifiers) ignore-constraints snap-pixel?)]
|
||||||
|
|
||||||
|
(assoc state :workspace-modifiers modif-tree))))))
|
||||||
|
|
||||||
;; Rotation use different algorithm to calculate children modifiers (and do not use child constraints).
|
;; Rotation use different algorithm to calculate children modifiers (and do not use child constraints).
|
||||||
(defn- set-rotation-modifiers
|
(defn- set-rotation-modifiers
|
||||||
|
@ -280,162 +277,9 @@
|
||||||
|
|
||||||
[root transformed-root ignore-geometry?]))
|
[root transformed-root ignore-geometry?]))
|
||||||
|
|
||||||
(defn set-pixel-precision
|
|
||||||
"Adjust modifiers so they adjust to the pixel grid"
|
|
||||||
[modifiers shape]
|
|
||||||
|
|
||||||
(if (some? (:resize-transform modifiers))
|
|
||||||
;; If we're working with a rotation we don't handle pixel precision because
|
|
||||||
;; the transformation won't have the precision anyway
|
|
||||||
modifiers
|
|
||||||
|
|
||||||
(let [center (gsh/center-shape shape)
|
|
||||||
base-bounds (-> (:points shape) (gsh/points->rect))
|
|
||||||
|
|
||||||
raw-bounds
|
|
||||||
(-> (gsh/transform-bounds (:points shape) center modifiers)
|
|
||||||
(gsh/points->rect))
|
|
||||||
|
|
||||||
flip-x? (neg? (get-in modifiers [:resize-vector :x]))
|
|
||||||
flip-y? (or (neg? (get-in modifiers [:resize-vector :y]))
|
|
||||||
(neg? (get-in modifiers [:resize-vector-2 :y])))
|
|
||||||
|
|
||||||
path? (= :path (:type shape))
|
|
||||||
vertical-line? (and path? (<= (:width raw-bounds) 0.01))
|
|
||||||
horizontal-line? (and path? (<= (:height raw-bounds) 0.01))
|
|
||||||
|
|
||||||
target-width (if vertical-line?
|
|
||||||
(:width raw-bounds)
|
|
||||||
(max 1 (mth/round (:width raw-bounds))))
|
|
||||||
|
|
||||||
target-height (if horizontal-line?
|
|
||||||
(:height raw-bounds)
|
|
||||||
(max 1 (mth/round (:height raw-bounds))))
|
|
||||||
|
|
||||||
target-p (cond-> (gpt/round (gpt/point raw-bounds))
|
|
||||||
flip-x?
|
|
||||||
(update :x + target-width)
|
|
||||||
|
|
||||||
flip-y?
|
|
||||||
(update :y + target-height))
|
|
||||||
|
|
||||||
ratio-width (/ target-width (:width raw-bounds))
|
|
||||||
ratio-height (/ target-height (:height raw-bounds))
|
|
||||||
|
|
||||||
modifiers
|
|
||||||
(-> modifiers
|
|
||||||
(d/without-nils)
|
|
||||||
(d/update-in-when
|
|
||||||
[:resize-vector :x] #(* % ratio-width))
|
|
||||||
|
|
||||||
;; If the resize-vector-2 modifier arrives means the resize-vector
|
|
||||||
;; will only resize on the x axis
|
|
||||||
(cond-> (nil? (:resize-vector-2 modifiers))
|
|
||||||
(d/update-in-when
|
|
||||||
[:resize-vector :y] #(* % ratio-height)))
|
|
||||||
|
|
||||||
(d/update-in-when
|
|
||||||
[:resize-vector-2 :y] #(* % ratio-height)))
|
|
||||||
|
|
||||||
origin (get modifiers :resize-origin)
|
|
||||||
origin-2 (get modifiers :resize-origin-2)
|
|
||||||
|
|
||||||
resize-v (get modifiers :resize-vector)
|
|
||||||
resize-v-2 (get modifiers :resize-vector-2)
|
|
||||||
displacement (get modifiers :displacement)
|
|
||||||
|
|
||||||
target-p-inv
|
|
||||||
(-> target-p
|
|
||||||
(gpt/transform
|
|
||||||
(cond-> (gmt/matrix)
|
|
||||||
(some? displacement)
|
|
||||||
(gmt/multiply (gmt/inverse displacement))
|
|
||||||
|
|
||||||
(and (some? resize-v) (some? origin))
|
|
||||||
(gmt/scale (gpt/inverse resize-v) origin)
|
|
||||||
|
|
||||||
(and (some? resize-v-2) (some? origin-2))
|
|
||||||
(gmt/scale (gpt/inverse resize-v-2) origin-2))))
|
|
||||||
|
|
||||||
delta-v (gpt/subtract target-p-inv (gpt/point base-bounds))
|
|
||||||
|
|
||||||
modifiers
|
|
||||||
(-> modifiers
|
|
||||||
(d/update-when :displacement #(gmt/multiply (gmt/translate-matrix delta-v) %))
|
|
||||||
(cond-> (nil? (:displacement modifiers))
|
|
||||||
(assoc :displacement (gmt/translate-matrix delta-v))))]
|
|
||||||
modifiers)))
|
|
||||||
|
|
||||||
(defn- set-objects-modifiers
|
|
||||||
[modif-tree objects shape modifiers ignore-constraints snap-pixel?]
|
|
||||||
(letfn [(set-modifiers-rec
|
|
||||||
[modif-tree shape modifiers]
|
|
||||||
|
|
||||||
(let [children (map (d/getf objects) (:shapes shape))
|
|
||||||
transformed-rect (gsh/transform-selrect (:selrect shape) modifiers)
|
|
||||||
|
|
||||||
set-layout-child
|
|
||||||
(fn [snap-pixel? {:keys [modif-tree] :as layout-data} child]
|
|
||||||
(let [current-modifier (get-in modif-tree [(:id child) :modifiers])
|
|
||||||
|
|
||||||
;; child (-> (merge child old-modif) gsh/transform-shape)
|
|
||||||
|
|
||||||
[child-modifiers next-layout-data] (gsh/calc-layout-modifiers shape child current-modifier modifiers transformed-rect layout-data)
|
|
||||||
child-modifiers (cond-> child-modifiers snap-pixel? (set-pixel-precision child))
|
|
||||||
|
|
||||||
;;child-modifiers (if (some? old-modif)
|
|
||||||
;; (d/deep-merge (:modifiers old-modif) child-modifiers)
|
|
||||||
;; child-modifiers)
|
|
||||||
|
|
||||||
modif-tree
|
|
||||||
(cond-> modif-tree
|
|
||||||
(not (gsh/empty-modifiers? child-modifiers))
|
|
||||||
(set-modifiers-rec child child-modifiers))]
|
|
||||||
|
|
||||||
(assoc next-layout-data :modif-tree modif-tree)))
|
|
||||||
|
|
||||||
set-child
|
|
||||||
(fn [snap-pixel? modif-tree child]
|
|
||||||
(let [child-modifiers (gsh/calc-child-modifiers shape child modifiers ignore-constraints transformed-rect)
|
|
||||||
child-modifiers (cond-> child-modifiers snap-pixel? (set-pixel-precision child))]
|
|
||||||
(cond-> modif-tree
|
|
||||||
(not (gsh/empty-modifiers? child-modifiers))
|
|
||||||
(set-modifiers-rec child child-modifiers))))
|
|
||||||
|
|
||||||
modif-tree
|
|
||||||
(-> modif-tree
|
|
||||||
(assoc-in [(:id shape) :modifiers] modifiers))
|
|
||||||
|
|
||||||
resize-modif?
|
|
||||||
(or (:resize-vector modifiers) (:resize-vector-2 modifiers))
|
|
||||||
|
|
||||||
|
|
||||||
modif-tree
|
|
||||||
(reduce (partial set-child (and snap-pixel? resize-modif?)) modif-tree children)]
|
|
||||||
|
|
||||||
(cond
|
|
||||||
(:layout shape)
|
|
||||||
(let [layout-data (gsh/calc-layout-data shape children modif-tree transformed-rect)
|
|
||||||
children (cond-> children (:reverse? layout-data) reverse)]
|
|
||||||
(->> children
|
|
||||||
(reduce (partial set-layout-child (and snap-pixel? resize-modif?))
|
|
||||||
(merge {:modif-tree modif-tree} layout-data))
|
|
||||||
:modif-tree))
|
|
||||||
|
|
||||||
:else
|
|
||||||
modif-tree)))]
|
|
||||||
|
|
||||||
(let [modifiers (cond-> modifiers snap-pixel? (set-pixel-precision shape))
|
|
||||||
modif-tree (set-modifiers-rec modif-tree shape modifiers)
|
|
||||||
|
|
||||||
parent (get objects (:parent-id shape))
|
|
||||||
|
|
||||||
modif-tree
|
|
||||||
(cond-> modif-tree
|
|
||||||
(:layout parent)
|
|
||||||
(set-modifiers-rec parent nil))]
|
|
||||||
|
|
||||||
modif-tree)))
|
|
||||||
|
|
||||||
(defn- get-ignore-tree
|
(defn- get-ignore-tree
|
||||||
"Retrieves a map with the flag `ignore-geometry?` given a tree of modifiers"
|
"Retrieves a map with the flag `ignore-geometry?` given a tree of modifiers"
|
||||||
|
@ -590,18 +434,16 @@
|
||||||
(ptk/reify ::update-dimensions
|
(ptk/reify ::update-dimensions
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(let [objects (wsh/lookup-page-objects state)
|
(let [objects (wsh/lookup-page-objects state)
|
||||||
layout (get state :workspace-layout)
|
snap-pixel? (and (contains? (:workspace-layout state) :snap-pixel-grid)
|
||||||
snap-pixel? (contains? layout :snap-pixel-grid)
|
(int? value))
|
||||||
|
get-modifier
|
||||||
|
(fn [shape] (gsh/resize-modifiers shape attr value))
|
||||||
|
|
||||||
update-modifiers
|
modif-tree
|
||||||
(fn [state id]
|
(gsh/set-objects-modifiers ids objects get-modifier false snap-pixel?)]
|
||||||
(let [shape (get objects id)
|
|
||||||
modifiers (gsh/resize-modifiers shape attr value)]
|
(assoc state :workspace-modifiers modif-tree)))
|
||||||
(-> state
|
|
||||||
(update :workspace-modifiers
|
|
||||||
#(set-objects-modifiers % objects shape modifiers false (and snap-pixel? (int? value)))))))]
|
|
||||||
(reduce update-modifiers state ids)))
|
|
||||||
|
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
|
@ -617,17 +459,15 @@
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(let [objects (wsh/lookup-page-objects state)
|
(let [objects (wsh/lookup-page-objects state)
|
||||||
layout (get state :workspace-layout)
|
snap-pixel? (contains? (get state :workspace-layout) :snap-pixel-grid)
|
||||||
snap-pixel? (contains? layout :snap-pixel-grid)
|
|
||||||
|
|
||||||
update-modifiers
|
get-modifier
|
||||||
(fn [state id]
|
(fn [shape] (gsh/change-orientation-modifiers shape orientation))
|
||||||
(let [shape (get objects id)
|
|
||||||
modifiers (gsh/change-orientation-modifiers shape orientation)]
|
modif-tree
|
||||||
(-> state
|
(gsh/set-objects-modifiers ids objects get-modifier false snap-pixel?)]
|
||||||
(update :workspace-modifiers
|
|
||||||
#(set-objects-modifiers % objects shape modifiers false snap-pixel?)))))]
|
(assoc state :workspace-modifiers modif-tree)))
|
||||||
(reduce update-modifiers state ids)))
|
|
||||||
|
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
|
|
Loading…
Add table
Reference in a new issue