diff --git a/frontend/src/uxbox/main/data/workspace/scroll.cljs b/frontend/src/uxbox/main/data/workspace/scroll.cljs index 34f796a44..cccd18411 100644 --- a/frontend/src/uxbox/main/data/workspace/scroll.cljs +++ b/frontend/src/uxbox/main/data/workspace/scroll.cljs @@ -9,6 +9,7 @@ are related to UI logic." (:require [beicon.core :as rx] [potok.core :as ptk] + [uxbox.main.refs :as refs] [uxbox.main.streams :as streams] [uxbox.util.mixins :as mx :include-macros true] [uxbox.util.rlocks :as rlocks] @@ -23,9 +24,9 @@ [stream] (let [stoper (->> (rx/filter stop-viewport-positioning? stream) (rx/take 1)) - reference @streams/mouse-viewport-a + reference @refs/viewport-mouse-position dom (dom/get-element "workspace-canvas")] - (->> streams/mouse-viewport-s + (->> streams/viewport-mouse-position (rx/take-until stoper) (rx/map (fn [point] (let [{:keys [x y]} (gpt/subtract point reference) diff --git a/frontend/src/uxbox/main/refs.cljs b/frontend/src/uxbox/main/refs.cljs index 75a0da1d3..9afdfe283 100644 --- a/frontend/src/uxbox/main/refs.cljs +++ b/frontend/src/uxbox/main/refs.cljs @@ -73,6 +73,18 @@ (-> (l/lens alignment-activated?) (l/derive flags))) +(def canvas-mouse-position + (-> (l/in [:pointer :canvas]) + (l/derive workspace))) + +(def viewport-mouse-position + (-> (l/in [:pointer :viewport]) + (l/derive workspace))) + +(def window-mouse-position + (-> (l/in [:pointer :window]) + (l/derive workspace))) + diff --git a/frontend/src/uxbox/main/streams.cljs b/frontend/src/uxbox/main/streams.cljs index 453a37ac1..f60096016 100644 --- a/frontend/src/uxbox/main/streams.cljs +++ b/frontend/src/uxbox/main/streams.cljs @@ -7,6 +7,8 @@ (ns uxbox.main.streams "A collection of derived streams." (:require [beicon.core :as rx] + [uxbox.main.store :as st] + [uxbox.main.user-events :as uev] [uxbox.main.refs :as refs] [uxbox.main.workers :as uwrk] [uxbox.util.geom.point :as gpt])) @@ -28,40 +30,36 @@ ;; --- Events -(defonce events-b (rx/subject)) -(defonce events-s (rx/dedupe events-b)) +(defn- user-interaction-event? + [event] + (or (uev/keyboard-event? event) + (uev/mouse-event? event))) + +(defonce events + (rx/filter user-interaction-event? st/stream)) ;; --- Mouse Position Stream -(defonce mouse-b (rx/subject)) -(defonce mouse-s (rx/dedupe mouse-b)) +(defonce mouse-position + (rx/filter uev/pointer-event? st/stream)) -(defonce mouse-canvas-s - (->> mouse-s - (rx/map :canvas-coords) +(defonce canvas-mouse-position + (->> mouse-position + (rx/map :canvas) (rx/share))) -(defonce mouse-canvas-a - (rx/to-atom mouse-canvas-s)) - -(defonce mouse-viewport-s - (->> mouse-s - (rx/map :viewport-coords) +(defonce viewport-mouse-position + (->> mouse-position + (rx/map :viewport) (rx/share))) -(defonce mouse-viewport-a - (rx/to-atom mouse-viewport-s)) - -(defonce mouse-absolute-s - (->> mouse-s - (rx/map :window-coords) +(defonce window-mouse-position + (->> mouse-position + (rx/map :window) (rx/share))) -(defonce mouse-absolute-a - (rx/to-atom mouse-absolute-s)) - -(defonce mouse-ctrl-s - (->> mouse-s +(defonce mouse-position-ctrl + (->> mouse-position (rx/map :ctrl) (rx/share))) @@ -69,8 +67,8 @@ [[old new]] (gpt/subtract new old)) -(defonce mouse-delta-s - (->> mouse-viewport-s +(defonce mouse-position-deltas + (->> viewport-mouse-position (rx/sample 10) (rx/map #(gpt/divide % @refs/selected-zoom)) (rx/mapcat (fn [point] diff --git a/frontend/src/uxbox/main/ui/shapes/common.cljs b/frontend/src/uxbox/main/ui/shapes/common.cljs index f62b2e844..025149347 100644 --- a/frontend/src/uxbox/main/ui/shapes/common.cljs +++ b/frontend/src/uxbox/main/ui/shapes/common.cljs @@ -12,6 +12,7 @@ [uxbox.main.refs :as refs] [uxbox.main.streams :as streams] [uxbox.main.geom :as geom] + [uxbox.main.user-events :as uev] [uxbox.main.data.shapes :as uds] [uxbox.main.ui.keyboard :as kbd] [uxbox.util.geom.point :as gpt] @@ -20,6 +21,8 @@ ;; --- Refs +;; FIXME: use the predefined lenses under uxbox.main.lenses + (def edition-ref (-> (l/in [:workspace :edition]) (l/derive st/state))) @@ -42,17 +45,16 @@ (rlocks/release! :shape/move) (st/emit! (uds/apply-displacement shape))) (on-start [shape] - (let [stoper (->> (rx/map first streams/events-s) - (rx/filter #(= % :mouse/up)) + (let [stoper (->> streams/events + (rx/filter uev/mouse-up?) (rx/take 1)) - stream (->> streams/mouse-delta-s + stream (->> streams/mouse-position-deltas (rx/take-until stoper)) on-move (partial on-move shape) on-stop (partial on-stop shape)] (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))) diff --git a/frontend/src/uxbox/main/ui/shapes/selection.cljs b/frontend/src/uxbox/main/ui/shapes/selection.cljs index 5fe854fd7..22498b7fc 100644 --- a/frontend/src/uxbox/main/ui/shapes/selection.cljs +++ b/frontend/src/uxbox/main/ui/shapes/selection.cljs @@ -15,6 +15,7 @@ [uxbox.main.refs :as refs] [uxbox.main.streams :as streams] [uxbox.main.workers :as uwrk] + [uxbox.main.user-events :as uev] [uxbox.main.data.shapes :as uds] [uxbox.main.ui.shapes.common :as scommon] [uxbox.main.geom :as geom] @@ -213,18 +214,19 @@ (let [shape (->> (geom/shape->rect-shape shape) (geom/size)) - stoper (->> streams/events-s - (rx/map first) - (rx/filter #(= % :mouse/up)) + + stoper (->> streams/events + (rx/filter uev/mouse-up?) (rx/take 1)) - stream (->> streams/mouse-canvas-s + + stream (->> streams/canvas-mouse-position (rx/map #(gpt/divide % @refs/selected-zoom)) (rx/mapcat (fn [point] (if @refs/selected-alignment (uwrk/align-point point) (rx/of point)))) (rx/take-until stoper) - (rx/with-latest-from vector streams/mouse-ctrl-s) + (rx/with-latest-from vector streams/mouse-position-ctrl) (rx/scan accumulate-width shape) (rx/map (partial calculate-ratio shape)))] (rlocks/acquire! :shape/resize) @@ -320,11 +322,11 @@ (st/emit! (uds/update-path shape-id index delta))) (on-end [] (rlocks/release! :shape/resize))] - (let [stoper (->> streams/events-s + (let [stoper (->> streams/events (rx/map first) (rx/filter #(= % :mouse/up)) (rx/take 1)) - stream (rx/take-until stoper streams/mouse-delta-s)] + 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))) diff --git a/frontend/src/uxbox/main/ui/workspace.cljs b/frontend/src/uxbox/main/ui/workspace.cljs index 1946ff1ba..698b43f66 100644 --- a/frontend/src/uxbox/main/ui/workspace.cljs +++ b/frontend/src/uxbox/main/ui/workspace.cljs @@ -92,7 +92,7 @@ (let [prev-zoom @refs/selected-zoom dom (mx/ref-node own "workspace-canvas") scroll-position (scroll/get-current-position-absolute dom) - mouse-point @streams/mouse-viewport-a] + mouse-point @refs/viewport-mouse-position] (dom/prevent-default event) (dom/stop-propagation event) (if (pos? (.-deltaY event)) diff --git a/frontend/src/uxbox/main/ui/workspace/canvas.cljs b/frontend/src/uxbox/main/ui/workspace/canvas.cljs index 809a0e9a6..13ea47395 100644 --- a/frontend/src/uxbox/main/ui/workspace/canvas.cljs +++ b/frontend/src/uxbox/main/ui/workspace/canvas.cljs @@ -14,6 +14,7 @@ [uxbox.main.constants :as c] [uxbox.main.refs :as refs] [uxbox.main.streams :as streams] + [uxbox.main.user-events :as uev] [uxbox.main.data.projects :as dp] [uxbox.main.data.workspace :as dw] [uxbox.main.data.shapes :as uds] @@ -49,7 +50,7 @@ {:mixins [mx/reactive mx/static]} [] (let [zoom (mx/react refs/selected-zoom) - coords (some-> (mx/react streams/mouse-canvas-a) + coords (some-> (mx/react refs/canvas-mouse-position) (gpt/divide zoom) (gpt/round 0))] [:ul.coordinates @@ -75,7 +76,7 @@ (mx/defc cursor-tooltip {:mixins [mx/reactive mx/static]} [tooltip] - (let [coords (mx/react streams/mouse-absolute-a)] + (let [coords (mx/react refs/window-mouse-position)] [:span.cursor-tooltip {:style {:position "fixed" @@ -129,36 +130,48 @@ (gpt/subtract brect)))))) (on-key-down [event] - (let [opts {:key (.-keyCode event) - :shift? (kbd/shift? event) - :ctrl? (kbd/ctrl? event)}] - (rx/push! streams/events-b [:key/down opts]) + (let [key (.-keyCode event) + ctrl? (kbd/ctrl? event) + shift? (kbd/shift? event) + opts {:key key + :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) (on-key-up [event] - (let [opts {:key (.-keyCode event) - :shift? (kbd/shift? event) - :ctrl? (kbd/ctrl? event)}] + (let [key (.-keyCode event) + ctrl? (kbd/ctrl? event) + shift? (kbd/shift? event) + opts {:key key + :shift? shift? + :ctrl? ctrl?}] (when (kbd/space? event) (st/emit! (dw/stop-viewport-positioning))) - (rx/push! streams/events-b [:key/up opts]))) + (st/emit! (uev/keyboard-event :up key ctrl? shift?)) + ;; TODO: remove (deprecated) + #_(rx/push! streams/events-b [:key/up opts]))) (on-mousemove [event] (let [wpt (gpt/point (.-clientX event) (.-clientY event)) - vppt (translate-point-to-viewport wpt) - cvpt (translate-point-to-canvas wpt) - event {:ctrl (kbd/ctrl? event) - :shift (kbd/shift? event) + vpt (translate-point-to-viewport wpt) + cpt (translate-point-to-canvas wpt) + ctrl? (kbd/ctrl? event) + shift? (kbd/shift? event) + event {:ctrl ctrl? + :shift shift? :window-coords wpt - :viewport-coords vppt - :canvas-coords cvpt}] - ;; FIXME: refactor streams in order to use the streams/events-b - ;; for all keyboard and mouse events and then derive - ;; all the other from it. - (rx/push! streams/mouse-b event)))] + :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)))] (let [key1 (events/listen js/document EventType.MOUSEMOVE on-mousemove) key2 (events/listen js/document EventType.KEYDOWN on-key-down) @@ -190,9 +203,13 @@ zoom (or (:zoom workspace) 1)] (letfn [(on-mouse-down [event] (dom/stop-propagation event) - (let [opts {:shift? (kbd/shift? event) - :ctrl? (kbd/ctrl? event)}] - (rx/push! streams/events-b [:mouse/down opts])) + (let [ctrl? (kbd/ctrl? event) + 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 @@ -202,24 +219,40 @@ (on-context-menu [event] (dom/prevent-default event) (dom/stop-propagation event) - (let [opts {:shift? (kbd/shift? event) - :ctrl? (kbd/ctrl? event)}] - (rx/push! streams/events-b [:mouse/right-click opts]))) + (let [ctrl? (kbd/ctrl? event) + 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]))) (on-mouse-up [event] (dom/stop-propagation event) - (let [opts {:shift? (kbd/shift? event) - :ctrl? (kbd/ctrl? event)}] - (rx/push! streams/events-b [:mouse/up]))) + (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]))) (on-click [event] (dom/stop-propagation event) - (let [opts {:shift? (kbd/shift? event) - :ctrl? (kbd/ctrl? event)}] - (rx/push! streams/events-b [:mouse/click opts]))) + (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]))) (on-double-click [event] (dom/stop-propagation event) - (let [opts {:shift? (kbd/shift? event) - :ctrl? (kbd/ctrl? event)}] - (rx/push! streams/events-b [:mouse/double-click opts])))] + (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])))] [:div (coordinates) (when tooltip diff --git a/frontend/src/uxbox/main/ui/workspace/drawarea.cljs b/frontend/src/uxbox/main/ui/workspace/drawarea.cljs index c87f21b08..8b54bcb7c 100644 --- a/frontend/src/uxbox/main/ui/workspace/drawarea.cljs +++ b/frontend/src/uxbox/main/ui/workspace/drawarea.cljs @@ -15,6 +15,7 @@ [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] @@ -128,7 +129,7 @@ (defn- on-init-draw-icon [{:keys [metadata] :as shape}] - (let [{:keys [x y]} (gpt/divide @streams/mouse-canvas-a @refs/selected-zoom) + (let [{:keys [x y]} (gpt/divide @refs/canvas-mouse-position @refs/selected-zoom) {:keys [width height]} metadata proportion (/ width height) props {:x1 x @@ -174,29 +175,30 @@ (defn- on-init-draw-path [shape] - (letfn [(stoper-event? [[type opts]] - (or (and (= type :key/down) - (= (:key opts) 13)) - (and (= type :mouse/double-click) - (true? (:shift? opts))) - (= type :mouse/right-click))) + (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/mouse-viewport-s) + (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-s)) + (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-ctrl-s)) - ptstream (->> (rx/take-until stoper streams/events-s) + (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)) @@ -253,12 +255,11 @@ (defn- on-init-draw-free-path [shape] - (let [mouse (->> (rx/sample 10 streams/mouse-viewport-s) + (let [mouse (->> (rx/sample 10 streams/viewport-mouse-position) (rx/mapcat conditional-align) (rx/map translate-to-canvas)) - stoper (->> streams/events-s - (rx/map first) - (rx/filter #(= % :mouse/up)) + stoper (->> streams/events + (rx/filter uev/mouse-up?) (rx/take 1)) stream (rx/take-until stoper mouse)] (letfn [(simplify-shape [{:keys [points] :as shape}] @@ -287,17 +288,16 @@ (defn- on-init-draw-generic [shape] - (let [mouse (->> streams/mouse-viewport-s + (let [mouse (->> streams/viewport-mouse-position (rx/mapcat conditional-align) (rx/map translate-to-canvas)) - stoper (->> streams/events-s - (rx/map first) - (rx/filter #(= % :mouse/up)) + 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-ctrl-s))] + (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})] diff --git a/frontend/src/uxbox/main/ui/workspace/ruler.cljs b/frontend/src/uxbox/main/ui/workspace/ruler.cljs index 948d44511..4da709a06 100644 --- a/frontend/src/uxbox/main/ui/workspace/ruler.cljs +++ b/frontend/src/uxbox/main/ui/workspace/ruler.cljs @@ -2,8 +2,8 @@ ;; 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-2016 Andrey Antukh -;; Copyright (c) 2015-2016 Juan de la Cruz +;; Copyright (c) 2015-2017 Andrey Antukh +;; Copyright (c) 2015-2017 Juan de la Cruz (ns uxbox.main.ui.workspace.ruler (:require [sablono.core :as html :refer-macros [html]] @@ -75,10 +75,10 @@ (on-value-aligned pos) (on-value-simple pos)))] - (let [stream (->> streams/mouse-absolute-s + (let [stream (->> streams/window-mouse-position (rx/filter #(:active @local)) (rx/map #(resolve-position own %)) - (rx/with-latest-from vector streams/mouse-ctrl-s)) + (rx/with-latest-from vector streams/mouse-position-ctrl)) sub (rx/on-value stream on-value)] (assoc own ::sub sub)))) diff --git a/frontend/src/uxbox/main/ui/workspace/scroll.cljs b/frontend/src/uxbox/main/ui/workspace/scroll.cljs index 13af56803..1516b1dac 100644 --- a/frontend/src/uxbox/main/ui/workspace/scroll.cljs +++ b/frontend/src/uxbox/main/ui/workspace/scroll.cljs @@ -15,6 +15,8 @@ [uxbox.util.dom :as dom] [uxbox.util.geom.point :as gpt])) +;; FIXME: revisit this ns in order to find a better location for its functions + (defn set-scroll-position [dom position] (set! (.-scrollLeft dom) (:x position)) diff --git a/frontend/src/uxbox/main/ui/workspace/selrect.cljs b/frontend/src/uxbox/main/ui/workspace/selrect.cljs index 6e585f417..8f740a79d 100644 --- a/frontend/src/uxbox/main/ui/workspace/selrect.cljs +++ b/frontend/src/uxbox/main/ui/workspace/selrect.cljs @@ -13,6 +13,7 @@ [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] @@ -102,11 +103,10 @@ (defn- on-start "Function execution when selrect action is started." [] - (let [stoper (->> streams/events-s - (rx/map first) - (rx/filter #(= % :mouse/up)) + (let [stoper (->> streams/events + (rx/filter uev/mouse-up?) (rx/take 1)) - stream (rx/take-until stoper streams/mouse-viewport-s) - pos @streams/mouse-viewport-a] + 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))) diff --git a/frontend/src/uxbox/main/user_events.cljs b/frontend/src/uxbox/main/user_events.cljs new file mode 100644 index 000000000..a04cb7c41 --- /dev/null +++ b/frontend/src/uxbox/main/user_events.cljs @@ -0,0 +1,71 @@ +;; 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 + +(ns uxbox.main.user-events + "Workspace user (keyboard, mouse and pointer) events." + (:require [beicon.core :as rx] + [potok.core :as ptk] + [uxbox.util.geom.point :as gpt])) + +(defrecord KeyboardEvent [type key shift ctrl]) +(defrecord MouseEvent [type ctrl shift]) + +(defrecord PointerEvent [window + viewport + canvas + ctrl + shift] + ptk/UpdateEvent + (update [it state] + (assoc-in state [:workspace :pointer] it))) + +(defn keyboard-event + [type key ctrl shift] + {:pre [(keyword? type) + (integer? key) + (boolean? ctrl) + (boolean? shift)]} + (KeyboardEvent. type key ctrl shift)) + +(defn keyboard-event? + [v] + (instance? KeyboardEvent v)) + +(defn mouse-event + [type ctrl shift] + {:pre [(keyword? type) + (boolean? ctrl) + (boolean? shift)]} + (MouseEvent. type ctrl shift)) + +(defn mouse-event? + [v] + (instance? MouseEvent v)) + +(defn mouse-up? + [v] + (and (mouse-event? v) + (= :up (:type v)))) + +;; TODO: add spec + +(defn pointer-event + [window viewport canvas ctrl shift] + {:pre [(gpt/point? window) + (gpt/point? viewport) + (or (gpt/point? canvas) + (nil? canvas)) + (boolean? ctrl) + (boolean? shift)]} + (PointerEvent. window + viewport + canvas + ctrl + shift)) + +(defn pointer-event? + [v] + (instance? PointerEvent v))