diff --git a/CHANGES.md b/CHANGES.md index 7d76d9b6a..fad43cc30 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -23,6 +23,7 @@ - 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) +- Improved mouse collision detection for groups and text shapes [Taiga #2452](https://tree.taiga.io/project/penpot/us/2452), [Taiga #2453](https://tree.taiga.io/project/penpot/us/2453) ### :bug: Bugs fixed diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index 16aff53f2..ffbdc7d39 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -84,6 +84,7 @@ ;; REFS viewport-ref (mf/use-ref nil) + raw-position-ref (mf/use-ref nil) ;; Stores the raw position of the cursor ;; VARS disable-paste (mf/use-var false) @@ -127,7 +128,7 @@ 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-move (actions/on-pointer-move viewport-ref raw-position-ref zoom move-stream) on-pointer-up (actions/on-pointer-up) on-move-selected (actions/on-move-selected hover hover-ids selected space?) on-menu-selected (actions/on-menu-selected hover hover-ids selected) @@ -164,7 +165,7 @@ (hooks/setup-viewport-size viewport-ref) (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-hover-shapes page-id move-stream raw-position-ref 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) diff --git a/frontend/src/app/main/ui/workspace/viewport/actions.cljs b/frontend/src/app/main/ui/workspace/viewport/actions.cljs index 084f9ec8f..c454d3698 100644 --- a/frontend/src/app/main/ui/workspace/viewport/actions.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/actions.cljs @@ -346,13 +346,14 @@ (kbd/shift? event) (kbd/alt? event)))))))) -(defn on-pointer-move [viewport-ref zoom move-stream] +(defn on-pointer-move [viewport-ref raw-position-ref zoom move-stream] (mf/use-callback (mf/deps zoom move-stream) (fn [event] (let [raw-pt (dom/get-client-position event) viewport (mf/ref-val viewport-ref) pt (utils/translate-point-to-viewport viewport zoom raw-pt)] + (mf/set-ref-val! raw-position-ref raw-pt) (rx/push! move-stream pt))))) (defn on-mouse-wheel [viewport-ref zoom] diff --git a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs index af3180260..81a9352ba 100644 --- a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs @@ -8,6 +8,7 @@ (:require [app.common.data :as d] [app.common.geom.shapes :as gsh] + [app.common.geom.shapes.rect :as gshr] [app.common.pages.helpers :as cph] [app.main.data.shortcuts :as dsc] [app.main.data.workspace :as dw] @@ -84,7 +85,30 @@ (hooks/use-stream ms/keyboard-ctrl #(reset! ctrl? %)) (hooks/use-stream ms/keyboard-space #(reset! space? %))) -(defn setup-hover-shapes [page-id move-stream objects transform selected ctrl? hover hover-ids hover-disabled? zoom] +(defn group-empty-space? + "Given a group `group-id` check if `hover-ids` contains any of its children. If it doesn't means + we're hovering over empty space for the group " + [group-id objects hover-ids] + + (and (contains? #{:group :bool} (get-in objects [group-id :type])) + + ;; If there are no children in the hover-ids we're in the empty side + (->> hover-ids + (remove #(contains? #{:group :bool} (get-in objects [% :type]))) + (some #(cph/is-parent? objects % group-id)) + (not)))) + +(defn check-text-collision? + "Checks if he current position `pos` overlaps any of the text-nodes for the given `text-id`" + [objects pos text-id] + (and (= :text (get-in objects [text-id :type])) + (let [collisions + (->> (dom/query-all (str "#shape-" text-id " .text-node")) + (map dom/get-bounding-rect) + (map dom/bounding-rect->rect))] + (not (some #(gshr/contains-point? % pos) collisions))))) + +(defn setup-hover-shapes [page-id move-stream raw-position-ref objects transform selected ctrl? hover hover-ids hover-disabled? zoom] (let [;; We use ref so we don't recreate the stream on a change zoom-ref (mf/use-ref zoom) ctrl-ref (mf/use-ref @ctrl?) @@ -156,6 +180,12 @@ remove-xfm (mapcat #(cph/get-parent-ids objects %)) remove-id? (cond-> (into #{} remove-xfm selected) + :always + (into (filter #(check-text-collision? objects (mf/ref-val raw-position-ref) %)) ids) + + (not @ctrl?) + (into (filter #(group-empty-space? % objects ids)) ids) + @ctrl? (into (filter is-group?) ids)) diff --git a/frontend/src/app/util/dom.cljs b/frontend/src/app/util/dom.cljs index b202fab0f..15cbf004e 100644 --- a/frontend/src/app/util/dom.cljs +++ b/frontend/src/app/util/dom.cljs @@ -257,6 +257,13 @@ :width (.-width ^js rect) :height (.-height ^js rect)})) +(defn bounding-rect->rect + [{:keys [left top width height]}] + {:x left + :y top + :width width + :height height}) + (defn get-window-size [] {:width (.-innerWidth ^js js/window)