mirror of
https://github.com/penpot/penpot.git
synced 2026-08-19 03:08:40 +00:00
118 lines
5.3 KiB
Clojure
118 lines
5.3 KiB
Clojure
;; 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 Sucursal en España SL
|
|
|
|
|
|
(ns frontend-tests.logic.path-helpers-test
|
|
(:require
|
|
[app.common.geom.point :as gpt]
|
|
[app.common.types.path :as path]
|
|
[app.main.data.workspace.path.helpers :as path.helpers]
|
|
[app.main.data.workspace.path.streams :as path.streams]
|
|
[app.main.store :as st]
|
|
[cljs.test :as t :include-macros true]
|
|
[frontend-tests.logic.path-test-helpers :as pth]))
|
|
|
|
(t/deftest to-pixel-snap-quantises-to-half-pixels-past-the-zoom-threshold
|
|
;; Pixel snapping uses half steps above 300% zoom.
|
|
(let [original @st/state
|
|
snap (fn [zoom p]
|
|
(reset! st/state {:workspace-layout #{:snap-pixel-grid}
|
|
:workspace-local {:zoom zoom}})
|
|
(path.streams/to-pixel-snap p))]
|
|
(try
|
|
;; at or below the threshold, snapping rounds to whole pixels
|
|
(t/is (= (gpt/point 100 100) (snap 1 (gpt/point 100.4 100.4))))
|
|
(t/is (= (gpt/point 100 100) (snap 3 (gpt/point 100.4 100.4))))
|
|
;; above 300% zoom it rounds to the nearest half pixel
|
|
(t/is (= (gpt/point 100.5 100.5) (snap 6 (gpt/point 100.4 100.4))))
|
|
;; with pixel snapping off the position passes through unchanged
|
|
(reset! st/state {:workspace-layout #{} :workspace-local {:zoom 6}})
|
|
(t/is (= (gpt/point 100.4 100.4)
|
|
(path.streams/to-pixel-snap (gpt/point 100.4 100.4))))
|
|
(finally
|
|
(reset! st/state original)))))
|
|
|
|
(t/deftest node-merge-snap-finds-the-closest-target-for-multiple-moving-points
|
|
(let [start-point (gpt/point 0 0)
|
|
selected-points #{start-point (gpt/point 100 0)}
|
|
points (into selected-points
|
|
[(gpt/point 8 14)
|
|
(gpt/point 111 10.5)
|
|
(gpt/point 500 500)])
|
|
snap-position (path.streams/make-node-merge-snap
|
|
start-point selected-points points 10)]
|
|
;; The closest merge target moves the full selection.
|
|
(t/is (= (gpt/point 11 10.5)
|
|
(snap-position (gpt/point 10 10))))
|
|
;; Missing merge targets return no snap delta.
|
|
(t/is (nil? (snap-position (gpt/point 300 300))))))
|
|
|
|
(t/deftest insertion-preview-reuses-precomputed-segment-midpoints
|
|
(let [content (path/content
|
|
[{:command :move-to :params {:x 0 :y 0}}
|
|
{:command :line-to :params {:x 10 :y 0}}
|
|
{:command :curve-to
|
|
:params {:c1x 10 :c1y 0
|
|
:c2x 20 :c2y 10
|
|
:x 20 :y 0}}
|
|
{:command :close-path :params {}}])
|
|
midpoints (path.helpers/insertion-mid-points content)
|
|
line-mid (first midpoints)
|
|
curve-mid (second midpoints)]
|
|
(t/is (= 2 (count midpoints)))
|
|
(t/is (= (gpt/point 5 0) line-mid))
|
|
(t/is (= {:from-p (gpt/point 0 0)
|
|
:to-p (gpt/point 10 0)
|
|
:t 0.5}
|
|
(meta line-mid)))
|
|
(t/is (= line-mid
|
|
(path.helpers/insertion-point
|
|
content (gpt/point 5.5 0) 1 false midpoints)))
|
|
(t/is (nil? (path.helpers/insertion-point
|
|
content (gpt/point 200 200) 1 false midpoints)))
|
|
;; Alt/insert-anywhere remains dynamic and ignores the midpoint cache.
|
|
(t/is (some? (path.helpers/insertion-point
|
|
content curve-mid 1 true [])))))
|
|
|
|
(t/deftest selected-node-indices-folds-segment-endpoints
|
|
(let [content (pth/selectable-path-content)]
|
|
;; segment index 1 connects nodes 0 and 1
|
|
(t/is (= #{0 1}
|
|
(path.helpers/selected-node-indices content {:nodes #{} :segments #{1}})))
|
|
;; explicit nodes and segment endpoints are unioned
|
|
(t/is (= #{0 1 2}
|
|
(path.helpers/selected-node-indices content {:nodes #{2} :segments #{1}})))))
|
|
|
|
(t/deftest remap-selection-follows-content-structure
|
|
(let [content (pth/selectable-path-content)
|
|
;; Same command layout: index 1 turned into a line-to
|
|
corner (path/content
|
|
(assoc (vec content) 1 {:command :line-to
|
|
:params {:x 10 :y 0}}))
|
|
;; Different layout: the middle node was removed
|
|
shorter (path/content
|
|
[{:command :move-to
|
|
:params {:x 0 :y 0}}
|
|
{:command :line-to
|
|
:params {:x 20 :y 0}}])
|
|
selection {:nodes #{1 2}
|
|
:segments #{2}
|
|
:handlers #{[1 :c1] [2 :c2]}}]
|
|
(t/is (= {:nodes #{1 2}
|
|
:segments #{2}
|
|
:handlers #{[2 :c2]}}
|
|
(path.helpers/remap-selection selection content corner)))
|
|
(t/is (= {:nodes #{1}
|
|
:segments #{}
|
|
:handlers #{}}
|
|
(path.helpers/remap-selection selection content shorter)))))
|
|
|
|
(t/deftest handlers-joined-detects-smooth-vs-corner-nodes
|
|
;; node (10,0): incoming [1 :c2]=(8,0), outgoing [2 :c1]
|
|
(t/is (path.helpers/handlers-joined? (pth/selectable-path-content) 2 :c1))
|
|
(t/is (not (path.helpers/handlers-joined? (pth/corner-path-content) 2 :c1))))
|
|
|