unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Juri Linkov <juri@linkov.net>
To: Lars Ingebrigtsen <larsi@gnus.org>
Cc: Stefan Kangas <stefan@marxist.se>, 38187@debbugs.gnu.org
Subject: bug#38187: 27.0.50; No mouse-wheel scaling on images
Date: Thu, 21 Nov 2019 01:12:17 +0200	[thread overview]
Message-ID: <87h82ykur6.fsf@mail.linkov.net> (raw)
In-Reply-To: <87zhgsnv7x.fsf@gnus.org> (Lars Ingebrigtsen's message of "Tue, 19 Nov 2019 09:09:22 +0100")

[-- Attachment #1: Type: text/plain, Size: 763 bytes --]

>> I tested this patch, and it works well:
>
> Great!  And I agree with Eli's comment -- a separate wrapper command
> that just takes an event would be a clearer interface.

I noticed that using the mouse-wheel on images is not responsive enough.
It takes too much time when every step of the mouse scrolling wheel
needs to scale the image separately for every consecutive rescaling.

So I experimented with debouncing - a new macro 'debounce' swallows
all intermediate calls in quick succession to 'image--change-size',
and executes only the last call in sequence.

But actually it requires another better macro 'debounce-reduce'
that accumulates the state from all calls by multiplying all
intermediate scaling factors, and using the result on the final call:


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: debounce-reduce.patch --]
[-- Type: text/x-diff, Size: 4245 bytes --]

diff --git a/lisp/emacs-lisp/timer.el b/lisp/emacs-lisp/timer.el
index 561cc70078..48301fd4fd 100644
--- a/lisp/emacs-lisp/timer.el
+++ b/lisp/emacs-lisp/timer.el
@@ -488,6 +488,48 @@ y-or-n-p-with-timeout
 If the user does not answer after SECONDS seconds, return DEFAULT-VALUE."
   (with-timeout (seconds default-value)
     (y-or-n-p prompt)))
+
+(defmacro debounce (secs function)
+  "Call FUNCTION after SECS seconds have elapsed.
+Postpone FUNCTION call until after SECS seconds have elapsed since the
+last time it was invoked.  On consecutive calls within the interval of
+SECS seconds, cancel all previous calls and in quick succession execute
+only the last call."
+  (declare (indent 1) (debug t))
+  (let ((timer-sym (make-symbol "timer")))
+    `(let (,timer-sym)
+       (lambda (&rest args)
+         (when (timerp ,timer-sym)
+           (cancel-timer ,timer-sym))
+         (setq ,timer-sym
+               (run-with-timer
+                ,secs nil (lambda ()
+                            (apply ,function args))))))))
+
+(defmacro debounce-reduce (secs state-function function)
+  "Call FUNCTION after SECS seconds have elapsed.
+Postpone FUNCTION call until after SECS seconds have elapsed since the
+last time it was invoked.  On consecutive calls within the interval of
+SECS seconds, cancel all previous calls and in quick succession execute
+only the last call.
+STATE-FUNCTION can be used to calculate the state on consecutive calls,
+and execute the last call with the collected state."
+  (declare (indent 1) (debug t))
+  (let ((timer-sym (make-symbol "timer"))
+        (state-sym (make-symbol "state")))
+    `(let (,timer-sym ,state-sym)
+       (lambda (&rest args)
+         (setq ,state-sym (apply ,state-function ,state-sym args))
+         (when (timerp ,timer-sym)
+           (cancel-timer ,timer-sym))
+         (setq ,timer-sym
+               (run-with-timer
+                ,secs nil (lambda ()
+                            (apply ,function (if (listp ,state-sym)
+                                                 ,state-sym
+                                               (list ,state-sym)))
+                            (setq ,state-sym nil))))))))
+
 \f
 (defconst timer-duration-words
   (list (cons "microsec" 0.000001)
diff --git a/lisp/image.el b/lisp/image.el
index e0965c1091..d57ae3a720 100644
--- a/lisp/image.el
+++ b/lisp/image.el
@@ -1016,18 +1016,20 @@ image-increase-size
 If N is 3, then the image size will be increased by 30%.  The
 default is 20%."
   (interactive "P")
-  (image--change-size (if n
-                          (1+ (/ (prefix-numeric-value n) 10.0))
-                        1.2)))
+  (funcall image--change-size
+           (if n
+               (1+ (/ (prefix-numeric-value n) 10.0))
+             1.2)))
 
 (defun image-decrease-size (&optional n)
   "Decrease the image size by a factor of N.
 If N is 3, then the image size will be decreased by 30%.  The
 default is 20%."
   (interactive "P")
-  (image--change-size (if n
-                          (- 1 (/ (prefix-numeric-value n) 10.0))
-                        0.8)))
+  (funcall image--change-size
+           (if n
+               (- 1 (/ (prefix-numeric-value n) 10.0))
+             0.8)))
 
 (defun image-mouse-increase-size (&optional event)
   "Increase the image size using the mouse."
@@ -1062,12 +1064,16 @@ image--get-imagemagick-and-warn
       (plist-put (cdr image) :type 'imagemagick))
     image))
 
-(defun image--change-size (factor)
-  (let* ((image (image--get-imagemagick-and-warn))
-         (new-image (image--image-without-parameters image))
-         (scale (image--current-scaling image new-image)))
-    (setcdr image (cdr new-image))
-    (plist-put (cdr image) :scale (* scale factor))))
+(defvar image--change-size
+  (debounce-reduce 0.3
+    (lambda (state factor)
+      (* (or state 1) factor))
+    (lambda (factor)
+      (let* ((image (image--get-imagemagick-and-warn))
+             (new-image (image--image-without-parameters image))
+             (scale (image--current-scaling image new-image)))
+        (setcdr image (cdr new-image))
+        (plist-put (cdr image) :scale (* scale factor))))))
 
 (defun image--image-without-parameters (image)
   (cons (pop image)

  reply	other threads:[~2019-11-20 23:12 UTC|newest]

Thread overview: 46+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-11-12 20:38 bug#38187: 27.0.50; No mouse-wheel scaling on images Juri Linkov
2019-11-14 12:48 ` Eli Zaretskii
2019-11-17 10:04   ` Lars Ingebrigtsen
2019-11-17 16:05     ` Eli Zaretskii
2019-11-17 16:07       ` Lars Ingebrigtsen
2019-11-17 21:20         ` Stefan Kangas
2019-11-17 22:42           ` Juri Linkov
2019-11-18  9:10             ` Lars Ingebrigtsen
2019-11-18 21:37               ` Juri Linkov
2019-11-19  3:31                 ` Eli Zaretskii
2019-11-20 23:00                   ` Juri Linkov
2019-11-21  3:35                     ` Eli Zaretskii
2019-11-21 21:18                     ` Alan Third
2019-11-21 22:51                       ` Juri Linkov
2019-11-22  7:47                         ` Eli Zaretskii
2019-11-21 21:26                     ` Lars Ingebrigtsen
2019-11-21 22:57                       ` Juri Linkov
2019-11-21 23:10                         ` Lars Ingebrigtsen
2019-11-22  7:58                           ` Eli Zaretskii
2019-11-22  7:51                         ` Eli Zaretskii
2019-11-22  7:31                       ` Eli Zaretskii
2019-11-22 12:41                         ` Lars Ingebrigtsen
2019-11-22  9:50                       ` Alan Third
2019-11-22 10:04                         ` Eli Zaretskii
2019-11-22 10:33                           ` Alan Third
2019-11-22 13:26                             ` Eli Zaretskii
2019-11-19  8:09                 ` Lars Ingebrigtsen
2019-11-20 23:12                   ` Juri Linkov [this message]
2019-11-21 12:11                     ` Lars Ingebrigtsen
2019-11-21 14:25                       ` Eli Zaretskii
2019-11-21 22:45                         ` Juri Linkov
2019-11-23 22:23                       ` Juri Linkov
2019-11-27 11:58                         ` Lars Ingebrigtsen
2019-11-17 23:01           ` Drew Adams
2019-11-18  9:08           ` Lars Ingebrigtsen
2019-11-19 14:49             ` Stefan Kangas
2019-11-19 15:27               ` Drew Adams
2019-11-19 16:07                 ` Stefan Kangas
2019-11-19 16:12                   ` Stefan Kangas
2019-11-19 16:27                   ` Drew Adams
2019-11-21  0:01                     ` Stefan Kangas
2019-11-21  0:41                       ` Drew Adams
2019-11-19 16:31                   ` Eli Zaretskii
2019-11-19 16:54                     ` Stefan Kangas
2019-11-19 22:50                       ` Juri Linkov
2019-11-19 17:27                   ` Eli Zaretskii

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87h82ykur6.fsf@mail.linkov.net \
    --to=juri@linkov.net \
    --cc=38187@debbugs.gnu.org \
    --cc=larsi@gnus.org \
    --cc=stefan@marxist.se \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).