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.lightbox :as udl]
[uxbox.ui.icons :as i]
[uxbox.ui.shapes.core :as uusc]
[uxbox.ui.shapes.icon :as icon]
[uxbox.ui.lightbox :as lbx]
[uxbox.ui.mixins :as mx]
[uxbox.ui.dashboard.header :refer (header)]
@ -111,7 +111,7 @@
[:div.dashboard-grid-row
(for [icon (:icons coll)]
[: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)]
#_[:div.project-th-actions
[:div.project-th-icon.edit i/pencil]

View file

@ -1,11 +1,31 @@
(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]
[uxbox.ui.shapes.line]
[uxbox.ui.shapes.circle]))
;; 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>
(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
(:require [sablono.core :refer-macros [html]]
[cuerdas.core :as str]
[rum.core :as rum]
[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.keyboard :as kbd]
[uxbox.ui.shapes.core :as uusc]
[uxbox.ui.shapes.icon :as uusi]
[uxbox.util.geom :as geom]
[uxbox.util.dom :as dom]))
[uxbox.ui.shapes.common :as common]
[uxbox.ui.shapes.attrs :as attrs]
[uxbox.util.geom :as geom]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Circle Component
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; --- Circle Component
(declare handlers)
(declare circle-shape)
;; (defmethod uusc/render-component :default ;; :icon
;; [own shape]
;; (let [{:keys [id x y width height group]} shape
;; selected (rum/react uusc/selected-shapes-l)
;; selected? (contains? selected id)
;; on-mouse-down #(uusi/on-mouse-down % shape selected)
;; on-mouse-up #(uusi/on-mouse-up % shape)]
;; (html
;; [:g.shape {:class (when selected? "selected")
;; :on-mouse-down on-mouse-down
;; :on-mouse-up on-mouse-up}
;; (uusc/render-shape shape #(uusc/shape %))
;; (when (and selected? (= (count selected) 1))
;; (handlers shape))])))
(defn- circle-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}
(circle-shape shape identity)])))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Circle Handlers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def circle-component
(mx/component
{:render circle-component-render
:name "circle-component"
:mixins [mx/static rum/reactive]}))
;; (defn- handlers-render
;; [own shape]
;; (letfn [(on-mouse-down [vid event]
;; (dom/stop-propagation event)
;; (uuc/acquire-action! "ui.shape.resize"
;; {:vid vid :shape (:id shape)}))
;; --- Circle Shape
;; (on-mouse-up [vid event]
;; (dom/stop-propagation event)
;; (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}]
(defn- circle-shape-render
[own {:keys [id] :as shape}]
(let [key (str id)
rfm (geom/transformation-matrix shape)
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 props))]
(html
[: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
(:require [sablono.core :refer-macros [html]]
[cuerdas.core :as str]
[rum.core :as rum]
[lentes.core :as l]
[uxbox.rstore :as rs]
[uxbox.state :as st]
[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.dom :as dom]))
[uxbox.ui.mixins :as mx]
[uxbox.ui.shapes.common :as common]
[uxbox.ui.shapes.attrs :as attrs]
[uxbox.ui.shapes.icon :as icon]
[uxbox.ui.shapes.rect :as rect]
[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
[{:keys [items id dx dy rotation] :as shape} factory]
;; --- Helpers
(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)
rfm (geom/transformation-matrix shape)
attrs (merge {:id key :key key :transform (str rfm)}
(uusc/extract-style-attrs shape)
(uusc/make-debug-attrs shape))
shapes-by-id (get @st/state :shapes-by-id)]
(attrs/extract-style-attrs shape)
(attrs/make-debug-attrs shape))
shapes-by-id (get @st/state :shapes-by-id)
xf (comp
(map #(get shapes-by-id %))
(remove :hidden)
(map factory))]
(html
[:g attrs
(for [item (->> items
(map #(get shapes-by-id %))
(remove :hidden)
(reverse))]
(-> (factory (:id item))
(rum/with-key (str (:id item)))))])))
(for [item (reverse (into [] xf items))]
(rum/with-key item (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
(:require [sablono.core :refer-macros [html]]
[cuerdas.core :as str]
[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.keyboard :as kbd]
[uxbox.ui.shapes.core :as uusc]
[uxbox.util.geom :as geom]
[uxbox.util.dom :as dom]))
[uxbox.ui.shapes.common :as common]
[uxbox.ui.shapes.attrs :as attrs]
[uxbox.util.geom :as geom]))
;; --- Icon Component
(defn on-mouse-down
[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
(declare icon-shape)
(and (not selected?) (empty? selected))
(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
(defn- icon-component-render
[own 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)
on-mouse-down #(on-mouse-down % shape selected)
on-mouse-up #(on-mouse-up % shape)]
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}
(uusc/render-shape shape #(uusc/shape %))])))
;; --- Shape & Shape Svg
(icon-shape shape identity)])))
(defmethod uusc/render-shape :icon
[{:keys [data id] :as shape} _]
(def icon-component
(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)
rfm (geom/transformation-matrix shape)
attrs (merge {:id key :key key :transform (str rfm)}
(uusc/extract-style-attrs shape)
(uusc/make-debug-attrs shape))]
(attrs/extract-style-attrs shape)
(attrs/make-debug-attrs shape))]
(html
[:g attrs data])))
(defmethod uusc/render-shape-svg :icon
[{:keys [data id view-box] :as shape}]
(def icon-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)
view-box (apply str (interpose " " view-box))
props {:view-box view-box :id key :key key}]
(html
[: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
(:require [sablono.core :refer-macros [html]]
[cuerdas.core :as str]
[rum.core :as rum]
[lentes.core :as l]
[uxbox.rstore :as rs]
[uxbox.state :as st]
[uxbox.data.workspace :as dw]
[uxbox.ui.core :as uuc]
[uxbox.ui.keyboard :as kbd]
[uxbox.ui.shapes.core :as uusc]
[uxbox.util.dom :as dom]))
[uxbox.ui.mixins :as mx]
[uxbox.ui.shapes.common :as common]
[uxbox.ui.shapes.attrs :as attrs]
[uxbox.util.geom :as geom]))
(defmethod uusc/render-shape :line
[{:keys [id x1 y1 x2 y2] :as shape}]
;; --- Line Component
(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)
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 props))]
(html
[: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
(:require [sablono.core :refer-macros [html]]
[cuerdas.core :as str]
[rum.core :as rum]
[lentes.core :as l]
[uxbox.rstore :as rs]
[uxbox.state :as st]
[uxbox.data.workspace :as dw]
[uxbox.ui.core :as uuc]
[uxbox.ui.keyboard :as kbd]
[uxbox.ui.shapes.core :as uusc]
[uxbox.ui.shapes.common :as common]
[uxbox.ui.shapes.attrs :as attrs]
[uxbox.ui.mixins :as mx]
[uxbox.util.geom :as geom]
[uxbox.util.dom :as dom]))
(defmethod uusc/render-shape :rect
[{:keys [id x1 y1 x2 y2] :as shape}]
;; --- Rect Component
(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)
rfm (geom/transformation-matrix shape)
size (geom/size shape)
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))]
(html
[: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
(:require [sablono.core :refer-macros [html]]
[cuerdas.core :as str]
@ -7,22 +13,25 @@
[uxbox.rstore :as rs]
[uxbox.state :as st]
[uxbox.data.shapes :as uds]
[uxbox.data.workspace :as dw]
[uxbox.ui.core :as uuc]
[uxbox.ui.core :as ui]
[uxbox.ui.mixins :as mx]
[uxbox.ui.keyboard :as kbd]
[uxbox.ui.shapes.core :as uusc]
[uxbox.ui.shapes.icon :as uusi]
[uxbox.ui.shapes.common :as common]
[uxbox.ui.shapes.attrs :as attrs]
[uxbox.util.geom :as geom]
[uxbox.util.color :as color]
[uxbox.util.dom :as dom])
(:import goog.events.EventType))
;; --- Events
;; FIXME: try to reuse the common.
(defn on-mouse-down
[event own {:keys [id group] :as shape} selected]
(let [selected? (contains? selected id)
local (:rum/local own)
drawing? @uusc/drawing-state-l]
drawing? @common/drawing-state-l]
(when-not (:blocked shape)
(cond
(or drawing?
@ -33,7 +42,7 @@
(and (not selected?) (empty? selected))
(do
(dom/stop-propagation event)
(uuc/acquire-action! "ui.shape.move")
(ui/acquire-action! "ui.shape.move")
(rs/emit! (uds/select-shape id)))
(and (not selected?) (not (empty? selected)))
@ -47,7 +56,7 @@
:else
(do
(dom/stop-propagation event)
(uuc/acquire-action! "ui.shape.move"))))))
(ui/acquire-action! "ui.shape.move"))))))
(defn on-mouse-up
[event {:keys [id group] :as shape}]
@ -58,7 +67,9 @@
:else
(do
(dom/stop-propagation event)
(uuc/release-action! "ui.shape"))))
(ui/release-action! "ui.shape"))))
;; --- Text Component
(defn- text-component-did-mount
[own]
@ -66,14 +77,14 @@
(let [container (mx/get-ref-dom own "container")
local (:rum/local own)]
(swap! local assoc :edition true)
(uuc/acquire-action! "ui.text.edit")
(ui/acquire-action! "ui.text.edit")
(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! "ui.text.edit")
(ui/release-action! "ui.text.edit")
(swap! local assoc :edition false)
(set! (.-contentEditable container) false)
(.removeAttribute container "contenteditable")))
@ -81,11 +92,11 @@
(let [content (dom/event->inner-text ev)
sid (:id (first (:rum/props own)))]
(rs/emit! (uds/update-text sid {:content content}))))]
(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)
key3 (events/listen dom2 EventType.INPUT on-input)]
(let [main-dom (mx/get-ref-dom own "main")
cntr-dom (mx/get-ref-dom own "container")
key1 (events/listen main-dom EventType.DBLCLICK on-double-click)
key2 (events/listen cntr-dom EventType.BLUR on-blur)
key3 (events/listen cntr-dom EventType.INPUT on-input)]
(assoc own ::key1 key1 ::key2 key2 ::key3 key3))))
(defn- text-component-will-unmount
@ -103,22 +114,26 @@
(let [data (select-keys old-own [::key1 ::key2 ::key3])]
(merge own data)))
(declare text-shape)
(declare text-shape-render)
(defn- text-component-render
[own 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))
on-mouse-down #(on-mouse-down % own shape selected)
on-mouse-up #(on-mouse-up % shape)
local (:rum/local own)]
local (:rum/local own)
shape (assoc shape :editing? (:edition @local false))]
(html
[:g.shape {:class (when selected? "selected")
:ref "main"
:on-mouse-down on-mouse-down
: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
{:render text-component-render
:name "text-componet"
@ -127,21 +142,19 @@
:transfer-state text-component-transfer-state
:mixins [mx/static rum/reactive (mx/local)]}))
(defmethod uusc/render-component :text
[own shape]
(text-component shape))
;; --- Test Shape
(def ^:const +style-attrs+ [:font-size])
(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 fill opacity] :or {fill "#000000" opacity 1}}]
(let [{:keys [family weight style size align line-height letter-spacing]
(defn- make-style
[{:keys [font fill opacity]
:or {fill "#000000" opacity 1}}]
(let [{:keys [family weight style size align
line-height letter-spacing]
:or {family "sourcesanspro"
weight "normal"
style "normal"
@ -162,15 +175,15 @@
(when line-height {:lineHeight line-height})
(when letter-spacing {:letterSpacing letter-spacing}))))
(defmethod uusc/render-shape :text
[{:keys [id x1 y1 x2 y2 content drawing? editing?] :as shape}]
(defn- text-shape-render
[own {:keys [id x1 y1 x2 y2 content drawing? editing?] :as shape}]
(let [key (str id)
rfm (geom/transformation-matrix shape)
size (geom/size shape)
props {:x x1 :y y1
:transform (str rfm)}
attrs (merge props size)
style (build-style shape)]
style (make-style shape)]
(html
[:g
(if (or drawing? editing?)
@ -179,3 +192,8 @@
[:foreignObject attrs
[: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.shapes :as uds]
[uxbox.ui.core :as uuc]
[uxbox.ui.shapes.core :as uusc]
[uxbox.ui.shapes :as shapes]
[uxbox.ui.workspace.base :as wb]
[uxbox.ui.mixins :as mx]
[uxbox.util.geom :as geom]
@ -39,7 +39,7 @@
(when (and shape position)
(-> (assoc shape :drawing? true)
(geom/resize position)
(uusc/render-shape identity)))))
(shapes/render-component)))))
(defn- draw-area-will-mount
[own]

View file

@ -12,11 +12,20 @@
[lentes.core :as l]
[uxbox.state :as st]
[uxbox.ui.mixins :as mx]
[uxbox.ui.shapes.core :as uusc]
[uxbox.ui.core :as uuc]
[uxbox.util.geom :as geom]
[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
(def ^:const selected-shapes-l
@ -53,49 +62,49 @@
[:rect.main {:x x :y y :width width :height height :stroke-dasharray "5,5"
:style {:stroke "#333" :fill "transparent" :stroke-opacity "1"}}]
[:circle.top
(merge uusc/+circle-props+
(merge +circle-props+
{:on-mouse-up #(on-mouse-up 5 %)
:on-mouse-down #(on-mouse-down 5 %)
:cx (+ x (/ width 2))
:cy (- y 2)})]
[:circle.right
(merge uusc/+circle-props+
(merge +circle-props+
{:on-mouse-up #(on-mouse-up 6 %)
:on-mouse-down #(on-mouse-down 6 %)
:cy (+ y (/ height 2))
:cx (+ x width 1)})]
[:circle.bottom
(merge uusc/+circle-props+
(merge +circle-props+
{:on-mouse-up #(on-mouse-up 7 %)
:on-mouse-down #(on-mouse-down 7 %)
:cx (+ x (/ width 2))
:cy (+ y height 2)})]
[:circle.left
(merge uusc/+circle-props+
(merge +circle-props+
{:on-mouse-up #(on-mouse-up 8 %)
:on-mouse-down #(on-mouse-down 8 %)
:cy (+ y (/ height 2))
:cx (- x 3)})]
[:circle.top-left
(merge uusc/+circle-props+
(merge +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+
(merge +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+
(merge +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+
(merge +circle-props+
{:on-mouse-up #(on-mouse-up 4 %)
:on-mouse-down #(on-mouse-down 4 %)
:cx (+ x width)

View file

@ -14,7 +14,7 @@
[uxbox.state :as st]
[uxbox.library :as library]
[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.icons :as i]
[uxbox.ui.mixins :as mx]
@ -50,7 +50,7 @@
(defn- icon-wrapper-render
[own icon]
(uusc/render-shape-svg icon nil))
(icon/icon-svg icon))
(def ^:static ^:private icon-wrapper
(mx/component

View file

@ -18,7 +18,7 @@
[uxbox.util.data :refer (read-string classnames)]
[uxbox.data.workspace :as udw]
[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.icons :as i]
[uxbox.ui.mixins :as mx]
@ -94,7 +94,7 @@
(defn- element-icon
[item]
(case (:type item)
:icon (uusc/render-shape-svg item)
:icon (icon/icon-svg item)
:line i/line
:circle i/circle
:rect i/box