penpot/src/uxbox/ui/shapes/text.cljs
2016-02-27 21:12:40 +02:00

159 lines
5 KiB
Clojure

(ns uxbox.ui.shapes.text
(:require [sablono.core :refer-macros [html]]
[cuerdas.core :as str]
[rum.core :as rum]
[lentes.core :as l]
[goog.events :as events]
[uxbox.rstore :as rs]
[uxbox.state :as st]
[uxbox.shapes :as ush]
[uxbox.data.workspace :as dw]
[uxbox.ui.core :as uuc]
[uxbox.ui.mixins :as mx]
[uxbox.ui.keyboard :as kbd]
[uxbox.ui.shapes.core :as uusc]
[uxbox.ui.shapes.icon :as uusi]
[uxbox.util.dom :as dom])
(:import goog.events.EventType))
(defn on-mouse-down
[event own {:keys [id group] :as shape} selected]
(let [selected? (contains? selected id)
local (:rum/local own)]
(when-not (:blocked shape)
(cond
(:edition @local)
nil
(and group (:locked (ush/resolve-parent shape)))
nil
(and (not selected?) (empty? selected))
(do
(dom/stop-propagation event)
(uuc/acquire-action! :shape/movement)
(rs/emit! (dw/select-shape id)))
(and (not selected?) (not (empty? selected)))
(do
(dom/stop-propagation event)
(if (kbd/shift? event)
(rs/emit! (dw/select-shape id))
(rs/emit! (dw/deselect-all)
(dw/select-shape id))))
:else
(do
(dom/stop-propagation event)
(uuc/acquire-action! :shape/movement))))))
(defn on-mouse-up
[event {:keys [id group] :as shape}]
(cond
(and group (:locked (ush/resolve-parent shape)))
nil
:else
(do
(dom/stop-propagation event)
(uuc/release-action! :draw/selrect)
(uuc/release-action! :shape/movement))))
(defn- text-component-did-mount
[own]
(letfn [(on-double-click [ev]
(let [container (mx/get-ref-dom own "container")
local (:rum/local own)]
(swap! local assoc :edition true)
(uuc/acquire-action! ::edition)
(set! (.-contentEditable container) true)
(.setAttribute container "contenteditable" "true")
(.focus container)))
(on-blur [ev]
(let [container (mx/get-ref-dom own "container")
local (:rum/local own)]
(uuc/release-action! ::edition)
(swap! local assoc :edition false)
(set! (.-contentEditable container) false)
(.removeAttribute container "contenteditable")))]
(let [dom (mx/get-ref-dom own "main")
dom2 (mx/get-ref-dom own "container")
key1 (events/listen dom EventType.DBLCLICK on-double-click)
key2 (events/listen dom2 EventType.BLUR on-blur)]
(assoc own ::key1 key1))))
(defn- text-component-will-unmount
[own]
(let [key1 (::key1 own)
key2 (::key2 own)]
(events/unlistenByKey key1)
(events/unlistenByKey key2)
(dissoc own ::key1 ::key2)))
(defn- text-component-transfer-state
[old-own own]
(let [data (select-keys old-own [::key1 ::key2])]
(merge own data)))
(defn- text-component-render
[own shape]
(let [{:keys [id x1 y1 content group]} shape
selected (rum/react uusc/selected-shapes-l)
selected? (and (contains? selected id) (= (count selected) 1))
on-mouse-down #(on-mouse-down % own shape selected)
on-mouse-up #(on-mouse-up % shape)
local (:rum/local own)]
(html
[:g.shape {:class (when selected? "selected")
;; :on-double-click #(on-double-click own %)
:ref "main"
:on-mouse-down on-mouse-down
:on-mouse-up on-mouse-up}
(uusc/render-shape (assoc shape :editing? (:edition @local false)) nil)
(when (and selected? (not (:edition @local false)))
(uusi/handlers shape))])))
(def ^:const text-component
(mx/component
{:render text-component-render
:name "text-componet"
:did-mount text-component-did-mount
:will-unmount text-component-will-unmount
:transfer-state text-component-transfer-state
:mixins [mx/static rum/reactive (mx/local)]}))
(defmethod uusc/render-component :builtin/text
[own shape]
(text-component shape))
(def ^:const +select-rect-attrs+
{:stroke-dasharray "5,5"
:style {:stroke "#333" :fill "transparent"
:stroke-opacity "0.4"}})
(def ^:const +style-attrs+
[:font-size])
(defn- build-style
[{:keys [font-size]}]
(merge {} (when font-size {:fontSize (str font-size "px")})))
(defmethod uusc/render-shape :builtin/text
[{:keys [id x1 y1 x2 y2 content drawing? editing?] :as shape}]
(let [key (str id)
rfm (ush/transformation shape)
size (ush/size shape)
props {:x x1 :y y1
:transform (str rfm)}
attrs (merge props size)
style (build-style shape)]
(html
[:g
(if (or drawing? editing?)
[:g
[:rect (merge attrs +select-rect-attrs+)]])
[:foreignObject attrs
[:p {:ref "container" :style style} content]]])))