Allow desaturated mode-line icons.

This commit is contained in:
Matthew Fidler 2016-03-31 12:38:09 -05:00
parent 34dc1e8851
commit 9403061cbf
3 changed files with 132 additions and 18 deletions

View file

@ -40,6 +40,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- This can be customized by the variable =mode-icons-change-mode-name=. - This can be customized by the variable =mode-icons-change-mode-name=.
- This should be modified for packages like =powerline= and - This should be modified for packages like =powerline= and
=smart-mode-line=. =smart-mode-line=.
- Allow desaturating and matching the mode-line face colors for xpm
images.
### Removed ### Removed

View file

@ -42,6 +42,25 @@ This may not work with enhanced mode-lines like ~poweline~ or
~smart-mode-line~, since they typically look at the ~mode-name~ ~smart-mode-line~, since they typically look at the ~mode-name~
variable. variable.
Additionally, if the image icon was an ~xpm~ icon, then you can have
it changed to match your mode-line face. In the example below, the
inactive mode-line shows the emacs and yasnippet icon changed to match
the inactive mode-line:
[[http://i.imgur.com/QOM9wYM.png]]
This is enabled by default, and can be disabled by:
#+BEGIN_SRC emacs-lisp
(setq mode-icons-desaturate-inactive nil)
#+END_SRC
You can also change the icon to match the active mode line (disabled by default):
#+BEGIN_SRC emacs-lisp
(setq mode-icons-desaturate-active t)
#+END_SRC
* Requirements * Requirements
As of version 0.3.0 you can also use icons from some icon fonts, As of version 0.3.0 you can also use icons from some icon fonts,

View file

@ -274,11 +274,21 @@ without the extension. And the third being the type of icon."
(const :tag "Black and White xpm that changes color to match the mode-line face" xpm-bw)))) (const :tag "Black and White xpm that changes color to match the mode-line face" xpm-bw))))
:group 'mode-icons) :group 'mode-icons)
(defvar mode-icons-get-xpm-string (make-hash-table :test 'equal))
(defun mode-icons-get-xpm-string (icon-path)
"Get XPM file contents for ICON-PATH.
If ICON-PATH is a string, return that."
(or (and (file-exists-p icon-path)
(or (gethash icon-path mode-icons-get-xpm-string)
(puthash icon-path (with-temp-buffer (insert-file-contents icon-path) (buffer-string))
mode-icons-get-xpm-string)))
(and (stringp icon-path) icon-path)))
(defun mode-icons-get-icon-display-xpm-replace (icon-path rep-alist &optional name) (defun mode-icons-get-icon-display-xpm-replace (icon-path rep-alist &optional name)
"Get xpm image from ICON-PATH and reaplce REP-ALIST in file. "Get xpm image from ICON-PATH and reaplce REP-ALIST in file.
When NAME is non-nil, also replace the internal xpm image name." When NAME is non-nil, also replace the internal xpm image name."
(let ((case-fold-search t) (let ((case-fold-search t)
(img (with-temp-buffer (insert-file-contents icon-path) (buffer-string)))) (img (mode-icons-get-xpm-string icon-path)))
(dolist (c rep-alist) (dolist (c rep-alist)
(setq img (replace-regexp-in-string (regexp-quote (car c)) (cdr c) img t t))) (setq img (replace-regexp-in-string (regexp-quote (car c)) (cdr c) img t t)))
(when name (when name
@ -299,7 +309,8 @@ If FACTOR is unspecified, use 0.5"
(defun mode-icons-interpolate-from-scale (foreground background) (defun mode-icons-interpolate-from-scale (foreground background)
"Interpolate black to FOREGROUND and white to BACKGROUND. "Interpolate black to FOREGROUND and white to BACKGROUND.
Grayscales are in between." Grayscales are in between.
Assumes that FOREGROUND and BACKGROUND are (r g b) lists."
(let ((black '(0.0 0.0 0.0)) (let ((black '(0.0 0.0 0.0))
(white '(1.0 1.0 1.0)) (white '(1.0 1.0 1.0))
lst tmp lst tmp
@ -329,6 +340,77 @@ Grayscale colors are aslo changed by `mode-icons-interpolate-from-scale'."
(or (gethash sym mode-icons-get-icon-display-xpm-bw-face) (or (gethash sym mode-icons-get-icon-display-xpm-bw-face)
(puthash sym (mode-icons-get-icon-display-xpm-replace icon-path lst name) mode-icons-get-icon-display-xpm-bw-face)))) (puthash sym (mode-icons-get-icon-display-xpm-replace icon-path lst name) mode-icons-get-icon-display-xpm-bw-face))))
(defun mode-icons-get-xpm-icon-colors (icon-path)
"Get a list of rgb colors based on ICON-PATH xpm icon.
ICON-PATH can be a XPM string or a XPM file."
(let (colors)
(with-temp-buffer
(insert (mode-icons-get-xpm-string icon-path))
(goto-char (point-min))
(while (re-search-forward "#[0-9A-Fa-f]\\{6\\}" nil t)
(push (color-name-to-rgb (match-string 0)) colors)))
colors))
(defun mode-icons-desaturate-colors (colors &optional foreground background)
"Desaturate COLORS.
If COLORS is an icon-path of an xpm file, use the colors from
that file.
When FOREGROUND and BACKGROUND are both non-nil, use
`mode-icons-interpolate-from-scale' to change the grayscale to
match the foreground (black) and background (white) colors.
Assume that COLORS is a list of (r g b) values.
Returns a replacement list for `mode-icons-get-icon-display-xpm-replace'"
(if (and colors (stringp colors))
(mode-icons-desaturate-colors (mode-icons-get-xpm-icon-colors colors) foreground background)
(let (color-list
val tmp
(trans-alist (and foreground background (mode-icons-interpolate-from-scale foreground background))))
(dolist (color colors)
(setq val (+ (* 0.3 (nth 0 color)) (* 0.59 (nth 1 color)) (* 0.11 (nth 2 color)))
val (color-rgb-to-hex val val val))
(when (and trans-alist (setq tmp (assoc val trans-alist)))
(setq val (cdr tmp)))
(push (cons (color-rgb-to-hex (nth 0 color) (nth 1 color) (nth 2 color)) val) color-list))
color-list)))
(defun mode-icons-desaturate-xpm (icon-path &optional face)
"Desaturate the xpm at ICON-PATH.
When FACE is non-nil, match the foreground and background colors
in FACE instead of making the image black and white."
(let* ((background (color-name-to-rgb (face-background (or face 'mode-line))))
(foreground (color-name-to-rgb (face-foreground (or face 'mode-line))))
(lst (mode-icons-desaturate-colors icon-path foreground background))
(name (concat "mode_icons_desaturate_"
(or (and background foreground
(substring (mode-icons-interpolate background foreground 0.0) 1))
"black") "_"
(or (and background foreground
(substring (mode-icons-interpolate background foreground 1.0) 1))
"white") "_"
(file-name-sans-extension (file-name-nondirectory icon-path))))
(sym (intern name)))
(or (gethash sym mode-icons-get-icon-display-xpm-bw-face)
(puthash sym (mode-icons-get-icon-display-xpm-replace icon-path lst name) mode-icons-get-icon-display-xpm-bw-face))))
(defcustom mode-icons-desaturate-inactive t
"Should the inactive mode-line be desaturated.
And changed to match the icon colors?
This only works with xpm files."
:type 'boolean
:group 'mode-icons)
(defcustom mode-icons-desaturate-active nil
"Should the active mode-line be desaturated.
And changed to match the icon colors?
This only works with xpm files."
:type 'boolean
:group 'mode-icons)
(defvar mode-icons-get-icon-display (make-hash-table :test 'equal) (defvar mode-icons-get-icon-display (make-hash-table :test 'equal)
"Hash table of `mode-icons-get-icon-display'.") "Hash table of `mode-icons-get-icon-display'.")
@ -341,20 +423,29 @@ the icon.
FACE should be the face for rendering black and white xpm icons FACE should be the face for rendering black and white xpm icons
specified by type 'xpm-bw." specified by type 'xpm-bw."
(let ((face (or face (let* ((active (mode-icons--selected-window-active))
(and (mode-icons--selected-window-active) (face (or face (and active 'mode-line) 'mode-line-inactive))
'mode-line) (key (list icon type face active
'mode-line-inactive))) mode-icons-desaturate-inactive mode-icons-desaturate-active
(or (gethash (list icon type face custom-enabled-themes) mode-icons-get-icon-display) custom-enabled-themes)))
(puthash (list icon type face custom-enabled-themes) (or (gethash key mode-icons-get-icon-display)
(puthash key
(let ((icon-path (mode-icons-get-icon-file (let ((icon-path (mode-icons-get-icon-file
(concat icon "." (or (and (eq type 'xpm-bw) "xpm") (concat icon "." (or (and (eq type 'xpm-bw) "xpm")
(symbol-name type)))))) (symbol-name type))))))
(if (eq type 'xpm-bw) (cond
((eq type 'xpm-bw)
(create-image (mode-icons-get-icon-display-xpm-bw-face icon-path face) (create-image (mode-icons-get-icon-display-xpm-bw-face icon-path face)
'xpm t :ascent 'center 'xpm t :ascent 'center
:face face) :face face))
`(image :type ,(or (and (eq type 'jpg) 'jpeg) type) :file ,icon-path :ascent center :face ',face))) ((and (eq type 'xpm)
(or (and active mode-icons-desaturate-active)
(and (not active) mode-icons-desaturate-inactive)))
(create-image (mode-icons-desaturate-xpm icon-path face)
'xpm t :ascent 'center
:face face))
(t
`(image :type ,(or (and (eq type 'jpg) 'jpeg) type) :file ,icon-path :ascent center :face ',face))))
mode-icons-get-icon-display)))) mode-icons-get-icon-display))))
(defcustom mode-icons-minor-mode-base-text-properties (defcustom mode-icons-minor-mode-base-text-properties
@ -602,10 +693,12 @@ FACE represents the face used when the icon is a xpm-bw image."
(unless mode-icons-cached-mode-name (unless mode-icons-cached-mode-name
(set (make-local-variable 'mode-icons-cached-mode-name) (set (make-local-variable 'mode-icons-cached-mode-name)
mode-name) mode-name)
(let ((mode-icons-desaturate-inactive mode-icons-desaturate-active))
(set (make-local-variable 'mode-icons-mode-name-active) (set (make-local-variable 'mode-icons-mode-name-active)
(mode-icons-get-mode-icon mode 'mode-line)) (mode-icons-get-mode-icon mode 'mode-line)))
(let ((mode-icons-desaturate-active mode-icons-desaturate-inactive))
(set (make-local-variable 'mode-icons-mode-name-inactive) (set (make-local-variable 'mode-icons-mode-name-inactive)
(mode-icons-get-mode-icon mode 'mode-line-inactive)) (mode-icons-get-mode-icon mode 'mode-line-inactive)))
(setq mode-name (mode-icons-get-mode-icon mode)))) (setq mode-name (mode-icons-get-mode-icon mode))))
(defun mode-icons-major-mode-icons-undo () (defun mode-icons-major-mode-icons-undo ()
@ -694,10 +787,10 @@ When DONT-UPDATE is non-nil, don't call `force-mode-line-update'"
;; focus-in-hook was introduced in emacs v24.4. ;; focus-in-hook was introduced in emacs v24.4.
;; Gets evaluated in the last frame's environment. ;; Gets evaluated in the last frame's environment.
(add-hook 'focus-in-hook 'mode-icons--set-selected-window) ;; (add-hook 'focus-in-hook 'mode-icons--set-selected-window)
;; focus-out-hook was introduced in emacs v24.4. ;; focus-out-hook was introduced in emacs v24.4.
(add-hook 'focus-out-hook 'mode-icons--unset-selected-window) ;; (add-hook 'focus-out-hook 'mode-icons--unset-selected-window)
;; Executes after the window manager requests that the user's events ;; Executes after the window manager requests that the user's events
;; be directed to a different frame. ;; be directed to a different frame.
@ -718,7 +811,7 @@ When DONT-UPDATE is non-nil, don't call `force-mode-line-update'"
"Recolor MODE image based on if the window is ACTIVE." "Recolor MODE image based on if the window is ACTIVE."
(let ((icon-spec (get-text-property 0 'mode-icons-p mode))) (let ((icon-spec (get-text-property 0 'mode-icons-p mode)))
(cond (cond
((and icon-spec (eq (nth 2 icon-spec) 'xpm-bw)) ((and icon-spec (memq (nth 2 icon-spec) '(xpm xpm-bw)))
(propertize mode 'display (mode-icons-get-icon-display (nth 1 icon-spec) (nth 2 icon-spec) (propertize mode 'display (mode-icons-get-icon-display (nth 1 icon-spec) (nth 2 icon-spec)
(or (and active 'mode-line) (or (and active 'mode-line)
'mode-line-inactive)) 'mode-line-inactive))