branch: elpa/scroll-on-jump commit 222f9c1d33659bc367a1b507a68c0df73f9e3db8 Author: Campbell Barton <ideasma...@gmail.com> Commit: Campbell Barton <ideasma...@gmail.com>
Add support for ease-in and ease-out curves Also add scroll-on-jump-curve-power to control the strength of the curve. --- changelog.rst | 3 ++ readme.rst | 20 +++++++++--- scroll-on-jump.el | 91 ++++++++++++++++++++++++++++++++++++++++--------------- 3 files changed, 86 insertions(+), 28 deletions(-) diff --git a/changelog.rst b/changelog.rst index b336034ab1..7c32d6bb86 100644 --- a/changelog.rst +++ b/changelog.rst @@ -3,6 +3,9 @@ Change Log ########## + - Add ``scroll-on-jump-curve`` & ``scroll-on-jump-curve-power`` + to support different kinds of curves & control their strength. + - Version 0.2 (2023-01-22) - Add ``scroll-on-jump-mode-line-format`` to support overriding the mode-line while scrolling. diff --git a/readme.rst b/readme.rst index a4af4efebf..9df3920e2a 100644 --- a/readme.rst +++ b/readme.rst @@ -162,13 +162,25 @@ Customization While the defaults seem to work well, these values can be customized. -``scroll-on-jump-duration``: 0.4 +``scroll-on-jump-duration``: ``0.4`` The duration for jumping to take, set to ``0.0`` to jump immediately. -``scroll-on-jump-smooth``: t +``scroll-on-jump-smooth``: ``t`` When not nil, use smooth scrolling (by pixels). -``scroll-on-jump-use-curve``: t +``scroll-on-jump-curve``: ``'smooth`` Apply a curve to the scroll speed, starting and ending slow. -``scroll-on-jump-mode-line-format``: nil + + :'smooth: Ease in/out. + :'smooth-in: Ease in (end slow). + :'smooth-out: Ease in (start slow). + :'linear: Linear motion (no easing). +``scroll-on-jump-curve-power``: ``3.0`` + The strength of the curve (when non-linear). + + Values between 2 and 8 work well. + + - Below 2.0 approaches a linear curve. + - Above 8.0 can make the motion overly abrupt. +``scroll-on-jump-mode-line-format``: ``nil`` When non-nil, use this value for the ``mode-line-format`` while scrolling. This can be used to temporarily override the mode-line while scrolling. It can also help to avoid overly complex mode-lines from slowing down scrolling. diff --git a/scroll-on-jump.el b/scroll-on-jump.el index 0bc11ebbdf..6cb9006caf 100644 --- a/scroll-on-jump.el +++ b/scroll-on-jump.el @@ -40,9 +40,19 @@ "Use smooth (pixel) scrolling, otherwise scroll by lines." :type 'boolean) -(defcustom scroll-on-jump-use-curve t - "Apply a curve to the scroll speed, starting and ending slow." - :type 'boolean) +(defcustom scroll-on-jump-curve 'smooth + "The the method scrolling is calculated." + :type + '(choice + (const :tag "Smooth in/out, starts & ends slow" smooth) + (const :tag "Smooth in, starts slow" smooth-in) + (const :tag "Smooth out, ends slow" smooth-out) + (const :tag "Linear" linear))) + +(defcustom scroll-on-jump-curve-power 3.0 + "The strength of the curve (when set to linear). +A value of 1.0 is linear, values between 2 and 8 work well." + :type 'float) (defcustom scroll-on-jump-mode-line-format nil "The `mode-line-format' to use or nil to leave the `mode-line-format' unchanged. @@ -135,10 +145,6 @@ Argument ALSO-MOVE-POINT When non-nil, move the POINT as well." (t (cons 0 0)))) -(defun scroll-on-jump--interpolate-ease (a b factor) - "Blend FACTOR between A and B using ease style curvature." - (+ a (* (- b a) (- (* 3.0 factor factor) (* 2.0 factor factor factor))))) - (defsubst scroll-on-jump--evil-visual-mode-workaround () "Workaround for `evil-mode' line-mode." ;; Without this, the line mode point jumps back to the origin, @@ -155,8 +161,57 @@ Argument ALSO-MOVE-POINT When non-nil, move the POINT as well." ;; --------------------------------------------------------------------------- -;; Internal Logic +;; Internal Interpolation Functions + +(defsubst scroll-on-jump--interp-linear-impl (a b factor) + "Internal macro for to blend A, B by FACTOR." + (+ a (* (- b a) factor))) +(defun scroll-on-jump--interp-linear (a b factor) + "Blend FACTOR between A and B using linear curvature." + (scroll-on-jump--interp-linear-impl a b factor)) + +(defun scroll-on-jump--interp-ease-in (a b factor) + "Blend FACTOR between A and B using ease-in curvature." + (scroll-on-jump--interp-linear-impl a b (expt factor scroll-on-jump-curve-power))) + +(defun scroll-on-jump--interp-ease-out (a b factor) + "Blend FACTOR between A and B using ease-in curvature." + (scroll-on-jump--interp-linear-impl + a b (- 1.0 (expt (- 1.0 factor) scroll-on-jump-curve-power)))) + +(defun scroll-on-jump--interp-ease-in-out (a b factor) + "Blend FACTOR between A and B using ease-in-out curvature." + (cond + ((< factor 0.5) + (let ((f (* (expt (* factor 2.0) scroll-on-jump-curve-power) 0.5))) + (scroll-on-jump--interp-linear-impl a b f))) + (t + (let ((f (- 1.0 (* (expt (* (- 1.0 factor) 2.0) scroll-on-jump-curve-power) 0.5)))) + (scroll-on-jump--interp-linear-impl a b f))))) + +(defun scroll-on-jump--interp-fn-get (curve) + "Return the interpolation function associated with CURVE." + (cond + ((<= scroll-on-jump-curve-power 1.0) + ;; A curve of 1.0 is linear by definition, + ;; also catches users entering in bad values (negative numbers for e.g.) + ;; that will only cause problems. + #'scroll-on-jump--interp-linear) + (t + (pcase curve + ('linear #'scroll-on-jump--interp-linear) + ('smooth #'scroll-on-jump--interp-ease-in-out) + ('smooth-in #'scroll-on-jump--interp-ease-in) + ('smooth-out #'scroll-on-jump--interp-ease-out) + (_ + (message "Unknown curve (%S), using linear" curve) + ;; Fall back to linear (as good an option as any). + #'scroll-on-jump--interp-linear))))) + + +;; --------------------------------------------------------------------------- +;; Internal Logic (defun scroll-on-jump--immediate-scroll (window lines-scroll _dir) "Non animated scroll for WINDOW to move LINES-SCROLL." @@ -171,7 +226,7 @@ Moving the point when ALSO-MOVE-POINT is set." (time-limit (* scroll-on-jump-duration (min 1.0 (/ (float (abs lines-scroll)) (float (window-body-height window)))))) - (use-curve scroll-on-jump-use-curve)) + (interp-fn (scroll-on-jump--interp-fn-get scroll-on-jump-curve))) ;; Animated scrolling (early exit on input to avoid annoying lag). (cond @@ -188,13 +243,7 @@ Moving the point when ALSO-MOVE-POINT is set." (step (let* ((time-elapsed (float-time (time-subtract (current-time) time-init))) (factor (min 1.0 (/ time-elapsed time-limit))) - (lines-target - (floor - (cond - (use-curve - (scroll-on-jump--interpolate-ease 0.0 lines-scroll-abs factor)) - (t - (* lines-scroll-abs factor))))) + (lines-target (floor (funcall interp-fn 0.0 lines-scroll-abs factor))) (lines-remainder (- lines-target lines-done-abs))) ;; Step result, we must move at least one line. (* dir (max 1 lines-remainder))))) @@ -242,7 +291,7 @@ Argument ALSO-MOVE-POINT moves the point while scrolling." (time-limit (* scroll-on-jump-duration (min 1.0 (/ (float (abs lines-scroll)) (float (window-body-height window)))))) - (use-curve scroll-on-jump-use-curve) + (interp-fn (scroll-on-jump--interp-fn-get scroll-on-jump-curve)) (char-height (frame-char-height (window-frame window)))) ;; Animated scrolling (early exit on input to avoid annoying lag). @@ -270,13 +319,7 @@ Argument ALSO-MOVE-POINT moves the point while scrolling." (step (let* ((time-elapsed (float-time (time-subtract (current-time) time-init))) (factor (min 1.0 (/ time-elapsed time-limit))) - (px-target - (floor - (cond - (use-curve - (scroll-on-jump--interpolate-ease 0.0 px-scroll-abs factor)) - (t - (* px-scroll-abs factor))))) + (px-target (floor (funcall interp-fn 0.0 px-scroll-abs factor))) (px-remainder (- px-target px-done-abs))) (* dir px-remainder))))