Refactor shapes related namespaces.

This commit is contained in:
Andrey Antukh 2016-05-22 20:11:30 +03:00
parent 2733debadc
commit defe616b22
No known key found for this signature in database
GPG key ID: 4DFEBCB8316A8B95
15 changed files with 456 additions and 366 deletions

View file

@ -17,7 +17,7 @@
[uxbox.data.dashboard :as dd] [uxbox.data.dashboard :as dd]
[uxbox.data.lightbox :as udl] [uxbox.data.lightbox :as udl]
[uxbox.ui.icons :as i] [uxbox.ui.icons :as i]
[uxbox.ui.shapes.core :as uusc] [uxbox.ui.shapes.icon :as icon]
[uxbox.ui.lightbox :as lbx] [uxbox.ui.lightbox :as lbx]
[uxbox.ui.mixins :as mx] [uxbox.ui.mixins :as mx]
[uxbox.ui.dashboard.header :refer (header)] [uxbox.ui.dashboard.header :refer (header)]
@ -111,7 +111,7 @@
[:div.dashboard-grid-row [:div.dashboard-grid-row
(for [icon (:icons coll)] (for [icon (:icons coll)]
[:div.grid-item.small-item.project-th {} [:div.grid-item.small-item.project-th {}
[:span.grid-item-image #_i/toggle (uusc/render-shape-svg icon nil)] [:span.grid-item-image (icon/icon-svg icon)]
[:h3 (:name icon)] [:h3 (:name icon)]
#_[:div.project-th-actions #_[:div.project-th-actions
[:div.project-th-icon.edit i/pencil] [:div.project-th-icon.edit i/pencil]

View file

@ -1,11 +1,31 @@
(ns uxbox.ui.shapes ;; This Source Code Form is subject to the terms of the Mozilla Public
"A ui related implementation for uxbox.shapes ns." ;; License, v. 2.0. If a copy of the MPL was not distributed with this
(:require [uxbox.ui.shapes.core :as usc] ;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
[uxbox.ui.shapes.text] ;;
[uxbox.ui.shapes.icon] ;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
[uxbox.ui.shapes.rect]
[uxbox.ui.shapes.group]
[uxbox.ui.shapes.line]
[uxbox.ui.shapes.circle]))
(def ^:const shape usc/shape) (ns uxbox.ui.shapes
(:require [lentes.core :as l]
[rum.core :as rum]
[uxbox.state :as st]
[uxbox.ui.mixins :as mx]
[uxbox.ui.shapes.group :as group]))
(def render-component group/render-component)
(defn- focus-shape
[id]
(-> (l/in [:shapes-by-id id])
(l/focus-atom st/state)))
(defn- shape-render
[own id]
(let [shape (rum/react (focus-shape id))]
(when-not (:hidden shape)
(render-component shape))))
(def shape
(mx/component
{:render shape-render
:name "shape"
:mixins [mx/static rum/reactive]}))

View file

@ -0,0 +1,48 @@
;; 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) 2016 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.ui.shapes.attrs)
(def ^:private +style-attrs+
#{:fill :fill-opacity :opacity
:stroke :stroke-opacity :stroke-width
:stroke-type :rx :ry})
(defn- transform-stroke-type
[attrs]
(if-let [type (:stroke-type attrs)]
(let [value (case type
:mixed "5,5,1,5"
:dotted "5,5"
:dashed "10,10"
nil)]
(if value
(-> attrs
(assoc! :stroke-dasharray value)
(dissoc! :stroke-type))
(dissoc! attrs :stroke-type)))
attrs))
(defn- transform-stroke-attrs
[attrs]
(if (= (:stroke-type attrs :none) :none)
(dissoc! attrs :stroke-type :stroke-width :stroke-opacity :stroke)
(transform-stroke-type attrs)))
(defn- extract-style-attrs
"Extract predefinet attrs from shapes."
[shape]
(let [attrs (select-keys shape +style-attrs+)]
(-> (transient attrs)
(transform-stroke-attrs)
(persistent!))))
(defn- make-debug-attrs
[shape]
(let [attrs (select-keys shape [:rotation :width :height :x :y])
xf (map (fn [[x v]]
[(keyword (str "data-" (name x))) v]))]
(into {} xf attrs)))

View file

@ -1,102 +1,56 @@
;; 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) 2016 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.ui.shapes.circle (ns uxbox.ui.shapes.circle
(:require [sablono.core :refer-macros [html]] (:require [sablono.core :refer-macros [html]]
[cuerdas.core :as str]
[rum.core :as rum] [rum.core :as rum]
[lentes.core :as l] [lentes.core :as l]
[uxbox.rstore :as rs]
[uxbox.state :as st]
[uxbox.data.workspace :as dw]
[uxbox.ui.core :as uuc]
[uxbox.ui.mixins :as mx] [uxbox.ui.mixins :as mx]
[uxbox.ui.keyboard :as kbd] [uxbox.ui.shapes.common :as common]
[uxbox.ui.shapes.core :as uusc] [uxbox.ui.shapes.attrs :as attrs]
[uxbox.ui.shapes.icon :as uusi] [uxbox.util.geom :as geom]))
[uxbox.util.geom :as geom]
[uxbox.util.dom :as dom]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; --- Circle Component
;; Circle Component
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(declare handlers) (declare circle-shape)
;; (defmethod uusc/render-component :default ;; :icon (defn- circle-component-render
;; [own shape] [own shape]
;; (let [{:keys [id x y width height group]} shape (let [{:keys [id x y width height group]} shape
;; selected (rum/react uusc/selected-shapes-l) selected (rum/react common/selected-shapes-l)
;; selected? (contains? selected id) selected? (contains? selected id)
;; on-mouse-down #(uusi/on-mouse-down % shape selected) on-mouse-down #(common/on-mouse-down % shape selected)
;; on-mouse-up #(uusi/on-mouse-up % shape)] on-mouse-up #(common/on-mouse-up % shape)]
;; (html (html
;; [:g.shape {:class (when selected? "selected") [:g.shape {:class (when selected? "selected")
;; :on-mouse-down on-mouse-down :on-mouse-down on-mouse-down
;; :on-mouse-up on-mouse-up} :on-mouse-up on-mouse-up}
;; (uusc/render-shape shape #(uusc/shape %)) (circle-shape shape identity)])))
;; (when (and selected? (= (count selected) 1))
;; (handlers shape))])))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (def circle-component
;; Circle Handlers (mx/component
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; {:render circle-component-render
:name "circle-component"
:mixins [mx/static rum/reactive]}))
;; (defn- handlers-render ;; --- Circle Shape
;; [own shape]
;; (letfn [(on-mouse-down [vid event]
;; (dom/stop-propagation event)
;; (uuc/acquire-action! "ui.shape.resize"
;; {:vid vid :shape (:id shape)}))
;; (on-mouse-up [vid event] (defn- circle-shape-render
;; (dom/stop-propagation event) [own {:keys [id] :as shape}]
;; (uuc/release-action! "ui.shape.resize"))]
;; (let [{:keys [x y width height]} (geom/outer-rect shape)]
;; (html
;; [:g.controls
;; [:rect {:x x :y y :width width :height height :stroke-dasharray "5,5"
;; :style {:stroke "#333" :fill "transparent"
;; :stroke-opacity "1"}}]
;; [:circle.top-left
;; (merge uusc/+circle-props+
;; {:on-mouse-up #(on-mouse-up 1 %)
;; :on-mouse-down #(on-mouse-down 1 %)
;; :cx x
;; :cy y})]
;; [:circle.top-right
;; (merge uusc/+circle-props+
;; {:on-mouse-up #(on-mouse-up 2 %)
;; :on-mouse-down #(on-mouse-down 2 %)
;; :cx (+ x width)
;; :cy y})]
;; [:circle.bottom-left
;; (merge uusc/+circle-props+
;; {:on-mouse-up #(on-mouse-up 3 %)
;; :on-mouse-down #(on-mouse-down 3 %)
;; :cx x
;; :cy (+ y height)})]
;; [:circle.bottom-right
;; (merge uusc/+circle-props+
;; {:on-mouse-up #(on-mouse-up 4 %)
;; :on-mouse-down #(on-mouse-down 4 %)
;; :cx (+ x width)
;; :cy (+ y height)})]]))))
;; (def ^:const handlers
;; (mx/component
;; {:render handlers-render
;; :name "handlers"
;; :mixins [mx/static]}))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Shape
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmethod uusc/render-shape :circle
[{:keys [id] :as shape}]
(let [key (str id) (let [key (str id)
rfm (geom/transformation-matrix shape) rfm (geom/transformation-matrix shape)
props (select-keys shape [:cx :cy :rx :ry]) props (select-keys shape [:cx :cy :rx :ry])
attrs (-> (uusc/extract-style-attrs shape) attrs (-> (attrs/extract-style-attrs shape)
(merge {:id key :key key :transform (str rfm)}) (merge {:id key :key key :transform (str rfm)})
(merge props))] (merge props))]
(html (html
[:ellipse attrs]))) [:ellipse attrs])))
(def circle-shape
(mx/component
{:render circle-shape-render
:name "circle-shape"
:mixins [mx/static]}))

View file

@ -0,0 +1,71 @@
;; 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) 2016 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.ui.shapes.common
(:require [sablono.core :refer-macros [html]]
[lentes.core :as l]
[uxbox.rstore :as rs]
[uxbox.state :as st]
[uxbox.data.shapes :as uds]
[uxbox.ui.core :as ui]
[uxbox.ui.keyboard :as kbd]
[uxbox.util.geom :as geom]
[uxbox.util.dom :as dom]))
;; --- Lenses
(def ^:const selected-shapes-l
(-> (l/in [:workspace :selected])
(l/focus-atom st/state)))
(def ^:const drawing-state-l
(-> (l/in [:workspace :drawing])
(l/focus-atom st/state)))
;; --- Events
(defn on-mouse-down
[event {:keys [id group] :as shape} selected]
(let [selected? (contains? selected id)
drawing? @drawing-state-l]
(when-not (:blocked shape)
(cond
(or drawing?
(and group (:locked (geom/resolve-parent shape))))
nil
(and (not selected?) (empty? selected))
(do
(dom/stop-propagation event)
(rs/emit! (uds/select-shape id))
(ui/acquire-action! "ui.shape.move"))
(and (not selected?) (not (empty? selected)))
(do
(dom/stop-propagation event)
(if (kbd/shift? event)
(rs/emit! (uds/select-shape id))
(do
(rs/emit! (uds/deselect-all)
(uds/select-shape id))
(ui/acquire-action! "ui.shape.move"))))
:else
(do
(dom/stop-propagation event)
(ui/acquire-action! "ui.shape.move"))))))
(defn on-mouse-up
[event {:keys [id group] :as shape}]
(cond
(and group (:locked (geom/resolve-parent shape)))
nil
:else
(do
(dom/stop-propagation event)
(ui/release-action! "ui.shape"))))

View file

@ -1,117 +0,0 @@
(ns uxbox.ui.shapes.core
(:require [lentes.core :as l]
[cuerdas.core :as str]
[rum.core :as rum]
[uxbox.state :as st]
[uxbox.ui.mixins :as mx]
[uxbox.util.geom :as geom]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Common constants
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def ^:const +circle-props+
{:r 6
:style {:fillOpacity "1"
:strokeWidth "1px"
:vectorEffect "non-scaling-stroke"}
:fill "#31e6e0"
:stroke "#28c4d4"})
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Implementation Api
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn dispatch-by-type
[shape & params]
(:type shape))
(defmulti render-component
(fn [own shape] (:type shape))
:hierarchy #'geom/+hierarchy+)
(defmulti render-shape
dispatch-by-type
:hierarchy #'geom/+hierarchy+)
(defmulti render-shape-svg
dispatch-by-type
:hierarchy #'geom/+hierarchy+)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Lenses
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def ^:const selected-shapes-l
(-> (l/in [:workspace :selected])
(l/focus-atom st/state)))
(def ^:const drawing-state-l
(-> (l/in [:workspace :drawing])
(l/focus-atom st/state)))
(defn- focus-shape
[id]
(as-> (l/in [:shapes-by-id id]) $
(l/focus-atom $ st/state)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Component Api
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn- shape-render
[own id]
(let [shape-l (focus-shape id)
shape (rum/react shape-l)]
(when-not (:hidden shape)
(render-component own shape))))
(def ^:const shape
(mx/component
{:render shape-render
:name "shape"
:mixins [(mx/local) mx/static rum/reactive]}))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Attribute transformations
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def ^:static ^:private +style-attrs+
#{:fill :fill-opacity :opacity :stroke :stroke-opacity
:stroke-width :stroke-type :rx :ry})
(defn- transform-stroke-type
[attrs]
(if-let [type (:stroke-type attrs)]
(let [value (case type
:mixed "5,5,1,5"
:dotted "5,5"
:dashed "10,10"
nil)]
(if value
(-> attrs
(assoc! :stroke-dasharray value)
(dissoc! :stroke-type))
(dissoc! attrs :stroke-type)))
attrs))
(defn- transform-stroke-attrs
[attrs]
(if (= (:stroke-type attrs :none) :none)
(dissoc! attrs :stroke-type :stroke-width :stroke-opacity :stroke)
(transform-stroke-type attrs)))
(defn- extract-style-attrs
"Extract predefinet attrs from shapes."
[shape]
(let [attrs (select-keys shape +style-attrs+)]
(-> (transient attrs)
(transform-stroke-attrs)
(persistent!))))
(defn- make-debug-attrs
[shape]
(let [attrs (select-keys shape [:rotation :width :height :x :y])
xf (map (fn [[x v]]
[(keyword (str "data-" (name x))) v]))]
(into {} xf attrs)))

View file

@ -1,31 +1,76 @@
;; 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) 2016 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.ui.shapes.group (ns uxbox.ui.shapes.group
(:require [sablono.core :refer-macros [html]] (:require [sablono.core :refer-macros [html]]
[cuerdas.core :as str]
[rum.core :as rum] [rum.core :as rum]
[lentes.core :as l] [lentes.core :as l]
[uxbox.rstore :as rs]
[uxbox.state :as st] [uxbox.state :as st]
[uxbox.data.workspace :as dw] [uxbox.ui.mixins :as mx]
[uxbox.ui.core :as uuc] [uxbox.ui.shapes.common :as common]
[uxbox.ui.keyboard :as kbd] [uxbox.ui.shapes.attrs :as attrs]
[uxbox.ui.shapes.core :as uusc] [uxbox.ui.shapes.icon :as icon]
[uxbox.util.geom :as geom] [uxbox.ui.shapes.rect :as rect]
[uxbox.util.dom :as dom])) [uxbox.ui.shapes.circle :as circle]
[uxbox.ui.shapes.text :as text]
[uxbox.ui.shapes.line :as line]
[uxbox.util.geom :as geom]))
(defmethod uusc/render-shape :group ;; --- Helpers
[{:keys [items id dx dy rotation] :as shape} factory]
(declare group-component)
(defn render-component
[{:keys [type] :as shape}]
(case type
:group (group-component shape)
:text (text/text-component shape)
:line (line/line-component shape)
:icon (icon/icon-component shape)
:rect (rect/rect-component shape)
:circle (circle/circle-component shape)))
;; --- Group Component
(declare group-shape)
(defn- group-component-render
[own shape]
(let [{:keys [id x y width height group]} shape
selected (rum/react common/selected-shapes-l)
selected? (contains? selected id)
on-mouse-down #(common/on-mouse-down % shape selected)
on-mouse-up #(common/on-mouse-up % shape)]
(html
[:g.shape {:class (when selected? "selected")
:on-mouse-down on-mouse-down
:on-mouse-up on-mouse-up}
(group-shape shape render-component)])))
(def group-component
(mx/component
{:render group-component-render
:name "group-component"
:mixins [mx/static rum/reactive]}))
;; --- Group Shape
(defn- group-shape-render
[own {:keys [items id dx dy rotation] :as shape} factory]
(let [key (str "group-" id) (let [key (str "group-" id)
rfm (geom/transformation-matrix shape) rfm (geom/transformation-matrix shape)
attrs (merge {:id key :key key :transform (str rfm)} attrs (merge {:id key :key key :transform (str rfm)}
(uusc/extract-style-attrs shape) (attrs/extract-style-attrs shape)
(uusc/make-debug-attrs shape)) (attrs/make-debug-attrs shape))
shapes-by-id (get @st/state :shapes-by-id)] shapes-by-id (get @st/state :shapes-by-id)
xf (comp
(map #(get shapes-by-id %))
(remove :hidden)
(map factory))]
(html (html
[:g attrs [:g attrs
(for [item (->> items (for [item (reverse (into [] xf items))]
(map #(get shapes-by-id %)) (rum/with-key item (str (:id item))))])))
(remove :hidden)
(reverse))]
(-> (factory (:id item))
(rum/with-key (str (:id item)))))])))

View file

@ -1,91 +1,70 @@
;; 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) 2016 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.ui.shapes.icon (ns uxbox.ui.shapes.icon
(:require [sablono.core :refer-macros [html]] (:require [sablono.core :refer-macros [html]]
[cuerdas.core :as str]
[rum.core :as rum] [rum.core :as rum]
[lentes.core :as l]
[uxbox.rstore :as rs]
[uxbox.state :as st]
[uxbox.data.workspace :as dw]
[uxbox.data.shapes :as uds]
[uxbox.ui.core :as uuc]
[uxbox.ui.mixins :as mx] [uxbox.ui.mixins :as mx]
[uxbox.ui.keyboard :as kbd] [uxbox.ui.shapes.common :as common]
[uxbox.ui.shapes.core :as uusc] [uxbox.ui.shapes.attrs :as attrs]
[uxbox.util.geom :as geom] [uxbox.util.geom :as geom]))
[uxbox.util.dom :as dom]))
;; --- Icon Component ;; --- Icon Component
(defn on-mouse-down (declare icon-shape)
[event {:keys [id group] :as shape} selected]
(let [selected? (contains? selected id)
drawing? @uusc/drawing-state-l]
(when-not (:blocked shape)
(cond
(or drawing?
(and group (:locked (geom/resolve-parent shape))))
nil
(and (not selected?) (empty? selected)) (defn- icon-component-render
(do
(dom/stop-propagation event)
(rs/emit! (uds/select-shape id))
(uuc/acquire-action! "ui.shape.move"))
(and (not selected?) (not (empty? selected)))
(do
(dom/stop-propagation event)
(if (kbd/shift? event)
(rs/emit! (uds/select-shape id))
(do
(rs/emit! (uds/deselect-all)
(uds/select-shape id))
(uuc/acquire-action! "ui.shape.move"))))
:else
(do
(dom/stop-propagation event)
(uuc/acquire-action! "ui.shape.move"))))))
(defn on-mouse-up
[event {:keys [id group] :as shape}]
(cond
(and group (:locked (geom/resolve-parent shape)))
nil
:else
(do
(dom/stop-propagation event)
(uuc/release-action! "ui.shape"))))
(defmethod uusc/render-component :default ;; :icon
[own shape] [own shape]
(let [{:keys [id x y width height group]} shape (let [{:keys [id x y width height group]} shape
selected (rum/react uusc/selected-shapes-l) selected (rum/react common/selected-shapes-l)
selected? (contains? selected id) selected? (contains? selected id)
on-mouse-down #(on-mouse-down % shape selected) on-mouse-down #(common/on-mouse-down % shape selected)
on-mouse-up #(on-mouse-up % shape)] on-mouse-up #(common/on-mouse-up % shape)]
(html (html
[:g.shape {:class (when selected? "selected") [:g.shape {:class (when selected? "selected")
:on-mouse-down on-mouse-down :on-mouse-down on-mouse-down
:on-mouse-up on-mouse-up} :on-mouse-up on-mouse-up}
(uusc/render-shape shape #(uusc/shape %))]))) (icon-shape shape identity)])))
;; --- Shape & Shape Svg
(defmethod uusc/render-shape :icon (def icon-component
[{:keys [data id] :as shape} _] (mx/component
{:render icon-component-render
:name "icon-component"
:mixins [mx/static rum/reactive]}))
;; --- Icon Shape
(defn- icon-shape-render
[own {:keys [data id] :as shape} factory]
(let [key (str id) (let [key (str id)
rfm (geom/transformation-matrix shape) rfm (geom/transformation-matrix shape)
attrs (merge {:id key :key key :transform (str rfm)} attrs (merge {:id key :key key :transform (str rfm)}
(uusc/extract-style-attrs shape) (attrs/extract-style-attrs shape)
(uusc/make-debug-attrs shape))] (attrs/make-debug-attrs shape))]
(html (html
[:g attrs data]))) [:g attrs data])))
(defmethod uusc/render-shape-svg :icon (def icon-shape
[{:keys [data id view-box] :as shape}] (mx/component
{:render icon-shape-render
:name "icon-shape"
:mixins [mx/static]}))
;; --- Icon SVG
(defn- icon-svg-render
[own {:keys [data id view-box] :as shape}]
(let [key (str "icon-svg-" id) (let [key (str "icon-svg-" id)
view-box (apply str (interpose " " view-box)) view-box (apply str (interpose " " view-box))
props {:view-box view-box :id key :key key}] props {:view-box view-box :id key :key key}]
(html (html
[:svg props data]))) [:svg props data])))
(def icon-svg
(mx/component
{:render icon-svg-render
:name "icon-svg"
:mixins [mx/static]}))

View file

@ -1,22 +1,54 @@
;; 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) 2016 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.ui.shapes.line (ns uxbox.ui.shapes.line
(:require [sablono.core :refer-macros [html]] (:require [sablono.core :refer-macros [html]]
[cuerdas.core :as str]
[rum.core :as rum] [rum.core :as rum]
[lentes.core :as l] [uxbox.ui.mixins :as mx]
[uxbox.rstore :as rs] [uxbox.ui.shapes.common :as common]
[uxbox.state :as st] [uxbox.ui.shapes.attrs :as attrs]
[uxbox.data.workspace :as dw] [uxbox.util.geom :as geom]))
[uxbox.ui.core :as uuc]
[uxbox.ui.keyboard :as kbd]
[uxbox.ui.shapes.core :as uusc]
[uxbox.util.dom :as dom]))
(defmethod uusc/render-shape :line ;; --- Line Component
[{:keys [id x1 y1 x2 y2] :as shape}]
(declare line-shape)
(defn- line-component-render
[own shape]
(let [{:keys [id x y width height group]} shape
selected (rum/react common/selected-shapes-l)
selected? (contains? selected id)
on-mouse-down #(common/on-mouse-down % shape selected)
on-mouse-up #(common/on-mouse-up % shape)]
(html
[:g.shape {:class (when selected? "selected")
:on-mouse-down on-mouse-down
:on-mouse-up on-mouse-up}
(line-shape shape identity)])))
(def line-component
(mx/component
{:render line-component-render
:name "line-component"
:mixins [mx/static rum/reactive]}))
;; --- Line Shape
(defn- line-shape-render
[own {:keys [id x1 y1 x2 y2] :as shape}]
(let [key (str id) (let [key (str id)
props (select-keys shape [:x1 :x2 :y2 :y1]) props (select-keys shape [:x1 :x2 :y2 :y1])
attrs (-> (uusc/extract-style-attrs shape) attrs (-> (attrs/extract-style-attrs shape)
(merge {:id key :key key}) (merge {:id key :key key})
(merge props))] (merge props))]
(html (html
[:line attrs]))) [:line attrs])))
(def line-shape
(mx/component
{:render line-shape-render
:name "line-shape"
:mixins [mx/static]}))

View file

@ -1,25 +1,56 @@
;; 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) 2016 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.ui.shapes.rect (ns uxbox.ui.shapes.rect
(:require [sablono.core :refer-macros [html]] (:require [sablono.core :refer-macros [html]]
[cuerdas.core :as str]
[rum.core :as rum] [rum.core :as rum]
[lentes.core :as l] [uxbox.ui.shapes.common :as common]
[uxbox.rstore :as rs] [uxbox.ui.shapes.attrs :as attrs]
[uxbox.state :as st] [uxbox.ui.mixins :as mx]
[uxbox.data.workspace :as dw]
[uxbox.ui.core :as uuc]
[uxbox.ui.keyboard :as kbd]
[uxbox.ui.shapes.core :as uusc]
[uxbox.util.geom :as geom] [uxbox.util.geom :as geom]
[uxbox.util.dom :as dom])) [uxbox.util.dom :as dom]))
(defmethod uusc/render-shape :rect ;; --- Rect Component
[{:keys [id x1 y1 x2 y2] :as shape}]
(declare rect-shape)
(defn- rect-component-render
[own shape]
(let [{:keys [id x y width height group]} shape
selected (rum/react common/selected-shapes-l)
selected? (contains? selected id)
on-mouse-down #(common/on-mouse-down % shape selected)
on-mouse-up #(common/on-mouse-up % shape)]
(html
[:g.shape {:class (when selected? "selected")
:on-mouse-down on-mouse-down
:on-mouse-up on-mouse-up}
(rect-shape shape identity)])))
(def rect-component
(mx/component
{:render rect-component-render
:name "rect-component"
:mixins [mx/static rum/reactive]}))
;; --- Rect Shape
(defn- rect-shape-render
[own {:keys [id x1 y1 x2 y2] :as shape}]
(let [key (str id) (let [key (str id)
rfm (geom/transformation-matrix shape) rfm (geom/transformation-matrix shape)
size (geom/size shape) size (geom/size shape)
props {:x x1 :y y1 :id key :key key :transform (str rfm)} props {:x x1 :y y1 :id key :key key :transform (str rfm)}
attrs (-> (uusc/extract-style-attrs shape) attrs (-> (attrs/extract-style-attrs shape)
(merge props size))] (merge props size))]
(html (html
[:rect attrs]))) [:rect attrs])))
(def rect-shape
(mx/component
{:render rect-shape-render
:name "rect-shape"
:mixins [mx/static]}))

View file

@ -1,3 +1,9 @@
;; 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) 2016 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.ui.shapes.text (ns uxbox.ui.shapes.text
(:require [sablono.core :refer-macros [html]] (:require [sablono.core :refer-macros [html]]
[cuerdas.core :as str] [cuerdas.core :as str]
@ -7,22 +13,25 @@
[uxbox.rstore :as rs] [uxbox.rstore :as rs]
[uxbox.state :as st] [uxbox.state :as st]
[uxbox.data.shapes :as uds] [uxbox.data.shapes :as uds]
[uxbox.data.workspace :as dw] [uxbox.ui.core :as ui]
[uxbox.ui.core :as uuc]
[uxbox.ui.mixins :as mx] [uxbox.ui.mixins :as mx]
[uxbox.ui.keyboard :as kbd] [uxbox.ui.keyboard :as kbd]
[uxbox.ui.shapes.core :as uusc] [uxbox.ui.shapes.common :as common]
[uxbox.ui.shapes.icon :as uusi] [uxbox.ui.shapes.attrs :as attrs]
[uxbox.util.geom :as geom] [uxbox.util.geom :as geom]
[uxbox.util.color :as color] [uxbox.util.color :as color]
[uxbox.util.dom :as dom]) [uxbox.util.dom :as dom])
(:import goog.events.EventType)) (:import goog.events.EventType))
;; --- Events
;; FIXME: try to reuse the common.
(defn on-mouse-down (defn on-mouse-down
[event own {:keys [id group] :as shape} selected] [event own {:keys [id group] :as shape} selected]
(let [selected? (contains? selected id) (let [selected? (contains? selected id)
local (:rum/local own) local (:rum/local own)
drawing? @uusc/drawing-state-l] drawing? @common/drawing-state-l]
(when-not (:blocked shape) (when-not (:blocked shape)
(cond (cond
(or drawing? (or drawing?
@ -33,7 +42,7 @@
(and (not selected?) (empty? selected)) (and (not selected?) (empty? selected))
(do (do
(dom/stop-propagation event) (dom/stop-propagation event)
(uuc/acquire-action! "ui.shape.move") (ui/acquire-action! "ui.shape.move")
(rs/emit! (uds/select-shape id))) (rs/emit! (uds/select-shape id)))
(and (not selected?) (not (empty? selected))) (and (not selected?) (not (empty? selected)))
@ -47,7 +56,7 @@
:else :else
(do (do
(dom/stop-propagation event) (dom/stop-propagation event)
(uuc/acquire-action! "ui.shape.move")))))) (ui/acquire-action! "ui.shape.move"))))))
(defn on-mouse-up (defn on-mouse-up
[event {:keys [id group] :as shape}] [event {:keys [id group] :as shape}]
@ -58,7 +67,9 @@
:else :else
(do (do
(dom/stop-propagation event) (dom/stop-propagation event)
(uuc/release-action! "ui.shape")))) (ui/release-action! "ui.shape"))))
;; --- Text Component
(defn- text-component-did-mount (defn- text-component-did-mount
[own] [own]
@ -66,14 +77,14 @@
(let [container (mx/get-ref-dom own "container") (let [container (mx/get-ref-dom own "container")
local (:rum/local own)] local (:rum/local own)]
(swap! local assoc :edition true) (swap! local assoc :edition true)
(uuc/acquire-action! "ui.text.edit") (ui/acquire-action! "ui.text.edit")
(set! (.-contentEditable container) true) (set! (.-contentEditable container) true)
(.setAttribute container "contenteditable" "true") (.setAttribute container "contenteditable" "true")
(.focus container))) (.focus container)))
(on-blur [ev] (on-blur [ev]
(let [container (mx/get-ref-dom own "container") (let [container (mx/get-ref-dom own "container")
local (:rum/local own)] local (:rum/local own)]
(uuc/release-action! "ui.text.edit") (ui/release-action! "ui.text.edit")
(swap! local assoc :edition false) (swap! local assoc :edition false)
(set! (.-contentEditable container) false) (set! (.-contentEditable container) false)
(.removeAttribute container "contenteditable"))) (.removeAttribute container "contenteditable")))
@ -81,11 +92,11 @@
(let [content (dom/event->inner-text ev) (let [content (dom/event->inner-text ev)
sid (:id (first (:rum/props own)))] sid (:id (first (:rum/props own)))]
(rs/emit! (uds/update-text sid {:content content}))))] (rs/emit! (uds/update-text sid {:content content}))))]
(let [dom (mx/get-ref-dom own "main") (let [main-dom (mx/get-ref-dom own "main")
dom2 (mx/get-ref-dom own "container") cntr-dom (mx/get-ref-dom own "container")
key1 (events/listen dom EventType.DBLCLICK on-double-click) key1 (events/listen main-dom EventType.DBLCLICK on-double-click)
key2 (events/listen dom2 EventType.BLUR on-blur) key2 (events/listen cntr-dom EventType.BLUR on-blur)
key3 (events/listen dom2 EventType.INPUT on-input)] key3 (events/listen cntr-dom EventType.INPUT on-input)]
(assoc own ::key1 key1 ::key2 key2 ::key3 key3)))) (assoc own ::key1 key1 ::key2 key2 ::key3 key3))))
(defn- text-component-will-unmount (defn- text-component-will-unmount
@ -103,22 +114,26 @@
(let [data (select-keys old-own [::key1 ::key2 ::key3])] (let [data (select-keys old-own [::key1 ::key2 ::key3])]
(merge own data))) (merge own data)))
(declare text-shape)
(declare text-shape-render)
(defn- text-component-render (defn- text-component-render
[own shape] [own shape]
(let [{:keys [id x1 y1 content group]} shape (let [{:keys [id x1 y1 content group]} shape
selected (rum/react uusc/selected-shapes-l) selected (rum/react common/selected-shapes-l)
selected? (and (contains? selected id) (= (count selected) 1)) selected? (and (contains? selected id) (= (count selected) 1))
on-mouse-down #(on-mouse-down % own shape selected) on-mouse-down #(on-mouse-down % own shape selected)
on-mouse-up #(on-mouse-up % shape) on-mouse-up #(on-mouse-up % shape)
local (:rum/local own)] local (:rum/local own)
shape (assoc shape :editing? (:edition @local false))]
(html (html
[:g.shape {:class (when selected? "selected") [:g.shape {:class (when selected? "selected")
:ref "main" :ref "main"
:on-mouse-down on-mouse-down :on-mouse-down on-mouse-down
:on-mouse-up on-mouse-up} :on-mouse-up on-mouse-up}
(uusc/render-shape (assoc shape :editing? (:edition @local false)) nil)]))) (text-shape-render own shape)])))
(def ^:const text-component (def text-component
(mx/component (mx/component
{:render text-component-render {:render text-component-render
:name "text-componet" :name "text-componet"
@ -127,21 +142,19 @@
:transfer-state text-component-transfer-state :transfer-state text-component-transfer-state
:mixins [mx/static rum/reactive (mx/local)]})) :mixins [mx/static rum/reactive (mx/local)]}))
(defmethod uusc/render-component :text ;; --- Test Shape
[own shape]
(text-component shape))
(def ^:const +style-attrs+ [:font-size])
(def ^:const +select-rect-attrs+ (def ^:const +select-rect-attrs+
{:stroke-dasharray "5,5" {:stroke-dasharray "5,5"
:style {:stroke "#333" :fill "transparent" :style {:stroke "#333" :fill "transparent"
:stroke-opacity "0.4"}}) :stroke-opacity "0.4"}})
(def ^:const +style-attrs+ (defn- make-style
[:font-size]) [{:keys [font fill opacity]
:or {fill "#000000" opacity 1}}]
(defn- build-style (let [{:keys [family weight style size align
[{:keys [font fill opacity] :or {fill "#000000" opacity 1}}] line-height letter-spacing]
(let [{:keys [family weight style size align line-height letter-spacing]
:or {family "sourcesanspro" :or {family "sourcesanspro"
weight "normal" weight "normal"
style "normal" style "normal"
@ -162,15 +175,15 @@
(when line-height {:lineHeight line-height}) (when line-height {:lineHeight line-height})
(when letter-spacing {:letterSpacing letter-spacing})))) (when letter-spacing {:letterSpacing letter-spacing}))))
(defmethod uusc/render-shape :text (defn- text-shape-render
[{:keys [id x1 y1 x2 y2 content drawing? editing?] :as shape}] [own {:keys [id x1 y1 x2 y2 content drawing? editing?] :as shape}]
(let [key (str id) (let [key (str id)
rfm (geom/transformation-matrix shape) rfm (geom/transformation-matrix shape)
size (geom/size shape) size (geom/size shape)
props {:x x1 :y y1 props {:x x1 :y y1
:transform (str rfm)} :transform (str rfm)}
attrs (merge props size) attrs (merge props size)
style (build-style shape)] style (make-style shape)]
(html (html
[:g [:g
(if (or drawing? editing?) (if (or drawing? editing?)
@ -179,3 +192,8 @@
[:foreignObject attrs [:foreignObject attrs
[:p {:ref "container" :style style} content]]]))) [:p {:ref "container" :style style} content]]])))
;; (def text-shape
;; (mx/component
;; {:render text-shape-render
;; :name "text-shape"
;; :mixins [mx/static]}))

View file

@ -16,7 +16,7 @@
[uxbox.data.workspace :as udw] [uxbox.data.workspace :as udw]
[uxbox.data.shapes :as uds] [uxbox.data.shapes :as uds]
[uxbox.ui.core :as uuc] [uxbox.ui.core :as uuc]
[uxbox.ui.shapes.core :as uusc] [uxbox.ui.shapes :as shapes]
[uxbox.ui.workspace.base :as wb] [uxbox.ui.workspace.base :as wb]
[uxbox.ui.mixins :as mx] [uxbox.ui.mixins :as mx]
[uxbox.util.geom :as geom] [uxbox.util.geom :as geom]
@ -39,7 +39,7 @@
(when (and shape position) (when (and shape position)
(-> (assoc shape :drawing? true) (-> (assoc shape :drawing? true)
(geom/resize position) (geom/resize position)
(uusc/render-shape identity))))) (shapes/render-component)))))
(defn- draw-area-will-mount (defn- draw-area-will-mount
[own] [own]

View file

@ -12,11 +12,20 @@
[lentes.core :as l] [lentes.core :as l]
[uxbox.state :as st] [uxbox.state :as st]
[uxbox.ui.mixins :as mx] [uxbox.ui.mixins :as mx]
[uxbox.ui.shapes.core :as uusc]
[uxbox.ui.core :as uuc] [uxbox.ui.core :as uuc]
[uxbox.util.geom :as geom] [uxbox.util.geom :as geom]
[uxbox.util.dom :as dom])) [uxbox.util.dom :as dom]))
;; --- Constants
(def ^:const +circle-props+
{:r 6
:style {:fillOpacity "1"
:strokeWidth "1px"
:vectorEffect "non-scaling-stroke"}
:fill "#31e6e0"
:stroke "#28c4d4"})
;; --- Lenses ;; --- Lenses
(def ^:const selected-shapes-l (def ^:const selected-shapes-l
@ -53,49 +62,49 @@
[:rect.main {:x x :y y :width width :height height :stroke-dasharray "5,5" [:rect.main {:x x :y y :width width :height height :stroke-dasharray "5,5"
:style {:stroke "#333" :fill "transparent" :stroke-opacity "1"}}] :style {:stroke "#333" :fill "transparent" :stroke-opacity "1"}}]
[:circle.top [:circle.top
(merge uusc/+circle-props+ (merge +circle-props+
{:on-mouse-up #(on-mouse-up 5 %) {:on-mouse-up #(on-mouse-up 5 %)
:on-mouse-down #(on-mouse-down 5 %) :on-mouse-down #(on-mouse-down 5 %)
:cx (+ x (/ width 2)) :cx (+ x (/ width 2))
:cy (- y 2)})] :cy (- y 2)})]
[:circle.right [:circle.right
(merge uusc/+circle-props+ (merge +circle-props+
{:on-mouse-up #(on-mouse-up 6 %) {:on-mouse-up #(on-mouse-up 6 %)
:on-mouse-down #(on-mouse-down 6 %) :on-mouse-down #(on-mouse-down 6 %)
:cy (+ y (/ height 2)) :cy (+ y (/ height 2))
:cx (+ x width 1)})] :cx (+ x width 1)})]
[:circle.bottom [:circle.bottom
(merge uusc/+circle-props+ (merge +circle-props+
{:on-mouse-up #(on-mouse-up 7 %) {:on-mouse-up #(on-mouse-up 7 %)
:on-mouse-down #(on-mouse-down 7 %) :on-mouse-down #(on-mouse-down 7 %)
:cx (+ x (/ width 2)) :cx (+ x (/ width 2))
:cy (+ y height 2)})] :cy (+ y height 2)})]
[:circle.left [:circle.left
(merge uusc/+circle-props+ (merge +circle-props+
{:on-mouse-up #(on-mouse-up 8 %) {:on-mouse-up #(on-mouse-up 8 %)
:on-mouse-down #(on-mouse-down 8 %) :on-mouse-down #(on-mouse-down 8 %)
:cy (+ y (/ height 2)) :cy (+ y (/ height 2))
:cx (- x 3)})] :cx (- x 3)})]
[:circle.top-left [:circle.top-left
(merge uusc/+circle-props+ (merge +circle-props+
{:on-mouse-up #(on-mouse-up 1 %) {:on-mouse-up #(on-mouse-up 1 %)
:on-mouse-down #(on-mouse-down 1 %) :on-mouse-down #(on-mouse-down 1 %)
:cx x :cx x
:cy y})] :cy y})]
[:circle.top-right [:circle.top-right
(merge uusc/+circle-props+ (merge +circle-props+
{:on-mouse-up #(on-mouse-up 2 %) {:on-mouse-up #(on-mouse-up 2 %)
:on-mouse-down #(on-mouse-down 2 %) :on-mouse-down #(on-mouse-down 2 %)
:cx (+ x width) :cx (+ x width)
:cy y})] :cy y})]
[:circle.bottom-left [:circle.bottom-left
(merge uusc/+circle-props+ (merge +circle-props+
{:on-mouse-up #(on-mouse-up 3 %) {:on-mouse-up #(on-mouse-up 3 %)
:on-mouse-down #(on-mouse-down 3 %) :on-mouse-down #(on-mouse-down 3 %)
:cx x :cx x
:cy (+ y height)})] :cy (+ y height)})]
[:circle.bottom-right [:circle.bottom-right
(merge uusc/+circle-props+ (merge +circle-props+
{:on-mouse-up #(on-mouse-up 4 %) {:on-mouse-up #(on-mouse-up 4 %)
:on-mouse-down #(on-mouse-down 4 %) :on-mouse-down #(on-mouse-down 4 %)
:cx (+ x width) :cx (+ x width)

View file

@ -14,7 +14,7 @@
[uxbox.state :as st] [uxbox.state :as st]
[uxbox.library :as library] [uxbox.library :as library]
[uxbox.data.workspace :as dw] [uxbox.data.workspace :as dw]
[uxbox.ui.shapes.core :as uusc] [uxbox.ui.shapes.icon :as icon]
[uxbox.ui.workspace.base :as wb] [uxbox.ui.workspace.base :as wb]
[uxbox.ui.icons :as i] [uxbox.ui.icons :as i]
[uxbox.ui.mixins :as mx] [uxbox.ui.mixins :as mx]
@ -50,7 +50,7 @@
(defn- icon-wrapper-render (defn- icon-wrapper-render
[own icon] [own icon]
(uusc/render-shape-svg icon nil)) (icon/icon-svg icon))
(def ^:static ^:private icon-wrapper (def ^:static ^:private icon-wrapper
(mx/component (mx/component

View file

@ -18,7 +18,7 @@
[uxbox.util.data :refer (read-string classnames)] [uxbox.util.data :refer (read-string classnames)]
[uxbox.data.workspace :as udw] [uxbox.data.workspace :as udw]
[uxbox.data.shapes :as uds] [uxbox.data.shapes :as uds]
[uxbox.ui.shapes.core :as uusc] [uxbox.ui.shapes.icon :as icon]
[uxbox.ui.workspace.base :as wb] [uxbox.ui.workspace.base :as wb]
[uxbox.ui.icons :as i] [uxbox.ui.icons :as i]
[uxbox.ui.mixins :as mx] [uxbox.ui.mixins :as mx]
@ -94,7 +94,7 @@
(defn- element-icon (defn- element-icon
[item] [item]
(case (:type item) (case (:type item)
:icon (uusc/render-shape-svg item) :icon (icon/icon-svg item)
:line i/line :line i/line
:circle i/circle :circle i/circle
:rect i/box :rect i/box