From 3fdce853d05cdd6456fd282f3ce71688039937ed Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 31 Jan 2017 16:58:10 +0100 Subject: [PATCH] Don't trigger page persistence on simple shape selection. --- frontend/src/uxbox/main/data/pages.cljs | 3 +- frontend/src/uxbox/main/data/shapes.cljs | 91 ++++++------------- frontend/src/uxbox/main/data/shapes_impl.cljs | 11 ++- frontend/src/uxbox/main/geom.cljs | 34 +++---- frontend/src/uxbox/main/ui/shapes/circle.cljs | 20 ++-- frontend/src/uxbox/main/ui/shapes/common.cljs | 11 ++- frontend/src/uxbox/main/ui/shapes/icon.cljs | 28 +++--- frontend/src/uxbox/main/ui/shapes/image.cljs | 23 +++-- frontend/src/uxbox/main/ui/shapes/path.cljs | 19 ++-- frontend/src/uxbox/main/ui/shapes/rect.cljs | 16 ++-- .../src/uxbox/main/ui/shapes/selection.cljs | 18 ++-- 11 files changed, 133 insertions(+), 141 deletions(-) diff --git a/frontend/src/uxbox/main/data/pages.cljs b/frontend/src/uxbox/main/data/pages.cljs index fa99a566c..448bad381 100644 --- a/frontend/src/uxbox/main/data/pages.cljs +++ b/frontend/src/uxbox/main/data/pages.cljs @@ -433,7 +433,8 @@ (rx/take 1))] (rx/merge (->> stream - (rx/filter #(satisfies? IPageUpdate %)) + (rx/filter #(or (satisfies? IPageUpdate %) + (= ::page-update %))) (rx/take-until stopper) (rx/debounce 1000) (rx/mapcat #(rx/merge (rx/of (persist-page id)) diff --git a/frontend/src/uxbox/main/data/shapes.cljs b/frontend/src/uxbox/main/data/shapes.cljs index 87b434d13..2c8d6591a 100644 --- a/frontend/src/uxbox/main/data/shapes.cljs +++ b/frontend/src/uxbox/main/data/shapes.cljs @@ -14,8 +14,8 @@ [uxbox.main.lenses :as ul] [uxbox.main.geom :as geom] [uxbox.main.workers :as uwrk] - [uxbox.main.data.shapes-impl :as impl] [uxbox.main.data.pages :as udp] + [uxbox.main.data.shapes-impl :as impl] [uxbox.main.user-events :as uev] [uxbox.util.data :refer [dissoc-in]] [uxbox.util.forms :as sc] @@ -177,13 +177,11 @@ ;; --- Apply Temporal Displacement (deftype ApplyTemporalDisplacement [id delta] - udp/IPageUpdate ptk/UpdateEvent (update [_ state] - (let [shape (get-in state [:shapes id]) - displ (:tmp-displacement shape (gpt/point 0 0)) - delta (gpt/add displ delta)] - (assoc-in state [:shapes id :tmp-displacement] delta)))) + (let [prev (get-in state [:workspace :modifiers id :displacement] (gmt/matrix)) + curr (gmt/translate prev delta)] + (assoc-in state [:workspace :modifiers id :displacement] curr)))) (defn apply-temporal-displacement [id pt] @@ -192,30 +190,15 @@ ;; --- Apply Displacement -;; TODO: move to shapes-impl ns. - (deftype ApplyDisplacement [id] - udp/IPageUpdate - ptk/UpdateEvent - (update [_ state] - (let [{:keys [tmp-displacement type] :as shape} (get-in state [:shapes id]) - xfmt (gmt/translate-matrix tmp-displacement)] - - (if (= type :group) - (letfn [(update-item [state id] - (let [{:keys [type items] :as shape} (get-in state [:shapes id])] - (if (= type :group) - (reduce update-item state items) - (update-in state [:shapes id] - (fn [shape] - (as-> (dissoc shape :tmp-displacement) $ - (geom/transform state $ xfmt)))))))] - (-> (reduce update-item state (:items shape)) - (update-in [:shapes id] dissoc :tmp-displacement))) - - (update-in state [:shapes id] (fn [shape] - (as-> (dissoc shape :tmp-displacement) $ - (geom/transform state $ xfmt)))))))) + ptk/WatchEvent + (watch [_ state stream] + (let [displacement (get-in state [:workspace :modifiers id :displacement])] + (if (gmt/matrix? displacement) + (rx/of #(impl/materialize-xfmt % id displacement) + #(update-in % [:workspace :modifiers id] dissoc :displacement) + ::udp/page-update) + (rx/empty))))) (defn apply-displacement [id] @@ -224,48 +207,34 @@ ;; --- Apply Temporal Resize Matrix -(deftype ApplyTemporalResizeMatrix [id mx] - udp/IPageUpdate +(deftype ApplyTemporalResize [id xfmt] ptk/UpdateEvent (update [_ state] - (assoc-in state [:shapes id :tmp-resize-xform] mx))) + (assoc-in state [:workspace :modifiers id :resize] xfmt))) -(defn apply-temporal-resize-matrix - "Attach temporal resize matrix transformation to the shape." - [id mx] - (ApplyTemporalResizeMatrix. id mx)) +(defn apply-temporal-resize + "Attach temporal resize transformation to the shape." + [id xfmt] + {:pre [(gmt/matrix? xfmt)]} + (ApplyTemporalResize. id xfmt)) ;; --- Apply Resize Matrix -(declare apply-resize-matrix) +(deftype ApplyResize [id] + ptk/WatchEvent + (watch [_ state stream] + (let [resize (get-in state [:workspace :modifiers id :resize])] + (if (gmt/matrix? resize) + (rx/of #(impl/materialize-xfmt % id resize) + #(update-in % [:workspace :modifiers id] dissoc :resize) + ::udp/page-update) + (rx/empty))))) -(deftype ApplyResizeMatrix [id] - udp/IPageUpdate - ptk/UpdateEvent - (update [_ state] - (let [{:keys [type tmp-resize-xform] - :or {tmp-resize-xform (gmt/matrix)} - :as shape} (get-in state [:shapes id])] - (if (= type :group) - (letfn [(update-item [state id] - (let [{:keys [type items] :as shape} (get-in state [:shapes id])] - (if (= type :group) - (reduce update-item state items) - (update-in state [:shapes id] - (fn [shape] - (as-> (dissoc shape :tmp-resize-xform) $ - (geom/transform state $ tmp-resize-xform)))))))] - (-> (reduce update-item state (:items shape)) - (update-in [:shapes id] dissoc :tmp-resize-xform))) - (update-in state [:shapes id] (fn [shape] - (as-> (dissoc shape :tmp-resize-xform) $ - (geom/transform state $ tmp-resize-xform)))))))) - -(defn apply-resize-matrix +(defn apply-resize "Apply definitivelly the resize matrix transformation to the shape." [id] {:pre [(uuid? id)]} - (ApplyResizeMatrix. id)) + (ApplyResize. id)) (defn update-position "Update the start position coordenate of the shape." diff --git a/frontend/src/uxbox/main/data/shapes_impl.cljs b/frontend/src/uxbox/main/data/shapes_impl.cljs index 0b0aa9e70..1c5411356 100644 --- a/frontend/src/uxbox/main/data/shapes_impl.cljs +++ b/frontend/src/uxbox/main/data/shapes_impl.cljs @@ -2,12 +2,13 @@ ;; 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) 2015-2016 Andrey Antukh +;; Copyright (c) 2015-2017 Andrey Antukh (ns uxbox.main.data.shapes-impl (:require [lentes.core :as l] [uxbox.main.geom :as geom] [uxbox.main.lenses :as ul] + [uxbox.util.geom.matrix :as gmt] [uxbox.util.uuid :as uuid] [uxbox.util.data :refer (index-of)])) @@ -413,3 +414,11 @@ (as-> state $ (empty-groups $ page groups-ids) (update $ :workspace assoc :selected (set groups-items)))))) + +(defn materialize-xfmt + [state id xfmt] + (let [{:keys [type items] :as shape} (get-in state [:shapes id])] + (if (= type :group) + (-> (reduce #(materialize-xfmt %1 %2 xfmt) state items) + (update-in [:shapes id] geom/transform xfmt)) + (update-in state [:shapes id] geom/transform xfmt)))) diff --git a/frontend/src/uxbox/main/geom.cljs b/frontend/src/uxbox/main/geom.cljs index ad16f1212..a0938d7e5 100644 --- a/frontend/src/uxbox/main/geom.cljs +++ b/frontend/src/uxbox/main/geom.cljs @@ -438,15 +438,14 @@ (defn transform "Apply the matrix transformation to shape." - ([shape xfmt] (transform @st/state shape xfmt)) - ([state {:keys [type] :as shape} xfmt] - (case type - :rect (transform-rect shape xfmt) - :icon (transform-rect shape xfmt) - :text (transform-rect shape xfmt) - :image (transform-rect shape xfmt) - :path (transform-path shape xfmt) - :circle (transform-circle shape xfmt)))) + [{:keys [type] :as shape} xfmt] + (case type + :rect (transform-rect shape xfmt) + :icon (transform-rect shape xfmt) + :text (transform-rect shape xfmt) + :image (transform-rect shape xfmt) + :path (transform-path shape xfmt) + :circle (transform-circle shape xfmt))) (defn- transform-rect [{:keys [x1 y1] :as shape} mx] @@ -524,29 +523,24 @@ (defn- selection-rect-generic [state {:keys [id x1 y1 x2 y2] :as shape}] - (let [resize-xf (:tmp-resize-xform shape (gmt/matrix)) - displc-xf (-> (:tmp-displacement shape (gpt/point 0 0)) - (gmt/translate-matrix))] + (let [{:keys [displacement resize]} (get-in state [:workspace :modifiers id])] (-> (shape->rect-shape shape) (assoc :type :rect :id id) - (transform resize-xf) - (transform displc-xf) + (transform (or resize (gmt/matrix))) + (transform (or displacement (gmt/matrix))) (rotate-shape) (size)))) (defn- selection-rect-group [state {:keys [id group items] :as shape}] - (let [resize-xf (:tmp-resize-xform shape (gmt/matrix)) - displc-xf (-> (:tmp-displacement shape (gpt/point 0 0)) - (gmt/translate-matrix)) + (let [{:keys [displacement resize]} (get-in state [:workspace :modifiers id]) shapes (->> items (map #(get-in state [:shapes %])) (map #(selection-rect state %)))] - (-> (shapes->rect-shape shapes) (assoc :id id) - (transform resize-xf) - (transform displc-xf) + (transform (or resize (gmt/matrix))) + (transform (or displacement (gmt/matrix))) (rotate-shape) (size)))) diff --git a/frontend/src/uxbox/main/ui/shapes/circle.cljs b/frontend/src/uxbox/main/ui/shapes/circle.cljs index a7dbc6076..74306dc95 100644 --- a/frontend/src/uxbox/main/ui/shapes/circle.cljs +++ b/frontend/src/uxbox/main/ui/shapes/circle.cljs @@ -19,23 +19,27 @@ (mx/defc circle-component {:mixins [mx/reactive mx/static]} - [shape] - (let [{:keys [id x y width height group]} shape + [{:keys [id] :as shape}] + (let [modifiers (mx/react (common/modifiers-ref id)) selected (mx/react common/selected-ref) selected? (contains? selected id) - on-mouse-down #(common/on-mouse-down % shape selected)] + on-mouse-down #(common/on-mouse-down % shape selected) + shape (assoc shape :modifiers modifiers)] [:g.shape {:class (when selected? "selected") :on-mouse-down on-mouse-down} - (circle-shape shape identity)])) + (circle-shape shape)])) ;; --- Circle Shape (mx/defc circle-shape {:mixins [mx/static]} - [{:keys [id tmp-resize-xform tmp-displacement rotation cx cy] :as shape}] - (let [shape (cond-> shape - tmp-displacement (geom/transform (gmt/translate-matrix tmp-displacement)) - tmp-resize-xform (geom/transform tmp-resize-xform)) + [{:keys [id modifiers rotation cx cy] :as shape}] + (let [{:keys [resize displacement]} modifiers + + shape (cond-> shape + displacement (geom/transform displacement) + resize (geom/transform resize)) + center (gpt/point (:cx shape) (:cy shape)) rotation (or rotation 0) diff --git a/frontend/src/uxbox/main/ui/shapes/common.cljs b/frontend/src/uxbox/main/ui/shapes/common.cljs index 877cccd97..980b783e0 100644 --- a/frontend/src/uxbox/main/ui/shapes/common.cljs +++ b/frontend/src/uxbox/main/ui/shapes/common.cljs @@ -20,8 +20,6 @@ ;; --- Refs -;; FIXME: use the predefined lenses under uxbox.main.lenses - (def edition-ref (-> (l/in [:workspace :edition]) (l/derive st/state))) @@ -31,8 +29,13 @@ (l/derive st/state))) (def selected-ref - (-> (l/in [:workspace :selected]) - (l/derive st/state))) + (-> (l/in [:selected]) + (l/derive refs/workspace))) + +(defn modifiers-ref + [id] + (-> (l/in [:modifiers id]) + (l/derive refs/workspace))) ;; --- Movement diff --git a/frontend/src/uxbox/main/ui/shapes/icon.cljs b/frontend/src/uxbox/main/ui/shapes/icon.cljs index 12affa59f..a6fadb36d 100644 --- a/frontend/src/uxbox/main/ui/shapes/icon.cljs +++ b/frontend/src/uxbox/main/ui/shapes/icon.cljs @@ -19,34 +19,36 @@ (mx/defc icon-component {:mixins [mx/static mx/reactive]} [{:keys [id] :as shape}] - (let [selected (mx/react common/selected-ref) + (let [modifiers (mx/react (common/modifiers-ref id)) + selected (mx/react common/selected-ref) selected? (contains? selected id) - on-mouse-down #(common/on-mouse-down % shape selected)] + on-mouse-down #(common/on-mouse-down % shape selected) + shape (assoc shape :modifiers modifiers)] [:g.shape {:class (when selected? "selected") :on-mouse-down on-mouse-down} - (icon-shape shape identity)])) + (icon-shape shape)])) ;; --- Icon Shape (mx/defc icon-shape {:mixins [mx/static]} - [shape] - (let [{:keys [x1 y1 content id metadata - width height rotation - tmp-resize-xform - tmp-displacement]} (geom/size shape) + [{:keys [id content metadata rotation x1 y1 modifiers] :as shape}] + (let [{:keys [width height]} (geom/size shape) + {:keys [resize displacement]} modifiers view-box (apply str (interpose " " (:view-box metadata))) xfmt (cond-> (gmt/matrix) - tmp-resize-xform (gmt/multiply tmp-resize-xform) - tmp-displacement (gmt/translate tmp-displacement) + resize (gmt/multiply resize) + displacement (gmt/multiply displacement) rotation (gmt/rotate* rotation (gpt/point (+ x1 (/ width 2)) (+ y1 (/ height 2))))) - props {:id (str id) - :x x1 :y y1 :view-box view-box - :width width :height height + :x x1 + :y y1 + :view-box view-box + :width width + :height height :preserve-aspect-ratio "none" :dangerouslySetInnerHTML {:__html content}} diff --git a/frontend/src/uxbox/main/ui/shapes/image.cljs b/frontend/src/uxbox/main/ui/shapes/image.cljs index ff8475d65..235c92d0f 100644 --- a/frontend/src/uxbox/main/ui/shapes/image.cljs +++ b/frontend/src/uxbox/main/ui/shapes/image.cljs @@ -36,27 +36,30 @@ (st/emit! (udi/fetch-image id))) own)} [own {:keys [id image] :as shape}] - (let [selected (mx/react common/selected-ref) + (let [modifiers (mx/react (common/modifiers-ref id)) + selected (mx/react common/selected-ref) image (mx/react (image-ref image)) selected? (contains? selected id) - on-mouse-down #(common/on-mouse-down % shape selected)] + on-mouse-down #(common/on-mouse-down % shape selected) + shape (assoc shape + :modifiers modifiers + :image image)] (when image [:g.shape {:class (when selected? "selected") :on-mouse-down on-mouse-down} - (image-shape (assoc shape :image image))]))) + (image-shape shape)]))) ;; --- Image Shape (mx/defc image-shape {:mixins [mx/static]} - [shape] - (let [{:keys [id x1 y1 image - width height - tmp-resize-xform - tmp-displacement]} (geom/size shape) + [{:keys [id x1 y1 image modifiers] :as shape}] + (let [{:keys [width height]} (geom/size shape) + {:keys [resize displacement]} modifiers - xfmt (cond-> (or tmp-resize-xform (gmt/matrix)) - tmp-displacement (gmt/translate tmp-displacement)) + xfmt (cond-> (gmt/matrix) + resize (gmt/multiply resize) + displacement (gmt/multiply displacement)) props {:x x1 :y y1 :id (str "shape-" id) diff --git a/frontend/src/uxbox/main/ui/shapes/path.cljs b/frontend/src/uxbox/main/ui/shapes/path.cljs index 3fe3534e7..707324748 100644 --- a/frontend/src/uxbox/main/ui/shapes/path.cljs +++ b/frontend/src/uxbox/main/ui/shapes/path.cljs @@ -22,8 +22,10 @@ (mx/defc path-component {:mixins [mx/static mx/reactive]} [{:keys [id] :as shape}] - (let [selected (mx/react common/selected-ref) - selected? (contains? selected id)] + (let [modifiers (mx/react (common/modifiers-ref id)) + selected (mx/react common/selected-ref) + selected? (contains? selected id) + shape (assoc shape :modifiers modifiers)] (letfn [(on-mouse-down [event] (common/on-mouse-down event shape selected)) (on-double-click [event] @@ -32,13 +34,12 @@ [:g.shape {:class (when selected? "selected") :on-double-click on-double-click :on-mouse-down on-mouse-down} - (path-shape shape identity)]))) + (path-shape shape)]))) ;; --- Path Shape (defn- render-path [{:keys [points close?] :as shape}] - {:pre [(pos? (count points))]} (let [start (first points) init (str "M " (:x start) " " (:y start)) path (reduce #(str %1 " L" (:x %2) " " (:y %2)) init points)] @@ -47,11 +48,11 @@ (mx/defc path-shape {:mixins [mx/static]} - [{:keys [id tmp-resize-xform tmp-displacement rotation] :as shape}] - - (let [shape (cond-> shape - tmp-displacement (geom/transform (gmt/translate-matrix tmp-displacement)) - tmp-resize-xform (geom/transform tmp-resize-xform) + [{:keys [id modifiers rotation] :as shape}] + (let [{:keys [resize displacement]} modifiers + shape (cond-> shape + displacement (geom/transform displacement) + resize (geom/transform resize) (pos? rotation) (geom/rotate-shape)) props {:id (str id) diff --git a/frontend/src/uxbox/main/ui/shapes/rect.cljs b/frontend/src/uxbox/main/ui/shapes/rect.cljs index cd52717a4..6f5778ec3 100644 --- a/frontend/src/uxbox/main/ui/shapes/rect.cljs +++ b/frontend/src/uxbox/main/ui/shapes/rect.cljs @@ -19,11 +19,12 @@ (mx/defc rect-component {:mixins [mx/reactive mx/static]} - [shape] - (let [{:keys [id x y width height group]} shape + [{:keys [id] :as shape}] + (let [modifiers (mx/react (common/modifiers-ref id)) selected (mx/react common/selected-ref) selected? (contains? selected id) - on-mouse-down #(common/on-mouse-down % shape selected)] + on-mouse-down #(common/on-mouse-down % shape selected) + shape (assoc shape :modifiers modifiers)] [:g.shape {:class (when selected? "selected") :on-mouse-down on-mouse-down} (rect-shape shape identity)])) @@ -40,10 +41,11 @@ (mx/defc rect-shape {:mixins [mx/static]} - [{:keys [id tmp-displacement tmp-resize-xform rotation] :as shape}] - (let [xfmt (cond-> (gmt/matrix) - tmp-displacement (gmt/translate tmp-displacement) - tmp-resize-xform (gmt/multiply tmp-resize-xform)) + [{:keys [id rotation modifiers] :as shape}] + (let [{:keys [displacement resize]} modifiers + xfmt (cond-> (gmt/matrix) + displacement (gmt/multiply displacement) + resize (gmt/multiply resize)) {:keys [x1 y1 width height] :as shape} (-> (geom/transform shape xfmt) (geom/size)) diff --git a/frontend/src/uxbox/main/ui/shapes/selection.cljs b/frontend/src/uxbox/main/ui/shapes/selection.cljs index 881adbad0..912548de1 100644 --- a/frontend/src/uxbox/main/ui/shapes/selection.cljs +++ b/frontend/src/uxbox/main/ui/shapes/selection.cljs @@ -44,6 +44,9 @@ (l/derive st/state))) (def ^:private edition-ref scommon/edition-ref) +(def ^:private modifiers-ref + (-> (l/key :modifiers) + (l/derive refs/workspace))) ;; --- Resize Implementation @@ -204,11 +207,11 @@ )) (on-resize [shape scale] (let [mt (gen-matrix shape scale) - xf (map #(uds/apply-temporal-resize-matrix % mt))] + xf (map #(uds/apply-temporal-resize % mt))] (apply st/emit! (sequence xf ids)))) (on-end [] - (apply st/emit! (map uds/apply-resize-matrix ids)))] + (apply st/emit! (map uds/apply-resize ids)))] (let [shape (->> (geom/shape->rect-shape shape) (geom/size)) @@ -349,7 +352,7 @@ (mx/defc multiple-selection-handlers {:mixins [mx/static]} - [[shape & rest :as shapes] zoom] + [[shape & rest :as shapes] modifiers zoom] (let [selection (-> (map #(geom/selection-rect %) shapes) (geom/shapes->rect-shape) (geom/selection-rect)) @@ -360,7 +363,7 @@ (mx/defc single-selection-handlers {:mixins [mx/static]} - [{:keys [id] :as shape} zoom] + [{:keys [id] :as shape} modifiers zoom] (let [on-click #(do (dom/stop-propagation %2) (start-resize %1 #{id} shape)) shape (geom/selection-rect shape)] @@ -384,6 +387,7 @@ {:mixins [mx/reactive mx/static]} [] (let [shapes (mx/react selected-shapes-ref) + modifiers (mx/react modifiers-ref) edition? (mx/react edition-ref) zoom (mx/react refs/selected-zoom) num (count shapes) @@ -393,7 +397,7 @@ nil (> num 1) - (multiple-selection-handlers shapes zoom) + (multiple-selection-handlers shapes modifiers zoom) (and (= type :text) edition?) (text-edition-selection-handlers shape zoom) @@ -401,7 +405,7 @@ (= type :path) (if (= @edition-ref (:id shape)) (path-edition-selection-handlers shape zoom) - (single-selection-handlers shape zoom)) + (single-selection-handlers shape modifiers zoom)) :else - (single-selection-handlers shape zoom)))) + (single-selection-handlers shape modifiers zoom))))