mirror of
https://github.com/penpot/penpot.git
synced 2026-02-17 09:03:03 +00:00
✨ Graphic tablet use improvements: add scroll bars
This commit is contained in:
committed by
Andrey Antukh
parent
04f7169aef
commit
f72e140327
@@ -6,8 +6,9 @@
|
||||
|
||||
### :sparkles: New features
|
||||
|
||||
- Scroll bars [Taiga #2550](https://tree.taiga.io/project/penpot/task/2550)
|
||||
- Add select layer option to context menu [Taiga #2474](https://tree.taiga.io/project/penpot/us/2474).
|
||||
- Guides [Taiga #290](https://tree.taiga.io/project/penpot/us/290?milestone=307334)
|
||||
- Guides [Taiga #290](https://tree.taiga.io/project/penpot/us/290)
|
||||
- Improve file menu by adding semantically groups [Github #1203](https://github.com/penpot/penpot/issues/1203).
|
||||
- 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)
|
||||
|
||||
@@ -138,10 +138,10 @@
|
||||
.coordinates {
|
||||
background-color: $color-dark-bg;
|
||||
border-radius: $br-small;
|
||||
bottom: -10px;
|
||||
bottom: 0px;
|
||||
padding-left: 5px;
|
||||
position: fixed;
|
||||
right: calc(#{$width-settings-bar} + 10px);
|
||||
right: calc(#{$width-settings-bar} + 14px);
|
||||
text-align: center;
|
||||
width: 125px;
|
||||
white-space: nowrap;
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
[app.main.ui.workspace.viewport.pixel-overlay :as pixel-overlay]
|
||||
[app.main.ui.workspace.viewport.presence :as presence]
|
||||
[app.main.ui.workspace.viewport.rules :as rules]
|
||||
[app.main.ui.workspace.viewport.scroll-bars :as scroll-bars]
|
||||
[app.main.ui.workspace.viewport.selection :as selection]
|
||||
[app.main.ui.workspace.viewport.snap-distances :as snap-distances]
|
||||
[app.main.ui.workspace.viewport.snap-points :as snap-points]
|
||||
@@ -250,7 +251,13 @@
|
||||
:hover (when (not= :frame (:type @hover))
|
||||
#{(or @frame-hover (:id @hover))})
|
||||
:edition edition
|
||||
:zoom zoom}])
|
||||
:zoom zoom}]
|
||||
|
||||
[:& scroll-bars/viewport-scrollbars
|
||||
{:objects base-objects
|
||||
:zoom zoom
|
||||
:vbox vbox
|
||||
:viewport-ref viewport-ref}])
|
||||
|
||||
(when show-selection-handlers?
|
||||
[:& selection/selection-handlers
|
||||
|
||||
212
frontend/src/app/main/ui/workspace/viewport/scroll_bars.cljs
Normal file
212
frontend/src/app/main/ui/workspace/viewport/scroll_bars.cljs
Normal file
@@ -0,0 +1,212 @@
|
||||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
;;
|
||||
;; Copyright (c) UXBOX Labs SL
|
||||
|
||||
(ns app.main.ui.workspace.viewport.scroll-bars
|
||||
(:require
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.geom.shapes.rect :as gpr]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.workspace.viewport.utils :as utils]
|
||||
[app.util.dom :as dom]
|
||||
[rumext.alpha :as mf]))
|
||||
|
||||
(mf/defc viewport-scrollbars
|
||||
{::mf/wrap [mf/memo]}
|
||||
[{:keys [objects viewport-ref zoom vbox]}]
|
||||
|
||||
(let [v-scrolling? (mf/use-state false)
|
||||
h-scrolling? (mf/use-state false)
|
||||
start-ref (mf/use-ref nil)
|
||||
v-scrollbar-y-ref (mf/use-ref nil)
|
||||
h-scrollbar-x-ref (mf/use-ref nil)
|
||||
v-scrollbar-y-stored (mf/ref-val v-scrollbar-y-ref)
|
||||
h-scrollbar-x-stored (mf/ref-val h-scrollbar-x-ref)
|
||||
v-scrollbar-y-padding-ref (mf/use-ref nil)
|
||||
h-scrollbar-x-padding-ref (mf/use-ref nil)
|
||||
scrollbar-height-ref (mf/use-ref nil)
|
||||
scrollbar-width-ref (mf/use-ref nil)
|
||||
scrollbar-height-stored (mf/ref-val scrollbar-height-ref)
|
||||
scrollbar-width-stored (mf/ref-val scrollbar-width-ref)
|
||||
height-factor-ref (mf/use-ref nil)
|
||||
width-factor-ref (mf/use-ref nil)
|
||||
vbox-y-ref (mf/use-ref nil)
|
||||
vbox-x-ref (mf/use-ref nil)
|
||||
|
||||
vbox-x (:x vbox)
|
||||
vbox-y (:y vbox)
|
||||
|
||||
base-objects-rect
|
||||
(mf/use-memo
|
||||
(mf/deps objects)
|
||||
(fn []
|
||||
(let [root-shapes (-> objects cph/get-top-frame :shapes)
|
||||
shapes (->> root-shapes (mapv #(get objects %)))]
|
||||
(gsh/selection-rect shapes))))
|
||||
|
||||
inv-zoom (/ 1 zoom)
|
||||
vbox-height (- (:height vbox) (* inv-zoom 44))
|
||||
vbox-width (- (:width vbox) (* inv-zoom 34))
|
||||
|
||||
;; top space hidden because of the scroll
|
||||
top-offset (-> (- vbox-y (:y base-objects-rect))
|
||||
(max 0)
|
||||
(* vbox-height)
|
||||
(/ (:height base-objects-rect)))
|
||||
;; left space hidden because of the scroll
|
||||
left-offset (-> (- vbox-x (:x base-objects-rect))
|
||||
(max 0)
|
||||
(* vbox-width)
|
||||
(/ (:width base-objects-rect)))
|
||||
|
||||
;; bottom space hidden because of the scroll
|
||||
bottom-offset (-> (- (:y2 base-objects-rect) (+ vbox-y vbox-height))
|
||||
(max 0)
|
||||
(* vbox-height)
|
||||
(/ (:height base-objects-rect)))
|
||||
|
||||
;; right space hidden because of the scroll
|
||||
right-offset (-> (- (:x2 base-objects-rect) (+ vbox-x vbox-width))
|
||||
(max 0)
|
||||
(* vbox-width)
|
||||
(/ (:width base-objects-rect)))
|
||||
|
||||
show-v-scroll? (or @v-scrolling? (> top-offset 0) (> bottom-offset 0))
|
||||
show-h-scroll? (or @h-scrolling? (> left-offset 0) (> right-offset 0))
|
||||
|
||||
v-scrollbar-x (+ vbox-x (:width vbox) (* inv-zoom -32))
|
||||
v-scrollbar-y (+ vbox-y top-offset)
|
||||
|
||||
h-scrollbar-x (+ vbox-x left-offset)
|
||||
h-scrollbar-y (+ vbox-y (:height vbox) (* inv-zoom -40))
|
||||
|
||||
scrollbar-height (-> (- (+ vbox-y vbox-height) bottom-offset v-scrollbar-y))
|
||||
scrollbar-height (-> (cond
|
||||
@v-scrolling? scrollbar-height-stored
|
||||
:else scrollbar-height)
|
||||
(max (* inv-zoom 100)))
|
||||
|
||||
scrollbar-width (-> (- (+ vbox-x vbox-width) right-offset h-scrollbar-x))
|
||||
scrollbar-width (-> (cond
|
||||
@h-scrolling? scrollbar-width-stored
|
||||
:else scrollbar-width)
|
||||
(max (* inv-zoom 100)))
|
||||
|
||||
v-scrollbar-y (-> (cond
|
||||
@v-scrolling? (- v-scrollbar-y-stored (- (- vbox-y (mf/ref-val vbox-y-ref))))
|
||||
:else v-scrollbar-y)
|
||||
(max (+ vbox-y (* inv-zoom 26))))
|
||||
|
||||
v-scrollbar-y (if (> (+ v-scrollbar-y scrollbar-height) (+ vbox-y vbox-height)) ;; the scroll bar is stick to the bottom
|
||||
(-> (+ vbox-y vbox-height)
|
||||
(- scrollbar-height))
|
||||
v-scrollbar-y)
|
||||
|
||||
h-scrollbar-x (-> (cond
|
||||
@h-scrolling? (- h-scrollbar-x-stored (- (- vbox-x (mf/ref-val vbox-x-ref))))
|
||||
:else h-scrollbar-x)
|
||||
(max (+ vbox-x (* inv-zoom 26))))
|
||||
|
||||
h-scrollbar-x (if (> (+ h-scrollbar-x scrollbar-width) (+ vbox-x vbox-width)) ;; the scroll bar is stick to the right
|
||||
(-> (+ vbox-x vbox-width)
|
||||
(- scrollbar-width))
|
||||
h-scrollbar-x)
|
||||
|
||||
on-mouse-move
|
||||
(mf/use-callback
|
||||
(mf/deps zoom v-scrolling?)
|
||||
(fn [event axis]
|
||||
(when-let [_ (or @v-scrolling? @h-scrolling?)]
|
||||
(let [viewport (mf/ref-val viewport-ref)
|
||||
start-pt (mf/ref-val start-ref)
|
||||
current-pt (dom/get-client-position event)
|
||||
current-pt-viewport (utils/translate-point-to-viewport-raw viewport zoom current-pt)
|
||||
y-delta (/ (* (mf/ref-val height-factor-ref) (- (:y current-pt) (:y start-pt))) zoom)
|
||||
x-delta (/ (* (mf/ref-val width-factor-ref) (- (:x current-pt) (:x start-pt))) zoom)
|
||||
new-v-scrollbar-y (-> current-pt-viewport
|
||||
(:y)
|
||||
(+ (mf/ref-val v-scrollbar-y-padding-ref)))
|
||||
new-h-scrollbar-x (-> current-pt-viewport
|
||||
(:x)
|
||||
(+ (mf/ref-val h-scrollbar-x-padding-ref)))
|
||||
viewport-update (-> {}
|
||||
(cond-> (= axis :y) (assoc :y #(+ % y-delta)))
|
||||
(cond-> (= axis :x) (assoc :x #(+ % x-delta))))]
|
||||
(mf/set-ref-val! vbox-y-ref vbox-y)
|
||||
(mf/set-ref-val! vbox-x-ref vbox-x)
|
||||
(st/emit! (dw/update-viewport-position viewport-update))
|
||||
(mf/set-ref-val! v-scrollbar-y-ref new-v-scrollbar-y)
|
||||
(mf/set-ref-val! h-scrollbar-x-ref new-h-scrollbar-x)
|
||||
(mf/set-ref-val! start-ref current-pt)))))
|
||||
|
||||
on-mouse-down
|
||||
(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)}
|
||||
containing-rect (gpr/join-selrects [base-objects-rect vbox-rect])
|
||||
height-factor (/ (:height containing-rect) vbox-height)
|
||||
width-factor (/ (:width containing-rect) vbox-width)]
|
||||
(mf/set-ref-val! start-ref start-pt)
|
||||
(mf/set-ref-val! v-scrollbar-y-padding-ref v-scrollbar-y-padding)
|
||||
(mf/set-ref-val! h-scrollbar-x-padding v-scrollbar-y-padding)
|
||||
(mf/set-ref-val! v-scrollbar-y-ref (+ new-v-scrollbar-y v-scrollbar-y-padding))
|
||||
(mf/set-ref-val! h-scrollbar-x-ref (+ new-h-scrollbar-x h-scrollbar-x-padding))
|
||||
(mf/set-ref-val! vbox-y-ref vbox-y)
|
||||
(mf/set-ref-val! vbox-x-ref vbox-x)
|
||||
(mf/set-ref-val! scrollbar-height-ref scrollbar-height)
|
||||
(mf/set-ref-val! scrollbar-width-ref scrollbar-width)
|
||||
(mf/set-ref-val! height-factor-ref height-factor)
|
||||
(mf/set-ref-val! width-factor-ref width-factor)
|
||||
(reset! v-scrolling? (= axis :y))
|
||||
(reset! h-scrolling? (= axis :x)))))
|
||||
|
||||
on-mouse-up
|
||||
(mf/use-callback
|
||||
(mf/deps)
|
||||
(fn [_]
|
||||
(reset! v-scrolling? false)
|
||||
(reset! h-scrolling? false)))]
|
||||
|
||||
[*
|
||||
(when show-v-scroll?
|
||||
[:g.v-scroll
|
||||
[:rect {:on-mouse-move #(on-mouse-move % :y)
|
||||
:on-mouse-down #(on-mouse-down % :y)
|
||||
:on-mouse-up #(on-mouse-up % :y)
|
||||
:width (* inv-zoom 7)
|
||||
:rx (* inv-zoom 3)
|
||||
:ry (* inv-zoom 3)
|
||||
:height scrollbar-height
|
||||
:fill-opacity 0.4
|
||||
:x v-scrollbar-x
|
||||
:y v-scrollbar-y}]])
|
||||
(when show-h-scroll?
|
||||
[:g.h-scroll
|
||||
[:rect {:on-mouse-move #(on-mouse-move % :x)
|
||||
:on-mouse-down #(on-mouse-down % :x)
|
||||
:on-mouse-up #(on-mouse-up % :x)
|
||||
:width scrollbar-width
|
||||
:rx (* inv-zoom 3)
|
||||
:ry (* inv-zoom 3)
|
||||
:height (* inv-zoom 7)
|
||||
:fill-opacity 0.4
|
||||
:x h-scrollbar-x
|
||||
:y h-scrollbar-y}]])]))
|
||||
@@ -153,7 +153,7 @@
|
||||
(:width vbox 0)
|
||||
(:height vbox 0)]))
|
||||
|
||||
(defn translate-point-to-viewport [viewport zoom pt]
|
||||
(defn translate-point-to-viewport-raw [viewport zoom pt]
|
||||
(let [vbox (.. ^js viewport -viewBox -baseVal)
|
||||
brect (dom/get-bounding-rect viewport)
|
||||
brect (gpt/point (d/parse-integer (:left brect))
|
||||
@@ -162,8 +162,11 @@
|
||||
zoom (gpt/point zoom)]
|
||||
(-> (gpt/subtract pt brect)
|
||||
(gpt/divide zoom)
|
||||
(gpt/add box)
|
||||
(gpt/round 0))))
|
||||
(gpt/add box))))
|
||||
|
||||
(defn translate-point-to-viewport [viewport zoom pt]
|
||||
(-> (translate-point-to-viewport-raw viewport zoom pt)
|
||||
(gpt/round 0)))
|
||||
|
||||
(defn get-cursor [cursor]
|
||||
(case cursor
|
||||
|
||||
Reference in New Issue
Block a user