Mercurial > hg > xemacs-beta
comparison lisp/menubar.el @ 2545:9caf26dd924f
[xemacs-hg @ 2005-02-03 05:03:36 by ben]
behavior ws #2: menu-related changes
menubar.c: New fun to compare menu itext as if the two were normalized.
menubar.c: Rename; there are no external callers of this function.
Remove unneeded BUFFER argument. Don't downcase.
(This will be done in compare-menu-text.)
Document that return value may be same string.
easymenu.el, map-ynp.el: Use normalize-menu-text not normalize-menu-item-name.
menubar-items.el, menubar.el: Move to menubar.el and rewrite for cleanliness.
menubar-items.el: Use menu-split-long-menu-and-sort.
menubar-items.el, menubar.el: Move to menubar.el.
menubar.el: New funs.
menubar.el: Split up find-menu-item w/find-menu-item-1, since PARENT is not
an external item.
Rewrite to use compare-menu-text.
menubar.el: Don't normalize items as find-menu-item does not need it.
menubar-items.el: Delete old Behavior menu defn, replaced by behavior-menu-filter.
Planning to [[Delete many menus from Tools menu -- they have been
integrated as part of the behavior system.]] Currently the new
Tools menu (very short, just a call to the behavior-menu-filter)
is commented out, and the old Toold menu defn remains. Once the
new packages are in place (c. 1 or 2 weeks), I'll make the
switchover.
Use menu-split-long-menu-and-sort.
author | ben |
---|---|
date | Thu, 03 Feb 2005 05:03:45 +0000 |
parents | a307f9a2021d |
children | 979c4c930bb5 |
comparison
equal
deleted
inserted
replaced
2544:b4a8cd0dd8df | 2545:9caf26dd924f |
---|---|
1 ;;; menubar.el --- Menubar support for XEmacs | 1 ;;; menubar.el --- Menubar support for XEmacs |
2 | 2 |
3 ;; Copyright (C) 1991-4, 1997-1998 Free Software Foundation, Inc. | 3 ;; Copyright (C) 1991-4, 1997-1998 Free Software Foundation, Inc. |
4 ;; Copyright (C) 1995 Tinker Systems and INS Engineering Corp. | 4 ;; Copyright (C) 1995 Tinker Systems and INS Engineering Corp. |
5 ;; Copyright (C) 1995, 1996 Ben Wing. | 5 ;; Copyright (C) 1995, 1996, 2003 Ben Wing. |
6 | 6 |
7 ;; Maintainer: XEmacs Development Team | 7 ;; Maintainer: XEmacs Development Team |
8 ;; Keywords: internal, extensions, dumped | 8 ;; Keywords: internal, extensions, dumped |
9 | 9 |
10 ;; This file is part of XEmacs. | 10 ;; This file is part of XEmacs. |
161 ;; (t (signal 'error (list "unrecognized menu descriptor" menuitem)))) | 161 ;; (t (signal 'error (list "unrecognized menu descriptor" menuitem)))) |
162 (t (message "unrecognized menu descriptor %s" (prin1-to-string menuitem)))) | 162 (t (message "unrecognized menu descriptor %s" (prin1-to-string menuitem)))) |
163 (setq menu (cdr menu))))) | 163 (setq menu (cdr menu))))) |
164 | 164 |
165 | 165 |
166 ;;; menu manipulation functions | 166 ;;; basic menu manipulation functions |
167 | 167 |
168 (defun find-menu-item (menubar item-path-list &optional parent) | 168 (defun menu-item-text (item &optional normalize) |
169 "Search MENUBAR for item given by ITEM-PATH-LIST starting from PARENT. | 169 "Return the text that is displayed for a menu item. |
170 If ITEM is a string (unselectable text), it is returned; otherwise, | |
171 the first element of the cons or vector is returned. | |
172 If NORMALIZE is non-nil, pass the text through `normalize-menu-text' | |
173 before being returned, to remove accelerator specs and convert %% to %." | |
174 (let ((val (if (stringp item) item (elt item 0)))) | |
175 (if normalize (normalize-menu-text val) val))) | |
176 | |
177 (defun find-menu-item (menubar item-path-list) | |
178 "Search MENUBAR for item given by ITEM-PATH-LIST. | |
170 Returns (ITEM . PARENT), where PARENT is the immediate parent of | 179 Returns (ITEM . PARENT), where PARENT is the immediate parent of |
171 the item found. | 180 the item found. |
172 If the item does not exist, the car of the returned value is nil. | 181 If the item does not exist, the car of the returned value is nil. |
173 If some menu in the ITEM-PATH-LIST does not exist, an error is signalled." | 182 If some menu in the ITEM-PATH-LIST does not exist, an error is signalled." |
183 (find-menu-item-1 menubar item-path-list)) | |
184 | |
185 (defun find-menu-item-1 (menubar item-path-list &optional parent) | |
174 (check-argument-type 'listp item-path-list) | 186 (check-argument-type 'listp item-path-list) |
175 (unless parent | |
176 (setq item-path-list (mapcar 'normalize-menu-item-name item-path-list))) | |
177 (if (not (consp menubar)) | 187 (if (not (consp menubar)) |
178 nil | 188 nil |
179 (let ((rest menubar) | 189 (let ((rest menubar) |
180 result) | 190 result) |
181 (when (stringp (car rest)) | 191 (when (stringp (car rest)) |
182 (setq rest (cdr rest))) | 192 (setq rest (cdr rest))) |
183 (while (keywordp (car rest)) | 193 (while (keywordp (car rest)) |
184 (setq rest (cddr rest))) | 194 (setq rest (cddr rest))) |
185 (while rest | 195 (while rest |
186 (if (and (car rest) | 196 (if (and (car rest) |
187 (equal (car item-path-list) | 197 (stringp (car item-path-list)) |
188 (normalize-menu-item-name | 198 (= 0 (compare-menu-text (car item-path-list) |
189 (cond ((vectorp (car rest)) | 199 (menu-item-text (car rest))))) |
190 (aref (car rest) 0)) | |
191 ((stringp (car rest)) | |
192 (car rest)) | |
193 (t | |
194 (caar rest)))))) | |
195 (setq result (car rest) | 200 (setq result (car rest) |
196 rest nil) | 201 rest nil) |
197 (setq rest (cdr rest)))) | 202 (setq rest (cdr rest)))) |
198 (if (cdr item-path-list) | 203 (if (cdr item-path-list) |
199 (cond ((consp result) | 204 (cond ((consp result) |
206 (cons result parent))))) | 211 (cons result parent))))) |
207 | 212 |
208 (defun add-menu-item-1 (leaf-p menu-path new-item before in-menu) | 213 (defun add-menu-item-1 (leaf-p menu-path new-item before in-menu) |
209 ;; This code looks like it could be cleaned up some more | 214 ;; This code looks like it could be cleaned up some more |
210 ;; Do we really need 6 calls to find-menu-item? | 215 ;; Do we really need 6 calls to find-menu-item? |
211 (when before (setq before (normalize-menu-item-name before))) | |
212 (let* ((item-name | 216 (let* ((item-name |
213 (cond ((vectorp new-item) (aref new-item 0)) | 217 (cond ((vectorp new-item) (aref new-item 0)) |
214 ((consp new-item) (car new-item)) | 218 ((consp new-item) (car new-item)) |
215 (t nil))) | 219 (t nil))) |
216 (menubar (or in-menu current-menubar)) | 220 (menubar (or in-menu current-menubar)) |
462 under the toplevel \"File\" menu. (\"Menu\" \"Foo\" \"Item\") means the | 466 under the toplevel \"File\" menu. (\"Menu\" \"Foo\" \"Item\") means the |
463 menu item called \"Item\" under the \"Foo\" submenu of \"Menu\"." | 467 menu item called \"Item\" under the \"Foo\" submenu of \"Menu\"." |
464 (enable-menu-item-1 path t nil)) | 468 (enable-menu-item-1 path t nil)) |
465 | 469 |
466 | 470 |
471 ;;; functions for manipulating whole menus -- adding accelerators, sorting, | |
472 ;;; splitting long menus, etc. | |
473 | |
474 (defun submenu-generate-accelerator-spec (list &optional omit-chars-list) | |
475 "Add auto-generated accelerator specifications to a submenu. | |
476 This can be used to add accelerators to the return value of a menu filter | |
477 function. It correctly ignores unselectable items. It will destructively | |
478 modify the list passed to it. If an item already has an auto-generated | |
479 accelerator spec, this will be removed before the new one is added, making | |
480 this function idempotent. | |
481 | |
482 If OMIT-CHARS-LIST is given, it should be a list of lowercase characters, | |
483 which will not be used as accelerators." | |
484 (let ((n 0)) | |
485 (dolist (item list list) | |
486 (cond | |
487 ((or (vectorp item) (consp item)) | |
488 (incf n) | |
489 (setf (elt item 0) | |
490 (concat | |
491 (menu-item-generate-accelerator-spec n omit-chars-list) | |
492 (menu-item-strip-accelerator-spec (elt item 0))))))))) | |
493 | |
494 (defun menu-item-strip-accelerator-spec (item) | |
495 "Strip an auto-generated accelerator spec off of ITEM. | |
496 ITEM should be a string. This removes specs added by | |
497 `menu-item-generate-accelerator-spec' and `submenu-generate-accelerator-spec'." | |
498 (if (string-match "%_. " item) | |
499 (substring item 4) | |
500 item)) | |
501 | |
502 (defun menu-item-generate-accelerator-spec (n &optional omit-chars-list) | |
503 "Return an accelerator specification for use with auto-generated menus. | |
504 This should be concat'd onto the beginning of each menu line. The spec | |
505 allows the Nth line to be selected by the number N. '0' is used for the | |
506 10th line, and 'a' through 'z' are used for the following 26 lines. | |
507 | |
508 If OMIT-CHARS-LIST is given, it should be a list of lowercase characters, | |
509 which will not be used as accelerators." | |
510 (cond ((< n 10) (concat "%_" (int-to-string n) " ")) | |
511 ((= n 10) "%_0 ") | |
512 ((<= n 36) | |
513 (setq n (- n 10)) | |
514 (let ((m 0)) | |
515 (while (> n 0) | |
516 (setq m (1+ m)) | |
517 (while (memq (int-to-char (+ m (- (char-to-int ?a) 1))) | |
518 omit-chars-list) | |
519 (setq m (1+ m))) | |
520 (setq n (1- n))) | |
521 (if (<= m 26) | |
522 (concat | |
523 "%_" | |
524 (char-to-string (int-to-char (+ m (- (char-to-int ?a) 1)))) | |
525 " ") | |
526 ""))) | |
527 (t ""))) | |
528 | |
529 (defcustom menu-max-items 25 | |
530 "*Maximum number of items in generated menus. | |
531 If number of entries in such a menu is larger than this value, split menu | |
532 into submenus of nearly equal length (see `menu-submenu-max-items'). If | |
533 nil, never split menu into submenus." | |
534 :group 'menu | |
535 :type '(choice (const :tag "no submenus" nil) | |
536 (integer))) | |
537 | |
538 (defcustom menu-submenu-max-items 20 | |
539 "*Maximum number of items in submenus when splitting menus. | |
540 We split large menus into submenus of this many items, and then balance | |
541 them out as much as possible (otherwise the last submenu may have very few | |
542 items)." | |
543 :group 'menu | |
544 :type 'integer) | |
545 | |
546 (defcustom menu-submenu-name-format "%-12.12s ... %.12s" | |
547 "*Format specification of the submenu name when splitting menus. | |
548 Used by `menu-split-long-menu' if the number of entries in a menu is | |
549 larger than `menu-menu-max-items'. | |
550 This string should contain one %s for the name of the first entry and | |
551 one %s for the name of the last entry in the submenu. | |
552 If the value is a function, it should return the submenu name. The | |
553 function is be called with two arguments, the names of the first and | |
554 the last entry in the menu." | |
555 :group 'menu | |
556 :type '(choice (string :tag "Format string") | |
557 (function))) | |
558 | |
559 (defun menu-split-long-menu-and-sort (menu) | |
560 "Sort MENU, split according to `menu-max-items' and add accelerator specs. | |
561 This is useful for menus generated by filter functions, to make them look | |
562 nice. This is equivalent to | |
563 | |
564 \(menu-split-long-menu (menu-sort-menu menu)) | |
565 | |
566 and you can call those functions individually if necessary. | |
567 You can also call `submenu-generate-accelerator-spec' yourself to add | |
568 accelerator specs -- this works even if the specs have already been added." | |
569 (menu-split-long-menu (menu-sort-menu menu))) | |
570 | |
571 (defun menu-split-long-menu (menu) | |
572 "Split MENU according to `menu-max-items' and add accelerator specs. | |
573 If MENU already has accelerator specs, they will be removed and new ones | |
574 generated. You should normally use `menu-split-long-menu-and-sort' instead. | |
575 The menu should already be sorted to get meaningful results when it is | |
576 split, since the outer menus are of the format `FROM ... TO'." | |
577 (let ((len (length menu))) | |
578 (if (or (null menu-max-items) | |
579 (<= len menu-max-items)) | |
580 (submenu-generate-accelerator-spec menu) | |
581 (let* ((outer (/ (+ len (1- menu-submenu-max-items)) | |
582 menu-submenu-max-items)) | |
583 (inner (/ (+ len (1- outer)) outer)) | |
584 (result nil)) | |
585 (while menu | |
586 (let ((sub nil) | |
587 (from (car menu))) | |
588 (dotimes (foo (min inner len)) | |
589 (setq sub (cons (car menu) sub) | |
590 menu (cdr menu))) | |
591 (setq len (- len inner)) | |
592 (let* ((to (car sub)) | |
593 (ftext (menu-item-strip-accelerator-spec | |
594 (menu-item-text from))) | |
595 (ttext (menu-item-strip-accelerator-spec | |
596 (menu-item-text to)))) | |
597 (setq sub (nreverse sub)) | |
598 (setq result | |
599 (cons (cons (if (stringp menu-submenu-name-format) | |
600 (format menu-submenu-name-format | |
601 ftext ttext) | |
602 (funcall menu-submenu-name-format | |
603 ftext ttext)) | |
604 (submenu-generate-accelerator-spec sub)) | |
605 result))))) | |
606 (submenu-generate-accelerator-spec (nreverse result)))))) | |
607 | |
608 (defun menu-sort-menu (menu) | |
609 "Sort MENU alphabetically. | |
610 You should normally use `menu-split-long-menu-and-sort' instead." | |
611 (sort menu | |
612 #'(lambda (a b) (< (compare-menu-text | |
613 (menu-item-text a) (menu-item-text b)) | |
614 0)))) | |
615 | |
467 | 616 |
468 ;;;;;;; popup menus | 617 ;;;;;;; popup menus |
469 | 618 |
470 (defvar global-popup-menu nil | 619 (defvar global-popup-menu nil |
471 "The global popup menu. This is present in all modes. | 620 "The global popup menu. This is present in all modes. |