mirror of
https://github.com/penpot/penpot.git
synced 2025-02-18 21:06:11 -05:00
🚧 Continue working on websocket communication.
This commit is contained in:
parent
d88bb1cfcb
commit
51058dd83a
8 changed files with 213 additions and 130 deletions
|
@ -56,8 +56,10 @@
|
||||||
|
|
||||||
(defmethod handle-message :disconnect
|
(defmethod handle-message :disconnect
|
||||||
[{:keys [user-id] :as ws} {:keys [file-id] :as message}]
|
[{:keys [user-id] :as ws} {:keys [file-id] :as message}]
|
||||||
(swap! state update file-id dissoc user-id)
|
(let [local (swap! state update file-id dissoc user-id)
|
||||||
nil)
|
sessions (get local file-id)
|
||||||
|
message {:type :who :users (set (keys sessions))}]
|
||||||
|
(run! #(send! % message) (vals sessions))))
|
||||||
|
|
||||||
(defmethod handle-message :who
|
(defmethod handle-message :who
|
||||||
[{:keys [file-id] :as ws} message]
|
[{:keys [file-id] :as ws} message]
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
(s/def ::id ::us/uuid)
|
(s/def ::id ::us/uuid)
|
||||||
(s/def ::name ::us/string)
|
(s/def ::name ::us/string)
|
||||||
(s/def ::project-id ::us/uuid)
|
(s/def ::project-id ::us/uuid)
|
||||||
|
(s/def ::file-id ::us/uuid)
|
||||||
(s/def ::user ::us/uuid)
|
(s/def ::user ::us/uuid)
|
||||||
|
|
||||||
(su/defstr sql:generic-project-files
|
(su/defstr sql:generic-project-files
|
||||||
|
@ -75,7 +76,6 @@
|
||||||
(-> (db/query conn [sql:recent-files user 20])
|
(-> (db/query conn [sql:recent-files user 20])
|
||||||
(p/then' (partial mapv decode-row))))
|
(p/then' (partial mapv decode-row))))
|
||||||
|
|
||||||
|
|
||||||
;; --- Query: Project File (By ID)
|
;; --- Query: Project File (By ID)
|
||||||
|
|
||||||
(su/defstr sql:project-file
|
(su/defstr sql:project-file
|
||||||
|
@ -90,6 +90,40 @@
|
||||||
(-> (db/query-one db/pool [sql:project-file user id])
|
(-> (db/query-one db/pool [sql:project-file user id])
|
||||||
(p/then' decode-row)))
|
(p/then' decode-row)))
|
||||||
|
|
||||||
|
;; --- Query: Users of the File
|
||||||
|
|
||||||
|
(su/defstr sql:file-users
|
||||||
|
"select u.id, u.fullname, u.photo
|
||||||
|
from users as u
|
||||||
|
join project_file_users as pfu on (pfu.user_id = u.id)
|
||||||
|
where pfu.file_id = $1
|
||||||
|
union all
|
||||||
|
select u.id, u.fullname, u.photo
|
||||||
|
from users as u
|
||||||
|
join project_users as pu on (pu.user_id = u.id)
|
||||||
|
where pu.project_id = $2")
|
||||||
|
|
||||||
|
(declare retrieve-minimal-file)
|
||||||
|
|
||||||
|
(su/defstr sql:minimal-file
|
||||||
|
"with files as (~{sql:generic-project-files})
|
||||||
|
select id, project_id from files where id = $2")
|
||||||
|
|
||||||
|
(s/def ::project-file-users
|
||||||
|
(s/keys :req-un [::user ::file-id]))
|
||||||
|
|
||||||
|
(sq/defquery ::project-file-users
|
||||||
|
[{:keys [user file-id] :as params}]
|
||||||
|
(db/with-atomic [conn db/pool]
|
||||||
|
(-> (retrieve-minimal-file conn user file-id)
|
||||||
|
(p/then (fn [{:keys [id project-id]}]
|
||||||
|
(prn ::project-file-users id project-id)
|
||||||
|
(db/query conn [sql:file-users id project-id]))))))
|
||||||
|
|
||||||
|
(defn- retrieve-minimal-file
|
||||||
|
[conn user-id file-id]
|
||||||
|
(-> (db/query-one conn [sql:minimal-file user-id file-id])
|
||||||
|
(p/then' su/raise-not-found-if-nil)))
|
||||||
|
|
||||||
;; --- Helpers
|
;; --- Helpers
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
(:require
|
(:require
|
||||||
[cljs.spec.alpha :as s]
|
[cljs.spec.alpha :as s]
|
||||||
[beicon.core :as rx]
|
[beicon.core :as rx]
|
||||||
|
[cuerdas.core :as str]
|
||||||
[potok.core :as ptk]
|
[potok.core :as ptk]
|
||||||
[uxbox.main.repo.core :as rp]
|
[uxbox.main.repo.core :as rp]
|
||||||
[uxbox.util.i18n :as i18n :refer [tr]]
|
[uxbox.util.i18n :as i18n :refer [tr]]
|
||||||
|
@ -31,7 +32,7 @@
|
||||||
|
|
||||||
;; --- Profile Fetched
|
;; --- Profile Fetched
|
||||||
|
|
||||||
(s/def ::profile-fetched-params
|
(s/def ::profile-fetched
|
||||||
(s/keys :req-un [::id
|
(s/keys :req-un [::id
|
||||||
::username
|
::username
|
||||||
::fullname
|
::fullname
|
||||||
|
@ -41,8 +42,8 @@
|
||||||
|
|
||||||
(defn profile-fetched
|
(defn profile-fetched
|
||||||
[data]
|
[data]
|
||||||
(s/assert ::profile-fetched-params data)
|
(s/assert ::profile-fetched data)
|
||||||
(reify
|
(ptk/reify ::profile-fetched
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(assoc state :profile data))
|
(assoc state :profile data))
|
||||||
|
|
98
frontend/src/uxbox/main/data/workspace_websocket.cljs
Normal file
98
frontend/src/uxbox/main/data/workspace_websocket.cljs
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
;; 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.data.workspace-websocket
|
||||||
|
(:require
|
||||||
|
[beicon.core :as rx]
|
||||||
|
[cljs.spec.alpha :as s]
|
||||||
|
[potok.core :as ptk]
|
||||||
|
[uxbox.config :as cfg]
|
||||||
|
[uxbox.common.data :as d]
|
||||||
|
[uxbox.common.pages :as cp]
|
||||||
|
[uxbox.main.websockets :as ws]
|
||||||
|
[uxbox.main.data.icons :as udi]
|
||||||
|
[uxbox.main.data.projects :as dp]
|
||||||
|
[uxbox.main.repo.core :as rp]
|
||||||
|
[uxbox.main.store :as st]
|
||||||
|
[uxbox.util.transit :as t]
|
||||||
|
[vendor.randomcolor]))
|
||||||
|
|
||||||
|
;; --- Initialize WebSocket
|
||||||
|
|
||||||
|
(declare fetch-users)
|
||||||
|
(declare handle-who)
|
||||||
|
|
||||||
|
(s/def ::type keyword?)
|
||||||
|
(s/def ::message
|
||||||
|
(s/keys :req-un [::type]))
|
||||||
|
|
||||||
|
(defn initialize
|
||||||
|
[file-id]
|
||||||
|
(ptk/reify ::initialize
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
;; (prn "initialize-websocket$update" file-id)
|
||||||
|
(let [uri (str "ws://localhost:6060/sub/" file-id)]
|
||||||
|
(assoc-in state [::ws file-id] (ws/open uri))))
|
||||||
|
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state stream]
|
||||||
|
;; (prn "initialize-websocket$watch" file-id)
|
||||||
|
(rx/merge
|
||||||
|
(rx/of (fetch-users file-id))
|
||||||
|
(->> (ws/-stream (get-in state [::ws file-id]))
|
||||||
|
(rx/filter #(= :message (:type %)))
|
||||||
|
(rx/map (comp t/decode :payload))
|
||||||
|
(rx/filter #(s/valid? ::message %))
|
||||||
|
;; (rx/tap #(js/console.log "ws-message" file-id %))
|
||||||
|
(rx/map (fn [{:keys [type] :as msg}]
|
||||||
|
(case type
|
||||||
|
:who (handle-who msg)
|
||||||
|
::unknown))))))))
|
||||||
|
|
||||||
|
;; --- Finalize Websocket
|
||||||
|
|
||||||
|
(defn finalize
|
||||||
|
[file-id]
|
||||||
|
(ptk/reify ::finalize
|
||||||
|
ptk/EffectEvent
|
||||||
|
(effect [_ state stream]
|
||||||
|
(ws/-close (get-in state [::ws file-id])))))
|
||||||
|
|
||||||
|
;; --- Fetch Workspace Users
|
||||||
|
|
||||||
|
(declare users-fetched)
|
||||||
|
|
||||||
|
(defn fetch-users
|
||||||
|
[file-id]
|
||||||
|
(ptk/reify ::fetch-users
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state stream]
|
||||||
|
(->> (rp/query :project-file-users {:file-id file-id})
|
||||||
|
(rx/map users-fetched)))))
|
||||||
|
|
||||||
|
(defn users-fetched
|
||||||
|
[users]
|
||||||
|
(ptk/reify ::users-fetched
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(reduce (fn [state user]
|
||||||
|
(assoc-in state [:workspace-users :by-id (:id user)] user))
|
||||||
|
state
|
||||||
|
users))))
|
||||||
|
|
||||||
|
|
||||||
|
;; --- Handle: Who
|
||||||
|
|
||||||
|
;; TODO: assign color
|
||||||
|
|
||||||
|
(defn handle-who
|
||||||
|
[{:keys [users] :as msg}]
|
||||||
|
(s/assert set? users)
|
||||||
|
(ptk/reify ::handle-who
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(assoc-in state [:workspace-users :active] users))))
|
|
@ -13,7 +13,8 @@
|
||||||
[uxbox.main.constants :as c]
|
[uxbox.main.constants :as c]
|
||||||
[uxbox.main.data.history :as udh]
|
[uxbox.main.data.history :as udh]
|
||||||
[uxbox.main.data.undo :as udu]
|
[uxbox.main.data.undo :as udu]
|
||||||
[uxbox.main.data.workspace :as udw]
|
[uxbox.main.data.workspace :as dw]
|
||||||
|
[uxbox.main.data.workspace-websocket :as dws]
|
||||||
[uxbox.main.refs :as refs]
|
[uxbox.main.refs :as refs]
|
||||||
[uxbox.main.store :as st]
|
[uxbox.main.store :as st]
|
||||||
[uxbox.main.ui.confirm]
|
[uxbox.main.ui.confirm]
|
||||||
|
@ -54,8 +55,8 @@
|
||||||
(dom/prevent-default event)
|
(dom/prevent-default event)
|
||||||
(dom/stop-propagation event)
|
(dom/stop-propagation event)
|
||||||
(if (pos? (.-deltaY event))
|
(if (pos? (.-deltaY event))
|
||||||
(st/emit! (udw/decrease-zoom))
|
(st/emit! (dw/decrease-zoom))
|
||||||
(st/emit! (udw/increase-zoom)))
|
(st/emit! (dw/increase-zoom)))
|
||||||
(scroll/scroll-to-point dom mouse-point scroll-position))))
|
(scroll/scroll-to-point dom mouse-point scroll-position))))
|
||||||
|
|
||||||
(mf/defc workspace-content
|
(mf/defc workspace-content
|
||||||
|
@ -96,17 +97,18 @@
|
||||||
[{:keys [file-id page-id] :as props}]
|
[{:keys [file-id page-id] :as props}]
|
||||||
|
|
||||||
(mf/use-effect
|
(mf/use-effect
|
||||||
{:deps #js [file-id page-id]
|
{:deps #js [(str file-id)
|
||||||
|
(str page-id)]
|
||||||
:fn (fn []
|
:fn (fn []
|
||||||
(let [sub (shortcuts/init)]
|
(let [sub (shortcuts/init)]
|
||||||
(st/emit! (udw/initialize file-id page-id))
|
(st/emit! (dw/initialize file-id page-id))
|
||||||
#(rx/cancel! sub)))})
|
#(rx/cancel! sub)))})
|
||||||
|
|
||||||
(mf/use-effect
|
(mf/use-effect
|
||||||
{:deps #js [(str file-id)]
|
{:deps #js [(str file-id)]
|
||||||
:fn (fn []
|
:fn (fn []
|
||||||
(st/emit! (udw/initialize-websocket file-id))
|
(st/emit! (dws/initialize file-id))
|
||||||
#(st/emit! (udw/finalize-websocket file-id)))})
|
#(st/emit! (dws/finalize file-id)))})
|
||||||
|
|
||||||
(let [layout (mf/deref refs/workspace-layout)
|
(let [layout (mf/deref refs/workspace-layout)
|
||||||
file (mf/deref refs/workspace-file)
|
file (mf/deref refs/workspace-file)
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
(ns uxbox.main.ui.workspace.header
|
(ns uxbox.main.ui.workspace.header
|
||||||
(:require
|
(:require
|
||||||
[rumext.alpha :as mf]
|
[rumext.alpha :as mf]
|
||||||
|
[lentes.core :as l]
|
||||||
[uxbox.builtins.icons :as i]
|
[uxbox.builtins.icons :as i]
|
||||||
[uxbox.config :as cfg]
|
[uxbox.config :as cfg]
|
||||||
[uxbox.main.data.history :as udh]
|
[uxbox.main.data.history :as udh]
|
||||||
|
@ -40,6 +41,50 @@
|
||||||
|
|
||||||
;; --- Header Component
|
;; --- Header Component
|
||||||
|
|
||||||
|
;; (mf/defc user
|
||||||
|
;; [props]
|
||||||
|
;; (let [open (mf/use-state false)
|
||||||
|
;; profile (mf/deref profile-ref)
|
||||||
|
;; photo (if (str/empty? (:photo profile ""))
|
||||||
|
;; "/images/avatar.jpg"
|
||||||
|
;; (:photo profile))]
|
||||||
|
;; [:div.user-zone {:on-click #(st/emit! (rt/navigate :settings/profile))
|
||||||
|
;; :on-mouse-enter #(reset! open true)
|
||||||
|
;; :on-mouse-leave #(reset! open false)}
|
||||||
|
;; [:span (:fullname profile)]
|
||||||
|
;; [:img {:src photo}]
|
||||||
|
;; (when @open
|
||||||
|
;; [:& user-menu])]))
|
||||||
|
|
||||||
|
|
||||||
|
(def profile-ref
|
||||||
|
(-> (l/key :profile)
|
||||||
|
(l/derive st/state)))
|
||||||
|
|
||||||
|
(def users-ref
|
||||||
|
(-> (l/key :workspace-users)
|
||||||
|
(l/derive st/state)))
|
||||||
|
|
||||||
|
(mf/defc user-item
|
||||||
|
[{:keys [user self?] :as props}]
|
||||||
|
[:li.tooltip.tooltip-bottom
|
||||||
|
{:alt (:fullname user)
|
||||||
|
:on-click (when self?
|
||||||
|
#(st/emit! (rt/navigate :settings/profile)))}
|
||||||
|
[:img {:src "/images/avatar.jpg"}]])
|
||||||
|
|
||||||
|
(mf/defc users
|
||||||
|
[props]
|
||||||
|
(let [profile (mf/deref profile-ref)
|
||||||
|
users (mf/deref users-ref)]
|
||||||
|
[:ul.user-multi
|
||||||
|
[:& user-item {:user profile :self? true}]
|
||||||
|
(for [id (->> (:active users)
|
||||||
|
(remove #(= % (:id profile))))]
|
||||||
|
[:& user-item {:user (get-in users [:by-id id])
|
||||||
|
:key id}])]))
|
||||||
|
|
||||||
|
|
||||||
(mf/defc header
|
(mf/defc header
|
||||||
[{:keys [page layout flags] :as props}]
|
[{:keys [page layout flags] :as props}]
|
||||||
(let [toggle #(st/emit! (dw/toggle-flag %))
|
(let [toggle #(st/emit! (dw/toggle-flag %))
|
||||||
|
@ -60,10 +105,7 @@
|
||||||
[:span {} "Project name / File name";(:name page)
|
[:span {} "Project name / File name";(:name page)
|
||||||
]]
|
]]
|
||||||
|
|
||||||
[:ul.user-multi
|
[:& users]
|
||||||
[:li.tooltip.tooltip-bottom
|
|
||||||
{:alt "USER_NAME"}
|
|
||||||
[:img {:src "images/avatar.jpg"}]]]
|
|
||||||
|
|
||||||
[:div.workspace-options
|
[:div.workspace-options
|
||||||
[:ul.options-btn
|
[:ul.options-btn
|
||||||
|
|
|
@ -1,111 +0,0 @@
|
||||||
;; 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) 2015-2019 Andrey Antukh <niwi@niwi.nz>
|
|
||||||
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
|
|
||||||
|
|
||||||
(ns uxbox.main.ui.workspace.sidebar.sitemap
|
|
||||||
(:require
|
|
||||||
[cuerdas.core :as str]
|
|
||||||
[lentes.core :as l]
|
|
||||||
[rumext.alpha :as mf]
|
|
||||||
[uxbox.builtins.icons :as i]
|
|
||||||
[uxbox.main.data.pages :as udp]
|
|
||||||
[uxbox.main.data.projects :as dp]
|
|
||||||
[uxbox.main.data.workspace :as dw]
|
|
||||||
[uxbox.main.store :as st]
|
|
||||||
[uxbox.main.refs :as refs]
|
|
||||||
[uxbox.main.ui.confirm :refer [confirm-dialog]]
|
|
||||||
[uxbox.main.ui.modal :as modal]
|
|
||||||
[uxbox.main.ui.workspace.sidebar.sitemap-forms :refer [page-form-dialog]]
|
|
||||||
[uxbox.main.ui.workspace.sortable :refer [use-sortable]]
|
|
||||||
[uxbox.util.data :refer [classnames enumerate]]
|
|
||||||
[uxbox.util.dom :as dom]
|
|
||||||
[uxbox.util.i18n :refer [tr]]
|
|
||||||
[uxbox.util.router :as rt]))
|
|
||||||
|
|
||||||
;; --- Page Item
|
|
||||||
|
|
||||||
(mf/defc page-item
|
|
||||||
[{:keys [page index deletable? selected?] :as props}]
|
|
||||||
(let [on-edit #(modal/show! page-form-dialog {:page page})
|
|
||||||
delete-fn #(st/emit! (udp/delete-page (:id page)))
|
|
||||||
on-delete #(do
|
|
||||||
(dom/prevent-default %)
|
|
||||||
(dom/stop-propagation %)
|
|
||||||
(modal/show! confirm-dialog {:on-accept delete-fn}))
|
|
||||||
on-drop #(do (prn "TODO"))
|
|
||||||
on-hover #(st/emit! (dw/change-page-order {:id (:id page)
|
|
||||||
:index index}))
|
|
||||||
|
|
||||||
navigate-fn #(st/emit! (dw/go-to-page (:id page)))
|
|
||||||
[dprops ref] (use-sortable {:type "page-item"
|
|
||||||
:data {:id (:id page)
|
|
||||||
:index index}
|
|
||||||
:on-hover on-hover
|
|
||||||
:on-drop on-drop})]
|
|
||||||
[:li {:ref ref :class (classnames :selected selected?)}
|
|
||||||
[:div.element-list-body
|
|
||||||
{:class (classnames :selected selected?
|
|
||||||
:dragging (:dragging? dprops))
|
|
||||||
:on-click navigate-fn
|
|
||||||
:on-double-click #(dom/stop-propagation %)
|
|
||||||
:draggable true}
|
|
||||||
|
|
||||||
[:div.page-icon i/page]
|
|
||||||
[:span (:name page)]
|
|
||||||
[:div.page-actions {}
|
|
||||||
[:a {:on-click on-edit} i/pencil]
|
|
||||||
(when deletable?
|
|
||||||
[:a {:on-click on-delete} i/trash])]]]))
|
|
||||||
|
|
||||||
|
|
||||||
;; --- Page Item Wrapper
|
|
||||||
|
|
||||||
(defn- make-page-ref
|
|
||||||
[page-id]
|
|
||||||
(-> (l/in [:pages page-id])
|
|
||||||
(l/derive st/state)))
|
|
||||||
|
|
||||||
(mf/defc page-item-wrapper
|
|
||||||
[{:keys [page-id index deletable? selected?] :as props}]
|
|
||||||
(let [page-ref (mf/use-memo {:deps #js [page-id]
|
|
||||||
:fn #(make-page-ref page-id)})
|
|
||||||
page (mf/deref page-ref)]
|
|
||||||
[:& page-item {:page page
|
|
||||||
:index index
|
|
||||||
:deletable? deletable?
|
|
||||||
:selected? selected?}]))
|
|
||||||
|
|
||||||
;; --- Pages List
|
|
||||||
|
|
||||||
(mf/defc pages-list
|
|
||||||
[{:keys [file current-page] :as props}]
|
|
||||||
(let [pages (enumerate (:pages file))
|
|
||||||
deletable? (> (count pages) 1)]
|
|
||||||
[:ul.element-list
|
|
||||||
(for [[index page-id] pages]
|
|
||||||
[:& page-item-wrapper
|
|
||||||
{:page-id page-id
|
|
||||||
:index index
|
|
||||||
:deletable? deletable?
|
|
||||||
:selected? (= page-id (:id current-page))
|
|
||||||
:key page-id}])]))
|
|
||||||
|
|
||||||
;; --- Sitemap Toolbox
|
|
||||||
|
|
||||||
(mf/defc sitemap-toolbox
|
|
||||||
[{:keys [file page] :as props}]
|
|
||||||
(let [create-fn #(modal/show! page-form-dialog {:page {:file-id (:file-id page)}})
|
|
||||||
close-fn #(st/emit! (dw/toggle-layout-flag :sitemap))]
|
|
||||||
[:div.sitemap.tool-window
|
|
||||||
[:div.tool-window-bar
|
|
||||||
[:div.tool-window-icon i/project-tree]
|
|
||||||
[:span (tr "ds.settings.sitemap")]
|
|
||||||
[:div.tool-window-close {:on-click close-fn} i/close]]
|
|
||||||
[:div.tool-window-content
|
|
||||||
[:div.project-title
|
|
||||||
#_[:span (:name project)]
|
|
||||||
[:div.add-page {:on-click create-fn} i/close]]
|
|
||||||
[:& pages-list {:file file :current-page page}]]]))
|
|
|
@ -73,14 +73,29 @@
|
||||||
|
|
||||||
;; --- Selection Rect
|
;; --- Selection Rect
|
||||||
|
|
||||||
|
(defn- selection->rect
|
||||||
|
[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))
|
||||||
|
end-y (max (:y start) (:y stop))]
|
||||||
|
(assoc data
|
||||||
|
:x1 start-x
|
||||||
|
:y1 start-y
|
||||||
|
:x2 end-x
|
||||||
|
:y2 end-y
|
||||||
|
:type :rect)))
|
||||||
|
|
||||||
(def ^:private handle-selrect
|
(def ^:private handle-selrect
|
||||||
(letfn [(update-state [state position]
|
(letfn [(update-state [state position]
|
||||||
(let [selrect (get-in state [:workspace-local :selrect])]
|
(let [selrect (get-in state [:workspace-local :selrect])]
|
||||||
(if selrect
|
(if selrect
|
||||||
(assoc-in state [:workspace-local :selrect]
|
(assoc-in state [:workspace-local :selrect]
|
||||||
(dw/selection->rect (assoc selrect :stop position)))
|
(selection->rect (assoc selrect :stop position)))
|
||||||
(assoc-in state [:workspace-local :selrect]
|
(assoc-in state [:workspace-local :selrect]
|
||||||
(dw/selection->rect {:start position :stop position})))))
|
(selection->rect {:start position :stop position})))))
|
||||||
|
|
||||||
(clear-state [state]
|
(clear-state [state]
|
||||||
(update state :workspace-local dissoc :selrect))]
|
(update state :workspace-local dissoc :selrect))]
|
||||||
|
|
Loading…
Add table
Reference in a new issue