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