diff --git a/CHANGES.md b/CHANGES.md index 9313cfa623..633dbddf48 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,6 +13,7 @@ ### :bug: Bugs fixed - Fix pan cursor not disabling viewport guides [Github #6985](https://github.com/penpot/penpot/issues/6985) +- Fix viewport resize on locked shapes [Taiga #11974](https://tree.taiga.io/project/penpot/issue/11974) ## 2.11.0 (Unreleased) diff --git a/frontend/playwright/ui/visual-specs/workspace.spec.js b/frontend/playwright/ui/visual-specs/workspace.spec.js index 418b92861d..628a7f2ebd 100644 --- a/frontend/playwright/ui/visual-specs/workspace.spec.js +++ b/frontend/playwright/ui/visual-specs/workspace.spec.js @@ -28,13 +28,29 @@ const setupFileWithAssets = async (workspace) => { return { fileId, pageId }; }; -test("Shows the workspace correctly for a blank file", async ({ page }) => { - const workspace = new WorkspacePage(page); - await workspace.setupEmptyFile(); +test.describe("Viewport", () => { + test("Shows the workspace correctly for a blank file", async ({ page }) => { + const workspace = new WorkspacePage(page); + await workspace.setupEmptyFile(); - await workspace.goToWorkspace(); + await workspace.goToWorkspace(); - await expect(workspace.page).toHaveScreenshot(); + await expect(workspace.page).toHaveScreenshot(); + }); + + test("User creates a rectangle and locks it", async ({ page }) => { + const workspace = new WorkspacePage(page); + await workspace.setupEmptyFile(page); + await workspace.goToWorkspace(); + + await workspace.rectShapeButton.click(); + await workspace.clickWithDragViewportAt(128, 128, 200, 100); + await workspace.clickLeafLayer("Rectangle"); + + await page.keyboard.press("Shift+Control+L"); + + await expect(workspace.page).toHaveScreenshot(); + }); }); test.describe("Design tab", () => { @@ -145,4 +161,4 @@ test.describe("Palette", () => { workspace.palette.getByRole("button", { name: "#7798ff" }), ).toBeVisible(); }); -}); +}); \ No newline at end of file diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 9a1bcaa319..e0dfddee42 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -273,76 +273,82 @@ ptk/WatchEvent (watch [_ state stream] - (let [initial-position @ms/mouse-position + (if (:blocked shape) + (rx/empty) + (let [initial-position @ms/mouse-position - stopper (mse/drag-stopper stream) - layout (:workspace-layout state) - page-id (:current-page-id state) - focus (:workspace-focus-selected state) - zoom (dm/get-in state [:workspace-local :zoom] 1) - objects (dsh/lookup-page-objects state page-id) - shapes (map (d/getf objects) ids) + stopper (mse/drag-stopper stream) + layout (:workspace-layout state) + page-id (:current-page-id state) + focus (:workspace-focus-selected state) + zoom (dm/get-in state [:workspace-local :zoom] 1) + objects (dsh/lookup-page-objects state page-id) + shape-ids (filterv (comp not :blocked (d/getf objects)) ids)] - resize-events-stream - (->> ms/mouse-position - (rx/filter some?) - (rx/with-latest-from ms/mouse-position-shift ms/mouse-position-alt) - (rx/map normalize-proportion-lock) - (rx/switch-map - (fn [[point _ _ :as current]] - (->> (snap/closest-snap-point page-id shapes objects layout zoom focus point) - (rx/map #(conj current %))))) - (rx/map #(resize shape initial-position layout %)) - (rx/share)) + (if (empty? shape-ids) + (rx/empty) + (let [shapes (map (d/getf objects) shape-ids) - modifiers-stream - (if (features/active-feature? state "render-wasm/v1") - (rx/merge - (->> resize-events-stream - (rx/mapcat - (fn [modifiers] - (let [modif-tree (dwm/create-modif-tree ids modifiers)] - (rx/of - (dwm/set-wasm-modifiers - modif-tree - :ignore-constraints (contains? layout :scale-text)))))) - (rx/take-until stopper)) + resize-events-stream + (->> ms/mouse-position + (rx/filter some?) + (rx/with-latest-from ms/mouse-position-shift ms/mouse-position-alt) + (rx/map normalize-proportion-lock) + (rx/switch-map + (fn [[point _ _ :as current]] + (->> (snap/closest-snap-point page-id shapes objects layout zoom focus point) + (rx/map #(conj current %))))) + (rx/map #(resize shape initial-position layout %)) + (rx/share)) + + modifiers-stream + (if (features/active-feature? state "render-wasm/v1") + (rx/merge + (->> resize-events-stream + (rx/mapcat + (fn [modifiers] + (let [modif-tree (dwm/create-modif-tree shape-ids modifiers)] + (rx/of + (dwm/set-wasm-modifiers + modif-tree + :ignore-constraints (contains? layout :scale-text)))))) + (rx/take-until stopper)) ;; The last event we need to use the old method so the elements are correctly positioned until ;; all the logic is implemented in wasm - (->> resize-events-stream - (rx/take-until stopper) - (rx/last) - (rx/map - #(dwm/apply-wasm-modifiers - (dwm/create-modif-tree ids %) - :ignore-constraints (contains? layout :scale-text))))) + (->> resize-events-stream + (rx/take-until stopper) + (rx/last) + (rx/map + #(dwm/apply-wasm-modifiers + (dwm/create-modif-tree shape-ids %) + :ignore-constraints (contains? layout :scale-text))))) - (->> resize-events-stream - (rx/mapcat - (fn [modifiers] - (let [modif-tree (dwm/create-modif-tree ids modifiers)] - (rx/of (dwm/set-modifiers modif-tree (contains? layout :scale-text)))))) - (rx/take-until stopper)))] + (->> resize-events-stream + (rx/mapcat + (fn [modifiers] + (let [modif-tree (dwm/create-modif-tree shape-ids modifiers)] + (rx/of (dwm/set-modifiers modif-tree (contains? layout :scale-text)))))) + (rx/take-until stopper)))] - (rx/concat + (rx/concat ;; This initial stream waits for some pixels to be move before making the resize ;; if you make a click in the border will not make a resize - (->> ms/mouse-position - (rx/map #(gpt/to-vec initial-position %)) - (rx/map #(gpt/length %)) - (rx/filter #(> % (/ 10 zoom))) - (rx/take 1) - (rx/take-until stopper) - (rx/mapcat (fn [] modifiers-stream))) + (->> ms/mouse-position + (rx/map #(gpt/to-vec initial-position %)) + (rx/map #(gpt/length %)) + (rx/filter #(> % (/ 10 zoom))) + (rx/take 1) + (rx/take-until stopper) + (rx/mapcat (fn [] modifiers-stream))) - (if (features/active-feature? state "render-wasm/v1") - (rx/of - (finish-transform)) + (if (features/active-feature? state "render-wasm/v1") + (rx/of + (finish-transform)) - (rx/of - (dwm/apply-modifiers) - (finish-transform))))))))) + (rx/of + (dwm/apply-modifiers) + (finish-transform)))))))))))) (defn trigger-bounding-box-cloaking "Trigger the bounding box cloaking (with default timer of 1sec) diff --git a/frontend/src/app/main/ui/workspace/viewport/selection.cljs b/frontend/src/app/main/ui/workspace/viewport/selection.cljs index 8b304eb2b7..071233f44b 100644 --- a/frontend/src/app/main/ui/workspace/viewport/selection.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/selection.cljs @@ -381,6 +381,7 @@ (and flip-y (not flip-x)))] (when (and (not ^boolean read-only?) + (not (:blocked shape)) (not (or (= transform-type :move) (= transform-type :rotate)))) diff --git a/frontend/src/app/main/ui/workspace/viewport/widgets.cljs b/frontend/src/app/main/ui/workspace/viewport/widgets.cljs index e494af80ef..6e2107e0aa 100644 --- a/frontend/src/app/main/ui/workspace/viewport/widgets.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/widgets.cljs @@ -100,9 +100,9 @@ on-pointer-down (mf/use-fn - (mf/deps (:id frame) on-frame-select workspace-read-only?) + (mf/deps (:id frame) on-frame-select workspace-read-only? blocked?) (fn [event] - (when (dom/left-mouse? event) + (when (and (dom/left-mouse? event) (not blocked?)) (dom/prevent-default event) (dom/stop-propagation event) (on-frame-select event (:id frame)))))