mirror of
https://github.com/penpot/penpot.git
synced 2025-04-05 03:21:26 -05:00
🐛 Fix edition mode of paths (and many perfomance improvements).
This commit is contained in:
parent
775166f5f2
commit
2c321cbdb8
10 changed files with 117 additions and 139 deletions
|
@ -468,26 +468,6 @@
|
|||
(not (neg? 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)
|
||||
|
||||
;; NOTE: moved to workspace
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
(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]
|
||||
|
@ -18,20 +19,20 @@
|
|||
[uxbox.main.data.projects :as dp]
|
||||
[uxbox.main.data.shapes :as uds]
|
||||
[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.scroll :as wscroll]
|
||||
[uxbox.main.geom :as geom]
|
||||
[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]]
|
||||
[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.point :as gpt]
|
||||
[uxbox.util.math :as mth]
|
||||
[uxbox.util.spec :as us]
|
||||
[uxbox.util.time :as dt]
|
||||
|
@ -656,6 +657,26 @@
|
|||
[]
|
||||
(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
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
|
|
@ -8,15 +8,13 @@
|
|||
(:require
|
||||
[cuerdas.core :as str :include-macros true]
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.main.data.shapes :as uds]
|
||||
[uxbox.main.data.workspace :as udw]
|
||||
[uxbox.main.geom :as geom]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.ui.shapes.attrs :as attrs]
|
||||
[uxbox.main.ui.shapes.common :as common]
|
||||
[uxbox.util.data :refer [classnames normalize-props]]
|
||||
[uxbox.util.geom.matrix :as gmt]
|
||||
[uxbox.util.geom.point :as gpt]))
|
||||
[uxbox.util.data :refer [classnames normalize-props]]))
|
||||
|
||||
;; --- Path Component
|
||||
|
||||
|
@ -31,7 +29,8 @@
|
|||
(common/on-mouse-down event shape selected))
|
||||
(on-double-click [event]
|
||||
(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")
|
||||
:on-double-click on-double-click
|
||||
:on-mouse-down on-mouse-down}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
[rumext.core :as mx]
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.main.data.shapes :as uds]
|
||||
[uxbox.main.data.workspace :as udw]
|
||||
[uxbox.main.geom :as geom]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.store :as st]
|
||||
|
@ -55,7 +56,7 @@
|
|||
;; TODO: handle grouping event propagation
|
||||
;; TODO: handle actions locking properly
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! (uds/start-edition-mode id)))]
|
||||
(st/emit! (udw/start-edition-mode id)))]
|
||||
[:g.shape {:class (when selected? "selected")
|
||||
:on-double-click on-double-click
|
||||
:on-mouse-down on-mouse-down}
|
||||
|
|
|
@ -123,7 +123,9 @@
|
|||
|
||||
;; Aside
|
||||
(when left-sidebar?
|
||||
[:& left-sidebar {:wst wst :page page}])
|
||||
[:& left-sidebar {:page page
|
||||
:selected (:selected wst)
|
||||
:flags (:flags wst)}])
|
||||
(when right-sidebar?
|
||||
[:& right-sidebar {:wst wst :page page}])]]))
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
(mf/defc canvas
|
||||
[{:keys [page wst] :as props}]
|
||||
(prn "canvas")
|
||||
(let [{:keys [metadata id]} page
|
||||
zoom (:zoom wst 1) ;; NOTE: maybe forward wst to draw-area
|
||||
width (:width metadata)
|
||||
|
@ -45,7 +46,8 @@
|
|||
[:g.main
|
||||
(for [id (reverse (:shapes page))]
|
||||
[:& uus/shape-component {:id id :key id}])
|
||||
[:& selection-handlers {:wst wst}]
|
||||
(when (seq (:selected wst))
|
||||
[:& selection-handlers {:wst wst}])
|
||||
(when-let [dshape (:drawing wst)]
|
||||
[:& draw-area {:shape dshape
|
||||
:zoom (:zoom wst)
|
||||
|
|
|
@ -2,17 +2,15 @@
|
|||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
;;
|
||||
;; Copyright (c) 2015-2017 Andrey Antukh <niwi@niwi.nz>
|
||||
;; 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
|
||||
"Multiple selection handlers component."
|
||||
"Selection handlers component."
|
||||
(:require
|
||||
[beicon.core :as rx]
|
||||
[lentes.core :as l]
|
||||
[potok.core :as ptk]
|
||||
[rumext.alpha :as mf]
|
||||
[rumext.core :as mx]
|
||||
[uxbox.main.constants :as c]
|
||||
[uxbox.main.data.shapes :as uds]
|
||||
[uxbox.main.data.workspace :as udw]
|
||||
|
@ -23,7 +21,6 @@
|
|||
[uxbox.main.user-events :as uev]
|
||||
[uxbox.main.workers :as uwrk]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.geom.matrix :as gmt]
|
||||
[uxbox.util.geom.point :as gpt]))
|
||||
|
||||
;; --- Refs & Constants
|
||||
|
@ -36,35 +33,10 @@
|
|||
:fill "#31e6e0"
|
||||
: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
|
||||
|
||||
;; 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
|
||||
[vid ids shape]
|
||||
(letfn [(on-resize [shape [point lock?]]
|
||||
|
@ -184,46 +156,40 @@
|
|||
|
||||
;; --- Selection Handlers (Component)
|
||||
|
||||
;; (defn get-path-edition-stoper
|
||||
;; [stream]
|
||||
;; (letfn [(stoper-event? [{:keys [type shift] :as event}]
|
||||
;; (and (uev/mouse-event? event) (= type :up)))]
|
||||
;; (rx/merge
|
||||
;; (rx/filter stoper-event? stream)
|
||||
;; (->> stream
|
||||
;; (rx/filter #(= % ::uev/interrupt))
|
||||
;; (rx/take 1)))))
|
||||
(mf/defc path-edition-selection-handlers
|
||||
[{:keys [shape modifiers zoom] :as props}]
|
||||
(letfn [(on-mouse-down [event index]
|
||||
(dom/stop-propagation event)
|
||||
|
||||
;; (defn start-path-edition
|
||||
;; [shape-id index]
|
||||
;; (letfn [(on-move [delta]
|
||||
;; (st/emit! (uds/update-path shape-id index delta)))]
|
||||
;; (let [stoper (get-path-edition-stoper streams/events)
|
||||
;; 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))))
|
||||
(let [stoper (get-edition-stream-stoper streams/events)
|
||||
stream (rx/take-until stoper streams/mouse-position-deltas)]
|
||||
(when @refs/selected-alignment
|
||||
(st/emit! (uds/initial-path-point-align (:id shape) index)))
|
||||
(rx/subscribe stream #(on-handler-move % index))))
|
||||
|
||||
;; (mx/defc path-edition-selection-handlers
|
||||
;; [{:keys [id segments modifiers] :as shape} zoom]
|
||||
;; (letfn [(on-click [index event]
|
||||
;; (dom/stop-propagation event)
|
||||
;; (start-path-edition id index))]
|
||||
(get-edition-stream-stoper [stream]
|
||||
(let [stoper? #(and (uev/mouse-event? %) (= (:type %) :up))]
|
||||
(rx/merge
|
||||
(rx/filter stoper? stream)
|
||||
(->> stream
|
||||
(rx/filter #(= % ::uev/interrupt))
|
||||
(rx/take 1)))))
|
||||
|
||||
;; (let [{:keys [displacement]} modifiers
|
||||
;; segments (if displacement
|
||||
;; (map #(gpt/transform % displacement) segments)
|
||||
;; segments)]
|
||||
(on-handler-move [delta index]
|
||||
(st/emit! (uds/update-path (:id shape) index delta)))]
|
||||
|
||||
;; [:g.controls
|
||||
;; (for [[index {:keys [x y]}] (map-indexed vector segments)]
|
||||
;; [:circle {:cx x :cy y
|
||||
;; :r (/ 6.0 zoom)
|
||||
;; :key index
|
||||
;; :on-click (partial on-click index)
|
||||
;; :fill "#31e6e0"
|
||||
;; :stroke "#28c4d4"
|
||||
;; :style {:cursor "pointer"}}])])))
|
||||
(let [displacement (:displacement modifiers)
|
||||
segments (cond->> (:segments shape)
|
||||
displacement (map #(gpt/transform % displacement)))]
|
||||
[:g.controls
|
||||
(for [[index {:keys [x y]}] (map-indexed vector segments)]
|
||||
[:circle {:cx x :cy y
|
||||
:r (/ 6.0 zoom)
|
||||
:key index
|
||||
:on-mouse-down #(on-mouse-down % index)
|
||||
:fill "#31e6e0"
|
||||
:stroke "#28c4d4"
|
||||
:style {:cursor "pointer"}}])])))
|
||||
|
||||
(mf/defc multiple-selection-handlers
|
||||
[{:keys [shapes modifiers zoom] :as props}]
|
||||
|
@ -239,10 +205,11 @@
|
|||
:on-click on-click}]))
|
||||
|
||||
(mf/defc single-selection-handlers
|
||||
[{:keys [shape zoom] :as props}]
|
||||
[{:keys [shape zoom modifiers] :as props}]
|
||||
(let [on-click #(do (dom/stop-propagation %2)
|
||||
(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}]))
|
||||
|
||||
;; (mx/defc text-edition-selection-handlers
|
||||
|
@ -259,19 +226,21 @@
|
|||
;; :stroke-opacity "0.5"
|
||||
;; :fill "transparent"}}]]))
|
||||
|
||||
(defn- focus-shapes
|
||||
[selected]
|
||||
(mapv #(get-in @st/state [:shapes %]) selected))
|
||||
(def ^:private shapes-map-iref
|
||||
(-> (l/key :shapes)
|
||||
(l/derive st/state)))
|
||||
|
||||
(mf/defc selection-handlers
|
||||
[{: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)
|
||||
modifiers (:modifiers wst)
|
||||
zoom (:zoom wst 1)
|
||||
num (count shapes)
|
||||
{:keys [id type] :as shape} (first shapes)]
|
||||
|
||||
|
||||
(cond
|
||||
(zero? num)
|
||||
nil
|
||||
|
@ -285,14 +254,13 @@
|
|||
;; (-> (assoc shape :modifiers (get modifiers id))
|
||||
;; (text-edition-selection-handlers zoom))
|
||||
|
||||
;; (= type :path)
|
||||
;; (if (= edition? (:id shape))
|
||||
;; (-> (assoc shape :modifiers (get modifiers id))
|
||||
;; (path-edition-selection-handlers zoom))
|
||||
;; (-> (assoc shape :modifiers (get modifiers id))
|
||||
;; (single-selection-handlers zoom)))
|
||||
(and (= type :path)
|
||||
(= edition? (:id shape)))
|
||||
[:& path-edition-selection-handlers {:shape shape
|
||||
:zoom zoom
|
||||
:modifiers (get modifiers id)}]
|
||||
|
||||
:else
|
||||
[:& single-selection-handlers
|
||||
{:shape (assoc shape :modifiers (get modifiers id))
|
||||
:zoom zoom}])))
|
||||
[:& single-selection-handlers {:shape shape
|
||||
:modifiers (get modifiers id)
|
||||
:zoom zoom}])))
|
||||
|
|
|
@ -19,20 +19,20 @@
|
|||
;; --- Left Sidebar (Component)
|
||||
|
||||
(mf/defc left-sidebar
|
||||
[{:keys [wst page] :as props}]
|
||||
(let [{:keys [flags selected]} wst]
|
||||
[:aside#settings-bar.settings-bar.settings-bar-left
|
||||
[:> rdnd/provider {:backend rdnd/html5}
|
||||
[:div.settings-bar-inside
|
||||
(when (contains? flags :sitemap)
|
||||
[:& sitemap-toolbox {:project-id (:project page)
|
||||
:current-page-id (:id page)
|
||||
:page page}])
|
||||
#_(when (contains? flags :document-history)
|
||||
(history-toolbox page-id))
|
||||
(when (contains? flags :layers)
|
||||
[:& layers-toolbox {:page page
|
||||
:selected selected}])]]]))
|
||||
{:wrap [mf/wrap-memo]}
|
||||
[{:keys [flags selected page] :as props}]
|
||||
[:aside#settings-bar.settings-bar.settings-bar-left
|
||||
[:> rdnd/provider {:backend rdnd/html5}
|
||||
[:div.settings-bar-inside
|
||||
(when (contains? flags :sitemap)
|
||||
[:& sitemap-toolbox {:project-id (:project page)
|
||||
:current-page-id (:id page)
|
||||
:page page}])
|
||||
#_(when (contains? flags :document-history)
|
||||
(history-toolbox page-id))
|
||||
(when (contains? flags :layers)
|
||||
[:& layers-toolbox {:page page
|
||||
:selected selected}])]]])
|
||||
|
||||
;; --- Right Sidebar (Component)
|
||||
|
||||
|
|
|
@ -73,16 +73,17 @@
|
|||
|
||||
(defn- make-pages-iref
|
||||
[{:keys [id pages] :as project}]
|
||||
(letfn [(selector [state]
|
||||
(into [] (map #(get-in state [:pages %])) pages))]
|
||||
(-> (l/lens selector)
|
||||
(l/derive st/state))))
|
||||
(-> (l/lens (fn [s] (into [] (map #(get-in s [:pages %])) pages)))
|
||||
(l/derive st/state {:equals? =})))
|
||||
|
||||
(def ^:private pages-map-iref
|
||||
(-> (l/key :pages)
|
||||
(l/derive st/state)))
|
||||
|
||||
(mf/defc pages-list
|
||||
[{:keys [project current-page-id] :as props}]
|
||||
(let [pages-iref (mf/use-memo {:deps #js [project]
|
||||
:init #(make-pages-iref project)})
|
||||
pages (mf/deref pages-iref)
|
||||
(let [pages-map (mf/deref pages-map-iref)
|
||||
pages (map #(get pages-map %) (:pages project))
|
||||
deletable? (> (count pages) 1)]
|
||||
[:ul.element-list
|
||||
(for [[index item] (map-indexed vector pages)]
|
||||
|
|
|
@ -158,19 +158,21 @@
|
|||
|
||||
:render
|
||||
(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))
|
||||
zoom (or zoom 1)]
|
||||
(letfn [(on-mouse-down [event]
|
||||
(prn "viewport.on-mouse-down")
|
||||
(dom/stop-propagation event)
|
||||
(let [ctrl? (kbd/ctrl? event)
|
||||
shift? (kbd/shift? event)
|
||||
opts {:shift? shift?
|
||||
:ctrl? ctrl?}]
|
||||
(st/emit! (uev/mouse-event :down ctrl? shift?)))
|
||||
(if drawing-tool
|
||||
(st/emit! (udwd/start-drawing drawing-tool))
|
||||
(st/emit! ::uev/interrupt (udw/start-selrect))))
|
||||
(when (not edition)
|
||||
(if drawing-tool
|
||||
(st/emit! (udwd/start-drawing drawing-tool))
|
||||
(st/emit! ::uev/interrupt (udw/start-selrect)))))
|
||||
(on-context-menu [event]
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event)
|
||||
|
@ -187,6 +189,7 @@
|
|||
:ctrl? ctrl?}]
|
||||
(st/emit! (uev/mouse-event :up ctrl? shift?))))
|
||||
(on-click [event]
|
||||
(js/console.log "viewport.on-click" event)
|
||||
(dom/stop-propagation event)
|
||||
(let [ctrl? (kbd/ctrl? event)
|
||||
shift? (kbd/shift? event)
|
||||
|
@ -213,7 +216,8 @@
|
|||
:on-click on-click
|
||||
:on-double-click on-double-click
|
||||
: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 ")")}
|
||||
(when page
|
||||
[:& canvas {:page page :wst wst}])
|
||||
|
|
Loading…
Add table
Reference in a new issue