diff --git a/src/uxbox/ui/dashboard/icons.cljs b/src/uxbox/ui/dashboard/icons.cljs index 777c7acce4..35d1cb4480 100644 --- a/src/uxbox/ui/dashboard/icons.cljs +++ b/src/uxbox/ui/dashboard/icons.cljs @@ -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] diff --git a/src/uxbox/ui/shapes.cljs b/src/uxbox/ui/shapes.cljs index e45178acff..0a3f5091fe 100644 --- a/src/uxbox/ui/shapes.cljs +++ b/src/uxbox/ui/shapes.cljs @@ -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 -(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]})) diff --git a/src/uxbox/ui/shapes/attrs.cljs b/src/uxbox/ui/shapes/attrs.cljs new file mode 100644 index 0000000000..e0fb350b4a --- /dev/null +++ b/src/uxbox/ui/shapes/attrs.cljs @@ -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 + +(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))) diff --git a/src/uxbox/ui/shapes/circle.cljs b/src/uxbox/ui/shapes/circle.cljs index 0f2d830794..cff21f867a 100644 --- a/src/uxbox/ui/shapes/circle.cljs +++ b/src/uxbox/ui/shapes/circle.cljs @@ -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 + (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]})) diff --git a/src/uxbox/ui/shapes/common.cljs b/src/uxbox/ui/shapes/common.cljs new file mode 100644 index 0000000000..5ca6fd93ac --- /dev/null +++ b/src/uxbox/ui/shapes/common.cljs @@ -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 + +(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")))) + diff --git a/src/uxbox/ui/shapes/core.cljs b/src/uxbox/ui/shapes/core.cljs deleted file mode 100644 index 900813cf08..0000000000 --- a/src/uxbox/ui/shapes/core.cljs +++ /dev/null @@ -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))) diff --git a/src/uxbox/ui/shapes/group.cljs b/src/uxbox/ui/shapes/group.cljs index a1fae973a3..e2b114d13b 100644 --- a/src/uxbox/ui/shapes/group.cljs +++ b/src/uxbox/ui/shapes/group.cljs @@ -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 + (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))))]))) diff --git a/src/uxbox/ui/shapes/icon.cljs b/src/uxbox/ui/shapes/icon.cljs index d161755c15..f7ca8a648d 100644 --- a/src/uxbox/ui/shapes/icon.cljs +++ b/src/uxbox/ui/shapes/icon.cljs @@ -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 + (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]})) diff --git a/src/uxbox/ui/shapes/line.cljs b/src/uxbox/ui/shapes/line.cljs index cec16ca281..44d7f91b63 100644 --- a/src/uxbox/ui/shapes/line.cljs +++ b/src/uxbox/ui/shapes/line.cljs @@ -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 + (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]})) diff --git a/src/uxbox/ui/shapes/rect.cljs b/src/uxbox/ui/shapes/rect.cljs index a3157434e3..de66056ac6 100644 --- a/src/uxbox/ui/shapes/rect.cljs +++ b/src/uxbox/ui/shapes/rect.cljs @@ -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 + (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]})) diff --git a/src/uxbox/ui/shapes/text.cljs b/src/uxbox/ui/shapes/text.cljs index 30c983faa4..dc4543cbc3 100644 --- a/src/uxbox/ui/shapes/text.cljs +++ b/src/uxbox/ui/shapes/text.cljs @@ -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 + (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]})) diff --git a/src/uxbox/ui/workspace/drawarea.cljs b/src/uxbox/ui/workspace/drawarea.cljs index 75f0da1fa9..9e3fe881de 100644 --- a/src/uxbox/ui/workspace/drawarea.cljs +++ b/src/uxbox/ui/workspace/drawarea.cljs @@ -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] diff --git a/src/uxbox/ui/workspace/selection.cljs b/src/uxbox/ui/workspace/selection.cljs index 95481f6fae..3c09d01f32 100644 --- a/src/uxbox/ui/workspace/selection.cljs +++ b/src/uxbox/ui/workspace/selection.cljs @@ -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) diff --git a/src/uxbox/ui/workspace/sidebar/icons.cljs b/src/uxbox/ui/workspace/sidebar/icons.cljs index 27a19087f5..7e57552aeb 100644 --- a/src/uxbox/ui/workspace/sidebar/icons.cljs +++ b/src/uxbox/ui/workspace/sidebar/icons.cljs @@ -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 diff --git a/src/uxbox/ui/workspace/sidebar/layers.cljs b/src/uxbox/ui/workspace/sidebar/layers.cljs index df2a678056..21d1fe940b 100644 --- a/src/uxbox/ui/workspace/sidebar/layers.cljs +++ b/src/uxbox/ui/workspace/sidebar/layers.cljs @@ -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