diff --git a/common/src/app/common/pages/changes_builder.cljc b/common/src/app/common/pages/changes_builder.cljc index 77e232f3b..8375fc451 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 af4f88160..a14b0454d 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 4a5fad453..e009b6f26 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 f6de2ab14..808798457 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 a5b4a30a5..a112da657 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 8791777c1..3ef4a4bf6 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 3e14d8227..8f1b69a9b 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 9fde82d4b..95adb579a 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 710fd10c6..000000000 --- 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 77b44c296..d5bde2091 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 405b3f1b0..b32b3dc06 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 f0b61abd7..cfb8b1c40 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}))