diff options
| author | Richard M. Stallman | 1997-06-24 22:44:30 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1997-06-24 22:44:30 +0000 |
| commit | 0b296daca5e507ae82d5360d39fe716b4cd5465a (patch) | |
| tree | 73221455d7f674f707f0527f89b6e683fd78c433 | |
| parent | b62c92bb795d0b25107e47a9d1f645a71655d555 (diff) | |
| download | emacs-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.el | 121 |
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. | ||
| 139 | This 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. | ||
| 211 | Non-nil means use the minibuffer; | ||
| 212 | nil 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. | ||
| 1490 | This 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. | ||
| 3094 | To 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" |