mirror of
https://github.com/penpot/penpot.git
synced 2025-06-02 06:41:37 +02:00
Get rid of buggy reactive locks and refactor all related code.
This commit is contained in:
parent
bce58df413
commit
b0de23b011
18 changed files with 611 additions and 516 deletions
|
@ -16,7 +16,6 @@
|
|||
[uxbox.main.data.shapes :as uds]
|
||||
[uxbox.main.ui.keyboard :as kbd]
|
||||
[uxbox.util.geom.point :as gpt]
|
||||
[uxbox.util.rlocks :as rlocks]
|
||||
[uxbox.util.dom :as dom]))
|
||||
|
||||
;; --- Refs
|
||||
|
@ -37,12 +36,13 @@
|
|||
|
||||
;; --- Movement
|
||||
|
||||
;; TODO: implement in the same way as drawing (move under uxbox.main.data.workspace.)
|
||||
|
||||
(defn start-move
|
||||
[]
|
||||
(letfn [(on-move [shape delta]
|
||||
(st/emit! (uds/apply-temporal-displacement shape delta)))
|
||||
(on-stop [{:keys [id] :as shape}]
|
||||
(rlocks/release! :shape/move)
|
||||
(st/emit! (uds/apply-displacement shape)))
|
||||
(on-start [shape]
|
||||
(let [stoper (->> streams/events
|
||||
|
@ -55,7 +55,6 @@
|
|||
(when @refs/selected-alignment
|
||||
(st/emit! (uds/initial-align-shape shape)))
|
||||
(rx/subscribe stream on-move nil on-stop)))]
|
||||
(rlocks/acquire! :shape/move)
|
||||
(run! on-start @selected-ref)))
|
||||
|
||||
;; --- Events
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
(mx/defc path-shape
|
||||
{:mixins [mx/static]}
|
||||
[{:keys [id tmp-resize-xform tmp-displacement rotation] :as shape}]
|
||||
|
||||
(let [shape (cond-> shape
|
||||
tmp-displacement (geom/transform (gmt/translate-matrix tmp-displacement))
|
||||
tmp-resize-xform (geom/transform tmp-resize-xform)
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
[uxbox.main.ui.shapes.common :as scommon]
|
||||
[uxbox.main.geom :as geom]
|
||||
[uxbox.util.mixins :as mx :include-macros true]
|
||||
[uxbox.util.rlocks :as rlocks]
|
||||
[uxbox.util.geom.matrix :as gmt]
|
||||
[uxbox.util.geom.point :as gpt]
|
||||
[uxbox.util.dom :as dom]))
|
||||
|
@ -209,8 +208,7 @@
|
|||
(apply st/emit! (sequence xf ids))))
|
||||
|
||||
(on-end []
|
||||
(apply st/emit! (map uds/apply-resize-matrix ids))
|
||||
(rlocks/release! :shape/resize))]
|
||||
(apply st/emit! (map uds/apply-resize-matrix ids)))]
|
||||
|
||||
(let [shape (->> (geom/shape->rect-shape shape)
|
||||
(geom/size))
|
||||
|
@ -229,7 +227,6 @@
|
|||
(rx/with-latest-from vector streams/mouse-position-ctrl)
|
||||
(rx/scan accumulate-width shape)
|
||||
(rx/map (partial calculate-ratio shape)))]
|
||||
(rlocks/acquire! :shape/resize)
|
||||
(rx/subscribe stream
|
||||
(partial on-resize shape)
|
||||
nil
|
||||
|
@ -316,27 +313,30 @@
|
|||
|
||||
;; --- Selection Handlers (Component)
|
||||
|
||||
(defn get-path-edition-stoper
|
||||
[stream]
|
||||
(letfn [(stoper-event? [{:keys [type shift] :as event}]
|
||||
(and (uev/mouse-event? event) (= type :up)))]
|
||||
(rx/merge
|
||||
(rx/filter stoper-event? stream)
|
||||
(->> stream
|
||||
(rx/filter #(= % ::uev/interrupt))
|
||||
(rx/take 1)))))
|
||||
|
||||
(defn start-path-edition
|
||||
[shape-id index]
|
||||
(letfn [(on-move [delta]
|
||||
(st/emit! (uds/update-path shape-id index delta)))
|
||||
(on-end []
|
||||
(rlocks/release! :shape/resize))]
|
||||
(let [stoper (->> streams/events
|
||||
(rx/map first)
|
||||
(rx/filter #(= % :mouse/up))
|
||||
(rx/take 1))
|
||||
(st/emit! (uds/update-path shape-id index delta)))]
|
||||
(let [stoper (get-path-edition-stoper streams/events)
|
||||
stream (rx/take-until stoper streams/mouse-position-deltas)]
|
||||
(rlocks/acquire! :shape/resize)
|
||||
(when @refs/selected-alignment
|
||||
(st/emit! (uds/initial-path-point-align shape-id index)))
|
||||
(rx/subscribe stream on-move nil on-end))))
|
||||
(rx/subscribe stream on-move))))
|
||||
|
||||
(mx/defc path-edition-selection-handlers
|
||||
[{:keys [id points] :as shape} zoom]
|
||||
(letfn [(on-mouse-down [index event]
|
||||
(dom/stop-propagation event)
|
||||
(rlocks/acquire! :shape/resize)
|
||||
(start-path-edition id index))]
|
||||
[:g.controls
|
||||
(for [[index {:keys [x y]}] (map-indexed vector points)]
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
[uxbox.util.color :as color]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.geom.matrix :as gmt]
|
||||
[uxbox.util.rlocks :as rlocks]
|
||||
[uxbox.util.mixins :as mx :include-macros true])
|
||||
(:import goog.events.EventType))
|
||||
|
||||
|
@ -48,6 +47,8 @@
|
|||
(letfn [(on-mouse-down [event]
|
||||
(handle-mouse-down event shape selected))
|
||||
(on-double-click [event]
|
||||
;; TODO: handle grouping event propagation
|
||||
;; TODO: handle actions locking properly
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! (uds/start-edition-mode id)))]
|
||||
[:g.shape {:class (when selected? "selected")
|
||||
|
@ -149,11 +150,9 @@
|
|||
own))
|
||||
|
||||
(mx/defc text-shape-wrapper
|
||||
{
|
||||
:did-mount text-shape-wrapper-did-mount
|
||||
{:did-mount text-shape-wrapper-did-mount
|
||||
:did-remount text-shape-wrapper-did-remount}
|
||||
[{:keys [id tmp-resize-xform tmp-displacement drawing?] :as shape}]
|
||||
(println "text-shape-wrapper" shape)
|
||||
(let [xfmt (cond-> (gmt/matrix)
|
||||
tmp-displacement (gmt/translate tmp-displacement)
|
||||
tmp-resize-xform (gmt/multiply tmp-resize-xform))
|
||||
|
@ -182,7 +181,6 @@
|
|||
(let [style (make-style shape)]
|
||||
[:div {:style style} content]))
|
||||
|
||||
|
||||
;; --- Text Shape Html
|
||||
|
||||
(mx/defc text-shape
|
||||
|
|
|
@ -15,22 +15,21 @@
|
|||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.streams :as streams]
|
||||
[uxbox.main.user-events :as uev]
|
||||
[uxbox.main.geom :as geom]
|
||||
[uxbox.main.data.projects :as dp]
|
||||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.data.workspace :as udw]
|
||||
[uxbox.main.data.shapes :as uds]
|
||||
[uxbox.main.ui.keyboard :as kbd]
|
||||
[uxbox.main.ui.shapes :as uus]
|
||||
[uxbox.main.ui.shapes.selection :refer (selection-handlers)]
|
||||
[uxbox.main.ui.shapes.selection :refer [selection-handlers]]
|
||||
[uxbox.main.ui.workspace.scroll :as scroll]
|
||||
[uxbox.main.ui.workspace.drawarea :refer (draw-area)]
|
||||
[uxbox.main.ui.workspace.ruler :refer (ruler)]
|
||||
[uxbox.main.ui.workspace.selrect :refer (selrect)]
|
||||
[uxbox.main.ui.workspace.grid :refer (grid)]
|
||||
[uxbox.main.ui.workspace.drawarea :refer [draw-area]]
|
||||
[uxbox.main.ui.workspace.ruler :refer [ruler]]
|
||||
[uxbox.main.ui.workspace.grid :refer [grid]]
|
||||
[uxbox.util.geom.point :as gpt]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.data :refer (parse-int)]
|
||||
[uxbox.util.mixins :as mx :include-macros true]
|
||||
[uxbox.util.rlocks :as rlocks])
|
||||
[uxbox.util.data :refer [parse-int]]
|
||||
[uxbox.util.mixins :as mx :include-macros true])
|
||||
(:import goog.events.EventType))
|
||||
|
||||
;; --- Background
|
||||
|
@ -59,6 +58,23 @@
|
|||
[:span {:alt "y"}
|
||||
(str "Y: " (:y coords "-"))]]))
|
||||
|
||||
;; --- Selection Rect
|
||||
|
||||
(def selrect-ref
|
||||
(-> (l/key :selrect)
|
||||
(l/derive refs/workspace)))
|
||||
|
||||
(mx/defc selrect
|
||||
{:mixins [mx/static mx/reactive]}
|
||||
[]
|
||||
(when-let [rect (mx/react selrect-ref)]
|
||||
(let [{:keys [x1 y1 width height]} (geom/size rect)]
|
||||
[:rect.selection-rect
|
||||
{:x x1
|
||||
:y y1
|
||||
:width width
|
||||
:height height}])))
|
||||
|
||||
;; --- Cursor tooltip
|
||||
|
||||
(defn- get-shape-tooltip
|
||||
|
@ -137,12 +153,8 @@
|
|||
:shift? shift?
|
||||
:ctrl? ctrl?}]
|
||||
(st/emit! (uev/keyboard-event :down key ctrl? shift?))
|
||||
|
||||
;; TODO: remove (deprecated)
|
||||
#_(rx/push! streams/events-b [:key/down opts])
|
||||
(when (kbd/space? event)
|
||||
(st/emit! (dw/start-viewport-positioning)))))
|
||||
#_(rlocks/acquire! :workspace/scroll)
|
||||
(st/emit! (udw/start-viewport-positioning)))))
|
||||
|
||||
(on-key-up [event]
|
||||
(let [key (.-keyCode event)
|
||||
|
@ -152,10 +164,8 @@
|
|||
:shift? shift?
|
||||
:ctrl? ctrl?}]
|
||||
(when (kbd/space? event)
|
||||
(st/emit! (dw/stop-viewport-positioning)))
|
||||
(st/emit! (uev/keyboard-event :up key ctrl? shift?))
|
||||
;; TODO: remove (deprecated)
|
||||
#_(rx/push! streams/events-b [:key/up opts])))
|
||||
(st/emit! (udw/stop-viewport-positioning)))
|
||||
(st/emit! (uev/keyboard-event :up key ctrl? shift?))))
|
||||
|
||||
(on-mousemove [event]
|
||||
(let [wpt (gpt/point (.-clientX event)
|
||||
|
@ -169,9 +179,7 @@
|
|||
:window-coords wpt
|
||||
:viewport-coords vpt
|
||||
:canvas-coords cpt}]
|
||||
(st/emit! (uev/pointer-event wpt vpt cpt ctrl? shift?))
|
||||
;; TODO: remove (deprecated)
|
||||
#_(rx/push! streams/mouse-b event)))]
|
||||
(st/emit! (uev/pointer-event wpt vpt cpt ctrl? shift?))))]
|
||||
|
||||
(let [key1 (events/listen js/document EventType.MOUSEMOVE on-mousemove)
|
||||
key2 (events/listen js/document EventType.KEYDOWN on-key-down)
|
||||
|
@ -207,15 +215,10 @@
|
|||
shift? (kbd/shift? event)
|
||||
opts {:shift? shift?
|
||||
:ctrl? ctrl?}]
|
||||
(st/emit! (uev/mouse-event :down ctrl? shift?))
|
||||
;; TODO: remove (deprecated)
|
||||
#_(rx/push! streams/events-b [:mouse/down opts]))
|
||||
(if (:drawing workspace)
|
||||
(rlocks/acquire! :ui/draw)
|
||||
(do
|
||||
(when (seq (:selected workspace))
|
||||
(rlocks/release! :shape/edition))
|
||||
(rlocks/acquire! :ui/selrect))))
|
||||
(st/emit! (uev/mouse-event :down ctrl? shift?)))
|
||||
(if-let [object (:drawing workspace)]
|
||||
(st/emit! (udw/start-drawing object))
|
||||
(st/emit! (udw/start-selrect))))
|
||||
(on-context-menu [event]
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event)
|
||||
|
@ -223,36 +226,28 @@
|
|||
shift? (kbd/shift? event)
|
||||
opts {:shift? shift?
|
||||
:ctrl? ctrl?}]
|
||||
(st/emit! (uev/mouse-event :context-menu ctrl? shift?))
|
||||
;; TODO: remove (deprecated)
|
||||
#_(rx/push! streams/events-b [:mouse/right-click opts])))
|
||||
(st/emit! (uev/mouse-event :context-menu ctrl? shift?))))
|
||||
(on-mouse-up [event]
|
||||
(dom/stop-propagation event)
|
||||
(let [ctrl? (kbd/ctrl? event)
|
||||
shift? (kbd/shift? event)
|
||||
opts {:shift? shift?
|
||||
:ctrl? ctrl?}]
|
||||
(st/emit! (uev/mouse-event :up ctrl? shift?))
|
||||
;; TODO: remove (deprecated)
|
||||
#_(rx/push! streams/events-b [:mouse/up])))
|
||||
(st/emit! (uev/mouse-event :up ctrl? shift?))))
|
||||
(on-click [event]
|
||||
(dom/stop-propagation event)
|
||||
(let [ctrl? (kbd/ctrl? event)
|
||||
shift? (kbd/shift? event)
|
||||
opts {:shift? shift?
|
||||
:ctrl? ctrl?}]
|
||||
(st/emit! (uev/mouse-event :click ctrl? shift?))
|
||||
;; TODO: remove (deprecated)
|
||||
#_(rx/push! streams/events-b [:mouse/click opts])))
|
||||
(st/emit! (uev/mouse-event :click ctrl? shift?))))
|
||||
(on-double-click [event]
|
||||
(dom/stop-propagation event)
|
||||
(let [ctrl? (kbd/ctrl? event)
|
||||
shift? (kbd/shift? event)
|
||||
opts {:shift? shift?
|
||||
:ctrl? ctrl?}]
|
||||
(st/emit! (uev/mouse-event :double-click ctrl? shift?))
|
||||
;; TODO: remove (deprecated)
|
||||
#_(rx/push! streams/events-b [:mouse/double-click opts])))]
|
||||
(st/emit! (uev/mouse-event :double-click ctrl? shift?))))]
|
||||
[:div
|
||||
(coordinates)
|
||||
(when tooltip
|
||||
|
|
|
@ -8,14 +8,13 @@
|
|||
"Draw interaction and component."
|
||||
(:require [beicon.core :as rx]
|
||||
[potok.core :as ptk]
|
||||
[lentes.core :as l]
|
||||
[uxbox.util.mixins :as mx :include-macros true]
|
||||
[uxbox.util.rlocks :as rlocks]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.constants :as c]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.streams :as streams]
|
||||
[uxbox.main.workers :as uwrk]
|
||||
[uxbox.main.user-events :as uev]
|
||||
[uxbox.main.data.workspace :as udw]
|
||||
[uxbox.main.data.shapes :as uds]
|
||||
[uxbox.main.ui.shapes :as shapes]
|
||||
|
@ -24,67 +23,36 @@
|
|||
[uxbox.util.geom.path :as path]
|
||||
[uxbox.util.dom :as dom]))
|
||||
|
||||
;; --- State
|
||||
;; --- Refs
|
||||
|
||||
(defonce drawing-stoper (rx/subject))
|
||||
(defonce drawing-shape (atom nil))
|
||||
(defonce drawing-position (atom nil))
|
||||
(def drawing-shape
|
||||
(-> (l/key :drawing)
|
||||
(l/derive refs/workspace)))
|
||||
|
||||
(def ^:private canvas-coords
|
||||
(gpt/point c/canvas-start-x
|
||||
c/canvas-start-y))
|
||||
;; --- Components
|
||||
|
||||
;; --- Draw Area (Component)
|
||||
|
||||
(declare watch-draw-actions)
|
||||
(declare on-init-draw)
|
||||
|
||||
(defn- watch-draw-actions
|
||||
[]
|
||||
(let [stream (->> (rx/map first rlocks/stream)
|
||||
(rx/filter #(= % :ui/draw)))]
|
||||
(rx/subscribe stream on-init-draw)))
|
||||
|
||||
(defn- draw-area-will-mount
|
||||
[own]
|
||||
(assoc own ::sub (watch-draw-actions)))
|
||||
|
||||
(defn- draw-area-will-unmount
|
||||
[own]
|
||||
(.close (::sub own))
|
||||
(dissoc own ::sub))
|
||||
|
||||
(declare generic-shape-draw-area)
|
||||
(declare path-shape-draw-area)
|
||||
(declare generic-draw-area)
|
||||
(declare path-draw-area)
|
||||
|
||||
(mx/defc draw-area
|
||||
{:will-mount draw-area-will-mount
|
||||
:will-unmount draw-area-will-unmount
|
||||
:mixins [mx/static mx/reactive]}
|
||||
{:mixins [mx/static mx/reactive]}
|
||||
[]
|
||||
(let [shape (mx/react drawing-shape)
|
||||
position (mx/react drawing-position)]
|
||||
(when shape
|
||||
(if (= (:type shape) :path)
|
||||
(path-shape-draw-area shape)
|
||||
(generic-shape-draw-area shape position)))))
|
||||
(when-let [shape (mx/react drawing-shape)]
|
||||
(if (= (:type shape) :path)
|
||||
(path-draw-area shape)
|
||||
(generic-draw-area shape))))
|
||||
|
||||
(mx/defc generic-shape-draw-area
|
||||
[shape position]
|
||||
(if position
|
||||
(-> (assoc shape :drawing? true)
|
||||
(geom/resize position)
|
||||
(shapes/render-component))
|
||||
(-> (assoc shape :drawing? true)
|
||||
(shapes/render-component))))
|
||||
(mx/defc generic-draw-area
|
||||
[shape]
|
||||
(-> (assoc shape :drawing? true)
|
||||
(shapes/render-component)))
|
||||
|
||||
(mx/defc path-shape-draw-area
|
||||
(mx/defc path-draw-area
|
||||
[{:keys [points] :as shape}]
|
||||
(letfn [(on-click [event]
|
||||
(dom/stop-propagation event)
|
||||
(swap! drawing-shape drop-last-point)
|
||||
(st/emit! (udw/set-tooltip nil))
|
||||
(rx/push! drawing-stoper true))
|
||||
(st/emit! (udw/set-tooltip nil)
|
||||
(udw/close-drawing-path)))
|
||||
(on-mouse-enter [event]
|
||||
(st/emit! (udw/set-tooltip "Click to close the path")))
|
||||
(on-mouse-leave [event]
|
||||
|
@ -93,227 +61,14 @@
|
|||
(let [points (:points shape)
|
||||
points (vec (butlast points))]
|
||||
(assoc shape :points points :close? true)))]
|
||||
(let [{:keys [x y]} (first points)]
|
||||
(when-let [{:keys [x y]} (first points)]
|
||||
[:g
|
||||
(-> (assoc shape :drawing? true)
|
||||
(shapes/render-component))
|
||||
(when-not (:free shape)
|
||||
[:circle.close-bezier {:cx x
|
||||
:cy y
|
||||
:r 5
|
||||
:on-click on-click
|
||||
:on-mouse-enter on-mouse-enter
|
||||
:on-mouse-leave on-mouse-leave}])])))
|
||||
|
||||
;; --- Drawing Initialization
|
||||
|
||||
(declare on-init-draw-icon)
|
||||
(declare on-init-draw-path)
|
||||
(declare on-init-draw-free-path)
|
||||
(declare on-init-draw-generic)
|
||||
|
||||
(defn- on-init-draw
|
||||
"Function execution when draw shape operation is requested.
|
||||
This is a entry point for the draw interaction."
|
||||
[]
|
||||
(when-let [shape (:drawing @refs/workspace)]
|
||||
(case (:type shape)
|
||||
:icon (on-init-draw-icon shape)
|
||||
:image (on-init-draw-icon shape)
|
||||
:path (if (:free shape)
|
||||
(on-init-draw-free-path shape)
|
||||
(on-init-draw-path shape))
|
||||
(on-init-draw-generic shape))))
|
||||
|
||||
;; --- Icon Drawing
|
||||
|
||||
(defn- on-init-draw-icon
|
||||
[{:keys [metadata] :as shape}]
|
||||
(let [{:keys [x y]} (gpt/divide @refs/canvas-mouse-position @refs/selected-zoom)
|
||||
{:keys [width height]} metadata
|
||||
proportion (/ width height)
|
||||
props {:x1 x
|
||||
:y1 y
|
||||
:x2 (+ x 200)
|
||||
:y2 (+ y (/ 200 proportion))}
|
||||
shape (geom/setup shape props)]
|
||||
(st/emit! (uds/add-shape shape)
|
||||
(udw/select-for-drawing nil)
|
||||
(uds/select-first-shape))
|
||||
(rlocks/release! :ui/draw)))
|
||||
|
||||
;; --- Path Drawing
|
||||
|
||||
(def ^:private immanted-zones
|
||||
(let [transform #(vector (- % 7) (+ % 7) %)]
|
||||
(concat
|
||||
(mapv transform (range 0 181 15))
|
||||
(mapv (comp transform -) (range 0 181 15)))))
|
||||
|
||||
(defn- align-position
|
||||
[angle pos]
|
||||
(reduce (fn [pos [a1 a2 v]]
|
||||
(if (< a1 angle a2)
|
||||
(reduced (gpt/update-angle pos v))
|
||||
pos))
|
||||
pos
|
||||
immanted-zones))
|
||||
|
||||
(defn- translate-to-canvas
|
||||
[point]
|
||||
(let [zoom @refs/selected-zoom
|
||||
ccords (gpt/multiply canvas-coords zoom)]
|
||||
(-> point
|
||||
(gpt/subtract ccords)
|
||||
(gpt/divide zoom))))
|
||||
|
||||
(defn- conditional-align
|
||||
[point]
|
||||
(if @refs/selected-alignment
|
||||
(uwrk/align-point point)
|
||||
(rx/of point)))
|
||||
|
||||
(defn- on-init-draw-path
|
||||
[shape]
|
||||
(letfn [(stoper-event? [{:keys [type shift] :as event}]
|
||||
(or (and (uev/mouse-event? event)
|
||||
(or (and (= type :double-click) shift)
|
||||
(= type :context-menu)))
|
||||
(and (uev/keyboard-event? event)
|
||||
(= type :down)
|
||||
(= 13 (:key event)))))
|
||||
|
||||
(new-point-event? [[type opts]]
|
||||
(and (= type :mouse/click)
|
||||
(false? (:shift? opts))))]
|
||||
|
||||
(let [mouse (->> (rx/sample 10 streams/viewport-mouse-position)
|
||||
(rx/mapcat conditional-align)
|
||||
(rx/map translate-to-canvas))
|
||||
stoper (->> (rx/merge
|
||||
(rx/take 1 drawing-stoper)
|
||||
(rx/filter stoper-event? streams/events))
|
||||
(rx/take 1))
|
||||
firstpos (rx/take 1 mouse)
|
||||
stream (->> (rx/take-until stoper mouse)
|
||||
(rx/skip-while #(nil? @drawing-shape))
|
||||
(rx/with-latest-from vector streams/mouse-position-ctrl))
|
||||
ptstream (->> (rx/take-until stoper streams/events)
|
||||
(rx/filter new-point-event?)
|
||||
(rx/with-latest-from vector mouse)
|
||||
(rx/map second))
|
||||
counter (atom 0)]
|
||||
(letfn [(append-point [{:keys [type] :as shape} point]
|
||||
(let [point (gpt/point point)]
|
||||
(update shape :points conj point)))
|
||||
|
||||
(update-point [{:keys [type points] :as shape} point index]
|
||||
(let [point (gpt/point point)
|
||||
points (:points shape)]
|
||||
(assoc-in shape [:points index] point)))
|
||||
|
||||
(on-first-point [point]
|
||||
(let [shape (append-point shape point)]
|
||||
(swap! counter inc)
|
||||
(reset! drawing-shape shape)))
|
||||
|
||||
(on-click [point]
|
||||
(let [shape (append-point @drawing-shape point)]
|
||||
(swap! counter inc)
|
||||
(reset! drawing-shape shape)))
|
||||
|
||||
(on-assisted-draw [point]
|
||||
(let [center (get-in @drawing-shape [:points (dec @counter)])
|
||||
point (as-> point $
|
||||
(gpt/subtract $ center)
|
||||
(align-position (gpt/angle $) $)
|
||||
(gpt/add $ center))]
|
||||
(->> (update-point @drawing-shape point @counter)
|
||||
(reset! drawing-shape))))
|
||||
|
||||
(on-free-draw [point]
|
||||
(->> (update-point @drawing-shape point @counter)
|
||||
(reset! drawing-shape)))
|
||||
|
||||
(on-draw [[point ctrl?]]
|
||||
(if ctrl?
|
||||
(on-assisted-draw point)
|
||||
(on-free-draw point)))
|
||||
|
||||
(on-end []
|
||||
(let [shape @drawing-shape]
|
||||
(st/emit! (uds/add-shape shape)
|
||||
(udw/select-for-drawing nil)
|
||||
(uds/select-first-shape))
|
||||
(reset! drawing-shape nil)
|
||||
(reset! drawing-position nil)
|
||||
(rlocks/release! :ui/draw)))]
|
||||
|
||||
(rx/subscribe firstpos on-first-point)
|
||||
(rx/subscribe ptstream on-click)
|
||||
(rx/subscribe stream on-draw nil on-end)))))
|
||||
|
||||
(defn- on-init-draw-free-path
|
||||
[shape]
|
||||
(let [mouse (->> (rx/sample 10 streams/viewport-mouse-position)
|
||||
(rx/mapcat conditional-align)
|
||||
(rx/map translate-to-canvas))
|
||||
stoper (->> streams/events
|
||||
(rx/filter uev/mouse-up?)
|
||||
(rx/take 1))
|
||||
stream (rx/take-until stoper mouse)]
|
||||
(letfn [(simplify-shape [{:keys [points] :as shape}]
|
||||
(let [prevnum (count points)
|
||||
points (path/simplify points 0.2)]
|
||||
(println "path simplification: previous=" prevnum
|
||||
" current=" (count points))
|
||||
(assoc shape :points points)))
|
||||
|
||||
(on-draw [point]
|
||||
(let [point (gpt/point point)
|
||||
shape (-> (or @drawing-shape shape)
|
||||
(update :points conj point))]
|
||||
(reset! drawing-shape shape)))
|
||||
|
||||
(on-end []
|
||||
(let [shape (simplify-shape @drawing-shape)]
|
||||
(st/emit! (uds/add-shape shape)
|
||||
(udw/select-for-drawing nil)
|
||||
(uds/select-first-shape))
|
||||
(reset! drawing-shape nil)
|
||||
(reset! drawing-position nil)
|
||||
(rlocks/release! :ui/draw)))]
|
||||
|
||||
(rx/subscribe stream on-draw nil on-end))))
|
||||
|
||||
(defn- on-init-draw-generic
|
||||
[shape]
|
||||
(let [mouse (->> streams/viewport-mouse-position
|
||||
(rx/mapcat conditional-align)
|
||||
(rx/map translate-to-canvas))
|
||||
stoper (->> streams/events
|
||||
(rx/filter uev/mouse-up?)
|
||||
(rx/take 1))
|
||||
firstpos (rx/take 1 mouse)
|
||||
stream (->> (rx/take-until stoper mouse)
|
||||
(rx/skip-while #(nil? @drawing-shape))
|
||||
(rx/with-latest-from vector streams/mouse-position-ctrl))]
|
||||
|
||||
(letfn [(on-start [{:keys [x y] :as pt}]
|
||||
(let [shape (geom/setup shape {:x1 x :y1 y :x2 x :y2 y})]
|
||||
(reset! drawing-shape shape)))
|
||||
|
||||
(on-draw [[pt ctrl?]]
|
||||
(reset! drawing-position (assoc pt :lock ctrl?)))
|
||||
(on-end []
|
||||
(let [shape @drawing-shape
|
||||
shpos @drawing-position
|
||||
shape (geom/resize shape shpos)]
|
||||
(st/emit! (uds/add-shape shape)
|
||||
(udw/select-for-drawing nil)
|
||||
(uds/select-first-shape))
|
||||
(reset! drawing-position nil)
|
||||
(reset! drawing-shape nil)
|
||||
(rlocks/release! :ui/draw)))]
|
||||
(rx/subscribe firstpos on-start)
|
||||
(rx/subscribe stream on-draw nil on-end))))
|
||||
:cy y
|
||||
:r 5
|
||||
:on-click on-click
|
||||
:on-mouse-enter on-mouse-enter
|
||||
:on-mouse-leave on-mouse-leave}])])))
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
[potok.core :as ptk]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.util.mixins :as mx :include-macros true]
|
||||
[uxbox.util.rlocks :as rlocks]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.geom.point :as gpt]))
|
||||
|
||||
|
|
|
@ -1,112 +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) 2015-2017 Andrey Antukh <niwi@niwi.nz>
|
||||
;; Copyright (c) 2015-2017 Juan de la Cruz <delacruzgarciajuan@gmail.com>
|
||||
|
||||
(ns uxbox.main.ui.workspace.selrect
|
||||
"Mouse selection interaction and component."
|
||||
(:require [beicon.core :as rx]
|
||||
[potok.core :as ptk]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.constants :as c]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.streams :as streams]
|
||||
[uxbox.main.user-events :as uev]
|
||||
[uxbox.main.geom :as geom]
|
||||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.data.shapes :as uds]
|
||||
[uxbox.util.mixins :as mx :include-macros true]
|
||||
[uxbox.util.rlocks :as rlocks]))
|
||||
|
||||
(defonce position (atom nil))
|
||||
|
||||
;; --- Selrect (Component)
|
||||
|
||||
(declare selrect->rect)
|
||||
(declare watch-selrect-actions)
|
||||
|
||||
(defn- will-mount
|
||||
[own]
|
||||
(assoc own ::sub (watch-selrect-actions)))
|
||||
|
||||
(defn- will-unmount
|
||||
[own]
|
||||
(.close (::sub own))
|
||||
(dissoc own ::sub))
|
||||
|
||||
(mx/defc selrect
|
||||
{:will-mount will-mount
|
||||
:will-unmount will-unmount
|
||||
:mixins [mx/static mx/reactive]}
|
||||
[]
|
||||
(when-let [data (mx/react position)]
|
||||
(let [{:keys [x1 y1 width height]} (geom/size (selrect->rect data))]
|
||||
[:rect.selection-rect
|
||||
{:x x1
|
||||
:y y1
|
||||
:width width
|
||||
:height height}])))
|
||||
|
||||
;; --- Interaction
|
||||
|
||||
(defn- selrect->rect
|
||||
[{:keys [start current] :as data}]
|
||||
(let [start-x (min (:x start) (:x current))
|
||||
start-y (min (:y start) (:y current))
|
||||
end-x (max (:x start) (:x current))
|
||||
end-y (max (:y start) (:y current))]
|
||||
{:x1 start-x
|
||||
:y1 start-y
|
||||
:x2 end-x
|
||||
:y2 end-y
|
||||
:type :rect}))
|
||||
|
||||
(defn- translate-to-canvas
|
||||
"Translate the given rect to the canvas coordinates system."
|
||||
[rect]
|
||||
(let [zoom @refs/selected-zoom
|
||||
startx (* c/canvas-start-x zoom)
|
||||
starty (* c/canvas-start-y zoom)]
|
||||
(assoc rect
|
||||
:x1 (/ (- (:x1 rect) startx) zoom)
|
||||
:y1 (/ (- (:y1 rect) starty) zoom)
|
||||
:x2 (/ (- (:x2 rect) startx) zoom)
|
||||
:y2 (/ (- (:y2 rect) starty) zoom))))
|
||||
|
||||
(declare on-start)
|
||||
|
||||
(defn- watch-selrect-actions
|
||||
[]
|
||||
(let [stream (->> (rx/map first rlocks/stream)
|
||||
(rx/filter #(= % :ui/selrect)))]
|
||||
(rx/subscribe stream on-start)))
|
||||
|
||||
(defn- on-move
|
||||
"Function executed on each mouse movement while selrect
|
||||
interaction is active."
|
||||
[pos]
|
||||
(swap! position assoc :current pos))
|
||||
|
||||
(defn- on-complete
|
||||
"Function executed when the selection rect
|
||||
interaction is terminated."
|
||||
[]
|
||||
(let [rect (-> (selrect->rect @position)
|
||||
(translate-to-canvas))]
|
||||
(st/emit! (uds/deselect-all)
|
||||
(uds/select-shapes-by-selrect rect))
|
||||
(rlocks/release! :ui/selrect)
|
||||
(reset! position nil)))
|
||||
|
||||
(defn- on-start
|
||||
"Function execution when selrect action is started."
|
||||
[]
|
||||
(let [stoper (->> streams/events
|
||||
(rx/filter uev/mouse-up?)
|
||||
(rx/take 1))
|
||||
stream (rx/take-until stoper streams/viewport-mouse-position)
|
||||
pos @refs/viewport-mouse-position]
|
||||
(reset! position {:start pos :current pos})
|
||||
(rx/subscribe stream on-move nil on-complete)))
|
|
@ -12,6 +12,7 @@
|
|||
[uxbox.main.store :as st]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.user-events :as uev]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.util.i18n :refer (tr)]
|
||||
[uxbox.util.router :as r]
|
||||
|
@ -82,7 +83,8 @@
|
|||
|
||||
(defn- select-for-draw
|
||||
[shape]
|
||||
(st/emit! (dw/select-for-drawing shape)))
|
||||
(st/emit! ::uev/interrupt
|
||||
(dw/select-for-drawing shape)))
|
||||
|
||||
(mx/defc draw-toolbox
|
||||
{:mixins [mx/static mx/reactive]}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue