From 29ef7cfbd778d963b22e1576bfe4ff000aa0b002 Mon Sep 17 00:00:00 2001 From: Daniel Woelfel Date: Tue, 16 Jun 2015 13:41:47 -0700 Subject: [PATCH 01/21] paste shapes at mouse point, click to place --- src-cljs/frontend/controllers/controls.cljs | 62 ++++++++++++++++----- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/src-cljs/frontend/controllers/controls.cljs b/src-cljs/frontend/controllers/controls.cljs index 4452629c..9b910946 100644 --- a/src-cljs/frontend/controllers/controls.cljs +++ b/src-cljs/frontend/controllers/controls.cljs @@ -898,6 +898,7 @@ (and (= button 0) ctrl? (not shift?)) [:open-radial] (and (= button 0) meta? (not shift?)) [:open-radial] (get-in state [:layer-properties-menu :opened?]) [:submit-layer-properties] + (get-in state [:drawing :moving?]) [:drop-layers] (contains? #{:pen :rect :circle :line :select} tool) [:start-drawing] (and (keyword-identical? tool :text) (not drawing-text?)) [:start-drawing] :else nil)))) @@ -908,6 +909,7 @@ (declare handle-layer-properties-submitted-after) (declare handle-text-layer-finished) (declare handle-text-layer-finished-after) +(declare handle-drawing-finalized-after) (defmethod control-event :mouse-depressed [browser-state message [x y {:keys [button type ctrl? shift? meta? outside-canvas?]}] state] @@ -921,6 +923,7 @@ (reduce (fn [s intent] (case intent :finish-text-layer (handle-text-layer-finished s) + :drop-layers (drop-layers s) :open-radial (handle-radial-opened s) :start-drawing (handle-drawing-started s x y) :submit-layer-properties (handle-layer-properties-submitted s) @@ -936,7 +939,8 @@ (doseq [intent intents] (case intent :finish-text-layer (handle-text-layer-finished-after previous-state current-state) - :open-radial (handle-radial-opened-after current-state previous-state) + :drop-layers (handle-drawing-finalized-after previous-state current-state x y) + :open-radial (handle-radial-opened-after previous-state current-state) :start-drawing nil :submit-layer-properties (handle-layer-properties-submitted-after current-state) nil))))) @@ -1025,6 +1029,24 @@ (get-in state [:drawing :moving?]) (drop-layers))))) +(defn handle-drawing-finalized-after [previous-state current-state x y] + (let [db (:db current-state) + original-layers (get-in previous-state [:drawing :original-layers]) + layers (mapv #(-> % + (dissoc :points) + (utils/update-when-in [:layer/points-to] (fn [p] (set (map :db/id p)))) + (utils/remove-map-nils)) + (get-in current-state [:drawing :finished-layers]))] + (do (when (and (some layer-model/detectable? layers) + (or (not (get-in previous-state [:drawing :moving?])) + (some true? (map detectable-movement? original-layers layers)))) + (doseq [layer-group (partition-all 100 layers)] + (d/transact! db (if (= :read (:max-document-scope current-state)) + (map #(assoc % :unsaved true) layer-group) + layer-group) + {:can-undo? true}))) + (maybe-notify-subscribers! previous-state current-state x y)))) + (defmethod post-control-event! :mouse-released [browser-state message [x y {:keys [button type ctrl? meta?]}] previous-state current-state] (let [cast! #(put! (get-in current-state [:comms :controls]) %) @@ -1059,15 +1081,7 @@ (every? #(= :layer.type/text (:layer/type %)) layers)) nil - was-drawing? (do (when (and (some layer-model/detectable? layers) - (or (not (get-in previous-state [:drawing :moving?])) - (some true? (map detectable-movement? original-layers layers)))) - (doseq [layer-group (partition-all 100 layers)] - (d/transact! db (if (= :read (:max-document-scope current-state)) - (map #(assoc % :unsaved true) layer-group) - layer-group) - {:can-undo? true}))) - (maybe-notify-subscribers! previous-state current-state x y)) + was-drawing? (handle-drawing-finalized-after previous-state current-state x y) :else nil))) @@ -1574,7 +1588,12 @@ (/ (:width canvas-size) 2)) new-y (+ (* (- center-y) zoom) (/ (:height canvas-size) 2)) + + new-x (get-in state [:mouse :x]) + new-y (get-in state [:mouse :y]) [move-x move-y] (cameras/screen->point camera new-x new-y) + move-x (+ (- center-x) (get-in state [:mouse :rx])) + move-y (+ (- center-y) (get-in state [:mouse :ry])) [snap-move-x snap-move-y] (cameras/snap-to-grid (:camera state) move-x move-y) new-layers (mapv (fn [l] (-> l @@ -1586,22 +1605,37 @@ (set (filter :db/id (map #(update-in % [:db/id] eid-map) dests))))) (#(move-layer % % {:snap-x snap-move-x :snap-y snap-move-y - :move-x move-x :move-y move-y :snap-paths? true})) - (dissoc :layer/current-x :layer/current-y :points))) + :move-x move-x :move-y move-y :snap-paths? true})))) layers)] + #_(-> state + (assoc-in [:clipboard :layers] new-layers) + (assoc-in [:selected-eids :selected-eids] (set entity-ids)) + (assoc-in [:selected-arrows :selected-arrows] (set (reduce (fn [acc layer] + (if-let [pointer (:layer/points-to layer)] + (conj acc {:origin-id (:db/id layer) + :dest-id (:db/id pointer)}) + acc)) + #{} new-layers)))) (-> state + (assoc-in [:mouse-down] true) + (assoc-in [:drawing :starting-mouse-position] (utils/inspect [(get-in state [:mouse :rx]) + (get-in state [:mouse :ry])])) (assoc-in [:clipboard :layers] new-layers) + (assoc-in [:drawing :moving?] true) + (assoc-in [:drawing :layers] new-layers) + (assoc-in [:drawing :original-layers] new-layers) + (assoc-in [:editing-eids :editing-eids] (set entity-ids)) (assoc-in [:selected-eids :selected-eids] (set entity-ids)) (assoc-in [:selected-arrows :selected-arrows] (set (reduce (fn [acc layer] (if-let [pointer (:layer/points-to layer)] (conj acc {:origin-id (:db/id layer) :dest-id (:db/id pointer)}) acc)) - #{} new-layers)))))) + #{} new-layers)))))) (defmethod post-control-event! :layers-pasted [browser-state message _ previous-state current-state] - (let [db (:db current-state) + #_(let [db (:db current-state) layers (mapv utils/remove-map-nils (get-in current-state [:clipboard :layers]))] (doseq [layer-group (partition-all 100 layers)] (d/transact! db From 41045a00c9d0600faffba51f00cbec76a0e0146d Mon Sep 17 00:00:00 2001 From: Daniel Woelfel Date: Tue, 16 Jun 2015 16:28:02 -0700 Subject: [PATCH 02/21] add a 'clip' class to in-progress paste --- resources/assets/css/components/canvas.less | 3 +++ src-cljs/frontend/components/canvas.cljs | 4 +++- src-cljs/frontend/controllers/controls.cljs | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/resources/assets/css/components/canvas.less b/resources/assets/css/components/canvas.less index daeb4f10..46a1f5a2 100644 --- a/resources/assets/css/components/canvas.less +++ b/resources/assets/css/components/canvas.less @@ -400,3 +400,6 @@ #selected-arrow-point { fill: @color_select; } +.clip { + opacity: 0.5; +} diff --git a/src-cljs/frontend/components/canvas.cljs b/src-cljs/frontend/components/canvas.cljs index cb4ea29b..c4345a1b 100644 --- a/src-cljs/frontend/components/canvas.cljs +++ b/src-cljs/frontend/components/canvas.cljs @@ -727,7 +727,9 @@ (= :layer.type/text (get-in drawing [:layers 0 :layer/type])) nil (:in-progress? drawing) (:layers drawing) :else nil)] - (apply dom/g #js {:className "layers"} + (apply dom/g #js {:className (str "layers " + (when (:clip? drawing) + "clip "))} (map (fn [sel] (let [sel (if (:force-even? sel) (layers/force-even sel) diff --git a/src-cljs/frontend/controllers/controls.cljs b/src-cljs/frontend/controllers/controls.cljs index 9b910946..5b237179 100644 --- a/src-cljs/frontend/controllers/controls.cljs +++ b/src-cljs/frontend/controllers/controls.cljs @@ -876,6 +876,7 @@ (assoc-in [:drawing :finished-layers] (mapv #(dissoc % :layer/current-x :layer/current-y) layers)) (assoc-in [:drawing :layers] []) (assoc-in [:drawing :moving?] false) + (assoc-in [:drawing :clip?] false) (assoc-in [:mouse-down] false) (assoc-in [:editing-eids :editing-eids] #{})))) @@ -1618,6 +1619,7 @@ #{} new-layers)))) (-> state (assoc-in [:mouse-down] true) + (assoc-in [:drawing :clip?] true) (assoc-in [:drawing :starting-mouse-position] (utils/inspect [(get-in state [:mouse :rx]) (get-in state [:mouse :ry])])) (assoc-in [:clipboard :layers] new-layers) From 89bddc8306d40b5548457d61d962da0b21ef77f6 Mon Sep 17 00:00:00 2001 From: danny Date: Tue, 16 Jun 2015 18:21:05 -0700 Subject: [PATCH 03/21] visual state for pasted shape --- resources/assets/css/components/canvas.less | 9 ++++++--- src-cljs/frontend/components/canvas.cljs | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/resources/assets/css/components/canvas.less b/resources/assets/css/components/canvas.less index 46a1f5a2..d259d637 100644 --- a/resources/assets/css/components/canvas.less +++ b/resources/assets/css/components/canvas.less @@ -158,7 +158,7 @@ stroke: @color_select; stroke-width: 2; &.selection { - stroke: @white; + stroke: @gray_lighter; stroke-width: 1; } } @@ -400,6 +400,9 @@ #selected-arrow-point { fill: @color_select; } -.clip { - opacity: 0.5; +.clips { + .shape-layer { + stroke: @gray_light; + stroke-dasharray: 2, 3; + } } diff --git a/src-cljs/frontend/components/canvas.cljs b/src-cljs/frontend/components/canvas.cljs index c4345a1b..6ba013c1 100644 --- a/src-cljs/frontend/components/canvas.cljs +++ b/src-cljs/frontend/components/canvas.cljs @@ -729,7 +729,7 @@ :else nil)] (apply dom/g #js {:className (str "layers " (when (:clip? drawing) - "clip "))} + "clips "))} (map (fn [sel] (let [sel (if (:force-even? sel) (layers/force-even sel) @@ -743,7 +743,7 @@ (when (= :layer.type/group (:layer/type sel)) {:layer/type :layer.type/rect :className "layer-in-progress selection" - :strokeDasharray "2,3"}))] + :strokeDasharray "1, 2"}))] (svg-element (assoc sel :key (str (:db/id sel) "-in-progress"))))) sels)))))))) From bb328c40c0925e2983360b6cac31ff4014dacfff Mon Sep 17 00:00:00 2001 From: danny Date: Tue, 16 Jun 2015 19:46:26 -0700 Subject: [PATCH 04/21] apply visual state to pasting text also --- resources/assets/css/components/canvas.less | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/resources/assets/css/components/canvas.less b/resources/assets/css/components/canvas.less index d259d637..f8ba428a 100644 --- a/resources/assets/css/components/canvas.less +++ b/resources/assets/css/components/canvas.less @@ -401,8 +401,12 @@ fill: @color_select; } .clips { + opacity: @opacity_darker_gray; .shape-layer { - stroke: @gray_light; + stroke: @white; stroke-dasharray: 2, 3; } + .text-layer { + fill: @white; + } } From 15ab69f5788d4e03c9686995b19bf5aab3cff5e2 Mon Sep 17 00:00:00 2001 From: Daniel Woelfel Date: Wed, 17 Jun 2015 15:32:02 -0700 Subject: [PATCH 05/21] make sure that clicking from clipboard history works --- src-cljs/frontend/controllers/controls.cljs | 63 +++++++++++---------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/src-cljs/frontend/controllers/controls.cljs b/src-cljs/frontend/controllers/controls.cljs index 5b237179..92726a99 100644 --- a/src-cljs/frontend/controllers/controls.cljs +++ b/src-cljs/frontend/controllers/controls.cljs @@ -1577,7 +1577,7 @@ (assoc-in [:layer-properties-menu :layer :layer/ui-target] (empty-str->nil value)))) (defmethod control-event :layers-pasted - [browser-state message {:keys [layers height width min-x min-y canvas-size] :as layer-data} state] + [browser-state message {:keys [layers height width min-x min-y canvas-size center?] :as layer-data} state] (let [{:keys [entity-ids state]} (frontend.db/get-entity-ids state (count layers)) eid-map (zipmap (map :db/id layers) entity-ids) doc-id (:document/id state) @@ -1585,16 +1585,17 @@ zoom (:zf camera) center-x (+ min-x (/ width 2)) center-y (+ min-y (/ height 2)) - new-x (+ (* (- center-x) zoom) - (/ (:width canvas-size) 2)) - new-y (+ (* (- center-y) zoom) - (/ (:height canvas-size) 2)) - - new-x (get-in state [:mouse :x]) - new-y (get-in state [:mouse :y]) + new-x (if center? + (+ (* (- center-x) zoom) + (/ (:width canvas-size) 2)) + (+ (* (- center-x) zoom) + (get-in state [:mouse :x]))) + new-y (if center? + (+ (* (- center-y) zoom) + (/ (:height canvas-size) 2)) + (+ (* (- center-y) zoom) + (get-in state [:mouse :y]))) [move-x move-y] (cameras/screen->point camera new-x new-y) - move-x (+ (- center-x) (get-in state [:mouse :rx])) - move-y (+ (- center-y) (get-in state [:mouse :ry])) [snap-move-x snap-move-y] (cameras/snap-to-grid (:camera state) move-x move-y) new-layers (mapv (fn [l] (-> l @@ -1608,7 +1609,8 @@ {:snap-x snap-move-x :snap-y snap-move-y :move-x move-x :move-y move-y :snap-paths? true})))) layers)] - #_(-> state + (if center? + (-> state (assoc-in [:clipboard :layers] new-layers) (assoc-in [:selected-eids :selected-eids] (set entity-ids)) (assoc-in [:selected-arrows :selected-arrows] (set (reduce (fn [acc layer] @@ -1617,27 +1619,27 @@ :dest-id (:db/id pointer)}) acc)) #{} new-layers)))) - (-> state - (assoc-in [:mouse-down] true) - (assoc-in [:drawing :clip?] true) - (assoc-in [:drawing :starting-mouse-position] (utils/inspect [(get-in state [:mouse :rx]) - (get-in state [:mouse :ry])])) - (assoc-in [:clipboard :layers] new-layers) - (assoc-in [:drawing :moving?] true) - (assoc-in [:drawing :layers] new-layers) - (assoc-in [:drawing :original-layers] new-layers) - (assoc-in [:editing-eids :editing-eids] (set entity-ids)) - (assoc-in [:selected-eids :selected-eids] (set entity-ids)) - (assoc-in [:selected-arrows :selected-arrows] (set (reduce (fn [acc layer] - (if-let [pointer (:layer/points-to layer)] - (conj acc {:origin-id (:db/id layer) - :dest-id (:db/id pointer)}) - acc)) - #{} new-layers)))))) + (-> state + (dissoc-in [:clipboard :layers]) + (assoc-in [:mouse-down] true) + (update :drawing merge {:clip? true + :starting-mouse-position [(get-in state [:mouse :rx]) + (get-in state [:mouse :ry])] + :moving? true + :layers new-layers + :original-layers new-layers}) + (assoc-in [:editing-eids :editing-eids] (set entity-ids)) + (assoc-in [:selected-eids :selected-eids] (set entity-ids)) + (assoc-in [:selected-arrows :selected-arrows] (set (reduce (fn [acc layer] + (if-let [pointer (:layer/points-to layer)] + (conj acc {:origin-id (:db/id layer) + :dest-id (:db/id pointer)}) + acc)) + #{} new-layers))))))) (defmethod post-control-event! :layers-pasted [browser-state message _ previous-state current-state] - #_(let [db (:db current-state) + (let [db (:db current-state) layers (mapv utils/remove-map-nils (get-in current-state [:clipboard :layers]))] (doseq [layer-group (partition-all 100 layers)] (d/transact! db @@ -2079,7 +2081,8 @@ (let [res (async/ Date: Sat, 20 Jun 2015 19:03:57 -0700 Subject: [PATCH 06/21] send important clips right away --- src-cljs/frontend/core.cljs | 10 ++++++++++ src/pc/http/routes.clj | 4 +++- src/pc/http/sente.clj | 3 +-- src/pc/models/clip.clj | 17 +++++++++++++++-- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src-cljs/frontend/core.cljs b/src-cljs/frontend/core.cljs index 5e8fbbf1..caad5aaa 100644 --- a/src-cljs/frontend/core.cljs +++ b/src-cljs/frontend/core.cljs @@ -1,5 +1,6 @@ (ns frontend.core (:require [cljs.core.async :as async :refer [>! req :session :sente-id) :hostname (profile/hostname)} (when-let [cust (-> req :auth :cust)] - {:cust (cust-model/read-api cust) + {:cust (assoc (cust-model/read-api cust) + :cust/clips (mapv clip-model/read-api (clip-model/find-important-by-cust (pcd/default-db) cust))) :admin? (contains? cust-model/admin-emails (:cust/email cust))}) (when-let [team (-> req :team)] {:team (team-model/public-read-api team)}) diff --git a/src/pc/http/sente.clj b/src/pc/http/sente.clj index 51147150..5bc420f0 100644 --- a/src/pc/http/sente.clj +++ b/src/pc/http/sente.clj @@ -482,8 +482,7 @@ (let [clips (clip-model/find-by-cust (:db req) cust)] (log/infof "sending %s clips to %s" (count clips) (:cust/email cust)) (send-reply req {:clips (map (fn [c] (-> c - (select-keys [:clip/uuid :clip/important?]) - (assoc :clip/s3-url (clipboard/create-presigned-clip-url c)))) + (clip-model/read-api))) clips)})))) (defmethod ws-handler :cust/delete-clip [{:keys [client-id ?data ?reply-fn] :as req}] diff --git a/src/pc/models/clip.clj b/src/pc/models/clip.clj index 2391ab3e..b4f9f94a 100644 --- a/src/pc/models/clip.clj +++ b/src/pc/models/clip.clj @@ -1,7 +1,8 @@ (ns pc.models.clip "cust is what would usually be called user, we call it cust b/c Clojure has already taken the name user in the repl" - (:require [pc.datomic :as pcd] + (:require [pc.http.clipboard :as clipboard] + [pc.datomic :as pcd] [pc.profile :as profile] [datomic.api :refer [db q] :as d])) @@ -9,7 +10,14 @@ (map #(d/entity db (:v %)) (d/datoms db :eavt (:db/id cust) :cust/clips))) -;; TODO: make sure this lookup is fast +(defn find-important-by-cust [db cust] + (map (partial d/entity db) + (d/q '{:find [[?e ...]] + :in [$ ?cust-id] + :where [[?cust-id :cust/clips ?e] + [?e :clip/important? true]]} + db (:db/id cust)))) + (defn find-by-cust-and-uuid [db cust uuid] (d/entity db (d/q '{:find [?e .] :in [$ ?cust-id ?uuid] @@ -23,3 +31,8 @@ :clip/s3-key "iphone" :clip/uuid (d/squuid) :clip/important? true}}) + +(defn read-api [clip] + (-> clip + (select-keys [:clip/uuid :clip/important?]) + (assoc :clip/s3-url (clipboard/create-presigned-clip-url clip)))) From a1db60e7d91070ca4764483b8c714878a55231a6 Mon Sep 17 00:00:00 2001 From: Daniel Woelfel Date: Sat, 20 Jun 2015 19:04:33 -0700 Subject: [PATCH 07/21] get scrolling working --- resources/assets/css/components/canvas.less | 6 + src-cljs/frontend/components/app.cljs | 4 +- src-cljs/frontend/components/canvas.cljs | 167 ++++++++++++++++++-- src-cljs/frontend/controllers/api.cljs | 9 ++ src-cljs/frontend/controllers/controls.cljs | 118 +++++++++++--- 5 files changed, 265 insertions(+), 39 deletions(-) diff --git a/resources/assets/css/components/canvas.less b/resources/assets/css/components/canvas.less index f8ba428a..8fe6f7d6 100644 --- a/resources/assets/css/components/canvas.less +++ b/resources/assets/css/components/canvas.less @@ -409,4 +409,10 @@ .text-layer { fill: @white; } + .active { + fill: @blue; + .shape-layer { + stroke: @blue; + } + } } diff --git a/src-cljs/frontend/components/app.cljs b/src-cljs/frontend/components/app.cljs index 1341ec2c..ef19e41c 100644 --- a/src-cljs/frontend/components/app.cljs +++ b/src-cljs/frontend/components/app.cljs @@ -85,6 +85,7 @@ state/right-click-learned-path [:drawing :in-progress?] [:drawing :relation-in-progress?] + [:drawing :clip?] [:mouse-down] [:layer-properties-menu] [:radial] @@ -92,7 +93,8 @@ [:cust-data] [:document/id] [:keyboard] - [:keyboard-shortcuts]]) + [:keyboard-shortcuts] + [:cust :cust/clips]]) {:react-key "canvas"}) (om/build chat/chat (select-in app [state/chat-opened-path diff --git a/src-cljs/frontend/components/canvas.cljs b/src-cljs/frontend/components/canvas.cljs index 6ba013c1..0d75fe63 100644 --- a/src-cljs/frontend/components/canvas.cljs +++ b/src-cljs/frontend/components/canvas.cljs @@ -710,6 +710,133 @@ (.focus (om/get-node owner "target-input")))} target)))))))))) +(defn pasted [{:keys [clips]} owner] + (reify + om/IDisplayName (display-name [_] "Pasted Layers") + om/IRender + (render [_] + (let [drawing (cursors/observe-drawing owner)] + (apply dom/g #js {:className "layers clips" + :transform (str "translate(" + + (- (first (:current-mouse-position drawing)) + (:clip-scroll drawing 0)) + "," + (second (:current-mouse-position drawing)) + ")")} + #_(dom/line #js {:x1 (:clip-scroll drawing 0) + :x2 (:clip-scroll drawing 0) + :y1 -10000 + :y2 10000 + :stroke "green" + :strokeWidth 5 + }) + (concat #_[(apply dom/g #js {:transform (str "translate(" + (- (+ (/ (:width drawing) 2) + (:min-x drawing))) + "," + (- (+ (/ (:height drawing) 2) + (:min-y drawing))) + ")")} + (map (fn [layer] + (let [layer (if (:force-even? layer) + (layers/force-even layer) + layer) + layer (merge layer + {:layer/current-x (:layer/end-x layer) + :layer/current-y (:layer/end-y layer) + :className "layer-in-progress"})] + (svg-element (assoc layer :key (str (:db/id layer) "-clip"))))) + (:layers drawing)))] + (let [offset (atom 0)] + (for [{:keys [layer-data]} clips + :let [current-offset @offset + center (+ current-offset (/ (:width layer-data) 2)) + scroll (get drawing :clip-scroll 0) + ;;scale (max 0.2 (min 1 (+ 1 (* 0.01 (- (Math/abs (- scroll center))))))) + min-scale (min (/ 100 (max (:width layer-data) + (:height layer-data))) + 0.5) + + ;; scale (max min-scale + ;; (min 1 + ;; (+ 1 (* (- (Math/abs (- scroll current-offset + ;; (/ (:width layer-data) 2)))) + ;; (/ 1 (:width layer-data)))))) + scale (max min-scale + (min 1 + (+ 1 (* (- (Math/abs + (- scroll + current-offset + (/ (:width layer-data) 2)))) + (/ 1 (:width layer-data)))))) + + center (+ current-offset (/ (* scale (:width layer-data)) + 2)) + next-offset (swap! offset + (* scale (+ (:width layer-data))) 40)]] + (dom/g #js {:className (if (< (+ (/ (:width layer-data) + 4) + current-offset) + scroll + (- next-offset + (/ (:width layer-data) + 4) + )) + "active" + "inactive")} + #_(dom/line #js {:x1 center + :x2 center + :y1 -10000 + :y2 10000 + :stroke "red" + :strokeWidth 5 + }) + #_(dom/line #js {:x1 current-offset + :x2 current-offset + :y1 -10000 + :y2 10000 + :stroke "blue" + :strokeWidth 5 + }) + (apply dom/g #js {:transform (str "translate(" + (- current-offset + (* scale (:min-x layer-data))) + "," + (* scale (- (+ (/ (:height layer-data) 2) + (:min-y layer-data)))) + ") " + "scale(" scale ")")} + + + #_(dom/rect #js {:x (:min-x layer-data) + :y (:min-y layer-data) + :width (:width layer-data) + :height (:height layer-data) + :stroke "orange" + :strokeWidth 5 + :fill "none"}) + #_(dom/text #js {:x (+ (:min-x layer-data) + (/ (:width layer-data) + 2)) + :y (- (+ (:min-y layer-data) + (:height layer-data)) + 16) + :fontSize 40 + :stroke "blue" + :fill "blue"} + (- scroll center) ; (int (* 100 scale)) + ) + (map (fn [layer] + (let [layer (if (:force-even? layer) + (layers/force-even layer) + layer) + layer (merge layer + {:layer/current-x (:layer/end-x layer) + :layer/current-y (:layer/end-y layer) + :className "layer-in-progress"})] + (svg-element (assoc layer :key (str (:db/id layer) "-clip"))))) + (:layers layer-data)))))))))))) + (defn in-progress [{:keys [mouse-down]} owner] (reify om/IDisplayName (display-name [_] "In Progress Layers") @@ -727,9 +854,7 @@ (= :layer.type/text (get-in drawing [:layers 0 :layer/type])) nil (:in-progress? drawing) (:layers drawing) :else nil)] - (apply dom/g #js {:className (str "layers " - (when (:clip? drawing) - "clips "))} + (apply dom/g #js {:className "layers"} (map (fn [sel] (let [sel (if (:force-even? sel) (layers/force-even sel) @@ -994,6 +1119,7 @@ camera (cursors/observe-camera owner) in-progress? (settings/drawing-in-progress? app) relation-in-progress? (get-in app [:drawing :relation-in-progress?]) + clip? (get-in app [:drawing :clip?]) tool (get-in app state/current-tool-path) mouse-down? (get-in app [:mouse-down]) right-click-learned? (get-in app state/right-click-learned-path)] @@ -1095,17 +1221,19 @@ :onWheel (fn [event] (let [dx (- (aget event "deltaX")) dy (aget event "deltaY")] - (om/transact! camera (fn [c] - (if (or (aget event "altKey") - ;; http://stackoverflow.com/questions/15416851/catching-mac-trackpad-zoom - ;; ctrl means pinch-to-zoom - (aget event "ctrlKey")) - (cameras/set-zoom c (cameras/screen-event-coords event) - (partial + (* -0.002 - dy - ;; pinch-to-zoom needs a boost to feel natural - (if (.-ctrlKey event) 10 1)))) - (cameras/move-camera c dx (- dy)))))) + (if clip? + (cast! :clip-scrolled {:dx dx :dy dy}) + (om/transact! camera (fn [c] + (if (or (aget event "altKey") + ;; http://stackoverflow.com/questions/15416851/catching-mac-trackpad-zoom + ;; ctrl means pinch-to-zoom + (aget event "ctrlKey")) + (cameras/set-zoom c (cameras/screen-event-coords event) + (partial + (* -0.002 + dy + ;; pinch-to-zoom needs a boost to feel natural + (if (.-ctrlKey event) 10 1)))) + (cameras/move-camera c dx (- dy))))))) (utils/stop-event event))} (defs camera) @@ -1134,8 +1262,15 @@ {:react-key "subscribers-layers"}) (om/build arrows app {:react-key "arrows"}) - - (om/build in-progress (select-keys app [:mouse-down]) {:react-key "in-progress"}))))))) + (cond + (or (get-in app [:drawing :in-progress?]) + (get-in app [:drawing :moving?])) + (om/build in-progress (select-keys app [:mouse-down]) {:react-key "in-progress"}) + + (get-in app [:drawing :clip?]) + (om/build pasted + {:clips (get-in app [:cust :cust/clips])} + {:react-key "pasted"})))))))) (defn needs-copy-paste-hack? [] (not (ua-browser/isChrome))) diff --git a/src-cljs/frontend/controllers/api.cljs b/src-cljs/frontend/controllers/api.cljs index 7151562d..2f6d4cab 100644 --- a/src-cljs/frontend/controllers/api.cljs +++ b/src-cljs/frontend/controllers/api.cljs @@ -89,6 +89,15 @@ (let [sorted-clips (sort clip-compare clips)] (assoc-in state [:cust :cust/clips] sorted-clips))) +(defmethod api-event [:clip-layers :success] + [target message status {:keys [layer-data clip/uuid]} state] + (update-in state [:cust :cust/clips] (fn [clips] + (map (fn [clip] + (if (= uuid (:clip/uuid clip)) + (assoc clip :layer-data layer-data) + clip)) + clips)))) + (defmethod api-event [:team-docs :success] [target message status {:keys [docs]} state] (assoc-in state [:team :recent-docs] docs)) diff --git a/src-cljs/frontend/controllers/controls.cljs b/src-cljs/frontend/controllers/controls.cljs index 92726a99..500126fd 100644 --- a/src-cljs/frontend/controllers/controls.cljs +++ b/src-cljs/frontend/controllers/controls.cljs @@ -774,6 +774,7 @@ (get-in state [:drawing :original-layers]))] (-> state (assoc-in [:drawing :layers] layers) + (assoc-in [:drawing :current-mouse-position] (cameras/screen->point (:camera state) x y)) (assoc-in [:editing-eids :editing-eids] (set (map :db/id layers)))))) (defn pan-canvas [state x y] @@ -788,23 +789,26 @@ [browser-state message [x y {:keys [shift?]}] state] (-> state - (update-mouse x y) - (cond-> (get-in state [:drawing :in-progress?]) - (draw-in-progress-drawing x y {:force-even? shift? - :delta {:x (- x (get-in state [:mouse :x])) - :y (- y (get-in state [:mouse :y]))}}) + (update-mouse x y) + (cond-> (get-in state [:drawing :in-progress?]) + (draw-in-progress-drawing x y {:force-even? shift? + :delta {:x (- x (get-in state [:mouse :x])) + :y (- y (get-in state [:mouse :y]))}}) - (get-in state [:drawing :relation-in-progress?]) - (draw-in-progress-relation x y) + (get-in state [:drawing :relation-in-progress?]) + (draw-in-progress-relation x y) - (get-in state [:drawing :moving?]) - (move-drawings x y) + (get-in state [:drawing :moving?]) + (move-drawings x y) - (keyboard/pan-shortcut-active? state) - ((fn [s] - (if (:mouse-down s) - (pan-canvas s x y) - (assoc-in s [:pan :position] {:x x :y y}))))))) + (get-in state [:drawing :clip?]) + (assoc-in [:drawing :current-mouse-position] (cameras/screen->point (:camera state) x y)) + + (keyboard/pan-shortcut-active? state) + ((fn [s] + (if (:mouse-down s) + (pan-canvas s x y) + (assoc-in s [:pan :position] {:x x :y y}))))))) (defmethod post-control-event! :text-layer-edited [browser-state message _ previous-state current-state] @@ -899,7 +903,7 @@ (and (= button 0) ctrl? (not shift?)) [:open-radial] (and (= button 0) meta? (not shift?)) [:open-radial] (get-in state [:layer-properties-menu :opened?]) [:submit-layer-properties] - (get-in state [:drawing :moving?]) [:drop-layers] + (get-in state [:drawing :clip?]) [:drop-clip] (contains? #{:pen :rect :circle :line :select} tool) [:start-drawing] (and (keyword-identical? tool :text) (not drawing-text?)) [:start-drawing] :else nil)))) @@ -924,7 +928,7 @@ (reduce (fn [s intent] (case intent :finish-text-layer (handle-text-layer-finished s) - :drop-layers (drop-layers s) + :drop-clip (assoc-in s [:drawing :clip?] false) :open-radial (handle-radial-opened s) :start-drawing (handle-drawing-started s x y) :submit-layer-properties (handle-layer-properties-submitted s) @@ -940,7 +944,7 @@ (doseq [intent intents] (case intent :finish-text-layer (handle-text-layer-finished-after previous-state current-state) - :drop-layers (handle-drawing-finalized-after previous-state current-state x y) + :drop-clip nil ;; XXX :open-radial (handle-radial-opened-after previous-state current-state) :start-drawing nil :submit-layer-properties (handle-layer-properties-submitted-after current-state) @@ -1576,7 +1580,7 @@ (-> state (assoc-in [:layer-properties-menu :layer :layer/ui-target] (empty-str->nil value)))) -(defmethod control-event :layers-pasted +#_(defmethod control-event :layers-pasted [browser-state message {:keys [layers height width min-x min-y canvas-size center?] :as layer-data} state] (let [{:keys [entity-ids state]} (frontend.db/get-entity-ids state (count layers)) eid-map (zipmap (map :db/id layers) entity-ids) @@ -1607,7 +1611,10 @@ (set (filter :db/id (map #(update-in % [:db/id] eid-map) dests))))) (#(move-layer % % {:snap-x snap-move-x :snap-y snap-move-y - :move-x move-x :move-y move-y :snap-paths? true})))) + :move-x move-x :move-y move-y :snap-paths? true})) + (#(if center? + (dissoc % :points :layer/current-x :layer/current-y) + %)))) layers)] (if center? (-> state @@ -1625,7 +1632,6 @@ (update :drawing merge {:clip? true :starting-mouse-position [(get-in state [:mouse :rx]) (get-in state [:mouse :ry])] - :moving? true :layers new-layers :original-layers new-layers}) (assoc-in [:editing-eids :editing-eids] (set entity-ids)) @@ -1637,7 +1643,58 @@ acc)) #{} new-layers))))))) -(defmethod post-control-event! :layers-pasted +(defmethod control-event :layers-pasted + [browser-state message {:keys [layers height width min-x min-y canvas-size] :as layer-data} state] + (let [{:keys [entity-ids state]} (frontend.db/get-entity-ids state (count layers)) + eid-map (zipmap (map :db/id layers) entity-ids) + doc-id (:document/id state) + camera (:camera state) + zoom (:zf camera) + center-x (+ min-x (/ width 2)) + center-y (+ min-y (/ height 2)) + new-x (+ (* (- center-x) zoom) + (get-in state [:mouse :x])) + new-y (+ (* (- center-y) zoom) + (get-in state [:mouse :y])) + [move-x move-y] (cameras/screen->point camera new-x new-y) + [snap-move-x snap-move-y] (cameras/snap-to-grid (:camera state) move-x move-y) + new-layers (mapv (fn [l] + (-> l + (assoc :db/id (get eid-map (:db/id l)) + :layer/document doc-id) + (utils/update-when-in [:layer/points-to] (fn [dests] + (set (filter :db/id (map #(update-in % [:db/id] eid-map) dests))))) + #_(#(move-layer % % + {:snap-x snap-move-x :snap-y snap-move-y + :move-x move-x :move-y move-y :snap-paths? true})) + #_(#(if center? + (dissoc % :points :layer/current-x :layer/current-y) + %)))) + layers)] + (-> state + (dissoc-in [:clipboard :layers]) + (assoc-in [:mouse-down] true) + (update :drawing merge {:clip? true + :starting-mouse-position [(get-in state [:mouse :rx]) + (get-in state [:mouse :ry])] + :current-mouse-position [(get-in state [:mouse :rx]) + (get-in state [:mouse :ry])] + :layers new-layers + :width width + :height height + :min-x min-x + :min-y min-y + :original-layers new-layers}) + (assoc-in [:editing-eids :editing-eids] (set entity-ids)) + (assoc-in [:selected-eids :selected-eids] (set entity-ids)) + (assoc-in [:selected-arrows :selected-arrows] (set (reduce (fn [acc layer] + (if-let [pointer (:layer/points-to layer)] + (conj acc {:origin-id (:db/id layer) + :dest-id (:db/id pointer)}) + acc)) + #{} new-layers)))))) + +#_(defmethod post-control-event! :layers-pasted [browser-state message _ previous-state current-state] (let [db (:db current-state) layers (mapv utils/remove-map-nils (get-in current-state [:clipboard :layers]))] @@ -2079,7 +2136,7 @@ (go ;; add xhr=true b/c it will use response from image request, which doesn't have cors headers (let [res (async/ state + (update-in [:drawing :clip-scroll] (fn [scroll] + (max 0 + (min (- (+ (/ (- max-x min-x) + 2) + (* 110 (count (get-in state [:cust :cust/clips])))) + 60) + ((fnil + 0) scroll (+ dx (- dy))))) + ((fnil + 0) scroll (+ dx (- dy)))))))) From 394fb91fb08d08c3ac97753004499ed384094da4 Mon Sep 17 00:00:00 2001 From: Daniel Woelfel Date: Tue, 23 Jun 2015 21:46:21 -0700 Subject: [PATCH 08/21] preserve old clips when we get new clips --- src-cljs/frontend/controllers/api.cljs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src-cljs/frontend/controllers/api.cljs b/src-cljs/frontend/controllers/api.cljs index 2f6d4cab..04573ebf 100644 --- a/src-cljs/frontend/controllers/api.cljs +++ b/src-cljs/frontend/controllers/api.cljs @@ -86,7 +86,21 @@ (defmethod api-event [:cust-clips :success] [target message status {:keys [clips]} state] - (let [sorted-clips (sort clip-compare clips)] + (let [existing-clips (get-in state [:cust :cust/clips]) + all-clips (-> (reduce (fn [acc clip] + (if-let [existing (get-in acc [:existing-uuid->clip (:clip/uuid clip)])] + (-> acc + (update-in [:existing-uuid->clip] dissoc (:clip/uuid clip)) + (update-in [:clips] conj (merge existing clip))) + (update-in acc [:clips] conj clip))) + {:existing-uuid->clip (reduce (fn [acc clip] + (assoc acc (:clip/uuid clip) clip)) + {} existing-clips) + :clips []} + clips) + (#(concat (:clips %) + (vals (:existing-uuid->clip %))))) + sorted-clips (sort clip-compare all-clips)] (assoc-in state [:cust :cust/clips] sorted-clips))) (defmethod api-event [:clip-layers :success] From c6c3ad571f5a41dabb2e248e1d7bb4bc437fb4d0 Mon Sep 17 00:00:00 2001 From: Daniel Woelfel Date: Tue, 23 Jun 2015 21:47:34 -0700 Subject: [PATCH 09/21] get scrolling working --- resources/assets/css/components/canvas.less | 11 +- src-cljs/frontend/components/canvas.cljs | 155 +++++--------------- src-cljs/frontend/controllers/controls.cljs | 46 +++--- src-cljs/frontend/layers.cljs | 43 ++++++ 4 files changed, 116 insertions(+), 139 deletions(-) diff --git a/resources/assets/css/components/canvas.less b/resources/assets/css/components/canvas.less index 8fe6f7d6..4e2c6fb2 100644 --- a/resources/assets/css/components/canvas.less +++ b/resources/assets/css/components/canvas.less @@ -410,9 +410,16 @@ fill: @white; } .active { - fill: @blue; + transition: all 400ms ease-in-out; + fill: @color_select; .shape-layer { - stroke: @blue; + stroke: @color_select; } + .text-layer { + fill: @color_select; + } + } + .inactive { + transition: all 400ms ease-in-out; } } diff --git a/src-cljs/frontend/components/canvas.cljs b/src-cljs/frontend/components/canvas.cljs index 0d75fe63..8683e7b5 100644 --- a/src-cljs/frontend/components/canvas.cljs +++ b/src-cljs/frontend/components/canvas.cljs @@ -715,127 +715,52 @@ om/IDisplayName (display-name [_] "Pasted Layers") om/IRender (render [_] - (let [drawing (cursors/observe-drawing owner)] + (let [drawing (cursors/observe-drawing owner) + normalized-layer-datas (map layers/normalize-pasted-layer-data (cons drawing + (map :layer-data (filter :clip/important? clips)))) + scrolled-layer-index (:scrolled-layer drawing) + clip-scroll (layers/clip-scroll normalized-layer-datas scrolled-layer-index)] (apply dom/g #js {:className "layers clips" :transform (str "translate(" (- (first (:current-mouse-position drawing)) - (:clip-scroll drawing 0)) + 0 ;;clip-scroll + ) "," - (second (:current-mouse-position drawing)) + (- (second (:current-mouse-position drawing)) + ;; don't let cursor overlap shapes + 16) ")")} - #_(dom/line #js {:x1 (:clip-scroll drawing 0) - :x2 (:clip-scroll drawing 0) - :y1 -10000 - :y2 10000 - :stroke "green" - :strokeWidth 5 - }) - (concat #_[(apply dom/g #js {:transform (str "translate(" - (- (+ (/ (:width drawing) 2) - (:min-x drawing))) - "," - (- (+ (/ (:height drawing) 2) - (:min-y drawing))) - ")")} - (map (fn [layer] - (let [layer (if (:force-even? layer) - (layers/force-even layer) - layer) - layer (merge layer - {:layer/current-x (:layer/end-x layer) - :layer/current-y (:layer/end-y layer) - :className "layer-in-progress"})] - (svg-element (assoc layer :key (str (:db/id layer) "-clip"))))) - (:layers drawing)))] - (let [offset (atom 0)] - (for [{:keys [layer-data]} clips - :let [current-offset @offset - center (+ current-offset (/ (:width layer-data) 2)) - scroll (get drawing :clip-scroll 0) - ;;scale (max 0.2 (min 1 (+ 1 (* 0.01 (- (Math/abs (- scroll center))))))) - min-scale (min (/ 100 (max (:width layer-data) - (:height layer-data))) - 0.5) - - ;; scale (max min-scale - ;; (min 1 - ;; (+ 1 (* (- (Math/abs (- scroll current-offset - ;; (/ (:width layer-data) 2)))) - ;; (/ 1 (:width layer-data)))))) - scale (max min-scale - (min 1 - (+ 1 (* (- (Math/abs - (- scroll - current-offset - (/ (:width layer-data) 2)))) - (/ 1 (:width layer-data)))))) - - center (+ current-offset (/ (* scale (:width layer-data)) - 2)) - next-offset (swap! offset + (* scale (+ (:width layer-data))) 40)]] - (dom/g #js {:className (if (< (+ (/ (:width layer-data) - 4) - current-offset) - scroll - (- next-offset - (/ (:width layer-data) - 4) - )) - "active" - "inactive")} - #_(dom/line #js {:x1 center - :x2 center - :y1 -10000 - :y2 10000 - :stroke "red" - :strokeWidth 5 - }) - #_(dom/line #js {:x1 current-offset - :x2 current-offset - :y1 -10000 - :y2 10000 - :stroke "blue" - :strokeWidth 5 - }) - (apply dom/g #js {:transform (str "translate(" - (- current-offset - (* scale (:min-x layer-data))) - "," - (* scale (- (+ (/ (:height layer-data) 2) - (:min-y layer-data)))) - ") " - "scale(" scale ")")} - - - #_(dom/rect #js {:x (:min-x layer-data) - :y (:min-y layer-data) - :width (:width layer-data) - :height (:height layer-data) - :stroke "orange" - :strokeWidth 5 - :fill "none"}) - #_(dom/text #js {:x (+ (:min-x layer-data) - (/ (:width layer-data) - 2)) - :y (- (+ (:min-y layer-data) - (:height layer-data)) - 16) - :fontSize 40 - :stroke "blue" - :fill "blue"} - (- scroll center) ; (int (* 100 scale)) - ) - (map (fn [layer] - (let [layer (if (:force-even? layer) - (layers/force-even layer) - layer) - layer (merge layer - {:layer/current-x (:layer/end-x layer) - :layer/current-y (:layer/end-y layer) - :className "layer-in-progress"})] - (svg-element (assoc layer :key (str (:db/id layer) "-clip"))))) - (:layers layer-data)))))))))))) + (map-indexed (fn [i layer-data] + (let [active? (= i scrolled-layer-index) + scale (if active? + 1 + (layers/pasted-inactive-scale layer-data))] + (apply dom/g #js {:className (if active? + "active" + "inactive") + :transform (str "translate(" + (- (layers/clip-offset normalized-layer-datas scrolled-layer-index i) + (* scale (:min-x layer-data))) + "," + (* scale (- (+ (/ (:height layer-data) 2) + (:min-y layer-data)))) + ") " + "scale(" scale ")")} + + + (map (fn [layer] + (let [layer (if (:force-even? layer) + (layers/force-even layer) + layer) + layer (merge layer + {:layer/current-x (:layer/end-x layer) + :layer/current-y (:layer/end-y layer) + :className "layer-in-progress"})] + (svg-element (assoc layer :key (str (:db/id layer) "-clip") + :vectorEffect "non-scaling-stroke")))) + (:layers layer-data))))) + normalized-layer-datas)))))) (defn in-progress [{:keys [mouse-down]} owner] (reify diff --git a/src-cljs/frontend/controllers/controls.cljs b/src-cljs/frontend/controllers/controls.cljs index 500126fd..5fcf3eec 100644 --- a/src-cljs/frontend/controllers/controls.cljs +++ b/src-cljs/frontend/controllers/controls.cljs @@ -1663,22 +1663,19 @@ (assoc :db/id (get eid-map (:db/id l)) :layer/document doc-id) (utils/update-when-in [:layer/points-to] (fn [dests] - (set (filter :db/id (map #(update-in % [:db/id] eid-map) dests))))) - #_(#(move-layer % % - {:snap-x snap-move-x :snap-y snap-move-y - :move-x move-x :move-y move-y :snap-paths? true})) - #_(#(if center? - (dissoc % :points :layer/current-x :layer/current-y) - %)))) + (set (filter :db/id (map #(update-in % [:db/id] eid-map) dests))))))) layers)] (-> state (dissoc-in [:clipboard :layers]) (assoc-in [:mouse-down] true) + ;; has to account for no clips + (assoc-in [:drawing :clip-scroll] (/ width 2)) + (assoc-in [:drawing :scrolled-layer] 0) (update :drawing merge {:clip? true :starting-mouse-position [(get-in state [:mouse :rx]) (get-in state [:mouse :ry])] :current-mouse-position [(get-in state [:mouse :rx]) - (get-in state [:mouse :ry])] + (get-in state [:mouse :ry])] :layers new-layers :width width :height height @@ -2154,17 +2151,22 @@ (defmethod control-event :clip-scrolled [browser-state message {:keys [dx dy]} state] - (let [layers (get-in state [:drawing :layers]) - xs (concat (map :layer/current-x layers) - (map :layer/start-x layers)) - max-x (apply max xs) - min-x (apply min xs)] - (-> state - (update-in [:drawing :clip-scroll] (fn [scroll] - (max 0 - (min (- (+ (/ (- max-x min-x) - 2) - (* 110 (count (get-in state [:cust :cust/clips])))) - 60) - ((fnil + 0) scroll (+ dx (- dy))))) - ((fnil + 0) scroll (+ dx (- dy)))))))) + (let [layer-data-count (+ (if (seq (get-in state [:drawing :layers])) + 1 + 0) + (count (filter :clip/important? (get-in state [:cust :cust/clips])))) + up? (pos? (+ dx (- dy))) + scrolled-layer (if up? + (if (= layer-data-count (inc (get-in state [:drawing :scrolled-layer]))) + (get-in state [:drawing :scrolled-layer]) + (inc (get-in state [:drawing :scrolled-layer]))) + (if (= 0 (get-in state [:drawing :scrolled-layer])) + 0 + (dec (get-in state [:drawing :scrolled-layer])))) + scroll-offset (+ (get-in state [:drawing :scroll-offset]) + (+ dx (- dy)))] + (if (> 15 (Math/abs scroll-offset)) + (update-in state [:drawing :scroll-offset] (fnil + 0) dx (- dy)) + (-> state + (assoc-in [:drawing :scroll-offset] 0) + (assoc-in [:drawing :scrolled-layer] scrolled-layer))))) diff --git a/src-cljs/frontend/layers.cljs b/src-cljs/frontend/layers.cljs index 810bfd0f..32401ed3 100644 --- a/src-cljs/frontend/layers.cljs +++ b/src-cljs/frontend/layers.cljs @@ -270,3 +270,46 @@ (defn calc-text-end-y [layer] (- (:layer/start-y layer) (:layer/font-size layer state/default-font-size))) + +(def pasted-unscaled-width 150) +(def pasted-scaled-width 100) +(def pasted-padding 40) + +(defn normalize-pasted-layer-data + "Makes sure that the layer-data is larger than the required minimum by expanding the width." + [layer-data] + (if (< pasted-unscaled-width (:width layer-data)) + layer-data + (let [width-delta (- pasted-unscaled-width (:width layer-data))] + (-> layer-data + (update :min-x (fn [min-x] + (- min-x + (/ width-delta + 2)))) + (assoc :width pasted-unscaled-width))))) + +(defn pasted-inactive-scale [normalized-layer-data] + (/ pasted-scaled-width + (:width normalized-layer-data))) + +;; remember that it's scrolling to the center +(defn clip-scroll [normalized-layer-datas scrolled-layer-index] + (- (/ (:width (nth normalized-layer-datas scrolled-layer-index)) + 2))) + +(defn clip-offset [normalized-layer-datas scrolled-layer-index layer-index] + (cond (= scrolled-layer-index layer-index) + (clip-scroll normalized-layer-datas layer-index) + + (> scrolled-layer-index layer-index) + (- (clip-scroll normalized-layer-datas scrolled-layer-index) + (* (- scrolled-layer-index layer-index) + (+ pasted-scaled-width pasted-padding))) + + :else + (+ (clip-scroll normalized-layer-datas scrolled-layer-index) + (:width (nth normalized-layer-datas scrolled-layer-index)) + (* (- layer-index scrolled-layer-index) + pasted-padding) + (* (dec (- layer-index scrolled-layer-index)) + pasted-scaled-width )))) From a3b8d5605eeaef347599c659cbda955c87c662ca Mon Sep 17 00:00:00 2001 From: Daniel Woelfel Date: Tue, 23 Jun 2015 22:30:23 -0700 Subject: [PATCH 10/21] make dropping clips mostly work --- src-cljs/frontend/controllers/controls.cljs | 50 ++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/src-cljs/frontend/controllers/controls.cljs b/src-cljs/frontend/controllers/controls.cljs index 5fcf3eec..4a503f85 100644 --- a/src-cljs/frontend/controllers/controls.cljs +++ b/src-cljs/frontend/controllers/controls.cljs @@ -936,6 +936,54 @@ s)) new-state intents)))) +(defn something-something [{:keys [layers height width min-x min-y canvas-size center?] :as layer-data} state] + (let [{:keys [entity-ids state]} (frontend.db/get-entity-ids state (count layers)) + eid-map (zipmap (map :db/id layers) entity-ids) + doc-id (:document/id state) + camera (:camera state) + zoom (:zf camera) + center-x (+ min-x (/ width 2)) + center-y (+ min-y (/ height 2)) + new-x (+ (* (- center-x) zoom) + (get-in state [:mouse :x])) + new-y (+ (* (- center-y) zoom) + (get-in state [:mouse :y])) + [move-x move-y] (cameras/screen->point camera new-x new-y) + [snap-move-x snap-move-y] [move-x move-y] + new-layers (mapv (fn [l] + (-> l + (assoc :layer/ancestor (:db/id l) + :db/id (get eid-map (:db/id l)) + :layer/document doc-id + :points (when (:layer/path l) (parse-points-from-path (:layer/path l)))) + (utils/update-when-in [:layer/points-to] (fn [dests] + (set (filter :db/id (map #(update-in % [:db/id] eid-map) dests))))) + (#(move-layer % % + {:snap-x snap-move-x :snap-y snap-move-y + :move-x move-x :move-y move-y :snap-paths? true})) + (dissoc :points :layer/current-x :layer/current-y))) + layers)] + new-layers)) + +(defn handle-drop-clip-after [previous-state current-state] + (let [db (:db current-state) + layer-datas (cons (:drawing previous-state) + (map :layer-data (filter :clip/important? (get-in previous-state [:cust :cust/clips])))) + [start-x start-y] (get-in previous-state [:drawing :current-mouse-position]) + [end-x end-y] (get-in previous-state [:drawing :starting-mouse-position]) + layer-index (get-in previous-state [:drawing :scrolled-layer]) + layer-data (update (layers/normalize-pasted-layer-data (nth layer-datas layer-index)) + :min-y + + 16) + + layers (something-something layer-data previous-state)] + (doseq [layer-group (partition-all 100 layers)] + (d/transact! db + (if (= :read (:max-document-scope current-state)) + (map #(assoc % :unsaved true) layer-group) + layer-group) + {:can-undo? true})))) + (defmethod post-control-event! :mouse-depressed [browser-state message [x y {:keys [button ctrl? shift? meta? outside-canvas?]}] previous-state current-state] (when-not (empty? (:frontend-id-state previous-state)) @@ -944,7 +992,7 @@ (doseq [intent intents] (case intent :finish-text-layer (handle-text-layer-finished-after previous-state current-state) - :drop-clip nil ;; XXX + :drop-clip (handle-drop-clip-after previous-state current-state) :open-radial (handle-radial-opened-after previous-state current-state) :start-drawing nil :submit-layer-properties (handle-layer-properties-submitted-after current-state) From 6a4660dcf5a5be96f8777a166ece0d1d87c09c84 Mon Sep 17 00:00:00 2001 From: Daniel Woelfel Date: Tue, 23 Jun 2015 23:04:42 -0700 Subject: [PATCH 11/21] lazy-load clips --- src-cljs/frontend/controllers/controls.cljs | 13 +++++++++++++ src-cljs/frontend/core.cljs | 9 --------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src-cljs/frontend/controllers/controls.cljs b/src-cljs/frontend/controllers/controls.cljs index 4a503f85..269b75b1 100644 --- a/src-cljs/frontend/controllers/controls.cljs +++ b/src-cljs/frontend/controllers/controls.cljs @@ -1750,6 +1750,19 @@ layer-group) {:can-undo? true})))) +(defmethod post-control-event! :layers-pasted + [browser-state message _ previous-state current-state] + (doseq [clip (filter #(and (:clip/important? %) + (empty? (:layer-data %))) + (get-in current-state [:cust :cust/clips]))] + (go + (let [res (async/ state diff --git a/src-cljs/frontend/core.cljs b/src-cljs/frontend/core.cljs index caad5aaa..bf7872ac 100644 --- a/src-cljs/frontend/core.cljs +++ b/src-cljs/frontend/core.cljs @@ -314,15 +314,6 @@ (async/tap (:api-mult comms) api-tap) (async/tap (:errors-mult comms) errors-tap) - (doseq [clip (get-in @state [:cust :cust/clips])] - (go - (let [res (async/ Date: Wed, 24 Jun 2015 14:32:09 -0700 Subject: [PATCH 12/21] move the cursor adjustment to normalize-layers --- src-cljs/frontend/components/canvas.cljs | 9 ++------- src-cljs/frontend/controllers/controls.cljs | 5 +---- src-cljs/frontend/layers.cljs | 6 ++---- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src-cljs/frontend/components/canvas.cljs b/src-cljs/frontend/components/canvas.cljs index 8683e7b5..3bc5b808 100644 --- a/src-cljs/frontend/components/canvas.cljs +++ b/src-cljs/frontend/components/canvas.cljs @@ -722,14 +722,9 @@ clip-scroll (layers/clip-scroll normalized-layer-datas scrolled-layer-index)] (apply dom/g #js {:className "layers clips" :transform (str "translate(" - - (- (first (:current-mouse-position drawing)) - 0 ;;clip-scroll - ) + (first (:current-mouse-position drawing)) "," - (- (second (:current-mouse-position drawing)) - ;; don't let cursor overlap shapes - 16) + (second (:current-mouse-position drawing)) ")")} (map-indexed (fn [i layer-data] (let [active? (= i scrolled-layer-index) diff --git a/src-cljs/frontend/controllers/controls.cljs b/src-cljs/frontend/controllers/controls.cljs index 269b75b1..a91712f7 100644 --- a/src-cljs/frontend/controllers/controls.cljs +++ b/src-cljs/frontend/controllers/controls.cljs @@ -972,10 +972,7 @@ [start-x start-y] (get-in previous-state [:drawing :current-mouse-position]) [end-x end-y] (get-in previous-state [:drawing :starting-mouse-position]) layer-index (get-in previous-state [:drawing :scrolled-layer]) - layer-data (update (layers/normalize-pasted-layer-data (nth layer-datas layer-index)) - :min-y - + 16) - + layer-data (layers/normalize-pasted-layer-data (nth layer-datas layer-index)) layers (something-something layer-data previous-state)] (doseq [layer-group (partition-all 100 layers)] (d/transact! db diff --git a/src-cljs/frontend/layers.cljs b/src-cljs/frontend/layers.cljs index 32401ed3..d75f13f3 100644 --- a/src-cljs/frontend/layers.cljs +++ b/src-cljs/frontend/layers.cljs @@ -282,10 +282,8 @@ layer-data (let [width-delta (- pasted-unscaled-width (:width layer-data))] (-> layer-data - (update :min-x (fn [min-x] - (- min-x - (/ width-delta - 2)))) + (update :min-x - (/ width-delta 2)) + (update :min-y + 16) ; don't let cursor overlap shapes (assoc :width pasted-unscaled-width))))) (defn pasted-inactive-scale [normalized-layer-data] From c02d63beadb6db51d20f84139daec7646a14fb7a Mon Sep 17 00:00:00 2001 From: Daniel Woelfel Date: Wed, 24 Jun 2015 14:49:51 -0700 Subject: [PATCH 13/21] snap to grid on clips --- src-cljs/frontend/components/canvas.cljs | 29 +++++++++++---------- src-cljs/frontend/controllers/controls.cljs | 5 +++- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src-cljs/frontend/components/canvas.cljs b/src-cljs/frontend/components/canvas.cljs index 3bc5b808..d8146b3d 100644 --- a/src-cljs/frontend/components/canvas.cljs +++ b/src-cljs/frontend/components/canvas.cljs @@ -716,34 +716,35 @@ om/IRender (render [_] (let [drawing (cursors/observe-drawing owner) + camera (cursors/observe-camera owner) normalized-layer-datas (map layers/normalize-pasted-layer-data (cons drawing (map :layer-data (filter :clip/important? clips)))) scrolled-layer-index (:scrolled-layer drawing) - clip-scroll (layers/clip-scroll normalized-layer-datas scrolled-layer-index)] + clip-scroll (layers/clip-scroll normalized-layer-datas scrolled-layer-index) + [mouse-x mouse-y] (apply cameras/snap-to-grid camera (:current-mouse-position drawing))] (apply dom/g #js {:className "layers clips" - :transform (str "translate(" - (first (:current-mouse-position drawing)) - "," - (second (:current-mouse-position drawing)) - ")")} + :transform (str "translate(" mouse-x "," mouse-y ")")} (map-indexed (fn [i layer-data] (let [active? (= i scrolled-layer-index) scale (if active? 1 - (layers/pasted-inactive-scale layer-data))] + (layers/pasted-inactive-scale layer-data)) + translate-x (- (layers/clip-offset normalized-layer-datas scrolled-layer-index i) + (* scale (:min-x layer-data))) + translate-y (* scale (- (+ (/ (:height layer-data) 2) + (:min-y layer-data)))) + [translate-x translate-y] (cameras/snap-to-grid camera translate-x translate-y) + ] (apply dom/g #js {:className (if active? "active" "inactive") :transform (str "translate(" - (- (layers/clip-offset normalized-layer-datas scrolled-layer-index i) - (* scale (:min-x layer-data))) + translate-x "," - (* scale (- (+ (/ (:height layer-data) 2) - (:min-y layer-data)))) + translate-y ") " - "scale(" scale ")")} - - + "scale(" scale ")") + :key i} (map (fn [layer] (let [layer (if (:force-even? layer) (layers/force-even layer) diff --git a/src-cljs/frontend/controllers/controls.cljs b/src-cljs/frontend/controllers/controls.cljs index a91712f7..60010e65 100644 --- a/src-cljs/frontend/controllers/controls.cljs +++ b/src-cljs/frontend/controllers/controls.cljs @@ -944,12 +944,15 @@ zoom (:zf camera) center-x (+ min-x (/ width 2)) center-y (+ min-y (/ height 2)) + [mouse-x mouse-y] (cameras/snap-to-grid camera + (get-in state [:mouse :x]) + (get-in state [:mouse :y])) new-x (+ (* (- center-x) zoom) (get-in state [:mouse :x])) new-y (+ (* (- center-y) zoom) (get-in state [:mouse :y])) [move-x move-y] (cameras/screen->point camera new-x new-y) - [snap-move-x snap-move-y] [move-x move-y] + [snap-move-x snap-move-y] (cameras/snap-to-grid camera move-x move-y) new-layers (mapv (fn [l] (-> l (assoc :layer/ancestor (:db/id l) From cb1de7ab8a49afaf1875d42866106a9198864055 Mon Sep 17 00:00:00 2001 From: Daniel Woelfel Date: Wed, 24 Jun 2015 16:30:17 -0700 Subject: [PATCH 14/21] scroll clips with arrow keys --- src-cljs/frontend/controllers/controls.cljs | 114 +++++++++++++------- 1 file changed, 75 insertions(+), 39 deletions(-) diff --git a/src-cljs/frontend/controllers/controls.cljs b/src-cljs/frontend/controllers/controls.cljs index 60010e65..fb3b96a0 100644 --- a/src-cljs/frontend/controllers/controls.cljs +++ b/src-cljs/frontend/controllers/controls.cljs @@ -257,24 +257,62 @@ (cond-> (= :layer.type/path (:layer/type layer)) (assoc :layer/path (svg/points->path (nudge-points (parse-points-from-path (:layer/path layer)) x y)))))) +(defn scroll-clips [state up?] + (let [layer-data-count (+ (if (seq (get-in state [:drawing :layers])) + 1 + 0) + (count (filter :clip/important? (get-in state [:cust :cust/clips])))) + scrolled-layer (if up? + (if (= layer-data-count (inc (get-in state [:drawing :scrolled-layer]))) + (get-in state [:drawing :scrolled-layer]) + (inc (get-in state [:drawing :scrolled-layer]))) + (if (= 0 (get-in state [:drawing :scrolled-layer])) + 0 + (dec (get-in state [:drawing :scrolled-layer]))))] + (-> state + (assoc-in [:drawing :scroll-offset] 0) + (assoc-in [:drawing :scrolled-layer] scrolled-layer)))) + +(defn maybe-scroll-clips [state up?] + (if (get-in state [:drawing :clip?]) + (scroll-clips state up?) + state)) + +(defmethod handle-keyboard-shortcut :nudge-shapes-left + [state shortcut-name key-set] + (maybe-scroll-clips state false)) + +(defmethod handle-keyboard-shortcut :nudge-shapes-right + [state shortcut-name key-set] + (maybe-scroll-clips state true)) + +(defmethod handle-keyboard-shortcut :nudge-shapes-up + [state shortcut-name key-set] + (maybe-scroll-clips state false)) + +(defmethod handle-keyboard-shortcut :nudge-shapes-down + [state shortcut-name key-set] + (maybe-scroll-clips state true)) + (defn nudge-shapes [state key-set direction] - (let [db (:db state) - layers (map (partial d/entity @db) (get-in state [:selected-eids :selected-eids])) - increment (cameras/grid-size->snap-increment (cameras/grid-width (:camera state))) - shift? (contains? key-set "shift") - x (* (if shift? 10 1) - (case direction - :left (- increment) - :right increment - 0)) - y (* (if shift? 10 1) - (case direction - :up (- increment) - :down increment - 0))] - (when (seq layers) - (d/transact! db (mapv #(nudge-layer % {:x x :y y}) layers) - {:can-undo? true})))) + (when-not (get-in state [:drawing :clip?]) + (let [db (:db state) + layers (map (partial d/entity @db) (get-in state [:selected-eids :selected-eids])) + increment (cameras/grid-size->snap-increment (cameras/grid-width (:camera state))) + shift? (contains? key-set "shift") + x (* (if shift? 10 1) + (case direction + :left (- increment) + :right increment + 0)) + y (* (if shift? 10 1) + (case direction + :up (- increment) + :down increment + 0))] + (when (seq layers) + (d/transact! db (mapv #(nudge-layer % {:x x :y y}) layers) + {:can-undo? true}))))) (defmethod handle-keyboard-shortcut-after :nudge-shapes-left [state shortcut-name key-set] @@ -371,6 +409,26 @@ key-set))) (maybe-notify-subscribers! previous-state current-state nil nil)) +(defmethod control-event :clip-scrolled + [browser-state message {:keys [dx dy]} state] + (let [layer-data-count (+ (if (seq (get-in state [:drawing :layers])) + 1 + 0) + (count (filter :clip/important? (get-in state [:cust :cust/clips])))) + up? (pos? (+ dx (- dy))) + scrolled-layer (if up? + (if (= layer-data-count (inc (get-in state [:drawing :scrolled-layer]))) + (get-in state [:drawing :scrolled-layer]) + (inc (get-in state [:drawing :scrolled-layer]))) + (if (= 0 (get-in state [:drawing :scrolled-layer])) + 0 + (dec (get-in state [:drawing :scrolled-layer])))) + scroll-offset (+ (get-in state [:drawing :scroll-offset]) + (+ dx (- dy)))] + (if (> 15 (Math/abs scroll-offset)) + (update-in state [:drawing :scroll-offset] (fnil + 0) dx (- dy)) + (scroll-clips state up?)))) + (defn update-mouse [state x y] (if (and x y) (let [[rx ry] (cameras/screen->point (:camera state) x y)] @@ -2209,25 +2267,3 @@ (:document/id current-state)) "plan") :replace-token? true}]))))) - -(defmethod control-event :clip-scrolled - [browser-state message {:keys [dx dy]} state] - (let [layer-data-count (+ (if (seq (get-in state [:drawing :layers])) - 1 - 0) - (count (filter :clip/important? (get-in state [:cust :cust/clips])))) - up? (pos? (+ dx (- dy))) - scrolled-layer (if up? - (if (= layer-data-count (inc (get-in state [:drawing :scrolled-layer]))) - (get-in state [:drawing :scrolled-layer]) - (inc (get-in state [:drawing :scrolled-layer]))) - (if (= 0 (get-in state [:drawing :scrolled-layer])) - 0 - (dec (get-in state [:drawing :scrolled-layer])))) - scroll-offset (+ (get-in state [:drawing :scroll-offset]) - (+ dx (- dy)))] - (if (> 15 (Math/abs scroll-offset)) - (update-in state [:drawing :scroll-offset] (fnil + 0) dx (- dy)) - (-> state - (assoc-in [:drawing :scroll-offset] 0) - (assoc-in [:drawing :scrolled-layer] scrolled-layer))))) From 8c701bd56688283a8ec5c032c01e6b8babc63648 Mon Sep 17 00:00:00 2001 From: Daniel Woelfel Date: Wed, 24 Jun 2015 16:30:34 -0700 Subject: [PATCH 15/21] don't prevent zooming when clips are open --- src-cljs/frontend/components/canvas.cljs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src-cljs/frontend/components/canvas.cljs b/src-cljs/frontend/components/canvas.cljs index d8146b3d..99e96de4 100644 --- a/src-cljs/frontend/components/canvas.cljs +++ b/src-cljs/frontend/components/canvas.cljs @@ -1141,14 +1141,15 @@ (.stopPropagation event)) :onWheel (fn [event] (let [dx (- (aget event "deltaX")) - dy (aget event "deltaY")] - (if clip? + dy (aget event "deltaY") + zoom? (or (aget event "altKey") + ;; http://stackoverflow.com/questions/15416851/catching-mac-trackpad-zoom + ;; ctrl means pinch-to-zoom + (aget event "ctrlKey"))] + (if (and clip? (not zoom?)) (cast! :clip-scrolled {:dx dx :dy dy}) (om/transact! camera (fn [c] - (if (or (aget event "altKey") - ;; http://stackoverflow.com/questions/15416851/catching-mac-trackpad-zoom - ;; ctrl means pinch-to-zoom - (aget event "ctrlKey")) + (if zoom? (cameras/set-zoom c (cameras/screen-event-coords event) (partial + (* -0.002 dy From 629448279ad2ffbe5b4be3b8dcbcc76b07fd978f Mon Sep 17 00:00:00 2001 From: Daniel Woelfel Date: Thu, 25 Jun 2015 17:27:35 -0700 Subject: [PATCH 16/21] disable pointer-events when clip is in progress --- resources/assets/css/components/canvas.less | 6 ++++++ src-cljs/frontend/components/canvas.cljs | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/resources/assets/css/components/canvas.less b/resources/assets/css/components/canvas.less index 4e2c6fb2..7327aceb 100644 --- a/resources/assets/css/components/canvas.less +++ b/resources/assets/css/components/canvas.less @@ -423,3 +423,9 @@ transition: all 400ms ease-in-out; } } + +.clip-in-progress { + .layer-handle { + pointer-events: none; + } +} diff --git a/src-cljs/frontend/components/canvas.cljs b/src-cljs/frontend/components/canvas.cljs index 99e96de4..dcf66680 100644 --- a/src-cljs/frontend/components/canvas.cljs +++ b/src-cljs/frontend/components/canvas.cljs @@ -1065,7 +1065,9 @@ " relation-in-progress ") (when-not right-click-learned? - "radial-not-learned")) + "radial-not-learned ") + + (when clip? "clip-in-progress ")) :onTouchStart (fn [event] (let [touches (.-touches event)] (cond From e72e2fee0cb1163526b115c89c2ceb52021203d2 Mon Sep 17 00:00:00 2001 From: Daniel Woelfel Date: Thu, 25 Jun 2015 17:30:01 -0700 Subject: [PATCH 17/21] don't mess with stroke-dasharray for in-progress --- src-cljs/frontend/components/canvas.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-cljs/frontend/components/canvas.cljs b/src-cljs/frontend/components/canvas.cljs index dcf66680..f31ef7f6 100644 --- a/src-cljs/frontend/components/canvas.cljs +++ b/src-cljs/frontend/components/canvas.cljs @@ -789,7 +789,7 @@ (when (= :layer.type/group (:layer/type sel)) {:layer/type :layer.type/rect :className "layer-in-progress selection" - :strokeDasharray "1, 2"}))] + :strokeDasharray "2,3"}))] (svg-element (assoc sel :key (str (:db/id sel) "-in-progress"))))) sels)))))))) From 24b8d1eb2db30d47c3e1a7c9bdcd3715fb288bbb Mon Sep 17 00:00:00 2001 From: Daniel Woelfel Date: Thu, 25 Jun 2015 17:33:29 -0700 Subject: [PATCH 18/21] fix moving --- src-cljs/frontend/components/app.cljs | 1 + 1 file changed, 1 insertion(+) diff --git a/src-cljs/frontend/components/app.cljs b/src-cljs/frontend/components/app.cljs index ef19e41c..1d962924 100644 --- a/src-cljs/frontend/components/app.cljs +++ b/src-cljs/frontend/components/app.cljs @@ -85,6 +85,7 @@ state/right-click-learned-path [:drawing :in-progress?] [:drawing :relation-in-progress?] + [:drawing :moving?] [:drawing :clip?] [:mouse-down] [:layer-properties-menu] From 356a3738f02b7f331dacd5535fdf4f39cb429f31 Mon Sep 17 00:00:00 2001 From: Daniel Woelfel Date: Mon, 29 Jun 2015 17:43:24 -0700 Subject: [PATCH 19/21] better way to handle mouse position --- src-cljs/frontend/components/canvas.cljs | 11 ++++-- src-cljs/frontend/components/drawing.cljs | 44 ++++++++++----------- src-cljs/frontend/controllers/controls.cljs | 43 ++++++++++---------- 3 files changed, 51 insertions(+), 47 deletions(-) diff --git a/src-cljs/frontend/components/canvas.cljs b/src-cljs/frontend/components/canvas.cljs index f31ef7f6..f3f96549 100644 --- a/src-cljs/frontend/components/canvas.cljs +++ b/src-cljs/frontend/components/canvas.cljs @@ -477,6 +477,7 @@ (common/svg-icon icon {:svg-props {:height 16 :width 16 :className "mouse-tool" + ;; TODO: should subscriber mouse position be a map? :x (- (first (:mouse-position subscriber)) (- 16)) :y (- (last (:mouse-position subscriber)) 8) :key (:client-id subscriber)} @@ -501,6 +502,7 @@ (common/svg-icon (subscriber-cursor-icon (:tool subscriber)) {:svg-props {:height 16 :width 16 :className "mouse-tool" + ;; TODO: should subscriber mouse position be a map? :x (- (first (:mouse-position subscriber)) 8) :y (- (last (:mouse-position subscriber)) 8) :key (:client-id subscriber)} @@ -721,7 +723,9 @@ (map :layer-data (filter :clip/important? clips)))) scrolled-layer-index (:scrolled-layer drawing) clip-scroll (layers/clip-scroll normalized-layer-datas scrolled-layer-index) - [mouse-x mouse-y] (apply cameras/snap-to-grid camera (:current-mouse-position drawing))] + [mouse-x mouse-y] (cameras/snap-to-grid camera + (:rx (:current-mouse-position drawing)) + (:ry (:current-mouse-position drawing)))] (apply dom/g #js {:className "layers clips" :transform (str "translate(" mouse-x "," mouse-y ")")} (map-indexed (fn [i layer-data] @@ -731,8 +735,9 @@ (layers/pasted-inactive-scale layer-data)) translate-x (- (layers/clip-offset normalized-layer-datas scrolled-layer-index i) (* scale (:min-x layer-data))) - translate-y (* scale (- (+ (/ (:height layer-data) 2) - (:min-y layer-data)))) + translate-y (* scale + (- (+ (/ (:height layer-data) 2) + (:min-y layer-data)))) [translate-x translate-y] (cameras/snap-to-grid camera translate-x translate-y) ] (apply dom/g #js {:className (if active? diff --git a/src-cljs/frontend/components/drawing.cljs b/src-cljs/frontend/components/drawing.cljs index 8a0d5c69..05bbd147 100644 --- a/src-cljs/frontend/components/drawing.cljs +++ b/src-cljs/frontend/components/drawing.cljs @@ -27,8 +27,8 @@ ((om/get-shared owner :cast!) :subscriber-updated {:client-id (:client-id (:bot tick-state)) :fields (merge (:bot tick-state) {:mouse-position nil - :tool nil - :show-mouse? false})}))) + :tool nil + :show-mouse? false})}))) (annotate-keyframes tick))) (defn move-mouse [tick-state {:keys [start-tick end-tick start-x end-x start-y end-y tool] @@ -46,8 +46,8 @@ ((om/get-shared owner :cast!) :subscriber-updated {:client-id (:client-id (:bot tick-state)) :fields (merge (:bot tick-state) {:mouse-position [ex ey] - :show-mouse? true - :tool tool})}))))) + :show-mouse? true + :tool tool})}))))) tick-state (range 0 (inc (- end-tick start-tick)))) (annotate-keyframes end-tick))) @@ -92,11 +92,11 @@ ((om/get-shared owner :cast!) :subscriber-updated {:client-id (:client-id (:bot tick-state)) :fields (merge (:bot tick-state) {:mouse-position [ex ey] - :show-mouse? true - :layers [(assoc base-layer - :layer/current-x ex - :layer/current-y ey)] - :tool tool})}))))) + :show-mouse? true + :layers [(assoc base-layer + :layer/current-x ex + :layer/current-y ey)] + :tool tool})}))))) tick-state (range 0 (inc (- end-tick start-tick pause-ticks)))) (add-tick end-tick @@ -150,11 +150,11 @@ ((om/get-shared owner :cast!) :subscriber-updated {:client-id (:client-id (:bot tick-state)) :fields (merge (:bot tick-state) {:mouse-position [(+ start-x move-x) - (+ start-y move-y)] - :show-mouse? true - :layers (map (fn [l] (move-layer l move-x move-y)) - base-layers) - :tool :select})}))))) + (+ start-y move-y)] + :show-mouse? true + :layers (map (fn [l] (move-layer l move-x move-y)) + base-layers) + :tool :select})}))))) tick-state (range 0 (inc (- end-tick start-tick pause-ticks)))) (add-tick end-tick @@ -199,12 +199,12 @@ ((om/get-shared owner :cast!) :subscriber-updated {:client-id (:client-id (:bot tick-state)) :fields (merge (:bot tick-state) {:mouse-position [start-x (- start-y (/ text-height 2))] - :show-mouse? true - :layers [(assoc base-layer - :layer/text (apply str (take letter-count text)) - :layer/current-x end-x - :layer/current-y end-y)] - :tool :text})}))))) + :show-mouse? true + :layers [(assoc base-layer + :layer/text (apply str (take letter-count text)) + :layer/current-x end-x + :layer/current-y end-y)] + :tool :text})}))))) tick-state (map int (range 0 @@ -216,8 +216,8 @@ ((om/get-shared owner :cast!) :subscriber-updated {:client-id (:client-id (:bot tick-state)) :fields (merge (:bot tick-state) {:mouse-position nil - :layers nil - :tool :text})}) + :layers nil + :tool :text})}) (d/transact! (om/get-shared owner :db) [base-layer] {:bot-layer true}))) (annotate-keyframes start-tick end-tick)))) diff --git a/src-cljs/frontend/controllers/controls.cljs b/src-cljs/frontend/controllers/controls.cljs index fb3b96a0..ce4e9ae0 100644 --- a/src-cljs/frontend/controllers/controls.cljs +++ b/src-cljs/frontend/controllers/controls.cljs @@ -527,7 +527,7 @@ :layer/ui-target (when (:layer/ui-target layer) (:layer/ui-target layer)))]) (assoc-in [:drawing :moving?] true) - (assoc-in [:drawing :starting-mouse-position] [rx ry])))) + (assoc-in [:drawing :starting-mouse-position] (:mouse state))))) (defmethod control-event :group-duplicated [browser-state message {:keys [x y]} state] @@ -562,7 +562,7 @@ ps)))))) layers (range))) (assoc-in [:drawing :moving?] true) - (assoc-in [:drawing :starting-mouse-position] [rx ry])))) + (assoc-in [:drawing :starting-mouse-position] (:mouse state))))) (defmethod control-event :text-layer-edited [browser-state message {:keys [value]} state] @@ -820,7 +820,8 @@ (update-in [:drawing :relation] merge {:rx rx :ry ry})))) (defn move-drawings [state x y] - (let [[start-x start-y] (get-in state [:drawing :starting-mouse-position]) + (let [start-x (get-in state [:drawing :starting-mouse-position :rx]) + start-y (get-in state [:drawing :starting-mouse-position :ry]) [rx ry] (cameras/screen->point (:camera state) x y) [move-x move-y] [(- rx start-x) (- ry start-y)] [snap-move-x snap-move-y] (cameras/snap-to-grid (:camera state) move-x move-y) @@ -832,7 +833,7 @@ (get-in state [:drawing :original-layers]))] (-> state (assoc-in [:drawing :layers] layers) - (assoc-in [:drawing :current-mouse-position] (cameras/screen->point (:camera state) x y)) + (assoc-in [:drawing :current-mouse-position] {:x x :y y :rx rx :ry ry}) (assoc-in [:editing-eids :editing-eids] (set (map :db/id layers)))))) (defn pan-canvas [state x y] @@ -860,7 +861,7 @@ (move-drawings x y) (get-in state [:drawing :clip?]) - (assoc-in [:drawing :current-mouse-position] (cameras/screen->point (:camera state) x y)) + (#(assoc-in % [:drawing :current-mouse-position] (:mouse %))) (keyboard/pan-shortcut-active? state) ((fn [s] @@ -1003,13 +1004,12 @@ center-x (+ min-x (/ width 2)) center-y (+ min-y (/ height 2)) [mouse-x mouse-y] (cameras/snap-to-grid camera - (get-in state [:mouse :x]) - (get-in state [:mouse :y])) - new-x (+ (* (- center-x) zoom) - (get-in state [:mouse :x])) - new-y (+ (* (- center-y) zoom) - (get-in state [:mouse :y])) - [move-x move-y] (cameras/screen->point camera new-x new-y) + (get-in state [:drawing :current-mouse-position :rx]) + (get-in state [:drawing :current-mouse-position :ry])) + move-x (+ (* (- center-x) zoom) + (get-in state [:drawing :current-mouse-position :rx])) + move-y (+ (* (- center-y) zoom) + (get-in state [:drawing :current-mouse-position :ry])) [snap-move-x snap-move-y] (cameras/snap-to-grid camera move-x move-y) new-layers (mapv (fn [l] (-> l @@ -1030,8 +1030,10 @@ (let [db (:db current-state) layer-datas (cons (:drawing previous-state) (map :layer-data (filter :clip/important? (get-in previous-state [:cust :cust/clips])))) - [start-x start-y] (get-in previous-state [:drawing :current-mouse-position]) - [end-x end-y] (get-in previous-state [:drawing :starting-mouse-position]) + start-x (get-in previous-state [:drawing :current-mouse-position :rx]) + start-y (get-in previous-state [:drawing :current-mouse-position :ry]) + end-x (get-in previous-state [:drawing :starting-mouse-position :rx]) + end-y (get-in previous-state [:drawing :starting-mouse-position :ry]) layer-index (get-in previous-state [:drawing :scrolled-layer]) layer-data (layers/normalize-pasted-layer-data (nth layer-datas layer-index)) layers (something-something layer-data previous-state)] @@ -1264,7 +1266,7 @@ (conjv (if append? layers []) layer))) (assoc-in [:drawing :moving?] true) - (assoc-in [:drawing :starting-mouse-position] [rx ry])))) + (assoc-in [:drawing :starting-mouse-position] {:x x :y y :rx rx :ry ry})))) (defmethod control-event :arrow-selected [browser-state message {:keys [origin dest append?]} state] @@ -1319,7 +1321,7 @@ layers)) (assoc-in [:drawing :original-layers] layers) (assoc-in [:drawing :moving?] true) - (assoc-in [:drawing :starting-mouse-position] [rx ry])))) + (assoc-in [:drawing :starting-mouse-position] {:x x :y y :rx rx :ry ry})))) (defn handle-radial-opened [state] (-> state @@ -1736,8 +1738,7 @@ (dissoc-in [:clipboard :layers]) (assoc-in [:mouse-down] true) (update :drawing merge {:clip? true - :starting-mouse-position [(get-in state [:mouse :rx]) - (get-in state [:mouse :ry])] + :starting-mouse-position (:mouse state) :layers new-layers :original-layers new-layers}) (assoc-in [:editing-eids :editing-eids] (set entity-ids)) @@ -1778,10 +1779,8 @@ (assoc-in [:drawing :clip-scroll] (/ width 2)) (assoc-in [:drawing :scrolled-layer] 0) (update :drawing merge {:clip? true - :starting-mouse-position [(get-in state [:mouse :rx]) - (get-in state [:mouse :ry])] - :current-mouse-position [(get-in state [:mouse :rx]) - (get-in state [:mouse :ry])] + :starting-mouse-position (:mouse state) + :current-mouse-position (:mouse state) :layers new-layers :width width :height height From e6a38a3778be752ce9eeb95394ac0ec093a23deb Mon Sep 17 00:00:00 2001 From: Daniel Woelfel Date: Mon, 29 Jun 2015 18:24:38 -0700 Subject: [PATCH 20/21] enable pasting without anything in clipboard --- src-cljs/frontend/clipboard.cljs | 6 +- src-cljs/frontend/components/canvas.cljs | 3 +- src-cljs/frontend/controllers/controls.cljs | 87 ++++++++++++--------- 3 files changed, 54 insertions(+), 42 deletions(-) diff --git a/src-cljs/frontend/clipboard.cljs b/src-cljs/frontend/clipboard.cljs index 6a7d8bb8..4c0039d6 100644 --- a/src-cljs/frontend/clipboard.cljs +++ b/src-cljs/frontend/clipboard.cljs @@ -282,7 +282,5 @@ ;; element is selected (see components.canvas) (or (= "_copy-hack" (.-id target)) (not (contains? #{"input" "textarea"} (str/lower-case (.-tagName js/document.activeElement)))))) - (when-let [layer-data (some->> (.getData (.-clipboardData e) "text") - (parse-pasted))] - (let [canvas-size (utils/canvas-size)] - (put! (get-in app-state [:comms :controls]) [:layers-pasted (assoc layer-data :canvas-size canvas-size)]))))) + (put! (get-in app-state [:comms :controls]) [:layers-pasted (some->> (.getData (.-clipboardData e) "text") + (parse-pasted))]))) diff --git a/src-cljs/frontend/components/canvas.cljs b/src-cljs/frontend/components/canvas.cljs index f3f96549..d3e011ab 100644 --- a/src-cljs/frontend/components/canvas.cljs +++ b/src-cljs/frontend/components/canvas.cljs @@ -719,7 +719,8 @@ (render [_] (let [drawing (cursors/observe-drawing owner) camera (cursors/observe-camera owner) - normalized-layer-datas (map layers/normalize-pasted-layer-data (cons drawing + normalized-layer-datas (map layers/normalize-pasted-layer-data (concat (when (:layers drawing) + [drawing]) (map :layer-data (filter :clip/important? clips)))) scrolled-layer-index (:scrolled-layer drawing) clip-scroll (layers/clip-scroll normalized-layer-datas scrolled-layer-index) diff --git a/src-cljs/frontend/controllers/controls.cljs b/src-cljs/frontend/controllers/controls.cljs index ce4e9ae0..10dfef8a 100644 --- a/src-cljs/frontend/controllers/controls.cljs +++ b/src-cljs/frontend/controllers/controls.cljs @@ -1028,7 +1028,8 @@ (defn handle-drop-clip-after [previous-state current-state] (let [db (:db current-state) - layer-datas (cons (:drawing previous-state) + layer-datas (concat (when (get-in previous-state [:drawing :layers]) + [(:drawing previous-state)]) (map :layer-data (filter :clip/important? (get-in previous-state [:cust :cust/clips])))) start-x (get-in previous-state [:drawing :current-mouse-position :rx]) start-y (get-in previous-state [:drawing :current-mouse-position :ry]) @@ -1752,49 +1753,61 @@ (defmethod control-event :layers-pasted [browser-state message {:keys [layers height width min-x min-y canvas-size] :as layer-data} state] - (let [{:keys [entity-ids state]} (frontend.db/get-entity-ids state (count layers)) - eid-map (zipmap (map :db/id layers) entity-ids) - doc-id (:document/id state) - camera (:camera state) - zoom (:zf camera) - center-x (+ min-x (/ width 2)) - center-y (+ min-y (/ height 2)) - new-x (+ (* (- center-x) zoom) - (get-in state [:mouse :x])) - new-y (+ (* (- center-y) zoom) - (get-in state [:mouse :y])) - [move-x move-y] (cameras/screen->point camera new-x new-y) - [snap-move-x snap-move-y] (cameras/snap-to-grid (:camera state) move-x move-y) - new-layers (mapv (fn [l] - (-> l - (assoc :db/id (get eid-map (:db/id l)) - :layer/document doc-id) - (utils/update-when-in [:layer/points-to] (fn [dests] - (set (filter :db/id (map #(update-in % [:db/id] eid-map) dests))))))) - layers)] + (if layer-data + (let [{:keys [entity-ids state]} (frontend.db/get-entity-ids state (count layers)) + eid-map (zipmap (map :db/id layers) entity-ids) + doc-id (:document/id state) + camera (:camera state) + zoom (:zf camera) + center-x (+ min-x (/ width 2)) + center-y (+ min-y (/ height 2)) + new-x (+ (* (- center-x) zoom) + (get-in state [:mouse :x])) + new-y (+ (* (- center-y) zoom) + (get-in state [:mouse :y])) + [move-x move-y] (cameras/screen->point camera new-x new-y) + [snap-move-x snap-move-y] (cameras/snap-to-grid (:camera state) move-x move-y) + new-layers (mapv (fn [l] + (-> l + (assoc :db/id (get eid-map (:db/id l)) + :layer/document doc-id) + (utils/update-when-in [:layer/points-to] (fn [dests] + (set (filter :db/id (map #(update-in % [:db/id] eid-map) dests))))))) + layers)] + (-> state + (dissoc-in [:clipboard :layers]) + (assoc-in [:mouse-down] true) + ;; has to account for no clips + (assoc-in [:drawing :clip-scroll] (/ width 2)) + (assoc-in [:drawing :scrolled-layer] 0) + (update :drawing merge {:clip? true + :starting-mouse-position (:mouse state) + :current-mouse-position (:mouse state) + :layers new-layers + :width width + :height height + :min-x min-x + :min-y min-y + :original-layers new-layers}) + (assoc-in [:editing-eids :editing-eids] (set entity-ids)) + (assoc-in [:selected-eids :selected-eids] (set entity-ids)) + (assoc-in [:selected-arrows :selected-arrows] (set (reduce (fn [acc layer] + (if-let [pointer (:layer/points-to layer)] + (conj acc {:origin-id (:db/id layer) + :dest-id (:db/id pointer)}) + acc)) + #{} new-layers))))) (-> state (dissoc-in [:clipboard :layers]) (assoc-in [:mouse-down] true) - ;; has to account for no clips - (assoc-in [:drawing :clip-scroll] (/ width 2)) (assoc-in [:drawing :scrolled-layer] 0) (update :drawing merge {:clip? true :starting-mouse-position (:mouse state) :current-mouse-position (:mouse state) - :layers new-layers - :width width - :height height - :min-x min-x - :min-y min-y - :original-layers new-layers}) - (assoc-in [:editing-eids :editing-eids] (set entity-ids)) - (assoc-in [:selected-eids :selected-eids] (set entity-ids)) - (assoc-in [:selected-arrows :selected-arrows] (set (reduce (fn [acc layer] - (if-let [pointer (:layer/points-to layer)] - (conj acc {:origin-id (:db/id layer) - :dest-id (:db/id pointer)}) - acc)) - #{} new-layers)))))) + :layers nil}) + (assoc-in [:editing-eids :editing-eids] #{}) + (assoc-in [:selected-eids :selected-eids] #{}) + (assoc-in [:selected-arrows :selected-arrows] #{})))) #_(defmethod post-control-event! :layers-pasted [browser-state message _ previous-state current-state] From cbc5935e21ba61d5416a36dc0c8159b0c6e2db7e Mon Sep 17 00:00:00 2001 From: danny Date: Mon, 6 Jul 2015 13:06:34 -0700 Subject: [PATCH 21/21] avoid style conflicts with clips on canvas --- resources/assets/css/components/menu.less | 4 ++-- src-cljs/frontend/components/clip_viewer.cljs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/assets/css/components/menu.less b/resources/assets/css/components/menu.less index 78239049..7893ddcd 100644 --- a/resources/assets/css/components/menu.less +++ b/resources/assets/css/components/menu.less @@ -733,10 +733,10 @@ .slack-channel-remove { margin-left: auto; } -.clips { +.clips-list { .flexy(wrap); } -.clip { +.clip-item { .flexy(center; center); position: relative; width: 50%; diff --git a/src-cljs/frontend/components/clip_viewer.cljs b/src-cljs/frontend/components/clip_viewer.cljs index 462594bc..314f63d9 100644 --- a/src-cljs/frontend/components/clip_viewer.cljs +++ b/src-cljs/frontend/components/clip_viewer.cljs @@ -52,10 +52,10 @@ "Cmd+C." "Ctrl+C.") " Star clips to pin them to the top. "] - [:div.clips + [:div.clips-list (for [clip clips] (html - [:div.clip.make + [:div.clip-item.make [:a.clip-preview {:role "button" :on-click #(cast! :clip-pasted clip)} [:img.clip-thumbnail {:src (:clip/s3-url clip)}]]