🐛 Fix edition mode of paths (and many perfomance improvements).

This commit is contained in:
Andrey Antukh 2019-08-09 10:43:02 +00:00
parent 775166f5f2
commit 2c321cbdb8
10 changed files with 117 additions and 139 deletions

View file

@ -468,26 +468,6 @@
(not (neg? index))]} (not (neg? index))]}
(InitialPathPointAlign. id index)) (InitialPathPointAlign. id index))
;; --- Start shape "edition mode"
(deftype StartEditionMode [id]
ptk/UpdateEvent
(update [_ state]
(assoc-in state [:workspace :edition] id))
ptk/WatchEvent
(watch [_ state stream]
;; Stop edition on interrupt event
(->> stream
(rx/filter #(= % ::uev/interrupt))
(rx/take 1)
(rx/map (fn [_] #(dissoc-in % [:workspace :edition]))))))
(defn start-edition-mode
[id]
{:pre [(uuid? id)]}
(StartEditionMode. id))
;; --- Events (implicit) (for selected) ;; --- Events (implicit) (for selected)
;; NOTE: moved to workspace ;; NOTE: moved to workspace

View file

@ -6,6 +6,7 @@
(ns uxbox.main.data.workspace (ns uxbox.main.data.workspace
(:require (:require
;; [uxbox.main.data.workspace.drawing :as wdrawing]
[beicon.core :as rx] [beicon.core :as rx]
[cljs.spec.alpha :as s] [cljs.spec.alpha :as s]
[potok.core :as ptk] [potok.core :as ptk]
@ -18,20 +19,20 @@
[uxbox.main.data.projects :as dp] [uxbox.main.data.projects :as dp]
[uxbox.main.data.shapes :as uds] [uxbox.main.data.shapes :as uds]
[uxbox.main.data.shapes-impl :as simpl] [uxbox.main.data.shapes-impl :as simpl]
;; [uxbox.main.data.workspace.drawing :as wdrawing]
[uxbox.main.data.workspace.ruler :as wruler] [uxbox.main.data.workspace.ruler :as wruler]
[uxbox.main.data.workspace.scroll :as wscroll] [uxbox.main.data.workspace.scroll :as wscroll]
[uxbox.main.geom :as geom]
[uxbox.main.lenses :as ul] [uxbox.main.lenses :as ul]
[uxbox.main.refs :as refs] [uxbox.main.refs :as refs]
[uxbox.main.store :as st] [uxbox.main.store :as st]
[uxbox.main.streams :as streams] [uxbox.main.streams :as streams]
[uxbox.main.user-events :as uev] [uxbox.main.user-events :as uev]
[uxbox.main.workers :as uwrk] [uxbox.main.workers :as uwrk]
[uxbox.util.data :refer [dissoc-in]]
[uxbox.util.data :refer [index-of]] [uxbox.util.data :refer [index-of]]
[uxbox.util.forms :as sc] [uxbox.util.forms :as sc]
[uxbox.main.geom :as geom]
[uxbox.util.geom.point :as gpt]
[uxbox.util.geom.matrix :as gmt] [uxbox.util.geom.matrix :as gmt]
[uxbox.util.geom.point :as gpt]
[uxbox.util.math :as mth] [uxbox.util.math :as mth]
[uxbox.util.spec :as us] [uxbox.util.spec :as us]
[uxbox.util.time :as dt] [uxbox.util.time :as dt]
@ -656,6 +657,26 @@
[] []
(StartMoveSelected.)) (StartMoveSelected.))
;; --- Start shape "edition mode"
(defn start-edition-mode
[id]
{:pre [(uuid? id)]}
(reify
ptk/UpdateEvent
(update [_ state]
(let [pid (get-in state [:workspace :current])]
(assoc-in state [:workspace pid :edition] id)))
ptk/WatchEvent
(watch [_ state stream]
(let [pid (get-in state [:workspace :current])]
(->> stream
(rx/filter #(= % ::uev/interrupt))
(rx/take 1)
(rx/map (fn [_] #(dissoc-in % [:workspace pid :edition]))))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Selection Rect Events ;; Selection Rect Events
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View file

@ -8,15 +8,13 @@
(:require (:require
[cuerdas.core :as str :include-macros true] [cuerdas.core :as str :include-macros true]
[rumext.alpha :as mf] [rumext.alpha :as mf]
[uxbox.main.data.shapes :as uds] [uxbox.main.data.workspace :as udw]
[uxbox.main.geom :as geom] [uxbox.main.geom :as geom]
[uxbox.main.refs :as refs] [uxbox.main.refs :as refs]
[uxbox.main.store :as st] [uxbox.main.store :as st]
[uxbox.main.ui.shapes.attrs :as attrs] [uxbox.main.ui.shapes.attrs :as attrs]
[uxbox.main.ui.shapes.common :as common] [uxbox.main.ui.shapes.common :as common]
[uxbox.util.data :refer [classnames normalize-props]] [uxbox.util.data :refer [classnames normalize-props]]))
[uxbox.util.geom.matrix :as gmt]
[uxbox.util.geom.point :as gpt]))
;; --- Path Component ;; --- Path Component
@ -31,7 +29,8 @@
(common/on-mouse-down event shape selected)) (common/on-mouse-down event shape selected))
(on-double-click [event] (on-double-click [event]
(when selected? (when selected?
(st/emit! (uds/start-edition-mode (:id shape)))))] (prn "on-double-click")
(st/emit! (udw/start-edition-mode (:id shape)))))]
[:g.shape {:class (when selected? "selected") [:g.shape {:class (when selected? "selected")
:on-double-click on-double-click :on-double-click on-double-click
:on-mouse-down on-mouse-down} :on-mouse-down on-mouse-down}

View file

@ -12,6 +12,7 @@
[rumext.core :as mx] [rumext.core :as mx]
[rumext.alpha :as mf] [rumext.alpha :as mf]
[uxbox.main.data.shapes :as uds] [uxbox.main.data.shapes :as uds]
[uxbox.main.data.workspace :as udw]
[uxbox.main.geom :as geom] [uxbox.main.geom :as geom]
[uxbox.main.refs :as refs] [uxbox.main.refs :as refs]
[uxbox.main.store :as st] [uxbox.main.store :as st]
@ -55,7 +56,7 @@
;; TODO: handle grouping event propagation ;; TODO: handle grouping event propagation
;; TODO: handle actions locking properly ;; TODO: handle actions locking properly
(dom/stop-propagation event) (dom/stop-propagation event)
(st/emit! (uds/start-edition-mode id)))] (st/emit! (udw/start-edition-mode id)))]
[:g.shape {:class (when selected? "selected") [:g.shape {:class (when selected? "selected")
:on-double-click on-double-click :on-double-click on-double-click
:on-mouse-down on-mouse-down} :on-mouse-down on-mouse-down}

View file

@ -123,7 +123,9 @@
;; Aside ;; Aside
(when left-sidebar? (when left-sidebar?
[:& left-sidebar {:wst wst :page page}]) [:& left-sidebar {:page page
:selected (:selected wst)
:flags (:flags wst)}])
(when right-sidebar? (when right-sidebar?
[:& right-sidebar {:wst wst :page page}])]])) [:& right-sidebar {:wst wst :page page}])]]))

View file

@ -32,6 +32,7 @@
(mf/defc canvas (mf/defc canvas
[{:keys [page wst] :as props}] [{:keys [page wst] :as props}]
(prn "canvas")
(let [{:keys [metadata id]} page (let [{:keys [metadata id]} page
zoom (:zoom wst 1) ;; NOTE: maybe forward wst to draw-area zoom (:zoom wst 1) ;; NOTE: maybe forward wst to draw-area
width (:width metadata) width (:width metadata)
@ -45,7 +46,8 @@
[:g.main [:g.main
(for [id (reverse (:shapes page))] (for [id (reverse (:shapes page))]
[:& uus/shape-component {:id id :key id}]) [:& uus/shape-component {:id id :key id}])
[:& selection-handlers {:wst wst}] (when (seq (:selected wst))
[:& selection-handlers {:wst wst}])
(when-let [dshape (:drawing wst)] (when-let [dshape (:drawing wst)]
[:& draw-area {:shape dshape [:& draw-area {:shape dshape
:zoom (:zoom wst) :zoom (:zoom wst)

View file

@ -2,17 +2,15 @@
;; License, v. 2.0. If a copy of the MPL was not distributed with this ;; 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/. ;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;; ;;
;; Copyright (c) 2015-2017 Andrey Antukh <niwi@niwi.nz>
;; Copyright (c) 2015-2017 Juan de la Cruz <delacruzgarciajuan@gmail.com> ;; Copyright (c) 2015-2017 Juan de la Cruz <delacruzgarciajuan@gmail.com>
;; Copyright (c) 2015-2019 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.main.ui.workspace.selection (ns uxbox.main.ui.workspace.selection
"Multiple selection handlers component." "Selection handlers component."
(:require (:require
[beicon.core :as rx] [beicon.core :as rx]
[lentes.core :as l] [lentes.core :as l]
[potok.core :as ptk]
[rumext.alpha :as mf] [rumext.alpha :as mf]
[rumext.core :as mx]
[uxbox.main.constants :as c] [uxbox.main.constants :as c]
[uxbox.main.data.shapes :as uds] [uxbox.main.data.shapes :as uds]
[uxbox.main.data.workspace :as udw] [uxbox.main.data.workspace :as udw]
@ -23,7 +21,6 @@
[uxbox.main.user-events :as uev] [uxbox.main.user-events :as uev]
[uxbox.main.workers :as uwrk] [uxbox.main.workers :as uwrk]
[uxbox.util.dom :as dom] [uxbox.util.dom :as dom]
[uxbox.util.geom.matrix :as gmt]
[uxbox.util.geom.point :as gpt])) [uxbox.util.geom.point :as gpt]))
;; --- Refs & Constants ;; --- Refs & Constants
@ -36,35 +33,10 @@
:fill "#31e6e0" :fill "#31e6e0"
:stroke "#28c4d4"}) :stroke "#28c4d4"})
(defn- focus-selected-shapes
[state]
(let [selected (get-in state [:workspace :selected])]
(mapv #(get-in state [:shapes %]) selected)))
(def ^:private selected-shapes-ref
"A customized version of `refs/selected-shapes` that
additionally resolves the shapes to the real object
instead of just return a set of ids."
(-> (l/lens focus-selected-shapes)
(l/derive st/state)))
(def ^:private selected-modifers-ref
"A customized version of `refs/selected-modifiers`
that instead of focus to one concrete id, it focuses
on the whole map."
(-> (l/key :modifiers)
(l/derive refs/workspace)))
;; --- Resize Implementation ;; --- Resize Implementation
;; TODO: this function need to be refactored ;; TODO: this function need to be refactored
;; (defrecord StartResizeSelected [vid ids shape]
;; ptk/WatchEvent
;; (watch [_ state stream]
;; (let [pid (get-in state [:workspace :current])
;; wst (get-in state [:workspace pid])
(defn- start-resize (defn- start-resize
[vid ids shape] [vid ids shape]
(letfn [(on-resize [shape [point lock?]] (letfn [(on-resize [shape [point lock?]]
@ -184,46 +156,40 @@
;; --- Selection Handlers (Component) ;; --- Selection Handlers (Component)
;; (defn get-path-edition-stoper (mf/defc path-edition-selection-handlers
;; [stream] [{:keys [shape modifiers zoom] :as props}]
;; (letfn [(stoper-event? [{:keys [type shift] :as event}] (letfn [(on-mouse-down [event index]
;; (and (uev/mouse-event? event) (= type :up)))] (dom/stop-propagation event)
;; (rx/merge
;; (rx/filter stoper-event? stream)
;; (->> stream
;; (rx/filter #(= % ::uev/interrupt))
;; (rx/take 1)))))
;; (defn start-path-edition (let [stoper (get-edition-stream-stoper streams/events)
;; [shape-id index] stream (rx/take-until stoper streams/mouse-position-deltas)]
;; (letfn [(on-move [delta] (when @refs/selected-alignment
;; (st/emit! (uds/update-path shape-id index delta)))] (st/emit! (uds/initial-path-point-align (:id shape) index)))
;; (let [stoper (get-path-edition-stoper streams/events) (rx/subscribe stream #(on-handler-move % index))))
;; stream (rx/take-until stoper streams/mouse-position-deltas)]
;; (when @refs/selected-alignment
;; (st/emit! (uds/initial-path-point-align shape-id index)))
;; (rx/subscribe stream on-move))))
;; (mx/defc path-edition-selection-handlers (get-edition-stream-stoper [stream]
;; [{:keys [id segments modifiers] :as shape} zoom] (let [stoper? #(and (uev/mouse-event? %) (= (:type %) :up))]
;; (letfn [(on-click [index event] (rx/merge
;; (dom/stop-propagation event) (rx/filter stoper? stream)
;; (start-path-edition id index))] (->> stream
(rx/filter #(= % ::uev/interrupt))
(rx/take 1)))))
;; (let [{:keys [displacement]} modifiers (on-handler-move [delta index]
;; segments (if displacement (st/emit! (uds/update-path (:id shape) index delta)))]
;; (map #(gpt/transform % displacement) segments)
;; segments)]
;; [:g.controls (let [displacement (:displacement modifiers)
;; (for [[index {:keys [x y]}] (map-indexed vector segments)] segments (cond->> (:segments shape)
;; [:circle {:cx x :cy y displacement (map #(gpt/transform % displacement)))]
;; :r (/ 6.0 zoom) [:g.controls
;; :key index (for [[index {:keys [x y]}] (map-indexed vector segments)]
;; :on-click (partial on-click index) [:circle {:cx x :cy y
;; :fill "#31e6e0" :r (/ 6.0 zoom)
;; :stroke "#28c4d4" :key index
;; :style {:cursor "pointer"}}])]))) :on-mouse-down #(on-mouse-down % index)
:fill "#31e6e0"
:stroke "#28c4d4"
:style {:cursor "pointer"}}])])))
(mf/defc multiple-selection-handlers (mf/defc multiple-selection-handlers
[{:keys [shapes modifiers zoom] :as props}] [{:keys [shapes modifiers zoom] :as props}]
@ -239,10 +205,11 @@
:on-click on-click}])) :on-click on-click}]))
(mf/defc single-selection-handlers (mf/defc single-selection-handlers
[{:keys [shape zoom] :as props}] [{:keys [shape zoom modifiers] :as props}]
(let [on-click #(do (dom/stop-propagation %2) (let [on-click #(do (dom/stop-propagation %2)
(start-resize %1 #{(:id shape)} shape)) (start-resize %1 #{(:id shape)} shape))
shape (geom/selection-rect shape)] shape (-> (assoc shape :modifiers modifiers)
(geom/selection-rect))]
[:& controls {:shape shape :zoom zoom :on-click on-click}])) [:& controls {:shape shape :zoom zoom :on-click on-click}]))
;; (mx/defc text-edition-selection-handlers ;; (mx/defc text-edition-selection-handlers
@ -259,19 +226,21 @@
;; :stroke-opacity "0.5" ;; :stroke-opacity "0.5"
;; :fill "transparent"}}]])) ;; :fill "transparent"}}]]))
(defn- focus-shapes (def ^:private shapes-map-iref
[selected] (-> (l/key :shapes)
(mapv #(get-in @st/state [:shapes %]) selected)) (l/derive st/state)))
(mf/defc selection-handlers (mf/defc selection-handlers
[{:keys [wst] :as props}] [{:keys [wst] :as props}]
(let [shapes (focus-shapes (:selected wst)) (let [shapes-map (mf/deref shapes-map-iref)
shapes (map #(get shapes-map %) (:selected wst))
edition? (:edition wst) edition? (:edition wst)
modifiers (:modifiers wst) modifiers (:modifiers wst)
zoom (:zoom wst 1) zoom (:zoom wst 1)
num (count shapes) num (count shapes)
{:keys [id type] :as shape} (first shapes)] {:keys [id type] :as shape} (first shapes)]
(cond (cond
(zero? num) (zero? num)
nil nil
@ -285,14 +254,13 @@
;; (-> (assoc shape :modifiers (get modifiers id)) ;; (-> (assoc shape :modifiers (get modifiers id))
;; (text-edition-selection-handlers zoom)) ;; (text-edition-selection-handlers zoom))
;; (= type :path) (and (= type :path)
;; (if (= edition? (:id shape)) (= edition? (:id shape)))
;; (-> (assoc shape :modifiers (get modifiers id)) [:& path-edition-selection-handlers {:shape shape
;; (path-edition-selection-handlers zoom)) :zoom zoom
;; (-> (assoc shape :modifiers (get modifiers id)) :modifiers (get modifiers id)}]
;; (single-selection-handlers zoom)))
:else :else
[:& single-selection-handlers [:& single-selection-handlers {:shape shape
{:shape (assoc shape :modifiers (get modifiers id)) :modifiers (get modifiers id)
:zoom zoom}]))) :zoom zoom}])))

View file

@ -19,20 +19,20 @@
;; --- Left Sidebar (Component) ;; --- Left Sidebar (Component)
(mf/defc left-sidebar (mf/defc left-sidebar
[{:keys [wst page] :as props}] {:wrap [mf/wrap-memo]}
(let [{:keys [flags selected]} wst] [{:keys [flags selected page] :as props}]
[:aside#settings-bar.settings-bar.settings-bar-left [:aside#settings-bar.settings-bar.settings-bar-left
[:> rdnd/provider {:backend rdnd/html5} [:> rdnd/provider {:backend rdnd/html5}
[:div.settings-bar-inside [:div.settings-bar-inside
(when (contains? flags :sitemap) (when (contains? flags :sitemap)
[:& sitemap-toolbox {:project-id (:project page) [:& sitemap-toolbox {:project-id (:project page)
:current-page-id (:id page) :current-page-id (:id page)
:page page}]) :page page}])
#_(when (contains? flags :document-history) #_(when (contains? flags :document-history)
(history-toolbox page-id)) (history-toolbox page-id))
(when (contains? flags :layers) (when (contains? flags :layers)
[:& layers-toolbox {:page page [:& layers-toolbox {:page page
:selected selected}])]]])) :selected selected}])]]])
;; --- Right Sidebar (Component) ;; --- Right Sidebar (Component)

View file

@ -73,16 +73,17 @@
(defn- make-pages-iref (defn- make-pages-iref
[{:keys [id pages] :as project}] [{:keys [id pages] :as project}]
(letfn [(selector [state] (-> (l/lens (fn [s] (into [] (map #(get-in s [:pages %])) pages)))
(into [] (map #(get-in state [:pages %])) pages))] (l/derive st/state {:equals? =})))
(-> (l/lens selector)
(l/derive st/state)))) (def ^:private pages-map-iref
(-> (l/key :pages)
(l/derive st/state)))
(mf/defc pages-list (mf/defc pages-list
[{:keys [project current-page-id] :as props}] [{:keys [project current-page-id] :as props}]
(let [pages-iref (mf/use-memo {:deps #js [project] (let [pages-map (mf/deref pages-map-iref)
:init #(make-pages-iref project)}) pages (map #(get pages-map %) (:pages project))
pages (mf/deref pages-iref)
deletable? (> (count pages) 1)] deletable? (> (count pages) 1)]
[:ul.element-list [:ul.element-list
(for [[index item] (map-indexed vector pages)] (for [[index item] (map-indexed vector pages)]

View file

@ -158,19 +158,21 @@
:render :render
(fn [own {:keys [page wst] :as props}] (fn [own {:keys [page wst] :as props}]
(let [{:keys [drawing-tool tooltip zoom flags]} wst (let [{:keys [drawing-tool tooltip zoom flags edition]} wst
tooltip (or tooltip (get-shape-tooltip drawing-tool)) tooltip (or tooltip (get-shape-tooltip drawing-tool))
zoom (or zoom 1)] zoom (or zoom 1)]
(letfn [(on-mouse-down [event] (letfn [(on-mouse-down [event]
(prn "viewport.on-mouse-down")
(dom/stop-propagation event) (dom/stop-propagation event)
(let [ctrl? (kbd/ctrl? event) (let [ctrl? (kbd/ctrl? event)
shift? (kbd/shift? event) shift? (kbd/shift? event)
opts {:shift? shift? opts {:shift? shift?
:ctrl? ctrl?}] :ctrl? ctrl?}]
(st/emit! (uev/mouse-event :down ctrl? shift?))) (st/emit! (uev/mouse-event :down ctrl? shift?)))
(if drawing-tool (when (not edition)
(st/emit! (udwd/start-drawing drawing-tool)) (if drawing-tool
(st/emit! ::uev/interrupt (udw/start-selrect)))) (st/emit! (udwd/start-drawing drawing-tool))
(st/emit! ::uev/interrupt (udw/start-selrect)))))
(on-context-menu [event] (on-context-menu [event]
(dom/prevent-default event) (dom/prevent-default event)
(dom/stop-propagation event) (dom/stop-propagation event)
@ -187,6 +189,7 @@
:ctrl? ctrl?}] :ctrl? ctrl?}]
(st/emit! (uev/mouse-event :up ctrl? shift?)))) (st/emit! (uev/mouse-event :up ctrl? shift?))))
(on-click [event] (on-click [event]
(js/console.log "viewport.on-click" event)
(dom/stop-propagation event) (dom/stop-propagation event)
(let [ctrl? (kbd/ctrl? event) (let [ctrl? (kbd/ctrl? event)
shift? (kbd/shift? event) shift? (kbd/shift? event)
@ -213,7 +216,8 @@
:on-click on-click :on-click on-click
:on-double-click on-double-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 ")")}
(when page (when page
[:& canvas {:page page :wst wst}]) [:& canvas {:page page :wst wst}])