mirror of
https://github.com/penpot/penpot.git
synced 2026-03-19 08:53:39 +00:00
255 lines
7.4 KiB
Clojure
255 lines
7.4 KiB
Clojure
;; 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-2016 Andrey Antukh <niwi@niwi.nz>
|
|
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
|
|
|
|
(ns uxbox.main.data.workspace
|
|
(:require [beicon.core :as rx]
|
|
[uxbox.util.uuid :as uuid]
|
|
[uxbox.main.constants :as c]
|
|
[uxbox.util.rstore :as rs]
|
|
[uxbox.util.schema :as sc]
|
|
[uxbox.util.geom.point :as gpt]
|
|
[uxbox.util.workers :as uw]
|
|
[uxbox.main.state :as st]
|
|
[uxbox.main.state.shapes :as stsh]
|
|
[uxbox.main.data.core :refer (worker)]
|
|
[uxbox.main.data.projects :as dp]
|
|
[uxbox.main.data.pages :as udp]
|
|
[uxbox.main.data.shapes :as uds]
|
|
[uxbox.main.data.forms :as udf]
|
|
[uxbox.main.data.lightbox :as udl]
|
|
[uxbox.main.data.history :as udh]
|
|
[uxbox.util.datetime :as dt]
|
|
[uxbox.util.math :as mth]
|
|
[uxbox.util.data :refer (index-of)]))
|
|
|
|
;; --- Constants
|
|
|
|
(def zoom-levels
|
|
[0.20 0.21 0.22 0.23 0.24 0.25 0.27 0.28 0.30 0.32 0.34
|
|
0.36 0.38 0.40 0.42 0.44 0.46 0.48 0.51 0.54 0.57 0.60
|
|
0.63 0.66 0.69 0.73 0.77 0.81 0.85 0.90 0.95 1.00 1.05
|
|
1.10 1.15 1.21 1.27 1.33 1.40 1.47 1.54 1.62 1.70 1.78
|
|
1.87 1.96 2.06 2.16 2.27 2.38 2.50 2.62 2.75 2.88 3.00])
|
|
|
|
;; --- Initialize Workspace
|
|
|
|
(declare initialize-alignment-index)
|
|
|
|
(defrecord InitializeWorkspace [project page]
|
|
rs/UpdateEvent
|
|
(-apply-update [_ state]
|
|
(if (:workspace state)
|
|
(update state :workspace merge
|
|
{:project project
|
|
:page page
|
|
:selected #{}
|
|
:drawing nil})
|
|
(assoc state :workspace
|
|
{:project project
|
|
:zoom 1
|
|
:page page
|
|
:flags #{:sitemap :drawtools :layers}
|
|
:selected #{}
|
|
:drawing nil})))
|
|
|
|
rs/WatchEvent
|
|
(-apply-watch [_ state s]
|
|
(let [page-id page
|
|
page (get-in state [:pages-by-id page-id])]
|
|
|
|
;; Activate loaded if page is not fetched.
|
|
(when-not page (reset! st/loader true))
|
|
|
|
(rx/merge
|
|
(if page
|
|
(rx/of (initialize-alignment-index page-id))
|
|
(rx/merge
|
|
(rx/of (udp/fetch-pages project))
|
|
(->> (rx/filter udp/pages-fetched? s)
|
|
(rx/take 1)
|
|
(rx/do #(reset! st/loader false))
|
|
(rx/map #(initialize-alignment-index page-id)))))
|
|
|
|
;; Initial history loading
|
|
(rx/of
|
|
(udh/fetch-page-history page-id)
|
|
(udh/fetch-pinned-page-history page-id)))))
|
|
|
|
rs/EffectEvent
|
|
(-apply-effect [_ state]
|
|
;; Optimistic prefetch of projects if them are not already fetched
|
|
(when-not (seq (:projects-by-id state))
|
|
(rs/emit! (dp/fetch-projects)))))
|
|
|
|
(defn initialize
|
|
"Initialize the workspace state."
|
|
[project page]
|
|
(InitializeWorkspace. project page))
|
|
|
|
;; --- Toggle Flag
|
|
|
|
(defn toggle-flag
|
|
"Toggle the enabled flag of the specified tool."
|
|
[key]
|
|
(reify
|
|
rs/UpdateEvent
|
|
(-apply-update [_ state]
|
|
(let [flags (get-in state [:workspace :flags])]
|
|
(if (contains? flags key)
|
|
(assoc-in state [:workspace :flags] (disj flags key))
|
|
(assoc-in state [:workspace :flags] (conj flags key)))))))
|
|
|
|
(defn select-for-drawing
|
|
"Mark a shape selected for drawing in the canvas."
|
|
[shape]
|
|
(reify
|
|
rs/UpdateEvent
|
|
(-apply-update [_ state]
|
|
(let [current (get-in state [:workspace :drawing])]
|
|
(if (or (nil? shape)
|
|
(= shape current))
|
|
(update state :workspace dissoc :drawing)
|
|
(assoc-in state [:workspace :drawing] shape))))))
|
|
|
|
;; --- Activate Workspace Flag
|
|
|
|
(defrecord ActivateFlag [flag]
|
|
rs/UpdateEvent
|
|
(-apply-update [_ state]
|
|
(update-in state [:workspace :flags] conj flag)))
|
|
|
|
(defn activate-flag
|
|
[flag]
|
|
(ActivateFlag. flag))
|
|
|
|
;; --- Copy to Clipboard
|
|
|
|
(defrecord CopyToClipboard []
|
|
rs/UpdateEvent
|
|
(-apply-update [_ state]
|
|
(let [selected (get-in state [:workspace :selected])
|
|
item {:id (uuid/random)
|
|
:created-at (dt/now)
|
|
:items selected}
|
|
clipboard (-> (:clipboard state)
|
|
(conj item))]
|
|
(assoc state :clipboard
|
|
(if (> (count clipboard) 5)
|
|
(pop clipboard)
|
|
clipboard)))))
|
|
|
|
(defn copy-to-clipboard
|
|
"Copy selected shapes to clipboard."
|
|
[]
|
|
(CopyToClipboard.))
|
|
|
|
;; --- Paste from Clipboard
|
|
|
|
(defrecord PasteFromClipboard [id]
|
|
rs/UpdateEvent
|
|
(-apply-update [_ state]
|
|
(let [page (get-in state [:workspace :page])
|
|
selected (if (nil? id)
|
|
(first (:clipboard state))
|
|
(->> (:clipboard state)
|
|
(filter #(= id (:id %)))
|
|
(first)))]
|
|
(stsh/duplicate-shapes state (:items selected) page))))
|
|
|
|
(defn paste-from-clipboard
|
|
"Copy selected shapes to clipboard."
|
|
([] (PasteFromClipboard. nil))
|
|
([id] (PasteFromClipboard. id)))
|
|
|
|
;; --- Increase Zoom
|
|
|
|
(defrecord IncreaseZoom []
|
|
rs/UpdateEvent
|
|
(-apply-update [_ state]
|
|
(let [increase #(nth zoom-levels
|
|
(+ (index-of zoom-levels %) 1)
|
|
(last zoom-levels))]
|
|
(update-in state [:workspace :zoom] (fnil increase 1)))))
|
|
|
|
(defn increase-zoom
|
|
[]
|
|
(IncreaseZoom.))
|
|
|
|
;; --- Decrease Zoom
|
|
|
|
(defrecord DecreaseZoom []
|
|
rs/UpdateEvent
|
|
(-apply-update [_ state]
|
|
(let [decrease #(nth zoom-levels
|
|
(- (index-of zoom-levels %) 1)
|
|
(first zoom-levels))]
|
|
(update-in state [:workspace :zoom] (fnil decrease 1)))))
|
|
|
|
(defn decrease-zoom
|
|
[]
|
|
(DecreaseZoom.))
|
|
|
|
;; --- Reset Zoom
|
|
|
|
(defrecord ResetZoom []
|
|
rs/UpdateEvent
|
|
(-apply-update [_ state]
|
|
(assoc-in state [:workspace :zoom] 1)))
|
|
|
|
(defn reset-zoom
|
|
[]
|
|
(ResetZoom.))
|
|
|
|
;; --- Initialize Alignment Index
|
|
|
|
(defrecord InitializeAlignmentIndex [id]
|
|
rs/WatchEvent
|
|
(-apply-watch [_ state s]
|
|
(let [page (get-in state [:pages-by-id id])
|
|
opts (:options page)
|
|
message {:cmd :grid/init
|
|
:width c/viewport-width
|
|
:height c/viewport-height
|
|
:x-axis (:grid/x-axis opts c/grid-x-axis)
|
|
:y-axis (:grid/y-axis opts c/grid-y-axis)}]
|
|
(rx/merge
|
|
(->> (uw/send! worker message)
|
|
(rx/map #(activate-flag :grid/indexed)))
|
|
(when (:grid/alignment opts)
|
|
(rx/of (activate-flag :grid/alignment)))))))
|
|
|
|
(defn initialize-alignment-index
|
|
[id]
|
|
(InitializeAlignmentIndex. id))
|
|
|
|
;; --- Update Workspace Settings (Form)
|
|
|
|
(defrecord SubmitWorkspaceSettings [id options]
|
|
rs/WatchEvent
|
|
(-apply-watch [_ state s]
|
|
(rx/of (udp/update-page-options id options)
|
|
(initialize-alignment-index id)
|
|
(udf/clean :workspace/settings)))
|
|
|
|
rs/EffectEvent
|
|
(-apply-effect [_ state]
|
|
(udl/close!)))
|
|
|
|
(def submit-workspace-settings-schema
|
|
{:grid/y-axis [sc/required sc/integer [sc/in-range 2 100]]
|
|
:grid/x-axis [sc/required sc/integer [sc/in-range 2 100]]
|
|
:grid/alignment [sc/boolean]
|
|
:grid/color [sc/required sc/color]})
|
|
|
|
(defn submit-workspace-settings
|
|
[id data]
|
|
(let [schema submit-workspace-settings-schema
|
|
[errors data] (sc/validate data schema)]
|
|
(if errors
|
|
(udf/assign-errors :workspace/settings errors)
|
|
(SubmitWorkspaceSettings. id data))))
|