From 5050c352573274fe760e6519bd5d3405e6e12a77 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Tue, 6 Sep 2022 13:19:19 +0200 Subject: [PATCH 01/36] :sparkles: Adds layout items options --- common/src/app/common/pages/common.cljc | 134 +++++++++- .../sidebar/options/menus/layout_item.cljs | 3 +- .../sidebar/options/shapes/multiple.cljs | 230 ++++++++++-------- 3 files changed, 248 insertions(+), 119 deletions(-) diff --git a/common/src/app/common/pages/common.cljc b/common/src/app/common/pages/common.cljc index 181cf32cf..3a47fdcd5 100644 --- a/common/src/app/common/pages/common.cljc +++ b/common/src/app/common/pages/common.cljc @@ -71,7 +71,26 @@ :constraints-h :constraints-group :constraints-v :constraints-group :fixed-scroll :constraints-group - :exports :exports-group}) + :exports :exports-group + + :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 + :layout-h-orientation :layout-container + :layout-v-orientation :layout-container + + :layout-margin :layout-item + :layout-margin-type :layout-item + :layout-h-behavior :layout-item + :layout-v-behavior :layout-item + :layout-max-h :layout-item + :layout-min-h :layout-item + :layout-max-w :layout-item + :layout-min-w :layout-item}) ;; Attributes that may directly be edited by the user with forms (def editable-attrs @@ -111,10 +130,29 @@ :stroke-cap-start :stroke-cap-end - :exports} + :exports - :group #{:proportion-lock - :width :height + :layout + :layout-dir + :layout-gap + :layout-type + :layout-wrap-type + :layout-padding-type + :layout-padding + :layout-h-orientation + :layout-v-orientation + + :layout-margin + :layout-margin-type + :layout-h-behavior + :layout-v-behavior + :layout-max-h + :layout-min-h + :layout-max-w + :layout-min-w} + + :group #{:proportion-lock + :width :height :x :y :rotation :selrect @@ -135,7 +173,16 @@ :blur - :exports} + :exports + + :layout-margin + :layout-margin-type + :layout-h-behavior + :layout-v-behavior + :layout-max-h + :layout-min-h + :layout-max-w + :layout-min-w} :rect #{:proportion-lock :width :height @@ -180,7 +227,16 @@ :blur - :exports} + :exports + + :layout-margin + :layout-margin-type + :layout-h-behavior + :layout-v-behavior + :layout-max-h + :layout-min-h + :layout-max-w + :layout-min-w} :circle #{:proportion-lock :width :height @@ -223,7 +279,16 @@ :blur - :exports} + :exports + + :layout-margin + :layout-margin-type + :layout-h-behavior + :layout-v-behavior + :layout-max-h + :layout-min-h + :layout-max-w + :layout-min-w} :path #{:proportion-lock :width :height @@ -266,7 +331,16 @@ :blur - :exports} + :exports + + :layout-margin + :layout-margin-type + :layout-h-behavior + :layout-v-behavior + :layout-max-h + :layout-min-h + :layout-max-w + :layout-min-w} :text #{:proportion-lock :width :height @@ -332,7 +406,16 @@ :grow-type - :exports} + :exports + + :layout-margin + :layout-margin-type + :layout-h-behavior + :layout-v-behavior + :layout-max-h + :layout-min-h + :layout-max-w + :layout-min-w} :image #{:proportion-lock :width :height @@ -358,7 +441,16 @@ :blur - :exports} + :exports + + :layout-margin + :layout-margin-type + :layout-h-behavior + :layout-v-behavior + :layout-max-h + :layout-min-h + :layout-max-w + :layout-min-w} :svg-raw #{:proportion-lock :width :height @@ -403,7 +495,16 @@ :blur - :exports} + :exports + + :layout-margin + :layout-margin-type + :layout-h-behavior + :layout-v-behavior + :layout-max-h + :layout-min-h + :layout-max-w + :layout-min-w} :bool #{:proportion-lock :width :height @@ -446,5 +547,14 @@ :blur - :exports}}) + :exports + + :layout-margin + :layout-margin-type + :layout-h-behavior + :layout-v-behavior + :layout-max-h + :layout-min-h + :layout-max-w + :layout-min-w}}) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs index 78b9ccbd4..d27cb93a5 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs @@ -136,7 +136,8 @@ (mf/defc layout-item-menu {::mf/wrap [#(mf/memo' % (mf/check-props ["ids" "values" "type"]))]} - [{:keys [ids _type values is-layout-child? is-layout-container?] :as props}] + [{:keys [ids values is-layout-child? is-layout-container?] :as props}] + (let [open? (mf/use-state false) toggle-open (fn [] (swap! open? not)) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs index 09a34eb25..17f5f7051 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs @@ -34,116 +34,134 @@ ;; - text: read it from all the content nodes, and then merging it. (def type->read-mode {:frame - {:measure :shape - :layer :shape - :constraint :shape - :fill :shape - :shadow :children - :blur :children - :stroke :shape - :text :children - :exports :shape} + {:measure :shape + :layer :shape + :constraint :shape + :fill :shape + :shadow :children + :blur :children + :stroke :shape + :text :children + :exports :shape + :layout-container :shape + :layout-item :shape} :group - {:measure :shape - :layer :shape - :constraint :shape - :fill :children - :shadow :shape - :blur :shape - :stroke :children - :text :children - :exports :shape} + {:measure :shape + :layer :shape + :constraint :shape + :fill :children + :shadow :shape + :blur :shape + :stroke :children + :text :children + :exports :shape + :layout-container :ignore + :layout-item :shape} :path - {:measure :shape - :layer :shape - :constraint :shape - :fill :shape - :shadow :shape - :blur :shape - :stroke :shape - :text :ignore - :exports :shape} + {:measure :shape + :layer :shape + :constraint :shape + :fill :shape + :shadow :shape + :blur :shape + :stroke :shape + :text :ignore + :exports :shape + :layout-container :ignore + :layout-item :shape} :text - {:measure :shape - :layer :shape - :constraint :shape - :fill :text - :shadow :shape - :blur :shape - :stroke :shape - :text :text - :exports :shape} + {:measure :shape + :layer :shape + :constraint :shape + :fill :text + :shadow :shape + :blur :shape + :stroke :shape + :text :text + :exports :shape + :layout-container :ignore + :layout-item :shape} :image - {:measure :shape - :layer :shape - :constraint :shape - :fill :ignore - :shadow :shape - :blur :shape - :stroke :ignore - :text :ignore - :exports :shape} + {:measure :shape + :layer :shape + :constraint :shape + :fill :ignore + :shadow :shape + :blur :shape + :stroke :ignore + :text :ignore + :exports :shape + :layout-container :ignore + :layout-item :shape} :rect - {:measure :shape - :layer :shape - :constraint :shape - :fill :shape - :shadow :shape - :blur :shape - :stroke :shape - :text :ignore - :exports :shape} + {:measure :shape + :layer :shape + :constraint :shape + :fill :shape + :shadow :shape + :blur :shape + :stroke :shape + :text :ignore + :exports :shape + :layout-container :ignore + :layout-item :shape} :circle - {:measure :shape - :layer :shape - :constraint :shape - :fill :shape - :shadow :shape - :blur :shape - :stroke :shape - :text :ignore - :exports :shape} + {:measure :shape + :layer :shape + :constraint :shape + :fill :shape + :shadow :shape + :blur :shape + :stroke :shape + :text :ignore + :exports :shape + :layout-container :ignore + :layout-item :shape} :svg-raw - {:measure :shape - :layer :shape - :constraint :shape - :fill :shape - :shadow :shape - :blur :shape - :stroke :shape - :text :ignore - :exports :shape} + {:measure :shape + :layer :shape + :constraint :shape + :fill :shape + :shadow :shape + :blur :shape + :stroke :shape + :text :ignore + :exports :shape + :layout-container :ignore + :layout-item :shape} :bool - {:measure :shape - :layer :shape - :constraint :shape - :fill :shape - :shadow :shape - :blur :shape - :stroke :shape - :text :ignore - :exports :shape}}) + {:measure :shape + :layer :shape + :constraint :shape + :fill :shape + :shadow :shape + :blur :shape + :stroke :shape + :text :ignore + :exports :shape + :layout-container :ignore + :layout-item :shape}}) (def group->attrs - {:measure measure-attrs - :layer layer-attrs - :constraint constraint-attrs - :fill fill-attrs - :shadow shadow-attrs - :blur blur-attrs - :stroke stroke-attrs - :text ot/attrs - :exports exports-attrs - :layout layout-container-flex-attrs - :layout-item layout-item-attrs}) + {:measure measure-attrs + :layer layer-attrs + :constraint constraint-attrs + :fill fill-attrs + :shadow shadow-attrs + :blur blur-attrs + :stroke stroke-attrs + :text ot/attrs + :exports exports-attrs + :layout-container layout-container-flex-attrs + :layout-item layout-item-attrs}) (def shadow-keys [:style :color :offset-x :offset-y :blur :spread]) @@ -254,20 +272,20 @@ is-layout-child? (mf/deref is-layout-child-ref) has-text? (contains? all-types :text) - + [measure-ids measure-values] (get-attrs shapes objects :measure) - [layer-ids layer-values - constraint-ids constraint-values - fill-ids fill-values - shadow-ids shadow-values - blur-ids blur-values - stroke-ids stroke-values - text-ids text-values - exports-ids exports-values - layout-ids layout-container-values - layout-item-ids layout-item-values] + [layer-ids layer-values + constraint-ids constraint-values + fill-ids fill-values + shadow-ids shadow-values + blur-ids blur-values + stroke-ids stroke-values + text-ids text-values + exports-ids exports-values + layout-container-ids layout-container-values + layout-item-ids layout-item-values] (mf/use-memo (mf/deps objects-no-measures) (fn [] @@ -282,7 +300,7 @@ (get-attrs shapes objects-no-measures :stroke) (get-attrs shapes objects-no-measures :text) (get-attrs shapes objects-no-measures :exports) - (get-attrs shapes objects-no-measures :layout) + (get-attrs shapes objects-no-measures :layout-container) (get-attrs shapes objects-no-measures :layout-item) ])))] @@ -291,8 +309,8 @@ [:& measures-menu {:type type :all-types all-types :ids measure-ids :values measure-values :shape shapes}]) (when (:layout layout-container-values) - [:& layout-container-menu {:type type :ids layout-ids :values layout-container-values}]) - + [:& layout-container-menu {:type type :ids layout-container-ids :values layout-container-values}]) + (when is-layout-child? [:& layout-item-menu {:type type From c01c46041d4a6e0304f20477d8b7ae1ac3b8e27f Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 29 Sep 2022 13:37:54 +0200 Subject: [PATCH 02/36] :sparkles: Adds autolayout positions calculations --- common/src/app/common/geom/matrix.cljc | 11 + common/src/app/common/geom/shapes.cljc | 10 +- .../app/common/geom/shapes/constraints.cljc | 312 ++++++++++------ .../src/app/common/geom/shapes/intersect.cljc | 22 ++ common/src/app/common/geom/shapes/layout.cljc | 76 +++- .../src/app/common/geom/shapes/modifiers.cljc | 164 +++++---- .../app/common/geom/shapes/transforms.cljc | 343 ++++++------------ common/src/app/common/pages/migrations.cljc | 8 +- common/src/app/common/types/modifiers.cljc | 256 +++++++++++++ .../src/app/main/data/workspace/comments.cljs | 4 +- .../app/main/data/workspace/drawing/box.cljs | 5 +- .../main/data/workspace/drawing/common.cljs | 9 +- .../src/app/main/data/workspace/guides.cljs | 3 +- .../app/main/data/workspace/shape_layout.cljs | 2 +- .../main/data/workspace/state_helpers.cljs | 7 +- .../src/app/main/data/workspace/texts.cljs | 23 +- .../app/main/data/workspace/transforms.cljs | 81 +++-- frontend/src/app/main/render.cljs | 44 +-- frontend/src/app/main/ui/shapes/bool.cljs | 4 +- frontend/src/app/main/ui/shapes/mask.cljs | 7 +- .../app/main/ui/viewer/handoff/render.cljs | 5 +- .../src/app/main/ui/viewer/interactions.cljs | 9 +- frontend/src/app/main/ui/viewer/shapes.cljs | 5 +- .../shapes/frame/dynamic_modifiers.cljs | 11 +- .../app/main/ui/workspace/shapes/text.cljs | 2 +- .../shapes/text/viewport_texts_html.cljs | 6 +- .../main/ui/workspace/sidebar/options.cljs | 4 +- .../src/app/main/ui/workspace/viewport.cljs | 17 +- .../main/ui/workspace/viewport/drawarea.cljs | 5 +- .../main/ui/workspace/viewport/guides.cljs | 2 +- .../ui/workspace/viewport/interactions.cljs | 7 +- .../main/ui/workspace/viewport/outline.cljs | 2 +- .../main/ui/workspace/viewport/selection.cljs | 21 +- .../ui/workspace/viewport/snap_points.cljs | 23 +- .../app/main/ui/workspace/viewport/utils.cljs | 4 +- .../main/ui/workspace/viewport/widgets.cljs | 11 +- frontend/src/app/util/geom/snap_points.cljs | 7 +- 37 files changed, 938 insertions(+), 594 deletions(-) create mode 100644 common/src/app/common/types/modifiers.cljc diff --git a/common/src/app/common/geom/matrix.cljc b/common/src/app/common/geom/matrix.cljc index e4448acb7..53f3d1748 100644 --- a/common/src/app/common/geom/matrix.cljc +++ b/common/src/app/common/geom/matrix.cljc @@ -252,3 +252,14 @@ (update :d mth/precision 4) (update :e mth/precision 4) (update :f mth/precision 4))) + +(defn transform-point-center + "Transform a point around the shape center" + [point center matrix] + (if (and (some? point) (some? matrix) (some? center)) + (gpt/transform + point + (multiply (translate-matrix center) + matrix + (translate-matrix (gpt/negate center)))) + point)) diff --git a/common/src/app/common/geom/shapes.cljc b/common/src/app/common/geom/shapes.cljc index d0d05d47f..a217d5322 100644 --- a/common/src/app/common/geom/shapes.cljc +++ b/common/src/app/common/geom/shapes.cljc @@ -28,7 +28,7 @@ rotation of each shape. Mainly used for multiple selection." [shapes] (->> shapes - (map (comp gpr/points->selrect :points gtr/transform-shape)) + (map (comp gpr/points->selrect :points)) (gpr/join-selrects))) (defn translate-to-frame @@ -166,23 +166,17 @@ (dm/export gtr/transform-matrix) (dm/export gtr/transform-str) (dm/export gtr/inverse-transform-matrix) -(dm/export gtr/transform-point-center) (dm/export gtr/transform-rect) (dm/export gtr/calculate-adjust-matrix) (dm/export gtr/update-group-selrect) (dm/export gtr/update-mask-selrect) -(dm/export gtr/resize-modifiers) -(dm/export gtr/change-orientation-modifiers) -(dm/export gtr/rotation-modifiers) -(dm/export gtr/merge-modifiers) (dm/export gtr/transform-shape) (dm/export gtr/transform-selrect) (dm/export gtr/transform-selrect-matrix) (dm/export gtr/transform-bounds) -(dm/export gtr/modifiers->transform) -(dm/export gtr/empty-modifiers?) (dm/export gtr/move-position-data) (dm/export gtr/apply-transform) +(dm/export gtr/apply-objects-modifiers) ;; Constratins (dm/export gct/calc-child-modifiers) diff --git a/common/src/app/common/geom/shapes/constraints.cljc b/common/src/app/common/geom/shapes/constraints.cljc index 79821b364..49db8a69d 100644 --- a/common/src/app/common/geom/shapes/constraints.cljc +++ b/common/src/app/common/geom/shapes/constraints.cljc @@ -6,14 +6,19 @@ (ns app.common.geom.shapes.constraints (:require - [app.common.geom.matrix :as gmt] + [app.common.data :as d] [app.common.geom.point :as gpt] [app.common.geom.shapes.common :as gco] + [app.common.geom.shapes.intersect :as gsi] [app.common.geom.shapes.rect :as gre] + [app.common.geom.shapes.transforms :as gst] [app.common.math :as mth] [app.common.uuid :as uuid])) ;; Auxiliary methods to work in an specifica axis +(defn other-axis [axis] + (if (= :x axis) :y :x)) + (defn get-delta-start [axis rect tr-rect] (if (= :x axis) (- (:x1 tr-rect) (:x1 rect)) @@ -29,6 +34,11 @@ (- (:width tr-rect) (:width rect)) (- (:height tr-rect) (:height rect)))) +(defn get-delta-scale [axis rect tr-rect] + (if (= :x axis) + (/ (:width tr-rect) (:width rect)) + (/ (:height tr-rect) (:height rect)))) + (defn get-delta-center [axis center tr-center] (if (= :x axis) (- (:x tr-center) (:x center)) @@ -53,78 +63,138 @@ (:width rect) (:height rect))) +(defn right-vector + [child-points parent-points] + (let [[p0 p1 p2 _] parent-points + [_c0 c1 _ _] child-points + dir-v (gpt/to-vec p0 p1) + cp (gsi/line-line-intersect c1 (gpt/add c1 dir-v) p1 p2)] + (gpt/to-vec c1 cp))) + +(defn left-vector + [child-points parent-points] + + (let [[p0 p1 _ p3] parent-points + [_ _ _ c3] child-points + dir-v (gpt/to-vec p0 p1) + cp (gsi/line-line-intersect c3 (gpt/add c3 dir-v) p0 p3)] + (gpt/to-vec c3 cp))) + + +(defn top-vector + [child-points parent-points] + + (let [[p0 p1 _ p3] parent-points + [c0 _ _ _] child-points + dir-v (gpt/to-vec p0 p3) + cp (gsi/line-line-intersect c0 (gpt/add c0 dir-v) p0 p1)] + (gpt/to-vec c0 cp))) + +(defn bottom-vector + [child-points parent-points] + + (let [[p0 _ p2 p3] parent-points + [_ _ c2 _] child-points + dir-v (gpt/to-vec p0 p3) + cp (gsi/line-line-intersect c2 (gpt/add c2 dir-v) p2 p3)] + (gpt/to-vec c2 cp))) + +(defn center-horizontal-vector + [child-points parent-points] + + (let [[p0 p1 _ p3] parent-points + [_ c1 _ _] child-points + + dir-v (gpt/to-vec p0 p1) + + p1c (gpt/add p0 (gpt/scale dir-v 0.5)) + p2c (gpt/add p3 (gpt/scale dir-v 0.5)) + + cp (gsi/line-line-intersect c1 (gpt/add c1 dir-v) p1c p2c)] + + (gpt/to-vec c1 cp))) + +(defn center-vertical-vector + [child-points parent-points] + (let [[p0 p1 p2 _] parent-points + [_ c1 _ _] child-points + + dir-v (gpt/to-vec p1 p2) + + p3c (gpt/add p0 (gpt/scale dir-v 0.5)) + p2c (gpt/add p1 (gpt/scale dir-v 0.5)) + + cp (gsi/line-line-intersect c1 (gpt/add c1 dir-v) p3c p2c)] + + (gpt/to-vec c1 cp))) + +(defn start-vector + [axis child-points parent-points] + ((if (= :x axis) left-vector top-vector) child-points parent-points)) + +(defn end-vector + [axis child-points parent-points] + ((if (= :x axis) right-vector bottom-vector) child-points parent-points)) + +(defn center-vector + [axis child-points parent-points] + ((if (= :x axis) center-horizontal-vector center-vertical-vector) child-points parent-points)) + + ;; Constraint function definitions (defmulti constraint-modifier (fn [type & _] type)) -(defmethod constraint-modifier :start - [_ axis parent _ _ transformed-parent-rect] - - (let [parent-rect (:selrect parent) - delta-start (get-delta-start axis parent-rect transformed-parent-rect)] - (if-not (mth/almost-zero? delta-start) - {:displacement (get-displacement axis delta-start)} - {}))) - (defmethod constraint-modifier :end - [_ axis parent _ _ transformed-parent-rect] - (let [parent-rect (:selrect parent) - delta-end (get-delta-end axis parent-rect transformed-parent-rect)] - (if-not (mth/almost-zero? delta-end) - {:displacement (get-displacement axis delta-end)} - {}))) + [_ axis child-points-before parent-points-before child-points-after parent-points-after] + (let [end-before (end-vector axis child-points-before parent-points-before) + end-after (end-vector axis child-points-after parent-points-after) + end-angl (gpt/angle-with-other end-before end-after) + target-end (if (mth/close? end-angl 180) (- (gpt/length end-before)) (gpt/length end-before)) + disp-vector-end (gpt/subtract end-after (gpt/scale (gpt/unit end-after) target-end))] + [{:type :move + :vector disp-vector-end}])) (defmethod constraint-modifier :fixed - [_ axis parent child _ transformed-parent-rect] - (let [parent-rect (:selrect parent) - child-rect (gre/points->rect (:points child)) + [_ axis child-points-before parent-points-before child-points-after parent-points-after transformed-parent] + (let [[c0 c1 _ c4] child-points-after - delta-start (get-delta-start axis parent-rect transformed-parent-rect) - delta-size (get-delta-size axis parent-rect transformed-parent-rect) - child-size (get-size axis child-rect)] - (if (or (not (mth/almost-zero? delta-start)) - (not (mth/almost-zero? delta-size))) + ;; Same as constraint end + end-before (end-vector axis child-points-before parent-points-before) + end-after (end-vector axis child-points-after parent-points-after) + end-angl (gpt/angle-with-other end-before end-after) + target-end (if (mth/close? end-angl 180) (- (gpt/length end-before)) (gpt/length end-before)) + disp-vector-end (gpt/subtract end-after (gpt/scale (gpt/unit end-after) target-end)) - {:displacement (get-displacement axis delta-start) - :resize-origin (get-displacement axis delta-start (:x child-rect) (:y child-rect)) - :resize-vector (get-scale axis (/ (+ child-size delta-size) child-size))} - {}))) + before-vec (if (= axis :x) (gpt/to-vec c0 c1) (gpt/to-vec c0 c4)) + after-vec (if (= axis :x) + (gpt/to-vec c0 (gpt/add c1 disp-vector-end)) + (gpt/to-vec c0 (gpt/add c4 disp-vector-end)) + ) + + resize-angl (gpt/angle-with-other before-vec after-vec) + resize-sign (if (mth/close? resize-angl 180) -1 1) + + scale (* resize-sign (/ (gpt/length after-vec) (gpt/length before-vec))) + ] + [{:type :resize + :vector (get-scale axis scale) + :origin c0 + :transform (:transform transformed-parent) + :transform-inverse (:transform-inverse transformed-parent)}])) (defmethod constraint-modifier :center - [_ axis parent _ _ transformed-parent-rect] - (let [parent-rect (:selrect parent) - parent-center (gco/center-rect parent-rect) - transformed-parent-center (gco/center-rect transformed-parent-rect) - delta-center (get-delta-center axis parent-center transformed-parent-center)] - (if-not (mth/almost-zero? delta-center) - {:displacement (get-displacement axis delta-center)} - {}))) - -(defmethod constraint-modifier :scale - [_ axis _ _ modifiers _] - (let [{:keys [resize-vector resize-vector-2 displacement]} modifiers] - (cond-> {} - (and (some? resize-vector) - (not= (axis resize-vector) 1)) - (assoc :resize-origin (:resize-origin modifiers) - :resize-vector (if (= :x axis) - (gpt/point (:x resize-vector) 1) - (gpt/point 1 (:y resize-vector)))) - - (and (= :y axis) (some? resize-vector-2) - (not (mth/close? (:y resize-vector-2) 1))) - (assoc :resize-origin (:resize-origin-2 modifiers) - :resize-vector (gpt/point 1 (:y resize-vector-2))) - - (some? displacement) - (assoc :displacement - (get-displacement axis (-> (gpt/point 0 0) - (gpt/transform displacement) - (gpt/transform (:resize-transform-inverse modifiers (gmt/matrix))) - axis)))))) + [_ axis child-points-before parent-points-before child-points-after parent-points-after] + (let [center-before (center-vector axis child-points-before parent-points-before) + center-after (center-vector axis child-points-after parent-points-after) + center-angl (gpt/angle-with-other center-before center-after) + target-center (if (mth/close? center-angl 180) (- (gpt/length center-before)) (gpt/length center-before)) + disp-vector-center (gpt/subtract center-after (gpt/scale (gpt/unit center-after) target-center))] + [{:type :move + :vector disp-vector-center}])) (defmethod constraint-modifier :default [_ _ _ _ _] - {}) + []) (def const->type+axis {:left :start @@ -152,7 +222,7 @@ :top :scale))) -(defn clean-modifiers +#_(defn clean-modifiers "Remove redundant modifiers" [{:keys [displacement resize-vector resize-vector-2] :as modifiers}] @@ -174,55 +244,91 @@ (mth/almost-zero? (- 1.0 (:y resize-vector-2)))) (dissoc :resize-origin-2 :resize-vector-2))) + +(defn bounding-box-parent-transform + "Returns a bounding box for the child in the same coordinate system + as the parent. + Returns a points array" + [child parent] + (-> child + :points + (gco/transform-points (:transform-inverse parent)) + (gre/points->rect) + (gre/rect->points) ;; Restore to points so we can transform them + (gco/transform-points (:transform parent)))) + +(defn normalize-modifiers + "Before aplying constraints we need to remove the deformation caused by the resizing of the parent" + [constraints-h constraints-v modifiers child parent transformed-child transformed-parent] + + (let [child-bb-before + (-> child + :points + (gco/transform-points (:transform-inverse parent)) + (gre/points->rect)) + + child-bb-after + (-> transformed-child + :points + (gco/transform-points (:transform-inverse transformed-parent)) + (gre/points->rect)) + + scale-x (/ (:width child-bb-before) (:width child-bb-after)) + scale-y (/ (:height child-bb-before) (:height child-bb-after))] + + (-> modifiers + (update :v2 #(cond-> % + (not= :scale constraints-h) + (conj + ;; This resize will leave the shape in its original position relative to the parent + {:type :resize + :transform (:transform transformed-parent) + :transform-inverse (:transform-inverse transformed-parent) + :origin (-> transformed-parent :points (nth 0)) + :vector (gpt/point scale-x 1)}) + + (not= :scale constraints-v) + (conj + {:type :resize + :transform (:transform transformed-parent) + :transform-inverse (:transform-inverse transformed-parent) + :origin (-> transformed-parent :points (nth 0)) + :vector (gpt/point 1 scale-y)})))))) + (defn calc-child-modifiers - [parent child modifiers ignore-constraints transformed-parent-rect] + [parent child modifiers ignore-constraints transformed-parent] - (if (and (nil? (:resize-vector modifiers)) - (nil? (:resize-vector-2 modifiers))) - ;; If we don't have a resize modifier we return the same modifiers - modifiers - (let [constraints-h - (if-not ignore-constraints - (:constraints-h child (default-constraints-h child)) - :scale) + (let [constraints-h + (if-not ignore-constraints + (:constraints-h child (default-constraints-h child)) + :scale) - constraints-v - (if-not ignore-constraints - (:constraints-v child (default-constraints-v child)) - :scale) + constraints-v + (if-not ignore-constraints + (:constraints-v child (default-constraints-v child)) + :scale)] - modifiers-h (constraint-modifier (constraints-h const->type+axis) :x parent child modifiers transformed-parent-rect) - modifiers-v (constraint-modifier (constraints-v const->type+axis) :y parent child modifiers transformed-parent-rect)] + (if (and (= :scale constraints-h) (= :scale constraints-v)) + modifiers - ;; 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. - (cond-> {} - (some? (:displacement-after modifiers)) - (assoc :displacement-after (:displacement-after modifiers)) + (let [transformed-child (gst/transform-shape child modifiers) + modifiers (normalize-modifiers constraints-h constraints-v modifiers child parent transformed-child transformed-parent) - (or (contains? modifiers-h :displacement) - (contains? modifiers-v :displacement)) - (assoc :displacement (cond-> (gpt/point (get-in modifiers-h [:displacement :x] 0) - (get-in modifiers-v [:displacement :y] 0)) - (some? (:resize-transform modifiers)) - (gpt/transform (:resize-transform modifiers)) + tranformed-child-2 (gst/transform-shape child modifiers) + parent-points-before (:points parent) + child-points-before (bounding-box-parent-transform child parent) - :always - (gmt/translate-matrix))) + parent-points-after (:points transformed-parent) + child-points-after (bounding-box-parent-transform tranformed-child-2 transformed-parent) - (:resize-vector modifiers-h) - (assoc :resize-origin (:resize-origin modifiers-h) - :resize-vector (gpt/point (get-in modifiers-h [:resize-vector :x] 1) - (get-in modifiers-h [:resize-vector :y] 1))) + modifiers-h (constraint-modifier (constraints-h const->type+axis) :x + child-points-before parent-points-before + child-points-after parent-points-after + transformed-parent) - (:resize-vector modifiers-v) - (assoc :resize-origin-2 (:resize-origin modifiers-v) - :resize-vector-2 (gpt/point (get-in modifiers-v [:resize-vector :x] 1) - (get-in modifiers-v [:resize-vector :y] 1))) + modifiers-v (constraint-modifier (constraints-v const->type+axis) :y + child-points-before parent-points-before + child-points-after parent-points-after + transformed-parent)] - (:resize-transform modifiers) - (assoc :resize-transform (:resize-transform modifiers) - :resize-transform-inverse (:resize-transform-inverse modifiers)) - - :always - (clean-modifiers))))) + (update modifiers :v2 d/concat-vec modifiers-h modifiers-v))))) diff --git a/common/src/app/common/geom/shapes/intersect.cljc b/common/src/app/common/geom/shapes/intersect.cljc index 34b5ec7f6..72d5bf47a 100644 --- a/common/src/app/common/geom/shapes/intersect.cljc +++ b/common/src/app/common/geom/shapes/intersect.cljc @@ -348,3 +348,25 @@ :points (every? (partial has-point-rect? rect)))) + +(defn line-line-intersect + "Calculates the interesection point for two lines given by the points a-b and b-c" + [a b c d] + + (let [;; Line equation representation: ax + by + c = 0 + a1 (- (:y b) (:y a)) + b1 (- (:x a) (:x b)) + c1 (+ (* a1 (:x a)) (* b1 (:y a))) + + a2 (- (:y d) (:y c)) + b2 (- (:x c) (:x d)) + c2 (+ (* a2 (:x c)) (* b2 (:y c))) + + ;; Cramer's rule + det (- (* a1 b2) (* a2 b1))] + + ;; If almost zero the lines are parallel + (when (not (mth/almost-zero? det)) + (let [x (/ (- (* b2 c1) (* b1 c2)) det) + y (/ (- (* c2 a1) (* c1 a2)) det)] + (gpt/point x y))))) diff --git a/common/src/app/common/geom/shapes/layout.cljc b/common/src/app/common/geom/shapes/layout.cljc index dc27fb429..e6f7cc70e 100644 --- a/common/src/app/common/geom/shapes/layout.cljc +++ b/common/src/app/common/geom/shapes/layout.cljc @@ -6,7 +6,6 @@ (ns app.common.geom.shapes.layout (:require - [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] [app.common.geom.shapes.rect :as gre])) @@ -71,24 +70,39 @@ (let [wrap? (= layout-wrap-type :wrap) reduce-fn - (fn [[{:keys [line-width line-height num-children] :as line-data} result] child] + (fn [[{:keys [line-width line-height num-children child-fill? num-child-fill] :as line-data} result] child] (let [child-bounds (-> child :points gre/points->rect) - next-width (-> child-bounds :width) - next-height (-> child-bounds :height)] + + 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? + 0 + (-> child-bounds :width)) + + next-height (if cur-child-fill? + 0 + (-> child-bounds :height))] (if (and (some? line-data) (or (not wrap?) (and (col? shape) (<= (+ line-width next-width (* layout-gap num-children)) width)) (and (row? shape) (<= (+ line-height next-height (* layout-gap num-children)) height)))) - [{: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)} + ;; Si autofill aƱadimos el minwidth que por defecto es 0 + [{: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?) + :num-child-fill (cond-> num-child-fill cur-child-fill? inc)} result] - [{:line-width next-width - :line-height next-height - :num-children 1} + [{:line-width next-width + :line-height next-height + :num-children 1 + :child-fill? child-fill? + :num-child-fill (if child-fill? 1 0)} (cond-> result (some? line-data) (conj line-data))]))) [line-data layout-lines] (reduce reduce-fn [nil []] children)] @@ -124,13 +138,14 @@ [base-x base-y])) (get-start-line - [{:keys [line-width line-height num-children]} base-x base-y] + [{:keys [line-width line-height num-children child-fill?]} base-x base-y] (let [children-gap (* layout-gap (dec num-children)) start-x (cond - (or (and (col? shape) (= :space-between layout-type)) + (or (and (col? shape) child-fill?) + (and (col? shape) (= :space-between layout-type)) (and (col? shape) (= :space-around layout-type))) x @@ -154,7 +169,8 @@ start-y (cond - (or (and (row? shape) (= :space-between layout-type)) + (or (and (row? shape) child-fill?) + (and (row? shape) (= :space-between layout-type)) (and (row? shape) (= :space-around layout-type))) y @@ -240,6 +256,7 @@ 0)] (assoc line-data + :layout-bounds layout-bounds :layout-gap layout-gap :margin-x margin-x :margin-y margin-y))) @@ -314,14 +331,39 @@ "Calculates the modifiers for the layout" [parent transform child layout-data] - (let [bounds (-> child :points gre/points->selrect) + (let [child-bounds (-> child :points gre/points->selrect) - [corner-p layout-data] (next-p parent bounds layout-data) + fill-space (- (-> layout-data :layout-bounds :width) (:line-width 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)) + + [corner-p layout-data] (next-p parent child-bounds layout-data) delta-p (-> corner-p - (gpt/subtract (gpt/point bounds)) + (gpt/subtract (gpt/point child-bounds)) (cond-> (some? transform) (gpt/transform transform))) - modifiers {:displacement-after (gmt/translate-matrix delta-p)}] + modifiers [] + + 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})] [modifiers layout-data])) diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index f93929abe..4645a6582 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -15,8 +15,10 @@ [app.common.geom.shapes.rect :as gpr] [app.common.geom.shapes.transforms :as gtr] [app.common.math :as mth] + [app.common.types.modifiers :as ctm] [app.common.uuid :as uuid])) +;; TODO LAYOUT: ADAPT TO NEW MODIFIERS (defn set-pixel-precision "Adjust modifiers so they adjust to the pixel grid" [modifiers shape] @@ -106,44 +108,65 @@ (defn set-children-modifiers - [modif-tree shape objects ignore-constraints snap-pixel?] - (letfn [(set-child [transformed-rect snap-pixel? modif-tree child] + [modif-tree objects shape ignore-constraints snap-pixel?] + ;; TODO LAYOUT: SNAP PIXEL! + (letfn [(set-child [transformed-parent _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)) - (update-in [(:id child) :modifiers] #(merge child-modifiers %)))))] + + child-modifiers (gct/calc-child-modifiers shape child modifiers ignore-constraints transformed-parent) + + ;;_ (.log js/console (:name child) (clj->js child-modifiers)) + + ;;child-modifiers (cond-> child-modifiers snap-pixel? (set-pixel-precision child)) + + result + (cond-> modif-tree + (not (ctm/empty-modifiers? child-modifiers)) + (update-in [(:id child) :modifiers :v2] #(d/concat-vec % (:v2 child-modifiers))) + #_(update-in [(:id child) :modifiers] #(merge-mod2 child-modifiers %)) + #_(update-in [(:id child) :modifiers] #(merge child-modifiers %))) + + ;;_ (.log js/console ">>>" (:name child)) + ;;_ (.log js/console " >" (clj->js child-modifiers)) + ;;_ (.log js/console " >" (clj->js (get-in modif-tree [(:id child) :modifiers]))) + ;;_ (.log js/console " >" (clj->js (get-in result [(:id child) :modifiers]))) + ] + result + )) + ] (let [children (map (d/getf objects) (:shapes shape)) modifiers (get-in modif-tree [(:id shape) :modifiers]) - transformed-rect (gtr/transform-selrect (:selrect shape) modifiers) + ;; transformed-rect (gtr/transform-selrect (:selrect shape) modifiers) + ;; transformed-rect (-> shape (merge {:modifiers modifiers}) gtr/transform-shape :selrect) + transformed-parent (-> shape (merge {:modifiers modifiers}) gtr/transform-shape) + resize-modif? (or (:resize-vector modifiers) (:resize-vector-2 modifiers))] - (reduce (partial set-child transformed-rect (and snap-pixel? resize-modif?)) modif-tree children)))) + (reduce (partial set-child transformed-parent (and snap-pixel? resize-modif?)) modif-tree children)))) (defn group? [shape] (or (= :group (:type shape)) (= :bool (:type shape)))) -(defn merge-modifiers - [modif-tree ids modifiers] - (reduce - (fn [modif-tree id] - (update-in modif-tree [id :modifiers] #(merge % modifiers))) - modif-tree - ids)) +(defn frame? [shape] + (= :frame (:type shape))) + +(defn layout? [shape] + (and (frame? shape) + (:layout shape))) (defn set-layout-modifiers - [modif-tree objects id] + ;; TODO LAYOUT: SNAP PIXEL! + [modif-tree objects parent _snap-pixel?] - (letfn [(transform-child [parent child] + (letfn [(transform-child [child] (let [modifiers (get modif-tree (:id child)) child (cond-> child - (not (group? child)) + (some? modifiers) (-> (merge modifiers) gtr/transform-shape) - (group? child) + (and (nil? modifiers) (group? child)) (gtr/apply-group-modifiers objects modif-tree)) child @@ -158,22 +181,17 @@ modif-tree (cond-> modif-tree - (not (gtr/empty-modifiers? modifiers)) - (merge-modifiers [(:id child)] modifiers) - - (and (not (gtr/empty-modifiers? modifiers)) (group? child)) - (merge-modifiers (:shapes child) modifiers))] + (d/not-empty? modifiers) + (update-in [(:id child) :modifiers :v2] d/concat-vec modifiers) + #_(merge-modifiers [(:id child)] modifiers))] [layout-data modif-tree]))] - (let [modifiers (get modif-tree id) - - shape (-> (get objects id) (merge modifiers) gtr/transform-shape) - - + (let [modifiers (get modif-tree (:id parent)) + shape (-> parent (merge modifiers) gtr/transform-shape) children (->> (:shapes shape) (map (d/getf objects)) - (map (partial transform-child shape))) + (map transform-child)) center (gco/center-shape shape) {:keys [transform transform-inverse]} shape @@ -230,6 +248,17 @@ :else (recur (:id parent) result))))) +(defn resolve-tree-sequence + ;; TODO LAYOUT: Esta ahora puesto al zero pero tiene que mirar todas las raices + "Given the ids that have changed search for layout roots to recalculate" + [_ids objects] + (->> (tree-seq + #(d/not-empty? (get-in objects [% :shapes])) + #(get-in objects [% :shapes]) + uuid/zero) + + (map #(get objects %)))) + (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" @@ -239,6 +268,28 @@ (map #(get-first-layout % objects)) ids)) +(defn inside-layout? + [objects shape] + + (loop [current-id (:id shape)] + (let [current (get objects current-id)] + (cond + (or (nil? current) (= current-id (:parent-id current))) + false + + (= :frame (:type current)) + (:layout current) + + :else + (recur (:parent-id current)))))) + +#_(defn modif->js + [modif-tree objects] + (clj->js (into {} + (map (fn [[k v]] + [(get-in objects [k :name]) v])) + modif-tree))) + (defn set-objects-modifiers [ids objects get-modifier ignore-constraints snap-pixel?] @@ -251,40 +302,27 @@ modif-tree (reduce set-modifiers {} ids) - ids (resolve-layout-ids ids objects) + shapes-tree (resolve-tree-sequence ids objects) - ;; First: Calculate children modifiers (constraints, etc) - [modif-tree touched-layouts] - (loop [current (first ids) - pending (rest ids) - modif-tree modif-tree - touched-layouts (d/ordered-set)] - (if (some? current) - (let [shape (get objects current) - pending (concat pending (:shapes shape)) - - touched-layouts - (cond-> touched-layouts - (:layout shape) - (conj (:id shape))) - - modif-tree - (-> modif-tree - (set-children-modifiers shape objects ignore-constraints snap-pixel?))] - - (recur (first pending) (rest pending) modif-tree touched-layouts)) - - [modif-tree touched-layouts])) - - ;; Second: Calculate layout positioning modif-tree - (loop [current (first touched-layouts) - pending (rest touched-layouts) - modif-tree modif-tree] + (->> shapes-tree + (reduce + (fn [modif-tree shape] + (let [has-modifiers? (some? (get-in modif-tree [(:id shape) :modifiers])) + is-layout? (layout? shape) + is-parent? (or (group? shape) (and (frame? shape) (not (layout? shape)))) - (if (some? current) - (let [modif-tree (set-layout-modifiers modif-tree objects current)] - (recur (first pending) (rest pending) modif-tree)) - modif-tree))] + ;; If the current child is inside the layout we ignore the constraints + is-inside-layout? (inside-layout? objects shape)] + (cond-> modif-tree + is-layout? + (set-layout-modifiers objects shape snap-pixel?) + + (and has-modifiers? is-parent?) + (set-children-modifiers objects shape (or ignore-constraints is-inside-layout?) snap-pixel?)))) + + modif-tree))] + + ;;(.log js/console ">result" (modif->js modif-tree objects)) modif-tree)) diff --git a/common/src/app/common/geom/shapes/transforms.cljc b/common/src/app/common/geom/shapes/transforms.cljc index be2792109..8b1dfaa36 100644 --- a/common/src/app/common/geom/shapes/transforms.cljc +++ b/common/src/app/common/geom/shapes/transforms.cljc @@ -14,8 +14,8 @@ [app.common.geom.shapes.path :as gpa] [app.common.geom.shapes.rect :as gpr] [app.common.math :as mth] - [app.common.spec :as us] - [app.common.text :as txt])) + [app.common.text :as txt] + [app.common.types.modifiers :as ctm])) (def ^:dynamic *skip-adjust* false) @@ -76,14 +76,6 @@ ; ---- Geometric operations -(defn- normalize-scale - "We normalize the scale so it's not too close to 0" - [scale] - (cond - (and (< scale 0) (> scale -0.01)) -0.01 - (and (>= scale 0) (< scale 0.01)) 0.01 - :else scale)) - (defn- calculate-skew-angle "Calculates the skew angle of the parallelogram given by the points" [[p1 _ p3 p4]] @@ -182,17 +174,6 @@ (gmt/multiply (:transform-inverse shape (gmt/matrix))) (gmt/translate (gpt/negate center))))) -(defn transform-point-center - "Transform a point around the shape center" - [point center matrix] - (if (and (some? point) (some? matrix) (some? center)) - (gpt/transform - point - (gmt/multiply (gmt/translate-matrix center) - matrix - (gmt/translate-matrix (gpt/negate center)))) - point)) - (defn transform-rect "Transform a rectangles and changes its attributes" [rect matrix] @@ -273,6 +254,30 @@ (if transform (gmt/multiply transform matrix) matrix) (if transform-inverse (gmt/multiply matrix-inverse transform-inverse) matrix-inverse)])) +(defn- adjust-shape-flips + "After some tranformations the flip-x/flip-y flags can change we need + to check this before adjusting the selrect" + [shape points] + + (let [points' (:points shape) + + xv1 (gpt/to-vec (nth points' 0) (nth points' 1)) + xv2 (gpt/to-vec (nth points 0) (nth points 1)) + dot-x (gpt/dot xv1 xv2) + + yv1 (gpt/to-vec (nth points' 0) (nth points' 3)) + yv2 (gpt/to-vec (nth points 0) (nth points 3)) + dot-y (gpt/dot yv1 yv2)] + + (cond-> shape + (neg? dot-x) + (-> (update :flip-x not) + (update :rotation -)) + + (neg? dot-y) + (-> (update :flip-y not) + (update :rotation -))))) + (defn apply-transform "Given a new set of points transformed, set up the rectangle so it keeps its properties. We adjust de x,y,width,height and create a custom transform" @@ -280,6 +285,7 @@ (let [points' (:points shape) points (gco/transform-points points' transform-mtx) + shape (-> shape (adjust-shape-flips points)) bool? (= (:type shape) :bool) path? (= (:type shape) :path) @@ -289,7 +295,6 @@ base-rotation (or (:rotation shape) 0) modif-rotation (or (get-in shape [:modifiers :rotation]) 0) rotation (mod (+ base-rotation modif-rotation) 360)] - (-> shape (cond-> bool? (update :bool-content gpa/transform-content transform-mtx)) @@ -368,173 +373,8 @@ (assoc :flip-x (-> mask :flip-x)) (assoc :flip-y (-> mask :flip-y))))) -;; --- Modifiers -;; The `modifiers` structure contains a list of transformations to -;; do make to a shape, in this order: -;; -;; - resize-origin (gpt/point) + resize-vector (gpt/point) -;; apply a scale vector to all points of the shapes, starting -;; from the origin point. -;; -;; - resize-origin-2 + resize-vector-2 -;; same as the previous one, for cases in that we need to make -;; two vectors from different origin points. -;; -;; - displacement (gmt/matrix) -;; apply a translation matrix to the shape -;; -;; - rotation (gmt/matrix) -;; apply a rotation matrix to the shape -;; -;; - resize-transform (gmt/matrix) + resize-transform-inverse (gmt/matrix) -;; a copy of the rotation matrix currently applied to the shape; -;; this is needed temporarily to apply the resize vectors. -;; -;; - resize-scale-text (bool) -;; tells if the resize vectors must be applied to text shapes -;; or not. - -(defn empty-modifiers? [modifiers] - (empty? (dissoc modifiers :ignore-geometry?))) - -(defn resize-modifiers - [shape attr value] - (us/assert map? shape) - (us/assert #{:width :height} attr) - (us/assert number? value) - (let [{:keys [proportion proportion-lock]} shape - size (select-keys (:selrect shape) [:width :height]) - new-size (if-not proportion-lock - (assoc size attr value) - (if (= attr :width) - (-> size - (assoc :width value) - (assoc :height (/ value proportion))) - (-> size - (assoc :height value) - (assoc :width (* value proportion))))) - width (:width new-size) - height (:height new-size) - - shape-transform (:transform shape) - shape-transform-inv (:transform-inverse shape) - shape-center (gco/center-shape shape) - {sr-width :width sr-height :height} (:selrect shape) - - origin (cond-> (gpt/point (:selrect shape)) - (some? shape-transform) - (transform-point-center shape-center shape-transform)) - - scalev (gpt/divide (gpt/point width height) - (gpt/point sr-width sr-height))] - {:resize-vector scalev - :resize-origin origin - :resize-transform shape-transform - :resize-transform-inverse shape-transform-inv})) - -(defn change-orientation-modifiers - [shape orientation] - (us/assert map? shape) - (us/verify #{:horiz :vert} orientation) - (let [width (:width shape) - height (:height shape) - new-width (if (= orientation :horiz) (max width height) (min width height)) - new-height (if (= orientation :horiz) (min width height) (max width height)) - - shape-transform (:transform shape) - shape-transform-inv (:transform-inverse shape) - shape-center (gco/center-shape shape) - {sr-width :width sr-height :height} (:selrect shape) - - origin (cond-> (gpt/point (:selrect shape)) - (some? shape-transform) - (transform-point-center shape-center shape-transform)) - - scalev (gpt/divide (gpt/point new-width new-height) - (gpt/point sr-width sr-height))] - {:resize-vector scalev - :resize-origin origin - :resize-transform shape-transform - :resize-transform-inverse shape-transform-inv})) - -(defn rotation-modifiers - [shape center angle] - (let [displacement (let [shape-center (gco/center-shape shape)] - (-> (gmt/matrix) - (gmt/rotate angle center) - (gmt/rotate (- angle) shape-center)))] - {:rotation angle - :displacement displacement})) - -(defn merge-modifiers - [objects modifiers] - - (let [set-modifier - (fn [objects [id modifiers]] - (-> objects - (d/update-when id merge modifiers)))] - (->> modifiers - (reduce set-modifier objects)))) - -(defn modifiers->transform - ([modifiers] - (modifiers->transform nil modifiers)) - - ([center modifiers] - (let [displacement (:displacement modifiers) - displacement-after (:displacement-after modifiers) - resize-v1 (:resize-vector modifiers) - resize-v2 (:resize-vector-2 modifiers) - origin-1 (:resize-origin modifiers (gpt/point)) - origin-2 (:resize-origin-2 modifiers (gpt/point)) - - ;; Normalize x/y vector coordinates because scale by 0 is infinite - resize-1 (when (some? resize-v1) - (gpt/point (normalize-scale (:x resize-v1)) - (normalize-scale (:y resize-v1)))) - - resize-2 (when (some? resize-v2) - (gpt/point (normalize-scale (:x resize-v2)) - (normalize-scale (:y resize-v2)))) - - - resize-transform (:resize-transform modifiers) - resize-transform-inverse (:resize-transform-inverse modifiers) - - rt-modif (:rotation modifiers)] - - (cond-> (gmt/matrix) - (some? displacement-after) - (gmt/multiply displacement-after) - - (some? resize-1) - (-> (gmt/translate origin-1) - (cond-> (some? resize-transform) - (gmt/multiply resize-transform)) - (gmt/scale resize-1) - (cond-> (some? resize-transform-inverse) - (gmt/multiply resize-transform-inverse)) - (gmt/translate (gpt/negate origin-1))) - - (some? resize-2) - (-> (gmt/translate origin-2) - (cond-> (some? resize-transform) - (gmt/multiply resize-transform)) - (gmt/scale resize-2) - (cond-> (some? resize-transform-inverse) - (gmt/multiply resize-transform-inverse)) - (gmt/translate (gpt/negate origin-2))) - - (some? displacement) - (gmt/multiply displacement) - - (some? rt-modif) - (-> (gmt/translate center) - (gmt/multiply (gmt/rotate-matrix rt-modif)) - (gmt/translate (gpt/negate center))))))) - -(defn- set-flip [shape modifiers] +#_(defn- set-flip [shape modifiers] (let [rv1x (or (get-in modifiers [:resize-vector :x]) 1) rv1y (or (get-in modifiers [:resize-vector :y]) 1) rv2x (or (get-in modifiers [:resize-vector-2 :x]) 1) @@ -547,7 +387,25 @@ (-> (update :flip-y not) (update :rotation -))))) -(defn- apply-displacement [shape] +#_(defn- set-flip-2 [shape transform] + (let [pt-a (gpt/point (:selrect shape)) + pt-b (gpt/point (-> shape :selrect :x2) (-> shape :selrect :y2)) + + shape-transform (:transform shape (gmt/matrix)) + pt-a' (gpt/transform pt-a (gmt/multiply shape-transform transform )) + pt-b' (gpt/transform pt-b (gmt/multiply shape-transform transform )) + + {:keys [x y]} (gpt/to-vec pt-a' pt-b')] + + (cond-> shape + (neg? x) + (-> (update :flip-x not) + (update :rotation -)) + (neg? y) + (-> (update :flip-y not) + (update :rotation -))))) + +#_(defn- apply-displacement [shape] (let [modifiers (:modifiers shape)] (if (contains? modifiers :displacement) (let [mov-vec (-> (gpt/point 0 0) @@ -580,64 +438,87 @@ (defn apply-modifiers [shape modifiers] (let [center (gco/center-shape shape) - transform (modifiers->transform center modifiers)] - (apply-transform shape transform))) + transform (ctm/modifiers->transform center modifiers)] + (-> shape + #_(set-flip-2 transform) + (apply-transform transform)))) + +(defn apply-objects-modifiers + [objects modifiers] + (letfn [(process-shape [objects [id modifier]] + (update objects id apply-modifiers (:modifiers modifier)))] + (reduce process-shape objects modifiers))) (defn transform-shape - [shape] - (let [modifiers (:modifiers shape)] - (cond - (nil? modifiers) - shape + ([shape] + (let [modifiers (:modifiers shape)] + (-> shape + (dissoc :modifiers) + (transform-shape modifiers)))) - (empty-modifiers? modifiers) - (dissoc shape :modifiers) + ([shape modifiers] + (cond-> shape + (and (some? modifiers) (not (ctm/empty-modifiers? modifiers))) + (-> (apply-modifiers modifiers) + (apply-text-resize modifiers))))) - :else - (let [shape (apply-displacement shape) - modifiers (:modifiers shape)] - (cond-> shape - (not (empty-modifiers? modifiers)) - (-> (set-flip modifiers) - (apply-modifiers modifiers) - (apply-text-resize modifiers)) +(defn transform-bounds-v2 + [points center modifiers] + (let [transform (ctm/modifiers->transform center {:v2 modifiers}) + result (gco/transform-points points center transform)] - :always - (dissoc :modifiers)))))) + ;;(.log js/console "??" (str transform) (clj->js result)) + result) + + #_(letfn [(apply-modifier [points {:keys [type vector origin]}] + (case type + :move + (let [displacement (gmt/translate-matrix vector)] + (gco/transform-points points displacement)) + + :resize + (gco/transform-points points origin (gmt/scale-matrix vector)) + + points))] + (->> modifiers + (reduce apply-modifier points)))) (defn transform-bounds - [points center {:keys [displacement displacement-after resize-transform-inverse resize-vector resize-origin resize-vector-2 resize-origin-2]}] + [points center {:keys [v2 displacement displacement-after resize-transform-inverse resize-vector resize-origin resize-vector-2 resize-origin-2]}] + ;; FIXME: Improve Performance - (let [resize-transform-inverse (or resize-transform-inverse (gmt/matrix)) + (if (some? v2) + (transform-bounds-v2 points center v2) + (let [resize-transform-inverse (or resize-transform-inverse (gmt/matrix)) - displacement - (when (some? displacement) - (gmt/multiply resize-transform-inverse displacement)) + displacement + (when (some? displacement) + (gmt/multiply resize-transform-inverse displacement)) - resize-origin - (when (some? resize-origin) - (transform-point-center resize-origin center resize-transform-inverse)) + resize-origin + (when (some? resize-origin) + (gmt/transform-point-center resize-origin center resize-transform-inverse)) - resize-origin-2 - (when (some? resize-origin-2) - (transform-point-center resize-origin-2 center resize-transform-inverse)) - ] + resize-origin-2 + (when (some? resize-origin-2) + (gmt/transform-point-center resize-origin-2 center resize-transform-inverse)) + ] - (if (and (nil? displacement) (nil? resize-origin) (nil? resize-origin-2) (nil? displacement-after)) - points + (if (and (nil? displacement) (nil? resize-origin) (nil? resize-origin-2) (nil? displacement-after)) + points - (cond-> points - (some? displacement) - (gco/transform-points displacement) + (cond-> points + (some? displacement) + (gco/transform-points displacement) - (some? resize-origin) - (gco/transform-points resize-origin (gmt/scale-matrix resize-vector)) + (some? resize-origin) + (gco/transform-points resize-origin (gmt/scale-matrix resize-vector)) - (some? resize-origin-2) - (gco/transform-points resize-origin-2 (gmt/scale-matrix resize-vector-2)) + (some? resize-origin-2) + (gco/transform-points resize-origin-2 (gmt/scale-matrix resize-vector-2)) - (some? displacement-after) - (gco/transform-points displacement-after))))) + (some? displacement-after) + (gco/transform-points displacement-after)))))) (defn transform-selrect [selrect modifiers] diff --git a/common/src/app/common/pages/migrations.cljc b/common/src/app/common/pages/migrations.cljc index 79c9de1c8..6ff873c8e 100644 --- a/common/src/app/common/pages/migrations.cljc +++ b/common/src/app/common/pages/migrations.cljc @@ -102,13 +102,7 @@ (fix-frames-selrects) (and (empty? (:points object)) (not= (:id object) uuid/zero)) - (fix-empty-points) - - ;; Setup an empty transformation to re-calculate selrects - ;; and points data - :always - (-> (assoc :modifiers {:displacement (gmt/matrix)}) - (gsh/transform-shape)))) + (fix-empty-points))) (update-page [page] (update page :objects d/update-vals update-object))] diff --git a/common/src/app/common/types/modifiers.cljc b/common/src/app/common/types/modifiers.cljc new file mode 100644 index 000000000..963bcd74f --- /dev/null +++ b/common/src/app/common/types/modifiers.cljc @@ -0,0 +1,256 @@ +;; 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.types.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.spec :as us])) + +;; --- Modifiers + +;; The `modifiers` structure contains a list of transformations to +;; do make to a shape, in this order: +;; +;; - resize-origin (gpt/point) + resize-vector (gpt/point)q +;; apply a scale vector to all points of the shapes, starting +;; from the origin point. +;; +;; - resize-origin-2 + resize-vector-2 +;; same as the previous one, for cases in that we need to make +;; two vectors from different origin points. +;; +;; - displacement (gmt/matrix) +;; apply a translation matrix to the shape +;; +;; - rotation (gmt/matrix) +;; apply a rotation matrix to the shape +;; +;; - resize-transform (gmt/matrix) + resize-transform-inverse (gmt/matrix) +;; a copy of the rotation matrix currently applied to the shape; +;; this is needed temporarily to apply the resize vectors. +;; +;; - resize-scale-text (bool) +;; tells if the resize vectors must be applied to text shapes +;; or not. + +(defn move + ([x y] + (move (gpt/point x y))) + + ([vector] + {:v2 [{:type :move :vector vector}]})) + +(defn resize + [vector origin] + {:v2 [{:type :resize :vector vector :origin origin}]}) + +(defn add-move + ([object x y] + (add-move object (gpt/point x y))) + + ([object vector] + (assoc-in + object + [:modifiers :displacement] + (gmt/translate-matrix (:x vector) (:y vector))))) + +(defn add-resize + [object vector origin] + (-> object + (assoc-in [:modifiers :resize-vector] vector) + (assoc-in [:modifiers :resize-origin] origin))) + +(defn empty-modifiers? [modifiers] + (empty? (dissoc modifiers :ignore-geometry?))) + +(defn resize-modifiers + [shape attr value] + (us/assert map? shape) + (us/assert #{:width :height} attr) + (us/assert number? value) + (let [{:keys [proportion proportion-lock]} shape + size (select-keys (:selrect shape) [:width :height]) + new-size (if-not proportion-lock + (assoc size attr value) + (if (= attr :width) + (-> size + (assoc :width value) + (assoc :height (/ value proportion))) + (-> size + (assoc :height value) + (assoc :width (* value proportion))))) + width (:width new-size) + height (:height new-size) + + shape-transform (:transform shape) + shape-transform-inv (:transform-inverse shape) + shape-center (gco/center-shape shape) + {sr-width :width sr-height :height} (:selrect shape) + + origin (cond-> (gpt/point (:selrect shape)) + (some? shape-transform) + (gmt/transform-point-center shape-center shape-transform)) + + scalev (gpt/divide (gpt/point width height) + (gpt/point sr-width sr-height))] + {:resize-vector scalev + :resize-origin origin + :resize-transform shape-transform + :resize-transform-inverse shape-transform-inv})) + +(defn change-orientation-modifiers + [shape orientation] + (us/assert map? shape) + (us/verify #{:horiz :vert} orientation) + (let [width (:width shape) + height (:height shape) + new-width (if (= orientation :horiz) (max width height) (min width height)) + new-height (if (= orientation :horiz) (min width height) (max width height)) + + shape-transform (:transform shape) + shape-transform-inv (:transform-inverse shape) + shape-center (gco/center-shape shape) + {sr-width :width sr-height :height} (:selrect shape) + + origin (cond-> (gpt/point (:selrect shape)) + (some? shape-transform) + (gmt/transform-point-center shape-center shape-transform)) + + scalev (gpt/divide (gpt/point new-width new-height) + (gpt/point sr-width sr-height))] + {:resize-vector scalev + :resize-origin origin + :resize-transform shape-transform + :resize-transform-inverse shape-transform-inv})) + +(defn rotation-modifiers + [shape center angle] + (let [shape-center (gco/center-shape shape) + rotation (-> (gmt/matrix) + (gmt/rotate angle center) + (gmt/rotate (- angle) shape-center))] + + {:v2 [{:type :rotation + :center shape-center + :rotation angle} + + {:type :move + :vector (gpt/transform (gpt/point 1 1) rotation)}]} + #_{:rotation angle + :displacement displacement})) + +(defn merge-modifiers + [objects modifiers] + + (let [set-modifier + (fn [objects [id modifiers]] + (-> objects + (d/update-when id merge modifiers)))] + (->> modifiers + (reduce set-modifier objects)))) + +(defn modifiers-v2->transform + [modifiers] + (letfn [(apply-modifier [matrix {:keys [type vector rotation center origin transform transform-inverse] :as modifier}] + (case type + :move + (gmt/multiply (gmt/translate-matrix vector) matrix) + + ;;:transform + ;;(gmt/multiply transform matrix) + + :resize + (gmt/multiply + (-> (gmt/matrix) + (gmt/translate origin) + (cond-> (some? transform) + (gmt/multiply transform)) + (gmt/scale vector) + (cond-> (some? transform-inverse) + (gmt/multiply transform-inverse)) + (gmt/translate (gpt/negate origin))) + matrix) + + :rotation + ;; TODO LAYOUT: Comprobar que pasa si no hay centro + (gmt/multiply + (-> (gmt/matrix) + (gmt/translate center) + (gmt/multiply (gmt/rotate-matrix rotation)) + (gmt/translate (gpt/negate center))) + matrix)))] + (->> modifiers + (reduce apply-modifier (gmt/matrix))))) + +(defn- normalize-scale + "We normalize the scale so it's not too close to 0" + [scale] + (cond + (and (< scale 0) (> scale -0.01)) -0.01 + (and (>= scale 0) (< scale 0.01)) 0.01 + :else scale)) + +(defn modifiers->transform + ([modifiers] + (modifiers->transform nil modifiers)) + + ([center modifiers] + (if (some? (:v2 modifiers)) + (modifiers-v2->transform (:v2 modifiers)) + (let [displacement (:displacement modifiers) + displacement-after (:displacement-after modifiers) + resize-v1 (:resize-vector modifiers) + resize-v2 (:resize-vector-2 modifiers) + origin-1 (:resize-origin modifiers (gpt/point)) + origin-2 (:resize-origin-2 modifiers (gpt/point)) + + ;; Normalize x/y vector coordinates because scale by 0 is infinite + resize-1 (when (some? resize-v1) + (gpt/point (normalize-scale (:x resize-v1)) + (normalize-scale (:y resize-v1)))) + + resize-2 (when (some? resize-v2) + (gpt/point (normalize-scale (:x resize-v2)) + (normalize-scale (:y resize-v2)))) + + resize-transform (:resize-transform modifiers) + resize-transform-inverse (:resize-transform-inverse modifiers) + + rt-modif (:rotation modifiers)] + + (cond-> (gmt/matrix) + (some? displacement-after) + (gmt/multiply displacement-after) + + (some? resize-1) + (-> (gmt/translate origin-1) + (cond-> (some? resize-transform) + (gmt/multiply resize-transform)) + (gmt/scale resize-1) + (cond-> (some? resize-transform-inverse) + (gmt/multiply resize-transform-inverse)) + (gmt/translate (gpt/negate origin-1))) + + (some? resize-2) + (-> (gmt/translate origin-2) + (cond-> (some? resize-transform) + (gmt/multiply resize-transform)) + (gmt/scale resize-2) + (cond-> (some? resize-transform-inverse) + (gmt/multiply resize-transform-inverse)) + (gmt/translate (gpt/negate origin-2))) + + (some? displacement) + (gmt/multiply displacement) + + (some? rt-modif) + (-> (gmt/translate center) + (gmt/multiply (gmt/rotate-matrix rt-modif)) + (gmt/translate (gpt/negate center)))))) + )) diff --git a/frontend/src/app/main/data/workspace/comments.cljs b/frontend/src/app/main/data/workspace/comments.cljs index c87150b31..7fddf1c78 100644 --- a/frontend/src/app/main/data/workspace/comments.cljs +++ b/frontend/src/app/main/data/workspace/comments.cljs @@ -159,8 +159,8 @@ build-move-event (fn [comment-thread] (let [frame (get objects (:frame-id comment-thread)) - frame' (-> (merge frame (get object-modifiers (:frame-id comment-thread))) - (gsh/transform-shape)) + modifiers (get object-modifiers (:frame-id comment-thread)) + frame' (gsh/transform-shape frame modifiers) moved (gpt/to-vec (gpt/point (:x frame) (:y frame)) (gpt/point (:x frame') (:y frame'))) position (get-in threads-position-map [(:id comment-thread) :position]) diff --git a/frontend/src/app/main/data/workspace/drawing/box.cljs b/frontend/src/app/main/data/workspace/drawing/box.cljs index de2a290ac..dc9e86762 100644 --- a/frontend/src/app/main/data/workspace/drawing/box.cljs +++ b/frontend/src/app/main/data/workspace/drawing/box.cljs @@ -10,6 +10,7 @@ [app.common.geom.shapes :as gsh] [app.common.math :as mth] [app.common.pages.helpers :as cph] + [app.common.types.modifiers :as ctm] [app.common.types.shape :as cts] [app.common.types.shape-tree :as ctst] [app.common.uuid :as uuid] @@ -37,9 +38,7 @@ scalev)] (-> shape (assoc :click-draw? false) - (assoc-in [:modifiers :resize-vector] scalev) - (assoc-in [:modifiers :resize-origin] (gpt/point x y)) - (assoc-in [:modifiers :resize-rotation] 0)))) + (gsh/transform-shape (ctm/resize scalev (gpt/point x y)))))) (defn update-drawing [state point lock?] (update-in state [:workspace-drawing :object] resize-shape point lock?)) diff --git a/frontend/src/app/main/data/workspace/drawing/common.cljs b/frontend/src/app/main/data/workspace/drawing/common.cljs index 1742bfd05..c13f76e70 100644 --- a/frontend/src/app/main/data/workspace/drawing/common.cljs +++ b/frontend/src/app/main/data/workspace/drawing/common.cljs @@ -6,10 +6,10 @@ (ns app.main.data.workspace.drawing.common (:require - [app.common.geom.matrix :as gmt] [app.common.geom.shapes :as gsh] [app.common.math :as mth] [app.common.pages.helpers :as cph] + [app.common.types.modifiers :as ctm] [app.common.types.shape :as cts] [app.main.data.workspace.shapes :as dwsh] [app.main.data.workspace.state-helpers :as wsh] @@ -51,8 +51,8 @@ (and click-draw? (not text?)) (-> (assoc :width min-side :height min-side) - (assoc-in [:modifiers :displacement] - (gmt/translate-matrix (- (/ min-side 2)) (- (/ min-side 2))))) + (gsh/transform-shape (ctm/move (- (/ min-side 2)) (- (/ min-side 2)))) + #_(ctm/add-move (- (/ min-side 2)) (- (/ min-side 2)))) (and click-draw? text?) (assoc :height 17 :width 4 :grow-type :auto-width) @@ -61,8 +61,7 @@ (cts/setup-rect-selrect) :always - (-> (gsh/transform-shape) - (dissoc :initialized? :click-draw?)))] + (dissoc :initialized? :click-draw?))] ;; Add & select the created shape to the workspace (rx/concat (if (= :text (:type shape)) diff --git a/frontend/src/app/main/data/workspace/guides.cljs b/frontend/src/app/main/data/workspace/guides.cljs index 35bae09d3..0ef6e5a0b 100644 --- a/frontend/src/app/main/data/workspace/guides.cljs +++ b/frontend/src/app/main/data/workspace/guides.cljs @@ -79,8 +79,7 @@ build-move-event (fn [guide] (let [frame (get objects (:frame-id guide)) - frame' (-> (merge frame (get object-modifiers (:frame-id guide))) - (gsh/transform-shape)) + frame' (gsh/transform-shape (get object-modifiers (:frame-id guide))) moved (gpt/to-vec (gpt/point (:x frame) (:y frame)) (gpt/point (:x frame') (:y frame'))) diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index 710995c9b..cffd33827 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -55,7 +55,7 @@ (dwt/apply-modifiers)) (rx/empty)))))) -;; TODO: Remove constraints from children +;; TODO LAYOUT: Remove constraints from children (defn create-layout [ids type] (ptk/reify ::create-layout diff --git a/frontend/src/app/main/data/workspace/state_helpers.cljs b/frontend/src/app/main/data/workspace/state_helpers.cljs index c2f68bd62..c56931cf1 100644 --- a/frontend/src/app/main/data/workspace/state_helpers.cljs +++ b/frontend/src/app/main/data/workspace/state_helpers.cljs @@ -8,9 +8,9 @@ (:require [app.common.data :as d] [app.common.data.macros :as dm] - [app.common.geom.shapes :as gsh] [app.common.pages.helpers :as cph] - [app.common.path.commands :as upc])) + [app.common.path.commands :as upc] + [app.common.types.modifiers :as ctm])) (defn lookup-page ([state] @@ -137,5 +137,6 @@ children (select-keys objects children-ids)] (as-> children $ - (gsh/merge-modifiers $ modifiers) + ;; TODO LAYOUT: REVIEW THIS + (ctm/merge-modifiers $ modifiers) (d/mapm (set-content-modifiers state) $)))) diff --git a/frontend/src/app/main/data/workspace/texts.cljs b/frontend/src/app/main/data/workspace/texts.cljs index 653b03abc..1c9f5f147 100644 --- a/frontend/src/app/main/data/workspace/texts.cljs +++ b/frontend/src/app/main/data/workspace/texts.cljs @@ -13,6 +13,7 @@ [app.common.math :as mth] [app.common.pages.helpers :as cph] [app.common.text :as txt] + [app.common.types.modifiers :as ctm] [app.common.uuid :as uuid] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.common :as dwc] @@ -319,17 +320,16 @@ (letfn [(update-fn [shape] (let [{:keys [selrect grow-type]} shape {shape-width :width shape-height :height} selrect - modifier-width (gsh/resize-modifiers shape :width new-width) - modifier-height (gsh/resize-modifiers shape :height new-height)] + modifier-width (ctm/resize-modifiers shape :width new-width) + modifier-height (ctm/resize-modifiers shape :height new-height)] + ;; TODO LAYOUT: MEZCLAR ESTOS EN UN UNICO MODIFIER (cond-> shape (and (not-changed? shape-width new-width) (= grow-type :auto-width)) - (-> (assoc :modifiers modifier-width) - (gsh/transform-shape)) + (gsh/transform-shape modifier-width) (and (not-changed? shape-height new-height) (or (= grow-type :auto-height) (= grow-type :auto-width))) - (-> (assoc :modifiers modifier-height) - (gsh/transform-shape)))))] + (gsh/transform-shape modifier-height))))] (rx/of (dch/update-shapes [id] update-fn {:reg-objects? true :save-undo? false})))))) @@ -346,18 +346,17 @@ (defn apply-text-modifier [shape {:keys [width height position-data]}] - (let [modifier-width (when width (gsh/resize-modifiers shape :width width)) - modifier-height (when height (gsh/resize-modifiers shape :height height)) + (let [modifier-width (when width (ctm/resize-modifiers shape :width width)) + modifier-height (when height (ctm/resize-modifiers shape :height height)) + ;; TODO LAYOUT: MEZCLAR LOS DOS EN UN UNICO MODIFIER new-shape (cond-> shape (some? modifier-width) - (-> (assoc :modifiers modifier-width) - (gsh/transform-shape)) + (gsh/transform-shape modifier-width) (some? modifier-height) - (-> (assoc :modifiers modifier-height) - (gsh/transform-shape)) + (gsh/transform-shape modifier-height) (some? position-data) (assoc :position-data position-data)) diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 0842f1885..9d8c186d5 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -16,6 +16,7 @@ [app.common.pages.common :as cpc] [app.common.pages.helpers :as cph] [app.common.spec :as us] + [app.common.types.modifiers :as ctm] [app.common.types.shape-tree :as ctst] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.collapse :as dwc] @@ -154,14 +155,14 @@ ids (->> shapes (remove #(get % :blocked false)) - (mapcat #(cph/get-children objects (:id %))) - (concat shapes) + #_(mapcat #(cph/get-children objects (:id %))) + #_(concat shapes) (filter #((cpc/editable-attrs (:type %)) :rotation)) (map :id)) get-modifier (fn [shape] - (gsh/rotation-modifiers shape center angle)) + (ctm/rotation-modifiers shape center angle)) modif-tree (gsh/set-objects-modifiers ids objects get-modifier false false)] @@ -193,7 +194,7 @@ (let [objects (wsh/lookup-page-objects state) object-modifiers (get state :workspace-modifiers) - ids (keys object-modifiers) + ids (or (keys object-modifiers) []) ids-with-children (into (vec ids) (mapcat #(cph/get-children-ids objects %)) ids) shapes (map (d/getf objects) ids) @@ -209,11 +210,10 @@ (dch/update-shapes ids (fn [shape] - (let [modif (get object-modifiers (:id shape)) + (let [modif (get-in object-modifiers [(:id shape) :modifiers]) text-shape? (cph/text-shape? shape)] (-> shape - (merge modif) - (gsh/transform-shape) + (gsh/transform-shape modif) (cond-> text-shape? (update-grow-type shape))))) {:reg-objects? true @@ -295,7 +295,7 @@ (let [children (map (d/getf objects) (:shapes shape)) shape-id (:id shape) - transformed-shape (gsh/transform-shape (merge shape (get modif-tree shape-id))) + transformed-shape (gsh/transform-shape shape (get modif-tree shape-id)) [root transformed-root ignore-geometry?] (check-delta shape root transformed-shape transformed-root objects modif-tree) @@ -331,10 +331,10 @@ rotation (or rotation 0) - initial (gsh/transform-point-center initial shape-center shape-transform-inverse) + initial (gmt/transform-point-center initial shape-center shape-transform-inverse) initial (fix-init-point initial handler shape) - point (gsh/transform-point-center (if (= rotation 0) point-snap point) + point (gmt/transform-point-center (if (= rotation 0) point-snap point) shape-center shape-transform-inverse) shapev (-> (gpt/point width height)) @@ -381,14 +381,28 @@ (gpt/transform shape-transform))) resize-origin - (cond-> (gsh/transform-point-center handler-origin shape-center shape-transform) + (cond-> (gmt/transform-point-center handler-origin shape-center shape-transform) (some? displacement) - (gpt/add displacement)) - - displacement (when (some? displacement) - (gmt/translate-matrix displacement))] + (gpt/add displacement))] (rx/of (set-modifiers ids + {:v2 (-> [] + (cond-> displacement + (conj {:type :move + :vector displacement})) + (conj {:type :resize + :vector scalev + :origin resize-origin + :transform shape-transform + :transform-inverse shape-transform-inverse})) + ;;:displacement displacement + ;;:resize-vector scalev + ;;:resize-origin resize-origin + ;;:resize-transform shape-transform + ;;:resize-scale-text scale-text + ;;:resize-transform-inverse shape-transform-inverse + })) + #_(rx/of (set-modifiers ids {:displacement displacement :resize-vector scalev :resize-origin resize-origin @@ -444,7 +458,7 @@ snap-pixel? (and (contains? (:workspace-layout state) :snap-pixel-grid) (int? value)) get-modifier - (fn [shape] (gsh/resize-modifiers shape attr value)) + (fn [shape] (ctm/resize-modifiers shape attr value)) modif-tree (gsh/set-objects-modifiers ids objects get-modifier false snap-pixel?)] @@ -468,7 +482,7 @@ snap-pixel? (contains? (get state :workspace-layout) :snap-pixel-grid) get-modifier - (fn [shape] (gsh/change-orientation-modifiers shape orientation)) + (fn [shape] (ctm/change-orientation-modifiers shape orientation)) modif-tree (gsh/set-objects-modifiers ids objects get-modifier false snap-pixel?)] @@ -655,7 +669,10 @@ (rx/with-latest vector snap-delta) ;; We try to use the previous snap so we don't have to wait for the result of the new (rx/map snap/correct-snap-point) - (rx/map #(hash-map :displacement (gmt/translate-matrix %))) + + #_(rx/map #(hash-map :displacement (gmt/translate-matrix %))) + (rx/map #(array-map :v2 [{:type :move :vector %}])) + (rx/map (partial set-modifiers ids)) (rx/take-until stopper)) @@ -704,7 +721,7 @@ (rx/merge (->> move-events (rx/scan #(gpt/add %1 mov-vec) (gpt/point 0 0)) - (rx/map #(hash-map :displacement (gmt/translate-matrix %))) + (rx/map #(ctm/move %)) (rx/map (partial set-modifiers selected)) (rx/take-until stopper)) (rx/of (move-selected direction shift?))) @@ -735,11 +752,11 @@ cpos (gpt/point (:x bbox) (:y bbox)) pos (gpt/point (or (:x position) (:x bbox)) (or (:y position) (:y bbox))) - delta (gpt/subtract pos cpos) - displ (gmt/translate-matrix delta)] + delta (gpt/subtract pos cpos)] - (rx/of (set-modifiers [id] {:displacement displ} false true) - (apply-modifiers [id])))))) + (rx/of + (set-modifiers [id] (ctm/move delta)) + (apply-modifiers [id])))))) (defn- calculate-frame-for-move [ids] @@ -787,11 +804,16 @@ (let [objects (wsh/lookup-page-objects state) selected (wsh/lookup-selected state {:omit-blocked? true}) shapes (map #(get objects %) selected) - selrect (gsh/selection-rect (->> shapes (map gsh/transform-shape))) + selrect (gsh/selection-rect shapes) origin (gpt/point (:x selrect) (+ (:y selrect) (/ (:height selrect) 2)))] (rx/of (set-modifiers selected - {:resize-vector (gpt/point -1.0 1.0) + {:v2 [{:type :resize + :vector (gpt/point -1.0 1.0) + :origin origin} + {:type :move + :vector (gpt/point (:width selrect) 0)}]} + #_{:resize-vector (gpt/point -1.0 1.0) :resize-origin origin :displacement (gmt/translate-matrix (gpt/point (- (:width selrect)) 0))} true) @@ -804,11 +826,16 @@ (let [objects (wsh/lookup-page-objects state) selected (wsh/lookup-selected state {:omit-blocked? true}) shapes (map #(get objects %) selected) - selrect (gsh/selection-rect (->> shapes (map gsh/transform-shape))) + selrect (gsh/selection-rect shapes) origin (gpt/point (+ (:x selrect) (/ (:width selrect) 2)) (:y selrect))] (rx/of (set-modifiers selected - {:resize-vector (gpt/point 1.0 -1.0) + {:v2 [{:type :resize + :vector (gpt/point 1.0 -1.0) + :origin origin} + {:type :move + :vector (gpt/point 0 (:height selrect))}]} + #_{:resize-vector (gpt/point 1.0 -1.0) :resize-origin origin :displacement (gmt/translate-matrix (gpt/point 0 (- (:height selrect))))} true) diff --git a/frontend/src/app/main/render.cljs b/frontend/src/app/main/render.cljs index c750538dc..77fa6f5a1 100644 --- a/frontend/src/app/main/render.cljs +++ b/frontend/src/app/main/render.cljs @@ -15,12 +15,12 @@ ["react-dom/server" :as rds] [app.common.colors :as clr] [app.common.data.macros :as dm] - [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] [app.common.geom.shapes.bounds :as gsb] [app.common.math :as mth] [app.common.pages.helpers :as cph] + [app.common.types.modifiers :as ctm] [app.common.types.shape-tree :as ctst] [app.config :as cfg] [app.main.fonts :as fonts] @@ -82,7 +82,8 @@ (let [render-thumbnails? (mf/use-ctx muc/render-thumbnails) childs (mapv #(get objects %) (:shapes shape)) - shape (gsh/transform-shape shape)] + ;;shape (gsh/transform-shape shape) + ] (if (and render-thumbnails? (some? (:thumbnail shape))) [:& frame/frame-thumbnail {:shape shape :bounds (:children-bounds shape)}] [:& frame-shape {:shape shape :childs childs}]))))) @@ -135,7 +136,7 @@ bool-wrapper (mf/use-memo (mf/deps objects) #(bool-wrapper-factory objects)) frame-wrapper (mf/use-memo (mf/deps objects) #(frame-wrapper-factory objects))] (when (and shape (not (:hidden shape))) - (let [shape (gsh/transform-shape shape) + (let [;;shape (gsh/transform-shape shape) opts #js {:shape shape} svg-raw? (= :svg-raw (:type shape))] (if-not svg-raw? @@ -167,7 +168,8 @@ (let [shapes (cph/get-immediate-children objects) srect (gsh/selection-rect shapes) object (merge object (select-keys srect [:x :y :width :height])) - object (gsh/transform-shape object)] + ;; object (gsh/transform-shape object) + ] (assoc object :fill-color "#f0f0f0"))) (defn adapt-objects-for-shape @@ -180,14 +182,12 @@ ;; Replace the previous object with the new one objects (assoc objects object-id object) - modifier (-> (gpt/point (:x object) (:y object)) - (gpt/negate) - (gmt/translate-matrix)) + vector (-> (gpt/point (:x object) (:y object)) + (gpt/negate)) mod-ids (cons object-id (cph/get-children-ids objects object-id)) - updt-fn #(-> %1 - (assoc-in [%2 :modifiers :displacement] modifier) - (update %2 gsh/transform-shape))] + + updt-fn #(update %1 %2 gsh/transform-shape (ctm/move vector))] (reduce updt-fn objects mod-ids))) @@ -247,24 +247,21 @@ bounds2 (gsb/get-object-bounds objects (dissoc frame :shadow :blur)) delta-bounds (gpt/point (:x bounds) (:y bounds)) - - modifier (gmt/translate-matrix (gpt/negate delta-bounds)) + vector (gpt/negate delta-bounds) children-ids (cph/get-children-ids objects frame-id) objects - (mf/with-memo [frame-id objects modifier] - (let [update-fn #(assoc-in %1 [%2 :modifiers :displacement] modifier)] + (mf/with-memo [frame-id objects vector] + (let [update-fn #(update-in %1 %2 ctm/add-move vector)] (->> children-ids (into [frame-id]) (reduce update-fn objects)))) frame - (mf/with-memo [modifier] - (-> frame - (assoc-in [:modifiers :displacement] modifier) - (gsh/transform-shape))) + (mf/with-memo [vector] + (gsh/transform-shape frame (ctm/move vector))) frame (cond-> frame @@ -305,22 +302,21 @@ (let [group-id (:id group) include-metadata? (mf/use-ctx export/include-metadata-ctx) - modifier + vector (mf/use-memo (mf/deps (:x group) (:y group)) (fn [] (-> (gpt/point (:x group) (:y group)) - (gpt/negate) - (gmt/translate-matrix)))) + (gpt/negate)))) objects (mf/use-memo - (mf/deps modifier objects group-id) + (mf/deps vector objects group-id) (fn [] (let [modifier-ids (cons group-id (cph/get-children-ids objects group-id)) - update-fn #(assoc-in %1 [%2 :modifiers :displacement] modifier) + update-fn #(update %1 %2 ctm/add-move vector) modifiers (reduce update-fn {} modifier-ids)] - (gsh/merge-modifiers objects modifiers)))) + (ctm/merge-modifiers objects modifiers)))) group (get objects group-id) width (* (:width group) zoom) diff --git a/frontend/src/app/main/ui/shapes/bool.cljs b/frontend/src/app/main/ui/shapes/bool.cljs index 94a76d893..2c00a9684 100644 --- a/frontend/src/app/main/ui/shapes/bool.cljs +++ b/frontend/src/app/main/ui/shapes/bool.cljs @@ -6,7 +6,6 @@ (ns app.main.ui.shapes.bool (:require - [app.common.data :as d] [app.common.data.macros :as dm] [app.common.geom.shapes :as gsh] [app.main.ui.hooks :refer [use-equal-memo]] @@ -15,6 +14,7 @@ [app.util.object :as obj] [rumext.v2 :as mf])) +;; TODO LAYOUT: REVIEW DYNAMIC CHANGES IN BOOLEANS (defn bool-shape [shape-wrapper] (mf/fnc bool-shape @@ -35,7 +35,7 @@ (some? childs) (->> childs - (d/mapm #(gsh/transform-shape %2)) + #_(d/mapm #(gsh/transform-shape %2)) (gsh/calc-bool-content shape)))))] [:* diff --git a/frontend/src/app/main/ui/shapes/mask.cljs b/frontend/src/app/main/ui/shapes/mask.cljs index 493c43691..d0685a5f5 100644 --- a/frontend/src/app/main/ui/shapes/mask.cljs +++ b/frontend/src/app/main/ui/shapes/mask.cljs @@ -7,6 +7,7 @@ (ns app.main.ui.shapes.mask (:require [app.common.data :as d] + [app.common.data.macros :as dm] [app.common.geom.shapes :as gsh] [app.main.ui.context :as muc] [cuerdas.core :as str] @@ -50,9 +51,7 @@ render-id (mf/use-ctx muc/render-id) svg-text? (and (= :text (:type mask)) (some? (:position-data mask))) - mask-bb (-> (gsh/transform-shape mask) - (:points)) - + mask-bb (:points mask) mask-bb-rect (gsh/points->rect mask-bb)] [:defs [:filter {:id (filter-id render-id mask)} @@ -68,7 +67,7 @@ [:clipPath {:class "mask-clip-path" :id (clip-id render-id mask)} [:polyline {:points (->> mask-bb - (map #(str (:x %) "," (:y %))) + (map #(dm/str (:x %) "," (:y %))) (str/join " "))}]] ;; When te shape is a text we pass to the shape the info and disable the filter. diff --git a/frontend/src/app/main/ui/viewer/handoff/render.cljs b/frontend/src/app/main/ui/viewer/handoff/render.cljs index 0567bf654..0fc20987e 100644 --- a/frontend/src/app/main/ui/viewer/handoff/render.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/render.cljs @@ -88,7 +88,7 @@ [props] (let [shape (unchecked-get props "shape") childs (mapv #(get objects %) (:shapes shape)) - shape (gsh/transform-shape shape) + ;;shape (gsh/transform-shape shape) props (-> (obj/create) (obj/merge! props) @@ -171,8 +171,7 @@ (mf/use-memo (mf/deps objects) #(svg-raw-container-factory objects))] (when (and shape (not (:hidden shape))) - (let [shape (-> (gsh/transform-shape shape) - (gsh/translate-to-frame frame)) + (let [shape (gsh/translate-to-frame shape frame) opts #js {:shape shape :frame frame}] (case (:type shape) diff --git a/frontend/src/app/main/ui/viewer/interactions.cljs b/frontend/src/app/main/ui/viewer/interactions.cljs index fafb5cf53..72d822828 100644 --- a/frontend/src/app/main/ui/viewer/interactions.cljs +++ b/frontend/src/app/main/ui/viewer/interactions.cljs @@ -8,9 +8,9 @@ (:require [app.common.data :as d] [app.common.data.macros :as dm] - [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] [app.common.pages.helpers :as cph] + [app.common.types.modifiers :as ctm] [app.common.types.page :as ctp] [app.common.uuid :as uuid] [app.main.data.comments :as dcm] @@ -31,11 +31,10 @@ [frame size objects] (let [ frame-id (:id frame) - modifier (-> (gpt/point (:x size) (:y size)) - (gpt/negate) - (gmt/translate-matrix)) + vector (-> (gpt/point (:x size) (:y size)) + (gpt/negate)) - update-fn #(d/update-when %1 %2 assoc-in [:modifiers :displacement] modifier)] + update-fn #(d/update-when %1 %2 ctm/add-move vector)] (->> (cph/get-children-ids objects frame-id) (into [frame-id]) diff --git a/frontend/src/app/main/ui/viewer/shapes.cljs b/frontend/src/app/main/ui/viewer/shapes.cljs index b884653ba..2b2522078 100644 --- a/frontend/src/app/main/ui/viewer/shapes.cljs +++ b/frontend/src/app/main/ui/viewer/shapes.cljs @@ -350,7 +350,7 @@ [props] (let [shape (obj/get props "shape") childs (mapv #(get objects %) (:shapes shape)) - shape (gsh/transform-shape shape) + ;;shape (gsh/transform-shape shape) props (obj/merge! #js {} props #js {:shape shape :childs childs @@ -429,7 +429,8 @@ (mf/with-memo [objects] (svg-raw-container-factory objects))] (when (and shape (not (:hidden shape))) - (let [shape (-> (gsh/transform-shape shape) + (let [shape (-> shape + #_(gsh/transform-shape) (gsh/translate-to-frame frame)) opts #js {:shape shape diff --git a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs index 2f4207e14..565cca9d5 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs @@ -11,6 +11,7 @@ [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] + [app.common.types.modifiers :as ctm] [app.main.store :as st] [app.main.ui.workspace.viewport.utils :as vwu] [app.util.dom :as dom] @@ -184,6 +185,7 @@ text? (= type :text) transform-text? (and text? (and (nil? (:resize-vector modifiers)) (nil? (:resize-vector-2 modifiers))))] + ;; TODO LAYOUT: Adapt to new modifiers (doseq [node nodes] (cond ;; Text shapes need special treatment because their resize only change @@ -197,7 +199,7 @@ (dom/class? node "text-container") (let [modifiers (dissoc modifiers :displacement :rotation)] - (when (not (gsh/empty-modifiers? modifiers)) + (when (not (ctm/empty-modifiers? modifiers)) (let [mtx (-> shape (assoc :modifiers modifiers) (gsh/transform-shape) @@ -260,12 +262,15 @@ (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]))] - (gsh/modifiers->transform center modifiers))) + (select-keys [:displacement :rotation])) + ] + (ctm/modifiers->transform center modifiers))) modifiers)))) shapes diff --git a/frontend/src/app/main/ui/workspace/shapes/text.cljs b/frontend/src/app/main/ui/workspace/shapes/text.cljs index 53ed5d9ac..b51432b5b 100644 --- a/frontend/src/app/main/ui/workspace/shapes/text.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/text.cljs @@ -58,7 +58,7 @@ :height height :style {:fill "none" :stroke "red"}}] - ;; Text baselineazo + ;; Text baseline [:line {:x1 (mth/round x) :y1 (mth/round (- (:y data) (:height data))) :x2 (mth/round (+ x width)) diff --git a/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs b/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs index 6ee6b3ddc..e104b64fa 100644 --- a/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs @@ -13,6 +13,7 @@ [app.common.math :as mth] [app.common.pages.helpers :as cph] [app.common.text :as txt] + [app.common.types.modifiers :as ctm] [app.main.data.workspace.texts :as dwt] [app.main.fonts :as fonts] [app.main.refs :as refs] @@ -33,6 +34,7 @@ (with-meta (meta (:position-data shape)))) (dissoc :position-data :transform :transform-inverse))) +;; TODO LAYOUT: Adapt to new modifiers (defn strip-modifier [modifier] (if (or (some? (dm/get-in modifier [:modifiers :resize-vector])) @@ -43,9 +45,9 @@ (defn process-shape [modifiers {:keys [id] :as shape}] (let [modifier (-> (get modifiers id) strip-modifier) shape (cond-> shape - (not (gsh/empty-modifiers? (:modifiers modifier))) + (not (ctm/empty-modifiers? (:modifiers modifier))) (-> (assoc :grow-type :fixed) - (merge modifier) gsh/transform-shape))] + (gsh/transform-shape modifier)))] (-> shape (cond-> (nil? (:position-data shape)) (assoc :migrate true)) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options.cljs b/frontend/src/app/main/ui/workspace/sidebar/options.cljs index 50ea9fa1e..99f65f0fe 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options.cljs @@ -7,7 +7,7 @@ (ns app.main.ui.workspace.sidebar.options (:require [app.common.data :as d] - [app.common.geom.shapes :as gsh] + [app.common.types.modifiers :as ctm] [app.main.data.workspace :as udw] [app.main.refs :as refs] [app.main.store :as st] @@ -64,7 +64,7 @@ shared-libs (mf/deref refs/workspace-libraries) modifiers (mf/deref refs/workspace-modifiers) objects-modified (mf/with-memo [base-objects modifiers] - (gsh/merge-modifiers base-objects modifiers)) + (ctm/merge-modifiers base-objects modifiers)) selected-shapes (into [] (keep (d/getf objects-modified)) selected)] [:div.tool-window [:div.tool-window-content diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index 3cf07759b..f5044bd0d 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -79,8 +79,7 @@ modifiers (mf/deref refs/workspace-modifiers) objects-modified (mf/with-memo [base-objects modifiers] - (gsh/merge-modifiers base-objects modifiers)) - + (gsh/apply-objects-modifiers base-objects modifiers)) background (get options :background clr/canvas) ;; STATE @@ -203,7 +202,7 @@ {:key (dm/str "texts-" page-id) :page-id page-id :objects objects - :modifiers modifiers + ;;:modifiers modifiers :edition edition}]]]] (when show-comments? @@ -336,10 +335,9 @@ (when show-prototypes? [:& widgets/frame-flows {:flows (:flows options) - :objects base-objects + :objects objects-modified :selected selected :zoom zoom - :modifiers modifiers :on-frame-enter on-frame-enter :on-frame-leave on-frame-leave :on-frame-select on-frame-select}]) @@ -348,8 +346,7 @@ [:& drawarea/draw-area {:shape drawing-obj :zoom zoom - :tool drawing-tool - :modifiers modifiers}]) + :tool drawing-tool}]) (when show-grids? [:& frame-grid/frame-grid @@ -371,9 +368,8 @@ :zoom zoom :page-id page-id :selected selected - :objects base-objects - :focus focus - :modifiers modifiers}]) + :objects objects-modified + :focus focus}]) (when show-snap-distance? [:& snap-distances/snap-distances @@ -416,7 +412,6 @@ {:zoom zoom :vbox vbox :hover-frame frame-parent - :modifiers modifiers :disabled-guides? disabled-guides?}]) (when show-selection-handlers? diff --git a/frontend/src/app/main/ui/workspace/viewport/drawarea.cljs b/frontend/src/app/main/ui/workspace/viewport/drawarea.cljs index 8d31ae5ac..356af918e 100644 --- a/frontend/src/app/main/ui/workspace/viewport/drawarea.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/drawarea.cljs @@ -7,7 +7,6 @@ (ns app.main.ui.workspace.viewport.drawarea "Drawing components." (:require - [app.common.geom.shapes :as gsh] [app.common.math :as mth] [app.main.ui.shapes.path :refer [path-shape]] [app.main.ui.workspace.shapes :as shapes] @@ -22,7 +21,7 @@ [:g.draw-area [:g {:style {:pointer-events "none"}} - [:& shapes/shape-wrapper {:shape (gsh/transform-shape shape)}]] + [:& shapes/shape-wrapper {:shape shape}]] (case tool :path [:& path-editor {:shape shape :zoom zoom}] @@ -31,7 +30,7 @@ (mf/defc generic-draw-area [{:keys [shape zoom]}] - (let [{:keys [x y width height]} (:selrect (gsh/transform-shape shape))] + (let [{:keys [x y width height]} (:selrect shape)] (when (and x y (not (mth/nan? x)) (not (mth/nan? y))) diff --git a/frontend/src/app/main/ui/workspace/viewport/guides.cljs b/frontend/src/app/main/ui/workspace/viewport/guides.cljs index efefcaf7a..5d158ee22 100644 --- a/frontend/src/app/main/ui/workspace/viewport/guides.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/guides.cljs @@ -278,7 +278,7 @@ frame]} (use-guide handle-change-position get-hover-frame zoom guide) base-frame (or frame hover-frame) - frame (gsh/transform-shape (merge base-frame frame-modifier)) + frame (gsh/transform-shape base-frame frame-modifier) move-vec (gpt/to-vec (gpt/point (:x base-frame) (:y base-frame)) (gpt/point (:x frame) (:y frame))) diff --git a/frontend/src/app/main/ui/workspace/viewport/interactions.cljs b/frontend/src/app/main/ui/workspace/viewport/interactions.cljs index 4ba7555ba..7ecc5989a 100644 --- a/frontend/src/app/main/ui/workspace/viewport/interactions.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/interactions.cljs @@ -9,7 +9,6 @@ (:require [app.common.data :as d] [app.common.data.macros :as dm] - [app.common.geom.shapes :as gsh] [app.common.pages.helpers :as cph] [app.common.types.shape.interactions :as ctsi] [app.main.data.workspace :as dw] @@ -254,13 +253,11 @@ (mf/defc interactions [{:keys [current-transform objects zoom selected hover-disabled?] :as props}] (let [active-shapes (into [] - (comp (filter #(seq (:interactions %))) - (map gsh/transform-shape)) + (comp (filter #(seq (:interactions %)))) (vals objects)) selected-shapes (into [] - (comp (map (d/getf objects)) - (map gsh/transform-shape)) + (map (d/getf objects)) selected) {:keys [editing-interaction-index diff --git a/frontend/src/app/main/ui/workspace/viewport/outline.cljs b/frontend/src/app/main/ui/workspace/viewport/outline.cljs index a8fd6c2df..416f71625 100644 --- a/frontend/src/app/main/ui/workspace/viewport/outline.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/outline.cljs @@ -72,7 +72,7 @@ "var(--color-primary)" "var(--color-component-highlight)")] (for [shape shapes] [:& outline {:key (str "outline-" (:id shape)) - :shape (gsh/transform-shape shape) + :shape shape :zoom zoom :color color}]))) diff --git a/frontend/src/app/main/ui/workspace/viewport/selection.cljs b/frontend/src/app/main/ui/workspace/viewport/selection.cljs index 65d1958e4..b42fbbc36 100644 --- a/frontend/src/app/main/ui/workspace/viewport/selection.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/selection.cljs @@ -341,7 +341,7 @@ (let [shape (mf/use-memo (mf/deps shapes) #(->> shapes - (map gsh/transform-shape) + #_(map gsh/transform-shape) (gsh/selection-rect) (cts/setup-shape))) on-resize @@ -369,7 +369,7 @@ (let [shape (mf/use-memo (mf/deps shapes) #(->> shapes - (map gsh/transform-shape) + #_(map gsh/transform-shape) (gsh/selection-rect) (cts/setup-shape)))] @@ -384,7 +384,7 @@ (mf/defc single-handlers [{:keys [shape zoom color disable-handlers] :as props}] (let [shape-id (:id shape) - shape (gsh/transform-shape shape) + ;;shape (gsh/transform-shape shape) on-resize (fn [current-position _initial-position event] @@ -408,14 +408,13 @@ (mf/defc single-selection [{:keys [shape zoom color disable-handlers on-move-selected on-context-menu] :as props}] - (let [shape (gsh/transform-shape shape)] - [:& controls-selection - {:shape shape - :zoom zoom - :color color - :disable-handlers disable-handlers - :on-move-selected on-move-selected - :on-context-menu on-context-menu}])) + [:& controls-selection + {:shape shape + :zoom zoom + :color color + :disable-handlers disable-handlers + :on-move-selected on-move-selected + :on-context-menu on-context-menu}]) (mf/defc selection-area {::mf/wrap [mf/memo]} diff --git a/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs b/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs index 1ef1bf79c..8b8892ea9 100644 --- a/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs @@ -50,20 +50,14 @@ :opacity line-opacity}]) (defn get-snap - [coord {:keys [shapes page-id remove-snap? zoom modifiers]}] - (let [shapes-sr - (->> shapes - ;; Merge modifiers into shapes - (map #(merge % (get modifiers (:id %)))) - ;; Create the bounding rectangle for the shapes - (gsh/selection-rect)) + [coord {:keys [shapes page-id remove-snap? zoom]}] + (let [bounds (gsh/selection-rect shapes) + frame-id (snap/snap-frame-id shapes)] - frame-id (snap/snap-frame-id shapes)] - - (->> (rx/of shapes-sr) + (->> (rx/of bounds) (rx/flat-map - (fn [selrect] - (->> (sp/selrect-snap-points selrect) + (fn [bounds] + (->> (sp/selrect-snap-points bounds) (map #(vector frame-id %))))) (rx/flat-map @@ -159,7 +153,7 @@ (mf/defc snap-points {::mf/wrap [mf/memo]} - [{:keys [layout zoom objects selected page-id drawing modifiers focus] :as props}] + [{:keys [layout zoom objects selected page-id drawing focus] :as props}] (us/assert set? selected) (let [shapes (into [] (keep (d/getf objects)) selected) @@ -182,6 +176,5 @@ [:& snap-feedback {:shapes shapes :page-id page-id :remove-snap? remove-snap? - :zoom zoom - :modifiers modifiers}])) + :zoom zoom}])) diff --git a/frontend/src/app/main/ui/workspace/viewport/utils.cljs b/frontend/src/app/main/ui/workspace/viewport/utils.cljs index 3c36704cc..40b54f43c 100644 --- a/frontend/src/app/main/ui/workspace/viewport/utils.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/utils.cljs @@ -53,9 +53,7 @@ (defn text-transform [{:keys [x y]} zoom] (let [inv-zoom (/ 1 zoom)] - (str - "scale(" inv-zoom ", " inv-zoom ") " - "translate(" (* zoom x) ", " (* zoom y) ")"))) + (dm/fmt "scale(%, %) translate(%, %)" inv-zoom inv-zoom (* zoom x) (* zoom y)))) (defn title-transform [frame zoom] (let [frame-transform (gsh/transform-str frame {:no-flip true}) diff --git a/frontend/src/app/main/ui/workspace/viewport/widgets.cljs b/frontend/src/app/main/ui/workspace/viewport/widgets.cljs index 42596402e..9da2e1673 100644 --- a/frontend/src/app/main/ui/workspace/viewport/widgets.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/widgets.cljs @@ -9,7 +9,6 @@ [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.types.shape-tree :as ctt] [app.common.uuid :as uuid] [app.main.data.workspace :as dw] @@ -182,8 +181,8 @@ :on-frame-select on-frame-select}]))])) (mf/defc frame-flow - [{:keys [flow frame modifiers selected? zoom on-frame-enter on-frame-leave on-frame-select]}] - (let [{:keys [x y]} (gsh/transform-shape frame) + [{:keys [flow frame selected? zoom on-frame-enter on-frame-leave on-frame-select]}] + (let [{:keys [x y]} frame flow-pos (gpt/point x (- y (/ 35 zoom))) on-mouse-down @@ -217,9 +216,7 @@ :y -15 :width 100000 :height 24 - :transform (str (when (and selected? modifiers) - (str (:displacement modifiers) " " )) - (vwu/text-transform flow-pos zoom))} + :transform (vwu/text-transform flow-pos zoom)} [:div.flow-badge {:class (dom/classnames :selected selected?)} [:div.content {:on-mouse-down on-mouse-down :on-double-click on-double-click @@ -234,7 +231,6 @@ (let [flows (unchecked-get props "flows") objects (unchecked-get props "objects") zoom (unchecked-get props "zoom") - modifiers (unchecked-get props "modifiers") selected (or (unchecked-get props "selected") #{}) on-frame-enter (unchecked-get props "on-frame-enter") @@ -248,7 +244,6 @@ :frame frame :selected? (contains? selected (:id frame)) :zoom zoom - :modifiers modifiers :on-frame-enter on-frame-enter :on-frame-leave on-frame-leave :on-frame-select on-frame-select}]))])) diff --git a/frontend/src/app/util/geom/snap_points.cljs b/frontend/src/app/util/geom/snap_points.cljs index ea2084c87..a6120d50f 100644 --- a/frontend/src/app/util/geom/snap_points.cljs +++ b/frontend/src/app/util/geom/snap_points.cljs @@ -29,10 +29,9 @@ (defn shape-snap-points [{:keys [hidden blocked] :as shape}] (when (and (not blocked) (not hidden)) - (let [shape (gsh/transform-shape shape)] - (case (:type shape) - :frame (-> shape :points gsh/points->selrect frame-snap-points) - (into #{(gsh/center-shape shape)} (:points shape)))))) + (case (:type shape) + :frame (-> shape :points gsh/points->selrect frame-snap-points) + (into #{(gsh/center-shape shape)} (:points shape))))) (defn guide-snap-points [guide frame] From 8d9ed4f8af8bba6b04d18266409158326002e184 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 30 Sep 2022 15:36:30 +0200 Subject: [PATCH 03/36] :sparkles: Fill elements in auto-layout --- common/src/app/common/geom/shapes/layout.cljc | 150 +++++++++++++----- .../app/common/geom/shapes/transforms.cljc | 1 + common/src/app/common/types/modifiers.cljc | 5 + .../shapes/frame/dynamic_modifiers.cljs | 50 +++--- .../shapes/text/viewport_texts_html.cljs | 27 ++-- .../sidebar/options/menus/constraints.cljs | 2 +- .../sidebar/options/menus/measures.cljs | 2 +- .../src/app/main/ui/workspace/viewport.cljs | 2 +- .../ui/workspace/viewport/frame_grid.cljs | 3 +- 9 files changed, 162 insertions(+), 80 deletions(-) diff --git a/common/src/app/common/geom/shapes/layout.cljc b/common/src/app/common/geom/shapes/layout.cljc index e6f7cc70e..658b09fc7 100644 --- a/common/src/app/common/geom/shapes/layout.cljc +++ b/common/src/app/common/geom/shapes/layout.cljc @@ -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])) + diff --git a/common/src/app/common/geom/shapes/transforms.cljc b/common/src/app/common/geom/shapes/transforms.cljc index 8b1dfaa36..5f1d160b6 100644 --- a/common/src/app/common/geom/shapes/transforms.cljc +++ b/common/src/app/common/geom/shapes/transforms.cljc @@ -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))) diff --git a/common/src/app/common/types/modifiers.cljc b/common/src/app/common/types/modifiers.cljc index 963bcd74f..7c8658cfb 100644 --- a/common/src/app/common/types/modifiers.cljc +++ b/common/src/app/common/types/modifiers.cljc @@ -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)))) diff --git a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs index 565cca9d5..0ea026601 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs @@ -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)))) diff --git a/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs b/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs index e104b64fa..74e8057e0 100644 --- a/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs @@ -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)) ] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs index d7ea7c715..4d22ffa54 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs @@ -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)] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs index 307b19164..8a9e73f3c 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs @@ -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 diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index f5044bd0d..5a4be44ca 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -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? diff --git a/frontend/src/app/main/ui/workspace/viewport/frame_grid.cljs b/frontend/src/app/main/ui/workspace/viewport/frame_grid.cljs index a26d7c6ab..c7b403286 100644 --- a/frontend/src/app/main/ui/workspace/viewport/frame_grid.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/frame_grid.cljs @@ -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}]))])) From bc890a0b33bb1bbb58ba25ee3a9cfc81ff1881e3 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Tue, 4 Oct 2022 18:12:08 +0200 Subject: [PATCH 04/36] :sparkles: Refactor frames --- common/src/app/common/geom/shapes.cljc | 3 + .../app/common/geom/shapes/constraints.cljc | 16 +- common/src/app/common/geom/shapes/layout.cljc | 7 +- .../app/common/geom/shapes/layout_new.cljc | 606 ++++++++++++++++++ .../src/app/common/geom/shapes/modifiers.cljc | 115 ++-- .../app/common/geom/shapes/transforms.cljc | 16 + .../app/main/ui/workspace/shapes/frame.cljs | 5 +- 7 files changed, 716 insertions(+), 52 deletions(-) create mode 100644 common/src/app/common/geom/shapes/layout_new.cljc diff --git a/common/src/app/common/geom/shapes.cljc b/common/src/app/common/geom/shapes.cljc index a217d5322..5364b9daa 100644 --- a/common/src/app/common/geom/shapes.cljc +++ b/common/src/app/common/geom/shapes.cljc @@ -177,6 +177,8 @@ (dm/export gtr/move-position-data) (dm/export gtr/apply-transform) (dm/export gtr/apply-objects-modifiers) +(dm/export gtr/parent-coords-rect) +(dm/export gtr/parent-coords-points) ;; Constratins (dm/export gct/calc-child-modifiers) @@ -210,3 +212,4 @@ ;; Modifiers (dm/export gsm/set-objects-modifiers) + diff --git a/common/src/app/common/geom/shapes/constraints.cljc b/common/src/app/common/geom/shapes/constraints.cljc index 49db8a69d..0c898348f 100644 --- a/common/src/app/common/geom/shapes/constraints.cljc +++ b/common/src/app/common/geom/shapes/constraints.cljc @@ -261,18 +261,8 @@ "Before aplying constraints we need to remove the deformation caused by the resizing of the parent" [constraints-h constraints-v modifiers child parent transformed-child transformed-parent] - (let [child-bb-before - (-> child - :points - (gco/transform-points (:transform-inverse parent)) - (gre/points->rect)) - - child-bb-after - (-> transformed-child - :points - (gco/transform-points (:transform-inverse transformed-parent)) - (gre/points->rect)) - + (let [child-bb-before (gst/parent-coords-rect child parent) + child-bb-after (gst/parent-coords-rect transformed-child transformed-parent) scale-x (/ (:width child-bb-before) (:width child-bb-after)) scale-y (/ (:height child-bb-before) (:height child-bb-after))] @@ -332,3 +322,5 @@ transformed-parent)] (update modifiers :v2 d/concat-vec modifiers-h modifiers-v))))) + + diff --git a/common/src/app/common/geom/shapes/layout.cljc b/common/src/app/common/geom/shapes/layout.cljc index 658b09fc7..73c08864a 100644 --- a/common/src/app/common/geom/shapes/layout.cljc +++ b/common/src/app/common/geom/shapes/layout.cljc @@ -120,7 +120,7 @@ (cond-> layout-lines (some? line-data) (conj line-data)))) (defn calc-layout-lines-position - [{:keys [layout-gap layout-type] :as shape} {:keys [x y width height]} layout-lines] + [{:keys [layout-gap layout-type] :as shape} {:keys [x y width height] :as layout-bounds} layout-lines] (letfn [(get-base-line [total-width total-height] @@ -414,8 +414,9 @@ (defn calc-layout-modifiers "Calculates the modifiers for the layout" - [parent transform child layout-data] - (let [child-bounds (-> child :points gre/points->selrect) + [parent child layout-data] + (let [transform (:transform parent) + child-bounds (-> child :points gre/points->selrect) fill-width (calc-fill-width-data child-bounds parent child layout-data) fill-height (calc-fill-height-data child-bounds parent child layout-data) diff --git a/common/src/app/common/geom/shapes/layout_new.cljc b/common/src/app/common/geom/shapes/layout_new.cljc new file mode 100644 index 000000000..a15d03870 --- /dev/null +++ b/common/src/app/common/geom/shapes/layout_new.cljc @@ -0,0 +1,606 @@ +;; 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.layout-new + (:require + [app.common.data :as d] + [app.common.geom.point :as gpt] + [app.common.geom.shapes.rect :as gre] + [app.common.geom.shapes.transforms :as gst] + )) + +;; :layout ;; true if active, false if not +;; :layout-dir ;; :right, :left, :top, :bottom +;; :layout-gap ;; number could be negative +;; :layout-type ;; :packed, :space-between, :space-around +;; :layout-wrap-type ;; :wrap, :no-wrap +;; :layout-padding-type ;; :simple, :multiple +;; :layout-padding ;; {:p1 num :p2 num :p3 num :p4 num} number could be negative +;; :layout-h-orientation ;; :top, :center, :bottom +;; :layout-v-orientation ;; :left, :center, :right + +(defn col? + [{:keys [layout-dir]}] + (or (= :right layout-dir) (= :left layout-dir))) + +(defn row? + [{:keys [layout-dir]}] + (or (= :top layout-dir) (= :bottom layout-dir))) + +(defn h-start? + [{:keys [layout-h-orientation]}] + (= layout-h-orientation :left)) + +(defn h-center? + [{:keys [layout-h-orientation]}] + (= layout-h-orientation :center)) + +(defn h-end? + [{:keys [layout-h-orientation]}] + (= layout-h-orientation :right)) + +(defn v-start? + [{:keys [layout-v-orientation]}] + (= layout-v-orientation :top)) + +(defn v-center? + [{:keys [layout-v-orientation]}] + (= layout-v-orientation :center)) + +(defn v-end? + [{:keys [layout-v-orientation]}] + (= layout-v-orientation :bottom)) + +(defn add-padding [transformed-rect {:keys [layout-padding-type layout-padding]}] + (let [{:keys [p1 p2 p3 p4]} layout-padding + [p1 p2 p3 p4] + (if (= layout-padding-type :multiple) + [p1 p2 p3 p4] + [p1 p1 p1 p1])] + + (-> transformed-rect + (update :y + p1) + (update :width - p2 p3) + (update :x + p3) + (update :height - p1 p4)))) + +;; FUNCTIONS TO WORK WITH POINTS SQUARES + +(defn origin + [points] + (nth points 0)) + +(defn start-hv + "Horizontal vector from the origin with a magnitude `val`" + [[p0 p1 p2 p3] val] + (-> (gpt/to-vec p0 p1) + (gpt/unit) + (gpt/scale val))) + +(defn end-hv + "Horizontal vector from the oposite to the origin in the x axis with a magnitude `val`" + [[p0 p1 p2 p3] val] + (-> (gpt/to-vec p1 p0) + (gpt/unit) + (gpt/scale val))) + +(defn start-vv + "Vertical vector from the oposite to the origin in the x axis with a magnitude `val`" + [[p0 p1 p2 p3] val] + (-> (gpt/to-vec p0 p3) + (gpt/unit) + (gpt/scale val))) + +(defn end-vv + "Vertical vector from the oposite to the origin in the x axis with a magnitude `val`" + [[p0 p1 p2 p3] val] + (-> (gpt/to-vec p3 p0) + (gpt/unit) + (gpt/scale val))) + +;;(defn start-hp +;; [[p0 _ _ _ :as points] val] +;; (gpt/add p0 (start-hv points val))) +;; +;;(defn end-hp +;; "Horizontal Vector from the oposite to the origin in the x axis with a magnitude `val`" +;; [[_ p1 _ _ :as points] val] +;; (gpt/add p1 (end-hv points val))) +;; +;;(defn start-vp +;; "Vertical Vector from the oposite to the origin in the x axis with a magnitude `val`" +;; [[p0 _ _ _ :as points] val] +;; (gpt/add p0 (start-vv points val))) +;; +;;(defn end-vp +;; "Vertical Vector from the oposite to the origin in the x axis with a magnitude `val`" +;; [[_ _ p3 _ :as points] val] +;; (gpt/add p3 (end-vv points val))) + +(defn width-points + [[p0 p1 p2 p3]] + (gpt/length (gpt/to-vec p0 p1))) + +(defn height-points + [[p0 p1 p2 p3]] + (gpt/length (gpt/to-vec p0 p3))) + +(defn pad-points + [[p0 p1 p2 p3 :as points] pad-top pad-right pad-bottom pad-left] + (let [top-v (start-vv points pad-top) + right-v (end-hv points pad-right) + bottom-v (end-vv points pad-bottom) + left-v (start-hv points pad-left)] + + [(-> p0 (gpt/add left-v) (gpt/add top-v)) + (-> p1 (gpt/add right-v) (gpt/add top-v)) + (-> p2 (gpt/add right-v) (gpt/add bottom-v)) + (-> p3 (gpt/add left-v) (gpt/add bottom-v))])) + +;;;; + + +(defn calc-layout-lines + [{:keys [layout-gap layout-wrap-type] :as parent} children layout-bounds] + + (let [wrap? (= layout-wrap-type :wrap) + layout-width (width-points layout-bounds) + layout-height (height-points layout-bounds) + + reduce-fn + (fn [[{:keys [line-width line-height num-children line-fill? child-fill? num-child-fill] :as line-data} result] child] + (let [child-bounds (gst/parent-coords-points child parent) + child-width (width-points child-bounds) + child-height (height-points child-bounds) + + col? (col? parent) + row? (row? parent) + + cur-child-fill? + (or (and col? (= :fill (:layout-h-behavior child))) + (and row? (= :fill (:layout-v-behavior child)))) + + cur-line-fill? + (or (and row? (= :fill (:layout-h-behavior child))) + (and col? (= :fill (:layout-v-behavior child)))) + + ;; TODO LAYOUT: ADD MINWIDTH/HEIGHT + next-width (if (or (and col? cur-child-fill?) + (and row? cur-line-fill?)) + 0 + child-width) + + next-height (if (or (and row? cur-child-fill?) + (and col? cur-line-fill?)) + 0 + child-height) + + next-total-width (+ line-width next-width (* layout-gap num-children)) + next-total-height (+ line-height next-height (* layout-gap num-children))] + + (if (and (some? line-data) + (or (not wrap?) + (and col? (<= next-total-width layout-width)) + (and row? (<= next-total-height layout-height)))) + + ;; When :fill we add min width (0 by default) + [{:line-width (if col? (+ line-width next-width) (max line-width next-width)) + :line-height (if row? (+ 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? 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)] + + (cond-> layout-lines (some? line-data) (conj line-data)))) + +(defn calc-layout-lines-position + [{:keys [layout-gap layout-type] :as parent} layout-bounds layout-lines] + + (let [layout-width (width-points layout-bounds) + layout-height (height-points layout-bounds) + row? (row? parent) + col? (col? parent) + h-center? (h-center? parent) + h-end? (h-end? parent) + v-center? (v-center? parent) + v-end? (v-end? parent) + space-between? (= :space-between layout-type) + space-around? (= :space-around layout-type)] + + (letfn [(get-base-line + [total-width total-height] + + (cond-> (origin layout-bounds) + (and row? h-center?) + (gpt/add (start-hv layout-bounds (/ (- layout-width total-width) 2))) + + (and row? h-end?) + (gpt/add (start-hv layout-bounds (- layout-width total-width))) + + (and col? v-center?) + (gpt/add (start-vv layout-bounds (/ (- layout-height total-height) 2))) + + (and col? v-end?) + (gpt/add (start-vv layout-bounds (- layout-height total-height))) + )) + + (get-start-line + [{:keys [line-width line-height num-children child-fill?]} base-p] + + (let [children-gap (* layout-gap (dec num-children)) + + ;;line-width (if (and col? child-fill?) + ;; (- layout-width (* layout-gap num-children)) + ;; line-width) + ;; + ;;line-height (if (and row? child-fill?) + ;; (- layout-height (* layout-gap num-children)) + ;; line-height) + + + start-p + (cond-> base-p + ;; X AXIS + (and col? h-center? (not space-between?) (not space-around?)) + (-> (gpt/add (start-hv layout-bounds (/ layout-width 2))) + (gpt/subtract (start-hv layout-bounds (/ (+ line-width children-gap) 2)))) + + (and col? h-end? (not space-between?) (not space-around?)) + (-> (gpt/add (start-hv layout-bounds layout-width)) + (gpt/subtract (start-hv layout-bounds (+ line-width children-gap)))) + + (and row? h-center? (not space-between?) (not space-around?)) + (gpt/add (start-hv layout-bounds (/ line-width 2))) + + (and row? h-end? (not space-between?) (not space-around?)) + (gpt/add (start-hv layout-bounds line-width)) + + ;; Y AXIS + (and row? v-center? (not space-between?) (not space-around?)) + (-> (gpt/add (start-vv layout-bounds (/ layout-height 2))) + (gpt/subtract (start-vv layout-bounds (/ (+ line-height children-gap) 2)))) + + (and row? v-end? (not space-between?) (not space-around?)) + (-> (gpt/add (start-vv layout-bounds layout-height)) + (gpt/subtract (start-vv layout-bounds (+ line-height children-gap)))) + + (and col? v-center? (not space-between?) (not space-around?)) + (gpt/add (start-vv layout-bounds (/ line-height 2))) + + (and col? v-end? (not space-between?) (not space-around?)) + (gpt/add (start-vv layout-bounds line-height)) + + ) + + + ;;start-x + ;;(cond + ;; ;;(and (col? shape) child-fill?) + ;; ;; TODO LAYOUT: Start has to take into account max-width + ;; ;;x + ;; + ;; (or (and col? space-between?) (and col? space-around?)) + ;; x + ;; + ;; (and col? h-center?) + ;; (- (+ x (/ width 2)) (/ (+ line-width children-gap) 2)) + ;; + ;; (and col? h-end?) + ;; (- (+ x width) (+ line-width children-gap)) + ;; + ;; (and row? h-center?) + ;; (+ base-x (/ line-width 2)) + ;; + ;; (and row? h-end?) + ;; (+ base-x line-width) + ;; + ;; row? + ;; base-x + ;; + ;; :else + ;; x) + + ;;start-y + ;;(cond + ;; ;; (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 + ;; + ;; (and (row? shape) (v-center? shape)) + ;; (- (+ y (/ height 2)) (/ (+ line-height children-gap) 2)) + ;; + ;; (and (row? shape) (v-end? shape)) + ;; (- (+ y height) (+ line-height children-gap)) + ;; + ;; (and (col? shape) (v-center? shape)) + ;; (+ base-y (/ line-height 2)) + ;; + ;; (and (col? shape) (v-end? shape)) + ;; (+ base-y line-height) + ;; + ;; (col? shape) + ;; base-y + ;; + ;; :else + ;; y) + ] + + start-p)) + + (get-next-line + [{:keys [line-width line-height]} base-p] + + (cond-> base-p + col? + (gpt/add (start-hv layout-bounds (+ line-width layout-gap))) + + row? + (gpt/add (start-vv layout-bounds (+ line-height layout-gap))) + ) + + #_(let [next-x (if col? base-x (+ base-x line-width layout-gap)) + next-y (if row? base-y (+ base-y line-height layout-gap))] + [next-x next-y])) + + (add-lines [[total-width total-height] {:keys [line-width line-height]}] + [(+ total-width line-width) + (+ total-height line-height)]) + + (add-starts [[result base-p] layout-line] + (let [start-p (get-start-line layout-line base-p) + next-p (get-next-line layout-line base-p)] + [(conj result + (assoc layout-line :start-p start-p)) + next-p]))] + + (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 (- layout-height total-height) + horizontal-fill-space (- layout-width total-width) + num-line-fill (count (->> layout-lines (filter :line-fill?))) + + layout-lines + (->> layout-lines + (mapv #(cond-> % + (and col? (:line-fill? %)) + (update :line-height + (/ vertical-fill-space num-line-fill)) + + (and row? (:line-fill? %)) + (update :line-width + (/ horizontal-fill-space num-line-fill))))) + + total-height (if (and col? (> num-line-fill 0)) layout-height total-height) + total-width (if (and row? (> num-line-fill 0)) layout-width total-width) + + base-p (get-base-line total-width total-height) + + [layout-lines _ _ _ _] + (reduce add-starts [[] base-p] layout-lines)] + layout-lines)))) + +(defn calc-layout-line-data + [{:keys [layout-type layout-gap] :as shape} + {:keys [width height] :as layout-bounds} + {:keys [num-children line-width line-height] :as line-data}] + + (let [layout-gap + (cond + (= :packed layout-type) + layout-gap + + (= :space-around layout-type) + 0 + + (and (col? shape) (= :space-between layout-type)) + (/ (- width line-width) (dec num-children)) + + (and (row? shape) (= :space-between layout-type)) + (/ (- height line-height) (dec num-children))) + + margin-x + (if (and (col? shape) (= :space-around layout-type)) + (/ (- width line-width) (inc num-children) ) + 0) + + margin-y + (if (and (row? shape) (= :space-around layout-type)) + (/ (- height line-height) (inc num-children)) + 0)] + + (assoc line-data + :layout-bounds layout-bounds + :layout-gap layout-gap + :margin-x margin-x + :margin-y margin-y))) + +(defn next-p + "Calculates the position for the current shape given the layout-data context" + [parent + child-bounds + {:keys [start-p layout-gap margin-x margin-y] :as layout-data}] + + (let [width (width-points child-bounds) + height (height-points child-bounds) + + row? (row? parent) + col? (col? parent) + h-center? (h-center? parent) + h-end? (h-end? parent) + v-center? (v-center? parent) + v-end? (v-end? parent) + points (:points parent) + + corner-p + (cond-> start-p + (and row? h-center?) + (gpt/add (start-hv points (- (/ width 2)))) + + (and row? h-end?) + (gpt/add (start-hv points (- width))) + + (and col? v-center?) + (gpt/add (start-vv points (- (/ height 2)))) + + (and col? v-end?) + (gpt/add (start-vv points (- height))) + + (some? margin-x) + (gpt/add (start-hv points margin-x)) + + (some? margin-y) + (gpt/add (start-vv points margin-y))) + + next-p + (cond-> start-p + col? + (gpt/add (start-hv points (+ width layout-gap))) + + row? + (gpt/add (start-vv points (+ height layout-gap))) + + (some? margin-x) + (gpt/add (start-hv points margin-x)) + + (some? margin-y) + (gpt/add (start-vv points margin-y))) + + layout-data + (assoc layout-data :start-p next-p)] + + [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 normalize-child-modifiers + "Apply the modifiers and then normalized them against the parent coordinates" + [parent child modifiers transformed-parent] + + (let [transformed-child (gst/transform-shape child modifiers) + child-bb-before (gst/parent-coords-rect child parent) + child-bb-after (gst/parent-coords-rect transformed-child transformed-parent) + scale-x (/ (:width child-bb-before) (:width child-bb-after)) + scale-y (/ (:height child-bb-before) (:height child-bb-after))] + (-> modifiers + (update :v2 #(conj % + {:type :resize + :transform (:transform transformed-parent) + :transform-inverse (:transform-inverse transformed-parent) + :origin (-> transformed-parent :points (nth 0)) + :vector (gpt/point scale-x scale-y)}))))) + +(defn calc-layout-data + "Digest the layout data to pass it to the constrains" + [{:keys [layout-dir points layout-padding layout-padding-type] :as parent} children] + + (let [;; Add padding to the bounds + {pad-top :p1 pad-right :p2 pad-bottom :p3 pad-left :p4} layout-padding + [pad-top pad-right pad-bottom pad-left] + (if (= layout-padding-type :multiple) + [pad-top pad-right pad-bottom pad-left] + [pad-top pad-top pad-top pad-top]) + layout-bounds (-> points (pad-points pad-top pad-right pad-bottom pad-left)) + + ;; Reverse + reverse? (or (= :left layout-dir) (= :bottom layout-dir)) + children (cond->> children reverse? reverse) + + ;; Creates the layout lines information + layout-lines + (->> (calc-layout-lines parent children layout-bounds) + (calc-layout-lines-position parent layout-bounds) + (map (partial calc-layout-line-data parent layout-bounds)))] + + {:layout-lines layout-lines + :reverse? reverse?})) + +(defn calc-layout-modifiers + "Calculates the modifiers for the layout" + [parent child layout-line] + (let [child-bounds (gst/parent-coords-points child parent) + + ;;fill-width (calc-fill-width-data child-bounds parent child layout-line) + ;;fill-height (calc-fill-height-data child-bounds parent child layout-line) + + ;;child-bounds (cond-> child-bounds + ;; fill-width (merge (:bounds fill-width)) + ;; fill-height (merge (:bounds fill-height))) + + + [corner-p layout-line] (next-p parent child-bounds layout-line) + + move-vec (gpt/to-vec (origin child-bounds) corner-p) + + modifiers + (-> [] + #_(cond-> fill-width (d/concat-vec (:modifiers fill-width))) + #_(cond-> fill-height (d/concat-vec (:modifiers fill-height))) + (conj {:type :move :vector move-vec}))] + + [modifiers layout-line])) + diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index 4645a6582..fc987dfc9 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -11,7 +11,8 @@ [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.layout :as gclo] + [app.common.geom.shapes.layout-new :as gcln] [app.common.geom.shapes.rect :as gpr] [app.common.geom.shapes.transforms :as gtr] [app.common.math :as mth] @@ -108,40 +109,21 @@ (defn set-children-modifiers - [modif-tree objects shape ignore-constraints snap-pixel?] + [modif-tree objects parent ignore-constraints snap-pixel?] ;; TODO LAYOUT: SNAP PIXEL! (letfn [(set-child [transformed-parent _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-parent) - - ;;_ (.log js/console (:name child) (clj->js child-modifiers)) - + (let [modifiers (get-in modif-tree [(:id parent) :modifiers]) + child-modifiers (gct/calc-child-modifiers parent child modifiers ignore-constraints transformed-parent) ;;child-modifiers (cond-> child-modifiers snap-pixel? (set-pixel-precision child)) - - result - (cond-> modif-tree - (not (ctm/empty-modifiers? child-modifiers)) - (update-in [(:id child) :modifiers :v2] #(d/concat-vec % (:v2 child-modifiers))) - #_(update-in [(:id child) :modifiers] #(merge-mod2 child-modifiers %)) - #_(update-in [(:id child) :modifiers] #(merge child-modifiers %))) - - ;;_ (.log js/console ">>>" (:name child)) - ;;_ (.log js/console " >" (clj->js child-modifiers)) - ;;_ (.log js/console " >" (clj->js (get-in modif-tree [(:id child) :modifiers]))) - ;;_ (.log js/console " >" (clj->js (get-in result [(:id child) :modifiers]))) ] - result - )) - ] - (let [children (map (d/getf objects) (:shapes shape)) - modifiers (get-in modif-tree [(:id shape) :modifiers]) - ;; transformed-rect (gtr/transform-selrect (:selrect shape) modifiers) - ;; transformed-rect (-> shape (merge {:modifiers modifiers}) gtr/transform-shape :selrect) - transformed-parent (-> shape (merge {:modifiers modifiers}) gtr/transform-shape) + (cond-> modif-tree + (not (ctm/empty-modifiers? child-modifiers)) + (update-in [(:id child) :modifiers :v2] d/concat-vec (:v2 child-modifiers)))))] - resize-modif? (or (:resize-vector modifiers) (:resize-vector-2 modifiers))] - (reduce (partial set-child transformed-parent (and snap-pixel? resize-modif?)) modif-tree children)))) + (let [children (map (d/getf objects) (:shapes parent)) + modifiers (get-in modif-tree [(:id parent) :modifiers]) + transformed-parent (gtr/transform-shape parent modifiers)] + (reduce (partial set-child transformed-parent snap-pixel?) modif-tree children)))) (defn group? [shape] (or (= :group (:type shape)) @@ -158,6 +140,68 @@ ;; TODO LAYOUT: SNAP PIXEL! [modif-tree objects parent _snap-pixel?] + (letfn [(normalize-child [transformed-parent _snap-pixel? modif-tree child] + (let [modifiers (get-in modif-tree [(:id parent) :modifiers]) + child-modifiers (gcln/normalize-child-modifiers parent child modifiers transformed-parent)] + (cond-> modif-tree + (not (ctm/empty-modifiers? child-modifiers)) + (update-in [(:id child) :modifiers :v2] d/concat-vec (:v2 child-modifiers))))) + + (apply-modifiers [modif-tree child] + (let [modifiers (get-in modif-tree [(:id child) :modifiers])] + (cond-> child + (some? modifiers) + (gtr/transform-shape modifiers) + + (and (nil? modifiers) (group? child)) + (gtr/apply-group-modifiers objects modif-tree)))) + + (set-layout-modifiers [parent [layout-line modif-tree] child] + (let [[modifiers layout-line] + (gcln/calc-layout-modifiers parent child layout-line) + + modif-tree + (cond-> modif-tree + (d/not-empty? modifiers) + (update-in [(:id child) :modifiers :v2] d/concat-vec modifiers))] + + [layout-line modif-tree]))] + + (let [children (map (d/getf objects) (:shapes parent)) + modifiers (get-in modif-tree [(:id parent) :modifiers]) + transformed-parent (gtr/transform-shape parent modifiers) + + modif-tree (reduce (partial normalize-child transformed-parent _snap-pixel?) modif-tree children) + + children (->> children (map (partial apply-modifiers modif-tree))) + + layout-data (gcln/calc-layout-data transformed-parent children) + + children (into [] (cond-> children (:reverse? layout-data) reverse)) + + max-idx (dec (count children)) + layout-lines (:layout-lines layout-data)] + + (loop [modif-tree modif-tree + layout-line (first layout-lines) + pending (rest layout-lines) + from-idx 0] + + + (if (and (some? layout-line) (<= from-idx max-idx)) + (let [to-idx (+ from-idx (:num-children layout-line)) + children (subvec children from-idx to-idx) + + [_ modif-tree] + (reduce (partial set-layout-modifiers transformed-parent) [layout-line modif-tree] children)] + (recur modif-tree (first pending) (rest pending) to-idx)) + + modif-tree))))) + +#_(defn set-layout-modifiers' + ;; TODO LAYOUT: SNAP PIXEL! + [modif-tree objects parent _snap-pixel?] + (letfn [(transform-child [child] (let [modifiers (get modif-tree (:id child)) @@ -182,8 +226,7 @@ modif-tree (cond-> modif-tree (d/not-empty? modifiers) - (update-in [(:id child) :modifiers :v2] d/concat-vec modifiers) - #_(merge-modifiers [(:id child)] modifiers))] + (update-in [(:id child) :modifiers :v2] d/concat-vec modifiers))] [layout-data modif-tree]))] @@ -218,7 +261,6 @@ [_ modif-tree] (reduce (partial set-layout-modifiers shape transform) [layout-line modif-tree] children)] - (recur modif-tree (first pending) (rest pending) to-idx)) modif-tree))))) @@ -316,11 +358,12 @@ is-inside-layout? (inside-layout? objects shape)] (cond-> modif-tree + (and has-modifiers? is-parent?) + (set-children-modifiers objects shape (or ignore-constraints is-inside-layout?) snap-pixel?) + is-layout? (set-layout-modifiers objects shape snap-pixel?) - - (and has-modifiers? is-parent?) - (set-children-modifiers objects shape (or ignore-constraints is-inside-layout?) snap-pixel?)))) + ))) modif-tree))] diff --git a/common/src/app/common/geom/shapes/transforms.cljc b/common/src/app/common/geom/shapes/transforms.cljc index 5f1d160b6..6c1957519 100644 --- a/common/src/app/common/geom/shapes/transforms.cljc +++ b/common/src/app/common/geom/shapes/transforms.cljc @@ -558,3 +558,19 @@ (apply-group-modifiers shape objects modif-tree) shape)))))] (update-group-selrect group children))) + +(defn parent-coords-rect + [child parent] + (-> child + :points + (gco/transform-points (:transform-inverse parent)) + (gpr/points->rect))) + +(defn parent-coords-points + [child parent] + (-> child + :points + (gco/transform-points (:transform-inverse parent)) + (gpr/points->rect) + (gpr/rect->points) + (gco/transform-points (:transform parent)))) diff --git a/frontend/src/app/main/ui/workspace/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/shapes/frame.cljs index 1de768035..07b57d156 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame.cljs @@ -24,7 +24,10 @@ [app.main.ui.workspace.shapes.frame.node-store :as fns] [app.main.ui.workspace.shapes.frame.thumbnail-render :as ftr] [beicon.core :as rx] - [rumext.v2 :as mf])) + [rumext.v2 :as mf] + + [app.common.geom.shapes.layout :as gsl] + [app.common.geom.point :as gpt])) (defn frame-shape-factory [shape-wrapper] From 8bcb9e19762363a33b46b1e1798cb6391905f375 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Wed, 5 Oct 2022 22:16:48 +0200 Subject: [PATCH 05/36] :sparkles: Autofill vectors calculation --- common/src/app/common/geom/shapes/layout.cljc | 565 +++++++++------- .../app/common/geom/shapes/layout_new.cljc | 606 ------------------ .../src/app/common/geom/shapes/modifiers.cljc | 27 +- .../app/main/ui/workspace/shapes/frame.cljs | 5 +- 4 files changed, 363 insertions(+), 840 deletions(-) delete mode 100644 common/src/app/common/geom/shapes/layout_new.cljc diff --git a/common/src/app/common/geom/shapes/layout.cljc b/common/src/app/common/geom/shapes/layout.cljc index 73c08864a..d0c616e85 100644 --- a/common/src/app/common/geom/shapes/layout.cljc +++ b/common/src/app/common/geom/shapes/layout.cljc @@ -8,10 +8,10 @@ (:require [app.common.data :as d] [app.common.geom.point :as gpt] - [app.common.geom.shapes.rect :as gre])) + [app.common.geom.shapes.transforms :as gst])) ;; :layout ;; true if active, false if not -;; :layout-flex-dir ;; :row, :column, :reverse-row, :reverse-column +;; :layout-dir ;; :right, :left, :top, :bottom ;; :layout-gap ;; number could be negative ;; :layout-type ;; :packed, :space-between, :space-around ;; :layout-wrap-type ;; :wrap, :no-wrap @@ -21,12 +21,12 @@ ;; :layout-v-orientation ;; :left, :center, :right (defn col? - [{:keys [layout-flex-dir]}] - (or (= :column layout-flex-dir) (= :reverse-column layout-flex-dir))) + [{:keys [layout-dir]}] + (or (= :right layout-dir) (= :left layout-dir))) (defn row? - [{:keys [layout-flex-dir]}] - (or (= :row layout-flex-dir) (= :reverse-row layout-flex-dir))) + [{:keys [layout-dir]}] + (or (= :top layout-dir) (= :bottom layout-dir))) (defn h-start? [{:keys [layout-h-orientation]}] @@ -65,42 +65,128 @@ (update :x + p3) (update :height - p1 p4)))) +;; FUNCTIONS TO WORK WITH POINTS SQUARES + +(defn origin + [points] + (nth points 0)) + +(defn start-hv + "Horizontal vector from the origin with a magnitude `val`" + [[p0 p1 _ _] val] + (-> (gpt/to-vec p0 p1) + (gpt/unit) + (gpt/scale val))) + +(defn end-hv + "Horizontal vector from the oposite to the origin in the x axis with a magnitude `val`" + [[p0 p1 _ _] val] + (-> (gpt/to-vec p1 p0) + (gpt/unit) + (gpt/scale val))) + +(defn start-vv + "Vertical vector from the oposite to the origin in the x axis with a magnitude `val`" + [[p0 _ _ p3] val] + (-> (gpt/to-vec p0 p3) + (gpt/unit) + (gpt/scale val))) + +(defn end-vv + "Vertical vector from the oposite to the origin in the x axis with a magnitude `val`" + [[p0 _ _ p3] val] + (-> (gpt/to-vec p3 p0) + (gpt/unit) + (gpt/scale val))) + +;;(defn start-hp +;; [[p0 _ _ _ :as points] val] +;; (gpt/add p0 (start-hv points val))) +;; +;;(defn end-hp +;; "Horizontal Vector from the oposite to the origin in the x axis with a magnitude `val`" +;; [[_ p1 _ _ :as points] val] +;; (gpt/add p1 (end-hv points val))) +;; +;;(defn start-vp +;; "Vertical Vector from the oposite to the origin in the x axis with a magnitude `val`" +;; [[p0 _ _ _ :as points] val] +;; (gpt/add p0 (start-vv points val))) +;; +;;(defn end-vp +;; "Vertical Vector from the oposite to the origin in the x axis with a magnitude `val`" +;; [[_ _ p3 _ :as points] val] +;; (gpt/add p3 (end-vv points val))) + +(defn width-points + [[p0 p1 _ _]] + (gpt/length (gpt/to-vec p0 p1))) + +(defn height-points + [[p0 _ _ p3]] + (gpt/length (gpt/to-vec p0 p3))) + +(defn pad-points + [[p0 p1 p2 p3 :as points] pad-top pad-right pad-bottom pad-left] + (let [top-v (start-vv points pad-top) + right-v (end-hv points pad-right) + bottom-v (end-vv points pad-bottom) + left-v (start-hv points pad-left)] + + [(-> p0 (gpt/add left-v) (gpt/add top-v)) + (-> p1 (gpt/add right-v) (gpt/add top-v)) + (-> p2 (gpt/add right-v) (gpt/add bottom-v)) + (-> p3 (gpt/add left-v) (gpt/add bottom-v))])) + +;;;; + + (defn calc-layout-lines - [{:keys [layout-gap layout-wrap-type] :as shape} children {:keys [width height] :as layout-bounds}] + [{:keys [layout-gap layout-wrap-type] :as parent} children layout-bounds] (let [wrap? (= layout-wrap-type :wrap) + layout-width (width-points layout-bounds) + layout-height (height-points layout-bounds) reduce-fn (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) + (let [child-bounds (gst/parent-coords-points child parent) + child-width (width-points child-bounds) + child-height (height-points child-bounds) + + col? (col? parent) + row? (row? parent) cur-child-fill? - (or (and (col? shape) (= :fill (:layout-h-behavior child))) - (and (row? shape) (= :fill (:layout-v-behavior child)))) + (or (and col? (= :fill (:layout-h-behavior child))) + (and row? (= :fill (:layout-v-behavior child)))) cur-line-fill? - (or (and (row? shape) (= :fill (:layout-h-behavior child))) - (and (col? shape) (= :fill (:layout-v-behavior child)))) + (or (and row? (= :fill (:layout-h-behavior child))) + (and col? (= :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?)) + next-width (if (or (and col? cur-child-fill?) + (and row? cur-line-fill?)) 0 - (-> child-bounds :width)) + child-width) - next-height (if (or (and (row? shape) cur-child-fill?) - (and (col? shape) cur-line-fill?)) + next-height (if (or (and row? cur-child-fill?) + (and col? cur-line-fill?)) 0 - (-> child-bounds :height))] + child-height) + + next-total-width (+ line-width next-width (* layout-gap (dec num-children))) + next-total-height (+ line-height next-height (* layout-gap (dec num-children)))] (if (and (some? line-data) (or (not wrap?) - (and (col? shape) (<= (+ line-width next-width (* layout-gap num-children)) width)) - (and (row? shape) (<= (+ line-height next-height (* layout-gap num-children)) height)))) + (and col? (<= next-total-width layout-width)) + (and row? (<= next-total-height layout-height)))) ;; 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)) + [{:line-width (if col? (+ line-width next-width) (max line-width next-width)) + :line-height (if row? (+ 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?) @@ -120,155 +206,148 @@ (cond-> layout-lines (some? line-data) (conj line-data)))) (defn calc-layout-lines-position - [{:keys [layout-gap layout-type] :as shape} {:keys [x y width height] :as layout-bounds} layout-lines] + [{:keys [layout-gap] :as parent} layout-bounds layout-lines] - (letfn [(get-base-line - [total-width total-height] + (let [layout-width (width-points layout-bounds) + layout-height (height-points layout-bounds) + row? (row? parent) + col? (col? parent) + h-center? (h-center? parent) + h-end? (h-end? parent) + v-center? (v-center? parent) + v-end? (v-end? parent)] - (let [base-x - (cond - (and (row? shape) (h-center? shape)) - (+ x (/ (- width total-width) 2)) + (letfn [;; short version to not repeat always with all arguments + (xv [val] + (start-hv layout-bounds val)) - (and (row? shape) (h-end? shape)) - (+ x width (- total-width)) + ;; short version to not repeat always with all arguments + (yv [val] + (start-vv layout-bounds val)) - :else x) + (get-base-line + [total-width total-height] - base-y - (cond - (and (col? shape) (v-center? shape)) - (+ y (/ (- height total-height) 2)) + (cond-> (origin layout-bounds) + (and row? h-center?) + (gpt/add (xv (/ (- layout-width total-width) 2))) - (and (col? shape) (v-end? shape)) - (+ y height (- total-height)) + (and row? h-end?) + (gpt/add (xv (- layout-width total-width))) - :else y)] + (and col? v-center?) + (gpt/add (yv (/ (- layout-height total-height) 2))) - [base-x base-y])) + (and col? v-end?) + (gpt/add (yv (- layout-height total-height))))) - (get-start-line - [{:keys [line-width line-height num-children child-fill?]} base-x base-y] + (get-start-line + [{:keys [line-width line-height num-children child-fill?]} base-p] - (let [children-gap (* layout-gap (dec num-children)) + (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) + line-width (if (and col? child-fill?) + (- layout-width (* layout-gap (dec num-children))) + line-width) - start-x - (cond - ;;(and (col? shape) child-fill?) - ;;;; TODO LAYOUT: Start has to take into account max-width - ;;x + line-height (if (and row? child-fill?) + (- layout-height (* layout-gap (dec num-children))) + line-height) - (or (and (col? shape) (= :space-between layout-type)) - (and (col? shape) (= :space-around layout-type))) - x + start-p + (cond-> base-p + ;; X AXIS + (and col? h-center?) + (-> (gpt/add (xv (/ layout-width 2))) + (gpt/subtract (xv (/ (+ line-width children-gap) 2)))) - (and (col? shape) (h-center? shape)) - (- (+ x (/ width 2)) (/ (+ line-width children-gap) 2)) + (and col? h-end?) + (-> (gpt/add (xv layout-width)) + (gpt/subtract (xv (+ line-width children-gap)))) - (and (col? shape) (h-end? shape)) - (- (+ x width) (+ line-width children-gap)) + (and row? h-center?) + (gpt/add (xv (/ line-width 2))) - (and (row? shape) (h-center? shape)) - (+ base-x (/ line-width 2)) + (and row? h-end?) + (gpt/add (xv line-width)) - (and (row? shape) (h-end? shape)) - (+ base-x line-width) + ;; Y AXIS + (and row? v-center?) + (-> (gpt/add (yv (/ layout-height 2))) + (gpt/subtract (yv (/ (+ line-height children-gap) 2)))) - (row? shape) - base-x + (and row? v-end?) + (-> (gpt/add (yv layout-height)) + (gpt/subtract (yv (+ line-height children-gap)))) - :else - x) + (and col? v-center?) + (gpt/add (yv (/ line-height 2))) - start-y - (cond - ;;(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 + (and col? v-end?) + (gpt/add (yv line-height)))] - (and (row? shape) (v-center? shape)) - (- (+ y (/ height 2)) (/ (+ line-height children-gap) 2)) + start-p)) - (and (row? shape) (v-end? shape)) - (- (+ y height) (+ line-height children-gap)) + (get-next-line + [{:keys [line-width line-height]} base-p] - (and (col? shape) (v-center? shape)) - (+ base-y (/ line-height 2)) + (cond-> base-p + row? + (gpt/add (xv (+ line-width layout-gap))) - (and (col? shape) (v-end? shape)) - (+ base-y line-height) + col? + (gpt/add (yv (+ line-height layout-gap))))) - (col? shape) - base-y + (add-lines [[total-width total-height] {:keys [line-width line-height]}] + [(+ total-width line-width) + (+ total-height line-height)]) - :else - y)] + (add-starts [[result base-p] layout-line] + (let [start-p (get-start-line layout-line base-p) + next-p (get-next-line layout-line base-p)] + [(conj result + (assoc layout-line :start-p start-p)) + next-p]))] - [start-x start-y])) + (let [[total-width total-height] (->> layout-lines (reduce add-lines [0 0])) - (get-next-line - [{:keys [line-width line-height]} base-x base-y] - (let [next-x (if (col? shape) base-x (+ base-x line-width layout-gap)) - next-y (if (row? shape) base-y (+ base-y line-height layout-gap))] - [next-x next-y])) + total-width (+ total-width (* layout-gap (dec (count layout-lines)))) + total-height (+ total-height (* layout-gap (dec (count layout-lines)))) - (add-lines [[total-width total-height] {:keys [line-width line-height]}] - [(+ total-width line-width) - (+ total-height line-height)]) + vertical-fill-space (- layout-height total-height) + horizontal-fill-space (- layout-width total-width) + num-line-fill (count (->> layout-lines (filter :line-fill?))) - (add-starts [[result base-x base-y] layout-line] - (let [[start-x start-y] (get-start-line layout-line base-x base-y) - [next-x next-y] (get-next-line layout-line base-x base-y)] - [(conj result - (assoc layout-line - :start-x start-x - :start-y start-y)) - next-x - next-y]))] + layout-lines + (->> layout-lines + (mapv #(cond-> % + (and col? (:line-fill? %)) + (update :line-height + (/ vertical-fill-space num-line-fill)) - (let [[total-width total-height] (->> layout-lines (reduce add-lines [0 0])) + (and row? (:line-fill? %)) + (update :line-width + (/ horizontal-fill-space num-line-fill))))) - total-width (+ total-width (* layout-gap (dec (count layout-lines)))) - total-height (+ total-height (* layout-gap (dec (count layout-lines)))) + total-height (if (and col? (> num-line-fill 0)) layout-height total-height) + total-width (if (and row? (> num-line-fill 0)) layout-width total-width) - vertical-fill-space (- height total-height) - horizontal-fill-space (- width total-width) - num-line-fill (count (->> layout-lines (filter :line-fill?))) + base-p (get-base-line total-width total-height) - 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) - - [layout-lines _ _ _ _] - (reduce add-starts [[] base-x base-y] layout-lines)] - layout-lines))) + [layout-lines _ _ _ _] + (reduce add-starts [[] base-p] layout-lines)] + layout-lines)))) (defn calc-layout-line-data + "Calculates the baseline for a flex layout" [{:keys [layout-type layout-gap] :as shape} - {:keys [width height] :as layout-bounds} - {:keys [num-children line-width line-height] :as line-data}] + layout-bounds + {:keys [num-children line-width line-height child-fill?] :as line-data}] - (let [layout-gap + (let [width (width-points layout-bounds) + height (height-points layout-bounds) + + layout-gap (cond - (= :packed layout-type) + (or (= :packed layout-type) child-fill?) layout-gap (= :space-around layout-type) @@ -282,7 +361,7 @@ margin-x (if (and (col? shape) (= :space-around layout-type)) - (/ (- width line-width) (inc num-children) ) + (/ (- width line-width) (inc num-children)) 0) margin-y @@ -296,147 +375,199 @@ :margin-x margin-x :margin-y margin-y))) - -(defn calc-layout-data - "Digest the layout data to pass it to the constrains" - [{:keys [layout-flex-dir] :as shape} children layout-bounds] - - (let [reverse? (or (= :reverse-row layout-flex-dir) (= :reverse-column layout-flex-dir)) - layout-bounds (-> layout-bounds (add-padding shape)) - children (cond->> children reverse? reverse) - layout-lines - (->> (calc-layout-lines shape children layout-bounds) - (calc-layout-lines-position shape layout-bounds) - (map (partial calc-layout-line-data shape layout-bounds)))] - - {:layout-lines layout-lines - :reverse? reverse?})) - (defn next-p "Calculates the position for the current shape given the layout-data context" - [shape - {:keys [width height]} - {:keys [start-x start-y layout-gap margin-x margin-y] :as layout-data}] + [parent + child-width child-height + {:keys [start-p layout-gap margin-x margin-y] :as layout-data}] - (let [pos-x - (cond - (and (row? shape) (h-center? shape)) - (- start-x (/ width 2)) + (let [row? (row? parent) + col? (col? parent) - (and (row? shape) (h-end? shape)) - (- start-x width) + layout-type (:layout-type parent) + space-around? (= :space-around layout-type) + space-between? (= :space-between layout-type) - :else - start-x) + stretch-h? (and row? (or space-around? space-between?)) + stretch-v? (and col? (or space-around? space-between?)) - pos-y - (cond - (and (col? shape) (v-center? shape)) - (- start-y (/ height 2)) + h-center? (and (h-center? parent) (not stretch-h?)) + h-end? (and (h-end? parent) (not stretch-h?)) + v-center? (and (v-center? parent) (not stretch-v?)) + v-end? (and (v-end? parent) (not stretch-v?)) + points (:points parent) - (and (col? shape) (v-end? shape)) - (- start-y height) + xv (partial start-hv points) + yv (partial start-vv points) - :else - start-y) + corner-p + (cond-> start-p + (and row? h-center?) + (gpt/add (xv (- (/ child-width 2)))) + (and row? h-end?) + (gpt/add (xv (- child-width))) - pos-x (cond-> pos-x (some? margin-x) (+ margin-x)) - pos-y (cond-> pos-y (some? margin-y) (+ margin-y)) + (and col? v-center? (not space-around?)) + (gpt/add (yv (- (/ child-height 2)))) - corner-p (gpt/point pos-x pos-y) + (and col? v-end? (not space-around?)) + (gpt/add (yv (- child-height))) - next-x - (if (col? shape) - (+ start-x width layout-gap) - start-x) + (some? margin-x) + (gpt/add (xv margin-x)) - next-y - (if (row? shape) - (+ start-y height layout-gap) - start-y) + (some? margin-y) + (gpt/add (yv margin-y))) - next-x (cond-> next-x (some? margin-x) (+ margin-x)) - next-y (cond-> next-y (some? margin-y) (+ margin-y)) + next-p + (cond-> start-p + col? + (gpt/add (xv (+ child-width layout-gap))) + row? + (gpt/add (yv (+ child-height layout-gap))) + + (some? margin-x) + (gpt/add (xv margin-x)) + + (some? margin-y) + (gpt/add (yv margin-y))) layout-data - (assoc layout-data :start-x next-x :start-y next-y)] + (assoc layout-data :start-p next-p)] + [corner-p layout-data])) (defn calc-fill-width-data - [child-bounds - {:keys [layout-gap] :as parent} + "Calculates the size and modifiers for the width of an auto-fill child" + [{:keys [layout-gap transform transform-inverse] :as parent} {:keys [layout-h-behavior] :as child} - {:keys [num-children line-width layout-bounds line-fill? child-fill?] :as layout-data}] + child-origin child-width + {:keys [num-children line-width line-fill? child-fill? layout-bounds] :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)) + (let [layout-width (width-points layout-bounds) + fill-space (- layout-width line-width (* layout-gap (dec num-children))) fill-width (/ fill-space (:num-child-fill layout-data)) - fill-scale (/ fill-width (:width child-bounds))] - {:bounds {:width fill-width} + fill-scale (/ fill-width child-width)] + {:width fill-width :modifiers [{:type :resize - :origin (gpt/point child-bounds) + :origin child-origin + :transform transform + :transform-inverse transform-inverse :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} + (let [fill-scale (/ line-width child-width)] + {:width line-width :modifiers [{:type :resize - :origin (gpt/point child-bounds) + :origin child-origin + :transform transform + :transform-inverse transform-inverse :vector (gpt/point fill-scale 1)}]}) )) (defn calc-fill-height-data - [child-bounds - {:keys [layout-gap] :as parent} + "Calculates the size and modifiers for the height of an auto-fill child" + [{:keys [layout-gap transform transform-inverse] :as parent} {:keys [layout-v-behavior] :as child} + child-origin child-height {: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)) + (let [layout-height (height-points layout-bounds) + fill-space (- layout-height line-height (* layout-gap (dec num-children))) fill-height (/ fill-space (:num-child-fill layout-data)) - fill-scale (/ fill-height (:height child-bounds))] - {:bounds {:height fill-height} + fill-scale (/ fill-height child-height)] + {:height fill-height :modifiers [{:type :resize - :origin (gpt/point child-bounds) + :origin child-origin + :transform transform + :transform-inverse transform-inverse :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} + (let [fill-scale (/ line-height child-height)] + {:height line-height :modifiers [{:type :resize - :origin (gpt/point child-bounds) + :origin child-origin + :transform transform + :transform-inverse transform-inverse :vector (gpt/point 1 fill-scale)}]}) )) +(defn normalize-child-modifiers + "Apply the modifiers and then normalized them against the parent coordinates" + [parent child modifiers transformed-parent] + + (let [transformed-child (gst/transform-shape child modifiers) + child-bb-before (gst/parent-coords-rect child parent) + child-bb-after (gst/parent-coords-rect transformed-child transformed-parent) + scale-x (/ (:width child-bb-before) (:width child-bb-after)) + scale-y (/ (:height child-bb-before) (:height child-bb-after))] + (-> modifiers + (update :v2 #(conj % + {:type :resize + :transform (:transform transformed-parent) + :transform-inverse (:transform-inverse transformed-parent) + :origin (-> transformed-parent :points (nth 0)) + :vector (gpt/point scale-x scale-y)}))))) + +(defn calc-layout-data + "Digest the layout data to pass it to the constrains" + [{:keys [layout-dir layout-padding layout-padding-type] :as parent} children] + + (let [;; Add padding to the bounds + {pad-top :p1 pad-right :p2 pad-bottom :p3 pad-left :p4} layout-padding + [pad-top pad-right pad-bottom pad-left] + (if (= layout-padding-type :multiple) + [pad-top pad-right pad-bottom pad-left] + [pad-top pad-top pad-top pad-top]) + + ;; Normalize the points to remove flips + points (gst/parent-coords-points parent parent) + + layout-bounds (pad-points points pad-top pad-right pad-bottom pad-left) + + ;; Reverse + reverse? (or (= :left layout-dir) (= :bottom layout-dir)) + children (cond->> children reverse? reverse) + + ;; Creates the layout lines information + layout-lines + (->> (calc-layout-lines parent children layout-bounds) + (calc-layout-lines-position parent layout-bounds) + (map (partial calc-layout-line-data parent layout-bounds)))] + + {:layout-lines layout-lines + :reverse? reverse?})) + (defn calc-layout-modifiers "Calculates the modifiers for the layout" - [parent child layout-data] - (let [transform (:transform parent) - child-bounds (-> child :points gre/points->selrect) + [parent child layout-line] + (let [child-bounds (gst/parent-coords-points child parent) - fill-width (calc-fill-width-data child-bounds parent child layout-data) - fill-height (calc-fill-height-data child-bounds parent child layout-data) + child-origin (origin child-bounds) + child-width (width-points child-bounds) + child-height (height-points child-bounds) - child-bounds (cond-> child-bounds - fill-width (merge (:bounds fill-width)) - fill-height (merge (:bounds fill-height))) + fill-width (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) - [corner-p layout-data] (next-p parent child-bounds layout-data) + child-width (or (:width fill-width) child-width) + child-height (or (:height fill-height) child-height) - delta-p - (-> corner-p - (gpt/subtract (gpt/point child-bounds)) - (cond-> (some? transform) (gpt/transform transform))) + [corner-p layout-line] (next-p parent child-width child-height layout-line) + + move-vec (gpt/to-vec child-origin corner-p) modifiers (-> [] (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])) + (conj {:type :move :vector move-vec}))] + [modifiers layout-line])) diff --git a/common/src/app/common/geom/shapes/layout_new.cljc b/common/src/app/common/geom/shapes/layout_new.cljc deleted file mode 100644 index a15d03870..000000000 --- a/common/src/app/common/geom/shapes/layout_new.cljc +++ /dev/null @@ -1,606 +0,0 @@ -;; 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.layout-new - (:require - [app.common.data :as d] - [app.common.geom.point :as gpt] - [app.common.geom.shapes.rect :as gre] - [app.common.geom.shapes.transforms :as gst] - )) - -;; :layout ;; true if active, false if not -;; :layout-dir ;; :right, :left, :top, :bottom -;; :layout-gap ;; number could be negative -;; :layout-type ;; :packed, :space-between, :space-around -;; :layout-wrap-type ;; :wrap, :no-wrap -;; :layout-padding-type ;; :simple, :multiple -;; :layout-padding ;; {:p1 num :p2 num :p3 num :p4 num} number could be negative -;; :layout-h-orientation ;; :top, :center, :bottom -;; :layout-v-orientation ;; :left, :center, :right - -(defn col? - [{:keys [layout-dir]}] - (or (= :right layout-dir) (= :left layout-dir))) - -(defn row? - [{:keys [layout-dir]}] - (or (= :top layout-dir) (= :bottom layout-dir))) - -(defn h-start? - [{:keys [layout-h-orientation]}] - (= layout-h-orientation :left)) - -(defn h-center? - [{:keys [layout-h-orientation]}] - (= layout-h-orientation :center)) - -(defn h-end? - [{:keys [layout-h-orientation]}] - (= layout-h-orientation :right)) - -(defn v-start? - [{:keys [layout-v-orientation]}] - (= layout-v-orientation :top)) - -(defn v-center? - [{:keys [layout-v-orientation]}] - (= layout-v-orientation :center)) - -(defn v-end? - [{:keys [layout-v-orientation]}] - (= layout-v-orientation :bottom)) - -(defn add-padding [transformed-rect {:keys [layout-padding-type layout-padding]}] - (let [{:keys [p1 p2 p3 p4]} layout-padding - [p1 p2 p3 p4] - (if (= layout-padding-type :multiple) - [p1 p2 p3 p4] - [p1 p1 p1 p1])] - - (-> transformed-rect - (update :y + p1) - (update :width - p2 p3) - (update :x + p3) - (update :height - p1 p4)))) - -;; FUNCTIONS TO WORK WITH POINTS SQUARES - -(defn origin - [points] - (nth points 0)) - -(defn start-hv - "Horizontal vector from the origin with a magnitude `val`" - [[p0 p1 p2 p3] val] - (-> (gpt/to-vec p0 p1) - (gpt/unit) - (gpt/scale val))) - -(defn end-hv - "Horizontal vector from the oposite to the origin in the x axis with a magnitude `val`" - [[p0 p1 p2 p3] val] - (-> (gpt/to-vec p1 p0) - (gpt/unit) - (gpt/scale val))) - -(defn start-vv - "Vertical vector from the oposite to the origin in the x axis with a magnitude `val`" - [[p0 p1 p2 p3] val] - (-> (gpt/to-vec p0 p3) - (gpt/unit) - (gpt/scale val))) - -(defn end-vv - "Vertical vector from the oposite to the origin in the x axis with a magnitude `val`" - [[p0 p1 p2 p3] val] - (-> (gpt/to-vec p3 p0) - (gpt/unit) - (gpt/scale val))) - -;;(defn start-hp -;; [[p0 _ _ _ :as points] val] -;; (gpt/add p0 (start-hv points val))) -;; -;;(defn end-hp -;; "Horizontal Vector from the oposite to the origin in the x axis with a magnitude `val`" -;; [[_ p1 _ _ :as points] val] -;; (gpt/add p1 (end-hv points val))) -;; -;;(defn start-vp -;; "Vertical Vector from the oposite to the origin in the x axis with a magnitude `val`" -;; [[p0 _ _ _ :as points] val] -;; (gpt/add p0 (start-vv points val))) -;; -;;(defn end-vp -;; "Vertical Vector from the oposite to the origin in the x axis with a magnitude `val`" -;; [[_ _ p3 _ :as points] val] -;; (gpt/add p3 (end-vv points val))) - -(defn width-points - [[p0 p1 p2 p3]] - (gpt/length (gpt/to-vec p0 p1))) - -(defn height-points - [[p0 p1 p2 p3]] - (gpt/length (gpt/to-vec p0 p3))) - -(defn pad-points - [[p0 p1 p2 p3 :as points] pad-top pad-right pad-bottom pad-left] - (let [top-v (start-vv points pad-top) - right-v (end-hv points pad-right) - bottom-v (end-vv points pad-bottom) - left-v (start-hv points pad-left)] - - [(-> p0 (gpt/add left-v) (gpt/add top-v)) - (-> p1 (gpt/add right-v) (gpt/add top-v)) - (-> p2 (gpt/add right-v) (gpt/add bottom-v)) - (-> p3 (gpt/add left-v) (gpt/add bottom-v))])) - -;;;; - - -(defn calc-layout-lines - [{:keys [layout-gap layout-wrap-type] :as parent} children layout-bounds] - - (let [wrap? (= layout-wrap-type :wrap) - layout-width (width-points layout-bounds) - layout-height (height-points layout-bounds) - - reduce-fn - (fn [[{:keys [line-width line-height num-children line-fill? child-fill? num-child-fill] :as line-data} result] child] - (let [child-bounds (gst/parent-coords-points child parent) - child-width (width-points child-bounds) - child-height (height-points child-bounds) - - col? (col? parent) - row? (row? parent) - - cur-child-fill? - (or (and col? (= :fill (:layout-h-behavior child))) - (and row? (= :fill (:layout-v-behavior child)))) - - cur-line-fill? - (or (and row? (= :fill (:layout-h-behavior child))) - (and col? (= :fill (:layout-v-behavior child)))) - - ;; TODO LAYOUT: ADD MINWIDTH/HEIGHT - next-width (if (or (and col? cur-child-fill?) - (and row? cur-line-fill?)) - 0 - child-width) - - next-height (if (or (and row? cur-child-fill?) - (and col? cur-line-fill?)) - 0 - child-height) - - next-total-width (+ line-width next-width (* layout-gap num-children)) - next-total-height (+ line-height next-height (* layout-gap num-children))] - - (if (and (some? line-data) - (or (not wrap?) - (and col? (<= next-total-width layout-width)) - (and row? (<= next-total-height layout-height)))) - - ;; When :fill we add min width (0 by default) - [{:line-width (if col? (+ line-width next-width) (max line-width next-width)) - :line-height (if row? (+ 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? 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)] - - (cond-> layout-lines (some? line-data) (conj line-data)))) - -(defn calc-layout-lines-position - [{:keys [layout-gap layout-type] :as parent} layout-bounds layout-lines] - - (let [layout-width (width-points layout-bounds) - layout-height (height-points layout-bounds) - row? (row? parent) - col? (col? parent) - h-center? (h-center? parent) - h-end? (h-end? parent) - v-center? (v-center? parent) - v-end? (v-end? parent) - space-between? (= :space-between layout-type) - space-around? (= :space-around layout-type)] - - (letfn [(get-base-line - [total-width total-height] - - (cond-> (origin layout-bounds) - (and row? h-center?) - (gpt/add (start-hv layout-bounds (/ (- layout-width total-width) 2))) - - (and row? h-end?) - (gpt/add (start-hv layout-bounds (- layout-width total-width))) - - (and col? v-center?) - (gpt/add (start-vv layout-bounds (/ (- layout-height total-height) 2))) - - (and col? v-end?) - (gpt/add (start-vv layout-bounds (- layout-height total-height))) - )) - - (get-start-line - [{:keys [line-width line-height num-children child-fill?]} base-p] - - (let [children-gap (* layout-gap (dec num-children)) - - ;;line-width (if (and col? child-fill?) - ;; (- layout-width (* layout-gap num-children)) - ;; line-width) - ;; - ;;line-height (if (and row? child-fill?) - ;; (- layout-height (* layout-gap num-children)) - ;; line-height) - - - start-p - (cond-> base-p - ;; X AXIS - (and col? h-center? (not space-between?) (not space-around?)) - (-> (gpt/add (start-hv layout-bounds (/ layout-width 2))) - (gpt/subtract (start-hv layout-bounds (/ (+ line-width children-gap) 2)))) - - (and col? h-end? (not space-between?) (not space-around?)) - (-> (gpt/add (start-hv layout-bounds layout-width)) - (gpt/subtract (start-hv layout-bounds (+ line-width children-gap)))) - - (and row? h-center? (not space-between?) (not space-around?)) - (gpt/add (start-hv layout-bounds (/ line-width 2))) - - (and row? h-end? (not space-between?) (not space-around?)) - (gpt/add (start-hv layout-bounds line-width)) - - ;; Y AXIS - (and row? v-center? (not space-between?) (not space-around?)) - (-> (gpt/add (start-vv layout-bounds (/ layout-height 2))) - (gpt/subtract (start-vv layout-bounds (/ (+ line-height children-gap) 2)))) - - (and row? v-end? (not space-between?) (not space-around?)) - (-> (gpt/add (start-vv layout-bounds layout-height)) - (gpt/subtract (start-vv layout-bounds (+ line-height children-gap)))) - - (and col? v-center? (not space-between?) (not space-around?)) - (gpt/add (start-vv layout-bounds (/ line-height 2))) - - (and col? v-end? (not space-between?) (not space-around?)) - (gpt/add (start-vv layout-bounds line-height)) - - ) - - - ;;start-x - ;;(cond - ;; ;;(and (col? shape) child-fill?) - ;; ;; TODO LAYOUT: Start has to take into account max-width - ;; ;;x - ;; - ;; (or (and col? space-between?) (and col? space-around?)) - ;; x - ;; - ;; (and col? h-center?) - ;; (- (+ x (/ width 2)) (/ (+ line-width children-gap) 2)) - ;; - ;; (and col? h-end?) - ;; (- (+ x width) (+ line-width children-gap)) - ;; - ;; (and row? h-center?) - ;; (+ base-x (/ line-width 2)) - ;; - ;; (and row? h-end?) - ;; (+ base-x line-width) - ;; - ;; row? - ;; base-x - ;; - ;; :else - ;; x) - - ;;start-y - ;;(cond - ;; ;; (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 - ;; - ;; (and (row? shape) (v-center? shape)) - ;; (- (+ y (/ height 2)) (/ (+ line-height children-gap) 2)) - ;; - ;; (and (row? shape) (v-end? shape)) - ;; (- (+ y height) (+ line-height children-gap)) - ;; - ;; (and (col? shape) (v-center? shape)) - ;; (+ base-y (/ line-height 2)) - ;; - ;; (and (col? shape) (v-end? shape)) - ;; (+ base-y line-height) - ;; - ;; (col? shape) - ;; base-y - ;; - ;; :else - ;; y) - ] - - start-p)) - - (get-next-line - [{:keys [line-width line-height]} base-p] - - (cond-> base-p - col? - (gpt/add (start-hv layout-bounds (+ line-width layout-gap))) - - row? - (gpt/add (start-vv layout-bounds (+ line-height layout-gap))) - ) - - #_(let [next-x (if col? base-x (+ base-x line-width layout-gap)) - next-y (if row? base-y (+ base-y line-height layout-gap))] - [next-x next-y])) - - (add-lines [[total-width total-height] {:keys [line-width line-height]}] - [(+ total-width line-width) - (+ total-height line-height)]) - - (add-starts [[result base-p] layout-line] - (let [start-p (get-start-line layout-line base-p) - next-p (get-next-line layout-line base-p)] - [(conj result - (assoc layout-line :start-p start-p)) - next-p]))] - - (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 (- layout-height total-height) - horizontal-fill-space (- layout-width total-width) - num-line-fill (count (->> layout-lines (filter :line-fill?))) - - layout-lines - (->> layout-lines - (mapv #(cond-> % - (and col? (:line-fill? %)) - (update :line-height + (/ vertical-fill-space num-line-fill)) - - (and row? (:line-fill? %)) - (update :line-width + (/ horizontal-fill-space num-line-fill))))) - - total-height (if (and col? (> num-line-fill 0)) layout-height total-height) - total-width (if (and row? (> num-line-fill 0)) layout-width total-width) - - base-p (get-base-line total-width total-height) - - [layout-lines _ _ _ _] - (reduce add-starts [[] base-p] layout-lines)] - layout-lines)))) - -(defn calc-layout-line-data - [{:keys [layout-type layout-gap] :as shape} - {:keys [width height] :as layout-bounds} - {:keys [num-children line-width line-height] :as line-data}] - - (let [layout-gap - (cond - (= :packed layout-type) - layout-gap - - (= :space-around layout-type) - 0 - - (and (col? shape) (= :space-between layout-type)) - (/ (- width line-width) (dec num-children)) - - (and (row? shape) (= :space-between layout-type)) - (/ (- height line-height) (dec num-children))) - - margin-x - (if (and (col? shape) (= :space-around layout-type)) - (/ (- width line-width) (inc num-children) ) - 0) - - margin-y - (if (and (row? shape) (= :space-around layout-type)) - (/ (- height line-height) (inc num-children)) - 0)] - - (assoc line-data - :layout-bounds layout-bounds - :layout-gap layout-gap - :margin-x margin-x - :margin-y margin-y))) - -(defn next-p - "Calculates the position for the current shape given the layout-data context" - [parent - child-bounds - {:keys [start-p layout-gap margin-x margin-y] :as layout-data}] - - (let [width (width-points child-bounds) - height (height-points child-bounds) - - row? (row? parent) - col? (col? parent) - h-center? (h-center? parent) - h-end? (h-end? parent) - v-center? (v-center? parent) - v-end? (v-end? parent) - points (:points parent) - - corner-p - (cond-> start-p - (and row? h-center?) - (gpt/add (start-hv points (- (/ width 2)))) - - (and row? h-end?) - (gpt/add (start-hv points (- width))) - - (and col? v-center?) - (gpt/add (start-vv points (- (/ height 2)))) - - (and col? v-end?) - (gpt/add (start-vv points (- height))) - - (some? margin-x) - (gpt/add (start-hv points margin-x)) - - (some? margin-y) - (gpt/add (start-vv points margin-y))) - - next-p - (cond-> start-p - col? - (gpt/add (start-hv points (+ width layout-gap))) - - row? - (gpt/add (start-vv points (+ height layout-gap))) - - (some? margin-x) - (gpt/add (start-hv points margin-x)) - - (some? margin-y) - (gpt/add (start-vv points margin-y))) - - layout-data - (assoc layout-data :start-p next-p)] - - [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 normalize-child-modifiers - "Apply the modifiers and then normalized them against the parent coordinates" - [parent child modifiers transformed-parent] - - (let [transformed-child (gst/transform-shape child modifiers) - child-bb-before (gst/parent-coords-rect child parent) - child-bb-after (gst/parent-coords-rect transformed-child transformed-parent) - scale-x (/ (:width child-bb-before) (:width child-bb-after)) - scale-y (/ (:height child-bb-before) (:height child-bb-after))] - (-> modifiers - (update :v2 #(conj % - {:type :resize - :transform (:transform transformed-parent) - :transform-inverse (:transform-inverse transformed-parent) - :origin (-> transformed-parent :points (nth 0)) - :vector (gpt/point scale-x scale-y)}))))) - -(defn calc-layout-data - "Digest the layout data to pass it to the constrains" - [{:keys [layout-dir points layout-padding layout-padding-type] :as parent} children] - - (let [;; Add padding to the bounds - {pad-top :p1 pad-right :p2 pad-bottom :p3 pad-left :p4} layout-padding - [pad-top pad-right pad-bottom pad-left] - (if (= layout-padding-type :multiple) - [pad-top pad-right pad-bottom pad-left] - [pad-top pad-top pad-top pad-top]) - layout-bounds (-> points (pad-points pad-top pad-right pad-bottom pad-left)) - - ;; Reverse - reverse? (or (= :left layout-dir) (= :bottom layout-dir)) - children (cond->> children reverse? reverse) - - ;; Creates the layout lines information - layout-lines - (->> (calc-layout-lines parent children layout-bounds) - (calc-layout-lines-position parent layout-bounds) - (map (partial calc-layout-line-data parent layout-bounds)))] - - {:layout-lines layout-lines - :reverse? reverse?})) - -(defn calc-layout-modifiers - "Calculates the modifiers for the layout" - [parent child layout-line] - (let [child-bounds (gst/parent-coords-points child parent) - - ;;fill-width (calc-fill-width-data child-bounds parent child layout-line) - ;;fill-height (calc-fill-height-data child-bounds parent child layout-line) - - ;;child-bounds (cond-> child-bounds - ;; fill-width (merge (:bounds fill-width)) - ;; fill-height (merge (:bounds fill-height))) - - - [corner-p layout-line] (next-p parent child-bounds layout-line) - - move-vec (gpt/to-vec (origin child-bounds) corner-p) - - modifiers - (-> [] - #_(cond-> fill-width (d/concat-vec (:modifiers fill-width))) - #_(cond-> fill-height (d/concat-vec (:modifiers fill-height))) - (conj {:type :move :vector move-vec}))] - - [modifiers layout-line])) - diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index fc987dfc9..7eaf9fb5a 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -11,8 +11,7 @@ [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 gclo] - [app.common.geom.shapes.layout-new :as gcln] + [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] @@ -142,7 +141,7 @@ (letfn [(normalize-child [transformed-parent _snap-pixel? modif-tree child] (let [modifiers (get-in modif-tree [(:id parent) :modifiers]) - child-modifiers (gcln/normalize-child-modifiers parent child modifiers transformed-parent)] + child-modifiers (gcl/normalize-child-modifiers parent child modifiers transformed-parent)] (cond-> modif-tree (not (ctm/empty-modifiers? child-modifiers)) (update-in [(:id child) :modifiers :v2] d/concat-vec (:v2 child-modifiers))))) @@ -153,12 +152,12 @@ (some? modifiers) (gtr/transform-shape modifiers) - (and (nil? modifiers) (group? child)) + (and (some? modifiers) (group? child)) (gtr/apply-group-modifiers objects modif-tree)))) (set-layout-modifiers [parent [layout-line modif-tree] child] (let [[modifiers layout-line] - (gcln/calc-layout-modifiers parent child layout-line) + (gcl/calc-layout-modifiers parent child layout-line) modif-tree (cond-> modif-tree @@ -175,7 +174,7 @@ children (->> children (map (partial apply-modifiers modif-tree))) - layout-data (gcln/calc-layout-data transformed-parent children) + layout-data (gcl/calc-layout-data transformed-parent children) children (into [] (cond-> children (:reverse? layout-data) reverse)) @@ -325,12 +324,13 @@ :else (recur (:parent-id current)))))) -#_(defn modif->js - [modif-tree objects] - (clj->js (into {} - (map (fn [[k v]] - [(get-in objects [k :name]) v])) - modif-tree))) +;;#?(:cljs +;; (defn modif->js +;; [modif-tree objects] +;; (clj->js (into {} +;; (map (fn [[k v]] +;; [(get-in objects [k :name]) v])) +;; modif-tree)))) (defn set-objects-modifiers [ids objects get-modifier ignore-constraints snap-pixel?] @@ -367,5 +367,6 @@ modif-tree))] - ;;(.log js/console ">result" (modif->js modif-tree objects)) + ;; #?(:cljs + ;; (.log js/console ">result" (modif->js modif-tree objects))) modif-tree)) diff --git a/frontend/src/app/main/ui/workspace/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/shapes/frame.cljs index 07b57d156..1de768035 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame.cljs @@ -24,10 +24,7 @@ [app.main.ui.workspace.shapes.frame.node-store :as fns] [app.main.ui.workspace.shapes.frame.thumbnail-render :as ftr] [beicon.core :as rx] - [rumext.v2 :as mf] - - [app.common.geom.shapes.layout :as gsl] - [app.common.geom.point :as gpt])) + [rumext.v2 :as mf])) (defn frame-shape-factory [shape-wrapper] From 025cac0228eb6124d4da1c0dfecd7fe2532b3aa8 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Mon, 10 Oct 2022 11:51:52 +0200 Subject: [PATCH 06/36] :sparkles: Drop-zone autolayout calculation --- common/src/app/common/geom/shapes/layout.cljc | 134 ++++++++++++++++++ common/src/app/common/pages/helpers.cljc | 6 +- common/src/app/common/types/shape_tree.cljc | 14 ++ .../app/main/ui/workspace/shapes/frame.cljs | 91 +++++++++++- .../src/app/main/ui/workspace/viewport.cljs | 93 +++++++++++- .../app/main/ui/workspace/viewport/hooks.cljs | 12 +- frontend/src/debug.cljs | 2 +- 7 files changed, 339 insertions(+), 13 deletions(-) diff --git a/common/src/app/common/geom/shapes/layout.cljc b/common/src/app/common/geom/shapes/layout.cljc index d0c616e85..8d1fbed87 100644 --- a/common/src/app/common/geom/shapes/layout.cljc +++ b/common/src/app/common/geom/shapes/layout.cljc @@ -8,6 +8,7 @@ (:require [app.common.data :as d] [app.common.geom.point :as gpt] + [app.common.geom.shapes.rect :as gsr] [app.common.geom.shapes.transforms :as gst])) ;; :layout ;; true if active, false if not @@ -571,3 +572,136 @@ (conj {:type :move :vector move-vec}))] [modifiers layout-line])) + + +(defn drop-areas + [{:keys [margin-x margin-y] :as frame} layout-data children] + + (let [col? (col? frame) + row? (row? frame) + h-center? (and row? (h-center? frame)) + h-end? (and row? (h-end? frame)) + v-center? (and col? (v-center? frame)) + v-end? (and row? (v-end? frame)) + layout-gap (:layout-gap frame 0) + + children (vec (cond->> children + (:reverse? layout-data) reverse)) + + redfn-child + (fn [[result parent-rect prev-x prev-y] [child next]] + (let [prev-x (or prev-x (:x parent-rect)) + prev-y (or prev-y (:y parent-rect)) + last? (nil? next) + + box-x (-> child :selrect :x) + box-y (-> child :selrect :y) + box-width (-> child :selrect :width) + box-height(-> child :selrect :height) + + + x (if row? (:x parent-rect) prev-x) + y (if col? (:y parent-rect) prev-y) + + width (cond + (and col? last?) + (- (+ (:x parent-rect) (:width parent-rect)) x) + + row? + (:width parent-rect) + + :else + (+ box-width (- box-x prev-x) (/ layout-gap 2))) + + height (cond + (and row? last?) + (- (+ (:y parent-rect) (:height parent-rect)) y) + + col? + (:height parent-rect) + + :else + (+ box-height (- box-y prev-y) (/ layout-gap 2))) + + line-area (gsr/make-rect x y width height) + result (conj result line-area)] + + [result parent-rect (+ x width) (+ y height)])) + + redfn-lines + (fn [[result from-idx prev-x prev-y] [{:keys [start-p layout-gap num-children line-width line-height]} next]] + (let [prev-x (or prev-x (:x frame)) + prev-y (or prev-y (:y frame)) + last? (nil? next) + + line-width + (if col? + (:width frame) + (+ line-width margin-x + (if col? (* layout-gap (dec num-children)) 0))) + + line-height + (if row? + (:height frame) + (+ line-height margin-y + (if row? + (* layout-gap (dec num-children)) + 0))) + + box-x + (- (:x start-p) + (cond + h-center? (/ line-width 2) + h-end? line-width + :else 0)) + + box-y + (- (:y start-p) + (cond + v-center? (/ line-height 2) + v-end? line-height + :else 0)) + + x (if col? (:x frame) prev-x) + y (if row? (:y frame) prev-y) + + width (cond + (and row? last?) + (- (+ (:x frame) (:width frame)) x) + + col? + (:width frame) + + :else + (+ line-width (- box-x prev-x) (/ layout-gap 2))) + + height (cond + (and col? last?) + (- (+ (:y frame) (:height frame)) y) + + row? + (:height frame) + + :else + (+ line-height (- box-y prev-y) (/ layout-gap 2))) + + line-area (gsr/make-rect x y width height) + + children (subvec children from-idx (+ from-idx num-children)) + + + ;; To debug the lines + ;;result (conj result line-area) + + result (first (reduce redfn-child [result line-area] (d/with-next children)))] + + [result (+ from-idx num-children) (+ x width) (+ y height)])) + + ret (first (reduce redfn-lines [[] 0] (d/with-next (:layout-lines layout-data)))) + ] + + + ;;(.log js/console "RET" (clj->js ret)) + ret + + )) diff --git a/common/src/app/common/pages/helpers.cljc b/common/src/app/common/pages/helpers.cljc index a680833d2..5d243c363 100644 --- a/common/src/app/common/pages/helpers.cljc +++ b/common/src/app/common/pages/helpers.cljc @@ -28,8 +28,10 @@ (= frame-id uuid/zero))) (defn frame-shape? - [{:keys [type]}] - (= type :frame)) + ([objects id] + (= (get-in objects [id :type]) id)) + ([{:keys [type]}] + (= type :frame))) (defn group-shape? [{:keys [type]}] diff --git a/common/src/app/common/types/shape_tree.cljc b/common/src/app/common/types/shape_tree.cljc index e39869c98..72388c216 100644 --- a/common/src/app/common/types/shape_tree.cljc +++ b/common/src/app/common/types/shape_tree.cljc @@ -234,6 +234,20 @@ (if (nil? child-frame-id) (or current-id uuid/zero) (recur child-frame-id)))))) +(defn top-nested-frame-ids + "Search the top nested frame in a list of ids" + [objects ids] + + (let [frame-ids (->> ids (filter #(cph/frame-shape? objects %))) + frame-set (set frame-ids)] + (loop [current-id (first frame-ids)] + (let [current-shape (get objects current-id) + child-frame-id (d/seek #(contains? frame-set %) + (-> (:shapes current-shape) reverse))] + (if (nil? child-frame-id) + (or current-id uuid/zero) + (recur child-frame-id))))) + ) (defn get-viewer-frames ([objects] diff --git a/frontend/src/app/main/ui/workspace/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/shapes/frame.cljs index 1de768035..a3745f16d 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame.cljs @@ -24,7 +24,87 @@ [app.main.ui.workspace.shapes.frame.node-store :as fns] [app.main.ui.workspace.shapes.frame.thumbnail-render :as ftr] [beicon.core :as rx] - [rumext.v2 :as mf])) + [rumext.v2 :as mf] + + [app.common.geom.shapes :as gsh] + [app.common.geom.shapes.layout :as gsl] + [app.main.data.workspace.state-helpers :as wsh] + [app.main.store :as st])) + +(mf/defc debug-layout + {::mf/wrap-props false} + [props] + + (let [shape (unchecked-get props "shape") + children (-> (wsh/lookup-page-objects @st/state) + (cph/get-immediate-children (:id shape))) + + layout-data (gsl/calc-layout-data shape children) + + drop-areas + (gsl/drop-areas shape layout-data children) + + ] + + [:g.debug-layout {:pointer-events "none"} + (for [[idx drop-area] (d/enumerate drop-areas)] + [:rect {:x (:x drop-area) + :y (:y drop-area) + :width (:width drop-area) + :height (:height drop-area) + :style {:fill "blue" + :fill-opacity 0.3 + :stroke "red" + :stroke-width 1 + :stroke-dasharray "3 6"}}]) + + + #_(for [[idx layout-line] (d/enumerate (:layout-lines layout-data))] + (let [col? (gsl/col? shape) + row? (gsl/row? shape) + h-center? (and row? (gsl/h-center? shape)) + h-end? (and row? (gsl/h-end? shape)) + v-center? (and col? (gsl/v-center? shape)) + v-end? (and row? (gsl/v-end? shape)) + + line-width + (+ (-> layout-line :line-width) + (:margin-x shape) + (if col? + (* (:layout-gap layout-line) (dec (-> layout-line :num-children))) + 0)) + + line-height + (+ (-> layout-line :line-height) + (:margin-y shape) + (if row? + (* (:layout-gap layout-line) (dec (-> layout-line :num-children))) + 0)) + ] + [:g {:key (dm/str "line-" idx)} + [:rect {:x (- (-> layout-line :start-p :x) + (cond + h-center? (/ line-width 2) + h-end? line-width + :else 0)) + :y (- (-> layout-line :start-p :y) + (cond + v-center? (/ line-height 2) + v-end? line-height + :else 0)) + :width line-width + :height line-height + :style {:fill "blue" + :fill-opacity 0.3} + }] + #_[:line {:x1 (-> layout-line :start-p :x) + :y1 (-> layout-line :start-p :y) + :x2 (+ (-> layout-line :start-p :x) (if col? line-width 0)) + :y2 (+ (-> layout-line :start-p :y) (if row? line-height 0)) + :transform (gsh/transform-str shape) + :style {:fill "none" + :stroke "red" + :stroke-width 2}}]]))])) (defn frame-shape-factory [shape-wrapper] @@ -39,9 +119,12 @@ childs-ref (mf/use-memo (mf/deps (:id shape)) #(refs/children-objects (:id shape))) childs (mf/deref childs-ref)] - [:& (mf/provider embed/context) {:value true} - [:& shape-container {:shape shape :ref ref :disable-shadows? (cph/root-frame? shape)} - [:& frame-shape {:shape shape :childs childs} ]]])))) + [:* + [:& (mf/provider embed/context) {:value true} + [:& shape-container {:shape shape :ref ref :disable-shadows? (cph/root-frame? shape)} + [:& frame-shape {:shape shape :childs childs} ]]] + + #_[:& debug-layout {:shape shape}]])))) (defn check-props [new-props old-props] diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index 5a4be44ca..4c219d3ac 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -41,7 +41,85 @@ [app.main.ui.workspace.viewport.widgets :as widgets] [beicon.core :as rx] [debug :refer [debug?]] - [rumext.v2 :as mf])) + [rumext.v2 :as mf] + + [app.common.uuid :as uuid] + [app.common.geom.shapes :as gsh] + [app.common.geom.shapes.layout :as gsl] + [app.main.data.workspace.state-helpers :as wsh] + [app.main.store :as st] + + )) + +(mf/defc debug-layout + {::mf/wrap-props false} + [props] + + (let [shape (unchecked-get props "shape") + objects (unchecked-get props "objects") + children (cph/get-immediate-children objects (:id shape)) + layout-data (gsl/calc-layout-data shape children) + drop-areas (gsl/drop-areas shape layout-data children)] + + [:g.debug-layout {:pointer-events "none"} + (for [[idx drop-area] (d/enumerate drop-areas)] + [:rect {:x (:x drop-area) + :y (:y drop-area) + :width (:width drop-area) + :height (:height drop-area) + :style {:fill "blue" + :fill-opacity 0.3 + :stroke "red" + :stroke-width 1 + :stroke-dasharray "3 6"}}]) + + + #_(for [[idx layout-line] (d/enumerate (:layout-lines layout-data))] + (let [col? (gsl/col? shape) + row? (gsl/row? shape) + h-center? (and row? (gsl/h-center? shape)) + h-end? (and row? (gsl/h-end? shape)) + v-center? (and col? (gsl/v-center? shape)) + v-end? (and row? (gsl/v-end? shape)) + + line-width + (+ (-> layout-line :line-width) + (:margin-x shape) + (if col? + (* (:layout-gap layout-line) (dec (-> layout-line :num-children))) + 0)) + + line-height + (+ (-> layout-line :line-height) + (:margin-y shape) + (if row? + (* (:layout-gap layout-line) (dec (-> layout-line :num-children))) + 0)) + ] + [:g {:key (dm/str "line-" idx)} + [:rect {:x (- (-> layout-line :start-p :x) + (cond + h-center? (/ line-width 2) + h-end? line-width + :else 0)) + :y (- (-> layout-line :start-p :y) + (cond + v-center? (/ line-height 2) + v-end? line-height + :else 0)) + :width line-width + :height line-height + :style {:fill "blue" + :fill-opacity 0.3} + }] + #_[:line {:x1 (-> layout-line :start-p :x) + :y1 (-> layout-line :start-p :y) + :x2 (+ (-> layout-line :start-p :x) (if col? line-width 0)) + :y2 (+ (-> layout-line :start-p :y) (if row? line-height 0)) + :transform (gsh/transform-str shape) + :style {:fill "none" + :stroke "red" + :stroke-width 2}}]]))])) ;; --- Viewport @@ -90,6 +168,7 @@ hover-ids (mf/use-state nil) hover (mf/use-state nil) hover-disabled? (mf/use-state false) + hover-top-frame-id (mf/use-state nil) frame-hover (mf/use-state nil) active-frames (mf/use-state #{}) @@ -186,7 +265,7 @@ (hooks/setup-viewport-size viewport-ref) (hooks/setup-cursor cursor alt? mod? space? panning drawing-tool drawing-path? node-editing?) (hooks/setup-keyboard alt? mod? space?) - (hooks/setup-hover-shapes page-id move-stream base-objects transform selected mod? hover hover-ids @hover-disabled? focus zoom) + (hooks/setup-hover-shapes page-id move-stream base-objects transform selected mod? hover hover-ids hover-top-frame-id @hover-disabled? focus zoom) (hooks/setup-viewport-modifiers modifiers base-objects) (hooks/setup-shortcuts node-editing? drawing-path?) (hooks/setup-active-frames base-objects hover-ids selected active-frames zoom transform vbox) @@ -414,6 +493,16 @@ :hover-frame frame-parent :disabled-guides? disabled-guides?}]) + (let [selected-frame (when (= 1 (count selected-shapes)) + (let [selected-shape (get objects-modified (first selected))] + (when (= :frame (:type selected-shape)) + selected-shape))) + + top-frame (or selected-frame (get objects-modified @hover-top-frame-id))] + (when (and top-frame (not= uuid/zero top-frame) (:layout top-frame)) + [:& debug-layout {:shape top-frame + :objects objects-modified}])) + (when show-selection-handlers? [:g.selection-handlers {:clipPath "url(#clip-handlers)"} [:defs diff --git a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs index c9071afc8..cc6c7bf8d 100644 --- a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs @@ -28,7 +28,8 @@ [beicon.core :as rx] [debug :refer [debug?]] [goog.events :as events] - [rumext.v2 :as mf]) + [rumext.v2 :as mf] + [app.common.types.shape-tree :as ctst]) (:import goog.events.EventType)) (defn setup-dom-events [viewport-ref zoom disable-paste in-viewport?] @@ -104,7 +105,8 @@ (some #(cph/is-parent? objects % group-id)) (not)))) -(defn setup-hover-shapes [page-id move-stream objects transform selected mod? hover hover-ids hover-disabled? focus zoom] +(defn setup-hover-shapes + [page-id move-stream objects transform selected mod? hover hover-ids hover-top-frame-id hover-disabled? focus zoom] (let [;; We use ref so we don't recreate the stream on a change zoom-ref (mf/use-ref zoom) mod-ref (mf/use-ref @mod?) @@ -143,9 +145,10 @@ (rx/map #(deref last-point-ref))) (->> move-stream + (rx/tap #(reset! last-point-ref %)) ;; When transforming shapes we stop querying the worker (rx/merge-map query-point) - (rx/tap #(reset! last-point-ref %))))))] + ))))] ;; Refresh the refs on a value change (mf/use-effect @@ -213,7 +216,8 @@ (first) (get objects))] (reset! hover hover-shape) - (reset! hover-ids ids)))))) + (reset! hover-ids ids) + (reset! hover-top-frame-id (ctst/top-nested-frame objects (deref last-point-ref)))))))) (defn setup-viewport-modifiers [modifiers objects] diff --git a/frontend/src/debug.cljs b/frontend/src/debug.cljs index a87d0cbac..96c986604 100644 --- a/frontend/src/debug.cljs +++ b/frontend/src/debug.cljs @@ -74,7 +74,7 @@ #{:app.main.data.workspace.notifications/handle-pointer-update :app.main.data.workspace.selection/change-hover-state}) -(defonce ^:dynamic *debug* (atom #{#_:events #_:text-outline})) +(defonce ^:dynamic *debug* (atom #{#_:events})) (defn debug-all! [] (reset! *debug* debug-options)) (defn debug-none! [] (reset! *debug* #{})) From c3ed46d3ab2f58465dda71d8d4fbc3032d3d68ef Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 14 Oct 2022 14:44:10 +0200 Subject: [PATCH 07/36] :sparkles: Move auto-layout children --- common/src/app/common/geom/point.cljc | 9 +- common/src/app/common/geom/shapes.cljc | 1 + .../app/common/geom/shapes/constraints.cljc | 4 +- common/src/app/common/geom/shapes/layout.cljc | 114 +++++++++++------- .../src/app/common/geom/shapes/modifiers.cljc | 17 ++- common/src/app/common/geom/shapes/rect.cljc | 23 ++-- .../app/common/geom/shapes/transforms.cljc | 43 ++++++- common/src/app/common/math.cljc | 5 + common/src/app/common/pages/helpers.cljc | 6 + common/src/app/common/types/modifiers.cljc | 5 +- common/src/app/common/types/shape_tree.cljc | 4 +- .../app/main/data/workspace/drawing/box.cljs | 49 +++++--- .../main/data/workspace/drawing/common.cljs | 3 +- .../src/app/main/data/workspace/shapes.cljs | 8 +- .../app/main/data/workspace/transforms.cljs | 89 +++++++++++--- .../src/app/main/ui/workspace/shapes.cljs | 78 ++++++------ .../app/main/ui/workspace/shapes/frame.cljs | 91 +------------- .../shapes/frame/dynamic_modifiers.cljs | 69 ++++++++++- .../src/app/main/ui/workspace/viewport.cljs | 94 ++------------- .../app/main/ui/workspace/viewport/debug.cljs | 54 +++++++++ .../app/main/ui/workspace/viewport/hooks.cljs | 8 +- frontend/src/debug.cljs | 12 +- 22 files changed, 457 insertions(+), 329 deletions(-) create mode 100644 frontend/src/app/main/ui/workspace/viewport/debug.cljs diff --git a/common/src/app/common/geom/point.cljc b/common/src/app/common/geom/point.cljc index 9ce97f8af..5b17160d9 100644 --- a/common/src/app/common/geom/point.cljc +++ b/common/src/app/common/geom/point.cljc @@ -5,7 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.common.geom.point - (:refer-clojure :exclude [divide min max]) + (:refer-clojure :exclude [divide min max abs]) (:require #?(:cljs [cljs.pprint :as pp] :clj [clojure.pprint :as pp]) @@ -328,6 +328,13 @@ (update :x #(if (mth/almost-zero? %) 0.001 %)) (update :y #(if (mth/almost-zero? %) 0.001 %)))) + +(defn abs + [point] + (-> point + (update :x mth/abs) + (update :y mth/abs))) + ;; --- Debug (defmethod pp/simple-dispatch Point [obj] (pr obj)) diff --git a/common/src/app/common/geom/shapes.cljc b/common/src/app/common/geom/shapes.cljc index 5364b9daa..25da561f3 100644 --- a/common/src/app/common/geom/shapes.cljc +++ b/common/src/app/common/geom/shapes.cljc @@ -160,6 +160,7 @@ (dm/export gpr/join-rects) (dm/export gpr/join-selrects) (dm/export gpr/contains-selrect?) +(dm/export gpr/contains-point?) (dm/export gtr/move) (dm/export gtr/absolute-move) diff --git a/common/src/app/common/geom/shapes/constraints.cljc b/common/src/app/common/geom/shapes/constraints.cljc index 0c898348f..2e9aa8a9b 100644 --- a/common/src/app/common/geom/shapes/constraints.cljc +++ b/common/src/app/common/geom/shapes/constraints.cljc @@ -288,7 +288,9 @@ (defn calc-child-modifiers [parent child modifiers ignore-constraints transformed-parent] - (let [constraints-h + (let [modifiers (select-keys modifiers [:v2]) + + constraints-h (if-not ignore-constraints (:constraints-h child (default-constraints-h child)) :scale) diff --git a/common/src/app/common/geom/shapes/layout.cljc b/common/src/app/common/geom/shapes/layout.cljc index 8d1fbed87..a5f0d79c5 100644 --- a/common/src/app/common/geom/shapes/layout.cljc +++ b/common/src/app/common/geom/shapes/layout.cljc @@ -7,9 +7,12 @@ (ns app.common.geom.shapes.layout (: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.rect :as gsr] - [app.common.geom.shapes.transforms :as gst])) + [app.common.geom.shapes.transforms :as gst] + [app.common.pages.helpers :as cph])) ;; :layout ;; true if active, false if not ;; :layout-dir ;; :right, :left, :top, :bottom @@ -213,6 +216,8 @@ layout-height (height-points layout-bounds) row? (row? parent) col? (col? parent) + space-between? (= :space-between (:layout-type parent)) + space-around? (= :space-around (:layout-type parent)) h-center? (h-center? parent) h-end? (h-end? parent) v-center? (v-center? parent) @@ -258,11 +263,11 @@ start-p (cond-> base-p ;; X AXIS - (and col? h-center?) + (and col? h-center? (not space-around?) (not space-between?)) (-> (gpt/add (xv (/ layout-width 2))) (gpt/subtract (xv (/ (+ line-width children-gap) 2)))) - (and col? h-end?) + (and col? h-end? (not space-around?) (not space-between?)) (-> (gpt/add (xv layout-width)) (gpt/subtract (xv (+ line-width children-gap)))) @@ -273,11 +278,11 @@ (gpt/add (xv line-width)) ;; Y AXIS - (and row? v-center?) + (and row? v-center? (not space-around?) (not space-between?)) (-> (gpt/add (yv (/ layout-height 2))) (gpt/subtract (yv (/ (+ line-height children-gap) 2)))) - (and row? v-end?) + (and row? v-end? (not space-around?) (not space-between?)) (-> (gpt/add (yv layout-height)) (gpt/subtract (yv (+ line-height children-gap)))) @@ -385,17 +390,10 @@ (let [row? (row? parent) col? (col? parent) - layout-type (:layout-type parent) - space-around? (= :space-around layout-type) - space-between? (= :space-between layout-type) - - stretch-h? (and row? (or space-around? space-between?)) - stretch-v? (and col? (or space-around? space-between?)) - - h-center? (and (h-center? parent) (not stretch-h?)) - h-end? (and (h-end? parent) (not stretch-h?)) - v-center? (and (v-center? parent) (not stretch-v?)) - v-end? (and (v-end? parent) (not stretch-v?)) + h-center? (h-center? parent) + h-end? (h-end? parent) + v-center? (v-center? parent) + v-end? (v-end? parent) points (:points parent) xv (partial start-hv points) @@ -409,10 +407,10 @@ (and row? h-end?) (gpt/add (xv (- child-width))) - (and col? v-center? (not space-around?)) + (and col? v-center?) (gpt/add (yv (- (/ child-height 2)))) - (and col? v-end? (not space-around?)) + (and col? v-end?) (gpt/add (yv (- child-height))) (some? margin-x) @@ -584,29 +582,35 @@ v-center? (and col? (v-center? frame)) v-end? (and row? (v-end? frame)) layout-gap (:layout-gap frame 0) + reverse? (:reverse? layout-data) - children (vec (cond->> children - (:reverse? layout-data) reverse)) + children (vec (cond->> (d/enumerate children) + reverse? reverse)) redfn-child - (fn [[result parent-rect prev-x prev-y] [child next]] + (fn [[result parent-rect prev-x prev-y] [[index child] next]] (let [prev-x (or prev-x (:x parent-rect)) prev-y (or prev-y (:y parent-rect)) + last? (nil? next) - box-x (-> child :selrect :x) - box-y (-> child :selrect :y) - box-width (-> child :selrect :width) - box-height(-> child :selrect :height) + start-p (gpt/point (:selrect child)) + start-p (-> start-p + (gmt/transform-point-center (gco/center-shape child) (:transform frame)) + (gmt/transform-point-center (gco/center-shape frame) (:transform-inverse frame))) + + box-x (:x start-p) + box-y (:y start-p) + box-width (-> child :selrect :width) + box-height (-> child :selrect :height) - x (if row? (:x parent-rect) prev-x) y (if col? (:y parent-rect) prev-y) width (cond (and col? last?) (- (+ (:x parent-rect) (:width parent-rect)) x) - + row? (:width parent-rect) @@ -616,21 +620,42 @@ height (cond (and row? last?) (- (+ (:y parent-rect) (:height parent-rect)) y) - + col? (:height parent-rect) :else (+ box-height (- box-y prev-y) (/ layout-gap 2))) - - line-area (gsr/make-rect x y width height) - result (conj result line-area)] + + [line-area-1 line-area-2] + (if col? + (let [half-point-width (+ (- box-x x) (/ box-width 2))] + [(-> (gsr/make-rect x y half-point-width height) + (assoc :index (if reverse? (inc index) index))) + (-> (gsr/make-rect (+ x half-point-width) y (- width half-point-width) height) + (assoc :index (if reverse? index (inc index))))]) + (let [half-point-height (+ (- box-y y) (/ box-height 2))] + [(-> (gsr/make-rect x y width half-point-height) + (assoc :index (if reverse? (inc index) index))) + (-> (gsr/make-rect x (+ y half-point-height) width (- height half-point-height)) + (assoc :index (if reverse? index (inc index))))])) + + result (conj result line-area-1 line-area-2) + + ;;line-area + ;;(-> (gsr/make-rect x y width height) + ;; (assoc :index (if reverse? (inc index) index))) + ;;result (conj result line-area) + ;;result (conj result (gsr/make-rect box-x box-y box-width box-height)) + ] [result parent-rect (+ x width) (+ y height)])) - + redfn-lines (fn [[result from-idx prev-x prev-y] [{:keys [start-p layout-gap num-children line-width line-height]} next]] - (let [prev-x (or prev-x (:x frame)) + (let [start-p (gmt/transform-point-center start-p (gco/center-shape frame) (:transform-inverse frame)) + + prev-x (or prev-x (:x frame)) prev-y (or prev-y (:y frame)) last? (nil? next) @@ -668,7 +693,7 @@ width (cond (and row? last?) (- (+ (:x frame) (:width frame)) x) - + col? (:width frame) @@ -678,7 +703,7 @@ height (cond (and col? last?) (- (+ (:y frame) (:height frame)) y) - + row? (:height frame) @@ -695,13 +720,16 @@ result (first (reduce redfn-child [result line-area] (d/with-next children)))] - [result (+ from-idx num-children) (+ x width) (+ y height)])) + [result (+ from-idx num-children) (+ x width) (+ y height)]))] - ret (first (reduce redfn-lines [[] 0] (d/with-next (:layout-lines layout-data)))) - ] + (first (reduce redfn-lines [[] 0] (d/with-next (:layout-lines layout-data)))))) - - ;;(.log js/console "RET" (clj->js ret)) - ret - - )) +(defn get-drop-index + [frame-id objects position] + (let [frame (get objects frame-id) + position (gmt/transform-point-center position (gco/center-shape frame) (:transform-inverse frame)) + children (cph/get-immediate-children objects frame-id) + layout-data (calc-layout-data frame children) + drop-areas (drop-areas frame layout-data children) + area (d/seek #(gsr/contains-point? % position) drop-areas)] + (:index area))) diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index 7eaf9fb5a..6cb5f0d6f 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -166,9 +166,9 @@ [layout-line modif-tree]))] - (let [children (map (d/getf objects) (:shapes parent)) - modifiers (get-in modif-tree [(:id parent) :modifiers]) + (let [modifiers (get-in modif-tree [(:id parent) :modifiers]) transformed-parent (gtr/transform-shape parent modifiers) + children (map (d/getf objects) (:shapes transformed-parent)) modif-tree (reduce (partial normalize-child transformed-parent _snap-pixel?) modif-tree children) @@ -343,27 +343,26 @@ (assoc id {:modifiers modifiers})))) modif-tree (reduce set-modifiers {} ids) - shapes-tree (resolve-tree-sequence ids objects) modif-tree (->> shapes-tree (reduce (fn [modif-tree shape] - (let [has-modifiers? (some? (get-in modif-tree [(:id shape) :modifiers])) + (let [modifiers (get-in modif-tree [(:id shape) :modifiers]) + has-modifiers? (some? modifiers) is-layout? (layout? shape) is-parent? (or (group? shape) (and (frame? shape) (not (layout? shape)))) - + root? (= uuid/zero (:id 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?) + (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?) - ))) + (set-layout-modifiers objects shape snap-pixel?)))) modif-tree))] diff --git a/common/src/app/common/geom/shapes/rect.cljc b/common/src/app/common/geom/shapes/rect.cljc index 6637b7533..895388371 100644 --- a/common/src/app/common/geom/shapes/rect.cljc +++ b/common/src/app/common/geom/shapes/rect.cljc @@ -11,14 +11,21 @@ [app.common.math :as mth])) (defn make-rect - [x y width height] - (when (d/num? x y width height) - (let [width (max width 0.01) - height (max height 0.01)] - {:x x - :y y - :width width - :height height}))) + ([p1 p2] + (let [x1 (min (:x p1) (:x p2)) + y1 (min (:y p1) (:y p2)) + x2 (max (:x p1) (:x p2)) + y2 (max (:y p1) (:y p2))] + (make-rect x1 y1 (- x2 x1) (- y2 y1)))) + + ([x y width height] + (when (d/num? x y width height) + (let [width (max width 0.01) + height (max height 0.01)] + {:x x + :y y + :width width + :height height})))) (defn make-selrect [x y width height] diff --git a/common/src/app/common/geom/shapes/transforms.cljc b/common/src/app/common/geom/shapes/transforms.cljc index 6c1957519..08bf7383e 100644 --- a/common/src/app/common/geom/shapes/transforms.cljc +++ b/common/src/app/common/geom/shapes/transforms.cljc @@ -14,8 +14,10 @@ [app.common.geom.shapes.path :as gpa] [app.common.geom.shapes.rect :as gpr] [app.common.math :as mth] + [app.common.pages.helpers :as cph] [app.common.text :as txt] - [app.common.types.modifiers :as ctm])) + [app.common.types.modifiers :as ctm] + [app.common.uuid :as uuid])) (def ^:dynamic *skip-adjust* false) @@ -436,13 +438,46 @@ %))) shape)) +(defn- apply-structure-modifiers + [shape modifiers] + + (let [remove-children + (fn [shapes children-to-remove] + (let [remove? (set children-to-remove)] + (d/removev remove? shapes))) + + apply-modifier + (fn [shape {:keys [type value index]}] + (cond-> shape + (and (= type :add-children) (some? index)) + (update :shapes + (fn [shapes] + (if (vector? shapes) + (cph/insert-at-index shapes index value) + (d/concat-vec shapes value)))) + + (and (= type :add-children) (nil? index)) + (update :shapes d/concat-vec value) + + (= type :remove-children) + (update :shapes remove-children value)))] + + (reduce apply-modifier shape (:v3 modifiers)))) + (defn apply-modifiers [shape modifiers] (let [center (gco/center-shape shape) transform (ctm/modifiers->transform center modifiers)] - (-> shape - #_(set-flip-2 transform) - (apply-transform transform)))) + + (cond-> shape + #_(set-flip-2 transform) + (and (some? transform) + ;; Never transform the root frame + (not= uuid/zero (:id shape))) + (apply-transform transform) + + :always + (apply-structure-modifiers modifiers)))) (defn apply-objects-modifiers [objects modifiers] diff --git a/common/src/app/common/math.cljc b/common/src/app/common/math.cljc index d32531a26..fc35d15f3 100644 --- a/common/src/app/common/math.cljc +++ b/common/src/app/common/math.cljc @@ -174,3 +174,8 @@ (defn max-abs [a b] (max (abs a) (abs b))) + +(defn sign + "Get the sign (+1 / -1) for the number" + [n] + (if (neg? n) -1 1)) diff --git a/common/src/app/common/pages/helpers.cljc b/common/src/app/common/pages/helpers.cljc index 5d243c363..f984574f5 100644 --- a/common/src/app/common/pages/helpers.cljc +++ b/common/src/app/common/pages/helpers.cljc @@ -33,6 +33,12 @@ ([{:keys [type]}] (= type :frame))) +(defn layout-shape? + ([objects id] + (layout-shape? (get objects id))) + ([{:keys [type layout]}] + (and (= type :frame) layout))) + (defn group-shape? [{:keys [type]}] (= type :group)) diff --git a/common/src/app/common/types/modifiers.cljc b/common/src/app/common/types/modifiers.cljc index 7c8658cfb..5c905aeff 100644 --- a/common/src/app/common/types/modifiers.cljc +++ b/common/src/app/common/types/modifiers.cljc @@ -162,9 +162,6 @@ :move (gmt/multiply (gmt/translate-matrix vector) matrix) - ;;:transform - ;;(gmt/multiply transform matrix) - :resize (gmt/multiply (-> (gmt/matrix) @@ -178,7 +175,7 @@ matrix) :rotation - ;; TODO LAYOUT: Comprobar que pasa si no hay centro + ;; TODO LAYOUT: Maybe an issue when no center data (gmt/multiply (-> (gmt/matrix) (gmt/translate center) diff --git a/common/src/app/common/types/shape_tree.cljc b/common/src/app/common/types/shape_tree.cljc index 72388c216..905854d03 100644 --- a/common/src/app/common/types/shape_tree.cljc +++ b/common/src/app/common/types/shape_tree.cljc @@ -234,6 +234,7 @@ (if (nil? child-frame-id) (or current-id uuid/zero) (recur child-frame-id)))))) + (defn top-nested-frame-ids "Search the top nested frame in a list of ids" [objects ids] @@ -246,8 +247,7 @@ (-> (:shapes current-shape) reverse))] (if (nil? child-frame-id) (or current-id uuid/zero) - (recur child-frame-id))))) - ) + (recur child-frame-id)))))) (defn get-viewer-frames ([objects] diff --git a/frontend/src/app/main/data/workspace/drawing/box.cljs b/frontend/src/app/main/data/workspace/drawing/box.cljs index dc9e86762..65843fc6b 100644 --- a/frontend/src/app/main/data/workspace/drawing/box.cljs +++ b/frontend/src/app/main/data/workspace/drawing/box.cljs @@ -21,27 +21,37 @@ [beicon.core :as rx] [potok.core :as ptk])) -(defn truncate-zero [num default] - (if (mth/almost-zero? num) default num)) +(defn adjust-ratio + [point initial] + (let [v (gpt/to-vec point initial) + dx (mth/abs (:x v)) + dy (mth/abs (:y v)) + sx (mth/sign (:x v)) + sy (mth/sign (:y v))] + + (cond-> point + (> dx dy) + (assoc :y (- (:y point) (* sy (- dx dy)))) + + (> dy dx) + (assoc :x (- (:x point) (* sx (- dy dx))))))) + +(defn resize-shape [{:keys [x y width height] :as shape} initial point lock?] + (let [draw-rect (gsh/make-rect initial (cond-> point lock? (adjust-ratio initial))) + shape-rect (gsh/make-rect x y width height) + + scalev (gpt/point (/ (:width draw-rect) (:width shape-rect)) + (/ (:height draw-rect) (:height shape-rect))) + + movev (gpt/to-vec (gpt/point shape-rect) (gpt/point draw-rect))] -(defn resize-shape [{:keys [x y width height] :as shape} point lock?] - (let [;; The new shape behaves like a resize on the bottom-right corner - initial (gpt/point (+ x width) (+ y height)) - shapev (gpt/point width height) - deltav (gpt/to-vec initial point) - scalev (-> (gpt/divide (gpt/add shapev deltav) shapev) - (update :x truncate-zero 0.01) - (update :y truncate-zero 0.01)) - scalev (if lock? - (let [v (max (:x scalev) (:y scalev))] - (gpt/point v v)) - scalev)] (-> shape (assoc :click-draw? false) - (gsh/transform-shape (ctm/resize scalev (gpt/point x y)))))) + (gsh/transform-shape (ctm/resize scalev (gpt/point x y))) + (gsh/transform-shape (ctm/move movev))))) -(defn update-drawing [state point lock?] - (update-in state [:workspace-drawing :object] resize-shape point lock?)) +(defn update-drawing [state initial point lock?] + (update-in state [:workspace-drawing :object] resize-shape initial point lock?)) (defn move-drawing [{:keys [x y]}] @@ -57,8 +67,7 @@ layout (get state :workspace-layout) snap-pixel? (contains? layout :snap-pixel-grid) - initial (cond-> @ms/mouse-position - snap-pixel? gpt/round) + initial (cond-> @ms/mouse-position snap-pixel? gpt/round) page-id (:current-page-id state) objects (wsh/lookup-page-objects state page-id) @@ -96,7 +105,7 @@ (rx/map #(conj current %))))) (rx/map (fn [[_ shift? point]] - #(update-drawing % (cond-> point snap-pixel? gpt/round) shift?))) + #(update-drawing % initial (cond-> point snap-pixel? gpt/round) shift?))) (rx/take-until stoper)) (rx/of (common/handle-finish-drawing))))))) diff --git a/frontend/src/app/main/data/workspace/drawing/common.cljs b/frontend/src/app/main/data/workspace/drawing/common.cljs index c13f76e70..2016c3c7d 100644 --- a/frontend/src/app/main/data/workspace/drawing/common.cljs +++ b/frontend/src/app/main/data/workspace/drawing/common.cljs @@ -51,8 +51,7 @@ (and click-draw? (not text?)) (-> (assoc :width min-side :height min-side) - (gsh/transform-shape (ctm/move (- (/ min-side 2)) (- (/ min-side 2)))) - #_(ctm/add-move (- (/ min-side 2)) (- (/ min-side 2)))) + (gsh/transform-shape (ctm/move (- (/ min-side 2)) (- (/ min-side 2))))) (and click-draw? text?) (assoc :height 17 :width 4 :grow-type :auto-width) diff --git a/frontend/src/app/main/data/workspace/shapes.cljs b/frontend/src/app/main/data/workspace/shapes.cljs index e7c8e6705..daa033365 100644 --- a/frontend/src/app/main/data/workspace/shapes.cljs +++ b/frontend/src/app/main/data/workspace/shapes.cljs @@ -22,6 +22,7 @@ [app.main.data.workspace.edition :as dwe] [app.main.data.workspace.selection :as dws] [app.main.data.workspace.shape-layout :as dwsl] + [app.main.data.workspace.shape-layout :as dwsl] [app.main.data.workspace.state-helpers :as wsh] [app.main.features :as features] [app.main.streams :as ms] @@ -146,6 +147,10 @@ ids (cph/clean-loops objects ids) lookup (d/getf objects) + layout-ids (->> ids + (mapcat (partial cph/get-parent-ids objects)) + (filter (partial cph/layout-shape? objects))) + components-v2 (features/active-feature? state :components-v2) groups-to-unmask @@ -266,7 +271,8 @@ (rx/of (dc/detach-comment-thread ids) (dwsl/update-layout-positions all-parents) - (dch/commit-changes changes))))))) + (dch/commit-changes changes) + (dwsl/update-layout-positions layout-ids))))))) (defn- viewport-center [state] diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 9d8c186d5..7873b7eba 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -11,6 +11,7 @@ [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] + [app.common.geom.shapes.layout :as gsl] [app.common.math :as mth] [app.common.pages.changes-builder :as pcb] [app.common.pages.common :as cpc] @@ -137,8 +138,20 @@ snap-pixel? (and (not ignore-snap-pixel) (contains? (:workspace-layout state) :snap-pixel-grid)) + workspace-modifiers (:workspace-modifiers state) + modif-tree - (gsh/set-objects-modifiers ids objects (constantly modifiers) ignore-constraints snap-pixel?)] + (gsh/set-objects-modifiers + ;; TODO LAYOUT: I don't like this + (concat (keys workspace-modifiers) ids) + objects + (fn [shape] + (let [modifiers (if (contains? ids (:id shape)) modifiers {}) + old-modifiers-v3 (get-in state [:workspace-modifiers (:id shape) :modifiers :v3])] + (cond-> modifiers + (some? old-modifiers-v3) + (assoc :v3 old-modifiers-v3)))) + ignore-constraints snap-pixel?)] (update state :workspace-modifiers merge modif-tree)))))) @@ -619,6 +632,40 @@ (rx/take 1) (rx/map #(start-move from-position)))))) +(defn set-change-frame-modifiers + [selected target-frame position] + + (ptk/reify ::set-change-frame-modifiers + ptk/UpdateEvent + (update [_ state] + (let [objects (wsh/lookup-page-objects state) + + origin-frame-ids (->> selected (group-by #(get-in objects [% :frame-id]))) + + layout? (get-in objects [target-frame :layout]) + + drop-index + (when layout? (gsl/get-drop-index target-frame objects position)) + + modif-tree + (into {} + (mapcat + (fn [original-frame] + (let [shapes (->> (get origin-frame-ids original-frame) + (d/removev #(= target-frame %)))] + (cond + (not= original-frame target-frame) + [[original-frame {:modifiers {:v3 [{:type :remove-children :value shapes}]}}] + [target-frame {:modifiers {:v3 [{:type :add-children + :value shapes + :index drop-index}]}}]] + layout? + [[target-frame {:modifiers {:v3 [{:type :add-children + :value shapes + :index drop-index}]}}]])))) + (keys origin-frame-ids))] + (assoc state :workspace-modifiers modif-tree))))) + (defn- start-move ([from-position] (start-move from-position nil)) ([from-position ids] @@ -664,17 +711,25 @@ (if (empty? shapes) (rx/of (finish-transform)) (rx/concat - (->> position - ;; We ask for the snap position but we continue even if the result is not available - (rx/with-latest vector snap-delta) - ;; We try to use the previous snap so we don't have to wait for the result of the new - (rx/map snap/correct-snap-point) + (rx/merge + (->> position + (rx/map (fn [delta] + (let [position (gpt/add from-position delta) + target-frame (ctst/top-nested-frame objects position)] + (set-change-frame-modifiers selected target-frame position)))) + (rx/take-until stopper)) - #_(rx/map #(hash-map :displacement (gmt/translate-matrix %))) - (rx/map #(array-map :v2 [{:type :move :vector %}])) + (->> position + ;; We ask for the snap position but we continue even if the result is not available + (rx/with-latest vector snap-delta) - (rx/map (partial set-modifiers ids)) - (rx/take-until stopper)) + ;; We try to use the previous snap so we don't have to wait for the result of the new + (rx/map snap/correct-snap-point) + + (rx/map (fn [move-vec] {:v2 [{:type :move :vector move-vec}]})) + + (rx/map (partial set-modifiers ids)) + (rx/take-until stopper))) (rx/of (dwu/start-undo-transaction) (calculate-frame-for-move ids) @@ -767,18 +822,22 @@ page-id (:current-page-id state) objects (wsh/lookup-page-objects state page-id) frame-id (ctst/top-nested-frame objects position) + layout? (get-in objects [frame-id :layout]) lookup (d/getf objects) + shapes (->> ids (cph/clean-loops objects) (keep lookup)) + moving-shapes - (->> ids - (cph/clean-loops objects) - (keep lookup) - (remove #(= (:frame-id %) frame-id))) + (cond->> shapes + (not layout?) + (remove #(= (:frame-id %) frame-id))) + + drop-index (when layout? (gsl/get-drop-index frame-id objects position)) changes (-> (pcb/empty-changes it page-id) (pcb/with-objects objects) - (pcb/change-parent frame-id moving-shapes))] + (pcb/change-parent frame-id moving-shapes drop-index))] (when-not (empty? changes) (rx/of (dch/commit-changes changes) diff --git a/frontend/src/app/main/ui/workspace/shapes.cljs b/frontend/src/app/main/ui/workspace/shapes.cljs index 2e71107b3..836114c51 100644 --- a/frontend/src/app/main/ui/workspace/shapes.cljs +++ b/frontend/src/app/main/ui/workspace/shapes.cljs @@ -12,7 +12,9 @@ others are defined using a generic wrapper implemented in common." (:require + [app.common.data.macros :as dm] [app.common.pages.helpers :as cph] + [app.common.uuid :as uuid] [app.main.ui.context :as ctx] [app.main.ui.shapes.circle :as circle] [app.main.ui.shapes.image :as image] @@ -55,33 +57,36 @@ (mf/deps objects) #(cph/objects-by-frame objects))] - [:& (mf/provider ctx/active-frames) {:value active-frames} - ;; Render font faces only for shapes that are part of the root - ;; frame but don't belongs to any other frame. - (let [xform (comp - (remove cph/frame-shape?) - (mapcat #(cph/get-children-with-self objects (:id %))))] - [:& ff/fontfaces-style {:shapes (into [] xform shapes)}]) + [:g {:id (dm/str "shape-" uuid/zero)} + [:& (mf/provider ctx/active-frames) {:value active-frames} + ;; Render font faces only for shapes that are part of the root + ;; frame but don't belongs to any other frame. + (let [xform (comp + (remove cph/frame-shape?) + (mapcat #(cph/get-children-with-self objects (:id %))))] + [:& ff/fontfaces-style {:shapes (into [] xform shapes)}]) - (for [shape shapes] - (cond - (not (cph/frame-shape? shape)) - [:& shape-wrapper - {:shape shape - :key (:id shape)}] + [:g.frame-children + (for [shape shapes] + [:g.ws-shape-wrapper + (cond + (not (cph/frame-shape? shape)) + [:& shape-wrapper + {:shape shape + :key (:id shape)}] - (cph/root-frame? shape) - [:& root-frame-wrapper - {:shape shape - :key (:id shape) - :objects (get frame-objects (:id shape)) - :thumbnail? (not (contains? active-frames (:id shape)))}] + (cph/root-frame? shape) + [:& root-frame-wrapper + {:shape shape + :key (:id shape) + :objects (get frame-objects (:id shape)) + :thumbnail? (not (contains? active-frames (:id shape)))}] - :else - [:& nested-frame-wrapper - {:shape shape - :key (:id shape) - :objects (get frame-objects (:id shape))}]))])) + :else + [:& nested-frame-wrapper + {:shape shape + :key (:id shape) + :objects (get frame-objects (:id shape))}])])]]])) (mf/defc shape-wrapper {::mf/wrap [#(mf/memo' % (mf/check-props ["shape"]))] @@ -98,20 +103,21 @@ opts #js {:shape shape :thumbnail? thumbnail?}] (when (and (some? shape) (not (:hidden shape))) - (case (:type shape) - :path [:> path/path-wrapper opts] - :text [:> text/text-wrapper opts] - :group [:> group-wrapper opts] - :rect [:> rect-wrapper opts] - :image [:> image-wrapper opts] - :circle [:> circle-wrapper opts] - :svg-raw [:> svg-raw-wrapper opts] - :bool [:> bool-wrapper opts] + [:g.ws-shape-wrapper + (case (:type shape) + :path [:> path/path-wrapper opts] + :text [:> text/text-wrapper opts] + :group [:> group-wrapper opts] + :rect [:> rect-wrapper opts] + :image [:> image-wrapper opts] + :circle [:> circle-wrapper opts] + :svg-raw [:> svg-raw-wrapper opts] + :bool [:> bool-wrapper opts] - ;; Only used when drawing a new frame. - :frame [:> nested-frame-wrapper opts] + ;; Only used when drawing a new frame. + :frame [:> nested-frame-wrapper opts] - nil)))) + nil)]))) (def group-wrapper (group/group-wrapper-factory shape-wrapper)) (def svg-raw-wrapper (svg-raw/svg-raw-wrapper-factory shape-wrapper)) diff --git a/frontend/src/app/main/ui/workspace/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/shapes/frame.cljs index a3745f16d..1de768035 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame.cljs @@ -24,87 +24,7 @@ [app.main.ui.workspace.shapes.frame.node-store :as fns] [app.main.ui.workspace.shapes.frame.thumbnail-render :as ftr] [beicon.core :as rx] - [rumext.v2 :as mf] - - [app.common.geom.shapes :as gsh] - [app.common.geom.shapes.layout :as gsl] - [app.main.data.workspace.state-helpers :as wsh] - [app.main.store :as st])) - -(mf/defc debug-layout - {::mf/wrap-props false} - [props] - - (let [shape (unchecked-get props "shape") - children (-> (wsh/lookup-page-objects @st/state) - (cph/get-immediate-children (:id shape))) - - layout-data (gsl/calc-layout-data shape children) - - drop-areas - (gsl/drop-areas shape layout-data children) - - ] - - [:g.debug-layout {:pointer-events "none"} - (for [[idx drop-area] (d/enumerate drop-areas)] - [:rect {:x (:x drop-area) - :y (:y drop-area) - :width (:width drop-area) - :height (:height drop-area) - :style {:fill "blue" - :fill-opacity 0.3 - :stroke "red" - :stroke-width 1 - :stroke-dasharray "3 6"}}]) - - - #_(for [[idx layout-line] (d/enumerate (:layout-lines layout-data))] - (let [col? (gsl/col? shape) - row? (gsl/row? shape) - h-center? (and row? (gsl/h-center? shape)) - h-end? (and row? (gsl/h-end? shape)) - v-center? (and col? (gsl/v-center? shape)) - v-end? (and row? (gsl/v-end? shape)) - - line-width - (+ (-> layout-line :line-width) - (:margin-x shape) - (if col? - (* (:layout-gap layout-line) (dec (-> layout-line :num-children))) - 0)) - - line-height - (+ (-> layout-line :line-height) - (:margin-y shape) - (if row? - (* (:layout-gap layout-line) (dec (-> layout-line :num-children))) - 0)) - ] - [:g {:key (dm/str "line-" idx)} - [:rect {:x (- (-> layout-line :start-p :x) - (cond - h-center? (/ line-width 2) - h-end? line-width - :else 0)) - :y (- (-> layout-line :start-p :y) - (cond - v-center? (/ line-height 2) - v-end? line-height - :else 0)) - :width line-width - :height line-height - :style {:fill "blue" - :fill-opacity 0.3} - }] - #_[:line {:x1 (-> layout-line :start-p :x) - :y1 (-> layout-line :start-p :y) - :x2 (+ (-> layout-line :start-p :x) (if col? line-width 0)) - :y2 (+ (-> layout-line :start-p :y) (if row? line-height 0)) - :transform (gsh/transform-str shape) - :style {:fill "none" - :stroke "red" - :stroke-width 2}}]]))])) + [rumext.v2 :as mf])) (defn frame-shape-factory [shape-wrapper] @@ -119,12 +39,9 @@ childs-ref (mf/use-memo (mf/deps (:id shape)) #(refs/children-objects (:id shape))) childs (mf/deref childs-ref)] - [:* - [:& (mf/provider embed/context) {:value true} - [:& shape-container {:shape shape :ref ref :disable-shadows? (cph/root-frame? shape)} - [:& frame-shape {:shape shape :childs childs} ]]] - - #_[:& debug-layout {:shape shape}]])))) + [:& (mf/provider embed/context) {:value true} + [:& shape-container {:shape shape :ref ref :disable-shadows? (cph/root-frame? shape)} + [:& frame-shape {:shape shape :childs childs} ]]])))) (defn check-props [new-props old-props] diff --git a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs index 0ea026601..6d95966d4 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs @@ -13,8 +13,10 @@ [app.common.geom.shapes :as gsh] [app.common.types.modifiers :as ctm] [app.main.store :as st] + [app.main.ui.hooks :as hooks] [app.main.ui.workspace.viewport.utils :as vwu] [app.util.dom :as dom] + [app.util.globals :as globals] [rumext.v2 :as mf])) (defn- transform-no-resize @@ -78,13 +80,20 @@ [result width height])) +(defn get-shape-node + ([id] + (get-shape-node js/document id)) + + ([base-node id] + (if (= (.-id base-node) (dm/str "shape-" id)) + base-node + (dom/query base-node (dm/str "#shape-" id))))) + (defn get-nodes "Retrieve the DOM nodes to apply the matrix transformation" [base-node {:keys [id type masked-group?] :as shape}] (when (some? base-node) - (let [shape-node (if (= (.-id base-node) (dm/str "shape-" id)) - base-node - (dom/query base-node (dm/str "#shape-" id))) + (let [shape-node (get-shape-node base-node id) frame? (= :frame type) group? (= :group type) @@ -164,7 +173,7 @@ (defn set-transform-att! [node att value] - + (let [old-att (dom/get-attribute node (dm/str "data-old-" att)) new-value (if (some? old-att) (dm/str value " " old-att) @@ -269,6 +278,33 @@ (ctm/modifiers->transform center modifiers))) modifiers)))) + structure-changes + (mf/use-memo + (mf/deps modifiers) + (fn [] + (into {} + (comp (filter (fn [[_ val]] (-> val :modifiers :v3 some?))) + (map (fn [[key val]] + [key (-> val :modifiers :v3)]))) + + modifiers))) + + structure-changes (hooks/use-equal-memo structure-changes) + + add-children + (mf/use-memo + (mf/deps structure-changes) + (fn [] + (into [] + (mapcat (fn [[frame-id changes]] + (->> changes + (filter (fn [{:keys [type]}] (= type :add-children))) + (mapcat (fn [{:keys [value]}] + (->> value (map (fn [id] {:frame frame-id :shape id})))))))) + structure-changes))) + + add-children-prev (hooks/use-previous add-children) + shapes (mf/use-memo (mf/deps transforms) @@ -280,6 +316,31 @@ prev-modifiers (mf/use-var nil) prev-transforms (mf/use-var nil)] + (mf/use-effect + (mf/deps add-children) + (fn [] + (doseq [{:keys [frame shape]} add-children-prev] + (let [frame-node (get-shape-node node frame) + shape-node (get-shape-node shape) + mirror-node (dom/query frame-node (dm/fmt ".mirror-shape[href='#shape-%'" shape))] + (when mirror-node (.remove mirror-node)) + (dom/remove-attribute! (dom/get-parent shape-node) "display"))) + + (doseq [{:keys [frame shape]} add-children] + (let [frame-node (get-shape-node node frame) + shape-node (get-shape-node shape) + + use-node + (.createElementNS globals/document "http://www.w3.org/2000/svg" "use") + + contents-node + (or (dom/query frame-node ".frame-children") frame-node)] + + (dom/set-attribute! use-node "href" (dm/fmt "#shape-%" shape)) + (dom/add-class! use-node "mirror-shape") + (dom/append-child! contents-node use-node) + (dom/set-attribute! (dom/get-parent shape-node) "display" "none"))))) + (mf/use-layout-effect (mf/deps transforms) (fn [] diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index 4c219d3ac..2896f6d4b 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -23,6 +23,7 @@ [app.main.ui.workspace.shapes.text.viewport-texts-html :as stvh] [app.main.ui.workspace.viewport.actions :as actions] [app.main.ui.workspace.viewport.comments :as comments] + [app.main.ui.workspace.viewport.debug :as wvd] [app.main.ui.workspace.viewport.drawarea :as drawarea] [app.main.ui.workspace.viewport.frame-grid :as frame-grid] [app.main.ui.workspace.viewport.gradients :as gradients] @@ -41,85 +42,7 @@ [app.main.ui.workspace.viewport.widgets :as widgets] [beicon.core :as rx] [debug :refer [debug?]] - [rumext.v2 :as mf] - - [app.common.uuid :as uuid] - [app.common.geom.shapes :as gsh] - [app.common.geom.shapes.layout :as gsl] - [app.main.data.workspace.state-helpers :as wsh] - [app.main.store :as st] - - )) - -(mf/defc debug-layout - {::mf/wrap-props false} - [props] - - (let [shape (unchecked-get props "shape") - objects (unchecked-get props "objects") - children (cph/get-immediate-children objects (:id shape)) - layout-data (gsl/calc-layout-data shape children) - drop-areas (gsl/drop-areas shape layout-data children)] - - [:g.debug-layout {:pointer-events "none"} - (for [[idx drop-area] (d/enumerate drop-areas)] - [:rect {:x (:x drop-area) - :y (:y drop-area) - :width (:width drop-area) - :height (:height drop-area) - :style {:fill "blue" - :fill-opacity 0.3 - :stroke "red" - :stroke-width 1 - :stroke-dasharray "3 6"}}]) - - - #_(for [[idx layout-line] (d/enumerate (:layout-lines layout-data))] - (let [col? (gsl/col? shape) - row? (gsl/row? shape) - h-center? (and row? (gsl/h-center? shape)) - h-end? (and row? (gsl/h-end? shape)) - v-center? (and col? (gsl/v-center? shape)) - v-end? (and row? (gsl/v-end? shape)) - - line-width - (+ (-> layout-line :line-width) - (:margin-x shape) - (if col? - (* (:layout-gap layout-line) (dec (-> layout-line :num-children))) - 0)) - - line-height - (+ (-> layout-line :line-height) - (:margin-y shape) - (if row? - (* (:layout-gap layout-line) (dec (-> layout-line :num-children))) - 0)) - ] - [:g {:key (dm/str "line-" idx)} - [:rect {:x (- (-> layout-line :start-p :x) - (cond - h-center? (/ line-width 2) - h-end? line-width - :else 0)) - :y (- (-> layout-line :start-p :y) - (cond - v-center? (/ line-height 2) - v-end? line-height - :else 0)) - :width line-width - :height line-height - :style {:fill "blue" - :fill-opacity 0.3} - }] - #_[:line {:x1 (-> layout-line :start-p :x) - :y1 (-> layout-line :start-p :y) - :x2 (+ (-> layout-line :start-p :x) (if col? line-width 0)) - :y2 (+ (-> layout-line :start-p :y) (if row? line-height 0)) - :transform (gsh/transform-str shape) - :style {:fill "none" - :stroke "red" - :stroke-width 2}}]]))])) + [rumext.v2 :as mf])) ;; --- Viewport @@ -493,15 +416,12 @@ :hover-frame frame-parent :disabled-guides? disabled-guides?}]) - (let [selected-frame (when (= 1 (count selected-shapes)) - (let [selected-shape (get objects-modified (first selected))] - (when (= :frame (:type selected-shape)) - selected-shape))) + ;; DEBUG LAYOUT DROP-ZONES + (when (debug? :layout-drop-zones) + [:& wvd/debug-layout {:selected-shapes selected-shapes + :objects objects-modified + :hover-top-frame-id @hover-top-frame-id}]) - top-frame (or selected-frame (get objects-modified @hover-top-frame-id))] - (when (and top-frame (not= uuid/zero top-frame) (:layout top-frame)) - [:& debug-layout {:shape top-frame - :objects objects-modified}])) (when show-selection-handlers? [:g.selection-handlers {:clipPath "url(#clip-handlers)"} diff --git a/frontend/src/app/main/ui/workspace/viewport/debug.cljs b/frontend/src/app/main/ui/workspace/viewport/debug.cljs new file mode 100644 index 000000000..0f23f9eee --- /dev/null +++ b/frontend/src/app/main/ui/workspace/viewport/debug.cljs @@ -0,0 +1,54 @@ +;; 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.main.ui.workspace.viewport.debug + (:require + [app.common.data :as d] + [app.common.data.macros :as dm] + [app.common.geom.shapes :as gsh] + [app.common.geom.shapes.layout :as gsl] + [app.common.pages.helpers :as cph] + [rumext.v2 :as mf])) + +(mf/defc debug-layout + "Debug component to show the auto-layout drop areas" + {::mf/wrap-props false} + [props] + + (let [objects (unchecked-get props "objects") + selected-shapes (unchecked-get props "selected-shapes") + hover-top-frame-id (unchecked-get props "hover-top-frame-id") + + selected-frame + (when (and (= (count selected-shapes) 1) (= :frame (-> selected-shapes first :type))) + (first selected-shapes)) + + shape (or selected-frame (get objects hover-top-frame-id))] + + (when (and shape (:layout shape)) + (let [children (cph/get-immediate-children objects (:id shape)) + layout-data (gsl/calc-layout-data shape children) + drop-areas (gsl/drop-areas shape layout-data children)] + [:g.debug-layout {:pointer-events "none" + :transform (gsh/transform-str shape)} + (for [[idx drop-area] (d/enumerate drop-areas)] + [:g.drop-area {:key (dm/str "drop-area-" idx)} + [:rect {:x (:x drop-area) + :y (:y drop-area) + :width (:width drop-area) + :height (:height drop-area) + :style {:fill "blue" + :fill-opacity 0.3 + :stroke "red" + :stroke-width 1 + :stroke-dasharray "3 6"}}] + [:text {:x (:x drop-area) + :y (:y drop-area) + :width (:width drop-area) + :height (:height drop-area) + :alignment-baseline "hanging" + :fill "black"} + (:index drop-area)]])])))) diff --git a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs index cc6c7bf8d..2ea2310da 100644 --- a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs @@ -11,6 +11,7 @@ [app.common.pages :as cp] [app.common.pages.helpers :as cph] [app.common.types.shape-tree :as ctt] + [app.common.uuid :as uuid] [app.main.data.shortcuts :as dsc] [app.main.data.workspace :as dw] [app.main.data.workspace.path.shortcuts :as psc] @@ -28,8 +29,7 @@ [beicon.core :as rx] [debug :refer [debug?]] [goog.events :as events] - [rumext.v2 :as mf] - [app.common.types.shape-tree :as ctst]) + [rumext.v2 :as mf]) (:import goog.events.EventType)) (defn setup-dom-events [viewport-ref zoom disable-paste in-viewport?] @@ -217,7 +217,7 @@ (get objects))] (reset! hover hover-shape) (reset! hover-ids ids) - (reset! hover-top-frame-id (ctst/top-nested-frame objects (deref last-point-ref)))))))) + (reset! hover-top-frame-id (ctt/top-nested-frame objects (deref last-point-ref)))))))) (defn setup-viewport-modifiers [modifiers objects] @@ -225,7 +225,7 @@ (mf/use-memo (mf/deps objects) #(ctt/get-root-shapes-ids objects)) - modifiers (select-keys modifiers root-frame-ids)] + modifiers (select-keys modifiers (conj root-frame-ids uuid/zero))] (sfd/use-dynamic-modifiers objects globals/document modifiers))) (defn inside-vbox [vbox objects frame-id] diff --git a/frontend/src/debug.cljs b/frontend/src/debug.cljs index 96c986604..3a3b9f366 100644 --- a/frontend/src/debug.cljs +++ b/frontend/src/debug.cljs @@ -67,6 +67,9 @@ ;; Disable frame thumbnails :disable-frame-thumbnails + + ;; Enable a widget to show the auto-layout drop-zones + :layout-drop-zones }) ;; These events are excluded when we activate the :events flag @@ -294,9 +297,16 @@ num-nodes (->> (dom/seq-nodes root-node) count)] #js {:number num-nodes})) -#_(defn modif->js +(defn modif->js [modif-tree objects] (clj->js (into {} (map (fn [[k v]] [(get-in objects [k :name]) v])) modif-tree))) + +(defn ^:export dump-modifiers + [] + (let [page-id (get @st/state :current-page-id) + objects (get-in @st/state [:workspace-data :pages-index page-id :objects])] + (.log js/console (modif->js (:workspace-modifiers @st/state) objects))) + nil) From 11f347941eae4bde24ba0ad053b25d6acd176c03 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Wed, 19 Oct 2022 13:27:44 +0200 Subject: [PATCH 08/36] :sparkles: Refactor for new modifiers --- .../app/common/geom/shapes/constraints.cljc | 78 ++--- common/src/app/common/geom/shapes/layout.cljc | 185 +++------- .../src/app/common/geom/shapes/modifiers.cljc | 187 +--------- .../common/geom/shapes/pixel_precision.cljc | 53 +++ common/src/app/common/geom/shapes/points.cljc | 61 ++++ .../app/common/geom/shapes/transforms.cljc | 163 +-------- common/src/app/common/types/modifiers.cljc | 325 +++++++++++------- .../app/main/data/workspace/drawing/box.cljs | 5 +- .../src/app/main/data/workspace/shapes.cljs | 1 - .../src/app/main/data/workspace/texts.cljs | 8 +- .../app/main/data/workspace/transforms.cljs | 88 ++--- .../src/app/main/ui/workspace/shapes.cljs | 2 +- .../shapes/frame/dynamic_modifiers.cljs | 104 +----- .../shapes/text/viewport_texts_html.cljs | 7 - .../app/main/ui/workspace/viewport/debug.cljs | 2 +- 15 files changed, 445 insertions(+), 824 deletions(-) create mode 100644 common/src/app/common/geom/shapes/pixel_precision.cljc create mode 100644 common/src/app/common/geom/shapes/points.cljc diff --git a/common/src/app/common/geom/shapes/constraints.cljc b/common/src/app/common/geom/shapes/constraints.cljc index 2e9aa8a9b..ce4171d02 100644 --- a/common/src/app/common/geom/shapes/constraints.cljc +++ b/common/src/app/common/geom/shapes/constraints.cljc @@ -6,13 +6,13 @@ (ns app.common.geom.shapes.constraints (:require - [app.common.data :as d] [app.common.geom.point :as gpt] [app.common.geom.shapes.common :as gco] [app.common.geom.shapes.intersect :as gsi] [app.common.geom.shapes.rect :as gre] [app.common.geom.shapes.transforms :as gst] [app.common.math :as mth] + [app.common.types.modifiers :as ctm] [app.common.uuid :as uuid])) ;; Auxiliary methods to work in an specifica axis @@ -152,8 +152,7 @@ end-angl (gpt/angle-with-other end-before end-after) target-end (if (mth/close? end-angl 180) (- (gpt/length end-before)) (gpt/length end-before)) disp-vector-end (gpt/subtract end-after (gpt/scale (gpt/unit end-after) target-end))] - [{:type :move - :vector disp-vector-end}])) + (ctm/move disp-vector-end))) (defmethod constraint-modifier :fixed [_ axis child-points-before parent-points-before child-points-after parent-points-after transformed-parent] @@ -177,11 +176,7 @@ scale (* resize-sign (/ (gpt/length after-vec) (gpt/length before-vec))) ] - [{:type :resize - :vector (get-scale axis scale) - :origin c0 - :transform (:transform transformed-parent) - :transform-inverse (:transform-inverse transformed-parent)}])) + (ctm/resize (get-scale axis scale) c0 (:transform transformed-parent) (:transform-inverse transformed-parent)))) (defmethod constraint-modifier :center [_ axis child-points-before parent-points-before child-points-after parent-points-after] @@ -190,8 +185,7 @@ center-angl (gpt/angle-with-other center-before center-after) target-center (if (mth/close? center-angl 180) (- (gpt/length center-before)) (gpt/length center-before)) disp-vector-center (gpt/subtract center-after (gpt/scale (gpt/unit center-after) target-center))] - [{:type :move - :vector disp-vector-center}])) + (ctm/move disp-vector-center))) (defmethod constraint-modifier :default [_ _ _ _ _] []) @@ -222,29 +216,6 @@ :top :scale))) -#_(defn clean-modifiers - "Remove redundant modifiers" - [{:keys [displacement resize-vector resize-vector-2] :as modifiers}] - - (cond-> modifiers - ;; Displacement with value 0. We don't move in any direction - (and (some? displacement) - (mth/almost-zero? (:e displacement)) - (mth/almost-zero? (:f displacement))) - (dissoc :displacement) - - ;; Resize with value very close to 1 means no resize - (and (some? resize-vector) - (mth/almost-zero? (- 1.0 (:x resize-vector))) - (mth/almost-zero? (- 1.0 (:y resize-vector)))) - (dissoc :resize-origin :resize-vector) - - (and (some? resize-vector) - (mth/almost-zero? (- 1.0 (:x resize-vector-2))) - (mth/almost-zero? (- 1.0 (:y resize-vector-2)))) - (dissoc :resize-origin-2 :resize-vector-2))) - - (defn bounding-box-parent-transform "Returns a bounding box for the child in the same coordinate system as the parent. @@ -259,36 +230,27 @@ (defn normalize-modifiers "Before aplying constraints we need to remove the deformation caused by the resizing of the parent" - [constraints-h constraints-v modifiers child parent transformed-child transformed-parent] + [constraints-h constraints-v modifiers child parent transformed-child {:keys [transform transform-inverse] :as transformed-parent}] (let [child-bb-before (gst/parent-coords-rect child parent) child-bb-after (gst/parent-coords-rect transformed-child transformed-parent) scale-x (/ (:width child-bb-before) (:width child-bb-after)) - scale-y (/ (:height child-bb-before) (:height child-bb-after))] + scale-y (/ (:height child-bb-before) (:height child-bb-after)) - (-> modifiers - (update :v2 #(cond-> % - (not= :scale constraints-h) - (conj - ;; This resize will leave the shape in its original position relative to the parent - {:type :resize - :transform (:transform transformed-parent) - :transform-inverse (:transform-inverse transformed-parent) - :origin (-> transformed-parent :points (nth 0)) - :vector (gpt/point scale-x 1)}) + ;; TODO LAYOUT: Is the first always the origin? + resize-origin (-> transformed-parent :points first)] - (not= :scale constraints-v) - (conj - {:type :resize - :transform (:transform transformed-parent) - :transform-inverse (:transform-inverse transformed-parent) - :origin (-> transformed-parent :points (nth 0)) - :vector (gpt/point 1 scale-y)})))))) + (cond-> modifiers + (not= :scale constraints-h) + (ctm/set-resize (gpt/point scale-x 1) resize-origin transform transform-inverse) + + (not= :scale constraints-v) + (ctm/set-resize (gpt/point 1 scale-y) resize-origin transform transform-inverse)))) (defn calc-child-modifiers [parent child modifiers ignore-constraints transformed-parent] - (let [modifiers (select-keys modifiers [:v2]) + (let [modifiers (ctm/select-child-modifiers modifiers) constraints-h (if-not ignore-constraints @@ -306,12 +268,12 @@ (let [transformed-child (gst/transform-shape child modifiers) modifiers (normalize-modifiers constraints-h constraints-v modifiers child parent transformed-child transformed-parent) - tranformed-child-2 (gst/transform-shape child modifiers) + transformed-child (gst/transform-shape child modifiers) parent-points-before (:points parent) child-points-before (bounding-box-parent-transform child parent) parent-points-after (:points transformed-parent) - child-points-after (bounding-box-parent-transform tranformed-child-2 transformed-parent) + child-points-after (bounding-box-parent-transform transformed-child transformed-parent) modifiers-h (constraint-modifier (constraints-h const->type+axis) :x child-points-before parent-points-before @@ -323,6 +285,6 @@ child-points-after parent-points-after transformed-parent)] - (update modifiers :v2 d/concat-vec modifiers-h modifiers-v))))) - - + (-> modifiers + (ctm/add-modifiers modifiers-h) + (ctm/add-modifiers modifiers-v)))))) diff --git a/common/src/app/common/geom/shapes/layout.cljc b/common/src/app/common/geom/shapes/layout.cljc index a5f0d79c5..d3282b357 100644 --- a/common/src/app/common/geom/shapes/layout.cljc +++ b/common/src/app/common/geom/shapes/layout.cljc @@ -10,9 +10,11 @@ [app.common.geom.matrix :as gmt] [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 gsr] [app.common.geom.shapes.transforms :as gst] - [app.common.pages.helpers :as cph])) + [app.common.pages.helpers :as cph] + [app.common.types.modifiers :as ctm])) ;; :layout ;; true if active, false if not ;; :layout-dir ;; :right, :left, :top, :bottom @@ -56,107 +58,18 @@ [{:keys [layout-v-orientation]}] (= layout-v-orientation :bottom)) -(defn add-padding [transformed-rect {:keys [layout-padding-type layout-padding]}] - (let [{:keys [p1 p2 p3 p4]} layout-padding - [p1 p2 p3 p4] - (if (= layout-padding-type :multiple) - [p1 p2 p3 p4] - [p1 p1 p1 p1])] - - (-> transformed-rect - (update :y + p1) - (update :width - p2 p3) - (update :x + p3) - (update :height - p1 p4)))) - -;; FUNCTIONS TO WORK WITH POINTS SQUARES - -(defn origin - [points] - (nth points 0)) - -(defn start-hv - "Horizontal vector from the origin with a magnitude `val`" - [[p0 p1 _ _] val] - (-> (gpt/to-vec p0 p1) - (gpt/unit) - (gpt/scale val))) - -(defn end-hv - "Horizontal vector from the oposite to the origin in the x axis with a magnitude `val`" - [[p0 p1 _ _] val] - (-> (gpt/to-vec p1 p0) - (gpt/unit) - (gpt/scale val))) - -(defn start-vv - "Vertical vector from the oposite to the origin in the x axis with a magnitude `val`" - [[p0 _ _ p3] val] - (-> (gpt/to-vec p0 p3) - (gpt/unit) - (gpt/scale val))) - -(defn end-vv - "Vertical vector from the oposite to the origin in the x axis with a magnitude `val`" - [[p0 _ _ p3] val] - (-> (gpt/to-vec p3 p0) - (gpt/unit) - (gpt/scale val))) - -;;(defn start-hp -;; [[p0 _ _ _ :as points] val] -;; (gpt/add p0 (start-hv points val))) -;; -;;(defn end-hp -;; "Horizontal Vector from the oposite to the origin in the x axis with a magnitude `val`" -;; [[_ p1 _ _ :as points] val] -;; (gpt/add p1 (end-hv points val))) -;; -;;(defn start-vp -;; "Vertical Vector from the oposite to the origin in the x axis with a magnitude `val`" -;; [[p0 _ _ _ :as points] val] -;; (gpt/add p0 (start-vv points val))) -;; -;;(defn end-vp -;; "Vertical Vector from the oposite to the origin in the x axis with a magnitude `val`" -;; [[_ _ p3 _ :as points] val] -;; (gpt/add p3 (end-vv points val))) - -(defn width-points - [[p0 p1 _ _]] - (gpt/length (gpt/to-vec p0 p1))) - -(defn height-points - [[p0 _ _ p3]] - (gpt/length (gpt/to-vec p0 p3))) - -(defn pad-points - [[p0 p1 p2 p3 :as points] pad-top pad-right pad-bottom pad-left] - (let [top-v (start-vv points pad-top) - right-v (end-hv points pad-right) - bottom-v (end-vv points pad-bottom) - left-v (start-hv points pad-left)] - - [(-> p0 (gpt/add left-v) (gpt/add top-v)) - (-> p1 (gpt/add right-v) (gpt/add top-v)) - (-> p2 (gpt/add right-v) (gpt/add bottom-v)) - (-> p3 (gpt/add left-v) (gpt/add bottom-v))])) - -;;;; - - (defn calc-layout-lines [{:keys [layout-gap layout-wrap-type] :as parent} children layout-bounds] (let [wrap? (= layout-wrap-type :wrap) - layout-width (width-points layout-bounds) - layout-height (height-points layout-bounds) + layout-width (gpo/width-points layout-bounds) + layout-height (gpo/height-points layout-bounds) reduce-fn (fn [[{:keys [line-width line-height num-children line-fill? child-fill? num-child-fill] :as line-data} result] child] (let [child-bounds (gst/parent-coords-points child parent) - child-width (width-points child-bounds) - child-height (height-points child-bounds) + child-width (gpo/width-points child-bounds) + child-height (gpo/height-points child-bounds) col? (col? parent) row? (row? parent) @@ -212,8 +125,8 @@ (defn calc-layout-lines-position [{:keys [layout-gap] :as parent} layout-bounds layout-lines] - (let [layout-width (width-points layout-bounds) - layout-height (height-points layout-bounds) + (let [layout-width (gpo/width-points layout-bounds) + layout-height (gpo/height-points layout-bounds) row? (row? parent) col? (col? parent) space-between? (= :space-between (:layout-type parent)) @@ -225,16 +138,16 @@ (letfn [;; short version to not repeat always with all arguments (xv [val] - (start-hv layout-bounds val)) + (gpo/start-hv layout-bounds val)) ;; short version to not repeat always with all arguments (yv [val] - (start-vv layout-bounds val)) + (gpo/start-vv layout-bounds val)) (get-base-line [total-width total-height] - (cond-> (origin layout-bounds) + (cond-> (gpo/origin layout-bounds) (and row? h-center?) (gpt/add (xv (/ (- layout-width total-width) 2))) @@ -348,8 +261,8 @@ layout-bounds {:keys [num-children line-width line-height child-fill?] :as line-data}] - (let [width (width-points layout-bounds) - height (height-points layout-bounds) + (let [width (gpo/width-points layout-bounds) + height (gpo/height-points layout-bounds) layout-gap (cond @@ -396,8 +309,8 @@ v-end? (v-end? parent) points (:points parent) - xv (partial start-hv points) - yv (partial start-vv points) + xv (partial gpo/start-hv points) + yv (partial gpo/start-vv points) corner-p (cond-> start-p @@ -447,26 +360,18 @@ (cond (and (col? parent) (= :fill layout-h-behavior) child-fill?) - (let [layout-width (width-points layout-bounds) + (let [layout-width (gpo/width-points layout-bounds) fill-space (- layout-width line-width (* layout-gap (dec num-children))) fill-width (/ fill-space (:num-child-fill layout-data)) fill-scale (/ fill-width child-width)] + {:width fill-width - :modifiers [{:type :resize - :origin child-origin - :transform transform - :transform-inverse transform-inverse - :vector (gpt/point fill-scale 1)}]}) + :modifiers (ctm/resize (gpt/point fill-scale 1) child-origin transform transform-inverse)}) (and (row? parent) (= :fill layout-h-behavior) line-fill?) (let [fill-scale (/ line-width child-width)] {:width line-width - :modifiers [{:type :resize - :origin child-origin - :transform transform - :transform-inverse transform-inverse - :vector (gpt/point fill-scale 1)}]}) - )) + :modifiers (ctm/resize (gpt/point fill-scale 1) child-origin transform transform-inverse)}))) (defn calc-fill-height-data "Calculates the size and modifiers for the height of an auto-fill child" @@ -477,43 +382,33 @@ (cond (and (row? parent) (= :fill layout-v-behavior) child-fill?) - (let [layout-height (height-points layout-bounds) + (let [layout-height (gpo/height-points layout-bounds) fill-space (- layout-height line-height (* layout-gap (dec num-children))) fill-height (/ fill-space (:num-child-fill layout-data)) fill-scale (/ fill-height child-height)] {:height fill-height - :modifiers [{:type :resize - :origin child-origin - :transform transform - :transform-inverse transform-inverse - :vector (gpt/point 1 fill-scale)}]}) + :modifiers (ctm/resize (gpt/point 1 fill-scale) child-origin transform transform-inverse)}) (and (col? parent) (= :fill layout-v-behavior) line-fill?) (let [fill-scale (/ line-height child-height)] {:height line-height - :modifiers [{:type :resize - :origin child-origin - :transform transform - :transform-inverse transform-inverse - :vector (gpt/point 1 fill-scale)}]}) - )) + :modifiers (ctm/resize (gpt/point 1 fill-scale) child-origin transform transform-inverse)}))) (defn normalize-child-modifiers "Apply the modifiers and then normalized them against the parent coordinates" - [parent child modifiers transformed-parent] + [parent child modifiers {:keys [transform transform-inverse] :as transformed-parent}] (let [transformed-child (gst/transform-shape child modifiers) child-bb-before (gst/parent-coords-rect child parent) child-bb-after (gst/parent-coords-rect transformed-child transformed-parent) scale-x (/ (:width child-bb-before) (:width child-bb-after)) - scale-y (/ (:height child-bb-before) (:height child-bb-after))] + scale-y (/ (:height child-bb-before) (:height child-bb-after)) + + resize-origin (-> transformed-parent :points first) ;; TODO LAYOUT: IS always the origin?n + resize-vector (gpt/point scale-x scale-y)] (-> modifiers - (update :v2 #(conj % - {:type :resize - :transform (:transform transformed-parent) - :transform-inverse (:transform-inverse transformed-parent) - :origin (-> transformed-parent :points (nth 0)) - :vector (gpt/point scale-x scale-y)}))))) + (ctm/select-child-modifiers) + (ctm/set-resize resize-vector resize-origin transform transform-inverse)))) (defn calc-layout-data "Digest the layout data to pass it to the constrains" @@ -529,7 +424,7 @@ ;; Normalize the points to remove flips points (gst/parent-coords-points parent parent) - layout-bounds (pad-points points pad-top pad-right pad-bottom pad-left) + layout-bounds (gpo/pad-points points pad-top pad-right pad-bottom pad-left) ;; Reverse reverse? (or (= :left layout-dir) (= :bottom layout-dir)) @@ -549,9 +444,9 @@ [parent child layout-line] (let [child-bounds (gst/parent-coords-points child parent) - child-origin (origin child-bounds) - child-width (width-points child-bounds) - child-height (height-points child-bounds) + child-origin (gpo/origin child-bounds) + child-width (gpo/width-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-height (calc-fill-height-data parent child child-origin child-height layout-line) @@ -564,15 +459,15 @@ move-vec (gpt/to-vec child-origin corner-p) modifiers - (-> [] - (cond-> fill-width (d/concat-vec (:modifiers fill-width))) - (cond-> fill-height (d/concat-vec (:modifiers fill-height))) - (conj {:type :move :vector move-vec}))] + (-> (ctm/empty-modifiers) + (cond-> fill-width (ctm/add-modifiers (:modifiers fill-width))) + (cond-> fill-height (ctm/add-modifiers (:modifiers fill-height))) + (ctm/set-move move-vec))] [modifiers layout-line])) -(defn drop-areas +(defn layout-drop-areas [{:keys [margin-x margin-y] :as frame} layout-data children] (let [col? (col? frame) @@ -730,6 +625,6 @@ position (gmt/transform-point-center position (gco/center-shape frame) (:transform-inverse frame)) children (cph/get-immediate-children objects frame-id) layout-data (calc-layout-data frame children) - drop-areas (drop-areas frame layout-data children) + drop-areas (layout-drop-areas frame layout-data children) area (d/seek #(gsr/contains-point? % position) drop-areas)] (:index area))) diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index 6cb5f0d6f..3660aec60 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -7,118 +7,22 @@ (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.pixel-precision :as gpp] [app.common.geom.shapes.transforms :as gtr] - [app.common.math :as mth] [app.common.types.modifiers :as ctm] [app.common.uuid :as uuid])) -;; TODO LAYOUT: ADAPT TO NEW MODIFIERS -(defn set-pixel-precision - "Adjust modifiers so they adjust to the pixel grid" - [modifiers shape] - - (if (and (some? (:resize-transform modifiers)) - (not (gmt/unit? (: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 objects parent ignore-constraints snap-pixel?] - ;; TODO LAYOUT: SNAP PIXEL! (letfn [(set-child [transformed-parent _snap-pixel? modif-tree child] (let [modifiers (get-in modif-tree [(:id parent) :modifiers]) child-modifiers (gct/calc-child-modifiers parent child modifiers ignore-constraints transformed-parent) - ;;child-modifiers (cond-> child-modifiers snap-pixel? (set-pixel-precision child)) - ] + child-modifiers (cond-> child-modifiers snap-pixel? (gpp/set-pixel-precision child))] (cond-> modif-tree (not (ctm/empty-modifiers? child-modifiers)) - (update-in [(:id child) :modifiers :v2] d/concat-vec (:v2 child-modifiers)))))] - + (update-in [(:id child) :modifiers] ctm/add-modifiers child-modifiers))))] (let [children (map (d/getf objects) (:shapes parent)) modifiers (get-in modif-tree [(:id parent) :modifiers]) transformed-parent (gtr/transform-shape parent modifiers)] @@ -144,7 +48,7 @@ child-modifiers (gcl/normalize-child-modifiers parent child modifiers transformed-parent)] (cond-> modif-tree (not (ctm/empty-modifiers? child-modifiers)) - (update-in [(:id child) :modifiers :v2] d/concat-vec (:v2 child-modifiers))))) + (update-in [(:id child) :modifiers] ctm/add-modifiers child-modifiers)))) (apply-modifiers [modif-tree child] (let [modifiers (get-in modif-tree [(:id child) :modifiers])] @@ -162,7 +66,7 @@ modif-tree (cond-> modif-tree (d/not-empty? modifiers) - (update-in [(:id child) :modifiers :v2] d/concat-vec modifiers))] + (update-in [(:id child) :modifiers] ctm/add-modifiers modifiers))] [layout-line modif-tree]))] @@ -186,7 +90,7 @@ pending (rest layout-lines) from-idx 0] - + (if (and (some? layout-line) (<= from-idx max-idx)) (let [to-idx (+ from-idx (:num-children layout-line)) children (subvec children from-idx to-idx) @@ -197,73 +101,6 @@ modif-tree))))) -#_(defn set-layout-modifiers' - ;; TODO LAYOUT: SNAP PIXEL! - [modif-tree objects parent _snap-pixel?] - - (letfn [(transform-child [child] - (let [modifiers (get modif-tree (:id child)) - - child - (cond-> child - (some? modifiers) - (-> (merge modifiers) gtr/transform-shape) - - (and (nil? modifiers) (group? child)) - (gtr/apply-group-modifiers objects modif-tree)) - - child - (-> child - (gtr/apply-transform (gmt/transform-in (gco/center-shape parent) (:transform-inverse parent))))] - - child)) - - (set-layout-modifiers [parent transform [layout-data modif-tree] child] - (let [[modifiers layout-data] - (gcl/calc-layout-modifiers parent transform child layout-data) - - modif-tree - (cond-> modif-tree - (d/not-empty? modifiers) - (update-in [(:id child) :modifiers :v2] d/concat-vec modifiers))] - - [layout-data modif-tree]))] - - (let [modifiers (get modif-tree (:id parent)) - shape (-> parent (merge modifiers) gtr/transform-shape) - children (->> (:shapes shape) - (map (d/getf objects)) - (map transform-child)) - - center (gco/center-shape shape) - {:keys [transform transform-inverse]} shape - - shape - (-> shape - (gtr/apply-transform (gmt/transform-in center transform-inverse))) - - transformed-rect (:selrect shape) - - layout-data (gcl/calc-layout-data shape children transformed-rect) - children (into [] (cond-> children (:reverse? layout-data) reverse)) - - max-idx (dec (count children)) - layout-lines (:layout-lines layout-data)] - - (loop [modif-tree modif-tree - layout-line (first layout-lines) - pending (rest layout-lines) - from-idx 0] - (if (and (some? layout-line) (<= from-idx max-idx)) - (let [to-idx (+ from-idx (:num-children layout-line)) - children (subvec children from-idx to-idx) - - [_ modif-tree] - (reduce (partial set-layout-modifiers shape transform) [layout-line modif-tree] children)] - (recur modif-tree (first pending) (rest pending) to-idx)) - - modif-tree))))) - (defn get-first-layout [id objects] @@ -337,8 +174,11 @@ (let [set-modifiers (fn [modif-tree id] - (let [shape (get objects id) - modifiers (cond-> (get-modifier shape) snap-pixel? (set-pixel-precision shape))] + (let [root? (= uuid/zero id) + shape (get objects id) + modifiers (cond-> (get-modifier shape) + (and (not root?) snap-pixel?) + (gpp/set-pixel-precision shape))] (-> modif-tree (assoc id {:modifiers modifiers})))) @@ -349,11 +189,12 @@ (->> shapes-tree (reduce (fn [modif-tree shape] - (let [modifiers (get-in modif-tree [(:id shape) :modifiers]) + (let [root? (= uuid/zero (:id shape)) + modifiers (get-in modif-tree [(:id shape) :modifiers]) has-modifiers? (some? modifiers) is-layout? (layout? shape) is-parent? (or (group? shape) (and (frame? shape) (not (layout? shape)))) - root? (= uuid/zero (:id shape)) + ;; If the current child is inside the layout we ignore the constraints is-inside-layout? (inside-layout? objects shape)] diff --git a/common/src/app/common/geom/shapes/pixel_precision.cljc b/common/src/app/common/geom/shapes/pixel_precision.cljc new file mode 100644 index 000000000..03aa4359a --- /dev/null +++ b/common/src/app/common/geom/shapes/pixel_precision.cljc @@ -0,0 +1,53 @@ +;; 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.pixel-precision + (:require + [app.common.geom.point :as gpt] + [app.common.geom.shapes.points :as gpo] + [app.common.geom.shapes.rect :as gpr] + [app.common.geom.shapes.transforms :as gtr] + [app.common.math :as mth] + [app.common.pages.helpers :as cph] + [app.common.types.modifiers :as ctm])) + +(defn size-pixel-precision + [modifiers shape] + (let [{:keys [points transform transform-inverse] :as shape} (gtr/transform-shape shape modifiers) + origin (gpo/origin points) + curr-width (gpo/width-points points) + curr-height (gpo/height-points points) + + path? (cph/path-shape? shape) + vertical-line? (and path? (<= curr-width 0.01)) + horizontal-line? (and path? (<= curr-height 0.01)) + + target-width (if vertical-line? curr-width (max 1 (mth/round curr-width))) + target-height (if horizontal-line? curr-height (max 1 (mth/round curr-height))) + + ratio-width (/ target-width curr-width) + ratio-height (/ target-height curr-height) + scalev (gpt/point ratio-width ratio-height)] + (-> modifiers + (ctm/set-resize scalev origin transform transform-inverse)))) + +(defn position-pixel-precision + [modifiers shape] + (let [{:keys [points]} (gtr/transform-shape shape modifiers) + bounds (gpr/points->rect points) + corner (gpt/point bounds) + target-corner (gpt/round corner) + deltav (gpt/to-vec corner target-corner)] + (-> modifiers + (ctm/set-move deltav)))) + +(defn set-pixel-precision + "Adjust modifiers so they adjust to the pixel grid" + [modifiers shape] + + (-> modifiers + (size-pixel-precision shape) + (position-pixel-precision shape))) diff --git a/common/src/app/common/geom/shapes/points.cljc b/common/src/app/common/geom/shapes/points.cljc new file mode 100644 index 000000000..1f80f28df --- /dev/null +++ b/common/src/app/common/geom/shapes/points.cljc @@ -0,0 +1,61 @@ +;; 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.points + (:require + [app.common.geom.point :as gpt])) + +(defn origin + [points] + (nth points 0)) + +(defn start-hv + "Horizontal vector from the origin with a magnitude `val`" + [[p0 p1 _ _] val] + (-> (gpt/to-vec p0 p1) + (gpt/unit) + (gpt/scale val))) + +(defn end-hv + "Horizontal vector from the oposite to the origin in the x axis with a magnitude `val`" + [[p0 p1 _ _] val] + (-> (gpt/to-vec p1 p0) + (gpt/unit) + (gpt/scale val))) + +(defn start-vv + "Vertical vector from the oposite to the origin in the x axis with a magnitude `val`" + [[p0 _ _ p3] val] + (-> (gpt/to-vec p0 p3) + (gpt/unit) + (gpt/scale val))) + +(defn end-vv + "Vertical vector from the oposite to the origin in the x axis with a magnitude `val`" + [[p0 _ _ p3] val] + (-> (gpt/to-vec p3 p0) + (gpt/unit) + (gpt/scale val))) + +(defn width-points + [[p0 p1 _ _]] + (gpt/length (gpt/to-vec p0 p1))) + +(defn height-points + [[p0 _ _ p3]] + (gpt/length (gpt/to-vec p0 p3))) + +(defn pad-points + [[p0 p1 p2 p3 :as points] pad-top pad-right pad-bottom pad-left] + (let [top-v (start-vv points pad-top) + right-v (end-hv points pad-right) + bottom-v (end-vv points pad-bottom) + left-v (start-hv points pad-left)] + + [(-> p0 (gpt/add left-v) (gpt/add top-v)) + (-> p1 (gpt/add right-v) (gpt/add top-v)) + (-> p2 (gpt/add right-v) (gpt/add bottom-v)) + (-> p3 (gpt/add left-v) (gpt/add bottom-v))])) diff --git a/common/src/app/common/geom/shapes/transforms.cljc b/common/src/app/common/geom/shapes/transforms.cljc index 08bf7383e..ce888ddf1 100644 --- a/common/src/app/common/geom/shapes/transforms.cljc +++ b/common/src/app/common/geom/shapes/transforms.cljc @@ -14,8 +14,6 @@ [app.common.geom.shapes.path :as gpa] [app.common.geom.shapes.rect :as gpr] [app.common.math :as mth] - [app.common.pages.helpers :as cph] - [app.common.text :as txt] [app.common.types.modifiers :as ctm] [app.common.uuid :as uuid])) @@ -312,6 +310,8 @@ (dissoc :transform :transform-inverse)) (cond-> (some? selrect) (assoc :selrect selrect)) + + ;; TODO LAYOUT: Make sure the order of points is alright (cond-> (d/not-empty? points) (assoc :points points)) (assoc :rotation rotation)))) @@ -376,113 +376,22 @@ (assoc :flip-x (-> mask :flip-x)) (assoc :flip-y (-> mask :flip-y))))) - -#_(defn- set-flip [shape modifiers] - (let [rv1x (or (get-in modifiers [:resize-vector :x]) 1) - rv1y (or (get-in modifiers [:resize-vector :y]) 1) - rv2x (or (get-in modifiers [:resize-vector-2 :x]) 1) - rv2y (or (get-in modifiers [:resize-vector-2 :y]) 1)] - (cond-> shape - (or (neg? rv1x) (neg? rv2x)) - (-> (update :flip-x not) - (update :rotation -)) - (or (neg? rv1y) (neg? rv2y)) - (-> (update :flip-y not) - (update :rotation -))))) - -#_(defn- set-flip-2 [shape transform] - (let [pt-a (gpt/point (:selrect shape)) - pt-b (gpt/point (-> shape :selrect :x2) (-> shape :selrect :y2)) - - shape-transform (:transform shape (gmt/matrix)) - pt-a' (gpt/transform pt-a (gmt/multiply shape-transform transform )) - pt-b' (gpt/transform pt-b (gmt/multiply shape-transform transform )) - - {:keys [x y]} (gpt/to-vec pt-a' pt-b')] - - (cond-> shape - (neg? x) - (-> (update :flip-x not) - (update :rotation -)) - (neg? y) - (-> (update :flip-y not) - (update :rotation -))))) - -#_(defn- apply-displacement [shape] - (let [modifiers (:modifiers shape)] - (if (contains? modifiers :displacement) - (let [mov-vec (-> (gpt/point 0 0) - (gpt/transform (:displacement modifiers))) - shape (move shape mov-vec) - modifiers (dissoc modifiers :displacement)] - (-> shape - (assoc :modifiers modifiers) - (cond-> (empty-modifiers? modifiers) - (dissoc :modifiers)))) - shape))) - -(defn- apply-text-resize - [shape modifiers] - (if (and (= (:type shape) :text) - (:resize-scale-text modifiers)) - (let [merge-attrs (fn [attrs] - (let [font-size (-> (get attrs :font-size 14) - (d/parse-double) - (* (get-in modifiers [:resize-vector :x] 1)) - (* (get-in modifiers [:resize-vector-2 :x] 1)) - (str))] - (d/txt-merge attrs {:font-size font-size})))] - (update shape :content #(txt/transform-nodes - txt/is-text-node? - merge-attrs - %))) - shape)) - -(defn- apply-structure-modifiers - [shape modifiers] - - (let [remove-children - (fn [shapes children-to-remove] - (let [remove? (set children-to-remove)] - (d/removev remove? shapes))) - - apply-modifier - (fn [shape {:keys [type value index]}] - (cond-> shape - (and (= type :add-children) (some? index)) - (update :shapes - (fn [shapes] - (if (vector? shapes) - (cph/insert-at-index shapes index value) - (d/concat-vec shapes value)))) - - (and (= type :add-children) (nil? index)) - (update :shapes d/concat-vec value) - - (= type :remove-children) - (update :shapes remove-children value)))] - - (reduce apply-modifier shape (:v3 modifiers)))) - (defn apply-modifiers [shape modifiers] - (let [center (gco/center-shape shape) - transform (ctm/modifiers->transform center modifiers)] - + (let [transform (ctm/modifiers->transform modifiers)] (cond-> shape - #_(set-flip-2 transform) (and (some? transform) ;; Never transform the root frame (not= uuid/zero (:id shape))) (apply-transform transform) :always - (apply-structure-modifiers modifiers)))) + (ctm/apply-structure-modifiers modifiers)))) (defn apply-objects-modifiers [objects modifiers] (letfn [(process-shape [objects [id modifier]] - (update objects id apply-modifiers (:modifiers modifier)))] + (d/update-when objects id apply-modifiers (:modifiers modifier)))] (reduce process-shape objects modifiers))) (defn transform-shape @@ -495,66 +404,12 @@ ([shape modifiers] (cond-> shape (and (some? modifiers) (not (ctm/empty-modifiers? modifiers))) - (-> (apply-modifiers modifiers) - (apply-text-resize modifiers))))) - -(defn transform-bounds-v2 - [points center modifiers] - (let [transform (ctm/modifiers->transform center {:v2 modifiers}) - result (gco/transform-points points center transform)] - - ;;(.log js/console "??" (str transform) (clj->js result)) - result) - - #_(letfn [(apply-modifier [points {:keys [type vector origin]}] - (case type - :move - (let [displacement (gmt/translate-matrix vector)] - (gco/transform-points points displacement)) - - :resize - (gco/transform-points points origin (gmt/scale-matrix vector)) - - points))] - (->> modifiers - (reduce apply-modifier points)))) + (apply-modifiers modifiers)))) (defn transform-bounds - [points center {:keys [v2 displacement displacement-after resize-transform-inverse resize-vector resize-origin resize-vector-2 resize-origin-2]}] - - ;; FIXME: Improve Performance - (if (some? v2) - (transform-bounds-v2 points center v2) - (let [resize-transform-inverse (or resize-transform-inverse (gmt/matrix)) - - displacement - (when (some? displacement) - (gmt/multiply resize-transform-inverse displacement)) - - resize-origin - (when (some? resize-origin) - (gmt/transform-point-center resize-origin center resize-transform-inverse)) - - resize-origin-2 - (when (some? resize-origin-2) - (gmt/transform-point-center resize-origin-2 center resize-transform-inverse)) - ] - - (if (and (nil? displacement) (nil? resize-origin) (nil? resize-origin-2) (nil? displacement-after)) - points - - (cond-> points - (some? displacement) - (gco/transform-points displacement) - - (some? resize-origin) - (gco/transform-points resize-origin (gmt/scale-matrix resize-vector)) - - (some? resize-origin-2) - (gco/transform-points resize-origin-2 (gmt/scale-matrix resize-vector-2)) - - (some? displacement-after) - (gco/transform-points displacement-after)))))) + [points center modifiers] + (let [transform (ctm/modifiers->transform modifiers)] + (gco/transform-points points center transform))) (defn transform-selrect [selrect modifiers] diff --git a/common/src/app/common/types/modifiers.cljc b/common/src/app/common/types/modifiers.cljc index 5c905aeff..bd0715aec 100644 --- a/common/src/app/common/types/modifiers.cljc +++ b/common/src/app/common/types/modifiers.cljc @@ -10,70 +10,168 @@ [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] [app.common.geom.shapes.common :as gco] - [app.common.spec :as us])) + [app.common.pages.helpers :as cph] + [app.common.spec :as us] + [app.common.text :as txt])) ;; --- Modifiers -;; The `modifiers` structure contains a list of transformations to -;; do make to a shape, in this order: +;; Moodifiers types +;; - geometry: Geometry +;; * move +;; * resize +;; * rotation +;; - structure-parent: Structure non recursive +;; * add-children +;; * remove-children +;; - structure-child: Structre recursive +;; * scale-content ;; -;; - resize-origin (gpt/point) + resize-vector (gpt/point)q -;; apply a scale vector to all points of the shapes, starting -;; from the origin point. -;; -;; - resize-origin-2 + resize-vector-2 -;; same as the previous one, for cases in that we need to make -;; two vectors from different origin points. -;; -;; - displacement (gmt/matrix) -;; apply a translation matrix to the shape -;; -;; - rotation (gmt/matrix) -;; apply a rotation matrix to the shape -;; -;; - resize-transform (gmt/matrix) + resize-transform-inverse (gmt/matrix) -;; a copy of the rotation matrix currently applied to the shape; -;; this is needed temporarily to apply the resize vectors. -;; -;; - resize-scale-text (bool) -;; tells if the resize vectors must be applied to text shapes -;; or not. + +(def conjv (fnil conj [])) + +;; Public builder API + +(defn empty-modifiers [] + {}) + +(defn set-move + ([modifiers x y] + (set-move modifiers (gpt/point x y))) + + ([modifiers vector] + (-> modifiers + (update :geometry conjv {:type :move :vector vector})))) + +(defn set-resize + ([modifiers vector origin] + (-> modifiers + (update :geometry conjv {:type :resize + :vector vector + :origin origin}))) + + ([modifiers vector origin transform transform-inverse] + (-> modifiers + (update :geometry conjv {:type :resize + :vector vector + :origin origin + :transform transform + :transform-inverse transform-inverse})))) + +(defn set-rotation + [modifiers center angle] + (-> modifiers + (update :geometry conjv {:type :rotation + :center center + :rotation angle}))) + +(defn set-remove-children + [modifiers shapes] + (-> modifiers + (update :structure-parent conjv {:type :remove-children + :value shapes})) + ) + +(defn set-add-children + [modifiers shapes index] + (-> modifiers + (update :structure-parent conjv {:type :add-children + :value shapes + :index index}))) + +(defn set-scale-content + [modifiers value] + (-> modifiers + (update :structure-child conjv {:type :scale-content :value value}))) + + +(defn add-modifiers + [modifiers new-modifiers] + + (cond-> modifiers + (some? (:geometry new-modifiers)) + (update :geometry #(d/concat-vec [] % (:geometry new-modifiers))) + + (some? (:structure-parent new-modifiers)) + (update :structure-parent #(d/concat-vec [] % (:structure-parent new-modifiers))) + + (some? (:structure-child new-modifiers)) + (update :structure-child #(d/concat-vec [] % (:structure-child new-modifiers))))) + + +;; These are convenience methods to create single operation modifiers without the builder (defn move ([x y] - (move (gpt/point x y))) + (set-move (empty-modifiers) (gpt/point x y))) ([vector] - {:v2 [{:type :move :vector vector}]})) + (set-move (empty-modifiers) vector))) (defn resize - [vector origin] - {:v2 [{:type :resize :vector vector :origin origin}]}) + ([vector origin] + (set-resize (empty-modifiers) vector origin)) + + ([vector origin transform transform-inverse] + (set-resize (empty-modifiers) vector origin transform transform-inverse))) + +(defn rotation + [shape center angle] + (let [shape-center (gco/center-shape shape) + rotation (-> (gmt/matrix) + (gmt/rotate angle center) + (gmt/rotate (- angle) shape-center))] + + (-> (empty-modifiers) + (set-rotation shape-center angle) + (set-move (gpt/transform (gpt/point 1 1) rotation))))) + +(defn remove-children + [shapes] + (-> (empty-modifiers) + (set-remove-children shapes))) + +(defn add-children + [shapes index] + (-> (empty-modifiers) + (set-add-children shapes index))) + +(defn scale-content + [value] + (-> (empty-modifiers) + (set-scale-content value))) + +(defn select-child-modifiers + [modifiers] + (select-keys modifiers [:geometry :structure-child])) + +(defn select-structure + [modifiers] + (select-keys modifiers [:structure-parent])) (defn add-move ([object x y] (add-move object (gpt/point x y))) ([object vector] - (assoc-in - object - [:modifiers :displacement] - (gmt/translate-matrix (:x vector) (:y vector))))) + (update object :modifiers (move vector)))) (defn add-resize [object vector origin] - (-> object - (assoc-in [:modifiers :resize-vector] vector) - (assoc-in [:modifiers :resize-origin] origin))) + (update object :modifiers (resize vector origin))) -(defn empty-modifiers? [modifiers] - (empty? (dissoc modifiers :ignore-geometry?))) +(defn empty-modifiers? + [modifiers] + (and (empty? (:geometry modifiers)) + (empty? (:structure-parent modifiers)) + (empty? (:structure-child modifiers)))) -(defn resize-modifiers +(defn change-dimensions [shape attr value] (us/assert map? shape) (us/assert #{:width :height} attr) (us/assert number? value) + (let [{:keys [proportion proportion-lock]} shape size (select-keys (:selrect shape) [:width :height]) new-size (if-not proportion-lock @@ -99,10 +197,8 @@ scalev (gpt/divide (gpt/point width height) (gpt/point sr-width sr-height))] - {:resize-vector scalev - :resize-origin origin - :resize-transform shape-transform - :resize-transform-inverse shape-transform-inv})) + + (resize scalev origin shape-transform shape-transform-inv))) (defn change-orientation-modifiers [shape orientation] @@ -124,26 +220,8 @@ scalev (gpt/divide (gpt/point new-width new-height) (gpt/point sr-width sr-height))] - {:resize-vector scalev - :resize-origin origin - :resize-transform shape-transform - :resize-transform-inverse shape-transform-inv})) -(defn rotation-modifiers - [shape center angle] - (let [shape-center (gco/center-shape shape) - rotation (-> (gmt/matrix) - (gmt/rotate angle center) - (gmt/rotate (- angle) shape-center))] - - {:v2 [{:type :rotation - :center shape-center - :rotation angle} - - {:type :move - :vector (gpt/transform (gpt/point 1 1) rotation)}]} - #_{:rotation angle - :displacement displacement})) + (resize scalev origin shape-transform shape-transform-inv))) (defn merge-modifiers [objects modifiers] @@ -155,7 +233,29 @@ (->> modifiers (reduce set-modifier objects)))) -(defn modifiers-v2->transform +(defn only-move? + [modifier] + (and (= 1 (-> modifier :geometry count)) + (= :move (-> modifier :geometry first :type)))) + +(defn get-frame-add-children + [modif-tree] + + (let [structure-changes + (into {} + (comp (filter (fn [[_ val]] (-> val :modifiers :structure-parent some?))) + (map (fn [[key val]] + [key (-> val :modifiers :structure-parent)]))) + modif-tree)] + (into [] + (mapcat (fn [[frame-id changes]] + (->> changes + (filter (fn [{:keys [type]}] (= type :add-children))) + (mapcat (fn [{:keys [value]}] + (->> value (map (fn [id] {:frame frame-id :shape id})))))))) + structure-changes))) + +(defn modifiers->transform [modifiers] (letfn [(apply-modifier [matrix {:keys [type vector rotation center origin transform transform-inverse] :as modifier}] (case type @@ -182,77 +282,58 @@ (gmt/multiply (gmt/rotate-matrix rotation)) (gmt/translate (gpt/negate center))) matrix)))] - (->> modifiers + (->> modifiers :geometry (reduce apply-modifier (gmt/matrix))))) -(defn- normalize-scale - "We normalize the scale so it's not too close to 0" - [scale] - (cond - (and (< scale 0) (> scale -0.01)) -0.01 - (and (>= scale 0) (< scale 0.01)) 0.01 - :else scale)) +(defn scale-text-content + [content value] -(defn modifiers->transform - ([modifiers] - (modifiers->transform nil modifiers)) + (->> content + (txt/transform-nodes + txt/is-text-node? + (fn [attrs] + (let [font-size (-> (get attrs :font-size 14) + (d/parse-double) + (* value) + (str)) ] + (d/txt-merge attrs {:font-size font-size})))))) - ([center modifiers] - (if (some? (:v2 modifiers)) - (modifiers-v2->transform (:v2 modifiers)) - (let [displacement (:displacement modifiers) - displacement-after (:displacement-after modifiers) - resize-v1 (:resize-vector modifiers) - resize-v2 (:resize-vector-2 modifiers) - origin-1 (:resize-origin modifiers (gpt/point)) - origin-2 (:resize-origin-2 modifiers (gpt/point)) +(defn apply-scale-content + [shape value] - ;; Normalize x/y vector coordinates because scale by 0 is infinite - resize-1 (when (some? resize-v1) - (gpt/point (normalize-scale (:x resize-v1)) - (normalize-scale (:y resize-v1)))) + (cond-> shape + (cph/text-shape? shape) + (update :content scale-text-content value))) - resize-2 (when (some? resize-v2) - (gpt/point (normalize-scale (:x resize-v2)) - (normalize-scale (:y resize-v2)))) +(defn apply-structure-modifiers + [shape modifiers] + (let [remove-children + (fn [shapes children-to-remove] + (let [remove? (set children-to-remove)] + (d/removev remove? shapes))) - resize-transform (:resize-transform modifiers) - resize-transform-inverse (:resize-transform-inverse modifiers) - rt-modif (:rotation modifiers)] - (cond-> (gmt/matrix) - (some? displacement-after) - (gmt/multiply displacement-after) + apply-modifier + (fn [shape {:keys [type value index]}] + (cond-> shape + (and (= type :add-children) (some? index)) + (update :shapes + (fn [shapes] + (if (vector? shapes) + (cph/insert-at-index shapes index value) + (d/concat-vec shapes value)))) - (some? resize-1) - (-> (gmt/translate origin-1) - (cond-> (some? resize-transform) - (gmt/multiply resize-transform)) - (gmt/scale resize-1) - (cond-> (some? resize-transform-inverse) - (gmt/multiply resize-transform-inverse)) - (gmt/translate (gpt/negate origin-1))) + (and (= type :add-children) (nil? index)) + (update :shapes d/concat-vec value) - (some? resize-2) - (-> (gmt/translate origin-2) - (cond-> (some? resize-transform) - (gmt/multiply resize-transform)) - (gmt/scale resize-2) - (cond-> (some? resize-transform-inverse) - (gmt/multiply resize-transform-inverse)) - (gmt/translate (gpt/negate origin-2))) + (= type :remove-children) + (update :shapes remove-children value) - (some? displacement) - (gmt/multiply displacement) + (= type :scale-content) + (apply-scale-content value)))] - (some? rt-modif) - (-> (gmt/translate center) - (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)))) + (as-> shape $ + (reduce apply-modifier $ (:structure-parent modifiers)) + (reduce apply-modifier $ (:structure-child modifiers))))) diff --git a/frontend/src/app/main/data/workspace/drawing/box.cljs b/frontend/src/app/main/data/workspace/drawing/box.cljs index 65843fc6b..ad91a1226 100644 --- a/frontend/src/app/main/data/workspace/drawing/box.cljs +++ b/frontend/src/app/main/data/workspace/drawing/box.cljs @@ -47,8 +47,9 @@ (-> shape (assoc :click-draw? false) - (gsh/transform-shape (ctm/resize scalev (gpt/point x y))) - (gsh/transform-shape (ctm/move movev))))) + (gsh/transform-shape (-> (ctm/empty-modifiers) + (ctm/set-resize scalev (gpt/point x y)) + (ctm/set-move movev)))))) (defn update-drawing [state initial point lock?] (update-in state [:workspace-drawing :object] resize-shape initial point lock?)) diff --git a/frontend/src/app/main/data/workspace/shapes.cljs b/frontend/src/app/main/data/workspace/shapes.cljs index daa033365..2f15ac226 100644 --- a/frontend/src/app/main/data/workspace/shapes.cljs +++ b/frontend/src/app/main/data/workspace/shapes.cljs @@ -22,7 +22,6 @@ [app.main.data.workspace.edition :as dwe] [app.main.data.workspace.selection :as dws] [app.main.data.workspace.shape-layout :as dwsl] - [app.main.data.workspace.shape-layout :as dwsl] [app.main.data.workspace.state-helpers :as wsh] [app.main.features :as features] [app.main.streams :as ms] diff --git a/frontend/src/app/main/data/workspace/texts.cljs b/frontend/src/app/main/data/workspace/texts.cljs index 1c9f5f147..dbfb5f453 100644 --- a/frontend/src/app/main/data/workspace/texts.cljs +++ b/frontend/src/app/main/data/workspace/texts.cljs @@ -320,8 +320,8 @@ (letfn [(update-fn [shape] (let [{:keys [selrect grow-type]} shape {shape-width :width shape-height :height} selrect - modifier-width (ctm/resize-modifiers shape :width new-width) - modifier-height (ctm/resize-modifiers shape :height new-height)] + modifier-width (ctm/change-dimensions shape :width new-width) + modifier-height (ctm/change-dimensions shape :height new-height)] ;; TODO LAYOUT: MEZCLAR ESTOS EN UN UNICO MODIFIER (cond-> shape (and (not-changed? shape-width new-width) (= grow-type :auto-width)) @@ -346,8 +346,8 @@ (defn apply-text-modifier [shape {:keys [width height position-data]}] - (let [modifier-width (when width (ctm/resize-modifiers shape :width width)) - modifier-height (when height (ctm/resize-modifiers shape :height height)) + (let [modifier-width (when width (ctm/change-dimensions shape :width width)) + modifier-height (when height (ctm/change-dimensions shape :height height)) ;; TODO LAYOUT: MEZCLAR LOS DOS EN UN UNICO MODIFIER new-shape diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 7873b7eba..f304dbe31 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -146,11 +146,14 @@ (concat (keys workspace-modifiers) ids) objects (fn [shape] - (let [modifiers (if (contains? ids (:id shape)) modifiers {}) - old-modifiers-v3 (get-in state [:workspace-modifiers (:id shape) :modifiers :v3])] + (let [ + modifiers (if (contains? ids (:id shape)) modifiers (ctm/empty-modifiers)) + + structure-modifiers (ctm/select-structure + (get-in state [:workspace-modifiers (:id shape) :modifiers]))] (cond-> modifiers - (some? old-modifiers-v3) - (assoc :v3 old-modifiers-v3)))) + (some? structure-modifiers) + (ctm/add-modifiers structure-modifiers)))) ignore-constraints snap-pixel?)] (update state :workspace-modifiers merge modif-tree)))))) @@ -175,7 +178,7 @@ get-modifier (fn [shape] - (ctm/rotation-modifiers shape center angle)) + (ctm/rotation shape center angle)) modif-tree (gsh/set-objects-modifiers ids objects get-modifier false false)] @@ -396,32 +399,18 @@ resize-origin (cond-> (gmt/transform-point-center handler-origin shape-center shape-transform) (some? displacement) - (gpt/add displacement))] + (gpt/add displacement)) - (rx/of (set-modifiers ids - {:v2 (-> [] - (cond-> displacement - (conj {:type :move - :vector displacement})) - (conj {:type :resize - :vector scalev - :origin resize-origin - :transform shape-transform - :transform-inverse shape-transform-inverse})) - ;;:displacement displacement - ;;:resize-vector scalev - ;;:resize-origin resize-origin - ;;:resize-transform shape-transform - ;;:resize-scale-text scale-text - ;;:resize-transform-inverse shape-transform-inverse - })) - #_(rx/of (set-modifiers ids - {:displacement displacement - :resize-vector scalev - :resize-origin resize-origin - :resize-transform shape-transform - :resize-scale-text scale-text - :resize-transform-inverse shape-transform-inverse})))) + modifiers + (-> (ctm/empty-modifiers) + (cond-> displacement + (ctm/set-move displacement)) + (ctm/set-resize scalev resize-origin shape-transform shape-transform-inverse) + + (cond-> scale-text + (ctm/set-scale-content (:x scalev))))] + + (rx/of (set-modifiers ids modifiers)))) ;; Unifies the instantaneous proportion lock modifier ;; activated by Shift key and the shapes own proportion @@ -471,7 +460,7 @@ snap-pixel? (and (contains? (:workspace-layout state) :snap-pixel-grid) (int? value)) get-modifier - (fn [shape] (ctm/resize-modifiers shape attr value)) + (fn [shape] (ctm/change-dimensions shape attr value)) modif-tree (gsh/set-objects-modifiers ids objects get-modifier false snap-pixel?)] @@ -655,15 +644,13 @@ (d/removev #(= target-frame %)))] (cond (not= original-frame target-frame) - [[original-frame {:modifiers {:v3 [{:type :remove-children :value shapes}]}}] - [target-frame {:modifiers {:v3 [{:type :add-children - :value shapes - :index drop-index}]}}]] + [[original-frame {:modifiers (ctm/remove-children shapes)}] + [target-frame {:modifiers (ctm/add-children shapes drop-index)}]] + layout? - [[target-frame {:modifiers {:v3 [{:type :add-children - :value shapes - :index drop-index}]}}]])))) + [[target-frame {:modifiers (ctm/add-children shapes drop-index)}]])))) (keys origin-frame-ids))] + (assoc state :workspace-modifiers modif-tree))))) (defn- start-move @@ -725,8 +712,7 @@ ;; We try to use the previous snap so we don't have to wait for the result of the new (rx/map snap/correct-snap-point) - - (rx/map (fn [move-vec] {:v2 [{:type :move :vector move-vec}]})) + (rx/map ctm/move) (rx/map (partial set-modifiers ids)) (rx/take-until stopper))) @@ -867,14 +853,9 @@ origin (gpt/point (:x selrect) (+ (:y selrect) (/ (:height selrect) 2)))] (rx/of (set-modifiers selected - {:v2 [{:type :resize - :vector (gpt/point -1.0 1.0) - :origin origin} - {:type :move - :vector (gpt/point (:width selrect) 0)}]} - #_{:resize-vector (gpt/point -1.0 1.0) - :resize-origin origin - :displacement (gmt/translate-matrix (gpt/point (- (:width selrect)) 0))} + (-> (ctm/empty-modifiers) + (ctm/set-resize (gpt/point -1.0 1.0) origin) + (ctm/move (gpt/point (:width selrect) 0))) true) (apply-modifiers)))))) @@ -889,13 +870,8 @@ origin (gpt/point (+ (:x selrect) (/ (:width selrect) 2)) (:y selrect))] (rx/of (set-modifiers selected - {:v2 [{:type :resize - :vector (gpt/point 1.0 -1.0) - :origin origin} - {:type :move - :vector (gpt/point 0 (:height selrect))}]} - #_{:resize-vector (gpt/point 1.0 -1.0) - :resize-origin origin - :displacement (gmt/translate-matrix (gpt/point 0 (- (:height selrect))))} + (-> (ctm/empty-modifiers) + (ctm/set-resize (gpt/point 1.0 -1.0) origin) + (ctm/move (gpt/point 0 (:height selrect)))) true) (apply-modifiers)))))) diff --git a/frontend/src/app/main/ui/workspace/shapes.cljs b/frontend/src/app/main/ui/workspace/shapes.cljs index 836114c51..a6ca1742b 100644 --- a/frontend/src/app/main/ui/workspace/shapes.cljs +++ b/frontend/src/app/main/ui/workspace/shapes.cljs @@ -103,7 +103,7 @@ opts #js {:shape shape :thumbnail? thumbnail?}] (when (and (some? shape) (not (:hidden shape))) - [:g.ws-shape-wrapper + [:g.workspace-shape-wrapper (case (:type shape) :path [:> path/path-wrapper opts] :text [:> text/text-wrapper opts] diff --git a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs index 6d95966d4..288ebcbff 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs @@ -19,67 +19,6 @@ [app.util.globals :as globals] [rumext.v2 :as mf])) -(defn- transform-no-resize - "If we apply a scale directly to the texts it will show deformed so we need to create this - correction matrix to \"undo\" the resize but keep the other transformations." - [{:keys [x y width height points transform transform-inverse] :as shape} current-transform modifiers] - - (let [corner-pt (first points) - corner-pt (cond-> corner-pt (some? transform-inverse) (gpt/transform transform-inverse)) - - resize-x? (some? (:resize-vector modifiers)) - resize-y? (some? (:resize-vector-2 modifiers)) - - 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]))) - - result (cond-> (gmt/matrix) - (and (some? transform) (or resize-x? resize-y?)) - (gmt/multiply transform) - - resize-x? - (gmt/scale (gpt/inverse (:resize-vector modifiers)) corner-pt) - - resize-y? - (gmt/scale (gpt/inverse (:resize-vector-2 modifiers)) corner-pt) - - flip-x? - (gmt/scale (gpt/point -1 1) corner-pt) - - flip-y? - (gmt/scale (gpt/point 1 -1) corner-pt) - - (and (some? transform) (or resize-x? resize-y?)) - (gmt/multiply transform-inverse)) - - [width height] - (if (or resize-x? resize-y?) - (let [pc (cond-> (gpt/point x y) - (some? transform) - (gpt/transform transform) - - (some? current-transform) - (gpt/transform current-transform)) - - pw (cond-> (gpt/point (+ x width) y) - (some? transform) - (gpt/transform transform) - - (some? current-transform) - (gpt/transform current-transform)) - - ph (cond-> (gpt/point x (+ y height)) - (some? transform) - (gpt/transform transform) - - (some? current-transform) - (gpt/transform current-transform))] - [(gpt/distance pc pw) (gpt/distance pc ph)]) - [width height])] - - [result width height])) - (defn get-shape-node ([id] (get-shape-node js/document id)) @@ -191,15 +130,8 @@ (let [transform (get transforms id) modifiers (get-in modifiers [id :modifiers])] - ;; TODO LAYOUT: Adapt to new modifiers (doseq [node nodes] (cond - ;; Text shapes need special treatment because their resize only change - ;; the text area, not the change size/position - (dom/class? node "frame-thumbnail") - (let [[transform] (transform-no-resize shape transform modifiers)] - (set-transform-att! node "transform" transform)) - (dom/class? node "frame-children") (set-transform-att! node "transform" (gmt/inverse transform)) @@ -256,11 +188,7 @@ (/ (: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)})))) + (ctm/set-resize scalev (-> shape' :points first) (:transform shape') (:transform-inverse shape'))))) (defn use-dynamic-modifiers [objects node modifiers] @@ -272,37 +200,13 @@ (when (some? modifiers) (d/mapm (fn [id {modifiers :modifiers}] (let [shape (get objects id) - center (gsh/center-shape shape) text? (= :text (:type shape)) modifiers (cond-> modifiers text? (adapt-text-modifiers shape))] - (ctm/modifiers->transform center modifiers))) + (ctm/modifiers->transform modifiers))) modifiers)))) - structure-changes - (mf/use-memo - (mf/deps modifiers) - (fn [] - (into {} - (comp (filter (fn [[_ val]] (-> val :modifiers :v3 some?))) - (map (fn [[key val]] - [key (-> val :modifiers :v3)]))) - - modifiers))) - - structure-changes (hooks/use-equal-memo structure-changes) - - add-children - (mf/use-memo - (mf/deps structure-changes) - (fn [] - (into [] - (mapcat (fn [[frame-id changes]] - (->> changes - (filter (fn [{:keys [type]}] (= type :add-children))) - (mapcat (fn [{:keys [value]}] - (->> value (map (fn [id] {:frame frame-id :shape id})))))))) - structure-changes))) - + add-children (mf/use-memo (mf/deps modifiers) #(ctm/get-frame-add-children modifiers)) + add-children (hooks/use-equal-memo add-children) add-children-prev (hooks/use-previous add-children) shapes diff --git a/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs b/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs index 74e8057e0..50e2e6ebc 100644 --- a/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs @@ -35,13 +35,6 @@ (with-meta (meta (:position-data shape)))) (dissoc :position-data :transform :transform-inverse))) -#_(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) diff --git a/frontend/src/app/main/ui/workspace/viewport/debug.cljs b/frontend/src/app/main/ui/workspace/viewport/debug.cljs index 0f23f9eee..ef81d5fa9 100644 --- a/frontend/src/app/main/ui/workspace/viewport/debug.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/debug.cljs @@ -31,7 +31,7 @@ (when (and shape (:layout shape)) (let [children (cph/get-immediate-children objects (:id shape)) layout-data (gsl/calc-layout-data shape children) - drop-areas (gsl/drop-areas shape layout-data children)] + drop-areas (gsl/layout-drop-areas shape layout-data children)] [:g.debug-layout {:pointer-events "none" :transform (gsh/transform-str shape)} (for [[idx drop-area] (d/enumerate drop-areas)] From af098bb64d21a269b5a59705519fd623ab091d62 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 20 Oct 2022 17:10:36 +0200 Subject: [PATCH 09/36] :sparkles: Adds integration with new UI --- common/src/app/common/geom/shapes.cljc | 2 +- .../shapes/{layout.cljc => flex_layout.cljc} | 352 ++++++++++-------- .../src/app/common/geom/shapes/modifiers.cljc | 80 ++-- .../common/geom/shapes/pixel_precision.cljc | 12 +- common/src/app/common/types/modifiers.cljc | 47 ++- .../test/common_tests/geom_shapes_test.cljc | 36 +- .../app/main/data/workspace/shape_layout.cljs | 9 +- .../app/main/data/workspace/transforms.cljs | 199 +++++----- frontend/src/app/main/snap.cljs | 7 +- .../src/app/main/ui/workspace/shapes.cljs | 7 +- .../sidebar/options/menus/layout_item.cljs | 12 +- .../sidebar/options/shapes/frame.cljs | 2 +- .../app/main/ui/workspace/viewport/debug.cljs | 2 +- 13 files changed, 431 insertions(+), 336 deletions(-) rename common/src/app/common/geom/shapes/{layout.cljc => flex_layout.cljc} (67%) diff --git a/common/src/app/common/geom/shapes.cljc b/common/src/app/common/geom/shapes.cljc index 25da561f3..941e6b634 100644 --- a/common/src/app/common/geom/shapes.cljc +++ b/common/src/app/common/geom/shapes.cljc @@ -13,8 +13,8 @@ [app.common.geom.shapes.common :as gco] [app.common.geom.shapes.constraints :as gct] [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.layout :as gcl] [app.common.geom.shapes.modifiers :as gsm] [app.common.geom.shapes.path :as gsp] [app.common.geom.shapes.rect :as gpr] diff --git a/common/src/app/common/geom/shapes/layout.cljc b/common/src/app/common/geom/shapes/flex_layout.cljc similarity index 67% rename from common/src/app/common/geom/shapes/layout.cljc rename to common/src/app/common/geom/shapes/flex_layout.cljc index d3282b357..b67e12e4d 100644 --- a/common/src/app/common/geom/shapes/layout.cljc +++ b/common/src/app/common/geom/shapes/flex_layout.cljc @@ -4,7 +4,7 @@ ;; ;; Copyright (c) KALEIDOS INC -(ns app.common.geom.shapes.layout +(ns app.common.geom.shapes.flex-layout (:require [app.common.data :as d] [app.common.geom.matrix :as gmt] @@ -16,52 +16,95 @@ [app.common.pages.helpers :as cph] [app.common.types.modifiers :as ctm])) -;; :layout ;; true if active, false if not -;; :layout-dir ;; :right, :left, :top, :bottom -;; :layout-gap ;; number could be negative -;; :layout-type ;; :packed, :space-between, :space-around +;; :layout ;; :flex, :grid in the future +;; :layout-flex-dir ;; :row, :reverse-row, :column, :reverse-column +;; :layout-gap-type ;; :simple, :multiple +;; :layout-gap ;; {:row-gap number , :column-gap number} +;; :layout-align-items ;; :start :end :center :strech +;; :layout-justify-content ;; :start :center :end :space-between :space-around +;; :layout-align-content ;; :start :center :end :space-between :space-around :strech (by default) ;; :layout-wrap-type ;; :wrap, :no-wrap ;; :layout-padding-type ;; :simple, :multiple ;; :layout-padding ;; {:p1 num :p2 num :p3 num :p4 num} number could be negative -;; :layout-h-orientation ;; :top, :center, :bottom -;; :layout-v-orientation ;; :left, :center, :right + +;; ITEMS +;; :layout-margin ;; {:m1 0 :m2 0 :m3 0 :m4 0} +;; :layout-margin-type ;; :simple :multiple +;; :layout-h-behavior ;; :fill :fix :auto +;; :layout-v-behavior ;; :fill :fix :auto +;; :layout-max-h ;; num +;; :layout-min-h ;; num +;; :layout-max-w ;; num +;; :layout-min-w (defn col? - [{:keys [layout-dir]}] - (or (= :right layout-dir) (= :left layout-dir))) + [{:keys [layout-flex-dir]}] + (or (= :column layout-flex-dir) (= :reverse-column layout-flex-dir))) (defn row? - [{:keys [layout-dir]}] - (or (= :top layout-dir) (= :bottom layout-dir))) + [{:keys [layout-flex-dir]}] + (or (= :row layout-flex-dir) (= :reverse-row layout-flex-dir))) (defn h-start? - [{:keys [layout-h-orientation]}] - (= layout-h-orientation :left)) + [{:keys [layout-align-items layout-justify-content] :as shape}] + (or (and (col? shape) + (= layout-align-items :start)) + (and (row? shape) + (= layout-justify-content :start)))) (defn h-center? - [{:keys [layout-h-orientation]}] - (= layout-h-orientation :center)) + [{:keys [layout-align-items layout-justify-content] :as shape}] + (or (and (col? shape) + (= layout-align-items :center)) + (and (row? shape) + (= layout-justify-content :center)))) (defn h-end? - [{:keys [layout-h-orientation]}] - (= layout-h-orientation :right)) + [{:keys [layout-align-items layout-justify-content] :as shape}] + (or (and (col? shape) + (= layout-align-items :end)) + (and (row? shape) + (= layout-justify-content :end)))) (defn v-start? - [{:keys [layout-v-orientation]}] - (= layout-v-orientation :top)) + [{:keys [layout-align-items layout-justify-content] :as shape}] + (or (and (row? shape) + (= layout-align-items :start)) + (and (col? shape) + (= layout-justify-content :start)))) (defn v-center? - [{:keys [layout-v-orientation]}] - (= layout-v-orientation :center)) + [{:keys [layout-align-items layout-justify-content] :as shape}] + (or (and (row? shape) + (= layout-align-items :center)) + (and (col? shape) + (= layout-justify-content :center)))) (defn v-end? - [{:keys [layout-v-orientation]}] - (= layout-v-orientation :bottom)) + [{:keys [layout-align-items layout-justify-content] :as shape}] + (or (and (row? shape) + (= layout-align-items :end)) + (and (col? shape) + (= layout-justify-content :end)))) + +(defn gaps + [{:keys [layout-gap layout-gap-type]}] + (let [layout-gap-row (or (-> layout-gap :row-gap) 0) + layout-gap-col (if (= layout-gap-type :simple) + layout-gap-row + (or (-> layout-gap :column-gap) 0))] + [layout-gap-row layout-gap-col])) (defn calc-layout-lines - [{:keys [layout-gap layout-wrap-type] :as parent} children layout-bounds] + "Calculates the lines basic data and accumulated values. The positions will be calculated in a different operation" + [{:keys [layout-wrap-type] :as parent} children layout-bounds] (let [wrap? (= layout-wrap-type :wrap) + col? (col? parent) + row? (row? parent) + + [layout-gap-row layout-gap-col] (gaps parent) + layout-width (gpo/width-points layout-bounds) layout-height (gpo/height-points layout-bounds) @@ -71,39 +114,36 @@ child-width (gpo/width-points child-bounds) child-height (gpo/height-points child-bounds) - col? (col? parent) - row? (row? parent) - cur-child-fill? - (or (and col? (= :fill (:layout-h-behavior child))) - (and row? (= :fill (:layout-v-behavior child)))) - - cur-line-fill? (or (and row? (= :fill (:layout-h-behavior child))) (and col? (= :fill (:layout-v-behavior child)))) + cur-line-fill? + (or (and col? (= :fill (:layout-h-behavior child))) + (and row? (= :fill (:layout-v-behavior child)))) + ;; TODO LAYOUT: ADD MINWIDTH/HEIGHT - next-width (if (or (and col? cur-child-fill?) - (and row? cur-line-fill?)) + next-width (if (or (and row? cur-child-fill?) + (and col? cur-line-fill?)) 0 child-width) - next-height (if (or (and row? cur-child-fill?) - (and col? cur-line-fill?)) + next-height (if (or (and col? cur-child-fill?) + (and row? cur-line-fill?)) 0 child-height) - next-total-width (+ line-width next-width (* layout-gap (dec num-children))) - next-total-height (+ line-height next-height (* layout-gap (dec num-children)))] + next-total-width (+ line-width next-width (* layout-gap-row (dec num-children))) + next-total-height (+ line-height next-height (* layout-gap-col (dec num-children)))] (if (and (some? line-data) (or (not wrap?) - (and col? (<= next-total-width layout-width)) - (and row? (<= next-total-height layout-height)))) + (and row? (<= next-total-width layout-width)) + (and col? (<= next-total-height layout-height)))) ;; When :fill we add min width (0 by default) - [{:line-width (if col? (+ line-width next-width) (max line-width next-width)) - :line-height (if row? (+ line-height next-height) (max line-height next-height)) + [{:line-width (if row? (+ line-width next-width) (max line-width next-width)) + :line-height (if col? (+ 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?) @@ -123,14 +163,16 @@ (cond-> layout-lines (some? line-data) (conj line-data)))) (defn calc-layout-lines-position - [{:keys [layout-gap] :as parent} layout-bounds layout-lines] + [{:keys [layout-justify-content] :as parent} layout-bounds layout-lines] (let [layout-width (gpo/width-points layout-bounds) layout-height (gpo/height-points layout-bounds) + [layout-gap-row layout-gap-col] (gaps parent) + row? (row? parent) col? (col? parent) - space-between? (= :space-between (:layout-type parent)) - space-around? (= :space-around (:layout-type parent)) + space-between? (= layout-justify-content :space-between) + space-around? (= layout-justify-content :space-around) h-center? (h-center? parent) h-end? (h-end? parent) v-center? (v-center? parent) @@ -148,61 +190,62 @@ [total-width total-height] (cond-> (gpo/origin layout-bounds) - (and row? h-center?) + (and col? h-center?) (gpt/add (xv (/ (- layout-width total-width) 2))) - (and row? h-end?) + (and col? h-end?) (gpt/add (xv (- layout-width total-width))) - (and col? v-center?) + (and row? v-center?) (gpt/add (yv (/ (- layout-height total-height) 2))) - (and col? v-end?) + (and row? v-end?) (gpt/add (yv (- layout-height total-height))))) (get-start-line [{:keys [line-width line-height num-children child-fill?]} base-p] - (let [children-gap (* layout-gap (dec num-children)) + (let [children-gap-width (* layout-gap-row (dec num-children)) + children-gap-height (* layout-gap-col (dec num-children)) - line-width (if (and col? child-fill?) - (- layout-width (* layout-gap (dec num-children))) + line-width (if (and row? child-fill?) + (- layout-width (* layout-gap-row (dec num-children))) line-width) - line-height (if (and row? child-fill?) - (- layout-height (* layout-gap (dec num-children))) + line-height (if (and col? child-fill?) + (- layout-height (* layout-gap-col (dec num-children))) line-height) start-p (cond-> base-p ;; X AXIS - (and col? h-center? (not space-around?) (not space-between?)) + (and row? h-center? (not space-around?) (not space-between?)) (-> (gpt/add (xv (/ layout-width 2))) - (gpt/subtract (xv (/ (+ line-width children-gap) 2)))) + (gpt/subtract (xv (/ (+ line-width children-gap-width) 2)))) - (and col? h-end? (not space-around?) (not space-between?)) + (and row? h-end? (not space-around?) (not space-between?)) (-> (gpt/add (xv layout-width)) - (gpt/subtract (xv (+ line-width children-gap)))) + (gpt/subtract (xv (+ line-width children-gap-width)))) - (and row? h-center?) + (and col? h-center?) (gpt/add (xv (/ line-width 2))) - (and row? h-end?) + (and col? h-end?) (gpt/add (xv line-width)) ;; Y AXIS - (and row? v-center? (not space-around?) (not space-between?)) + (and col? v-center? (not space-around?) (not space-between?)) (-> (gpt/add (yv (/ layout-height 2))) - (gpt/subtract (yv (/ (+ line-height children-gap) 2)))) + (gpt/subtract (yv (/ (+ line-height children-gap-height) 2)))) - (and row? v-end? (not space-around?) (not space-between?)) + (and col? v-end? (not space-around?) (not space-between?)) (-> (gpt/add (yv layout-height)) - (gpt/subtract (yv (+ line-height children-gap)))) + (gpt/subtract (yv (+ line-height children-gap-height)))) - (and col? v-center?) + (and row? v-center?) (gpt/add (yv (/ line-height 2))) - (and col? v-end?) + (and row? v-end?) (gpt/add (yv line-height)))] start-p)) @@ -211,11 +254,11 @@ [{:keys [line-width line-height]} base-p] (cond-> base-p - row? - (gpt/add (xv (+ line-width layout-gap))) - col? - (gpt/add (yv (+ line-height layout-gap))))) + (gpt/add (xv (+ line-width layout-gap-row))) + + row? + (gpt/add (yv (+ line-height layout-gap-col))))) (add-lines [[total-width total-height] {:keys [line-width line-height]}] [(+ total-width line-width) @@ -230,24 +273,25 @@ (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)))) + total-width (+ total-width (* layout-gap-row (dec (count layout-lines)))) + total-height (+ total-height (* layout-gap-col (dec (count layout-lines)))) vertical-fill-space (- layout-height total-height) + horizontal-fill-space (- layout-width total-width) num-line-fill (count (->> layout-lines (filter :line-fill?))) layout-lines (->> layout-lines (mapv #(cond-> % - (and col? (:line-fill? %)) + (and row? (:line-fill? %)) (update :line-height + (/ vertical-fill-space num-line-fill)) - (and row? (:line-fill? %)) + (and col? (:line-fill? %)) (update :line-width + (/ horizontal-fill-space num-line-fill))))) - total-height (if (and col? (> num-line-fill 0)) layout-height total-height) - total-width (if (and row? (> num-line-fill 0)) layout-width total-width) + total-width (if (and col? (> num-line-fill 0)) layout-width total-width) + total-height (if (and row? (> num-line-fill 0)) layout-height total-height) base-p (get-base-line total-width total-height) @@ -257,40 +301,54 @@ (defn calc-layout-line-data "Calculates the baseline for a flex layout" - [{:keys [layout-type layout-gap] :as shape} + [{:keys [layout-justify-content] :as shape} layout-bounds - {:keys [num-children line-width line-height child-fill?] :as line-data}] + {:keys [num-children line-width line-height] :as line-data}] (let [width (gpo/width-points layout-bounds) height (gpo/height-points layout-bounds) - layout-gap - (cond - (or (= :packed layout-type) child-fill?) - layout-gap + row? (row? shape) + col? (col? shape) + space-between? (= layout-justify-content :space-between) + space-around? (= layout-justify-content :space-around) - (= :space-around layout-type) - 0 + [layout-gap-row layout-gap-col] (gaps shape) - (and (col? shape) (= :space-between layout-type)) - (/ (- width line-width) (dec num-children)) + layout-gap-row + (cond (and row? space-around?) + 0 - (and (row? shape) (= :space-between layout-type)) - (/ (- height line-height) (dec num-children))) + (and row? space-between?) + (/ (- width line-width) (dec num-children)) + + :else + layout-gap-row) + + layout-gap-col + (cond (and col? space-around?) + 0 + + (and col? space-between?) + (/ (- height line-height) (dec num-children)) + + :else + layout-gap-col) margin-x - (if (and (col? shape) (= :space-around layout-type)) + (if (and row? space-around?) (/ (- width line-width) (inc num-children)) 0) margin-y - (if (and (row? shape) (= :space-around layout-type)) + (if (and col? space-around?) (/ (- height line-height) (inc num-children)) 0)] (assoc line-data :layout-bounds layout-bounds - :layout-gap layout-gap + :layout-gap-row layout-gap-row + :layout-gap-col layout-gap-col :margin-x margin-x :margin-y margin-y))) @@ -298,7 +356,7 @@ "Calculates the position for the current shape given the layout-data context" [parent child-width child-height - {:keys [start-p layout-gap margin-x margin-y] :as layout-data}] + {:keys [start-p layout-gap-row layout-gap-col margin-x margin-y] :as layout-data}] (let [row? (row? parent) col? (col? parent) @@ -314,16 +372,16 @@ corner-p (cond-> start-p - (and row? h-center?) + (and col? h-center?) (gpt/add (xv (- (/ child-width 2)))) - (and row? h-end?) + (and col? h-end?) (gpt/add (xv (- child-width))) - (and col? v-center?) + (and row? v-center?) (gpt/add (yv (- (/ child-height 2)))) - (and col? v-end?) + (and row? v-end?) (gpt/add (yv (- child-height))) (some? margin-x) @@ -334,11 +392,11 @@ next-p (cond-> start-p - col? - (gpt/add (xv (+ child-width layout-gap))) - row? - (gpt/add (yv (+ child-height layout-gap))) + (gpt/add (xv (+ child-width layout-gap-row))) + + col? + (gpt/add (yv (+ child-height layout-gap-col))) (some? margin-x) (gpt/add (xv margin-x)) @@ -353,46 +411,48 @@ (defn calc-fill-width-data "Calculates the size and modifiers for the width of an auto-fill child" - [{:keys [layout-gap transform transform-inverse] :as parent} + [{:keys [transform transform-inverse] :as parent} {:keys [layout-h-behavior] :as child} child-origin child-width {:keys [num-children line-width line-fill? child-fill? layout-bounds] :as layout-data}] - (cond - (and (col? parent) (= :fill layout-h-behavior) child-fill?) - (let [layout-width (gpo/width-points layout-bounds) - fill-space (- layout-width line-width (* layout-gap (dec num-children))) - fill-width (/ fill-space (:num-child-fill layout-data)) - fill-scale (/ fill-width child-width)] + (let [[layout-gap-row _] (gaps parent)] + (cond + (and (row? parent) (= :fill layout-h-behavior) child-fill?) + (let [layout-width (gpo/width-points layout-bounds) + fill-space (- layout-width line-width (* layout-gap-row (dec num-children))) + fill-width (/ fill-space (:num-child-fill layout-data)) + fill-scale (/ fill-width child-width)] - {:width fill-width - :modifiers (ctm/resize (gpt/point fill-scale 1) child-origin transform transform-inverse)}) + {:width fill-width + :modifiers (ctm/resize (gpt/point fill-scale 1) child-origin transform transform-inverse)}) - (and (row? parent) (= :fill layout-h-behavior) line-fill?) - (let [fill-scale (/ line-width child-width)] - {:width line-width - :modifiers (ctm/resize (gpt/point fill-scale 1) child-origin transform transform-inverse)}))) + (and (col? parent) (= :fill layout-h-behavior) line-fill?) + (let [fill-scale (/ line-width child-width)] + {:width line-width + :modifiers (ctm/resize (gpt/point fill-scale 1) child-origin transform transform-inverse)})))) (defn calc-fill-height-data "Calculates the size and modifiers for the height of an auto-fill child" - [{:keys [layout-gap transform transform-inverse] :as parent} + [{:keys [transform transform-inverse] :as parent} {:keys [layout-v-behavior] :as child} child-origin child-height {: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 [layout-height (gpo/height-points layout-bounds) - fill-space (- layout-height line-height (* layout-gap (dec num-children))) - fill-height (/ fill-space (:num-child-fill layout-data)) - fill-scale (/ fill-height child-height)] - {:height fill-height - :modifiers (ctm/resize (gpt/point 1 fill-scale) child-origin transform transform-inverse)}) + (let [[_ layout-gap-col] (gaps parent)] + (cond + (and (col? parent) (= :fill layout-v-behavior) child-fill?) + (let [layout-height (gpo/height-points layout-bounds) + fill-space (- layout-height line-height (* layout-gap-col (dec num-children))) + fill-height (/ fill-space (:num-child-fill layout-data)) + fill-scale (/ fill-height child-height)] + {:height fill-height + :modifiers (ctm/resize (gpt/point 1 fill-scale) child-origin transform transform-inverse)}) - (and (col? parent) (= :fill layout-v-behavior) line-fill?) - (let [fill-scale (/ line-height child-height)] - {:height line-height - :modifiers (ctm/resize (gpt/point 1 fill-scale) child-origin transform transform-inverse)}))) + (and (row? parent) (= :fill layout-v-behavior) line-fill?) + (let [fill-scale (/ line-height child-height)] + {:height line-height + :modifiers (ctm/resize (gpt/point 1 fill-scale) child-origin transform transform-inverse)})))) (defn normalize-child-modifiers "Apply the modifiers and then normalized them against the parent coordinates" @@ -412,7 +472,7 @@ (defn calc-layout-data "Digest the layout data to pass it to the constrains" - [{:keys [layout-dir layout-padding layout-padding-type] :as parent} children] + [{:keys [layout-flex-dir layout-padding layout-padding-type] :as parent} children] (let [;; Add padding to the bounds {pad-top :p1 pad-right :p2 pad-bottom :p3 pad-left :p4} layout-padding @@ -427,7 +487,7 @@ layout-bounds (gpo/pad-points points pad-top pad-right pad-bottom pad-left) ;; Reverse - reverse? (or (= :left layout-dir) (= :bottom layout-dir)) + reverse? (or (= :reverse-row layout-flex-dir) (= :reverse-column layout-flex-dir)) children (cond->> children reverse? reverse) ;; Creates the layout lines information @@ -476,7 +536,9 @@ h-end? (and row? (h-end? frame)) v-center? (and col? (v-center? frame)) v-end? (and row? (v-end? frame)) - layout-gap (:layout-gap frame 0) + layout-gap-row (or (-> frame :layout-gap :row-gap) 0) + ;;layout-gap-col (or (-> frame :layout-gap :column-gap) 0) + layout-gap layout-gap-row ;; TODO LAYOUT: FIXME reverse? (:reverse? layout-data) children (vec (cond->> (d/enumerate children) @@ -499,31 +561,31 @@ box-width (-> child :selrect :width) box-height (-> child :selrect :height) - x (if row? (:x parent-rect) prev-x) - y (if col? (:y parent-rect) prev-y) + x (if col? (:x parent-rect) prev-x) + y (if row? (:y parent-rect) prev-y) width (cond - (and col? last?) + (and row? last?) (- (+ (:x parent-rect) (:width parent-rect)) x) - row? + col? (:width parent-rect) :else (+ box-width (- box-x prev-x) (/ layout-gap 2))) height (cond - (and row? last?) + (and col? last?) (- (+ (:y parent-rect) (:height parent-rect)) y) - col? + row? (:height parent-rect) :else (+ box-height (- box-y prev-y) (/ layout-gap 2))) [line-area-1 line-area-2] - (if col? + (if row? (let [half-point-width (+ (- box-x x) (/ box-width 2))] [(-> (gsr/make-rect x y half-point-width height) (assoc :index (if reverse? (inc index) index))) @@ -555,16 +617,16 @@ last? (nil? next) line-width - (if col? + (if row? (:width frame) (+ line-width margin-x - (if col? (* layout-gap (dec num-children)) 0))) + (if row? (* layout-gap (dec num-children)) 0))) line-height - (if row? + (if col? (:height frame) (+ line-height margin-y - (if row? + (if col? (* layout-gap (dec num-children)) 0))) @@ -582,24 +644,24 @@ v-end? line-height :else 0)) - x (if col? (:x frame) prev-x) - y (if row? (:y frame) prev-y) + x (if row? (:x frame) prev-x) + y (if col? (:y frame) prev-y) width (cond - (and row? last?) + (and col? last?) (- (+ (:x frame) (:width frame)) x) - col? + row? (:width frame) :else (+ line-width (- box-x prev-x) (/ layout-gap 2))) height (cond - (and col? last?) + (and row? last?) (- (+ (:y frame) (:height frame)) y) - row? + col? (:height frame) :else diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index 3660aec60..6f7d9a5ec 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -8,9 +8,10 @@ (:require [app.common.data :as d] [app.common.geom.shapes.constraints :as gct] - [app.common.geom.shapes.layout :as gcl] + [app.common.geom.shapes.flex-layout :as gcl] [app.common.geom.shapes.pixel-precision :as gpp] [app.common.geom.shapes.transforms :as gtr] + [app.common.pages.helpers :as cph] [app.common.types.modifiers :as ctm] [app.common.uuid :as uuid])) @@ -101,7 +102,7 @@ modif-tree))))) -(defn get-first-layout +(defn get-tree-root [id objects] (loop [current id @@ -127,24 +128,40 @@ (recur (:id parent) result))))) (defn resolve-tree-sequence - ;; TODO LAYOUT: Esta ahora puesto al zero pero tiene que mirar todas las raices "Given the ids that have changed search for layout roots to recalculate" - [_ids objects] - (->> (tree-seq - #(d/not-empty? (get-in objects [% :shapes])) - #(get-in objects [% :shapes]) - uuid/zero) + [modif-tree objects] - (map #(get objects %)))) + (let [redfn + (fn [result id] + (if (= id uuid/zero) + result + (let [root (get-tree-root id objects) -(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] + ;; Remove the children from the current root + result + (into #{} (remove #(cph/is-child? objects root %)) result) - (into (d/ordered-set) - (map #(get-first-layout % objects)) - ids)) + contains-parent? + (some #(cph/is-child? objects % root) result)] + + (cond-> result + (not contains-parent?) + (conj root))))) + + generate-tree + (fn [id] + (->> (tree-seq + #(d/not-empty? (get-in objects [% :shapes])) + #(get-in objects [% :shapes]) + id) + + (map #(get objects %)))) + + roots (->> modif-tree keys (reduce redfn #{}))] + + (concat + (when (contains? modif-tree uuid/zero) [(get objects uuid/zero)]) + (mapcat generate-tree roots)))) (defn inside-layout? [objects shape] @@ -170,34 +187,31 @@ ;; modif-tree)))) (defn set-objects-modifiers - [ids objects get-modifier ignore-constraints snap-pixel?] + [modif-tree objects ignore-constraints snap-pixel?] - (let [set-modifiers - (fn [modif-tree id] - (let [root? (= uuid/zero id) - shape (get objects id) - modifiers (cond-> (get-modifier shape) - (and (not root?) snap-pixel?) - (gpp/set-pixel-precision shape))] - (-> modif-tree - (assoc id {:modifiers modifiers})))) - - modif-tree (reduce set-modifiers {} ids) - shapes-tree (resolve-tree-sequence ids objects) + (let [shapes-tree (resolve-tree-sequence modif-tree objects) modif-tree (->> shapes-tree (reduce (fn [modif-tree shape] + (let [root? (= uuid/zero (:id shape)) + modifiers (get-in modif-tree [(:id shape) :modifiers]) - has-modifiers? (some? modifiers) + 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?) @@ -207,6 +221,6 @@ modif-tree))] - ;; #?(:cljs - ;; (.log js/console ">result" (modif->js modif-tree objects))) + ;;#?(:cljs + ;; (.log js/console ">result" (modif->js modif-tree objects))) modif-tree)) diff --git a/common/src/app/common/geom/shapes/pixel_precision.cljc b/common/src/app/common/geom/shapes/pixel_precision.cljc index 03aa4359a..40e32ae72 100644 --- a/common/src/app/common/geom/shapes/pixel_precision.cljc +++ b/common/src/app/common/geom/shapes/pixel_precision.cljc @@ -31,8 +31,10 @@ ratio-width (/ target-width curr-width) ratio-height (/ target-height curr-height) scalev (gpt/point ratio-width ratio-height)] - (-> modifiers - (ctm/set-resize scalev origin transform transform-inverse)))) + (cond-> modifiers + (or (not (mth/almost-zero? (- ratio-width 1))) + (not (mth/almost-zero? (- ratio-height 1)))) + (ctm/set-resize scalev origin transform transform-inverse)))) (defn position-pixel-precision [modifiers shape] @@ -41,8 +43,10 @@ corner (gpt/point bounds) target-corner (gpt/round corner) deltav (gpt/to-vec corner target-corner)] - (-> modifiers - (ctm/set-move deltav)))) + (cond-> modifiers + (or (not (mth/almost-zero? (:x deltav))) + (not (mth/almost-zero? (:y deltav)))) + (ctm/set-move deltav)))) (defn set-pixel-precision "Adjust modifiers so they adjust to the pixel grid" diff --git a/common/src/app/common/types/modifiers.cljc b/common/src/app/common/types/modifiers.cljc index bd0715aec..22c5ff636 100644 --- a/common/src/app/common/types/modifiers.cljc +++ b/common/src/app/common/types/modifiers.cljc @@ -24,7 +24,8 @@ ;; - structure-parent: Structure non recursive ;; * add-children ;; * remove-children -;; - structure-child: Structre recursive +;; * reflow +;; - structure-child: Structure recursive ;; * scale-content ;; @@ -47,44 +48,48 @@ ([modifiers vector origin] (-> modifiers (update :geometry conjv {:type :resize - :vector vector - :origin origin}))) + :vector vector + :origin origin}))) ([modifiers vector origin transform transform-inverse] (-> modifiers (update :geometry conjv {:type :resize - :vector vector - :origin origin - :transform transform - :transform-inverse transform-inverse})))) + :vector vector + :origin origin + :transform transform + :transform-inverse transform-inverse})))) (defn set-rotation [modifiers center angle] (-> modifiers (update :geometry conjv {:type :rotation - :center center - :rotation angle}))) + :center center + :rotation angle}))) (defn set-remove-children [modifiers shapes] (-> modifiers (update :structure-parent conjv {:type :remove-children - :value shapes})) + :value shapes})) ) (defn set-add-children [modifiers shapes index] (-> modifiers (update :structure-parent conjv {:type :add-children - :value shapes - :index index}))) + :value shapes + :index index}))) + +(defn set-reflow + [modifiers] + (-> modifiers + (update :structure-parent conjv {:type :reflow}))) (defn set-scale-content [modifiers value] (-> modifiers (update :structure-child conjv {:type :scale-content :value value}))) - (defn add-modifiers [modifiers new-modifiers] @@ -124,7 +129,7 @@ (-> (empty-modifiers) (set-rotation shape-center angle) - (set-move (gpt/transform (gpt/point 1 1) rotation))))) + (set-move (gpt/transform (gpt/point 0 0) rotation))))) (defn remove-children [shapes] @@ -136,11 +141,21 @@ (-> (empty-modifiers) (set-add-children shapes index))) +(defn reflow + [] + (-> (empty-modifiers) + (set-reflow))) + (defn scale-content [value] (-> (empty-modifiers) (set-scale-content value))) +(defn child-modifiers? + [{:keys [geometry structure-child]}] + (or (d/not-empty? geometry) + (d/not-empty? structure-child))) + (defn select-child-modifiers [modifiers] (select-keys modifiers [:geometry :structure-child])) @@ -337,3 +352,7 @@ (as-> shape $ (reduce apply-modifier $ (:structure-parent modifiers)) (reduce apply-modifier $ (:structure-child modifiers))))) + +(defn has-geometry? + [{:keys [geometry]}] + (d/not-empty? geometry)) diff --git a/common/test/common_tests/geom_shapes_test.cljc b/common/test/common_tests/geom_shapes_test.cljc index f86487de2..e36a487e7 100644 --- a/common/test/common_tests/geom_shapes_test.cljc +++ b/common/test/common_tests/geom_shapes_test.cljc @@ -10,6 +10,7 @@ [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] [app.common.math :as mth :refer [close?]] + [app.common.types.modifiers :as ctm] [app.common.types.shape :as cts] [clojure.test :as t])) @@ -59,7 +60,7 @@ (t/testing "Transform shape with translation modifiers" (t/are [type] - (let [modifiers {:displacement (gmt/translate-matrix (gpt/point 10 -10))}] + (let [modifiers (ctm/move (gpt/point 10 -10))] (let [shape-before (create-test-shape type {:modifiers modifiers}) shape-after (gsh/transform-shape shape-before)] (t/is (not= shape-before shape-after)) @@ -91,9 +92,7 @@ (t/testing "Transform shape with resize modifiers" (t/are [type] - (let [modifiers {:resize-origin (gpt/point 0 0) - :resize-vector (gpt/point 2 2) - :resize-transform (gmt/matrix)} + (let [modifiers (ctm/resize (gpt/point 2 2) (gpt/point 0 0)) shape-before (create-test-shape type {:modifiers modifiers}) shape-after (gsh/transform-shape shape-before)] (t/is (not= shape-before shape-after)) @@ -113,9 +112,7 @@ (t/testing "Transform with empty resize" (t/are [type] - (let [modifiers {:resize-origin (gpt/point 0 0) - :resize-vector (gpt/point 1 1) - :resize-transform (gmt/matrix)} + (let [modifiers (ctm/resize (gpt/point 1 1) (gpt/point 0 0)) shape-before (create-test-shape type {:modifiers modifiers}) shape-after (gsh/transform-shape shape-before)] (t/are [prop] @@ -126,9 +123,7 @@ (t/testing "Transform with resize=0" (t/are [type] - (let [modifiers {:resize-origin (gpt/point 0 0) - :resize-vector (gpt/point 0 0) - :resize-transform (gmt/matrix)} + (let [modifiers (ctm/resize (gpt/point 0 0) (gpt/point 0 0)) shape-before (create-test-shape type {:modifiers modifiers}) shape-after (gsh/transform-shape shape-before)] (t/is (> (get-in shape-before [:selrect :width]) @@ -142,13 +137,13 @@ (t/testing "Transform shape with rotation modifiers" (t/are [type] - (let [modifiers {:rotation 30} - shape-before (create-test-shape type {:modifiers modifiers}) + (let [shape-before (create-test-shape type) + modifiers (ctm/rotation shape-before (gsh/center-shape shape-before) 30 ) + shape-before (assoc shape-before :modifiers modifiers) shape-after (gsh/transform-shape shape-before)] - (t/is (not= shape-before shape-after)) + (t/is (not= (:selrect shape-before) (:selrect shape-after))) - ;; Selrect won't change with a rotation, but points will (t/is (close? (get-in shape-before [:selrect :x]) (get-in shape-after [:selrect :x]))) @@ -166,9 +161,9 @@ (t/testing "Transform shape with rotation = 0 should leave equal selrect" (t/are [type] - (let [modifiers {:rotation 0} - shape-before (create-test-shape type {:modifiers modifiers}) - shape-after (gsh/transform-shape shape-before)] + (let [shape-before (create-test-shape type) + modifiers (ctm/rotation shape-before (gsh/center-shape shape-before) 0) + shape-after (gsh/transform-shape (assoc shape-before :modifiers modifiers))] (t/are [prop] (t/is (close? (get-in shape-before [:selrect prop]) (get-in shape-after [:selrect prop]))) @@ -177,12 +172,13 @@ (t/testing "Transform shape with invalid selrect fails gracefully" (t/are [type selrect] - (let [modifiers {:displacement (gmt/matrix)} + (let [modifiers (ctm/move 0 0) shape-before (-> (create-test-shape type {:modifiers modifiers}) (assoc :selrect selrect)) shape-after (gsh/transform-shape shape-before)] - (= (:selrect shape-before) - (:selrect shape-after))) + + (t/is (not= (:selrect shape-before) + (:selrect shape-after)))) :rect {:x 0.0 :y 0.0 :x1 0.0 :y1 0.0 :x2 ##Inf :y2 ##Inf :width ##Inf :height ##Inf} :path {:x 0.0 :y 0.0 :x1 0.0 :y1 0.0 :x2 ##Inf :y2 ##Inf :width ##Inf :height ##Inf} diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index cffd33827..da2262c53 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -8,6 +8,7 @@ (:require [app.common.data :as d] [app.common.pages.helpers :as cph] + [app.common.types.modifiers :as ctm] [app.main.data.workspace.changes :as dwc] [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.transforms :as dwt] @@ -25,8 +26,7 @@ :layout-wrap-type :layout-padding-type :layout-padding - ]) - + :layout-gap-type]) (def initial-flex-layout {:layout :flex @@ -51,8 +51,9 @@ (let [objects (wsh/lookup-page-objects state) ids (->> ids (filter #(get-in objects [% :layout])))] (if (d/not-empty? ids) - (rx/of (dwt/set-modifiers ids) - (dwt/apply-modifiers)) + (let [modif-tree (dwt/create-modif-tree ids (ctm/reflow))] + (rx/of (dwt/set-modifiers modif-tree) + (dwt/apply-modifiers))) (rx/empty)))))) ;; TODO LAYOUT: Remove constraints from children diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index f304dbe31..1769d41ae 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -11,7 +11,7 @@ [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] - [app.common.geom.shapes.layout :as gsl] + [app.common.geom.shapes.flex-layout :as gsl] [app.common.math :as mth] [app.common.pages.changes-builder :as pcb] [app.common.pages.common :as cpc] @@ -117,46 +117,69 @@ (declare get-ignore-tree) +(defn create-modif-tree + [ids modifiers] + (us/verify (s/coll-of uuid?) ids) + (into {} (map #(vector % {:modifiers modifiers})) ids)) + +(defn build-modif-tree + [ids objects get-modifier] + (us/verify (s/coll-of uuid?) ids) + (into {} (map #(vector % {:modifiers (get-modifier (get objects %))})) ids)) + +(defn build-change-frame-modifiers + [modif-tree objects selected target-frame position] + + (let [origin-frame-ids (->> selected (group-by #(get-in objects [% :frame-id]))) + layout? (get-in objects [target-frame :layout]) + child-set (set (get-in objects [target-frame :shapes])) + drop-index (when layout? (gsl/get-drop-index target-frame objects position)) + + update-frame-modifiers + (fn [modif-tree [original-frame shapes]] + (let [shapes (->> shapes (d/removev #(= target-frame %))) + shapes (cond->> shapes + (and layout? (= original-frame target-frame)) + ;; When movining inside a layout frame remove the shapes that are not immediate children + (filterv #(contains? child-set %)))] + (cond-> modif-tree + (not= original-frame target-frame) + (-> (update-in [original-frame :modifiers] ctm/set-remove-children shapes) + (update-in [target-frame :modifiers] ctm/set-add-children shapes drop-index)) + + (and layout? (= original-frame target-frame)) + (update-in [target-frame :modifiers] ctm/set-add-children shapes drop-index))))] + + (reduce update-frame-modifiers modif-tree origin-frame-ids))) + +(defn modif->js + [modif-tree objects] + (clj->js (into {} + (map (fn [[k v]] + [(get-in objects [k :name]) v])) + modif-tree))) + (defn set-modifiers - ([ids] - (set-modifiers ids nil false)) + ([modif-tree] + (set-modifiers modif-tree false)) - ([ids modifiers] - (set-modifiers ids modifiers false)) + ([modif-tree ignore-constraints] + (set-modifiers modif-tree ignore-constraints false)) - ([ids modifiers ignore-constraints] - (set-modifiers ids modifiers ignore-constraints false)) - - ([ids modifiers ignore-constraints ignore-snap-pixel] - (us/verify (s/coll-of uuid?) ids) + ([modif-tree ignore-constraints ignore-snap-pixel] (ptk/reify ::set-modifiers ptk/UpdateEvent (update [_ state] - (let [objects (wsh/lookup-page-objects state) - ids (into #{} (remove #(get-in objects [% :blocked] false)) ids) + (let [objects + (wsh/lookup-page-objects state) - snap-pixel? (and (not ignore-snap-pixel) - (contains? (:workspace-layout state) :snap-pixel-grid)) - - workspace-modifiers (:workspace-modifiers state) + snap-pixel? + (and (not ignore-snap-pixel) (contains? (:workspace-layout state) :snap-pixel-grid)) modif-tree - (gsh/set-objects-modifiers - ;; TODO LAYOUT: I don't like this - (concat (keys workspace-modifiers) ids) - objects - (fn [shape] - (let [ - modifiers (if (contains? ids (:id shape)) modifiers (ctm/empty-modifiers)) + (gsh/set-objects-modifiers modif-tree objects ignore-constraints snap-pixel?)] - structure-modifiers (ctm/select-structure - (get-in state [:workspace-modifiers (:id shape) :modifiers]))] - (cond-> modifiers - (some? structure-modifiers) - (ctm/add-modifiers structure-modifiers)))) - ignore-constraints snap-pixel?)] - - (update state :workspace-modifiers merge modif-tree)))))) + (assoc state :workspace-modifiers modif-tree)))))) ;; Rotation use different algorithm to calculate children modifiers (and do not use child constraints). (defn- set-rotation-modifiers @@ -171,8 +194,6 @@ ids (->> shapes (remove #(get % :blocked false)) - #_(mapcat #(cph/get-children objects (:id %))) - #_(concat shapes) (filter #((cpc/editable-attrs (:type %)) :rotation)) (map :id)) @@ -181,9 +202,10 @@ (ctm/rotation shape center angle)) modif-tree - (gsh/set-objects-modifiers ids objects get-modifier false false)] + (-> (build-modif-tree ids objects get-modifier) + (gsh/set-objects-modifiers objects false false))] - (update state :workspace-modifiers merge modif-tree)))))) + (assoc state :workspace-modifiers modif-tree)))))) (defn- update-grow-type [shape old-shape] @@ -408,9 +430,11 @@ (ctm/set-resize scalev resize-origin shape-transform shape-transform-inverse) (cond-> scale-text - (ctm/set-scale-content (:x scalev))))] + (ctm/set-scale-content (:x scalev)))) - (rx/of (set-modifiers ids modifiers)))) + modif-tree (create-modif-tree ids modifiers)] + + (rx/of (set-modifiers modif-tree)))) ;; Unifies the instantaneous proportion lock modifier ;; activated by Shift key and the shapes own proportion @@ -463,7 +487,8 @@ (fn [shape] (ctm/change-dimensions shape attr value)) modif-tree - (gsh/set-objects-modifiers ids objects get-modifier false snap-pixel?)] + (-> (build-modif-tree ids objects get-modifier) + (gsh/set-objects-modifiers objects false snap-pixel?))] (assoc state :workspace-modifiers modif-tree))) @@ -487,7 +512,8 @@ (fn [shape] (ctm/change-orientation-modifiers shape orientation)) modif-tree - (gsh/set-objects-modifiers ids objects get-modifier false snap-pixel?)] + (-> (build-modif-tree ids objects get-modifier) + (gsh/set-objects-modifiers objects false snap-pixel?))] (assoc state :workspace-modifiers modif-tree))) @@ -621,37 +647,6 @@ (rx/take 1) (rx/map #(start-move from-position)))))) -(defn set-change-frame-modifiers - [selected target-frame position] - - (ptk/reify ::set-change-frame-modifiers - ptk/UpdateEvent - (update [_ state] - (let [objects (wsh/lookup-page-objects state) - - origin-frame-ids (->> selected (group-by #(get-in objects [% :frame-id]))) - - layout? (get-in objects [target-frame :layout]) - - drop-index - (when layout? (gsl/get-drop-index target-frame objects position)) - - modif-tree - (into {} - (mapcat - (fn [original-frame] - (let [shapes (->> (get origin-frame-ids original-frame) - (d/removev #(= target-frame %)))] - (cond - (not= original-frame target-frame) - [[original-frame {:modifiers (ctm/remove-children shapes)}] - [target-frame {:modifiers (ctm/add-children shapes drop-index)}]] - - layout? - [[target-frame {:modifiers (ctm/add-children shapes drop-index)}]])))) - (keys origin-frame-ids))] - - (assoc state :workspace-modifiers modif-tree))))) (defn- start-move ([from-position] (start-move from-position nil)) @@ -699,22 +694,21 @@ (rx/of (finish-transform)) (rx/concat (rx/merge - (->> position - (rx/map (fn [delta] - (let [position (gpt/add from-position delta) - target-frame (ctst/top-nested-frame objects position)] - (set-change-frame-modifiers selected target-frame position)))) - (rx/take-until stopper)) - (->> position ;; We ask for the snap position but we continue even if the result is not available (rx/with-latest vector snap-delta) ;; We try to use the previous snap so we don't have to wait for the result of the new (rx/map snap/correct-snap-point) - (rx/map ctm/move) - (rx/map (partial set-modifiers ids)) + (rx/map + (fn [move-vector] + (let [position (gpt/add from-position move-vector) + target-frame (ctst/top-nested-frame objects position)] + (-> (create-modif-tree ids (ctm/move move-vector)) + (build-change-frame-modifiers objects selected target-frame position) + (set-modifiers))))) + (rx/take-until stopper))) (rx/of (dwu/start-undo-transaction) @@ -762,8 +756,8 @@ (rx/merge (->> move-events (rx/scan #(gpt/add %1 mov-vec) (gpt/point 0 0)) - (rx/map #(ctm/move %)) - (rx/map (partial set-modifiers selected)) + (rx/map #(create-modif-tree selected (ctm/move %))) + (rx/map (partial set-modifiers)) (rx/take-until stopper)) (rx/of (move-selected direction shift?))) @@ -793,11 +787,12 @@ cpos (gpt/point (:x bbox) (:y bbox)) pos (gpt/point (or (:x position) (:x bbox)) (or (:y position) (:y bbox))) - delta (gpt/subtract pos cpos)] + delta (gpt/subtract pos cpos) - (rx/of - (set-modifiers [id] (ctm/move delta)) - (apply-modifiers [id])))))) + modif-tree (create-modif-tree [id] (ctm/move delta))] + + (rx/of (set-modifiers modif-tree) + (apply-modifiers)))))) (defn- calculate-frame-for-move [ids] @@ -816,7 +811,11 @@ moving-shapes (cond->> shapes (not layout?) - (remove #(= (:frame-id %) frame-id))) + (remove #(= (:frame-id %) frame-id)) + + layout? + (remove #(and (= (:frame-id %) frame-id) + (not= (:parent-id %) frame-id)))) drop-index (when layout? (gsl/get-drop-index frame-id objects position)) @@ -850,13 +849,15 @@ selected (wsh/lookup-selected state {:omit-blocked? true}) shapes (map #(get objects %) selected) selrect (gsh/selection-rect shapes) - origin (gpt/point (:x selrect) (+ (:y selrect) (/ (:height selrect) 2)))] + origin (gpt/point (:x selrect) (+ (:y selrect) (/ (:height selrect) 2))) - (rx/of (set-modifiers selected - (-> (ctm/empty-modifiers) - (ctm/set-resize (gpt/point -1.0 1.0) origin) - (ctm/move (gpt/point (:width selrect) 0))) - true) + modif-tree (create-modif-tree + selected + (-> (ctm/empty-modifiers) + (ctm/set-resize (gpt/point -1.0 1.0) origin) + (ctm/move (gpt/point (:width selrect) 0))))] + + (rx/of (set-modifiers modif-tree true) (apply-modifiers)))))) (defn flip-vertical-selected [] @@ -867,11 +868,13 @@ selected (wsh/lookup-selected state {:omit-blocked? true}) shapes (map #(get objects %) selected) selrect (gsh/selection-rect shapes) - origin (gpt/point (+ (:x selrect) (/ (:width selrect) 2)) (:y selrect))] + origin (gpt/point (+ (:x selrect) (/ (:width selrect) 2)) (:y selrect)) - (rx/of (set-modifiers selected - (-> (ctm/empty-modifiers) - (ctm/set-resize (gpt/point 1.0 -1.0) origin) - (ctm/move (gpt/point 0 (:height selrect)))) - true) + modif-tree (create-modif-tree + selected + (-> (ctm/empty-modifiers) + (ctm/set-resize (gpt/point 1.0 -1.0) origin) + (ctm/move (gpt/point 0 (:height selrect)))))] + + (rx/of (set-modifiers modif-tree true) (apply-modifiers)))))) diff --git a/frontend/src/app/main/snap.cljs b/frontend/src/app/main/snap.cljs index ce2b97c24..f9585b5bf 100644 --- a/frontend/src/app/main/snap.cljs +++ b/frontend/src/app/main/snap.cljs @@ -358,7 +358,8 @@ "Snaps a position given an old snap to a different position. We use this to provide a temporal snap while the new is being processed." [[position [snap-pos snap-delta]]] - (if (some? snap-delta) + (if (nil? snap-delta) + position (let [dx (if (not= 0 (:x snap-delta)) (- (+ (:x snap-pos) (:x snap-delta)) (:x position)) 0) @@ -372,6 +373,4 @@ dy (if (> (mth/abs dy) snap-accuracy) 0 dy)] (-> position (update :x + dx) - (update :y + dy))) - - position)) + (update :y + dy))))) diff --git a/frontend/src/app/main/ui/workspace/shapes.cljs b/frontend/src/app/main/ui/workspace/shapes.cljs index a6ca1742b..0b92d475e 100644 --- a/frontend/src/app/main/ui/workspace/shapes.cljs +++ b/frontend/src/app/main/ui/workspace/shapes.cljs @@ -68,24 +68,21 @@ [:g.frame-children (for [shape shapes] - [:g.ws-shape-wrapper + [:g.ws-shape-wrapper {:key (:id shape)} (cond (not (cph/frame-shape? shape)) [:& shape-wrapper - {:shape shape - :key (:id shape)}] + {:shape shape}] (cph/root-frame? shape) [:& root-frame-wrapper {:shape shape - :key (:id shape) :objects (get frame-objects (:id shape)) :thumbnail? (not (contains? active-frames (:id shape)))}] :else [:& nested-frame-wrapper {:shape shape - :key (:id shape) :objects (get frame-objects (:id shape))}])])]]])) (mf/defc shape-wrapper diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs index d27cb93a5..e0b8fd357 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs @@ -84,38 +84,38 @@ [:div.layout-behavior.horizontal [:button.behavior-btn.tooltip.tooltip-bottom {:alt "Fix width" - :class (dom/classnames :activated (= layout-h-behavior :fix)) + :class (dom/classnames :active (= layout-h-behavior :fix)) :on-click #(on-change-behavior :h :fix)} i/auto-fix-layout] (when fill? [:button.behavior-btn.tooltip.tooltip-bottom {:alt "Width 100%" - :class (dom/classnames :activated (= layout-h-behavior :fill)) + :class (dom/classnames :active (= layout-h-behavior :fill)) :on-click #(on-change-behavior :h :fill)} i/auto-fill]) (when auto? [:button.behavior-btn.tooltip.tooltip-bottom {:alt "Fit content" - :class (dom/classnames :activated (= layout-v-behavior :auto)) + :class (dom/classnames :active (= layout-v-behavior :auto)) :on-click #(on-change-behavior :h :auto)} i/auto-hug])] [:div.layout-behavior [:button.behavior-btn.tooltip.tooltip-bottom {:alt "Fix height" - :class (dom/classnames :activated (= layout-v-behavior :fix)) + :class (dom/classnames :active (= layout-v-behavior :fix)) :on-click #(on-change-behavior :v :fix)} i/auto-fix-layout] (when fill? [:button.behavior-btn.tooltip.tooltip-bottom {:alt "Height 100%" - :class (dom/classnames :activated (= layout-v-behavior :fill)) + :class (dom/classnames :active (= layout-v-behavior :fill)) :on-click #(on-change-behavior :v :fill)} i/auto-fill]) (when auto? [:button.behavior-btn.tooltip.tooltip-bottom-left {:alt "Fit content" - :class (dom/classnames :activated (= layout-v-behavior :auto)) + :class (dom/classnames :active (= layout-v-behavior :auto)) :on-click #(on-change-behavior :v :auto)} i/auto-hug])]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs index bd9df2411..048fff5c0 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs @@ -47,7 +47,7 @@ [:* [:& layout-container-menu {:type type :ids [(:id shape)] :values layout-container-values}] - (when (or (:layout shape) is-layout-child?) + (when is-layout-child? [:& layout-item-menu {:ids ids :type type diff --git a/frontend/src/app/main/ui/workspace/viewport/debug.cljs b/frontend/src/app/main/ui/workspace/viewport/debug.cljs index ef81d5fa9..869caa8ca 100644 --- a/frontend/src/app/main/ui/workspace/viewport/debug.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/debug.cljs @@ -9,7 +9,7 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.geom.shapes :as gsh] - [app.common.geom.shapes.layout :as gsl] + [app.common.geom.shapes.flex-layout :as gsl] [app.common.pages.helpers :as cph] [rumext.v2 :as mf])) From 58fd20094a0c56ec1f345d0ef32aa1626ecbd008 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 21 Oct 2022 16:03:11 +0200 Subject: [PATCH 10/36] :sparkles: Adapted dynamic modifiers and options for new modifiers --- common/src/app/common/types/modifiers.cljc | 11 +++++---- .../shapes/frame/dynamic_modifiers.cljs | 24 +++++++++++-------- .../main/ui/workspace/sidebar/options.cljs | 7 ++---- .../sidebar/options/menus/measures.cljs | 10 ++++---- 4 files changed, 29 insertions(+), 23 deletions(-) diff --git a/common/src/app/common/types/modifiers.cljc b/common/src/app/common/types/modifiers.cljc index 22c5ff636..fe308d402 100644 --- a/common/src/app/common/types/modifiers.cljc +++ b/common/src/app/common/types/modifiers.cljc @@ -27,6 +27,7 @@ ;; * reflow ;; - structure-child: Structure recursive ;; * scale-content +;; * rotation ;; (def conjv (fnil conj [])) @@ -62,6 +63,8 @@ (defn set-rotation [modifiers center angle] (-> modifiers + (update :structure-child conjv {:type :rotation + :rotation angle}) (update :geometry conjv {:type :rotation :center center :rotation angle}))) @@ -327,11 +330,12 @@ (let [remove? (set children-to-remove)] (d/removev remove? shapes))) - - apply-modifier - (fn [shape {:keys [type value index]}] + (fn [shape {:keys [type value index rotation]}] (cond-> shape + (= type :rotation) + (update :rotation #(mod (+ % rotation) 360)) + (and (= type :add-children) (some? index)) (update :shapes (fn [shapes] @@ -348,7 +352,6 @@ (= type :scale-content) (apply-scale-content value)))] - (as-> shape $ (reduce apply-modifier $ (:structure-parent modifiers)) (reduce apply-modifier $ (:structure-child modifiers))))) diff --git a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs index 288ebcbff..b5a34ba65 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs @@ -248,18 +248,22 @@ (mf/use-layout-effect (mf/deps transforms) (fn [] - (let [is-prev-val? (d/not-empty? @prev-modifiers) - is-cur-val? (d/not-empty? modifiers)] - (when (and (not is-prev-val?) is-cur-val?) - (start-transform! node shapes)) + (let [curr-shapes-set (into #{} (map :id) shapes) + prev-shapes-set (into #{} (map :id) @prev-shapes) - (when is-cur-val? + new-shapes (->> shapes (remove #(contains? prev-shapes-set (:id %)))) + removed-shapes (->> @prev-shapes (remove #(contains? curr-shapes-set (:id %))))] + + (when (d/not-empty? new-shapes) + (start-transform! node new-shapes)) + + (when (d/not-empty? shapes) (update-transform! node shapes transforms modifiers)) - (when (and is-prev-val? (not is-cur-val?)) - (remove-transform! node @prev-shapes)) + (when (d/not-empty? removed-shapes) + (remove-transform! node @prev-shapes))) - (reset! prev-modifiers modifiers) - (reset! prev-transforms transforms) - (reset! prev-shapes shapes)))))) + (reset! prev-modifiers modifiers) + (reset! prev-transforms transforms) + (reset! prev-shapes shapes))))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options.cljs b/frontend/src/app/main/ui/workspace/sidebar/options.cljs index 99f65f0fe..1a0faed46 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options.cljs @@ -60,12 +60,9 @@ {::mf/wrap [mf/memo]} [{:keys [selected section shapes shapes-with-children page-id file-id]}] (let [drawing (mf/deref refs/workspace-drawing) - base-objects (-> (mf/deref refs/workspace-page-objects)) + objects (mf/deref refs/workspace-page-objects) shared-libs (mf/deref refs/workspace-libraries) - modifiers (mf/deref refs/workspace-modifiers) - objects-modified (mf/with-memo [base-objects modifiers] - (ctm/merge-modifiers base-objects modifiers)) - selected-shapes (into [] (keep (d/getf objects-modified)) selected)] + selected-shapes (into [] (keep (d/getf objects)) selected)] [:div.tool-window [:div.tool-window-content [:& tab-container {:on-change-tab #(st/emit! (udw/set-options-mode %)) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs index 8a9e73f3c..2fdea6e9f 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs @@ -68,7 +68,9 @@ ;; -- User/drawing coords (mf/defc measures-menu [{:keys [ids ids-with-children values type all-types shape] :as props}] - (let [options (if (= type :multiple) + (let [workspace-modifiers (mf/deref refs/workspace-modifiers) + + options (if (= type :multiple) (reduce #(union %1 %2) (map #(get type->options %) all-types)) (get type->options type)) @@ -83,7 +85,9 @@ ;; the shape with the mouse, generate a copy of the shapes applying ;; the transient transformations. shapes (as-> old-shapes $ - #_(map gsh/transform-shape $) + (map (fn [shape] + (let [modifiers (get-in workspace-modifiers [(:id shape) :modifiers])] + (gsh/transform-shape shape modifiers))) $) (map gsh/translate-to-frame $ frames)) ;; For rotated or stretched shapes, the origin point we show in the menu @@ -441,5 +445,3 @@ (tr "workspace.options.show-in-viewer")]]) ]]])) - - From b8c90fdcf3c63b470520de0b768ca802c5036ecf Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Mon, 24 Oct 2022 15:58:38 +0200 Subject: [PATCH 11/36] :sparkles: Refactor flex layout namespace --- .../app/common/geom/shapes/flex_layout.cljc | 694 +----------------- .../geom/shapes/flex_layout/drop_area.cljc | 179 +++++ .../common/geom/shapes/flex_layout/lines.cljc | 309 ++++++++ .../geom/shapes/flex_layout/modifiers.cljc | 103 +++ .../geom/shapes/flex_layout/positions.cljc | 68 ++ common/src/app/common/types/shape/layout.cljc | 129 ++++ .../main/ui/workspace/sidebar/options.cljs | 1 - 7 files changed, 798 insertions(+), 685 deletions(-) create mode 100644 common/src/app/common/geom/shapes/flex_layout/drop_area.cljc create mode 100644 common/src/app/common/geom/shapes/flex_layout/lines.cljc create mode 100644 common/src/app/common/geom/shapes/flex_layout/modifiers.cljc create mode 100644 common/src/app/common/geom/shapes/flex_layout/positions.cljc diff --git a/common/src/app/common/geom/shapes/flex_layout.cljc b/common/src/app/common/geom/shapes/flex_layout.cljc index b67e12e4d..8361d230f 100644 --- a/common/src/app/common/geom/shapes/flex_layout.cljc +++ b/common/src/app/common/geom/shapes/flex_layout.cljc @@ -6,687 +6,13 @@ (ns app.common.geom.shapes.flex-layout (: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.points :as gpo] - [app.common.geom.shapes.rect :as gsr] - [app.common.geom.shapes.transforms :as gst] - [app.common.pages.helpers :as cph] - [app.common.types.modifiers :as ctm])) - -;; :layout ;; :flex, :grid in the future -;; :layout-flex-dir ;; :row, :reverse-row, :column, :reverse-column -;; :layout-gap-type ;; :simple, :multiple -;; :layout-gap ;; {:row-gap number , :column-gap number} -;; :layout-align-items ;; :start :end :center :strech -;; :layout-justify-content ;; :start :center :end :space-between :space-around -;; :layout-align-content ;; :start :center :end :space-between :space-around :strech (by default) -;; :layout-wrap-type ;; :wrap, :no-wrap -;; :layout-padding-type ;; :simple, :multiple -;; :layout-padding ;; {:p1 num :p2 num :p3 num :p4 num} number could be negative - -;; ITEMS -;; :layout-margin ;; {:m1 0 :m2 0 :m3 0 :m4 0} -;; :layout-margin-type ;; :simple :multiple -;; :layout-h-behavior ;; :fill :fix :auto -;; :layout-v-behavior ;; :fill :fix :auto -;; :layout-max-h ;; num -;; :layout-min-h ;; num -;; :layout-max-w ;; num -;; :layout-min-w - -(defn col? - [{:keys [layout-flex-dir]}] - (or (= :column layout-flex-dir) (= :reverse-column layout-flex-dir))) - -(defn row? - [{:keys [layout-flex-dir]}] - (or (= :row layout-flex-dir) (= :reverse-row layout-flex-dir))) - -(defn h-start? - [{:keys [layout-align-items layout-justify-content] :as shape}] - (or (and (col? shape) - (= layout-align-items :start)) - (and (row? shape) - (= layout-justify-content :start)))) - -(defn h-center? - [{:keys [layout-align-items layout-justify-content] :as shape}] - (or (and (col? shape) - (= layout-align-items :center)) - (and (row? shape) - (= layout-justify-content :center)))) - -(defn h-end? - [{:keys [layout-align-items layout-justify-content] :as shape}] - (or (and (col? shape) - (= layout-align-items :end)) - (and (row? shape) - (= layout-justify-content :end)))) - -(defn v-start? - [{:keys [layout-align-items layout-justify-content] :as shape}] - (or (and (row? shape) - (= layout-align-items :start)) - (and (col? shape) - (= layout-justify-content :start)))) - -(defn v-center? - [{:keys [layout-align-items layout-justify-content] :as shape}] - (or (and (row? shape) - (= layout-align-items :center)) - (and (col? shape) - (= layout-justify-content :center)))) - -(defn v-end? - [{:keys [layout-align-items layout-justify-content] :as shape}] - (or (and (row? shape) - (= layout-align-items :end)) - (and (col? shape) - (= layout-justify-content :end)))) - -(defn gaps - [{:keys [layout-gap layout-gap-type]}] - (let [layout-gap-row (or (-> layout-gap :row-gap) 0) - layout-gap-col (if (= layout-gap-type :simple) - layout-gap-row - (or (-> layout-gap :column-gap) 0))] - [layout-gap-row layout-gap-col])) - -(defn calc-layout-lines - "Calculates the lines basic data and accumulated values. The positions will be calculated in a different operation" - [{:keys [layout-wrap-type] :as parent} children layout-bounds] - - (let [wrap? (= layout-wrap-type :wrap) - col? (col? parent) - row? (row? parent) - - [layout-gap-row layout-gap-col] (gaps parent) - - layout-width (gpo/width-points layout-bounds) - layout-height (gpo/height-points layout-bounds) - - reduce-fn - (fn [[{:keys [line-width line-height num-children line-fill? child-fill? num-child-fill] :as line-data} result] child] - (let [child-bounds (gst/parent-coords-points child parent) - child-width (gpo/width-points child-bounds) - child-height (gpo/height-points child-bounds) - - cur-child-fill? - (or (and row? (= :fill (:layout-h-behavior child))) - (and col? (= :fill (:layout-v-behavior child)))) - - cur-line-fill? - (or (and col? (= :fill (:layout-h-behavior child))) - (and row? (= :fill (:layout-v-behavior child)))) - - ;; TODO LAYOUT: ADD MINWIDTH/HEIGHT - next-width (if (or (and row? cur-child-fill?) - (and col? cur-line-fill?)) - 0 - child-width) - - next-height (if (or (and col? cur-child-fill?) - (and row? cur-line-fill?)) - 0 - child-height) - - next-total-width (+ line-width next-width (* layout-gap-row (dec num-children))) - next-total-height (+ line-height next-height (* layout-gap-col (dec num-children)))] - - (if (and (some? line-data) - (or (not wrap?) - (and row? (<= next-total-width layout-width)) - (and col? (<= next-total-height layout-height)))) - - ;; When :fill we add min width (0 by default) - [{:line-width (if row? (+ line-width next-width) (max line-width next-width)) - :line-height (if col? (+ 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? 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)] - - (cond-> layout-lines (some? line-data) (conj line-data)))) - -(defn calc-layout-lines-position - [{:keys [layout-justify-content] :as parent} layout-bounds layout-lines] - - (let [layout-width (gpo/width-points layout-bounds) - layout-height (gpo/height-points layout-bounds) - [layout-gap-row layout-gap-col] (gaps parent) - - row? (row? parent) - col? (col? parent) - space-between? (= layout-justify-content :space-between) - space-around? (= layout-justify-content :space-around) - h-center? (h-center? parent) - h-end? (h-end? parent) - v-center? (v-center? parent) - v-end? (v-end? parent)] - - (letfn [;; short version to not repeat always with all arguments - (xv [val] - (gpo/start-hv layout-bounds val)) - - ;; short version to not repeat always with all arguments - (yv [val] - (gpo/start-vv layout-bounds val)) - - (get-base-line - [total-width total-height] - - (cond-> (gpo/origin layout-bounds) - (and col? h-center?) - (gpt/add (xv (/ (- layout-width total-width) 2))) - - (and col? h-end?) - (gpt/add (xv (- layout-width total-width))) - - (and row? v-center?) - (gpt/add (yv (/ (- layout-height total-height) 2))) - - (and row? v-end?) - (gpt/add (yv (- layout-height total-height))))) - - (get-start-line - [{:keys [line-width line-height num-children child-fill?]} base-p] - - (let [children-gap-width (* layout-gap-row (dec num-children)) - children-gap-height (* layout-gap-col (dec num-children)) - - line-width (if (and row? child-fill?) - (- layout-width (* layout-gap-row (dec num-children))) - line-width) - - line-height (if (and col? child-fill?) - (- layout-height (* layout-gap-col (dec num-children))) - line-height) - - start-p - (cond-> base-p - ;; X AXIS - (and row? h-center? (not space-around?) (not space-between?)) - (-> (gpt/add (xv (/ layout-width 2))) - (gpt/subtract (xv (/ (+ line-width children-gap-width) 2)))) - - (and row? h-end? (not space-around?) (not space-between?)) - (-> (gpt/add (xv layout-width)) - (gpt/subtract (xv (+ line-width children-gap-width)))) - - (and col? h-center?) - (gpt/add (xv (/ line-width 2))) - - (and col? h-end?) - (gpt/add (xv line-width)) - - ;; Y AXIS - (and col? v-center? (not space-around?) (not space-between?)) - (-> (gpt/add (yv (/ layout-height 2))) - (gpt/subtract (yv (/ (+ line-height children-gap-height) 2)))) - - (and col? v-end? (not space-around?) (not space-between?)) - (-> (gpt/add (yv layout-height)) - (gpt/subtract (yv (+ line-height children-gap-height)))) - - (and row? v-center?) - (gpt/add (yv (/ line-height 2))) - - (and row? v-end?) - (gpt/add (yv line-height)))] - - start-p)) - - (get-next-line - [{:keys [line-width line-height]} base-p] - - (cond-> base-p - col? - (gpt/add (xv (+ line-width layout-gap-row))) - - row? - (gpt/add (yv (+ line-height layout-gap-col))))) - - (add-lines [[total-width total-height] {:keys [line-width line-height]}] - [(+ total-width line-width) - (+ total-height line-height)]) - - (add-starts [[result base-p] layout-line] - (let [start-p (get-start-line layout-line base-p) - next-p (get-next-line layout-line base-p)] - [(conj result - (assoc layout-line :start-p start-p)) - next-p]))] - - (let [[total-width total-height] (->> layout-lines (reduce add-lines [0 0])) - - total-width (+ total-width (* layout-gap-row (dec (count layout-lines)))) - total-height (+ total-height (* layout-gap-col (dec (count layout-lines)))) - - vertical-fill-space (- layout-height total-height) - - horizontal-fill-space (- layout-width total-width) - num-line-fill (count (->> layout-lines (filter :line-fill?))) - - layout-lines - (->> layout-lines - (mapv #(cond-> % - (and row? (:line-fill? %)) - (update :line-height + (/ vertical-fill-space num-line-fill)) - - (and col? (:line-fill? %)) - (update :line-width + (/ horizontal-fill-space num-line-fill))))) - - total-width (if (and col? (> num-line-fill 0)) layout-width total-width) - total-height (if (and row? (> num-line-fill 0)) layout-height total-height) - - base-p (get-base-line total-width total-height) - - [layout-lines _ _ _ _] - (reduce add-starts [[] base-p] layout-lines)] - layout-lines)))) - -(defn calc-layout-line-data - "Calculates the baseline for a flex layout" - [{:keys [layout-justify-content] :as shape} - layout-bounds - {:keys [num-children line-width line-height] :as line-data}] - - (let [width (gpo/width-points layout-bounds) - height (gpo/height-points layout-bounds) - - row? (row? shape) - col? (col? shape) - space-between? (= layout-justify-content :space-between) - space-around? (= layout-justify-content :space-around) - - [layout-gap-row layout-gap-col] (gaps shape) - - layout-gap-row - (cond (and row? space-around?) - 0 - - (and row? space-between?) - (/ (- width line-width) (dec num-children)) - - :else - layout-gap-row) - - layout-gap-col - (cond (and col? space-around?) - 0 - - (and col? space-between?) - (/ (- height line-height) (dec num-children)) - - :else - layout-gap-col) - - margin-x - (if (and row? space-around?) - (/ (- width line-width) (inc num-children)) - 0) - - margin-y - (if (and col? space-around?) - (/ (- height line-height) (inc num-children)) - 0)] - - (assoc line-data - :layout-bounds layout-bounds - :layout-gap-row layout-gap-row - :layout-gap-col layout-gap-col - :margin-x margin-x - :margin-y margin-y))) - -(defn next-p - "Calculates the position for the current shape given the layout-data context" - [parent - child-width child-height - {:keys [start-p layout-gap-row layout-gap-col margin-x margin-y] :as layout-data}] - - (let [row? (row? parent) - col? (col? parent) - - h-center? (h-center? parent) - h-end? (h-end? parent) - v-center? (v-center? parent) - v-end? (v-end? parent) - points (:points parent) - - xv (partial gpo/start-hv points) - yv (partial gpo/start-vv points) - - corner-p - (cond-> start-p - (and col? h-center?) - (gpt/add (xv (- (/ child-width 2)))) - - (and col? h-end?) - (gpt/add (xv (- child-width))) - - (and row? v-center?) - (gpt/add (yv (- (/ child-height 2)))) - - (and row? v-end?) - (gpt/add (yv (- child-height))) - - (some? margin-x) - (gpt/add (xv margin-x)) - - (some? margin-y) - (gpt/add (yv margin-y))) - - next-p - (cond-> start-p - row? - (gpt/add (xv (+ child-width layout-gap-row))) - - col? - (gpt/add (yv (+ child-height layout-gap-col))) - - (some? margin-x) - (gpt/add (xv margin-x)) - - (some? margin-y) - (gpt/add (yv margin-y))) - - layout-data - (assoc layout-data :start-p next-p)] - - [corner-p layout-data])) - -(defn calc-fill-width-data - "Calculates the size and modifiers for the width of an auto-fill child" - [{:keys [transform transform-inverse] :as parent} - {:keys [layout-h-behavior] :as child} - child-origin child-width - {:keys [num-children line-width line-fill? child-fill? layout-bounds] :as layout-data}] - - (let [[layout-gap-row _] (gaps parent)] - (cond - (and (row? parent) (= :fill layout-h-behavior) child-fill?) - (let [layout-width (gpo/width-points layout-bounds) - fill-space (- layout-width line-width (* layout-gap-row (dec num-children))) - fill-width (/ fill-space (:num-child-fill layout-data)) - fill-scale (/ fill-width child-width)] - - {:width fill-width - :modifiers (ctm/resize (gpt/point fill-scale 1) child-origin transform transform-inverse)}) - - (and (col? parent) (= :fill layout-h-behavior) line-fill?) - (let [fill-scale (/ line-width child-width)] - {:width line-width - :modifiers (ctm/resize (gpt/point fill-scale 1) child-origin transform transform-inverse)})))) - -(defn calc-fill-height-data - "Calculates the size and modifiers for the height of an auto-fill child" - [{:keys [transform transform-inverse] :as parent} - {:keys [layout-v-behavior] :as child} - child-origin child-height - {:keys [num-children line-height layout-bounds line-fill? child-fill?] :as layout-data}] - - (let [[_ layout-gap-col] (gaps parent)] - (cond - (and (col? parent) (= :fill layout-v-behavior) child-fill?) - (let [layout-height (gpo/height-points layout-bounds) - fill-space (- layout-height line-height (* layout-gap-col (dec num-children))) - fill-height (/ fill-space (:num-child-fill layout-data)) - fill-scale (/ fill-height child-height)] - {:height fill-height - :modifiers (ctm/resize (gpt/point 1 fill-scale) child-origin transform transform-inverse)}) - - (and (row? parent) (= :fill layout-v-behavior) line-fill?) - (let [fill-scale (/ line-height child-height)] - {:height line-height - :modifiers (ctm/resize (gpt/point 1 fill-scale) child-origin transform transform-inverse)})))) - -(defn normalize-child-modifiers - "Apply the modifiers and then normalized them against the parent coordinates" - [parent child modifiers {:keys [transform transform-inverse] :as transformed-parent}] - - (let [transformed-child (gst/transform-shape child modifiers) - child-bb-before (gst/parent-coords-rect child parent) - child-bb-after (gst/parent-coords-rect transformed-child transformed-parent) - scale-x (/ (:width child-bb-before) (:width child-bb-after)) - scale-y (/ (:height child-bb-before) (:height child-bb-after)) - - resize-origin (-> transformed-parent :points first) ;; TODO LAYOUT: IS always the origin?n - resize-vector (gpt/point scale-x scale-y)] - (-> modifiers - (ctm/select-child-modifiers) - (ctm/set-resize resize-vector resize-origin transform transform-inverse)))) - -(defn calc-layout-data - "Digest the layout data to pass it to the constrains" - [{:keys [layout-flex-dir layout-padding layout-padding-type] :as parent} children] - - (let [;; Add padding to the bounds - {pad-top :p1 pad-right :p2 pad-bottom :p3 pad-left :p4} layout-padding - [pad-top pad-right pad-bottom pad-left] - (if (= layout-padding-type :multiple) - [pad-top pad-right pad-bottom pad-left] - [pad-top pad-top pad-top pad-top]) - - ;; Normalize the points to remove flips - points (gst/parent-coords-points parent parent) - - layout-bounds (gpo/pad-points points pad-top pad-right pad-bottom pad-left) - - ;; Reverse - reverse? (or (= :reverse-row layout-flex-dir) (= :reverse-column layout-flex-dir)) - children (cond->> children reverse? reverse) - - ;; Creates the layout lines information - layout-lines - (->> (calc-layout-lines parent children layout-bounds) - (calc-layout-lines-position parent layout-bounds) - (map (partial calc-layout-line-data parent layout-bounds)))] - - {:layout-lines layout-lines - :reverse? reverse?})) - -(defn calc-layout-modifiers - "Calculates the modifiers for the layout" - [parent child layout-line] - (let [child-bounds (gst/parent-coords-points child parent) - - child-origin (gpo/origin child-bounds) - child-width (gpo/width-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-height (calc-fill-height-data parent child child-origin child-height layout-line) - - child-width (or (:width fill-width) child-width) - child-height (or (:height fill-height) child-height) - - [corner-p layout-line] (next-p parent child-width child-height layout-line) - - move-vec (gpt/to-vec child-origin corner-p) - - modifiers - (-> (ctm/empty-modifiers) - (cond-> fill-width (ctm/add-modifiers (:modifiers fill-width))) - (cond-> fill-height (ctm/add-modifiers (:modifiers fill-height))) - (ctm/set-move move-vec))] - - [modifiers layout-line])) - - -(defn layout-drop-areas - [{:keys [margin-x margin-y] :as frame} layout-data children] - - (let [col? (col? frame) - row? (row? frame) - h-center? (and row? (h-center? frame)) - h-end? (and row? (h-end? frame)) - v-center? (and col? (v-center? frame)) - v-end? (and row? (v-end? frame)) - layout-gap-row (or (-> frame :layout-gap :row-gap) 0) - ;;layout-gap-col (or (-> frame :layout-gap :column-gap) 0) - layout-gap layout-gap-row ;; TODO LAYOUT: FIXME - reverse? (:reverse? layout-data) - - children (vec (cond->> (d/enumerate children) - reverse? reverse)) - - redfn-child - (fn [[result parent-rect prev-x prev-y] [[index child] next]] - (let [prev-x (or prev-x (:x parent-rect)) - prev-y (or prev-y (:y parent-rect)) - - last? (nil? next) - - start-p (gpt/point (:selrect child)) - start-p (-> start-p - (gmt/transform-point-center (gco/center-shape child) (:transform frame)) - (gmt/transform-point-center (gco/center-shape frame) (:transform-inverse frame))) - - box-x (:x start-p) - box-y (:y start-p) - box-width (-> child :selrect :width) - box-height (-> child :selrect :height) - - x (if col? (:x parent-rect) prev-x) - y (if row? (:y parent-rect) prev-y) - - width (cond - (and row? last?) - (- (+ (:x parent-rect) (:width parent-rect)) x) - - col? - (:width parent-rect) - - :else - (+ box-width (- box-x prev-x) (/ layout-gap 2))) - - height (cond - (and col? last?) - (- (+ (:y parent-rect) (:height parent-rect)) y) - - row? - (:height parent-rect) - - :else - (+ box-height (- box-y prev-y) (/ layout-gap 2))) - - [line-area-1 line-area-2] - (if row? - (let [half-point-width (+ (- box-x x) (/ box-width 2))] - [(-> (gsr/make-rect x y half-point-width height) - (assoc :index (if reverse? (inc index) index))) - (-> (gsr/make-rect (+ x half-point-width) y (- width half-point-width) height) - (assoc :index (if reverse? index (inc index))))]) - (let [half-point-height (+ (- box-y y) (/ box-height 2))] - [(-> (gsr/make-rect x y width half-point-height) - (assoc :index (if reverse? (inc index) index))) - (-> (gsr/make-rect x (+ y half-point-height) width (- height half-point-height)) - (assoc :index (if reverse? index (inc index))))])) - - result (conj result line-area-1 line-area-2) - - ;;line-area - ;;(-> (gsr/make-rect x y width height) - ;; (assoc :index (if reverse? (inc index) index))) - ;;result (conj result line-area) - ;;result (conj result (gsr/make-rect box-x box-y box-width box-height)) - ] - - [result parent-rect (+ x width) (+ y height)])) - - redfn-lines - (fn [[result from-idx prev-x prev-y] [{:keys [start-p layout-gap num-children line-width line-height]} next]] - (let [start-p (gmt/transform-point-center start-p (gco/center-shape frame) (:transform-inverse frame)) - - prev-x (or prev-x (:x frame)) - prev-y (or prev-y (:y frame)) - last? (nil? next) - - line-width - (if row? - (:width frame) - (+ line-width margin-x - (if row? (* layout-gap (dec num-children)) 0))) - - line-height - (if col? - (:height frame) - (+ line-height margin-y - (if col? - (* layout-gap (dec num-children)) - 0))) - - box-x - (- (:x start-p) - (cond - h-center? (/ line-width 2) - h-end? line-width - :else 0)) - - box-y - (- (:y start-p) - (cond - v-center? (/ line-height 2) - v-end? line-height - :else 0)) - - x (if row? (:x frame) prev-x) - y (if col? (:y frame) prev-y) - - width (cond - (and col? last?) - (- (+ (:x frame) (:width frame)) x) - - row? - (:width frame) - - :else - (+ line-width (- box-x prev-x) (/ layout-gap 2))) - - height (cond - (and row? last?) - (- (+ (:y frame) (:height frame)) y) - - col? - (:height frame) - - :else - (+ line-height (- box-y prev-y) (/ layout-gap 2))) - - line-area (gsr/make-rect x y width height) - - children (subvec children from-idx (+ from-idx num-children)) - - - ;; To debug the lines - ;;result (conj result line-area) - - result (first (reduce redfn-child [result line-area] (d/with-next children)))] - - [result (+ from-idx num-children) (+ x width) (+ y height)]))] - - (first (reduce redfn-lines [[] 0] (d/with-next (:layout-lines layout-data)))))) - -(defn get-drop-index - [frame-id objects position] - (let [frame (get objects frame-id) - position (gmt/transform-point-center position (gco/center-shape frame) (:transform-inverse frame)) - children (cph/get-immediate-children objects frame-id) - layout-data (calc-layout-data frame children) - drop-areas (layout-drop-areas frame layout-data children) - area (d/seek #(gsr/contains-point? % position) drop-areas)] - (:index area))) + [app.common.data.macros :as dm] + [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.modifiers :as fmo])) + +(dm/export fli/calc-layout-data) +(dm/export fmo/normalize-child-modifiers) +(dm/export fmo/calc-layout-modifiers) +(dm/export fdr/layout-drop-areas) +(dm/export fdr/get-drop-index) diff --git a/common/src/app/common/geom/shapes/flex_layout/drop_area.cljc b/common/src/app/common/geom/shapes/flex_layout/drop_area.cljc new file mode 100644 index 000000000..228e09b13 --- /dev/null +++ b/common/src/app/common/geom/shapes/flex_layout/drop_area.cljc @@ -0,0 +1,179 @@ +;; 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.drop-area + (: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.flex-layout.lines :as fli] + [app.common.geom.shapes.rect :as gsr] + [app.common.pages.helpers :as cph] + [app.common.types.shape.layout :as ctl])) + +(defn layout-drop-areas + [{:keys [margin-x margin-y] :as frame} layout-data children] + + (let [col? (ctl/col? frame) + row? (ctl/row? frame) + h-center? (and row? (ctl/h-center? frame)) + h-end? (and row? (ctl/h-end? frame)) + v-center? (and col? (ctl/v-center? frame)) + v-end? (and row? (ctl/v-end? frame)) + reverse? (:reverse? layout-data) + + [layout-gap-row layout-gap-col] (ctl/gaps frame) + + children (vec (cond->> (d/enumerate children) + reverse? reverse)) + + redfn-child + (fn [[result parent-rect prev-x prev-y] [[index child] next]] + (let [prev-x (or prev-x (:x parent-rect)) + prev-y (or prev-y (:y parent-rect)) + + last? (nil? next) + + start-p (gpt/point (:selrect child)) + start-p (-> start-p + (gmt/transform-point-center (gco/center-shape child) (:transform frame)) + (gmt/transform-point-center (gco/center-shape frame) (:transform-inverse frame))) + + box-x (:x start-p) + box-y (:y start-p) + box-width (-> child :selrect :width) + box-height (-> child :selrect :height) + + x (if col? (:x parent-rect) prev-x) + y (if row? (:y parent-rect) prev-y) + + width (cond + (and row? last?) + (- (+ (:x parent-rect) (:width parent-rect)) x) + + col? + (:width parent-rect) + + :else + (+ box-width (- box-x prev-x) (/ layout-gap-row 2))) + + height (cond + (and col? last?) + (- (+ (:y parent-rect) (:height parent-rect)) y) + + row? + (:height parent-rect) + + :else + (+ box-height (- box-y prev-y) (/ layout-gap-col 2))) + + [line-area-1 line-area-2] + (if row? + (let [half-point-width (+ (- box-x x) (/ box-width 2))] + [(-> (gsr/make-rect x y half-point-width height) + (assoc :index (if reverse? (inc index) index))) + (-> (gsr/make-rect (+ x half-point-width) y (- width half-point-width) height) + (assoc :index (if reverse? index (inc index))))]) + (let [half-point-height (+ (- box-y y) (/ box-height 2))] + [(-> (gsr/make-rect x y width half-point-height) + (assoc :index (if reverse? (inc index) index))) + (-> (gsr/make-rect x (+ y half-point-height) width (- height half-point-height)) + (assoc :index (if reverse? index (inc index))))])) + + result (conj result line-area-1 line-area-2) + + ;;line-area + ;;(-> (gsr/make-rect x y width height) + ;; (assoc :index (if reverse? (inc index) index))) + ;;result (conj result line-area) + ;;result (conj result (gsr/make-rect box-x box-y box-width box-height)) + ] + + [result parent-rect (+ x width) (+ y height)])) + + redfn-lines + (fn [[result from-idx prev-x prev-y] [{:keys [start-p layout-gap-row layout-gap-col num-children line-width line-height]} next]] + (let [start-p (gmt/transform-point-center start-p (gco/center-shape frame) (:transform-inverse frame)) + + prev-x (or prev-x (:x frame)) + prev-y (or prev-y (:y frame)) + last? (nil? next) + + line-width + (if row? + (:width frame) + (+ line-width margin-x + (if row? (* layout-gap-row (dec num-children)) 0))) + + line-height + (if col? + (:height frame) + (+ line-height margin-y + (if col? + (* layout-gap-col (dec num-children)) + 0))) + + box-x + (- (:x start-p) + (cond + h-center? (/ line-width 2) + h-end? line-width + :else 0)) + + box-y + (- (:y start-p) + (cond + v-center? (/ line-height 2) + v-end? line-height + :else 0)) + + x (if row? (:x frame) prev-x) + y (if col? (:y frame) prev-y) + + width (cond + (and col? last?) + (- (+ (:x frame) (:width frame)) x) + + row? + (:width frame) + + :else + (+ line-width (- box-x prev-x) (/ layout-gap-row 2))) + + height (cond + (and row? last?) + (- (+ (:y frame) (:height frame)) y) + + col? + (:height frame) + + :else + (+ line-height (- box-y prev-y) (/ layout-gap-col 2))) + + line-area (gsr/make-rect x y width height) + + children (subvec children from-idx (+ from-idx num-children)) + + + ;; To debug the lines + ;;result (conj result line-area) + + result (first (reduce redfn-child [result line-area] (d/with-next children)))] + + [result (+ from-idx num-children) (+ x width) (+ y height)]))] + + (first (reduce redfn-lines [[] 0] (d/with-next (:layout-lines layout-data)))))) + +(defn get-drop-index + [frame-id objects position] + (let [frame (get objects frame-id) + position (gmt/transform-point-center position (gco/center-shape frame) (:transform-inverse frame)) + children (cph/get-immediate-children objects frame-id) + layout-data (fli/calc-layout-data frame children) + drop-areas (layout-drop-areas frame layout-data children) + area (d/seek #(gsr/contains-point? % position) drop-areas)] + (:index area))) diff --git a/common/src/app/common/geom/shapes/flex_layout/lines.cljc b/common/src/app/common/geom/shapes/flex_layout/lines.cljc new file mode 100644 index 000000000..a1e5cc3c4 --- /dev/null +++ b/common/src/app/common/geom/shapes/flex_layout/lines.cljc @@ -0,0 +1,309 @@ +;; 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.lines + (:require + [app.common.geom.point :as gpt] + [app.common.geom.shapes.points :as gpo] + [app.common.geom.shapes.transforms :as gst] + [app.common.types.shape.layout :as ctl])) + +(defn layout-bounds + [{:keys [layout-padding layout-padding-type] :as shape}] + (let [;; Add padding to the bounds + {pad-top :p1 pad-right :p2 pad-bottom :p3 pad-left :p4} layout-padding + [pad-top pad-right pad-bottom pad-left] + (if (= layout-padding-type :multiple) + [pad-top pad-right pad-bottom pad-left] + [pad-top pad-top pad-top pad-top]) + + ;; Normalize the points to remove flips + ;; TODO LAYOUT: Need function to normalize the points + points (gst/parent-coords-points shape shape)] + + (gpo/pad-points points pad-top pad-right pad-bottom pad-left))) + +(defn init-layout-lines + "Calculates the lines basic data and accumulated values. The positions will be calculated in a different operation" + [shape children layout-bounds] + + (let [wrap? (ctl/wrap? shape) + col? (ctl/col? shape) + row? (ctl/row? shape) + + [layout-gap-row layout-gap-col] (ctl/gaps shape) + layout-width (gpo/width-points layout-bounds) + layout-height (gpo/height-points layout-bounds) + + reduce-fn + (fn [[{:keys [line-width line-height num-children line-fill? child-fill? num-child-fill] :as line-data} result] child] + (let [child-bounds (gst/parent-coords-points child shape) + child-width (gpo/width-points child-bounds) + child-height (gpo/height-points child-bounds) + child-min-width (ctl/child-min-width child) + child-min-height (ctl/child-min-height child) + + fill-width? (ctl/fill-width? child) + fill-height? (ctl/fill-height? child) + + cur-child-fill? (or (and row? fill-width?) (and col? fill-height?)) + cur-line-fill? (or (and col? fill-width?) (and row? fill-height?)) + + next-width (if fill-width? child-min-width child-width) + next-height (if fill-height? child-min-height child-height) + + next-line-width (+ line-width next-width (* layout-gap-row (dec num-children))) + next-line-height (+ line-height next-height (* layout-gap-col (dec num-children)))] + + (if (and (some? line-data) + (or (not wrap?) + (and row? (<= next-line-width layout-width)) + (and col? (<= next-line-height layout-height)))) + + [{:line-width (if row? (+ line-width next-width) (max line-width next-width)) + :line-height (if col? (+ 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? 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)] + + (cond-> layout-lines (some? line-data) (conj line-data)))) + +(defn get-base-line + [parent layout-bounds total-width total-height] + + (let [layout-width (gpo/width-points layout-bounds) + layout-height (gpo/height-points layout-bounds) + row? (ctl/row? parent) + col? (ctl/col? parent) + h-center? (ctl/h-center? parent) + h-end? (ctl/h-end? parent) + v-center? (ctl/v-center? parent) + v-end? (ctl/v-end? parent) + hv (partial gpo/start-hv layout-bounds) + vv (partial gpo/start-vv layout-bounds)] + + (cond-> (gpo/origin layout-bounds) + (and col? h-center?) + (gpt/add (hv (/ (- layout-width total-width) 2))) + + (and col? h-end?) + (gpt/add (hv (- layout-width total-width))) + + (and row? v-center?) + (gpt/add (vv (/ (- layout-height total-height) 2))) + + (and row? v-end?) + (gpt/add (vv (- layout-height total-height)))))) + +(defn get-next-line + [parent layout-bounds {:keys [line-width line-height]} base-p] + + (let [row? (ctl/row? parent) + col? (ctl/col? parent) + + [layout-gap-row layout-gap-col] (ctl/gaps parent) + + hv #(gpo/start-hv layout-bounds %) + vv #(gpo/start-vv layout-bounds %)] + + (cond-> base-p + col? + (gpt/add (hv (+ line-width layout-gap-row))) + + row? + (gpt/add (vv (+ line-height layout-gap-col)))))) + +(defn get-start-line + [parent layout-bounds {:keys [line-width line-height num-children child-fill? ]} base-p] + + (let [layout-width (gpo/width-points layout-bounds) + layout-height (gpo/height-points layout-bounds) + [layout-gap-row layout-gap-col] (ctl/gaps parent) + + row? (ctl/row? parent) + col? (ctl/col? parent) + space-between? (ctl/space-between? parent) + space-around? (ctl/space-around? parent) + h-center? (ctl/h-center? parent) + h-end? (ctl/h-end? parent) + v-center? (ctl/v-center? parent) + v-end? (ctl/v-end? parent) + + hv #(gpo/start-hv layout-bounds %) + vv #(gpo/start-vv layout-bounds %) + + children-gap-width (* layout-gap-row (dec num-children)) + children-gap-height (* layout-gap-col (dec num-children)) + + line-width (if (and row? child-fill?) + (- layout-width (* layout-gap-row (dec num-children))) + line-width) + + line-height (if (and col? child-fill?) + (- layout-height (* layout-gap-col (dec num-children))) + line-height) + + start-p + (cond-> base-p + ;; X AXIS + (and row? h-center? (not space-around?) (not space-between?)) + (-> (gpt/add (hv (/ layout-width 2))) + (gpt/subtract (hv (/ (+ line-width children-gap-width) 2)))) + + (and row? h-end? (not space-around?) (not space-between?)) + (-> (gpt/add (hv layout-width)) + (gpt/subtract (hv (+ line-width children-gap-width)))) + + (and col? h-center?) + (gpt/add (hv (/ line-width 2))) + + (and col? h-end?) + (gpt/add (hv line-width)) + + ;; Y AXIS + (and col? v-center? (not space-around?) (not space-between?)) + (-> (gpt/add (vv (/ layout-height 2))) + (gpt/subtract (vv (/ (+ line-height children-gap-height) 2)))) + + (and col? v-end? (not space-around?) (not space-between?)) + (-> (gpt/add (vv layout-height)) + (gpt/subtract (vv (+ line-height children-gap-height)))) + + (and row? v-center?) + (gpt/add (vv (/ line-height 2))) + + (and row? v-end?) + (gpt/add (vv line-height)))] + + start-p)) + + +(defn add-lines-positions + [parent layout-bounds layout-lines] + + (let [layout-width (gpo/width-points layout-bounds) + layout-height (gpo/height-points layout-bounds) + [layout-gap-row layout-gap-col] (ctl/gaps parent) + + row? (ctl/row? parent) + col? (ctl/col? parent)] + + (letfn [(add-lines [[total-width total-height] {:keys [line-width line-height]}] + [(+ total-width line-width) + (+ total-height line-height)]) + + (add-starts [[result base-p] layout-line] + (let [start-p (get-start-line parent layout-bounds layout-line base-p) + next-p (get-next-line parent layout-bounds layout-line base-p)] + + [(conj result + (assoc layout-line :start-p start-p)) + next-p]))] + + (let [[total-width total-height] (->> layout-lines (reduce add-lines [0 0])) + + total-width (+ total-width (* layout-gap-row (dec (count layout-lines)))) + total-height (+ total-height (* layout-gap-col (dec (count layout-lines)))) + + vertical-fill-space (- layout-height total-height) + horizontal-fill-space (- layout-width total-width) + + num-line-fill (count (->> layout-lines (filter :line-fill?))) + + layout-lines + (->> layout-lines + (mapv #(cond-> % + (and row? (:line-fill? %)) + (update :line-height + (/ vertical-fill-space num-line-fill)) + + (and col? (:line-fill? %)) + (update :line-width + (/ horizontal-fill-space num-line-fill))))) + + total-width (if (and col? (> num-line-fill 0)) layout-width total-width) + total-height (if (and row? (> num-line-fill 0)) layout-height total-height) + + base-p (get-base-line parent layout-bounds total-width total-height)] + + (first (reduce add-starts [[] base-p] layout-lines)))))) + +(defn add-line-spacing + "Calculates the baseline for a flex layout" + [shape layout-bounds {:keys [num-children line-width line-height] :as line-data}] + + (let [width (gpo/width-points layout-bounds) + height (gpo/height-points layout-bounds) + + row? (ctl/row? shape) + col? (ctl/col? shape) + space-between? (ctl/space-between? shape) + space-around? (ctl/space-around? shape) + + [layout-gap-row layout-gap-col] (ctl/gaps shape) + + layout-gap-row + (cond (and row? space-around?) + 0 + + (and row? space-between?) + (/ (- width line-width) (dec num-children)) + + :else + layout-gap-row) + + layout-gap-col + (cond (and col? space-around?) + 0 + + (and col? space-between?) + (/ (- height line-height) (dec num-children)) + + :else + layout-gap-col) + + margin-x + (if (and row? space-around?) + (/ (- width line-width) (inc num-children)) + 0) + + margin-y + (if (and col? space-around?) + (/ (- height line-height) (inc num-children)) + 0)] + (assoc line-data + :layout-bounds layout-bounds + :layout-gap-row layout-gap-row + :layout-gap-col layout-gap-col + :margin-x margin-x + :margin-y margin-y))) + +(defn calc-layout-data + "Digest the layout data to pass it to the constrains" + [shape children] + + (let [layout-bounds (layout-bounds shape) + reverse? (ctl/reverse? shape) + children (cond->> children reverse? reverse) + + ;; Creates the layout lines information + layout-lines + (->> (init-layout-lines shape children layout-bounds) + (add-lines-positions shape layout-bounds) + (mapv (partial add-line-spacing shape layout-bounds)))] + + {:layout-lines layout-lines + :reverse? reverse?})) diff --git a/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc b/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc new file mode 100644 index 000000000..4343960d0 --- /dev/null +++ b/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc @@ -0,0 +1,103 @@ +;; 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.modifiers + (:require + [app.common.geom.point :as gpt] + [app.common.geom.shapes.flex-layout.positions :as fpo] + [app.common.geom.shapes.points :as gpo] + [app.common.geom.shapes.transforms :as gst] + [app.common.types.modifiers :as ctm] + [app.common.types.shape.layout :as ctl])) + + +(defn normalize-child-modifiers + "Apply the modifiers and then normalized them against the parent coordinates" + [parent child modifiers {:keys [transform transform-inverse] :as transformed-parent}] + + (let [transformed-child (gst/transform-shape child modifiers) + child-bb-before (gst/parent-coords-rect child parent) + child-bb-after (gst/parent-coords-rect transformed-child transformed-parent) + scale-x (/ (:width child-bb-before) (:width child-bb-after)) + scale-y (/ (:height child-bb-before) (:height child-bb-after)) + + resize-origin (-> transformed-parent :points first) ;; TODO LAYOUT: IS always the origin?n + resize-vector (gpt/point scale-x scale-y)] + (-> modifiers + (ctm/select-child-modifiers) + (ctm/set-resize resize-vector resize-origin transform transform-inverse)))) + +(defn calc-fill-width-data + "Calculates the size and modifiers for the width of an auto-fill child" + [{:keys [transform transform-inverse] :as parent} + {:keys [layout-h-behavior] :as child} + child-origin child-width + {:keys [num-children line-width line-fill? child-fill? layout-bounds] :as layout-data}] + + (let [[layout-gap-row _] (ctl/gaps parent)] + (cond + (and (ctl/row? parent) (= :fill layout-h-behavior) child-fill?) + (let [layout-width (gpo/width-points layout-bounds) + fill-space (- layout-width line-width (* layout-gap-row (dec num-children))) + fill-width (/ fill-space (:num-child-fill layout-data)) + fill-scale (/ fill-width child-width)] + + {:width fill-width + :modifiers (ctm/resize (gpt/point fill-scale 1) child-origin transform transform-inverse)}) + + (and (ctl/col? parent) (= :fill layout-h-behavior) line-fill?) + (let [fill-scale (/ line-width child-width)] + {:width line-width + :modifiers (ctm/resize (gpt/point fill-scale 1) child-origin transform transform-inverse)})))) + +(defn calc-fill-height-data + "Calculates the size and modifiers for the height of an auto-fill child" + [{:keys [transform transform-inverse] :as parent} + {:keys [layout-v-behavior] :as child} + child-origin child-height + {:keys [num-children line-height layout-bounds line-fill? child-fill?] :as layout-data}] + + (let [[_ layout-gap-col] (ctl/gaps parent)] + (cond + (and (ctl/col? parent) (= :fill layout-v-behavior) child-fill?) + (let [layout-height (gpo/height-points layout-bounds) + fill-space (- layout-height line-height (* layout-gap-col (dec num-children))) + fill-height (/ fill-space (:num-child-fill layout-data)) + fill-scale (/ fill-height child-height)] + {:height fill-height + :modifiers (ctm/resize (gpt/point 1 fill-scale) child-origin transform transform-inverse)}) + + (and (ctl/row? parent) (= :fill layout-v-behavior) line-fill?) + (let [fill-scale (/ line-height child-height)] + {:height line-height + :modifiers (ctm/resize (gpt/point 1 fill-scale) child-origin transform transform-inverse)})))) + +(defn calc-layout-modifiers + "Calculates the modifiers for the layout" + [parent child layout-line] + (let [child-bounds (gst/parent-coords-points child parent) + + child-origin (gpo/origin child-bounds) + child-width (gpo/width-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-height (calc-fill-height-data parent child child-origin child-height layout-line) + + child-width (or (:width fill-width) child-width) + child-height (or (:height fill-height) child-height) + + [corner-p layout-line] (fpo/get-child-position parent child-width child-height layout-line) + + move-vec (gpt/to-vec child-origin corner-p) + + modifiers + (-> (ctm/empty-modifiers) + (cond-> fill-width (ctm/add-modifiers (:modifiers fill-width))) + (cond-> fill-height (ctm/add-modifiers (:modifiers fill-height))) + (ctm/set-move move-vec))] + + [modifiers layout-line])) diff --git a/common/src/app/common/geom/shapes/flex_layout/positions.cljc b/common/src/app/common/geom/shapes/flex_layout/positions.cljc new file mode 100644 index 000000000..e230da22e --- /dev/null +++ b/common/src/app/common/geom/shapes/flex_layout/positions.cljc @@ -0,0 +1,68 @@ +;; 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.positions + (:require + [app.common.geom.point :as gpt] + [app.common.geom.shapes.points :as gpo] + [app.common.types.shape.layout :as ctl])) + +(defn get-child-position + "Calculates the position for the current shape given the layout-data context" + [parent + child-width child-height + {:keys [start-p layout-gap-row layout-gap-col margin-x margin-y] :as layout-data}] + + (let [row? (ctl/row? parent) + col? (ctl/col? parent) + + h-center? (ctl/h-center? parent) + h-end? (ctl/h-end? parent) + v-center? (ctl/v-center? parent) + v-end? (ctl/v-end? parent) + points (:points parent) + + hv (partial gpo/start-hv points) + vv (partial gpo/start-vv points) + + corner-p + (cond-> start-p + (and col? h-center?) + (gpt/add (hv (- (/ child-width 2)))) + + (and col? h-end?) + (gpt/add (hv (- child-width))) + + (and row? v-center?) + (gpt/add (vv (- (/ child-height 2)))) + + (and row? v-end?) + (gpt/add (vv (- child-height))) + + (some? margin-x) + (gpt/add (hv margin-x)) + + (some? margin-y) + (gpt/add (vv margin-y))) + + next-p + (cond-> start-p + row? + (gpt/add (hv (+ child-width layout-gap-row))) + + col? + (gpt/add (vv (+ child-height layout-gap-col))) + + (some? margin-x) + (gpt/add (hv margin-x)) + + (some? margin-y) + (gpt/add (vv margin-y))) + + layout-data + (assoc layout-data :start-p next-p)] + + [corner-p layout-data])) diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 498df01ec..b25e3cb27 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -9,6 +9,27 @@ [app.common.spec :as us] [clojure.spec.alpha :as s])) +;; :layout ;; :flex, :grid in the future +;; :layout-flex-dir ;; :row, :reverse-row, :column, :reverse-column +;; :layout-gap-type ;; :simple, :multiple +;; :layout-gap ;; {:row-gap number , :column-gap number} +;; :layout-align-items ;; :start :end :center :strech +;; :layout-justify-content ;; :start :center :end :space-between :space-around +;; :layout-align-content ;; :start :center :end :space-between :space-around :strech (by default) +;; :layout-wrap-type ;; :wrap, :no-wrap +;; :layout-padding-type ;; :simple, :multiple +;; :layout-padding ;; {:p1 num :p2 num :p3 num :p4 num} number could be negative + +;; ITEMS +;; :layout-margin ;; {:m1 0 :m2 0 :m3 0 :m4 0} +;; :layout-margin-type ;; :simple :multiple +;; :layout-h-behavior ;; :fill :fix :auto +;; :layout-v-behavior ;; :fill :fix :auto +;; :layout-max-h ;; num +;; :layout-min-h ;; num +;; :layout-max-w ;; num +;; :layout-min-w + (s/def ::layout #{:flex :grid}) (s/def ::layout-flex-dir #{:row :reverse-row :column :reverse-column}) (s/def ::layout-gap-type #{:simple :multiple}) @@ -75,3 +96,111 @@ ::layout-max-w ::layout-min-w ::layout-align-self])) + + +(defn wrap? [{:keys [layout-wrap-type]}] + (= layout-wrap-type :wrap)) + +(defn fill-width? [child] + (= :fill (:layout-h-behavior child))) + +(defn fill-height? [child] + (= :fill (:layout-v-behavior child))) + +(defn col? + [{:keys [layout-flex-dir]}] + (or (= :column layout-flex-dir) (= :reverse-column layout-flex-dir))) + +(defn row? + [{:keys [layout-flex-dir]}] + (or (= :row layout-flex-dir) (= :reverse-row layout-flex-dir))) + +(defn gaps + [{:keys [layout-gap layout-gap-type]}] + (let [layout-gap-row (or (-> layout-gap :row-gap) 0) + layout-gap-col (if (= layout-gap-type :simple) + layout-gap-row + (or (-> layout-gap :column-gap) 0))] + [layout-gap-row layout-gap-col])) + +(defn child-min-width + [child] + (if (and (fill-width? child) + (some? (:layout-min-h child))) + (max 0 (:layout-min-h child)) + 0)) + +(defn child-max-width + [child] + (if (and (fill-width? child) + (some? (:layout-min-h child))) + (max 0 (:layout-min-h child)) + 0)) + +(defn child-min-height + [child] + (if (and (fill-width? child) + (some? (:layout-min-v child))) + (max 0 (:layout-min-v child)) + 0)) + +(defn child-max-height + [child] + (if (and (fill-width? child) + (some? (:layout-min-v child))) + (max 0 (:layout-min-v child)) + 0)) + +(defn h-start? + [{:keys [layout-align-items layout-justify-content] :as shape}] + (or (and (col? shape) + (= layout-align-items :start)) + (and (row? shape) + (= layout-justify-content :start)))) + +(defn h-center? + [{:keys [layout-align-items layout-justify-content] :as shape}] + (or (and (col? shape) + (= layout-align-items :center)) + (and (row? shape) + (= layout-justify-content :center)))) + +(defn h-end? + [{:keys [layout-align-items layout-justify-content] :as shape}] + (or (and (col? shape) + (= layout-align-items :end)) + (and (row? shape) + (= layout-justify-content :end)))) + +(defn v-start? + [{:keys [layout-align-items layout-justify-content] :as shape}] + (or (and (row? shape) + (= layout-align-items :start)) + (and (col? shape) + (= layout-justify-content :start)))) + +(defn v-center? + [{:keys [layout-align-items layout-justify-content] :as shape}] + (or (and (row? shape) + (= layout-align-items :center)) + (and (col? shape) + (= layout-justify-content :center)))) + +(defn v-end? + [{:keys [layout-align-items layout-justify-content] :as shape}] + (or (and (row? shape) + (= layout-align-items :end)) + (and (col? shape) + (= layout-justify-content :end)))) +(defn reverse? + [{:keys [layout-flex-dir]}] + (or (= :reverse-row layout-flex-dir) + (= :reverse-column layout-flex-dir))) + +(defn space-between? + [{:keys [layout-justify-content]}] + (= layout-justify-content :space-between)) + +(defn space-around? + [{:keys [layout-justify-content]}] + (= layout-justify-content :space-around)) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options.cljs b/frontend/src/app/main/ui/workspace/sidebar/options.cljs index 1a0faed46..5024d3dd9 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options.cljs @@ -7,7 +7,6 @@ (ns app.main.ui.workspace.sidebar.options (:require [app.common.data :as d] - [app.common.types.modifiers :as ctm] [app.main.data.workspace :as udw] [app.main.refs :as refs] [app.main.store :as st] From 4b61e3228f892ac4ea55c36138ff6a9ca229ae73 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Tue, 25 Oct 2022 15:23:01 +0200 Subject: [PATCH 12/36] :sparkles: Add min/max width/height for elements --- .../common/geom/shapes/flex_layout/lines.cljc | 227 ++++++++++++------ .../geom/shapes/flex_layout/modifiers.cljc | 55 ++--- .../src/app/common/geom/shapes/modifiers.cljc | 17 +- common/src/app/common/types/shape/layout.cljc | 28 +-- .../sidebar/options/menus/layout_item.cljs | 5 +- 5 files changed, 203 insertions(+), 129 deletions(-) diff --git a/common/src/app/common/geom/shapes/flex_layout/lines.cljc b/common/src/app/common/geom/shapes/flex_layout/lines.cljc index a1e5cc3c4..2ac988748 100644 --- a/common/src/app/common/geom/shapes/flex_layout/lines.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/lines.cljc @@ -6,11 +6,15 @@ (ns app.common.geom.shapes.flex-layout.lines (:require + [app.common.data :as d] [app.common.geom.point :as gpt] [app.common.geom.shapes.points :as gpo] [app.common.geom.shapes.transforms :as gst] + [app.common.math :as mth] [app.common.types.shape.layout :as ctl])) +(def conjv (fnil conj [])) + (defn layout-bounds [{:keys [layout-padding layout-padding-type] :as shape}] (let [;; Add padding to the bounds @@ -38,53 +42,65 @@ layout-width (gpo/width-points layout-bounds) layout-height (gpo/height-points layout-bounds) - reduce-fn - (fn [[{:keys [line-width line-height num-children line-fill? child-fill? num-child-fill] :as line-data} result] child] - (let [child-bounds (gst/parent-coords-points child shape) - child-width (gpo/width-points child-bounds) - child-height (gpo/height-points child-bounds) - child-min-width (ctl/child-min-width child) - child-min-height (ctl/child-min-height child) + calculate-line-data + (fn [[{:keys [line-min-width line-min-height + line-max-width line-max-height + num-children + children-data] :as line-data} result] child] - fill-width? (ctl/fill-width? child) + (let [child-bounds (gst/parent-coords-points child shape) + child-width (gpo/width-points child-bounds) + child-height (gpo/height-points child-bounds) + child-min-width (ctl/child-min-width child) + child-min-height (ctl/child-min-height child) + child-max-width (ctl/child-max-width child) + child-max-height (ctl/child-max-height child) + + fill-width? (ctl/fill-width? child) fill-height? (ctl/fill-height? child) - cur-child-fill? (or (and row? fill-width?) (and col? fill-height?)) - cur-line-fill? (or (and col? fill-width?) (and row? fill-height?)) + ;; We need this info later to calculate the child resizes when fill + child-data {:id (:id child) + :child-min-width (if fill-width? child-min-width child-width) + :child-min-height (if fill-height? child-min-height child-height) + :child-max-width (if fill-width? child-max-width child-width) + :child-max-height (if fill-height? child-max-height child-height)} - next-width (if fill-width? child-min-width child-width) - next-height (if fill-height? child-min-height child-height) - - next-line-width (+ line-width next-width (* layout-gap-row (dec num-children))) - next-line-height (+ line-height next-height (* layout-gap-col (dec num-children)))] + next-min-width (if fill-width? child-min-width child-width) + next-min-height (if fill-height? child-min-height child-height) + next-max-width (if fill-width? child-max-width child-width) + next-max-height (if fill-height? child-max-height child-height) + next-line-min-width (+ line-min-width next-min-width (* layout-gap-row num-children)) + next-line-min-height (+ line-min-height next-min-height (* layout-gap-col num-children))] (if (and (some? line-data) (or (not wrap?) - (and row? (<= next-line-width layout-width)) - (and col? (<= next-line-height layout-height)))) + (and row? (<= next-line-min-width layout-width)) + (and col? (<= next-line-min-height layout-height)))) - [{:line-width (if row? (+ line-width next-width) (max line-width next-width)) - :line-height (if col? (+ line-height next-height) (max line-height next-height)) + [{:line-min-width (if row? (+ line-min-width next-min-width) (max line-min-width next-min-width)) + :line-max-width (if row? (+ line-max-width next-max-width) (max line-max-width next-max-width)) + :line-min-height (if col? (+ line-min-height next-min-height) (max line-min-height next-min-height)) + :line-max-height (if col? (+ line-max-height next-max-height) (max line-max-height next-max-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)} + :children-data (conjv children-data child-data)} result] - [{:line-width next-width - :line-height next-height + [{:line-min-width next-min-width + :line-min-height next-min-height + :line-max-width next-max-width + :line-max-height next-max-height :num-children 1 - :child-fill? cur-child-fill? - :line-fill? cur-line-fill? - :num-child-fill (if cur-child-fill? 1 0)} + :children-data [child-data]} (cond-> result (some? line-data) (conj line-data))]))) - [line-data layout-lines] (reduce reduce-fn [nil []] children)] + [line-data layout-lines] (reduce calculate-line-data [nil []] children)] (cond-> layout-lines (some? line-data) (conj line-data)))) (defn get-base-line - [parent layout-bounds total-width total-height] + "Main axis line" + [parent layout-bounds total-width total-height num-lines] (let [layout-width (gpo/width-points layout-bounds) layout-height (gpo/height-points layout-bounds) @@ -95,20 +111,25 @@ v-center? (ctl/v-center? parent) v-end? (ctl/v-end? parent) hv (partial gpo/start-hv layout-bounds) - vv (partial gpo/start-vv layout-bounds)] + vv (partial gpo/start-vv layout-bounds) + + ;; Adjust the totals so it takes into account the gaps + [layout-gap-row layout-gap-col] (ctl/gaps parent) + lines-gap-row (* (dec num-lines) layout-gap-row) + lines-gap-col (* (dec num-lines) layout-gap-col)] (cond-> (gpo/origin layout-bounds) - (and col? h-center?) - (gpt/add (hv (/ (- layout-width total-width) 2))) - - (and col? h-end?) - (gpt/add (hv (- layout-width total-width))) - (and row? v-center?) - (gpt/add (vv (/ (- layout-height total-height) 2))) + (gpt/add (vv (/ (- layout-height total-height lines-gap-col) 2))) (and row? v-end?) - (gpt/add (vv (- layout-height total-height)))))) + (gpt/add (vv (- layout-height total-height lines-gap-col))) + + (and col? h-center?) + (gpt/add (hv (/ (- layout-width total-width lines-gap-row) 2))) + + (and col? h-end?) + (gpt/add (hv (- layout-width total-width lines-gap-row)))))) (defn get-next-line [parent layout-bounds {:keys [line-width line-height]} base-p] @@ -129,6 +150,7 @@ (gpt/add (vv (+ line-height layout-gap-col)))))) (defn get-start-line + "Cross axis line. It's position is fixed along the different lines" [parent layout-bounds {:keys [line-width line-height num-children child-fill? ]} base-p] (let [layout-width (gpo/width-points layout-bounds) @@ -150,14 +172,6 @@ children-gap-width (* layout-gap-row (dec num-children)) children-gap-height (* layout-gap-col (dec num-children)) - line-width (if (and row? child-fill?) - (- layout-width (* layout-gap-row (dec num-children))) - line-width) - - line-height (if (and col? child-fill?) - (- layout-height (* layout-gap-col (dec num-children))) - line-height) - start-p (cond-> base-p ;; X AXIS @@ -192,20 +206,60 @@ start-p)) +(defn add-space-to-items + ;; Distributes the remainder space between the lines + [prop prop-min prop-max to-share items] + (let [num-items (->> items (remove #(mth/close? (get % prop) (get % prop-max))) count) + per-line-target (/ to-share num-items)] + (loop [current (first items) + items (rest items) + remainder to-share + result []] + (if (nil? current) + [result remainder] + (let [cur-val (or (get current prop) (get current prop-min) 0) + max-val (get current prop-max) + cur-inc (if (> (+ cur-val per-line-target) max-val) + (- max-val cur-val) + per-line-target) + current (assoc current prop (+ cur-val cur-inc)) + remainder (- remainder cur-inc) + result (conj result current)] + (recur (first items) (rest items) remainder result)))))) + +(defn distribute-space + [prop prop-min prop-max min-value bound-value items] + (loop [to-share (- bound-value min-value) + items items] + (if (<= to-share 0) + items + (let [[items remainder] (add-space-to-items prop prop-min prop-max to-share items)] + (assert (<= remainder to-share) (str remainder ">" to-share)) + (if (or (<= remainder 0) (= remainder to-share)) + items + (recur remainder items)))))) (defn add-lines-positions [parent layout-bounds layout-lines] - (let [layout-width (gpo/width-points layout-bounds) - layout-height (gpo/height-points layout-bounds) + (let [row? (ctl/row? parent) + col? (ctl/col? parent) + [layout-gap-row layout-gap-col] (ctl/gaps parent) - row? (ctl/row? parent) - col? (ctl/col? parent)] + layout-width (gpo/width-points layout-bounds) + layout-height (gpo/height-points layout-bounds)] - (letfn [(add-lines [[total-width total-height] {:keys [line-width line-height]}] - [(+ total-width line-width) - (+ total-height line-height)]) + (letfn [(add-lines [[total-width total-height] + {:keys [line-width line-height]}] + [(+ total-width line-width) (+ total-height line-height)]) + + (add-ranges [[total-min-width total-min-height total-max-width total-max-height] + {:keys [line-min-width line-min-height line-max-width line-max-height]}] + [(+ total-min-width line-min-width) + (+ total-min-height line-min-height) + (+ total-max-width line-max-width) + (+ total-max-height line-max-height)]) (add-starts [[result base-p] layout-line] (let [start-p (get-start-line parent layout-bounds layout-line base-p) @@ -215,29 +269,44 @@ (assoc layout-line :start-p start-p)) next-p]))] - (let [[total-width total-height] (->> layout-lines (reduce add-lines [0 0])) + (let [[total-min-width total-min-height total-max-width total-max-height] + (->> layout-lines (reduce add-ranges [0 0 0 0])) - total-width (+ total-width (* layout-gap-row (dec (count layout-lines)))) - total-height (+ total-height (* layout-gap-col (dec (count layout-lines)))) + get-layout-width (fn [{:keys [num-children]}] (- layout-width (* layout-gap-row (dec num-children)))) + get-layout-height (fn [{:keys [num-children]}] (- layout-height (* layout-gap-col (dec num-children)))) - vertical-fill-space (- layout-height total-height) - horizontal-fill-space (- layout-width total-width) - - num-line-fill (count (->> layout-lines (filter :line-fill?))) + num-lines (count layout-lines) + ;; Distributes the space between the layout lines based on its max/min constraints layout-lines - (->> layout-lines - (mapv #(cond-> % - (and row? (:line-fill? %)) - (update :line-height + (/ vertical-fill-space num-line-fill)) + (cond->> layout-lines + row? + (map #(assoc % :line-width (max (:line-min-width %) (min (get-layout-width %) (:line-max-width %))))) - (and col? (:line-fill? %)) - (update :line-width + (/ horizontal-fill-space num-line-fill))))) + col? + (map #(assoc % :line-height (max (:line-min-height %) (min (get-layout-height %) (:line-max-height %))))) - total-width (if (and col? (> num-line-fill 0)) layout-width total-width) - total-height (if (and row? (> num-line-fill 0)) layout-height total-height) + (and row? (>= total-min-height layout-height)) + (map #(assoc % :line-height (:line-min-height %))) - base-p (get-base-line parent layout-bounds total-width total-height)] + (and row? (<= total-max-height layout-height)) + (map #(assoc % :line-height (:line-max-height %))) + + (and row? (< total-min-height layout-height total-max-height)) + (distribute-space :line-height :line-min-height :line-max-height total-min-height (- layout-height (* (dec num-lines) layout-gap-col))) + + (and col? (>= total-min-width layout-width)) + (map #(assoc % :line-width (:line-min-width %))) + + (and col? (<= total-max-width layout-width)) + (map #(assoc % :line-width (:line-max-width %))) + + (and col? (< total-min-width layout-width total-max-width)) + (distribute-space :line-width :line-min-width :line-max-width total-min-width (- layout-width (* (dec num-lines) layout-gap-row)))) + + [total-width total-height] (->> layout-lines (reduce add-lines [0 0])) + + base-p (get-base-line parent layout-bounds total-width total-height num-lines)] (first (reduce add-starts [[] base-p] layout-lines)))))) @@ -291,6 +360,23 @@ :margin-x margin-x :margin-y margin-y))) +(defn add-children-resizes + [shape {:keys [line-min-width line-width line-min-height line-height] :as line-data}] + + (let [row? (ctl/row? shape) + col? (ctl/col? shape)] + (update line-data :children-data + (fn [children-data] + (cond->> children-data + row? + (distribute-space :child-width :child-min-width :child-max-width line-min-width line-width) + + col? + (distribute-space :child-height :child-min-height :child-max-height line-min-height line-height) + + :always + (d/index-by :id)))))) + (defn calc-layout-data "Digest the layout data to pass it to the constrains" [shape children] @@ -303,7 +389,8 @@ layout-lines (->> (init-layout-lines shape children layout-bounds) (add-lines-positions shape layout-bounds) - (mapv (partial add-line-spacing shape layout-bounds)))] + (mapv (partial add-line-spacing shape layout-bounds)) + (mapv (partial add-children-resizes shape)))] {:layout-lines layout-lines :reverse? reverse?})) diff --git a/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc b/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc index 4343960d0..731df28a5 100644 --- a/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc @@ -33,47 +33,40 @@ (defn calc-fill-width-data "Calculates the size and modifiers for the width of an auto-fill child" [{:keys [transform transform-inverse] :as parent} - {:keys [layout-h-behavior] :as child} + child child-origin child-width - {:keys [num-children line-width line-fill? child-fill? layout-bounds] :as layout-data}] + {:keys [children-data line-width] :as layout-data}] - (let [[layout-gap-row _] (ctl/gaps parent)] - (cond - (and (ctl/row? parent) (= :fill layout-h-behavior) child-fill?) - (let [layout-width (gpo/width-points layout-bounds) - fill-space (- layout-width line-width (* layout-gap-row (dec num-children))) - fill-width (/ fill-space (:num-child-fill layout-data)) - fill-scale (/ fill-width child-width)] + (cond + (and (ctl/row? parent) (ctl/fill-width? child)) + (let [target-width (get-in children-data [(:id child) :child-width]) + fill-scale (/ target-width child-width)] + {:width target-width + :modifiers (ctm/resize (gpt/point fill-scale 1) child-origin transform transform-inverse)}) - {:width fill-width - :modifiers (ctm/resize (gpt/point fill-scale 1) child-origin transform transform-inverse)}) - - (and (ctl/col? parent) (= :fill layout-h-behavior) line-fill?) - (let [fill-scale (/ line-width child-width)] - {:width line-width - :modifiers (ctm/resize (gpt/point fill-scale 1) child-origin transform transform-inverse)})))) + (and (ctl/col? parent) (ctl/fill-width? child)) + (let [fill-scale (/ line-width child-width)] + {:width line-width + :modifiers (ctm/resize (gpt/point fill-scale 1) child-origin transform transform-inverse)}))) (defn calc-fill-height-data "Calculates the size and modifiers for the height of an auto-fill child" [{:keys [transform transform-inverse] :as parent} - {:keys [layout-v-behavior] :as child} + child child-origin child-height - {:keys [num-children line-height layout-bounds line-fill? child-fill?] :as layout-data}] + {:keys [children-data line-height] :as layout-data}] - (let [[_ layout-gap-col] (ctl/gaps parent)] - (cond - (and (ctl/col? parent) (= :fill layout-v-behavior) child-fill?) - (let [layout-height (gpo/height-points layout-bounds) - fill-space (- layout-height line-height (* layout-gap-col (dec num-children))) - fill-height (/ fill-space (:num-child-fill layout-data)) - fill-scale (/ fill-height child-height)] - {:height fill-height - :modifiers (ctm/resize (gpt/point 1 fill-scale) child-origin transform transform-inverse)}) + (cond + (and (ctl/col? parent) (ctl/fill-height? child)) + (let [target-height (get-in children-data [(:id child) :child-height]) + fill-scale (/ target-height child-height)] + {:height target-height + :modifiers (ctm/resize (gpt/point 1 fill-scale) child-origin transform transform-inverse)}) - (and (ctl/row? parent) (= :fill layout-v-behavior) line-fill?) - (let [fill-scale (/ line-height child-height)] - {:height line-height - :modifiers (ctm/resize (gpt/point 1 fill-scale) child-origin transform transform-inverse)})))) + (and (ctl/row? parent) (ctl/fill-height? child)) + (let [fill-scale (/ line-height child-height)] + {:height line-height + :modifiers (ctm/resize (gpt/point 1 fill-scale) child-origin transform transform-inverse)}))) (defn calc-layout-modifiers "Calculates the modifiers for the layout" diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index 6f7d9a5ec..31b86a297 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -75,23 +75,18 @@ transformed-parent (gtr/transform-shape parent modifiers) 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 normalize-child transformed-parent _snap-pixel?) modif-tree children) + children (->> children (map (partial apply-modifiers modif-tree))) + layout-data (gcl/calc-layout-data transformed-parent children) + children (into [] (cond-> children (:reverse? layout-data) reverse)) + max-idx (dec (count children)) - children (->> children (map (partial apply-modifiers modif-tree))) - - layout-data (gcl/calc-layout-data transformed-parent children) - - children (into [] (cond-> children (:reverse? layout-data) reverse)) - - max-idx (dec (count children)) - layout-lines (:layout-lines layout-data)] + layout-lines (:layout-lines layout-data)] (loop [modif-tree modif-tree layout-line (first layout-lines) pending (rest layout-lines) from-idx 0] - - (if (and (some? layout-line) (<= from-idx max-idx)) (let [to-idx (+ from-idx (:num-children layout-line)) children (subvec children from-idx to-idx) diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index b25e3cb27..8f4b43128 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -80,7 +80,7 @@ (s/def ::layout-margin-type #{:simple :multiple}) (s/def ::layout-h-behavior #{:fill :fix :auto}) (s/def ::layout-v-behavior #{:fill :fix :auto}) -(s/def ::layout-align-self #{:start :end :center :strech :baseline}) +(s/def ::layout-align-self #{:start :end :center :strech}) (s/def ::layout-max-h ::us/safe-number) (s/def ::layout-min-h ::us/safe-number) (s/def ::layout-max-w ::us/safe-number) @@ -126,30 +126,30 @@ (defn child-min-width [child] (if (and (fill-width? child) - (some? (:layout-min-h child))) - (max 0 (:layout-min-h child)) + (some? (:layout-min-w child))) + (max 0 (:layout-min-w child)) 0)) (defn child-max-width [child] (if (and (fill-width? child) + (some? (:layout-max-w child))) + (max 0 (:layout-max-w child)) + ##Inf)) + +(defn child-min-height + [child] + (if (and (fill-height? child) (some? (:layout-min-h child))) (max 0 (:layout-min-h child)) 0)) -(defn child-min-height - [child] - (if (and (fill-width? child) - (some? (:layout-min-v child))) - (max 0 (:layout-min-v child)) - 0)) - (defn child-max-height [child] - (if (and (fill-width? child) - (some? (:layout-min-v child))) - (max 0 (:layout-min-v child)) - 0)) + (if (and (fill-height? child) + (some? (:layout-max-h child))) + (max 0 (:layout-max-h child)) + ##Inf)) (defn h-start? [{:keys [layout-align-items layout-justify-content] :as shape}] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs index e0b8fd357..c01ea7ddb 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs @@ -218,6 +218,5 @@ :placeholder "--" :on-click #(dom/select-target %) :on-change (partial on-size-change item) - ;; :value (get values item) - :value 100}]]])]])]] - )) + :value (get values item) + :nillable true}]]])]])]])) From 81d2f9dd9d38575efd2b984f568ecb7f6a8f51b8 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Wed, 26 Oct 2022 15:45:09 +0200 Subject: [PATCH 13/36] :sparkles: Adds align-content options --- .../common/geom/shapes/flex_layout/lines.cljc | 123 +++++++++++++----- .../geom/shapes/flex_layout/modifiers.cljc | 12 +- .../geom/shapes/flex_layout/positions.cljc | 39 +++++- common/src/app/common/types/shape/layout.cljc | 57 +++++++- .../app/main/data/workspace/shape_layout.cljs | 2 +- .../options/menus/layout_container.cljs | 20 +-- .../sidebar/options/menus/layout_item.cljs | 4 +- 7 files changed, 204 insertions(+), 53 deletions(-) diff --git a/common/src/app/common/geom/shapes/flex_layout/lines.cljc b/common/src/app/common/geom/shapes/flex_layout/lines.cljc index 2ac988748..478bbc746 100644 --- a/common/src/app/common/geom/shapes/flex_layout/lines.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/lines.cljc @@ -56,6 +56,12 @@ child-max-width (ctl/child-max-width child) child-max-height (ctl/child-max-height child) + [child-margin-top child-margin-right child-margin-bottom child-margin-left] + (ctl/child-margins child) + + child-margin-width (+ child-margin-left child-margin-right) + child-margin-height (+ child-margin-top child-margin-bottom) + fill-width? (ctl/fill-width? child) fill-height? (ctl/fill-height? child) @@ -66,10 +72,10 @@ :child-max-width (if fill-width? child-max-width child-width) :child-max-height (if fill-height? child-max-height child-height)} - next-min-width (if fill-width? child-min-width child-width) - next-min-height (if fill-height? child-min-height child-height) - next-max-width (if fill-width? child-max-width child-width) - next-max-height (if fill-height? child-max-height child-height) + next-min-width (+ child-margin-width (if fill-width? child-min-width child-width)) + next-min-height (+ child-margin-height (if fill-height? child-min-height child-height)) + next-max-width (+ child-margin-width (if fill-width? child-max-width child-width)) + next-max-height (+ child-margin-height (if fill-height? child-max-height child-height)) next-line-min-width (+ line-min-width next-min-width (* layout-gap-row num-children)) next-line-min-height (+ line-min-height next-min-height (* layout-gap-col num-children))] @@ -106,52 +112,100 @@ layout-height (gpo/height-points layout-bounds) row? (ctl/row? parent) col? (ctl/col? parent) - h-center? (ctl/h-center? parent) - h-end? (ctl/h-end? parent) - v-center? (ctl/v-center? parent) - v-end? (ctl/v-end? parent) hv (partial gpo/start-hv layout-bounds) vv (partial gpo/start-vv layout-bounds) + end? (ctl/content-end? parent) + center? (ctl/content-center? parent) + around? (ctl/content-around? parent) + ;; Adjust the totals so it takes into account the gaps [layout-gap-row layout-gap-col] (ctl/gaps parent) lines-gap-row (* (dec num-lines) layout-gap-row) - lines-gap-col (* (dec num-lines) layout-gap-col)] + lines-gap-col (* (dec num-lines) layout-gap-col) + + free-width-gap (- layout-width total-width lines-gap-row) + free-height-gap (- layout-height total-height lines-gap-col) + free-width (- layout-width total-width) + free-height (- layout-height total-height)] (cond-> (gpo/origin layout-bounds) - (and row? v-center?) - (gpt/add (vv (/ (- layout-height total-height lines-gap-col) 2))) + row? + (cond-> center? + (gpt/add (vv (/ free-height-gap 2))) - (and row? v-end?) - (gpt/add (vv (- layout-height total-height lines-gap-col))) + end? + (gpt/add (vv free-height-gap)) - (and col? h-center?) - (gpt/add (hv (/ (- layout-width total-width lines-gap-row) 2))) + around? + (gpt/add (vv (/ free-height (inc num-lines))))) - (and col? h-end?) - (gpt/add (hv (- layout-width total-width lines-gap-row)))))) + col? + (cond-> center? + (gpt/add (hv (/ free-width-gap 2))) + + end? + (gpt/add (hv free-width-gap)) + + around? + (gpt/add (hv (/ free-width (inc num-lines)))))))) (defn get-next-line - [parent layout-bounds {:keys [line-width line-height]} base-p] + [parent layout-bounds {:keys [line-width line-height]} base-p total-width total-height num-lines] - (let [row? (ctl/row? parent) + (let [layout-width (gpo/width-points layout-bounds) + layout-height (gpo/height-points layout-bounds) + row? (ctl/row? parent) col? (ctl/col? parent) [layout-gap-row layout-gap-col] (ctl/gaps parent) hv #(gpo/start-hv layout-bounds %) - vv #(gpo/start-vv layout-bounds %)] + vv #(gpo/start-vv layout-bounds %) + + stretch? (ctl/content-stretch? parent) + between? (ctl/content-between? parent) + around? (ctl/content-around? parent) + + free-width (- layout-width total-width) + free-height (- layout-height total-height) + + line-gap-row (cond + stretch? + (/ free-width num-lines) + + between? + (/ free-width (dec num-lines)) + + around? + (/ free-width (inc num-lines)) + + :else + layout-gap-row) + + line-gap-col (cond + stretch? + (/ free-height num-lines) + + between? + (/ free-height (dec num-lines)) + + around? + (/ free-height (inc num-lines)) + + :else + layout-gap-col)] (cond-> base-p - col? - (gpt/add (hv (+ line-width layout-gap-row))) - row? - (gpt/add (vv (+ line-height layout-gap-col)))))) + (gpt/add (vv (+ line-height (max layout-gap-col line-gap-col)))) + + col? + (gpt/add (hv (+ line-width (max layout-gap-row line-gap-row))))))) (defn get-start-line "Cross axis line. It's position is fixed along the different lines" - [parent layout-bounds {:keys [line-width line-height num-children child-fill? ]} base-p] + [parent layout-bounds {:keys [line-width line-height num-children]} base-p total-width total-height num-lines] (let [layout-width (gpo/width-points layout-bounds) layout-height (gpo/height-points layout-bounds) @@ -165,6 +219,7 @@ h-end? (ctl/h-end? parent) v-center? (ctl/v-center? parent) v-end? (ctl/v-end? parent) + content-stretch? (ctl/content-stretch? parent) hv #(gpo/start-hv layout-bounds %) vv #(gpo/start-vv layout-bounds %) @@ -172,6 +227,16 @@ children-gap-width (* layout-gap-row (dec num-children)) children-gap-height (* layout-gap-col (dec num-children)) + line-height + (if (and row? content-stretch?) + (+ line-height (/ (- layout-height total-height) num-lines)) + line-height) + + line-width + (if (and col? content-stretch?) + (+ line-width (/ (- layout-width total-width) num-lines)) + line-width) + start-p (cond-> base-p ;; X AXIS @@ -261,9 +326,9 @@ (+ total-max-width line-max-width) (+ total-max-height line-max-height)]) - (add-starts [[result base-p] layout-line] - (let [start-p (get-start-line parent layout-bounds layout-line base-p) - next-p (get-next-line parent layout-bounds layout-line base-p)] + (add-starts [total-width total-height num-lines [result base-p] layout-line] + (let [start-p (get-start-line parent layout-bounds layout-line base-p total-width total-height num-lines) + next-p (get-next-line parent layout-bounds layout-line base-p total-width total-height num-lines)] [(conj result (assoc layout-line :start-p start-p)) @@ -308,7 +373,7 @@ base-p (get-base-line parent layout-bounds total-width total-height num-lines)] - (first (reduce add-starts [[] base-p] layout-lines)))))) + (first (reduce (partial add-starts total-width total-height num-lines) [[] base-p] layout-lines)))))) (defn add-line-spacing "Calculates the baseline for a flex layout" diff --git a/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc b/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc index 731df28a5..02e778550 100644 --- a/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc @@ -45,8 +45,9 @@ :modifiers (ctm/resize (gpt/point fill-scale 1) child-origin transform transform-inverse)}) (and (ctl/col? parent) (ctl/fill-width? child)) - (let [fill-scale (/ line-width child-width)] - {:width line-width + (let [target-width (- line-width (ctl/child-width-margin child)) + fill-scale (/ target-width child-width)] + {:width target-width :modifiers (ctm/resize (gpt/point fill-scale 1) child-origin transform transform-inverse)}))) (defn calc-fill-height-data @@ -64,8 +65,9 @@ :modifiers (ctm/resize (gpt/point 1 fill-scale) child-origin transform transform-inverse)}) (and (ctl/row? parent) (ctl/fill-height? child)) - (let [fill-scale (/ line-height child-height)] - {:height line-height + (let [target-height (- line-height (ctl/child-height-margin child)) + fill-scale (/ target-height child-height)] + {:height target-height :modifiers (ctm/resize (gpt/point 1 fill-scale) child-origin transform transform-inverse)}))) (defn calc-layout-modifiers @@ -83,7 +85,7 @@ child-width (or (:width fill-width) child-width) child-height (or (:height fill-height) child-height) - [corner-p layout-line] (fpo/get-child-position parent child-width child-height layout-line) + [corner-p layout-line] (fpo/get-child-position parent child child-width child-height layout-line) move-vec (gpt/to-vec child-origin corner-p) diff --git a/common/src/app/common/geom/shapes/flex_layout/positions.cljc b/common/src/app/common/geom/shapes/flex_layout/positions.cljc index e230da22e..c9b4c13aa 100644 --- a/common/src/app/common/geom/shapes/flex_layout/positions.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/positions.cljc @@ -12,15 +12,17 @@ (defn get-child-position "Calculates the position for the current shape given the layout-data context" - [parent + [parent child child-width child-height {:keys [start-p layout-gap-row layout-gap-col margin-x margin-y] :as layout-data}] (let [row? (ctl/row? parent) col? (ctl/col? parent) + h-start? (ctl/h-start? parent) h-center? (ctl/h-center? parent) h-end? (ctl/h-end? parent) + v-start? (ctl/v-start? parent) v-center? (ctl/v-center? parent) v-end? (ctl/v-end? parent) points (:points parent) @@ -28,6 +30,8 @@ hv (partial gpo/start-hv points) vv (partial gpo/start-vv points) + [margin-top margin-right margin-bottom margin-left] (ctl/child-margins child) + corner-p (cond-> start-p (and col? h-center?) @@ -36,12 +40,39 @@ (and col? h-end?) (gpt/add (hv (- child-width))) + col? + (gpt/add (vv margin-top)) + + (and col? h-start?) + (gpt/add (hv margin-left)) + + (and col? h-center?) + (gpt/add (hv (/ (- margin-left margin-right) 2))) + + (and col? h-end?) + (gpt/add (hv (- margin-right))) + + ;; X COORD (and row? v-center?) (gpt/add (vv (- (/ child-height 2)))) (and row? v-end?) (gpt/add (vv (- child-height))) + row? + (gpt/add (hv margin-left)) + + (and row? v-start?) + (gpt/add (vv margin-top)) + + (and row? v-center?) + (gpt/add (vv (/ (- margin-top margin-bottom) 2))) + + (and row? v-end?) + (gpt/add (vv (- margin-bottom))) + + ;; Margins + (some? margin-x) (gpt/add (hv margin-x)) @@ -50,6 +81,12 @@ next-p (cond-> start-p + (and row? (or (> margin-left 0) (> margin-right 0))) + (gpt/add (hv (+ margin-left margin-right))) + + (and col? (or (> margin-top 0) (> margin-bottom 0))) + (gpt/add (vv (+ margin-top margin-bottom))) + row? (gpt/add (hv (+ child-width layout-gap-row))) diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 8f4b43128..23b02cd6d 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -13,9 +13,9 @@ ;; :layout-flex-dir ;; :row, :reverse-row, :column, :reverse-column ;; :layout-gap-type ;; :simple, :multiple ;; :layout-gap ;; {:row-gap number , :column-gap number} -;; :layout-align-items ;; :start :end :center :strech +;; :layout-align-items ;; :start :end :center :stretch ;; :layout-justify-content ;; :start :center :end :space-between :space-around -;; :layout-align-content ;; :start :center :end :space-between :space-around :strech (by default) +;; :layout-align-content ;; :start :center :end :space-between :space-around :stretch (by default) ;; :layout-wrap-type ;; :wrap, :no-wrap ;; :layout-padding-type ;; :simple, :multiple ;; :layout-padding ;; {:p1 num :p2 num :p3 num :p4 num} number could be negative @@ -34,8 +34,8 @@ (s/def ::layout-flex-dir #{:row :reverse-row :column :reverse-column}) (s/def ::layout-gap-type #{:simple :multiple}) (s/def ::layout-gap ::us/safe-number) -(s/def ::layout-align-items #{:start :end :center :strech}) -(s/def ::layout-align-content #{:start :end :center :space-between :space-around :strech}) +(s/def ::layout-align-items #{:start :end :center :stretch}) +(s/def ::layout-align-content #{:start :end :center :space-between :space-around :stretch}) (s/def ::layout-justify-content #{:start :center :end :space-between :space-around}) (s/def ::layout-wrap-type #{:wrap :no-wrap}) (s/def ::layout-padding-type #{:simple :multiple}) @@ -80,7 +80,7 @@ (s/def ::layout-margin-type #{:simple :multiple}) (s/def ::layout-h-behavior #{:fill :fix :auto}) (s/def ::layout-v-behavior #{:fill :fix :auto}) -(s/def ::layout-align-self #{:start :end :center :strech}) +(s/def ::layout-align-self #{:start :end :center :stretch}) (s/def ::layout-max-h ::us/safe-number) (s/def ::layout-min-h ::us/safe-number) (s/def ::layout-max-w ::us/safe-number) @@ -151,6 +151,26 @@ (max 0 (:layout-max-h child)) ##Inf)) +(defn child-margins + [{{:keys [m1 m2 m3 m4]} :layout-margin :keys [layout-margin-type]}] + (let [m1 (or m1 0) + m2 (or m2 0) + m3 (or m3 0) + m4 (or m4 0)] + (if (= layout-margin-type :multiple) + [m1 m2 m3 m4] + [m1 m1 m1 m1]))) + +(defn child-height-margin + [child] + (let [[top _ bottom _] (child-margins child)] + (+ top bottom))) + +(defn child-width-margin + [child] + (let [[_ right _ left] (child-margins child)] + (+ right left))) + (defn h-start? [{:keys [layout-align-items layout-justify-content] :as shape}] (or (and (col? shape) @@ -192,6 +212,33 @@ (= layout-align-items :end)) (and (col? shape) (= layout-justify-content :end)))) + +(defn content-start? + [{:keys [layout-align-content]}] + (= :start layout-align-content)) + +(defn content-center? + [{:keys [layout-align-content]}] + (= :center layout-align-content)) + +(defn content-end? + [{:keys [layout-align-content]}] + (= :end layout-align-content)) + +(defn content-between? + [{:keys [layout-align-content]}] + (= :space-between layout-align-content)) + +(defn content-around? + [{:keys [layout-align-content]}] + (= :space-around layout-align-content)) + +(defn content-stretch? + [{:keys [layout-align-content]}] + (or (= :stretch layout-align-content) + (nil? layout-align-content))) + + (defn reverse? [{:keys [layout-flex-dir]}] (or (= :reverse-row layout-flex-dir) diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index da2262c53..9ab3536bc 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -35,7 +35,7 @@ :layout-gap {:row-gap 0 :column-gap 0} :layout-align-items :start :layout-justify-content :start - :layout-align-content :strech + :layout-align-content :stretch :layout-wrap-type :no-wrap :layout-padding-type :simple :layout-padding {:p1 0 :p2 0 :p3 0 :p4 0}}) 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 1d1191a74..4eb03a287 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 @@ -21,9 +21,9 @@ :layout-flex-dir ;; :row, :reverse-row, :column, :reverse-column :layout-gap-type ;; :simple, :multiple :layout-gap ;; {:row-gap number , :column-gap number} - :layout-align-items ;; :start :end :center :strech + :layout-align-items ;; :start :end :center :stretch :layout-justify-content ;; :start :center :end :space-between :space-around - :layout-align-content ;; :start :center :end :space-between :space-around :strech (by default) + :layout-align-content ;; :start :center :end :space-between :space-around :stretch (by default) :layout-wrap-type ;; :wrap, :no-wrap :layout-padding-type ;; :simple, :multiple :layout-padding ;; {:p1 num :p2 num :p3 num :p4 num} number could be negative @@ -37,13 +37,13 @@ :start i/align-items-column-start :end i/align-items-column-end :center i/align-items-column-center - :strech i/align-items-column-strech + :stretch i/align-items-column-strech :baseline i/align-items-column-baseline) (case val :start i/align-items-row-start :end i/align-items-row-end :center i/align-items-row-center - :strech i/align-items-row-strech + :stretch i/align-items-row-strech :baseline i/align-items-row-baseline)) :justify-content (if is-col? (case val @@ -66,7 +66,7 @@ :center i/align-content-column-center :space-around i/align-content-column-around :space-between i/align-content-column-between - :strech nil) + :stretch nil) (case val :start i/align-content-row-start @@ -74,20 +74,20 @@ :center i/align-content-row-center :space-around i/align-content-row-around :space-between i/align-content-row-between - :strech nil)) + :stretch nil)) :align-self (if is-col? (case val :start i/align-self-column-top :end i/align-self-column-bottom :center i/align-self-column-center - :strech i/align-self-column-strech + :stretch i/align-self-column-strech :baseline i/align-self-column-baseline) (case val :start i/align-self-row-left :end i/align-self-row-right :center i/align-self-row-center - :strech i/align-self-row-strech + :stretch i/align-self-row-strech :baseline i/align-self-row-baseline)))) (mf/defc direction-btn @@ -129,7 +129,7 @@ [{:keys [is-col? align-items set-align] :as props}] [:div.align-items-style - (for [align [:start :center :end :strech]] + (for [align [:start :center :end :stretch]] [:button.align-start.tooltip {:class (dom/classnames :active (= align-items align) :tooltip-bottom-left (not= align :start) @@ -312,7 +312,7 @@ align-content (:layout-align-content values) set-align-content (fn [value] (if (= align-content value) - (st/emit! (dwsl/update-layout ids {:layout-align-content :strech})) + (st/emit! (dwsl/update-layout ids {:layout-align-content :stretch})) (st/emit! (dwsl/update-layout ids {:layout-align-content value})))) ;; Gap diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs index c01ea7ddb..f36291ca2 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs @@ -26,7 +26,7 @@ :layout-item-min-h ;; num :layout-item-max-w ;; num :layout-item-min-w ;; num - :layout-item-align-self ;; :start :end :center :strech :baseline + :layout-item-align-self ;; :start :end :center :stretch :baseline ]) (mf/defc margin-section @@ -122,7 +122,7 @@ (mf/defc align-self-row [{:keys [is-col? align-self set-align-self] :as props}] - (let [dir-v [:start :center :end :strech :baseline]] + (let [dir-v [:start :center :end :stretch :baseline]] [:div.align-self-style (for [align dir-v] [:button.align-self.tooltip.tooltip-bottom From 503a1dabac2f20422f5a9f5086f39be57d5bb35d Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 27 Oct 2022 12:22:50 +0200 Subject: [PATCH 14/36] :sparkles: Align self and stretch fixes --- .../common/geom/shapes/flex_layout/lines.cljc | 189 ++----------- .../geom/shapes/flex_layout/positions.cljc | 260 ++++++++++++++---- common/src/app/common/types/shape/layout.cljc | 12 + 3 files changed, 242 insertions(+), 219 deletions(-) diff --git a/common/src/app/common/geom/shapes/flex_layout/lines.cljc b/common/src/app/common/geom/shapes/flex_layout/lines.cljc index 478bbc746..c05a0cf52 100644 --- a/common/src/app/common/geom/shapes/flex_layout/lines.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/lines.cljc @@ -7,7 +7,7 @@ (ns app.common.geom.shapes.flex-layout.lines (:require [app.common.data :as d] - [app.common.geom.point :as gpt] + [app.common.geom.shapes.flex-layout.positions :as flp] [app.common.geom.shapes.points :as gpo] [app.common.geom.shapes.transforms :as gst] [app.common.math :as mth] @@ -104,172 +104,6 @@ (cond-> layout-lines (some? line-data) (conj line-data)))) -(defn get-base-line - "Main axis line" - [parent layout-bounds total-width total-height num-lines] - - (let [layout-width (gpo/width-points layout-bounds) - layout-height (gpo/height-points layout-bounds) - row? (ctl/row? parent) - col? (ctl/col? parent) - hv (partial gpo/start-hv layout-bounds) - vv (partial gpo/start-vv layout-bounds) - - end? (ctl/content-end? parent) - center? (ctl/content-center? parent) - around? (ctl/content-around? parent) - - ;; Adjust the totals so it takes into account the gaps - [layout-gap-row layout-gap-col] (ctl/gaps parent) - lines-gap-row (* (dec num-lines) layout-gap-row) - lines-gap-col (* (dec num-lines) layout-gap-col) - - free-width-gap (- layout-width total-width lines-gap-row) - free-height-gap (- layout-height total-height lines-gap-col) - free-width (- layout-width total-width) - free-height (- layout-height total-height)] - - (cond-> (gpo/origin layout-bounds) - row? - (cond-> center? - (gpt/add (vv (/ free-height-gap 2))) - - end? - (gpt/add (vv free-height-gap)) - - around? - (gpt/add (vv (/ free-height (inc num-lines))))) - - col? - (cond-> center? - (gpt/add (hv (/ free-width-gap 2))) - - end? - (gpt/add (hv free-width-gap)) - - around? - (gpt/add (hv (/ free-width (inc num-lines)))))))) - -(defn get-next-line - [parent layout-bounds {:keys [line-width line-height]} base-p total-width total-height num-lines] - - (let [layout-width (gpo/width-points layout-bounds) - layout-height (gpo/height-points layout-bounds) - row? (ctl/row? parent) - col? (ctl/col? parent) - - [layout-gap-row layout-gap-col] (ctl/gaps parent) - - hv #(gpo/start-hv layout-bounds %) - vv #(gpo/start-vv layout-bounds %) - - stretch? (ctl/content-stretch? parent) - between? (ctl/content-between? parent) - around? (ctl/content-around? parent) - - free-width (- layout-width total-width) - free-height (- layout-height total-height) - - line-gap-row (cond - stretch? - (/ free-width num-lines) - - between? - (/ free-width (dec num-lines)) - - around? - (/ free-width (inc num-lines)) - - :else - layout-gap-row) - - line-gap-col (cond - stretch? - (/ free-height num-lines) - - between? - (/ free-height (dec num-lines)) - - around? - (/ free-height (inc num-lines)) - - :else - layout-gap-col)] - - (cond-> base-p - row? - (gpt/add (vv (+ line-height (max layout-gap-col line-gap-col)))) - - col? - (gpt/add (hv (+ line-width (max layout-gap-row line-gap-row))))))) - -(defn get-start-line - "Cross axis line. It's position is fixed along the different lines" - [parent layout-bounds {:keys [line-width line-height num-children]} base-p total-width total-height num-lines] - - (let [layout-width (gpo/width-points layout-bounds) - layout-height (gpo/height-points layout-bounds) - [layout-gap-row layout-gap-col] (ctl/gaps parent) - - row? (ctl/row? parent) - col? (ctl/col? parent) - space-between? (ctl/space-between? parent) - space-around? (ctl/space-around? parent) - h-center? (ctl/h-center? parent) - h-end? (ctl/h-end? parent) - v-center? (ctl/v-center? parent) - v-end? (ctl/v-end? parent) - content-stretch? (ctl/content-stretch? parent) - - hv #(gpo/start-hv layout-bounds %) - vv #(gpo/start-vv layout-bounds %) - - children-gap-width (* layout-gap-row (dec num-children)) - children-gap-height (* layout-gap-col (dec num-children)) - - line-height - (if (and row? content-stretch?) - (+ line-height (/ (- layout-height total-height) num-lines)) - line-height) - - line-width - (if (and col? content-stretch?) - (+ line-width (/ (- layout-width total-width) num-lines)) - line-width) - - start-p - (cond-> base-p - ;; X AXIS - (and row? h-center? (not space-around?) (not space-between?)) - (-> (gpt/add (hv (/ layout-width 2))) - (gpt/subtract (hv (/ (+ line-width children-gap-width) 2)))) - - (and row? h-end? (not space-around?) (not space-between?)) - (-> (gpt/add (hv layout-width)) - (gpt/subtract (hv (+ line-width children-gap-width)))) - - (and col? h-center?) - (gpt/add (hv (/ line-width 2))) - - (and col? h-end?) - (gpt/add (hv line-width)) - - ;; Y AXIS - (and col? v-center? (not space-around?) (not space-between?)) - (-> (gpt/add (vv (/ layout-height 2))) - (gpt/subtract (vv (/ (+ line-height children-gap-height) 2)))) - - (and col? v-end? (not space-around?) (not space-between?)) - (-> (gpt/add (vv layout-height)) - (gpt/subtract (vv (+ line-height children-gap-height)))) - - (and row? v-center?) - (gpt/add (vv (/ line-height 2))) - - (and row? v-end?) - (gpt/add (vv line-height)))] - - start-p)) (defn add-space-to-items ;; Distributes the remainder space between the lines @@ -327,8 +161,8 @@ (+ total-max-height line-max-height)]) (add-starts [total-width total-height num-lines [result base-p] layout-line] - (let [start-p (get-start-line parent layout-bounds layout-line base-p total-width total-height num-lines) - next-p (get-next-line parent layout-bounds layout-line base-p total-width total-height num-lines)] + (let [start-p (flp/get-start-line parent layout-bounds layout-line base-p total-width total-height num-lines) + next-p (flp/get-next-line parent layout-bounds layout-line base-p total-width total-height num-lines)] [(conj result (assoc layout-line :start-p start-p)) @@ -342,6 +176,17 @@ num-lines (count layout-lines) + ;; When align-items is stretch we need to adjust the main axis size to grow for the full content + stretch-width-fix + (if (and col? (ctl/content-stretch? parent)) + (/ (- layout-width (* layout-gap-row (dec num-lines)) total-max-width) num-lines) + 0) + + stretch-height-fix + (if (and row? (ctl/content-stretch? parent)) + (/ (- layout-height (* layout-gap-col (dec num-lines)) total-max-height) num-lines) + 0) + ;; Distributes the space between the layout lines based on its max/min constraints layout-lines (cond->> layout-lines @@ -355,7 +200,7 @@ (map #(assoc % :line-height (:line-min-height %))) (and row? (<= total-max-height layout-height)) - (map #(assoc % :line-height (:line-max-height %))) + (map #(assoc % :line-height (+ (:line-max-height %) stretch-height-fix))) (and row? (< total-min-height layout-height total-max-height)) (distribute-space :line-height :line-min-height :line-max-height total-min-height (- layout-height (* (dec num-lines) layout-gap-col))) @@ -364,14 +209,14 @@ (map #(assoc % :line-width (:line-min-width %))) (and col? (<= total-max-width layout-width)) - (map #(assoc % :line-width (:line-max-width %))) + (map #(assoc % :line-width (+ (:line-max-width %) stretch-width-fix))) (and col? (< total-min-width layout-width total-max-width)) (distribute-space :line-width :line-min-width :line-max-width total-min-width (- layout-width (* (dec num-lines) layout-gap-row)))) [total-width total-height] (->> layout-lines (reduce add-lines [0 0])) - base-p (get-base-line parent layout-bounds total-width total-height num-lines)] + base-p (flp/get-base-line parent layout-bounds total-width total-height num-lines)] (first (reduce (partial add-starts total-width total-height num-lines) [[] base-p] layout-lines)))))) diff --git a/common/src/app/common/geom/shapes/flex_layout/positions.cljc b/common/src/app/common/geom/shapes/flex_layout/positions.cljc index c9b4c13aa..30437fd16 100644 --- a/common/src/app/common/geom/shapes/flex_layout/positions.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/positions.cljc @@ -10,69 +10,239 @@ [app.common.geom.shapes.points :as gpo] [app.common.types.shape.layout :as ctl])) +(defn get-base-line + [parent layout-bounds total-width total-height num-lines] + + (let [layout-width (gpo/width-points layout-bounds) + layout-height (gpo/height-points layout-bounds) + row? (ctl/row? parent) + col? (ctl/col? parent) + hv (partial gpo/start-hv layout-bounds) + vv (partial gpo/start-vv layout-bounds) + + end? (ctl/content-end? parent) + center? (ctl/content-center? parent) + around? (ctl/content-around? parent) + + ;; Adjust the totals so it takes into account the gaps + [layout-gap-row layout-gap-col] (ctl/gaps parent) + lines-gap-row (* (dec num-lines) layout-gap-row) + lines-gap-col (* (dec num-lines) layout-gap-col) + + free-width-gap (- layout-width total-width lines-gap-row) + free-height-gap (- layout-height total-height lines-gap-col) + free-width (- layout-width total-width) + free-height (- layout-height total-height)] + + (cond-> (gpo/origin layout-bounds) + row? + (cond-> center? + (gpt/add (vv (/ free-height-gap 2))) + + end? + (gpt/add (vv free-height-gap)) + + around? + (gpt/add (vv (/ free-height (inc num-lines))))) + + col? + (cond-> center? + (gpt/add (hv (/ free-width-gap 2))) + + end? + (gpt/add (hv free-width-gap)) + + around? + (gpt/add (hv (/ free-width (inc num-lines)))))))) + +(defn get-next-line + [parent layout-bounds {:keys [line-width line-height]} base-p total-width total-height num-lines] + + (let [layout-width (gpo/width-points layout-bounds) + layout-height (gpo/height-points layout-bounds) + row? (ctl/row? parent) + col? (ctl/col? parent) + + [layout-gap-row layout-gap-col] (ctl/gaps parent) + + hv #(gpo/start-hv layout-bounds %) + vv #(gpo/start-vv layout-bounds %) + + stretch? (ctl/content-stretch? parent) + between? (ctl/content-between? parent) + around? (ctl/content-around? parent) + + free-width (- layout-width total-width) + free-height (- layout-height total-height) + + line-gap-row + (cond + stretch? + (/ free-width num-lines) + + between? + (/ free-width (dec num-lines)) + + around? + (/ free-width (inc num-lines)) + + :else + layout-gap-row) + + line-gap-col + (cond + stretch? + (/ free-height num-lines) + + between? + (/ free-height (dec num-lines)) + + around? + (/ free-height (inc num-lines)) + + :else + layout-gap-col)] + + (cond-> base-p + row? + (gpt/add (vv (+ line-height (max layout-gap-col line-gap-col)))) + + col? + (gpt/add (hv (+ line-width (max layout-gap-row line-gap-row))))))) + +(defn get-start-line + "Cross axis line. It's position is fixed along the different lines" + [parent layout-bounds {:keys [line-width line-height num-children]} base-p total-width total-height num-lines] + + (let [layout-width (gpo/width-points layout-bounds) + layout-height (gpo/height-points layout-bounds) + [layout-gap-row layout-gap-col] (ctl/gaps parent) + + row? (ctl/row? parent) + col? (ctl/col? parent) + space-between? (ctl/space-between? parent) + space-around? (ctl/space-around? parent) + h-center? (ctl/h-center? parent) + h-end? (ctl/h-end? parent) + v-center? (ctl/v-center? parent) + v-end? (ctl/v-end? parent) + content-stretch? (ctl/content-stretch? parent) + + hv #(gpo/start-hv layout-bounds %) + vv #(gpo/start-vv layout-bounds %) + + children-gap-width (* layout-gap-row (dec num-children)) + children-gap-height (* layout-gap-col (dec num-children)) + + line-height + (if (and row? content-stretch?) + (+ line-height (/ (- layout-height total-height) num-lines)) + line-height) + + line-width + (if (and col? content-stretch?) + (+ line-width (/ (- layout-width total-width) num-lines)) + line-width) + + start-p + (cond-> base-p + ;; X AXIS + (and row? h-center? (not space-around?) (not space-between?)) + (-> (gpt/add (hv (/ layout-width 2))) + (gpt/subtract (hv (/ (+ line-width children-gap-width) 2)))) + + (and row? h-end? (not space-around?) (not space-between?)) + (-> (gpt/add (hv layout-width)) + (gpt/subtract (hv (+ line-width children-gap-width)))) + + ;; Y AXIS + (and col? v-center? (not space-around?) (not space-between?)) + (-> (gpt/add (vv (/ layout-height 2))) + (gpt/subtract (vv (/ (+ line-height children-gap-height) 2)))) + + (and col? v-end? (not space-around?) (not space-between?)) + (-> (gpt/add (vv layout-height)) + (gpt/subtract (vv (+ line-height children-gap-height)))))] + + start-p)) + (defn get-child-position "Calculates the position for the current shape given the layout-data context" [parent child child-width child-height - {:keys [start-p layout-gap-row layout-gap-col margin-x margin-y] :as layout-data}] + {:keys [start-p layout-gap-row layout-gap-col margin-x margin-y line-height line-width] :as layout-data}] - (let [row? (ctl/row? parent) - col? (ctl/col? parent) + (let [row? (ctl/row? parent) + col? (ctl/col? parent) + h-start? (ctl/h-start? parent) + h-center? (ctl/h-center? parent) + h-end? (ctl/h-end? 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) - v-start? (ctl/v-start? parent) - v-center? (ctl/v-center? parent) - v-end? (ctl/v-end? parent) - points (:points parent) + self-start? (ctl/align-self-start? child) + self-end? (ctl/align-self-end? child) + self-center? (ctl/align-self-center? child) + align-self? (or self-start? self-end? self-center?) - hv (partial gpo/start-hv points) - vv (partial gpo/start-vv points) + v-start? (if (or col? (not align-self?)) v-start? self-start?) + v-center? (if (or col? (not align-self?)) v-center? self-center?) + v-end? (if (or col? (not align-self?)) v-end? self-end?) + + h-start? (if (or row? (not align-self?)) h-start? self-start?) + h-center? (if (or row? (not align-self?)) h-center? self-center?) + h-end? (if (or row? (not align-self?)) h-end? self-end?) [margin-top margin-right margin-bottom margin-left] (ctl/child-margins child) + points (:points parent) + hv (partial gpo/start-hv points) + vv (partial gpo/start-vv points) + corner-p (cond-> start-p - (and col? h-center?) - (gpt/add (hv (- (/ child-width 2)))) - - (and col? h-end?) - (gpt/add (hv (- child-width))) - + ;; COLUMN DIRECTION col? - (gpt/add (vv margin-top)) + (cond-> (some? margin-top) + (gpt/add (vv margin-top)) - (and col? h-start?) - (gpt/add (hv margin-left)) + h-center? + (gpt/add (hv (- (/ child-width 2)))) - (and col? h-center?) - (gpt/add (hv (/ (- margin-left margin-right) 2))) + h-end? + (gpt/add (hv (- child-width))) - (and col? h-end?) - (gpt/add (hv (- margin-right))) + h-start? + (gpt/add (hv margin-left)) - ;; X COORD - (and row? v-center?) - (gpt/add (vv (- (/ child-height 2)))) + h-center? + (gpt/add (hv (+ (/ line-width 2) (/ (- margin-left margin-right) 2)))) - (and row? v-end?) - (gpt/add (vv (- child-height))) + h-end? + (gpt/add (hv (+ line-width (- margin-right))))) + ;; ROW DIRECTION row? - (gpt/add (hv margin-left)) + (cond-> v-center? + (gpt/add (vv (- (/ child-height 2)))) - (and row? v-start?) - (gpt/add (vv margin-top)) + v-end? + (gpt/add (vv (- child-height))) - (and row? v-center?) - (gpt/add (vv (/ (- margin-top margin-bottom) 2))) + (some? margin-left) + (gpt/add (hv margin-left)) - (and row? v-end?) - (gpt/add (vv (- margin-bottom))) + v-start? + (gpt/add (vv margin-top)) + + v-center? + (gpt/add (vv (+ (/ line-height 2) (/ (- margin-top margin-bottom) 2)))) + + v-end? + (gpt/add (vv (+ line-height (- margin-bottom))))) ;; Margins - (some? margin-x) (gpt/add (hv margin-x)) @@ -81,18 +251,14 @@ next-p (cond-> start-p - (and row? (or (> margin-left 0) (> margin-right 0))) - (gpt/add (hv (+ margin-left margin-right))) - - (and col? (or (> margin-top 0) (> margin-bottom 0))) - (gpt/add (vv (+ margin-top margin-bottom))) - row? - (gpt/add (hv (+ child-width layout-gap-row))) + (-> (gpt/add (hv (+ child-width layout-gap-row))) + (gpt/add (hv (+ margin-left margin-right)))) col? - (gpt/add (vv (+ child-height layout-gap-col))) - + (-> (gpt/add (vv (+ margin-top margin-bottom))) + (gpt/add (vv (+ child-height layout-gap-col)))) + (some? margin-x) (gpt/add (hv margin-x)) diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 23b02cd6d..98a767711 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -251,3 +251,15 @@ (defn space-around? [{:keys [layout-justify-content]}] (= layout-justify-content :space-around)) + +(defn align-self-start? [{:keys [layout-align-self]}] + (= :start layout-align-self)) + +(defn align-self-end? [{:keys [layout-align-self]}] + (= :end layout-align-self)) + +(defn align-self-center? [{:keys [layout-align-self]}] + (= :center layout-align-self)) + +(defn align-self-stretch? [{:keys [layout-align-self]}] + (= :stretch layout-align-self)) From 94602feab1e9eec59b64885e21b12bffc96f19f0 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 27 Oct 2022 15:18:21 +0200 Subject: [PATCH 15/36] :sparkles: Updated translation keys --- frontend/translations/de.po | 18 +++++++++--------- frontend/translations/en.po | 16 ++++++++-------- frontend/translations/es.po | 16 ++++++++-------- frontend/translations/eu.po | 18 +++++++++--------- frontend/translations/fr.po | 18 +++++++++--------- frontend/translations/he.po | 18 +++++++++--------- frontend/translations/hr.po | 18 +++++++++--------- frontend/translations/pl.po | 14 +++++++------- frontend/translations/pt_BR.po | 18 +++++++++--------- frontend/translations/pt_PT.po | 18 +++++++++--------- frontend/translations/tr.po | 18 +++++++++--------- frontend/translations/zh_CN.po | 18 +++++++++--------- 12 files changed, 104 insertions(+), 104 deletions(-) diff --git a/frontend/translations/de.po b/frontend/translations/de.po index f046c5808..22c2a2649 100644 --- a/frontend/translations/de.po +++ b/frontend/translations/de.po @@ -3827,19 +3827,19 @@ msgid "workspace.options.layout-item.advanced-ops" msgstr "Erweiterte Optionen" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-max-h" +msgid "workspace.options.layout-item.layout-item-max-h" msgstr "Max.Hƶhe" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-max-w" +msgid "workspace.options.layout-item.layout-item-max-w" msgstr "Max.Breite" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-min-h" +msgid "workspace.options.layout-item.layout-item-min-h" msgstr "Min.Hƶhe" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-min-w" +msgid "workspace.options.layout-item.layout-item-min-w" msgstr "Min.Breite" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs @@ -3847,19 +3847,19 @@ msgid "workspace.options.layout-item.title" msgstr "ElementgrĆ¶ĆŸe Ƥndern" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-max-h" +msgid "workspace.options.layout-item.title.layout-item-max-h" msgstr "Maximale Hƶhe" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-max-w" +msgid "workspace.options.layout-item.title.layout-item-max-w" msgstr "Maximale Breite" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-min-h" +msgid "workspace.options.layout-item.title.layout-item-min-h" msgstr "Mindesthƶhe" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-min-w" +msgid "workspace.options.layout-item.title.layout-item-min-w" msgstr "Mindestbreite" #: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs @@ -4701,4 +4701,4 @@ msgid "workspace.updates.update" msgstr "Aktualisieren" msgid "workspace.viewport.click-to-close-path" -msgstr "Klicken Sie, um den Pfad zu schlieƟen" \ No newline at end of file +msgstr "Klicken Sie, um den Pfad zu schlieƟen" diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 3bccfefad..45cd4a44f 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -3490,35 +3490,35 @@ msgid "workspace.options.layout-item.advanced-ops" msgstr "Advanced options" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-max-h" +msgid "workspace.options.layout-item.layout-item-max-h" msgstr "Max.Height" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-max-w" +msgid "workspace.options.layout-item.layout-item-max-w" msgstr "Max.Width" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-min-h" +msgid "workspace.options.layout-item.layout-item-min-h" msgstr "Min.Height" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-min-w" +msgid "workspace.options.layout-item.layout-item-min-w" msgstr "Min.Width" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-max-h" +msgid "workspace.options.layout-item.title.layout-item-max-h" msgstr "Maximum height" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-max-w" +msgid "workspace.options.layout-item.title.layout-item-max-w" msgstr "Maximum width" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-min-h" +msgid "workspace.options.layout-item.title.layout-item-min-h" msgstr "Minimum height" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-min-w" +msgid "workspace.options.layout-item.title.layout-item-min-w" msgstr "Minimum width" #: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs diff --git a/frontend/translations/es.po b/frontend/translations/es.po index efed7f480..00a47ffed 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -3889,35 +3889,35 @@ msgid "workspace.options.layout-item.advanced-ops" msgstr "Opciones avanzadas" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-max-h" +msgid "workspace.options.layout-item.layout-item-max-h" msgstr "Altura.Max" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-max-w" +msgid "workspace.options.layout-item.layout-item-max-w" msgstr "Ancho.Max" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-min-h" +msgid "workspace.options.layout-item.layout-item-min-h" msgstr "Altura.Min" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-min-w" +msgid "workspace.options.layout-item.layout-item-min-w" msgstr "Ancho.Min" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-max-h" +msgid "workspace.options.layout-item.title.layout-item-max-h" msgstr "Altura mĆ”xima" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-max-w" +msgid "workspace.options.layout-item.title.layout-item-max-w" msgstr "Ancho mĆ”ximo" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-min-h" +msgid "workspace.options.layout-item.title.layout-item-min-h" msgstr "Altura mĆ­nima" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-min-w" +msgid "workspace.options.layout-item.title.layout-item-min-w" msgstr "Ancho mĆ­nimo" #: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs diff --git a/frontend/translations/eu.po b/frontend/translations/eu.po index c2064616d..148c2066c 100644 --- a/frontend/translations/eu.po +++ b/frontend/translations/eu.po @@ -3682,19 +3682,19 @@ msgid "workspace.options.layout-item.advanced-ops" msgstr "Aukera aurreratuak" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-max-h" +msgid "workspace.options.layout-item.layout-item-max-h" msgstr "Gehieneko altuera" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-max-w" +msgid "workspace.options.layout-item.layout-item-max-w" msgstr "Gehieneko zabalera" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-min-h" +msgid "workspace.options.layout-item.layout-item-min-h" msgstr "Gutxieneko altuera" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-min-w" +msgid "workspace.options.layout-item.layout-item-min-w" msgstr "Gutxieneko zabalera" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs @@ -3706,19 +3706,19 @@ msgid "workspace.options.layout-item.title" msgstr "Elementuaren tamaina aldatzea" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-max-h" +msgid "workspace.options.layout-item.title.layout-item-max-h" msgstr "Gehieneko altuera" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-max-w" +msgid "workspace.options.layout-item.title.layout-item-max-w" msgstr "Gehieneko zabalaera" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-min-h" +msgid "workspace.options.layout-item.title.layout-item-min-h" msgstr "Gutxieneko altuera" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-min-w" +msgid "workspace.options.layout-item.title.layout-item-min-w" msgstr "Gutxieneko zabalera" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs @@ -4524,4 +4524,4 @@ msgid "workspace.updates.update" msgstr "Eguneratu" msgid "workspace.viewport.click-to-close-path" -msgstr "Egin klik bidea ixteko" \ No newline at end of file +msgstr "Egin klik bidea ixteko" diff --git a/frontend/translations/fr.po b/frontend/translations/fr.po index 0efd2d560..05cc81b4f 100644 --- a/frontend/translations/fr.po +++ b/frontend/translations/fr.po @@ -3404,19 +3404,19 @@ msgid "workspace.options.layout-item.advanced-ops" msgstr "Options avancĆ©es" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-max-h" +msgid "workspace.options.layout-item.layout-item-max-h" msgstr "Hauteur max" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-max-w" +msgid "workspace.options.layout-item.layout-item-max-w" msgstr "Largeur max" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-min-h" +msgid "workspace.options.layout-item.layout-item-min-h" msgstr "Hauteur min" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-min-w" +msgid "workspace.options.layout-item.layout-item-min-w" msgstr "Largeur min" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs @@ -3424,19 +3424,19 @@ msgid "workspace.options.layout-item.title" msgstr "Redimensionnement de l'Ć©lĆ©ment" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-max-h" +msgid "workspace.options.layout-item.title.layout-item-max-h" msgstr "Hauteur maximale" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-max-w" +msgid "workspace.options.layout-item.title.layout-item-max-w" msgstr "Largeur maximale" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-min-h" +msgid "workspace.options.layout-item.title.layout-item-min-h" msgstr "Hauteur minimale" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-min-w" +msgid "workspace.options.layout-item.title.layout-item-min-w" msgstr "Largeur minimale" #: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs @@ -4131,4 +4131,4 @@ msgid "workspace.updates.update" msgstr "Actualiser" msgid "workspace.viewport.click-to-close-path" -msgstr "Cliquez pour fermer le chemin" \ No newline at end of file +msgstr "Cliquez pour fermer le chemin" diff --git a/frontend/translations/he.po b/frontend/translations/he.po index 5c58ec20c..b49a94924 100644 --- a/frontend/translations/he.po +++ b/frontend/translations/he.po @@ -3782,19 +3782,19 @@ msgid "workspace.options.layout-item.advanced-ops" msgstr "אפש×Øויו×Ŗ מ×Ŗקדמו×Ŗ" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-max-h" +msgid "workspace.options.layout-item.layout-item-max-h" msgstr "גובה מ×Ø.ā€" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-max-w" +msgid "workspace.options.layout-item.layout-item-max-w" msgstr "×Øוחב מ×Ø.ā€" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-min-h" +msgid "workspace.options.layout-item.layout-item-min-h" msgstr "גובה מז.ā€" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-min-w" +msgid "workspace.options.layout-item.layout-item-min-w" msgstr "×Øוחב מז.ā€" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs @@ -3810,19 +3810,19 @@ msgid "workspace.options.layout-item.title" msgstr "שינוי גודל ×Øכיבים" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-max-h" +msgid "workspace.options.layout-item.title.layout-item-max-h" msgstr "גובה מ×Øבי" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-max-w" +msgid "workspace.options.layout-item.title.layout-item-max-w" msgstr "×Øוחב מ×Øבי" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-min-h" +msgid "workspace.options.layout-item.title.layout-item-min-h" msgstr "גובה מזע×Øי" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-min-w" +msgid "workspace.options.layout-item.title.layout-item-min-w" msgstr "×Øוחב מזע×Øי" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs @@ -4660,4 +4660,4 @@ msgid "workspace.updates.update" msgstr "עדכון" msgid "workspace.viewport.click-to-close-path" -msgstr "לחיצה ×Ŗהגו×Ø ××Ŗ הנ×Ŗיב" \ No newline at end of file +msgstr "לחיצה ×Ŗהגו×Ø ××Ŗ הנ×Ŗיב" diff --git a/frontend/translations/hr.po b/frontend/translations/hr.po index 83f662528..473d978e1 100644 --- a/frontend/translations/hr.po +++ b/frontend/translations/hr.po @@ -3731,19 +3731,19 @@ msgid "workspace.options.layout-item.advanced-ops" msgstr "Napredne opcije" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-max-h" +msgid "workspace.options.layout-item.layout-item-max-h" msgstr "Max.visina" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-max-w" +msgid "workspace.options.layout-item.layout-item-max-w" msgstr "Max.Å”irina" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-min-h" +msgid "workspace.options.layout-item.layout-item-min-h" msgstr "Min.visina" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-min-w" +msgid "workspace.options.layout-item.layout-item-min-w" msgstr "Min.Å”irina" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs @@ -3751,19 +3751,19 @@ msgid "workspace.options.layout-item.title" msgstr "Promjena veličine elementa" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-max-h" +msgid "workspace.options.layout-item.title.layout-item-max-h" msgstr "Maksimalna visina" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-max-w" +msgid "workspace.options.layout-item.title.layout-item-max-w" msgstr "Maksimalna Å”irina" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-min-h" +msgid "workspace.options.layout-item.title.layout-item-min-h" msgstr "Minimalna visina" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-min-w" +msgid "workspace.options.layout-item.title.layout-item-min-w" msgstr "Minimalna Å”irina" #: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs @@ -4602,4 +4602,4 @@ msgstr "Ažuriraj" #, fuzzy msgid "workspace.viewport.click-to-close-path" -msgstr "Pritisni da zatvoriÅ” path" \ No newline at end of file +msgstr "Pritisni da zatvoriÅ” path" diff --git a/frontend/translations/pl.po b/frontend/translations/pl.po index 3fdb268ff..72e0fa8b7 100644 --- a/frontend/translations/pl.po +++ b/frontend/translations/pl.po @@ -3545,27 +3545,27 @@ msgid "workspace.options.layer-options.title.multiple" msgstr "Wybrane warstwy" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-min-h" +msgid "workspace.options.layout-item.layout-item-min-h" msgstr "Min.Wysokość" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-min-w" +msgid "workspace.options.layout-item.layout-item-min-w" msgstr "Min.Szerokość" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-max-h" +msgid "workspace.options.layout-item.title.layout-item-max-h" msgstr "Maksymalna wysokość" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-max-w" +msgid "workspace.options.layout-item.title.layout-item-max-w" msgstr "Maksymalna szerokość" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-min-h" +msgid "workspace.options.layout-item.title.layout-item-min-h" msgstr "Minimalna wysokość" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-min-w" +msgid "workspace.options.layout-item.title.layout-item-min-w" msgstr "Minimalna szerokość" #: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs @@ -4320,4 +4320,4 @@ msgid "workspace.updates.update" msgstr "Aktualizuj" msgid "workspace.viewport.click-to-close-path" -msgstr "Kliknij, aby zamknąć ścieżkę" \ No newline at end of file +msgstr "Kliknij, aby zamknąć ścieżkę" diff --git a/frontend/translations/pt_BR.po b/frontend/translations/pt_BR.po index 0b8347697..47b4ba86d 100644 --- a/frontend/translations/pt_BR.po +++ b/frontend/translations/pt_BR.po @@ -3681,19 +3681,19 @@ msgid "workspace.options.layout-item.advanced-ops" msgstr "OpƧƵes avanƧadas" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-max-h" +msgid "workspace.options.layout-item.layout-item-max-h" msgstr "Altura.MĆ”x" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-max-w" +msgid "workspace.options.layout-item.layout-item-max-w" msgstr "Largura.MĆ”x" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-min-h" +msgid "workspace.options.layout-item.layout-item-min-h" msgstr "Altura.Min" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-min-w" +msgid "workspace.options.layout-item.layout-item-min-w" msgstr "Altura.Min" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs @@ -3701,19 +3701,19 @@ msgid "workspace.options.layout-item.title" msgstr "Redimensionar elemento" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-max-h" +msgid "workspace.options.layout-item.title.layout-item-max-h" msgstr "Altura mĆ”xima" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-max-w" +msgid "workspace.options.layout-item.title.layout-item-max-w" msgstr "Largura mĆ”xima" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-min-h" +msgid "workspace.options.layout-item.title.layout-item-min-h" msgstr "Altura mĆ­nima" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-min-w" +msgid "workspace.options.layout-item.title.layout-item-min-w" msgstr "Largura mĆ­nima" #: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs @@ -4527,4 +4527,4 @@ msgid "workspace.updates.update" msgstr "Atualizar" msgid "workspace.viewport.click-to-close-path" -msgstr "Clique para fechar o caminho" \ No newline at end of file +msgstr "Clique para fechar o caminho" diff --git a/frontend/translations/pt_PT.po b/frontend/translations/pt_PT.po index 423d51d11..d3bae6133 100644 --- a/frontend/translations/pt_PT.po +++ b/frontend/translations/pt_PT.po @@ -3678,19 +3678,19 @@ msgid "workspace.options.layout-item.advanced-ops" msgstr "OpƧƵes avanƧadas" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-max-h" +msgid "workspace.options.layout-item.layout-item-max-h" msgstr "Altura.MĆ”x" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-max-w" +msgid "workspace.options.layout-item.layout-item-max-w" msgstr "Largura.MĆ”x" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-min-h" +msgid "workspace.options.layout-item.layout-item-min-h" msgstr "Altura.Min" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-min-w" +msgid "workspace.options.layout-item.layout-item-min-w" msgstr "Largura.Min" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs @@ -3698,19 +3698,19 @@ msgid "workspace.options.layout-item.title" msgstr "Redimensionar elementos" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-max-h" +msgid "workspace.options.layout-item.title.layout-item-max-h" msgstr "Altura mĆ”xima" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-max-w" +msgid "workspace.options.layout-item.title.layout-item-max-w" msgstr "Largura mĆ”xima" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-min-h" +msgid "workspace.options.layout-item.title.layout-item-min-h" msgstr "Altura mĆ­nima" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-min-w" +msgid "workspace.options.layout-item.title.layout-item-min-w" msgstr "Largura mĆ­nima" #: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs @@ -4526,4 +4526,4 @@ msgid "workspace.updates.update" msgstr "Atualizar" msgid "workspace.viewport.click-to-close-path" -msgstr "Clica para fechar o caminho" \ No newline at end of file +msgstr "Clica para fechar o caminho" diff --git a/frontend/translations/tr.po b/frontend/translations/tr.po index 239d4c315..14d9d75b9 100644 --- a/frontend/translations/tr.po +++ b/frontend/translations/tr.po @@ -3820,19 +3820,19 @@ msgid "workspace.options.layout-item.advanced-ops" msgstr "Gelişmiş seƧenekler" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-max-h" +msgid "workspace.options.layout-item.layout-item-max-h" msgstr "Azami YĆ¼kseklik" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-max-w" +msgid "workspace.options.layout-item.layout-item-max-w" msgstr "Azami Genişlik" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-min-h" +msgid "workspace.options.layout-item.layout-item-min-h" msgstr "Asgari YĆ¼kseklik" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-min-w" +msgid "workspace.options.layout-item.layout-item-min-w" msgstr "Asgari Genişlik" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs @@ -3848,19 +3848,19 @@ msgid "workspace.options.layout-item.title" msgstr "Ɩge yeniden boyutlandırma" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-max-h" +msgid "workspace.options.layout-item.title.layout-item-max-h" msgstr "Azami yĆ¼kseklik" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-max-w" +msgid "workspace.options.layout-item.title.layout-item-max-w" msgstr "Azami genişlik" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-min-h" +msgid "workspace.options.layout-item.title.layout-item-min-h" msgstr "Asgari yĆ¼kseklik" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-min-w" +msgid "workspace.options.layout-item.title.layout-item-min-w" msgstr "Asgari genişlik" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs @@ -4700,4 +4700,4 @@ msgid "workspace.updates.update" msgstr "GĆ¼ncelle" msgid "workspace.viewport.click-to-close-path" -msgstr "Yolu kapatmak iƧin tıklayın" \ No newline at end of file +msgstr "Yolu kapatmak iƧin tıklayın" diff --git a/frontend/translations/zh_CN.po b/frontend/translations/zh_CN.po index 9f55473b3..cf3e34c85 100644 --- a/frontend/translations/zh_CN.po +++ b/frontend/translations/zh_CN.po @@ -3565,19 +3565,19 @@ msgid "workspace.options.layout-item.advanced-ops" msgstr "高ēŗ§é€‰é”¹" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-max-h" +msgid "workspace.options.layout-item.layout-item-max-h" msgstr "ęœ€å¤§é«˜åŗ¦" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-max-w" +msgid "workspace.options.layout-item.layout-item-max-w" msgstr "ęœ€å¤§å®½åŗ¦" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-min-h" +msgid "workspace.options.layout-item.layout-item-min-h" msgstr "ęœ€å°é«˜åŗ¦" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.layout-min-w" +msgid "workspace.options.layout-item.layout-item-min-w" msgstr "ęœ€å°å®½åŗ¦" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs @@ -3585,19 +3585,19 @@ msgid "workspace.options.layout-item.title" msgstr "č°ƒę•“å¤§å°" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-max-h" +msgid "workspace.options.layout-item.title.layout-item-max-h" msgstr "ęœ€å¤§é«˜åŗ¦" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-max-w" +msgid "workspace.options.layout-item.title.layout-item-max-w" msgstr "ęœ€å¤§å®½åŗ¦" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-min-h" +msgid "workspace.options.layout-item.title.layout-item-min-h" msgstr "ęœ€å°é«˜åŗ¦" #: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs -msgid "workspace.options.layout-item.title.layout-min-w" +msgid "workspace.options.layout-item.title.layout-item-min-w" msgstr "ęœ€å°å®½åŗ¦" #: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs @@ -4405,4 +4405,4 @@ msgid "workspace.updates.update" msgstr "ꛓꖰ" msgid "workspace.viewport.click-to-close-path" -msgstr "单击仄闭合č·Æ径" \ No newline at end of file +msgstr "单击仄闭合č·Æ径" From cebda20dd4c55725f3346dd88466f7190f79e40f Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 27 Oct 2022 15:18:41 +0200 Subject: [PATCH 16/36] :sparkles: Adapt to handoff changes --- common/src/app/common/pages/common.cljc | 562 +++++++++--------- common/src/app/common/types/shape/layout.cljc | 94 +-- frontend/src/app/main/refs.cljs | 5 +- frontend/src/app/main/render.cljs | 10 +- .../ui/viewer/handoff/selection_feedback.cljs | 2 - .../src/app/main/ui/viewer/interactions.cljs | 8 +- .../options/menus/layout_container.cljs | 23 +- .../sidebar/options/menus/layout_item.cljs | 52 +- 8 files changed, 384 insertions(+), 372 deletions(-) diff --git a/common/src/app/common/pages/common.cljc b/common/src/app/common/pages/common.cljc index 3a47fdcd5..de34e6b74 100644 --- a/common/src/app/common/pages/common.cljc +++ b/common/src/app/common/pages/common.cljc @@ -83,14 +83,16 @@ :layout-h-orientation :layout-container :layout-v-orientation :layout-container - :layout-margin :layout-item - :layout-margin-type :layout-item - :layout-h-behavior :layout-item - :layout-v-behavior :layout-item - :layout-max-h :layout-item - :layout-min-h :layout-item - :layout-max-w :layout-item - :layout-min-w :layout-item}) + :layout-item-margin :layout-item + :layout-item-margin-type :layout-item + :layout-item-h-sizing :layout-item + :layout-item-v-sizing :layout-item + :layout-item-max-h :layout-item + :layout-item-min-h :layout-item + :layout-item-max-w :layout-item + :layout-item-min-w :layout-item + :layout-item-align-self :layout-item + }) ;; Attributes that may directly be edited by the user with forms (def editable-attrs @@ -133,56 +135,59 @@ :exports :layout - :layout-dir + :layout-flex-dir :layout-gap - :layout-type + :layout-gap-type + :layout-align-items + :layout-justify-content + :layout-align-content :layout-wrap-type :layout-padding-type :layout-padding - :layout-h-orientation - :layout-v-orientation - :layout-margin - :layout-margin-type - :layout-h-behavior - :layout-v-behavior - :layout-max-h - :layout-min-h - :layout-max-w - :layout-min-w} + :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} :group #{:proportion-lock :width :height - :x :y - :rotation - :selrect - :points + :x :y + :rotation + :selrect + :points - :constraints-h - :constraints-v - :fixed-scroll - :parent-id - :frame-id + :constraints-h + :constraints-v + :fixed-scroll + :parent-id + :frame-id - :opacity - :blend-mode - :blocked - :hidden + :opacity + :blend-mode + :blocked + :hidden - :shadow + :shadow - :blur + :blur - :exports + :exports - :layout-margin - :layout-margin-type - :layout-h-behavior - :layout-v-behavior - :layout-max-h - :layout-min-h - :layout-max-w - :layout-min-w} + :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} :rect #{:proportion-lock :width :height @@ -229,14 +234,15 @@ :exports - :layout-margin - :layout-margin-type - :layout-h-behavior - :layout-v-behavior - :layout-max-h - :layout-min-h - :layout-max-w - :layout-min-w} + :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} :circle #{:proportion-lock :width :height @@ -281,143 +287,237 @@ :exports - :layout-margin - :layout-margin-type - :layout-h-behavior - :layout-v-behavior - :layout-max-h - :layout-min-h - :layout-max-w - :layout-min-w} + :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} - :path #{:proportion-lock - :width :height - :x :y - :rotation - :selrect - :points + :path #{:proportion-lock + :width :height + :x :y + :rotation + :selrect + :points - :constraints-h - :constraints-v - :fixed-scroll - :parent-id - :frame-id + :constraints-h + :constraints-v + :fixed-scroll + :parent-id + :frame-id - :opacity - :blend-mode - :blocked - :hidden + :opacity + :blend-mode + :blocked + :hidden - :fills - :fill-color - :fill-opacity - :fill-color-ref-id - :fill-color-ref-file - :fill-color-gradient + :fills + :fill-color + :fill-opacity + :fill-color-ref-id + :fill-color-ref-file + :fill-color-gradient - :strokes - :stroke-style - :stroke-alignment - :stroke-width - :stroke-color - :stroke-color-ref-id - :stroke-color-ref-file - :stroke-opacity - :stroke-color-gradient - :stroke-cap-start - :stroke-cap-end + :strokes + :stroke-style + :stroke-alignment + :stroke-width + :stroke-color + :stroke-color-ref-id + :stroke-color-ref-file + :stroke-opacity + :stroke-color-gradient + :stroke-cap-start + :stroke-cap-end - :shadow + :shadow - :blur + :blur - :exports + :exports - :layout-margin - :layout-margin-type - :layout-h-behavior - :layout-v-behavior - :layout-max-h - :layout-min-h - :layout-max-w - :layout-min-w} + :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} - :text #{:proportion-lock - :width :height - :x :y - :rotation - :selrect - :points + :text #{:proportion-lock + :width :height + :x :y + :rotation + :selrect + :points - :constraints-h - :constraints-v - :fixed-scroll - :parent-id - :frame-id + :constraints-h + :constraints-v + :fixed-scroll + :parent-id + :frame-id - :opacity - :blend-mode - :blocked - :hidden + :opacity + :blend-mode + :blocked + :hidden - :fill-color - :fill-opacity - :fill-color-ref-id - :fill-color-ref-file - :fill-color-gradient + :fill-color + :fill-opacity + :fill-color-ref-id + :fill-color-ref-file + :fill-color-gradient - :stroke-style - :stroke-alignment - :stroke-width - :stroke-color - :stroke-color-ref-id - :stroke-color-ref-file - :stroke-opacity - :stroke-color-gradient - :stroke-cap-start - :stroke-cap-end + :stroke-style + :stroke-alignment + :stroke-width + :stroke-color + :stroke-color-ref-id + :stroke-color-ref-file + :stroke-opacity + :stroke-color-gradient + :stroke-cap-start + :stroke-cap-end - :shadow + :shadow - :blur + :blur - :typography-ref-id - :typography-ref-file + :typography-ref-id + :typography-ref-file - :font-id - :font-family - :font-variant-id - :font-size - :font-weight - :font-style + :font-id + :font-family + :font-variant-id + :font-size + :font-weight + :font-style - :text-align + :text-align - :text-direction + :text-direction - :line-height - :letter-spacing + :line-height + :letter-spacing - :vertical-align + :vertical-align - :text-decoration + :text-decoration - :text-transform + :text-transform - :grow-type + :grow-type - :exports + :exports - :layout-margin - :layout-margin-type - :layout-h-behavior - :layout-v-behavior - :layout-max-h - :layout-min-h - :layout-max-w - :layout-min-w} + :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} - :image #{:proportion-lock + :image #{:proportion-lock + :width :height + :x :y + :rotation + :rx :ry + :r1 :r2 :r3 :r4 + :selrect + :points + + :constraints-h + :constraints-v + :fixed-scroll + :parent-id + :frame-id + + :opacity + :blend-mode + :blocked + :hidden + + :shadow + + :blur + + :exports + + :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} + + :svg-raw #{:proportion-lock + :width :height + :x :y + :rotation + :rx :ry + :r1 :r2 :r3 :r4 + :selrect + :points + + :constraints-h + :constraints-v + :fixed-scroll + :parent-id + :frame-id + + :opacity + :blend-mode + :blocked + :hidden + + :fills + :fill-color + :fill-opacity + :fill-color-ref-id + :fill-color-ref-file + :fill-color-gradient + + :strokes + :stroke-style + :stroke-alignment + :stroke-width + :stroke-color + :stroke-color-ref-id + :stroke-color-ref-file + :stroke-opacity + :stroke-color-gradient + :stroke-cap-start + :stroke-cap-end + + :shadow + + :blur + + :exports + + :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} + + :bool #{:proportion-lock :width :height :x :y :rotation @@ -437,124 +537,36 @@ :blocked :hidden + :fill-color + :fill-opacity + :fill-color-ref-id + :fill-color-ref-file + :fill-color-gradient + + :stroke-style + :stroke-alignment + :stroke-width + :stroke-color + :stroke-color-ref-id + :stroke-color-ref-file + :stroke-opacity + :stroke-color-gradient + :stroke-cap-start + :stroke-cap-end + :shadow :blur :exports - :layout-margin - :layout-margin-type - :layout-h-behavior - :layout-v-behavior - :layout-max-h - :layout-min-h - :layout-max-w - :layout-min-w} - - :svg-raw #{:proportion-lock - :width :height - :x :y - :rotation - :rx :ry - :r1 :r2 :r3 :r4 - :selrect - :points - - :constraints-h - :constraints-v - :fixed-scroll - :parent-id - :frame-id - - :opacity - :blend-mode - :blocked - :hidden - - :fills - :fill-color - :fill-opacity - :fill-color-ref-id - :fill-color-ref-file - :fill-color-gradient - - :strokes - :stroke-style - :stroke-alignment - :stroke-width - :stroke-color - :stroke-color-ref-id - :stroke-color-ref-file - :stroke-opacity - :stroke-color-gradient - :stroke-cap-start - :stroke-cap-end - - :shadow - - :blur - - :exports - - :layout-margin - :layout-margin-type - :layout-h-behavior - :layout-v-behavior - :layout-max-h - :layout-min-h - :layout-max-w - :layout-min-w} - - :bool #{:proportion-lock - :width :height - :x :y - :rotation - :rx :ry - :r1 :r2 :r3 :r4 - :selrect - :points - - :constraints-h - :constraints-v - :fixed-scroll - :parent-id - :frame-id - - :opacity - :blend-mode - :blocked - :hidden - - :fill-color - :fill-opacity - :fill-color-ref-id - :fill-color-ref-file - :fill-color-gradient - - :stroke-style - :stroke-alignment - :stroke-width - :stroke-color - :stroke-color-ref-id - :stroke-color-ref-file - :stroke-opacity - :stroke-color-gradient - :stroke-cap-start - :stroke-cap-end - - :shadow - - :blur - - :exports - - :layout-margin - :layout-margin-type - :layout-h-behavior - :layout-v-behavior - :layout-max-h - :layout-min-h - :layout-max-w - :layout-min-w}}) + :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}}) diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 98a767711..32f54e16e 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -21,14 +21,14 @@ ;; :layout-padding ;; {:p1 num :p2 num :p3 num :p4 num} number could be negative ;; ITEMS -;; :layout-margin ;; {:m1 0 :m2 0 :m3 0 :m4 0} -;; :layout-margin-type ;; :simple :multiple -;; :layout-h-behavior ;; :fill :fix :auto -;; :layout-v-behavior ;; :fill :fix :auto -;; :layout-max-h ;; num -;; :layout-min-h ;; num -;; :layout-max-w ;; num -;; :layout-min-w +;; :layout-item-margin ;; {:m1 0 :m2 0 :m3 0 :m4 0} +;; :layout-item-margin-type ;; :simple :multiple +;; :layout-item-h-sizing ;; :fill :fix :auto +;; :layout-item-v-sizing ;; :fill :fix :auto +;; :layout-item-max-h ;; num +;; :layout-item-min-h ;; num +;; :layout-item-max-w ;; num +;; :layout-item-min-w (s/def ::layout #{:flex :grid}) (s/def ::layout-flex-dir #{:row :reverse-row :column :reverse-column}) @@ -74,38 +74,38 @@ (s/def ::m3 ::us/safe-number) (s/def ::m4 ::us/safe-number) -(s/def ::layout-margin (s/keys :req-un [::m1] - :opt-un [::m2 ::m3 ::m4])) +(s/def ::layout-item-margin (s/keys :req-un [::m1] + :opt-un [::m2 ::m3 ::m4])) -(s/def ::layout-margin-type #{:simple :multiple}) -(s/def ::layout-h-behavior #{:fill :fix :auto}) -(s/def ::layout-v-behavior #{:fill :fix :auto}) -(s/def ::layout-align-self #{:start :end :center :stretch}) -(s/def ::layout-max-h ::us/safe-number) -(s/def ::layout-min-h ::us/safe-number) -(s/def ::layout-max-w ::us/safe-number) -(s/def ::layout-min-w ::us/safe-number) +(s/def ::layout-item-margin-type #{:simple :multiple}) +(s/def ::layout-item-h-sizing #{:fill :fix :auto}) +(s/def ::layout-item-v-sizing #{:fill :fix :auto}) +(s/def ::layout-item-align-self #{:start :end :center :stretch}) +(s/def ::layout-item-max-h ::us/safe-number) +(s/def ::layout-item-min-h ::us/safe-number) +(s/def ::layout-item-max-w ::us/safe-number) +(s/def ::layout-item-min-w ::us/safe-number) (s/def ::layout-child-props - (s/keys :opt-un [::layout-margin - ::layout-margin-type - ::layout-h-behavior - ::layout-v-behavior - ::layout-max-h - ::layout-min-h - ::layout-max-w - ::layout-min-w - ::layout-align-self])) + (s/keys :opt-un [::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])) (defn wrap? [{:keys [layout-wrap-type]}] (= layout-wrap-type :wrap)) (defn fill-width? [child] - (= :fill (:layout-h-behavior child))) + (= :fill (:layout-item-h-sizing child))) (defn fill-height? [child] - (= :fill (:layout-v-behavior child))) + (= :fill (:layout-item-v-sizing child))) (defn col? [{:keys [layout-flex-dir]}] @@ -126,38 +126,38 @@ (defn child-min-width [child] (if (and (fill-width? child) - (some? (:layout-min-w child))) - (max 0 (:layout-min-w child)) + (some? (:layout-item-min-w child))) + (max 0 (:layout-item-min-w child)) 0)) (defn child-max-width [child] (if (and (fill-width? child) - (some? (:layout-max-w child))) - (max 0 (:layout-max-w child)) + (some? (:layout-item-max-w child))) + (max 0 (:layout-item-max-w child)) ##Inf)) (defn child-min-height [child] (if (and (fill-height? child) - (some? (:layout-min-h child))) - (max 0 (:layout-min-h child)) + (some? (:layout-item-min-h child))) + (max 0 (:layout-item-min-h child)) 0)) (defn child-max-height [child] (if (and (fill-height? child) - (some? (:layout-max-h child))) - (max 0 (:layout-max-h child)) + (some? (:layout-item-max-h child))) + (max 0 (:layout-item-max-h child)) ##Inf)) (defn child-margins - [{{:keys [m1 m2 m3 m4]} :layout-margin :keys [layout-margin-type]}] + [{{:keys [m1 m2 m3 m4]} :layout-item-margin :keys [layout-item-margin-type]}] (let [m1 (or m1 0) m2 (or m2 0) m3 (or m3 0) m4 (or m4 0)] - (if (= layout-margin-type :multiple) + (if (= layout-item-margin-type :multiple) [m1 m2 m3 m4] [m1 m1 m1 m1]))) @@ -252,14 +252,14 @@ [{:keys [layout-justify-content]}] (= layout-justify-content :space-around)) -(defn align-self-start? [{:keys [layout-align-self]}] - (= :start layout-align-self)) +(defn align-self-start? [{:keys [layout-item-align-self]}] + (= :start layout-item-align-self)) -(defn align-self-end? [{:keys [layout-align-self]}] - (= :end layout-align-self)) +(defn align-self-end? [{:keys [layout-item-align-self]}] + (= :end layout-item-align-self)) -(defn align-self-center? [{:keys [layout-align-self]}] - (= :center layout-align-self)) +(defn align-self-center? [{:keys [layout-item-align-self]}] + (= :center layout-item-align-self)) -(defn align-self-stretch? [{:keys [layout-align-self]}] - (= :stretch layout-align-self)) +(defn align-self-stretch? [{:keys [layout-item-align-self]}] + (= :stretch layout-item-align-self)) diff --git a/frontend/src/app/main/refs.cljs b/frontend/src/app/main/refs.cljs index fb66b3b6b..4f6015f09 100644 --- a/frontend/src/app/main/refs.cljs +++ b/frontend/src/app/main/refs.cljs @@ -442,7 +442,10 @@ (l/derived (fn [state] (let [objects (wsh/lookup-viewer-objects state page-id)] - (filterv #(= :flex (:layout (cph/get-parent objects %))) ids))) + (into [] + (comp (filter #(= :flex (:layout (cph/get-parent objects %)))) + (map #(get objects %))) + ids))) st/state =)) (def colorpicker diff --git a/frontend/src/app/main/render.cljs b/frontend/src/app/main/render.cljs index 77fa6f5a1..a2627d2da 100644 --- a/frontend/src/app/main/render.cljs +++ b/frontend/src/app/main/render.cljs @@ -254,7 +254,7 @@ objects (mf/with-memo [frame-id objects vector] - (let [update-fn #(update-in %1 %2 ctm/add-move vector)] + (let [update-fn #(update %1 %2 gsh/transform-shape (ctm/move vector))] (->> children-ids (into [frame-id]) (reduce update-fn objects)))) @@ -290,7 +290,6 @@ :xmlnsXlink "http://www.w3.org/1999/xlink" :xmlns:penpot (when include-metadata? "https://penpot.app/xmlns") :fill "none"} - [:& shape-wrapper {:shape frame}]]])) @@ -313,10 +312,9 @@ (mf/use-memo (mf/deps vector objects group-id) (fn [] - (let [modifier-ids (cons group-id (cph/get-children-ids objects group-id)) - update-fn #(update %1 %2 ctm/add-move vector) - modifiers (reduce update-fn {} modifier-ids)] - (ctm/merge-modifiers objects modifiers)))) + (let [children-ids (cons group-id (cph/get-children-ids objects group-id)) + update-fn #(update %1 %2 gsh/transform-shape (ctm/move vector))] + (reduce update-fn objects children-ids)))) group (get objects group-id) width (* (:width group) zoom) diff --git a/frontend/src/app/main/ui/viewer/handoff/selection_feedback.cljs b/frontend/src/app/main/ui/viewer/handoff/selection_feedback.cljs index 0b7af463a..9d3325710 100644 --- a/frontend/src/app/main/ui/viewer/handoff/selection_feedback.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/selection_feedback.cljs @@ -57,8 +57,6 @@ shapes (resolve-shapes objects [hover]) hover-shape (or (first shapes) frame) - hover-shape (gsh/translate-to-frame hover-shape size) - selected-shapes (resolve-shapes objects selected) selrect (gsh/selection-rect selected-shapes)] diff --git a/frontend/src/app/main/ui/viewer/interactions.cljs b/frontend/src/app/main/ui/viewer/interactions.cljs index 72d822828..51b136d11 100644 --- a/frontend/src/app/main/ui/viewer/interactions.cljs +++ b/frontend/src/app/main/ui/viewer/interactions.cljs @@ -9,6 +9,7 @@ [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.pages.helpers :as cph] [app.common.types.modifiers :as ctm] [app.common.types.page :as ctp] @@ -29,13 +30,10 @@ (defn prepare-objects [frame size objects] - (let [ - frame-id (:id frame) + (let [frame-id (:id frame) vector (-> (gpt/point (:x size) (:y size)) (gpt/negate)) - - update-fn #(d/update-when %1 %2 ctm/add-move vector)] - + update-fn #(d/update-when %1 %2 gsh/transform-shape (ctm/move vector))] (->> (cph/get-children-ids objects frame-id) (into [frame-id]) (reduce update-fn objects)))) 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 4eb03a287..71545cb59 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 @@ -18,7 +18,7 @@ (def layout-container-flex-attrs [:layout ;; :flex, :grid in the future - :layout-flex-dir ;; :row, :reverse-row, :column, :reverse-column + :layout-flex-dir ;; :row, :reverse-row, :column, :reverse-column :layout-gap-type ;; :simple, :multiple :layout-gap ;; {:row-gap number , :column-gap number} :layout-align-items ;; :start :end :center :stretch @@ -67,7 +67,7 @@ :space-around i/align-content-column-around :space-between i/align-content-column-between :stretch nil) - + (case val :start i/align-content-row-start :end i/align-content-row-end @@ -129,7 +129,7 @@ [{:keys [is-col? align-items set-align] :as props}] [:div.align-items-style - (for [align [:start :center :end :stretch]] + (for [align [:start :center :end #_:stretch #_:baseline]] [:button.align-start.tooltip {:class (dom/classnames :active (= align-items align) :tooltip-bottom-left (not= align :start) @@ -274,13 +274,14 @@ (st/emit! (dwsl/remove-layout ids)) (reset! open? false)) - set-flex (fn [] - (st/emit! (dwsl/remove-layout ids)) - (on-add-layout :flex)) - - set-grid (fn [] - (st/emit! (dwsl/remove-layout ids)) - (on-add-layout :grid)) + ;; Uncomment when activating the grid options + ;; set-flex (fn [] + ;; (st/emit! (dwsl/remove-layout ids)) + ;; (on-add-layout :flex)) + ;; + ;; set-grid (fn [] + ;; (st/emit! (dwsl/remove-layout ids)) + ;; (on-add-layout :grid)) ;; Flex-direction @@ -365,7 +366,7 @@ [:span "Layout"] (if (:layout values) [:div.title-actions - [:div.layout-btns + #_[:div.layout-btns [:button {:on-click set-flex :class (dom/classnames :active (= :flex layout-type))} "Flex"] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs index f36291ca2..4ce0b57e3 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs @@ -32,7 +32,7 @@ (mf/defc margin-section [{:keys [values change-margin-style on-margin-change] :as props}] - (let [margin-type (or (:layout-margin-type values) :simple)] + (let [margin-type (or (:layout-item-margin-type values) :simple)] [:div.margin-row [:div.margin-icons @@ -57,7 +57,7 @@ {:placeholder "--" :on-click #(dom/select-target %) :on-change (partial on-margin-change :simple) - :value (or (-> values :layout-margin :m1) 0)}]]] + :value (or (-> values :layout-item-margin :m1) 0)}]]] (= margin-type :multiple) (for [num [:m1 :m2 :m3 :m4]] @@ -73,10 +73,10 @@ {:placeholder "--" :on-click #(dom/select-target %) :on-change (partial on-margin-change num) - :value (or (-> values :layout-margin num) 0)}]]]))]])) + :value (or (-> values :layout-item-margin num) 0)}]]]))]])) (mf/defc element-behavior - [{:keys [is-layout-container? is-layout-child? layout-h-behavior layout-v-behavior 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? auto? is-layout-container?] @@ -84,45 +84,45 @@ [:div.layout-behavior.horizontal [:button.behavior-btn.tooltip.tooltip-bottom {:alt "Fix width" - :class (dom/classnames :active (= layout-h-behavior :fix)) + :class (dom/classnames :active (= layout-item-h-sizing :fix)) :on-click #(on-change-behavior :h :fix)} i/auto-fix-layout] (when fill? [:button.behavior-btn.tooltip.tooltip-bottom {:alt "Width 100%" - :class (dom/classnames :active (= layout-h-behavior :fill)) + :class (dom/classnames :active (= layout-item-h-sizing :fill)) :on-click #(on-change-behavior :h :fill)} i/auto-fill]) (when auto? [:button.behavior-btn.tooltip.tooltip-bottom {:alt "Fit content" - :class (dom/classnames :active (= layout-v-behavior :auto)) + :class (dom/classnames :active (= layout-item-v-sizing :auto)) :on-click #(on-change-behavior :h :auto)} i/auto-hug])] [:div.layout-behavior [:button.behavior-btn.tooltip.tooltip-bottom {:alt "Fix height" - :class (dom/classnames :active (= layout-v-behavior :fix)) + :class (dom/classnames :active (= layout-item-v-sizing :fix)) :on-click #(on-change-behavior :v :fix)} i/auto-fix-layout] (when fill? [:button.behavior-btn.tooltip.tooltip-bottom {:alt "Height 100%" - :class (dom/classnames :active (= layout-v-behavior :fill)) + :class (dom/classnames :active (= layout-item-v-sizing :fill)) :on-click #(on-change-behavior :v :fill)} i/auto-fill]) (when auto? [:button.behavior-btn.tooltip.tooltip-bottom-left {:alt "Fit content" - :class (dom/classnames :active (= layout-v-behavior :auto)) + :class (dom/classnames :active (= layout-item-v-sizing :auto)) :on-click #(on-change-behavior :v :auto)} i/auto-hug])]])) (mf/defc align-self-row [{:keys [is-col? align-self set-align-self] :as props}] - (let [dir-v [:start :center :end :stretch :baseline]] + (let [dir-v [:start :center :end #_:stretch #_:baseline]] [:div.align-self-style (for [align dir-v] [:button.align-self.tooltip.tooltip-bottom @@ -143,11 +143,13 @@ change-margin-style (fn [type] - (st/emit! (dwsl/update-layout-child ids {:layout-margin-type type}))) + (st/emit! (dwsl/update-layout-child ids {:layout-item-margin-type type}))) - align-self (:layout-align-self values) + align-self (:layout-item-align-self values) set-align-self (fn [value] - (st/emit! (dwsl/update-layout-child ids {:layout-align-self value}))) + (if (= align-self value) + (st/emit! (dwsl/update-layout-child ids {:layout-item-align-self nil})) + (st/emit! (dwsl/update-layout-child ids {:layout-item-align-self value})))) saved-dir (:layout-flex-dir values) is-col? (or (= :column saved-dir) (= :reverse-column saved-dir)) @@ -155,14 +157,14 @@ on-margin-change (fn [type val] (if (= type :simple) - (st/emit! (dwsl/update-layout-child ids {:layout-margin {:m1 val :m2 val :m3 val :m4 val}})) - (st/emit! (dwsl/update-layout-child ids {:layout-margin {type val}})))) + (st/emit! (dwsl/update-layout-child ids {:layout-item-margin {:m1 val :m2 val :m3 val :m4 val}})) + (st/emit! (dwsl/update-layout-child ids {:layout-item-margin {type val}})))) on-change-behavior (fn [dir value] (if (= dir :h) - (st/emit! (dwsl/update-layout-child ids {:layout-h-behavior value})) - (st/emit! (dwsl/update-layout-child ids {:layout-v-behavior value})))) + (st/emit! (dwsl/update-layout-child ids {:layout-item-h-sizing value})) + (st/emit! (dwsl/update-layout-child ids {:layout-item-v-sizing value})))) on-size-change (fn [measure value] @@ -177,8 +179,8 @@ [:div.row-title "Sizing"] [:& element-behavior {:is-layout-child? is-layout-child? :is-layout-container? is-layout-container? - :layout-v-behavior (or (:layout-v-behavior values) :fix) - :layout-h-behavior (or (:layout-h-behavior values) :fix) + :layout-item-v-sizing (or (:layout-item-v-sizing values) :fix) + :layout-item-h-sizing (or (:layout-item-h-sizing values) :fix) :on-change-behavior on-change-behavior}]] @@ -201,14 +203,14 @@ :align-self align-self :set-align-self set-align-self}]]] [:div.input-wrapper - (for [item [:layout-max-h :layout-min-h :layout-max-w :layout-min-w]] + (for [item [:layout-item-max-h :layout-item-min-h :layout-item-max-w :layout-item-min-w]] [:div.tooltip.tooltip-bottom {:key (d/name item) :alt (tr (dm/str "workspace.options.layout-item.title." (d/name item))) - :class (dom/classnames "maxH" (= item :layout-max-h) - "minH" (= item :layout-min-h) - "maxW" (= item :layout-max-w) - "minW" (= item :layout-min-w))} + :class (dom/classnames "maxH" (= item :layout-item-max-h) + "minH" (= item :layout-item-min-h) + "maxW" (= item :layout-item-max-w) + "minW" (= item :layout-item-min-w))} [:div.input-element {:alt (tr (dm/str "workspace.options.layout-item." (d/name item)))} [:> numeric-input From 0274567d83fb69f85b82c65ebb8ac79bf3048a6f Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 27 Oct 2022 16:34:26 +0200 Subject: [PATCH 17/36] :sparkles: Visual adjustments --- common/src/app/common/types/shape/layout.cljc | 2 ++ frontend/resources/images/icons/layout-columns.svg | 3 +++ frontend/resources/images/icons/layout-rows.svg | 3 +++ .../main/partials/sidebar-element-options.scss | 4 ++++ frontend/src/app/main/refs.cljs | 8 ++++++++ frontend/src/app/main/ui/components/shape_icon.cljs | 11 ++++++++++- frontend/src/app/main/ui/icons.cljs | 2 ++ .../workspace/sidebar/options/menus/layout_item.cljs | 12 ++++++++---- .../ui/workspace/sidebar/options/menus/measures.cljs | 8 ++++++++ 9 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 frontend/resources/images/icons/layout-columns.svg create mode 100644 frontend/resources/images/icons/layout-rows.svg diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 32f54e16e..53aa8fc6e 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -97,6 +97,8 @@ ::layout-item-min-w ::layout-item-align-self])) +(defn layout? [shape] + (and (= :frame (:type shape)) (= :flex (:layout shape)))) (defn wrap? [{:keys [layout-wrap-type]}] (= layout-wrap-type :wrap)) diff --git a/frontend/resources/images/icons/layout-columns.svg b/frontend/resources/images/icons/layout-columns.svg new file mode 100644 index 000000000..4c9381c99 --- /dev/null +++ b/frontend/resources/images/icons/layout-columns.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/resources/images/icons/layout-rows.svg b/frontend/resources/images/icons/layout-rows.svg new file mode 100644 index 000000000..f09a1ced8 --- /dev/null +++ b/frontend/resources/images/icons/layout-rows.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/resources/styles/main/partials/sidebar-element-options.scss b/frontend/resources/styles/main/partials/sidebar-element-options.scss index 3c785391e..7e956838d 100644 --- a/frontend/resources/styles/main/partials/sidebar-element-options.scss +++ b/frontend/resources/styles/main/partials/sidebar-element-options.scss @@ -182,6 +182,10 @@ &.error { border-color: $color-danger; } + + &[disabled] { + color: $color-gray-30; + } } .input-select { diff --git a/frontend/src/app/main/refs.cljs b/frontend/src/app/main/refs.cljs index 4f6015f09..9c5f35f7c 100644 --- a/frontend/src/app/main/refs.cljs +++ b/frontend/src/app/main/refs.cljs @@ -265,6 +265,14 @@ [ids] (l/derived #(into [] (keep (d/getf %)) ids) workspace-page-objects =)) +(defn parents-by-ids + [ids] + (l/derived + (fn [objects] + (let [parent-ids (into #{} (keep #(get-in objects [% :parent-id])) ids)] + (into [] (keep #(get objects %)) parent-ids))) + workspace-page-objects =)) + (defn children-objects [id] (l/derived diff --git a/frontend/src/app/main/ui/components/shape_icon.cljs b/frontend/src/app/main/ui/components/shape_icon.cljs index 27a8794b9..ab42a2e4c 100644 --- a/frontend/src/app/main/ui/components/shape_icon.cljs +++ b/frontend/src/app/main/ui/components/shape_icon.cljs @@ -6,6 +6,7 @@ (ns app.main.ui.components.shape-icon (:require + [app.common.types.shape.layout :as ctl] [app.main.ui.icons :as i] [rumext.v2 :as mf])) @@ -13,7 +14,15 @@ (mf/defc element-icon [{:keys [shape main-instance?] :as props}] (case (:type shape) - :frame i/artboard + :frame (cond + (and (ctl/layout? shape) (ctl/col? shape)) + i/layout-columns + + (and (ctl/layout? shape) (ctl/row? shape)) + i/layout-rows + + :else + i/artboard) :image i/image :line i/line :circle i/circle diff --git a/frontend/src/app/main/ui/icons.cljs b/frontend/src/app/main/ui/icons.cljs index 69dd22c14..e6c073122 100644 --- a/frontend/src/app/main/ui/icons.cljs +++ b/frontend/src/app/main/ui/icons.cljs @@ -133,6 +133,8 @@ (def justify-content-row-end (icon-xref :justify-content-row-end)) (def justify-content-row-start (icon-xref :justify-content-row-start)) (def layers (icon-xref :layers)) +(def layout-columns (icon-xref :layout-columns)) +(def layout-rows (icon-xref :layout-rows)) (def letter-spacing (icon-xref :letter-spacing)) (def libraries (icon-xref :libraries)) (def library (icon-xref :library)) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs index 4ce0b57e3..c36017017 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs @@ -8,7 +8,9 @@ (:require [app.common.data :as d] [app.common.data.macros :as dm] + [app.common.types.shape.layout :as ctl] [app.main.data.workspace.shape-layout :as dwsl] + [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.numeric-input :refer [numeric-input]] [app.main.ui.icons :as i] @@ -129,7 +131,7 @@ {:class (dom/classnames :active (= align-self align) :tooltip-bottom-left (not= align :start) :tooltip-bottom (= align :start)) - :alt (dm/str "Align self " (d/name align)) ;; TODO aƱadir lineas de texto a tradus + :alt (dm/str "Align self " (d/name align)) :on-click #(set-align-self align) :key (str "align-self" align)} (get-layout-flex-icon :align-self align is-col?)])])) @@ -141,6 +143,9 @@ (let [open? (mf/use-state false) toggle-open (fn [] (swap! open? not)) + selection-parents-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) + selection-parents (mf/deref selection-parents-ref) + change-margin-style (fn [type] (st/emit! (dwsl/update-layout-child ids {:layout-item-margin-type type}))) @@ -151,8 +156,7 @@ (st/emit! (dwsl/update-layout-child ids {:layout-item-align-self nil})) (st/emit! (dwsl/update-layout-child ids {:layout-item-align-self value})))) - saved-dir (:layout-flex-dir values) - is-col? (or (= :column saved-dir) (= :reverse-column saved-dir)) + is-col? (every? ctl/col? selection-parents) on-margin-change (fn [type val] @@ -182,7 +186,7 @@ :layout-item-v-sizing (or (:layout-item-v-sizing values) :fix) :layout-item-h-sizing (or (:layout-item-h-sizing values) :fix) :on-change-behavior on-change-behavior}]] - + [:& margin-section {:values values :change-margin-style change-margin-style diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs index 2fdea6e9f..cba05bc1e 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs @@ -8,6 +8,7 @@ (:require [app.common.data :as d] [app.common.geom.shapes :as gsh] + [app.common.types.shape.layout :as ctl] [app.common.types.shape.radius :as ctsr] [app.main.constants :refer [size-presets]] [app.main.data.workspace :as udw] @@ -81,6 +82,11 @@ [shape]) frames (map #(deref (refs/object-by-id (:frame-id %))) old-shapes) + selection-parents-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) + selection-parents (mf/deref selection-parents-ref) + + flex-child? (->> selection-parents (some ctl/layout?)) + ;; To show interactively the measures while the user is manipulating ;; the shape with the mouse, generate a copy of the shapes applying ;; the transient transformations. @@ -327,11 +333,13 @@ :placeholder "--" :on-click select-all :on-change on-pos-x-change + :disabled flex-child? :value (:x values)}]] [:div.input-element.Yaxis {:title (tr "workspace.options.y")} [:> numeric-input {:no-validate true :placeholder "--" :on-click select-all + :disabled flex-child? :on-change on-pos-y-change :value (:y values)}]]]) From 7f0054959ff92dc096ddbe80638d2ba9ec5f4ca0 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Wed, 2 Nov 2022 14:14:22 +0100 Subject: [PATCH 18/36] :sparkles: Hug content to frames --- common/src/app/common/geom/shapes.cljc | 5 - .../app/common/geom/shapes/constraints.cljc | 2 +- .../app/common/geom/shapes/flex_layout.cljc | 11 +- .../geom/shapes/flex_layout/bounds.cljc | 113 +++++++++++ .../common/geom/shapes/flex_layout/lines.cljc | 14 +- .../geom/shapes/flex_layout/modifiers.cljc | 29 +-- .../src/app/common/geom/shapes/modifiers.cljc | 192 ++++++++++++------ common/src/app/common/geom/shapes/points.cljc | 17 +- common/src/app/common/geom/shapes/rect.cljc | 13 ++ .../app/common/geom/shapes/transforms.cljc | 33 ++- common/src/app/common/types/modifiers.cljc | 120 +++++++---- common/src/app/common/types/shape/layout.cljc | 6 + .../test/common_tests/geom_shapes_test.cljc | 2 - .../app/main/data/workspace/shape_layout.cljs | 7 +- frontend/src/app/main/refs.cljs | 3 +- .../sidebar/options/menus/layout_item.cljs | 25 ++- .../sidebar/options/shapes/frame.cljs | 25 +-- 17 files changed, 448 insertions(+), 169 deletions(-) create mode 100644 common/src/app/common/geom/shapes/flex_layout/bounds.cljc diff --git a/common/src/app/common/geom/shapes.cljc b/common/src/app/common/geom/shapes.cljc index 941e6b634..163a29b1c 100644 --- a/common/src/app/common/geom/shapes.cljc +++ b/common/src/app/common/geom/shapes.cljc @@ -13,7 +13,6 @@ [app.common.geom.shapes.common :as gco] [app.common.geom.shapes.constraints :as gct] [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.modifiers :as gsm] [app.common.geom.shapes.path :as gsp] @@ -184,10 +183,6 @@ ;; Constratins (dm/export gct/calc-child-modifiers) -;; Layout -(dm/export gcl/calc-layout-data) -(dm/export gcl/calc-layout-modifiers) - ;; PATHS (dm/export gsp/content->selrect) (dm/export gsp/transform-content) diff --git a/common/src/app/common/geom/shapes/constraints.cljc b/common/src/app/common/geom/shapes/constraints.cljc index ce4171d02..2be4becad 100644 --- a/common/src/app/common/geom/shapes/constraints.cljc +++ b/common/src/app/common/geom/shapes/constraints.cljc @@ -265,7 +265,7 @@ (if (and (= :scale constraints-h) (= :scale constraints-v)) 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) transformed-child (gst/transform-shape child modifiers) diff --git a/common/src/app/common/geom/shapes/flex_layout.cljc b/common/src/app/common/geom/shapes/flex_layout.cljc index 8361d230f..b61eabf09 100644 --- a/common/src/app/common/geom/shapes/flex_layout.cljc +++ b/common/src/app/common/geom/shapes/flex_layout.cljc @@ -7,12 +7,15 @@ (ns app.common.geom.shapes.flex-layout (:require [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.lines :as fli] [app.common.geom.shapes.flex-layout.modifiers :as fmo])) -(dm/export fli/calc-layout-data) -(dm/export fmo/normalize-child-modifiers) -(dm/export fmo/calc-layout-modifiers) -(dm/export fdr/layout-drop-areas) +(dm/export fbo/layout-content-bounds) (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) + diff --git a/common/src/app/common/geom/shapes/flex_layout/bounds.cljc b/common/src/app/common/geom/shapes/flex_layout/bounds.cljc new file mode 100644 index 000000000..e8cd52ce2 --- /dev/null +++ b/common/src/app/common/geom/shapes/flex_layout/bounds.cljc @@ -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 $)))) diff --git a/common/src/app/common/geom/shapes/flex_layout/lines.cljc b/common/src/app/common/geom/shapes/flex_layout/lines.cljc index c05a0cf52..e26894fa6 100644 --- a/common/src/app/common/geom/shapes/flex_layout/lines.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/lines.cljc @@ -34,10 +34,13 @@ "Calculates the lines basic data and accumulated values. The positions will be calculated in a different operation" [shape children layout-bounds] - (let [wrap? (ctl/wrap? shape) - col? (ctl/col? shape) + (let [col? (ctl/col? 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-width (gpo/width-points layout-bounds) layout-height (gpo/height-points layout-bounds) @@ -278,6 +281,12 @@ (update line-data :children-data (fn [children-data] (cond->> children-data + row? + (map #(assoc % :child-width (:child-min-width %))) + + col? + (map #(assoc % :child-height (:child-min-height %))) + row? (distribute-space :child-width :child-min-width :child-max-width line-min-width line-width) @@ -304,3 +313,4 @@ {:layout-lines layout-lines :reverse? reverse?})) + diff --git a/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc b/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc index 02e778550..fc0b60683 100644 --- a/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc @@ -13,10 +13,9 @@ [app.common.types.modifiers :as ctm] [app.common.types.shape.layout :as ctl])) - (defn normalize-child-modifiers "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) child-bb-before (gst/parent-coords-rect child parent) @@ -38,14 +37,16 @@ {:keys [children-data line-width] :as layout-data}] (cond - (and (ctl/row? parent) (ctl/fill-width? child)) - (let [target-width (get-in children-data [(:id child) :child-width]) + (ctl/row? parent) + (let [target-width (max (get-in children-data [(:id child) :child-width]) 0.01) fill-scale (/ target-width child-width)] {:width target-width :modifiers (ctm/resize (gpt/point fill-scale 1) child-origin transform transform-inverse)}) - (and (ctl/col? parent) (ctl/fill-width? child)) - (let [target-width (- line-width (ctl/child-width-margin child)) + (ctl/col? parent) + (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)] {:width target-width :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}] (cond - (and (ctl/col? parent) (ctl/fill-height? child)) - (let [target-height (get-in children-data [(:id child) :child-height]) + (ctl/col? parent) + (let [target-height (max (get-in children-data [(:id child) :child-height]) 0.01) fill-scale (/ target-height child-height)] {:height target-height :modifiers (ctm/resize (gpt/point 1 fill-scale) child-origin transform transform-inverse)}) - (and (ctl/row? parent) (ctl/fill-height? child)) - (let [target-height (- line-height (ctl/child-height-margin child)) + (ctl/row? parent) + (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)] {:height target-height :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" [parent child layout-line] (let [child-bounds (gst/parent-coords-points child parent) @@ -79,8 +82,8 @@ child-width (gpo/width-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-height (calc-fill-height-data parent child child-origin child-height layout-line) + fill-width (when (ctl/fill-width? child) (calc-fill-width-data parent child child-origin child-width 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-height (or (:height fill-height) child-height) diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index 31b86a297..9f7b9ae5c 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -7,27 +7,42 @@ (ns app.common.geom.shapes.modifiers (:require [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.flex-layout :as gcl] [app.common.geom.shapes.pixel-precision :as gpp] [app.common.geom.shapes.transforms :as gtr] [app.common.pages.helpers :as cph] [app.common.types.modifiers :as ctm] + [app.common.types.shape.layout :as ctl] [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 [modif-tree objects parent ignore-constraints snap-pixel?] - (letfn [(set-child [transformed-parent _snap-pixel? modif-tree child] - (let [modifiers (get-in modif-tree [(:id parent) :modifiers]) - child-modifiers (gct/calc-child-modifiers parent child modifiers ignore-constraints transformed-parent) - child-modifiers (cond-> child-modifiers snap-pixel? (gpp/set-pixel-precision child))] - (cond-> modif-tree - (not (ctm/empty-modifiers? child-modifiers)) - (update-in [(:id child) :modifiers] ctm/add-modifiers child-modifiers))))] - (let [children (map (d/getf objects) (:shapes parent)) - modifiers (get-in modif-tree [(:id parent) :modifiers]) - transformed-parent (gtr/transform-shape parent modifiers)] - (reduce (partial set-child transformed-parent snap-pixel?) modif-tree children)))) + (let [children (map (d/getf objects) (:shapes parent)) + modifiers (get-in modif-tree [(:id parent) :modifiers]) + transformed-parent (gtr/transform-shape parent modifiers) + parent (gtr/transform-shape parent (ctm/select-parent-modifiers modifiers)) + + set-child + (fn [modif-tree child] + (let [child-modifiers (gct/calc-child-modifiers parent child modifiers ignore-constraints transformed-parent) + child-modifiers (cond-> child-modifiers snap-pixel? (gpp/set-pixel-precision child))] + (cond-> modif-tree + (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] (or (= :group (:type shape)) @@ -36,17 +51,15 @@ (defn frame? [shape] (= :frame (:type shape))) -(defn layout? [shape] - (and (frame? shape) - (:layout shape))) - (defn set-layout-modifiers ;; TODO LAYOUT: 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]) - 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 (not (ctm/empty-modifiers? child-modifiers)) (update-in [(:id child) :modifiers] ctm/add-modifiers child-modifiers)))) @@ -60,9 +73,9 @@ (and (some? modifiers) (group? child)) (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] - (gcl/calc-layout-modifiers parent child layout-line) + (gcl/layout-child-modifiers parent child layout-line) modif-tree (cond-> modif-tree @@ -75,8 +88,9 @@ transformed-parent (gtr/transform-shape parent modifiers) 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))) + layout-data (gcl/calc-layout-data transformed-parent children) children (into [] (cond-> children (:reverse? layout-data) reverse)) max-idx (dec (count children)) @@ -92,11 +106,56 @@ children (subvec children from-idx to-idx) [_ 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)) 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 [id objects] @@ -109,7 +168,9 @@ result ;; 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))) result @@ -124,7 +185,9 @@ (defn resolve-tree-sequence "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 (fn [result id] @@ -152,10 +215,10 @@ (map #(get objects %)))) - roots (->> modif-tree keys (reduce redfn #{}))] + roots (->> ids (reduce redfn #{}))] (concat - (when (contains? modif-tree uuid/zero) [(get objects uuid/zero)]) + (when (contains? ids uuid/zero) [(get objects uuid/zero)]) (mapcat generate-tree roots)))) (defn inside-layout? @@ -173,48 +236,55 @@ :else (recur (:parent-id current)))))) -;;#?(:cljs -;; (defn modif->js -;; [modif-tree objects] -;; (clj->js (into {} -;; (map (fn [[k v]] -;; [(get-in objects [k :name]) v])) -;; modif-tree)))) +(defn- calculate-modifiers + ([objects snap-pixel? ignore-constraints [modif-tree recalculate] shape] + (calculate-modifiers objects snap-pixel? ignore-constraints false [modif-tree recalculate] shape)) + + ([objects snap-pixel? ignore-constraints ignore-auto? [modif-tree recalculate] shape] + (let [shape-id (:id shape) + 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 [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 - (->> shapes-tree - (reduce - (fn [modif-tree shape] - - (let [root? (= uuid/zero (:id shape)) + [modif-tree recalculate] + (reduce (partial calculate-modifiers objects snap-pixel? ignore-constraints) [modif-tree #{}] shapes-tree) - modifiers (get-in modif-tree [(:id shape) :modifiers]) - 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))] + shapes-tree (resolve-tree-sequence recalculate objects) + [modif-tree _] + (reduce (partial calculate-modifiers objects snap-pixel? ignore-constraints true) [modif-tree #{}] shapes-tree)] ;;#?(:cljs ;; (.log js/console ">result" (modif->js modif-tree objects))) diff --git a/common/src/app/common/geom/shapes/points.cljc b/common/src/app/common/geom/shapes/points.cljc index 1f80f28df..adae25ace 100644 --- a/common/src/app/common/geom/shapes/points.cljc +++ b/common/src/app/common/geom/shapes/points.cljc @@ -50,12 +50,13 @@ (defn pad-points [[p0 p1 p2 p3 :as points] pad-top pad-right pad-bottom pad-left] - (let [top-v (start-vv points pad-top) - right-v (end-hv points pad-right) - bottom-v (end-vv points pad-bottom) - left-v (start-hv points pad-left)] + (when (some? points) + (let [top-v (start-vv points pad-top) + right-v (end-hv points pad-right) + bottom-v (end-vv points pad-bottom) + left-v (start-hv points pad-left)] - [(-> p0 (gpt/add left-v) (gpt/add top-v)) - (-> p1 (gpt/add right-v) (gpt/add top-v)) - (-> p2 (gpt/add right-v) (gpt/add bottom-v)) - (-> p3 (gpt/add left-v) (gpt/add bottom-v))])) + [(-> p0 (gpt/add left-v) (gpt/add top-v)) + (-> p1 (gpt/add right-v) (gpt/add top-v)) + (-> p2 (gpt/add right-v) (gpt/add bottom-v)) + (-> p3 (gpt/add left-v) (gpt/add bottom-v))]))) diff --git a/common/src/app/common/geom/shapes/rect.cljc b/common/src/app/common/geom/shapes/rect.cljc index 895388371..d523f8321 100644 --- a/common/src/app/common/geom/shapes/rect.cljc +++ b/common/src/app/common/geom/shapes/rect.cljc @@ -87,6 +87,19 @@ (when (d/num? minx miny maxx maxy) (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] (when-let [rect (points->rect points)] (let [{:keys [x y width height]} rect] diff --git a/common/src/app/common/geom/shapes/transforms.cljc b/common/src/app/common/geom/shapes/transforms.cljc index ce888ddf1..bdaa87807 100644 --- a/common/src/app/common/geom/shapes/transforms.cljc +++ b/common/src/app/common/geom/shapes/transforms.cljc @@ -434,20 +434,35 @@ (map (comp gpr/points->selrect :points transform-shape)) (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 "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 - (->> (:shapes group) + (->> (:shapes parent) (map (d/getf objects)) - (map (fn [shape] - (let [modifiers (get modif-tree (:id shape)) - shape (-> shape (merge modifiers) transform-shape)] - (if (= :group (:type shape)) - (apply-group-modifiers shape objects modif-tree) - shape)))))] - (update-group-selrect group children))) + (apply-children-modifiers objects modif-tree))] + (->> children (mapcat :points) gpr/points->rect))) (defn parent-coords-rect [child parent] diff --git a/common/src/app/common/types/modifiers.cljc b/common/src/app/common/types/modifiers.cljc index fe308d402..a99c5b893 100644 --- a/common/src/app/common/types/modifiers.cljc +++ b/common/src/app/common/types/modifiers.cljc @@ -17,7 +17,11 @@ ;; --- Modifiers ;; Moodifiers types -;; - geometry: Geometry +;; - geometry-parent: Geometry non-recursive +;; * move +;; * resize +;; * rotation +;; - geometry-child: Geometry recursive ;; * move ;; * resize ;; * rotation @@ -28,7 +32,6 @@ ;; - structure-child: Structure recursive ;; * scale-content ;; * rotation -;; (def conjv (fnil conj [])) @@ -37,37 +40,59 @@ (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 ([modifiers x y] (set-move modifiers (gpt/point x y))) ([modifiers vector] (-> modifiers - (update :geometry conjv {:type :move :vector vector})))) + (update :geometry-child conjv {:type :move :vector vector})))) (defn set-resize ([modifiers vector origin] (-> modifiers - (update :geometry conjv {:type :resize - :vector vector - :origin origin}))) + (update :geometry-child conjv {:type :resize + :vector vector + :origin origin}))) ([modifiers vector origin transform transform-inverse] (-> modifiers - (update :geometry conjv {:type :resize - :vector vector - :origin origin - :transform transform - :transform-inverse transform-inverse})))) + (update :geometry-child conjv {:type :resize + :vector vector + :origin origin + :transform transform + :transform-inverse transform-inverse})))) (defn set-rotation [modifiers center angle] (-> modifiers (update :structure-child conjv {:type :rotation :rotation angle}) - (update :geometry conjv {:type :rotation - :center center - :rotation angle}))) + (update :geometry-child conjv {:type :rotation + :center center + :rotation angle}))) (defn set-remove-children [modifiers shapes] @@ -97,8 +122,11 @@ [modifiers new-modifiers] (cond-> modifiers - (some? (:geometry new-modifiers)) - (update :geometry #(d/concat-vec [] % (:geometry new-modifiers))) + (some? (:geometry-child 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)) (update :structure-parent #(d/concat-vec [] % (:structure-parent new-modifiers))) @@ -116,6 +144,13 @@ ([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 ([vector origin] (set-resize (empty-modifiers) vector origin)) @@ -123,6 +158,13 @@ ([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 [shape center angle] (let [shape-center (gco/center-shape shape) @@ -155,32 +197,30 @@ (set-scale-content value))) (defn child-modifiers? - [{:keys [geometry structure-child]}] - (or (d/not-empty? geometry) + [{:keys [geometry-child structure-child]}] + (or (d/not-empty? geometry-child) (d/not-empty? structure-child))) (defn select-child-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 [modifiers] (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? [modifiers] - (and (empty? (:geometry modifiers)) + (and (empty? (:geometry-child modifiers)) + (empty? (:geometry-parent modifiers)) (empty? (:structure-parent modifiers)) (empty? (:structure-child modifiers)))) @@ -253,8 +293,10 @@ (defn only-move? [modifier] - (and (= 1 (-> modifier :geometry count)) - (= :move (-> modifier :geometry first :type)))) + (or (and (= 1 (-> modifier :geometry-child count)) + (= :move (-> modifier :geometry-child first :type))) + (and (= 1 (-> modifier :geometry-parent count)) + (= :move (-> modifier :geometry-parent first :type))))) (defn get-frame-add-children [modif-tree] @@ -300,8 +342,11 @@ (gmt/multiply (gmt/rotate-matrix rotation)) (gmt/translate (gpt/negate center))) matrix)))] - (->> modifiers :geometry - (reduce apply-modifier (gmt/matrix))))) + (let [modifiers (if (d/not-empty? (:geometry-parent modifiers)) + (d/concat-vec (:geometry-parent modifiers) (:geometry-child modifiers)) + (:geometry-child modifiers))] + (->> modifiers + (reduce apply-modifier (gmt/matrix)))))) (defn scale-text-content [content value] @@ -357,5 +402,6 @@ (reduce apply-modifier $ (:structure-child modifiers))))) (defn has-geometry? - [{:keys [geometry]}] - (d/not-empty? geometry)) + [{:keys [geometry-parent geometry-child]}] + (or (d/not-empty? geometry-parent) + (d/not-empty? geometry-child))) diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 53aa8fc6e..8ab1f67c4 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -109,6 +109,12 @@ (defn fill-height? [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? [{:keys [layout-flex-dir]}] (or (= :column layout-flex-dir) (= :reverse-column layout-flex-dir))) diff --git a/common/test/common_tests/geom_shapes_test.cljc b/common/test/common_tests/geom_shapes_test.cljc index e36a487e7..eae43ef1b 100644 --- a/common/test/common_tests/geom_shapes_test.cljc +++ b/common/test/common_tests/geom_shapes_test.cljc @@ -142,8 +142,6 @@ shape-before (assoc shape-before :modifiers modifiers) 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]) (get-in shape-after [:selrect :x]))) diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index 9ab3536bc..956d24e1e 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -9,6 +9,7 @@ [app.common.data :as d] [app.common.pages.helpers :as cph] [app.common.types.modifiers :as ctm] + [app.common.types.shape.layout :as ctl] [app.main.data.workspace.changes :as dwc] [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.transforms :as dwt] @@ -68,7 +69,6 @@ (rx/of (dwc/update-shapes ids #(merge % initial-grid-layout)) (update-layout-positions ids)))))) - (defn remove-layout [ids] (ptk/reify ::remove-layout @@ -91,6 +91,7 @@ ptk/WatchEvent (watch [_ 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)) - (update-layout-positions parent-ids)))))) + (update-layout-positions (d/concat-vec layout-ids parent-ids))))))) diff --git a/frontend/src/app/main/refs.cljs b/frontend/src/app/main/refs.cljs index 9c5f35f7c..fe9b1ca48 100644 --- a/frontend/src/app/main/refs.cljs +++ b/frontend/src/app/main/refs.cljs @@ -11,6 +11,7 @@ [app.common.data.macros :as dm] [app.common.pages.helpers :as cph] [app.common.types.shape-tree :as ctt] + [app.common.types.shape.layout :as ctl] [app.main.data.workspace.state-helpers :as wsh] [app.main.store :as st] [okulary.core :as l])) @@ -442,7 +443,7 @@ (l/derived (fn [objects] (->> ids - (some #(-> (cph/get-parent objects %) :layout)))) + (some #(-> (cph/get-parent objects %) ctl/layout?)))) workspace-page-objects)) (defn get-flex-child-viewer? diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs index c36017017..97aff0879 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs @@ -80,7 +80,7 @@ (mf/defc element-behavior [{: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? - auto? is-layout-container?] + auto? is-layout-container?] [:div.btn-wrapper [:div.layout-behavior.horizontal @@ -98,7 +98,7 @@ (when auto? [:button.behavior-btn.tooltip.tooltip-bottom {: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)} i/auto-hug])] @@ -188,9 +188,11 @@ :on-change-behavior on-change-behavior}]] - [:& margin-section {:values values - :change-margin-style change-margin-style - :on-margin-change on-margin-change}] + (when is-layout-child? + [:& margin-section {:values values + :change-margin-style change-margin-style + :on-margin-change on-margin-change}]) + [:div.advanced-ops-container [:button.advanced-ops.toltip.tooltip-bottom {:on-click toggle-open @@ -200,12 +202,13 @@ (when @open? [:div.advanced-ops-body - [:div.layout-row - [:div.direction-wrap.row-title "Align"] - [:div.btn-wrapper - [:& align-self-row {:is-col? is-col? - :align-self align-self - :set-align-self set-align-self}]]] + (when is-layout-child? + [:div.layout-row + [:div.direction-wrap.row-title "Align"] + [:div.btn-wrapper + [:& align-self-row {:is-col? is-col? + :align-self align-self + :set-align-self set-align-self}]]]) [:div.input-wrapper (for [item [:layout-item-max-h :layout-item-min-h :layout-item-max-w :layout-item-min-w]] [:div.tooltip.tooltip-bottom diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs index 048fff5c0..219518ec1 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs @@ -6,6 +6,7 @@ (ns app.main.ui.workspace.sidebar.options.shapes.frame (:require + [app.common.types.shape.layout :as ctl] [app.main.features :as features] [app.main.refs :as refs] [app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]] @@ -35,7 +36,8 @@ 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? (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)] :values measure-values @@ -43,18 +45,17 @@ :shape shape}] [:& constraints-menu {:ids ids :values constraint-values}] - (when layout-active? - [:* - [:& layout-container-menu {:type type :ids [(:id shape)] :values layout-container-values}] + (when (or layout-active? is-layout-container?) + [:& layout-container-menu {:type type :ids [(:id shape)] :values layout-container-values}]) - (when is-layout-child? - [:& layout-item-menu - {:ids ids - :type type - :values layout-item-values - :is-layout-child? is-layout-child? - :is-layout-container? (:layout shape) - :shape shape}])]) + (when (and layout-active? (or is-layout-child? is-layout-container?)) + [:& layout-item-menu + {:ids ids + :type type + :values layout-item-values + :is-layout-child? is-layout-child? + :is-layout-container? is-layout-container? + :shape shape}]) [:& layer-menu {:ids ids :type type From 4ecc166055fb28736cfc7b3c4dec4b408fa0701a Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 3 Nov 2022 15:11:29 +0100 Subject: [PATCH 19/36] :sparkles: Remove fill/auto when resizing --- .../src/app/common/geom/shapes/modifiers.cljc | 9 +- common/src/app/common/pages/helpers.cljc | 9 +- common/src/app/common/types/modifiers.cljc | 15 +- common/src/app/common/types/shape/layout.cljc | 12 +- .../app/main/data/workspace/modifiers.cljs | 284 ++++++++++++++ .../app/main/data/workspace/selection.cljs | 7 +- .../app/main/data/workspace/shape_layout.cljs | 10 +- .../app/main/data/workspace/transforms.cljs | 347 +++--------------- frontend/src/app/main/refs.cljs | 7 +- .../sidebar/options/menus/measures.cljs | 8 + .../src/app/main/ui/workspace/viewport.cljs | 2 +- .../app/main/ui/workspace/viewport/debug.cljs | 40 +- frontend/src/app/util/snap_data.cljs | 78 ++-- 13 files changed, 479 insertions(+), 349 deletions(-) create mode 100644 frontend/src/app/main/data/workspace/modifiers.cljs diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index 9f7b9ae5c..878c97759 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -138,20 +138,21 @@ (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)) + (when (and (d/not-empty? children) (or (ctl/auto-height? transformed-parent) (ctl/auto-width? transformed-parent))) + (gcl/layout-content-bounds transformed-parent children)) modifiers (cond-> modifiers - (and (some? auto-width) (ctl/auto-width? parent)) + (and (some? auto-width) (ctl/auto-width? transformed-parent)) (set-parent-auto-width transformed-parent auto-width) - (and (some? auto-height) (ctl/auto-height? parent)) + (and (some? auto-height) (ctl/auto-height? transformed-parent)) (set-parent-auto-height transformed-parent auto-height))] (assoc-in modif-tree [(:id parent) :modifiers] modifiers)))) diff --git a/common/src/app/common/pages/helpers.cljc b/common/src/app/common/pages/helpers.cljc index f984574f5..55b3c571e 100644 --- a/common/src/app/common/pages/helpers.cljc +++ b/common/src/app/common/pages/helpers.cljc @@ -71,9 +71,12 @@ (defn get-children-ids [objects id] - (if-let [shapes (-> (get objects id) :shapes (some-> vec))] - (into shapes (mapcat #(get-children-ids objects %)) shapes) - [])) + (letfn [(get-children-ids-rec + [id processed] + (when (not (contains? processed id)) + (when-let [shapes (-> (get objects id) :shapes (some-> vec))] + (into shapes (mapcat #(get-children-ids-rec % (conj processed id))) shapes))))] + (get-children-ids-rec id #{}))) (defn get-children [objects id] diff --git a/common/src/app/common/types/modifiers.cljc b/common/src/app/common/types/modifiers.cljc index a99c5b893..25e17df9d 100644 --- a/common/src/app/common/types/modifiers.cljc +++ b/common/src/app/common/types/modifiers.cljc @@ -32,6 +32,7 @@ ;; - structure-child: Structure recursive ;; * scale-content ;; * rotation +;; * change-properties (def conjv (fnil conj [])) @@ -118,6 +119,13 @@ (-> modifiers (update :structure-child conjv {:type :scale-content :value value}))) +(defn set-change-property + [modifiers property value] + (-> modifiers + (update :structure-child conjv {:type :change-property + :property property + :value value}))) + (defn add-modifiers [modifiers new-modifiers] @@ -376,7 +384,7 @@ (d/removev remove? shapes))) apply-modifier - (fn [shape {:keys [type value index rotation]}] + (fn [shape {:keys [type property value index rotation]}] (cond-> shape (= type :rotation) (update :rotation #(mod (+ % rotation) 360)) @@ -395,7 +403,10 @@ (update :shapes remove-children value) (= type :scale-content) - (apply-scale-content value)))] + (apply-scale-content value) + + (= type :change-property) + (assoc property value)))] (as-> shape $ (reduce apply-modifier $ (:structure-parent modifiers)) diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 8ab1f67c4..87a1ad3fe 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -97,8 +97,16 @@ ::layout-item-min-w ::layout-item-align-self])) -(defn layout? [shape] - (and (= :frame (:type shape)) (= :flex (:layout shape)))) +(defn layout? + ([objects id] + (layout? (get objects id))) + ([shape] + (and (= :frame (:type shape)) (= :flex (:layout shape))))) + +(defn layout-child? [objects shape] + (let [parent-id (:parent-id shape) + parent (get objects parent-id)] + (layout? parent))) (defn wrap? [{:keys [layout-wrap-type]}] (= layout-wrap-type :wrap)) diff --git a/frontend/src/app/main/data/workspace/modifiers.cljs b/frontend/src/app/main/data/workspace/modifiers.cljs new file mode 100644 index 000000000..4861414e3 --- /dev/null +++ b/frontend/src/app/main/data/workspace/modifiers.cljs @@ -0,0 +1,284 @@ +;; 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.main.data.workspace.modifiers + "Events related with shapes transformations" + (:require + [app.common.data :as d] + [app.common.geom.point :as gpt] + [app.common.geom.shapes :as gsh] + [app.common.geom.shapes.flex-layout :as gsl] + [app.common.math :as mth] + [app.common.pages.common :as cpc] + [app.common.pages.helpers :as cph] + [app.common.spec :as us] + [app.common.types.modifiers :as ctm] + [app.main.data.workspace.changes :as dch] + [app.main.data.workspace.comments :as-alias dwcm] + [app.main.data.workspace.guides :as-alias dwg] + [app.main.data.workspace.state-helpers :as wsh] + [app.main.data.workspace.undo :as dwu] + [beicon.core :as rx] + [cljs.spec.alpha :as s] + [potok.core :as ptk])) + +;; -- temporary modifiers ------------------------------------------- + +;; During an interactive transformation of shapes (e.g. when resizing or rotating +;; a group with the mouse), there are a lot of objects that need to be modified +;; (in this case, the group and all its children). +;; +;; To avoid updating the shapes theirselves, and forcing redraw of all components +;; that depend on the "objects" global state, we set a "modifiers" structure, with +;; the changes that need to be applied, and store it in :workspace-modifiers global +;; variable. The viewport reads this and merges it into the objects list it uses to +;; paint the viewport content, redrawing only the objects that have new modifiers. +;; +;; When the interaction is finished (e.g. user releases mouse button), the +;; apply-modifiers event is done, that consolidates all modifiers into the base +;; geometric attributes of the shapes. + + +(defn- check-delta + "If the shape is a component instance, check its relative position respect the + root of the component, and see if it changes after applying a transformation." + [shape root transformed-shape transformed-root objects modif-tree] + (let [root + (cond + (:component-root? shape) + shape + + (nil? root) + (cph/get-root-shape objects shape) + + :else root) + + transformed-root + (cond + (:component-root? transformed-shape) + transformed-shape + + (nil? transformed-root) + (as-> (cph/get-root-shape objects transformed-shape) $ + (gsh/transform-shape (merge $ (get modif-tree (:id $))))) + + :else transformed-root) + + shape-delta + (when root + (gpt/point (- (gsh/left-bound shape) (gsh/left-bound root)) + (- (gsh/top-bound shape) (gsh/top-bound root)))) + + transformed-shape-delta + (when transformed-root + (gpt/point (- (gsh/left-bound transformed-shape) (gsh/left-bound transformed-root)) + (- (gsh/top-bound transformed-shape) (gsh/top-bound transformed-root)))) + + ;; There are cases in that the coordinates change slightly (e.g. when + ;; rounding to pixel, or when recalculating text positions in different + ;; zoom levels). To take this into account, we ignore movements smaller + ;; than 1 pixel. + distance (if (and shape-delta transformed-shape-delta) + (gpt/distance-vector shape-delta transformed-shape-delta) + (gpt/point 0 0)) + + ignore-geometry? (and (< (:x distance) 1) (< (:y distance) 1))] + + [root transformed-root ignore-geometry?])) + +(defn- get-ignore-tree + "Retrieves a map with the flag `ignore-geometry?` given a tree of modifiers" + ([modif-tree objects shape] + (get-ignore-tree modif-tree objects shape nil nil {})) + + ([modif-tree objects shape root transformed-root ignore-tree] + (let [children (map (d/getf objects) (:shapes shape)) + + shape-id (:id shape) + transformed-shape (gsh/transform-shape shape (get modif-tree shape-id)) + + [root transformed-root ignore-geometry?] + (check-delta shape root transformed-shape transformed-root objects modif-tree) + + ignore-tree (assoc ignore-tree shape-id ignore-geometry?) + + set-child + (fn [ignore-tree child] + (get-ignore-tree modif-tree objects child root transformed-root ignore-tree))] + + (reduce set-child ignore-tree children)))) + +(defn- update-grow-type + [shape old-shape] + (let [auto-width? (= :auto-width (:grow-type shape)) + auto-height? (= :auto-height (:grow-type shape)) + + changed-width? (not (mth/close? (:width shape) (:width old-shape))) + changed-height? (not (mth/close? (:height shape) (:height old-shape))) + + change-to-fixed? (or (and auto-width? (or changed-height? changed-width?)) + (and auto-height? changed-height?))] + (cond-> shape + change-to-fixed? + (assoc :grow-type :fixed)))) + +(defn- clear-local-transform [] + (ptk/reify ::clear-local-transform + ptk/UpdateEvent + (update [_ state] + (-> state + (dissoc :workspace-modifiers) + (dissoc ::current-move-selected))))) + +(defn create-modif-tree + [ids modifiers] + (us/verify (s/coll-of uuid?) ids) + (into {} (map #(vector % {:modifiers modifiers})) ids)) + +(defn build-modif-tree + [ids objects get-modifier] + (us/verify (s/coll-of uuid?) ids) + (into {} (map #(vector % {:modifiers (get-modifier (get objects %))})) ids)) + +(defn build-change-frame-modifiers + [modif-tree objects selected target-frame position] + + (let [origin-frame-ids (->> selected (group-by #(get-in objects [% :frame-id]))) + layout? (get-in objects [target-frame :layout]) + child-set (set (get-in objects [target-frame :shapes])) + drop-index (when layout? (gsl/get-drop-index target-frame objects position)) + + update-frame-modifiers + (fn [modif-tree [original-frame shapes]] + (let [shapes (->> shapes (d/removev #(= target-frame %))) + shapes (cond->> shapes + (and layout? (= original-frame target-frame)) + ;; When movining inside a layout frame remove the shapes that are not immediate children + (filterv #(contains? child-set %)))] + (cond-> modif-tree + (not= original-frame target-frame) + (-> (update-in [original-frame :modifiers] ctm/set-remove-children shapes) + (update-in [target-frame :modifiers] ctm/set-add-children shapes drop-index)) + + (and layout? (= original-frame target-frame)) + (update-in [target-frame :modifiers] ctm/set-add-children shapes drop-index))))] + + (reduce update-frame-modifiers modif-tree origin-frame-ids))) + +(defn modif->js + [modif-tree objects] + (clj->js (into {} + (map (fn [[k v]] + [(get-in objects [k :name]) v])) + modif-tree))) + +(defn set-modifiers + ([modif-tree] + (set-modifiers modif-tree false)) + + ([modif-tree ignore-constraints] + (set-modifiers modif-tree ignore-constraints false)) + + ([modif-tree ignore-constraints ignore-snap-pixel] + (ptk/reify ::set-modifiers + ptk/UpdateEvent + (update [_ state] + (let [objects + (wsh/lookup-page-objects state) + + snap-pixel? + (and (not ignore-snap-pixel) (contains? (:workspace-layout state) :snap-pixel-grid)) + + modif-tree + (gsh/set-objects-modifiers modif-tree objects ignore-constraints snap-pixel?)] + + (assoc state :workspace-modifiers modif-tree)))))) + +;; Rotation use different algorithm to calculate children modifiers (and do not use child constraints). +(defn set-rotation-modifiers + ([angle shapes] + (set-rotation-modifiers angle shapes (-> shapes gsh/selection-rect gsh/center-selrect))) + + ([angle shapes center] + (ptk/reify ::set-rotation-modifiers + ptk/UpdateEvent + (update [_ state] + (let [objects (wsh/lookup-page-objects state) + ids + (->> shapes + (remove #(get % :blocked false)) + (filter #((cpc/editable-attrs (:type %)) :rotation)) + (map :id)) + + get-modifier + (fn [shape] + (ctm/rotation shape center angle)) + + modif-tree + (-> (build-modif-tree ids objects get-modifier) + (gsh/set-objects-modifiers objects false false))] + + (assoc state :workspace-modifiers modif-tree)))))) + + +(defn apply-modifiers + ([] + (apply-modifiers nil)) + + ([{:keys [undo-transation?] :or {undo-transation? true}}] + (ptk/reify ::apply-modifiers + ptk/WatchEvent + (watch [_ state _] + (let [objects (wsh/lookup-page-objects state) + object-modifiers (get state :workspace-modifiers) + + ids (or (keys object-modifiers) []) + ids-with-children (into (vec ids) (mapcat #(cph/get-children-ids objects %)) ids) + + shapes (map (d/getf objects) ids) + ignore-tree (->> (map #(get-ignore-tree object-modifiers objects %) shapes) + (reduce merge {}))] + + (rx/concat + (if undo-transation? + (rx/of (dwu/start-undo-transaction)) + (rx/empty)) + (rx/of (ptk/event ::dwg/move-frame-guides ids-with-children) + (ptk/event ::dwcm/move-frame-comment-threads ids-with-children) + (dch/update-shapes + ids + (fn [shape] + (let [modif (get-in object-modifiers [(:id shape) :modifiers]) + text-shape? (cph/text-shape? shape)] + (-> shape + (gsh/transform-shape modif) + (cond-> text-shape? + (update-grow-type shape))))) + {:reg-objects? true + :ignore-tree ignore-tree + ;; Attributes that can change in the transform. This way we don't have to check + ;; all the attributes + :attrs [:selrect + :points + :x + :y + :width + :height + :content + :transform + :transform-inverse + :rotation + :position-data + :flip-x + :flip-y + :grow-type + :layout-item-h-sizing + :layout-item-v-sizing + ]}) + (clear-local-transform)) + (if undo-transation? + (rx/of (dwu/commit-undo-transaction)) + (rx/empty)))))))) diff --git a/frontend/src/app/main/data/workspace/selection.cljs b/frontend/src/app/main/data/workspace/selection.cljs index e662eb486..4d3dffaa7 100644 --- a/frontend/src/app/main/data/workspace/selection.cljs +++ b/frontend/src/app/main/data/workspace/selection.cljs @@ -21,6 +21,7 @@ [app.main.data.modal :as md] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.collapse :as dwc] + [app.main.data.workspace.shape-layout :as dwsl] [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.thumbnails :as dwt] [app.main.data.workspace.zoom :as dwz] @@ -552,8 +553,11 @@ (filter #(= :frame (get-in % [:obj :type]))) (map #(vector (:old-id %) (get-in % [:obj :id])))) - id-duplicated (first new-selected)] + id-duplicated (first new-selected) + frames (into #{} + (map #(get-in objects [% :frame-id])) + selected)] (rx/concat (->> (rx/from dup-frames) (rx/map (fn [[old-id new-id]] (dwt/duplicate-thumbnail old-id new-id)))) @@ -561,6 +565,7 @@ ;; Warning: This order is important for the focus mode. (rx/of (dch/commit-changes changes) (select-shapes new-selected) + (dwsl/update-layout-positions frames) (memorize-duplicated id-original id-duplicated)))))))))) (defn change-hover-state diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index 956d24e1e..1e6864349 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -11,8 +11,8 @@ [app.common.types.modifiers :as ctm] [app.common.types.shape.layout :as ctl] [app.main.data.workspace.changes :as dwc] + [app.main.data.workspace.modifiers :as dwm] [app.main.data.workspace.state-helpers :as wsh] - [app.main.data.workspace.transforms :as dwt] [beicon.core :as rx] [potok.core :as ptk])) @@ -50,11 +50,11 @@ ptk/WatchEvent (watch [_ state _] (let [objects (wsh/lookup-page-objects state) - ids (->> ids (filter #(get-in objects [% :layout])))] + ids (->> ids (filter (partial ctl/layout? objects)))] (if (d/not-empty? ids) - (let [modif-tree (dwt/create-modif-tree ids (ctm/reflow))] - (rx/of (dwt/set-modifiers modif-tree) - (dwt/apply-modifiers))) + (let [modif-tree (dwm/create-modif-tree ids (ctm/reflow))] + (rx/of (dwm/set-modifiers modif-tree) + (dwm/apply-modifiers))) (rx/empty)))))) ;; TODO LAYOUT: Remove constraints from children diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 1769d41ae..9ec4c4383 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -14,15 +14,14 @@ [app.common.geom.shapes.flex-layout :as gsl] [app.common.math :as mth] [app.common.pages.changes-builder :as pcb] - [app.common.pages.common :as cpc] [app.common.pages.helpers :as cph] [app.common.spec :as us] [app.common.types.modifiers :as ctm] [app.common.types.shape-tree :as ctst] + [app.common.types.shape.layout :as ctl] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.collapse :as dwc] - [app.main.data.workspace.comments :as-alias dwcm] - [app.main.data.workspace.guides :as-alias dwg] + [app.main.data.workspace.modifiers :as dwm] [app.main.data.workspace.selection :as dws] [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.undo :as dwu] @@ -97,269 +96,12 @@ (update state :workspace-local dissoc :transform)))) -;; -- Temporary modifiers ------------------------------------------- - -;; During an interactive transformation of shapes (e.g. when resizing or rotating -;; a group with the mouse), there are a lot of objects that need to be modified -;; (in this case, the group and all its children). -;; -;; To avoid updating the shapes theirselves, and forcing redraw of all components -;; that depend on the "objects" global state, we set a "modifiers" structure, with -;; the changes that need to be applied, and store it in :workspace-modifiers global -;; variable. The viewport reads this and merges it into the objects list it uses to -;; paint the viewport content, redrawing only the objects that have new modifiers. -;; -;; When the interaction is finished (e.g. user releases mouse button), the -;; apply-modifiers event is done, that consolidates all modifiers into the base -;; geometric attributes of the shapes. - -(declare clear-local-transform) - -(declare get-ignore-tree) - -(defn create-modif-tree - [ids modifiers] - (us/verify (s/coll-of uuid?) ids) - (into {} (map #(vector % {:modifiers modifiers})) ids)) - -(defn build-modif-tree - [ids objects get-modifier] - (us/verify (s/coll-of uuid?) ids) - (into {} (map #(vector % {:modifiers (get-modifier (get objects %))})) ids)) - -(defn build-change-frame-modifiers - [modif-tree objects selected target-frame position] - - (let [origin-frame-ids (->> selected (group-by #(get-in objects [% :frame-id]))) - layout? (get-in objects [target-frame :layout]) - child-set (set (get-in objects [target-frame :shapes])) - drop-index (when layout? (gsl/get-drop-index target-frame objects position)) - - update-frame-modifiers - (fn [modif-tree [original-frame shapes]] - (let [shapes (->> shapes (d/removev #(= target-frame %))) - shapes (cond->> shapes - (and layout? (= original-frame target-frame)) - ;; When movining inside a layout frame remove the shapes that are not immediate children - (filterv #(contains? child-set %)))] - (cond-> modif-tree - (not= original-frame target-frame) - (-> (update-in [original-frame :modifiers] ctm/set-remove-children shapes) - (update-in [target-frame :modifiers] ctm/set-add-children shapes drop-index)) - - (and layout? (= original-frame target-frame)) - (update-in [target-frame :modifiers] ctm/set-add-children shapes drop-index))))] - - (reduce update-frame-modifiers modif-tree origin-frame-ids))) - -(defn modif->js - [modif-tree objects] - (clj->js (into {} - (map (fn [[k v]] - [(get-in objects [k :name]) v])) - modif-tree))) - -(defn set-modifiers - ([modif-tree] - (set-modifiers modif-tree false)) - - ([modif-tree ignore-constraints] - (set-modifiers modif-tree ignore-constraints false)) - - ([modif-tree ignore-constraints ignore-snap-pixel] - (ptk/reify ::set-modifiers - ptk/UpdateEvent - (update [_ state] - (let [objects - (wsh/lookup-page-objects state) - - snap-pixel? - (and (not ignore-snap-pixel) (contains? (:workspace-layout state) :snap-pixel-grid)) - - modif-tree - (gsh/set-objects-modifiers modif-tree objects ignore-constraints snap-pixel?)] - - (assoc state :workspace-modifiers modif-tree)))))) - -;; Rotation use different algorithm to calculate children modifiers (and do not use child constraints). -(defn- set-rotation-modifiers - ([angle shapes] - (set-rotation-modifiers angle shapes (-> shapes gsh/selection-rect gsh/center-selrect))) - - ([angle shapes center] - (ptk/reify ::set-rotation-modifiers - ptk/UpdateEvent - (update [_ state] - (let [objects (wsh/lookup-page-objects state) - ids - (->> shapes - (remove #(get % :blocked false)) - (filter #((cpc/editable-attrs (:type %)) :rotation)) - (map :id)) - - get-modifier - (fn [shape] - (ctm/rotation shape center angle)) - - modif-tree - (-> (build-modif-tree ids objects get-modifier) - (gsh/set-objects-modifiers objects false false))] - - (assoc state :workspace-modifiers modif-tree)))))) - -(defn- update-grow-type - [shape old-shape] - (let [auto-width? (= :auto-width (:grow-type shape)) - auto-height? (= :auto-height (:grow-type shape)) - - changed-width? (not (mth/close? (:width shape) (:width old-shape))) - changed-height? (not (mth/close? (:height shape) (:height old-shape))) - - change-to-fixed? (or (and auto-width? (or changed-height? changed-width?)) - (and auto-height? changed-height?))] - (cond-> shape - change-to-fixed? - (assoc :grow-type :fixed)))) - -(defn apply-modifiers - ([] - (apply-modifiers nil)) - - ([{:keys [undo-transation?] :or {undo-transation? true}}] - (ptk/reify ::apply-modifiers - ptk/WatchEvent - (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) - object-modifiers (get state :workspace-modifiers) - - ids (or (keys object-modifiers) []) - ids-with-children (into (vec ids) (mapcat #(cph/get-children-ids objects %)) ids) - - shapes (map (d/getf objects) ids) - ignore-tree (->> (map #(get-ignore-tree object-modifiers objects %) shapes) - (reduce merge {}))] - - (rx/concat - (if undo-transation? - (rx/of (dwu/start-undo-transaction)) - (rx/empty)) - (rx/of (ptk/event ::dwg/move-frame-guides ids-with-children) - (ptk/event ::dwcm/move-frame-comment-threads ids-with-children) - (dch/update-shapes - ids - (fn [shape] - (let [modif (get-in object-modifiers [(:id shape) :modifiers]) - text-shape? (cph/text-shape? shape)] - (-> shape - (gsh/transform-shape modif) - (cond-> text-shape? - (update-grow-type shape))))) - {:reg-objects? true - :ignore-tree ignore-tree - ;; Attributes that can change in the transform. This way we don't have to check - ;; all the attributes - :attrs [:selrect - :points - :x - :y - :width - :height - :content - :transform - :transform-inverse - :rotation - :position-data - :flip-x - :flip-y - :grow-type]}) - (clear-local-transform)) - (if undo-transation? - (rx/of (dwu/commit-undo-transaction)) - (rx/empty)))))))) - -(defn- check-delta - "If the shape is a component instance, check its relative position respect the - root of the component, and see if it changes after applying a transformation." - [shape root transformed-shape transformed-root objects modif-tree] - (let [root - (cond - (:component-root? shape) - shape - - (nil? root) - (cph/get-root-shape objects shape) - - :else root) - - transformed-root - (cond - (:component-root? transformed-shape) - transformed-shape - - (nil? transformed-root) - (as-> (cph/get-root-shape objects transformed-shape) $ - (gsh/transform-shape (merge $ (get modif-tree (:id $))))) - - :else transformed-root) - - shape-delta - (when root - (gpt/point (- (gsh/left-bound shape) (gsh/left-bound root)) - (- (gsh/top-bound shape) (gsh/top-bound root)))) - - transformed-shape-delta - (when transformed-root - (gpt/point (- (gsh/left-bound transformed-shape) (gsh/left-bound transformed-root)) - (- (gsh/top-bound transformed-shape) (gsh/top-bound transformed-root)))) - - ;; There are cases in that the coordinates change slightly (e.g. when - ;; rounding to pixel, or when recalculating text positions in different - ;; zoom levels). To take this into account, we ignore movements smaller - ;; than 1 pixel. - distance (if (and shape-delta transformed-shape-delta) - (gpt/distance-vector shape-delta transformed-shape-delta) - (gpt/point 0 0)) - - ignore-geometry? (and (< (:x distance) 1) (< (:y distance) 1))] - - [root transformed-root ignore-geometry?])) - -(defn- get-ignore-tree - "Retrieves a map with the flag `ignore-geometry?` given a tree of modifiers" - ([modif-tree objects shape] - (get-ignore-tree modif-tree objects shape nil nil {})) - - ([modif-tree objects shape root transformed-root ignore-tree] - (let [children (map (d/getf objects) (:shapes shape)) - - shape-id (:id shape) - transformed-shape (gsh/transform-shape shape (get modif-tree shape-id)) - - [root transformed-root ignore-geometry?] - (check-delta shape root transformed-shape transformed-root objects modif-tree) - - ignore-tree (assoc ignore-tree shape-id ignore-geometry?) - - set-child - (fn [ignore-tree child] - (get-ignore-tree modif-tree objects child root transformed-root ignore-tree))] - - (reduce set-child ignore-tree children)))) - -(defn- clear-local-transform [] - (ptk/reify ::clear-local-transform - ptk/UpdateEvent - (update [_ state] - (-> state - (dissoc :workspace-modifiers) - (dissoc ::current-move-selected))))) - ;; -- Resize -------------------------------------------------------- (defn start-resize "Enter mouse resize mode, until mouse button is released." [handler ids shape] - (letfn [(resize [shape initial layout [point lock? center? point-snap]] + (letfn [(resize [shape objects initial layout [point lock? center? point-snap]] (let [{:keys [width height]} (:selrect shape) {:keys [rotation]} shape @@ -423,18 +165,42 @@ (some? displacement) (gpt/add displacement)) + ;; When the horizontal/vertical scale a flex children with auto/fill + ;; we change it too fixed + layout? (ctl/layout? shape) + layout-child? (ctl/layout-child? objects shape) + auto-width? (ctl/auto-width? shape) + fill-width? (ctl/fill-width? shape) + auto-height? (ctl/auto-height? shape) + fill-height? (ctl/fill-height? shape) + + set-fix-width? + (and (not (mth/close? (:x scalev) 1)) + (or (and (or layout? layout-child?) auto-width?) + (and layout-child? fill-width?))) + + set-fix-height? + (and (not (mth/close? (:y scalev) 1)) + (or (and (or layout? layout-child?) auto-height?) + (and layout-child? fill-height?))) + modifiers (-> (ctm/empty-modifiers) (cond-> displacement (ctm/set-move displacement)) (ctm/set-resize scalev resize-origin shape-transform shape-transform-inverse) + (cond-> set-fix-width? + (ctm/set-change-property :layout-item-h-sizing :fix)) + + (cond-> set-fix-height? + (ctm/set-change-property :layout-item-v-sizing :fix)) + (cond-> scale-text (ctm/set-scale-content (:x scalev)))) - modif-tree (create-modif-tree ids modifiers)] - - (rx/of (set-modifiers modif-tree)))) + modif-tree (dwm/create-modif-tree ids modifiers)] + (rx/of (dwm/set-modifiers modif-tree)))) ;; Unifies the instantaneous proportion lock modifier ;; activated by Shift key and the shapes own proportion @@ -458,6 +224,7 @@ zoom (get-in state [:workspace-local :zoom] 1) objects (wsh/lookup-page-objects state page-id) resizing-shapes (map #(get objects %) ids)] + (rx/concat (->> ms/mouse-position (rx/with-latest-from ms/mouse-position-shift ms/mouse-position-alt) @@ -465,9 +232,9 @@ (rx/switch-map (fn [[point _ _ :as current]] (->> (snap/closest-snap-point page-id resizing-shapes objects layout zoom focus point) (rx/map #(conj current %))))) - (rx/mapcat (partial resize shape initial-position layout)) + (rx/mapcat (partial resize shape objects initial-position layout)) (rx/take-until stoper)) - (rx/of (apply-modifiers) + (rx/of (dwm/apply-modifiers) (finish-transform)))))))) (defn update-dimensions @@ -487,14 +254,14 @@ (fn [shape] (ctm/change-dimensions shape attr value)) modif-tree - (-> (build-modif-tree ids objects get-modifier) + (-> (dwm/build-modif-tree ids objects get-modifier) (gsh/set-objects-modifiers objects false snap-pixel?))] (assoc state :workspace-modifiers modif-tree))) ptk/WatchEvent (watch [_ _ _] - (rx/of (apply-modifiers))))) + (rx/of (dwm/apply-modifiers))))) (defn change-orientation "Change orientation of shapes, from the sidebar options form. @@ -512,14 +279,14 @@ (fn [shape] (ctm/change-orientation-modifiers shape orientation)) modif-tree - (-> (build-modif-tree ids objects get-modifier) + (-> (dwm/build-modif-tree ids objects get-modifier) (gsh/set-objects-modifiers objects false snap-pixel?))] (assoc state :workspace-modifiers modif-tree))) ptk/WatchEvent (watch [_ _ _] - (rx/of (apply-modifiers))))) + (rx/of (dwm/apply-modifiers))))) ;; -- Rotate -------------------------------------------------------- @@ -560,9 +327,9 @@ (rx/map (fn [[[pos mod?] shift?]] (let [delta-angle (calculate-angle pos mod? shift?)] - (set-rotation-modifiers delta-angle shapes group-center)))) + (dwm/set-rotation-modifiers delta-angle shapes group-center)))) (rx/take-until stoper)) - (rx/of (apply-modifiers) + (rx/of (dwm/apply-modifiers) (finish-transform))))))) (defn increase-rotation @@ -576,10 +343,10 @@ objects (wsh/lookup-page-objects state page-id) rotate-shape (fn [shape] (let [delta (- rotation (:rotation shape))] - (set-rotation-modifiers delta [shape])))] + (dwm/set-rotation-modifiers delta [shape])))] (rx/concat (rx/from (->> ids (map #(get objects %)) (map rotate-shape))) - (rx/of (apply-modifiers))))))) + (rx/of (dwm/apply-modifiers))))))) ;; -- Move ---------------------------------------------------------- @@ -705,15 +472,15 @@ (fn [move-vector] (let [position (gpt/add from-position move-vector) target-frame (ctst/top-nested-frame objects position)] - (-> (create-modif-tree ids (ctm/move move-vector)) - (build-change-frame-modifiers objects selected target-frame position) - (set-modifiers))))) + (-> (dwm/create-modif-tree ids (ctm/move move-vector)) + (dwm/build-change-frame-modifiers objects selected target-frame position) + (dwm/set-modifiers))))) (rx/take-until stopper))) (rx/of (dwu/start-undo-transaction) (calculate-frame-for-move ids) - (apply-modifiers {:undo-transation? false}) + (dwm/apply-modifiers {:undo-transation? false}) (finish-transform) (dwu/commit-undo-transaction))))))))) @@ -756,12 +523,12 @@ (rx/merge (->> move-events (rx/scan #(gpt/add %1 mov-vec) (gpt/point 0 0)) - (rx/map #(create-modif-tree selected (ctm/move %))) - (rx/map (partial set-modifiers)) + (rx/map #(dwm/create-modif-tree selected (ctm/move %))) + (rx/map (partial dwm/set-modifiers)) (rx/take-until stopper)) (rx/of (move-selected direction shift?))) - (rx/of (apply-modifiers) + (rx/of (dwm/apply-modifiers) (finish-transform)))) (rx/empty)))))) @@ -789,10 +556,10 @@ (or (:y position) (:y bbox))) delta (gpt/subtract pos cpos) - modif-tree (create-modif-tree [id] (ctm/move delta))] + modif-tree (dwm/create-modif-tree [id] (ctm/move delta))] - (rx/of (set-modifiers modif-tree) - (apply-modifiers)))))) + (rx/of (dwm/set-modifiers modif-tree) + (dwm/apply-modifiers)))))) (defn- calculate-frame-for-move [ids] @@ -851,14 +618,14 @@ selrect (gsh/selection-rect shapes) origin (gpt/point (:x selrect) (+ (:y selrect) (/ (:height selrect) 2))) - modif-tree (create-modif-tree + modif-tree (dwm/create-modif-tree selected (-> (ctm/empty-modifiers) (ctm/set-resize (gpt/point -1.0 1.0) origin) (ctm/move (gpt/point (:width selrect) 0))))] - (rx/of (set-modifiers modif-tree true) - (apply-modifiers)))))) + (rx/of (dwm/set-modifiers modif-tree true) + (dwm/apply-modifiers)))))) (defn flip-vertical-selected [] (ptk/reify ::flip-vertical-selected @@ -870,11 +637,11 @@ selrect (gsh/selection-rect shapes) origin (gpt/point (+ (:x selrect) (/ (:width selrect) 2)) (:y selrect)) - modif-tree (create-modif-tree + modif-tree (dwm/create-modif-tree selected (-> (ctm/empty-modifiers) (ctm/set-resize (gpt/point 1.0 -1.0) origin) (ctm/move (gpt/point 0 (:height selrect)))))] - (rx/of (set-modifiers modif-tree true) - (apply-modifiers)))))) + (rx/of (dwm/set-modifiers modif-tree true) + (dwm/apply-modifiers)))))) diff --git a/frontend/src/app/main/refs.cljs b/frontend/src/app/main/refs.cljs index fe9b1ca48..72e4420d1 100644 --- a/frontend/src/app/main/refs.cljs +++ b/frontend/src/app/main/refs.cljs @@ -443,7 +443,8 @@ (l/derived (fn [objects] (->> ids - (some #(-> (cph/get-parent objects %) ctl/layout?)))) + (map (d/getf objects)) + (some (partial ctl/layout-child? objects)))) workspace-page-objects)) (defn get-flex-child-viewer? @@ -452,8 +453,8 @@ (fn [state] (let [objects (wsh/lookup-viewer-objects state page-id)] (into [] - (comp (filter #(= :flex (:layout (cph/get-parent objects %)))) - (map #(get objects %))) + (comp (filter (partial ctl/layout-child? objects)) + (map (d/getf objects))) ids))) st/state =)) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs index cba05bc1e..6488fafe0 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs @@ -87,6 +87,12 @@ flex-child? (->> selection-parents (some ctl/layout?)) + flex-container? (ctl/layout? shape) + flex-auto-width? (ctl/auto-width? shape) + flex-fill-width? (ctl/fill-width? shape) + flex-auto-height? (ctl/auto-height? shape) + flex-fill-height? (ctl/fill-height? shape) + ;; To show interactively the measures while the user is manipulating ;; the shape with the mouse, generate a copy of the shapes applying ;; the transient transformations. @@ -306,6 +312,7 @@ :placeholder "--" :on-click select-all :on-change on-width-change + :disabled (and (or flex-child? flex-container?) (or flex-auto-width? flex-fill-width?)) :value (:width values)}]] [:div.input-element.height {:title (tr "workspace.options.height")} @@ -314,6 +321,7 @@ :placeholder "--" :on-click select-all :on-change on-height-change + :disabled (and (or flex-child? flex-container?) (or flex-auto-height? flex-fill-height?)) :value (:height values)}]] [:div.lock-size {:class (dom/classnames diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index 2896f6d4b..586e1b389 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -286,7 +286,7 @@ (when show-frame-outline? [:& outline/shape-outlines - {:objects base-objects + {:objects objects-modified :hover #{(->> @hover-ids (filter #(cph/frame-shape? (get base-objects %))) (remove selected) diff --git a/frontend/src/app/main/ui/workspace/viewport/debug.cljs b/frontend/src/app/main/ui/workspace/viewport/debug.cljs index 869caa8ca..d338c0a71 100644 --- a/frontend/src/app/main/ui/workspace/viewport/debug.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/debug.cljs @@ -13,6 +13,44 @@ [app.common.pages.helpers :as cph] [rumext.v2 :as mf])) +;; Helper to debug the bounds when set the "hug" content property +#_(mf/defc debug-bounds + "Debug component to show the auto-layout drop areas" + {::mf/wrap-props false} + [props] + + (let [objects (unchecked-get props "objects") + selected-shapes (unchecked-get props "selected-shapes") + hover-top-frame-id (unchecked-get props "hover-top-frame-id") + + selected-frame + (when (and (= (count selected-shapes) 1) (= :frame (-> selected-shapes first :type))) + (first selected-shapes)) + + shape (or selected-frame (get objects hover-top-frame-id))] + + (when (and shape (:layout shape)) + (let [children (cph/get-immediate-children objects (:id shape)) + layout-data (gsl/calc-layout-data shape children) + + {pad-top :p1 pad-right :p2 pad-bottom :p3 pad-left :p4} (:layout-padding shape) + pad-top (or pad-top 0) + pad-right (or pad-right 0) + pad-bottom (or pad-bottom 0) + pad-left (or pad-left 0) + + layout-bounds (gsl/layout-content-bounds shape children)] + [:g.debug-layout {:pointer-events "none" + :transform (gsh/transform-str shape)} + + + [:rect {:x (:x layout-bounds) + :y (:y layout-bounds) + :width (:width layout-bounds) + :height (:height layout-bounds) + :style {:stroke "red" + :fill "none"}}]])))) + (mf/defc debug-layout "Debug component to show the auto-layout drop areas" {::mf/wrap-props false} @@ -27,7 +65,7 @@ (first selected-shapes)) shape (or selected-frame (get objects hover-top-frame-id))] - + (when (and shape (:layout shape)) (let [children (cph/get-immediate-children objects (:id shape)) layout-data (gsl/calc-layout-data shape children) diff --git a/frontend/src/app/util/snap_data.cljs b/frontend/src/app/util/snap_data.cljs index 865162aa3..1de3b7a25 100644 --- a/frontend/src/app/util/snap_data.cljs +++ b/frontend/src/app/util/snap_data.cljs @@ -13,6 +13,7 @@ [app.common.pages.diff :as diff] [app.common.pages.helpers :as cph] [app.common.types.shape-tree :as ctst] + [app.common.types.shape.layout :as ctl] [app.common.uuid :as uuid] [app.util.geom.grid :as gg] [app.util.geom.snap-points :as snap] @@ -70,7 +71,7 @@ (mapv grid->snap))))) (defn- add-frame - [page-data frame] + [objects page-data frame] (let [frame-id (:id frame) parent-id (:parent-id frame) frame-data (->> (snap/shape-snap-points frame) @@ -79,21 +80,24 @@ :pt %))) grid-x-data (get-grids-snap-points frame :x) grid-y-data (get-grids-snap-points frame :y)] - (-> page-data - ;; Update root frame information - (assoc-in [uuid/zero :objects-data frame-id] frame-data) - (update-in [parent-id :x] (make-insert-tree-data frame-data :x)) - (update-in [parent-id :y] (make-insert-tree-data frame-data :y)) - ;; Update frame information - (assoc-in [frame-id :objects-data frame-id] (d/concat-vec frame-data grid-x-data grid-y-data)) - (update-in [frame-id :x] #(or % (rt/make-tree))) - (update-in [frame-id :y] #(or % (rt/make-tree))) - (update-in [frame-id :x] (make-insert-tree-data (d/concat-vec frame-data grid-x-data) :x)) - (update-in [frame-id :y] (make-insert-tree-data (d/concat-vec frame-data grid-y-data) :y))))) + (cond-> page-data + (not (ctl/layout-child? objects frame)) + + (-> ;; Update root frame information + (assoc-in [uuid/zero :objects-data frame-id] frame-data) + (update-in [parent-id :x] (make-insert-tree-data frame-data :x)) + (update-in [parent-id :y] (make-insert-tree-data frame-data :y)) + + ;; Update frame information + (assoc-in [frame-id :objects-data frame-id] (d/concat-vec frame-data grid-x-data grid-y-data)) + (update-in [frame-id :x] #(or % (rt/make-tree))) + (update-in [frame-id :y] #(or % (rt/make-tree))) + (update-in [frame-id :x] (make-insert-tree-data (d/concat-vec frame-data grid-x-data) :x)) + (update-in [frame-id :y] (make-insert-tree-data (d/concat-vec frame-data grid-y-data) :y)))))) (defn- add-shape - [page-data shape] + [objects page-data shape] (let [frame-id (:frame-id shape) snap-points (snap/shape-snap-points shape) shape-data (->> snap-points @@ -101,11 +105,11 @@ :type :shape :id (:id shape) :pt %)))] - (-> page-data - (assoc-in [frame-id :objects-data (:id shape)] shape-data) - (update-in [frame-id :x] (make-insert-tree-data shape-data :x)) - (update-in [frame-id :y] (make-insert-tree-data shape-data :y))))) - + (cond-> page-data + (not (ctl/layout-child? objects shape)) + (-> (assoc-in [frame-id :objects-data (:id shape)] shape-data) + (update-in [frame-id :x] (make-insert-tree-data shape-data :x)) + (update-in [frame-id :y] (make-insert-tree-data shape-data :y)))))) (defn- add-guide [objects page-data guide] @@ -164,22 +168,22 @@ (update-in [:guides (:axis guide)] (make-delete-tree-data guide-data (:axis guide))))))) (defn- update-frame - [page-data [_ new-frame]] + [objects page-data [_ new-frame]] (let [frame-id (:id new-frame) root-data (get-in page-data [uuid/zero :objects-data frame-id]) frame-data (get-in page-data [frame-id :objects-data frame-id])] - (-> page-data - (update-in [uuid/zero :x] (make-delete-tree-data root-data :x)) - (update-in [uuid/zero :y] (make-delete-tree-data root-data :y)) - (update-in [frame-id :x] (make-delete-tree-data frame-data :x)) - (update-in [frame-id :y] (make-delete-tree-data frame-data :y)) - (add-frame new-frame)))) + (as-> page-data $ + (update-in $ [uuid/zero :x] (make-delete-tree-data root-data :x)) + (update-in $ [uuid/zero :y] (make-delete-tree-data root-data :y)) + (update-in $ [frame-id :x] (make-delete-tree-data frame-data :x)) + (update-in $ [frame-id :y] (make-delete-tree-data frame-data :y)) + (add-frame objects $ new-frame)))) (defn- update-shape - [page-data [old-shape new-shape]] - (-> page-data - (remove-shape old-shape) - (add-shape new-shape))) + [objects page-data [old-shape new-shape]] + (as-> page-data $ + (remove-shape $ old-shape) + (add-shape objects $ new-shape))) (defn- update-guide [objects page-data [old-guide new-guide]] @@ -205,8 +209,8 @@ page-data (as-> {} $ (add-root-frame $) - (reduce add-frame $ frames) - (reduce add-shape $ shapes) + (reduce (partial add-frame objects) $ frames) + (reduce (partial add-shape objects) $ shapes) (reduce (partial add-guide objects) $ guides))] (assoc snap-data (:id page) page-data))) @@ -233,16 +237,16 @@ (diff/calculate-page-diff old-page page snap-attrs)] (as-> page-data $ - (reduce update-shape $ change-frame-shapes) + (reduce (partial update-shape objects) $ change-frame-shapes) (reduce remove-frame $ removed-frames) (reduce remove-shape $ removed-shapes) - (reduce update-frame $ updated-frames) - (reduce update-shape $ updated-shapes) - (reduce add-frame $ new-frames) - (reduce add-shape $ new-shapes) - (reduce remove-guide $ removed-guides) + (reduce (partial update-frame objects) $ updated-frames) + (reduce (partial update-shape objects) $ updated-shapes) + (reduce (partial add-frame objects) $ new-frames) + (reduce (partial add-shape objects) $ new-shapes) ;; Guides functions. Need objects to get its frame data + (reduce remove-guide $ removed-guides) (reduce (partial update-guide objects) $ change-frame-guides) (reduce (partial update-guide objects) $ updated-guides) (reduce (partial add-guide objects) $ new-guides))))) From 7caf4b9136e13ad038fb2641245ee051815c721c Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 3 Nov 2022 16:13:58 +0100 Subject: [PATCH 20/36] :sparkles: Removed constraints when layout child --- .../main/ui/workspace/sidebar/options.cljs | 40 ++++++++++--------- .../sidebar/options/menus/constraints.cljs | 1 - .../options/menus/layout_container.cljs | 17 ++++---- .../sidebar/options/menus/measures.cljs | 7 +--- .../sidebar/options/shapes/bool.cljs | 6 ++- .../sidebar/options/shapes/circle.cljs | 5 ++- .../sidebar/options/shapes/frame.cljs | 5 ++- .../sidebar/options/shapes/group.cljs | 3 +- .../sidebar/options/shapes/image.cljs | 5 ++- .../sidebar/options/shapes/multiple.cljs | 6 ++- .../sidebar/options/shapes/path.cljs | 5 ++- .../sidebar/options/shapes/rect.cljs | 6 ++- .../sidebar/options/shapes/svg_raw.cljs | 5 ++- .../sidebar/options/shapes/text.cljs | 8 ++-- 14 files changed, 67 insertions(+), 52 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options.cljs b/frontend/src/app/main/ui/workspace/sidebar/options.cljs index 5024d3dd9..360151a9c 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options.cljs @@ -7,6 +7,7 @@ (ns app.main.ui.workspace.sidebar.options (:require [app.common.data :as d] + [app.common.geom.shapes :as gsh] [app.main.data.workspace :as udw] [app.main.refs :as refs] [app.main.store :as st] @@ -36,24 +37,27 @@ (mf/defc shape-options {::mf/wrap [#(mf/throttle % 60)]} [{:keys [shape shapes-with-children page-id file-id shared-libs]}] - [:* - (case (:type shape) - :frame [:& frame/options {:shape shape}] - :group [:& group/options {:shape shape :shape-with-children shapes-with-children :file-id file-id :shared-libs shared-libs}] - :text [:& text/options {:shape shape :file-id file-id :shared-libs shared-libs}] - :rect [:& rect/options {:shape shape}] - :circle [:& circle/options {:shape shape}] - :path [:& path/options {:shape shape}] - :image [:& image/options {:shape shape}] - :svg-raw [:& svg-raw/options {:shape shape}] - :bool [:& bool/options {:shape shape}] - nil) - [:& exports-menu - {:ids [(:id shape)] - :values (select-keys shape [:exports]) - :shape shape - :page-id page-id - :file-id file-id}]]) + (let [workspace-modifiers (mf/deref refs/workspace-modifiers) + modifiers (get-in workspace-modifiers [(:id shape) :modifiers]) + shape (gsh/transform-shape shape modifiers)] + [:* + (case (:type shape) + :frame [:& frame/options {:shape shape}] + :group [:& group/options {:shape shape :shape-with-children shapes-with-children :file-id file-id :shared-libs shared-libs}] + :text [:& text/options {:shape shape :file-id file-id :shared-libs shared-libs}] + :rect [:& rect/options {:shape shape}] + :circle [:& circle/options {:shape shape}] + :path [:& path/options {:shape shape}] + :image [:& image/options {:shape shape}] + :svg-raw [:& svg-raw/options {:shape shape}] + :bool [:& bool/options {:shape shape}] + nil) + [:& exports-menu + {:ids [(:id shape)] + :values (select-keys shape [:exports]) + :shape shape + :page-id page-id + :file-id file-id}]])) (mf/defc options-content {::mf/wrap [mf/memo]} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs index 4d22ffa54..a6089f49d 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs @@ -30,7 +30,6 @@ frames (map #(deref (refs/object-by-id (:frame-id %))) old-shapes) shapes (as-> old-shapes $ - #_(map gsh/transform-shape $) (map gsh/translate-to-frame $ frames)) values (let [{:keys [x y]} (-> shapes first :points gsh/points->selrect)] 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 71545cb59..68452f9df 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 @@ -77,18 +77,18 @@ :stretch nil)) :align-self (if is-col? - (case val - :start i/align-self-column-top - :end i/align-self-column-bottom - :center i/align-self-column-center - :stretch i/align-self-column-strech - :baseline i/align-self-column-baseline) (case val :start i/align-self-row-left :end i/align-self-row-right :center i/align-self-row-center :stretch i/align-self-row-strech - :baseline i/align-self-row-baseline)))) + :baseline i/align-self-row-baseline) + (case val + :start i/align-self-column-top + :end i/align-self-column-bottom + :center i/align-self-column-center + :stretch i/align-self-column-strech + :baseline i/align-self-column-baseline)))) (mf/defc direction-btn [{:keys [dir saved-dir set-direction] :as props}] @@ -170,7 +170,8 @@ [{:keys [values on-change-style on-change] :as props}] (let [padding-type (:layout-padding-type values) - rx (if (apply = (vals (:layout-padding values))) + rx (if (and (not (= :multiple (:layout-padding values))) + (apply = (vals (:layout-padding values)))) (:p1 (:layout-padding values)) "--")] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs index 6488fafe0..5c0f2fa7c 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs @@ -69,9 +69,7 @@ ;; -- User/drawing coords (mf/defc measures-menu [{:keys [ids ids-with-children values type all-types shape] :as props}] - (let [workspace-modifiers (mf/deref refs/workspace-modifiers) - - options (if (= type :multiple) + (let [options (if (= type :multiple) (reduce #(union %1 %2) (map #(get type->options %) all-types)) (get type->options type)) @@ -97,9 +95,6 @@ ;; the shape with the mouse, generate a copy of the shapes applying ;; the transient transformations. shapes (as-> old-shapes $ - (map (fn [shape] - (let [modifiers (get-in workspace-modifiers [(:id shape) :modifiers])] - (gsh/transform-shape shape modifiers))) $) (map gsh/translate-to-frame $ frames)) ;; For rotated or stretched shapes, the origin point we show in the menu diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/bool.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/bool.cljs index 1c45a1bf2..ff84041d0 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/bool.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/bool.cljs @@ -41,8 +41,10 @@ :values layout-item-values :is-layout-child? true :shape shape}]) - [:& constraints-menu {:ids ids - :values constraint-values}] + + (when (not is-layout-child?) + [:& constraints-menu {:ids ids + :values constraint-values}]) [:& layer-menu {:ids ids :type type :values layer-values}] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/circle.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/circle.cljs index af0878b7e..812e3c8d9 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/circle.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/circle.cljs @@ -43,8 +43,9 @@ :is-layout-child? true :is-layout-container? false :shape shape}]) - [:& constraints-menu {:ids ids - :values constraint-values}] + (when (not is-layout-child?) + [:& constraints-menu {:ids ids + :values constraint-values}]) [:& layer-menu {:ids ids :type type :values layer-values}] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs index 219518ec1..1fcb34ed6 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs @@ -43,8 +43,9 @@ :values measure-values :type type :shape shape}] - [:& constraints-menu {:ids ids - :values constraint-values}] + (when (not is-layout-child?) + [:& constraints-menu {:ids ids + :values constraint-values}]) (when (or layout-active? is-layout-container?) [:& layout-container-menu {:type type :ids [(:id shape)] :values layout-container-values}]) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs index b81a4a46a..6f921a4b0 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs @@ -62,7 +62,8 @@ :is-layout-container? false :values layout-item-values}]) - [:& constraints-menu {:ids constraint-ids :values constraint-values}] + (when (not is-layout-child?) + [:& constraints-menu {:ids constraint-ids :values constraint-values}]) [:& layer-menu {:type type :ids layer-ids :values layer-values}] (when-not (empty? fill-ids) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/image.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/image.cljs index d2b1a8358..0f99ca979 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/image.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/image.cljs @@ -44,8 +44,9 @@ :is-layout-child? true :shape shape}]) - [:& constraints-menu {:ids ids - :values constraint-values}] + (when (not is-layout-child?) + [:& constraints-menu {:ids ids + :values constraint-values}]) [:& layer-menu {:ids ids :type type diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs index 17f5f7051..06425fd9e 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs @@ -253,6 +253,10 @@ [props] (let [shapes (unchecked-get props "shapes") shapes-with-children (unchecked-get props "shapes-with-children") + + workspace-modifiers (mf/deref refs/workspace-modifiers) + shapes (map #(gsh/transform-shape % (get-in workspace-modifiers [(:id %) :modifiers])) shapes) + page-id (unchecked-get props "page-id") file-id (unchecked-get props "file-id") shared-libs (unchecked-get props "shared-libs") @@ -319,7 +323,7 @@ :is-layout-container? true :values layout-item-values}]) - (when-not (empty? constraint-ids) + (when-not (or (empty? constraint-ids) is-layout-child?) [:& constraints-menu {:ids constraint-ids :values constraint-values}]) (when-not (empty? layer-ids) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/path.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/path.cljs index 22f750df4..5b1a89426 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/path.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/path.cljs @@ -43,8 +43,9 @@ :is-layout-child? true :is-layout-container? false :shape shape}]) - [:& constraints-menu {:ids ids - :values constraint-values}] + (when (not is-layout-child?) + [:& constraints-menu {:ids ids + :values constraint-values}]) [:& layer-menu {:ids ids :type type :values layer-values}] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs index 654aad11b..582f476d8 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs @@ -44,8 +44,10 @@ :values layout-item-values :is-layout-child? true :shape shape}]) - [:& constraints-menu {:ids ids - :values constraint-values}] + + (when (not is-layout-child?) + [:& constraints-menu {:ids ids + :values constraint-values}]) [:& layer-menu {:ids ids :type type diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs index bd7a2c138..e05bf68d8 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs @@ -120,8 +120,9 @@ :is-layout-child? true :shape shape}]) - [:& constraints-menu {:ids ids - :values constraint-values}] + (when (not is-layout-child?) + [:& constraints-menu {:ids ids + :values constraint-values}]) [:& fill-menu {:ids ids :type type diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs index 620832b1d..7c84cdeb5 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs @@ -78,9 +78,11 @@ :values layout-item-values :is-layout-child? true :shape shape}]) - [:& constraints-menu - {:ids ids - :values (select-keys shape constraint-attrs)}] + + (when (not is-layout-child?) + [:& constraints-menu + {:ids ids + :values (select-keys shape constraint-attrs)}]) [:& layer-menu {:ids ids :type type From c86d88834e65efa8b956ccaf97dcb68424e23bdb Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 3 Nov 2022 17:44:10 +0100 Subject: [PATCH 21/36] :sparkles: Fix problems moving frames --- common/src/app/common/pages/helpers.cljc | 3 +- common/src/app/common/types/shape_tree.cljc | 29 ++++-- .../app/main/data/workspace/modifiers.cljs | 6 +- .../app/main/data/workspace/transforms.cljs | 93 +++++++++++-------- 4 files changed, 77 insertions(+), 54 deletions(-) diff --git a/common/src/app/common/pages/helpers.cljc b/common/src/app/common/pages/helpers.cljc index 55b3c571e..e04291bd2 100644 --- a/common/src/app/common/pages/helpers.cljc +++ b/common/src/app/common/pages/helpers.cljc @@ -29,7 +29,7 @@ (defn frame-shape? ([objects id] - (= (get-in objects [id :type]) id)) + (frame-shape? (get objects id))) ([{:keys [type]}] (= type :frame))) @@ -467,7 +467,6 @@ (defn selected-with-children [objects selected] - (into selected (mapcat #(get-children-ids objects %)) selected)) diff --git a/common/src/app/common/types/shape_tree.cljc b/common/src/app/common/types/shape_tree.cljc index 905854d03..d894d77ef 100644 --- a/common/src/app/common/types/shape_tree.cljc +++ b/common/src/app/common/types/shape_tree.cljc @@ -224,16 +224,25 @@ "Search for the top nested frame for positioning shapes when moving or creating. Looks for all the frames in a position and then goes in depth between the top-most and its children to find the target." - [objects position] - (let [frame-ids (all-frames-by-position objects position) - frame-set (set frame-ids)] - (loop [current-id (first frame-ids)] - (let [current-shape (get objects current-id) - child-frame-id (d/seek #(contains? frame-set %) - (-> (:shapes current-shape) reverse))] - (if (nil? child-frame-id) - (or current-id uuid/zero) - (recur child-frame-id)))))) + ([objects position] + (top-nested-frame objects position nil)) + + ([objects position excluded] + (assert (or (nil? excluded) (set? excluded))) + + (let [frame-ids (cond->> (all-frames-by-position objects position) + (some? excluded) + (remove excluded)) + + frame-set (set frame-ids)] + + (loop [current-id (first frame-ids)] + (let [current-shape (get objects current-id) + child-frame-id (d/seek #(contains? frame-set %) + (-> (:shapes current-shape) reverse))] + (if (nil? child-frame-id) + (or current-id uuid/zero) + (recur child-frame-id))))))) (defn top-nested-frame-ids "Search the top nested frame in a list of ids" diff --git a/frontend/src/app/main/data/workspace/modifiers.cljs b/frontend/src/app/main/data/workspace/modifiers.cljs index 4861414e3..1e322c83f 100644 --- a/frontend/src/app/main/data/workspace/modifiers.cljs +++ b/frontend/src/app/main/data/workspace/modifiers.cljs @@ -16,6 +16,7 @@ [app.common.pages.helpers :as cph] [app.common.spec :as us] [app.common.types.modifiers :as ctm] + [app.common.types.shape.layout :as ctl] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.comments :as-alias dwcm] [app.main.data.workspace.guides :as-alias dwg] @@ -144,12 +145,11 @@ (into {} (map #(vector % {:modifiers (get-modifier (get objects %))})) ids)) (defn build-change-frame-modifiers - [modif-tree objects selected target-frame position] + [modif-tree objects selected target-frame drop-index] (let [origin-frame-ids (->> selected (group-by #(get-in objects [% :frame-id]))) - layout? (get-in objects [target-frame :layout]) child-set (set (get-in objects [target-frame :shapes])) - drop-index (when layout? (gsl/get-drop-index target-frame objects position)) + layout? (ctl/layout? objects target-frame) update-frame-modifiers (fn [modif-tree [original-frame shapes]] diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 9ec4c4383..46aa09915 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -353,7 +353,7 @@ (declare start-move) (declare start-move-duplicate) -(declare calculate-frame-for-move) +(declare move-shapes-to-frame) (declare get-displacement) (defn start-move-selected @@ -414,7 +414,6 @@ (rx/take 1) (rx/map #(start-move from-position)))))) - (defn- start-move ([from-position] (start-move from-position nil)) ([from-position ids] @@ -436,13 +435,18 @@ zoom (get-in state [:workspace-local :zoom] 1) focus (:workspace-focus-selected state) - fix-axis (fn [[position shift?]] - (let [delta (gpt/to-vec from-position position)] - (if shift? - (if (> (mth/abs (:x delta)) (mth/abs (:y delta))) - (gpt/point (:x delta) 0) - (gpt/point 0 (:y delta))) - delta))) + exclude-frames (into #{} + (filter (partial cph/frame-shape? objects)) + (cph/selected-with-children objects selected)) + + fix-axis + (fn [[position shift?]] + (let [delta (gpt/to-vec from-position position)] + (if shift? + (if (> (mth/abs (:x delta)) (mth/abs (:y delta))) + (gpt/point (:x delta) 0) + (gpt/point 0 (:y delta))) + delta))) position (->> ms/mouse-position (rx/with-latest-from ms/mouse-position-shift) @@ -456,33 +460,48 @@ (rx/switch-map (fn [pos] (->> (snap/closest-snap-move page-id shapes objects layout zoom focus pos) - (rx/map #(vector pos %)))))))] + (rx/map #(vector pos %))))))) + + drop-frame (atom nil)] (if (empty? shapes) (rx/of (finish-transform)) - (rx/concat - (rx/merge - (->> position - ;; We ask for the snap position but we continue even if the result is not available - (rx/with-latest vector snap-delta) + (let [move-stream + (->> position + ;; We ask for the snap position but we continue even if the result is not available + (rx/with-latest vector snap-delta) - ;; We try to use the previous snap so we don't have to wait for the result of the new - (rx/map snap/correct-snap-point) + ;; We try to use the previous snap so we don't have to wait for the result of the new + (rx/map snap/correct-snap-point) - (rx/map - (fn [move-vector] - (let [position (gpt/add from-position move-vector) - target-frame (ctst/top-nested-frame objects position)] - (-> (dwm/create-modif-tree ids (ctm/move move-vector)) - (dwm/build-change-frame-modifiers objects selected target-frame position) - (dwm/set-modifiers))))) + (rx/map + (fn [move-vector] + (let [position (gpt/add from-position move-vector) + target-frame (ctst/top-nested-frame objects position exclude-frames) + layout? (ctl/layout? objects target-frame) + drop-index (when layout? (gsl/get-drop-index target-frame objects position))] + [move-vector target-frame drop-index]))) - (rx/take-until stopper))) + (rx/take-until stopper))] - (rx/of (dwu/start-undo-transaction) - (calculate-frame-for-move ids) - (dwm/apply-modifiers {:undo-transation? false}) - (finish-transform) - (dwu/commit-undo-transaction))))))))) + (rx/merge + ;; Temporary modifiers stream + (->> move-stream + (rx/map + (fn [[move-vector target-frame drop-index]] + (-> (dwm/create-modif-tree ids (ctm/move move-vector)) + (dwm/build-change-frame-modifiers objects selected target-frame drop-index) + (dwm/set-modifiers))))) + + ;; Last event will write the modifiers creating the changes + (->> move-stream + (rx/last) + (rx/mapcat + (fn [[move-vector target-frame drop-index]] + (rx/of (dwu/start-undo-transaction) + (move-shapes-to-frame ids target-frame drop-index) + (dwm/apply-modifiers {:undo-transation? false}) + (finish-transform) + (dwu/commit-undo-transaction))))))))))))) (s/def ::direction #{:up :down :right :left}) @@ -561,15 +580,13 @@ (rx/of (dwm/set-modifiers modif-tree) (dwm/apply-modifiers)))))) -(defn- calculate-frame-for-move - [ids] - (ptk/reify ::calculate-frame-for-move +(defn- move-shapes-to-frame + [ids frame-id drop-index] + (ptk/reify ::move-shapes-to-frame ptk/WatchEvent (watch [it state _] - (let [position @ms/mouse-position - page-id (:current-page-id state) + (let [page-id (:current-page-id state) objects (wsh/lookup-page-objects state page-id) - frame-id (ctst/top-nested-frame objects position) layout? (get-in objects [frame-id :layout]) lookup (d/getf objects) @@ -584,14 +601,12 @@ (remove #(and (= (:frame-id %) frame-id) (not= (:parent-id %) frame-id)))) - drop-index (when layout? (gsl/get-drop-index frame-id objects position)) - changes (-> (pcb/empty-changes it page-id) (pcb/with-objects objects) (pcb/change-parent frame-id moving-shapes drop-index))] - (when-not (empty? changes) + (when (and (some? frame-id) (not (empty? changes))) (rx/of (dch/commit-changes changes) (dwc/expand-collapse frame-id))))))) From 861eb283e8f44e55ba4a532a55c12e58c8b0c8c9 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 4 Nov 2022 14:56:51 +0100 Subject: [PATCH 22/36] :sparkles: Flex layout small fixes --- .../src/app/common/geom/shapes/modifiers.cljc | 98 +++++++++++-------- .../common/geom/shapes/pixel_precision.cljc | 12 +-- common/src/app/common/types/modifiers.cljc | 89 ++++++++++------- common/src/app/common/types/shape/layout.cljc | 8 +- .../app/main/data/workspace/modifiers.cljs | 1 - .../app/main/data/workspace/transforms.cljs | 12 +-- .../main/ui/workspace/shapes/path/editor.cljs | 6 +- .../main/ui/workspace/viewport/widgets.cljs | 5 +- frontend/src/debug.cljs | 3 + 9 files changed, 132 insertions(+), 102 deletions(-) diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index 878c97759..7ec14c2d7 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -26,7 +26,6 @@ ;; [(get-in objects [k :name]) v])) ;; modif-tree)))) - (defn set-children-modifiers [modif-tree objects parent ignore-constraints snap-pixel?] (let [children (map (d/getf objects) (:shapes parent)) @@ -52,10 +51,9 @@ (= :frame (:type shape))) (defn set-layout-modifiers - ;; TODO LAYOUT: SNAP PIXEL! - [modif-tree objects parent _snap-pixel?] + [modif-tree objects parent process-child?] - (letfn [(process-child [transformed-parent _snap-pixel? modif-tree child] + (letfn [(process-child [transformed-parent modif-tree child] (let [modifiers (get-in modif-tree [(:id parent) :modifiers]) child-modifiers (-> modifiers (ctm/select-child-geometry-modifiers) @@ -88,7 +86,9 @@ transformed-parent (gtr/transform-shape parent modifiers) children (map (d/getf objects) (:shapes transformed-parent)) - modif-tree (reduce (partial process-child transformed-parent _snap-pixel?) modif-tree children) + modif-tree (if process-child? + (reduce (partial process-child transformed-parent) modif-tree children) + modif-tree) children (->> children (map (partial apply-modifiers modif-tree))) layout-data (gcl/calc-layout-data transformed-parent children) @@ -169,16 +169,13 @@ result ;; Frame found, but not layout we return the last layout found (or the id) - (and (and (= :frame (:type parent)) - (not (ctl/auto-width? parent)) - (not (ctl/auto-height? parent))) - (not (:layout parent))) + (and (= :frame (:type parent)) + (not (ctl/layout? parent))) result ;; Layout found. We continue upward but we mark this layout - (and (= :frame (:type parent)) - (:layout parent)) - (:id parent) + (ctl/layout? parent) + (recur (:id parent) (:id parent)) ;; If group or boolean or other type of group we continue with the last result :else @@ -238,42 +235,50 @@ (recur (:parent-id current)))))) (defn- calculate-modifiers - ([objects snap-pixel? ignore-constraints [modif-tree recalculate] shape] - (calculate-modifiers objects snap-pixel? ignore-constraints false [modif-tree recalculate] shape)) + [objects snap-pixel? ignore-constraints [modif-tree recalculate] shape] + (let [shape-id (:id shape) + root? (= uuid/zero shape-id) + modifiers (get-in modif-tree [shape-id :modifiers]) - ([objects snap-pixel? ignore-constraints ignore-auto? [modif-tree recalculate] shape] - (let [shape-id (:id shape) - 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)) - 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)) - 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)))) - 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)] - ;; 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?) - [(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 true) - is-layout? - (set-layout-modifiers objects shape snap-pixel?) + is-auto? + (set-auto-modifiers objects shape)) - (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 + is-auto? + (conj (:id 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- calculate-reflow-layout + [objects snap-pixel? modif-tree shape] + (let [is-layout? (ctl/layout? shape) + is-auto? (or (ctl/auto-height? shape) (ctl/auto-width? shape))] + (cond-> modif-tree + is-layout? + (set-layout-modifiers objects shape false) + + is-auto? + (set-auto-modifiers objects shape)))) (defn set-objects-modifiers [modif-tree objects ignore-constraints snap-pixel?] @@ -284,8 +289,19 @@ (reduce (partial calculate-modifiers objects snap-pixel? ignore-constraints) [modif-tree #{}] shapes-tree) shapes-tree (resolve-tree-sequence recalculate objects) - [modif-tree _] - (reduce (partial calculate-modifiers objects snap-pixel? ignore-constraints true) [modif-tree #{}] shapes-tree)] + + ;; We need to go again and recalculate the layout positions+hug + ;; TODO LAYOUT: How to remove this recalculus? + modif-tree + (->> shapes-tree + reverse + (filter ctl/layout?) + (reduce (partial calculate-reflow-layout objects snap-pixel?) modif-tree )) + + modif-tree + (->> shapes-tree + (filter ctl/layout?) + (reduce (partial calculate-reflow-layout objects snap-pixel?) modif-tree ))] ;;#?(:cljs ;; (.log js/console ">result" (modif->js modif-tree objects))) diff --git a/common/src/app/common/geom/shapes/pixel_precision.cljc b/common/src/app/common/geom/shapes/pixel_precision.cljc index 40e32ae72..03aa4359a 100644 --- a/common/src/app/common/geom/shapes/pixel_precision.cljc +++ b/common/src/app/common/geom/shapes/pixel_precision.cljc @@ -31,10 +31,8 @@ ratio-width (/ target-width curr-width) ratio-height (/ target-height curr-height) scalev (gpt/point ratio-width ratio-height)] - (cond-> modifiers - (or (not (mth/almost-zero? (- ratio-width 1))) - (not (mth/almost-zero? (- ratio-height 1)))) - (ctm/set-resize scalev origin transform transform-inverse)))) + (-> modifiers + (ctm/set-resize scalev origin transform transform-inverse)))) (defn position-pixel-precision [modifiers shape] @@ -43,10 +41,8 @@ corner (gpt/point bounds) target-corner (gpt/round corner) deltav (gpt/to-vec corner target-corner)] - (cond-> modifiers - (or (not (mth/almost-zero? (:x deltav))) - (not (mth/almost-zero? (:y deltav)))) - (ctm/set-move deltav)))) + (-> modifiers + (ctm/set-move deltav)))) (defn set-pixel-precision "Adjust modifiers so they adjust to the pixel grid" diff --git a/common/src/app/common/types/modifiers.cljc b/common/src/app/common/types/modifiers.cljc index 25e17df9d..48710b40c 100644 --- a/common/src/app/common/types/modifiers.cljc +++ b/common/src/app/common/types/modifiers.cljc @@ -10,6 +10,7 @@ [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] [app.common.geom.shapes.common :as gco] + [app.common.math :as mth] [app.common.pages.helpers :as cph] [app.common.spec :as us] [app.common.text :as txt])) @@ -41,73 +42,89 @@ (defn empty-modifiers [] {}) +(defn move-vec? [vector] + (or (not (mth/almost-zero? (:x vector))) + (not (mth/almost-zero? (:y vector))))) + +(defn resize-vec? [vector] + (or (not (mth/almost-zero? (- (:x vector) 1))) + (not (mth/almost-zero? (- (:y vector) 1))))) + (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})))) + (cond-> modifiers + (move-vec? vector) + (update :geometry-parent conjv {:type :move :vector vector})))) (defn set-resize-parent ([modifiers vector origin] - (-> modifiers - (update :geometry-parent conjv {:type :resize + (cond-> modifiers + (resize-vec? vector) + (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})))) + (cond-> modifiers + (resize-vec? vector) + (update :geometry-parent conjv {:type :resize + :vector vector + :origin origin + :transform transform + :transform-inverse transform-inverse})))) (defn set-move ([modifiers x y] (set-move modifiers (gpt/point x y))) ([modifiers vector] - (-> modifiers - (update :geometry-child conjv {:type :move :vector vector})))) + (cond-> modifiers + (move-vec? vector) + (update :geometry-child conjv {:type :move :vector vector})))) (defn set-resize ([modifiers vector origin] - (-> modifiers - (update :geometry-child conjv {:type :resize - :vector vector - :origin origin}))) + (cond-> modifiers + (resize-vec? vector) + (update :geometry-child conjv {:type :resize + :vector vector + :origin origin}))) ([modifiers vector origin transform transform-inverse] - (-> modifiers - (update :geometry-child conjv {:type :resize - :vector vector - :origin origin - :transform transform - :transform-inverse transform-inverse})))) + (cond-> modifiers + (resize-vec? vector) + (update :geometry-child conjv {:type :resize + :vector vector + :origin origin + :transform transform + :transform-inverse transform-inverse})))) (defn set-rotation [modifiers center angle] - (-> modifiers - (update :structure-child conjv {:type :rotation - :rotation angle}) - (update :geometry-child conjv {:type :rotation - :center center - :rotation angle}))) + (cond-> modifiers + (not (mth/close? angle 0)) + (-> (update :structure-child conjv {:type :rotation + :rotation angle}) + (update :geometry-child conjv {:type :rotation + :center center + :rotation angle})))) (defn set-remove-children [modifiers shapes] - (-> modifiers - (update :structure-parent conjv {:type :remove-children - :value shapes})) - ) + (cond-> modifiers + (d/not-empty? shapes) + (update :structure-parent conjv {:type :remove-children + :value shapes}))) (defn set-add-children [modifiers shapes index] - (-> modifiers - (update :structure-parent conjv {:type :add-children - :value shapes - :index index}))) + (cond-> modifiers + (d/not-empty? shapes) + (update :structure-parent conjv {:type :add-children + :value shapes + :index index}))) (defn set-reflow [modifiers] diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 87a1ad3fe..d25dc9844 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -46,15 +46,14 @@ (s/def ::p4 ::us/safe-number) (s/def ::layout-padding - (s/keys :req-un [::p1] - :opt-un [::p2 ::p3 ::p4])) + (s/keys :opt-un [::p1 ::p2 ::p3 ::p4])) (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 :req-un [::row-gap ::column-gap])) + (s/keys :opt-un [::row-gap ::column-gap])) (s/def ::layout-container-props (s/keys :opt-un [::layout @@ -74,8 +73,7 @@ (s/def ::m3 ::us/safe-number) (s/def ::m4 ::us/safe-number) -(s/def ::layout-item-margin (s/keys :req-un [::m1] - :opt-un [::m2 ::m3 ::m4])) +(s/def ::layout-item-margin (s/keys :opt-un [::m1 ::m2 ::m3 ::m4])) (s/def ::layout-item-margin-type #{:simple :multiple}) (s/def ::layout-item-h-sizing #{:fill :fix :auto}) diff --git a/frontend/src/app/main/data/workspace/modifiers.cljs b/frontend/src/app/main/data/workspace/modifiers.cljs index 1e322c83f..9263d9745 100644 --- a/frontend/src/app/main/data/workspace/modifiers.cljs +++ b/frontend/src/app/main/data/workspace/modifiers.cljs @@ -10,7 +10,6 @@ [app.common.data :as d] [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] - [app.common.geom.shapes.flex-layout :as gsl] [app.common.math :as mth] [app.common.pages.common :as cpc] [app.common.pages.helpers :as cph] diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 46aa09915..7ef6eb3cd 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -460,9 +460,7 @@ (rx/switch-map (fn [pos] (->> (snap/closest-snap-move page-id shapes objects layout zoom focus pos) - (rx/map #(vector pos %))))))) - - drop-frame (atom nil)] + (rx/map #(vector pos %)))))))] (if (empty? shapes) (rx/of (finish-transform)) (let [move-stream @@ -496,7 +494,7 @@ (->> move-stream (rx/last) (rx/mapcat - (fn [[move-vector target-frame drop-index]] + (fn [[_ target-frame drop-index]] (rx/of (dwu/start-undo-transaction) (move-shapes-to-frame ids target-frame drop-index) (dwm/apply-modifiers {:undo-transation? false}) @@ -606,7 +604,7 @@ (pcb/with-objects objects) (pcb/change-parent frame-id moving-shapes drop-index))] - (when (and (some? frame-id) (not (empty? changes))) + (when (and (some? frame-id) (d/not-empty? changes)) (rx/of (dch/commit-changes changes) (dwc/expand-collapse frame-id))))))) @@ -637,7 +635,7 @@ selected (-> (ctm/empty-modifiers) (ctm/set-resize (gpt/point -1.0 1.0) origin) - (ctm/move (gpt/point (:width selrect) 0))))] + (ctm/set-move (gpt/point (:width selrect) 0))))] (rx/of (dwm/set-modifiers modif-tree true) (dwm/apply-modifiers)))))) @@ -656,7 +654,7 @@ selected (-> (ctm/empty-modifiers) (ctm/set-resize (gpt/point 1.0 -1.0) origin) - (ctm/move (gpt/point 0 (:height selrect)))))] + (ctm/set-move (gpt/point 0 (:height selrect)))))] (rx/of (dwm/set-modifiers modif-tree true) (dwm/apply-modifiers)))))) diff --git a/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs b/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs index d6f2a1dd1..67b79a46a 100644 --- a/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs @@ -6,6 +6,8 @@ (ns app.main.ui.workspace.shapes.path.editor (:require + [app.common.data :as d] + [app.common.data.macros :as dm] [app.common.geom.point :as gpt] [app.common.geom.shapes.path :as gsp] [app.common.path.commands :as upc] @@ -308,7 +310,7 @@ :start-path? start-p? :zoom zoom}]]) - (for [position points] + (for [[index position] (d/enumerate points)] (let [show-handler? (fn [[index prefix]] (let [handler-position (upc/handler->point content index prefix)] @@ -322,7 +324,7 @@ pos-handlers (->> pos-handlers (filter show-handler?)) curve? (boolean (seq pos-handlers))] - [:g.path-node + [:g.path-node {:key (dm/str index "-" (:x position) "-" (:y position))} [:g.point-handlers {:pointer-events (when (= edit-mode :draw) "none")} (for [[index prefix] pos-handlers] (let [handler-position (upc/handler->point content index prefix) diff --git a/frontend/src/app/main/ui/workspace/viewport/widgets.cljs b/frontend/src/app/main/ui/workspace/viewport/widgets.cljs index 9da2e1673..d78b53463 100644 --- a/frontend/src/app/main/ui/workspace/viewport/widgets.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/widgets.cljs @@ -21,6 +21,7 @@ [app.main.ui.workspace.viewport.path-actions :refer [path-actions]] [app.main.ui.workspace.viewport.utils :as vwu] [app.util.dom :as dom] + [debug :refer [debug?]] [rumext.v2 :as mf])) (mf/defc pixel-grid @@ -34,8 +35,8 @@ :pattern-units "userSpaceOnUse"} [:path {:d "M 1 0 L 0 0 0 1" :style {:fill "none" - :stroke "var(--color-info)" - :stroke-opacity "0.2" + :stroke (if (debug? :pixel-grid) "red" "var(--color-info)") + :stroke-opacity (if (debug? :pixel-grid) 1 "0.2") :stroke-width (str (/ 1 zoom))}}]]] [:rect {:x (:x vbox) :y (:y vbox) diff --git a/frontend/src/debug.cljs b/frontend/src/debug.cljs index 3a3b9f366..d4856cbda 100644 --- a/frontend/src/debug.cljs +++ b/frontend/src/debug.cljs @@ -70,6 +70,9 @@ ;; Enable a widget to show the auto-layout drop-zones :layout-drop-zones + + ;; Makes the pixel grid red so its more visibile + :pixel-grid }) ;; These events are excluded when we activate the :events flag From 7375eed18f7f531a1e6e93213fa3d4cf5b116b8a Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 4 Nov 2022 15:50:55 +0100 Subject: [PATCH 23/36] :sparkles: Refactor modifiers --- .../src/app/common/geom/shapes/modifiers.cljc | 259 ++++++++---------- common/src/app/common/pages/helpers.cljc | 4 + common/src/app/common/types/shape/layout.cljc | 16 ++ 3 files changed, 138 insertions(+), 141 deletions(-) diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index 7ec14c2d7..3b6a3c61b 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -26,11 +26,71 @@ ;; [(get-in objects [k :name]) v])) ;; modif-tree)))) -(defn set-children-modifiers - [modif-tree objects parent ignore-constraints snap-pixel?] +(defn resolve-tree-sequence + "Given the ids that have changed search for layout roots to recalculate" + [ids objects] + + (assert (or (nil? ids) (set? ids)) (dm/str "tree sequence from not set: " ids)) + + (letfn [(get-tree-root ;; Finds the tree root for the current id + [id] + + (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 (ctl/layout? parent))) + result + + ;; Layout found. We continue upward but we mark this layout + (ctl/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))))) + + (calculate-common-roots ;; Given some roots retrieves the minimum number of tree roots + [result id] + (if (= id uuid/zero) + result + (let [root (get-tree-root id) + + ;; Remove the children from the current root + result + (into #{} (remove #(cph/is-child? objects root %)) result) + + contains-parent? + (some #(cph/is-child? objects % root) result)] + + (cond-> result + (not contains-parent?) + (conj root))))) + + (generate-tree ;; Generate a tree sequence from a given root id + [id] + (->> (tree-seq + #(d/not-empty? (get-in objects [% :shapes])) + #(get-in objects [% :shapes]) + id) + (map #(get objects %))))] + + (let [roots (->> ids (reduce calculate-common-roots #{}))] + (concat + (when (contains? ids uuid/zero) [(get objects uuid/zero)]) + (mapcat generate-tree roots))))) + +(defn- set-children-modifiers + "Propagates the modifiers from a parent too its children applying constraints if necesary" + [modif-tree objects parent transformed-parent ignore-constraints snap-pixel?] (let [children (map (d/getf objects) (:shapes parent)) modifiers (get-in modif-tree [(:id parent) :modifiers]) - transformed-parent (gtr/transform-shape parent modifiers) parent (gtr/transform-shape parent (ctm/select-parent-modifiers modifiers)) set-child @@ -43,32 +103,29 @@ (reduce set-child modif-tree children))) -(defn group? [shape] - (or (= :group (:type shape)) - (= :bool (:type shape)))) - -(defn frame? [shape] - (= :frame (:type shape))) - -(defn set-layout-modifiers - [modif-tree objects parent process-child?] - - (letfn [(process-child [transformed-parent modif-tree child] +(defn- process-layout-children + [modif-tree objects parent transformed-parent] + (letfn [(process-child [modif-tree child] (let [modifiers (get-in modif-tree [(:id parent) :modifiers]) child-modifiers (-> modifiers (ctm/select-child-geometry-modifiers) (gcl/normalize-child-modifiers parent child transformed-parent))] (cond-> modif-tree (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))))] + (let [children (map (d/getf objects) (:shapes transformed-parent))] + (reduce process-child modif-tree children)))) - (apply-modifiers [modif-tree child] +(defn- set-layout-modifiers + [modif-tree objects parent] + + (letfn [(apply-modifiers [modif-tree child] (let [modifiers (get-in modif-tree [(:id child) :modifiers])] (cond-> child (some? modifiers) (gtr/transform-shape modifiers) - (and (some? modifiers) (group? child)) + (and (some? modifiers) (cph/group-like-shape? child)) (gtr/apply-group-modifiers objects modif-tree)))) (set-child-modifiers [parent [layout-line modif-tree] child] @@ -82,19 +139,11 @@ [layout-line modif-tree]))] - (let [modifiers (get-in modif-tree [(:id parent) :modifiers]) - transformed-parent (gtr/transform-shape parent modifiers) - children (map (d/getf objects) (:shapes transformed-parent)) - - modif-tree (if process-child? - (reduce (partial process-child transformed-parent) modif-tree children) - modif-tree) + (let [children (map (d/getf objects) (:shapes parent)) children (->> children (map (partial apply-modifiers modif-tree))) - - layout-data (gcl/calc-layout-data transformed-parent children) + layout-data (gcl/calc-layout-data parent children) children (into [] (cond-> children (:reverse? layout-data) reverse)) max-idx (dec (count children)) - layout-lines (:layout-lines layout-data)] (loop [modif-tree modif-tree @@ -106,20 +155,22 @@ children (subvec children from-idx to-idx) [_ modif-tree] - (reduce (partial set-child-modifiers transformed-parent) [layout-line modif-tree] children)] + (reduce (partial set-child-modifiers parent) [layout-line modif-tree] children)] (recur modif-tree (first pending) (rest pending) to-idx)) modif-tree))))) -(defn set-auto-modifiers +(defn- set-auto-modifiers + "Calculates the modifiers to adjust the bounds for auto-width/auto-height shapes" [modif-tree objects parent] - (letfn [(apply-modifiers [child] + (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)) + (and (some? modifiers) (cph/group-like-shape? child)) (gtr/apply-group-modifiers objects modif-tree)))) (set-parent-auto-width @@ -137,148 +188,74 @@ (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 + children (->> 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? transformed-parent) (ctl/auto-width? transformed-parent))) - (gcl/layout-content-bounds transformed-parent children)) + (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? transformed-parent)) - (set-parent-auto-width transformed-parent auto-width) + (and (some? auto-width) (ctl/auto-width? parent)) + (set-parent-auto-width parent auto-width) - (and (some? auto-height) (ctl/auto-height? transformed-parent)) - (set-parent-auto-height transformed-parent auto-height))] + (and (some? auto-height) (ctl/auto-height? parent)) + (set-parent-auto-height parent auto-height))] (assoc-in modif-tree [(:id parent) :modifiers] modifiers)))) -(defn get-tree-root - [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 (ctl/layout? parent))) - result - - ;; Layout found. We continue upward but we mark this layout - (ctl/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-tree-sequence - "Given the ids that have changed search for layout roots to recalculate" - [ids objects] - - (assert (or (nil? ids) (set? ids)) (dm/str "tree sequence from not set: " ids)) - - (let [redfn - (fn [result id] - (if (= id uuid/zero) - result - (let [root (get-tree-root id objects) - - ;; Remove the children from the current root - result - (into #{} (remove #(cph/is-child? objects root %)) result) - - contains-parent? - (some #(cph/is-child? objects % root) result)] - - (cond-> result - (not contains-parent?) - (conj root))))) - - generate-tree - (fn [id] - (->> (tree-seq - #(d/not-empty? (get-in objects [% :shapes])) - #(get-in objects [% :shapes]) - id) - - (map #(get objects %)))) - - roots (->> ids (reduce redfn #{}))] - - (concat - (when (contains? ids uuid/zero) [(get objects uuid/zero)]) - (mapcat generate-tree roots)))) - -(defn inside-layout? - [objects shape] - - (loop [current-id (:id shape)] - (let [current (get objects current-id)] - (cond - (or (nil? current) (= current-id (:parent-id current))) - false - - (= :frame (:type current)) - (:layout current) - - :else - (recur (:parent-id current)))))) - -(defn- calculate-modifiers - [objects snap-pixel? ignore-constraints [modif-tree recalculate] shape] - (let [shape-id (:id shape) - root? (= uuid/zero shape-id) - modifiers (get-in modif-tree [shape-id :modifiers]) +(defn- propagate-modifiers + [objects snap-pixel? ignore-constraints [modif-tree recalculate] parent] + (let [parent-id (:id parent) + root? (= uuid/zero parent-id) + modifiers (get-in modif-tree [parent-id :modifiers]) modifiers (cond-> modifiers (and (not root?) (ctm/has-geometry? modifiers) snap-pixel?) - (gpp/set-pixel-precision shape)) + (gpp/set-pixel-precision parent)) - modif-tree (-> modif-tree (assoc-in [shape-id :modifiers] modifiers)) + modif-tree (-> modif-tree (assoc-in [parent-id :modifiers] modifiers)) + + transformed-parent (gtr/transform-shape parent 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)))) + is-layout? (ctl/layout? parent) + is-auto? (or (ctl/auto-height? transformed-parent) (ctl/auto-width? transformed-parent)) + is-parent? (or (cph/group-like-shape? parent) (and (cph/frame-shape? parent) (not (ctl/layout? parent)))) ;; If the current child is inside the layout we ignore the constraints - is-inside-layout? (inside-layout? objects shape)] + is-inside-layout? (ctl/inside-layout? objects parent)] [(cond-> modif-tree (and has-modifiers? is-parent? (not root?)) - (set-children-modifiers objects shape (or ignore-constraints is-inside-layout?) snap-pixel?) + (set-children-modifiers objects parent transformed-parent (or ignore-constraints is-inside-layout?) snap-pixel?) is-layout? - (set-layout-modifiers objects shape true) + (-> (process-layout-children objects parent transformed-parent) + (set-layout-modifiers objects transformed-parent)) is-auto? - (set-auto-modifiers objects shape)) + (set-auto-modifiers objects transformed-parent)) (cond-> recalculate ;; Auto-width/height can change the positions in the parent so we need to recalculate is-auto? - (conj (:id shape)))])) + (conj (:id parent)))])) (defn- calculate-reflow-layout - [objects snap-pixel? modif-tree shape] - (let [is-layout? (ctl/layout? shape) - is-auto? (or (ctl/auto-height? shape) (ctl/auto-width? shape))] + [objects modif-tree parent] + (let [is-layout? (ctl/layout? parent) + is-auto? (or (ctl/auto-height? parent) (ctl/auto-width? parent)) + modifiers (get-in modif-tree [(:id parent) :modifiers]) + transformed-parent (gtr/transform-shape parent modifiers)] (cond-> modif-tree is-layout? - (set-layout-modifiers objects shape false) + (set-layout-modifiers objects transformed-parent) is-auto? - (set-auto-modifiers objects shape)))) + (set-auto-modifiers objects transformed-parent)))) (defn set-objects-modifiers [modif-tree objects ignore-constraints snap-pixel?] @@ -286,22 +263,22 @@ (let [shapes-tree (resolve-tree-sequence (-> modif-tree keys set) objects) [modif-tree recalculate] - (reduce (partial calculate-modifiers objects snap-pixel? ignore-constraints) [modif-tree #{}] shapes-tree) + (reduce (partial propagate-modifiers objects snap-pixel? ignore-constraints) [modif-tree #{}] shapes-tree) shapes-tree (resolve-tree-sequence recalculate objects) ;; We need to go again and recalculate the layout positions+hug - ;; TODO LAYOUT: How to remove this recalculus? + ;; TODO LAYOUT: How to remove this recalculation? modif-tree (->> shapes-tree reverse (filter ctl/layout?) - (reduce (partial calculate-reflow-layout objects snap-pixel?) modif-tree )) + (reduce (partial calculate-reflow-layout objects) modif-tree)) modif-tree (->> shapes-tree (filter ctl/layout?) - (reduce (partial calculate-reflow-layout objects snap-pixel?) modif-tree ))] + (reduce (partial calculate-reflow-layout objects) modif-tree ))] ;;#?(:cljs ;; (.log js/console ">result" (modif->js modif-tree objects))) diff --git a/common/src/app/common/pages/helpers.cljc b/common/src/app/common/pages/helpers.cljc index e04291bd2..2799639a5 100644 --- a/common/src/app/common/pages/helpers.cljc +++ b/common/src/app/common/pages/helpers.cljc @@ -47,6 +47,10 @@ [{:keys [type]}] (= type :bool)) +(defn group-like-shape? + [{:keys [type]}] + (or (= :group type) (= :bool type))) + (defn text-shape? [{:keys [type]}] (= type :text)) diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index d25dc9844..b318191c0 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -106,6 +106,22 @@ parent (get objects parent-id)] (layout? parent))) +(defn inside-layout? + "Check if the shape is inside a layout" + [objects shape] + + (loop [current-id (:id shape)] + (let [current (get objects current-id)] + (cond + (or (nil? current) (= current-id (:parent-id current))) + false + + (= :frame (:type current)) + (:layout current) + + :else + (recur (:parent-id current)))))) + (defn wrap? [{:keys [layout-wrap-type]}] (= layout-wrap-type :wrap)) From b5df7bbfc524c309fbe83a8d8e77e1bddc129040 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 4 Nov 2022 15:53:50 +0100 Subject: [PATCH 24/36] :sparkles: Remove constraints when autolayout --- CHANGES.md | 3 +++ frontend/resources/images/icons/auto-flex.svg | 3 --- .../images/icons/auto-row-column.svg | 3 --- .../resources/images/icons/layout-columns.svg | 4 ++-- .../resources/images/icons/layout-rows.svg | 4 ++-- .../app/main/data/workspace/shape_layout.cljs | 20 ++++++++++------ .../main/data/workspace/state_helpers.cljs | 19 ++++++++------- .../src/app/main/data/workspace/texts.cljs | 23 +++++++------------ frontend/src/app/main/ui/shapes/bool.cljs | 5 +--- .../main/ui/workspace/shapes/path/editor.cljs | 5 ++-- 10 files changed, 41 insertions(+), 48 deletions(-) delete mode 100644 frontend/resources/images/icons/auto-flex.svg delete mode 100644 frontend/resources/images/icons/auto-row-column.svg diff --git a/CHANGES.md b/CHANGES.md index 5238ce23a..8c3d7ac4f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,8 +4,11 @@ ### :boom: Breaking changes & Deprecations ### :sparkles: New features + +- Adds layout flex functionality for boards - Better overlays interactions on boards inside boards [Taiga #4386](https://tree.taiga.io/project/penpot/us/4386) - Show board miniature in manual overlay setting [Taiga #4475](https://tree.taiga.io/project/penpot/issue/4475) + ### :bug: Bugs fixed - Add title to color bullets [Taiga #4218](https://tree.taiga.io/project/penpot/task/4218) diff --git a/frontend/resources/images/icons/auto-flex.svg b/frontend/resources/images/icons/auto-flex.svg deleted file mode 100644 index 9023c8fcf..000000000 --- a/frontend/resources/images/icons/auto-flex.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/frontend/resources/images/icons/auto-row-column.svg b/frontend/resources/images/icons/auto-row-column.svg deleted file mode 100644 index 9023c8fcf..000000000 --- a/frontend/resources/images/icons/auto-row-column.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/frontend/resources/images/icons/layout-columns.svg b/frontend/resources/images/icons/layout-columns.svg index 4c9381c99..eb4b7ba55 100644 --- a/frontend/resources/images/icons/layout-columns.svg +++ b/frontend/resources/images/icons/layout-columns.svg @@ -1,3 +1,3 @@ - - + + diff --git a/frontend/resources/images/icons/layout-rows.svg b/frontend/resources/images/icons/layout-rows.svg index f09a1ced8..9023c8fcf 100644 --- a/frontend/resources/images/icons/layout-rows.svg +++ b/frontend/resources/images/icons/layout-rows.svg @@ -1,3 +1,3 @@ - - + + diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index 1e6864349..c1a94684a 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -57,17 +57,23 @@ (dwm/apply-modifiers))) (rx/empty)))))) -;; TODO LAYOUT: Remove constraints from children +(defn get-layout-initializer + [type] + (let [initial-layout-data (if (= type :flex) initial-flex-layout initial-grid-layout)] + (fn [shape] + (-> shape + (merge shape initial-layout-data))))) + (defn create-layout [ids type] (ptk/reify ::create-layout ptk/WatchEvent - (watch [_ _ _] - (if (= type :flex) - (rx/of (dwc/update-shapes ids #(merge % initial-flex-layout)) - (update-layout-positions ids)) - (rx/of (dwc/update-shapes ids #(merge % initial-grid-layout)) - (update-layout-positions ids)))))) + (watch [_ state _] + (let [objects (wsh/lookup-page-objects state) + children-ids (into [] (mapcat #(get-in objects [% :shapes])) ids)] + (rx/of (dwc/update-shapes ids (get-layout-initializer type)) + (update-layout-positions ids) + (dwc/update-shapes children-ids #(dissoc % :constraints-h :constraints-v))))))) (defn remove-layout [ids] diff --git a/frontend/src/app/main/data/workspace/state_helpers.cljs b/frontend/src/app/main/data/workspace/state_helpers.cljs index c56931cf1..5804e1434 100644 --- a/frontend/src/app/main/data/workspace/state_helpers.cljs +++ b/frontend/src/app/main/data/workspace/state_helpers.cljs @@ -8,9 +8,9 @@ (:require [app.common.data :as d] [app.common.data.macros :as dm] + [app.common.geom.shapes :as gsh] [app.common.pages.helpers :as cph] - [app.common.path.commands :as upc] - [app.common.types.modifiers :as ctm])) + [app.common.path.commands :as upc])) (defn lookup-page ([state] @@ -127,16 +127,15 @@ (defn select-bool-children [parent-id state] (let [objects (lookup-page-objects state) - selected (lookup-selected-raw state) modifiers (:workspace-modifiers state) - children-ids (cph/get-children-ids objects parent-id) - selected-children (into [] (filter selected) children-ids) - - modifiers (select-keys modifiers selected-children) - children (select-keys objects children-ids)] + children + (-> (select-keys objects children-ids) + (d/update-vals + (fn [child] + (cond-> child + (contains? modifiers (:id child)) + (gsh/transform-shape (get-in modifiers [(:id child) :modifiers]))))))] (as-> children $ - ;; TODO LAYOUT: REVIEW THIS - (ctm/merge-modifiers $ modifiers) (d/mapm (set-content-modifiers state) $)))) diff --git a/frontend/src/app/main/data/workspace/texts.cljs b/frontend/src/app/main/data/workspace/texts.cljs index dbfb5f453..06592a153 100644 --- a/frontend/src/app/main/data/workspace/texts.cljs +++ b/frontend/src/app/main/data/workspace/texts.cljs @@ -319,17 +319,14 @@ (watch [_ _ _] (letfn [(update-fn [shape] (let [{:keys [selrect grow-type]} shape - {shape-width :width shape-height :height} selrect - modifier-width (ctm/change-dimensions shape :width new-width) - modifier-height (ctm/change-dimensions shape :height new-height)] - ;; TODO LAYOUT: MEZCLAR ESTOS EN UN UNICO MODIFIER + {shape-width :width shape-height :height} selrect] (cond-> shape (and (not-changed? shape-width new-width) (= grow-type :auto-width)) - (gsh/transform-shape modifier-width) + (gsh/transform-shape (ctm/change-dimensions shape :width new-width)) (and (not-changed? shape-height new-height) (or (= grow-type :auto-height) (= grow-type :auto-width))) - (gsh/transform-shape modifier-height))))] + (gsh/transform-shape (ctm/change-dimensions shape :height new-height)))))] (rx/of (dch/update-shapes [id] update-fn {:reg-objects? true :save-undo? false})))))) @@ -346,17 +343,13 @@ (defn apply-text-modifier [shape {:keys [width height position-data]}] - (let [modifier-width (when width (ctm/change-dimensions shape :width width)) - modifier-height (when height (ctm/change-dimensions shape :height height)) - - ;; TODO LAYOUT: MEZCLAR LOS DOS EN UN UNICO MODIFIER - new-shape + (let [new-shape (cond-> shape - (some? modifier-width) - (gsh/transform-shape modifier-width) + (some? width) + (gsh/transform-shape (ctm/change-dimensions shape :width width)) - (some? modifier-height) - (gsh/transform-shape modifier-height) + (some? height) + (gsh/transform-shape (ctm/change-dimensions shape :height height)) (some? position-data) (assoc :position-data position-data)) diff --git a/frontend/src/app/main/ui/shapes/bool.cljs b/frontend/src/app/main/ui/shapes/bool.cljs index 2c00a9684..d725a00ae 100644 --- a/frontend/src/app/main/ui/shapes/bool.cljs +++ b/frontend/src/app/main/ui/shapes/bool.cljs @@ -14,7 +14,6 @@ [app.util.object :as obj] [rumext.v2 :as mf])) -;; TODO LAYOUT: REVIEW DYNAMIC CHANGES IN BOOLEANS (defn bool-shape [shape-wrapper] (mf/fnc bool-shape @@ -34,9 +33,7 @@ (:bool-content shape) (some? childs) - (->> childs - #_(d/mapm #(gsh/transform-shape %2)) - (gsh/calc-bool-content shape)))))] + (gsh/calc-bool-content shape childs))))] [:* (when (some? bool-content) diff --git a/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs b/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs index 67b79a46a..8a991bf3f 100644 --- a/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs @@ -185,8 +185,9 @@ matches (concat (second (:x snap-matches)) (second (:y snap-matches)))] [:g.snap-paths - (for [[from to] matches] - [:line {:x1 (:x from) + (for [[idx [from to]] (d/enumerate matches)] + [:line {:key (dm/str "snap-" idx "-" from "-" to) + :x1 (:x from) :y1 (:y from) :x2 (:x to) :y2 (:y to) From a2e26210d1550296101a9f34d039ecd4c07d8258 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Mon, 7 Nov 2022 12:25:22 +0100 Subject: [PATCH 25/36] :sparkles: Renamed modifiers functions --- .../app/common/geom/shapes/constraints.cljc | 13 +- .../geom/shapes/flex_layout/modifiers.cljc | 16 +- .../src/app/common/geom/shapes/modifiers.cljc | 8 +- .../common/geom/shapes/pixel_precision.cljc | 4 +- .../app/common/geom/shapes/transforms.cljc | 2 +- common/src/app/common/types/modifiers.cljc | 270 +++++++++--------- .../test/common_tests/geom_shapes_test.cljc | 14 +- .../app/main/data/workspace/drawing/box.cljs | 6 +- .../main/data/workspace/drawing/common.cljs | 2 +- .../app/main/data/workspace/modifiers.cljs | 8 +- .../app/main/data/workspace/shape_layout.cljs | 2 +- .../src/app/main/data/workspace/texts.cljs | 8 +- .../app/main/data/workspace/transforms.cljs | 32 +-- frontend/src/app/main/render.cljs | 8 +- .../src/app/main/ui/viewer/interactions.cljs | 2 +- .../shapes/frame/dynamic_modifiers.cljs | 4 +- .../shapes/text/viewport_texts_html.cljs | 2 +- 17 files changed, 201 insertions(+), 200 deletions(-) diff --git a/common/src/app/common/geom/shapes/constraints.cljc b/common/src/app/common/geom/shapes/constraints.cljc index 2be4becad..c90cd179b 100644 --- a/common/src/app/common/geom/shapes/constraints.cljc +++ b/common/src/app/common/geom/shapes/constraints.cljc @@ -152,7 +152,7 @@ end-angl (gpt/angle-with-other end-before end-after) target-end (if (mth/close? end-angl 180) (- (gpt/length end-before)) (gpt/length end-before)) disp-vector-end (gpt/subtract end-after (gpt/scale (gpt/unit end-after) target-end))] - (ctm/move disp-vector-end))) + (ctm/move-modifiers disp-vector-end))) (defmethod constraint-modifier :fixed [_ axis child-points-before parent-points-before child-points-after parent-points-after transformed-parent] @@ -174,9 +174,8 @@ resize-angl (gpt/angle-with-other before-vec after-vec) resize-sign (if (mth/close? resize-angl 180) -1 1) - scale (* resize-sign (/ (gpt/length after-vec) (gpt/length before-vec))) - ] - (ctm/resize (get-scale axis scale) c0 (:transform transformed-parent) (:transform-inverse transformed-parent)))) + scale (* resize-sign (/ (gpt/length after-vec) (gpt/length before-vec)))] + (ctm/resize-modifiers (get-scale axis scale) c0 (:transform transformed-parent) (:transform-inverse transformed-parent)))) (defmethod constraint-modifier :center [_ axis child-points-before parent-points-before child-points-after parent-points-after] @@ -185,7 +184,7 @@ center-angl (gpt/angle-with-other center-before center-after) target-center (if (mth/close? center-angl 180) (- (gpt/length center-before)) (gpt/length center-before)) disp-vector-center (gpt/subtract center-after (gpt/scale (gpt/unit center-after) target-center))] - (ctm/move disp-vector-center))) + (ctm/move-modifiers disp-vector-center))) (defmethod constraint-modifier :default [_ _ _ _ _] []) @@ -242,10 +241,10 @@ (cond-> modifiers (not= :scale constraints-h) - (ctm/set-resize (gpt/point scale-x 1) resize-origin transform transform-inverse) + (ctm/resize (gpt/point scale-x 1) resize-origin transform transform-inverse) (not= :scale constraints-v) - (ctm/set-resize (gpt/point 1 scale-y) resize-origin transform transform-inverse)))) + (ctm/resize (gpt/point 1 scale-y) resize-origin transform transform-inverse)))) (defn calc-child-modifiers [parent child modifiers ignore-constraints transformed-parent] diff --git a/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc b/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc index fc0b60683..2a9a04e09 100644 --- a/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc @@ -23,11 +23,11 @@ scale-x (/ (:width child-bb-before) (:width child-bb-after)) scale-y (/ (:height child-bb-before) (:height child-bb-after)) - resize-origin (-> transformed-parent :points first) ;; TODO LAYOUT: IS always the origin?n + resize-origin (-> transformed-parent :points first) ;; TODO LAYOUT: IS always the origin resize-vector (gpt/point scale-x scale-y)] (-> modifiers (ctm/select-child-modifiers) - (ctm/set-resize resize-vector resize-origin transform transform-inverse)))) + (ctm/resize resize-vector resize-origin transform transform-inverse)))) (defn calc-fill-width-data "Calculates the size and modifiers for the width of an auto-fill child" @@ -41,7 +41,7 @@ (let [target-width (max (get-in children-data [(:id child) :child-width]) 0.01) fill-scale (/ target-width child-width)] {:width target-width - :modifiers (ctm/resize (gpt/point fill-scale 1) child-origin transform transform-inverse)}) + :modifiers (ctm/resize-modifiers (gpt/point fill-scale 1) child-origin transform transform-inverse)}) (ctl/col? parent) (let [target-width (max (- line-width (ctl/child-width-margin child)) 0.01) @@ -49,7 +49,7 @@ target-width (min max-width target-width) fill-scale (/ target-width child-width)] {:width target-width - :modifiers (ctm/resize (gpt/point fill-scale 1) child-origin transform transform-inverse)}))) + :modifiers (ctm/resize-modifiers (gpt/point fill-scale 1) child-origin transform transform-inverse)}))) (defn calc-fill-height-data "Calculates the size and modifiers for the height of an auto-fill child" @@ -63,7 +63,7 @@ (let [target-height (max (get-in children-data [(:id child) :child-height]) 0.01) fill-scale (/ target-height child-height)] {:height target-height - :modifiers (ctm/resize (gpt/point 1 fill-scale) child-origin transform transform-inverse)}) + :modifiers (ctm/resize-modifiers (gpt/point 1 fill-scale) child-origin transform transform-inverse)}) (ctl/row? parent) (let [target-height (max (- line-height (ctl/child-height-margin child)) 0.01) @@ -71,7 +71,7 @@ target-height (min max-height target-height) fill-scale (/ target-height child-height)] {:height target-height - :modifiers (ctm/resize (gpt/point 1 fill-scale) child-origin transform transform-inverse)}))) + :modifiers (ctm/resize-modifiers (gpt/point 1 fill-scale) child-origin transform transform-inverse)}))) (defn layout-child-modifiers "Calculates the modifiers for the layout" @@ -93,9 +93,9 @@ move-vec (gpt/to-vec child-origin corner-p) modifiers - (-> (ctm/empty-modifiers) + (-> (ctm/empty) (cond-> fill-width (ctm/add-modifiers (:modifiers fill-width))) (cond-> fill-height (ctm/add-modifiers (:modifiers fill-height))) - (ctm/set-move move-vec))] + (ctm/move move-vec))] [modifiers layout-line])) diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index 3b6a3c61b..2f365a6a2 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -98,7 +98,7 @@ (let [child-modifiers (gct/calc-child-modifiers parent child modifiers ignore-constraints transformed-parent) child-modifiers (cond-> child-modifiers snap-pixel? (gpp/set-pixel-precision child))] (cond-> modif-tree - (not (ctm/empty-modifiers? child-modifiers)) + (not (ctm/empty? child-modifiers)) (update-in [(:id child) :modifiers] ctm/add-modifiers child-modifiers))))] (reduce set-child modif-tree children))) @@ -111,7 +111,7 @@ (ctm/select-child-geometry-modifiers) (gcl/normalize-child-modifiers parent child transformed-parent))] (cond-> modif-tree - (not (ctm/empty-modifiers? child-modifiers)) + (not (ctm/empty? child-modifiers)) (update-in [(:id child) :modifiers] ctm/add-modifiers child-modifiers))))] (let [children (map (d/getf objects) (:shapes transformed-parent))] (reduce process-child modif-tree children)))) @@ -178,14 +178,14 @@ (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))))) + (ctm/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)))))] + (ctm/resize-parent (gpt/point 1 scale-height) origin (:transform parent) (:transform-inverse parent)))))] (let [modifiers (get-in modif-tree [(:id parent) :modifiers]) children (->> parent diff --git a/common/src/app/common/geom/shapes/pixel_precision.cljc b/common/src/app/common/geom/shapes/pixel_precision.cljc index 03aa4359a..297abf99a 100644 --- a/common/src/app/common/geom/shapes/pixel_precision.cljc +++ b/common/src/app/common/geom/shapes/pixel_precision.cljc @@ -32,7 +32,7 @@ ratio-height (/ target-height curr-height) scalev (gpt/point ratio-width ratio-height)] (-> modifiers - (ctm/set-resize scalev origin transform transform-inverse)))) + (ctm/resize scalev origin transform transform-inverse)))) (defn position-pixel-precision [modifiers shape] @@ -42,7 +42,7 @@ target-corner (gpt/round corner) deltav (gpt/to-vec corner target-corner)] (-> modifiers - (ctm/set-move deltav)))) + (ctm/move deltav)))) (defn set-pixel-precision "Adjust modifiers so they adjust to the pixel grid" diff --git a/common/src/app/common/geom/shapes/transforms.cljc b/common/src/app/common/geom/shapes/transforms.cljc index bdaa87807..3dcf61c89 100644 --- a/common/src/app/common/geom/shapes/transforms.cljc +++ b/common/src/app/common/geom/shapes/transforms.cljc @@ -403,7 +403,7 @@ ([shape modifiers] (cond-> shape - (and (some? modifiers) (not (ctm/empty-modifiers? modifiers))) + (and (some? modifiers) (not (ctm/empty? modifiers))) (apply-modifiers modifiers)))) (defn transform-bounds diff --git a/common/src/app/common/types/modifiers.cljc b/common/src/app/common/types/modifiers.cljc index 48710b40c..e6c7943d1 100644 --- a/common/src/app/common/types/modifiers.cljc +++ b/common/src/app/common/types/modifiers.cljc @@ -5,6 +5,7 @@ ;; Copyright (c) UXBOX Labs SL (ns app.common.types.modifiers + (:refer-clojure :exclude [empty empty?]) (:require [app.common.data :as d] [app.common.geom.matrix :as gmt] @@ -13,7 +14,9 @@ [app.common.math :as mth] [app.common.pages.helpers :as cph] [app.common.spec :as us] - [app.common.text :as txt])) + [app.common.text :as txt] + #?(:cljs [cljs.core :as c] + :clj [clojure.core :as c]))) ;; --- Modifiers @@ -39,7 +42,7 @@ ;; Public builder API -(defn empty-modifiers [] +(defn empty [] {}) (defn move-vec? [vector] @@ -50,16 +53,16 @@ (or (not (mth/almost-zero? (- (:x vector) 1))) (not (mth/almost-zero? (- (:y vector) 1))))) -(defn set-move-parent +(defn move-parent ([modifiers x y] - (set-move-parent modifiers (gpt/point x y))) + (move-parent modifiers (gpt/point x y))) ([modifiers vector] (cond-> modifiers (move-vec? vector) (update :geometry-parent conjv {:type :move :vector vector})))) -(defn set-resize-parent +(defn resize-parent ([modifiers vector origin] (cond-> modifiers (resize-vec? vector) @@ -75,16 +78,16 @@ :origin origin :transform transform :transform-inverse transform-inverse})))) -(defn set-move +(defn move ([modifiers x y] - (set-move modifiers (gpt/point x y))) + (move modifiers (gpt/point x y))) ([modifiers vector] (cond-> modifiers (move-vec? vector) (update :geometry-child conjv {:type :move :vector vector})))) -(defn set-resize +(defn resize ([modifiers vector origin] (cond-> modifiers (resize-vec? vector) @@ -101,7 +104,7 @@ :transform transform :transform-inverse transform-inverse})))) -(defn set-rotation +(defn rotation [modifiers center angle] (cond-> modifiers (not (mth/close? angle 0)) @@ -111,14 +114,14 @@ :center center :rotation angle})))) -(defn set-remove-children +(defn remove-children [modifiers shapes] (cond-> modifiers (d/not-empty? shapes) (update :structure-parent conjv {:type :remove-children :value shapes}))) -(defn set-add-children +(defn add-children [modifiers shapes index] (cond-> modifiers (d/not-empty? shapes) @@ -126,17 +129,17 @@ :value shapes :index index}))) -(defn set-reflow +(defn reflow [modifiers] (-> modifiers (update :structure-parent conjv {:type :reflow}))) -(defn set-scale-content +(defn scale-content [modifiers value] (-> modifiers (update :structure-child conjv {:type :scale-content :value value}))) -(defn set-change-property +(defn change-property [modifiers property value] (-> modifiers (update :structure-child conjv {:type :change-property @@ -162,94 +165,66 @@ ;; These are convenience methods to create single operation modifiers without the builder -(defn move +(defn move-modifiers ([x y] - (set-move (empty-modifiers) (gpt/point x y))) + (move (empty) (gpt/point x y))) ([vector] - (set-move (empty-modifiers) vector))) + (move (empty) vector))) -(defn move-parent +(defn move-parent-modifiers ([x y] - (set-move-parent (empty-modifiers) (gpt/point x y))) + (move-parent (empty) (gpt/point x y))) ([vector] - (set-move-parent (empty-modifiers) vector))) + (move-parent (empty) vector))) -(defn resize +(defn resize-modifiers ([vector origin] - (set-resize (empty-modifiers) vector origin)) + (resize (empty) vector origin)) ([vector origin transform transform-inverse] - (set-resize (empty-modifiers) vector origin transform transform-inverse))) + (resize (empty) vector origin transform transform-inverse))) -(defn resize-parent +(defn resize-parent-modifiers ([vector origin] - (set-resize-parent (empty-modifiers) vector origin)) + (resize-parent (empty) vector origin)) ([vector origin transform transform-inverse] - (set-resize-parent (empty-modifiers) vector origin transform transform-inverse))) + (resize-parent (empty) vector origin transform transform-inverse))) -(defn rotation +(defn rotation-modifiers [shape center angle] (let [shape-center (gco/center-shape shape) rotation (-> (gmt/matrix) (gmt/rotate angle center) (gmt/rotate (- angle) shape-center))] - (-> (empty-modifiers) - (set-rotation shape-center angle) - (set-move (gpt/transform (gpt/point 0 0) rotation))))) + (-> (empty) + (rotation shape-center angle) + (move (gpt/transform (gpt/point 0 0) rotation))))) -(defn remove-children +(defn remove-children-modifiers [shapes] - (-> (empty-modifiers) - (set-remove-children shapes))) + (-> (empty) + (remove-children shapes))) -(defn add-children +(defn add-children-modifiers [shapes index] - (-> (empty-modifiers) - (set-add-children shapes index))) + (-> (empty) + (add-children shapes index))) -(defn reflow +(defn reflow-modifiers [] - (-> (empty-modifiers) - (set-reflow))) + (-> (empty) + (reflow))) -(defn scale-content +(defn scale-content-modifiers [value] - (-> (empty-modifiers) - (set-scale-content value))) + (-> (empty) + (scale-content value))) -(defn child-modifiers? - [{:keys [geometry-child structure-child]}] - (or (d/not-empty? geometry-child) - (d/not-empty? structure-child))) - -(defn select-child-modifiers - [modifiers] - (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 - [modifiers] - (select-keys modifiers [:structure-parent])) - -(defn empty-modifiers? - [modifiers] - (and (empty? (:geometry-child modifiers)) - (empty? (:geometry-parent modifiers)) - (empty? (:structure-parent modifiers)) - (empty? (:structure-child modifiers)))) - -(defn change-dimensions +(defn change-dimensions-modifiers [shape attr value] (us/assert map? shape) (us/assert #{:width :height} attr) @@ -281,7 +256,7 @@ scalev (gpt/divide (gpt/point width height) (gpt/point sr-width sr-height))] - (resize scalev origin shape-transform shape-transform-inv))) + (resize-modifiers scalev origin shape-transform shape-transform-inv))) (defn change-orientation-modifiers [shape orientation] @@ -304,28 +279,56 @@ scalev (gpt/divide (gpt/point new-width new-height) (gpt/point sr-width sr-height))] - (resize scalev origin shape-transform shape-transform-inv))) + (resize-modifiers scalev origin shape-transform shape-transform-inv))) -(defn merge-modifiers - [objects modifiers] +;; Predicates - (let [set-modifier - (fn [objects [id modifiers]] - (-> objects - (d/update-when id merge modifiers)))] - (->> modifiers - (reduce set-modifier objects)))) +(defn empty? + [modifiers] + (and (c/empty? (:geometry-child modifiers)) + (c/empty? (:geometry-parent modifiers)) + (c/empty? (:structure-parent modifiers)) + (c/empty? (:structure-child modifiers)))) + +(defn child-modifiers? + [{:keys [geometry-child structure-child]}] + (or (d/not-empty? geometry-child) + (d/not-empty? structure-child))) (defn only-move? + "Returns true if there are only move operations" [modifier] (or (and (= 1 (-> modifier :geometry-child count)) (= :move (-> modifier :geometry-child first :type))) (and (= 1 (-> modifier :geometry-parent count)) (= :move (-> modifier :geometry-parent first :type))))) -(defn get-frame-add-children - [modif-tree] +(defn has-geometry? + [{:keys [geometry-parent geometry-child]}] + (or (d/not-empty? geometry-parent) + (d/not-empty? geometry-child))) +;; Extract subsets of modifiers + +(defn select-child-modifiers + [modifiers] + (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 + [modifiers] + (select-keys modifiers [:structure-parent])) + +(defn added-children-frames + "Returns the frames that have an 'add-children' operation" + [modif-tree] (let [structure-changes (into {} (comp (filter (fn [[_ val]] (-> val :modifiers :structure-parent some?))) @@ -340,7 +343,10 @@ (->> value (map (fn [id] {:frame frame-id :shape id})))))))) structure-changes))) +;; Main transformation functions + (defn modifiers->transform + "Given a set of modifiers returns its transformation matrix" [modifiers] (letfn [(apply-modifier [matrix {:keys [type vector rotation center origin transform transform-inverse] :as modifier}] (case type @@ -360,7 +366,6 @@ matrix) :rotation - ;; TODO LAYOUT: Maybe an issue when no center data (gmt/multiply (-> (gmt/matrix) (gmt/translate center) @@ -373,63 +378,60 @@ (->> modifiers (reduce apply-modifier (gmt/matrix)))))) -(defn scale-text-content - [content value] - - (->> content - (txt/transform-nodes - txt/is-text-node? - (fn [attrs] - (let [font-size (-> (get attrs :font-size 14) - (d/parse-double) - (* value) - (str)) ] - (d/txt-merge attrs {:font-size font-size})))))) - -(defn apply-scale-content - [shape value] - - (cond-> shape - (cph/text-shape? shape) - (update :content scale-text-content value))) - (defn apply-structure-modifiers + "Apply structure changes to a shape" [shape modifiers] - (let [remove-children - (fn [shapes children-to-remove] - (let [remove? (set children-to-remove)] - (d/removev remove? shapes))) + (letfn [(scale-text-content + [content value] - apply-modifier - (fn [shape {:keys [type property value index rotation]}] - (cond-> shape - (= type :rotation) - (update :rotation #(mod (+ % rotation) 360)) + (->> content + (txt/transform-nodes + txt/is-text-node? + (fn [attrs] + (let [font-size (-> (get attrs :font-size 14) + (d/parse-double) + (* value) + (str)) ] + (d/txt-merge attrs {:font-size font-size})))))) - (and (= type :add-children) (some? index)) - (update :shapes - (fn [shapes] - (if (vector? shapes) - (cph/insert-at-index shapes index value) - (d/concat-vec shapes value)))) + (apply-scale-content + [shape value] - (and (= type :add-children) (nil? index)) - (update :shapes d/concat-vec value) + (cond-> shape + (cph/text-shape? shape) + (update :content scale-text-content value)))] + (let [remove-children + (fn [shapes children-to-remove] + (let [remove? (set children-to-remove)] + (d/removev remove? shapes))) - (= type :remove-children) - (update :shapes remove-children value) + apply-modifier + (fn [shape {:keys [type property value index rotation]}] + (cond-> shape + (= type :rotation) + (update :rotation #(mod (+ % rotation) 360)) - (= type :scale-content) - (apply-scale-content value) + (and (= type :add-children) (some? index)) + (update :shapes + (fn [shapes] + (if (vector? shapes) + (cph/insert-at-index shapes index value) + (d/concat-vec shapes value)))) - (= type :change-property) - (assoc property value)))] + (and (= type :add-children) (nil? index)) + (update :shapes d/concat-vec value) + + (= type :remove-children) + (update :shapes remove-children value) + + (= type :scale-content) + (apply-scale-content value) + + (= type :change-property) + (assoc property value)))] + + (as-> shape $ + (reduce apply-modifier $ (:structure-parent modifiers)) + (reduce apply-modifier $ (:structure-child modifiers)))))) - (as-> shape $ - (reduce apply-modifier $ (:structure-parent modifiers)) - (reduce apply-modifier $ (:structure-child modifiers))))) -(defn has-geometry? - [{:keys [geometry-parent geometry-child]}] - (or (d/not-empty? geometry-parent) - (d/not-empty? geometry-child))) diff --git a/common/test/common_tests/geom_shapes_test.cljc b/common/test/common_tests/geom_shapes_test.cljc index eae43ef1b..e974774f8 100644 --- a/common/test/common_tests/geom_shapes_test.cljc +++ b/common/test/common_tests/geom_shapes_test.cljc @@ -60,7 +60,7 @@ (t/testing "Transform shape with translation modifiers" (t/are [type] - (let [modifiers (ctm/move (gpt/point 10 -10))] + (let [modifiers (ctm/move-modifiers (gpt/point 10 -10))] (let [shape-before (create-test-shape type {:modifiers modifiers}) shape-after (gsh/transform-shape shape-before)] (t/is (not= shape-before shape-after)) @@ -92,7 +92,7 @@ (t/testing "Transform shape with resize modifiers" (t/are [type] - (let [modifiers (ctm/resize (gpt/point 2 2) (gpt/point 0 0)) + (let [modifiers (ctm/resize-modifiers (gpt/point 2 2) (gpt/point 0 0)) shape-before (create-test-shape type {:modifiers modifiers}) shape-after (gsh/transform-shape shape-before)] (t/is (not= shape-before shape-after)) @@ -112,7 +112,7 @@ (t/testing "Transform with empty resize" (t/are [type] - (let [modifiers (ctm/resize (gpt/point 1 1) (gpt/point 0 0)) + (let [modifiers (ctm/resize-modifiers (gpt/point 1 1) (gpt/point 0 0)) shape-before (create-test-shape type {:modifiers modifiers}) shape-after (gsh/transform-shape shape-before)] (t/are [prop] @@ -123,7 +123,7 @@ (t/testing "Transform with resize=0" (t/are [type] - (let [modifiers (ctm/resize (gpt/point 0 0) (gpt/point 0 0)) + (let [modifiers (ctm/resize-modifiers (gpt/point 0 0) (gpt/point 0 0)) shape-before (create-test-shape type {:modifiers modifiers}) shape-after (gsh/transform-shape shape-before)] (t/is (> (get-in shape-before [:selrect :width]) @@ -138,7 +138,7 @@ (t/testing "Transform shape with rotation modifiers" (t/are [type] (let [shape-before (create-test-shape type) - modifiers (ctm/rotation shape-before (gsh/center-shape shape-before) 30 ) + modifiers (ctm/rotation-modifiers shape-before (gsh/center-shape shape-before) 30 ) shape-before (assoc shape-before :modifiers modifiers) shape-after (gsh/transform-shape shape-before)] @@ -160,7 +160,7 @@ (t/testing "Transform shape with rotation = 0 should leave equal selrect" (t/are [type] (let [shape-before (create-test-shape type) - modifiers (ctm/rotation shape-before (gsh/center-shape shape-before) 0) + modifiers (ctm/rotation-modifiers shape-before (gsh/center-shape shape-before) 0) shape-after (gsh/transform-shape (assoc shape-before :modifiers modifiers))] (t/are [prop] (t/is (close? (get-in shape-before [:selrect prop]) @@ -170,7 +170,7 @@ (t/testing "Transform shape with invalid selrect fails gracefully" (t/are [type selrect] - (let [modifiers (ctm/move 0 0) + (let [modifiers (ctm/move-modifiers 0 0) shape-before (-> (create-test-shape type {:modifiers modifiers}) (assoc :selrect selrect)) shape-after (gsh/transform-shape shape-before)] diff --git a/frontend/src/app/main/data/workspace/drawing/box.cljs b/frontend/src/app/main/data/workspace/drawing/box.cljs index ad91a1226..c586af8c4 100644 --- a/frontend/src/app/main/data/workspace/drawing/box.cljs +++ b/frontend/src/app/main/data/workspace/drawing/box.cljs @@ -47,9 +47,9 @@ (-> shape (assoc :click-draw? false) - (gsh/transform-shape (-> (ctm/empty-modifiers) - (ctm/set-resize scalev (gpt/point x y)) - (ctm/set-move movev)))))) + (gsh/transform-shape (-> (ctm/empty) + (ctm/resize scalev (gpt/point x y)) + (ctm/move movev)))))) (defn update-drawing [state initial point lock?] (update-in state [:workspace-drawing :object] resize-shape initial point lock?)) diff --git a/frontend/src/app/main/data/workspace/drawing/common.cljs b/frontend/src/app/main/data/workspace/drawing/common.cljs index 2016c3c7d..ad0da2563 100644 --- a/frontend/src/app/main/data/workspace/drawing/common.cljs +++ b/frontend/src/app/main/data/workspace/drawing/common.cljs @@ -51,7 +51,7 @@ (and click-draw? (not text?)) (-> (assoc :width min-side :height min-side) - (gsh/transform-shape (ctm/move (- (/ min-side 2)) (- (/ min-side 2))))) + (gsh/transform-shape (ctm/move-modifiers (- (/ min-side 2)) (- (/ min-side 2))))) (and click-draw? text?) (assoc :height 17 :width 4 :grow-type :auto-width) diff --git a/frontend/src/app/main/data/workspace/modifiers.cljs b/frontend/src/app/main/data/workspace/modifiers.cljs index 9263d9745..b6f6d2464 100644 --- a/frontend/src/app/main/data/workspace/modifiers.cljs +++ b/frontend/src/app/main/data/workspace/modifiers.cljs @@ -159,11 +159,11 @@ (filterv #(contains? child-set %)))] (cond-> modif-tree (not= original-frame target-frame) - (-> (update-in [original-frame :modifiers] ctm/set-remove-children shapes) - (update-in [target-frame :modifiers] ctm/set-add-children shapes drop-index)) + (-> (update-in [original-frame :modifiers] ctm/remove-children shapes) + (update-in [target-frame :modifiers] ctm/add-children shapes drop-index)) (and layout? (= original-frame target-frame)) - (update-in [target-frame :modifiers] ctm/set-add-children shapes drop-index))))] + (update-in [target-frame :modifiers] ctm/add-children shapes drop-index))))] (reduce update-frame-modifiers modif-tree origin-frame-ids))) @@ -214,7 +214,7 @@ get-modifier (fn [shape] - (ctm/rotation shape center angle)) + (ctm/rotation-modifiers shape center angle)) modif-tree (-> (build-modif-tree ids objects get-modifier) diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index c1a94684a..799cf0497 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -52,7 +52,7 @@ (let [objects (wsh/lookup-page-objects state) ids (->> ids (filter (partial ctl/layout? objects)))] (if (d/not-empty? ids) - (let [modif-tree (dwm/create-modif-tree ids (ctm/reflow))] + (let [modif-tree (dwm/create-modif-tree ids (ctm/reflow-modifiers))] (rx/of (dwm/set-modifiers modif-tree) (dwm/apply-modifiers))) (rx/empty)))))) diff --git a/frontend/src/app/main/data/workspace/texts.cljs b/frontend/src/app/main/data/workspace/texts.cljs index 06592a153..0527184a0 100644 --- a/frontend/src/app/main/data/workspace/texts.cljs +++ b/frontend/src/app/main/data/workspace/texts.cljs @@ -322,11 +322,11 @@ {shape-width :width shape-height :height} selrect] (cond-> shape (and (not-changed? shape-width new-width) (= grow-type :auto-width)) - (gsh/transform-shape (ctm/change-dimensions shape :width new-width)) + (gsh/transform-shape (ctm/change-dimensions-modifiers shape :width new-width)) (and (not-changed? shape-height new-height) (or (= grow-type :auto-height) (= grow-type :auto-width))) - (gsh/transform-shape (ctm/change-dimensions shape :height new-height)))))] + (gsh/transform-shape (ctm/change-dimensions-modifiers shape :height new-height)))))] (rx/of (dch/update-shapes [id] update-fn {:reg-objects? true :save-undo? false})))))) @@ -346,10 +346,10 @@ (let [new-shape (cond-> shape (some? width) - (gsh/transform-shape (ctm/change-dimensions shape :width width)) + (gsh/transform-shape (ctm/change-dimensions-modifiers shape :width width)) (some? height) - (gsh/transform-shape (ctm/change-dimensions shape :height height)) + (gsh/transform-shape (ctm/change-dimensions-modifiers shape :height height)) (some? position-data) (assoc :position-data position-data)) diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 7ef6eb3cd..543757c1f 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -185,19 +185,19 @@ (and layout-child? fill-height?))) modifiers - (-> (ctm/empty-modifiers) + (-> (ctm/empty) (cond-> displacement - (ctm/set-move displacement)) - (ctm/set-resize scalev resize-origin shape-transform shape-transform-inverse) + (ctm/move displacement)) + (ctm/resize scalev resize-origin shape-transform shape-transform-inverse) (cond-> set-fix-width? - (ctm/set-change-property :layout-item-h-sizing :fix)) + (ctm/change-property :layout-item-h-sizing :fix)) (cond-> set-fix-height? - (ctm/set-change-property :layout-item-v-sizing :fix)) + (ctm/change-property :layout-item-v-sizing :fix)) (cond-> scale-text - (ctm/set-scale-content (:x scalev)))) + (ctm/scale-content (:x scalev)))) modif-tree (dwm/create-modif-tree ids modifiers)] (rx/of (dwm/set-modifiers modif-tree)))) @@ -251,7 +251,7 @@ snap-pixel? (and (contains? (:workspace-layout state) :snap-pixel-grid) (int? value)) get-modifier - (fn [shape] (ctm/change-dimensions shape attr value)) + (fn [shape] (ctm/change-dimensions-modifiers shape attr value)) modif-tree (-> (dwm/build-modif-tree ids objects get-modifier) @@ -486,7 +486,7 @@ (->> move-stream (rx/map (fn [[move-vector target-frame drop-index]] - (-> (dwm/create-modif-tree ids (ctm/move move-vector)) + (-> (dwm/create-modif-tree ids (ctm/move-modifiers move-vector)) (dwm/build-change-frame-modifiers objects selected target-frame drop-index) (dwm/set-modifiers))))) @@ -540,7 +540,7 @@ (rx/merge (->> move-events (rx/scan #(gpt/add %1 mov-vec) (gpt/point 0 0)) - (rx/map #(dwm/create-modif-tree selected (ctm/move %))) + (rx/map #(dwm/create-modif-tree selected (ctm/move-modifiers %))) (rx/map (partial dwm/set-modifiers)) (rx/take-until stopper)) (rx/of (move-selected direction shift?))) @@ -573,7 +573,7 @@ (or (:y position) (:y bbox))) delta (gpt/subtract pos cpos) - modif-tree (dwm/create-modif-tree [id] (ctm/move delta))] + modif-tree (dwm/create-modif-tree [id] (ctm/move-modifiers delta))] (rx/of (dwm/set-modifiers modif-tree) (dwm/apply-modifiers)))))) @@ -633,9 +633,9 @@ modif-tree (dwm/create-modif-tree selected - (-> (ctm/empty-modifiers) - (ctm/set-resize (gpt/point -1.0 1.0) origin) - (ctm/set-move (gpt/point (:width selrect) 0))))] + (-> (ctm/empty) + (ctm/resize (gpt/point -1.0 1.0) origin) + (ctm/move (gpt/point (:width selrect) 0))))] (rx/of (dwm/set-modifiers modif-tree true) (dwm/apply-modifiers)))))) @@ -652,9 +652,9 @@ modif-tree (dwm/create-modif-tree selected - (-> (ctm/empty-modifiers) - (ctm/set-resize (gpt/point 1.0 -1.0) origin) - (ctm/set-move (gpt/point 0 (:height selrect)))))] + (-> (ctm/empty) + (ctm/resize (gpt/point 1.0 -1.0) origin) + (ctm/move (gpt/point 0 (:height selrect)))))] (rx/of (dwm/set-modifiers modif-tree true) (dwm/apply-modifiers)))))) diff --git a/frontend/src/app/main/render.cljs b/frontend/src/app/main/render.cljs index a2627d2da..c12236ad1 100644 --- a/frontend/src/app/main/render.cljs +++ b/frontend/src/app/main/render.cljs @@ -187,7 +187,7 @@ mod-ids (cons object-id (cph/get-children-ids objects object-id)) - updt-fn #(update %1 %2 gsh/transform-shape (ctm/move vector))] + updt-fn #(update %1 %2 gsh/transform-shape (ctm/move-modifiers vector))] (reduce updt-fn objects mod-ids))) @@ -254,14 +254,14 @@ objects (mf/with-memo [frame-id objects vector] - (let [update-fn #(update %1 %2 gsh/transform-shape (ctm/move vector))] + (let [update-fn #(update %1 %2 gsh/transform-shape (ctm/move-modifiers vector))] (->> children-ids (into [frame-id]) (reduce update-fn objects)))) frame (mf/with-memo [vector] - (gsh/transform-shape frame (ctm/move vector))) + (gsh/transform-shape frame (ctm/move-modifiers vector))) frame (cond-> frame @@ -313,7 +313,7 @@ (mf/deps vector objects group-id) (fn [] (let [children-ids (cons group-id (cph/get-children-ids objects group-id)) - update-fn #(update %1 %2 gsh/transform-shape (ctm/move vector))] + update-fn #(update %1 %2 gsh/transform-shape (ctm/move-modifiers vector))] (reduce update-fn objects children-ids)))) group (get objects group-id) diff --git a/frontend/src/app/main/ui/viewer/interactions.cljs b/frontend/src/app/main/ui/viewer/interactions.cljs index 51b136d11..47bd71143 100644 --- a/frontend/src/app/main/ui/viewer/interactions.cljs +++ b/frontend/src/app/main/ui/viewer/interactions.cljs @@ -33,7 +33,7 @@ (let [frame-id (:id frame) vector (-> (gpt/point (:x size) (:y size)) (gpt/negate)) - update-fn #(d/update-when %1 %2 gsh/transform-shape (ctm/move vector))] + update-fn #(d/update-when %1 %2 gsh/transform-shape (ctm/move-modifiers vector))] (->> (cph/get-children-ids objects frame-id) (into [frame-id]) (reduce update-fn objects)))) diff --git a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs index b5a34ba65..5b2a0a800 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs @@ -188,7 +188,7 @@ (/ (:height shape) (:height shape')))] ;; Reverse the change in size so we can recalculate the layout (-> modifiers - (ctm/set-resize scalev (-> shape' :points first) (:transform shape') (:transform-inverse shape'))))) + (ctm/resize scalev (-> shape' :points first) (:transform shape') (:transform-inverse shape'))))) (defn use-dynamic-modifiers [objects node modifiers] @@ -205,7 +205,7 @@ (ctm/modifiers->transform modifiers))) modifiers)))) - add-children (mf/use-memo (mf/deps modifiers) #(ctm/get-frame-add-children modifiers)) + add-children (mf/use-memo (mf/deps modifiers) #(ctm/added-children-frames modifiers)) add-children (hooks/use-equal-memo add-children) add-children-prev (hooks/use-previous add-children) diff --git a/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs b/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs index 50e2e6ebc..96d946f26 100644 --- a/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs @@ -42,7 +42,7 @@ deltav (gpt/to-vec (gpt/point (:selrect shape')) (gpt/point (:selrect shape)))] - (gsh/transform-shape shape' (ctm/move deltav)))) + (gsh/transform-shape shape' (ctm/move-modifiers deltav)))) (defn process-shape [modifiers {:keys [id] :as shape}] (let [modifier (dm/get-in modifiers [id :modifiers])] From e61e76a074ce4cc6ced5cca22b4046f7a36204cd Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Mon, 7 Nov 2022 17:26:28 +0100 Subject: [PATCH 26/36] :sparkles: Fix problems with flipped layouts --- .../app/common/geom/shapes/constraints.cljc | 5 +- .../common/geom/shapes/flex_layout/lines.cljc | 10 ++-- .../geom/shapes/flex_layout/modifiers.cljc | 3 +- .../geom/shapes/flex_layout/positions.cljc | 10 ++++ .../app/common/geom/shapes/transforms.cljc | 1 - common/src/app/common/types/modifiers.cljc | 12 +++-- frontend/src/app/main/data/workspace.cljs | 3 +- .../src/app/main/ui/workspace/viewport.cljs | 10 +++- .../app/main/ui/workspace/viewport/debug.cljs | 51 +++++++++++++++++-- frontend/src/debug.cljs | 3 ++ 10 files changed, 84 insertions(+), 24 deletions(-) diff --git a/common/src/app/common/geom/shapes/constraints.cljc b/common/src/app/common/geom/shapes/constraints.cljc index c90cd179b..0b9fe0b6f 100644 --- a/common/src/app/common/geom/shapes/constraints.cljc +++ b/common/src/app/common/geom/shapes/constraints.cljc @@ -9,6 +9,7 @@ [app.common.geom.point :as gpt] [app.common.geom.shapes.common :as gco] [app.common.geom.shapes.intersect :as gsi] + [app.common.geom.shapes.points :as gpo] [app.common.geom.shapes.rect :as gre] [app.common.geom.shapes.transforms :as gst] [app.common.math :as mth] @@ -235,9 +236,7 @@ child-bb-after (gst/parent-coords-rect transformed-child transformed-parent) scale-x (/ (:width child-bb-before) (:width child-bb-after)) scale-y (/ (:height child-bb-before) (:height child-bb-after)) - - ;; TODO LAYOUT: Is the first always the origin? - resize-origin (-> transformed-parent :points first)] + resize-origin (-> transformed-parent :points gpo/origin)] (cond-> modifiers (not= :scale constraints-h) diff --git a/common/src/app/common/geom/shapes/flex_layout/lines.cljc b/common/src/app/common/geom/shapes/flex_layout/lines.cljc index e26894fa6..2a5c255b8 100644 --- a/common/src/app/common/geom/shapes/flex_layout/lines.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/lines.cljc @@ -22,13 +22,8 @@ [pad-top pad-right pad-bottom pad-left] (if (= layout-padding-type :multiple) [pad-top pad-right pad-bottom pad-left] - [pad-top pad-top pad-top pad-top]) - - ;; Normalize the points to remove flips - ;; TODO LAYOUT: Need function to normalize the points - points (gst/parent-coords-points shape shape)] - - (gpo/pad-points points pad-top pad-right pad-bottom pad-left))) + [pad-top pad-top pad-top pad-top])] + (gpo/pad-points (:points shape) pad-top pad-right pad-bottom pad-left))) (defn init-layout-lines "Calculates the lines basic data and accumulated values. The positions will be calculated in a different operation" @@ -312,5 +307,6 @@ (mapv (partial add-children-resizes shape)))] {:layout-lines layout-lines + :layout-bounds layout-bounds :reverse? reverse?})) diff --git a/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc b/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc index 2a9a04e09..039f17f98 100644 --- a/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc @@ -22,8 +22,7 @@ child-bb-after (gst/parent-coords-rect transformed-child transformed-parent) scale-x (/ (:width child-bb-before) (:width child-bb-after)) scale-y (/ (:height child-bb-before) (:height child-bb-after)) - - resize-origin (-> transformed-parent :points first) ;; TODO LAYOUT: IS always the origin + resize-origin (-> transformed-parent :points gpo/origin) resize-vector (gpt/point scale-x scale-y)] (-> modifiers (ctm/select-child-modifiers) diff --git a/common/src/app/common/geom/shapes/flex_layout/positions.cljc b/common/src/app/common/geom/shapes/flex_layout/positions.cljc index 30437fd16..d6bc69c21 100644 --- a/common/src/app/common/geom/shapes/flex_layout/positions.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/positions.cljc @@ -249,6 +249,16 @@ (some? margin-y) (gpt/add (vv margin-y))) + + ;; Fix position when layout is flipped + corner-p + (cond-> corner-p + (:flip-x parent) + (gpt/add (hv child-width)) + + (:flip-y parent) + (gpt/add (vv child-height))) + next-p (cond-> start-p row? diff --git a/common/src/app/common/geom/shapes/transforms.cljc b/common/src/app/common/geom/shapes/transforms.cljc index 3dcf61c89..564f9cf74 100644 --- a/common/src/app/common/geom/shapes/transforms.cljc +++ b/common/src/app/common/geom/shapes/transforms.cljc @@ -311,7 +311,6 @@ (cond-> (some? selrect) (assoc :selrect selrect)) - ;; TODO LAYOUT: Make sure the order of points is alright (cond-> (d/not-empty? points) (assoc :points points)) (assoc :rotation rotation)))) diff --git a/common/src/app/common/types/modifiers.cljc b/common/src/app/common/types/modifiers.cljc index e6c7943d1..8b2d27445 100644 --- a/common/src/app/common/types/modifiers.cljc +++ b/common/src/app/common/types/modifiers.cljc @@ -196,13 +196,17 @@ (defn rotation-modifiers [shape center angle] (let [shape-center (gco/center-shape shape) - rotation (-> (gmt/matrix) - (gmt/rotate angle center) - (gmt/rotate (- angle) shape-center))] + ;; Translation caused by the rotation + move-vec + (gpt/transform + (gpt/point 0 0) + (-> (gmt/matrix) + (gmt/rotate angle center) + (gmt/rotate (- angle) shape-center)))] (-> (empty) (rotation shape-center angle) - (move (gpt/transform (gpt/point 0 0) rotation))))) + (move move-vec)))) (defn remove-children-modifiers [shapes] diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 895c5799e..bedd71065 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -1580,8 +1580,7 @@ (ptk/reify ::create-artboard-from-selection ptk/WatchEvent (watch [_ state _] - (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + (let [objects (wsh/lookup-page-objects state) selected (wsh/lookup-selected state) selected-objs (map #(get objects %) selected)] (when (d/not-empty? selected) diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index 586e1b389..80217083d 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -418,10 +418,16 @@ ;; DEBUG LAYOUT DROP-ZONES (when (debug? :layout-drop-zones) + [:& wvd/debug-drop-zones {:selected-shapes selected-shapes + :objects objects-modified + :hover-top-frame-id @hover-top-frame-id + :zoom zoom}]) + + (when (debug? :layout-lines) [:& wvd/debug-layout {:selected-shapes selected-shapes :objects objects-modified - :hover-top-frame-id @hover-top-frame-id}]) - + :hover-top-frame-id @hover-top-frame-id + :zoom zoom}]) (when show-selection-handlers? [:g.selection-handlers {:clipPath "url(#clip-handlers)"} diff --git a/frontend/src/app/main/ui/workspace/viewport/debug.cljs b/frontend/src/app/main/ui/workspace/viewport/debug.cljs index d338c0a71..f1fcecf0e 100644 --- a/frontend/src/app/main/ui/workspace/viewport/debug.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/debug.cljs @@ -8,13 +8,17 @@ (: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.flex-layout :as gsl] + [app.common.geom.shapes.points :as gpo] [app.common.pages.helpers :as cph] + [app.common.types.shape.layout :as ctl] + [cuerdas.core :as str] [rumext.v2 :as mf])) ;; Helper to debug the bounds when set the "hug" content property -#_(mf/defc debug-bounds +#_(mf/defc debug-layout "Debug component to show the auto-layout drop areas" {::mf/wrap-props false} [props] @@ -57,6 +61,47 @@ [props] (let [objects (unchecked-get props "objects") + zoom (unchecked-get props "zoom") + selected-shapes (unchecked-get props "selected-shapes") + hover-top-frame-id (unchecked-get props "hover-top-frame-id") + + selected-frame + (when (and (= (count selected-shapes) 1) (= :frame (-> selected-shapes first :type))) + (first selected-shapes)) + + shape (or selected-frame (get objects hover-top-frame-id))] + + (when (and shape (ctl/layout? shape)) + (let [row? (ctl/row? shape) + col? (ctl/col? shape) + + children (cph/get-immediate-children objects (:id shape)) + layout-data (gsl/calc-layout-data shape children) + + layout-bounds (:layout-bounds layout-data) + xv #(gpo/start-hv layout-bounds %) + yv #(gpo/start-vv layout-bounds %)] + [:g.debug-layout {:pointer-events "none"} + (for [[idx {:keys [start-p line-width line-height layout-gap-row layout-gap-col num-children]}] (d/enumerate (:layout-lines layout-data))] + (let [line-width (if row? (+ line-width (* (dec num-children) layout-gap-row)) line-width) + line-height (if col? (+ line-height (* (dec num-children) layout-gap-col)) line-height) + + 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))) + ]] + [: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))}}]]))])))) + +(mf/defc debug-drop-zones + "Debug component to show the auto-layout drop areas" + {::mf/wrap-props false} + [props] + + (let [objects (unchecked-get props "objects") + zoom (unchecked-get props "objects") selected-shapes (unchecked-get props "selected-shapes") hover-top-frame-id (unchecked-get props "hover-top-frame-id") @@ -81,8 +126,8 @@ :style {:fill "blue" :fill-opacity 0.3 :stroke "red" - :stroke-width 1 - :stroke-dasharray "3 6"}}] + :stroke-width (/ zoom 1) + :stroke-dasharray (dm/str (/ 3 zoom) " " (/ 6 zoom))}}] [:text {:x (:x drop-area) :y (:y drop-area) :width (:width drop-area) diff --git a/frontend/src/debug.cljs b/frontend/src/debug.cljs index d4856cbda..f64e98f4b 100644 --- a/frontend/src/debug.cljs +++ b/frontend/src/debug.cljs @@ -71,6 +71,9 @@ ;; Enable a widget to show the auto-layout drop-zones :layout-drop-zones + ;; Display the layout lines + :layout-lines + ;; Makes the pixel grid red so its more visibile :pixel-grid }) From cdaba395c400011f157d138d1e140975b12808e4 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Mon, 7 Nov 2022 18:21:36 +0100 Subject: [PATCH 27/36] :sparkles: Small fixes for flex layout --- common/src/app/common/geom/shapes/constraints.cljc | 1 - .../common/geom/shapes/flex_layout/drop_area.cljc | 14 ++------------ .../common/geom/shapes/flex_layout/positions.cljc | 1 - common/src/app/common/pages/helpers.cljc | 6 ------ common/test/common_tests/geom_shapes_test.cljc | 9 ++++----- frontend/src/app/main/data/workspace/shapes.cljs | 3 ++- frontend/src/app/main/render.cljs | 11 +++-------- .../src/app/main/ui/viewer/handoff/render.cljs | 2 -- frontend/src/app/main/ui/viewer/shapes.cljs | 1 - .../app/main/ui/workspace/viewport/selection.cljs | 3 --- 10 files changed, 11 insertions(+), 40 deletions(-) diff --git a/common/src/app/common/geom/shapes/constraints.cljc b/common/src/app/common/geom/shapes/constraints.cljc index 0b9fe0b6f..00b1f700a 100644 --- a/common/src/app/common/geom/shapes/constraints.cljc +++ b/common/src/app/common/geom/shapes/constraints.cljc @@ -81,7 +81,6 @@ cp (gsi/line-line-intersect c3 (gpt/add c3 dir-v) p0 p3)] (gpt/to-vec c3 cp))) - (defn top-vector [child-points parent-points] diff --git a/common/src/app/common/geom/shapes/flex_layout/drop_area.cljc b/common/src/app/common/geom/shapes/flex_layout/drop_area.cljc index 228e09b13..3b9ff8a58 100644 --- a/common/src/app/common/geom/shapes/flex_layout/drop_area.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/drop_area.cljc @@ -16,6 +16,7 @@ [app.common.types.shape.layout :as ctl])) (defn layout-drop-areas + "Retrieve the layout drop areas to move shapes inside layouts" [{:keys [margin-x margin-y] :as frame} layout-data children] (let [col? (ctl/col? frame) @@ -84,14 +85,7 @@ (-> (gsr/make-rect x (+ y half-point-height) width (- height half-point-height)) (assoc :index (if reverse? index (inc index))))])) - result (conj result line-area-1 line-area-2) - - ;;line-area - ;;(-> (gsr/make-rect x y width height) - ;; (assoc :index (if reverse? (inc index) index))) - ;;result (conj result line-area) - ;;result (conj result (gsr/make-rect box-x box-y box-width box-height)) - ] + result (conj result line-area-1 line-area-2)] [result parent-rect (+ x width) (+ y height)])) @@ -158,10 +152,6 @@ children (subvec children from-idx (+ from-idx num-children)) - - ;; To debug the lines - ;;result (conj result line-area) - result (first (reduce redfn-child [result line-area] (d/with-next children)))] [result (+ from-idx num-children) (+ x width) (+ y height)]))] diff --git a/common/src/app/common/geom/shapes/flex_layout/positions.cljc b/common/src/app/common/geom/shapes/flex_layout/positions.cljc index d6bc69c21..ae748d060 100644 --- a/common/src/app/common/geom/shapes/flex_layout/positions.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/positions.cljc @@ -249,7 +249,6 @@ (some? margin-y) (gpt/add (vv margin-y))) - ;; Fix position when layout is flipped corner-p (cond-> corner-p diff --git a/common/src/app/common/pages/helpers.cljc b/common/src/app/common/pages/helpers.cljc index 2799639a5..7bbda08e8 100644 --- a/common/src/app/common/pages/helpers.cljc +++ b/common/src/app/common/pages/helpers.cljc @@ -33,12 +33,6 @@ ([{:keys [type]}] (= type :frame))) -(defn layout-shape? - ([objects id] - (layout-shape? (get objects id))) - ([{:keys [type layout]}] - (and (= type :frame) layout))) - (defn group-shape? [{:keys [type]}] (= type :group)) diff --git a/common/test/common_tests/geom_shapes_test.cljc b/common/test/common_tests/geom_shapes_test.cljc index e974774f8..864bf6b8c 100644 --- a/common/test/common_tests/geom_shapes_test.cljc +++ b/common/test/common_tests/geom_shapes_test.cljc @@ -171,12 +171,11 @@ (t/testing "Transform shape with invalid selrect fails gracefully" (t/are [type selrect] (let [modifiers (ctm/move-modifiers 0 0) - shape-before (-> (create-test-shape type {:modifiers modifiers}) - (assoc :selrect selrect)) - shape-after (gsh/transform-shape shape-before)] + shape-before (-> (create-test-shape type) (assoc :selrect selrect)) + shape-after (gsh/transform-shape shape-before modifiers)] - (t/is (not= (:selrect shape-before) - (:selrect shape-after)))) + (t/is (= (:selrect shape-before) + (:selrect shape-after)))) :rect {:x 0.0 :y 0.0 :x1 0.0 :y1 0.0 :x2 ##Inf :y2 ##Inf :width ##Inf :height ##Inf} :path {:x 0.0 :y 0.0 :x1 0.0 :y1 0.0 :x2 ##Inf :y2 ##Inf :width ##Inf :height ##Inf} diff --git a/frontend/src/app/main/data/workspace/shapes.cljs b/frontend/src/app/main/data/workspace/shapes.cljs index 2f15ac226..b36930d58 100644 --- a/frontend/src/app/main/data/workspace/shapes.cljs +++ b/frontend/src/app/main/data/workspace/shapes.cljs @@ -16,6 +16,7 @@ [app.common.types.shape :as cts] [app.common.types.shape-tree :as ctst] [app.common.types.shape.interactions :as ctsi] + [app.common.types.shape.layout :as ctl] [app.common.uuid :as uuid] [app.main.data.comments :as dc] [app.main.data.workspace.changes :as dch] @@ -148,7 +149,7 @@ layout-ids (->> ids (mapcat (partial cph/get-parent-ids objects)) - (filter (partial cph/layout-shape? objects))) + (filter (partial ctl/layout? objects))) components-v2 (features/active-feature? state :components-v2) diff --git a/frontend/src/app/main/render.cljs b/frontend/src/app/main/render.cljs index c12236ad1..41073f6e2 100644 --- a/frontend/src/app/main/render.cljs +++ b/frontend/src/app/main/render.cljs @@ -81,9 +81,7 @@ [{:keys [shape] :as props}] (let [render-thumbnails? (mf/use-ctx muc/render-thumbnails) - childs (mapv #(get objects %) (:shapes shape)) - ;;shape (gsh/transform-shape shape) - ] + childs (mapv #(get objects %) (:shapes shape))] (if (and render-thumbnails? (some? (:thumbnail shape))) [:& frame/frame-thumbnail {:shape shape :bounds (:children-bounds shape)}] [:& frame-shape {:shape shape :childs childs}]))))) @@ -136,8 +134,7 @@ bool-wrapper (mf/use-memo (mf/deps objects) #(bool-wrapper-factory objects)) frame-wrapper (mf/use-memo (mf/deps objects) #(frame-wrapper-factory objects))] (when (and shape (not (:hidden shape))) - (let [;;shape (gsh/transform-shape shape) - opts #js {:shape shape} + (let [opts #js {:shape shape} svg-raw? (= :svg-raw (:type shape))] (if-not svg-raw? [:> shape-container {:shape shape} @@ -167,9 +164,7 @@ [objects object] (let [shapes (cph/get-immediate-children objects) srect (gsh/selection-rect shapes) - object (merge object (select-keys srect [:x :y :width :height])) - ;; object (gsh/transform-shape object) - ] + object (merge object (select-keys srect [:x :y :width :height]))] (assoc object :fill-color "#f0f0f0"))) (defn adapt-objects-for-shape diff --git a/frontend/src/app/main/ui/viewer/handoff/render.cljs b/frontend/src/app/main/ui/viewer/handoff/render.cljs index 0fc20987e..d32844940 100644 --- a/frontend/src/app/main/ui/viewer/handoff/render.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/render.cljs @@ -88,8 +88,6 @@ [props] (let [shape (unchecked-get props "shape") childs (mapv #(get objects %) (:shapes shape)) - ;;shape (gsh/transform-shape shape) - props (-> (obj/create) (obj/merge! props) (obj/merge! #js {:shape shape diff --git a/frontend/src/app/main/ui/viewer/shapes.cljs b/frontend/src/app/main/ui/viewer/shapes.cljs index 2b2522078..e43ff5780 100644 --- a/frontend/src/app/main/ui/viewer/shapes.cljs +++ b/frontend/src/app/main/ui/viewer/shapes.cljs @@ -350,7 +350,6 @@ [props] (let [shape (obj/get props "shape") childs (mapv #(get objects %) (:shapes shape)) - ;;shape (gsh/transform-shape shape) props (obj/merge! #js {} props #js {:shape shape :childs childs diff --git a/frontend/src/app/main/ui/workspace/viewport/selection.cljs b/frontend/src/app/main/ui/workspace/viewport/selection.cljs index b42fbbc36..0a1cb7821 100644 --- a/frontend/src/app/main/ui/workspace/viewport/selection.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/selection.cljs @@ -341,7 +341,6 @@ (let [shape (mf/use-memo (mf/deps shapes) #(->> shapes - #_(map gsh/transform-shape) (gsh/selection-rect) (cts/setup-shape))) on-resize @@ -369,7 +368,6 @@ (let [shape (mf/use-memo (mf/deps shapes) #(->> shapes - #_(map gsh/transform-shape) (gsh/selection-rect) (cts/setup-shape)))] @@ -384,7 +382,6 @@ (mf/defc single-handlers [{:keys [shape zoom color disable-handlers] :as props}] (let [shape-id (:id shape) - ;;shape (gsh/transform-shape shape) on-resize (fn [current-position _initial-position event] From c1affe75e19c6f55aa720258b4ffe7f1a0c598a9 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Tue, 8 Nov 2022 12:06:28 +0100 Subject: [PATCH 28/36] :sparkles: Fix problem with fixed constraints --- .../app/common/geom/shapes/constraints.cljc | 92 ++++++++++++------- .../app/main/data/workspace/modifiers.cljs | 2 +- 2 files changed, 61 insertions(+), 33 deletions(-) diff --git a/common/src/app/common/geom/shapes/constraints.cljc b/common/src/app/common/geom/shapes/constraints.cljc index 00b1f700a..ef72945c9 100644 --- a/common/src/app/common/geom/shapes/constraints.cljc +++ b/common/src/app/common/geom/shapes/constraints.cljc @@ -130,61 +130,89 @@ (defn start-vector [axis child-points parent-points] - ((if (= :x axis) left-vector top-vector) child-points parent-points)) + (let [pos-vector + (cond (= :x axis) left-vector + (= :y axis) top-vector)] + (pos-vector child-points parent-points))) (defn end-vector [axis child-points parent-points] - ((if (= :x axis) right-vector bottom-vector) child-points parent-points)) + (let [pos-vector + (cond (= :x axis) right-vector + (= :y axis) bottom-vector)] + (pos-vector child-points parent-points))) (defn center-vector [axis child-points parent-points] ((if (= :x axis) center-horizontal-vector center-vertical-vector) child-points parent-points)) +(defn displacement + [before-v after-v] + (let [angl (gpt/angle-with-other before-v after-v) + sign (if (mth/close? angl 180) -1 1) + length (* sign (gpt/length before-v))] + (gpt/subtract after-v (gpt/scale (gpt/unit after-v) length)))) + +(defn side-vector + [axis [c0 c1 _ c3]] + (if (= axis :x) + (gpt/to-vec c0 c1) + (gpt/to-vec c0 c3))) + +(defn side-vector-resize + [axis [c0 c1 _ c3] start-vector end-vector] + (if (= axis :x) + (gpt/to-vec (gpt/add c0 start-vector) (gpt/add c1 end-vector)) + (gpt/to-vec (gpt/add c0 start-vector) (gpt/add c3 end-vector)))) ;; Constraint function definitions (defmulti constraint-modifier (fn [type & _] type)) +(defmethod constraint-modifier :start + [_ axis child-points-before parent-points-before child-points-after parent-points-after] + (let [start-before (start-vector axis child-points-before parent-points-before) + start-after (start-vector axis child-points-after parent-points-after)] + (ctm/move-modifiers (displacement start-before start-after)))) + (defmethod constraint-modifier :end [_ axis child-points-before parent-points-before child-points-after parent-points-after] (let [end-before (end-vector axis child-points-before parent-points-before) - end-after (end-vector axis child-points-after parent-points-after) - end-angl (gpt/angle-with-other end-before end-after) - target-end (if (mth/close? end-angl 180) (- (gpt/length end-before)) (gpt/length end-before)) - disp-vector-end (gpt/subtract end-after (gpt/scale (gpt/unit end-after) target-end))] - (ctm/move-modifiers disp-vector-end))) + end-after (end-vector axis child-points-after parent-points-after)] + (ctm/move-modifiers (displacement end-before end-after)))) (defmethod constraint-modifier :fixed [_ axis child-points-before parent-points-before child-points-after parent-points-after transformed-parent] - (let [[c0 c1 _ c4] child-points-after + (let [;; Same as constraint end + end-before (end-vector axis child-points-before parent-points-before) + end-after (end-vector axis child-points-after parent-points-after) + start-before (start-vector axis child-points-before parent-points-before) + start-after (start-vector axis child-points-after parent-points-after) - ;; Same as constraint end - end-before (end-vector axis child-points-before parent-points-before) - end-after (end-vector axis child-points-after parent-points-after) - end-angl (gpt/angle-with-other end-before end-after) - target-end (if (mth/close? end-angl 180) (- (gpt/length end-before)) (gpt/length end-before)) - disp-vector-end (gpt/subtract end-after (gpt/scale (gpt/unit end-after) target-end)) + disp-end (displacement end-before end-after) + disp-start (displacement start-before start-after) - before-vec (if (= axis :x) (gpt/to-vec c0 c1) (gpt/to-vec c0 c4)) - after-vec (if (= axis :x) - (gpt/to-vec c0 (gpt/add c1 disp-vector-end)) - (gpt/to-vec c0 (gpt/add c4 disp-vector-end)) - ) + ;; We get the current axis side and grow it on both side by the end+start displacements + before-vec (side-vector axis child-points-after) + after-vec (side-vector-resize axis child-points-after disp-start disp-end) - resize-angl (gpt/angle-with-other before-vec after-vec) - resize-sign (if (mth/close? resize-angl 180) -1 1) + ;; after-vec will contain the side length of the grown side + ;; we scale the shape by the diference and translate it by the start + ;; displacement (so its left+top position is constant) + scale (/ (gpt/length after-vec) (gpt/length before-vec)) - scale (* resize-sign (/ (gpt/length after-vec) (gpt/length before-vec)))] - (ctm/resize-modifiers (get-scale axis scale) c0 (:transform transformed-parent) (:transform-inverse transformed-parent)))) + resize-origin (first child-points-after) + {:keys [transform transform-inverse]} transformed-parent] + + (-> (ctm/empty) + (ctm/resize (get-scale axis scale) resize-origin transform transform-inverse) + (ctm/move disp-start)))) (defmethod constraint-modifier :center [_ axis child-points-before parent-points-before child-points-after parent-points-after] (let [center-before (center-vector axis child-points-before parent-points-before) - center-after (center-vector axis child-points-after parent-points-after) - center-angl (gpt/angle-with-other center-before center-after) - target-center (if (mth/close? center-angl 180) (- (gpt/length center-before)) (gpt/length center-before)) - disp-vector-center (gpt/subtract center-after (gpt/scale (gpt/unit center-after) target-center))] - (ctm/move-modifiers disp-vector-center))) + center-after (center-vector axis child-points-after parent-points-after)] + (ctm/move-modifiers (displacement center-before center-after)))) (defmethod constraint-modifier :default [_ _ _ _ _] []) @@ -266,11 +294,11 @@ modifiers (normalize-modifiers constraints-h constraints-v modifiers child parent transformed-child transformed-parent) transformed-child (gst/transform-shape child modifiers) - parent-points-before (:points parent) - child-points-before (bounding-box-parent-transform child parent) - parent-points-after (:points transformed-parent) - child-points-after (bounding-box-parent-transform transformed-child transformed-parent) + parent-points-before (bounding-box-parent-transform parent parent) + child-points-before (bounding-box-parent-transform child parent) + parent-points-after (bounding-box-parent-transform transformed-parent transformed-parent) + child-points-after (bounding-box-parent-transform transformed-child transformed-parent) modifiers-h (constraint-modifier (constraints-h const->type+axis) :x child-points-before parent-points-before diff --git a/frontend/src/app/main/data/workspace/modifiers.cljs b/frontend/src/app/main/data/workspace/modifiers.cljs index b6f6d2464..f76c36d0f 100644 --- a/frontend/src/app/main/data/workspace/modifiers.cljs +++ b/frontend/src/app/main/data/workspace/modifiers.cljs @@ -131,7 +131,7 @@ (update [_ state] (-> state (dissoc :workspace-modifiers) - (dissoc ::current-move-selected))))) + (dissoc :app.main.data.workspace.transforms/current-move-selected))))) (defn create-modif-tree [ids modifiers] From 56efb571be0e0250c386722bd573fcf197460b01 Mon Sep 17 00:00:00 2001 From: Eva Date: Mon, 7 Nov 2022 18:00:26 +0100 Subject: [PATCH 29/36] :sparkles: Add `add flex layout` option in context menu --- frontend/src/app/main/data/workspace.cljs | 34 +-------- .../app/main/data/workspace/selection.cljs | 4 +- .../app/main/data/workspace/shape_layout.cljs | 70 ++++++++++++++----- .../src/app/main/data/workspace/shapes.cljs | 44 ++++++++++-- .../data/workspace/shapes_update_layout.cljs | 28 ++++++++ .../app/main/data/workspace/shortcuts.cljs | 11 ++- .../app/main/ui/workspace/context_menu.cljs | 30 +++++++- frontend/translations/en.po | 8 +++ frontend/translations/es.po | 8 +++ 9 files changed, 177 insertions(+), 60 deletions(-) create mode 100644 frontend/src/app/main/data/workspace/shapes_update_layout.cljs diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index bedd71065..9b801f12a 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -52,8 +52,8 @@ [app.main.data.workspace.path.shapes-to-path :as dwps] [app.main.data.workspace.persistence :as dwp] [app.main.data.workspace.selection :as dws] - [app.main.data.workspace.shape-layout :as dwsl] [app.main.data.workspace.shapes :as dwsh] + [app.main.data.workspace.shapes-update-layout :as dwul] [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.svg-upload :as svg] [app.main.data.workspace.thumbnails :as dwth] @@ -690,7 +690,7 @@ (rx/of (dch/commit-changes changes) (dwco/expand-collapse parent-id) - (dwsl/update-layout-positions [parent-id])))))) + (dwul/update-layout-positions [parent-id])))))) (defn relocate-selected-shapes [parent-id to-index] @@ -1571,36 +1571,6 @@ (rx/of (dch/commit-changes changes)))))) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Artboard -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defn create-artboard-from-selection - [] - (ptk/reify ::create-artboard-from-selection - ptk/WatchEvent - (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) - selected (wsh/lookup-selected state) - selected-objs (map #(get objects %) selected)] - (when (d/not-empty? selected) - (let [srect (gsh/selection-rect selected-objs) - frame-id (get-in objects [(first selected) :frame-id]) - parent-id (get-in objects [(first selected) :parent-id]) - shape (-> (cts/make-minimal-shape :frame) - (merge {:x (:x srect) :y (:y srect) :width (:width srect) :height (:height srect)}) - (assoc :frame-id frame-id :parent-id parent-id) - (cond-> (not= frame-id uuid/zero) - (assoc :fills [] :hide-in-viewer true)) - (cts/setup-rect-selrect))] - (rx/of - (dwu/start-undo-transaction) - (dwsh/add-shape shape) - (dwsh/move-shapes-into-frame (:id shape) selected) - - (dwu/commit-undo-transaction)))))))) - - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Remove graphics ;; TODO: this should be deprecated and removed together with components-v2 diff --git a/frontend/src/app/main/data/workspace/selection.cljs b/frontend/src/app/main/data/workspace/selection.cljs index 4d3dffaa7..8791777c1 100644 --- a/frontend/src/app/main/data/workspace/selection.cljs +++ b/frontend/src/app/main/data/workspace/selection.cljs @@ -21,7 +21,7 @@ [app.main.data.modal :as md] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.collapse :as dwc] - [app.main.data.workspace.shape-layout :as dwsl] + [app.main.data.workspace.shapes-update-layout :as dwul] [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.thumbnails :as dwt] [app.main.data.workspace.zoom :as dwz] @@ -565,7 +565,7 @@ ;; Warning: This order is important for the focus mode. (rx/of (dch/commit-changes changes) (select-shapes new-selected) - (dwsl/update-layout-positions frames) + (dwul/update-layout-positions frames) (memorize-duplicated id-original id-duplicated)))))))))) (defn change-hover-state diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index 799cf0497..7f2d7d3ae 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -8,10 +8,12 @@ (:require [app.common.data :as d] [app.common.pages.helpers :as cph] - [app.common.types.modifiers :as ctm] [app.common.types.shape.layout :as ctl] + [app.common.uuid :as uuid] [app.main.data.workspace.changes :as dwc] - [app.main.data.workspace.modifiers :as dwm] + [app.main.data.workspace.selection :as dwse] + [app.main.data.workspace.shapes :as dws] + [app.main.data.workspace.shapes-update-layout :as wsul] [app.main.data.workspace.state-helpers :as wsh] [beicon.core :as rx] [potok.core :as ptk])) @@ -44,19 +46,6 @@ (def initial-grid-layout ;; TODO {:layout :grid}) -(defn update-layout-positions - [ids] - (ptk/reify ::update-layout-positions - ptk/WatchEvent - (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) - ids (->> ids (filter (partial ctl/layout? objects)))] - (if (d/not-empty? ids) - (let [modif-tree (dwm/create-modif-tree ids (ctm/reflow-modifiers))] - (rx/of (dwm/set-modifiers modif-tree) - (dwm/apply-modifiers))) - (rx/empty)))))) - (defn get-layout-initializer [type] (let [initial-layout-data (if (= type :flex) initial-flex-layout initial-grid-layout)] @@ -72,16 +61,59 @@ (let [objects (wsh/lookup-page-objects state) children-ids (into [] (mapcat #(get-in objects [% :shapes])) ids)] (rx/of (dwc/update-shapes ids (get-layout-initializer type)) - (update-layout-positions ids) + (wsul/update-layout-positions ids) (dwc/update-shapes children-ids #(dissoc % :constraints-h :constraints-v))))))) +(defn create-layout-from-selection + [type] + (ptk/reify ::create-layout-from-selection + ptk/WatchEvent + (watch [_ state _] + + (let [page-id (:current-page-id state) + objects (wsh/lookup-page-objects state page-id) + selected (wsh/lookup-selected state) + selected-shapes (map (d/getf objects) selected) + single? (= (count selected-shapes) 1) + has-group? (->> selected-shapes (d/seek cph/group-shape?)) + is-group? (and single? has-group?)] + (if is-group? + (let [parent-id (:parent-id (first selected-shapes)) + new-shape-id (uuid/next) + shapes-ids (:shapes (first selected-shapes)) + ordered-ids (into (d/ordered-set) shapes-ids)] + (rx/of (dwse/select-shapes ordered-ids) + (dws/create-artboard-from-selection new-shape-id parent-id) + (create-layout [new-shape-id] type) + (dws/delete-shapes page-id selected))) + + (let [new-shape-id (uuid/next)] + (rx/of (dws/create-artboard-from-selection new-shape-id) + (create-layout [new-shape-id] type)))))))) + (defn remove-layout [ids] (ptk/reify ::remove-layout ptk/WatchEvent (watch [_ _ _] (rx/of (dwc/update-shapes ids #(apply dissoc % layout-keys)) - (update-layout-positions ids))))) + (wsul/update-layout-positions ids))))) + +(defn toogle-layout-flex + [] + (ptk/reify ::toogle-layout-flex + ptk/WatchEvent + (watch [_ state _] + (let [page-id (:current-page-id state) + objects (wsh/lookup-page-objects state page-id) + selected (wsh/lookup-selected state) + selected-shapes (map (d/getf objects) selected) + single? (= (count selected-shapes) 1) + has-flex-layout? (and single? (= :flex (:layout (first selected-shapes))))] + + (if has-flex-layout? + (rx/of (remove-layout selected)) + (rx/of (create-layout-from-selection :flex))))))) (defn update-layout [ids changes] @@ -89,7 +121,7 @@ ptk/WatchEvent (watch [_ _ _] (rx/of (dwc/update-shapes ids #(d/deep-merge % changes)) - (update-layout-positions ids))))) + (wsul/update-layout-positions ids))))) (defn update-layout-child [ids changes] @@ -100,4 +132,4 @@ 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)) - (update-layout-positions (d/concat-vec layout-ids parent-ids))))))) + (wsul/update-layout-positions (d/concat-vec layout-ids parent-ids))))))) diff --git a/frontend/src/app/main/data/workspace/shapes.cljs b/frontend/src/app/main/data/workspace/shapes.cljs index b36930d58..ee39ddc8d 100644 --- a/frontend/src/app/main/data/workspace/shapes.cljs +++ b/frontend/src/app/main/data/workspace/shapes.cljs @@ -9,6 +9,7 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.geom.proportions :as gpr] + [app.common.geom.shapes :as gsh] [app.common.pages.changes-builder :as pcb] [app.common.pages.helpers :as cph] [app.common.spec :as us] @@ -22,8 +23,9 @@ [app.main.data.workspace.changes :as dch] [app.main.data.workspace.edition :as dwe] [app.main.data.workspace.selection :as dws] - [app.main.data.workspace.shape-layout :as dwsl] + [app.main.data.workspace.shapes-update-layout :as dwsul] [app.main.data.workspace.state-helpers :as wsh] + [app.main.data.workspace.undo :as dwu] [app.main.features :as features] [app.main.streams :as ms] [beicon.core :as rx] @@ -102,7 +104,7 @@ (rx/concat (rx/of (dch/commit-changes changes) - (dwsl/update-layout-positions [(:parent-id shape)]) + (dwsul/update-layout-positions [(:parent-id shape)]) (when-not no-select? (dws/select-shapes (d/ordered-set id)))) (when (= :text (:type attrs)) @@ -270,9 +272,9 @@ (reduce ctp/remove-flow flows))))))] (rx/of (dc/detach-comment-thread ids) - (dwsl/update-layout-positions all-parents) + (dwsul/update-layout-positions all-parents) (dch/commit-changes changes) - (dwsl/update-layout-positions layout-ids))))))) + (dwsul/update-layout-positions layout-ids))))))) (defn- viewport-center [state] @@ -298,3 +300,37 @@ (assoc :frame-id frame-id) (cts/setup-rect-selrect))] (rx/of (add-shape shape)))))) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Artboard +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defn create-artboard-from-selection + ([] + (create-artboard-from-selection nil)) + ([id] + (create-artboard-from-selection id nil)) + ([id parent-id] + (ptk/reify ::create-artboard-from-selection + ptk/WatchEvent + (watch [_ state _] + (let [page-id (:current-page-id state) + objects (wsh/lookup-page-objects state page-id) + selected (wsh/lookup-selected state) + selected-objs (map #(get objects %) selected)] + (when (d/not-empty? selected) + (let [srect (gsh/selection-rect selected-objs) + frame-id (get-in objects [(first selected) :frame-id]) + parent-id (or parent-id (get-in objects [(first selected) :parent-id])) + shape (-> (cts/make-minimal-shape :frame) + (merge {:x (:x srect) :y (:y srect) :width (:width srect) :height (:height srect)}) + (cond-> id + (assoc :id id)) + (assoc :frame-id frame-id :parent-id parent-id) + (cond-> (not= frame-id uuid/zero) + (assoc :fills [] :hide-in-viewer true)) + (cts/setup-rect-selrect))] + (rx/of + (dwu/start-undo-transaction) + (add-shape shape) + (move-shapes-into-frame (:id shape) selected) + (dwu/commit-undo-transaction))))))))) diff --git a/frontend/src/app/main/data/workspace/shapes_update_layout.cljs b/frontend/src/app/main/data/workspace/shapes_update_layout.cljs new file mode 100644 index 000000000..3274d2356 --- /dev/null +++ b/frontend/src/app/main/data/workspace/shapes_update_layout.cljs @@ -0,0 +1,28 @@ +;; 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.main.data.workspace.shapes-update-layout + (:require + [app.common.data :as d] + [app.common.types.modifiers :as ctm] + [app.common.types.shape.layout :as ctl] + [app.main.data.workspace.modifiers :as dwm] + [app.main.data.workspace.state-helpers :as wsh] + [beicon.core :as rx] + [potok.core :as ptk])) + +(defn update-layout-positions + [ids] + (ptk/reify ::update-layout-positions + ptk/WatchEvent + (watch [_ state _] + (let [objects (wsh/lookup-page-objects state) + ids (->> ids (filter (partial ctl/layout? objects)))] + (if (d/not-empty? ids) + (let [modif-tree (dwm/create-modif-tree ids (ctm/reflow-modifiers))] + (rx/of (dwm/set-modifiers modif-tree) + (dwm/apply-modifiers))) + (rx/empty)))))) diff --git a/frontend/src/app/main/data/workspace/shortcuts.cljs b/frontend/src/app/main/data/workspace/shortcuts.cljs index 4f2728d9f..31fc056ee 100644 --- a/frontend/src/app/main/data/workspace/shortcuts.cljs +++ b/frontend/src/app/main/data/workspace/shortcuts.cljs @@ -15,6 +15,8 @@ [app.main.data.workspace.drawing :as dwd] [app.main.data.workspace.layers :as dwly] [app.main.data.workspace.libraries :as dwl] + [app.main.data.workspace.shape-layout :as dwsl] + [app.main.data.workspace.shapes :as dws] [app.main.data.workspace.texts :as dwtxt] [app.main.data.workspace.transforms :as dwt] [app.main.data.workspace.undo :as dwu] @@ -204,7 +206,12 @@ :artboard-selection {:tooltip (ds/meta (ds/alt "G")) :command (ds/c-mod "alt+g") :subsections [:modify-layers] - :fn #(st/emit! (dw/create-artboard-from-selection))} + :fn #(st/emit! (dws/create-artboard-from-selection))} + + :toogle-layout-flex {:tooltip (ds/shift "F") + :command "shift+f" + :subsections [:modify-layers] + :fn #(st/emit! (dwsl/toogle-layout-flex))} ;; TOOLS @@ -382,7 +389,7 @@ :show-shortcuts {:tooltip "?" :command "?" :subsections [:main-menu] - :fn #(st/emit! (toggle-layout-flag :shortcuts)) } + :fn #(st/emit! (toggle-layout-flag :shortcuts))} ;; PANELS diff --git a/frontend/src/app/main/ui/workspace/context_menu.cljs b/frontend/src/app/main/ui/workspace/context_menu.cljs index 39b8cfc10..ab69b3879 100644 --- a/frontend/src/app/main/ui/workspace/context_menu.cljs +++ b/frontend/src/app/main/ui/workspace/context_menu.cljs @@ -19,6 +19,8 @@ [app.main.data.workspace.interactions :as dwi] [app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.selection :as dws] + [app.main.data.workspace.shape-layout :as dwsl] + [app.main.data.workspace.shapes :as dwsh] [app.main.data.workspace.shortcuts :as sc] [app.main.features :as features] [app.main.refs :as refs] @@ -212,7 +214,7 @@ (let [multiple? (> (count shapes) 1) single? (= (count shapes) 1) - do-create-artboard-from-selection #(st/emit! (dw/create-artboard-from-selection)) + do-create-artboard-from-selection #(st/emit! (dwsh/create-artboard-from-selection)) has-frame? (->> shapes (d/seek cph/frame-shape?)) has-group? (->> shapes (d/seek cph/group-shape?)) @@ -364,6 +366,31 @@ [:& menu-entry {:title (tr "workspace.shape.menu.flow-start") :on-click do-add-flow}]))))) +(mf/defc context-menu-flex + [{:keys [shapes]}] + (let [single? (= (count shapes) 1) + has-frame? (->> shapes (d/seek cph/frame-shape?)) + is-frame? (and single? has-frame?) + is-flex-container? (and is-frame? (= :flex (:layout (first shapes)))) + has-group? (->> shapes (d/seek cph/group-shape?)) + is-group? (and single? has-group?) + ids (->> shapes (map :id)) + add-flex #(st/emit! (dwsl/create-layout-from-selection :flex)) + remove-flex #(st/emit! (dwsl/remove-layout ids))] + (cond + (or (not single?) (and is-frame? (not is-flex-container?)) is-group?) + [:* + [:& menu-separator] + [:& menu-entry {:title (tr "workspace.shape.menu.add-flex") + :shortcut (sc/get-tooltip :toogle-layout-flex) + :on-click add-flex}]] + + is-flex-container? + [:* + [:& menu-separator] + [:& menu-entry {:title (tr "workspace.shape.menu.remove-flex") + :shortcut (sc/get-tooltip :toogle-layout-flex) + :on-click remove-flex}]]))) (mf/defc context-menu-component [{:keys [shapes]}] @@ -517,6 +544,7 @@ [:> context-menu-path props] [:> context-menu-layer-options props] [:> context-menu-prototype props] + [:> context-menu-flex props] [:> context-menu-component props] [:> context-menu-delete props]]))) diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 45cd4a44f..ebf0fefaa 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -4077,6 +4077,14 @@ msgstr "Update main components" msgid "workspace.shape.menu.update-main" msgstr "Update main component" +#: src/app/main/ui/workspace/context_menu.cljs +msgid "workspace.shape.menu.add-flex" +msgstr "Add layout flex" + +#: src/app/main/ui/workspace/context_menu.cljs +msgid "workspace.shape.menu.remove-flex" +msgstr "Remove layout flex" + msgid "workspace.sidebar.collapse" msgstr "Collapse sidebar" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 00a47ffed..0e833ab0b 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -4518,6 +4518,14 @@ msgstr "Actualizar componentes" msgid "workspace.shape.menu.update-main" msgstr "Actualizar componente principal" +#: src/app/main/ui/workspace/context_menu.cljs +msgid "workspace.shape.menu.add-flex" +msgstr "AƱadir layout flex" + +#: src/app/main/ui/workspace/context_menu.cljs +msgid "workspace.shape.menu.remove-flex" +msgstr "Eliminar layout flex" + msgid "workspace.sidebar.collapse" msgstr "Cerrar barra lateral" From 39041bb63b1828c3e668cb1109e77c88d60b28f3 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Tue, 8 Nov 2022 15:10:01 +0100 Subject: [PATCH 30/36] :sparkles: Fix problem with constraints --- common/src/app/common/geom/shapes/constraints.cljc | 4 +++- .../src/app/main/data/workspace/shape_layout.cljs | 4 ++-- frontend/src/app/main/data/workspace/shapes.cljs | 1 + .../ui/workspace/shapes/frame/thumbnail_render.cljs | 2 ++ .../ui/workspace/sidebar/options/rows/stroke_row.cljs | 11 +++++++---- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/common/src/app/common/geom/shapes/constraints.cljc b/common/src/app/common/geom/shapes/constraints.cljc index ef72945c9..2ced1cce1 100644 --- a/common/src/app/common/geom/shapes/constraints.cljc +++ b/common/src/app/common/geom/shapes/constraints.cljc @@ -151,7 +151,9 @@ (let [angl (gpt/angle-with-other before-v after-v) sign (if (mth/close? angl 180) -1 1) length (* sign (gpt/length before-v))] - (gpt/subtract after-v (gpt/scale (gpt/unit after-v) length)))) + (if (mth/almost-zero? length) + after-v + (gpt/subtract after-v (gpt/scale (gpt/unit after-v) length))))) (defn side-vector [axis [c0 c1 _ c3]] diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index 7f2d7d3ae..d1f171b3d 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -78,8 +78,8 @@ has-group? (->> selected-shapes (d/seek cph/group-shape?)) is-group? (and single? has-group?)] (if is-group? - (let [parent-id (:parent-id (first selected-shapes)) - new-shape-id (uuid/next) + (let [new-shape-id (uuid/next) + parent-id (:parent-id (first selected-shapes)) shapes-ids (:shapes (first selected-shapes)) ordered-ids (into (d/ordered-set) shapes-ids)] (rx/of (dwse/select-shapes ordered-ids) diff --git a/frontend/src/app/main/data/workspace/shapes.cljs b/frontend/src/app/main/data/workspace/shapes.cljs index ee39ddc8d..72012c8d6 100644 --- a/frontend/src/app/main/data/workspace/shapes.cljs +++ b/frontend/src/app/main/data/workspace/shapes.cljs @@ -300,6 +300,7 @@ (assoc :frame-id frame-id) (cts/setup-rect-selrect))] (rx/of (add-shape shape)))))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Artboard ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/frontend/src/app/main/ui/workspace/shapes/frame/thumbnail_render.cljs b/frontend/src/app/main/ui/workspace/shapes/frame/thumbnail_render.cljs index 5c06eb06b..1715b887a 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame/thumbnail_render.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame/thumbnail_render.cljs @@ -199,6 +199,8 @@ (mf/use-effect (mf/deps disable?) (fn [] + (when (and disable? (not @disable-ref?)) + (rx/push! updates-str :update)) (reset! disable-ref? disable?))) (mf/use-effect diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs index bc804fad9..fb83ff3c3 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs @@ -7,6 +7,7 @@ (ns app.main.ui.workspace.sidebar.options.rows.stroke-row (:require [app.common.data :as d] + [app.common.data.macros :as dm] [app.main.ui.components.dropdown :refer [dropdown]] [app.main.ui.components.numeric-input :refer [numeric-input]] [app.main.ui.hooks :as h] @@ -132,9 +133,10 @@ :on-close (close-caps-select start-caps-state)} [:ul.dropdown.cap-select-dropdown {:style {:top (:top @start-caps-state) :left (:left @start-caps-state)}} - (for [[value label separator] (stroke-cap-names)] + (for [[idx [value label separator]] (d/enumerate (stroke-cap-names))] (let [img (value->img value)] - [:li {:class (dom/classnames :separator separator) + [:li {:key (dm/str "start-cap-" idx) + :class (dom/classnames :separator separator) :on-click #(on-stroke-cap-start-change index value)} (when img [:img {:src (value->img value)}]) label]))]] @@ -151,9 +153,10 @@ :on-close (close-caps-select end-caps-state)} [:ul.dropdown.cap-select-dropdown {:style {:top (:top @end-caps-state) :left (:left @end-caps-state)}} - (for [[value label separator] (stroke-cap-names)] + (for [[idx [value label separator]] (d/enumerate (stroke-cap-names))] (let [img (value->img value)] - [:li {:class (dom/classnames :separator separator) + [:li {:key (dm/str "end-cap-" idx) + :class (dom/classnames :separator separator) :on-click #(on-stroke-cap-end-change index value)} (when img [:img {:src (value->img value)}]) label]))]]])])) From 6e35b5c6b68a4274b0caca979cacd5079ae02b7e Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Tue, 8 Nov 2022 17:08:41 +0100 Subject: [PATCH 31/36] :sparkles: Fixed problem with new modifiers and text auto-heigh --- common/src/app/common/types/modifiers.cljc | 19 ++++------ .../src/app/main/data/workspace/texts.cljs | 2 +- .../shapes/text/viewport_texts_html.cljs | 35 +++++++++++-------- 3 files changed, 27 insertions(+), 29 deletions(-) diff --git a/common/src/app/common/types/modifiers.cljc b/common/src/app/common/types/modifiers.cljc index 8b2d27445..2b994d6f6 100644 --- a/common/src/app/common/types/modifiers.cljc +++ b/common/src/app/common/types/modifiers.cljc @@ -229,7 +229,7 @@ (scale-content value))) (defn change-dimensions-modifiers - [shape attr value] + [{:keys [transform transform-inverse] :as shape} attr value] (us/assert map? shape) (us/assert #{:width :height} attr) (us/assert number? value) @@ -245,22 +245,17 @@ (-> size (assoc :height value) (assoc :width (* value proportion))))) + width (:width new-size) height (:height new-size) - shape-transform (:transform shape) - shape-transform-inv (:transform-inverse shape) - shape-center (gco/center-shape shape) {sr-width :width sr-height :height} (:selrect shape) - origin (cond-> (gpt/point (:selrect shape)) - (some? shape-transform) - (gmt/transform-point-center shape-center shape-transform)) + origin (-> shape :points first) + scalex (/ width sr-width) + scaley (/ height sr-height)] - scalev (gpt/divide (gpt/point width height) - (gpt/point sr-width sr-height))] - - (resize-modifiers scalev origin shape-transform shape-transform-inv))) + (resize-modifiers (gpt/point scalex scaley) origin transform transform-inverse))) (defn change-orientation-modifiers [shape orientation] @@ -437,5 +432,3 @@ (as-> shape $ (reduce apply-modifier $ (:structure-parent modifiers)) (reduce apply-modifier $ (:structure-child modifiers)))))) - - diff --git a/frontend/src/app/main/data/workspace/texts.cljs b/frontend/src/app/main/data/workspace/texts.cljs index 0527184a0..d4cf5995f 100644 --- a/frontend/src/app/main/data/workspace/texts.cljs +++ b/frontend/src/app/main/data/workspace/texts.cljs @@ -394,7 +394,7 @@ ptk/UpdateEvent (update [_ state] (let [ids (keys (::update-position-data state))] - (update state :workspace-text-modifiers #(apply dissoc % ids)))) + (update state :workspace-text-modifier #(apply dissoc % ids)))) ptk/WatchEvent (watch [_ state _] diff --git a/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs b/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs index 96d946f26..8dc6f1e82 100644 --- a/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs @@ -33,7 +33,7 @@ (-> shape (cond-> (some? (meta (:position-data shape))) (with-meta (meta (:position-data shape)))) - (dissoc :position-data :transform :transform-inverse))) + (dissoc :position-data))) (defn fix-position [shape modifier] (let [shape' (-> shape @@ -92,20 +92,26 @@ (defn- update-text-modifier [{:keys [grow-type id]} node] - (p/let [position-data (tsp/calc-position-data id) - props {:position-data position-data} + (ts/raf + #(p/let [position-data (tsp/calc-position-data id) + props {:position-data position-data} - props - (if (contains? #{:auto-height :auto-width} grow-type) - (let [{:keys [width height]} (-> (dom/query node ".paragraph-set") (dom/get-client-size)) - width (mth/ceil width) - height (mth/ceil height)] - (if (and (not (mth/almost-zero? width)) (not (mth/almost-zero? height))) - (assoc props :width width :height height) - props)) - props)] + props + (if (contains? #{:auto-height :auto-width} grow-type) + (let [{:keys [width height]} (-> (dom/query node ".paragraph-set") (dom/get-client-size)) + width (mth/ceil width) + height (mth/ceil height)] + (if (and (not (mth/almost-zero? width)) (not (mth/almost-zero? height))) + (cond-> props + (= grow-type :auto-width) + (assoc :width width) - (st/emit! (dwt/update-text-modifier id props)))) + (or (= grow-type :auto-height) (= grow-type :auto-width)) + (assoc :height height)) + props)) + props)] + + (st/emit! (dwt/update-text-modifier id props))))) (mf/defc text-container {::mf/wrap-props false @@ -163,10 +169,9 @@ handle-update-modifier (mf/use-callback update-text-modifier) handle-update-shape (mf/use-callback update-text-shape)] - [:* (for [{:keys [id] :as shape} changed-texts] - [:& text-container {:shape (gsh/transform-shape shape) + [:& text-container {:shape shape :on-update (if (some? (get modifiers (:id shape))) handle-update-modifier handle-update-shape) From 4c5e8f42ce376c26e71dcd0cfbae5923156aa5cb Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 10 Nov 2022 14:55:13 +0100 Subject: [PATCH 32/36] :sparkles: Review changes --- .../geom/shapes/flex_layout/bounds.cljc | 11 +- .../geom/shapes/flex_layout/drop_area.cljc | 253 ++++++++++-------- .../common/geom/shapes/flex_layout/lines.cljc | 121 +++++---- .../geom/shapes/flex_layout/positions.cljc | 31 +-- .../src/app/common/geom/shapes/modifiers.cljc | 23 +- common/src/app/common/geom/shapes/rect.cljc | 12 +- .../app/common/geom/shapes/transforms.cljc | 3 +- 7 files changed, 245 insertions(+), 209 deletions(-) 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 e8cd52ce2..07552e540 100644 --- a/common/src/app/common/geom/shapes/flex_layout/bounds.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/bounds.cljc @@ -105,9 +105,8 @@ (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 $)))) + (-> (mapcat child-bounds children) + (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)))) diff --git a/common/src/app/common/geom/shapes/flex_layout/drop_area.cljc b/common/src/app/common/geom/shapes/flex_layout/drop_area.cljc index 3b9ff8a58..00de11f3a 100644 --- a/common/src/app/common/geom/shapes/flex_layout/drop_area.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/drop_area.cljc @@ -8,16 +8,71 @@ (: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.flex-layout.lines :as fli] [app.common.geom.shapes.rect :as gsr] [app.common.pages.helpers :as cph] [app.common.types.shape.layout :as ctl])) -(defn layout-drop-areas - "Retrieve the layout drop areas to move shapes inside layouts" - [{:keys [margin-x margin-y] :as frame} layout-data children] +(defn drop-child-areas + [{:keys [transform-inverse] :as frame} parent-rect child index reverse? prev-x prev-y last?] + + (let [col? (ctl/col? frame) + row? (ctl/row? frame) + [layout-gap-row layout-gap-col] (ctl/gaps frame) + + start-p (-> child :points first) + center (gco/center-shape frame) + start-p (gmt/transform-point-center start-p center transform-inverse) + + box-x (:x start-p) + box-y (:y start-p) + box-width (-> child :selrect :width) + box-height (-> child :selrect :height) + + x (if col? (:x parent-rect) prev-x) + y (if row? (:y parent-rect) prev-y) + + width + (cond + (and row? last?) + (- (+ (:x parent-rect) (:width parent-rect)) x) + + col? + (:width parent-rect) + + :else + (+ box-width (- box-x prev-x) (/ layout-gap-row 2))) + + height + (cond + (and col? last?) + (- (+ (:y parent-rect) (:height parent-rect)) y) + + row? + (:height parent-rect) + + :else + (+ box-height (- box-y prev-y) (/ layout-gap-col 2)))] + + (if row? + (let [half-point-width (+ (- box-x x) (/ box-width 2))] + [(gsr/make-rect x y width height) + (-> (gsr/make-rect x y half-point-width height) + (assoc :index (if reverse? (inc index) index))) + (-> (gsr/make-rect (+ x half-point-width) y (- width half-point-width) height) + (assoc :index (if reverse? index (inc index))))]) + (let [half-point-height (+ (- box-y y) (/ box-height 2))] + [(gsr/make-rect x y width height) + (-> (gsr/make-rect x y width half-point-height) + (assoc :index (if reverse? (inc index) index))) + (-> (gsr/make-rect x (+ y half-point-height) width (- height half-point-height)) + (assoc :index (if reverse? index (inc index))))])))) + +(defn drop-line-area + [{:keys [transform-inverse margin-x margin-y] :as frame} + {:keys [start-p layout-gap-row layout-gap-col num-children line-width line-height] :as line-data} + prev-x prev-y last?] (let [col? (ctl/col? frame) row? (ctl/row? frame) @@ -25,138 +80,108 @@ h-end? (and row? (ctl/h-end? frame)) v-center? (and col? (ctl/v-center? frame)) v-end? (and row? (ctl/v-end? frame)) - reverse? (:reverse? layout-data) - [layout-gap-row layout-gap-col] (ctl/gaps frame) + center (gco/center-shape frame) + start-p (gmt/transform-point-center start-p center transform-inverse) - children (vec (cond->> (d/enumerate children) - reverse? reverse)) + line-width + (if row? + (:width frame) + (+ line-width margin-x + (if row? (* layout-gap-row (dec num-children)) 0))) - redfn-child - (fn [[result parent-rect prev-x prev-y] [[index child] next]] - (let [prev-x (or prev-x (:x parent-rect)) - prev-y (or prev-y (:y parent-rect)) + line-height + (if col? + (:height frame) + (+ line-height margin-y + (if col? + (* layout-gap-col (dec num-children)) + 0))) - last? (nil? next) + box-x + (- (:x start-p) + (cond + h-center? (/ line-width 2) + h-end? line-width + :else 0)) - start-p (gpt/point (:selrect child)) - start-p (-> start-p - (gmt/transform-point-center (gco/center-shape child) (:transform frame)) - (gmt/transform-point-center (gco/center-shape frame) (:transform-inverse frame))) + box-y + (- (:y start-p) + (cond + v-center? (/ line-height 2) + v-end? line-height + :else 0)) - box-x (:x start-p) - box-y (:y start-p) - box-width (-> child :selrect :width) - box-height (-> child :selrect :height) + x (if row? (:x frame) prev-x) + y (if col? (:y frame) prev-y) - x (if col? (:x parent-rect) prev-x) - y (if row? (:y parent-rect) prev-y) + width (cond + (and col? last?) + (- (+ (:x frame) (:width frame)) x) - width (cond - (and row? last?) - (- (+ (:x parent-rect) (:width parent-rect)) x) + row? + (:width frame) - col? - (:width parent-rect) + :else + (+ line-width (- box-x prev-x) (/ layout-gap-row 2))) - :else - (+ box-width (- box-x prev-x) (/ layout-gap-row 2))) + height (cond + (and row? last?) + (- (+ (:y frame) (:height frame)) y) - height (cond - (and col? last?) - (- (+ (:y parent-rect) (:height parent-rect)) y) + col? + (:height frame) - row? - (:height parent-rect) + :else + (+ line-height (- box-y prev-y) (/ layout-gap-col 2)))] + (gsr/make-rect x y width height))) - :else - (+ box-height (- box-y prev-y) (/ layout-gap-col 2))) +(defn layout-drop-areas + "Retrieve the layout drop areas to move shapes inside layouts" + [frame layout-data children] - [line-area-1 line-area-2] - (if row? - (let [half-point-width (+ (- box-x x) (/ box-width 2))] - [(-> (gsr/make-rect x y half-point-width height) - (assoc :index (if reverse? (inc index) index))) - (-> (gsr/make-rect (+ x half-point-width) y (- width half-point-width) height) - (assoc :index (if reverse? index (inc index))))]) - (let [half-point-height (+ (- box-y y) (/ box-height 2))] - [(-> (gsr/make-rect x y width half-point-height) - (assoc :index (if reverse? (inc index) index))) - (-> (gsr/make-rect x (+ y half-point-height) width (- height half-point-height)) - (assoc :index (if reverse? index (inc index))))])) + (let [reverse? (:reverse? layout-data) + children (vec (cond->> (d/enumerate children) reverse? reverse)) + lines (:layout-lines layout-data)] - result (conj result line-area-1 line-area-2)] + (loop [areas [] + from-idx 0 + prev-line-x (:x frame) + prev-line-y (:y frame) - [result parent-rect (+ x width) (+ y height)])) + current-line (first lines) + lines (rest lines)] - redfn-lines - (fn [[result from-idx prev-x prev-y] [{:keys [start-p layout-gap-row layout-gap-col num-children line-width line-height]} next]] - (let [start-p (gmt/transform-point-center start-p (gco/center-shape frame) (:transform-inverse frame)) + (if (nil? current-line) + areas - prev-x (or prev-x (:x frame)) - prev-y (or prev-y (:y frame)) - last? (nil? next) + (let [line-area (drop-line-area frame current-line prev-line-x prev-line-y (nil? (first lines))) + children (subvec children from-idx (+ from-idx (:num-children current-line))) - line-width - (if row? - (:width frame) - (+ line-width margin-x - (if row? (* layout-gap-row (dec num-children)) 0))) + next-areas + (loop [areas areas + prev-child-x (:x line-area) + prev-child-y (:y line-area) + [index child] (first children) + children (rest children)] - line-height - (if col? - (:height frame) - (+ line-height margin-y - (if col? - (* layout-gap-col (dec num-children)) - 0))) + (if (nil? child) + areas - box-x - (- (:x start-p) - (cond - h-center? (/ line-width 2) - h-end? line-width - :else 0)) + (let [[child-area child-area-start child-area-end] + (drop-child-areas frame line-area child index reverse? prev-child-x prev-child-y (nil? (first children)))] + (recur (conj areas child-area-start child-area-end) + (+ (:x child-area) (:width child-area)) + (+ (:y child-area) (:height child-area)) + (first children) + (rest children)))))] - box-y - (- (:y start-p) - (cond - v-center? (/ line-height 2) - v-end? line-height - :else 0)) - - x (if row? (:x frame) prev-x) - y (if col? (:y frame) prev-y) - - width (cond - (and col? last?) - (- (+ (:x frame) (:width frame)) x) - - row? - (:width frame) - - :else - (+ line-width (- box-x prev-x) (/ layout-gap-row 2))) - - height (cond - (and row? last?) - (- (+ (:y frame) (:height frame)) y) - - col? - (:height frame) - - :else - (+ line-height (- box-y prev-y) (/ layout-gap-col 2))) - - line-area (gsr/make-rect x y width height) - - children (subvec children from-idx (+ from-idx num-children)) - - result (first (reduce redfn-child [result line-area] (d/with-next children)))] - - [result (+ from-idx num-children) (+ x width) (+ y height)]))] - - (first (reduce redfn-lines [[] 0] (d/with-next (:layout-lines layout-data)))))) + (recur next-areas + (+ from-idx (:num-children current-line)) + (+ (:x line-area) (:width line-area)) + (+ (:y line-area) (:height line-area)) + (first lines) + (rest lines))))))) (defn get-drop-index [frame-id objects position] diff --git a/common/src/app/common/geom/shapes/flex_layout/lines.cljc b/common/src/app/common/geom/shapes/flex_layout/lines.cljc index 2a5c255b8..5b0fafdbc 100644 --- a/common/src/app/common/geom/shapes/flex_layout/lines.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/lines.cljc @@ -37,71 +37,79 @@ (or row? (not (ctl/auto-height? shape)))) [layout-gap-row layout-gap-col] (ctl/gaps shape) - layout-width (gpo/width-points layout-bounds) - layout-height (gpo/height-points layout-bounds) - calculate-line-data - (fn [[{:keys [line-min-width line-min-height + layout-width (gpo/width-points layout-bounds) + layout-height (gpo/height-points layout-bounds)] + + (loop [line-data nil + result [] + child (first children) + children (rest children)] + + (if (nil? child) + (cond-> result (some? line-data) (conj line-data)) + + (let [{:keys [line-min-width line-min-height line-max-width line-max-height num-children - children-data] :as line-data} result] child] + children-data]} line-data - (let [child-bounds (gst/parent-coords-points child shape) - child-width (gpo/width-points child-bounds) - child-height (gpo/height-points child-bounds) - child-min-width (ctl/child-min-width child) - child-min-height (ctl/child-min-height child) - child-max-width (ctl/child-max-width child) - child-max-height (ctl/child-max-height child) + child-bounds (gst/parent-coords-points child shape) + child-width (gpo/width-points child-bounds) + child-height (gpo/height-points child-bounds) + child-min-width (ctl/child-min-width child) + child-min-height (ctl/child-min-height child) + child-max-width (ctl/child-max-width child) + child-max-height (ctl/child-max-height child) - [child-margin-top child-margin-right child-margin-bottom child-margin-left] - (ctl/child-margins child) + [child-margin-top child-margin-right child-margin-bottom child-margin-left] + (ctl/child-margins child) - child-margin-width (+ child-margin-left child-margin-right) - child-margin-height (+ child-margin-top child-margin-bottom) + child-margin-width (+ child-margin-left child-margin-right) + child-margin-height (+ child-margin-top child-margin-bottom) - fill-width? (ctl/fill-width? child) - fill-height? (ctl/fill-height? child) + fill-width? (ctl/fill-width? child) + fill-height? (ctl/fill-height? child) - ;; We need this info later to calculate the child resizes when fill - child-data {:id (:id child) - :child-min-width (if fill-width? child-min-width child-width) - :child-min-height (if fill-height? child-min-height child-height) - :child-max-width (if fill-width? child-max-width child-width) - :child-max-height (if fill-height? child-max-height child-height)} + ;; We need this info later to calculate the child resizes when fill + child-data {:id (:id child) + :child-min-width (if fill-width? child-min-width child-width) + :child-min-height (if fill-height? child-min-height child-height) + :child-max-width (if fill-width? child-max-width child-width) + :child-max-height (if fill-height? child-max-height child-height)} - next-min-width (+ child-margin-width (if fill-width? child-min-width child-width)) - next-min-height (+ child-margin-height (if fill-height? child-min-height child-height)) - next-max-width (+ child-margin-width (if fill-width? child-max-width child-width)) - next-max-height (+ child-margin-height (if fill-height? child-max-height child-height)) + next-min-width (+ child-margin-width (if fill-width? child-min-width child-width)) + next-min-height (+ child-margin-height (if fill-height? child-min-height child-height)) + next-max-width (+ child-margin-width (if fill-width? child-max-width child-width)) + next-max-height (+ child-margin-height (if fill-height? child-max-height child-height)) - next-line-min-width (+ line-min-width next-min-width (* layout-gap-row num-children)) - next-line-min-height (+ line-min-height next-min-height (* layout-gap-col num-children))] - (if (and (some? line-data) - (or (not wrap?) - (and row? (<= next-line-min-width layout-width)) - (and col? (<= next-line-min-height layout-height)))) + next-line-min-width (+ line-min-width next-min-width (* layout-gap-row num-children)) + next-line-min-height (+ line-min-height next-min-height (* layout-gap-col num-children))] - [{:line-min-width (if row? (+ line-min-width next-min-width) (max line-min-width next-min-width)) - :line-max-width (if row? (+ line-max-width next-max-width) (max line-max-width next-max-width)) - :line-min-height (if col? (+ line-min-height next-min-height) (max line-min-height next-min-height)) - :line-max-height (if col? (+ line-max-height next-max-height) (max line-max-height next-max-height)) - :num-children (inc num-children) - :children-data (conjv children-data child-data)} - result] + (if (and (some? line-data) + (or (not wrap?) + (and row? (<= next-line-min-width layout-width)) + (and col? (<= next-line-min-height layout-height)))) - [{:line-min-width next-min-width - :line-min-height next-min-height - :line-max-width next-max-width - :line-max-height next-max-height - :num-children 1 - :children-data [child-data]} - (cond-> result (some? line-data) (conj line-data))]))) - - [line-data layout-lines] (reduce calculate-line-data [nil []] children)] - - (cond-> layout-lines (some? line-data) (conj line-data)))) + (recur {:line-min-width (if row? (+ line-min-width next-min-width) (max line-min-width next-min-width)) + :line-max-width (if row? (+ line-max-width next-max-width) (max line-max-width next-max-width)) + :line-min-height (if col? (+ line-min-height next-min-height) (max line-min-height next-min-height)) + :line-max-height (if col? (+ line-max-height next-max-height) (max line-max-height next-max-height)) + :num-children (inc num-children) + :children-data (conjv children-data child-data)} + result + (first children) + (rest children)) + (recur {:line-min-width next-min-width + :line-min-height next-min-height + :line-max-width next-max-width + :line-max-height next-max-height + :num-children 1 + :children-data [child-data]} + (cond-> result (some? line-data) (conj line-data)) + (first children) + (rest children)))))))) (defn add-space-to-items ;; Distributes the remainder space between the lines @@ -162,8 +170,7 @@ (let [start-p (flp/get-start-line parent layout-bounds layout-line base-p total-width total-height num-lines) next-p (flp/get-next-line parent layout-bounds layout-line base-p total-width total-height num-lines)] - [(conj result - (assoc layout-line :start-p start-p)) + [(conj result (assoc layout-line :start-p start-p)) next-p]))] (let [[total-min-width total-min-height total-max-width total-max-height] @@ -303,10 +310,10 @@ layout-lines (->> (init-layout-lines shape children layout-bounds) (add-lines-positions shape layout-bounds) - (mapv (partial add-line-spacing shape layout-bounds)) - (mapv (partial add-children-resizes shape)))] + (into [] + (comp (map (partial add-line-spacing shape layout-bounds)) + (map (partial add-children-resizes shape)))))] {:layout-lines layout-lines :layout-bounds layout-bounds :reverse? reverse?})) - diff --git a/common/src/app/common/geom/shapes/flex_layout/positions.cljc b/common/src/app/common/geom/shapes/flex_layout/positions.cljc index ae748d060..3c710f669 100644 --- a/common/src/app/common/geom/shapes/flex_layout/positions.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/positions.cljc @@ -114,24 +114,21 @@ "Cross axis line. It's position is fixed along the different lines" [parent layout-bounds {:keys [line-width line-height num-children]} base-p total-width total-height num-lines] - (let [layout-width (gpo/width-points layout-bounds) - layout-height (gpo/height-points layout-bounds) + (let [layout-width (gpo/width-points layout-bounds) + layout-height (gpo/height-points layout-bounds) [layout-gap-row layout-gap-col] (ctl/gaps parent) - - row? (ctl/row? parent) - col? (ctl/col? parent) - space-between? (ctl/space-between? parent) - space-around? (ctl/space-around? parent) - h-center? (ctl/h-center? parent) - h-end? (ctl/h-end? parent) - v-center? (ctl/v-center? parent) - v-end? (ctl/v-end? parent) - content-stretch? (ctl/content-stretch? parent) - - hv #(gpo/start-hv layout-bounds %) - vv #(gpo/start-vv layout-bounds %) - - children-gap-width (* layout-gap-row (dec num-children)) + row? (ctl/row? parent) + col? (ctl/col? parent) + space-between? (ctl/space-between? parent) + space-around? (ctl/space-around? parent) + h-center? (ctl/h-center? parent) + h-end? (ctl/h-end? parent) + v-center? (ctl/v-center? parent) + v-end? (ctl/v-end? parent) + content-stretch? (ctl/content-stretch? parent) + hv (partial gpo/start-hv layout-bounds) + vv (partial gpo/start-vv layout-bounds) + children-gap-width (* layout-gap-row (dec num-children)) children-gap-height (* layout-gap-col (dec num-children)) line-height diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index 2f365a6a2..dc57ac178 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -14,6 +14,7 @@ [app.common.geom.shapes.pixel-precision :as gpp] [app.common.geom.shapes.transforms :as gtr] [app.common.pages.helpers :as cph] + [app.common.spec :as us] [app.common.types.modifiers :as ctm] [app.common.types.shape.layout :as ctl] [app.common.uuid :as uuid])) @@ -30,7 +31,9 @@ "Given the ids that have changed search for layout roots to recalculate" [ids objects] - (assert (or (nil? ids) (set? ids)) (dm/str "tree sequence from not set: " ids)) + (us/assert! + :expr (or (nil? ids) (set? ids)) + :hint (dm/str "tree sequence from not set: " ids)) (letfn [(get-tree-root ;; Finds the tree root for the current id [id] @@ -76,8 +79,8 @@ (generate-tree ;; Generate a tree sequence from a given root id [id] (->> (tree-seq - #(d/not-empty? (get-in objects [% :shapes])) - #(get-in objects [% :shapes]) + #(d/not-empty? (dm/get-in objects [% :shapes])) + #(dm/get-in objects [% :shapes]) id) (map #(get objects %))))] @@ -90,7 +93,7 @@ "Propagates the modifiers from a parent too its children applying constraints if necesary" [modif-tree objects parent transformed-parent ignore-constraints snap-pixel?] (let [children (map (d/getf objects) (:shapes parent)) - modifiers (get-in modif-tree [(:id parent) :modifiers]) + modifiers (dm/get-in modif-tree [(:id parent) :modifiers]) parent (gtr/transform-shape parent (ctm/select-parent-modifiers modifiers)) set-child @@ -106,7 +109,7 @@ (defn- process-layout-children [modif-tree objects parent transformed-parent] (letfn [(process-child [modif-tree child] - (let [modifiers (get-in modif-tree [(:id parent) :modifiers]) + (let [modifiers (dm/get-in modif-tree [(:id parent) :modifiers]) child-modifiers (-> modifiers (ctm/select-child-geometry-modifiers) (gcl/normalize-child-modifiers parent child transformed-parent))] @@ -120,7 +123,7 @@ [modif-tree objects parent] (letfn [(apply-modifiers [modif-tree child] - (let [modifiers (get-in modif-tree [(:id child) :modifiers])] + (let [modifiers (dm/get-in modif-tree [(:id child) :modifiers])] (cond-> child (some? modifiers) (gtr/transform-shape modifiers) @@ -165,7 +168,7 @@ [modif-tree objects parent] (letfn [(apply-modifiers [child] - (let [modifiers (get-in modif-tree [(:id child) :modifiers])] + (let [modifiers (dm/get-in modif-tree [(:id child) :modifiers])] (cond-> child (some? modifiers) (gtr/transform-shape modifiers) @@ -187,7 +190,7 @@ (-> modifiers (ctm/resize-parent (gpt/point 1 scale-height) origin (:transform parent) (:transform-inverse parent)))))] - (let [modifiers (get-in modif-tree [(:id parent) :modifiers]) + (let [modifiers (dm/get-in modif-tree [(:id parent) :modifiers]) children (->> parent :shapes (map (comp apply-modifiers (d/getf objects)))) @@ -210,7 +213,7 @@ [objects snap-pixel? ignore-constraints [modif-tree recalculate] parent] (let [parent-id (:id parent) root? (= uuid/zero parent-id) - modifiers (get-in modif-tree [parent-id :modifiers]) + modifiers (dm/get-in modif-tree [parent-id :modifiers]) modifiers (cond-> modifiers (and (not root?) (ctm/has-geometry? modifiers) snap-pixel?) @@ -248,7 +251,7 @@ [objects modif-tree parent] (let [is-layout? (ctl/layout? parent) is-auto? (or (ctl/auto-height? parent) (ctl/auto-width? parent)) - modifiers (get-in modif-tree [(:id parent) :modifiers]) + modifiers (dm/get-in modif-tree [(:id parent) :modifiers]) transformed-parent (gtr/transform-shape parent modifiers)] (cond-> modif-tree is-layout? diff --git a/common/src/app/common/geom/shapes/rect.cljc b/common/src/app/common/geom/shapes/rect.cljc index d523f8321..ad0ff5659 100644 --- a/common/src/app/common/geom/shapes/rect.cljc +++ b/common/src/app/common/geom/shapes/rect.cljc @@ -12,10 +12,14 @@ (defn make-rect ([p1 p2] - (let [x1 (min (:x p1) (:x p2)) - y1 (min (:y p1) (:y p2)) - x2 (max (:x p1) (:x p2)) - y2 (max (:y p1) (:y p2))] + (let [xp1 (:x p1) + yp1 (:y p1) + xp2 (:x p2) + yp2 (:y p2) + x1 (min xp1 xp2) + y1 (min yp1 yp2) + x2 (max xp1 xp2) + y2 (max yp1 yp2)] (make-rect x1 y1 (- x2 x1) (- y2 y1)))) ([x y width height] diff --git a/common/src/app/common/geom/shapes/transforms.cljc b/common/src/app/common/geom/shapes/transforms.cljc index 564f9cf74..45ece704b 100644 --- a/common/src/app/common/geom/shapes/transforms.cljc +++ b/common/src/app/common/geom/shapes/transforms.cljc @@ -14,6 +14,7 @@ [app.common.geom.shapes.path :as gpa] [app.common.geom.shapes.rect :as gpr] [app.common.math :as mth] + [app.common.pages.helpers :as cph] [app.common.types.modifiers :as ctm] [app.common.uuid :as uuid])) @@ -452,7 +453,7 @@ (map (d/getf objects)) (apply-children-modifiers objects modif-tree))] (cond-> parent - (= :group (:type parent)) + (cph/group-shape? parent) (update-group-selrect children)))) (defn get-children-bounds From 7b2f0303e8dddeb0746185b5d704c9dd21565342 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Mon, 14 Nov 2022 11:46:33 +0100 Subject: [PATCH 33/36] :sparkles: Fixed problems with masks --- .../src/app/common/geom/shapes/modifiers.cljc | 6 +- .../app/common/geom/shapes/transforms.cljc | 55 ++++++++++++------- common/src/app/common/pages/helpers.cljc | 4 ++ frontend/src/app/main/data/workspace.cljs | 10 +++- .../ui/workspace/viewport/snap_distances.cljs | 33 ++++++----- .../ui/workspace/viewport/snap_points.cljs | 13 +++-- 6 files changed, 75 insertions(+), 46 deletions(-) diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index dc57ac178..5386c05c5 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -128,7 +128,7 @@ (some? modifiers) (gtr/transform-shape modifiers) - (and (some? modifiers) (cph/group-like-shape? child)) + (cph/group-like-shape? child) (gtr/apply-group-modifiers objects modif-tree)))) (set-child-modifiers [parent [layout-line modif-tree] child] @@ -226,13 +226,13 @@ has-modifiers? (ctm/child-modifiers? modifiers) is-layout? (ctl/layout? parent) is-auto? (or (ctl/auto-height? transformed-parent) (ctl/auto-width? transformed-parent)) - is-parent? (or (cph/group-like-shape? parent) (and (cph/frame-shape? parent) (not (ctl/layout? parent)))) + is-parent? (or (cph/group-like-shape? parent) (cph/frame-shape? parent)) ;; If the current child is inside the layout we ignore the constraints is-inside-layout? (ctl/inside-layout? objects parent)] [(cond-> modif-tree - (and has-modifiers? is-parent? (not root?)) + (and (not is-layout?) has-modifiers? is-parent? (not root?)) (set-children-modifiers objects parent transformed-parent (or ignore-constraints is-inside-layout?) snap-pixel?) is-layout? diff --git a/common/src/app/common/geom/shapes/transforms.cljc b/common/src/app/common/geom/shapes/transforms.cljc index 45ece704b..9928ffee1 100644 --- a/common/src/app/common/geom/shapes/transforms.cljc +++ b/common/src/app/common/geom/shapes/transforms.cljc @@ -407,17 +407,19 @@ (apply-modifiers modifiers)))) (defn transform-bounds - [points center modifiers] - (let [transform (ctm/modifiers->transform modifiers)] - (gco/transform-points points center transform))) + ([points modifiers] + (transform-bounds points nil modifiers)) + + ([points center modifiers] + (let [transform (ctm/modifiers->transform modifiers)] + (gco/transform-points points center transform)))) (defn transform-selrect [selrect modifiers] - (let [center (gco/center-selrect selrect)] - (-> selrect - (gpr/rect->points) - (transform-bounds center modifiers) - (gpr/points->selrect)))) + (-> selrect + (gpr/rect->points) + (transform-bounds modifiers) + (gpr/points->selrect))) (defn transform-selrect-matrix [selrect mtx] @@ -434,34 +436,45 @@ (map (comp gpr/points->selrect :points transform-shape)) (gpr/join-selrects))) +(declare apply-group-modifiers) + (defn apply-children-modifiers - [objects modif-tree children] + [objects modif-tree parent-modifiers 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)))] + (let [modifiers (->> (get-in modif-tree [(:id child) :modifiers]) + (ctm/add-modifiers parent-modifiers)) + child (transform-shape child modifiers) + parent? (cph/group-like-shape? child)] (cond-> child parent? - (apply-children-modifiers objects modif-tree))))))) + (apply-group-modifiers objects (assoc-in modif-tree [(:id child) :modifiers] modifiers)))))))) (defn apply-group-modifiers "Apply the modifiers to the group children to calculate its selection rect" - [parent objects modif-tree] + [group objects modif-tree] - (let [children (->> (:shapes parent) + (let [modifiers (get-in modif-tree [(:id group) :modifiers]) + children (->> (:shapes group) (map (d/getf objects)) - (apply-children-modifiers objects modif-tree))] - (cond-> parent - (cph/group-shape? parent) - (update-group-selrect children)))) + (apply-children-modifiers objects modif-tree modifiers))] + (cond + (cph/mask-shape? group) + (update-mask-selrect group children) + + (cph/group-shape? group) + (update-group-selrect group children) + + :else + group))) (defn get-children-bounds [parent objects modif-tree] - (let [children + (let [modifiers (get-in modif-tree [(:id parent) :modifiers]) + children (->> (:shapes parent) (map (d/getf objects)) - (apply-children-modifiers objects modif-tree))] + (apply-children-modifiers objects modif-tree modifiers))] (->> children (mapcat :points) gpr/points->rect))) (defn parent-coords-rect diff --git a/common/src/app/common/pages/helpers.cljc b/common/src/app/common/pages/helpers.cljc index 7bbda08e8..76e234f57 100644 --- a/common/src/app/common/pages/helpers.cljc +++ b/common/src/app/common/pages/helpers.cljc @@ -37,6 +37,10 @@ [{:keys [type]}] (= type :group)) +(defn mask-shape? + [{:keys [type masked-group?]}] + (and (= type :group) masked-group?)) + (defn bool-shape? [{:keys [type]}] (= type :bool)) diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 9b801f12a..eb8916711 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -25,6 +25,7 @@ [app.common.types.pages-list :as ctpl] [app.common.types.shape :as cts] [app.common.types.shape-tree :as ctst] + [app.common.types.shape.layout :as ctl] [app.common.uuid :as uuid] [app.config :as cfg] [app.main.data.comments :as dcm] @@ -686,11 +687,16 @@ shapes-to-detach shapes-to-reroot shapes-to-deroot - ids)] + ids) + + layouts-to-update + (into #{} + (filter (partial ctl/layout? objects)) + (concat [parent-id] (cph/get-parent-ids objects parent-id)))] (rx/of (dch/commit-changes changes) (dwco/expand-collapse parent-id) - (dwul/update-layout-positions [parent-id])))))) + (dwul/update-layout-positions layouts-to-update)))))) (defn relocate-selected-shapes [parent-id to-index] diff --git a/frontend/src/app/main/ui/workspace/viewport/snap_distances.cljs b/frontend/src/app/main/ui/workspace/viewport/snap_distances.cljs index 95cc5693c..7854fd8c8 100644 --- a/frontend/src/app/main/ui/workspace/viewport/snap_distances.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/snap_distances.cljs @@ -10,6 +10,7 @@ [app.common.geom.shapes :as gsh] [app.common.math :as mth] [app.common.pages.helpers :as cph] + [app.common.types.shape.layout :as ctl] [app.main.refs :as refs] [app.main.ui.formats :as fmt] [app.main.worker :as uw] @@ -272,18 +273,20 @@ frame-id (-> selected-shapes first :frame-id) frame (mf/deref (refs/object-by-id frame-id)) selrect (gsh/selection-rect selected-shapes)] - [:g.distance - [:& shape-distance - {:selrect selrect - :page-id page-id - :frame frame - :zoom zoom - :coord :x - :selected selected}] - [:& shape-distance - {:selrect selrect - :page-id page-id - :frame frame - :zoom zoom - :coord :y - :selected selected}]])) + + (when-not (ctl/layout? frame) + [:g.distance + [:& shape-distance + {:selrect selrect + :page-id page-id + :frame frame + :zoom zoom + :coord :x + :selected selected}] + [:& shape-distance + {:selrect selrect + :page-id page-id + :frame frame + :zoom zoom + :coord :y + :selected selected}]]))) diff --git a/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs b/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs index 8b8892ea9..88fe7bc81 100644 --- a/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs @@ -10,6 +10,7 @@ [app.common.geom.shapes :as gsh] [app.common.pages.helpers :as cph] [app.common.spec :as us] + [app.common.types.shape.layout :as ctl] [app.main.snap :as snap] [app.util.geom.snap-points :as sp] [beicon.core :as rx] @@ -172,9 +173,11 @@ (and (= type :layout) (= grid :square)) (= type :guide)))) - shapes (if drawing [drawing] shapes)] - [:& snap-feedback {:shapes shapes - :page-id page-id - :remove-snap? remove-snap? - :zoom zoom}])) + shapes (if drawing [drawing] shapes) + frame-id (snap/snap-frame-id shapes)] + (when-not (ctl/layout? objects frame-id) + [:& snap-feedback {:shapes shapes + :page-id page-id + :remove-snap? remove-snap? + :zoom zoom}]))) From efc1b87ab0d054de754ad3dc27c6d361a6f1c22b Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 11 Nov 2022 10:37:09 +0100 Subject: [PATCH 34/36] :sparkles: Performance improvements --- common/src/app/common/geom/matrix.cljc | 7 + common/src/app/common/geom/shapes.cljc | 1 - common/src/app/common/geom/shapes/common.cljc | 24 ++- .../src/app/common/geom/shapes/modifiers.cljc | 54 +++--- .../common/geom/shapes/pixel_precision.cljc | 36 +++- common/src/app/common/geom/shapes/rect.cljc | 7 + .../app/common/geom/shapes/transforms.cljc | 159 +++++++++++------- common/src/app/common/math.cljc | 2 +- common/src/app/common/types/modifiers.cljc | 126 ++++++++++---- .../shapes/frame/dynamic_modifiers.cljs | 5 +- 10 files changed, 292 insertions(+), 129 deletions(-) diff --git a/common/src/app/common/geom/matrix.cljc b/common/src/app/common/geom/matrix.cljc index 53f3d1748..b8145090f 100644 --- a/common/src/app/common/geom/matrix.cljc +++ b/common/src/app/common/geom/matrix.cljc @@ -263,3 +263,10 @@ matrix (translate-matrix (gpt/negate center)))) point)) + +(defn move? + [{:keys [a b c d _ _]}] + (and (mth/almost-zero? (- a 1)) + (mth/almost-zero? b) + (mth/almost-zero? c) + (mth/almost-zero? (- d 1)))) diff --git a/common/src/app/common/geom/shapes.cljc b/common/src/app/common/geom/shapes.cljc index 163a29b1c..8d56036a0 100644 --- a/common/src/app/common/geom/shapes.cljc +++ b/common/src/app/common/geom/shapes.cljc @@ -175,7 +175,6 @@ (dm/export gtr/transform-selrect-matrix) (dm/export gtr/transform-bounds) (dm/export gtr/move-position-data) -(dm/export gtr/apply-transform) (dm/export gtr/apply-objects-modifiers) (dm/export gtr/parent-coords-rect) (dm/export gtr/parent-coords-points) diff --git a/common/src/app/common/geom/shapes/common.cljc b/common/src/app/common/geom/shapes/common.cljc index 8cb899f04..710c15e78 100644 --- a/common/src/app/common/geom/shapes/common.cljc +++ b/common/src/app/common/geom/shapes/common.cljc @@ -8,7 +8,8 @@ (:require [app.common.data :as d] [app.common.geom.matrix :as gmt] - [app.common.geom.point :as gpt])) + [app.common.geom.point :as gpt] + [app.common.geom.shapes.rect :as gpr])) (defn center-rect [{:keys [x y width height]}] @@ -31,6 +32,22 @@ (gpt/point (/ (+ minx maxx) 2.0) (/ (+ miny maxy) 2.0)))) +(defn center-bounds [[a b c d]] + (let [xa (:x a) + ya (:y a) + xb (:x b) + yb (:y b) + xc (:x c) + yc (:y c) + xd (:x d) + yd (:y d) + minx (min xa xb xc xd) + miny (min ya yb yc yd) + maxx (max xa xb xc xd) + maxy (max ya yb yc yd)] + (gpt/point (/ (+ minx maxx) 2.0) + (/ (+ miny maxy) 2.0)))) + (defn center-shape "Calculate the center of the shape." [shape] @@ -49,3 +66,8 @@ (gpt/transform point (gmt/multiply prev matrix post)))] (mapv tr-point points)) points))) + +(defn transform-selrect + [{:keys [x1 y1 x2 y2] :as sr} matrix] + (let [[c1 c2] (transform-points [(gpt/point x1 y1) (gpt/point x2 y2)] matrix)] + (gpr/corners->selrect c1 c2))) diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index 5386c05c5..4a187191b 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -91,20 +91,30 @@ (defn- set-children-modifiers "Propagates the modifiers from a parent too its children applying constraints if necesary" - [modif-tree objects parent transformed-parent ignore-constraints snap-pixel?] - (let [children (map (d/getf objects) (:shapes parent)) - modifiers (dm/get-in modif-tree [(:id parent) :modifiers]) - parent (gtr/transform-shape parent (ctm/select-parent-modifiers modifiers)) + [modif-tree objects parent transformed-parent ignore-constraints] + (let [children (:shapes parent) + modifiers (dm/get-in modif-tree [(:id parent) :modifiers])] - set-child - (fn [modif-tree child] - (let [child-modifiers (gct/calc-child-modifiers parent child modifiers ignore-constraints transformed-parent) - child-modifiers (cond-> child-modifiers snap-pixel? (gpp/set-pixel-precision child))] - (cond-> modif-tree - (not (ctm/empty? child-modifiers)) - (update-in [(:id child) :modifiers] ctm/add-modifiers child-modifiers))))] + (if (ctm/only-move? modifiers) + ;; Move modifiers don't need to calculate constraints + (loop [modif-tree modif-tree + children (seq children)] + (if-let [current (first children)] + (recur (update-in modif-tree [current :modifiers] ctm/add-modifiers modifiers) + (rest children)) + modif-tree)) - (reduce set-child modif-tree children))) + ;; Check the constraints, then resize + (let [parent (gtr/transform-shape parent (ctm/select-parent-modifiers modifiers))] + (loop [modif-tree modif-tree + children (seq children)] + (if-let [current (first children)] + (let [child-modifiers (gct/calc-child-modifiers parent (get objects current) modifiers ignore-constraints transformed-parent)] + (recur (cond-> modif-tree + (not (ctm/empty? child-modifiers)) + (update-in [current :modifiers] ctm/add-modifiers child-modifiers)) + (rest children))) + modif-tree)))))) (defn- process-layout-children [modif-tree objects parent transformed-parent] @@ -210,17 +220,11 @@ (assoc-in modif-tree [(:id parent) :modifiers] modifiers)))) (defn- propagate-modifiers - [objects snap-pixel? ignore-constraints [modif-tree recalculate] parent] + "Propagate modifiers to its children" + [objects ignore-constraints [modif-tree recalculate] parent] (let [parent-id (:id parent) root? (= uuid/zero parent-id) modifiers (dm/get-in modif-tree [parent-id :modifiers]) - - modifiers (cond-> modifiers - (and (not root?) (ctm/has-geometry? modifiers) snap-pixel?) - (gpp/set-pixel-precision parent)) - - modif-tree (-> modif-tree (assoc-in [parent-id :modifiers] modifiers)) - transformed-parent (gtr/transform-shape parent modifiers) has-modifiers? (ctm/child-modifiers? modifiers) @@ -233,7 +237,7 @@ [(cond-> modif-tree (and (not is-layout?) has-modifiers? is-parent? (not root?)) - (set-children-modifiers objects parent transformed-parent (or ignore-constraints is-inside-layout?) snap-pixel?) + (set-children-modifiers objects parent transformed-parent (or ignore-constraints is-inside-layout?)) is-layout? (-> (process-layout-children objects parent transformed-parent) @@ -266,7 +270,7 @@ (let [shapes-tree (resolve-tree-sequence (-> modif-tree keys set) objects) [modif-tree recalculate] - (reduce (partial propagate-modifiers objects snap-pixel? ignore-constraints) [modif-tree #{}] shapes-tree) + (reduce (partial propagate-modifiers objects ignore-constraints) [modif-tree #{}] shapes-tree) shapes-tree (resolve-tree-sequence recalculate objects) @@ -281,7 +285,11 @@ modif-tree (->> shapes-tree (filter ctl/layout?) - (reduce (partial calculate-reflow-layout objects) modif-tree ))] + (reduce (partial calculate-reflow-layout objects) modif-tree)) + + modif-tree + (cond-> modif-tree + snap-pixel? (gpp/adjust-pixel-precision objects))] ;;#?(:cljs ;; (.log js/console ">result" (modif->js modif-tree objects))) diff --git a/common/src/app/common/geom/shapes/pixel_precision.cljc b/common/src/app/common/geom/shapes/pixel_precision.cljc index 297abf99a..93dd26dcd 100644 --- a/common/src/app/common/geom/shapes/pixel_precision.cljc +++ b/common/src/app/common/geom/shapes/pixel_precision.cljc @@ -6,6 +6,8 @@ (ns app.common.geom.shapes.pixel-precision (:require + [app.common.data :as d] + [app.common.data.macros :as dm] [app.common.geom.point :as gpt] [app.common.geom.shapes.points :as gpo] [app.common.geom.shapes.rect :as gpr] @@ -15,9 +17,8 @@ [app.common.types.modifiers :as ctm])) (defn size-pixel-precision - [modifiers shape] - (let [{:keys [points transform transform-inverse] :as shape} (gtr/transform-shape shape modifiers) - origin (gpo/origin points) + [modifiers {:keys [points transform transform-inverse] :as shape}] + (let [origin (gpo/origin points) curr-width (gpo/width-points points) curr-height (gpo/height-points points) @@ -35,9 +36,8 @@ (ctm/resize scalev origin transform transform-inverse)))) (defn position-pixel-precision - [modifiers shape] - (let [{:keys [points]} (gtr/transform-shape shape modifiers) - bounds (gpr/points->rect points) + [modifiers {:keys [points]}] + (let [bounds (gpr/points->rect points) corner (gpt/point bounds) target-corner (gpt/round corner) deltav (gpt/to-vec corner target-corner)] @@ -47,7 +47,25 @@ (defn set-pixel-precision "Adjust modifiers so they adjust to the pixel grid" [modifiers shape] - - (-> modifiers + (let [move? (ctm/only-move? modifiers)] + (cond-> modifiers + (not move?) (size-pixel-precision shape) - (position-pixel-precision shape))) + + :always + (position-pixel-precision shape)))) + +(defn adjust-pixel-precision + [modif-tree objects] + (let [update-modifiers + (fn [modif-tree shape] + (let [modifiers (dm/get-in modif-tree [(:id shape) :modifiers])] + (if-not (ctm/has-geometry? modifiers) + modif-tree + (let [shape (gtr/transform-shape shape modifiers)] + (-> modif-tree + (update-in [(:id shape) :modifiers] set-pixel-precision shape))))))] + + (->> (keys modif-tree) + (map (d/getf objects)) + (reduce update-modifiers modif-tree)))) diff --git a/common/src/app/common/geom/shapes/rect.cljc b/common/src/app/common/geom/shapes/rect.cljc index ad0ff5659..be8d5a5b5 100644 --- a/common/src/app/common/geom/shapes/rect.cljc +++ b/common/src/app/common/geom/shapes/rect.cljc @@ -192,3 +192,10 @@ (>= (:y1 sr2) (:y1 sr1)) (<= (:y2 sr2) (:y2 sr1)))) +(defn corners->selrect + [p1 p2] + (let [xp1 (:x p1) + xp2 (:x p2) + yp1 (:y p1) + yp2 (:y p2)] + (make-selrect (min xp1 xp2) (min yp1 yp2) (abs (- xp1 xp2)) (abs (- yp1 yp2))))) diff --git a/common/src/app/common/geom/shapes/transforms.cljc b/common/src/app/common/geom/shapes/transforms.cljc index 9928ffee1..04ac8fc27 100644 --- a/common/src/app/common/geom/shapes/transforms.cljc +++ b/common/src/app/common/geom/shapes/transforms.cljc @@ -188,55 +188,52 @@ "Calculates a matrix that is a series of transformations we have to do to the transformed rectangle so that after applying them the end result is the `shape-path-temp`. This is compose of three transformations: skew, resize and rotation" - ([points-temp points-rec] - (calculate-adjust-matrix points-temp points-rec false false)) + [points-temp points-rec flip-x flip-y] + (let [center (gco/center-bounds points-temp) - ([points-temp points-rec flip-x flip-y] - (let [center (gco/center-points points-temp) + stretch-matrix (gmt/matrix) - stretch-matrix (gmt/matrix) + skew-angle (calculate-skew-angle points-temp) - skew-angle (calculate-skew-angle points-temp) + ;; When one of the axis is flipped we have to reverse the skew + ;; skew-angle (if (neg? (* (:x resize-vector) (:y resize-vector))) (- skew-angle) skew-angle ) + skew-angle (if (and (or flip-x flip-y) + (not (and flip-x flip-y))) (- skew-angle) skew-angle ) + skew-angle (if (mth/nan? skew-angle) 0 skew-angle) - ;; When one of the axis is flipped we have to reverse the skew - ;; skew-angle (if (neg? (* (:x resize-vector) (:y resize-vector))) (- skew-angle) skew-angle ) - skew-angle (if (and (or flip-x flip-y) - (not (and flip-x flip-y))) (- skew-angle) skew-angle ) - skew-angle (if (mth/nan? skew-angle) 0 skew-angle) + stretch-matrix (gmt/multiply stretch-matrix (gmt/skew-matrix skew-angle 0)) - stretch-matrix (gmt/multiply stretch-matrix (gmt/skew-matrix skew-angle 0)) + h1 (max 1 (calculate-height points-temp)) + h2 (max 1 (calculate-height (gco/transform-points points-rec center stretch-matrix))) + h3 (if-not (mth/almost-zero? h2) (/ h1 h2) 1) + h3 (if (mth/nan? h3) 1 h3) - h1 (max 1 (calculate-height points-temp)) - h2 (max 1 (calculate-height (gco/transform-points points-rec center stretch-matrix))) - h3 (if-not (mth/almost-zero? h2) (/ h1 h2) 1) - h3 (if (mth/nan? h3) 1 h3) + w1 (max 1 (calculate-width points-temp)) + w2 (max 1 (calculate-width (gco/transform-points points-rec center stretch-matrix))) + w3 (if-not (mth/almost-zero? w2) (/ w1 w2) 1) + w3 (if (mth/nan? w3) 1 w3) - w1 (max 1 (calculate-width points-temp)) - w2 (max 1 (calculate-width (gco/transform-points points-rec center stretch-matrix))) - w3 (if-not (mth/almost-zero? w2) (/ w1 w2) 1) - w3 (if (mth/nan? w3) 1 w3) + stretch-matrix (gmt/multiply stretch-matrix (gmt/scale-matrix (gpt/point w3 h3))) - stretch-matrix (gmt/multiply stretch-matrix (gmt/scale-matrix (gpt/point w3 h3))) + rotation-angle (calculate-rotation + center + (gco/transform-points points-rec (gco/center-points points-rec) stretch-matrix) + points-temp + flip-x + flip-y) - rotation-angle (calculate-rotation - center - (gco/transform-points points-rec (gco/center-points points-rec) stretch-matrix) - points-temp - flip-x - flip-y) + stretch-matrix (gmt/multiply (gmt/rotate-matrix rotation-angle) stretch-matrix) - stretch-matrix (gmt/multiply (gmt/rotate-matrix rotation-angle) stretch-matrix) - - ;; This is the inverse to be able to remove the transformation - stretch-matrix-inverse - (gmt/multiply (gmt/scale-matrix (gpt/point (/ 1 w3) (/ 1 h3))) - (gmt/skew-matrix (- skew-angle) 0) - (gmt/rotate-matrix (- rotation-angle)))] - [stretch-matrix stretch-matrix-inverse rotation-angle]))) + ;; This is the inverse to be able to remove the transformation + stretch-matrix-inverse + (gmt/multiply (gmt/scale-matrix (gpt/point (/ 1 w3) (/ 1 h3))) + (gmt/skew-matrix (- skew-angle) 0) + (gmt/rotate-matrix (- rotation-angle)))] + [stretch-matrix stretch-matrix-inverse rotation-angle])) (defn- adjust-rotated-transform [{:keys [transform transform-inverse flip-x flip-y]} points] - (let [center (gco/center-points points) + (let [center (gco/center-bounds points) points-temp (cond-> points (some? transform-inverse) @@ -280,7 +277,28 @@ (-> (update :flip-y not) (update :rotation -))))) -(defn apply-transform +(defn- apply-transform-move + "Given a new set of points transformed, set up the rectangle so it keeps + its properties. We adjust de x,y,width,height and create a custom transform" + [shape transform-mtx] + (let [bool? (= (:type shape) :bool) + path? (= (:type shape) :path) + points (gco/transform-points (:points shape) transform-mtx) + selrect (gco/transform-selrect (:selrect shape) transform-mtx)] + (-> shape + (cond-> bool? + (update :bool-content gpa/transform-content transform-mtx)) + (cond-> path? + (update :content gpa/transform-content transform-mtx)) + (cond-> (not path?) + (assoc :x (:x selrect) + :y (:y selrect) + :width (:width selrect) + :height (:height selrect))) + (assoc :selrect selrect) + (assoc :points points)))) + +(defn- apply-transform-generic "Given a new set of points transformed, set up the rectangle so it keeps its properties. We adjust de x,y,width,height and create a custom transform" [shape transform-mtx] @@ -303,7 +321,10 @@ (cond-> path? (update :content gpa/transform-content transform-mtx)) (cond-> (not path?) - (-> (merge (select-keys selrect [:x :y :width :height])))) + (assoc :x (:x selrect) + :y (:y selrect) + :width (:width selrect) + :height (:height selrect))) (cond-> transform (-> (assoc :transform transform) (assoc :transform-inverse transform-inverse))) @@ -316,6 +337,14 @@ (assoc :points points)) (assoc :rotation rotation)))) +(defn- apply-transform + "Given a new set of points transformed, set up the rectangle so it keeps + its properties. We adjust de x,y,width,height and create a custom transform" + [shape transform-mtx] + (if (gmt/move? transform-mtx) + (apply-transform-move shape transform-mtx) + (apply-transform-generic shape transform-mtx))) + (defn- update-group-viewbox "Updates the viewbox for groups imported from SVG's" [{:keys [selrect svg-viewbox] :as group} new-selrect] @@ -376,24 +405,6 @@ (assoc :flip-x (-> mask :flip-x)) (assoc :flip-y (-> mask :flip-y))))) -(defn apply-modifiers - [shape modifiers] - (let [transform (ctm/modifiers->transform modifiers)] - (cond-> shape - (and (some? transform) - ;; Never transform the root frame - (not= uuid/zero (:id shape))) - (apply-transform transform) - - :always - (ctm/apply-structure-modifiers modifiers)))) - -(defn apply-objects-modifiers - [objects modifiers] - (letfn [(process-shape [objects [id modifier]] - (d/update-when objects id apply-modifiers (:modifiers modifier)))] - (reduce process-shape objects modifiers))) - (defn transform-shape ([shape] (let [modifiers (:modifiers shape)] @@ -402,9 +413,35 @@ (transform-shape modifiers)))) ([shape modifiers] - (cond-> shape - (and (some? modifiers) (not (ctm/empty? modifiers))) - (apply-modifiers modifiers)))) + (letfn [(apply-modifiers + [shape modifiers] + (if (ctm/empty? modifiers) + shape + (let [transform (ctm/modifiers->transform modifiers)] + (cond-> shape + (and (some? transform) (not= uuid/zero (:id shape))) ;; Never transform the root frame + (apply-transform transform) + + (ctm/has-structure? modifiers) + (ctm/apply-structure-modifiers modifiers)))))] + + (cond-> shape + (and (some? modifiers) (not (ctm/empty? modifiers))) + (apply-modifiers modifiers))))) + +(defn apply-objects-modifiers + [objects modifiers] + + (loop [objects objects + entry (first modifiers) + modifiers (rest modifiers)] + + (if (nil? entry) + objects + (let [[id modifier] entry] + (recur (d/update-when objects id transform-shape (:modifiers modifier)) + (first modifiers) + (rest modifiers)))))) (defn transform-bounds ([points modifiers] @@ -412,7 +449,9 @@ ([points center modifiers] (let [transform (ctm/modifiers->transform modifiers)] - (gco/transform-points points center transform)))) + (cond-> points + (some? transform) + (gco/transform-points center transform))))) (defn transform-selrect [selrect modifiers] diff --git a/common/src/app/common/math.cljc b/common/src/app/common/math.cljc index fc35d15f3..e5483b118 100644 --- a/common/src/app/common/math.cljc +++ b/common/src/app/common/math.cljc @@ -156,7 +156,7 @@ (if (> num to) to num))) (defn almost-zero? [num] - (< (abs (double num)) 1e-5)) + (< (abs (double num)) 1e-4)) (defonce float-equal-precision 0.001) diff --git a/common/src/app/common/types/modifiers.cljc b/common/src/app/common/types/modifiers.cljc index 2b994d6f6..61af67564 100644 --- a/common/src/app/common/types/modifiers.cljc +++ b/common/src/app/common/types/modifiers.cljc @@ -38,21 +38,79 @@ ;; * rotation ;; * change-properties +;; Private aux functions + (def conjv (fnil conj [])) +(defn- move-vec? [vector] + (or (not (mth/almost-zero? (:x vector))) + (not (mth/almost-zero? (:y vector))))) + +(defn- resize-vec? [vector] + (or (not (mth/almost-zero? (- (:x vector) 1))) + (not (mth/almost-zero? (- (:y vector) 1))))) + + +(defn- mergeable-move? + [op1 op2] + (and (= :move (:type op1)) + (= :move (:type op2)))) + +(defn- mergeable-resize? + [op1 op2] + (and (= :resize (:type op1)) + (= :resize (:type op2)) + + ;; Same transforms + (gmt/close? (or (:transform op1) (gmt/matrix)) (or (:transform op2) (gmt/matrix))) + (gmt/close? (or (:transform-inverse op1) (gmt/matrix)) (or (:transform-inverse op2) (gmt/matrix))) + + ;; Same origin + (gpt/close? (:origin op1) (:origin op2)))) + +(defn- merge-move + [op1 op2] + {:type :move + :vector (gpt/add (:vector op1) (:vector op2))}) + +(defn- merge-resize + [op1 op2] + (let [vector (gpt/point (* (-> op1 :vector :x) (-> op2 :vector :x)) + (* (-> op1 :vector :y) (-> op2 :vector :y)))] + (assoc op1 :vector vector))) + +(defn- maybe-add-move + "Check the last operation to check if we can stack it over the last one" + [operations op] + (if (c/empty? operations) + [op] + (let [head (peek operations)] + (if (mergeable-move? head op) + (let [item (merge-move head op)] + (cond-> (pop operations) + (move-vec? (:vector item)) + (conj item))) + (conj operations op))))) + +(defn- maybe-add-resize + "Check the last operation to check if we can stack it over the last one" + [operations op] + + (if (c/empty? operations) + [op] + (let [head (peek operations)] + (if (mergeable-resize? head op) + (let [item (merge-resize head op)] + (cond-> (pop operations) + (resize-vec? (:vector item)) + (conj item))) + (conj operations op))))) + ;; Public builder API (defn empty [] {}) -(defn move-vec? [vector] - (or (not (mth/almost-zero? (:x vector))) - (not (mth/almost-zero? (:y vector))))) - -(defn resize-vec? [vector] - (or (not (mth/almost-zero? (- (:x vector) 1))) - (not (mth/almost-zero? (- (:y vector) 1))))) - (defn move-parent ([modifiers x y] (move-parent modifiers (gpt/point x y))) @@ -66,18 +124,18 @@ ([modifiers vector origin] (cond-> modifiers (resize-vec? vector) - (update :geometry-parent conjv {:type :resize - :vector vector - :origin origin}))) + (update :geometry-parent maybe-add-resize {:type :resize + :vector vector + :origin origin}))) ([modifiers vector origin transform transform-inverse] (cond-> modifiers (resize-vec? vector) - (update :geometry-parent conjv {:type :resize - :vector vector - :origin origin - :transform transform - :transform-inverse transform-inverse})))) + (update :geometry-parent maybe-add-resize {:type :resize + :vector vector + :origin origin + :transform transform + :transform-inverse transform-inverse})))) (defn move ([modifiers x y] (move modifiers (gpt/point x y))) @@ -85,24 +143,24 @@ ([modifiers vector] (cond-> modifiers (move-vec? vector) - (update :geometry-child conjv {:type :move :vector vector})))) + (update :geometry-child maybe-add-move {:type :move :vector vector})))) (defn resize ([modifiers vector origin] (cond-> modifiers (resize-vec? vector) - (update :geometry-child conjv {:type :resize - :vector vector - :origin origin}))) + (update :geometry-child maybe-add-resize {:type :resize + :vector vector + :origin origin}))) ([modifiers vector origin transform transform-inverse] (cond-> modifiers (resize-vec? vector) - (update :geometry-child conjv {:type :resize - :vector vector - :origin origin - :transform transform - :transform-inverse transform-inverse})))) + (update :geometry-child maybe-add-resize {:type :resize + :vector vector + :origin origin + :transform transform + :transform-inverse transform-inverse})))) (defn rotation [modifiers center angle] @@ -296,17 +354,20 @@ (defn only-move? "Returns true if there are only move operations" - [modifier] - (or (and (= 1 (-> modifier :geometry-child count)) - (= :move (-> modifier :geometry-child first :type))) - (and (= 1 (-> modifier :geometry-parent count)) - (= :move (-> modifier :geometry-parent first :type))))) + [{:keys [geometry-child geometry-parent]}] + (and (every? #(= :move (:type %)) geometry-child) + (every? #(= :move (:type %)) geometry-parent))) (defn has-geometry? [{:keys [geometry-parent geometry-child]}] (or (d/not-empty? geometry-parent) (d/not-empty? geometry-child))) +(defn has-structure? + [{:keys [structure-parent structure-child]}] + (or (d/not-empty? structure-parent) + (d/not-empty? structure-child))) + ;; Extract subsets of modifiers (defn select-child-modifiers @@ -374,8 +435,9 @@ (let [modifiers (if (d/not-empty? (:geometry-parent modifiers)) (d/concat-vec (:geometry-parent modifiers) (:geometry-child modifiers)) (:geometry-child modifiers))] - (->> modifiers - (reduce apply-modifier (gmt/matrix)))))) + (when (d/not-empty? modifiers) + (->> modifiers + (reduce apply-modifier (gmt/matrix))))))) (defn apply-structure-modifiers "Apply structure changes to a shape" diff --git a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs index 5b2a0a800..c4df18c29 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs @@ -200,8 +200,8 @@ (when (some? modifiers) (d/mapm (fn [id {modifiers :modifiers}] (let [shape (get objects id) - text? (= :text (:type shape)) - modifiers (cond-> modifiers text? (adapt-text-modifiers shape))] + adapt-text? (and (= :text (:type shape)) (not (ctm/only-move? modifiers))) + modifiers (cond-> modifiers adapt-text? (adapt-text-modifiers shape))] (ctm/modifiers->transform modifiers))) modifiers)))) @@ -214,6 +214,7 @@ (mf/deps transforms) (fn [] (->> (keys transforms) + (filter #(some? (get transforms %))) (mapv (d/getf objects))))) prev-shapes (mf/use-var nil) From 32756db1c19d3361a384cb2812ef68385bea1708 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Tue, 15 Nov 2022 18:17:11 +0100 Subject: [PATCH 35/36] :sparkles: Redone the calculus of sizing auto --- .../src/app/common/geom/shapes/modifiers.cljc | 163 ++++++++++-------- .../app/common/geom/shapes/transforms.cljc | 55 +++--- common/src/app/common/types/modifiers.cljc | 6 +- 3 files changed, 124 insertions(+), 100 deletions(-) diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index 4a187191b..3c77f4a6f 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -135,10 +135,10 @@ (letfn [(apply-modifiers [modif-tree child] (let [modifiers (dm/get-in modif-tree [(:id child) :modifiers])] (cond-> child - (some? modifiers) + (and (not (cph/group-shape? child)) (some? modifiers)) (gtr/transform-shape modifiers) - (cph/group-like-shape? child) + (cph/group-shape? child) (gtr/apply-group-modifiers objects modif-tree)))) (set-child-modifiers [parent [layout-line modif-tree] child] @@ -152,7 +152,7 @@ [layout-line modif-tree]))] - (let [children (map (d/getf objects) (:shapes parent)) + (let [children (map (d/getf objects) (:shapes parent)) children (->> children (map (partial apply-modifiers modif-tree))) layout-data (gcl/calc-layout-data parent children) children (into [] (cond-> children (:reverse? layout-data) reverse)) @@ -173,119 +173,136 @@ modif-tree))))) -(defn- set-auto-modifiers +(defn- calc-auto-modifiers "Calculates the modifiers to adjust the bounds for auto-width/auto-height shapes" - [modif-tree objects parent] - (letfn [(apply-modifiers - [child] - (let [modifiers (dm/get-in modif-tree [(:id child) :modifiers])] - (cond-> child - (some? modifiers) - (gtr/transform-shape modifiers) - - (and (some? modifiers) (cph/group-like-shape? child)) - (gtr/apply-group-modifiers objects modif-tree)))) - - (set-parent-auto-width - [modifiers parent auto-width] + [objects parent] + (letfn [(set-parent-auto-width + [modifiers auto-width] (let [origin (-> parent :points first) scale-width (/ auto-width (-> parent :selrect :width) )] (-> modifiers (ctm/resize-parent (gpt/point scale-width 1) origin (:transform parent) (:transform-inverse parent))))) (set-parent-auto-height - [modifiers parent auto-height] + [modifiers auto-height] (let [origin (-> parent :points first) scale-height (/ auto-height (-> parent :selrect :height) )] (-> modifiers (ctm/resize-parent (gpt/point 1 scale-height) origin (:transform parent) (:transform-inverse parent)))))] - (let [modifiers (dm/get-in modif-tree [(:id parent) :modifiers]) - children (->> parent - :shapes - (map (comp apply-modifiers (d/getf objects)))) + (let [children (->> parent :shapes (map (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)) + (gcl/layout-content-bounds parent children))] - modifiers - (cond-> modifiers - (and (some? auto-width) (ctl/auto-width? parent)) - (set-parent-auto-width parent auto-width) + (cond-> (ctm/empty) + (and (some? auto-width) (ctl/auto-width? parent)) + (set-parent-auto-width auto-width) - (and (some? auto-height) (ctl/auto-height? parent)) - (set-parent-auto-height parent auto-height))] - - (assoc-in modif-tree [(:id parent) :modifiers] modifiers)))) + (and (some? auto-height) (ctl/auto-height? parent)) + (set-parent-auto-height auto-height))))) (defn- propagate-modifiers "Propagate modifiers to its children" - [objects ignore-constraints [modif-tree recalculate] parent] + [objects ignore-constraints [modif-tree autolayouts] parent] (let [parent-id (:id parent) root? (= uuid/zero parent-id) modifiers (dm/get-in modif-tree [parent-id :modifiers]) transformed-parent (gtr/transform-shape parent modifiers) has-modifiers? (ctm/child-modifiers? modifiers) - is-layout? (ctl/layout? parent) - is-auto? (or (ctl/auto-height? transformed-parent) (ctl/auto-width? transformed-parent)) - is-parent? (or (cph/group-like-shape? parent) (cph/frame-shape? parent)) + layout? (ctl/layout? parent) + auto? (or (ctl/auto-height? transformed-parent) (ctl/auto-width? transformed-parent)) + parent? (or (cph/group-like-shape? parent) (cph/frame-shape? parent)) ;; If the current child is inside the layout we ignore the constraints - is-inside-layout? (ctl/inside-layout? objects parent)] + inside-layout? (ctl/inside-layout? objects parent)] [(cond-> modif-tree - (and (not is-layout?) has-modifiers? is-parent? (not root?)) - (set-children-modifiers objects parent transformed-parent (or ignore-constraints is-inside-layout?)) + (and (not layout?) has-modifiers? parent? (not root?)) + (set-children-modifiers objects parent transformed-parent (or ignore-constraints inside-layout?)) - is-layout? + layout? (-> (process-layout-children objects parent transformed-parent) - (set-layout-modifiers objects transformed-parent)) + (set-layout-modifiers objects transformed-parent))) - is-auto? - (set-auto-modifiers objects transformed-parent)) + ;; Auto-width/height can change the positions in the parent so we need to recalculate + (cond-> autolayouts auto? (conj (:id parent)))])) - (cond-> recalculate - ;; Auto-width/height can change the positions in the parent so we need to recalculate - is-auto? - (conj (:id parent)))])) +(defn- apply-structure-modifiers + [objects modif-tree] + (letfn [(apply-shape [objects [id {:keys [modifiers]}]] + (if (ctm/has-structure? modifiers) + (let [shape (get objects id)] + (update objects id ctm/apply-structure-modifiers modifiers)) + objects))] + (reduce apply-shape objects modif-tree))) -(defn- calculate-reflow-layout - [objects modif-tree parent] - (let [is-layout? (ctl/layout? parent) - is-auto? (or (ctl/auto-height? parent) (ctl/auto-width? parent)) - modifiers (dm/get-in modif-tree [(:id parent) :modifiers]) - transformed-parent (gtr/transform-shape parent modifiers)] - (cond-> modif-tree - is-layout? - (set-layout-modifiers objects transformed-parent) +(defn- apply-partial-objects-modifiers + [objects tree-seq modif-tree] - is-auto? - (set-auto-modifiers objects transformed-parent)))) + (letfn [(apply-shape [objects {:keys [id] :as shape}] + (if (cph/group-shape? shape) + (let [children (cph/get-children objects id)] + (assoc objects id + (cond + (cph/mask-shape? shape) + (gtr/update-mask-selrect shape children) + + :else + (gtr/update-group-selrect shape children)))) + + (let [modifiers (get-in modif-tree [id :modifiers]) + object (cond-> shape + (some? modifiers) + (gtr/transform-shape modifiers))] + (assoc objects id object))))] + + (reduce apply-shape objects (reverse tree-seq)))) + +(defn merge-modif-tree + [modif-tree other-tree] + (reduce (fn [modif-tree [id {:keys [modifiers]}]] + (update-in modif-tree [id :modifiers] ctm/add-modifiers modifiers)) + modif-tree + other-tree)) + +(defn sizing-auto-modifiers + "Recalculates the layouts to adjust the sizing: auto new sizes" + [modif-tree sizing-auto-layouts objects ignore-constraints] + (loop [modif-tree modif-tree + sizing-auto-layouts (reverse sizing-auto-layouts)] + (if-let [current (first sizing-auto-layouts)] + (let [parent-base (get objects current) + tree-seq (resolve-tree-sequence #{current} objects) + + ;; Apply the current stack of transformations so we can calculate the auto-layouts + objects (apply-partial-objects-modifiers objects tree-seq modif-tree) + + resize-modif-tree + {current {:modifiers (calc-auto-modifiers objects parent-base)}} + + tree-seq (resolve-tree-sequence #{current} objects) + + [resize-modif-tree _] + (reduce (partial propagate-modifiers objects ignore-constraints) [resize-modif-tree #{}] tree-seq) + + modif-tree (merge-modif-tree modif-tree resize-modif-tree)] + (recur modif-tree (rest sizing-auto-layouts))) + modif-tree))) (defn set-objects-modifiers [modif-tree objects ignore-constraints snap-pixel?] - (let [shapes-tree (resolve-tree-sequence (-> modif-tree keys set) objects) + (let [objects (apply-structure-modifiers objects modif-tree) + shapes-tree (resolve-tree-sequence (-> modif-tree keys set) objects) - [modif-tree recalculate] + [modif-tree sizing-auto-layouts] (reduce (partial propagate-modifiers objects ignore-constraints) [modif-tree #{}] shapes-tree) - shapes-tree (resolve-tree-sequence recalculate objects) - - ;; We need to go again and recalculate the layout positions+hug - ;; TODO LAYOUT: How to remove this recalculation? - modif-tree - (->> shapes-tree - reverse - (filter ctl/layout?) - (reduce (partial calculate-reflow-layout objects) modif-tree)) - - modif-tree - (->> shapes-tree - (filter ctl/layout?) - (reduce (partial calculate-reflow-layout objects) modif-tree)) + ;; Calculate hug layouts positions + modif-tree (sizing-auto-modifiers modif-tree sizing-auto-layouts objects ignore-constraints) modif-tree (cond-> modif-tree diff --git a/common/src/app/common/geom/shapes/transforms.cljc b/common/src/app/common/geom/shapes/transforms.cljc index 04ac8fc27..f2c63f5df 100644 --- a/common/src/app/common/geom/shapes/transforms.cljc +++ b/common/src/app/common/geom/shapes/transforms.cljc @@ -369,6 +369,9 @@ ;; Points for every shape inside the group points (->> children (mapcat :points)) + ;; Fixed problem with empty groups. Should not happen (but it does) + points (if (empty? points) (:points group) points) + ;; Invert to get the points minus the transforms applied to the group base-points (gco/transform-points points shape-center (:transform-inverse group (gmt/matrix))) @@ -478,43 +481,43 @@ (declare apply-group-modifiers) (defn apply-children-modifiers - [objects modif-tree parent-modifiers children] + [objects modif-tree parent-modifiers children propagate?] (->> children (map (fn [child] - (let [modifiers (->> (get-in modif-tree [(:id child) :modifiers]) - (ctm/add-modifiers parent-modifiers)) + (let [modifiers (cond-> (get-in modif-tree [(:id child) :modifiers]) + propagate? (ctm/add-modifiers parent-modifiers)) child (transform-shape child modifiers) - parent? (cph/group-like-shape? child)] + parent? (cph/group-like-shape? child) + + modif-tree + (cond-> modif-tree + propagate? + (assoc-in [(:id child) :modifiers] modifiers))] + (cond-> child parent? - (apply-group-modifiers objects (assoc-in modif-tree [(:id child) :modifiers] modifiers)))))))) + (apply-group-modifiers objects modif-tree propagate?))))))) (defn apply-group-modifiers "Apply the modifiers to the group children to calculate its selection rect" - [group objects modif-tree] + ([group objects modif-tree] + (apply-group-modifiers group objects modif-tree true)) - (let [modifiers (get-in modif-tree [(:id group) :modifiers]) - children (->> (:shapes group) - (map (d/getf objects)) - (apply-children-modifiers objects modif-tree modifiers))] - (cond - (cph/mask-shape? group) - (update-mask-selrect group children) + ([group objects modif-tree propagate?] + (let [modifiers (get-in modif-tree [(:id group) :modifiers]) + children + (as-> (:shapes group) $ + (map (d/getf objects) $) + (apply-children-modifiers objects modif-tree modifiers $ propagate?))] + (cond + (cph/mask-shape? group) + (update-mask-selrect group children) - (cph/group-shape? group) - (update-group-selrect group children) + (cph/group-shape? group) + (update-group-selrect group children) - :else - group))) - -(defn get-children-bounds - [parent objects modif-tree] - (let [modifiers (get-in modif-tree [(:id parent) :modifiers]) - children - (->> (:shapes parent) - (map (d/getf objects)) - (apply-children-modifiers objects modif-tree modifiers))] - (->> children (mapcat :points) gpr/points->rect))) + :else + group)))) (defn parent-coords-rect [child parent] diff --git a/common/src/app/common/types/modifiers.cljc b/common/src/app/common/types/modifiers.cljc index 61af67564..d95d0d31f 100644 --- a/common/src/app/common/types/modifiers.cljc +++ b/common/src/app/common/types/modifiers.cljc @@ -384,7 +384,11 @@ (defn select-structure [modifiers] - (select-keys modifiers [:structure-parent])) + (select-keys modifiers [:structure-parent :structure-child])) + +(defn select-geometry + [modifiers] + (select-keys modifiers [:geometry-parent :geometry-child])) (defn added-children-frames "Returns the frames that have an 'add-children' operation" From afa6a97693a2beafff2e0fcdfe0c37e3fe2b8f38 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 17 Nov 2022 09:18:51 +0100 Subject: [PATCH 36/36] :sparkles: Fixes problem with bool shapes --- common/src/app/common/geom/shapes.cljc | 4 ++- common/src/app/common/geom/shapes/bool.cljc | 14 ---------- .../src/app/common/geom/shapes/modifiers.cljc | 26 +++++++++++-------- .../app/common/geom/shapes/transforms.cljc | 18 +++++++++++++ common/src/app/common/pages/changes.cljc | 3 +-- .../src/app/common/pages/changes_builder.cljc | 6 ++--- .../app/main/data/workspace/modifiers.cljs | 16 +++++++++++- 7 files changed, 54 insertions(+), 33 deletions(-) diff --git a/common/src/app/common/geom/shapes.cljc b/common/src/app/common/geom/shapes.cljc index 8d56036a0..54c07a570 100644 --- a/common/src/app/common/geom/shapes.cljc +++ b/common/src/app/common/geom/shapes.cljc @@ -160,6 +160,7 @@ (dm/export gpr/join-selrects) (dm/export gpr/contains-selrect?) (dm/export gpr/contains-point?) +(dm/export gpr/close-selrect?) (dm/export gtr/move) (dm/export gtr/absolute-move) @@ -170,6 +171,7 @@ (dm/export gtr/calculate-adjust-matrix) (dm/export gtr/update-group-selrect) (dm/export gtr/update-mask-selrect) +(dm/export gtr/update-bool-selrect) (dm/export gtr/transform-shape) (dm/export gtr/transform-selrect) (dm/export gtr/transform-selrect-matrix) @@ -194,7 +196,7 @@ (dm/export gin/rect-contains-shape?) ;; Bool -(dm/export gsb/update-bool-selrect) + (dm/export gsb/calc-bool-content) ;; Constraints diff --git a/common/src/app/common/geom/shapes/bool.cljc b/common/src/app/common/geom/shapes/bool.cljc index f404e680c..a3a464544 100644 --- a/common/src/app/common/geom/shapes/bool.cljc +++ b/common/src/app/common/geom/shapes/bool.cljc @@ -7,8 +7,6 @@ (ns app.common.geom.shapes.bool (:require [app.common.data :as d] - [app.common.geom.shapes.path :as gsp] - [app.common.geom.shapes.transforms :as gtr] [app.common.path.bool :as pb] [app.common.path.shapes-to-path :as stp])) @@ -25,17 +23,5 @@ (into [] extract-content-xf (:shapes shape))] (pb/content-bool (:bool-type shape) shapes-content))) -(defn update-bool-selrect - "Calculates the selrect+points for the boolean shape" - [shape children objects] - (let [bool-content (calc-bool-content shape objects) - shape (assoc shape :bool-content bool-content) - [points selrect] (gsp/content->points+selrect shape bool-content)] - - (if (and (some? selrect) (d/not-empty? points)) - (-> shape - (assoc :selrect selrect) - (assoc :points points)) - (gtr/update-group-selrect shape children)))) diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index 3c77f4a6f..36265536a 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -133,13 +133,17 @@ [modif-tree objects parent] (letfn [(apply-modifiers [modif-tree child] - (let [modifiers (dm/get-in modif-tree [(:id child) :modifiers])] - (cond-> child - (and (not (cph/group-shape? child)) (some? modifiers)) - (gtr/transform-shape modifiers) + (let [modifiers (-> (dm/get-in modif-tree [(:id child) :modifiers]) + (ctm/select-geometry))] + (cond + (cph/group-like-shape? child) + (gtr/apply-group-modifiers child objects modif-tree) - (cph/group-shape? child) - (gtr/apply-group-modifiers objects modif-tree)))) + (some? modifiers) + (gtr/transform-shape child modifiers) + + :else + child))) (set-child-modifiers [parent [layout-line modif-tree] child] (let [[modifiers layout-line] @@ -208,7 +212,8 @@ [objects ignore-constraints [modif-tree autolayouts] parent] (let [parent-id (:id parent) root? (= uuid/zero parent-id) - modifiers (dm/get-in modif-tree [parent-id :modifiers]) + modifiers (-> (dm/get-in modif-tree [parent-id :modifiers]) + (ctm/select-geometry)) transformed-parent (gtr/transform-shape parent modifiers) has-modifiers? (ctm/child-modifiers? modifiers) @@ -233,10 +238,9 @@ (defn- apply-structure-modifiers [objects modif-tree] (letfn [(apply-shape [objects [id {:keys [modifiers]}]] - (if (ctm/has-structure? modifiers) - (let [shape (get objects id)] - (update objects id ctm/apply-structure-modifiers modifiers)) - objects))] + (cond-> objects + (ctm/has-structure? modifiers) + (update id ctm/apply-structure-modifiers modifiers)))] (reduce apply-shape objects modif-tree))) (defn- apply-partial-objects-modifiers diff --git a/common/src/app/common/geom/shapes/transforms.cljc b/common/src/app/common/geom/shapes/transforms.cljc index f2c63f5df..e8c942fd6 100644 --- a/common/src/app/common/geom/shapes/transforms.cljc +++ b/common/src/app/common/geom/shapes/transforms.cljc @@ -10,6 +10,7 @@ [app.common.data.macros :as dm] [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] + [app.common.geom.shapes.bool :as gshb] [app.common.geom.shapes.common :as gco] [app.common.geom.shapes.path :as gpa] [app.common.geom.shapes.rect :as gpr] @@ -408,6 +409,20 @@ (assoc :flip-x (-> mask :flip-x)) (assoc :flip-y (-> mask :flip-y))))) +(defn update-bool-selrect + "Calculates the selrect+points for the boolean shape" + [shape children objects] + + (let [bool-content (gshb/calc-bool-content shape objects) + shape (assoc shape :bool-content bool-content) + [points selrect] (gpa/content->points+selrect shape bool-content)] + + (if (and (some? selrect) (d/not-empty? points)) + (-> shape + (assoc :selrect selrect) + (assoc :points points)) + (update-group-selrect shape children)))) + (defn transform-shape ([shape] (let [modifiers (:modifiers shape)] @@ -513,6 +528,9 @@ (cph/mask-shape? group) (update-mask-selrect group children) + (cph/bool-shape? group) + (transform-shape group modifiers) + (cph/group-shape? group) (update-group-selrect group children) diff --git a/common/src/app/common/pages/changes.cljc b/common/src/app/common/pages/changes.cljc index 9e60acfd0..cee62de19 100644 --- a/common/src/app/common/pages/changes.cljc +++ b/common/src/app/common/pages/changes.cljc @@ -11,7 +11,6 @@ [app.common.data.macros :as dm] [app.common.exceptions :as ex] [app.common.geom.shapes :as gsh] - [app.common.geom.shapes.bool :as gshb] [app.common.math :as mth] [app.common.pages.common :refer [component-sync-attrs]] [app.common.pages.helpers :as cph] @@ -170,7 +169,7 @@ group (= :bool (:type group)) - (gshb/update-bool-selrect group children objects) + (gsh/update-bool-selrect group children objects) (:masked-group? group) (set-mask-selrect group children) diff --git a/common/src/app/common/pages/changes_builder.cljc b/common/src/app/common/pages/changes_builder.cljc index 52eae30f8..77e232f3b 100644 --- a/common/src/app/common/pages/changes_builder.cljc +++ b/common/src/app/common/pages/changes_builder.cljc @@ -12,8 +12,6 @@ [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] - [app.common.geom.shapes.bool :as gshb] - [app.common.geom.shapes.rect :as gshr] [app.common.math :as mth] [app.common.pages :as cp] [app.common.pages.helpers :as cph] @@ -419,7 +417,7 @@ (every? #(apply gpt/close? %) (d/zip old-val new-val)) (= attr :selrect) - (gshr/close-selrect? old-val new-val) + (gsh/close-selrect? old-val new-val) :else (= old-val new-val))] @@ -438,7 +436,7 @@ nil ;; so it does not need resize (= (:type parent) :bool) - (gshb/update-bool-selrect parent children objects) + (gsh/update-bool-selrect parent children objects) (= (:type parent) :group) (if (:masked-group? parent) diff --git a/frontend/src/app/main/data/workspace/modifiers.cljs b/frontend/src/app/main/data/workspace/modifiers.cljs index f76c36d0f..9b3766e59 100644 --- a/frontend/src/app/main/data/workspace/modifiers.cljs +++ b/frontend/src/app/main/data/workspace/modifiers.cljs @@ -150,6 +150,19 @@ child-set (set (get-in objects [target-frame :shapes])) layout? (ctl/layout? objects target-frame) + set-parent-ids + (fn [modif-tree shapes target-frame] + (reduce + (fn [modif-tree id] + (update-in + modif-tree + [id :modifiers] + #(-> % + (ctm/change-property :frame-id target-frame) + (ctm/change-property :parent-id target-frame)))) + modif-tree + shapes)) + update-frame-modifiers (fn [modif-tree [original-frame shapes]] (let [shapes (->> shapes (d/removev #(= target-frame %))) @@ -160,7 +173,8 @@ (cond-> modif-tree (not= original-frame target-frame) (-> (update-in [original-frame :modifiers] ctm/remove-children shapes) - (update-in [target-frame :modifiers] ctm/add-children shapes drop-index)) + (update-in [target-frame :modifiers] ctm/add-children shapes drop-index) + (set-parent-ids shapes target-frame)) (and layout? (= original-frame target-frame)) (update-in [target-frame :modifiers] ctm/add-children shapes drop-index))))]