diff --git a/src/uxbox/data/workspace.cljs b/src/uxbox/data/workspace.cljs index a091a7cc1..ab88c2923 100644 --- a/src/uxbox/data/workspace.cljs +++ b/src/uxbox/data/workspace.cljs @@ -194,13 +194,14 @@ instread final point of coordinates. WARN: only works with shapes that works - with height and width such are" + with height and width such are ::rect" [sid {:keys [width height] :as opts}] (sc/validate! +shape-size-schema+ opts) (reify rs/UpdateEvent (-apply-update [_ state] - (let [size {:width width :height height}] + (let [shape (get-in state [:shapes-by-id sid]) + size (merge (sh/-size shape) opts)] (update-in state [:shapes-by-id sid] sh/-resize' size))))) (defn update-position @@ -210,7 +211,7 @@ (reify rs/UpdateEvent (-apply-update [_ state] - (update-in state [:shapes-by-id sid] sh/-move' [x y])))) + (update-in state [:shapes-by-id sid] sh/-move' opts)))) (defn update-fill-attrs [sid {:keys [color opacity] :as opts}] diff --git a/src/uxbox/shapes.cljs b/src/uxbox/shapes.cljs index 3c99cac29..5764a0fa1 100644 --- a/src/uxbox/shapes.cljs +++ b/src/uxbox/shapes.cljs @@ -1,5 +1,6 @@ (ns uxbox.shapes - (:require [uxbox.util.matrix :as mtx] + (:require [uxbox.util.geom.matrix :as gmt] + [uxbox.util.geom.point :as gpt] [uxbox.util.math :as mth] [uxbox.state :as st])) @@ -54,6 +55,10 @@ dispatch-by-type :hierarchy #'+hierarchy+) +(defmulti -size + dispatch-by-type + :hierarchy #'+hierarchy+) + (defmulti -rotate dispatch-by-type :hierarchy #'+hierarchy+) @@ -75,6 +80,10 @@ dispatch-by-type :hierarchy #'+hierarchy+) +(defmulti -transformation + dispatch-by-type + :hierarchy #'+hierarchy+) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Implementation ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -84,10 +93,12 @@ (defmethod -initialize ::shape [shape {:keys [x1 y1 x2 y2]}] (assoc shape - :x x1 - :y y1 - :width (- x2 x1) - :height (- y2 y1))) + :x1 x1 + :y1 y1 + :x2 x2 + :y2 y2)) + ;; :width (- x2 x1) + ;; :height (- y2 y1))) (defmethod -initialize :builtin/group [shape {:keys [x1 y1 x2 y2] :as props}] @@ -103,53 +114,34 @@ (defmethod -initialize :builtin/circle [shape {:keys [x1 y1 x2 y2]}] - (let [width (- x2 x1) - height (- y2 y1) + (assoc shape + :cx x1 + :cy y1 + :rx (mth/abs (- x2 x1)) + :ry (mth/abs (- y2 y1)))) - rx (/ width 2) - ry (/ height 2) - - cx (+ x1 (/ width 2)) - cy (+ y1 (/ height 2))] - (assoc shape :rx rx :ry ry :cx cx :cy cy))) - -;; Resize +;; FIXME: lock mode (defmethod -resize :builtin/line [shape {:keys [x y] :as pos}] - (assoc shape - :x2 x :y2 x)) + (assoc shape :x2 x :y2 y)) (defmethod -resize :builtin/circle - [{:keys [cx cy rx ry] :as shape} {:keys [x y lock] :as pos}] - (let [x1 (- cx rx) - y1 (- cy ry) - x2 x - y2 y + [shape {:keys [x y lock] :as pos}] + (let [cx (:cx shape) + cy (:cy shape) - width (- x2 x1) - height (if lock - width - (- y2 y1)) - - rx (/ width 2) - ry (/ height 2) - - cx (+ x1 (/ width 2)) - cy (+ y1 (/ height 2))] + rx (mth/abs (- x cx)) + ry (mth/abs (- y cy))] (if lock - (assoc shape :rx rx :ry ry :cx cx :cy cy) - (assoc shape :rx rx :ry ry :cx cx :cy cy)))) + (assoc shape :rx rx :ry rx) + (assoc shape :rx rx :ry ry)))) (defmethod -resize :builtin/rect [shape {:keys [x y lock] :as pos}] (if lock - (assoc shape - :width (- x (:x shape)) - :height (- x (:x shape))) - (assoc shape - :width (- x (:x shape)) - :height (- y (:y shape))))) + (assoc shape :x2 x :y2 x) + (assoc shape :x2 x :y2 y))) (defmethod -resize :default [shape _] @@ -157,21 +149,38 @@ (defmethod -resize' ::rect [shape {:keys [width height] :as size}] - (merge shape - (when width {:width width}) - (when height {:height height}))) + (let [x1 (:x1 shape) + y1 (:y1 shape)] + (assoc shape + :x2 (+ x1 width) + :y2 (+ y1 height)))) + + ;; (merge shape + ;; (when width {:width width}) + ;; (when height {:height height}))) (defmethod -resize' :default [shape _] (throw (ex-info "Not implemented" (select-keys shape [:type])))) +(defmethod -size ::rect + [{:keys [x1 y1 x2 y2] :as shape}] + {:width (- x2 x1) + :height (- y2 y1)}) + +(defmethod -size :default + [shape _] + (throw (ex-info "Not implemented" (select-keys shape [:type])))) + ;; Move (defmethod -move ::rect [shape {dx :x dy :y}] (assoc shape - :x (+ (:x shape) dx) - :y (+ (:y shape) dy))) + :x1 (+ (:x1 shape) dx) + :y1 (+ (:y1 shape) dy) + :x2 (+ (:x2 shape) dx) + :y2 (+ (:y2 shape) dy))) (defmethod -move :builtin/group [shape {dx :x dy :y}] @@ -198,22 +207,22 @@ (throw (ex-info "Not implemented" (select-keys shape [:type])))) (defmethod -move' ::rect - [shape [x y]] - (let [dx (if x (- (:x shape) x) 0) - dy (if y (- (:y shape) y) 0)] - (-move shape [dx dy]))) - -(defmethod -move' :builtin/line - [shape [x y]] + [shape {:keys [x y] :as pos}] (let [dx (if x (- (:x1 shape) x) 0) dy (if y (- (:y1 shape) y) 0)] - (-move shape [dx dy]))) + (-move shape (gpt/point dx dy)))) + +(defmethod -move' :builtin/line + [shape {:keys [x y] :as pos}] + (let [dx (if x (- (:x1 shape) x) 0) + dy (if y (- (:y1 shape) y) 0)] + (-move shape (gpt/point dx dy)))) (defmethod -move' :builtin/circle - [shape [x y]] + [shape {:keys [x y] :as pos}] (let [dx (if x (- (:cx shape) x) 0) dy (if y (- (:cy shape) y) 0)] - (-move shape [dx dy]))) + (-move shape (gpt/point dx dy)))) (defmethod -move' :default [shape _] @@ -229,8 +238,9 @@ [{:keys [group] :as shape}] (let [group (get-in @st/state [:shapes-by-id group])] (as-> shape $ - (assoc $ :x (+ (:x shape) (:dx group 0))) - (assoc $ :y (+ (:y shape) (:dy group 0))) + (assoc $ :x (+ (:x1 shape) (:dx group 0))) + (assoc $ :y (+ (:y1 shape) (:dy group 0))) + (merge $ (-size $)) (container-rect $)))) (defmethod -outer-rect :builtin/line @@ -277,6 +287,26 @@ [shape _] (throw (ex-info "Not implemented" (select-keys shape [:type])))) +(defmethod -transformation :builtin/icon + [{:keys [x1 y1 rotation view-box] :or {rotation 0} :as shape}] + (let [{:keys [width height]} (-size shape) + orig-width (nth view-box 2) + orig-height (nth view-box 3) + scale-x (/ width orig-width) + scale-y (/ height orig-height) + center-x (- width (/ width 2)) + center-y (- height (/ height 2))] + (as-> (gmt/matrix) $ + (gmt/translate $ x1 y1) + (gmt/translate $ center-x center-y) + (gmt/rotate $ rotation) + (gmt/translate $ (- center-x) (- center-y)) + (gmt/scale $ scale-x scale-y)))) + +(defmethod -transformation :default + [shape _] + (throw (ex-info "Not implemented" (select-keys shape [:type])))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/src/uxbox/ui/shapes.cljs b/src/uxbox/ui/shapes.cljs index d306812cb..7f9a78b73 100644 --- a/src/uxbox/ui/shapes.cljs +++ b/src/uxbox/ui/shapes.cljs @@ -51,8 +51,8 @@ (defmethod sh/-render :builtin/icon [{:keys [data id] :as shape} _] (let [key (str id) - rfm (svg/calculate-transform shape) - attrs (merge {:id key :key key :transform rfm} + rfm (sh/-transformation shape) + attrs (merge {:id key :key key :transform (str rfm)} (extract-style-attrs shape) (make-debug-attrs shape))] (html diff --git a/src/uxbox/ui/workspace/canvas/draw.cljs b/src/uxbox/ui/workspace/canvas/draw.cljs index 380b5fa32..017913cf9 100644 --- a/src/uxbox/ui/workspace/canvas/draw.cljs +++ b/src/uxbox/ui/workspace/canvas/draw.cljs @@ -43,10 +43,12 @@ (define-once :drawing-subscriptions (letfn [(init-shape [shape] - (let [{:keys [x y]} (gpt/subtract @wb/mouse-position @wb/scroll) + (let [{:keys [x y] :as point} (gpt/subtract @wb/mouse-position + @wb/scroll) shape (sh/-initialize shape {:x1 x :y1 y :x2 x :y2 y})] + (reset! +drawing-shape+ shape) - (reset! +drawing-position+ {:x2 x :y2 y :lock false}) + (reset! +drawing-position+ (assoc point :lock false)) (as-> wb/interactions-b $ (rx/filter #(not= % :shape/movement) $) @@ -56,8 +58,8 @@ (rx/subscribe $ on-value nil on-complete)))) (on-value [[pos ctrl?]] - (let [{:keys [x y] :as pos} (gpt/subtract pos @wb/scroll)] - (reset! +drawing-position+ {:x2 x :y2 y :lock ctrl?}))) + (let [point (gpt/subtract pos @wb/scroll)] + (reset! +drawing-position+ (assoc point :lock ctrl?)))) (on-complete [] (let [shape @+drawing-shape+ diff --git a/src/uxbox/ui/workspace/options.cljs b/src/uxbox/ui/workspace/options.cljs index a0f32e2c1..d81881363 100644 --- a/src/uxbox/ui/workspace/options.cljs +++ b/src/uxbox/ui/workspace/options.cljs @@ -196,76 +196,77 @@ sid (:id shape) props {attr value}] (rs/emit! (dw/update-radius-attrs sid props))))] - (html - [:div.element-set {:key (str (:id menu))} - [:div.element-set-title (:name menu)] - [:div.element-set-content - ;; SLIDEBAR FOR ROTATION AND OPACITY - [:span "Size"] - [:div.row-flex - [:input#width.input-text - {:placeholder "Width" - :type "number" - :min "0" - :value (:width shape) - :on-change (partial on-size-change :width)}] - [:div.lock-size i/lock] - [:input#width.input-text - {:placeholder "Height" - :type "number" - :min "0" - :value (:height shape) - :on-change (partial on-size-change :height)}]] + (let [size (sh/-size shape)] + (html + [:div.element-set {:key (str (:id menu))} + [:div.element-set-title (:name menu)] + [:div.element-set-content + ;; SLIDEBAR FOR ROTATION AND OPACITY + [:span "Size"] + [:div.row-flex + [:input#width.input-text + {:placeholder "Width" + :type "number" + :min "0" + :value (:width size) + :on-change (partial on-size-change :width)}] + [:div.lock-size i/lock] + [:input#width.input-text + {:placeholder "Height" + :type "number" + :min "0" + :value (:height size) + :on-change (partial on-size-change :height)}]] - [:span "Position"] - [:div.row-flex - [:input#width.input-text - {:placeholder "x" - :type "number" - :value (:x shape "") - :on-change (partial on-pos-change :x)}] - [:input#width.input-text - {:placeholder "y" - :type "number" - :value (:y shape "") - :on-change (partial on-pos-change :y)}]] + [:span "Position"] + [:div.row-flex + [:input#width.input-text + {:placeholder "x" + :type "number" + :value (:x1 shape "") + :on-change (partial on-pos-change :x)}] + [:input#width.input-text + {:placeholder "y" + :type "number" + :value (:y1 shape "") + :on-change (partial on-pos-change :y)}]] - [:span "Border radius"] - [:div.row-flex - [:input#width.input-text - {:placeholder "rx" - :type "number" - :value (:rx shape "") - :on-change (partial on-border-change :rx)}] - [:div.lock-size i/lock] - [:input#width.input-text - {:placeholder "ry" - :type "number" - :value (:ry shape "") - :on-change (partial on-border-change :ry)}]] + [:span "Border radius"] + [:div.row-flex + [:input#width.input-text + {:placeholder "rx" + :type "number" + :value (:rx shape "") + :on-change (partial on-border-change :rx)}] + [:div.lock-size i/lock] + [:input#width.input-text + {:placeholder "ry" + :type "number" + :value (:ry shape "") + :on-change (partial on-border-change :ry)}]] - [:span "Rotation"] - [:div.row-flex - [:input.slidebar - {:type "range" - :min 0 - :max 360 - :value (:rotation shape 0) - :on-change on-rotation-change}]] + [:span "Rotation"] + [:div.row-flex + [:input.slidebar + {:type "range" + :min 0 + :max 360 + :value (:rotation shape 0) + :on-change on-rotation-change}]] - [:div.row-flex - [:input#width.input-text - {:placeholder "" - :type "number" - :min 0 - :max 360 - :value (:rotation shape "0") - :on-change on-rotation-change - }] - [:input.input-text - {:style {:visibility "hidden"}}] - ]]] - ))) + [:div.row-flex + [:input#width.input-text + {:placeholder "" + :type "number" + :min 0 + :max 360 + :value (:rotation shape "0") + :on-change on-rotation-change + }] + [:input.input-text + {:style {:visibility "hidden"}}] + ]]] + )))) (defmethod -render-menu :menu/icon-measures @@ -287,62 +288,63 @@ sid (:id shape) props {attr value}] (rs/emit! (dw/update-position sid props))))] - (html - [:div.element-set {:key (str (:id menu))} - [:div.element-set-title (:name menu)] - [:div.element-set-content - ;; SLIDEBAR FOR ROTATION AND OPACITY - [:span "Size"] - [:div.row-flex - [:input#width.input-text - {:placeholder "Width" - :type "number" - :min "0" - :value (:width shape) - :on-change (partial on-size-change :width)}] - [:div.lock-size i/lock] - [:input#width.input-text - {:placeholder "Height" - :type "number" - :min "0" - :value (:height shape) - :on-change (partial on-size-change :height)}]] + (let [size (sh/-size shape)] + (html + [:div.element-set {:key (str (:id menu))} + [:div.element-set-title (:name menu)] + [:div.element-set-content + ;; SLIDEBAR FOR ROTATION AND OPACITY + [:span "Size"] + [:div.row-flex + [:input#width.input-text + {:placeholder "Width" + :type "number" + :min "0" + :value (:width size) + :on-change (partial on-size-change :width)}] + [:div.lock-size i/lock] + [:input#width.input-text + {:placeholder "Height" + :type "number" + :min "0" + :value (:height size) + :on-change (partial on-size-change :height)}]] - [:span "Position"] - [:div.row-flex - [:input#width.input-text - {:placeholder "x" - :type "number" - :value (:x shape "") - :on-change (partial on-pos-change :x)}] - [:input#width.input-text - {:placeholder "y" - :type "number" - :value (:y shape "") - :on-change (partial on-pos-change :y)}]] + [:span "Position"] + [:div.row-flex + [:input#width.input-text + {:placeholder "x" + :type "number" + :value (:x1 shape "") + :on-change (partial on-pos-change :x)}] + [:input#width.input-text + {:placeholder "y" + :type "number" + :value (:y1 shape "") + :on-change (partial on-pos-change :y)}]] - [:span "Rotation"] - [:div.row-flex - [:input.slidebar - {:type "range" - :min 0 - :max 360 - :value (:rotation shape 0) - :on-change on-rotation-change}]] + [:span "Rotation"] + [:div.row-flex + [:input.slidebar + {:type "range" + :min 0 + :max 360 + :value (:rotation shape 0) + :on-change on-rotation-change}]] - [:div.row-flex - [:input#width.input-text - {:placeholder "" - :type "number" - :min 0 - :max 360 - :value (:rotation shape "0") - :on-change on-rotation-change - }] - [:input.input-text - {:style {:visibility "hidden"}}] - ]]] - ))) + [:div.row-flex + [:input#width.input-text + {:placeholder "" + :type "number" + :min 0 + :max 360 + :value (:rotation shape "0") + :on-change on-rotation-change + }] + [:input.input-text + {:style {:visibility "hidden"}}] + ]]] + )))) (defmethod -render-menu :menu/circle-measures [menu own shape]