aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard M. Stallman1997-06-24 22:44:30 +0000
committerRichard M. Stallman1997-06-24 22:44:30 +0000
commit0b296daca5e507ae82d5360d39fe716b4cd5465a (patch)
tree73221455d7f674f707f0527f89b6e683fd78c433
parentb62c92bb795d0b25107e47a9d1f645a71655d555 (diff)
downloademacs-0b296daca5e507ae82d5360d39fe716b4cd5465a.tar.gz
emacs-0b296daca5e507ae82d5360d39fe716b4cd5465a.zip
(widget-menu-minibuffer-flag): New variable.
(widget-choose): Alternative method to read one character from the keyboard. (widget-documentation-face): New variable. (widget-specify-doc): Use the variable. (widget-default-button-face-get): Try to get it from the parent. (widget-default-create): Use :tag-face for tags. (widget-edit-functions): Renamed from widget-edit-hook. (widget-field-action): Pass the widget as an arg when running hook. (character): Doc fix. (restricted-sexp): New widget type. (integer, number): Use restricted-sexp.
-rw-r--r--lisp/wid-edit.el121
1 files changed, 97 insertions, 24 deletions
diff --git a/lisp/wid-edit.el b/lisp/wid-edit.el
index 1a445d57321..ccaae14b78a 100644
--- a/lisp/wid-edit.el
+++ b/lisp/wid-edit.el
@@ -134,6 +134,10 @@ is the string or buffer containing the text."
134 :group 'widgets 134 :group 'widgets
135 :group 'faces) 135 :group 'faces)
136 136
137(defvar widget-documentation-face 'widget-documentation-face
138 "Face used for documentation strings in widges.
139This exists as a variable so it can be set locally in certain buffers.")
140
137(defface widget-documentation-face '((((class color) 141(defface widget-documentation-face '((((class color)
138 (background dark)) 142 (background dark))
139 (:foreground "lime green")) 143 (:foreground "lime green"))
@@ -202,6 +206,13 @@ Larger menus are read through the minibuffer."
202 :group 'widgets 206 :group 'widgets
203 :type 'integer) 207 :type 'integer)
204 208
209(defcustom widget-menu-minibuffer-flag nil
210 "*Control how to ask for a choice from the keyboard.
211Non-nil means use the minibuffer;
212nil means read a single character."
213 :group 'widgets
214 :type 'boolean)
215
205(defun widget-choose (title items &optional event) 216(defun widget-choose (title items &optional event)
206 "Choose an item from a list. 217 "Choose an item from a list.
207 218
@@ -238,7 +249,8 @@ minibuffer."
238 (stringp (car-safe (event-object val))) 249 (stringp (car-safe (event-object val)))
239 (car (event-object val)))) 250 (car (event-object val))))
240 (cdr (assoc val items)))) 251 (cdr (assoc val items))))
241 (t 252 (widget-menu-minibuffer-flag
253 ;; Read the choice of name from the minibuffer.
242 (setq items (widget-remove-if 'stringp items)) 254 (setq items (widget-remove-if 'stringp items))
243 (let ((val (completing-read (concat title ": ") items nil t))) 255 (let ((val (completing-read (concat title ": ") items nil t)))
244 (if (stringp val) 256 (if (stringp val)
@@ -246,7 +258,45 @@ minibuffer."
246 (when (stringp try) 258 (when (stringp try)
247 (setq val try)) 259 (setq val try))
248 (cdr (assoc val items))) 260 (cdr (assoc val items)))
249 nil))))) 261 nil)))
262 (t
263 ;; Construct a menu of the choices
264 ;; and then use it for prompting for a single character.
265 (let* ((overriding-terminal-local-map
266 (make-sparse-keymap))
267 map choice (next-digit ?0)
268 value)
269 ;; Define SPC as a prefix char to get to this menu.
270 (define-key overriding-terminal-local-map " "
271 (setq map (make-sparse-keymap title)))
272 (while items
273 (setq choice (car items) items (cdr items))
274 (if (consp choice)
275 (let* ((name (car choice))
276 (function (cdr choice))
277 (character (aref name 0)))
278 ;; Pick a character for this choice;
279 ;; avoid duplication.
280 (when (lookup-key map (vector character))
281 (setq character (downcase character))
282 (when (lookup-key map (vector character))
283 (setq character next-digit
284 next-digit (1+ next-digit))))
285 (define-key map (vector character)
286 (cons (format "%c = %s" character name) function)))))
287 (define-key map [?\C-g] '("Quit" . keyboard-quit))
288 (define-key map [t] 'keyboard-quit)
289 (setcdr map (nreverse (cdr map)))
290 ;; Unread a SPC to lead to our new menu.
291 (setq unread-command-events (cons ?\ unread-command-events))
292 ;; Read a char with the menu, and return the result
293 ;; that corresponds to it.
294 (setq value
295 (lookup-key overriding-terminal-local-map
296 (read-key-sequence title) t))
297 (when (eq value 'keyboard-quit)
298 (error "Canceled"))
299 value))))
250 300
251(defun widget-remove-if (predictate list) 301(defun widget-remove-if (predictate list)
252 (let (result (tail list)) 302 (let (result (tail list))
@@ -354,7 +404,7 @@ size field."
354(defun widget-specify-doc (widget from to) 404(defun widget-specify-doc (widget from to)
355 ;; Specify documentation for WIDGET between FROM and TO. 405 ;; Specify documentation for WIDGET between FROM and TO.
356 (add-text-properties from to (list 'widget-doc widget 406 (add-text-properties from to (list 'widget-doc widget
357 'face 'widget-documentation-face))) 407 'face widget-documentation-face)))
358 408
359(defmacro widget-specify-insert (&rest form) 409(defmacro widget-specify-insert (&rest form)
360 ;; Execute FORM without inheriting any text properties. 410 ;; Execute FORM without inheriting any text properties.
@@ -1435,9 +1485,17 @@ If that does not exists, call the value of `widget-complete-field'."
1435 (error "Unknown escape `%c'" escape))) 1485 (error "Unknown escape `%c'" escape)))
1436 (widget-put widget :buttons buttons))) 1486 (widget-put widget :buttons buttons)))
1437 1487
1488(defvar widget-button-face nil
1489 "Face to use for buttons.
1490This is a variable so that it can be buffer-local.")
1491
1438(defun widget-default-button-face-get (widget) 1492(defun widget-default-button-face-get (widget)
1439 ;; Use :button-face or widget-button-face 1493 ;; Use :button-face or widget-button-face
1440 (or (widget-get widget :button-face) 'widget-button-face)) 1494 (or (widget-get widget :button-face)
1495 (let ((parent (widget-get widget :parent)))
1496 (if parent
1497 (widget-apply parent :button-face-get)
1498 'widget-button-face))))
1441 1499
1442(defun widget-default-sample-face-get (widget) 1500(defun widget-default-sample-face-get (widget)
1443 ;; Use :sample-face. 1501 ;; Use :sample-face.
@@ -1716,12 +1774,12 @@ If END is omitted, it defaults to the length of LIST."
1716 :prompt-internal prompt initial history))) 1774 :prompt-internal prompt initial history)))
1717 (widget-apply widget :value-to-external answer)))) 1775 (widget-apply widget :value-to-external answer))))
1718 1776
1719(defvar widget-edit-hook nil) 1777(defvar widget-edit-functions nil)
1720 1778
1721(defun widget-field-action (widget &optional event) 1779(defun widget-field-action (widget &optional event)
1722 ;; Move to next field. 1780 ;; Move to next field.
1723 (widget-forward 1) 1781 (widget-forward 1)
1724 (run-hooks 'widget-edit-hook)) 1782 (run-hook-with-args 'widget-edit-functions widget))
1725 1783
1726(defun widget-field-validate (widget) 1784(defun widget-field-validate (widget)
1727 ;; Valid if the content matches `:valid-regexp'. 1785 ;; Valid if the content matches `:valid-regexp'.
@@ -3031,19 +3089,45 @@ It will read a directory name from the minibuffer when invoked."
3031 (buffer-substring (point) (point-max)))) 3089 (buffer-substring (point) (point-max))))
3032 answer))))) 3090 answer)))))
3033 3091
3034(define-widget 'integer 'sexp 3092(define-widget 'restricted-sexp 'sexp
3093 "A Lisp expression restricted to values that match.
3094To use this type, you must define :match or :match-alternatives."
3095 :type-error "The specified value is not valid"
3096 :match 'widget-restricted-sexp-match
3097 :value-to-internal (lambda (widget value)
3098 (if (widget-apply widget :match value)
3099 (prin1-to-string value)
3100 value)))
3101
3102(defun widget-restricted-sexp-match (widget value)
3103 (let ((alternatives (widget-get widget :match-alternatives))
3104 matched)
3105 (while (and alternatives (not matched))
3106 (if (cond ((functionp (car alternatives))
3107 (funcall (car alternatives) value))
3108 ((and (consp (car alternatives))
3109 (eq (car (car alternatives)) 'quote))
3110 (eq value (nth 1 (car alternatives)))))
3111 (setq matched t))
3112 (setq alternatives (cdr alternatives)))
3113 matched))
3114
3115(define-widget 'integer 'restricted-sexp
3035 "An integer." 3116 "An integer."
3036 :tag "Integer" 3117 :tag "Integer"
3037 :value 0 3118 :value 0
3038 :type-error "This field should contain an integer" 3119 :type-error "This field should contain an integer"
3039 :value-to-internal (lambda (widget value) 3120 :match-alternatives '(integerp))
3040 (if (integerp value) 3121
3041 (prin1-to-string value) 3122(define-widget 'number 'restricted-sexp
3042 value)) 3123 "A floating point number."
3043 :match (lambda (widget value) (integerp value))) 3124 :tag "Number"
3125 :value 0.0
3126 :type-error "This field should contain a number"
3127 :match-alternatives '(numberp))
3044 3128
3045(define-widget 'character 'editable-field 3129(define-widget 'character 'editable-field
3046 "An character." 3130 "A character."
3047 :tag "Character" 3131 :tag "Character"
3048 :value 0 3132 :value 0
3049 :size 1 3133 :size 1
@@ -3063,17 +3147,6 @@ It will read a directory name from the minibuffer when invoked."
3063 (characterp value) 3147 (characterp value)
3064 (integerp value)))) 3148 (integerp value))))
3065 3149
3066(define-widget 'number 'sexp
3067 "A floating point number."
3068 :tag "Number"
3069 :value 0.0
3070 :type-error "This field should contain a number"
3071 :value-to-internal (lambda (widget value)
3072 (if (numberp value)
3073 (prin1-to-string value)
3074 value))
3075 :match (lambda (widget value) (numberp value)))
3076
3077(define-widget 'list 'group 3150(define-widget 'list 'group
3078 "A lisp list." 3151 "A lisp list."
3079 :tag "List" 3152 :tag "List"