From 0dff98801c8b8453bd794e5d4dbcfeb334bf96bb Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 10 Aug 2016 23:10:33 +0300 Subject: [PATCH] Add missing stuff in order to make path usable. --- src/uxbox/main/geom.cljs | 45 +++++++++ src/uxbox/main/ui/shapes/group.cljs | 1 - src/uxbox/main/ui/shapes/path.cljs | 48 ++++++++++ src/uxbox/main/ui/workspace/base.cljs | 7 ++ src/uxbox/main/ui/workspace/canvas.cljs | 29 +++--- src/uxbox/main/ui/workspace/drawarea.cljs | 92 ++++++++++++++++--- src/uxbox/main/ui/workspace/selection.cljs | 6 +- src/uxbox/main/ui/workspace/selrect.cljs | 3 +- .../main/ui/workspace/sidebar/drawtools.cljs | 6 +- .../main/ui/workspace/sidebar/layers.cljs | 1 + 10 files changed, 202 insertions(+), 36 deletions(-) create mode 100644 src/uxbox/main/ui/shapes/path.cljs diff --git a/src/uxbox/main/geom.cljs b/src/uxbox/main/geom.cljs index 46d19d191..fa9d2d48c 100644 --- a/src/uxbox/main/geom.cljs +++ b/src/uxbox/main/geom.cljs @@ -29,6 +29,7 @@ ;; --- Relative Movement (declare move-rect) +(declare move-path) (declare move-circle) (declare move-group) @@ -41,6 +42,7 @@ :rect (move-rect shape dpoint) :text (move-rect shape dpoint) :line (move-rect shape dpoint) + :path (move-path shape dpoint) :circle (move-circle shape dpoint) :group (move-group shape dpoint))) @@ -70,6 +72,16 @@ :dx (mth/round (+ (:dx shape 0) dx)) :dy (mth/round (+ (:dy shape 0) dy)))) +(defn- move-path + "A specialized function for relative movement + for path shapes." + [shape {dx :x dy :y}] + (let [points (:points shape) + xf (comp + (map #(update % :x + dx)) + (map #(update % :y + dy)))] + (assoc shape :points (into [] xf points)))) + ;; --- Absolute Movement (declare absolute-move-rect) @@ -353,6 +365,7 @@ (declare apply-rotation-transformation) (declare generic-inner-rect) +(declare path-inner-rect) (declare circle-inner-rect) (declare group-inner-rect) @@ -364,6 +377,7 @@ :rect (generic-inner-rect state shape) :text (generic-inner-rect shape shape) :line (generic-inner-rect state shape) + :path (path-inner-rect state shape) :circle (circle-inner-rect state shape) :group (group-inner-rect state shape)))) @@ -373,6 +387,19 @@ (merge (size shape)) (apply-rotation-transformation))) +(defn- path-inner-rect + [state {:keys [points] :as shape}] + (let [minx (apply min (map :x points)) + miny (apply min (map :y points)) + maxx (apply max (map :x points)) + maxy (apply max (map :y points)) + props {:x minx + :y miny + :width (- maxx minx) + :height (- maxy miny)}] + (-> (merge shape props) + (apply-rotation-transformation)))) + (defn- circle-inner-rect [state {:keys [cx cy rx ry group] :as shape}] (let [props {:x (- cx rx) @@ -402,6 +429,7 @@ (declare generic-outer-rect) (declare circle-outer-rect) +(declare path-outer-rect) (declare group-outer-rect) (declare apply-rotation-transformation) (declare apply-parent-deltas) @@ -415,6 +443,7 @@ :text (generic-outer-rect state shape) :icon (generic-outer-rect state shape) :line (generic-outer-rect state shape) + :path (path-outer-rect state shape) :circle (circle-outer-rect state shape) :group (group-outer-rect state shape))] (if (:group shape) @@ -450,6 +479,22 @@ (-> (merge shape props) (apply-rotation-transformation)))) +(defn- path-outer-rect + [state {:keys [points group] :as shape}] + (let [group (get-in state [:shapes-by-id group]) + minx (apply min (map :x points)) + miny (apply min (map :y points)) + maxx (apply max (map :x points)) + maxy (apply max (map :y points)) + + props {:x (+ minx (:dx group 0)) + :y (+ miny (:dy group 0)) + :width (- maxx minx) + :height (- maxy miny)}] + (-> (merge shape props) + (apply-rotation-transformation)))) + + (defn- group-outer-rect [state {:keys [id group rotation dx dy] :as shape}] (let [shapes (->> (:items shape) diff --git a/src/uxbox/main/ui/shapes/group.cljs b/src/uxbox/main/ui/shapes/group.cljs index ac2582d94..39807ebfb 100644 --- a/src/uxbox/main/ui/shapes/group.cljs +++ b/src/uxbox/main/ui/shapes/group.cljs @@ -26,7 +26,6 @@ (defn render-component [{:keys [type] :as shape}] - ;; (println "render-component" shape) (case type :group (group-component shape) :text (text/text-component shape) diff --git a/src/uxbox/main/ui/shapes/path.cljs b/src/uxbox/main/ui/shapes/path.cljs new file mode 100644 index 000000000..14e2d377d --- /dev/null +++ b/src/uxbox/main/ui/shapes/path.cljs @@ -0,0 +1,48 @@ +;; 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.shapes.path + (:require [uxbox.util.mixins :as mx :include-macros true] + [uxbox.main.ui.shapes.common :as common] + [uxbox.main.ui.shapes.attrs :as attrs] + [uxbox.main.geom :as geom])) + +;; --- Path Component + +(declare path-shape) + +(mx/defc path-component + {:mixins [mx/static mx/reactive]} + [{: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) + ] + [:g.shape {:class (when selected? "selected") + :on-mouse-down on-mouse-down + } + (path-shape shape identity)])) + +;; --- Path Shape + +(defn- render-path + [{:keys [points close?] :as shape}] + {:pre [(pos? (count points))]} + (let [start (first points) + init (str "M " (:x start) " " (:y start)) + path (reduce #(str %1 " L" (:x %2) " " (:y %2)) init points)] + (cond-> path + close? (str " Z")))) + +(mx/defc path-shape + {:mixins [mx/static]} + [{:keys [id] :as shape}] + (let [key (str "shape-" id) + props {:d (render-path shape)} + attrs (-> (attrs/extract-style-attrs shape) + (merge {:id key :key key}) + (merge props))] + [:path attrs])) diff --git a/src/uxbox/main/ui/workspace/base.cljs b/src/uxbox/main/ui/workspace/base.cljs index cb5aba015..8f1b5ff2a 100644 --- a/src/uxbox/main/ui/workspace/base.cljs +++ b/src/uxbox/main/ui/workspace/base.cljs @@ -80,9 +80,16 @@ ;; --- Events +;; TODO: this should replace mouse-events-s and keyboard-events-b +(defonce events-b (rx/bus)) +(defonce events-s (rx/dedupe events-b)) + (defonce mouse-events-b (rx/bus)) (defonce mouse-events-s (rx/dedupe mouse-events-b)) +;; (defonce kaka +;; (rx/subscribe mouse-events-s #(println "event:" %))) + (defonce keyboard-events-b (rx/bus)) (defonce keyboard-events-s (rx/dedupe keyboard-events-b)) diff --git a/src/uxbox/main/ui/workspace/canvas.cljs b/src/uxbox/main/ui/workspace/canvas.cljs index 3a9e91c96..74d13ebc2 100644 --- a/src/uxbox/main/ui/workspace/canvas.cljs +++ b/src/uxbox/main/ui/workspace/canvas.cljs @@ -19,7 +19,6 @@ [uxbox.util.data :refer (parse-int)] [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 wb] [uxbox.main.ui.workspace.rlocks :as rlocks] @@ -42,19 +41,6 @@ ;; --- Canvas -;; (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) -;; ]}) - (mx/defc canvas {:mixins [mx/reactive]} [{:keys [width height id] :as page}] @@ -71,7 +57,6 @@ (for [item (reverse (:shapes page))] (-> (uus/shape item) (mx/with-key (str item)))) - ;; (spath/path-component test-path-shape) (selection-handlers) (draw-area)]]])) @@ -150,17 +135,25 @@ zoom (or (:zoom workspace) 1)] (letfn [(on-mouse-down [event] (dom/stop-propagation event) - (rx/push! wb/mouse-events-b :mouse/down) + (rx/push! wb/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))] + (dom/stop-propagation event) + (rx/push! wb/events-b [:mouse/up])) + (on-click [event] + (dom/stop-propagation event) + (rx/push! wb/events-b [:mouse/click])) + (on-double-click [event] + (dom/stop-propagation event) + (rx/push! wb/events-b [:mouse/double-click]))] [:svg.viewport {:width (* c/viewport-width zoom) :height (* c/viewport-height zoom) :ref "viewport" :class (when drawing? "drawing") + :on-click on-click + :on-double-click on-double-click :on-mouse-down on-mouse-down :on-mouse-up on-mouse-up} [:g.zoom {:transform (str "scale(" zoom ", " zoom ")")} diff --git a/src/uxbox/main/ui/workspace/drawarea.cljs b/src/uxbox/main/ui/workspace/drawarea.cljs index 8ed355ede..6903a98ad 100644 --- a/src/uxbox/main/ui/workspace/drawarea.cljs +++ b/src/uxbox/main/ui/workspace/drawarea.cljs @@ -49,15 +49,19 @@ [own] (let [shape (mx/react drawing-shape) position (mx/react drawing-position)] - (when (and shape position) - (-> (assoc shape :drawing? true) - (geom/resize position) - (shapes/render-component))))) + (when shape + (if position + (-> (assoc shape :drawing? true) + (geom/resize position) + (shapes/render-component)) + (-> (assoc shape :drawing? true) + (shapes/render-component)))))) ;; --- Drawing Initialization (declare on-init) (declare on-init-draw-icon) +(declare on-init-draw-path) (declare on-init-draw-generic) (declare on-draw-start) (declare on-draw) @@ -76,6 +80,7 @@ (when-let [shape (:drawing @wb/workspace-ref)] (case (:type shape) :icon (on-init-draw-icon shape) + :path (on-init-draw-path shape) (on-init-draw-generic shape)))) (defn- on-init-draw-icon @@ -88,6 +93,65 @@ (uds/select-first-shape)) (rlocks/release! :ui/draw))) +(defn- on-init-draw-path + [shape] + (let [mouse (->> (rx/sample 10 wb/mouse-viewport-s) + (rx/mapcat (fn [point] + (if @wb/alignment-ref + (uds/align-point point) + (rx/of point)))) + (rx/map #(gpt/subtract % canvas-coords))) + + stoper (->> wb/events-s + (rx/map first) + (rx/filter #(= % :mouse/double-click)) + (rx/take 1)) + ;; stoper (rx/empty) + firstpos (rx/take 1 mouse) + stream (->> (rx/take-until stoper mouse) + (rx/skip-while #(nil? @drawing-shape)) + (rx/with-latest-from vector wb/mouse-ctrl-s)) + ptstream (->> wb/events-s + (rx/map first) + (rx/filter #(= % :mouse/click)) + (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] :as shape} point index] + (let [point (gpt/point point) + points (:points shape)] + (if (= (count points) index) + (append-point shape point) + (assoc-in shape [:points index] point)))) + (on-first-point [point] + (println "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-draw [[point ctrl?]] + (let [shape (update-point @drawing-shape point @counter)] + (reset! drawing-shape shape))) + (on-end [] + (let [shape @drawing-shape] + (rs/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-first-point) + (rx/subscribe ptstream on-click) + (rx/subscribe stream on-draw nil on-end)))) + (defn- on-init-draw-generic [shape] (let [mouse (->> (rx/sample 10 wb/mouse-viewport-s) @@ -97,23 +161,25 @@ (rx/of point)))) (rx/map #(gpt/subtract % canvas-coords))) - stoper (->> wb/mouse-events-s + stoper (->> wb/events-s + (rx/map first) (rx/filter #(= % :mouse/up)) - (rx/pr-log "mouse-events-s") (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 wb/mouse-ctrl-s))] - (rx/subscribe firstpos #(on-draw-start shape %)) + (rx/subscribe firstpos (fn [{:keys [x y] :as pt}] + (let [shape (geom/setup shape {:x1 x :y1 y + :x2 x :y2 y})] + (reset! drawing-shape shape)))) (rx/subscribe stream on-draw nil on-draw-complete))) -(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))) +;; (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))) (defn- on-draw [[pt ctrl?]] @@ -124,7 +190,7 @@ [] (let [shape @drawing-shape shpos @drawing-position - shape (geom/resize shape shpos)] + shape (geom/resize shape shpos)] (rs/emit! (uds/add-shape shape) (udw/select-for-drawing nil) (uds/select-first-shape)) diff --git a/src/uxbox/main/ui/workspace/selection.cljs b/src/uxbox/main/ui/workspace/selection.cljs index 8a5e6176a..a2f42c792 100644 --- a/src/uxbox/main/ui/workspace/selection.cljs +++ b/src/uxbox/main/ui/workspace/selection.cljs @@ -60,7 +60,8 @@ (defn- on-resize-start [[vid shape]] - (let [stoper (->> wb/mouse-events-s + (let [stoper (->> wb/events-s + (rx/map first) (rx/filter #(= % :mouse/up)) (rx/take 1)) stream (->> wb/mouse-delta-s @@ -81,7 +82,8 @@ (defn- on-move-start [shape] - (let [stoper (->> wb/mouse-events-s + (let [stoper (->> wb/events-s + (rx/map first) (rx/filter #(= % :mouse/up)) (rx/take 1)) stream (rx/take-until stoper wb/mouse-delta-s) diff --git a/src/uxbox/main/ui/workspace/selrect.cljs b/src/uxbox/main/ui/workspace/selrect.cljs index 43ff966e2..a0e7dad0b 100644 --- a/src/uxbox/main/ui/workspace/selrect.cljs +++ b/src/uxbox/main/ui/workspace/selrect.cljs @@ -101,7 +101,8 @@ (defn- on-start "Function execution when selrect action is started." [] - (let [stoper (->> wb/mouse-events-s + (let [stoper (->> wb/events-s + (rx/map first) (rx/filter #(= % :mouse/up)) (rx/take 1)) stream (rx/take-until stoper wb/mouse-viewport-s) diff --git a/src/uxbox/main/ui/workspace/sidebar/drawtools.cljs b/src/uxbox/main/ui/workspace/sidebar/drawtools.cljs index 05bc4ca5b..24af1b0f9 100644 --- a/src/uxbox/main/ui/workspace/sidebar/drawtools.cljs +++ b/src/uxbox/main/ui/workspace/sidebar/drawtools.cljs @@ -51,7 +51,11 @@ {:type :path :name "Path" :stroke-type :solid - :stroke "#000000"}) + :stroke "#000000" + :stroke-width 2 + :fill "transparent" + ;; :close? true + :points []}) (def +draw-tool-text+ {:type :text diff --git a/src/uxbox/main/ui/workspace/sidebar/layers.cljs b/src/uxbox/main/ui/workspace/sidebar/layers.cljs index d07cecdcd..68871263e 100644 --- a/src/uxbox/main/ui/workspace/sidebar/layers.cljs +++ b/src/uxbox/main/ui/workspace/sidebar/layers.cljs @@ -96,6 +96,7 @@ :icon (icon/icon-svg item) :line i/line :circle i/circle + :path i/curve :rect i/box :text i/text :group i/folder))