Add missing stuff in order to make path usable.

This commit is contained in:
Andrey Antukh 2016-08-10 23:10:33 +03:00
parent 8f935b4d60
commit 0dff98801c
No known key found for this signature in database
GPG key ID: 4DFEBCB8316A8B95
10 changed files with 202 additions and 36 deletions

View file

@ -29,6 +29,7 @@
;; --- Relative Movement ;; --- Relative Movement
(declare move-rect) (declare move-rect)
(declare move-path)
(declare move-circle) (declare move-circle)
(declare move-group) (declare move-group)
@ -41,6 +42,7 @@
:rect (move-rect shape dpoint) :rect (move-rect shape dpoint)
:text (move-rect shape dpoint) :text (move-rect shape dpoint)
:line (move-rect shape dpoint) :line (move-rect shape dpoint)
:path (move-path shape dpoint)
:circle (move-circle shape dpoint) :circle (move-circle shape dpoint)
:group (move-group shape dpoint))) :group (move-group shape dpoint)))
@ -70,6 +72,16 @@
:dx (mth/round (+ (:dx shape 0) dx)) :dx (mth/round (+ (:dx shape 0) dx))
:dy (mth/round (+ (:dy shape 0) dy)))) :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 ;; --- Absolute Movement
(declare absolute-move-rect) (declare absolute-move-rect)
@ -353,6 +365,7 @@
(declare apply-rotation-transformation) (declare apply-rotation-transformation)
(declare generic-inner-rect) (declare generic-inner-rect)
(declare path-inner-rect)
(declare circle-inner-rect) (declare circle-inner-rect)
(declare group-inner-rect) (declare group-inner-rect)
@ -364,6 +377,7 @@
:rect (generic-inner-rect state shape) :rect (generic-inner-rect state shape)
:text (generic-inner-rect shape shape) :text (generic-inner-rect shape shape)
:line (generic-inner-rect state shape) :line (generic-inner-rect state shape)
:path (path-inner-rect state shape)
:circle (circle-inner-rect state shape) :circle (circle-inner-rect state shape)
:group (group-inner-rect state shape)))) :group (group-inner-rect state shape))))
@ -373,6 +387,19 @@
(merge (size shape)) (merge (size shape))
(apply-rotation-transformation))) (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 (defn- circle-inner-rect
[state {:keys [cx cy rx ry group] :as shape}] [state {:keys [cx cy rx ry group] :as shape}]
(let [props {:x (- cx rx) (let [props {:x (- cx rx)
@ -402,6 +429,7 @@
(declare generic-outer-rect) (declare generic-outer-rect)
(declare circle-outer-rect) (declare circle-outer-rect)
(declare path-outer-rect)
(declare group-outer-rect) (declare group-outer-rect)
(declare apply-rotation-transformation) (declare apply-rotation-transformation)
(declare apply-parent-deltas) (declare apply-parent-deltas)
@ -415,6 +443,7 @@
:text (generic-outer-rect state shape) :text (generic-outer-rect state shape)
:icon (generic-outer-rect state shape) :icon (generic-outer-rect state shape)
:line (generic-outer-rect state shape) :line (generic-outer-rect state shape)
:path (path-outer-rect state shape)
:circle (circle-outer-rect state shape) :circle (circle-outer-rect state shape)
:group (group-outer-rect state shape))] :group (group-outer-rect state shape))]
(if (:group shape) (if (:group shape)
@ -450,6 +479,22 @@
(-> (merge shape props) (-> (merge shape props)
(apply-rotation-transformation)))) (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 (defn- group-outer-rect
[state {:keys [id group rotation dx dy] :as shape}] [state {:keys [id group rotation dx dy] :as shape}]
(let [shapes (->> (:items shape) (let [shapes (->> (:items shape)

View file

@ -26,7 +26,6 @@
(defn render-component (defn render-component
[{:keys [type] :as shape}] [{:keys [type] :as shape}]
;; (println "render-component" shape)
(case type (case type
:group (group-component shape) :group (group-component shape)
:text (text/text-component shape) :text (text/text-component shape)

View file

@ -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 <niwi@niwi.nz>
(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]))

View file

@ -80,9 +80,16 @@
;; --- Events ;; --- 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-b (rx/bus))
(defonce mouse-events-s (rx/dedupe mouse-events-b)) (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-b (rx/bus))
(defonce keyboard-events-s (rx/dedupe keyboard-events-b)) (defonce keyboard-events-s (rx/dedupe keyboard-events-b))

View file

@ -19,7 +19,6 @@
[uxbox.util.data :refer (parse-int)] [uxbox.util.data :refer (parse-int)]
[uxbox.main.ui.keyboard :as kbd] [uxbox.main.ui.keyboard :as kbd]
[uxbox.main.ui.shapes :as uus] [uxbox.main.ui.shapes :as uus]
;; [uxbox.main.ui.shapes.path :as spath]
[uxbox.util.mixins :as mx :include-macros true] [uxbox.util.mixins :as mx :include-macros true]
[uxbox.main.ui.workspace.base :as wb] [uxbox.main.ui.workspace.base :as wb]
[uxbox.main.ui.workspace.rlocks :as rlocks] [uxbox.main.ui.workspace.rlocks :as rlocks]
@ -42,19 +41,6 @@
;; --- Canvas ;; --- 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 (mx/defc canvas
{:mixins [mx/reactive]} {:mixins [mx/reactive]}
[{:keys [width height id] :as page}] [{:keys [width height id] :as page}]
@ -71,7 +57,6 @@
(for [item (reverse (:shapes page))] (for [item (reverse (:shapes page))]
(-> (uus/shape item) (-> (uus/shape item)
(mx/with-key (str item)))) (mx/with-key (str item))))
;; (spath/path-component test-path-shape)
(selection-handlers) (selection-handlers)
(draw-area)]]])) (draw-area)]]]))
@ -150,17 +135,25 @@
zoom (or (:zoom workspace) 1)] zoom (or (:zoom workspace) 1)]
(letfn [(on-mouse-down [event] (letfn [(on-mouse-down [event]
(dom/stop-propagation event) (dom/stop-propagation event)
(rx/push! wb/mouse-events-b :mouse/down) (rx/push! wb/events-b [:mouse/down])
(if (:drawing workspace) (if (:drawing workspace)
(rlocks/acquire! :ui/draw) (rlocks/acquire! :ui/draw)
(rlocks/acquire! :ui/selrect))) (rlocks/acquire! :ui/selrect)))
(on-mouse-up [event] (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) [:svg.viewport {:width (* c/viewport-width zoom)
:height (* c/viewport-height zoom) :height (* c/viewport-height zoom)
:ref "viewport" :ref "viewport"
:class (when drawing? "drawing") :class (when drawing? "drawing")
:on-click on-click
:on-double-click on-double-click
:on-mouse-down on-mouse-down :on-mouse-down on-mouse-down
:on-mouse-up on-mouse-up} :on-mouse-up on-mouse-up}
[:g.zoom {:transform (str "scale(" zoom ", " zoom ")")} [:g.zoom {:transform (str "scale(" zoom ", " zoom ")")}

View file

@ -49,15 +49,19 @@
[own] [own]
(let [shape (mx/react drawing-shape) (let [shape (mx/react drawing-shape)
position (mx/react drawing-position)] position (mx/react drawing-position)]
(when (and shape position) (when shape
(-> (assoc shape :drawing? true) (if position
(geom/resize position) (-> (assoc shape :drawing? true)
(shapes/render-component))))) (geom/resize position)
(shapes/render-component))
(-> (assoc shape :drawing? true)
(shapes/render-component))))))
;; --- Drawing Initialization ;; --- Drawing Initialization
(declare on-init) (declare on-init)
(declare on-init-draw-icon) (declare on-init-draw-icon)
(declare on-init-draw-path)
(declare on-init-draw-generic) (declare on-init-draw-generic)
(declare on-draw-start) (declare on-draw-start)
(declare on-draw) (declare on-draw)
@ -76,6 +80,7 @@
(when-let [shape (:drawing @wb/workspace-ref)] (when-let [shape (:drawing @wb/workspace-ref)]
(case (:type shape) (case (:type shape)
:icon (on-init-draw-icon shape) :icon (on-init-draw-icon shape)
:path (on-init-draw-path shape)
(on-init-draw-generic shape)))) (on-init-draw-generic shape))))
(defn- on-init-draw-icon (defn- on-init-draw-icon
@ -88,6 +93,65 @@
(uds/select-first-shape)) (uds/select-first-shape))
(rlocks/release! :ui/draw))) (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 (defn- on-init-draw-generic
[shape] [shape]
(let [mouse (->> (rx/sample 10 wb/mouse-viewport-s) (let [mouse (->> (rx/sample 10 wb/mouse-viewport-s)
@ -97,23 +161,25 @@
(rx/of point)))) (rx/of point))))
(rx/map #(gpt/subtract % canvas-coords))) (rx/map #(gpt/subtract % canvas-coords)))
stoper (->> wb/mouse-events-s stoper (->> wb/events-s
(rx/map first)
(rx/filter #(= % :mouse/up)) (rx/filter #(= % :mouse/up))
(rx/pr-log "mouse-events-s")
(rx/take 1)) (rx/take 1))
firstpos (rx/take 1 mouse) firstpos (rx/take 1 mouse)
stream (->> (rx/take-until stoper mouse) stream (->> (rx/take-until stoper mouse)
(rx/skip-while #(nil? @drawing-shape)) (rx/skip-while #(nil? @drawing-shape))
(rx/with-latest-from vector wb/mouse-ctrl-s))] (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))) (rx/subscribe stream on-draw nil on-draw-complete)))
(defn- on-draw-start ;; (defn- on-draw-start
[shape {:keys [x y] :as pt}] ;; [shape {:keys [x y] :as pt}]
(let [shape (geom/setup shape {:x1 x :y1 y :x2 x :y2 y})] ;; (let [shape (geom/setup shape {:x1 x :y1 y :x2 x :y2 y})]
(reset! drawing-shape shape))) ;; (reset! drawing-shape shape)))
(defn- on-draw (defn- on-draw
[[pt ctrl?]] [[pt ctrl?]]
@ -124,7 +190,7 @@
[] []
(let [shape @drawing-shape (let [shape @drawing-shape
shpos @drawing-position shpos @drawing-position
shape (geom/resize shape shpos)] shape (geom/resize shape shpos)]
(rs/emit! (uds/add-shape shape) (rs/emit! (uds/add-shape shape)
(udw/select-for-drawing nil) (udw/select-for-drawing nil)
(uds/select-first-shape)) (uds/select-first-shape))

View file

@ -60,7 +60,8 @@
(defn- on-resize-start (defn- on-resize-start
[[vid shape]] [[vid shape]]
(let [stoper (->> wb/mouse-events-s (let [stoper (->> wb/events-s
(rx/map first)
(rx/filter #(= % :mouse/up)) (rx/filter #(= % :mouse/up))
(rx/take 1)) (rx/take 1))
stream (->> wb/mouse-delta-s stream (->> wb/mouse-delta-s
@ -81,7 +82,8 @@
(defn- on-move-start (defn- on-move-start
[shape] [shape]
(let [stoper (->> wb/mouse-events-s (let [stoper (->> wb/events-s
(rx/map first)
(rx/filter #(= % :mouse/up)) (rx/filter #(= % :mouse/up))
(rx/take 1)) (rx/take 1))
stream (rx/take-until stoper wb/mouse-delta-s) stream (rx/take-until stoper wb/mouse-delta-s)

View file

@ -101,7 +101,8 @@
(defn- on-start (defn- on-start
"Function execution when selrect action is started." "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/filter #(= % :mouse/up))
(rx/take 1)) (rx/take 1))
stream (rx/take-until stoper wb/mouse-viewport-s) stream (rx/take-until stoper wb/mouse-viewport-s)

View file

@ -51,7 +51,11 @@
{:type :path {:type :path
:name "Path" :name "Path"
:stroke-type :solid :stroke-type :solid
:stroke "#000000"}) :stroke "#000000"
:stroke-width 2
:fill "transparent"
;; :close? true
:points []})
(def +draw-tool-text+ (def +draw-tool-text+
{:type :text {:type :text

View file

@ -96,6 +96,7 @@
:icon (icon/icon-svg item) :icon (icon/icon-svg item)
:line i/line :line i/line
:circle i/circle :circle i/circle
:path i/curve
:rect i/box :rect i/box
:text i/text :text i/text
:group i/folder)) :group i/folder))