image-mode-winprops-alist))))
(let ((winprops (assq window image-mode-winprops-alist)))
;; For new windows, set defaults from the latest.
- (unless winprops
+ (if winprops
+ ;; Move window to front.
+ (setq image-mode-winprops-alist
+ (cons winprops (delq winprops image-mode-winprops-alist)))
(setq winprops (cons window
(copy-alist (cdar image-mode-winprops-alist))))
+ ;; Add winprops before running the hook, to avoid inf-loops if the hook
+ ;; triggers window-configuration-change-hook.
+ (setq image-mode-winprops-alist
+ (cons winprops image-mode-winprops-alist))
(run-hook-with-args 'image-mode-new-window-functions winprops))
- ;; Move window to front.
- (setq image-mode-winprops-alist
- (cons winprops (delq winprops image-mode-winprops-alist)))
winprops))
(defun image-mode-window-get (prop &optional winprops)
(defun image-mode-reapply-winprops ()
;; When set-window-buffer, set hscroll and vscroll to what they were
;; last time the image was displayed in this window.
- (when (and (image-get-display-property)
- (listp image-mode-winprops-alist))
+ (when (listp image-mode-winprops-alist)
+ ;; Beware: this call to image-mode-winprops can't be optimized away,
+ ;; because it not only gets the winprops data but sets it up if needed
+ ;; (e.g. it's used by doc-view to display the image in a new window).
(let* ((winprops (image-mode-winprops nil t))
(hscroll (image-mode-window-get 'hscroll winprops))
(vscroll (image-mode-window-get 'vscroll winprops)))
- (if hscroll (set-window-hscroll (selected-window) hscroll))
- (if vscroll (set-window-vscroll (selected-window) vscroll)))))
+ (when (image-get-display-property) ;Only do it if we display an image!
+ (if hscroll (set-window-hscroll (selected-window) hscroll))
+ (if vscroll (set-window-vscroll (selected-window) vscroll))))))
(defun image-mode-setup-winprops ()
;; Record current scroll settings.
;;; Image Mode setup
-(defvar image-type nil
+(defvar-local image-type nil
"The image type for the current Image mode buffer.")
-(make-variable-buffer-local 'image-type)
+
+(defvar-local image-multi-frame nil
+ "Non-nil if image for the current Image mode buffer has multiple frames.")
(defvar image-mode-previous-major-mode nil
"Internal variable to keep the previous non-image major mode.")
(set-keymap-parent map special-mode-map)
(define-key map "\C-c\C-c" 'image-toggle-display)
(define-key map (kbd "SPC") 'image-scroll-up)
+ (define-key map (kbd "S-SPC") 'image-scroll-down)
(define-key map (kbd "DEL") 'image-scroll-down)
(define-key map (kbd "RET") 'image-toggle-animation)
+ (define-key map "F" 'image-goto-frame)
+ (define-key map "f" 'image-next-frame)
+ (define-key map "b" 'image-previous-frame)
(define-key map "n" 'image-next-file)
(define-key map "p" 'image-previous-file)
(define-key map [remap forward-char] 'image-forward-hscroll)
(define-key map [remap move-end-of-line] 'image-eol)
(define-key map [remap beginning-of-buffer] 'image-bob)
(define-key map [remap end-of-buffer] 'image-eob)
+ (easy-menu-define image-mode-menu map "Menu for Image mode."
+ '("Image"
+ ["Show as Text" image-toggle-display :active t
+ :help "Show image as text"]
+ "--"
+ ["Fit Frame to Image" image-mode-fit-frame :active t
+ :help "Resize frame to match image"]
+ ["Fit to Window Height" image-transform-fit-to-height
+ :visible (eq image-type 'imagemagick)
+ :help "Resize image to match the window height"]
+ ["Fit to Window Width" image-transform-fit-to-width
+ :visible (eq image-type 'imagemagick)
+ :help "Resize image to match the window width"]
+ ["Rotate Image..." image-transform-set-rotation
+ :visible (eq image-type 'imagemagick)
+ :help "Rotate the image"]
+ "--"
+ ["Show Thumbnails"
+ (lambda ()
+ (interactive)
+ (image-dired default-directory))
+ :active default-directory
+ :help "Show thumbnails for all images in this directory"]
+ ["Next Image" image-next-file :active buffer-file-name
+ :help "Move to next image in this directory"]
+ ["Previous Image" image-previous-file :active buffer-file-name
+ :help "Move to previous image in this directory"]
+ "--"
+ ["Animate Image" image-toggle-animation :style toggle
+ :selected (let ((image (image-get-display-property)))
+ (and image (image-animate-timer image)))
+ :active image-multi-frame
+ :help "Toggle image animation"]
+ ["Loop Animation"
+ (lambda () (interactive)
+ (setq image-animate-loop (not image-animate-loop))
+ ;; FIXME this is a hacky way to make it affect a currently
+ ;; animating image.
+ (when (let ((image (image-get-display-property)))
+ (and image (image-animate-timer image)))
+ (image-toggle-animation)
+ (image-toggle-animation)))
+ :style toggle :selected image-animate-loop
+ :active image-multi-frame
+ :help "Animate images once, or forever?"]
+ ["Next Frame" image-next-frame :active image-multi-frame
+ :help "Show the next frame of this image"]
+ ["Previous Frame" image-previous-frame :active image-multi-frame
+ :help "Show the previous frame of this image"]
+ ["Goto Frame..." image-goto-frame :active image-multi-frame
+ :help "Show a specific frame of this image"]
+ ))
map)
"Mode keymap for `image-mode'.")
(use-local-map image-mode-map)
;; Use our own bookmarking function for images.
- (set (make-local-variable 'bookmark-make-record-function)
- 'image-bookmark-make-record)
+ (setq-local bookmark-make-record-function
+ #'image-bookmark-make-record)
;; Keep track of [vh]scroll when switching buffers
(image-mode-setup-winprops)
(run-mode-hooks 'image-mode-hook)
(let ((image (image-get-display-property))
(msg1 (substitute-command-keys
- "Type \\[image-toggle-display] to view the image as ")))
+ "Type \\[image-toggle-display] to view the image as "))
+ animated)
(cond
((null image)
(message "%s" (concat msg1 "an image.")))
- ((image-animated-p image)
+ ((setq animated (image-multi-frame-p image))
+ (setq image-multi-frame t
+ mode-line-process
+ `(:eval
+ (concat " "
+ (propertize
+ (format "[%s/%s]"
+ (1+ (image-current-frame ',image))
+ ,(car animated))
+ 'help-echo "Frames
+mouse-1: Next frame
+mouse-3: Previous frame"
+ 'mouse-face 'mode-line-highlight
+ 'local-map
+ '(keymap
+ (mode-line
+ keymap
+ (down-mouse-1 . image-next-frame)
+ (down-mouse-3 . image-previous-frame)))))))
(message "%s"
- (concat msg1 "text, or "
- (substitute-command-keys
- "\\[image-toggle-animation] to animate."))))
+ (concat msg1 "text. This image has multiple frames.")))
+;;; (substitute-command-keys
+;;; "\\[image-toggle-animation] to animate."))))
(t
(message "%s" (concat msg1 "text."))))))
elt))
magic-fallback-mode-alist))))
(normal-mode)
- (set (make-local-variable 'image-mode-previous-major-mode) major-mode)))
+ (setq-local image-mode-previous-major-mode major-mode)))
;; Restore `image-type' after `kill-all-local-variables' in `normal-mode'.
(setq image-type previous-image-type)
;; Enable image minor mode with `C-c C-c'.
;; is written with, e.g., C-x C-w.
(if (coding-system-equal (coding-system-base buffer-file-coding-system)
'no-conversion)
- (set (make-local-variable 'find-file-literally) t))
- ;; Allow navigation of large images
- (set (make-local-variable 'auto-hscroll-mode) nil)
+ (setq-local find-file-literally t))
+ ;; Allow navigation of large images.
+ (setq-local auto-hscroll-mode nil)
(setq image-type type)
(if (eq major-mode 'image-mode)
(setq mode-name (format "Image[%s]" type)))
(cond
((null image)
(error "No image is present"))
- ((null (setq animation (image-animated-p image)))
+ ((null (setq animation (image-multi-frame-p image)))
(message "No image animation."))
(t
(let ((timer (image-animate-timer image)))
(image-animate image index
(if image-animate-loop t)))))))))
+(defun image-goto-frame (n &optional relative)
+ "Show frame N of a multi-frame image.
+Optional argument OFFSET non-nil means interpret N as relative to the
+current frame. Frames are indexed from 1."
+ (interactive
+ (list (or current-prefix-arg
+ (read-number "Show frame number: "))))
+ (let ((image (image-get-display-property)))
+ (cond
+ ((null image)
+ (error "No image is present"))
+ ((null image-multi-frame)
+ (message "No image animation."))
+ (t
+ (image-show-frame image
+ (if relative
+ (+ n (image-current-frame image))
+ (1- n)))))))
+
+(defun image-next-frame (&optional n)
+ "Switch to the next frame of a multi-frame image.
+With optional argument N, switch to the Nth frame after the current one.
+If N is negative, switch to the Nth frame before the current one."
+ (interactive "p")
+ (image-goto-frame n t))
+
+(defun image-previous-frame (&optional n)
+ "Switch to the previous frame of a multi-frame image.
+With optional argument N, switch to the Nth frame before the current one.
+If N is negative, switch to the Nth frame after the current one."
+ (interactive "p")
+ (image-next-frame (- n)))
+
\f
;;; Switching to the next/previous image