tool-bar.el 13.5 KB
Newer Older
1
;;; tool-bar.el --- setting up the tool bar
2
;;
3
;; Copyright (C) 2000, 2001, 2002, 2003, 2004,
Glenn Morris's avatar
Glenn Morris committed
4
;;   2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
5 6 7 8 9 10
;;
;; Author: Dave Love <fx@gnu.org>
;; Keywords: mouse frames

;; This file is part of GNU Emacs.

11
;; GNU Emacs is free software: you can redistribute it and/or modify
12
;; it under the terms of the GNU General Public License as published by
13 14
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
15 16 17 18 19 20 21

;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
22
;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
23 24 25

;;; Commentary:

Richard M. Stallman's avatar
Richard M. Stallman committed
26
;; Provides `tool-bar-mode' to control display of the tool-bar and
27 28 29
;; bindings for the global tool bar with convenience functions
;; `tool-bar-add-item' and `tool-bar-add-item-from-menu'.

Dave Love's avatar
Dave Love committed
30
;; The normal global binding for [tool-bar] (below) uses the value of
Dave Love's avatar
Dave Love committed
31 32 33
;; `tool-bar-map' as the actual keymap to define the tool bar.  Modes
;; may either bind items under the [tool-bar] prefix key of the local
;; map to add to the global bar or may set `tool-bar-map'
Eli Zaretskii's avatar
Eli Zaretskii committed
34
;; buffer-locally to override it.  (Some items are removed from the
Dave Love's avatar
Dave Love committed
35
;; global bar in modes which have `special' as their `mode-class'
Juanma Barranquero's avatar
Juanma Barranquero committed
36
;; property.)
Dave Love's avatar
Dave Love committed
37

38 39
;; Todo: Somehow make tool bars easily customizable by the naive?

40 41
;;; Code:

42 43 44
;; The autoload cookie doesn't work when preloading.
;; Deleting it means invoking this command won't work
;; when you are on a tty.  I hope that won't cause too much trouble -- rms.
45 46
(define-minor-mode tool-bar-mode
  "Toggle use of the tool bar.
Gerd Moellmann's avatar
Gerd Moellmann committed
47
With numeric ARG, display the tool bar if and only if ARG is positive.
48 49 50

See `tool-bar-add-item' and `tool-bar-add-item-from-menu' for
conveniently adding tool bar items."
51
  :init-value nil
52 53 54
  :global t
  :group 'mouse
  :group 'frames
55 56
  (if tool-bar-mode
      (progn
57 58 59 60 61 62
	;; Make one tool-bar-line for any - including non-graphical -
	;; terminal, see Bug#1754.  If this causes problems, we should
	;; handle the problem in `modify-frame-parameters' or do not
	;; call `modify-all-frames-parameters' when toggling the tool
	;; bar off either.
	(modify-all-frames-parameters (list (cons 'tool-bar-lines 1)))
63 64
	(if (= 1 (length (default-value 'tool-bar-map))) ; not yet setup
	    (tool-bar-setup)))
65
    (modify-all-frames-parameters (list (cons 'tool-bar-lines 0)))))
66

67
;;;###autoload
68 69 70 71 72 73 74 75 76 77
;; Used in the Show/Hide menu, to have the toggle reflect the current frame.
(defun toggle-tool-bar-mode-from-frame (&optional arg)
  "Toggle tool bar on or off, based on the status of the current frame.
See `tool-bar-mode' for more information."
  (interactive (list (or current-prefix-arg 'toggle)))
  (if (eq arg 'toggle)
      (tool-bar-mode (if (> (frame-parameter nil 'tool-bar-lines) 0) 0 1))
    (tool-bar-mode arg)))

;;;###autoload
78 79 80 81 82 83 84 85 86 87
;; We want to pretend the toolbar by standard is on, as this will make
;; customize consider disabling the toolbar a customization, and save
;; that.  We could do this for real by setting :init-value above, but
;; that would turn on the toolbar in MS Windows where it is currently
;; useless, and it would overwrite disabling the tool bar from X
;; resources.  If anyone want to implement this in a cleaner way,
;; please do so.
;; -- Per Abrahamsen <abraham@dina.kvl.dk> 2002-02-21.
(put 'tool-bar-mode 'standard-value '(t))

Dave Love's avatar
Dave Love committed
88 89 90 91 92
(defvar tool-bar-map (make-sparse-keymap)
  "Keymap for the tool bar.
Define this locally to override the global tool bar.")

(global-set-key [tool-bar]
93
		`(menu-item ,(purecopy "tool bar") ignore
Stefan Monnier's avatar
Stefan Monnier committed
94 95
			    :filter tool-bar-make-keymap))

96 97
(declare-function image-mask-p "image.c" (spec &optional frame))

98 99
(defconst tool-bar-keymap-cache (make-hash-table :weakness t :test 'equal))

Stefan Monnier's avatar
Stefan Monnier committed
100 101 102 103
(defun tool-bar-make-keymap (&optional ignore)
  "Generate an actual keymap from `tool-bar-map'.
Its main job is to figure out which images to use based on the display's
color capability and based on the available image libraries."
104 105 106 107 108 109
  (let ((key (cons (frame-terminal) tool-bar-map)))
    (or (gethash key tool-bar-keymap-cache)
	(puthash key (tool-bar-make-keymap-1) tool-bar-keymap-cache))))

(defun tool-bar-make-keymap-1 ()
  "Generate an actual keymap from `tool-bar-map', without caching."
Stefan Monnier's avatar
Stefan Monnier committed
110
  (mapcar (lambda (bind)
111
            (let (image-exp plist)
Stefan Monnier's avatar
Stefan Monnier committed
112
              (when (and (eq (car-safe (cdr-safe bind)) 'menu-item)
113 114 115 116 117 118 119 120 121 122 123
			 ;; For the format of menu-items, see node
			 ;; `Extended Menu Items' in the Elisp manual.
			 (setq plist (nthcdr (if (consp (nth 4 bind)) 5 4)
					     bind))
			 (setq image-exp (plist-get plist :image))
			 (consp image-exp)
			 (not (eq (car image-exp) 'image))
			 (fboundp (car image-exp)))
		(if (not (display-images-p))
		    (setq bind nil)
		  (let ((image (eval image-exp)))
124
		    (unless (and image (image-mask-p image))
125 126 127 128 129 130
		      (setq image (append image '(:mask heuristic))))
		    (setq bind (copy-sequence bind)
			  plist (nthcdr (if (consp (nth 4 bind)) 5 4)
					bind))
		    (plist-put plist :image image))))
	      bind))
Stefan Monnier's avatar
Stefan Monnier committed
131 132
	  tool-bar-map))

133
;;;###autoload
Dave Love's avatar
Dave Love committed
134
(defun tool-bar-add-item (icon def key &rest props)
135 136
  "Add an item to the tool bar.
ICON names the image, DEF is the key definition and KEY is a symbol
Dave Love's avatar
Dave Love committed
137 138 139
for the fake function key in the menu keymap.  Remaining arguments
PROPS are additional items to add to the menu item specification.  See
Info node `(elisp)Tool Bar'.  Items are added from left to right.
140

Eli Zaretskii's avatar
Eli Zaretskii committed
141
ICON is the base name of a file containing the image to use.  The
142
function will first try to use low-color/ICON.xpm if `display-color-cells'
Jan Djärv's avatar
Jan Djärv committed
143
is less or equal to 256, then ICON.xpm, then ICON.pbm, and finally
Eli Zaretskii's avatar
Eli Zaretskii committed
144
ICON.xbm, using `find-image'.
Dave Love's avatar
Dave Love committed
145

146 147 148 149 150 151 152 153 154 155 156 157 158
Use this function only to make bindings in the global value of `tool-bar-map'.
To define items in any other map, use `tool-bar-local-item'."
  (apply 'tool-bar-local-item icon def key tool-bar-map props))

;;;###autoload
(defun tool-bar-local-item (icon def key map &rest props)
  "Add an item to the tool bar in map MAP.
ICON names the image, DEF is the key definition and KEY is a symbol
for the fake function key in the menu keymap.  Remaining arguments
PROPS are additional items to add to the menu item specification.  See
Info node `(elisp)Tool Bar'.  Items are added from left to right.

ICON is the base name of a file containing the image to use.  The
Stefan Monnier's avatar
Stefan Monnier committed
159
function will first try to use low-color/ICON.xpm if `display-color-cells'
Jan Djärv's avatar
Jan Djärv committed
160
is less or equal to 256, then ICON.xpm, then ICON.pbm, and finally
161
ICON.xbm, using `find-image'."
162 163 164 165
  (let* ((fg (face-attribute 'tool-bar :foreground))
	 (bg (face-attribute 'tool-bar :background))
	 (colors (nconc (if (eq fg 'unspecified) nil (list :foreground fg))
			(if (eq bg 'unspecified) nil (list :background bg))))
166
	 (xpm-spec (list :type 'xpm :file (concat icon ".xpm")))
Chong Yidong's avatar
Chong Yidong committed
167 168
	 (xpm-lo-spec (list :type 'xpm :file
			    (concat "low-color/" icon ".xpm")))
169 170 171 172
	 (pbm-spec (append (list :type 'pbm :file
                                 (concat icon ".pbm")) colors))
	 (xbm-spec (append (list :type 'xbm :file
                                 (concat icon ".xbm")) colors))
173
	 (image-exp `(find-image
Chong Yidong's avatar
Chong Yidong committed
174 175 176 177 178 179
		      (cond ((not (display-color-p))
			     ',(list pbm-spec xbm-spec xpm-lo-spec xpm-spec))
			    ((< (display-color-cells) 256)
			     ',(list xpm-lo-spec xpm-spec pbm-spec xbm-spec))
			    (t
			     ',(list xpm-spec pbm-spec xbm-spec))))))
Stefan Monnier's avatar
Stefan Monnier committed
180 181
    (define-key-after map (vector key)
      `(menu-item ,(symbol-name key) ,def :image ,image-exp ,@props))))
182

183
;;;###autoload
184
(defun tool-bar-add-item-from-menu (command icon &optional map &rest props)
Nick Roberts's avatar
Nick Roberts committed
185
  "Define tool bar binding for COMMAND in keymap MAP using the given ICON.
186 187 188 189 190 191 192 193 194
This makes a binding for COMMAND in `tool-bar-map', copying its
binding from the menu bar in MAP (which defaults to `global-map'), but
modifies the binding by adding an image specification for ICON.  It
finds ICON just like `tool-bar-add-item'.  PROPS are additional
properties to add to the binding.

MAP must contain appropriate binding for `[menu-bar]' which holds a keymap.

Use this function only to make bindings in the global value of `tool-bar-map'.
Nick Roberts's avatar
Nick Roberts committed
195
To define items in any other map, use `tool-bar-local-item-from-menu'."
196 197
  (apply 'tool-bar-local-item-from-menu command icon
	 (default-value 'tool-bar-map) map props))
198 199 200

;;;###autoload
(defun tool-bar-local-item-from-menu (command icon in-map &optional from-map &rest props)
Nick Roberts's avatar
Nick Roberts committed
201
  "Define local tool bar binding for COMMAND using the given ICON.
202 203 204 205 206 207
This makes a binding for COMMAND in IN-MAP, copying its binding from
the menu bar in FROM-MAP (which defaults to `global-map'), but
modifies the binding by adding an image specification for ICON.  It
finds ICON just like `tool-bar-add-item'.  PROPS are additional
properties to add to the binding.

Nick Roberts's avatar
Nick Roberts committed
208 209
FROM-MAP must contain appropriate binding for `[menu-bar]' which
holds a keymap."
210 211 212
  (unless from-map
    (setq from-map global-map))
  (let* ((menu-bar-map (lookup-key from-map [menu-bar]))
213
	 (keys (where-is-internal command menu-bar-map))
214 215 216 217
	 (fg (face-attribute 'tool-bar :foreground))
	 (bg (face-attribute 'tool-bar :background))
	 (colors (nconc (if (eq fg 'unspecified) nil (list :foreground fg))
			(if (eq bg 'unspecified) nil (list :background bg))))
218
	 (xpm-spec (list :type 'xpm :file (concat icon ".xpm")))
Chong Yidong's avatar
Chong Yidong committed
219 220
	 (xpm-lo-spec (list :type 'xpm :file
			    (concat "low-color/" icon ".xpm")))
221 222 223 224
	 (pbm-spec (append (list :type 'pbm :file
                                 (concat icon ".pbm")) colors))
	 (xbm-spec (append (list :type 'xbm :file
                                 (concat icon ".xbm")) colors))
225
	 (image-exp `(find-image
Chong Yidong's avatar
Chong Yidong committed
226 227 228 229 230 231
		      (cond ((not (display-color-p))
			     ',(list pbm-spec xbm-spec xpm-lo-spec xpm-spec))
			    ((< (display-color-cells) 256)
			     ',(list xpm-lo-spec xpm-spec pbm-spec xbm-spec))
			    (t
			     ',(list xpm-spec pbm-spec xbm-spec)))))
232
	 submap key)
Stefan Monnier's avatar
Stefan Monnier committed
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
    ;; We'll pick up the last valid entry in the list of keys if
    ;; there's more than one.
    (dolist (k keys)
      ;; We're looking for a binding of the command in a submap of
      ;; the menu bar map, so the key sequence must be two or more
      ;; long.
      (if (and (vectorp k)
               (> (length k) 1))
          (let ((m (lookup-key menu-bar-map (substring k 0 -1)))
                ;; Last element in the bound key sequence:
                (kk (aref k (1- (length k)))))
            (if (and (keymapp m)
                     (symbolp kk))
                (setq submap m
                      key kk)))))
    (when (and (symbolp submap) (boundp submap))
      (setq submap (eval submap)))
    (let ((defn (assq key (cdr submap))))
      (if (eq (cadr defn) 'menu-item)
          (define-key-after in-map (vector key)
            (append (cdr defn) (list :image image-exp) props))
        (setq defn (cdr defn))
        (define-key-after in-map (vector key)
          (let ((rest (cdr defn)))
            ;; If the rest of the definition starts
            ;; with a list of menu cache info, get rid of that.
            (if (and (consp rest) (consp (car rest)))
                (setq rest (cdr rest)))
            (append `(menu-item ,(car defn) ,rest)
                    (list :image image-exp) props)))))))
263 264 265

;;; Set up some global items.  Additions/deletions up for grabs.

266 267 268 269
(defun tool-bar-setup ()
  ;; People say it's bad to have EXIT on the tool bar, since users
  ;; might inadvertently click that button.
  ;;(tool-bar-add-item-from-menu 'save-buffers-kill-emacs "exit")
270
  (tool-bar-add-item-from-menu 'find-file "new" nil :label "New File")
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
  (tool-bar-add-item-from-menu 'menu-find-file-existing "open")
  (tool-bar-add-item-from-menu 'dired "diropen")
  (tool-bar-add-item-from-menu 'kill-this-buffer "close")
  (tool-bar-add-item-from-menu 'save-buffer "save" nil
			       :visible '(or buffer-file-name
					     (not (eq 'special
						      (get major-mode
							   'mode-class)))))
  (tool-bar-add-item-from-menu 'write-file "saveas" nil
			       :visible '(or buffer-file-name
					     (not (eq 'special
						      (get major-mode
							   'mode-class)))))
  (tool-bar-add-item-from-menu 'undo "undo" nil
			       :visible '(not (eq 'special (get major-mode
								'mode-class))))
  (tool-bar-add-item-from-menu (lookup-key menu-bar-edit-menu [cut])
			       "cut" nil
			       :visible '(not (eq 'special (get major-mode
								'mode-class))))
  (tool-bar-add-item-from-menu (lookup-key menu-bar-edit-menu [copy])
			       "copy")
  (tool-bar-add-item-from-menu (lookup-key menu-bar-edit-menu [paste])
			       "paste" nil
			       :visible '(not (eq 'special (get major-mode
								'mode-class))))
297 298
  (tool-bar-add-item-from-menu 'nonincremental-search-forward "search"
			       nil :label "Search")
299 300 301 302 303 304
  ;;(tool-bar-add-item-from-menu 'ispell-buffer "spell")

  ;; There's no icon appropriate for News and we need a command rather
  ;; than a lambda for Read Mail.
  ;;(tool-bar-add-item-from-menu 'compose-mail "mail/compose")

305
  (tool-bar-add-item-from-menu 'print-buffer "print" nil :label "Print")
306 307 308 309 310 311 312 313 314 315 316 317 318 319

  ;; tool-bar-add-item-from-menu itself operates on
  ;; (default-value 'tool-bar-map), but when we don't use that function,
  ;; we must explicitly operate on the default value.

  (let ((tool-bar-map (default-value 'tool-bar-map)))
    (tool-bar-add-item "preferences" 'customize 'customize
		       :help "Edit preferences (customize)")

    (tool-bar-add-item "help" (lambda ()
				(interactive)
				(popup-menu menu-bar-help-menu))
		       'help
		       :help "Pop up the Help menu")))
320 321


Karoly Lorentey's avatar
Karoly Lorentey committed
322
(provide 'tool-bar)
323
;; arch-tag: 15f30f0a-d0d7-4d50-bbb7-f48fd0c8582f
324
;;; tool-bar.el ends here