mirror of
https://github.com/penpot/penpot.git
synced 2025-02-12 18:18:24 -05:00
♻️ Completelly rewrite drawing mechanism.
This commit is contained in:
parent
4cacb9f92c
commit
f8ff79e23c
15 changed files with 935 additions and 623 deletions
|
@ -7,7 +7,7 @@
|
|||
environ/environ {:mvn/version "1.1.0"}
|
||||
metosin/reitit-core {:mvn/version "0.3.9"}
|
||||
|
||||
funcool/beicon {:mvn/version "5.0.0"}
|
||||
funcool/beicon {:mvn/version "5.1.0-SNAPSHOT"}
|
||||
funcool/cuerdas {:mvn/version "2.2.0"}
|
||||
funcool/lentes {:mvn/version "1.3.0-SNAPSHOT"}
|
||||
funcool/potok {:mvn/version "2.3.0"}
|
||||
|
@ -19,7 +19,7 @@
|
|||
{:dev {:extra-deps {com.bhauman/rebel-readline-cljs {:mvn/version "0.1.4"}
|
||||
com.bhauman/rebel-readline {:mvn/version "0.1.4"}
|
||||
com.bhauman/figwheel-main {:mvn/version "0.2.3"}
|
||||
org.clojure/tools.namespace {:mvn/version "0.3.0"}}
|
||||
org.clojure/tools.namespace {:mvn/version "0.3.1"}}
|
||||
:extra-paths ["test"]}
|
||||
|
||||
:repl {:main-opts ["-m" "rebel-readline.main"]}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
(ns uxbox.main.data.workspace
|
||||
(:require
|
||||
;; [uxbox.main.data.workspace.drawing :as wdrawing]
|
||||
[beicon.core :as rx]
|
||||
[cljs.spec.alpha :as s]
|
||||
[potok.core :as ptk]
|
||||
|
@ -25,8 +24,6 @@
|
|||
[uxbox.main.lenses :as ul]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.streams :as streams]
|
||||
[uxbox.main.user-events :as uev]
|
||||
[uxbox.main.workers :as uwrk]
|
||||
[uxbox.util.data :refer [dissoc-in]]
|
||||
[uxbox.util.data :refer [index-of]]
|
||||
|
@ -368,7 +365,7 @@
|
|||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(rx/just ::uev/interrupt)))
|
||||
(rx/just :interrupt)))
|
||||
|
||||
(defn deselect-all
|
||||
"Clear all possible state of drawing, edition
|
||||
|
@ -626,40 +623,6 @@
|
|||
{:pre [(uuid? id)]}
|
||||
(ApplyResize. id))
|
||||
|
||||
;; --- Shape Movement (by mouse)
|
||||
|
||||
(defrecord StartMove [id]
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [pid (get-in state [:workspace :current])
|
||||
wst (get-in state [:workspace pid])
|
||||
stoper (->> streams/events
|
||||
(rx/filter uev/mouse-up?)
|
||||
(rx/take 1))
|
||||
stream (->> streams/mouse-position-deltas
|
||||
(rx/take-until stoper))]
|
||||
(rx/concat
|
||||
(when (refs/alignment-activated? (:flags wst))
|
||||
(rx/of (initial-shape-align id)))
|
||||
(rx/map #(apply-temporal-displacement id %) stream)
|
||||
(rx/of (apply-displacement id))))))
|
||||
|
||||
(defn start-move
|
||||
[id]
|
||||
{:pre [(uuid? id)]}
|
||||
(StartMove. id))
|
||||
|
||||
(defrecord StartMoveSelected []
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [pid (get-in state [:workspace :current])
|
||||
selected (get-in state [:workspace pid :selected])]
|
||||
(rx/from-coll (map start-move selected)))))
|
||||
|
||||
(defn start-move-selected
|
||||
[]
|
||||
(StartMoveSelected.))
|
||||
|
||||
;; --- Start shape "edition mode"
|
||||
|
||||
(defn start-edition-mode
|
||||
|
@ -675,96 +638,36 @@
|
|||
(watch [_ state stream]
|
||||
(let [pid (get-in state [:workspace :current])]
|
||||
(->> stream
|
||||
(rx/filter #(= % ::uev/interrupt))
|
||||
(rx/filter #(= % :interrupt))
|
||||
(rx/take 1)
|
||||
(rx/map (fn [_] #(dissoc-in % [:workspace pid :edition]))))))))
|
||||
|
||||
;; --- Select for Drawing
|
||||
|
||||
(defn select-for-drawing
|
||||
[shape]
|
||||
(reify
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [pid (get-in state [:workspace :current])
|
||||
current (get-in state [:workspace pid :drawing-tool])]
|
||||
(if (or (nil? shape)
|
||||
(= shape current))
|
||||
(update-in state [:workspace pid] dissoc :drawing :drawing-tool)
|
||||
(update-in state [:workspace pid] assoc
|
||||
:drawing shape
|
||||
:drawing-tool shape))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Selection Rect Events
|
||||
;; Selection Rect IMPL
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(declare stop-selrect)
|
||||
(declare update-selrect)
|
||||
(declare get-selection-stoper)
|
||||
(declare selection->rect)
|
||||
(declare translate-to-canvas)
|
||||
;; TODO: move to shapes impl maybe...
|
||||
|
||||
;; --- Start Selrect
|
||||
|
||||
(defrecord StartSelrect []
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [id (get-in state [:workspace :current])
|
||||
position (get-in state [:workspace :pointer :viewport])
|
||||
selection {::start position ::stop position}]
|
||||
(assoc-in state [:workspace id :selrect] (selection->rect selection))))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [stoper (get-selection-stoper stream)]
|
||||
;; NOTE: the `viewport-mouse-position` can be derived from `stream`
|
||||
;; but it used from `streams/` ns just for convenience
|
||||
(rx/concat
|
||||
(->> streams/viewport-mouse-position
|
||||
(rx/take-until stoper)
|
||||
(rx/map update-selrect))
|
||||
(rx/just (stop-selrect))))))
|
||||
|
||||
(defn start-selrect
|
||||
[]
|
||||
(StartSelrect.))
|
||||
|
||||
;; --- Update Selrect
|
||||
|
||||
(defrecord UpdateSelrect [position]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [id (get-in state [:workspace :current])]
|
||||
(-> state
|
||||
(assoc-in [:workspace id :selrect ::stop] position)
|
||||
(update-in [:workspace id :selrect] selection->rect)))))
|
||||
|
||||
(defn update-selrect
|
||||
[position]
|
||||
{:pre [(gpt/point? position)]}
|
||||
(UpdateSelrect. position))
|
||||
|
||||
;; --- Clear Selrect
|
||||
|
||||
(defrecord ClearSelrect []
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [id (get-in state [:workspace :current])]
|
||||
(update-in state [:workspace id] dissoc :selrect))))
|
||||
|
||||
(defn clear-selrect
|
||||
[]
|
||||
(ClearSelrect.))
|
||||
|
||||
;; --- Stop Selrect
|
||||
|
||||
(defrecord StopSelrect []
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [id (get-in state [:workspace :current])
|
||||
zoom (get-in state [:workspace id :zoom])
|
||||
rect (-> (get-in state [:workspace id :selrect])
|
||||
(translate-to-canvas zoom))]
|
||||
(rx/of
|
||||
(clear-selrect)
|
||||
(deselect-all)
|
||||
(select-shapes-by-selrect rect)))))
|
||||
|
||||
(defn stop-selrect
|
||||
[]
|
||||
(StopSelrect.))
|
||||
|
||||
;; --- Impl
|
||||
|
||||
(defn- selection->rect
|
||||
(defn selection->rect
|
||||
[data]
|
||||
(let [start (::start data)
|
||||
stop (::stop data)
|
||||
(let [start (:start data)
|
||||
stop (:stop data)
|
||||
start-x (min (:x start) (:x stop))
|
||||
start-y (min (:y start) (:y stop))
|
||||
end-x (max (:x start) (:x stop))
|
||||
|
@ -776,13 +679,7 @@
|
|||
:y2 end-y
|
||||
:type :rect)))
|
||||
|
||||
(defn- get-selection-stoper
|
||||
[stream]
|
||||
(->> (rx/merge (rx/filter #(= % ::uev/interrupt) stream)
|
||||
(rx/filter uev/mouse-up? stream))
|
||||
(rx/take 1)))
|
||||
|
||||
(defn- translate-to-canvas
|
||||
(defn translate-to-canvas
|
||||
"Translate the given rect to the canvas coordinates system."
|
||||
[rect zoom]
|
||||
(let [startx (* c/canvas-start-x zoom)
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
;;
|
||||
;; Copyright (c) 2015-2017 Andrey Antukh <niwi@niwi.nz>
|
||||
|
||||
;; TODO: DEPRECTATED, maintained just for temporal documentation, delete on near future
|
||||
|
||||
(ns uxbox.main.data.workspace-drawing
|
||||
"Workspace drawing data events and impl."
|
||||
(:require [beicon.core :as rx]
|
||||
|
@ -26,390 +28,359 @@
|
|||
;; Data Events
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; --- Select for Drawing
|
||||
|
||||
(deftype SelectForDrawing [shape]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [pid (get-in state [:workspace :current])
|
||||
current (l/focus ul/selected-drawing state)]
|
||||
(if (or (nil? shape)
|
||||
(= shape current))
|
||||
(update-in state [:workspace pid] dissoc :drawing :drawing-tool)
|
||||
(update-in state [:workspace pid] assoc
|
||||
:drawing shape
|
||||
:drawing-tool shape)))))
|
||||
|
||||
(defn select-for-drawing
|
||||
[shape]
|
||||
(SelectForDrawing. shape))
|
||||
|
||||
|
||||
;; --- Clear Drawing State
|
||||
|
||||
(deftype ClearDrawingState []
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [pid (get-in state [:workspace :current])]
|
||||
(update-in state [:workspace pid] dissoc :drawing-tool :drawing))))
|
||||
|
||||
(defn clear-drawing-state
|
||||
[]
|
||||
(ClearDrawingState.))
|
||||
|
||||
;; -- Start Drawing
|
||||
|
||||
(declare on-init-draw)
|
||||
;; (declare on-init-draw)
|
||||
|
||||
(deftype StartDrawing [id object]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update-in state [:workspace :drawing-lock] #(if (nil? %) id %)))
|
||||
;; (deftype StartDrawing [id object]
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (update-in state [:workspace :drawing-lock] #(if (nil? %) id %)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [lock (get-in state [:workspace :drawing-lock])]
|
||||
(if (= lock id)
|
||||
(->> stream
|
||||
(rx/filter #(= % ::uev/interrupt))
|
||||
(rx/take 1)
|
||||
(rx/map (fn [_] #(update % :workspace dissoc :drawing-lock))))
|
||||
(rx/empty))))
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state stream]
|
||||
;; (let [lock (get-in state [:workspace :drawing-lock])]
|
||||
;; (if (= lock id)
|
||||
;; (->> stream
|
||||
;; (rx/filter #(= % :interrupt))
|
||||
;; (rx/take 1)
|
||||
;; (rx/map (fn [_] #(update % :workspace dissoc :drawing-lock))))
|
||||
;; (rx/empty))))
|
||||
|
||||
ptk/EffectEvent
|
||||
(effect [_ state stream]
|
||||
(let [lock (get-in state [:workspace :drawing-lock])]
|
||||
(when (= lock id)
|
||||
(on-init-draw object stream)))))
|
||||
;; ptk/EffectEvent
|
||||
;; (effect [_ state stream]
|
||||
;; (let [lock (get-in state [:workspace :drawing-lock])]
|
||||
;; (when (= lock id)
|
||||
;; (on-init-draw object stream)))))
|
||||
|
||||
(defn start-drawing
|
||||
[object]
|
||||
(let [id (gensym "drawing")]
|
||||
(StartDrawing. id object)))
|
||||
;; (defn start-drawing
|
||||
;; [object]
|
||||
;; (let [id (gensym "drawing")]
|
||||
;; (StartDrawing. id object)))
|
||||
|
||||
;; --- Initialize Draw Area
|
||||
;; ;; --- Initialize Draw Area
|
||||
|
||||
(deftype InitializeDrawing [point]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [pid (get-in state [:workspace :current])
|
||||
shape (get-in state [:workspace pid :drawing])
|
||||
shape (geom/setup shape {:x1 (:x point)
|
||||
:y1 (:y point)
|
||||
:x2 (+ (:x point) 2)
|
||||
:y2 (+ (:y point) 2)})]
|
||||
(assoc-in state [:workspace pid :drawing] shape))))
|
||||
;; (deftype InitializeDrawing [point]
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (let [pid (get-in state [:workspace :current])
|
||||
;; shape (get-in state [:workspace pid :drawing])
|
||||
;; shape (geom/setup shape {:x1 (:x point)
|
||||
;; :y1 (:y point)
|
||||
;; :x2 (+ (:x point) 2)
|
||||
;; :y2 (+ (:y point) 2)})]
|
||||
;; (assoc-in state [:workspace pid :drawing] shape))))
|
||||
|
||||
(defn initialize-drawing
|
||||
[point]
|
||||
{:pre [(gpt/point? point)]}
|
||||
(InitializeDrawing. point))
|
||||
;; (defn initialize-drawing
|
||||
;; [point]
|
||||
;; {:pre [(gpt/point? point)]}
|
||||
;; (InitializeDrawing. point))
|
||||
|
||||
;; --- Update Draw Area State
|
||||
;; ;; --- Update Draw Area State
|
||||
|
||||
(deftype UpdateDrawing [position lock?]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [pid (get-in state [:workspace :current])
|
||||
{:keys [id] :as shape} (-> (get-in state [:workspace pid :drawing])
|
||||
(geom/shape->rect-shape)
|
||||
(geom/size))
|
||||
result (geom/resize-shape :bottom-right shape position lock?)
|
||||
scale (geom/calculate-scale-ratio shape result)
|
||||
resize-mtx (geom/generate-resize-matrix :bottom-right shape scale)]
|
||||
(assoc-in state [:workspace pid :modifiers id] {:resize resize-mtx}))))
|
||||
;; (deftype UpdateDrawing [position lock?]
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (let [pid (get-in state [:workspace :current])
|
||||
;; {:keys [id] :as shape} (-> (get-in state [:workspace pid :drawing])
|
||||
;; (geom/shape->rect-shape)
|
||||
;; (geom/size))
|
||||
;; result (geom/resize-shape :bottom-right shape position lock?)
|
||||
;; scale (geom/calculate-scale-ratio shape result)
|
||||
;; resize-mtx (geom/generate-resize-matrix :bottom-right shape scale)]
|
||||
;; (assoc-in state [:workspace pid :modifiers id] {:resize resize-mtx}))))
|
||||
|
||||
(defn update-drawing
|
||||
[position lock?]
|
||||
{:pre [(gpt/point? position) (boolean? lock?)]}
|
||||
(UpdateDrawing. position lock?))
|
||||
;; (defn update-drawing
|
||||
;; [position lock?]
|
||||
;; {:pre [(gpt/point? position) (boolean? lock?)]}
|
||||
;; (UpdateDrawing. position lock?))
|
||||
|
||||
;; --- Finish Drawin
|
||||
;; ;; --- Finish Drawin
|
||||
|
||||
(deftype FinishDrawing []
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [pid (get-in state [:workspace :current])
|
||||
{:keys [id] :as shape} (get-in state [:workspace pid :drawing])
|
||||
resize-mtx (get-in state [:workspace pid :modifiers id :resize])
|
||||
shape (cond-> shape
|
||||
resize-mtx (geom/transform resize-mtx))]
|
||||
(prn "finish-drawing" shape)
|
||||
(if-not shape
|
||||
(rx/empty)
|
||||
(rx/of (clear-drawing-state)
|
||||
(uds/add-shape shape)
|
||||
(udw/select-first-shape)
|
||||
::uev/interrupt)))))
|
||||
;; (deftype FinishDrawing []
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state stream]
|
||||
;; (let [pid (get-in state [:workspace :current])
|
||||
;; {:keys [id] :as shape} (get-in state [:workspace pid :drawing])
|
||||
;; resize-mtx (get-in state [:workspace pid :modifiers id :resize])
|
||||
;; shape (cond-> shape
|
||||
;; resize-mtx (geom/transform resize-mtx))]
|
||||
;; (prn "finish-drawing" shape)
|
||||
;; (if-not shape
|
||||
;; (rx/empty)
|
||||
;; (rx/of (clear-drawing-state)
|
||||
;; (uds/add-shape shape)
|
||||
;; (udw/select-first-shape)
|
||||
;; :interrupt)))))
|
||||
|
||||
(defn finish-drawing
|
||||
[]
|
||||
(FinishDrawing.))
|
||||
;; (defn finish-drawing
|
||||
;; []
|
||||
;; (FinishDrawing.))
|
||||
|
||||
;; --- Finish Path Drawing
|
||||
;; ;; --- Finish Path Drawing
|
||||
|
||||
(deftype FinishPathDrawing []
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [pid (get-in state [:workspace :current])]
|
||||
(update-in state [:workspace pid :drawing :segments] #(vec (butlast %))))))
|
||||
;; (deftype FinishPathDrawing []
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (let [pid (get-in state [:workspace :current])]
|
||||
;; (update-in state [:workspace pid :drawing :segments] #(vec (butlast %))))))
|
||||
|
||||
(defn finish-path-drawing
|
||||
[]
|
||||
(FinishPathDrawing.))
|
||||
;; (defn finish-path-drawing
|
||||
;; []
|
||||
;; (FinishPathDrawing.))
|
||||
|
||||
;; --- Insert Drawing Path Point
|
||||
;; ;; --- Insert Drawing Path Point
|
||||
|
||||
(deftype InsertDrawingPathPoint [point]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [pid (get-in state [:workspace :current])]
|
||||
(update-in state [:workspace pid :drawing :segments] (fnil conj []) point))))
|
||||
;; (deftype InsertDrawingPathPoint [point]
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (let [pid (get-in state [:workspace :current])]
|
||||
;; (update-in state [:workspace pid :drawing :segments] (fnil conj []) point))))
|
||||
|
||||
(defn insert-drawing-path-point
|
||||
[point]
|
||||
{:pre [(gpt/point? point)]}
|
||||
(InsertDrawingPathPoint. point))
|
||||
;; (defn insert-drawing-path-point
|
||||
;; [point]
|
||||
;; {:pre [(gpt/point? point)]}
|
||||
;; (InsertDrawingPathPoint. point))
|
||||
|
||||
;; --- Update Drawing Path Point
|
||||
;; ;; --- Update Drawing Path Point
|
||||
|
||||
(deftype UpdateDrawingPathPoint [index point]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [pid (get-in state [:workspace :current])
|
||||
segments (count (get-in state [:workspace pid :drawing :segments]))
|
||||
exists? (< -1 index segments)]
|
||||
(cond-> state
|
||||
exists? (assoc-in [:workspace pid :drawing :segments index] point)))))
|
||||
;; (deftype UpdateDrawingPathPoint [index point]
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (let [pid (get-in state [:workspace :current])
|
||||
;; segments (count (get-in state [:workspace pid :drawing :segments]))
|
||||
;; exists? (< -1 index segments)]
|
||||
;; (cond-> state
|
||||
;; exists? (assoc-in [:workspace pid :drawing :segments index] point)))))
|
||||
|
||||
(defn update-drawing-path-point
|
||||
[index point]
|
||||
{:pre [(integer? index) (gpt/point? point)]}
|
||||
(UpdateDrawingPathPoint. index point))
|
||||
;; (defn update-drawing-path-point
|
||||
;; [index point]
|
||||
;; {:pre [(integer? index) (gpt/point? point)]}
|
||||
;; (UpdateDrawingPathPoint. index point))
|
||||
|
||||
;; --- Close Drawing Path
|
||||
;; ;; --- Close Drawing Path
|
||||
|
||||
(deftype CloseDrawingPath []
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [pid (get-in state [:workspace :current])]
|
||||
(assoc-in state [:workspace pid :drawing :close?] true)))
|
||||
;; (deftype CloseDrawingPath []
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (let [pid (get-in state [:workspace :current])]
|
||||
;; (assoc-in state [:workspace pid :drawing :close?] true)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(rx/of ::uev/interrupt)))
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state stream]
|
||||
;; (rx/of :interrupt)))
|
||||
|
||||
(defn close-drawing-path
|
||||
[]
|
||||
(CloseDrawingPath.))
|
||||
;; (defn close-drawing-path
|
||||
;; []
|
||||
;; (CloseDrawingPath.))
|
||||
|
||||
;; --- Simplify Drawing Path
|
||||
;; ;; --- Simplify Drawing Path
|
||||
|
||||
(deftype SimplifyDrawingPath [tolerance]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [pid (get-in state [:workspace :current])]
|
||||
(update-in state [:workspace pid :drawing :segments] pth/simplify tolerance))))
|
||||
;; (deftype SimplifyDrawingPath [tolerance]
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (let [pid (get-in state [:workspace :current])]
|
||||
;; (update-in state [:workspace pid :drawing :segments] pth/simplify tolerance))))
|
||||
|
||||
(defn simplify-drawing-path
|
||||
[tolerance]
|
||||
{:pre [(number? tolerance)]}
|
||||
(SimplifyDrawingPath. tolerance))
|
||||
;; (defn simplify-drawing-path
|
||||
;; [tolerance]
|
||||
;; {:pre [(number? tolerance)]}
|
||||
;; (SimplifyDrawingPath. tolerance))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Drawing Implementation
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;; Drawing Implementation
|
||||
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(def ^:private canvas-coords
|
||||
(gpt/point c/canvas-start-x
|
||||
c/canvas-start-y))
|
||||
;; (def ^:private canvas-coords
|
||||
;; (gpt/point c/canvas-start-x
|
||||
;; c/canvas-start-y))
|
||||
|
||||
(defn- conditional-align
|
||||
[point]
|
||||
(if @refs/selected-alignment
|
||||
(uwrk/align-point point)
|
||||
(rx/of point)))
|
||||
;; (defn- conditional-align
|
||||
;; [point]
|
||||
;; (if @refs/selected-alignment
|
||||
;; (uwrk/align-point point)
|
||||
;; (rx/of point)))
|
||||
|
||||
(defn- translate-to-canvas
|
||||
[point]
|
||||
(-> point
|
||||
(gpt/subtract (gpt/multiply canvas-coords @refs/selected-zoom))
|
||||
(gpt/divide @refs/selected-zoom)))
|
||||
;; (defn- translate-to-canvas
|
||||
;; [point]
|
||||
;; (-> point
|
||||
;; (gpt/subtract (gpt/multiply canvas-coords @refs/selected-zoom))
|
||||
;; (gpt/divide @refs/selected-zoom)))
|
||||
|
||||
(declare on-init-draw-icon)
|
||||
(declare on-init-draw-image)
|
||||
(declare on-init-draw-path)
|
||||
(declare on-init-draw-free-path)
|
||||
(declare on-init-draw-generic)
|
||||
;; (declare on-init-draw-icon)
|
||||
;; (declare on-init-draw-image)
|
||||
;; (declare on-init-draw-path)
|
||||
;; (declare on-init-draw-free-path)
|
||||
;; (declare on-init-draw-generic)
|
||||
|
||||
(defn- on-init-draw
|
||||
"Function execution when draw shape operation is requested.
|
||||
This is a entry point for the draw interaction."
|
||||
[shape stream]
|
||||
(let [stoper (->> stream
|
||||
(rx/filter #(= % ::uev/interrupt))
|
||||
(rx/take 1))]
|
||||
(case (:type shape)
|
||||
:icon (on-init-draw-icon shape)
|
||||
:image (on-init-draw-image shape)
|
||||
:path (if (:free shape)
|
||||
(on-init-draw-free-path shape stoper)
|
||||
(on-init-draw-path shape stoper))
|
||||
(on-init-draw-generic shape stoper))))
|
||||
;; (defn- on-init-draw
|
||||
;; "Function execution when draw shape operation is requested.
|
||||
;; This is a entry point for the draw interaction."
|
||||
;; [shape stream]
|
||||
;; (let [stoper (->> stream
|
||||
;; (rx/filter #(= % :interrupt))
|
||||
;; (rx/take 1))]
|
||||
;; (case (:type shape)
|
||||
;; :icon (on-init-draw-icon shape)
|
||||
;; :image (on-init-draw-image shape)
|
||||
;; :path (if (:free shape)
|
||||
;; (on-init-draw-free-path shape stoper)
|
||||
;; (on-init-draw-path shape stoper))
|
||||
;; (on-init-draw-generic shape stoper))))
|
||||
|
||||
(defn- on-init-draw-generic
|
||||
[shape stoper]
|
||||
(let [stoper (rx/merge stoper (->> streams/events
|
||||
(rx/filter uev/mouse-up?)
|
||||
(rx/take 1)))
|
||||
start? (volatile! true)
|
||||
mouse (->> streams/viewport-mouse-position
|
||||
(rx/take-until stoper)
|
||||
(rx/mapcat conditional-align)
|
||||
(rx/map translate-to-canvas)
|
||||
(rx/with-latest vector streams/mouse-position-ctrl))]
|
||||
;; (defn- on-init-draw-generic
|
||||
;; [shape stoper]
|
||||
;; (let [stoper (rx/merge stoper (->> streams/events
|
||||
;; (rx/filter uev/mouse-up?)
|
||||
;; (rx/take 1)))
|
||||
;; start? (volatile! true)
|
||||
;; mouse (->> streams/viewport-mouse-position
|
||||
;; (rx/take-until stoper)
|
||||
;; (rx/mapcat conditional-align)
|
||||
;; (rx/map translate-to-canvas)
|
||||
;; (rx/with-latest vector streams/mouse-position-ctrl))]
|
||||
|
||||
(letfn [(on-position [[point ctrl?]]
|
||||
(if @start?
|
||||
(do
|
||||
(st/emit! (initialize-drawing point))
|
||||
(vreset! start? false))
|
||||
(st/emit! (update-drawing point ctrl?))))
|
||||
;; (letfn [(on-position [[point ctrl?]]
|
||||
;; (if @start?
|
||||
;; (do
|
||||
;; (st/emit! (initialize-drawing point))
|
||||
;; (vreset! start? false))
|
||||
;; (st/emit! (update-drawing point ctrl?))))
|
||||
|
||||
(on-finish []
|
||||
(if @start?
|
||||
(st/emit! ::uev/interrupt)
|
||||
(st/emit! (finish-drawing))))]
|
||||
(rx/subscribe mouse on-position nil on-finish))))
|
||||
;; (on-finish []
|
||||
;; (if @start?
|
||||
;; (st/emit! ::uev/interrupt)
|
||||
;; (st/emit! (finish-drawing))))]
|
||||
;; (rx/subscribe mouse on-position nil on-finish))))
|
||||
|
||||
(defn- on-init-draw-icon
|
||||
[{:keys [metadata] :as shape}]
|
||||
(let [{:keys [x y]} (gpt/divide @refs/canvas-mouse-position
|
||||
@refs/selected-zoom)
|
||||
{:keys [width height]} metadata
|
||||
proportion (/ width height)
|
||||
props {:x1 x
|
||||
:y1 y
|
||||
:x2 (+ x 200)
|
||||
:y2 (+ y (/ 200 proportion))}
|
||||
shape (geom/setup shape props)]
|
||||
(st/emit! (uds/add-shape shape)
|
||||
(udw/select-first-shape)
|
||||
(select-for-drawing nil)
|
||||
::uev/interrupt)))
|
||||
;; (defn- on-init-draw-icon
|
||||
;; [{:keys [metadata] :as shape}]
|
||||
;; (let [{:keys [x y]} (gpt/divide @refs/canvas-mouse-position
|
||||
;; @refs/selected-zoom)
|
||||
;; {:keys [width height]} metadata
|
||||
;; proportion (/ width height)
|
||||
;; props {:x1 x
|
||||
;; :y1 y
|
||||
;; :x2 (+ x 200)
|
||||
;; :y2 (+ y (/ 200 proportion))}
|
||||
;; shape (geom/setup shape props)]
|
||||
;; (st/emit! (uds/add-shape shape)
|
||||
;; (udw/select-first-shape)
|
||||
;; (select-for-drawing nil)
|
||||
;; ::uev/interrupt)))
|
||||
|
||||
(defn- on-init-draw-image
|
||||
[{:keys [metadata] :as shape}]
|
||||
(let [{:keys [x y]} (gpt/divide @refs/canvas-mouse-position
|
||||
@refs/selected-zoom)
|
||||
{:keys [width height]} metadata
|
||||
proportion (/ width height)
|
||||
props {:x1 x
|
||||
:y1 y
|
||||
:x2 (+ x width)
|
||||
:y2 (+ y height)}
|
||||
shape (geom/setup shape props)]
|
||||
(st/emit! (uds/add-shape shape)
|
||||
(udw/select-first-shape)
|
||||
(select-for-drawing nil)
|
||||
::uev/interrupt)))
|
||||
;; (defn- on-init-draw-image
|
||||
;; [{:keys [metadata] :as shape}]
|
||||
;; (let [{:keys [x y]} (gpt/divide @refs/canvas-mouse-position
|
||||
;; @refs/selected-zoom)
|
||||
;; {:keys [width height]} metadata
|
||||
;; proportion (/ width height)
|
||||
;; props {:x1 x
|
||||
;; :y1 y
|
||||
;; :x2 (+ x width)
|
||||
;; :y2 (+ y height)}
|
||||
;; shape (geom/setup shape props)]
|
||||
;; (st/emit! (uds/add-shape shape)
|
||||
;; (udw/select-first-shape)
|
||||
;; (select-for-drawing nil)
|
||||
;; ::uev/interrupt)))
|
||||
|
||||
(def ^:private immanted-zones
|
||||
(let [transform #(vector (- % 7) (+ % 7) %)]
|
||||
(concat
|
||||
(mapv transform (range 0 181 15))
|
||||
(mapv (comp transform -) (range 0 181 15)))))
|
||||
;; (def ^:private immanted-zones
|
||||
;; (let [transform #(vector (- % 7) (+ % 7) %)]
|
||||
;; (concat
|
||||
;; (mapv transform (range 0 181 15))
|
||||
;; (mapv (comp transform -) (range 0 181 15)))))
|
||||
|
||||
(defn- align-position
|
||||
[angle pos]
|
||||
(reduce (fn [pos [a1 a2 v]]
|
||||
(if (< a1 angle a2)
|
||||
(reduced (gpt/update-angle pos v))
|
||||
pos))
|
||||
pos
|
||||
immanted-zones))
|
||||
;; (defn- align-position
|
||||
;; [angle pos]
|
||||
;; (reduce (fn [pos [a1 a2 v]]
|
||||
;; (if (< a1 angle a2)
|
||||
;; (reduced (gpt/update-angle pos v))
|
||||
;; pos))
|
||||
;; pos
|
||||
;; immanted-zones))
|
||||
|
||||
(defn- get-path-stoper-stream
|
||||
([stoper] (get-path-stoper-stream stoper false))
|
||||
([stoper mouseup?]
|
||||
(letfn [(stoper-event? [{:keys [type shift] :as event}]
|
||||
(or (and (uev/mouse-event? event)
|
||||
(or (and (= type :double-click) shift)
|
||||
(= type :context-menu)
|
||||
(and mouseup? (= type :up))))
|
||||
(and (uev/keyboard-event? event)
|
||||
(= type :down)
|
||||
(= 13 (:key event)))))]
|
||||
(->> (rx/filter stoper-event? streams/events)
|
||||
(rx/merge stoper)
|
||||
(rx/take 1)
|
||||
(rx/share)))))
|
||||
;; (defn- get-path-stoper-stream
|
||||
;; ([stoper] (get-path-stoper-stream stoper false))
|
||||
;; ([stoper mouseup?]
|
||||
;; (letfn [(stoper-event? [{:keys [type shift] :as event}]
|
||||
;; (or (and (uev/mouse-event? event)
|
||||
;; (or (and (= type :double-click) shift)
|
||||
;; (= type :context-menu)
|
||||
;; (and mouseup? (= type :up))))
|
||||
;; (and (uev/keyboard-event? event)
|
||||
;; (= type :down)
|
||||
;; (= 13 (:key event)))))]
|
||||
;; (->> (rx/filter stoper-event? streams/events)
|
||||
;; (rx/merge stoper)
|
||||
;; (rx/take 1)
|
||||
;; (rx/share)))))
|
||||
|
||||
(defn- get-path-point-stream
|
||||
[]
|
||||
(->> streams/events
|
||||
(rx/filter uev/mouse-click?)
|
||||
(rx/filter #(false? (:shift %)))))
|
||||
;; (defn- get-path-point-stream
|
||||
;; []
|
||||
;; (->> streams/events
|
||||
;; (rx/filter uev/mouse-click?)
|
||||
;; (rx/filter #(false? (:shift %)))))
|
||||
|
||||
(defn- on-init-draw-free-path
|
||||
[shape stoper]
|
||||
(let [stoper (get-path-stoper-stream stoper true)
|
||||
mouse (->> streams/viewport-mouse-position
|
||||
(rx/mapcat conditional-align)
|
||||
(rx/map translate-to-canvas))
|
||||
;; (defn- on-init-draw-free-path
|
||||
;; [shape stoper]
|
||||
;; (let [stoper (get-path-stoper-stream stoper true)
|
||||
;; mouse (->> streams/viewport-mouse-position
|
||||
;; (rx/mapcat conditional-align)
|
||||
;; (rx/map translate-to-canvas))
|
||||
|
||||
stream (rx/take-until stoper mouse)]
|
||||
(letfn [(on-draw [point]
|
||||
(st/emit! (insert-drawing-path-point point)))
|
||||
(on-end []
|
||||
(st/emit! (simplify-drawing-path 0.3)
|
||||
(finish-drawing)))]
|
||||
(rx/subscribe stream on-draw nil on-end))))
|
||||
;; stream (rx/take-until stoper mouse)]
|
||||
;; (letfn [(on-draw [point]
|
||||
;; (st/emit! (insert-drawing-path-point point)))
|
||||
;; (on-end []
|
||||
;; (st/emit! (simplify-drawing-path 0.3)
|
||||
;; (finish-drawing)))]
|
||||
;; (rx/subscribe stream on-draw nil on-end))))
|
||||
|
||||
(defn- on-init-draw-path
|
||||
[shape stoper]
|
||||
(let [last-point (volatile! @refs/canvas-mouse-position)
|
||||
stoper (get-path-stoper-stream stoper)
|
||||
mouse (->> (rx/sample 10 streams/viewport-mouse-position)
|
||||
(rx/mapcat conditional-align)
|
||||
(rx/map translate-to-canvas))
|
||||
points (->> (get-path-point-stream)
|
||||
(rx/with-latest vector mouse)
|
||||
(rx/map second)
|
||||
(rx/take-until stoper))
|
||||
counter (rx/merge (rx/scan #(inc %) 1 points) (rx/of 1))
|
||||
stream (->> mouse
|
||||
(rx/with-latest vector streams/mouse-position-ctrl)
|
||||
(rx/with-latest vector counter)
|
||||
(rx/map flatten)
|
||||
(rx/take-until stoper))]
|
||||
;; (defn- on-init-draw-path
|
||||
;; [shape stoper]
|
||||
;; (let [last-point (volatile! @refs/canvas-mouse-position)
|
||||
;; stoper (get-path-stoper-stream stoper)
|
||||
;; mouse (->> (rx/sample 10 streams/viewport-mouse-position)
|
||||
;; (rx/mapcat conditional-align)
|
||||
;; (rx/map translate-to-canvas))
|
||||
;; points (->> (get-path-point-stream)
|
||||
;; (rx/with-latest vector mouse)
|
||||
;; (rx/map second)
|
||||
;; (rx/take-until stoper))
|
||||
;; counter (rx/merge (rx/scan #(inc %) 1 points) (rx/of 1))
|
||||
;; stream (->> mouse
|
||||
;; (rx/with-latest vector streams/mouse-position-ctrl)
|
||||
;; (rx/with-latest vector counter)
|
||||
;; (rx/map flatten)
|
||||
;; (rx/take-until stoper))]
|
||||
|
||||
(letfn [(on-point [point]
|
||||
(vreset! last-point point)
|
||||
(st/emit! (insert-drawing-path-point point)))
|
||||
;; (letfn [(on-point [point]
|
||||
;; (vreset! last-point point)
|
||||
;; (st/emit! (insert-drawing-path-point point)))
|
||||
|
||||
(on-generic-draw [point counter]
|
||||
(st/emit! (update-drawing-path-point counter point)))
|
||||
;; (on-generic-draw [point counter]
|
||||
;; (st/emit! (update-drawing-path-point counter point)))
|
||||
|
||||
(on-assisted-draw [point counter]
|
||||
(let [point (as-> point $
|
||||
(gpt/subtract $ @last-point)
|
||||
(align-position (gpt/angle $) $)
|
||||
(gpt/add $ @last-point))]
|
||||
(st/emit! (update-drawing-path-point counter point))))
|
||||
;; (on-assisted-draw [point counter]
|
||||
;; (let [point (as-> point $
|
||||
;; (gpt/subtract $ @last-point)
|
||||
;; (align-position (gpt/angle $) $)
|
||||
;; (gpt/add $ @last-point))]
|
||||
;; (st/emit! (update-drawing-path-point counter point))))
|
||||
|
||||
(on-draw [[point ctrl? counter]]
|
||||
(if ctrl?
|
||||
(on-assisted-draw point counter)
|
||||
(on-generic-draw point counter)))
|
||||
;; (on-draw [[point ctrl? counter]]
|
||||
;; (if ctrl?
|
||||
;; (on-assisted-draw point counter)
|
||||
;; (on-generic-draw point counter)))
|
||||
|
||||
(on-finish []
|
||||
(st/emit! (finish-path-drawing)
|
||||
(finish-drawing)))]
|
||||
;; (on-finish []
|
||||
;; (st/emit! (finish-path-drawing)
|
||||
;; (finish-drawing)))]
|
||||
|
||||
;; Initialize path drawing
|
||||
(st/emit! (insert-drawing-path-point @last-point)
|
||||
(insert-drawing-path-point @last-point))
|
||||
;; ;; Initialize path drawing
|
||||
;; (st/emit! (insert-drawing-path-point @last-point)
|
||||
;; (insert-drawing-path-point @last-point))
|
||||
|
||||
(rx/subscribe points on-point)
|
||||
(rx/subscribe stream on-draw nil on-finish))))
|
||||
;; (rx/subscribe points on-point)
|
||||
;; (rx/subscribe stream on-draw nil on-finish))))
|
||||
|
|
|
@ -409,19 +409,15 @@
|
|||
(declare setup-rect)
|
||||
(declare setup-image)
|
||||
(declare setup-circle)
|
||||
(declare setup-group)
|
||||
|
||||
(defn setup
|
||||
"A function that initializes the first coordinates for
|
||||
the shape. Used mainly for draw operations."
|
||||
[shape props]
|
||||
(case (:type shape)
|
||||
:rect (setup-rect shape props)
|
||||
:icon (setup-rect shape props)
|
||||
:image (setup-image shape props)
|
||||
:text (setup-rect shape props)
|
||||
:circle (setup-circle shape props)
|
||||
:group (setup-group shape props)))
|
||||
(setup-rect shape props)))
|
||||
|
||||
(defn- setup-rect
|
||||
"A specialized function for setup rect-like shapes."
|
||||
|
@ -432,11 +428,6 @@
|
|||
:x2 x2
|
||||
:y2 y2))
|
||||
|
||||
(defn- setup-group
|
||||
"A specialized function for setup group shapes."
|
||||
[shape {:keys [x1 y1 x2 y2] :as props}]
|
||||
(assoc shape :initial props))
|
||||
|
||||
(defn- setup-circle
|
||||
"A specialized function for setup circle shapes."
|
||||
[shape {:keys [x1 y1 x2 y2]}]
|
||||
|
@ -447,8 +438,8 @@
|
|||
:ry (mth/abs (- y2 y1))))
|
||||
|
||||
(defn- setup-image
|
||||
[{:keys [view-box] :as shape} {:keys [x1 y1 x2 y2] :as props}]
|
||||
(let [[_ _ width height] view-box]
|
||||
[{:keys [metadata] :as shape} {:keys [x1 y1 x2 y2] :as props}]
|
||||
(let [{:keys [width height]} metadata]
|
||||
(assoc shape
|
||||
:x1 x1
|
||||
:y1 y1
|
||||
|
@ -470,7 +461,6 @@
|
|||
(case type
|
||||
:circle (circle->rect-shape state shape)
|
||||
:path (path->rect-shape state shape)
|
||||
:group (group->rect-shape state shape)
|
||||
shape)))
|
||||
|
||||
(defn shapes->rect-shape
|
||||
|
@ -488,13 +478,6 @@
|
|||
:y2 maxy
|
||||
:type :rect})))
|
||||
|
||||
(defn- group->rect-shape
|
||||
[state {:keys [id items rotation] :as group}]
|
||||
(let [shapes (map #(get-in state [:shapes %]) items)]
|
||||
(-> (shapes->rect-shape state shapes)
|
||||
(assoc :rotation rotation)
|
||||
(assoc :id id))))
|
||||
|
||||
(defn- path->rect-shape
|
||||
[state {:keys [segments] :as shape}]
|
||||
(let [minx (apply min (map :x segments))
|
||||
|
@ -606,32 +589,13 @@
|
|||
([shape]
|
||||
(selection-rect @st/state shape))
|
||||
([state shape]
|
||||
(case (:type shape)
|
||||
:group (selection-rect-group state shape)
|
||||
(selection-rect-generic state shape))))
|
||||
|
||||
(defn- selection-rect-generic
|
||||
[state {:keys [id modifiers] :as shape}]
|
||||
(let [{:keys [displacement resize]} modifiers]
|
||||
(-> (shape->rect-shape shape)
|
||||
(assoc :type :rect :id id)
|
||||
(transform (or resize (gmt/matrix)))
|
||||
(transform (or displacement (gmt/matrix)))
|
||||
(rotate-shape)
|
||||
(size))))
|
||||
|
||||
(defn- selection-rect-group
|
||||
[state {:keys [id group items modifiers] :as shape}]
|
||||
(let [{:keys [displacement resize]} modifiers
|
||||
shapes (->> items
|
||||
(map #(get-in state [:shapes %]))
|
||||
(map #(selection-rect state %)))]
|
||||
(-> (shapes->rect-shape shapes)
|
||||
(assoc :id id)
|
||||
(transform (or resize (gmt/matrix)))
|
||||
(transform (or displacement (gmt/matrix)))
|
||||
(rotate-shape)
|
||||
(size))))
|
||||
(let [{:keys [displacement resize]} (:modifiers shape)]
|
||||
(-> (shape->rect-shape shape)
|
||||
(assoc :type :rect :id (:id shape))
|
||||
(transform (or resize (gmt/matrix)))
|
||||
(transform (or displacement (gmt/matrix)))
|
||||
(rotate-shape)
|
||||
(size)))))
|
||||
|
||||
;; --- Helpers
|
||||
|
||||
|
|
|
@ -6,13 +6,45 @@
|
|||
|
||||
(ns uxbox.main.ui.shapes.common
|
||||
(:require
|
||||
[uxbox.main.data.workspace :as udw]
|
||||
[potok.core :as ptk]
|
||||
[beicon.core :as rx]
|
||||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.ui.keyboard :as kbd]
|
||||
[uxbox.main.ui.workspace.streams :as ws]
|
||||
[uxbox.util.dom :as dom]))
|
||||
|
||||
;; --- Events
|
||||
;; --- Shape Movement (by mouse)
|
||||
|
||||
(defn start-move
|
||||
[id]
|
||||
{:pre [(uuid? id)]}
|
||||
(reify
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [pid (get-in state [:workspace :current])
|
||||
wst (get-in state [:workspace pid])
|
||||
stoper (->> ws/interaction-events
|
||||
(rx/filter ws/mouse-up?)
|
||||
(rx/take 1))
|
||||
stream (->> ws/mouse-position-deltas
|
||||
(rx/take-until stoper))]
|
||||
(rx/concat
|
||||
(when (refs/alignment-activated? (:flags wst))
|
||||
(rx/of (dw/initial-shape-align id)))
|
||||
(rx/map #(dw/apply-temporal-displacement id %) stream)
|
||||
(rx/of (dw/apply-displacement id)))))))
|
||||
|
||||
(defn start-move-selected
|
||||
[]
|
||||
(reify
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [pid (get-in state [:workspace :current])
|
||||
selected (get-in state [:workspace pid :selected])]
|
||||
(rx/from-coll (map start-move selected))))))
|
||||
|
||||
|
||||
(defn on-mouse-down
|
||||
[event {:keys [id group] :as shape} selected]
|
||||
|
@ -26,18 +58,18 @@
|
|||
(and (not selected?) (empty? selected))
|
||||
(do
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! (udw/select-shape id)
|
||||
(udw/start-move-selected)))
|
||||
(st/emit! (dw/select-shape id)
|
||||
(start-move-selected)))
|
||||
|
||||
(and (not selected?) (not (empty? selected)))
|
||||
(do
|
||||
(dom/stop-propagation event)
|
||||
(if (kbd/shift? event)
|
||||
(st/emit! (udw/select-shape id))
|
||||
(st/emit! (udw/deselect-all)
|
||||
(udw/select-shape id)
|
||||
(udw/start-move-selected))))
|
||||
(st/emit! (dw/select-shape id))
|
||||
(st/emit! (dw/deselect-all)
|
||||
(dw/select-shape id)
|
||||
(start-move-selected))))
|
||||
:else
|
||||
(do
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! (udw/start-move-selected)))))))
|
||||
(st/emit! (start-move-selected)))))))
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.streams :as streams]
|
||||
[uxbox.main.ui.confirm]
|
||||
[uxbox.main.ui.keyboard :as kbd]
|
||||
[uxbox.main.ui.messages :refer [messages-widget]]
|
||||
|
@ -32,7 +31,7 @@
|
|||
[uxbox.main.ui.workspace.shortcuts :as shortcuts]
|
||||
[uxbox.main.ui.workspace.sidebar :refer [left-sidebar right-sidebar]]
|
||||
[uxbox.main.ui.workspace.sidebar.history :refer [history-dialog]]
|
||||
[uxbox.main.user-events :as uev]
|
||||
[uxbox.main.ui.workspace.streams :as ws]
|
||||
[uxbox.util.data :refer [classnames]]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.geom.point :as gpt]
|
||||
|
@ -42,10 +41,11 @@
|
|||
|
||||
(defn- on-scroll
|
||||
[event]
|
||||
(let [target (.-target event)
|
||||
;; TODO: refactor
|
||||
#_(let [target (.-target event)
|
||||
top (.-scrollTop target)
|
||||
left (.-scrollLeft target)]
|
||||
(st/emit! (uev/scroll-event (gpt/point left top)))))
|
||||
(ws/emit! (ws/scroll-event (gpt/point left top)))))
|
||||
|
||||
(defn- on-wheel
|
||||
[event canvas]
|
||||
|
|
|
@ -7,17 +7,298 @@
|
|||
(ns uxbox.main.ui.workspace.drawarea
|
||||
"Draw interaction and component."
|
||||
(:require
|
||||
[beicon.core :as rx]
|
||||
[potok.core :as ptk]
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.main.data.workspace :as udw]
|
||||
[uxbox.main.data.workspace-drawing :as udwd]
|
||||
[uxbox.main.constants :as c]
|
||||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.data.shapes :as ds]
|
||||
[uxbox.main.geom :as geom]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.streams :as streams]
|
||||
[uxbox.main.ui.shapes :as shapes]
|
||||
[uxbox.main.ui.workspace.streams :as uws]
|
||||
[uxbox.main.workers :as uwrk]
|
||||
[uxbox.util.math :as mth]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.geom.path :as path]
|
||||
[uxbox.util.geom.point :as gpt]))
|
||||
|
||||
(def ^:private canvas-coords
|
||||
(gpt/point c/canvas-start-x
|
||||
c/canvas-start-y))
|
||||
|
||||
;; --- Events
|
||||
|
||||
(declare handle-drawing)
|
||||
(declare handle-drawing-generic)
|
||||
(declare handle-drawing-path)
|
||||
(declare handle-drawing-free-path)
|
||||
(declare handle-finish-drawing)
|
||||
|
||||
(defn start-drawing
|
||||
[object]
|
||||
(let [id (gensym "drawing")]
|
||||
(reify
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update-in state [:workspace :drawing-lock] #(if (nil? %) id %)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [lock (get-in state [:workspace :drawing-lock])]
|
||||
(if (= lock id)
|
||||
(rx/merge (->> stream
|
||||
(rx/filter #(= % handle-finish-drawing))
|
||||
(rx/take 1)
|
||||
(rx/map (fn [_] #(update % :workspace dissoc :drawing-lock))))
|
||||
(rx/of (handle-drawing object)))
|
||||
(rx/empty)))))))
|
||||
|
||||
(defn- translate-to-canvas [point zoom]
|
||||
(-> point
|
||||
(gpt/subtract (gpt/multiply canvas-coords zoom))
|
||||
(gpt/divide zoom)))
|
||||
|
||||
(defn- conditional-align [point align?]
|
||||
(if align?
|
||||
(uwrk/align-point point)
|
||||
(rx/of point)))
|
||||
|
||||
|
||||
;; TODO: maybe this should be a simple function
|
||||
(defn handle-drawing
|
||||
[shape]
|
||||
(reify
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(rx/of
|
||||
(if (= :path (:type shape))
|
||||
(if (:free shape)
|
||||
(handle-drawing-free-path shape)
|
||||
(handle-drawing-path shape))
|
||||
(handle-drawing-generic shape))))))
|
||||
|
||||
(defn- handle-drawing-generic
|
||||
[shape]
|
||||
(letfn [(initialize-drawing [state point]
|
||||
(let [pid (get-in state [:workspace :current])
|
||||
shape (get-in state [:workspace pid :drawing])
|
||||
shape (geom/setup shape {:x1 (:x point)
|
||||
:y1 (:y point)
|
||||
:x2 (+ (:x point) 2)
|
||||
:y2 (+ (:y point) 2)})]
|
||||
(assoc-in state [:workspace pid :drawing] (assoc shape ::initialized? true))))
|
||||
|
||||
;; TODO: this is a new approach for resizing, when all the
|
||||
;; subsystem are migrated to the new resize approach, this
|
||||
;; function should be moved into uxbox.main.geom ns.
|
||||
(resize-shape [shape point lock?]
|
||||
(if (= (:type shape) :circle)
|
||||
(let [rx (mth/abs (- (:x point) (:cx shape)))
|
||||
ry (mth/abs (- (:y point) (:cy shape)))]
|
||||
(if lock?
|
||||
(assoc shape :rx rx :ry ry)
|
||||
(assoc shape :rx rx :ry rx)))
|
||||
(let [width (- (:x point) (:x1 shape))
|
||||
height (- (:y point) (:y1 shape))
|
||||
proportion (:proportion shape 1)]
|
||||
(assoc shape
|
||||
:x2 (+ (:x1 shape) width)
|
||||
:y2 (if lock?
|
||||
(+ (:y1 shape) (/ width proportion))
|
||||
(+ (:y1 shape) height))))))
|
||||
|
||||
(update-drawing [state point lock?]
|
||||
(let [pid (get-in state [:workspace :current])]
|
||||
(update-in state [:workspace pid :drawing] resize-shape point lock?)))]
|
||||
|
||||
(reify
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [pid (get-in state [:workspace :current])
|
||||
zoom (get-in state [:workspace pid :zoom])
|
||||
flags (get-in state [:workspace pid :flags])
|
||||
align? (refs/alignment-activated? flags)
|
||||
|
||||
stoper (->> (rx/filter #(or (uws/mouse-up? %) (= % :interrupt)) stream)
|
||||
(rx/take 1))
|
||||
|
||||
mouse (->> uws/viewport-mouse-position
|
||||
(rx/mapcat #(conditional-align % align?))
|
||||
(rx/map #(translate-to-canvas % zoom))
|
||||
(rx/with-latest vector uws/mouse-position-ctrl))]
|
||||
(rx/concat
|
||||
(rx/of #(initialize-drawing % @uws/canvas-mouse-position))
|
||||
(->> mouse
|
||||
(rx/map (fn [[pt ctrl?]] #(update-drawing % pt ctrl?)))
|
||||
(rx/take-until stoper))
|
||||
(rx/of handle-finish-drawing)))))))
|
||||
|
||||
(defn handle-drawing-path
|
||||
[shape]
|
||||
(letfn [(stoper-event? [{:keys [type shift] :as event}]
|
||||
(or (= event :interrupt)
|
||||
(and (uws/mouse-event? event)
|
||||
(or (and (= type :double-click) shift)
|
||||
(= type :context-menu)))
|
||||
(and (uws/keyboard-event? event)
|
||||
(= type :down)
|
||||
(= 13 (:key event)))))
|
||||
|
||||
(initialize-drawing [state point]
|
||||
(let [pid (get-in state [:workspace :current])]
|
||||
(-> state
|
||||
(assoc-in [:workspace pid :drawing :segments] [point point])
|
||||
(assoc-in [:workspace pid :drawing ::initialized?] true))))
|
||||
|
||||
(insert-point-segment [state point]
|
||||
(let [pid (get-in state [:workspace :current])]
|
||||
(update-in state [:workspace pid :drawing :segments] (fnil conj []) point)))
|
||||
|
||||
(update-point-segment [state index point]
|
||||
(let [pid (get-in state [:workspace :current])
|
||||
segments (count (get-in state [:workspace pid :drawing :segments]))
|
||||
exists? (< -1 index segments)]
|
||||
(cond-> state
|
||||
exists? (assoc-in [:workspace pid :drawing :segments index] point))))
|
||||
|
||||
(remove-dangling-segmnet [state]
|
||||
(let [pid (get-in state [:workspace :current])]
|
||||
(update-in state [:workspace pid :drawing :segments] #(vec (butlast %)))))]
|
||||
(reify
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [pid (get-in state [:workspace :current])
|
||||
zoom (get-in state [:workspace pid :zoom])
|
||||
flags (get-in state [:workspace pid :flags])
|
||||
align? (refs/alignment-activated? flags)
|
||||
|
||||
last-point (volatile! @uws/canvas-mouse-position)
|
||||
|
||||
stoper (->> (rx/filter stoper-event? stream)
|
||||
(rx/take 1))
|
||||
|
||||
mouse (->> (rx/sample 10 uws/viewport-mouse-position)
|
||||
(rx/mapcat #(conditional-align % align?))
|
||||
(rx/map #(translate-to-canvas % zoom)))
|
||||
|
||||
points (->> stream
|
||||
(rx/filter uws/mouse-click?)
|
||||
(rx/filter #(false? (:shift %)))
|
||||
(rx/with-latest vector mouse)
|
||||
(rx/map second))
|
||||
|
||||
counter (rx/merge (rx/scan #(inc %) 1 points) (rx/of 1))
|
||||
stream' (->> mouse
|
||||
(rx/with-latest vector uws/mouse-position-ctrl)
|
||||
(rx/with-latest vector counter)
|
||||
(rx/map flatten))
|
||||
|
||||
|
||||
imm-transform #(vector (- % 7) (+ % 7) %)
|
||||
immanted-zones (vec (concat
|
||||
(map imm-transform (range 0 181 15))
|
||||
(map (comp imm-transform -) (range 0 181 15))))
|
||||
|
||||
align-position (fn [angle pos]
|
||||
(reduce (fn [pos [a1 a2 v]]
|
||||
(if (< a1 angle a2)
|
||||
(reduced (gpt/update-angle pos v))
|
||||
pos))
|
||||
pos
|
||||
immanted-zones))]
|
||||
|
||||
(rx/merge
|
||||
(rx/of #(initialize-drawing % @last-point))
|
||||
|
||||
(->> points
|
||||
(rx/take-until stoper)
|
||||
(rx/map (fn [pt]
|
||||
#(insert-point-segment % pt))))
|
||||
(rx/concat
|
||||
(->> stream'
|
||||
(rx/map (fn [[point ctrl? index :as xxx]]
|
||||
(let [point (if ctrl?
|
||||
(as-> point $
|
||||
(gpt/subtract $ @last-point)
|
||||
(align-position (gpt/angle $) $)
|
||||
(gpt/add $ @last-point))
|
||||
point)]
|
||||
#(update-point-segment % index point))))
|
||||
(rx/take-until stoper))
|
||||
(rx/of remove-dangling-segmnet
|
||||
handle-finish-drawing))))))))
|
||||
|
||||
(defn- handle-drawing-free-path
|
||||
[shape]
|
||||
(letfn [(stoper-event? [{:keys [type shift] :as event}]
|
||||
(or (= event :interrupt)
|
||||
(and (uws/mouse-event? event) (= type :up))))
|
||||
|
||||
(initialize-drawing [state]
|
||||
(let [pid (get-in state [:workspace :current])]
|
||||
(assoc-in state [:workspace pid :drawing ::initialized?] true)))
|
||||
|
||||
(insert-point-segment [state point]
|
||||
(let [pid (get-in state [:workspace :current])]
|
||||
(update-in state [:workspace pid :drawing :segments] (fnil conj []) point)))
|
||||
|
||||
(simplify-drawing-path [state tolerance]
|
||||
(let [pid (get-in state [:workspace :current])]
|
||||
(update-in state [:workspace pid :drawing :segments] path/simplify tolerance)))]
|
||||
(reify
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [pid (get-in state [:workspace :current])
|
||||
zoom (get-in state [:workspace pid :zoom])
|
||||
flags (get-in state [:workspace pid :flags])
|
||||
align? (refs/alignment-activated? flags)
|
||||
|
||||
stoper (->> (rx/filter stoper-event? stream)
|
||||
(rx/take 1))
|
||||
|
||||
mouse (->> (rx/sample 10 uws/viewport-mouse-position)
|
||||
(rx/mapcat #(conditional-align % align?))
|
||||
(rx/map #(translate-to-canvas % zoom)))]
|
||||
(rx/concat
|
||||
(rx/of initialize-drawing)
|
||||
(->> mouse
|
||||
(rx/map (fn [pt] #(insert-point-segment % pt)))
|
||||
(rx/take-until stoper))
|
||||
(rx/of #(simplify-drawing-path % 0.3)
|
||||
handle-finish-drawing)))))))
|
||||
|
||||
(def handle-finish-drawing
|
||||
(reify
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [pid (get-in state [:workspace :current])
|
||||
shape (get-in state [:workspace pid :drawing])]
|
||||
(if (::initialized? shape)
|
||||
(let [resize-mtx (get-in state [:workspace pid :modifiers (:id shape) :resize])
|
||||
shape (cond-> shape
|
||||
resize-mtx (geom/transform resize-mtx))]
|
||||
(rx/of
|
||||
;; Remove the stalled modifiers
|
||||
;; TODO: maybe a specific event for "clear modifiers"
|
||||
#(update-in % [:workspace pid :modifiers] dissoc (:id shape))
|
||||
|
||||
;; Unselect the drawing tool
|
||||
#(update-in % [:workspace pid] dissoc :drawing :drawing-tool)
|
||||
|
||||
;; Add & select the cred shape to the workspace
|
||||
(ds/add-shape shape)
|
||||
(dw/select-first-shape)))
|
||||
(rx/of #(update-in % [:workspace pid] dissoc :drawing :drawing-tool)))))))
|
||||
|
||||
(def close-drawing-path
|
||||
(reify
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [pid (get-in state [:workspace :current])]
|
||||
(assoc-in state [:workspace pid :drawing :close?] true)))))
|
||||
|
||||
;; --- Components
|
||||
|
||||
(declare generic-draw-area)
|
||||
|
@ -47,12 +328,13 @@
|
|||
[{:keys [shape] :as props}]
|
||||
(letfn [(on-click [event]
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! (udw/set-tooltip nil)
|
||||
(udwd/close-drawing-path)))
|
||||
(st/emit! (dw/set-tooltip nil)
|
||||
close-drawing-path
|
||||
:interrupt))
|
||||
(on-mouse-enter [event]
|
||||
(st/emit! (udw/set-tooltip "Click to close the path")))
|
||||
(st/emit! (dw/set-tooltip "Click to close the path")))
|
||||
(on-mouse-leave [event]
|
||||
(st/emit! (udw/set-tooltip nil)))]
|
||||
(st/emit! (dw/set-tooltip nil)))]
|
||||
(when-let [{:keys [x y] :as segment} (first (:segments shape))]
|
||||
[:g
|
||||
(shapes/render-shape shape)
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
[rumext.core :as mx]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.main.data.images :as udi]
|
||||
[uxbox.main.data.workspace-drawing :as udwd]
|
||||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.ui.modal :as modal]
|
||||
[uxbox.util.data :refer [read-string jscoll->vec]]
|
||||
|
@ -54,7 +54,7 @@
|
|||
:metadata {:width width
|
||||
:height height}
|
||||
:image id}]
|
||||
(st/emit! (udwd/select-for-drawing shape))
|
||||
(st/emit! (dw/select-for-drawing shape))
|
||||
(modal/hide!)))
|
||||
|
||||
(on-files-selected [event]
|
||||
|
@ -99,7 +99,7 @@
|
|||
:metadata {:width (:width image)
|
||||
:height (:height image)}
|
||||
:image (:id image)}]
|
||||
(st/emit! (udwd/select-for-drawing shape))
|
||||
(st/emit! (dw/select-for-drawing shape))
|
||||
(modal/hide!)))]
|
||||
[:div.library-item {:on-click on-click}
|
||||
[:div.library-item-th
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
[uxbox.main.constants :as c]
|
||||
[uxbox.main.data.workspace :as udw]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.user-events :as uev]
|
||||
[uxbox.main.ui.workspace.streams :as ws]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.geom.point :as gpt]
|
||||
[uxbox.util.math :as mth]))
|
||||
|
@ -56,14 +56,14 @@
|
|||
[{:keys [ruler zoom] :as props}]
|
||||
(letfn [(on-mouse-down [event]
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! ::uev/interrupt
|
||||
(st/emit! :interrupt
|
||||
(udw/set-tooltip nil)
|
||||
(udw/start-ruler)))
|
||||
(on-mouse-up [event]
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! ::uev/interrupt))
|
||||
(st/emit! :interrupt))
|
||||
(on-unmount []
|
||||
(st/emit! ::uev/interrupt
|
||||
(st/emit! :interrupt
|
||||
(udw/clear-ruler)))]
|
||||
(mf/use-effect {:end on-unmount})
|
||||
[:svg {:on-mouse-down on-mouse-down
|
||||
|
|
|
@ -17,8 +17,7 @@
|
|||
[uxbox.main.geom :as geom]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.streams :as streams]
|
||||
[uxbox.main.user-events :as uev]
|
||||
[uxbox.main.ui.workspace.streams :as ws]
|
||||
[uxbox.main.workers :as uwrk]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.geom.point :as gpt]))
|
||||
|
@ -69,14 +68,14 @@
|
|||
|
||||
(let [shape (->> (geom/shape->rect-shape shape)
|
||||
(geom/size))
|
||||
stoper (->> streams/events
|
||||
(rx/filter uev/mouse-up?)
|
||||
stoper (->> ws/interaction-events
|
||||
(rx/filter ws/mouse-up?)
|
||||
(rx/take 1))
|
||||
stream (->> streams/canvas-mouse-position
|
||||
stream (->> ws/canvas-mouse-position
|
||||
(rx/take-until stoper)
|
||||
(rx/map apply-zoom)
|
||||
(rx/mapcat apply-grid-alignment)
|
||||
(rx/with-latest vector streams/mouse-position-ctrl)
|
||||
(rx/with-latest vector ws/mouse-position-ctrl)
|
||||
(rx/map normalize-proportion-lock))]
|
||||
(rx/subscribe stream (partial on-resize shape) nil on-end))))
|
||||
|
||||
|
@ -161,18 +160,18 @@
|
|||
(letfn [(on-mouse-down [event index]
|
||||
(dom/stop-propagation event)
|
||||
|
||||
(let [stoper (get-edition-stream-stoper streams/events)
|
||||
stream (rx/take-until stoper streams/mouse-position-deltas)]
|
||||
(let [stoper (get-edition-stream-stoper ws/interaction-events)
|
||||
stream (rx/take-until stoper ws/mouse-position-deltas)]
|
||||
(when @refs/selected-alignment
|
||||
(st/emit! (uds/initial-path-point-align (:id shape) index)))
|
||||
(rx/subscribe stream #(on-handler-move % index))))
|
||||
|
||||
(get-edition-stream-stoper [stream]
|
||||
(let [stoper? #(and (uev/mouse-event? %) (= (:type %) :up))]
|
||||
(let [stoper? #(and (ws/mouse-event? %) (= (:type %) :up))]
|
||||
(rx/merge
|
||||
(rx/filter stoper? stream)
|
||||
(->> stream
|
||||
(rx/filter #(= % ::uev/interrupt))
|
||||
(rx/filter #(= % :interrupt))
|
||||
(rx/take 1)))))
|
||||
|
||||
(on-handler-move [delta index]
|
||||
|
|
|
@ -10,9 +10,8 @@
|
|||
[beicon.core :as rx]
|
||||
[potok.core :as ptk]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.data.lightbox :as udl]
|
||||
[uxbox.main.data.workspace :as udw]
|
||||
[uxbox.main.data.workspace-drawing :as udwd]
|
||||
[uxbox.main.data.lightbox :as dl]
|
||||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.data.shapes :as uds]
|
||||
[uxbox.main.data.undo :as udu]
|
||||
[uxbox.main.data.history :as udh]
|
||||
|
@ -27,39 +26,39 @@
|
|||
;; --- Shortcuts
|
||||
|
||||
(defonce +shortcuts+
|
||||
{:shift+g #(st/emit! (udw/toggle-flag :grid))
|
||||
{:shift+g #(st/emit! (dw/toggle-flag :grid))
|
||||
:ctrl+g #(st/emit! (uds/group-selected))
|
||||
:ctrl+shift+g #(st/emit! (uds/ungroup-selected))
|
||||
:ctrl+shift+m #(st/emit! (udw/toggle-flag :sitemap))
|
||||
:ctrl+shift+f #(st/emit! (udw/toggle-flag :drawtools))
|
||||
:ctrl+shift+i #(st/emit! (udw/toggle-flag :icons))
|
||||
:ctrl+shift+l #(st/emit! (udw/toggle-flag :layers))
|
||||
:ctrl+0 #(st/emit! (udw/reset-zoom))
|
||||
:ctrl+r #(st/emit! (udw/toggle-flag :ruler))
|
||||
:ctrl+shift+m #(st/emit! (dw/toggle-flag :sitemap))
|
||||
:ctrl+shift+f #(st/emit! (dw/toggle-flag :drawtools))
|
||||
:ctrl+shift+i #(st/emit! (dw/toggle-flag :icons))
|
||||
:ctrl+shift+l #(st/emit! (dw/toggle-flag :layers))
|
||||
:ctrl+0 #(st/emit! (dw/reset-zoom))
|
||||
:ctrl+r #(st/emit! (dw/toggle-flag :ruler))
|
||||
:ctrl+d #(st/emit! (uds/duplicate-selected))
|
||||
:ctrl+c #(st/emit! (udw/copy-to-clipboard))
|
||||
:ctrl+v #(st/emit! (udw/paste-from-clipboard))
|
||||
:ctrl+shift+v #(udl/open! :clipboard)
|
||||
:ctrl+c #(st/emit! (dw/copy-to-clipboard))
|
||||
:ctrl+v #(st/emit! (dw/paste-from-clipboard))
|
||||
:ctrl+shift+v #(dl/open! :clipboard)
|
||||
:ctrl+z #(st/emit! (udu/undo))
|
||||
:ctrl+shift+z #(st/emit! (udu/redo))
|
||||
:ctrl+y #(st/emit! (udu/redo))
|
||||
:ctrl+b #(st/emit! (udwd/select-for-drawing wsd/+draw-tool-rect+))
|
||||
:ctrl+e #(st/emit! (udwd/select-for-drawing wsd/+draw-tool-circle+))
|
||||
:ctrl+t #(st/emit! (udwd/select-for-drawing wsd/+draw-tool-text+))
|
||||
:esc #(st/emit! (udw/deselect-all))
|
||||
:delete #(st/emit! (udw/delete-selected))
|
||||
:ctrl+up #(st/emit! (udw/move-selected-layer :up))
|
||||
:ctrl+down #(st/emit! (udw/move-selected-layer :down))
|
||||
:ctrl+shift+up #(st/emit! (udw/move-selected-layer :top))
|
||||
:ctrl+shift+down #(st/emit! (udw/move-selected-layer :bottom))
|
||||
:shift+up #(st/emit! (udw/move-selected :up :fast))
|
||||
:shift+down #(st/emit! (udw/move-selected :down :fast))
|
||||
:shift+right #(st/emit! (udw/move-selected :right :fast))
|
||||
:shift+left #(st/emit! (udw/move-selected :left :fast))
|
||||
:up #(st/emit! (udw/move-selected :up :std))
|
||||
:down #(st/emit! (udw/move-selected :down :std))
|
||||
:right #(st/emit! (udw/move-selected :right :std))
|
||||
:left #(st/emit! (udw/move-selected :left :std))
|
||||
:ctrl+b #(st/emit! (dw/select-for-drawing wsd/+draw-tool-rect+))
|
||||
:ctrl+e #(st/emit! (dw/select-for-drawing wsd/+draw-tool-circle+))
|
||||
:ctrl+t #(st/emit! (dw/select-for-drawing wsd/+draw-tool-text+))
|
||||
:esc #(st/emit! (dw/deselect-all))
|
||||
:delete #(st/emit! (dw/delete-selected))
|
||||
:ctrl+up #(st/emit! (dw/move-selected-layer :up))
|
||||
:ctrl+down #(st/emit! (dw/move-selected-layer :down))
|
||||
:ctrl+shift+up #(st/emit! (dw/move-selected-layer :top))
|
||||
:ctrl+shift+down #(st/emit! (dw/move-selected-layer :bottom))
|
||||
:shift+up #(st/emit! (dw/move-selected :up :fast))
|
||||
:shift+down #(st/emit! (dw/move-selected :down :fast))
|
||||
:shift+right #(st/emit! (dw/move-selected :right :fast))
|
||||
:shift+left #(st/emit! (dw/move-selected :left :fast))
|
||||
:up #(st/emit! (dw/move-selected :up :std))
|
||||
:down #(st/emit! (dw/move-selected :down :std))
|
||||
:right #(st/emit! (dw/move-selected :right :std))
|
||||
:left #(st/emit! (dw/move-selected :left :std))
|
||||
})
|
||||
|
||||
;; --- Shortcuts Setup Functions
|
||||
|
|
|
@ -9,13 +9,10 @@
|
|||
(:require
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.main.data.shapes :as uds]
|
||||
[uxbox.main.data.workspace :as udw]
|
||||
[uxbox.main.data.workspace-drawing :as udwd]
|
||||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.user-events :as uev]
|
||||
[uxbox.util.i18n :refer (tr)]
|
||||
[uxbox.util.i18n :refer [tr]]
|
||||
[uxbox.util.uuid :as uuid]))
|
||||
|
||||
;; --- Constants
|
||||
|
@ -81,17 +78,17 @@
|
|||
(mf/defc draw-toolbox
|
||||
{:wrap [mf/wrap-memo]}
|
||||
[{:keys [flags] :as props}]
|
||||
(let [close #(st/emit! (udw/toggle-flag :drawtools))
|
||||
(let [close #(st/emit! (dw/toggle-flag :drawtools))
|
||||
dtool (mf/deref refs/selected-drawing-tool)
|
||||
tools (->> (into [] +draw-tools+)
|
||||
(sort-by (comp :priority second)))
|
||||
|
||||
select-drawtool #(st/emit! ::uev/interrupt
|
||||
(udw/deactivate-ruler)
|
||||
(udwd/select-for-drawing %))
|
||||
toggle-ruler #(st/emit! (udwd/select-for-drawing nil)
|
||||
(uds/deselect-all)
|
||||
(udw/toggle-ruler))]
|
||||
select-drawtool #(st/emit! :interrupt
|
||||
(dw/deactivate-ruler)
|
||||
(dw/select-for-drawing %))
|
||||
toggle-ruler #(st/emit! (dw/select-for-drawing nil)
|
||||
(dw/deselect-all)
|
||||
(dw/toggle-ruler))]
|
||||
|
||||
[:div#form-tools.tool-window.drawing-tools
|
||||
[:div.tool-window-bar
|
||||
|
|
|
@ -6,20 +6,19 @@
|
|||
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
|
||||
|
||||
(ns uxbox.main.ui.workspace.sidebar.icons
|
||||
(:require [lentes.core :as l]
|
||||
[uxbox.util.router :as r]
|
||||
[potok.core :as ptk]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.lenses :as ul]
|
||||
[uxbox.main.data.workspace :as udw]
|
||||
[uxbox.main.data.workspace-drawing :as udwd]
|
||||
[uxbox.main.data.icons :as udi]
|
||||
[uxbox.main.ui.shapes.icon :as icon]
|
||||
[uxbox.main.ui.dashboard.icons :as icons]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[rumext.core :as mx :include-macros true]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.data :refer (read-string)]))
|
||||
(:require
|
||||
[lentes.core :as l]
|
||||
[rumext.core :as mx]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.main.data.icons :as udi]
|
||||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.lenses :as ul]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.ui.dashboard.icons :as icons]
|
||||
[uxbox.main.ui.shapes.icon :as icon]
|
||||
[uxbox.util.data :refer (read-string)]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.router :as r]))
|
||||
|
||||
;; --- Refs
|
||||
|
||||
|
@ -43,7 +42,7 @@
|
|||
|
||||
(defn- icons-toolbox-init
|
||||
[own]
|
||||
(st/emit! (udw/initialize-icons-toolbox))
|
||||
(st/emit! (dw/initialize-icons-toolbox))
|
||||
own)
|
||||
|
||||
(mx/defc icons-toolbox
|
||||
|
@ -60,13 +59,13 @@
|
|||
icons (->> (vals (mx/react icons/icons-ref))
|
||||
(filter #(= (:id selected-coll) (:collection %))))]
|
||||
(letfn [(on-close [event]
|
||||
(st/emit! (udw/toggle-flag :icons)))
|
||||
(st/emit! (dw/toggle-flag :icons)))
|
||||
(on-select [icon event]
|
||||
(st/emit! (udwd/select-for-drawing icon)))
|
||||
(st/emit! (dw/select-for-drawing icon)))
|
||||
(on-change [event]
|
||||
(let [value (read-string (dom/event->value event))]
|
||||
(st/emit! (udwd/select-for-drawing nil)
|
||||
(udw/select-icons-toolbox-collection value))))]
|
||||
(st/emit! (dw/select-for-drawing nil)
|
||||
(dw/select-icons-toolbox-collection value))))]
|
||||
[:div#form-figures.tool-window
|
||||
[:div.tool-window-bar
|
||||
[:div.tool-window-icon i/icon-set]
|
||||
|
|
128
frontend/src/uxbox/main/ui/workspace/streams.cljs
Normal file
128
frontend/src/uxbox/main/ui/workspace/streams.cljs
Normal file
|
@ -0,0 +1,128 @@
|
|||
;; 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) 2019 Andrey Antukh <niwi@niwi.nz>
|
||||
|
||||
(ns uxbox.main.ui.workspace.streams
|
||||
"User interaction events and streams."
|
||||
(:require
|
||||
[beicon.core :as rx]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.workers :as uwrk]
|
||||
[uxbox.util.geom.point :as gpt]))
|
||||
|
||||
;; --- User Events
|
||||
|
||||
(defrecord KeyboardEvent [type key shift ctrl])
|
||||
|
||||
(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))
|
||||
|
||||
(defrecord MouseEvent [type ctrl shift])
|
||||
|
||||
(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))))
|
||||
|
||||
(defn mouse-click?
|
||||
[v]
|
||||
(and (mouse-event? v)
|
||||
(= :click (:type v))))
|
||||
|
||||
(defrecord PointerEvent [window
|
||||
viewport
|
||||
canvas
|
||||
ctrl
|
||||
shift])
|
||||
|
||||
(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))
|
||||
|
||||
;; --- Derived streams
|
||||
|
||||
(defn interaction-event?
|
||||
[event]
|
||||
(or (keyboard-event? event)
|
||||
(mouse-event? event)))
|
||||
|
||||
;; TODO: this shoul be DEPRECATED
|
||||
(defonce interaction-events
|
||||
(rx/filter interaction-event? st/stream))
|
||||
|
||||
(defonce mouse-position
|
||||
(rx/filter pointer-event? st/stream))
|
||||
|
||||
(defonce canvas-mouse-position
|
||||
(let [sub (rx/behavior-subject nil)]
|
||||
(-> (rx/map :canvas mouse-position)
|
||||
(rx/subscribe-with sub))
|
||||
sub))
|
||||
|
||||
(defonce viewport-mouse-position
|
||||
(let [sub (rx/behavior-subject nil)]
|
||||
(-> (rx/map :viewport mouse-position)
|
||||
(rx/subscribe-with sub))
|
||||
sub))
|
||||
|
||||
(defonce window-mouse-position
|
||||
(let [sub (rx/behavior-subject nil)]
|
||||
(-> (rx/map :window mouse-position)
|
||||
(rx/subscribe-with sub))
|
||||
sub))
|
||||
|
||||
(defonce mouse-position-ctrl
|
||||
(let [sub (rx/behavior-subject nil)]
|
||||
(-> (rx/map :ctrl mouse-position)
|
||||
(rx/subscribe-with sub))
|
||||
sub))
|
||||
|
||||
(defonce mouse-position-deltas
|
||||
(->> viewport-mouse-position
|
||||
(rx/sample 10)
|
||||
(rx/map #(gpt/divide % @refs/selected-zoom))
|
||||
(rx/mapcat (fn [point]
|
||||
(if @refs/selected-alignment
|
||||
(uwrk/align-point point)
|
||||
(rx/of point))))
|
||||
(rx/buffer 2 1)
|
||||
(rx/map (fn [[old new]]
|
||||
(gpt/subtract new old)))
|
||||
(rx/share)))
|
|
@ -7,11 +7,12 @@
|
|||
|
||||
(ns uxbox.main.ui.workspace.viewport
|
||||
(:require
|
||||
[beicon.core :as rx]
|
||||
[goog.events :as events]
|
||||
[potok.core :as ptk]
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.main.constants :as c]
|
||||
[uxbox.main.data.workspace :as udw]
|
||||
[uxbox.main.data.workspace-drawing :as udwd]
|
||||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.geom :as geom]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.store :as st]
|
||||
|
@ -19,7 +20,8 @@
|
|||
[uxbox.main.ui.workspace.canvas :refer [canvas]]
|
||||
[uxbox.main.ui.workspace.grid :refer [grid]]
|
||||
[uxbox.main.ui.workspace.ruler :refer [ruler]]
|
||||
[uxbox.main.user-events :as uev]
|
||||
[uxbox.main.ui.workspace.streams :as uws]
|
||||
[uxbox.main.ui.workspace.drawarea :refer [start-drawing]]
|
||||
[uxbox.util.data :refer [parse-int]]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.geom.point :as gpt])
|
||||
|
@ -67,11 +69,53 @@
|
|||
|
||||
;; --- Selection Rect
|
||||
|
||||
(defn stop-selrect
|
||||
[]
|
||||
(letfn [(clear-state [state]
|
||||
(prn "clear-state")
|
||||
(let [id (get-in state [:workspace :current])]
|
||||
(update-in state [:workspace id] dissoc :selrect)))]
|
||||
(reify
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [id (get-in state [:workspace :current])
|
||||
zoom (get-in state [:workspace id :zoom])
|
||||
rect (some-> (get-in state [:workspace id :selrect])
|
||||
(dw/translate-to-canvas zoom))]
|
||||
(if rect
|
||||
(rx/of clear-state
|
||||
(dw/deselect-all)
|
||||
(dw/select-shapes-by-selrect rect))
|
||||
(rx/of (dw/deselect-all))))))))
|
||||
|
||||
(defn start-selrect
|
||||
[]
|
||||
(letfn [(update-state [state position]
|
||||
(let [id (get-in state [:workspace :current])
|
||||
selrect (get-in state [:workspace id :selrect])]
|
||||
(if selrect
|
||||
(assoc-in state [:workspace id :selrect] (dw/selection->rect (assoc selrect :stop position)))
|
||||
(assoc-in state [:workspace id :selrect] (dw/selection->rect {:start position :stop position})))))
|
||||
|
||||
(selection-stoper [stream]
|
||||
(->> (rx/merge (rx/filter #(= % :interrupt) stream)
|
||||
(rx/filter uws/mouse-up? stream))
|
||||
(rx/take 1)))]
|
||||
|
||||
(reify
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(rx/concat
|
||||
(->> uws/viewport-mouse-position
|
||||
(rx/take-until (selection-stoper stream))
|
||||
(rx/map (fn [pos] #(update-state % pos))))
|
||||
(rx/of (stop-selrect)))))))
|
||||
|
||||
(mf/defc selrect
|
||||
{:wrap [mf/wrap-memo]}
|
||||
[{rect :value}]
|
||||
(when rect
|
||||
(let [{:keys [x1 y1 width height]} (geom/size rect)]
|
||||
[{:keys [data] :as props}]
|
||||
(when data
|
||||
(let [{:keys [x1 y1 width height]} (geom/size data)]
|
||||
[:rect.selection-rect
|
||||
{:x x1
|
||||
:y y1
|
||||
|
@ -112,9 +156,9 @@
|
|||
opts {:key key
|
||||
:shift? shift?
|
||||
:ctrl? ctrl?}]
|
||||
(st/emit! (uev/keyboard-event :down key ctrl? shift?))
|
||||
(st/emit! (uws/keyboard-event :down key ctrl? shift?))
|
||||
(when (kbd/space? event)
|
||||
(st/emit! (udw/start-viewport-positioning)))))
|
||||
(st/emit! (dw/start-viewport-positioning)))))
|
||||
|
||||
(on-key-up [event]
|
||||
(let [key (.-keyCode event)
|
||||
|
@ -124,8 +168,8 @@
|
|||
:shift? shift?
|
||||
:ctrl? ctrl?}]
|
||||
(when (kbd/space? event)
|
||||
(st/emit! (udw/stop-viewport-positioning)))
|
||||
(st/emit! (uev/keyboard-event :up key ctrl? shift?))))
|
||||
(st/emit! (dw/stop-viewport-positioning)))
|
||||
(st/emit! (uws/keyboard-event :up key ctrl? shift?))))
|
||||
|
||||
(on-mousemove [event]
|
||||
(let [wpt (gpt/point (.-clientX event)
|
||||
|
@ -139,7 +183,7 @@
|
|||
:window-coords wpt
|
||||
:viewport-coords vpt
|
||||
:canvas-coords cpt}]
|
||||
(st/emit! (uev/pointer-event wpt vpt cpt ctrl? shift?))))]
|
||||
(st/emit! (uws/pointer-event wpt vpt cpt ctrl? shift?))))]
|
||||
|
||||
(let [key1 (events/listen js/document EventType.MOUSEMOVE on-mousemove)
|
||||
key2 (events/listen js/document EventType.KEYDOWN on-key-down)
|
||||
|
@ -169,11 +213,11 @@
|
|||
shift? (kbd/shift? event)
|
||||
opts {:shift? shift?
|
||||
:ctrl? ctrl?}]
|
||||
(st/emit! (uev/mouse-event :down ctrl? shift?)))
|
||||
(st/emit! (uws/mouse-event :down ctrl? shift?)))
|
||||
(when (not edition)
|
||||
(if drawing-tool
|
||||
(st/emit! (udwd/start-drawing drawing-tool))
|
||||
(st/emit! ::uev/interrupt (udw/start-selrect)))))
|
||||
(st/emit! (start-drawing drawing-tool))
|
||||
(st/emit! :interrupt (start-selrect)))))
|
||||
(on-context-menu [event]
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event)
|
||||
|
@ -181,28 +225,28 @@
|
|||
shift? (kbd/shift? event)
|
||||
opts {:shift? shift?
|
||||
:ctrl? ctrl?}]
|
||||
(st/emit! (uev/mouse-event :context-menu ctrl? shift?))))
|
||||
(st/emit! (uws/mouse-event :context-menu ctrl? shift?))))
|
||||
(on-mouse-up [event]
|
||||
(dom/stop-propagation event)
|
||||
(let [ctrl? (kbd/ctrl? event)
|
||||
shift? (kbd/shift? event)
|
||||
opts {:shift? shift?
|
||||
:ctrl? ctrl?}]
|
||||
(st/emit! (uev/mouse-event :up ctrl? shift?))))
|
||||
(st/emit! (uws/mouse-event :up ctrl? shift?))))
|
||||
(on-click [event]
|
||||
(dom/stop-propagation event)
|
||||
(let [ctrl? (kbd/ctrl? event)
|
||||
shift? (kbd/shift? event)
|
||||
opts {:shift? shift?
|
||||
:ctrl? ctrl?}]
|
||||
(st/emit! (uev/mouse-event :click ctrl? shift?))))
|
||||
(st/emit! (uws/mouse-event :click ctrl? shift?))))
|
||||
(on-double-click [event]
|
||||
(dom/stop-propagation event)
|
||||
(let [ctrl? (kbd/ctrl? event)
|
||||
shift? (kbd/shift? event)
|
||||
opts {:shift? shift?
|
||||
:ctrl? ctrl?}]
|
||||
(st/emit! (uev/mouse-event :double-click ctrl? shift?))))]
|
||||
(st/emit! (uws/mouse-event :double-click ctrl? shift?))))]
|
||||
[:*
|
||||
[:& coordinates {:zoom zoom}]
|
||||
[:div.tooltip-container
|
||||
|
@ -224,4 +268,4 @@
|
|||
[:& grid {:page page}])]
|
||||
(when (contains? flags :ruler)
|
||||
[:& ruler {:zoom zoom :ruler (:ruler wst)}])
|
||||
[:& selrect {:value (:selrect wst)}]]]))))
|
||||
[:& selrect {:data (:selrect wst)}]]]))))
|
||||
|
|
Loading…
Add table
Reference in a new issue