diff --git a/common/src/app/common/geom/shapes/flex_layout/bounds.cljc b/common/src/app/common/geom/shapes/flex_layout/bounds.cljc index b762090d3e..64e673fd23 100644 --- a/common/src/app/common/geom/shapes/flex_layout/bounds.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/bounds.cljc @@ -8,7 +8,6 @@ (:require [app.common.geom.point :as gpt] [app.common.geom.shapes.points :as gpo] - [app.common.math :as mth] [app.common.types.shape.layout :as ctl])) (defn child-layout-bound-points @@ -55,38 +54,32 @@ (gpt/add (hv (/ width 2))) (and col? h-end?) - (gpt/add (hv width)))] + (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)) + ;; We need some height/width to calculate the bounds. We stablish the minimum + min-width (max min-width 0.01) + min-height (max min-height 0.01)] - col? - (gpt/add (vv height)))) + (-> [base-p] + (conj (cond-> base-p + (or row? h-start?) + (gpt/add (hv min-width)) - (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/add (hv (/ min-width 2))) + (and col? h-center?) + (gpt/subtract (hv min-width)))) - (and col? h-center?) - (gpt/subtract (hv min-width)))) + (conj (cond-> base-p + (or col? v-start?) + (gpt/add (vv min-height)) - (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-center?) - (gpt/add (vv (/ min-height 2))) - - (and row? v-end?) - (gpt/subtract (vv min-height))))))) + (and row? v-end?) + (gpt/subtract (vv min-height))))))) (defn layout-content-bounds [bounds {:keys [layout-padding] :as parent} children] @@ -107,8 +100,11 @@ child-bounds (if (or (ctl/fill-height? child) (ctl/fill-height? child)) (child-layout-bound-points parent child parent-bounds child-bounds) - child-bounds)] - (gpo/parent-coords-bounds child-bounds parent-bounds)))] + child-bounds) + + [margin-top margin-right margin-bottom margin-left] (ctl/child-margins child)] + (-> (gpo/parent-coords-bounds child-bounds parent-bounds) + (gpo/pad-points (- margin-top) (- margin-right) (- margin-bottom) (- margin-left)))))] (as-> children $ (map child-bounds $) diff --git a/common/src/app/common/geom/shapes/pixel_precision.cljc b/common/src/app/common/geom/shapes/pixel_precision.cljc index f6451ab022..fa7c501317 100644 --- a/common/src/app/common/geom/shapes/pixel_precision.cljc +++ b/common/src/app/common/geom/shapes/pixel_precision.cljc @@ -32,6 +32,7 @@ ratio-width (/ target-width curr-width) ratio-height (/ target-height curr-height) scalev (gpt/point ratio-width ratio-height)] + (-> modifiers (ctm/resize scalev origin transform transform-inverse)))) @@ -41,7 +42,6 @@ corner (gpt/point bounds) target-corner (gpt/round corner) deltav (gpt/to-vec corner target-corner)] - (ctm/move modifiers deltav))) (defn set-pixel-precision @@ -56,8 +56,10 @@ has-resize? (size-pixel-precision shape points)) points - (cond-> (:points shape) - has-resize? (gco/transform-points (ctm/modifiers->transform modifiers)))] + (if has-resize? + (-> (:points shape) + (gco/transform-points (ctm/modifiers->transform modifiers)) ) + points)] [modifiers points])] (position-pixel-precision modifiers shape points))) diff --git a/common/src/app/common/pages/common.cljc b/common/src/app/common/pages/common.cljc index de34e6b742..885cdb9678 100644 --- a/common/src/app/common/pages/common.cljc +++ b/common/src/app/common/pages/common.cljc @@ -76,7 +76,6 @@ :layout :layout-container :layout-dir :layout-container :layout-gap :layout-container - :layout-type :layout-container :layout-wrap-type :layout-container :layout-padding-type :layout-container :layout-padding :layout-container diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 1fb0f40509..bfe99ed200 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -50,7 +50,6 @@ (s/def ::row-gap ::us/safe-number) (s/def ::column-gap ::us/safe-number) -(s/def ::layout-type #{:flex :grid}) (s/def ::layout-gap (s/keys :opt-un [::row-gap ::column-gap])) @@ -60,7 +59,6 @@ ::layout-flex-dir ::layout-gap ::layout-gap-type - ::layout-type ::layout-wrap-type ::layout-padding-type ::layout-padding diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 14cac6d30b..f6f0801572 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -28,6 +28,7 @@ [app.main.data.workspace.undo :as dwu] [app.main.snap :as snap] [app.main.streams :as ms] + [app.util.dom :as dom] [beicon.core :as rx] [cljs.spec.alpha :as s] [potok.core :as ptk])) @@ -415,6 +416,14 @@ (rx/take 1) (rx/map #(start-move from-position)))))) +(defn set-ghost-displacement + [move-vector] + (ptk/reify ::set-ghost-displacement + ptk/EffectEvent + (effect [_ _ _] + (when-let [node (dom/get-element-by-class "ghost-outline")] + (dom/set-property! node "transform" (gmt/translate-matrix move-vector)))))) + (defn- start-move ([from-position] (start-move from-position nil)) ([from-position ids] @@ -501,6 +510,9 @@ (dwm/build-change-frame-modifiers objects selected target-frame drop-index) (dwm/set-modifiers))))) + (->> move-stream + (rx/map (comp set-ghost-displacement first))) + ;; Last event will write the modifiers creating the changes (->> move-stream (rx/last) @@ -508,10 +520,10 @@ (fn [[_ target-frame drop-index]] (let [undo-id (uuid/next)] (rx/of (dwu/start-undo-transaction undo-id) - (move-shapes-to-frame ids target-frame drop-index) - (dwm/apply-modifiers {:undo-transation? false}) - (finish-transform) - (dwu/commit-undo-transaction undo-id)))))))))))))) + (move-shapes-to-frame ids target-frame drop-index) + (dwm/apply-modifiers {:undo-transation? false}) + (finish-transform) + (dwu/commit-undo-transaction undo-id)))))))))))))) (s/def ::direction #{:up :down :right :left}) diff --git a/frontend/src/app/main/ui/shapes/export.cljs b/frontend/src/app/main/ui/shapes/export.cljs index 1ea742cebb..00de59a7a6 100644 --- a/frontend/src/app/main/ui/shapes/export.cljs +++ b/frontend/src/app/main/ui/shapes/export.cljs @@ -332,16 +332,84 @@ :penpot:preserve-scroll ((d/nilf str) (:preserve-scroll interaction))}])]))) +(defn- export-layout-container-data + [{:keys [layout + layout-flex-dir + layout-gap + layout-gap-type + layout-wrap-type + layout-padding-type + layout-padding + layout-justify-content + layout-align-items + layout-align-content]}] + + (when layout + (mf/html + [:> "penpot:layout" + #js {:penpot:layout (d/name layout) + :penpot:layout-flex-dir (d/name layout-flex-dir) + :penpot:layout-gap-type (d/name layout-gap-type) + :penpot:layout-gap-row (:row-gap layout-gap) + :penpot:layout-gap-column (:column-gap layout-gap) + :penpot:layout-wrap-type (d/name layout-wrap-type) + :penpot:layout-padding-type (d/name layout-padding-type) + :penpot:layout-padding-p1 (:p1 layout-padding) + :penpot:layout-padding-p2 (:p2 layout-padding) + :penpot:layout-padding-p3 (:p3 layout-padding) + :penpot:layout-padding-p4 (:p4 layout-padding) + :penpot:layout-justify-content (d/name layout-justify-content) + :penpot:layout-align-items (d/name layout-align-items) + :penpot:layout-align-content (d/name layout-align-content)}]))) + +(defn- export-layout-item-data + [{:keys [layout-item-margin + layout-item-margin-type + layout-item-h-sizing + layout-item-v-sizing + layout-item-max-h + layout-item-min-h + layout-item-max-w + layout-item-min-w + layout-item-align-self]}] + + (when (or layout-item-margin + layout-item-margin-type + layout-item-h-sizing + layout-item-v-sizing + layout-item-max-h + layout-item-min-h + layout-item-max-w + layout-item-min-w + layout-item-align-self) + (mf/html + [:> "penpot:layout-item" + #js {:penpot:layout-item-margin-m1 (:m1 layout-item-margin) + :penpot:layout-item-margin-m2 (:m2 layout-item-margin) + :penpot:layout-item-margin-m3 (:m3 layout-item-margin) + :penpot:layout-item-margin-m4 (:m4 layout-item-margin) + :penpot:layout-item-margin-type (d/name layout-item-margin-type) + :penpot:layout-item-h-sizing (d/name layout-item-h-sizing) + :penpot:layout-item-v-sizing (d/name layout-item-v-sizing) + :penpot:layout-item-max-h layout-item-max-h + :penpot:layout-item-min-h layout-item-min-h + :penpot:layout-item-max-w layout-item-max-w + :penpot:layout-item-min-w layout-item-min-w + :penpot:layout-item-align-self (d/name layout-item-align-self)}]))) + + (mf/defc export-data [{:keys [shape]}] (let [props (-> (obj/create) (add-data shape) (add-library-refs shape))] [:> "penpot:shape" props - (export-shadow-data shape) - (export-blur-data shape) - (export-exports-data shape) - (export-svg-data shape) - (export-interactions-data shape) - (export-fills-data shape) - (export-strokes-data shape) - (export-grid-data shape)])) + (export-shadow-data shape) + (export-blur-data shape) + (export-exports-data shape) + (export-svg-data shape) + (export-interactions-data shape) + (export-fills-data shape) + (export-strokes-data shape) + (export-grid-data shape) + (export-layout-container-data shape) + (export-layout-item-data shape)])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs index fe63d9831c..bb1d404723 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs @@ -382,7 +382,6 @@ on-padding-change (fn [type prop val] - (prn "??" type prop val) (cond (and (= type :simple) (= prop :p1)) (st/emit! (dwsl/update-layout ids {:layout-padding {:p1 val :p3 val}})) diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index e144ed7312..e6888a28ed 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -11,6 +11,7 @@ [app.common.data.macros :as dm] [app.common.geom.shapes :as gsh] [app.common.pages.helpers :as cph] + [app.common.types.shape.layout :as ctl] [app.main.refs :as refs] [app.main.ui.context :as ctx] [app.main.ui.hooks :as ui-hooks] @@ -293,14 +294,25 @@ :modifiers modifiers}]) (when show-frame-outline? - [:& outline/shape-outlines - {:objects objects-modified - :hover #{(->> @hover-ids - (filter #(cph/frame-shape? (get base-objects %))) - (remove selected) - (first))} - :zoom zoom - :modifiers modifiers}]) + (let [outlined-frame-id + (->> @hover-ids + (filter #(cph/frame-shape? (get base-objects %))) + (remove selected) + (first)) + outlined-frame (get objects outlined-frame-id)] + [:* + [:& outline/shape-outlines + {:objects objects-modified + :hover #{outlined-frame-id} + :zoom zoom + :modifiers modifiers}] + + (when (ctl/layout? outlined-frame) + [:g.ghost-outline + [:& outline/shape-outlines + {:objects base-objects + :selected selected + :zoom zoom}]])])) (when show-outlines? [:& outline/shape-outlines diff --git a/frontend/src/app/main/ui/workspace/viewport/debug.cljs b/frontend/src/app/main/ui/workspace/viewport/debug.cljs index b8079c324f..845e38ca41 100644 --- a/frontend/src/app/main/ui/workspace/viewport/debug.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/debug.cljs @@ -75,8 +75,8 @@ points [start-p (-> start-p (gpt/add (xv line-width))) (-> start-p (gpt/add (xv line-width)) (gpt/add (yv line-height))) - (-> start-p (gpt/add (yv line-height))) - ]] + (-> start-p (gpt/add (yv line-height)))]] + [:g.layout-line {:key (dm/str "line-" idx)} [:polygon {:points (->> points (map #(dm/fmt "%, %" (:x %) (:y %))) (str/join " ")) :style {:stroke "red" :stroke-width (/ 2 zoom) :stroke-dasharray (dm/str (/ 10 zoom) " " (/ 5 zoom))}}]]))])))) diff --git a/frontend/src/app/util/import/parser.cljs b/frontend/src/app/util/import/parser.cljs index 34479481ef..cd908e1123 100644 --- a/frontend/src/app/util/import/parser.cljs +++ b/frontend/src/app/util/import/parser.cljs @@ -869,6 +869,54 @@ :style parse-style)))) +(defn add-layout-container-data [props node] + (if-let [data (get-data node :penpot:layout)] + (merge props + (d/without-nils + {:layout (get-meta data :layout keyword) + :layout-flex-dir (get-meta data :layout-flex-dir keyword) + :layout-wrap-type (get-meta data :layout-wrap-type keyword) + + :layout-gap-type (get-meta data :layout-gap-type keyword) + :layout-gap + (d/without-nils + {:row-gap (get-meta data :layout-gap-row d/parse-double) + :column-gap (get-meta data :layout-gap-column d/parse-double)}) + + :layout-padding-type (get-meta data :layout-padding-type keyword) + :layout-padding + (d/without-nils + {:p1 (get-meta data :layout-padding-p1 d/parse-double) + :p2 (get-meta data :layout-padding-p2 d/parse-double) + :p3 (get-meta data :layout-padding-p3 d/parse-double) + :p4 (get-meta data :layout-padding-p4 d/parse-double)}) + + :layout-justify-content (get-meta data :layout-justify-content keyword) + :layout-align-items (get-meta data :layout-align-items keyword) + :layout-align-content (get-meta data :layout-align-content keyword)})) + props)) + +(defn add-layout-item-data [props node] + (if-let [data (get-data node :penpot:layout-item)] + (merge props + (d/without-nils + {:layout-item-margin + (d/without-nils + {:m1 (get-meta data :layout-item-margin-m1 d/parse-double) + :m2 (get-meta data :layout-item-margin-m2 d/parse-double) + :m3 (get-meta data :layout-item-margin-m3 d/parse-double) + :m4 (get-meta data :layout-item-margin-m4 d/parse-double)}) + + :layout-item-margin-type (get-meta data :layout-item-margin-type keyword) + :layout-item-h-sizing (get-meta data :layout-item-h-sizing keyword) + :layout-item-v-sizing (get-meta data :layout-item-v-sizing keyword) + :layout-item-max-h (get-meta data :layout-item-max-h d/parse-double) + :layout-item-min-h (get-meta data :layout-item-min-h d/parse-double) + :layout-item-max-w (get-meta data :layout-item-max-w d/parse-double) + :layout-item-min-w (get-meta data :layout-item-min-w d/parse-double) + :layout-item-align-self (get-meta data :layout-item-align-self keyword)})) + props)) + (defn parse-data [type node] @@ -894,7 +942,10 @@ (add-svg-content node)) (cond-> (= :frame type) - (add-frame-data node)) + (-> (add-frame-data node) + (add-layout-container-data node))) + + (add-layout-item-data node) (cond-> (= :group type) (add-group-data node))