From fbbb079599cdecf830824debc5a5d166f7977e43 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 3 Feb 2022 18:30:25 +0100 Subject: [PATCH 1/8] :recycle: Remove `rx/first` calls and replaced by safer `rx/take 1` --- frontend/src/app/main/data/workspace.cljs | 4 ++-- frontend/src/app/main/data/workspace/colors.cljs | 2 +- frontend/src/app/main/data/workspace/drawing.cljs | 2 +- frontend/src/app/main/data/workspace/layers.cljs | 2 +- frontend/src/app/main/data/workspace/transforms.cljs | 4 ++-- frontend/src/app/main/snap.cljs | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index d36dde063..21fb41f39 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -196,7 +196,7 @@ (->> stream (rx/filter #(= ::dwc/index-initialized %)) - (rx/first) + (rx/take 1) (rx/map #(file-initialized bundle))))))))) ptk/EffectEvent @@ -1636,7 +1636,7 @@ (->> (rx/concat paste-transit-str paste-plain-text-str paste-image-str) - (rx/first) + (rx/take 1) (rx/catch (fn [err] (js/console.error "Clipboard error:" err) diff --git a/frontend/src/app/main/data/workspace/colors.cljs b/frontend/src/app/main/data/workspace/colors.cljs index 017cc967d..5c9d01fab 100644 --- a/frontend/src/app/main/data/workspace/colors.cljs +++ b/frontend/src/app/main/data/workspace/colors.cljs @@ -219,7 +219,7 @@ ;; Hide the modal if the stop event is emitted (->> stop? - (rx/first) + (rx/take 1) (rx/map #(md/hide)))))) ptk/UpdateEvent diff --git a/frontend/src/app/main/data/workspace/drawing.cljs b/frontend/src/app/main/data/workspace/drawing.cljs index 14ec47a2a..1fc7186e9 100644 --- a/frontend/src/app/main/data/workspace/drawing.cljs +++ b/frontend/src/app/main/data/workspace/drawing.cljs @@ -74,7 +74,7 @@ (rx/of (handle-drawing type)) (->> stream (rx/filter (ptk/type? ::common/handle-finish-drawing) ) - (rx/first) + (rx/take 1) (rx/map #(fn [state] (update state :workspace-drawing dissoc :lock))))))))))) (defn handle-drawing diff --git a/frontend/src/app/main/data/workspace/layers.cljs b/frontend/src/app/main/data/workspace/layers.cljs index 4344e13e8..0f06eac31 100644 --- a/frontend/src/app/main/data/workspace/layers.cljs +++ b/frontend/src/app/main/data/workspace/layers.cljs @@ -70,7 +70,7 @@ (let [opacity-events (->> stream ;; Stop buffering after time without opacities (rx/filter (ptk/type? ::pressed-opacity)) (rx/buffer-time 600) - (rx/first) + (rx/take 1) (rx/map #(set-opacity (calculate-opacity (map deref %)))))] (rx/concat (rx/of (set-opacity (calculate-opacity [opacity]))) ;; First opacity is always fired diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 559895ddd..1d343f035 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -523,7 +523,7 @@ (watch [_ _ stream] (->> stream (rx/filter (ptk/type? ::dws/duplicate-selected)) - (rx/first) + (rx/take 1) (rx/map #(start-move from-position)))))) (defn- start-move @@ -612,7 +612,7 @@ (rx/filter #(= direction (deref %)))) stopper (->> move-events (rx/debounce 100) - (rx/first)) + (rx/take 1)) scale (if shift? (gpt/point (:big nudge)) (gpt/point (:small nudge))) mov-vec (gpt/multiply (get-displacement direction) scale)] diff --git a/frontend/src/app/main/snap.cljs b/frontend/src/app/main/snap.cljs index 1de5b1aab..3da469e5d 100644 --- a/frontend/src/app/main/snap.cljs +++ b/frontend/src/app/main/snap.cljs @@ -82,7 +82,7 @@ :frame-id frame-id :axis coord :ranges [[(- value 0.5) (+ value 0.5)]]}) - (rx/first) + (rx/take 1) (rx/map (remove-from-snap-points remove-snap?)) (rx/map flatten-to-points)))) @@ -98,7 +98,7 @@ :frame-id frame-id :axis coord :ranges ranges}) - (rx/first) + (rx/take 1) (rx/map (remove-from-snap-points remove-snap?)) (rx/map (get-min-distance-snap points coord))))) From ec1cc8ec64fb7f26dae06040af9e164fa6de7c04 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 3 Feb 2022 18:32:06 +0100 Subject: [PATCH 2/8] :sparkles: Adds new shortcut for zoom in --- frontend/src/app/main/data/workspace/shortcuts.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/main/data/workspace/shortcuts.cljs b/frontend/src/app/main/data/workspace/shortcuts.cljs index 44667db49..ec42b727a 100644 --- a/frontend/src/app/main/data/workspace/shortcuts.cljs +++ b/frontend/src/app/main/data/workspace/shortcuts.cljs @@ -80,7 +80,7 @@ :fn #(st/emit! (dw/toggle-layout-flags :scale-text))} :increase-zoom {:tooltip "+" - :command "+" + :command ["+" "="] :fn #(st/emit! (dw/increase-zoom nil))} :decrease-zoom {:tooltip "-" From 72c2a213b42c98397496931f23b224a6a7786541 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 3 Feb 2022 18:32:23 +0100 Subject: [PATCH 3/8] :sparkles: Curve tool improvements --- .../src/app/main/data/workspace/common.cljs | 58 ++++++++++--------- .../src/app/main/data/workspace/drawing.cljs | 9 +++ .../main/data/workspace/drawing/common.cljs | 5 +- .../src/app/main/ui/workspace/viewport.cljs | 2 +- 4 files changed, 44 insertions(+), 30 deletions(-) diff --git a/frontend/src/app/main/data/workspace/common.cljs b/frontend/src/app/main/data/workspace/common.cljs index 21406795d..a58bf8aa5 100644 --- a/frontend/src/app/main/data/workspace/common.cljs +++ b/frontend/src/app/main/data/workspace/common.cljs @@ -314,37 +314,41 @@ [redo-changes undo-changes]))) (defn add-shape - [attrs] - (us/verify ::shape-attrs attrs) - (ptk/reify ::add-shape - ptk/WatchEvent - (watch [it state _] - (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + ([attrs] + (add-shape attrs {})) - id (or (:id attrs) (uuid/next)) - name (-> objects - (retrieve-used-names) - (generate-unique-name (:name attrs))) + ([attrs {:keys [no-select?]}] + (us/verify ::shape-attrs attrs) + (ptk/reify ::add-shape + ptk/WatchEvent + (watch [it state _] + (let [page-id (:current-page-id state) + objects (wsh/lookup-page-objects state page-id) - selected (wsh/lookup-selected state) + id (or (:id attrs) (uuid/next)) + name (-> objects + (retrieve-used-names) + (generate-unique-name (:name attrs))) - [rchanges uchanges] (add-shape-changes - page-id - objects - selected - (-> attrs - (assoc :id id ) - (assoc :name name)))] + selected (wsh/lookup-selected state) - (rx/concat - (rx/of (dch/commit-changes {:redo-changes rchanges - :undo-changes uchanges - :origin it}) - (select-shapes (d/ordered-set id))) - (when (= :text (:type attrs)) - (->> (rx/of (start-edition-mode id)) - (rx/observe-on :async)))))))) + [rchanges uchanges] (add-shape-changes + page-id + objects + selected + (-> attrs + (assoc :id id ) + (assoc :name name)))] + + (rx/concat + (rx/of (dch/commit-changes {:redo-changes rchanges + :undo-changes uchanges + :origin it}) + (when-not no-select? + (select-shapes (d/ordered-set id)))) + (when (= :text (:type attrs)) + (->> (rx/of (start-edition-mode id)) + (rx/observe-on :async))))))))) (defn move-shapes-into-frame [frame-id shapes] (ptk/reify ::move-shapes-into-frame diff --git a/frontend/src/app/main/data/workspace/drawing.cljs b/frontend/src/app/main/data/workspace/drawing.cljs index 1fc7186e9..522d0150a 100644 --- a/frontend/src/app/main/data/workspace/drawing.cljs +++ b/frontend/src/app/main/data/workspace/drawing.cljs @@ -42,6 +42,15 @@ (when (= tool :path) (rx/of (start-drawing :path))) + (when (= tool :curve) + (let [stopper (->> stream (rx/filter dwc/interrupt?))] + (->> stream + (rx/take-until stopper) + (rx/filter (ptk/type? ::common/handle-finish-drawing)) + (rx/take 1) + (rx/observe-on :async) + (rx/map #(select-for-drawing tool data))))) + ;; NOTE: comments are a special case and they manage they ;; own interrupt cycle.q (when (and (not= tool :comments) diff --git a/frontend/src/app/main/data/workspace/drawing/common.cljs b/frontend/src/app/main/data/workspace/drawing/common.cljs index fb93c6f5c..624bbf308 100644 --- a/frontend/src/app/main/data/workspace/drawing/common.cljs +++ b/frontend/src/app/main/data/workspace/drawing/common.cljs @@ -24,7 +24,8 @@ (ptk/reify ::handle-finish-drawing ptk/WatchEvent (watch [_ state _] - (let [shape (get-in state [:workspace-drawing :object])] + (let [tool (get-in state [:workspace-drawing :tool]) + shape (get-in state [:workspace-drawing :object])] (rx/concat (when (:initialized? shape) (let [page-id (:current-page-id state) @@ -55,7 +56,7 @@ (rx/of (dwu/start-undo-transaction)) (rx/empty)) - (rx/of (dwc/add-shape shape)) + (rx/of (dwc/add-shape shape {:no-select? (= tool :curve)})) (if (= :frame (:type shape)) (->> (uw/ask! {:cmd :selection/query diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index 35e8f44b1..f88972c48 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -142,7 +142,7 @@ show-draw-area? drawing-obj show-gradient-handlers? (= (count selected) 1) show-grids? (contains? layout :display-grid) - show-outlines? (and (nil? transform) (not edition) (not drawing-obj) (not (#{:comments :path} drawing-tool))) + show-outlines? (and (nil? transform) (not edition) (not drawing-obj) (not (#{:comments :path :curve} drawing-tool))) show-pixel-grid? (>= zoom 8) show-presence? page-id show-prototypes? (= options-mode :prototype) From 67c6a042a0900d87e6bcd22f60c80f7b22cba17f Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 4 Feb 2022 09:51:26 +0100 Subject: [PATCH 4/8] :sparkles: Improved incremental selection --- frontend/src/app/main/data/workspace/selection.cljs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/main/data/workspace/selection.cljs b/frontend/src/app/main/data/workspace/selection.cljs index f6bd9a518..46b554a22 100644 --- a/frontend/src/app/main/data/workspace/selection.cljs +++ b/frontend/src/app/main/data/workspace/selection.cljs @@ -88,7 +88,9 @@ (rx/merge (->> selrect-stream (rx/map update-selrect)) (->> selrect-stream - (rx/debounce 50) + (rx/buffer-time 100) + (rx/map #(last %)) + (rx/dedupe) (rx/map #(select-shapes-by-current-selrect preserve?)))) (rx/of (update-selrect nil)))))))) From 76b34bb600403ffc10f43b8977ca42f3a29852f4 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 4 Feb 2022 12:52:00 +0100 Subject: [PATCH 5/8] :sparkles: Workspace interactions improvements --- frontend/resources/images/cursors/zoom-in.svg | 1 + .../resources/images/cursors/zoom-out.svg | 1 + frontend/resources/images/cursors/zoom.svg | 1 + .../main/partials/debug-icons-preview.scss | 2 + .../app/main/data/workspace/selection.cljs | 7 +- frontend/src/app/main/ui/cursors.cljs | 3 + .../src/app/main/ui/workspace/viewport.cljs | 14 +-- .../main/ui/workspace/viewport/actions.cljs | 105 ++++++++++-------- .../app/main/ui/workspace/viewport/hooks.cljs | 7 +- .../app/main/ui/workspace/viewport/utils.cljs | 3 + frontend/src/app/worker/selection.cljs | 7 +- 11 files changed, 89 insertions(+), 62 deletions(-) create mode 100644 frontend/resources/images/cursors/zoom-in.svg create mode 100644 frontend/resources/images/cursors/zoom-out.svg create mode 100644 frontend/resources/images/cursors/zoom.svg diff --git a/frontend/resources/images/cursors/zoom-in.svg b/frontend/resources/images/cursors/zoom-in.svg new file mode 100644 index 000000000..ecd153448 --- /dev/null +++ b/frontend/resources/images/cursors/zoom-in.svg @@ -0,0 +1 @@ + diff --git a/frontend/resources/images/cursors/zoom-out.svg b/frontend/resources/images/cursors/zoom-out.svg new file mode 100644 index 000000000..65a5a300f --- /dev/null +++ b/frontend/resources/images/cursors/zoom-out.svg @@ -0,0 +1 @@ + diff --git a/frontend/resources/images/cursors/zoom.svg b/frontend/resources/images/cursors/zoom.svg new file mode 100644 index 000000000..9650153fe --- /dev/null +++ b/frontend/resources/images/cursors/zoom.svg @@ -0,0 +1 @@ + diff --git a/frontend/resources/styles/main/partials/debug-icons-preview.scss b/frontend/resources/styles/main/partials/debug-icons-preview.scss index 8ddba1688..afca85123 100644 --- a/frontend/resources/styles/main/partials/debug-icons-preview.scss +++ b/frontend/resources/styles/main/partials/debug-icons-preview.scss @@ -2,7 +2,9 @@ display: flex; flex-direction: column; overflow: scroll; + height: 100%; } + .debug-icons-preview { display: flex; flex-wrap: wrap; diff --git a/frontend/src/app/main/data/workspace/selection.cljs b/frontend/src/app/main/data/workspace/selection.cljs index 46b554a22..264874a94 100644 --- a/frontend/src/app/main/data/workspace/selection.cljs +++ b/frontend/src/app/main/data/workspace/selection.cljs @@ -47,7 +47,7 @@ (assoc-in state [:workspace-local :selrect] selrect)))) (defn handle-area-selection - [preserve?] + [preserve? ignore-groups?] (letfn [(data->selrect [data] (let [start (:start data) stop (:stop data) @@ -91,7 +91,7 @@ (rx/buffer-time 100) (rx/map #(last %)) (rx/dedupe) - (rx/map #(select-shapes-by-current-selrect preserve?)))) + (rx/map #(select-shapes-by-current-selrect preserve? ignore-groups?)))) (rx/of (update-selrect nil)))))))) @@ -218,7 +218,7 @@ ;; --- Select Shapes (By selrect) (defn select-shapes-by-current-selrect - [preserve?] + [preserve? ignore-groups?] (ptk/reify ::select-shapes-by-current-selrect ptk/WatchEvent (watch [_ state _] @@ -237,6 +237,7 @@ :page-id page-id :rect selrect :include-frames? true + :ignore-groups? ignore-groups? :full-frame? true}) (rx/map #(cp/clean-loops objects %)) (rx/map #(into initial-set (filter (comp not blocked?)) %)) diff --git a/frontend/src/app/main/ui/cursors.cljs b/frontend/src/app/main/ui/cursors.cljs index a57575099..2d571ed06 100644 --- a/frontend/src/app/main/ui/cursors.cljs +++ b/frontend/src/app/main/ui/cursors.cljs @@ -30,6 +30,9 @@ (def pointer-node (cursor-ref :pointer-node 0 0 10 32)) (def resize-alt (cursor-ref :resize-alt)) (def text (cursor-ref :text)) +(def zoom (cursor-ref :zoom)) +(def zoom-in (cursor-ref :zoom-in)) +(def zoom-out (cursor-ref :zoom-out)) ;; Dynamic cursors (def resize-ew (cursor-fn :resize-h 0)) diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index f88972c48..def9a0852 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -115,21 +115,21 @@ node-editing? (and edition (not= :text (get-in base-objects [edition :type]))) text-editing? (and edition (= :text (get-in base-objects [edition :type]))) - on-click (actions/on-click hover selected edition drawing-path? drawing-tool) + on-click (actions/on-click hover selected edition drawing-path? drawing-tool space?) on-context-menu (actions/on-context-menu hover hover-ids) on-double-click (actions/on-double-click hover hover-ids drawing-path? base-objects edition) on-drag-enter (actions/on-drag-enter) on-drag-over (actions/on-drag-over) on-drop (actions/on-drop file viewport-ref zoom) on-mouse-down (actions/on-mouse-down @hover selected edition drawing-tool text-editing? node-editing? - drawing-path? create-comment? space? viewport-ref zoom) + drawing-path? create-comment? space? viewport-ref zoom panning) on-mouse-up (actions/on-mouse-up disable-paste) on-pointer-down (actions/on-pointer-down) on-pointer-enter (actions/on-pointer-enter in-viewport?) on-pointer-leave (actions/on-pointer-leave in-viewport?) on-pointer-move (actions/on-pointer-move viewport-ref zoom move-stream) on-pointer-up (actions/on-pointer-up) - on-move-selected (actions/on-move-selected hover hover-ids selected) + on-move-selected (actions/on-move-selected hover hover-ids selected space?) on-menu-selected (actions/on-menu-selected hover hover-ids selected) on-frame-enter (actions/on-frame-enter frame-hover) @@ -162,15 +162,13 @@ (hooks/setup-dom-events viewport-ref zoom disable-paste in-viewport?) (hooks/setup-viewport-size viewport-ref) - (hooks/setup-cursor cursor alt? panning drawing-tool drawing-path? node-editing?) + (hooks/setup-cursor cursor alt? ctrl? space? panning drawing-tool drawing-path? node-editing?) (hooks/setup-keyboard alt? ctrl? space?) (hooks/setup-hover-shapes page-id move-stream base-objects transform selected ctrl? hover hover-ids @hover-disabled? zoom) (hooks/setup-viewport-modifiers modifiers base-objects) (hooks/setup-shortcuts node-editing? drawing-path?) (hooks/setup-active-frames base-objects vbox hover active-frames) - - [:div.viewport [:div.viewport-overlays @@ -245,7 +243,7 @@ [:& outline/shape-outlines {:objects base-objects :selected selected - :hover (when (not= :frame (:type @hover)) + :hover (when (or @ctrl? (not= :frame (:type @hover))) #{(or @frame-hover (:id @hover))}) :edition edition :zoom zoom}]) @@ -262,7 +260,7 @@ :shapes selected-shapes :zoom zoom :edition edition - :disable-handlers (or drawing-tool edition) + :disable-handlers (or drawing-tool edition @space?) :on-move-selected on-move-selected :on-context-menu on-menu-selected}]) diff --git a/frontend/src/app/main/ui/workspace/viewport/actions.cljs b/frontend/src/app/main/ui/workspace/viewport/actions.cljs index 486288374..084f9ec8f 100644 --- a/frontend/src/app/main/ui/workspace/viewport/actions.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/actions.cljs @@ -28,10 +28,11 @@ (defn on-mouse-down [{:keys [id blocked hidden type]} selected edition drawing-tool text-editing? - node-editing? drawing-path? create-comment? space? viewport-ref zoom] + node-editing? drawing-path? create-comment? space? viewport-ref zoom panning] (mf/use-callback (mf/deps id blocked hidden type selected edition drawing-tool text-editing? - node-editing? drawing-path? create-comment? space? viewport-ref zoom) + node-editing? drawing-path? create-comment? @space? viewport-ref zoom + panning) (fn [bevent] (when (or (dom/class? (dom/get-target bevent) "viewport-controls") (dom/class? (dom/get-target bevent) "viewport-selrect")) @@ -42,62 +43,75 @@ shift? (kbd/shift? event) alt? (kbd/alt? event) - left-click? (= 1 (.-which event)) - middle-click? (= 2 (.-which event)) + left-click? (and (not panning) (= 1 (.-which event))) + middle-click? (and (not panning) (= 2 (.-which event))) frame? (= :frame type) selected? (contains? selected id)] - (when middle-click? - (dom/prevent-default bevent) - (if ctrl? - (let [raw-pt (dom/get-client-position event) - viewport (mf/ref-val viewport-ref) - pt (utils/translate-point-to-viewport viewport zoom raw-pt)] - (st/emit! (dw/start-zooming pt))) - (st/emit! (dw/start-panning)))) + (cond + middle-click? + (do + (dom/prevent-default bevent) + (if ctrl? + (let [raw-pt (dom/get-client-position event) + viewport (mf/ref-val viewport-ref) + pt (utils/translate-point-to-viewport viewport zoom raw-pt)] + (st/emit! (dw/start-zooming pt))) + (st/emit! (dw/start-panning)))) - (when left-click? - (st/emit! (ms/->MouseEvent :down ctrl? shift? alt?)) - (when (and (not= edition id) text-editing?) - (st/emit! dw/clear-edition-mode)) + left-click? + (do + (st/emit! (ms/->MouseEvent :down ctrl? shift? alt?)) - (when (and (not text-editing?) - (not blocked) - (not hidden) - (not create-comment?) - (not drawing-path?)) - (cond - drawing-tool - (st/emit! (dd/start-drawing drawing-tool)) + (when (and (not= edition id) text-editing?) + (st/emit! dw/clear-edition-mode)) - node-editing? - ;; Handle path node area selection - (st/emit! (dwdp/handle-area-selection shift?)) + (when (and (not text-editing?) + (not blocked) + (not hidden) + (not create-comment?) + (not drawing-path?)) + (cond + node-editing? + ;; Handle path node area selection + (st/emit! (dwdp/handle-area-selection shift?)) - @space? - (st/emit! (dw/start-panning)) + (and @space? ctrl?) + (let [raw-pt (dom/get-client-position event) + viewport (mf/ref-val viewport-ref) + pt (utils/translate-point-to-viewport viewport zoom raw-pt)] + (st/emit! (dw/start-zooming pt))) - (or (not id) (and frame? (not selected?))) - (st/emit! (dw/handle-area-selection shift?)) + @space? + (st/emit! (dw/start-panning)) - (not drawing-tool) - (st/emit! (when (or shift? (not selected?)) - (dw/select-shape id shift?)) - (dw/start-move-selected)))))))))) + drawing-tool + (st/emit! (dd/start-drawing drawing-tool)) + + (or (not id) (and frame? (not selected?)) ctrl?) + (st/emit! (dw/handle-area-selection shift? ctrl?)) + + (not drawing-tool) + (st/emit! (when (or shift? (not selected?)) + (dw/select-shape id shift?)) + (dw/start-move-selected))))))))))) (defn on-move-selected - [hover hover-ids selected] + [hover hover-ids selected space?] (mf/use-callback - (mf/deps @hover @hover-ids selected) + (mf/deps @hover @hover-ids selected @space?) (fn [bevent] (let [event (.-nativeEvent bevent) shift? (kbd/shift? event) + ctrl? (kbd/ctrl? event) left-click? (= 1 (.-which event))] (when (and left-click? + (not ctrl?) (not shift?) + (not @space?) (or (not @hover) (= :frame (:type @hover)) (some #(contains? selected %) @hover-ids))) @@ -130,9 +144,9 @@ (reset! frame-hover nil)))) (defn on-click - [hover selected edition drawing-path? drawing-tool] + [hover selected edition drawing-path? drawing-tool space?] (mf/use-callback - (mf/deps @hover selected edition drawing-path? drawing-tool) + (mf/deps @hover selected edition drawing-path? drawing-tool @space?) (fn [event] (when (or (dom/class? (dom/get-target event) "viewport-controls") (dom/class? (dom/get-target event) "viewport-selrect")) @@ -147,7 +161,8 @@ (when (and hovering? (not shift?) - (not frame?) + (or ctrl? (not frame?)) + (not @space?) (not selected?) (not edition) (not drawing-path?) @@ -229,17 +244,17 @@ middle-click? (= 2 (.-which event))] (when left-click? - (st/emit! (dw/finish-panning) - (ms/->MouseEvent :up ctrl? shift? alt?))) + (st/emit! (ms/->MouseEvent :up ctrl? shift? alt?))) (when middle-click? (dom/prevent-default event) ;; We store this so in Firefox the middle button won't do a paste of the content (reset! disable-paste true) - (timers/schedule #(reset! disable-paste false)) - (st/emit! (dw/finish-panning) - (dw/finish-zooming))))))) + (timers/schedule #(reset! disable-paste false))) + + (st/emit! (dw/finish-panning) + (dw/finish-zooming)))))) (defn on-pointer-enter [in-viewport?] (mf/use-callback diff --git a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs index 21ea3e700..49c1d9315 100644 --- a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs @@ -57,13 +57,14 @@ ;; We schedule the event so it fires after `initialize-page` event (timers/schedule #(st/emit! (dw/initialize-viewport size))))))) -(defn setup-cursor [cursor alt? panning drawing-tool drawing-path? path-editing?] +(defn setup-cursor [cursor alt? ctrl? space? panning drawing-tool drawing-path? path-editing?] (mf/use-effect - (mf/deps @cursor @alt? panning drawing-tool drawing-path? path-editing?) + (mf/deps @cursor @alt? @ctrl? @space? panning drawing-tool drawing-path? path-editing?) (fn [] (let [new-cursor (cond - panning (utils/get-cursor :hand) + (and @ctrl? @space?) (utils/get-cursor :zoom) + (or panning @space?) (utils/get-cursor :hand) (= drawing-tool :comments) (utils/get-cursor :comments) (= drawing-tool :frame) (utils/get-cursor :create-artboard) (= drawing-tool :rect) (utils/get-cursor :create-rectangle) diff --git a/frontend/src/app/main/ui/workspace/viewport/utils.cljs b/frontend/src/app/main/ui/workspace/viewport/utils.cljs index 9c0734afa..873061070 100644 --- a/frontend/src/app/main/ui/workspace/viewport/utils.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/utils.cljs @@ -179,4 +179,7 @@ :pencil cur/pencil :create-shape cur/create-shape :duplicate cur/duplicate + :zoom cur/zoom + :zoom-in cur/zoom-in + :zooom-out cur/zoom-out cur/pointer-inner)) diff --git a/frontend/src/app/worker/selection.cljs b/frontend/src/app/worker/selection.cljs index d0b229034..ed0412f86 100644 --- a/frontend/src/app/worker/selection.cljs +++ b/frontend/src/app/worker/selection.cljs @@ -105,7 +105,7 @@ (assoc data :index index :z-index z-index))) (defn- query-index - [{index :index z-index :z-index} rect frame-id full-frame? include-frames? clip-children? reverse?] + [{index :index z-index :z-index} rect frame-id full-frame? include-frames? ignore-groups? clip-children? reverse?] (let [result (-> (qdt/search index (clj->js rect)) (es6-iterator-seq)) @@ -117,6 +117,7 @@ (or (not frame-id) (= frame-id (:frame-id shape))) (case (:type shape) :frame include-frames? + (:bool :group) (not ignore-groups?) true) (or (not full-frame?) @@ -189,10 +190,10 @@ nil) (defmethod impl/handler :selection/query - [{:keys [page-id rect frame-id reverse? full-frame? include-frames? clip-children?] + [{:keys [page-id rect frame-id reverse? full-frame? include-frames? ignore-groups? clip-children?] :or {reverse? false full-frame? false include-frames? false clip-children? true} :as message}] (when-let [index (get @state page-id)] - (query-index index rect frame-id full-frame? include-frames? clip-children? reverse?))) + (query-index index rect frame-id full-frame? include-frames? ignore-groups? clip-children? reverse?))) (defmethod impl/handler :selection/query-z-index [{:keys [page-id objects ids]}] From 1abcd5819bdf73c23b506b1b1c34b348823e95c0 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 4 Feb 2022 15:57:11 +0100 Subject: [PATCH 6/8] :sparkles: Enter in dashboard to open files --- frontend/src/app/main/data/dashboard.cljs | 13 ++++++++++++- frontend/src/app/main/ui/dashboard.cljs | 15 ++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/main/data/dashboard.cljs b/frontend/src/app/main/data/dashboard.cljs index c986116f8..6e34b0f5d 100644 --- a/frontend/src/app/main/data/dashboard.cljs +++ b/frontend/src/app/main/data/dashboard.cljs @@ -834,4 +834,15 @@ action (if in-project? file-created project-created)] (->> (rp/mutation! action-name params) - (rx/map action)))))) \ No newline at end of file + (rx/map action)))))) + +(defn open-selected-file + [] + (ptk/reify ::open-selected-file + ptk/WatchEvent + (watch [_ state _] + (let [files (get-in state [:dashboard-local :selected-files])] + (if (= 1 (count files)) + (let [file (get-in state [:dashboard-files (first files)])] + (rx/of (go-to-workspace file))) + (rx/empty)))))) diff --git a/frontend/src/app/main/ui/dashboard.cljs b/frontend/src/app/main/ui/dashboard.cljs index d27bca6ba..a377a70df 100644 --- a/frontend/src/app/main/ui/dashboard.cljs +++ b/frontend/src/app/main/ui/dashboard.cljs @@ -22,7 +22,10 @@ [app.main.ui.dashboard.sidebar :refer [sidebar]] [app.main.ui.dashboard.team :refer [team-settings-page team-members-page]] [app.main.ui.hooks :as hooks] - [rumext.alpha :as mf])) + [app.util.keyboard :as kbd] + [goog.events :as events] + [rumext.alpha :as mf]) + (:import goog.events.EventType)) (defn ^boolean uuid-str? [s] @@ -95,6 +98,16 @@ (mf/with-effect [team-id] (st/emit! (dd/initialize {:id team-id}))) + (mf/use-effect + (fn [] + (let [events [(events/listen goog/global EventType.KEYDOWN + (fn [event] + (when (kbd/enter? event) + (st/emit! (dd/open-selected-file)))))]] + (fn [] + (doseq [key events] + (events/unlistenByKey key)))))) + [:& (mf/provider ctx/current-team-id) {:value team-id} [:& (mf/provider ctx/current-project-id) {:value project-id} ;; NOTE: dashboard events and other related functions assumes From 2b1c8cafe981b0ec96680116842468592b083616 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Mon, 7 Feb 2022 12:35:24 +0100 Subject: [PATCH 7/8] :sparkles: Improved color picker --- .../src/app/main/data/workspace/colors.cljs | 10 +++--- .../app/main/ui/workspace/colorpicker.cljs | 4 +-- .../sidebar/options/menus/shadow.cljs | 6 ++-- .../src/app/main/ui/workspace/viewport.cljs | 12 +++---- .../ui/workspace/viewport/pixel_overlay.cljs | 7 ++-- .../ui/workspace/viewport/scroll_bars.cljs | 36 ++++++++++--------- 6 files changed, 39 insertions(+), 36 deletions(-) diff --git a/frontend/src/app/main/data/workspace/colors.cljs b/frontend/src/app/main/data/workspace/colors.cljs index 5c9d01fab..0cb4eca12 100644 --- a/frontend/src/app/main/data/workspace/colors.cljs +++ b/frontend/src/app/main/data/workspace/colors.cljs @@ -206,11 +206,9 @@ stop? (rx/filter (ptk/type? ::stop-picker) stream) update-events - (fn [[color shift?]] - (rx/of (if shift? - (change-stroke ids color) - (change-fill ids color)) - (stop-picker)))] + (fn [color] + (rx/of (change-fill ids color)))] + (rx/merge ;; Stream that updates the stroke/width and stops if `esc` pressed (->> sub @@ -224,7 +222,7 @@ ptk/UpdateEvent (update [_ state] - (let [handle-change-color (fn [color shift?] (rx/push! sub [color shift?]))] + (let [handle-change-color (fn [color] (rx/push! sub color))] (-> state (assoc-in [:workspace-local :picking-color?] true) (assoc ::md/modal {:id (random-uuid) diff --git a/frontend/src/app/main/ui/workspace/colorpicker.cljs b/frontend/src/app/main/ui/workspace/colorpicker.cljs index 2b3451307..1b5046eeb 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker.cljs @@ -226,9 +226,9 @@ ;; Updates color when used el pixel picker (mf/use-effect - (mf/deps picking-color? picked-color-select) + (mf/deps picking-color? picked-color picked-color-select) (fn [] - (when (and picking-color? picked-color-select) + (when (and picking-color? picked-color picked-color-select) (let [[r g b alpha] picked-color hex (uc/rgb->hex [r g b]) [h s v] (uc/hex->hsv hex)] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs index f7e126c70..6ad85d7fe 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs @@ -77,13 +77,11 @@ update-color (fn [index] - (fn [color opacity] + (fn [color] (let [color (dissoc color :id :file-id :gradient)] (st/emit! (dch/update-shapes ids - #(-> % - (assoc-in [:shadow index :color] color) - (assoc-in [:shadow index :opacity] opacity))))))) + #(assoc-in % [:shadow index :color] color)))))) detach-color (fn [index] diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index def9a0852..16aff53f2 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -248,12 +248,6 @@ :edition edition :zoom zoom}]) - [:& scroll-bars/viewport-scrollbars - {:objects base-objects - :zoom zoom - :vbox vbox - :viewport-ref viewport-ref}] - (when show-selection-handlers? [:& selection/selection-handlers {:selected selected @@ -361,6 +355,12 @@ [:& widgets/viewport-actions] + [:& scroll-bars/viewport-scrollbars + {:objects base-objects + :zoom zoom + :vbox vbox + :viewport-ref viewport-ref}] + (when show-rules? [:* [:& rules/rules diff --git a/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs b/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs index fb35ba997..9fda55c82 100644 --- a/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs @@ -10,6 +10,7 @@ [app.common.uuid :as uuid] [app.main.data.modal :as modal] [app.main.data.workspace.colors :as dwc] + [app.main.data.workspace.undo :as dwu] [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.cursors :as cur] @@ -101,14 +102,16 @@ (fn [event] (dom/prevent-default event) (dom/stop-propagation event) - (st/emit! (dwc/pick-color-select true (kbd/shift? event))))) + (st/emit! (dwu/start-undo-transaction) + (dwc/pick-color-select true (kbd/shift? event))))) handle-mouse-up-picker (mf/use-callback (fn [event] (dom/prevent-default event) (dom/stop-propagation event) - (st/emit! (dwc/stop-picker)) + (st/emit! (dwu/commit-undo-transaction) + (dwc/stop-picker)) (modal/disallow-click-outside!))) handle-image-load diff --git a/frontend/src/app/main/ui/workspace/viewport/scroll_bars.cljs b/frontend/src/app/main/ui/workspace/viewport/scroll_bars.cljs index 70aa9746c..61830c566 100644 --- a/frontend/src/app/main/ui/workspace/viewport/scroll_bars.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/scroll_bars.cljs @@ -157,20 +157,20 @@ (mf/use-callback (mf/deps v-scrollbar-y scrollbar-height) (fn [event axis] - (let [viewport (mf/ref-val viewport-ref) - start-pt (dom/get-client-position event) - new-v-scrollbar-y (-> (utils/translate-point-to-viewport-raw viewport zoom start-pt) :y) - new-h-scrollbar-x (-> (utils/translate-point-to-viewport-raw viewport zoom start-pt) :x) - v-scrollbar-y-padding (- v-scrollbar-y new-v-scrollbar-y) - h-scrollbar-x-padding (- h-scrollbar-x new-h-scrollbar-x) - vbox-rect {:x vbox-x - :y vbox-y - :x1 vbox-x - :y1 vbox-y - :x2 (+ vbox-x (:width vbox)) - :y2 (+ vbox-y (:height vbox)) - :width (:width vbox) - :height (:height vbox)} + (let [viewport (mf/ref-val viewport-ref) + start-pt (dom/get-client-position event) + new-v-scrollbar-y (-> (utils/translate-point-to-viewport-raw viewport zoom start-pt) :y) + new-h-scrollbar-x (-> (utils/translate-point-to-viewport-raw viewport zoom start-pt) :x) + v-scrollbar-y-padding (- v-scrollbar-y new-v-scrollbar-y) + h-scrollbar-x-padding (- h-scrollbar-x new-h-scrollbar-x) + vbox-rect {:x vbox-x + :y vbox-y + :x1 vbox-x + :y1 vbox-y + :x2 (+ vbox-x (:width vbox)) + :y2 (+ vbox-y (:height vbox)) + :width (:width vbox) + :height (:height vbox)} containing-rect (gpr/join-selrects [base-objects-rect vbox-rect]) height-factor (/ (:height containing-rect) vbox-height) width-factor (/ (:width containing-rect) vbox-width)] @@ -207,7 +207,9 @@ :height scrollbar-height :fill-opacity 0.4 :x v-scrollbar-x - :y v-scrollbar-y}]]) + :y v-scrollbar-y + :style {:stroke "white" + :stroke-width 0.15}}]]) (when show-h-scroll? [:g.h-scroll [:rect {:on-mouse-move #(on-mouse-move % :x) @@ -219,4 +221,6 @@ :height (* inv-zoom 7) :fill-opacity 0.4 :x h-scrollbar-x - :y h-scrollbar-y}]])])) + :y h-scrollbar-y + :style {:stroke "white" + :stroke-width 0.15}}]])])) From af8e9058a3c3fff781a3447de8c8c864ea51415f Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Mon, 7 Feb 2022 15:05:38 +0100 Subject: [PATCH 8/8] :sparkles: Move selection with space --- CHANGES.md | 1 + .../src/app/main/data/workspace/drawing.cljs | 4 +- .../app/main/data/workspace/selection.cljs | 90 ++++++++++--------- 3 files changed, 50 insertions(+), 45 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 108078dca..bcfe10084 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -22,6 +22,7 @@ - Add update components in bulk option in context menu [Taiga #1975](https://tree.taiga.io/project/penpot/us/1975) - Create first E2E tests [Taiga #2608](https://tree.taiga.io/project/penpot/task/2608), [Taiga #2608](https://tree.taiga.io/project/penpot/task/2608) - Redesign of workspace toolbars [Taiga #2319](https://tree.taiga.io/project/penpot/us/2319) +- Graphic Tablet usability improvements [Taiga #1913](https://tree.taiga.io/project/penpot/us/1913) ### :bug: Bugs fixed diff --git a/frontend/src/app/main/data/workspace/drawing.cljs b/frontend/src/app/main/data/workspace/drawing.cljs index 522d0150a..c333a7a29 100644 --- a/frontend/src/app/main/data/workspace/drawing.cljs +++ b/frontend/src/app/main/data/workspace/drawing.cljs @@ -45,11 +45,11 @@ (when (= tool :curve) (let [stopper (->> stream (rx/filter dwc/interrupt?))] (->> stream - (rx/take-until stopper) (rx/filter (ptk/type? ::common/handle-finish-drawing)) (rx/take 1) (rx/observe-on :async) - (rx/map #(select-for-drawing tool data))))) + (rx/map #(select-for-drawing tool data)) + (rx/take-until stopper)))) ;; NOTE: comments are a special case and they manage they ;; own interrupt cycle.q diff --git a/frontend/src/app/main/data/workspace/selection.cljs b/frontend/src/app/main/data/workspace/selection.cljs index 264874a94..916103b03 100644 --- a/frontend/src/app/main/data/workspace/selection.cljs +++ b/frontend/src/app/main/data/workspace/selection.cljs @@ -9,7 +9,6 @@ [app.common.data :as d] [app.common.geom.point :as gpt] [app.common.geom.shapes :as geom] - [app.common.math :as mth] [app.common.pages :as cp] [app.common.spec :as us] [app.common.spec.interactions :as cti] @@ -48,52 +47,57 @@ (defn handle-area-selection [preserve? ignore-groups?] - (letfn [(data->selrect [data] - (let [start (:start data) - stop (:stop data) - start-x (min (:x start) (:x stop)) - start-y (min (:y start) (:y stop)) - end-x (max (:x start) (:x stop)) - end-y (max (:y start) (:y stop))] - {:type :rect - :x start-x - :y start-y - :width (mth/abs (- end-x start-x)) - :height (mth/abs (- end-y start-y))}))] - (ptk/reify ::handle-area-selection - ptk/WatchEvent - (watch [_ state stream] - (let [zoom (get-in state [:workspace-local :zoom] 1) - stop? (fn [event] (or (dwc/interrupt? event) (ms/mouse-up? event))) - stoper (->> stream (rx/filter stop?)) + (ptk/reify ::handle-area-selection + ptk/WatchEvent + (watch [_ state stream] + (let [zoom (get-in state [:workspace-local :zoom] 1) + stop? (fn [event] (or (dwc/interrupt? event) (ms/mouse-up? event))) + stoper (->> stream (rx/filter stop?)) - calculate-selrect - (fn [data pos] - (if data - (assoc data :stop pos) - {:start pos :stop pos})) + init-selrect + {:type :rect + :x (:x @ms/mouse-position) + :y (:y @ms/mouse-position) + :width 0 + :height 0} - selrect-stream - (->> ms/mouse-position - (rx/scan calculate-selrect nil) - (rx/map data->selrect) - (rx/filter #(or (> (:width %) (/ 10 zoom)) - (> (:height %) (/ 10 zoom)))) - (rx/take-until stoper))] - (rx/concat - (if preserve? - (rx/empty) - (rx/of (deselect-all))) + calculate-selrect + (fn [selrect [delta space?]] + (if space? + (-> selrect + (update :x + (:x delta)) + (update :y + (:y delta))) - (rx/merge - (->> selrect-stream (rx/map update-selrect)) - (->> selrect-stream - (rx/buffer-time 100) - (rx/map #(last %)) - (rx/dedupe) - (rx/map #(select-shapes-by-current-selrect preserve? ignore-groups?)))) + (-> selrect + (update :width + (:x delta)) + (update :height + (:y delta))))) - (rx/of (update-selrect nil)))))))) + selrect-stream + (->> ms/mouse-position + (rx/buffer 2 1) + (rx/map (fn [[from to]] (when (and from to) (gpt/to-vec from to)))) + (rx/filter some?) + (rx/with-latest-from ms/keyboard-space) + (rx/scan calculate-selrect init-selrect) + (rx/filter #(or (> (:width %) (/ 10 zoom)) + (> (:height %) (/ 10 zoom)))) + (rx/take-until stoper))] + (rx/concat + (if preserve? + (rx/empty) + (rx/of (deselect-all))) + + (rx/merge + (->> selrect-stream + (rx/map update-selrect)) + + (->> selrect-stream + (rx/buffer-time 100) + (rx/map #(last %)) + (rx/dedupe) + (rx/map #(select-shapes-by-current-selrect preserve? ignore-groups?)))) + + (rx/of (update-selrect nil))))))) ;; --- Toggle shape's selection status (selected or deselected)