diff options
| author | Richard M. Stallman | 1998-01-27 20:43:57 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1998-01-27 20:43:57 +0000 |
| commit | 024bda024c737b337ed924db6d1bb6c7af7a4217 (patch) | |
| tree | 5f6dc2c8f8535d61522a9a18be771d59c82032c0 | |
| parent | 8aa3a244a3eb61c7eddccf41a6c963530361276a (diff) | |
| download | emacs-024bda024c737b337ed924db6d1bb6c7af7a4217.tar.gz emacs-024bda024c737b337ed924db6d1bb6c7af7a4217.zip | |
easy-menu-define): Use ` and , read-macros
instead of (` and (,. Implement :filter. Doc fix.
(easy-menu-do-define): Call `easy-menu-create-menu' instead of
`easy-menu-create-keymaps'.
(easy-menu-create-keymaps): Replaced by `easy-menu-create-menu'.
(easy-menu-create-menu): New public function. Replaces
`easy-menu-create-keymaps', but with large changes.
(easy-menu-button-prefix): New constant.
(easy-menu-do-add-item, easy-menu-make-symbol): New functions.
(easy-menu-update-button): Doc fix.
(easy-menu-change): New optional argument BEFORE.
Now just a call to `easy-menu-add-item'.
(easy-menu-add-item, easy-menu-item-present-p)
(easy-menu-remove-item): New public functions.
(easy-menu-get-map, easy-menu-is-button-p, easy-menu-have-button-p)
(easy-menu-real-binding, easy-menu-change-prefix, easy-menu-filter):
New functions.
| -rw-r--r-- | lisp/emacs-lisp/easymenu.el | 410 |
1 files changed, 302 insertions, 108 deletions
diff --git a/lisp/emacs-lisp/easymenu.el b/lisp/emacs-lisp/easymenu.el index 4988d0e1d14..5abda172c1e 100644 --- a/lisp/emacs-lisp/easymenu.el +++ b/lisp/emacs-lisp/easymenu.el | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | ;;; easymenu.el --- support the easymenu interface for defining a menu. | 1 | ;;; easymenu.el --- support the easymenu interface for defining a menu. |
| 2 | 2 | ||
| 3 | ;; Copyright (C) 1994, 1996 Free Software Foundation, Inc. | 3 | ;; Copyright (C) 1994, 1996, 1998 Free Software Foundation, Inc. |
| 4 | 4 | ||
| 5 | ;; Keywords: emulations | 5 | ;; Keywords: emulations |
| 6 | ;; Author: rms | 6 | ;; Author: rms |
| @@ -37,6 +37,11 @@ The menu keymap is stored in symbol SYMBOL, both as its value | |||
| 37 | and as its function definition. DOC is used as the doc string for SYMBOL. | 37 | and as its function definition. DOC is used as the doc string for SYMBOL. |
| 38 | 38 | ||
| 39 | The first element of MENU must be a string. It is the menu bar item name. | 39 | The first element of MENU must be a string. It is the menu bar item name. |
| 40 | It may be followed by the keyword argument pair | ||
| 41 | :filter FUNCTION | ||
| 42 | FUNCTION is a function with one argument, the menu. It returns the actual | ||
| 43 | menu displayed. | ||
| 44 | |||
| 40 | The rest of the elements are menu items. | 45 | The rest of the elements are menu items. |
| 41 | 46 | ||
| 42 | A menu item is usually a vector of three elements: [NAME CALLBACK ENABLE] | 47 | A menu item is usually a vector of three elements: [NAME CALLBACK ENABLE] |
| @@ -53,7 +58,7 @@ Alternatively, a menu item may have the form: | |||
| 53 | 58 | ||
| 54 | [ NAME CALLBACK [ KEYWORD ARG ] ... ] | 59 | [ NAME CALLBACK [ KEYWORD ARG ] ... ] |
| 55 | 60 | ||
| 56 | Where KEYWORD is one of the symbol defined below. | 61 | Where KEYWORD is one of the symbols defined below. |
| 57 | 62 | ||
| 58 | :keys KEYS | 63 | :keys KEYS |
| 59 | 64 | ||
| @@ -92,11 +97,12 @@ as a solid horizontal line. | |||
| 92 | 97 | ||
| 93 | A menu item can be a list. It is treated as a submenu. | 98 | A menu item can be a list. It is treated as a submenu. |
| 94 | The first element should be the submenu name. That's used as the | 99 | The first element should be the submenu name. That's used as the |
| 95 | menu item in the top-level menu. The cdr of the submenu list | 100 | menu item name in the top-level menu. It may be followed by the :filter |
| 96 | is a list of menu items, as above." | 101 | FUNCTION keyword argument pair. The rest of the submenu list are menu items, |
| 97 | (` (progn | 102 | as above." |
| 98 | (defvar (, symbol) nil (, doc)) | 103 | `(progn |
| 99 | (easy-menu-do-define (quote (, symbol)) (, maps) (, doc) (, menu))))) | 104 | (defvar ,symbol nil ,doc) |
| 105 | (easy-menu-do-define (quote ,symbol) ,maps ,doc ,menu))) | ||
| 100 | 106 | ||
| 101 | ;;;###autoload | 107 | ;;;###autoload |
| 102 | (defun easy-menu-do-define (symbol maps doc menu) | 108 | (defun easy-menu-do-define (symbol maps doc menu) |
| @@ -104,7 +110,7 @@ is a list of menu items, as above." | |||
| 104 | ;; `easy-menu-define' in order to make byte compiled files | 110 | ;; `easy-menu-define' in order to make byte compiled files |
| 105 | ;; compatible. Therefore everything interesting is done in this | 111 | ;; compatible. Therefore everything interesting is done in this |
| 106 | ;; function. | 112 | ;; function. |
| 107 | (set symbol (easy-menu-create-keymaps (car menu) (cdr menu))) | 113 | (set symbol (easy-menu-create-menu (car menu) (cdr menu))) |
| 108 | (fset symbol (` (lambda (event) (, doc) (interactive "@e") | 114 | (fset symbol (` (lambda (event) (, doc) (interactive "@e") |
| 109 | (x-popup-menu event (, symbol))))) | 115 | (x-popup-menu event (, symbol))))) |
| 110 | (mapcar (function (lambda (map) | 116 | (mapcar (function (lambda (map) |
| @@ -112,110 +118,169 @@ is a list of menu items, as above." | |||
| 112 | (cons (car menu) (symbol-value symbol))))) | 118 | (cons (car menu) (symbol-value symbol))))) |
| 113 | (if (keymapp maps) (list maps) maps))) | 119 | (if (keymapp maps) (list maps) maps))) |
| 114 | 120 | ||
| 115 | (defvar easy-menu-item-count 0) | 121 | (defun easy-menu-filter-return (menu) |
| 122 | "Convert MENU to the right thing to return from a menu filter. | ||
| 123 | MENU is a menu as computed by `easy-menu-define' or `easy-menu-create-menu' or | ||
| 124 | a symbol whose value is such a menu. | ||
| 125 | In Emacs a menu filter must return a menu (a keymap), in XEmacs a filter must | ||
| 126 | return a menu items list (without menu name and keywords). This function | ||
| 127 | returns the right thing in the two cases." | ||
| 128 | (easy-menu-get-map menu nil)) ; Get past indirections. | ||
| 116 | 129 | ||
| 117 | ;; Return a menu keymap corresponding to a Lucid-style menu list | ||
| 118 | ;; MENU-ITEMS, and with name MENU-NAME. | ||
| 119 | ;;;###autoload | 130 | ;;;###autoload |
| 120 | (defun easy-menu-create-keymaps (menu-name menu-items) | 131 | (defun easy-menu-create-menu (menu-name menu-items) |
| 121 | (let ((menu (make-sparse-keymap menu-name)) old-items have-buttons) | 132 | "Create a menu called MENU-NAME with items described in MENU-ITEMS. |
| 133 | MENU-NAME is a string, the name of the menu. MENU-ITEMS is a list of items | ||
| 134 | possibly preceded by keyword pairs as described in `easy-menu-define'." | ||
| 135 | (let ((menu (make-sparse-keymap menu-name)) | ||
| 136 | keyword filter have-buttons) | ||
| 137 | ;; Look for keywords. | ||
| 138 | (while (and menu-items (cdr menu-items) | ||
| 139 | (symbolp (setq keyword (car menu-items))) | ||
| 140 | (= ?: (aref (symbol-name keyword) 0))) | ||
| 141 | (if (eq keyword ':filter) (setq filter (cadr menu-items))) | ||
| 142 | (setq menu-items (cddr menu-items))) | ||
| 122 | ;; Process items in reverse order, | 143 | ;; Process items in reverse order, |
| 123 | ;; since the define-key loop reverses them again. | 144 | ;; since the define-key loop reverses them again. |
| 124 | (setq menu-items (reverse menu-items)) | 145 | (setq menu-items (reverse menu-items)) |
| 125 | (while menu-items | 146 | (while menu-items |
| 126 | (let* ((item (car menu-items)) | 147 | (setq have-buttons |
| 127 | (callback (if (vectorp item) (aref item 1))) | 148 | (easy-menu-do-add-item menu (car menu-items) have-buttons)) |
| 128 | (not-button t) | ||
| 129 | command enabler item-string name) | ||
| 130 | (cond ((stringp item) | ||
| 131 | (setq command nil) | ||
| 132 | (setq item-string (if (string-match "^-+$" item) "" item))) | ||
| 133 | ((consp item) | ||
| 134 | (setq command (easy-menu-create-keymaps (car item) (cdr item))) | ||
| 135 | (setq name (setq item-string (car item)))) | ||
| 136 | ((vectorp item) | ||
| 137 | (setq command (make-symbol (format "menu-function-%d" | ||
| 138 | easy-menu-item-count))) | ||
| 139 | (setq easy-menu-item-count (1+ easy-menu-item-count)) | ||
| 140 | (setq name (setq item-string (aref item 0))) | ||
| 141 | (let ((keyword (aref item 2))) | ||
| 142 | (if (and (symbolp keyword) | ||
| 143 | (= ?: (aref (symbol-name keyword) 0))) | ||
| 144 | (let ((count 2) | ||
| 145 | style selected active keys active-specified | ||
| 146 | arg) | ||
| 147 | (while (> (length item) count) | ||
| 148 | (setq keyword (aref item count)) | ||
| 149 | (setq arg (aref item (1+ count))) | ||
| 150 | (setq count (+ 2 count)) | ||
| 151 | (cond ((eq keyword ':keys) | ||
| 152 | (setq keys arg)) | ||
| 153 | ((eq keyword ':active) | ||
| 154 | (setq active (or arg ''nil) | ||
| 155 | active-specified t)) | ||
| 156 | ((eq keyword ':suffix) | ||
| 157 | (setq item-string | ||
| 158 | (concat item-string " " arg))) | ||
| 159 | ((eq keyword ':style) | ||
| 160 | (setq style arg)) | ||
| 161 | ((eq keyword ':selected) | ||
| 162 | (setq selected arg)))) | ||
| 163 | (if keys | ||
| 164 | (setq item-string | ||
| 165 | (concat item-string " (" keys ")"))) | ||
| 166 | (if (and selected | ||
| 167 | (or (eq style 'radio) (eq style 'toggle))) | ||
| 168 | ;; Simulate checkboxes and radio buttons. | ||
| 169 | (progn | ||
| 170 | (setq item-string | ||
| 171 | (concat | ||
| 172 | (if (eval selected) | ||
| 173 | (if (eq style 'radio) "(*) " "[X] ") | ||
| 174 | (if (eq style 'radio) "( ) " "[ ] ")) | ||
| 175 | item-string)) | ||
| 176 | (put command 'menu-enable | ||
| 177 | (list 'easy-menu-update-button | ||
| 178 | item-string | ||
| 179 | (if (eq style 'radio) ?* ?X) | ||
| 180 | selected | ||
| 181 | (or active t))) | ||
| 182 | (setq not-button nil | ||
| 183 | active nil | ||
| 184 | have-buttons t) | ||
| 185 | (while old-items ; Fix items aleady defined. | ||
| 186 | (setcar (car old-items) | ||
| 187 | (concat " " (car (car old-items)))) | ||
| 188 | (setq old-items (cdr old-items))))) | ||
| 189 | (if active-specified (put command 'menu-enable active))) | ||
| 190 | ;; If the third element is nil, | ||
| 191 | ;; make this command always disabled. | ||
| 192 | (put command 'menu-enable (or keyword ''nil)))) | ||
| 193 | (if (symbolp callback) | ||
| 194 | (fset command callback) | ||
| 195 | (fset command (list 'lambda () '(interactive) callback))) | ||
| 196 | (put command 'menu-alias t))) | ||
| 197 | (if (null command) | ||
| 198 | ;; Handle inactive strings specially--allow any number | ||
| 199 | ;; of identical ones. | ||
| 200 | (setcdr menu (cons (list nil item-string) (cdr menu))) | ||
| 201 | (if (and not-button have-buttons) | ||
| 202 | (setq item-string (concat " " item-string))) | ||
| 203 | (setq command (cons item-string command)) | ||
| 204 | (if (not have-buttons) ; Save all items so that we can fix | ||
| 205 | (setq old-items (cons command old-items))) ; if we have buttons. | ||
| 206 | (when name | ||
| 207 | (let ((key (vector (intern name)))) | ||
| 208 | (if (lookup-key menu key) | ||
| 209 | (setq key (vector (intern (concat name "*"))))) | ||
| 210 | (define-key menu key command))))) | ||
| 211 | (setq menu-items (cdr menu-items))) | 149 | (setq menu-items (cdr menu-items))) |
| 150 | (when filter | ||
| 151 | (setq menu (easy-menu-make-symbol menu nil)) | ||
| 152 | (put menu 'menu-enable | ||
| 153 | `(easy-menu-filter (quote ,menu) (quote ,filter)))) | ||
| 212 | menu)) | 154 | menu)) |
| 213 | 155 | ||
| 156 | |||
| 157 | ;; Button prefixes. | ||
| 158 | (defvar easy-menu-button-prefix | ||
| 159 | '((radio ?* . "( ) ") (toggle ?X . "[ ] "))) | ||
| 160 | |||
| 161 | (defun easy-menu-do-add-item (menu item have-buttons &optional prev top) | ||
| 162 | ;; Parse an item description and add the item to a keymap. This is | ||
| 163 | ;; the function that is used for item definition by the other easy-menu | ||
| 164 | ;; functions. | ||
| 165 | ;; MENU is a sparse keymap. | ||
| 166 | ;; ITEM defines an item as in `easy-menu-define'. | ||
| 167 | ;; HAVE-BUTTONS is a string or nil. If not nil, use as item prefix for | ||
| 168 | ;; items that are not toggle or radio buttons to compensate for the | ||
| 169 | ;; button prefix. | ||
| 170 | ;; PREV is nil or a tail in MENU. If PREV is not nil put item after | ||
| 171 | ;; PREV in MENU, otherwise put it first in MENU. | ||
| 172 | ;; If TOP is true, this is an item in the menu bar itself so | ||
| 173 | ;; don't use prefix. In this case HAVE-BUTTONS will be nil. | ||
| 174 | (let (command name item-string is-button) | ||
| 175 | (cond | ||
| 176 | ((stringp item) | ||
| 177 | (setq item | ||
| 178 | (if (string-match ; If an XEmacs separator | ||
| 179 | "^\\(-+\\|\ | ||
| 180 | --:\\(\\(no\\|\\(sing\\|doub\\)le\\(Dashed\\)?\\)Line\\|\ | ||
| 181 | shadow\\(Double\\)?Etched\\(In\\|Out\\)\\(Dash\\)?\\)\\)$" | ||
| 182 | item) "" ; use a single line separator. | ||
| 183 | (concat have-buttons item))) | ||
| 184 | ;; Handle inactive strings specially, | ||
| 185 | ;; allow any number of identical ones. | ||
| 186 | (cond | ||
| 187 | (prev (setq menu prev)) | ||
| 188 | ((and (consp (cdr menu)) (stringp (cadr menu))) (setq menu (cdr menu)))) | ||
| 189 | (setcdr menu (cons (list nil item) (cdr menu)))) | ||
| 190 | ((consp item) | ||
| 191 | (setq name (setq item-string (car item))) | ||
| 192 | (setq command (if (keymapp (setq item (cdr item))) item | ||
| 193 | (easy-menu-create-menu name item)))) | ||
| 194 | ((vectorp item) | ||
| 195 | (setq name (setq item-string (aref item 0))) | ||
| 196 | (setq command (easy-menu-make-symbol (aref item 1) t)) | ||
| 197 | (let ((active (aref item 2)) | ||
| 198 | (count 2) | ||
| 199 | style selected) | ||
| 200 | (if (and (symbolp active) (= ?: (aref (symbol-name active) 0))) | ||
| 201 | (let ((count 2) keyword arg suffix keys) | ||
| 202 | (setq active nil) | ||
| 203 | (while (> (length item) count) | ||
| 204 | (setq keyword (aref item count)) | ||
| 205 | (setq arg (aref item (1+ count))) | ||
| 206 | (setq count (+ 2 count)) | ||
| 207 | (cond | ||
| 208 | ((eq keyword ':keys) (setq keys arg)) | ||
| 209 | ((eq keyword ':active) (setq active arg)) | ||
| 210 | ((eq keyword ':suffix) (setq suffix arg)) | ||
| 211 | ((eq keyword ':style) (setq style arg)) | ||
| 212 | ((eq keyword ':selected) (setq selected arg)))) | ||
| 213 | (if suffix (setq item-string (concat item-string " " suffix))) | ||
| 214 | (if keys | ||
| 215 | (setq item-string (concat item-string " (" keys ")"))) | ||
| 216 | (when (and selected | ||
| 217 | (setq style (assq style easy-menu-button-prefix))) | ||
| 218 | ;; Simulate checkboxes and radio buttons. | ||
| 219 | (setq item-string (concat (cddr style) item-string)) | ||
| 220 | (put command 'menu-enable | ||
| 221 | `(easy-menu-update-button ,item-string | ||
| 222 | ,(cadr style) | ||
| 223 | ,selected | ||
| 224 | ,(or active t))) | ||
| 225 | (setq is-button t) | ||
| 226 | (setq active nil) ; Already taken care of active. | ||
| 227 | (when (not (or have-buttons top)) | ||
| 228 | (setq have-buttons " ") | ||
| 229 | ;; Add prefix to menu items defined so far. | ||
| 230 | (easy-menu-change-prefix menu t))))) | ||
| 231 | (if active (put command 'menu-enable active))))) | ||
| 232 | (when name | ||
| 233 | (and (not is-button) have-buttons | ||
| 234 | (setq item-string (concat have-buttons item-string))) | ||
| 235 | (setq item (cons item-string command)) | ||
| 236 | (setq name (vector (intern name))) | ||
| 237 | (if prev (define-key-after menu name item (vector (caar prev))) | ||
| 238 | (define-key menu name item))) | ||
| 239 | have-buttons)) | ||
| 240 | |||
| 241 | (defvar easy-menu-item-count 0) | ||
| 242 | |||
| 243 | (defun easy-menu-make-symbol (callback call) | ||
| 244 | ;; Return a unique symbol with CALLBACK as function value. | ||
| 245 | ;; If CALL is false then this is a keymap, not a function. | ||
| 246 | ;; Else if CALLBACK is a symbol, avoid the indirection when looking for | ||
| 247 | ;; key-bindings in menu. | ||
| 248 | ;; Else make a lambda expression of CALLBACK. | ||
| 249 | (let ((command | ||
| 250 | (make-symbol (format "menu-function-%d" easy-menu-item-count)))) | ||
| 251 | (setq easy-menu-item-count (1+ easy-menu-item-count)) | ||
| 252 | (fset command | ||
| 253 | (cond | ||
| 254 | ((not call) callback) | ||
| 255 | ((symbolp callback) | ||
| 256 | ;; Try find key-bindings for callback instead of for command | ||
| 257 | (put command 'menu-alias t) ; when displaying menu. | ||
| 258 | callback) | ||
| 259 | (t `(lambda () (interactive) ,callback)))) | ||
| 260 | command)) | ||
| 261 | |||
| 262 | (defun easy-menu-filter (name filter) | ||
| 263 | "Used as menu-enable property to filter menus. | ||
| 264 | A call to this function is used as the menu-enable property for a menu with | ||
| 265 | a filter function. | ||
| 266 | NAME is a symbol with a keymap as function value. Call the function FILTER | ||
| 267 | with this keymap as argument. FILTER must return a keymap which becomes the | ||
| 268 | new function value for NAME. Use `easy-menu-filter-return' to return the | ||
| 269 | correct value in a way portable to XEmacs. If the new keymap is `eq' the old, | ||
| 270 | then the menu is not updated." | ||
| 271 | (let* ((old (symbol-function name)) | ||
| 272 | (new (funcall filter old))) | ||
| 273 | (or (eq old new) ; No change | ||
| 274 | (and (fset name new) | ||
| 275 | ;; Make sure the menu gets updated by returning a | ||
| 276 | ;; different value than last time to cheat the cache. | ||
| 277 | (random))))) | ||
| 278 | |||
| 214 | (defun easy-menu-update-button (item ch selected active) | 279 | (defun easy-menu-update-button (item ch selected active) |
| 215 | "Used as menu-enable property to update buttons. | 280 | "Used as menu-enable property to update buttons. |
| 216 | A call to this function is used as the menu-enable property for buttons. | 281 | A call to this function is used as the menu-enable property for buttons. |
| 217 | ITEM is the item-string into wich CH or ` ' is inserted depending on if | 282 | ITEM is the item-string into which CH or ` ' is inserted depending on if |
| 218 | SELECTED is true or not. The menu entry in enabled iff ACTIVE is true." | 283 | SELECTED is true or not. The menu entry in enabled iff ACTIVE is true." |
| 219 | (let ((new (if selected ch ? )) | 284 | (let ((new (if selected ch ? )) |
| 220 | (old (aref item 1))) | 285 | (old (aref item 1))) |
| 221 | (if (eq new old) | 286 | (if (eq new old) |
| @@ -228,24 +293,153 @@ SELECTED is true or not. The menu entry in enabled iff ACTIVE is true." | |||
| 228 | (and active | 293 | (and active |
| 229 | (random))))) | 294 | (random))))) |
| 230 | 295 | ||
| 231 | (defun easy-menu-change (path name items) | 296 | (defun easy-menu-change (path name items &optional before) |
| 232 | "Change menu found at PATH as item NAME to contain ITEMS. | 297 | "Change menu found at PATH as item NAME to contain ITEMS. |
| 233 | PATH is a list of strings for locating the menu containing NAME in the | 298 | PATH is a list of strings for locating the menu containing NAME in the |
| 234 | menu bar. ITEMS is a list of menu items, as in `easy-menu-define'. | 299 | menu bar. ITEMS is a list of menu items, as in `easy-menu-define'. |
| 235 | These items entirely replace the previous items in that map. | 300 | These items entirely replace the previous items in that map. |
| 301 | If NAME is not present in the menu located by PATH, then add item NAME to | ||
| 302 | that menu. If the optional argument BEFORE is present add NAME in menu | ||
| 303 | just before BEFORE, otherwise add at end of menu. | ||
| 236 | 304 | ||
| 237 | Call this from `menu-bar-update-hook' to implement dynamic menus." | 305 | Either call this from `menu-bar-update-hook' or use a menu filter, |
| 238 | (let ((map (key-binding (apply 'vector | 306 | to implement dynamic menus." |
| 239 | 'menu-bar | 307 | (easy-menu-add-item nil path (cons name items) before)) |
| 240 | (mapcar 'intern (append path (list name))))))) | ||
| 241 | (if (keymapp map) | ||
| 242 | (setcdr map (cdr (easy-menu-create-keymaps name items))) | ||
| 243 | (error "Malformed menu in `easy-menu-change'")))) | ||
| 244 | 308 | ||
| 309 | ;; XEmacs needs the following two functions to add and remove menus. | ||
| 310 | ;; In Emacs this is done automatically when switching keymaps, so | ||
| 311 | ;; here these functions are noops. | ||
| 245 | (defun easy-menu-remove (menu)) | 312 | (defun easy-menu-remove (menu)) |
| 246 | 313 | ||
| 247 | (defun easy-menu-add (menu &optional map)) | 314 | (defun easy-menu-add (menu &optional map)) |
| 248 | 315 | ||
| 316 | (defun easy-menu-add-item (menu path item &optional before) | ||
| 317 | "At the end of the submenu of MENU with path PATH add ITEM. | ||
| 318 | If ITEM is already present in this submenu, then this item will be changed. | ||
| 319 | otherwise ITEM will be added at the end of the submenu, unless the optional | ||
| 320 | argument BEFORE is present, in which case ITEM will instead be added | ||
| 321 | before the item named BEFORE. | ||
| 322 | MENU is either a symbol, which have earlier been used as the first | ||
| 323 | argument in a call to `easy-menu-define', or the value of such a symbol | ||
| 324 | i.e. a menu, or nil which stands for the menu-bar itself. | ||
| 325 | PATH is a list of strings for locating the submenu where ITEM is to be | ||
| 326 | added. If PATH is nil, MENU itself is used. Otherwise, the first | ||
| 327 | element should be the name of a submenu directly under MENU. This | ||
| 328 | submenu is then traversed recursively with the remaining elements of PATH. | ||
| 329 | ITEM is either defined as in `easy-menu-define' or a menu defined earlier | ||
| 330 | by `easy-menu-define' or `easy-menu-create-menu'." | ||
| 331 | (let ((top (not (or menu path))) | ||
| 332 | tmp prev next) | ||
| 333 | (setq menu (easy-menu-get-map menu path)) | ||
| 334 | (or (lookup-key menu (vector (intern (elt item 0)))) | ||
| 335 | (and menu (keymapp (cdr menu))) | ||
| 336 | (setq tmp (cdr menu))) | ||
| 337 | (while (and tmp (not (keymapp tmp)) | ||
| 338 | (not (and (consp (car tmp)) (symbolp (caar tmp))))) | ||
| 339 | (setq tmp (cdr tmp))) | ||
| 340 | (and before (setq before (intern before))) | ||
| 341 | (if (or (null tmp) (keymapp tmp) (eq (setq prev (caar tmp)) before)) | ||
| 342 | (setq prev nil) | ||
| 343 | (while (and tmp (not (keymapp tmp)) | ||
| 344 | (not (and (consp (car tmp)) | ||
| 345 | (eq (caar (setq next tmp)) before)))) | ||
| 346 | (if next (setq prev next)) | ||
| 347 | (setq next nil) | ||
| 348 | (setq tmp (cdr tmp)))) | ||
| 349 | (when (or (keymapp item) | ||
| 350 | (and (symbolp item) (keymapp (symbol-value item)))) | ||
| 351 | ;; Item is a keymap, find the prompt string and use as item name. | ||
| 352 | (setq next (easy-menu-get-map item nil)) | ||
| 353 | (if (not (keymapp item)) (setq item next)) | ||
| 354 | (setq tmp nil) ; No item name yet. | ||
| 355 | (while (and (null tmp) (consp (setq next (cdr next))) | ||
| 356 | (not (keymapp next))) | ||
| 357 | (if (stringp (car next)) (setq tmp (car next)) ; Got a name. | ||
| 358 | (setq next (cdr next)))) | ||
| 359 | (setq item (cons tmp item))) | ||
| 360 | (easy-menu-do-add-item menu item | ||
| 361 | (and (not top) (easy-menu-have-button menu) " ") | ||
| 362 | prev top))) | ||
| 363 | |||
| 364 | (defun easy-menu-item-present-p (menu path name) | ||
| 365 | "In submenu of MENU with path PATH, return true iff item NAME is present. | ||
| 366 | MENU and PATH are defined as in `easy-menu-add-item'. | ||
| 367 | NAME should be a string, the name of the element to be looked for." | ||
| 368 | (lookup-key (easy-menu-get-map menu path) (vector (intern name)))) | ||
| 369 | |||
| 370 | (defun easy-menu-remove-item (menu path name) | ||
| 371 | "From submenu of MENU with path PATH remove item NAME. | ||
| 372 | MENU and PATH are defined as in `easy-menu-add-item'. | ||
| 373 | NAME should be a string, the name of the element to be removed." | ||
| 374 | (let ((item (vector (intern name))) | ||
| 375 | (top (not (or menu path))) | ||
| 376 | tmp) | ||
| 377 | (setq menu (easy-menu-get-map menu path)) | ||
| 378 | (when (setq tmp (lookup-key menu item)) | ||
| 379 | (define-key menu item nil) | ||
| 380 | (and (not top) | ||
| 381 | (easy-menu-is-button tmp) ; Removed item was a button and | ||
| 382 | (not (easy-menu-have-button menu)) ; no buttons left then | ||
| 383 | ;; remove prefix from items in menu | ||
| 384 | (easy-menu-change-prefix menu nil))))) | ||
| 385 | |||
| 386 | (defun easy-menu-get-map (menu path) | ||
| 387 | ;; Return a sparse keymap in which to add or remove an item. | ||
| 388 | ;; MENU and PATH are as defined in `easy-menu-remove-item'. | ||
| 389 | (if (null menu) | ||
| 390 | (setq menu (key-binding (vconcat '(menu-bar) (mapcar 'intern path)))) | ||
| 391 | (if (and (symbolp menu) (not (keymapp menu))) | ||
| 392 | (setq menu (symbol-value menu))) | ||
| 393 | (if path (setq menu (lookup-key menu (vconcat (mapcar 'intern path)))))) | ||
| 394 | (while (and (symbolp menu) (keymapp menu)) | ||
| 395 | (setq menu (symbol-function menu))) | ||
| 396 | (or (keymapp menu) (error "Malformed menu in easy-menu: (%s)" menu)) | ||
| 397 | menu) | ||
| 398 | |||
| 399 | (defun easy-menu-is-button (val) | ||
| 400 | ;; VAL is a real menu binding. Return true iff it is a toggle or | ||
| 401 | ;; radio button. | ||
| 402 | (and (symbolp val) | ||
| 403 | (consp (setq val (get val 'menu-enable))) | ||
| 404 | (eq (car val) 'easy-menu-update-button))) | ||
| 405 | |||
| 406 | (defun easy-menu-have-button (map) | ||
| 407 | ;; MAP is a sparse keymap. Return true iff there is any toggle or radio | ||
| 408 | ;; button in MAP. | ||
| 409 | (let ((have nil) tmp) | ||
| 410 | (while (and (consp map) (not have)) | ||
| 411 | (and (consp (setq tmp (car map))) | ||
| 412 | (consp (setq tmp (cdr tmp))) | ||
| 413 | (stringp (car tmp)) | ||
| 414 | (setq have (easy-menu-is-button (easy-menu-real-binding tmp)))) | ||
| 415 | (setq map (cdr map))) | ||
| 416 | have)) | ||
| 417 | |||
| 418 | (defun easy-menu-real-binding (val) | ||
| 419 | ;; Val is a menu keymap binding. Skip item string. | ||
| 420 | ;; Also skip a possible help string and/or key-binding cache. | ||
| 421 | (if (and (consp (setq val (cdr val))) (stringp (car val))) | ||
| 422 | (setq val (cdr val))) ; Skip help string. | ||
| 423 | (if (and (consp val) (consp (car val)) | ||
| 424 | (or (null (caar val)) (vectorp (caar val)))) | ||
| 425 | (setq val (cdr val))) ; Skip key-binding cache. | ||
| 426 | val) | ||
| 427 | |||
| 428 | (defun easy-menu-change-prefix (map add) | ||
| 429 | ;; MAP is a sparse keymap. | ||
| 430 | ;; If ADD is true add a button compensating prefix to each menu item in MAP. | ||
| 431 | ;; Else remove prefix instead. | ||
| 432 | (let (tmp val) | ||
| 433 | (while (consp map) | ||
| 434 | (when (and (consp (setq tmp (car map))) | ||
| 435 | (consp (setq tmp (cdr tmp))) | ||
| 436 | (stringp (car tmp))) | ||
| 437 | (cond | ||
| 438 | (add (setcar tmp (concat " " (car tmp)))) | ||
| 439 | ((string-match "$ " (car tmp)) | ||
| 440 | (setcar tmp (substring (car tmp) (match-end 0)))))) | ||
| 441 | (setq map (cdr map))))) | ||
| 442 | |||
| 249 | (provide 'easymenu) | 443 | (provide 'easymenu) |
| 250 | 444 | ||
| 251 | ;;; easymenu.el ends here | 445 | ;;; easymenu.el ends here |