;;; easymenu.el --- support the easymenu interface for defining a menu.
-;; Keywords: emulations
-
;; Copyright (C) 1994 Free Software Foundation, Inc.
+;; Keywords: emulations
+;; Author: rms
+
;; This file is part of GNU Emacs.
;; GNU Emacs is free software; you can redistribute it and/or modify
;;; Code:
-;;;###autoload.
-(defun easy-menu-define (symbol maps doc menu)
+;;;###autoload
+(defmacro easy-menu-define (symbol maps doc menu)
"Define a menu bar submenu in maps MAPS, according to MENU.
-The arguments SYMBOL and DOC are ignored; they are present for
-compatibility only.
+SYMBOL is used as a variable to hold the menu data. It is not evaluated.
+DOC is a doc string for that variable.
The first element of MENU must be a string. It is the menu bar item name.
The rest of the elements are menu items.
-A menu item is a vector of three elements:
+A menu item is usually a vector of three elements: [NAME CALLBACK ENABLE]
+
+NAME is a string--the menu item name.
+
+CALLBACK is a command to run when the item is chosen,
+or a list to evaluate when the item is chosen.
+
+ENABLE is an expression; the item is enabled for selection
+whenever this expression's value is non-nil.
+
+Alternatively, a menu item may have the form:
+
+ [ NAME CALLBACK [ KEYWORD ARG ] ... ]
+
+Where KEYWORD is one of the symbol defined below.
+
+ :keys KEYS
- - the name of the menu item (a string);
- - the `callback' of that item;
- - t.
+KEYS is a string; a complex keyboard equivalent to this menu item.
+This is normally not needed because keyboard equivalents are usually
+computed automatically.
-If the `callback' of a menu item is a symbol, then it must name a
-command. It will be invoked with `call-interactively'. If it is a
-list, then it is evaluated with `eval'.
+ :active ENABLE
-If an element of a menu is a string, then that string appears in the
-menu as unselectable text.
+ENABLE is an expression; the item is enabled for selection
+whenever this expression's value is non-nil.
-If an element of a menu is a string consisting solely of hyphens, then that
-item is displayed as a solid horizontal line.
+ :suffix NAME
-If an element of a menu is a list, it is treated as a submenu.
+NAME is a string; the name of an argument to CALLBACK.
+
+ :style
+
+STYLE is a symbol describing the type of menu item. The following are
+defined:
+
+toggle: A checkbox.
+ Currently just prepend the name with the string \"Toggle \".
+radio: A radio button.
+nil: An ordinary menu item.
+
+ :selected SELECTED
+
+SELECTED is an expression; the checkbox or radio button is selected
+whenever this expression's value is non-nil.
+Currently just disable radio buttons, no effect on checkboxes.
+
+A menu item can be a string. Then that string appears in the menu as
+unselectable text. A string consisting solely of hyphens is displayed
+as a solid horizontal line.
+
+A menu item can be a list. It is treated as a submenu.
The first element should be the submenu name. That's used as the
menu item in the top-level menu. The cdr of the submenu list
is a list of menu items, as above."
- (let ((keymap (easy-menu-keymap (car menu) (cdr menu))))
- (mapcar (function (lambda (map)
- (define-key map (vector 'menu-bar (intern (car menu)))
- (cons (car menu) keymap))))
- (if (keymapp maps) (list maps) maps))))
+ (` (progn
+ (defvar (, symbol) nil (, doc))
+ (easy-menu-do-define (quote (, symbol)) (, maps) (, doc) (, menu)))))
+
+(defun easy-menu-do-define (symbol maps doc menu)
+ ;; We can't do anything that might differ between Emacs dialects in
+ ;; `easy-menu-define' in order to make byte compiled files
+ ;; compatible. Therefore everything interesting is done in this
+ ;; function.
+ (set symbol (easy-menu-create-keymaps (car menu) (cdr menu)))
+ (fset symbol (` (lambda (event) (, doc) (interactive "@e")
+ (easy-popup-menu event (, symbol)))))
+ (mapcar (function (lambda (map)
+ (define-key map (vector 'menu-bar (intern (car menu)))
+ (cons (car menu) (symbol-value symbol)))))
+ (if (keymapp maps) (list maps) maps)))
+
+(defvar easy-menu-item-count 0)
;; Return a menu keymap corresponding to a Lucid-style menu list
;; MENU-ITEMS, and with name MENU-NAME.
-(defun easy-menu-keymap (menu-name menu-items)
+;;;###autoload
+(defun easy-menu-create-keymaps (menu-name menu-items)
(let ((menu (make-sparse-keymap menu-name)))
;; Process items in reverse order,
;; since the define-key loop reverses them again.
(setq command nil)
(setq name (if (string-match "^-+$" item) "" item)))
((consp item)
- (setq command (make-lucid-menu-keymap (car item) (cdr item)))
+ (setq command (easy-menu-create-keymaps (car item) (cdr item)))
(setq name (car item)))
((vectorp item)
(setq command (make-symbol (format "menu-function-%d"
- add-menu-item-count)))
- (setq enabler (make-symbol (format "menu-function-%d-enabler"
- add-menu-item-count)))
- (setq add-menu-item-count (1+ add-menu-item-count))
- (put command 'menu-enable enabler)
- (set enabler (aref item 2))
- (setq name (aref item 0))
+ easy-menu-item-count)))
+ (setq easy-menu-item-count (1+ easy-menu-item-count))
+ (setq name (aref item 0))
+ (let ((keyword (aref item 2)))
+ (if (and (symbolp keyword)
+ (= ?: (aref (symbol-name keyword) 0)))
+ (let ((count 2)
+ style selected active keys
+ arg)
+ (while (> (length item) count)
+ (setq keyword (aref item count))
+ (setq arg (aref item (1+ count)))
+ (setq count (+ 2 count))
+ (cond ((eq keyword ':keys)
+ (setq keys arg))
+ ((eq keyword ':active)
+ (setq active arg))
+ ((eq keyword ':suffix)
+ (setq name (concat name " " arg)))
+ ((eq keyword ':style)
+ (setq style arg))
+ ((eq keyword ':selected)
+ (setq selected arg))))
+ (if keys
+ (setq name (concat name " (" keys ")")))
+ (if (eq style 'toggle)
+ ;; Simulate checkboxes.
+ (setq name (concat "Toggle " name)))
+ (if active
+ (put command 'menu-enable active)
+ (and (eq style 'radio)
+ selected
+ ;; Simulate radio buttons with menu-enable.
+ (put command 'menu-enable
+ (list 'not selected)))))))
+ (if (keymapp callback)
+ (setq name (concat name " ...")))
(if (symbolp callback)
(fset command callback)
(fset command (list 'lambda () '(interactive) callback)))))
(setq menu-items (cdr menu-items)))
menu))
+(defun easy-menu-change (path name items)
+ "Change menu found at PATH as item NAME to contain ITEMS.
+PATH is a list of strings for locating the menu containing NAME in the
+menu bar. ITEMS is a list of menu items, as in `easy-menu-define'.
+These items entirely replace the previous items in that map.
+
+Call this from `activate-menubar-hook' to implement dynamic menus."
+ (let ((map (key-binding (apply 'vector
+ 'menu-bar
+ (mapcar 'intern (append path (list name)))))))
+ (if (keymapp map)
+ (setcdr map (cdr (easy-menu-create-keymaps name items)))
+ (error "Malformed menu in `easy-menu-change'"))))
+
+(defun easy-menu-remove (menu))
+
+(defun easy-menu-add (menu &optional map))
+
(provide 'easymenu)
;;; easymenu.el ends here