(tex-goto-last-unclosed-latex-block): New function. Bound to C-c C-u in
[bpt/emacs.git] / lisp / emacs-lisp / lmenu.el
CommitLineData
aae56ea7
ER
1;;; lmenu.el --- emulate Lucid's menubar support
2
76550a57
ER
3;; Keywords: emulations
4
c7986c18
ER
5;; Copyright (C) 1992, 1993 Free Software Foundation, Inc.
6
7;; This file is part of GNU Emacs.
8
9;; GNU Emacs is free software; you can redistribute it and/or modify
10;; it under the terms of the GNU General Public License as published by
11;; the Free Software Foundation; either version 2, or (at your option)
12;; any later version.
13
14;; GNU Emacs is distributed in the hope that it will be useful,
15;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17;; GNU General Public License for more details.
18
19;; You should have received a copy of the GNU General Public License
20;; along with GNU Emacs; see the file COPYING. If not, write to
21;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22
aae56ea7
ER
23;;; Code:
24
c7986c18
ER
25\f
26;; First, emulate the Lucid menubar support in GNU Emacs 19.
27
28;; Arrange to use current-menubar to set up part of the menu bar.
29
30(setq recompute-lucid-menubar 'recompute-lucid-menubar)
31(defun recompute-lucid-menubar ()
32 (define-key lucid-menubar-map [menu-bar]
33 (condition-case nil
34 (make-lucid-menu-keymap "menu-bar" current-menubar)
35 (error (message "Invalid data in current-menubar moved to lucid-failing-menubar")
36 (sit-for 1)
37 (setq lucid-failing-menubar current-menubar
38 current-menubar nil))))
39 (setq lucid-menu-bar-dirty-flag nil))
40
41(defvar lucid-menubar-map (make-sparse-keymap))
42(or (assq 'current-menubar minor-mode-map-alist)
43 (setq minor-mode-map-alist
44 (cons (cons 'current-menubar lucid-menubar-map)
45 minor-mode-map-alist)))
46
47(defun set-menubar-dirty-flag ()
48 (force-mode-line-update)
49 (setq lucid-menu-bar-dirty-flag t))
50
51(defvar add-menu-item-count 0)
52
53;; Return a menu keymap corresponding to a Lucid-style menu list
54;; MENU-ITEMS, and with name MENU-NAME.
55(defun make-lucid-menu-keymap (menu-name menu-items)
56 (let ((menu (make-sparse-keymap menu-name)))
57 ;; Process items in reverse order,
58 ;; since the define-key loop reverses them again.
59 (setq menu-items (reverse menu-items))
60 (while menu-items
61 (let* ((item (car menu-items))
62 (callback (if (vectorp item) (aref item 1)))
63 command enabler name)
64 (cond ((stringp item)
65 (setq command nil)
a7605222 66 (setq name (if (string-match "^-+$" item) "" item)))
c7986c18
ER
67 ((consp item)
68 (setq command (make-lucid-menu-keymap (car item) (cdr item)))
69 (setq name (car item)))
70 ((vectorp item)
71 (setq command (make-symbol (format "menu-function-%d"
72 add-menu-item-count)))
73 (setq enabler (make-symbol (format "menu-function-%d-enabler"
74 add-menu-item-count)))
75 (setq add-menu-item-count (1+ add-menu-item-count))
76 (put command 'menu-enable enabler)
77 (set enabler (aref item 2))
78 (setq name (aref item 0))
79 (if (symbolp callback)
80 (fset command callback)
81 (fset command (list 'lambda () '(interactive) callback)))))
b69f3ab1
RS
82 (if (null command)
83 ;; Handle inactive strings specially--allow any number
84 ;; of identical ones.
85 (setcdr menu (cons (list nil name) (cdr menu)))
86 (if name
87 (define-key menu (vector (intern name)) (cons name command)))))
c7986c18
ER
88 (setq menu-items (cdr menu-items)))
89 menu))
90
91(defun popup-menu (menu-desc)
92 "Pop up the given menu.
93A menu is a list of menu items, strings, and submenus.
94
95The first element of a menu must be a string, which is the name of the
96menu. This is the string that will be displayed in the parent menu, if
97any. For toplevel menus, it is ignored. This string is not displayed
98in the menu itself.
99
100A menu item is a vector of three or four elements:
101
102 - the name of the menu item (a string);
103 - the `callback' of that item;
104 - whether this item is active (selectable);
105 - and an optional string to append to the name.
106
107If the `callback' of a menu item is a symbol, then it must name a command.
108It will be invoked with `call-interactively'. If it is a list, then it is
109evaluated with `eval'.
110
111The fourth element of a menu item is a convenient way of adding the name
112of a command's ``argument'' to the menu, like ``Kill Buffer NAME''.
113
114If an element of a menu is a string, then that string will be presented in
115the menu as unselectable text.
116
117If an element of a menu is a string consisting solely of hyphens, then that
118item will be presented as a solid horizontal line.
119
120If an element of a menu is a list, it is treated as a submenu. The name of
121that submenu (the first element in the list) will be used as the name of the
122item representing this menu on the parent.
123
124The syntax, more precisely:
125
126 form := <something to pass to `eval'>
127 command := <a symbol or string, to pass to `call-interactively'>
128 callback := command | form
129 active-p := <t or nil, whether this thing is selectable>
130 text := <string, non selectable>
131 name := <string>
132 argument := <string>
133 menu-item := '[' name callback active-p [ argument ] ']'
134 menu := '(' name [ menu-item | menu | text ]+ ')'
135"
136 (let ((menu (make-lucid-menu-keymap (car menu-desc) (cdr menu-desc)))
137 (pos (mouse-position))
138 answer)
d06752db
RS
139 (while menu
140 (setq answer (x-popup-menu (list (list (nth 1 pos) (nthcdr 2 pos))
141 (car pos))
142 menu))
143 (setq cmd (lookup-key menu (vector answer)))
144 (setq menu nil)
145 (and cmd
146 (if (keymapp cmd)
147 (setq menu cmd)
148 (call-interactively cmd))))))
73a644b4
RS
149
150(defun popup-dialog-box (data)
151 "Pop up a dialog box.
152A dialog box description is a list.
153
154 - The first element of the list is a string to display in the dialog box.
155 - The rest of the elements are descriptions of the dialog box's buttons.
156 Each one is a vector of three elements:
157 - The first element is the text of the button.
158 - The second element is the `callback'.
159 - The third element is t or nil, whether this button is selectable.
160
161If the `callback' of a button is a symbol, then it must name a command.
162It will be invoked with `call-interactively'. If it is a list, then it is
163evaluated with `eval'.
164
165One (and only one) of the buttons may be `nil'. This marker means that all
166following buttons should be flushright instead of flushleft.
167
168The syntax, more precisely:
169
170 form := <something to pass to `eval'>
171 command := <a symbol or string, to pass to `call-interactively'>
172 callback := command | form
173 active-p := <t, nil, or a form to evaluate to decide whether this
174 button should be selectable>
175 name := <string>
176 partition := 'nil'
177 button := '[' name callback active-p ']'
178 dialog := '(' name [ button ]+ [ partition [ button ]+ ] ')'"
179 (let ((name (car data))
180 (tail (cdr data))
181 converted
182 choice)
183 (while tail
184 (if (null (car tail))
185 (setq converted (cons nil converted))
186 (let ((item (aref (car tail) 0))
187 (callback (aref (car tail) 1))
188 (enable (aref (car tail) 2)))
189 (setq converted
190 (cons (if enable (cons item callback) item)
191 converted))))
192 (setq tail (cdr tail)))
193 (setq choice (x-popup-dialog t (cons name (nreverse converted))))
194 (setq meaning (assq choice converted))
195 (if meaning
196 (if (symbolp (cdr meaning))
197 (call-interactively (cdr meaning))
198 (eval (cdr meaning))))))
c7986c18 199\f
8b86c9eb
RS
200;; This is empty because the usual elements of the menu bar
201;; are provided by menu-bar.el instead.
202;; It would not make sense to duplicate them here.
203(defconst default-menubar nil)
c7986c18
ER
204
205(defun set-menubar (menubar)
206 "Set the default menubar to be menubar."
207 (setq-default current-menubar (copy-sequence menubar))
208 (set-menubar-dirty-flag))
209
210(defun set-buffer-menubar (menubar)
211 "Set the buffer-local menubar to be menubar."
212 (make-local-variable 'current-menubar)
213 (setq current-menubar (copy-sequence menubar))
214 (set-menubar-dirty-flag))
215
216\f
217;;; menu manipulation functions
218
219(defun find-menu-item (menubar item-path-list &optional parent)
220 "Searches MENUBAR for item given by ITEM-PATH-LIST.
221Returns (ITEM . PARENT), where PARENT is the immediate parent of
222 the item found.
223Signals an error if the item is not found."
224 (or parent (setq item-path-list (mapcar 'downcase item-path-list)))
225 (if (not (consp menubar))
226 nil
227 (let ((rest menubar)
228 result)
229 (while rest
230 (if (and (car rest)
231 (equal (car item-path-list)
232 (downcase (if (vectorp (car rest))
233 (aref (car rest) 0)
234 (if (stringp (car rest))
235 (car rest)
236 (car (car rest)))))))
237 (setq result (car rest) rest nil)
238 (setq rest (cdr rest))))
239 (if (cdr item-path-list)
240 (if (consp result)
241 (find-menu-item (cdr result) (cdr item-path-list) result)
242 (if result
243 (signal 'error (list "not a submenu" result))
244 (signal 'error (list "no such submenu" (car item-path-list)))))
245 (cons result parent)))))
246
247
248(defun disable-menu-item (path)
249 "Make the named menu item be unselectable.
250PATH is a list of strings which identify the position of the menu item in
251the menu hierarchy. (\"File\" \"Save\") means the menu item called \"Save\"
252under the toplevel \"File\" menu. (\"Menu\" \"Foo\" \"Item\") means the
253menu item called \"Item\" under the \"Foo\" submenu of \"Menu\"."
254 (let* ((menubar current-menubar)
255 (pair (find-menu-item menubar path))
256 (item (car pair))
257 (menu (cdr pair)))
258 (or item
259 (signal 'error (list (if menu "No such menu item" "No such menu")
260 path)))
261 (if (consp item) (error "can't disable menus, only menu items"))
262 (aset item 2 nil)
263 (set-menubar-dirty-flag)
264 item))
265
266
267(defun enable-menu-item (path)
268 "Make the named menu item be selectable.
269PATH is a list of strings which identify the position of the menu item in
270the menu hierarchy. (\"File\" \"Save\") means the menu item called \"Save\"
271under the toplevel \"File\" menu. (\"Menu\" \"Foo\" \"Item\") means the
272menu item called \"Item\" under the \"Foo\" submenu of \"Menu\"."
273 (let* ((menubar current-menubar)
274 (pair (find-menu-item menubar path))
275 (item (car pair))
276 (menu (cdr pair)))
277 (or item
278 (signal 'error (list (if menu "No such menu item" "No such menu")
279 path)))
280 (if (consp item) (error "%S is a menu, not a menu item" path))
281 (aset item 2 t)
282 (set-menubar-dirty-flag)
283 item))
284
285
286(defun add-menu-item-1 (item-p menu-path item-name item-data enabled-p before)
287 (if before (setq before (downcase before)))
288 (let* ((menubar current-menubar)
289 (menu (condition-case ()
290 (car (find-menu-item menubar menu-path))
291 (error nil)))
292 (item (if (listp menu)
293 (car (find-menu-item (cdr menu) (list item-name)))
294 (signal 'error (list "not a submenu" menu-path)))))
295 (or menu
296 (let ((rest menu-path)
297 (so-far menubar))
298 (while rest
299;;; (setq menu (car (find-menu-item (cdr so-far) (list (car rest)))))
300 (setq menu
301 (if (eq so-far menubar)
302 (car (find-menu-item so-far (list (car rest))))
303 (car (find-menu-item (cdr so-far) (list (car rest))))))
304 (or menu
305 (let ((rest2 so-far))
306 (while (and (cdr rest2) (car (cdr rest2)))
307 (setq rest2 (cdr rest2)))
308 (setcdr rest2
309 (nconc (list (setq menu (list (car rest))))
310 (cdr rest2)))))
311 (setq so-far menu)
312 (setq rest (cdr rest)))))
313 (or menu (setq menu menubar))
314 (if item
315 nil ; it's already there
316 (if item-p
317 (setq item (vector item-name item-data enabled-p))
318 (setq item (cons item-name item-data)))
319 ;; if BEFORE is specified, try to add it there.
320 (if before
321 (setq before (car (find-menu-item menu (list before)))))
322 (let ((rest menu)
323 (added-before nil))
324 (while rest
325 (if (eq before (car (cdr rest)))
326 (progn
327 (setcdr rest (cons item (cdr rest)))
328 (setq rest nil added-before t))
329 (setq rest (cdr rest))))
330 (if (not added-before)
331 ;; adding before the first item on the menubar itself is harder
332 (if (and (eq menu menubar) (eq before (car menu)))
333 (setq menu (cons item menu)
334 current-menubar menu)
335 ;; otherwise, add the item to the end.
336 (nconc menu (list item))))))
337 (if item-p
338 (progn
339 (aset item 1 item-data)
340 (aset item 2 (not (null enabled-p))))
341 (setcar item item-name)
342 (setcdr item item-data))
343 (set-menubar-dirty-flag)
344 item))
345
346(defun add-menu-item (menu-path item-name function enabled-p &optional before)
347 "Add a menu item to some menu, creating the menu first if necessary.
348If the named item exists already, it is changed.
349MENU-PATH identifies the menu under which the new menu item should be inserted.
350 It is a list of strings; for example, (\"File\") names the top-level \"File\"
351 menu. (\"File\" \"Foo\") names a hypothetical submenu of \"File\".
352ITEM-NAME is the string naming the menu item to be added.
353FUNCTION is the command to invoke when this menu item is selected.
354 If it is a symbol, then it is invoked with `call-interactively', in the same
355 way that functions bound to keys are invoked. If it is a list, then the
356 list is simply evaluated.
357ENABLED-P controls whether the item is selectable or not.
358BEFORE, if provided, is the name of a menu item before which this item should
359 be added, if this item is not on the menu already. If the item is already
360 present, it will not be moved."
361 (or menu-path (error "must specify a menu path"))
362 (or item-name (error "must specify an item name"))
363 (add-menu-item-1 t menu-path item-name function enabled-p before))
364
365
366(defun delete-menu-item (path)
367 "Remove the named menu item from the menu hierarchy.
368PATH is a list of strings which identify the position of the menu item in
369the menu hierarchy. (\"File\" \"Save\") means the menu item called \"Save\"
370under the toplevel \"File\" menu. (\"Menu\" \"Foo\" \"Item\") means the
371menu item called \"Item\" under the \"Foo\" submenu of \"Menu\"."
372 (let* ((menubar current-menubar)
373 (pair (find-menu-item menubar path))
374 (item (car pair))
375 (menu (or (cdr pair) menubar)))
376 (if (not item)
377 nil
378 ;; the menubar is the only special case, because other menus begin
379 ;; with their name.
380 (if (eq menu current-menubar)
381 (setq current-menubar (delq item menu))
382 (delq item menu))
383 (set-menubar-dirty-flag)
384 item)))
385
386
387(defun relabel-menu-item (path new-name)
388 "Change the string of the specified menu item.
389PATH is a list of strings which identify the position of the menu item in
390the menu hierarchy. (\"File\" \"Save\") means the menu item called \"Save\"
391under the toplevel \"File\" menu. (\"Menu\" \"Foo\" \"Item\") means the
392menu item called \"Item\" under the \"Foo\" submenu of \"Menu\".
393NEW-NAME is the string that the menu item will be printed as from now on."
394 (or (stringp new-name)
395 (setq new-name (signal 'wrong-type-argument (list 'stringp new-name))))
396 (let* ((menubar current-menubar)
397 (pair (find-menu-item menubar path))
398 (item (car pair))
399 (menu (cdr pair)))
400 (or item
401 (signal 'error (list (if menu "No such menu item" "No such menu")
402 path)))
403 (if (and (consp item)
404 (stringp (car item)))
405 (setcar item new-name)
406 (aset item 0 new-name))
407 (set-menubar-dirty-flag)
408 item))
409
410(defun add-menu (menu-path menu-name menu-items &optional before)
411 "Add a menu to the menubar or one of its submenus.
412If the named menu exists already, it is changed.
413MENU-PATH identifies the menu under which the new menu should be inserted.
414 It is a list of strings; for example, (\"File\") names the top-level \"File\"
415 menu. (\"File\" \"Foo\") names a hypothetical submenu of \"File\".
416 If MENU-PATH is nil, then the menu will be added to the menubar itself.
417MENU-NAME is the string naming the menu to be added.
418MENU-ITEMS is a list of menu item descriptions.
419 Each menu item should be a vector of three elements:
420 - a string, the name of the menu item;
421 - a symbol naming a command, or a form to evaluate;
422 - and t or nil, whether this item is selectable.
423BEFORE, if provided, is the name of a menu before which this menu should
424 be added, if this menu is not on its parent already. If the menu is already
425 present, it will not be moved."
426 (or menu-name (error "must specify a menu name"))
427 (or menu-items (error "must specify some menu items"))
428 (add-menu-item-1 nil menu-path menu-name menu-items t before))
429
430\f
431
432(defvar put-buffer-names-in-file-menu t)
433
c7986c18 434
b0413013
RS
435;; Don't unconditionally enable menu bars; leave that up to the user.
436;;(let ((frames (frame-list)))
437;; (while frames
438;; (modify-frame-parameters (car frames) '((menu-bar-lines . 1)))
439;; (setq frames (cdr frames))))
440;;(or (assq 'menu-bar-lines default-frame-alist)
441;; (setq default-frame-alist
442;; (cons '(menu-bar-lines . 1) default-frame-alist)))
c7986c18
ER
443
444(set-menubar default-menubar)
445\f
289c4836 446(provide 'lmenu)
c7986c18 447
aae56ea7 448;;; lmenu.el ends here