mirror of
https://github.com/penpot/penpot.git
synced 2025-01-09 08:20:45 -05:00
Initial (buggy) implementation of text drawing tool.
This commit is contained in:
parent
b3ec87d0f4
commit
94e22902f0
8 changed files with 197 additions and 15 deletions
|
@ -15,7 +15,7 @@
|
|||
(derive $ :builtin/rect ::rect)
|
||||
(derive $ :builtin/line ::shape)
|
||||
(derive $ :builtin/circle ::shape)
|
||||
(derive $ :builtin/text ::shape)
|
||||
(derive $ :builtin/text ::rect)
|
||||
(derive $ :builtin/group ::rect)))
|
||||
|
||||
(defn shape?
|
||||
|
@ -135,9 +135,15 @@
|
|||
(assoc shape :x2 x :y2 x)
|
||||
(assoc shape :x2 x :y2 y)))
|
||||
|
||||
(defmethod resize :builtin/text
|
||||
[shape {:keys [x y lock] :as pos}]
|
||||
(if lock
|
||||
(assoc shape :x2 x :y2 x)
|
||||
(assoc shape :x2 x :y2 y)))
|
||||
|
||||
(defmethod resize :default
|
||||
[shape _]
|
||||
(throw (ex-info "Not implemented" (select-keys shape [:type]))))
|
||||
(throw (ex-info "Not implemented (resize)" (select-keys shape [:type]))))
|
||||
|
||||
(defmethod resize' ::rect
|
||||
[shape {:keys [width height] :as size}]
|
||||
|
@ -149,7 +155,7 @@
|
|||
|
||||
(defmethod resize' :default
|
||||
[shape _]
|
||||
(throw (ex-info "Not implemented" (select-keys shape [:type]))))
|
||||
(throw (ex-info "Not implemented (resize')" (select-keys shape [:type]))))
|
||||
|
||||
(defmethod size ::rect
|
||||
[{:keys [x1 y1 x2 y2] :as shape}]
|
||||
|
@ -158,7 +164,7 @@
|
|||
|
||||
(defmethod size :default
|
||||
[shape _]
|
||||
(throw (ex-info "Not implemented" (select-keys shape [:type]))))
|
||||
(throw (ex-info "Not implemented (size)" (select-keys shape [:type]))))
|
||||
|
||||
;; Move
|
||||
|
||||
|
@ -192,7 +198,7 @@
|
|||
|
||||
(defmethod move :default
|
||||
[shape _]
|
||||
(throw (ex-info "Not implemented" (select-keys shape [:type]))))
|
||||
(throw (ex-info "Not implemented (move)" (select-keys shape [:type]))))
|
||||
|
||||
(defmethod move' ::rect
|
||||
[shape {:keys [x y] :as pos}]
|
||||
|
@ -214,7 +220,7 @@
|
|||
|
||||
(defmethod move' :default
|
||||
[shape _]
|
||||
(throw (ex-info "Not implemented" (select-keys shape [:type]))))
|
||||
(throw (ex-info "Not implemented (move')" (select-keys shape [:type]))))
|
||||
|
||||
(defmethod rotate ::shape
|
||||
[shape rotation]
|
||||
|
@ -273,7 +279,7 @@
|
|||
|
||||
(defmethod outer-rect' :default
|
||||
[shape _]
|
||||
(throw (ex-info "Not implemented" (select-keys shape [:type]))))
|
||||
(throw (ex-info "Not implemented (outer-rect')" (select-keys shape [:type]))))
|
||||
|
||||
(defmethod -transformation :builtin/icon
|
||||
[{:keys [x1 y1 rotation view-box] :or {rotation 0} :as shape}]
|
||||
|
@ -301,6 +307,18 @@
|
|||
(gmt/rotate rotation)
|
||||
(gmt/translate (- center-x) (- center-y)))))
|
||||
|
||||
|
||||
(defmethod -transformation :builtin/text
|
||||
[{:keys [x1 y1 rotation] :or {rotation 0} :as shape}]
|
||||
(let [{:keys [width height]} (size shape)
|
||||
center-x (+ x1 (/ width 2))
|
||||
center-y (+ y1 (/ height 2))]
|
||||
(-> (gmt/matrix)
|
||||
(gmt/translate center-x center-y)
|
||||
(gmt/rotate rotation)
|
||||
(gmt/translate (- center-x) (- center-y)))))
|
||||
|
||||
|
||||
(defmethod -transformation :builtin/circle
|
||||
[{:keys [cx cy rx ry rotation] :or {rotation 0} :as shape}]
|
||||
(-> (gmt/matrix)
|
||||
|
@ -325,7 +343,7 @@
|
|||
|
||||
(defmethod -transformation :default
|
||||
[shape _]
|
||||
(throw (ex-info "Not implemented" (select-keys shape [:type]))))
|
||||
(throw (ex-info "Not implemented (-transformation)" (select-keys shape [:type]))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Helpers
|
||||
|
|
|
@ -26,6 +26,12 @@
|
|||
(rum/element cls state nil))))]
|
||||
(with-meta ctr {:rum/class cls})))
|
||||
|
||||
(defn ref-html
|
||||
[own ref]
|
||||
(let [component (-> own :rum/react-component)
|
||||
node (aget (.-refs component) ref)]
|
||||
(.-innerHTML node)))
|
||||
|
||||
(defn ref-value
|
||||
[own ref]
|
||||
(let [component (-> own :rum/react-component)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
(ns uxbox.ui.shapes
|
||||
"A ui related implementation for uxbox.shapes ns."
|
||||
(:require [uxbox.ui.shapes.core :as usc]
|
||||
[uxbox.ui.shapes.text]
|
||||
[uxbox.ui.shapes.icon]
|
||||
[uxbox.ui.shapes.rect]
|
||||
[uxbox.ui.shapes.group]
|
||||
|
|
147
src/uxbox/ui/shapes/text.cljs
Normal file
147
src/uxbox/ui/shapes/text.cljs
Normal file
|
@ -0,0 +1,147 @@
|
|||
(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/emit-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/emit-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/emit-action! :nothing))))
|
||||
|
||||
(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)
|
||||
(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)]
|
||||
(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 "1"}})
|
||||
|
||||
(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)]
|
||||
(html
|
||||
[:g
|
||||
(if (or drawing? editing?)
|
||||
[:g
|
||||
[:rect (merge attrs +select-rect-attrs+)]])
|
||||
[:foreignObject attrs
|
||||
[:p {:ref "container"} content]]])))
|
||||
|
|
@ -32,11 +32,11 @@
|
|||
|
||||
(defn- on-key-down
|
||||
[event]
|
||||
(js/console.log event))
|
||||
#_(js/console.log event))
|
||||
|
||||
(defn- on-key-up
|
||||
[event]
|
||||
(js/console.log event))
|
||||
#_(js/console.log event))
|
||||
|
||||
(defn- workspace-render
|
||||
[own projectid]
|
||||
|
|
|
@ -26,7 +26,8 @@
|
|||
(let [shape (rum/react +drawing-shape+)
|
||||
position (rum/react +drawing-position+)]
|
||||
(when shape
|
||||
(-> (ush/resize shape position)
|
||||
(-> (assoc shape :drawing? true)
|
||||
(ush/resize position)
|
||||
(uusc/render-shape identity)))))
|
||||
|
||||
(def ^:static draw-area
|
||||
|
@ -79,6 +80,7 @@
|
|||
(when-let [shape (:drawing @wb/workspace-l)]
|
||||
(case (:type shape)
|
||||
:builtin/icon (init-icon shape)
|
||||
:builtin/text (init-shape shape)
|
||||
:builtin/rect (init-shape shape)
|
||||
:builtin/circle (init-shape shape)
|
||||
:builtin/line (init-shape shape))))]
|
||||
|
|
|
@ -31,27 +31,34 @@
|
|||
;; Draw Tools
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(def ^:staric +draw-tools+
|
||||
(def ^:const +draw-tools+
|
||||
{:rect
|
||||
{:icon i/box
|
||||
:help (tr "ds.help.rect")
|
||||
:shape {:type :builtin/rect
|
||||
:name "Rect"
|
||||
:stroke "#000000"}
|
||||
:priority 10}
|
||||
:priority 1}
|
||||
:circle
|
||||
{:icon i/circle
|
||||
:help (tr "ds.help.circle")
|
||||
:shape {:type :builtin/circle
|
||||
:name "Circle"}
|
||||
:priority 20}
|
||||
:priority 2}
|
||||
:line
|
||||
{:icon i/line
|
||||
:help (tr "ds.help.line")
|
||||
:shape {:type :builtin/line
|
||||
:name "Line"
|
||||
:stroke "#000000"}
|
||||
:priority 30}})
|
||||
:priority 3}
|
||||
:text
|
||||
{:icon i/text
|
||||
:help (tr "ds.help.text")
|
||||
:shape {:type :builtin/text
|
||||
:name "Text"
|
||||
:content "Hello world"}
|
||||
:priority 4}})
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Draw Tool Box
|
||||
|
|
|
@ -90,6 +90,7 @@
|
|||
:builtin/line i/line
|
||||
:builtin/circle i/circle
|
||||
:builtin/rect i/box
|
||||
:builtin/text i/text
|
||||
:builtin/group i/folder))
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue