Hug content to frames

This commit is contained in:
alonso.torres 2022-11-02 14:14:22 +01:00
parent 0274567d83
commit 7f0054959f
17 changed files with 448 additions and 169 deletions

View file

@ -13,7 +13,6 @@
[app.common.geom.shapes.common :as gco] [app.common.geom.shapes.common :as gco]
[app.common.geom.shapes.constraints :as gct] [app.common.geom.shapes.constraints :as gct]
[app.common.geom.shapes.corners :as gsc] [app.common.geom.shapes.corners :as gsc]
[app.common.geom.shapes.flex-layout :as gcl]
[app.common.geom.shapes.intersect :as gin] [app.common.geom.shapes.intersect :as gin]
[app.common.geom.shapes.modifiers :as gsm] [app.common.geom.shapes.modifiers :as gsm]
[app.common.geom.shapes.path :as gsp] [app.common.geom.shapes.path :as gsp]
@ -184,10 +183,6 @@
;; Constratins ;; Constratins
(dm/export gct/calc-child-modifiers) (dm/export gct/calc-child-modifiers)
;; Layout
(dm/export gcl/calc-layout-data)
(dm/export gcl/calc-layout-modifiers)
;; PATHS ;; PATHS
(dm/export gsp/content->selrect) (dm/export gsp/content->selrect)
(dm/export gsp/transform-content) (dm/export gsp/transform-content)

View file

@ -265,7 +265,7 @@
(if (and (= :scale constraints-h) (= :scale constraints-v)) (if (and (= :scale constraints-h) (= :scale constraints-v))
modifiers modifiers
(let [transformed-child (gst/transform-shape child modifiers) (let [transformed-child (gst/transform-shape child (ctm/select-child-modifiers modifiers))
modifiers (normalize-modifiers constraints-h constraints-v modifiers child parent transformed-child transformed-parent) modifiers (normalize-modifiers constraints-h constraints-v modifiers child parent transformed-child transformed-parent)
transformed-child (gst/transform-shape child modifiers) transformed-child (gst/transform-shape child modifiers)

View file

@ -7,12 +7,15 @@
(ns app.common.geom.shapes.flex-layout (ns app.common.geom.shapes.flex-layout
(:require (:require
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.geom.shapes.flex-layout.bounds :as fbo]
[app.common.geom.shapes.flex-layout.drop-area :as fdr] [app.common.geom.shapes.flex-layout.drop-area :as fdr]
[app.common.geom.shapes.flex-layout.lines :as fli] [app.common.geom.shapes.flex-layout.lines :as fli]
[app.common.geom.shapes.flex-layout.modifiers :as fmo])) [app.common.geom.shapes.flex-layout.modifiers :as fmo]))
(dm/export fli/calc-layout-data) (dm/export fbo/layout-content-bounds)
(dm/export fmo/normalize-child-modifiers)
(dm/export fmo/calc-layout-modifiers)
(dm/export fdr/layout-drop-areas)
(dm/export fdr/get-drop-index) (dm/export fdr/get-drop-index)
(dm/export fdr/layout-drop-areas)
(dm/export fli/calc-layout-data)
(dm/export fmo/layout-child-modifiers)
(dm/export fmo/normalize-child-modifiers)

View file

@ -0,0 +1,113 @@
;; 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) KALEIDOS INC
(ns app.common.geom.shapes.flex-layout.bounds
(:require
[app.common.geom.point :as gpt]
[app.common.geom.shapes.common :as gco]
[app.common.geom.shapes.points :as gpo]
[app.common.geom.shapes.rect :as gre]
[app.common.math :as mth]
[app.common.types.shape.layout :as ctl]))
(defn- child-layout-bound-points
"Returns the bounds of the children as points"
[parent child]
(let [row? (ctl/row? parent)
col? (ctl/col? parent)
hv (partial gpo/start-hv (:points parent))
vv (partial gpo/start-vv (:points parent))
v-start? (ctl/v-start? parent)
v-center? (ctl/v-center? parent)
v-end? (ctl/v-end? parent)
h-start? (ctl/h-start? parent)
h-center? (ctl/h-center? parent)
h-end? (ctl/h-end? parent)
base-p (first (:points child))
width (-> child :selrect :width)
height (-> child :selrect :height)
min-width (if (ctl/fill-width? child)
(ctl/child-min-width child)
width)
min-height (if (ctl/fill-height? child)
(ctl/child-min-height child)
height)
;; This is the leftmost (when row) or topmost (when col) point
;; Will be added always to the bounds and then calculated the other limits
;; from there
base-p (cond-> base-p
(and row? v-center?)
(gpt/add (vv (/ height 2)))
(and row? v-end?)
(gpt/add (vv height))
(and col? h-center?)
(gpt/add (hv (/ width 2)))
(and col? h-end?)
(gpt/add (hv width)))]
(cond-> [base-p]
(and (mth/almost-zero? min-width) (mth/almost-zero? min-height))
(conj (cond-> base-p
row?
(gpt/add (hv width))
col?
(gpt/add (vv height))))
(not (mth/almost-zero? min-width))
(conj (cond-> base-p
(or row? h-start?)
(gpt/add (hv min-width))
(and col? h-center?)
(gpt/add (hv (/ min-width 2)))
(and col? h-center?)
(gpt/subtract (hv min-width))))
(not (mth/almost-zero? min-height))
(conj (cond-> base-p
(or col? v-start?)
(gpt/add (vv min-height))
(and row? v-center?)
(gpt/add (vv (/ min-height 2)))
(and row? v-end?)
(gpt/subtract (vv min-height)))))))
(defn layout-content-bounds
[{:keys [layout-padding] :as parent} children]
(let [{pad-top :p1 pad-right :p2 pad-bottom :p3 pad-left :p4} layout-padding
pad-top (or pad-top 0)
pad-right (or pad-right 0)
pad-bottom (or pad-bottom 0)
pad-left (or pad-left 0)
child-bounds
(fn [{:keys [points] :as child}]
(if (or (ctl/fill-height? child) (ctl/fill-height? child))
(child-layout-bound-points parent child)
points))]
(as-> children $
(mapcat child-bounds $)
(gco/transform-points $ (gco/center-shape parent) (:transform-inverse parent))
(gre/squared-points $)
(gpo/pad-points $ (- pad-top) (- pad-right) (- pad-bottom) (- pad-left))
(gre/points->rect $))))

View file

@ -34,10 +34,13 @@
"Calculates the lines basic data and accumulated values. The positions will be calculated in a different operation" "Calculates the lines basic data and accumulated values. The positions will be calculated in a different operation"
[shape children layout-bounds] [shape children layout-bounds]
(let [wrap? (ctl/wrap? shape) (let [col? (ctl/col? shape)
col? (ctl/col? shape)
row? (ctl/row? shape) row? (ctl/row? shape)
wrap? (and (ctl/wrap? shape)
(or col? (not (ctl/auto-width? shape)))
(or row? (not (ctl/auto-height? shape))))
[layout-gap-row layout-gap-col] (ctl/gaps shape) [layout-gap-row layout-gap-col] (ctl/gaps shape)
layout-width (gpo/width-points layout-bounds) layout-width (gpo/width-points layout-bounds)
layout-height (gpo/height-points layout-bounds) layout-height (gpo/height-points layout-bounds)
@ -278,6 +281,12 @@
(update line-data :children-data (update line-data :children-data
(fn [children-data] (fn [children-data]
(cond->> children-data (cond->> children-data
row?
(map #(assoc % :child-width (:child-min-width %)))
col?
(map #(assoc % :child-height (:child-min-height %)))
row? row?
(distribute-space :child-width :child-min-width :child-max-width line-min-width line-width) (distribute-space :child-width :child-min-width :child-max-width line-min-width line-width)
@ -304,3 +313,4 @@
{:layout-lines layout-lines {:layout-lines layout-lines
:reverse? reverse?})) :reverse? reverse?}))

View file

@ -13,10 +13,9 @@
[app.common.types.modifiers :as ctm] [app.common.types.modifiers :as ctm]
[app.common.types.shape.layout :as ctl])) [app.common.types.shape.layout :as ctl]))
(defn normalize-child-modifiers (defn normalize-child-modifiers
"Apply the modifiers and then normalized them against the parent coordinates" "Apply the modifiers and then normalized them against the parent coordinates"
[parent child modifiers {:keys [transform transform-inverse] :as transformed-parent}] [modifiers parent child {:keys [transform transform-inverse] :as transformed-parent}]
(let [transformed-child (gst/transform-shape child modifiers) (let [transformed-child (gst/transform-shape child modifiers)
child-bb-before (gst/parent-coords-rect child parent) child-bb-before (gst/parent-coords-rect child parent)
@ -38,14 +37,16 @@
{:keys [children-data line-width] :as layout-data}] {:keys [children-data line-width] :as layout-data}]
(cond (cond
(and (ctl/row? parent) (ctl/fill-width? child)) (ctl/row? parent)
(let [target-width (get-in children-data [(:id child) :child-width]) (let [target-width (max (get-in children-data [(:id child) :child-width]) 0.01)
fill-scale (/ target-width child-width)] fill-scale (/ target-width child-width)]
{:width target-width {:width target-width
:modifiers (ctm/resize (gpt/point fill-scale 1) child-origin transform transform-inverse)}) :modifiers (ctm/resize (gpt/point fill-scale 1) child-origin transform transform-inverse)})
(and (ctl/col? parent) (ctl/fill-width? child)) (ctl/col? parent)
(let [target-width (- line-width (ctl/child-width-margin child)) (let [target-width (max (- line-width (ctl/child-width-margin child)) 0.01)
max-width (ctl/child-max-width child)
target-width (min max-width target-width)
fill-scale (/ target-width child-width)] fill-scale (/ target-width child-width)]
{:width target-width {:width target-width
:modifiers (ctm/resize (gpt/point fill-scale 1) child-origin transform transform-inverse)}))) :modifiers (ctm/resize (gpt/point fill-scale 1) child-origin transform transform-inverse)})))
@ -58,19 +59,21 @@
{:keys [children-data line-height] :as layout-data}] {:keys [children-data line-height] :as layout-data}]
(cond (cond
(and (ctl/col? parent) (ctl/fill-height? child)) (ctl/col? parent)
(let [target-height (get-in children-data [(:id child) :child-height]) (let [target-height (max (get-in children-data [(:id child) :child-height]) 0.01)
fill-scale (/ target-height child-height)] fill-scale (/ target-height child-height)]
{:height target-height {:height target-height
:modifiers (ctm/resize (gpt/point 1 fill-scale) child-origin transform transform-inverse)}) :modifiers (ctm/resize (gpt/point 1 fill-scale) child-origin transform transform-inverse)})
(and (ctl/row? parent) (ctl/fill-height? child)) (ctl/row? parent)
(let [target-height (- line-height (ctl/child-height-margin child)) (let [target-height (max (- line-height (ctl/child-height-margin child)) 0.01)
max-height (ctl/child-max-height child)
target-height (min max-height target-height)
fill-scale (/ target-height child-height)] fill-scale (/ target-height child-height)]
{:height target-height {:height target-height
:modifiers (ctm/resize (gpt/point 1 fill-scale) child-origin transform transform-inverse)}))) :modifiers (ctm/resize (gpt/point 1 fill-scale) child-origin transform transform-inverse)})))
(defn calc-layout-modifiers (defn layout-child-modifiers
"Calculates the modifiers for the layout" "Calculates the modifiers for the layout"
[parent child layout-line] [parent child layout-line]
(let [child-bounds (gst/parent-coords-points child parent) (let [child-bounds (gst/parent-coords-points child parent)
@ -79,8 +82,8 @@
child-width (gpo/width-points child-bounds) child-width (gpo/width-points child-bounds)
child-height (gpo/height-points child-bounds) child-height (gpo/height-points child-bounds)
fill-width (calc-fill-width-data parent child child-origin child-width layout-line) fill-width (when (ctl/fill-width? child) (calc-fill-width-data parent child child-origin child-width layout-line))
fill-height (calc-fill-height-data parent child child-origin child-height layout-line) fill-height (when (ctl/fill-height? child) (calc-fill-height-data parent child child-origin child-height layout-line))
child-width (or (:width fill-width) child-width) child-width (or (:width fill-width) child-width)
child-height (or (:height fill-height) child-height) child-height (or (:height fill-height) child-height)

View file

@ -7,27 +7,42 @@
(ns app.common.geom.shapes.modifiers (ns app.common.geom.shapes.modifiers
(: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.shapes.constraints :as gct] [app.common.geom.shapes.constraints :as gct]
[app.common.geom.shapes.flex-layout :as gcl] [app.common.geom.shapes.flex-layout :as gcl]
[app.common.geom.shapes.pixel-precision :as gpp] [app.common.geom.shapes.pixel-precision :as gpp]
[app.common.geom.shapes.transforms :as gtr] [app.common.geom.shapes.transforms :as gtr]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.types.modifiers :as ctm] [app.common.types.modifiers :as ctm]
[app.common.types.shape.layout :as ctl]
[app.common.uuid :as uuid])) [app.common.uuid :as uuid]))
;;#?(:cljs
;; (defn modif->js
;; [modif-tree objects]
;; (clj->js (into {}
;; (map (fn [[k v]]
;; [(get-in objects [k :name]) v]))
;; modif-tree))))
(defn set-children-modifiers (defn set-children-modifiers
[modif-tree objects parent ignore-constraints snap-pixel?] [modif-tree objects parent ignore-constraints snap-pixel?]
(letfn [(set-child [transformed-parent _snap-pixel? modif-tree child] (let [children (map (d/getf objects) (:shapes parent))
(let [modifiers (get-in modif-tree [(:id parent) :modifiers]) modifiers (get-in modif-tree [(:id parent) :modifiers])
child-modifiers (gct/calc-child-modifiers parent child modifiers ignore-constraints transformed-parent) transformed-parent (gtr/transform-shape parent modifiers)
child-modifiers (cond-> child-modifiers snap-pixel? (gpp/set-pixel-precision child))] parent (gtr/transform-shape parent (ctm/select-parent-modifiers modifiers))
(cond-> modif-tree
(not (ctm/empty-modifiers? child-modifiers)) set-child
(update-in [(:id child) :modifiers] ctm/add-modifiers child-modifiers))))] (fn [modif-tree child]
(let [children (map (d/getf objects) (:shapes parent)) (let [child-modifiers (gct/calc-child-modifiers parent child modifiers ignore-constraints transformed-parent)
modifiers (get-in modif-tree [(:id parent) :modifiers]) child-modifiers (cond-> child-modifiers snap-pixel? (gpp/set-pixel-precision child))]
transformed-parent (gtr/transform-shape parent modifiers)] (cond-> modif-tree
(reduce (partial set-child transformed-parent snap-pixel?) modif-tree children)))) (not (ctm/empty-modifiers? child-modifiers))
(update-in [(:id child) :modifiers] ctm/add-modifiers child-modifiers))))]
(reduce set-child modif-tree children)))
(defn group? [shape] (defn group? [shape]
(or (= :group (:type shape)) (or (= :group (:type shape))
@ -36,17 +51,15 @@
(defn frame? [shape] (defn frame? [shape]
(= :frame (:type shape))) (= :frame (:type shape)))
(defn layout? [shape]
(and (frame? shape)
(:layout shape)))
(defn set-layout-modifiers (defn set-layout-modifiers
;; TODO LAYOUT: SNAP PIXEL! ;; TODO LAYOUT: SNAP PIXEL!
[modif-tree objects parent _snap-pixel?] [modif-tree objects parent _snap-pixel?]
(letfn [(normalize-child [transformed-parent _snap-pixel? modif-tree child] (letfn [(process-child [transformed-parent _snap-pixel? modif-tree child]
(let [modifiers (get-in modif-tree [(:id parent) :modifiers]) (let [modifiers (get-in modif-tree [(:id parent) :modifiers])
child-modifiers (gcl/normalize-child-modifiers parent child modifiers transformed-parent)] child-modifiers (-> modifiers
(ctm/select-child-geometry-modifiers)
(gcl/normalize-child-modifiers parent child transformed-parent))]
(cond-> modif-tree (cond-> modif-tree
(not (ctm/empty-modifiers? child-modifiers)) (not (ctm/empty-modifiers? child-modifiers))
(update-in [(:id child) :modifiers] ctm/add-modifiers child-modifiers)))) (update-in [(:id child) :modifiers] ctm/add-modifiers child-modifiers))))
@ -60,9 +73,9 @@
(and (some? modifiers) (group? child)) (and (some? modifiers) (group? child))
(gtr/apply-group-modifiers objects modif-tree)))) (gtr/apply-group-modifiers objects modif-tree))))
(set-layout-modifiers [parent [layout-line modif-tree] child] (set-child-modifiers [parent [layout-line modif-tree] child]
(let [[modifiers layout-line] (let [[modifiers layout-line]
(gcl/calc-layout-modifiers parent child layout-line) (gcl/layout-child-modifiers parent child layout-line)
modif-tree modif-tree
(cond-> modif-tree (cond-> modif-tree
@ -75,8 +88,9 @@
transformed-parent (gtr/transform-shape parent modifiers) transformed-parent (gtr/transform-shape parent modifiers)
children (map (d/getf objects) (:shapes transformed-parent)) children (map (d/getf objects) (:shapes transformed-parent))
modif-tree (reduce (partial normalize-child transformed-parent _snap-pixel?) modif-tree children) modif-tree (reduce (partial process-child transformed-parent _snap-pixel?) modif-tree children)
children (->> children (map (partial apply-modifiers modif-tree))) children (->> children (map (partial apply-modifiers modif-tree)))
layout-data (gcl/calc-layout-data transformed-parent children) layout-data (gcl/calc-layout-data transformed-parent children)
children (into [] (cond-> children (:reverse? layout-data) reverse)) children (into [] (cond-> children (:reverse? layout-data) reverse))
max-idx (dec (count children)) max-idx (dec (count children))
@ -92,11 +106,56 @@
children (subvec children from-idx to-idx) children (subvec children from-idx to-idx)
[_ modif-tree] [_ modif-tree]
(reduce (partial set-layout-modifiers transformed-parent) [layout-line modif-tree] children)] (reduce (partial set-child-modifiers transformed-parent) [layout-line modif-tree] children)]
(recur modif-tree (first pending) (rest pending) to-idx)) (recur modif-tree (first pending) (rest pending) to-idx))
modif-tree))))) modif-tree)))))
(defn set-auto-modifiers
[modif-tree objects parent]
(letfn [(apply-modifiers [child]
(let [modifiers (get-in modif-tree [(:id child) :modifiers])]
(cond-> child
(some? modifiers)
(gtr/transform-shape modifiers)
(and (some? modifiers) (group? child))
(gtr/apply-group-modifiers objects modif-tree))))
(set-parent-auto-width
[modifiers parent auto-width]
(let [origin (-> parent :points first)
scale-width (/ auto-width (-> parent :selrect :width) )]
(-> modifiers
(ctm/set-resize-parent (gpt/point scale-width 1) origin (:transform parent) (:transform-inverse parent)))))
(set-parent-auto-height
[modifiers parent auto-height]
(let [origin (-> parent :points first)
scale-height (/ auto-height (-> parent :selrect :height) )]
(-> modifiers
(ctm/set-resize-parent (gpt/point 1 scale-height) origin (:transform parent) (:transform-inverse parent)))))]
(let [modifiers (get-in modif-tree [(:id parent) :modifiers])
transformed-parent (gtr/transform-shape parent modifiers)
children (->> transformed-parent
:shapes
(map (comp apply-modifiers (d/getf objects))))
{auto-width :width auto-height :height}
(when (and (d/not-empty? children) (or (ctl/auto-height? parent) (ctl/auto-width? parent)))
(gcl/layout-content-bounds parent children))
modifiers
(cond-> modifiers
(and (some? auto-width) (ctl/auto-width? parent))
(set-parent-auto-width transformed-parent auto-width)
(and (some? auto-height) (ctl/auto-height? parent))
(set-parent-auto-height transformed-parent auto-height))]
(assoc-in modif-tree [(:id parent) :modifiers] modifiers))))
(defn get-tree-root (defn get-tree-root
[id objects] [id objects]
@ -109,7 +168,9 @@
result result
;; Frame found, but not layout we return the last layout found (or the id) ;; Frame found, but not layout we return the last layout found (or the id)
(and (= :frame (:type parent)) (and (and (= :frame (:type parent))
(not (ctl/auto-width? parent))
(not (ctl/auto-height? parent)))
(not (:layout parent))) (not (:layout parent)))
result result
@ -124,7 +185,9 @@
(defn resolve-tree-sequence (defn resolve-tree-sequence
"Given the ids that have changed search for layout roots to recalculate" "Given the ids that have changed search for layout roots to recalculate"
[modif-tree objects] [ids objects]
(assert (or (nil? ids) (set? ids)) (dm/str "tree sequence from not set: " ids))
(let [redfn (let [redfn
(fn [result id] (fn [result id]
@ -152,10 +215,10 @@
(map #(get objects %)))) (map #(get objects %))))
roots (->> modif-tree keys (reduce redfn #{}))] roots (->> ids (reduce redfn #{}))]
(concat (concat
(when (contains? modif-tree uuid/zero) [(get objects uuid/zero)]) (when (contains? ids uuid/zero) [(get objects uuid/zero)])
(mapcat generate-tree roots)))) (mapcat generate-tree roots))))
(defn inside-layout? (defn inside-layout?
@ -173,48 +236,55 @@
:else :else
(recur (:parent-id current)))))) (recur (:parent-id current))))))
;;#?(:cljs (defn- calculate-modifiers
;; (defn modif->js ([objects snap-pixel? ignore-constraints [modif-tree recalculate] shape]
;; [modif-tree objects] (calculate-modifiers objects snap-pixel? ignore-constraints false [modif-tree recalculate] shape))
;; (clj->js (into {}
;; (map (fn [[k v]] ([objects snap-pixel? ignore-constraints ignore-auto? [modif-tree recalculate] shape]
;; [(get-in objects [k :name]) v])) (let [shape-id (:id shape)
;; modif-tree)))) root? (= uuid/zero shape-id)
modifiers (get-in modif-tree [shape-id :modifiers])
modifiers (cond-> modifiers
(and (not root?) (ctm/has-geometry? modifiers) snap-pixel?)
(gpp/set-pixel-precision shape))
modif-tree (-> modif-tree (assoc-in [shape-id :modifiers] modifiers))
has-modifiers? (ctm/child-modifiers? modifiers)
is-layout? (ctl/layout? shape)
is-auto? (or (ctl/auto-height? shape) (ctl/auto-width? shape))
is-parent? (or (group? shape) (and (frame? shape) (not (ctl/layout? shape))))
;; If the current child is inside the layout we ignore the constraints
is-inside-layout? (inside-layout? objects shape)]
[(cond-> modif-tree
(and has-modifiers? is-parent? (not root?))
(set-children-modifiers objects shape (or ignore-constraints is-inside-layout?) snap-pixel?)
is-layout?
(set-layout-modifiers objects shape snap-pixel?)
(and (not ignore-auto?) is-auto?)
(set-auto-modifiers objects shape))
(cond-> recalculate
;; Auto-width/height can change the positions in the parent so we need to recalculate
(and (not ignore-auto?) is-auto?)
(conj (:id shape)))])))
(defn set-objects-modifiers (defn set-objects-modifiers
[modif-tree objects ignore-constraints snap-pixel?] [modif-tree objects ignore-constraints snap-pixel?]
(let [shapes-tree (resolve-tree-sequence modif-tree objects) (let [shapes-tree (resolve-tree-sequence (-> modif-tree keys set) objects)
modif-tree [modif-tree recalculate]
(->> shapes-tree (reduce (partial calculate-modifiers objects snap-pixel? ignore-constraints) [modif-tree #{}] shapes-tree)
(reduce
(fn [modif-tree shape]
(let [root? (= uuid/zero (:id shape)) shapes-tree (resolve-tree-sequence recalculate objects)
[modif-tree _]
modifiers (get-in modif-tree [(:id shape) :modifiers]) (reduce (partial calculate-modifiers objects snap-pixel? ignore-constraints true) [modif-tree #{}] shapes-tree)]
modifiers (cond-> modifiers
(and (not root?) (ctm/has-geometry? modifiers) snap-pixel?)
(gpp/set-pixel-precision shape))
modif-tree (-> modif-tree (assoc-in [(:id shape) :modifiers] modifiers))
has-modifiers? (ctm/child-modifiers? modifiers)
is-layout? (layout? shape)
is-parent? (or (group? shape) (and (frame? shape) (not (layout? shape))))
;; If the current child is inside the layout we ignore the constraints
is-inside-layout? (inside-layout? objects shape)]
(cond-> modif-tree
(and has-modifiers? is-parent? (not root?))
(set-children-modifiers objects shape (or ignore-constraints is-inside-layout?) snap-pixel?)
is-layout?
(set-layout-modifiers objects shape snap-pixel?))))
modif-tree))]
;;#?(:cljs ;;#?(:cljs
;; (.log js/console ">result" (modif->js modif-tree objects))) ;; (.log js/console ">result" (modif->js modif-tree objects)))

View file

@ -50,12 +50,13 @@
(defn pad-points (defn pad-points
[[p0 p1 p2 p3 :as points] pad-top pad-right pad-bottom pad-left] [[p0 p1 p2 p3 :as points] pad-top pad-right pad-bottom pad-left]
(let [top-v (start-vv points pad-top) (when (some? points)
right-v (end-hv points pad-right) (let [top-v (start-vv points pad-top)
bottom-v (end-vv points pad-bottom) right-v (end-hv points pad-right)
left-v (start-hv points pad-left)] bottom-v (end-vv points pad-bottom)
left-v (start-hv points pad-left)]
[(-> p0 (gpt/add left-v) (gpt/add top-v)) [(-> p0 (gpt/add left-v) (gpt/add top-v))
(-> p1 (gpt/add right-v) (gpt/add top-v)) (-> p1 (gpt/add right-v) (gpt/add top-v))
(-> p2 (gpt/add right-v) (gpt/add bottom-v)) (-> p2 (gpt/add right-v) (gpt/add bottom-v))
(-> p3 (gpt/add left-v) (gpt/add bottom-v))])) (-> p3 (gpt/add left-v) (gpt/add bottom-v))])))

View file

@ -87,6 +87,19 @@
(when (d/num? minx miny maxx maxy) (when (d/num? minx miny maxx maxy)
(make-rect minx miny (- maxx minx) (- maxy miny)))))) (make-rect minx miny (- maxx minx) (- maxy miny))))))
(defn squared-points
[points]
(when (d/not-empty? points)
(let [minx (transduce (keep :x) min ##Inf points)
miny (transduce (keep :y) min ##Inf points)
maxx (transduce (keep :x) max ##-Inf points)
maxy (transduce (keep :y) max ##-Inf points)]
(when (d/num? minx miny maxx maxy)
[(gpt/point minx miny)
(gpt/point maxx miny)
(gpt/point maxx maxy)
(gpt/point minx maxy)]))))
(defn points->selrect [points] (defn points->selrect [points]
(when-let [rect (points->rect points)] (when-let [rect (points->rect points)]
(let [{:keys [x y width height]} rect] (let [{:keys [x y width height]} rect]

View file

@ -434,20 +434,35 @@
(map (comp gpr/points->selrect :points transform-shape)) (map (comp gpr/points->selrect :points transform-shape))
(gpr/join-selrects))) (gpr/join-selrects)))
(defn apply-children-modifiers
[objects modif-tree children]
(->> children
(map (fn [child]
(let [modifiers (get-in modif-tree [(:id child) :modifiers])
child (transform-shape child modifiers)
parent? (or (= :group (:type child)) (= :bool (:type child)))]
(cond-> child
parent?
(apply-children-modifiers objects modif-tree)))))))
(defn apply-group-modifiers (defn apply-group-modifiers
"Apply the modifiers to the group children to calculate its selection rect" "Apply the modifiers to the group children to calculate its selection rect"
[group objects modif-tree] [parent objects modif-tree]
(let [children (->> (:shapes parent)
(map (d/getf objects))
(apply-children-modifiers objects modif-tree))]
(cond-> parent
(= :group (:type parent))
(update-group-selrect children))))
(defn get-children-bounds
[parent objects modif-tree]
(let [children (let [children
(->> (:shapes group) (->> (:shapes parent)
(map (d/getf objects)) (map (d/getf objects))
(map (fn [shape] (apply-children-modifiers objects modif-tree))]
(let [modifiers (get modif-tree (:id shape)) (->> children (mapcat :points) gpr/points->rect)))
shape (-> shape (merge modifiers) transform-shape)]
(if (= :group (:type shape))
(apply-group-modifiers shape objects modif-tree)
shape)))))]
(update-group-selrect group children)))
(defn parent-coords-rect (defn parent-coords-rect
[child parent] [child parent]

View file

@ -17,7 +17,11 @@
;; --- Modifiers ;; --- Modifiers
;; Moodifiers types ;; Moodifiers types
;; - geometry: Geometry ;; - geometry-parent: Geometry non-recursive
;; * move
;; * resize
;; * rotation
;; - geometry-child: Geometry recursive
;; * move ;; * move
;; * resize ;; * resize
;; * rotation ;; * rotation
@ -28,7 +32,6 @@
;; - structure-child: Structure recursive ;; - structure-child: Structure recursive
;; * scale-content ;; * scale-content
;; * rotation ;; * rotation
;;
(def conjv (fnil conj [])) (def conjv (fnil conj []))
@ -37,37 +40,59 @@
(defn empty-modifiers [] (defn empty-modifiers []
{}) {})
(defn set-move-parent
([modifiers x y]
(set-move-parent modifiers (gpt/point x y)))
([modifiers vector]
(-> modifiers
(update :geometry-parent conjv {:type :move :vector vector}))))
(defn set-resize-parent
([modifiers vector origin]
(-> modifiers
(update :geometry-parent conjv {:type :resize
:vector vector
:origin origin})))
([modifiers vector origin transform transform-inverse]
(-> modifiers
(update :geometry-parent conjv {:type :resize
:vector vector
:origin origin
:transform transform
:transform-inverse transform-inverse}))))
(defn set-move (defn set-move
([modifiers x y] ([modifiers x y]
(set-move modifiers (gpt/point x y))) (set-move modifiers (gpt/point x y)))
([modifiers vector] ([modifiers vector]
(-> modifiers (-> modifiers
(update :geometry conjv {:type :move :vector vector})))) (update :geometry-child conjv {:type :move :vector vector}))))
(defn set-resize (defn set-resize
([modifiers vector origin] ([modifiers vector origin]
(-> modifiers (-> modifiers
(update :geometry conjv {:type :resize (update :geometry-child conjv {:type :resize
:vector vector :vector vector
:origin origin}))) :origin origin})))
([modifiers vector origin transform transform-inverse] ([modifiers vector origin transform transform-inverse]
(-> modifiers (-> modifiers
(update :geometry conjv {:type :resize (update :geometry-child conjv {:type :resize
:vector vector :vector vector
:origin origin :origin origin
:transform transform :transform transform
:transform-inverse transform-inverse})))) :transform-inverse transform-inverse}))))
(defn set-rotation (defn set-rotation
[modifiers center angle] [modifiers center angle]
(-> modifiers (-> modifiers
(update :structure-child conjv {:type :rotation (update :structure-child conjv {:type :rotation
:rotation angle}) :rotation angle})
(update :geometry conjv {:type :rotation (update :geometry-child conjv {:type :rotation
:center center :center center
:rotation angle}))) :rotation angle})))
(defn set-remove-children (defn set-remove-children
[modifiers shapes] [modifiers shapes]
@ -97,8 +122,11 @@
[modifiers new-modifiers] [modifiers new-modifiers]
(cond-> modifiers (cond-> modifiers
(some? (:geometry new-modifiers)) (some? (:geometry-child new-modifiers))
(update :geometry #(d/concat-vec [] % (:geometry new-modifiers))) (update :geometry-child #(d/concat-vec [] % (:geometry-child new-modifiers)))
(some? (:geometry-parent new-modifiers))
(update :geometry-parent #(d/concat-vec [] % (:geometry-parent new-modifiers)))
(some? (:structure-parent new-modifiers)) (some? (:structure-parent new-modifiers))
(update :structure-parent #(d/concat-vec [] % (:structure-parent new-modifiers))) (update :structure-parent #(d/concat-vec [] % (:structure-parent new-modifiers)))
@ -116,6 +144,13 @@
([vector] ([vector]
(set-move (empty-modifiers) vector))) (set-move (empty-modifiers) vector)))
(defn move-parent
([x y]
(set-move-parent (empty-modifiers) (gpt/point x y)))
([vector]
(set-move-parent (empty-modifiers) vector)))
(defn resize (defn resize
([vector origin] ([vector origin]
(set-resize (empty-modifiers) vector origin)) (set-resize (empty-modifiers) vector origin))
@ -123,6 +158,13 @@
([vector origin transform transform-inverse] ([vector origin transform transform-inverse]
(set-resize (empty-modifiers) vector origin transform transform-inverse))) (set-resize (empty-modifiers) vector origin transform transform-inverse)))
(defn resize-parent
([vector origin]
(set-resize-parent (empty-modifiers) vector origin))
([vector origin transform transform-inverse]
(set-resize-parent (empty-modifiers) vector origin transform transform-inverse)))
(defn rotation (defn rotation
[shape center angle] [shape center angle]
(let [shape-center (gco/center-shape shape) (let [shape-center (gco/center-shape shape)
@ -155,32 +197,30 @@
(set-scale-content value))) (set-scale-content value)))
(defn child-modifiers? (defn child-modifiers?
[{:keys [geometry structure-child]}] [{:keys [geometry-child structure-child]}]
(or (d/not-empty? geometry) (or (d/not-empty? geometry-child)
(d/not-empty? structure-child))) (d/not-empty? structure-child)))
(defn select-child-modifiers (defn select-child-modifiers
[modifiers] [modifiers]
(select-keys modifiers [:geometry :structure-child])) (select-keys modifiers [:geometry-child :structure-child]))
(defn select-child-geometry-modifiers
[modifiers]
(select-keys modifiers [:geometry-child]))
(defn select-parent-modifiers
[modifiers]
(select-keys modifiers [:geometry-parent :structure-parent]))
(defn select-structure (defn select-structure
[modifiers] [modifiers]
(select-keys modifiers [:structure-parent])) (select-keys modifiers [:structure-parent]))
(defn add-move
([object x y]
(add-move object (gpt/point x y)))
([object vector]
(update object :modifiers (move vector))))
(defn add-resize
[object vector origin]
(update object :modifiers (resize vector origin)))
(defn empty-modifiers? (defn empty-modifiers?
[modifiers] [modifiers]
(and (empty? (:geometry modifiers)) (and (empty? (:geometry-child modifiers))
(empty? (:geometry-parent modifiers))
(empty? (:structure-parent modifiers)) (empty? (:structure-parent modifiers))
(empty? (:structure-child modifiers)))) (empty? (:structure-child modifiers))))
@ -253,8 +293,10 @@
(defn only-move? (defn only-move?
[modifier] [modifier]
(and (= 1 (-> modifier :geometry count)) (or (and (= 1 (-> modifier :geometry-child count))
(= :move (-> modifier :geometry first :type)))) (= :move (-> modifier :geometry-child first :type)))
(and (= 1 (-> modifier :geometry-parent count))
(= :move (-> modifier :geometry-parent first :type)))))
(defn get-frame-add-children (defn get-frame-add-children
[modif-tree] [modif-tree]
@ -300,8 +342,11 @@
(gmt/multiply (gmt/rotate-matrix rotation)) (gmt/multiply (gmt/rotate-matrix rotation))
(gmt/translate (gpt/negate center))) (gmt/translate (gpt/negate center)))
matrix)))] matrix)))]
(->> modifiers :geometry (let [modifiers (if (d/not-empty? (:geometry-parent modifiers))
(reduce apply-modifier (gmt/matrix))))) (d/concat-vec (:geometry-parent modifiers) (:geometry-child modifiers))
(:geometry-child modifiers))]
(->> modifiers
(reduce apply-modifier (gmt/matrix))))))
(defn scale-text-content (defn scale-text-content
[content value] [content value]
@ -357,5 +402,6 @@
(reduce apply-modifier $ (:structure-child modifiers))))) (reduce apply-modifier $ (:structure-child modifiers)))))
(defn has-geometry? (defn has-geometry?
[{:keys [geometry]}] [{:keys [geometry-parent geometry-child]}]
(d/not-empty? geometry)) (or (d/not-empty? geometry-parent)
(d/not-empty? geometry-child)))

View file

@ -109,6 +109,12 @@
(defn fill-height? [child] (defn fill-height? [child]
(= :fill (:layout-item-v-sizing child))) (= :fill (:layout-item-v-sizing child)))
(defn auto-width? [child]
(= :auto (:layout-item-h-sizing child)))
(defn auto-height? [child]
(= :auto (:layout-item-v-sizing child)))
(defn col? (defn col?
[{:keys [layout-flex-dir]}] [{:keys [layout-flex-dir]}]
(or (= :column layout-flex-dir) (= :reverse-column layout-flex-dir))) (or (= :column layout-flex-dir) (= :reverse-column layout-flex-dir)))

View file

@ -142,8 +142,6 @@
shape-before (assoc shape-before :modifiers modifiers) shape-before (assoc shape-before :modifiers modifiers)
shape-after (gsh/transform-shape shape-before)] shape-after (gsh/transform-shape shape-before)]
(t/is (not= (:selrect shape-before) (:selrect shape-after)))
(t/is (close? (get-in shape-before [:selrect :x]) (t/is (close? (get-in shape-before [:selrect :x])
(get-in shape-after [:selrect :x]))) (get-in shape-after [:selrect :x])))

View file

@ -9,6 +9,7 @@
[app.common.data :as d] [app.common.data :as d]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.types.modifiers :as ctm] [app.common.types.modifiers :as ctm]
[app.common.types.shape.layout :as ctl]
[app.main.data.workspace.changes :as dwc] [app.main.data.workspace.changes :as dwc]
[app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.transforms :as dwt] [app.main.data.workspace.transforms :as dwt]
@ -68,7 +69,6 @@
(rx/of (dwc/update-shapes ids #(merge % initial-grid-layout)) (rx/of (dwc/update-shapes ids #(merge % initial-grid-layout))
(update-layout-positions ids)))))) (update-layout-positions ids))))))
(defn remove-layout (defn remove-layout
[ids] [ids]
(ptk/reify ::remove-layout (ptk/reify ::remove-layout
@ -91,6 +91,7 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(let [objects (wsh/lookup-page-objects state) (let [objects (wsh/lookup-page-objects state)
parent-ids (->> ids (map #(cph/get-parent-id objects %)))] parent-ids (->> ids (map #(cph/get-parent-id objects %)))
layout-ids (->> ids (filter (comp ctl/layout? (d/getf objects))))]
(rx/of (dwc/update-shapes ids #(d/deep-merge (or % {}) changes)) (rx/of (dwc/update-shapes ids #(d/deep-merge (or % {}) changes))
(update-layout-positions parent-ids)))))) (update-layout-positions (d/concat-vec layout-ids parent-ids)))))))

View file

@ -11,6 +11,7 @@
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.types.shape-tree :as ctt] [app.common.types.shape-tree :as ctt]
[app.common.types.shape.layout :as ctl]
[app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.state-helpers :as wsh]
[app.main.store :as st] [app.main.store :as st]
[okulary.core :as l])) [okulary.core :as l]))
@ -442,7 +443,7 @@
(l/derived (l/derived
(fn [objects] (fn [objects]
(->> ids (->> ids
(some #(-> (cph/get-parent objects %) :layout)))) (some #(-> (cph/get-parent objects %) ctl/layout?))))
workspace-page-objects)) workspace-page-objects))
(defn get-flex-child-viewer? (defn get-flex-child-viewer?

View file

@ -80,7 +80,7 @@
(mf/defc element-behavior (mf/defc element-behavior
[{:keys [is-layout-container? is-layout-child? layout-item-h-sizing layout-item-v-sizing on-change-behavior] :as props}] [{:keys [is-layout-container? is-layout-child? layout-item-h-sizing layout-item-v-sizing on-change-behavior] :as props}]
(let [fill? is-layout-child? (let [fill? is-layout-child?
auto? is-layout-container?] auto? is-layout-container?]
[:div.btn-wrapper [:div.btn-wrapper
[:div.layout-behavior.horizontal [:div.layout-behavior.horizontal
@ -98,7 +98,7 @@
(when auto? (when auto?
[:button.behavior-btn.tooltip.tooltip-bottom [:button.behavior-btn.tooltip.tooltip-bottom
{:alt "Fit content" {:alt "Fit content"
:class (dom/classnames :active (= layout-item-v-sizing :auto)) :class (dom/classnames :active (= layout-item-h-sizing :auto))
:on-click #(on-change-behavior :h :auto)} :on-click #(on-change-behavior :h :auto)}
i/auto-hug])] i/auto-hug])]
@ -188,9 +188,11 @@
:on-change-behavior on-change-behavior}]] :on-change-behavior on-change-behavior}]]
[:& margin-section {:values values (when is-layout-child?
:change-margin-style change-margin-style [:& margin-section {:values values
:on-margin-change on-margin-change}] :change-margin-style change-margin-style
:on-margin-change on-margin-change}])
[:div.advanced-ops-container [:div.advanced-ops-container
[:button.advanced-ops.toltip.tooltip-bottom [:button.advanced-ops.toltip.tooltip-bottom
{:on-click toggle-open {:on-click toggle-open
@ -200,12 +202,13 @@
(when @open? (when @open?
[:div.advanced-ops-body [:div.advanced-ops-body
[:div.layout-row (when is-layout-child?
[:div.direction-wrap.row-title "Align"] [:div.layout-row
[:div.btn-wrapper [:div.direction-wrap.row-title "Align"]
[:& align-self-row {:is-col? is-col? [:div.btn-wrapper
:align-self align-self [:& align-self-row {:is-col? is-col?
:set-align-self set-align-self}]]] :align-self align-self
:set-align-self set-align-self}]]])
[:div.input-wrapper [:div.input-wrapper
(for [item [:layout-item-max-h :layout-item-min-h :layout-item-max-w :layout-item-min-w]] (for [item [:layout-item-max-h :layout-item-min-h :layout-item-max-w :layout-item-min-w]]
[:div.tooltip.tooltip-bottom [:div.tooltip.tooltip-bottom

View file

@ -6,6 +6,7 @@
(ns app.main.ui.workspace.sidebar.options.shapes.frame (ns app.main.ui.workspace.sidebar.options.shapes.frame
(:require (:require
[app.common.types.shape.layout :as ctl]
[app.main.features :as features] [app.main.features :as features]
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]] [app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]]
@ -35,7 +36,8 @@
layout-item-values (select-keys shape layout-item-attrs) layout-item-values (select-keys shape layout-item-attrs)
is-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-layout-child? ids)) is-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-layout-child? ids))
is-layout-child? (mf/deref is-layout-child-ref)] is-layout-child? (mf/deref is-layout-child-ref)
is-layout-container? (ctl/layout? shape)]
[:* [:*
[:& measures-menu {:ids [(:id shape)] [:& measures-menu {:ids [(:id shape)]
:values measure-values :values measure-values
@ -43,18 +45,17 @@
:shape shape}] :shape shape}]
[:& constraints-menu {:ids ids [:& constraints-menu {:ids ids
:values constraint-values}] :values constraint-values}]
(when layout-active? (when (or layout-active? is-layout-container?)
[:* [:& layout-container-menu {:type type :ids [(:id shape)] :values layout-container-values}])
[:& layout-container-menu {:type type :ids [(:id shape)] :values layout-container-values}]
(when is-layout-child? (when (and layout-active? (or is-layout-child? is-layout-container?))
[:& layout-item-menu [:& layout-item-menu
{:ids ids {:ids ids
:type type :type type
:values layout-item-values :values layout-item-values
:is-layout-child? is-layout-child? :is-layout-child? is-layout-child?
:is-layout-container? (:layout shape) :is-layout-container? is-layout-container?
:shape shape}])]) :shape shape}])
[:& layer-menu {:ids ids [:& layer-menu {:ids ids
:type type :type type