mirror of
https://github.com/penpot/penpot.git
synced 2025-03-13 16:21:57 -05:00
✨ Improved snap to grids
This commit is contained in:
parent
b5e965cf1a
commit
aec68c52ab
15 changed files with 220 additions and 119 deletions
|
@ -9,7 +9,7 @@
|
|||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.math :as mth]
|
||||
[app.common.math :as mth :refer [close?]]
|
||||
[app.common.pages :refer [make-minimal-shape]]
|
||||
[clojure.test :as t]))
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
(ns app.common.geom-test
|
||||
(:require
|
||||
[clojure.test :as t]
|
||||
[app.common.math :as mth]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.matrix :as gmt]))
|
||||
|
||||
|
@ -67,7 +68,7 @@
|
|||
p2 (gpt/point 10 10)
|
||||
angle (gpt/angle-with-other p1 p2)]
|
||||
(t/is (number? angle))
|
||||
(t/is (= angle 45.0)))))
|
||||
(t/is (mth/close? angle 45.0)))))
|
||||
|
||||
(t/deftest matrix-constructors-test
|
||||
(let [m (gmt/matrix)]
|
||||
|
|
|
@ -678,7 +678,9 @@
|
|||
(rx/of (finish-transform))
|
||||
(rx/concat
|
||||
(->> position
|
||||
;; We ask for the snap position but we continue even if the result is not available
|
||||
(rx/with-latest vector snap-delta)
|
||||
;; We try to use the previous snap so we don't have to wait for the result of the new
|
||||
(rx/map snap/correct-snap-point)
|
||||
(rx/map #(hash-map :displacement (gmt/translate-matrix %)))
|
||||
(rx/map (partial set-modifiers ids))
|
||||
|
|
|
@ -55,10 +55,6 @@
|
|||
(and (d/not-empty? focus)
|
||||
(not (cp/is-in-focus? objects focus id)))))))
|
||||
|
||||
(defn- flatten-to-points
|
||||
[query-result]
|
||||
(mapcat (fn [[_ data]] (map :pt data)) query-result))
|
||||
|
||||
(defn- calculate-distance [query-result point coord]
|
||||
(->> query-result
|
||||
(map (fn [[value _]] [(mth/abs (- value (coord point))) [(coord point) value]]))))
|
||||
|
@ -90,8 +86,7 @@
|
|||
:axis coord
|
||||
:ranges [[(- value (/ 0.5 zoom)) (+ value (/ 0.5 zoom))]]})
|
||||
(rx/take 1)
|
||||
(rx/map (remove-from-snap-points remove-snap?))
|
||||
(rx/map flatten-to-points))))
|
||||
(rx/map (remove-from-snap-points remove-snap?)))))
|
||||
|
||||
(defn- search-snap
|
||||
[page-id frame-id points coord remove-snap? zoom]
|
||||
|
@ -369,7 +364,12 @@
|
|||
0)
|
||||
dy (if (not= 0 (:y snap-delta))
|
||||
(- (+ (:y snap-pos) (:y snap-delta)) (:y position))
|
||||
0)]
|
||||
0)
|
||||
|
||||
;; If the deltas (dx,dy) are bigger than the snap-accuracy means the stored snap
|
||||
;; is not valid, so we change to 0
|
||||
dx (if (> (mth/abs dx) snap-accuracy) 0 dx)
|
||||
dy (if (> (mth/abs dy) snap-accuracy) 0 dy)]
|
||||
(-> position
|
||||
(update :x + dx)
|
||||
(update :y + dy)))
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
on-blur (obj/get props "onBlur")
|
||||
title (obj/get props "title")
|
||||
default-val (obj/get props "default")
|
||||
nillable (obj/get props "nillable")
|
||||
|
||||
;; We need a ref pointing to the input dom element, but the user
|
||||
;; of this component may provide one (that is forwarded here).
|
||||
|
@ -71,21 +72,27 @@
|
|||
|
||||
parse-value
|
||||
(mf/use-callback
|
||||
(mf/deps ref min-val max-val value)
|
||||
(mf/deps ref min-val max-val value nillable default-val)
|
||||
(fn []
|
||||
(let [input-node (mf/ref-val ref)
|
||||
new-value (-> (dom/get-value input-node)
|
||||
(sm/expr-eval value))]
|
||||
(when (d/num? new-value)
|
||||
(cond
|
||||
(d/num? new-value)
|
||||
(-> new-value
|
||||
(cljs.core/max us/min-safe-int)
|
||||
(cljs.core/min us/max-safe-int)
|
||||
(cond->
|
||||
(d/num? min-val)
|
||||
(d/num? min-val)
|
||||
(cljs.core/max min-val)
|
||||
|
||||
(d/num? max-val)
|
||||
(cljs.core/min max-val)))))))
|
||||
(cljs.core/min max-val)))
|
||||
|
||||
nillable
|
||||
default-val
|
||||
|
||||
:else value))))
|
||||
|
||||
update-input
|
||||
(mf/use-callback
|
||||
|
@ -109,8 +116,14 @@
|
|||
(fn [event up? down?]
|
||||
(let [current-value (parse-value)]
|
||||
(when current-value
|
||||
(let [increment (if (kbd/shift? event)
|
||||
(let [increment (cond
|
||||
(kbd/shift? event)
|
||||
(if up? (* step-val 10) (* step-val -10))
|
||||
|
||||
(kbd/alt? event)
|
||||
(if up? (* step-val 0.1) (* step-val -0.1))
|
||||
|
||||
:else
|
||||
(if up? step-val (- step-val)))
|
||||
|
||||
new-value (+ current-value increment)
|
||||
|
@ -154,14 +167,19 @@
|
|||
(mf/use-callback
|
||||
(mf/deps set-delta)
|
||||
(fn [event]
|
||||
(set-delta event (< (.-deltaY event) 0) (> (.-deltaY event) 0))))
|
||||
(let [input-node (mf/ref-val ref)]
|
||||
(when (dom/active? input-node)
|
||||
(let [event (.getBrowserEvent ^js event)]
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event)
|
||||
(set-delta event (< (.-deltaY event) 0) (> (.-deltaY event) 0)))))))
|
||||
|
||||
handle-blur
|
||||
(mf/use-callback
|
||||
(mf/deps parse-value apply-value update-input on-blur)
|
||||
(fn [_]
|
||||
(let [new-value (or (parse-value) default-val)]
|
||||
(if new-value
|
||||
(if (or nillable new-value)
|
||||
(apply-value new-value)
|
||||
(update-input new-value)))
|
||||
(when on-blur (on-blur))))
|
||||
|
@ -176,13 +194,12 @@
|
|||
(dom/blur! current)))))))
|
||||
|
||||
props (-> props
|
||||
(obj/without ["value" "onChange"])
|
||||
(obj/without ["value" "onChange" "nillable"])
|
||||
(obj/set! "className" "input-text")
|
||||
(obj/set! "type" "text")
|
||||
(obj/set! "ref" ref)
|
||||
(obj/set! "defaultValue" (fmt/format-number value))
|
||||
(obj/set! "title" title)
|
||||
(obj/set! "onWheel" handle-mouse-wheel)
|
||||
(obj/set! "onKeyDown" handle-key-down)
|
||||
(obj/set! "onBlur" handle-blur))]
|
||||
|
||||
|
@ -203,6 +220,13 @@
|
|||
(let [handle-blur (:fn (mf/ref-val handle-blur-ref))]
|
||||
(handle-blur)))))
|
||||
|
||||
(mf/use-layout-effect
|
||||
(mf/deps handle-mouse-wheel)
|
||||
(fn []
|
||||
(let [keys [(events/listen (mf/ref-val ref) EventType.WHEEL handle-mouse-wheel #js {:pasive false})]]
|
||||
#(doseq [key keys]
|
||||
(events/unlistenByKey key)))))
|
||||
|
||||
(mf/use-layout-effect
|
||||
(fn []
|
||||
(let [keys [(events/listen globals/window EventType.POINTERDOWN on-click)
|
||||
|
@ -212,4 +236,3 @@
|
|||
(events/unlistenByKey key)))))
|
||||
|
||||
[:> :input props]))
|
||||
|
||||
|
|
|
@ -205,7 +205,7 @@
|
|||
[:> numeric-input
|
||||
{:placeholder "Auto"
|
||||
:value (or (:item-length params) "")
|
||||
:default nil
|
||||
:nillable true
|
||||
:on-change handle-change-item-length}]])
|
||||
|
||||
(when (#{:row :column} type)
|
||||
|
@ -214,11 +214,15 @@
|
|||
:class "pixels"
|
||||
:value (:gutter params)
|
||||
:min 0
|
||||
:nillable true
|
||||
:default 0
|
||||
:placeholder "0"
|
||||
:on-change (handle-change :params :gutter)}]
|
||||
[:& input-row {:label (tr "workspace.options.grid.params.margin")
|
||||
:class "pixels"
|
||||
:min 0
|
||||
:nillable true
|
||||
:default 0
|
||||
:placeholder "0"
|
||||
:value (:margin params)
|
||||
:on-change (handle-change :params :margin)}]])
|
||||
|
|
|
@ -41,12 +41,6 @@
|
|||
:svg-raw #{:size :position :rotation}
|
||||
:text #{:size :position :rotation}})
|
||||
|
||||
(defn- attr->string [attr values]
|
||||
(let [value (attr values)]
|
||||
(if (= value :multiple)
|
||||
""
|
||||
(str (-> value (d/coalesce 0))))))
|
||||
|
||||
(declare +size-presets+)
|
||||
|
||||
;; -- User/drawing coords
|
||||
|
@ -241,7 +235,7 @@
|
|||
:placeholder "--"
|
||||
:on-click select-all
|
||||
:on-change on-width-change
|
||||
:value (attr->string :width values)}]]
|
||||
:value (:width values)}]]
|
||||
|
||||
[:div.input-element.height {:title (tr "workspace.options.height")}
|
||||
[:> numeric-input {:min 0.01
|
||||
|
@ -249,7 +243,7 @@
|
|||
:placeholder "--"
|
||||
:on-click select-all
|
||||
:on-change on-height-change
|
||||
:value (attr->string :height values)}]]
|
||||
:value (:height values)}]]
|
||||
|
||||
[:div.lock-size {:class (dom/classnames
|
||||
:selected (true? proportion-lock)
|
||||
|
@ -268,13 +262,13 @@
|
|||
:placeholder "--"
|
||||
:on-click select-all
|
||||
:on-change on-pos-x-change
|
||||
:value (attr->string :x values)}]]
|
||||
:value (:x values)}]]
|
||||
[:div.input-element.Yaxis {:title (tr "workspace.options.y")}
|
||||
[:> numeric-input {:no-validate true
|
||||
:placeholder "--"
|
||||
:on-click select-all
|
||||
:on-change on-pos-y-change
|
||||
:value (attr->string :y values)}]]])
|
||||
:value (:y values)}]]])
|
||||
|
||||
;; ROTATION
|
||||
(when (options :rotation)
|
||||
|
@ -285,19 +279,12 @@
|
|||
{:no-validate true
|
||||
:min 0
|
||||
:max 359
|
||||
:default 0
|
||||
:data-wrap true
|
||||
:placeholder "--"
|
||||
:on-click select-all
|
||||
:on-change on-rotation-change
|
||||
:value (attr->string :rotation values)}]]
|
||||
#_[:input.slidebar
|
||||
{:type "range"
|
||||
:min "0"
|
||||
:max "359"
|
||||
:step "10"
|
||||
:no-validate true
|
||||
:on-change on-rotation-change
|
||||
:value (attr->string :rotation values)}]])
|
||||
:value (:rotation values)}]]])
|
||||
|
||||
;; RADIUS
|
||||
(when (options :radius)
|
||||
|
@ -325,13 +312,14 @@
|
|||
:min 0
|
||||
:on-click select-all
|
||||
:on-change on-radius-1-change
|
||||
:value (attr->string :rx values)}]]
|
||||
:value (:rx values)}]]
|
||||
|
||||
@radius-multi?
|
||||
[:div.input-element.mini {:title (tr "workspace.options.radius")}
|
||||
[:input.input-text
|
||||
{:type "number"
|
||||
:placeholder "--"
|
||||
:min 0
|
||||
:on-click select-all
|
||||
:on-change on-radius-multi-change
|
||||
:value ""}]]
|
||||
|
@ -344,7 +332,7 @@
|
|||
:min 0
|
||||
:on-click select-all
|
||||
:on-change on-radius-r1-change
|
||||
:value (attr->string :r1 values)}]]
|
||||
:value (:r1 values)}]]
|
||||
|
||||
[:div.input-element.mini {:title (tr "workspace.options.radius")}
|
||||
[:> numeric-input
|
||||
|
@ -352,7 +340,7 @@
|
|||
:min 0
|
||||
:on-click select-all
|
||||
:on-change on-radius-r2-change
|
||||
:value (attr->string :r2 values)}]]
|
||||
:value (:r2 values)}]]
|
||||
|
||||
[:div.input-element.mini {:title (tr "workspace.options.radius")}
|
||||
[:> numeric-input
|
||||
|
@ -360,7 +348,7 @@
|
|||
:min 0
|
||||
:on-click select-all
|
||||
:on-change on-radius-r3-change
|
||||
:value (attr->string :r3 values)}]]
|
||||
:value (:r3 values)}]]
|
||||
|
||||
[:div.input-element.mini {:title (tr "workspace.options.radius")}
|
||||
[:> numeric-input
|
||||
|
@ -368,7 +356,7 @@
|
|||
:min 0
|
||||
:on-click select-all
|
||||
:on-change on-radius-r4-change
|
||||
:value (attr->string :r4 values)}]]])])]]]))
|
||||
:value (:r4 values)}]]])])]]]))
|
||||
|
||||
(def +size-presets+
|
||||
[{:name "APPLE"}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
[app.util.object :as obj]
|
||||
[rumext.alpha :as mf]))
|
||||
|
||||
(mf/defc input-row [{:keys [label options value class min max on-change type placeholder]}]
|
||||
(mf/defc input-row [{:keys [label options value class min max on-change type placeholder default nillable]}]
|
||||
[:div.row-flex.input-row
|
||||
[:span.element-set-subtitle label]
|
||||
[:div.input-element {:class class}
|
||||
|
@ -43,6 +43,8 @@
|
|||
{:placeholder placeholder
|
||||
:min min
|
||||
:max max
|
||||
:default default
|
||||
:nillable nillable
|
||||
:on-change on-change
|
||||
:value (or value "")}])]])
|
||||
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
|
||||
(ns app.main.ui.workspace.viewport.frame-grid
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.math :as mth]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.refs :as refs]
|
||||
[app.util.geom.grid :as gg]
|
||||
|
@ -41,27 +43,71 @@
|
|||
:fill (str "url(#" grid-id ")")}]]))
|
||||
|
||||
(mf/defc layout-grid
|
||||
[{:keys [key frame grid]}]
|
||||
[{:keys [key frame grid zoom]}]
|
||||
(let [{color-value :color color-opacity :opacity} (-> grid :params :color)
|
||||
;; Support for old color format
|
||||
color-value (or color-value (:value (get-in grid [:params :color :value])))
|
||||
gutter (-> grid :params :gutter)
|
||||
gutter? (and (not (nil? gutter)) (not= gutter 0))
|
||||
gutter (gg/grid-gutter frame grid)
|
||||
gutter? (and (not (nil? gutter)) (not (mth/almost-zero? gutter)))]
|
||||
|
||||
style (if gutter?
|
||||
#js {:fill color-value
|
||||
:opacity color-opacity}
|
||||
#js {:stroke color-value
|
||||
:strokeOpacity color-opacity
|
||||
:fill "none"})]
|
||||
[:g.grid
|
||||
(for [{:keys [x y width height] :as area} (gg/grid-areas frame grid)]
|
||||
[:rect {:key (str key "-" x "-" y)
|
||||
:x x
|
||||
:y y
|
||||
:width (- (+ x width) x)
|
||||
:height (- (+ y height) y)
|
||||
:style style}])]))
|
||||
(for [[idx {:keys [x y width height] :as area}] (d/enumerate (gg/grid-areas frame grid))]
|
||||
(cond
|
||||
gutter?
|
||||
[:rect {:key (str key "-" x "-" y)
|
||||
:x x
|
||||
:y y
|
||||
:width (- (+ x width) x)
|
||||
:height (- (+ y height) y)
|
||||
:style {:fill color-value
|
||||
:stroke-width 0
|
||||
:opacity color-opacity}}]
|
||||
|
||||
(and (not gutter?) (= :column (:type grid)))
|
||||
[:*
|
||||
(when (= idx 0)
|
||||
[:line {:key (str key "-" x "-" y "-start")
|
||||
:x1 x
|
||||
:y1 y
|
||||
:x2 x
|
||||
:y2 (+ y height)
|
||||
:style {:stroke color-value
|
||||
:stroke-width (/ 1 zoom)
|
||||
:strokeOpacity color-opacity
|
||||
:fill "none"}}])
|
||||
|
||||
[:line {:key (str key "-" x "-" y "-end")
|
||||
:x1 (+ x width)
|
||||
:y1 y
|
||||
:x2 (+ x width)
|
||||
:y2 (+ y height)
|
||||
:style {:stroke color-value
|
||||
:stroke-width (/ 1 zoom)
|
||||
:strokeOpacity color-opacity
|
||||
:fill "none"}}]]
|
||||
|
||||
(and (not gutter?) (= :row (:type grid)))
|
||||
[:*
|
||||
(when (= idx 0)
|
||||
[:line {:key (str key "-" x "-" y "-start")
|
||||
:x1 x
|
||||
:y1 y
|
||||
:x2 (+ x width)
|
||||
:y2 y
|
||||
:style {:stroke color-value
|
||||
:stroke-width (/ 1 zoom)
|
||||
:strokeOpacity color-opacity
|
||||
:fill "none"}}])
|
||||
|
||||
[:line {:key (str key "-" x "-" y "-end")
|
||||
:x1 x
|
||||
:y1 (+ y height)
|
||||
:x2 (+ x width)
|
||||
:y2 (+ y height)
|
||||
:style {:stroke color-value
|
||||
:stroke-width (/ 1 zoom)
|
||||
:strokeOpacity color-opacity
|
||||
:fill "none"}}]]))]))
|
||||
|
||||
(mf/defc grid-display-frame
|
||||
[{:keys [frame zoom]}]
|
||||
|
|
|
@ -69,6 +69,8 @@
|
|||
(rx/flat-map
|
||||
(fn [[frame-id point]]
|
||||
(->> (snap/get-snap-points page-id frame-id remove-snap? zoom point coord)
|
||||
(rx/map #(mapcat second %))
|
||||
(rx/map #(map :pt %))
|
||||
(rx/map #(vector point % coord)))))
|
||||
(rx/reduce conj []))))
|
||||
|
||||
|
@ -157,22 +159,29 @@
|
|||
|
||||
(mf/defc snap-points
|
||||
{::mf/wrap [mf/memo]}
|
||||
[{:keys [layout zoom objects selected page-id drawing transform modifiers focus] :as props}]
|
||||
[{:keys [layout zoom objects selected page-id drawing modifiers focus] :as props}]
|
||||
(us/assert set? selected)
|
||||
(let [shapes (into [] (keep (d/getf objects)) selected)
|
||||
|
||||
filter-shapes
|
||||
(into selected (mapcat #(cph/get-children-ids objects %)) selected)
|
||||
|
||||
remove-snap?
|
||||
remove-snap-base?
|
||||
(mf/with-memo [layout filter-shapes objects focus]
|
||||
(snap/make-remove-snap layout filter-shapes objects focus))
|
||||
|
||||
shapes (if drawing [drawing] shapes)]
|
||||
(when (or drawing transform)
|
||||
[:& snap-feedback {:shapes shapes
|
||||
:page-id page-id
|
||||
:remove-snap? remove-snap?
|
||||
:zoom zoom
|
||||
:modifiers modifiers}])))
|
||||
remove-snap?
|
||||
(mf/use-callback
|
||||
(mf/deps remove-snap-base?)
|
||||
(fn [{:keys [type grid] :as snap}]
|
||||
(or (remove-snap-base? snap)
|
||||
(and (= type :layout) (= grid :square))
|
||||
(= type :guide))))
|
||||
|
||||
shapes (if drawing [drawing] shapes)]
|
||||
[:& snap-feedback {:shapes shapes
|
||||
:page-id page-id
|
||||
:remove-snap? remove-snap?
|
||||
:zoom zoom
|
||||
:modifiers modifiers}]))
|
||||
|
||||
|
|
|
@ -168,3 +168,10 @@
|
|||
nm (str/trim (str/lower name))]
|
||||
(str/includes? nm st))))
|
||||
|
||||
(defn tap
|
||||
"Works like rx/tap but for normal collections"
|
||||
;; Signature for transducer use
|
||||
([f]
|
||||
(map #(do (f %) %)))
|
||||
([f coll]
|
||||
(map #(do (f %) %) coll)))
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
next-v (fn [cur-val]
|
||||
(+ offset v (* (+ width' gutter) cur-val)))]
|
||||
|
||||
[size width' next-v]))
|
||||
[size width' next-v gutter]))
|
||||
|
||||
(defn- calculate-column-grid
|
||||
[{:keys [width height x y] :as frame} params]
|
||||
|
@ -70,6 +70,20 @@
|
|||
|
||||
[(* col-size row-size) size size next-x next-y]))
|
||||
|
||||
(defn grid-gutter
|
||||
[{:keys [x y width height]} {:keys [type params] :as grid}]
|
||||
|
||||
(case type
|
||||
:column
|
||||
(let [[_ _ _ gutter] (calculate-generic-grid x width params)]
|
||||
gutter)
|
||||
|
||||
:row
|
||||
(let [[_ _ _ gutter] (calculate-generic-grid y height params)]
|
||||
gutter)
|
||||
|
||||
nil))
|
||||
|
||||
(defn grid-areas
|
||||
"Given a frame and the grid parameters returns the areas defined on the grid"
|
||||
[frame grid]
|
||||
|
@ -93,28 +107,25 @@
|
|||
|
||||
(defn grid-snap-points
|
||||
"Returns the snap points for a given grid"
|
||||
([shape coord]
|
||||
(mapcat #(grid-snap-points shape % coord) (:grids shape)))
|
||||
[shape {:keys [type params] :as grid} coord]
|
||||
(when (:display grid)
|
||||
(case type
|
||||
:square
|
||||
(let [{:keys [x y width height]} shape
|
||||
size (-> params :size)]
|
||||
(when (> size 0)
|
||||
(if (= coord :x)
|
||||
(mapcat #(vector (gpt/point (+ x %) y)
|
||||
(gpt/point (+ x %) (+ y height))) (range size width size))
|
||||
(mapcat #(vector (gpt/point x (+ y %))
|
||||
(gpt/point (+ x width) (+ y %))) (range size height size)))))
|
||||
|
||||
([shape {:keys [type params] :as grid} coord]
|
||||
(when (:display grid)
|
||||
(case type
|
||||
:square
|
||||
(let [{:keys [x y width height]} shape
|
||||
size (-> params :size)]
|
||||
(when (> size 0)
|
||||
(if (= coord :x)
|
||||
(mapcat #(vector (gpt/point (+ x %) y)
|
||||
(gpt/point (+ x %) (+ y height))) (range size width size))
|
||||
(mapcat #(vector (gpt/point x (+ y %))
|
||||
(gpt/point (+ x width) (+ y %))) (range size height size)))))
|
||||
:column
|
||||
(when (= coord :x)
|
||||
(->> (grid-areas shape grid)
|
||||
(mapcat grid-area-points)))
|
||||
|
||||
:column
|
||||
(when (= coord :x)
|
||||
(->> (grid-areas shape grid)
|
||||
(mapcat grid-area-points)))
|
||||
|
||||
:row
|
||||
(when (= coord :y)
|
||||
(->> (grid-areas shape grid)
|
||||
(mapcat grid-area-points)))))))
|
||||
:row
|
||||
(when (= coord :y)
|
||||
(->> (grid-areas shape grid)
|
||||
(mapcat grid-area-points))))))
|
||||
|
|
|
@ -9,25 +9,28 @@
|
|||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]))
|
||||
|
||||
(defn selrect-snap-points [{:keys [x y width height]}]
|
||||
(defn selrect-snap-points [{:keys [x y width height] :as selrect}]
|
||||
#{(gpt/point x y)
|
||||
(gpt/point (+ x width) y)
|
||||
(gpt/point (+ x width) (+ y height))
|
||||
(gpt/point x (+ y height))})
|
||||
(gpt/point x (+ y height))
|
||||
(gsh/center-selrect selrect)})
|
||||
|
||||
(defn frame-snap-points [{:keys [x y width height] :as selrect}]
|
||||
(into (selrect-snap-points selrect)
|
||||
#{(gpt/point (+ x (/ width 2)) y)
|
||||
(gpt/point (+ x width) (+ y (/ height 2)))
|
||||
(gpt/point (+ x (/ width 2)) (+ y height))
|
||||
(gpt/point x (+ y (/ height 2)))}))
|
||||
(defn frame-snap-points [{:keys [x y width height blocked hidden] :as selrect}]
|
||||
(when (and (not blocked) (not hidden))
|
||||
(into (selrect-snap-points selrect)
|
||||
#{(gpt/point (+ x (/ width 2)) y)
|
||||
(gpt/point (+ x width) (+ y (/ height 2)))
|
||||
(gpt/point (+ x (/ width 2)) (+ y height))
|
||||
(gpt/point x (+ y (/ height 2)))})))
|
||||
|
||||
(defn shape-snap-points
|
||||
[shape]
|
||||
(let [shape (gsh/transform-shape shape)]
|
||||
(case (:type shape)
|
||||
:frame (-> shape :selrect frame-snap-points)
|
||||
(into #{(gsh/center-shape shape)} (:points shape)))))
|
||||
[{:keys [hidden blocked] :as shape}]
|
||||
(when (and (not blocked) (not hidden))
|
||||
(let [shape (gsh/transform-shape shape)]
|
||||
(case (:type shape)
|
||||
:frame (-> shape :selrect frame-snap-points)
|
||||
(into #{(gsh/center-shape shape)} (:points shape))))))
|
||||
|
||||
(defn guide-snap-points
|
||||
[guide]
|
||||
|
|
|
@ -53,6 +53,19 @@
|
|||
(assoc-in [frame-id :x] (rt/make-tree))
|
||||
(assoc-in [frame-id :y] (rt/make-tree)))))
|
||||
|
||||
(defn get-grids-snap-points
|
||||
[frame coord]
|
||||
(let [grid->snap (fn [[grid-type position]]
|
||||
{:type :layout
|
||||
:id (:id frame)
|
||||
:grid grid-type
|
||||
:pt position})]
|
||||
(->> (:grids frame)
|
||||
(mapcat (fn [grid]
|
||||
(->> (gg/grid-snap-points frame grid coord)
|
||||
(mapv #(vector (:type grid) %)))))
|
||||
(mapv grid->snap))))
|
||||
|
||||
(defn- add-frame
|
||||
[page-data frame]
|
||||
(let [frame-id (:id frame)
|
||||
|
@ -61,17 +74,8 @@
|
|||
(mapv #(array-map :type :shape
|
||||
:id frame-id
|
||||
:pt %)))
|
||||
|
||||
grid-x-data (->> (gg/grid-snap-points frame :x)
|
||||
(mapv #(array-map :type :layout
|
||||
:id frame-id
|
||||
:pt %)))
|
||||
|
||||
grid-y-data (->> (gg/grid-snap-points frame :y)
|
||||
(mapv #(array-map :type :layout
|
||||
:id frame-id
|
||||
:pt %)))]
|
||||
|
||||
grid-x-data (get-grids-snap-points frame :x)
|
||||
grid-y-data (get-grids-snap-points frame :y)]
|
||||
(-> page-data
|
||||
;; Update root frame information
|
||||
(assoc-in [uuid/zero :objects-data frame-id] frame-data)
|
||||
|
@ -107,6 +111,7 @@
|
|||
(mapv #(array-map
|
||||
:type :guide
|
||||
:id (:id guide)
|
||||
:axis (:axis guide)
|
||||
:frame-id (:frame-id guide)
|
||||
:pt %)))]
|
||||
(if-let [frame-id (:frame-id guide)]
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
(let [page (current-page state)
|
||||
frame (cph/get-frame (:objects page))
|
||||
shape (-> (cp/make-minimal-shape type)
|
||||
(gsh/setup {:x 0 :y 0 :width 1 :height 1})
|
||||
(cp/setup-shape {:x 0 :y 0 :width 1 :height 1})
|
||||
(merge props))]
|
||||
(swap! idmap assoc label (:id shape))
|
||||
(update state :workspace-data
|
||||
|
|
Loading…
Add table
Reference in a new issue