From 6c2d2e142b59653a5bca1e4910c978ec3d56cd55 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 2 Dec 2022 12:17:32 +0100 Subject: [PATCH 1/5] :sparkles: Improve reflow texts --- .../src/app/common/pages/changes_builder.cljc | 15 +++++++ frontend/src/app/main/data/workspace.cljs | 10 +++-- .../src/app/main/data/workspace/groups.cljs | 3 +- .../app/main/data/workspace/modifiers.cljs | 39 ++++++++++-------- .../app/main/data/workspace/path/edition.cljs | 3 +- .../app/main/data/workspace/selection.cljs | 3 +- .../app/main/data/workspace/shape_layout.cljs | 40 ++++++++++++++++--- .../src/app/main/data/workspace/shapes.cljs | 7 ++-- .../data/workspace/shapes_update_layout.cljs | 24 ----------- .../src/app/main/data/workspace/texts.cljs | 4 +- .../shapes/text/viewport_texts_html.cljs | 5 ++- frontend/src/debug.cljs | 4 ++ 12 files changed, 95 insertions(+), 62 deletions(-) delete mode 100644 frontend/src/app/main/data/workspace/shapes_update_layout.cljs diff --git a/common/src/app/common/pages/changes_builder.cljc b/common/src/app/common/pages/changes_builder.cljc index 77e232f3bd..8375fc4513 100644 --- a/common/src/app/common/pages/changes_builder.cljc +++ b/common/src/app/common/pages/changes_builder.cljc @@ -276,6 +276,21 @@ (update :undo-changes #(reduce mk-undo-change % shapes)) (apply-changes-local))))) + +(defn changed-attrs + [object update-fn {:keys [attrs]}] + (let [changed? + (fn [old new attr] + (let [old-val (get old attr) + new-val (get new attr)] + (not= old-val new-val)))] + (let [new-obj (update-fn object)] + (if (= object new-obj) + '() + + (let [attrs (or attrs (d/concat-set (keys object) (keys new-obj)))] + (filter (partial changed? object new-obj) attrs)))))) + (defn update-shapes "Calculate the changes and undos to be done when a function is applied to a single object" diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index af4f881608..a14b0454d6 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -56,7 +56,7 @@ [app.main.data.workspace.persistence :as dwp] [app.main.data.workspace.selection :as dws] [app.main.data.workspace.shapes :as dwsh] - [app.main.data.workspace.shapes-update-layout :as dwul] + [app.main.data.workspace.shape-layout :as dwsl] [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.thumbnails :as dwth] [app.main.data.workspace.transforms :as dwt] @@ -177,6 +177,7 @@ (->> (rx/merge ;; Initialize notifications & load team fonts (rx/of (dwn/initialize team-id id) + (dwsl/initialize) (df/load-team-fonts team-id)) ;; Load all pages, independently if they are pointers or already @@ -316,7 +317,8 @@ ptk/WatchEvent (watch [_ _ _] - (rx/of (dwn/finalize file-id))))) + (rx/of (dwn/finalize file-id) + (dwsl/finalize))))) (declare go-to-page) (declare ^:private preload-data-uris) @@ -808,7 +810,7 @@ (rx/of (dch/commit-changes changes) (dwco/expand-collapse parent-id) - (dwul/update-layout-positions layouts-to-update)))))) + (ptk/data-event :layout/update layouts-to-update)))))) (defn relocate-selected-shapes [parent-id to-index] @@ -1554,7 +1556,7 @@ (rx/of (dch/commit-changes changes) (dws/select-shapes selected) - (dwul/update-layout-positions [frame-id]))))] + (ptk/data-event :layout/update [frame-id]))))] (ptk/reify ::paste-shape ptk/WatchEvent diff --git a/frontend/src/app/main/data/workspace/groups.cljs b/frontend/src/app/main/data/workspace/groups.cljs index 4a5fad453b..e009b6f26e 100644 --- a/frontend/src/app/main/data/workspace/groups.cljs +++ b/frontend/src/app/main/data/workspace/groups.cljs @@ -14,7 +14,6 @@ [app.common.types.shape-tree :as ctt] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.selection :as dws] - [app.main.data.workspace.shapes-update-layout :as dwul] [app.main.data.workspace.state-helpers :as wsh] [beicon.core :as rx] [potok.core :as ptk])) @@ -190,7 +189,7 @@ :origin it}] (rx/of (dch/commit-changes changes) - (dwul/update-layout-positions parents)))))) + (ptk/data-event :layout/update parents)))))) (def mask-group (ptk/reify ::mask-group diff --git a/frontend/src/app/main/data/workspace/modifiers.cljs b/frontend/src/app/main/data/workspace/modifiers.cljs index f6de2ab145..808798457c 100644 --- a/frontend/src/app/main/data/workspace/modifiers.cljs +++ b/frontend/src/app/main/data/workspace/modifiers.cljs @@ -113,7 +113,7 @@ (reduce set-child ignore-tree children)))) -(defn- update-grow-type +(defn update-grow-type [shape old-shape] (let [auto-width? (= :auto-width (:grow-type shape)) auto-height? (= :auto-height (:grow-type shape)) @@ -226,6 +226,22 @@ (recur (rest modifiers) (update objects id apply-path-modifier path-modifier))))))) +(defn- calculate-modifiers + ([state modif-tree] + (calculate-modifiers state false false modif-tree)) + + ([state ignore-constraints ignore-snap-pixel modif-tree] + (let [objects + (wsh/lookup-page-objects state) + + snap-pixel? + (and (not ignore-snap-pixel) (contains? (:workspace-layout state) :snap-pixel-grid))] + + (as-> objects $ + (apply-text-modifiers $ (get state :workspace-text-modifier)) + ;;(apply-path-modifiers $ (get-in state [:workspace-local :edit-path])) + (gsh/set-objects-modifiers modif-tree $ ignore-constraints snap-pixel?))))) + (defn set-modifiers ([modif-tree] (set-modifiers modif-tree false)) @@ -237,19 +253,7 @@ (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 - (as-> objects $ - (apply-text-modifiers $ (get state :workspace-text-modifier)) - ;;(apply-path-modifiers $ (get-in state [:workspace-local :edit-path])) - (gsh/set-objects-modifiers modif-tree $ ignore-constraints snap-pixel?))] - - (assoc state :workspace-modifiers modif-tree)))))) + (assoc state :workspace-modifiers (calculate-modifiers state ignore-constraints ignore-snap-pixel modif-tree)))))) ;; Rotation use different algorithm to calculate children modifiers (and do not use child constraints). (defn set-rotation-modifiers @@ -282,12 +286,14 @@ ([] (apply-modifiers nil)) - ([{:keys [undo-transation?] :or {undo-transation? true}}] + ([{:keys [undo-transation? modifiers] :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) + object-modifiers (if modifiers + (calculate-modifiers state modifiers) + (get state :workspace-modifiers)) ids (or (keys object-modifiers) []) ids-with-children (into (vec ids) (mapcat #(cph/get-children-ids objects %)) ids) @@ -326,7 +332,6 @@ :transform :transform-inverse :rotation - :position-data :flip-x :flip-y :grow-type diff --git a/frontend/src/app/main/data/workspace/path/edition.cljs b/frontend/src/app/main/data/workspace/path/edition.cljs index a5b4a30a5b..a112da6575 100644 --- a/frontend/src/app/main/data/workspace/path/edition.cljs +++ b/frontend/src/app/main/data/workspace/path/edition.cljs @@ -21,7 +21,6 @@ [app.main.data.workspace.path.state :as st] [app.main.data.workspace.path.streams :as streams] [app.main.data.workspace.path.undo :as undo] - [app.main.data.workspace.shapes-update-layout :as dwul] [app.main.data.workspace.state-helpers :as wsh] [app.main.streams :as ms] [app.util.path.tools :as upt] @@ -316,7 +315,7 @@ ptk/WatchEvent (watch [_ _ _] - (rx/of (dwul/update-layout-positions [id]))))) + (rx/of (ptk/data-event :layout/update [id]))))) (defn split-segments [{:keys [from-p to-p t]}] diff --git a/frontend/src/app/main/data/workspace/selection.cljs b/frontend/src/app/main/data/workspace/selection.cljs index 8791777c11..3ef4a4bf6c 100644 --- a/frontend/src/app/main/data/workspace/selection.cljs +++ b/frontend/src/app/main/data/workspace/selection.cljs @@ -21,7 +21,6 @@ [app.main.data.modal :as md] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.collapse :as dwc] - [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 +564,7 @@ ;; Warning: This order is important for the focus mode. (rx/of (dch/commit-changes changes) (select-shapes new-selected) - (dwul/update-layout-positions frames) + (ptk/data-event :layout/update 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 3e14d82279..8f1b69a9b9 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -9,13 +9,14 @@ [app.common.colors :as clr] [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.colors :as cl] + [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] [app.main.data.workspace.undo :as dwu] [beicon.core :as rx] @@ -64,9 +65,38 @@ (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)) - (wsul/update-layout-positions ids) + (ptk/data-event :layout/update ids) (dwc/update-shapes children-ids #(dissoc % :constraints-h :constraints-v))))))) + +;; Never call this directly but through the data-event `:layout/update` +;; Otherwise a lot of cycle dependencies could be generated +(defn- update-layout-positions + [ids] + (ptk/reify ::update-layout-positions + ptk/WatchEvent + (watch [_ _ _] + (if (d/not-empty? ids) + (let [modif-tree (dwm/create-modif-tree ids (ctm/reflow-modifiers))] + (rx/of (dwm/apply-modifiers {:modifiers modif-tree}))) + (rx/empty))))) + +(defn initialize + [] + (ptk/reify ::initialize + ptk/WatchEvent + (watch [_ _ stream] + (let [stopper (rx/filter (ptk/type? ::finalize) stream)] + (->> stream + (rx/filter (ptk/type? :layout/update)) + (rx/map deref) + (rx/map #(update-layout-positions %)) + (rx/take-until stopper)))))) + +(defn finalize + [] + (ptk/reify ::finalize)) + (defn create-layout-from-selection [type] (ptk/reify ::create-layout-from-selection @@ -115,7 +145,7 @@ (rx/of (dwu/start-undo-transaction undo-id) (dwc/update-shapes ids #(apply dissoc % layout-keys)) - (wsul/update-layout-positions ids) + (ptk/data-event :layout/update ids) (dwu/commit-undo-transaction undo-id)))))) (defn create-layout @@ -163,7 +193,7 @@ ptk/WatchEvent (watch [_ _ _] (rx/of (dwc/update-shapes ids #(d/deep-merge % changes)) - (wsul/update-layout-positions ids))))) + (ptk/data-event :layout/update ids))))) (defn update-layout-child [ids changes] @@ -174,4 +204,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)) - (wsul/update-layout-positions (d/concat-vec layout-ids parent-ids))))))) + (ptk/data-event :layout/update (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 9fde82d4be..95adb579a0 100644 --- a/frontend/src/app/main/data/workspace/shapes.cljs +++ b/frontend/src/app/main/data/workspace/shapes.cljs @@ -24,7 +24,6 @@ [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.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] @@ -105,7 +104,7 @@ (rx/concat (rx/of (dch/commit-changes changes) - (dwsul/update-layout-positions [(:parent-id shape)]) + (ptk/data-event :layout/update [(:parent-id shape)]) (when-not no-select? (dws/select-shapes (d/ordered-set id)))) (when (= :text (:type attrs)) @@ -310,9 +309,9 @@ (reduce ctp/remove-flow flows))))))] (rx/of (dc/detach-comment-thread ids) - (dwsul/update-layout-positions all-parents) + (ptk/data-event :layout/update all-parents) (dch/commit-changes changes) - (dwsul/update-layout-positions layout-ids)))) + (ptk/data-event :layout/update layout-ids)))) (defn create-and-add-shape [type frame-x frame-y data] diff --git a/frontend/src/app/main/data/workspace/shapes_update_layout.cljs b/frontend/src/app/main/data/workspace/shapes_update_layout.cljs deleted file mode 100644 index 710fd10c69..0000000000 --- a/frontend/src/app/main/data/workspace/shapes_update_layout.cljs +++ /dev/null @@ -1,24 +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) KALEIDOS INC - -(ns app.main.data.workspace.shapes-update-layout - (:require - [app.common.data :as d] - [app.common.types.modifiers :as ctm] - [app.main.data.workspace.modifiers :as dwm] - [beicon.core :as rx] - [potok.core :as ptk])) - -(defn update-layout-positions - [ids] - (ptk/reify ::update-layout-positions - ptk/WatchEvent - (watch [_ _ _] - (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/texts.cljs b/frontend/src/app/main/data/workspace/texts.cljs index 77b44c2962..d5bde20916 100644 --- a/frontend/src/app/main/data/workspace/texts.cljs +++ b/frontend/src/app/main/data/workspace/texts.cljs @@ -343,7 +343,9 @@ (when (or (and (not-changed? (:width shape) new-width) (= (:grow-type shape) :auto-width)) (and (not-changed? (:height shape) new-height) (or (= (:grow-type shape) :auto-height) (= (:grow-type shape) :auto-width)))) - (rx/of (dch/update-shapes [id] update-fn {:reg-objects? true :save-undo? false})))))))) + (rx/of (dch/update-shapes [id] update-fn {:reg-objects? true :save-undo? false}) + (ptk/data-event :layout/update [id])))))))) + (defn save-font [data] 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 405b3f1b06..b32b3dc06e 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 @@ -15,6 +15,7 @@ [app.common.pages.helpers :as cph] [app.common.text :as txt] [app.common.types.modifiers :as ctm] + [app.main.data.workspace.modifiers :as mdwm] [app.main.data.workspace.texts :as dwt] [app.main.fonts :as fonts] [app.main.refs :as refs] @@ -40,7 +41,9 @@ ;; We need to remove the movement because the dynamic modifiers will have move it deltav (gpt/to-vec (gpt/point (:selrect shape')) (gpt/point (:selrect shape)))] - (gsh/transform-shape shape (ctm/move modifier deltav)))) + (-> shape + (gsh/transform-shape (ctm/move modifier deltav)) + (mdwm/update-grow-type shape)))) (defn process-shape [modifiers {:keys [id] :as shape}] (let [modifier (dm/get-in modifiers [id :modifiers])] diff --git a/frontend/src/debug.cljs b/frontend/src/debug.cljs index f0b61abd76..cfb8b1c40a 100644 --- a/frontend/src/debug.cljs +++ b/frontend/src/debug.cljs @@ -91,6 +91,10 @@ ;; These events are excluded when we activate the :events flag (def debug-exclude-events #{:app.main.data.workspace.notifications/handle-pointer-update + :app.main.data.workspace.notifications/handle-pointer-send + :app.main.data.workspace.persistence/update-persistence-status + :app.main.data.workspace.changes/update-indices + :app.main.data.websocket/send-message :app.main.data.workspace.selection/change-hover-state}) (defonce ^:dynamic *debug* (atom #{#_:events})) From 7dbe39b1b53e0001b2b70e94a9b12cb05be2ce68 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Mon, 5 Dec 2022 13:21:06 +0100 Subject: [PATCH 2/5] :bug: Fix problems with cache and thumbnails --- .../app/common/geom/shapes/constraints.cljc | 17 +++++++++-- .../src/app/common/pages/changes_builder.cljc | 12 ++++---- frontend/src/app/main/data/workspace.cljs | 2 +- frontend/src/app/util/cache.cljs | 29 +++++++++++-------- 4 files changed, 39 insertions(+), 21 deletions(-) diff --git a/common/src/app/common/geom/shapes/constraints.cljc b/common/src/app/common/geom/shapes/constraints.cljc index 6275e673fb..bd158ccd54 100644 --- a/common/src/app/common/geom/shapes/constraints.cljc +++ b/common/src/app/common/geom/shapes/constraints.cljc @@ -13,6 +13,7 @@ [app.common.geom.shapes.transforms :as gtr] [app.common.math :as mth] [app.common.types.modifiers :as ctm] + [app.common.types.shape.layout :as ctl] [app.common.uuid :as uuid])) ;; Auxiliary methods to work in an specifica axis @@ -285,13 +286,25 @@ (let [modifiers (ctm/select-child modifiers) constraints-h - (if-not ignore-constraints + (cond + (ctl/layout? parent) + :left + + (not ignore-constraints) (:constraints-h child (default-constraints-h child)) + + :else :scale) constraints-v - (if-not ignore-constraints + (cond + (ctl/layout? parent) + :top + + (not ignore-constraints) (:constraints-v child (default-constraints-v child)) + + :else :scale)] (if (and (= :scale constraints-h) (= :scale constraints-v)) diff --git a/common/src/app/common/pages/changes_builder.cljc b/common/src/app/common/pages/changes_builder.cljc index 8375fc4513..e27b7f3a3a 100644 --- a/common/src/app/common/pages/changes_builder.cljc +++ b/common/src/app/common/pages/changes_builder.cljc @@ -283,13 +283,13 @@ (fn [old new attr] (let [old-val (get old attr) new-val (get new attr)] - (not= old-val new-val)))] - (let [new-obj (update-fn object)] - (if (= object new-obj) - '() + (not= old-val new-val))) + new-obj (update-fn object)] + (if (= object new-obj) + '() - (let [attrs (or attrs (d/concat-set (keys object) (keys new-obj)))] - (filter (partial changed? object new-obj) attrs)))))) + (let [attrs (or attrs (d/concat-set (keys object) (keys new-obj)))] + (filter (partial changed? object new-obj) attrs))))) (defn update-shapes "Calculate the changes and undos to be done when a function is applied to a diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index a14b0454d6..74d1e1c1a6 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -55,8 +55,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.shapes :as dwsh] [app.main.data.workspace.shape-layout :as dwsl] + [app.main.data.workspace.shapes :as dwsh] [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.thumbnails :as dwth] [app.main.data.workspace.transforms :as dwt] diff --git a/frontend/src/app/util/cache.cljs b/frontend/src/app/util/cache.cljs index 90c675bb05..fcb54c9174 100644 --- a/frontend/src/app/util/cache.cljs +++ b/frontend/src/app/util/cache.cljs @@ -29,15 +29,20 @@ :else (let [subject (rx/subject)] - (swap! pending assoc key subject) - (->> observable - (rx/catch #(do (rx/error! subject %) - (swap! pending dissoc key) - (rx/throw %))) - (rx/tap - (fn [data] - (let [entry {:created-at (dt/now) :data data}] - (swap! cache assoc key entry)) - (rx/push! subject data) - (rx/end! subject) - (swap! pending dissoc key)))))))) + (do + (swap! pending assoc key subject) + + (rx/subscribe + observable + + (fn [data] + (let [entry {:created-at (dt/now) :data data}] + (swap! cache assoc key entry)) + (swap! pending dissoc key) + (rx/push! subject data) + (rx/end! subject)) + + #(do + (swap! pending dissoc key) + (rx/error! subject %)))) + subject)))) From 4b55c7a8e0dec5e1e44f933e681742e74afb10f2 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Wed, 7 Dec 2022 07:52:58 +0100 Subject: [PATCH 3/5] :bug: Fix problem with text not growing the hug container --- .../src/app/common/geom/shapes/modifiers.cljc | 4 +- common/src/app/common/types/modifiers.cljc | 156 ++++++++++++------ .../src/app/main/data/workspace/texts.cljs | 36 ++-- 3 files changed, 129 insertions(+), 67 deletions(-) diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index b4fa223bd3..5470730d7b 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -121,7 +121,7 @@ (update-in [child-id :modifiers] ctm/add-modifiers child-modifiers)) (rest children))))))))) -(defn- process-layout-children +#_(defn- process-layout-children [modif-tree objects bounds parent transformed-parent-bounds] (letfn [(process-child [modif-tree child] (let [child-id (:id child) @@ -275,7 +275,7 @@ (set-children-modifiers objects bounds parent transformed-parent-bounds ignore-constraints) layout? - (-> (process-layout-children objects bounds parent transformed-parent-bounds) + (-> #_(process-layout-children objects bounds parent transformed-parent-bounds) (set-layout-modifiers objects bounds parent transformed-parent-bounds))) ;; Auto-width/height can change the positions in the parent so we need to recalculate diff --git a/common/src/app/common/types/modifiers.cljc b/common/src/app/common/types/modifiers.cljc index 22a428b262..ece78a0e59 100644 --- a/common/src/app/common/types/modifiers.cljc +++ b/common/src/app/common/types/modifiers.cljc @@ -40,13 +40,15 @@ ;; * change-properties (defrecord Modifiers - [geometry-parent + [last-order ;; Last `order` attribute in the geometry list + geometry-parent geometry-child structure-parent structure-child]) (defrecord GeometricOperation - [type + [order ;; Need the order to keep consistent between geometry-parent and geometry-child + type vector origin transform @@ -62,41 +64,42 @@ ;; Record constructors -(defn move-op - [vector] - (GeometricOperation. :move vector nil nil nil nil nil)) +(defn- move-op + [order vector] + (GeometricOperation. order :move vector nil nil nil nil nil)) -(defn resize-op - ([vector origin] - (GeometricOperation. :resize vector origin nil nil nil nil)) - ([vector origin transform transform-inverse] - (GeometricOperation. :resize vector origin transform transform-inverse nil nil))) +(defn- resize-op + ([order vector origin] + (GeometricOperation. order :resize vector origin nil nil nil nil)) -(defn rotation-geom-op - [center angle] - (GeometricOperation. :rotation nil nil nil nil angle center)) + ([order vector origin transform transform-inverse] + (GeometricOperation. order :resize vector origin transform transform-inverse nil nil))) -(defn rotation-struct-op +(defn- rotation-geom-op + [order center angle] + (GeometricOperation. order :rotation nil nil nil nil angle center)) + +(defn- rotation-struct-op [angle] (StructureOperation. :rotation nil angle nil)) -(defn remove-children-op +(defn- remove-children-op [shapes] (StructureOperation. :remove-children nil shapes nil)) -(defn add-children-op +(defn- add-children-op [shapes index] (StructureOperation. :add-children nil shapes index)) -(defn reflow-op +(defn- reflow-op [] (StructureOperation. :reflow nil nil nil)) -(defn scale-content-op +(defn- scale-content-op [value] (StructureOperation. :scale-content nil value nil)) -(defn change-property-op +(defn- change-property-op [property value] (StructureOperation. :change-property property value nil)) @@ -142,8 +145,9 @@ (defn- merge-move [op1 op2] (let [vector-op1 (dm/get-prop op1 :vector) - vector-op2 (dm/get-prop op2 :vector)] - (move-op (gpt/add vector-op1 vector-op2)))) + vector-op2 (dm/get-prop op2 :vector) + vector (gpt/add vector-op1 vector-op2)] + (assoc op1 :vector vector))) (defn- merge-resize [op1 op2] @@ -197,7 +201,7 @@ ;; Public builder API (defn empty [] - (Modifiers. [] [] [] [])) + (Modifiers. 0 [] [] [] [])) (defn move-parent ([modifiers x y] @@ -205,22 +209,31 @@ ([modifiers vector] (assert (valid-vector? vector) (dm/str "Invalid move vector: " (:x vector) "," (:y vector))) - (cond-> (or modifiers (empty)) - (move-vec? vector) - (update :geometry-parent maybe-add-move (move-op vector))))) + (let [modifiers (or modifiers (empty)) + order (inc (dm/get-prop modifiers :last-order)) + modifiers (assoc modifiers :last-order order)] + (cond-> modifiers + (move-vec? vector) + (update :geometry-parent maybe-add-move (move-op order vector)))))) (defn resize-parent ([modifiers vector origin] (assert (valid-vector? vector) (dm/str "Invalid move vector: " (:x vector) "," (:y vector))) - (cond-> (or modifiers (empty)) - (resize-vec? vector) - (update :geometry-parent maybe-add-resize (resize-op vector origin)))) + (let [modifiers (or modifiers (empty)) + order (inc (dm/get-prop modifiers :last-order)) + modifiers (assoc modifiers :last-order order)] + (cond-> modifiers + (resize-vec? vector) + (update :geometry-parent maybe-add-resize (resize-op order vector origin))))) ([modifiers vector origin transform transform-inverse] (assert (valid-vector? vector) (dm/str "Invalid move vector: " (:x vector) "," (:y vector))) - (cond-> (or modifiers (empty)) - (resize-vec? vector) - (update :geometry-parent maybe-add-resize (resize-op vector origin transform transform-inverse))))) + (let [modifiers (or modifiers (empty)) + order (inc (dm/get-prop modifiers :last-order)) + modifiers (assoc modifiers :last-order order)] + (cond-> modifiers + (resize-vec? vector) + (update :geometry-parent maybe-add-resize (resize-op order vector origin transform transform-inverse)))))) (defn move ([modifiers x y] @@ -228,29 +241,41 @@ ([modifiers vector] (assert (valid-vector? vector) (dm/str "Invalid move vector: " (:x vector) "," (:y vector))) - (cond-> (or modifiers (empty)) - (move-vec? vector) - (update :geometry-child maybe-add-move (move-op vector))))) + (let [modifiers (or modifiers (empty)) + order (inc (dm/get-prop modifiers :last-order)) + modifiers (assoc modifiers :last-order order)] + (cond-> modifiers + (move-vec? vector) + (update :geometry-child maybe-add-move (move-op order vector)))))) (defn resize ([modifiers vector origin] (assert (valid-vector? vector) (dm/str "Invalid move vector: " (:x vector) "," (:y vector))) - (cond-> (or modifiers (empty)) - (resize-vec? vector) - (update :geometry-child maybe-add-resize (resize-op vector origin)))) + (let [modifiers (or modifiers (empty)) + order (inc (dm/get-prop modifiers :last-order)) + modifiers (assoc modifiers :last-order order)] + (cond-> modifiers + (resize-vec? vector) + (update :geometry-child maybe-add-resize (resize-op order vector origin))))) ([modifiers vector origin transform transform-inverse] (assert (valid-vector? vector) (dm/str "Invalid move vector: " (:x vector) "," (:y vector))) - (cond-> (or modifiers (empty)) - (resize-vec? vector) - (update :geometry-child maybe-add-resize (resize-op vector origin transform transform-inverse))))) + (let [modifiers (or modifiers (empty)) + order (inc (dm/get-prop modifiers :last-order)) + modifiers (assoc modifiers :last-order order)] + (cond-> modifiers + (resize-vec? vector) + (update :geometry-child maybe-add-resize (resize-op order vector origin transform transform-inverse)))))) (defn rotation [modifiers center angle] - (cond-> (or modifiers (empty)) - (not (mth/close? angle 0)) - (-> (update :structure-child conj (rotation-struct-op angle)) - (update :geometry-child conj (rotation-geom-op center angle))))) + (let [modifiers (or modifiers (empty)) + order (inc (dm/get-prop modifiers :last-order)) + modifiers (assoc modifiers :last-order order)] + (cond-> modifiers + (not (mth/close? angle 0)) + (-> (update :structure-child conj (rotation-struct-op angle)) + (update :geometry-child conj (rotation-geom-op order center angle)))))) (defn remove-children [modifiers shapes] @@ -279,8 +304,8 @@ (-> (or modifiers (empty)) (update :structure-child conj (change-property-op property value)))) -(defn- merge-geometry - [operations other] +(defn- concat-geometry + [operations other merge?] (cond (c/empty? operations) @@ -297,10 +322,10 @@ (let [current (first operations) result (cond - (= :move (dm/get-prop current :type)) + (and merge? (= :move (dm/get-prop current :type))) (maybe-add-move result current) - (= :resize (dm/get-prop current :type)) + (and merge? (= :resize (dm/get-prop current :type))) (maybe-add-resize result current) :else @@ -308,15 +333,37 @@ (recur result (rest operations))))))) +(defn increase-order + [operations last-order] + (->> operations + (mapv #(update % :order + last-order)))) + (defn add-modifiers [modifiers new-modifiers] + (let [modifiers (or modifiers (empty)) - new-modifiers (or new-modifiers (empty))] + new-modifiers (or new-modifiers (empty)) + last-order (dm/get-prop modifiers :last-order) + new-last-order (dm/get-prop new-modifiers :last-order) + + + old-geom-child (dm/get-prop modifiers :geometry-child) + new-geom-child (-> (dm/get-prop new-modifiers :geometry-child) + (increase-order last-order)) + + old-geom-parent (dm/get-prop modifiers :geometry-parent) + new-geom-parent (-> (dm/get-prop new-modifiers :geometry-parent) + (increase-order last-order)) + + ;; We can only merge if the result will respect the global order in modifiers + merge-child? (and (c/empty? new-geom-parent) (c/empty? old-geom-parent)) + merge-parent? (and (c/empty? new-geom-child) (c/empty? old-geom-child))] (-> modifiers - (update :geometry-child merge-geometry (dm/get-prop new-modifiers :geometry-child)) - (update :geometry-parent merge-geometry (dm/get-prop new-modifiers :geometry-parent)) + (assoc :last-order (+ last-order new-last-order)) + (update :geometry-child #(concat-geometry % new-geom-child merge-child?)) + (update :geometry-parent #(concat-geometry % new-geom-parent merge-parent?)) (update :structure-parent #(d/concat-vec [] % (dm/get-prop new-modifiers :structure-parent))) - (update :structure-child #(d/concat-vec [] % (dm/get-prop new-modifiers :structure-child)))))) + (update :structure-child #(d/concat-vec [] % (dm/get-prop new-modifiers :structure-child)))))) ;; These are convenience methods to create single operation modifiers without the builder @@ -522,8 +569,9 @@ (defn modifiers->transform "Given a set of modifiers returns its transformation matrix" [modifiers] - (let [modifiers (concat (dm/get-prop modifiers :geometry-parent) - (dm/get-prop modifiers :geometry-child))] + (let [modifiers (->> (concat (dm/get-prop modifiers :geometry-parent) + (dm/get-prop modifiers :geometry-child)) + (sort-by :order))] (loop [matrix (gmt/matrix) modifiers (seq modifiers)] diff --git a/frontend/src/app/main/data/workspace/texts.cljs b/frontend/src/app/main/data/workspace/texts.cljs index d5bde20916..f24868f55b 100644 --- a/frontend/src/app/main/data/workspace/texts.cljs +++ b/frontend/src/app/main/data/workspace/texts.cljs @@ -8,6 +8,7 @@ (:require [app.common.attrs :as attrs] [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.math :as mth] @@ -380,23 +381,36 @@ new-shape)) +(defn update-text-modifier-state + [id props] + (ptk/reify ::update-text-modifier-state + ptk/UpdateEvent + (update [_ state] + (update-in state [:workspace-text-modifier id] (fnil merge {}) props)))) + (defn update-text-modifier [id props] (ptk/reify ::update-text-modifier - ptk/UpdateEvent - (update [_ state] - (update-in state [:workspace-text-modifier id] (fnil merge {}) props)) - ptk/WatchEvent (watch [_ state _] - (let [shape (wsh/lookup-shape state id)] - (when (or (and (some? (:width props)) - (not (mth/close? (:width props) (:width shape)))) - (and (some? (:height props)) - (not (mth/close? (:height props) (:height shape))))) + (let [shape (wsh/lookup-shape state id) - (let [modif-tree (dwm/create-modif-tree [id] (ctm/reflow-modifiers))] - (rx/of (dwm/set-modifiers modif-tree)))))))) + text-modifier (dm/get-in state [:workspace-text-modifier id]) + + current-width (or (:width text-modifier) (:width shape)) + current-height (or (:height text-modifier) (:height shape))] + (rx/concat + (rx/of (update-text-modifier-state id props)) + + (if (or (and (some? (:width props)) + (not (mth/close? (:width props) current-width))) + (and (some? (:height props)) + (not (mth/close? (:height props) current-height)))) + + (let [modif-tree (dwm/create-modif-tree [id] (ctm/reflow-modifiers))] + (->> (rx/of (dwm/set-modifiers modif-tree)) + (rx/observe-on :async))) + (rx/empty))))))) (defn clean-text-modifier [id] From 172f4c142b439ceaaf72b9a12db3bc6f9d94bba4 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Wed, 7 Dec 2022 10:36:35 +0100 Subject: [PATCH 4/5] :sparkles: Remove unused functions --- .../app/common/geom/shapes/flex_layout.cljc | 2 +- .../geom/shapes/flex_layout/modifiers.cljc | 29 ------------------- .../src/app/common/geom/shapes/modifiers.cljc | 20 +------------ 3 files changed, 2 insertions(+), 49 deletions(-) diff --git a/common/src/app/common/geom/shapes/flex_layout.cljc b/common/src/app/common/geom/shapes/flex_layout.cljc index 9379752468..9119d8dab0 100644 --- a/common/src/app/common/geom/shapes/flex_layout.cljc +++ b/common/src/app/common/geom/shapes/flex_layout.cljc @@ -18,4 +18,4 @@ (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/modifiers.cljc b/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc index 481d27390f..29eea82f0d 100644 --- a/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc @@ -6,41 +6,12 @@ (ns app.common.geom.shapes.flex-layout.modifiers (:require - [app.common.geom.matrix :as gmt] [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 gtr] [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" - [modifiers {:keys [transform transform-inverse] :as parent} child-bounds parent-bounds transformed-parent-bounds] - - (let [transformed-child-bounds (gtr/transform-bounds child-bounds modifiers) - - child-bb-before (gpo/parent-coords-bounds child-bounds parent-bounds) - child-bb-after (gpo/parent-coords-bounds transformed-child-bounds transformed-parent-bounds) - - scale-x (/ (gpo/width-points child-bb-before) (gpo/width-points child-bb-after)) - scale-y (/ (gpo/height-points child-bb-before) (gpo/height-points child-bb-after)) - - resize-vector (gpt/point scale-x scale-y) - modif-transform (or (ctm/modifiers->transform modifiers) (gmt/matrix)) - modif-transform-inverse (gmt/inverse modif-transform) - resize-transform (gmt/multiply modif-transform transform) - resize-transform-inverse (gmt/multiply transform-inverse modif-transform-inverse) - resize-origin (gpo/origin transformed-child-bounds)] - - (-> modifiers - (ctm/select-child) - (ctm/resize - resize-vector - resize-origin - resize-transform - resize-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} diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index 5470730d7b..887681e756 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -121,23 +121,6 @@ (update-in [child-id :modifiers] ctm/add-modifiers child-modifiers)) (rest children))))))))) -#_(defn- process-layout-children - [modif-tree objects bounds parent transformed-parent-bounds] - (letfn [(process-child [modif-tree child] - (let [child-id (:id child) - parent-id (:id parent) - modifiers (dm/get-in modif-tree [parent-id :modifiers]) - child-bounds @(get bounds child-id) - parent-bounds @(get bounds parent-id) - child-modifiers (-> modifiers - (ctm/select-child-geometry-modifiers) - (gcl/normalize-child-modifiers parent child-bounds parent-bounds @transformed-parent-bounds))] - (cond-> modif-tree - (not (ctm/empty? child-modifiers)) - (update-in [child-id :modifiers] ctm/add-modifiers child-modifiers))))] - (let [children (map (d/getf objects) (:shapes parent))] - (reduce process-child modif-tree children)))) - (defn get-group-bounds [objects bounds modif-tree shape] (let [shape-id (:id shape) @@ -275,8 +258,7 @@ (set-children-modifiers objects bounds parent transformed-parent-bounds ignore-constraints) layout? - (-> #_(process-layout-children objects bounds parent transformed-parent-bounds) - (set-layout-modifiers objects bounds parent transformed-parent-bounds))) + (set-layout-modifiers objects bounds parent transformed-parent-bounds)) ;; Auto-width/height can change the positions in the parent so we need to recalculate (cond-> autolayouts auto? (conj (:id parent)))])) From a64d92b005765e4ed00b1f05e48f436913175014 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Wed, 7 Dec 2022 15:05:29 +0100 Subject: [PATCH 5/5] :sparkles: Change default parameters on selection to layout --- .../src/app/common/pages/changes_builder.cljc | 5 +- .../app/main/data/workspace/shape_layout.cljs | 62 ++++++++++++++++++- 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/common/src/app/common/pages/changes_builder.cljc b/common/src/app/common/pages/changes_builder.cljc index e27b7f3a3a..bb669eeb1b 100644 --- a/common/src/app/common/pages/changes_builder.cljc +++ b/common/src/app/common/pages/changes_builder.cljc @@ -278,6 +278,7 @@ (defn changed-attrs + "Returns the list of attributes that will change when `update-fn` is applied" [object update-fn {:keys [attrs]}] (let [changed? (fn [old new attr] @@ -285,9 +286,7 @@ new-val (get new attr)] (not= old-val new-val))) new-obj (update-fn object)] - (if (= object new-obj) - '() - + (when-not (= object new-obj) (let [attrs (or attrs (d/concat-set (keys object) (keys new-obj)))] (filter (partial changed? object new-obj) attrs))))) diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index 8f1b69a9b9..b0eb038125 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -8,8 +8,12 @@ (:require [app.common.colors :as clr] [app.common.data :as d] + [app.common.geom.point :as gpt] + [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-tree :as ctt] [app.common.types.shape.layout :as ctl] [app.common.uuid :as uuid] [app.main.data.workspace.changes :as dwc] @@ -38,7 +42,7 @@ (def initial-flex-layout {:layout :flex :layout-flex-dir :row - :layout-gap-type :simple + :layout-gap-type :multiple :layout-gap {:row-gap 0 :column-gap 0} :layout-align-items :start :layout-justify-content :start @@ -97,6 +101,41 @@ [] (ptk/reify ::finalize)) +(defn shapes->flex-params + "Given the shapes calculate its flex parameters (horizontal vs vertical etc)" + [objects shapes] + + (let [points + (->> shapes + (map :id) + (ctt/sort-z-index objects) + (map (comp gsh/center-shape (d/getf objects)))) + + start (first points) + end (reduce (fn [acc p] (gpt/add acc (gpt/to-vec start p))) points) + + angle (gpt/signed-angle-with-other + (gpt/to-vec start end) + (gpt/point 1 0)) + + angle (mod angle 360) + + t1 (min (abs (- angle 0)) (abs (- angle 360))) + t2 (abs (- angle 90)) + t3 (abs (- angle 180)) + t4 (abs (- angle 270)) + + tmin (min t1 t2 t3 t4) + + direction + (cond + (mth/close? tmin t1) :row + (mth/close? tmin t2) :reverse-column + (mth/close? tmin t3) :reverse-row + (mth/close? tmin t4) :column)] + + {:layout-flex-dir direction})) + (defn create-layout-from-selection [type] (ptk/reify ::create-layout-from-selection @@ -110,6 +149,7 @@ single? (= (count selected-shapes) 1) has-group? (->> selected-shapes (d/seek cph/group-shape?)) is-group? (and single? has-group?)] + (if is-group? (let [new-shape-id (uuid/next) parent-id (:parent-id (first selected-shapes)) @@ -123,17 +163,35 @@ (cl/remove-all-fills [new-shape-id] {:color clr/black :opacity 1}) (create-layout-from-id [new-shape-id] type) + (dwc/update-shapes + [new-shape-id] + (fn [shape] + (-> shape + (assoc :layout-item-h-sizing :auto + :layout-item-v-sizing :auto)))) + + (ptk/data-event :layout/update [new-shape-id]) (dws/delete-shapes page-id selected) (dwu/commit-undo-transaction undo-id))) (let [new-shape-id (uuid/next) - undo-id (uuid/next)] + undo-id (uuid/next) + flex-params (shapes->flex-params objects selected-shapes)] (rx/of (dwu/start-undo-transaction undo-id) (dws/create-artboard-from-selection new-shape-id) (cl/remove-all-fills [new-shape-id] {:color clr/black :opacity 1}) (create-layout-from-id [new-shape-id] type) + (dwc/update-shapes + [new-shape-id] + (fn [shape] + (-> shape + (merge flex-params) + (assoc :layout-item-h-sizing :auto + :layout-item-v-sizing :auto)))) + + (ptk/data-event :layout/update [new-shape-id]) (dwu/commit-undo-transaction undo-id)))))))) (defn remove-layout