From b8e5239ee39deb4cf4cb2d7cf514c53f7512c72c Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 10 Aug 2016 19:15:13 +0300 Subject: [PATCH] Refactor user interaction locking. --- src/uxbox/main/ui/core.cljs | 26 -- src/uxbox/main/ui/shapes/circle.cljs | 6 +- src/uxbox/main/ui/shapes/common.cljs | 20 +- src/uxbox/main/ui/shapes/group.cljs | 9 +- src/uxbox/main/ui/shapes/icon.cljs | 11 +- src/uxbox/main/ui/shapes/line.cljs | 6 +- src/uxbox/main/ui/shapes/rect.cljs | 6 +- src/uxbox/main/ui/shapes/text.cljs | 96 +++----- src/uxbox/main/ui/workspace/base.cljs | 12 +- src/uxbox/main/ui/workspace/canvas.cljs | 164 ++++++------ src/uxbox/main/ui/workspace/drawarea.cljs | 81 +++--- src/uxbox/main/ui/workspace/movement.cljs | 43 ---- src/uxbox/main/ui/workspace/resize.cljs | 48 ---- src/uxbox/main/ui/workspace/rlocks.cljs | 35 +++ src/uxbox/main/ui/workspace/scroll.cljs | 37 ++- src/uxbox/main/ui/workspace/selection.cljs | 233 +++++++++++------- src/uxbox/main/ui/workspace/selrect.cljs | 102 ++++---- .../main/ui/workspace/sidebar/drawtools.cljs | 78 +++--- 18 files changed, 468 insertions(+), 545 deletions(-) delete mode 100644 src/uxbox/main/ui/core.cljs delete mode 100644 src/uxbox/main/ui/workspace/movement.cljs delete mode 100644 src/uxbox/main/ui/workspace/resize.cljs create mode 100644 src/uxbox/main/ui/workspace/rlocks.cljs diff --git a/src/uxbox/main/ui/core.cljs b/src/uxbox/main/ui/core.cljs deleted file mode 100644 index d6478ba45..000000000 --- a/src/uxbox/main/ui/core.cljs +++ /dev/null @@ -1,26 +0,0 @@ -(ns uxbox.main.ui.core - (:require [beicon.core :as rx] - [cuerdas.core :as str])) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Actions -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defonce lock (atom "")) -(defonce actions-s (rx/bus)) - -(defn acquire-action! - ([type] - (acquire-action! type nil)) - ([type payload] - (when (empty? @lock) - (reset! lock type) - (rx/push! actions-s {:type type :payload payload})))) - -(defn release-action! - ([type] - (when (str/contains? @lock type) - (rx/push! actions-s {:type ""}) - (reset! lock ""))) - ([type & more] - (run! release-action! (cons type more)))) diff --git a/src/uxbox/main/ui/shapes/circle.cljs b/src/uxbox/main/ui/shapes/circle.cljs index c53249c6b..59e0df38e 100644 --- a/src/uxbox/main/ui/shapes/circle.cljs +++ b/src/uxbox/main/ui/shapes/circle.cljs @@ -22,12 +22,10 @@ (let [{:keys [id x y width height group]} shape selected (mx/react common/selected-shapes-ref) selected? (contains? selected id) - on-mouse-down #(common/on-mouse-down % shape selected) - on-mouse-up #(common/on-mouse-up % shape)] + on-mouse-down #(common/on-mouse-down % shape selected)] (html [:g.shape {:class (when selected? "selected") - :on-mouse-down on-mouse-down - :on-mouse-up on-mouse-up} + :on-mouse-down on-mouse-down} (circle-shape shape identity)]))) (def circle-component diff --git a/src/uxbox/main/ui/shapes/common.cljs b/src/uxbox/main/ui/shapes/common.cljs index d826db977..759b80f5f 100644 --- a/src/uxbox/main/ui/shapes/common.cljs +++ b/src/uxbox/main/ui/shapes/common.cljs @@ -10,8 +10,8 @@ [uxbox.util.rstore :as rs] [uxbox.main.state :as st] [uxbox.main.data.shapes :as uds] - [uxbox.main.ui.core :as ui] [uxbox.main.ui.keyboard :as kbd] + [uxbox.main.ui.workspace.rlocks :as rlocks] [uxbox.main.geom :as geom] [uxbox.util.dom :as dom])) @@ -41,7 +41,7 @@ (do (dom/stop-propagation event) (rs/emit! (uds/select-shape id)) - (ui/acquire-action! "ui.shape.move")) + (rlocks/acquire! :shape/move)) (and (not selected?) (not (empty? selected))) (do @@ -51,21 +51,9 @@ (do (rs/emit! (uds/deselect-all) (uds/select-shape id)) - (ui/acquire-action! "ui.shape.move")))) + (rlocks/acquire! :shape/move)))) :else (do (dom/stop-propagation event) - (ui/acquire-action! "ui.shape.move")))))) - -(defn on-mouse-up - [event {:keys [id group] :as shape}] - (cond - (and group (:locked (geom/resolve-parent shape))) - nil - - :else - (do - (dom/stop-propagation event) - (ui/release-action! "ui.shape")))) - + (rlocks/acquire! :shape/move)))))) diff --git a/src/uxbox/main/ui/shapes/group.cljs b/src/uxbox/main/ui/shapes/group.cljs index 0299e22e1..ac2582d94 100644 --- a/src/uxbox/main/ui/shapes/group.cljs +++ b/src/uxbox/main/ui/shapes/group.cljs @@ -17,6 +17,7 @@ [uxbox.main.ui.shapes.circle :as circle] [uxbox.main.ui.shapes.text :as text] [uxbox.main.ui.shapes.line :as line] + [uxbox.main.ui.shapes.path :as path] [uxbox.main.geom :as geom])) ;; --- Helpers @@ -25,12 +26,14 @@ (defn render-component [{:keys [type] :as shape}] + ;; (println "render-component" shape) (case type :group (group-component shape) :text (text/text-component shape) :line (line/line-component shape) :icon (icon/icon-component shape) :rect (rect/rect-component shape) + :path (path/path-component shape) :circle (circle/circle-component shape))) ;; --- Group Component @@ -42,13 +45,11 @@ (let [{:keys [id x y width height group]} shape selected (mx/react common/selected-shapes-ref) selected? (contains? selected id) - on-mouse-down #(common/on-mouse-down % shape selected) - on-mouse-up #(common/on-mouse-up % shape)] + on-mouse-down #(common/on-mouse-down % shape selected)] (html [:g.shape.group-shape {:class (when selected? "selected") - :on-mouse-down on-mouse-down - :on-mouse-up on-mouse-up} + :on-mouse-down on-mouse-down} (group-shape shape render-component)]))) (def group-component diff --git a/src/uxbox/main/ui/shapes/icon.cljs b/src/uxbox/main/ui/shapes/icon.cljs index 0bc95ccbe..fdf2aa82e 100644 --- a/src/uxbox/main/ui/shapes/icon.cljs +++ b/src/uxbox/main/ui/shapes/icon.cljs @@ -17,16 +17,13 @@ (declare icon-shape) (defn- icon-component-render - [own shape] - (let [{:keys [id x y width height group]} shape - selected (mx/react common/selected-shapes-ref) + [own {:keys [id] :as shape}] + (let [selected (mx/react common/selected-shapes-ref) selected? (contains? selected id) - on-mouse-down #(common/on-mouse-down % shape selected) - on-mouse-up #(common/on-mouse-up % shape)] + on-mouse-down #(common/on-mouse-down % shape selected)] (html [:g.shape {:class (when selected? "selected") - :on-mouse-down on-mouse-down - :on-mouse-up on-mouse-up} + :on-mouse-down on-mouse-down} (icon-shape shape identity)]))) (def icon-component diff --git a/src/uxbox/main/ui/shapes/line.cljs b/src/uxbox/main/ui/shapes/line.cljs index c3788b2de..9fb1180ce 100644 --- a/src/uxbox/main/ui/shapes/line.cljs +++ b/src/uxbox/main/ui/shapes/line.cljs @@ -21,12 +21,10 @@ (let [{:keys [id x y width height group]} shape selected (mx/react common/selected-shapes-ref) selected? (contains? selected id) - on-mouse-down #(common/on-mouse-down % shape selected) - on-mouse-up #(common/on-mouse-up % shape)] + on-mouse-down #(common/on-mouse-down % shape selected)] (html [:g.shape {:class (when selected? "selected") - :on-mouse-down on-mouse-down - :on-mouse-up on-mouse-up} + :on-mouse-down on-mouse-down} (line-shape shape identity)]))) (def line-component diff --git a/src/uxbox/main/ui/shapes/rect.cljs b/src/uxbox/main/ui/shapes/rect.cljs index 2705361f3..7594c6c5e 100644 --- a/src/uxbox/main/ui/shapes/rect.cljs +++ b/src/uxbox/main/ui/shapes/rect.cljs @@ -22,12 +22,10 @@ (let [{:keys [id x y width height group]} shape selected (mx/react common/selected-shapes-ref) selected? (contains? selected id) - on-mouse-down #(common/on-mouse-down % shape selected) - on-mouse-up #(common/on-mouse-up % shape)] + on-mouse-down #(common/on-mouse-down % shape selected)] (html [:g.shape {:class (when selected? "selected") - :on-mouse-down on-mouse-down - :on-mouse-up on-mouse-up} + :on-mouse-down on-mouse-down} (rect-shape shape identity)]))) (def rect-component diff --git a/src/uxbox/main/ui/shapes/text.cljs b/src/uxbox/main/ui/shapes/text.cljs index f383a22b8..c8c0b16b3 100644 --- a/src/uxbox/main/ui/shapes/text.cljs +++ b/src/uxbox/main/ui/shapes/text.cljs @@ -5,20 +5,18 @@ ;; Copyright (c) 2016 Andrey Antukh (ns uxbox.main.ui.shapes.text - (:require [sablono.core :refer-macros [html]] - [cuerdas.core :as str] - [rum.core :as rum] + (:require [cuerdas.core :as str] [lentes.core :as l] [goog.events :as events] [uxbox.util.rstore :as rs] + [uxbox.util.mixins :as mx :include-macros true] + [uxbox.util.color :as color] + [uxbox.util.dom :as dom] [uxbox.main.data.shapes :as uds] - [uxbox.main.ui.core :as ui] - [uxbox.util.mixins :as mx] [uxbox.main.ui.shapes.common :as common] [uxbox.main.ui.shapes.attrs :as attrs] - [uxbox.main.geom :as geom] - [uxbox.util.color :as color] - [uxbox.util.dom :as dom]) + [uxbox.main.ui.workspace.rlocks :as rlocks] + [uxbox.main.geom :as geom]) (:import goog.events.EventType)) ;; --- Events @@ -37,7 +35,8 @@ (declare text-shape) (declare text-shape-edit) -(defn- text-component-render +(mx/defcs text-component + {:mixins [mx/static mx/reactive (mx/local)]} [own {:keys [id x1 y1 content group] :as shape}] (let [selected (mx/react common/selected-shapes-ref) selected? (and (contains? selected id) @@ -45,28 +44,18 @@ local (:rum/local own)] (letfn [(on-mouse-down [event] (handle-mouse-down event local shape selected)) - (on-mouse-up [event] - (common/on-mouse-up event shape)) (on-done [_] (swap! local assoc :edition false)) (on-double-click [event] (swap! local assoc :edition true) - (ui/acquire-action! "ui.text.edit"))] - (html - [:g.shape {:class (when selected? "selected") - :ref "main" - :on-double-click on-double-click - :on-mouse-down on-mouse-down - :on-mouse-up on-mouse-up} - (if (:edition @local false) - (text-shape-edit shape on-done) - (text-shape shape))])))) - -(def text-component - (mx/component - {:render text-component-render - :name "text-componet" - :mixins [mx/static mx/reactive (mx/local)]})) + (rlocks/acquire! :ui/text-edit))] + [:g.shape {:class (when selected? "selected") + :ref "main" + :on-double-click on-double-click + :on-mouse-down on-mouse-down} + (if (:edition @local false) + (text-shape-edit shape on-done) + (text-shape shape))]))) ;; --- Text Styles Helpers @@ -112,8 +101,10 @@ (.focus dom) own)) -(defn- text-shape-edit-render - [own {:keys [id x1 y1 content] :as shape} on-done] +(mx/defc text-shape-edit + {:did-mount text-shape-edit-did-mount + :mixins [mx/static]} + [{:keys [id x1 y1 content] :as shape} on-done] (let [size (geom/size shape) style (make-style shape) rfm (geom/transformation-matrix shape) @@ -121,33 +112,25 @@ :transform (str rfm)} props (merge props size)] (letfn [(on-blur [ev] - (ui/release-action! "ui.text.edit") + (rlocks/release! :ui/text-edit) (on-done)) (on-input [ev] - (let [content (dom/event->inner-text ev) - sid (:id (first (:rum/args own)))] - (rs/emit! (uds/update-text sid {:content content}))))] - (html - [:g - [:rect (merge props +select-rect-attrs+)] - [:foreignObject props - [:p {:ref "container" - :on-blur on-blur - :on-input on-input - :contentEditable true - :style style}]]])))) - -(def text-shape-edit - (mx/component - {:render text-shape-edit-render - :did-mount text-shape-edit-did-mount - :name "text-shape-edit" - :mixins [mx/static]})) + (let [content (dom/event->inner-text ev)] + (rs/emit! (uds/update-text id {:content content}))))] + [:g + [:rect (merge props +select-rect-attrs+)] + [:foreignObject props + [:p {:ref "container" + :on-blur on-blur + :on-input on-input + :contentEditable true + :style style}]]]))) ;; --- Text Shape -(defn- text-shape-render - [own {:keys [id x1 y1 content] :as shape}] +(mx/defc text-shape + {:mixins [mx/static]} + [{:keys [id x1 y1 content] :as shape}] (let [key (str "shape-" id) rfm (geom/transformation-matrix shape) size (geom/size shape) @@ -155,12 +138,5 @@ :transform (str rfm)} attrs (merge props size) style (make-style shape)] - (html - [:foreignObject attrs - [:p {:style style} content]]))) - -(def text-shape - (mx/component - {:render text-shape-render - :name "text-shape" - :mixins [mx/static]})) + [:foreignObject attrs + [:p {:style style} content]])) diff --git a/src/uxbox/main/ui/workspace/base.cljs b/src/uxbox/main/ui/workspace/base.cljs index dedc5df19..cb5aba015 100644 --- a/src/uxbox/main/ui/workspace/base.cljs +++ b/src/uxbox/main/ui/workspace/base.cljs @@ -77,11 +77,19 @@ (defonce scroll-a (rx/to-atom scroll-s)) + +;; --- Events + +(defonce mouse-events-b (rx/bus)) +(defonce mouse-events-s (rx/dedupe mouse-events-b)) + +(defonce keyboard-events-b (rx/bus)) +(defonce keyboard-events-s (rx/dedupe keyboard-events-b)) + ;; --- Mouse Position Stream (defonce mouse-b (rx/bus)) -(defonce mouse-s - (rx/dedupe mouse-b)) +(defonce mouse-s (rx/dedupe mouse-b)) (defonce mouse-canvas-s (->> mouse-s diff --git a/src/uxbox/main/ui/workspace/canvas.cljs b/src/uxbox/main/ui/workspace/canvas.cljs index 0bebe1402..cb623ec4b 100644 --- a/src/uxbox/main/ui/workspace/canvas.cljs +++ b/src/uxbox/main/ui/workspace/canvas.cljs @@ -6,9 +6,7 @@ ;; Copyright (c) 2015-2016 Juan de la Cruz (ns uxbox.main.ui.workspace.canvas - (:require [sablono.core :as html :refer-macros [html]] - [rum.core :as rum] - [beicon.core :as rx] + (:require [beicon.core :as rx] [lentes.core :as l] [goog.events :as events] [uxbox.main.constants :as c] @@ -19,14 +17,13 @@ [uxbox.main.geom.point :as gpt] [uxbox.util.dom :as dom] [uxbox.util.data :refer (parse-int)] - [uxbox.main.ui.core :as uuc] [uxbox.main.ui.keyboard :as kbd] [uxbox.main.ui.shapes :as uus] + [uxbox.main.ui.shapes.path :as spath] [uxbox.util.mixins :as mx :include-macros true] - [uxbox.main.ui.workspace.base :as uuwb] + [uxbox.main.ui.workspace.base :as wb] + [uxbox.main.ui.workspace.rlocks :as rlocks] [uxbox.main.ui.workspace.drawarea :refer (draw-area)] - [uxbox.main.ui.workspace.movement :as cmov] - [uxbox.main.ui.workspace.resize :as cres] [uxbox.main.ui.workspace.ruler :refer (ruler)] [uxbox.main.ui.workspace.selection :refer (selection-handlers)] [uxbox.main.ui.workspace.selrect :refer (selrect)] @@ -45,67 +42,41 @@ ;; --- Canvas -(defn- canvas-render - [own {:keys [width height id] :as page}] - (let [workspace (mx/react uuwb/workspace-ref) - flags (:flags workspace)] - (html - [:svg.page-canvas {:x c/canvas-start-x - :y c/canvas-start-y - :ref (str "canvas" id) - :width width - :height height} - (background) - [:svg.page-layout {} - [:g.main {} - (for [item (reverse (:shapes page))] - (-> (uus/shape item) - (rum/with-key (str item)))) - (selection-handlers) - (draw-area)]]]))) +(def ^:private test-path-shape + {:type :path + :id #uuid "042951a0-804a-4cf1-b606-3e97157f55b5" + :stroke-type :solid + :stroke "#000000" + :stroke-width 2 + :fill "transparent" + :close? true + :points [(gpt/point 100 100) + (gpt/point 300 100) + (gpt/point 200 300) + ]}) -(def canvas - (mx/component - {:render canvas-render - :name "canvas" - :mixins [mx/static mx/reactive]})) +(mx/defc canvas + {:mixins [mx/reactive]} + [{:keys [width height id] :as page}] + (let [workspace (mx/react wb/workspace-ref) + flags (:flags workspace)] + [:svg.page-canvas {:x c/canvas-start-x + :y c/canvas-start-y + :ref (str "canvas" id) + :width width + :height height} + (background) + [:svg.page-layout {} + [:g.main {} + (for [item (reverse (:shapes page))] + (-> (uus/shape item) + (mx/with-key (str item)))) + (spath/path-component test-path-shape) + (selection-handlers) + (draw-area)]]])) ;; --- Viewport -(defn viewport-render - [own] - (let [workspace (mx/react uuwb/workspace-ref) - page (mx/react uuwb/page-ref) - flags (:flags workspace) - drawing? (:drawing workspace) - zoom (or (:zoom workspace) 1)] - (letfn [(on-mouse-down [event] - (dom/stop-propagation event) - (if-let [shape (:drawing workspace)] - (uuc/acquire-action! "ui.shape.draw") - (do - (when-not (empty? (:selected workspace)) - (rs/emit! (uds/deselect-all))) - (uuc/acquire-action! "ui.selrect")))) - (on-mouse-up [event] - (dom/stop-propagation event) - (uuc/release-action! "ui.shape" - "ui.selrect"))] - (html - [:svg.viewport {:width (* c/viewport-width zoom) - :height (* c/viewport-height zoom) - :ref "viewport" - :class (when drawing? "drawing") - :on-mouse-down on-mouse-down - :on-mouse-up on-mouse-up} - [:g.zoom {:transform (str "scale(" zoom ", " zoom ")")} - (if page - (canvas page)) - (if (contains? flags :grid) - (grid))] - (ruler) - (selrect)])))) - (defn- viewport-did-mount [own] (letfn [(translate-point-to-viewport [pt] @@ -127,12 +98,18 @@ (gpt/subtract brect)))))) (on-key-down [event] + (rx/push! wb/keyboard-events-b {:type :keyboard/down + :key (.-keyCode event) + :shift? (kbd/shift? event) + :ctrl? (kbd/ctrl? event)}) (when (kbd/space? event) - (uuc/acquire-action! "ui.workspace.scroll"))) + (rlocks/acquire! :workspace/scroll))) (on-key-up [event] - (when (kbd/space? event) - (uuc/release-action! "ui.workspace.scroll"))) + (rx/push! wb/keyboard-events-b {:type :keyboard/up + :key (.-keyCode event) + :shift? (kbd/shift? event) + :ctrl? (kbd/ctrl? event)})) (on-mousemove [event] (let [wpt (gpt/point (.-clientX event) @@ -144,16 +121,12 @@ :window-coords wpt :viewport-coords vppt :canvas-coords cvpt}] - (rx/push! uuwb/mouse-b event)))] + (rx/push! wb/mouse-b event)))] (let [key1 (events/listen js/document EventType.MOUSEMOVE on-mousemove) key2 (events/listen js/document EventType.KEYDOWN on-key-down) - key3 (events/listen js/document EventType.KEYUP on-key-up) - sub1 (cmov/watch-move-actions) - sub2 (cres/watch-resize-actions)] + key3 (events/listen js/document EventType.KEYUP on-key-up)] (assoc own - ::sub1 sub1 - ::sub2 sub2 ::key1 key1 ::key2 key2 ::key3 key3)))) @@ -163,14 +136,39 @@ (events/unlistenByKey (::key1 own)) (events/unlistenByKey (::key2 own)) (events/unlistenByKey (::key3 own)) - (.close (::sub1 own)) - (.close (::sub2 own)) - (dissoc own ::key1 ::key2 ::key3 ::sub1 ::sub2)) + (dissoc own ::key1 ::key2 ::key3)) + +(mx/defc viewport + {:did-mount viewport-did-mount + :will-unmount viewport-will-unmount + :mixins [mx/reactive]} + [] + (let [workspace (mx/react wb/workspace-ref) + page (mx/react wb/page-ref) + flags (:flags workspace) + drawing? (:drawing workspace) + zoom (or (:zoom workspace) 1)] + (letfn [(on-mouse-down [event] + (dom/stop-propagation event) + (rx/push! wb/mouse-events-b :mouse/down) + (if (:drawing workspace) + (rlocks/acquire! :ui/draw) + (rlocks/acquire! :ui/selrect))) + (on-mouse-up [event] + (rx/push! wb/mouse-events-b :mouse/up) + (dom/stop-propagation event))] + [:svg.viewport {:width (* c/viewport-width zoom) + :height (* c/viewport-height zoom) + :ref "viewport" + :class (when drawing? "drawing") + :on-mouse-down on-mouse-down + :on-mouse-up on-mouse-up} + [:g.zoom {:transform (str "scale(" zoom ", " zoom ")")} + (if page + (canvas page)) + (if (contains? flags :grid) + (grid))] + (ruler) + (selrect)]))) + -(def viewport - (mx/component - {:render viewport-render - :name "viewport" - :did-mount viewport-did-mount - :will-unmount viewport-will-unmount - :mixins [mx/reactive]})) diff --git a/src/uxbox/main/ui/workspace/drawarea.cljs b/src/uxbox/main/ui/workspace/drawarea.cljs index d466a7c6e..8ed355ede 100644 --- a/src/uxbox/main/ui/workspace/drawarea.cljs +++ b/src/uxbox/main/ui/workspace/drawarea.cljs @@ -6,18 +6,16 @@ ;; Copyright (c) 2015-2016 Juan de la Cruz (ns uxbox.main.ui.workspace.drawarea - (:require [sablono.core :as html :refer-macros [html]] - [beicon.core :as rx] - [lentes.core :as l] + "Draw interaction and component." + (:require [beicon.core :as rx] [uxbox.util.rstore :as rs] [uxbox.util.mixins :as mx :include-macros true] [uxbox.main.constants :as c] - [uxbox.main.state :as st] [uxbox.main.data.workspace :as udw] [uxbox.main.data.shapes :as uds] - [uxbox.main.ui.core :as uuc] [uxbox.main.ui.shapes :as shapes] [uxbox.main.ui.workspace.base :as wb] + [uxbox.main.ui.workspace.rlocks :as rlocks] [uxbox.main.geom :as geom] [uxbox.main.geom.point :as gpt] [uxbox.util.dom :as dom])) @@ -27,6 +25,10 @@ (defonce drawing-shape (atom nil)) (defonce drawing-position (atom nil)) +(def ^:private canvas-coords + (gpt/point c/canvas-start-x + c/canvas-start-y)) + ;; --- Draw Area (Component) (declare watch-draw-actions) @@ -52,48 +54,41 @@ (geom/resize position) (shapes/render-component))))) -;; --- Drawing Logic +;; --- Drawing Initialization -(declare initialize) +(declare on-init) +(declare on-init-draw-icon) +(declare on-init-draw-generic) +(declare on-draw-start) +(declare on-draw) +(declare on-draw-complete) (defn- watch-draw-actions [] - (let [stream (->> uuc/actions-s - (rx/map :type) - (rx/dedupe) - (rx/filter #(= "ui.shape.draw" %)) - (rx/map #(:drawing @wb/workspace-ref)) - (rx/filter identity))] - (rx/subscribe stream initialize))) + (let [stream (->> (rx/map first rlocks/stream) + (rx/filter #(= % :ui/draw)))] + (rx/subscribe stream on-init))) -(declare initialize-icon-drawing) -(declare initialize-shape-drawing) +(defn- on-init + "Function execution when draw shape operation is requested. + This is a entry point for the draw interaction." + [] + (when-let [shape (:drawing @wb/workspace-ref)] + (case (:type shape) + :icon (on-init-draw-icon shape) + (on-init-draw-generic shape)))) -(defn- initialize - [shape] - (if (= (:type shape) :icon) - (initialize-icon-drawing shape) - (initialize-shape-drawing shape))) - -(defn- initialize-icon-drawing - "A drawing handler for icons." +(defn- on-init-draw-icon [shape] (let [{:keys [x y]} (gpt/divide @wb/mouse-canvas-a @wb/zoom-ref) props {:x1 x :y1 y :x2 (+ x 100) :y2 (+ y 100)} shape (geom/setup shape props)] (rs/emit! (uds/add-shape shape) (udw/select-for-drawing nil) - (uds/select-first-shape)))) + (uds/select-first-shape)) + (rlocks/release! :ui/draw))) -(def ^:private canvas-coords - (gpt/point c/canvas-start-x - c/canvas-start-y)) - -(declare on-draw) -(declare on-draw-complete) -(declare on-first-draw) - -(defn- initialize-shape-drawing +(defn- on-init-draw-generic [shape] (let [mouse (->> (rx/sample 10 wb/mouse-viewport-s) (rx/mapcat (fn [point] @@ -101,20 +96,21 @@ (uds/align-point point) (rx/of point)))) (rx/map #(gpt/subtract % canvas-coords))) - stoper (->> uuc/actions-s - (rx/map :type) - (rx/filter #(empty? %)) + + stoper (->> wb/mouse-events-s + (rx/filter #(= % :mouse/up)) + (rx/pr-log "mouse-events-s") (rx/take 1)) + firstpos (rx/take 1 mouse) - stream (->> mouse - (rx/take-until stoper) + stream (->> (rx/take-until stoper mouse) (rx/skip-while #(nil? @drawing-shape)) (rx/with-latest-from vector wb/mouse-ctrl-s))] - (rx/subscribe firstpos #(on-first-draw shape %)) + (rx/subscribe firstpos #(on-draw-start shape %)) (rx/subscribe stream on-draw nil on-draw-complete))) -(defn- on-first-draw +(defn- on-draw-start [shape {:keys [x y] :as pt}] (let [shape (geom/setup shape {:x1 x :y1 y :x2 x :y2 y})] (reset! drawing-shape shape))) @@ -133,4 +129,5 @@ (udw/select-for-drawing nil) (uds/select-first-shape)) (reset! drawing-position nil) - (reset! drawing-shape nil))) + (reset! drawing-shape nil) + (rlocks/release! :ui/draw))) diff --git a/src/uxbox/main/ui/workspace/movement.cljs b/src/uxbox/main/ui/workspace/movement.cljs deleted file mode 100644 index a6d2840a5..000000000 --- a/src/uxbox/main/ui/workspace/movement.cljs +++ /dev/null @@ -1,43 +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-2016 Andrey Antukh -;; Copyright (c) 2015-2016 Juan de la Cruz - -(ns uxbox.main.ui.workspace.movement - "Shape movement in workspace logic." - (:require [beicon.core :as rx] - [lentes.core :as l] - [uxbox.main.constants :as c] - [uxbox.util.rstore :as rs] - [uxbox.main.state :as st] - [uxbox.main.ui.core :as uuc] - [uxbox.main.ui.workspace.base :as wb] - [uxbox.main.data.shapes :as uds] - [uxbox.main.geom :as geom] - [uxbox.main.geom.point :as gpt])) - -;; --- Public Api - -(declare watch-movement) - -(defn watch-move-actions - [] - (let [initialize #(run! watch-movement @wb/selected-shapes-ref) - stream (rx/filter #(= "ui.shape.move" (:type %)) uuc/actions-s)] - (rx/subscribe stream initialize))) - -;; --- Implementation - -(defn- watch-movement - [shape] - (let [stoper (->> uuc/actions-s - (rx/map :type) - (rx/filter empty?) - (rx/take 1)) - stream (->> wb/mouse-delta-s - (rx/take-until stoper))] - (when @wb/alignment-ref - (rs/emit! (uds/initial-align-shape shape))) - (rx/subscribe stream #(rs/emit! (uds/move-shape shape %))))) diff --git a/src/uxbox/main/ui/workspace/resize.cljs b/src/uxbox/main/ui/workspace/resize.cljs deleted file mode 100644 index 8802ca06d..000000000 --- a/src/uxbox/main/ui/workspace/resize.cljs +++ /dev/null @@ -1,48 +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-2016 Andrey Antukh -;; Copyright (c) 2015-2016 Juan de la Cruz - -(ns uxbox.main.ui.workspace.resize - (:require [beicon.core :as rx] - [uxbox.util.rstore :as rs] - [uxbox.main.data.shapes :as uds] - [uxbox.main.ui.core :as uuc] - [uxbox.main.ui.workspace.base :as wb] - [uxbox.main.geom.point :as gpt])) - -(declare initialize) - -;; --- Public Api - -(defn watch-resize-actions - [] - (as-> uuc/actions-s $ - (rx/dedupe $) - (rx/filter #(= (:type %) "ui.shape.resize") $) - (rx/on-value $ initialize))) - -;; --- Implementation - -(declare handle-resize) - -(defn- initialize - [event] - (let [{:keys [vid shape] :as payload} (:payload event) - stoper (->> uuc/actions-s - (rx/map :type) - (rx/filter #(empty? %)) - (rx/take 1)) - stream (->> wb/mouse-delta-s - (rx/take-until stoper) - (rx/with-latest-from vector wb/mouse-ctrl-s))] - (when @wb/alignment-ref - (rs/emit! (uds/initial-vertext-align shape vid))) - (rx/subscribe stream #(handle-resize shape vid %)))) - -(defn- handle-resize - [shape vid [delta ctrl?]] - (let [params {:vid vid :delta (assoc delta :lock ctrl?)}] - (rs/emit! (uds/update-vertex-position shape params)))) diff --git a/src/uxbox/main/ui/workspace/rlocks.cljs b/src/uxbox/main/ui/workspace/rlocks.cljs new file mode 100644 index 000000000..531cba5b4 --- /dev/null +++ b/src/uxbox/main/ui/workspace/rlocks.cljs @@ -0,0 +1,35 @@ +;; 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) 2016 Andrey Antukh + +(ns uxbox.main.ui.workspace.rlocks + "Reactive locks abstraction. + + Mainly used for lock the interface to do one concrete user action + such can be draw new shape, scroll, move shape, etc, and avoid + that other posible actions interfere in the locked one." + (:require [beicon.core :as rx])) + +(defonce lock (atom ::none)) +(defonce stream (rx/bus)) + +(defn acquire! + ([type] + (when (= @lock ::none) + (println "acquire!" type) + (reset! lock type) + (rx/push! stream [type nil]))) + ([type payload] + (when (= @lock ::none) + (reset! lock type) + (rx/push! stream [type payload])))) + +(defn release! + [type] + (when (= @lock type) + (println "release!" type) + (reset! lock ::none) + (rx/push! stream [::none nil]))) + diff --git a/src/uxbox/main/ui/workspace/scroll.cljs b/src/uxbox/main/ui/workspace/scroll.cljs index 4906faffe..46a68bc92 100644 --- a/src/uxbox/main/ui/workspace/scroll.cljs +++ b/src/uxbox/main/ui/workspace/scroll.cljs @@ -6,32 +6,30 @@ ;; Copyright (c) 2015-2016 Juan de la Cruz (ns uxbox.main.ui.workspace.scroll + "Workspace scroll events handling." (:require [beicon.core :as rx] - [lentes.core :as l] - [uxbox.main.constants :as c] - [uxbox.util.rstore :as rs] - [uxbox.main.state :as ust] - [uxbox.main.data.shapes :as uds] - [uxbox.main.ui.core :as uuc] [uxbox.util.mixins :as mx] - [uxbox.main.ui.workspace.base :as uuwb] + [uxbox.main.ui.workspace.base :as wb] + [uxbox.main.ui.workspace.rlocks :as rlocks] [uxbox.main.geom.point :as gpt])) (defn watch-scroll-interactions [own] - (letfn [(handle-scroll-interaction [] - (let [stoper (->> uuc/actions-s - (rx/map :type) - (rx/filter #(empty? %)) + (letfn [(is-space-up? [{:keys [key type]}] + (and (= 32 key) (= :keyboard/up type))) + + (on-start [] + (let [stoper (->> wb/keyboard-events-s + (rx/filter is-space-up?) (rx/take 1)) local (:rum/local own) - initial @uuwb/mouse-viewport-a] + initial @wb/mouse-viewport-a + stream (rx/take-until stoper wb/mouse-viewport-s)] (swap! local assoc :scrolling true) - (as-> uuwb/mouse-viewport-s $ - (rx/take-until stoper $) - (rx/subscribe $ #(on-scroll % initial) nil on-scroll-end)))) + (rx/subscribe stream #(on-scroll % initial) nil on-scroll-end))) (on-scroll-end [] + (rlocks/release! :workspace/scroll) (let [local (:rum/local own)] (swap! local assoc :scrolling false))) @@ -42,8 +40,7 @@ cy (.-scrollTop el)] (set! (.-scrollLeft el) (- cx x)) (set! (.-scrollTop el) (- cy y))))] - (as-> uuc/actions-s $ - (rx/map :type $) - (rx/dedupe $) - (rx/filter #(= "ui.workspace.scroll" %) $) - (rx/on-value $ handle-scroll-interaction)))) + + (let [stream (->> (rx/map first rlocks/stream) + (rx/filter #(= % :workspace/scroll)))] + (rx/subscribe stream on-start)))) diff --git a/src/uxbox/main/ui/workspace/selection.cljs b/src/uxbox/main/ui/workspace/selection.cljs index 242fb69b5..8a5e6176a 100644 --- a/src/uxbox/main/ui/workspace/selection.cljs +++ b/src/uxbox/main/ui/workspace/selection.cljs @@ -7,18 +7,21 @@ (ns uxbox.main.ui.workspace.selection "Multiple selection handlers component." - (:require [sablono.core :as html :refer-macros [html]] - [rum.core :as rum] - [lentes.core :as l] + (:require [lentes.core :as l] + [beicon.core :as rx] [uxbox.main.state :as st] - [uxbox.util.mixins :as mx] - [uxbox.main.ui.core :as uuc] + [uxbox.util.mixins :as mx :include-macros true] + [uxbox.util.rstore :as rs] + [uxbox.main.data.shapes :as uds] + [uxbox.main.ui.workspace.base :as wb] + [uxbox.main.ui.workspace.rlocks :as rlocks] [uxbox.main.geom :as geom] + [uxbox.main.geom.point :as gpt] [uxbox.util.dom :as dom])) -;; --- Constants +;; --- Refs & Constants -(def +circle-props+ +(def ^:private +circle-props+ {:r 6 :style {:fillOpacity "1" :strokeWidth "1px" @@ -26,100 +29,150 @@ :fill "#31e6e0" :stroke "#28c4d4"}) -;; --- Lenses +(defn- focus-selected-shapes + [state] + (let [selected (get-in state [:workspace :selected])] + (mapv #(get-in state [:shapes-by-id %]) selected))) -(def selected-shapes-ref - (letfn [(getter [state] - (let [selected (get-in state [:workspace :selected])] - (mapv #(get-in state [:shapes-by-id %]) selected)))] - (-> (l/lens getter) - (l/derive st/state)))) +(def ^:private selected-shapes-ref + (-> (l/lens focus-selected-shapes) + (l/derive st/state))) + +;; --- Resize + +(declare on-resize-start) + +(defn watch-resize-actions + [] + (let [stream (->> rlocks/stream + (rx/filter #(= (first %) :shape/resize)) + (rx/map second))] + (rx/subscribe stream on-resize-start))) + +(defn- on-resize + [shape vid [delta ctrl?]] + (let [params {:vid vid :delta (assoc delta :lock ctrl?)}] + (rs/emit! (uds/update-vertex-position shape params)))) + +(defn- on-resize-stop + [] + (rlocks/release! :shape/resize)) + +(defn- on-resize-start + [[vid shape]] + (let [stoper (->> wb/mouse-events-s + (rx/filter #(= % :mouse/up)) + (rx/take 1)) + stream (->> wb/mouse-delta-s + (rx/take-until stoper) + (rx/with-latest-from vector wb/mouse-ctrl-s))] + (when @wb/alignment-ref + (rs/emit! (uds/initial-vertext-align shape vid))) + (rx/subscribe stream (partial on-resize shape vid) nil on-resize-stop))) + +;; --- Movement + +(declare on-move-start) + +(defn watch-move-actions + [] + (-> (rx/filter #(= (first %) :shape/move) rlocks/stream) + (rx/subscribe #(run! on-move-start @wb/selected-shapes-ref)))) + +(defn- on-move-start + [shape] + (let [stoper (->> wb/mouse-events-s + (rx/filter #(= % :mouse/up)) + (rx/take 1)) + stream (rx/take-until stoper wb/mouse-delta-s) + on-move #(rs/emit! (uds/move-shape shape %)) + on-stop #(rlocks/release! :shape/move)] + (when @wb/alignment-ref + (rs/emit! (uds/initial-align-shape shape))) + (rx/subscribe stream on-move nil on-stop))) ;; --- Selection Handlers (Component) -(defn- multiple-selection-handlers-render +(mx/defc multiple-selection-handlers [shapes] (let [{:keys [width height x y]} (geom/outer-rect-coll shapes)] - (html - [:g.controls - [:rect.main {:x x :y y :width width :height height :stroke-dasharray "5,5" - :style {:stroke "#333" :fill "transparent" :stroke-opacity "1"}}]]))) + [:g.controls + [:rect.main {:x x :y y + :width width + :height height + :stroke-dasharray "5,5" + :style {:stroke "#333" :fill "transparent" + :stroke-opacity "1"}}]])) -(defn- single-selection-handlers-render - [shape] - (letfn [ - (on-mouse-down [vid event] +(mx/defc single-selection-handlers + [{:keys [id] :as shape}] + (letfn [(on-mouse-down [vid event] (dom/stop-propagation event) - (uuc/acquire-action! "ui.shape.resize" - {:vid vid :shape (:id shape)})) - - (on-mouse-up [vid event] - (dom/stop-propagation event) - (uuc/release-action! "ui.shape.resize"))] + (rlocks/acquire! :shape/resize [vid id]))] (let [{:keys [x y width height]} (geom/outer-rect shape)] - (html - [:g.controls - [:rect.main {:x x :y y :width width :height height :stroke-dasharray "5,5" - :style {:stroke "#333" :fill "transparent" :stroke-opacity "1"}}] - [:circle.top - (merge +circle-props+ - {:on-mouse-up #(on-mouse-up :top %) - :on-mouse-down #(on-mouse-down :top %) - :cx (+ x (/ width 2)) - :cy (- y 2)})] - [:circle.right - (merge +circle-props+ - {:on-mouse-up #(on-mouse-up :right %) - :on-mouse-down #(on-mouse-down :right %) - :cy (+ y (/ height 2)) - :cx (+ x width 1)})] - [:circle.bottom - (merge +circle-props+ - {:on-mouse-up #(on-mouse-up :bottom %) - :on-mouse-down #(on-mouse-down :bottom %) - :cx (+ x (/ width 2)) - :cy (+ y height 2)})] - [:circle.left - (merge +circle-props+ - {:on-mouse-up #(on-mouse-up :left %) - :on-mouse-down #(on-mouse-down :left %) - :cy (+ y (/ height 2)) - :cx (- x 3)})] - [:circle.top-left - (merge +circle-props+ - {:on-mouse-up #(on-mouse-up :top-left %) - :on-mouse-down #(on-mouse-down :top-left %) - :cx x - :cy y})] - [:circle.top-right - (merge +circle-props+ - {:on-mouse-up #(on-mouse-up :top-right %) - :on-mouse-down #(on-mouse-down :top-right %) - :cx (+ x width) - :cy y})] - [:circle.bottom-left - (merge +circle-props+ - {:on-mouse-up #(on-mouse-up :bottom-left %) - :on-mouse-down #(on-mouse-down :bottom-left %) - :cx x - :cy (+ y height)})] - [:circle.bottom-right - (merge +circle-props+ - {:on-mouse-up #(on-mouse-up :bottom-right %) - :on-mouse-down #(on-mouse-down :bottom-right %) - :cx (+ x width) - :cy (+ y height)})]])))) + [:g.controls + [:rect.main {:x x :y y :width width :height height :stroke-dasharray "5,5" + :style {:stroke "#333" :fill "transparent" :stroke-opacity "1"}}] + [:circle.top + (merge +circle-props+ + {:on-mouse-down #(on-mouse-down :top %) + :cx (+ x (/ width 2)) + :cy (- y 2)})] + [:circle.right + (merge +circle-props+ + {:on-mouse-down #(on-mouse-down :right %) + :cy (+ y (/ height 2)) + :cx (+ x width 1)})] + [:circle.bottom + (merge +circle-props+ + {:on-mouse-down #(on-mouse-down :bottom %) + :cx (+ x (/ width 2)) + :cy (+ y height 2)})] + [:circle.left + (merge +circle-props+ + {:on-mouse-down #(on-mouse-down :left %) + :cy (+ y (/ height 2)) + :cx (- x 3)})] + [:circle.top-left + (merge +circle-props+ + {:on-mouse-down #(on-mouse-down :top-left %) + :cx x + :cy y})] + [:circle.top-right + (merge +circle-props+ + {:on-mouse-down #(on-mouse-down :top-right %) + :cx (+ x width) + :cy y})] + [:circle.bottom-left + (merge +circle-props+ + {:on-mouse-down #(on-mouse-down :bottom-left %) + :cx x + :cy (+ y height)})] + [:circle.bottom-right + (merge +circle-props+ + {:on-mouse-down #(on-mouse-down :bottom-right %) + :cx (+ x width) + :cy (+ y height)})]]))) -(defn selection-handlers-render +(defn- selection-handlers-will-mount [own] + (assoc own + ::sub1 (watch-resize-actions) + ::sub2 (watch-move-actions))) + +(defn- selection-handlers-will-unmount + [own] + (.close (::sub1 own)) + (.close (::sub2 own)) + (dissoc own ::sub1 ::sub2)) + +(mx/defc selection-handlers + {:mixins [mx/reactive mx/static] + :will-mount selection-handlers-will-mount + :will-unmount selection-handlers-will-unmount} + [] (let [shapes (mx/react selected-shapes-ref) shapes-num (count shapes)] (cond - (> shapes-num 1) (multiple-selection-handlers-render shapes) - (= shapes-num 1) (single-selection-handlers-render (first shapes))))) - -(def selection-handlers - (mx/component - {:render selection-handlers-render - :name "selection-handlers" - :mixins [mx/reactive mx/static]})) + (> shapes-num 1) (multiple-selection-handlers shapes) + (= shapes-num 1) (single-selection-handlers (first shapes))))) diff --git a/src/uxbox/main/ui/workspace/selrect.cljs b/src/uxbox/main/ui/workspace/selrect.cljs index 5308dd495..43ff966e2 100644 --- a/src/uxbox/main/ui/workspace/selrect.cljs +++ b/src/uxbox/main/ui/workspace/selrect.cljs @@ -6,17 +6,15 @@ ;; Copyright (c) 2015-2016 Juan de la Cruz (ns uxbox.main.ui.workspace.selrect - "Components for indicate the user selection and selected shapes group." - (:require [sablono.core :as html :refer-macros [html]] - [rum.core :as rum] - [beicon.core :as rx] - [uxbox.main.constants :as c] + "Mouse selection interaction and component." + (:require [beicon.core :as rx] [uxbox.util.rstore :as rs] + [uxbox.util.mixins :as mx :include-macros true] + [uxbox.main.constants :as c] [uxbox.main.data.workspace :as dw] [uxbox.main.data.shapes :as uds] - [uxbox.main.ui.core :as uuc] - [uxbox.util.mixins :as mx] - [uxbox.main.ui.workspace.base :as wb])) + [uxbox.main.ui.workspace.base :as wb] + [uxbox.main.ui.workspace.rlocks :as rlocks])) (defonce position (atom nil)) @@ -25,35 +23,29 @@ (declare selrect->rect) (declare watch-selrect-actions) -(defn- selrect-render - [own] - (when-let [data (mx/react position)] - (let [{:keys [x y width height]} (selrect->rect data)] - (html - [:rect.selection-rect - {:x x - :y y - :width width - :height height}])))) - -(defn- selrect-will-mount +(defn- will-mount [own] (assoc own ::sub (watch-selrect-actions))) -(defn- selrect-will-unmount +(defn- will-unmount [own] (.close (::sub own)) (dissoc own ::sub)) -(def selrect - (mx/component - {:render selrect-render - :name "selrect" - :will-mount selrect-will-mount - :will-unmount selrect-will-unmount - :mixins [mx/static mx/reactive]})) +(mx/defc selrect + {:will-mount will-mount + :will-unmount will-unmount + :mixins [mx/static mx/reactive]} + [] + (when-let [data (mx/react position)] + (let [{:keys [x y width height]} (selrect->rect data)] + [:rect.selection-rect + {:x x + :y y + :width width + :height height}]))) -;; --- Implementation +;; --- Interaction (defn- selrect->rect [data] @@ -82,31 +74,37 @@ :width (/ (:width rect) zoom) :height (/ (:height rect) zoom)))) +(declare on-start) + (defn- watch-selrect-actions [] - (letfn [(on-value [pos] - (swap! position assoc :current pos)) + (let [stream (->> (rx/map first rlocks/stream) + (rx/filter #(= % :ui/selrect)))] + (rx/subscribe stream on-start))) - (on-complete [] - (rs/emit! (-> (selrect->rect @position) - (translate-to-canvas) - (uds/select-shapes))) - (reset! position nil)) +(defn- on-move + "Function executed on each mouse movement while selrect + interaction is active." + [pos] + (swap! position assoc :current pos)) - (init [] - (let [stoper (->> uuc/actions-s - (rx/map :type) - (rx/filter #(empty? %)) - (rx/take 1)) - pos @wb/mouse-viewport-a] - (reset! position {:start pos :current pos}) +(defn- on-complete + "Function executed when the selection rect + interaction is terminated." + [] + (rs/emit! (-> (selrect->rect @position) + (translate-to-canvas) + (uds/select-shapes))) + (rlocks/release! :ui/selrect) + (reset! position nil)) - (as-> wb/mouse-viewport-s $ - (rx/take-until stoper $) - (rx/subscribe $ on-value nil on-complete))))] - - (as-> uuc/actions-s $ - (rx/map :type $) - (rx/dedupe $) - (rx/filter #(= "ui.selrect" %) $) - (rx/on-value $ init)))) +(defn- on-start + "Function execution when selrect action is started." + [] + (let [stoper (->> wb/mouse-events-s + (rx/filter #(= % :mouse/up)) + (rx/take 1)) + stream (rx/take-until stoper wb/mouse-viewport-s) + pos @wb/mouse-viewport-a] + (reset! position {:start pos :current pos}) + (rx/subscribe stream on-move nil on-complete))) diff --git a/src/uxbox/main/ui/workspace/sidebar/drawtools.cljs b/src/uxbox/main/ui/workspace/sidebar/drawtools.cljs index 9d4bc0b5e..05bc4ca5b 100644 --- a/src/uxbox/main/ui/workspace/sidebar/drawtools.cljs +++ b/src/uxbox/main/ui/workspace/sidebar/drawtools.cljs @@ -7,35 +7,30 @@ (ns uxbox.main.ui.workspace.sidebar.drawtools (:require [sablono.core :as html :refer-macros [html]] - [rum.core :as rum] [lentes.core :as l] [uxbox.util.i18n :refer (tr)] [uxbox.util.router :as r] [uxbox.util.rstore :as rs] + [uxbox.util.data :refer (read-string)] + [uxbox.util.mixins :as mx :include-macros true] + [uxbox.util.dom :as dom] [uxbox.main.state :as st] [uxbox.main.library :as library] - [uxbox.util.data :refer (read-string)] [uxbox.main.data.workspace :as dw] [uxbox.main.ui.workspace.base :as wb] - [uxbox.main.ui.icons :as i] - [uxbox.util.mixins :as mx] - [uxbox.util.dom :as dom])) + [uxbox.main.ui.icons :as i])) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Lenses -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; --- Refs (def ^:private drawing-shape "A focused vision of the drawing property of the workspace status. This avoids rerender the whole toolbox on each workspace change." - (as-> (l/in [:workspace :drawing]) $ - (l/derive $ st/state))) + (-> (l/in [:workspace :drawing]) + (l/derive st/state))) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Draw Tools -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; --- Constants (def +draw-tool-rect+ {:type :rect @@ -52,6 +47,12 @@ :stroke-type :solid :stroke "#000000"}) +(def +draw-tool-path+ + {:type :path + :name "Path" + :stroke-type :solid + :stroke "#000000"}) + (def +draw-tool-text+ {:type :text :name "Text" @@ -77,41 +78,38 @@ {:icon i/text :help (tr "ds.help.text") :shape +draw-tool-text+ - :priority 4}}) + :priority 4} + :path + {:icon i/curve + :help (tr "ds.help.path") + :shape +draw-tool-path+ + :priority 5}}) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Draw Tool Box -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; --- Draw Toolbox (Component) (defn- select-for-draw [shape] (rs/emit! (dw/select-for-drawing shape))) -(defn draw-tools-render - [open-toolboxes] +(mx/defc draw-toolbox + {:mixins [mx/static mx/reactive]} + [own] (let [workspace (mx/react wb/workspace-ref) drawing (mx/react drawing-shape) close #(rs/emit! (dw/toggle-flag :drawtools)) tools (->> (into [] +draw-tools+) (sort-by (comp :priority second)))] - (html - [:div#form-tools.tool-window.drawing-tools - [:div.tool-window-bar - [:div.tool-window-icon i/window] - [:span (tr "ds.draw-tools")] - [:div.tool-window-close {:on-click close} i/close]] - [:div.tool-window-content - (for [[key props] tools - :let [selected? (= drawing (:shape props))]] - [:div.tool-btn.tooltip.tooltip-hover - {:alt (:help props) - :class (when selected? "selected") - :key (name key) - :on-click (partial select-for-draw (:shape props))} - (:icon props)])]]))) - -(def draw-toolbox - (mx/component - {:render draw-tools-render - :name "draw-tools" - :mixins [mx/static mx/reactive]})) + [:div#form-tools.tool-window.drawing-tools + [:div.tool-window-bar + [:div.tool-window-icon i/window] + [:span (tr "ds.draw-tools")] + [:div.tool-window-close {:on-click close} i/close]] + [:div.tool-window-content + (for [[key props] tools + :let [selected? (= drawing (:shape props))]] + [:div.tool-btn.tooltip.tooltip-hover + {:alt (:help props) + :class (when selected? "selected") + :key (name key) + :on-click (partial select-for-draw (:shape props))} + (:icon props)])]]))