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 307e9ecb26..b762090d3e 100644 --- a/common/src/app/common/geom/shapes/flex_layout/bounds.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/bounds.cljc @@ -11,7 +11,7 @@ [app.common.math :as mth] [app.common.types.shape.layout :as ctl])) -(defn- child-layout-bound-points +(defn child-layout-bound-points "Returns the bounds of the children as points" [parent child parent-bounds child-bounds] diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index 48b1eda5b9..a2a4e47522 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -12,7 +12,6 @@ [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.points :as cpo] [app.common.geom.shapes.points :as gpo] [app.common.geom.shapes.transforms :as gtr] [app.common.pages.helpers :as cph] @@ -158,7 +157,7 @@ children-bounds (->> children (mapv #(get-group-bounds objects bounds modif-tree %)))] - (cpo/merge-parent-coords-bounds children-bounds current-bounds)) + (gpo/merge-parent-coords-bounds children-bounds current-bounds)) (cph/mask-shape? shape) (get-group-bounds objects bounds modif-tree (-> children first)) diff --git a/common/src/app/common/types/modifiers.cljc b/common/src/app/common/types/modifiers.cljc index b0c8827008..22a428b262 100644 --- a/common/src/app/common/types/modifiers.cljc +++ b/common/src/app/common/types/modifiers.cljc @@ -384,6 +384,17 @@ (-> (empty) (scale-content value))) +(defn change-size + [{:keys [selrect points transform transform-inverse] :as shape} width height] + (let [old-width (-> selrect :width) + old-height (-> selrect :height) + width (or width old-width) + height (or height old-height) + origin (first points) + scalex (/ width old-width) + scaley (/ height old-height)] + (resize-modifiers (gpt/point scalex scaley) origin transform transform-inverse))) + (defn change-dimensions-modifiers [{:keys [transform transform-inverse] :as shape} attr value] (us/assert map? shape) diff --git a/common/src/app/common/types/shape.cljc b/common/src/app/common/types/shape.cljc index 9249ac5608..507860fb4f 100644 --- a/common/src/app/common/types/shape.cljc +++ b/common/src/app/common/types/shape.cljc @@ -375,7 +375,10 @@ "Initializes the selrect and points for a shape." [shape] (let [selrect (gsh/rect->selrect shape) - points (gsh/rect->points shape)] + points (gsh/rect->points shape) + points (cond-> points + (:transform shape) + (gsh/transform-points (gsh/center-points points) (:transform shape)))] (-> shape (assoc :selrect selrect :points points)))) diff --git a/frontend/src/app/main/data/workspace/texts.cljs b/frontend/src/app/main/data/workspace/texts.cljs index f0694b253f..77b44c2962 100644 --- a/frontend/src/app/main/data/workspace/texts.cljs +++ b/frontend/src/app/main/data/workspace/texts.cljs @@ -14,13 +14,12 @@ [app.common.pages.helpers :as cph] [app.common.text :as txt] [app.common.types.modifiers :as ctm] - [app.common.types.shape :as cts] [app.common.uuid :as uuid] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.common :as dwc] + [app.main.data.workspace.modifiers :as dwm] [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.state-helpers :as wsh] [app.main.data.workspace.undo :as dwu] [app.util.router :as rt] @@ -74,11 +73,14 @@ (when (and (not= content (:content shape)) (some? (:current-page-id state))) (rx/of - (dch/update-shapes [id] (fn [shape] - (-> shape - (assoc :content content) - (merge modifiers) - (cts/setup-rect-selrect)))) + (dch/update-shapes + [id] + (fn [shape] + (let [{:keys [width height]} modifiers] + (-> shape + (assoc :content content) + (cond-> (or (some? width) (some? height)) + (gsh/transform-shape (ctm/change-size shape width height))))))) (dwu/commit-undo-transaction (:id shape)))))) (when (some? id) @@ -323,20 +325,25 @@ (let [shape (wsh/lookup-shape state id)] (letfn [(update-fn [shape] (let [{:keys [selrect grow-type]} shape - {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-modifiers shape :width new-width)) + {shape-width :width shape-height :height} selrect - (and (not-changed? shape-height new-height) - (or (= grow-type :auto-height) (= grow-type :auto-width))) - (gsh/transform-shape (ctm/change-dimensions-modifiers shape :height new-height)))))] + shape + (cond-> shape + (and (not-changed? shape-width new-width) (= grow-type :auto-width)) + (gsh/transform-shape (ctm/change-dimensions-modifiers shape :width new-width))) + + shape + (cond-> shape + (and (not-changed? shape-height new-height) + (or (= grow-type :auto-height) (= grow-type :auto-width))) + (gsh/transform-shape (ctm/change-dimensions-modifiers shape :height new-height)))] + + shape))] (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}) - (dwul/update-layout-positions [id])))))))) + (rx/of (dch/update-shapes [id] update-fn {:reg-objects? true :save-undo? false})))))))) (defn save-font [data] @@ -385,7 +392,9 @@ (not (mth/close? (:width props) (:width shape)))) (and (some? (:height props)) (not (mth/close? (:height props) (:height shape))))) - (rx/of (dwul/update-layout-positions [id]))))))) + + (let [modif-tree (dwm/create-modif-tree [id] (ctm/reflow-modifiers))] + (rx/of (dwm/set-modifiers modif-tree)))))))) (defn clean-text-modifier [id] @@ -401,7 +410,11 @@ (ptk/reify ::remove-text-modifier ptk/UpdateEvent (update [_ state] - (d/dissoc-in state [:workspace-text-modifier id])))) + (d/dissoc-in state [:workspace-text-modifier id])) + + ptk/WatchEvent + (watch [_ _ _] + (rx/of (dwm/apply-modifiers))))) (defn commit-position-data [] diff --git a/frontend/src/app/main/ui/workspace/shapes/text/editor.cljs b/frontend/src/app/main/ui/workspace/shapes/text/editor.cljs index 419c8f7e55..e323b4672c 100644 --- a/frontend/src/app/main/ui/workspace/shapes/text/editor.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/text/editor.cljs @@ -257,7 +257,9 @@ (mf/defc text-editor-svg {::mf/wrap-props false} [props] - (let [shape (obj/get props "shape") + (let [shape (obj/get props "shape") + modifiers (obj/get props "modifiers") + modifiers (get-in modifiers [(:id shape) :modifiers]) clip-id (dm/str "text-edition-clip" (:id shape)) @@ -270,7 +272,10 @@ shape (cond-> shape (some? text-modifier) - (dwt/apply-text-modifier text-modifier)) + (dwt/apply-text-modifier text-modifier) + + (some? modifiers) + (gsh/transform-shape modifiers)) bounding-box (gsht/position-data-selrect shape) diff --git a/frontend/src/app/main/ui/workspace/shapes/text/text_edition_outline.cljs b/frontend/src/app/main/ui/workspace/shapes/text/text_edition_outline.cljs index bacf0eea67..aa4e291643 100644 --- a/frontend/src/app/main/ui/workspace/shapes/text/text_edition_outline.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/text/text_edition_outline.cljs @@ -12,14 +12,19 @@ [rumext.v2 :as mf])) (mf/defc text-edition-outline - [{:keys [shape zoom]}] - (let [text-modifier-ref + [{:keys [shape zoom modifiers]}] + (let [modifiers (get-in modifiers [(:id shape) :modifiers]) + + text-modifier-ref (mf/use-memo (mf/deps (:id shape)) #(refs/workspace-text-modifier-by-id (:id shape))) text-modifier (mf/deref text-modifier-ref) shape (cond-> shape + (some? modifiers) + (gsh/transform-shape modifiers) + (some? text-modifier) (dwt/apply-text-modifier text-modifier)) 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 673f47a35e..405b3f1b06 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 @@ -36,13 +36,11 @@ (dissoc :position-data))) (defn fix-position [shape modifier] - (let [shape' (-> shape - (assoc :grow-type :fixed) - (gsh/transform-shape modifier)) - + (let [shape' (gsh/transform-shape shape modifier) + ;; 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-modifiers deltav)))) + (gsh/transform-shape shape (ctm/move modifier deltav)))) (defn process-shape [modifiers {:keys [id] :as shape}] (let [modifier (dm/get-in modifiers [id :modifiers])] diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index 418c22a5a7..5d55889f27 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -204,9 +204,9 @@ [:div.viewport-overlays ;; The behaviour inside a foreign object is a bit different that in plain HTML so we wrap ;; inside a foreign object "dummy" so this awkward behaviour is take into account - [:svg {:style {:top 0 :left 0 :position "fixed" :width "100%" :height "100%" :opacity 0}} + [:svg {:style {:top 0 :left 0 :position "fixed" :width "100%" :height "100%" :opacity (when-not (debug? :html-text) 0)}} [:foreignObject {:x 0 :y 0 :width "100%" :height "100%"} - [:div {:style {:pointer-events "none"}} + [:div {:style {:pointer-events (when-not (debug? :html-text) "none")}} [:& stvh/viewport-texts {:key (dm/str "texts-" page-id) :page-id page-id @@ -289,7 +289,8 @@ [:g {:style {:pointer-events (if disable-events? "none" "auto")}} (when show-text-editor? - [:& editor/text-editor-svg {:shape editing-shape}]) + [:& editor/text-editor-svg {:shape editing-shape + :modifiers modifiers}]) (when show-frame-outline? [:& outline/shape-outlines @@ -298,7 +299,8 @@ (filter #(cph/frame-shape? (get base-objects %))) (remove selected) (first))} - :zoom zoom}]) + :zoom zoom + :modifiers modifiers}]) (when show-outlines? [:& outline/shape-outlines @@ -307,7 +309,8 @@ :hover #{(:id @hover) @frame-hover} :highlighted highlighted :edition edition - :zoom zoom}]) + :zoom zoom + :modifiers modifiers}]) (when show-selection-handlers? [:& selection/selection-area @@ -321,7 +324,8 @@ (when show-text-editor? [:& text-edition-outline {:shape (get base-objects edition) - :zoom zoom}]) + :zoom zoom + :modifiers modifiers}]) (when show-measures? [:& msr/measurement diff --git a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs index 508a227dc8..c35b2aedbb 100644 --- a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs @@ -130,12 +130,15 @@ rect (gsh/center->rect point (/ 5 zoom) (/ 5 zoom))] (if (mf/ref-val hover-disabled-ref) (rx/of nil) - (uw/ask-buffered! - {:cmd :selection/query - :page-id page-id - :rect rect - :include-frames? true - :clip-children? (not mod?)}))))) + (->> (uw/ask-buffered! + {:cmd :selection/query + :page-id page-id + :rect rect + :include-frames? true + :clip-children? (not mod?)}) + ;; When the ask-buffered is canceled returns null. We filter them + ;; to improve the behavior + (rx/filter some?)))))) over-shapes-stream (mf/use-memo diff --git a/frontend/src/app/main/ui/workspace/viewport/outline.cljs b/frontend/src/app/main/ui/workspace/viewport/outline.cljs index 416f71625f..3cba35078e 100644 --- a/frontend/src/app/main/ui/workspace/viewport/outline.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/outline.cljs @@ -9,6 +9,7 @@ [app.common.data :as d] [app.common.exceptions :as ex] [app.common.geom.shapes :as gsh] + [app.main.ui.hooks :as hooks] [app.util.object :as obj] [app.util.path.format :as upf] [clojure.set :as set] @@ -18,10 +19,12 @@ (mf/defc outline {::mf/wrap-props false} [props] - (let [shape (obj/get props "shape") - zoom (obj/get props "zoom" 1) + (let [shape (obj/get props "shape") + zoom (obj/get props "zoom" 1) + color (obj/get props "color") + modifier (obj/get props "modifier") - color (unchecked-get props "color") + shape (gsh/transform-shape shape (:modifiers modifier)) transform (gsh/transform-str shape) path? (= :path (:type shape)) path-data @@ -64,17 +67,22 @@ (mf/defc shape-outlines-render {::mf/wrap-props false - ::mf/wrap [#(mf/memo' % (mf/check-props ["shapes" "zoom"]))]} + ::mf/wrap [#(mf/memo' % (mf/check-props ["shapes" "zoom" "modifiers"]))]} [props] + (let [shapes (obj/get props "shapes") zoom (obj/get props "zoom") + modifiers (obj/get props "modifiers") color (if (or (> (count shapes) 1) (nil? (:shape-ref (first shapes)))) "var(--color-primary)" "var(--color-component-highlight)")] + (for [shape shapes] - [:& outline {:key (str "outline-" (:id shape)) - :shape shape - :zoom zoom - :color color}]))) + (let [modifier (get modifiers (:id shape))] + [:& outline {:key (str "outline-" (:id shape)) + :shape shape + :modifier modifier + :zoom zoom + :color color}])))) (defn- show-outline? [shape] @@ -91,6 +99,7 @@ objects (obj/get props "objects") edition (obj/get props "edition") zoom (obj/get props "zoom") + modifiers (obj/get props "modifiers") lookup (d/getf objects) edition? (fn [o] (= edition o)) @@ -102,7 +111,13 @@ (set/union selected hover)) (into (comp (remove edition?) (keep lookup)) - highlighted))] + highlighted)) + + modifiers (select-keys modifiers (map :id shapes)) + modifiers (hooks/use-equal-memo modifiers) + shapes (hooks/use-equal-memo shapes)] [:g.outlines - [:& shape-outlines-render {:shapes shapes :zoom zoom}]])) + [:& shape-outlines-render {:shapes shapes + :zoom zoom + :modifiers modifiers}]])) diff --git a/frontend/src/debug.cljs b/frontend/src/debug.cljs index 1b1625fc74..f0b61abd76 100644 --- a/frontend/src/debug.cljs +++ b/frontend/src/debug.cljs @@ -83,6 +83,9 @@ ;; Show the bounds relative to the parent :parent-bounds + + ;; Show html text + :html-text }) ;; These events are excluded when we activate the :events flag