From a06a8c648ecffcff32969a5fdeb5c09be895e1b7 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Tue, 30 Mar 2021 17:13:05 +0200 Subject: [PATCH] :sparkles: Select path nodes in area --- common/app/common/geom/shapes.cljc | 1 + common/app/common/geom/shapes/intersect.cljc | 5 ++ common/app/common/geom/shapes/rect.cljc | 6 ++ .../app/main/data/workspace/drawing/path.cljs | 71 ++++++++++++++++++- .../app/main/data/workspace/selection.cljs | 5 +- .../main/ui/workspace/shapes/path/editor.cljs | 34 +++++---- .../src/app/main/ui/workspace/viewport.cljs | 2 +- .../main/ui/workspace/viewport/actions.cljs | 14 ++-- 8 files changed, 112 insertions(+), 26 deletions(-) diff --git a/common/app/common/geom/shapes.cljc b/common/app/common/geom/shapes.cljc index de6826249..28e110b73 100644 --- a/common/app/common/geom/shapes.cljc +++ b/common/app/common/geom/shapes.cljc @@ -253,3 +253,4 @@ ;; Intersection (d/export gin/overlaps?) (d/export gin/has-point?) +(d/export gin/has-point-rect?) diff --git a/common/app/common/geom/shapes/intersect.cljc b/common/app/common/geom/shapes/intersect.cljc index 6b9e3f5be..0b6fbcd6f 100644 --- a/common/app/common/geom/shapes/intersect.cljc +++ b/common/app/common/geom/shapes/intersect.cljc @@ -285,6 +285,11 @@ (or (not path?) (overlaps-path? shape rect)) (or (not circle?) (overlaps-ellipse? shape rect)))))) +(defn has-point-rect? + [rect point] + (let [lines (gpr/rect->lines rect)] + (is-point-inside-evenodd? point lines))) + (defn has-point? "Check if the shape contains a point" [shape point] diff --git a/common/app/common/geom/shapes/rect.cljc b/common/app/common/geom/shapes/rect.cljc index be221b1d9..91e7d18a9 100644 --- a/common/app/common/geom/shapes/rect.cljc +++ b/common/app/common/geom/shapes/rect.cljc @@ -19,6 +19,12 @@ (gpt/point (+ x width) (+ y height)) (gpt/point x (+ y height))]) +(defn rect->lines [{:keys [x y width height]}] + [[(gpt/point x y) (gpt/point (+ x width) y)] + [(gpt/point (+ x width) y) (gpt/point (+ x width) (+ y height))] + [(gpt/point (+ x width) (+ y height)) (gpt/point x (+ y height))] + [(gpt/point x (+ y height)) (gpt/point x y)]]) + (defn points->rect [points] (let [minx (transduce gco/map-x-xf min ##Inf points) diff --git a/frontend/src/app/main/data/workspace/drawing/path.cljs b/frontend/src/app/main/data/workspace/drawing/path.cljs index 494d796af..b0ed2dcac 100644 --- a/frontend/src/app/main/data/workspace/drawing/path.cljs +++ b/frontend/src/app/main/data/workspace/drawing/path.cljs @@ -732,7 +732,23 @@ (-> state (update-in [:workspace-local :edit-path id :selected-handlers] (fnil conj #{}) [index type])))))) -(defn select-node [position] +(defn select-node-area [shift?] + (ptk/reify ::select-node-area + ptk/UpdateEvent + (update [_ state] + (let [selrect (get-in state [:workspace-local :selrect]) + id (get-in state [:workspace-local :edition]) + content (get-in state (get-path state :content)) + selected-point? (fn [point] + (gsh/has-point-rect? selrect point)) + positions (into #{} + (comp (map (comp gpt/point :params)) + (filter selected-point?)) + content)] + (-> state + (assoc-in [:workspace-local :edit-path id :selected-points] positions)))))) + +(defn select-node [position shift?] (ptk/reify ::select-node ptk/UpdateEvent (update [_ state] @@ -740,7 +756,7 @@ (-> state (assoc-in [:workspace-local :edit-path id :selected-points] #{position})))))) -(defn deselect-node [position] +(defn deselect-node [position shift?] (ptk/reify ::deselect-node ptk/UpdateEvent (update [_ state] @@ -858,3 +874,54 @@ (rx/filter #(= % :interrupt)) (rx/take 1) (rx/map #(stop-path-edit)))))))) + + +(defn update-area-selection + [selrect] + (ptk/reify ::update-area-selection + ptk/UpdateEvent + (update [_ state] + (assoc-in state [:workspace-local :selrect] selrect)))) + +(defn clear-area-selection + [] + (ptk/reify ::clear-area-selection + ptk/UpdateEvent + (update [_ state] + (update state :workspace-local dissoc :selrect)))) + +(defn handle-selection + [shift?] + (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))] + {:x start-x + :y start-y + :width (mth/abs (- end-x start-x)) + :height (mth/abs (- end-y start-y))}))] + (ptk/reify ::handle-selection + ptk/WatchEvent + (watch [_ state stream] + (let [stop? (fn [event] (or (dwc/interrupt? event) (ms/mouse-up? event))) + stoper (->> stream (rx/filter stop?))] + (rx/concat + #_(when-not preserve? + (rx/of (deselect-all))) + (->> ms/mouse-position + (rx/scan (fn [data pos] + (if data + (assoc data :stop pos) + {:start pos :stop pos})) + nil) + (rx/map data->selrect) + (rx/filter #(or (> (:width %) 10) + (> (:height %) 10))) + (rx/map update-area-selection) + (rx/take-until stoper)) + (rx/of (select-node-area shift?) + (clear-area-selection)) + #_(rx/of (select-shapes-by-current-selrect preserve?)))))))) diff --git a/frontend/src/app/main/data/workspace/selection.cljs b/frontend/src/app/main/data/workspace/selection.cljs index 8761f0a67..6812a5a9f 100644 --- a/frontend/src/app/main/data/workspace/selection.cljs +++ b/frontend/src/app/main/data/workspace/selection.cljs @@ -60,9 +60,8 @@ (ptk/reify ::handle-selection ptk/WatchEvent (watch [_ state stream] - (let [stoper (rx/filter #(or (dwc/interrupt? %) - (ms/mouse-up? %)) - stream)] + (let [stop? (fn [event] (or (dwc/interrupt? event) (ms/mouse-up? event))) + stoper (->> stream (rx/filter stop?))] (rx/concat (when-not preserve? (rx/of (deselect-all))) diff --git a/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs b/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs index 494761da8..b743e4270 100644 --- a/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs @@ -15,7 +15,9 @@ [app.util.dom :as dom] [app.util.geom.path :as ugp] [goog.events :as events] - [rumext.alpha :as mf]) + [rumext.alpha :as mf] + + [app.util.keyboard :as kbd]) (:import goog.events.EventType)) (mf/defc path-point [{:keys [position zoom edit-mode hover? selected? preview? start-path? last-p?]}] @@ -35,12 +37,13 @@ (dom/stop-propagation event) (dom/prevent-default event) - (cond - (and (= edit-mode :move) (not selected?)) - (st/emit! (drp/select-node position)) + (let [shift? (kbd/shift? event)] + (cond + (and (= edit-mode :move) (not selected?)) + (st/emit! (drp/select-node position shift?)) - (and (= edit-mode :move) selected?) - (st/emit! (drp/deselect-node position))))) + (and (= edit-mode :move) selected?) + (st/emit! (drp/deselect-node position shift?)))))) on-mouse-down @@ -177,23 +180,24 @@ last-p (->> content last ugp/command->point) handlers (ugp/content->handlers content) - handle-click-outside - (fn [event] - (let [current (dom/get-target event) - editor-dom (mf/ref-val editor-ref)] - (when-not (or (.contains editor-dom current) - (dom/class? current "viewport-actions-entry")) - (st/emit! (drp/deselect-all))))) + ;;handle-click-outside + ;;(fn [event] + ;; (let [current (dom/get-target event) + ;; editor-dom (mf/ref-val editor-ref)] + ;; (when-not (or (.contains editor-dom current) + ;; (dom/class? current "viewport-actions-entry")) + ;; (st/emit! (drp/deselect-all))))) handle-double-click-outside (fn [event] (when (= edit-mode :move) - (st/emit! :interrupt)))] + (st/emit! :interrupt))) + ] (mf/use-layout-effect (mf/deps edit-mode) (fn [] - (let [keys [(events/listen (dom/get-root) EventType.CLICK handle-click-outside) + (let [keys [;;(events/listen (dom/get-root) EventType.CLICK handle-click-outside) (events/listen (dom/get-root) EventType.DBLCLICK handle-double-click-outside)]] #(doseq [key keys] (events/unlistenByKey key))))) diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index cff98f588..bd2ccb43c 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -101,7 +101,7 @@ on-click (actions/on-click hover selected edition drawing-path? drawing-tool) on-context-menu (actions/on-context-menu hover) - on-double-click (actions/on-double-click hover hover-ids drawing-path? objects) + on-double-click (actions/on-double-click hover hover-ids drawing-path? 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) diff --git a/frontend/src/app/main/ui/workspace/viewport/actions.cljs b/frontend/src/app/main/ui/workspace/viewport/actions.cljs index 1d94d938d..f2d2d203b 100644 --- a/frontend/src/app/main/ui/workspace/viewport/actions.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/actions.cljs @@ -15,6 +15,7 @@ [app.main.store :as st] [app.main.streams :as ms] [app.main.ui.workspace.viewport.utils :as utils] + [app.main.data.workspace.drawing.path :as dwdp] [app.util.dom :as dom] [app.util.dom.dnd :as dnd] [app.util.keyboard :as kbd] @@ -57,13 +58,16 @@ (st/emit! dw/clear-edition-mode)) (when (and (or (not edition) (not= edition id)) (not blocked) (not hidden) (not (#{:comments :path} drawing-tool))) + (not= edition id)) + (not blocked) + (not hidden)) (cond drawing-tool (st/emit! (dd/start-drawing drawing-tool)) (and edit-path (contains? edit-path edition)) - ;; Handle node select-drawing. NOP at the moment - nil + ;; Handle path node area selection + (st/emit! (dwdp/handle-selection shift?)) (or (not id) (and frame? (not selected?))) (st/emit! (dw/handle-selection shift?)) @@ -142,9 +146,9 @@ (st/emit! (dw/select-shape (:id @hover))))))))) (defn on-double-click - [hover hover-ids drawing-path? objects] + [hover hover-ids drawing-path? objects edition] (mf/use-callback - (mf/deps @hover @hover-ids drawing-path?) + (mf/deps @hover @hover-ids drawing-path? edition) (fn [event] (dom/stop-propagation event) (let [ctrl? (kbd/ctrl? event) @@ -170,7 +174,7 @@ (reset! hover-ids (into [] (rest @hover-ids))) (st/emit! (dw/select-shape (:id selected)))) - (or text? path?) + (and (not= id edition) (or text? path?)) (st/emit! (dw/select-shape id) (dw/start-editing-selected))